summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml6
-rw-r--r--.clang-format67
-rw-r--r--.editorconfig2
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md3
-rw-r--r--.github/workflows/check-style.yml34
-rw-r--r--.github/workflows/check-whitespace.yml67
-rw-r--r--.github/workflows/coverity.yml8
-rw-r--r--.github/workflows/l10n.yml6
-rw-r--r--.github/workflows/main.yml78
-rw-r--r--.gitignore3
-rw-r--r--.gitlab-ci.yml212
-rw-r--r--.mailmap8
-rw-r--r--CODE_OF_CONDUCT.md4
-rw-r--r--Documentation/BreakingChanges.txt174
-rw-r--r--Documentation/CodingGuidelines307
-rw-r--r--Documentation/DecisionMaking.txt74
-rw-r--r--Documentation/Makefile14
-rw-r--r--Documentation/MyFirstContribution.txt23
-rw-r--r--Documentation/MyFirstObjectWalk.txt37
-rw-r--r--Documentation/RelNotes/1.6.2.txt2
-rw-r--r--Documentation/RelNotes/1.6.3.txt2
-rw-r--r--Documentation/RelNotes/1.6.4.txt2
-rw-r--r--Documentation/RelNotes/1.6.5.txt2
-rw-r--r--Documentation/RelNotes/1.6.6.txt2
-rw-r--r--Documentation/RelNotes/2.43.0.txt323
-rw-r--r--Documentation/RelNotes/2.43.1.txt82
-rw-r--r--Documentation/RelNotes/2.43.2.txt37
-rw-r--r--Documentation/RelNotes/2.43.3.txt12
-rw-r--r--Documentation/RelNotes/2.43.4.txt7
-rw-r--r--Documentation/RelNotes/2.43.5.txt26
-rw-r--r--Documentation/RelNotes/2.44.0.txt334
-rw-r--r--Documentation/RelNotes/2.44.1.txt8
-rw-r--r--Documentation/RelNotes/2.44.2.txt26
-rw-r--r--Documentation/RelNotes/2.45.0.txt476
-rw-r--r--Documentation/RelNotes/2.45.1.txt8
-rw-r--r--Documentation/RelNotes/2.45.2.txt26
-rw-r--r--Documentation/RelNotes/2.45.3.txt107
-rw-r--r--Documentation/RelNotes/2.46.0.txt461
-rw-r--r--Documentation/RelNotes/2.46.1.txt75
-rw-r--r--Documentation/RelNotes/2.46.2.txt23
-rw-r--r--Documentation/RelNotes/2.47.0.txt342
-rw-r--r--Documentation/RelNotes/2.47.1.txt31
-rw-r--r--Documentation/RelNotes/2.48.0.txt195
-rw-r--r--Documentation/ReviewingGuidelines.txt29
-rw-r--r--Documentation/SubmittingPatches334
-rw-r--r--Documentation/ToolsForGit.txt4
-rw-r--r--Documentation/asciidoc.conf20
-rw-r--r--Documentation/asciidoctor-extensions.rb87
-rw-r--r--Documentation/config.txt67
-rw-r--r--Documentation/config/add.txt25
-rw-r--r--Documentation/config/advice.txt206
-rw-r--r--Documentation/config/alias.txt27
-rw-r--r--Documentation/config/apply.txt4
-rw-r--r--Documentation/config/attr.txt6
-rw-r--r--Documentation/config/bitmap-pseudo-merge.txt91
-rw-r--r--Documentation/config/branch.txt6
-rw-r--r--Documentation/config/checkout.txt4
-rw-r--r--Documentation/config/clean.txt4
-rw-r--r--Documentation/config/clone.txt22
-rw-r--r--Documentation/config/color.txt2
-rw-r--r--Documentation/config/column.txt4
-rw-r--r--Documentation/config/commit.txt4
-rw-r--r--Documentation/config/commitgraph.txt29
-rw-r--r--Documentation/config/core.txt26
-rw-r--r--Documentation/config/credential.txt12
-rw-r--r--Documentation/config/diff.txt36
-rw-r--r--Documentation/config/extensions.txt74
-rw-r--r--Documentation/config/fastimport.txt4
-rw-r--r--Documentation/config/feature.txt3
-rw-r--r--Documentation/config/fetch.txt10
-rw-r--r--Documentation/config/format.txt4
-rw-r--r--Documentation/config/fsck.txt22
-rw-r--r--Documentation/config/fsmonitor--daemon.txt2
-rw-r--r--Documentation/config/gc.txt29
-rw-r--r--Documentation/config/gpg.txt6
-rw-r--r--Documentation/config/grep.txt2
-rw-r--r--Documentation/config/gui.txt2
-rw-r--r--Documentation/config/http.txt39
-rw-r--r--Documentation/config/i18n.txt2
-rw-r--r--Documentation/config/imap.txt4
-rw-r--r--Documentation/config/index.txt2
-rw-r--r--Documentation/config/init.txt21
-rw-r--r--Documentation/config/interactive.txt12
-rw-r--r--Documentation/config/log.txt2
-rw-r--r--Documentation/config/mailinfo.txt2
-rw-r--r--Documentation/config/maintenance.txt13
-rw-r--r--Documentation/config/man.txt2
-rw-r--r--Documentation/config/merge.txt2
-rw-r--r--Documentation/config/mergetool.txt29
-rw-r--r--Documentation/config/notes.txt2
-rw-r--r--Documentation/config/pack.txt25
-rw-r--r--Documentation/config/promisor.txt3
-rw-r--r--Documentation/config/push.txt4
-rw-r--r--Documentation/config/rebase.txt6
-rw-r--r--Documentation/config/receive.txt6
-rw-r--r--Documentation/config/reftable.txt56
-rw-r--r--Documentation/config/remote.txt34
-rw-r--r--Documentation/config/rerere.txt2
-rw-r--r--Documentation/config/safe.txt7
-rw-r--r--Documentation/config/sendemail.txt31
-rw-r--r--Documentation/config/sequencer.txt2
-rw-r--r--Documentation/config/splitindex.txt6
-rw-r--r--Documentation/config/stash.txt8
-rw-r--r--Documentation/config/status.txt6
-rw-r--r--Documentation/config/submodule.txt4
-rw-r--r--Documentation/config/trace2.txt2
-rw-r--r--Documentation/config/transfer.txt10
-rw-r--r--Documentation/config/uploadpack.txt6
-rw-r--r--Documentation/config/user.txt10
-rw-r--r--Documentation/config/versionsort.txt6
-rw-r--r--Documentation/date-formats.txt2
-rw-r--r--Documentation/diff-generate-patch.txt26
-rw-r--r--Documentation/diff-options.txt143
-rw-r--r--Documentation/docinfo-html.in5
-rw-r--r--Documentation/fetch-options.txt17
-rw-r--r--Documentation/fsck-msgids.txt52
-rw-r--r--Documentation/git-add.txt128
-rw-r--r--Documentation/git-am.txt41
-rw-r--r--Documentation/git-apply.txt23
-rw-r--r--Documentation/git-archive.txt26
-rw-r--r--Documentation/git-bisect.txt18
-rw-r--r--Documentation/git-blame.txt10
-rw-r--r--Documentation/git-branch.txt5
-rw-r--r--Documentation/git-bugreport.txt19
-rw-r--r--Documentation/git-bundle.txt59
-rw-r--r--Documentation/git-cat-file.txt6
-rw-r--r--Documentation/git-check-attr.txt6
-rw-r--r--Documentation/git-check-ignore.txt2
-rw-r--r--Documentation/git-check-mailmap.txt18
-rw-r--r--Documentation/git-check-ref-format.txt4
-rw-r--r--Documentation/git-checkout-index.txt10
-rw-r--r--Documentation/git-checkout.txt25
-rw-r--r--Documentation/git-cherry-pick.txt30
-rw-r--r--Documentation/git-clean.txt8
-rw-r--r--Documentation/git-clone.txt151
-rw-r--r--Documentation/git-commit-graph.txt2
-rw-r--r--Documentation/git-commit.txt6
-rw-r--r--Documentation/git-config.txt246
-rw-r--r--Documentation/git-count-objects.txt6
-rw-r--r--Documentation/git-credential-cache.txt2
-rw-r--r--Documentation/git-credential-store.txt2
-rw-r--r--Documentation/git-credential.txt106
-rw-r--r--Documentation/git-cvsimport.txt4
-rw-r--r--Documentation/git-cvsserver.txt4
-rw-r--r--Documentation/git-daemon.txt12
-rw-r--r--Documentation/git-diagnose.txt2
-rw-r--r--Documentation/git-diff-files.txt6
-rw-r--r--Documentation/git-diff-index.txt4
-rw-r--r--Documentation/git-diff-tree.txt14
-rw-r--r--Documentation/git-diff.txt2
-rw-r--r--Documentation/git-difftool.txt7
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-fast-import.txt45
-rw-r--r--Documentation/git-fetch-pack.txt4
-rw-r--r--Documentation/git-fetch.txt4
-rw-r--r--Documentation/git-filter-branch.txt6
-rw-r--r--Documentation/git-for-each-ref.txt84
-rw-r--r--Documentation/git-for-each-repo.txt9
-rw-r--r--Documentation/git-format-patch.txt64
-rw-r--r--Documentation/git-fsck.txt6
-rw-r--r--Documentation/git-fsmonitor--daemon.txt10
-rw-r--r--Documentation/git-gc.txt12
-rw-r--r--Documentation/git-get-tar-commit-id.txt2
-rw-r--r--Documentation/git-grep.txt36
-rw-r--r--Documentation/git-gui.txt2
-rw-r--r--Documentation/git-hash-object.txt8
-rw-r--r--Documentation/git-help.txt18
-rw-r--r--Documentation/git-hook.txt4
-rw-r--r--Documentation/git-http-backend.txt10
-rw-r--r--Documentation/git-http-fetch.txt2
-rw-r--r--Documentation/git-http-push.txt10
-rw-r--r--Documentation/git-imap-send.txt2
-rw-r--r--Documentation/git-index-pack.txt43
-rw-r--r--Documentation/git-init.txt104
-rw-r--r--Documentation/git-interpret-trailers.txt183
-rw-r--r--Documentation/git-log.txt4
-rw-r--r--Documentation/git-ls-files.txt39
-rw-r--r--Documentation/git-ls-remote.txt15
-rw-r--r--Documentation/git-mailsplit.txt2
-rw-r--r--Documentation/git-maintenance.txt13
-rw-r--r--Documentation/git-merge-base.txt12
-rw-r--r--Documentation/git-merge-file.txt44
-rw-r--r--Documentation/git-merge-tree.txt30
-rw-r--r--Documentation/git-merge.txt74
-rw-r--r--Documentation/git-mergetool--lib.txt10
-rw-r--r--Documentation/git-mergetool.txt8
-rw-r--r--Documentation/git-mktag.txt6
-rw-r--r--Documentation/git-mktree.txt4
-rw-r--r--Documentation/git-multi-pack-index.txt11
-rw-r--r--Documentation/git-mv.txt4
-rw-r--r--Documentation/git-name-rev.txt2
-rw-r--r--Documentation/git-notes.txt12
-rw-r--r--Documentation/git-pack-objects.txt8
-rw-r--r--Documentation/git-pack-refs.txt15
-rw-r--r--Documentation/git-prune-packed.txt2
-rw-r--r--Documentation/git-prune.txt2
-rw-r--r--Documentation/git-pull.txt4
-rw-r--r--Documentation/git-push.txt2
-rw-r--r--Documentation/git-quiltimport.txt4
-rw-r--r--Documentation/git-range-diff.txt4
-rw-r--r--Documentation/git-read-tree.txt6
-rw-r--r--Documentation/git-rebase.txt90
-rw-r--r--Documentation/git-receive-pack.txt4
-rw-r--r--Documentation/git-reflog.txt3
-rw-r--r--Documentation/git-refs.txt74
-rw-r--r--Documentation/git-remote-ext.txt10
-rw-r--r--Documentation/git-remote-fd.txt10
-rw-r--r--Documentation/git-remote.txt2
-rw-r--r--Documentation/git-repack.txt36
-rw-r--r--Documentation/git-replace.txt10
-rw-r--r--Documentation/git-replay.txt127
-rw-r--r--Documentation/git-request-pull.txt4
-rw-r--r--Documentation/git-restore.txt8
-rw-r--r--Documentation/git-rev-list.txt4
-rw-r--r--Documentation/git-rev-parse.txt72
-rw-r--r--Documentation/git-revert.txt12
-rw-r--r--Documentation/git-rm.txt2
-rw-r--r--Documentation/git-send-email.txt60
-rw-r--r--Documentation/git-send-pack.txt16
-rw-r--r--Documentation/git-sh-setup.txt2
-rw-r--r--Documentation/git-show-branch.txt14
-rw-r--r--Documentation/git-show-ref.txt40
-rw-r--r--Documentation/git-show.txt2
-rw-r--r--Documentation/git-status.txt19
-rw-r--r--Documentation/git-stripspace.txt6
-rw-r--r--Documentation/git-submodule.txt12
-rw-r--r--Documentation/git-svn.txt32
-rw-r--r--Documentation/git-switch.txt11
-rw-r--r--Documentation/git-symbolic-ref.txt6
-rw-r--r--Documentation/git-tag.txt18
-rw-r--r--Documentation/git-update-index.txt33
-rw-r--r--Documentation/git-update-ref.txt133
-rw-r--r--Documentation/git-update-server-info.txt4
-rw-r--r--Documentation/git-upload-pack.txt2
-rw-r--r--Documentation/git-var.txt2
-rw-r--r--Documentation/git-verify-pack.txt6
-rw-r--r--Documentation/git-whatchanged.txt8
-rw-r--r--Documentation/git-worktree.txt6
-rw-r--r--Documentation/git.txt102
-rw-r--r--Documentation/gitattributes.txt35
-rw-r--r--Documentation/gitcli.txt11
-rw-r--r--Documentation/gitcore-tutorial.txt2
-rw-r--r--Documentation/gitdiffcore.txt22
-rw-r--r--Documentation/giteveryday.txt4
-rw-r--r--Documentation/gitfaq.txt109
-rw-r--r--Documentation/gitformat-bundle.txt8
-rw-r--r--Documentation/gitformat-chunk.txt4
-rw-r--r--Documentation/gitformat-commit-graph.txt11
-rw-r--r--Documentation/gitformat-index.txt4
-rw-r--r--Documentation/gitformat-pack.txt139
-rw-r--r--Documentation/githooks.txt47
-rw-r--r--Documentation/gitk.txt6
-rw-r--r--Documentation/gitpacking.txt195
-rw-r--r--Documentation/gitprotocol-capabilities.txt22
-rw-r--r--Documentation/gitprotocol-common.txt2
-rw-r--r--Documentation/gitprotocol-http.txt24
-rw-r--r--Documentation/gitprotocol-pack.txt6
-rw-r--r--Documentation/gitprotocol-v2.txt22
-rw-r--r--Documentation/gitremote-helpers.txt15
-rw-r--r--Documentation/gitrepository-layout.txt5
-rw-r--r--Documentation/gitsubmodules.txt10
-rw-r--r--Documentation/gittutorial.txt10
-rw-r--r--Documentation/gitweb.conf.txt16
-rw-r--r--Documentation/gitweb.txt22
-rw-r--r--Documentation/glossary-content.txt137
-rw-r--r--Documentation/howto/coordinate-embargoed-releases.txt2
-rw-r--r--Documentation/howto/keep-canonical-history-correct.txt4
-rw-r--r--Documentation/howto/maintain-git.txt227
-rw-r--r--Documentation/howto/update-hook-example.txt4
-rw-r--r--Documentation/howto/use-git-daemon.txt2
-rw-r--r--Documentation/howto/using-merge-subtree.txt2
-rw-r--r--Documentation/i18n.txt4
-rwxr-xr-xDocumentation/lint-manpages.sh108
-rw-r--r--Documentation/merge-options.txt2
-rw-r--r--Documentation/mergetools/vimdiff.txt9
-rw-r--r--Documentation/pretty-formats.txt59
-rw-r--r--Documentation/pretty-options.txt8
-rw-r--r--Documentation/pull-fetch-param.txt13
-rw-r--r--Documentation/ref-storage-format.txt3
-rw-r--r--Documentation/rev-list-options.txt37
-rw-r--r--Documentation/scalar.txt7
-rw-r--r--Documentation/signoff-option.txt2
-rw-r--r--Documentation/technical/api-index-skel.txt2
-rw-r--r--Documentation/technical/api-simple-ipc.txt10
-rw-r--r--Documentation/technical/api-trace2.txt17
-rw-r--r--Documentation/technical/bitmap-format.txt147
-rw-r--r--Documentation/technical/commit-graph.txt2
-rw-r--r--Documentation/technical/hash-function-transition.txt4
-rw-r--r--Documentation/technical/multi-pack-index.txt103
-rw-r--r--Documentation/technical/parallel-checkout.txt10
-rw-r--r--Documentation/technical/partial-clone.txt10
-rw-r--r--Documentation/technical/platform-support.txt190
-rw-r--r--Documentation/technical/racy-git.txt10
-rw-r--r--Documentation/technical/reftable.txt10
-rw-r--r--Documentation/technical/repository-version.txt38
-rw-r--r--Documentation/technical/rerere.txt6
-rw-r--r--Documentation/technical/sparse-checkout.txt2
-rw-r--r--Documentation/technical/unit-tests.txt242
-rw-r--r--Documentation/trace2-target-values.txt2
-rw-r--r--Documentation/urls-remotes.txt4
-rw-r--r--Documentation/urls.txt58
-rw-r--r--Documentation/user-manual.txt44
-rwxr-xr-xGIT-VERSION-GEN4
-rw-r--r--INSTALL4
-rw-r--r--Makefile382
-rw-r--r--README.md6
l---------RelNotes2
-rw-r--r--add-interactive.c30
-rw-r--r--add-patch.c115
-rw-r--r--advice.c126
-rw-r--r--advice.h20
-rw-r--r--alias.c12
-rw-r--r--apply.c637
-rw-r--r--apply.h5
-rw-r--r--archive-tar.c6
-rw-r--r--archive-zip.c4
-rw-r--r--archive.c55
-rw-r--r--archive.h1
-rw-r--r--attr.c200
-rw-r--r--attr.h4
-rw-r--r--bisect.c171
-rw-r--r--bisect.h2
-rw-r--r--blame.c15
-rw-r--r--blame.h5
-rw-r--r--blob.c1
-rw-r--r--block-sha1/sha1.h2
-rw-r--r--bloom.c252
-rw-r--r--bloom.h40
-rw-r--r--branch.c49
-rw-r--r--branch.h14
-rw-r--r--builtin.h275
-rw-r--r--builtin/add.c172
-rw-r--r--builtin/am.c253
-rw-r--r--builtin/annotate.c26
-rw-r--r--builtin/apply.c18
-rw-r--r--builtin/archive.c25
-rw-r--r--builtin/bisect.c77
-rw-r--r--builtin/blame.c53
-rw-r--r--builtin/branch.c240
-rw-r--r--builtin/bugreport.c25
-rw-r--r--builtin/bundle.c19
-rw-r--r--builtin/cat-file.c70
-rw-r--r--builtin/check-attr.c15
-rw-r--r--builtin/check-ignore.c18
-rw-r--r--builtin/check-mailmap.c31
-rw-r--r--builtin/check-ref-format.c6
-rw-r--r--builtin/checkout--worker.c6
-rw-r--r--builtin/checkout-index.c46
-rw-r--r--builtin/checkout.c389
-rw-r--r--builtin/clean.c37
-rw-r--r--builtin/clone.c261
-rw-r--r--builtin/column.c10
-rw-r--r--builtin/commit-graph.c49
-rw-r--r--builtin/commit-tree.c22
-rw-r--r--builtin/commit.c287
-rw-r--r--builtin/config.c1197
-rw-r--r--builtin/count-objects.c13
-rw-r--r--builtin/credential-cache--daemon.c35
-rw-r--r--builtin/credential-cache.c34
-rw-r--r--builtin/credential-store.c9
-rw-r--r--builtin/credential.c24
-rw-r--r--builtin/describe.c63
-rw-r--r--builtin/diagnose.c7
-rw-r--r--builtin/diff-files.c10
-rw-r--r--builtin/diff-index.c15
-rw-r--r--builtin/diff-tree.c14
-rw-r--r--builtin/diff.c34
-rw-r--r--builtin/difftool.c49
-rw-r--r--builtin/fast-export.c67
-rw-r--r--builtin/fast-import.c288
-rw-r--r--builtin/fetch-pack.c42
-rw-r--r--builtin/fetch.c138
-rw-r--r--builtin/fmt-merge-msg.c12
-rw-r--r--builtin/for-each-ref.c55
-rw-r--r--builtin/for-each-repo.c20
-rw-r--r--builtin/fsck.c48
-rw-r--r--builtin/fsmonitor--daemon.c37
-rw-r--r--builtin/gc.c986
-rw-r--r--builtin/get-tar-commit-id.c7
-rw-r--r--builtin/grep.c52
-rw-r--r--builtin/hash-object.c10
-rw-r--r--builtin/help.c38
-rw-r--r--builtin/hook.c9
-rw-r--r--builtin/index-pack.c185
-rw-r--r--builtin/init-db.c56
-rw-r--r--builtin/interpret-trailers.c141
-rw-r--r--builtin/log.c918
-rw-r--r--builtin/ls-files.c23
-rw-r--r--builtin/ls-remote.c74
-rw-r--r--builtin/ls-tree.c28
-rw-r--r--builtin/mailinfo.c7
-rw-r--r--builtin/mailsplit.c9
-rw-r--r--builtin/merge-base.c33
-rw-r--r--builtin/merge-file.c98
-rw-r--r--builtin/merge-index.c24
-rw-r--r--builtin/merge-ours.c8
-rw-r--r--builtin/merge-recursive.c18
-rw-r--r--builtin/merge-tree.c103
-rw-r--r--builtin/merge.c269
-rw-r--r--builtin/mktag.c10
-rw-r--r--builtin/mktree.c7
-rw-r--r--builtin/multi-pack-index.c29
-rw-r--r--builtin/mv.c345
-rw-r--r--builtin/name-rev.c59
-rw-r--r--builtin/notes.c116
-rw-r--r--builtin/pack-objects.c321
-rw-r--r--builtin/pack-redundant.c65
-rw-r--r--builtin/pack-refs.c38
-rw-r--r--builtin/patch-id.c25
-rw-r--r--builtin/prune-packed.c5
-rw-r--r--builtin/prune.c14
-rw-r--r--builtin/pull.c95
-rw-r--r--builtin/push.c122
-rw-r--r--builtin/range-diff.c9
-rw-r--r--builtin/read-tree.c32
-rw-r--r--builtin/rebase.c262
-rw-r--r--builtin/receive-pack.c165
-rw-r--r--builtin/reflog.c90
-rw-r--r--builtin/refs.c118
-rw-r--r--builtin/remote-ext.c5
-rw-r--r--builtin/remote-fd.c5
-rw-r--r--builtin/remote.c235
-rw-r--r--builtin/repack.c829
-rw-r--r--builtin/replace.c38
-rw-r--r--builtin/replay.c461
-rw-r--r--builtin/rerere.c17
-rw-r--r--builtin/reset.c66
-rw-r--r--builtin/rev-list.c129
-rw-r--r--builtin/rev-parse.c158
-rw-r--r--builtin/revert.c71
-rw-r--r--builtin/rm.c50
-rw-r--r--builtin/send-pack.c47
-rw-r--r--builtin/shortlog.c28
-rw-r--r--builtin/show-branch.c90
-rw-r--r--builtin/show-index.c7
-rw-r--r--builtin/show-ref.c311
-rw-r--r--builtin/sparse-checkout.c159
-rw-r--r--builtin/stash.c191
-rw-r--r--builtin/stripspace.c10
-rw-r--r--builtin/submodule--helper.c220
-rw-r--r--builtin/symbolic-ref.c19
-rw-r--r--builtin/tag.c156
-rw-r--r--builtin/unpack-file.c6
-rw-r--r--builtin/unpack-objects.c32
-rw-r--r--builtin/update-index.c248
-rw-r--r--builtin/update-ref.c315
-rw-r--r--builtin/update-server-info.c6
-rw-r--r--builtin/upload-archive.c20
-rw-r--r--builtin/upload-pack.c11
-rw-r--r--builtin/var.c14
-rw-r--r--builtin/verify-commit.c9
-rw-r--r--builtin/verify-pack.c6
-rw-r--r--builtin/verify-tag.c8
-rw-r--r--builtin/worktree.c182
-rw-r--r--builtin/write-tree.c14
-rw-r--r--bulk-checkin.c46
-rw-r--r--bulk-checkin.h6
-rw-r--r--bundle-uri.c45
-rw-r--r--bundle.c47
-rw-r--r--bundle.h1
-rw-r--r--cache-tree.c123
-rw-r--r--cache-tree.h2
-rw-r--r--cbtree.c2
-rw-r--r--checkout.c6
-rw-r--r--checkout.h8
-rw-r--r--chunk-format.c26
-rw-r--r--chunk-format.h11
-rwxr-xr-xci/check-directional-formatting.bash2
-rwxr-xr-xci/check-whitespace.sh101
-rwxr-xr-xci/install-dependencies.sh124
-rwxr-xr-xci/install-docker-dependencies.sh22
-rwxr-xr-xci/install-sdk.ps112
-rwxr-xr-xci/lib.sh237
-rwxr-xr-xci/print-test-failures.sh8
-rwxr-xr-xci/run-build-and-minimal-fuzzers.sh20
-rwxr-xr-xci/run-build-and-tests.sh5
-rwxr-xr-xci/run-docker-build.sh66
-rwxr-xr-xci/run-docker.sh47
-rwxr-xr-xci/run-style-check.sh25
-rwxr-xr-xci/run-test-slice.sh5
-rwxr-xr-xci/test-documentation.sh1
-rw-r--r--color.c23
-rw-r--r--color.h3
-rw-r--r--column.c4
-rw-r--r--combine-diff.c16
-rw-r--r--command-list.txt2
-rw-r--r--commit-graph.c456
-rw-r--r--commit-graph.h16
-rw-r--r--commit-reach.c342
-rw-r--r--commit-reach.h43
-rw-r--r--commit.c318
-rw-r--r--commit.h32
-rw-r--r--common-main.c4
-rw-r--r--compat/basename.c16
-rw-r--r--compat/compiler.h5
-rw-r--r--compat/disk.h1
-rw-r--r--compat/fsmonitor/fsm-health-darwin.c8
-rw-r--r--compat/fsmonitor/fsm-health-win32.c1
-rw-r--r--compat/fsmonitor/fsm-ipc-darwin.c9
-rw-r--r--compat/fsmonitor/fsm-ipc-win32.c2
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c11
-rw-r--r--compat/fsmonitor/fsm-listen-win32.c35
-rw-r--r--compat/fsmonitor/fsm-path-utils-win32.c7
-rw-r--r--compat/fsmonitor/fsm-settings-win32.c2
-rw-r--r--compat/mingw.c322
-rw-r--r--compat/mingw.h24
-rw-r--r--compat/nedmalloc/nedmalloc.c2
-rw-r--r--compat/precompose_utf8.c1
-rw-r--r--compat/regex/regcomp.c16
-rw-r--r--compat/regex/regex_internal.c4
-rw-r--r--compat/regex/regexec.c12
-rw-r--r--compat/sha1-chunked.c2
-rw-r--r--compat/simple-ipc/ipc-shared.c8
-rw-r--r--compat/simple-ipc/ipc-unix-socket.c31
-rw-r--r--compat/simple-ipc/ipc-win32.c48
-rw-r--r--compat/stub/procinfo.c2
-rw-r--r--compat/terminal.c2
-rw-r--r--compat/vcbuild/include/unistd.h4
-rw-r--r--compat/win32/headless.c2
-rw-r--r--compat/win32/path-utils.c39
-rw-r--r--compat/win32/path-utils.h4
-rw-r--r--compat/win32/pthread.c2
-rw-r--r--compat/win32/pthread.h4
-rw-r--r--compat/win32/syslog.c2
-rw-r--r--compat/win32/trace2_win32_process_info.c2
-rw-r--r--compat/win32mmap.c2
-rw-r--r--compat/winansi.c4
-rw-r--r--config.c660
-rw-r--r--config.h334
-rw-r--r--config.mak.dev6
-rw-r--r--config.mak.uname179
-rw-r--r--configure.ac2
-rw-r--r--connect.c7
-rw-r--r--connected.c6
-rw-r--r--contrib/README4
-rw-r--r--contrib/buildsystems/CMakeLists.txt88
-rw-r--r--contrib/coccinelle/refs.cocci103
-rw-r--r--contrib/coccinelle/xstrncmpz.cocci28
-rw-r--r--contrib/completion/git-completion.bash514
-rw-r--r--contrib/completion/git-completion.zsh1
-rw-r--r--contrib/completion/git-prompt.sh212
-rwxr-xr-xcontrib/coverage-diff.sh9
-rw-r--r--contrib/credential/libsecret/git-credential-libsecret.c98
-rw-r--r--contrib/credential/osxkeychain/Makefile3
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c390
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c66
-rw-r--r--contrib/diff-highlight/DiffHighlight.pm2
-rwxr-xr-xcontrib/git-jump/git-jump6
-rwxr-xr-xcontrib/hg-to-git/hg-to-git.py254
-rw-r--r--contrib/hg-to-git/hg-to-git.txt21
-rw-r--r--contrib/mw-to-git/Git/Mediawiki.pm2
-rwxr-xr-xcontrib/mw-to-git/t/t9363-mw-to-git-export-import.sh2
-rwxr-xr-xcontrib/subtree/git-subtree.sh76
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh46
-rwxr-xr-xcontrib/vscode/init.sh1
-rwxr-xr-xcontrib/workdir/git-new-workdir2
-rw-r--r--convert.c54
-rw-r--r--convert.h2
-rw-r--r--credential.c184
-rw-r--r--credential.h126
-rw-r--r--csum-file.c38
-rw-r--r--csum-file.h13
-rw-r--r--daemon.c20
-rw-r--r--date.c62
-rw-r--r--date.h6
-rw-r--r--decorate.h2
-rw-r--r--delta-islands.c16
-rw-r--r--diagnose.c44
-rw-r--r--diff-lib.c56
-rw-r--r--diff-merges.c3
-rw-r--r--diff-no-index.c5
-rw-r--r--diff.c242
-rw-r--r--diff.h10
-rw-r--r--diffcore-break.c16
-rw-r--r--diffcore-delta.c5
-rw-r--r--diffcore-order.c19
-rw-r--r--diffcore-pickaxe.c4
-rw-r--r--diffcore-rename.c20
-rw-r--r--diffcore-rotate.c3
-rw-r--r--diffcore.h12
-rw-r--r--dir-iterator.c105
-rw-r--r--dir-iterator.h3
-rw-r--r--dir.c156
-rw-r--r--dir.h35
-rw-r--r--editor.c22
-rw-r--r--editor.h5
-rw-r--r--entry.c26
-rw-r--r--entry.h6
-rw-r--r--environment.c270
-rw-r--r--environment.h164
-rw-r--r--ewah/bitmap.c85
-rw-r--r--ewah/ewok.h9
-rw-r--r--exec-cmd.c24
-rw-r--r--fetch-pack.c105
-rw-r--r--fetch-pack.h6
-rw-r--r--fmt-merge-msg.c16
-rw-r--r--fsck.c306
-rw-r--r--fsck.h85
-rw-r--r--fsmonitor--daemon.h6
-rw-r--r--fsmonitor-ipc.c13
-rw-r--r--fsmonitor-settings.c10
-rw-r--r--fsmonitor.c317
-rw-r--r--gettext.c2
-rwxr-xr-xgit-archimport.perl2
-rw-r--r--git-compat-util.h116
-rwxr-xr-xgit-cvsexportcommit.perl2
-rwxr-xr-xgit-cvsimport.perl4
-rwxr-xr-xgit-cvsserver.perl2
-rwxr-xr-xgit-difftool--helper.sh13
-rw-r--r--git-gui/.gitattributes1
-rw-r--r--git-gui/Makefile37
-rw-r--r--git-gui/README.md6
-rwxr-xr-xgit-gui/git-gui.sh344
-rw-r--r--git-gui/lib/choose_repository.tcl27
-rw-r--r--git-gui/lib/commit.tcl11
-rw-r--r--git-gui/lib/encoding.tcl2
-rw-r--r--git-gui/lib/mergetool.tcl21
-rw-r--r--git-gui/lib/shortcut.tcl31
-rw-r--r--git-gui/po/README2
-rw-r--r--git-gui/po/fr.po2
-rw-r--r--git-gui/po/sv.po3267
-rwxr-xr-xgit-instaweb.sh6
-rwxr-xr-xgit-p4.py61
-rwxr-xr-xgit-quiltimport.sh2
-rwxr-xr-xgit-send-email.perl275
-rwxr-xr-xgit-submodule.sh82
-rwxr-xr-xgit-svn.perl53
-rw-r--r--git.c177
-rw-r--r--gitk-git/Makefile4
-rwxr-xr-xgitk-git/gitk4
-rw-r--r--gitweb/INSTALL4
-rwxr-xr-xgitweb/gitweb.perl20
-rw-r--r--gitweb/static/gitweb.css2
-rw-r--r--gitweb/static/js/lib/common-lib.js10
-rw-r--r--gpg-interface.c62
-rw-r--r--gpg-interface.h6
-rw-r--r--graph.c32
-rw-r--r--graph.h4
-rw-r--r--grep.c57
-rw-r--r--hash-ll.h309
-rw-r--r--hash-lookup.c5
-rw-r--r--hash.h442
-rw-r--r--help.c98
-rw-r--r--help.h4
-rw-r--r--hex-ll.c49
-rw-r--r--hex-ll.h27
-rw-r--r--hex.c55
-rw-r--r--hex.h52
-rw-r--r--hook.c21
-rw-r--r--hook.h14
-rw-r--r--http-backend.c36
-rw-r--r--http-fetch.c26
-rw-r--r--http-push.c61
-rw-r--r--http-walker.c46
-rw-r--r--http.c344
-rw-r--r--http.h10
-rw-r--r--ident.c4
-rw-r--r--imap-send.c231
-rw-r--r--json-writer.c5
-rw-r--r--json-writer.h4
-rw-r--r--kwset.c2
-rw-r--r--kwset.h2
-rw-r--r--line-log.c100
-rw-r--r--line-log.h2
-rw-r--r--line-range.c3
-rw-r--r--list-objects-filter-options.c24
-rw-r--r--list-objects-filter.c20
-rw-r--r--list-objects.c20
-rw-r--r--list.h2
-rw-r--r--lockfile.h6
-rw-r--r--log-tree.c269
-rw-r--r--log-tree.h20
-rw-r--r--loose.c260
-rw-r--r--loose.h24
-rw-r--r--ls-refs.c19
-rw-r--r--mailinfo.c58
-rw-r--r--mailmap.c21
-rw-r--r--mailmap.h11
-rw-r--r--match-trees.c20
-rw-r--r--mem-pool.c52
-rw-r--r--mem-pool.h6
-rw-r--r--merge-blobs.c4
-rw-r--r--merge-ll.c53
-rw-r--r--merge-ll.h5
-rw-r--r--merge-ort-wrappers.c2
-rw-r--r--merge-ort-wrappers.h2
-rw-r--r--merge-ort.c348
-rw-r--r--merge-ort.h4
-rw-r--r--merge-recursive.c208
-rw-r--r--merge-recursive.h13
-rw-r--r--merge.c13
-rw-r--r--mergetools/vimdiff19
-rw-r--r--mergetools/vscode19
-rw-r--r--midx-write.c1777
-rw-r--r--midx.c2059
-rw-r--r--midx.h63
-rw-r--r--name-hash.c12
-rw-r--r--name-hash.h7
-rw-r--r--negotiator/default.c7
-rw-r--r--negotiator/noop.c13
-rw-r--r--negotiator/skipping.c16
-rw-r--r--notes-cache.c8
-rw-r--r--notes-merge.c14
-rw-r--r--notes-utils.c21
-rw-r--r--notes-utils.h2
-rw-r--r--notes.c65
-rw-r--r--notes.h8
-rw-r--r--object-file-convert.c279
-rw-r--r--object-file-convert.h24
-rw-r--r--object-file.c525
-rw-r--r--object-file.h6
-rw-r--r--object-name.c235
-rw-r--r--object-name.h5
-rw-r--r--object-store-ll.h22
-rw-r--r--object.c67
-rw-r--r--object.h64
-rw-r--r--oid-array.c14
-rw-r--r--oidmap.h2
-rw-r--r--oidset.c18
-rw-r--r--oidset.h10
-rw-r--r--oidtree.c6
-rw-r--r--oidtree.h2
-rw-r--r--oss-fuzz/.gitignore2
-rw-r--r--oss-fuzz/dummy-cmd-main.c14
-rw-r--r--oss-fuzz/fuzz-commit-graph.c8
-rw-r--r--oss-fuzz/fuzz-config.c33
-rw-r--r--oss-fuzz/fuzz-date.c49
-rw-r--r--pack-bitmap-write.c543
-rw-r--r--pack-bitmap.c746
-rw-r--r--pack-bitmap.h78
-rw-r--r--pack-check.c8
-rw-r--r--pack-objects.c17
-rw-r--r--pack-objects.h1
-rw-r--r--pack-revindex.c73
-rw-r--r--pack-revindex.h3
-rw-r--r--pack-write.c58
-rw-r--r--pack.h4
-rw-r--r--packfile.c96
-rw-r--r--packfile.h48
-rw-r--r--pager.c61
-rw-r--r--pager.h1
-rw-r--r--parallel-checkout.c10
-rw-r--r--parse-options-cb.c9
-rw-r--r--parse-options.c389
-rw-r--r--parse-options.h5
-rw-r--r--parse.c211
-rw-r--r--parse.h21
-rw-r--r--patch-ids.c1
-rw-r--r--path.c172
-rw-r--r--path.h175
-rw-r--r--pathspec.c52
-rw-r--r--pathspec.h2
-rw-r--r--perl/FromCPAN/Error.pm2
-rw-r--r--perl/Git.pm20
-rw-r--r--perl/Git/I18N.pm4
-rw-r--r--perl/Git/LoadCPAN.pm2
-rw-r--r--perl/Git/LoadCPAN/Error.pm2
-rw-r--r--perl/Git/LoadCPAN/Mail/Address.pm2
-rw-r--r--perl/Git/Packet.pm2
-rw-r--r--perl/Git/SVN.pm4
-rw-r--r--pkt-line.c37
-rw-r--r--pkt-line.h5
-rw-r--r--po/README.md2
-rw-r--r--po/TEAMS27
-rw-r--r--po/bg.po3365
-rw-r--r--po/ca.po8780
-rw-r--r--po/de.po2425
-rw-r--r--po/fr.po2615
-rw-r--r--po/id.po2979
-rw-r--r--po/sv.po5457
-rw-r--r--po/tr.po2389
-rw-r--r--po/uk.po2274
-rw-r--r--po/vi.po10804
-rw-r--r--po/zh_CN.po2894
-rw-r--r--po/zh_TW.po4159
-rw-r--r--preload-index.c5
-rw-r--r--pretty.c175
-rw-r--r--pretty.h13
-rw-r--r--progress.c4
-rw-r--r--promisor-remote.c11
-rw-r--r--promisor-remote.h2
-rw-r--r--prompt.c4
-rw-r--r--protocol-caps.c6
-rw-r--r--protocol.c2
-rw-r--r--protocol.h2
-rw-r--r--prune-packed.c6
-rw-r--r--pseudo-merge.c784
-rw-r--r--pseudo-merge.h218
-rw-r--r--range-diff.c14
-rw-r--r--range-diff.h6
-rw-r--r--reachable.c60
-rw-r--r--read-cache-ll.h18
-rw-r--r--read-cache.c205
-rw-r--r--rebase-interactive.c33
-rw-r--r--rebase-interactive.h9
-rw-r--r--rebase.c4
-rw-r--r--ref-filter.c712
-rw-r--r--ref-filter.h51
-rw-r--r--reflog-walk.c37
-rw-r--r--reflog-walk.h4
-rw-r--r--reflog.c35
-rw-r--r--refs.c1298
-rw-r--r--refs.h365
-rw-r--r--refs/debug.c73
-rw-r--r--refs/files-backend.c1294
-rw-r--r--refs/iterator.c77
-rw-r--r--refs/packed-backend.c190
-rw-r--r--refs/packed-backend.h13
-rw-r--r--refs/ref-cache.c18
-rw-r--r--refs/ref-cache.h4
-rw-r--r--refs/refs-internal.h158
-rw-r--r--refs/reftable-backend.c2507
-rw-r--r--refspec.c41
-rw-r--r--refspec.h7
-rw-r--r--reftable/basics.c206
-rw-r--r--reftable/basics.h115
-rw-r--r--reftable/basics_test.c98
-rw-r--r--reftable/block.c490
-rw-r--r--reftable/block.h73
-rw-r--r--reftable/block_test.c125
-rw-r--r--reftable/blocksource.c114
-rw-r--r--reftable/blocksource.h7
-rw-r--r--reftable/constants.h1
-rw-r--r--reftable/dump.c107
-rw-r--r--reftable/error.c8
-rw-r--r--reftable/generic.c180
-rw-r--r--reftable/generic.h32
-rw-r--r--reftable/iter.c173
-rw-r--r--reftable/iter.h48
-rw-r--r--reftable/merged.c358
-rw-r--r--reftable/merged.h19
-rw-r--r--reftable/merged_test.c468
-rw-r--r--reftable/pq.c75
-rw-r--r--reftable/pq.h19
-rw-r--r--reftable/pq_test.c79
-rw-r--r--reftable/publicbasics.c65
-rw-r--r--reftable/reader.c708
-rw-r--r--reftable/reader.h11
-rw-r--r--reftable/readwrite_test.c851
-rw-r--r--reftable/record.c746
-rw-r--r--reftable/record.h71
-rw-r--r--reftable/record_test.c419
-rw-r--r--reftable/refname.c209
-rw-r--r--reftable/refname.h29
-rw-r--r--reftable/refname_test.c102
-rw-r--r--reftable/reftable-basics.h18
-rw-r--r--reftable/reftable-error.h11
-rw-r--r--reftable/reftable-generic.h47
-rw-r--r--reftable/reftable-iterator.h21
-rw-r--r--reftable/reftable-malloc.h18
-rw-r--r--reftable/reftable-merged.h37
-rw-r--r--reftable/reftable-reader.h71
-rw-r--r--reftable/reftable-record.h26
-rw-r--r--reftable/reftable-stack.h36
-rw-r--r--reftable/reftable-tests.h23
-rw-r--r--reftable/reftable-writer.h37
-rw-r--r--reftable/stack.c1626
-rw-r--r--reftable/stack.h14
-rw-r--r--reftable/stack_test.c979
-rw-r--r--reftable/system.h5
-rw-r--r--reftable/test_framework.c23
-rw-r--r--reftable/test_framework.h53
-rw-r--r--reftable/tree.c57
-rw-r--r--reftable/tree.h21
-rw-r--r--reftable/tree_test.c62
-rw-r--r--reftable/writer.c461
-rw-r--r--reftable/writer.h5
-rw-r--r--remote-curl.c125
-rw-r--r--remote.c332
-rw-r--r--remote.h38
-rw-r--r--replace-object.c13
-rw-r--r--repo-settings.c43
-rw-r--r--repo-settings.h75
-rw-r--r--repository.c153
-rw-r--r--repository.h89
-rw-r--r--rerere.c32
-rw-r--r--reset.c39
-rw-r--r--reset.h2
-rw-r--r--resolve-undo.c106
-rw-r--r--resolve-undo.h7
-rw-r--r--revision.c322
-rw-r--r--revision.h25
-rw-r--r--run-command.c60
-rw-r--r--run-command.h14
-rw-r--r--scalar.c40
-rw-r--r--send-pack.c89
-rw-r--r--sequencer.c1038
-rw-r--r--sequencer.h20
-rw-r--r--serve.c20
-rw-r--r--server-info.c37
-rw-r--r--setup.c630
-rw-r--r--setup.h21
-rw-r--r--sh-i18n--envsubst.c4
-rw-r--r--sha1/openssl.h2
-rw-r--r--sha1dc/sha1.c2
-rw-r--r--sha1dc_git.h3
-rw-r--r--shallow.c58
-rw-r--r--shared.mak8
-rw-r--r--shell.c7
-rw-r--r--sideband.c28
-rw-r--r--simple-ipc.h17
-rw-r--r--sparse-index.c260
-rw-r--r--sparse-index.h7
-rw-r--r--split-index.c10
-rw-r--r--split-index.h2
-rw-r--r--statinfo.c49
-rw-r--r--statinfo.h8
-rw-r--r--strbuf.c86
-rw-r--r--strbuf.h27
-rw-r--r--streaming.c3
-rw-r--r--strvec.c42
-rw-r--r--strvec.h33
-rw-r--r--submodule-config.c187
-rw-r--r--submodule-config.h8
-rw-r--r--submodule.c91
-rw-r--r--submodule.h6
-rw-r--r--t/.gitattributes2
-rw-r--r--t/Makefile61
-rw-r--r--t/README124
-rw-r--r--t/annotate-tests.sh2
-rw-r--r--t/chainlint-cat.pl29
-rwxr-xr-xt/chainlint.pl95
-rw-r--r--t/chainlint/arithmetic-expansion.expect18
-rw-r--r--t/chainlint/arithmetic-expansion.test2
-rw-r--r--t/chainlint/bash-array.expect20
-rw-r--r--t/chainlint/bash-array.test2
-rw-r--r--t/chainlint/blank-line-before-esac.expect36
-rw-r--r--t/chainlint/blank-line-before-esac.test2
-rw-r--r--t/chainlint/blank-line.expect12
-rw-r--r--t/chainlint/blank-line.test2
-rw-r--r--t/chainlint/block-comment.expect16
-rw-r--r--t/chainlint/block-comment.test2
-rw-r--r--t/chainlint/block.expect46
-rw-r--r--t/chainlint/block.test2
-rw-r--r--t/chainlint/broken-chain.expect12
-rw-r--r--t/chainlint/broken-chain.test2
-rw-r--r--t/chainlint/case-comment.expect22
-rw-r--r--t/chainlint/case-comment.test2
-rw-r--r--t/chainlint/case.expect38
-rw-r--r--t/chainlint/case.test2
-rw-r--r--t/chainlint/chain-break-background.expect18
-rw-r--r--t/chainlint/chain-break-background.test2
-rw-r--r--t/chainlint/chain-break-continue.expect24
-rw-r--r--t/chainlint/chain-break-continue.test2
-rw-r--r--t/chainlint/chain-break-false.expect18
-rw-r--r--t/chainlint/chain-break-false.test2
-rw-r--r--t/chainlint/chain-break-return-exit.expect38
-rw-r--r--t/chainlint/chain-break-return-exit.test2
-rw-r--r--t/chainlint/chain-break-status.expect18
-rw-r--r--t/chainlint/chain-break-status.test2
-rw-r--r--t/chainlint/chained-block.expect18
-rw-r--r--t/chainlint/chained-block.test2
-rw-r--r--t/chainlint/chained-subshell.expect20
-rw-r--r--t/chainlint/chained-subshell.test2
-rw-r--r--t/chainlint/close-nested-and-parent-together.expect6
-rw-r--r--t/chainlint/close-nested-and-parent-together.test2
-rw-r--r--t/chainlint/close-subshell.expect52
-rw-r--r--t/chainlint/close-subshell.test2
-rw-r--r--t/chainlint/command-substitution-subsubshell.expect4
-rw-r--r--t/chainlint/command-substitution-subsubshell.test2
-rw-r--r--t/chainlint/command-substitution.expect18
-rw-r--r--t/chainlint/command-substitution.test2
-rw-r--r--t/chainlint/comment.expect16
-rw-r--r--t/chainlint/comment.test2
-rw-r--r--t/chainlint/complex-if-in-cuddled-loop.expect18
-rw-r--r--t/chainlint/complex-if-in-cuddled-loop.test2
-rw-r--r--t/chainlint/cuddled-if-then-else.expect12
-rw-r--r--t/chainlint/cuddled-if-then-else.test2
-rw-r--r--t/chainlint/cuddled-loop.expect8
-rw-r--r--t/chainlint/cuddled-loop.test2
-rw-r--r--t/chainlint/cuddled.expect34
-rw-r--r--t/chainlint/cuddled.test2
-rw-r--r--t/chainlint/double-here-doc.expect24
-rw-r--r--t/chainlint/double-here-doc.test2
-rw-r--r--t/chainlint/dqstring-line-splice.expect8
-rw-r--r--t/chainlint/dqstring-line-splice.test2
-rw-r--r--t/chainlint/dqstring-no-interpolate.expect23
-rw-r--r--t/chainlint/dqstring-no-interpolate.test2
-rw-r--r--t/chainlint/empty-here-doc.expect8
-rw-r--r--t/chainlint/empty-here-doc.test2
-rw-r--r--t/chainlint/exclamation.expect8
-rw-r--r--t/chainlint/exclamation.test2
-rw-r--r--t/chainlint/exit-loop.expect48
-rw-r--r--t/chainlint/exit-loop.test2
-rw-r--r--t/chainlint/exit-subshell.expect10
-rw-r--r--t/chainlint/exit-subshell.test2
-rw-r--r--t/chainlint/for-loop-abbreviated.expect10
-rw-r--r--t/chainlint/for-loop-abbreviated.test2
-rw-r--r--t/chainlint/for-loop.expect27
-rw-r--r--t/chainlint/for-loop.test2
-rw-r--r--t/chainlint/function.expect22
-rw-r--r--t/chainlint/function.test2
-rw-r--r--t/chainlint/here-doc-body-indent.expect2
-rw-r--r--t/chainlint/here-doc-body-indent.test4
-rw-r--r--t/chainlint/here-doc-body-pathological.expect7
-rw-r--r--t/chainlint/here-doc-body-pathological.test9
-rw-r--r--t/chainlint/here-doc-body.expect7
-rw-r--r--t/chainlint/here-doc-body.test9
-rw-r--r--t/chainlint/here-doc-close-subshell.expect8
-rw-r--r--t/chainlint/here-doc-close-subshell.test2
-rw-r--r--t/chainlint/here-doc-double.expect2
-rw-r--r--t/chainlint/here-doc-double.test10
-rw-r--r--t/chainlint/here-doc-indent-operator.expect22
-rw-r--r--t/chainlint/here-doc-indent-operator.test2
-rw-r--r--t/chainlint/here-doc-multi-line-command-subst.expect16
-rw-r--r--t/chainlint/here-doc-multi-line-command-subst.test2
-rw-r--r--t/chainlint/here-doc-multi-line-string.expect14
-rw-r--r--t/chainlint/here-doc-multi-line-string.test2
-rw-r--r--t/chainlint/here-doc.expect50
-rw-r--r--t/chainlint/here-doc.test2
-rw-r--r--t/chainlint/if-condition-split.expect14
-rw-r--r--t/chainlint/if-condition-split.test2
-rw-r--r--t/chainlint/if-in-loop.expect24
-rw-r--r--t/chainlint/if-in-loop.test2
-rw-r--r--t/chainlint/if-then-else.expect44
-rw-r--r--t/chainlint/if-then-else.test2
-rw-r--r--t/chainlint/incomplete-line.expect20
-rw-r--r--t/chainlint/incomplete-line.test2
-rw-r--r--t/chainlint/inline-comment.expect16
-rw-r--r--t/chainlint/inline-comment.test2
-rw-r--r--t/chainlint/loop-detect-failure.expect30
-rw-r--r--t/chainlint/loop-detect-failure.test2
-rw-r--r--t/chainlint/loop-detect-status.expect36
-rw-r--r--t/chainlint/loop-detect-status.test2
-rw-r--r--t/chainlint/loop-in-if.expect24
-rw-r--r--t/chainlint/loop-in-if.test2
-rw-r--r--t/chainlint/loop-upstream-pipe.expect20
-rw-r--r--t/chainlint/loop-upstream-pipe.test2
-rw-r--r--t/chainlint/multi-line-nested-command-substitution.expect36
-rw-r--r--t/chainlint/multi-line-nested-command-substitution.test2
-rw-r--r--t/chainlint/multi-line-string.expect28
-rw-r--r--t/chainlint/multi-line-string.test2
-rw-r--r--t/chainlint/negated-one-liner.expect10
-rw-r--r--t/chainlint/negated-one-liner.test2
-rw-r--r--t/chainlint/nested-cuddled-subshell.expect44
-rw-r--r--t/chainlint/nested-cuddled-subshell.test2
-rw-r--r--t/chainlint/nested-here-doc.expect60
-rw-r--r--t/chainlint/nested-here-doc.test2
-rw-r--r--t/chainlint/nested-loop-detect-failure.expect62
-rw-r--r--t/chainlint/nested-loop-detect-failure.test2
-rw-r--r--t/chainlint/nested-subshell-comment.expect22
-rw-r--r--t/chainlint/nested-subshell-comment.test2
-rw-r--r--t/chainlint/nested-subshell.expect25
-rw-r--r--t/chainlint/nested-subshell.test2
-rw-r--r--t/chainlint/not-heredoc.expect28
-rw-r--r--t/chainlint/not-heredoc.test2
-rw-r--r--t/chainlint/one-liner-for-loop.expect18
-rw-r--r--t/chainlint/one-liner-for-loop.test2
-rw-r--r--t/chainlint/one-liner.expect18
-rw-r--r--t/chainlint/one-liner.test2
-rw-r--r--t/chainlint/p4-filespec.expect8
-rw-r--r--t/chainlint/p4-filespec.test2
-rw-r--r--t/chainlint/pipe.expect18
-rw-r--r--t/chainlint/pipe.test2
-rw-r--r--t/chainlint/return-loop.expect10
-rw-r--r--t/chainlint/return-loop.test2
-rw-r--r--t/chainlint/semicolon.expect38
-rw-r--r--t/chainlint/semicolon.test2
-rw-r--r--t/chainlint/sqstring-in-sqstring.expect8
-rw-r--r--t/chainlint/sqstring-in-sqstring.test2
-rw-r--r--t/chainlint/subshell-here-doc.expect60
-rw-r--r--t/chainlint/subshell-here-doc.test2
-rw-r--r--t/chainlint/subshell-one-liner.expect33
-rw-r--r--t/chainlint/subshell-one-liner.test2
-rw-r--r--t/chainlint/t7900-subtree.expect43
-rw-r--r--t/chainlint/t7900-subtree.test2
-rw-r--r--t/chainlint/token-pasting.expect54
-rw-r--r--t/chainlint/token-pasting.test2
-rw-r--r--t/chainlint/unclosed-here-doc-indent.expect8
-rw-r--r--t/chainlint/unclosed-here-doc-indent.test2
-rw-r--r--t/chainlint/unclosed-here-doc.expect14
-rw-r--r--t/chainlint/unclosed-here-doc.test2
-rw-r--r--t/chainlint/while-loop.expect27
-rw-r--r--t/chainlint/while-loop.test2
-rwxr-xr-xt/check-non-portable-shell.pl6
-rw-r--r--t/helper/test-advise.c2
-rw-r--r--t/helper/test-bitmap.c36
-rw-r--r--t/helper/test-bloom.c12
-rw-r--r--t/helper/test-bundle-uri.c4
-rw-r--r--t/helper/test-cache-tree.c19
-rw-r--r--t/helper/test-config.c5
-rw-r--r--t/helper/test-ctype.c70
-rw-r--r--t/helper/test-date.c2
-rw-r--r--t/helper/test-delete-gpgsig.c62
-rw-r--r--t/helper/test-dump-cache-tree.c7
-rw-r--r--t/helper/test-dump-fsmonitor.c2
-rw-r--r--t/helper/test-dump-split-index.c13
-rw-r--r--t/helper/test-dump-untracked-cache.c7
-rw-r--r--t/helper/test-env-helper.c2
-rw-r--r--t/helper/test-example-decorate.c78
-rw-r--r--t/helper/test-example-tap.c131
-rw-r--r--t/helper/test-fast-rebase.c241
-rw-r--r--t/helper/test-find-pack.c52
-rw-r--r--t/helper/test-fsmonitor-client.c2
-rw-r--r--t/helper/test-hash-speed.c2
-rw-r--r--t/helper/test-hashmap.c103
-rw-r--r--t/helper/test-index-version.c15
-rw-r--r--t/helper/test-json-writer.c12
-rw-r--r--t/helper/test-lazy-init-name-hash.c41
-rw-r--r--t/helper/test-match-trees.c2
-rw-r--r--t/helper/test-mergesort.c2
-rw-r--r--t/helper/test-oid-array.c45
-rw-r--r--t/helper/test-oidmap.c123
-rw-r--r--t/helper/test-oidtree.c54
-rw-r--r--t/helper/test-pack-mtimes.c2
-rw-r--r--t/helper/test-parse-options.c17
-rw-r--r--t/helper/test-partial-clone.c4
-rw-r--r--t/helper/test-path-utils.c8
-rw-r--r--t/helper/test-pkt-line.c60
-rw-r--r--t/helper/test-prio-queue.c51
-rw-r--r--t/helper/test-proc-receive.c16
-rw-r--r--t/helper/test-progress.c10
-rw-r--r--t/helper/test-reach.c33
-rw-r--r--t/helper/test-read-cache.c13
-rw-r--r--t/helper/test-read-graph.c68
-rw-r--r--t/helper/test-read-midx.c69
-rw-r--r--t/helper/test-ref-store.c60
-rw-r--r--t/helper/test-reftable.c203
-rw-r--r--t/helper/test-regex.c6
-rw-r--r--t/helper/test-repository.c8
-rw-r--r--t/helper/test-revision-walking.c2
-rw-r--r--t/helper/test-rot13-filter.c7
-rw-r--r--t/helper/test-run-command.c28
-rw-r--r--t/helper/test-scrap-cache-tree.c9
-rw-r--r--t/helper/test-sha1.c2
-rw-r--r--t/helper/test-sha256.c2
-rw-r--r--t/helper/test-simple-ipc.c4
-rw-r--r--t/helper/test-strcmp-offset.c23
-rw-r--r--t/helper/test-submodule-config.c4
-rw-r--r--t/helper/test-submodule-nested-repo-config.c4
-rw-r--r--t/helper/test-submodule.c55
-rw-r--r--t/helper/test-tool.c17
-rw-r--r--t/helper/test-tool.h15
-rw-r--r--t/helper/test-trace2.c64
-rw-r--r--t/helper/test-truncate.c25
-rw-r--r--t/helper/test-urlmatch-normalization.c56
-rw-r--r--t/helper/test-userdiff.c2
-rw-r--r--t/helper/test-write-cache.c5
-rw-r--r--t/interop/README7
-rwxr-xr-xt/interop/i5500-git-daemon.sh1
-rw-r--r--t/interop/interop-lib.sh8
-rw-r--r--t/lib-bitmap.sh6
-rw-r--r--t/lib-bundle-uri-protocol.sh4
-rw-r--r--t/lib-bundle.sh2
-rw-r--r--t/lib-chunk.sh18
-rw-r--r--t/lib-chunk/corrupt-chunk-file.pl90
-rw-r--r--t/lib-credential.sh201
-rw-r--r--t/lib-cvs.sh4
-rw-r--r--t/lib-git-svn.sh4
-rw-r--r--t/lib-gitweb.sh4
-rw-r--r--t/lib-gpg.sh4
-rw-r--r--t/lib-httpd.sh34
-rw-r--r--t/lib-httpd/nph-custom-auth.sh17
-rw-r--r--t/lib-httpd/passwd2
-rw-r--r--t/lib-httpd/proxy-passwd2
-rw-r--r--t/lib-midx.sh28
-rw-r--r--t/lib-parallel-checkout.sh2
-rw-r--r--t/lib-rebase.sh27
-rw-r--r--t/lib-submodule-update.sh2
-rw-r--r--t/lib-sudo.sh2
-rwxr-xr-xt/lib-unicode-nfc-nfd.sh2
-rw-r--r--t/oid-info/hash-info12
-rwxr-xr-xt/perf/p1500-graph-walks.sh31
-rwxr-xr-xt/perf/p2000-sparse-operations.sh1
-rwxr-xr-xt/perf/p5332-multi-pack-reuse.sh81
-rwxr-xr-xt/perf/p5333-pseudo-merge-bitmaps.sh32
-rwxr-xr-xt/perf/p6300-for-each-ref.sh87
-rwxr-xr-xt/perf/p7527-builtin-fsmonitor.sh2
-rw-r--r--t/perf/perf-lib.sh8
-rwxr-xr-xt/perf/repos/inflate-repo.sh2
-rwxr-xr-xt/perf/run9
-rwxr-xr-xt/run-test.sh18
-rw-r--r--t/socks4-proxy.pl48
-rwxr-xr-xt/t0000-basic.sh4
-rwxr-xr-xt/t0001-init.sh291
-rwxr-xr-xt/t0002-gitfile.sh7
-rwxr-xr-xt/t0003-attributes.sh184
-rwxr-xr-xt/t0004-unwritable.sh1
-rwxr-xr-xt/t0005-signals.sh1
-rwxr-xr-xt/t0006-date.sh61
-rwxr-xr-xt/t0007-git-var.sh3
-rwxr-xr-xt/t0008-ignores.sh13
-rwxr-xr-xt/t0009-prio-queue.sh66
-rwxr-xr-xt/t0010-racy-git.sh32
-rwxr-xr-xt/t0011-hashmap.sh260
-rwxr-xr-xt/t0012-help.sh16
-rwxr-xr-xt/t0013-sha1dc.sh3
-rwxr-xr-xt/t0014-alias.sh19
-rwxr-xr-xt/t0015-hash.sh56
-rwxr-xr-xt/t0016-oidmap.sh112
-rwxr-xr-xt/t0017-env-helper.sh10
-rwxr-xr-xt/t0018-advice.sh72
-rwxr-xr-xt/t0019-json-writer.sh1
-rwxr-xr-xt/t0020-crlf.sh1
-rwxr-xr-xt/t0021-conversion.sh10
-rwxr-xr-xt/t0022-crlf-rename.sh1
-rwxr-xr-xt/t0023-crlf-am.sh1
-rwxr-xr-xt/t0024-crlf-archive.sh14
-rwxr-xr-xt/t0025-crlf-renormalize.sh1
-rwxr-xr-xt/t0026-eol-config.sh1
-rwxr-xr-xt/t0027-auto-crlf.sh1
-rwxr-xr-xt/t0028-working-tree-encoding.sh43
-rwxr-xr-xt/t0029-core-unsetenvvars.sh1
-rwxr-xr-xt/t0030-stripspace.sh16
-rwxr-xr-xt/t0032-reftable-unittest.sh16
-rwxr-xr-xt/t0033-safe-directory.sh194
-rwxr-xr-xt/t0035-safe-bare-repository.sh35
-rwxr-xr-xt/t0040-parse-options.sh111
-rwxr-xr-xt/t0041-usage.sh33
-rwxr-xr-xt/t0050-filesystem.sh1
-rwxr-xr-xt/t0052-simple-ipc.sh1
-rwxr-xr-xt/t0055-beyond-symlinks.sh1
-rwxr-xr-xt/t0056-git-C.sh1
-rwxr-xr-xt/t0060-path-utils.sh1
-rwxr-xr-xt/t0061-run-command.sh7
-rwxr-xr-xt/t0062-revision-walking.sh1
-rwxr-xr-xt/t0063-string-list.sh1
-rwxr-xr-xt/t0064-oid-array.sh104
-rwxr-xr-xt/t0065-strcmp-offset.sh22
-rwxr-xr-xt/t0066-dir-iterator.sh1
-rwxr-xr-xt/t0067-parse_pathspec_file.sh1
-rwxr-xr-xt/t0068-for-each-repo.sh17
-rwxr-xr-xt/t0069-oidtree.sh50
-rwxr-xr-xt/t0070-fundamental.sh67
-rwxr-xr-xt/t0071-sort.sh1
-rwxr-xr-xt/t0080-unit-test-output.sh92
-rwxr-xr-xt/t0081-find-pack.sh81
-rwxr-xr-xt/t0090-cache-tree.sh1
-rwxr-xr-xt/t0091-bugreport.sh14
-rwxr-xr-xt/t0092-diagnose.sh1
-rwxr-xr-xt/t0095-bloom.sh11
-rwxr-xr-xt/t0100-previous.sh1
-rwxr-xr-xt/t0101-at-syntax.sh1
-rwxr-xr-xt/t0110-urlmatch-normalization.sh182
-rw-r--r--t/t0110/README9
-rw-r--r--t/t0110/url-11
-rw-r--r--t/t0110/url-101
-rw-r--r--t/t0110/url-111
-rw-r--r--t/t0110/url-21
-rw-r--r--t/t0110/url-31
-rw-r--r--t/t0110/url-41
-rw-r--r--t/t0110/url-51
-rw-r--r--t/t0110/url-61
-rw-r--r--t/t0110/url-71
-rw-r--r--t/t0110/url-81
-rw-r--r--t/t0110/url-91
-rwxr-xr-xt/t0200-gettext-basic.sh1
-rwxr-xr-xt/t0201-gettext-fallbacks.sh1
-rwxr-xr-xt/t0202-gettext-perl.sh1
-rwxr-xr-xt/t0202/test.pl2
-rwxr-xr-xt/t0203-gettext-setlocale-sanity.sh1
-rwxr-xr-xt/t0204-gettext-reencode-sanity.sh3
-rwxr-xr-xt/t0210-trace2-normal.sh19
-rwxr-xr-xt/t0211-trace2-perf.sh255
-rwxr-xr-xt/t0212-trace2-event.sh41
-rw-r--r--t/t0212/parse_events.perl2
-rwxr-xr-xt/t0300-credentials.sh168
-rwxr-xr-xt/t0301-credential-cache.sh11
-rwxr-xr-xt/t0302-credential-store.sh1
-rwxr-xr-xt/t0303-credential-external.sh28
-rwxr-xr-xt/t0410-partial-clone.sh89
-rwxr-xr-xt/t0411-clone-from-partial.sh18
-rwxr-xr-xt/t0450-txt-doc-vs-help.sh10
-rw-r--r--t/t0450/txt-help-mismatches1
-rwxr-xr-xt/t0500-progress-display.sh1
-rwxr-xr-xt/t0600-reffiles-backend.sh502
-rwxr-xr-xt/t0601-reffiles-pack-refs.sh (renamed from t/t3210-pack-refs.sh)155
-rwxr-xr-xt/t0602-reffiles-fsck.sh599
-rwxr-xr-xt/t0610-reftable-basics.sh1136
-rwxr-xr-xt/t0611-reftable-httpd.sh26
-rwxr-xr-xt/t0612-reftable-jgit-compatibility.sh132
-rwxr-xr-xt/t0613-reftable-write-options.sh286
-rwxr-xr-xt/t1000-read-tree-m-3way.sh1
-rwxr-xr-xt/t1001-read-tree-m-2way.sh3
-rwxr-xr-xt/t1002-read-tree-m-u-2way.sh1
-rwxr-xr-xt/t1003-read-tree-prefix.sh1
-rwxr-xr-xt/t1005-read-tree-reset.sh1
-rwxr-xr-xt/t1006-cat-file.sh447
-rwxr-xr-xt/t1007-hash-object.sh13
-rwxr-xr-xt/t1008-read-tree-overlay.sh1
-rwxr-xr-xt/t1009-read-tree-new-index.sh1
-rwxr-xr-xt/t1010-mktree.sh1
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh1
-rwxr-xr-xt/t1012-read-tree-df.sh1
-rwxr-xr-xt/t1014-read-tree-confusing.sh1
-rwxr-xr-xt/t1015-read-index-unmerged.sh1
-rwxr-xr-xt/t1016-compatObjectFormat.sh278
-rwxr-xr-xt/t1016/gpg2
-rwxr-xr-xt/t1020-subdirectory.sh1
-rwxr-xr-xt/t1022-read-tree-partial-clone.sh1
-rwxr-xr-xt/t1051-large-conversion.sh1
-rwxr-xr-xt/t1060-object-corruption.sh3
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh78
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh168
-rwxr-xr-xt/t1100-commit-tree-options.sh1
-rwxr-xr-xt/t1300-config.sh681
-rwxr-xr-xt/t1301-shared-repo.sh32
-rwxr-xr-xt/t1302-repo-version.sh24
-rwxr-xr-xt/t1303-wacky-config.sh1
-rwxr-xr-xt/t1304-default-acl.sh1
-rwxr-xr-xt/t1305-config-include.sh41
-rwxr-xr-xt/t1307-config-blob.sh3
-rwxr-xr-xt/t1308-config-set.sh11
-rwxr-xr-xt/t1309-early-config.sh3
-rwxr-xr-xt/t1310-config-default.sh5
-rwxr-xr-xt/t1400-update-ref.sh622
-rwxr-xr-xt/t1401-symbolic-ref.sh12
-rwxr-xr-xt/t1402-check-ref-format.sh1
-rwxr-xr-xt/t1403-show-ref.sh115
-rwxr-xr-xt/t1404-update-ref-errors.sh439
-rwxr-xr-xt/t1405-main-ref-store.sh25
-rwxr-xr-xt/t1406-submodule-ref-store.sh9
-rwxr-xr-xt/t1407-worktree-ref-store.sh38
-rwxr-xr-xt/t1408-packed-refs.sh1
-rwxr-xr-xt/t1409-avoid-packing-refs.sh7
-rwxr-xr-xt/t1410-reflog.sh192
-rwxr-xr-xt/t1411-reflog-show.sh1
-rwxr-xr-xt/t1412-reflog-loop.sh1
-rwxr-xr-xt/t1413-reflog-detach.sh1
-rwxr-xr-xt/t1414-reflog-walk.sh11
-rwxr-xr-xt/t1415-worktree-refs.sh12
-rwxr-xr-xt/t1416-ref-transaction-hooks.sh82
-rwxr-xr-xt/t1417-reflog-updateref.sh11
-rwxr-xr-xt/t1418-reflog-exists.sh1
-rwxr-xr-xt/t1419-exclude-refs.sh44
-rwxr-xr-xt/t1420-lost-found.sh1
-rwxr-xr-xt/t1430-bad-ref-name.sh62
-rwxr-xr-xt/t1450-fsck.sh134
-rwxr-xr-xt/t1451-fsck-buffer.sh1
-rwxr-xr-xt/t1460-refs-migrate.sh242
-rwxr-xr-xt/t1500-rev-parse.sh47
-rwxr-xr-xt/t1501-work-tree.sh1
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh143
-rw-r--r--t/t1502/.gitattributes1
-rw-r--r--t/t1502/optionspec-neg8
-rw-r--r--t/t1502/optionspec-neg.help12
-rwxr-xr-xt/t1502/optionspec.help36
-rwxr-xr-xt/t1503-rev-parse-verify.sh6
-rwxr-xr-xt/t1504-ceiling-dirs.sh1
-rwxr-xr-xt/t1505-rev-parse-last.sh1
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh37
-rwxr-xr-xt/t1507-rev-parse-upstream.sh1
-rwxr-xr-xt/t1508-at-combinations.sh1
-rwxr-xr-xt/t1509/prepare-chroot.sh2
-rwxr-xr-xt/t1510-repo-setup.sh1
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh6
-rwxr-xr-xt/t1513-rev-parse-prefix.sh1
-rwxr-xr-xt/t1514-rev-parse-push.sh1
-rwxr-xr-xt/t1515-rev-parse-outside-repo.sh1
-rwxr-xr-xt/t1517-outside-repo.sh110
-rwxr-xr-xt/t1600-index.sh3
-rwxr-xr-xt/t1601-index-bogus.sh1
-rwxr-xr-xt/t1700-split-index.sh4
-rwxr-xr-xt/t1701-racy-split-index.sh1
-rwxr-xr-xt/t1800-hook.sh1
-rwxr-xr-xt/t2000-conflict-when-checking-files-out.sh1
-rwxr-xr-xt/t2002-checkout-cache-u.sh1
-rwxr-xr-xt/t2003-checkout-cache-mkdir.sh1
-rwxr-xr-xt/t2004-checkout-cache-temp.sh23
-rwxr-xr-xt/t2005-checkout-index-symlinks.sh1
-rwxr-xr-xt/t2006-checkout-index-basic.sh15
-rwxr-xr-xt/t2007-checkout-symlink.sh1
-rwxr-xr-xt/t2008-checkout-subdir.sh1
-rwxr-xr-xt/t2009-checkout-statinfo.sh1
-rwxr-xr-xt/t2010-checkout-ambiguous.sh5
-rwxr-xr-xt/t2011-checkout-invalid-head.sh10
-rwxr-xr-xt/t2012-checkout-last.sh1
-rwxr-xr-xt/t2014-checkout-switch.sh1
-rwxr-xr-xt/t2015-checkout-unborn.sh1
-rwxr-xr-xt/t2016-checkout-patch.sh46
-rwxr-xr-xt/t2017-checkout-orphan.sh3
-rwxr-xr-xt/t2018-checkout-branch.sh5
-rwxr-xr-xt/t2019-checkout-ambiguous-ref.sh9
-rwxr-xr-xt/t2020-checkout-detach.sh26
-rwxr-xr-xt/t2021-checkout-overwrite.sh1
-rwxr-xr-xt/t2022-checkout-paths.sh1
-rwxr-xr-xt/t2023-checkout-m.sh1
-rwxr-xr-xt/t2024-checkout-dwim.sh10
-rwxr-xr-xt/t2025-checkout-no-overlay.sh3
-rwxr-xr-xt/t2026-checkout-pathspec-file.sh9
-rwxr-xr-xt/t2027-checkout-track.sh3
-rwxr-xr-xt/t2030-unresolve-info.sh47
-rwxr-xr-xt/t2050-git-dir-relative.sh1
-rwxr-xr-xt/t2060-switch.sh2
-rwxr-xr-xt/t2070-restore.sh71
-rwxr-xr-xt/t2071-restore-patch.sh46
-rwxr-xr-xt/t2072-restore-pathspec-file.sh8
-rwxr-xr-xt/t2081-parallel-checkout-collisions.sh1
-rwxr-xr-xt/t2082-parallel-checkout-attributes.sh4
-rwxr-xr-xt/t2100-update-cache-badpath.sh1
-rwxr-xr-xt/t2101-update-index-reupdate.sh1
-rwxr-xr-xt/t2102-update-index-symlinks.sh1
-rwxr-xr-xt/t2103-update-index-ignore-missing.sh1
-rwxr-xr-xt/t2104-update-index-skip-worktree.sh37
-rwxr-xr-xt/t2105-update-index-gitfile.sh1
-rwxr-xr-xt/t2106-update-index-assume-unchanged.sh3
-rwxr-xr-xt/t2107-update-index-basic.sh35
-rwxr-xr-xt/t2108-update-index-refresh-racy.sh1
-rwxr-xr-xt/t2200-add-update.sh11
-rwxr-xr-xt/t2201-add-update-typechange.sh1
-rwxr-xr-xt/t2202-add-addremove.sh1
-rwxr-xr-xt/t2203-add-intent.sh7
-rwxr-xr-xt/t2204-add-ignored.sh9
-rwxr-xr-xt/t2205-add-worktree-config.sh1
-rwxr-xr-xt/t2300-cd-to-toplevel.sh1
-rwxr-xr-xt/t2400-worktree-add.sh41
-rwxr-xr-xt/t2401-worktree-prune.sh30
-rwxr-xr-xt/t2402-worktree-list.sh7
-rwxr-xr-xt/t2403-worktree-move.sh3
-rwxr-xr-xt/t2404-worktree-config.sh1
-rwxr-xr-xt/t2406-worktree-repair.sh44
-rwxr-xr-xt/t2407-worktree-heads.sh19
-rwxr-xr-xt/t2408-worktree-relative.sh38
-rwxr-xr-xt/t3000-ls-files-others.sh1
-rwxr-xr-xt/t3001-ls-files-others-exclude.sh1
-rwxr-xr-xt/t3002-ls-files-dashpath.sh1
-rwxr-xr-xt/t3003-ls-files-exclude.sh1
-rwxr-xr-xt/t3004-ls-files-basic.sh5
-rwxr-xr-xt/t3005-ls-files-relative.sh1
-rwxr-xr-xt/t3006-ls-files-long.sh1
-rwxr-xr-xt/t3007-ls-files-recurse-submodules.sh4
-rwxr-xr-xt/t3008-ls-files-lazy-init-name-hash.sh1
-rwxr-xr-xt/t3009-ls-files-others-nonsubmodule.sh1
-rwxr-xr-xt/t3010-ls-files-killed-modified.sh1
-rwxr-xr-xt/t3012-ls-files-dedup.sh1
-rwxr-xr-xt/t3013-ls-files-format.sh1
-rwxr-xr-xt/t3020-ls-files-error-unmatch.sh1
-rwxr-xr-xt/t3040-subprojects-basic.sh1
-rwxr-xr-xt/t3050-subprojects-fetch.sh1
-rwxr-xr-xt/t3060-ls-files-with-tree.sh1
-rwxr-xr-xt/t3070-wildmatch.sh1
-rwxr-xr-xt/t3100-ls-tree-restrict.sh1
-rwxr-xr-xt/t3101-ls-tree-dirname.sh1
-rwxr-xr-xt/t3102-ls-tree-wildcards.sh1
-rwxr-xr-xt/t3103-ls-tree-misc.sh1
-rwxr-xr-xt/t3104-ls-tree-format.sh1
-rwxr-xr-xt/t3105-ls-tree-output.sh1
-rwxr-xr-xt/t3200-branch.sh339
-rwxr-xr-xt/t3202-show-branch.sh59
-rwxr-xr-xt/t3203-branch-output.sh1
-rwxr-xr-xt/t3204-branch-name-interpretation.sh1
-rwxr-xr-xt/t3205-branch-color.sh1
-rwxr-xr-xt/t3206-range-diff.sh104
-rwxr-xr-xt/t3211-peel-ref.sh1
-rwxr-xr-xt/t3300-funny-names.sh1
-rwxr-xr-xt/t3301-notes.sh77
-rwxr-xr-xt/t3302-notes-index-expensive.sh1
-rwxr-xr-xt/t3303-notes-subtrees.sh1
-rwxr-xr-xt/t3304-notes-mixed.sh1
-rwxr-xr-xt/t3305-notes-fanout.sh1
-rwxr-xr-xt/t3307-notes-man.sh1
-rwxr-xr-xt/t3310-notes-merge-manual-resolve.sh22
-rwxr-xr-xt/t3320-notes-merge-worktrees.sh5
-rwxr-xr-xt/t3321-notes-stripspace.sh11
-rwxr-xr-xt/t3400-rebase.sh26
-rwxr-xr-xt/t3402-rebase-merge.sh3
-rwxr-xr-xt/t3403-rebase-skip.sh30
-rwxr-xr-xt/t3404-rebase-interactive.sh204
-rwxr-xr-xt/t3405-rebase-malformed.sh1
-rwxr-xr-xt/t3406-rebase-message.sh18
-rwxr-xr-xt/t3407-rebase-abort.sh17
-rwxr-xr-xt/t3408-rebase-multi-line.sh1
-rwxr-xr-xt/t3409-rebase-environ.sh1
-rwxr-xr-xt/t3412-rebase-root.sh1
-rwxr-xr-xt/t3413-rebase-hook.sh5
-rwxr-xr-xt/t3415-rebase-autosquash.sh38
-rwxr-xr-xt/t3416-rebase-onto-threedots.sh1
-rwxr-xr-xt/t3418-rebase-continue.sh6
-rwxr-xr-xt/t3419-rebase-patch-id.sh1
-rwxr-xr-xt/t3420-rebase-autostash.sh50
-rwxr-xr-xt/t3421-rebase-topology-linear.sh1
-rwxr-xr-xt/t3422-rebase-incompatible-options.sh13
-rwxr-xr-xt/t3423-rebase-reword.sh1
-rwxr-xr-xt/t3424-rebase-empty.sh55
-rwxr-xr-xt/t3425-rebase-topology-merges.sh1
-rwxr-xr-xt/t3428-rebase-signoff.sh149
-rwxr-xr-xt/t3429-rebase-edit-todo.sh1
-rwxr-xr-xt/t3430-rebase-merges.sh15
-rwxr-xr-xt/t3431-rebase-fork-point.sh5
-rwxr-xr-xt/t3432-rebase-fast-forward.sh1
-rwxr-xr-xt/t3433-rebase-across-mode-change.sh1
-rwxr-xr-xt/t3434-rebase-i18n.sh8
-rwxr-xr-xt/t3437-rebase-fixup-options.sh1
-rwxr-xr-xt/t3438-rebase-broken-files.sh10
-rwxr-xr-xt/t3501-revert-cherry-pick.sh45
-rwxr-xr-xt/t3502-cherry-pick-merge.sh1
-rwxr-xr-xt/t3503-cherry-pick-root.sh1
-rwxr-xr-xt/t3504-cherry-pick-rerere.sh2
-rwxr-xr-xt/t3505-cherry-pick-empty.sh51
-rwxr-xr-xt/t3506-cherry-pick-ff.sh1
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh10
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh38
-rwxr-xr-xt/t3511-cherry-pick-x.sh1
-rwxr-xr-xt/t3600-rm.sh8
-rwxr-xr-xt/t3601-rm-pathspec-file.sh7
-rwxr-xr-xt/t3650-replay-basics.sh198
-rwxr-xr-xt/t3700-add.sh54
-rwxr-xr-xt/t3701-add-interactive.sh164
-rwxr-xr-xt/t3702-add-edit.sh1
-rwxr-xr-xt/t3703-add-magic-pathspec.sh1
-rwxr-xr-xt/t3704-add-pathspec-file.sh13
-rwxr-xr-xt/t3800-mktag.sh1
-rwxr-xr-xt/t3900-i18n-commit.sh14
-rwxr-xr-xt/t3901-i18n-patch.sh8
-rwxr-xr-xt/t3902-quoted.sh1
-rwxr-xr-xt/t3903-stash.sh102
-rwxr-xr-xt/t3904-stash-patch.sh7
-rwxr-xr-xt/t3905-stash-include-untracked.sh2
-rwxr-xr-xt/t3908-stash-in-worktree.sh1
-rwxr-xr-xt/t3909-stash-pathspec-file.sh6
-rwxr-xr-xt/t3910-mac-os-precompose.sh39
-rwxr-xr-xt/t3920-crlf-messages.sh7
-rwxr-xr-xt/t4000-diff-format.sh1
-rwxr-xr-xt/t4001-diff-rename.sh61
-rwxr-xr-xt/t4002-diff-basic.sh3
-rwxr-xr-xt/t4003-diff-rename-1.sh1
-rwxr-xr-xt/t4004-diff-rename-symlink.sh1
-rwxr-xr-xt/t4005-diff-rename-2.sh1
-rwxr-xr-xt/t4006-diff-mode.sh1
-rwxr-xr-xt/t4007-rename-3.sh1
-rwxr-xr-xt/t4008-diff-break-rewrite.sh1
-rwxr-xr-xt/t4009-diff-rename-4.sh1
-rwxr-xr-xt/t4010-diff-pathspec.sh1
-rwxr-xr-xt/t4011-diff-symlink.sh5
-rwxr-xr-xt/t4012-diff-binary.sh1
-rwxr-xr-xt/t4013-diff-various.sh100
-rwxr-xr-xt/t4014-format-patch.sh166
-rwxr-xr-xt/t4015-diff-whitespace.sh30
-rwxr-xr-xt/t4016-diff-quote.sh1
-rwxr-xr-xt/t4017-diff-retval.sh46
-rwxr-xr-xt/t4018-diff-funcname.sh14
-rw-r--r--t/t4018/csharp-exclude-assignments20
-rw-r--r--t/t4018/csharp-exclude-control-statements34
-rw-r--r--t/t4018/csharp-exclude-exceptions29
-rw-r--r--t/t4018/csharp-exclude-generic-method-calls12
-rw-r--r--t/t4018/csharp-exclude-init-dispose22
-rw-r--r--t/t4018/csharp-exclude-iterations26
-rw-r--r--t/t4018/csharp-exclude-method-calls20
-rw-r--r--t/t4018/csharp-exclude-other18
-rw-r--r--t/t4018/csharp-method10
-rw-r--r--t/t4018/csharp-method-array10
-rw-r--r--t/t4018/csharp-method-explicit12
-rw-r--r--t/t4018/csharp-method-generics11
-rw-r--r--t/t4018/csharp-method-generics-alternate-spaces11
-rw-r--r--t/t4018/csharp-method-modifiers13
-rw-r--r--t/t4018/csharp-method-multiline10
-rw-r--r--t/t4018/csharp-method-params10
-rw-r--r--t/t4018/csharp-method-special-chars11
-rw-r--r--t/t4018/csharp-method-with-spacing10
-rw-r--r--t/t4018/csharp-property11
-rw-r--r--t/t4018/csharp-property-braces-same-line10
-rwxr-xr-xt/t4019-diff-wserror.sh1
-rwxr-xr-xt/t4020-diff-external.sh73
-rwxr-xr-xt/t4021-format-patch-numbered.sh1
-rwxr-xr-xt/t4024-diff-optimize-common.sh1
-rwxr-xr-xt/t4025-hunk-header.sh1
-rwxr-xr-xt/t4026-color.sh27
-rwxr-xr-xt/t4027-diff-submodule.sh1
-rwxr-xr-xt/t4028-format-patch-mime-headers.sh1
-rwxr-xr-xt/t4029-diff-trailing-space.sh1
-rwxr-xr-xt/t4030-diff-textconv.sh1
-rwxr-xr-xt/t4031-diff-rewrite-binary.sh2
-rwxr-xr-xt/t4032-diff-inter-hunk-context.sh1
-rwxr-xr-xt/t4033-diff-patience.sh1
-rwxr-xr-xt/t4034-diff-words.sh3
-rwxr-xr-xt/t4035-diff-quiet.sh1
-rwxr-xr-xt/t4036-format-patch-signer-mime.sh1
-rwxr-xr-xt/t4037-diff-r-t-dirs.sh1
-rwxr-xr-xt/t4039-diff-assume-unchanged.sh1
-rwxr-xr-xt/t4040-whitespace-status.sh1
-rwxr-xr-xt/t4041-diff-submodule-option.sh16
-rwxr-xr-xt/t4042-diff-textconv-caching.sh23
-rwxr-xr-xt/t4044-diff-index-unique-abbrev.sh1
-rwxr-xr-xt/t4045-diff-relative.sh1
-rwxr-xr-xt/t4046-diff-unmerged.sh25
-rwxr-xr-xt/t4047-diff-dirstat.sh23
-rwxr-xr-xt/t4049-diff-stat-count.sh1
-rwxr-xr-xt/t4050-diff-histogram.sh1
-rwxr-xr-xt/t4051-diff-function-context.sh1
-rwxr-xr-xt/t4052-stat-output.sh98
-rwxr-xr-xt/t4053-diff-no-index.sh15
-rwxr-xr-xt/t4054-diff-bogus-tree.sh1
-rwxr-xr-xt/t4055-diff-context.sh5
-rwxr-xr-xt/t4057-diff-combined-paths.sh1
-rwxr-xr-xt/t4058-diff-duplicates.sh18
-rwxr-xr-xt/t4059-diff-submodule-not-initialized.sh16
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh17
-rwxr-xr-xt/t4062-diff-pickaxe.sh1
-rwxr-xr-xt/t4063-diff-blobs.sh1
-rwxr-xr-xt/t4064-diff-oidfind.sh1
-rwxr-xr-xt/t4066-diff-emit-delay.sh1
-rwxr-xr-xt/t4067-diff-partial-clone.sh1
-rwxr-xr-xt/t4068-diff-symmetric-merge-base.sh37
-rwxr-xr-xt/t4069-remerge-diff.sh35
-rwxr-xr-xt/t4100-apply-stat.sh1
-rwxr-xr-xt/t4101-apply-nonl.sh1
-rwxr-xr-xt/t4102-apply-rename.sh1
-rwxr-xr-xt/t4105-apply-fuzz.sh1
-rwxr-xr-xt/t4106-apply-stdin.sh1
-rwxr-xr-xt/t4107-apply-ignore-whitespace.sh3
-rwxr-xr-xt/t4108-apply-threeway.sh40
-rwxr-xr-xt/t4109-apply-multifrag.sh1
-rwxr-xr-xt/t4110-apply-scan.sh1
-rwxr-xr-xt/t4111-apply-subdir.sh1
-rwxr-xr-xt/t4112-apply-renames.sh1
-rwxr-xr-xt/t4114-apply-typechange.sh1
-rwxr-xr-xt/t4115-apply-symlink.sh3
-rwxr-xr-xt/t4116-apply-reverse.sh1
-rwxr-xr-xt/t4118-apply-empty-context.sh1
-rwxr-xr-xt/t4119-apply-config.sh1
-rwxr-xr-xt/t4120-apply-popt.sh4
-rwxr-xr-xt/t4121-apply-diffs.sh1
-rwxr-xr-xt/t4122-apply-symlink-inside.sh15
-rwxr-xr-xt/t4126-apply-empty.sh25
-rwxr-xr-xt/t4127-apply-same-fn.sh1
-rwxr-xr-xt/t4128-apply-root.sh1
-rwxr-xr-xt/t4129-apply-samemode.sh100
-rwxr-xr-xt/t4130-apply-criss-cross-rename.sh1
-rwxr-xr-xt/t4132-apply-removal.sh1
-rwxr-xr-xt/t4133-apply-filenames.sh9
-rwxr-xr-xt/t4134-apply-submodule.sh1
-rwxr-xr-xt/t4135-apply-weird-filenames.sh1
-rwxr-xr-xt/t4136-apply-check.sh1
-rwxr-xr-xt/t4139-apply-escape.sh1
-rwxr-xr-xt/t4140-apply-ita.sh1
-rwxr-xr-xt/t4141-apply-too-large.sh1
-rwxr-xr-xt/t4150-am.sh12
-rwxr-xr-xt/t4151-am-abort.sh2
-rwxr-xr-xt/t4152-am-subjects.sh1
-rwxr-xr-xt/t4153-am-resume-override-opts.sh16
-rwxr-xr-xt/t4200-rerere.sh67
-rwxr-xr-xt/t4201-shortlog.sh46
-rwxr-xr-xt/t4202-log.sh55
-rwxr-xr-xt/t4203-mailmap.sh44
-rwxr-xr-xt/t4204-patch-id.sh34
-rwxr-xr-xt/t4205-log-pretty-formats.sh207
-rwxr-xr-xt/t4206-log-follow-harder-copies.sh1
-rwxr-xr-xt/t4207-log-decoration-colors.sh55
-rwxr-xr-xt/t4208-log-magic-pathspec.sh6
-rwxr-xr-xt/t4209-log-pickaxe.sh5
-rwxr-xr-xt/t4210-log-i18n.sh11
-rwxr-xr-xt/t4211-line-log.sh32
-rwxr-xr-xt/t4212-log-corrupt.sh3
-rwxr-xr-xt/t4213-log-tabexpand.sh1
-rwxr-xr-xt/t4216-log-bloom.sh373
-rwxr-xr-xt/t4217-log-limit.sh1
-rwxr-xr-xt/t4252-am-options.sh1
-rwxr-xr-xt/t4254-am-corrupt.sh9
-rwxr-xr-xt/t4256-am-format-flowed.sh3
-rwxr-xr-xt/t4257-am-interactive.sh1
-rwxr-xr-xt/t4300-merge-tree.sh28
-rwxr-xr-xt/t4301-merge-tree-write-tree.sh78
-rwxr-xr-xt/t5000-tar-tree.sh22
-rwxr-xr-xt/t5001-archive-attr.sh6
-rwxr-xr-xt/t5002-archive-attr-pattern.sh1
-rwxr-xr-xt/t5003-archive-zip.sh34
-rwxr-xr-xt/t5004-archive-corner-cases.sh1
-rwxr-xr-xt/t5100-mailinfo.sh38
-rw-r--r--t/t5100/comment.expect2
-rw-r--r--t/t5100/comment.in2
-rwxr-xr-xt/t5200-update-server-info.sh9
-rwxr-xr-xt/t5300-pack-object.sh99
-rwxr-xr-xt/t5301-sliding-window.sh1
-rwxr-xr-xt/t5302-pack-index.sh5
-rwxr-xr-xt/t5303-pack-corruption-resilience.sh10
-rwxr-xr-xt/t5304-prune.sh4
-rwxr-xr-xt/t5306-pack-nobase.sh1
-rwxr-xr-xt/t5307-pack-missing-commit.sh1
-rwxr-xr-xt/t5308-pack-detect-duplicates.sh1
-rwxr-xr-xt/t5309-pack-delta-cycles.sh1
-rwxr-xr-xt/t5310-pack-bitmaps.sh24
-rwxr-xr-xt/t5311-pack-bitmaps-shallow.sh1
-rwxr-xr-xt/t5312-prune-corruption.sh27
-rwxr-xr-xt/t5313-pack-bounds-checks.sh9
-rwxr-xr-xt/t5314-pack-cycle-detection.sh1
-rwxr-xr-xt/t5315-pack-objects-compression.sh1
-rwxr-xr-xt/t5316-pack-delta-depth.sh1
-rwxr-xr-xt/t5317-pack-objects-filter-objects.sh11
-rwxr-xr-xt/t5318-commit-graph.sh151
-rwxr-xr-xt/t5319-multi-pack-index.sh272
-rwxr-xr-xt/t5320-delta-islands.sh1
-rwxr-xr-xt/t5321-pack-large-objects.sh1
-rwxr-xr-xt/t5322-pack-objects-sparse.sh1
-rwxr-xr-xt/t5324-split-commit-graph.sh132
-rwxr-xr-xt/t5325-reverse-index.sh1
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh73
-rwxr-xr-xt/t5327-multi-pack-bitmaps-rev.sh6
-rwxr-xr-xt/t5328-commit-graph-64bit-time.sh11
-rwxr-xr-xt/t5329-pack-objects-cruft.sh57
-rwxr-xr-xt/t5330-no-lazy-fetch-with-commit-graph.sh5
-rwxr-xr-xt/t5331-pack-objects-stdin.sh5
-rwxr-xr-xt/t5332-multi-pack-reuse.sh283
-rwxr-xr-xt/t5333-pseudo-merge-bitmaps.sh449
-rwxr-xr-xt/t5334-incremental-multi-pack-index.sh47
-rwxr-xr-xt/t5351-unpack-large-objects.sh1
-rwxr-xr-xt/t5401-update-hooks.sh9
-rwxr-xr-xt/t5402-post-merge-hook.sh1
-rwxr-xr-xt/t5403-post-checkout-hook.sh1
-rwxr-xr-xt/t5404-tracking-branches.sh1
-rwxr-xr-xt/t5405-send-pack-rewind.sh1
-rwxr-xr-xt/t5406-remote-rejects.sh1
-rwxr-xr-xt/t5408-send-pack-stdin.sh1
-rwxr-xr-xt/t5410-receive-pack-alternates.sh1
-rw-r--r--t/t5411/test-0026-push-options.sh2
-rw-r--r--t/t5411/test-0027-push-options--porcelain.sh2
-rw-r--r--t/t5411/test-0034-report-ft.sh2
-rw-r--r--t/t5411/test-0035-report-ft--porcelain.sh2
-rwxr-xr-xt/t5500-fetch-pack.sh83
-rwxr-xr-xt/t5502-quickfetch.sh1
-rwxr-xr-xt/t5503-tagfollow.sh1
-rwxr-xr-xt/t5504-fetch-receive-strict.sh27
-rwxr-xr-xt/t5505-remote.sh58
-rwxr-xr-xt/t5506-remote-groups.sh1
-rwxr-xr-xt/t5507-remote-environment.sh1
-rwxr-xr-xt/t5509-fetch-push-namespaces.sh9
-rwxr-xr-xt/t5510-fetch.sh36
-rwxr-xr-xt/t5511-refspec.sh1
-rwxr-xr-xt/t5512-ls-remote.sh48
-rwxr-xr-xt/t5513-fetch-track.sh1
-rwxr-xr-xt/t5514-fetch-multiple.sh165
-rwxr-xr-xt/t5515-fetch-merge-logic.sh1
-rwxr-xr-xt/t5516-fetch-push.sh18
-rwxr-xr-xt/t5517-push-mirror.sh1
-rwxr-xr-xt/t5518-fetch-exit-status.sh1
-rwxr-xr-xt/t5520-pull.sh34
-rwxr-xr-xt/t5521-pull-options.sh6
-rwxr-xr-xt/t5522-pull-symlink.sh1
-rwxr-xr-xt/t5523-push-upstream.sh17
-rwxr-xr-xt/t5524-pull-msg.sh1
-rwxr-xr-xt/t5525-fetch-tagopt.sh1
-rwxr-xr-xt/t5526-fetch-submodules.sh2
-rwxr-xr-xt/t5527-fetch-odd-refs.sh1
-rwxr-xr-xt/t5528-push-default.sh4
-rwxr-xr-xt/t5529-push-errors.sh18
-rwxr-xr-xt/t5530-upload-pack-error.sh4
-rwxr-xr-xt/t5531-deep-submodule-push.sh4
-rwxr-xr-xt/t5532-fetch-proxy.sh1
-rwxr-xr-xt/t5534-push-signed.sh8
-rwxr-xr-xt/t5536-fetch-conflicts.sh8
-rwxr-xr-xt/t5541-http-push-smart.sh38
-rwxr-xr-xt/t5544-pack-objects-hook.sh1
-rwxr-xr-xt/t5545-push-options.sh2
-rwxr-xr-xt/t5546-receive-limits.sh1
-rwxr-xr-xt/t5547-push-quarantine.sh1
-rwxr-xr-xt/t5550-http-fetch-dumb.sh65
-rwxr-xr-xt/t5551-http-fetch-smart.sh49
-rwxr-xr-xt/t5552-skipping-fetch-negotiator.sh1
-rwxr-xr-xt/t5553-set-upstream.sh8
-rwxr-xr-xt/t5554-noop-fetch-negotiator.sh1
-rwxr-xr-xt/t5555-http-smart-common.sh2
-rwxr-xr-xt/t5557-http-get.sh1
-rwxr-xr-xt/t5558-clone-bundle-uri.sh209
-rwxr-xr-xt/t5560-http-backend-noserver.sh1
-rwxr-xr-xt/t5561-http-backend.sh1
-rwxr-xr-xt/t5562-http-backend-content-length.sh1
-rw-r--r--t/t5562/invoke-with-content-length.pl2
-rwxr-xr-xt/t5563-simple-http-auth.sh424
-rwxr-xr-xt/t5564-http-proxy.sh55
-rwxr-xr-xt/t5570-git-daemon.sh35
-rwxr-xr-xt/t5571-pre-push-hook.sh1
-rwxr-xr-xt/t5572-pull-submodule.sh22
-rwxr-xr-xt/t5573-pull-verify-signatures.sh27
-rwxr-xr-xt/t5574-fetch-output.sh93
-rwxr-xr-xt/t5580-unc-paths.sh3
-rwxr-xr-xt/t5582-fetch-negative-refspec.sh4
-rwxr-xr-xt/t5583-push-branches.sh1
-rwxr-xr-xt/t5600-clone-fail-cleanup.sh1
-rwxr-xr-xt/t5601-clone.sh77
-rwxr-xr-xt/t5602-clone-remote-exec.sh1
-rwxr-xr-xt/t5603-clone-dirname.sh1
-rwxr-xr-xt/t5604-clone-reference.sh3
-rwxr-xr-xt/t5605-clone-local.sh8
-rwxr-xr-xt/t5606-clone-options.sh19
-rwxr-xr-xt/t5607-clone-bundle.sh39
-rwxr-xr-xt/t5609-clone-branch.sh1
-rwxr-xr-xt/t5610-clone-detached.sh1
-rwxr-xr-xt/t5611-clone-config.sh5
-rwxr-xr-xt/t5613-info-alternate.sh1
-rwxr-xr-xt/t5614-clone-submodules-shallow.sh1
-rwxr-xr-xt/t5615-alternate-env.sh1
-rwxr-xr-xt/t5616-partial-clone.sh58
-rwxr-xr-xt/t5617-clone-submodules-remote.sh1
-rwxr-xr-xt/t5618-alternate-refs.sh1
-rwxr-xr-xt/t5701-git-serve.sh33
-rwxr-xr-xt/t5702-protocol-v2.sh210
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh4
-rwxr-xr-xt/t5704-protocol-violations.sh5
-rwxr-xr-xt/t5705-session-id-in-capabilities.sh1
-rwxr-xr-xt/t5750-bundle-uri-parse.sh1
-rwxr-xr-xt/t5801-remote-helpers.sh42
-rwxr-xr-xt/t5801/git-remote-nourl3
-rwxr-xr-xt/t5801/git-remote-testgit12
-rwxr-xr-xt/t5802-connect-helper.sh1
-rwxr-xr-xt/t5810-proto-disable-local.sh1
-rwxr-xr-xt/t5811-proto-disable-git.sh1
-rwxr-xr-xt/t5812-proto-disable-http.sh3
-rwxr-xr-xt/t5813-proto-disable-ssh.sh1
-rwxr-xr-xt/t5814-proto-disable-ext.sh1
-rwxr-xr-xt/t5815-submodule-protos.sh1
-rwxr-xr-xt/t5900-repo-selection.sh1
-rwxr-xr-xt/t6000-rev-list-misc.sh13
-rwxr-xr-xt/t6001-rev-list-graft.sh4
-rwxr-xr-xt/t6002-rev-list-bisect.sh1
-rwxr-xr-xt/t6003-rev-list-topo-order.sh1
-rwxr-xr-xt/t6005-rev-list-count.sh19
-rwxr-xr-xt/t6006-rev-list-format.sh58
-rwxr-xr-xt/t6008-rev-list-submodule.sh1
-rwxr-xr-xt/t6009-rev-list-parent.sh11
-rwxr-xr-xt/t6011-rev-list-with-bad-commit.sh1
-rwxr-xr-xt/t6014-rev-list-all.sh1
-rwxr-xr-xt/t6017-rev-list-stdin.sh21
-rwxr-xr-xt/t6018-rev-list-glob.sh7
-rwxr-xr-xt/t6020-bundle-misc.sh32
-rwxr-xr-xt/t6021-rev-list-exclude-hidden.sh5
-rwxr-xr-xt/t6022-rev-list-missing.sh148
-rwxr-xr-xt/t6030-bisect-porcelain.sh34
-rwxr-xr-xt/t6040-tracking-info.sh19
-rwxr-xr-xt/t6050-replace.sh147
-rwxr-xr-xt/t6060-merge-index.sh1
-rwxr-xr-xt/t6100-rev-list-in-order.sh1
-rwxr-xr-xt/t6101-rev-parse-parents.sh1
-rwxr-xr-xt/t6102-rev-list-unexpected-objects.sh17
-rwxr-xr-xt/t6110-rev-list-sparse.sh1
-rwxr-xr-xt/t6112-rev-list-filters-objects.sh16
-rwxr-xr-xt/t6113-rev-list-bitmap-filters.sh15
-rwxr-xr-xt/t6114-keep-packs.sh1
-rwxr-xr-xt/t6115-rev-list-du.sh8
-rwxr-xr-xt/t6120-describe.sh38
-rwxr-xr-xt/t6130-pathspec-noglob.sh1
-rwxr-xr-xt/t6131-pathspec-icase.sh1
-rwxr-xr-xt/t6133-pathspec-rev-dwim.sh1
-rwxr-xr-xt/t6134-pathspec-in-submodule.sh3
-rwxr-xr-xt/t6135-pathspec-with-attrs.sh144
-rwxr-xr-xt/t6136-pathspec-in-bare.sh9
-rwxr-xr-xt/t6200-fmt-merge-msg.sh16
-rwxr-xr-xt/t6300-for-each-ref.sh277
-rwxr-xr-xt/t6301-for-each-ref-errors.sh14
-rwxr-xr-xt/t6302-for-each-ref-filter.sh75
-rwxr-xr-xt/t6401-merge-criss-cross.sh1
-rwxr-xr-xt/t6402-merge-rename.sh16
-rwxr-xr-xt/t6403-merge-file.sh183
-rwxr-xr-xt/t6404-recursive-merge.sh3
-rwxr-xr-xt/t6405-merge-symlinks.sh1
-rwxr-xr-xt/t6406-merge-attr.sh68
-rwxr-xr-xt/t6407-merge-binary.sh1
-rwxr-xr-xt/t6408-merge-up-to-date.sh1
-rwxr-xr-xt/t6411-merge-filemode.sh1
-rwxr-xr-xt/t6413-merge-crlf.sh5
-rwxr-xr-xt/t6414-merge-rename-nocruft.sh1
-rwxr-xr-xt/t6415-merge-dir-to-symlink.sh1
-rwxr-xr-xt/t6417-merge-ours-theirs.sh1
-rwxr-xr-xt/t6421-merge-partial-clone.sh15
-rwxr-xr-xt/t6422-merge-rename-corner-cases.sh17
-rwxr-xr-xt/t6423-merge-rename-directories.sh140
-rwxr-xr-xt/t6424-merge-unrelated-index-changes.sh6
-rwxr-xr-xt/t6425-merge-rename-delete.sh5
-rwxr-xr-xt/t6426-merge-skip-unneeded-updates.sh2
-rwxr-xr-xt/t6429-merge-sequence-rename-caching.sh45
-rwxr-xr-xt/t6430-merge-recursive.sh8
-rwxr-xr-xt/t6431-merge-criscross.sh1
-rwxr-xr-xt/t6433-merge-toplevel.sh4
-rwxr-xr-xt/t6435-merge-sparse.sh1
-rwxr-xr-xt/t6436-merge-overwrite.sh4
-rwxr-xr-xt/t6437-submodule-merge.sh16
-rwxr-xr-xt/t6439-merge-co-error-msgs.sh3
-rwxr-xr-xt/t6500-gc.sh140
-rwxr-xr-xt/t6501-freshen-objects.sh1
-rwxr-xr-xt/t6600-test-reach.sh121
-rwxr-xr-xt/t6700-tree-depth.sh94
-rwxr-xr-xt/t7001-mv.sh17
-rwxr-xr-xt/t7003-filter-branch.sh5
-rwxr-xr-xt/t7004-tag.sh1307
-rwxr-xr-xt/t7006-pager.sh17
-rwxr-xr-xt/t7007-show.sh1
-rwxr-xr-xt/t7011-skip-worktree-reading.sh23
-rwxr-xr-xt/t7031-verify-tag-signed-ssh.sh2
-rwxr-xr-xt/t7060-wtstatus.sh1
-rwxr-xr-xt/t7062-wtstatus-ignorecase.sh1
-rwxr-xr-xt/t7064-wtstatus-pv2.sh2
-rwxr-xr-xt/t7101-reset-empty-subdirs.sh1
-rwxr-xr-xt/t7102-reset.sh48
-rwxr-xr-xt/t7103-reset-bare.sh1
-rwxr-xr-xt/t7104-reset-hard.sh1
-rwxr-xr-xt/t7105-reset-patch.sh43
-rwxr-xr-xt/t7106-reset-unborn-branch.sh5
-rwxr-xr-xt/t7107-reset-pathspec-file.sh11
-rwxr-xr-xt/t7110-reset-merge.sh7
-rwxr-xr-xt/t7111-reset-table.sh1
-rwxr-xr-xt/t7113-post-index-change-hook.sh1
-rwxr-xr-xt/t7201-co.sh130
-rwxr-xr-xt/t7300-clean.sh401
-rwxr-xr-xt/t7301-clean-interactive.sh491
-rwxr-xr-xt/t7400-submodule-basic.sh71
-rwxr-xr-xt/t7401-submodule-summary.sh1
-rwxr-xr-xt/t7402-submodule-rebase.sh3
-rwxr-xr-xt/t7403-submodule-sync.sh5
-rwxr-xr-xt/t7406-submodule-update.sh8
-rwxr-xr-xt/t7408-submodule-reference.sh1
-rwxr-xr-xt/t7409-submodule-detached-work-tree.sh1
-rwxr-xr-xt/t7411-submodule-config.sh4
-rwxr-xr-xt/t7412-submodule-absorbgitdirs.sh1
-rwxr-xr-xt/t7413-submodule-is-active.sh3
-rwxr-xr-xt/t7414-submodule-mistakes.sh9
-rwxr-xr-xt/t7416-submodule-dash-url.sh5
-rwxr-xr-xt/t7417-submodule-path-url.sh4
-rwxr-xr-xt/t7419-submodule-set-branch.sh55
-rwxr-xr-xt/t7420-submodule-set-url.sh28
-rwxr-xr-xt/t7422-submodule-output.sh8
-rwxr-xr-xt/t7424-submodule-mixed-ref-formats.sh143
-rwxr-xr-xt/t7450-bad-git-dotfiles.sh39
-rwxr-xr-xt/t7500-commit-template-squash-signoff.sh2
-rwxr-xr-xt/t7501-commit-basic-functionality.sh90
-rwxr-xr-xt/t7502-commit-porcelain.sh55
-rwxr-xr-xt/t7503-pre-commit-and-pre-merge-commit-hooks.sh1
-rwxr-xr-xt/t7504-commit-msg-hook.sh1
-rwxr-xr-xt/t7506-status-submodule.sh29
-rwxr-xr-xt/t7507-commit-verbose.sh15
-rwxr-xr-xt/t7508-status.sh77
-rwxr-xr-xt/t7509-commit-authorship.sh5
-rwxr-xr-xt/t7511-status-index.sh1
-rwxr-xr-xt/t7512-status-help.sh28
-rwxr-xr-xt/t7513-interpret-trailers.sh579
-rwxr-xr-xt/t7514-commit-patch.sh7
-rwxr-xr-xt/t7515-status-symlinks.sh1
-rwxr-xr-xt/t7516-commit-races.sh1
-rwxr-xr-xt/t7517-per-repo-email.sh1
-rwxr-xr-xt/t7518-ident-corner-cases.sh11
-rwxr-xr-xt/t7519-status-fsmonitor.sh6
-rwxr-xr-xt/t7520-ignored-hook-warning.sh9
-rwxr-xr-xt/t7524-commit-summary.sh1
-rwxr-xr-xt/t7525-status-rename.sh55
-rwxr-xr-xt/t7526-commit-pathspec-file.sh15
-rwxr-xr-xt/t7527-builtin-fsmonitor.sh278
-rwxr-xr-xt/t7600-merge.sh40
-rwxr-xr-xt/t7601-merge-pull-config.sh76
-rwxr-xr-xt/t7604-merge-custom-message.sh1
-rwxr-xr-xt/t7605-merge-resolve.sh1
-rwxr-xr-xt/t7609-mergetool--lib.sh1
-rwxr-xr-xt/t7611-merge-abort.sh4
-rwxr-xr-xt/t7612-merge-verify-signatures.sh25
-rwxr-xr-xt/t7614-merge-signoff.sh1
-rwxr-xr-xt/t7615-diff-algo-with-mergy-operations.sh59
-rw-r--r--t/t7615/base.c17
-rw-r--r--t/t7615/ours.c17
-rw-r--r--t/t7615/theirs.c17
-rwxr-xr-xt/t7700-repack.sh360
-rwxr-xr-xt/t7701-repack-unpack-unreachable.sh1
-rwxr-xr-xt/t7702-repack-cyclic-alternate.sh3
-rwxr-xr-xt/t7703-repack-geometric.sh4
-rwxr-xr-xt/t7704-repack-cruft.sh414
-rwxr-xr-xt/t7800-difftool.sh121
-rwxr-xr-xt/t7810-grep.sh54
-rwxr-xr-xt/t7811-grep-open.sh3
-rwxr-xr-xt/t7812-grep-icase-non-ascii.sh1
-rwxr-xr-xt/t7813-grep-icase-iso.sh1
-rwxr-xr-xt/t7814-grep-recurse-submodules.sh2
-rwxr-xr-xt/t7815-grep-binary.sh1
-rwxr-xr-xt/t7816-grep-binary-pattern.sh5
-rwxr-xr-xt/t7900-maintenance.sh239
-rwxr-xr-xt/t8003-blame-corner-cases.sh2
-rwxr-xr-xt/t8005-blame-i18n.sh7
-rwxr-xr-xt/t8006-blame-textconv.sh1
-rwxr-xr-xt/t8007-cat-file-textconv.sh1
-rwxr-xr-xt/t8008-blame-formats.sh1
-rwxr-xr-xt/t8009-blame-vs-topicbranches.sh3
-rwxr-xr-xt/t8010-cat-file-filters.sh3
-rwxr-xr-xt/t8011-blame-split-file.sh1
-rwxr-xr-xt/t8013-blame-ignore-revs.sh35
-rwxr-xr-xt/t8014-blame-ignore-fuzzy.sh1
-rwxr-xr-xt/t9001-send-email.sh352
-rwxr-xr-xt/t9002-column.sh11
-rwxr-xr-xt/t9003-help-autocorrect.sh3
-rwxr-xr-xt/t9004-example.sh12
-rwxr-xr-xt/t9101-git-svn-props.sh34
-rwxr-xr-xt/t9114-git-svn-dcommit-merge.sh2
-rwxr-xr-xt/t9117-git-svn-init-clone.sh16
-rwxr-xr-xt/t9118-git-svn-funky-branch-names.sh2
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh1
-rwxr-xr-xt/t9133-git-svn-nested-git-repo.sh2
-rwxr-xr-xt/t9139-git-svn-non-utf8-commitencoding.sh1
-rwxr-xr-xt/t9146-git-svn-empty-dirs.sh56
-rwxr-xr-xt/t9164-git-svn-dcommit-concurrent.sh9
-rwxr-xr-xt/t9210-scalar.sh72
-rwxr-xr-xt/t9300-fast-import.sh700
-rwxr-xr-xt/t9301-fast-import-notes.sh1
-rwxr-xr-xt/t9302-fast-import-unpack-limit.sh1
-rwxr-xr-xt/t9303-fast-import-compression.sh1
-rwxr-xr-xt/t9304-fast-import-marks.sh1
-rwxr-xr-xt/t9350-fast-export.sh24
-rwxr-xr-xt/t9400-git-cvsserver-server.sh35
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh5
-rwxr-xr-xt/t9501-gitweb-standalone-http-status.sh1
-rwxr-xr-xt/t9603-cvsimport-patchsets.sh1
-rwxr-xr-xt/t9604-cvsimport-timestamps.sh30
-rwxr-xr-xt/t9700-perl-git.sh4
-rwxr-xr-xt/t9700/test.pl7
-rwxr-xr-xt/t9800-git-p4-basic.sh34
-rwxr-xr-xt/t9801-git-p4-branch.sh4
-rwxr-xr-xt/t9802-git-p4-filetype.sh20
-rwxr-xr-xt/t9807-git-p4-submit.sh14
-rwxr-xr-xt/t9815-git-p4-submit-fail.sh12
-rwxr-xr-xt/t9816-git-p4-locked.sh2
-rwxr-xr-xt/t9824-git-p4-git-lfs.sh4
-rwxr-xr-xt/t9825-git-p4-handle-utf16-without-bom.sh22
-rwxr-xr-xt/t9850-shell.sh1
-rwxr-xr-xt/t9901-git-web--browse.sh1
-rwxr-xr-xt/t9902-completion.sh354
-rw-r--r--t/test-lib-functions.sh163
-rw-r--r--t/test-lib-github-workflow-markup.sh6
-rw-r--r--t/test-lib-junit.sh2
-rw-r--r--t/test-lib.sh245
-rwxr-xr-xt/test-terminal.perl31
-rw-r--r--t/unit-tests/.gitignore3
-rw-r--r--t/unit-tests/clar/.editorconfig13
-rw-r--r--t/unit-tests/clar/.github/workflows/ci.yml35
-rw-r--r--t/unit-tests/clar/.gitignore1
-rw-r--r--t/unit-tests/clar/CMakeLists.txt28
-rw-r--r--t/unit-tests/clar/COPYING15
-rw-r--r--t/unit-tests/clar/README.md329
-rw-r--r--t/unit-tests/clar/clar.c857
-rw-r--r--t/unit-tests/clar/clar.h173
-rw-r--r--t/unit-tests/clar/clar/fixtures.h50
-rw-r--r--t/unit-tests/clar/clar/fs.h524
-rw-r--r--t/unit-tests/clar/clar/print.h216
-rw-r--r--t/unit-tests/clar/clar/sandbox.h158
-rw-r--r--t/unit-tests/clar/clar/summary.h139
-rwxr-xr-xt/unit-tests/clar/generate.py266
-rw-r--r--t/unit-tests/clar/test/CMakeLists.txt39
-rw-r--r--t/unit-tests/clar/test/clar_test.h16
-rw-r--r--t/unit-tests/clar/test/main.c40
-rw-r--r--t/unit-tests/clar/test/main.c.sample27
-rw-r--r--t/unit-tests/clar/test/resources/test/file1
-rw-r--r--t/unit-tests/clar/test/sample.c84
-rw-r--r--t/unit-tests/ctype.c102
-rwxr-xr-xt/unit-tests/generate-clar-decls.sh16
-rwxr-xr-xt/unit-tests/generate-clar-suites.sh63
-rw-r--r--t/unit-tests/lib-oid.c52
-rw-r--r--t/unit-tests/lib-oid.h25
-rw-r--r--t/unit-tests/lib-reftable.c95
-rw-r--r--t/unit-tests/lib-reftable.h21
-rw-r--r--t/unit-tests/strvec.c306
-rw-r--r--t/unit-tests/t-example-decorate.c74
-rw-r--r--t/unit-tests/t-hash.c84
-rw-r--r--t/unit-tests/t-hashmap.c361
-rw-r--r--t/unit-tests/t-mem-pool.c31
-rw-r--r--t/unit-tests/t-oid-array.c126
-rw-r--r--t/unit-tests/t-oidmap.c181
-rw-r--r--t/unit-tests/t-oidtree.c122
-rw-r--r--t/unit-tests/t-prio-queue.c91
-rw-r--r--t/unit-tests/t-reftable-basics.c145
-rw-r--r--t/unit-tests/t-reftable-block.c382
-rw-r--r--t/unit-tests/t-reftable-merged.c473
-rw-r--r--t/unit-tests/t-reftable-pq.c152
-rw-r--r--t/unit-tests/t-reftable-reader.c96
-rw-r--r--t/unit-tests/t-reftable-readwrite.c939
-rw-r--r--t/unit-tests/t-reftable-record.c551
-rw-r--r--t/unit-tests/t-reftable-stack.c1394
-rw-r--r--t/unit-tests/t-reftable-tree.c86
-rw-r--r--t/unit-tests/t-strbuf.c122
-rw-r--r--t/unit-tests/t-strcmp-offset.c35
-rw-r--r--t/unit-tests/t-trailer.c315
-rw-r--r--t/unit-tests/t-urlmatch-normalization.c271
-rw-r--r--t/unit-tests/test-lib.c454
-rw-r--r--t/unit-tests/test-lib.h183
-rw-r--r--t/unit-tests/unit-test.c47
-rw-r--r--t/unit-tests/unit-test.h10
-rwxr-xr-xt/valgrind/valgrind.sh2
-rw-r--r--tag.c6
-rw-r--r--tag.h2
-rw-r--r--tempfile.c21
-rw-r--r--tempfile.h2
-rwxr-xr-xtemplates/hooks--pre-commit.sample2
-rw-r--r--tmp-objdir.c37
-rw-r--r--trace.c12
-rw-r--r--trace2.c138
-rw-r--r--trace2.h6
-rw-r--r--trace2/tr2_cfg.c4
-rw-r--r--trace2/tr2_ctr.c8
-rw-r--r--trace2/tr2_sysenv.c5
-rw-r--r--trace2/tr2_tgt_event.c45
-rw-r--r--trace2/tr2_tgt_normal.c21
-rw-r--r--trace2/tr2_tls.c11
-rw-r--r--trace2/tr2_tls.h3
-rw-r--r--trace2/tr2_tmr.c1
-rw-r--r--trailer.c513
-rw-r--r--trailer.h132
-rw-r--r--transport-helper.c115
-rw-r--r--transport.c83
-rw-r--r--transport.h4
-rw-r--r--tree-diff.c27
-rw-r--r--tree-walk.c82
-rw-r--r--tree-walk.h11
-rw-r--r--tree.c16
-rw-r--r--tree.h1
-rw-r--r--unicode-width.h42
-rw-r--r--unpack-trees.c30
-rw-r--r--unpack-trees.h2
-rw-r--r--upload-pack.c268
-rw-r--r--url.c2
-rw-r--r--urlmatch.c2
-rw-r--r--usage.c20
-rw-r--r--userdiff.c101
-rw-r--r--userdiff.h11
-rw-r--r--utf8.c2
-rw-r--r--utf8.h11
-rw-r--r--versioncmp.c2
-rw-r--r--walker.c17
-rw-r--r--walker.h4
-rw-r--r--worktree.c384
-rw-r--r--worktree.h32
-rw-r--r--wrapper.c21
-rw-r--r--wrapper.h29
-rw-r--r--write-or-die.c29
-rw-r--r--wt-status.c131
-rw-r--r--wt-status.h7
-rw-r--r--xdiff-interface.c40
-rw-r--r--xdiff-interface.h3
2117 files changed, 118406 insertions, 51940 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 4860bebd32..1fbdc2652b 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,7 +1,7 @@
env:
CIRRUS_CLONE_DEPTH: 1
-freebsd_12_task:
+freebsd_task:
env:
GIT_PROVE_OPTS: "--timer --jobs 10"
GIT_TEST_OPTS: "--no-chain-lint --no-bin-wrappers"
@@ -9,7 +9,7 @@ freebsd_12_task:
DEFAULT_TEST_TARGET: prove
DEVELOPER: 1
freebsd_instance:
- image_family: freebsd-12-3
+ image_family: freebsd-13-4
memory: 2G
install_script:
pkg install -y gettext gmake perl5
@@ -19,4 +19,4 @@ freebsd_12_task:
build_script:
- su git -c gmake
test_script:
- - su git -c 'gmake test'
+ - su git -c 'gmake DEFAULT_UNIT_TEST_TARGET=unit-tests-prove test unit-tests'
diff --git a/.clang-format b/.clang-format
index c592dda681..9547fe1b77 100644
--- a/.clang-format
+++ b/.clang-format
@@ -32,6 +32,9 @@ AlignConsecutiveAssignments: false
# double b = 3.14;
AlignConsecutiveDeclarations: false
+# Align consecutive macro definitions.
+AlignConsecutiveMacros: true
+
# Align escaped newlines as far left as possible
# #define A \
# int aaaa; \
@@ -72,6 +75,10 @@ AlwaysBreakAfterReturnType: None
BinPackArguments: true
BinPackParameters: true
+# Add no space around the bit field
+# unsigned bf:2;
+BitFieldColonSpacing: None
+
# Attach braces to surrounding context except break before braces on function
# definitions.
# void foo()
@@ -83,9 +90,9 @@ BinPackParameters: true
BreakBeforeBraces: Linux
# Break after operators
-# int valuve = aaaaaaaaaaaaa +
-# bbbbbb -
-# ccccccccccc;
+# int value = aaaaaaaaaaaaa +
+# bbbbbb -
+# ccccccccccc;
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: false
@@ -96,6 +103,14 @@ BreakStringLiterals: false
# Switch statement body is always indented one level more than case labels.
IndentCaseLabels: false
+# Indents directives before the hash. Each level uses a single space for
+# indentation.
+# #if FOO
+# # include <foo>
+# #endif
+IndentPPDirectives: AfterHash
+PPIndentWidth: 1
+
# Don't indent a function definition or declaration if it is wrapped after the
# type
IndentWrappedFunctionNames: false
@@ -108,11 +123,18 @@ PointerAlignment: Right
# x = (int32)y; not x = (int32) y;
SpaceAfterCStyleCast: false
+# No space is inserted after the logical not operator
+SpaceAfterLogicalNot: false
+
# Insert spaces before and after assignment operators
# int a = 5; not int a=5;
# a += 42; a+=42;
SpaceBeforeAssignmentOperators: true
+# Spaces will be removed before case colon.
+# case 1: break; not case 1 : break;
+SpaceBeforeCaseColon: false
+
# Put a space before opening parentheses only after control statement keywords.
# void f() {
# if (true) {
@@ -124,6 +146,14 @@ SpaceBeforeParens: ControlStatements
# Don't insert spaces inside empty '()'
SpaceInEmptyParentheses: false
+# No space before first '[' in arrays
+# int a[5][5]; not int a [5][5];
+SpaceBeforeSquareBrackets: false
+
+# No space will be inserted into {}
+# while (true) {} not while (true) { }
+SpaceInEmptyBlock: false
+
# The number of spaces before trailing line comments (// - comments).
# This does not affect trailing block comments (/* - comments).
SpacesBeforeTrailingComments: 1
@@ -149,20 +179,30 @@ Cpp11BracedListStyle: false
# A list of macros that should be interpreted as foreach loops instead of as
# function calls. Taken from:
-# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' \
-# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
-# | sort | uniq
+# git grep -h '^#define [^[:space:]]*for_\?each[^[:space:]]*(' |
+# sed "s/^#define / - '/; s/(.*$/'/" | sort | uniq
ForEachMacros:
- - 'for_each_abbrev'
- 'for_each_builtin'
- 'for_each_string_list_item'
- 'for_each_ut'
- 'for_each_wanted_builtin'
+ - 'hashmap_for_each_entry'
+ - 'hashmap_for_each_entry_from'
+ - 'kh_foreach'
+ - 'kh_foreach_value'
- 'list_for_each'
- 'list_for_each_dir'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_safe'
+ - 'strintmap_for_each_entry'
+ - 'strmap_for_each_entry'
+ - 'strset_for_each_entry'
+
+# A list of macros that should be interpreted as conditionals instead of as
+# function calls.
+IfMacros:
+ - 'if_test'
# The maximum number of consecutive empty lines to keep.
MaxEmptyLinesToKeep: 1
@@ -172,13 +212,14 @@ KeepEmptyLinesAtTheStartOfBlocks: false
# Penalties
# This decides what order things should be done if a line is too long
-PenaltyBreakAssignment: 10
-PenaltyBreakBeforeFirstCallParameter: 30
-PenaltyBreakComment: 10
+PenaltyBreakAssignment: 5
+PenaltyBreakBeforeFirstCallParameter: 5
+PenaltyBreakComment: 5
PenaltyBreakFirstLessLess: 0
-PenaltyBreakString: 10
-PenaltyExcessCharacter: 100
-PenaltyReturnTypeOnItsOwnLine: 60
+PenaltyBreakOpenParenthesis: 300
+PenaltyBreakString: 5
+PenaltyExcessCharacter: 10
+PenaltyReturnTypeOnItsOwnLine: 300
# Don't sort #include's
SortIncludes: false
diff --git a/.editorconfig b/.editorconfig
index f9d819623d..15d6cbeab1 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -4,7 +4,7 @@ insert_final_newline = true
# The settings for C (*.c and *.h) files are mirrored in .clang-format. Keep
# them in sync.
-[*.{c,h,sh,perl,pl,pm,txt}]
+[{*.{c,h,sh,perl,pl,pm,txt},config.mak.*,Makefile}]
indent_style = tab
tab_width = 8
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 952c7c3a2a..37654cdfd7 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,4 +4,7 @@ a mailing list (git@vger.kernel.org) for code submissions, code reviews, and
bug reports. Nevertheless, you can use GitGitGadget (https://gitgitgadget.github.io/)
to conveniently send your Pull Requests commits to our mailing list.
+For a single-commit pull request, please *leave the pull request description
+empty*: your commit message itself should describe your changes.
+
Please read the "guidelines for contributing" linked above!
diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml
new file mode 100644
index 0000000000..c052a5df23
--- /dev/null
+++ b/.github/workflows/check-style.yml
@@ -0,0 +1,34 @@
+name: check-style
+
+# Get the repository with all commits to ensure that we can analyze
+# all of the commits contributed via the Pull Request.
+
+on:
+ pull_request:
+ types: [opened, synchronize]
+
+# Avoid unnecessary builds. Unlike the main CI jobs, these are not
+# ci-configurable (but could be).
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ check-style:
+ env:
+ CC: clang
+ jobname: ClangFormat
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - run: ci/install-dependencies.sh
+
+ - name: git clang-format
+ continue-on-error: true
+ id: check_out
+ run: |
+ ./ci/run-style-check.sh \
+ "${{github.event.pull_request.base.sha}}"
diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml
index a241a63428..d0a78fc426 100644
--- a/.github/workflows/check-whitespace.yml
+++ b/.github/workflows/check-whitespace.yml
@@ -26,66 +26,7 @@ jobs:
- name: git log --check
id: check_out
run: |
- baseSha=${{github.event.pull_request.base.sha}}
- problems=()
- commit=
- commitText=
- commitTextmd=
- goodparent=
- while read dash sha etc
- do
- case "${dash}" in
- "---")
- if test -z "${commit}"
- then
- goodparent=${sha}
- fi
- commit="${sha}"
- commitText="${sha} ${etc}"
- commitTextmd="[${sha}](https://github.com/${{ github.repository }}/commit/${sha}) ${etc}"
- ;;
- "")
- ;;
- *)
- if test -n "${commit}"
- then
- problems+=("1) --- ${commitTextmd}")
- echo ""
- echo "--- ${commitText}"
- commit=
- fi
- case "${dash}" in
- *:[1-9]*:) # contains file and line number information
- dashend=${dash#*:}
- problems+=("[${dash}](https://github.com/${{ github.repository }}/blob/${{github.event.pull_request.head.ref}}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}")
- ;;
- *)
- problems+=("\`${dash} ${sha} ${etc}\`")
- ;;
- esac
- echo "${dash} ${sha} ${etc}"
- ;;
- esac
- done <<< $(git log --check --pretty=format:"---% h% s" ${baseSha}..)
-
- if test ${#problems[*]} -gt 0
- then
- if test -z "${commit}"
- then
- goodparent=${baseSha: 0:7}
- fi
- echo "🛑 Please review the Summary output for further information."
- echo "### :x: A whitespace issue was found in one or more of the commits." >$GITHUB_STEP_SUMMARY
- echo "" >>$GITHUB_STEP_SUMMARY
- echo "Run these commands to correct the problem:" >>$GITHUB_STEP_SUMMARY
- echo "1. \`git rebase --whitespace=fix ${goodparent}\`" >>$GITHUB_STEP_SUMMARY
- echo "1. \`git push --force\`" >>$GITHUB_STEP_SUMMARY
- echo " " >>$GITHUB_STEP_SUMMARY
- echo "Errors:" >>$GITHUB_STEP_SUMMARY
- for i in "${problems[@]}"
- do
- echo "${i}" >>$GITHUB_STEP_SUMMARY
- done
-
- exit 2
- fi
+ ./ci/check-whitespace.sh \
+ "${{github.event.pull_request.base.sha}}" \
+ "$GITHUB_STEP_SUMMARY" \
+ "https://github.com/${{github.repository}}"
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
index e5532d381b..48341e81f4 100644
--- a/.github/workflows/coverity.yml
+++ b/.github/workflows/coverity.yml
@@ -38,14 +38,14 @@ jobs:
COVERITY_LANGUAGE: cxx
COVERITY_PLATFORM: overridden-below
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- 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 }}
+ distro: ${{ 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.
@@ -98,7 +98,7 @@ jobs:
# 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
+ uses: actions/cache/restore@v4
with:
path: ${{ runner.temp }}/cov-analysis
key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
@@ -141,7 +141,7 @@ jobs:
esac
- name: cache the Coverity Build Tool
if: steps.cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@v3
+ uses: actions/cache/save@v4
with:
path: ${{ runner.temp }}/cov-analysis
key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
diff --git a/.github/workflows/l10n.yml b/.github/workflows/l10n.yml
index 6c3849658a..e2c3dbdcb5 100644
--- a/.github/workflows/l10n.yml
+++ b/.github/workflows/l10n.yml
@@ -63,9 +63,10 @@ jobs:
origin \
${{ github.ref }} \
$args
- - uses: actions/setup-go@v2
+ - uses: actions/setup-go@v5
with:
go-version: '>=1.16'
+ cache: false
- name: Install git-po-helper
run: go install github.com/git-l10n/git-po-helper@main
- name: Install other dependencies
@@ -91,14 +92,13 @@ jobs:
cat git-po-helper.out
exit $exit_code
- name: Create comment in pull request for report
- uses: mshick/add-pr-comment@v1
+ uses: mshick/add-pr-comment@v2
if: >-
always() &&
github.event_name == 'pull_request_target' &&
env.COMMENT_BODY != ''
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- repo-token-user-login: 'github-actions[bot]'
message: >
${{ steps.check-commits.outcome == 'failure' && 'Errors and warnings' || 'Warnings' }}
found by [git-po-helper](https://github.com/git-l10n/git-po-helper#readme) in workflow
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index b40f0e7fc6..9301a1edd6 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -113,13 +113,15 @@ jobs:
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v4
- - uses: git-for-windows/setup-git-for-windows-sdk@v1
+ - name: setup SDK
+ shell: powershell
+ run: ci/install-sdk.ps1
- name: build
- shell: bash
+ shell: powershell
env:
HOME: ${{runner.workspace}}
NO_PERL: 1
- run: . /etc/profile && ci/make-test-artifacts.sh artifacts
+ run: git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts'
- name: zip up tracked files
run: git archive -o artifacts/tracked.tar.gz HEAD
- name: upload tracked files and build artifacts
@@ -147,10 +149,12 @@ jobs:
- name: extract tracked files and build artifacts
shell: bash
run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz
- - uses: git-for-windows/setup-git-for-windows-sdk@v1
+ - name: setup SDK
+ shell: powershell
+ run: ci/install-sdk.ps1
- name: test
- shell: bash
- run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10
+ shell: powershell
+ run: git-sdk/usr/bin/bash.exe -l -c 'ci/run-test-slice.sh ${{matrix.nr}} 10'
- name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
shell: bash
@@ -159,7 +163,7 @@ jobs:
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v4
with:
- name: failed-tests-windows
+ name: failed-tests-windows-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
vs-build:
name: win+VS build
@@ -181,16 +185,12 @@ jobs:
repository: 'microsoft/vcpkg'
path: 'compat/vcbuild/vcpkg'
- name: download vcpkg artifacts
- shell: powershell
- run: |
- $urlbase = "https://dev.azure.com/git/git/_apis/build/builds"
- $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=9&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
- $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[0].resource.downloadUrl
- (New-Object Net.WebClient).DownloadFile($downloadUrl, "compat.zip")
- Expand-Archive compat.zip -DestinationPath . -Force
- Remove-Item compat.zip
+ uses: git-for-windows/get-azure-pipelines-artifact@v0
+ with:
+ repository: git/git
+ definitionId: 9
- name: add msbuild to PATH
- uses: microsoft/setup-msbuild@v1
+ uses: microsoft/setup-msbuild@v2
- name: copy dlls to root
shell: cmd
run: compat\vcbuild\vcpkg_copy_dlls.bat release
@@ -250,7 +250,7 @@ jobs:
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v4
with:
- name: failed-tests-windows
+ name: failed-tests-windows-vs-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
regular:
name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}})
@@ -266,6 +266,9 @@ jobs:
- jobname: linux-sha256
cc: clang
pool: ubuntu-latest
+ - jobname: linux-reftable
+ cc: clang
+ pool: ubuntu-latest
- jobname: linux-gcc
cc: gcc
cc_package: gcc-8
@@ -277,6 +280,9 @@ jobs:
- jobname: osx-clang
cc: clang
pool: macos-13
+ - jobname: osx-reftable
+ cc: clang
+ pool: macos-13
- jobname: osx-gcc
cc: gcc-13
pool: macos-13
@@ -286,6 +292,9 @@ jobs:
- jobname: linux-leaks
cc: gcc
pool: ubuntu-latest
+ - jobname: linux-reftable-leaks
+ cc: gcc
+ pool: ubuntu-latest
- jobname: linux-asan-ubsan
cc: clang
pool: ubuntu-latest
@@ -293,7 +302,7 @@ jobs:
CC: ${{matrix.vector.cc}}
CC_PACKAGE: ${{matrix.vector.cc_package}}
jobname: ${{matrix.vector.jobname}}
- runs_on_pool: ${{matrix.vector.pool}}
+ distro: ${{matrix.vector.pool}}
runs-on: ${{matrix.vector.pool}}
steps:
- uses: actions/checkout@v4
@@ -308,6 +317,17 @@ jobs:
with:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
+ fuzz-smoke-test:
+ name: fuzz smoke test
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
+ env:
+ CC: clang
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - run: ci/install-dependencies.sh
+ - run: ci/run-build-and-minimal-fuzzers.sh
dockerized:
name: ${{matrix.vector.jobname}} (${{matrix.vector.image}})
needs: ci-config
@@ -321,36 +341,34 @@ jobs:
vector:
- jobname: linux-musl
image: alpine
+ distro: alpine-latest
- jobname: linux32
- image: daald/ubuntu32:xenial
+ image: i386/ubuntu:focal
+ distro: ubuntu32-20.04
- jobname: pedantic
image: fedora
+ distro: fedora-latest
env:
jobname: ${{matrix.vector.jobname}}
+ distro: ${{matrix.vector.distro}}
runs-on: ubuntu-latest
container: ${{matrix.vector.image}}
steps:
- - uses: actions/checkout@v4
- if: matrix.vector.jobname != 'linux32'
- - uses: actions/checkout@v1 # cannot be upgraded because Node.js Actions aren't supported in this container
+ - name: prepare libc6 for actions
if: matrix.vector.jobname == 'linux32'
- - run: ci/install-docker-dependencies.sh
+ run: apt -q update && apt -q -y install libc6-amd64 lib64stdc++6
+ - uses: actions/checkout@v4
+ - run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
- if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname != 'linux32'
+ if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v4
with:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
- - name: Upload failed tests' directories
- if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname == 'linux32'
- uses: actions/upload-artifact@v1 # cannot be upgraded because Node.js Actions aren't supported in this container
- with:
- name: failed-tests-${{matrix.vector.jobname}}
- path: ${{env.FAILED_TEST_ARTIFACTS}}
static-analysis:
needs: ci-config
if: needs.ci-config.outputs.enabled == 'yes'
diff --git a/.gitignore b/.gitignore
index 5e56e471b3..6687bd6db4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
/GIT-PYTHON-VARS
/GIT-SCRIPT-DEFINES
/GIT-SPATCH-DEFINES
+/GIT-TEST-SUITES
/GIT-USER-AGENT
/GIT-VERSION-FILE
/bin-wrappers/
@@ -126,6 +127,7 @@
/git-rebase
/git-receive-pack
/git-reflog
+/git-refs
/git-remote
/git-remote-http
/git-remote-https
@@ -135,6 +137,7 @@
/git-remote-ext
/git-repack
/git-replace
+/git-replay
/git-request-pull
/git-rerere
/git-reset
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000..526ecfe030
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,212 @@
+default:
+ timeout: 2h
+
+stages:
+ - build
+ - test
+ - analyze
+
+workflow:
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ - if: $CI_COMMIT_TAG
+ - if: $CI_COMMIT_REF_PROTECTED == "true"
+
+test:linux:
+ image: $image
+ stage: test
+ needs: [ ]
+ tags:
+ - saas-linux-medium-amd64
+ variables:
+ CUSTOM_PATH: "/custom"
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - useradd builder --create-home
+ - chown -R builder "${CI_PROJECT_DIR}"
+ - sudo --preserve-env --set-home --user=builder ./ci/run-build-and-tests.sh
+ after_script:
+ - |
+ if test "$CI_JOB_STATUS" != 'success'
+ then
+ sudo --preserve-env --set-home --user=builder ./ci/print-test-failures.sh
+ fi
+ parallel:
+ matrix:
+ - jobname: linux-old
+ image: ubuntu:16.04
+ CC: gcc
+ - jobname: linux-sha256
+ image: ubuntu:latest
+ CC: clang
+ - jobname: linux-reftable
+ image: ubuntu:latest
+ CC: clang
+ - jobname: linux-gcc
+ image: ubuntu:20.04
+ CC: gcc
+ CC_PACKAGE: gcc-8
+ - jobname: linux-TEST-vars
+ image: ubuntu:20.04
+ CC: gcc
+ CC_PACKAGE: gcc-8
+ - jobname: linux-gcc-default
+ image: ubuntu:latest
+ CC: gcc
+ - jobname: linux-leaks
+ image: ubuntu:latest
+ CC: gcc
+ - jobname: linux-reftable-leaks
+ image: ubuntu:latest
+ CC: gcc
+ - jobname: linux-asan-ubsan
+ image: ubuntu:latest
+ CC: clang
+ - jobname: pedantic
+ image: fedora:latest
+ - jobname: linux-musl
+ image: alpine:latest
+ artifacts:
+ paths:
+ - t/failed-test-artifacts
+ when: on_failure
+
+test:osx:
+ image: $image
+ stage: test
+ needs: [ ]
+ tags:
+ - saas-macos-medium-m1
+ variables:
+ TEST_OUTPUT_DIRECTORY: "/Volumes/RAMDisk"
+ before_script:
+ # Create a 4GB RAM disk that we use to store test output on. This small hack
+ # significantly speeds up tests by more than a factor of 2 because the
+ # macOS runners use network-attached storage as disks, which is _really_
+ # slow with the many small writes that our tests do.
+ - sudo diskutil apfs create $(hdiutil attach -nomount ram://8192000) RAMDisk
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/run-build-and-tests.sh
+ after_script:
+ - |
+ if test "$CI_JOB_STATUS" != 'success'
+ then
+ ./ci/print-test-failures.sh
+ mv "$TEST_OUTPUT_DIRECTORY"/failed-test-artifacts t/
+ fi
+ parallel:
+ matrix:
+ - jobname: osx-clang
+ image: macos-13-xcode-14
+ CC: clang
+ - jobname: osx-reftable
+ image: macos-13-xcode-14
+ CC: clang
+ artifacts:
+ paths:
+ - t/failed-test-artifacts
+ when: on_failure
+
+build:mingw64:
+ stage: build
+ tags:
+ - saas-windows-medium-amd64
+ variables:
+ NO_PERL: 1
+ before_script:
+ - ./ci/install-sdk.ps1 -directory "git-sdk"
+ script:
+ - git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts'
+ artifacts:
+ paths:
+ - artifacts
+ - git-sdk
+
+test:mingw64:
+ stage: test
+ tags:
+ - saas-windows-medium-amd64
+ needs:
+ - job: "build:mingw64"
+ artifacts: true
+ before_script:
+ - git-sdk/usr/bin/bash.exe -l -c 'tar xf artifacts/artifacts.tar.gz'
+ - New-Item -Path .git/info -ItemType Directory
+ - New-Item .git/info/exclude -ItemType File -Value "/git-sdk"
+ script:
+ - git-sdk/usr/bin/bash.exe -l -c "ci/run-test-slice.sh $CI_NODE_INDEX $CI_NODE_TOTAL"
+ after_script:
+ - git-sdk/usr/bin/bash.exe -l -c 'ci/print-test-failures.sh'
+ parallel: 10
+
+test:fuzz-smoke-tests:
+ image: ubuntu:latest
+ stage: test
+ needs: [ ]
+ variables:
+ CC: clang
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/run-build-and-minimal-fuzzers.sh
+
+static-analysis:
+ image: ubuntu:22.04
+ stage: analyze
+ needs: [ ]
+ variables:
+ jobname: StaticAnalysis
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/run-static-analysis.sh
+ - ./ci/check-directional-formatting.bash
+
+check-whitespace:
+ image: ubuntu:latest
+ stage: analyze
+ needs: [ ]
+ before_script:
+ - ./ci/install-dependencies.sh
+ # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged
+ # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should
+ # be defined in all pipelines.
+ script:
+ - |
+ R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
+ ./ci/check-whitespace.sh "$R"
+ rules:
+ - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+
+check-style:
+ image: ubuntu:latest
+ stage: analyze
+ needs: [ ]
+ allow_failure: true
+ variables:
+ CC: clang
+ jobname: ClangFormat
+ before_script:
+ - ./ci/install-dependencies.sh
+ # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged
+ # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should
+ # be defined in all pipelines.
+ script:
+ - |
+ R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
+ ./ci/run-style-check.sh "$R"
+ rules:
+ - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+
+documentation:
+ image: ubuntu:latest
+ stage: analyze
+ needs: [ ]
+ variables:
+ jobname: Documentation
+ before_script:
+ - ./ci/install-dependencies.sh
+ script:
+ - ./ci/test-documentation.sh
diff --git a/.mailmap b/.mailmap
index dc31d70b8c..96c2740fbb 100644
--- a/.mailmap
+++ b/.mailmap
@@ -59,9 +59,9 @@ David Reiss <dreiss@facebook.com> <dreiss@dreiss-vmware.(none)>
David S. Miller <davem@davemloft.net>
David Turner <novalis@novalis.org> <dturner@twopensource.com>
David Turner <novalis@novalis.org> <dturner@twosigma.com>
-Derrick Stolee <derrickstolee@github.com> <stolee@gmail.com>
-Derrick Stolee <derrickstolee@github.com> Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
-Derrick Stolee <derrickstolee@github.com> <dstolee@microsoft.com>
+Derrick Stolee <stolee@gmail.com> <derrickstolee@github.com>
+Derrick Stolee <stolee@gmail.com> Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
+Derrick Stolee <stolee@gmail.com> <dstolee@microsoft.com>
Deskin Miller <deskinm@umich.edu>
Äoàn Trần Công Danh <congdanhqx@gmail.com> Doan Tran Cong Danh
Dirk Süsserott <newsletter@dirk.my1.cc>
@@ -152,6 +152,7 @@ Lars Doelle <lars.doelle@on-line ! de>
Lars Doelle <lars.doelle@on-line.de>
Lars Noschinski <lars@public.noschinski.de> <lars.noschinski@rwth-aachen.de>
Li Hong <leehong@pku.edu.cn>
+Linus Arver <linus@ucla.edu> <linusa@google.com>
Linus Torvalds <torvalds@linux-foundation.org> <torvalds@evo.osdl.org>
Linus Torvalds <torvalds@linux-foundation.org> <torvalds@g5.osdl.org>
Linus Torvalds <torvalds@linux-foundation.org> <torvalds@osdl.org>
@@ -256,6 +257,7 @@ Stefan Naewe <stefan.naewe@gmail.com> <stefan.naewe@googlemail.com>
Stefan Sperling <stsp@elego.de> <stsp@stsp.name>
Štěpán Němec <stepnem@gmail.com> <stepan.nemec@gmail.com>
Stephen Boyd <bebarino@gmail.com> <sboyd@codeaurora.org>
+Stephen P. Smith <ishchis2@gmail.com> <ischis2@cox.net>
Steven Drake <sdrake@xnet.co.nz> <sdrake@ihug.co.nz>
Steven Grimm <koreth@midwinter.com> <sgrimm@sgrimm-mbp.local>
Steven Grimm <koreth@midwinter.com> koreth@midwinter.com
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 0215b1fd4c..e58917c50a 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -130,11 +130,11 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
-Community Impact Guidelines were inspired by
+Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
-[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
diff --git a/Documentation/BreakingChanges.txt b/Documentation/BreakingChanges.txt
new file mode 100644
index 0000000000..27acff86db
--- /dev/null
+++ b/Documentation/BreakingChanges.txt
@@ -0,0 +1,174 @@
+= Upcoming breaking changes
+
+The Git project aims to ensure backwards compatibility to the best extent
+possible. Minor releases will not break backwards compatibility unless there is
+a very strong reason to do so, like for example a security vulnerability.
+
+Regardless of that, due to the age of the Git project, it is only natural to
+accumulate a backlog of backwards-incompatible changes that will eventually be
+required to keep the project aligned with a changing world. These changes fall
+into several categories:
+
+* Changes to long established defaults.
+* Concepts that have been replaced with a superior design.
+* Concepts, commands, configuration or options that have been lacking in major
+ ways and that cannot be fixed and which will thus be removed without any
+ replacement.
+
+Explicitly not included in this list are fixes to minor bugs that may cause a
+change in user-visible behavior.
+
+The Git project irregularly releases breaking versions that deliberately break
+backwards compatibility with older versions. This is done to ensure that Git
+remains relevant, safe and maintainable going forward. The release cadence of
+breaking versions is typically measured in multiple years. We had the following
+major breaking releases in the past:
+
+* Git 1.6.0, released in August 2008.
+* Git 2.0, released in May 2014.
+
+We use <major>.<minor> release numbers these days, starting from Git 2.0. For
+future releases, our plan is to increment <major> in the release number when we
+make the next breaking release. Before Git 2.0, the release numbers were
+1.<major>.<minor> with the intention to increment <major> for "usual" breaking
+releases, reserving the jump to Git 2.0 for really large backward-compatibility
+breaking changes.
+
+The intent of this document is to track upcoming deprecations for future
+breaking releases. Furthermore, this document also tracks what will _not_ be
+deprecated. This is done such that the outcome of discussions document both
+when the discussion favors deprecation, but also when it rejects a deprecation.
+
+Items should have a clear summary of the reasons why we do or do not want to
+make the described change that can be easily understood without having to read
+the mailing list discussions. If there are alternatives to the changed feature,
+those alternatives should be pointed out to our users.
+
+All items should be accompanied by references to relevant mailing list threads
+where the deprecation was discussed. These references use message-IDs, which
+can visited via
+
+ https://lore.kernel.org/git/$message_id/
+
+to see the message and its surrounding discussion. Such a reference is there to
+make it easier for you to find how the project reached consensus on the
+described item back then.
+
+This is a living document as the environment surrounding the project changes
+over time. If circumstances change, an earlier decision to deprecate or change
+something may need to be revisited from time to time. So do not take items on
+this list to mean "it is settled, do not waste our time bringing it up again".
+
+== Procedure
+
+Discussing the desire to make breaking changes, declaring that breaking
+changes are made at a certain version boundary, and recording these
+decisions in this document, are necessary but not sufficient.
+Because such changes are expected to be numerous, and the design and
+implementation of them are expected to span over time, they have to
+be deployable trivially at such a version boundary.
+
+The breaking changes MUST be guarded with the a compile-time switch,
+WITH_BREAKING_CHANGES, to help this process. When built with it,
+the resulting Git binary together with its documentation would
+behave as if these breaking changes slated for the next big version
+boundary are already in effect. We may also want to have a CI job
+or two to exercise the work-in-progress version of Git with these
+breaking changes.
+
+
+== Git 3.0
+
+The following subsections document upcoming breaking changes for Git 3.0. There
+is no planned release date for this breaking version yet. The early
+adopter configuration used for changes for this release is `feature.git3`.
+
+Proposed changes and removals only include items which are "ready" to be done.
+In other words, this is not supposed to be a wishlist of features that should
+be changed to or replaced in case the alternative was implemented already.
+
+=== Changes
+
+* The default hash function for new repositories will be changed from "sha1"
+ to "sha256". SHA-1 has been deprecated by NIST in 2011 and is nowadays
+ recommended against in FIPS 140-2 and similar certifications. Furthermore,
+ there are practical attacks on SHA-1 that weaken its cryptographic properties:
++
+ ** The SHAppening (2015). The first demonstration of a practical attack
+ against SHA-1 with 2^57 operations.
+ ** SHAttered (2017). Generation of two valid PDF files with 2^63 operations.
+ ** Birthday-Near-Collision (2019). This attack allows for chosen prefix
+ attacks with 2^68 operations.
+ ** Shambles (2020). This attack allows for chosen prefix attacks with 2^63
+ operations.
++
+While we have protections in place against known attacks, it is expected
+that more attacks against SHA-1 will be found by future research. Paired
+with the ever-growing capability of hardware, it is only a matter of time
+before SHA-1 will be considered broken completely. We want to be prepared
+and will thus change the default hash algorithm to "sha256" for newly
+initialized repositories.
++
+An important requirement for this change is that the ecosystem is ready to
+support the "sha256" object format. This includes popular Git libraries,
+applications and forges.
++
+There is no plan to deprecate the "sha1" object format at this point in time.
++
+Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>,
+<20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>,
+<CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>.
+
+=== Removals
+
+* Support for grafting commits has long been superseded by git-replace(1).
+ Grafts are inferior to replacement refs:
++
+ ** Grafts are a local-only mechanism and cannot be shared across
+ repositories.
+ ** Grafts can lead to hard-to-diagnose problems when transferring objects
+ between repositories.
++
+The grafting mechanism has been marked as outdated since e650d0643b (docs: mark
+info/grafts as outdated, 2014-03-05) and will be removed.
++
+Cf. <20140304174806.GA11561@sigill.intra.peff.net>.
+
+* The git-pack-redundant(1) command can be used to remove redundant pack files.
+ The subcommand is unusably slow and the reason why nobody reports it as a
+ performance bug is suspected to be the absence of users. We have nominated
+ the command for removal and have started to emit a user-visible warning in
+ c3b58472be (pack-redundant: gauge the usage before proposing its removal,
+ 2020-08-25) whenever the command is executed.
++
+So far there was a single complaint about somebody still using the command, but
+that complaint did not cause us to reverse course. On the contrary, we have
+doubled down on the deprecation and starting with 4406522b76 (pack-redundant:
+escalate deprecation warning to an error, 2023-03-23), the command dies unless
+the user passes the `--i-still-use-this` option.
++
+There have not been any subsequent complaints, so this command will finally be
+removed.
++
+Cf. <xmqq1rjuz6n3.fsf_-_@gitster.c.googlers.com>,
+ <CAKvOHKAFXQwt4D8yUCCkf_TQL79mYaJ=KAKhtpDNTvHJFuX1NA@mail.gmail.com>,
+ <20230323204047.GA9290@coredump.intra.peff.net>,
+
+== Superseded features that will not be deprecated
+
+Some features have gained newer replacements that aim to improve the design in
+certain ways. The fact that there is a replacement does not automatically mean
+that the old way of doing things will eventually be removed. This section tracks
+those features with newer alternatives.
+
+* The features git-checkout(1) offers are covered by the pair of commands
+ git-restore(1) and git-switch(1). Because the use of git-checkout(1) is still
+ widespread, and it is not expected that this will change anytime soon, all
+ three commands will stay.
++
+This decision may get revisited in case we ever figure out that there are
+almost no users of any of the commands anymore.
++
+Cf. <xmqqttjazwwa.fsf@gitster.g>,
+<xmqqleeubork.fsf@gitster.g>,
+<112b6568912a6de6672bf5592c3a718e@manjaro.org>.
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 9495df835d..87904791cb 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -1,5 +1,5 @@
-Like other projects, we also have some guidelines to keep to the
-code. For Git in general, a few rough rules are:
+Like other projects, we also have some guidelines for our code. For
+Git in general, a few rough rules are:
- Most importantly, we never say "It's in POSIX; we'll happily
ignore your needs should your system not conform to it."
@@ -40,7 +40,7 @@ As for more concrete guidelines, just imitate the existing code
contributing to). It is always preferable to match the _local_
convention. New code added to Git suite is expected to match
the overall style of existing code. Modifications to existing
-code is expected to match the style the surrounding code already
+code are expected to match the style the surrounding code already
uses (even if it doesn't match the overall style of existing code).
But if you must have a list of rules, here are some language
@@ -185,8 +185,51 @@ For shell scripts specifically (not exhaustive):
- Even though "local" is not part of POSIX, we make heavy use of it
in our test suite. We do not use it in scripted Porcelains, and
- hopefully nobody starts using "local" before they are reimplemented
- in C ;-)
+ hopefully nobody starts using "local" before all shells that matter
+ support it (notably, ksh from AT&T Research does not support it yet).
+
+ - Some versions of shell do not understand "export variable=value",
+ so we write "variable=value" and then "export variable" on two
+ separate lines.
+
+ - Some versions of dash have broken variable assignment when prefixed
+ with "local", "export", and "readonly", in that the value to be
+ assigned goes through field splitting at $IFS unless quoted.
+
+ (incorrect)
+ local variable=$value
+ local variable=$(command args)
+
+ (correct)
+ local variable="$value"
+ local variable="$(command args)"
+
+ - The common construct
+
+ VAR=VAL command args
+
+ to temporarily set and export environment variable VAR only while
+ "command args" is running is handy, but this triggers an
+ unspecified behaviour according to POSIX when used for a command
+ that is not an external command (like shell functions). Indeed,
+ dash 0.5.10.2-6 on Ubuntu 20.04, /bin/sh on FreeBSD 13, and AT&T
+ ksh all make a temporary assignment without exporting the variable,
+ in such a case. As it does not work portably across shells, do not
+ use this syntax for shell functions. A common workaround is to do
+ an explicit export in a subshell, like so:
+
+ (incorrect)
+ VAR=VAL func args
+
+ (correct)
+ (
+ VAR=VAL &&
+ export VAR &&
+ func args
+ )
+
+ but be careful that the effect "func" makes to the variables in the
+ current shell will be lost across the subshell boundary.
- Use octal escape sequences (e.g. "\302\242"), not hexadecimal (e.g.
"\xc2\xa2") in printf format strings, since hexadecimal escape
@@ -198,6 +241,16 @@ For C programs:
- We use tabs to indent, and interpret tabs as taking up to
8 spaces.
+ - Nested C preprocessor directives are indented after the hash by one
+ space per nesting level.
+
+ #if FOO
+ # include <foo.h>
+ # if BAR
+ # include <bar.h>
+ # endif
+ #endif
+
- We try to keep to at most 80 characters per line.
- As a Git developer we assume you have a reasonably modern compiler
@@ -205,6 +258,14 @@ For C programs:
ensure your patch is clear of all compiler warnings we care about,
by e.g. "echo DEVELOPER=1 >>config.mak".
+ - When using DEVELOPER=1 mode, you may see warnings from the compiler
+ like "error: unused parameter 'foo' [-Werror=unused-parameter]",
+ which indicates that a function ignores its argument. If the unused
+ parameter can't be removed (e.g., because the function is used as a
+ callback and has to match a certain interface), you can annotate
+ the individual parameters with the UNUSED (or MAYBE_UNUSED)
+ keyword, like "int foo UNUSED".
+
- We try to support a wide range of C compilers to compile Git with,
including old ones. As of Git v2.35.0 Git requires C99 (we check
"__STDC_VERSION__"). You should not use features from a newer C
@@ -218,7 +279,7 @@ For C programs:
. since around 2007 with 2b6854c863a, we have been using
initializer elements which are not computable at load time. E.g.:
- const char *args[] = {"constant", variable, NULL};
+ const char *args[] = { "constant", variable, NULL };
. since early 2012 with e1327023ea, we have been using an enum
definition whose last element is followed by a comma. This, like
@@ -250,7 +311,9 @@ For C programs:
v12.01, 2022-03-28).
- Variables have to be declared at the beginning of the block, before
- the first statement (i.e. -Wdeclaration-after-statement).
+ the first statement (i.e. -Wdeclaration-after-statement). It is
+ encouraged to have a blank line between the end of the declarations
+ and the first statement in the block.
- NULL pointers shall be written as NULL, not as 0.
@@ -270,6 +333,13 @@ For C programs:
while( condition )
func (bar+1);
+ - A binary operator (other than ",") and ternary conditional "?:"
+ have a space on each side of the operator to separate it from its
+ operands. E.g. "A + 1", not "A+1".
+
+ - A unary operator (other than "." and "->") have no space between it
+ and its operand. E.g. "(char *)ptr", not "(char *) ptr".
+
- Do not explicitly compare an integral value with constant 0 or '\0',
or a pointer value with constant NULL. For instance, to validate that
counted array <ptr, cnt> is initialized but has no elements, write:
@@ -446,12 +516,41 @@ For C programs:
detail.
- The first #include in C files, except in platform specific compat/
- implementations and sha1dc/, must be either "git-compat-util.h" or
- one of the approved headers that includes it first for you. (The
- approved headers currently include "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.
+ implementations and sha1dc/, must be <git-compat-util.h>. This
+ header file insulates other header files and source files from
+ platform differences, like which system header files must be
+ included in what order, and what C preprocessor feature macros must
+ be defined to trigger certain features we expect out of the system.
+ A collorary to this is that C files should not directly include
+ system header files themselves.
+
+ There are some exceptions, because certain group of files that
+ implement an API all have to include the same header file that
+ defines the API and it is convenient to include <git-compat-util.h>
+ there. Namely:
+
+ - the implementation of the built-in commands in the "builtin/"
+ directory that include "builtin.h" for the cmd_foo() prototype
+ definition,
+
+ - the test helper programs in the "t/helper/" directory that include
+ "t/helper/test-tool.h" for the cmd__foo() prototype definition,
+
+ - the xdiff implementation in the "xdiff/" directory that includes
+ "xdiff/xinclude.h" for the xdiff machinery internals,
+
+ - the unit test programs in "t/unit-tests/" directory that include
+ "t/unit-tests/test-lib.h" that gives them the unit-tests
+ framework, and
+
+ - the source files that implement reftable in the "reftable/"
+ directory that include "reftable/system.h" for the reftable
+ internals,
+
+ are allowed to assume that they do not have to include
+ <git-compat-util.h> themselves, as it is included as the first
+ '#include' in these header files. These headers must be the first
+ header file to be "#include"d in them, though.
- A C file must directly include the header files that declare the
functions and the types it uses, except for the functions and types
@@ -486,11 +585,61 @@ For C programs:
use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb"
./bin-wrappers/git log` (See `wrap-for-bin.sh`.)
+ - The primary data structure that a subsystem 'S' deals with is called
+ `struct S`. Functions that operate on `struct S` are named
+ `S_<verb>()` and should generally receive a pointer to `struct S` as
+ first parameter. E.g.
+
+ struct strbuf;
+
+ void strbuf_add(struct strbuf *buf, ...);
+
+ void strbuf_reset(struct strbuf *buf);
+
+ is preferred over:
+
+ struct strbuf;
+
+ void add_string(struct strbuf *buf, ...);
+
+ void reset_strbuf(struct strbuf *buf);
+
+ - There are several common idiomatic names for functions performing
+ specific tasks on a structure `S`:
+
+ - `S_init()` initializes a structure without allocating the
+ structure itself.
+
+ - `S_release()` releases a structure's contents without freeing the
+ structure.
+
+ - `S_clear()` is equivalent to `S_release()` followed by `S_init()`
+ such that the structure is directly usable after clearing it. When
+ `S_clear()` is provided, `S_init()` shall not allocate resources
+ that need to be released again.
+
+ - `S_free()` releases a structure's contents and frees the
+ structure.
+
+ - Function names should be clear and descriptive, accurately reflecting
+ their purpose or behavior. Arbitrary suffixes that do not add meaningful
+ context can lead to confusion, particularly for newcomers to the codebase.
+
+ Historically, the '_1' suffix has been used in situations where:
+
+ - A function handles one element among a group that requires similar
+ processing.
+ - A recursive function has been separated from its setup phase.
+
+ The '_1' suffix can be used as a concise way to indicate these specific
+ cases. However, it is recommended to find a more descriptive name wherever
+ possible to improve the readability and maintainability of the code.
+
For Perl programs:
- Most of the C guidelines above apply.
- - We try to support Perl 5.8 and later ("use Perl 5.008").
+ - We try to support Perl 5.8.1 and later ("use Perl 5.008001").
- use strict and use warnings are strongly preferred.
@@ -518,7 +667,7 @@ For Perl programs:
For Python scripts:
- - We follow PEP-8 (http://www.python.org/dev/peps/pep-0008/).
+ - We follow PEP-8 (https://peps.python.org/pep-0008/).
- As a minimum, we aim to be compatible with Python 2.7.
@@ -578,7 +727,7 @@ Externally Visible Names
. The variable name describes the effect of tweaking this knob.
The section and variable names that consist of multiple words are
- formed by concatenating the words without punctuations (e.g. `-`),
+ formed by concatenating the words without punctuation marks (e.g. `-`),
and are broken using bumpyCaps in documentation as a hint to the
reader.
@@ -612,15 +761,15 @@ Writing Documentation:
- Prefer succinctness and matter-of-factly describing functionality
in the abstract. E.g.
- --short:: Emit output in the short-format.
+ `--short`:: Emit output in the short-format.
and avoid something like these overly verbose alternatives:
- --short:: Use this to emit output in the short-format.
- --short:: You can use this to get output in the short-format.
- --short:: A user who prefers shorter output could....
- --short:: Should a person and/or program want shorter output, he
- she/they/it can...
+ `--short`:: Use this to emit output in the short-format.
+ `--short`:: You can use this to get output in the short-format.
+ `--short`:: A user who prefers shorter output could....
+ `--short`:: Should a person and/or program want shorter output, he
+ she/they/it can...
This practice often eliminates the need to involve human actors in
your description, but it is a good practice regardless of the
@@ -630,12 +779,12 @@ Writing Documentation:
addressing the hypothetical user, and possibly "we" when
discussing how the program might react to the user. E.g.
- You can use this option instead of --xyz, but we might remove
+ You can use this option instead of `--xyz`, but we might remove
support for it in future versions.
while keeping in mind that you can probably be less verbose, e.g.
- Use this instead of --xyz. This option might be removed in future
+ Use this instead of `--xyz`. This option might be removed in future
versions.
- If you still need to refer to an example person that is
@@ -653,18 +802,72 @@ Writing Documentation:
The same general rule as for code applies -- imitate the existing
conventions.
- A few commented examples follow to provide reference when writing or
- modifying command usage strings and synopsis sections in the manual
- pages:
- Placeholders are spelled in lowercase and enclosed in angle brackets:
- <file>
- --sort=<key>
- --abbrev[=<n>]
+Markup:
+
+ Literal parts (e.g. use of command-line options, command names,
+ branch names, URLs, pathnames (files and directories), configuration and
+ environment variables) must be typeset as verbatim (i.e. wrapped with
+ backticks):
+ `--pretty=oneline`
+ `git rev-list`
+ `remote.pushDefault`
+ `http://git.example.com`
+ `.git/config`
+ `GIT_DIR`
+ `HEAD`
+ `umask`(2)
+
+ An environment variable must be prefixed with "$" only when referring to its
+ value and not when referring to the variable itself, in this case there is
+ nothing to add except the backticks:
+ `GIT_DIR` is specified
+ `$GIT_DIR/hooks/pre-receive`
+
+ Word phrases enclosed in `backtick characters` are rendered literally
+ and will not be further expanded. The use of `backticks` to achieve the
+ previous rule means that literal examples should not use AsciiDoc
+ escapes.
+ Correct:
+ `--pretty=oneline`
+ Incorrect:
+ `\--pretty=oneline`
+
+ Placeholders are spelled in lowercase and enclosed in
+ angle brackets surrounded by underscores:
+ _<file>_
+ _<commit>_
If a placeholder has multiple words, they are separated by dashes:
- <new-branch-name>
- --template=<template-directory>
+ _<new-branch-name>_
+ _<template-directory>_
+
+ When needed, use a distinctive identifier for placeholders, usually
+ made of a qualification and a type:
+ _<git-dir>_
+ _<key-id>_
+
+ Git's Asciidoc processor has been tailored to treat backticked text
+ as complex synopsis. When literal and placeholders are mixed, you can
+ use the backtick notation which will take care of correctly typesetting
+ the content.
+ `--jobs <n>`
+ `--sort=<key>`
+ `<directory>/.git`
+ `remote.<name>.mirror`
+ `ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>`
+
+As a side effect, backquoted placeholders are correctly typeset, but
+this style is not recommended.
+
+Synopsis Syntax
+
+ The synopsis (a paragraph with [synopsis] attribute) is automatically
+ formatted by the toolchain and does not need typesetting.
+
+ A few commented examples follow to provide reference when writing or
+ modifying command usage strings and synopsis sections in the manual
+ pages:
Possibility of multiple occurrences is indicated by three dots:
<file>...
@@ -674,6 +877,9 @@ Writing Documentation:
[<file>...]
(Zero or more of <file>.)
+ An optional parameter needs to be typeset with unconstrained pairs
+ [<repository>]
+
--exec-path[=<path>]
(Option with an optional argument. Note that the "=" is inside the
brackets.)
@@ -697,14 +903,14 @@ Writing Documentation:
Don't: --track[=(direct | inherit)]
Parentheses are used for grouping:
- [(<rev> | <range>)...]
+ [(<rev>|<range>)...]
(Any number of either <rev> or <range>. Parens are needed to make
it clear that "..." pertains to both <rev> and <range>.)
[(-p <parent>)...]
(Any number of option -p, each with one <parent> argument.)
- git remote set-head <name> (-a | -d | <branch>)
+ git remote set-head <name> (-a|-d|<branch>)
(One and only one of "-a", "-d" or "<branch>" _must_ (no square
brackets) be provided.)
@@ -720,37 +926,6 @@ Writing Documentation:
the user would type into a shell and use 'Git' (uppercase first letter)
when talking about the version control system and its properties.
- A few commented examples follow to provide reference when writing or
- modifying paragraphs or option/command explanations that contain options
- or commands:
-
- Literal examples (e.g. use of command-line options, command names,
- branch names, URLs, pathnames (files and directories), configuration and
- environment variables) must be typeset in monospace (i.e. wrapped with
- backticks):
- `--pretty=oneline`
- `git rev-list`
- `remote.pushDefault`
- `http://git.example.com`
- `.git/config`
- `GIT_DIR`
- `HEAD`
-
- An environment variable must be prefixed with "$" only when referring to its
- value and not when referring to the variable itself, in this case there is
- nothing to add except the backticks:
- `GIT_DIR` is specified
- `$GIT_DIR/hooks/pre-receive`
-
- Word phrases enclosed in `backtick characters` are rendered literally
- and will not be further expanded. The use of `backticks` to achieve the
- previous rule means that literal examples should not use AsciiDoc
- escapes.
- Correct:
- `--pretty=oneline`
- Incorrect:
- `\--pretty=oneline`
-
If some place in the documentation needs to typeset a command usage
example with inline substitutions, it is fine to use +monospaced and
inline substituted text+ instead of `monospaced literal text`, and with
diff --git a/Documentation/DecisionMaking.txt b/Documentation/DecisionMaking.txt
new file mode 100644
index 0000000000..b43c472ae5
--- /dev/null
+++ b/Documentation/DecisionMaking.txt
@@ -0,0 +1,74 @@
+Decision-Making Process in the Git Project
+==========================================
+
+Introduction
+------------
+This document describes the current decision-making process in the Git
+project. It is a descriptive rather than prescriptive doc; that is, we want to
+describe how things work in practice rather than explicitly recommending any
+particular process or changes to the current process.
+
+Here we document how the project makes decisions for discussions
+(with or without patches), in scale larger than an individual patch
+series (which is fully covered by the SubmittingPatches document).
+
+
+Larger Discussions (with patches)
+---------------------------------
+As with discussions on an individual patch series, starting a larger-scale
+discussion often begins by sending a patch or series to the list. This might
+take the form of an initial design doc, with implementation following in later
+iterations of the series (for example,
+link:https://lore.kernel.org/git/0169ce6fb9ccafc089b74ae406db0d1a8ff8ac65.1688165272.git.steadmon@google.com/[adding unit tests] or
+link:https://lore.kernel.org/git/20200420235310.94493-1-emilyshaffer@google.com/[config-based hooks]),
+or it might include a full implementation from the beginning.
+In either case, discussion progresses the same way for an individual patch series,
+until consensus is reached or the topic is dropped.
+
+
+Larger Discussions (without patches)
+------------------------------------
+Occasionally, larger discussions might occur without an associated patch series.
+These may be very large-scale technical decisions that are beyond the scope of
+even a single large patch series, or they may be more open-ended,
+policy-oriented discussions (examples:
+link:https://lore.kernel.org/git/ZZ77NQkSuiRxRDwt@nand.local/[introducing Rust]
+or link:https://lore.kernel.org/git/YHofmWcIAidkvJiD@google.com/[improving submodule UX]).
+In either case, discussion progresses as described above for general patch series.
+
+For larger discussions without a patch series or other concrete implementation,
+it may be hard to judge when consensus has been reached, as there are not any
+official guidelines. If discussion stalls at this point, it may be helpful to
+restart discussion with an RFC patch series (such as a partial, unfinished
+implementation or proof of concept) that can be more easily debated.
+
+When consensus is reached that it is a good idea, the original
+proposer is expected to coordinate the effort to make it happen,
+with help from others who were involved in the discussion, as
+needed.
+
+For decisions that require code changes, it is often the case that the original
+proposer will follow up with a patch series, although it is also common for
+other interested parties to provide an implementation (or parts of the
+implementation, for very large changes).
+
+For non-technical decisions such as community norms or processes, it is up to
+the community as a whole to implement and sustain agreed-upon changes.
+The project leadership committee (PLC) may help the implementation of
+policy decisions.
+
+
+Other Discussion Venues
+-----------------------
+Occasionally decision proposals are presented off-list, e.g. at the semi-regular
+Contributors' Summit. While higher-bandwidth face-to-face discussion is often
+useful for quickly reaching consensus among attendees, generally we expect to
+summarize the discussion in notes that can later be presented on-list. For an
+example, see the thread
+link:https://lore.kernel.org/git/AC2EB721-2979-43FD-922D-C5076A57F24B@jramsay.com.au/[Notes
+from Git Contributor Summit, Los Angeles (April 5, 2020)] by James Ramsay.
+
+We prefer that "official" discussion happens on the list so that the full
+community has opportunity to engage in discussion. This also means that the
+mailing list archives contain a more-or-less complete history of project
+discussions and decisions.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index b629176d7d..0f55baa252 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -51,6 +51,7 @@ MAN7_TXT += gitdiffcore.txt
MAN7_TXT += giteveryday.txt
MAN7_TXT += gitfaq.txt
MAN7_TXT += gitglossary.txt
+MAN7_TXT += gitpacking.txt
MAN7_TXT += gitnamespaces.txt
MAN7_TXT += gitremote-helpers.txt
MAN7_TXT += gitrevisions.txt
@@ -103,6 +104,7 @@ SP_ARTICLES += howto/coordinate-embargoed-releases
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
SP_ARTICLES += $(API_DOCS)
+TECH_DOCS += DecisionMaking
TECH_DOCS += ReviewingGuidelines
TECH_DOCS += MyFirstContribution
TECH_DOCS += MyFirstObjectWalk
@@ -116,12 +118,14 @@ TECH_DOCS += technical/multi-pack-index
TECH_DOCS += technical/pack-heuristics
TECH_DOCS += technical/parallel-checkout
TECH_DOCS += technical/partial-clone
+TECH_DOCS += technical/platform-support
TECH_DOCS += technical/racy-git
TECH_DOCS += technical/reftable
TECH_DOCS += technical/scalar
TECH_DOCS += technical/send-pack-pipeline
TECH_DOCS += technical/shallow
TECH_DOCS += technical/trivial-merge
+TECH_DOCS += technical/unit-tests
SP_ARTICLES += $(TECH_DOCS)
SP_ARTICLES += technical/api-index
@@ -201,12 +205,15 @@ ASCIIDOC_DOCBOOK = docbook5
ASCIIDOC_EXTRA += -acompat-mode -atabsize=8
ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;'
+ASCIIDOC_EXTRA += -adocinfo=shared
ASCIIDOC_DEPS = asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS
DBLATEX_COMMON =
XMLTO_EXTRA += --skip-validation
XMLTO_EXTRA += -x manpage.xsl
endif
+ASCIIDOC_DEPS += docinfo.html
+
SHELL_PATH ?= $(SHELL)
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
@@ -335,6 +342,9 @@ clean:
$(RM) $(cmds_txt) $(mergetools_txt) *.made
$(RM) GIT-ASCIIDOCFLAGS
+docinfo.html: docinfo-html.in
+ $(QUIET_GEN)$(RM) $@ && cat $< >$@
+
$(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS)
$(QUIET_ASCIIDOC)$(TXT_TO_HTML) -d manpage -o $@ $<
@@ -483,12 +493,16 @@ $(LINT_DOCS_FSCK_MSGIDS): ../fsck.h fsck-msgids.txt
lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS)
+lint-docs-manpages:
+ $(QUIET_GEN)./lint-manpages.sh
+
## Lint: list of targets above
.PHONY: lint-docs
lint-docs: lint-docs-fsck-msgids
lint-docs: lint-docs-gitlink
lint-docs: lint-docs-man-end-blurb
lint-docs: lint-docs-man-section-order
+lint-docs: lint-docs-manpages
ifeq ($(wildcard po/Makefile),po/Makefile)
doc-l10n install-l10n::
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 62d11a5cd7..e41654c00a 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -35,8 +35,9 @@ announcements, design discussions, and more take place. Those interested in
contributing are welcome to post questions here. The Git list requires
plain-text-only emails and prefers inline and bottom-posting when replying to
mail; you will be CC'd in all replies to you. Optionally, you can subscribe to
-the list by sending an email to majordomo@vger.kernel.org with "subscribe git"
-in the body. The https://lore.kernel.org/git[archive] of this mailing list is
+the list by sending an email to <git+subscribe@vger.kernel.org>
+(see https://subspace.kernel.org/subscribing.html for details).
+The https://lore.kernel.org/git[archive] of this mailing list is
available to view in a browser.
==== https://groups.google.com/forum/#!forum/git-mentoring[git-mentoring@googlegroups.com]
@@ -160,10 +161,11 @@ in order to keep the declarations alphabetically sorted:
int cmd_psuh(int argc, const char **argv, const char *prefix);
----
-Be sure to `#include "builtin.h"` in your `psuh.c`.
+Be sure to `#include "builtin.h"` in your `psuh.c`. You'll also need to
+`#include "gettext.h"` to use functions related to printing output text.
-Go ahead and add some throwaway printf to that function. This is a decent
-starting point as we can now add build rules and register the command.
+Go ahead and add some throwaway printf to the `cmd_psuh` function. This is a
+decent starting point as we can now add build rules and register the command.
NOTE: Your throwaway text, as well as much of the text you will be adding over
the course of this tutorial, is user-facing. That means it needs to be
@@ -832,7 +834,7 @@ Johannes Schindelin to make life as a Git contributor easier for those used to
the GitHub PR workflow. It allows contributors to open pull requests against its
mirror of the Git project, and does some magic to turn the PR into a set of
emails and send them out for you. It also runs the Git continuous integration
-suite for you. It's documented at http://gitgitgadget.github.io.
+suite for you. It's documented at https://gitgitgadget.github.io/.
[[create-fork]]
=== Forking `git/git` on GitHub
@@ -1114,6 +1116,15 @@ $ git send-email --to=target@example.com psuh/*.patch
NOTE: Check `git help send-email` for some other options which you may find
valuable, such as changing the Reply-to address or adding more CC and BCC lines.
+:contrib-scripts: footnoteref:[contrib-scripts,Scripts under `contrib/` are +
+not part of the core `git` binary and must be called directly. Clone the Git +
+codebase and run `perl contrib/contacts/git-contacts`.]
+
+NOTE: If you're not sure whom to CC, running `contrib/contacts/git-contacts` can
+list potential reviewers. In addition, you can do `git send-email
+--cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch`{contrib-scripts} to
+automatically pass this list of emails to `send-email`.
+
NOTE: When you are sending a real patch, it will go to git@vger.kernel.org - but
please don't send your patchset from the tutorial to the real mailing list! For
now, you can send it to yourself, to make sure you understand how it will look.
diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.txt
index c68cdb11b9..dec8afe5b1 100644
--- a/Documentation/MyFirstObjectWalk.txt
+++ b/Documentation/MyFirstObjectWalk.txt
@@ -210,13 +210,14 @@ We'll also need to include the `config.h` header:
...
-static int git_walken_config(const char *var, const char *value, void *cb)
+static int git_walken_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
/*
* For now, we don't have any custom configuration, so fall back to
* the default config.
*/
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
----
@@ -389,10 +390,11 @@ modifying `rev_info.grep_filter`, which is a `struct grep_opt`.
First some setup. Add `grep_config()` to `git_walken_config()`:
----
-static int git_walken_config(const char *var, const char *value, void *cb)
+static int git_walken_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- grep_config(var, value, cb);
- return git_default_config(var, value, cb);
+ grep_config(var, value, ctx, cb);
+ return git_default_config(var, value, ctx, cb);
}
----
@@ -523,7 +525,7 @@ about each one.
We can base our work on an example. `git pack-objects` prepares all kinds of
objects for packing into a bitmap or packfile. The work we are interested in
-resides in `builtins/pack-objects.c:get_object_list()`; examination of that
+resides in `builtin/pack-objects.c:get_object_list()`; examination of that
function shows that the all-object walk is being performed by
`traverse_commit_list()` or `traverse_commit_list_filtered()`. Those two
functions reside in `list-objects.c`; examining the source shows that, despite
@@ -732,8 +734,8 @@ walk we've just performed:
} else {
trace_printf(
_("Filtered object walk with filterspec 'tree:1'.\n"));
- CALLOC_ARRAY(rev->filter, 1);
- parse_list_objects_filter(rev->filter, "tree:1");
+
+ parse_list_objects_filter(&rev->filter, "tree:1");
}
traverse_commit_list(rev, walken_show_commit,
walken_show_object, NULL);
@@ -752,10 +754,12 @@ points to the same tree object as its grandparent.)
=== Counting Omitted Objects
We also have the capability to enumerate all objects which were omitted by a
-filter, like with `git log --filter=<spec> --filter-print-omitted`. Asking
-`traverse_commit_list_filtered()` to populate the `omitted` list means that our
-object walk does not perform any better than an unfiltered object walk; all
-reachable objects are walked in order to populate the list.
+filter, like with `git log --filter=<spec> --filter-print-omitted`. To do this,
+change `traverse_commit_list()` to `traverse_commit_list_filtered()`, which is
+able to populate an `omitted` list. Asking for this list of filtered objects
+may cause performance degradations, however, because in this case, despite
+filtering objects, the possibly much larger set of all reachable objects must
+be processed in order to populate that list.
First, add the `struct oidset` and related items we will use to iterate it:
@@ -776,8 +780,9 @@ static void walken_object_walk(
...
----
-Modify the call to `traverse_commit_list_filtered()` to include your `omitted`
-object:
+Replace the call to `traverse_commit_list()` with
+`traverse_commit_list_filtered()` and pass a pointer to the `omitted` oidset
+defined and initialized above:
----
...
@@ -843,7 +848,7 @@ those lines without having to recompile.
With only that change, run again (but save yourself some scrollback):
----
-$ GIT_TRACE=1 ./bin-wrappers/git walken | head -n 10
+$ GIT_TRACE=1 ./bin-wrappers/git walken 2>&1 | head -n 10
----
Take a look at the top commit with `git show` and the object ID you printed; it
@@ -871,7 +876,7 @@ of the first handful:
----
$ make
-$ GIT_TRACE=1 ./bin-wrappers git walken | tail -n 10
+$ GIT_TRACE=1 ./bin-wrappers/git walken 2>&1 | tail -n 10
----
The last commit object given should have the same OID as the one we saw at the
diff --git a/Documentation/RelNotes/1.6.2.txt b/Documentation/RelNotes/1.6.2.txt
index 980adfb315..166d73c60f 100644
--- a/Documentation/RelNotes/1.6.2.txt
+++ b/Documentation/RelNotes/1.6.2.txt
@@ -10,7 +10,7 @@ To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
- http://git.or.cz/gitwiki/GitFaq#non-bare
+ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
for more details on the reason why this change is needed and the
diff --git a/Documentation/RelNotes/1.6.3.txt b/Documentation/RelNotes/1.6.3.txt
index 4bcff945e0..bbf177fc3c 100644
--- a/Documentation/RelNotes/1.6.3.txt
+++ b/Documentation/RelNotes/1.6.3.txt
@@ -10,7 +10,7 @@ To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
- http://git.or.cz/gitwiki/GitFaq#non-bare
+ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
for more details on the reason why this change is needed and the
diff --git a/Documentation/RelNotes/1.6.4.txt b/Documentation/RelNotes/1.6.4.txt
index a2a34b43a7..0fccfb0bf0 100644
--- a/Documentation/RelNotes/1.6.4.txt
+++ b/Documentation/RelNotes/1.6.4.txt
@@ -10,7 +10,7 @@ To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
- http://git.or.cz/gitwiki/GitFaq#non-bare
+ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
for more details on the reason why this change is needed and the
diff --git a/Documentation/RelNotes/1.6.5.txt b/Documentation/RelNotes/1.6.5.txt
index 6c7f7da7eb..79cb1b2b6d 100644
--- a/Documentation/RelNotes/1.6.5.txt
+++ b/Documentation/RelNotes/1.6.5.txt
@@ -21,7 +21,7 @@ To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
- http://git.or.cz/gitwiki/GitFaq#non-bare
+ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
for more details on the reason why this change is needed and the
diff --git a/Documentation/RelNotes/1.6.6.txt b/Documentation/RelNotes/1.6.6.txt
index 3ed1e01433..88b86a827e 100644
--- a/Documentation/RelNotes/1.6.6.txt
+++ b/Documentation/RelNotes/1.6.6.txt
@@ -63,7 +63,7 @@ users will fare this time.
Please refer to:
- http://git.or.cz/gitwiki/GitFaq#non-bare
+ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
for more details on the reason why this change is needed and the
diff --git a/Documentation/RelNotes/2.43.0.txt b/Documentation/RelNotes/2.43.0.txt
new file mode 100644
index 0000000000..e0e5b535bb
--- /dev/null
+++ b/Documentation/RelNotes/2.43.0.txt
@@ -0,0 +1,323 @@
+Git v2.43 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+ * The "--rfc" option of "git format-patch" used to be a valid way to
+ override an earlier "--subject-prefix=<something>" on the command
+ line and replace it with "[RFC PATCH]", but from this release, it
+ merely prefixes the string "RFC " in front of the given subject
+ prefix. If you are negatively affected by this change, please use
+ "--subject-prefix=PATCH --rfc" as a replacement.
+
+ * In Git 2.42, "git rev-list --stdin" learned to take non-revisions
+ (like "--not") from the standard input, but the way such a "--not" was
+ handled was quite confusing, which has been rethought. The updated
+ rule is that "--not" given from the command line only affects revs
+ given from the command line that comes but not revs read from the
+ standard input, and "--not" read from the standard input affects
+ revs given from the standard input and not revs given from the
+ command line.
+
+UI, Workflows & Features
+
+ * A message written in olden time prevented a branch from getting
+ checked out, saying it is already checked out elsewhere. But these
+ days, we treat a branch that is being bisected or rebased just like
+ a branch that is checked out and protect it from getting modified
+ with the same codepath. The message has been rephrased to say that
+ the branch is "in use" to avoid confusion.
+
+ * Hourly and other schedules of "git maintenance" jobs are randomly
+ distributed now.
+
+ * "git cmd -h" learned to signal which options can be negated by
+ listing such options like "--[no-]opt".
+
+ * The way authentication related data other than passwords (e.g.,
+ oauth token and password expiration data) are stored in libsecret
+ keyrings has been rethought.
+
+ * Update the libsecret and wincred credential helpers to correctly
+ match which credential to erase; they erased the wrong entry in
+ some cases.
+
+ * Git GUI updates.
+
+ * "git format-patch" learned a new "--description-file" option that
+ lets cover letter description to be fed; this can be used on
+ detached HEAD where there is no branch description available, and
+ also can override the branch description if there is one.
+
+ * Use of the "--max-pack-size" option to allow multiple packfiles to
+ be created is now supported even when we are sending unreachable
+ objects to cruft packs.
+
+ * "git format-patch --rfc --subject-prefix=<foo>" used to ignore the
+ "--subject-prefix" option and used "[RFC PATCH]"; now we will add
+ "RFC" prefix to whatever subject prefix is specified.
+
+ * "git log --format" has been taught the %(decorate) placeholder for
+ further customization over what the "--decorate" option offers.
+
+ * The default log message created by "git revert", when reverting a
+ commit that records a revert, has been tweaked, to encourage people
+ to describe complex "revert of revert of revert" situations better in
+ their own words.
+
+ * The command-line completion support (in contrib/) learned to
+ complete "git commit --trailer=" for possible trailer keys.
+
+ * "git update-index" learned the "--show-index-version" option to
+ inspect the index format version used by the on-disk index file.
+
+ * "git diff" learned the "diff.statNameWidth" configuration variable,
+ to give the default width for the name part in the "--stat" output.
+
+ * "git range-diff --notes=foo" compared "log --notes=foo --notes" of
+ the two ranges, instead of using just the specified notes tree,
+ which has been corrected to use only the specified notes tree.
+
+ * The command line completion script (in contrib/) can be told to
+ complete aliases by including ": git <cmd> ;" in the alias to tell
+ it that the alias should be completed in a similar way to how "git
+ <cmd>" is completed. The parsing code for the alias has been
+ loosened to allow ';' without an extra space before it.
+
+ * "git for-each-ref" and friends learned to apply mailmap to
+ authorname and other fields in a more flexible way than using
+ separate placeholder letters like %a[eElL] every time we want to
+ come up with small variants.
+
+ * "git repack" machinery learned to pay attention to the "--filter="
+ option.
+
+ * "git repack" learned the "--max-cruft-size" option to prevent cruft
+ packs from growing without bounds.
+
+ * "git merge-tree" learned to take strategy backend specific options
+ via the "-X" option, like "git merge" does.
+
+ * "git log" and friends learned the "--dd" option that is a
+ short-hand for "--diff-merges=first-parent -p".
+
+ * The attribute subsystem learned to honor the "attr.tree"
+ configuration variable that specifies which tree to read the
+ .gitattributes files from.
+
+ * "git merge-file" learns a mode to read three variants of the
+ contents to be merged from blob objects.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git check-attr" has been taught to work better with sparse-index.
+
+ * It may be tempting to leave the help text NULL for a command line
+ option that is either hidden or too obvious, but "git subcmd -h"
+ and "git subcmd --help-all" would have segfaulted if done so. Now
+ the help text is truly optional.
+
+ * Tests that are known to pass with LSan are now marked as such.
+
+ * Flaky "git p4" tests, as well as "git svn" tests, are now skipped
+ in the (rather expensive) sanitizer CI job.
+
+ * Tests with LSan from time to time seem to emit harmless messages
+ that make our tests unnecessarily flaky; we work around it by
+ filtering the uninteresting output.
+
+ * Unused parameters to functions are marked as such, and/or removed,
+ in order to bring us closer to "-Wunused-parameter" clean.
+
+ * The code to keep track of existing packs in the repository while
+ repacking has been refactored.
+
+ * The "streaming" interface used for bulk-checkin codepath has been
+ narrowed to take only blob objects for now, with no real loss of
+ functionality.
+
+ * GitHub CI workflow has learned to trigger Coverity check.
+
+ * Test coverage for trailers has been improved.
+
+ * The code to iterate over loose references has been optimized to
+ reduce the number of lstat() system calls.
+
+ * The codepaths that read "chunk" formatted files have been corrected
+ to pay attention to the chunk size and notice broken files.
+
+ * Replace macos-12 used at GitHub CI with macos-13.
+ (merge 682a868f67 js/ci-use-macos-13 later to maint).
+
+
+Fixes since v2.42
+-----------------
+
+ * Overly long label names used in the sequencer machinery are now
+ chopped to fit under filesystem limitation.
+
+ * Scalar updates.
+
+ * Tweak GitHub Actions CI so that pushing the same commit to multiple
+ branch tips at the same time will not waste building and testing
+ the same thing twice.
+
+ * The commit-graph verification code that detects a mixture of zero and
+ non-zero generation numbers has been updated.
+
+ * "git diff -w --exit-code" with various options did not work
+ correctly, which has been corrected.
+
+ * The "transfer.unpackLimit" configuration variable ought to be used
+ as a fallback, but overrode the more specific "fetch.unpackLimit"
+ and "receive.unpackLimit" configuration variables by mistake, which
+ has been corrected.
+
+ * The use of API between two calls to require_clean_work_tree() from
+ the sequencer code has been cleaned up for consistency.
+
+ * "git diff --no-such-option" and other corner cases around the exit
+ status of the "diff" command have been corrected.
+
+ * "git for-each-ref --sort='contents:size'" sorted the refs according
+ to size numerically, giving a ref that points at a blob twelve-byte
+ (12) long before showing a blob hundred-byte (100) long, which has
+ been corrected.
+
+ * We now limit the depth of the tree objects and maximum length of
+ pathnames recorded in tree objects.
+ (merge 4d5693ba05 jk/tree-name-and-depth-limit later to maint).
+
+ * Various fixes to the behavior of "rebase -i", when the command got
+ interrupted by conflicting changes, have been made.
+
+ * References from a description of the `--patch` option in various
+ manual pages have been simplified and improved.
+
+ * "git grep -e A --no-or -e B" is accepted, even though the negation
+ of the "--or" option did not mean anything, which has been tightened.
+
+ * The completion script (in contrib/) has been taught to treat the
+ "-t" option to "git checkout" and "git switch" just like the
+ "--track" option, to complete remote-tracking branches.
+
+ * "git diff --no-index -R <(one) <(two)" did not work correctly,
+ which has been corrected.
+
+ * "git maintenance" timers' implementation has been updated, based on
+ systemd timers, to work with WSL.
+
+ * "git diff --cached" codepath did not fill the necessary stat
+ information for a file when fsmonitor knows it is clean and ended
+ up behaving as if it were not clean, which has been corrected.
+
+ * How "alias.foo = : git cmd ; aliased-command-string" should be
+ spelled with necessary whitespace around punctuation marks to work
+ has been more clearly documented (but this will be moot with newer
+ versions of Git where the parsing rules have been improved).
+
+ * HTTP Header redaction code has been adjusted for a newer version of
+ cURL library that shows its traces differently from earlier
+ versions.
+
+ * An error message given by "git send-email", when given a malformed
+ address, did not show the offending address, which has been corrected.
+
+ * UBSan options were not propagated through the test framework to git
+ run via the httpd, unlike ASan options, which has been corrected.
+
+ * "checkout --merge -- path" and "update-index --unresolve path" did
+ not resurrect conflicted state that was resolved to remove path,
+ but now they do.
+ (merge 5bdedac3c7 jc/unresolve-removal later to maint).
+
+ * The display width table for unicode characters has been updated for
+ Unicode 15.1
+ (merge 872976c37e bb/unicode-width-table-15 later to maint).
+
+ * Update mailmap entry for Derrick.
+ (merge 6e5457d8c7 ds/mailmap-entry-update later to maint).
+
+ * In the ".gitmodules" files, submodules are keyed by their names,
+ and the path to the submodule whose name is $name is specified by
+ the submodule.$name.path variable. There were a few codepaths that
+ mixed the name and path up when consulting the submodule database,
+ which have been corrected. It took long for these bugs to be found
+ as the name of a submodule initially is the same as its path, and
+ the problem does not surface until it is moved to a different path,
+ which apparently happens very rarely.
+
+ * "git diff --merge-base X other args..." insisted that X must be a
+ commit and errored out when given an annotated tag that peels to a
+ commit, but we only need it to be a committish. This has been
+ corrected.
+ (merge 4adceb5a29 ar/diff-index-merge-base-fix later to maint).
+
+ * "git merge-tree" used to segfault when the "--attr-source"
+ option is used, which has been corrected.
+ (merge e95bafc52f jc/merge-ort-attr-index-fix later to maint).
+
+ * Unlike "git log --pretty=%D", "git log --pretty="%(decorate)" did
+ not auto-initialize the decoration subsystem, which has been
+ corrected.
+
+ * Feeding "git stash store" with a random commit that was not created
+ by "git stash create" now errors out.
+ (merge d9b6634589 jc/fail-stash-to-store-non-stash later to maint).
+
+ * The index file has room only for the lower 32-bit of the file size in
+ the cached stat information, which means cached stat information
+ will have 0 in its sd_size member for a file whose size is a multiple
+ of 4GiB. This is mistaken for a racily clean path. Avoid it by
+ storing a bogus sd_size value instead for such files.
+ (merge 5143ac07b1 bc/racy-4gb-files later to maint).
+
+ * "git p4" tried to store symlinks to LFS when told, but has been
+ fixed not to do so, because it does not make sense.
+ (merge 10c89a02b0 mm/p4-symlink-with-lfs later to maint).
+
+ * The codepath to handle recipient addresses `git send-email
+ --compose` learns from the user was completely broken, which has
+ been corrected.
+ (merge 3ec6167567 jk/send-email-fix-addresses-from-composed-messages later to maint).
+
+ * "cd sub && git grep -f patterns" tried to read "patterns" file at
+ the top level of the working tree; it has been corrected to read
+ "sub/patterns" instead.
+
+ * "git reflog expire --single-worktree" has been broken for the past
+ 20 months or so, which has been corrected.
+
+ * "git send-email" did not have certain pieces of data computed yet
+ when it tried to validate the outgoing messages and its recipient
+ addresses, which has been sorted out.
+
+ * "git bugreport" learned to complain when it received a command line
+ argument that it will not use.
+
+ * The codepath to traverse the commit-graph learned to notice that a
+ commit is missing (e.g., corrupt repository lost an object), even
+ though it knows something about the commit (like its parents) from
+ what is in commit-graph.
+ (merge 7a5d604443 ps/do-not-trust-commit-graph-blindly-for-existence later to maint).
+
+ * "git rev-list --missing" did not work for missing commit objects,
+ which has been corrected.
+
+ * "git rev-list --unpacked --objects" failed to exclude packed
+ non-commit objects, which has been corrected.
+ (merge 7b3c8e9f38 tb/rev-list-unpacked-fix later to maint).
+
+ * "To dereference" and "to peel" were sometimes used in in-code
+ comments and documentation but without description in the glossary.
+ (merge 893dce2ffb vd/glossary-dereference-peel later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge c2c349a15c xz/commit-title-soft-limit-doc later to maint).
+ (merge 1bd809938a tb/format-pack-doc-update later to maint).
+ (merge 8f81532599 an/clang-format-typofix later to maint).
+ (merge 3ca86adc2d la/strvec-header-fix later to maint).
+ (merge 6789275d37 jc/test-i18ngrep later to maint).
+ (merge 9972cd6004 ps/leakfixes later to maint).
+ (merge 46edab516b tz/send-email-helpfix later to maint).
diff --git a/Documentation/RelNotes/2.43.1.txt b/Documentation/RelNotes/2.43.1.txt
new file mode 100644
index 0000000000..20e96f2dfa
--- /dev/null
+++ b/Documentation/RelNotes/2.43.1.txt
@@ -0,0 +1,82 @@
+Git 2.43.1 Release Notes
+========================
+
+There is nothing exciting to see here. Relative to Git 2.43, this
+release contains the fixes that have already been merged to the
+'master' branch of the development towards the next major release.
+
+Fixes since Git 2.43.0
+----------------------
+
+ * The way CI testing used "prove" could lead to running the test
+ suite twice needlessly, which has been corrected.
+
+ * Newer versions of Getopt::Long started giving warnings against our
+ (ab)use of it in "git send-email". Bump the minimum version
+ requirement for Perl to 5.8.1 (from September 2002) to allow
+ simplifying our implementation.
+
+ * Earlier we stopped relying on commit-graph that (still) records
+ information about commits that are lost from the object store,
+ which has negative performance implications. The default has been
+ flipped to disable this pessimization.
+
+ * Stale URLs have been updated to their current counterparts (or
+ archive.org) and HTTP links are replaced with working HTTPS links.
+
+ * trace2 streams used to record the URLs that potentially embed
+ authentication material, which has been corrected.
+
+ * The sample pre-commit hook that tries to catch introduction of new
+ paths that use potentially non-portable characters did not notice
+ an existing path getting renamed to such a problematic path, when
+ rename detection was enabled.
+
+ * The command line parser for the "log" family of commands was too
+ loose when parsing certain numbers, e.g., silently ignoring the
+ extra 'q' in "git log -n 1q" without complaining, which has been
+ tightened up.
+
+ * "git $cmd --end-of-options --rev -- --path" for some $cmd failed
+ to interpret "--rev" as a rev, and "--path" as a path. This was
+ fixed for many programs like "reset" and "checkout".
+
+ * "git bisect reset" has been taught to clean up state files and refs
+ even when BISECT_START file is gone.
+
+ * Some codepaths did not correctly parse configuration variables
+ specified with valueless "true", which has been corrected.
+
+ * Code clean-up for sanity checking of command line options for "git
+ show-ref".
+
+ * The code to parse the From e-mail header has been updated to avoid
+ recursion.
+
+ * "git fetch --atomic" issued an unnecessary empty error message,
+ which has been corrected.
+
+ * Command line completion script (in contrib/) learned to work better
+ with the reftable backend.
+
+ * "git status" is taught to show both the branch being bisected and
+ being rebased when both are in effect at the same time.
+ cf. <xmqqil76kyov.fsf@gitster.g>
+
+ * "git archive --list extra garbage" silently ignored excess command
+ line parameters, which has been corrected.
+
+ * "git sparse-checkout set" added default patterns even when the
+ patterns are being fed from the standard input, which has been
+ corrected.
+
+ * Unlike other environment variables that took the usual
+ true/false/yes/no as well as 0/1, GIT_FLUSH only understood 0/1,
+ which has been corrected.
+
+ * Clearing in-core repository (happens during e.g., "git fetch
+ --recurse-submodules" with commit graph enabled) made in-core
+ commit object in an inconsistent state by discarding the necessary
+ data from commit-graph too early, which has been corrected.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.43.2.txt b/Documentation/RelNotes/2.43.2.txt
new file mode 100644
index 0000000000..5895e23a54
--- /dev/null
+++ b/Documentation/RelNotes/2.43.2.txt
@@ -0,0 +1,37 @@
+Git 2.43.2 Release Notes
+========================
+
+Relative to Git 2.43.1, this release has two important fixes to allow
+"git imap-send" to be built with NO_CURL defined, and to restore the
+forced flushing behaviour when GIT_FLUSH=1 is set. It also contains
+other, unexciting, fixes that have already been merged to the 'master'
+branch of the development towards the next major release.
+
+Fixes since Git 2.43.1
+----------------------
+
+ * Update to a new feature recently added, "git show-ref --exists".
+
+ * Rename detection logic ignored the final line of a file if it is an
+ incomplete line.
+
+ * "git diff --no-rename A B" did not disable rename detection but did
+ not trigger an error from the command line parser.
+
+ * "git diff --no-index file1 file2" segfaulted while invoking the
+ external diff driver, which has been corrected.
+
+ * Rewrite //-comments to /* comments */ in files whose comments
+ prevalently use the latter.
+
+ * A failed "git tag -s" did not necessarily result in an error
+ depending on the crypto backend, which has been corrected.
+
+ * "git stash" sometimes was silent even when it failed due to
+ unwritable index file, which has been corrected.
+
+ * Recent conversion to allow more than 0/1 in GIT_FLUSH broke the
+ mechanism by flipping what yes/no means by mistake, which has been
+ corrected.
+
+Also contains documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.43.3.txt b/Documentation/RelNotes/2.43.3.txt
new file mode 100644
index 0000000000..924f20594f
--- /dev/null
+++ b/Documentation/RelNotes/2.43.3.txt
@@ -0,0 +1,12 @@
+Git 2.43.3 Release Notes
+========================
+
+Relative to Git 2.43.2, this release fixes one regression that
+manifests while running "git commit -v --trailer".
+
+Fixes since Git 2.43.2
+----------------------
+
+ * "git commit -v --trailer=..." was broken with recent update and
+ placed the trailer _after_ the divider line, which has been
+ corrected.
diff --git a/Documentation/RelNotes/2.43.4.txt b/Documentation/RelNotes/2.43.4.txt
new file mode 100644
index 0000000000..0a842515ff
--- /dev/null
+++ b/Documentation/RelNotes/2.43.4.txt
@@ -0,0 +1,7 @@
+Git v2.43.4 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4, v2.40.2,
+v2.41.1 and v2.42.2 to address the security issues CVE-2024-32002,
+CVE-2024-32004, CVE-2024-32020, CVE-2024-32021 and CVE-2024-32465;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.43.5.txt b/Documentation/RelNotes/2.43.5.txt
new file mode 100644
index 0000000000..236b234b06
--- /dev/null
+++ b/Documentation/RelNotes/2.43.5.txt
@@ -0,0 +1,26 @@
+Git v2.43.5 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.' This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.43.4 and were not
+direct security fixes.
+
+Jeff King (5):
+ send-email: drop FakeTerm hack
+ send-email: avoid creating more than one Term::ReadLine object
+ ci: drop mention of BREW_INSTALL_PACKAGES variable
+ ci: avoid bare "gcc" for osx-gcc job
+ ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+ hook: plug a new memory leak
+ init: use the correct path of the templates directory again
+ Revert "core.hooksPath: add some protection while cloning"
+ tests: verify that `clone -c core.hooksPath=/dev/null` works again
+ clone: drop the protections where hooks aren't run
+ Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+ Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.44.0.txt b/Documentation/RelNotes/2.44.0.txt
new file mode 100644
index 0000000000..14f9ce8226
--- /dev/null
+++ b/Documentation/RelNotes/2.44.0.txt
@@ -0,0 +1,334 @@
+Git v2.44 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+ * "git checkout -B <branch>" used to allow switching to a branch that
+ is in use on another worktree, but this was by mistake. The users
+ need to use "--ignore-other-worktrees" option.
+
+
+UI, Workflows & Features
+
+ * "git add" and "git stash" learned to support the ":(attr:...)"
+ magic pathspec.
+
+ * "git rebase --autosquash" is now enabled for non-interactive rebase,
+ but it is still incompatible with the apply backend.
+
+ * Introduce "git replay", a tool meant on the server side without
+ working tree to recreate a history.
+
+ * "git merge-file" learned to take the "--diff-algorithm" option to
+ use algorithm different from the default "myers" diff.
+
+ * Command line completion (in contrib/) learned to complete path
+ arguments to the "add/set" subcommands of "git sparse-checkout"
+ better.
+
+ * "git checkout -B <branch> [<start-point>]" allowed a branch that is
+ in use in another worktree to be updated and checked out, which
+ might be a bit unexpected. The rule has been tightened, which is a
+ breaking change. "--ignore-other-worktrees" option is required to
+ unbreak you, if you are used to the current behaviour that "-B"
+ overrides the safety.
+
+ * The builtin_objectmode attribute is populated for each path
+ without adding anything in .gitattributes files, which would be
+ useful in magic pathspec, e.g., ":(attr:builtin_objectmode=100755)"
+ to limit to executables.
+
+ * "git fetch" learned to pay attention to "fetch.all" configuration
+ variable, which pretends as if "--all" was passed from the command
+ line when no remote parameter was given.
+
+ * In addition to (rather cryptic) Security Identifiers, show username
+ and domain in the error message when we barf on mismatch between
+ the Git directory and the current user on Windows.
+
+ * The error message given when "git branch -d branch" fails due to
+ commits unique to the branch has been split into an error and a new
+ conditional advice message.
+
+ * When given an existing but unreadable file as a configuration file,
+ gitweb behaved as if the file did not exist at all, but now it
+ errors out. This is a change that may break backward compatibility.
+
+ * When $HOME/.gitconfig is missing but XDG config file is available, we
+ should write into the latter, not former. "git gc" and "git
+ maintenance" wrote into a wrong "global config" file, which have
+ been corrected.
+
+ * Define "special ref" as a very narrow set that consists of
+ FETCH_HEAD and MERGE_HEAD, and clarify everything else that used to
+ be classified as such are actually just pseudorefs.
+
+ * All conditional "advice" messages show how to turn them off, which
+ becomes repetitive. Setting advice.* configuration explicitly on
+ now omits the instruction part.
+
+ * The "disable repository discovery of a bare repository" check,
+ triggered by setting safe.bareRepository configuration variable to
+ 'explicit', has been loosened to exclude the ".git/" directory inside
+ a non-bare repository from the check. So you can do "cd .git &&
+ git cmd" to run a Git command that works on a bare repository without
+ explicitly specifying $GIT_DIR now.
+
+ * The completion script (in contrib/) learned more options that can
+ be used with "git log".
+
+ * The labels on conflict markers for the common ancestor, our version,
+ and the other version are available to custom 3-way merge driver
+ via %S, %X, and %Y placeholders.
+
+ * The write codepath for the reftable data learned to honor
+ core.fsync configuration.
+
+ * The "--fsck-objects" option of "git index-pack" now can take the
+ optional parameter to tweak severity of different fsck errors.
+
+ * The wincred credential backend has been taught to support oauth
+ refresh token the same way as credential-cache and
+ credential-libsecret backends.
+
+ * Command line completion support (in contrib/) has been
+ updated for "git bisect".
+
+ * "git branch" and friends learned to use the formatted text as
+ sorting key, not the underlying timestamp value, when the --sort
+ option is used with author or committer timestamp with a format
+ specifier (e.g., "--sort=creatordate:format:%H:%M:%S").
+
+ * The command line completion script (in contrib/) learned to
+ complete configuration variable names better.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Process to add some form of low-level unit tests has started.
+
+ * Add support for GitLab CI.
+
+ * "git for-each-ref --no-sort" still sorted the refs alphabetically
+ which paid non-trivial cost. It has been redefined to show output
+ in an unspecified order, to allow certain optimizations to take
+ advantage of.
+
+ * Simplify API implementation to delete references by eliminating
+ duplication.
+
+ * Subject approxidate() and show_date() machinery to OSS-Fuzz.
+
+ * A new helper to let us pretend that we called lstat() when we know
+ our cache_entry is up-to-date via fsmonitor.
+
+ * The optimization based on fsmonitor in the "diff --cached"
+ codepath is resurrected with the "fake-lstat" introduced earlier.
+
+ * Test balloon to use C99 "bool" type from <stdbool.h> has been
+ added.
+
+ * "git clone" has been prepared to allow cloning a repository with
+ non-default hash function into a repository that uses the reftable
+ backend.
+
+ * Streaming spans of packfile data used to be done only from a
+ single, primary, pack in a repository with multiple packfiles. It
+ has been extended to allow reuse from other packfiles, too.
+
+ * Comment updates to help developers not to attempt to modify
+ messages from plumbing commands that must stay constant.
+
+ It might make sense to reassess the plumbing needs every few years,
+ but that should be done as a separate effort.
+
+ * Move test-ctype helper to the unit-test framework.
+
+ * Instead of manually creating refs/ hierarchy on disk upon a
+ creation of a secondary worktree, which is only usable via the
+ files backend, use the refs API to populate it.
+
+ * CI for GitLab learned to drive macOS jobs.
+
+ * A few tests to "git commit -o <pathspec>" and "git commit -i
+ <pathspec>" has been added.
+
+ * Tests on ref API are moved around to prepare for reftable.
+
+ * The Makefile often had to say "-L$(path) -R$(path)" that repeats
+ the path to the same library directory for link time and runtime.
+ A Makefile template is used to reduce such repetition.
+
+ * The priority queue test has been migrated to the unit testing
+ framework.
+
+ * Setting `feature.experimental` opts the user into multi-pack reuse
+ experiment
+
+ * Squelch node.js 16 deprecation warnings from GitHub Actions CI
+ by updating actions/github-script and actions/checkout that use
+ node.js 20.
+
+ * The mechanism to report the filename in the source code, used by
+ the unit-test machinery, assumed that the compiler expanded __FILE__
+ to the path to the source given to the $(CC), but some compilers
+ give full path, breaking the output. This has been corrected.
+
+
+Fixes since v2.43
+-----------------
+
+ * The way CI testing used "prove" could lead to running the test
+ suite twice needlessly, which has been corrected.
+
+ * Update ref-related tests.
+
+ * "git format-patch --encode-email-headers" ignored the option when
+ preparing the cover letter, which has been corrected.
+
+ * Newer versions of Getopt::Long started giving warnings against our
+ (ab)use of it in "git send-email". Bump the minimum version
+ requirement for Perl to 5.8.1 (from September 2002) to allow
+ simplifying our implementation.
+
+ * Earlier we stopped relying on commit-graph that (still) records
+ information about commits that are lost from the object store,
+ which has negative performance implications. The default has been
+ flipped to disable this pessimization.
+
+ * Stale URLs have been updated to their current counterparts (or
+ archive.org) and HTTP links are replaced with working HTTPS links.
+
+ * trace2 streams used to record the URLs that potentially embed
+ authentication material, which has been corrected.
+
+ * The sample pre-commit hook that tries to catch introduction of new
+ paths that use potentially non-portable characters did not notice
+ an existing path getting renamed to such a problematic path, when
+ rename detection was enabled.
+
+ * The command line parser for the "log" family of commands was too
+ loose when parsing certain numbers, e.g., silently ignoring the
+ extra 'q' in "git log -n 1q" without complaining, which has been
+ tightened up.
+
+ * "git $cmd --end-of-options --rev -- --path" for some $cmd failed
+ to interpret "--rev" as a rev, and "--path" as a path. This was
+ fixed for many programs like "reset" and "checkout".
+
+ * "git bisect reset" has been taught to clean up state files and refs
+ even when BISECT_START file is gone.
+
+ * Some codepaths did not correctly parse configuration variables
+ specified with valueless "true", which has been corrected.
+
+ * Code clean-up for sanity checking of command line options for "git
+ show-ref".
+
+ * The code to parse the From e-mail header has been updated to avoid
+ recursion.
+
+ * "git fetch --atomic" issued an unnecessary empty error message,
+ which has been corrected.
+
+ * Command line completion script (in contrib/) learned to work better
+ with the reftable backend.
+
+ * "git status" is taught to show both the branch being bisected and
+ being rebased when both are in effect at the same time.
+
+ * "git archive --list extra garbage" silently ignored excess command
+ line parameters, which has been corrected.
+
+ * "git sparse-checkout set" added default patterns even when the
+ patterns are being fed from the standard input, which has been
+ corrected.
+
+ * "git sparse-checkout (add|set) --[no-]cone --end-of-options" did
+ not handle "--end-of-options" correctly after a recent update.
+
+ * Unlike other environment variables that took the usual
+ true/false/yes/no as well as 0/1, GIT_FLUSH only understood 0/1,
+ which has been corrected.
+
+ * Clearing in-core repository (happens during e.g., "git fetch
+ --recurse-submodules" with commit graph enabled) made in-core
+ commit object in an inconsistent state by discarding the necessary
+ data from commit-graph too early, which has been corrected.
+
+ * Update to a new feature recently added, "git show-ref --exists".
+
+ * oss-fuzz tests are built and run in CI.
+ (merge c4a9cf1df3 js/oss-fuzz-build-in-ci later to maint).
+
+ * Rename detection logic ignored the final line of a file if it is an
+ incomplete line.
+
+ * GitHub CI update.
+ (merge 0188b2c8e0 pb/ci-github-skip-logs-for-broken-tests later to maint).
+
+ * "git diff --no-rename A B" did not disable rename detection but did
+ not trigger an error from the command line parser.
+
+ * "git archive --remote=<remote>" learned to talk over the smart
+ http (aka stateless) transport.
+ (merge 176cd68634 jx/remote-archive-over-smart-http later to maint).
+
+ * Fetching via protocol v0 over Smart HTTP transport sometimes failed
+ to correctly auto-follow tags.
+ (merge fba732c462 jk/fetch-auto-tag-following-fix later to maint).
+
+ * The documentation for the --exclude-per-directory option marked it
+ as deprecated, which confused readers into thinking there may be a
+ plan to remove it in the future, which was not our intention.
+ (merge 0009542cab jc/ls-files-doc-update later to maint).
+
+ * "git diff --no-index file1 file2" segfaulted while invoking the
+ external diff driver, which has been corrected.
+
+ * Rewrite //-comments to /* comments */ in files whose comments
+ prevalently use the latter.
+
+ * Cirrus CI jobs started breaking because we specified version of
+ FreeBSD that is no longer available, which has been corrected.
+ (merge 81fffb66d3 cb/use-freebsd-13-2-at-cirrus-ci later to maint).
+
+ * A caller called index_file_exists() that takes a string expressed
+ as <ptr, length> with a wrong length, which has been corrected.
+ (merge 156e28b36d jh/sparse-index-expand-to-path-fix later to maint).
+
+ * A failed "git tag -s" did not necessarily result in an error
+ depending on the crypto backend, which has been corrected.
+
+ * "git stash" sometimes was silent even when it failed due to
+ unwritable index file, which has been corrected.
+
+ * "git show-ref --verify" did not show things like "CHERRY_PICK_HEAD",
+ which has been corrected.
+
+ * Recent conversion to allow more than 0/1 in GIT_FLUSH broke the
+ mechanism by flipping what yes/no means by mistake, which has been
+ corrected.
+
+ * The sequencer machinery does not use the ref API and instead
+ records names of certain objects it needs for its correct operation
+ in temporary files, which makes these objects susceptible to loss
+ by garbage collection. These temporary files have been added as
+ starting points for reachability analysis to fix this.
+ (merge bc7f5db896 pw/gc-during-rebase later to maint).
+
+ * "git cherry-pick" invoked during "git rebase -i" session lost
+ the authorship information, which has been corrected.
+ (merge e4301f73ff vn/rebase-with-cherry-pick-authorship later to maint).
+
+ * The code paths that call repo_read_object_file() have been
+ tightened to react to errors.
+ (merge 568459bf5e js/check-null-from-read-object-file later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 5aea3955bc rj/clarify-branch-doc-m later to maint).
+ (merge 9cce3be2df bk/bisect-doc-fix later to maint).
+ (merge 8430b438f6 vd/fsck-submodule-url-test later to maint).
+ (merge 3cb4384683 jc/t0091-with-unknown-git later to maint).
+ (merge 020456cb74 rs/receive-pack-remove-find-header later to maint).
+ (merge bc47139f4f la/trailer-cleanups later to maint).
diff --git a/Documentation/RelNotes/2.44.1.txt b/Documentation/RelNotes/2.44.1.txt
new file mode 100644
index 0000000000..b5135c3281
--- /dev/null
+++ b/Documentation/RelNotes/2.44.1.txt
@@ -0,0 +1,8 @@
+Git v2.44.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4, v2.40.2,
+v2.41.1, v2.42.2 and v2.43.4 to address the security issues
+CVE-2024-32002, CVE-2024-32004, CVE-2024-32020, CVE-2024-32021
+and CVE-2024-32465; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.44.2.txt b/Documentation/RelNotes/2.44.2.txt
new file mode 100644
index 0000000000..76700f0b73
--- /dev/null
+++ b/Documentation/RelNotes/2.44.2.txt
@@ -0,0 +1,26 @@
+Git v2.44.2 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.' This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.44.1 and were not
+direct security fixes.
+
+Jeff King (5):
+ send-email: drop FakeTerm hack
+ send-email: avoid creating more than one Term::ReadLine object
+ ci: drop mention of BREW_INSTALL_PACKAGES variable
+ ci: avoid bare "gcc" for osx-gcc job
+ ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+ hook: plug a new memory leak
+ init: use the correct path of the templates directory again
+ Revert "core.hooksPath: add some protection while cloning"
+ tests: verify that `clone -c core.hooksPath=/dev/null` works again
+ clone: drop the protections where hooks aren't run
+ Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+ Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.45.0.txt b/Documentation/RelNotes/2.45.0.txt
new file mode 100644
index 0000000000..aa0315259b
--- /dev/null
+++ b/Documentation/RelNotes/2.45.0.txt
@@ -0,0 +1,476 @@
+Git v2.45 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+UI, Workflows & Features
+
+ * Integrate the reftable code into the refs framework as a backend.
+ With "git init --ref-format=reftable", hopefully it would be a lot
+ more efficient to manage a repository with many references.
+
+ * "git checkout -p" and friends learned that "@" is a synonym
+ for "HEAD".
+
+ * Variants of vimdiff learned to honor mergetool.<variant>.layout
+ settings.
+
+ * "git reflog" learned a "list" subcommand that enumerates known reflogs.
+
+ * When a merge conflicted at a submodule, merge-ort backend used to
+ unconditionally give a lengthy message to suggest how to resolve
+ it. Now the message can be squelched as an advice message.
+
+ * "git for-each-ref" learned "--include-root-refs" option to show
+ even the stuff outside the 'refs/' hierarchy.
+
+ * "git rev-list --missing=print" has learned to optionally take
+ "--allow-missing-tips", which allows the objects at the starting
+ points to be missing.
+
+ * "git merge-tree" has learned that the three trees involved in the
+ 3-way merge only need to be trees, not necessarily commits.
+
+ * "git log --merge" learned to pay attention to CHERRY_PICK_HEAD and
+ other kinds of *_HEAD pseudorefs.
+
+ * Platform specific tweaks for OS/390 has been added to
+ config.mak.uname.
+
+ * Users with safe.bareRepository=explicit can still work from within
+ $GIT_DIR of a seconary worktree (which resides at .git/worktrees/$name/)
+ of the primary worktree without explicitly specifying the $GIT_DIR
+ environment variable or the --git-dir=<path> option.
+
+ * The output format for dates "iso-strict" has been tweaked to show
+ a time in the Zulu timezone with "Z" suffix, instead of "+00:00".
+
+ * "git diff" and friends learned two extra configuration variables,
+ diff.srcPrefix and diff.dstPrefix.
+
+ * The status.showUntrackedFiles configuration variable had a name
+ that tempts users to set a Boolean value expressed in our usual
+ "false", "off", and "0", but it only took "no". This has been
+ corrected so "true" and its synonyms are taken as "normal", while
+ "false" and its synonyms are taken as "no".
+
+ * Remove an ancient and not well maintained Hg-to-git migration
+ script from contrib/.
+
+ * Hints that suggest what to do after resolving conflicts can now be
+ squelched by disabling advice.mergeConflict.
+
+ * Allow git-cherry-pick(1) to automatically drop redundant commits via
+ a new `--empty` option, similar to the `--empty` options for
+ git-rebase(1) and git-am(1). Includes a soft deprecation of
+ `--keep-redundant-commits` as well as some related docs changes and
+ sequencer code cleanup.
+
+ * "git config" learned "--comment=<message>" option to leave a
+ comment immediately after the "variable = value" on the same line
+ in the configuration file.
+
+ * core.commentChar used to be limited to a single byte, but has been
+ updated to allow an arbitrary multi-byte sequence.
+
+ * "git add -p" and other "interactive hunk selection" UI has learned to
+ skip showing the hunk immediately after it has already been shown, and
+ an additional action to explicitly ask to reshow the current hunk.
+
+ * "git pack-refs" learned the "--auto" option, which defers the decision of
+ whether and how to pack to the ref backend. This is used by the reftable
+ backend to avoid repacking of an already-optimal ref database. The new mode
+ is triggered from "git gc --auto".
+
+ * "git add -u <pathspec>" and "git commit [-i] <pathspec>" did not
+ diagnose a pathspec element that did not match any files in certain
+ situations, unlike "git add <pathspec>" did.
+
+ * The userdiff patterns for C# has been updated.
+
+ * Git writes a "waiting for your editor" message on an incomplete
+ line after launching an editor, and then append another error
+ message on the same line if the editor errors out. It now clears
+ the "waiting for..." line before giving the error message.
+
+ * The filename used for rejected hunks "git apply --reject" creates
+ was limited to PATH_MAX, which has been lifted.
+
+ * When "git bisect" reports the commit it determined to be the
+ culprit, we used to show it in a format that does not honor common
+ UI tweaks, like log.date and log.decorate. The code has been
+ taught to use "git show" to follow more customizations.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The code to iterate over refs with the reftable backend has seen
+ some optimization.
+
+ * More tests that are marked as "ref-files only" have been updated to
+ improve test coverage of reftable backend.
+
+ * Some parts of command line completion script (in contrib/) have
+ been micro-optimized.
+
+ * The way placeholders are to be marked-up in documentation have been
+ specified; use "_<placeholder>_" to typeset the word inside a pair
+ of <angle-brackets> emphasized.
+
+ * "git --no-lazy-fetch cmd" allows to run "cmd" while disabling lazy
+ fetching of objects from the promisor remote, which may be handy
+ for debugging.
+
+ * The implementation in "git clean" that makes "-n" and "-i" ignore
+ clean.requireForce has been simplified, together with the
+ documentation.
+
+ * Uses of xwrite() helper have been audited and updated for better
+ error checking and simpler code.
+
+ * Some trace2 events that lacked def_param have learned to show it,
+ enriching the output.
+
+ * The parse-options code that deals with abbreviated long option
+ names have been cleaned up.
+
+ * The code in reftable backend that creates new table files works
+ better with the tempfile framework to avoid leaving cruft after a
+ failure.
+
+ * The reftable code has its own custom binary search function whose
+ comparison callback has an unusual interface, which caused the
+ binary search to degenerate into a linear search, which has been
+ corrected.
+
+ * The code to iterate over reflogs in the reftable has been optimized
+ to reduce memory allocation and deallocation.
+
+ * Work to support a repository that work with both SHA-1 and SHA-256
+ hash algorithms has started.
+
+ * A new fuzz target that exercises config parsing code has been
+ added.
+
+ * Fix the way recently added tests interpolate variables defined
+ outside them, and document the best practice to help future
+ developers.
+
+ * Introduce an experimental protocol for contributors to propose the
+ topic description to be used in the "What's cooking" report, the
+ merge commit message for the topic, and in the release notes and
+ document it in the SubmittingPatches document.
+
+ * The t/README file now gives a hint on running individual tests in
+ the "t/" directory with "make t<num>-*.sh t<num>-*.sh".
+ (merge 8d383806fc pb/test-scripts-are-build-targets later to maint).
+
+ * The "hint:" messages given by the advice mechanism, when given a
+ message with a blank line, left a line with trailing whitespace,
+ which has been cleansed.
+
+ * Documentation rules has been explicitly described how to mark-up
+ literal parts and a few manual pages have been updated as examples.
+
+ * The .editorconfig file has been taught that a Makefile uses HT
+ indentation.
+
+ * t-prio-queue test has been cleaned up by using C99 compound
+ literals; this is meant to also serve as a weather-balloon to smoke
+ out folks with compilers who have trouble compiling code that uses
+ the feature.
+
+ * Windows binary used to decide the use of unix-domain socket at
+ build time, but it learned to make the decision at runtime instead.
+
+ * The "shared repository" test in the t0610 reftable test failed
+ under restrictive umask setting (e.g. 007), which has been
+ corrected.
+
+ * Document and apply workaround for a buggy version of dash that
+ mishandles "local var=val" construct.
+
+ * The codepaths that reach date_mode_from_type() have been updated to
+ pass "struct date_mode" by value to make them thread safe.
+
+ * The strategy to compact multiple tables of reftables after many
+ operations accumulate many entries has been improved to avoid
+ accumulating too many tables uncollected.
+
+ * The code to iterate over reftable blocks has seen some optimization
+ to reduce memory allocation and deallocation.
+
+ * The way "git fast-import" handles paths described in its input has
+ been tightened up and more clearly documented.
+
+ * The cvsimport tests required that the platform understands
+ traditional timezone notations like CST6CDT, which has been
+ updated to work on those systems as long as they understand
+ POSIX notation with explicit tz transition dates.
+
+ * The code to format trailers have been cleaned up.
+
+
+Fixes since v2.44
+-----------------
+
+ * "git apply" on a filesystem without filemode support have learned
+ to take a hint from what is in the index for the path, even when
+ not working with the "--index" or "--cached" option, when checking
+ the executable bit match what is required by the preimage in the
+ patch.
+ (merge 45b625142d cp/apply-core-filemode later to maint).
+
+ * "git column" has been taught to reject negative padding value, as
+ it would lead to nonsense behaviour including division by zero.
+ (merge 76fb807faa kh/column-reject-negative-padding later to maint).
+
+ * "git am --help" now tells readers what actions are available in
+ "git am --whitespace=<action>", in addition to saying that the
+ option is passed through to the underlying "git apply".
+ (merge a171dac734 jc/am-whitespace-doc later to maint).
+
+ * "git tag --column" failed to check the exit status of its "git
+ column" invocation, which has been corrected.
+ (merge 92e66478fc rj/tag-column-fix later to maint).
+
+ * Credential helper based on libsecret (in contrib/) has been updated
+ to handle an empty password correctly.
+ (merge 8f1f2023b7 mh/libsecret-empty-password-fix later to maint).
+
+ * "git difftool --dir-diff" learned to honor the "--trust-exit-code"
+ option; it used to always exit with 0 and signalled success.
+ (merge eb84c8b6ce ps/difftool-dir-diff-exit-code later to maint).
+
+ * The code incorrectly attempted to use textconv cache when asked,
+ even when we are not running in a repository, which has been
+ corrected.
+ (merge affe355fe7 jk/textconv-cache-outside-repo-fix later to maint).
+
+ * Remove an empty file that shouldn't have been added in the first
+ place.
+ (merge 4f66942215 js/remove-cruft-files later to maint).
+
+ * The logic to access reflog entries by date and number had ugly
+ corner cases at the boundaries, which have been cleaned up.
+ (merge 5edd126720 jk/reflog-special-cases-fix later to maint).
+
+ * An error message from "git upload-pack", which responds to "git
+ fetch" requests, had a trailing NUL in it, which has been
+ corrected.
+ (merge 3f4c7a0805 sg/upload-pack-error-message-fix later to maint).
+
+ * Clarify wording in the CodingGuidelines that requires <git-compat-util.h>
+ to be the first header file.
+ (merge 4e89f0e07c jc/doc-compat-util later to maint).
+
+ * "git commit -v --cleanup=scissors" used to add the scissors line
+ twice in the log message buffer, which has been corrected.
+ (merge e90cc075cc jt/commit-redundant-scissors-fix later to maint).
+
+ * A custom remote helper no longer cannot access the newly created
+ repository during "git clone", which is a regression in Git 2.44.
+ This has been corrected.
+ (merge 199f44cb2e ps/remote-helper-repo-initialization-fix later to maint).
+
+ * Various parts of upload-pack have been updated to bound the resource
+ consumption relative to the size of the repository to protect from
+ abusive clients.
+ (merge 6cd05e768b jk/upload-pack-bounded-resources later to maint).
+
+ * The upload-pack program, when talking over v2, accepted the
+ packfile-uris protocol extension from the client, even if it did
+ not advertise the capability, which has been corrected.
+ (merge a922bfa3b5 jk/upload-pack-v2-capability-cleanup later to maint).
+
+ * Make sure failure return from merge_bases_many() is properly caught.
+ (merge 25fd20eb44 js/merge-base-with-missing-commit later to maint).
+
+ * FSMonitor client code was confused when FSEvents were given in a
+ different case on a case-insensitive filesystem, which has been
+ corrected.
+ (merge 29c139ce78 jh/fsmonitor-icase-corner-case-fix later to maint).
+
+ * The "core.commentChar" configuration variable only allows an ASCII
+ character, which was not clearly documented, which has been
+ corrected.
+ (merge fb7c556f58 kh/doc-commentchar-is-a-byte later to maint).
+
+ * With release 2.44 we got rid of all uses of test_i18ngrep and there
+ is no in-flight topic that adds a new use of it. Make a call to
+ test_i18ngrep a hard failure, so that we can remove it at the end
+ of this release cycle.
+ (merge 381a83dfa3 jc/test-i18ngrep later to maint).
+
+ * The command line completion script (in contrib/) learned to
+ complete "git reflog" better.
+ (merge 1284f9cc11 rj/complete-reflog later to maint).
+
+ * The logic to complete the command line arguments to "git worktree"
+ subcommand (in contrib/) has been updated to correctly honor things
+ like "git -C dir" etc.
+ (merge 3574816d98 rj/complete-worktree-paths-fix later to maint).
+
+ * When git refuses to create a branch because the proposed branch
+ name is not a valid refname, an advice message is given to refer
+ the user to exact naming rules.
+ (merge 8fbd903e58 kh/branch-ref-syntax-advice later to maint).
+
+ * Code simplification by getting rid of code that sets an environment
+ variable that is no longer used.
+ (merge 72a8d3f027 pw/rebase-i-ignore-cherry-pick-help-environment later to maint).
+
+ * The code to find the effective end of log messages can fall into an
+ endless loop, which has been corrected.
+ (merge 2541cba2d6 fs/find-end-of-log-message-fix later to maint).
+
+ * Mark-up used in the documentation has been improved for
+ consistency.
+ (merge 45d5ed3e50 ja/doc-markup-fixes later to maint).
+
+ * The status.showUntrackedFiles configuration variable was
+ incorrectly documented to accept "false", which has been corrected.
+
+ * Leaks from "git restore" have been plugged.
+ (merge 2f64da0790 rj/restore-plug-leaks later to maint).
+
+ * "git bugreport --no-suffix" was not supported and instead
+ segfaulted, which has been corrected.
+ (merge b3b57c69da js/bugreport-no-suffix-fix later to maint).
+
+ * The documentation for "%(trailers[:options])" placeholder in the
+ "--pretty" option of commands in the "git log" family has been
+ updated.
+ (merge bff85a338c bl/doc-key-val-sep-fix later to maint).
+
+ * "git checkout --conflict=bad" reported a bad conflictStyle as if it
+ were given to a configuration variable; it has been corrected to
+ report that the command line option is bad.
+ (merge 5a99c1ac1a pw/checkout-conflict-errorfix later to maint).
+
+ * Code clean-up in the "git log" machinery that implements custom log
+ message formatting.
+ (merge 1c10b8e5b0 jk/pretty-subject-cleanup later to maint).
+
+ * "git config" corrupted literal HT characters written in the
+ configuration file as part of a value, which has been corrected.
+ (merge e6895c3f97 ds/config-internal-whitespace-fix later to maint).
+
+ * A unit test for reftable code tried to enumerate all files in a
+ directory after reftable operations and expected to see nothing but
+ the files it wanted to leave there, but was fooled by .nfs* cruft
+ files left, which has been corrected.
+ (merge 0068aa7946 ps/reftable-unit-test-nfs-workaround later to maint).
+
+ * The implementation and documentation of "object-format" option
+ exchange between the Git itself and its remote helpers did not
+ quite match, which has been corrected.
+
+ * The "--pretty=<shortHand>" option of the commands in the "git log"
+ family, defined as "[pretty] shortHand = <expansion>" should have
+ been looked up case insensitively, but was not, which has been
+ corrected.
+ (merge f999d5188b bl/pretty-shorthand-config-fix later to maint).
+
+ * "git apply" failed to extract the filename the patch applied to,
+ when the change was about an empty file created in or deleted from
+ a directory whose name ends with a SP, which has been corrected.
+ (merge 776ffd1a30 jc/apply-parse-diff-git-header-names-fix later to maint).
+
+ * Update a more recent tutorial doc.
+ (merge 95ab557b4b dg/myfirstobjectwalk-updates later to maint).
+
+ * The test script had an incomplete and ineffective attempt to avoid
+ clobbering the testing user's real crontab (and its equivalents),
+ which has been completed.
+ (merge 73cb87773b es/test-cron-safety later to maint).
+
+ * Use advice_if_enabled() API to rewrite a simple pattern to
+ call advise() after checking advice_enabled().
+ (merge 6412d01527 rj/use-adv-if-enabled later to maint).
+
+ * Another "set -u" fix for the bash prompt (in contrib/) script.
+ (merge d7805bc743 vs/complete-with-set-u-fix later to maint).
+
+ * "git checkout/switch --detach foo", after switching to the detached
+ HEAD state, gave the tracking information for the 'foo' branch,
+ which was pointless.
+
+ * "git apply" has been updated to lift the hardcoded pathname length
+ limit, which in turn allowed a mksnpath() function that is no
+ longer used.
+ (merge 708f7e0590 rs/apply-lift-path-length-limit later to maint).
+
+ * A file descriptor leak in an error codepath, used when "git apply
+ --reject" fails to create the *.rej file, has been corrected.
+ (merge 2b1f456adf rs/apply-reject-fd-leakfix later to maint).
+
+ * A config parser callback function fell through instead of returning
+ after recognising and processing a variable, wasting cycles, which
+ has been corrected.
+ (merge a816ccd642 ds/fetch-config-parse-microfix later to maint).
+
+ * Fix was added to work around a regression in libcURL 8.7.0 (which has
+ already been fixed in their tip of the tree).
+ (merge 92a209bf24 jk/libcurl-8.7-regression-workaround later to maint).
+
+ * The variable that holds the value read from the core.excludefile
+ configuration variable used to leak, which has been corrected.
+ (merge 0e0fefb29f jc/unleak-core-excludesfile later to maint).
+
+ * vreportf(), which is used by error() and friends, has been taught
+ to give the error message printf-format string when its vsnprintf()
+ call fails, instead of showing nothing useful to identify the
+ nature of the error.
+ (merge c63adab961 rs/usage-fallback-to-show-message-format later to maint).
+
+ * Adjust to an upcoming changes to GNU make that breaks our Makefiles.
+ (merge 227b8fd902 tb/make-indent-conditional-with-non-spaces later to maint).
+
+ * Git 2.44 introduced a regression that makes the updated code to
+ barf in repositories with multi-pack index written by older
+ versions of Git, which has been corrected.
+
+ * When .git/rr-cache/ rerere database gets corrupted or rerere is fed to
+ work on a file with conflicted hunks resolved incompletely, the rerere
+ machinery got confused and segfaulted, which has been corrected.
+ (merge 167395bb47 mr/rerere-crash-fix later to maint).
+
+ * The "receive-pack" program (which responds to "git push") was not
+ converted to run "git maintenance --auto" when other codepaths that
+ used to run "git gc --auto" were updated, which has been corrected.
+ (merge 7bf3057d9c ps/run-auto-maintenance-in-receive-pack later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge f0e578c69c rs/use-xstrncmpz later to maint).
+ (merge 83e6eb7d7a ba/credential-test-clean-fix later to maint).
+ (merge 64562d784d jb/doc-interactive-singlekey-do-not-need-perl later to maint).
+ (merge c431a235e2 cp/t9146-use-test-path-helpers later to maint).
+ (merge 82d75402d5 ds/doc-send-email-capitalization later to maint).
+ (merge 41bff66e35 jc/doc-add-placeholder-fix later to maint).
+ (merge 6835f0efe9 jw/remote-doc-typofix later to maint).
+ (merge 244001aa20 hs/rebase-not-in-progress later to maint).
+ (merge 2ca6c07db2 jc/no-include-of-compat-util-from-headers later to maint).
+ (merge 87bd7fbb9c rs/fetch-simplify-with-starts-with later to maint).
+ (merge f39addd0d9 rs/name-rev-with-mempool later to maint).
+ (merge 9a97b43e03 rs/submodule-prefix-simplify later to maint).
+ (merge 40b8076462 ak/rebase-autosquash later to maint).
+ (merge 3223204456 eg/add-uflags later to maint).
+ (merge 5f78d52dce es/config-doc-sort-sections later to maint).
+ (merge 781fb7b4c2 as/option-names-in-messages later to maint).
+ (merge 51d41dc243 jk/doc-remote-helpers-markup-fix later to maint).
+ (merge e1aaf309db pb/ci-win-artifact-names-fix later to maint).
+ (merge ad538c61da jc/index-pack-fsck-levels later to maint).
+ (merge 67471bc704 ja/doc-formatting-fix later to maint).
+ (merge 86f9ce7dd6 bl/doc-config-fixes later to maint).
+ (merge 0d527842b7 az/grep-group-error-message-update later to maint).
+ (merge 7c43bdf07b rs/strbuf-expand-bad-format later to maint).
+ (merge 8b68b48d5c ds/typofix-core-config-doc later to maint).
+ (merge 39bb692152 rs/imap-send-use-xsnprintf later to maint).
+ (merge 8d320cec60 jc/t2104-style-fixes later to maint).
+ (merge b4454d5a7b pw/t3428-cleanup later to maint).
+ (merge 84a7c33a4b pf/commitish-committish later to maint).
+ (merge 8882ee9d68 la/mailmap-entry later to maint).
+ (merge 44bdba2fa6 rs/no-openssl-compilation-fix-on-macos later to maint).
+ (merge f412d72c19 yb/replay-doc-linkfix later to maint).
+ (merge 5da40be8d7 xx/rfc2822-date-format-in-doc later to maint).
diff --git a/Documentation/RelNotes/2.45.1.txt b/Documentation/RelNotes/2.45.1.txt
new file mode 100644
index 0000000000..3b0d60cfa3
--- /dev/null
+++ b/Documentation/RelNotes/2.45.1.txt
@@ -0,0 +1,8 @@
+Git v2.45.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4,
+v2.40.2, v2.41.1, v2.42.2, v2.43.4 and v2.44.1 to address the
+security issues CVE-2024-32002, CVE-2024-32004, CVE-2024-32020,
+CVE-2024-32021 and CVE-2024-32465; see the release notes for
+these versions for details.
diff --git a/Documentation/RelNotes/2.45.2.txt b/Documentation/RelNotes/2.45.2.txt
new file mode 100644
index 0000000000..13429e6491
--- /dev/null
+++ b/Documentation/RelNotes/2.45.2.txt
@@ -0,0 +1,26 @@
+Git v2.45.2 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.' This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.45.1 and were not
+direct security fixes.
+
+Jeff King (5):
+ send-email: drop FakeTerm hack
+ send-email: avoid creating more than one Term::ReadLine object
+ ci: drop mention of BREW_INSTALL_PACKAGES variable
+ ci: avoid bare "gcc" for osx-gcc job
+ ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+ hook: plug a new memory leak
+ init: use the correct path of the templates directory again
+ Revert "core.hooksPath: add some protection while cloning"
+ tests: verify that `clone -c core.hooksPath=/dev/null` works again
+ clone: drop the protections where hooks aren't run
+ Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+ Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.45.3.txt b/Documentation/RelNotes/2.45.3.txt
new file mode 100644
index 0000000000..2a1e9aa608
--- /dev/null
+++ b/Documentation/RelNotes/2.45.3.txt
@@ -0,0 +1,107 @@
+Git v2.45.3 Release Notes
+=========================
+
+This primarily is to backport various small fixes accumulated on the
+'master' front during the development towards Git 2.46, the next
+feature release.
+
+
+Fixes since v2.45.2
+-------------------
+
+ * Git-GUI has a new maintainer, Johannes Sixt.
+
+ * Tests that try to corrupt in-repository files in chunked format did
+ not work well on macOS due to its broken "mv", which has been
+ worked around.
+
+ * The maximum size of attribute files is enforced more consistently.
+
+ * Unbreak CI jobs so that we do not attempt to use Python 2 that has
+ been removed from the platform.
+
+ * Git 2.43 started using the tree of HEAD as the source of attributes
+ in a bare repository, which has severe performance implications.
+ For now, revert the change, without ripping out a more explicit
+ support for the attr.tree configuration variable.
+
+ * Windows CI running in GitHub Actions started complaining about the
+ order of arguments given to calloc(); the imported regex code uses
+ the wrong order almost consistently, which has been corrected.
+
+ * The SubmittingPatches document now refers folks to manpages
+ translation project.
+
+ * "git rebase --signoff" used to forget that it needs to add a
+ sign-off to the resulting commit when told to continue after a
+ conflict stops its operation.
+
+ * The procedure to build multi-pack-index got confused by the
+ replace-refs mechanism, which has been corrected by disabling the
+ latter.
+
+ * "git stash -S" did not handle binary files correctly, which has
+ been corrected.
+
+ * A scheduled "git maintenance" job is expected to work on all
+ repositories it knows about, but it stopped at the first one that
+ errored out. Now it keeps going.
+
+ * zsh can pretend to be a normal shell pretty well except for some
+ glitches that we tickle in some of our scripts. Work them around
+ so that "vimdiff" and our test suite works well enough with it.
+
+ * Command line completion support for zsh (in contrib/) has been
+ updated to stop exposing internal state to end-user shell
+ interaction.
+
+ * The documentation for "git diff --name-only" has been clarified
+ that it is about showing the names in the post-image tree.
+
+ * The chainlint script (invoked during "make test") did nothing when
+ it failed to detect the number of available CPUs. It now falls
+ back to 1 CPU to avoid the problem.
+
+ * "git init" in an already created directory, when the user
+ configuration has includeif.onbranch, started to fail recently,
+ which has been corrected.
+
+ * The safe.directory configuration knob has been updated to
+ optionally allow leading path matches.
+
+ * An overly large ".gitignore" files are now rejected silently.
+
+ * Fix for an embarrassing typo that prevented Python2 tests from running
+ anywhere.
+
+ * Varargs functions that are unannotated as printf-like or execl-like
+ have been annotated as such.
+
+ * The "-k" and "--rfc" options of "format-patch" will now error out
+ when used together, as one tells us not to add anything to the
+ title of the commit, and the other one tells us to add "RFC" in
+ addition to "PATCH".
+
+ * When the user adds to "git rebase -i" instruction to "pick" a merge
+ commit, the error experience is not pleasant. Such an error is now
+ caught earlier in the process that parses the todo list.
+
+ * We forgot to normalize the result of getcwd() to NFC on macOS where
+ all other paths are normalized, which has been corrected. This still
+ does not address the case where core.precomposeUnicode configuration
+ is not defined globally.
+
+ * Earlier we stopped using the tree of HEAD as the default source of
+ attributes in a bare repository, but failed to document it. This
+ has been corrected.
+
+ * An unused extern declaration for mingw has been removed to prevent
+ it from causing build failure.
+
+ * A helper function shared between two tests had a copy-paste bug,
+ which has been corrected.
+
+ * "git fetch-pack -k -k" without passing "--lock-pack" (which we
+ never do ourselves) did not work at all, which has been corrected.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.46.0.txt b/Documentation/RelNotes/2.46.0.txt
new file mode 100644
index 0000000000..c06a04a91b
--- /dev/null
+++ b/Documentation/RelNotes/2.46.0.txt
@@ -0,0 +1,461 @@
+Git v2.46 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * The "--rfc" option of "git format-patch" learned to take an
+ optional string value to be used in place of "RFC" to tweak the
+ "[PATCH]" on the subject header.
+
+ * The credential helper protocol, together with the HTTP layer, have
+ been enhanced to support authentication schemes different from
+ username & password pair, like Bearer and NTLM.
+
+ * Command line completion script (in contrib/) learned to complete
+ "git symbolic-ref" a bit better (you need to enable plumbing
+ commands to be completed with GIT_COMPLETION_SHOW_ALL_COMMANDS).
+
+ * When the user responds to a prompt given by "git add -p" with an
+ unsupported command, list of available commands were given, which
+ was too much if the user knew what they wanted to type but merely
+ made a typo. Now the user gets a much shorter error message.
+
+ * The color parsing code learned to handle 12-bit RGB colors, spelled
+ as "#RGB" (in addition to "#RRGGBB" that is already supported).
+
+ * The operation mode options (like "--get") the "git config" command
+ uses have been deprecated and replaced with subcommands (like "git
+ config get").
+
+ * "git tag" learned the "--trailer" option to futz with the trailers
+ in the same way as "git commit" does.
+
+ * A new global "--no-advice" option can be used to disable all advice
+ messages, which is meant to be used only in scripts.
+
+ * Updates to symbolic refs can now be made as a part of ref
+ transaction.
+
+ * The trailer API has been reshuffled a bit.
+
+ * Terminology to call various ref-like things are getting
+ straightened out.
+
+ * The command line completion script (in contrib/) has been adjusted
+ to the recent update to "git config" that adopted subcommand based
+ UI.
+
+ * The knobs to tweak how reftable files are written have been made
+ available as configuration variables.
+
+ * When "git push" notices that the commit at the tip of the ref on
+ the other side it is about to overwrite does not exist locally, it
+ used to first try fetching it if the local repository is a partial
+ clone. The command has been taught not to do so and immediately
+ fail instead.
+
+ * The promisor.quiet configuration knob can be set to true to make
+ lazy fetching from promisor remotes silent.
+
+ * The inter/range-diff output has been moved to the end of the patch
+ when format-patch adds it to a single patch, instead of writing it
+ before the patch text, to be consistent with what is done for a
+ cover letter for a multi-patch series.
+
+ * A new command has been added to migrate a repository that uses the
+ files backend for its ref storage to use the reftable backend, with
+ limitations.
+
+ * "git diff --exit-code --ext-diff" learned to take the exit status
+ of the external diff driver into account when deciding the exit
+ status of the overall "git diff" invocation when configured to do
+ so.
+
+ * "git update-ref --stdin" learned to handle transactional updates of
+ symbolic-refs.
+
+ * "git format-patch --interdiff" for multi-patch series learned to
+ turn on cover letters automatically (unless told never to enable
+ cover letter with "--no-cover-letter" and such).
+
+ * The "--heads" option of "ls-remote" and "show-ref" has been
+ deprecated; "--branches" replaces "--heads".
+
+ * For over a year, setting add.interactive.useBuiltin configuration
+ variable did nothing but giving a "this does not do anything"
+ warning. The warning has been removed.
+
+ * The http transport can now be told to send request with
+ authentication material without first getting a 401 response.
+
+ * A handful of entries are added to the GitFAQ document.
+
+ * "git var GIT_SHELL_PATH" should report the path to the shell used
+ to spawn external commands, but it didn't do so on Windows, which
+ has been corrected.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Advertise "git contacts", a tool for newcomers to find people to
+ ask review for their patches, a bit more in our developer
+ documentation.
+
+ * In addition to building the objects needed, try to link the objects
+ that are used in fuzzer tests, to make sure at least they build
+ without bitrot, in Linux CI runs.
+
+ * Code to write out reftable has seen some optimization and
+ simplification.
+
+ * Tests to ensure interoperability between reftable written by jgit
+ and our code have been added and enabled in CI.
+
+ * The singleton index_state instance "the_index" has been eliminated
+ by always instantiating "the_repository" and replacing references
+ to "the_index" with references to its .index member.
+
+ * Git-GUI has a new maintainer, Johannes Sixt.
+
+ * The "test-tool" has been taught to run testsuite tests in parallel,
+ bypassing the need to use the "prove" tool.
+
+ * The "whitespace check" task that was enabled for GitHub Actions CI
+ has been ported to GitLab CI.
+
+ * The refs API lost functions that implicitly assumes to work on the
+ primary ref_store by forcing the callers to pass a ref_store as an
+ argument.
+
+ * Code clean-up to reduce inter-function communication inside
+ builtin/config.c done via the use of global variables.
+
+ * The pack bitmap code saw some clean-up to prepare for a follow-up topic.
+
+ * Preliminary code clean-up for "git send-email".
+
+ * The default "creation-factor" used by "git format-patch" has been
+ raised to make it more aggressively find matching commits.
+
+ * Before discovering the repository details, We used to assume SHA-1
+ as the "default" hash function, which has been corrected. Hopefully
+ this will smoke out codepaths that rely on such an unwarranted
+ assumptions.
+
+ * The project decision making policy has been documented.
+
+ * The strcmp-offset tests have been rewritten using the unit test
+ framework.
+
+ * "git add -p" learned to complain when an answer with more than one
+ letter is given to a prompt that expects a single letter answer.
+
+ * The alias-expanded command lines are logged to the trace output.
+
+ * A new test was added to ensure git commands that are designed to
+ run outside repositories do work.
+
+ * A few tests in reftable library have been rewritten using the
+ unit test framework.
+
+ * A pair of test helpers that essentially are unit tests on hash
+ algorithms have been rewritten using the unit-tests framework.
+
+ * A test helper that essentially is unit tests on the "decorate"
+ logic has been rewritten using the unit-tests framework.
+
+ * Many memory leaks in the sparse-checkout code paths have been
+ plugged.
+
+ * "make check-docs" noticed problems and reported to its output but
+ failed to signal its findings with its exit status, which has been
+ corrected.
+
+ * Building with "-Werror -Wwrite-strings" is now supported.
+
+ * To help developers, the build procedure now allows builders to use
+ CFLAGS_APPEND to specify additional CFLAGS.
+
+ * "oidtree" tests were rewritten to use the unit test framework.
+
+ * The structure of the document that records longer-term project
+ decisions to deprecate/remove/update various behaviour has been
+ outlined.
+
+ * The pseudo-merge reachability bitmap to help more efficient storage
+ of the reachability bitmap in a repository with too many refs has
+ been added.
+
+ * When "git merge" sees that the index cannot be refreshed (e.g. due
+ to another process doing the same in the background), it died but
+ after writing MERGE_HEAD etc. files, which was useless for the
+ purpose to recover from the failure.
+
+ * The output from "git cat-file --batch-check" and "--batch-command
+ (info)" should not be unbuffered, for which some tests have been
+ added.
+
+ * A CPP macro USE_THE_REPOSITORY_VARIABLE is introduced to help
+ transition the codebase to rely less on the availability of the
+ singleton the_repository instance.
+
+ * "git version --build-options" reports the version information of
+ OpenSSL and other libraries (if used) in the build.
+
+ * Memory ownership rules for the in-core representation of
+ remote.*.url configuration values have been straightened out, which
+ resulted in a few leak fixes and code clarification.
+
+ * When bundleURI interface fetches multiple bundles, Git failed to
+ take full advantage of all bundles and ended up slurping duplicated
+ objects, which has been corrected.
+
+ * The code to deal with modified paths that are out-of-cone in a
+ sparsely checked out working tree has been optimized.
+
+ * An existing test of oidmap API has been rewritten with the
+ unit-test framework.
+
+ * The "ort" merge backend saw one bugfix for a crash that happens
+ when inner merge gets killed, and assorted code clean-ups.
+
+ * A new warning message is issued when a command has to expand a
+ sparse index to handle working tree cruft that are outside of the
+ sparse checkout.
+
+ * The test framework learned to take the test body not as a single
+ string but as a here-document.
+
+ * "git push '' HEAD:there" used to hit a BUG(); it has been corrected
+ to die with "fatal: bad repository ''".
+
+ * What happens when http.cookieFile gets the special value "" has
+ been clarified in the documentation.
+
+
+Fixes since v2.45
+-----------------
+
+ * "git rebase --signoff" used to forget that it needs to add a
+ sign-off to the resulting commit when told to continue after a
+ conflict stops its operation.
+
+ * The procedure to build multi-pack-index got confused by the
+ replace-refs mechanism, which has been corrected by disabling the
+ latter.
+
+ * The "-k" and "--rfc" options of "format-patch" will now error out
+ when used together, as one tells us not to add anything to the
+ title of the commit, and the other one tells us to add "RFC" in
+ addition to "PATCH".
+
+ * "git stash -S" did not handle binary files correctly, which has
+ been corrected.
+
+ * A scheduled "git maintenance" job is expected to work on all
+ repositories it knows about, but it stopped at the first one that
+ errored out. Now it keeps going.
+
+ * zsh can pretend to be a normal shell pretty well except for some
+ glitches that we tickle in some of our scripts. Work them around
+ so that "vimdiff" and our test suite works well enough with it.
+
+ * Command line completion support for zsh (in contrib/) has been
+ updated to stop exposing internal state to end-user shell
+ interaction.
+
+ * Tests that try to corrupt in-repository files in chunked format did
+ not work well on macOS due to its broken "mv", which has been
+ worked around.
+
+ * The maximum size of attribute files is enforced more consistently.
+
+ * Unbreak CI jobs so that we do not attempt to use Python 2 that has
+ been removed from the platform.
+
+ * Git 2.43 started using the tree of HEAD as the source of attributes
+ in a bare repository, which has severe performance implications.
+ For now, revert the change, without ripping out a more explicit
+ support for the attr.tree configuration variable.
+
+ * The "--exit-code" option of "git diff" command learned to work with
+ the "--ext-diff" option.
+
+ * Windows CI running in GitHub Actions started complaining about the
+ order of arguments given to calloc(); the imported regex code uses
+ the wrong order almost consistently, which has been corrected.
+
+ * Expose "name conflict" error when a ref creation fails due to D/F
+ conflict in the ref namespace, to improve an error message given by
+ "git fetch".
+ (merge 9339fca23e it/refs-name-conflict later to maint).
+
+ * The SubmittingPatches document now refers folks to manpages
+ translation project.
+
+ * The documentation for "git diff --name-only" has been clarified
+ that it is about showing the names in the post-image tree.
+
+ * The credential helper that talks with osx keychain learned to avoid
+ storing back the authentication material it just got received from
+ the keychain.
+ (merge e1ab45b2da kn/osxkeychain-skip-idempotent-store later to maint).
+
+ * The chainlint script (invoked during "make test") did nothing when
+ it failed to detect the number of available CPUs. It now falls
+ back to 1 CPU to avoid the problem.
+
+ * Revert overly aggressive "layered defence" that went into 2.45.1
+ and friends, which broke "git-lfs", "git-annex", and other use
+ cases, so that we can rebuild necessary counterparts in the open.
+
+ * "git init" in an already created directory, when the user
+ configuration has includeif.onbranch, started to fail recently,
+ which has been corrected.
+
+ * Memory leaks in "git mv" has been plugged.
+
+ * The safe.directory configuration knob has been updated to
+ optionally allow leading path matches.
+
+ * An overly large ".gitignore" files are now rejected silently.
+
+ * Upon expiration event, the credential subsystem forgot to clear
+ in-core authentication material other than password (whose support
+ was added recently), which has been corrected.
+
+ * Fix for an embarrassing typo that prevented Python2 tests from running
+ anywhere.
+
+ * Varargs functions that are unannotated as printf-like or execl-like
+ have been annotated as such.
+
+ * "git am" has a safety feature to prevent it from starting a new
+ session when there already is a session going. It reliably
+ triggers when a mbox is given on the command line, but it has to
+ rely on the tty-ness of the standard input. Add an explicit way to
+ opt out of this safety with a command line option.
+ (merge 62c71ace44 jk/am-retry later to maint).
+
+ * A leak in "git imap-send" that somehow escapes LSan has been
+ plugged.
+
+ * Setting core.abbrev too early before the repository set-up
+ (typically in "git clone") caused segfault, which as been
+ corrected.
+
+ * When the user adds to "git rebase -i" instruction to "pick" a merge
+ commit, the error experience is not pleasant. Such an error is now
+ caught earlier in the process that parses the todo list.
+
+ * We forgot to normalize the result of getcwd() to NFC on macOS where
+ all other paths are normalized, which has been corrected. This still
+ does not address the case where core.precomposeUnicode configuration
+ is not defined globally.
+
+ * Earlier we stopped using the tree of HEAD as the default source of
+ attributes in a bare repository, but failed to document it. This
+ has been corrected.
+
+ * "git update-server-info" and "git commit-graph --write" have been
+ updated to use the tempfile API to avoid leaving cruft after
+ failing.
+
+ * An unused extern declaration for mingw has been removed to prevent
+ it from causing build failure.
+
+ * A helper function shared between two tests had a copy-paste bug,
+ which has been corrected.
+
+ * "git fetch-pack -k -k" without passing "--lock-pack" (which we
+ never do ourselves) did not work at all, which has been corrected.
+
+ * CI job to build minimum fuzzers learned to pass NO_CURL=NoThanks to
+ the build procedure, as its build environment does not offer, or
+ the rest of the build needs, anything cURL.
+ (merge 4e66b5a990 jc/fuzz-sans-curl later to maint).
+
+ * "git diff --no-ext-diff" when diff.external is configured ignored
+ the "--color-moved" option.
+ (merge 0f4b0d4cf0 rs/diff-color-moved-w-no-ext-diff-fix later to maint).
+
+ * "git archive --add-virtual-file=<path>:<contents>" never paid
+ attention to the --prefix=<prefix> option but the documentation
+ said it would. The documentation has been corrected.
+ (merge 72c282098d jc/archive-prefix-with-add-virtual-file later to maint).
+
+ * When GIT_PAGER failed to spawn, depending on the code path taken,
+ we failed immediately (correct) or just spew the payload to the
+ standard output (incorrect). The code now always fail immediately
+ when GIT_PAGER fails.
+ (merge 78f0a5d187 rj/pager-die-upon-exec-failure later to maint).
+
+ * date parser updates to be more careful about underflowing epoch
+ based timestamp.
+ (merge 9d69789770 db/date-underflow-fix later to maint).
+
+ * The Bloom filter used for path limited history traversal was broken
+ on systems whose "char" is unsigned; update the implementation and
+ bump the format version to 2.
+ (merge 9c8a9ec787 tb/path-filter-fix later to maint).
+
+ * Typofix.
+ (merge 231cf7370e as/pathspec-h-typofix later to maint).
+
+ * Code clean-up.
+ (merge 4b837f821e rs/simplify-submodule-helper-super-prefix-invocation later to maint).
+
+ * "git describe --dirty --broken" forgot to refresh the index before
+ seeing if there is any chang, ("git describe --dirty" correctly did
+ so), which has been corrected.
+ (merge b8ae42e292 as/describe-broken-refresh-index-fix later to maint).
+
+ * Test suite has been taught not to unnecessarily rely on DNS failing
+ a bogus external name.
+ (merge 407cdbd271 jk/tests-without-dns later to maint).
+
+ * GitWeb update to use committer date consistently in rss/atom feeds.
+ (merge cf6ead095b am/gitweb-feed-use-committer-date later to maint).
+
+ * Custom control structures we invented more recently have been
+ taught to the clang-format file.
+ (merge 1457dff9be rs/clang-format-updates later to maint).
+
+ * Developer build procedure fix.
+ (merge df32729866 tb/dev-build-pedantic-fix later to maint).
+
+ * "git push" that pushes only deletion gave an unnecessary and
+ harmless error message when push negotiation is configured, which
+ has been corrected.
+ (merge 4d8ee0317f jc/disable-push-nego-for-deletion later to maint).
+
+ * Address-looking strings found on the trailer are now placed on the
+ Cc: list after running through sanitize_address by "git send-email".
+ (merge c852531f45 cb/send-email-sanitize-trailer-addresses later to maint).
+
+ * Tests that use GIT_TEST_SANITIZE_LEAK_LOG feature got their exit
+ status inverted, which has been corrected.
+ (merge 8c1d6691bc rj/test-sanitize-leak-log-fix later to maint).
+
+ * The http.cookieFile and http.saveCookies configuration variables
+ have a few values that need to be avoided, which are now ignored
+ with warning messages.
+ (merge 4f5822076f jc/http-cookiefile later to maint).
+
+ * Repacking a repository with multi-pack index started making stupid
+ pack selections in Git 2.45, which has been corrected.
+ (merge 8fb6d11fad ds/midx-write-repack-fix later to maint).
+
+ * Fix documentation mark-up regression in 2.45.
+ (merge 6474da0aa4 ja/doc-markup-updates-fix later to maint).
+
+ * Work around asciidoctor's css that renders `monospace` material
+ in the SYNOPSIS section of manual pages as block elements.
+ (merge d44ce6ddd5 js/doc-markup-updates-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 493fdae046 ew/object-convert-leakfix later to maint).
+ (merge 00f3661a0a ss/doc-eol-attr-fix later to maint).
+ (merge 428c40da61 ri/doc-show-branch-fix later to maint).
+ (merge 58696bfcaa jc/where-is-bash-for-ci later to maint).
+ (merge 616e94ca24 tb/doc-max-tree-depth-fix later to maint).
diff --git a/Documentation/RelNotes/2.46.1.txt b/Documentation/RelNotes/2.46.1.txt
new file mode 100644
index 0000000000..e55c2c4a46
--- /dev/null
+++ b/Documentation/RelNotes/2.46.1.txt
@@ -0,0 +1,75 @@
+Git 2.46.1 Release Notes
+========================
+
+This release is primarily to merge fixes accumulated on the 'master'
+front to prepare for 2.47 release that are still relevant to 2.46.x
+maintenance track.
+
+Fixes since Git 2.46
+--------------------
+
+ * "git checkout --ours" (no other arguments) complained that the
+ option is incompatible with branch switching, which is technically
+ correct, but found confusing by some users. It now says that the
+ user needs to give pathspec to specify what paths to checkout.
+
+ * It has been documented that we avoid "VAR=VAL shell_func" and why.
+
+ * "git add -p" by users with diff.suppressBlankEmpty set to true
+ failed to parse the patch that represents an unmodified empty line
+ with an empty line (not a line with a single space on it), which
+ has been corrected.
+
+ * "git rebase --help" referred to "offset" (the difference between
+ the location a change was taken from and the change gets replaced)
+ incorrectly and called it "fuzz", which has been corrected.
+
+ * "git notes add -m '' --allow-empty" and friends that take prepared
+ data to create notes should not invoke an editor, but it started
+ doing so since Git 2.42, which has been corrected.
+
+ * An expensive operation to prepare tracing was done in re-encoding
+ code path even when the tracing was not requested, which has been
+ corrected.
+
+ * Perforce tests have been updated.
+
+ * The credential helper to talk to OSX keychain sometimes sent
+ garbage bytes after the username, which has been corrected.
+
+ * A recent update broke "git ls-remote" used outside a repository,
+ which has been corrected.
+
+ * "git config --value=foo --fixed-value section.key newvalue" barfed
+ when the existing value in the configuration file used the
+ valueless true syntax, which has been corrected.
+
+ * "git reflog expire" failed to honor annotated tags when computing
+ reachable commits.
+
+ * A flakey test and incorrect calls to strtoX() functions have been
+ fixed.
+
+ * Follow-up on 2.45.1 regression fix.
+
+ * "git rev-list ... | git diff-tree -p --remerge-diff --stdin" should
+ behave more or less like "git log -p --remerge-diff" but instead it
+ crashed, forgetting to prepare a temporary object store needed.
+
+ * The patch parser in "git patch-id" has been tightened to avoid
+ getting confused by lines that look like a patch header in the log
+ message.
+
+ * "git bundle unbundle" outside a repository triggered a BUG()
+ unnecessarily, which has been corrected.
+
+ * The code forgot to discard unnecessary in-core commit buffer data
+ for commits that "git log --skip=<number>" traversed but omitted
+ from the output, which has been corrected.
+
+ * "git verify-pack" and "git index-pack" started dying outside a
+ repository, which has been corrected.
+
+ * A corner case bug in "git stash" was fixed.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.46.2.txt b/Documentation/RelNotes/2.46.2.txt
new file mode 100644
index 0000000000..613386878d
--- /dev/null
+++ b/Documentation/RelNotes/2.46.2.txt
@@ -0,0 +1,23 @@
+Git 2.46.2 Release Notes
+========================
+
+This release is primarily to merge changes to unbreak the 32-bit
+GitHub actions jobs we use for CI testing, so that we can release
+real fixes for the 2.46.x track after they pass CI.
+
+It also reverts the "git patch-id" change that went into 2.46.1,
+as it seems to have got a regression reported (I haven't verified,
+but it is better to keep a known breakage than adding an unintended
+regression).
+
+Other than that, a handful of minor bugfixes are included.
+
+ * In a few corner cases "git diff --exit-code" failed to report
+ "changes" (e.g., renamed without any content change), which has
+ been corrected.
+
+ * Cygwin does have /dev/tty support that is needed by things like
+ single-key input mode.
+
+ * The interpret-trailers command failed to recognise the end of the
+ message when the commit log ends in an incomplete line.
diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt
new file mode 100644
index 0000000000..b63c3364af
--- /dev/null
+++ b/Documentation/RelNotes/2.47.0.txt
@@ -0,0 +1,342 @@
+Git v2.47 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * Many Porcelain commands that internally use the merge machinery
+ were taught to consistently honor the diff.algorithm configuration.
+
+ * A few descriptions in "git show-ref -h" have been clarified.
+
+ * A 'P' command to "git add -p" that passes the patch hunk to the
+ pager has been added.
+
+ * "git grep -W" omits blank lines that follow the found function at
+ the end of the file, just like it omits blank lines before the next
+ function.
+
+ * The value of http.proxy can have "path" at the end for a socks
+ proxy that listens to a unix-domain socket, but we started to
+ discard it when we taught proxy auth code path to use the
+ credential helpers, which has been corrected.
+
+ * The code paths to compact multiple reftable files have been updated
+ to correctly deal with multiple compaction triggering at the same
+ time.
+
+ * Support to specify ref backend for submodules has been enhanced.
+
+ * "git svn" has been taught about svn:global-ignores property
+ recent versions of Subversion has.
+
+ * The default object hash and ref backend format used to be settable
+ only with explicit command line option to "git init" and
+ environment variables, but now they can be configured in the user's
+ global and system wide configuration.
+
+ * "git send-email" learned "--translate-aliases" option that reads
+ addresses from the standard input and emits the result of applying
+ aliases on them to the standard output.
+
+ * 'git for-each-ref' learned a new "--format" atom to find the branch
+ that the history leading to a given commit "%(is-base:<commit>)" is
+ likely based on.
+
+ * The command line prompt support used to be littered with bash-isms,
+ which has been corrected to work with more shells.
+
+ * Support for the RUNTIME_PREFIX feature has been added to z/OS port.
+
+ * "git send-email" learned "--mailmap" option to allow rewriting the
+ recipient addresses.
+
+ * "git mergetool" learned to use VSCode as a merge backend.
+
+ * "git pack-redundant" has been marked for removal in Git 3.0.
+
+ * One-line messages to "die" and other helper functions will get LF
+ added by these helper functions, but many existing messages had an
+ unnecessary LF at the end, which have been corrected.
+
+ * The "scalar clone" command learned the "--no-tags" option.
+
+ * The environment GIT_ADVICE has been intentionally kept undocumented
+ to discourage its use by interactive users. Add documentation to
+ help tool writers.
+
+ * "git apply --3way" learned to take "--ours" and other options.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * A build tweak knob has been simplified by not setting the value
+ that is already the default; another unused one has been removed.
+
+ * A CI job that use clang-format to check coding style issues in new
+ code has been added.
+
+ * The reviewing guidelines document now explicitly encourages people
+ to give positive reviews and how.
+
+ * Test script linter has been updated to catch an attempt to use
+ one-shot export construct "VAR=VAL func" for shell functions (which
+ does not work for some shells) better.
+
+ * Some project conventions have been added to CodingGuidelines.
+
+ * In the refs subsystem, implicit reliance of the_repository has been
+ eliminated; the repository associated with the ref store object is
+ used instead.
+
+ * Various tests in reftable library have been rewritten using the unit test
+ framework.
+
+ * A test that fails on an unusually slow machine was found, and made
+ less likely to cause trouble by lengthening the expiry value it
+ uses.
+
+ * An existing test of hashmap API has been rewritten with the
+ unit-test framework.
+
+ * A policy document that describes platform support levels and
+ expectation on platform stakeholders has been introduced.
+
+ * The refs API has been taught to give symref target information to
+ the users of ref iterators, allowing for-each-ref and friends to
+ avoid an extra ref_resolve_* API call per a symbolic ref.
+
+ * Unit-test framework has learned a simple control structure to allow
+ embedding test statements in-line instead of having to create a new
+ function to contain them.
+
+ * Incremental updates of multi-pack index files is getting worked on.
+
+ * Use of API functions that implicitly depend on the_repository
+ object in the config subsystem has been rewritten to pass a
+ repository object through the callchain.
+
+ * Unused parameters have been either marked as UNUSED to squelch
+ -Wunused warnings or dropped from many functions..
+
+ * The code in the reftable library has been cleaned up by discarding
+ unused "generic" interface.
+
+ * The underlying machinery for "git diff-index" has long been made to
+ expand the sparse index as needed, but the command fully expanded
+ the sparse index upfront, which now has been taught not to do.
+
+ * More trace2 events at key points on push and fetch code paths have
+ been added.
+
+ * Make our codebase compilable with the -Werror=unused-parameter
+ option.
+
+ * "git cat-file" works well with the sparse-index, and gets marked as
+ such.
+
+ * CI started failing completely for linux32 jobs, as the step to
+ upload failed test directory uses GitHub actions that is deprecated
+ and is now disabled.
+
+ * Import clar unit tests framework libgit2 folks invented for our
+ use.
+
+ * The error messages from the test script checker have been improved.
+
+ * The convention to calling into built-in command implementation has
+ been updated to pass the repository, if known, together with the
+ prefix value.
+
+ * "git apply" had custom buffer management code that predated before
+ use of strbuf got widespread, which has been updated to use strbuf,
+ which also plugged some memory leaks.
+
+ * The reftable backend learned to more efficiently handle exclude
+ patterns while enumerating the refs.
+
+ * CI updates. FreeBSD image has been updated to 13.4.
+ (merge 2eeb29702e cb/ci-freebsd-13-4 later to maint).
+
+ * Give timeout to the locking code to write to reftable, instead of
+ failing on the first failure without retrying.
+
+ * The checksum at the tail of files are now computed without
+ collision detection protection. This is safe as the consumer of
+ the information to protect itself from replay attacks checks for
+ hash collisions independently.
+
+
+Fixes since v2.46
+-----------------
+
+ * "git add -p" by users with diff.suppressBlankEmpty set to true
+ failed to parse the patch that represents an unmodified empty line
+ with an empty line (not a line with a single space on it), which
+ has been corrected.
+
+ * "git checkout --ours" (no other arguments) complained that the
+ option is incompatible with branch switching, which is technically
+ correct, but found confusing by some users. It now says that the
+ user needs to give pathspec to specify what paths to checkout.
+
+ * It has been documented that we avoid "VAR=VAL shell_func" and why.
+
+ * "git rebase --help" referred to "offset" (the difference between
+ the location a change was taken from and the change gets replaced)
+ incorrectly and called it "fuzz", which has been corrected.
+
+ * "git notes add -m '' --allow-empty" and friends that take prepared
+ data to create notes should not invoke an editor, but it started
+ doing so since Git 2.42, which has been corrected.
+
+ * An expensive operation to prepare tracing was done in re-encoding
+ code path even when the tracing was not requested, which has been
+ corrected.
+
+ * More leakfixes.
+
+ * The credential helper to talk to OSX keychain sometimes sent
+ garbage bytes after the username, which has been corrected.
+
+ * A recent update broke "git ls-remote" used outside a repository,
+ which has been corrected.
+
+ * The patch parser in 'git apply' has been a bit more lenient against
+ unexpected mode bits, like 100664, recorded on extended header lines.
+
+ * "git config --value=foo --fixed-value section.key newvalue" barfed
+ when the existing value in the configuration file used the
+ valueless true syntax, which has been corrected.
+
+ * The patch parser in "git patch-id" has been tightened to avoid
+ getting confused by lines that look like a patch header in the log
+ message.
+
+ * "git reflog expire" failed to honor annotated tags when computing
+ reachable commits.
+
+ * A flakey test and incorrect calls to strtoX() functions have been
+ fixed.
+
+ * Follow-up on 2.45.1 regression fix.
+
+ * "git rev-list ... | git diff-tree -p --remerge-diff --stdin" should
+ behave more or less like "git log -p --remerge-diff" but instead it
+ crashed, forgetting to prepare a temporary object store needed.
+
+ * "git bundle unbundle" outside a repository triggered a BUG()
+ unnecessarily, which has been corrected.
+
+ * Maintenance tasks other than "gc" now properly go background when
+ "git maintenance" runs them.
+
+ * We created a useless pseudo-merge reachability bitmap that is about
+ 0 commits, and attempted to include commits that are not in packs,
+ which made no sense. These bugs have been corrected.
+ (merge a72dfab8b8 tb/pseudo-merge-bitmap-fixes later to maint).
+
+ * "git rebase -x --quiet" was not quiet, which was corrected.
+
+ * The code path for compacting reftable files saw some bugfixes
+ against concurrent operation.
+
+ * The code forgot to discard unnecessary in-core commit buffer data
+ for commits that "git log --skip=<number>" traversed but omitted
+ from the output, which has been corrected.
+
+ * "git verify-pack" and "git index-pack" started dying outside a
+ repository, which has been corrected.
+
+ * A data corruption bug when multi-pack-index is used and the same
+ objects are stored in multiple packfiles has been corrected.
+
+ * "git pack-refs --auto" for the files backend was too aggressive,
+ which has been a bit tamed.
+ (merge c3459ae9ef ps/pack-refs-auto-heuristics later to maint).
+
+ * A file descriptor left open is now properly closed when "git
+ sparse-checkout" updates the sparse patterns.
+
+ * In a few corner cases "git diff --exit-code" failed to report
+ "changes" (e.g., renamed without any content change), which has
+ been corrected.
+
+ * Cygwin does have /dev/tty support that is needed by things like
+ single-key input mode.
+
+ * The interpret-trailers command failed to recognise the end of the
+ message when the commit log ends in an incomplete line.
+
+ * "git rebase --autostash" failed to resurrect the autostashed
+ changes when the command gets aborted after giving back control
+ asking for hlep in conflict resolution.
+ (merge bf6ab087d1 pw/rebase-autostash-fix later to maint).
+
+ * The "imap-send" now allows to be compiled with NO_OPENSSL and
+ OPENSSL_SHA1 defined together.
+ (merge 997950a750 jk/no-openssl-with-openssl-sha1 later to maint).
+
+ * The support to customize build options to adjust for older versions
+ and/or older systems for the interop tests has been improved.
+ (merge 22ef5f02a8 jk/interop-test-build-options later to maint).
+
+ * Update the character width table for Unicode 16.
+ (merge 44dc651132 bb/unicode-width-table-16 later to maint).
+
+ * In Git 2.39, Git.pm stopped working in a bare repository, which has
+ been corrected.
+ (merge d3edb0bdde jk/git-pm-bare-repo-fix later to maint).
+
+ * When a remote-helper dies before Git writes to it, SIGPIPE killed
+ Git silently. We now explain the situation a bit better to the end
+ user in our error message.
+ (merge 6e7fac9bca jk/diag-unexpected-remote-helper-death later to maint).
+
+ * A few usability fixes to "git jump" (in contrib/).
+ (merge 083b82544d jk/jump-quickfix-fixes later to maint).
+
+ * "git diff --exit-code" ignored modified binary files, which has
+ been corrected.
+ (merge 9a41735af6 rs/diff-exit-code-binary later to maint).
+
+ * When a subprocess to work in a submodule spawned by "git submodule"
+ fails with SIGPIPE, the parent Git process caught the death of it,
+ but gave a generic "failed to work in that submodule", which was
+ misleading. We now behave as if the parent got SIGPIPE and die.
+ (merge 082caf527e pw/submodule-process-sigpipe later to maint).
+
+ * "git archive" with pathspec magic that uses the attribute
+ information did not work well, which has been corrected.
+ (merge 296743a7ca rs/archive-with-attr-pathspec-fix later to maint).
+
+ * Background tasks "git maintenance" runs may need to use credential
+ information when going over the network, but a credential helper
+ may work only in an interactive environment, and end up blocking a
+ scheduled task waiting for UI. Credential helpers can now behave
+ differently when they are not running interactively.
+ (merge b9183b0a02 ds/background-maintenance-with-credential later to maint).
+
+ * "git --git-dir=nowhere cmd" failed to properly notice that it
+ wasn't in any repository while processing includeIf.onbranch
+ configuration and instead crashed.
+
+ * When "git sparse-checkout disable" turns a sparse checkout into a
+ regular checkout, the index is fully expanded. This totally
+ expected behaviour however had an "oops, we are expanding the
+ index" advice message, which has been corrected.
+ (merge 537e516a39 ds/sparse-checkout-expansion-advice later to maint).
+
+ * macOS with fsmonitor daemon can hang forever when a submodule is
+ involved, which has been corrected.
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge be10ac7037 jc/mailinfo-header-cleanup later to maint).
+ (merge 4460e052e0 jc/range-diff-lazy-setup later to maint).
+ (merge 0627c58e7a ak/typofixes later to maint).
+ (merge 83799f1500 jk/t9001-deflake later to maint).
+ (merge e02cc08a88 ak/typofix-2.46-maint later to maint).
+ (merge 5c5d29e1c4 ps/ci-gitlab-upgrade later to maint).
+ (merge 9c4c840901 jc/doc-discarding-stalled-topics later to maint).
+ (merge 5e6f359f6b ds/read-cache-mempool-leakfix later to maint).
diff --git a/Documentation/RelNotes/2.47.1.txt b/Documentation/RelNotes/2.47.1.txt
new file mode 100644
index 0000000000..39206c09fd
--- /dev/null
+++ b/Documentation/RelNotes/2.47.1.txt
@@ -0,0 +1,31 @@
+Git 2.47.1 Release Notes
+========================
+
+This is to flush accumulated fixes since 2.47.0 on the 'master'
+front down to the maintenance track.
+
+
+Fixes since Git 2.47
+--------------------
+
+ * Use after free and double freeing at the end in "git log -L... -p"
+ had been identified and fixed.
+
+ * On macOS, fsmonitor can fall into a race condition that results in
+ a client waiting forever to be notified for an event that have
+ already happened. This problem has been corrected.
+
+ * "git maintenance start" crashed due to an uninitialized variable
+ reference, which has been corrected.
+
+ * Fail gracefully instead of crashing when attempting to write the
+ contents of a corrupt in-core index as a tree object.
+
+ * A "git fetch" from the superproject going down to a submodule used
+ a wrong remote when the default remote names are set differently
+ between them.
+
+ * The "gitk" project tree has been synchronized again with its new
+ maintainer, Johannes Sixt.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt
new file mode 100644
index 0000000000..a949a103b1
--- /dev/null
+++ b/Documentation/RelNotes/2.48.0.txt
@@ -0,0 +1,195 @@
+Git v2.48 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * A new configuration variable remote.<name>.serverOption makes the
+ transport layer act as if the --serverOption=<value> option is
+ given from the command line.
+
+ * "git rebase --rebase-merges" now uses branch names as labels when
+ able.
+
+ * Describe the policy to introduce breaking changes.
+
+ * Teach 'git notes add' and 'git notes append' a new '-e' flag,
+ instructing them to open the note in $GIT_EDITOR before saving.
+
+ * Documentation for "git bundle" saw improvements to more prominently
+ call out the use of '--all' when creating bundles.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * Document "amlog" notes.
+ (merge ddfb5bcfc6 tb/notes-amlog-doc later to maint).
+
+ * The way AsciiDoc is used for SYNOPSIS part of the manual pages has
+ been revamped. The sources, at least for the simple cases, got
+ vastly pleasant to work with.
+
+ * The reftable library is now prepared to expect that the memory
+ allocation function given to it may fail to allocate and to deal
+ with such an error.
+
+ * An extra worktree attached to a repository points at each other to
+ allow finding the repository from the worktree and vice versa
+ possible. Turn this linkage to relative paths.
+
+ * Enable Windows-based CI in GitLab.
+
+ * Commands that can also work outside Git have learned to take the
+ repository instance "repo" when we know we are in a repository, and
+ NULL when we are not, in a parameter. The uses of the_repository
+ variable in a few of them have been removed using the new calling
+ convention.
+
+ * The reftable sub-system grew a new reftable-specific strbuf
+ replacement to reduce its dependency on Git-specific data
+ structures.
+
+ * The ref-filter machinery learns to recognize and avoid cases where
+ sorting would be redundant.
+
+ * Various platform compatibility fixes split out of the larger effort
+ to use Meson as the primary build tool.
+
+ * Treat ECONNABORTED the same as ECONNRESET in 'git credential-cache'
+ to work around a possible Cygwin regression. This resolves a race
+ condition caused by changes in Cygwin's handling of socket
+ closures, allowing the client to exit cleanly when encountering
+ ECONNABORTED.
+
+ * Demonstrate an assertion failure in 'git mv'.
+
+ * Documentation update to clarify that 'uploadpack.allowAnySHA1InWant'
+ implies both 'allowTipSHA1InWant' and 'allowReachableSHA1InWant'.
+
+ * Replace various calls to atoi() with strtol_i() and strtoul_ui(),
+ and add improved error handling.
+
+ * Documentation updates to 'git-update-ref(1)'.
+
+ * Update the project's CodingGuidelines to discourage naming functions
+ with a "_1()" suffix.
+
+ * Updates the '.clang-format' to match project conventions.
+
+ * Centralize documentation for repository extensions into a single place.
+
+ * Buildfix and upgrade of Clar to a newer version.
+
+ * Documentation mark-up updates.
+
+ * Renaming a handful of variables and structure fields.
+
+ * Fix for clar unit tests to support CMake build.
+
+ * C23 compatibility updates.
+
+ * GCC 15 compatibility updates.
+
+ * We now ensure "index-pack" is used with the "--promisor" option
+ only during a "git fetch".
+
+
+Fixes since v2.47
+-----------------
+
+ * Doc update to clarify how periodical maintenance are scheduled,
+ spread across time to avoid thundering hurds.
+ (merge 3d6ab4177d sk/doc-maintenance-schedule later to maint).
+
+ * Use after free and double freeing at the end in "git log -L... -p"
+ had been identified and fixed.
+
+ * On macOS, fsmonitor can fall into a race condition that results in
+ a client waiting forever to be notified for an event that have
+ already happened. This problem has been corrected.
+
+ * "git maintenance start" crashed due to an uninitialized variable
+ reference, which has been corrected.
+
+ * Fail gracefully instead of crashing when attempting to write the
+ contents of a corrupt in-core index as a tree object.
+
+ * A "git fetch" from the superproject going down to a submodule used
+ a wrong remote when the default remote names are set differently
+ between them.
+
+ * Fixes compile time warnings with 64-bit MSVC.
+
+ * Teaches 'shortlog' to explicitly use SHA-1 when operating outside
+ of a repository.
+
+ * Fix 'git grep' regression on macOS by disabling lookahead when
+ encountering invalid UTF-8 byte sequences.
+
+ * The dumb-http code regressed when the result of re-indexing a pack
+ yielded an *.idx file that differs in content from the *.idx file
+ it downloaded from the remote. This has been corrected by no longer
+ relying on: the *.idx file we got from the remote.
+
+ * When called with '--left-right' and '--use-bitmap-index', 'rev-list'
+ will produce output without any left/right markers, which has been
+ corrected.
+
+ * More leakfixes.
+
+ * Test modernization.
+
+ * The "--shallow-exclude=<ref>" option to various history transfer
+ commands takes a ref, not an arbitrary revision.
+
+ * A regression where commit objects missing from a commit-graph can
+ cause an infinite loop when doing a fetch in a partial clone has
+ been fixed.
+
+ * The MinGW compatibility layer has been taught to support POSIX
+ semantics for atomic renames when other process(es) have a file
+ opened at the destination path.
+
+ * "git gc" discards any objects that are outside promisor packs that
+ are referred to by an object in a promisor pack, and we do not
+ refetch them from the promisor at runtime, resulting an unusable
+ repository. Work it around by including these objects in the
+ referring promisor pack at the receiving end of the fetch.
+
+ * Avoid build/test breakage on a system without working malloc debug
+ support dynamic library.
+ (merge 72ad6dc368 jk/test-malloc-debug-check later to maint).
+
+ * Double-free fix.
+ (merge fe17a25905 jk/fetch-prefetch-double-free-fix later to maint).
+
+ * Use of some uninitialized variables in "git difftool" has been
+ corrected.
+
+ * Object reuse code based on multi-pack-index sent an unwanted copy
+ of object.
+ (merge e199290592 tb/multi-pack-reuse-dupfix later to maint).
+
+ * "git fast-import" can be tricked into a replace ref that maps an
+ object to itself, which is a useless thing to do.
+ (merge 5e904f1a4a en/fast-import-avoid-self-replace later to maint).
+
+ * The ref-transaction hook triggered for reflog updates, which has
+ been corrected.
+ (merge b886db48c6 kn/ref-transaction-hook-with-reflog later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 1164e270b5 jk/output-prefix-cleanup later to maint).
+ (merge f36b8cbaef jh/config-unset-doc-fix later to maint).
+ (merge 4154ed4108 js/doc-platform-support-link-fix later to maint).
+ (merge 77af53f56f aa/t7300-modernize later to maint).
+ (merge 8ead1bba3e jc/doc-refspec-syntax later to maint).
+ (merge 432f666aa6 kn/loose-object-layer-wo-global-hash later to maint).
+ (merge c4b8fb6ef2 kh/merge-tree-doc later to maint).
+ (merge b8139c8f4e kh/checkout-ignore-other-docfix later to maint).
+ (merge 6dab49b9fb tc/bundle-uri-leakfix later to maint).
+ (merge f1ed39987b xx/protocol-v2-doc-markup-fix later to maint).
+ (merge 41869f7447 ak/typofixes later to maint).
+ (merge dcd590a39d bf/t-readme-mention-reftable later to maint).
+ (merge 68e3c69efa kh/trailer-in-glossary later to maint).
diff --git a/Documentation/ReviewingGuidelines.txt b/Documentation/ReviewingGuidelines.txt
index 0e323d5477..6534643cff 100644
--- a/Documentation/ReviewingGuidelines.txt
+++ b/Documentation/ReviewingGuidelines.txt
@@ -19,7 +19,7 @@ Principles
Selecting patch(es) to review
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are looking for a patch series in need of review, start by checking
-latest "What's cooking in git.git" email
+the latest "What's cooking in git.git" email
(https://lore.kernel.org/git/xmqqilm1yp3m.fsf@gitster.g/[example]). The "What's
cooking" emails & replies can be found using the query `s:"What's cooking"` on
the https://lore.kernel.org/git/[`lore.kernel.org` mailing list archive];
@@ -72,12 +72,29 @@ guidance, and concrete tips for interacting with patches on the mailing list.
could fix it. This not only helps the author to understand and fix the issue,
it also deepens and improves your understanding of the topic.
-- Reviews do not need to exclusively point out problems. Feel free to "think out
+- Reviews do not need to exclusively point out problems. Positive
+ reviews indicate that it is not only the original author of the
+ patches who care about the issue the patches address, and are
+ highly encouraged.
+
+- Do not hesitate to give positive reviews on a series from your
+ work colleague. If your positive review is written well, it will
+ not make you look as if you two are representing corporate
+ interest on a series that is otherwise uninteresting to other
+ community members and shoving it down their throat.
+
+- Write a positive review in such a way that others can understand
+ why you support the goal, the approach, and the implementation the
+ patches took. Make sure to demonstrate that you did thoroughly read
+ the series and understood problem area well enough to be able to
+ say that the patches are written well. Feel free to "think out
loud" in your review: describe how you read & understood a complex section of
a patch, ask a question about something that confused you, point out something
- you found exceptionally well-written, etc. In particular, uplifting feedback
- goes a long way towards encouraging contributors to participate more actively
- in the Git community.
+ you found exceptionally well-written, etc.
+
+- In particular, uplifting feedback goes a long way towards
+ encouraging contributors to participate more actively in the Git
+ community.
==== Performing your review
- Provide your review comments per-patch in a plaintext "Reply-All" email to the
@@ -126,7 +143,7 @@ Terminology
-----------
nit: ::
Denotes a small issue that should be fixed, such as a typographical error
- or mis-alignment of conditions in an `if()` statement.
+ or misalignment of conditions in an `if()` statement.
aside: ::
optional: ::
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 973d7a81d4..db17bc7fe2 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -7,6 +7,73 @@ 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.
+[[patch-flow]]
+=== A typical life cycle of a patch series
+
+To help us understand the reason behind various guidelines given later
+in the document, first let's understand how the life cycle of a
+typical patch series for this project goes.
+
+. You come up with an itch. You code it up. You do not need any
+ pre-authorization from the project to do so.
++
+Your patches will be reviewed by other contributors on the mailing
+list, and the reviews will be done to assess the merit of various
+things, like the general idea behind your patch (including "is it
+solving a problem worth solving in the first place?"), the reason
+behind the design of the solution, and the actual implementation.
+The guidelines given here are there to help your patches by making
+them easier to understand by the reviewers.
+
+. You send the patches to the list and cc people who may need to know
+ about the change. Your goal is *not* necessarily to convince others
+ that what you are building is good. Your goal is to get help in
+ coming up with a solution for the "itch" that is better than what
+ you can build alone.
++
+The people who may need to know are the ones who worked on the code
+you are touching. These people happen to be the ones who are
+most likely to be knowledgeable enough to help you, but
+they have no obligation to help you (i.e. you ask them for help,
+you don't demand). +git log -p {litdd} _$area_you_are_modifying_+ would
+help you find out who they are.
+
+. You get comments and suggestions for improvements. You may even get
+ them in an "on top of your change" patch form. You are expected to
+ respond to them with "Reply-All" on the mailing list, while taking
+ them into account while preparing an updated set of patches.
+
+. Polish, refine, and re-send your patches to the list and to the people
+ who spent their time to improve your patch. Go back to step (2).
+
+. While the above iterations improve your patches, the maintainer may
+ pick the patches up from the list and queue them to the `seen`
+ branch, in order to make it easier for people to play with it
+ without having to pick up and apply the patches to their trees
+ themselves. Being in `seen` has no other meaning. Specifically, it
+ does not mean the patch was "accepted" in any way.
+
+. When the discussion reaches a consensus that the latest iteration of
+ the patches are in good enough shape, the maintainer includes the
+ topic in the "What's cooking" report that are sent out a few times a
+ week to the mailing list, marked as "Will merge to 'next'." This
+ decision is primarily made by the maintainer with help from those
+ who participated in the review discussion.
+
+. After the patches are merged to the 'next' branch, the discussion
+ can still continue to further improve them by adding more patches on
+ top, but by the time a topic gets merged to 'next', it is expected
+ that everybody agrees that the scope and the basic direction of the
+ topic are appropriate, so such an incremental updates are limited to
+ small corrections and polishing. After a topic cooks for some time
+ (like 7 calendar days) in 'next' without needing further tweaks on
+ top, it gets merged to the 'master' branch and wait to become part
+ of the next major release.
+
+In the following sections, many techniques and conventions are listed
+to help your patches get reviewed effectively in such a life cycle.
+
+
[[choose-starting-point]]
=== Choose a starting point.
@@ -87,7 +154,7 @@ 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
+`master` and merging the required topic branches into it. You could then
work on top of this base-branch. But keep in mind that this base-branch
would only be known privately to you. So when you are ready to send
your patches to the list, be sure to communicate how you created it in
@@ -192,8 +259,9 @@ reasons:
which case, they can explain why they extend your code to cover
files, too).
-The goal of your log message is to convey the _why_ behind your
-change to help future developers.
+The goal of your log message is to convey the _why_ behind your change
+to help future developers. The reviewers will also make sure that
+your proposed log message will serve this purpose well.
The first line of the commit message should be a short description (50
characters is the soft limit, see DISCUSSION in linkgit:git-commit[1]),
@@ -266,7 +334,7 @@ date)", like this:
noticed that ...
....
-The "Copy commit summary" command of gitk can be used to obtain this
+The "Copy commit reference" command of gitk can be used to obtain this
format (with the subject enclosed in a pair of double-quotes), or this
invocation of `git show`:
@@ -344,20 +412,32 @@ Also notice that a real name is used in the `Signed-off-by` trailer. Please
don't hide your real name.
[[commit-trailers]]
-If you like, you can put extra tags at the end:
+If you like, you can put extra trailers at the end:
. `Reported-by:` is used to credit someone who found the bug that
the patch attempts to fix.
. `Acked-by:` says that the person who is more familiar with the area
the patch attempts to modify liked the patch.
-. `Reviewed-by:`, unlike the other tags, can only be offered by the
+. `Reviewed-by:`, unlike the other trailers, can only be offered by the
reviewers themselves when they are completely satisfied with the
patch after a detailed analysis.
. `Tested-by:` is used to indicate that the person applied the patch
and found it to have the desired effect.
-
-You can also create your own tag or use one that's in common usage
-such as "Thanks-to:", "Based-on-patch-by:", or "Mentored-by:".
+. `Co-authored-by:` is used to indicate that people exchanged drafts
+ of a patch before submitting it.
+. `Helped-by:` is used to credit someone who suggested ideas for
+ changes without providing the precise changes in patch form.
+. `Mentored-by:` is used to credit someone with helping develop a
+ patch as part of a mentorship program (e.g., GSoC or Outreachy).
+. `Suggested-by:` is used to credit someone with suggesting the idea
+ for a patch.
+
+While you can also create your own trailer if the situation warrants it, we
+encourage you to instead use one of the common trailers in this project
+highlighted above.
+
+Only capitalize the very first letter of the trailer, i.e. favor
+"Signed-off-by" over "Signed-Off-By" and "Acked-by:" over "Acked-By".
[[git-tools]]
=== Generate your patch using Git tools out of your commits.
@@ -385,16 +465,56 @@ letter.
[[send-patches]]
=== Sending your patches.
+==== Choosing your reviewers
+
:security-ml: footnoteref:[security-ml,The Git Security mailing list: git-security@googlegroups.com]
-Before sending any patches, please note that patches that may be
+NOTE: Patches that may be
security relevant should be submitted privately to the Git Security
mailing list{security-ml}, instead of the public mailing list.
-Learn to use format-patch and send-email if possible. These commands
+:contrib-scripts: footnoteref:[contrib-scripts,Scripts under `contrib/` are +
+not part of the core `git` binary and must be called directly. Clone the Git +
+codebase and run `perl contrib/contacts/git-contacts`.]
+
+Send your patch with "To:" set to the mailing list, with "cc:" listing
+people who are involved in the area you are touching (the `git-contacts`
+script in `contrib/contacts/`{contrib-scripts} can help to
+identify them), to solicit comments and reviews. Also, when you made
+trial merges of your topic to `next` and `seen`, you may have noticed
+work by others conflicting with your changes. There is a good possibility
+that these people may know the area you are touching well.
+
+If you are using `send-email`, you can feed it the output of `git-contacts` like
+this:
+
+....
+ git send-email --cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch
+....
+
+:current-maintainer: footnote:[The current maintainer: gitster@pobox.com]
+:git-ml: footnote:[The mailing list: git@vger.kernel.org]
+
+After the list reached a consensus that it is a good idea to apply the
+patch, re-send it with "To:" set to the maintainer{current-maintainer}
+and "cc:" the list{git-ml} for inclusion. This is especially relevant
+when the maintainer did not heavily participate in the discussion and
+instead left the review to trusted others.
+
+Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
+`Tested-by:` lines as necessary to credit people who helped your
+patch, and "cc:" them when sending such a final version for inclusion.
+
+==== `format-patch` and `send-email`
+
+Learn to use `format-patch` and `send-email` if possible. These commands
are optimized for the workflow of sending patches, avoiding many ways
-your existing e-mail client that is optimized for "multipart/*" mime
-type e-mails to corrupt and render your patches unusable.
+your existing e-mail client (often optimized for "multipart/*" MIME
+type e-mails) might render your patches unusable.
+
+NOTE: Here we outline the procedure using `format-patch` and
+`send-email`, but you can instead use GitGitGadget to send in your
+patches (see link:MyFirstContribution.html[MyFirstContribution]).
People on the Git mailing list need to be able to read and
comment on the changes you are submitting. It is important for
@@ -403,10 +523,12 @@ e-mail tools, so that they may comment on specific portions of
your code. For this reason, each patch should be submitted
"inline" in a separate message.
-Multiple related patches should be grouped into their own e-mail
-thread to help readers find all parts of the series. To that end,
-send them as replies to either an additional "cover letter" message
-(see below), the first patch, or the respective preceding patch.
+All subsequent versions of a patch series and other related patches should be
+grouped into their own e-mail thread to help readers find all parts of the
+series. To that end, send them as replies to either an additional "cover
+letter" message (see below), the first patch, or the respective preceding patch.
+Here is a link:MyFirstContribution.html#v2-git-send-email[step-by-step guide] on
+how to submit updated versions of a patch series.
If your log message (including your name on the
`Signed-off-by` trailer) is not writable in ASCII, make sure that
@@ -447,6 +569,18 @@ an explanation of changes between each iteration can be kept in
Git-notes and inserted automatically following the three-dash
line via `git format-patch --notes`.
+[[the-topic-summary]]
+*This is EXPERIMENTAL*.
+
+When sending a topic, you can propose a one-paragraph summary that
+should appear in the "What's cooking" report when it is picked up to
+explain the topic. If you choose to do so, please write a 2-5 line
+paragraph that will fit well in our release notes (see many bulleted
+entries in the Documentation/RelNotes/* files for examples), and make
+it the first paragraph of the cover letter. For a single-patch
+series, use the space between the three-dash line and the diffstat, as
+described earlier.
+
[[attachment]]
Do not attach the patch as a MIME attachment, compressed or not.
Do not let your e-mail client send quoted-printable. Do not let
@@ -474,49 +608,100 @@ patch, format it as "multipart/signed", not a text/plain message
that starts with `-----BEGIN PGP SIGNED MESSAGE-----`. That is
not a text/plain, it's something else.
-:security-ml-ref: footnoteref:[security-ml]
+=== Handling Conflicts and Iterating Patches
-As mentioned at the beginning of the section, patches that may be
-security relevant should not be submitted to the public mailing list
-mentioned below, but should instead be sent privately to the Git
-Security mailing list{security-ml-ref}.
+When revising changes made to your patches, it's important to
+acknowledge the possibility of conflicts with other ongoing topics. To
+navigate these potential conflicts effectively, follow the recommended
+steps outlined below:
-Send your patch with "To:" set to the mailing list, with "cc:" listing
-people who are involved in the area you are touching (the `git
-contacts` command in `contrib/contacts/` can help to
-identify them), to solicit comments and reviews. Also, when you made
-trial merges of your topic to `next` and `seen`, you may have noticed
-work by others conflicting with your changes. There is a good possibility
-that these people may know the area you are touching well.
+. Build on a suitable base branch, see the <<choose-starting-point, section above>>,
+and format-patch the series. If you are doing "rebase -i" in-place to
+update from the previous round, this will reuse the previous base so
+(2) and (3) may become trivial.
-:current-maintainer: footnote:[The current maintainer: gitster@pobox.com]
-:git-ml: footnote:[The mailing list: git@vger.kernel.org]
+. Find the base of where the last round was queued
++
+ $ mine='kn/ref-transaction-symref'
+ $ git checkout "origin/seen^{/^Merge branch '$mine'}...master"
-After the list reached a consensus that it is a good idea to apply the
-patch, re-send it with "To:" set to the maintainer{current-maintainer}
-and "cc:" the list{git-ml} for inclusion. This is especially relevant
-when the maintainer did not heavily participate in the discussion and
-instead left the review to trusted others.
+. Apply your format-patch result. There are two cases
+.. Things apply cleanly and tests fine. Go to (4).
+.. Things apply cleanly but does not build or test fails, or things do
+not apply cleanly.
++
+In the latter case, you have textual or semantic conflicts coming from
+the difference between the old base and the base you used to build in
+(1). Identify what caused the breakages (e.g., a topic or two may have
+merged since the base used by (2) until the base used by (1)).
++
+Check out the latest 'origin/master' (which may be newer than the base
+used by (2)), "merge --no-ff" the topics you newly depend on in there,
+and use the result of the merge(s) as the base, rebuild the series and
+test again. Run format-patch from the last such merges to the tip of
+your topic. If you did
++
+ $ git checkout origin/master
+ $ git merge --no-ff --into-name kn/ref-transaction-symref fo/obar
+ $ git merge --no-ff --into-name kn/ref-transaction-symref ba/zqux
+ ... rebuild the topic ...
++
+Then you'd just format your topic above these "preparing the ground"
+merges, e.g.
++
+ $ git format-patch "HEAD^{/^Merge branch 'ba/zqux'}"..HEAD
++
+Do not forget to write in the cover letter you did this, including the
+topics you have in your base on top of 'master'. Then go to (4).
-Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
-`Tested-by:` lines as necessary to credit people who helped your
-patch, and "cc:" them when sending such a final version for inclusion.
+. Make a trial merge of your topic into 'next' and 'seen', e.g.
++
+ $ git checkout --detach 'origin/seen'
+ $ git revert -m 1 <the merge of the previous iteration into seen>
+ $ git merge kn/ref-transaction-symref
++
+The "revert" is needed if the previous iteration of your topic is
+already in 'seen' (like in this case). You could choose to rebuild
+master..origin/seen from scratch while excluding your previous
+iteration, which may emulate what happens on the maintainers end more
+closely.
++
+This trial merge may conflict. It is primarily to see what conflicts
+_other_ topics may have with your topic. In other words, you do not
+have to depend on it to make your topic work on 'master'. It may
+become the job of the other topic owners to resolve conflicts if your
+topic goes to 'next' before theirs.
++
+Make a note on what conflict you saw in the cover letter. You do not
+necessarily have to resolve them, but it would be a good opportunity to
+learn what others are doing in related areas.
++
+ $ git checkout --detach 'origin/next'
+ $ git merge kn/ref-transaction-symref
++
+This is to see what conflicts your topic has with other topics that are
+already cooking. This should not conflict if (3)-2 prepared a base on
+top of updated master plus dependent topics taken from 'next'. Unless
+the context is severe (one way to tell is try the same trial merge with
+your old iteration, which may conflict in a similar way), expect that it
+will be handled on maintainers end (if it gets unmanageable, I'll ask to
+rebase when I receive your patches).
== Subsystems with dedicated maintainers
Some parts of the system have dedicated maintainers with their own
repositories.
-- `git-gui/` comes from git-gui project, maintained by Pratyush Yadav:
+- `git-gui/` comes from git-gui project, maintained by Johannes Sixt:
- https://github.com/prati0100/git-gui.git
+ https://github.com/j6t/git-gui
- `gitk-git/` comes from Paul Mackerras's gitk project:
git://git.ozlabs.org/~paulus/gitk
- Those who are interested in improve gitk can volunteer to help Paul
- in maintaining it cf. <YntxL/fTplFm8lr6@cleo>.
+ Those who are interested in improving gitk can volunteer to help Paul
+ maintain it, cf. <YntxL/fTplFm8lr6@cleo>.
- `po/` comes from the localization coordinator, Jiang Xin:
@@ -524,54 +709,12 @@ repositories.
Patches to these parts should be based on their trees.
-[[patch-flow]]
-== An ideal patch flow
-
-Here is an ideal patch flow for this project the current maintainer
-suggests to the contributors:
-
-. You come up with an itch. You code it up.
-
-. Send it to the list and cc people who may need to know about
- the change.
-+
-The people who may need to know are the ones whose code you
-are butchering. These people happen to be the ones who are
-most likely to be knowledgeable enough to help you, but
-they have no obligation to help you (i.e. you ask for help,
-don't demand). +git log -p {litdd} _$area_you_are_modifying_+ would
-help you find out who they are.
-
-. You get comments and suggestions for improvements. You may
- even get them in an "on top of your change" patch form.
-
-. Polish, refine, and re-send to the list and the people who
- spend their time to improve your patch. Go back to step (2).
-
-. The list forms consensus that the last round of your patch is
- good. Send it to the maintainer and cc the list.
-
-. A topic branch is created with the patch and is merged to `next`,
- and cooked further and eventually graduates to `master`.
-
-In any time between the (2)-(3) cycle, the maintainer may pick it up
-from the list and queue it to `seen`, in order to make it easier for
-people play with it without having to pick up and apply the patch to
-their trees themselves.
-
-[[patch-status]]
-== Know the status of your patch after submission
+- The "Git documentation translations" project, led by Jean-Noël
+ Avila, translates our documentation pages. Their work products are
+ maintained separately from this project, not as part of our tree:
-* You can use Git itself to find out when your patch is merged in
- master. `git pull --rebase` will automatically skip already-applied
- patches, and will let you know. This works only if you rebase on top
- of the branch in which your patch has been merged (i.e. it will not
- tell you if your patch is merged in `seen` if you rebase on top of
- master).
+ https://github.com/jnavila/git-manpages-l10n/
-* Read the Git mailing list, the maintainer regularly posts messages
- entitled "What's cooking in git.git" and "What's in git.git" giving
- the status of various proposed changes.
== GitHub CI[[GHCI]]
@@ -590,11 +733,12 @@ After the initial setup, CI will run whenever you push new changes
to your fork of Git on GitHub. You can monitor the test state of all your
branches here: `https://github.com/<Your GitHub handle>/git/actions/workflows/main.yml`
-If a branch did not pass all test cases then it is marked with a red
-cross. In that case you can click on the failing job and navigate to
-"ci/run-build-and-tests.sh" and/or "ci/print-test-failures.sh". You
-can also download "Artifacts" which are tarred (or zipped) archives
-with test data relevant for debugging.
+If a branch does not pass all test cases then it will be marked with a
+red +x+, instead of a green check. In that case, you can click on the
+failing job and navigate to "ci/run-build-and-tests.sh" and/or
+"ci/print-test-failures.sh". You can also download "Artifacts" which
+are zip archives containing tarred (or zipped) archives with test data
+relevant for debugging.
Then fix the problem and push your fix to your GitHub fork. This will
trigger a new CI build to ensure all tests pass.
@@ -686,7 +830,7 @@ message to an external program, and this is a handy way to drive
`git am`. However, if the message is MIME encoded, what is
piped into the program is the representation you see in your
`*Article*` buffer after unwrapping MIME. This is often not what
-you would want for two reasons. It tends to screw up non ASCII
+you would want for two reasons. It tends to screw up non-ASCII
characters (most notably in people's names), and also
whitespaces (fatal in patches). Running "C-u g" to display the
message in raw form before using "|" to run the pipe can work
diff --git a/Documentation/ToolsForGit.txt b/Documentation/ToolsForGit.txt
index 5060d0d231..ae7690b45d 100644
--- a/Documentation/ToolsForGit.txt
+++ b/Documentation/ToolsForGit.txt
@@ -5,7 +5,7 @@ Tools for developing Git
[[summary]]
== Summary
-This document gathers tips, scripts and configuration file to help people
+This document gathers tips, scripts, and configuration files to help people
working on Git's codebase use their favorite tools while following Git's
coding style.
@@ -32,7 +32,7 @@ information on using the script.
This is adapted from Linux's suggestion in its CodingStyle document:
-- To follow rules of the CodingGuideline, it's useful to put the following in
+- To follow the rules in CodingGuidelines, it's useful to put the following in
GIT_CHECKOUT/.dir-locals.el, assuming you use cperl-mode:
----
;; note the first part is useful for C editing, too
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index 60f76f43ed..f6da6d1fbd 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -28,6 +28,10 @@ ifdef::backend-docbook[]
{0#<citerefentry>}
{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
{0#</citerefentry>}
+
+[literal-inlinemacro]
+{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}
+
endif::backend-docbook[]
ifdef::backend-docbook[]
@@ -56,4 +60,20 @@ ifdef::backend-xhtml11[]
git-relative-html-prefix=
[linkgit-inlinemacro]
<a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
+
+[literal-inlinemacro]
+{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<em>\1</em>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<code>\2</code>', re.sub(r'(\.\.\.?)([^\]$.])', r'<code>\1</code>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}
+
+endif::backend-xhtml11[]
+
+ifdef::backend-docbook[]
+ifdef::doctype-manpage[]
+[paradef-default]
+synopsis-style=template="verseparagraph",filter="sed 's!&#8230;\\(\\]\\|$\\)!<phrase>\\0</phrase>!g;s!\\([\\[ |()]\\|^\\|\\]\\|&gt;\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|&#8230;\\)!\\1<literal>\\2</literal>!g;s!&lt;[-a-zA-Z0-9.]\\+&gt;!<emphasis>\\0</emphasis>!g'"
+endif::doctype-manpage[]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[paradef-default]
+synopsis-style=template="verseparagraph",filter="sed 's!&#8230;\\(\\]\\|$\\)!<span>\\0</span>!g;s!\\([\\[ |()]\\|^\\|\\]\\|&gt;\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|&#8230;\\)!\\1<code>\\2</code>!g;s!&lt;[-a-zA-Z0-9.]\\+&gt;!<em>\\0</em>!g'"
endif::backend-xhtml11[]
diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb
index d906a00803..cb24480b63 100644
--- a/Documentation/asciidoctor-extensions.rb
+++ b/Documentation/asciidoctor-extensions.rb
@@ -1,5 +1,7 @@
require 'asciidoctor'
require 'asciidoctor/extensions'
+require 'asciidoctor/converter/docbook5'
+require 'asciidoctor/converter/html5'
module Git
module Documentation
@@ -39,10 +41,95 @@ module Git
output
end
end
+
+ class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor
+
+ use_dsl
+ named :synopsis
+ parse_content_as :simple
+
+ def process parent, reader, attrs
+ outlines = reader.lines.map do |l|
+ l.gsub(/(\.\.\.?)([^\]$.])/, '`\1`\2')
+ .gsub(%r{([\[\] |()>]|^)([-a-zA-Z0-9:+=~@,/_^\$]+)}, '\1{empty}`\2`{empty}')
+ .gsub(/(<[-a-zA-Z0-9.]+>)/, '__\\1__')
+ .gsub(']', ']{empty}')
+ end
+ create_block parent, :verse, outlines, attrs
+ end
+ end
+
+ class GitDBConverter < Asciidoctor::Converter::DocBook5Converter
+
+ extend Asciidoctor::Converter::Config
+ register_for 'docbook5'
+
+ def convert_inline_quoted node
+ if (type = node.type) == :asciimath
+ # NOTE fop requires jeuclid to process mathml markup
+ asciimath_available? ? %(<inlineequation>#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}</inlineequation>) : %(<inlineequation><mathphrase><![CDATA[#{node.text}]]></mathphrase></inlineequation>)
+ elsif type == :latexmath
+ # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
+ %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
+ elsif type == :monospaced
+ node.text.gsub(/(\.\.\.?)([^\]$.])/, '<literal>\1</literal>\2')
+ .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<literal>\2</literal>')
+ .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<emphasis>\1</emphasis>')
+ else
+ open, close, supports_phrase = QUOTE_TAGS[type]
+ text = node.text
+ if node.role
+ if supports_phrase
+ quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
+ else
+ quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
+ end
+ else
+ quoted_text = %(#{open}#{text}#{close})
+ end
+ node.id ? %(<anchor#{common_attributes node.id, nil, text}/>#{quoted_text}) : quoted_text
+ end
+ end
+ end
+
+ # register a html5 converter that takes in charge to convert monospaced text into Git style synopsis
+ class GitHTMLConverter < Asciidoctor::Converter::Html5Converter
+
+ extend Asciidoctor::Converter::Config
+ register_for 'html5'
+
+ def convert_inline_quoted node
+ if node.type == :monospaced
+ node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2')
+ .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<code>\2</code>')
+ .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<em>\1</em>')
+
+ else
+ open, close, tag = QUOTE_TAGS[node.type]
+ if node.id
+ class_attr = node.role ? %( class="#{node.role}") : ''
+ if tag
+ %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close})
+ else
+ %(<span id="#{node.id}"#{class_attr}>#{open}#{node.text}#{close}</span>)
+ end
+ elsif node.role
+ if tag
+ %(#{open.chop} class="#{node.role}">#{node.text}#{close})
+ else
+ %(<span class="#{node.role}">#{open}#{node.text}#{close}</span>)
+ end
+ else
+ %(#{open}#{node.text}#{close})
+ end
+ end
+ end
+ end
end
end
Asciidoctor::Extensions.register do
inline_macro Git::Documentation::LinkGitProcessor, :linkgit
+ block Git::Documentation::SynopsisBlock
postprocessor Git::Documentation::DocumentPostProcessor
end
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 229b63a454..8c0b3ed807 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -11,7 +11,7 @@ file. The file `/etc/gitconfig` can be used to store a system-wide
default configuration.
The configuration variables are used by both the Git plumbing
-and the porcelains. The variables are divided into sections, wherein
+and the porcelain commands. The variables are divided into sections, wherein
the fully qualified variable name of the variable itself is the last
dot-separated segment and the section name is everything before the last
dot. The variable names are case-insensitive, allow only alphanumeric
@@ -22,9 +22,10 @@ multivalued.
Syntax
~~~~~~
-The syntax is fairly flexible and permissive; whitespaces are mostly
-ignored. The '#' and ';' characters begin comments to the end of line,
-blank lines are ignored.
+The syntax is fairly flexible and permissive. Whitespace characters,
+which in this context are the space character (SP) and the horizontal
+tabulation (HT), are mostly ignored. The '#' and ';' characters begin
+comments to the end of line. Blank lines are ignored.
The file consists of sections and variables. A section begins with
the name of the section in square brackets and continues until the next
@@ -63,16 +64,17 @@ the variable is the boolean "true").
The variable names are case-insensitive, allow only alphanumeric characters
and `-`, and must start with an alphabetic character.
-A line that defines a value can be continued to the next line by
-ending it with a `\`; the backslash and the end-of-line are
-stripped. Leading whitespaces after 'name =', the remainder of the
-line after the first comment character '#' or ';', and trailing
-whitespaces of the line are discarded unless they are enclosed in
-double quotes. Internal whitespaces within the value are retained
-verbatim.
+Whitespace characters surrounding `name`, `=` and `value` are discarded.
+Internal whitespace characters within 'value' are retained verbatim.
+Comments starting with either `#` or `;` and extending to the end of line
+are discarded. A line that defines a value can be continued to the next
+line by ending it with a backslash (`\`); the backslash and the end-of-line
+characters are discarded.
-Inside double quotes, double quote `"` and backslash `\` characters
-must be escaped: use `\"` for `"` and `\\` for `\`.
+If `value` needs to contain leading or trailing whitespace characters,
+it must be enclosed in double quotation marks (`"`). Inside double quotation
+marks, double quote (`"`) and backslash (`\`) characters must be escaped:
+use `\"` for `"` and `\\` for `\`.
The following escape sequences (beside `\"` and `\\`) are recognized:
`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
@@ -103,7 +105,7 @@ was found. See below for examples.
Conditional includes
~~~~~~~~~~~~~~~~~~~~
-You can include a config file from another conditionally by setting a
+You can conditionally include a config file from another by setting an
`includeIf.<condition>.path` variable to the name of the file to be
included.
@@ -118,7 +120,7 @@ are:
pattern, the include condition is met.
+
The .git location may be auto-discovered, or come from `$GIT_DIR`
-environment variable. If the repository is auto discovered via a .git
+environment variable. If the repository is auto-discovered via a .git
file (e.g. from submodules, or a linked worktree), the .git location
would be the final location where the .git directory is, not where the
.git file is.
@@ -314,7 +316,8 @@ terminals, this is usually not the same as setting to "white black".
Colors may also be given as numbers between 0 and 255; these use ANSI
256-color mode (but note that not all terminals may support this). If
your terminal supports it, you may also specify 24-bit RGB values as
-hex, like `#ff0ab3`.
+hex, like `#ff0ab3`, or 12-bit RGB values like `#f1b`, which is
+equivalent to the 24-bit color `#ff11bb`.
+
The accepted attributes are `bold`, `dim`, `ul`, `blink`, `reverse`,
`italic`, and `strike` (for crossed-out or "strikethrough" letters).
@@ -369,18 +372,20 @@ inventing new variables for use in your own tool, make sure their
names do not conflict with those that are used by Git itself and
other popular tools, and describe them in your documentation.
-include::config/advice.txt[]
-
-include::config/core.txt[]
-
include::config/add.txt[]
+include::config/advice.txt[]
+
include::config/alias.txt[]
include::config/am.txt[]
include::config/apply.txt[]
+include::config/attr.txt[]
+
+include::config/bitmap-pseudo-merge.txt[]
+
include::config/blame.txt[]
include::config/branch.txt[]
@@ -403,10 +408,12 @@ include::config/commit.txt[]
include::config/commitgraph.txt[]
-include::config/credential.txt[]
-
include::config/completion.txt[]
+include::config/core.txt[]
+
+include::config/credential.txt[]
+
include::config/diff.txt[]
include::config/difftool.txt[]
@@ -419,10 +426,10 @@ include::config/feature.txt[]
include::config/fetch.txt[]
-include::config/format.txt[]
-
include::config/filter.txt[]
+include::config/format.txt[]
+
include::config/fsck.txt[]
include::config/fsmonitor--daemon.txt[]
@@ -433,10 +440,10 @@ include::config/gitcvs.txt[]
include::config/gitweb.txt[]
-include::config/grep.txt[]
-
include::config/gpg.txt[]
+include::config/grep.txt[]
+
include::config/gui.txt[]
include::config/guitool.txt[]
@@ -483,6 +490,8 @@ include::config/pager.txt[]
include::config/pretty.txt[]
+include::config/promisor.txt[]
+
include::config/protocol.txt[]
include::config/pull.txt[]
@@ -493,6 +502,8 @@ include::config/rebase.txt[]
include::config/receive.txt[]
+include::config/reftable.txt[]
+
include::config/remote.txt[]
include::config/remotes.txt[]
@@ -517,10 +528,10 @@ include::config/splitindex.txt[]
include::config/ssh.txt[]
-include::config/status.txt[]
-
include::config/stash.txt[]
+include::config/status.txt[]
+
include::config/submodule.txt[]
include::config/tag.txt[]
diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt
index e0354ceaed..7497533cbc 100644
--- a/Documentation/config/add.txt
+++ b/Documentation/config/add.txt
@@ -1,13 +1,12 @@
-add.ignoreErrors::
-add.ignore-errors (deprecated)::
- Tells 'git add' to continue adding files when some files cannot be
- added due to indexing errors. Equivalent to the `--ignore-errors`
- option of linkgit:git-add[1]. `add.ignore-errors` is deprecated,
- as it does not follow the usual naming convention for configuration
- variables.
-
-add.interactive.useBuiltin::
- Unused configuration variable. Used in Git versions v2.25.0 to
- v2.36.0 to enable the built-in version of linkgit:git-add[1]'s
- interactive mode, which then became the default in Git
- versions v2.37.0 to v2.39.0.
+`add.ignoreErrors`::
+`add.ignore-errors` (deprecated)::
+ Tells `git add` to continue adding files when some files cannot be
+ added due to indexing errors.
+ifdef::git-add[]
+ Equivalent to the `--ignore-errors` option.
+endif::git-add[]
+ifndef::git-add[]
+ Equivalent to the `--ignore-errors` option of linkgit:git-add[1].
+endif::git-add[]
+ `add.ignore-errors` is deprecated, as it does not follow the usual
+ naming convention for configuration variables.
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index c548a91e67..257db58918 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -1,30 +1,71 @@
advice.*::
These variables control various optional help messages designed to
- aid new users. All 'advice.*' variables default to 'true', and you
- can tell Git that you do not need help by setting these to 'false':
+ aid new users. When left unconfigured, Git will give the message
+ alongside instructions on how to squelch it. You can tell Git
+ that you have understood the issue and no longer need a specific
+ help message by setting the corresponding variable to `false`.
++
+As they are intended to help human users, these messages are output to
+the standard error. When tools that run Git as a subprocess find them
+disruptive, they can set `GIT_ADVICE=0` in the environment to squelch
+all advice messages.
+
--
+ addEmbeddedRepo::
+ Shown when the user accidentally adds one
+ git repo inside of another.
+ addEmptyPathspec::
+ Shown when the user runs `git add` without providing
+ the pathspec parameter.
+ addIgnoredFile::
+ Shown when the user attempts to add an ignored file to
+ the index.
+ amWorkDir::
+ Shown when linkgit:git-am[1] fails to apply a patch
+ file, to tell the user the location of the file.
ambiguousFetchRefspec::
- Advice shown when fetch refspec for multiple remotes map to
+ Shown when a fetch refspec for multiple remotes maps to
the same remote-tracking branch namespace and causes branch
tracking set-up to fail.
+ checkoutAmbiguousRemoteBranchName::
+ Shown when the argument to
+ linkgit:git-checkout[1] and linkgit:git-switch[1]
+ ambiguously resolves to a
+ remote tracking branch on more than one remote in
+ situations where an unambiguous argument would have
+ otherwise caused a remote-tracking branch to be
+ checked out. See the `checkout.defaultRemote`
+ configuration variable for how to set a given remote
+ to be used by default in some situations where this
+ advice would be printed.
+ commitBeforeMerge::
+ Shown when linkgit:git-merge[1] refuses to
+ merge to avoid overwriting local changes.
+ detachedHead::
+ Shown when the user uses
+ linkgit:git-switch[1] or linkgit:git-checkout[1]
+ to move to the detached HEAD state, to tell the user how
+ to create a local branch after the fact.
+ diverging::
+ Shown when a fast-forward is not possible.
fetchShowForcedUpdates::
- Advice shown when linkgit:git-fetch[1] takes a long time
+ Shown when linkgit:git-fetch[1] takes a long time
to calculate forced updates after ref updates, or to warn
that the check is disabled.
- pushUpdateRejected::
- Set this variable to 'false' if you want to disable
- 'pushNonFFCurrent', 'pushNonFFMatching', 'pushAlreadyExists',
- 'pushFetchFirst', 'pushNeedsForce', and 'pushRefNeedsUpdate'
- simultaneously.
- pushNonFFCurrent::
- Advice shown when linkgit:git-push[1] fails due to a
- non-fast-forward update to the current branch.
- pushNonFFMatching::
- Advice shown when you ran linkgit:git-push[1] and pushed
- 'matching refs' explicitly (i.e. you used ':', or
- specified a refspec that isn't your current branch) and
- it resulted in a non-fast-forward error.
+ forceDeleteBranch::
+ Shown when the user tries to delete a not fully merged
+ branch without the force option set.
+ ignoredHook::
+ Shown when a hook is ignored because the hook is not
+ set as executable.
+ implicitIdentity::
+ Shown when the user's information is guessed from the
+ system username and domain name, to tell the user how to
+ set their identity configuration.
+ mergeConflict::
+ Shown when various commands stop because of conflicts.
+ nestedTag::
+ Shown when a user attempts to recursively tag a tag object.
pushAlreadyExists::
Shown when linkgit:git-push[1] rejects an update that
does not qualify for fast-forwarding (e.g., a tag.)
@@ -37,20 +78,54 @@ advice.*::
tries to overwrite a remote ref that points at an
object that is not a commit-ish, or make the remote
ref point at an object that is not a commit-ish.
+ pushNonFFCurrent::
+ Shown when linkgit:git-push[1] fails due to a
+ non-fast-forward update to the current branch.
+ pushNonFFMatching::
+ Shown when the user ran linkgit:git-push[1] and pushed
+ "matching refs" explicitly (i.e. used `:`, or
+ specified a refspec that isn't the current branch) and
+ it resulted in a non-fast-forward error.
+ pushRefNeedsUpdate::
+ Shown when linkgit:git-push[1] rejects a forced update of
+ a branch when its remote-tracking ref has updates that we
+ do not have locally.
pushUnqualifiedRefname::
Shown when linkgit:git-push[1] gives up trying to
guess based on the source and destination refs what
remote ref namespace the source belongs in, but where
we can still suggest that the user push to either
- refs/heads/* or refs/tags/* based on the type of the
+ `refs/heads/*` or `refs/tags/*` based on the type of the
source object.
- pushRefNeedsUpdate::
- Shown when linkgit:git-push[1] rejects a forced update of
- a branch when its remote-tracking ref has updates that we
- do not have locally.
+ pushUpdateRejected::
+ Set this variable to `false` if you want to disable
+ `pushNonFFCurrent`, `pushNonFFMatching`, `pushAlreadyExists`,
+ `pushFetchFirst`, `pushNeedsForce`, and `pushRefNeedsUpdate`
+ simultaneously.
+ rebaseTodoError::
+ Shown when there is an error after editing the rebase todo list.
+ refSyntax::
+ Shown when the user provides an illegal ref name, to
+ tell the user about the ref syntax documentation.
+ resetNoRefresh::
+ Shown when linkgit:git-reset[1] takes more than 2
+ seconds to refresh the index after reset, to tell the user
+ that they can use the `--no-refresh` option.
+ resolveConflict::
+ Shown by various commands when conflicts
+ prevent the operation from being performed.
+ rmHints::
+ Shown on failure in the output of linkgit:git-rm[1], to
+ give directions on how to proceed from the current state.
+ sequencerInUse::
+ Shown when a sequencer command is already in progress.
skippedCherryPicks::
Shown when linkgit:git-rebase[1] skips a commit that has already
been cherry-picked onto the upstream branch.
+ sparseIndexExpanded::
+ Shown when a sparse index is expanded to a full index, which is likely
+ due to an unexpected set of files existing outside of the
+ sparse-checkout.
statusAheadBehind::
Shown when linkgit:git-status[1] computes the ahead/behind
counts for a local ref compared to its remote tracking ref,
@@ -63,83 +138,32 @@ advice.*::
the template shown when writing commit messages in
linkgit:git-commit[1], and in the help message shown
by linkgit:git-switch[1] or
- linkgit:git-checkout[1] when switching branch.
+ linkgit:git-checkout[1] when switching branches.
statusUoption::
- Advise to consider using the `-u` option to linkgit:git-status[1]
- when the command takes more than 2 seconds to enumerate untracked
- files.
- commitBeforeMerge::
- Advice shown when linkgit:git-merge[1] refuses to
- merge to avoid overwriting local changes.
- resetNoRefresh::
- Advice to consider using the `--no-refresh` option to
- linkgit:git-reset[1] when the command takes more than 2 seconds
- to refresh the index after reset.
- resolveConflict::
- Advice shown by various commands when conflicts
- prevent the operation from being performed.
- sequencerInUse::
- Advice shown when a sequencer command is already in progress.
- implicitIdentity::
- Advice on how to set your identity configuration when
- your information is guessed from the system username and
- domain name.
- detachedHead::
- Advice shown when you used
- linkgit:git-switch[1] or linkgit:git-checkout[1]
- to move to the detach HEAD state, to instruct how to
- create a local branch after the fact.
- suggestDetachingHead::
- Advice shown when linkgit:git-switch[1] refuses to detach HEAD
- without the explicit `--detach` option.
- checkoutAmbiguousRemoteBranchName::
- Advice shown when the argument to
- linkgit:git-checkout[1] and linkgit:git-switch[1]
- ambiguously resolves to a
- remote tracking branch on more than one remote in
- situations where an unambiguous argument would have
- otherwise caused a remote-tracking branch to be
- checked out. See the `checkout.defaultRemote`
- configuration variable for how to set a given remote
- to used by default in some situations where this
- advice would be printed.
- amWorkDir::
- Advice that shows the location of the patch file when
- linkgit:git-am[1] fails to apply it.
- rmHints::
- In case of failure in the output of linkgit:git-rm[1],
- show directions on how to proceed from the current state.
- addEmbeddedRepo::
- Advice on what to do when you've accidentally added one
- git repo inside of another.
- ignoredHook::
- Advice shown if a hook is ignored because the hook is not
- set as executable.
- waitingForEditor::
- Print a message to the terminal whenever Git is waiting for
- editor input from the user.
- nestedTag::
- Advice shown if a user attempts to recursively tag a tag object.
+ Shown when linkgit:git-status[1] takes more than 2
+ seconds to enumerate untracked files, to tell the user that
+ they can use the `-u` option.
submoduleAlternateErrorStrategyDie::
- Advice shown when a submodule.alternateErrorStrategy option
+ Shown when a submodule.alternateErrorStrategy option
configured to "die" causes a fatal error.
+ submoduleMergeConflict::
+ Advice shown when a non-trivial submodule merge conflict is
+ encountered.
submodulesNotUpdated::
- Advice shown when a user runs a submodule command that fails
+ Shown when a user runs a submodule command that fails
because `git submodule update --init` was not run.
- addIgnoredFile::
- Advice shown if a user attempts to add an ignored file to
- the index.
- addEmptyPathspec::
- Advice shown if a user runs the add command without providing
- the pathspec parameter.
+ suggestDetachingHead::
+ Shown when linkgit:git-switch[1] refuses to detach HEAD
+ without the explicit `--detach` option.
updateSparsePath::
- Advice shown when either linkgit:git-add[1] or linkgit:git-rm[1]
+ 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.
+ waitingForEditor::
+ Shown when Git is waiting for editor input. Relevant
+ when e.g. the editor is not launched inside the terminal.
worktreeAddOrphan::
- Advice shown when a user tries to create a worktree from an
- invalid reference, to instruct how to create a new orphan
+ Shown when the user tries to create a worktree from an
+ invalid reference, to tell the user how to create a new unborn
branch instead.
--
diff --git a/Documentation/config/alias.txt b/Documentation/config/alias.txt
index f1ca739d57..2c5db0ad84 100644
--- a/Documentation/config/alias.txt
+++ b/Documentation/config/alias.txt
@@ -4,7 +4,7 @@ alias.*::
`git last` is equivalent to `git cat-file commit HEAD`. To avoid
confusion and troubles with script usage, aliases that
hide existing Git commands are ignored. Arguments are split by
- spaces, the usual shell quoting and escaping is supported.
+ spaces, the usual shell quoting and escaping are supported.
A quote pair or a backslash can be used to quote them.
+
Note that the first word of an alias does not necessarily have to be a
@@ -21,8 +21,23 @@ If the alias expansion is prefixed with an exclamation point,
it will be treated as a shell command. For example, defining
`alias.new = !gitk --all --not ORIG_HEAD`, the invocation
`git new` is equivalent to running the shell command
-`gitk --all --not ORIG_HEAD`. Note that shell commands will be
-executed from the top-level directory of a repository, which may
-not necessarily be the current directory.
-`GIT_PREFIX` is set as returned by running `git rev-parse --show-prefix`
-from the original current directory. See linkgit:git-rev-parse[1].
+`gitk --all --not ORIG_HEAD`. Note:
++
+* Shell commands will be executed from the top-level directory of a
+ repository, which may not necessarily be the current directory.
+* `GIT_PREFIX` is set as returned by running `git rev-parse --show-prefix`
+ from the original current directory. See linkgit:git-rev-parse[1].
+* Shell command aliases always receive any extra arguments provided to
+ the Git command-line as positional arguments.
+** Care should be taken if your shell alias is a "one-liner" script
+ with multiple commands (e.g. in a pipeline), references multiple
+ arguments, or is otherwise not able to handle positional arguments
+ added at the end. For example: `alias.cmd = "!echo $1 | grep $2"`
+ called as `git cmd 1 2` will be executed as 'echo $1 | grep $2
+ 1 2', which is not what you want.
+** A convenient way to deal with this is to write your script
+ operations in an inline function that is then called with any
+ arguments from the command-line. For example `alias.cmd = "!c() {
+ echo $1 | grep $2 ; }; c" will correctly execute the prior example.
+** Setting `GIT_TRACE=1` can help you debug the command being run for
+ your alias.
diff --git a/Documentation/config/apply.txt b/Documentation/config/apply.txt
index 8fb8ef763d..f9908e210a 100644
--- a/Documentation/config/apply.txt
+++ b/Documentation/config/apply.txt
@@ -2,10 +2,10 @@ apply.ignoreWhitespace::
When set to 'change', tells 'git apply' to ignore changes in
whitespace, in the same way as the `--ignore-space-change`
option.
- When set to one of: no, none, never, false tells 'git apply' to
+ When set to one of: no, none, never, false, it tells 'git apply' to
respect all whitespace differences.
See linkgit:git-apply[1].
apply.whitespace::
- Tells 'git apply' how to handle whitespaces, in the same way
+ Tells 'git apply' how to handle whitespace, in the same way
as the `--whitespace` option. See linkgit:git-apply[1].
diff --git a/Documentation/config/attr.txt b/Documentation/config/attr.txt
new file mode 100644
index 0000000000..c4a5857993
--- /dev/null
+++ b/Documentation/config/attr.txt
@@ -0,0 +1,6 @@
+attr.tree::
+ A reference to a tree in the repository from which to read attributes,
+ instead of the `.gitattributes` file in the working tree. If the value
+ does not resolve to a valid tree object, an empty tree is used instead.
+ When the `GIT_ATTR_SOURCE` environment variable or `--attr-source`
+ command line option are used, this configuration variable has no effect.
diff --git a/Documentation/config/bitmap-pseudo-merge.txt b/Documentation/config/bitmap-pseudo-merge.txt
new file mode 100644
index 0000000000..1f264eca99
--- /dev/null
+++ b/Documentation/config/bitmap-pseudo-merge.txt
@@ -0,0 +1,91 @@
+NOTE: The configuration options in `bitmapPseudoMerge.*` are considered
+EXPERIMENTAL and may be subject to change or be removed entirely in the
+future. For more information about the pseudo-merge bitmap feature, see
+the "Pseudo-merge bitmaps" section of linkgit:gitpacking[7].
+
+bitmapPseudoMerge.<name>.pattern::
+ Regular expression used to match reference names. Commits
+ pointed to by references matching this pattern (and meeting
+ the below criteria, like `bitmapPseudoMerge.<name>.sampleRate`
+ and `bitmapPseudoMerge.<name>.threshold`) will be considered
+ for inclusion in a pseudo-merge bitmap.
++
+Commits are grouped into pseudo-merge groups based on whether or not
+any reference(s) that point at a given commit match the pattern, which
+is an extended regular expression.
++
+Within a pseudo-merge group, commits may be further grouped into
+sub-groups based on the capture groups in the pattern. These
+sub-groupings are formed from the regular expressions by concatenating
+any capture groups from the regular expression, with a '-' dash in
+between.
++
+For example, if the pattern is `refs/tags/`, then all tags (provided
+they meet the below criteria) will be considered candidates for the
+same pseudo-merge group. However, if the pattern is instead
+`refs/remotes/([0-9])+/tags/`, then tags from different remotes will
+be grouped into separate pseudo-merge groups, based on the remote
+number.
+
+bitmapPseudoMerge.<name>.decay::
+ Determines the rate at which consecutive pseudo-merge bitmap
+ groups decrease in size. Must be non-negative. This parameter
+ can be thought of as `k` in the function `f(n) = C * n^-k`,
+ where `f(n)` is the size of the `n`th group.
++
+Setting the decay rate equal to `0` will cause all groups to be the
+same size. Setting the decay rate equal to `1` will cause the `n`th
+group to be `1/n` the size of the initial group. Higher values of the
+decay rate cause consecutive groups to shrink at an increasing rate.
+The default is `1`.
++
+If all groups are the same size, it is possible that groups containing
+newer commits will be able to be used less often than earlier groups,
+since it is more likely that the references pointing at newer commits
+will be updated more often than a reference pointing at an old commit.
+
+bitmapPseudoMerge.<name>.sampleRate::
+ Determines the proportion of non-bitmapped commits (among
+ reference tips) which are selected for inclusion in an
+ unstable pseudo-merge bitmap. Must be between `0` and `1`
+ (inclusive). The default is `1`.
+
+bitmapPseudoMerge.<name>.threshold::
+ Determines the minimum age of non-bitmapped commits (among
+ reference tips, as above) which are candidates for inclusion
+ in an unstable pseudo-merge bitmap. The default is
+ `1.week.ago`.
+
+bitmapPseudoMerge.<name>.maxMerges::
+ Determines the maximum number of pseudo-merge commits among
+ which commits may be distributed.
++
+For pseudo-merge groups whose pattern does not contain any capture
+groups, this setting is applied for all commits matching the regular
+expression. For patterns that have one or more capture groups, this
+setting is applied for each distinct capture group.
++
+For example, if your capture group is `refs/tags/`, then this setting
+will distribute all tags into a maximum of `maxMerges` pseudo-merge
+commits. However, if your capture group is, say,
+`refs/remotes/([0-9]+)/tags/`, then this setting will be applied to
+each remote's set of tags individually.
++
+Must be non-negative. The default value is 64.
+
+bitmapPseudoMerge.<name>.stableThreshold::
+ Determines the minimum age of commits (among reference tips,
+ as above, however stable commits are still considered
+ candidates even when they have been covered by a bitmap) which
+ are candidates for a stable a pseudo-merge bitmap. The default
+ is `1.month.ago`.
++
+Setting this threshold to a smaller value (e.g., 1.week.ago) will cause
+more stable groups to be generated (which impose a one-time generation
+cost) but those groups will likely become stale over time. Using a
+larger value incurs the opposite penalty (fewer stable groups which are
+more useful).
+
+bitmapPseudoMerge.<name>.stableSize::
+ Determines the size (in number of commits) of a stable
+ psuedo-merge bitmap. The default is `512`.
diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index 445341a906..432b9cd2c0 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -36,7 +36,7 @@ branch.sort::
branch.<name>.remote::
When on branch <name>, it tells 'git fetch' and 'git push'
- which remote to fetch from/push to. The remote to push to
+ which remote to fetch from or push to. The remote to push to
may be overridden with `remote.pushDefault` (for all branches).
The remote to push to, for the current branch, may be further
overridden by `branch.<name>.pushRemote`. If no remote is
@@ -64,7 +64,7 @@ branch.<name>.merge::
handled like the remote part of a refspec, and must match a
ref which is fetched from the remote given by
"branch.<name>.remote".
- The merge information is used by 'git pull' (which at first calls
+ The merge information is used by 'git pull' (which first calls
'git fetch') to lookup the default branch for merging. Without
this option, 'git pull' defaults to merge the first refspec fetched.
Specify multiple values to get an octopus merge.
@@ -99,5 +99,5 @@ for details).
branch.<name>.description::
Branch description, can be edited with
`git branch --edit-description`. Branch description is
- automatically added in the format-patch cover letter or
+ automatically added to the format-patch cover letter or
request-pull summary.
diff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt
index bfbca90f0e..a323022993 100644
--- a/Documentation/config/checkout.txt
+++ b/Documentation/config/checkout.txt
@@ -30,7 +30,7 @@ checkout.workers::
all commands that perform checkout. E.g. checkout, clone, reset,
sparse-checkout, etc.
+
-Note: parallel checkout usually delivers better performance for repositories
+Note: Parallel checkout usually delivers better performance for repositories
located on SSDs or over NFS. For repositories on spinning disks and/or machines
with a small number of cores, the default sequential checkout often performs
better. The size and compression level of a repository might also influence how
@@ -39,6 +39,6 @@ well the parallel version performs.
checkout.thresholdForParallelism::
When running parallel checkout with a small number of files, the cost
of subprocess spawning and inter-process communication might outweigh
- the parallelization gains. This setting allows to define the minimum
+ the parallelization gains. This setting allows you to define the minimum
number of files for which parallel checkout should be attempted. The
default is 100.
diff --git a/Documentation/config/clean.txt b/Documentation/config/clean.txt
index a807c925b9..c0188ead4e 100644
--- a/Documentation/config/clean.txt
+++ b/Documentation/config/clean.txt
@@ -1,3 +1,3 @@
clean.requireForce::
- A boolean to make git-clean do nothing unless given -f,
- -i or -n. Defaults to true.
+ A boolean to make git-clean refuse to delete files unless -f
+ is given. Defaults to true.
diff --git a/Documentation/config/clone.txt b/Documentation/config/clone.txt
index 26f4fb137a..0a10efd174 100644
--- a/Documentation/config/clone.txt
+++ b/Documentation/config/clone.txt
@@ -1,13 +1,23 @@
-clone.defaultRemoteName::
+`clone.defaultRemoteName`::
The name of the remote to create when cloning a repository. Defaults to
- `origin`, and can be overridden by passing the `--origin` command-line
+ `origin`.
+ifdef::git-clone[]
+ It can be overridden by passing the `--origin` command-line
+ option.
+endif::[]
+ifndef::git-clone[]
+ It can be overridden by passing the `--origin` command-line
option to linkgit:git-clone[1].
+endif::[]
-clone.rejectShallow::
- Reject to clone a repository if it is a shallow one, can be overridden by
- passing option `--reject-shallow` in command line. See linkgit:git-clone[1]
+`clone.rejectShallow`::
+ Reject cloning a repository if it is a shallow one; this can be overridden by
+ passing the `--reject-shallow` option on the command line.
+ifndef::git-clone[]
+ See linkgit:git-clone[1].
+endif::[]
-clone.filterSubmodules::
+`clone.filterSubmodules`::
If a partial clone filter is provided (see `--filter` in
linkgit:git-rev-list[1]) and `--recurse-submodules` is used, also apply
the filter to submodules.
diff --git a/Documentation/config/color.txt b/Documentation/config/color.txt
index 1795b2d16b..2f2275ac69 100644
--- a/Documentation/config/color.txt
+++ b/Documentation/config/color.txt
@@ -106,7 +106,7 @@ color.grep.<slot>::
matching text in context lines
`matchSelected`;;
matching text in selected lines. Also, used to customize the following
- linkgit:git-log[1] subcommands: `--grep`, `--author` and `--committer`.
+ linkgit:git-log[1] subcommands: `--grep`, `--author`, and `--committer`.
`selected`;;
non-matching text in selected lines. Also, used to customize the
following linkgit:git-log[1] subcommands: `--grep`, `--author` and
diff --git a/Documentation/config/column.txt b/Documentation/config/column.txt
index 76aa2f29dc..01e4198429 100644
--- a/Documentation/config/column.txt
+++ b/Documentation/config/column.txt
@@ -43,7 +43,7 @@ column.branch::
See `column.ui` for details.
column.clean::
- Specify the layout when list items in `git clean -i`, which always
+ Specify the layout when listing items in `git clean -i`, which always
shows files and directories in columns. See `column.ui` for details.
column.status::
@@ -51,5 +51,5 @@ column.status::
See `column.ui` for details.
column.tag::
- Specify whether to output tag listing in `git tag` in columns.
+ Specify whether to output tag listings in `git tag` in columns.
See `column.ui` for details.
diff --git a/Documentation/config/commit.txt b/Documentation/config/commit.txt
index 2c95573930..62f0d92fda 100644
--- a/Documentation/config/commit.txt
+++ b/Documentation/config/commit.txt
@@ -2,7 +2,7 @@ commit.cleanup::
This setting overrides the default of the `--cleanup` option in
`git commit`. See linkgit:git-commit[1] for details. Changing the
default can be useful when you always want to keep lines that begin
- with comment character `#` in your log message, in which case you
+ with the comment character `#` in your log message, in which case you
would do `git config commit.cleanup whitespace` (note that you will
have to remove the help lines that begin with `#` in the commit log
template yourself, if you do this).
@@ -25,5 +25,5 @@ commit.template::
new commit messages.
commit.verbose::
- A boolean or int to specify the level of verbose with `git commit`.
+ A boolean or int to specify the level of verbosity with `git commit`.
See linkgit:git-commit[1].
diff --git a/Documentation/config/commitgraph.txt b/Documentation/config/commitgraph.txt
index 30604e4a4c..7f8c9d6638 100644
--- a/Documentation/config/commitgraph.txt
+++ b/Documentation/config/commitgraph.txt
@@ -9,6 +9,29 @@ commitGraph.maxNewFilters::
commit-graph write` (c.f., linkgit:git-commit-graph[1]).
commitGraph.readChangedPaths::
- If true, then git will use the changed-path Bloom filters in the
- commit-graph file (if it exists, and they are present). Defaults to
- true. See linkgit:git-commit-graph[1] for more information.
+ Deprecated. Equivalent to commitGraph.changedPathsVersion=-1 if true, and
+ commitGraph.changedPathsVersion=0 if false. (If commitGraph.changedPathVersion
+ is also set, commitGraph.changedPathsVersion takes precedence.)
+
+commitGraph.changedPathsVersion::
+ Specifies the version of the changed-path Bloom filters that Git will read and
+ write. May be -1, 0, 1, or 2. Note that values greater than 1 may be
+ incompatible with older versions of Git which do not yet understand
+ those versions. Use caution when operating in a mixed-version
+ environment.
++
+Defaults to -1.
++
+If -1, Git will use the version of the changed-path Bloom filters in the
+repository, defaulting to 1 if there are none.
++
+If 0, Git will not read any Bloom filters, and will write version 1 Bloom
+filters when instructed to write.
++
+If 1, Git will only read version 1 Bloom filters, and will write version 1
+Bloom filters.
++
+If 2, Git will only read version 2 Bloom filters, and will write version 2
+Bloom filters.
++
+See linkgit:git-commit-graph[1] for more information.
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index dfbdaf00b8..8f6d8e7754 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -366,7 +366,7 @@ default in a bare repository.
core.repositoryFormatVersion::
Internal variable identifying the repository format and layout
- version.
+ version. See linkgit:gitrepository-layout[5].
core.sharedRepository::
When 'group' (or 'true'), the repository is made shareable between
@@ -520,6 +520,7 @@ core.editor::
`GIT_EDITOR` is not set. See linkgit:git-var[1].
core.commentChar::
+core.commentString::
Commands such as `commit` and `tag` that let you edit
messages consider a line that begins with this character
commented, and removes them after the editor returns
@@ -527,6 +528,20 @@ core.commentChar::
+
If set to "auto", `git-commit` would select a character that is not
the beginning character of any line in existing commit messages.
++
+Note that these two variables are aliases of each other, and in modern
+versions of Git you are free to use a string (e.g., `//` or `â‘â•â‘`) with
+`commentChar`. Versions of Git prior to v2.45.0 will ignore
+`commentString` but will reject a value of `commentChar` that consists
+of more than a single ASCII byte. If you plan to use your config with
+older and newer versions of Git, you may want to specify both:
++
+ [core]
+ # single character for older versions
+ commentChar = "#"
+ # string for newer versions (which will override commentChar
+ # because it comes later in the file)
+ commentString = "//"
core.filesRefLockTimeout::
The length of time, in milliseconds, to retry when trying to
@@ -688,7 +703,7 @@ core.createObject::
will not overwrite existing objects.
+
On some file system/operating system combinations, this is unreliable.
-Set this config setting to 'rename' there; However, This will remove the
+Set this config setting to 'rename' there; however, this will remove the
check that makes sure that existing object files will not get overwritten.
core.notesRef::
@@ -736,3 +751,10 @@ core.abbrev::
If set to "no", no abbreviation is made and the object names
are shown in their full length.
The minimum length is 4.
+
+core.maxTreeDepth::
+ The maximum depth Git is willing to recurse while traversing a
+ tree (e.g., "a/b/cde/f" has a depth of 4). This is a fail-safe
+ to allow Git to abort cleanly, and should not generally need to
+ be adjusted. When Git is compiled with MSVC, the default is 512.
+ Otherwise, the default is 2048.
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt
index 512f31876e..470482ff4c 100644
--- a/Documentation/config/credential.txt
+++ b/Documentation/config/credential.txt
@@ -9,6 +9,14 @@ credential.helper::
Note that multiple helpers may be defined. See linkgit:gitcredentials[7]
for details and examples.
+credential.interactive::
+ By default, Git and any configured credential helpers will ask for
+ user input when new credentials are required. Many of these helpers
+ will succeed based on stored credentials if those credentials are
+ still valid. To avoid the possibility of user interactivity from
+ Git, set `credential.interactive=false`. Some credential helpers
+ respect this option as well.
+
credential.useHttpPath::
When acquiring credentials, consider the "path" component of an http
or https URL to be important. Defaults to false. See
@@ -21,7 +29,7 @@ credential.username::
credential.<url>.*::
Any of the credential.* options above can be applied selectively to
- some credentials. For example "credential.https://example.com.username"
+ some credentials. For example, "credential.https://example.com.username"
would set the default username only for https connections to
example.com. See linkgit:gitcredentials[7] for details on how URLs are
matched.
@@ -31,6 +39,6 @@ credentialCache.ignoreSIGHUP::
credentialStore.lockTimeoutMS::
The length of time, in milliseconds, for git-credential-store to retry
- when trying to lock the credentials file. Value 0 means not to retry at
+ when trying to lock the credentials file. A value of 0 means not to retry at
all; -1 means to try indefinitely. Default is 1000 (i.e., retry for
1s).
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt
index 35a7bf86d7..190bda17e5 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.txt
@@ -1,6 +1,6 @@
diff.autoRefreshIndex::
When using 'git diff' to compare with work tree
- files, do not consider stat-only change as changed.
+ files, do not consider stat-only changes as changed.
Instead, silently run `git update-index --refresh` to
update the cached stat information for paths whose
contents in the work tree match the contents in the
@@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files,
and accumulating child directory counts in the parent directories:
`files,10,cumulative`.
+diff.statNameWidth::
+ Limit the width of the filename part in --stat output. If set, applies
+ to all commands generating --stat output except format-patch.
+
diff.statGraphWidth::
Limit the width of the graph part in --stat output. If set, applies
to all commands generating --stat output except format-patch.
@@ -75,6 +79,15 @@ diff.external::
you want to use an external diff program only on a subset of
your files, you might want to use linkgit:gitattributes[5] instead.
+diff.trustExitCode::
+ If this boolean value is set to true then the
+ `diff.external` command is expected to return exit code
+ 0 if it considers the input files to be equal or 1 if it
+ considers them to be different, like `diff(1)`.
+ If it is set to false, which is the default, then the command
+ is expected to return exit code 0 regardless of equality.
+ Any other exit code causes Git to report a fatal error.
+
diff.ignoreSubmodules::
Sets the default value of --ignore-submodules. Note that this
affects only 'git diff' Porcelain, and not lower level 'diff'
@@ -104,9 +117,15 @@ diff.mnemonicPrefix::
`git diff --no-index a b`;;
compares two non-git things (1) and (2).
-diff.noprefix::
+diff.noPrefix::
If set, 'git diff' does not show any source or destination prefix.
+diff.srcPrefix::
+ If set, 'git diff' uses this source prefix. Defaults to "a/".
+
+diff.dstPrefix::
+ If set, 'git diff' uses this destination prefix. Defaults to "b/".
+
diff.relative::
If set to 'true', 'git diff' does not show changes outside of the directory
and show pathnames relative to the current directory.
@@ -154,6 +173,15 @@ diff.<driver>.command::
The custom diff driver command. See linkgit:gitattributes[5]
for details.
+diff.<driver>.trustExitCode::
+ If this boolean value is set to true then the
+ `diff.<driver>.command` command is expected to return exit code
+ 0 if it considers the input files to be equal or 1 if it
+ considers them to be different, like `diff(1)`.
+ If it is set to false, which is the default, then the command
+ is expected to return exit code 0 regardless of equality.
+ Any other exit code causes Git to report a fatal error.
+
diff.<driver>.xfuncname::
The regular expression that the diff driver should use to
recognize the hunk header. A built-in pattern may also be used.
@@ -219,5 +247,5 @@ diff.colorMoved::
diff.colorMovedWS::
When moved lines are colored using e.g. the `diff.colorMoved` setting,
- this option controls the `<mode>` how spaces are treated
- for details of valid modes see '--color-moved-ws' in linkgit:git-diff[1].
+ this option controls the `<mode>` how spaces are treated.
+ For details of valid modes see '--color-moved-ws' in linkgit:git-diff[1].
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt
index bccaec7a96..5dc569d1c9 100644
--- a/Documentation/config/extensions.txt
+++ b/Documentation/config/extensions.txt
@@ -1,13 +1,69 @@
-extensions.objectFormat::
+extensions.*::
+ Unless otherwise stated, is an error to specify an extension if
+ `core.repositoryFormatVersion` is not `1`. See
+ linkgit:gitrepository-layout[5].
++
+--
+compatObjectFormat::
+ Specify a compatibility hash algorithm to use. The acceptable values
+ are `sha1` and `sha256`. The value specified must be different from the
+ value of `extensions.objectFormat`. This allows client level
+ interoperability between git repositories whose objectFormat matches
+ this compatObjectFormat. In particular when fully implemented the
+ pushes and pulls from a repository in whose objectFormat matches
+ compatObjectFormat. As well as being able to use oids encoded in
+ compatObjectFormat in addition to oids encoded with objectFormat to
+ locally specify objects.
+
+noop::
+ This extension does not change git's behavior at all. It is useful only
+ for testing format-1 compatibility.
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+
+noop-v1::
+ This extension does not change git's behavior at all. It is useful only
+ for testing format-1 compatibility.
+
+objectFormat::
Specify the hash algorithm to use. The acceptable values are `sha1` and
- `sha256`. If not specified, `sha1` is assumed. It is an error to specify
- this key unless `core.repositoryFormatVersion` is 1.
+ `sha256`. If not specified, `sha1` is assumed.
+
Note that this setting should only be set by linkgit:git-init[1] or
linkgit:git-clone[1]. Trying to change it after initialization will not
work and will produce hard-to-diagnose issues.
-extensions.worktreeConfig::
+partialClone::
+ When enabled, indicates that the repo was created with a partial clone
+ (or later performed a partial fetch) and that the remote may have
+ omitted sending certain unwanted objects. Such a remote is called a
+ "promisor remote" and it promises that all such omitted objects can
+ be fetched from it in the future.
++
+The value of this key is the name of the promisor remote.
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+
+preciousObjects::
+ If enabled, indicates that objects in the repository MUST NOT be deleted
+ (e.g., by `git-prune` or `git repack -d`).
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+
+refStorage::
+ Specify the ref storage format to use. The acceptable values are:
++
+include::../ref-storage-format.txt[]
+
++
+Note that this setting should only be set by linkgit:git-init[1] or
+linkgit:git-clone[1]. Trying to change it after initialization will not
+work and will produce hard-to-diagnose issues.
+
+worktreeConfig::
If enabled, then worktrees will load config settings from the
`$GIT_DIR/config.worktree` file in addition to the
`$GIT_COMMON_DIR/config` file. Note that `$GIT_COMMON_DIR` and
@@ -17,7 +73,7 @@ extensions.worktreeConfig::
`config.worktree` file will override settings from any other
config files.
+
-When enabling `extensions.worktreeConfig`, you must be careful to move
+When enabling this extension, you must be careful to move
certain values from the common config file to the main working tree's
`config.worktree` file, if present:
+
@@ -25,15 +81,17 @@ certain values from the common config file to the main working tree's
`$GIT_COMMON_DIR/config.worktree`.
* If `core.bare` is true, then it must be moved from `$GIT_COMMON_DIR/config`
to `$GIT_COMMON_DIR/config.worktree`.
+
+
It may also be beneficial to adjust the locations of `core.sparseCheckout`
and `core.sparseCheckoutCone` depending on your desire for customizable
sparse-checkout settings for each worktree. By default, the `git
-sparse-checkout` builtin enables `extensions.worktreeConfig`, assigns
+sparse-checkout` builtin enables this extension, assigns
these config values on a per-worktree basis, and uses the
`$GIT_DIR/info/sparse-checkout` file to specify the sparsity for each
worktree independently. See linkgit:git-sparse-checkout[1] for more
details.
+
-For historical reasons, `extensions.worktreeConfig` is respected
-regardless of the `core.repositoryFormatVersion` setting.
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+--
diff --git a/Documentation/config/fastimport.txt b/Documentation/config/fastimport.txt
index c1166e330d..903677d7ef 100644
--- a/Documentation/config/fastimport.txt
+++ b/Documentation/config/fastimport.txt
@@ -1,8 +1,8 @@
fastimport.unpackLimit::
If the number of objects imported by linkgit:git-fast-import[1]
is below this limit, then the objects will be unpacked into
- loose object files. However if the number of imported objects
- equals or exceeds this limit then the pack will be stored as a
+ loose object files. However, if the number of imported objects
+ equals or exceeds this limit, then the pack will be stored as a
pack. Storing the pack from a fast-import can make the import
operation complete faster, especially on slow filesystems. If
not set, the value of `transfer.unpackLimit` is used instead.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index bf9546fca4..f061b64b74 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -17,6 +17,9 @@ skipping more commits at a time, reducing the number of round trips.
+
* `pack.useBitmapBoundaryTraversal=true` may improve bitmap traversal times by
walking fewer objects.
++
+* `pack.allowPackReuse=multi` may improve the time it takes to create a pack by
+reusing objects from multiple packs instead of just one.
feature.manyFiles::
Enable config options that optimize for repos with many files in the
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index 568f0f75b3..d7dc461bd1 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -50,10 +50,16 @@ fetch.pruneTags::
refs. See also `remote.<name>.pruneTags` and the PRUNING
section of linkgit:git-fetch[1].
+fetch.all::
+ If true, fetch will attempt to update all available remotes.
+ This behavior can be overridden by passing `--no-all` or by
+ explicitly specifying one or more remote(s) to fetch from.
+ Defaults to false.
+
fetch.output::
Control how ref update status is printed. Valid values are
- `full` and `compact`. Default value is `full`. See section
- OUTPUT in linkgit:git-fetch[1] for detail.
+ `full` and `compact`. Default value is `full`. See the
+ OUTPUT section in linkgit:git-fetch[1] for details.
fetch.negotiationAlgorithm::
Control how information about the commits in the local repository
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index 8cf6f00d93..7410e930e5 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -68,7 +68,7 @@ format.encodeEmailHeaders::
Defaults to true.
format.pretty::
- The default pretty format for log/show/whatchanged command,
+ The default pretty format for log/show/whatchanged command.
See linkgit:git-log[1], linkgit:git-show[1],
linkgit:git-whatchanged[1].
@@ -119,7 +119,7 @@ format.notes::
`--notes=<ref>`, where `ref` is the non-boolean value. Defaults
to false.
+
-If one wishes to use the ref `ref/notes/true`, please use that literal
+If one wishes to use the ref `refs/notes/true`, please use that literal
instead.
+
This configuration can be specified multiple times in order to allow
diff --git a/Documentation/config/fsck.txt b/Documentation/config/fsck.txt
index a3c865df56..8e9e508933 100644
--- a/Documentation/config/fsck.txt
+++ b/Documentation/config/fsck.txt
@@ -11,13 +11,13 @@ to clone or fetch it set `fetch.fsck.<msg-id>`.
+
The rest of the documentation discusses `fsck.*` for brevity, but the
same applies for the corresponding `receive.fsck.*` and
-`fetch.<msg-id>.*`. variables.
+`fetch.fsck.*`. variables.
+
-Unlike variables like `color.ui` and `core.editor` the
+Unlike variables like `color.ui` and `core.editor`, the
`receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>` variables will not
fall back on the `fsck.<msg-id>` configuration if they aren't set. To
-uniformly configure the same fsck settings in different circumstances
-all three of them they must all set to the same values.
+uniformly configure the same fsck settings in different circumstances,
+all three of them must be set to the same values.
+
When `fsck.<msg-id>` is set, errors can be switched to warnings and
vice versa by configuring the `fsck.<msg-id>` setting where the
@@ -36,19 +36,19 @@ Setting an unknown `fsck.<msg-id>` value will cause fsck to die, but
doing the same for `receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>`
will only cause git to warn.
+
-See `Fsck Messages` section of linkgit:git-fsck[1] for supported
+See the `Fsck Messages` section of linkgit:git-fsck[1] for supported
values of `<msg-id>`.
fsck.skipList::
The path to a list of object names (i.e. one unabbreviated SHA-1 per
line) that are known to be broken in a non-fatal way and should
- be ignored. On versions of Git 2.20 and later comments ('#'), empty
- lines, and any leading and trailing whitespace is ignored. Everything
+ be ignored. On versions of Git 2.20 and later, comments ('#'), empty
+ lines, and any leading and trailing whitespace are ignored. Everything
but a SHA-1 per line will error out on older versions.
+
This feature is useful when an established project should be accepted
-despite early commits containing errors that can be safely ignored
+despite early commits containing errors that can be safely ignored,
such as invalid committer email addresses. Note: corrupt objects
cannot be skipped with this setting.
+
@@ -58,11 +58,11 @@ Like `fsck.<msg-id>` this variable has corresponding
Unlike variables like `color.ui` and `core.editor` the
`receive.fsck.skipList` and `fetch.fsck.skipList` variables will not
fall back on the `fsck.skipList` configuration if they aren't set. To
-uniformly configure the same fsck settings in different circumstances
-all three of them they must all set to the same values.
+uniformly configure the same fsck settings in different circumstances,
+all three of them must be set to the same values.
+
Older versions of Git (before 2.20) documented that the object names
-list should be sorted. This was never a requirement, the object names
+list should be sorted. This was never a requirement; the object names
could appear in any order, but when reading the list we tracked whether
the list was sorted for the purposes of an internal binary search
implementation, which could save itself some work with an already sorted
diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt
index c225c6c9e7..671f9b9462 100644
--- a/Documentation/config/fsmonitor--daemon.txt
+++ b/Documentation/config/fsmonitor--daemon.txt
@@ -1,5 +1,5 @@
fsmonitor.allowRemote::
- By default, the fsmonitor daemon refuses to work against network-mounted
+ By default, the fsmonitor daemon refuses to work with network-mounted
repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
behavior. Only respected when `core.fsmonitor` is set to `true`.
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt
index ca47eb2008..21d56db279 100644
--- a/Documentation/config/gc.txt
+++ b/Documentation/config/gc.txt
@@ -24,7 +24,7 @@ gc.auto::
default value is 6700.
+
Setting this to 0 disables not only automatic packing based on the
-number of loose objects, but any other heuristic `git gc --auto` will
+number of loose objects, but also any other heuristic `git gc --auto` will
otherwise use to determine if there's work to do, such as
`gc.autoPackLimit`.
@@ -39,8 +39,9 @@ See the `gc.bigPackThreshold` configuration variable below. When in
use, it'll affect how the auto pack limit works.
gc.autoDetach::
- Make `git gc --auto` return immediately and run in background
- if the system supports it. Default is true.
+ Make `git gc --auto` return immediately and run in the background
+ if the system supports it. Default is true. This config variable acts
+ as a fallback in case `maintenance.autoDetach` is not set.
gc.bigPackThreshold::
If non-zero, all non-cruft packs larger than this limit are kept
@@ -86,6 +87,12 @@ gc.cruftPacks::
linkgit:git-repack[1]) instead of as loose objects. The default
is `true`.
+gc.maxCruftSize::
+ Limit the size of new cruft packs when repacking. When
+ specified in addition to `--max-cruft-size`, the command line
+ option takes priority. See the `--max-cruft-size` option of
+ linkgit:git-repack[1].
+
gc.pruneExpire::
When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
(and 'repack --cruft --cruft-expiration 2.weeks.ago' if using
@@ -145,6 +152,22 @@ Multiple hooks are supported, but all must exit successfully, else the
operation (either generating a cruft pack or unpacking unreachable
objects) will be halted.
+gc.repackFilter::
+ When repacking, use the specified filter to move certain
+ objects into a separate packfile. See the
+ `--filter=<filter-spec>` option of linkgit:git-repack[1].
+
+gc.repackFilterTo::
+ When repacking and using a filter, see `gc.repackFilter`, the
+ specified location will be used to create the packfile
+ containing the filtered out objects. **WARNING:** The
+ specified location should be accessible, using for example the
+ Git alternates mechanism, otherwise the repo could be
+ considered corrupt by Git as it might not be able to access the
+ objects in that packfile. See the `--filter-to=<dir>` option
+ of linkgit:git-repack[1] and the `objects/info/alternates`
+ section of linkgit:gitrepository-layout[5].
+
gc.rerereResolved::
Records of conflicted merge you resolved earlier are
kept for this many days when 'git rerere gc' is run.
diff --git a/Documentation/config/gpg.txt b/Documentation/config/gpg.txt
index 37e2831cd5..5cf32b179d 100644
--- a/Documentation/config/gpg.txt
+++ b/Documentation/config/gpg.txt
@@ -4,7 +4,7 @@ gpg.program::
same command-line interface as GPG, namely, to verify a detached
signature, "`gpg --verify $signature - <$file`" is run, and the
program is expected to signal a good signature by exiting with
- code 0, and to generate an ASCII-armored detached signature, the
+ code 0. To generate an ASCII-armored detached signature, the
standard input of "`gpg -bsau $key`" is fed with the contents to be
signed, and the program is expected to send the result to its
standard output.
@@ -25,7 +25,7 @@ gpg.<format>.program::
gpg.minTrustLevel::
Specifies a minimum trust level for signature verification. If
this option is unset, then signature verification for merge
- operations require a key with at least `marginal` trust. Other
+ operations requires a key with at least `marginal` trust. Other
operations that perform signature verification require a key
with at least `undefined` trust. Setting this option overrides
the required trust-level for all operations. Supported values,
@@ -38,7 +38,7 @@ gpg.minTrustLevel::
* `ultimate`
gpg.ssh.defaultKeyCommand::
- This command that will be run when user.signingkey is not set and a ssh
+ This command will be run when user.signingkey is not set and a ssh
signature is requested. On successful exit a valid ssh public key
prefixed with `key::` is expected in the first line of its output.
This allows for a script doing a dynamic lookup of the correct public
diff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt
index e521f20390..10041f27b0 100644
--- a/Documentation/config/grep.txt
+++ b/Documentation/config/grep.txt
@@ -24,5 +24,5 @@ grep.fullName::
If set to true, enable `--full-name` option by default.
grep.fallbackToNoIndex::
- If set to true, fall back to git grep --no-index if git grep
+ If set to true, fall back to `git grep --no-index` if `git grep`
is executed outside of a git repository. Defaults to false.
diff --git a/Documentation/config/gui.txt b/Documentation/config/gui.txt
index 0c087fd8c9..171be774d2 100644
--- a/Documentation/config/gui.txt
+++ b/Documentation/config/gui.txt
@@ -24,7 +24,7 @@ gui.matchTrackingBranch::
not. Default: "false".
gui.newBranchTemplate::
- Is used as suggested name when creating new branches using the
+ Is used as a suggested name when creating new branches using the
linkgit:git-gui[1].
gui.pruneDuringFetch::
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index 51a70781e5..a14371b5c9 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -5,8 +5,13 @@ http.proxy::
proxy string with a user name but no password, in which case git will
attempt to acquire one in the same way it does for other credentials. See
linkgit:gitcredentials[7] for more information. The syntax thus is
- '[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden
- on a per-remote basis; see remote.<name>.proxy
+ '[protocol://][user[:password]@]proxyhost[:port][/path]'. This can be
+ overridden on a per-remote basis; see remote.<name>.proxy
++
+Any proxy, however configured, must be completely transparent and must not
+modify, transform, or buffer the request or response in any way. Proxies which
+are not completely transparent are known to cause various forms of breakage
+with Git.
http.proxyAuthMethod::
Set the method with which to authenticate against the HTTP proxy. This
@@ -56,6 +61,26 @@ http.emptyAuth::
a username in the URL, as libcurl normally requires a username for
authentication.
+http.proactiveAuth::
+ Attempt authentication without first making an unauthenticated attempt and
+ receiving a 401 response. This can be used to ensure that all requests are
+ authenticated. If `http.emptyAuth` is set to true, this value has no effect.
++
+If the credential helper used specifies an authentication scheme (i.e., via the
+`authtype` field), that value will be used; if a username and password is
+provided without a scheme, then Basic authentication is used. The value of the
+option determines the scheme requested from the helper. Possible values are:
++
+--
+* `basic` - Request Basic authentication from the helper.
+* `auto` - Allow the helper to pick an appropriate scheme.
+* `none` - Disable proactive authentication.
+--
++
+Note that TLS should always be used with this configuration, since otherwise it
+is easy to accidentally expose plaintext credentials if Basic authentication
+is selected.
+
http.delegation::
Control GSSAPI credential delegation. The delegation is disabled
by default in libcurl since version 7.21.7. Set parameter to tell
@@ -82,12 +107,16 @@ http.cookieFile::
in the Git http session, if they match the server. The file format
of the file to read cookies from should be plain HTTP headers or
the Netscape/Mozilla cookie file format (see `curl(1)`).
+ Set it to an empty string, to accept only new cookies from
+ the server and send them back in successive requests within same
+ connection.
NOTE that the file specified with http.cookieFile is used only as
input unless http.saveCookies is set.
http.saveCookies::
If set, store cookies received during requests to the file specified by
- http.cookieFile. Has no effect if http.cookieFile is unset.
+ http.cookieFile. Has no effect if http.cookieFile is unset, or set to
+ an empty string.
http.version::
Use the specified HTTP protocol version when communicating with a server.
@@ -254,13 +283,13 @@ http.lowSpeedLimit, http.lowSpeedTime::
http.noEPSV::
A boolean which disables using of EPSV ftp command by curl.
- This can helpful with some "poor" ftp servers which don't
+ This can be helpful with some "poor" ftp servers which don't
support EPSV mode. Can be overridden by the `GIT_CURL_FTP_NO_EPSV`
environment variable. Default is false (curl will use EPSV).
http.userAgent::
The HTTP USER_AGENT string presented to an HTTP server. The default
- value represents the version of the client Git such as git/1.7.1.
+ value represents the version of the Git client such as git/1.7.1.
This option allows you to override this value to a more common value
such as Mozilla/4.0. This may be necessary, for instance, if
connecting through a firewall that restricts HTTP connections to a set
diff --git a/Documentation/config/i18n.txt b/Documentation/config/i18n.txt
index cc25621731..6e72fdb45b 100644
--- a/Documentation/config/i18n.txt
+++ b/Documentation/config/i18n.txt
@@ -2,7 +2,7 @@ i18n.commitEncoding::
Character encoding the commit messages are stored in; Git itself
does not care per se, but this information is necessary e.g. when
importing commits from emails or in the gitk graphical history
- browser (and possibly at other places in the future or in other
+ browser (and possibly in other places in the future or in other
porcelains). See e.g. linkgit:git-mailinfo[1]. Defaults to 'utf-8'.
i18n.logOutputEncoding::
diff --git a/Documentation/config/imap.txt b/Documentation/config/imap.txt
index 06166fb5c0..3d28f72643 100644
--- a/Documentation/config/imap.txt
+++ b/Documentation/config/imap.txt
@@ -4,7 +4,7 @@ imap.folder::
"[Gmail]/Drafts". Required.
imap.tunnel::
- Command used to setup a tunnel to the IMAP server through which
+ Command used to set up a tunnel to the IMAP server through which
commands will be piped instead of using a direct network connection
to the server. Required when imap.host is not set.
@@ -37,7 +37,7 @@ imap.preformattedHTML::
format=fixed email. Default is `false`.
imap.authMethod::
- Specify authenticate method for authentication with IMAP server.
+ Specify the authentication method for authenticating with the IMAP server.
If Git was built with the NO_CURL option, or if your curl version is older
than 7.34.0, or if you're running git-imap-send with the `--no-curl`
option, the only supported method is 'CRAM-MD5'. If this is not set
diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt
index 23c7985eb4..3eff420360 100644
--- a/Documentation/config/index.txt
+++ b/Documentation/config/index.txt
@@ -23,7 +23,7 @@ index.threads::
Specifies the number of threads to spawn when loading the index.
This is meant to reduce index load time on multiprocessor machines.
Specifying 0 or 'true' will cause Git to auto-detect the number of
- CPU's and set the number of threads accordingly. Specifying 1 or
+ CPUs and set the number of threads accordingly. Specifying 1 or
'false' will disable multithreading. Defaults to 'true'.
index.version::
diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt
index 79c79d6617..e45b2a8121 100644
--- a/Documentation/config/init.txt
+++ b/Documentation/config/init.txt
@@ -1,7 +1,20 @@
-init.templateDir::
- Specify the directory from which templates will be copied.
- (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+:see-git-init:
+ifndef::git-init[]
+:see-git-init: (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+endif::[]
-init.defaultBranch::
+`init.templateDir`::
+ Specify the directory from which templates will be copied. {see-git-init}
+`init.defaultBranch`::
Allows overriding the default branch name e.g. when initializing
a new repository.
+`init.defaultObjectFormat`::
+ Allows overriding the default object format for new repositories. See
+ `--object-format=` in linkgit:git-init[1]. Both the command line option
+ and the `GIT_DEFAULT_HASH` environment variable take precedence over
+ this config.
+`init.defaultRefFormat`::
+ Allows overriding the default ref storage format for new repositories.
+ See `--ref-format=` in linkgit:git-init[1]. Both the command line
+ option and the `GIT_DEFAULT_REF_FORMAT` environment variable take
+ precedence over this config.
diff --git a/Documentation/config/interactive.txt b/Documentation/config/interactive.txt
index a2d3c7ec44..8b876cb4eb 100644
--- a/Documentation/config/interactive.txt
+++ b/Documentation/config/interactive.txt
@@ -1,12 +1,10 @@
interactive.singleKey::
- In interactive commands, allow the user to provide one-letter
- input with a single key (i.e., without hitting enter).
- Currently this is used by the `--patch` mode of
- linkgit:git-add[1], linkgit:git-checkout[1],
+ When set to true, allow the user to provide one-letter input
+ with a single key (i.e., without hitting the Enter key) in
+ interactive commands. This is currently used by the `--patch`
+ mode of linkgit:git-add[1], linkgit:git-checkout[1],
linkgit:git-restore[1], linkgit:git-commit[1],
- linkgit:git-reset[1], and linkgit:git-stash[1]. Note that this
- setting is silently ignored if portable keystroke input
- is not available; requires the Perl module Term::ReadKey.
+ linkgit:git-reset[1], and linkgit:git-stash[1].
interactive.diffFilter::
When an interactive command (such as `git add --patch`) shows
diff --git a/Documentation/config/log.txt b/Documentation/config/log.txt
index 5f96cf87fb..9003a82191 100644
--- a/Documentation/config/log.txt
+++ b/Documentation/config/log.txt
@@ -9,7 +9,7 @@ log.date::
`--date` option. See linkgit:git-log[1] for details.
+
If the format is set to "auto:foo" and the pager is in use, format
-"foo" will be the used for the date format. Otherwise "default" will
+"foo" will be used for the date format. Otherwise, "default" will
be used.
log.decorate::
diff --git a/Documentation/config/mailinfo.txt b/Documentation/config/mailinfo.txt
index 3854d4ae37..ec3a5d81f7 100644
--- a/Documentation/config/mailinfo.txt
+++ b/Documentation/config/mailinfo.txt
@@ -1,6 +1,6 @@
mailinfo.scissors::
If true, makes linkgit:git-mailinfo[1] (and therefore
linkgit:git-am[1]) act by default as if the --scissors option
- was provided on the command-line. When active, this features
+ was provided on the command-line. When active, this feature
removes everything from the message body before a scissors
line (i.e. consisting mainly of ">8", "8<" and "-").
diff --git a/Documentation/config/maintenance.txt b/Documentation/config/maintenance.txt
index 18f0562131..72a9d6cf81 100644
--- a/Documentation/config/maintenance.txt
+++ b/Documentation/config/maintenance.txt
@@ -3,6 +3,17 @@ maintenance.auto::
`git maintenance run --auto` after doing their normal work. Defaults
to true.
+maintenance.autoDetach::
+ Many Git commands trigger automatic maintenance after they have
+ written data into the repository. This boolean config option
+ controls whether this automatic maintenance shall happen in the
+ foreground or whether the maintenance process shall detach and
+ continue to run in the background.
++
+If unset, the value of `gc.autoDetach` is used as a fallback. Defaults
+to true if both are unset, meaning that the maintenance process will
+detach.
+
maintenance.strategy::
This string config option provides a way to specify one of a few
recommended schedules for background maintenance. This only affects
@@ -12,7 +23,7 @@ maintenance.strategy::
then that value is used instead of the one provided by
`maintenance.strategy`. The possible strategy strings are:
+
-* `none`: This default setting implies no task are run at any schedule.
+* `none`: This default setting implies no tasks are run at any schedule.
* `incremental`: This setting optimizes for performing small maintenance
activities that do not delete any data. This does not schedule the `gc`
task, but runs the `prefetch` and `commit-graph` tasks hourly, the
diff --git a/Documentation/config/man.txt b/Documentation/config/man.txt
index a727d987a8..5a0f82cc23 100644
--- a/Documentation/config/man.txt
+++ b/Documentation/config/man.txt
@@ -5,7 +5,7 @@ man.viewer::
man.<tool>.cmd::
Specify the command to invoke the specified man viewer. The
specified command is evaluated in shell with the man page
- passed as argument. (See linkgit:git-help[1].)
+ passed as an argument. (See linkgit:git-help[1].)
man.<tool>.path::
Override the path for the given tool that may be used to
diff --git a/Documentation/config/merge.txt b/Documentation/config/merge.txt
index 99e83dd36e..8851b6cede 100644
--- a/Documentation/config/merge.txt
+++ b/Documentation/config/merge.txt
@@ -7,7 +7,7 @@ merge.conflictStyle::
marker and the original text before the `=======` marker. The
"merge" style tends to produce smaller conflict regions than diff3,
both because of the exclusion of the original text, and because
- when a subset of lines match on the two sides they are just pulled
+ when a subset of lines match on the two sides, they are just pulled
out of the conflict region. Another alternate style, "zdiff3", is
similar to diff3 but removes matching lines on the two sides from
the conflict region when those matching lines appear near either
diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.txt
index 56a7eeeffb..00bf665aa0 100644
--- a/Documentation/config/mergetool.txt
+++ b/Documentation/config/mergetool.txt
@@ -22,8 +22,8 @@ mergetool.<tool>.trustExitCode::
For a custom merge command, specify whether the exit code of
the merge command can be used to determine whether the merge was
successful. If this is not set to true then the merge target file
- timestamp is checked and the merge assumed to have been successful
- if the file has been updated, otherwise the user is prompted to
+ timestamp is checked, and the merge is assumed to have been successful
+ if the file has been updated; otherwise, the user is prompted to
indicate the success of the merge.
mergetool.meld.hasOutput::
@@ -37,7 +37,7 @@ mergetool.meld.hasOutput::
mergetool.meld.useAutoMerge::
When the `--auto-merge` is given, meld will merge all non-conflicting
- parts automatically, highlight the conflicting parts and wait for
+ parts automatically, highlight the conflicting parts, and wait for
user decision. Setting `mergetool.meld.useAutoMerge` to `true` tells
Git to unconditionally use the `--auto-merge` option with `meld`.
Setting this value to `auto` makes git detect whether `--auto-merge`
@@ -45,17 +45,24 @@ mergetool.meld.useAutoMerge::
value of `false` avoids using `--auto-merge` altogether, and is the
default value.
-mergetool.vimdiff.layout::
- The vimdiff backend uses this variable to control how its split
- windows look like. Applies even if you are using Neovim (`nvim`) or
- gVim (`gvim`) as the merge tool. See BACKEND SPECIFIC HINTS section
+mergetool.<vimdiff variant>.layout::
+ Configure the split window layout for vimdiff's `<variant>`, which is any of `vimdiff`,
+ `nvimdiff`, `gvimdiff`.
+ Upon launching `git mergetool` with `--tool=<variant>` (or without `--tool`
+ if `merge.tool` is configured as `<variant>`), Git will consult
+ `mergetool.<variant>.layout` to determine the tool's layout. If the
+ variant-specific configuration is not available, `vimdiff`'s is used as
+ fallback. If that too is not available, a default layout with 4 windows
+ will be used. To configure the layout, see the `BACKEND SPECIFIC HINTS`
+ifdef::git-mergetool[]
+ section.
+endif::[]
ifndef::git-mergetool[]
- in linkgit:git-mergetool[1].
+ section in linkgit:git-mergetool[1].
endif::[]
- for details.
mergetool.hideResolved::
- During a merge Git will automatically resolve as many conflicts as
+ During a merge, Git will automatically resolve as many conflicts as
possible and write the 'MERGED' file containing conflict markers around
any conflicts that it cannot resolve; 'LOCAL' and 'REMOTE' normally
represent the versions of the file from before Git's conflict
@@ -74,7 +81,7 @@ mergetool.keepTemporaries::
When invoking a custom merge tool, Git uses a set of temporary
files to pass to the tool. If the tool returns an error and this
variable is set to `true`, then these temporary files will be
- preserved, otherwise they will be removed after the tool has
+ preserved; otherwise, they will be removed after the tool has
exited. Defaults to `false`.
mergetool.writeToTemp::
diff --git a/Documentation/config/notes.txt b/Documentation/config/notes.txt
index c7c4811734..43db8e808d 100644
--- a/Documentation/config/notes.txt
+++ b/Documentation/config/notes.txt
@@ -1,7 +1,7 @@
notes.mergeStrategy::
Which merge strategy to choose by default when resolving notes
conflicts. Must be one of `manual`, `ours`, `theirs`, `union`, or
- `cat_sort_uniq`. Defaults to `manual`. See "NOTES MERGE STRATEGIES"
+ `cat_sort_uniq`. Defaults to `manual`. See the "NOTES MERGE STRATEGIES"
section of linkgit:git-notes[1] for more information on each strategy.
+
This setting can be overridden by passing the `--strategy` option to
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt
index 3748136d14..da527377fa 100644
--- a/Documentation/config/pack.txt
+++ b/Documentation/config/pack.txt
@@ -28,11 +28,16 @@ all existing objects. You can force recompression by passing the -F option
to linkgit:git-repack[1].
pack.allowPackReuse::
- When true, and when reachability bitmaps are enabled,
- pack-objects will try to send parts of the bitmapped packfile
- verbatim. This can reduce memory and CPU usage to serve fetches,
- but might result in sending a slightly larger pack. Defaults to
- true.
+ When true or "single", and when reachability bitmaps are
+ enabled, pack-objects will try to send parts of the bitmapped
+ packfile verbatim. When "multi", and when a multi-pack
+ reachability bitmap is available, pack-objects will try to send
+ parts of all packs in the MIDX.
++
+If only a single pack bitmap is available, and `pack.allowPackReuse`
+is set to "multi", reuse parts of just the bitmapped packfile. This
+can reduce memory and CPU usage to serve fetches, but might result in
+sending a slightly larger pack. Defaults to true.
pack.island::
An extended regular expression configuring a set of delta
@@ -74,7 +79,7 @@ pack.threads::
warning. This is meant to reduce packing time on multiprocessor
machines. The required amount of memory for the delta search window
is however multiplied by the number of threads.
- Specifying 0 will cause Git to auto-detect the number of CPU's
+ Specifying 0 will cause Git to auto-detect the number of CPUs
and set the number of threads accordingly.
pack.indexVersion::
@@ -83,11 +88,11 @@ pack.indexVersion::
the new pack index with capabilities for packs larger than 4 GB
as well as proper protection against the repacking of corrupted
packs. Version 2 is the default. Note that version 2 is enforced
- and this config option ignored whenever the corresponding pack is
+ and this config option is ignored whenever the corresponding pack is
larger than 2 GB.
+
If you have an old Git that does not understand the version 2 `*.idx` file,
-cloning or fetching over a non native protocol (e.g. "http")
+cloning or fetching over a non-native protocol (e.g. "http")
that will copy both `*.pack` file and corresponding `*.idx` file from the
other side may give you a repository that cannot be accessed with your
older version of Git. If the `*.pack` file is smaller than 2 GB, however,
@@ -102,8 +107,8 @@ pack.packSizeLimit::
in the creation of multiple packfiles.
+
Note that this option is rarely useful, and may result in a larger total
-on-disk size (because Git will not store deltas between packs), as well
-as worse runtime performance (object lookup within multiple packs is
+on-disk size (because Git will not store deltas between packs) and
+worse runtime performance (object lookup within multiple packs is
slower than a single pack, and optimizations like reachability bitmaps
cannot cope with multiple packs).
+
diff --git a/Documentation/config/promisor.txt b/Documentation/config/promisor.txt
new file mode 100644
index 0000000000..98c5cb2ec2
--- /dev/null
+++ b/Documentation/config/promisor.txt
@@ -0,0 +1,3 @@
+promisor.quiet::
+ If set to "true" assume `--quiet` when fetching additional
+ objects for a partial clone.
diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt
index 43338b65e8..0acbbea18a 100644
--- a/Documentation/config/push.txt
+++ b/Documentation/config/push.txt
@@ -35,7 +35,7 @@ push.default::
* `tracking` - This is a deprecated synonym for `upstream`.
-* `simple` - pushes the current branch with the same name on the remote.
+* `simple` - push the current branch with the same name on the remote.
+
If you are working on a centralized workflow (pushing to the same repository you
pull from, which is typically `origin`), then you need to configure an upstream
@@ -67,7 +67,7 @@ new default).
--
push.followTags::
- If set to true enable `--follow-tags` option by default. You
+ If set to true, enable `--follow-tags` option by default. You
may override this configuration at time of push by specifying
`--no-follow-tags`.
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 9c248accec..c6187ab28b 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -9,7 +9,9 @@ rebase.stat::
rebase. False by default.
rebase.autoSquash::
- If set to true enable `--autosquash` option by default.
+ If set to true, enable the `--autosquash` option of
+ linkgit:git-rebase[1] by default for interactive mode.
+ This can be overridden with the `--no-autosquash` option.
rebase.autoStash::
When set to true, automatically create a temporary stash entry
@@ -38,7 +40,7 @@ rebase.missingCommitsCheck::
rebase.instructionFormat::
A format string, as specified in linkgit:git-log[1], to be used for the
todo list during an interactive rebase. The format will
- automatically have the long commit hash prepended to the format.
+ automatically have the commit hash prepended to the format.
rebase.abbreviateCommands::
If set to true, `git rebase` will use abbreviated command names in the
diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt
index 85d5b5a3d2..36a1e6f2d2 100644
--- a/Documentation/config/receive.txt
+++ b/Documentation/config/receive.txt
@@ -8,18 +8,18 @@ receive.advertisePushOptions::
capability to its clients. False by default.
receive.autogc::
- By default, git-receive-pack will run "git-gc --auto" after
+ By default, git-receive-pack will run "git maintenance run --auto" after
receiving data from git-push and updating refs. You can stop
it by setting this variable to false.
receive.certNonceSeed::
By setting this variable to a string, `git receive-pack`
- will accept a `git push --signed` and verifies it by using
+ will accept a `git push --signed` and verify it by using
a "nonce" protected by HMAC using this string as a secret
key.
receive.certNonceSlop::
- When a `git push --signed` sent a push certificate with a
+ When a `git push --signed` sends a push certificate with a
"nonce" that was issued by a receive-pack serving the same
repository within this many seconds, export the "nonce"
found in the certificate to `GIT_PUSH_CERT_NONCE` to the
diff --git a/Documentation/config/reftable.txt b/Documentation/config/reftable.txt
new file mode 100644
index 0000000000..57087803a5
--- /dev/null
+++ b/Documentation/config/reftable.txt
@@ -0,0 +1,56 @@
+reftable.blockSize::
+ The size in bytes used by the reftable backend when writing blocks.
+ The block size is determined by the writer, and does not have to be a
+ power of 2. The block size must be larger than the longest reference
+ name or log entry used in the repository, as references cannot span
+ blocks.
++
+Powers of two that are friendly to the virtual memory system or
+filesystem (such as 4kB or 8kB) are recommended. Larger sizes (64kB) can
+yield better compression, with a possible increased cost incurred by
+readers during access.
++
+The largest block size is `16777215` bytes (15.99 MiB). The default value is
+`4096` bytes (4kB). A value of `0` will use the default value.
+
+reftable.restartInterval::
+ The interval at which to create restart points. The reftable backend
+ determines the restart points at file creation. Every 16 may be
+ more suitable for smaller block sizes (4k or 8k), every 64 for larger
+ block sizes (64k).
++
+More frequent restart points reduces prefix compression and increases
+space consumed by the restart table, both of which increase file size.
++
+Less frequent restart points makes prefix compression more effective,
+decreasing overall file size, with increased penalties for readers
+walking through more records after the binary search step.
++
+A maximum of `65535` restart points per block is supported.
++
+The default value is to create restart points every 16 records. A value of `0`
+will use the default value.
+
+reftable.indexObjects::
+ Whether the reftable backend shall write object blocks. Object blocks
+ are a reverse mapping of object ID to the references pointing to them.
++
+The default value is `true`.
+
+reftable.geometricFactor::
+ Whenever the reftable backend appends a new table to the stack, it
+ performs auto compaction to ensure that there is only a handful of
+ tables. The backend does this by ensuring that tables form a geometric
+ sequence regarding the respective sizes of each table.
++
+By default, the geometric sequence uses a factor of 2, meaning that for any
+table, the next-biggest table must at least be twice as big. A maximum factor
+of 256 is supported.
+
+reftable.lockTimeout::
+ Whenever the reftable backend appends a new table to the stack, it has
+ to lock the central "tables.list" file before updating it. This config
+ controls how long the process will wait to acquire the lock in case
+ another process has already acquired it. Value 0 means not to retry at
+ all; -1 means to try indefinitely. Default is 100 (i.e., retry for
+ 100ms).
diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt
index 0678b4bcfe..6d8b7d6c63 100644
--- a/Documentation/config/remote.txt
+++ b/Documentation/config/remote.txt
@@ -5,10 +5,19 @@ remote.pushDefault::
remote.<name>.url::
The URL of a remote repository. See linkgit:git-fetch[1] or
- linkgit:git-push[1].
+ linkgit:git-push[1]. A configured remote can have multiple URLs;
+ in this case the first is used for fetching, and all are used
+ for pushing (assuming no `remote.<name>.pushurl` is defined).
+ Setting this key to the empty string clears the list of urls,
+ allowing you to override earlier config.
remote.<name>.pushurl::
The push URL of a remote repository. See linkgit:git-push[1].
+ If a `pushurl` option is present in a configured remote, it
+ is used for pushing instead of `remote.<name>.url`. A configured
+ remote can have multiple push URLs; in this case a push goes to
+ all of them. Setting this key to the empty string clears the
+ list of urls, allowing you to override earlier config.
remote.<name>.proxy::
For remotes that require curl (http, https and ftp), the URL to
@@ -33,14 +42,15 @@ remote.<name>.mirror::
as if the `--mirror` option was given on the command line.
remote.<name>.skipDefaultUpdate::
- If true, this remote will be skipped by default when updating
- using linkgit:git-fetch[1] or the `update` subcommand of
- linkgit:git-remote[1].
+ A deprecated synonym to `remote.<name>.skipFetchAll` (if
+ both are set in the configuration files with different
+ values, the value of the last occurrence will be used).
remote.<name>.skipFetchAll::
- If true, this remote will be skipped by default when updating
- using linkgit:git-fetch[1] or the `update` subcommand of
- linkgit:git-remote[1].
+ If true, this remote will be skipped when updating
+ using linkgit:git-fetch[1], the `update` subcommand of
+ linkgit:git-remote[1], and ignored by the prefetch task
+ of `git maintenance`.
remote.<name>.receivepack::
The default program to execute on the remote side when pushing. See
@@ -86,3 +96,13 @@ remote.<name>.partialclonefilter::
Changing or clearing this value will only affect fetches for new commits.
To fetch associated objects for commits already present in the local object
database, use the `--refetch` option of linkgit:git-fetch[1].
+
+remote.<name>.serverOption::
+ The default set of server options used when fetching from this remote.
+ These server options can be overridden by the `--server-option=` command
+ line arguments.
++
+This is a multi-valued variable, and an empty value can be used in a higher
+priority configuration file (e.g. `.git/config` in a repository) to clear
+the values inherited from a lower priority configuration files (e.g.
+`$HOME/.gitconfig`).
diff --git a/Documentation/config/rerere.txt b/Documentation/config/rerere.txt
index 40abdf6a6b..3a78b5ebb1 100644
--- a/Documentation/config/rerere.txt
+++ b/Documentation/config/rerere.txt
@@ -1,7 +1,7 @@
rerere.autoUpdate::
When set to true, `git-rerere` updates the index with the
resulting contents after it cleanly resolves conflicts using
- previously recorded resolution. Defaults to false.
+ previously recorded resolutions. Defaults to false.
rerere.enabled::
Activate recording of resolved conflicts, so that identical
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
index bde7f31459..2d45c98b12 100644
--- a/Documentation/config/safe.txt
+++ b/Documentation/config/safe.txt
@@ -14,7 +14,7 @@ repository that contains a bare repository and running a Git command
within that directory.
+
This config setting is only respected in protected configuration (see
-<<SCOPES>>). This prevents the untrusted repository from tampering with
+<<SCOPES>>). This prevents untrusted repositories from tampering with
this value.
safe.directory::
@@ -32,7 +32,7 @@ override any such directories specified in the system config), add a
`safe.directory` entry with an empty value.
+
This config setting is only respected in protected configuration (see
-<<SCOPES>>). This prevents the untrusted repository from tampering with this
+<<SCOPES>>). This prevents untrusted repositories from tampering with this
value.
+
The value of this setting is interpolated, i.e. `~/<path>` expands to a
@@ -44,7 +44,8 @@ string `*`. This will allow all repositories to be treated as if their
directory was listed in the `safe.directory` list. If `safe.directory=*`
is set in system config and you want to re-enable this protection, then
initialize your list with an empty value before listing the repositories
-that you deem safe.
+that you deem safe. Giving a directory with `/*` appended to it will
+allow access to all repositories under the named directory.
+
As explained, Git only allows you to access repositories owned by
yourself, i.e. the user who is running Git, by default. When Git
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt
index 92a9ebe98c..5ffcfc9f2a 100644
--- a/Documentation/config/sendemail.txt
+++ b/Documentation/config/sendemail.txt
@@ -8,7 +8,7 @@ sendemail.smtpEncryption::
See linkgit:git-send-email[1] for description. Note that this
setting is not subject to the 'identity' mechanism.
-sendemail.smtpsslcertpath::
+sendemail.smtpSSLCertPath::
Path to ca-certificates (either a directory or a single file).
Set it to an empty string to disable certificate verification.
@@ -30,13 +30,28 @@ sendemail.confirm::
in the linkgit:git-send-email[1] documentation for the meaning of these
values.
+sendemail.mailmap::
+ If true, makes linkgit:git-send-email[1] assume `--mailmap`,
+ otherwise assume `--no-mailmap`. False by default.
+
+sendemail.mailmap.file::
+ The location of a linkgit:git-send-email[1] specific augmenting
+ mailmap file. The default mailmap and `mailmap.file` are loaded
+ first. Thus, entries in this file take precedence over entries in
+ the default mailmap locations. See linkgit:gitmailmap[5].
+
+sendemail.mailmap.blob::
+ Like `sendemail.mailmap.file`, but consider the value as a reference
+ to a blob in the repository. Entries in `sendemail.mailmap.file`
+ take precedence over entries here. See linkgit:gitmailmap[5].
+
sendemail.aliasesFile::
To avoid typing long email addresses, point this to one or more
email aliases files. You must also supply `sendemail.aliasFileType`.
sendemail.aliasFileType::
Format of the file(s) specified in sendemail.aliasesFile. Must be
- one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus', or 'sendmail'.
+ one of 'mutt', 'mailrc', 'pine', 'elm', 'gnus', or 'sendmail'.
+
What an alias file in each format looks like can be found in
the documentation of the email program of the same name. The
@@ -62,12 +77,12 @@ sendemail.chainReplyTo::
sendemail.envelopeSender::
sendemail.from::
sendemail.headerCmd::
-sendemail.signedoffbycc::
+sendemail.signedOffByCc::
sendemail.smtpPass::
-sendemail.suppresscc::
+sendemail.suppressCc::
sendemail.suppressFrom::
sendemail.to::
-sendemail.tocmd::
+sendemail.toCmd::
sendemail.smtpDomain::
sendemail.smtpServer::
sendemail.smtpServerPort::
@@ -81,8 +96,8 @@ sendemail.xmailer::
linkgit:git-send-email[1] command-line options. See its
documentation for details.
-sendemail.signedoffcc (deprecated)::
- Deprecated alias for `sendemail.signedoffbycc`.
+sendemail.signedOffCc (deprecated)::
+ Deprecated alias for `sendemail.signedOffByCc`.
sendemail.smtpBatchSize::
Number of messages to be sent per connection, after that a relogin
@@ -91,7 +106,7 @@ sendemail.smtpBatchSize::
See also the `--batch-size` option of linkgit:git-send-email[1].
sendemail.smtpReloginDelay::
- Seconds wait before reconnecting to smtp server.
+ Seconds to wait before reconnecting to the smtp server.
See also the `--relogin-delay` option of linkgit:git-send-email[1].
sendemail.forbidSendmailVariables::
diff --git a/Documentation/config/sequencer.txt b/Documentation/config/sequencer.txt
index b48d532a96..e664eef01d 100644
--- a/Documentation/config/sequencer.txt
+++ b/Documentation/config/sequencer.txt
@@ -2,4 +2,4 @@ sequence.editor::
Text editor used by `git rebase -i` for editing the rebase instruction file.
The value is meant to be interpreted by the shell when it is used.
It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable.
- When not configured the default commit message editor is used instead.
+ When not configured, the default commit message editor is used instead.
diff --git a/Documentation/config/splitindex.txt b/Documentation/config/splitindex.txt
index afdb186df8..cfaa29610b 100644
--- a/Documentation/config/splitindex.txt
+++ b/Documentation/config/splitindex.txt
@@ -3,10 +3,10 @@ splitIndex.maxPercentChange::
percent of entries the split index can contain compared to the
total number of entries in both the split index and the shared
index before a new shared index is written.
- The value should be between 0 and 100. If the value is 0 then
- a new shared index is always written, if it is 100 a new
+ The value should be between 0 and 100. If the value is 0, then
+ a new shared index is always written; if it is 100, a new
shared index is never written.
- By default the value is 20, so a new shared index is written
+ By default, the value is 20, so a new shared index is written
if the number of entries in the split index would be greater
than 20 percent of the total number of entries.
See linkgit:git-update-index[1].
diff --git a/Documentation/config/stash.txt b/Documentation/config/stash.txt
index b9f609ed76..ec1edaeba6 100644
--- a/Documentation/config/stash.txt
+++ b/Documentation/config/stash.txt
@@ -1,14 +1,14 @@
stash.showIncludeUntracked::
If this is set to true, the `git stash show` command will show
the untracked files of a stash entry. Defaults to false. See
- description of 'show' command in linkgit:git-stash[1].
+ the description of the 'show' command in linkgit:git-stash[1].
stash.showPatch::
If this is set to true, the `git stash show` command without an
option will show the stash entry in patch form. Defaults to false.
- See description of 'show' command in linkgit:git-stash[1].
+ See the description of the 'show' command in linkgit:git-stash[1].
stash.showStat::
If this is set to true, the `git stash show` command without an
- option will show diffstat of the stash entry. Defaults to true.
- See description of 'show' command in linkgit:git-stash[1].
+ option will show a diffstat of the stash entry. Defaults to true.
+ See the description of the 'show' command in linkgit:git-stash[1].
diff --git a/Documentation/config/status.txt b/Documentation/config/status.txt
index 0fc704ab80..8caf90f51c 100644
--- a/Documentation/config/status.txt
+++ b/Documentation/config/status.txt
@@ -47,7 +47,7 @@ status.showUntrackedFiles::
contain only untracked files, are shown with the directory name
only. Showing untracked files means that Git needs to lstat() all
the files in the whole repository, which might be slow on some
- systems. So, this variable controls how the commands displays
+ systems. So, this variable controls how the commands display
the untracked files. Possible values are:
+
--
@@ -57,12 +57,14 @@ status.showUntrackedFiles::
--
+
If this variable is not specified, it defaults to 'normal'.
+All usual spellings for Boolean value `true` are taken as `normal`
+and `false` as `no`.
This variable can be overridden with the -u|--untracked-files option
of linkgit:git-status[1] and linkgit:git-commit[1].
status.submoduleSummary::
Defaults to false.
- If this is set to a non zero number or true (identical to -1 or an
+ If this is set to a non-zero number or true (identical to -1 or an
unlimited number), the submodule summary will be enabled and a
summary of commits for modified submodules will be shown (see
--summary-limit option of linkgit:git-submodule[1]). Please note
diff --git a/Documentation/config/submodule.txt b/Documentation/config/submodule.txt
index 6490527b45..0672d99117 100644
--- a/Documentation/config/submodule.txt
+++ b/Documentation/config/submodule.txt
@@ -2,7 +2,7 @@ submodule.<name>.url::
The URL for a submodule. This variable is copied from the .gitmodules
file to the git config via 'git submodule init'. The user can change
the configured URL before obtaining the submodule via 'git submodule
- update'. If neither submodule.<name>.active or submodule.active are
+ update'. If neither submodule.<name>.active nor submodule.active are
set, the presence of this variable is used as a fallback to indicate
whether the submodule is of interest to git commands.
See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
@@ -35,7 +35,7 @@ submodule.<name>.ignore::
a submodule as modified. When set to "all", it will never be considered
modified (but it will nonetheless show up in the output of status and
commit when it has been staged), "dirty" will ignore all changes
- to the submodules work tree and
+ to the submodule's work tree and
takes only differences between the HEAD of the submodule and the commit
recorded in the superproject into account. "untracked" will additionally
let submodules with modified tracked files in their work tree show up.
diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.txt
index fe1642f0d4..3b6bca2b7a 100644
--- a/Documentation/config/trace2.txt
+++ b/Documentation/config/trace2.txt
@@ -66,6 +66,6 @@ trace2.destinationDebug::
trace2.maxFiles::
Integer. When writing trace files to a target directory, do not
- write additional traces if we would exceed this many files. Instead,
+ write additional traces if doing so would exceed this many files. Instead,
write a sentinel file that will block further tracing to this
directory. Defaults to 0, which disables this check.
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt
index c3ac767d1e..f1ce50f4a6 100644
--- a/Documentation/config/transfer.txt
+++ b/Documentation/config/transfer.txt
@@ -7,7 +7,7 @@ transfer.credentialsInUrl::
and any other direct use of the configured URL.
+
Note that this is currently limited to detecting credentials in
-`remote.<name>.url` configuration, it won't detect credentials in
+`remote.<name>.url` configuration; it won't detect credentials in
`remote.<name>.pushurl` configuration.
+
You might want to enable this to prevent inadvertent credentials
@@ -21,12 +21,12 @@ exposure, e.g. because:
system.
* The git programs will pass the full URL to one another as arguments
on the command-line, meaning the credentials will be exposed to other
- users on OS's or systems that allow other users to see the full
+ unprivileged users on systems that allow them to see the full
process list of other users. On linux the "hidepid" setting
documented in procfs(5) allows for configuring this behavior.
+
If such concerns don't apply to you then you probably don't need to be
-concerned about credentials exposure due to storing that sensitive
+concerned about credentials exposure due to storing sensitive
data in git's configuration files. If you do want to use this, set
`transfer.credentialsInUrl` to one of these values:
+
@@ -121,3 +121,7 @@ transfer.bundleURI::
information from the remote server (if advertised) and download
bundles before continuing the clone through the Git protocol.
Defaults to `false`.
+
+transfer.advertiseObjectInfo::
+ When `true`, the `object-info` capability is advertised by
+ servers. Defaults to false.
diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.txt
index 16264d82a7..0e1dda944a 100644
--- a/Documentation/config/uploadpack.txt
+++ b/Documentation/config/uploadpack.txt
@@ -25,7 +25,11 @@ uploadpack.allowReachableSHA1InWant::
uploadpack.allowAnySHA1InWant::
Allow `upload-pack` to accept a fetch request that asks for any
object at all.
- Defaults to `false`.
+ It implies `uploadpack.allowTipSHA1InWant` and
+ `uploadpack.allowReachableSHA1InWant`. If set to `true` it will
+ enable both of them, it set to `false` it will disable both of
+ them.
+ By default not set.
uploadpack.keepAlive::
When `upload-pack` has started `pack-objects`, there may be a
diff --git a/Documentation/config/user.txt b/Documentation/config/user.txt
index ec9233b060..2ffc38d164 100644
--- a/Documentation/config/user.txt
+++ b/Documentation/config/user.txt
@@ -5,14 +5,14 @@ author.email::
committer.name::
committer.email::
The `user.name` and `user.email` variables determine what ends
- up in the `author` and `committer` field of commit
+ up in the `author` and `committer` fields of commit
objects.
If you need the `author` or `committer` to be different, the
- `author.name`, `author.email`, `committer.name` or
+ `author.name`, `author.email`, `committer.name`, or
`committer.email` variables can be set.
- Also, all of these can be overridden by the `GIT_AUTHOR_NAME`,
+ All of these can be overridden by the `GIT_AUTHOR_NAME`,
`GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,
- `GIT_COMMITTER_EMAIL` and `EMAIL` environment variables.
+ `GIT_COMMITTER_EMAIL`, and `EMAIL` environment variables.
+
Note that the `name` forms of these variables conventionally refer to
some form of a personal name. See linkgit:git-commit[1] and the
@@ -40,7 +40,7 @@ user.signingKey::
your private ssh key or the public key when ssh-agent is used.
Alternatively it can contain a public key prefixed with `key::`
directly (e.g.: "key::ssh-rsa XXXXXX identifier"). The private key
- needs to be available via ssh-agent. If not set git will call
+ needs to be available via ssh-agent. If not set Git will call
gpg.ssh.defaultKeyCommand (e.g.: "ssh-add -L") and try to use the
first key available. For backward compatibility, a raw key which
begins with "ssh-", such as "ssh-rsa XXXXXX identifier", is treated
diff --git a/Documentation/config/versionsort.txt b/Documentation/config/versionsort.txt
index 6c7cc054fa..0cff090819 100644
--- a/Documentation/config/versionsort.txt
+++ b/Documentation/config/versionsort.txt
@@ -19,14 +19,14 @@ with those suffixes. E.g. if "-pre" appears before "-rc" in the
configuration, then all "1.0-preX" tags will be listed before any
"1.0-rcX" tags. The placement of the main release tag relative to tags
with various suffixes can be determined by specifying the empty suffix
-among those other suffixes. E.g. if the suffixes "-rc", "", "-ck" and
+among those other suffixes. E.g. if the suffixes "-rc", "", "-ck", and
"-bfs" appear in the configuration in this order, then all "v4.8-rcX" tags
are listed first, followed by "v4.8", then "v4.8-ckX" and finally
"v4.8-bfsX".
+
-If more than one suffixes match the same tagname, then that tagname will
+If more than one suffix matches the same tagname, then that tagname will
be sorted according to the suffix which starts at the earliest position in
-the tagname. If more than one different matching suffixes start at
+the tagname. If more than one different matching suffix starts at
that earliest position, then that tagname will be sorted according to the
longest of those suffixes.
The sorting order between different suffixes is undefined if they are
diff --git a/Documentation/date-formats.txt b/Documentation/date-formats.txt
index 67645cae64..e24517c496 100644
--- a/Documentation/date-formats.txt
+++ b/Documentation/date-formats.txt
@@ -11,7 +11,7 @@ Git internal format::
For example CET (which is 1 hour ahead of UTC) is `+0100`.
RFC 2822::
- The standard email format as described by RFC 2822, for example
+ The standard date format as described by RFC 2822, for example
`Thu, 07 Apr 2005 22:13:13 +0200`.
ISO 8601::
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index 546adf79e5..4b5aa5c2e0 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -17,7 +17,7 @@ You can customize the creation of patch text via the
What the -p option produces is slightly different from the traditional
diff format:
-1. It is preceded with a "git diff" header that looks like this:
+1. It is preceded by a "git diff" header that looks like this:
diff --git a/file1 b/file2
+
@@ -25,9 +25,9 @@ The `a/` and `b/` filenames are the same unless rename/copy is
involved. Especially, even for a creation or a deletion,
`/dev/null` is _not_ used in place of the `a/` or `b/` filenames.
+
-When rename/copy is involved, `file1` and `file2` show the
+When a rename/copy is involved, `file1` and `file2` show the
name of the source file of the rename/copy and the name of
-the file that rename/copy produces, respectively.
+the file that the rename/copy produces, respectively.
2. It is followed by one or more extended header lines:
@@ -77,7 +77,7 @@ separate lines indicate the old and the new mode.
5. Hunk headers mention the name of the function to which the hunk
applies. See "Defining a custom hunk-header" in
- linkgit:gitattributes[5] for details of how to tailor to this to
+ linkgit:gitattributes[5] for details of how to tailor this to
specific languages.
@@ -89,7 +89,7 @@ produce a 'combined diff' when showing a merge. This is the default
format when showing merges with linkgit:git-diff[1] or
linkgit:git-show[1]. Note also that you can give suitable
`--diff-merges` option to any of these commands to force generation of
-diffs in specific format.
+diffs in a specific format.
A "combined diff" format looks like this:
@@ -123,7 +123,7 @@ index fabadb8,cc95eb0..4866510
for_each_ref(get_name);
------------
-1. It is preceded with a "git diff" header, that looks like
+1. It is preceded by a "git diff" header, that looks like
this (when the `-c` option is used):
diff --combined file
@@ -142,22 +142,22 @@ or like this (when the `--cc` option is used):
+
The `mode <mode>,<mode>..<mode>` line appears only if at least one of
the <mode> is different from the rest. Extended headers with
-information about detected contents movement (renames and
-copying detection) are designed to work with diff of two
+information about detected content movement (renames and
+copying detection) are designed to work with the diff of two
<tree-ish> and are not used by combined diff format.
-3. It is followed by two-line from-file/to-file header
+3. It is followed by a two-line from-file/to-file header:
--- a/file
+++ b/file
+
-Similar to two-line header for traditional 'unified' diff
+Similar to the two-line header for the traditional 'unified' diff
format, `/dev/null` is used to signal created or deleted
files.
+
However, if the --combined-all-paths option is provided, instead of a
-two-line from-file/to-file you get a N+1 line from-file/to-file header,
-where N is the number of parents in the merge commit
+two-line from-file/to-file, you get an N+1 line from-file/to-file header,
+where N is the number of parents in the merge commit:
--- a/file
--- a/file
@@ -197,7 +197,7 @@ added, from the point of view of that parent).
In the above example output, the function signature was changed
from both files (hence two `-` removals from both file1 and
file2, plus `++` to mean one line that was added does not appear
-in either file1 or file2). Also eight other lines are the same
+in either file1 or file2). Also, eight other lines are the same
from file1 but do not appear in file2 (hence prefixed with `+`).
When shown by `git diff-tree -c`, it compares the parents of a
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index c07488b123..cd0b81adbb 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -37,66 +37,79 @@ endif::git-diff[]
endif::git-format-patch[]
ifdef::git-log[]
---diff-merges=(off|none|on|first-parent|1|separate|m|combined|c|dense-combined|cc|remerge|r)::
+-m::
+ Show diffs for merge commits in the default format. This is
+ similar to '--diff-merges=on', except `-m` will
+ produce no output unless `-p` is given as well.
+
+-c::
+ Produce combined diff output for merge commits.
+ Shortcut for '--diff-merges=combined -p'.
+
+--cc::
+ Produce dense combined diff output for merge commits.
+ Shortcut for '--diff-merges=dense-combined -p'.
+
+--dd::
+ Produce diff with respect to first parent for both merge and
+ regular commits.
+ Shortcut for '--diff-merges=first-parent -p'.
+
+--remerge-diff::
+ Produce remerge-diff output for merge commits.
+ Shortcut for '--diff-merges=remerge -p'.
+
--no-diff-merges::
+ Synonym for '--diff-merges=off'.
+
+--diff-merges=<format>::
Specify diff format to be used for merge commits. Default is
- {diff-merges-default} unless `--first-parent` is in use, in which case
- `first-parent` is the default.
+ {diff-merges-default} unless `--first-parent` is in use, in
+ which case `first-parent` is the default.
+
---diff-merges=(off|none):::
---no-diff-merges:::
+The following formats are supported:
++
+--
+off, none::
Disable output of diffs for merge commits. Useful to override
implied value.
+
---diff-merges=on:::
---diff-merges=m:::
--m:::
- This option makes diff output for merge commits to be shown in
- the default format. `-m` will produce the output only if `-p`
- is given as well. The default format could be changed using
- `log.diffMerges` configuration parameter, which default value
+on, m::
+ Make diff output for merge commits to be shown in the default
+ format. The default format can be changed using
+ `log.diffMerges` configuration variable, whose default value
is `separate`.
+
---diff-merges=first-parent:::
---diff-merges=1:::
- This option makes merge commits show the full diff with
- respect to the first parent only.
+first-parent, 1::
+ Show full diff with respect to first parent. This is the same
+ format as `--patch` produces for non-merge commits.
++
+separate::
+ Show full diff with respect to each of parents.
+ Separate log entry and diff is generated for each parent.
+
---diff-merges=separate:::
- This makes merge commits show the full diff with respect to
- each of the parents. Separate log entry and diff is generated
- for each parent.
+combined, c::
+ Show differences from each of the parents to the merge
+ result simultaneously instead of showing pairwise diff between
+ a parent and the result one at a time. Furthermore, it lists
+ only files which were modified from all parents.
+
---diff-merges=remerge:::
---diff-merges=r:::
---remerge-diff:::
- With this option, two-parent merge commits are remerged to
- create a temporary tree object -- potentially containing files
- with conflict markers and such. A diff is then shown between
- that temporary tree and the actual merge commit.
+dense-combined, cc::
+ Further compress output produced by `--diff-merges=combined`
+ by omitting uninteresting hunks whose contents in the parents
+ have only two variants and the merge result picks one of them
+ without modification.
++
+remerge, r::
+ Remerge two-parent merge commits to create a temporary tree
+ object--potentially containing files with conflict markers
+ and such. A diff is then shown between that temporary tree
+ and the actual merge commit.
+
The output emitted when this option is used is subject to change, and
so is its interaction with other options (unless explicitly
documented).
-+
---diff-merges=combined:::
---diff-merges=c:::
--c:::
- With this option, diff output for a merge commit shows the
- differences from each of the parents to the merge result
- simultaneously instead of showing pairwise diff between a
- parent and the result one at a time. Furthermore, it lists
- only files which were modified from all parents. `-c` implies
- `-p`.
-+
---diff-merges=dense-combined:::
---diff-merges=cc:::
---cc:::
- With this option the output produced by
- `--diff-merges=combined` is further compressed by omitting
- uninteresting hunks whose contents in the parents have only
- two variants and the merge result picks one of them without
- modification. `--cc` implies `-p`.
+--
--combined-all-paths::
This flag causes combined diffs (used for merge commits) to
@@ -204,14 +217,15 @@ have to use `--diff-algorithm=default` option.
part. Maximum width defaults to terminal width, or 80 columns
if not connected to a terminal, and can be overridden by
`<width>`. The width of the filename part can be limited by
- giving another width `<name-width>` after a comma. The width
- of the graph part can be limited by using
- `--stat-graph-width=<width>` (affects all commands generating
- a stat graph) or by setting `diff.statGraphWidth=<width>`
- (does not affect `git format-patch`).
- By giving a third parameter `<count>`, you can limit the
- output to the first `<count>` lines, followed by `...` if
- there are more.
+ giving another width `<name-width>` after a comma or by setting
+ `diff.statNameWidth=<width>`. The width of the graph part can be
+ limited by using `--stat-graph-width=<width>` or by setting
+ `diff.statGraphWidth=<width>`. Using `--stat` or
+ `--stat-graph-width` affects all commands generating a stat graph,
+ while setting `diff.statNameWidth` or `diff.statGraphWidth`
+ does not affect `git format-patch`.
+ By giving a third parameter `<count>`, you can limit the output to
+ the first `<count>` lines, followed by `...` if there are more.
+
These parameters can also be set individually with `--stat-width=<width>`,
`--stat-name-width=<name-width>` and `--stat-count=<count>`.
@@ -285,7 +299,7 @@ and accumulating child directory counts in the parent directories:
Synonym for --dirstat=cumulative
--dirstat-by-file[=<param1,param2>...]::
- Synonym for --dirstat=files,param1,param2...
+ Synonym for --dirstat=files,<param1>,<param2>...
--summary::
Output a condensed summary of extended header information
@@ -300,7 +314,7 @@ ifndef::git-format-patch[]
-z::
ifdef::git-log[]
- Separate the commits with NULs instead of with new newlines.
+ Separate the commits with NULs instead of newlines.
+
Also, when `--raw` or `--numstat` has been given, do not munge
pathnames and use NULs as output field terminators.
@@ -315,12 +329,13 @@ explained for the configuration variable `core.quotePath` (see
linkgit:git-config[1]).
--name-only::
- Show only names of changed files. The file names are often encoded in UTF-8.
+ Show only the name of each changed file in the post-image tree.
+ The file names are often encoded in UTF-8.
For more information see the discussion about encoding in the linkgit:git-log[1]
manual page.
--name-status::
- Show only names and status of changed files. See the description
+ Show only the name(s) and status of each changed file. See the description
of the `--diff-filter` option on what the status letters mean.
Just like `--name-only` the file names are often encoded in UTF-8.
@@ -732,7 +747,7 @@ matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
--rotate-to=<file>::
Discard the files before the named <file> from the output
(i.e. 'skip to'), or move them to the end of the output
- (i.e. 'rotate to'). These were invented primarily for use
+ (i.e. 'rotate to'). These options were invented primarily for the use
of the `git difftool` command, and may not be very useful
otherwise.
@@ -805,6 +820,11 @@ ifndef::git-log[]
--quiet::
Disable all output of the program. Implies `--exit-code`.
+ Disables execution of external diff helpers whose exit code
+ is not trusted, i.e. their respective configuration option
+ `diff.trustExitCode` or `diff.<driver>.trustExitCode` or
+ environment variable `GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE` is
+ false.
endif::git-log[]
endif::git-format-patch[]
@@ -851,8 +871,9 @@ endif::git-format-patch[]
--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`.
+ This overrides configuration variables such as `diff.noprefix`,
+ `diff.srcPrefix`, `diff.dstPrefix`, and `diff.mnemonicPrefix`
+ (see `git-config`(1)).
--line-prefix=<prefix>::
Prepend an additional prefix to every line of output.
diff --git a/Documentation/docinfo-html.in b/Documentation/docinfo-html.in
new file mode 100644
index 0000000000..fb3560eb92
--- /dev/null
+++ b/Documentation/docinfo-html.in
@@ -0,0 +1,5 @@
+<style>
+pre>code {
+ display: inline;
+}
+</style>
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 41fc7ca3c6..b01372e4b3 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -1,5 +1,7 @@
---all::
- Fetch all remotes.
+--[no-]all::
+ Fetch all remotes, except for the ones that has the
+ `remote.<name>.skipFetchAll` configuration variable set.
+ This overrides the configuration variable fetch.all`.
-a::
--append::
@@ -27,7 +29,7 @@
Deepen or shorten the history of a shallow repository to
include all reachable commits after <date>.
---shallow-exclude=<revision>::
+--shallow-exclude=<ref>::
Deepen or shorten the history of a shallow repository to
exclude commits reachable from a specified remote branch or tag.
This option can be specified multiple times.
@@ -43,7 +45,7 @@ the current repository has the same history as the source repository.
--update-shallow::
By default when fetching from a shallow repository,
`git fetch` refuses refs that require updating
- .git/shallow. This option updates .git/shallow and accept such
+ .git/shallow. This option updates .git/shallow and accepts such
refs.
--negotiation-tip=<commit|glob>::
@@ -96,7 +98,7 @@ endif::git-pull[]
-f::
--force::
- When 'git fetch' is used with `<src>:<dst>` refspec it may
+ When 'git fetch' is used with `<src>:<dst>` refspec, it may
refuse to update the local branch as discussed
ifdef::git-pull[]
in the `<refspec>` part of the linkgit:git-fetch[1]
@@ -201,7 +203,7 @@ endif::git-pull[]
destination of an explicit refspec; see `--prune`).
ifndef::git-pull[]
---recurse-submodules[=yes|on-demand|no]::
+--recurse-submodules[=(yes|on-demand|no)]::
This option controls if and under what conditions new commits of
submodules should be fetched too. When recursing through submodules,
`git fetch` always attempts to fetch "changed" submodules, that is, a
@@ -303,6 +305,9 @@ endif::git-pull[]
unknown ones, is server-specific.
When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line.
+ When no `--server-option=<option>` is given from the command line,
+ the values of configuration variable `remote.<name>.serverOption`
+ are used instead.
--show-forced-updates::
By default, git checks if a branch is force-updated during
diff --git a/Documentation/fsck-msgids.txt b/Documentation/fsck-msgids.txt
index 12eae8a222..b14bc44ca4 100644
--- a/Documentation/fsck-msgids.txt
+++ b/Documentation/fsck-msgids.txt
@@ -19,6 +19,18 @@
`badParentSha1`::
(ERROR) A commit object has a bad parent sha1.
+`badRefContent`::
+ (ERROR) A ref has bad content.
+
+`badRefFiletype`::
+ (ERROR) A ref has a bad file type.
+
+`badRefName`::
+ (ERROR) A ref has an invalid format.
+
+`badReferentName`::
+ (ERROR) The referent name of a symref is invalid.
+
`badTagName`::
(INFO) A tag has an invalid format.
@@ -103,6 +115,13 @@
`hasDotgit`::
(WARN) A tree contains an entry named `.git`.
+`largePathname`::
+ (WARN) A tree contains an entry with a very long path name. If
+ the value of `fsck.largePathname` contains a colon, that value
+ is used as the maximum allowable length (e.g., "warn:10" would
+ complain about any path component of 11 or more bytes). The
+ default value is 4096.
+
`mailmapSymlink`::
(INFO) `.mailmap` is a symlink.
@@ -125,7 +144,7 @@
(ERROR) Missing space before date in an author/committer line.
`missingSpaceBeforeEmail`::
- (ERROR) Missing space before the email in author/committer line.
+ (ERROR) Missing space before the email in an author/committer line.
`missingTag`::
(ERROR) Unexpected end after `type` line in a tag object.
@@ -157,6 +176,35 @@
`nullSha1`::
(WARN) Tree contains entries pointing to a null sha1.
+`refMissingNewline`::
+ (INFO) A loose ref that does not end with newline(LF). As
+ valid implementations of Git never created such a loose ref
+ file, it may become an error in the future. Report to the
+ git@vger.kernel.org mailing list if you see this error, as
+ we need to know what tools created such a file.
+
+`symlinkRef`::
+ (INFO) A symbolic link is used as a symref. Report to the
+ git@vger.kernel.org mailing list if you see this error, as we
+ are assessing the feasibility of dropping the support to drop
+ creating symbolic links as symrefs.
+
+`symrefTargetIsNotARef`::
+ (INFO) The target of a symbolic reference points neither to
+ a root reference nor to a reference starting with "refs/".
+ Although we allow create a symref pointing to the referent which
+ is outside the "ref" by using `git symbolic-ref`, we may tighten
+ the rule in the future. Report to the git@vger.kernel.org
+ mailing list if you see this error, as we need to know what tools
+ created such a file.
+
+`trailingRefContent`::
+ (INFO) A loose ref has trailing content. As valid implementations
+ of Git never created such a loose ref file, it may become an
+ error in the future. Report to the git@vger.kernel.org mailing
+ list if you see this error, as we need to know what tools
+ created such a file.
+
`treeNotSorted`::
(ERROR) A tree is not properly sorted.
@@ -167,7 +215,7 @@
(FATAL) Missing end-of-line in the object header.
`zeroPaddedDate`::
- (ERROR) Found a zero padded date in an author/commiter line.
+ (ERROR) Found a zero padded date in an author/committer line.
`zeroPaddedFilemode`::
(WARN) Found a zero padded filemode in a tree.
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index ed44c1cb31..5f2c3592b8 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -7,12 +7,12 @@ git-add - Add file contents to the index
SYNOPSIS
--------
-[verse]
-'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
- [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]] [--sparse]
- [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize]
- [--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]]
- [--] [<pathspec>...]
+[synopsis]
+git add [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
+ [--edit | -e] [--[no-]all | -A | --[no-]ignore-removal | [--update | -u]] [--sparse]
+ [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize]
+ [--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]]
+ [--] [<pathspec>...]
DESCRIPTION
-----------
@@ -41,7 +41,7 @@ The `git add` command will not add ignored files by default. If any
ignored files were explicitly specified on the command line, `git add`
will fail with a list of ignored files. Ignored files reached by
directory recursion or filename globbing performed by Git (quote your
-globs before the shell) will be silently ignored. The 'git add' command can
+globs before the shell) will be silently ignored. The `git add` command can
be used to add ignored files with the `-f` (force) option.
Please see linkgit:git-commit[1] for alternative ways to add content to a
@@ -50,7 +50,7 @@ commit.
OPTIONS
-------
-<pathspec>...::
+`<pathspec>...`::
Files to add content from. Fileglobs (e.g. `*.c`) can
be given to add all matching files. Also a
leading directory name (e.g. `dir` to add `dir/file1`
@@ -63,38 +63,38 @@ OPTIONS
to ignore removed files; use `--no-all` option if you want
to add modified or new files but ignore removed ones.
+
-For more details about the <pathspec> syntax, see the 'pathspec' entry
+For more details about the _<pathspec>_ syntax, see the 'pathspec' entry
in linkgit:gitglossary[7].
--n::
---dry-run::
+`-n`::
+`--dry-run`::
Don't actually add the file(s), just show if they exist and/or will
be ignored.
--v::
---verbose::
+`-v`::
+`--verbose`::
Be verbose.
--f::
---force::
+`-f`::
+`--force`::
Allow adding otherwise ignored files.
---sparse::
+`--sparse`::
Allow updating index entries outside of the sparse-checkout cone.
Normally, `git add` refuses to update index entries whose paths do
not fit within the sparse-checkout cone, since those files might
be removed from the working tree without warning. See
linkgit:git-sparse-checkout[1] for more details.
--i::
---interactive::
+`-i`::
+`--interactive`::
Add modified contents in the working tree interactively to
the index. Optional path arguments may be supplied to limit
operation to a subset of the working tree. See ``Interactive
mode'' for details.
--p::
---patch::
+`-p`::
+`--patch`::
Interactively choose hunks of patch between the index and the
work tree and add them to the index. This gives the user a chance
to review the difference before adding modified contents to the
@@ -104,8 +104,8 @@ This effectively runs `add --interactive`, but bypasses the
initial command menu and directly jumps to the `patch` subcommand.
See ``Interactive mode'' for details.
--e::
---edit::
+`-e`::
+`--edit`::
Open the diff vs. the index in an editor and let the user
edit it. After the editor was closed, adjust the hunk headers
and apply the patch to the index.
@@ -116,101 +116,101 @@ quicker and more flexible than using the interactive hunk selector.
However, it is easy to confuse oneself and create a patch that does not
apply to the index. See EDITING PATCHES below.
--u::
---update::
+`-u`::
+`--update`::
Update the index just where it already has an entry matching
- <pathspec>. This removes as well as modifies index entries to
+ _<pathspec>_. This removes as well as modifies index entries to
match the working tree, but adds no new files.
+
-If no <pathspec> is given when `-u` option is used, all
+If no _<pathspec>_ is given when `-u` option is used, all
tracked files in the entire working tree are updated (old versions
of Git used to limit the update to the current directory and its
subdirectories).
--A::
---all::
---no-ignore-removal::
+`-A`::
+`--all`::
+`--no-ignore-removal`::
Update the index not only where the working tree has a file
- matching <pathspec> but also where the index already has an
+ matching _<pathspec>_ but also where the index already has an
entry. This adds, modifies, and removes index entries to
match the working tree.
+
-If no <pathspec> is given when `-A` option is used, all
+If no _<pathspec>_ is given when `-A` option is used, all
files in the entire working tree are updated (old versions
of Git used to limit the update to the current directory and its
subdirectories).
---no-all::
---ignore-removal::
+`--no-all`::
+`--ignore-removal`::
Update the index by adding new files that are unknown to the
index and files modified in the working tree, but ignore
files that have been removed from the working tree. This
- option is a no-op when no <pathspec> is used.
+ option is a no-op when no _<pathspec>_ is used.
+
This option is primarily to help users who are used to older
-versions of Git, whose "git add <pathspec>..." was a synonym
-for "git add --no-all <pathspec>...", i.e. ignored removed files.
+versions of Git, whose `git add <pathspec>...` was a synonym
+for `git add --no-all <pathspec>...`, i.e. ignored removed files.
--N::
---intent-to-add::
+`-N`::
+`--intent-to-add`::
Record only the fact that the path will be added later. An entry
for the path is placed in the index with no content. This is
useful for, among other things, showing the unstaged content of
such files with `git diff` and committing them with `git commit
-a`.
---refresh::
+`--refresh`::
Don't add the file(s), but only refresh their stat()
information in the index.
---ignore-errors::
+`--ignore-errors`::
If some files could not be added because of errors indexing
them, do not abort the operation, but continue adding the
others. The command shall still exit with non-zero status.
The configuration variable `add.ignoreErrors` can be set to
true to make this the default behaviour.
---ignore-missing::
- This option can only be used together with --dry-run. By using
+`--ignore-missing`::
+ This option can only be used together with `--dry-run`. By using
this option the user can check if any of the given files would
be ignored, no matter if they are already present in the work
tree or not.
---no-warn-embedded-repo::
+`--no-warn-embedded-repo`::
By default, `git add` will warn when adding an embedded
repository to the index without using `git submodule add` to
create an entry in `.gitmodules`. This option will suppress the
warning (e.g., if you are manually performing operations on
submodules).
---renormalize::
+`--renormalize`::
Apply the "clean" process freshly to all tracked files to
forcibly add them again to the index. This is useful after
changing `core.autocrlf` configuration or the `text` attribute
- in order to correct files added with wrong CRLF/LF line endings.
+ in order to correct files added with wrong _CRLF/LF_ line endings.
This option implies `-u`. Lone CR characters are untouched, thus
- while a CRLF cleans to LF, a CRCRLF sequence is only partially
- cleaned to CRLF.
+ while a _CRLF_ cleans to _LF_, a _CRCRLF_ sequence is only partially
+ cleaned to _CRLF_.
---chmod=(+|-)x::
+`--chmod=(+|-)x`::
Override the executable bit of the added files. The executable
bit is only changed in the index, the files on disk are left
unchanged.
---pathspec-from-file=<file>::
- Pathspec is passed in `<file>` instead of commandline args. If
- `<file>` is exactly `-` then standard input is used. Pathspec
- elements are separated by LF or CR/LF. Pathspec elements can be
+`--pathspec-from-file=<file>`::
+ Pathspec is passed in _<file>_ instead of commandline args. If
+ _<file>_ is exactly `-` then standard input is used. Pathspec
+ elements are separated by _LF_ or _CR/LF_. Pathspec elements can be
quoted as explained for the configuration variable `core.quotePath`
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
global `--literal-pathspecs`.
---pathspec-file-nul::
+`--pathspec-file-nul`::
Only meaningful with `--pathspec-from-file`. Pathspec elements are
- separated with NUL character and all other characters are taken
+ separated with _NUL_ character and all other characters are taken
literally (including newlines and quotes).
-\--::
+`--`::
This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken
for command-line options).
@@ -219,18 +219,18 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
EXAMPLES
--------
-* Adds content from all `*.txt` files under `Documentation` directory
+* Adds content from all ++*.txt++ files under `Documentation` directory
and its subdirectories:
+
------------
$ git add Documentation/\*.txt
------------
+
-Note that the asterisk `*` is quoted from the shell in this
+Note that the asterisk ++*++ is quoted from the shell in this
example; this lets the command include the files from
subdirectories of `Documentation/` directory.
-* Considers adding content from all git-*.sh scripts:
+* Considers adding content from all ++git-*.sh++ scripts:
+
------------
$ git add git-*.sh
@@ -265,7 +265,7 @@ The main command loop has 6 subcommands (plus help and quit).
status::
- This shows the change between HEAD and index (i.e. what will be
+ This shows the change between `HEAD` and index (i.e. what will be
committed if you say `git commit`), and between index and
working tree files (i.e. what you could stage further before
`git commit` using `git add`) for each path. A sample output
@@ -277,12 +277,12 @@ status::
2: +403/-35 +1/-1 add-interactive.c
------------
+
-It shows that foo.png has differences from HEAD (but that is
+It shows that `foo.png` has differences from `HEAD` (but that is
binary so line count cannot be shown) and there is no
difference between indexed copy and the working tree
version (if the working tree version were also different,
'binary' would have been shown in place of 'nothing'). The
-other file, add-interactive.c, has 403 lines added
+other file, `add-interactive.c`, has 403 lines added
and 35 lines deleted if you commit what is in the index, but
working tree file has further modifications (one addition and
one deletion).
@@ -348,6 +348,7 @@ patch::
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
+ p - print the current hunk
? - print help
+
After deciding the fate for all hunks, if there is any hunk
@@ -359,7 +360,7 @@ variable `interactive.singleKey` to `true`.
diff::
This lets you review what will be committed (i.e. between
- HEAD and index).
+ `HEAD` and index).
EDITING PATCHES
@@ -398,7 +399,7 @@ There are also more complex operations that can be performed. But beware
that because the patch is applied only to the index and not the working
tree, the working tree will appear to "undo" the change in the index.
For example, introducing a new line into the index that is in neither
-the HEAD nor the working tree will stage the new line for commit, but
+the `HEAD` nor the working tree will stage the new line for commit, but
the line will appear to be reverted in the working tree.
Avoid using these constructs, or do so with extreme caution.
@@ -438,6 +439,7 @@ CONFIGURATION
include::includes/cmd-config-section-all.txt[]
+:git-add: 1
include::config/add.txt[]
SEE ALSO
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 82dadbecc8..69d5cc9f21 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -18,12 +18,12 @@ SYNOPSIS
[--quoted-cr=<action>]
[--empty=(stop|drop|keep)]
[(<mbox> | <Maildir>)...]
-'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)] | --allow-empty)
+'git am' (--continue | --skip | --abort | --quit | --retry | --show-current-patch[=(diff|raw)] | --allow-empty)
DESCRIPTION
-----------
-Splits mail messages in a mailbox into commit log message,
-authorship information and patches, and applies them to the
+Splits mail messages in a mailbox into commit log messages,
+authorship information, and patches, and applies them to the
current branch. You could think of it as a reverse operation
of linkgit:git-format-patch[1] run on a branch with a straight
history without merges.
@@ -66,13 +66,19 @@ OPTIONS
--quoted-cr=<action>::
This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).
---empty=(stop|drop|keep)::
- By default, or when the option is set to 'stop', the command
- errors out on an input e-mail message lacking a patch
- and stops into the middle of the current am session. When this
- option is set to 'drop', skip such an e-mail message instead.
- When this option is set to 'keep', create an empty commit,
- recording the contents of the e-mail message as its log.
+--empty=(drop|keep|stop)::
+ How to handle an e-mail message lacking a patch:
++
+--
+`drop`;;
+ The e-mail message will be skipped.
+`keep`;;
+ An empty commit will be created, with the contents of the e-mail
+ message as its log.
+`stop`;;
+ The command will fail, stopping in the middle of the current `am`
+ session. This is the default behavior.
+--
-m::
--message-id::
@@ -94,7 +100,7 @@ OPTIONS
Pass `-u` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
The proposed commit log message taken from the e-mail
is re-coded into UTF-8 encoding (configuration variable
- `i18n.commitEncoding` can be used to specify project's
+ `i18n.commitEncoding` can be used to specify the project's
preferred encoding if it is not UTF-8).
+
This was optional in prior versions of git, but now it is the
@@ -128,13 +134,16 @@ include::rerere-options.txt[]
These flags are passed to the 'git apply' (see linkgit:git-apply[1])
program that applies
the patch.
++
+Valid <action> for the `--whitespace` option are:
+`nowarn`, `warn`, `fix`, `error`, and `error-all`.
--patch-format::
By default the command will try to detect the patch format
automatically. This option allows the user to bypass the automatic
detection and specify the patch format that the patch(es) should be
interpreted as. Valid formats are mbox, mboxrd,
- stgit, stgit-series and hg.
+ stgit, stgit-series, and hg.
-i::
--interactive::
@@ -192,13 +201,19 @@ include::rerere-options.txt[]
--abort::
Restore the original branch and abort the patching operation.
- Revert contents of files involved in the am operation to their
+ Revert the contents of files involved in the am operation to their
pre-am state.
--quit::
Abort the patching operation but keep HEAD and the index
untouched.
+--retry::
+ Try to apply the last conflicting patch again. This is generally
+ only useful for passing extra options to the retry attempt
+ (e.g., `--3way`), since otherwise you'll just see the same
+ failure again.
+
--show-current-patch[=(diff|raw)]::
Show the message at which `git am` has stopped due to
conflicts. If `raw` is specified, show the raw contents of
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 5e16e6db7e..dd4a61ef28 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -9,7 +9,8 @@ git-apply - Apply a patch to files and/or to the index
SYNOPSIS
--------
[verse]
-'git apply' [--stat] [--numstat] [--summary] [--check] [--index | --intent-to-add] [--3way]
+'git apply' [--stat] [--numstat] [--summary] [--check]
+ [--index | --intent-to-add] [--3way] [--ours | --theirs | --union]
[--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z]
[-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -23,8 +24,8 @@ DESCRIPTION
Reads the supplied diff output (i.e. "a patch") and applies it to files.
When running from a subdirectory in a repository, patched paths
outside the directory are ignored.
-With the `--index` option the patch is also applied to the index, and
-with the `--cached` option the patch is only applied to the index.
+With the `--index` option, the patch is also applied to the index, and
+with the `--cached` option, the patch is only applied to the index.
Without these options, the command applies the patch only to files,
and does not require them to be in a Git repository.
@@ -52,7 +53,7 @@ OPTIONS
--summary::
Instead of applying the patch, output a condensed
summary of information obtained from git diff extended
- headers, such as creations, renames and mode changes.
+ headers, such as creations, renames, and mode changes.
Turns off "apply".
--check::
@@ -92,6 +93,12 @@ OPTIONS
When used with the `--cached` option, any conflicts are left at higher stages
in the cache.
+--ours::
+--theirs::
+--union::
+ Instead of leaving conflicts in the file, resolve conflicts favouring
+ our (or their or both) side of the lines. Requires --3way.
+
--build-fake-ancestor=<file>::
Newer 'git diff' output has embedded 'index information'
for each blob to help identify the original version that
@@ -140,7 +147,7 @@ linkgit:git-config[1]).
applying a diff generated with `--unified=0`. To bypass these
checks use `--unidiff-zero`.
+
-Note, for the reasons stated above usage of context-free patches is
+Note, for the reasons stated above, the usage of context-free patches is
discouraged.
--apply::
@@ -159,9 +166,9 @@ discouraged.
--allow-binary-replacement::
--binary::
- Historically we did not allow binary patch applied
+ Historically we did not allow binary patch application
without an explicit permission from the user, and this
- flag was the way to do so. Currently we always allow binary
+ flag was the way to do so. Currently, we always allow binary
patch application, so this is a no-op.
--exclude=<path-pattern>::
@@ -257,7 +264,7 @@ the `--unsafe-paths` option to override this safety check. This option
has no effect when `--index` or `--cached` is in use.
--allow-empty::
- Don't return error for patches containing no diff. This includes
+ Don't return an error for patches containing no diff. This includes
empty patches and patches with commit text only.
CONFIGURATION
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 6bab201d37..a0e3fe7996 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -21,14 +21,14 @@ structure for the named tree, and writes it out to the standard
output. If <prefix> is specified it is
prepended to the filenames in the archive.
-'git archive' behaves differently when given a tree ID versus when
-given a commit ID or tag ID. In the first case the current time is
-used as the modification time of each file in the archive. In the latter
-case the commit time as recorded in the referenced commit object is
-used instead. Additionally the commit ID is stored in a global
-extended pax header if the tar format is used; it can be extracted
-using 'git get-tar-commit-id'. In ZIP files it is stored as a file
-comment.
+'git archive' behaves differently when given a tree ID as opposed to a
+commit ID or tag ID. When a tree ID is provided, the current time is
+used as the modification time of each file in the archive. On the
+other hand, when a commit ID or tag ID is provided, the commit time as
+recorded in the referenced commit object is used instead.
+Additionally the commit ID is stored in a global extended pax header
+if the tar format is used; it can be extracted using 'git
+get-tar-commit-id'. In ZIP files it is stored as a file comment.
OPTIONS
-------
@@ -53,7 +53,7 @@ OPTIONS
--prefix=<prefix>/::
Prepend <prefix>/ to paths in the archive. Can be repeated; its
rightmost value is used for all tracked files. See below which
- value gets used by `--add-file` and `--add-virtual-file`.
+ value gets used by `--add-file`.
-o <file>::
--output=<file>::
@@ -67,9 +67,7 @@ OPTIONS
--add-virtual-file=<path>:<content>::
Add the specified contents to the archive. Can be repeated to add
- multiple files. The path of the file in the archive is built
- by concatenating the value of the last `--prefix` option (if any)
- before this `--add-virtual-file` and `<path>`.
+ multiple files.
+
The `<path>` argument can start and end with a literal double-quote
character; the contained file name is interpreted as a C-style string,
@@ -81,6 +79,10 @@ if the path begins or ends with a double-quote character.
The file mode is limited to a regular file, and the option may be
subject to platform-dependent command-line limits. For non-trivial
cases, write an untracked file and use `--add-file` instead.
++
+Note that unlike `--add-file` the path created in the archive is not
+affected by the `--prefix` option, as a full `<path>` can be given as
+the value of the option.
--worktree-attributes::
Look for attributes in .gitattributes files in the working tree
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 7872dba3ae..82f944dc03 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -16,17 +16,17 @@ DESCRIPTION
The command takes various subcommands, and different options depending
on the subcommand:
- git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
- [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
+ git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]
+ [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>...]
- git bisect terms [--term-good | --term-bad]
+ git bisect terms [--term-(good|old) | --term-(bad|new)]
git bisect skip [(<rev>|<range>)...]
git bisect reset [<commit>]
git bisect (visualize|view)
git bisect replay <logfile>
git bisect log
- git bisect run <cmd>...
+ git bisect run <cmd> [<arg>...]
git bisect help
This command uses a binary search algorithm to find which commit in
@@ -165,8 +165,10 @@ To get a reminder of the currently used terms, use
git bisect terms
------------------------------------------------
-You can get just the old (respectively new) term with `git bisect terms
---term-old` or `git bisect terms --term-good`.
+You can get just the old term with `git bisect terms --term-old`
+or `git bisect terms --term-good`; `git bisect terms --term-new`
+and `git bisect terms --term-bad` can be used to learn how to call
+the commits more recent than the sought change.
If you would like to use your own terms instead of "bad"/"good" or
"new"/"old", you can choose any names you like (except existing bisect
@@ -299,7 +301,7 @@ Cutting down bisection by giving more parameters to bisect start
You can further cut down the number of trials, if you know what part of
the tree is involved in the problem you are tracking down, by specifying
-path parameters when issuing the `bisect start` command:
+pathspec parameters when issuing the `bisect start` command:
------------
$ git bisect start -- arch/i386 include/asm-i386
@@ -362,7 +364,7 @@ OPTIONS
--no-checkout::
+
Do not checkout the new working tree at each iteration of the bisection
-process. Instead just update a special reference named `BISECT_HEAD` to make
+process. Instead just update the reference named `BISECT_HEAD` to make
it point to the commit that should be tested.
+
This option may be useful when the test you would perform in each step
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index f69a871a96..b1d7fb539d 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -77,7 +77,7 @@ include::blame-options.txt[]
-e::
--show-email::
- Show the author email instead of author name (Default: off).
+ Show the author email instead of the author name (Default: off).
This can also be controlled via the `blame.showEmail` config
option.
@@ -100,7 +100,7 @@ When neither `--porcelain` nor `--incremental` option is specified,
`git blame` will output annotation for each line with:
- abbreviated object name for the commit the line came from;
-- author ident (by default author name and date, unless `-s` or `-e`
+- author ident (by default the author name and date, unless `-s` or `-e`
is specified); and
- line number
@@ -128,7 +128,7 @@ at least once for each commit:
- the filename in the commit that the line is attributed to.
- the first line of the commit log message ("summary").
-The contents of the actual line is output after the above
+The contents of the actual line are output after the above
header, prefixed by a TAB. This is to allow adding more
header elements later.
@@ -170,7 +170,7 @@ which limits the annotation to the body of the `hello` subroutine.
When you are not interested in changes older than version
v2.6.18, or changes older than 3 weeks, you can use revision
-range specifiers similar to 'git rev-list':
+range specifiers similar to 'git rev-list':
git blame v2.6.18.. -- foo
git blame --since=3.weeks -- foo
@@ -210,7 +210,7 @@ annotated.
. Each blame entry always starts with a line of:
- <40-byte hex sha1> <sourceline> <resultline> <num_lines>
+ <40-byte-hex-sha1> <sourceline> <resultline> <num-lines>
+
Line numbers count from 1.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d207da9101..0b08442932 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -312,7 +312,8 @@ superproject's "origin/main", but tracks the submodule's "origin/main".
option is omitted, the current HEAD will be used instead.
<oldbranch>::
- The name of an existing branch to rename.
+ The name of an existing branch. If this option is omitted,
+ the name of the current branch will be used instead.
<newbranch>::
The new name for an existing branch. The same restrictions as for
@@ -324,7 +325,7 @@ superproject's "origin/main", but tracks the submodule's "origin/main".
multiple times, in which case the last key becomes the primary
key. The keys supported are the same as those in `git
for-each-ref`. Sort order defaults to the value configured for the
- `branch.sort` variable if exists, or to sorting based on the
+ `branch.sort` variable if it exists, or to sorting based on the
full refname (including `refs/...` prefix). This lists
detached HEAD (if present) first, then local branches and
finally remote-tracking branches. See linkgit:git-config[1].
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index eca726e579..112658b3c3 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -8,15 +8,17 @@ git-bugreport - Collect information for user to file a bug report
SYNOPSIS
--------
[verse]
-'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+'git bugreport' [(-o | --output-directory) <path>]
+ [(-s | --suffix) <format> | --no-suffix]
[--diagnose[=<mode>]]
DESCRIPTION
-----------
-Captures information about the user's machine, Git client, and repository state,
-as well as a form requesting information about the behavior the user observed,
-into a single text file which the user can then share, for example to the Git
-mailing list, in order to report an observed bug.
+Collects information about the user's machine, Git client, and repository
+state, in addition to a form requesting information about the behavior the
+user observed, and stores it in a single text file which the user can then
+share, for example to the Git mailing list, in order to report an observed
+bug.
The following information is requested from the user:
@@ -50,16 +52,19 @@ OPTIONS
-s <format>::
--suffix <format>::
+--no-suffix::
Specify an alternate suffix for the bugreport name, to create a file
- named 'git-bugreport-<formatted suffix>'. This should take the form of a
+ named 'git-bugreport-<formatted-suffix>'. This should take the form of a
strftime(3) format string; the current local time will be used.
+ `--no-suffix` disables the suffix and the file is just named
+ `git-bugreport` without any disambiguation measure.
--no-diagnose::
--diagnose[=<mode>]::
Create a zip archive of supplemental information about the user's
machine, Git client, and repository state. The archive is written to the
same output directory as the bug report and is named
- 'git-diagnostics-<formatted suffix>'.
+ 'git-diagnostics-<formatted-suffix>'.
+
Without `mode` specified, the diagnostic archive will contain the default set of
statistics reported by `git diagnose`. An optional `mode` value may be specified
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 3ab42a19ca..504b8a8143 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -23,8 +23,9 @@ the "offline" transfer of Git objects without an active "server"
sitting on the other side of the network connection.
They can be used to create both incremental and full backups of a
-repository, and to relay the state of the references in one repository
-to another.
+repository (see the "full backup" example in "EXAMPLES"), and to relay
+the state of the references in one repository to another (see the second
+example).
Git commands that fetch or otherwise "read" via protocols such as
`ssh://` and `https://` can also operate on bundle files. It is
@@ -34,8 +35,6 @@ contained within it with linkgit:git-ls-remote[1]. There's no
corresponding "write" support, i.e.a 'git push' into a bundle is not
supported.
-See the "EXAMPLES" section below for examples of how to use bundles.
-
BUNDLE FORMAT
-------------
@@ -132,7 +131,7 @@ SPECIFYING REFERENCES
---------------------
Revisions must be accompanied by reference names to be packaged in a
-bundle.
+bundle. Alternatively `--all` can be used to package all refs.
More than one reference may be packaged, and more than one set of prerequisite objects can
be specified. The objects packaged are those not contained in the
@@ -203,8 +202,6 @@ It is okay to err on the side of caution, causing the bundle file
to contain objects already in the destination, as these are ignored
when unpacking at the destination.
-If you want to match `git clone --mirror`, which would include your
-refs such as `refs/remotes/*`, use `--all`.
If you want to provide the same set of refs that a clone directly
from the source repository would get, use `--branches --tags` for
the `<git-rev-list-args>`.
@@ -216,8 +213,34 @@ bundle.
EXAMPLES
--------
-Assume you want to transfer the history from a repository R1 on machine A
-to another repository R2 on machine B.
+We'll discuss two cases:
+
+1. Taking a full backup of a repository
+2. Transferring the history of a repository to another machine when the
+ two machines have no direct connection
+
+First let's consider a full backup of the repository. The following
+command will take a full backup of the repository in the sense that all
+refs are included in the bundle:
+
+----------------
+$ git bundle create backup.bundle --all
+----------------
+
+But note again that this is only for the refs, i.e. you will only
+include refs and commits reachable from those refs. You will not
+include other local state, such as the contents of the index, working
+tree, the stash, per-repository configuration, hooks, etc.
+
+You can later recover that repository by using for example
+linkgit:git-clone[1]:
+
+----------------
+$ git clone backup.bundle <new directory>
+----------------
+
+For the next example, assume you want to transfer the history from a
+repository R1 on machine A to another repository R2 on machine B.
For whatever reason, direct connection between A and B is not allowed,
but we can move data from A to B via some mechanism (CD, email, etc.).
We want to update R2 with development made on the branch master in R1.
@@ -321,6 +344,24 @@ You can also see what references it offers:
$ git ls-remote mybundle
----------------
+DISCUSSION
+----------
+
+A naive way to make a full backup of a repository is to use something to
+the effect of `cp -r <repo> <destination>`. This is discouraged since
+the repository could be written to during the copy operation. In turn
+some files at `<destination>` could be corrupted.
+
+This is why it is recommended to use Git tooling for making repository
+backups, either with this command or with e.g. linkgit:git-clone[1].
+But keep in mind that these tools will not help you backup state other
+than refs and commits. In other words they will not help you backup
+contents of the index, working tree, the stash, per-repository
+configuration, hooks, etc.
+
+See also linkgit:gitfaq[7], section "TRANSFERS" for a discussion of the
+problems associated with file syncing across systems.
+
FILE FORMAT
-----------
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index bd95a6c10a..d5890ae368 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -270,9 +270,9 @@ BATCH OUTPUT
------------
If `--batch` or `--batch-check` is given, `cat-file` will read objects
-from stdin, one per line, and print information about them. By default,
-the whole line is considered as an object, as if it were fed to
-linkgit:git-rev-parse[1].
+from stdin, one per line, and print information about them in the same
+order as they have been read. By default, the whole line is
+considered as an object, as if it were fed to linkgit:git-rev-parse[1].
When `--batch-command` is given, `cat-file` will read commands from stdin,
one per line, and print information based on the command given. With
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 6e4f3aaf34..cb5a6c8f33 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -29,7 +29,7 @@ OPTIONS
--stdin::
Read pathnames from the standard input, one per line,
- instead of from the command-line.
+ instead of from the command line.
-z::
The output format is modified to be machine-parsable.
@@ -38,7 +38,7 @@ OPTIONS
--source=<tree-ish>::
Check attributes against the specified tree-ish. It is common to
- specify the source tree by naming a commit, branch or tag associated
+ specify the source tree by naming a commit, branch, or tag associated
with it.
\--::
@@ -60,7 +60,7 @@ unless `-z` is in effect, in which case NUL is used as delimiter:
<path> is the path of a file being queried, <attribute> is an attribute
-being queried and <info> can be either:
+being queried, and <info> can be either:
'unspecified';; when the attribute is not defined for the path.
'unset';; when the attribute is defined as false.
diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt
index 2892799e32..3e3b4e3446 100644
--- a/Documentation/git-check-ignore.txt
+++ b/Documentation/git-check-ignore.txt
@@ -50,7 +50,7 @@ linkgit:gitignore[5].
with a NUL character instead of a linefeed character.
-n, --non-matching::
- Show given paths which don't match any pattern. This only
+ Show given paths which don't match any pattern. This only
makes sense when `--verbose` is enabled, otherwise it would
not be possible to distinguish between paths which match a
pattern and those which don't.
diff --git a/Documentation/git-check-mailmap.txt b/Documentation/git-check-mailmap.txt
index 02f4418323..966c91c46a 100644
--- a/Documentation/git-check-mailmap.txt
+++ b/Documentation/git-check-mailmap.txt
@@ -15,10 +15,10 @@ SYNOPSIS
DESCRIPTION
-----------
-For each ``Name $$<user@host>$$'' or ``$$<user@host>$$'' from the command-line
-or standard input (when using `--stdin`), look up the person's canonical name
-and email address (see "Mapping Authors" below). If found, print them;
-otherwise print the input as-is.
+For each ``Name $$<user@host>$$'', ``$$<user@host>$$'', or ``$$user@host$$''
+from the command-line or standard input (when using `--stdin`), look up the
+person's canonical name and email address (see "Mapping Authors" below). If
+found, print them; otherwise print the input as-is.
OPTIONS
@@ -27,6 +27,16 @@ OPTIONS
Read contacts, one per line, from the standard input after exhausting
contacts provided on the command-line.
+--mailmap-file=<file>::
+ In addition to any configured mailmap files, read the specified
+ mailmap file. Entries in this file take precedence over entries in
+ either the default mailmap file or any configured mailmap file.
+
+--mailmap-blob=<blob>::
+ Like `--mailmap-file`, but consider the value as a reference to a
+ blob in the repository. If both `--mailmap-file` and
+ `--mailmap-blob` are specified, entries in `--mailmap-file` will
+ take precedence.
OUTPUT
------
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index ee6a4144fb..2aacfd1808 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -48,7 +48,7 @@ Git imposes the following rules on how references are named:
. They cannot begin or end with a slash `/` or contain multiple
consecutive slashes (see the `--normalize` option below for an
- exception to this rule)
+ exception to this rule).
. They cannot end with a dot `.`.
@@ -85,7 +85,7 @@ The rule `git check-ref-format --branch $name` implements
may be stricter than what `git check-ref-format refs/heads/$name`
says (e.g. a dash may appear at the beginning of a ref component,
but it is explicitly forbidden at the beginning of a branch name).
-When run with `--branch` option in a repository, the input is first
+When run with the `--branch` option in a repository, the input is first
expanded for the ``previous checkout syntax''
`@{-n}`. For example, `@{-1}` is a way to refer the last thing that
was checked out using "git switch" or "git checkout" operation.
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index 01dbd5cbf5..faf8d6ca36 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -18,7 +18,7 @@ SYNOPSIS
DESCRIPTION
-----------
-Will copy all files listed from the index to the working directory
+Copies all listed files from the index to the working directory
(not overwriting existing files).
OPTIONS
@@ -53,11 +53,11 @@ OPTIONS
--stage=<number>|all::
Instead of checking out unmerged entries, copy out the
- files from named stage. <number> must be between 1 and 3.
+ files from the named stage. <number> must be between 1 and 3.
Note: --stage=all automatically implies --temp.
--temp::
- Instead of copying the files to the working directory
+ Instead of copying the files to the working directory,
write the content to temporary files. The temporary name
associations will be written to stdout.
@@ -66,8 +66,8 @@ OPTIONS
set.
--stdin::
- Instead of taking list of paths from the command line,
- read list of paths from the standard input. Paths are
+ Instead of taking a list of paths from the command line,
+ read the list of paths from the standard input. Paths are
separated by LF (i.e. one path per line) by default.
-z::
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 4af0904f47..bf26655764 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -12,8 +12,10 @@ SYNOPSIS
'git checkout' [-q] [-f] [-m] --detach [<branch>]
'git checkout' [-q] [-f] [-m] [--detach] <commit>
'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new-branch>] [<start-point>]
-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...
-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' [-f] <tree-ish> [--] <pathspec>...
+'git checkout' [-f] <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>...
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]
'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]
DESCRIPTION
@@ -41,7 +43,7 @@ $ git checkout -b <branch> --track <remote>/<branch>
You could omit `<branch>`, in which case the command degenerates to
"check out the current branch", which is a glorified no-op with
rather expensive side-effects to show only the tracking information,
-if exists, for the current branch.
+if it exists, for the current branch.
'git checkout' -b|-B <new-branch> [<start-point>]::
@@ -61,7 +63,9 @@ $ git checkout <branch>
------------
+
that is to say, the branch is not reset/created unless "git checkout" is
-successful.
+successful (e.g., when the branch is in use in another worktree, not
+just the current branch stays the same, but the branch is not reset to
+the start-point, either).
'git checkout' --detach [<branch>]::
'git checkout' [--detach] <commit>::
@@ -213,7 +217,7 @@ variable.
below for details.
--orphan <new-branch>::
- Create a new 'orphan' branch, named `<new-branch>`, started from
+ Create a new unborn branch, named `<new-branch>`, started from
`<start-point>` and switch to it. The first commit made on this
new branch will have no parents and it will be the root of a new
history totally disconnected from all the other branches and
@@ -260,7 +264,8 @@ and mark the resolved paths with `git add` (or `git rm` if the merge
should result in deletion of the path).
+
When checking out paths from the index, this option lets you recreate
-the conflicted merge in the specified paths.
+the conflicted merge in the specified paths. This option cannot be
+used when checking out paths from a tree-ish.
+
When switching branches with `--merge`, staged changes may be lost.
@@ -285,10 +290,10 @@ Note that this option uses the no overlay mode by default (see also
`--overlay`), and currently doesn't support overlay mode.
--ignore-other-worktrees::
- `git checkout` refuses when the wanted ref is already checked
- out by another worktree. This option makes it check the ref
- out anyway. In other words, the ref can be held by more than one
- worktree.
+ `git checkout` refuses when the wanted branch is already checked
+ out or otherwise in use by another worktree. This option makes
+ it check the branch out anyway. In other words, the branch can
+ be in use by more than one worktree.
--overwrite-ignore::
--no-overwrite-ignore::
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fdcad3d200..81ace900fc 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -131,20 +131,36 @@ effect to your index in a row.
even without this option. Note also, that use of this option only
keeps commits that were initially empty (i.e. the commit recorded the
same tree as its parent). Commits which are made empty due to a
- previous commit are dropped. To force the inclusion of those commits
- use `--keep-redundant-commits`.
+ previous commit will cause the cherry-pick to fail. To force the
+ inclusion of those commits, use `--empty=keep`.
--allow-empty-message::
By default, cherry-picking a commit with an empty message will fail.
This option overrides that behavior, allowing commits with empty
messages to be cherry picked.
+--empty=(drop|keep|stop)::
+ How to handle commits being cherry-picked that are redundant with
+ changes already in the current history.
++
+--
+`drop`;;
+ The commit will be dropped.
+`keep`;;
+ The commit will be kept. Implies `--allow-empty`.
+`stop`;;
+ The cherry-pick will stop when the commit is applied, allowing
+ you to examine the commit. This is the default behavior.
+--
++
+Note that `--empty=drop` and `--empty=stop` only specify how to handle a
+commit that was not initially empty, but rather became empty due to a previous
+commit. Commits that were initially empty will still cause the cherry-pick to
+fail unless one of `--empty=keep` or `--allow-empty` are specified.
++
+
--keep-redundant-commits::
- If a commit being cherry picked duplicates a commit already in the
- current history, it will become empty. By default these
- redundant commits cause `cherry-pick` to stop so the user can
- examine the commit. This option overrides that behavior and
- creates an empty commit object. Implies `--allow-empty`.
+ Deprecated synonym for `--empty=keep`.
--strategy=<strategy>::
Use the given merge strategy. Should only be used once.
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 5e1a3d5148..fd17165416 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -37,7 +37,7 @@ OPTIONS
--force::
If the Git configuration variable clean.requireForce is not set
to false, 'git clean' will refuse to delete files or directories
- unless given -f or -i. Git will refuse to modify untracked
+ unless given -f. Git will refuse to modify untracked
nested git repositories (directories with a .git subdirectory)
unless a second -f is given.
@@ -45,10 +45,14 @@ OPTIONS
--interactive::
Show what would be done and clean files interactively. See
``Interactive mode'' for details.
+ Configuration variable `clean.requireForce` is ignored, as
+ this mode gives its own safety protection by going interactive.
-n::
--dry-run::
Don't actually remove anything, just show what would be done.
+ Configuration variable `clean.requireForce` is ignored, as
+ nothing will be deleted anyway.
-q::
--quiet::
@@ -103,7 +107,7 @@ filter by pattern::
This shows the files and directories to be deleted and issues an
"Input ignore patterns>>" prompt. You can input space-separated
patterns to exclude files and directories from deletion.
- E.g. "*.c *.h" will excludes files end with ".c" and ".h" from
+ E.g. "*.c *.h" will exclude files ending with ".c" and ".h" from
deletion. When you are satisfied with the filtered result, press
ENTER (empty) back to the main menu.
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index c37c4a37f7..7acb4cb176 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -8,15 +8,15 @@ git-clone - Clone a repository into a new directory
SYNOPSIS
--------
-[verse]
-'git clone' [--template=<template-directory>]
+[synopsis]
+git clone [--template=<template-directory>]
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--dissociate] [--separate-git-dir <git-dir>]
[--depth <depth>] [--[no-]single-branch] [--no-tags]
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
[--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
- [--filter=<filter> [--also-filter-submodules]] [--] <repository>
+ [--filter=<filter-spec>] [--also-filter-submodules]] [--] <repository>
[<directory>]
DESCRIPTION
@@ -31,7 +31,7 @@ currently active branch.
After the clone, a plain `git fetch` without arguments will update
all the remote-tracking branches, and a `git pull` without
arguments will in addition merge the remote master branch into the
-current master branch, if any (this is untrue when "--single-branch"
+current master branch, if any (this is untrue when `--single-branch`
is given; see below).
This default configuration is achieved by creating references to
@@ -42,17 +42,17 @@ configuration variables.
OPTIONS
-------
--l::
---local::
+`-l`::
+`--local`::
When the repository to clone from is on a local machine,
this flag bypasses the normal "Git aware" transport
mechanism and clones the repository by making a copy of
- HEAD and everything under objects and refs directories.
+ `HEAD` and everything under objects and refs directories.
The files under `.git/objects/` directory are hardlinked
to save space when possible.
+
If the repository is specified as a local path (e.g., `/path/to/repo`),
-this is the default, and --local is essentially a no-op. If the
+this is the default, and `--local` is essentially a no-op. If the
repository is specified as a URL, then this flag is ignored (and we
never use the local optimizations). Specifying `--no-local` will
override the default when `/path/to/repo` is given, using the regular
@@ -64,17 +64,17 @@ 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`.
+source repository, similar to running `cp -r <src> <dst>` while modifying
+_<src>_.
---no-hardlinks::
+`--no-hardlinks`::
Force the cloning process from a repository on a local
filesystem to copy the files under the `.git/objects`
directory instead of using hardlinks. This may be desirable
if you are trying to make a back-up of your repository.
--s::
---shared::
+`-s`::
+`--shared`::
When the repository to clone is on the local machine,
instead of using hard links, automatically setup
`.git/objects/info/alternates` to share the objects
@@ -101,10 +101,10 @@ If you want to break the dependency of a repository cloned with `--shared` on
its source repository, you can simply run `git repack -a` to copy all
objects from the source repository into a pack in the cloned repository.
---reference[-if-able] <repository>::
- If the reference repository is on the local machine,
+`--reference[-if-able] <repository>`::
+ If the reference _<repository>_ is on the local machine,
automatically setup `.git/objects/info/alternates` to
- obtain objects from the reference repository. Using
+ obtain objects from the reference _<repository>_. Using
an already existing repository as an alternate will
require fewer objects to be copied from the repository
being cloned, reducing network and local storage costs.
@@ -115,7 +115,7 @@ objects from the source repository into a pack in the cloned repository.
*NOTE*: see the NOTE for the `--shared` option, and also the
`--dissociate` option.
---dissociate::
+`--dissociate`::
Borrow the objects from reference repositories specified
with the `--reference` options only to reduce network
transfer, and stop borrowing from them after a clone is made
@@ -126,43 +126,46 @@ objects from the source repository into a pack in the cloned repository.
same repository, and this option can be used to stop the
borrowing.
--q::
---quiet::
+`-q`::
+`--quiet`::
Operate quietly. Progress is not reported to the standard
error stream.
--v::
---verbose::
+`-v`::
+`--verbose`::
Run verbosely. Does not affect the reporting of progress status
to the standard error stream.
---progress::
+`--progress`::
Progress status is reported on the standard error stream
by default when it is attached to a terminal, unless `--quiet`
is specified. This flag forces progress status even if the
standard error stream is not directed to a terminal.
---server-option=<option>::
+`--server-option=<option>`::
Transmit the given string to the server when communicating using
protocol version 2. The given string must not contain a NUL or LF
character. The server's handling of server options, including
unknown ones, is server-specific.
When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line.
+ When no ++--server-option=++__<option>__ is given from the command
+ line, the values of configuration variable `remote.<name>.serverOption`
+ are used instead.
--n::
---no-checkout::
- No checkout of HEAD is performed after the clone is complete.
+`-n`::
+`--no-checkout`::
+ No checkout of `HEAD` is performed after the clone is complete.
---[no-]reject-shallow::
+`--`[`no-`]`reject-shallow`::
Fail if the source repository is a shallow repository.
- The 'clone.rejectShallow' configuration variable can be used to
+ The `clone.rejectShallow` configuration variable can be used to
specify the default.
---bare::
+`--bare`::
Make a 'bare' Git repository. That is, instead of
- creating `<directory>` and placing the administrative
- files in `<directory>/.git`, make the `<directory>`
+ creating _<directory>_ and placing the administrative
+ files in `<directory>/.git`, make the _<directory>_
itself the `$GIT_DIR`. This obviously implies the `--no-checkout`
because there is nowhere to check out the working tree.
Also the branch heads at the remote are copied directly
@@ -171,28 +174,28 @@ objects from the source repository into a pack in the cloned repository.
used, neither remote-tracking branches nor the related
configuration variables are created.
---sparse::
+`--sparse`::
Employ a sparse-checkout, with only files in the toplevel
directory initially being present. The
linkgit:git-sparse-checkout[1] command can be used to grow the
working directory as needed.
---filter=<filter-spec>::
+`--filter=<filter-spec>`::
Use the partial clone feature and request that the server sends
a subset of reachable objects according to a given object filter.
- When using `--filter`, the supplied `<filter-spec>` is used for
+ When using `--filter`, the supplied _<filter-spec>_ is used for
the partial clone filter. For example, `--filter=blob:none` will
filter out all blobs (file contents) until needed by Git. Also,
`--filter=blob:limit=<size>` will filter out all blobs of size
- at least `<size>`. For more details on filter specifications, see
+ at least _<size>_. For more details on filter specifications, see
the `--filter` option in linkgit:git-rev-list[1].
---also-filter-submodules::
+`--also-filter-submodules`::
Also apply the partial clone filter to any submodules in the repository.
Requires `--filter` and `--recurse-submodules`. This can be turned on by
default by setting the `clone.filterSubmodules` config option.
---mirror::
+`--mirror`::
Set up a mirror of the source repository. This implies `--bare`.
Compared to `--bare`, `--mirror` not only maps local branches of the
source to local branches of the target, it maps all refs (including
@@ -200,37 +203,37 @@ objects from the source repository into a pack in the cloned repository.
that all these refs are overwritten by a `git remote update` in the
target repository.
--o <name>::
---origin <name>::
+`-o` _<name>_::
+`--origin` _<name>_::
Instead of using the remote name `origin` to keep track of the upstream
- repository, use `<name>`. Overrides `clone.defaultRemoteName` from the
+ repository, use _<name>_. Overrides `clone.defaultRemoteName` from the
config.
--b <name>::
---branch <name>::
- Instead of pointing the newly created HEAD to the branch pointed
- to by the cloned repository's HEAD, point to `<name>` branch
+`-b` _<name>_::
+`--branch` _<name>_::
+ Instead of pointing the newly created `HEAD` to the branch pointed
+ to by the cloned repository's `HEAD`, point to _<name>_ branch
instead. In a non-bare repository, this is the branch that will
be checked out.
- `--branch` can also take tags and detaches the HEAD at that commit
+ `--branch` can also take tags and detaches the `HEAD` at that commit
in the resulting repository.
--u <upload-pack>::
---upload-pack <upload-pack>::
+`-u` _<upload-pack>_::
+`--upload-pack` _<upload-pack>_::
When given, and the repository to clone from is accessed
via ssh, this specifies a non-default path for the command
run on the other end.
---template=<template-directory>::
+`--template=<template-directory>`::
Specify the directory from which templates will be used;
(See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
--c <key>=<value>::
---config <key>=<value>::
+`-c` `<key>=<value>`::
+`--config` `<key>=<value>`::
Set a configuration variable in the newly-created repository;
this takes effect immediately after the repository is
initialized, but before the remote history is fetched or any
- files checked out. The key is in the same format as expected by
+ files checked out. The _<key>_ is in the same format as expected by
linkgit:git-config[1] (e.g., `core.eol=true`). If multiple
values are given for the same key, each value will be written to
the config file. This makes it safe, for example, to add
@@ -242,32 +245,32 @@ Configuration variables known to not take effect are:
`remote.<name>.mirror` and `remote.<name>.tagOpt`. Use the
corresponding `--mirror` and `--no-tags` options instead.
---depth <depth>::
+`--depth <depth>`::
Create a 'shallow' clone with a history truncated to the
specified number of commits. Implies `--single-branch` unless
`--no-single-branch` is given to fetch the histories near the
tips of all branches. If you want to clone submodules shallowly,
also pass `--shallow-submodules`.
---shallow-since=<date>::
+`--shallow-since=<date>`::
Create a shallow clone with a history after the specified time.
---shallow-exclude=<revision>::
+`--shallow-exclude=<ref>`::
Create a shallow clone with a history, excluding commits
reachable from a specified remote branch or tag. This option
can be specified multiple times.
---[no-]single-branch::
+`--[no-]single-branch`::
Clone only the history leading to the tip of a single branch,
either specified by the `--branch` option or the primary
branch remote's `HEAD` points at.
Further fetches into the resulting repository will only update the
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
+ 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-tags::
+`--no-tags`::
Don't clone any tags, and set
`remote.<remote>.tagOpt=--no-tags` in the config, ensuring
that future `git pull` and `git fetch` operations won't follow
@@ -279,13 +282,13 @@ maintain a branch with no references other than a single cloned
branch. This is useful e.g. to maintain minimal clones of the default
branch of some repository for search indexing.
---recurse-submodules[=<pathspec>]::
+`--recurse-submodules[=<pathspec>]`::
After the clone is created, initialize and clone submodules
- within based on the provided pathspec. If no pathspec is
+ within based on the provided _<pathspec>_. If no `=<pathspec>` is
provided, all submodules are initialized and cloned.
This option can be given multiple times for pathspecs consisting
of multiple entries. The resulting clone has `submodule.active` set to
- the provided pathspec, or "." (meaning all submodules) if no
+ the provided pathspec, or "`.`" (meaning all submodules) if no
pathspec is provided.
+
Submodules are initialized and cloned using their default settings. This is
@@ -295,42 +298,48 @@ the clone is finished. This option is ignored if the cloned repository does
not have a worktree/checkout (i.e. if any of `--no-checkout`/`-n`, `--bare`,
or `--mirror` is given)
---[no-]shallow-submodules::
+`--[no-]shallow-submodules`::
All submodules which are cloned will be shallow with a depth of 1.
---[no-]remote-submodules::
+`--[no-]remote-submodules`::
All submodules which are cloned will use the status of the submodule's
remote-tracking branch to update the submodule, rather than the
superproject's recorded SHA-1. Equivalent to passing `--remote` to
`git submodule update`.
---separate-git-dir=<git-dir>::
+`--separate-git-dir=<git-dir>`::
Instead of placing the cloned repository where it is supposed
to be, place the cloned repository at the specified directory,
then make a filesystem-agnostic Git symbolic link to there.
The result is Git repository can be separated from working
tree.
--j <n>::
---jobs <n>::
+`--ref-format=<ref-format>`::
+
+Specify the given ref storage format for the repository. The valid values are:
++
+include::ref-storage-format.txt[]
+
+`-j` _<n>_::
+`--jobs` _<n>_::
The number of submodules fetched at the same time.
Defaults to the `submodule.fetchJobs` option.
-<repository>::
- The (possibly remote) repository to clone from. See the
+_<repository>_::
+ The (possibly remote) _<repository>_ to clone from. See the
<<URLS,GIT URLS>> section below for more information on specifying
repositories.
-<directory>::
+_<directory>_::
The name of a new directory to clone into. The "humanish"
- part of the source repository is used if no directory is
+ part of the source repository is used if no _<directory>_ is
explicitly given (`repo` for `/path/to/repo.git` and `foo`
for `host.xz:foo/.git`). Cloning into an existing directory
is only allowed if the directory is empty.
---bundle-uri=<uri>::
+`--bundle-uri=<uri>`::
Before fetching from the remote, fetch a bundle from the given
- `<uri>` and unbundle the data into the local repository. The refs
+ _<uri>_ and unbundle the data into the local repository. The refs
in the bundle will be stored under the hidden `refs/bundle/*`
namespace. This option is incompatible with `--depth`,
`--shallow-since`, and `--shallow-exclude`.
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index c8dbceba01..903b16830e 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -13,7 +13,7 @@ SYNOPSIS
'git commit-graph write' [--object-dir <dir>] [--append]
[--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]
[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]
- <split options>
+ <split-options>
DESCRIPTION
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 225c6c9f2e..c822113c11 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git commit' [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
- [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
+ [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
[--date=<date>] [--cleanup=<mode>] [--[no-]status]
@@ -347,6 +347,8 @@ The possible options are:
- 'normal' - Shows untracked files and directories
- 'all' - Also shows individual files in untracked directories.
+All usual spellings for Boolean value `true` are taken as `normal`
+and `false` as `no`.
The default can be changed using the status.showUntrackedFiles
configuration variable documented in linkgit:git-config[1].
--
@@ -541,7 +543,7 @@ DISCUSSION
----------
Though not required, it's a good idea to begin the commit message
-with a single short (less than 50 character) line summarizing the
+with a single short (no more than 50 characters) line summarizing the
change, followed by a blank line and then a more thorough description.
The text up to the first blank line in a commit message is treated
as the commit title, and that title is used throughout Git.
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index b1caac887a..3e420177c1 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -9,21 +9,14 @@ git-config - Get and set repository or global options
SYNOPSIS
--------
[verse]
-'git config' [<file-option>] [--type=<type>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]]
-'git config' [<file-option>] [--type=<type>] --add <name> <value>
-'git config' [<file-option>] [--type=<type>] [--fixed-value] --replace-all <name> <value> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get <name> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get-all <name> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] [--name-only] --get-regexp <name-regex> [<value-pattern>]
-'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch <name> <URL>
-'git config' [<file-option>] [--fixed-value] --unset <name> [<value-pattern>]
-'git config' [<file-option>] [--fixed-value] --unset-all <name> [<value-pattern>]
-'git config' [<file-option>] --rename-section <old-name> <new-name>
-'git config' [<file-option>] --remove-section <name>
-'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
-'git config' [<file-option>] --get-color <name> [<default>]
+'git config list' [<file-option>] [<display-option>] [--includes]
+'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>
+'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>
+'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>
+'git config rename-section' [<file-option>] <old-name> <new-name>
+'git config remove-section' [<file-option>] <name>
+'git config edit' [<file-option>]
'git config' [<file-option>] --get-colorbool <name> [<stdout-is-tty>]
-'git config' [<file-option>] -e | --edit
DESCRIPTION
-----------
@@ -31,7 +24,7 @@ You can query/set/replace/unset options with this command. The name is
actually the section and the key separated by a dot, and the value will be
escaped.
-Multiple lines can be added to an option by using the `--add` option.
+Multiple lines can be added to an option by using the `--append` option.
If you want to update or unset an option which can occur on multiple
lines, a `value-pattern` (which is an extended regular expression,
unless the `--fixed-value` option is given) needs to be given. Only the
@@ -74,6 +67,42 @@ On success, the command returns the exit code 0.
A list of all available configuration variables can be obtained using the
`git help --config` command.
+COMMANDS
+--------
+
+list::
+ List all variables set in config file, along with their values.
+
+get::
+ Emits the value of the specified key. If key is present multiple times
+ in the configuration, emits the last value. If `--all` is specified,
+ emits all values associated with key. Returns error code 1 if key is
+ not present.
+
+set::
+ Set value for one or more config options. By default, this command
+ refuses to write multi-valued config options. Passing `--all` will
+ replace all multi-valued config options with the new value, whereas
+ `--value=` will replace all config options whose values match the given
+ pattern.
+
+unset::
+ Unset value for one or more config options. By default, this command
+ refuses to unset multi-valued keys. Passing `--all` will unset all
+ multi-valued config options, whereas `--value` will unset all config
+ options whose values match the given pattern.
+
+rename-section::
+ Rename the given section to a new name.
+
+remove-section::
+ Remove the given section from the configuration file.
+
+edit::
+ Opens an editor to modify the specified config file; either
+ `--system`, `--global`, `--local` (default), `--worktree`, or
+ `--file <config-file>`.
+
[[OPTIONS]]
OPTIONS
-------
@@ -82,32 +111,37 @@ OPTIONS
Default behavior is to replace at most one line. This replaces
all lines matching the key (and optionally the `value-pattern`).
---add::
+--append::
Adds a new line to the option without altering any existing
- values. This is the same as providing '^$' as the `value-pattern`
- in `--replace-all`.
-
---get::
- Get the value for a given key (optionally filtered by a regex
- matching the value). Returns error code 1 if the key was not
- found and the last value if multiple key values were found.
-
---get-all::
- Like get, but returns all values for a multi-valued key.
-
---get-regexp::
- Like --get-all, but interprets the name as a regular expression and
- writes out the key names. Regular expression matching is currently
- case-sensitive and done against a canonicalized version of the key
- in which section and variable names are lowercased, but subsection
- names are not.
-
---get-urlmatch <name> <URL>::
- When given a two-part name section.key, the value for
- section.<URL>.key whose <URL> part matches the best to the
+ values. This is the same as providing '--value=^$' in `set`.
+
+--comment <message>::
+ Append a comment at the end of new or modified lines.
+
+ If _<message>_ begins with one or more whitespaces followed
+ by "#", it is used as-is. If it begins with "#", a space is
+ prepended before it is used. Otherwise, a string " # " (a
+ space followed by a hash followed by a space) is prepended
+ to it. And the resulting string is placed immediately after
+ the value defined for the variable. The _<message>_ must
+ not contain linefeed characters (no multi-line comments are
+ permitted).
+
+--all::
+ With `get`, return all values for a multi-valued key.
+
+--regexp::
+ With `get`, interpret the name as a regular expression. Regular
+ expression matching is currently case-sensitive and done against a
+ canonicalized version of the key in which section and variable names
+ are lowercased, but subsection names are not.
+
+--url=<URL>::
+ When given a two-part <name> as <section>.<key>, the value for
+ <section>.<URL>.<key> whose <URL> part matches the best to the
given URL is returned (if no such key exists, the value for
- section.key is used as a fallback). When given just the
- section as name, do so for all the keys in the section and
+ <section>.<key> is used as a fallback). When given just the
+ <section> as name, do so for all the keys in the section and
list them. Returns error code 1 if no value is found.
--global::
@@ -166,22 +200,6 @@ See also <<FILES>>.
section in linkgit:gitrevisions[7] for a more complete list of
ways to spell blob names.
---remove-section::
- Remove the given section from the configuration file.
-
---rename-section::
- Rename the given section to a new name.
-
---unset::
- Remove the line matching the key from config file.
-
---unset-all::
- Remove all lines matching the key from config file.
-
--l::
---list::
- List all variables set in config file, along with their values.
-
--fixed-value::
When used with the `value-pattern` argument, treat `value-pattern` as
an exact string instead of a regular expression. This will restrict
@@ -236,8 +254,8 @@ Valid `<type>`'s include:
contain line breaks.
--name-only::
- Output only the names of config variables for `--list` or
- `--get-regexp`.
+ Output only the names of config variables for `list` or
+ `get`.
--show-origin::
Augment the output of all queried config options with the
@@ -261,22 +279,6 @@ Valid `<type>`'s include:
When the color setting for `name` is undefined, the command uses
`color.ui` as fallback.
---get-color <name> [<default>]::
-
- Find the color configured for `name` (e.g. `color.diff.new`) and
- output it as the ANSI color escape sequence to the standard
- output. The optional `default` parameter is used instead, if
- there is no color configured for `name`.
-+
-`--type=color [--default=<default>]` is preferred over `--get-color`
-(but note that `--get-color` will omit the trailing newline printed by
-`--type=color`).
-
--e::
---edit::
- Opens an editor to modify the specified config file; either
- `--system`, `--global`, or repository (default).
-
--[no-]includes::
Respect `include.*` directives in config files when looking up
values. Defaults to `off` when a specific file is given (e.g.,
@@ -284,14 +286,64 @@ Valid `<type>`'s include:
config files.
--default <value>::
- When using `--get`, and the requested variable is not found, behave as if
- <value> were the value assigned to the that variable.
+ When using `get`, and the requested variable is not found, behave as if
+ <value> were the value assigned to that variable.
+
+DEPRECATED MODES
+----------------
+
+The following modes have been deprecated in favor of subcommands. It is
+recommended to migrate to the new syntax.
+
+'git config <name>'::
+ Replaced by `git config get <name>`.
+
+'git config <name> <value> [<value-pattern>]'::
+ Replaced by `git config set [--value=<pattern>] <name> <value>`.
+
+-l::
+--list::
+ Replaced by `git config list`.
+
+--get <name> [<value-pattern>]::
+ Replaced by `git config get [--value=<pattern>] <name>`.
+
+--get-all <name> [<value-pattern>]::
+ Replaced by `git config get [--value=<pattern>] --all <name>`.
+
+--get-regexp <name-regexp>::
+ Replaced by `git config get --all --show-names --regexp <name-regexp>`.
+
+--get-urlmatch <name> <URL>::
+ Replaced by `git config get --all --show-names --url=<URL> <name>`.
+
+--get-color <name> [<default>]::
+ Replaced by `git config get --type=color [--default=<default>] <name>`.
+
+--add <name> <value>::
+ Replaced by `git config set --append <name> <value>`.
+
+--unset <name> [<value-pattern>]::
+ Replaced by `git config unset [--value=<pattern>] <name>`.
+
+--unset-all <name> [<value-pattern>]::
+ Replaced by `git config unset [--value=<pattern>] --all <name>`.
+
+--rename-section <old-name> <new-name>::
+ Replaced by `git config rename-section <old-name> <new-name>`.
+
+--remove-section <name>::
+ Replaced by `git config remove-section <name>`.
+
+-e::
+--edit::
+ Replaced by `git config edit`.
CONFIGURATION
-------------
`pager.config` is only respected when listing configuration, i.e., when
-using `--list` or any of the `--get-*` which may return multiple results.
-The default is to use a pager.
+using `list` or `get` which may return multiple results. The default is to use
+a pager.
[[FILES]]
FILES
@@ -333,8 +385,8 @@ precedence over values read earlier. When multiple values are taken then all
values of a key from all files will be used.
By default, options are only written to the repository specific
-configuration file. Note that this also affects options like `--replace-all`
-and `--unset`. *'git config' will only ever change one file at a time*.
+configuration file. Note that this also affects options like `set`
+and `unset`. *'git config' will only ever change one file at a time*.
You can limit which configuration sources are read from or written to by
specifying the path of a file with the `--file` option, or by specifying a
@@ -469,7 +521,7 @@ Given a .git/config like this:
you can set the filemode to true with
------------
-% git config core.filemode true
+% git config set core.filemode true
------------
The hypothetical proxy command entries actually have a postfix to discern
@@ -477,7 +529,7 @@ what URL they apply to. Here is how to change the entry for kernel.org
to "ssh".
------------
-% git config core.gitproxy '"ssh" for kernel.org' 'for kernel.org$'
+% git config set --value='for kernel.org$' core.gitproxy '"ssh" for kernel.org'
------------
This makes sure that only the key/value pair for kernel.org is replaced.
@@ -485,7 +537,7 @@ This makes sure that only the key/value pair for kernel.org is replaced.
To delete the entry for renames, do
------------
-% git config --unset diff.renames
+% git config unset diff.renames
------------
If you want to delete an entry for a multivar (like core.gitproxy above),
@@ -494,51 +546,45 @@ you have to provide a regex matching the value of exactly one line.
To query the value for a given key, do
------------
-% git config --get core.filemode
-------------
-
-or
-
-------------
-% git config core.filemode
+% git config get core.filemode
------------
or, to query a multivar:
------------
-% git config --get core.gitproxy "for kernel.org$"
+% git config get --value="for kernel.org$" core.gitproxy
------------
If you want to know all the values for a multivar, do:
------------
-% git config --get-all core.gitproxy
+% git config get --all --show-names core.gitproxy
------------
If you like to live dangerously, you can replace *all* core.gitproxy by a
new one with
------------
-% git config --replace-all core.gitproxy ssh
+% git config set --all core.gitproxy ssh
------------
However, if you really only want to replace the line for the default proxy,
i.e. the one without a "for ..." postfix, do something like this:
------------
-% git config core.gitproxy ssh '! for '
+% git config set --value='! for ' core.gitproxy ssh
------------
To actually match only values with an exclamation mark, you have to
------------
-% git config section.key value '[!]'
+% git config set --value='[!]' section.key value
------------
To add a new proxy, without altering any of the existing ones, use
------------
-% git config --add core.gitproxy '"proxy-command" for example.com'
+% git config set --append core.gitproxy '"proxy-command" for example.com'
------------
An example to use customized color from the configuration in your
@@ -546,8 +592,8 @@ script:
------------
#!/bin/sh
-WS=$(git config --get-color color.diff.whitespace "blue reverse")
-RESET=$(git config --get-color "" "reset")
+WS=$(git config get --type=color --default="blue reverse" color.diff.whitespace)
+RESET=$(git config get --type=color --default="reset" "")
echo "${WS}your whitespace color or blue reverse${RESET}"
------------
@@ -555,11 +601,11 @@ For URLs in `https://weak.example.com`, `http.sslVerify` is set to
false, while it is set to `true` for all others:
------------
-% git config --type=bool --get-urlmatch http.sslverify https://good.example.com
+% git config get --type=bool --url=https://good.example.com http.sslverify
true
-% git config --type=bool --get-urlmatch http.sslverify https://weak.example.com
+% git config get --type=bool --url=https://weak.example.com http.sslverify
false
-% git config --get-urlmatch http https://weak.example.com
+% git config get --url=https://weak.example.com http
http.cookieFile /tmp/cookie.txt
http.sslverify false
------------
diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt
index cb9b4d2e46..97f9f12610 100644
--- a/Documentation/git-count-objects.txt
+++ b/Documentation/git-count-objects.txt
@@ -12,7 +12,7 @@ SYNOPSIS
DESCRIPTION
-----------
-This counts the number of unpacked object files and disk space consumed by
+Counts the number of unpacked object files and disk space consumed by
them, to help you decide when it is a good time to repack.
@@ -20,7 +20,7 @@ OPTIONS
-------
-v::
--verbose::
- Report in more detail:
+ Provide more detailed reports:
+
count: the number of loose objects
+
@@ -33,7 +33,7 @@ size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
prune-packable: the number of loose objects that are also present in
the packs. These objects could be pruned using `git prune-packed`.
+
-garbage: the number of files in object database that are neither valid loose
+garbage: the number of files in the object database that are neither valid loose
objects nor valid packs
+
size-garbage: disk space consumed by garbage files, in KiB (unless -H is
diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt
index f473994a86..487cc557a8 100644
--- a/Documentation/git-credential-cache.txt
+++ b/Documentation/git-credential-cache.txt
@@ -16,7 +16,7 @@ DESCRIPTION
This command caches credentials for use by future Git programs.
The stored credentials are kept in memory of the cache-daemon
-process (instead of written to a file) and are forgotten after a
+process (instead of being written to a file) and are forgotten after a
configurable timeout. Credentials are forgotten sooner if the
cache-daemon dies, for example if the system restarts. The cache
is accessible over a Unix domain socket, restricted to the current
diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt
index 76b0798856..71864a8726 100644
--- a/Documentation/git-credential-store.txt
+++ b/Documentation/git-credential-store.txt
@@ -33,7 +33,7 @@ OPTIONS
Use `<path>` to lookup and store credentials. The file will have its
filesystem permissions set to prevent other users on the system
- from reading it, but will not be encrypted or otherwise
+ from reading it, but it will not be encrypted or otherwise
protected. If not specified, credentials will be searched for from
`~/.git-credentials` and `$XDG_CONFIG_HOME/git/credentials`, and
credentials will be written to `~/.git-credentials` if it exists, or
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index a220afed4f..e41493292f 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -8,7 +8,7 @@ git-credential - Retrieve and store user credentials
SYNOPSIS
--------
------------------
-'git credential' (fill|approve|reject)
+'git credential' (fill|approve|reject|capability)
------------------
DESCRIPTION
@@ -41,6 +41,9 @@ If the action is `reject`, git-credential will send the description to
any configured credential helpers, which may erase any stored
credentials matching the description.
+If the action is `capability`, git-credential will announce any capabilities
+it supports to standard output.
+
If the action is `approve` or `reject`, no output should be emitted.
TYPICAL USE OF GIT CREDENTIAL
@@ -94,7 +97,7 @@ unlocked) before it returned `password=secr3t`.
that `git credential` will ask for a new password in its next
invocation. In either case, `git credential` should be fed with
the credential description obtained from step (2) (which also
- contain the ones provided in step (1)).
+ contains the fields provided in step (1)).
[[IOFMT]]
INPUT/OUTPUT FORMAT
@@ -111,7 +114,9 @@ attribute per line. Each attribute is specified by a key-value pair,
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.
+contain any bytes except newline or NUL. A line, including the trailing
+newline, may not exceed 65535 bytes in order to allow implementations to
+parse efficiently.
Attributes with keys that end with C-style array brackets `[]` can have
multiple values. Each instance of a multi-valued attribute forms an
@@ -178,6 +183,61 @@ empty string.
Components which are missing from the URL (e.g., there is no
username in the example above) will be left unset.
+`authtype`::
+ This indicates that the authentication scheme in question should be used.
+ Common values for HTTP and HTTPS include `basic`, `bearer`, and `digest`,
+ although the latter is insecure and should not be used. If `credential`
+ is used, this may be set to an arbitrary string suitable for the protocol in
+ question (usually HTTP).
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`credential`::
+ The pre-encoded credential, suitable for the protocol in question (usually
+ HTTP). If this key is sent, `authtype` is mandatory, and `username` and
+ `password` are not used. For HTTP, Git concatenates the `authtype` value and
+ this value with a single space to determine the `Authorization` header.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`ephemeral`::
+ This boolean value indicates, if true, that the value in the `credential`
+ field should not be saved by the credential helper because its usefulness is
+ limited in time. For example, an HTTP Digest `credential` value is computed
+ using a nonce and reusing it will not result in successful authentication.
+ This may also be used for situations with short duration (e.g., 24-hour)
+ credentials. The default value is false.
++
+The credential helper will still be invoked with `store` or `erase` so that it
+can determine whether the operation was successful.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`state[]`::
+ This value provides an opaque state that will be passed back to this helper
+ if it is called again. Each different credential helper may specify this
+ once. The value should include a prefix unique to the credential helper and
+ should ignore values that don't match its prefix.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`continue`::
+ This is a boolean value, which, if enabled, indicates that this
+ authentication is a non-final part of a multistage authentication step. This
+ is common in protocols such as NTLM and Kerberos, where two rounds of client
+ authentication are required, and setting this flag allows the credential
+ helper to implement the multistage authentication step. This flag should
+ only be sent if a further stage is required; that is, if another round of
+ authentication is expected.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input. This attribute is 'one-way' from a credential helper to
+pass information to Git (or other programs invoking `git credential`).
+
`wwwauth[]`::
When an HTTP response is received by Git that includes one or more
@@ -189,7 +249,45 @@ 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.
+`capability[]`::
+ This signals that Git, or the helper, as appropriate, supports the capability
+ in question. This can be used to provide better, more specific data as part
+ of the protocol. A `capability[]` directive must precede any value depending
+ on it and these directives _should_ be the first item announced in the
+ protocol.
++
+There are two currently supported capabilities. The first is `authtype`, which
+indicates that the `authtype`, `credential`, and `ephemeral` values are
+understood. The second is `state`, which indicates that the `state[]` and
+`continue` values are understood.
++
+It is not obligatory to use the additional features just because the capability
+is supported, but they should not be provided without the capability.
+
+Unrecognised attributes and capabilities are silently discarded.
+
+[[CAPA-IOFMT]]
+CAPABILITY INPUT/OUTPUT FORMAT
+------------------------------
+
+For `git credential capability`, the format is slightly different. First, a
+`version 0` announcement is made to indicate the current version of the
+protocol, and then each capability is announced with a line like `capability
+authtype`. Credential helpers may also implement this format, again with the
+`capability` argument. Additional lines may be added in the future; callers
+should ignore lines which they don't understand.
+
+Because this is a new part of the credential helper protocol, older versions of
+Git, as well as some credential helpers, may not support it. If a non-zero
+exit status is received, or if the first line doesn't start with the word
+`version` and a space, callers should assume that no capabilities are supported.
+
+The intention of this format is to differentiate it from the credential output
+in an unambiguous way. It is possible to use very simple credential helpers
+(e.g., inline shell scripts) which always produce identical output. Using a
+distinct format allows users to continue to use this syntax without having to
+worry about correctly implementing capability advertisements or accidentally
+confusing callers querying for capabilities.
GIT
---
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index b3f27671a0..90fdc2551a 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -22,7 +22,7 @@ DESCRIPTION
deprecated; it does not work with cvsps version 3 and later. If you are
performing a one-shot import of a CVS repository consider using
http://cvs2svn.tigris.org/cvs2git.html[cvs2git] or
-http://www.catb.org/esr/cvs-fast-export/[cvs-fast-export].
+https://gitlab.com/esr/cvs-fast-export[cvs-fast-export].
Imports a CVS repository into Git. It will either create a new
repository, or incrementally import into an existing one.
@@ -221,7 +221,7 @@ Problems related to tags:
If you suspect that any of these issues may apply to the repository you
want to import, consider using cvs2git:
-* cvs2git (part of cvs2svn), `http://subversion.apache.org/`
+* cvs2git (part of cvs2svn), `https://subversion.apache.org/`
GIT
---
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index cf4a5a283e..4c475efeab 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -197,7 +197,7 @@ allowing access over SSH.
5. Clients should now be able to check out the project. Use the CVS 'module'
name to indicate what Git 'head' you want to check out. This also sets the
name of your newly checked-out directory, unless you tell it otherwise with
- `-d <dir_name>`. For example, this checks out 'master' branch to the
+ `-d <dir-name>`. For example, this checks out 'master' branch to the
`project-master` directory:
+
------
@@ -224,7 +224,7 @@ the database to work reliably (otherwise you need to make sure
that the database is up to date any time 'git-cvsserver' is executed).
By default it uses SQLite databases in the Git directory, named
-`gitcvs.<module_name>.sqlite`. Note that the SQLite backend creates
+`gitcvs.<module-name>.sqlite`. Note that the SQLite backend creates
temporary files in the same directory as the database file on
write so it might not be enough to grant the users using
'git-cvsserver' write access to the database file without granting
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index 236df516c7..ede7b935d6 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -18,7 +18,7 @@ SYNOPSIS
[--allow-override=<service>] [--forbid-override=<service>]
[--access-hook=<path>] [--[no-]informative-errors]
[--inetd |
- [--listen=<host_or_ipaddr>] [--port=<n>]
+ [--listen=<host-or-ipaddr>] [--port=<n>]
[--user=<user> [--group=<group>]]]
[--log-destination=(stderr|syslog|none)]
[<directory>...]
@@ -86,10 +86,10 @@ OPTIONS
Incompatible with --detach, --port, --listen, --user and --group
options.
---listen=<host_or_ipaddr>::
+--listen=<host-or-ipaddr>::
Listen on a specific IP address or hostname. IP addresses can
be either an IPv4 address or an IPv6 address if supported. If IPv6
- is not supported, then --listen=hostname is also not supported and
+ is not supported, then --listen=<hostname> is also not supported and
--listen must be given an IPv4 address.
Can be given more than once.
Incompatible with `--inetd` option.
@@ -138,11 +138,11 @@ otherwise `stderr`.
--user-path::
--user-path=<path>::
Allow {tilde}user notation to be used in requests. When
- specified with no parameter, requests to
+ specified with no parameter, a request to
git://host/{tilde}alice/foo is taken as a request to access
'foo' repository in the home directory of user `alice`.
- If `--user-path=path` is specified, the same request is
- taken as a request to access `path/foo` repository in
+ If `--user-path=<path>` is specified, the same request is
+ taken as a request to access `<path>/foo` repository in
the home directory of user `alice`.
--verbose::
diff --git a/Documentation/git-diagnose.txt b/Documentation/git-diagnose.txt
index 3ec8cc7ad7..0711959e6f 100644
--- a/Documentation/git-diagnose.txt
+++ b/Documentation/git-diagnose.txt
@@ -45,7 +45,7 @@ OPTIONS
-s <format>::
--suffix <format>::
Specify an alternate suffix for the diagnostics archive name, to create
- a file named 'git-diagnostics-<formatted suffix>'. This should take the
+ a file named 'git-diagnostics-<formatted-suffix>'. This should take the
form of a strftime(3) format string; the current local time will be
used.
diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt
index 591e3801b7..bf78e31431 100644
--- a/Documentation/git-diff-files.txt
+++ b/Documentation/git-diff-files.txt
@@ -26,7 +26,7 @@ include::diff-options.txt[]
-2 --ours::
-3 --theirs::
-0::
- Diff against the "base" version, "our branch" or "their
+ Diff against the "base" version, "our branch", or "their
branch" respectively. With these options, diffs for
merged entries are not shown.
+
@@ -37,12 +37,12 @@ omit diff output for unmerged entries and just show "Unmerged".
-c::
--cc::
This compares stage 2 (our branch), stage 3 (their
- branch) and the working tree file and outputs a combined
+ branch), and the working tree file and outputs a combined
diff, similar to the way 'diff-tree' shows a merge
commit with these flags.
-q::
- Remain silent even on nonexistent files
+ Remain silent even for nonexistent files
include::diff-format.txt[]
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt
index c30d8f0da8..4de1d4c8f1 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.txt
@@ -13,10 +13,10 @@ SYNOPSIS
DESCRIPTION
-----------
-Compares the content and mode of the blobs found in a tree object
+Compare the content and mode of the blobs found in a tree object
with the corresponding tracked files in the working tree, or with the
corresponding paths in the index. When <path> arguments are present,
-compares only paths matching those patterns. Otherwise all tracked
+compare only paths matching those patterns. Otherwise all tracked
files are compared.
OPTIONS
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt
index 274d5eaba9..09286a85eb 100644
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.txt
@@ -15,7 +15,7 @@ SYNOPSIS
DESCRIPTION
-----------
-Compares the content and mode of the blobs found via two tree objects.
+Compare the content and mode of blobs found via two tree objects.
If there is only one <tree-ish> given, the commit is compared with its parents
(see --stdin below).
@@ -34,10 +34,10 @@ include::diff-options.txt[]
matching one of the provided pathspecs.
-r::
- recurse into sub-trees
+ Recurse into sub-trees.
-t::
- show tree entry itself as well as subtrees. Implies -r.
+ Show tree entry itself as well as subtrees. Implies -r.
--root::
When `--root` is specified the initial commit will be shown as a big
@@ -78,7 +78,7 @@ commits (but not trees).
By default, 'git diff-tree --stdin' shows differences,
either in machine-readable form (without `-p`) or in patch
form (with `-p`). This output can be suppressed. It is
- only useful with `-v` flag.
+ only useful with the `-v` flag.
-v::
This flag causes 'git diff-tree --stdin' to also show
@@ -88,7 +88,7 @@ include::pretty-options.txt[]
--no-commit-id::
'git diff-tree' outputs a line with the commit ID when
- applicable. This flag suppressed the commit ID output.
+ applicable. This flag suppresses the commit ID output.
-c::
This flag changes the way a merge commit is displayed
@@ -104,10 +104,10 @@ include::pretty-options.txt[]
This flag changes the way a merge commit patch is displayed,
in a similar way to the `-c` option. It implies the `-c`
and `-p` options and further compresses the patch output
- by omitting uninteresting hunks whose the contents in the parents
+ by omitting uninteresting hunks whose contents in the parents
have only two variants and the merge result picks one of them
without modification. When all hunks are uninteresting, the commit
- itself and the commit log message is not shown, just like in any other
+ itself and the commit log message are not shown, just like in any other
"empty diff" case.
--combined-all-paths::
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 08087ffad5..c065f023ec 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -103,7 +103,7 @@ 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>. A tree of interest is the one pointed to
-by the special ref `AUTO_MERGE`, which is written by the 'ort' merge
+by the ref named `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).
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index ac0ac6fa02..a616f8b2e6 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -36,7 +36,7 @@ OPTIONS
--rotate-to=<file>::
Start showing the diff for the given path,
- the paths before it will move to end and output.
+ the paths before it will move to the end and output.
--skip-to=<file>::
Start showing the diff for the given path, skipping all
@@ -78,7 +78,7 @@ with custom merge tool commands and has the same value as `$MERGED`.
Print a list of diff tools that may be used with `--tool`.
--[no-]symlinks::
- 'git difftool''s default behavior is create symlinks to the
+ 'git difftool''s default behavior is to create symlinks to the
working tree when run in `--dir-diff` mode and the right-hand
side of the comparison yields the same content as the file in
the working tree.
@@ -90,7 +90,7 @@ instead. `--no-symlinks` is the default on Windows.
--extcmd=<command>::
Specify a custom command for viewing diffs.
'git-difftool' ignores the configured defaults and runs
- `$command $LOCAL $REMOTE` when this option is specified.
+ `<command> $LOCAL $REMOTE` when this option is specified.
Additionally, `$BASE` is set in the environment.
-g::
@@ -105,7 +105,6 @@ instead. `--no-symlinks` is the default on Windows.
`merge.tool` until a tool is found.
--[no-]trust-exit-code::
- 'git-difftool' invokes a diff tool individually on each file.
Errors reported by the diff tool are ignored by default.
Use `--trust-exit-code` to make 'git-difftool' exit when an
invoked diff tool returns a non-zero exit code.
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 4643ddbe68..752e4b9b01 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -48,7 +48,7 @@ When asking to 'abort' (which is the default), this program will die
when encountering such a tag. With 'drop' it will omit such tags from
the output. With 'rewrite', if the tagged object is a commit, it will
rewrite the tag to tag an ancestor commit (via parent rewriting; see
-linkgit:git-rev-list[1])
+linkgit:git-rev-list[1]).
-M::
-C::
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 8b5dd6add0..3d435157a6 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -303,7 +303,7 @@ and some sanity checks on the numeric values may also be performed.
with e.g. bogus timezone values.
`rfc2822`::
- This is the standard email format as described by RFC 2822.
+ This is the standard date format as described by RFC 2822.
+
An example value is ``Tue Feb 6 11:22:18 2007 -0500''. The Git
parser is accurate, but a little on the lenient side. It is the
@@ -622,7 +622,7 @@ in octal. Git only supports the following modes:
* `100755` or `755`: A normal, but executable, file.
* `120000`: A symlink, the content of the file will be the link target.
* `160000`: A gitlink, SHA-1 of the object refers to a commit in
- another repository. Git links can only be specified by SHA or through
+ another repository. Git links can only be specified either by SHA or through
a commit mark. They are used to implement submodules.
* `040000`: A subdirectory. Subdirectories can only be specified by
SHA or through a tree mark set with `--import-marks`.
@@ -630,18 +630,28 @@ in octal. Git only supports the following modes:
In both formats `<path>` is the complete path of the file to be added
(if not already existing) or modified (if already existing).
-A `<path>` string must use UNIX-style directory separators (forward
-slash `/`), may contain any byte other than `LF`, and must not
-start with double quote (`"`).
-
-A path can use C-style string quoting; this is accepted in all cases
-and mandatory if the filename starts with double quote or contains
-`LF`. In C-style quoting, the complete name should be surrounded with
-double quotes, and any `LF`, backslash, or double quote characters
-must be escaped by preceding them with a backslash (e.g.,
-`"path/with\n, \\ and \" in it"`).
-
-The value of `<path>` must be in canonical form. That is it must not:
+A `<path>` can be written as unquoted bytes or a C-style quoted string.
+
+When a `<path>` does not start with a double quote (`"`), it is an
+unquoted string and is parsed as literal bytes without any escape
+sequences. However, if the filename contains `LF` or starts with double
+quote, it cannot be represented as an unquoted string and must be
+quoted. Additionally, the source `<path>` in `filecopy` or `filerename`
+must be quoted if it contains SP.
+
+When a `<path>` starts with a double quote (`"`), it is a C-style quoted
+string, where the complete filename is enclosed in a pair of double
+quotes and escape sequences are used. Certain characters must be escaped
+by preceding them with a backslash: `LF` is written as `\n`, backslash
+as `\\`, and double quote as `\"`. Some characters may optionally be
+written with escape sequences: `\a` for bell, `\b` for backspace, `\f`
+for form feed, `\n` for line feed, `\r` for carriage return, `\t` for
+horizontal tab, and `\v` for vertical tab. Any byte can be written with
+3-digit octal codes (e.g., `\033`). All filenames can be represented as
+quoted strings.
+
+A `<path>` must use UNIX-style directory separators (forward slash `/`)
+and its value must be in canonical form. That is it must not:
* contain an empty directory component (e.g. `foo//bar` is invalid),
* end with a directory separator (e.g. `foo/` is invalid),
@@ -651,6 +661,7 @@ The value of `<path>` must be in canonical form. That is it must not:
The root of the tree can be represented by an empty string as `<path>`.
+`<path>` cannot contain NUL, either literally or escaped as `\000`.
It is recommended that `<path>` always be encoded using UTF-8.
`filedelete`
@@ -745,11 +756,11 @@ paths for a commit are encouraged to do so.
`notemodify`
^^^^^^^^^^^^
-Included in a `commit` `<notes_ref>` command to add a new note
+Included in a `commit` `<notes-ref>` command to add a new note
annotating a `<commit-ish>` or change this annotation contents.
Internally it is similar to filemodify 100644 on `<commit-ish>`
path (maybe split into subdirectories). It's not advised to
-use any other commands to write to the `<notes_ref>` tree except
+use any other commands to write to the `<notes-ref>` tree except
`filedeleteall` to delete all existing notes in this tree.
This command has two different means of specifying the content
of the note.
@@ -1353,7 +1364,7 @@ the marks back to the source repository, it is easy to verify the
accuracy and completeness of the import by comparing each Git
commit to the corresponding source revision.
-Coming from a system such as Perforce or Subversion this should be
+Coming from a system such as Perforce or Subversion, this should be
quite simple, as the fast-import mark can also be the Perforce changeset
number or the Subversion revision number.
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index 46747d5f42..b5223576a7 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -69,7 +69,7 @@ be in a separate packet, and the list must end with a flush packet.
--upload-pack=<git-upload-pack>::
Use this to specify the path to 'git-upload-pack' on the
- remote side, if is not found on your $PATH.
+ remote side, if it is not found on your $PATH.
Installations of sshd ignores the user's environment
setup scripts for login shells (e.g. .bash_profile) and
your privately installed git may not be found on the system
@@ -91,7 +91,7 @@ be in a separate packet, and the list must end with a flush packet.
Deepen or shorten the history of a shallow repository to
include all reachable commits after <date>.
---shallow-exclude=<revision>::
+--shallow-exclude=<ref>::
Deepen or shorten the history of a shallow repository to
exclude commits reachable from a specified remote branch or tag.
This option can be specified multiple times.
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index f123139c58..50900a50da 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -186,8 +186,8 @@ origin:
------------------------------------------------
$ git fetch origin --prune --prune-tags
$ git fetch origin --prune 'refs/tags/*:refs/tags/*'
-$ git fetch <url of origin> --prune --prune-tags
-$ git fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
+$ git fetch <url-of-origin> --prune --prune-tags
+$ git fetch <url-of-origin> --prune 'refs/tags/*:refs/tags/*'
------------------------------------------------
OUTPUT
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 62e482a95e..5a4f853785 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -14,7 +14,7 @@ SYNOPSIS
[--msg-filter <command>] [--commit-filter <command>]
[--tag-name-filter <command>] [--prune-empty]
[--original <namespace>] [-d <directory>] [-f | --force]
- [--state-branch <branch>] [--] [<rev-list options>...]
+ [--state-branch <branch>] [--] [<rev-list-options>...]
WARNING
-------
@@ -32,7 +32,7 @@ listed there as reasonably possible.
DESCRIPTION
-----------
Lets you rewrite Git revision history by rewriting the branches mentioned
-in the <rev-list options>, applying custom filters on each revision.
+in the <rev-list-options>, applying custom filters on each revision.
Those filters can modify each tree (e.g. removing a file or running
a perl rewrite on all files) or information about each commit.
Otherwise, all information (including original commit times or merge
@@ -624,7 +624,7 @@ with:
real backup; it dereferences tags first.)
** Running git-filter-branch with either --tags or --all in your
- <rev-list options>. In order to retain annotated tags as
+ <rev-list-options>. In order to retain annotated tags as
annotated, you must use --tag-name-filter (and must not have
restored from refs/original/ in a previously botched rewrite).
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 11b2bc3121..d3764401a2 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
[(--sort=<key>)...] [--format=<format>]
- [ --stdin | <pattern>... ]
+ [--include-root-refs] [ --stdin | <pattern>... ]
[--points-at=<object>]
[--merged[=<object>]] [--no-merged[=<object>]]
[--contains[=<object>]] [--no-contains[=<object>]]
@@ -51,17 +51,14 @@ OPTIONS
key.
--format=<format>::
- A string that interpolates `%(fieldname)` from a ref being shown
- and the object it points at. If `fieldname`
- is prefixed with an asterisk (`*`) and the ref points
- at a tag object, use the value for the field in the object
- which the tag object refers to (instead of the field in the tag object).
- When unspecified, `<format>` defaults to
- `%(objectname) SPC %(objecttype) TAB %(refname)`.
- 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).
+ A string that interpolates `%(fieldname)` from a ref being shown and
+ the object it points at. In addition, the string literal `%%`
+ renders as `%` and `%xx` - where `xx` are hex digits - renders as
+ the character with hex code `xx`. For example, `%00` interpolates to
+ `\0` (NUL), `%09` to `\t` (TAB), and `%0a` to `\n` (LF).
++
+When unspecified, `<format>` defaults to `%(objectname) SPC %(objecttype)
+TAB %(refname)`.
--color[=<when>]::
Respect any colors specified in the `--format` option. The
@@ -108,6 +105,9 @@ OPTIONS
any excluded pattern(s) are shown. Matching is done using the
same rules as `<pattern>` above.
+--include-root-refs::
+ List root refs (HEAD and pseudorefs) apart from regular refs.
+
FIELD NAMES
-----------
@@ -264,6 +264,48 @@ ahead-behind:<committish>::
commits ahead and behind, respectively, when comparing the output
ref to the `<committish>` specified in the format.
+is-base:<committish>::
+ In at most one row, `(<committish>)` will appear to indicate the ref
+ that is most likely the ref used as a starting point for the branch
+ that produced `<committish>`. This choice is made using a heuristic:
+ choose the ref that minimizes the number of commits in the
+ first-parent history of `<committish>` and not in the first-parent
+ history of the ref.
++
+For example, consider the following figure of first-parent histories of
+several refs:
++
+----
+*--*--*--*--*--* refs/heads/A
+\
+ \
+ *--*--*--* refs/heads/B
+ \ \
+ \ \
+ * * refs/heads/C
+ \
+ \
+ *--* refs/heads/D
+----
++
+Here, if `A`, `B`, and `C` are the filtered references, and the format
+string is `%(refname):%(is-base:D)`, then the output would be
++
+----
+refs/heads/A:
+refs/heads/B:(D)
+refs/heads/C:
+----
++
+This is because the first-parent history of `D` has its earliest
+intersection with the first-parent histories of the filtered refs at a
+common first-parent ancestor of `B` and `C` and ties are broken by the
+earliest ref in the sorted order.
++
+Note that this token will not appear if the first-parent history of
+`<committish>` does not intersect the first-parent histories of the
+filtered refs.
+
describe[:options]::
A human-readable name, like linkgit:git-describe[1];
empty string for undescribable commits. The `describe` string may
@@ -298,12 +340,20 @@ fields will correspond to the appropriate date or name-email-date tuple
from the `committer` or `tagger` fields depending on the object type.
These are intended for working on a mix of annotated and lightweight tags.
+For tag objects, a `fieldname` prefixed with an asterisk (`*`) expands to
+the `fieldname` value of the peeled object, rather than that of the tag
+object itself.
+
Fields that have name-email-date tuple as its value (`author`,
`committer`, and `tagger`) can be suffixed with `name`, `email`,
and `date` to extract the named component. For email fields (`authoremail`,
`committeremail` and `taggeremail`), `:trim` can be appended to get the email
without angle brackets, and `:localpart` to get the part before the `@` symbol
-out of the trimmed email.
+out of the trimmed email. In addition to these, the `:mailmap` option and the
+corresponding `:mailmap,trim` and `:mailmap,localpart` can be used (order does
+not matter) to get values of the name and email according to the .mailmap file
+or according to the file set in the mailmap.file or mailmap.blob configuration
+variable (see linkgit:gitmailmap[5]).
The raw data in an object is `raw`.
@@ -354,9 +404,11 @@ In any case, a field name that refers to a field inapplicable to
the object referred by the ref does not cause an error. It
returns an empty string instead.
-As a special case for the date-type fields, you may specify a format for
-the date by adding `:` followed by date format name (see the
-values the `--date` option to linkgit:git-rev-list[1] takes).
+As a special case for the date-type fields, you may specify a format for the
+date by adding `:` followed by date format name (see the values the `--date`
+option to linkgit:git-rev-list[1] takes). If this formatting is provided in
+a `--sort` key, references will be sorted according to the byte-value of the
+formatted string rather than the numeric value of the underlying timestamp.
Some atoms like %(align) and %(if) always require a matching %(end).
We call them "opening atoms" and sometimes denote them as %($open).
diff --git a/Documentation/git-for-each-repo.txt b/Documentation/git-for-each-repo.txt
index 94bd19da26..abe3527aac 100644
--- a/Documentation/git-for-each-repo.txt
+++ b/Documentation/git-for-each-repo.txt
@@ -42,6 +42,15 @@ These config values are loaded from system, global, and local Git config,
as available. If `git for-each-repo` is run in a directory that is not a
Git repository, then only the system and global config is used.
+--keep-going::
+ Continue with the remaining repositories if the command failed
+ on a repository. The exit code will still indicate that the
+ overall operation was not successful.
++
+Note that the exact exit code of the failing command is not passed
+through as the exit code of the `for-each-repo` command: If the command
+failed in any of the specified repositories, the overall exit code will
+be 1.
SUBPROCESS BEHAVIOR
-------------------
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 373b46fc0d..5dc7bb4cfc 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -17,10 +17,10 @@ SYNOPSIS
[--signature-file=<file>]
[-n | --numbered | -N | --no-numbered]
[--start-number <n>] [--numbered-files]
- [--in-reply-to=<message id>] [--suffix=.<sfx>]
+ [--in-reply-to=<message-id>] [--suffix=.<sfx>]
[--ignore-if-in-upstream] [--always]
[--cover-from-description=<mode>]
- [--rfc] [--subject-prefix=<subject prefix>]
+ [--rfc[=<rfc>]] [--subject-prefix=<subject-prefix>]
[(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
[--[no-]cover-letter] [--quiet]
@@ -30,8 +30,8 @@ SYNOPSIS
[--range-diff=<previous> [--creation-factor=<percent>]]
[--filename-max-length=<n>]
[--progress]
- [<common diff options>]
- [ <since> | <revision range> ]
+ [<common-diff-options>]
+ [ <since> | <revision-range> ]
DESCRIPTION
-----------
@@ -55,7 +55,7 @@ A "message" generated by the command consists of three parts:
* The "patch", which is the "diff -p --stat" output (see
linkgit:git-diff[1]) between the commit and its parent.
-The log message and the patch is separated by a line with a
+The log message and the patch are separated by a line with a
three-dash line.
There are two ways to specify which commits to operate on.
@@ -64,7 +64,7 @@ There are two ways to specify which commits to operate on.
to the tip of the current branch that are not in the history
that leads to the <since> to be output.
-2. Generic <revision range> expression (see "SPECIFYING
+2. Generic <revision-range> expression (see "SPECIFYING
REVISIONS" section in linkgit:gitrevisions[7]) means the
commits in the specified range.
@@ -179,9 +179,9 @@ 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
will want to ensure that threading is disabled for `git send-email`.
---in-reply-to=<message id>::
+--in-reply-to=<message-id>::
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.
--ignore-if-in-upstream::
@@ -215,11 +215,21 @@ is greater than 100 bytes, then the mode will be `message`, otherwise
If `<mode>` is `none`, both the cover letter subject and body will be
populated with placeholder text.
---subject-prefix=<subject prefix>::
+--description-file=<file>::
+ Use the contents of <file> instead of the branch's description
+ for generating the cover letter.
+
+--subject-prefix=<subject-prefix>::
Instead of the standard '[PATCH]' prefix in the subject
- line, instead use '[<subject prefix>]'. This
- allows for useful naming of a patch series, and can be
- combined with the `--numbered` option.
+ line, instead use '[<subject-prefix>]'. This can be used
+ to name a patch series, and can be combined with the
+ `--numbered` option.
++
+The configuration variable `format.subjectPrefix` may also be used
+to configure a subject prefix to apply to a given repository for
+all patches. This is often useful on mailing lists which receive
+patches for several repositories and can be used to disambiguate
+the patches (with a value of e.g. "PATCH my-project").
--filename-max-length=<n>::
Instead of the standard 64 bytes, chomp the generated output
@@ -228,10 +238,21 @@ populated with placeholder text.
value of the `format.filenameMaxLength` configuration
variable, or 64 if unconfigured.
---rfc::
- Alias for `--subject-prefix="RFC PATCH"`. RFC means "Request For
- Comments"; use this when sending an experimental patch for
- discussion rather than application.
+--rfc[=<rfc>]::
+ Prepends the string _<rfc>_ (defaults to "RFC") to
+ the subject prefix. As the subject prefix defaults to
+ "PATCH", you'll get "RFC PATCH" by default.
++
+RFC means "Request For Comments"; use this when sending
+an experimental patch for discussion rather than application.
+"--rfc=WIP" may also be a useful way to indicate that a patch
+is not complete yet ("WIP" stands for "Work In Progress").
++
+If the convention of the receiving community for a particular extra
+string is to have it _after_ the subject prefix, the string _<rfc>_
+can be prefixed with a dash ("`-`") to signal that the rest of
+the _<rfc>_ string should be appended to the subject prefix instead,
+e.g., `--rfc='-(WIP)'` results in "PATCH (WIP)".
-v <n>::
--reroll-count=<n>::
@@ -336,6 +357,11 @@ material (this may change in the future).
between the previous and current series of patches by adjusting the
creation/deletion cost fudge factor. See linkgit:git-range-diff[1])
for details.
++
+Defaults to 999 (the linkgit:git-range-diff[1] uses 60), as the use
+case is to show comparison with an older iteration of the same
+topic and the tool should find more correspondence between the two
+sets of patches.
--notes[=<ref>]::
--no-notes::
@@ -393,7 +419,7 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
`format.useAutoBase` configuration.
--root::
- Treat the revision argument as a <revision range>, even if it
+ Treat the revision argument as a <revision-range>, even if it
is just a single commit (that would normally be treated as a
<since>). Note that root commits included in the specified
range are always formatted as creation patches, independently
@@ -600,8 +626,8 @@ Approach #3 (external editor)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following Thunderbird extensions are needed:
-AboutConfig from http://aboutconfig.mozdev.org/ and
-External Editor from http://globs.org/articles.php?lng=en&pg=8
+AboutConfig from https://mjg.github.io/AboutConfig/ and
+External Editor from https://globs.org/articles.php?lng=en&pg=8
1. Prepare the patch as a text file using your method of choice.
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index b6a0f8a085..5b82e4605c 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -24,7 +24,7 @@ OPTIONS
An object to treat as the head of an unreachability trace.
+
If no objects are given, 'git fsck' defaults to using the
-index file, all SHA-1 references in `refs` namespace, and all reflogs
+index file, all SHA-1 references in the `refs` namespace, and all reflogs
(unless --no-reflogs is given) as heads.
--unreachable::
@@ -64,7 +64,7 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
--connectivity-only::
Check only the connectivity of reachable objects, making sure
that any objects referenced by a reachable tag, commit, or tree
- is present. This speeds up the operation by avoiding reading
+ are present. This speeds up the operation by avoiding reading
blobs entirely (though it does still check that referenced blobs
exist). This will detect corruption in commits and trees, but
not do any semantic checks (e.g., for format errors). Corruption
@@ -79,7 +79,7 @@ care about this output and want to speed it up further.
recorded with g+w bit set, which was created by older
versions of Git. Existing repositories, including the
Linux kernel, Git itself, and sparse repository have old
- objects that triggers this check, but it is recommended
+ objects that trigger this check, but it is recommended
to check new projects with this flag.
--verbose::
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index 8238eadb0e..8585d19f4d 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -70,10 +70,10 @@ the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
-By default, the fsmonitor daemon refuses to work against network-mounted
+By default, the fsmonitor daemon refuses to work with network-mounted
repositories; this may be overridden by setting `fsmonitor.allowRemote` to
`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
-correctly with all network-mounted repositories and such use is considered
+correctly with all network-mounted repositories, so such use is considered
experimental.
On Mac OS, the inter-process communication (IPC) between various Git
@@ -83,10 +83,10 @@ but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
may or may not have the needed support; the fsmonitor daemon is not guaranteed
to work with these filesystems and such use is considered experimental.
-By default, the socket is created in the `.git` directory, however, if the
-`.git` directory is on a network-mounted filesystem, it will be instead be
+By default, the socket is created in the `.git` directory. However, if the
+`.git` directory is on a network-mounted filesystem, it will instead be
created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
-network-mounted filesystem in which case you must set the configuration
+network-mounted filesystem, in which case you must set the configuration
variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
filesystem in which to create the socket file.
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 90806fd26a..370e22faae 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -9,7 +9,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
SYNOPSIS
--------
[verse]
-'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
+'git gc' [--aggressive] [--auto] [--[no-]detach] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
DESCRIPTION
-----------
@@ -53,12 +53,22 @@ configuration options such as `gc.auto` and `gc.autoPackLimit`, all
other housekeeping tasks (e.g. rerere, working trees, reflog...) will
be performed as well.
+--[no-]detach::
+ Run in the background if the system supports it. This option overrides
+ the `gc.autoDetach` config.
--[no-]cruft::
When expiring unreachable objects, pack them separately into a
cruft pack instead of storing them as loose objects. `--cruft`
is on by default.
+--max-cruft-size=<n>::
+ When packing unreachable objects into a cruft pack, limit the
+ size of new cruft packs to be at most `<n>` bytes. Overrides any
+ value specified via the `gc.maxCruftSize` configuration. See
+ the `--max-cruft-size` option of linkgit:git-repack[1] for
+ more.
+
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
overridable by the config variable `gc.pruneExpire`).
diff --git a/Documentation/git-get-tar-commit-id.txt b/Documentation/git-get-tar-commit-id.txt
index ac44d85b0b..b537bb45b1 100644
--- a/Documentation/git-get-tar-commit-id.txt
+++ b/Documentation/git-get-tar-commit-id.txt
@@ -20,7 +20,7 @@ and extract the commit ID stored in it. It reads only the first
1024 bytes of input, thus its runtime is not influenced by the size
of the tar archive very much.
-If no commit ID is found, 'git get-tar-commit-id' quietly exists with a
+If no commit ID is found, 'git get-tar-commit-id' quietly exits with a
return code of 1. This can happen if the archive had not been created
using 'git archive' or if the first parameter of 'git archive' had been
a tree ID instead of a commit ID or tag.
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index dabdbe8471..1e6d7b65c8 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -28,7 +28,7 @@ SYNOPSIS
[-f <file>] [-e] <pattern>
[--and|--or|--not|(|)|-e <pattern>...]
[--recurse-submodules] [--parent-basename <basename>]
- [ [--[no-]exclude-standard] [--cached | --no-index | --untracked] | <tree>...]
+ [ [--[no-]exclude-standard] [--cached | --untracked | --no-index] | <tree>...]
[--] [<pathspec>...]
DESCRIPTION
@@ -45,13 +45,21 @@ OPTIONS
Instead of searching tracked files in the working tree, search
blobs registered in the index file.
---no-index::
- Search files in the current directory that is not managed by Git.
-
--untracked::
In addition to searching in the tracked files in the working
tree, search also in untracked files.
+--no-index::
+ Search files in the current directory that is not managed by Git,
+ or by ignoring that the current directory is managed by Git. This
+ is rather similar to running the regular `grep(1)` utility with its
+ `-r` option specified, but with some additional benefits, such as
+ using pathspec patterns to limit paths; see the 'pathspec' entry
+ in linkgit:gitglossary[7] for more information.
++
+This option cannot be used together with `--cached` or `--untracked`.
+See also `grep.fallbackToNoIndex` in 'CONFIGURATION' below.
+
--no-exclude-standard::
Also search in ignored files by not honoring the `.gitignore`
mechanism. Only useful with `--untracked`.
@@ -64,9 +72,9 @@ OPTIONS
--recurse-submodules::
Recursively search in each submodule that is active and
checked out in the repository. When used in combination with the
- <tree> option the prefix of all submodule output will be the name of
- the parent project's <tree> object. This option has no effect
- if `--no-index` is given.
+ _<tree>_ option the prefix of all submodule output will be the name of
+ the parent project's _<tree>_ object. This option cannot be used together
+ with `--untracked`, and it has no effect if `--no-index` is specified.
-a::
--text::
@@ -178,7 +186,7 @@ providing this option will cause it to die.
Use \0 as the delimiter for pathnames in the output, and print
them verbatim. Without this option, pathnames with "unusual"
characters are quoted as explained for the configuration
- variable core.quotePath (see linkgit:git-config[1]).
+ variable `core.quotePath` (see linkgit:git-config[1]).
-o::
--only-matching::
@@ -248,8 +256,8 @@ providing this option will cause it to die.
a non-zero status.
--threads <num>::
- Number of grep worker threads to use.
- See `grep.threads` in 'CONFIGURATION' for more information.
+ Number of `grep` worker threads to use. See 'NOTES ON THREADS'
+ and `grep.threads` in 'CONFIGURATION' for more information.
-f <file>::
Read patterns from <file>, one per line.
@@ -332,13 +340,13 @@ EXAMPLES
NOTES ON THREADS
----------------
-The `--threads` option (and the grep.threads configuration) will be ignored when
+The `--threads` option (and the `grep.threads` configuration) will be ignored when
`--open-files-in-pager` is used, forcing a single-threaded execution.
When grepping the object store (with `--cached` or giving tree objects), running
-with multiple threads might perform slower than single threaded if `--textconv`
-is given and there're too many text conversions. So if you experience low
-performance in this case, it might be desirable to use `--threads=1`.
+with multiple threads might perform slower than single-threaded if `--textconv`
+is given and there are too many text conversions. Thus, if low performance is
+experienced in this case, it might be desirable to use `--threads=1`.
CONFIGURATION
-------------
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt
index e8f3ccb433..f5b02ef114 100644
--- a/Documentation/git-gui.txt
+++ b/Documentation/git-gui.txt
@@ -114,7 +114,7 @@ of end users.
The official repository of the 'git gui' project can be found at:
- https://github.com/prati0100/git-gui.git/
+ https://github.com/j6t/git-gui
GIT
---
diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt
index 8577f7a7d4..ef4719ae41 100644
--- a/Documentation/git-hash-object.txt
+++ b/Documentation/git-hash-object.txt
@@ -39,10 +39,10 @@ OPTIONS
of from the command-line.
--path::
- Hash object as it were located at the given path. The location of
- file does not directly influence on the hash value, but path is
- used to determine what Git filters should be applied to the object
- before it can be placed to the object database, and, as result of
+ Hash object as if it were located at the given path. The location of
+ the file does not directly influence the hash value, but the path is
+ used to determine which Git filters should be applied to the object
+ before it can be placed in the object database. As a result of
applying filters, the actual blob put into the object database may
differ from the given file. This option is mainly useful for hashing
temporary files located outside of the working directory or files
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index 2b0b5e390d..f0bedc1f96 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -42,13 +42,13 @@ former is internally converted into the latter.
To display the linkgit:git[1] man page, use `git help git`.
-This page can be displayed with 'git help help' or `git help --help`
+This page can be displayed with 'git help help' or `git help --help`.
OPTIONS
-------
-a::
--all::
- Prints all the available commands on the standard output.
+ Print all the available commands on the standard output.
--no-external-commands::
When used with `--all`, exclude the listing of external "git-*"
@@ -59,7 +59,7 @@ OPTIONS
aliases.
--verbose::
- When used with `--all` print description for all recognized
+ When used with `--all`, print description for all recognized
commands. This is the default.
-c::
@@ -69,10 +69,10 @@ OPTIONS
-g::
--guides::
- Prints a list of the Git concept guides on the standard output.
+ Print a list of the Git concept guides on the standard output.
--user-interfaces::
- Prints a list of the repository, command and file interfaces
+ Print a list of the repository, command and file interfaces
documentation on the standard output.
+
In-repository file interfaces such as `.git/info/exclude` are
@@ -85,7 +85,7 @@ pseudo-configuration such as the file-based `.git/hooks/*` interface
described in linkgit:githooks[5].
--developer-interfaces::
- Print list of file formats, protocols and other developer
+ Print a list of file formats, protocols and other developer
interfaces documentation on the standard output.
-i::
@@ -109,7 +109,7 @@ other display programs (see below).
format. A web browser will be used for that purpose.
+
The web browser can be specified using the configuration variable
-`help.browser`, or `web.browser` if the former is not set. If none of
+`help.browser`, or `web.browser` if the former is not set. If neither of
these config variables is set, the 'git web{litdd}browse' helper script
(called by 'git help') will pick a suitable default. See
linkgit:git-web{litdd}browse[1] for more information about this.
@@ -129,8 +129,8 @@ line option:
* "info" corresponds to '-i|--info',
* "web" or "html" correspond to '-w|--web'.
-help.browser, web.browser and browser.<tool>.path
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help.browser, web.browser, and browser.<tool>.path
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The `help.browser`, `web.browser` and `browser.<tool>.path` will also
be checked if the 'web' format is chosen (either by command-line
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index 3407f3c2c0..f6cc72d2ca 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -13,7 +13,7 @@ SYNOPSIS
DESCRIPTION
-----------
-A command interface to running git hooks (see linkgit:githooks[5]),
+A command interface for running git hooks (see linkgit:githooks[5]),
for use by other scripted git commands.
SUBCOMMANDS
@@ -32,7 +32,7 @@ OPTIONS
-------
--to-stdin::
- For "run"; Specify a file which will be streamed into the
+ For "run"; specify a file which will be streamed into the
hook's stdin. The hook will receive the entire file from
beginning to EOF.
diff --git a/Documentation/git-http-backend.txt b/Documentation/git-http-backend.txt
index 0c5c0dde19..f37ddaded8 100644
--- a/Documentation/git-http-backend.txt
+++ b/Documentation/git-http-backend.txt
@@ -23,7 +23,7 @@ discussion of `GIT_PROTOCOL` in the ENVIRONMENT section below.
It verifies that the directory has the magic file
"git-daemon-export-ok", and it will refuse to export any Git directory
that hasn't explicitly been marked for export this way (unless the
-`GIT_HTTP_EXPORT_ALL` environmental variable is set).
+`GIT_HTTP_EXPORT_ALL` environment variable is set).
By default, only the `upload-pack` service is enabled, which serves
'git fetch-pack' and 'git ls-remote' clients, which are invoked from
@@ -42,12 +42,12 @@ http.getanyfile::
any file within the repository, including objects that are
no longer reachable from a branch but are still present.
It is enabled by default, but a repository can disable it
- by setting this configuration item to `false`.
+ by setting this configuration value to `false`.
http.uploadpack::
This serves 'git fetch-pack' and 'git ls-remote' clients.
It is enabled by default, but a repository can disable it
- by setting this configuration item to `false`.
+ by setting this configuration value to `false`.
http.receivepack::
This serves 'git send-pack' clients, allowing push. It is
@@ -265,12 +265,12 @@ by the invoking web server, including:
* QUERY_STRING
* REQUEST_METHOD
-The `GIT_HTTP_EXPORT_ALL` environmental variable may be passed to
+The `GIT_HTTP_EXPORT_ALL` environment variable may be passed to
'git-http-backend' to bypass the check for the "git-daemon-export-ok"
file in each repository before allowing export of that repository.
The `GIT_HTTP_MAX_REQUEST_BUFFER` environment variable (or the
-`http.maxRequestBuffer` config variable) may be set to change the
+`http.maxRequestBuffer` config option) may be set to change the
largest ref negotiation request that git will handle during a fetch; any
fetch requiring a larger buffer will not succeed. This value should not
normally need to be changed, but may be helpful if you are fetching from
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt
index 319062c021..4ec7c68d3b 100644
--- a/Documentation/git-http-fetch.txt
+++ b/Documentation/git-http-fetch.txt
@@ -31,7 +31,7 @@ commit-id::
Report what is downloaded.
-w <filename>::
- Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
+ Writes the commit-id into the specified filename under $GIT_DIR/refs/<filename> on
the local end after the transfer is complete.
--stdin::
diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt
index 7c6a6dd7f6..ce0d808212 100644
--- a/Documentation/git-http-push.txt
+++ b/Documentation/git-http-push.txt
@@ -13,12 +13,12 @@ SYNOPSIS
DESCRIPTION
-----------
-Sends missing objects to remote repository, and updates the
+Sends missing objects to the remote repository, and updates the
remote branch.
*NOTE*: This command is temporarily disabled if your libcurl
is older than 7.16, as the combination has been reported
-not to work and sometimes corrupts repository.
+not to work and sometimes corrupts the repository.
OPTIONS
-------
@@ -44,7 +44,7 @@ OPTIONS
-d::
-D::
Remove <ref> from remote repository. The specified branch
- cannot be the remote HEAD. If -d is specified the following
+ cannot be the remote HEAD. If -d is specified, the following
other conditions must also be met:
- Remote HEAD must resolve to an object that exists locally
@@ -83,8 +83,8 @@ and where it is pushed is determined by using the destination side.
Without `--force`, the <src> ref is stored at the remote only if
<dst> does not exist, or <dst> is a proper subset (i.e. an
ancestor) of <src>. This check, known as "fast-forward check",
-is performed in order to avoid accidentally overwriting the
-remote ref and lose other peoples' commits from there.
+is performed to avoid accidentally overwriting the
+remote ref and losing other peoples' commits from there.
With `--force`, the fast-forward check is disabled for all refs.
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index f7b1851514..c8a89d7243 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -135,7 +135,7 @@ flames ridiculing you if you don't check this.
Thunderbird in particular is known to be problematic. Thunderbird
users may wish to visit this web page for more information:
- http://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
+ https://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
SEE ALSO
--------
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 4e71c256ec..58dd5b5f0e 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -16,10 +16,10 @@ SYNOPSIS
DESCRIPTION
-----------
-Reads a packed archive (.pack) from the specified file, and
-builds a pack index file (.idx) for it. Optionally writes a
+Reads a packed archive (.pack) from the specified file,
+builds a pack index file (.idx) for it, and optionally writes a
reverse-index (.rev) for the specified pack. The packed
-archive together with the pack index can then be placed in
+archive, together with the pack index, can then be placed in
the objects/pack/ directory of a Git repository.
@@ -68,8 +68,8 @@ OPTIONS
updated to use objects contained in the pack.
--keep=<msg>::
- Like --keep create a .keep file before moving the index into
- its final destination, but rather than creating an empty file
+ Like --keep, create a .keep file before moving the index into
+ its final destination. However, instead of creating an empty file
place '<msg>' followed by an LF into the .keep file. The '<msg>'
message can later be searched for within all .keep files to
locate any which have outlived their usefulness.
@@ -79,8 +79,13 @@ OPTIONS
to force the version for the generated pack index, and to force
64-bit index entries on objects located above the given offset.
---strict::
- Die, if the pack contains broken objects or links.
+--strict[=<msg-id>=<severity>...]::
+ Die, if the pack contains broken objects or links. An optional
+ comma-separated list of `<msg-id>=<severity>` can be passed to change
+ the severity of some possible issues, e.g.,
+ `--strict="missingEmail=ignore,badTagName=error"`. See the entry for the
+ `fsck.<msg-id>` configuration options in linkgit:git-fsck[1] for more
+ information on the possible values of `<msg-id>` and `<severity>`.
--progress-title::
For internal use only.
@@ -91,13 +96,18 @@ default and "Indexing objects" when `--stdin` is specified.
--check-self-contained-and-connected::
Die if the pack contains broken links. For internal use only.
---fsck-objects::
- For internal use only.
+--fsck-objects[=<msg-id>=<severity>...]::
+ Die if the pack contains broken objects, but unlike `--strict`, don't
+ choke on broken links. If the pack contains a tree pointing to a
+ .gitmodules blob that does not exist, prints the hash of that blob
+ (for the caller to check) after the hash that goes into the name of the
+ pack/idx file (see "Notes").
+
-Die if the pack contains broken objects. If the pack contains a tree
-pointing to a .gitmodules blob that does not exist, prints the hash of
-that blob (for the caller to check) after the hash that goes into the
-name of the pack/idx file (see "Notes").
+An optional comma-separated list of `<msg-id>=<severity>` can be passed to
+change the severity of some possible issues, e.g.,
+`--fsck-objects="missingEmail=ignore,badTagName=ignore"`. See the entry for the
+`fsck.<msg-id>` configuration options in linkgit:git-fsck[1] for more
+information on the possible values of `<msg-id>` and `<severity>`.
--threads=<n>::
Specifies the number of threads to spawn when resolving
@@ -129,6 +139,13 @@ include::object-format-disclaimer.txt[]
written. If a `<message>` is provided, then that content will be
written to the .promisor file for future reference. See
link:technical/partial-clone.html[partial clone] for more information.
++
+Also, if there are objects in the given pack that references non-promisor
+objects (in the repo), repacks those non-promisor objects into a promisor
+pack. This avoids a situation in which a repo has non-promisor objects that are
+accessible through promisor objects.
++
+Requires <pack-file> to not be specified.
NOTES
-----
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 160dea1372..315f7f7530 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -8,11 +8,12 @@ git-init - Create an empty Git repository or reinitialize an existing one
SYNOPSIS
--------
-[verse]
-'git init' [-q | --quiet] [--bare] [--template=<template-directory>]
- [--separate-git-dir <git-dir>] [--object-format=<format>]
- [-b <branch-name> | --initial-branch=<branch-name>]
- [--shared[=<permissions>]] [<directory>]
+[synopsis]
+git init [-q | --quiet] [--bare] [--template=<template-directory>]
+ [--separate-git-dir <git-dir>] [--object-format=<format>]
+ [--ref-format=<format>]
+ [-b <branch-name> | --initial-branch=<branch-name>]
+ [--shared[=<permissions>]] [<directory>]
DESCRIPTION
@@ -24,99 +25,104 @@ directory with subdirectories for `objects`, `refs/heads`,
commits will be created (see the `--initial-branch` option below
for its name).
-If the `$GIT_DIR` environment variable is set then it specifies a path
+If the `GIT_DIR` environment variable is set then it specifies a path
to use instead of `./.git` for the base of the repository.
If the object storage directory is specified via the
-`$GIT_OBJECT_DIRECTORY` environment variable then the sha1 directories
-are created underneath - otherwise the default `$GIT_DIR/objects`
+`GIT_OBJECT_DIRECTORY` environment variable then the sha1 directories
+are created underneath; otherwise, the default `$GIT_DIR/objects`
directory is used.
-Running 'git init' in an existing repository is safe. It will not
+Running `git init` in an existing repository is safe. It will not
overwrite things that are already there. The primary reason for
-rerunning 'git init' is to pick up newly added templates (or to move
-the repository to another place if --separate-git-dir is given).
+rerunning `git init` is to pick up newly added templates (or to move
+the repository to another place if `--separate-git-dir` is given).
OPTIONS
-------
--q::
---quiet::
+`-q`::
+`--quiet`::
Only print error and warning messages; all other output will be suppressed.
---bare::
+`--bare`::
Create a bare repository. If `GIT_DIR` environment is not set, it is set to the
current working directory.
---object-format=<format>::
-
-Specify the given object format (hash algorithm) for the repository. The valid
-values are 'sha1' and (if enabled) 'sha256'. 'sha1' is the default.
+`--object-format=<format>`::
+Specify the given object _<format>_ (hash algorithm) for the repository. The valid
+values are `sha1` and (if enabled) `sha256`. `sha1` is the default.
+
include::object-format-disclaimer.txt[]
---template=<template-directory>::
+`--ref-format=<format>`::
+Specify the given ref storage _<format>_ for the repository. The valid values are:
++
+include::ref-storage-format.txt[]
+`--template=<template-directory>`::
Specify the directory from which templates will be used. (See the "TEMPLATE
DIRECTORY" section below.)
---separate-git-dir=<git-dir>::
-
+`--separate-git-dir=<git-dir>`::
Instead of initializing the repository as a directory to either `$GIT_DIR` or
`./.git/`, create a text file there containing the path to the actual
-repository. This file acts as filesystem-agnostic Git symbolic link to the
+repository. This file acts as a filesystem-agnostic Git symbolic link to the
repository.
+
-If this is reinitialization, the repository will be moved to the specified path.
+If this is a reinitialization, the repository will be moved to the specified path.
--b <branch-name>::
---initial-branch=<branch-name>::
-
-Use the specified name for the initial branch in the newly created
+`-b <branch-name>`::
+`--initial-branch=<branch-name>`::
+Use _<branch-name>_ for the initial branch in the newly created
repository. If not specified, fall back to the default name (currently
`master`, but this is subject to change in the future; the name can be
customized via the `init.defaultBranch` configuration variable).
---shared[=(false|true|umask|group|all|world|everybody|<perm>)]::
+`--shared[=(false|true|umask|group|all|world|everybody|<perm>)]`::
Specify that the Git repository is to be shared amongst several users. This
allows users belonging to the same group to push into that
-repository. When specified, the config variable "core.sharedRepository" is
+repository. When specified, the config variable `core.sharedRepository` is
set so that files and directories under `$GIT_DIR` are created with the
requested permissions. When not specified, Git will use permissions reported
-by umask(2).
+by `umask`(2).
+
-The option can have the following values, defaulting to 'group' if no value
+The option can have the following values, defaulting to `group` if no value
is given:
+
--
-'umask' (or 'false')::
+`umask`::
+`false`::
-Use permissions reported by umask(2). The default, when `--shared` is not
+Use permissions reported by `umask`(2). The default, when `--shared` is not
specified.
-'group' (or 'true')::
+`group`::
+`true`::
-Make the repository group-writable, (and g+sx, since the git group may be not
+Make the repository group-writable, (and `g+sx`, since the git group may not be
the primary group of all users). This is used to loosen the permissions of an
-otherwise safe umask(2) value. Note that the umask still applies to the other
-permission bits (e.g. if umask is '0022', using 'group' will not remove read
-privileges from other (non-group) users). See '0xxx' for how to exactly specify
+otherwise safe `umask`(2) value. Note that the umask still applies to the other
+permission bits (e.g. if umask is `0022`, using `group` will not remove read
+privileges from other (non-group) users). See `0xxx` for how to exactly specify
the repository permissions.
-'all' (or 'world' or 'everybody')::
+`all`::
+`world`::
+`everybody`::
-Same as 'group', but make the repository readable by all users.
+Same as `group`, but make the repository readable by all users.
-'<perm>'::
+_<perm>_::
-'<perm>' is a 3-digit octal number prefixed with `0` and each file
-will have mode '<perm>'. '<perm>' will override users' umask(2)
-value (and not only loosen permissions as 'group' and 'all'
-does). '0640' will create a repository which is group-readable, but
-not group-writable or accessible to others. '0660' will create a repo
+_<perm>_ is a 3-digit octal number prefixed with `0` and each file
+will have mode _<perm>_. _<perm>_ will override users' `umask`(2)
+value (and not only loosen permissions as `group` and `all`
+do). `0640` will create a repository which is group-readable, but
+not group-writable or accessible to others. `0660` will create a repo
that is readable and writable to the current user and group, but
inaccessible to others (directories and executable files get their
`x` bit from the `r` bit for corresponding classes of users).
@@ -126,7 +132,7 @@ By default, the configuration flag `receive.denyNonFastForwards` is enabled
in shared repositories, so that you cannot force a non fast-forwarding push
into it.
-If you provide a 'directory', the command is run inside it. If this directory
+If you provide a _<directory>_, the command is run inside it. If this directory
does not exist, it will be created.
TEMPLATE DIRECTORY
@@ -165,7 +171,7 @@ $ git add . <2>
$ git commit <3>
----------------
+
-<1> Create a /path/to/my/codebase/.git directory.
+<1> Create a `/path/to/my/codebase/.git` directory.
<2> Add all existing files to the index.
<3> Record the pristine state as the first commit in the history.
@@ -174,6 +180,8 @@ CONFIGURATION
include::includes/cmd-config-section-all.txt[]
+:git-init:
+
include::config/init.txt[]
GIT
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 55d8961466..d9dfb75fef 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git interpret-trailers' [--in-place] [--trim-empty]
- [(--trailer <token>[(=|:)<value>])...]
+ [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]
[--parse] [<file>...]
DESCRIPTION
@@ -31,10 +31,15 @@ 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 each input file. The result is emitted on the
-standard output.
+If `--parse` is specified, the output consists of the parsed trailers
+coming from the input, without influencing them with any command line
+options or configuration variables.
+
+Otherwise, this command applies `trailer.*` configuration variables
+(which could potentially add new trailers, as well as reposition them),
+as well as any command line arguments that can override configuration
+variables (such as `--trailer=...` which could also add new trailers),
+to each input file. The result is emitted on the standard output.
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
@@ -48,22 +53,32 @@ are applied to each input and the way any existing trailer in
the input is changed. They also make it possible to
automatically add some trailers.
-By default, a '<token>=<value>' or '<token>:<value>' argument given
+By default, a '<key>=<value>' or '<key>:<value>' argument given
using `--trailer` will be appended after the existing trailers only if
-the last trailer has a different (<token>, <value>) pair (or if there
-is no existing trailer). The <token> and <value> parts will be trimmed
+the last trailer has a different (<key>, <value>) pair (or if there
+is no existing trailer). The <key> and <value> parts will be trimmed
to remove starting and trailing whitespace, and the resulting trimmed
-<token> and <value> will appear in the output like this:
+<key> and <value> will appear in the output like this:
------------------------------------------------
-token: value
+key: value
------------------------------------------------
-This means that the trimmed <token> and <value> will be separated by
-`': '` (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.
+This means that the trimmed <key> and <value> will be separated by
+`': '` (one colon followed by one space).
+
+For convenience, a <key-alias> can be configured to make using `--trailer`
+shorter to type on the command line. This can be configured using the
+'trailer.<key-alias>.key' configuration variable. The <keyAlias> must be a prefix
+of the full <key> string, although case sensitivity does not matter. For
+example, if you have
+
+------------------------------------------------
+trailer.sign.key "Signed-off-by: "
+------------------------------------------------
+
+in your configuration, you only need to specify `--trailer="sign: foo"`
+on the command line instead of `--trailer="Signed-off-by: foo"`.
By default the new trailer will appear at the end of all the existing
trailers. If there is no existing trailer, the new trailer will appear
@@ -80,14 +95,14 @@ non-whitespace lines before a line that starts with '---' (followed by a
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,
+<key>, but any number of regular space and tab characters are allowed
+between the <key> and the separator. There can be whitespaces before,
inside or after the <value>. The <value> may be split over multiple lines
with each subsequent line starting with at least one whitespace, like
the "folding" in RFC 822. Example:
------------------------------------------------
-token: This is a very long value, with spaces and
+key: This is a very long value, with spaces and
newlines in it.
------------------------------------------------
@@ -104,35 +119,44 @@ OPTIONS
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 <key>[(=|:)<value>]::
+ Specify a (<key>, <value>) pair that should be applied as a
trailer to the inputs. See the description of this
command.
--where <placement>::
--no-where::
Specify where all new trailers will be added. A setting
- provided with '--where' overrides all configuration variables
+ provided with '--where' overrides the `trailer.where` and any
+ applicable `trailer.<keyAlias>.where` configuration variables
and applies to all '--trailer' options until the next occurrence of
- '--where' or '--no-where'. Possible values are `after`, `before`,
- `end` or `start`.
+ '--where' or '--no-where'. Upon encountering '--no-where', clear the
+ effect of any previous use of '--where', such that the relevant configuration
+ variables are no longer overridden. Possible placements are `after`,
+ `before`, `end` or `start`.
--if-exists <action>::
--no-if-exists::
Specify what action will be performed when there is already at
- least one trailer with the same <token> in the input. A setting
- provided with '--if-exists' overrides all configuration variables
+ least one trailer with the same <key> in the input. A setting
+ provided with '--if-exists' overrides the `trailer.ifExists` and any
+ applicable `trailer.<keyAlias>.ifExists` configuration variables
and applies to all '--trailer' options until the next occurrence of
- '--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`,
+ '--if-exists' or '--no-if-exists'. Upon encountering '--no-if-exists, clear the
+ effect of any previous use of '--if-exists, such that the relevant configuration
+ variables are no longer overridden. Possible actions are `addIfDifferent`,
`addIfDifferentNeighbor`, `add`, `replace` and `doNothing`.
--if-missing <action>::
--no-if-missing::
Specify what action will be performed when there is no other
- trailer with the same <token> in the input. A setting
- provided with '--if-missing' overrides all configuration variables
+ trailer with the same <key> in the input. A setting
+ provided with '--if-missing' overrides the `trailer.ifMissing` and any
+ applicable `trailer.<keyAlias>.ifMissing` configuration variables
and applies to all '--trailer' options until the next occurrence of
- '--if-missing' or '--no-if-missing'. Possible actions are `doNothing`
+ '--if-missing' or '--no-if-missing'. Upon encountering '--no-if-missing,
+ clear the effect of any previous use of '--if-missing, such that the relevant
+ configuration variables are no longer overridden. Possible actions are `doNothing`
or `add`.
--only-trailers::
@@ -140,16 +164,19 @@ OPTIONS
--only-input::
Output only trailers that exist in the input; do not add any
- from the command-line or by following configured `trailer.*`
- rules.
+ from the command-line or by applying `trailer.*` configuration
+ variables.
--unfold::
- Remove any whitespace-continuation in trailers, so that each
- trailer appears on a line by itself with its full content.
+ If a trailer has a value that runs over multiple lines (aka "folded"),
+ reformat the value into a single line.
--parse::
A convenience alias for `--only-trailers --only-input
- --unfold`.
+ --unfold`. This makes it easier to only see the trailers coming from the
+ input without influencing them with any command line options or
+ configuration variables, while also making the output machine-friendly with
+ --unfold.
--no-divider::
Do not treat `---` as the end of the commit message. Use this
@@ -170,11 +197,11 @@ used when another separator is not specified in the config for this
trailer.
+
For example, if the value for this option is "%=$", then only lines
-using the format '<token><sep><value>' with <sep> containing '%', '='
+using the format '<key><sep><value>' with <sep> containing '%', '='
or '$' and then spaces will be considered trailers. And '%' will be
the default separator used, so by default trailers will appear like:
-'<token>% <value>' (one percent sign and one space will appear between
-the token and the value).
+'<key>% <value>' (one percent sign and one space will appear between
+the key and the value).
trailer.where::
This option tells where a new trailer will be added.
@@ -188,41 +215,41 @@ If it is `start`, then each new trailer will appear at the start,
instead of the end, of the existing trailers.
+
If it is `after`, then each new trailer will appear just after the
-last trailer with the same <token>.
+last trailer with the same <key>.
+
If it is `before`, then each new trailer will appear just before the
-first trailer with the same <token>.
+first trailer with the same <key>.
trailer.ifexists::
This option makes it possible to choose what action will be
performed when there is already at least one trailer with the
- same <token> in the input.
+ same <key> in the input.
+
The valid values for this option are: `addIfDifferentNeighbor` (this
is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
+
With `addIfDifferentNeighbor`, a new trailer will be added only if no
-trailer with the same (<token>, <value>) pair is above or below the line
+trailer with the same (<key>, <value>) pair is above or below the line
where the new trailer will be added.
+
With `addIfDifferent`, a new trailer will be added only if no trailer
-with the same (<token>, <value>) pair is already in the input.
+with the same (<key>, <value>) pair is already in the input.
+
With `add`, a new trailer will be added, even if some trailers with
-the same (<token>, <value>) pair are already in the input.
+the same (<key>, <value>) pair are already in the input.
+
-With `replace`, an existing trailer with the same <token> will be
+With `replace`, an existing trailer with the same <key> will be
deleted and the new trailer will be added. The deleted trailer will be
-the closest one (with the same <token>) to the place where the new one
+the closest one (with the same <key>) to the place where the new one
will be added.
+
With `doNothing`, nothing will be done; that is no new trailer will be
-added if there is already one with the same <token> in the input.
+added if there is already one with the same <key> in the input.
trailer.ifmissing::
This option makes it possible to choose what action will be
performed when there is not yet any trailer with the same
- <token> in the input.
+ <key> in the input.
+
The valid values for this option are: `add` (this is the default) and
`doNothing`.
@@ -231,34 +258,40 @@ With `add`, a new trailer will be added.
+
With `doNothing`, nothing will be done.
-trailer.<token>.key::
- This `key` will be used instead of <token> in the trailer. At
- the end of this key, a separator can appear and then some
- space characters. By default the only valid separator is ':',
- but this can be changed using the `trailer.separators` config
- variable.
+trailer.<keyAlias>.key::
+ Defines a <keyAlias> for the <key>. The <keyAlias> must be a
+ prefix (case does not matter) of the <key>. For example, in `git
+ config trailer.ack.key "Acked-by"` the "Acked-by" is the <key> and
+ the "ack" is the <keyAlias>. This configuration allows the shorter
+ `--trailer "ack:..."` invocation on the command line using the "ack"
+ <keyAlias> instead of the longer `--trailer "Acked-by:..."`.
++
+At the end of the <key>, a separator can appear and then some
+space characters. By default the only valid separator is ':',
+but this can be changed using the `trailer.separators` config
+variable.
+
-If there is a separator, then the key will be used instead of both the
-<token> and the default separator when adding the trailer.
+If there is a separator in the key, then it overrides the default
+separator when adding the trailer.
-trailer.<token>.where::
+trailer.<keyAlias>.where::
This option takes the same values as the 'trailer.where'
configuration variable and it overrides what is specified by
- that option for trailers with the specified <token>.
+ that option for trailers with the specified <keyAlias>.
-trailer.<token>.ifexists::
+trailer.<keyAlias>.ifexists::
This option takes the same values as the 'trailer.ifexists'
configuration variable and it overrides what is specified by
- that option for trailers with the specified <token>.
+ that option for trailers with the specified <keyAlias>.
-trailer.<token>.ifmissing::
+trailer.<keyAlias>.ifmissing::
This option takes the same values as the 'trailer.ifmissing'
configuration variable and it overrides what is specified by
- that option for trailers with the specified <token>.
+ that option for trailers with the specified <keyAlias>.
-trailer.<token>.command::
- Deprecated in favor of 'trailer.<token>.cmd'.
- This option behaves in the same way as 'trailer.<token>.cmd', except
+trailer.<keyAlias>.command::
+ Deprecated in favor of 'trailer.<keyAlias>.cmd'.
+ This option behaves in the same way as 'trailer.<keyAlias>.cmd', except
that it doesn't pass anything as argument to the specified command.
Instead the first occurrence of substring $ARG is replaced by the
<value> that would be passed as argument.
@@ -266,29 +299,29 @@ trailer.<token>.command::
Note that $ARG in the user's command is
only replaced once and that the original way of replacing $ARG is not safe.
+
-When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given
-for the same <token>, 'trailer.<token>.cmd' is used and
-'trailer.<token>.command' is ignored.
+When both 'trailer.<keyAlias>.cmd' and 'trailer.<keyAlias>.command' are given
+for the same <keyAlias>, 'trailer.<keyAlias>.cmd' is used and
+'trailer.<keyAlias>.command' is ignored.
-trailer.<token>.cmd::
+trailer.<keyAlias>.cmd::
This option can be used to specify a shell command that will be called
- once to automatically add a trailer with the specified <token>, and then
- called each time a '--trailer <token>=<value>' argument is specified to
+ once to automatically add a trailer with the specified <keyAlias>, and then
+ called each time a '--trailer <keyAlias>=<value>' argument is specified to
modify the <value> of the trailer that this option would produce.
+
When the specified command is first called to add a trailer
-with the specified <token>, the behavior is as if a special
-'--trailer <token>=<value>' argument was added at the beginning
+with the specified <keyAlias>, the behavior is as if a special
+'--trailer <keyAlias>=<value>' argument was added at the beginning
of the "git interpret-trailers" command, where <value>
is taken to be the standard output of the command with any
leading and trailing whitespace trimmed off.
+
-If some '--trailer <token>=<value>' arguments are also passed
+If some '--trailer <keyAlias>=<value>' arguments are also passed
on the command line, the command is called again once for each
-of these arguments with the same <token>. And the <value> part
+of these arguments with the same <keyAlias>. And the <value> part
of these arguments, if any, will be passed to the command as its
first argument. This way the command can produce a <value> computed
-from the <value> passed in the '--trailer <token>=<value>' argument.
+from the <value> passed in the '--trailer <keyAlias>=<value>' argument.
EXAMPLES
--------
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 2a66cf8880..579682172f 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -120,11 +120,11 @@ By default, `git log` does not generate any diff output. The options
below can be used to show the changes made by each commit.
Note that unless one of `--diff-merges` variants (including short
-`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+`-m`, `-c`, `--cc`, and `--dd` options) is explicitly given, merge commits
will not show a diff, even if a diff format like `--patch` is
selected, nor will they match search options like `-S`. The exception
is when `--first-parent` is in use, in which case `first-parent` is
-the default format.
+the default format for merge commits.
:git-log: 1
:diff-merges-default: `off`
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 1bc0328bb7..58c529afbe 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -25,12 +25,12 @@ SYNOPSIS
DESCRIPTION
-----------
-This merges the file listing in the index with the actual working
+This command merges the file listing in the index with the actual working
directory list, and shows different combinations of the two.
-One or more of the options below may be used to determine the files
+Several flags can be used to determine which files are
shown, and each file may be printed multiple times if there are
-multiple entries in the index or multiple statuses are applicable for
+multiple entries in the index or if multiple statuses are applicable for
the relevant file selection options.
OPTIONS
@@ -62,7 +62,7 @@ OPTIONS
matching an exclude pattern. When showing "other" files
(i.e. when used with '-o'), show only those matched by an
exclude pattern. Standard ignore rules are not automatically
- activated, therefore at least one of the `--exclude*` options
+ activated; therefore, at least one of the `--exclude*` options
is required.
-s::
@@ -119,8 +119,10 @@ OPTIONS
--exclude-per-directory=<file>::
Read additional exclude patterns that apply only to the
- directory and its subdirectories in <file>. Deprecated; use
- --exclude-standard instead.
+ directory and its subdirectories in <file>. If you are
+ trying to emulate the way Porcelain commands work, using
+ the `--exclude-standard` option instead is easier and more
+ thorough.
--exclude-standard::
Add the standard Git exclusions: .git/info/exclude, .gitignore
@@ -141,7 +143,7 @@ OPTIONS
Show status tags together with filenames. Note that for
scripting purposes, linkgit:git-status[1] `--porcelain` and
linkgit:git-diff-files[1] `--name-status` are almost always
- superior alternatives, and users should look at
+ superior alternatives; users should look at
linkgit:git-status[1] `--short` or linkgit:git-diff[1]
`--name-status` for more user-friendly alternatives.
+
@@ -217,9 +219,9 @@ followed by the ("attr/<eolattr>").
--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).
+ It also interpolates `%%` to `%`, and `%xXX` where `XX` are hex digits
+ interpolates to character with hex code `XX`; for example `%x00`
+ interpolates to `\0` (NUL), `%x09` to `\t` (TAB) and %x0a to `\n` (LF).
--format cannot be combined with `-s`, `-o`, `-k`, `-t`, `--resolve-undo`
and `--eol`.
\--::
@@ -298,9 +300,8 @@ traversing the directory tree and finding files to show when the
flags --others or --ignored are specified. linkgit:gitignore[5]
specifies the format of exclude patterns.
-Generally, you should just use --exclude-standard, but for historical
-reasons the exclude patterns can be specified from the following
-places, in order:
+These exclude patterns can be specified from the following places,
+in order:
1. The command-line flag --exclude=<pattern> specifies a
single pattern. Patterns are ordered in the same order
@@ -322,6 +323,18 @@ top of the directory tree. A pattern read from a file specified
by --exclude-per-directory is relative to the directory that the
pattern file appears in.
+Generally, you should be able to use `--exclude-standard` when you
+want the exclude rules applied the same way as what Porcelain
+commands do. To emulate what `--exclude-standard` specifies, you
+can give `--exclude-per-directory=.gitignore`, and then specify:
+
+ 1. The file specified by the `core.excludesfile` configuration
+ variable, if exists, or the `$XDG_CONFIG_HOME/git/ignore` file.
+
+ 2. The `$GIT_DIR/info/exclude` file.
+
+via the `--exclude-from=` option.
+
SEE ALSO
--------
linkgit:git-read-tree[1], linkgit:gitignore[5]
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 1c4f696ab5..d71c4ab3e2 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -9,7 +9,7 @@ git-ls-remote - List references in a remote repository
SYNOPSIS
--------
[verse]
-'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]
+'git ls-remote' [--branches] [--tags] [--refs] [--upload-pack=<exec>]
[-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
[--symref] [<repository> [<patterns>...]]
@@ -21,14 +21,16 @@ commit IDs.
OPTIONS
-------
--h::
---heads::
+-b::
+--branches::
-t::
--tags::
- Limit to only refs/heads and refs/tags, respectively.
+ Limit to only local branches and local tags, respectively.
These options are _not_ mutually exclusive; when given
both, references stored in refs/heads and refs/tags are
- displayed. Note that `git ls-remote -h` used without
+ displayed. Note that `--heads` and `-h` are deprecated
+ synonyms for `--branches` and `-b` and may be removed in
+ the future. Also note that `git ls-remote -h` used without
anything else on the command line gives help, consistent
with other git subcommands.
@@ -79,6 +81,9 @@ OPTIONS
character.
When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line.
+ When no `--server-option=<option>` is given from the command line,
+ the values of configuration variable `remote.<name>.serverOption`
+ are used instead.
<repository>::
The "remote" repository to query. This parameter can be
diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index e3b2a88c4b..3f0a6662c8 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -34,7 +34,7 @@ OPTIONS
-b::
If any file doesn't begin with a From line, assume it is a
- single mail message instead of signaling error.
+ single mail message instead of signaling an error.
-d<prec>::
Instead of the default 4 digits with leading zeros,
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt
index 805e5a2e3a..6e6651309d 100644
--- a/Documentation/git-maintenance.txt
+++ b/Documentation/git-maintenance.txt
@@ -102,11 +102,14 @@ prefetch::
requested refs within `refs/prefetch/`. Also, tags are not updated.
+
This is done to avoid disrupting the remote-tracking branches. The end users
-expect these refs to stay unmoved unless they initiate a fetch. With prefetch
-task, however, the objects necessary to complete a later real fetch would
-already be obtained, so the real fetch would go faster. In the ideal case,
+expect these refs to stay unmoved unless they initiate a fetch. However,
+with the prefetch task, the objects necessary to complete a later real fetch
+would already be obtained, making the real fetch faster. In the ideal case,
it will just become an update to a bunch of remote-tracking branches without
any object transfer.
++
+The `remote.<name>.skipFetchAll` configuration can be used to
+exclude a particular remote from getting prefetched.
gc::
Clean up unnecessary files and optimize the local repository. "GC"
@@ -217,7 +220,9 @@ on an hourly basis. Each run executes the "hourly" tasks. At midnight,
that process also executes the "daily" tasks. At midnight on the first day
of the week, that process also executes the "weekly" tasks. A single
process iterates over each registered repository, performing the scheduled
-tasks for that frequency. Depending on the number of registered
+tasks for that frequency. The processes are scheduled to a random minute of
+the hour per client to spread out the load that multiple clients might
+generate (e.g. from prefetching). Depending on the number of registered
repositories and their sizes, this process may take longer than an hour.
In this case, multiple `git maintenance run` commands may run on the same
repository at the same time, colliding on the object database lock. This
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index b01ba3d356..5ab957cfbc 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -18,7 +18,7 @@ SYNOPSIS
DESCRIPTION
-----------
-'git merge-base' finds best common ancestor(s) between two commits to use
+'git merge-base' finds the best common ancestor(s) between two commits to use
in a three-way merge. One common ancestor is 'better' than another common
ancestor if the latter is an ancestor of the former. A common ancestor
that does not have any better common ancestor is a 'best common
@@ -28,7 +28,7 @@ merge base for a pair of commits.
OPERATION MODES
---------------
-As the most common special case, specifying only two commits on the
+In the most common special case, specifying only two commits on the
command line means computing the merge base between the given two commits.
More generally, among the two commits to compute the merge base from,
@@ -64,7 +64,7 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option.
the two commits, but also takes into account the reflog of
<ref> to see if the history leading to <commit> forked from
an earlier incarnation of the branch <ref> (see discussion
- on this mode below).
+ of this mode below).
OPTIONS
-------
@@ -88,7 +88,7 @@ For example, with this topology:
the merge base between 'A' and 'B' is '1'.
-Given three commits 'A', 'B' and 'C', `git merge-base A B C` will compute the
+Given three commits 'A', 'B', and 'C', `git merge-base A B C` will compute the
merge base between 'A' and a hypothetical commit 'M', which is a merge
between 'B' and 'C'. For example, with this topology:
@@ -130,7 +130,7 @@ When the history involves criss-cross merges, there can be more than one
---2---o---o---B
....
-both '1' and '2' are merge-bases of A and B. Neither one is better than
+both '1' and '2' are merge bases of A and B. Neither one is better than
the other (both are 'best' merge bases). When the `--all` option is not given,
it is unspecified which best one is output.
@@ -204,7 +204,7 @@ will find B0, and
$ git rebase --onto origin/master $fork_point topic
-will replay D0, D1 and D on top of B to create a new history of this
+will replay D0, D1, and D on top of B to create a new history of this
shape:
....
diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt
index 7e9093fab6..71915a00fa 100644
--- a/Documentation/git-merge-file.txt
+++ b/Documentation/git-merge-file.txt
@@ -11,19 +11,20 @@ SYNOPSIS
[verse]
'git merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
[--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
- [--[no-]diff3] <current-file> <base-file> <other-file>
+ [--[no-]diff3] [--object-id] <current> <base> <other>
DESCRIPTION
-----------
-'git merge-file' incorporates all changes that lead from the `<base-file>`
-to `<other-file>` into `<current-file>`. The result ordinarily goes into
-`<current-file>`. 'git merge-file' is useful for combining separate changes
-to an original. Suppose `<base-file>` is the original, and both
-`<current-file>` and `<other-file>` are modifications of `<base-file>`,
+Given three files `<current>`, `<base>` and `<other>`,
+'git merge-file' incorporates all changes that lead from `<base>`
+to `<other>` into `<current>`. The result ordinarily goes into
+`<current>`. 'git merge-file' is useful for combining separate changes
+to an original. Suppose `<base>` is the original, and both
+`<current>` and `<other>` are modifications of `<base>`,
then 'git merge-file' combines both changes.
-A conflict occurs if both `<current-file>` and `<other-file>` have changes
+A conflict occurs if both `<current>` and `<other>` have changes
in a common segment of lines. If a conflict is found, 'git merge-file'
normally outputs a warning and brackets the conflict with lines containing
<<<<<<< and >>>>>>> markers. A typical conflict will look like this:
@@ -36,10 +37,14 @@ normally outputs a warning and brackets the conflict with lines containing
If there are conflicts, the user should edit the result and delete one of
the alternatives. When `--ours`, `--theirs`, or `--union` option is in effect,
-however, these conflicts are resolved favouring lines from `<current-file>`,
-lines from `<other-file>`, or lines from both respectively. The length of the
+however, these conflicts are resolved favouring lines from `<current>`,
+lines from `<other>`, or lines from both respectively. The length of the
conflict markers can be given with the `--marker-size` option.
+If `--object-id` is specified, exactly the same behavior occurs, except that
+instead of specifying what to merge as files, it is specified as a list of
+object IDs referring to blobs.
+
The exit value of this program is negative on error, and the number of
conflicts otherwise (truncated to 127 if there are more than that many
conflicts). If the merge was clean, the exit value is 0.
@@ -52,6 +57,14 @@ linkgit:git[1].
OPTIONS
-------
+--object-id::
+ Specify the contents to merge as blobs in the current repository instead of
+ files. In this case, the operation must take place within a valid repository.
++
+If the `-p` option is specified, the merged file (including conflicts, if any)
+goes to standard output as normal; otherwise, the merged file is written to the
+object store and the object ID of its blob is written to standard output.
+
-L <label>::
This option may be given up to three times, and
specifies labels to be used in place of the
@@ -62,7 +75,7 @@ OPTIONS
-p::
Send results to standard output instead of overwriting
- `<current-file>`.
+ `<current>`.
-q::
Quiet; do not warn about conflicts.
@@ -79,6 +92,12 @@ OPTIONS
Instead of leaving conflicts in the file, resolve conflicts
favouring our (or their or both) side of the lines.
+--diff-algorithm={patience|minimal|histogram|myers}::
+ Use a different diff algorithm while merging. The current default is "myers",
+ but selecting more recent algorithm such as "histogram" can help
+ avoid mismerges that occur due to unimportant matching lines
+ (such as braces from distinct functions). See also
+ linkgit:git-diff[1] `--diff-algorithm`.
EXAMPLES
--------
@@ -93,6 +112,11 @@ EXAMPLES
merges tmp/a123 and tmp/c345 with the base tmp/b234, but uses labels
`a` and `c` instead of `tmp/a123` and `tmp/c345`.
+`git merge-file -p --object-id abc1234 def567 890abcd`::
+
+ combines the changes of the blob abc1234 and 890abcd since def567,
+ tries to merge them and writes the result to standard output
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index ffc4fbf7e8..0b6a8a19b1 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -19,12 +19,12 @@ DESCRIPTION
This command has a modern `--write-tree` mode and a deprecated
`--trivial-merge` mode. With the exception of the
<<DEPMERGE,DEPRECATED DESCRIPTION>> section at the end, the rest of
-this documentation describes modern `--write-tree` mode.
+this documentation describes the modern `--write-tree` mode.
Performs a merge, but does not make any new commits and does not read
from or write to either the working tree or index.
-The performed merge will use the same feature as the "real"
+The performed merge will use the same features as the "real"
linkgit:git-merge[1], including:
* three way content merges of individual files
@@ -64,10 +64,18 @@ OPTIONS
share no common history. This flag can be given to override that
check and make the merge proceed anyway.
---merge-base=<commit>::
+--merge-base=<tree-ish>::
Instead of finding the merge-bases for <branch1> and <branch2>,
specify a merge-base for the merge, and specifying multiple bases is
currently not supported. This option is incompatible with `--stdin`.
++
+As the merge-base is provided directly, <branch1> and <branch2> do not need
+to specify commits; trees are enough.
+
+-X<option>::
+--strategy-option=<option>::
+ Pass the merge strategy-specific option through to the merge strategy.
+ See linkgit:git-merge[1] for details.
[[OUTPUT]]
OUTPUT
@@ -203,9 +211,15 @@ linkgit:git-commit-tree[1], linkgit:git-write-tree[1],
linkgit:git-update-ref[1], and linkgit:git-mktag[1]. Thus, it can be
used as a part of a series of steps such as:
- NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
- test $? -eq 0 || die "There were conflicts..."
- NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
+ vi message.txt
+ BRANCH1=refs/heads/test
+ BRANCH2=main
+ NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) || {
+ echo "There were conflicts..." 1>&2
+ exit 1
+ }
+ NEWCOMMIT=$(git commit-tree $NEWTREE -F message.txt \
+ -p $BRANCH1 -p $BRANCH2)
git update-ref $BRANCH1 $NEWCOMMIT
Note that when the exit status is non-zero, `NEWTREE` in this sequence
@@ -253,7 +267,7 @@ Do NOT attempt to guess or make the user guess the conflict types from
the <<CFI,Conflicted file info>> list. The information there is
insufficient to do so. For example: Rename/rename(1to2) conflicts (both
sides renamed the same file differently) will result in three different
-file having higher order stages (but each only has one higher order
+files having higher order stages (but each only has one higher order
stage), with no way (short of the <<IM,Informational messages>> section)
to determine which three files are related. File/directory conflicts
also result in a file with exactly one higher order stage.
@@ -263,7 +277,7 @@ a file with exactly one higher order stage. In all cases, the
<<IM,Informational messages>> section has the necessary info, though it
is not designed to be machine parseable.
-Do NOT assume that each paths from <<CFI,Conflicted file info>>, and
+Do NOT assume that each path from <<CFI,Conflicted file info>>, and
the logical conflicts in the <<IM,Informational messages>> have a
one-to-one mapping, nor that there is a one-to-many mapping, nor a
many-to-one mapping. Many-to-many mappings exist, meaning that each
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 8625c5cb0e..1ab69f61f5 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -20,12 +20,12 @@ DESCRIPTION
-----------
Incorporates changes from the named commits (since the time their
histories diverged from the current branch) into the current
-branch. This command is used by 'git pull' to incorporate changes
+branch. This command is used by `git pull` to incorporate changes
from another repository and can be used by hand to merge changes
from one branch into another.
Assume the following history exists and the current branch is
-"`master`":
+`master`:
------------
A---B---C topic
@@ -33,7 +33,7 @@ Assume the following history exists and the current branch is
D---E---F---G master
------------
-Then "`git merge topic`" will replay the changes made on the
+Then `git merge topic` will replay the changes made on the
`topic` branch since it diverged from `master` (i.e., `E`) until
its current commit (`C`) on top of `master`, and record the result
in a new commit along with the names of the two parent commits and
@@ -46,21 +46,21 @@ a log message from the user describing the changes. Before the operation,
D---E---F---G---H master
------------
-The second syntax ("`git merge --abort`") can only be run after the
-merge has resulted in conflicts. 'git merge --abort' will abort the
-merge process and try to reconstruct the pre-merge state. However,
-if there were uncommitted changes when the merge started (and
-especially if those changes were further modified after the merge
-was started), 'git merge --abort' will in some cases be unable to
-reconstruct the original (pre-merge) changes. Therefore:
+A merge stops if there's a conflict that cannot be resolved
+automatically or if `--no-commit` was provided when initiating the
+merge. At that point you can run `git merge --abort` or `git merge
+--continue`.
-*Warning*: Running 'git merge' with non-trivial uncommitted changes is
+`git merge --abort` will abort the merge process and try to reconstruct
+the pre-merge state. However, if there were uncommitted changes when the
+merge started (and especially if those changes were further modified
+after the merge was started), `git merge --abort` will in some cases be
+unable to reconstruct the original (pre-merge) changes. Therefore:
+
+*Warning*: Running `git merge` with non-trivial uncommitted changes is
discouraged: while possible, it may leave you in a state that is hard to
back out of in the case of a conflict.
-The third syntax ("`git merge --continue`") can only be run after the
-merge has resulted in conflicts.
-
OPTIONS
-------
:git-merge: 1
@@ -74,8 +74,8 @@ include::merge-options.txt[]
If `--log` is specified, a shortlog of the commits being merged
will be appended to the specified message.
+
-The 'git fmt-merge-msg' command can be
-used to give a good default for automated 'git merge'
+The `git fmt-merge-msg` command can be
+used to give a good default for automated `git merge`
invocations. The automated message can include the branch description.
--into-name <branch>::
@@ -104,14 +104,14 @@ include::rerere-options.txt[]
present, apply it to the worktree.
+
If there were uncommitted worktree changes present when the merge
-started, 'git merge --abort' will in some cases be unable to
+started, `git merge --abort` will in some cases be unable to
reconstruct these changes. It is therefore recommended to always
-commit or stash your changes before running 'git merge'.
+commit or stash your changes before running `git merge`.
+
-'git merge --abort' is equivalent to 'git reset --merge' when
+`git merge --abort` is equivalent to `git reset --merge` when
`MERGE_HEAD` is present unless `MERGE_AUTOSTASH` is also present in
-which case 'git merge --abort' applies the stash entry to the worktree
-whereas 'git reset --merge' will save the stashed changes in the stash
+which case `git merge --abort` applies the stash entry to the worktree
+whereas `git reset --merge` will save the stashed changes in the stash
list.
--quit::
@@ -120,8 +120,8 @@ list.
stash entry will be saved to the stash list.
--continue::
- After a 'git merge' stops due to conflicts you can conclude the
- merge by running 'git merge --continue' (see "HOW TO RESOLVE
+ After a `git merge` stops due to conflicts you can conclude the
+ merge by running `git merge --continue` (see "HOW TO RESOLVE
CONFLICTS" section below).
<commit>...::
@@ -144,25 +144,25 @@ PRE-MERGE CHECKS
Before applying outside changes, you should get your own work in
good shape and committed locally, so it will not be clobbered if
there are conflicts. See also linkgit:git-stash[1].
-'git pull' and 'git merge' will stop without doing anything when
-local uncommitted changes overlap with files that 'git pull'/'git
-merge' may need to update.
+`git pull` and `git merge` will stop without doing anything when
+local uncommitted changes overlap with files that `git pull`/`git
+merge` may need to update.
To avoid recording unrelated changes in the merge commit,
-'git pull' and 'git merge' will also abort if there are any changes
+`git pull` and `git merge` will also abort if there are any changes
registered in the index relative to the `HEAD` commit. (Special
narrow exceptions to this rule may exist depending on which merge
strategy is in use, but generally, the index must match HEAD.)
-If all named commits are already ancestors of `HEAD`, 'git merge'
+If all named commits are already ancestors of `HEAD`, `git merge`
will exit early with the message "Already up to date."
FAST-FORWARD MERGE
------------------
Often the current branch head is an ancestor of the named commit.
-This is the most common case especially when invoked from 'git
-pull': you are tracking an upstream repository, you have committed
+This is the most common case especially when invoked from `git
+pull`: you are tracking an upstream repository, you have committed
no local changes, and now you want to update to a newer upstream
revision. In this case, a new commit is not needed to store the
combined history; instead, the `HEAD` (along with the index) is
@@ -196,7 +196,7 @@ happens:
can inspect the stages with `git ls-files -u`). The working
tree files contain the result of the merge operation; i.e. 3-way
merge results with familiar conflict markers `<<<` `===` `>>>`.
-5. A special ref `AUTO_MERGE` is written, pointing to a tree
+5. A ref named `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).
@@ -269,7 +269,7 @@ Barbie's remark on your side. The only thing you can tell is that your
side wants to say it is hard and you'd prefer to go shopping, while the
other side wants to claim it is easy.
-An alternative style can be used by setting the "merge.conflictStyle"
+An alternative style can be used by setting the `merge.conflictStyle`
configuration variable to either "diff3" or "zdiff3". In "diff3"
style, the above conflict may look like this:
@@ -328,15 +328,15 @@ After seeing a conflict, you can do two things:
* Resolve the conflicts. Git will mark the conflicts in
the working tree. Edit the files into shape and
- 'git add' them to the index. Use 'git commit' or
- 'git merge --continue' to seal the deal. The latter command
+ `git add` them to the index. Use `git commit` or
+ `git merge --continue` to seal the deal. The latter command
checks whether there is a (interrupted) merge in progress
- before calling 'git commit'.
+ before calling `git commit`.
You can work through the conflict with a number of tools:
* Use a mergetool. `git mergetool` to launch a graphical
- mergetool which will work you through the merge.
+ mergetool which will work through the merge with you.
* Look at the diffs. `git diff` will show a three-way diff,
highlighting changes from both the `HEAD` and `MERGE_HEAD`
@@ -392,7 +392,7 @@ CONFIGURATION
branch.<name>.mergeOptions::
Sets default options for merging into branch <name>. The syntax and
- supported options are the same as those of 'git merge', but option
+ supported options are the same as those of `git merge`, but option
values containing whitespace characters are currently not supported.
include::includes/cmd-config-section-rest.txt[]
diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt
index 3e8f59ac0e..0726b560d4 100644
--- a/Documentation/git-mergetool--lib.txt
+++ b/Documentation/git-mergetool--lib.txt
@@ -28,22 +28,22 @@ to define the operation mode for the functions listed below.
FUNCTIONS
---------
get_merge_tool::
- returns a merge tool. the return code is 1 if we returned a guessed
+ Returns a merge tool. The return code is 1 if we returned a guessed
merge tool, else 0. '$GIT_MERGETOOL_GUI' may be set to 'true' to
search for the appropriate guitool.
get_merge_tool_cmd::
- returns the custom command for a merge tool.
+ Returns the custom command for a merge tool.
get_merge_tool_path::
- returns the custom path for a merge tool.
+ Returns the custom path for a merge tool.
initialize_merge_tool::
- bring merge tool specific functions into scope so they can be used or
+ Brings merge tool specific functions into scope so they can be used or
overridden.
run_merge_tool::
- launches a merge tool given the tool name and a true/false
+ Launches a merge tool given the tool name and a true/false
flag to indicate whether a merge base is present.
'$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
for use by the merge tool.
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index 07535f6576..b9e20c5dcd 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -17,7 +17,7 @@ Use `git mergetool` to run one of several merge utilities to resolve
merge conflicts. It is typically run after 'git merge'.
If one or more <file> parameters are given, the merge tool program will
-be run to resolve differences on each file (skipping those without
+be run to resolve differences in each file (skipping those without
conflicts). Specifying a directory will include all unresolved files in
that path. If no <file> names are specified, 'git mergetool' will run
the merge tool program on every file with merge conflicts.
@@ -49,7 +49,7 @@ variable `mergetool.<tool>.cmd`.
+
When 'git mergetool' is invoked with this tool (either through the
`-t` or `--tool` option or the `merge.tool` configuration
-variable) the configured command line will be invoked with `$BASE`
+variable), the configured command line will be invoked with `$BASE`
set to the name of a temporary file containing the common base for
the merge, if available; `$LOCAL` set to the name of a temporary
file containing the contents of the file on the current branch;
@@ -81,7 +81,7 @@ success of the resolution after the custom tool has exited.
-g::
--gui::
- When 'git-mergetool' is invoked with the `-g` or `--gui` option
+ When 'git-mergetool' is invoked with the `-g` or `--gui` option,
the default merge tool will be read from the configured
`merge.guitool` variable instead of `merge.tool`. If
`merge.guitool` is not set, we will fallback to the tool
@@ -115,7 +115,7 @@ These are safe to remove once a file has been merged and its
`git mergetool` session has completed.
Setting the `mergetool.keepBackup` configuration variable to `false`
-causes `git mergetool` to automatically remove the backup as files
+causes `git mergetool` to automatically remove the backup files as files
are successfully merged.
BACKEND SPECIFIC HINTS
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt
index b2a2e80d42..006d759962 100644
--- a/Documentation/git-mktag.txt
+++ b/Documentation/git-mktag.txt
@@ -14,7 +14,7 @@ SYNOPSIS
DESCRIPTION
-----------
-Reads a tag contents on standard input and creates a tag object. The
+Reads a tag's contents on standard input and creates a tag object. The
output is the new tag's <object> identifier.
This command is mostly equivalent to linkgit:git-hash-object[1]
@@ -27,7 +27,7 @@ write a tag found in `my-tag`:
The difference is that mktag will die before writing the tag if the
tag doesn't pass a linkgit:git-fsck[1] check.
-The "fsck" check done mktag is stricter than what linkgit:git-fsck[1]
+The "fsck" check done by mktag is stricter than what linkgit:git-fsck[1]
would run by default in that all `fsck.<msg-id>` messages are promoted
from warnings to errors (so e.g. a missing "tagger" line is an error).
@@ -56,7 +56,7 @@ has a very simple fixed format: four lines of
tagger <tagger>
followed by some 'optional' free-form message (some tags created
-by older Git may not have `tagger` line). The message, when it
+by older Git may not have a `tagger` line). The message, when it
exists, is separated by a blank line from the header. The
message part may contain a signature that Git itself doesn't
care about, but that can be verified with gpg.
diff --git a/Documentation/git-mktree.txt b/Documentation/git-mktree.txt
index 76b44f4da1..383f09dd33 100644
--- a/Documentation/git-mktree.txt
+++ b/Documentation/git-mktree.txt
@@ -25,13 +25,13 @@ OPTIONS
--missing::
Allow missing objects. The default behaviour (without this option)
- is to verify that each tree entry's sha1 identifies an existing
+ is to verify that each tree entry's hash identifies an existing
object. This option has no effect on the treatment of gitlink entries
(aka "submodules") which are always allowed to be missing.
--batch::
Allow building of more than one tree object before exiting. Each
- tree is separated by a single blank line. The final new-line is
+ tree is separated by a single blank line. The final newline is
optional. Note - if the `-z` option is used, lines are terminated
with NUL.
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 3696506eb3..631d5c7d15 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -64,6 +64,12 @@ The file given at `<path>` is expected to be readable, and can contain
duplicates. (If a given OID is given more than once, it is marked as
preferred if at least one instance of it begins with the special `+`
marker).
+
+ --incremental::
+ Write an incremental MIDX file containing only objects
+ and packs not present in an existing MIDX layer.
+ Migrates non-incremental MIDXs to incremental ones when
+ necessary. Incompatible with `--bitmap`.
--
verify::
@@ -74,6 +80,8 @@ expire::
have no objects referenced by the MIDX (with the exception of
`.keep` packs and cruft packs). Rewrite the MIDX file afterward
to remove all references to these pack-files.
++
+NOTE: this mode is incompatible with incremental MIDX files.
repack::
Create a new pack-file containing objects in small pack-files
@@ -95,7 +103,8 @@ repack::
+
If `repack.packKeptObjects` is `false`, then any pack-files with an
associated `.keep` file will not be selected for the batch to repack.
-
++
+NOTE: this mode is incompatible with incremental MIDX files.
EXAMPLES
--------
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index fb0220fd18..dc1bf61534 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -13,10 +13,10 @@ SYNOPSIS
DESCRIPTION
-----------
-Move or rename a file, directory or symlink.
+Move or rename a file, directory, or symlink.
git mv [-v] [-f] [-n] [-k] <source> <destination>
- git mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
+ git mv [-v] [-f] [-n] [-k] <source> ... <destination-directory>
In the first form, it renames <source>, which must exist and be either
a file, symlink or directory, to <destination>.
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index 5c56c87025..d4f1c4d594 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -26,7 +26,7 @@ OPTIONS
--refs=<pattern>::
Only use refs whose names match a given shell pattern. The pattern
- can be one of branch name, tag name or fully qualified ref name. If
+ can be a branch name, a tag name, or a fully qualified ref name. If
given multiple times, use refs whose names match any of the given shell
patterns. Use `--no-refs` to clear any previous ref patterns given.
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index f8310e56a8..84022f99d7 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -9,9 +9,9 @@ SYNOPSIS
--------
[verse]
'git notes' [list [<object>]]
-'git notes' add [-f] [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-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>] [-e] [<object>]
'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
-'git notes' append [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' append [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
'git notes' edit [--allow-empty] [<object>] [--[no-]stripspace]
'git notes' show [<object>]
'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
@@ -56,7 +56,7 @@ SUBCOMMANDS
list::
List the notes object for a given object. If no object is
given, show a list of all note objects and the objects they
- annotate (in the format "<note object> <annotated object>").
+ annotate (in the format "<note-object> <annotated-object>").
This is the default subcommand if no subcommand is given.
add::
@@ -67,7 +67,9 @@ add::
the existing notes will be opened in the editor (like the `edit`
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.
+ option to insert other delimiters. You can use `-e` to edit and
+ fine-tune the message(s) supplied from `-m` and `-F` options
+ interactively (using an editor) before adding the note.
copy::
Copy the notes for the first object onto the second object (defaults to
@@ -93,6 +95,8 @@ append::
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 the notes to be appended given by `-m` and `-F` options with
+ `-e` interactively (using an editor) before appending the note.
edit::
Edit the notes for a given object (defaults to HEAD).
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index a9995a932c..e32404c6aa 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -116,9 +116,7 @@ unreachable object whose mtime is newer than the `--cruft-expiration`).
+
Incompatible with `--unpack-unreachable`, `--keep-unreachable`,
`--pack-loose-unreachable`, `--stdin-packs`, as well as any other
-options which imply `--revs`. Also incompatible with `--max-pack-size`;
-when this option is set, the maximum pack size is not inferred from
-`pack.packSizeLimit`.
+options which imply `--revs`.
--cruft-expiration=<approxidate>::
If specified, objects are eliminated from the cruft pack if they
@@ -298,8 +296,8 @@ So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle.
nevertheless.
--filter=<filter-spec>::
- Requires `--stdout`. Omits certain objects (usually blobs) from
- the resulting packfile. See linkgit:git-rev-list[1] for valid
+ Omits certain objects (usually blobs) from the resulting
+ packfile. See linkgit:git-rev-list[1] for valid
`<filter-spec>` forms.
--no-filter::
diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt
index 284956acb3..2dcabaf74c 100644
--- a/Documentation/git-pack-refs.txt
+++ b/Documentation/git-pack-refs.txt
@@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
SYNOPSIS
--------
[verse]
-'git pack-refs' [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]
+'git pack-refs' [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
DESCRIPTION
-----------
@@ -60,6 +60,19 @@ with many branches of historical interests.
The command usually removes loose refs under `$GIT_DIR/refs`
hierarchy after packing them. This option tells it not to.
+--auto::
+
+Pack refs as needed depending on the current state of the ref database. The
+behavior depends on the ref format used by the repository and may change in the
+future.
++
+ - "files": No special handling for `--auto` has been implemented.
++
+ - "reftable": Tables are compacted such that they form a geometric
+ sequence. For two tables N and N+1, where N+1 is newer, this
+ maintains the property that N is at least twice as big as N+1. Only
+ tables that violate this property are compacted.
+
--include <pattern>::
Pack refs based on a `glob(7)` pattern. Repetitions of this option
diff --git a/Documentation/git-prune-packed.txt b/Documentation/git-prune-packed.txt
index 844d6f808a..db742dcfee 100644
--- a/Documentation/git-prune-packed.txt
+++ b/Documentation/git-prune-packed.txt
@@ -15,7 +15,7 @@ SYNOPSIS
DESCRIPTION
-----------
This program searches the `$GIT_OBJECT_DIRECTORY` for all objects that currently
-exist in a pack file as well as the independent object directories.
+exist in a pack file as well as in the independent object directories.
All such extra objects are removed.
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 03552dd86f..9a45571b90 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -18,7 +18,7 @@ NOTE: In most cases, users should run 'git gc', which calls
'git prune'. See the section "NOTES", below.
This runs 'git fsck --unreachable' using all the refs
-available in `refs/`, optionally with additional set of
+available in `refs/`, optionally with an additional set of
objects specified on the command line, and prunes all unpacked
objects unreachable from any of these head objects from the object database.
In addition, it
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 0e14f8b5b2..b2ae496e48 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -87,7 +87,7 @@ OPTIONS
--verbose::
Pass --verbose to git-fetch and git-merge.
---[no-]recurse-submodules[=yes|on-demand|no]::
+--[no-]recurse-submodules[=(yes|on-demand|no)]::
This option controls if new commits of populated submodules should
be fetched, and if the working trees of active submodules should be
updated, too (see linkgit:git-fetch[1], linkgit:git-config[1] and
@@ -105,7 +105,7 @@ Options related to merging
include::merge-options.txt[]
-r::
---rebase[=false|true|merges|interactive]::
+--rebase[=(false|true|merges|interactive)]::
When true, rebase the current branch on top of the upstream
branch after fetching. If there is a remote-tracking branch
corresponding to the upstream branch and the upstream branch
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 003bc7d9ce..9b7cfbc5c1 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -48,7 +48,7 @@ local one.
OPTIONS[[OPTIONS]]
------------------
<repository>::
- The "remote" repository that is destination of a push
+ The "remote" repository that is the destination of a push
operation. This parameter can be either a URL
(see the section <<URLS,GIT URLS>> below) or the name
of a remote (see the section <<REMOTES,REMOTES>> below).
diff --git a/Documentation/git-quiltimport.txt b/Documentation/git-quiltimport.txt
index 70562dc4c0..40e02d92eb 100644
--- a/Documentation/git-quiltimport.txt
+++ b/Documentation/git-quiltimport.txt
@@ -38,14 +38,14 @@ OPTIONS
a patch. At the time of this writing only missing author
information is warned about.
---author Author Name <Author Email>::
+--author 'Author Name <Author Email>'::
The author name and email address to use when no author
information can be found in the patch description.
--patches <dir>::
The directory to find the quilt patches.
+
-The default for the patch directory is patches
+The default for the patch directory is 'patches'
or the value of the `$QUILT_PATCHES` environment
variable.
diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt
index 0b393715d7..fbdbe0befe 100644
--- a/Documentation/git-range-diff.txt
+++ b/Documentation/git-range-diff.txt
@@ -70,7 +70,7 @@ to revert to color all lines according to the outer diff markers
Defaults to 60. Try a larger value if `git range-diff` erroneously
considers a large change a total rewrite (deletion of one commit
and addition of another), and a smaller one in the reverse case.
- See the ``Algorithm`` section below for an explanation why this is
+ See the ``Algorithm`` section below for an explanation of why this is
needed.
--left-only::
@@ -166,7 +166,7 @@ A typical output of `git range-diff` would look like this:
In this example, there are 3 old and 3 new commits, where the developer
removed the 3rd, added a new one before the first two, and modified the
-commit message of the 2nd commit as well its diff.
+commit message of the 2nd commit as well as its diff.
When the output goes to a terminal, it is color-coded by default, just
like regular `git diff`'s output. In addition, the first line (adding a
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index b09707474d..1c48c28996 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -25,15 +25,15 @@ fast-forward (i.e. 2-way) merge, or a 3-way merge, with the `-m`
flag. When used with `-m`, the `-u` flag causes it to also update
the files in the work tree with the result of the merge.
-Trivial merges are done by 'git read-tree' itself. Only conflicting paths
-will be in unmerged state when 'git read-tree' returns.
+Only trivial merges are done by 'git read-tree' itself. Only conflicting paths
+will be in an unmerged state when 'git read-tree' returns.
OPTIONS
-------
-m::
Perform a merge, not just a read. The command will
refuse to run if your index file has unmerged entries,
- indicating that you have not finished previous merge you
+ indicating that you have not finished a previous merge you
started.
--reset::
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index e7b39ad244..b18cdbc023 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[--onto <newbase> | --keep-base] [<upstream> [<branch>]]
'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
-'git rebase' (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
+'git rebase' (--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
DESCRIPTION
-----------
@@ -289,17 +289,25 @@ See also INCOMPATIBLE OPTIONS below.
+
See also INCOMPATIBLE OPTIONS below.
---empty={drop,keep,ask}::
+--empty=(drop|keep|stop)::
How to handle commits that are not empty to start and are not
clean cherry-picks of any upstream commit, but which become
empty after rebasing (because they contain a subset of already
- upstream changes). With drop (the default), commits that
- become empty are dropped. With keep, such commits are kept.
- With ask (implied by `--interactive`), the rebase will halt when
- an empty commit is applied allowing you to choose whether to
- drop it, edit files more, or just commit the empty changes.
- Other options, like `--exec`, will use the default of drop unless
- `-i`/`--interactive` is explicitly specified.
+ upstream changes):
++
+--
+`drop`;;
+ The commit will be dropped. This is the default behavior.
+`keep`;;
+ The commit will be kept. This option is implied when `--exec` is
+ specified unless `-i`/`--interactive` is also specified.
+`stop`;;
+`ask`;;
+ The rebase will halt when the commit is applied, allowing you to
+ choose whether to drop it, edit files more, or just commit the empty
+ changes. This option is implied when `-i`/`--interactive` is
+ specified. `ask` is a deprecated synonym of `stop`.
+--
+
Note that commits which start empty are kept (unless `--no-keep-empty`
is specified), and commits which are clean cherry-picks (as determined
@@ -523,7 +531,7 @@ See also INCOMPATIBLE OPTIONS below.
+
The commit list format can be changed by setting the configuration option
rebase.instructionFormat. A customized instruction format will automatically
-have the long commit hash prepended to the format.
+have the commit hash prepended to the format.
+
See also INCOMPATIBLE OPTIONS below.
@@ -589,21 +597,27 @@ See also INCOMPATIBLE OPTIONS below.
--autosquash::
--no-autosquash::
- When the commit log message begins with "squash! ..." or "fixup! ..."
- or "amend! ...", and there is already a commit in the todo list that
- matches the same `...`, automatically modify the todo list of
- `rebase -i`, so that the commit marked for squashing comes right after
- the commit to be modified, and change the action of the moved commit
- from `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit
- matches the `...` if the commit subject matches, or if the `...` refers
- to the commit's hash. As a fall-back, partial matches of the commit
- subject work, too. The recommended way to create fixup/amend/squash
- commits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`
- and `--squash` options respectively of linkgit:git-commit[1].
+ Automatically squash commits with specially formatted messages into
+ previous commits being rebased. If a commit message starts with
+ "squash! ", "fixup! " or "amend! ", the remainder of the subject line
+ is taken as a commit specifier, which matches a previous commit if it
+ matches the subject line or the hash of that commit. If no commit
+ matches fully, matches of the specifier with the start of commit
+ subjects are considered.
++
+In the rebase todo list, the actions of squash, fixup and amend commits are
+changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they
+are moved right after the commit they modify. The `--interactive` option can
+be used to review and edit the todo list before proceeding.
+
-If the `--autosquash` option is enabled by default using the
-configuration variable `rebase.autoSquash`, this option can be
-used to override and disable this setting.
+The recommended way to create commits with squash markers is by using the
+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of
+linkgit:git-commit[1], which take the target commit as an argument and
+automatically fill in the subject line of the new commit from that.
++
+Setting configuration variable `rebase.autoSquash` to true enables
+auto-squashing by default for interactive rebase. The `--no-autosquash`
+option can be used to override that setting.
+
See also INCOMPATIBLE OPTIONS below.
@@ -620,13 +634,16 @@ See also INCOMPATIBLE OPTIONS below.
Automatically reschedule `exec` commands that failed. This only makes
sense in interactive mode (or when an `--exec` option was provided).
+
-Even though this option applies once a rebase is started, it's set for
-the whole rebase at the start based on either the
-`rebase.rescheduleFailedExec` configuration (see linkgit:git-config[1]
-or "CONFIGURATION" below) or whether this option is
-provided. Otherwise an explicit `--no-reschedule-failed-exec` at the
-start would be overridden by the presence of
-`rebase.rescheduleFailedExec=true` configuration.
+This option applies once a rebase is started. It is preserved for the whole
+rebase based on, in order, the command line option provided to the initial `git
+rebase`, the `rebase.rescheduleFailedExec` configuration (see
+linkgit:git-config[1] or "CONFIGURATION" below), or it defaults to false.
++
+Recording this option for the whole rebase is a convenience feature. Otherwise
+an explicit `--no-reschedule-failed-exec` at the start would be overridden by
+the presence of a `rebase.rescheduleFailedExec=true` configuration when `git
+rebase --continue` is invoked. Currently, you cannot pass
+`--[no-]reschedule-failed-exec` to `git rebase --continue`.
--update-refs::
--no-update-refs::
@@ -695,7 +712,7 @@ be dropped automatically with `--no-keep-empty`).
Similar to the apply backend, by default the merge backend drops
commits that become empty unless `-i`/`--interactive` is specified (in
which case it stops and asks the user what to do). The merge backend
-also has an `--empty={drop,keep,ask}` option for changing the behavior
+also has an `--empty=(drop|keep|stop)` option for changing the behavior
of handling commits that become empty.
Directory rename detection
@@ -720,7 +737,7 @@ The 'apply' backend works by creating a sequence of patches (by calling
`format-patch` internally), and then applying the patches in sequence
(calling `am` internally). Patches are composed of multiple hunks,
each with line numbers, a context region, and the actual changes. The
-line numbers have to be taken with some fuzz, since the other side
+line numbers have to be taken with some offset, since the other side
will likely have inserted or deleted lines earlier in the file. The
context region is meant to help find how to adjust the line numbers in
order to apply the changes to the right lines. However, if multiple
@@ -957,10 +974,9 @@ The interactive rebase will stop when a command fails (i.e. exits with
non-0 status) to give you an opportunity to fix the problem. You can
continue with `git rebase --continue`.
-The "exec" command launches the command in a shell (the one specified
-in `$SHELL`, or the default shell if `$SHELL` is not set), so you can
-use shell features (like "cd", ">", ";" ...). The command is run from
-the root of the working tree.
+The "exec" command launches the command in a shell (the default one, usually
+/bin/sh), so you can use shell features (like "cd", ">", ";" ...). The command
+is run from the root of the working tree.
----------------------------------
$ git rebase -i --exec "make test"
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 65ff518ccf..20aca92073 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -18,10 +18,10 @@ information fed from the remote end.
This command is usually not invoked directly by the end user.
The UI for the protocol is on the 'git send-pack' side, and the
-program pair is meant to be used to push updates to remote
+program pair is meant to be used to push updates to a remote
repository. For pull operations, see linkgit:git-fetch-pack[1].
-The command allows for creation and fast-forwarding of sha1 refs
+The command allows for the creation and fast-forwarding of sha1 refs
(heads/tags) on the remote end (strictly speaking, it is the
local end 'git-receive-pack' runs, but to the user who is sitting at
the send-pack end, it is updating the remote. Confused?)
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index ec64cbff4c..a929c52982 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git reflog' [show] [<log-options>] [<ref>]
+'git reflog list'
'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
[--rewrite] [--updateref] [--stale-fix]
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
@@ -39,6 +40,8 @@ actions, and in addition the `HEAD` reflog records branch switching.
`git reflog show` is an alias for `git log -g --abbrev-commit
--pretty=oneline`; see linkgit:git-log[1] for more information.
+The "list" subcommand lists all refs which have a corresponding reflog.
+
The "expire" subcommand prunes older reflog entries. Entries older
than `expire` time, or entries older than `expire-unreachable` time
and not reachable from the current tip, are removed from the reflog.
diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.txt
new file mode 100644
index 0000000000..ce31f93061
--- /dev/null
+++ b/Documentation/git-refs.txt
@@ -0,0 +1,74 @@
+git-refs(1)
+===========
+
+NAME
+----
+git-refs - Low-level access to refs
+
+
+SYNOPSIS
+--------
+[verse]
+'git refs migrate' --ref-format=<format> [--dry-run]
+'git refs verify' [--strict] [--verbose]
+
+DESCRIPTION
+-----------
+
+This command provides low-level access to refs.
+
+COMMANDS
+--------
+
+migrate::
+ Migrate ref store between different formats.
+
+verify::
+ Verify reference database consistency.
+
+OPTIONS
+-------
+
+The following options are specific to 'git refs migrate':
+
+--ref-format=<format>::
+ The ref format to migrate the ref store to. Can be one of:
++
+include::ref-storage-format.txt[]
+
+--dry-run::
+ Perform the migration, but do not modify the repository. The migrated
+ refs will be written into a separate directory that can be inspected
+ separately. The name of the directory will be reported on stdout. This
+ can be used to double check that the migration works as expected before
+ performing the actual migration.
+
+The following options are specific to 'git refs verify':
+
+--strict::
+ Enable stricter error checking. This will cause warnings to be
+ reported as errors. See linkgit:git-fsck[1].
+
+--verbose::
+ When verifying the reference database consistency, be chatty.
+
+KNOWN LIMITATIONS
+-----------------
+
+The ref format migration has several known limitations in its current form:
+
+* It is not possible to migrate repositories that have reflogs.
+
+* It is not possible to migrate repositories that have worktrees.
+
+* There is no way to block concurrent writes to the repository during an
+ ongoing migration. Concurrent writes can lead to an inconsistent migrated
+ state. Users are expected to block writes on a higher level. If your
+ repository is registered for scheduled maintenance, it is recommended to
+ unregister it first with git-maintenance(1).
+
+These limitations may eventually be lifted.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote-ext.txt b/Documentation/git-remote-ext.txt
index 88ea7e1cc0..b33ee3c9e8 100644
--- a/Documentation/git-remote-ext.txt
+++ b/Documentation/git-remote-ext.txt
@@ -44,15 +44,15 @@ The following sequences have a special meaning:
This argument will not be passed to '<command>'. Instead, it
will cause the helper to start by sending git:// service requests to
the remote side with the service field set to an appropriate value and
- the repository field set to rest of the argument. Default is not to send
+ the repository field set to the rest of the argument. Default is not to send
such a request.
+
-This is useful if remote side is git:// server accessed over
+This is useful if the remote side is git:// server accessed over
some tunnel.
'%V' (must be first characters in argument)::
This argument will not be passed to '<command>'. Instead it sets
- the vhost field in the git:// service request (to rest of the argument).
+ the vhost field in the git:// service request (to the rest of the argument).
Default is not to send vhost in such request (if sent).
ENVIRONMENT VARIABLES
@@ -82,12 +82,12 @@ begins with `ext::`. Examples:
"ext::ssh -i /home/foo/.ssh/somekey user&#64;host.example %S 'foo/repo'"::
Like host.example:foo/repo, but use /home/foo/.ssh/somekey as
- keypair and user as user on remote side. This avoids needing to
+ keypair and user as the user on the remote side. This avoids the need to
edit .ssh/config.
"ext::socat -t3600 - ABSTRACT-CONNECT:/git-server %G/somerepo"::
Represents repository with path /somerepo accessible over
- git protocol at abstract namespace address /git-server.
+ git protocol at the abstract namespace address /git-server.
"ext::git-server-alias foo %G/repo"::
Represents a repository with path /repo accessed using the
diff --git a/Documentation/git-remote-fd.txt b/Documentation/git-remote-fd.txt
index 0451ceb8a2..1dd2648a79 100644
--- a/Documentation/git-remote-fd.txt
+++ b/Documentation/git-remote-fd.txt
@@ -13,19 +13,19 @@ DESCRIPTION
-----------
This helper uses specified file descriptors to connect to a remote Git server.
This is not meant for end users but for programs and scripts calling git
-fetch, push or archive.
+fetch, push, or archive.
If only <infd> is given, it is assumed to be a bidirectional socket connected
-to remote Git server (git-upload-pack, git-receive-pack or
+to a remote Git server (git-upload-pack, git-receive-pack, or
git-upload-archive). If both <infd> and <outfd> are given, they are assumed
to be pipes connected to a remote Git server (<infd> being the inbound pipe
-and <outfd> being the outbound pipe.
+and <outfd> being the outbound pipe).
It is assumed that any handshaking procedures have already been completed
(such as sending service request for git://) before this helper is started.
<anything> can be any string. It is ignored. It is meant for providing
-information to user in the URL in case that URL is displayed in some
+information to the user in the URL in case that URL is displayed in some
context.
ENVIRONMENT VARIABLES
@@ -45,7 +45,7 @@ EXAMPLES
`git push fd::7,8 master (as URL)`::
Push master, using file descriptor #7 to read data from
git-receive-pack and file descriptor #8 to write data to
- same service.
+ the same service.
`git push fd::7,8/bar master`::
Same as above.
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 1dec314834..932a5c3ea4 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -35,7 +35,7 @@ OPTIONS
-v::
--verbose::
Be a little more verbose and show remote url after name.
- For promisor remotes, also show which filter (`blob:none` etc.)
+ For promisor remotes, also show which filters (`blob:none` etc.)
are configured.
NOTE: This must be placed between `remote` and subcommand.
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index b63e8abc7d..c902512a9e 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -74,6 +74,17 @@ to the new separate pack will be written.
immediately instead of waiting for the next `git gc` invocation.
Only useful with `--cruft -d`.
+--max-cruft-size=<n>::
+ Repack cruft objects into packs as large as `<n>` bytes before
+ creating new packs. As long as there are enough cruft packs
+ smaller than `<n>`, repacking will cause a new cruft pack to
+ be created containing objects from any combined cruft packs,
+ along with any new unreachable objects. Cruft packs larger than
+ `<n>` will not be modified. When the new cruft pack is larger
+ than `<n>` bytes, it will be split into multiple packs, all of
+ which are guaranteed to be at most `<n>` bytes in size. Only
+ useful with `--cruft -d`.
+
--expire-to=<dir>::
Write a cruft pack containing pruned objects (if any) to the
directory `<dir>`. This option is useful for keeping a copy of
@@ -143,6 +154,29 @@ depth is 4095.
a larger and slower repository; see the discussion in
`pack.packSizeLimit`.
+--filter=<filter-spec>::
+ Remove objects matching the filter specification from the
+ resulting packfile and put them into a separate packfile. Note
+ that objects used in the working directory are not filtered
+ out. So for the split to fully work, it's best to perform it
+ in a bare repo and to use the `-a` and `-d` options along with
+ this option. Also `--no-write-bitmap-index` (or the
+ `repack.writebitmaps` config option set to `false`) should be
+ used otherwise writing bitmap index will fail, as it supposes
+ a single packfile containing all the objects. See
+ linkgit:git-rev-list[1] for valid `<filter-spec>` forms.
+
+--filter-to=<dir>::
+ Write the pack containing filtered out objects to the
+ directory `<dir>`. Only useful with `--filter`. This can be
+ used for putting the pack on a separate object directory that
+ is accessed through the Git alternates mechanism. **WARNING:**
+ If the packfile containing the filtered out objects is not
+ accessible, the repo can become corrupt as it might not be
+ possible to access the objects in that packfile. See the
+ `objects` and `objects/info/alternates` sections of
+ linkgit:gitrepository-layout[5].
+
-b::
--write-bitmap-index::
Write a reachability bitmap index as part of the repack. This
@@ -165,7 +199,7 @@ depth is 4095.
Exclude the given pack from repacking. This is the equivalent
of having `.keep` file on the pack. `<pack-name>` is the
pack file name without leading directory (e.g. `pack-123.pack`).
- The option could be specified multiple times to keep multiple
+ The option can be specified multiple times to keep multiple
packs.
--unpack-unreachable=<when>::
diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt
index f271d758c3..0a65460adb 100644
--- a/Documentation/git-replace.txt
+++ b/Documentation/git-replace.txt
@@ -35,7 +35,7 @@ Replacement references will be used by default by all Git commands
except those doing reachability traversal (prune, pack transfer and
fsck).
-It is possible to disable use of replacement references for any
+It is possible to disable the use of replacement references for any
command using the `--no-replace-objects` option just after 'git'.
For example if commit 'foo' has been replaced by commit 'bar':
@@ -111,14 +111,14 @@ OPTIONS
FORMATS
-------
-The following format are available:
+The following formats are available:
* 'short':
- <replaced sha1>
+ <replaced-sha1>
* 'medium':
- <replaced sha1> -> <replacement sha1>
+ <replaced-sha1> -> <replacement-sha1>
* 'long':
- <replaced sha1> (<replaced type>) -> <replacement sha1> (<replacement type>)
+ <replaced-sha1> (<replaced-type>) -> <replacement-sha1> (<replacement-type>)
CREATING REPLACEMENT OBJECTS
----------------------------
diff --git a/Documentation/git-replay.txt b/Documentation/git-replay.txt
new file mode 100644
index 0000000000..8f3300c683
--- /dev/null
+++ b/Documentation/git-replay.txt
@@ -0,0 +1,127 @@
+git-replay(1)
+=============
+
+NAME
+----
+git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos too
+
+
+SYNOPSIS
+--------
+[verse]
+(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>...
+
+DESCRIPTION
+-----------
+
+Takes ranges of commits and replays them onto a new location. Leaves
+the working tree and the index untouched, and updates no references.
+The output of this command is meant to be used as input to
+`git update-ref --stdin`, which would update the relevant branches
+(see the OUTPUT section below).
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+OPTIONS
+-------
+
+--onto <newbase>::
+ Starting point at which to create the new commits. May be any
+ valid commit, and not just an existing branch name.
++
+When `--onto` is specified, the update-ref command(s) in the output will
+update the branch(es) in the revision range to point at the new
+commits, similar to the way how `git rebase --update-refs` updates
+multiple branches in the affected range.
+
+--advance <branch>::
+ Starting point at which to create the new commits; must be a
+ branch name.
++
+When `--advance` is specified, the update-ref command(s) in the output
+will update the branch passed as an argument to `--advance` to point at
+the new commits (in other words, this mimics a cherry-pick operation).
+
+<revision-range>::
+ Range of commits to replay. More than one <revision-range> can
+ be passed, but in `--advance <branch>` mode, they should have
+ a single tip, so that it's clear where <branch> should point
+ to. See "Specifying Ranges" in linkgit:git-rev-parse[1] and the
+ "Commit Limiting" options below.
+
+include::rev-list-options.txt[]
+
+OUTPUT
+------
+
+When there are no conflicts, the output of this command is usable as
+input to `git update-ref --stdin`. It is of the form:
+
+ update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
+ update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
+ update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
+
+where the number of refs updated depends on the arguments passed and
+the shape of the history being replayed. When using `--advance`, the
+number of refs updated is always one, but for `--onto`, it can be one
+or more (rebasing multiple branches simultaneously is supported).
+
+EXIT STATUS
+-----------
+
+For a successful, non-conflicted replay, the exit status is 0. When
+the replay has conflicts, the exit status is 1. If the replay is not
+able to complete (or start) due to some kind of error, the exit status
+is something other than 0 or 1.
+
+EXAMPLES
+--------
+
+To simply rebase `mybranch` onto `target`:
+
+------------
+$ git replay --onto target origin/main..mybranch
+update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}
+------------
+
+To cherry-pick the commits from mybranch onto target:
+
+------------
+$ git replay --advance target origin/main..mybranch
+update refs/heads/target ${NEW_target_HASH} ${OLD_target_HASH}
+------------
+
+Note that the first two examples replay the exact same commits and on
+top of the exact same new base, they only differ in that the first
+provides instructions to make mybranch point at the new commits and
+the second provides instructions to make target point at them.
+
+What if you have a stack of branches, one depending upon another, and
+you'd really like to rebase the whole set?
+
+------------
+$ git replay --contained --onto origin/main origin/main..tipbranch
+update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
+update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
+update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH}
+------------
+
+When calling `git replay`, one does not need to specify a range of
+commits to replay using the syntax `A..B`; any range expression will
+do:
+
+------------
+$ git replay --onto origin/main ^base branch1 branch2 branch3
+update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
+update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
+update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
+------------
+
+This will simultaneously rebase `branch1`, `branch2`, and `branch3`,
+all commits they have since `base`, playing them on top of
+`origin/main`. These three branches may have commits on top of `base`
+that they have in common, but that does not need to be the case.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-request-pull.txt b/Documentation/git-request-pull.txt
index fa5a426709..15dcbb6d91 100644
--- a/Documentation/git-request-pull.txt
+++ b/Documentation/git-request-pull.txt
@@ -16,7 +16,7 @@ DESCRIPTION
Generate a request asking your upstream project to pull changes into
their tree. The request, printed to the standard output,
begins with the branch description, summarizes
-the changes and indicates from where they can be pulled.
+the changes, and indicates from where they can be pulled.
The upstream project is expected to have the commit named by
`<start>` and the output asks it to integrate the changes you made
@@ -50,7 +50,7 @@ EXAMPLES
--------
Imagine that you built your work on your `master` branch on top of
-the `v1.0` release, and want it to be integrated to the project.
+the `v1.0` release, and want it to be integrated into the project.
First you push that change to your public repository for others to
see:
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index 5964810caa..975825b44a 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -78,6 +78,8 @@ all modified paths.
--theirs::
When restoring files in the working tree from the index, use
stage #2 ('ours') or #3 ('theirs') for unmerged paths.
+ This option cannot be used when checking out paths from a
+ tree-ish (i.e. with the `--source` option).
+
Note that during `git rebase` and `git pull --rebase`, 'ours' and
'theirs' may appear swapped. See the explanation of the same options
@@ -87,6 +89,8 @@ in linkgit:git-checkout[1] for details.
--merge::
When restoring files on the working tree from the index,
recreate the conflicted merge in the unmerged paths.
+ This option cannot be used when checking out paths from a
+ tree-ish (i.e. with the `--source` option).
--conflict=<style>::
The same as `--merge` option above, but changes the way the
@@ -101,7 +105,7 @@ in linkgit:git-checkout[1] for details.
specified. Unmerged paths on the working tree are left alone.
--ignore-skip-worktree-bits::
- In sparse checkout mode, by default is to only update entries
+ In sparse checkout mode, the default is to only update entries
matched by `<pathspec>` and sparse patterns in
$GIT_DIR/info/sparse-checkout. This option ignores the sparse
patterns and unconditionally restores any files in
@@ -195,7 +199,7 @@ the same as using linkgit:git-reset[1])
$ git restore --staged hello.c
------------
-or you can restore both the index and the working tree (this the same
+or you can restore both the index and the working tree (this is the same
as using linkgit:git-checkout[1])
------------
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 51029a2271..2e05c4b510 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -17,9 +17,9 @@ DESCRIPTION
:git-rev-list: 1
include::rev-list-description.txt[]
-'rev-list' is a very essential Git command, since it
+'rev-list' is an essential Git command, since it
provides the ability to build and traverse commit ancestry graphs. For
-this reason, it has a lot of different options that enables it to be
+this reason, it has a lot of different options that enable it to be
used by commands as different as 'git bisect' and
'git repack'.
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index f26a7591e3..dc12d38534 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -9,17 +9,24 @@ git-rev-parse - Pick out and massage parameters
SYNOPSIS
--------
[verse]
-'git rev-parse' [<options>] <args>...
+'git rev-parse' [<options>] <arg>...
DESCRIPTION
-----------
-Many Git porcelainish commands take mixture of flags
+Many Git porcelainish commands take a mixture of flags
(i.e. parameters that begin with a dash '-') and parameters
meant for the underlying 'git rev-list' command they use internally
and flags and parameters for the other commands they use
-downstream of 'git rev-list'. This command is used to
-distinguish between them.
+downstream of 'git rev-list'. The primary purpose of this command
+is to allow calling programs to distinguish between them. There are
+a few other operation modes that have nothing to do with the above
+"help parse command line options".
+
+Unless otherwise specified, most of the options and operation modes
+require you to run this command inside a git repository or a working
+tree that is under the control of a git repository, and will give you
+a fatal error otherwise.
OPTIONS
@@ -32,11 +39,15 @@ Each of these options must appear first on the command line.
--parseopt::
Use 'git rev-parse' in option parsing mode (see PARSEOPT section below).
+ The command in this mode can be used outside a repository or
+ a working tree controlled by a repository.
--sq-quote::
Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
section below). In contrast to the `--sq` option below, this
- mode does only quoting. Nothing else is done to command input.
+ mode only does quoting. Nothing else is done to command input.
+ The command in this mode can be used outside a repository or
+ a working tree controlled by a repository.
Options for --parseopt
~~~~~~~~~~~~~~~~~~~~~~
@@ -130,7 +141,7 @@ for another option.
'git diff-{asterisk}'). In contrast to the `--sq-quote` option,
the command input is still interpreted as usual.
---short[=length]::
+--short[=<length>]::
Same as `--verify` but shortens the object name to a unique
prefix with at least `length` characters. The minimum length
is 4, the default is the effective value of the `core.abbrev`
@@ -156,18 +167,30 @@ for another option.
are not refs (i.e. branch or tag names; or more
explicitly disambiguating "heads/master" form, when you
want to name the "master" branch when there is an
- unfortunately named tag "master"), and show them as full
+ unfortunately named tag "master"), and shows them as full
refnames (e.g. "refs/heads/master").
+--output-object-format=(sha1|sha256|storage)::
+
+ Allow oids to be input from any object format that the current
+ repository supports.
+
+ Specifying "sha1" translates if necessary and returns a sha1 oid.
+
+ Specifying "sha256" translates if necessary and returns a sha256 oid.
+
+ Specifying "storage" translates if necessary and returns an oid in
+ encoded in the storage hash algorithm.
+
Options for Objects
~~~~~~~~~~~~~~~~~~~
--all::
Show all refs found in `refs/`.
---branches[=pattern]::
---tags[=pattern]::
---remotes[=pattern]::
+--branches[=<pattern>]::
+--tags[=<pattern>]::
+--remotes[=<pattern>]::
Show all branches, tags, or remote-tracking branches,
respectively (i.e., refs found in `refs/heads`,
`refs/tags`, or `refs/remotes`, respectively).
@@ -176,7 +199,7 @@ If a `pattern` is given, only refs matching the given shell glob are
shown. If the pattern does not contain a globbing character (`?`,
`*`, or `[`), it is turned into a prefix match by appending `/*`.
---glob=pattern::
+--glob=<pattern>::
Show all refs matching the shell glob pattern `pattern`. If
the pattern does not start with `refs/`, this is automatically
prepended. If the pattern does not contain a globbing
@@ -197,7 +220,7 @@ 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=[fetch|receive|uploadpack]::
+--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`
@@ -307,21 +330,24 @@ The following options are unaffected by `--path-format`:
input, multiple algorithms may be printed, space-separated.
If not specified, the default is "storage".
+--show-ref-format::
+ Show the reference storage format used for the repository.
+
Other Options
~~~~~~~~~~~~~
---since=datestring::
---after=datestring::
+--since=<datestring>::
+--after=<datestring>::
Parse the date string, and output the corresponding
--max-age= parameter for 'git rev-list'.
---until=datestring::
---before=datestring::
+--until=<datestring>::
+--before=<datestring>::
Parse the date string, and output the corresponding
--min-age= parameter for 'git rev-list'.
-<args>...::
+<arg>...::
Flags and parameters to be parsed.
@@ -383,7 +409,7 @@ Each line of options has this format:
dash to separate words in a multi-word argument hint.
The remainder of the line, after stripping the spaces, is used
-as the help associated to the option.
+as the help associated with the option.
Blank lines are ignored, and lines that don't match this specification are used
as option group headers (start the line with a space to create such
@@ -398,7 +424,7 @@ some-command [<options>] <args>...
some-command does foo and bar!
--
-h,help show the help
+h,help! show the help
foo some nifty option --foo
bar= some cool option --bar with an argument
@@ -424,10 +450,10 @@ usage: some-command [<options>] <args>...
some-command does foo and bar!
-h, --help show the help
- --foo some nifty option --foo
- --bar ... some cool option --bar with an argument
- --baz <arg> another cool option --baz with a named argument
- --qux[=<path>] qux may take a path argument but has meaning by itself
+ --[no-]foo some nifty option --foo
+ --[no-]bar ... some cool option --bar with an argument
+ --[no-]baz <arg> another cool option --baz with a named argument
+ --[no-]qux[=<path>] qux may take a path argument but has meaning by itself
An option group Header
-C[...] option C with an optional argument
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index d2e10d3dce..568925db53 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -116,7 +116,7 @@ include::rerere-options.txt[]
--reference::
Instead of starting the body of the log message with "This
- reverts <full object name of the commit being reverted>.",
+ reverts <full-object-name-of-the-commit-being-reverted>.",
refer to the commit using "--pretty=reference" format
(cf. linkgit:git-log[1]). The `revert.reference`
configuration variable can be used to enable this option by
@@ -142,6 +142,16 @@ EXAMPLES
changes. The revert only modifies the working tree and the
index.
+DISCUSSION
+----------
+
+While git creates a basic commit message automatically, it is
+_strongly_ recommended to explain why the original commit is being
+reverted.
+In addition, repeatedly reverting reverts will result in increasingly
+unwieldy subject lines, for example 'Reapply "Reapply "<original-subject>""'.
+Please consider rewording these to be shorter and more unique.
+
CONFIGURATION
-------------
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 81bc23f3cd..363a26934f 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -163,7 +163,7 @@ will be staged (unless --cached or -n are used).
A submodule is considered up to date when the HEAD is the same as
recorded in the index, no tracked files are modified and no untracked
-files that aren't ignored are present in the submodules work tree.
+files that aren't ignored are present in the submodule's work tree.
Ignored files are deemed expendable and won't stop a submodule's work
tree from being removed.
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 492a82323d..bc3ef45acb 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -9,9 +9,10 @@ git-send-email - Send a collection of patches as emails
SYNOPSIS
--------
[verse]
-'git send-email' [<options>] <file|directory>...
-'git send-email' [<options>] <format-patch options>
+'git send-email' [<options>] (<file>|<directory>)...
+'git send-email' [<options>] <format-patch-options>
'git send-email' --dump-aliases
+'git send-email' --translate-aliases
DESCRIPTION
@@ -68,11 +69,12 @@ This option may be specified multiple times.
Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1])
to edit an introductory message for the patch series.
+
-When `--compose` is used, git send-email will use the From, Subject, and
-In-Reply-To headers specified in the message. If the body of the message
-(what you type after the headers and a blank line) only contains blank
-(or Git: prefixed) lines, the summary won't be sent, but From, Subject,
-and In-Reply-To headers will be used unless they are removed.
+When `--compose` is used, git send-email will use the From, To, Cc, Bcc,
+Subject, Reply-To, and In-Reply-To headers specified in the message. If
+the body of the message (what you type after the headers and a blank
+line) only contains blank (or Git: prefixed) lines, the summary won't be
+sent, but the headers mentioned above will be used unless they are
+removed.
+
Missing From or In-Reply-To headers will be prompted for.
+
@@ -137,7 +139,7 @@ Note that no attempts whatsoever are made to validate the encoding.
--compose-encoding=<encoding>::
Specify encoding of compose message. Default is the value of the
- 'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
+ 'sendemail.composeEncoding'; if that is unspecified, UTF-8 is assumed.
--transfer-encoding=(7bit|8bit|quoted-printable|base64|auto)::
Specify the transfer encoding to be used to send the message over SMTP.
@@ -173,7 +175,7 @@ Sending
Specify a command to run to send the email. The command should
be sendmail-like; specifically, it must support the `-i` option.
The command will be executed in the shell if necessary. Default
- is the value of `sendemail.sendmailcmd`. If unspecified, and if
+ is the value of `sendemail.sendmailCmd`. If unspecified, and if
--smtp-server is also unspecified, git-send-email will search
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.
@@ -268,7 +270,7 @@ must be used for each option.
certificates concatenated together: see verify(1) -CAfile and
-CApath for more information on these). Set it to an empty string
to disable certificate verification. Defaults to the value of the
- `sendemail.smtpsslcertpath` configuration variable, if set, or the
+ `sendemail.smtpSSLCertPath` configuration variable, if set, or the
backing SSL library's compiled-in default otherwise (which should
be the best choice on most platforms).
@@ -277,7 +279,7 @@ must be used for each option.
if a username is not specified (with `--smtp-user` or `sendemail.smtpUser`),
then authentication is not attempted.
---smtp-debug=0|1::
+--smtp-debug=(0|1)::
Enable (1) or disable (0) debug output. If enabled, SMTP
commands and replies will be printed. Useful to debug TLS
connection and authentication problems.
@@ -300,7 +302,9 @@ must be used for each option.
Automating
~~~~~~~~~~
---no-[to|cc|bcc]::
+--no-to::
+--no-cc::
+--no-bcc::
Clears any list of "To:", "Cc:", "Bcc:" addresses previously
set via config.
@@ -312,7 +316,7 @@ Automating
Specify a command to execute once per patch file which
should generate patch file specific "To:" entries.
Output of this command must be single email address per line.
- Default is the value of 'sendemail.tocmd' configuration value.
+ Default is the value of 'sendemail.toCmd' configuration value.
--cc-cmd=<command>::
Specify a command to execute once per patch file which
@@ -347,19 +351,19 @@ Automating
--[no-]signed-off-by-cc::
If this is set, add emails found in the `Signed-off-by` trailer or Cc: lines to the
- cc list. Default is the value of `sendemail.signedoffbycc` configuration
+ cc list. Default is the value of `sendemail.signedOffByCc` configuration
value; if that is unspecified, default to --signed-off-by-cc.
--[no-]cc-cover::
If this is set, emails found in Cc: headers in the first patch of
the series (typically the cover letter) are added to the cc list
- for each email set. Default is the value of 'sendemail.cccover'
+ for each email set. Default is the value of 'sendemail.ccCover'
configuration value; if that is unspecified, default to --no-cc-cover.
--[no-]to-cover::
If this is set, emails found in To: headers in the first patch of
the series (typically the cover letter) are added to the to list
- for each email set. Default is the value of 'sendemail.tocover'
+ for each email set. Default is the value of 'sendemail.toCover'
configuration value; if that is unspecified, default to --no-to-cover.
--suppress-cc=<category>::
@@ -383,7 +387,7 @@ Automating
- 'all' will suppress all auto cc values.
--
+
-Default is the value of `sendemail.suppresscc` configuration value; if
+Default is the value of `sendemail.suppressCc` configuration value; if
that is unspecified, default to 'self' if --suppress-from is
specified, as well as 'body' if --no-signed-off-cc is specified.
@@ -410,6 +414,12 @@ exists when 'git send-email' is asked to add it (especially note that
Failure to do so may not produce the expected result in the
recipient's MUA.
+--[no-]mailmap::
+ Use the mailmap file (see linkgit:gitmailmap[5]) to map all
+ addresses to their canonical real name and email address. Additional
+ mailmap data specific to git-send-email may be provided using the
+ `sendemail.mailmap.file` or `sendemail.mailmap.blob` configuration
+ values. Defaults to `sendemail.mailmap`.
Administering
~~~~~~~~~~~~~
@@ -453,7 +463,7 @@ have been specified, in which case default to 'compose'.
998 characters unless a suitable transfer encoding
('auto', 'base64', or 'quoted-printable') is used;
this is due to SMTP limits as described by
- http://www.ietf.org/rfc/rfc5322.txt.
+ https://www.ietf.org/rfc/rfc5322.txt.
--
+
Default is the value of `sendemail.validate`; if this is not set,
@@ -468,10 +478,16 @@ Information
--dump-aliases::
Instead of the normal operation, dump the shorthand alias names from
- the configured alias file(s), one per line in alphabetical order. Note,
- this only includes the alias name and not its expanded email addresses.
- See 'sendemail.aliasesfile' for more information about aliases.
-
+ the configured alias file(s), one per line in alphabetical order. Note
+ that this only includes the alias name and not its expanded email addresses.
+ See 'sendemail.aliasesFile' for more information about aliases.
+
+--translate-aliases::
+ Instead of the normal operation, read from standard input and
+ interpret each line as an email alias. Translate it according to the
+ configured alias file(s). Output each translated name and email
+ address to standard output, one per line. See 'sendemail.aliasFile'
+ for more information about aliases.
CONFIGURATION
-------------
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 595b002152..b9e73f2e77 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -55,7 +55,7 @@ be in a separate packet, and the list must end with a flush packet.
--force::
Usually, the command refuses to update a remote ref that
is not an ancestor of the local ref used to overwrite it.
- This flag disables the check. What this means is that
+ This flag disables the check. This means that
the remote repository can lose commits; use it with
care.
@@ -106,7 +106,7 @@ SPECIFYING THE REFS
There are three ways to specify which refs to update on the
remote end.
-With `--all` flag, all refs that exist locally are transferred to
+With the `--all` flag, all refs that exist locally are transferred to
the remote side. You cannot specify any '<ref>' if you use
this flag.
@@ -115,9 +115,9 @@ both on the local side and on the remote side are updated.
When one or more '<ref>' are specified explicitly (whether on the
command line or via `--stdin`), it can be either a
-single pattern, or a pair of such pattern separated by a colon
+single pattern, or a pair of such patterns separated by a colon
":" (this means that a ref name cannot have a colon in it). A
-single pattern '<name>' is just a shorthand for '<name>:<name>'.
+single pattern '<name>' is just shorthand for '<name>:<name>'.
Each pattern pair consists of the source side (before the colon)
and the destination side (after the colon). The ref to be
@@ -130,7 +130,7 @@ name. See linkgit:git-rev-parse[1].
- It is an error if <src> does not match exactly one of the
local refs.
- - It is an error if <dst> matches more than one remote refs.
+ - It is an error if <dst> matches more than one remote ref.
- If <dst> does not match any remote ref, either
@@ -143,9 +143,9 @@ name. See linkgit:git-rev-parse[1].
Without `--force`, the <src> ref is stored at the remote only if
<dst> does not exist, or <dst> is a proper subset (i.e. an
-ancestor) of <src>. This check, known as "fast-forward check",
-is performed in order to avoid accidentally overwriting the
-remote ref and lose other peoples' commits from there.
+ancestor) of <src>. This check, known as the "fast-forward check",
+is performed to avoid accidentally overwriting the
+remote ref and losing other people's commits from there.
With `--force`, the fast-forward check is disabled for all refs.
diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.txt
index 8632612c31..bdaf6e5fc4 100644
--- a/Documentation/git-sh-setup.txt
+++ b/Documentation/git-sh-setup.txt
@@ -22,7 +22,7 @@ The 'git sh-setup' scriptlet is designed to be sourced (using
the normal Git directories and a few helper shell functions.
Before sourcing it, your script should set up a few variables;
-`USAGE` (and `LONG_USAGE`, if any) is used to define message
+`USAGE` (and `LONG_USAGE`, if any) is used to define the message
given by `usage()` shell function. `SUBDIRECTORY_OK` can be set
if the script can run from a subdirectory of the working tree
(some commands do not).
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 58cf6210cd..bc31d8b6d3 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -22,7 +22,7 @@ Shows the commit ancestry graph starting from the commits named
with <rev>s or <glob>s (or all refs under refs/heads
and/or refs/tags) semi-visually.
-It cannot show more than 29 branches and commits at a time.
+It cannot show more than 26 branches and commits at a time.
It uses `showbranch.default` multi-valued configuration items if
no <rev> or <glob> is given on the command line.
@@ -50,7 +50,7 @@ OPTIONS
--current::
With this option, the command includes the current
- branch to the list of revs to be shown when it is not
+ branch in the list of revs to be shown when it is not
given on the command line.
--topo-order::
@@ -125,7 +125,7 @@ OPTIONS
default to color output.
Same as `--color=never`.
-Note that --more, --list, --independent and --merge-base options
+Note that --more, --list, --independent, and --merge-base options
are mutually exclusive.
@@ -137,14 +137,14 @@ 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
+Following these N lines, a one-line log for each commit is
displayed, indented N places. If a commit is on the I-th
branch, the I-th indentation character shows a `+` sign;
otherwise it shows a space. Merge commits are denoted by
a `-` sign. Each commit shows a short name that
can be used as an extended SHA-1 to name that commit.
-The following example shows three branches, "master", "fixes"
+The following example shows three branches, "master", "fixes",
and "mhf":
------------------------------------------------
@@ -154,7 +154,7 @@ $ git show-branch master fixes mhf
! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
---
+ [mhf] Allow "+remote:local" refspec to cause --force when fetching.
- + [mhf~1] Use git-octopus when pulling more than one heads.
+ + [mhf~1] Use git-octopus when pulling more than one head.
+ [fixes] Introduce "reset type" flag to "git reset"
+ [mhf~2] "git fetch --force".
+ [mhf~3] Use .git/remote/origin, not .git/branches/origin.
@@ -197,7 +197,7 @@ $ git show-branch --reflog="10,1 hour ago" --list master
shows 10 reflog entries going back from the tip as of 1 hour ago.
Without `--list`, the output also shows how these tips are
-topologically related with each other.
+topologically related to each other.
CONFIGURATION
-------------
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index 2fe274b8fa..616d919655 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -8,10 +8,14 @@ git-show-ref - List references in a local repository
SYNOPSIS
--------
[verse]
-'git show-ref' [-q | --quiet] [--verify] [--head] [-d | --dereference]
- [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]
- [--heads] [--] [<pattern>...]
+'git show-ref' [--head] [-d | --dereference]
+ [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]
+ [--] [<pattern>...]
+'git show-ref' --verify [-q | --quiet] [-d | --dereference]
+ [-s | --hash[=<n>]] [--abbrev[=<n>]]
+ [--] [<ref>...]
'git show-ref' --exclude-existing[=<pattern>]
+'git show-ref' --exists <ref>
DESCRIPTION
-----------
@@ -27,6 +31,10 @@ 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.
+The `--exists` form can be used to check for the existence of a single
+references. This form does not verify whether the reference resolves to an
+actual object.
+
Use of this utility is encouraged in favor of directly accessing files under
the `.git` directory.
@@ -37,12 +45,14 @@ OPTIONS
Show the HEAD reference, even if it would normally be filtered out.
---heads::
+--branches::
--tags::
- Limit to "refs/heads" and "refs/tags", respectively. These options
+ Limit to local branches and local tags, respectively. These options
are not mutually exclusive; when given both, references stored in
- "refs/heads" and "refs/tags" are displayed.
+ "refs/heads" and "refs/tags" are displayed. Note that `--heads`
+ is a deprecated synonym for `--branches` and may be removed
+ in the future.
-d::
--dereference::
@@ -62,6 +72,12 @@ OPTIONS
Aside from returning an error code of 1, it will also print an error
message if `--quiet` was not specified.
+--exists::
+
+ Check whether the given reference exists. Returns an exit code of 0 if
+ it does, 2 if it is missing, and 1 in case looking up the reference
+ failed with an error other than the reference being missing.
+
--abbrev[=<n>]::
Abbreviate the object name. When using `--hash`, you do
@@ -70,8 +86,8 @@ OPTIONS
-q::
--quiet::
- Do not print any results to stdout. When combined with `--verify`, this
- can be used to silently check if a reference exists.
+ Do not print any results to stdout. Can be used with `--verify` to
+ silently check if a reference exists.
--exclude-existing[=<pattern>]::
@@ -125,7 +141,7 @@ When using `--hash` (and not `--dereference`), the output is in the format:
For example,
-----------------------------------------------------------------------------
-$ git show-ref --heads --hash
+$ git show-ref --branches --hash
2e3ba0114a1f52b47df29743d6915d056be13278
185008ae97960c8d551adcd9e23565194651b5d1
03adf42c988195b50e1a1935ba5fcbc39b2b029b
@@ -144,7 +160,7 @@ use:
-----------------------------------------------------------------------------
This will show "refs/heads/master" but also "refs/remote/other-repo/master",
-if such references exists.
+if such references exist.
When using the `--verify` flag, the command requires an exact path:
@@ -169,8 +185,8 @@ 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`
-respectively (using both means that it shows tags and heads, but not other
+To show only tags, or only proper branch heads, use `--tags` and/or `--branches`
+respectively (using both means that it shows tags and branches, but not other
random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the `-d` or `--dereference`
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 03c0634518..5eb67439af 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -61,7 +61,7 @@ EXAMPLES
--------
`git show v1.0.0`::
- Shows the tag `v1.0.0`, along with the object the tags
+ Shows the tag `v1.0.0`, along with the object the tag
points at.
`git show v1.0.0^{tree}`::
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index a051b1e8f3..9a376886a5 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -79,6 +79,8 @@ Consider enabling untracked cache and split index if supported (see
`git update-index --untracked-cache` and `git update-index
--split-index`), Otherwise you can use `no` to have `git status`
return more quickly without showing untracked files.
+All usual spellings for Boolean value `true` are taken as `normal`
+and `false` as `no`.
The default can be changed using the status.showUntrackedFiles
configuration variable documented in linkgit:git-config[1].
@@ -245,11 +247,12 @@ U U unmerged, both modified
....
Submodules have more state and instead report
- M the submodule has a different HEAD than
- recorded in the index
- m the submodule has modified content
- ? the submodule has untracked files
-since modified content or untracked files in a submodule cannot be added
+
+* 'M' = the submodule has a different HEAD than recorded in the index
+* 'm' = the submodule has modified content
+* '?' = the submodule has untracked files
+
+This is since modified content or untracked files in a submodule cannot be added
via `git add` in the superproject to prepare a commit.
'm' and '?' are applied recursively. For example if a nested submodule
@@ -308,7 +311,7 @@ Line Notes
------------------------------------------------------------
# branch.oid <commit> | (initial) Current commit.
# branch.head <branch> | (detached) Current branch.
-# branch.upstream <upstream_branch> If upstream is set.
+# branch.upstream <upstream-branch> If upstream is set.
# branch.ab +<ahead> -<behind> If upstream is set and
the commit is present.
------------------------------------------------------------
@@ -471,7 +474,7 @@ again, because your configuration may already be caching `git status`
results, so it could be faster on subsequent runs.
* The `--untracked-files=no` flag or the
- `status.showUntrackedfiles=false` config (see above for both):
+ `status.showUntrackedFiles=no` config (see above for both):
indicate that `git status` should not report untracked
files. This is the fastest option. `git status` will not list
the untracked files, so you need to be careful to remember if
@@ -501,7 +504,7 @@ results, so it could be faster on subsequent runs.
usually worth the additional size.
* `core.untrackedCache=true` and `core.fsmonitor=true` or
- `core.fsmonitor=<hook_command_pathname>` (see
+ `core.fsmonitor=<hook-command-pathname>` (see
linkgit:git-update-index[1]): enable both the untracked cache
and FSMonitor features and only search directories that have
been modified since the previous `git status` command. This
diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt
index 2438f76da0..a293327581 100644
--- a/Documentation/git-stripspace.txt
+++ b/Documentation/git-stripspace.txt
@@ -29,7 +29,7 @@ With no arguments, this will:
In the case where the input consists entirely of whitespace characters, no
output will be produced.
-*NOTE*: This is intended for cleaning metadata, prefer the `--whitespace=fix`
+*NOTE*: This is intended for cleaning metadata. Prefer the `--whitespace=fix`
mode of linkgit:git-apply[1] for correcting whitespace of patches or files in
the repository.
@@ -37,11 +37,11 @@ OPTIONS
-------
-s::
--strip-comments::
- Skip and remove all lines starting with comment character (default '#').
+ Skip and remove all lines starting with a comment character (default '#').
-c::
--comment-lines::
- Prepend comment character and blank to each line. Lines will automatically
+ Prepend the comment character and a blank space to each line. Lines will automatically
be terminated with a newline. On empty lines, only the comment character
will be prepended.
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 695730609a..87d8e0f0c5 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -34,7 +34,7 @@ COMMANDS
With no arguments, shows the status of existing submodules. Several
subcommands are available to perform operations on the submodules.
-add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]::
+add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--] <repository> [<path>]::
Add the given repository as a submodule at the given path
to the changeset to be committed next to the current
project: the current project is termed the "superproject".
@@ -71,6 +71,9 @@ submodule repositories will be kept together in the same relative
location, and only the superproject's URL needs to be provided.
git-submodule will correctly locate the submodule using the relative
URL in `.gitmodules`.
++
+If `--ref-format <format>` is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
status [--cached] [--recursive] [--] [<path>...]::
Show the status of the submodules. This will print the SHA-1 of the
@@ -136,7 +139,7 @@ If you really want to remove a submodule from the repository and commit
that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal
options.
-update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter spec>] [--] [<path>...]::
+update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
+
--
Update the registered submodules to match what the superproject
@@ -185,7 +188,10 @@ submodule with the `--init` option.
If `--recursive` is specified, this command will recurse into the
registered submodules, and update any nested submodules within.
-If `--filter <filter spec>` is specified, the given partial clone filter will be
+If `--ref-format <format>` is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
+
+If `--filter <filter-spec>` is specified, the given partial clone filter will be
applied to the submodule. See linkgit:git-rev-list[1] for details on filter
specifications.
--
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 4e92308e85..bcf7d84a87 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -37,12 +37,12 @@ COMMANDS
argument. Normally this command initializes the current
directory.
--T<trunk_subdir>;;
---trunk=<trunk_subdir>;;
--t<tags_subdir>;;
---tags=<tags_subdir>;;
--b<branches_subdir>;;
---branches=<branches_subdir>;;
+-T<trunk-subdir>;;
+--trunk=<trunk-subdir>;;
+-t<tags-subdir>;;
+--tags=<tags-subdir>;;
+-b<branches-subdir>;;
+--branches=<branches-subdir>;;
-s;;
--stdlayout;;
These are optional command-line options for init. Each of
@@ -431,14 +431,14 @@ Any other arguments are passed directly to 'git log'
independently of 'git svn' functions.
'create-ignore'::
- Recursively finds the svn:ignore property on directories and
- creates matching .gitignore files. The resulting files are staged to
- be committed, but are not committed. Use -r/--revision to refer to a
- specific revision.
+ Recursively finds the svn:ignore and svn:global-ignores properties
+ on directories and creates matching .gitignore files. The resulting
+ files are staged to be committed, but are not committed. Use
+ -r/--revision to refer to a specific revision.
'show-ignore'::
- Recursively finds and lists the svn:ignore property on
- directories. The output is suitable for appending to
+ Recursively finds and lists the svn:ignore and svn:global-ignores
+ properties on directories. The output is suitable for appending to
the $GIT_DIR/info/exclude file.
'mkdirs'::
@@ -726,9 +726,9 @@ ADVANCED OPTIONS
when tracking a single URL. The 'log' and 'dcommit' commands
no longer require this switch as an argument.
--R<remote name>::
---svn-remote <remote name>::
- Specify the [svn-remote "<remote name>"] section to use,
+-R<remote-name>::
+--svn-remote <remote-name>::
+ Specify the [svn-remote "<remote-name>"] section to use,
this allows SVN multiple repositories to be tracked.
Default: "svn"
@@ -871,7 +871,7 @@ Tracking and contributing to the trunk of a Subversion-managed project
# Now commit your changes (that were committed previously using Git) to SVN,
# as well as automatically updating your working HEAD:
git svn dcommit
-# Append svn:ignore settings to the default Git exclude file:
+# Append svn:ignore and svn:global-ignores settings to the default Git exclude file:
git svn show-ignore >> .git/info/exclude
------------------------------------------------------------------------
diff --git a/Documentation/git-switch.txt b/Documentation/git-switch.txt
index c60fc9c138..f38e4c8afa 100644
--- a/Documentation/git-switch.txt
+++ b/Documentation/git-switch.txt
@@ -59,13 +59,18 @@ out at most one of `A` and `B`, in which case it defaults to `HEAD`.
-c <new-branch>::
--create <new-branch>::
Create a new branch named `<new-branch>` starting at
- `<start-point>` before switching to the branch. This is a
- convenient shortcut for:
+ `<start-point>` before switching to the branch. This is the
+ transactional equivalent of
+
------------
$ git branch <new-branch>
$ git switch <new-branch>
------------
++
+that is to say, the branch is not reset/created unless "git switch" is
+successful (e.g., when the branch is in use in another worktree, not
+just the current branch stays the same, but the branch is not reset to
+the start-point, either).
-C <new-branch>::
--force-create <new-branch>::
@@ -171,7 +176,7 @@ name, the guessing is aborted. You can explicitly give a name with
`branch.autoSetupMerge` configuration variable is true.
--orphan <new-branch>::
- Create a new 'orphan' branch, named `<new-branch>`. All
+ Create a new unborn branch, named `<new-branch>`. All
tracked files are removed.
--ignore-other-worktrees::
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index 102c83eb19..33ca381fde 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -27,7 +27,7 @@ symbolic ref.
A symbolic ref is a regular file that stores a string that
begins with `ref: refs/`. For example, your `.git/HEAD` is
-a regular file whose contents is `ref: refs/heads/master`.
+a regular file whose content is `ref: refs/heads/master`.
OPTIONS
-------
@@ -73,6 +73,10 @@ default.
symbolic ref were printed correctly, with status 1 if the requested
name is not a symbolic ref, or 128 if another error occurs.
+SEE ALSO
+--------
+linkgit:git-update-ref[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index d42efb3112..4494729f5e 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]
+ [(--trailer <token>[(=|:)<value>])...]
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
@@ -31,8 +32,8 @@ creates a 'tag' object, and requires a tag message. Unless
`-m <msg>` or `-F <file>` is given, an editor is started for the user to type
in the tag message.
-If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <key-id>`
-are absent, `-a` is implied.
+If `-m <msg>` or `-F <file>` or `--trailer <token>[=<value>]` is given
+and `-a`, `-s`, and `-u <key-id>` are absent, `-a` is implied.
Otherwise, a tag reference that points directly at the given object
(i.e., a lightweight tag) is created.
@@ -178,6 +179,17 @@ This option is only applicable when listing tags without annotation lines.
Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
is given.
+--trailer <token>[(=|:)<value>]::
+ Specify a (<token>, <value>) pair that should be applied as a
+ trailer. (e.g. `git tag --trailer "Custom-Key: value"`
+ will add a "Custom-Key" trailer to the tag message.)
+ The `trailer.*` configuration variables
+ (linkgit:git-interpret-trailers[1]) can be used to define if
+ a duplicated trailer is omitted, where in the run of trailers
+ each trailer would appear, and other details.
+ The trailers can be extracted in `git tag --list`, using
+ `--format="%(trailers)"` placeholder.
+
-e::
--edit::
The message taken from file with `-F` and command line with
@@ -224,7 +236,7 @@ it in the repository configuration as follows:
-------------------------------------
[user]
- signingKey = <gpg-key_id>
+ signingKey = <gpg-key-id>
-------------------------------------
`pager.tag` is only respected when listing tags, i.e., when `-l` is
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index f4bb9c5daf..7128aed540 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -25,6 +25,7 @@ SYNOPSIS
[--really-refresh] [--unresolve] [--again | -g]
[--info-only] [--index-info]
[-z] [--stdin] [--index-version <n>]
+ [--show-index-version]
[--verbose]
[--] [<file>...]
@@ -49,7 +50,7 @@ OPTIONS
--remove::
If a specified file is in the index but is missing then it's
removed.
- Default behavior is to ignore removed file.
+ Default behavior is to ignore removed files.
--refresh::
Looks at the current index and checks to see if merges or
@@ -95,7 +96,7 @@ OPTIONS
the index. If you want to change the working tree file,
you need to unset the bit to tell Git. This is
sometimes helpful when working with a big project on a
- filesystem that has very slow lstat(2) system call
+ filesystem that has a very slow lstat(2) system call
(e.g. cifs).
+
Git will fail (gracefully) in case it needs to modify this file
@@ -108,7 +109,7 @@ you will need to handle the situation manually.
without regard to the "assume unchanged" setting.
--[no-]skip-worktree::
- When one of these flags is specified, the object name recorded
+ When one of these flags is specified, the object names recorded
for the paths are not updated. Instead, these options
set and unset the "skip-worktree" bit for the paths. See
section "Skip-worktree bit" below for more information.
@@ -119,7 +120,7 @@ you will need to handle the situation manually.
the `--remove` option was specified.
--[no-]fsmonitor-valid::
- When one of these flags is specified, the object name recorded
+ When one of these flags is specified, the object names recorded
for the paths are not updated. Instead, these options
set and unset the "fsmonitor valid" bit for the paths. See
section "File System Monitor" below for more information.
@@ -127,7 +128,7 @@ you will need to handle the situation manually.
-g::
--again::
Runs 'git update-index' itself on the paths whose index
- entries are different from those from the `HEAD` commit.
+ entries are different from those of the `HEAD` commit.
--unresolve::
Restores the 'unmerged' or 'needs updating' state of a
@@ -151,24 +152,30 @@ you will need to handle the situation manually.
automatically removed with warning messages.
--stdin::
- Instead of taking list of paths from the command line,
- read list of paths from the standard input. Paths are
+ Instead of taking a list of paths from the command line,
+ read a list of paths from the standard input. Paths are
separated by LF (i.e. one path per line) by default.
--verbose::
- Report what is being added and removed from index.
+ Report what is being added and removed from the index.
--index-version <n>::
Write the resulting index out in the named on-disk format version.
- Supported versions are 2, 3 and 4. The current default version is 2
+ Supported versions are 2, 3, and 4. The current default version is 2
or 3, depending on whether extra features are used, such as
- `git add -N`.
+ `git add -N`. With `--verbose`, also report the version the index
+ file uses before and after this command.
+
Version 4 performs a simple pathname compression that reduces index
size by 30%-50% on large repositories, which results in faster load
-time. Version 4 is relatively young (first released in 1.8.0 in
-October 2012). Other Git implementations such as JGit and libgit2
-may not support it yet.
+time. Git supports it since version 1.8.0, released in October 2012,
+and support for it was added to libgit2 in 2016 and to JGit in 2020.
+Older versions of this manual page called it "relatively young", but
+it should be considered mature technology these days.
+
+--show-index-version::
+ Report the index format version used by the on-disk index file.
+ See `--index-version` above.
-z::
Only meaningful with `--stdin` or `--index-info`; paths are
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 48b6683071..8a4281cde9 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -8,63 +8,46 @@ git-update-ref - Update the object name stored in a ref safely
SYNOPSIS
--------
[verse]
-'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<oldvalue>] | [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
+'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<old-oid>] | [--create-reflog] <ref> <new-oid> [<old-oid>] | --stdin [-z])
DESCRIPTION
-----------
-Given two arguments, stores the <newvalue> in the <ref>, possibly
+Given two arguments, stores the <new-oid> in the <ref>, possibly
dereferencing the symbolic refs. E.g. `git update-ref HEAD
-<newvalue>` updates the current branch head to the new object.
+<new-oid>` updates the current branch head to the new object.
-Given three arguments, stores the <newvalue> in the <ref>,
+Given three arguments, stores the <new-oid> in the <ref>,
possibly dereferencing the symbolic refs, after verifying that
-the current value of the <ref> matches <oldvalue>.
-E.g. `git update-ref refs/heads/master <newvalue> <oldvalue>`
-updates the master branch head to <newvalue> only if its current
-value is <oldvalue>. You can specify 40 "0" or an empty string
-as <oldvalue> to make sure that the ref you are creating does
+the current value of the <ref> matches <old-oid>.
+E.g. `git update-ref refs/heads/master <new-oid> <old-oid>`
+updates the master branch head to <new-oid> only if its current
+value is <old-oid>. You can specify 40 "0" or an empty string
+as <old-oid> to make sure that the ref you are creating does
not exist.
-It also allows a "ref" file to be a symbolic pointer to another
-ref file by starting with the four-byte header sequence of
-"ref:".
-
-More importantly, it allows the update of a ref file to follow
-these symbolic pointers, whether they are symlinks or these
-"regular file symbolic refs". It follows *real* symlinks only
-if they start with "refs/": otherwise it will just try to read
-them and update them as a regular file (i.e. it will allow the
-filesystem to follow them, but will overwrite such a symlink to
-somewhere else with a regular filename).
+The final arguments are object names; this command without any options
+does not support updating a symbolic ref to point to another ref (see
+linkgit:git-symbolic-ref[1]). But `git update-ref --stdin` does have
+the `symref-*` commands so that regular refs and symbolic refs can be
+committed in the same transaction.
If --no-deref is given, <ref> itself is overwritten, rather than
the result of following the symbolic pointers.
-In general, using
-
- git update-ref HEAD "$head"
-
-should be a _lot_ safer than doing
-
- echo "$head" > "$GIT_DIR/HEAD"
-
-both from a symlink following standpoint *and* an error checking
-standpoint. The "refs/" rule for symlinks means that symlinks
-that point to "outside" the tree are safe: they'll be followed
-for reading but not for writing (so we'll never write through a
-ref symlink to some other tree, if you have copied a whole
-archive by creating a symlink tree).
-
-With `-d` flag, it deletes the named <ref> after verifying it
-still contains <oldvalue>.
+With `-d`, it deletes the named <ref> after verifying that it
+still contains <old-oid>.
With `--stdin`, update-ref reads instructions from standard input and
performs all modifications together. Specify commands of the form:
- update SP <ref> SP <newvalue> [SP <oldvalue>] LF
- create SP <ref> SP <newvalue> LF
- delete SP <ref> [SP <oldvalue>] LF
- verify SP <ref> [SP <oldvalue>] LF
+ update SP <ref> SP <new-oid> [SP <old-oid>] LF
+ create SP <ref> SP <new-oid> LF
+ delete SP <ref> [SP <old-oid>] LF
+ verify SP <ref> [SP <old-oid>] LF
+ symref-update SP <ref> SP <new-target> [SP (ref SP <old-target> | oid SP <old-oid>)] LF
+ symref-create SP <ref> SP <new-target> LF
+ symref-delete SP <ref> [SP <old-target>] LF
+ symref-verify SP <ref> [SP <old-target>] LF
option SP <opt> LF
start LF
prepare LF
@@ -82,10 +65,14 @@ specify a missing value, omit the value and its preceding SP entirely.
Alternatively, use `-z` to specify in NUL-terminated format, without
quoting:
- update SP <ref> NUL <newvalue> NUL [<oldvalue>] NUL
- create SP <ref> NUL <newvalue> NUL
- delete SP <ref> NUL [<oldvalue>] NUL
- verify SP <ref> NUL [<oldvalue>] NUL
+ update SP <ref> NUL <new-oid> NUL [<old-oid>] NUL
+ create SP <ref> NUL <new-oid> NUL
+ delete SP <ref> NUL [<old-oid>] NUL
+ verify SP <ref> NUL [<old-oid>] NUL
+ symref-update SP <ref> NUL <new-target> [NUL (ref NUL <old-target> | oid NUL <old-oid>)] NUL
+ symref-create SP <ref> NUL <new-target> NUL
+ symref-delete SP <ref> [NUL <old-target>] NUL
+ symref-verify SP <ref> [NUL <old-target>] NUL
option SP <opt> NUL
start NUL
prepare NUL
@@ -100,25 +87,42 @@ recognizes as an object name. Commands in any other format or a
repeated <ref> produce an error. Command meanings are:
update::
- Set <ref> to <newvalue> after verifying <oldvalue>, if given.
- Specify a zero <newvalue> to ensure the ref does not exist
- after the update and/or a zero <oldvalue> to make sure the
+ Set <ref> to <new-oid> after verifying <old-oid>, if given.
+ Specify a zero <new-oid> to ensure the ref does not exist
+ after the update and/or a zero <old-oid> to make sure the
ref does not exist before the update.
create::
- Create <ref> with <newvalue> after verifying it does not
- exist. The given <newvalue> may not be zero.
+ Create <ref> with <new-oid> after verifying it does not
+ exist. The given <new-oid> may not be zero.
delete::
- Delete <ref> after verifying it exists with <oldvalue>, if
- given. If given, <oldvalue> may not be zero.
+ Delete <ref> after verifying it exists with <old-oid>, if
+ given. If given, <old-oid> may not be zero.
+
+symref-update::
+ Set <ref> to <new-target> after verifying <old-target> or <old-oid>,
+ if given. Specify a zero <old-oid> to ensure that the ref does not
+ exist before the update.
verify::
- Verify <ref> against <oldvalue> but do not change it. If
- <oldvalue> is zero or missing, the ref must not exist.
+ Verify <ref> against <old-oid> but do not change it. If
+ <old-oid> is zero or missing, the ref must not exist.
+
+symref-create:
+ Create symbolic ref <ref> with <new-target> after verifying
+ it does not exist.
+
+symref-delete::
+ Delete <ref> after verifying it exists with <old-target>, if given.
+
+symref-verify::
+ Verify symbolic <ref> against <old-target> but do not change it.
+ If <old-target> is missing, the ref must not exist. Can only be
+ used in `no-deref` mode.
option::
- Modify behavior of the next command naming a <ref>.
+ Modify the behavior of the next command naming a <ref>.
The only valid option is `no-deref` to avoid dereferencing
a symbolic ref.
@@ -141,7 +145,7 @@ abort::
Abort the transaction, releasing all locks if the transaction is in
prepared state.
-If all <ref>s can be locked with matching <oldvalue>s
+If all <ref>s can be locked with matching <old-oid>s
simultaneously, all modifications are performed. Otherwise, no
modifications are performed. Note that while each individual
<ref> is updated or deleted atomically, a concurrent reader may
@@ -161,7 +165,7 @@ formatted as:
Where "oldsha1" is the 40 character hexadecimal value previously
stored in <ref>, "newsha1" is the 40 character hexadecimal value of
-<newvalue> and "committer" is the committer's name, email address
+<new-oid> and "committer" is the committer's name, email address
and date in the standard Git committer ident format.
Optionally with -m:
@@ -175,6 +179,21 @@ An update will fail (without changing <ref>) if the current user is
unable to create a new log file, append to the existing log file
or does not have committer information available.
+NOTES
+-----
+
+Symbolic refs were initially implemented using symbolic links. This is
+now deprecated since not all filesystems support symbolic links.
+
+This command follows *real* symlinks only if they start with "refs/":
+otherwise it will just try to read them and update them as a regular
+file (i.e. it will allow the filesystem to follow them, but will
+overwrite such a symlink to somewhere else with a regular filename).
+
+SEE ALSO
+--------
+linkgit:git-symbolic-ref[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt
index 17e429dbd0..6bc9b50d89 100644
--- a/Documentation/git-update-server-info.txt
+++ b/Documentation/git-update-server-info.txt
@@ -23,13 +23,13 @@ OPTIONS
-------
-f::
--force::
- update the info files from scratch.
+ Update the info files from scratch.
OUTPUT
------
Currently the command updates the following files. Please see
-linkgit:gitrepository-layout[5] for description of
+linkgit:gitrepository-layout[5] for a description of
what they are for:
* objects/info/packs
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index 1d30a4f6b4..516d1639d9 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -26,7 +26,7 @@ OPTIONS
-------
--[no-]strict::
- Do not try <directory>/.git/ if <directory> is no Git directory.
+ Do not try <directory>/.git/ if <directory> is not a Git directory.
--timeout=<n>::
Interrupt transfer after <n> seconds of inactivity.
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index c38fb3968b..0680568dfd 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -19,7 +19,7 @@ no value.
OPTIONS
-------
-l::
- Cause the logical variables to be listed. In addition, all the
+ Display the logical variables. In addition, all the
variables of the Git configuration file .git/config are listed
as well. (However, the configuration variables listing functionality
is deprecated in favor of `git config -l`.)
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index b8720dce8a..d7e886918a 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -15,7 +15,7 @@ SYNOPSIS
DESCRIPTION
-----------
Reads given idx file for packed Git archive created with the
-'git pack-objects' command and verifies idx file and the
+'git pack-objects' command and verifies the idx file and the
corresponding pack file.
OPTIONS
@@ -25,13 +25,13 @@ OPTIONS
-v::
--verbose::
- After verifying the pack, show list of objects contained
+ After verifying the pack, show the list of objects contained
in the pack and a histogram of delta chain length.
-s::
--stat-only::
Do not verify the pack contents; only show the histogram of delta
- chain length. With `--verbose`, list of objects is also shown.
+ chain length. With `--verbose`, the list of objects is also shown.
\--::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index 8b63ceb00e..8e55e0bb1e 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -3,7 +3,7 @@ git-whatchanged(1)
NAME
----
-git-whatchanged - Show logs with difference each commit introduces
+git-whatchanged - Show logs with differences each commit introduces
SYNOPSIS
@@ -18,11 +18,11 @@ Shows commit logs and diff output each commit introduces.
New users are encouraged to use linkgit:git-log[1] instead. The
`whatchanged` command is essentially the same as linkgit:git-log[1]
-but defaults to show the raw format diff output and to skip merges.
+but defaults to showing the raw format diff output and skipping merges.
-The command is kept primarily for historical reasons; fingers of
+The command is primarily kept for historical reasons; fingers of
many people who learned Git long before `git log` was invented by
-reading Linux kernel mailing list are trained to type it.
+reading the Linux kernel mailing list are trained to type it.
Examples
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 93d76f5d66..70437c815f 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -99,7 +99,7 @@ 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
+associated with a new unborn 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
@@ -157,7 +157,7 @@ will reestablish the connection. If multiple linked worktrees are moved,
running `repair` from any worktree with each tree's new `<path>` as an
argument, will reestablish the connection to all the specified paths.
+
-If both the main worktree and linked worktrees have been moved manually,
+If both the main worktree and linked worktrees have been moved or copied manually,
then running `repair` in the main worktree and specifying the new `<path>`
of each linked worktree will reestablish all connections in both
directions.
@@ -234,7 +234,7 @@ This can also be set up as the default behaviour by using the
--orphan::
With `add`, make the new worktree and index empty, associating
- the worktree with a new orphan/unborn branch named `<new-branch>`.
+ the worktree with a new unborn branch named `<new-branch>`.
--porcelain::
With `list`, output in an easy-to-parse format for scripts.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 14ed05116b..d15a869762 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -11,9 +11,10 @@ SYNOPSIS
[verse]
'git' [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
- [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
- [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
- [--config-env=<name>=<envvar>] <command> [<args>]
+ [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]
+ [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]
+ [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]
+ <command> [<args>]
DESCRIPTION
-----------
@@ -96,9 +97,9 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config
to avoid ambiguity with `<name>` containing one.
+
This is useful for cases where you want to pass transitory
-configuration options to git, but are doing so on OS's where
-other processes might be able to read your cmdline
-(e.g. `/proc/self/cmdline`), but not your environ
+configuration options to git, but are doing so on operating systems
+where other processes might be able to read your command line
+(e.g. `/proc/self/cmdline`), but not your environment
(e.g. `/proc/self/environ`). That behavior is the default on
Linux, but may not be on your system.
+
@@ -174,8 +175,24 @@ If you just want to run git as if it was started in `<path>` then use
directory.
--no-replace-objects::
- Do not use replacement refs to replace Git objects. See
- linkgit:git-replace[1] for more information.
+ Do not use replacement refs to replace Git objects.
+ This is equivalent to exporting the `GIT_NO_REPLACE_OBJECTS`
+ environment variable with any value.
+ See linkgit:git-replace[1] for more information.
+
+--no-lazy-fetch::
+ Do not fetch missing objects from the promisor remote on
+ demand. Useful together with `git cat-file -e <object>` to
+ see if the object is locally available.
+ This is equivalent to setting the `GIT_NO_LAZY_FETCH`
+ environment variable to `1`.
+
+--no-optional-locks::
+ Do not perform optional operations that require locks. This is
+ equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`.
+
+--no-advice::
+ Disable all advice hints from being printed.
--literal-pathspecs::
Treat pathspecs literally (i.e. no globbing, no pathspec magic).
@@ -198,11 +215,7 @@ If you just want to run git as if it was started in `<path>` then use
Add "icase" magic to all pathspec. This is equivalent to setting
the `GIT_ICASE_PATHSPECS` environment variable to `1`.
---no-optional-locks::
- Do not perform optional operations that require locks. This is
- equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`.
-
---list-cmds=group[,group...]::
+--list-cmds=<group>[,<group>...]::
List commands by group. This is an internal/experimental
option and may change or be removed in the future. Supported
groups are: builtins, parseopt (builtin commands that use
@@ -556,6 +569,11 @@ double-quotes and respecting backslash escapes. E.g., the value
is always used. The default is "sha1".
See `--object-format` in linkgit:git-init[1].
+`GIT_DEFAULT_REF_FORMAT`::
+ If this variable is set, the default reference backend format for new
+ repositories will be set to this value. The default is "files".
+ See `--ref-format` in linkgit:git-init[1].
+
Git Commits
~~~~~~~~~~~
`GIT_AUTHOR_NAME`::
@@ -626,6 +644,16 @@ parameter, <path>.
For each path `GIT_EXTERNAL_DIFF` is called, two environment variables,
`GIT_DIFF_PATH_COUNTER` and `GIT_DIFF_PATH_TOTAL` are set.
+`GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE`::
+ If this Boolean environment variable is set to true then the
+ `GIT_EXTERNAL_DIFF` command is expected to return exit code
+ 0 if it considers the input files to be equal or 1 if it
+ considers them to be different, like `diff(1)`.
+ If it is set to false, which is the default, then the command
+ is expected to return exit code 0 regardless of equality.
+ Any other exit code causes Git to report a fatal error.
+
+
`GIT_DIFF_PATH_COUNTER`::
A 1-based counter incremented by one for every path.
@@ -724,13 +752,12 @@ for further details.
waiting for someone with sufficient permissions to fix it.
`GIT_FLUSH`::
-// NEEDSWORK: make it into a usual Boolean environment variable
- If this environment variable is set to "1", then commands such
+ If this Boolean environment variable is set to true, then commands such
as 'git blame' (in incremental mode), 'git rev-list', 'git log',
'git check-attr' and 'git check-ignore' will
force a flush of the output stream after each record have been
flushed. If this
- variable is set to "0", the output of these commands will be done
+ variable is set to false, the output of these commands will be done
using completely buffered I/O. If this environment variable is
not set, Git will choose buffered or record-oriented flushing
based on whether stdout appears to be redirected to a file or not.
@@ -838,7 +865,7 @@ of the SID and an optional counter (to avoid filename
collisions).
+
In addition, if the variable is set to
-`af_unix:[<socket_type>:]<absolute-pathname>`, Git will try
+`af_unix:[<socket-type>:]<absolute-pathname>`, Git will try
to open the path as a Unix Domain Socket. The socket type
can be either `stream` or `dgram`.
+
@@ -868,6 +895,10 @@ for full details.
header and packfile URIs. Set this Boolean environment variable to false to prevent this
redaction.
+`GIT_NO_REPLACE_OBJECTS`::
+ Setting and exporting this environment variable tells Git to
+ ignore replacement refs and do not replace Git objects.
+
`GIT_LITERAL_PATHSPECS`::
Setting this Boolean environment variable to true will cause Git to treat all
pathspecs literally, rather than as glob patterns. For example,
@@ -889,6 +920,11 @@ for full details.
Setting this Boolean environment variable to true will cause Git to treat all
pathspecs as case-insensitive.
+`GIT_NO_LAZY_FETCH`::
+ Setting this Boolean environment variable to true tells Git
+ not to lazily fetch missing objects from the promisor remote
+ on demand.
+
`GIT_REFLOG_ACTION`::
When a ref is updated, reflog entries are created to keep
track of the reason why the ref was updated (which is
@@ -911,6 +947,16 @@ for full details.
should not normally need to set this to `0`, but it may be
useful when trying to salvage data from a corrupted repository.
+`GIT_COMMIT_GRAPH_PARANOIA`::
+ When loading a commit object from the commit-graph, Git performs an
+ existence check on the object in the object database. This is done to
+ avoid issues with stale commit-graphs that contain references to
+ already-deleted commits, but comes with a performance penalty.
++
+The default is "false", which disables the aforementioned behavior.
+Setting this to "true" enables the existence check so that stale commits
+will never be returned from the commit-graph at the cost of performance.
+
`GIT_ALLOW_PROTOCOL`::
If set to a colon-separated list of protocols, behave as if
`protocol.allow` is set to `never`, and each of the listed
@@ -928,7 +974,7 @@ for full details.
`GIT_PROTOCOL`::
For internal use only. 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
+ '<key>[=<value>]'. Presence of unknown keys and values must be
ignored.
+
Note that servers may need to be configured to allow this variable to
@@ -981,6 +1027,17 @@ standard output.
adequate and support for it is likely to be removed in the
foreseeable future (along with the variable).
+`GIT_ADVICE`::
+ If set to `0`, then disable all advice messages. These messages are
+ intended to provide hints to human users that may help them get out of
+ problematic situations or take advantage of new features. Users can
+ disable individual messages using the `advice.*` config keys. These
+ messages may be disruptive to tools that execute Git processes, so this
+ variable is available to disable the messages. (The `--no-advice`
+ global option is also available, but old Git versions may fail when
+ this option is not understood. The environment variable will be ignored
+ by Git versions that do not understand it.)
+
Discussion[[Discussion]]
------------------------
@@ -1015,10 +1072,11 @@ When first created, objects are stored in individual files, but for
efficiency may later be compressed together into "pack files".
Named pointers called refs mark interesting points in history. A ref
-may contain the SHA-1 name of an object or the name of another ref. Refs
-with names beginning `ref/head/` contain the SHA-1 name of the most
+may contain the SHA-1 name of an object or the name of another ref (the
+latter is called a "symbolic ref").
+Refs with names beginning `refs/head/` contain the SHA-1 name of the most
recent commit (or "head") of a branch under development. SHA-1 names of
-tags of interest are stored under `ref/tags/`. A special ref named
+tags of interest are stored under `refs/tags/`. A symbolic ref named
`HEAD` contains the name of the currently checked-out branch.
The index file is initialized with a list of all paths and, for each
@@ -1092,7 +1150,7 @@ Authors
-------
Git was started by Linus Torvalds, and is currently maintained by Junio
C Hamano. Numerous contributions have come from the Git mailing list
-<git@vger.kernel.org>. http://www.openhub.net/p/git/contributors/summary
+<git@vger.kernel.org>. https://openhub.net/p/git/contributors/summary
gives you a more complete list of contributors.
If you have a clone of git.git itself, the
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 6deb89a296..e6150595af 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -100,6 +100,21 @@ for a path to `Unspecified` state. This can be done by listing
the name of the attribute prefixed with an exclamation point `!`.
+RESERVED BUILTIN_* ATTRIBUTES
+-----------------------------
+
+builtin_* is a reserved namespace for builtin attribute values. Any
+user defined attributes under this namespace will be ignored and
+trigger a warning.
+
+`builtin_objectmode`
+~~~~~~~~~~~~~~~~~~~~
+This attribute is for filtering files by their file bit modes (40000,
+120000, 160000, 100755, 100644). e.g. ':(attr:builtin_objectmode=160000)'.
+You may also check these values with `git check-attr builtin_objectmode -- <file>`.
+If the object is not in the index `git check-attr --cached` will return unspecified.
+
+
EFFECTS
-------
@@ -359,7 +374,7 @@ explicitly define the line endings with `eol` if the `working-tree-encoding`
attribute is used to avoid ambiguity.
------------------------
-*.ps1 text working-tree-encoding=UTF-16LE eol=CRLF
+*.ps1 text working-tree-encoding=UTF-16LE eol=crlf
------------------------
You can get a list of all available encodings on your platform with the
@@ -761,6 +776,11 @@ with the above configuration, i.e. `j-c-diff`, with 7
parameters, just like `GIT_EXTERNAL_DIFF` program is called.
See linkgit:git[1] for details.
+If the program is able to ignore certain changes (similar to
+`git diff --ignore-space-change`), then also set the option
+`trustExitCode` to true. It is then expected to return exit code 1 if
+it finds significant changes and 0 if it doesn't.
+
Setting the internal diff algorithm
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1122,11 +1142,11 @@ The `merge.*.name` variable gives the driver a human-readable
name.
The `merge.*.driver` variable's value is used to construct a
-command to run to merge ancestor's version (`%O`), current
+command to run to common ancestor's version (`%O`), current
version (`%A`) and the other branches' version (`%B`). These
three tokens are replaced with the names of temporary files that
hold the contents of these versions when the command line is
-built. Additionally, %L will be replaced with the conflict marker
+built. Additionally, `%L` will be replaced with the conflict marker
size (see below).
The merge driver is expected to leave the result of the merge in
@@ -1144,15 +1164,16 @@ When left unspecified, the driver itself is used for both
internal merge and the final merge.
The merge driver can learn the pathname in which the merged result
-will be stored via placeholder `%P`.
-
+will be stored via placeholder `%P`. The conflict labels to be used
+for the common ancestor, local head and other head can be passed by
+using '%S', '%X' and '%Y` respectively.
`conflict-marker-size`
^^^^^^^^^^^^^^^^^^^^^^
This attribute controls the length of conflict markers left in
-the work tree file during a conflicted merge. Only setting to
-the value to a positive integer has any meaningful effect.
+the work tree file during a conflicted merge. Only a positive
+integer has a meaningful effect.
For example, this line in `.gitattributes` can be used to tell the merge
machinery to leave much longer (instead of the usual 7-character-long)
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 1819a5a185..7c709324ba 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -23,10 +23,10 @@ arguments. Here are the rules:
A subcommand may take dashed options (which may take their own
arguments, e.g. "--max-parents 2") and arguments. You SHOULD
give dashed options first and then arguments. Some commands may
- accept dashed options after you have already gave non-option
+ accept dashed options after you have already given non-option
arguments (which may make the command ambiguous), but you should
not rely on it (because eventually we may find a way to fix
- these ambiguity by enforcing the "options then args" rule).
+ these ambiguities by enforcing the "options then args" rule).
* Revisions come first and then paths.
E.g. in `git diff v1.0 v2.0 arch/x86 include/asm-x86`,
@@ -37,12 +37,12 @@ arguments. Here are the rules:
they can be disambiguated by placing `--` between them.
E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
tree. Please show changes between the version I staged in the index
- and what I have in the work tree for that file", not "show difference
+ and what I have in the work tree for that file", not "show the difference
between the HEAD commit and the work tree as a whole". You can say
`git diff HEAD --` to ask for the latter.
* Without disambiguating `--`, Git makes a reasonable guess, but errors
- out and asking you to disambiguate when ambiguous. E.g. if you have a
+ out and asks you to disambiguate when ambiguous. E.g. if you have a
file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
you have to say either `git diff HEAD --` or `git diff -- HEAD` to
disambiguate.
@@ -81,9 +81,6 @@ you will.
Here are the rules regarding the "flags" that you should follow when you are
scripting Git:
- * It's preferred to use the non-dashed form of Git commands, which means that
- you should prefer `git foo` to `git-foo`.
-
* Splitting short options to separate words (prefer `git foo -a -b`
to `git foo -ab`, the latter may not even work).
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index c0b95256cc..2122aeb976 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -1089,7 +1089,7 @@ the remote repository URL in the local repository's config file
like this:
------------------------------------------------
-$ git config remote.linus.url http://www.kernel.org/pub/scm/git/git.git/
+$ git config remote.linus.url https://git.kernel.org/pub/scm/git/git.git/
------------------------------------------------
and use the "linus" keyword with 'git pull' instead of the full URL.
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 0d57f86abc..642c51227b 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -173,7 +173,7 @@ Note that when rename detection is on but both copy and break
detection are off, rename detection adds a preliminary step that first
checks if files are moved across directories while keeping their
filename the same. If there is a file added to a directory whose
-contents is sufficiently similar to a file with the same name that got
+contents are sufficiently similar to a file with the same name that got
deleted from a different directory, it will mark them as renames and
exclude them from the later quadratic step (the one that pairwise
compares all unmatched files to find the "best" matches, determined by
@@ -213,7 +213,7 @@ from the original, and does not count insertion. If you removed
only 10 lines from a 100-line document, even if you added 910
new lines to make a new 1000-line document, you did not do a
complete rewrite. diffcore-break breaks such a case in order to
-help diffcore-rename to consider such filepairs as candidate of
+help diffcore-rename to consider such filepairs as a candidate of
rename/copy detection, but if filepairs broken that way were not
matched with other filepairs to create rename/copy, then this
transformation merges them back into the original
@@ -230,13 +230,13 @@ like these:
* -B/60 (the same as above, since diffcore-break defaults to 50%).
-Note that earlier implementation left a broken pair as a separate
-creation and deletion patches. This was an unnecessary hack and
+Note that earlier implementation left a broken pair as separate
+creation and deletion patches. This was an unnecessary hack, and
the latest implementation always merges all the broken pairs
back into modifications, but the resulting patch output is
formatted differently for easier review in case of such
-a complete rewrite by showing the entire contents of old version
-prefixed with '-', followed by the entire contents of new
+a complete rewrite by showing the entire contents of the old version
+prefixed with '-', followed by the entire contents of the new
version prefixed with '+'.
@@ -245,25 +245,25 @@ diffcore-pickaxe: For Detecting Addition/Deletion of Specified String
This transformation limits the set of filepairs to those that change
specified strings between the preimage and the postimage in a certain
-way. -S<block of text> and -G<regular expression> options are used to
+way. -S<block-of-text> and -G<regular-expression> options are used to
specify different ways these strings are sought.
-"-S<block of text>" detects filepairs whose preimage and postimage
+"-S<block-of-text>" detects filepairs whose preimage and postimage
have different number of occurrences of the specified block of text.
By definition, it will not detect in-file moves. Also, when a
changeset moves a file wholesale without affecting the interesting
string, diffcore-rename kicks in as usual, and `-S` omits the filepair
(since the number of occurrences of that string didn't change in that
rename-detected filepair). When used with `--pickaxe-regex`, treat
-the <block of text> as an extended POSIX regular expression to match,
+the <block-of-text> as an extended POSIX regular expression to match,
instead of a literal string.
-"-G<regular expression>" (mnemonic: grep) detects filepairs whose
+"-G<regular-expression>" (mnemonic: grep) detects filepairs whose
textual diff has an added or a deleted line that matches the given
regular expression. This means that it will detect in-file (or what
rename-detection considers the same file) moves, which is noise. The
implementation runs diff twice and greps, and this can be quite
-expensive. To speed things up binary files without textconv filters
+expensive. To speed things up, binary files without textconv filters
will be ignored.
When `-S` or `-G` are used without `--pickaxe-all`, only filepairs
diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt
index faba2ef088..6cfdd0e07b 100644
--- a/Documentation/giteveryday.txt
+++ b/Documentation/giteveryday.txt
@@ -14,7 +14,7 @@ DESCRIPTION
-----------
Git users can broadly be grouped into four categories for the purposes of
-describing here a small set of useful command for everyday Git.
+describing here a small set of useful commands for everyday Git.
* <<STANDALONE,Individual Developer (Standalone)>> commands are essential
for anybody who makes a commit, even for somebody who works alone.
@@ -229,7 +229,7 @@ without a formal "merging". Or longhand +
git am -3 -k`
An alternate participant submission mechanism is using the
-`git request-pull` or pull-request mechanisms (e.g as used on
+`git request-pull` or pull-request mechanisms (e.g. as used on
GitHub (www.github.com) to notify your upstream of your
contribution.
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 8c1f2d5675..f2917d142c 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -185,6 +185,58 @@ Then, you can adjust your push URL to use `git@example_author` or
`git@example_committer` instead of `git@example.org` (e.g., `git remote set-url
git@example_author:org1/project1.git`).
+Transfers
+---------
+
+[[sync-working-tree]]
+How do I sync a working tree across systems?::
+ First, decide whether you want to do this at all. Git works best when you
+ push or pull your work using the typical `git push` and `git fetch` commands
+ and isn't designed to share a working tree across systems. This is
+ potentially risky and in some cases can cause repository corruption or data
+ loss.
++
+Usually, doing so will cause `git status` to need to re-read every file in the
+working tree. Additionally, Git's security model does not permit sharing a
+working tree across untrusted users, so it is only safe to sync a working tree
+if it will only be used by a single user across all machines.
++
+It is important not to use a cloud syncing service to sync any portion of a Git
+repository, since this can cause corruption, such as missing objects, changed
+or added files, broken refs, and a wide variety of other problems. These
+services tend to sync file by file on a continuous basis and don't understand
+the structure of a Git repository. This is especially bad if they sync the
+repository in the middle of it being updated, since that is very likely to
+cause incomplete or partial updates and therefore data loss.
++
+An example of the kind of corruption that can occur is conflicts over the state
+of refs, such that both sides end up with different commits on a branch that
+the other doesn't have. This can result in important objects becoming
+unreferenced and possibly pruned by `git gc`, causing data loss.
++
+Therefore, it's better to push your work to either the other system or a central
+server using the normal push and pull mechanism. However, this doesn't always
+preserve important data, like stashes, so some people prefer to share a working
+tree across systems.
++
+If you do this, the recommended approach is to use `rsync -a --delete-after`
+(ideally with an encrypted connection such as with `ssh`) on the root of
+repository. You should ensure several things when you do this:
++
+* If you have additional worktrees or a separate Git directory, they must be
+ synced at the same time as the main working tree and repository.
+* You are comfortable with the destination directory being an exact copy of the
+ source directory, _deleting any data that is already there_.
+* The repository (including all worktrees and the Git directory) is in a
+ quiescent state for the duration of the transfer (that is, no operations of
+ any sort are taking place on it, including background operations like `git
+ gc` and operations invoked by your editor).
++
+Be aware that even with these recommendations, syncing in this way has some risk
+since it bypasses Git's normal integrity checking for repositories, so having
+backups is advised. You may also wish to do a `git fsck` to verify the
+integrity of your data on the destination system after syncing.
+
Common Issues
-------------
@@ -241,6 +293,42 @@ How do I know if I want to do a fetch or a pull?::
ignore the upstream changes. A pull consists of a fetch followed
immediately by either a merge or rebase. See linkgit:git-pull[1].
+[[proxy]]
+Can I use a proxy with Git?::
+ Yes, Git supports the use of proxies. Git honors the standard `http_proxy`,
+ `https_proxy`, and `no_proxy` environment variables commonly used on Unix, and
+ it also can be configured with `http.proxy` and similar options for HTTPS (see
+ linkgit:git-config[1]). The `http.proxy` and related options can be
+ customized on a per-URL pattern basis. In addition, Git can in theory
+ function normally with transparent proxies that exist on the network.
++
+For SSH, Git can support a proxy using OpenSSH's `ProxyCommand`. Commonly used
+tools include `netcat` and `socat`. However, they must be configured not to
+exit when seeing EOF on standard input, which usually means that `netcat` will
+require `-q` and `socat` will require a timeout with something like `-t 10`.
+This is required because the way the Git SSH server knows that no more requests
+will be made is an EOF on standard input, but when that happens, the server may
+not have yet processed the final request, so dropping the connection at that
+point would interrupt that request.
++
+An example configuration entry in `~/.ssh/config` with an HTTP proxy might look
+like this:
++
+----
+Host git.example.org
+ User git
+ ProxyCommand socat -t 10 - PROXY:proxy.example.org:%h:%p,proxyport=8080
+----
++
+Note that in all cases, for Git to work properly, the proxy must be completely
+transparent. The proxy cannot modify, tamper with, or buffer the connection in
+any way, or Git will almost certainly fail to work. Note that many proxies,
+including many TLS middleboxes, Windows antivirus and firewall programs other
+than Windows Defender and Windows Firewall, and filtering proxies fail to meet
+this standard, and as a result end up breaking Git. Because of the many
+reports of problems and their poor security history, we recommend against the
+use of these classes of software and devices.
+
Merging and Rebasing
--------------------
@@ -357,8 +445,9 @@ I'm on Windows and git diff shows my files as having a `^M` at the end.::
+
You can store the files in the repository with Unix line endings and convert
them automatically to your platform's line endings. To do that, set the
-configuration option `core.eol` to `native` and see the following entry for
-information about how to configure files as text or binary.
+configuration option `core.eol` to `native` and see
+<<recommended-storage-settings,the question on recommended storage settings>>
+for information about how to configure files as text or binary.
+
You can also control this behavior with the `core.whitespace` setting if you
don't wish to remove the carriage returns from your line endings.
@@ -420,14 +509,26 @@ references, URLs, and hashes stored in the repository.
+
We also recommend setting a linkgit:gitattributes[5] file to explicitly mark
which files are text and which are binary. If you want Git to guess, you can
-set the attribute `text=auto`. For example, the following might be appropriate
-in some projects:
+set the attribute `text=auto`.
++
+With text files, Git will generally ensure that LF endings are used in the
+repository. The `core.autocrlf` and `core.eol` configuration variables specify
+what line-ending convention is followed when any text file is checked out. You
+can also use the `eol` attribute (e.g., `eol=crlf`) to override which files get
+what line-ending treatment.
++
+For example, generally shell files must have LF endings and batch files must
+have CRLF endings, so the following might be appropriate in some projects:
+
----
# By default, guess.
* text=auto
# Mark all C files as text.
*.c text
+# Ensure all shell files have LF endings and all batch files have CRLF
+# endings in the working tree and both have LF in the repo.
+*.sh text eol=lf
+*.bat text eol=crlf
# Mark all JPEG files as binary.
*.jpg binary
----
diff --git a/Documentation/gitformat-bundle.txt b/Documentation/gitformat-bundle.txt
index 00e0a20e65..1b75cf71ce 100644
--- a/Documentation/gitformat-bundle.txt
+++ b/Documentation/gitformat-bundle.txt
@@ -67,7 +67,7 @@ A Git bundle consists of several parts.
* "Capabilities", which are only in the v3 format, indicate functionality that
the bundle requires to be read properly.
-* "Prerequisites" lists the objects that are NOT included in the bundle and the
+* "Prerequisites" list the objects that are NOT included in the bundle and the
reader of the bundle MUST already have, in order to use the data in the
bundle. The objects stored in the bundle may refer to prerequisite objects and
anything reachable from them (e.g. a tree object in the bundle can reference
@@ -86,10 +86,10 @@ In the bundle format, there can be a comment following a prerequisite obj-id.
This is a comment and it has no specific meaning. The writer of the bundle MAY
put any string here. The reader of the bundle MUST ignore the comment.
-Note on the shallow clone and a Git bundle
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note on shallow clones and Git bundles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Note that the prerequisites does not represent a shallow-clone boundary. The
+Note that the prerequisites do not represent a shallow-clone boundary. The
semantics of the prerequisites and the shallow-clone boundaries are different,
and the Git bundle v2 format cannot represent a shallow clone repository.
diff --git a/Documentation/gitformat-chunk.txt b/Documentation/gitformat-chunk.txt
index 57202ede27..3315df6201 100644
--- a/Documentation/gitformat-chunk.txt
+++ b/Documentation/gitformat-chunk.txt
@@ -42,7 +42,7 @@ Each row consists of a 4-byte chunk identifier (ID) and an 8-byte offset.
Each integer is stored in network-byte order.
The chunk identifier `ID[i]` is a label for the data stored within this
-fill from `OFFSET[i]` (inclusive) to `OFFSET[i+1]` (exclusive). Thus, the
+file from `OFFSET[i]` (inclusive) to `OFFSET[i+1]` (exclusive). Thus, the
size of the `i`th chunk is equal to the difference between `OFFSET[i+1]`
and `OFFSET[i]`. This requires that the chunk data appears contiguously
in the same order as the table of contents.
@@ -67,7 +67,7 @@ caller is responsible for opening the `hashfile` and writing header
information so the file format is identifiable before the chunk-based
format begins.
-Then, call `add_chunk()` for each chunk that is intended for write. This
+Then, call `add_chunk()` for each chunk that is intended for writing. This
populates the `chunkfile` with information about the order and size of
each chunk to write. Provide a `chunk_write_fn` function pointer to
perform the write of the chunk data upon request.
diff --git a/Documentation/gitformat-commit-graph.txt b/Documentation/gitformat-commit-graph.txt
index 31cad585e2..14d1631234 100644
--- a/Documentation/gitformat-commit-graph.txt
+++ b/Documentation/gitformat-commit-graph.txt
@@ -122,7 +122,7 @@ All multi-byte numbers are in network byte order.
for commits with corrected commit date offsets that cannot be
stored within 31 bits.
* Generation Data Overflow chunk is present only when Generation Data
- chunk is present and atleast one corrected commit date offset cannot
+ chunk is present and at least one corrected commit date offset cannot
be stored within 31 bits.
==== Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
@@ -142,13 +142,16 @@ All multi-byte numbers are in network byte order.
==== Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
* It starts with header consisting of three unsigned 32-bit integers:
- - Version of the hash algorithm being used. We currently only support
- value 1 which corresponds to the 32-bit version of the murmur3 hash
+ - Version of the hash algorithm being used. We currently support
+ value 2 which corresponds to the 32-bit version of the murmur3 hash
implemented exactly as described in
https://en.wikipedia.org/wiki/MurmurHash#Algorithm and the double
hashing technique using seed values 0x293ae76f and 0x7e646e2 as
described in https://doi.org/10.1007/978-3-540-30494-4_26 "Bloom Filters
- in Probabilistic Verification"
+ in Probabilistic Verification". Version 1 Bloom filters have a bug that appears
+ when char is signed and the repository has path names that have characters >=
+ 0x80; Git supports reading and writing them, but this ability will be removed
+ in a future version of Git.
- The number of times a path is hashed and hence the number of bit positions
that cumulatively determine whether a file is present in the commit.
- The minimum number of bits 'b' per entry in the Bloom filter. If the filter
diff --git a/Documentation/gitformat-index.txt b/Documentation/gitformat-index.txt
index 0773e5c380..145cace1fe 100644
--- a/Documentation/gitformat-index.txt
+++ b/Documentation/gitformat-index.txt
@@ -386,8 +386,8 @@ The remaining data of each directory block is grouped by type:
long, "REUC" extension that is M-bytes long, followed by "EOIE",
then the hash would be:
- Hash("TREE" + <binary representation of N> +
- "REUC" + <binary representation of M>)
+ Hash("TREE" + <binary-representation-of-N> +
+ "REUC" + <binary-representation-of-M>)
== Index Entry Offset Table
diff --git a/Documentation/gitformat-pack.txt b/Documentation/gitformat-pack.txt
index 0c1be2dbe8..d6ae229be5 100644
--- a/Documentation/gitformat-pack.txt
+++ b/Documentation/gitformat-pack.txt
@@ -17,8 +17,8 @@ $GIT_DIR/objects/pack/multi-pack-index
DESCRIPTION
-----------
-The Git pack format is now Git stores most of its primary repository
-data. Over the lietime af a repository loose objects (if any) and
+The Git pack format is how Git stores most of its primary repository
+data. Over the lifetime of a repository, loose objects (if any) and
smaller packs are consolidated into larger pack(s). See
linkgit:git-gc[1] and linkgit:git-pack-objects[1].
@@ -48,7 +48,7 @@ Similarly, in SHA-256 repositories, these values are computed using SHA-256.
Observation: we cannot have more than 4G versions ;-) and
more than 4G objects in a pack.
- - The header is followed by number of object entries, each of
+ - The header is followed by a number of object entries, each of
which looks like this:
(undeltified representation)
@@ -62,7 +62,7 @@ Similarly, in SHA-256 repositories, these values are computed using SHA-256.
is an OBJ_OFS_DELTA object
compressed delta data
- Observation: length of each object is encoded in a variable
+ Observation: the length of each object is encoded in a variable
length format and is not constrained to 32-bit or anything.
- The trailer records a pack checksum of all of the above.
@@ -117,7 +117,7 @@ the delta data is a sequence of instructions to reconstruct the object
from the base object. If the base object is deltified, it must be
converted to canonical form first. Each instruction appends more and
more data to the target object until it's complete. There are two
-supported instructions so far: one for copy a byte range from the
+supported instructions so far: one for copying a byte range from the
source object and one for inserting new data embedded in the
instruction itself.
@@ -137,7 +137,7 @@ copy. Offset and size are in little-endian order.
All offset and size bytes are optional. This is to reduce the
instruction size when encoding small offsets or sizes. The first seven
-bits in the first octet determines which of the next seven octets is
+bits in the first octet determine which of the next seven octets is
present. If bit zero is set, offset1 is present. If bit one is set
offset2 is present and so on.
@@ -161,9 +161,9 @@ converted to 0x10000.
| 0xxxxxxx | data |
+----------+============+
-This is the instruction to construct target object without the base
+This is the instruction to construct the target object without the base
object. The following data is appended to the target object. The first
-seven bits of the first octet determines the size of data in
+seven bits of the first octet determine the size of data in
bytes. The size must be non-zero.
==== Reserved instruction
@@ -294,7 +294,7 @@ Pack file entry: <+
- The same trailer as a v1 pack file:
- A copy of the pack checksum at the end of
+ A copy of the pack checksum at the end of the
corresponding packfile.
Index checksum of all of the above.
@@ -390,10 +390,20 @@ CHUNK LOOKUP:
CHUNK DATA:
Packfile Names (ID: {'P', 'N', 'A', 'M'})
- Stores the packfile names as concatenated, null-terminated strings.
- Packfiles must be listed in lexicographic order for fast lookups by
- name. This is the only chunk not guaranteed to be a multiple of four
- bytes in length, so should be the last chunk for alignment reasons.
+ Store the names of packfiles as a sequence of NUL-terminated
+ strings. There is no extra padding between the filenames,
+ and they are listed in lexicographic order. The chunk itself
+ is padded at the end with between 0 and 3 NUL bytes to make the
+ chunk size a multiple of 4 bytes.
+
+ Bitmapped Packfiles (ID: {'B', 'T', 'M', 'P'})
+ Stores a table of two 4-byte unsigned integers in network order.
+ Each table entry corresponds to a single pack (in the order that
+ they appear above in the `PNAM` chunk). The values for each table
+ entry are as follows:
+ - The first bit position (in pseudo-pack order, see below) to
+ contain an object from that pack.
+ - The number of bits whose objects are selected from that pack.
OID Fanout (ID: {'O', 'I', 'D', 'F'})
The ith entry, F[i], stores the number of OIDs with first
@@ -508,6 +518,73 @@ packs arranged in MIDX order (with the preferred pack coming first).
The MIDX's reverse index is stored in the optional 'RIDX' chunk within
the MIDX itself.
+=== `BTMP` chunk
+
+The Bitmapped Packfiles (`BTMP`) chunk encodes additional information
+about the objects in the multi-pack index's reachability bitmap. Recall
+that objects from the MIDX are arranged in "pseudo-pack" order (see
+above) for reachability bitmaps.
+
+From the example above, suppose we have packs "a", "b", and "c", with
+10, 15, and 20 objects, respectively. In pseudo-pack order, those would
+be arranged as follows:
+
+ |a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
+
+When working with single-pack bitmaps (or, equivalently, multi-pack
+reachability bitmaps with a preferred pack), linkgit:git-pack-objects[1]
+performs ``verbatim'' reuse, attempting to reuse chunks of the bitmapped
+or preferred packfile instead of adding objects to the packing list.
+
+When a chunk of bytes is reused from an existing pack, any objects
+contained therein do not need to be added to the packing list, saving
+memory and CPU time. But a chunk from an existing packfile can only be
+reused when the following conditions are met:
+
+ - The chunk contains only objects which were requested by the caller
+ (i.e. does not contain any objects which the caller didn't ask for
+ explicitly or implicitly).
+
+ - All objects stored in non-thin packs as offset- or reference-deltas
+ also include their base object in the resulting pack.
+
+The `BTMP` chunk encodes the necessary information in order to implement
+multi-pack reuse over a set of packfiles as described above.
+Specifically, the `BTMP` chunk encodes three pieces of information (all
+32-bit unsigned integers in network byte-order) for each packfile `p`
+that is stored in the MIDX, as follows:
+
+`bitmap_pos`:: The first bit position (in pseudo-pack order) in the
+ multi-pack index's reachability bitmap occupied by an object from `p`.
+
+`bitmap_nr`:: The number of bit positions (including the one at
+ `bitmap_pos`) that encode objects from that pack `p`.
+
+For example, the `BTMP` chunk corresponding to the above example (with
+packs ``a'', ``b'', and ``c'') would look like:
+
+[cols="1,2,2"]
+|===
+| |`bitmap_pos` |`bitmap_nr`
+
+|packfile ``a''
+|`0`
+|`10`
+
+|packfile ``b''
+|`10`
+|`15`
+
+|packfile ``c''
+|`25`
+|`20`
+|===
+
+With this information in place, we can treat each packfile as
+individually reusable in the same fashion as verbatim pack reuse is
+performed on individual packs prior to the implementation of the `BTMP`
+chunk.
+
== cruft packs
The cruft packs feature offer an alternative to Git's traditional mechanism of
@@ -588,51 +665,17 @@ later on.
It is linkgit:git-gc[1] that is typically responsible for removing expired
unreachable objects.
-=== Caution for mixed-version environments
-
-Repositories that have cruft packs in them will continue to work with any older
-version of Git. Note, however, that previous versions of Git which do not
-understand the `.mtimes` file will use the cruft pack's mtime as the mtime for
-all of the objects in it. In other words, do not expect older (pre-cruft pack)
-versions of Git to interpret or even read the contents of the `.mtimes` file.
-
-Note that having mixed versions of Git GC-ing the same repository can lead to
-unreachable objects never being completely pruned. This can happen under the
-following circumstances:
-
- - An older version of Git running GC explodes the contents of an existing
- cruft pack loose, using the cruft pack's mtime.
- - A newer version running GC collects those loose objects into a cruft pack,
- where the .mtime file reflects the loose object's actual mtimes, but the
- cruft pack mtime is "now".
-
-Repeating this process will lead to unreachable objects not getting pruned as a
-result of repeatedly resetting the objects' mtimes to the present time.
-
-If you are GC-ing repositories in a mixed version environment, consider omitting
-the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
-setting the `gc.cruftPacks` configuration to "false" until all writers
-understand cruft packs.
-
=== Alternatives
Notable alternatives to this design include:
- - The location of the per-object mtime data, and
- - Storing unreachable objects in multiple cruft packs.
+ - The location of the per-object mtime data.
On the location of mtime data, a new auxiliary file tied to the pack was chosen
to avoid complicating the `.idx` format. If the `.idx` format were ever to gain
support for optional chunks of data, it may make sense to consolidate the
`.mtimes` format into the `.idx` itself.
-Storing unreachable objects among multiple cruft packs (e.g., creating a new
-cruft pack during each repacking operation including only unreachable objects
-which aren't already stored in an earlier cruft pack) is significantly more
-complicated to construct, and so aren't pursued here. The obvious drawback to
-the current implementation is that the entire cruft pack must be re-written from
-scratch.
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 86f804720a..0397dec64d 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -80,7 +80,7 @@ If it exits with non-zero status, then the working tree will not be
committed after applying the patch.
It can be used to inspect the current working tree and refuse to
-make a commit if it does not pass certain test.
+make a commit if it does not pass certain tests.
The default 'pre-applypatch' hook, when enabled, runs the
'pre-commit' hook, if the latter is enabled.
@@ -157,7 +157,7 @@ If the exit status is non-zero, `git commit` will abort.
The purpose of the hook is to edit the message file in place, and
it is not suppressed by the `--no-verify` option. A non-zero exit
means a failure of the hook and aborts the commit. It should not
-be used as replacement for pre-commit hook.
+be used as a replacement for the pre-commit hook.
The sample `prepare-commit-msg` hook that comes with Git removes the
help message found in the commented portion of the commit template.
@@ -243,7 +243,7 @@ named remote is not being used both values will be the same.
Information about what is to be pushed is provided on the hook's standard
input with lines of the form:
- <local ref> SP <local object name> SP <remote ref> SP <remote object name> LF
+ <local-ref> SP <local-object-name> SP <remote-ref> SP <remote-object-name> LF
For instance, if the command +git push origin master:foreign+ were run the
hook would receive a line like the following:
@@ -251,9 +251,9 @@ hook would receive a line like the following:
refs/heads/master 67890 refs/heads/foreign 12345
although the full object name would be supplied. If the foreign ref does not
-yet exist the `<remote object name>` will be the all-zeroes object name. If a
-ref is to be deleted, the `<local ref>` will be supplied as `(delete)` and the
-`<local object name>` will be the all-zeroes object name. If the local commit
+yet exist the `<remote-object-name>` will be the all-zeroes object name. If a
+ref is to be deleted, the `<local-ref>` will be supplied as `(delete)` and the
+`<local-object-name>` will be the all-zeroes object name. If the local commit
was specified by something other than a name which could be expanded (such as
`HEAD~`, or an object name) it will be supplied as it was originally given.
@@ -275,12 +275,12 @@ This hook executes once for the receive operation. It takes no
arguments, but for each ref to be updated it receives on standard
input a line of the format:
- <old-value> SP <new-value> SP <ref-name> LF
+ <old-oid> SP <new-oid> SP <ref-name> LF
-where `<old-value>` is the old object name stored in the ref,
-`<new-value>` is the new object name to be stored in the ref and
+where `<old-oid>` is the old object name stored in the ref,
+`<new-oid>` is the new object name to be stored in the ref and
`<ref-name>` is the full name of the ref.
-When creating a new ref, `<old-value>` is the all-zeroes object name.
+When creating a new ref, `<old-oid>` is the all-zeroes object name.
If the hook exits with non-zero status, none of the refs will be
updated. If the hook exits with zero, updating of individual refs can
@@ -345,7 +345,7 @@ for the user.
The default 'update' hook, when enabled--and with
`hooks.allowunannotated` config option unset or set to false--prevents
-unannotated tags to be pushed.
+unannotated tags from being pushed.
[[proc-receive]]
proc-receive
@@ -379,12 +379,12 @@ following example for the protocol, the letter 'S' stands for
S: ... ...
S: flush-pkt
- # Receive result from the hook.
+ # Receive results from the hook.
# OK, run this command successfully.
H: PKT-LINE(ok <ref>)
# NO, I reject it.
H: PKT-LINE(ng <ref> <reason>)
- # Fall through, let 'receive-pack' to execute it.
+ # Fall through, let 'receive-pack' execute it.
H: PKT-LINE(ok <ref>)
H: PKT-LINE(option fall-through)
# OK, but has an alternate reference. The alternate reference name
@@ -415,13 +415,13 @@ post-receive
This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
`git push` and updates reference(s) in its repository.
-It executes on the remote repository once after all the refs have
-been updated.
+The hook executes on the remote repository once after all the proposed
+ref updates are processed and if at least one ref is updated as the
+result.
-This hook executes once for the receive operation. It takes no
-arguments, but gets the same information as the
-<<pre-receive,'pre-receive'>>
-hook does on its standard input.
+The hook takes no arguments. It receives one line on standard input for
+each ref that is successfully updated following the same format as the
+<<pre-receive,'pre-receive'>> hook.
This hook does not affect the outcome of `git receive-pack`, as it
is called after the real work is done.
@@ -448,6 +448,9 @@ environment variables will not be set. If the client selects
to use push options, but doesn't transmit any, the count variable
will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
+See the "post-receive" section in linkgit:git-receive-pack[1] for
+additional details.
+
[[post-update]]
post-update
~~~~~~~~~~~
@@ -486,7 +489,7 @@ reference-transaction
This hook is invoked by any Git command that performs reference
updates. It executes whenever a reference transaction is prepared,
committed or aborted and may thus get called multiple times. The hook
-does not cover symbolic references (but that may change in the future).
+also supports symbolic reference updates.
The hook takes exactly one argument, which is the current state the
given reference transaction is in:
@@ -513,6 +516,10 @@ to be created anew, `<old-value>` is the all-zeroes object name. To
distinguish these cases, you can inspect the current value of
`<ref-name>` via `git rev-parse`.
+For symbolic reference updates the `<old_value>` and `<new-value>`
+fields could denote references instead of objects. A reference will be
+denoted with a 'ref:' prefix, like `ref:<ref-target>`.
+
The exit status of the hook is ignored for any state except for the
"prepared" state. In the "prepared" state, a non-zero exit status will
cause the transaction to be aborted. The hook will not be called with
diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt
index d50e9ed10e..35b3996029 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.txt
@@ -8,7 +8,7 @@ gitk - The Git repository browser
SYNOPSIS
--------
[verse]
-'gitk' [<options>] [<revision range>] [--] [<path>...]
+'gitk' [<options>] [<revision-range>] [--] [<path>...]
DESCRIPTION
-----------
@@ -26,7 +26,7 @@ changes each commit introduces are shown. Finally, it supports some
gitk-specific options.
gitk generally only understands options with arguments in the
-'sticked' form (see linkgit:gitcli[7]) due to limitations in the
+'stuck' form (see linkgit:gitcli[7]) due to limitations in the
command-line parser.
rev-list options and arguments
@@ -124,7 +124,7 @@ gitk-specific options
range to show. The command is expected to print on its
standard output a list of additional revisions to be shown,
one per line. Use this instead of explicitly specifying a
- '<revision range>' if the set of commits to show may vary
+ '<revision-range>' if the set of commits to show may vary
between refreshes.
--select-commit=<ref>::
diff --git a/Documentation/gitpacking.txt b/Documentation/gitpacking.txt
new file mode 100644
index 0000000000..321154d4e6
--- /dev/null
+++ b/Documentation/gitpacking.txt
@@ -0,0 +1,195 @@
+gitpacking(7)
+=============
+
+NAME
+----
+gitpacking - Advanced concepts related to packing in Git
+
+SYNOPSIS
+--------
+gitpacking
+
+DESCRIPTION
+-----------
+
+This document aims to describe some advanced concepts related to packing
+in Git.
+
+Many concepts are currently described scattered between manual pages of
+various Git commands, including linkgit:git-pack-objects[1],
+linkgit:git-repack[1], and others, as well as linkgit:gitformat-pack[5],
+and parts of the `Documentation/technical` tree.
+
+There are many aspects of packing in Git that are not covered in this
+document that instead live in the aforementioned areas. Over time, those
+scattered bits may coalesce into this document.
+
+== Pseudo-merge bitmaps
+
+NOTE: Pseudo-merge bitmaps are considered an experimental feature, so
+the configuration and many of the ideas are subject to change.
+
+=== Background
+
+Reachability bitmaps are most efficient when we have on-disk stored
+bitmaps for one or more of the starting points of a traversal. For this
+reason, Git prefers storing bitmaps for commits at the tips of refs,
+because traversals tend to start with those points.
+
+But if you have a large number of refs, it's not feasible to store a
+bitmap for _every_ ref tip. It takes up space, and just OR-ing all of
+those bitmaps together is expensive.
+
+One way we can deal with that is to create bitmaps that represent
+_groups_ of refs. When a traversal asks about the entire group, then we
+can use this single bitmap instead of considering each ref individually.
+Because these bitmaps represent the set of objects which would be
+reachable in a hypothetical merge of all of the commits, we call them
+pseudo-merge bitmaps.
+
+=== Overview
+
+A "pseudo-merge bitmap" is used to refer to a pair of bitmaps, as
+follows:
+
+Commit bitmap::
+
+ A bitmap whose set bits describe the set of commits included in the
+ pseudo-merge's "merge" bitmap (as below).
+
+Merge bitmap::
+
+ A bitmap whose set bits describe the reachability closure over the set
+ of commits in the pseudo-merge's "commits" bitmap (as above). An
+ identical bitmap would be generated for an octopus merge with the same
+ set of parents as described in the commits bitmap.
+
+Pseudo-merge bitmaps can accelerate bitmap traversals when all commits
+for a given pseudo-merge are listed on either side of the traversal,
+either directly (by explicitly asking for them as part of the `HAVES`
+or `WANTS`) or indirectly (by encountering them during a fill-in
+traversal).
+
+=== Use-cases
+
+For example, suppose there exists a pseudo-merge bitmap with a large
+number of commits, all of which are listed in the `WANTS` section of
+some bitmap traversal query. When pseudo-merge bitmaps are enabled, the
+bitmap machinery can quickly determine there is a pseudo-merge which
+satisfies some subset of the wanted objects on either side of the query.
+Then, we can inflate the EWAH-compressed bitmap, and `OR` it in to the
+resulting bitmap. By contrast, without pseudo-merge bitmaps, we would
+have to repeat the decompression and `OR`-ing step over a potentially
+large number of individual bitmaps, which can take proportionally more
+time.
+
+Another benefit of pseudo-merges arises when there is some combination
+of (a) a large number of references, with (b) poor bitmap coverage, and
+(c) deep, nested trees, making fill-in traversal relatively expensive.
+For example, suppose that there are a large enough number of tags where
+bitmapping each of the tags individually is infeasible. Without
+pseudo-merge bitmaps, computing the result of, say, `git rev-list
+--use-bitmap-index --count --objects --tags` would likely require a
+large amount of fill-in traversal. But when a large quantity of those
+tags are stored together in a pseudo-merge bitmap, the bitmap machinery
+can take advantage of the fact that we only care about the union of
+objects reachable from all of those tags, and answer the query much
+faster.
+
+=== Configuration
+
+Reference tips are grouped into different pseudo-merge groups according
+to two criteria. A reference name matches one or more of the defined
+pseudo-merge patterns, and optionally one or more capture groups within
+that pattern which further partition the group.
+
+Within a group, commits may be considered "stable", or "unstable"
+depending on their age. These are adjusted by setting the
+`bitmapPseudoMerge.<name>.stableThreshold` and
+`bitmapPseudoMerge.<name>.threshold` configuration values, respectively.
+
+All stable commits are grouped into pseudo-merges of equal size
+(`bitmapPseudoMerge.<name>.stableSize`). If the `stableSize`
+configuration is set to, say, 100, then the first 100 commits (ordered
+by committer date) which are older than the `stableThreshold` value will
+form one group, the next 100 commits will form another group, and so on.
+
+Among unstable commits, the pseudo-merge machinery will attempt to
+combine older commits into large groups as opposed to newer commits
+which will appear in smaller groups. This is based on the heuristic that
+references whose tip commit is older are less likely to be modified to
+point at a different commit than a reference whose tip commit is newer.
+
+The size of groups is determined by a power-law decay function, and the
+decay parameter roughly corresponds to "k" in `f(n) = C*n^(-k/100)`,
+where `f(n)` describes the size of the `n`-th pseudo-merge group. The
+sample rate controls what percentage of eligible commits are considered
+as candidates. The threshold parameter indicates the minimum age (so as
+to avoid including too-recent commits in a pseudo-merge group, making it
+less likely to be valid). The "maxMerges" parameter sets an upper-bound
+on the number of pseudo-merge commits an individual group
+
+The "stable"-related parameters control "stable" pseudo-merge groups,
+comprised of a fixed number of commits which are older than the
+configured "stable threshold" value and may be grouped together in
+chunks of "stableSize" in order of age.
+
+The exact configuration for pseudo-merges is as follows:
+
+include::config/bitmap-pseudo-merge.txt[]
+
+=== Examples
+
+Suppose that you have a repository with a large number of references,
+and you want a bare-bones configuration of pseudo-merge bitmaps that
+will enhance bitmap coverage of the `refs/` namespace. You may start
+with a configuration like so:
+
+----
+[bitmapPseudoMerge "all"]
+ pattern = "refs/"
+ threshold = now
+ stableThreshold = never
+ sampleRate = 100
+ maxMerges = 64
+----
+
+This will create pseudo-merge bitmaps for all references, regardless of
+their age, and group them into 64 pseudo-merge commits.
+
+If you wanted to separate tags from branches when generating
+pseudo-merge commits, you would instead define the pattern with a
+capture group, like so:
+
+----
+[bitmapPseudoMerge "all"]
+ pattern = "refs/(heads/tags)/"
+----
+
+Suppose instead that you are working in a fork-network repository, with
+each fork specified by some numeric ID, and whose refs reside in
+`refs/virtual/NNN/` (where `NNN` is the numeric ID corresponding to some
+fork) in the network. In this instance, you may instead write something
+like:
+
+----
+[bitmapPseudoMerge "all"]
+ pattern = "refs/virtual/([0-9]+)/(heads|tags)/"
+ threshold = now
+ stableThreshold = never
+ sampleRate = 100
+ maxMerges = 64
+----
+
+Which would generate pseudo-merge group identifiers like "1234-heads",
+and "5678-tags" (for branches in fork "1234", and tags in remote "5678",
+respectively).
+
+SEE ALSO
+--------
+linkgit:git-pack-objects[1]
+linkgit:git-repack[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitprotocol-capabilities.txt b/Documentation/gitprotocol-capabilities.txt
index 0fb5ea0c1c..2cf7735be4 100644
--- a/Documentation/gitprotocol-capabilities.txt
+++ b/Documentation/gitprotocol-capabilities.txt
@@ -30,7 +30,7 @@ to be in effect. The client MUST NOT ask for capabilities the server
did not say it supports.
Server MUST diagnose and abort if capabilities it does not understand
-was sent. Server MUST NOT ignore capabilities that client requested
+were sent. Server MUST NOT ignore capabilities that client requested
and server advertised. As a consequence of these rules, server MUST
NOT advertise capabilities it does not understand.
@@ -61,8 +61,8 @@ complete cut across the DAG, or the client has said "done".
Without multi_ack, a client sends have lines in --date-order until
the server has found a common base. That means the client will send
have lines that are already known by the server to be common, because
-they overlap in time with another branch that the server hasn't found
-a common base on yet.
+they overlap in time with another branch on which the server hasn't found
+a common base yet.
For example suppose the client has commits in caps that the server
doesn't and the server has commits in lower case that the client
@@ -88,7 +88,7 @@ interleaved with S-R-Q.
multi_ack_detailed
------------------
-This is an extension of multi_ack that permits client to better
+This is an extension of multi_ack that permits the client to better
understand the server's in-memory state. See linkgit:gitprotocol-pack[5],
section "Packfile Negotiation" for more information.
@@ -135,7 +135,7 @@ to disable the feature in a backwards-compatible manner.
side-band, side-band-64k
------------------------
-This capability means that server can send, and client understand multiplexed
+This capability means that the server can send, and the client can understand, multiplexed
progress reports and error info interleaved with the packfile itself.
These two options are mutually exclusive. A modern client always
@@ -163,14 +163,14 @@ Further, with side-band and its up to 1000-byte messages, it's actually
same deal, you have up to 65519 bytes of data and 1 byte for the stream
code.
-The client MUST send only maximum of one of "side-band" and "side-
-band-64k". Server MUST diagnose it as an error if client requests
+The client MUST send only one of "side-band" and "side-
+band-64k". The server MUST diagnose it as an error if client requests
both.
ofs-delta
---------
-Server can send, and client understand PACKv2 with delta referring to
+The server can send, and the client can understand, PACKv2 with delta referring to
its base by position in pack rather than by an obj-id. That is, they can
send/read OBJ_OFS_DELTA (aka type 6) in a packfile.
@@ -252,7 +252,7 @@ the current shallow boundary, instead of the depth from remote refs.
no-progress
-----------
-The client was started with "git clone -q" or something, and doesn't
+The client was started with "git clone -q" or something similar, and doesn't
want that side band 2. Basically the client just says "I do not
wish to receive stream 2 on sideband, so do not send it to me, and if
you did, I will drop it on the floor anyway". However, the sideband
@@ -273,7 +273,7 @@ request include-tag only has to do with the client's desires for tag
data, whether or not a server had advertised objects in the
refs/tags/* namespace.
-Servers MUST pack the tags if their referrant is packed and the client
+Servers MUST pack the tags if their referent is packed and the client
has requested include-tags.
Clients MUST be prepared for the case where a server has ignored
@@ -378,7 +378,7 @@ fetch-pack may send "filter" commands to request a partial clone
or partial fetch and request that the server omit various objects
from the packfile.
-session-id=<session id>
+session-id=<session-id>
-----------------------
The server may advertise a session ID that can be used to identify this process
diff --git a/Documentation/gitprotocol-common.txt b/Documentation/gitprotocol-common.txt
index 1486651bd1..cdc9d6e707 100644
--- a/Documentation/gitprotocol-common.txt
+++ b/Documentation/gitprotocol-common.txt
@@ -13,7 +13,7 @@ SYNOPSIS
DESCRIPTION
-----------
-This document sets defines things common to various over-the-wire
+This document defines things common to various over-the-wire
protocols and file formats used in Git.
ABNF Notation
diff --git a/Documentation/gitprotocol-http.txt b/Documentation/gitprotocol-http.txt
index ccc13f0a40..ec40a550cc 100644
--- a/Documentation/gitprotocol-http.txt
+++ b/Documentation/gitprotocol-http.txt
@@ -42,7 +42,7 @@ both the "smart" and "dumb" HTTP protocols used by Git operate
by appending additional path components onto the end of the user
supplied `$GIT_URL` string.
-An example of a dumb client requesting for a loose object:
+An example of a dumb client requesting a loose object:
$GIT_URL: http://example.com:8080/git/repo.git
URL request: http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355
@@ -379,7 +379,7 @@ C: Place any object seen into set `advertised`.
C: Build an empty set, `common`, to hold the objects that are later
determined to be on both ends.
-C: Build a set, `want`, of the objects from `advertised` the client
+C: Build a set, `want`, of the objects from `advertised` that the client
wants to fetch, based on what it saw during ref discovery.
C: Start a queue, `c_pending`, ordered by commit time (popping newest
@@ -391,14 +391,14 @@ C: Start a queue, `c_pending`, ordered by commit time (popping newest
C: Send one `$GIT_URL/git-upload-pack` request:
- C: 0032want <want #1>...............................
- C: 0032want <want #2>...............................
+ C: 0032want <want-#1>...............................
+ C: 0032want <want-#2>...............................
....
- C: 0032have <common #1>.............................
- C: 0032have <common #2>.............................
+ C: 0032have <common-#1>.............................
+ C: 0032have <common-#2>.............................
....
- C: 0032have <have #1>...............................
- C: 0032have <have #2>...............................
+ C: 0032have <have-#1>...............................
+ C: 0032have <have-#2>...............................
....
C: 0000
@@ -423,7 +423,7 @@ multiple commands. Object names MUST be given using the object format
negotiated through the `object-format` capability (default SHA-1).
The `have` list is created by popping the first 32 commits
-from `c_pending`. Less can be supplied if `c_pending` empties.
+from `c_pending`. Fewer can be supplied if `c_pending` empties.
If the client has sent 256 "have" commits and has not yet
received one of those back from `s_common`, or the client has
@@ -512,7 +512,7 @@ Within the command portion of the request body clients SHOULD send
the id obtained through ref discovery as old_id.
update_request = command_list
- "PACK" <binary data>
+ "PACK" <binary-data>
command_list = PKT-LINE(command NUL cap_list LF)
*(command_pkt)
@@ -529,8 +529,8 @@ TODO: Document this further.
REFERENCES
----------
-http://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
-http://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
+https://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
+https://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
SEE ALSO
--------
diff --git a/Documentation/gitprotocol-pack.txt b/Documentation/gitprotocol-pack.txt
index dd4108b7a3..837b691c89 100644
--- a/Documentation/gitprotocol-pack.txt
+++ b/Documentation/gitprotocol-pack.txt
@@ -30,7 +30,7 @@ pkt-line Format
---------------
The descriptions below build on the pkt-line format described in
-linkgit:gitprotocol-common[5]. When the grammar indicate `PKT-LINE(...)`, unless
+linkgit:gitprotocol-common[5]. When the grammar indicates `PKT-LINE(...)`, unless
otherwise noted the usual pkt-line LF rules apply: the sender SHOULD
include a LF, but the receiver MUST NOT complain if it is not present.
@@ -137,7 +137,7 @@ an absolute path in the remote filesystem.
v
ssh user@example.com "git-upload-pack '/project.git'"
-In a "user@host:path" format URI, its relative to the user's home
+In a "user@host:path" format URI, it's relative to the user's home
directory, because the Git client will run:
git clone user@example.com:project.git
@@ -325,7 +325,7 @@ a positive depth, this step is skipped.
If the client has requested a positive depth, the server will compute
the set of commits which are no deeper than the desired depth. The set
-of commits start at the client's wants.
+of commits starts at the client's wants.
The server writes 'shallow' lines for each
commit whose parents will not be sent as a result. The server writes
diff --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.txt
index acb97ad0c2..1652fef3ae 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.txt
@@ -29,7 +29,7 @@ protocol. Protocol v2 will improve upon v1 in the following ways:
semantics the http remote helper can simply act as a proxy
In protocol v2 communication is command oriented. When first contacting a
-server a list of capabilities will advertised. Some of these capabilities
+server a list of capabilities will be advertised. Some of these capabilities
will be commands which a client can request be executed. Once a command
has completed, a client can reuse the connection and request that other
commands be executed.
@@ -199,7 +199,7 @@ which can be used to limit the refs sent from the server.
Additional features not supported in the base command will be advertised
as the value of the command in the capability advertisement in the form
-of a space separated list of features: "<command>=<feature 1> <feature 2>"
+of a space separated list of features: "<command>=<feature-1> <feature-2>"
ls-refs takes in the following arguments:
@@ -245,7 +245,7 @@ addition of future extensions.
Additional features not supported in the base command will be advertised
as the value of the command in the capability advertisement in the form
-of a space separated list of features: "<command>=<feature 1> <feature 2>"
+of a space separated list of features: "<command>=<feature-1> <feature-2>"
A `fetch` request can take the following arguments:
@@ -346,7 +346,8 @@ the 'wanted-refs' section in the server's response as explained below.
want-ref <ref>
Indicates to the server that the client wants to retrieve a
particular ref, where <ref> is the full name of a ref on the
- server.
+ server. It is a protocol error to send want-ref for the
+ same ref more than once.
If the 'sideband-all' feature is advertised, the following argument can be
included in the client's request:
@@ -361,9 +362,10 @@ included in the client's request:
If the 'packfile-uris' feature is advertised, the following argument
can be included in the client's request as well as the potential
addition of the 'packfile-uris' section in the server's response as
-explained below.
+explained below. Note that at most one `packfile-uris` line can be sent
+to the server.
- packfile-uris <comma-separated list of protocols>
+ packfile-uris <comma-separated-list-of-protocols>
Indicates to the server that the client is willing to receive
URIs of any of the given protocols in place of objects in the
sent packfile. Before performing the connectivity check, the
@@ -525,8 +527,8 @@ a request.
The provided options must not contain a NUL or LF character.
- object-format
-~~~~~~~~~~~~~~~
+object-format
+~~~~~~~~~~~~~
The server can advertise the `object-format` capability with a value `X` (in the
form `object-format=X`) to notify the client that the server is able to deal
@@ -534,7 +536,7 @@ with objects using hash algorithm X. If not specified, the server is assumed to
only handle SHA-1. If the client would like to use a hash algorithm other than
SHA-1, it should specify its object-format string.
-session-id=<session id>
+session-id=<session-id>
~~~~~~~~~~~~~~~~~~~~~~~
The server may advertise a session ID that can be used to identify this process
@@ -774,7 +776,7 @@ This would allow for optimizing the common case of servers who'd like
to provide one "big bundle" containing only their "main" branch,
and/or incremental updates thereof.
+
-A client receiving such a a response MAY assume that they can skip
+A client receiving such a response MAY assume that they can skip
retrieving the header from a bundle at the indicated URI, and thus
save themselves and the server(s) the request(s) needed to inspect the
headers of that bundle or bundles.
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index ed8da428c9..d0be008e5e 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -479,14 +479,14 @@ set by Git if the remote helper has the 'option' capability.
'option depth' <depth>::
Deepens the history of a shallow repository.
-'option deepen-since <timestamp>::
+'option deepen-since' <timestamp>::
Deepens the history of a shallow repository based on time.
-'option deepen-not <ref>::
+'option deepen-not' <ref>::
Deepens the history of a shallow repository excluding ref.
Multiple options add up.
-'option deepen-relative {'true'|'false'}::
+'option deepen-relative' {'true'|'false'}::
Deepens the history of a shallow repository relative to
current boundary. Only valid when used with "option depth".
@@ -526,7 +526,7 @@ set by Git if the remote helper has the 'option' capability.
'option pushcert' {'true'|'false'}::
GPG sign pushes.
-'option push-option <string>::
+'option push-option' <string>::
Transmit <string> as a push option. As the push option
must not contain LF or NUL characters, the string is not encoded.
@@ -542,13 +542,10 @@ set by Git if the remote helper has the 'option' capability.
transaction. If successful, all refs will be updated, or none will. If the
remote side does not support this capability, the push will fail.
-'option object-format' {'true'|algorithm}::
- If 'true', indicate that the caller wants hash algorithm information
+'option object-format true'::
+ Indicate that the caller wants hash algorithm information
to be passed back from the remote. This mode is used when fetching
refs.
-+
-If set to an algorithm, indicate that the caller wants to interact with
-the remote side using that algorithm.
SEE ALSO
--------
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 1a2ef4c150..fa8b51daf0 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -23,7 +23,9 @@ A Git repository comes in two different flavours:
*Note*: Also you can have a plain text file `.git` at the root of
your working tree, containing `gitdir: <path>` to point at the real
-directory that has the repository. This mechanism is often used for
+directory that has the repository.
+This mechanism is called a 'gitfile' and is usually managed via the
+`git submodule` and `git worktree` commands. It is often used for
a working tree of a submodule checkout, to allow you in the
containing superproject to `git checkout` a branch that does not
have the submodule. The `checkout` has to remove the entire
@@ -296,6 +298,7 @@ SEE ALSO
--------
linkgit:git-init[1],
linkgit:git-clone[1],
+linkgit:git-config[1],
linkgit:git-fetch[1],
linkgit:git-pack-refs[1],
linkgit:git-gc[1],
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 941858a6ec..f7b5a25a0c 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -78,7 +78,7 @@ Submodule operations can be configured using the following mechanisms
* The command line for those commands that support taking submodules
as part of their pathspecs. Most commands have a boolean flag
- `--recurse-submodules` which specify whether to recurse into submodules.
+ `--recurse-submodules` which specifies whether to recurse into submodules.
Examples are `grep` and `checkout`.
Some commands take enums, such as `fetch` and `push`, where you can
specify how submodules are affected.
@@ -151,7 +151,7 @@ the superproject's `$GIT_DIR/config` file, so the superproject's history
is not affected. This can be undone using `git submodule init`.
* Deleted submodule: A submodule can be deleted by running
-`git rm <submodule path> && git commit`. This can be undone
+`git rm <submodule-path> && git commit`. This can be undone
using `git revert`.
+
The deletion removes the superproject's tracking data, which are
@@ -192,7 +192,7 @@ For example:
[submodule "baz"]
url = https://example.org/baz
-In the above config only the submodule 'bar' and 'baz' are active,
+In the above config only the submodules 'bar' and 'baz' are active,
'bar' due to (1) and 'baz' due to (3). 'foo' is inactive because
(1) takes precedence over (3)
@@ -229,7 +229,7 @@ Workflow for a third party library
git submodule add <URL> <path>
# Occasionally update the submodule to a new version:
- git -C <path> checkout <new version>
+ git -C <path> checkout <new-version>
git add <path>
git commit -m "update submodule to new version"
@@ -274,7 +274,7 @@ will not be checked out by default; you can instruct `clone` to recurse
into submodules. The `init` and `update` subcommands of `git submodule`
will maintain submodules checked out and at an appropriate revision in
your working tree. Alternatively you can set `submodule.recurse` to have
-`checkout` recursing into submodules (note that `submodule.recurse` also
+`checkout` recurse into submodules (note that `submodule.recurse` also
affects other Git commands, see linkgit:git-config[1] for a complete list).
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index c7cadd8aaf..f89ad30cf6 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -137,10 +137,10 @@ which will automatically notice any modified (but not new) files, add
them to the index, and commit, all in one step.
A note on commit messages: Though not required, it's a good idea to
-begin the commit message with a single short (less than 50 character)
-line summarizing the change, followed by a blank line and then a more
-thorough description. The text up to the first blank line in a commit
-message is treated as the commit title, and that title is used
+begin the commit message with a single short (no more than 50
+characters) line summarizing the change, followed by a blank line and
+then a more thorough description. The text up to the first blank line in
+a commit message is treated as the commit title, and that title is used
throughout Git. For example, linkgit:git-format-patch[1] turns a
commit into email, and it uses the title on the Subject line and the
rest of the commit in the body.
@@ -360,7 +360,7 @@ $ gitk HEAD...FETCH_HEAD
This means "show everything that is reachable from either one, but
exclude anything that is reachable from both of them".
-Please note that these range notation can be used with both `gitk`
+Please note that these range notations can be used with both `gitk`
and `git log`.
After inspecting what Bob did, if there is nothing urgent, Alice may
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index 34b1d6e224..85983587fc 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -53,7 +53,7 @@ following order:
`/etc/gitweb-common.conf`),
* either per-instance configuration file (defaults to 'gitweb_config.perl'
- in the same directory as the installed gitweb), or if it does not exists
+ in the same directory as the installed gitweb), or if it does not exist
then fallback system-wide configuration file (defaults to `/etc/gitweb.conf`).
Values obtained in later configuration files override values obtained earlier
@@ -242,7 +242,7 @@ $mimetypes_file::
$highlight_bin::
Path to the highlight executable to use (it must be the one from
- http://www.andre-simon.de[] due to assumptions about parameters and output).
+ http://andre-simon.de/zip/download.php[] due to assumptions about parameters and output).
By default set to 'highlight'; set it to full path to highlight
executable if it is not installed on your web server's PATH.
Note that 'highlight' feature must be set for gitweb to actually
@@ -343,7 +343,7 @@ $home_link_str::
Label for the "home link" at the top of all pages, leading to `$home_link`
(usually the main gitweb page, which contains the projects list). It is
used as the first component of gitweb's "breadcrumb trail":
- `<home link> / <project> / <action>`. Can be set at build time using
+ `<home-link> / <project> / <action>`. Can be set at build time using
the `GITWEB_HOME_LINK_STR` variable. By default it is set to "projects",
as this link leads to the list of projects. Another popular choice is to
set it to the name of site. Note that it is treated as raw HTML so it
@@ -604,9 +604,9 @@ Many gitweb features can be enabled (or disabled) and configured using the
Each `%feature` hash element is a hash reference and has the following
structure:
----------------------------------------------------------------------
-"<feature_name>" => {
- "sub" => <feature-sub (subroutine)>,
- "override" => <allow-override (boolean)>,
+"<feature-name>" => {
+ "sub" => <feature-sub-(subroutine)>,
+ "override" => <allow-override-(boolean)>,
"default" => [ <options>... ]
},
----------------------------------------------------------------------
@@ -614,7 +614,7 @@ Some features cannot be overridden per project. For those
features the structure of appropriate `%feature` hash element has a simpler
form:
----------------------------------------------------------------------
-"<feature_name>" => {
+"<feature-name>" => {
"override" => 0,
"default" => [ <options>... ]
},
@@ -820,7 +820,7 @@ filesystem (i.e. "$projectroot/$project"), `%h` to the current hash
(\'h' gitweb parameter) and `%b` to the current hash base
(\'hb' gitweb parameter); `%%` expands to \'%'.
+
-For example, at the time this page was written, the http://repo.or.cz[]
+For example, at the time this page was written, the https://repo.or.cz[]
Git hosting site set it to the following to enable graphical log
(using the third party tool *git-browser*):
+
diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt
index af6bf3c45e..5e2b491ec2 100644
--- a/Documentation/gitweb.txt
+++ b/Documentation/gitweb.txt
@@ -8,7 +8,7 @@ gitweb - Git web interface (web frontend to Git repositories)
SYNOPSIS
--------
To get started with gitweb, run linkgit:git-instaweb[1] from a Git repository.
-This would configure and start your web server, and run web browser pointing to
+This will configure and start your web server, and run a web browser pointing to
gitweb.
@@ -20,15 +20,15 @@ Gitweb provides a web interface to Git repositories. Its features include:
* Browsing every revision of the repository.
* Viewing the contents of files in the repository at any revision.
* Viewing the revision log of branches, history of files and directories,
- see what was changed when, by who.
+ seeing what was changed, when, and by whom.
* Viewing the blame/annotation details of any file (if enabled).
* Generating RSS and Atom feeds of commits, for any branch.
The feeds are auto-discoverable in modern web browsers.
-* Viewing everything that was changed in a revision, and step through
+* Viewing everything that was changed in a revision, and stepping through
revisions one at a time, viewing the history of the repository.
-* Finding commits which commit messages matches given search term.
+* Finding commits whose commit messages match a given search term.
-See http://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
+See https://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
browsed using gitweb itself.
@@ -41,9 +41,9 @@ for details.
Repositories
~~~~~~~~~~~~
Gitweb can show information from one or more Git repositories. These
-repositories have to be all on local filesystem, and have to share common
+repositories have to be all on local filesystem, and have to share a common
repository root, i.e. be all under a single parent repository (but see also
-"Advanced web server setup" section, "Webserver configuration with multiple
+the "Advanced web server setup" section, "Webserver configuration with multiple
projects' root" subsection).
-----------------------------------------------------------------------
@@ -51,7 +51,7 @@ our $projectroot = '/path/to/parent/directory';
-----------------------------------------------------------------------
The default value for `$projectroot` is `/pub/git`. You can change it during
-building gitweb via `GITWEB_PROJECTROOT` build configuration variable.
+building gitweb via the `GITWEB_PROJECTROOT` build configuration variable.
By default all Git repositories under `$projectroot` are visible and available
to gitweb. The list of projects is generated by default by scanning the
@@ -66,7 +66,7 @@ found at "$projectroot/$repo".
Projects list file format
~~~~~~~~~~~~~~~~~~~~~~~~~
-Instead of having gitweb find repositories by scanning filesystem
+Instead of having gitweb find repositories by scanning the filesystem
starting from $projectroot, you can provide a pre-generated list of
visible projects by setting `$projects_list` to point to a plain text
file with a list of projects (with some additional info).
@@ -234,7 +234,7 @@ from the template during repository creation, usually installed in
configuration variable, but the file takes precedence.
category (or `gitweb.category`)::
- Singe line category of a project, used to group projects if
+ Single line category of a project, used to group projects if
`$projects_list_group_categories` is enabled. By default (file and
configuration variable absent), uncategorized projects are put in the
`$project_list_default_category` category. You can use the
@@ -305,7 +305,7 @@ pathnames. In most general form such path_info (component) based gitweb URL
looks like this:
-----------------------------------------------------------------------
-.../gitweb.cgi/<repo>/<action>/<revision_from>:/<path_from>..<revision_to>:/<path_to>?<arguments>
+.../gitweb.cgi/<repo>/<action>/<revision-from>:/<path-from>..<revision-to>:/<path-to>?<arguments>
-----------------------------------------------------------------------
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index 5a537268e2..575c18f776 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -98,9 +98,8 @@ to point at the new commit.
revision.
[[def_commit-ish]]commit-ish (also committish)::
- A <<def_commit_object,commit object>> or an
- <<def_object,object>> that can be recursively dereferenced to
- a commit object.
+ A <<def_commit_object,commit object>> or an <<def_object,object>> that
+ can be recursively <<def_dereference,dereferenced>> to a commit object.
The following are all commit-ishes:
a commit object,
a <<def_tag_object,tag object>> that points to a commit
@@ -125,6 +124,25 @@ to point at the new commit.
dangling object has no references to it from any
reference or <<def_object,object>> in the <<def_repository,repository>>.
+[[def_dereference]]dereference::
+ Referring to a <<def_symref,symbolic ref>>: the action of accessing the
+ <<def_ref,reference>> pointed at by a symbolic ref. Recursive
+ dereferencing involves repeating the aforementioned process on the
+ resulting ref until a non-symbolic reference is found.
++
+Referring to a <<def_tag_object,tag object>>: the action of accessing the
+<<def_object,object>> a tag points at. Tags are recursively dereferenced by
+repeating the operation on the result object until the result has either a
+specified <<def_object_type,object type>> (where applicable) or any non-"tag"
+object type. A synonym for "recursive dereference" in the context of tags is
+"<<def_peel,peel>>".
++
+Referring to a <<def_commit_object,commit object>>: the action of accessing
+the commit's tree object. Commits cannot be dereferenced recursively.
++
+Unless otherwise specified, "dereferencing" as it used in the context of Git
+commands or protocols is implicitly recursive.
+
[[def_detached_HEAD]]detached HEAD::
Normally the <<def_HEAD,HEAD>> stores the name of a
<<def_branch,branch>>, and commands that operate on the
@@ -184,9 +202,11 @@ current branch integrates with) obviously do not work, as there is no
[[def_gitfile]]gitfile::
A plain file `.git` at the root of a working tree that
points at the directory that is the real repository.
+ For proper use see linkgit:git-worktree[1] or linkgit:git-submodule[1].
+ For syntax see linkgit:gitrepository-layout[5].
[[def_grafts]]grafts::
- Grafts enables two otherwise different lines of development to be joined
+ Grafts enable two otherwise different lines of development to be joined
together by recording fake ancestry information for commits. This way
you can make Git pretend the set of <<def_parent,parents>> a <<def_commit,commit>> has
is different from what was recorded when the commit was
@@ -294,6 +314,12 @@ This commit is referred to as a "merge commit", or sometimes just a
[[def_octopus]]octopus::
To <<def_merge,merge>> more than two <<def_branch,branches>>.
+[[def_orphan]]orphan::
+ The act of getting on a <<def_branch,branch>> that does not
+ exist yet (i.e., an <<def_unborn,unborn>> branch). After
+ such an operation, the commit first created becomes a commit
+ without a parent, starting a new history.
+
[[def_origin]]origin::
The default upstream <<def_repository,repository>>. Most projects have
at least one upstream project which they track. By default
@@ -444,6 +470,10 @@ exclude;;
of the logical predecessor(s) in the line of development, i.e. its
parents.
+[[def_peel]]peel::
+ The action of recursively <<def_dereference,dereferencing>> a
+ <<def_tag_object,tag object>>.
+
[[def_pickaxe]]pickaxe::
The term <<def_pickaxe,pickaxe>> refers to an option to the diffcore
routines that help select changes that add or delete a given text
@@ -467,20 +497,18 @@ exclude;;
unusual refs.
[[def_pseudoref]]pseudoref::
- Pseudorefs are a class of files under `$GIT_DIR` which behave
- like refs for the purposes of rev-parse, but which are treated
- specially by git. Pseudorefs both have names that are all-caps,
- and always start with a line consisting of a
- <<def_SHA1,SHA-1>> followed by whitespace. So, HEAD is not a
- pseudoref, because it is sometimes a symbolic ref. They might
- optionally contain some additional data. `MERGE_HEAD` and
- `CHERRY_PICK_HEAD` are examples. Unlike
- <<def_per_worktree_ref,per-worktree refs>>, these files cannot
- be symbolic refs, and never have reflogs. They also cannot be
- updated through the normal ref update machinery. Instead,
- they are updated by directly writing to the files. However,
- they can be read as if they were refs, so `git rev-parse
- MERGE_HEAD` will work.
+ A ref that has different semantics than normal refs. These refs can be
+ read via normal Git commands, but cannot be written to by commands like
+ linkgit:git-update-ref[1].
++
+The following pseudorefs are known to Git:
+
+ - `FETCH_HEAD` is written by linkgit:git-fetch[1] or linkgit:git-pull[1]. It
+ may refer to multiple object IDs. Each object ID is annotated with metadata
+ indicating where it was fetched from and its fetch status.
+
+ - `MERGE_HEAD` is written by linkgit:git-merge[1] when resolving merge
+ conflicts. It contains all commit IDs which are being merged.
[[def_pull]]pull::
Pulling a <<def_branch,branch>> means to <<def_fetch,fetch>> it and
@@ -522,20 +550,38 @@ exclude;;
to the result.
[[def_ref]]ref::
- A name that begins with `refs/` (e.g. `refs/heads/master`)
- that points to an <<def_object_name,object name>> or another
- ref (the latter is called a <<def_symref,symbolic ref>>).
+ A name that points to an <<def_object_name,object name>> or
+ another ref (the latter is called a <<def_symref,symbolic ref>>).
For convenience, a ref can sometimes be abbreviated when used
as an argument to a Git command; see linkgit:gitrevisions[7]
for details.
Refs are stored in the <<def_repository,repository>>.
+
The ref namespace is hierarchical.
-Different subhierarchies are used for different purposes (e.g. the
-`refs/heads/` hierarchy is used to represent local branches).
+Ref names must either start with `refs/` or be located in the root of
+the hierarchy. For the latter, their name must follow these rules:
++
+ - The name consists of only upper-case characters or underscores.
+
+ - The name ends with "`_HEAD`" or is equal to "`HEAD`".
++
+There are some irregular refs in the root of the hierarchy that do not
+match these rules. The following list is exhaustive and shall not be
+extended in the future:
++
+ - `AUTO_MERGE`
+
+ - `BISECT_EXPECTED_REV`
+
+ - `NOTES_MERGE_PARTIAL`
+
+ - `NOTES_MERGE_REF`
+
+ - `MERGE_AUTOSTASH`
+
-There are a few special-purpose refs that do not begin with `refs/`.
-The most notable example is `HEAD`.
+Different subhierarchies are used for different purposes. For example,
+the `refs/heads/` hierarchy is used to represent local branches whereas
+the `refs/tags/` hierarchy is used to represent local tags..
[[def_reflog]]reflog::
A reflog shows the local "history" of a ref. In other words,
@@ -546,7 +592,8 @@ The most notable example is `HEAD`.
[[def_refspec]]refspec::
A "refspec" is used by <<def_fetch,fetch>> and
<<def_push,push>> to describe the mapping between remote
- <<def_ref,ref>> and local ref.
+ <<def_ref,ref>> and local ref. See linkgit:git-fetch[1] or
+ linkgit:git-push[1] for details.
[[def_remote]]remote repository::
A <<def_repository,repository>> which is used to track the same
@@ -620,12 +667,11 @@ The most notable example is `HEAD`.
copies of) commit objects of the contained submodules.
[[def_symref]]symref::
- Symbolic reference: instead of containing the <<def_SHA1,SHA-1>>
- id itself, it is of the format 'ref: refs/some/thing' and when
- referenced, it recursively dereferences to this reference.
- '<<def_HEAD,HEAD>>' is a prime example of a symref. Symbolic
- references are manipulated with the linkgit:git-symbolic-ref[1]
- command.
+ Symbolic reference: instead of containing the <<def_SHA1,SHA-1>> id
+ itself, it is of the format 'ref: refs/some/thing' and when referenced,
+ it recursively <<def_dereference,dereferences>> to this reference.
+ '<<def_HEAD,HEAD>>' is a prime example of a symref. Symbolic references
+ are manipulated with the linkgit:git-symbolic-ref[1] command.
[[def_tag]]tag::
A <<def_ref,ref>> under `refs/tags/` namespace that points to an
@@ -650,6 +696,11 @@ The most notable example is `HEAD`.
that each contain very well defined concepts or small incremental yet
related changes.
+[[def_trailer]]trailer::
+ Key-value metadata. Trailers are optionally found at the end of
+ a commit message. Might be called "footers" or "tags" in other
+ communities. See linkgit:git-interpret-trailers[1].
+
[[def_tree]]tree::
Either a <<def_working_tree,working tree>>, or a <<def_tree_object,tree
object>> together with the dependent <<def_blob_object,blob>> and tree objects
@@ -661,11 +712,11 @@ The most notable example is `HEAD`.
<<def_tree,tree>> is equivalent to a <<def_directory,directory>>.
[[def_tree-ish]]tree-ish (also treeish)::
- A <<def_tree_object,tree object>> or an <<def_object,object>>
- that can be recursively dereferenced to a tree object.
- Dereferencing a <<def_commit_object,commit object>> yields the
- tree object corresponding to the <<def_revision,revision>>'s
- top <<def_directory,directory>>.
+ A <<def_tree_object,tree object>> or an <<def_object,object>> that can
+ be recursively <<def_dereference,dereferenced>> to a tree object.
+ Dereferencing a <<def_commit_object,commit object>> yields the tree
+ object corresponding to the <<def_revision,revision>>'s top
+ <<def_directory,directory>>.
The following are all tree-ishes:
a <<def_commit-ish,commit-ish>>,
a tree object,
@@ -674,6 +725,18 @@ The most notable example is `HEAD`.
object,
etc.
+[[def_unborn]]unborn::
+ The <<def_HEAD,HEAD>> can point at a <<def_branch,branch>>
+ that does not yet exist and that does not have any commit on
+ it yet, and such a branch is called an unborn branch. The
+ most typical way users encounter an unborn branch is by
+ creating a repository anew without cloning from elsewhere.
+ The HEAD would point at the 'main' (or 'master', depending
+ on your configuration) branch that is yet to be born. Also
+ some operations can get you on an unborn branch with their
+ <<def_orphan,orphan>> option.
+
+
[[def_unmerged_index]]unmerged index::
An <<def_index,index>> which contains unmerged
<<def_index_entry,index entries>>.
diff --git a/Documentation/howto/coordinate-embargoed-releases.txt b/Documentation/howto/coordinate-embargoed-releases.txt
index e653775bab..b9cb95e82f 100644
--- a/Documentation/howto/coordinate-embargoed-releases.txt
+++ b/Documentation/howto/coordinate-embargoed-releases.txt
@@ -145,7 +145,7 @@ Opening a Security Advisory draft
The first step is to https://github.com/git/git/security/advisories/new[open
an advisory]. Technically, this is not necessary. However, it is the most
-convenient way to obtain the CVE number and it give us a private repository
+convenient way to obtain the CVE number and it gives us a private repository
associated with it that can be used to collaborate on a fix.
Notifying the Linux distributions
diff --git a/Documentation/howto/keep-canonical-history-correct.txt b/Documentation/howto/keep-canonical-history-correct.txt
index 35d48ef714..e98f03275e 100644
--- a/Documentation/howto/keep-canonical-history-correct.txt
+++ b/Documentation/howto/keep-canonical-history-correct.txt
@@ -13,7 +13,7 @@ that appears to be "backwards" from what other project developers
expect. This howto presents a suggested integration workflow for
maintaining a central repository.
-Suppose that that central repository has this history:
+Suppose that the central repository has this history:
------------
---o---o---A
@@ -213,4 +213,4 @@ The procedure will result in a history that looks like this:
B0--B1---------B2
------------
-See also http://git-blame.blogspot.com/2013/09/fun-with-first-parent-history.html
+See also https://git-blame.blogspot.com/2013/09/fun-with-first-parent-history.html
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index d07c6d44e5..45e2599c5d 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -37,22 +37,20 @@ The Policy
The policy on Integration is informally mentioned in "A Note
from the maintainer" message, which is periodically posted to
-this mailing list after each feature release is made.
+the mailing list after each feature release is made:
- Feature releases are numbered as vX.Y.0 and are meant to
contain bugfixes and enhancements in any area, including
functionality, performance and usability, without regression.
- - One release cycle for a feature release is expected to last for
- eight to ten weeks.
-
- - Maintenance releases are numbered as vX.Y.Z and are meant
+ - Maintenance releases are numbered as vX.Y.Z (0 < Z) and are meant
to contain only bugfixes for the corresponding vX.Y.0 feature
release and earlier maintenance releases vX.Y.W (W < Z).
- - 'master' branch is used to prepare for the next feature
+ - The 'master' branch is used to prepare for the next feature
release. In other words, at some point, the tip of 'master'
- branch is tagged with vX.Y.0.
+ branch is tagged as vX.(Y+1).0, when vX.Y.0 is the latest
+ feature release.
- 'maint' branch is used to prepare for the next maintenance
release. After the feature release vX.Y.0 is made, the tip
@@ -63,11 +61,28 @@ this mailing list after each feature release is made.
- 'next' branch is used to publish changes (both enhancements
and fixes) that (1) have worthwhile goal, (2) are in a fairly
good shape suitable for everyday use, (3) but have not yet
- demonstrated to be regression free. New changes are tested
- in 'next' before merged to 'master'.
+ demonstrated to be regression free. Reviews from contributors on
+ the mailing list help to make the determination. After a topic
+ is merged to 'next', it is tested for at least 7 calendar days
+ before getting merged to 'master'.
- 'seen' branch is used to publish other proposed changes that do
- not yet pass the criteria set for 'next'.
+ not yet pass the criteria set for 'next' (see above), but there
+ is no promise that 'seen' will contain everything. A topic that
+ had no reviewer reaction may not be picked up.
+
+ - A new topic will first get merged to 'seen', unless it is
+ trivially correct and clearly urgent, in which case it may be
+ directly merged to 'next' or even to 'master'.
+
+ - If a topic that was picked up to 'seen' becomes and stays
+ inactive for 3 calendar weeks without having seen a clear
+ consensus that it is good enough to be moved to 'next', the
+ topic may be discarded from 'seen'. Interested parties are
+ still free to revive the topic. For the purpose of this
+ guideline, the definition of being "inactive" is that nobody
+ has discussed the topic, no new iteration of the topic was
+ posted, and no responses to the review comments were given.
- The tips of 'master' and 'maint' branches will not be rewound to
allow people to build their own customization on top of them.
@@ -86,10 +101,49 @@ this mailing list after each feature release is made.
users are encouraged to test it so that regressions and bugs
are found before new topics are merged to 'master'.
+ - When a problem is found in a topic in 'next', the topic is marked
+ not to be merged to 'master'. Follow-up patches are discussed on
+ the mailing list and applied to the topic after being reviewed and
+ then the topic is merged (again) to 'next'. After going through
+ the usual testing in 'next', the entire (fixed) topic is merged
+ to 'master'.
+
+ - One release cycle for a feature release is expected to last for
+ eight to ten weeks. A few "release candidate" releases are
+ expected to be tagged about a week apart before the final
+ release, and a "preview" release is tagged about a week before
+ the first release candidate gets tagged.
+
+ - After the preview release is tagged, topics that were well
+ reviewed may be merged to 'master' before spending the usual 7
+ calendar days in 'next', with the expectation that any bugs in
+ them can be caught and fixed in the release candidates before
+ the final release.
+
+ - After the first release candidate is tagged, the contributors are
+ strongly encouraged to focus on finding and fixing new regressions
+ introduced during the cycle, over addressing old bugs and any new
+ features. Topics stop getting merged down from 'next' to 'master',
+ and new topics stop getting merged to 'next'. Unless they are fixes
+ to new regressions in the cycle, that is.
+
+ - Soon after a feature release is made, the tip of 'maint' gets
+ fast-forwarded to point at the release. Topics that have been
+ kept in 'next' are merged down to 'master' and a new development
+ cycle starts.
+
+
Note that before v1.9.0 release, the version numbers used to be
structured slightly differently. vX.Y.Z were feature releases while
vX.Y.Z.W were maintenance releases for vX.Y.Z.
+Because most of the lines of code in Git are written by individual
+contributors, and contributions come in the form of e-mailed patches
+published on the mailing list, the project maintains a mapping from
+individual commits to the Message-Id of the e-mail that resulted in
+the commit, to help tracking the origin of the changes. The notes
+in "refs/notes/amlog" are used for this purpose, and are published
+along with the broken-out branches to the maintainer's repository.
A Typical Git Day
-----------------
@@ -104,7 +158,7 @@ by doing the following:
files in mbox format).
- Write his own patches to address issues raised on the list but
- nobody has stepped up solving. Send it out just like other
+ nobody has stepped up to solve. Send it out just like other
contributors do, and pick them up just like patches from other
contributors (see above).
@@ -133,6 +187,43 @@ by doing the following:
In practice, almost no patch directly goes to 'master' or
'maint'.
+ Applying the e-mailed patches using "git am" automatically records
+ the mappings from 'Message-Id' to the applied commit in the "amlog"
+ notes. Periodically check that this is working with "git show -s
+ --notes=amlog $commit".
+
+ This mapping is maintained with the aid of the "post-applypatch"
+ hook found in the 'todo' branch. That hook should be installed
+ before applying patches. It is also helpful to carry forward any
+ relevant amlog entries when rebasing, so the following config may
+ be useful:
+
+ [notes]
+ rewriteRef = refs/notes/amlog
+
+ Avoid "cherry-pick", as it does not propagate notes by design. Use
+ either "git commit --amend" or "git rebase" to make corrections to
+ an existing commit, even for a single-patch topic.
+
+ Make sure that a push refspec for 'refs/notes/amlog' is in the
+ remote configuration for publishing repositories. A few sample
+ configurations look like the following:
+
+ [remote "github"]
+ url = https://github.com/gitster/git
+ pushurl = github.com:gitster/git.git
+ mirror
+
+ [remote "github2"]
+ url = https://github.com/git/git
+ fetch = +refs/heads/*:refs/remotes/github2/*
+ pushurl = github.com:git/git.git
+ push = refs/heads/maint:refs/heads/maint
+ push = refs/heads/master:refs/heads/master
+ push = refs/heads/next:refs/heads/next
+ push = +refs/heads/seen:refs/heads/seen
+ push = +refs/notes/amlog
+
- Review the last issue of "What's cooking" message, review the
topics ready for merging (topic->master and topic->maint). Use
"Meta/cook -w" script (where Meta/ contains a checkout of the
@@ -149,6 +240,10 @@ by doing the following:
$ git diff ORIG_HEAD.. ;# final review
$ make test ;# final review
+ If the tip of 'master' is updated, also generate the preformatted
+ documentation and push the out result to git-htmldocs and
+ git-manpages repositories.
+
- Handle the remaining patches:
- Anything unobvious that is applicable to 'master' (in other
@@ -179,12 +274,12 @@ by doing the following:
The initial round is done with:
$ git checkout ai/topic ;# or "git checkout -b ai/topic master"
- $ git am -sc3 mailbox
+ $ git am -sc3 --whitespace=warn mailbox
and replacing an existing topic with subsequent round is done with:
$ git checkout master...ai/topic ;# try to reapply to the same base
- $ git am -sc3 mailbox
+ $ git am -sc3 --whitespace=warn mailbox
to prepare the new round on a detached HEAD, and then
@@ -209,39 +304,59 @@ by doing the following:
(trivial typofixes etc. are often squashed directly into the
patches that need fixing, without being applied as a separate
"SQUASH???" commit), so that they can be removed easily as needed.
+ The expectation is that the original author will make corrections
+ in a reroll.
+ - By now, new topic branches are created and existing topic
+ branches are updated. The integration branches 'next', 'jch',
+ and 'seen' need to be updated to contain them.
- - Merge maint to master as needed:
+ - If there are topics that have been merged to 'master' and should
+ be merged to 'maint', merge them to 'maint', and update the
+ release notes to the next maintenance release.
- $ git checkout master
- $ git merge maint
- $ make test
+ - Review the latest issue of "What's cooking" again. Are topics
+ that have been sufficiently long in 'next' ready to be merged to
+ 'master'? Are topics we saw earlier and are in 'seen' now got
+ positive reviews and are ready to be merged to 'next'?
- - Merge master to next as needed:
+ - If there are topics that have been cooking in 'next' long enough
+ and should be merged to 'master', merge them to 'master', and
+ update the release notes to the next feature release.
- $ git checkout next
- $ git merge master
- $ make test
+ - If there were patches directly made on 'maint', merge 'maint' to
+ 'master'; make sure that the result is what you want.
- - Review the last issue of "What's cooking" again and see if topics
- that are ready to be merged to 'next' are still in good shape
- (e.g. has there any new issue identified on the list with the
- series?)
+ $ git checkout master
+ $ git merge -m "Sync with 'maint'" --no-log maint
+ $ git log -p --first-parent ORIG_HEAD..
+ $ make test
- - Prepare 'jch' branch, which is used to represent somewhere
- between 'master' and 'seen' and often is slightly ahead of 'next'.
+ - Prepare to update the 'jch' branch, which is used to represent
+ somewhere between 'master' and 'seen' and often is slightly ahead
+ of 'next', and the 'seen' branch, which is used to hold the rest.
$ Meta/Reintegrate master..jch >Meta/redo-jch.sh
The result is a script that lists topics to be merged in order to
- rebuild 'seen' as the input to Meta/Reintegrate script. Remove
- later topics that should not be in 'jch' yet. Add a line that
- consists of '### match next' before the name of the first topic
- in the output that should be in 'jch' but not in 'next' yet.
+ rebuild the current 'jch'. Do the same for 'seen'.
+
+ - Review the Meta/redo-jch.sh and Meta/redo-seen.sh scripts. The
+ former should have a line '### match next'---the idea is that
+ merging the topics listed before the line on top of 'master'
+ should result in a tree identical to that of 'next'.
- - Now we are ready to start merging topics to 'next'. For each
- branch whose tip is not merged to 'next', one of three things can
- happen:
+ - As newly created topics are usually merged near the tip of
+ 'seen', add them to the end of the Meta/redo-seen.sh script.
+ Among the topics that were in 'seen', there may be ones that
+ are not quite ready for 'next' but are getting there. Move
+ them from Meta/redo-seen.sh to the end of Meta/redo-jch.sh.
+ The expectation is that you'd use 'jch' as your daily driver
+ as the first guinea pig, so you should choose carefully.
+
+ - Now we are ready to start rebuilding 'jch' and merging topics to
+ 'next'. For each branch whose tip is not merged to 'next', one
+ of three things can happen:
- The commits are all next-worthy; merge the topic to next;
- The new parts are of mixed quality, but earlier ones are
@@ -252,10 +367,12 @@ by doing the following:
If a topic that was already in 'next' gained a patch, the script
would list it as "ai/topic~1". To include the new patch to the
updated 'next', drop the "~1" part; to keep it excluded, do not
- touch the line. If a topic that was not in 'next' should be
- merged to 'next', add it at the end of the list. Then:
+ touch the line.
+
+ If a topic that was not in 'next' should be merged to 'next', add
+ it before the '### match next' line. Then:
- $ git checkout -B jch master
+ $ git checkout --detach master
$ sh Meta/redo-jch.sh -c1
to rebuild the 'jch' branch from scratch. "-c1" tells the script
@@ -267,26 +384,29 @@ by doing the following:
reference to the variable under its old name), in which case
prepare an appropriate merge-fix first (see appendix), and
rebuild the 'jch' branch from scratch, starting at the tip of
- 'master'.
+ 'master', this time without using "-c1" to merge all topics.
- Then do the same to 'next'
+ Then do the same to 'next'.
$ git checkout next
$ sh Meta/redo-jch.sh -c1 -e
The "-e" option allows the merge message that comes from the
history of the topic and the comments in the "What's cooking" to
- be edited. The resulting tree should match 'jch' as the same set
- of topics are merged on 'master'; otherwise there is a mismerge.
- Investigate why and do not proceed until the mismerge is found
- and rectified.
+ be edited. The resulting tree should match 'jch^{/^### match next'}'
+ as the same set of topics are merged on 'master'; otherwise there
+ is a mismerge. Investigate why and do not proceed until the mismerge
+ is found and rectified.
+
+ If 'master' was updated before you started redoing 'next', then
- $ git diff jch next
+ $ git diff 'jch^{/^### match next}' next
- Then build the rest of 'jch':
+ would show differences that went into 'master' (which 'jch' has,
+ but 'next' does not yet---often it is updates to the release
+ notes). Merge 'master' back to 'next' if that is the case.
- $ git checkout jch
- $ sh Meta/redo-jch.sh
+ $ git merge -m "Sync with 'master'" --no-log master
When all is well, clean up the redo-jch.sh script with
@@ -296,12 +416,7 @@ by doing the following:
merged to 'master'. This may lose '### match next' marker;
add it again to the appropriate place when it happens.
- - Rebuild 'seen'.
-
- $ Meta/Reintegrate jch..seen >Meta/redo-seen.sh
-
- Edit the result by adding new topics that are not still in 'seen'
- in the script. Then
+ - Rebuild 'seen' on top of 'jch'.
$ git checkout -B seen jch
$ sh Meta/redo-seen.sh
@@ -312,7 +427,7 @@ by doing the following:
Double check by running
- $ git branch --no-merged seen
+ $ git branch --no-merged seen '??/*'
to see there is no unexpected leftover topics.
@@ -411,13 +526,13 @@ Preparing a "merge-fix"
A merge of two topics may not textually conflict but still have
conflict at the semantic level. A classic example is for one topic
-to rename an variable and all its uses, while another topic adds a
+to rename a variable and all its uses, while another topic adds a
new use of the variable under its old name. When these two topics
are merged together, the reference to the variable newly added by
the latter topic will still use the old name in the result.
The Meta/Reintegrate script that is used by redo-jch and redo-seen
-scripts implements a crude but usable way to work this issue around.
+scripts implements a crude but usable way to work around this issue.
When the script merges branch $X, it checks if "refs/merge-fix/$X"
exists, and if so, the effect of it is squashed into the result of
the mechanical merge. In other words,
diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt
index 151ee84ceb..4e727deedd 100644
--- a/Documentation/howto/update-hook-example.txt
+++ b/Documentation/howto/update-hook-example.txt
@@ -100,7 +100,7 @@ info "The user is: '$username'"
if test -f "$allowed_users_file"
then
- rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
+ rc=$(grep -Ev '^(#|$)' $allowed_users_file |
while read heads user_patterns
do
# does this rule apply to us?
@@ -138,7 +138,7 @@ info "'$groups'"
if test -f "$allowed_groups_file"
then
- rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
+ rc=$(grep -Ev '^(#|$)' $allowed_groups_file |
while read heads group_patterns
do
# does this rule apply to us?
diff --git a/Documentation/howto/use-git-daemon.txt b/Documentation/howto/use-git-daemon.txt
index 7af2e52cf3..2cad9b3ca5 100644
--- a/Documentation/howto/use-git-daemon.txt
+++ b/Documentation/howto/use-git-daemon.txt
@@ -4,7 +4,7 @@ How to use git-daemon
=====================
Git can be run in inetd mode and in stand alone mode. But all you want is
-let a coworker pull from you, and therefore need to set up a Git server
+to let a coworker pull from you, and therefore need to set up a Git server
real quick, right?
Note that git-daemon is not really chatty at the moment, especially when
diff --git a/Documentation/howto/using-merge-subtree.txt b/Documentation/howto/using-merge-subtree.txt
index a499a94ac2..3bd581ac35 100644
--- a/Documentation/howto/using-merge-subtree.txt
+++ b/Documentation/howto/using-merge-subtree.txt
@@ -11,7 +11,7 @@ Message-ID: <BAYC1-PASMTP12374B54BA370A1E1C6E78AE4E0@CEZ.ICE>
How to use the subtree merge strategy
=====================================
-There are situations where you want to include contents in your project
+There are situations where you want to include content in your project
from an independently developed project. You can just pull from the
other project as long as there are no conflicting paths.
diff --git a/Documentation/i18n.txt b/Documentation/i18n.txt
index 6c6baeeeb7..3a866af4a4 100644
--- a/Documentation/i18n.txt
+++ b/Documentation/i18n.txt
@@ -34,7 +34,7 @@ project find it more convenient to use legacy encodings, Git
does not forbid it. However, there are a few things to keep in
mind.
-. 'git commit' and 'git commit-tree' issues
+. 'git commit' and 'git commit-tree' issue
a warning if the commit log message given to it does not look
like a valid UTF-8 string, unless you explicitly say your
project uses a legacy encoding. The way to say this is to
@@ -46,7 +46,7 @@ mind.
------------
+
Commit objects created with the above setting record the value
-of `i18n.commitEncoding` in its `encoding` header. This is to
+of `i18n.commitEncoding` in their `encoding` header. This is to
help other people who look at them later. Lack of this header
implies that the commit log message is encoded in UTF-8.
diff --git a/Documentation/lint-manpages.sh b/Documentation/lint-manpages.sh
new file mode 100755
index 0000000000..92cfc0a15a
--- /dev/null
+++ b/Documentation/lint-manpages.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+extract_variable () {
+ (
+ cat ../Makefile
+ cat <<EOF
+print_variable:
+ @\$(foreach b,\$($1),echo XXX \$(b:\$X=) YYY;)
+EOF
+ ) |
+ make -C .. -f - print_variable 2>/dev/null |
+ sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p'
+}
+
+check_missing_docs () (
+ ret=0
+
+ for v in $ALL_COMMANDS
+ do
+ case "$v" in
+ git-merge-octopus) continue;;
+ git-merge-ours) continue;;
+ git-merge-recursive) continue;;
+ git-merge-resolve) continue;;
+ git-merge-subtree) continue;;
+ git-fsck-objects) continue;;
+ git-init-db) continue;;
+ git-remote-*) continue;;
+ git-stage) continue;;
+ git-legacy-*) continue;;
+ git-?*--?* ) continue ;;
+ esac
+
+ if ! test -f "$v.txt"
+ then
+ echo "no doc: $v"
+ ret=1
+ fi
+
+ if ! sed -e '1,/^### command list/d' -e '/^#/d' ../command-list.txt |
+ grep -q "^$v[ ]"
+ then
+ case "$v" in
+ git)
+ ;;
+ *)
+ echo "no link: $v"
+ ret=1
+ ;;
+ esac
+ fi
+ done
+
+ exit $ret
+)
+
+check_extraneous_docs () {
+ (
+ sed -e '1,/^### command list/d' \
+ -e '/^#/d' \
+ -e '/guide$/d' \
+ -e '/interfaces$/d' \
+ -e 's/[ ].*//' \
+ -e 's/^/listed /' ../command-list.txt
+ make print-man1 |
+ grep '\.txt$' |
+ sed -e 's|^|documented |' \
+ -e 's/\.txt//'
+ ) | (
+ all_commands="$(printf "%s " "$ALL_COMMANDS" "$BUILT_INS" "$EXCLUDED_PROGRAMS" | tr '\n' ' ')"
+ ret=0
+
+ while read how cmd
+ do
+ case " $all_commands " in
+ *" $cmd "*) ;;
+ *)
+ echo "removed but $how: $cmd"
+ ret=1;;
+ esac
+ done
+
+ exit $ret
+ )
+}
+
+BUILT_INS="$(extract_variable BUILT_INS)"
+ALL_COMMANDS="$(extract_variable ALL_COMMANDS)"
+EXCLUDED_PROGRAMS="$(extract_variable EXCLUDED_PROGRAMS)"
+
+findings=$(
+ if ! check_missing_docs
+ then
+ ret=1
+ fi
+
+ if ! check_extraneous_docs
+ then
+ ret=1
+ fi
+
+ exit $ret
+)
+ret=$?
+
+printf "%s" "$findings" | sort
+
+exit $ret
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index d8f7cd7ca0..3eaefc4e94 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -191,7 +191,7 @@ endif::git-pull[]
--autostash::
--no-autostash::
Automatically create a temporary stash entry before the operation
- begins, record it in the special ref `MERGE_AUTOSTASH`
+ begins, record it in the ref `MERGE_AUTOSTASH`
and apply it after the operation ends. This means
that you can run the operation on a dirty worktree. However, use
with care: the final stash application after a successful
diff --git a/Documentation/mergetools/vimdiff.txt b/Documentation/mergetools/vimdiff.txt
index 2d631e9b1f..befa86d692 100644
--- a/Documentation/mergetools/vimdiff.txt
+++ b/Documentation/mergetools/vimdiff.txt
@@ -32,10 +32,10 @@ have special meaning:
- `+` is used to "open a new tab"
- `,` is used to "open a new vertical split"
- `/` is used to "open a new horizontal split"
- - `@` is used to indicate which is the file containing the final version after
+ - `@` is used to indicate the file containing the final version after
solving the conflicts. If not present, `MERGED` will be used by default.
-The precedence of the operators is this one (you can use parentheses to change
+The precedence of the operators is as follows (you can use parentheses to change
it):
`@` > `+` > `/` > `,`
@@ -162,7 +162,7 @@ information as the first tab, with a different layout.
| REMOTE | |
---------------------------------------------
....
-Note how in the third tab definition we need to use parenthesis to make `,`
+Note how in the third tab definition we need to use parentheses to make `,`
have precedence over `/`.
--
@@ -177,7 +177,8 @@ Instead of `--tool=vimdiff`, you can also use one of these other variants:
When using these variants, in order to specify a custom layout you will have to
set configuration variables `mergetool.gvimdiff.layout` and
-`mergetool.nvimdiff.layout` instead of `mergetool.vimdiff.layout`
+`mergetool.nvimdiff.layout` instead of `mergetool.vimdiff.layout` (though the
+latter will be used as fallback if the variant-specific one is not set).
In addition, for backwards compatibility with previous Git versions, you can
also append `1`, `2` or `3` to either `vimdiff` or any of the variants (ex:
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 3b71334459..8ee940b6a4 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -122,7 +122,9 @@ The placeholders are:
- Placeholders that expand to a single literal character:
'%n':: newline
'%%':: a raw '%'
-'%x00':: print a byte from a hex code
+'%x00':: '%x' followed by two hexadecimal digits is replaced with a
+ byte with the hexadecimal digits' value (we will call this
+ "literal formatting code" in the rest of this document).
- Placeholders that affect formatting of later placeholders:
'%Cred':: switch color to red
@@ -222,13 +224,30 @@ The placeholders are:
linkgit:git-rev-list[1])
'%d':: ref names, like the --decorate option of linkgit:git-log[1]
'%D':: ref names without the " (", ")" wrapping.
-'%(describe[:options])':: human-readable name, like
- linkgit:git-describe[1]; empty string for
- undescribable commits. The `describe` string
- may be followed by a colon and zero or more
- comma-separated options. Descriptions can be
- inconsistent when tags are added or removed at
- the same time.
+'%(decorate[:<options>])'::
+ref names with custom decorations. The `decorate` string may be followed by a
+colon and zero or more comma-separated options. Option values may contain
+literal formatting codes. These must be used for commas (`%x2C`) and closing
+parentheses (`%x29`), due to their role in the option syntax.
++
+** 'prefix=<value>': Shown before the list of ref names. Defaults to "{nbsp}`(`".
+** 'suffix=<value>': Shown after the list of ref names. Defaults to "`)`".
+** 'separator=<value>': Shown between ref names. Defaults to "`,`{nbsp}".
+** 'pointer=<value>': Shown between HEAD and the branch it points to, if any.
+ Defaults to "{nbsp}`->`{nbsp}".
+** 'tag=<value>': Shown before tag names. Defaults to "`tag:`{nbsp}".
+
++
+For example, to produce decorations with no wrapping
+or tag annotations, and spaces as separators:
++
+`%(decorate:prefix=,suffix=,tag=,separator= )`
+
+'%(describe[:<options>])'::
+human-readable name, like linkgit:git-describe[1]; empty string for
+undescribable commits. The `describe` string may be followed by a colon and
+zero or more comma-separated options. Descriptions can be inconsistent when
+tags are added or removed at the same time.
+
** 'tags[=<bool-value>]': Instead of only considering annotated tags,
consider lightweight tags as well.
@@ -281,13 +300,11 @@ endif::git-rev-list[]
'%gE':: reflog identity email (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%gs':: reflog subject
-'%(trailers[:options])':: display the trailers of the body as
- interpreted by
- linkgit:git-interpret-trailers[1]. The
- `trailers` string may be followed by a colon
- and zero or more comma-separated options.
- If any option is provided multiple times the
- last occurrence wins.
+'%(trailers[:<options>])'::
+display the trailers of the body as interpreted by
+linkgit:git-interpret-trailers[1]. The `trailers` string may be followed by
+a colon and zero or more comma-separated options. If any option is provided
+multiple times, the last occurrence wins.
+
** 'key=<key>': only show trailers with specified <key>. Matching is done
case-insensitively and trailing colon is optional. If option is
@@ -299,9 +316,8 @@ endif::git-rev-list[]
`Reviewed-by`.
** 'only[=<bool>]': select whether non-trailer lines from the trailer
block should be included.
-** 'separator=<sep>': specify a separator inserted between trailer
- lines. When this option is not given each trailer line is
- terminated with a line feed character. The string <sep> may contain
+** 'separator=<sep>': specify the separator inserted between trailer
+ lines. Defaults to a line feed character. The string <sep> may contain
the literal formatting codes described above. To use comma as
separator one must use `%x2C` as it would otherwise be parsed as
next option. E.g., `%(trailers:key=Ticket,separator=%x2C )`
@@ -312,10 +328,9 @@ endif::git-rev-list[]
`%(trailers:only,unfold=true)` unfolds and shows all trailer lines.
** 'keyonly[=<bool>]': only show the key part of the trailer.
** 'valueonly[=<bool>]': only show the value part of the trailer.
-** 'key_value_separator=<sep>': specify a separator inserted between
- trailer lines. When this option is not given each trailer key-value
- pair is separated by ": ". Otherwise it shares the same semantics
- as 'separator=<sep>' above.
+** 'key_value_separator=<sep>': specify the separator inserted between
+ the key and value of each trailer. Defaults to ": ". Otherwise it
+ shares the same semantics as 'separator=<sep>' above.
NOTE: Some placeholders may depend on other options given to the
revision traversal engine. For example, the `%g*` reflog options will
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index dc685be363..23888cd612 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -48,7 +48,7 @@ people using 80-column terminals.
--expand-tabs::
--no-expand-tabs::
Perform a tab expansion (replace each tab with enough spaces
- to fill to the next display column that is multiple of '<n>')
+ to fill to the next display column that is a multiple of '<n>')
in the log message before showing it in the output.
`--expand-tabs` is a short-hand for `--expand-tabs=8`, and
`--no-expand-tabs` is a short-hand for `--expand-tabs=0`,
@@ -73,7 +73,7 @@ environment overrides). See linkgit:git-config[1] for more details.
With an optional '<ref>' argument, use the ref to find the notes
to display. The ref can specify the full refname when it begins
with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
-`refs/notes/` is prefixed to form a full name of the ref.
+`refs/notes/` is prefixed to form the full name of the ref.
+
Multiple --notes options can be combined to control which notes are
being displayed. Examples: "--notes=foo" will show only notes from
@@ -87,6 +87,10 @@ being displayed. Examples: "--notes=foo" will show only notes from
"--notes --notes=foo --no-notes --notes=bar" will only show notes
from "refs/notes/bar".
+--show-notes-by-default::
+ Show the default notes unless options for displaying specific
+ notes are given.
+
--show-notes[=<ref>]::
--[no-]standard-notes::
These options are deprecated. Use the above --notes/--no-notes
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index 95a7390b2c..d79d2f6065 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -25,14 +25,15 @@ endif::git-pull[]
+
The format of a <refspec> parameter is an optional plus
`+`, followed by the source <src>, followed
-by a colon `:`, followed by the destination ref <dst>.
+by a colon `:`, followed by the destination <dst>.
The colon can be omitted when <dst> is empty. <src> is
-typically a ref, but it can also be a fully spelled hex object
+typically a ref, or a glob pattern with a single `*` that is used
+to match a set of refs, but it can also be a fully spelled hex object
name.
+
A <refspec> may contain a `*` in its <src> to indicate a simple pattern
match. Such a refspec functions like a glob that matches any ref with the
-same prefix. A pattern <refspec> must have a `*` in both the <src> and
+pattern. A pattern <refspec> must have one and only one `*` in both the <src> and
<dst>. It will map refs to the destination by replacing the `*` with the
contents matched from the source.
+
@@ -71,7 +72,7 @@ refspec (or `--force`).
Unlike when pushing with linkgit:git-push[1], any updates outside of
`refs/{tags,heads}/*` will be accepted without `+` in the refspec (or
`--force`), whether that's swapping e.g. a tree object for a blob, or
-a commit for another commit that's doesn't have the previous commit as
+a commit for another commit that doesn't have the previous commit as
an ancestor etc.
+
Unlike when pushing with linkgit:git-push[1], there is no
@@ -80,7 +81,7 @@ configuration which'll amend these rules, and nothing like a
+
As with pushing with linkgit:git-push[1], all of the rules described
above about what's not allowed as an update can be overridden by
-adding an the optional leading `+` to a refspec (or using `--force`
+adding an optional leading `+` to a refspec (or using the `--force`
command line option). The only exception to this is that no amount of
forcing will make the `refs/heads/*` namespace accept a non-commit
object.
@@ -88,7 +89,7 @@ object.
[NOTE]
When the remote branch you want to fetch is known to
be rewound and rebased regularly, it is expected that
-its new tip will not be descendant of its previous tip
+its new tip will not be a descendant of its previous tip
(as stored in your remote-tracking branch the last time
you fetched). You would want
to use the `+` sign to indicate non-fast-forward updates
diff --git a/Documentation/ref-storage-format.txt b/Documentation/ref-storage-format.txt
new file mode 100644
index 0000000000..14fff8a9c6
--- /dev/null
+++ b/Documentation/ref-storage-format.txt
@@ -0,0 +1,3 @@
+* `files` for loose files with packed-refs. This is the default.
+* `reftable` for the reftable format. This format is experimental and its
+ internals are subject to change.
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index a4a0cb93b2..00ccf68744 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -56,7 +56,7 @@ endif::git-rev-list[]
error to use this option unless `--walk-reflogs` is in use.
--grep=<pattern>::
- Limit the commits output to ones with log message that
+ Limit the commits output to ones with a log message that
matches the specified pattern (regular expression). With
more than one `--grep=<pattern>`, commits whose message
matches any of the given patterns are chosen (but see
@@ -72,7 +72,7 @@ endif::git-rev-list[]
instead of ones that match at least one.
--invert-grep::
- Limit the commits output to ones with log message that do not
+ Limit the commits output to ones with a log message that do not
match the pattern specified with `--grep=<pattern>`.
-i::
@@ -151,6 +151,10 @@ endif::git-log[]
--not::
Reverses the meaning of the '{caret}' prefix (or lack thereof)
for all following revision specifiers, up to the next `--not`.
+ When used on the command line before --stdin, the revisions passed
+ through stdin will not be affected by it. Conversely, when passed
+ via standard input, the revisions passed on the command line will
+ not be affected by it.
--all::
Pretend as if all the refs in `refs/`, along with `HEAD`, are
@@ -240,7 +244,9 @@ endif::git-rev-list[]
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.
+ limit the result. Flags like `--not` which are read via standard input
+ are only respected for arguments passed in the same way and will not
+ influence any subsequent command line arguments.
ifdef::git-rev-list[]
--quiet::
@@ -310,12 +316,12 @@ list.
With `--pretty` format other than `oneline` and `reference` (for obvious reasons),
this causes the output to have two extra lines of information
taken from the reflog. The reflog designator in the output may be shown
-as `ref@{Nth}` (where `Nth` is the reverse-chronological index in the
-reflog) or as `ref@{timestamp}` (with the timestamp for that entry),
+as `ref@{<Nth>}` (where _<Nth>_ is the reverse-chronological index in the
+reflog) or as `ref@{<timestamp>}` (with the _<timestamp>_ for that entry),
depending on a few rules:
+
--
-1. If the starting point is specified as `ref@{Nth}`, show the index
+1. If the starting point is specified as `ref@{<Nth>}`, show the index
format.
+
2. If the starting point was specified as `ref@{now}`, show the
@@ -335,8 +341,11 @@ See also linkgit:git-reflog[1].
Under `--pretty=reference`, this information will not be shown at all.
--merge::
- After a failed merge, show refs that touch files having a
- conflict and don't exist on all heads to merge.
+ Show commits touching conflicted paths in the range `HEAD...<other>`,
+ where `<other>` is the first existing pseudoref in `MERGE_HEAD`,
+ `CHERRY_PICK_HEAD`, `REVERT_HEAD` or `REBASE_HEAD`. Only works
+ when the index has unmerged entries. This option can be used to show
+ relevant commits when resolving conflicts from a 3-way merge.
--boundary::
Output excluded boundary commits. Boundary commits are
@@ -941,10 +950,10 @@ ifdef::git-rev-list[]
+
The form '--filter=blob:none' omits all blobs.
+
-The form '--filter=blob:limit=<n>[kmg]' omits blobs larger than n bytes
-or units. n may be zero. The suffixes k, m, and g can be used to name
-units in KiB, MiB, or GiB. For example, 'blob:limit=1k' is the same
-as 'blob:limit=1024'.
+The form '--filter=blob:limit=<n>[kmg]' omits blobs of size at least n
+bytes or units. n may be zero. The suffixes k, m, and g can be used
+to name units in KiB, MiB, or GiB. For example, 'blob:limit=1k'
+is the same as 'blob:limit=1024'.
+
The form '--filter=object:type=(tag|commit|tree|blob)' omits all objects
which are not of the requested type.
@@ -1013,6 +1022,10 @@ Unexpected missing objects will raise an error.
+
The form '--missing=print' is like 'allow-any', but will also print a
list of the missing objects. Object IDs are prefixed with a ``?'' character.
++
+If some tips passed to the traversal are missing, they will be
+considered as missing too, and the traversal will ignore them. In case
+we cannot get their Object ID though, an error will be raised.
--exclude-promisor-objects::
(For internal use only.) Prefilter object traversal at
diff --git a/Documentation/scalar.txt b/Documentation/scalar.txt
index 361f51a647..7e4259c674 100644
--- a/Documentation/scalar.txt
+++ b/Documentation/scalar.txt
@@ -86,6 +86,13 @@ cloning. If the HEAD at the remote did not point at any branch when
`<entlistment>/src` directory. Use `--no-src` to place the cloned
repository directly in the `<enlistment>` directory.
+--[no-]tags::
+ By default, `scalar clone` will fetch the tag objects advertised by
+ the remote and future `git fetch` commands will do the same. Use
+ `--no-tags` to avoid fetching tags in `scalar clone` and to configure
+ the repository to avoid fetching tags in the future. To fetch tags after
+ cloning with `--no-tags`, run `git fetch --tags`.
+
--[no-]full-clone::
A sparse-checkout is initialized by default. This behavior can be
turned off via `--full-clone`.
diff --git a/Documentation/signoff-option.txt b/Documentation/signoff-option.txt
index 12aa2333e4..d98758f3cb 100644
--- a/Documentation/signoff-option.txt
+++ b/Documentation/signoff-option.txt
@@ -9,7 +9,7 @@ endif::git-commit[]
the committer has the rights to submit the work under the
project's license or agrees to some contributor representation,
such as a Developer Certificate of Origin.
- (See http://developercertificate.org for the one used by the
+ (See https://developercertificate.org for the one used by the
Linux kernel and Git projects.) Consult the documentation or
leadership of the project to which you're contributing to
understand how the signoffs are used in that project.
diff --git a/Documentation/technical/api-index-skel.txt b/Documentation/technical/api-index-skel.txt
index eda8c195c1..7780a76b08 100644
--- a/Documentation/technical/api-index-skel.txt
+++ b/Documentation/technical/api-index-skel.txt
@@ -1,7 +1,7 @@
Git API Documents
=================
-Git has grown a set of internal API over time. This collection
+Git has grown a set of internal APIs over time. This collection
documents them.
////////////////////////////////////////////////////////////////
diff --git a/Documentation/technical/api-simple-ipc.txt b/Documentation/technical/api-simple-ipc.txt
index d44ada98e7..c4fb152b23 100644
--- a/Documentation/technical/api-simple-ipc.txt
+++ b/Documentation/technical/api-simple-ipc.txt
@@ -2,7 +2,7 @@ Simple-IPC API
==============
The Simple-IPC API is a collection of `ipc_` prefixed library routines
-and a basic communication protocol that allow an IPC-client process to
+and a basic communication protocol that allows an IPC-client process to
send an application-specific IPC-request message to an IPC-server
process and receive an application-specific IPC-response message.
@@ -20,12 +20,12 @@ IPC-client.
The IPC-client routines within a client application process connect
to the IPC-server and send a request message and wait for a response.
-When received, the response is returned back the caller.
+When received, the response is returned back to the caller.
For example, the `fsmonitor--daemon` feature will be built as a server
application on top of the IPC-server library routines. It will have
threads watching for file system events and a thread pool waiting for
-client connections. Clients, such as `git status` will request a list
+client connections. Clients, such as `git status`, will request a list
of file system events since a point in time and the server will
respond with a list of changed files and directories. The formats of
the request and response are application-specific; the IPC-client and
@@ -37,7 +37,7 @@ Comparison with sub-process model
The Simple-IPC mechanism differs from the existing `sub-process.c`
model (Documentation/technical/long-running-process-protocol.txt) and
-used by applications like Git-LFS. In the LFS-style sub-process model
+used by applications like Git-LFS. In the LFS-style sub-process model,
the helper is started by the foreground process, communication happens
via a pair of file descriptors bound to the stdin/stdout of the
sub-process, the sub-process only serves the current foreground
@@ -102,4 +102,4 @@ stateless request, receive an application-specific
response, and disconnect. It is a one round trip facility for
querying the server. The Simple-IPC routines hide the socket,
named pipe, and thread pool details and allow the application
-layer to focus on the application at hand.
+layer to focus on the task at hand.
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index de5fc25059..5817b18310 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -128,7 +128,7 @@ yields
------------
$ cat ~/log.event
-{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"3","exe":"2.20.1.155.g426c96fcdb"}
+{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"4","exe":"2.20.1.155.g426c96fcdb"}
{"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]}
{"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"}
{"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0}
@@ -344,7 +344,7 @@ only present on the "start" and "atexit" events.
{
"event":"version",
...
- "evt":"3", # EVENT format version
+ "evt":"4", # EVENT format version
"exe":"2.20.1.155.g426c96fcdb" # git version
}
------------
@@ -835,6 +835,19 @@ The "value" field may be an integer or a string.
}
------------
+`"printf"`::
+ This event logs a human-readable message with no particular formatting
+ guidelines.
++
+------------
+{
+ "event":"printf",
+ ...
+ "t_abs":0.015905, # elapsed time in seconds
+ "msg":"Hello world" # optional
+}
+------------
+
== Example Trace2 API Usage
diff --git a/Documentation/technical/bitmap-format.txt b/Documentation/technical/bitmap-format.txt
index c2e652b71a..bfb0ec7beb 100644
--- a/Documentation/technical/bitmap-format.txt
+++ b/Documentation/technical/bitmap-format.txt
@@ -114,7 +114,7 @@ result in an empty bitmap (no bits set).
* N entries with compressed bitmaps, one for each indexed commit
+
-Where `N` is the total amount of entries in this bitmap index.
+Where `N` is the total number of entries in this bitmap index.
Each entry contains the following:
** {empty}
@@ -126,7 +126,7 @@ Each entry contains the following:
** {empty}
1-byte XOR-offset: ::
The xor offset used to compress this bitmap. For an entry
- in position `x`, a XOR offset of `y` means that the actual
+ in position `x`, an XOR offset of `y` means that the actual
bitmap representing this commit is composed by XORing the
bitmap for this entry with the bitmap in entry `x-y` (i.e.
the bitmap `y` entries before this one).
@@ -239,7 +239,7 @@ bitmaps.
For a `.bitmap` containing `nr_entries` reachability bitmaps, the table
contains a list of `nr_entries` <commit_pos, offset, xor_row> triplets
-(sorted in the ascending order of `commit_pos`). The content of i'th
+(sorted in the ascending order of `commit_pos`). The content of the i'th
triplet is -
* {empty}
@@ -255,3 +255,144 @@ triplet is -
xor_row (4 byte integer, network byte order): ::
The position of the triplet whose bitmap is used to compress
this one, or `0xffffffff` if no such bitmap exists.
+
+Pseudo-merge bitmaps
+--------------------
+
+If the `BITMAP_OPT_PSEUDO_MERGES` flag is set, a variable number of
+bytes (preceding the name-hash cache, commit lookup table, and trailing
+checksum) of the `.bitmap` file is used to store pseudo-merge bitmaps.
+
+For more information on what pseudo-merges are, why they are useful, and
+how to configure them, see the information in linkgit:gitpacking[7].
+
+=== File format
+
+If enabled, pseudo-merge bitmaps are stored in an optional section at
+the end of a `.bitmap` file. The format is as follows:
+
+....
++-------------------------------------------+
+| .bitmap File |
++-------------------------------------------+
+| |
+| Pseudo-merge bitmaps (Variable Length) |
+| +---------------------------+ |
+| | commits_bitmap (EWAH) | |
+| +---------------------------+ |
+| | merge_bitmap (EWAH) | |
+| +---------------------------+ |
+| |
++-------------------------------------------+
+| |
+| Lookup Table |
+| +---------------------------+ |
+| | commit_pos (4 bytes) | |
+| +---------------------------+ |
+| | offset (8 bytes) | |
+| +------------+--------------+ |
+| |
+| Offset Cases: |
+| ------------- |
+| |
+| 1. MSB Unset: single pseudo-merge bitmap |
+| + offset to pseudo-merge bitmap |
+| |
+| 2. MSB Set: multiple pseudo-merges |
+| + offset to extended lookup table |
+| |
++-------------------------------------------+
+| |
+| Extended Lookup Table (Optional) |
+| +----+----------+----------+----------+ |
+| | N | Offset 1 | .... | Offset N | |
+| +----+----------+----------+----------+ |
+| | | 8 bytes | .... | 8 bytes | |
+| +----+----------+----------+----------+ |
+| |
++-------------------------------------------+
+| |
+| Pseudo-merge position table |
+| +----+----------+----------+----------+ |
+| | N | Offset 1 | .... | Offset N | |
+| +----+----------+----------+----------+ |
+| | | 8 bytes | .... | 8 bytes | |
+| +----+----------+----------+----------+ |
+| |
++-------------------------------------------+
+| |
+| Pseudo-merge Metadata |
+| +-----------------------------------+ |
+| | # pseudo-merges (4 bytes) | |
+| +-----------------------------------+ |
+| | # commits (4 bytes) | |
+| +-----------------------------------+ |
+| | Lookup offset (8 bytes) | |
+| +-----------------------------------+ |
+| | Extension size (8 bytes) | |
+| +-----------------------------------+ |
+| |
++-------------------------------------------+
+....
+
+* One or more pseudo-merge bitmaps, each containing:
+
+ ** `commits_bitmap`, an EWAH-compressed bitmap describing the set of
+ commits included in the this psuedo-merge.
+
+ ** `merge_bitmap`, an EWAH-compressed bitmap describing the union of
+ the set of objects reachable from all commits listed in the
+ `commits_bitmap`.
+
+* A lookup table, mapping pseudo-merged commits to the pseudo-merges
+ they belong to. Entries appear in increasing order of each commit's
+ bit position. Each entry is 12 bytes wide, and is comprised of the
+ following:
+
+ ** `commit_pos`, a 4-byte unsigned value (in network byte-order)
+ containing the bit position for this commit.
+
+ ** `offset`, an 8-byte unsigned value (also in network byte-order)
+ containing either one of two possible offsets, depending on whether or
+ not the most-significant bit is set.
+
+ *** If unset (i.e. `offset & ((uint64_t)1<<63) == 0`), the offset
+ (relative to the beginning of the `.bitmap` file) at which the
+ pseudo-merge bitmap for this commit can be read. This indicates
+ only a single pseudo-merge bitmap contains this commit.
+
+ *** If set (i.e. `offset & ((uint64_t)1<<63) != 0`), the offset
+ (again relative to the beginning of the `.bitmap` file) at which
+ the extended offset table can be located describing the set of
+ pseudo-merge bitmaps which contain this commit. This indicates
+ that multiple pseudo-merge bitmaps contain this commit.
+
+* An (optional) extended lookup table (written if and only if there is
+ at least one commit which appears in more than one pseudo-merge).
+ There are as many entries as commits which appear in multiple
+ pseudo-merges. Each entry contains the following:
+
+ ** `N`, a 4-byte unsigned value equal to the number of pseudo-merges
+ which contain a given commit.
+
+ ** An array of `N` 8-byte unsigned values, each of which is
+ interpreted as an offset (relative to the beginning of the
+ `.bitmap` file) at which a pseudo-merge bitmap for this commit can
+ be read. These values occur in no particular order.
+
+* Positions for all pseudo-merges, each stored as an 8-byte unsigned
+ value (in network byte-order) containing the offset (relative to the
+ beginning of the `.bitmap` file) of each consecutive pseudo-merge.
+
+* A 4-byte unsigned value (in network byte-order) equal to the number of
+ pseudo-merges.
+
+* A 4-byte unsigned value (in network byte-order) equal to the number of
+ unique commits which appear in any pseudo-merge.
+
+* An 8-byte unsigned value (in network byte-order) equal to the number
+ of bytes between the start of the pseudo-merge section and the
+ beginning of the lookup table.
+
+* An 8-byte unsigned value (in network byte-order) equal to the number
+ of bytes in the pseudo-merge section (including this field).
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index 86fed0de0f..2c26e95e51 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -136,7 +136,7 @@ Design Details
- Commit grafts and replace objects can change the shape of the commit
history. The latter can also be enabled/disabled on the fly using
- `--no-replace-objects`. This leads to difficultly storing both possible
+ `--no-replace-objects`. This leads to difficulty storing both possible
interpretations of a commit id, especially when computing generation
numbers. The commit-graph will not be read or written when
replace-objects or grafts are present.
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index ed57481089..7102c7c8f5 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -148,8 +148,8 @@ Detailed Design
Repository format extension
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A SHA-256 repository uses repository format version `1` (see
-Documentation/technical/repository-version.txt) with extensions
-`objectFormat` and `compatObjectFormat`:
+linkgit:gitrepository-layout[5]) with `extensions.objectFormat` and
+`extensions.compatObjectFormat` (see linkgit:git-config[1]) set to:
[core]
repositoryFormatVersion = 1
diff --git a/Documentation/technical/multi-pack-index.txt b/Documentation/technical/multi-pack-index.txt
index f2221d2b44..cc063b30be 100644
--- a/Documentation/technical/multi-pack-index.txt
+++ b/Documentation/technical/multi-pack-index.txt
@@ -61,6 +61,109 @@ Design Details
- The MIDX file format uses a chunk-based approach (similar to the
commit-graph file) that allows optional data to be added.
+Incremental multi-pack indexes
+------------------------------
+
+As repositories grow in size, it becomes more expensive to write a
+multi-pack index (MIDX) that includes all packfiles. To accommodate
+this, the "incremental multi-pack indexes" feature allows for combining
+a "chain" of multi-pack indexes.
+
+Each individual component of the chain need only contain a small number
+of packfiles. Appending to the chain does not invalidate earlier parts
+of the chain, so repositories can control how much time is spent
+updating the MIDX chain by determining the number of packs in each layer
+of the MIDX chain.
+
+=== Design state
+
+At present, the incremental multi-pack indexes feature is missing two
+important components:
+
+ - The ability to rewrite earlier portions of the MIDX chain (i.e., to
+ "compact" some collection of adjacent MIDX layers into a single
+ MIDX). At present the only supported way of shrinking a MIDX chain
+ is to rewrite the entire chain from scratch without the `--split`
+ flag.
++
+There are no fundamental limitations that stand in the way of being able
+to implement this feature. It is omitted from the initial implementation
+in order to reduce the complexity, but will be added later.
+
+ - Support for reachability bitmaps. The classic single MIDX
+ implementation does support reachability bitmaps (see the section
+ titled "multi-pack-index reverse indexes" in
+ linkgit:gitformat-pack[5] for more details).
++
+As above, there are no fundamental limitations that stand in the way of
+extending the incremental MIDX format to support reachability bitmaps.
+The design below specifically takes this into account, and support for
+reachability bitmaps will be added in a future patch series. It is
+omitted from the current implementation for the same reason as above.
++
+In brief, to support reachability bitmaps with the incremental MIDX
+feature, the concept of the pseudo-pack order is extended across each
+layer of the incremental MIDX chain to form a concatenated pseudo-pack
+order. This concatenation takes place in the same order as the chain
+itself (in other words, the concatenated pseudo-pack order for a chain
+`{$H1, $H2, $H3}` would be the pseudo-pack order for `$H1`, followed by
+the pseudo-pack order for `$H2`, followed by the pseudo-pack order for
+`$H3`).
++
+The layout will then be extended so that each layer of the incremental
+MIDX chain can write a `*.bitmap`. The objects in each layer's bitmap
+are offset by the number of objects in the previous layers of the chain.
+
+=== File layout
+
+Instead of storing a single `multi-pack-index` file (with an optional
+`.rev` and `.bitmap` extension) in `$GIT_DIR/objects/pack`, incremental
+MIDXs are stored in the following layout:
+
+----
+$GIT_DIR/objects/pack/multi-pack-index.d/
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-chain
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H1.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H2.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H3.midx
+----
+
+The `multi-pack-index-chain` file contains a list of the incremental
+MIDX files in the chain, in order. The above example shows a chain whose
+`multi-pack-index-chain` file would contain the following lines:
+
+----
+$H1
+$H2
+$H3
+----
+
+The `multi-pack-index-$H1.midx` file contains the first layer of the
+multi-pack-index chain. The `multi-pack-index-$H2.midx` file contains
+the second layer of the chain, and so on.
+
+When both an incremental- and non-incremental MIDX are present, the
+non-incremental MIDX is always read first.
+
+=== Object positions for incremental MIDXs
+
+In the original multi-pack-index design, we refer to objects via their
+lexicographic position (by object IDs) within the repository's singular
+multi-pack-index. In the incremental multi-pack-index design, we refer
+to objects via their index into a concatenated lexicographic ordering
+among each component in the MIDX chain.
+
+If `objects_nr()` is a function that returns the number of objects in a
+given MIDX layer, then the index of an object at lexicographic position
+`i` within, say, $H3 is defined as:
+
+----
+objects_nr($H2) + objects_nr($H1) + i
+----
+
+(in the C implementation, this is often computed as `i +
+m->num_objects_in_base`).
+
Future Work
-----------
diff --git a/Documentation/technical/parallel-checkout.txt b/Documentation/technical/parallel-checkout.txt
index 47c9b6183c..b4a144e5f4 100644
--- a/Documentation/technical/parallel-checkout.txt
+++ b/Documentation/technical/parallel-checkout.txt
@@ -63,7 +63,7 @@ improvements over the sequential code, but there was still too much lock
contention. A `perf` profiling indicated that around 20% of the runtime
during a local Linux clone (on an SSD) was spent in locking functions.
For this reason this approach was rejected in favor of using multiple
-child processes, which led to a better performance.
+child processes, which led to better performance.
Multi-Process Solution
----------------------
@@ -126,7 +126,7 @@ Then, for each assigned item, each worker:
* W5: Writes the result to the file descriptor opened at W2.
-* W6: Calls `fstat()` or lstat()` on the just-written path, and sends
+* W6: Calls `fstat()` or `lstat()` on the just-written path, and sends
the result back to the main process, together with the end status of
the operation and the item's identification number.
@@ -148,7 +148,7 @@ information, the main process handles the results in two steps:
- First, it updates the in-memory index with the `lstat()` information
sent by the workers. (This must be done first as this information
- might me required in the following step.)
+ might be required in the following step.)
- Then it writes the items which collided on disk (i.e. items marked
with `PC_ITEM_COLLIDED`). More on this below.
@@ -185,7 +185,7 @@ quite straightforward: for each parallel-eligible entry, the main
process must remove all files that prevent this entry from being written
(before enqueueing it). This includes any non-directory file in the
leading path of the entry. Later, when a worker gets assigned the entry,
-it looks again for the non-directories files and for an already existing
+it looks again for the non-directory files and for an already existing
file at the entry's path. If any of these checks finds something, the
worker knows that there was a path collision.
@@ -232,7 +232,7 @@ conversion and re-encoding, are eligible for parallel checkout.
Ineligible entries are checked out by the classic sequential codepath
*before* spawning workers.
-Note: submodules's files are also eligible for parallel checkout (as
+Note: submodules' files are also eligible for parallel checkout (as
long as they don't fall into any of the excluding categories mentioned
above). But since each submodule is checked out in its own child
process, we don't mix the superproject's and the submodules' files in
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt
index 92fcee2bff..bf5ec5c82d 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -3,7 +3,7 @@ Partial Clone Design Notes
The "Partial Clone" feature is a performance optimization for Git that
allows Git to function without having a complete copy of the repository.
-The goal of this work is to allow Git better handle extremely large
+The goal of this work is to allow Git to better handle extremely large
repositories.
During clone and fetch operations, Git downloads the complete contents
@@ -102,7 +102,7 @@ or commits that reference missing trees.
- On the client a repository extension is added to the local config to
prevent older versions of git from failing mid-operation because of
missing objects that they cannot handle.
- See "extensions.partialClone" in Documentation/technical/repository-version.txt"
+ See `extensions.partialClone` in linkgit:git-config[1].
Handling Missing Objects
@@ -256,7 +256,7 @@ remote in a specific order.
- Dynamic object fetching currently uses the existing pack protocol V0
which means that each object is requested via fetch-pack. The server
will send a full set of info/refs when the connection is established.
- If there are large number of refs, this may incur significant overhead.
+ If there are a large number of refs, this may incur significant overhead.
Future Work
@@ -265,7 +265,7 @@ Future Work
- Improve the way to specify the order in which promisor remotes are
tried.
+
-For example this could allow to specify explicitly something like:
+For example this could allow specifying explicitly something like:
"When fetching from this remote, I want to use these promisor remotes
in this order, though, when pushing or fetching to that remote, I want
to use those promisor remotes in that order."
@@ -322,7 +322,7 @@ Footnotes
[a] expensive-to-modify list of missing objects: Earlier in the design of
partial clone we discussed the need for a single list of missing objects.
- This would essentially be a sorted linear list of OIDs that the were
+ This would essentially be a sorted linear list of OIDs that were
omitted by the server during a clone or subsequent fetches.
This file would need to be loaded into memory on every object lookup.
diff --git a/Documentation/technical/platform-support.txt b/Documentation/technical/platform-support.txt
new file mode 100644
index 0000000000..0a2fb28d62
--- /dev/null
+++ b/Documentation/technical/platform-support.txt
@@ -0,0 +1,190 @@
+Platform Support Policy
+=======================
+
+Git has a history of providing broad "support" for exotic platforms and older
+platforms, without an explicit commitment. Stakeholders of these platforms may
+want a more predictable support commitment. This is only possible when platform
+stakeholders supply Git developers with adequate tooling, so we can test for
+compatibility or develop workarounds for platform-specific quirks on our own.
+Various levels of platform-specific tooling will allow us to make more solid
+commitments around Git's compatibility with that platform.
+
+Note that this document is about maintaining existing support for a platform
+that has generally worked in the past; for adding support to a platform which
+doesn't generally work with Git, the stakeholders for that platform are expected
+to do the bulk of that work themselves. We will consider such patches if they
+don't make life harder for other supported platforms or for Git contributors.
+Some contributors may volunteer to help with the initial or continued support,
+but that's not a given. Support work which is too intrusive or difficult for the
+project to maintain may still not be accepted.
+
+Minimum Requirements
+--------------------
+
+The rest of this doc describes best practices for platforms to make themselves
+easy to support. However, before considering support at all, platforms need to
+meet the following minimum requirements:
+
+* Has C99 or C11
+
+* Uses versions of dependencies which are generally accepted as stable and
+ supportable, e.g., in line with the version used by other long-term-support
+ distributions
+
+* Has active security support (taking security releases of dependencies, etc)
+
+These requirements are a starting point, and not sufficient on their own for the
+Git community to be enthusiastic about supporting your platform. Maintainers of
+platforms which do meet these requirements can follow the steps below to make it
+more likely that Git updates will respect the platform's needs.
+
+Compatible by next release
+--------------------------
+
+To increase probability that compatibility issues introduced in a release
+will be fixed in a later release:
+
+* You should send a bug report as soon as you notice the breakage on your
+ platform. The sooner you notice, the better; watching `seen` means you can
+ notice problems before they are considered "done with review"; whereas
+ watching `master` means the stable branch could break for your platform, but
+ you have a decent chance of avoiding a tagged release breaking you. See "The
+ Policy" in link:../howto/maintain-git.html["How to maintain Git"] for an
+ overview of which branches are used in the Git project, and how.
+
+* The bug report should include information about what platform you are using.
+
+* You should also use linkgit:git-bisect[1] and determine which commit
+ introduced the breakage.
+
+* Please include any information you have about the nature of the breakage: is
+ it a memory alignment issue? Is an underlying library missing or broken for
+ your platform? Is there some quirk about your platform which means typical
+ practices (like malloc) behave strangely?
+
+* If possible, build Git from the exact same source both for your platform and
+ for a mainstream platform, to see if the problem you noticed appears only
+ on your platform. If the problem appears in both, then it's not a
+ compatibility issue, but we of course appreciate hearing about it in a bug
+ report anyway, to benefit users of every platform. If it appears only on your
+ platform, mention clearly that it is a compatibility issue in your report.
+
+* Once we begin to fix the issue, please work closely with the contributor
+ working on it to test the proposed fix against your platform.
+
+Example: NonStop
+https://lore.kernel.org/git/01bd01da681a$b8d70a70$2a851f50$@nexbridge.com/[reports
+problems] when they're noticed.
+
+Compatible on `master` and releases
+-----------------------------------
+
+To make sure all stable builds and regular releases work for your platform the
+first time, help us avoid breaking `master` for your platform:
+
+* You should run regular tests against the `next` branch and
+ publish breakage reports to the mailing list immediately when they happen.
+
+** Ideally, these tests should run daily. They must run more often than
+ weekly, as topics generally spend at least 7 days in `next` before graduating
+ to `master`, and it takes time to put the brakes on a patch once it lands in
+ `next`.
+
+** You may want to ask to join the mailto:git-security@googlegroups.com[security
+ mailing list] in order to run tests against the fixes proposed there, too.
+
+* It may make sense to automate these; if you do, make sure they are not noisy
+ (you don't need to send a report when everything works, only when something
+ breaks; you don't need to send repeated reports for the same breakage night
+ after night).
+
+* Breakage reports should be actionable - include clear error messages that can
+ help developers who may not have access to test directly on your platform.
+
+* You should use git-bisect and determine which commit introduced the breakage;
+ if you can't do this with automation, you should do this yourself manually as
+ soon as you notice a breakage report was sent.
+
+* You should either:
+
+** Provide on-demand access to your platform to a trusted developer working to
+ fix the issue, so they can test their fix, OR
+
+** Work closely with the developer fixing the issue; the turnaround to check
+ that their proposed fix works for your platform should be fast enough that it
+ doesn't hinder the developer working on that fix. Slow testing turnarounds
+ may cause the fix to miss the next release, or the developer may lose
+ interest in working on the fix at all.
+
+Example:
+https://lore.kernel.org/git/CAHd-oW6X4cwD_yLNFONPnXXUAFPxgDoccv2SOdpeLrqmHCJB4Q@mail.gmail.com/[AIX]
+provides a build farm and runs tests against release candidates.
+
+Compatible on `next`
+--------------------
+
+To avoid reactive debugging and fixing when changes hit a release or stable, you
+can aim to ensure `next` always works for your platform. (See "The Policy" in
+link:../howto/maintain-git.html["How to maintain Git"] for an overview of how
+`next` is used in the Git project.) To do that:
+
+* You should add a runner for your platform to the GitHub Actions or GitLab CI
+ suite. This suite is run when any Git developer proposes a new patch, and
+ having a runner for your platform/configuration means every developer will
+ know if they break you, immediately.
+
+** If adding it to an existing CI suite is infeasible (due to architecture
+ constraints or for performance reasons), any other method which runs as
+ automatically and quickly as possible works, too. For example, a service
+ which snoops on the mailing list and automatically runs tests on new [PATCH]
+ emails, replying to the author with the results, would also be within the
+ spirit of this requirement.
+
+* If you rely on Git avoiding a specific pattern that doesn't work well with
+ your platform (like a certain malloc pattern), raise it on the mailing list.
+ We'll work case-by-case to look for a solution that doesn't unnecessarily
+ constrain other platforms to keep compatibility with yours.
+
+* If you rely on some configuration or behavior, add a test for it. Untested
+ behavior is subject to breakage at any time.
+
+** Clearly label these tests as necessary for platform compatibility. Add them
+ to an isolated compatibility-related test suite, like a new t* file or unit
+ test suite, so that they're easy to remove when compatibility is no longer
+ required. If the specific compatibility need is gated behind an issue with
+ another project, link to documentation of that issue (like a bug or email
+ thread) to make it easier to tell when that compatibility need goes away.
+
+** Include a comment with an expiration date for these tests no more than 1 year
+ from now. You can update the expiration date if your platform still needs
+ that assurance down the road, but we need to know you still care about that
+ compatibility case and are working to make it unnecessary.
+
+Example: We run our
+https://git.kernel.org/pub/scm/git/git.git/tree/.github/workflows/main.yml[CI
+suite] on Windows, Ubuntu, Mac, and others.
+
+Getting help writing platform support patches
+---------------------------------------------
+
+In general, when sending patches to fix platform support problems, follow
+these guidelines to make sure the patch is reviewed with the appropriate level
+of urgency:
+
+* Clearly state in the commit message that you are fixing a platform breakage,
+ and for which platform.
+
+* Use the CI and test suite to ensure that the fix for your platform doesn't
+ break other platforms.
+
+* If possible, add a test ensuring this regression doesn't happen again. If
+ it's not possible to add a test, explain why in the commit message.
+
+Platform Maintainers
+--------------------
+
+If you maintain a platform, or Git for that platform, and intend to work with
+the Git project to ensure compatibility, please send a patch to add yourself to
+this list.
+
+NonStop: Randall S. Becker <rsbecker@nexbridge.com>
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
index ceda4bbfda..59bea66c0f 100644
--- a/Documentation/technical/racy-git.txt
+++ b/Documentation/technical/racy-git.txt
@@ -11,7 +11,7 @@ write out the next tree object to be committed. The state is
"virtual" in the sense that it does not necessarily have to, and
often does not, match the files in the working tree.
-There are cases Git needs to examine the differences between the
+There are cases where Git needs to examine the differences between the
virtual working tree state in the index and the files in the
working tree. The most obvious case is when the user asks `git
diff` (or its low level implementation, `git diff-files`) or
@@ -165,9 +165,9 @@ Avoiding runtime penalty
In order to avoid the above runtime penalty, post 1.4.2 Git used
to have a code that made sure the index file
-got timestamp newer than the youngest files in the index when
-there are many young files with the same timestamp as the
-resulting index file would otherwise would have by waiting
+got a timestamp newer than the youngest files in the index when
+there were many young files with the same timestamp as the
+resulting index file otherwise would have by waiting
before finishing writing the index file out.
I suspected that in practice the situation where many paths in the
@@ -190,7 +190,7 @@ In a large project where raciness avoidance cost really matters,
however, the initial computation of all object names in the
index takes more than one second, and the index file is written
out after all that happens. Therefore the timestamp of the
-index file will be more than one seconds later than the
+index file will be more than one second later than the
youngest file in the working tree. This means that in these
cases there actually will not be any racily clean entry in
the resulting index.
diff --git a/Documentation/technical/reftable.txt b/Documentation/technical/reftable.txt
index 6a67cc4174..dd0b37c4e3 100644
--- a/Documentation/technical/reftable.txt
+++ b/Documentation/technical/reftable.txt
@@ -46,7 +46,7 @@ search lookup, and range scans.
Storage in the file is organized into variable sized blocks. Prefix
compression is used within a single block to reduce disk space. Block
-size and alignment is tunable by the writer.
+size and alignment are tunable by the writer.
Performance
^^^^^^^^^^^
@@ -115,7 +115,7 @@ Varint encoding
Varint encoding is identical to the ofs-delta encoding method used
within pack files.
-Decoder works such as:
+Decoder works as follows:
....
val = buf[ptr] & 0x7f
@@ -175,7 +175,7 @@ log_index*
footer
....
-in a log-only file the first log block immediately follows the file
+In a log-only file, the first log block immediately follows the file
header, without padding to block alignment.
Block size
@@ -247,7 +247,7 @@ uint32( hash_id )
....
The header is identical to `version_number=1`, with the 4-byte hash ID
-("sha1" for SHA1 and "s256" for SHA-256) append to the header.
+("sha1" for SHA1 and "s256" for SHA-256) appended to the header.
For maximum backward compatibility, it is recommended to use version 1 when
writing SHA1 reftables.
@@ -288,7 +288,7 @@ The 2-byte `restart_count` stores the number of entries in the
`restart_count` to binary search between restarts before starting a
linear scan.
-Exactly `restart_count` 3-byte `restart_offset` values precedes the
+Exactly `restart_count` 3-byte `restart_offset` values precede the
`restart_count`. Offsets are relative to the start of the block and
refer to the first byte of any `ref_record` whose name has not been
prefix compressed. Entries in the `restart_offset` list must be sorted,
diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt
index 8ef664b0b9..b9bb81a81f 100644
--- a/Documentation/technical/repository-version.txt
+++ b/Documentation/technical/repository-version.txt
@@ -65,38 +65,6 @@ Note that if no extensions are specified in the config file, then
provides no benefit, and makes the repository incompatible with older
implementations of git).
-This document will serve as the master list for extensions. Any
-implementation wishing to define a new extension should make a note of
-it here, in order to claim the name.
-
-The defined extensions are:
-
-==== `noop`
-
-This extension does not change git's behavior at all. It is useful only
-for testing format-1 compatibility.
-
-==== `preciousObjects`
-
-When the config key `extensions.preciousObjects` is set to `true`,
-objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
-`git repack -d`).
-
-==== `partialClone`
-
-When the config key `extensions.partialClone` is set, it indicates
-that the repo was created with a partial clone (or later performed
-a partial fetch) and that the remote may have omitted sending
-certain unwanted objects. Such a remote is called a "promisor remote"
-and it promises that all such omitted objects can be fetched from it
-in the future.
-
-The value of this key is the name of the promisor remote.
-
-==== `worktreeConfig`
-
-If set, by default "git config" reads from both "config" and
-"config.worktree" file from GIT_DIR in that order. In
-multiple working directory mode, "config" file is shared while
-"config.worktree" is per-working directory (i.e., it's in
-GIT_COMMON_DIR/worktrees/<id>/config.worktree)
+The defined extensions are given in the `extensions.*` section of
+linkgit:git-config[1]. Any implementation wishing to define a new
+extension should make a note of it there, in order to claim the name.
diff --git a/Documentation/technical/rerere.txt b/Documentation/technical/rerere.txt
index be58f1bee3..580f23360a 100644
--- a/Documentation/technical/rerere.txt
+++ b/Documentation/technical/rerere.txt
@@ -60,7 +60,7 @@ By resolving this conflict, to leave line D, the user declares:
what AB and AC wanted to do.
As branch AC2 refers to the same commit as AC, the above implies that
-this is also compatible what AB and AC2 wanted to do.
+this is also compatible with what AB and AC2 wanted to do.
By extension, this means that rerere should recognize that the above
conflicts are the same. To do this, the labels on the conflict
@@ -76,7 +76,7 @@ examples would both result in the following normalized conflict:
Sorting hunks
~~~~~~~~~~~~~
-As before, lets imagine that a common ancestor had a file with line A
+As before, let's imagine that a common ancestor had a file with line A
its early part, and line X in its late part. And then four branches
are forked that do these things:
@@ -145,7 +145,7 @@ Nested conflicts
Nested conflicts are handled very similarly to "simple" conflicts.
Similar to simple conflicts, the conflict is first normalized by
stripping the labels from conflict markers, stripping the common ancestor
-version, and the sorting the conflict hunks, both for the outer and the
+version, and sorting the conflict hunks, both for the outer and the
inner conflict. This is done recursively, so any number of nested
conflicts can be handled.
diff --git a/Documentation/technical/sparse-checkout.txt b/Documentation/technical/sparse-checkout.txt
index fa0d01cbda..d968659354 100644
--- a/Documentation/technical/sparse-checkout.txt
+++ b/Documentation/technical/sparse-checkout.txt
@@ -287,7 +287,7 @@ everything behaves like a dense checkout with a few exceptions (e.g. branch
checkouts and switches write fewer things, knowing the VFS will lazily
write the rest on an as-needed basis).
-Since there is no publically available VFS-related code for folks to try,
+Since there is no publicly available VFS-related code for folks to try,
the number of folks who can test such a usecase is limited.
The primary reason to note the Behavior C usecase is that as we fix things
diff --git a/Documentation/technical/unit-tests.txt b/Documentation/technical/unit-tests.txt
new file mode 100644
index 0000000000..5a432b7b29
--- /dev/null
+++ b/Documentation/technical/unit-tests.txt
@@ -0,0 +1,242 @@
+= Unit Testing
+
+In our current testing environment, we spend a significant amount of effort
+crafting end-to-end tests for error conditions that could easily be captured by
+unit tests (or we simply forgo some hard-to-setup and rare error conditions).
+Unit tests additionally provide stability to the codebase and can simplify
+debugging through isolation. Writing unit tests in pure C, rather than with our
+current shell/test-tool helper setup, simplifies test setup, simplifies passing
+data around (no shell-isms required), and reduces testing runtime by not
+spawning a separate process for every test invocation.
+
+We believe that a large body of unit tests, living alongside the existing test
+suite, will improve code quality for the Git project.
+
+== Definitions
+
+For the purposes of this document, we'll use *test framework* to refer to
+projects that support writing test cases and running tests within the context
+of a single executable. *Test harness* will refer to projects that manage
+running multiple executables (each of which may contain multiple test cases) and
+aggregating their results.
+
+In reality, these terms are not strictly defined, and many of the projects
+discussed below contain features from both categories.
+
+For now, we will evaluate projects solely on their framework features. Since we
+are relying on having TAP output (see below), we can assume that any framework
+can be made to work with a harness that we can choose later.
+
+
+== Summary
+
+We believe the best way forward is to implement a custom TAP framework for the
+Git project. We use a version of the framework originally proposed in
+https://lore.kernel.org/git/c902a166-98ce-afba-93f2-ea6027557176@gmail.com/[1].
+
+See the <<framework-selection,Framework Selection>> section below for the
+rationale behind this decision.
+
+
+== Choosing a test harness
+
+During upstream discussion, it was occasionally noted that `prove` provides many
+convenient features, such as scheduling slower tests first, or re-running
+previously failed tests.
+
+While we already support the use of `prove` as a test harness for the shell
+tests, it is not strictly required. The t/Makefile allows running shell tests
+directly (though with interleaved output if parallelism is enabled). Git
+developers who wish to use `prove` as a more advanced harness can do so by
+setting DEFAULT_TEST_TARGET=prove in their config.mak.
+
+We will follow a similar approach for unit tests: by default the test
+executables will be run directly from the t/Makefile, but `prove` can be
+configured with DEFAULT_UNIT_TEST_TARGET=prove.
+
+
+[[framework-selection]]
+== Framework selection
+
+There are a variety of features we can use to rank the candidate frameworks, and
+those features have different priorities:
+
+* Critical features: we probably won't consider a framework without these
+** Can we legally / easily use the project?
+*** <<license,License>>
+*** <<vendorable-or-ubiquitous,Vendorable or ubiquitous>>
+*** <<maintainable-extensible,Maintainable / extensible>>
+*** <<major-platform-support,Major platform support>>
+** Does the project support our bare-minimum needs?
+*** <<tap-support,TAP support>>
+*** <<diagnostic-output,Diagnostic output>>
+*** <<runtime-skippable-tests,Runtime-skippable tests>>
+* Nice-to-have features:
+** <<parallel-execution,Parallel execution>>
+** <<mock-support,Mock support>>
+** <<signal-error-handling,Signal & error-handling>>
+* Tie-breaker stats
+** <<project-kloc,Project KLOC>>
+** <<adoption,Adoption>>
+
+[[license]]
+=== License
+
+We must be able to legally use the framework in connection with Git. As Git is
+licensed only under GPLv2, we must eliminate any LGPLv3, GPLv3, or Apache 2.0
+projects.
+
+[[vendorable-or-ubiquitous]]
+=== Vendorable or ubiquitous
+
+We want to avoid forcing Git developers to install new tools just to run unit
+tests. Any prospective frameworks and harnesses must either be vendorable
+(meaning, we can copy their source directly into Git's repository), or so
+ubiquitous that it is reasonable to expect that most developers will have the
+tools installed already.
+
+[[maintainable-extensible]]
+=== Maintainable / extensible
+
+It is unlikely that any pre-existing project perfectly fits our needs, so any
+project we select will need to be actively maintained and open to accepting
+changes. Alternatively, assuming we are vendoring the source into our repo, it
+must be simple enough that Git developers can feel comfortable making changes as
+needed to our version.
+
+In the comparison table below, "True" means that the framework seems to have
+active developers, that it is simple enough that Git developers can make changes
+to it, and that the project seems open to accepting external contributions (or
+that it is vendorable). "Partial" means that at least one of the above
+conditions holds.
+
+[[major-platform-support]]
+=== Major platform support
+
+At a bare minimum, unit-testing must work on Linux, MacOS, and Windows.
+
+In the comparison table below, "True" means that it works on all three major
+platforms with no issues. "Partial" means that there may be annoyances on one or
+more platforms, but it is still usable in principle.
+
+[[tap-support]]
+=== TAP support
+
+The https://testanything.org/[Test Anything Protocol] is a text-based interface
+that allows tests to communicate with a test harness. It is already used by
+Git's integration test suite. Supporting TAP output is a mandatory feature for
+any prospective test framework.
+
+In the comparison table below, "True" means this is natively supported.
+"Partial" means TAP output must be generated by post-processing the native
+output.
+
+Frameworks that do not have at least Partial support will not be evaluated
+further.
+
+[[diagnostic-output]]
+=== Diagnostic output
+
+When a test case fails, the framework must generate enough diagnostic output to
+help developers find the appropriate test case in source code in order to debug
+the failure.
+
+[[runtime-skippable-tests]]
+=== Runtime-skippable tests
+
+Test authors may wish to skip certain test cases based on runtime circumstances,
+so the framework should support this.
+
+[[parallel-execution]]
+=== Parallel execution
+
+Ideally, we will build up a significant collection of unit test cases, most
+likely split across multiple executables. It will be necessary to run these
+tests in parallel to enable fast develop-test-debug cycles.
+
+In the comparison table below, "True" means that individual test cases within a
+single test executable can be run in parallel. We assume that executable-level
+parallelism can be handled by the test harness.
+
+[[mock-support]]
+=== Mock support
+
+Unit test authors may wish to test code that interacts with objects that may be
+inconvenient to handle in a test (e.g. interacting with a network service).
+Mocking allows test authors to provide a fake implementation of these objects
+for more convenient tests.
+
+[[signal-error-handling]]
+=== Signal & error handling
+
+The test framework should fail gracefully when test cases are themselves buggy
+or when they are interrupted by signals during runtime.
+
+[[project-kloc]]
+=== Project KLOC
+
+The size of the project, in thousands of lines of code as measured by
+https://dwheeler.com/sloccount/[sloccount] (rounded up to the next multiple of
+1,000). As a tie-breaker, we probably prefer a project with fewer LOC.
+
+[[adoption]]
+=== Adoption
+
+As a tie-breaker, we prefer a more widely-used project. We use the number of
+GitHub / GitLab stars to estimate this.
+
+
+=== Comparison
+
+:true: [lime-background]#True#
+:false: [red-background]#False#
+:partial: [yellow-background]#Partial#
+
+:gpl: [lime-background]#GPL v2#
+:isc: [lime-background]#ISC#
+:mit: [lime-background]#MIT#
+:expat: [lime-background]#Expat#
+:lgpl: [lime-background]#LGPL v2.1#
+
+:custom-impl: https://lore.kernel.org/git/c902a166-98ce-afba-93f2-ea6027557176@gmail.com/[Custom Git impl.]
+:greatest: https://github.com/silentbicycle/greatest[Greatest]
+:criterion: https://github.com/Snaipe/Criterion[Criterion]
+:c-tap: https://github.com/rra/c-tap-harness/[C TAP]
+:check: https://libcheck.github.io/check/[Check]
+:clar: https://github.com/clar-test/clar[Clar]
+
+[format="csv",options="header",width="33%",subs="specialcharacters,attributes,quotes,macros"]
+|=====
+Framework,"<<license,License>>","<<vendorable-or-ubiquitous,Vendorable or ubiquitous>>","<<maintainable-extensible,Maintainable / extensible>>","<<major-platform-support,Major platform support>>","<<tap-support,TAP support>>","<<diagnostic-output,Diagnostic output>>","<<runtime--skippable-tests,Runtime- skippable tests>>","<<parallel-execution,Parallel execution>>","<<mock-support,Mock support>>","<<signal-error-handling,Signal & error handling>>","<<project-kloc,Project KLOC>>","<<adoption,Adoption>>"
+{custom-impl},{gpl},{true},{true},{true},{true},{true},{true},{false},{false},{false},1,0
+{greatest},{isc},{true},{partial},{true},{partial},{true},{true},{false},{false},{false},3,1400
+{criterion},{mit},{false},{partial},{true},{true},{true},{true},{true},{false},{true},19,1800
+{c-tap},{expat},{true},{partial},{partial},{true},{false},{true},{false},{false},{false},4,33
+{check},{lgpl},{false},{partial},{true},{true},{true},{false},{false},{false},{true},17,973
+{clar},{isc},{false},{partial},{true},{true},{true},{true},{false},{false},{true},1,192
+|=====
+
+=== Additional framework candidates
+
+Several suggested frameworks have been eliminated from consideration:
+
+* Incompatible licenses:
+** https://github.com/zorgnax/libtap[libtap] (LGPL v3)
+** https://cmocka.org/[cmocka] (Apache 2.0)
+* Missing source: https://www.kindahl.net/mytap/doc/index.html[MyTap]
+* No TAP support:
+** https://nemequ.github.io/munit/[µnit]
+** https://github.com/google/cmockery[cmockery]
+** https://github.com/lpabon/cmockery2[cmockery2]
+** https://github.com/ThrowTheSwitch/Unity[Unity]
+** https://github.com/siu/minunit[minunit]
+** https://cunit.sourceforge.net/[CUnit]
+
+
+== Milestones
+
+* Add useful tests of library-like code
+* Integrate with
+ https://lore.kernel.org/git/20230502211454.1673000-1-calvinwan@google.com/[stdlib
+ work]
+* Run alongside regular `make test` target
diff --git a/Documentation/trace2-target-values.txt b/Documentation/trace2-target-values.txt
index 3985b6d3c2..06f1953313 100644
--- a/Documentation/trace2-target-values.txt
+++ b/Documentation/trace2-target-values.txt
@@ -5,7 +5,7 @@
* `<absolute-pathname>` - Writes to the file in append mode. If the target
already exists and is a directory, the traces will be written to files (one
per process) underneath the given directory.
-* `af_unix:[<socket_type>:]<absolute-pathname>` - Write to a
+* `af_unix:[<socket-type>:]<absolute-pathname>` - Write to a
Unix DomainSocket (on platforms that support them). Socket
type can be either `stream` or `dgram`; if omitted Git will
try both.
diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.txt
index ae8c2db427..bf17012241 100644
--- a/Documentation/urls-remotes.txt
+++ b/Documentation/urls-remotes.txt
@@ -33,7 +33,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
+to `<URL>`. Pushing to a remote affects all defined pushurls or all
defined urls if no pushurls are defined. Fetch, however, will only
fetch from the first defined url if multiple urls are defined.
@@ -48,7 +48,7 @@ provide a refspec on the command line. This file should have the
following format:
------------
- URL: one of the above URL format
+ URL: one of the above URL formats
Push: <refspec>
Pull: <refspec>
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index 1c229d7581..9c871e716a 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -6,23 +6,23 @@ address of the remote server, and the path to the repository.
Depending on the transport protocol, some of this information may be
absent.
-Git supports ssh, git, http, and https protocols (in addition, ftp,
+Git supports ssh, git, http, and https protocols (in addition, ftp
and ftps can be used for fetching, but this is inefficient and
-deprecated; do not use it).
+deprecated; do not use them).
-The native transport (i.e. git:// URL) does no authentication and
+The native transport (i.e. `git://` URL) does no authentication and
should be used with caution on unsecured networks.
The following syntaxes may be used with them:
-- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/
-- git://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- http{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- ftp{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- `ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>`
+- `git://<host>[:<port>]/<path-to-git-repo>`
+- `http[s]://<host>[:<port>]/<path-to-git-repo>`
+- `ftp[s]://<host>[:<port>]/<path-to-git-repo>`
An alternative scp-like syntax may also be used with the ssh protocol:
-- {startsb}user@{endsb}host.xz:path/to/repo.git/
+- `[<user>@]<host>:/<path-to-git-repo>`
This syntax is only recognized if there are no slashes before the
first colon. This helps differentiate a local path that contains a
@@ -30,40 +30,40 @@ colon. For example the local path `foo:bar` could be specified as an
absolute path or `./foo:bar` to avoid being misinterpreted as an ssh
url.
-The ssh and git protocols additionally support ~username expansion:
+The ssh and git protocols additionally support `~<username>` expansion:
-- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
-- git://host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
-- {startsb}user@{endsb}host.xz:/~{startsb}user{endsb}/path/to/repo.git/
+- `ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo>`
+- `git://<host>[:<port>]/~<user>/<path-to-git-repo>`
+- `[<user>@]<host>:~<user>/<path-to-git-repo>`
For local repositories, also supported by Git natively, the following
syntaxes may be used:
-- /path/to/repo.git/
-- \file:///path/to/repo.git/
+- `/path/to/repo.git/`
+- `file:///path/to/repo.git/`
ifndef::git-clone[]
These two syntaxes are mostly equivalent, except when cloning, when
-the former implies --local option. See linkgit:git-clone[1] for
+the former implies `--local` option. See linkgit:git-clone[1] for
details.
endif::git-clone[]
ifdef::git-clone[]
These two syntaxes are mostly equivalent, except the former implies
---local option.
+`--local` option.
endif::git-clone[]
-'git clone', 'git fetch' and 'git pull', but not 'git push', will also
+`git clone`, `git fetch` and `git pull`, but not `git push`, will also
accept a suitable bundle file. See linkgit:git-bundle[1].
When Git doesn't know how to handle a certain transport protocol, it
-attempts to use the 'remote-<transport>' remote helper, if one
+attempts to use the `remote-<transport>` remote helper, if one
exists. To explicitly request a remote helper, the following syntax
may be used:
-- <transport>::<address>
+- `<transport>::<address>`
-where <address> may be a path, a server and path, or an arbitrary
+where _<address>_ may be a path, a server and path, or an arbitrary
URL-like string recognized by the specific remote helper being
invoked. See linkgit:gitremote-helpers[7] for details.
@@ -72,10 +72,11 @@ you want to use a different format for them (such that the URLs you
use will be rewritten into URLs that work), you can create a
configuration section of the form:
-------------
- [url "<actual url base>"]
- insteadOf = <other url base>
-------------
+[verse]
+--
+ [url "__<actual-url-base>__"]
+ insteadOf = _<other-url-base>_
+--
For example, with this:
@@ -91,10 +92,11 @@ rewritten in any context that takes a URL to be "git://git.host.xz/repo.git".
If you want to rewrite URLs for push only, you can create a
configuration section of the form:
-------------
- [url "<actual url base>"]
- pushInsteadOf = <other url base>
-------------
+[verse]
+--
+ [url "__<actual-url-base>__"]
+ pushInsteadOf = _<other-url-base>_
+--
For example, with this:
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 4281396093..90a4189358 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1122,7 +1122,7 @@ choosing "Stage Hunk For Commit").
=== Creating good commit messages
Though not required, it's a good idea to begin the commit message
-with a single short (less than 50 character) line summarizing the
+with a single short (no more than 50 characters) line summarizing the
change, followed by a blank line and then a more thorough
description. The text up to the first blank line in a commit
message is treated as the commit title, and that title is used
@@ -1344,7 +1344,7 @@ $ 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
+tree with the result of the merge, Git writes a 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
@@ -4093,15 +4093,46 @@ that not only specifies their type, but also provides size information
about the data in the object. It's worth noting that the SHA-1 hash
that is used to name the object is the hash of the original data
plus this header, so `sha1sum` 'file' does not match the object name
-for 'file'.
+for 'file' (the earliest versions of Git hashed slightly differently
+but the conclusion is still the same).
+
+The following is a short example that demonstrates how these hashes
+can be generated manually:
+
+Let's assume a small text file with some simple content:
+
+-------------------------------------------------
+$ echo "Hello world" >hello.txt
+-------------------------------------------------
+
+We can now manually generate the hash Git would use for this file:
+
+- The object we want the hash for is of type "blob" and its size is
+ 12 bytes.
+
+- Prepend the object header to the file content and feed this to
+ `sha1sum`:
+
+-------------------------------------------------
+$ { printf "blob 12\0"; cat hello.txt; } | sha1sum
+802992c4220de19a90767f3000a79a31b98d0df7 -
+-------------------------------------------------
+
+This manually constructed hash can be verified using `git hash-object`
+which of course hides the addition of the header:
+
+-------------------------------------------------
+$ git hash-object hello.txt
+802992c4220de19a90767f3000a79a31b98d0df7
+-------------------------------------------------
As a result, the general consistency of an object can always be tested
independently of the contents or the type of the object: all objects can
be validated by verifying that (a) their hashes match the content of the
file and (b) the object successfully inflates to a stream of bytes that
forms a sequence of
-`<ascii type without space> + <space> + <ascii decimal size> +
-<byte\0> + <binary object data>`.
+`<ascii-type-without-space> + <space> + <ascii-decimal-size> +
+<byte\0> + <binary-object-data>`.
The structured objects can further have their structure and
connectivity to other objects verified. This is generally done with
@@ -4123,7 +4154,8 @@ $ git switch --detach e83c5163
----------------------------------------------------
The initial revision lays the foundation for almost everything Git has
-today, but is small enough to read in one sitting.
+today (even though details may differ in a few places), but is small
+enough to read in one sitting.
Note that terminology has changed since that revision. For example, the
README in that revision uses the word "changeset" to describe what we
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 070d22c6d1..78e8631f67 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.42.3
+DEF_VER=v2.47.GIT
LF='
'
@@ -11,7 +11,7 @@ LF='
if test -f version
then
VN=$(cat version) || VN="$DEF_VER"
-elif test -d ${GIT_DIR:-.git} -o -f .git &&
+elif { test -d "${GIT_DIR:-.git}" || test -f .git; } &&
VN=$(git describe --match "v[0-9]*" HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
diff --git a/INSTALL b/INSTALL
index 6745146902..2a46d04592 100644
--- a/INSTALL
+++ b/INSTALL
@@ -119,12 +119,12 @@ Issues of note:
- A POSIX-compliant shell is required to run some scripts needed
for everyday use (e.g. "bisect", "request-pull").
- - "Perl" version 5.8 or later is needed to use some of the
+ - "Perl" version 5.8.1 or later is needed to use some of the
features (e.g. sending patches using "git send-email",
interacting with svn repositories with "git svn"). If you can
live without these, use NO_PERL. Note that recent releases of
Redhat/Fedora are reported to ship Perl binary package with some
- core modules stripped away (see http://lwn.net/Articles/477234/),
+ core modules stripped away (see https://lwn.net/Articles/477234/),
so you might need to install additional packages other than Perl
itself, e.g. Digest::MD5, File::Spec, File::Temp, Net::Domain,
Net::SMTP, and Time::HiRes.
diff --git a/Makefile b/Makefile
index 5776309365..549b24e7fd 100644
--- a/Makefile
+++ b/Makefile
@@ -186,7 +186,7 @@ include shared.mak
# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
#
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
-# as the compiler can crash (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
+# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
# Define USE_NSEC below if you want git to care about sub-second file mtimes
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
@@ -385,6 +385,10 @@ include shared.mak
# supports calling _NSGetExecutablePath to retrieve the path of the running
# executable.
#
+# When using RUNTIME_PREFIX, define HAVE_ZOS_GET_EXECUTABLE_PATH if your platform
+# supports calling __getprogramdir and getprogname to retrieve the path of the
+# running executable.
+#
# When using RUNTIME_PREFIX, define HAVE_WPGMPTR if your platform offers
# the global variable _wpgmptr containing the absolute path of the current
# executable (this is the case on Windows).
@@ -409,6 +413,9 @@ include shared.mak
# to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
# that implements the `fsm_os_settings__*()` routines.
#
+# Define LINK_FUZZ_PROGRAMS if you want `make all` to also build the fuzz test
+# programs in oss-fuzz/.
+#
# === Optional library: libintl ===
#
# Define NO_GETTEXT if you don't want Git output to be translated.
@@ -514,6 +521,10 @@ include shared.mak
# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
# SHA-1.
#
+# Define the same Makefile knobs as above, but suffixed with _UNSAFE to
+# use the corresponding implementations for unsafe SHA-1 hashing for
+# non-cryptographic purposes.
+#
# If don't enable any of the *_SHA1 settings in this section, Git will
# default to its built-in sha1collisiondetection library, which is a
# collision-detecting sha1 This is slower, but may detect attempted
@@ -682,6 +693,9 @@ TEST_BUILTINS_OBJS =
TEST_OBJS =
TEST_PROGRAMS_NEED_X =
THIRD_PARTY_SOURCES =
+UNIT_TEST_PROGRAMS =
+UNIT_TEST_DIR = t/unit-tests
+UNIT_TEST_BIN = $(UNIT_TEST_DIR)/bin
# Having this variable in your environment would break pipelines because
# you cause "cd" to echo its destination to stdout. It can also take
@@ -749,17 +763,6 @@ SCRIPTS = $(SCRIPT_SH_GEN) \
ETAGS_TARGET = TAGS
-FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
-FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
-FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
-.PHONY: fuzz-objs
-fuzz-objs: $(FUZZ_OBJS)
-
-# Always build fuzz objects even if not testing, to prevent bit-rot.
-all:: $(FUZZ_OBJS)
-
-FUZZ_PROGRAMS += $(patsubst %.o,%,$(FUZZ_OBJS))
-
# Empty...
EXTRA_PROGRAMS =
@@ -788,8 +791,8 @@ TEST_BUILTINS_OBJS += test-chmtime.o
TEST_BUILTINS_OBJS += test-config.o
TEST_BUILTINS_OBJS += test-crontab.o
TEST_BUILTINS_OBJS += test-csprng.o
-TEST_BUILTINS_OBJS += test-ctype.o
TEST_BUILTINS_OBJS += test-date.o
+TEST_BUILTINS_OBJS += test-delete-gpgsig.o
TEST_BUILTINS_OBJS += test-delta.o
TEST_BUILTINS_OBJS += test-dir-iterator.o
TEST_BUILTINS_OBJS += test-drop-caches.o
@@ -798,8 +801,8 @@ TEST_BUILTINS_OBJS += test-dump-fsmonitor.o
TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
TEST_BUILTINS_OBJS += test-env-helper.o
-TEST_BUILTINS_OBJS += test-example-decorate.o
-TEST_BUILTINS_OBJS += test-fast-rebase.o
+TEST_BUILTINS_OBJS += test-example-tap.o
+TEST_BUILTINS_OBJS += test-find-pack.o
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
TEST_BUILTINS_OBJS += test-genrandom.o
TEST_BUILTINS_OBJS += test-genzeros.o
@@ -808,15 +811,11 @@ TEST_BUILTINS_OBJS += test-hash-speed.o
TEST_BUILTINS_OBJS += test-hash.o
TEST_BUILTINS_OBJS += test-hashmap.o
TEST_BUILTINS_OBJS += test-hexdump.o
-TEST_BUILTINS_OBJS += test-index-version.o
TEST_BUILTINS_OBJS += test-json-writer.o
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
TEST_BUILTINS_OBJS += test-match-trees.o
TEST_BUILTINS_OBJS += test-mergesort.o
TEST_BUILTINS_OBJS += test-mktemp.o
-TEST_BUILTINS_OBJS += test-oid-array.o
-TEST_BUILTINS_OBJS += test-oidmap.o
-TEST_BUILTINS_OBJS += test-oidtree.o
TEST_BUILTINS_OBJS += test-online-cpus.o
TEST_BUILTINS_OBJS += test-pack-mtimes.o
TEST_BUILTINS_OBJS += test-parse-options.o
@@ -825,7 +824,6 @@ TEST_BUILTINS_OBJS += test-partial-clone.o
TEST_BUILTINS_OBJS += test-path-utils.o
TEST_BUILTINS_OBJS += test-pcre2-config.o
TEST_BUILTINS_OBJS += test-pkt-line.o
-TEST_BUILTINS_OBJS += test-prio-queue.o
TEST_BUILTINS_OBJS += test-proc-receive.o
TEST_BUILTINS_OBJS += test-progress.o
TEST_BUILTINS_OBJS += test-reach.o
@@ -845,14 +843,13 @@ TEST_BUILTINS_OBJS += test-sha1.o
TEST_BUILTINS_OBJS += test-sha256.o
TEST_BUILTINS_OBJS += test-sigchain.o
TEST_BUILTINS_OBJS += test-simple-ipc.o
-TEST_BUILTINS_OBJS += test-strcmp-offset.o
TEST_BUILTINS_OBJS += test-string-list.o
TEST_BUILTINS_OBJS += test-submodule-config.o
TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
TEST_BUILTINS_OBJS += test-submodule.o
TEST_BUILTINS_OBJS += test-subprocess.o
TEST_BUILTINS_OBJS += test-trace2.o
-TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
+TEST_BUILTINS_OBJS += test-truncate.o
TEST_BUILTINS_OBJS += test-userdiff.o
TEST_BUILTINS_OBJS += test-wildmatch.o
TEST_BUILTINS_OBJS += test-windows-named-pipe.o
@@ -918,11 +915,12 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
XDIFF_LIB = xdiff/lib.a
REFTABLE_LIB = reftable/libreftable.a
-REFTABLE_TEST_LIB = reftable/libreftable_test.a
GENERATED_H += command-list.h
GENERATED_H += config-list.h
GENERATED_H += hook-list.h
+GENERATED_H += $(UNIT_TEST_DIR)/clar-decls.h
+GENERATED_H += $(UNIT_TEST_DIR)/clar.suite
.PHONY: generated-hdrs
generated-hdrs: $(GENERATED_H)
@@ -1040,6 +1038,7 @@ LIB_OBJS += hash-lookup.o
LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
+LIB_OBJS += hex-ll.o
LIB_OBJS += hook.o
LIB_OBJS += ident.o
LIB_OBJS += json-writer.o
@@ -1053,6 +1052,7 @@ LIB_OBJS += list-objects-filter.o
LIB_OBJS += list-objects.o
LIB_OBJS += lockfile.o
LIB_OBJS += log-tree.o
+LIB_OBJS += loose.o
LIB_OBJS += ls-refs.o
LIB_OBJS += mailinfo.o
LIB_OBJS += mailmap.o
@@ -1065,6 +1065,7 @@ LIB_OBJS += merge-ort-wrappers.o
LIB_OBJS += merge-recursive.o
LIB_OBJS += merge.o
LIB_OBJS += midx.o
+LIB_OBJS += midx-write.o
LIB_OBJS += name-hash.o
LIB_OBJS += negotiator/default.o
LIB_OBJS += negotiator/noop.o
@@ -1073,6 +1074,7 @@ LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
LIB_OBJS += notes-utils.o
LIB_OBJS += notes.o
+LIB_OBJS += object-file-convert.o
LIB_OBJS += object-file.o
LIB_OBJS += object-name.o
LIB_OBJS += object.o
@@ -1090,6 +1092,7 @@ LIB_OBJS += pack-write.o
LIB_OBJS += packfile.o
LIB_OBJS += pager.o
LIB_OBJS += parallel-checkout.o
+LIB_OBJS += parse.o
LIB_OBJS += parse-options-cb.o
LIB_OBJS += parse-options.o
LIB_OBJS += patch-delta.o
@@ -1106,6 +1109,7 @@ LIB_OBJS += prompt.o
LIB_OBJS += protocol.o
LIB_OBJS += protocol-caps.o
LIB_OBJS += prune-packed.o
+LIB_OBJS += pseudo-merge.o
LIB_OBJS += quote.o
LIB_OBJS += range-diff.o
LIB_OBJS += reachable.o
@@ -1118,6 +1122,7 @@ LIB_OBJS += reflog.o
LIB_OBJS += refs.o
LIB_OBJS += refs/debug.o
LIB_OBJS += refs/files-backend.o
+LIB_OBJS += refs/reftable-backend.o
LIB_OBJS += refs/iterator.o
LIB_OBJS += refs/packed-backend.o
LIB_OBJS += refs/ref-cache.o
@@ -1282,11 +1287,13 @@ BUILTIN_OBJS += builtin/read-tree.o
BUILTIN_OBJS += builtin/rebase.o
BUILTIN_OBJS += builtin/receive-pack.o
BUILTIN_OBJS += builtin/reflog.o
+BUILTIN_OBJS += builtin/refs.o
BUILTIN_OBJS += builtin/remote-ext.o
BUILTIN_OBJS += builtin/remote-fd.o
BUILTIN_OBJS += builtin/remote.o
BUILTIN_OBJS += builtin/repack.o
BUILTIN_OBJS += builtin/replace.o
+BUILTIN_OBJS += builtin/replay.o
BUILTIN_OBJS += builtin/rerere.o
BUILTIN_OBJS += builtin/reset.o
BUILTIN_OBJS += builtin/rev-list.o
@@ -1331,6 +1338,41 @@ THIRD_PARTY_SOURCES += compat/poll/%
THIRD_PARTY_SOURCES += compat/regex/%
THIRD_PARTY_SOURCES += sha1collisiondetection/%
THIRD_PARTY_SOURCES += sha1dc/%
+THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/%
+THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
+
+CLAR_TEST_SUITES += ctype
+CLAR_TEST_SUITES += strvec
+CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
+CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES))
+CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o
+CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
+
+UNIT_TEST_PROGRAMS += t-example-decorate
+UNIT_TEST_PROGRAMS += t-hash
+UNIT_TEST_PROGRAMS += t-hashmap
+UNIT_TEST_PROGRAMS += t-mem-pool
+UNIT_TEST_PROGRAMS += t-oid-array
+UNIT_TEST_PROGRAMS += t-oidmap
+UNIT_TEST_PROGRAMS += t-oidtree
+UNIT_TEST_PROGRAMS += t-prio-queue
+UNIT_TEST_PROGRAMS += t-reftable-basics
+UNIT_TEST_PROGRAMS += t-reftable-block
+UNIT_TEST_PROGRAMS += t-reftable-merged
+UNIT_TEST_PROGRAMS += t-reftable-pq
+UNIT_TEST_PROGRAMS += t-reftable-reader
+UNIT_TEST_PROGRAMS += t-reftable-readwrite
+UNIT_TEST_PROGRAMS += t-reftable-record
+UNIT_TEST_PROGRAMS += t-reftable-stack
+UNIT_TEST_PROGRAMS += t-reftable-tree
+UNIT_TEST_PROGRAMS += t-strbuf
+UNIT_TEST_PROGRAMS += t-strcmp-offset
+UNIT_TEST_PROGRAMS += t-trailer
+UNIT_TEST_PROGRAMS += t-urlmatch-normalization
+UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o
# xdiff and reftable libs may in turn depend on what is in libgit.a
GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
@@ -1358,7 +1400,7 @@ PTHREAD_CFLAGS =
# For the 'sparse' target
SPARSE_FLAGS ?= -std=gnu99
-SP_EXTRA_FLAGS = -Wno-universal-initializer
+SP_EXTRA_FLAGS =
# For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets
SANITIZE_LEAK =
@@ -1434,8 +1476,8 @@ ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
endif
-ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS)
-ALL_LDFLAGS = $(LDFLAGS)
+ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_APPEND)
+ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
ifdef SANITIZE
SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag))
@@ -1534,23 +1576,23 @@ ifneq (,$(SOCKLEN_T))
endif
ifeq ($(uname_S),Darwin)
- ifndef NO_FINK
- ifeq ($(shell test -d /sw/lib && echo y),y)
+ ifndef NO_FINK
+ ifeq ($(shell test -d /sw/lib && echo y),y)
BASIC_CFLAGS += -I/sw/include
BASIC_LDFLAGS += -L/sw/lib
- endif
- endif
- ifndef NO_DARWIN_PORTS
- ifeq ($(shell test -d /opt/local/lib && echo y),y)
+ endif
+ endif
+ ifndef NO_DARWIN_PORTS
+ ifeq ($(shell test -d /opt/local/lib && echo y),y)
BASIC_CFLAGS += -I/opt/local/include
BASIC_LDFLAGS += -L/opt/local/lib
- endif
- endif
- ifndef NO_APPLE_COMMON_CRYPTO
+ endif
+ endif
+ ifndef NO_APPLE_COMMON_CRYPTO
NO_OPENSSL = YesPlease
APPLE_COMMON_CRYPTO = YesPlease
COMPAT_CFLAGS += -DAPPLE_COMMON_CRYPTO
- endif
+ endif
PTHREAD_LIBS =
endif
@@ -1572,7 +1614,7 @@ endif
ifdef LIBPCREDIR
BASIC_CFLAGS += -I$(LIBPCREDIR)/include
- EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib)
+ EXTLIBS += $(call libpath_template,$(LIBPCREDIR)/$(lib))
endif
ifdef HAVE_ALLOCA_H
@@ -1589,23 +1631,23 @@ ifdef NO_CURL
REMOTE_CURL_NAMES =
EXCLUDED_PROGRAMS += git-http-fetch git-http-push
else
- ifdef CURLDIR
+ ifdef CURLDIR
# Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case.
CURL_CFLAGS = -I$(CURLDIR)/include
- CURL_LIBCURL = -L$(CURLDIR)/$(lib) $(CC_LD_DYNPATH)$(CURLDIR)/$(lib)
- else
+ CURL_LIBCURL = $(call libpath_template,$(CURLDIR)/$(lib))
+ else
CURL_CFLAGS =
CURL_LIBCURL =
- endif
+ endif
- ifndef CURL_LDFLAGS
+ ifndef CURL_LDFLAGS
CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)
- endif
+ endif
CURL_LIBCURL += $(CURL_LDFLAGS)
- ifndef CURL_CFLAGS
+ ifndef CURL_CFLAGS
CURL_CFLAGS = $(eval CURL_CFLAGS := $$(shell $$(CURL_CONFIG) --cflags))$(CURL_CFLAGS)
- endif
+ endif
BASIC_CFLAGS += $(CURL_CFLAGS)
REMOTE_CURL_PRIMARY = git-remote-http$X
@@ -1613,49 +1655,49 @@ else
REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
PROGRAM_OBJS += http-fetch.o
PROGRAMS += $(REMOTE_CURL_NAMES)
- ifndef NO_EXPAT
+ ifndef NO_EXPAT
PROGRAM_OBJS += http-push.o
- endif
+ endif
curl_check := $(shell (echo 072200; $(CURL_CONFIG) --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
- ifeq "$(curl_check)" "072200"
+ ifeq "$(curl_check)" "072200"
USE_CURL_FOR_IMAP_SEND = YesPlease
- endif
- ifdef USE_CURL_FOR_IMAP_SEND
+ endif
+ ifdef USE_CURL_FOR_IMAP_SEND
BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
IMAP_SEND_BUILDDEPS = http.o
IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
- endif
- ifndef NO_EXPAT
- ifdef EXPATDIR
+ endif
+ ifndef NO_EXPAT
+ ifdef EXPATDIR
BASIC_CFLAGS += -I$(EXPATDIR)/include
- EXPAT_LIBEXPAT = -L$(EXPATDIR)/$(lib) $(CC_LD_DYNPATH)$(EXPATDIR)/$(lib) -lexpat
- else
+ EXPAT_LIBEXPAT = $(call libpath_template,$(EXPATDIR)/$(lib)) -lexpat
+ else
EXPAT_LIBEXPAT = -lexpat
- endif
- ifdef EXPAT_NEEDS_XMLPARSE_H
+ endif
+ ifdef EXPAT_NEEDS_XMLPARSE_H
BASIC_CFLAGS += -DEXPAT_NEEDS_XMLPARSE_H
- endif
- endif
+ endif
+ endif
endif
IMAP_SEND_LDFLAGS += $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
ifdef ZLIB_PATH
BASIC_CFLAGS += -I$(ZLIB_PATH)/include
- EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
+ EXTLIBS += $(call libpath_template,$(ZLIB_PATH)/$(lib))
endif
EXTLIBS += -lz
ifndef NO_OPENSSL
OPENSSL_LIBSSL = -lssl
- ifdef OPENSSLDIR
+ ifdef OPENSSLDIR
BASIC_CFLAGS += -I$(OPENSSLDIR)/include
- OPENSSL_LINK = -L$(OPENSSLDIR)/$(lib) $(CC_LD_DYNPATH)$(OPENSSLDIR)/$(lib)
- else
+ OPENSSL_LINK = $(call libpath_template,$(OPENSSLDIR)/$(lib))
+ else
OPENSSL_LINK =
- endif
- ifdef NEEDS_CRYPTO_WITH_SSL
+ endif
+ ifdef NEEDS_CRYPTO_WITH_SSL
OPENSSL_LIBSSL += -lcrypto
- endif
+ endif
else
BASIC_CFLAGS += -DNO_OPENSSL
OPENSSL_LIBSSL =
@@ -1673,18 +1715,18 @@ ifdef APPLE_COMMON_CRYPTO
endif
endif
ifndef NO_ICONV
- ifdef NEEDS_LIBICONV
- ifdef ICONVDIR
+ ifdef NEEDS_LIBICONV
+ ifdef ICONVDIR
BASIC_CFLAGS += -I$(ICONVDIR)/include
- ICONV_LINK = -L$(ICONVDIR)/$(lib) $(CC_LD_DYNPATH)$(ICONVDIR)/$(lib)
- else
+ ICONV_LINK = $(call libpath_template,$(ICONVDIR)/$(lib))
+ else
ICONV_LINK =
- endif
- ifdef NEEDS_LIBINTL_BEFORE_LIBICONV
+ endif
+ ifdef NEEDS_LIBINTL_BEFORE_LIBICONV
ICONV_LINK += -lintl
- endif
+ endif
EXTLIBS += $(ICONV_LINK) -liconv
- endif
+ endif
endif
ifdef ICONV_OMITS_BOM
BASIC_CFLAGS += -DICONV_OMITS_BOM
@@ -1805,10 +1847,10 @@ ifdef NO_MMAP
COMPAT_CFLAGS += -DNO_MMAP
COMPAT_OBJS += compat/mmap.o
else
- ifdef USE_WIN32_MMAP
+ ifdef USE_WIN32_MMAP
COMPAT_CFLAGS += -DUSE_WIN32_MMAP
COMPAT_OBJS += compat/win32mmap.o
- endif
+ endif
endif
ifdef MMAP_PREVENTS_DELETE
BASIC_CFLAGS += -DMMAP_PREVENTS_DELETE
@@ -1933,11 +1975,11 @@ else
BASIC_CFLAGS += -DSHA1_DC
LIB_OBJS += sha1dc_git.o
ifdef DC_SHA1_EXTERNAL
- ifdef DC_SHA1_SUBMODULE
- ifneq ($(DC_SHA1_SUBMODULE),auto)
+ ifdef DC_SHA1_SUBMODULE
+ ifneq ($(DC_SHA1_SUBMODULE),auto)
$(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
- endif
- endif
+ endif
+ endif
BASIC_CFLAGS += -DDC_SHA1_EXTERNAL
EXTLIBS += -lsha1detectcoll
else
@@ -1959,6 +2001,27 @@ endif
endif
endif
+ifdef OPENSSL_SHA1_UNSAFE
+ifndef OPENSSL_SHA1
+ EXTLIBS += $(LIB_4_CRYPTO)
+ BASIC_CFLAGS += -DSHA1_OPENSSL_UNSAFE
+endif
+else
+ifdef BLK_SHA1_UNSAFE
+ifndef BLK_SHA1
+ LIB_OBJS += block-sha1/sha1.o
+ BASIC_CFLAGS += -DSHA1_BLK_UNSAFE
+endif
+else
+ifdef APPLE_COMMON_CRYPTO_SHA1_UNSAFE
+ifndef APPLE_COMMON_CRYPTO_SHA1
+ COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
+ BASIC_CFLAGS += -DSHA1_APPLE_UNSAFE
+endif
+endif
+endif
+endif
+
ifdef OPENSSL_SHA256
EXTLIBS += $(LIB_4_CRYPTO)
BASIC_CFLAGS += -DSHA256_OPENSSL
@@ -2133,6 +2196,10 @@ ifdef HAVE_NS_GET_EXECUTABLE_PATH
BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
endif
+ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+ BASIC_CFLAGS += -DHAVE_ZOS_GET_EXECUTABLE_PATH
+endif
+
ifdef HAVE_WPGMPTR
BASIC_CFLAGS += -DHAVE_WPGMPTR
endif
@@ -2339,7 +2406,7 @@ profile-fast: profile-clean
all:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
ifneq (,$X)
- $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) $(OTHER_PROGRAMS))), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
+ $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) $(OTHER_PROGRAMS))), if test ! -d '$p' && test ! '$p' -ef '$p$X'; then $(RM) '$p'; fi;)
endif
all::
@@ -2349,6 +2416,29 @@ ifndef NO_TCLTK
endif
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
+# If you add a new fuzzer, please also make sure to run it in
+# ci/run-build-and-minimal-fuzzers.sh so that we make sure it still links and
+# runs in the future.
+FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o
+FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
+FUZZ_OBJS += oss-fuzz/fuzz-config.o
+FUZZ_OBJS += oss-fuzz/fuzz-date.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
+.PHONY: fuzz-objs
+fuzz-objs: $(FUZZ_OBJS)
+
+# Always build fuzz objects even if not testing, to prevent bit-rot.
+all:: $(FUZZ_OBJS)
+
+FUZZ_PROGRAMS += $(patsubst %.o,%,$(filter-out %dummy-cmd-main.o,$(FUZZ_OBJS)))
+
+# Build fuzz programs when possible, even without the necessary fuzzing support,
+# to prevent bit-rot.
+ifdef LINK_FUZZ_PROGRAMS
+all:: $(FUZZ_PROGRAMS)
+endif
+
please_set_SHELL_PATH_to_a_more_modern_shell:
@$$(:)
@@ -2627,29 +2717,14 @@ REFTABLE_OBJS += reftable/error.o
REFTABLE_OBJS += reftable/block.o
REFTABLE_OBJS += reftable/blocksource.o
REFTABLE_OBJS += reftable/iter.o
-REFTABLE_OBJS += reftable/publicbasics.o
REFTABLE_OBJS += reftable/merged.o
REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
-REFTABLE_OBJS += reftable/refname.o
-REFTABLE_OBJS += reftable/generic.o
REFTABLE_OBJS += reftable/stack.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o
-REFTABLE_TEST_OBJS += reftable/basics_test.o
-REFTABLE_TEST_OBJS += reftable/block_test.o
-REFTABLE_TEST_OBJS += reftable/dump.o
-REFTABLE_TEST_OBJS += reftable/merged_test.o
-REFTABLE_TEST_OBJS += reftable/pq_test.o
-REFTABLE_TEST_OBJS += reftable/record_test.o
-REFTABLE_TEST_OBJS += reftable/readwrite_test.o
-REFTABLE_TEST_OBJS += reftable/refname_test.o
-REFTABLE_TEST_OBJS += reftable/stack_test.o
-REFTABLE_TEST_OBJS += reftable/test_framework.o
-REFTABLE_TEST_OBJS += reftable/tree_test.o
-
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
.PHONY: test-objs
@@ -2673,6 +2748,9 @@ OBJECTS += $(TEST_OBJS)
OBJECTS += $(XDIFF_OBJS)
OBJECTS += $(FUZZ_OBJS)
OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
+OBJECTS += $(UNIT_TEST_OBJS)
+OBJECTS += $(CLAR_TEST_OBJS)
+OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
ifndef NO_CURL
OBJECTS += http.o http-walker.o remote-curl.o
@@ -2720,7 +2798,7 @@ $(OBJECTS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
ifdef USE_COMPUTED_HEADER_DEPENDENCIES
# Take advantage of gcc's on-the-fly dependency generation
-# See <http://gcc.gnu.org/gcc-3.0/features.html>.
+# See <https://gcc.gnu.org/gcc-3.0/features.html>.
dep_files_present := $(wildcard $(dep_files))
ifneq ($(dep_files_present),)
include $(dep_files_present)
@@ -2823,9 +2901,6 @@ $(XDIFF_LIB): $(XDIFF_OBJS)
$(REFTABLE_LIB): $(REFTABLE_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-$(REFTABLE_TEST_LIB): $(REFTABLE_TEST_OBJS)
- $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
export DEFAULT_EDITOR DEFAULT_PAGER
Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -3096,6 +3171,7 @@ GIT-BUILD-OPTIONS: FORCE
@echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@+
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+
+ @echo NO_ICONV=\''$(subst ','\'',$(subst ','\'',$(NO_ICONV)))'\' >>$@+
@echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+
@echo USE_LIBPCRE2=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE2)))'\' >>$@+
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
@@ -3175,7 +3251,7 @@ endif
test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
-all:: $(TEST_PROGRAMS) $(test_bindir_programs)
+all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
bin-wrappers/%: wrap-for-bin.sh
$(call mkdir_p_parent_template)
@@ -3203,17 +3279,18 @@ perf: all
.PRECIOUS: $(TEST_OBJS)
-t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
+t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) $(UNIT_TEST_DIR)/test-lib.o
-t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB)
+t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
check-sha1:: t/helper/test-tool$X
t/helper/test-sha1.sh
-SP_OBJ = $(patsubst %.o,%.sp,$(OBJECTS))
+SP_SRC = $(filter-out $(THIRD_PARTY_SOURCES),$(patsubst %.o,%.c,$(OBJECTS)))
+SP_OBJ = $(patsubst %.c,%.sp,$(SP_SRC))
-$(SP_OBJ): %.sp: %.c %.o
+$(SP_OBJ): %.sp: %.c %.o $(GENERATED_H)
$(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
-Wsparse-error \
$(SPARSE_FLAGS) $(SP_EXTRA_FLAGS) $< && \
@@ -3222,7 +3299,7 @@ $(SP_OBJ): %.sp: %.c %.o
.PHONY: sparse
sparse: $(SP_OBJ)
-EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
+EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/% $(UNIT_TEST_DIR)/clar/% $(UNIT_TEST_DIR)/clar/clar/%
ifndef OPENSSL_SHA1
EXCEPT_HDRS += sha1/openssl.h
endif
@@ -3243,7 +3320,7 @@ HCC = $(HCO:hco=hcc)
@echo '#include "git-compat-util.h"' >$@
@echo '#include "$<"' >>$@
-$(HCO): %.hco: %.hcc FORCE
+$(HCO): %.hco: %.hcc $(GENERATED_H) FORCE
$(QUIET_HDR)$(CC) $(ALL_CFLAGS) -o /dev/null -c -xc $<
.PHONY: hdr-check $(HCO)
@@ -3254,7 +3331,7 @@ style:
git clang-format --style file --diff --extensions c,h
.PHONY: check
-check: $(GENERATED_H)
+check:
@if sparse; \
then \
echo >&2 "Use 'make sparse' instead"; \
@@ -3601,12 +3678,12 @@ rpm::
.PHONY: rpm
ifneq ($(INCLUDE_DLLS_IN_ARTIFACTS),)
-OTHER_PROGRAMS += $(shell echo *.dll t/helper/*.dll)
+OTHER_PROGRAMS += $(shell echo *.dll t/helper/*.dll t/unit-tests/bin/*.dll)
endif
artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
- $(MOFILES)
+ $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) $(MOFILES)
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
test -n "$(ARTIFACTS_DIRECTORY)"
@@ -3661,12 +3738,13 @@ cocciclean:
$(RM) contrib/coccinelle/*.cocci.patch
clean: profile-clean coverage-clean cocciclean
- $(RM) -r .build
+ $(RM) -r .build $(UNIT_TEST_BIN)
+ $(RM) GIT-TEST-SUITES
$(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) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
$(RM) $(TEST_PROGRAMS)
$(RM) $(FUZZ_PROGRAMS)
@@ -3724,42 +3802,6 @@ ALL_COMMANDS += scalar
.PHONY: check-docs
check-docs::
$(MAKE) -C Documentation lint-docs
- @(for v in $(patsubst %$X,%,$(ALL_COMMANDS)); \
- do \
- case "$$v" in \
- git-merge-octopus | git-merge-ours | git-merge-recursive | \
- git-merge-resolve | git-merge-subtree | \
- git-fsck-objects | git-init-db | \
- git-remote-* | git-stage | git-legacy-* | \
- git-?*--?* ) continue ;; \
- esac ; \
- test -f "Documentation/$$v.txt" || \
- echo "no doc: $$v"; \
- sed -e '1,/^### command list/d' -e '/^#/d' command-list.txt | \
- grep -q "^$$v[ ]" || \
- case "$$v" in \
- git) ;; \
- *) echo "no link: $$v";; \
- esac ; \
- done; \
- ( \
- sed -e '1,/^### command list/d' \
- -e '/^#/d' \
- -e '/guide$$/d' \
- -e '/interfaces$$/d' \
- -e 's/[ ].*//' \
- -e 's/^/listed /' command-list.txt; \
- $(MAKE) -C Documentation print-man1 | \
- grep '\.txt$$' | \
- sed -e 's|^|documented |' \
- -e 's/\.txt//'; \
- ) | while read how cmd; \
- do \
- case " $(patsubst %$X,%,$(ALL_COMMANDS) $(BUILT_INS) $(EXCLUDED_PROGRAMS)) " in \
- *" $$cmd "*) ;; \
- *) echo "removed but $$how: $$cmd" ;; \
- esac; \
- done ) | sort
### Make sure built-ins do not have dups and listed in git.c
#
@@ -3833,17 +3875,47 @@ cover_db_html: cover_db
#
# An example command to build against libFuzzer from LLVM 11.0.0:
#
-# make CC=clang CXX=clang++ \
+# make CC=clang FUZZ_CXX=clang++ \
# CFLAGS="-fsanitize=fuzzer-no-link,address" \
-# LIB_FUZZING_ENGINE="-fsanitize=fuzzer" \
+# LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
# fuzz-all
#
-FUZZ_CXXFLAGS ?= $(CFLAGS)
+FUZZ_CXX ?= $(CC)
+FUZZ_CXXFLAGS ?= $(ALL_CFLAGS)
.PHONY: fuzz-all
+fuzz-all: $(FUZZ_PROGRAMS)
-$(FUZZ_PROGRAMS): all
- $(QUIET_LINK)$(CXX) $(FUZZ_CXXFLAGS) $(LIB_OBJS) $(BUILTIN_OBJS) \
- $(XDIFF_OBJS) $(EXTLIBS) git.o $@.o $(LIB_FUZZING_ENGINE) -o $@
+$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT-LDFLAGS
+ $(QUIET_LINK)$(FUZZ_CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \
+ -Wl,--allow-multiple-definition \
+ $(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
-fuzz-all: $(FUZZ_PROGRAMS)
+$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_OBJS) \
+ $(GITLIBS) GIT-LDFLAGS
+ $(call mkdir_p_parent_template)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
+ $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
+
+GIT-TEST-SUITES: FORCE
+ @FLAGS='$(CLAR_TEST_SUITES)'; \
+ if test x"$$FLAGS" != x"`cat GIT-TEST-SUITES 2>/dev/null`" ; then \
+ echo >&2 " * new test suites"; \
+ echo "$$FLAGS" >GIT-TEST-SUITES; \
+ fi
+
+$(UNIT_TEST_DIR)/clar-decls.h: $(patsubst %,$(UNIT_TEST_DIR)/%.c,$(CLAR_TEST_SUITES)) $(UNIT_TEST_DIR)/generate-clar-decls.sh GIT-TEST-SUITES
+ $(QUIET_GEN)$(SHELL_PATH) $(UNIT_TEST_DIR)/generate-clar-decls.sh "$@" $(filter %.c,$^)
+$(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h $(UNIT_TEST_DIR)/generate-clar-suites.sh
+ $(QUIET_GEN)$(SHELL_PATH) $(UNIT_TEST_DIR)/generate-clar-suites.sh $< $(UNIT_TEST_DIR)/clar.suite
+$(UNIT_TEST_DIR)/clar/clar.o: $(UNIT_TEST_DIR)/clar.suite
+$(CLAR_TEST_OBJS): $(UNIT_TEST_DIR)/clar-decls.h
+$(CLAR_TEST_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR)
+$(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) $(GITLIBS) GIT-LDFLAGS
+ $(call mkdir_p_parent_template)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+
+.PHONY: build-unit-tests unit-tests
+build-unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
+unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) t/helper/test-tool$X
+ $(MAKE) -C t/ unit-tests
diff --git a/README.md b/README.md
index 7ce4f05bae..665ce5f5a8 100644
--- a/README.md
+++ b/README.md
@@ -39,10 +39,10 @@ Those wishing to help with error message, usage and informational message
string translations (localization l10) should see [po/README.md][]
(a `po` file is a Portable Object file that holds the translations).
-To subscribe to the list, send an email with just "subscribe git" in
-the body to majordomo@vger.kernel.org (not the Git list). The mailing
+To subscribe to the list, send an email to <git+subscribe@vger.kernel.org>
+(see https://subspace.kernel.org/subscribing.html for details). The mailing
list archives are available at <https://lore.kernel.org/git/>,
-<http://marc.info/?l=git> and other archival sites.
+<https://marc.info/?l=git> and other archival sites.
Issues which are security relevant should be disclosed privately to
the Git Security mailing list <git-security@googlegroups.com>.
diff --git a/RelNotes b/RelNotes
index 7af3372ac2..061d699283 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.42.3.txt \ No newline at end of file
+Documentation/RelNotes/2.48.0.txt \ No newline at end of file
diff --git a/add-interactive.c b/add-interactive.c
index 7fd00c5e25..49042b3026 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "add-interactive.h"
#include "color.h"
@@ -532,8 +534,9 @@ static int get_modified_files(struct repository *r,
size_t *binary_count)
{
struct object_id head_oid;
- int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- &head_oid, NULL);
+ int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING,
+ &head_oid, NULL);
struct collection_status s = { 0 };
int i;
@@ -556,7 +559,7 @@ static int get_modified_files(struct repository *r,
s.skip_unseen = filter && i;
opt.def = is_initial ?
- empty_tree_oid_hex() : oid_to_hex(&head_oid);
+ empty_tree_oid_hex(the_repository->hash_algo) : oid_to_hex(&head_oid);
repo_init_revisions(r, &rev, NULL);
setup_revisions(0, NULL, &rev, &opt);
@@ -761,8 +764,10 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps,
size_t count, i, j;
struct object_id oid;
- int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
- NULL);
+ int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING,
+ &oid,
+ NULL);
struct lock_file index_lock;
const char **paths;
struct tree *tree;
@@ -865,6 +870,7 @@ static int get_untracked_files(struct repository *r,
}
strbuf_release(&buf);
+ dir_clear(&dir);
return 0;
}
@@ -989,8 +995,10 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
ssize_t count, i;
struct object_id oid;
- int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
- NULL);
+ int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING,
+ &oid,
+ NULL);
if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
return -1;
@@ -1021,9 +1029,9 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
return res;
}
-static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
- struct prefix_item_list *unused_files,
- struct list_and_choose_options *unused_opts)
+static int run_help(struct add_i_state *s, const struct pathspec *ps UNUSED,
+ struct prefix_item_list *files UNUSED,
+ struct list_and_choose_options *opts UNUSED)
{
color_fprintf_ln(stdout, s->help_color, "status - %s",
_("show paths with changes"));
@@ -1074,7 +1082,7 @@ struct print_command_item_data {
const char *color, *reset;
};
-static void print_command_item(int i, int selected,
+static void print_command_item(int i, int selected UNUSED,
struct string_list_item *item,
void *print_command_item_data)
{
diff --git a/add-patch.c b/add-patch.c
index bfe19876cd..557903310d 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "add-interactive.h"
#include "advice.h"
@@ -5,14 +7,15 @@
#include "environment.h"
#include "gettext.h"
#include "object-name.h"
+#include "pager.h"
#include "read-cache-ll.h"
#include "repository.h"
#include "strbuf.h"
+#include "sigchain.h"
#include "run-command.h"
#include "strvec.h"
#include "pathspec.h"
#include "color.h"
-#include "diff.h"
#include "compat/terminal.h"
#include "prompt.h"
@@ -294,13 +297,13 @@ static void err(struct add_p_state *s, const char *fmt, ...)
va_list args;
va_start(args, fmt);
- fputs(s->s.error_color, stderr);
- vfprintf(stderr, fmt, args);
- fputs(s->s.reset_color, stderr);
- fputc('\n', stderr);
+ fputs(s->s.error_color, stdout);
+ vprintf(fmt, args);
+ puts(s->s.reset_color);
va_end(args);
}
+LAST_ARG_MUST_BE_NULL
static void setup_child_process(struct add_p_state *s,
struct child_process *cp, ...)
{
@@ -401,6 +404,12 @@ static void complete_file(char marker, struct hunk *hunk)
hunk->splittable_into++;
}
+/* Empty context lines may omit the leading ' ' */
+static int normalize_marker(const char *p)
+{
+ return p[0] == '\n' || (p[0] == '\r' && p[1] == '\n') ? ' ' : p[0];
+}
+
static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
{
struct strvec args = STRVEC_INIT;
@@ -422,7 +431,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
/* could be on an unborn branch */
!strcmp("HEAD", s->revision) &&
repo_get_oid(the_repository, "HEAD", &oid) ?
- empty_tree_oid_hex() : s->revision);
+ empty_tree_oid_hex(the_repository->hash_algo) : s->revision);
}
color_arg_index = args.nr;
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
@@ -486,6 +495,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
while (p != pend) {
char *eol = memchr(p, '\n', pend - p);
const char *deleted = NULL, *mode_change = NULL;
+ char ch = normalize_marker(p);
if (!eol)
eol = pend;
@@ -533,7 +543,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
* Start counting into how many hunks this one can be
* split
*/
- marker = *p;
+ marker = ch;
} else if (hunk == &file_diff->head &&
starts_with(p, "new file")) {
file_diff->added = 1;
@@ -587,10 +597,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
(int)(eol - (plain->buf + file_diff->head.start)),
plain->buf + file_diff->head.start);
- if ((marker == '-' || marker == '+') && *p == ' ')
+ if ((marker == '-' || marker == '+') && ch == ' ')
hunk->splittable_into++;
- if (marker && *p != '\\')
- marker = *p;
+ if (marker && ch != '\\')
+ marker = ch;
p = eol == pend ? pend : eol + 1;
hunk->end = p - plain->buf;
@@ -814,7 +824,7 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
(int)(hunk->end - hunk->start),
plain + hunk->start);
- if (plain[overlap_end] != ' ')
+ if (normalize_marker(&plain[overlap_end]) != ' ')
return error(_("expected context line "
"#%d in\n%.*s"),
(int)(j + 1),
@@ -954,7 +964,7 @@ static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
context_line_count = 0;
while (splittable_into > 1) {
- ch = s->plain.buf[current];
+ ch = normalize_marker(&s->plain.buf[current]);
if (!ch)
BUG("buffer overrun while splitting hunks");
@@ -1106,33 +1116,34 @@ 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, comment_line_char,
+ strbuf_commented_addf(&s->buf, comment_line_str,
_("Manual hunk edit mode -- see bottom for "
"a quick guide.\n"));
render_hunk(s, hunk, 0, 0, &s->buf);
- strbuf_commented_addf(&s->buf, comment_line_char,
+ strbuf_commented_addf(&s->buf, comment_line_str,
_("---\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"),
+ "Lines starting with %s will be removed.\n"),
s->mode->is_reverse ? '+' : '-',
s->mode->is_reverse ? '-' : '+',
- comment_line_char);
- strbuf_commented_addf(&s->buf, comment_line_char, "%s",
+ comment_line_str);
+ strbuf_commented_addf(&s->buf, comment_line_str, "%s",
_(s->mode->edit_hunk_hint));
/*
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
* messages.
*/
- strbuf_commented_addf(&s->buf, comment_line_char,
+ strbuf_commented_addf(&s->buf, comment_line_str,
_("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"));
- if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
+ if (strbuf_edit_interactively(the_repository, &s->buf,
+ "addp-hunk-edit.diff", NULL) < 0)
return -1;
/* strip out commented lines */
@@ -1140,7 +1151,7 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
for (i = 0; i < s->buf.len; ) {
size_t next = find_next_line(&s->buf, i);
- if (s->buf.buf[i] != comment_line_char)
+ if (!starts_with(s->buf.buf + i, comment_line_str))
strbuf_add(&s->plain, s->buf.buf + i, next - i);
i = next;
}
@@ -1172,14 +1183,14 @@ static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
header->old_count = header->new_count = 0;
for (i = hunk->start; i < hunk->end; ) {
- switch (s->plain.buf[i]) {
+ switch(normalize_marker(&s->plain.buf[i])) {
case '-':
header->old_count++;
break;
case '+':
header->new_count++;
break;
- case ' ': case '\r': case '\n':
+ case ' ':
header->old_count++;
header->new_count++;
break;
@@ -1229,6 +1240,7 @@ static int prompt_yesno(struct add_p_state *s, const char *prompt)
fflush(stdout);
if (read_single_character(s) == EOF)
return -1;
+ /* do not limit to 1-byte input to allow 'no' etc. */
switch (tolower(s->answer.buf[0])) {
case 'n': return 0;
case 'y': return 1;
@@ -1327,7 +1339,7 @@ static int apply_for_checkout(struct add_p_state *s, struct strbuf *diff,
err(s, _("Nothing was applied.\n"));
} else
/* As a last resort, show the diff to the user */
- fwrite(diff->buf, diff->len, 1, stderr);
+ fwrite(diff->buf, diff->len, 1, stdout);
return 0;
}
@@ -1389,17 +1401,18 @@ N_("j - leave this hunk undecided, see next undecided hunk\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"
+ "p - print the current hunk, 'P' to use the pager\n"
"? - print help\n");
static int patch_update_file(struct add_p_state *s,
struct file_diff *file_diff)
{
size_t hunk_index = 0;
- ssize_t i, undecided_previous, undecided_next;
+ ssize_t i, undecided_previous, undecided_next, rendered_hunk_index = -1;
struct hunk *hunk;
char ch;
struct child_process cp = CHILD_PROCESS_INIT;
- int colored = !!s->colored.len, quit = 0;
+ int colored = !!s->colored.len, quit = 0, use_pager = 0;
enum prompt_mode_type prompt_mode_type;
enum {
ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
@@ -1448,8 +1461,20 @@ static int patch_update_file(struct add_p_state *s,
strbuf_reset(&s->buf);
if (file_diff->hunk_nr) {
- render_hunk(s, hunk, 0, colored, &s->buf);
- fputs(s->buf.buf, stdout);
+ if (rendered_hunk_index != hunk_index) {
+ if (use_pager) {
+ setup_pager();
+ sigchain_push(SIGPIPE, SIG_IGN);
+ }
+ render_hunk(s, hunk, 0, colored, &s->buf);
+ fputs(s->buf.buf, stdout);
+ rendered_hunk_index = hunk_index;
+ if (use_pager) {
+ sigchain_pop(SIGPIPE);
+ wait_for_pager();
+ use_pager = 0;
+ }
+ }
strbuf_reset(&s->buf);
if (undecided_previous >= 0) {
@@ -1481,6 +1506,7 @@ static int patch_update_file(struct add_p_state *s,
permitted |= ALLOW_EDIT;
strbuf_addstr(&s->buf, ",e");
}
+ strbuf_addstr(&s->buf, ",p");
}
if (file_diff->deleted)
prompt_mode_type = PROMPT_DELETION;
@@ -1507,6 +1533,12 @@ static int patch_update_file(struct add_p_state *s,
if (!s->answer.len)
continue;
ch = tolower(s->answer.buf[0]);
+
+ /* 'g' takes a hunk number and '/' takes a regexp */
+ if (s->answer.len != 1 && (ch != 'g' && ch != '/')) {
+ err(s, _("Only one letter is expected, got '%s'"), s->answer.buf);
+ continue;
+ }
if (ch == 'y') {
hunk->use = USE_HUNK;
soft_increment:
@@ -1642,16 +1674,19 @@ soft_increment:
err(s, _("No hunk matches the given pattern"));
break;
}
+ regfree(&regex);
hunk_index = i;
} else if (s->answer.buf[0] == 's') {
size_t splittable_into = hunk->splittable_into;
- if (!(permitted & ALLOW_SPLIT))
+ if (!(permitted & ALLOW_SPLIT)) {
err(s, _("Sorry, cannot split this hunk"));
- else if (!split_hunk(s, file_diff,
- hunk - file_diff->hunk))
+ } else if (!split_hunk(s, file_diff,
+ hunk - file_diff->hunk)) {
color_fprintf_ln(stdout, s->s.header_color,
_("Split into %d hunks."),
(int)splittable_into);
+ rendered_hunk_index = -1;
+ }
} else if (s->answer.buf[0] == 'e') {
if (!(permitted & ALLOW_EDIT))
err(s, _("Sorry, cannot edit this hunk"));
@@ -1659,7 +1694,10 @@ soft_increment:
hunk->use = USE_HUNK;
goto soft_increment;
}
- } else {
+ } else if (ch == 'p') {
+ rendered_hunk_index = -1;
+ use_pager = (s->answer.buf[0] == 'P') ? 1 : 0;
+ } else if (s->answer.buf[0] == '?') {
const char *p = _(help_patch_remainder), *eol = p;
color_fprintf(stdout, s->s.help_color, "%s",
@@ -1683,6 +1721,9 @@ soft_increment:
color_fprintf_ln(stdout, s->s.help_color,
"%.*s", (int)(eol - p), p);
}
+ } else {
+ err(s, _("Unknown command '%s' (use '?' for help)"),
+ s->answer.buf);
}
}
@@ -1730,14 +1771,6 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
if (mode == ADD_P_STASH)
s.mode = &patch_mode_stash;
else if (mode == ADD_P_RESET) {
- /*
- * NEEDSWORK: Instead of comparing to the literal "HEAD",
- * compare the commit objects instead so that other ways of
- * saying the same thing (such as "@") are also handled
- * appropriately.
- *
- * This applies to the cases below too.
- */
if (!revision || !strcmp(revision, "HEAD"))
s.mode = &patch_mode_reset_head;
else
@@ -1777,9 +1810,9 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
break;
if (s.file_diff_nr == 0)
- fprintf(stderr, _("No changes.\n"));
+ err(&s, _("No changes."));
else if (binary_count == s.file_diff_nr)
- fprintf(stderr, _("Only binary files changed.\n"));
+ err(&s, _("Only binary files changed."));
add_p_state_clear(&s);
return 0;
diff --git a/advice.c b/advice.c
index 50c79443ba..6b879d805c 100644
--- a/advice.c
+++ b/advice.c
@@ -2,6 +2,7 @@
#include "advice.h"
#include "config.h"
#include "color.h"
+#include "environment.h"
#include "gettext.h"
#include "help.h"
#include "string-list.h"
@@ -33,52 +34,61 @@ static const char *advise_get_color(enum color_advice ix)
return "";
}
+enum advice_level {
+ ADVICE_LEVEL_NONE = 0,
+ ADVICE_LEVEL_DISABLED,
+ ADVICE_LEVEL_ENABLED,
+};
+
static struct {
const char *key;
- int enabled;
+ enum advice_level level;
} advice_setting[] = {
- [ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo", 1 },
- [ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec", 1 },
- [ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile", 1 },
- [ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
- [ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec", 1 },
- [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
- [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 },
- [ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity", 1 },
- [ADVICE_NESTED_TAG] = { "nestedTag", 1 },
- [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning", 1 },
- [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists", 1 },
- [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst", 1 },
- [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce", 1 },
- [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate", 1 },
-
- /* make this an alias for backward compatibility */
- [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward", 1 },
-
- [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent", 1 },
- [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching", 1 },
- [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName", 1 },
- [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected", 1 },
- [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh", 1 },
- [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict", 1 },
- [ADVICE_RM_HINTS] = { "rmHints", 1 },
- [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
- [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure", 1 },
- [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks", 1 },
- [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning", 1 },
- [ADVICE_STATUS_HINTS] = { "statusHints", 1 },
- [ADVICE_STATUS_U_OPTION] = { "statusUoption", 1 },
- [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie", 1 },
- [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated", 1 },
- [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath", 1 },
- [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor", 1 },
- [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan", 1 },
+ [ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo" },
+ [ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec" },
+ [ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile" },
+ [ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec" },
+ [ADVICE_AM_WORK_DIR] = { "amWorkDir" },
+ [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName" },
+ [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge" },
+ [ADVICE_DETACHED_HEAD] = { "detachedHead" },
+ [ADVICE_DIVERGING] = { "diverging" },
+ [ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates" },
+ [ADVICE_FORCE_DELETE_BRANCH] = { "forceDeleteBranch" },
+ [ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated" },
+ [ADVICE_IGNORED_HOOK] = { "ignoredHook" },
+ [ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity" },
+ [ADVICE_MERGE_CONFLICT] = { "mergeConflict" },
+ [ADVICE_NESTED_TAG] = { "nestedTag" },
+ [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning" },
+ [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists" },
+ [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst" },
+ [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce" },
+ [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent" },
+ [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching" },
+ [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate" },
+ [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
+ [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
+ [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
+ [ADVICE_REBASE_TODO_ERROR] = { "rebaseTodoError" },
+ [ADVICE_REF_SYNTAX] = { "refSyntax" },
+ [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
+ [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },
+ [ADVICE_RM_HINTS] = { "rmHints" },
+ [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse" },
+ [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure" },
+ [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks" },
+ [ADVICE_SPARSE_INDEX_EXPANDED] = { "sparseIndexExpanded" },
+ [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning" },
+ [ADVICE_STATUS_HINTS] = { "statusHints" },
+ [ADVICE_STATUS_U_OPTION] = { "statusUoption" },
+ [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated" },
+ [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie" },
+ [ADVICE_SUBMODULE_MERGE_CONFLICT] = { "submoduleMergeConflict" },
+ [ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead" },
+ [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath" },
+ [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor" },
+ [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan" },
};
static const char turn_off_instructions[] =
@@ -98,8 +108,9 @@ static void vadvise(const char *advice, int display_instructions,
for (cp = buf.buf; *cp; cp = np) {
np = strchrnul(cp, '\n');
- fprintf(stderr, _("%shint: %.*s%s\n"),
+ fprintf(stderr, _("%shint:%s%.*s%s\n"),
advise_get_color(ADVICE_COLOR_HINT),
+ (np == cp) ? "" : " ",
(int)(np - cp), cp,
advise_get_color(ADVICE_COLOR_RESET));
if (*np)
@@ -118,13 +129,19 @@ void advise(const char *advice, ...)
int advice_enabled(enum advice_type type)
{
- switch(type) {
- case ADVICE_PUSH_UPDATE_REJECTED:
- return advice_setting[ADVICE_PUSH_UPDATE_REJECTED].enabled &&
- advice_setting[ADVICE_PUSH_UPDATE_REJECTED_ALIAS].enabled;
- default:
- return advice_setting[type].enabled;
- }
+ int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
+ static int globally_enabled = -1;
+
+ if (globally_enabled < 0)
+ globally_enabled = git_env_bool(GIT_ADVICE_ENVIRONMENT, 1);
+ if (!globally_enabled)
+ return 0;
+
+ if (type == ADVICE_PUSH_UPDATE_REJECTED)
+ return enabled &&
+ advice_enabled(ADVICE_PUSH_UPDATE_REJECTED_ALIAS);
+
+ return enabled;
}
void advise_if_enabled(enum advice_type type, const char *advice, ...)
@@ -135,7 +152,8 @@ void advise_if_enabled(enum advice_type type, const char *advice, ...)
return;
va_start(params, advice);
- vadvise(advice, 1, advice_setting[type].key, params);
+ vadvise(advice, !advice_setting[type].level, advice_setting[type].key,
+ params);
va_end(params);
}
@@ -164,7 +182,9 @@ int git_default_advice_config(const char *var, const char *value)
for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
if (strcasecmp(k, advice_setting[i].key))
continue;
- advice_setting[i].enabled = git_config_bool(var, value);
+ advice_setting[i].level = git_config_bool(var, value)
+ ? ADVICE_LEVEL_ENABLED
+ : ADVICE_LEVEL_DISABLED;
return 0;
}
diff --git a/advice.h b/advice.h
index 2affbe1426..d7466bc0ef 100644
--- a/advice.h
+++ b/advice.h
@@ -10,21 +10,22 @@ struct string_list;
* Add the new config variable to Documentation/config/advice.txt.
* Call advise_if_enabled to print your advice.
*/
- enum advice_type {
+enum advice_type {
ADVICE_ADD_EMBEDDED_REPO,
ADVICE_ADD_EMPTY_PATHSPEC,
ADVICE_ADD_IGNORED_FILE,
- ADVICE_AM_WORK_DIR,
ADVICE_AMBIGUOUS_FETCH_REFSPEC,
+ ADVICE_AM_WORK_DIR,
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_FORCE_DELETE_BRANCH,
ADVICE_GRAFT_FILE_DEPRECATED,
ADVICE_IGNORED_HOOK,
ADVICE_IMPLICIT_IDENTITY,
+ ADVICE_MERGE_CONFLICT,
ADVICE_NESTED_TAG,
ADVICE_OBJECT_NAME_WARNING,
ADVICE_PUSH_ALREADY_EXISTS,
@@ -32,23 +33,28 @@ struct string_list;
ADVICE_PUSH_NEEDS_FORCE,
ADVICE_PUSH_NON_FF_CURRENT,
ADVICE_PUSH_NON_FF_MATCHING,
+ ADVICE_PUSH_REF_NEEDS_UPDATE,
ADVICE_PUSH_UNQUALIFIED_REF_NAME,
- ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
ADVICE_PUSH_UPDATE_REJECTED,
- ADVICE_PUSH_REF_NEEDS_UPDATE,
+ ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
+ ADVICE_REBASE_TODO_ERROR,
+ ADVICE_REF_SYNTAX,
ADVICE_RESET_NO_REFRESH_WARNING,
ADVICE_RESOLVE_CONFLICT,
ADVICE_RM_HINTS,
ADVICE_SEQUENCER_IN_USE,
ADVICE_SET_UPSTREAM_FAILURE,
+ ADVICE_SKIPPED_CHERRY_PICKS,
+ ADVICE_SPARSE_INDEX_EXPANDED,
ADVICE_STATUS_AHEAD_BEHIND_WARNING,
ADVICE_STATUS_HINTS,
ADVICE_STATUS_U_OPTION,
- ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
ADVICE_SUBMODULES_NOT_UPDATED,
+ ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
+ ADVICE_SUBMODULE_MERGE_CONFLICT,
+ ADVICE_SUGGEST_DETACHING_HEAD,
ADVICE_UPDATE_SPARSE_PATH,
ADVICE_WAITING_FOR_EDITOR,
- ADVICE_SKIPPED_CHERRY_PICKS,
ADVICE_WORKTREE_ADD_ORPHAN,
};
diff --git a/alias.c b/alias.c
index 5a238f2e30..1a1a141a0a 100644
--- a/alias.c
+++ b/alias.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "alias.h"
#include "config.h"
@@ -21,9 +23,11 @@ static int config_alias_cb(const char *key, const char *value,
return 0;
if (data->alias) {
- if (!strcasecmp(p, data->alias))
- return git_config_string((const char **)&data->v,
+ if (!strcasecmp(p, data->alias)) {
+ FREE_AND_NULL(data->v);
+ return git_config_string(&data->v,
key, value);
+ }
} else if (data->list) {
string_list_append(data->list, p);
}
@@ -35,7 +39,7 @@ char *alias_lookup(const char *alias)
{
struct config_alias_data data = { alias, NULL };
- read_early_config(config_alias_cb, &data);
+ read_early_config(the_repository, config_alias_cb, &data);
return data.v;
}
@@ -44,7 +48,7 @@ void list_aliases(struct string_list *list)
{
struct config_alias_data data = { NULL, NULL, list };
- read_early_config(config_alias_cb, &data);
+ read_early_config(the_repository, config_alias_cb, &data);
}
void quote_cmdline(struct strbuf *buf, const char **argv)
diff --git a/apply.c b/apply.c
index 3d69fec836..a3fc2d5330 100644
--- a/apply.c
+++ b/apply.c
@@ -7,12 +7,13 @@
*
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "base85.h"
#include "config.h"
#include "object-store-ll.h"
-#include "blob.h"
#include "delta.h"
#include "diff.h"
#include "dir.h"
@@ -29,6 +30,7 @@
#include "path.h"
#include "quote.h"
#include "read-cache.h"
+#include "repository.h"
#include "rerere.h"
#include "apply.h"
#include "entry.h"
@@ -78,7 +80,8 @@ static int parse_whitespace_option(struct apply_state *state, const char *option
return 0;
}
/*
- * Please update $__git_whitespacelist in git-completion.bash
+ * Please update $__git_whitespacelist in git-completion.bash,
+ * Documentation/git-apply.txt, and Documentation/git-am.txt
* when you add new options.
*/
return error(_("unrecognized whitespace option '%s'"), option);
@@ -135,6 +138,7 @@ void clear_apply_state(struct apply_state *state)
strset_clear(&state->removed_symlinks);
strset_clear(&state->kept_symlinks);
strbuf_release(&state->root);
+ FREE_AND_NULL(state->fake_ancestor);
/* &state->fn_table is cleared at the end of apply_patch() */
}
@@ -274,13 +278,26 @@ struct line {
* This represents a "file", which is an array of "lines".
*/
struct image {
- char *buf;
- size_t len;
- size_t nr;
- size_t alloc;
- struct line *line_allocated;
+ struct strbuf buf;
struct line *line;
+ size_t line_nr, line_alloc;
};
+#define IMAGE_INIT { \
+ .buf = STRBUF_INIT, \
+}
+
+static void image_init(struct image *image)
+{
+ struct image empty = IMAGE_INIT;
+ memcpy(image, &empty, sizeof(*image));
+}
+
+static void image_clear(struct image *image)
+{
+ strbuf_release(&image->buf);
+ free(image->line);
+ image_init(image);
+}
static uint32_t hash_line(const char *cp, size_t len)
{
@@ -294,49 +311,13 @@ static uint32_t hash_line(const char *cp, size_t len)
return h;
}
-/*
- * Compare lines s1 of length n1 and s2 of length n2, ignoring
- * whitespace difference. Returns 1 if they match, 0 otherwise
- */
-static int fuzzy_matchlines(const char *s1, size_t n1,
- const char *s2, size_t n2)
-{
- const char *end1 = s1 + n1;
- const char *end2 = s2 + n2;
-
- /* ignore line endings */
- while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
- end1--;
- while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
- end2--;
-
- while (s1 < end1 && s2 < end2) {
- if (isspace(*s1)) {
- /*
- * Skip whitespace. We check on both buffers
- * because we don't want "a b" to match "ab".
- */
- if (!isspace(*s2))
- return 0;
- while (s1 < end1 && isspace(*s1))
- s1++;
- while (s2 < end2 && isspace(*s2))
- s2++;
- } else if (*s1++ != *s2++)
- return 0;
- }
-
- /* If we reached the end on one side only, lines don't match. */
- return s1 == end1 && s2 == end2;
-}
-
-static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)
+static void image_add_line(struct image *img, const char *bol, size_t len, unsigned flag)
{
- ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);
- img->line_allocated[img->nr].len = len;
- img->line_allocated[img->nr].hash = hash_line(bol, len);
- img->line_allocated[img->nr].flag = flag;
- img->nr++;
+ ALLOC_GROW(img->line, img->line_nr + 1, img->line_alloc);
+ img->line[img->line_nr].len = len;
+ img->line[img->line_nr].hash = hash_line(bol, len);
+ img->line[img->line_nr].flag = flag;
+ img->line_nr++;
}
/*
@@ -344,37 +325,43 @@ static void add_line_info(struct image *img, const char *bol, size_t len, unsign
* attach it to "image" and add line-based index to it.
* "image" now owns the "buf".
*/
-static void prepare_image(struct image *image, char *buf, size_t len,
+static void image_prepare(struct image *image, char *buf, size_t len,
int prepare_linetable)
{
const char *cp, *ep;
- memset(image, 0, sizeof(*image));
- image->buf = buf;
- image->len = len;
+ image_clear(image);
+ strbuf_attach(&image->buf, buf, len, len + 1);
if (!prepare_linetable)
return;
- ep = image->buf + image->len;
- cp = image->buf;
+ ep = image->buf.buf + image->buf.len;
+ cp = image->buf.buf;
while (cp < ep) {
const char *next;
for (next = cp; next < ep && *next != '\n'; next++)
;
if (next < ep)
next++;
- add_line_info(image, cp, next - cp, 0);
+ image_add_line(image, cp, next - cp, 0);
cp = next;
}
- image->line = image->line_allocated;
}
-static void clear_image(struct image *image)
+static void image_remove_first_line(struct image *img)
{
- free(image->buf);
- free(image->line_allocated);
- memset(image, 0, sizeof(*image));
+ strbuf_remove(&img->buf, 0, img->line[0].len);
+ img->line_nr--;
+ if (img->line_nr)
+ MOVE_ARRAY(img->line, img->line + 1, img->line_nr);
+}
+
+static void image_remove_last_line(struct image *img)
+{
+ size_t last_line_len = img->line[img->line_nr - 1].len;
+ strbuf_setlen(&img->buf, img->buf.len - last_line_len);
+ img->line_nr--;
}
/* fmt must contain _one_ %s and no other substitution */
@@ -992,6 +979,7 @@ static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
*mode = strtoul(line, &end, 8);
if (end == line || !isspace(*end))
return error(_("invalid mode on line %d: %s"), linenr, line);
+ *mode = canon_mode(*mode);
return 0;
}
@@ -1292,8 +1280,15 @@ static char *git_header_name(int p_value,
return NULL; /* no postimage name */
second = skip_tree_prefix(p_value, name + len + 1,
line_len - (len + 1));
+ /*
+ * If we are at the SP at the end of a directory,
+ * skip_tree_prefix() may return NULL as that makes
+ * it appears as if we have an absolute path.
+ * Keep going to find another SP.
+ */
if (!second)
- return NULL;
+ continue;
+
/*
* Does len bytes starting at "name" and "second"
* (that are separated by one HT or SP we just
@@ -2220,7 +2215,8 @@ static void reverse_patches(struct patch *p)
struct fragment *frag = p->fragments;
SWAP(p->new_name, p->old_name);
- SWAP(p->new_mode, p->old_mode);
+ if (p->new_mode)
+ SWAP(p->new_mode, p->old_mode);
SWAP(p->is_new, p->is_delete);
SWAP(p->lines_added, p->lines_deleted);
SWAP(p->old_oid_prefix, p->new_oid_prefix);
@@ -2314,65 +2310,43 @@ static int read_old_data(struct stat *st, struct patch *patch,
/*
* Update the preimage, and the common lines in postimage,
- * from buffer buf of length len. If postlen is 0 the postimage
- * is updated in place, otherwise it's updated on a new buffer
- * of length postlen
+ * from buffer buf of length len.
*/
-
static void update_pre_post_images(struct image *preimage,
struct image *postimage,
- char *buf,
- size_t len, size_t postlen)
+ char *buf, size_t len)
{
+ struct image fixed_preimage = IMAGE_INIT;
+ size_t insert_pos = 0;
int i, ctx, reduced;
- char *new_buf, *old_buf, *fixed;
- struct image fixed_preimage;
+ const char *fixed;
/*
* Update the preimage with whitespace fixes. Note that we
* are not losing preimage->buf -- apply_one_fragment() will
* free "oldlines".
*/
- prepare_image(&fixed_preimage, buf, len, 1);
- assert(postlen
- ? fixed_preimage.nr == preimage->nr
- : fixed_preimage.nr <= preimage->nr);
- for (i = 0; i < fixed_preimage.nr; i++)
+ image_prepare(&fixed_preimage, buf, len, 1);
+ for (i = 0; i < fixed_preimage.line_nr; i++)
fixed_preimage.line[i].flag = preimage->line[i].flag;
- free(preimage->line_allocated);
+ image_clear(preimage);
*preimage = fixed_preimage;
+ fixed = preimage->buf.buf;
/*
- * Adjust the common context lines in postimage. This can be
- * done in-place when we are shrinking it with whitespace
- * fixing, but needs a new buffer when ignoring whitespace or
- * expanding leading tabs to spaces.
- *
- * We trust the caller to tell us if the update can be done
- * in place (postlen==0) or not.
+ * Adjust the common context lines in postimage.
*/
- old_buf = postimage->buf;
- if (postlen)
- new_buf = postimage->buf = xmalloc(postlen);
- else
- new_buf = old_buf;
- fixed = preimage->buf;
-
- for (i = reduced = ctx = 0; i < postimage->nr; i++) {
+ for (i = reduced = ctx = 0; i < postimage->line_nr; i++) {
size_t l_len = postimage->line[i].len;
+
if (!(postimage->line[i].flag & LINE_COMMON)) {
/* an added line -- no counterparts in preimage */
- memmove(new_buf, old_buf, l_len);
- old_buf += l_len;
- new_buf += l_len;
+ insert_pos += l_len;
continue;
}
- /* a common context -- skip it in the original postimage */
- old_buf += l_len;
-
/* and find the corresponding one in the fixed preimage */
- while (ctx < preimage->nr &&
+ while (ctx < preimage->line_nr &&
!(preimage->line[ctx].flag & LINE_COMMON)) {
fixed += preimage->line[ctx].len;
ctx++;
@@ -2382,29 +2356,59 @@ static void update_pre_post_images(struct image *preimage,
* preimage is expected to run out, if the caller
* fixed addition of trailing blank lines.
*/
- if (preimage->nr <= ctx) {
+ if (preimage->line_nr <= ctx) {
reduced++;
continue;
}
/* and copy it in, while fixing the line length */
l_len = preimage->line[ctx].len;
- memcpy(new_buf, fixed, l_len);
- new_buf += l_len;
+ strbuf_splice(&postimage->buf, insert_pos, postimage->line[i].len,
+ fixed, l_len);
+ insert_pos += l_len;
fixed += l_len;
postimage->line[i].len = l_len;
ctx++;
}
- if (postlen
- ? postlen < new_buf - postimage->buf
- : postimage->len < new_buf - postimage->buf)
- BUG("caller miscounted postlen: asked %d, orig = %d, used = %d",
- (int)postlen, (int) postimage->len, (int)(new_buf - postimage->buf));
-
/* Fix the length of the whole thing */
- postimage->len = new_buf - postimage->buf;
- postimage->nr -= reduced;
+ postimage->line_nr -= reduced;
+}
+
+/*
+ * Compare lines s1 of length n1 and s2 of length n2, ignoring
+ * whitespace difference. Returns 1 if they match, 0 otherwise
+ */
+static int fuzzy_matchlines(const char *s1, size_t n1,
+ const char *s2, size_t n2)
+{
+ const char *end1 = s1 + n1;
+ const char *end2 = s2 + n2;
+
+ /* ignore line endings */
+ while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
+ end1--;
+ while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
+ end2--;
+
+ while (s1 < end1 && s2 < end2) {
+ if (isspace(*s1)) {
+ /*
+ * Skip whitespace. We check on both buffers
+ * because we don't want "a b" to match "ab".
+ */
+ if (!isspace(*s2))
+ return 0;
+ while (s1 < end1 && isspace(*s1))
+ s1++;
+ while (s2 < end2 && isspace(*s2))
+ s2++;
+ } else if (*s1++ != *s2++)
+ return 0;
+ }
+
+ /* If we reached the end on one side only, lines don't match. */
+ return s1 == end1 && s2 == end2;
}
static int line_by_line_fuzzy_match(struct image *img,
@@ -2417,7 +2421,6 @@ static int line_by_line_fuzzy_match(struct image *img,
int i;
size_t imgoff = 0;
size_t preoff = 0;
- size_t postlen = postimage->len;
size_t extra_chars;
char *buf;
char *preimage_eof;
@@ -2430,11 +2433,9 @@ static int line_by_line_fuzzy_match(struct image *img,
size_t prelen = preimage->line[i].len;
size_t imglen = img->line[current_lno+i].len;
- if (!fuzzy_matchlines(img->buf + current + imgoff, imglen,
- preimage->buf + preoff, prelen))
+ if (!fuzzy_matchlines(img->buf.buf + current + imgoff, imglen,
+ preimage->buf.buf + preoff, prelen))
return 0;
- if (preimage->line[i].flag & LINE_COMMON)
- postlen += imglen - prelen;
imgoff += imglen;
preoff += prelen;
}
@@ -2450,10 +2451,10 @@ static int line_by_line_fuzzy_match(struct image *img,
* are whitespace characters. (This can only happen if
* we are removing blank lines at the end of the file.)
*/
- buf = preimage_eof = preimage->buf + preoff;
- for ( ; i < preimage->nr; i++)
+ buf = preimage_eof = preimage->buf.buf + preoff;
+ for ( ; i < preimage->line_nr; i++)
preoff += preimage->line[i].len;
- preimage_end = preimage->buf + preoff;
+ preimage_end = preimage->buf.buf + preoff;
for ( ; buf < preimage_end; buf++)
if (!isspace(*buf))
return 0;
@@ -2467,11 +2468,11 @@ static int line_by_line_fuzzy_match(struct image *img,
*/
extra_chars = preimage_end - preimage_eof;
strbuf_init(&fixed, imgoff + extra_chars);
- strbuf_add(&fixed, img->buf + current, imgoff);
+ strbuf_add(&fixed, img->buf.buf + current, imgoff);
strbuf_add(&fixed, preimage_eof, extra_chars);
fixed_buf = strbuf_detach(&fixed, &fixed_len);
update_pre_post_images(preimage, postimage,
- fixed_buf, fixed_len, postlen);
+ fixed_buf, fixed_len);
return 1;
}
@@ -2485,18 +2486,22 @@ static int match_fragment(struct apply_state *state,
int match_beginning, int match_end)
{
int i;
- char *fixed_buf, *buf, *orig, *target;
- struct strbuf fixed;
- size_t fixed_len, postlen;
+ const char *orig, *target;
+ struct strbuf fixed = STRBUF_INIT;
+ char *fixed_buf;
+ size_t fixed_len;
int preimage_limit;
+ int ret;
- if (preimage->nr + current_lno <= img->nr) {
+ if (preimage->line_nr + current_lno <= img->line_nr) {
/*
* The hunk falls within the boundaries of img.
*/
- preimage_limit = preimage->nr;
- if (match_end && (preimage->nr + current_lno != img->nr))
- return 0;
+ preimage_limit = preimage->line_nr;
+ if (match_end && (preimage->line_nr + current_lno != img->line_nr)) {
+ ret = 0;
+ goto out;
+ }
} else if (state->ws_error_action == correct_ws_error &&
(ws_rule & WS_BLANK_AT_EOF)) {
/*
@@ -2506,26 +2511,32 @@ static int match_fragment(struct apply_state *state,
* match with img, and the remainder of the preimage
* must be blank.
*/
- preimage_limit = img->nr - current_lno;
+ preimage_limit = img->line_nr - current_lno;
} else {
/*
* The hunk extends beyond the end of the img and
* we are not removing blanks at the end, so we
* should reject the hunk at this position.
*/
- return 0;
+ ret = 0;
+ goto out;
}
- if (match_beginning && current_lno)
- return 0;
+ if (match_beginning && current_lno) {
+ ret = 0;
+ goto out;
+ }
/* Quick hash check */
- for (i = 0; i < preimage_limit; i++)
+ for (i = 0; i < preimage_limit; i++) {
if ((img->line[current_lno + i].flag & LINE_PATCHED) ||
- (preimage->line[i].hash != img->line[current_lno + i].hash))
- return 0;
+ (preimage->line[i].hash != img->line[current_lno + i].hash)) {
+ ret = 0;
+ goto out;
+ }
+ }
- if (preimage_limit == preimage->nr) {
+ if (preimage_limit == preimage->line_nr) {
/*
* Do we have an exact match? If we were told to match
* at the end, size must be exactly at current+fragsize,
@@ -2534,10 +2545,12 @@ static int match_fragment(struct apply_state *state,
* exactly.
*/
if ((match_end
- ? (current + preimage->len == img->len)
- : (current + preimage->len <= img->len)) &&
- !memcmp(img->buf + current, preimage->buf, preimage->len))
- return 1;
+ ? (current + preimage->buf.len == img->buf.len)
+ : (current + preimage->buf.len <= img->buf.len)) &&
+ !memcmp(img->buf.buf + current, preimage->buf.buf, preimage->buf.len)) {
+ ret = 1;
+ goto out;
+ }
} else {
/*
* The preimage extends beyond the end of img, so
@@ -2546,9 +2559,9 @@ static int match_fragment(struct apply_state *state,
* There must be one non-blank context line that match
* a line before the end of img.
*/
- char *buf_end;
+ const char *buf, *buf_end;
- buf = preimage->buf;
+ buf = preimage->buf.buf;
buf_end = buf;
for (i = 0; i < preimage_limit; i++)
buf_end += preimage->line[i].len;
@@ -2556,8 +2569,10 @@ static int match_fragment(struct apply_state *state,
for ( ; buf < buf_end; buf++)
if (!isspace(*buf))
break;
- if (buf == buf_end)
- return 0;
+ if (buf == buf_end) {
+ ret = 0;
+ goto out;
+ }
}
/*
@@ -2565,12 +2580,16 @@ static int match_fragment(struct apply_state *state,
* fuzzy matching. We collect all the line length information because
* we need it to adjust whitespace if we match.
*/
- if (state->ws_ignore_action == ignore_ws_change)
- return line_by_line_fuzzy_match(img, preimage, postimage,
- current, current_lno, preimage_limit);
+ if (state->ws_ignore_action == ignore_ws_change) {
+ ret = line_by_line_fuzzy_match(img, preimage, postimage,
+ current, current_lno, preimage_limit);
+ goto out;
+ }
- if (state->ws_error_action != correct_ws_error)
- return 0;
+ if (state->ws_error_action != correct_ws_error) {
+ ret = 0;
+ goto out;
+ }
/*
* The hunk does not apply byte-by-byte, but the hash says
@@ -2587,21 +2606,14 @@ static int match_fragment(struct apply_state *state,
* fixed.
*/
- /* First count added lines in postimage */
- postlen = 0;
- for (i = 0; i < postimage->nr; i++) {
- if (!(postimage->line[i].flag & LINE_COMMON))
- postlen += postimage->line[i].len;
- }
-
/*
* The preimage may extend beyond the end of the file,
* but in this loop we will only handle the part of the
* preimage that falls within the file.
*/
- strbuf_init(&fixed, preimage->len + 1);
- orig = preimage->buf;
- target = img->buf + current;
+ strbuf_grow(&fixed, preimage->buf.len + 1);
+ orig = preimage->buf.buf;
+ target = img->buf.buf + current;
for (i = 0; i < preimage_limit; i++) {
size_t oldlen = preimage->line[i].len;
size_t tgtlen = img->line[current_lno + i].len;
@@ -2630,13 +2642,11 @@ static int match_fragment(struct apply_state *state,
!memcmp(tgtfix.buf, fixed.buf + fixstart,
fixed.len - fixstart));
- /* Add the length if this is common with the postimage */
- if (preimage->line[i].flag & LINE_COMMON)
- postlen += tgtfix.len;
-
strbuf_release(&tgtfix);
- if (!match)
- goto unmatch_exit;
+ if (!match) {
+ ret = 0;
+ goto out;
+ }
orig += oldlen;
target += tgtlen;
@@ -2649,7 +2659,7 @@ static int match_fragment(struct apply_state *state,
* empty or only contain whitespace (if WS_BLANK_AT_EOL is
* false).
*/
- for ( ; i < preimage->nr; i++) {
+ for ( ; i < preimage->line_nr; i++) {
size_t fixstart = fixed.len; /* start of the fixed preimage */
size_t oldlen = preimage->line[i].len;
int j;
@@ -2657,9 +2667,13 @@ static int match_fragment(struct apply_state *state,
/* Try fixing the line in the preimage */
ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
- for (j = fixstart; j < fixed.len; j++)
- if (!isspace(fixed.buf[j]))
- goto unmatch_exit;
+ for (j = fixstart; j < fixed.len; j++) {
+ if (!isspace(fixed.buf[j])) {
+ ret = 0;
+ goto out;
+ }
+ }
+
orig += oldlen;
}
@@ -2670,15 +2684,14 @@ static int match_fragment(struct apply_state *state,
* hunk match. Update the context lines in the postimage.
*/
fixed_buf = strbuf_detach(&fixed, &fixed_len);
- if (postlen < postimage->len)
- postlen = 0;
update_pre_post_images(preimage, postimage,
- fixed_buf, fixed_len, postlen);
- return 1;
+ fixed_buf, fixed_len);
- unmatch_exit:
+ ret = 1;
+
+out:
strbuf_release(&fixed);
- return 0;
+ return ret;
}
static int find_pos(struct apply_state *state,
@@ -2700,7 +2713,7 @@ static int find_pos(struct apply_state *state,
* than `match_beginning`.
*/
if (state->allow_overlap && match_beginning && match_end &&
- img->nr - preimage->nr != 0)
+ img->line_nr - preimage->line_nr != 0)
match_beginning = 0;
/*
@@ -2711,15 +2724,15 @@ static int find_pos(struct apply_state *state,
if (match_beginning)
line = 0;
else if (match_end)
- line = img->nr - preimage->nr;
+ line = img->line_nr - preimage->line_nr;
/*
* Because the comparison is unsigned, the following test
* will also take care of a negative line number that can
* result when match_end and preimage is larger than the target.
*/
- if ((size_t) line > img->nr)
- line = img->nr;
+ if ((size_t) line > img->line_nr)
+ line = img->line_nr;
current = 0;
for (i = 0; i < line; i++)
@@ -2742,7 +2755,7 @@ static int find_pos(struct apply_state *state,
return current_lno;
again:
- if (backwards_lno == 0 && forwards_lno == img->nr)
+ if (backwards_lno == 0 && forwards_lno == img->line_nr)
break;
if (i & 1) {
@@ -2755,7 +2768,7 @@ static int find_pos(struct apply_state *state,
current = backwards;
current_lno = backwards_lno;
} else {
- if (forwards_lno == img->nr) {
+ if (forwards_lno == img->line_nr) {
i++;
goto again;
}
@@ -2769,19 +2782,6 @@ static int find_pos(struct apply_state *state,
return -1;
}
-static void remove_first_line(struct image *img)
-{
- img->buf += img->line[0].len;
- img->len -= img->line[0].len;
- img->line++;
- img->nr--;
-}
-
-static void remove_last_line(struct image *img)
-{
- img->len -= img->line[--img->nr].len;
-}
-
/*
* The change from "preimage" and "postimage" has been found to
* apply at applied_pos (counts in line numbers) in "img".
@@ -2799,6 +2799,7 @@ static void update_image(struct apply_state *state,
*/
int i, nr;
size_t remove_count, insert_count, applied_at = 0;
+ size_t result_alloc;
char *result;
int preimage_limit;
@@ -2811,9 +2812,9 @@ static void update_image(struct apply_state *state,
* to the number of lines in the preimage that falls
* within the boundaries.
*/
- preimage_limit = preimage->nr;
- if (preimage_limit > img->nr - applied_pos)
- preimage_limit = img->nr - applied_pos;
+ preimage_limit = preimage->line_nr;
+ if (preimage_limit > img->line_nr - applied_pos)
+ preimage_limit = img->line_nr - applied_pos;
for (i = 0; i < applied_pos; i++)
applied_at += img->line[i].len;
@@ -2821,39 +2822,36 @@ static void update_image(struct apply_state *state,
remove_count = 0;
for (i = 0; i < preimage_limit; i++)
remove_count += img->line[applied_pos + i].len;
- insert_count = postimage->len;
+ insert_count = postimage->buf.len;
/* Adjust the contents */
- result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));
- memcpy(result, img->buf, applied_at);
- memcpy(result + applied_at, postimage->buf, postimage->len);
- memcpy(result + applied_at + postimage->len,
- img->buf + (applied_at + remove_count),
- img->len - (applied_at + remove_count));
- free(img->buf);
- img->buf = result;
- img->len += insert_count - remove_count;
- result[img->len] = '\0';
+ result_alloc = st_add3(st_sub(img->buf.len, remove_count), insert_count, 1);
+ result = xmalloc(result_alloc);
+ memcpy(result, img->buf.buf, applied_at);
+ memcpy(result + applied_at, postimage->buf.buf, postimage->buf.len);
+ memcpy(result + applied_at + postimage->buf.len,
+ img->buf.buf + (applied_at + remove_count),
+ img->buf.len - (applied_at + remove_count));
+ strbuf_attach(&img->buf, result, postimage->buf.len + img->buf.len - remove_count,
+ result_alloc);
/* Adjust the line table */
- nr = img->nr + postimage->nr - preimage_limit;
- if (preimage_limit < postimage->nr) {
+ nr = img->line_nr + postimage->line_nr - preimage_limit;
+ if (preimage_limit < postimage->line_nr)
/*
- * NOTE: this knows that we never call remove_first_line()
+ * NOTE: this knows that we never call image_remove_first_line()
* on anything other than pre/post image.
*/
REALLOC_ARRAY(img->line, nr);
- img->line_allocated = img->line;
- }
- if (preimage_limit != postimage->nr)
- MOVE_ARRAY(img->line + applied_pos + postimage->nr,
+ if (preimage_limit != postimage->line_nr)
+ MOVE_ARRAY(img->line + applied_pos + postimage->line_nr,
img->line + applied_pos + preimage_limit,
- img->nr - (applied_pos + preimage_limit));
- COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->nr);
+ img->line_nr - (applied_pos + preimage_limit));
+ COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->line_nr);
if (!state->allow_overlap)
- for (i = 0; i < postimage->nr; i++)
+ for (i = 0; i < postimage->line_nr; i++)
img->line[applied_pos + i].flag |= LINE_PATCHED;
- img->nr = nr;
+ img->line_nr = nr;
}
/*
@@ -2876,11 +2874,9 @@ static int apply_one_fragment(struct apply_state *state,
int hunk_linenr = frag->linenr;
unsigned long leading, trailing;
int pos, applied_pos;
- struct image preimage;
- struct image postimage;
+ struct image preimage = IMAGE_INIT;
+ struct image postimage = IMAGE_INIT;
- memset(&preimage, 0, sizeof(preimage));
- memset(&postimage, 0, sizeof(postimage));
oldlines = xmalloc(size);
strbuf_init(&newlines, size);
@@ -2922,8 +2918,8 @@ static int apply_one_fragment(struct apply_state *state,
break;
*old++ = '\n';
strbuf_addch(&newlines, '\n');
- add_line_info(&preimage, "\n", 1, LINE_COMMON);
- add_line_info(&postimage, "\n", 1, LINE_COMMON);
+ image_add_line(&preimage, "\n", 1, LINE_COMMON);
+ image_add_line(&postimage, "\n", 1, LINE_COMMON);
is_blank_context = 1;
break;
case ' ':
@@ -2933,7 +2929,7 @@ static int apply_one_fragment(struct apply_state *state,
/* fallthrough */
case '-':
memcpy(old, patch + 1, plen);
- add_line_info(&preimage, old, plen,
+ image_add_line(&preimage, old, plen,
(first == ' ' ? LINE_COMMON : 0));
old += plen;
if (first == '-')
@@ -2953,7 +2949,7 @@ static int apply_one_fragment(struct apply_state *state,
else {
ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &state->applied_after_fixing_ws);
}
- add_line_info(&postimage, newlines.buf + start, newlines.len - start,
+ image_add_line(&postimage, newlines.buf + start, newlines.len - start,
(first == '+' ? 0 : LINE_COMMON));
if (first == '+' &&
(ws_rule & WS_BLANK_AT_EOF) &&
@@ -2987,8 +2983,8 @@ static int apply_one_fragment(struct apply_state *state,
newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
old--;
strbuf_setlen(&newlines, newlines.len - 1);
- preimage.line_allocated[preimage.nr - 1].len--;
- postimage.line_allocated[postimage.nr - 1].len--;
+ preimage.line[preimage.line_nr - 1].len--;
+ postimage.line[postimage.line_nr - 1].len--;
}
leading = frag->leading;
@@ -3018,12 +3014,8 @@ static int apply_one_fragment(struct apply_state *state,
match_end = !state->unidiff_zero && !trailing;
pos = frag->newpos ? (frag->newpos - 1) : 0;
- preimage.buf = oldlines;
- preimage.len = old - oldlines;
- postimage.buf = newlines.buf;
- postimage.len = newlines.len;
- preimage.line = preimage.line_allocated;
- postimage.line = postimage.line_allocated;
+ strbuf_add(&preimage.buf, oldlines, old - oldlines);
+ strbuf_swap(&postimage.buf, &newlines);
for (;;) {
@@ -3047,28 +3039,28 @@ static int apply_one_fragment(struct apply_state *state,
* just reduce the larger context.
*/
if (leading >= trailing) {
- remove_first_line(&preimage);
- remove_first_line(&postimage);
+ image_remove_first_line(&preimage);
+ image_remove_first_line(&postimage);
pos--;
leading--;
}
if (trailing > leading) {
- remove_last_line(&preimage);
- remove_last_line(&postimage);
+ image_remove_last_line(&preimage);
+ image_remove_last_line(&postimage);
trailing--;
}
}
if (applied_pos >= 0) {
if (new_blank_lines_at_end &&
- preimage.nr + applied_pos >= img->nr &&
+ preimage.line_nr + applied_pos >= img->line_nr &&
(ws_rule & WS_BLANK_AT_EOF) &&
state->ws_error_action != nowarn_ws_error) {
record_ws_error(state, WS_BLANK_AT_EOF, "+", 1,
found_new_blank_lines_at_end);
if (state->ws_error_action == correct_ws_error) {
while (new_blank_lines_at_end--)
- remove_last_line(&postimage);
+ image_remove_last_line(&postimage);
}
/*
* We would want to prevent write_out_results()
@@ -3111,8 +3103,8 @@ static int apply_one_fragment(struct apply_state *state,
out:
free(oldlines);
strbuf_release(&newlines);
- free(preimage.line_allocated);
- free(postimage.line_allocated);
+ image_clear(&preimage);
+ image_clear(&postimage);
return (applied_pos < 0);
}
@@ -3142,18 +3134,16 @@ static int apply_binary_fragment(struct apply_state *state,
}
switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED:
- dst = patch_delta(img->buf, img->len, fragment->patch,
+ dst = patch_delta(img->buf.buf, img->buf.len, fragment->patch,
fragment->size, &len);
if (!dst)
return -1;
- clear_image(img);
- img->buf = dst;
- img->len = len;
+ image_clear(img);
+ strbuf_attach(&img->buf, dst, len, len + 1);
return 0;
case BINARY_LITERAL_DEFLATED:
- clear_image(img);
- img->len = fragment->size;
- img->buf = xmemdupz(fragment->patch, img->len);
+ image_clear(img);
+ strbuf_add(&img->buf, fragment->patch, fragment->size);
return 0;
}
return -1;
@@ -3189,8 +3179,8 @@ static int apply_binary(struct apply_state *state,
* See if the old one matches what the patch
* applies to.
*/
- hash_object_file(the_hash_algo, img->buf, img->len, OBJ_BLOB,
- &oid);
+ hash_object_file(the_hash_algo, img->buf.buf, img->buf.len,
+ OBJ_BLOB, &oid);
if (strcmp(oid_to_hex(&oid), patch->old_oid_prefix))
return error(_("the patch applies to '%s' (%s), "
"which does not match the "
@@ -3199,14 +3189,14 @@ static int apply_binary(struct apply_state *state,
}
else {
/* Otherwise, the old one must be empty. */
- if (img->len)
+ if (img->buf.len)
return error(_("the patch applies to an empty "
"'%s' but it is not empty"), name);
}
get_oid_hex(patch->new_oid_prefix, &oid);
if (is_null_oid(&oid)) {
- clear_image(img);
+ image_clear(img);
return 0; /* deletion patch */
}
@@ -3222,9 +3212,8 @@ static int apply_binary(struct apply_state *state,
return error(_("the necessary postimage %s for "
"'%s' cannot be read"),
patch->new_oid_prefix, name);
- clear_image(img);
- img->buf = result;
- img->len = size;
+ image_clear(img);
+ strbuf_attach(&img->buf, result, size, size + 1);
} else {
/*
* We have verified buf matches the preimage;
@@ -3236,7 +3225,7 @@ static int apply_binary(struct apply_state *state,
name);
/* verify that the result matches */
- hash_object_file(the_hash_algo, img->buf, img->len, OBJ_BLOB,
+ hash_object_file(the_hash_algo, img->buf.buf, img->buf.len, OBJ_BLOB,
&oid);
if (strcmp(oid_to_hex(&oid), patch->new_oid_prefix))
return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
@@ -3498,7 +3487,7 @@ static int load_preimage(struct apply_state *state,
}
img = strbuf_detach(&buf, &len);
- prepare_image(image, img, len, !patch->is_binary);
+ image_prepare(image, img, len, !patch->is_binary);
return 0;
}
@@ -3506,14 +3495,14 @@ static int resolve_to(struct image *image, const struct object_id *result_id)
{
unsigned long size;
enum object_type type;
+ char *data;
- clear_image(image);
+ image_clear(image);
- image->buf = repo_read_object_file(the_repository, result_id, &type,
- &size);
- if (!image->buf || type != OBJ_BLOB)
+ data = repo_read_object_file(the_repository, result_id, &type, &size);
+ if (!data || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(result_id));
- image->len = size;
+ strbuf_attach(&image->buf, data, size, size + 1);
return 0;
}
@@ -3526,6 +3515,7 @@ static int three_way_merge(struct apply_state *state,
const struct object_id *theirs)
{
mmfile_t base_file, our_file, their_file;
+ struct ll_merge_options merge_opts = LL_MERGE_OPTIONS_INIT;
mmbuffer_t result = { NULL };
enum ll_merge_result status;
@@ -3538,12 +3528,13 @@ static int three_way_merge(struct apply_state *state,
read_mmblob(&base_file, base);
read_mmblob(&our_file, ours);
read_mmblob(&their_file, theirs);
+ merge_opts.variant = state->merge_variant;
status = ll_merge(&result, path,
&base_file, "base",
&our_file, "ours",
&their_file, "theirs",
state->repo->index,
- NULL);
+ &merge_opts);
if (status == LL_MERGE_BINARY_CONFLICT)
warning("Cannot merge binary files: %s (%s vs. %s)",
path, "ours", "theirs");
@@ -3554,9 +3545,8 @@ static int three_way_merge(struct apply_state *state,
free(result.ptr);
return -1;
}
- clear_image(image);
- image->buf = result.ptr;
- image->len = result.size;
+ image_clear(image);
+ strbuf_attach(&image->buf, result.ptr, result.size, result.size);
return status;
}
@@ -3601,7 +3591,7 @@ static int load_current(struct apply_state *state,
else if (status)
return -1;
img = strbuf_detach(&buf, &len);
- prepare_image(image, img, len, !patch->is_binary);
+ image_prepare(image, img, len, !patch->is_binary);
return 0;
}
@@ -3616,7 +3606,7 @@ static int try_threeway(struct apply_state *state,
size_t len;
int status;
char *img;
- struct image tmp_image;
+ struct image tmp_image = IMAGE_INIT;
/* No point falling back to 3-way merge in these cases */
if (patch->is_delete ||
@@ -3636,15 +3626,15 @@ static int try_threeway(struct apply_state *state,
fprintf(stderr, _("Performing three-way merge...\n"));
img = strbuf_detach(&buf, &len);
- prepare_image(&tmp_image, img, len, 1);
+ image_prepare(&tmp_image, img, len, 1);
/* Apply the patch to get the post image */
if (apply_fragments(state, &tmp_image, patch) < 0) {
- clear_image(&tmp_image);
+ image_clear(&tmp_image);
return -1;
}
/* post_oid is theirs */
- write_object_file(tmp_image.buf, tmp_image.len, OBJ_BLOB, &post_oid);
- clear_image(&tmp_image);
+ write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &post_oid);
+ image_clear(&tmp_image);
/* our_oid is ours */
if (patch->is_new) {
@@ -3656,8 +3646,8 @@ static int try_threeway(struct apply_state *state,
return error(_("cannot read the current contents of '%s'"),
patch->old_name);
}
- write_object_file(tmp_image.buf, tmp_image.len, OBJ_BLOB, &our_oid);
- clear_image(&tmp_image);
+ write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &our_oid);
+ image_clear(&tmp_image);
/* in-core three-way merge between post and our using pre as base */
status = three_way_merge(state, image, patch->new_name,
@@ -3672,7 +3662,7 @@ static int try_threeway(struct apply_state *state,
if (status) {
patch->conflicted_threeway = 1;
if (patch->is_new)
- oidclr(&patch->threeway_stage[0]);
+ oidclr(&patch->threeway_stage[0], the_repository->hash_algo);
else
oidcpy(&patch->threeway_stage[0], &pre_oid);
oidcpy(&patch->threeway_stage[1], &our_oid);
@@ -3693,7 +3683,7 @@ static int try_threeway(struct apply_state *state,
static int apply_data(struct apply_state *state, struct patch *patch,
struct stat *st, const struct cache_entry *ce)
{
- struct image image;
+ struct image image = IMAGE_INIT;
if (load_preimage(state, &image, patch, st, ce) < 0)
return -1;
@@ -3704,13 +3694,14 @@ static int apply_data(struct apply_state *state, struct patch *patch,
fprintf(stderr, _("Falling back to direct application...\n"));
/* Note: with --reject, apply_fragments() returns 0 */
- if (patch->direct_to_threeway || apply_fragments(state, &image, patch) < 0)
+ if (patch->direct_to_threeway || apply_fragments(state, &image, patch) < 0) {
+ image_clear(&image);
return -1;
+ }
}
- patch->result = image.buf;
- patch->resultsize = image.len;
+ patch->result = strbuf_detach(&image.buf, &patch->resultsize);
add_to_fn_table(state, patch);
- free(image.line_allocated);
+ free(image.line);
if (0 < patch->is_delete && patch->resultsize)
return error(_("removal patch leaves file contents"));
@@ -3778,8 +3769,17 @@ static int check_preimage(struct apply_state *state,
return error_errno("%s", old_name);
}
- if (!state->cached && !previous)
- st_mode = ce_mode_from_stat(*ce, st->st_mode);
+ if (!state->cached && !previous) {
+ if (*ce && !(*ce)->ce_mode)
+ BUG("ce_mode == 0 for path '%s'", old_name);
+
+ if (trust_executable_bit)
+ st_mode = ce_mode_from_stat(*ce, st->st_mode);
+ else if (*ce)
+ st_mode = (*ce)->ce_mode;
+ else
+ st_mode = patch->old_mode;
+ }
if (patch->is_new < 0)
patch->is_new = 0;
@@ -4065,7 +4065,7 @@ static int read_apply_cache(struct apply_state *state)
{
if (state->index_file)
return read_index_from(state->repo->index, state->index_file,
- get_git_dir());
+ repo_get_git_dir(the_repository));
else
return repo_read_index(state->repo);
}
@@ -4431,6 +4431,7 @@ static int create_one_file(struct apply_state *state,
const char *buf,
unsigned long size)
{
+ char *newpath = NULL;
int res;
if (state->cached)
@@ -4492,24 +4493,26 @@ static int create_one_file(struct apply_state *state,
unsigned int nr = getpid();
for (;;) {
- char newpath[PATH_MAX];
- mksnpath(newpath, sizeof(newpath), "%s~%u", path, nr);
+ newpath = mkpathdup("%s~%u", path, nr);
res = try_create_file(state, newpath, mode, buf, size);
if (res < 0)
- return -1;
+ goto out;
if (!res) {
if (!rename(newpath, path))
- return 0;
+ goto out;
unlink_or_warn(newpath);
break;
}
if (errno != EEXIST)
break;
++nr;
+ FREE_AND_NULL(newpath);
}
}
- return error_errno(_("unable to write file '%s' mode %o"),
- path, mode);
+ res = error_errno(_("unable to write file '%s' mode %o"), path, mode);
+out:
+ free(newpath);
+ return res;
}
static int add_conflicted_stages_file(struct apply_state *state,
@@ -4592,7 +4595,7 @@ static int write_out_one_result(struct apply_state *state,
static int write_out_one_reject(struct apply_state *state, struct patch *patch)
{
FILE *rej;
- char namebuf[PATH_MAX];
+ char *namebuf;
struct fragment *frag;
int fd, cnt = 0;
struct strbuf sb = STRBUF_INIT;
@@ -4625,28 +4628,30 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
say_patch_name(stderr, sb.buf, patch);
strbuf_release(&sb);
- cnt = strlen(patch->new_name);
- if (ARRAY_SIZE(namebuf) <= cnt + 5) {
- cnt = ARRAY_SIZE(namebuf) - 5;
- warning(_("truncating .rej filename to %.*s.rej"),
- cnt - 1, patch->new_name);
- }
- memcpy(namebuf, patch->new_name, cnt);
- memcpy(namebuf + cnt, ".rej", 5);
+ namebuf = xstrfmt("%s.rej", patch->new_name);
fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0) {
- if (errno != EEXIST)
- return error_errno(_("cannot open %s"), namebuf);
- if (unlink(namebuf))
- return error_errno(_("cannot unlink '%s'"), namebuf);
+ if (errno != EEXIST) {
+ error_errno(_("cannot open %s"), namebuf);
+ goto error;
+ }
+ if (unlink(namebuf)) {
+ error_errno(_("cannot unlink '%s'"), namebuf);
+ goto error;
+ }
fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
- if (fd < 0)
- return error_errno(_("cannot open %s"), namebuf);
+ if (fd < 0) {
+ error_errno(_("cannot open %s"), namebuf);
+ goto error;
+ }
}
rej = fdopen(fd, "w");
- if (!rej)
- return error_errno(_("cannot open %s"), namebuf);
+ if (!rej) {
+ error_errno(_("cannot open %s"), namebuf);
+ close(fd);
+ goto error;
+ }
/* Normal git tools never deal with .rej, so do not pretend
* this is a git patch by saying --git or giving extended
@@ -4670,6 +4675,8 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
fputc('\n', rej);
}
fclose(rej);
+error:
+ free(namebuf);
return -1;
}
@@ -5098,6 +5105,15 @@ int apply_parse_options(int argc, const char **argv,
N_("also apply the patch (use with --stat/--summary/--check)")),
OPT_BOOL('3', "3way", &state->threeway,
N_( "attempt three-way merge, fall back on normal patch if that fails")),
+ OPT_SET_INT_F(0, "ours", &state->merge_variant,
+ N_("for conflicts, use our version"),
+ XDL_MERGE_FAVOR_OURS, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "theirs", &state->merge_variant,
+ N_("for conflicts, use their version"),
+ XDL_MERGE_FAVOR_THEIRS, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "union", &state->merge_variant,
+ N_("for conflicts, use a union version"),
+ XDL_MERGE_FAVOR_UNION, PARSE_OPT_NONEG),
OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor,
N_("build a temporary index based on embedded index information")),
/* Think twice before adding "--nul" synonym to this */
@@ -5137,5 +5153,10 @@ int apply_parse_options(int argc, const char **argv,
OPT_END()
};
- return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+ argc = parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+
+ if (state->merge_variant && !state->threeway)
+ die(_("--ours, --theirs, and --union require --3way"));
+
+ return argc;
}
diff --git a/apply.h b/apply.h
index 7cd38b1443..90e887ec0e 100644
--- a/apply.h
+++ b/apply.h
@@ -1,7 +1,7 @@
#ifndef APPLY_H
#define APPLY_H
-#include "hash-ll.h"
+#include "hash.h"
#include "lockfile.h"
#include "string-list.h"
#include "strmap.h"
@@ -59,7 +59,8 @@ struct apply_state {
struct repository *repo;
const char *index_file;
enum apply_verbosity apply_verbosity;
- const char *fake_ancestor;
+ int merge_variant;
+ char *fake_ancestor;
const char *patch_input_file;
int line_termination;
struct strbuf root;
diff --git a/archive-tar.c b/archive-tar.c
index 0726996839..e7b3489e1e 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -1,6 +1,9 @@
/*
* Copyright (c) 2005, 2006 Rene Scharfe
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "gettext.h"
@@ -9,6 +12,7 @@
#include "tar.h"
#include "archive.h"
#include "object-store-ll.h"
+#include "strbuf.h"
#include "streaming.h"
#include "run-command.h"
#include "write-or-die.h"
@@ -364,7 +368,7 @@ static struct archiver *find_tar_filter(const char *name, size_t len)
int i;
for (i = 0; i < nr_tar_filters; i++) {
struct archiver *ar = tar_filters[i];
- if (!strncmp(ar->name, name, len) && !ar->name[len])
+ if (!xstrncmpz(ar->name, name, len))
return ar;
}
return NULL;
diff --git a/archive-zip.c b/archive-zip.c
index 7229e3e454..9f32730181 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -1,6 +1,9 @@
/*
* Copyright (c) 2006 Rene Scharfe
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "archive.h"
@@ -10,6 +13,7 @@
#include "streaming.h"
#include "utf8.h"
#include "object-store-ll.h"
+#include "strbuf.h"
#include "userdiff.h"
#include "write-or-die.h"
#include "xdiff-interface.h"
diff --git a/archive.c b/archive.c
index ca11db185b..a7a92ff839 100644
--- a/archive.c
+++ b/archive.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
@@ -5,6 +7,7 @@
#include "environment.h"
#include "gettext.h"
#include "hex.h"
+#include "object-name.h"
#include "path.h"
#include "pretty.h"
#include "setup.h"
@@ -17,7 +20,6 @@
#include "archive.h"
#include "parse-options.h"
#include "unpack-trees.h"
-#include "dir.h"
#include "quote.h"
static char const * const archive_usage[] = {
@@ -302,8 +304,6 @@ int write_archive_entries(struct archiver_args *args,
write_archive_entry_fn_t write_entry)
{
struct archiver_context context;
- struct unpack_trees_options opts;
- struct tree_desc t;
int err;
struct strbuf path_in_archive = STRBUF_INIT;
struct strbuf content = STRBUF_INIT;
@@ -329,22 +329,6 @@ int write_archive_entries(struct archiver_args *args,
context.args = args;
context.write_entry = write_entry;
- /*
- * Setup index and instruct attr to read index only
- */
- if (!args->worktree_attributes) {
- memset(&opts, 0, sizeof(opts));
- opts.index_only = 1;
- opts.head_idx = -1;
- opts.src_index = args->repo->index;
- opts.dst_index = args->repo->index;
- opts.fn = oneway_merge;
- init_tree_desc(&t, args->tree->buffer, args->tree->size);
- if (unpack_trees(1, &t, &opts))
- return -1;
- git_attr_set_direction(GIT_ATTR_INDEX);
- }
-
err = read_tree(args->repo, args->tree,
&args->pathspec,
queue_or_write_archive_entry,
@@ -537,6 +521,27 @@ static void parse_treeish_arg(const char **argv,
if (!tree)
die(_("not a tree object: %s"), oid_to_hex(&oid));
+ /*
+ * Setup index and instruct attr to read index only
+ */
+ if (!ar_args->worktree_attributes) {
+ struct unpack_trees_options opts;
+ struct tree_desc t;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.index_only = 1;
+ opts.head_idx = -1;
+ opts.src_index = ar_args->repo->index;
+ opts.dst_index = ar_args->repo->index;
+ opts.fn = oneway_merge;
+ init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
+ if (unpack_trees(1, &t, &opts))
+ die(_("failed to unpack tree object %s"),
+ oid_to_hex(&tree->object.oid));
+
+ git_attr_set_direction(GIT_ATTR_INDEX);
+ }
+
ar_args->refname = ref;
ar_args->tree = tree;
ar_args->commit_oid = commit_oid;
@@ -685,6 +690,8 @@ static int parse_archive_args(int argc, const char **argv,
base = "";
if (list) {
+ if (argc)
+ die(_("extra command line parameter '%s'"), *argv);
for (i = 0; i < nr_archivers; i++)
if (!is_remote || archivers[i]->flags & ARCHIVER_REMOTE)
printf("%s\n", archivers[i]->name);
@@ -731,6 +738,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
struct pretty_print_describe_status describe_status = {0};
struct pretty_print_context ctx = {0};
struct archiver_args args;
+ const char **argv_copy;
int rc;
git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
@@ -744,6 +752,14 @@ int write_archive(int argc, const char **argv, const char *prefix,
args.repo = repo;
args.prefix = prefix;
string_list_init_dup(&args.extra_files);
+
+ /*
+ * `parse_archive_args()` modifies contents of `argv`, which is what we
+ * want. Our callers may not want it though, so we create a copy here.
+ */
+ DUP_ARRAY(argv_copy, argv, argc);
+ argv = argv_copy;
+
argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
if (!startup_info->have_repository) {
/*
@@ -762,6 +778,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
string_list_clear_func(&args.extra_files, extra_file_info_clear);
free(args.refname);
clear_pathspec(&args.pathspec);
+ free(argv_copy);
return rc;
}
diff --git a/archive.h b/archive.h
index 3a4bdfbd07..bbe65ba0f9 100644
--- a/archive.h
+++ b/archive.h
@@ -1,7 +1,6 @@
#ifndef ARCHIVE_H
#define ARCHIVE_H
-#include "object-name.h"
#include "pathspec.h"
#include "string-list.h"
diff --git a/attr.c b/attr.c
index ff0a3e7b61..c605d2c170 100644
--- a/attr.c
+++ b/attr.c
@@ -6,6 +6,8 @@
* an insanely large number of attributes.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -17,6 +19,7 @@
#include "utf8.h"
#include "quote.h"
#include "read-cache-ll.h"
+#include "refs.h"
#include "revision.h"
#include "object-store-ll.h"
#include "setup.h"
@@ -24,6 +27,8 @@
#include "tree-walk.h"
#include "object-name.h"
+char *git_attr_tree;
+
const char git_attr__true[] = "(builtin)true";
const char git_attr__false[] = "\0(builtin)false";
static const char git_attr__unknown[] = "(builtin)unknown";
@@ -181,6 +186,15 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
}
}
+/*
+ * Attribute name cannot begin with "builtin_" which
+ * is a reserved namespace for built in attributes values.
+ */
+static int attr_name_reserved(const char *name)
+{
+ return starts_with(name, "builtin_");
+}
+
static int attr_name_valid(const char *name, size_t namelen)
{
/*
@@ -313,7 +327,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
cp++;
len--;
}
- if (!attr_name_valid(cp, len)) {
+ if (!attr_name_valid(cp, len) || attr_name_reserved(cp)) {
report_invalid_attr(cp, len, src, lineno);
return NULL;
}
@@ -377,7 +391,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
name += strlen(ATTRIBUTE_MACRO_PREFIX);
name += strspn(name, blank);
namelen = strcspn(name, blank);
- if (!attr_name_valid(name, namelen)) {
+ if (!attr_name_valid(name, namelen) || attr_name_reserved(name)) {
report_invalid_attr(name, namelen, src, lineno);
goto fail_return;
}
@@ -753,8 +767,8 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
return res;
}
-static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
- unsigned flags)
+static struct attr_stack *read_attr_from_buf(char *buf, size_t length,
+ const char *path, unsigned flags)
{
struct attr_stack *res;
char *sp;
@@ -762,6 +776,11 @@ static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
if (!buf)
return NULL;
+ if (length >= ATTR_MAX_FILE_SIZE) {
+ warning(_("ignoring overly large gitattributes blob '%s'"), path);
+ free(buf);
+ return NULL;
+ }
CALLOC_ARRAY(res, 1);
for (sp = buf; *sp;) {
@@ -801,41 +820,57 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,
return NULL;
}
- return read_attr_from_buf(buf, path, flags);
+ return read_attr_from_buf(buf, sz, path, flags);
}
static struct attr_stack *read_attr_from_index(struct index_state *istate,
const char *path, unsigned flags)
{
+ struct attr_stack *stack = NULL;
char *buf;
unsigned long size;
+ int sparse_dir_pos = -1;
if (!istate)
return NULL;
/*
- * The .gitattributes file only applies to files within its
- * parent directory. In the case of cone-mode sparse-checkout,
- * the .gitattributes file is sparse if and only if all paths
- * within that directory are also sparse. Thus, don't load the
- * .gitattributes file since it will not matter.
- *
- * In the case of a sparse index, it is critical that we don't go
- * looking for a .gitattributes file, as doing so would cause the
- * index to expand.
+ * When handling sparse-checkouts, .gitattributes files
+ * may reside within a sparse directory. We distinguish
+ * whether a path exists directly in the index or not by
+ * evaluating if 'pos' is negative.
+ * If 'pos' is negative, the path is not directly present
+ * in the index and is likely within a sparse directory.
+ * For paths not in the index, The absolute value of 'pos'
+ * minus 1 gives us the position where the path would be
+ * inserted in lexicographic order within the index.
+ * We then subtract another 1 from this value
+ * (sparse_dir_pos = -pos - 2) to find the position of the
+ * last index entry which is lexicographically smaller than
+ * the path. This would be the sparse directory containing
+ * the path. By identifying the sparse directory containing
+ * the path, we can correctly read the attributes specified
+ * in the .gitattributes file from the tree object of the
+ * sparse directory.
*/
- if (!path_in_cone_mode_sparse_checkout(path, istate))
- return NULL;
+ if (!path_in_cone_mode_sparse_checkout(path, istate)) {
+ int pos = index_name_pos_sparse(istate, path, strlen(path));
- buf = read_blob_data_from_index(istate, path, &size);
- if (!buf)
- return NULL;
- if (size >= ATTR_MAX_FILE_SIZE) {
- warning(_("ignoring overly large gitattributes blob '%s'"), path);
- return NULL;
+ if (pos < 0)
+ sparse_dir_pos = -pos - 2;
}
- return read_attr_from_buf(buf, path, flags);
+ if (sparse_dir_pos >= 0 &&
+ S_ISSPARSEDIR(istate->cache[sparse_dir_pos]->ce_mode) &&
+ !strncmp(istate->cache[sparse_dir_pos]->name, path, ce_namelen(istate->cache[sparse_dir_pos]))) {
+ const char *relative_path = path + ce_namelen(istate->cache[sparse_dir_pos]);
+ stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags);
+ } else {
+ buf = read_blob_data_from_index(istate, path, &size);
+ if (buf)
+ stack = read_attr_from_buf(buf, size, path, flags);
+ }
+ return stack;
}
static struct attr_stack *read_attr(struct index_state *istate,
@@ -1179,29 +1214,130 @@ 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)
+static int compute_default_attr_source(struct object_id *attr_source)
{
+ int ignore_bad_attr_tree = 0;
+
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 (!default_attr_source_tree_object_name && git_attr_tree) {
+ default_attr_source_tree_object_name = git_attr_tree;
+ ignore_bad_attr_tree = 1;
+ }
+
+ if (!default_attr_source_tree_object_name)
+ return 0;
+
+ if (!startup_info->have_repository) {
+ if (!ignore_bad_attr_tree)
+ die(_("cannot use --attr-source or GIT_ATTR_SOURCE without repo"));
+ return 0;
+ }
+
+ if (repo_get_oid_treeish(the_repository,
+ default_attr_source_tree_object_name,
+ attr_source)) {
+ if (!ignore_bad_attr_tree)
+ die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+ return 0;
+ }
- if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source))
- die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+ return 1;
}
static struct object_id *default_attr_source(void)
{
static struct object_id attr_source;
+ static int has_attr_source = -1;
- if (is_null_oid(&attr_source))
- compute_default_attr_source(&attr_source);
- if (is_null_oid(&attr_source))
+ if (has_attr_source < 0)
+ has_attr_source = compute_default_attr_source(&attr_source);
+ if (!has_attr_source)
return NULL;
return &attr_source;
}
+static const char *interned_mode_string(unsigned int mode)
+{
+ static struct {
+ unsigned int val;
+ char str[7];
+ } mode_string[] = {
+ { .val = 0040000 },
+ { .val = 0100644 },
+ { .val = 0100755 },
+ { .val = 0120000 },
+ { .val = 0160000 },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mode_string); i++) {
+ if (mode_string[i].val != mode)
+ continue;
+ if (!*mode_string[i].str)
+ snprintf(mode_string[i].str, sizeof(mode_string[i].str),
+ "%06o", mode);
+ return mode_string[i].str;
+ }
+ BUG("Unsupported mode 0%o", mode);
+}
+
+static const char *builtin_object_mode_attr(struct index_state *istate, const char *path)
+{
+ unsigned int mode;
+
+ if (direction == GIT_ATTR_CHECKIN) {
+ struct object_id oid;
+ struct stat st;
+ if (lstat(path, &st))
+ die_errno(_("unable to stat '%s'"), path);
+ mode = canon_mode(st.st_mode);
+ if (S_ISDIR(mode)) {
+ /*
+ *`path` is either a directory or it is a submodule,
+ * in which case it is already indexed as submodule
+ * or it does not exist in the index yet and we need to
+ * check if we can resolve to a ref.
+ */
+ int pos = index_name_pos(istate, path, strlen(path));
+ if (pos >= 0) {
+ if (S_ISGITLINK(istate->cache[pos]->ce_mode))
+ mode = istate->cache[pos]->ce_mode;
+ } else if (repo_resolve_gitlink_ref(the_repository, path,
+ "HEAD", &oid) == 0) {
+ mode = S_IFGITLINK;
+ }
+ }
+ } else {
+ /*
+ * For GIT_ATTR_CHECKOUT and GIT_ATTR_INDEX we only check
+ * for mode in the index.
+ */
+ int pos = index_name_pos(istate, path, strlen(path));
+ if (pos >= 0)
+ mode = istate->cache[pos]->ce_mode;
+ else
+ return ATTR__UNSET;
+ }
+
+ return interned_mode_string(mode);
+}
+
+
+static const char *compute_builtin_attr(struct index_state *istate,
+ const char *path,
+ const struct git_attr *attr) {
+ static const struct git_attr *object_mode_attr;
+
+ if (!object_mode_attr)
+ object_mode_attr = git_attr("builtin_objectmode");
+
+ if (attr == object_mode_attr)
+ return builtin_object_mode_attr(istate, path);
+ return ATTR__UNSET;
+}
+
void git_check_attr(struct index_state *istate,
const char *path,
struct attr_check *check)
@@ -1215,7 +1351,7 @@ void git_check_attr(struct index_state *istate,
unsigned int n = check->items[i].attr->attr_nr;
const char *value = check->all_attrs[n].value;
if (value == ATTR__UNKNOWN)
- value = ATTR__UNSET;
+ value = compute_builtin_attr(istate, path, check->all_attrs[n].attr);
check->items[i].value = value;
}
}
diff --git a/attr.h b/attr.h
index 2b745df405..bb33b60880 100644
--- a/attr.h
+++ b/attr.h
@@ -190,6 +190,8 @@ struct attr_check {
};
struct attr_check *attr_check_alloc(void);
+
+LAST_ARG_MUST_BE_NULL
struct attr_check *attr_check_initl(const char *, ...);
struct attr_check *attr_check_dup(const struct attr_check *check);
@@ -236,4 +238,6 @@ const char *git_attr_global_file(void);
/* Return whether the system gitattributes file is enabled and should be used. */
int git_attr_system_is_enabled(void);
+extern char *git_attr_tree;
+
#endif /* ATTR_H */
diff --git a/bisect.c b/bisect.c
index 1be8e0a271..f6fa5c235f 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
@@ -9,7 +11,6 @@
#include "refs.h"
#include "list-objects.h"
#include "quote.h"
-#include "hash-lookup.h"
#include "run-command.h"
#include "log-tree.h"
#include "bisect.h"
@@ -27,8 +28,8 @@ static struct oid_array skipped_revs;
static struct object_id *current_bad_oid;
-static const char *term_bad;
-static const char *term_good;
+static char *term_bad;
+static char *term_good;
/* Remember to update object flag allocation in object.h */
#define COUNTED (1u<<16)
@@ -159,6 +160,9 @@ static void show_list(const char *debug, int counted, int nr,
const char *subject_start;
int subject_len;
+ if (!buf)
+ die(_("unable to read %s"), oid_to_hex(&commit->object.oid));
+
fprintf(stderr, "%c%c%c ",
(commit_flags & TREESAME) ? ' ' : 'T',
(commit_flags & UNINTERESTING) ? 'U' : ' ',
@@ -438,13 +442,16 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
best->next = NULL;
}
*reaches = weight(best);
+ } else {
+ free_commit_list(*commit_list);
}
- free(weights);
*commit_list = best;
+
+ free(weights);
clear_commit_weight(&commit_weight);
}
-static int register_ref(const char *refname, const struct object_id *oid,
+static int register_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb_data UNUSED)
{
struct strbuf good_prefix = STRBUF_INIT;
@@ -452,6 +459,7 @@ static int register_ref(const char *refname, const struct object_id *oid,
strbuf_addstr(&good_prefix, "-");
if (!strcmp(refname, term_bad)) {
+ free(current_bad_oid);
current_bad_oid = xmalloc(sizeof(*current_bad_oid));
oidcpy(current_bad_oid, oid);
} else if (starts_with(refname, good_prefix.buf)) {
@@ -467,11 +475,11 @@ static int register_ref(const char *refname, const struct object_id *oid,
static int read_bisect_refs(void)
{
- return for_each_ref_in("refs/bisect/", register_ref, NULL);
+ return refs_for_each_ref_in(get_main_ref_store(the_repository),
+ "refs/bisect/", register_ref, NULL);
}
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
-static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
@@ -552,8 +560,11 @@ struct commit_list *filter_skipped(struct commit_list *list,
tried = &list->next;
} else {
if (!show_all) {
- if (!skipped_first || !*skipped_first)
+ if (!skipped_first || !*skipped_first) {
+ free_commit_list(next);
+ free_commit_list(filtered);
return list;
+ }
} else if (skipped_first && !*skipped_first) {
/* This means we know it's not skipped */
*skipped_first = -1;
@@ -609,7 +620,7 @@ static int sqrti(int val)
static struct commit_list *skip_away(struct commit_list *list, int count)
{
- struct commit_list *cur, *previous;
+ struct commit_list *cur, *previous, *result = list;
int prn, index, i;
prn = get_prn(count);
@@ -621,15 +632,23 @@ static struct commit_list *skip_away(struct commit_list *list, int count)
for (i = 0; cur; cur = cur->next, i++) {
if (i == index) {
if (!oideq(&cur->item->object.oid, current_bad_oid))
- return cur;
- if (previous)
- return previous;
- return list;
+ result = cur;
+ else if (previous)
+ result = previous;
+ else
+ result = list;
+ break;
}
previous = cur;
}
- return list;
+ for (cur = list; cur != result; ) {
+ struct commit_list *next = cur->next;
+ free(cur);
+ cur = next;
+ }
+
+ return result;
}
static struct commit_list *managed_skipped(struct commit_list *list,
@@ -707,26 +726,10 @@ static enum bisect_error error_if_skipped_commits(struct commit_list *tried,
static int is_expected_rev(const struct object_id *oid)
{
- const char *filename = git_path_bisect_expected_rev();
- struct stat st;
- struct strbuf str = STRBUF_INIT;
- FILE *fp;
- int res = 0;
-
- if (stat(filename, &st) || !S_ISREG(st.st_mode))
- return 0;
-
- fp = fopen_or_warn(filename, "r");
- if (!fp)
+ struct object_id expected_oid;
+ if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected_oid))
return 0;
-
- if (strbuf_getline_lf(&str, fp) != EOF)
- res = !strcmp(str.buf, oid_to_hex(oid));
-
- strbuf_release(&str);
- fclose(fp);
-
- return res;
+ return oideq(oid, &expected_oid);
}
enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
@@ -736,11 +739,14 @@ enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
struct pretty_print_context pp = {0};
struct strbuf commit_msg = STRBUF_INIT;
- update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), NULL,
+ "BISECT_EXPECTED_REV", bisect_rev, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (no_checkout) {
- update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), NULL,
+ "BISECT_HEAD", bisect_rev, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -810,6 +816,8 @@ static enum bisect_error handle_bad_merge_base(void)
"between %s and [%s].\n"),
bad_hex, term_bad, term_good, bad_hex, good_hex);
}
+
+ free(good_hex);
return BISECT_MERGE_BASE_CHECK;
}
@@ -851,13 +859,14 @@ static void handle_skipped_merge_base(const struct object_id *mb)
static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int no_checkout)
{
enum bisect_error res = BISECT_OK;
- struct commit_list *result;
+ struct commit_list *result = NULL;
- result = repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
- rev + 1);
+ if (repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
+ rev + 1, &result) < 0)
+ exit(128);
- for (; result; result = result->next) {
- const struct object_id *mb = &result->item->object.oid;
+ for (struct commit_list *l = result; l; l = l->next) {
+ const struct object_id *mb = &l->item->object.oid;
if (oideq(mb, current_bad_oid)) {
res = handle_bad_merge_base();
break;
@@ -960,23 +969,32 @@ static enum bisect_error check_good_are_ancestors_of_bad(struct repository *r,
}
/*
- * This does "git diff-tree --pretty COMMIT" without one fork+exec.
+ * Display a commit summary to the user.
*/
-static void show_diff_tree(struct repository *r,
- const char *prefix,
- struct commit *commit)
+static void show_commit(struct commit *commit)
{
- const char *argv[] = {
- "diff-tree", "--pretty", "--stat", "--summary", "--cc", NULL
- };
- struct rev_info opt;
-
- git_config(git_diff_ui_config, NULL);
- repo_init_revisions(r, &opt, prefix);
+ struct child_process show = CHILD_PROCESS_INIT;
- setup_revisions(ARRAY_SIZE(argv) - 1, argv, &opt, NULL);
- log_tree_commit(&opt, commit);
- release_revisions(&opt);
+ /*
+ * Call git show with --no-pager, as it would otherwise
+ * paginate the "git show" output only, not the output
+ * from bisect_next_all(); this can be fixed by moving
+ * it into a --format parameter, but that would override
+ * the user's default options for "git show", which we
+ * are trying to honour.
+ */
+ strvec_pushl(&show.args,
+ "--no-pager",
+ "show",
+ "--stat",
+ "--summary",
+ "--no-abbrev-commit",
+ "--diff-merges=first-parent",
+ oid_to_hex(&commit->object.oid), NULL);
+ show.git_cmd = 1;
+ if (run_command(&show))
+ die(_("unable to start 'show' for object '%s'"),
+ oid_to_hex(&commit->object.oid));
}
/*
@@ -984,7 +1002,7 @@ static void show_diff_tree(struct repository *r,
* We read them and store them to adapt the messages accordingly.
* Default is bad/good.
*/
-void read_bisect_terms(const char **read_bad, const char **read_good)
+void read_bisect_terms(char **read_bad, char **read_good)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path_bisect_terms();
@@ -992,16 +1010,20 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
if (!fp) {
if (errno == ENOENT) {
- *read_bad = "bad";
- *read_good = "good";
+ free(*read_bad);
+ *read_bad = xstrdup("bad");
+ free(*read_good);
+ *read_good = xstrdup("good");
return;
} else {
die_errno(_("could not read file '%s'"), filename);
}
} else {
strbuf_getline_lf(&str, fp);
+ free(*read_bad);
*read_bad = strbuf_detach(&str, NULL);
strbuf_getline_lf(&str, fp);
+ free(*read_good);
*read_good = strbuf_detach(&str, NULL);
}
strbuf_release(&str);
@@ -1023,7 +1045,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
{
struct strvec rev_argv = STRVEC_INIT;
struct rev_info revs = REV_INFO_INIT;
- struct commit_list *tried;
+ struct commit_list *tried = NULL;
int reaches = 0, all = 0, nr, steps;
enum bisect_error res = BISECT_OK;
struct object_id *bisect_rev;
@@ -1032,7 +1054,8 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
* If no_checkout is non-zero, the bisection process does not
* checkout the trial commit but instead simply updates BISECT_HEAD.
*/
- int no_checkout = ref_exists("BISECT_HEAD");
+ int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
+ "BISECT_HEAD");
unsigned bisect_flags = 0;
read_bisect_terms(&term_bad, &term_good);
@@ -1089,11 +1112,11 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
if (oideq(bisect_rev, current_bad_oid)) {
res = error_if_skipped_commits(tried, current_bad_oid);
if (res)
- return res;
+ goto cleanup;
printf("%s is the first %s commit\n", oid_to_hex(bisect_rev),
term_bad);
- show_diff_tree(r, prefix, revs.commits->item);
+ show_commit(revs.commits->item);
/*
* This means the bisection process succeeded.
* Using BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND (-10)
@@ -1123,21 +1146,12 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
res = bisect_checkout(bisect_rev, no_checkout);
cleanup:
+ free_commit_list(tried);
release_revisions(&revs);
strvec_clear(&rev_argv);
return res;
}
-static inline int log2i(int n)
-{
- int log2 = 0;
-
- for (; n > 1; n >>= 1)
- log2++;
-
- return log2;
-}
-
static inline int exp2i(int n)
{
return 1 << n;
@@ -1160,7 +1174,7 @@ int estimate_bisect_steps(int all)
if (all < 3)
return 0;
- n = log2i(all);
+ n = log2u(all);
e = exp2i(n);
x = all - e;
@@ -1168,6 +1182,7 @@ int estimate_bisect_steps(int all)
}
static int mark_for_removal(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cb_data)
{
@@ -1183,12 +1198,16 @@ int bisect_clean_state(void)
/* There may be some refs packed during bisection */
struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
- for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ "refs/bisect", mark_for_removal,
+ (void *) &refs_for_removal);
string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
- result = delete_refs("bisect: remove", &refs_for_removal, REF_NO_DEREF);
+ string_list_append(&refs_for_removal, xstrdup("BISECT_EXPECTED_REV"));
+ result = refs_delete_refs(get_main_ref_store(the_repository),
+ "bisect: remove", &refs_for_removal,
+ REF_NO_DEREF);
refs_for_removal.strdup_strings = 1;
string_list_clear(&refs_for_removal, 0);
- unlink_or_warn(git_path_bisect_expected_rev());
unlink_or_warn(git_path_bisect_ancestors_ok());
unlink_or_warn(git_path_bisect_log());
unlink_or_warn(git_path_bisect_names());
diff --git a/bisect.h b/bisect.h
index ee3fd65f3b..944439bfac 100644
--- a/bisect.h
+++ b/bisect.h
@@ -75,7 +75,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix);
int estimate_bisect_steps(int all);
-void read_bisect_terms(const char **bad, const char **good);
+void read_bisect_terms(char **bad, char **good);
int bisect_clean_state(void);
diff --git a/blame.c b/blame.c
index 141756975b..bf69768a7d 100644
--- a/blame.c
+++ b/blame.c
@@ -1,8 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "refs.h"
#include "object-store-ll.h"
#include "cache-tree.h"
#include "mergesort.h"
+#include "commit.h"
#include "convert.h"
#include "diff.h"
#include "diffcore.h"
@@ -10,6 +13,7 @@
#include "hex.h"
#include "path.h"
#include "read-cache.h"
+#include "revision.h"
#include "setup.h"
#include "tag.h"
#include "trace2.h"
@@ -1244,7 +1248,7 @@ static int fill_blob_sha1_and_mode(struct repository *r,
goto error_out;
return 0;
error_out:
- oidclr(&origin->blob_oid);
+ oidclr(&origin->blob_oid, the_repository->hash_algo);
origin->mode = S_IFINVALID;
return -1;
}
@@ -2698,7 +2702,7 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs,
return NULL;
/* Do we have HEAD? */
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return NULL;
head_commit = lookup_commit_reference_gently(revs->repo,
&head_oid, 1);
@@ -2801,7 +2805,7 @@ void setup_scoreboard(struct blame_scoreboard *sb,
if (sb->final) {
parent_oid = &sb->final->object.oid;
} else {
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL))
die("no such ref: HEAD");
parent_oid = &head_oid;
}
@@ -2926,6 +2930,11 @@ void setup_blame_bloom_data(struct blame_scoreboard *sb)
void cleanup_scoreboard(struct blame_scoreboard *sb)
{
+ free(sb->lineno);
+ free(sb->final_buf);
+ clear_prio_queue(&sb->commits);
+ oidset_clear(&sb->ignore_list);
+
if (sb->bloom_data) {
int i;
for (i = 0; i < sb->bloom_data->nr; i++) {
diff --git a/blame.h b/blame.h
index 31ddc85f19..3b34be0e5c 100644
--- a/blame.h
+++ b/blame.h
@@ -1,12 +1,9 @@
#ifndef BLAME_H
#define BLAME_H
-#include "commit.h"
#include "oidset.h"
#include "xdiff-interface.h"
-#include "revision.h"
#include "prio-queue.h"
-#include "diff.h"
#define PICKAXE_BLAME_MOVE 01
#define PICKAXE_BLAME_COPY 02
@@ -119,7 +116,7 @@ struct blame_scoreboard {
* Used by many functions to obtain contents of the nth line,
* indexed with scoreboard.lineno[blame_entry.lno].
*/
- const char *final_buf;
+ char *final_buf;
unsigned long final_buf_size;
/* linked list of blames */
diff --git a/blob.c b/blob.c
index 888e28a559..3fb2922b1a 100644
--- a/blob.c
+++ b/blob.c
@@ -1,6 +1,5 @@
#include "git-compat-util.h"
#include "blob.h"
-#include "repository.h"
#include "alloc.h"
const char *blob_type = "blob";
diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h
index 9fb0441b98..47bb916636 100644
--- a/block-sha1/sha1.h
+++ b/block-sha1/sha1.h
@@ -16,7 +16,9 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx);
void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, size_t len);
void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
+#ifndef platform_SHA_CTX
#define platform_SHA_CTX blk_SHA_CTX
#define platform_SHA1_Init blk_SHA1_Init
#define platform_SHA1_Update blk_SHA1_Update
#define platform_SHA1_Final blk_SHA1_Final
+#endif
diff --git a/bloom.c b/bloom.c
index aef6b5fea2..c428634105 100644
--- a/bloom.c
+++ b/bloom.c
@@ -2,11 +2,14 @@
#include "bloom.h"
#include "diff.h"
#include "diffcore.h"
-#include "revision.h"
#include "hashmap.h"
#include "commit-graph.h"
#include "commit.h"
#include "commit-slab.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "config.h"
+#include "repository.h"
define_commit_slab(bloom_filter_slab, struct bloom_filter);
@@ -29,9 +32,29 @@ static inline unsigned char get_bitmask(uint32_t pos)
return ((unsigned char)1) << (pos & (BITS_PER_WORD - 1));
}
-static int load_bloom_filter_from_graph(struct commit_graph *g,
- struct bloom_filter *filter,
- uint32_t graph_pos)
+static int check_bloom_offset(struct commit_graph *g, uint32_t pos,
+ uint32_t offset)
+{
+ /*
+ * Note that we allow offsets equal to the data size, which would set
+ * our pointers at one past the end of the chunk memory. This is
+ * necessary because the on-disk index points to the end of the
+ * entries (so we can compute size by comparing adjacent ones). And
+ * naturally the final entry's end is one-past-the-end of the chunk.
+ */
+ if (offset <= g->chunk_bloom_data_size - BLOOMDATA_CHUNK_HEADER_SIZE)
+ return 0;
+
+ warning("ignoring out-of-range offset (%"PRIuMAX") for changed-path"
+ " filter at pos %"PRIuMAX" of %s (chunk size: %"PRIuMAX")",
+ (uintmax_t)offset, (uintmax_t)pos,
+ g->filename, (uintmax_t)g->chunk_bloom_data_size);
+ return -1;
+}
+
+int load_bloom_filter_from_graph(struct commit_graph *g,
+ struct bloom_filter *filter,
+ uint32_t graph_pos)
{
uint32_t lex_pos, start_index, end_index;
@@ -51,10 +74,26 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
else
start_index = 0;
+ if (check_bloom_offset(g, lex_pos, end_index) < 0 ||
+ check_bloom_offset(g, lex_pos - 1, start_index) < 0)
+ return 0;
+
+ if (end_index < start_index) {
+ warning("ignoring decreasing changed-path index offsets"
+ " (%"PRIuMAX" > %"PRIuMAX") for positions"
+ " %"PRIuMAX" and %"PRIuMAX" of %s",
+ (uintmax_t)start_index, (uintmax_t)end_index,
+ (uintmax_t)(lex_pos-1), (uintmax_t)lex_pos,
+ g->filename);
+ return 0;
+ }
+
filter->len = end_index - start_index;
filter->data = (unsigned char *)(g->chunk_bloom_data +
sizeof(unsigned char) * start_index +
BLOOMDATA_CHUNK_HEADER_SIZE);
+ filter->version = g->bloom_filter_settings->hash_version;
+ filter->to_free = NULL;
return 1;
}
@@ -66,7 +105,64 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
* Not considered to be cryptographically secure.
* Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm
*/
-uint32_t murmur3_seeded(uint32_t seed, const char *data, size_t len)
+uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len)
+{
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
+ const uint32_t r1 = 15;
+ const uint32_t r2 = 13;
+ const uint32_t m = 5;
+ const uint32_t n = 0xe6546b64;
+ int i;
+ uint32_t k1 = 0;
+ const char *tail;
+
+ int len4 = len / sizeof(uint32_t);
+
+ uint32_t k;
+ for (i = 0; i < len4; i++) {
+ uint32_t byte1 = (uint32_t)(unsigned char)data[4*i];
+ uint32_t byte2 = ((uint32_t)(unsigned char)data[4*i + 1]) << 8;
+ uint32_t byte3 = ((uint32_t)(unsigned char)data[4*i + 2]) << 16;
+ uint32_t byte4 = ((uint32_t)(unsigned char)data[4*i + 3]) << 24;
+ k = byte1 | byte2 | byte3 | byte4;
+ k *= c1;
+ k = rotate_left(k, r1);
+ k *= c2;
+
+ seed ^= k;
+ seed = rotate_left(seed, r2) * m + n;
+ }
+
+ tail = (data + len4 * sizeof(uint32_t));
+
+ switch (len & (sizeof(uint32_t) - 1)) {
+ case 3:
+ k1 ^= ((uint32_t)(unsigned char)tail[2]) << 16;
+ /*-fallthrough*/
+ case 2:
+ k1 ^= ((uint32_t)(unsigned char)tail[1]) << 8;
+ /*-fallthrough*/
+ case 1:
+ k1 ^= ((uint32_t)(unsigned char)tail[0]) << 0;
+ k1 *= c1;
+ k1 = rotate_left(k1, r1);
+ k1 *= c2;
+ seed ^= k1;
+ break;
+ }
+
+ seed ^= (uint32_t)len;
+ seed ^= (seed >> 16);
+ seed *= 0x85ebca6b;
+ seed ^= (seed >> 13);
+ seed *= 0xc2b2ae35;
+ seed ^= (seed >> 16);
+
+ return seed;
+}
+
+static uint32_t murmur3_seeded_v1(uint32_t seed, const char *data, size_t len)
{
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
@@ -131,8 +227,14 @@ void fill_bloom_key(const char *data,
int i;
const uint32_t seed0 = 0x293ae76f;
const uint32_t seed1 = 0x7e646e2c;
- const uint32_t hash0 = murmur3_seeded(seed0, data, len);
- const uint32_t hash1 = murmur3_seeded(seed1, data, len);
+ uint32_t hash0, hash1;
+ if (settings->hash_version == 2) {
+ hash0 = murmur3_seeded_v2(seed0, data, len);
+ hash1 = murmur3_seeded_v2(seed1, data, len);
+ } else {
+ hash0 = murmur3_seeded_v1(seed0, data, len);
+ hash1 = murmur3_seeded_v1(seed1, data, len);
+ }
key->hashes = (uint32_t *)xcalloc(settings->num_hashes, sizeof(uint32_t));
for (i = 0; i < settings->num_hashes; i++)
@@ -164,6 +266,18 @@ void init_bloom_filters(void)
init_bloom_filter_slab(&bloom_filters);
}
+static void free_one_bloom_filter(struct bloom_filter *filter)
+{
+ if (!filter)
+ return;
+ free(filter->to_free);
+}
+
+void deinit_bloom_filters(void)
+{
+ deep_clear_bloom_filter_slab(&bloom_filters, free_one_bloom_filter);
+}
+
static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
@@ -177,11 +291,97 @@ static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED,
return strcmp(e1->path, e2->path);
}
-static void init_truncated_large_filter(struct bloom_filter *filter)
+static void init_truncated_large_filter(struct bloom_filter *filter,
+ int version)
{
- filter->data = xmalloc(1);
+ filter->data = filter->to_free = xmalloc(1);
filter->data[0] = 0xFF;
filter->len = 1;
+ filter->version = version;
+}
+
+#define VISITED (1u<<21)
+#define HIGH_BITS (1u<<22)
+
+static int has_entries_with_high_bit(struct repository *r, struct tree *t)
+{
+ if (parse_tree(t))
+ return 1;
+
+ if (!(t->object.flags & VISITED)) {
+ struct tree_desc desc;
+ struct name_entry entry;
+
+ init_tree_desc(&desc, &t->object.oid, t->buffer, t->size);
+ while (tree_entry(&desc, &entry)) {
+ size_t i;
+ for (i = 0; i < entry.pathlen; i++) {
+ if (entry.path[i] & 0x80) {
+ t->object.flags |= HIGH_BITS;
+ goto done;
+ }
+ }
+
+ if (S_ISDIR(entry.mode)) {
+ struct tree *sub = lookup_tree(r, &entry.oid);
+ if (sub && has_entries_with_high_bit(r, sub)) {
+ t->object.flags |= HIGH_BITS;
+ goto done;
+ }
+ }
+
+ }
+
+done:
+ t->object.flags |= VISITED;
+ }
+
+ return !!(t->object.flags & HIGH_BITS);
+}
+
+static int commit_tree_has_high_bit_paths(struct repository *r,
+ struct commit *c)
+{
+ struct tree *t;
+ if (repo_parse_commit(r, c))
+ return 1;
+ t = repo_get_commit_tree(r, c);
+ if (!t)
+ return 1;
+ return has_entries_with_high_bit(r, t);
+}
+
+static struct bloom_filter *upgrade_filter(struct repository *r, struct commit *c,
+ struct bloom_filter *filter,
+ int hash_version)
+{
+ struct commit_list *p = c->parents;
+ if (commit_tree_has_high_bit_paths(r, c))
+ return NULL;
+
+ if (p && commit_tree_has_high_bit_paths(r, p->item))
+ return NULL;
+
+ filter->version = hash_version;
+
+ return filter;
+}
+
+struct bloom_filter *get_bloom_filter(struct repository *r, struct commit *c)
+{
+ struct bloom_filter *filter;
+ int hash_version;
+
+ filter = get_or_compute_bloom_filter(r, c, 0, NULL, NULL);
+ if (!filter)
+ return NULL;
+
+ prepare_repo_settings(r);
+ hash_version = r->settings.commit_graph_changed_paths_version;
+
+ if (!(hash_version == -1 || hash_version == filter->version))
+ return NULL; /* unusable filter */
+ return filter;
}
struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
@@ -209,8 +409,23 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
filter, graph_pos);
}
- if (filter->data && filter->len)
- return filter;
+ if (filter->data && filter->len) {
+ struct bloom_filter *upgrade;
+ if (!settings || settings->hash_version == filter->version)
+ return filter;
+
+ /* version mismatch, see if we can upgrade */
+ if (compute_if_not_present &&
+ git_env_bool("GIT_TEST_UPGRADE_BLOOM_FILTERS", 1)) {
+ upgrade = upgrade_filter(r, c, filter,
+ settings->hash_version);
+ if (upgrade) {
+ if (computed)
+ *computed |= BLOOM_UPGRADED;
+ return upgrade;
+ }
+ }
+ }
if (!compute_if_not_present)
return NULL;
@@ -261,24 +476,25 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
*last_slash = '\0';
} while (*path);
-
- diff_free_filepair(diff_queued_diff.queue[i]);
}
if (hashmap_get_size(&pathmap) > settings->max_changed_paths) {
- init_truncated_large_filter(filter);
+ init_truncated_large_filter(filter,
+ settings->hash_version);
if (computed)
*computed |= BLOOM_TRUNC_LARGE;
goto cleanup;
}
filter->len = (hashmap_get_size(&pathmap) * settings->bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ filter->version = settings->hash_version;
if (!filter->len) {
if (computed)
*computed |= BLOOM_TRUNC_EMPTY;
filter->len = 1;
}
CALLOC_ARRAY(filter->data, filter->len);
+ filter->to_free = filter->data;
hashmap_for_each_entry(&pathmap, &iter, e, entry) {
struct bloom_key key;
@@ -290,9 +506,7 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
cleanup:
hashmap_clear_and_free(&pathmap, struct pathmap_hash_entry, entry);
} else {
- for (i = 0; i < diff_queued_diff.nr; i++)
- diff_free_filepair(diff_queued_diff.queue[i]);
- init_truncated_large_filter(filter);
+ init_truncated_large_filter(filter, settings->hash_version);
if (computed)
*computed |= BLOOM_TRUNC_LARGE;
@@ -301,9 +515,7 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
if (computed)
*computed |= BLOOM_COMPUTED;
- free(diff_queued_diff.queue);
- DIFF_QUEUE_CLEAR(&diff_queued_diff);
-
+ diff_queue_clear(&diff_queued_diff);
return filter;
}
diff --git a/bloom.h b/bloom.h
index adde6dfe21..6e46489a20 100644
--- a/bloom.h
+++ b/bloom.h
@@ -3,19 +3,22 @@
struct commit;
struct repository;
+struct commit_graph;
struct bloom_filter_settings {
/*
* The version of the hashing technique being used.
- * We currently only support version = 1 which is
+ * The newest version is 2, which is
* the seeded murmur3 hashing technique implemented
- * in bloom.c.
+ * in bloom.c. Bloom filters of version 1 were created
+ * with prior versions of Git, which had a bug in the
+ * implementation of the hash function.
*/
uint32_t hash_version;
/*
* The number of times a path is hashed, i.e. the
- * number of bit positions tht cumulatively
+ * number of bit positions that cumulatively
* determine whether a path is present in the
* Bloom filter.
*/
@@ -52,6 +55,9 @@ struct bloom_filter_settings {
struct bloom_filter {
unsigned char *data;
size_t len;
+ int version;
+
+ void *to_free;
};
/*
@@ -68,6 +74,10 @@ struct bloom_key {
uint32_t *hashes;
};
+int load_bloom_filter_from_graph(struct commit_graph *g,
+ struct bloom_filter *filter,
+ uint32_t graph_pos);
+
/*
* Calculate the murmur3 32-bit hash value for the given data
* using the given seed.
@@ -75,7 +85,7 @@ struct bloom_key {
* Not considered to be cryptographically secure.
* Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm
*/
-uint32_t murmur3_seeded(uint32_t seed, const char *data, size_t len);
+uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len);
void fill_bloom_key(const char *data,
size_t len,
@@ -88,12 +98,14 @@ void add_key_to_filter(const struct bloom_key *key,
const struct bloom_filter_settings *settings);
void init_bloom_filters(void);
+void deinit_bloom_filters(void);
enum bloom_filter_computed {
BLOOM_NOT_COMPUTED = (1 << 0),
BLOOM_COMPUTED = (1 << 1),
BLOOM_TRUNC_LARGE = (1 << 2),
BLOOM_TRUNC_EMPTY = (1 << 3),
+ BLOOM_UPGRADED = (1 << 4),
};
struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
@@ -102,8 +114,24 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
const struct bloom_filter_settings *settings,
enum bloom_filter_computed *computed);
-#define get_bloom_filter(r, c) get_or_compute_bloom_filter( \
- (r), (c), 0, NULL, NULL)
+/*
+ * Find the Bloom filter associated with the given commit "c".
+ *
+ * If any of the following are true
+ *
+ * - the repository does not have a commit-graph, or
+ * - the repository disables reading from the commit-graph, or
+ * - the given commit does not have a Bloom filter computed, or
+ * - there is a Bloom filter for commit "c", but it cannot be read
+ * because the filter uses an incompatible version of murmur3
+ *
+ * , then `get_bloom_filter()` will return NULL. Otherwise, the corresponding
+ * Bloom filter will be returned.
+ *
+ * For callers who wish to inspect Bloom filters with incompatible hash
+ * versions, use get_or_compute_bloom_filter().
+ */
+struct bloom_filter *get_bloom_filter(struct repository *r, struct commit *c);
int bloom_filter_contains(const struct bloom_filter *filter,
const struct bloom_key *key,
diff --git a/branch.c b/branch.c
index 3e4684f79f..ebaa870c01 100644
--- a/branch.c
+++ b/branch.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "config.h"
@@ -370,10 +372,14 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
*/
int validate_branchname(const char *name, struct strbuf *ref)
{
- if (strbuf_check_branch_ref(ref, name))
- die(_("'%s' is not a valid branch name"), name);
+ if (strbuf_check_branch_ref(ref, name)) {
+ int code = die_message(_("'%s' is not a valid branch name"), name);
+ advise_if_enabled(ADVICE_REF_SYNTAX,
+ _("See `man git check-ref-format`"));
+ exit(code);
+ }
- return ref_exists(ref->buf);
+ return refs_ref_exists(get_main_ref_store(the_repository), ref->buf);
}
static int initialized_checked_out_branches;
@@ -420,9 +426,9 @@ static void prepare_checked_out_branches(void)
wt_status_state_free_buffers(&state);
if (wt_status_check_bisect(wt, &state) &&
- state.branch) {
+ state.bisecting_from) {
struct strbuf ref = STRBUF_INIT;
- strbuf_addf(&ref, "refs/heads/%s", state.branch);
+ strbuf_addf(&ref, "refs/heads/%s", state.bisecting_from);
old = strmap_put(&current_checked_out_branches,
ref.buf,
xstrdup(wt->path));
@@ -595,6 +601,7 @@ void create_branch(struct repository *r,
int forcing = 0;
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
+ int flags = 0;
char *msg;
if (track == BRANCH_TRACK_OVERRIDE)
@@ -613,17 +620,18 @@ void create_branch(struct repository *r,
goto cleanup;
if (reflog)
- log_all_ref_updates = LOG_REFS_NORMAL;
+ flags |= REF_FORCE_CREATE_REFLOG;
if (forcing)
msg = xstrfmt("branch: Reset to %s", start_name);
else
msg = xstrfmt("branch: Created from %s", start_name);
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf,
&oid, forcing ? NULL : null_oid(),
- 0, msg, &err) ||
+ NULL, NULL, flags, msg, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
@@ -730,11 +738,12 @@ static int submodule_create_branch(struct repository *r,
strbuf_release(&child_err);
strbuf_release(&out_buf);
+ free(out_prefix);
return ret;
}
void create_branches_recursively(struct repository *r, const char *name,
- const char *start_commitish,
+ const char *start_committish,
const char *tracking_name, int force,
int reflog, int quiet, enum branch_track track,
int dry_run)
@@ -744,8 +753,8 @@ void create_branches_recursively(struct repository *r, const char *name,
struct object_id super_oid;
struct submodule_entry_list submodule_entry_list;
- /* Perform dwim on start_commitish to get super_oid and branch_point. */
- dwim_branch_start(r, start_commitish, BRANCH_TRACK_NEVER,
+ /* Perform dwim on start_committish to get super_oid and branch_point. */
+ dwim_branch_start(r, start_committish, BRANCH_TRACK_NEVER,
&branch_point, &super_oid);
/*
@@ -768,7 +777,7 @@ void create_branches_recursively(struct repository *r, const char *name,
submodule_entry_list.entries[i].submodule->name);
if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED))
advise(_("You may try updating the submodules using 'git checkout --no-recurse-submodules %s && git submodule update --init'"),
- start_commitish);
+ start_committish);
exit(code);
}
@@ -783,10 +792,10 @@ void create_branches_recursively(struct repository *r, const char *name,
name);
}
- create_branch(r, name, start_commitish, force, 0, reflog, quiet,
+ create_branch(r, name, start_committish, force, 0, reflog, quiet,
BRANCH_TRACK_NEVER, dry_run);
if (dry_run)
- return;
+ goto out;
/*
* NEEDSWORK If tracking was set up in the superproject but not the
* submodule, users might expect "git branch --recurse-submodules" to
@@ -807,8 +816,11 @@ void create_branches_recursively(struct repository *r, const char *name,
die(_("submodule '%s': cannot create branch '%s'"),
submodule_entry_list.entries[i].submodule->name,
name);
- repo_clear(submodule_entry_list.entries[i].repo);
}
+
+out:
+ submodule_entry_list_release(&submodule_entry_list);
+ free(branch_point);
}
void remove_merge_branch_state(struct repository *r)
@@ -817,8 +829,9 @@ void remove_merge_branch_state(struct repository *r)
unlink(git_path_merge_rr(r));
unlink(git_path_merge_msg(r));
unlink(git_path_merge_mode(r));
- unlink(git_path_auto_merge(r));
- save_autostash(git_path_merge_autostash(r));
+ refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
+ NULL, REF_NO_DEREF);
+ save_autostash_ref(r, "MERGE_AUTOSTASH");
}
void remove_branch_state(struct repository *r, int verbose)
@@ -838,7 +851,7 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree)
if (is_shared_symref(worktrees[i], "HEAD", branch)) {
skip_prefix(branch, "refs/heads/", &branch);
- die(_("'%s' is already checked out at '%s'"),
+ die(_("'%s' is already used by worktree at '%s'"),
branch, worktrees[i]->path);
}
}
diff --git a/branch.h b/branch.h
index 30c01aed73..ec2f35fda4 100644
--- a/branch.h
+++ b/branch.h
@@ -78,26 +78,26 @@ void create_branch(struct repository *r,
* those of create_branch() except for start_name, which is represented
* by two different parameters:
*
- * - start_commitish is the commit-ish, in repository r, that determines
+ * - start_committish is the commit-ish, in repository r, that determines
* which commits the branches will point to. The superproject branch
- * will point to the commit of start_commitish and the submodule
- * branches will point to the gitlink commit oids in start_commitish's
+ * will point to the commit of start_committish and the submodule
+ * branches will point to the gitlink commit oids in start_committish's
* tree.
*
* - tracking_name is the name of the ref, in repository r, that will be
* used to set up tracking information. This value is propagated to
* all submodules, which will evaluate the ref using their own ref
- * stores. If NULL, this defaults to start_commitish.
+ * stores. If NULL, this defaults to start_committish.
*
- * When this function is called on the superproject, start_commitish
+ * When this function is called on the superproject, start_committish
* can be any user-provided ref and tracking_name can be NULL (similar
* to create_branches()). But when recursing through submodules,
- * start_commitish is the plain gitlink commit oid. Since the oid cannot
+ * start_committish is the plain gitlink commit oid. Since the oid cannot
* be used for tracking information, tracking_name is propagated and
* used for tracking instead.
*/
void create_branches_recursively(struct repository *r, const char *name,
- const char *start_commitish,
+ const char *start_committish,
const char *tracking_name, int force,
int reflog, int quiet, enum branch_track track,
int dry_run);
diff --git a/builtin.h b/builtin.h
index d560baa661..f7b166b334 100644
--- a/builtin.h
+++ b/builtin.h
@@ -2,6 +2,7 @@
#define BUILTIN_H
#include "git-compat-util.h"
+#include "repository.h"
/*
* builtin API
@@ -114,141 +115,143 @@ int is_builtin(const char *s);
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);
-int cmd_apply(int argc, const char **argv, const char *prefix);
-int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect(int argc, const char **argv, const char *prefix);
-int cmd_blame(int argc, const char **argv, const char *prefix);
-int cmd_branch(int argc, const char **argv, const char *prefix);
-int cmd_bugreport(int argc, const char **argv, const char *prefix);
-int cmd_bundle(int argc, const char **argv, const char *prefix);
-int cmd_cat_file(int argc, const char **argv, const char *prefix);
-int cmd_checkout(int argc, const char **argv, const char *prefix);
-int cmd_checkout__worker(int argc, const char **argv, const char *prefix);
-int cmd_checkout_index(int argc, const char **argv, const char *prefix);
-int cmd_check_attr(int argc, const char **argv, const char *prefix);
-int cmd_check_ignore(int argc, const char **argv, const char *prefix);
-int cmd_check_mailmap(int argc, const char **argv, const char *prefix);
-int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
-int cmd_cherry(int argc, const char **argv, const char *prefix);
-int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
-int cmd_clone(int argc, const char **argv, const char *prefix);
-int cmd_clean(int argc, const char **argv, const char *prefix);
-int cmd_column(int argc, const char **argv, const char *prefix);
-int cmd_commit(int argc, const char **argv, const char *prefix);
-int cmd_commit_graph(int argc, const char **argv, const char *prefix);
-int cmd_commit_tree(int argc, const char **argv, const char *prefix);
-int cmd_config(int argc, const char **argv, const char *prefix);
-int cmd_count_objects(int argc, const char **argv, const char *prefix);
-int cmd_credential(int argc, const char **argv, const char *prefix);
-int cmd_credential_cache(int argc, const char **argv, const char *prefix);
-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
-int cmd_credential_store(int argc, const char **argv, const char *prefix);
-int cmd_describe(int argc, const char **argv, const char *prefix);
-int cmd_diagnose(int argc, const char **argv, const char *prefix);
-int cmd_diff_files(int argc, const char **argv, const char *prefix);
-int cmd_diff_index(int argc, const char **argv, const char *prefix);
-int cmd_diff(int argc, const char **argv, const char *prefix);
-int cmd_diff_tree(int argc, const char **argv, const char *prefix);
-int cmd_difftool(int argc, const char **argv, const char *prefix);
-int cmd_env__helper(int argc, const char **argv, const char *prefix);
-int cmd_fast_export(int argc, const char **argv, const char *prefix);
-int cmd_fast_import(int argc, const char **argv, const char *prefix);
-int cmd_fetch(int argc, const char **argv, const char *prefix);
-int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
-int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
-int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
-int cmd_for_each_repo(int argc, const char **argv, const char *prefix);
-int cmd_format_patch(int argc, const char **argv, const char *prefix);
-int cmd_fsck(int argc, const char **argv, const char *prefix);
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix);
-int cmd_gc(int argc, const char **argv, const char *prefix);
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
-int cmd_grep(int argc, const char **argv, const char *prefix);
-int cmd_hash_object(int argc, const char **argv, const char *prefix);
-int cmd_help(int argc, const char **argv, const char *prefix);
-int cmd_hook(int argc, const char **argv, const char *prefix);
-int cmd_index_pack(int argc, const char **argv, const char *prefix);
-int cmd_init_db(int argc, const char **argv, const char *prefix);
-int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
-int cmd_log(int argc, const char **argv, const char *prefix);
-int cmd_log_reflog(int argc, const char **argv, const char *prefix);
-int cmd_ls_files(int argc, const char **argv, const char *prefix);
-int cmd_ls_tree(int argc, const char **argv, const char *prefix);
-int cmd_ls_remote(int argc, const char **argv, const char *prefix);
-int cmd_mailinfo(int argc, const char **argv, const char *prefix);
-int cmd_mailsplit(int argc, const char **argv, const char *prefix);
-int cmd_maintenance(int argc, const char **argv, const char *prefix);
-int cmd_merge(int argc, const char **argv, const char *prefix);
-int cmd_merge_base(int argc, const char **argv, const char *prefix);
-int cmd_merge_index(int argc, const char **argv, const char *prefix);
-int cmd_merge_ours(int argc, const char **argv, const char *prefix);
-int cmd_merge_file(int argc, const char **argv, const char *prefix);
-int cmd_merge_recursive(int argc, const char **argv, const char *prefix);
-int cmd_merge_tree(int argc, const char **argv, const char *prefix);
-int cmd_mktag(int argc, const char **argv, const char *prefix);
-int cmd_mktree(int argc, const char **argv, const char *prefix);
-int cmd_multi_pack_index(int argc, const char **argv, const char *prefix);
-int cmd_mv(int argc, const char **argv, const char *prefix);
-int cmd_name_rev(int argc, const char **argv, const char *prefix);
-int cmd_notes(int argc, const char **argv, const char *prefix);
-int cmd_pack_objects(int argc, const char **argv, const char *prefix);
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix);
-int cmd_patch_id(int argc, const char **argv, const char *prefix);
-int cmd_prune(int argc, const char **argv, const char *prefix);
-int cmd_prune_packed(int argc, const char **argv, const char *prefix);
-int cmd_pull(int argc, const char **argv, const char *prefix);
-int cmd_push(int argc, const char **argv, const char *prefix);
-int cmd_range_diff(int argc, const char **argv, const char *prefix);
-int cmd_read_tree(int argc, const char **argv, const char *prefix);
-int cmd_rebase(int argc, const char **argv, const char *prefix);
-int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);
-int cmd_receive_pack(int argc, const char **argv, const char *prefix);
-int cmd_reflog(int argc, const char **argv, const char *prefix);
-int cmd_remote(int argc, const char **argv, const char *prefix);
-int cmd_remote_ext(int argc, const char **argv, const char *prefix);
-int cmd_remote_fd(int argc, const char **argv, const char *prefix);
-int cmd_repack(int argc, const char **argv, const char *prefix);
-int cmd_rerere(int argc, const char **argv, const char *prefix);
-int cmd_reset(int argc, const char **argv, const char *prefix);
-int cmd_restore(int argc, const char **argv, const char *prefix);
-int cmd_rev_list(int argc, const char **argv, const char *prefix);
-int cmd_rev_parse(int argc, const char **argv, const char *prefix);
-int cmd_revert(int argc, const char **argv, const char *prefix);
-int cmd_rm(int argc, const char **argv, const char *prefix);
-int cmd_send_pack(int argc, const char **argv, const char *prefix);
-int cmd_shortlog(int argc, const char **argv, const char *prefix);
-int cmd_show(int argc, const char **argv, const char *prefix);
-int cmd_show_branch(int argc, const char **argv, const char *prefix);
-int cmd_show_index(int argc, const char **argv, const char *prefix);
-int cmd_sparse_checkout(int argc, const char **argv, const char *prefix);
-int cmd_status(int argc, const char **argv, const char *prefix);
-int cmd_stash(int argc, const char **argv, const char *prefix);
-int cmd_stripspace(int argc, const char **argv, const char *prefix);
-int cmd_submodule__helper(int argc, const char **argv, const char *prefix);
-int cmd_switch(int argc, const char **argv, const char *prefix);
-int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
-int cmd_tag(int argc, const char **argv, const char *prefix);
-int cmd_unpack_file(int argc, const char **argv, const char *prefix);
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
-int cmd_update_index(int argc, const char **argv, const char *prefix);
-int cmd_update_ref(int argc, const char **argv, const char *prefix);
-int cmd_update_server_info(int argc, const char **argv, const char *prefix);
-int cmd_upload_archive(int argc, const char **argv, const char *prefix);
-int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
-int cmd_upload_pack(int argc, const char **argv, const char *prefix);
-int cmd_var(int argc, const char **argv, const char *prefix);
-int cmd_verify_commit(int argc, const char **argv, const char *prefix);
-int cmd_verify_tag(int argc, const char **argv, const char *prefix);
-int cmd_version(int argc, const char **argv, const char *prefix);
-int cmd_whatchanged(int argc, const char **argv, const char *prefix);
-int cmd_worktree(int argc, const char **argv, const char *prefix);
-int cmd_write_tree(int argc, const char **argv, const char *prefix);
-int cmd_verify_pack(int argc, const char **argv, const char *prefix);
-int cmd_show_ref(int argc, const char **argv, const char *prefix);
-int cmd_pack_refs(int argc, const char **argv, const char *prefix);
-int cmd_replace(int argc, const char **argv, const char *prefix);
+int cmd_add(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_am(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_annotate(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_apply(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bisect(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_blame(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_branch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bugreport(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bundle(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cat_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout__worker(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_attr(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_ignore(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_mailmap(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_ref_format(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cherry(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cherry_pick(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_clone(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_clean(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_column(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit_graph(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_config(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_count_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_cache(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_store(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_describe(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diagnose(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_files(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_difftool(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_env__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fast_export(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fast_import(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fetch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_for_each_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_for_each_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_format_patch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fsck(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_gc(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_grep(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_hash_object(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_help(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_hook(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_index_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_init_db(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_interpret_trailers(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_log_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_log(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_files(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_remote(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mailinfo(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mailsplit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_maintenance(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_base(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_ours(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_recursive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mktag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mktree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_multi_pack_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mv(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_name_rev(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_notes(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_patch_id(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_prune(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_prune_packed(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pull(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_push(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_range_diff(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_read_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rebase(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rebase__interactive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_receive_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_refs(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rev_list(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rev_parse(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_revert(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rm(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_send_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_shortlog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_branch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_sparse_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_status(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_stash(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_stripspace(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_submodule__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_switch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_symbolic_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_tag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_unpack_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_server_info(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_var(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_tag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_whatchanged(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_worktree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_write_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_refs(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_replace(int argc, const char **argv, const char *prefix, struct repository *repo);
#endif
diff --git a/builtin/add.c b/builtin/add.c
index 0057392f98..7d35307792 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -3,7 +3,6 @@
*
* Copyright (C) 2006 Linus Torvalds
*/
-#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -12,16 +11,12 @@
#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"
@@ -39,24 +34,27 @@ static int pathspec_file_nul;
static int include_sparse;
static const char *pathspec_from_file;
-static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
+static int chmod_pathspec(struct repository *repo,
+ struct pathspec *pathspec,
+ char flip,
+ int show_only)
{
int i, ret = 0;
- for (i = 0; i < the_index.cache_nr; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < repo->index->cache_nr; i++) {
+ struct cache_entry *ce = repo->index->cache[i];
int err;
if (!include_sparse &&
(ce_skip_worktree(ce) ||
- !path_in_sparse_checkout(ce->name, &the_index)))
+ !path_in_sparse_checkout(ce->name, repo->index)))
continue;
- if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
+ if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL))
continue;
if (!show_only)
- err = chmod_index_entry(&the_index, ce, flip);
+ err = chmod_index_entry(repo->index, ce, flip);
else
err = S_ISREG(ce->ce_mode) ? 0 : -1;
@@ -67,31 +65,36 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
return ret;
}
-static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
+static int renormalize_tracked_files(struct repository *repo,
+ const struct pathspec *pathspec,
+ int flags)
{
int i, retval = 0;
- for (i = 0; i < the_index.cache_nr; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < repo->index->cache_nr; i++) {
+ struct cache_entry *ce = repo->index->cache[i];
if (!include_sparse &&
(ce_skip_worktree(ce) ||
- !path_in_sparse_checkout(ce->name, &the_index)))
+ !path_in_sparse_checkout(ce->name, repo->index)))
continue;
if (ce_stage(ce))
continue; /* do not touch unmerged paths */
if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
continue; /* do not touch non blobs */
- if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
+ if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL))
continue;
- retval |= add_file_to_index(&the_index, ce->name,
+ retval |= add_file_to_index(repo->index, ce->name,
flags | ADD_CACHE_RENORMALIZE);
}
return retval;
}
-static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
+static char *prune_directory(struct repository *repo,
+ struct dir_struct *dir,
+ struct pathspec *pathspec,
+ int prefix)
{
char *seen;
int i;
@@ -103,33 +106,33 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (dir_path_match(&the_index, entry, pathspec, prefix, seen))
+ if (dir_path_match(repo->index, entry, pathspec, prefix, seen))
*dst++ = entry;
}
dir->nr = dst - dir->entries;
- add_pathspec_matches_against_index(pathspec, &the_index, seen,
+ add_pathspec_matches_against_index(pathspec, repo->index, seen,
PS_IGNORE_SKIP_WORKTREE);
return seen;
}
-static int refresh(int verbose, const struct pathspec *pathspec)
+static int refresh(struct repository *repo, int verbose, const struct pathspec *pathspec)
{
char *seen;
int i, ret = 0;
char *skip_worktree_seen = NULL;
struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
- int flags = REFRESH_IGNORE_SKIP_WORKTREE |
+ unsigned int flags = REFRESH_IGNORE_SKIP_WORKTREE |
(verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
seen = xcalloc(pathspec->nr, 1);
- refresh_index(&the_index, flags, pathspec, seen,
+ refresh_index(repo->index, flags, pathspec, seen,
_("Unstaged changes after refreshing the index:"));
for (i = 0; i < pathspec->nr; i++) {
if (!seen[i]) {
const char *path = pathspec->items[i].original;
if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
- !path_in_sparse_checkout(path, &the_index)) {
+ !path_in_sparse_checkout(path, repo->index)) {
string_list_append(&only_match_skip_worktree,
pathspec->items[i].original);
} else {
@@ -150,14 +153,13 @@ static int refresh(int verbose, const struct pathspec *pathspec)
return ret;
}
-int interactive_add(const char **argv, const char *prefix, int patch)
+int interactive_add(struct repository *repo,
+ const char **argv,
+ const char *prefix,
+ int patch)
{
struct pathspec pathspec;
- int unused;
-
- if (!git_config_get_bool("add.interactive.usebuiltin", &unused))
- warning(_("the add.interactive.useBuiltin setting has been removed!\n"
- "See its entry in 'git help config' for details."));
+ int ret;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
@@ -166,25 +168,31 @@ int interactive_add(const char **argv, const char *prefix, int patch)
prefix, argv);
if (patch)
- return !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
+ ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec);
else
- return !!run_add_i(the_repository, &pathspec);
+ ret = !!run_add_i(repo, &pathspec);
+
+ clear_pathspec(&pathspec);
+ return ret;
}
-static int edit_patch(int argc, const char **argv, const char *prefix)
+static int edit_patch(struct repository *repo,
+ int argc,
+ const char **argv,
+ const char *prefix)
{
- char *file = git_pathdup("ADD_EDIT.patch");
+ char *file = repo_git_path(repo, "ADD_EDIT.patch");
struct child_process child = CHILD_PROCESS_INIT;
struct rev_info rev;
int out;
struct stat st;
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(repo, git_diff_basic_config, NULL);
- if (repo_read_index(the_repository) < 0)
+ if (repo_read_index(repo) < 0)
die(_("could not read the index"));
- repo_init_revisions(the_repository, &rev, prefix);
+ repo_init_revisions(repo, &rev, prefix);
rev.diffopt.context = 7;
argc = setup_revisions(argc, argv, &rev, NULL);
@@ -231,6 +239,8 @@ static char *chmod_arg;
static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_ARG(arg);
+
/* if we are told to ignore, we are not adding removals */
*(int *)opt->value = !unset ? 0 : 1;
return 0;
@@ -311,16 +321,16 @@ static void check_embedded_repo(const char *path)
strbuf_strip_suffix(&name, "/");
warning(_("adding embedded git repository: %s"), name.buf);
- if (!adviced_on_embedded_repo &&
- advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {
- advise(embedded_advice, name.buf, name.buf);
+ if (!adviced_on_embedded_repo) {
+ advise_if_enabled(ADVICE_ADD_EMBEDDED_REPO,
+ embedded_advice, name.buf, name.buf);
adviced_on_embedded_repo = 1;
}
strbuf_release(&name);
}
-static int add_files(struct dir_struct *dir, int flags)
+static int add_files(struct repository *repo, struct dir_struct *dir, int flags)
{
int i, exit_status = 0;
struct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;
@@ -329,21 +339,19 @@ static int add_files(struct dir_struct *dir, int flags)
fprintf(stderr, _(ignore_error));
for (i = 0; i < dir->ignored_nr; i++)
fprintf(stderr, "%s\n", dir->ignored[i]->name);
- if (advice_enabled(ADVICE_ADD_IGNORED_FILE))
- advise(_("Use -f if you really want to add them.\n"
- "Turn this message off by running\n"
- "\"git config advice.addIgnoredFile false\""));
+ advise_if_enabled(ADVICE_ADD_IGNORED_FILE,
+ _("Use -f if you really want to add them."));
exit_status = 1;
}
for (i = 0; i < dir->nr; i++) {
if (!include_sparse &&
- !path_in_sparse_checkout(dir->entries[i]->name, &the_index)) {
+ !path_in_sparse_checkout(dir->entries[i]->name, repo->index)) {
string_list_append(&matched_sparse_paths,
dir->entries[i]->name);
continue;
}
- if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
+ if (add_file_to_index(repo->index, dir->entries[i]->name, flags)) {
if (!ignore_add_errors)
die(_("adding files failed"));
exit_status = 1;
@@ -362,7 +370,10 @@ static int add_files(struct dir_struct *dir, int flags)
return exit_status;
}
-int cmd_add(int argc, const char **argv, const char *prefix)
+int cmd_add(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo)
{
int exit_status = 0;
struct pathspec pathspec;
@@ -371,9 +382,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int add_new_files;
int require_pathspec;
char *seen = NULL;
+ char *ps_matched = NULL;
struct lock_file lock_file = LOCK_INIT;
- git_config(add_config, NULL);
+ if (repo)
+ repo_config(repo, add_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_add_options,
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
@@ -384,13 +397,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch");
if (pathspec_from_file)
die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
- exit(interactive_add(argv + 1, prefix, patch_interactive));
+ exit(interactive_add(repo, argv + 1, prefix, patch_interactive));
}
if (edit_interactive) {
if (pathspec_from_file)
die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--edit");
- return(edit_patch(argc, argv, prefix));
+ return(edit_patch(repo, argc, argv, prefix));
}
argc--;
argv++;
@@ -413,16 +426,16 @@ int cmd_add(int argc, const char **argv, const char *prefix)
add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
- prepare_repo_settings(the_repository);
- the_repository->settings.command_requires_full_index = 0;
+ prepare_repo_settings(repo);
+ repo->settings.command_requires_full_index = 0;
- repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(repo, &lock_file, LOCK_DIE_ON_ERROR);
/*
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
*/
- parse_pathspec(&pathspec, PATHSPEC_ATTR,
+ parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv);
@@ -431,7 +444,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (pathspec.nr)
die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
- parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
+ parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, pathspec_from_file, pathspec_file_nul);
@@ -441,10 +454,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (require_pathspec && pathspec.nr == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
- if (advice_enabled(ADVICE_ADD_EMPTY_PATHSPEC))
- advise( _("Maybe you wanted to say 'git add .'?\n"
- "Turn this message off by running\n"
- "\"git config advice.addEmptyPathspec false\""));
+ advise_if_enabled(ADVICE_ADD_EMPTY_PATHSPEC,
+ _("Maybe you wanted to say 'git add .'?"));
return 0;
}
@@ -459,11 +470,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));
- if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
+ if (repo_read_index_preload(repo, &pathspec, 0) < 0)
die(_("index file corrupt"));
- die_in_unpopulated_submodule(&the_index, prefix);
- die_path_inside_submodule(&the_index, &pathspec);
+ die_in_unpopulated_submodule(repo->index, prefix);
+ die_path_inside_submodule(repo->index, &pathspec);
if (add_new_files) {
int baselen;
@@ -475,13 +486,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
/* This picks up the paths that are not tracked */
- baselen = fill_directory(&dir, &the_index, &pathspec);
+ baselen = fill_directory(&dir, repo->index, &pathspec);
if (pathspec.nr)
- seen = prune_directory(&dir, &pathspec, baselen);
+ seen = prune_directory(repo, &dir, &pathspec, baselen);
}
if (refresh_only) {
- exit_status |= refresh(verbose, &pathspec);
+ exit_status |= refresh(repo, verbose, &pathspec);
goto finish;
}
@@ -492,7 +503,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (!seen)
seen = find_pathspecs_matching_against_index(&pathspec,
- &the_index, PS_IGNORE_SKIP_WORKTREE);
+ repo->index, PS_IGNORE_SKIP_WORKTREE);
/*
* file_exists() assumes exact match
@@ -502,7 +513,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
@@ -527,8 +539,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
!file_exists(path)) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
- if (is_excluded(&dir, &the_index, path, &dtype))
- dir_add_ignored(&dir, &the_index,
+ if (is_excluded(&dir, repo->index, path, &dtype))
+ dir_add_ignored(&dir, repo->index,
path, pathspec.items[i].len);
} else
die(_("pathspec '%s' did not match any files"),
@@ -549,25 +561,31 @@ int cmd_add(int argc, const char **argv, const char *prefix)
begin_odb_transaction();
+ ps_matched = xcalloc(pathspec.nr, 1);
if (add_renormalize)
- exit_status |= renormalize_tracked_files(&pathspec, flags);
+ exit_status |= renormalize_tracked_files(repo, &pathspec, flags);
else
- exit_status |= add_files_to_cache(the_repository, prefix,
- &pathspec, include_sparse,
- flags);
+ exit_status |= add_files_to_cache(repo, prefix,
+ &pathspec, ps_matched,
+ include_sparse, flags);
+
+ if (take_worktree_changes && !add_renormalize && !ignore_add_errors &&
+ report_path_error(ps_matched, &pathspec))
+ exit(128);
if (add_new_files)
- exit_status |= add_files(&dir, flags);
+ exit_status |= add_files(repo, &dir, flags);
if (chmod_arg && pathspec.nr)
- exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
+ exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
end_odb_transaction();
finish:
- if (write_locked_index(&the_index, &lock_file,
+ if (write_locked_index(repo->index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write new index file"));
+ free(ps_matched);
dir_clear(&dir);
clear_pathspec(&pathspec);
return exit_status;
diff --git a/builtin/am.c b/builtin/am.c
index 6655059a57..bfa95147cf 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -3,14 +3,14 @@
*
* Based on git-am.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_VARIABLE
+
+#define USE_THE_REPOSITORY_VARIABLE
#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"
@@ -24,7 +24,6 @@
#include "refs.h"
#include "commit.h"
#include "diff.h"
-#include "diffcore.h"
#include "unpack-trees.h"
#include "branch.h"
#include "object-name.h"
@@ -35,14 +34,11 @@
#include "log-tree.h"
#include "notes-utils.h"
#include "rerere.h"
-#include "prompt.h"
#include "mailinfo.h"
#include "apply.h"
#include "string-list.h"
-#include "packfile.h"
#include "pager.h"
#include "path.h"
-#include "repository.h"
#include "pretty.h"
/**
@@ -92,9 +88,16 @@ enum signoff_type {
SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
};
-enum show_patch_type {
- SHOW_PATCH_RAW = 0,
- SHOW_PATCH_DIFF = 1,
+enum resume_type {
+ RESUME_FALSE = 0,
+ RESUME_APPLY,
+ RESUME_RESOLVED,
+ RESUME_SKIP,
+ RESUME_ABORT,
+ RESUME_QUIT,
+ RESUME_SHOW_PATCH_RAW,
+ RESUME_SHOW_PATCH_DIFF,
+ RESUME_ALLOW_EMPTY,
};
enum empty_action {
@@ -405,7 +408,7 @@ static void am_load(struct am_state *state)
read_commit_msg(state);
if (read_state_file(&sb, state, "original-commit", 1) < 0)
- oidclr(&state->orig_commit);
+ oidclr(&state->orig_commit, the_repository->hash_algo);
else if (get_oid_hex(sb.buf, &state->orig_commit) < 0)
die(_("could not parse %s"), am_path(state, "original-commit"));
@@ -487,7 +490,8 @@ static int run_applypatch_msg_hook(struct am_state *state)
assert(state->msg);
if (!state->no_verify)
- ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+ ret = run_hooks_l(the_repository, "applypatch-msg",
+ am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
@@ -509,7 +513,7 @@ static int run_post_rewrite_hook(const struct am_state *state)
strvec_push(&opt.args, "rebase");
opt.path_to_stdin = am_path(state, "rewritten");
- return run_hooks_opt("post-rewrite", &opt);
+ return run_hooks_opt(the_repository, "post-rewrite", &opt);
}
/**
@@ -998,7 +1002,8 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "REBASE_HEAD", NULL, REF_NO_DEREF);
if (split_mail(state, patch_format, paths, keep_cr) < 0) {
am_destroy(state);
@@ -1078,12 +1083,15 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
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,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "am", "ORIG_HEAD", &curr_head, NULL,
+ 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
- delete_ref(NULL, "ORIG_HEAD", NULL, 0);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, "ORIG_HEAD", NULL, 0);
}
/*
@@ -1114,9 +1122,10 @@ static void am_next(struct am_state *state)
unlink(am_path(state, "author-script"));
unlink(am_path(state, "final-commit"));
- oidclr(&state->orig_commit);
+ oidclr(&state->orig_commit, the_repository->hash_algo);
unlink(am_path(state, "original-commit"));
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "REBASE_HEAD", NULL, REF_NO_DEREF);
if (!repo_get_oid(the_repository, "HEAD", &head))
write_state_text(state, "abort-safety", oid_to_hex(&head));
@@ -1147,19 +1156,23 @@ static const char *msgnum(const struct am_state *state)
static void NORETURN die_user_resolve(const struct am_state *state)
{
if (state->resolvemsg) {
- printf_ln("%s", state->resolvemsg);
+ advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", state->resolvemsg);
} else {
const char *cmdline = state->interactive ? "git am -i" : "git am";
+ struct strbuf sb = STRBUF_INIT;
- printf_ln(_("When you have resolved this problem, run \"%s --continue\"."), cmdline);
- printf_ln(_("If you prefer to skip this patch, run \"%s --skip\" instead."), cmdline);
+ strbuf_addf(&sb, _("When you have resolved this problem, run \"%s --continue\".\n"), cmdline);
+ strbuf_addf(&sb, _("If you prefer to skip this patch, run \"%s --skip\" instead.\n"), cmdline);
if (advice_enabled(ADVICE_AM_WORK_DIR) &&
is_empty_or_missing_file(am_path(state, "patch")) &&
!repo_index_has_changes(the_repository, NULL, NULL))
- printf_ln(_("To record the empty patch as an empty commit, run \"%s --allow-empty\"."), cmdline);
+ strbuf_addf(&sb, _("To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"), cmdline);
- printf_ln(_("To restore the original branch and stop patching, run \"%s --abort\"."), cmdline);
+ strbuf_addf(&sb, _("To restore the original branch and stop patching, run \"%s --abort\"."), cmdline);
+
+ advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", sb.buf);
+ strbuf_release(&sb);
}
exit(128);
@@ -1283,7 +1296,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, NULL);
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
@@ -1459,8 +1472,9 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
oidcpy(&state->orig_commit, &commit_oid);
write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
- update_ref("am", "REBASE_HEAD", &commit_oid,
- NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), "am",
+ "REBASE_HEAD", &commit_oid,
+ NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
return 0;
}
@@ -1529,8 +1543,9 @@ static int run_apply(const struct am_state *state, const char *index_file)
if (index_file) {
/* Reload index as apply_all_patches() will have modified it. */
- discard_index(&the_index);
- read_index_from(&the_index, index_file, get_git_dir());
+ discard_index(the_repository->index);
+ read_index_from(the_repository->index, index_file,
+ repo_get_git_dir(the_repository));
}
return 0;
@@ -1560,8 +1575,8 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f
*/
static int fall_back_threeway(const struct am_state *state, const char *index_path)
{
- struct object_id orig_tree, their_tree, our_tree;
- const struct object_id *bases[1] = { &orig_tree };
+ struct object_id their_tree, our_tree;
+ struct object_id bases[1] = { 0 };
struct merge_options o;
struct commit *result;
char *their_tree_name;
@@ -1572,10 +1587,10 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
if (build_fake_ancestor(state, index_path))
return error("could not build fake ancestor");
- discard_index(&the_index);
- read_index_from(&the_index, index_path, get_git_dir());
+ discard_index(the_repository->index);
+ read_index_from(the_repository->index, index_path, repo_get_git_dir(the_repository));
- if (write_index_as_tree(&orig_tree, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(&bases[0], the_repository->index, index_path, 0, NULL))
return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
say(state, stdout, _("Using index info to reconstruct a base tree..."));
@@ -1601,12 +1616,12 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
return error(_("Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."));
- if (write_index_as_tree(&their_tree, &the_index, index_path, 0, NULL))
+ if (write_index_as_tree(&their_tree, the_repository->index, index_path, 0, NULL))
return error("could not write tree");
say(state, stdout, _("Falling back to patching base and 3-way merge..."));
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
/*
@@ -1617,7 +1632,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
* changes.
*/
- init_merge_options(&o, the_repository);
+ init_ui_merge_options(&o, the_repository);
o.branch1 = "HEAD";
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
@@ -1650,10 +1665,12 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (!state->no_verify && run_hooks("pre-applypatch"))
+ if (!state->no_verify && run_hooks(the_repository, "pre-applypatch"))
exit(1);
- if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(&tree, the_repository->index,
+ repo_get_index_file(the_repository),
+ 0, NULL))
die(_("git write-tree failed to write a tree"));
if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
@@ -1690,8 +1707,9 @@ static void do_commit(const struct am_state *state)
strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
state->msg);
- update_ref(sb.buf, "HEAD", &commit, old_oid, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), sb.buf, "HEAD",
+ &commit, old_oid, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (state->rebasing) {
FILE *fp = xfopen(am_path(state, "rewritten"), "a");
@@ -1702,8 +1720,9 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
- run_hooks("post-applypatch");
+ run_hooks(the_repository, "post-applypatch");
+ free_commit_list(parents);
strbuf_release(&sb);
}
@@ -1941,7 +1960,7 @@ static void am_resolve(struct am_state *state, int allow_empty)
}
}
- if (unmerged_index(&the_index)) {
+ if (unmerged_index(the_repository->index)) {
printf_ln(_("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."));
@@ -1980,26 +1999,26 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.update = 1;
opts.merge = 1;
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
opts.fn = twoway_merge;
- init_tree_desc(&t[0], head->buffer, head->size);
- init_tree_desc(&t[1], remote->buffer, remote->size);
+ init_tree_desc(&t[0], &head->object.oid, head->buffer, head->size);
+ init_tree_desc(&t[1], &remote->object.oid, remote->buffer, remote->size);
if (unpack_trees(2, t, &opts)) {
rollback_lock_file(&lock_file);
return -1;
}
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
@@ -2022,18 +2041,18 @@ static int merge_tree(struct tree *tree)
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.merge = 1;
opts.fn = oneway_merge;
- init_tree_desc(&t[0], tree->buffer, tree->size);
+ init_tree_desc(&t[0], &tree->object.oid, tree->buffer, tree->size);
if (unpack_trees(1, t, &opts)) {
rollback_lock_file(&lock_file);
return -1;
}
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
@@ -2061,7 +2080,9 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_index_as_tree(&index, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(&index, the_repository->index,
+ repo_get_index_file(the_repository),
+ 0, NULL))
return -1;
index_tree = parse_tree_indirect(&index);
@@ -2137,11 +2158,11 @@ static int safe_to_abort(const struct am_state *state)
if (get_oid_hex(sb.buf, &abort_safety))
die(_("could not parse %s"), am_path(state, "abort-safety"));
} else
- oidclr(&abort_safety);
+ oidclr(&abort_safety, the_repository->hash_algo);
strbuf_release(&sb);
if (repo_get_oid(the_repository, "HEAD", &head))
- oidclr(&head);
+ oidclr(&head, the_repository->hash_algo);
if (oideq(&head, &abort_safety))
return 1;
@@ -2168,7 +2189,8 @@ static void am_abort(struct am_state *state)
am_rerere_clear();
- curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
+ curr_branch = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &curr_head, NULL);
has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
oidcpy(&curr_head, the_hash_algo->empty_tree);
@@ -2181,17 +2203,19 @@ static void am_abort(struct am_state *state)
die(_("failed to clean index"));
if (has_orig_head)
- update_ref("am --abort", "HEAD", &orig_head,
- has_curr_head ? &curr_head : NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "am --abort", "HEAD", &orig_head,
+ has_curr_head ? &curr_head : NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
- delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ curr_branch, NULL, REF_NO_DEREF);
free(curr_branch);
am_destroy(state);
}
-static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
+static int show_patch(struct am_state *state, enum resume_type resume_mode)
{
struct strbuf sb = STRBUF_INIT;
const char *patch_path;
@@ -2206,11 +2230,11 @@ static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
return run_command(&cmd);
}
- switch (sub_mode) {
- case SHOW_PATCH_RAW:
+ switch (resume_mode) {
+ case RESUME_SHOW_PATCH_RAW:
patch_path = am_path(state, msgnum(state));
break;
- case SHOW_PATCH_DIFF:
+ case RESUME_SHOW_PATCH_DIFF:
patch_path = am_path(state, "patch");
break;
default:
@@ -2257,67 +2281,38 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
return 0;
}
-enum resume_type {
- RESUME_FALSE = 0,
- RESUME_APPLY,
- RESUME_RESOLVED,
- RESUME_SKIP,
- RESUME_ABORT,
- RESUME_QUIT,
- RESUME_SHOW_PATCH,
- RESUME_ALLOW_EMPTY,
-};
-
-struct resume_mode {
- enum resume_type mode;
- enum show_patch_type sub_mode;
-};
-
static int parse_opt_show_current_patch(const struct option *opt, const char *arg, int unset)
{
int *opt_value = opt->value;
- struct resume_mode *resume = container_of(opt_value, struct resume_mode, mode);
+ BUG_ON_OPT_NEG(unset);
+
+ if (!arg)
+ *opt_value = opt->defval;
+ else if (!strcmp(arg, "raw"))
+ *opt_value = RESUME_SHOW_PATCH_RAW;
+ else if (!strcmp(arg, "diff"))
+ *opt_value = RESUME_SHOW_PATCH_DIFF;
/*
* Please update $__git_showcurrentpatch in git-completion.bash
* when you add new options
*/
- const char *valid_modes[] = {
- [SHOW_PATCH_DIFF] = "diff",
- [SHOW_PATCH_RAW] = "raw"
- };
- int new_value = SHOW_PATCH_RAW;
-
- BUG_ON_OPT_NEG(unset);
-
- if (arg) {
- for (new_value = 0; new_value < ARRAY_SIZE(valid_modes); new_value++) {
- if (!strcmp(arg, valid_modes[new_value]))
- break;
- }
- if (new_value >= ARRAY_SIZE(valid_modes))
- return error(_("invalid value for '%s': '%s'"),
- "--show-current-patch", arg);
- }
-
- if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
- return error(_("options '%s=%s' and '%s=%s' "
- "cannot be used together"),
- "--show-current-patch", arg,
- "--show-current-patch", valid_modes[resume->sub_mode]);
-
- resume->mode = RESUME_SHOW_PATCH;
- resume->sub_mode = new_value;
+ else
+ return error(_("invalid value for '%s': '%s'"),
+ "--show-current-patch", arg);
return 0;
}
-int cmd_am(int argc, const char **argv, const char *prefix)
+int cmd_am(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct am_state state;
int binary = -1;
int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
- struct resume_mode resume = { .mode = RESUME_FALSE };
+ enum resume_type resume_mode = RESUME_FALSE;
int in_progress;
int ret = 0;
@@ -2388,27 +2383,30 @@ int cmd_am(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG),
OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL,
N_("override error message when patch failure occurs")),
- OPT_CMDMODE(0, "continue", &resume.mode,
+ OPT_CMDMODE(0, "continue", &resume_mode,
N_("continue applying patches after resolving a conflict"),
RESUME_RESOLVED),
- OPT_CMDMODE('r', "resolved", &resume.mode,
+ OPT_CMDMODE('r', "resolved", &resume_mode,
N_("synonyms for --continue"),
RESUME_RESOLVED),
- OPT_CMDMODE(0, "skip", &resume.mode,
+ OPT_CMDMODE(0, "skip", &resume_mode,
N_("skip the current patch"),
RESUME_SKIP),
- OPT_CMDMODE(0, "abort", &resume.mode,
+ OPT_CMDMODE(0, "abort", &resume_mode,
N_("restore the original branch and abort the patching operation"),
RESUME_ABORT),
- OPT_CMDMODE(0, "quit", &resume.mode,
+ OPT_CMDMODE(0, "quit", &resume_mode,
N_("abort the patching operation but keep HEAD where it is"),
RESUME_QUIT),
- { OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
+ { OPTION_CALLBACK, 0, "show-current-patch", &resume_mode,
"(diff|raw)",
N_("show the patch being applied"),
PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
- parse_opt_show_current_patch, RESUME_SHOW_PATCH },
- OPT_CMDMODE(0, "allow-empty", &resume.mode,
+ parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW },
+ OPT_CMDMODE(0, "retry", &resume_mode,
+ N_("try to apply current patch again"),
+ RESUME_APPLY),
+ OPT_CMDMODE(0, "allow-empty", &resume_mode,
N_("record the empty patch as an empty commit"),
RESUME_ALLOW_EMPTY),
OPT_BOOL(0, "committer-date-is-author-date",
@@ -2420,7 +2418,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"),
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- OPT_CALLBACK_F(STOP_ON_EMPTY_COMMIT, "empty", &state.empty_type, "{stop,drop,keep}",
+ OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)",
N_("how to handle empty patches"),
PARSE_OPT_NONEG, am_option_parse_empty),
OPT_HIDDEN_BOOL(0, "rebasing", &state.rebasing,
@@ -2463,12 +2461,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* intend to feed us a patch but wanted to continue
* unattended.
*/
- if (argc || (resume.mode == RESUME_FALSE && !isatty(0)))
+ if (argc || (resume_mode == RESUME_FALSE && !isatty(0)))
die(_("previous rebase directory %s still exists but mbox given."),
state.dir);
- if (resume.mode == RESUME_FALSE)
- resume.mode = RESUME_APPLY;
+ if (resume_mode == RESUME_FALSE)
+ resume_mode = RESUME_APPLY;
if (state.signoff == SIGNOFF_EXPLICIT)
am_append_signoff(&state);
@@ -2482,7 +2480,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* stray directories.
*/
if (file_exists(state.dir) && !state.rebasing) {
- if (resume.mode == RESUME_ABORT || resume.mode == RESUME_QUIT) {
+ if (resume_mode == RESUME_ABORT || resume_mode == RESUME_QUIT) {
am_destroy(&state);
am_state_release(&state);
return 0;
@@ -2493,7 +2491,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
state.dir);
}
- if (resume.mode)
+ if (resume_mode)
die(_("Resolve operation not in progress, we are not resuming."));
for (i = 0; i < argc; i++) {
@@ -2511,7 +2509,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
strvec_clear(&paths);
}
- switch (resume.mode) {
+ switch (resume_mode) {
case RESUME_FALSE:
am_run(&state, 0);
break;
@@ -2520,7 +2518,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
break;
case RESUME_RESOLVED:
case RESUME_ALLOW_EMPTY:
- am_resolve(&state, resume.mode == RESUME_ALLOW_EMPTY ? 1 : 0);
+ am_resolve(&state, resume_mode == RESUME_ALLOW_EMPTY ? 1 : 0);
break;
case RESUME_SKIP:
am_skip(&state);
@@ -2532,8 +2530,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
am_rerere_clear();
am_destroy(&state);
break;
- case RESUME_SHOW_PATCH:
- ret = show_patch(&state, resume.sub_mode);
+ case RESUME_SHOW_PATCH_RAW:
+ case RESUME_SHOW_PATCH_DIFF:
+ ret = show_patch(&state, resume_mode);
break;
default:
BUG("invalid resume value");
diff --git a/builtin/annotate.c b/builtin/annotate.c
index 58ff977a23..7f754f2309 100644
--- a/builtin/annotate.c
+++ b/builtin/annotate.c
@@ -3,20 +3,34 @@
*
* Copyright (C) 2006 Ryan Anderson
*/
+
#include "git-compat-util.h"
#include "builtin.h"
#include "strvec.h"
-int cmd_annotate(int argc, const char **argv, const char *prefix)
+int cmd_annotate(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo)
{
struct strvec args = STRVEC_INIT;
- int i;
+ const char **args_copy;
+ int ret;
strvec_pushl(&args, "annotate", "-c", NULL);
-
- for (i = 1; i < argc; i++) {
+ for (int i = 1; i < argc; i++)
strvec_push(&args, argv[i]);
- }
- return cmd_blame(args.nr, args.v, prefix);
+ /*
+ * `cmd_blame()` ends up modifying the array, which causes memory leaks
+ * if we didn't copy the array here.
+ */
+ CALLOC_ARRAY(args_copy, args.nr + 1);
+ COPY_ARRAY(args_copy, args.v, args.nr);
+
+ ret = cmd_blame(args.nr, args_copy, prefix, repo);
+
+ strvec_clear(&args);
+ free(args_copy);
+ return ret;
}
diff --git a/builtin/apply.c b/builtin/apply.c
index c18b7ea5d3..84f1863d3a 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,7 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
-#include "parse-options.h"
-#include "repository.h"
+#include "hash.h"
#include "apply.h"
static const char * const apply_usage[] = {
@@ -9,7 +9,10 @@ static const char * const apply_usage[] = {
NULL
};
-int cmd_apply(int argc, const char **argv, const char *prefix)
+int cmd_apply(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int force_apply = 0;
int options = 0;
@@ -19,6 +22,15 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
if (init_apply_state(&state, the_repository, prefix))
exit(128);
+ /*
+ * We could to redo the "apply.c" machinery to make this
+ * arbitrary fallback unnecessary, but it is dubious that it
+ * is worth the effort.
+ * cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/
+ */
+ if (!the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
argc = apply_parse_options(argc, argv,
&state, &force_apply, &options,
apply_usage);
diff --git a/builtin/archive.c b/builtin/archive.c
index 90761fdfee..13ea7308c8 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -8,8 +8,6 @@
#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)
{
@@ -32,9 +30,7 @@ static int run_remote_archiver(int argc, const char **argv,
struct packet_reader reader;
_remote = remote_get(remote);
- if (!_remote->url[0])
- die(_("git archive: Remote with no URL"));
- transport = transport_get(_remote, _remote->url[0]);
+ transport = transport_get(_remote, _remote->url.v[0]);
transport_connect(transport, "git-upload-archive", exec, fd);
/*
@@ -79,7 +75,10 @@ static int run_remote_archiver(int argc, const char **argv,
PARSE_OPT_KEEP_UNKNOWN_OPT | \
PARSE_OPT_NO_INTERNAL_HELP )
-int cmd_archive(int argc, const char **argv, const char *prefix)
+int cmd_archive(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo)
{
const char *exec = "git-upload-archive";
char *output = NULL;
@@ -93,6 +92,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
N_("path to the remote git-upload-archive command")),
OPT_END()
};
+ int ret;
argc = parse_options(argc, argv, prefix, local_opts, NULL,
PARSE_OPT_KEEP_ALL);
@@ -102,11 +102,16 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
if (output)
create_output_file(output);
- if (remote)
- return run_remote_archiver(argc, argv, remote, exec, output);
+ if (remote) {
+ ret = run_remote_archiver(argc, argv, remote, exec, output);
+ goto out;
+ }
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- UNLEAK(output);
- return write_archive(argc, argv, prefix, the_repository, output, 0);
+ ret = write_archive(argc, argv, prefix, repo, output, 0);
+
+out:
+ free(output);
+ return ret;
}
diff --git a/builtin/bisect.c b/builtin/bisect.c
index 65478ef40f..21d17a6c1a 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "copy.h"
#include "environment.h"
@@ -7,7 +8,6 @@
#include "parse-options.h"
#include "bisect.h"
#include "refs.h"
-#include "dir.h"
#include "strvec.h"
#include "run-command.h"
#include "oid-array.h"
@@ -17,7 +17,6 @@
#include "revision.h"
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
-static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
@@ -26,7 +25,7 @@ static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
#define BUILTIN_GIT_BISECT_START_USAGE \
- N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+ N_("git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]" \
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
" [<pathspec>...]")
#define BUILTIN_GIT_BISECT_STATE_USAGE \
@@ -46,7 +45,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
#define BUILTIN_GIT_BISECT_LOG_USAGE \
"git bisect log"
#define BUILTIN_GIT_BISECT_RUN_USAGE \
- N_("git bisect run <cmd>...")
+ N_("git bisect run <cmd> [<arg>...]")
static const char * const git_bisect_usage[] = {
BUILTIN_GIT_BISECT_START_USAGE,
@@ -233,11 +232,10 @@ static int bisect_reset(const char *commit)
struct strbuf branch = STRBUF_INIT;
if (!commit) {
- if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
+ if (!strbuf_read_file(&branch, git_path_bisect_start(), 0))
printf(_("We are not bisecting.\n"));
- return 0;
- }
- strbuf_rtrim(&branch);
+ else
+ strbuf_rtrim(&branch);
} else {
struct object_id oid;
@@ -246,7 +244,7 @@ static int bisect_reset(const char *commit)
strbuf_addstr(&branch, commit);
}
- if (!ref_exists("BISECT_HEAD")) {
+ if (branch.len && !refs_ref_exists(get_main_ref_store(the_repository), "BISECT_HEAD")) {
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
@@ -265,7 +263,8 @@ static int bisect_reset(const char *commit)
return bisect_clean_state();
}
-static void log_commit(FILE *fp, char *fmt, const char *state,
+static void log_commit(FILE *fp,
+ const char *fmt, const char *state,
struct commit *commit)
{
struct pretty_print_context pp = {0};
@@ -305,8 +304,8 @@ static int bisect_write(const char *state, const char *rev,
goto finish;
}
- if (update_ref(NULL, tag.buf, &oid, NULL, 0,
- UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), NULL, tag.buf, &oid, NULL, 0,
+ UPDATE_REFS_MSG_ON_ERR)) {
res = -1;
goto finish;
}
@@ -358,6 +357,7 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
}
static int inc_nr(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cb_data)
{
@@ -419,11 +419,12 @@ static void bisect_status(struct bisect_state *state,
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
char *good_glob = xstrfmt("%s-*", terms->term_good);
- if (ref_exists(bad_ref))
+ if (refs_ref_exists(get_main_ref_store(the_repository), bad_ref))
state->nr_bad = 1;
- for_each_glob_ref_in(inc_nr, good_glob, "refs/bisect/",
- (void *) &state->nr_good);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository), inc_nr,
+ good_glob, "refs/bisect/",
+ (void *) &state->nr_good);
free(good_glob);
free(bad_ref);
@@ -546,7 +547,7 @@ finish:
return res;
}
-static int add_bisect_ref(const char *refname, const struct object_id *oid,
+static int add_bisect_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb)
{
struct add_bisect_ref_data *data = cb;
@@ -577,11 +578,13 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
reset_revision_walk();
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);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ add_bisect_ref, bad, "refs/bisect/", &cb);
cb.object_flags = UNINTERESTING;
- for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ add_bisect_ref, good, "refs/bisect/", &cb);
if (prepare_revision_walk(revs))
- res = error(_("revision walk setup failed\n"));
+ res = error(_("revision walk setup failed"));
free(good);
free(bad);
@@ -639,7 +642,7 @@ static int bisect_successful(struct bisect_terms *terms)
char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
int res;
- read_ref(bad_ref, &oid);
+ refs_read_ref(get_main_ref_store(the_repository), bad_ref, &oid);
commit = lookup_commit_reference_by_name(bad_ref);
repo_format_commit_message(the_repository, commit, "%s", &commit_name,
&pp);
@@ -782,7 +785,8 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
/*
* Verify HEAD
*/
- head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
+ head = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, &head_oid, &flags);
if (!head)
if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("bad HEAD - I need a HEAD"));
@@ -841,8 +845,8 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
res = error(_("invalid ref: '%s'"), start_head.buf);
goto finish;
}
- if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
- UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), NULL, "BISECT_HEAD", &oid, NULL, 0,
+ UPDATE_REFS_MSG_ON_ERR)) {
res = BISECT_FAILED;
goto finish;
}
@@ -921,7 +925,6 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
const char *state;
int i, verify_expected = 1;
struct object_id oid, expected;
- struct strbuf buf = STRBUF_INIT;
struct oid_array revs = OID_ARRAY_INIT;
if (!argc)
@@ -976,10 +979,8 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
oid_array_append(&revs, &commit->object.oid);
}
- if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
- get_oid_hex(buf.buf, &expected) < 0)
+ if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected))
verify_expected = 0; /* Ignore invalid file contents */
- strbuf_release(&buf);
for (i = 0; i < revs.nr; i++) {
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
@@ -988,7 +989,9 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
}
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
unlink_or_warn(git_path_bisect_ancestors_ok());
- unlink_or_warn(git_path_bisect_expected_rev());
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, "BISECT_EXPECTED_REV", NULL,
+ REF_NO_DEREF);
verify_expected = 0;
}
}
@@ -1106,7 +1109,7 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
setup_revisions(2, argv + i - 1, &revs, NULL);
if (prepare_revision_walk(&revs))
- die(_("revision walk setup failed\n"));
+ die(_("revision walk setup failed"));
while ((commit = get_revision(&revs)) != NULL)
strvec_push(&argv_state,
oid_to_hex(&commit->object.oid));
@@ -1161,6 +1164,7 @@ static int bisect_visualize(struct bisect_terms *terms, int argc,
}
static int get_first_good(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
@@ -1185,13 +1189,15 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
struct object_id good_rev;
struct object_id current_rev;
char *good_glob = xstrfmt("%s-*", terms->term_good);
- int no_checkout = ref_exists("BISECT_HEAD");
+ int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
+ "BISECT_HEAD");
- for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/",
- &good_rev);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ get_first_good, good_glob, "refs/bisect/",
+ &good_rev);
free(good_glob);
- if (read_ref(no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))
+ if (refs_read_ref(get_main_ref_store(the_repository), no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))
return -1;
res = bisect_checkout(&good_rev, no_checkout);
@@ -1406,7 +1412,10 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
return res;
}
-int cmd_bisect(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int res = 0;
parse_opt_subcommand_fn *fn = NULL;
diff --git a/builtin/blame.c b/builtin/blame.c
index 9c987d6567..6a7bb3b072 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -4,15 +4,14 @@
* Copyright (c) 2006, 2014 by its authors
* See COPYING for licensing conditions
*/
-
-#include "git-compat-util.h"
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.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 "revision.h"
@@ -25,7 +24,6 @@
#include "userdiff.h"
#include "line-range.h"
#include "line-log.h"
-#include "dir.h"
#include "progress.h"
#include "object-name.h"
#include "object-store-ll.h"
@@ -68,7 +66,7 @@ static int no_whole_file_rename;
static int show_progress;
static char repeated_meta_color[COLOR_MAXLEN];
static int coloring_mode;
-static struct string_list ignore_revs_file_list = STRING_LIST_INIT_NODUP;
+static struct string_list ignore_revs_file_list = STRING_LIST_INIT_DUP;
static int mark_unblamable_lines;
static int mark_ignored_lines;
@@ -135,7 +133,7 @@ static void get_ac_line(const char *inbuf, const char *what,
{
struct ident_split ident;
size_t len, maillen, namelen;
- char *tmp, *endp;
+ const char *tmp, *endp;
const char *namebuf, *mailbuf;
tmp = strstr(inbuf, what);
@@ -317,7 +315,7 @@ static const char *format_time(timestamp_t time, const char *tz_str,
size_t time_width;
int tz;
tz = atoi(tz_str);
- time_str = show_date(time, tz, &blame_date_mode);
+ time_str = show_date(time, tz, blame_date_mode);
strbuf_addstr(&time_buf, time_str);
/*
* Add space paddings to time_buf to display a fixed width
@@ -688,7 +686,7 @@ static unsigned parse_score(const char *arg)
return score;
}
-static const char *add_prefix(const char *prefix, const char *path)
+static char *add_prefix(const char *prefix, const char *path)
{
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
}
@@ -719,13 +717,14 @@ static int git_blame_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "blame.ignorerevsfile")) {
- const char *str;
+ char *str;
int ret;
ret = git_config_pathname(&str, var, value);
if (ret)
return ret;
string_list_insert(&ignore_revs_file_list, str);
+ free(str);
return 0;
}
if (!strcmp(var, "blame.markunblamablelines")) {
@@ -748,6 +747,8 @@ static int git_blame_config(const char *var, const char *value,
}
if (!strcmp(var, "blame.coloring")) {
+ if (!value)
+ return config_error_nonbool(var);
if (!strcmp(value, "repeatedLines")) {
coloring_mode |= OUTPUT_COLOR_LINE;
} else if (!strcmp(value, "highlightRecent")) {
@@ -851,6 +852,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,
oidset_clear(&sb->ignore_list);
else
oidset_parse_file_carefully(&sb->ignore_list, i->string,
+ the_repository->hash_algo,
peel_to_commit_oid, sb);
}
for_each_string_list_item(i, ignore_rev_list) {
@@ -861,10 +863,13 @@ static void build_ignorelist(struct blame_scoreboard *sb,
}
}
-int cmd_blame(int argc, const char **argv, const char *prefix)
+int cmd_blame(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info revs;
- const char *path;
+ char *path = NULL;
struct blame_scoreboard sb;
struct blame_origin *o;
struct blame_entry *ent = NULL;
@@ -914,7 +919,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
struct range_set ranges;
unsigned int range_i;
long anchor;
- const int hexsz = the_hash_algo->hexsz;
long num_lines = 0;
const char *str_usage = cmd_is_annotate ? annotate_usage : blame_usage;
const char **opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
@@ -972,11 +976,11 @@ parse_done:
} else if (show_progress < 0)
show_progress = isatty(2);
- if (0 < abbrev && abbrev < hexsz)
+ if (0 < abbrev && abbrev < (int)the_hash_algo->hexsz)
/* one more abbrev length is needed for the boundary commit */
abbrev++;
else if (!abbrev)
- abbrev = hexsz;
+ abbrev = the_hash_algo->hexsz;
if (revs_file && read_ancestry(revs_file))
die_errno("reading graft file '%s' failed", revs_file);
@@ -1028,7 +1032,7 @@ parse_done:
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
break;
case DATE_STRFTIME:
- blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
+ blame_date_width = strlen(show_date(0, 0, blame_date_mode)) + 1; /* add the null */
break;
}
blame_date_width -= 1; /* strip the null */
@@ -1079,7 +1083,7 @@ parse_done:
path = add_prefix(prefix, argv[1]);
argv[1] = argv[2];
} else { /* (2a) */
- if (argc == 2 && is_a_rev(argv[1]) && !get_git_work_tree())
+ if (argc == 2 && is_a_rev(argv[1]) && !repo_get_work_tree(the_repository))
die("missing <path> to blame");
path = add_prefix(prefix, argv[argc - 1]);
}
@@ -1092,8 +1096,8 @@ parse_done:
struct commit *head_commit;
struct object_id head_oid;
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- &head_oid, NULL) ||
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING,
+ &head_oid, NULL) ||
!(head_commit = lookup_commit_reference_gently(revs.repo,
&head_oid, 1)))
die("no such ref: HEAD");
@@ -1212,12 +1216,6 @@ parse_done:
output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
output(&sb, output_option);
- free((void *)sb.final_buf);
- for (ent = sb.ent; ent; ) {
- struct blame_entry *e = ent->next;
- free(ent);
- ent = e;
- }
if (show_stats) {
printf("num read blob: %d\n", sb.num_read_blob);
@@ -1226,6 +1224,13 @@ parse_done:
}
cleanup:
+ for (ent = sb.ent; ent; ) {
+ struct blame_entry *e = ent->next;
+ free(ent);
+ ent = e;
+ }
+
+ free(path);
cleanup_scoreboard(&sb);
release_revisions(&revs);
return 0;
diff --git a/builtin/branch.c b/builtin/branch.c
index 08da650516..05ba4cd7a6 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
* Based on git-branch.sh by Junio C Hamano.
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "color.h"
@@ -17,16 +17,14 @@
#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"
#include "utf8.h"
-#include "wt-status.h"
#include "ref-filter.h"
#include "worktree.h"
#include "help.h"
+#include "advice.h"
#include "commit-reach.h"
static const char * const builtin_branch_usage[] = {
@@ -45,7 +43,6 @@ 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] = {
@@ -151,8 +148,8 @@ static int branch_merged(int kind, const char *name,
if (upstream &&
(reference_name = reference_name_to_free =
- resolve_refdup(upstream, RESOLVE_REF_READING,
- &oid, NULL)) != NULL)
+ refs_resolve_refdup(get_main_ref_store(the_repository), upstream, RESOLVE_REF_READING,
+ &oid, NULL)) != NULL)
reference_rev = lookup_commit_reference(the_repository,
&oid);
}
@@ -161,6 +158,8 @@ static int branch_merged(int kind, const char *name,
merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
reference_rev) : 0;
+ if (merged < 0)
+ exit(128);
/*
* After the safety valve is fully redefined to "check with
@@ -169,15 +168,19 @@ static int branch_merged(int kind, const char *name,
* any of the following code, but during the transition period,
* a gentle reminder is in order.
*/
- if ((head_rev != reference_rev) &&
- (head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
- if (merged)
+ if (head_rev != reference_rev) {
+ int expect = head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0;
+ if (expect < 0)
+ exit(128);
+ if (expect == merged)
+ ; /* okay */
+ else if (merged)
warning(_("deleting branch '%s' that has been merged to\n"
- " '%s', but not yet merged to HEAD."),
+ " '%s', but not yet merged to HEAD"),
name, reference_name);
else
warning(_("not deleting branch '%s' that is not yet merged to\n"
- " '%s', even though it is merged to HEAD."),
+ " '%s', even though it is merged to HEAD"),
name, reference_name);
}
free(reference_name_to_free);
@@ -190,13 +193,14 @@ static int check_branch_commit(const char *branchname, const char *refname,
{
struct commit *rev = lookup_commit_reference(the_repository, oid);
if (!force && !rev) {
- error(_("Couldn't look up commit object for '%s'"), refname);
+ error(_("couldn't look up commit object for '%s'"), refname);
return -1;
}
if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
- error(_("The branch '%s' is not fully merged.\n"
- "If you are sure you want to delete it, "
- "run 'git branch -D %s'."), branchname, branchname);
+ error(_("the branch '%s' is not fully merged"), branchname);
+ advise_if_enabled(ADVICE_FORCE_DELETE_BRANCH,
+ _("If you are sure you want to delete it, "
+ "run 'git branch -D %s'"), branchname);
return -1;
}
return 0;
@@ -206,8 +210,8 @@ static void delete_branch_config(const char *branchname)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "branch.%s", branchname);
- if (git_config_rename_section(buf.buf, NULL) < 0)
- warning(_("Update of config-file failed"));
+ if (repo_config_rename_section(the_repository, buf.buf, NULL) < 0)
+ warning(_("update of config-file failed"));
strbuf_release(&buf);
}
@@ -260,29 +264,32 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
if (kinds == FILTER_REFS_BRANCHES) {
const char *path;
if ((path = branch_checked_out(name))) {
- error(_("Cannot delete branch '%s' "
- "checked out at '%s'"),
+ error(_("cannot delete branch '%s' "
+ "used by worktree at '%s'"),
bname.buf, path);
ret = 1;
continue;
}
}
- target = resolve_refdup(name,
- RESOLVE_REF_READING
- | RESOLVE_REF_NO_RECURSE
- | RESOLVE_REF_ALLOW_BAD_NAME,
- &oid, &flags);
+ target = refs_resolve_refdup(get_main_ref_store(the_repository),
+ name,
+ RESOLVE_REF_READING
+ | RESOLVE_REF_NO_RECURSE
+ | RESOLVE_REF_ALLOW_BAD_NAME,
+ &oid, &flags);
if (!target) {
if (remote_branch) {
- error(_("remote-tracking branch '%s' not found."), bname.buf);
+ error(_("remote-tracking branch '%s' not found"), bname.buf);
} else {
char *virtual_name = mkpathdup(fmt_remotes, bname.buf);
- char *virtual_target = resolve_refdup(virtual_name,
- RESOLVE_REF_READING
- | RESOLVE_REF_NO_RECURSE
- | RESOLVE_REF_ALLOW_BAD_NAME,
- &oid, &flags);
+ char *virtual_target = refs_resolve_refdup(get_main_ref_store(the_repository),
+ virtual_name,
+ RESOLVE_REF_READING
+ | RESOLVE_REF_NO_RECURSE
+ | RESOLVE_REF_ALLOW_BAD_NAME,
+ &oid,
+ &flags);
FREE_AND_NULL(virtual_name);
if (virtual_target)
@@ -290,7 +297,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
"Did you forget --remote?"),
bname.buf);
else
- error(_("branch '%s' not found."), bname.buf);
+ error(_("branch '%s' not found"), bname.buf);
FREE_AND_NULL(virtual_target);
}
ret = 1;
@@ -313,13 +320,13 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
free(target);
}
- if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
+ if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF))
ret = 1;
for_each_string_list_item(item, &refs_to_delete) {
char *describe_ref = item->util;
char *name = item->string;
- if (!ref_exists(name)) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), name)) {
char *refname = name + branch_name_pos;
if (!quiet)
printf(remote_branch
@@ -438,8 +445,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
{
int i;
struct ref_array array;
- struct strbuf out = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
int maxwidth = 0;
const char *remote_prefix = "";
char *to_free = NULL;
@@ -469,24 +474,27 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
filter_ahead_behind(the_repository, format, &array);
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++) {
- strbuf_reset(&err);
- strbuf_reset(&out);
- if (format_ref_array_item(array.items[i], format, &out, &err))
- die("%s", err.buf);
- if (column_active(colopts)) {
- assert(!filter->verbose && "--column and --verbose are incompatible");
- /* format to a string_list to let print_columns() do its job */
+ if (column_active(colopts)) {
+ struct strbuf out = STRBUF_INIT, err = STRBUF_INIT;
+
+ assert(!filter->verbose && "--column and --verbose are incompatible");
+
+ for (i = 0; i < array.nr; i++) {
+ strbuf_reset(&err);
+ strbuf_reset(&out);
+ if (format_ref_array_item(array.items[i], format, &out, &err))
+ die("%s", err.buf);
+
+ /* format to a string_list to let print_columns() do its job */
string_list_append(output, out.buf);
- } else {
- fwrite(out.buf, 1, out.len, stdout);
- if (out.len || !omit_empty)
- putchar('\n');
}
+
+ strbuf_release(&err);
+ strbuf_release(&out);
+ } else {
+ print_formatted_ref_array(&array, format);
}
- strbuf_release(&err);
- strbuf_release(&out);
ref_array_clear(&array);
free(to_free);
}
@@ -494,7 +502,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
static void print_current_branch_name(void)
{
int flags;
- const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
+ const char *refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
const char *shortname;
if (!refname)
die(_("could not resolve HEAD"));
@@ -518,11 +527,11 @@ static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
continue;
if (is_worktree_being_rebased(wt, target))
- die(_("Branch %s is being rebased at %s"),
+ die(_("branch %s is being rebased at %s"),
target, wt->path);
if (is_worktree_being_bisected(wt, target))
- die(_("Branch %s is being bisected at %s"),
+ die(_("branch %s is being bisected at %s"),
target, wt->path);
}
}
@@ -550,7 +559,7 @@ static int replace_each_worktree_head_symref(struct worktree **worktrees,
continue;
refs = get_worktree_ref_store(worktrees[i]);
- if (refs_create_symref(refs, "HEAD", newref, logmsg))
+ if (refs_update_symref(refs, "HEAD", newref, logmsg))
ret = error(_("HEAD of working tree %s is not updated"),
worktrees[i]->path);
}
@@ -575,10 +584,14 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
* Bad name --- this could be an attempt to rename a
* ref that we used to allow to be created by accident.
*/
- if (ref_exists(oldref.buf))
+ if (refs_ref_exists(get_main_ref_store(the_repository), oldref.buf))
recovery = 1;
- else
- die(_("Invalid branch name: '%s'"), oldname);
+ else {
+ int code = die_message(_("invalid branch name: '%s'"), oldname);
+ advise_if_enabled(ADVICE_REF_SYNTAX,
+ _("See `man git check-ref-format`"));
+ exit(code);
+ }
}
for (int i = 0; worktrees[i]; i++) {
@@ -592,11 +605,11 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
}
}
- if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
+ if ((copy || !(oldref_usage & IS_HEAD)) && !refs_ref_exists(get_main_ref_store(the_repository), oldref.buf)) {
if (oldref_usage & IS_HEAD)
- die(_("No commit on branch '%s' yet."), oldname);
+ die(_("no commit on branch '%s' yet"), oldname);
else
- die(_("No branch named '%s'."), oldname);
+ die(_("no branch named '%s'"), oldname);
}
/*
@@ -623,33 +636,34 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
oldref.buf, newref.buf);
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))
- die(_("Branch copy failed"));
+ refs_rename_ref(get_main_ref_store(the_repository), oldref.buf, newref.buf, logmsg.buf))
+ die(_("branch rename failed"));
+ if (copy && refs_copy_existing_ref(get_main_ref_store(the_repository), oldref.buf, newref.buf, logmsg.buf))
+ die(_("branch copy failed"));
if (recovery) {
if (copy)
- warning(_("Created a copy of a misnamed branch '%s'"),
+ warning(_("created a copy of a misnamed branch '%s'"),
interpreted_oldname);
else
- warning(_("Renamed a misnamed branch '%s' away"),
+ warning(_("renamed a misnamed branch '%s' away"),
interpreted_oldname);
}
if (!copy && (oldref_usage & IS_HEAD) &&
replace_each_worktree_head_symref(worktrees, oldref.buf, newref.buf,
logmsg.buf))
- die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
+ die(_("branch renamed to %s, but HEAD is not updated"), newname);
strbuf_release(&logmsg);
strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
strbuf_addf(&newsection, "branch.%s", interpreted_newname);
- if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
- die(_("Branch is renamed, but update of config-file failed"));
- if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
- die(_("Branch is copied, but update of config-file failed"));
+ if (!copy && repo_config_rename_section(the_repository, oldsection.buf, newsection.buf) < 0)
+ die(_("branch is renamed, but update of config-file failed"));
+ if (copy && strcmp(interpreted_oldname, interpreted_newname) &&
+ repo_config_copy_section(the_repository, oldsection.buf, newsection.buf) < 0)
+ die(_("branch is copied, but update of config-file failed"));
strbuf_release(&oldref);
strbuf_release(&newref);
strbuf_release(&oldsection);
@@ -668,18 +682,18 @@ 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, comment_line_char,
+ strbuf_commented_addf(&buf, comment_line_str,
_("Please edit the description for the branch\n"
" %s\n"
- "Lines starting with '%c' will be stripped.\n"),
- branch_name, comment_line_char);
+ "Lines starting with '%s' will be stripped.\n"),
+ branch_name, comment_line_str);
write_file_buf(edit_description(), buf.buf, buf.len);
strbuf_reset(&buf);
if (launch_editor(edit_description(), &buf, NULL)) {
strbuf_release(&buf);
return -1;
}
- strbuf_stripspace(&buf, comment_line_char);
+ strbuf_stripspace(&buf, comment_line_str);
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
@@ -690,7 +704,10 @@ static int edit_branch_description(const char *branch_name)
return 0;
}
-int cmd_branch(int argc, const char **argv, const char *prefix)
+int cmd_branch(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
/* possible actions */
int delete = 0, rename = 0, copy = 0, list = 0,
@@ -705,6 +722,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
static struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
+ int ret;
struct option options[] = {
OPT_GROUP(N_("Generic options")),
@@ -737,7 +755,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
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,
+ OPT_BOOL(0, "omit-empty", &format.array_opts.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),
@@ -767,13 +785,20 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_branch_usage, options);
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_branch_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
track = git_branch_track;
- head = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ 0, &head_oid, NULL);
if (!head)
- die(_("Failed to resolve HEAD as a valid ref."));
+ die(_("failed to resolve HEAD as a valid ref"));
if (!strcmp(head, "HEAD"))
filter.detached = 1;
else if (!skip_prefix(head, "refs/heads/", &head))
@@ -827,15 +852,15 @@ 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"));
- return delete_branches(argc, argv, delete > 1, filter.kind, quiet);
+ ret = delete_branches(argc, argv, delete > 1, filter.kind, quiet);
+ goto out;
} else if (show_current) {
print_current_branch_name();
- return 0;
+ ret = 0;
+ goto out;
} else if (list) {
/* git branch --list also shows HEAD when it is detached */
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
@@ -857,16 +882,18 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
string_list_clear(&output, 0);
ref_sorting_release(sorting);
ref_filter_clear(&filter);
- return 0;
+ ref_format_clear(&format);
+
+ ret = 0;
+ goto out;
} else if (edit_description) {
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
- int ret = 1; /* assume failure */
if (!argc) {
if (filter.detached)
- die(_("Cannot give description to detached HEAD"));
+ die(_("cannot give description to detached HEAD"));
branch_name = head;
} else if (argc == 1) {
strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
@@ -876,24 +903,28 @@ 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))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), branch_ref.buf)) {
error((!argc || branch_checked_out(branch_ref.buf))
- ? _("No commit on branch '%s' yet.")
- : _("No branch named '%s'."),
+ ? _("no commit on branch '%s' yet")
+ : _("no branch named '%s'"),
branch_name);
- else if (!edit_branch_description(branch_name))
+ ret = 1;
+ } else if (!edit_branch_description(branch_name)) {
ret = 0; /* happy */
+ } else {
+ ret = 1;
+ }
strbuf_release(&branch_ref);
strbuf_release(&buf);
- return ret;
+ goto out;
} else if (copy || rename) {
if (!argc)
die(_("branch name required"));
else if ((argc == 1) && filter.detached)
- die(copy? _("cannot copy the current branch while not on any.")
- : _("cannot rename the current branch while not on any."));
+ die(copy? _("cannot copy the current branch while not on any")
+ : _("cannot rename the current branch while not on any"));
else if (argc == 1)
copy_or_rename_branch(head, argv[0], copy, copy + rename > 1);
else if (argc == 2)
@@ -916,14 +947,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
die(_("could not set upstream of HEAD to %s when "
- "it does not point to any branch."),
+ "it does not point to any branch"),
new_upstream);
die(_("no such branch '%s'"), argv[0]);
}
- if (!ref_exists(branch->refname)) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname)) {
if (!argc || branch_checked_out(branch->refname))
- die(_("No commit on branch '%s' yet."), branch->name);
+ die(_("no commit on branch '%s' yet"), branch->name);
die(_("branch '%s' does not exist"), branch->name);
}
@@ -946,12 +977,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
die(_("could not unset upstream of HEAD when "
- "it does not point to any branch."));
+ "it does not point to any branch"));
die(_("no such branch '%s'"), argv[0]);
}
if (!branch_has_merge_config(branch))
- die(_("Branch '%s' has no upstream information"), branch->name);
+ die(_("branch '%s' has no upstream information"), branch->name);
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", branch->name);
@@ -965,22 +996,27 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
const char *start_name = argc == 2 ? argv[1] : head;
if (filter.kind != FILTER_REFS_BRANCHES)
- die(_("The -a, and -r, options to 'git branch' do not take a branch name.\n"
+ die(_("the -a, and -r, options to 'git branch' do not take a branch name.\n"
"Did you mean to use: -a|-r --list <pattern>?"));
if (track == BRANCH_TRACK_OVERRIDE)
- die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
+ die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead"));
if (recurse_submodules) {
create_branches_recursively(the_repository, branch_name,
start_name, NULL, force,
reflog, quiet, track, 0);
- return 0;
+ ret = 0;
+ goto out;
}
create_branch(the_repository, branch_name, start_name, force, 0,
reflog, quiet, track, 0);
} else
usage_with_options(builtin_branch_usage, options);
- return 0;
+ ret = 0;
+
+out:
+ string_list_clear(&sorting_options, 0);
+ return ret;
}
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index d2ae5c305d..7c2df035c9 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "editor.h"
@@ -58,13 +59,14 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
for (p = hook_name_list; *p; p++) {
const char *hook = *p;
- if (hook_exists(hook))
+ if (hook_exists(the_repository, hook))
strbuf_addf(hook_info, "%s\n", hook);
}
}
static const char * const bugreport_usage[] = {
- N_("git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+ N_("git bugreport [(-o | --output-directory) <path>]\n"
+ " [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"),
NULL
};
@@ -97,7 +99,10 @@ static void get_header(struct strbuf *buf, const char *title)
strbuf_addf(buf, "\n\n[%s]\n", title);
}
-int cmd_bugreport(int argc, const char **argv, const char *prefix)
+int cmd_bugreport(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct strbuf buffer = STRBUF_INIT;
struct strbuf report_path = STRBUF_INIT;
@@ -106,7 +111,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
struct tm tm;
enum diagnose_mode diagnose = DIAGNOSE_NONE;
char *option_output = NULL;
- char *option_suffix = "%Y-%m-%d-%H%M";
+ const char *option_suffix = "%Y-%m-%d-%H%M";
const char *user_relative_path = NULL;
char *prefixed_filename;
size_t output_path_len;
@@ -126,6 +131,11 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, bugreport_options,
bugreport_usage, 0);
+ if (argc) {
+ error(_("unknown argument `%s'"), argv[0]);
+ usage(bugreport_usage[0]);
+ }
+
/* Prepare the path to put the result */
prefixed_filename = prefix_filename(prefix,
option_output ? option_output : "");
@@ -133,8 +143,11 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
strbuf_complete(&report_path, '/');
output_path_len = report_path.len;
- strbuf_addstr(&report_path, "git-bugreport-");
- strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+ strbuf_addstr(&report_path, "git-bugreport");
+ if (option_suffix) {
+ strbuf_addch(&report_path, '-');
+ strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+ }
strbuf_addstr(&report_path, ".txt");
switch (safe_create_leading_directories(report_path.buf)) {
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 3ad11dc5d0..127518c2a8 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "gettext.h"
@@ -5,7 +6,6 @@
#include "strvec.h"
#include "parse-options.h"
#include "pkt-line.h"
-#include "repository.h"
#include "bundle.h"
/*
@@ -140,6 +140,11 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
+ if (!startup_info->have_repository) {
+ ret = error(_("need a repository to verify a bundle"));
+ goto cleanup;
+ }
+
if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
ret = 1;
goto cleanup;
@@ -202,12 +207,13 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
+ if (!startup_info->have_repository)
+ die(_("Need a repository to unbundle."));
+
if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
- if (!startup_info->have_repository)
- die(_("Need a repository to unbundle."));
if (progress)
strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
_("Unbundling objects"), NULL);
@@ -215,12 +221,17 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
&extra_index_pack_args, 0) ||
list_bundle_refs(&header, argc, argv);
bundle_header_release(&header);
+
cleanup:
+ strvec_clear(&extra_index_pack_args);
free(bundle_file);
return ret;
}
-int cmd_bundle(int argc, const char **argv, const char *prefix)
+int cmd_bundle(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index ea8ad601ec..bfdfb51c7c 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "convert.h"
@@ -15,7 +15,6 @@
#include "parse-options.h"
#include "userdiff.h"
#include "streaming.h"
-#include "tree-walk.h"
#include "oid-array.h"
#include "packfile.h"
#include "object-file.h"
@@ -78,7 +77,7 @@ static int filter_object(const char *path, unsigned mode,
struct checkout_metadata meta;
init_checkout_metadata(&meta, NULL, NULL, oid);
- if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, &meta)) {
+ if (convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta)) {
free(*buf);
*size = strbuf.len;
*buf = strbuf_detach(&strbuf, NULL);
@@ -103,11 +102,14 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
enum object_type type;
char *buf;
unsigned long size;
- struct object_context obj_context;
+ struct object_context obj_context = {0};
struct object_info oi = OBJECT_INFO_INIT;
struct strbuf sb = STRBUF_INIT;
unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
- unsigned get_oid_flags = GET_OID_RECORD_PATH | GET_OID_ONLY_TO_DIE;
+ unsigned get_oid_flags =
+ GET_OID_RECORD_PATH |
+ GET_OID_ONLY_TO_DIE |
+ GET_OID_HASH_ANY;
const char *path = force_path;
const int opt_cw = (opt == 'c' || opt == 'w');
if (!path && opt_cw)
@@ -161,7 +163,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
goto cleanup;
case 'e':
- return !repo_has_object_file(the_repository, &oid);
+ ret = !repo_has_object_file(the_repository, &oid);
+ goto cleanup;
case 'w':
@@ -188,7 +191,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
const char *ls_args[3] = { NULL };
ls_args[0] = "ls-tree";
ls_args[1] = obj_name;
- ret = cmd_ls_tree(2, ls_args, NULL);
+ ret = cmd_ls_tree(2, ls_args, NULL, the_repository);
goto cleanup;
}
@@ -222,8 +225,13 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
&type,
&size);
const char *target;
+
+ if (!buffer)
+ die(_("unable to read %s"), oid_to_hex(&oid));
+
if (!skip_prefix(buffer, "object ", &target) ||
- get_oid_hex(target, &blob_oid))
+ get_oid_hex_algop(target, &blob_oid,
+ &hash_algos[oid.algo]))
die("%s not a valid tag", oid_to_hex(&oid));
free(buffer);
} else
@@ -261,7 +269,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
ret = 0;
cleanup:
free(buf);
- free(obj_context.path);
+ object_context_release(&obj_context);
return ret;
}
@@ -307,8 +315,8 @@ static int is_atom(const char *atom, const char *s, int slen)
return alen == slen && !memcmp(atom, s, alen);
}
-static void expand_atom(struct strbuf *sb, const char *atom, int len,
- struct expand_data *data)
+static int expand_atom(struct strbuf *sb, const char *atom, int len,
+ struct expand_data *data)
{
if (is_atom("objectname", atom, len)) {
if (!data->mark_query)
@@ -340,7 +348,8 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
strbuf_addstr(sb,
oid_to_hex(&data->delta_base_oid));
} else
- die("unknown format element: %.*s", len, atom);
+ return 0;
+ return 1;
}
static void expand_format(struct strbuf *sb, const char *start,
@@ -351,12 +360,11 @@ static void expand_format(struct strbuf *sb, const char *start,
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);
+ else if ((end = strchr(start + 1, ')')) &&
+ expand_atom(sb, start + 1, end - start - 1, data))
start = end + 1;
- }
+ else
+ strbuf_expand_bad_format(start, "cat-file");
}
}
@@ -417,6 +425,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
contents = repo_read_object_file(the_repository, oid, &type,
&size);
+ if (!contents)
+ die("object %s disappeared", oid_to_hex(oid));
if (use_mailmap) {
size_t s = size;
@@ -424,8 +434,6 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
size = cast_size_t_to_ulong(s);
}
- if (!contents)
- die("object %s disappeared", oid_to_hex(oid));
if (type != data->type)
die("object %s changed type!?", oid_to_hex(oid));
if (data->info.sizep && size != data->size && !use_mailmap)
@@ -482,6 +490,8 @@ static void batch_object_write(const char *obj_name,
buf = repo_read_object_file(the_repository, &data->oid, &data->type,
&data->size);
+ if (!buf)
+ die(_("unable to read %s"), oid_to_hex(&data->oid));
buf = replace_idents_using_mailmap(buf, &s);
data->size = cast_size_t_to_ulong(s);
@@ -511,8 +521,10 @@ static void batch_one_object(const char *obj_name,
struct batch_options *opt,
struct expand_data *data)
{
- struct object_context ctx;
- int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
+ struct object_context ctx = {0};
+ int flags =
+ GET_OID_HASH_ANY |
+ (opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0);
enum get_oid_result result;
result = get_oid_with_context(the_repository, obj_name,
@@ -546,7 +558,8 @@ static void batch_one_object(const char *obj_name,
break;
}
fflush(stdout);
- return;
+
+ goto out;
}
if (ctx.mode == 0) {
@@ -554,10 +567,13 @@ static void batch_one_object(const char *obj_name,
(uintmax_t)ctx.symlink_path.len,
opt->output_delim, ctx.symlink_path.buf, opt->output_delim);
fflush(stdout);
- return;
+ goto out;
}
batch_object_write(obj_name, scratch, opt, data, NULL, 0);
+
+out:
+ object_context_release(&ctx);
}
struct object_cb_data {
@@ -907,7 +923,10 @@ static int batch_option_callback(const struct option *opt,
return 0;
}
-int cmd_cat_file(int argc, const char **argv, const char *prefix)
+int cmd_cat_file(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int opt = 0;
int opt_cw = 0;
@@ -1031,6 +1050,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
if (batch.buffer_output < 0)
batch.buffer_output = batch.all_objects;
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
/* Return early if we're in batch mode? */
if (batch.enabled) {
if (opt_cw)
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index b22ff748c3..7cf275b893 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "attr.h"
@@ -6,7 +6,6 @@
#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"
@@ -71,9 +70,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, full_path, check);
+ git_all_attrs(the_repository->index, full_path, check);
} else {
- git_check_attr(&the_index, full_path, check);
+ git_check_attr(the_repository->index, full_path, check);
}
output_attr(check, file);
@@ -108,7 +107,10 @@ static NORETURN void error_with_usage(const char *msg)
usage_with_options(check_attr_usage, check_attr_options);
}
-int cmd_check_attr(int argc, const char **argv, const char *prefix)
+int cmd_check_attr(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct attr_check *check;
struct object_id initialized_oid;
@@ -122,6 +124,9 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, check_attr_options,
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
if (repo_read_index(the_repository) < 0) {
die("invalid cache");
}
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 906cd96753..7b7831d13a 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "dir.h"
@@ -6,7 +6,6 @@
#include "quote.h"
#include "pathspec.h"
#include "parse-options.h"
-#include "repository.h"
#include "submodule.h"
#include "write-or-die.h"
@@ -36,8 +35,8 @@ static const struct option check_ignore_options[] = {
static void output_pattern(const char *path, struct path_pattern *pattern)
{
- char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
- char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
+ const char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
+ const char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
if (!nul_term_line) {
if (!verbose) {
write_name_quoted(path, stdout, '\n');
@@ -95,21 +94,21 @@ static int check_ignore(struct dir_struct *dir,
PATHSPEC_KEEP_ORDER,
prefix, argv);
- die_path_inside_submodule(&the_index, &pathspec);
+ die_path_inside_submodule(the_repository->index, &pathspec);
/*
* look for pathspecs matching entries in the index, since these
* should not be ignored, in order to be consistent with
* 'git status', 'git add' etc.
*/
- seen = find_pathspecs_matching_against_index(&pathspec, &the_index,
+ seen = find_pathspecs_matching_against_index(&pathspec, the_repository->index,
PS_HEED_SKIP_WORKTREE);
for (i = 0; i < pathspec.nr; i++) {
full_path = pathspec.items[i].match;
pattern = NULL;
if (!seen[i]) {
int dtype = DT_UNKNOWN;
- pattern = last_matching_pattern(dir, &the_index,
+ pattern = last_matching_pattern(dir, the_repository->index,
full_path, &dtype);
if (!verbose && pattern &&
pattern->flags & PATTERN_FLAG_NEGATIVE)
@@ -152,7 +151,10 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
return num_ignored;
}
-int cmd_check_ignore(int argc, const char **argv, const char *prefix)
+int cmd_check_ignore(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int num_ignored;
struct dir_struct dir = DIR_INIT;
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index b8a05b8e07..df00b5ee13 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -9,6 +10,7 @@
#include "write-or-die.h"
static int use_stdin;
+static const char *mailmap_file, *mailmap_blob;
static const char * const check_mailmap_usage[] = {
N_("git check-mailmap [<options>] <contact>..."),
NULL
@@ -16,6 +18,8 @@ NULL
static const struct option check_mailmap_options[] = {
OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")),
+ OPT_FILENAME(0, "mailmap-file", &mailmap_file, N_("read additional mailmap entries from file")),
+ OPT_STRING(0, "mailmap-blob", &mailmap_blob, N_("blob"), N_("read additional mailmap entries from blob")),
OPT_END()
};
@@ -25,13 +29,17 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
size_t namelen, maillen;
struct ident_split ident;
- if (split_ident_line(&ident, contact, strlen(contact)))
- die(_("unable to parse contact: %s"), contact);
-
- name = ident.name_begin;
- namelen = ident.name_end - ident.name_begin;
- mail = ident.mail_begin;
- maillen = ident.mail_end - ident.mail_begin;
+ if (!split_ident_line(&ident, contact, strlen(contact))) {
+ name = ident.name_begin;
+ namelen = ident.name_end - ident.name_begin;
+ mail = ident.mail_begin;
+ maillen = ident.mail_end - ident.mail_begin;
+ } else {
+ name = NULL;
+ namelen = 0;
+ mail = contact;
+ maillen = strlen(contact);
+ }
map_user(mailmap, &mail, &maillen, &name, &namelen);
@@ -40,7 +48,10 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
printf("<%.*s>\n", (int)maillen, mail);
}
-int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
+int cmd_check_mailmap(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i;
struct string_list mailmap = STRING_LIST_INIT_NODUP;
@@ -52,6 +63,10 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
die(_("no contacts specified"));
read_mailmap(&mailmap);
+ if (mailmap_blob)
+ read_mailmap_blob(&mailmap, mailmap_blob);
+ if (mailmap_file)
+ read_mailmap_file(&mailmap, mailmap_file, 0);
for (i = 0; i < argc; ++i)
check_mailmap(&mailmap, argv[i]);
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 5eb6bdc3f6..e86d8ef980 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -1,7 +1,6 @@
/*
* GIT - The information manager from hell
*/
-
#include "builtin.h"
#include "refs.h"
#include "setup.h"
@@ -51,7 +50,10 @@ static int check_ref_format_branch(const char *arg)
return 0;
}
-int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
+int cmd_check_ref_format(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i;
int normalize = 0;
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index 6b62b5375b..ff6cdccc21 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "entry.h"
@@ -113,7 +114,10 @@ static const char * const checkout_worker_usage[] = {
NULL
};
-int cmd_checkout__worker(int argc, const char **argv, const char *prefix)
+int cmd_checkout__worker(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct checkout state = CHECKOUT_INIT;
struct option checkout_worker_options[] = {
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index f62f13f2b5..6dd38eb05d 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -4,14 +4,12 @@
* Copyright (C) 2005 Linus Torvalds
*
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#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"
@@ -24,7 +22,7 @@
static int nul_term_line;
static int checkout_stage; /* default to checkout stage0 */
static int ignore_skip_worktree; /* default to 0 */
-static int to_tempfile;
+static int to_tempfile = -1;
static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
static struct checkout state = CHECKOUT_INIT;
@@ -70,7 +68,7 @@ static void write_tempfile_record(const char *name, const char *prefix)
static int checkout_file(const char *name, const char *prefix)
{
int namelen = strlen(name);
- int pos = index_name_pos(&the_index, name, namelen);
+ int pos = index_name_pos(the_repository->index, name, namelen);
int has_same_name = 0;
int is_file = 0;
int is_skipped = 1;
@@ -80,8 +78,8 @@ static int checkout_file(const char *name, const char *prefix)
if (pos < 0)
pos = -pos - 1;
- while (pos < the_index.cache_nr) {
- struct cache_entry *ce = the_index.cache[pos];
+ while (pos <the_repository->index->cache_nr) {
+ struct cache_entry *ce =the_repository->index->cache[pos];
if (ce_namelen(ce) != namelen ||
memcmp(ce->name, name, namelen))
break;
@@ -141,8 +139,8 @@ static int checkout_all(const char *prefix, int prefix_length)
int i, errs = 0;
struct cache_entry *last_ce = NULL;
- for (i = 0; i < the_index.cache_nr ; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr ; i++) {
+ struct cache_entry *ce = the_repository->index->cache[i];
if (S_ISSPARSEDIR(ce->ce_mode)) {
if (!ce_skip_worktree(ce))
@@ -155,8 +153,8 @@ static int checkout_all(const char *prefix, int prefix_length)
* first entry inside the expanded sparse directory).
*/
if (ignore_skip_worktree) {
- ensure_full_index(&the_index);
- ce = the_index.cache[i];
+ ensure_full_index(the_repository->index);
+ ce = the_repository->index->cache[i];
}
}
@@ -193,22 +191,26 @@ static const char * const builtin_checkout_index_usage[] = {
static int option_parse_stage(const struct option *opt,
const char *arg, int unset)
{
+ int *stage = opt->value;
+
BUG_ON_OPT_NEG(unset);
if (!strcmp(arg, "all")) {
- to_tempfile = 1;
- checkout_stage = CHECKOUT_ALL;
+ *stage = CHECKOUT_ALL;
} else {
int ch = arg[0];
if ('1' <= ch && ch <= '3')
- checkout_stage = arg[0] - '0';
+ *stage = arg[0] - '0';
else
die(_("stage should be between 1 and 3 or all"));
}
return 0;
}
-int cmd_checkout_index(int argc, const char **argv, const char *prefix)
+int cmd_checkout_index(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i;
struct lock_file lock_file = LOCK_INIT;
@@ -239,7 +241,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
N_("write the content to temporary files")),
OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
N_("when creating files, prepend <string>")),
- OPT_CALLBACK_F(0, "stage", NULL, "(1|2|3|all)",
+ OPT_CALLBACK_F(0, "stage", &checkout_stage, "(1|2|3|all)",
N_("copy out the files from named stage"),
PARSE_OPT_NONEG, option_parse_stage),
OPT_END()
@@ -260,7 +262,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
builtin_checkout_index_usage, 0);
- state.istate = &the_index;
+ state.istate = the_repository->index;
state.force = force;
state.quiet = quiet;
state.not_new = not_new;
@@ -269,12 +271,18 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
state.base_dir = "";
state.base_dir_len = strlen(state.base_dir);
+ if (to_tempfile < 0)
+ to_tempfile = (checkout_stage == CHECKOUT_ALL);
+ if (!to_tempfile && checkout_stage == CHECKOUT_ALL)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--stage=all", "--no-temp");
+
/*
* when --prefix is specified we do not want to update cache.
*/
if (index_opt && !state.base_dir_len && !to_tempfile) {
state.refresh_cache = 1;
- state.istate = &the_index;
+ state.istate = the_repository->index;
repo_hold_locked_index(the_repository, &lock_file,
LOCK_DIE_ON_ERROR);
}
@@ -333,7 +341,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
return 1;
if (is_lock_file_locked(&lock_file) &&
- write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
return 0;
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f53612f468..c449558e66 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,7 +1,6 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "advice.h"
-#include "blob.h"
#include "branch.h"
#include "cache-tree.h"
#include "checkout.h"
@@ -25,12 +24,11 @@
#include "read-cache.h"
#include "refs.h"
#include "remote.h"
+#include "repo-settings.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"
@@ -94,7 +92,7 @@ struct checkout_opts {
int new_branch_log;
enum branch_track track;
struct diff_options diff_options;
- char *conflict_style;
+ int conflict_style;
int branch_exists;
const char *prefix;
@@ -103,6 +101,8 @@ struct checkout_opts {
struct tree *source_tree;
};
+#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 }
+
struct branch_info {
char *name; /* The short name used */
char *path; /* The full name of a real branch */
@@ -127,7 +127,7 @@ static void branch_info_release(struct branch_info *info)
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
- return run_hooks_l("post-checkout",
+ return run_hooks_l(the_repository, "post-checkout",
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
changed ? "1" : "0", NULL);
@@ -147,7 +147,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
return READ_TREE_RECURSIVE;
len = base->len + strlen(pathname);
- ce = make_empty_cache_entry(&the_index, len);
+ ce = make_empty_cache_entry(the_repository->index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, base->buf, base->len);
memcpy(ce->name + base->len, pathname, len - base->len);
@@ -160,9 +160,9 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
* entry in place. Whether it is UPTODATE or not, checkout_entry will
* do the right thing.
*/
- pos = index_name_pos(&the_index, ce->name, ce->ce_namelen);
+ pos = index_name_pos(the_repository->index, ce->name, ce->ce_namelen);
if (pos >= 0) {
- struct cache_entry *old = the_index.cache[pos];
+ struct cache_entry *old = the_repository->index->cache[pos];
if (ce->ce_mode == old->ce_mode &&
!ce_intent_to_add(old) &&
oideq(&ce->oid, &old->oid)) {
@@ -172,7 +172,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
}
}
- add_index_entry(&the_index, ce,
+ add_index_entry(the_repository->index, ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
return 0;
}
@@ -191,8 +191,8 @@ static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
static int skip_same_name(const struct cache_entry *ce, int pos)
{
- while (++pos < the_index.cache_nr &&
- !strcmp(the_index.cache[pos]->name, ce->name))
+ while (++pos < the_repository->index->cache_nr &&
+ !strcmp(the_repository->index->cache[pos]->name, ce->name))
; /* skip */
return pos;
}
@@ -200,9 +200,9 @@ static int skip_same_name(const struct cache_entry *ce, int pos)
static int check_stage(int stage, const struct cache_entry *ce, int pos,
int overlay_mode)
{
- while (pos < the_index.cache_nr &&
- !strcmp(the_index.cache[pos]->name, ce->name)) {
- if (ce_stage(the_index.cache[pos]) == stage)
+ while (pos < the_repository->index->cache_nr &&
+ !strcmp(the_repository->index->cache[pos]->name, ce->name)) {
+ if (ce_stage(the_repository->index->cache[pos]) == stage)
return 0;
pos++;
}
@@ -219,8 +219,8 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)
unsigned seen = 0;
const char *name = ce->name;
- while (pos < the_index.cache_nr) {
- ce = the_index.cache[pos];
+ while (pos < the_repository->index->cache_nr) {
+ ce = the_repository->index->cache[pos];
if (strcmp(name, ce->name))
break;
seen |= (1 << ce_stage(ce));
@@ -236,10 +236,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
const struct checkout *state, int *nr_checkouts,
int overlay_mode)
{
- while (pos < the_index.cache_nr &&
- !strcmp(the_index.cache[pos]->name, ce->name)) {
- if (ce_stage(the_index.cache[pos]) == stage)
- return checkout_entry(the_index.cache[pos], state,
+ while (pos < the_repository->index->cache_nr &&
+ !strcmp(the_repository->index->cache[pos]->name, ce->name)) {
+ if (ce_stage(the_repository->index->cache[pos]) == stage)
+ return checkout_entry(the_repository->index->cache[pos], state,
NULL, nr_checkouts);
pos++;
}
@@ -254,9 +254,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
}
static int checkout_merged(int pos, const struct checkout *state,
- int *nr_checkouts, struct mem_pool *ce_mem_pool)
+ int *nr_checkouts, struct mem_pool *ce_mem_pool,
+ int conflict_style)
{
- struct cache_entry *ce = the_index.cache[pos];
+ struct cache_entry *ce = the_repository->index->cache[pos];
const char *path = ce->name;
mmfile_t ancestor, ours, theirs;
enum ll_merge_result merge_status;
@@ -265,11 +266,11 @@ static int checkout_merged(int pos, const struct checkout *state,
mmbuffer_t result_buf;
struct object_id threeway[3];
unsigned mode = 0;
- struct ll_merge_options ll_opts;
+ struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
int renormalize = 0;
memset(threeway, 0, sizeof(threeway));
- while (pos < the_index.cache_nr) {
+ while (pos < the_repository->index->cache_nr) {
int stage;
stage = ce_stage(ce);
if (!stage || strcmp(path, ce->name))
@@ -278,7 +279,7 @@ static int checkout_merged(int pos, const struct checkout *state,
if (stage == 2)
mode = create_ce_mode(ce->ce_mode);
pos++;
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
}
if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2]))
return error(_("path '%s' does not have necessary versions"), path);
@@ -287,9 +288,9 @@ static int checkout_merged(int pos, const struct checkout *state,
read_mmblob(&ours, &threeway[1]);
read_mmblob(&theirs, &threeway[2]);
- memset(&ll_opts, 0, sizeof(ll_opts));
git_config_get_bool("merge.renormalize", &renormalize);
ll_opts.renormalize = renormalize;
+ ll_opts.conflict_style = conflict_style;
merge_status = ll_merge(&result_buf, path, &ancestor, "base",
&ours, "ours", &theirs, "theirs",
state->istate, &ll_opts);
@@ -356,7 +357,7 @@ static void mark_ce_for_checkout_overlay(struct cache_entry *ce,
* match_pathspec() for _all_ entries when
* opts->source_tree != NULL.
*/
- if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
+ if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched))
ce->ce_flags |= CE_MATCHED;
}
@@ -367,7 +368,7 @@ static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,
ce->ce_flags &= ~CE_MATCHED;
if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
return;
- if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {
+ if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched)) {
ce->ce_flags |= CE_MATCHED;
if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
/*
@@ -391,7 +392,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
state.force = 1;
state.refresh_cache = 1;
- state.istate = &the_index;
+ state.istate = the_repository->index;
mem_pool_init(&ce_mem_pool, 0);
get_parallel_checkout_configs(&pc_workers, &pc_threshold);
@@ -404,8 +405,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
if (pc_workers > 1)
init_parallel_checkout();
- for (pos = 0; pos < the_index.cache_nr; pos++) {
- struct cache_entry *ce = the_index.cache[pos];
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+ struct cache_entry *ce = the_repository->index->cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state,
@@ -420,7 +421,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
else if (opts->merge)
errs |= checkout_merged(pos, &state,
&nr_unmerged,
- &ce_mem_pool);
+ &ce_mem_pool,
+ opts->conflict_style);
pos = skip_same_name(ce, pos) - 1;
}
}
@@ -428,7 +430,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
NULL, NULL);
mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
- remove_marked_cache_entries(&the_index, 1);
+ remove_marked_cache_entries(the_repository->index, 1);
remove_scheduled_dirs();
errs |= finish_delayed_checkout(&state, opts->show_progress);
@@ -523,6 +525,15 @@ static int checkout_paths(const struct checkout_opts *opts,
"--merge", "--conflict", "--staged");
}
+ /*
+ * recreating unmerged index entries and writing out data from
+ * unmerged index entries would make no sense when checking out
+ * of a tree-ish.
+ */
+ if ((opts->merge || opts->writeout_stage) && opts->source_tree)
+ die(_("'%s', '%s', or '%s' cannot be used when checking out of a tree"),
+ "--merge", "--ours", "--theirs");
+
if (opts->patch_mode) {
enum add_p_mode patch_mode;
const char *rev = new_branch_info->name;
@@ -560,6 +571,8 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->source_tree)
read_tree_some(opts->source_tree, &opts->pathspec);
+ if (opts->merge)
+ unmerge_index(the_repository->index, &opts->pathspec, CE_MATCHED);
ps_matched = xcalloc(opts->pathspec.nr, 1);
@@ -567,13 +580,13 @@ static int checkout_paths(const struct checkout_opts *opts,
* Make sure all pathspecs participated in locating the paths
* to be checked out.
*/
- for (pos = 0; pos < the_index.cache_nr; pos++)
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++)
if (opts->overlay_mode)
- mark_ce_for_checkout_overlay(the_index.cache[pos],
+ mark_ce_for_checkout_overlay(the_repository->index->cache[pos],
ps_matched,
opts);
else
- mark_ce_for_checkout_no_overlay(the_index.cache[pos],
+ mark_ce_for_checkout_no_overlay(the_repository->index->cache[pos],
ps_matched,
opts);
@@ -583,13 +596,9 @@ static int checkout_paths(const struct checkout_opts *opts,
}
free(ps_matched);
- /* "checkout -m path" to recreate conflicted state */
- if (opts->merge)
- unmerge_marked_index(&the_index);
-
/* Any unmerged paths? */
- for (pos = 0; pos < the_index.cache_nr; pos++) {
- const struct cache_entry *ce = the_index.cache[pos];
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+ const struct cache_entry *ce = the_repository->index->cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce))
continue;
@@ -614,7 +623,7 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->checkout_worktree)
errs |= checkout_worktree(opts, new_branch_info);
else
- remove_marked_cache_entries(&the_index, 1);
+ remove_marked_cache_entries(the_repository->index, 1);
/*
* Allow updating the index when checking out from the index.
@@ -626,7 +635,7 @@ static int checkout_paths(const struct checkout_opts *opts,
checkout_index = opts->checkout_index;
if (checkout_index) {
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
} else {
/*
@@ -638,7 +647,8 @@ static int checkout_paths(const struct checkout_opts *opts,
rollback_lock_file(&lock_file);
}
- read_ref_full("HEAD", 0, &rev, NULL);
+ refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0,
+ &rev, NULL);
head = lookup_commit_reference_gently(the_repository, &rev, 1);
errs |= post_checkout_hook(head, head, 0);
@@ -695,13 +705,14 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = o->show_progress;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
init_checkout_metadata(&opts.meta, info->refname,
info->commit ? &info->commit->object.oid : null_oid(),
NULL);
- parse_tree(tree);
- init_tree_desc(&tree_desc, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ return 128;
+ init_tree_desc(&tree_desc, &tree->object.oid, tree->buffer, tree->size);
switch (unpack_trees(1, &tree_desc, &opts)) {
case -2:
*writeout_error = 1;
@@ -747,12 +758,12 @@ static void init_topts(struct unpack_trees_options *topts, int merge,
{
memset(topts, 0, sizeof(*topts));
topts->head_idx = -1;
- topts->src_index = &the_index;
- topts->dst_index = &the_index;
+ topts->src_index = the_repository->index;
+ topts->dst_index = the_repository->index;
setup_unpack_trees_porcelain(topts, "checkout");
- topts->initial_checkout = is_index_unborn(&the_index);
+ topts->initial_checkout = is_index_unborn(the_repository->index);
topts->update = 1;
topts->merge = 1;
topts->quiet = merge && old_commit;
@@ -774,14 +785,20 @@ static int merge_working_tree(const struct checkout_opts *opts,
if (repo_read_index_preload(the_repository, NULL, 0) < 0)
return error(_("index file corrupt"));
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
if (new_branch_info->commit)
BUG("'switch --orphan' should never accept a commit as starting point");
new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
- } else
+ if (!new_tree)
+ BUG("unable to read empty tree");
+ } else {
new_tree = repo_get_commit_tree(the_repository,
new_branch_info->commit);
+ if (!new_tree)
+ return error(_("unable to read tree (%s)"),
+ oid_to_hex(&new_branch_info->commit->object.oid));
+ }
if (opts->discard_changes) {
ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
@@ -792,9 +809,9 @@ static int merge_working_tree(const struct checkout_opts *opts,
struct unpack_trees_options topts;
const struct object_id *old_commit_oid;
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
- if (unmerged_index(&the_index)) {
+ if (unmerged_index(the_repository->index)) {
error(_("you need to resolve your current index first"));
return 1;
}
@@ -815,10 +832,13 @@ static int merge_working_tree(const struct checkout_opts *opts,
die(_("unable to parse commit %s"),
oid_to_hex(old_commit_oid));
- init_tree_desc(&trees[0], tree->buffer, tree->size);
- parse_tree(new_tree);
+ init_tree_desc(&trees[0], &tree->object.oid,
+ tree->buffer, tree->size);
+ if (parse_tree(new_tree) < 0)
+ exit(128);
tree = new_tree;
- init_tree_desc(&trees[1], tree->buffer, tree->size);
+ init_tree_desc(&trees[1], &tree->object.oid,
+ tree->buffer, tree->size);
ret = unpack_trees(2, trees, &topts);
clear_unpack_trees_porcelain(&topts);
@@ -864,8 +884,9 @@ static int merge_working_tree(const struct checkout_opts *opts,
* entries in the index.
*/
- add_files_to_cache(the_repository, NULL, NULL, 0, 0);
- init_merge_options(&o, the_repository);
+ add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
+ 0);
+ init_ui_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository);
@@ -883,6 +904,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
o.branch1 = new_branch_info->name;
o.branch2 = "local";
+ o.conflict_style = opts->conflict_style;
ret = merge_trees(&o,
new_tree,
work,
@@ -899,10 +921,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
}
- if (!cache_tree_fully_valid(the_index.cache_tree))
- cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+ if (!cache_tree_fully_valid(the_repository->index->cache_tree))
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
if (!opts->discard_changes && !opts->quiet && new_branch_info->commit)
@@ -930,15 +952,18 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
const char *old_desc, *reflog_msg;
if (opts->new_branch) {
if (opts->new_orphan_branch) {
+ enum log_refs_config log_all_ref_updates =
+ repo_settings_get_log_all_ref_updates(the_repository);
char *refname;
refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
if (opts->new_branch_log &&
- !should_autocreate_reflog(refname)) {
+ !should_autocreate_reflog(log_all_ref_updates, refname)) {
int ret;
struct strbuf err = STRBUF_INIT;
- ret = safe_create_reflog(refname, &err);
+ ret = refs_create_reflog(get_main_ref_store(the_repository),
+ refname, &err);
if (ret) {
fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
opts->new_orphan_branch, err.buf);
@@ -979,8 +1004,10 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
if (!strcmp(new_branch_info->name, "HEAD") && !new_branch_info->path && !opts->force_detach) {
/* Nothing to do. */
} else if (opts->force_detach || !new_branch_info->path) { /* No longer on any branch. */
- update_ref(msg.buf, "HEAD", &new_branch_info->commit->object.oid, NULL,
- REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ "HEAD", &new_branch_info->commit->object.oid,
+ NULL,
+ REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
if (!opts->quiet) {
if (old_branch_info->path &&
advice_enabled(ADVICE_DETACHED_HEAD) && !opts->force_detach)
@@ -988,7 +1015,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
}
} else if (new_branch_info->path) { /* Switch branches. */
- if (create_symref("HEAD", new_branch_info->path, msg.buf) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf) < 0)
die(_("unable to update HEAD"));
if (!opts->quiet) {
if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) {
@@ -1009,18 +1036,20 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
}
}
if (old_branch_info->path && old_branch_info->name) {
- if (!ref_exists(old_branch_info->path) && reflog_exists(old_branch_info->path))
- delete_reflog(old_branch_info->path);
+ if (!refs_ref_exists(get_main_ref_store(the_repository), old_branch_info->path) && refs_reflog_exists(get_main_ref_store(the_repository), old_branch_info->path))
+ refs_delete_reflog(get_main_ref_store(the_repository),
+ old_branch_info->path);
}
}
remove_branch_state(the_repository, !opts->quiet);
strbuf_release(&msg);
if (!opts->quiet &&
- (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, "HEAD"))))
+ !opts->force_detach &&
+ (new_branch_info->path || !strcmp(new_branch_info->name, "HEAD")))
report_tracking(new_branch_info);
}
-static int add_pending_uninteresting_ref(const char *refname,
+static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
@@ -1108,7 +1137,8 @@ static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne
object->flags &= ~UNINTERESTING;
add_pending_object(&revs, object, oid_to_hex(&object->oid));
- for_each_ref(add_pending_uninteresting_ref, &revs);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_pending_uninteresting_ref, &revs);
if (new_commit)
add_pending_oid(&revs, "HEAD",
&new_commit->object.oid,
@@ -1138,7 +1168,8 @@ static int switch_branches(const struct checkout_opts *opts,
trace2_cmd_mode("branch");
memset(&old_branch_info, 0, sizeof(old_branch_info));
- old_branch_info.path = resolve_refdup("HEAD", 0, &rev, &flag);
+ old_branch_info.path = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &rev, &flag);
if (old_branch_info.path)
old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
if (!(flag & REF_ISSYMREF))
@@ -1195,6 +1226,8 @@ static int git_checkout_config(const char *var, const char *value,
struct checkout_opts *opts = cb;
if (!strcmp(var, "diff.ignoresubmodules")) {
+ if (!value)
+ return config_error_nonbool(var);
handle_ignore_submodules_arg(&opts->diff_options, value);
return 0;
}
@@ -1218,11 +1251,13 @@ static void setup_new_branch_info_and_source_tree(
struct tree **source_tree = &opts->source_tree;
struct object_id branch_rev;
- new_branch_info->name = xstrdup(arg);
+ /* treat '@' as a shortcut for 'HEAD' */
+ new_branch_info->name = !strcmp(arg, "@") ? xstrdup("HEAD") :
+ xstrdup(arg);
setup_branch_path(new_branch_info);
if (!check_refname_format(new_branch_info->path, 0) &&
- !read_ref(new_branch_info->path, &branch_rev))
+ !refs_read_ref(get_main_ref_store(the_repository), new_branch_info->path, &branch_rev))
oidcpy(rev, &branch_rev);
else
/* not an existing branch */
@@ -1232,19 +1267,24 @@ static void setup_new_branch_info_and_source_tree(
if (!new_branch_info->commit) {
/* not a commit */
*source_tree = parse_tree_indirect(rev);
+ if (!*source_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(rev));
} else {
parse_commit_or_die(new_branch_info->commit);
*source_tree = repo_get_commit_tree(the_repository,
new_branch_info->commit);
+ if (!*source_tree)
+ die(_("unable to read tree (%s)"),
+ oid_to_hex(&new_branch_info->commit->object.oid));
}
}
-static const char *parse_remote_branch(const char *arg,
- struct object_id *rev,
- int could_be_checkout_paths)
+static char *parse_remote_branch(const char *arg,
+ struct object_id *rev,
+ int could_be_checkout_paths)
{
int num_matches = 0;
- const char *remote = unique_tracking_name(arg, rev, &num_matches);
+ char *remote = unique_tracking_name(arg, rev, &num_matches);
if (remote && could_be_checkout_paths) {
die(_("'%s' could be both a local file and a tracking branch.\n"
@@ -1280,6 +1320,7 @@ static int parse_branchname_arg(int argc, const char **argv,
const char **new_branch = &opts->new_branch;
int argcount = 0;
const char *arg;
+ char *remote = NULL;
int dash_dash_pos;
int has_dash_dash = 0;
int i;
@@ -1380,8 +1421,8 @@ static int parse_branchname_arg(int argc, const char **argv,
recover_with_dwim = 0;
if (recover_with_dwim) {
- const char *remote = parse_remote_branch(arg, rev,
- could_be_checkout_paths);
+ remote = parse_remote_branch(arg, rev,
+ could_be_checkout_paths);
if (remote) {
*new_branch = arg;
arg = remote;
@@ -1423,6 +1464,7 @@ static int parse_branchname_arg(int argc, const char **argv,
argc--;
}
+ free(remote);
return argcount;
}
@@ -1436,7 +1478,8 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
if (!opts->new_branch)
die(_("You are on a branch yet to be born"));
strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
- status = create_symref("HEAD", branch_ref.buf, "checkout -b");
+ status = refs_update_symref(get_main_ref_store(the_repository),
+ "HEAD", branch_ref.buf, "checkout -b");
strbuf_release(&branch_ref);
if (!opts->quiet)
fprintf(stderr, _("Switched to a new branch '%s'\n"),
@@ -1509,9 +1552,34 @@ static void die_if_some_operation_in_progress(void)
wt_status_state_free_buffers(&state);
}
+/*
+ * die if attempting to checkout an existing branch that is in use
+ * in another worktree, unless ignore-other-wortrees option is given.
+ * The check is bypassed when the branch is already the current one,
+ * as it will not make things any worse.
+ */
+static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
+ const char *full_ref)
+{
+ int flags;
+ char *head_ref;
+
+ if (opts->ignore_other_worktrees)
+ return;
+ head_ref = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
+ if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref)))
+ die_if_checked_out(full_ref, 1);
+ free(head_ref);
+}
+
static int checkout_branch(struct checkout_opts *opts,
struct branch_info *new_branch_info)
{
+ int noop_switch = (!new_branch_info->name &&
+ !opts->new_branch &&
+ !opts->force_detach);
+
if (opts->pathspec.nr)
die(_("paths cannot be used with switching branches"));
@@ -1523,9 +1591,14 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("'%s' cannot be used with switching branches"),
"--[no]-overlay");
- if (opts->writeout_stage)
- die(_("'%s' cannot be used with switching branches"),
- "--ours/--theirs");
+ if (opts->writeout_stage) {
+ const char *msg;
+ if (noop_switch)
+ msg = _("'%s' needs the paths to check out");
+ else
+ msg = _("'%s' cannot be used with switching branches");
+ die(msg, "--ours/--theirs");
+ }
if (opts->force && opts->merge)
die(_("'%s' cannot be used with '%s'"), "-f", "-m");
@@ -1552,10 +1625,8 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("Cannot switch branch to a non-commit '%s'"),
new_branch_info->name);
- if (!opts->switch_branch_doing_nothing_is_ok &&
- !new_branch_info->name &&
- !opts->new_branch &&
- !opts->force_detach)
+ if (noop_switch &&
+ !opts->switch_branch_doing_nothing_is_ok)
die(_("missing branch or commit argument"));
if (!opts->implicit_detach &&
@@ -1569,27 +1640,46 @@ static int checkout_branch(struct checkout_opts *opts,
if (!opts->can_switch_when_in_progress)
die_if_some_operation_in_progress();
- if (new_branch_info->path && !opts->force_detach && !opts->new_branch &&
- !opts->ignore_other_worktrees) {
- int flag;
- char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
- if (head_ref &&
- (!(flag & REF_ISSYMREF) || strcmp(head_ref, new_branch_info->path)))
- die_if_checked_out(new_branch_info->path, 1);
- free(head_ref);
+ /* "git checkout <branch>" */
+ if (new_branch_info->path && !opts->force_detach && !opts->new_branch)
+ die_if_switching_to_a_branch_in_use(opts, new_branch_info->path);
+
+ /* "git checkout -B <branch>" */
+ if (opts->new_branch_force) {
+ char *full_ref = xstrfmt("refs/heads/%s", opts->new_branch);
+ die_if_switching_to_a_branch_in_use(opts, full_ref);
+ free(full_ref);
}
if (!new_branch_info->commit && opts->new_branch) {
struct object_id rev;
int flag;
- if (!read_ref_full("HEAD", 0, &rev, &flag) &&
+ if (!refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0, &rev, &flag) &&
(flag & REF_ISSYMREF) && is_null_oid(&rev))
return switch_unborn_to_new_branch(opts);
}
return switch_branches(opts, new_branch_info);
}
+static int parse_opt_conflict(const struct option *o, const char *arg, int unset)
+{
+ struct checkout_opts *opts = o->value;
+
+ if (unset) {
+ opts->conflict_style = -1;
+ return 0;
+ }
+ opts->conflict_style = parse_conflict_style_name(arg);
+ if (opts->conflict_style < 0)
+ return error(_("unknown conflict style '%s'"), arg);
+ /* --conflict overrides a previous --no-merge */
+ if (!opts->merge)
+ opts->merge = -1;
+
+ return 0;
+}
+
static struct option *add_common_options(struct checkout_opts *opts,
struct option *prevopts)
{
@@ -1600,8 +1690,9 @@ static struct option *add_common_options(struct checkout_opts *opts,
PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
- OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
- N_("conflict style (merge, diff3, or zdiff3)")),
+ OPT_CALLBACK(0, "conflict", opts, N_("style"),
+ N_("conflict style (merge, diff3, or zdiff3)"),
+ parse_opt_conflict),
OPT_END()
};
struct option *newopts = parse_options_concat(prevopts, options);
@@ -1620,12 +1711,12 @@ static struct option *add_common_switch_branch_options(
parse_opt_tracking_mode),
OPT__FORCE(&opts->force, N_("force checkout (throw away local modifications)"),
PARSE_OPT_NOCOMPLETE),
- OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
+ OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unborn branch")),
OPT_BOOL_F(0, "overwrite-ignore", &opts->overwrite_ignore,
N_("update ignored files (default)"),
PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "ignore-other-worktrees", &opts->ignore_other_worktrees,
- N_("do not check if another worktree is holding the given ref")),
+ N_("do not check if another worktree is using this branch")),
OPT_END()
};
struct option *newopts = parse_options_concat(prevopts, options);
@@ -1660,10 +1751,11 @@ static char cb_option = 'b';
static int checkout_main(int argc, const char **argv, const char *prefix,
struct checkout_opts *opts, struct option *options,
- const char * const usagestr[],
- struct branch_info *new_branch_info)
+ const char * const usagestr[])
{
int parseopt_flags = 0;
+ struct branch_info new_branch_info = { 0 };
+ int ret;
opts->overwrite_ignore = 1;
opts->prefix = prefix;
@@ -1692,15 +1784,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->show_progress = isatty(2);
}
- 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,
- &ctx, NULL);
- }
+ /* --conflicts implies --merge */
+ if (opts->merge == -1)
+ opts->merge = opts->conflict_style >= 0;
+
if (opts->force) {
opts->discard_changes = 1;
opts->ignore_unmerged_opt = "--force";
@@ -1779,7 +1866,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->track == BRANCH_TRACK_UNSPECIFIED &&
!opts->new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- new_branch_info, opts, &rev);
+ &new_branch_info, opts, &rev);
argv += n;
argc -= n;
} else if (!opts->accept_ref && opts->from_treeish) {
@@ -1788,7 +1875,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
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,
+ setup_new_branch_info_and_source_tree(&new_branch_info,
opts, &rev,
opts->from_treeish);
@@ -1808,7 +1895,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
* Try to give more helpful suggestion.
* new_branch && argc > 1 will be caught later.
*/
- if (opts->new_branch && argc == 1 && !new_branch_info->commit)
+ if (opts->new_branch && argc == 1 && !new_branch_info.commit)
die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
argv[0], opts->new_branch);
@@ -1858,14 +1945,24 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
if (opts->patch_mode || opts->pathspec.nr)
- return checkout_paths(opts, new_branch_info);
+ ret = checkout_paths(opts, &new_branch_info);
else
- return checkout_branch(opts, new_branch_info);
+ ret = checkout_branch(opts, &new_branch_info);
+
+ branch_info_release(&new_branch_info);
+ clear_pathspec(&opts->pathspec);
+ free(opts->pathspec_from_file);
+ free(options);
+
+ return ret;
}
-int cmd_checkout(int argc, const char **argv, const char *prefix)
+int cmd_checkout(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- struct checkout_opts opts;
+ struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options;
struct option checkout_options[] = {
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -1878,10 +1975,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")),
OPT_END()
};
- int ret;
- struct branch_info new_branch_info = { 0 };
- memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
opts.switch_branch_doing_nothing_is_ok = 1;
opts.only_merge_on_switching_branches = 0;
@@ -1909,18 +2003,16 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
options = add_common_switch_branch_options(&opts, options);
options = add_checkout_path_options(&opts, options);
- ret = checkout_main(argc, argv, prefix, &opts,
- 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;
+ return checkout_main(argc, argv, prefix, &opts, options,
+ checkout_usage);
}
-int cmd_switch(int argc, const char **argv, const char *prefix)
+int cmd_switch(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- struct checkout_opts opts;
+ struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options = NULL;
struct option switch_options[] = {
OPT_STRING('c', "create", &opts.new_branch, N_("branch"),
@@ -1933,10 +2025,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
N_("throw away local modifications")),
OPT_END()
};
- int ret;
- struct branch_info new_branch_info = { 0 };
- memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
opts.accept_ref = 1;
opts.accept_pathspec = 0;
@@ -1953,16 +2042,16 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
cb_option = 'c';
- ret = checkout_main(argc, argv, prefix, &opts,
- options, switch_branch_usage, &new_branch_info);
- branch_info_release(&new_branch_info);
- FREE_AND_NULL(options);
- return ret;
+ return checkout_main(argc, argv, prefix, &opts, options,
+ switch_branch_usage);
}
-int cmd_restore(int argc, const char **argv, const char *prefix)
+int cmd_restore(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- struct checkout_opts opts;
+ struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options;
struct option restore_options[] = {
OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
@@ -1976,10 +2065,7 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode")),
OPT_END()
};
- int ret;
- struct branch_info new_branch_info = { 0 };
- memset(&opts, 0, sizeof(opts));
opts.accept_ref = 0;
opts.accept_pathspec = 1;
opts.empty_pathspec_ok = 0;
@@ -1992,9 +2078,6 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
options = add_common_options(&opts, options);
options = add_checkout_path_options(&opts, options);
- ret = checkout_main(argc, argv, prefix, &opts,
- options, restore_usage, &new_branch_info);
- branch_info_release(&new_branch_info);
- FREE_AND_NULL(options);
- return ret;
+ return checkout_main(argc, argv, prefix, &opts, options,
+ restore_usage);
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 49c224e626..9c48dd0271 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -5,8 +5,7 @@
*
* Based on git-clean.sh by Pavel Roskin
*/
-
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -15,7 +14,6 @@
#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"
@@ -25,7 +23,7 @@
#include "help.h"
#include "prompt.h"
-static int force = -1; /* unset */
+static int require_force = -1; /* unset */
static int interactive;
static struct string_list del_list = STRING_LIST_INIT_DUP;
static unsigned int colopts;
@@ -128,7 +126,7 @@ static int git_clean_config(const char *var, const char *value,
}
if (!strcmp(var, "clean.requireforce")) {
- force = !git_config_bool(var, value);
+ require_force = git_config_bool(var, value);
return 0;
}
@@ -714,7 +712,7 @@ static int filter_by_patterns_cmd(void)
for_each_string_list_item(item, &del_list) {
int dtype = DT_UNKNOWN;
- if (is_excluded(&dir, &the_index, item->string, &dtype)) {
+ if (is_excluded(&dir, the_repository->index, item->string, &dtype)) {
*item->string = '\0';
changed++;
}
@@ -916,11 +914,14 @@ static void correct_untracked_entries(struct dir_struct *dir)
dir->nr = dst;
}
-int cmd_clean(int argc, const char **argv, const char *prefix)
+int cmd_clean(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i, res;
int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
+ int ignored_only = 0, force = 0, errors = 0, gone = 1;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf abs_path = STRBUF_INIT;
struct dir_struct dir = DIR_INIT;
@@ -946,22 +947,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
};
git_config(git_clean_config, NULL);
- if (force < 0)
- force = 0;
- else
- config_set = 1;
argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
0);
- if (!interactive && !dry_run && !force) {
- if (config_set)
- die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
- "refusing to clean"));
- else
- die(_("clean.requireForce defaults to true and neither -i, -n, nor -f given;"
- " refusing to clean"));
- }
+ if (require_force != 0 && !force && !interactive && !dry_run)
+ die(_("clean.requireForce is true and -f not given: refusing to clean"));
if (force > 1)
rm_flags = 0;
@@ -971,7 +962,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (ignored && ignored_only)
- die(_("-x and -X cannot be used together"));
+ die(_("options '%s' and '%s' cannot be used together"), "-x", "-X");
if (!ignored)
setup_standard_excludes(&dir);
if (ignored_only)
@@ -1031,7 +1022,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
PATHSPEC_PREFER_CWD,
prefix, argv);
- fill_directory(&dir, &the_index, &pathspec);
+ fill_directory(&dir, the_repository->index, &pathspec);
correct_untracked_entries(&dir);
for (i = 0; i < dir.nr; i++) {
@@ -1039,7 +1030,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
struct stat st;
const char *rel;
- if (!index_name_is_other(&the_index, ent->name, ent->len))
+ if (!index_name_is_other(the_repository->index, ent->name, ent->len))
continue;
if (lstat(ent->name, &st))
diff --git a/builtin/clone.c b/builtin/clone.c
index 2fce25acd4..21721db28a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -7,9 +7,9 @@
*
* Clone a repository into a different directory that does not yet exist.
*/
-
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+
#include "abspath.h"
#include "advice.h"
#include "config.h"
@@ -19,7 +19,6 @@
#include "hex.h"
#include "lockfile.h"
#include "parse-options.h"
-#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
#include "object-file.h"
@@ -72,7 +71,8 @@ static char *remote_name = NULL;
static char *option_branch = NULL;
static struct string_list option_not = STRING_LIST_INIT_NODUP;
static const char *real_git_dir;
-static char *option_upload_pack = "git-upload-pack";
+static const char *ref_format;
+static const char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
static int option_sparse_checkout;
@@ -116,7 +116,7 @@ static struct option builtin_clone_options[] = {
OPT_HIDDEN_BOOL(0, "naked", &option_bare,
N_("create a bare repository")),
OPT_BOOL(0, "mirror", &option_mirror,
- N_("create a mirror repository (implies bare)")),
+ N_("create a mirror repository (implies --bare)")),
OPT_BOOL('l', "local", &option_local,
N_("to clone from a local repository")),
OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
@@ -147,8 +147,8 @@ static struct option builtin_clone_options[] = {
N_("create a shallow clone of that depth")),
OPT_STRING(0, "shallow-since", &option_since, N_("time"),
N_("create a shallow clone since a specific time")),
- OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"),
- N_("deepen history of shallow clone, excluding rev")),
+ OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("ref"),
+ N_("deepen history of shallow clone, excluding ref")),
OPT_BOOL(0, "single-branch", &option_single_branch,
N_("clone only one branch, HEAD or --branch")),
OPT_BOOL(0, "no-tags", &option_no_tags,
@@ -157,6 +157,8 @@ static struct option builtin_clone_options[] = {
N_("any cloned submodules will be shallow")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
+ OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
N_("set config inside the new repository")),
OPT_STRING_LIST(0, "server-option", &server_options,
@@ -176,8 +178,8 @@ static struct option builtin_clone_options[] = {
static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
{
- static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
- static char *bundle_suffix[] = { ".bundle", "" };
+ static const char *suffix[] = { "/.git", "", ".git/.git", ".git" };
+ static const char *bundle_suffix[] = { ".bundle", "" };
size_t baselen = path->len;
struct stat st;
int i;
@@ -522,6 +524,9 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
struct ref *local_refs = head;
struct ref **tail = head ? &head->next : &local_refs;
+ struct refspec_item tag_refspec;
+
+ refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
if (option_single_branch) {
struct ref *remote_head = NULL;
@@ -529,7 +534,8 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
if (!option_branch)
remote_head = guess_remote_head(head, refs, 0);
else {
- local_refs = NULL;
+ free_one_ref(head);
+ local_refs = head = NULL;
tail = &local_refs;
remote_head = copy_ref(find_remote_branch(refs, option_branch));
}
@@ -544,7 +550,7 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
&tail, 0);
/* if --branch=tag, pull the requested tag explicitly */
- get_fetch_map(remote_head, tag_refspec, &tail, 0);
+ get_fetch_map(remote_head, &tag_refspec, &tail, 0);
}
free_refs(remote_head);
} else {
@@ -554,8 +560,9 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
}
if (!option_mirror && !option_single_branch && !option_no_tags)
- get_fetch_map(refs, tag_refspec, &tail, 0);
+ get_fetch_map(refs, &tag_refspec, &tail, 0);
+ refspec_item_clear(&tag_refspec);
return local_refs;
}
@@ -566,7 +573,8 @@ static void write_remote_refs(const struct ref *local_refs)
struct ref_transaction *t;
struct strbuf err = STRBUF_INIT;
- t = ref_transaction_begin(&err);
+ t = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ REF_TRANSACTION_FLAG_INITIAL, &err);
if (!t)
die("%s", err.buf);
@@ -574,11 +582,11 @@ static void write_remote_refs(const struct ref *local_refs)
if (!r->peer_ref)
continue;
if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
- 0, NULL, &err))
+ NULL, 0, NULL, &err))
die("%s", err.buf);
}
- if (initial_ref_transaction_commit(t, &err))
+ if (ref_transaction_commit(t, &err))
die("%s", err.buf);
strbuf_release(&err);
@@ -597,8 +605,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
OBJECT_INFO_QUICK |
OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
- update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg,
+ ref->name, &ref->old_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
}
}
@@ -650,9 +659,9 @@ static void update_remote_refs(const struct ref *refs,
struct strbuf head_ref = STRBUF_INIT;
strbuf_addstr(&head_ref, branch_top);
strbuf_addstr(&head_ref, "HEAD");
- if (create_symref(head_ref.buf,
- remote_head_points_at->peer_ref->name,
- msg) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), head_ref.buf,
+ remote_head_points_at->peer_ref->name,
+ msg) < 0)
die(_("unable to update %s"), head_ref.buf);
strbuf_release(&head_ref);
}
@@ -664,33 +673,36 @@ static void update_head(const struct ref *our, const struct ref *remote,
const char *head;
if (our && skip_prefix(our->name, "refs/heads/", &head)) {
/* Local default branch link */
- if (create_symref("HEAD", our->name, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0)
die(_("unable to update HEAD"));
if (!option_bare) {
- update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ msg, "HEAD", &our->old_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
install_branch_config(0, head, remote_name, our->name);
}
} else if (our) {
struct commit *c = lookup_commit_reference(the_repository,
&our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
- update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg,
+ "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
} else if (remote) {
/*
* We know remote HEAD points to a non-branch, or
* HEAD points to a branch but we don't know which one.
* Detach HEAD in all these cases.
*/
- update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg,
+ "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
} else if (unborn && skip_prefix(unborn, "refs/heads/", &head)) {
/*
* Unborn head from remote; same as "our" case above except
* that we have no ref to update.
*/
- if (create_symref("HEAD", unborn, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL) < 0)
die(_("unable to update HEAD"));
if (!option_bare)
install_branch_config(0, head, remote_name, unborn);
@@ -718,7 +730,8 @@ static int git_sparse_checkout_init(const char *repo)
return result;
}
-static int checkout(int submodule_progress, int filter_submodules)
+static int checkout(int submodule_progress, int filter_submodules,
+ enum ref_storage_format ref_storage_format)
{
struct object_id oid;
char *head;
@@ -731,7 +744,8 @@ static int checkout(int submodule_progress, int filter_submodules)
if (option_no_checkout)
return 0;
- head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ RESOLVE_REF_READING, &oid, NULL);
if (!head) {
warning(_("remote HEAD refers to nonexistent ref, "
"unable to checkout"));
@@ -758,24 +772,25 @@ static int checkout(int submodule_progress, int filter_submodules)
opts.preserve_ignored = 0;
opts.fn = oneway_merge;
opts.verbose_update = (option_verbosity >= 0);
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
init_checkout_metadata(&opts.meta, head, &oid, NULL);
tree = parse_tree_indirect(&oid);
if (!tree)
die(_("unable to parse commit %s"), oid_to_hex(&oid));
- parse_tree(tree);
- init_tree_desc(&t, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ exit(128);
+ init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts) < 0)
die(_("unable to checkout working tree"));
free(head);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
+ err |= run_hooks_l(the_repository, "post-checkout", oid_to_hex(null_oid()),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
@@ -800,6 +815,10 @@ static int checkout(int submodule_progress, int filter_submodules)
strvec_push(&cmd.args, "--no-fetch");
}
+ if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(&cmd.args, "--ref-format=%s",
+ ref_storage_format_to_name(ref_storage_format));
+
if (filter_submodules && filter_options.choice)
strvec_pushf(&cmd.args, "--filter=%s",
expand_list_objects_filter_spec(&filter_options));
@@ -820,6 +839,8 @@ static int git_clone_config(const char *k, const char *v,
const struct config_context *ctx, void *cb)
{
if (!strcmp(k, "clone.defaultremotename")) {
+ if (!v)
+ return config_error_nonbool(k);
free(remote_name);
remote_name = xstrdup(v);
}
@@ -936,7 +957,10 @@ static int path_exists(const char *path)
return !stat(path, &sb);
}
-int cmd_clone(int argc, const char **argv, const char *prefix)
+int cmd_clone(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repository UNUSED)
{
int is_bundle = 0, is_local;
int reject_shallow = 0;
@@ -951,6 +975,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct ref *mapped_refs = NULL;
const struct ref *ref;
struct strbuf key = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
const char *src_ref_prefix = "refs/heads/";
@@ -959,6 +984,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int submodule_progress;
int filter_submodules = 0;
int hash_algo;
+ enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
const int do_not_override_repo_unix_permissions = -1;
struct transport_ls_refs_options transport_ls_refs_options =
@@ -984,6 +1010,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_single_branch == -1)
option_single_branch = deepen ? 1 : 0;
+ if (ref_format) {
+ ref_storage_format = ref_storage_format_by_name(ref_format);
+ if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_format);
+ }
+
if (option_mirror)
option_bare = 1;
@@ -994,7 +1026,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (bundle_uri && deepen)
- die(_("--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-exclude"));
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--bundle-uri",
+ "--depth/--shallow-since/--shallow-exclude");
repo_name = argv[0];
@@ -1126,8 +1160,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
- do_not_override_repo_unix_permissions, INIT_DB_QUIET);
+ /*
+ * Initialize the repository, but skip initializing the reference
+ * database. We do not yet know about the object format of the
+ * repository, and reference backends may persist that information into
+ * their on-disk data structures.
+ */
+ init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
+ ref_storage_format, NULL,
+ do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
if (real_git_dir) {
free((char *)git_dir);
@@ -1135,6 +1176,50 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
/*
+ * We have a chicken-and-egg situation between initializing the refdb
+ * and spawning transport helpers:
+ *
+ * - Initializing the refdb requires us to know about the object
+ * format. We thus have to spawn the transport helper to learn
+ * about it.
+ *
+ * - The transport helper may want to access the Git repository. But
+ * because the refdb has not been initialized, we don't have "HEAD"
+ * or "refs/". Thus, the helper cannot find the Git repository.
+ *
+ * Ideally, we would have structured the helper protocol such that it's
+ * mandatory for the helper to first announce its capabilities without
+ * yet assuming a fully initialized repository. Like that, we could
+ * have added a "lazy-refdb-init" capability that announces whether the
+ * helper is ready to handle not-yet-initialized refdbs. If any helper
+ * didn't support them, we would have fully initialized the refdb with
+ * the SHA1 object format, but later on bailed out if we found out that
+ * the remote repository used a different object format.
+ *
+ * But we didn't, and thus we use the following workaround to partially
+ * initialize the repository's refdb such that it can be discovered by
+ * Git commands. To do so, we:
+ *
+ * - Create an invalid HEAD ref pointing at "refs/heads/.invalid".
+ *
+ * - Create the "refs/" directory.
+ *
+ * - Set up the ref storage format and repository version as
+ * required.
+ *
+ * This is sufficient for Git commands to discover the Git directory.
+ */
+ initialize_repository_version(GIT_HASH_UNKNOWN,
+ the_repository->ref_storage_format, 1);
+
+ strbuf_addf(&buf, "%s/HEAD", git_dir);
+ write_file(buf.buf, "ref: refs/heads/.invalid");
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s/refs", git_dir);
+ safe_create_dir(buf.buf, 1);
+
+ /*
* additional config can be injected with -c, make sure it's included
* after init_db, which clears the entire config environment.
*/
@@ -1214,15 +1299,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- if (option_sparse_checkout && git_sparse_checkout_init(dir))
- return 1;
-
- remote = remote_get(remote_name);
+ remote = remote_get_early(remote_name);
refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
branch_top.buf);
- path = get_repo_path(remote->url[0], &is_bundle);
+ path = get_repo_path(remote->url.v[0], &is_bundle);
is_local = option_local != 0 && path && !is_bundle;
if (is_local) {
if (option_depth)
@@ -1244,7 +1326,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_local > 0 && !is_local)
warning(_("--local is ignored"));
- transport = transport_get(remote, path ? path : remote->url[0]);
+ transport = transport_get(remote, path ? path : remote->url.v[0]);
transport_set_verbosity(transport, option_verbosity, option_progress);
transport->family = family;
transport->cloning = 1;
@@ -1295,13 +1377,43 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport->smart_options && !deepen && !filter_options.choice)
transport->smart_options->check_self_contained_and_connected = 1;
+ strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+ refspec_ref_prefixes(&remote->fetch,
+ &transport_ls_refs_options.ref_prefixes);
+ if (option_branch)
+ expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
+ option_branch);
+ if (!option_no_tags)
+ strvec_push(&transport_ls_refs_options.ref_prefixes,
+ "refs/tags/");
+
+ refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
+
+ /*
+ * Now that we know what algorithm the remote side is using, let's set
+ * ours to the same thing.
+ */
+ hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+ initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
+ repo_set_hash_algo(the_repository, hash_algo);
+ create_reference_database(the_repository->ref_storage_format, NULL, 1);
+
/*
* Before fetching from the remote, download and install bundle
* data from the --bundle-uri option.
*/
if (bundle_uri) {
+ struct remote_state *state;
int has_heuristic = 0;
+ /*
+ * We need to save the remote state as our remote's lifetime is
+ * tied to it.
+ */
+ state = the_repository->remote_state;
+ the_repository->remote_state = NULL;
+ repo_clear(the_repository);
+
/* At this point, we need the_repository to match the cloned repo. */
if (repo_init(the_repository, git_dir, work_tree))
warning(_("failed to initialize the repo, skipping bundle URI"));
@@ -1310,24 +1422,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
bundle_uri);
else if (has_heuristic)
git_config_set_gently("fetch.bundleuri", bundle_uri);
- }
-
- strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
- refspec_ref_prefixes(&remote->fetch,
- &transport_ls_refs_options.ref_prefixes);
- if (option_branch)
- expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
- option_branch);
- if (!option_no_tags)
- strvec_push(&transport_ls_refs_options.ref_prefixes,
- "refs/tags/");
-
- refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
- if (refs)
- mapped_refs = wanted_peer_refs(refs, &remote->fetch);
-
- if (!bundle_uri) {
+ remote_state_clear(the_repository->remote_state);
+ free(the_repository->remote_state);
+ the_repository->remote_state = state;
+ } else {
/*
* Populate transport->got_remote_bundle_uri and
* transport->bundle_uri. We might get nothing.
@@ -1336,25 +1435,34 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport->bundles &&
hashmap_get_size(&transport->bundles->bundles)) {
+ struct remote_state *state;
+
+ /*
+ * We need to save the remote state as our remote's
+ * lifetime is tied to it.
+ */
+ state = the_repository->remote_state;
+ the_repository->remote_state = NULL;
+ repo_clear(the_repository);
+
/* At this point, we need the_repository to match the cloned repo. */
if (repo_init(the_repository, git_dir, work_tree))
warning(_("failed to initialize the repo, skipping bundle URI"));
else if (fetch_bundle_list(the_repository,
transport->bundles))
warning(_("failed to fetch advertised bundles"));
+
+ remote_state_clear(the_repository->remote_state);
+ free(the_repository->remote_state);
+ the_repository->remote_state = state;
} else {
clear_bundle_list(transport->bundles);
FREE_AND_NULL(transport->bundles);
}
}
- /*
- * Now that we know what algorithm the remote side is using,
- * let's set ours to the same thing.
- */
- 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 (refs)
+ mapped_refs = wanted_peer_refs(refs, &remote->fetch);
if (mapped_refs) {
/*
@@ -1392,6 +1500,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
} else if (remote_head) {
our_head_points_at = NULL;
} else {
+ char *to_free = NULL;
const char *branch;
if (!mapped_refs) {
@@ -1404,7 +1513,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
"refs/heads/", &branch)) {
unborn_head = xstrdup(transport_ls_refs_options.unborn_head_target);
} else {
- branch = git_default_branch_name(0);
+ branch = to_free = repo_default_branch_name(the_repository, 0);
unborn_head = xstrfmt("refs/heads/%s", branch);
}
@@ -1420,6 +1529,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* a match.
*/
our_head_points_at = find_remote_branch(mapped_refs, branch);
+
+ free(to_free);
}
write_refspec_config(src_ref_prefix, our_head_points_at,
@@ -1457,12 +1568,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
dissociate_from_references();
}
+ if (option_sparse_checkout && git_sparse_checkout_init(dir))
+ return 1;
+
junk_mode = JUNK_LEAVE_REPO;
- err = checkout(submodule_progress, filter_submodules);
+ err = checkout(submodule_progress, filter_submodules,
+ ref_storage_format);
free(remote_name);
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
+ strbuf_release(&buf);
strbuf_release(&key);
free_refs(mapped_refs);
free_refs(remote_head_points_at);
@@ -1470,7 +1586,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
free(dir);
free(path);
free(repo_to_free);
- UNLEAK(repo);
junk_mode = JUNK_LEAVE_ALL;
transport_ls_refs_options_release(&transport_ls_refs_options);
diff --git a/builtin/column.c b/builtin/column.c
index a83be8bc99..50314cc255 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -18,7 +19,10 @@ static int column_config(const char *var, const char *value,
return git_column_config(var, value, cb, &colopts);
}
-int cmd_column(int argc, const char **argv, const char *prefix)
+int cmd_column(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct string_list list = STRING_LIST_INIT_DUP;
struct strbuf sb = STRBUF_INIT;
@@ -45,6 +49,8 @@ int cmd_column(int argc, const char **argv, const char *prefix)
memset(&copts, 0, sizeof(copts));
copts.padding = 1;
argc = parse_options(argc, argv, prefix, options, builtin_column_usage, 0);
+ if (copts.padding < 0)
+ die(_("%s must be non-negative"), "--padding");
if (argc)
usage_with_options(builtin_column_usage, options);
if (real_command || command) {
@@ -56,5 +62,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)
string_list_append(&list, sb.buf);
print_columns(&list, colopts, &copts);
+ strbuf_release(&sb);
+ string_list_clear(&list, 0);
return 0;
}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index c88389df24..7c991db6eb 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -1,17 +1,15 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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-ll.h"
#include "progress.h"
#include "replace-object.h"
+#include "strbuf.h"
#include "tag.h"
#include "trace2.h"
@@ -22,7 +20,7 @@
N_("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>")
+ " <split-options>")
static const char * builtin_commit_graph_verify_usage[] = {
BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
@@ -69,10 +67,12 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
struct commit_graph *graph = NULL;
struct object_directory *odb = NULL;
char *graph_name;
- int open_ok;
+ char *chain_name;
+ enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
int fd;
struct stat st;
int flags = 0;
+ int incomplete_chain = 0;
int ret;
static struct option builtin_commit_graph_verify_options[] = {
@@ -94,7 +94,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
usage_with_options(builtin_commit_graph_verify_usage, options);
if (!opts.obj_dir)
- opts.obj_dir = get_object_directory();
+ opts.obj_dir = repo_get_object_directory(the_repository);
if (opts.shallow)
flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
if (opts.progress)
@@ -102,24 +102,39 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
odb = find_odb(the_repository, opts.obj_dir);
graph_name = get_commit_graph_filename(odb);
- open_ok = open_commit_graph(graph_name, &fd, &st);
- if (!open_ok && errno != ENOENT)
+ chain_name = get_commit_graph_chain_filename(odb);
+ if (open_commit_graph(graph_name, &fd, &st))
+ opened = OPENED_GRAPH;
+ else if (errno != ENOENT)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
+ else if (open_commit_graph_chain(chain_name, &fd, &st))
+ opened = OPENED_CHAIN;
+ else if (errno != ENOENT)
+ die_errno(_("could not open commit-graph chain '%s'"), chain_name);
FREE_AND_NULL(graph_name);
+ FREE_AND_NULL(chain_name);
FREE_AND_NULL(options);
- if (open_ok)
+ if (opened == OPENED_NONE)
+ return 0;
+ else if (opened == OPENED_GRAPH)
graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
else
- graph = read_commit_graph_one(the_repository, odb);
+ graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
+ &incomplete_chain);
- /* Return failure if open_ok predicted success */
if (!graph)
- return !!open_ok;
+ return 1;
ret = verify_commit_graph(the_repository, graph, flags);
free_commit_graph(graph);
+
+ if (incomplete_chain) {
+ error("one or more commit-graph chain files could not be loaded");
+ ret |= 1;
+ }
+
return ret;
}
@@ -259,7 +274,7 @@ static int graph_write(int argc, const char **argv, const char *prefix)
if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
if (!opts.obj_dir)
- opts.obj_dir = get_object_directory();
+ opts.obj_dir = repo_get_object_directory(the_repository);
if (opts.append)
flags |= COMMIT_GRAPH_WRITE_APPEND;
if (opts.split)
@@ -311,10 +326,14 @@ cleanup:
FREE_AND_NULL(options);
string_list_clear(&pack_indexes, 0);
strbuf_release(&buf);
+ oidset_clear(&commits);
return result;
}
-int cmd_commit_graph(int argc, const char **argv, const char *prefix)
+int cmd_commit_graph(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option builtin_commit_graph_options[] = {
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 02625e7176..2ca1a57ebb 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -3,17 +3,15 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.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 "utf8.h"
-#include "gpg-interface.h"
#include "parse-options.h"
static const char * const commit_tree_usage[] = {
@@ -93,7 +91,10 @@ static int parse_file_arg_callback(const struct option *opt,
return 0;
}
-int cmd_commit_tree(int argc, const char **argv, const char *prefix)
+int cmd_commit_tree(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
static struct strbuf buffer = STRBUF_INIT;
struct commit_list *parents = NULL;
@@ -114,6 +115,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END()
};
+ int ret;
git_config(git_default_config, NULL);
@@ -135,11 +137,15 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid,
NULL, sign_commit)) {
- strbuf_release(&buffer);
- return 1;
+ ret = 1;
+ goto out;
}
printf("%s\n", oid_to_hex(&commit_oid));
+ ret = 0;
+
+out:
+ free_commit_list(parents);
strbuf_release(&buffer);
- return 0;
+ return ret;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 781af2e206..71d674138c 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -4,8 +4,7 @@
* Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
*/
-
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -16,28 +15,21 @@
#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 "hook.h"
-#include "refs.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 "repository.h"
#include "string-list.h"
#include "rerere.h"
#include "unpack-trees.h"
-#include "quote.h"
-#include "submodule.h"
-#include "gpg-interface.h"
#include "column.h"
#include "sequencer.h"
#include "sparse-index.h"
@@ -46,10 +38,11 @@
#include "commit-reach.h"
#include "commit-graph.h"
#include "pretty.h"
+#include "trailer.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
- " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\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"
@@ -114,14 +107,15 @@ static enum {
COMMIT_PARTIAL
} commit_style;
-static const char *logfile, *force_author;
-static const char *template_file;
+static const char *force_author;
+static char *logfile;
+static char *template_file;
/*
* The _message variables are commit names from which to take
* the commit message and/or authorship.
*/
static const char *author_message, *author_message_buffer;
-static char *edit_message, *use_message;
+static const char *edit_message, *use_message;
static char *fixup_message, *fixup_commit, *squash_message;
static const char *fixup_prefix;
static int all, also, interactive, patch_interactive, only, amend, signoff;
@@ -129,8 +123,8 @@ static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
static int no_post_rewrite, allow_empty_message, pathspec_file_nul;
-static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
-static char *sign_commit, *pathspec_from_file;
+static const char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
+static const char *sign_commit, *pathspec_from_file;
static struct strvec trailer_args = STRVEC_INIT;
/*
@@ -141,7 +135,7 @@ static struct strvec trailer_args = STRVEC_INIT;
* is specified explicitly.
*/
static enum commit_msg_cleanup_mode cleanup_mode;
-static const char *cleanup_arg;
+static char *cleanup_config;
static enum commit_whence whence;
static int use_editor = 1, include_status = 1;
@@ -150,14 +144,6 @@ static struct strbuf message = STRBUF_INIT;
static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
-static int opt_pass_trailer(const struct option *opt, const char *arg, int unset)
-{
- BUG_ON_OPT_NEG(unset);
-
- strvec_pushl(opt->value, "--trailer", arg, NULL);
- return 0;
-}
-
static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)
{
enum wt_status_format *value = (enum wt_status_format *)opt->value;
@@ -274,19 +260,19 @@ static int list_paths(struct string_list *list, const char *with_tree,
if (with_tree) {
char *max_prefix = common_prefix(pattern);
- overlay_tree_on_index(&the_index, with_tree, max_prefix);
+ overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
free(max_prefix);
}
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
struct string_list_item *item;
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!ce_path_match(&the_index, ce, pattern, m))
+ if (!ce_path_match(the_repository->index, ce, pattern, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
@@ -310,10 +296,10 @@ static void add_remove_files(struct string_list *list)
continue;
if (!lstat(p->string, &st)) {
- if (add_to_index(&the_index, p->string, &st, 0))
+ if (add_to_index(the_repository->index, p->string, &st, 0))
die(_("updating files failed"));
} else
- remove_file_from_index(&the_index, p->string);
+ remove_file_from_index(the_repository->index, p->string);
}
}
@@ -324,7 +310,7 @@ static void create_base_index(const struct commit *current_head)
struct tree_desc t;
if (!current_head) {
- discard_index(&the_index);
+ discard_index(the_repository->index);
return;
}
@@ -332,15 +318,16 @@ static void create_base_index(const struct commit *current_head)
opts.head_idx = 1;
opts.index_only = 1;
opts.merge = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.fn = oneway_merge;
tree = parse_tree_indirect(&current_head->object.oid);
if (!tree)
die(_("failed to unpack HEAD tree object"));
- parse_tree(tree);
- init_tree_desc(&t, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ exit(128);
+ init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts))
exit(128); /* We've already reported the error, finish dying */
}
@@ -351,7 +338,7 @@ static void refresh_cache_or_die(int refresh_flags)
* refresh_flags contains REFRESH_QUIET, so the only errors
* are for unmerged entries.
*/
- if (refresh_index(&the_index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL))
+ if (refresh_index(the_repository->index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL))
die_resolve_conflict("commit");
}
@@ -400,7 +387,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
refresh_cache_or_die(refresh_flags);
- if (write_locked_index(&the_index, &index_lock, 0))
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to create temporary index"));
old_repo_index_file = the_repository->index_file;
@@ -409,7 +396,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- if (interactive_add(argv, prefix, patch_interactive) != 0)
+ if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0)
die(_("interactive add failed"));
the_repository->index_file = old_repo_index_file;
@@ -419,13 +406,13 @@ static const char *prepare_index(const char **argv, const char *prefix,
unsetenv(INDEX_ENVIRONMENT);
FREE_AND_NULL(old_index_env);
- discard_index(&the_index);
- read_index_from(&the_index, get_lock_file_path(&index_lock),
- get_git_dir());
- if (cache_tree_update(&the_index, WRITE_TREE_SILENT) == 0) {
+ discard_index(the_repository->index);
+ read_index_from(the_repository->index, get_lock_file_path(&index_lock),
+ repo_get_git_dir(the_repository));
+ if (cache_tree_update(the_repository->index, WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
- if (write_locked_index(&the_index, &index_lock, 0))
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to update temporary index"));
} else
warning(_("Failed to update main cache tree"));
@@ -448,16 +435,21 @@ static const char *prepare_index(const char **argv, const char *prefix,
* (B) on failure, rollback the real index.
*/
if (all || (also && pathspec.nr)) {
+ char *ps_matched = xcalloc(pathspec.nr, 1);
repo_hold_locked_index(the_repository, &index_lock,
LOCK_DIE_ON_ERROR);
add_files_to_cache(the_repository, also ? prefix : NULL,
- &pathspec, 0, 0);
+ &pathspec, ps_matched, 0, 0);
+ if (!all && report_path_error(ps_matched, &pathspec))
+ exit(128);
+
refresh_cache_or_die(refresh_flags);
- cache_tree_update(&the_index, WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, 0))
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to write new index file"));
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
+ free(ps_matched);
goto out;
}
@@ -474,14 +466,14 @@ static const char *prepare_index(const char **argv, const char *prefix,
repo_hold_locked_index(the_repository, &index_lock,
LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
- if (the_index.cache_changed
- || !cache_tree_fully_valid(the_index.cache_tree))
- cache_tree_update(&the_index, WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock,
+ if (the_repository->index->cache_changed
+ || !cache_tree_fully_valid(the_repository->index->cache_tree))
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+ if (write_locked_index(the_repository->index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write new index file"));
commit_style = COMMIT_AS_IS;
- ret = get_index_file();
+ ret = repo_get_index_file(the_repository);
goto out;
}
@@ -518,15 +510,15 @@ static const char *prepare_index(const char **argv, const char *prefix,
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
exit(1);
- discard_index(&the_index);
+ discard_index(the_repository->index);
if (repo_read_index(the_repository) < 0)
die(_("cannot read the index"));
repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
add_remove_files(&partial);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
- cache_tree_update(&the_index, WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, 0))
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+ if (write_locked_index(the_repository->index, &index_lock, 0))
die(_("unable to write new index file"));
hold_lock_file_for_update(&false_lock,
@@ -536,14 +528,14 @@ static const char *prepare_index(const char **argv, const char *prefix,
create_base_index(current_head);
add_remove_files(&partial);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
- if (write_locked_index(&the_index, &false_lock, 0))
+ if (write_locked_index(the_repository->index, &false_lock, 0))
die(_("unable to write temporary index file"));
- discard_index(&the_index);
+ discard_index(the_repository->index);
ret = get_lock_file_path(&false_lock);
- read_index_from(&the_index, ret, get_git_dir());
+ read_index_from(the_repository->index, ret, repo_get_git_dir(the_repository));
out:
string_list_clear(&partial, 0);
clear_pathspec(&pathspec);
@@ -692,9 +684,12 @@ static void adjust_comment_line_char(const struct strbuf *sb)
char *candidate;
const char *p;
- comment_line_char = candidates[0];
- if (!memchr(sb->buf, comment_line_char, sb->len))
+ if (!memchr(sb->buf, candidates[0], sb->len)) {
+ free(comment_line_str_to_free);
+ comment_line_str = comment_line_str_to_free =
+ xstrfmt("%c", candidates[0]);
return;
+ }
p = sb->buf;
candidate = strchr(candidates, *p);
@@ -713,7 +708,8 @@ static void adjust_comment_line_char(const struct strbuf *sb)
if (!*p)
die(_("unable to select a comment character that is not used\n"
"in the current commit message"));
- comment_line_char = *p;
+ free(comment_line_str_to_free);
+ comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p);
}
static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
@@ -732,6 +728,13 @@ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
repo_unuse_commit_buffer(the_repository, commit, buffer);
}
+static void change_data_free(void *util, const char *str UNUSED)
+{
+ struct wt_status_change_data *d = util;
+ free(d->rename_source);
+ free(d);
+}
+
static int prepare_to_commit(const char *index_file, const char *prefix,
struct commit *current_head,
struct wt_status *s,
@@ -745,7 +748,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
const char *hook_arg2 = NULL;
int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
int old_display_comment_prefix;
- int merge_contains_scissors = 0;
int invoked_hook;
/* This checks and barfs if author is badly specified */
@@ -849,7 +851,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
wt_status_locate_end(sb.buf + merge_msg_start,
sb.len - merge_msg_start) <
sb.len - merge_msg_start)
- merge_contains_scissors = 1;
+ s->added_cut_line = 1;
} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
@@ -897,10 +899,10 @@ 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, NULL);
if (signoff)
- append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
+ append_signoff(&sb, ignored_log_message_bytes(sb.buf, sb.len), 0);
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
@@ -917,24 +919,23 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct ident_split ci, ai;
const char *hint_cleanup_all = allow_empty_message ?
_("Please enter the commit message for your changes."
- " Lines starting\nwith '%c' will be ignored.\n") :
+ " Lines starting\nwith '%s' will be ignored.\n") :
_("Please enter the commit message for your changes."
- " Lines starting\nwith '%c' will be ignored, and an empty"
+ " Lines starting\nwith '%s' will be ignored, and an empty"
" message aborts the commit.\n");
const char *hint_cleanup_space = allow_empty_message ?
_("Please enter the commit message for your changes."
" Lines starting\n"
- "with '%c' will be kept; you may remove them"
+ "with '%s' will be kept; you may remove them"
" yourself if you want to.\n") :
_("Please enter the commit message for your changes."
" Lines starting\n"
- "with '%c' will be kept; you may remove them"
+ "with '%s' will be kept; you may remove them"
" yourself if you want to.\n"
"An empty message aborts the commit.\n");
if (whence != FROM_COMMIT) {
- if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
- !merge_contains_scissors)
- wt_status_add_cut_line(s->fp);
+ if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+ wt_status_add_cut_line(s);
status_printf_ln(
s, GIT_COLOR_NORMAL,
whence == FROM_MERGE ?
@@ -952,12 +953,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
fprintf(s->fp, "\n");
if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
- status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_all, comment_line_char);
+ status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_all, comment_line_str);
else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
- if (whence == FROM_COMMIT && !merge_contains_scissors)
- wt_status_add_cut_line(s->fp);
+ if (whence == FROM_COMMIT)
+ wt_status_add_cut_line(s);
} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
- status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_space, comment_line_char);
+ status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_space, comment_line_str);
/*
* These should never fail because they come from our own
@@ -997,12 +998,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
s->use_color = 0;
committable = run_status(s->fp, index_file, prefix, 1, s);
s->use_color = saved_color_setting;
- string_list_clear(&s->change, 1);
+ string_list_clear_func(&s->change, change_data_free);
} else {
struct object_id oid;
const char *parent = "HEAD";
- if (!the_index.initialized && repo_read_index(the_repository) < 0)
+ if (!the_repository->index->initialized && repo_read_index(the_repository) < 0)
die(_("Cannot read index"));
if (amend)
@@ -1012,11 +1013,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int i, ita_nr = 0;
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++)
- if (ce_intent_to_add(the_index.cache[i]))
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++)
+ if (ce_intent_to_add(the_repository->index->cache[i]))
ita_nr++;
- committable = the_index.cache_nr - ita_nr > 0;
+ committable = the_repository->index->cache_nr - ita_nr > 0;
} else {
/*
* Unless the user did explicitly request a submodule
@@ -1041,14 +1042,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
fclose(s->fp);
if (trailer_args.nr) {
- struct child_process run_trailer = CHILD_PROCESS_INIT;
-
- strvec_pushl(&run_trailer.args, "interpret-trailers",
- "--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))
+ if (amend_file_with_trailers(git_path_commit_editmsg(), &trailer_args))
die(_("unable to pass trailers to --trailers"));
strvec_clear(&trailer_args);
}
@@ -1084,11 +1078,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
* and could have updated it. We must do this before we invoke
* the editor and after we invoke run_status above.
*/
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
- read_index_from(&the_index, index_file, get_git_dir());
+ read_index_from(the_repository->index, index_file, repo_get_git_dir(the_repository));
- if (cache_tree_update(&the_index, 0)) {
+ if (cache_tree_update(the_repository->index, 0)) {
error(_("Error building trees"));
return 0;
}
@@ -1166,22 +1160,45 @@ static void handle_ignored_arg(struct wt_status *s)
die(_("Invalid ignored mode '%s'"), ignored_arg);
}
-static void handle_untracked_files_arg(struct wt_status *s)
+static enum untracked_status_type parse_untracked_setting_name(const char *u)
{
- if (!untracked_files_arg)
- ; /* default already initialized */
- else if (!strcmp(untracked_files_arg, "no"))
- s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
- else if (!strcmp(untracked_files_arg, "normal"))
- s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
- else if (!strcmp(untracked_files_arg, "all"))
- s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
/*
* Please update $__git_untracked_file_modes in
* git-completion.bash when you add new options
*/
+ switch (git_parse_maybe_bool(u)) {
+ case 0:
+ u = "no";
+ break;
+ case 1:
+ u = "normal";
+ break;
+ default:
+ break;
+ }
+
+ if (!strcmp(u, "no"))
+ return SHOW_NO_UNTRACKED_FILES;
+ else if (!strcmp(u, "normal"))
+ return SHOW_NORMAL_UNTRACKED_FILES;
+ else if (!strcmp(u, "all"))
+ return SHOW_ALL_UNTRACKED_FILES;
else
- die(_("Invalid untracked files mode '%s'"), untracked_files_arg);
+ return SHOW_UNTRACKED_FILES_ERROR;
+}
+
+static void handle_untracked_files_arg(struct wt_status *s)
+{
+ enum untracked_status_type u;
+
+ if (!untracked_files_arg)
+ return; /* default already initialized */
+
+ u = parse_untracked_setting_name(untracked_files_arg);
+ if (u == SHOW_UNTRACKED_FILES_ERROR)
+ die(_("Invalid untracked files mode '%s'"),
+ untracked_files_arg);
+ s->show_untracked_files = u;
}
static const char *read_commit_message(const char *name)
@@ -1304,7 +1321,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
!!use_message, "-C",
!!logfile, "-F");
if (use_message || edit_message || logfile ||fixup_message || have_option_m)
- template_file = NULL;
+ FREE_AND_NULL(template_file);
if (edit_message)
use_message = edit_message;
if (amend && !use_message && !fixup_message)
@@ -1370,8 +1387,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (0 <= edit_flag)
use_editor = edit_flag;
- cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
-
handle_untracked_files_arg(s);
if (all && argc > 0)
@@ -1464,16 +1479,12 @@ static int git_status_config(const char *k, const char *v,
return 0;
}
if (!strcmp(k, "status.showuntrackedfiles")) {
- if (!v)
- return config_error_nonbool(k);
- else if (!strcmp(v, "no"))
- s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
- else if (!strcmp(v, "normal"))
- s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
- else if (!strcmp(v, "all"))
- s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
- else
+ enum untracked_status_type u;
+
+ u = parse_untracked_setting_name(v);
+ if (u == SHOW_UNTRACKED_FILES_ERROR)
return error(_("Invalid untracked files mode '%s'"), v);
+ s->show_untracked_files = u;
return 0;
}
if (!strcmp(k, "diff.renamelimit")) {
@@ -1497,7 +1508,10 @@ static int git_status_config(const char *k, const char *v,
return git_diff_ui_config(k, v, ctx, NULL);
}
-int cmd_status(int argc, const char **argv, const char *prefix)
+int cmd_status(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
{
static int no_renames = -1;
static const char *rename_score_arg = (const char *)-1;
@@ -1570,7 +1584,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
status_format != STATUS_FORMAT_PORCELAIN_V2)
progress_flag = REFRESH_PROGRESS;
repo_read_index(the_repository);
- refresh_index(&the_index,
+ refresh_index(the_repository->index,
REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
&s.pathspec, NULL, NULL);
@@ -1620,8 +1634,10 @@ static int git_commit_config(const char *k, const char *v,
include_status = git_config_bool(k, v);
return 0;
}
- if (!strcmp(k, "commit.cleanup"))
- return git_config_string(&cleanup_arg, k, v);
+ if (!strcmp(k, "commit.cleanup")) {
+ FREE_AND_NULL(cleanup_config);
+ return git_config_string(&cleanup_config, k, v);
+ }
if (!strcmp(k, "commit.gpgsign")) {
sign_commit = git_config_bool(k, v) ? "" : NULL;
return 0;
@@ -1636,9 +1652,13 @@ static int git_commit_config(const char *k, const char *v,
return git_status_config(k, v, ctx, s);
}
-int cmd_commit(int argc, const char **argv, const char *prefix)
+int cmd_commit(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
static struct wt_status s;
+ static const char *cleanup_arg = NULL;
static struct option builtin_commit_options[] = {
OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
OPT__VERBOSE(&verbose, N_("show diff in commit message template")),
@@ -1657,7 +1677,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
- OPT_CALLBACK_F(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer),
+ OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG),
OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
@@ -1738,6 +1758,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (verbose == -1)
verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose;
+ if (cleanup_arg) {
+ free(cleanup_config);
+ cleanup_config = xstrdup(cleanup_arg);
+ }
+ cleanup_mode = get_cleanup_mode(cleanup_config, use_editor);
+
if (dry_run)
return dry_run_commit(argv, prefix, current_head, &s);
index_file = prepare_index(argv, prefix, current_head, 0);
@@ -1840,13 +1866,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
append_merge_tag_headers(parents, &tail);
}
- if (commit_tree_extended(sb.buf, sb.len, &the_index.cache_tree->oid,
+ if (commit_tree_extended(sb.buf, sb.len, &the_repository->index->cache_tree->oid,
parents, &oid, author_ident.buf, NULL,
sign_commit, extra)) {
rollback_index_files();
die(_("failed to write commit object"));
}
- free_commit_extra_headers(extra);
if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
&err)) {
@@ -1869,8 +1894,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
repo_rerere(the_repository, 0);
run_auto_maintenance(quiet);
- run_commit_hook(use_editor, get_index_file(), NULL, "post-commit",
- NULL);
+ run_commit_hook(use_editor, repo_get_index_file(the_repository),
+ NULL, "post-commit", NULL);
if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
}
@@ -1885,11 +1910,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
&oid, flags);
}
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
cleanup:
+ free_commit_extra_headers(extra);
+ free_commit_list(parents);
strbuf_release(&author_ident);
strbuf_release(&err);
strbuf_release(&sb);
+ free(logfile);
+ free(template_file);
return ret;
}
diff --git a/builtin/config.c b/builtin/config.c
index 11a4d4ef14..cba7022108 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -1,10 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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"
@@ -16,58 +16,112 @@
#include "worktree.h"
static const char *const builtin_config_usage[] = {
- N_("git config [<options>]"),
+ N_("git config list [<file-option>] [<display-option>] [--includes]"),
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
+ N_("git config rename-section [<file-option>] <old-name> <new-name>"),
+ N_("git config remove-section [<file-option>] <name>"),
+ N_("git config edit [<file-option>]"),
+ N_("git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"),
NULL
};
-static char *key;
-static regex_t *key_regexp;
-static const char *value_pattern;
-static regex_t *regexp;
-static int show_keys;
-static int omit_values;
-static int use_key_regexp;
-static int do_all;
-static int do_not_match;
-static char delim = '=';
-static char key_delim = ' ';
-static char term = '\n';
-
-static int use_global_config, use_system_config, use_local_config;
-static int use_worktree_config;
-static struct git_config_source given_config_source;
-static int actions, type;
-static char *default_value;
-static int end_nul;
-static int respect_includes_opt = -1;
-static struct config_options config_options;
-static int show_origin;
-static int show_scope;
-static int fixed_value;
-
-#define ACTION_GET (1<<0)
-#define ACTION_GET_ALL (1<<1)
-#define ACTION_GET_REGEXP (1<<2)
-#define ACTION_REPLACE_ALL (1<<3)
-#define ACTION_ADD (1<<4)
-#define ACTION_UNSET (1<<5)
-#define ACTION_UNSET_ALL (1<<6)
-#define ACTION_RENAME_SECTION (1<<7)
-#define ACTION_REMOVE_SECTION (1<<8)
-#define ACTION_LIST (1<<9)
-#define ACTION_EDIT (1<<10)
-#define ACTION_SET (1<<11)
-#define ACTION_SET_ALL (1<<12)
-#define ACTION_GET_COLOR (1<<13)
-#define ACTION_GET_COLORBOOL (1<<14)
-#define ACTION_GET_URLMATCH (1<<15)
-
-/*
- * The actions "ACTION_LIST | ACTION_GET_*" which may produce more than
- * one line of output and which should therefore be paged.
- */
-#define PAGING_ACTIONS (ACTION_LIST | ACTION_GET_ALL | \
- ACTION_GET_REGEXP | ACTION_GET_URLMATCH)
+static const char *const builtin_config_list_usage[] = {
+ N_("git config list [<file-option>] [<display-option>] [--includes]"),
+ NULL
+};
+
+static const char *const builtin_config_get_usage[] = {
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ NULL
+};
+
+static const char *const builtin_config_set_usage[] = {
+ N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ NULL
+};
+
+static const char *const builtin_config_unset_usage[] = {
+ N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
+ NULL
+};
+
+static const char *const builtin_config_rename_section_usage[] = {
+ N_("git config rename-section [<file-option>] <old-name> <new-name>"),
+ NULL
+};
+
+static const char *const builtin_config_remove_section_usage[] = {
+ N_("git config remove-section [<file-option>] <name>"),
+ NULL
+};
+
+static const char *const builtin_config_edit_usage[] = {
+ N_("git config edit [<file-option>]"),
+ NULL
+};
+
+#define CONFIG_LOCATION_OPTIONS(opts) \
+ OPT_GROUP(N_("Config file location")), \
+ OPT_BOOL(0, "global", &opts.use_global_config, N_("use global config file")), \
+ OPT_BOOL(0, "system", &opts.use_system_config, N_("use system config file")), \
+ OPT_BOOL(0, "local", &opts.use_local_config, N_("use repository config file")), \
+ OPT_BOOL(0, "worktree", &opts.use_worktree_config, N_("use per-worktree config file")), \
+ OPT_STRING('f', "file", &opts.source.file, N_("file"), N_("use given config file")), \
+ OPT_STRING(0, "blob", &opts.source.blob, N_("blob-id"), N_("read config from given blob object"))
+
+struct config_location_options {
+ struct git_config_source source;
+ struct config_options options;
+ char *file_to_free;
+ int use_global_config;
+ int use_system_config;
+ int use_local_config;
+ int use_worktree_config;
+ int respect_includes_opt;
+};
+#define CONFIG_LOCATION_OPTIONS_INIT { \
+ .respect_includes_opt = -1, \
+}
+
+#define CONFIG_TYPE_OPTIONS(type) \
+ OPT_GROUP(N_("Type")), \
+ OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
+ OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), \
+ OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), \
+ OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), \
+ OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), \
+ OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH), \
+ OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE)
+
+#define CONFIG_DISPLAY_OPTIONS(opts) \
+ OPT_GROUP(N_("Display options")), \
+ OPT_BOOL('z', "null", &opts.end_nul, N_("terminate values with NUL byte")), \
+ OPT_BOOL(0, "name-only", &opts.omit_values, N_("show variable names only")), \
+ OPT_BOOL(0, "show-origin", &opts.show_origin, N_("show origin of config (file, standard input, blob, command line)")), \
+ OPT_BOOL(0, "show-scope", &opts.show_scope, N_("show scope of config (worktree, local, global, system, command)")), \
+ OPT_BOOL(0, "show-names", &opts.show_keys, N_("show config keys in addition to their values")), \
+ CONFIG_TYPE_OPTIONS(opts.type)
+
+struct config_display_options {
+ int end_nul;
+ int omit_values;
+ int show_origin;
+ int show_scope;
+ int show_keys;
+ int type;
+ char *default_value;
+ /* Populated via `display_options_init()`. */
+ int term;
+ int delim;
+ int key_delim;
+};
+#define CONFIG_DISPLAY_OPTIONS_INIT { \
+ .term = '\n', \
+ .delim = '=', \
+ .key_delim = ' ', \
+}
#define TYPE_BOOL 1
#define TYPE_INT 2
@@ -81,8 +135,6 @@ static int fixed_value;
{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
PARSE_OPT_NONEG, option_parse_type, (i) }
-static NORETURN void usage_builtin_config(void);
-
static int option_parse_type(const struct option *opt, const char *arg,
int unset)
{
@@ -127,60 +179,13 @@ static int option_parse_type(const struct option *opt, const char *arg,
* --type=int'.
*/
error(_("only one type at a time"));
- usage_builtin_config();
+ exit(129);
}
*to_type = new_type;
return 0;
}
-static struct option builtin_config_options[] = {
- OPT_GROUP(N_("Config file location")),
- OPT_BOOL(0, "global", &use_global_config, N_("use global config file")),
- OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
- OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")),
- OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")),
- OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
- OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
- OPT_GROUP(N_("Action")),
- OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET),
- OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL),
- OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP),
- OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
- OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL),
- OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
- OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-pattern]"), ACTION_UNSET),
- OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL),
- OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
- OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
- OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
- OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")),
- OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
- OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
- OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
- OPT_GROUP(N_("Type")),
- OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type),
- OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
- OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
- OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
- OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR),
- OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
- OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
- OPT_GROUP(N_("Other")),
- OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
- OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
- OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
- OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
- OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
- OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
- OPT_END(),
-};
-
-static NORETURN void usage_builtin_config(void)
-{
- usage_with_options(builtin_config_usage, builtin_config_options);
-}
-
static void check_argc(int argc, int min, int max)
{
if (argc >= min && argc <= max)
@@ -190,27 +195,29 @@ static void check_argc(int argc, int min, int max)
else
error(_("wrong number of arguments, should be from %d to %d"),
min, max);
- usage_builtin_config();
+ exit(129);
}
-static void show_config_origin(const struct key_value_info *kvi,
+static void show_config_origin(const struct config_display_options *opts,
+ const struct key_value_info *kvi,
struct strbuf *buf)
{
- const char term = end_nul ? '\0' : '\t';
+ const char term = opts->end_nul ? '\0' : '\t';
strbuf_addstr(buf, config_origin_type_name(kvi->origin_type));
strbuf_addch(buf, ':');
- if (end_nul)
+ if (opts->end_nul)
strbuf_addstr(buf, kvi->filename ? kvi->filename : "");
else
quote_c_style(kvi->filename ? kvi->filename : "", buf, NULL, 0);
strbuf_addch(buf, term);
}
-static void show_config_scope(const struct key_value_info *kvi,
+static void show_config_scope(const struct config_display_options *opts,
+ const struct key_value_info *kvi,
struct strbuf *buf)
{
- const char term = end_nul ? '\0' : '\t';
+ const char term = opts->end_nul ? '\0' : '\t';
const char *scope = config_scope_name(kvi->scope);
strbuf_addstr(buf, N_(scope));
@@ -219,24 +226,25 @@ static void show_config_scope(const struct key_value_info *kvi,
static int show_all_config(const char *key_, const char *value_,
const struct config_context *ctx,
- void *cb UNUSED)
+ void *cb)
{
+ const struct config_display_options *opts = cb;
const struct key_value_info *kvi = ctx->kvi;
- if (show_origin || show_scope) {
+ if (opts->show_origin || opts->show_scope) {
struct strbuf buf = STRBUF_INIT;
- if (show_scope)
- show_config_scope(kvi, &buf);
- if (show_origin)
- show_config_origin(kvi, &buf);
+ if (opts->show_scope)
+ show_config_scope(opts, kvi, &buf);
+ if (opts->show_origin)
+ show_config_origin(opts, 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);
}
- if (!omit_values && value_)
- printf("%s%c%s%c", key_, delim, value_, term);
+ if (!opts->omit_values && value_)
+ printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
else
- printf("%s%c", key_, term);
+ printf("%s%c", key_, opts->term);
return 0;
}
@@ -246,26 +254,27 @@ struct strbuf_list {
int alloc;
};
-static int format_config(struct strbuf *buf, const char *key_,
+static int format_config(const struct config_display_options *opts,
+ struct strbuf *buf, const char *key_,
const char *value_, const struct key_value_info *kvi)
{
- if (show_scope)
- show_config_scope(kvi, buf);
- if (show_origin)
- show_config_origin(kvi, buf);
- if (show_keys)
+ if (opts->show_scope)
+ show_config_scope(opts, kvi, buf);
+ if (opts->show_origin)
+ show_config_origin(opts, kvi, buf);
+ if (opts->show_keys)
strbuf_addstr(buf, key_);
- if (!omit_values) {
- if (show_keys)
- strbuf_addch(buf, key_delim);
+ if (!opts->omit_values) {
+ if (opts->show_keys)
+ strbuf_addch(buf, opts->key_delim);
- if (type == TYPE_INT)
+ if (opts->type == TYPE_INT)
strbuf_addf(buf, "%"PRId64,
git_config_int64(key_, value_ ? value_ : "", kvi));
- else if (type == TYPE_BOOL)
+ else if (opts->type == TYPE_BOOL)
strbuf_addstr(buf, git_config_bool(key_, value_) ?
"true" : "false");
- else if (type == TYPE_BOOL_OR_INT) {
+ else if (opts->type == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, kvi,
&is_bool);
@@ -273,24 +282,24 @@ static int format_config(struct strbuf *buf, const char *key_,
strbuf_addstr(buf, v ? "true" : "false");
else
strbuf_addf(buf, "%d", v);
- } else if (type == TYPE_BOOL_OR_STR) {
+ } else if (opts->type == TYPE_BOOL_OR_STR) {
int v = git_parse_maybe_bool(value_);
if (v < 0)
strbuf_addstr(buf, value_);
else
strbuf_addstr(buf, v ? "true" : "false");
- } else if (type == TYPE_PATH) {
- const char *v;
+ } else if (opts->type == TYPE_PATH) {
+ char *v;
if (git_config_pathname(&v, key_, value_) < 0)
return -1;
strbuf_addstr(buf, v);
free((char *)v);
- } else if (type == TYPE_EXPIRY_DATE) {
+ } else if (opts->type == TYPE_EXPIRY_DATE) {
timestamp_t t;
if (git_config_expiry_date(&t, key_, value_) < 0)
return -1;
strbuf_addf(buf, "%"PRItime, t);
- } else if (type == TYPE_COLOR) {
+ } else if (opts->type == TYPE_COLOR) {
char v[COLOR_MAXLEN];
if (git_config_color(v, key_, value_) < 0)
return -1;
@@ -299,43 +308,73 @@ static int format_config(struct strbuf *buf, const char *key_,
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
- if (show_keys)
+ if (opts->show_keys)
strbuf_setlen(buf, buf->len - 1);
}
}
- strbuf_addch(buf, term);
+ strbuf_addch(buf, opts->term);
return 0;
}
+#define GET_VALUE_ALL (1 << 0)
+#define GET_VALUE_KEY_REGEXP (1 << 1)
+
+struct collect_config_data {
+ const struct config_display_options *display_opts;
+ struct strbuf_list *values;
+ const char *value_pattern;
+ const char *key;
+ regex_t *regexp;
+ regex_t *key_regexp;
+ int do_not_match;
+ unsigned get_value_flags;
+ unsigned flags;
+};
+
static int collect_config(const char *key_, const char *value_,
const struct config_context *ctx, void *cb)
{
- struct strbuf_list *values = cb;
+ struct collect_config_data *data = cb;
+ struct strbuf_list *values = data->values;
const struct key_value_info *kvi = ctx->kvi;
- if (!use_key_regexp && strcmp(key_, key))
+ if (!(data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
+ strcmp(key_, data->key))
return 0;
- if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+ if ((data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
+ regexec(data->key_regexp, key_, 0, NULL, 0))
return 0;
- if (fixed_value && strcmp(value_pattern, (value_?value_:"")))
+ if ((data->flags & CONFIG_FLAGS_FIXED_VALUE) &&
+ strcmp(data->value_pattern, (value_?value_:"")))
return 0;
- if (regexp != NULL &&
- (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
+ if (data->regexp &&
+ (data->do_not_match ^ !!regexec(data->regexp, (value_?value_:""), 0, NULL, 0)))
return 0;
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_, kvi);
+ return format_config(data->display_opts, &values->items[values->nr++],
+ key_, value_, kvi);
}
-static int get_value(const char *key_, const char *regex_, unsigned flags)
+static int get_value(const struct config_location_options *opts,
+ const struct config_display_options *display_opts,
+ const char *key_, const char *regex_,
+ unsigned get_value_flags, unsigned flags)
{
int ret = CONFIG_GENERIC_ERROR;
struct strbuf_list values = {NULL};
+ struct collect_config_data data = {
+ .display_opts = display_opts,
+ .values = &values,
+ .get_value_flags = get_value_flags,
+ .flags = flags,
+ };
+ char *key = NULL;
int i;
- if (use_key_regexp) {
+ if (get_value_flags & GET_VALUE_KEY_REGEXP) {
char *tl;
/*
@@ -352,10 +391,10 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
for (tl = key; *tl && *tl != '.'; tl++)
*tl = tolower(*tl);
- key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
- if (regcomp(key_regexp, key, REG_EXTENDED)) {
+ data.key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
+ if (regcomp(data.key_regexp, key, REG_EXTENDED)) {
error(_("invalid key pattern: %s"), key_);
- FREE_AND_NULL(key_regexp);
+ FREE_AND_NULL(data.key_regexp);
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
@@ -364,30 +403,32 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
ret = CONFIG_INVALID_KEY;
goto free_strings;
}
+
+ data.key = key;
}
if (regex_ && (flags & CONFIG_FLAGS_FIXED_VALUE))
- value_pattern = regex_;
+ data.value_pattern = regex_;
else if (regex_) {
if (regex_[0] == '!') {
- do_not_match = 1;
+ data.do_not_match = 1;
regex_++;
}
- regexp = (regex_t*)xmalloc(sizeof(regex_t));
- if (regcomp(regexp, regex_, REG_EXTENDED)) {
+ data.regexp = (regex_t*)xmalloc(sizeof(regex_t));
+ if (regcomp(data.regexp, regex_, REG_EXTENDED)) {
error(_("invalid pattern: %s"), regex_);
- FREE_AND_NULL(regexp);
+ FREE_AND_NULL(data.regexp);
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
}
- config_with_options(collect_config, &values,
- &given_config_source, the_repository,
- &config_options);
+ config_with_options(collect_config, &data,
+ &opts->source, the_repository,
+ &opts->options);
- if (!values.nr && default_value) {
+ if (!values.nr && display_opts->default_value) {
struct key_value_info kvi = KVI_INIT;
struct strbuf *item;
@@ -395,16 +436,17 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
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, &kvi) < 0)
+ if (format_config(display_opts, item, key_,
+ display_opts->default_value, &kvi) < 0)
die(_("failed to format default config value: %s"),
- default_value);
+ display_opts->default_value);
}
ret = !values.nr;
for (i = 0; i < values.nr; i++) {
struct strbuf *buf = values.items + i;
- if (do_all || i == values.nr - 1)
+ if ((get_value_flags & GET_VALUE_ALL) || i == values.nr - 1)
fwrite(buf->buf, 1, buf->len, stdout);
strbuf_release(buf);
}
@@ -412,20 +454,20 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
free_strings:
free(key);
- if (key_regexp) {
- regfree(key_regexp);
- free(key_regexp);
+ if (data.key_regexp) {
+ regfree(data.key_regexp);
+ free(data.key_regexp);
}
- if (regexp) {
- regfree(regexp);
- free(regexp);
+ if (data.regexp) {
+ regfree(data.regexp);
+ free(data.regexp);
}
return ret;
}
static char *normalize_value(const char *key, const char *value,
- struct key_value_info *kvi)
+ int type, struct key_value_info *kvi)
{
if (!value)
return NULL;
@@ -476,97 +518,113 @@ static char *normalize_value(const char *key, const char *value,
BUG("cannot normalize type %d", type);
}
-static int get_color_found;
-static const char *get_color_slot;
-static const char *get_colorbool_slot;
-static char parsed_color[COLOR_MAXLEN];
+struct get_color_config_data {
+ int get_color_found;
+ const char *get_color_slot;
+ 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)
+ void *cb)
{
- if (!strcmp(var, get_color_slot)) {
+ struct get_color_config_data *data = cb;
+
+ if (!strcmp(var, data->get_color_slot)) {
if (!value)
config_error_nonbool(var);
- if (color_parse(value, parsed_color) < 0)
+ if (color_parse(value, data->parsed_color) < 0)
return -1;
- get_color_found = 1;
+ data->get_color_found = 1;
}
return 0;
}
-static void get_color(const char *var, const char *def_color)
+static void get_color(const struct config_location_options *opts,
+ const char *var, const char *def_color)
{
- get_color_slot = var;
- get_color_found = 0;
- parsed_color[0] = '\0';
- config_with_options(git_get_color_config, NULL,
- &given_config_source, the_repository,
- &config_options);
-
- if (!get_color_found && def_color) {
- if (color_parse(def_color, parsed_color) < 0)
+ struct get_color_config_data data = {
+ .get_color_slot = var,
+ .parsed_color[0] = '\0',
+ };
+
+ config_with_options(git_get_color_config, &data,
+ &opts->source, the_repository,
+ &opts->options);
+
+ if (!data.get_color_found && def_color) {
+ if (color_parse(def_color, data.parsed_color) < 0)
die(_("unable to parse default color value"));
}
- fputs(parsed_color, stdout);
+ fputs(data.parsed_color, stdout);
}
-static int get_colorbool_found;
-static int get_diff_color_found;
-static int get_color_ui_found;
+struct get_colorbool_config_data {
+ int get_colorbool_found;
+ int get_diff_color_found;
+ int get_color_ui_found;
+ const char *get_colorbool_slot;
+};
+
static int git_get_colorbool_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
- void *data UNUSED)
+ void *cb)
{
- if (!strcmp(var, get_colorbool_slot))
- get_colorbool_found = git_config_colorbool(var, value);
+ struct get_colorbool_config_data *data = cb;
+
+ if (!strcmp(var, data->get_colorbool_slot))
+ data->get_colorbool_found = git_config_colorbool(var, value);
else if (!strcmp(var, "diff.color"))
- get_diff_color_found = git_config_colorbool(var, value);
+ data->get_diff_color_found = git_config_colorbool(var, value);
else if (!strcmp(var, "color.ui"))
- get_color_ui_found = git_config_colorbool(var, value);
+ data->get_color_ui_found = git_config_colorbool(var, value);
return 0;
}
-static int get_colorbool(const char *var, int print)
+static int get_colorbool(const struct config_location_options *opts,
+ const char *var, int print)
{
- get_colorbool_slot = var;
- get_colorbool_found = -1;
- get_diff_color_found = -1;
- get_color_ui_found = -1;
- config_with_options(git_get_colorbool_config, NULL,
- &given_config_source, the_repository,
- &config_options);
-
- if (get_colorbool_found < 0) {
- if (!strcmp(get_colorbool_slot, "color.diff"))
- get_colorbool_found = get_diff_color_found;
- if (get_colorbool_found < 0)
- get_colorbool_found = get_color_ui_found;
- }
-
- if (get_colorbool_found < 0)
+ struct get_colorbool_config_data data = {
+ .get_colorbool_slot = var,
+ .get_colorbool_found = -1,
+ .get_diff_color_found = -1,
+ .get_color_ui_found = -1,
+ };
+
+ config_with_options(git_get_colorbool_config, &data,
+ &opts->source, the_repository,
+ &opts->options);
+
+ if (data.get_colorbool_found < 0) {
+ if (!strcmp(data.get_colorbool_slot, "color.diff"))
+ data.get_colorbool_found = data.get_diff_color_found;
+ if (data.get_colorbool_found < 0)
+ data.get_colorbool_found = data.get_color_ui_found;
+ }
+
+ if (data.get_colorbool_found < 0)
/* default value if none found in config */
- get_colorbool_found = GIT_COLOR_AUTO;
+ data.get_colorbool_found = GIT_COLOR_AUTO;
- get_colorbool_found = want_color(get_colorbool_found);
+ data.get_colorbool_found = want_color(data.get_colorbool_found);
if (print) {
- printf("%s\n", get_colorbool_found ? "true" : "false");
+ printf("%s\n", data.get_colorbool_found ? "true" : "false");
return 0;
} else
- return get_colorbool_found ? 0 : 1;
+ return data.get_colorbool_found ? 0 : 1;
}
-static void check_write(void)
+static void check_write(const struct git_config_source *source)
{
- if (!given_config_source.file && !startup_info->have_repository)
+ if (!source->file && !startup_info->have_repository)
die(_("not in a git directory"));
- if (given_config_source.use_stdin)
+ if (source->use_stdin)
die(_("writing to stdin is not supported"));
- if (given_config_source.blob)
+ if (source->blob)
die(_("writing config blobs is not supported"));
}
@@ -603,10 +661,13 @@ static int urlmatch_collect_fn(const char *var, const char *value,
return 0;
}
-static int get_urlmatch(const char *var, const char *url)
+static int get_urlmatch(const struct config_location_options *opts,
+ const struct config_display_options *_display_opts,
+ const char *var, const char *url)
{
int ret;
char *section_tail;
+ struct config_display_options display_opts = *_display_opts;
struct string_list_item *item;
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
struct string_list values = STRING_LIST_INIT_DUP;
@@ -623,15 +684,15 @@ static int get_urlmatch(const char *var, const char *url)
if (section_tail) {
*section_tail = '\0';
config.key = section_tail + 1;
- show_keys = 0;
+ display_opts.show_keys = 0;
} else {
config.key = NULL;
- show_keys = 1;
+ display_opts.show_keys = 1;
}
config_with_options(urlmatch_config_entry, &config,
- &given_config_source, the_repository,
- &config_options);
+ &opts->source, the_repository,
+ &opts->options);
ret = !values.nr;
@@ -639,7 +700,7 @@ static int get_urlmatch(const char *var, const char *url)
struct urlmatch_current_candidate_value *matched = item->util;
struct strbuf buf = STRBUF_INIT;
- format_config(&buf, item->string,
+ format_config(&display_opts, &buf, item->string,
matched->value_is_null ? NULL : matched->value.buf,
&matched->kvi);
fwrite(buf.buf, 1, buf.len, stdout);
@@ -669,49 +730,39 @@ static char *default_user_config(void)
return strbuf_detach(&buf, NULL);
}
-int cmd_config(int argc, const char **argv, const char *prefix)
+static void location_options_init(struct config_location_options *opts,
+ const char *prefix)
{
- int nongit = !startup_info->have_repository;
- 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));
-
- argc = parse_options(argc, argv, prefix, builtin_config_options,
- builtin_config_usage,
- PARSE_OPT_STOP_AT_NON_OPTION);
+ if (!opts->source.file)
+ opts->source.file = opts->file_to_free =
+ xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
- if (use_global_config + use_system_config + use_local_config +
- use_worktree_config +
- !!given_config_source.file + !!given_config_source.blob > 1) {
+ if (opts->use_global_config + opts->use_system_config +
+ opts->use_local_config + opts->use_worktree_config +
+ !!opts->source.file + !!opts->source.blob > 1) {
error(_("only one config file at a time"));
- usage_builtin_config();
+ exit(129);
}
- if (nongit) {
- if (use_local_config)
+ if (!startup_info->have_repository) {
+ if (opts->use_local_config)
die(_("--local can only be used inside a git repository"));
- if (given_config_source.blob)
+ if (opts->source.blob)
die(_("--blob can only be used inside a git repository"));
- if (use_worktree_config)
+ if (opts->use_worktree_config)
die(_("--worktree can only be used inside a git repository"));
-
}
- if (given_config_source.file &&
- !strcmp(given_config_source.file, "-")) {
- given_config_source.file = NULL;
- given_config_source.use_stdin = 1;
- given_config_source.scope = CONFIG_SCOPE_COMMAND;
+ if (opts->source.file &&
+ !strcmp(opts->source.file, "-")) {
+ opts->source.file = NULL;
+ opts->source.use_stdin = 1;
+ opts->source.scope = CONFIG_SCOPE_COMMAND;
}
- if (use_global_config) {
- char *user_config, *xdg_config;
-
- git_global_config(&user_config, &xdg_config);
- if (!user_config)
+ if (opts->use_global_config) {
+ opts->source.file = opts->file_to_free = git_global_config();
+ if (!opts->source.file)
/*
* It is unknown if HOME/.gitconfig exists, so
* we do not know if we should write to XDG
@@ -719,28 +770,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
* is set and points at a sane location.
*/
die(_("$HOME not set"));
-
- given_config_source.scope = CONFIG_SCOPE_GLOBAL;
-
- if (access_or_warn(user_config, R_OK, 0) &&
- xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
- given_config_source.file = xdg_config;
- free(user_config);
- } else {
- given_config_source.file = user_config;
- free(xdg_config);
- }
- }
- else if (use_system_config) {
- given_config_source.file = git_system_config();
- given_config_source.scope = CONFIG_SCOPE_SYSTEM;
- } else if (use_local_config) {
- given_config_source.file = git_pathdup("config");
- given_config_source.scope = CONFIG_SCOPE_LOCAL;
- } else if (use_worktree_config) {
+ opts->source.scope = CONFIG_SCOPE_GLOBAL;
+ } else if (opts->use_system_config) {
+ opts->source.file = opts->file_to_free = git_system_config();
+ opts->source.scope = CONFIG_SCOPE_SYSTEM;
+ } else if (opts->use_local_config) {
+ opts->source.file = opts->file_to_free = git_pathdup("config");
+ opts->source.scope = CONFIG_SCOPE_LOCAL;
+ } else if (opts->use_worktree_config) {
struct worktree **worktrees = get_worktrees();
if (the_repository->repository_format_worktree_config)
- given_config_source.file = git_pathdup("config.worktree");
+ opts->source.file = opts->file_to_free =
+ git_pathdup("config.worktree");
else if (worktrees[0] && worktrees[1])
die(_("--worktree cannot be used with multiple "
"working trees unless the config\n"
@@ -748,71 +789,439 @@ int cmd_config(int argc, const char **argv, const char *prefix)
"Please read \"CONFIGURATION FILE\"\n"
"section in \"git help worktree\" for details"));
else
- given_config_source.file = git_pathdup("config");
- given_config_source.scope = CONFIG_SCOPE_LOCAL;
+ opts->source.file = opts->file_to_free =
+ git_pathdup("config");
+ opts->source.scope = CONFIG_SCOPE_LOCAL;
free_worktrees(worktrees);
- } else if (given_config_source.file) {
- if (!is_absolute_path(given_config_source.file) && prefix)
- given_config_source.file =
- prefix_filename(prefix, given_config_source.file);
- given_config_source.scope = CONFIG_SCOPE_COMMAND;
- } else if (given_config_source.blob) {
- given_config_source.scope = CONFIG_SCOPE_COMMAND;
+ } else if (opts->source.file) {
+ if (!is_absolute_path(opts->source.file) && prefix)
+ opts->source.file = opts->file_to_free =
+ prefix_filename(prefix, opts->source.file);
+ opts->source.scope = CONFIG_SCOPE_COMMAND;
+ } else if (opts->source.blob) {
+ opts->source.scope = CONFIG_SCOPE_COMMAND;
+ }
+
+ if (opts->respect_includes_opt == -1)
+ opts->options.respect_includes = !opts->source.file;
+ else
+ opts->options.respect_includes = opts->respect_includes_opt;
+ if (startup_info->have_repository) {
+ opts->options.commondir = repo_get_common_dir(the_repository);
+ opts->options.git_dir = repo_get_git_dir(the_repository);
+ }
+}
+
+static void location_options_release(struct config_location_options *opts)
+{
+ free(opts->file_to_free);
+}
+
+static void display_options_init(struct config_display_options *opts)
+{
+ if (opts->end_nul) {
+ opts->term = '\0';
+ opts->delim = '\n';
+ opts->key_delim = '\n';
+ }
+}
+
+static int cmd_config_list(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ CONFIG_DISPLAY_OPTIONS(display_opts),
+ OPT_GROUP(N_("Other")),
+ OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+ N_("respect include directives on lookup")),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_list_usage, 0);
+ check_argc(argc, 0, 0);
+
+ location_options_init(&location_opts, prefix);
+ display_options_init(&display_opts);
+
+ setup_auto_pager("config", 1);
+
+ if (config_with_options(show_all_config, &display_opts,
+ &location_opts.source, the_repository,
+ &location_opts.options) < 0) {
+ if (location_opts.source.file)
+ die_errno(_("unable to read config file '%s'"),
+ location_opts.source.file);
+ else
+ die(_("error processing config file(s)"));
}
+ location_options_release(&location_opts);
+ return 0;
+}
+
+static int cmd_config_get(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+ const char *value_pattern = NULL, *url = NULL;
+ int flags = 0;
+ unsigned get_value_flags = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_GROUP(N_("Filter options")),
+ OPT_BIT(0, "all", &get_value_flags, N_("return all values for multi-valued config options"), GET_VALUE_ALL),
+ OPT_BIT(0, "regexp", &get_value_flags, N_("interpret the name as a regular expression"), GET_VALUE_KEY_REGEXP),
+ OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_STRING(0, "url", &url, N_("URL"), N_("show config matching the given URL")),
+ CONFIG_DISPLAY_OPTIONS(display_opts),
+ OPT_GROUP(N_("Other")),
+ OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+ N_("respect include directives on lookup")),
+ OPT_STRING(0, "default", &display_opts.default_value,
+ N_("value"), N_("use default value when missing entry")),
+ OPT_END(),
+ };
+ int ret;
- if (respect_includes_opt == -1)
- config_options.respect_includes = !given_config_source.file;
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_get_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 1, 1);
+
+ if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+ die(_("--fixed-value only applies with 'value-pattern'"));
+ if (display_opts.default_value &&
+ ((get_value_flags & GET_VALUE_ALL) || url))
+ die(_("--default= cannot be used with --all or --url="));
+ if (url && ((get_value_flags & GET_VALUE_ALL) ||
+ (get_value_flags & GET_VALUE_KEY_REGEXP) ||
+ value_pattern))
+ die(_("--url= cannot be used with --all, --regexp or --value"));
+
+ location_options_init(&location_opts, prefix);
+ display_options_init(&display_opts);
+
+ setup_auto_pager("config", 1);
+
+ if (url)
+ ret = get_urlmatch(&location_opts, &display_opts, argv[0], url);
else
- config_options.respect_includes = respect_includes_opt;
- if (!nongit) {
- config_options.commondir = get_git_common_dir();
- config_options.git_dir = get_git_dir();
+ ret = get_value(&location_opts, &display_opts, argv[0], value_pattern,
+ get_value_flags, flags);
+
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_set(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ const char *value_pattern = NULL, *comment_arg = NULL;
+ char *comment = NULL;
+ int flags = 0, append = 0, type = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ CONFIG_TYPE_OPTIONS(type),
+ OPT_GROUP(N_("Filter")),
+ OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
+ OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_GROUP(N_("Other")),
+ OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
+ OPT_BOOL(0, "append", &append, N_("add a new line without altering any existing values")),
+ OPT_END(),
+ };
+ struct key_value_info default_kvi = KVI_INIT;
+ char *value;
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_set_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 2, 2);
+
+ if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+ die(_("--fixed-value only applies with --value=<pattern>"));
+ if (append && value_pattern)
+ die(_("--append cannot be used with --value=<pattern>"));
+ if (append)
+ value_pattern = CONFIG_REGEX_NONE;
+
+ comment = git_config_prepare_comment_string(comment_arg);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ value = normalize_value(argv[0], argv[1], type, &default_kvi);
+
+ if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) {
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], value, value_pattern,
+ comment, flags);
+ } else {
+ ret = git_config_set_in_file_gently(location_opts.source.file,
+ argv[0], comment, value);
+ if (ret == CONFIG_NOTHING_SET)
+ error(_("cannot overwrite multiple values with a single value\n"
+ " Use a regexp, --add or --replace-all to change %s."), argv[0]);
}
- if (end_nul) {
- term = '\0';
- delim = '\n';
- key_delim = '\n';
+ location_options_release(&location_opts);
+ free(comment);
+ free(value);
+ return ret;
+}
+
+static int cmd_config_unset(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ const char *value_pattern = NULL;
+ int flags = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_GROUP(N_("Filter")),
+ OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
+ OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_unset_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 1, 1);
+
+ if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+ die(_("--fixed-value only applies with 'value-pattern'"));
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], NULL, value_pattern,
+ NULL, flags);
+ else
+ ret = git_config_set_in_file_gently(location_opts.source.file, argv[0],
+ NULL, NULL);
+
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_rename_section(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_rename_section_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 2, 2);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], argv[1]);
+ if (ret < 0)
+ goto out;
+ else if (!ret)
+ die(_("no such section: %s"), argv[0]);
+ ret = 0;
+
+out:
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_remove_section(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_remove_section_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ check_argc(argc, 1, 1);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], NULL);
+ if (ret < 0)
+ goto out;
+ else if (!ret)
+ die(_("no such section: %s"), argv[0]);
+ ret = 0;
+
+out:
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int show_editor(struct config_location_options *opts)
+{
+ char *config_file;
+
+ if (!opts->source.file && !startup_info->have_repository)
+ die(_("not in a git directory"));
+ if (opts->source.use_stdin)
+ die(_("editing stdin is not supported"));
+ if (opts->source.blob)
+ die(_("editing blobs is not supported"));
+ git_config(git_default_config, NULL);
+ config_file = opts->source.file ?
+ xstrdup(opts->source.file) :
+ git_pathdup("config");
+ if (opts->use_global_config) {
+ int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd >= 0) {
+ char *content = default_user_config();
+ write_str_in_full(fd, content);
+ free(content);
+ close(fd);
+ }
+ else if (errno != EEXIST)
+ die_errno(_("cannot create configuration file %s"), config_file);
}
+ launch_editor(config_file, NULL, NULL);
+ free(config_file);
+
+ return 0;
+}
- if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
+static int cmd_config_edit(int argc, const char **argv, const char *prefix)
+{
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0);
+ check_argc(argc, 0, 0);
+
+ location_options_init(&location_opts, prefix);
+ check_write(&location_opts.source);
+
+ ret = show_editor(&location_opts);
+ location_options_release(&location_opts);
+ return ret;
+}
+
+static int cmd_config_actions(int argc, const char **argv, const char *prefix)
+{
+ enum {
+ ACTION_GET = (1<<0),
+ ACTION_GET_ALL = (1<<1),
+ ACTION_GET_REGEXP = (1<<2),
+ ACTION_REPLACE_ALL = (1<<3),
+ ACTION_ADD = (1<<4),
+ ACTION_UNSET = (1<<5),
+ ACTION_UNSET_ALL = (1<<6),
+ ACTION_RENAME_SECTION = (1<<7),
+ ACTION_REMOVE_SECTION = (1<<8),
+ ACTION_LIST = (1<<9),
+ ACTION_EDIT = (1<<10),
+ ACTION_SET = (1<<11),
+ ACTION_SET_ALL = (1<<12),
+ ACTION_GET_COLOR = (1<<13),
+ ACTION_GET_COLORBOOL = (1<<14),
+ ACTION_GET_URLMATCH = (1<<15),
+ };
+ struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+ struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+ const char *comment_arg = NULL;
+ int actions = 0;
+ unsigned flags = 0;
+ struct option opts[] = {
+ CONFIG_LOCATION_OPTIONS(location_opts),
+ OPT_GROUP(N_("Action")),
+ OPT_CMDMODE(0, "get", &actions, N_("get value: name [<value-pattern>]"), ACTION_GET),
+ OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key [<value-pattern>]"), ACTION_GET_ALL),
+ OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex [<value-pattern>]"), ACTION_GET_REGEXP),
+ OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
+ OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value [<value-pattern>]"), ACTION_REPLACE_ALL),
+ OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
+ OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name [<value-pattern>]"), ACTION_UNSET),
+ OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name [<value-pattern>]"), ACTION_UNSET_ALL),
+ OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
+ OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
+ OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST),
+ OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
+ OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot [<default>]"), ACTION_GET_COLOR),
+ OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL),
+ CONFIG_DISPLAY_OPTIONS(display_opts),
+ OPT_GROUP(N_("Other")),
+ OPT_STRING(0, "default", &display_opts.default_value,
+ N_("value"), N_("with --get, use default value when missing entry")),
+ OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
+ OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+ OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+ N_("respect include directives on lookup")),
+ OPT_END(),
+ };
+ char *value = NULL, *comment = NULL;
+ int ret = 0;
+ struct key_value_info default_kvi = KVI_INIT;
+
+ argc = parse_options(argc, argv, prefix, opts,
+ builtin_config_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ location_options_init(&location_opts, prefix);
+ display_options_init(&display_opts);
+
+ if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && display_opts.type) {
error(_("--get-color and variable type are incoherent"));
- usage_builtin_config();
+ exit(129);
}
- if (HAS_MULTI_BITS(actions)) {
- error(_("only one action at a time"));
- usage_builtin_config();
- }
if (actions == 0)
switch (argc) {
case 1: actions = ACTION_GET; break;
case 2: actions = ACTION_SET; break;
case 3: actions = ACTION_SET_ALL; break;
default:
- usage_builtin_config();
+ error(_("no action specified"));
+ exit(129);
}
- if (omit_values &&
+ if (display_opts.omit_values &&
!(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
error(_("--name-only is only applicable to --list or --get-regexp"));
- usage_builtin_config();
+ exit(129);
}
- if (show_origin && !(actions &
+ if (display_opts.show_origin && !(actions &
(ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
error(_("--show-origin is only applicable to --get, --get-all, "
"--get-regexp, and --list"));
- usage_builtin_config();
+ exit(129);
}
- if (default_value && !(actions & ACTION_GET)) {
+ if (display_opts.default_value && !(actions & ACTION_GET)) {
error(_("--default is only applicable to --get"));
- usage_builtin_config();
+ exit(129);
+ }
+
+ if (comment_arg &&
+ !(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) {
+ error(_("--comment is only applicable to add/set/replace operations"));
+ exit(129);
}
/* check usage of --fixed-value */
- if (fixed_value) {
+ if (flags & CONFIG_FLAGS_FIXED_VALUE) {
int allowed_usage = 0;
switch (actions) {
@@ -841,146 +1250,125 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (!allowed_usage) {
error(_("--fixed-value only applies with 'value-pattern'"));
- usage_builtin_config();
+ exit(129);
}
-
- flags |= CONFIG_FLAGS_FIXED_VALUE;
}
- if (actions & PAGING_ACTIONS)
+ comment = git_config_prepare_comment_string(comment_arg);
+
+ /*
+ * The following actions may produce more than one line of output and
+ * should therefore be paged.
+ */
+ if (actions & (ACTION_LIST | ACTION_GET_ALL | ACTION_GET_REGEXP | ACTION_GET_URLMATCH))
setup_auto_pager("config", 1);
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
- if (config_with_options(show_all_config, NULL,
- &given_config_source, the_repository,
- &config_options) < 0) {
- if (given_config_source.file)
+ if (config_with_options(show_all_config, &display_opts,
+ &location_opts.source, the_repository,
+ &location_opts.options) < 0) {
+ if (location_opts.source.file)
die_errno(_("unable to read config file '%s'"),
- given_config_source.file);
+ location_opts.source.file);
else
die(_("error processing config file(s)"));
}
}
else if (actions == ACTION_EDIT) {
- char *config_file;
-
- check_argc(argc, 0, 0);
- if (!given_config_source.file && nongit)
- die(_("not in a git directory"));
- if (given_config_source.use_stdin)
- die(_("editing stdin is not supported"));
- if (given_config_source.blob)
- die(_("editing blobs is not supported"));
- git_config(git_default_config, NULL);
- config_file = given_config_source.file ?
- xstrdup(given_config_source.file) :
- git_pathdup("config");
- if (use_global_config) {
- int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
- if (fd >= 0) {
- char *content = default_user_config();
- write_str_in_full(fd, content);
- free(content);
- close(fd);
- }
- else if (errno != EEXIST)
- die_errno(_("cannot create configuration file %s"), config_file);
- }
- launch_editor(config_file, NULL, NULL);
- free(config_file);
+ ret = show_editor(&location_opts);
}
else if (actions == ACTION_SET) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 2);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
}
else if (actions == ACTION_SET_ALL) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 3);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
argv[0], value, argv[2],
- flags);
+ comment, flags);
}
else if (actions == ACTION_ADD) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 2);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
argv[0], value,
CONFIG_REGEX_NONE,
- flags);
+ comment, flags);
}
else if (actions == ACTION_REPLACE_ALL) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 3);
- value = normalize_value(argv[0], argv[1], &default_kvi);
- ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
argv[0], value, argv[2],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1], flags);
+ ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+ 0, flags);
}
else if (actions == ACTION_GET_ALL) {
- do_all = 1;
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1], flags);
+ ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+ GET_VALUE_ALL, flags);
}
else if (actions == ACTION_GET_REGEXP) {
- show_keys = 1;
- use_key_regexp = 1;
- do_all = 1;
+ display_opts.show_keys = 1;
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1], flags);
+ ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+ GET_VALUE_ALL|GET_VALUE_KEY_REGEXP, flags);
}
else if (actions == ACTION_GET_URLMATCH) {
check_argc(argc, 2, 2);
- return get_urlmatch(argv[0], argv[1]);
+ ret = get_urlmatch(&location_opts, &display_opts, argv[0], argv[1]);
}
else if (actions == ACTION_UNSET) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 1, 2);
if (argc == 2)
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1],
- flags);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags);
else
- return git_config_set_in_file_gently(given_config_source.file,
- argv[0], NULL);
+ ret = git_config_set_in_file_gently(location_opts.source.file,
+ argv[0], NULL, NULL);
}
else if (actions == ACTION_UNSET_ALL) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 1, 2);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 2, 2);
- ret = git_config_rename_section_in_file(given_config_source.file,
- argv[0], argv[1]);
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], argv[1]);
if (ret < 0)
- return ret;
+ goto out;
else if (!ret)
die(_("no such section: %s"), argv[0]);
else
ret = 0;
}
else if (actions == ACTION_REMOVE_SECTION) {
- check_write();
+ check_write(&location_opts.source);
check_argc(argc, 1, 1);
- ret = git_config_rename_section_in_file(given_config_source.file,
- argv[0], NULL);
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], NULL);
if (ret < 0)
- return ret;
+ goto out;
else if (!ret)
die(_("no such section: %s"), argv[0]);
else
@@ -988,15 +1376,54 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
else if (actions == ACTION_GET_COLOR) {
check_argc(argc, 1, 2);
- get_color(argv[0], argv[1]);
+ get_color(&location_opts, argv[0], argv[1]);
}
else if (actions == ACTION_GET_COLORBOOL) {
check_argc(argc, 1, 2);
if (argc == 2)
color_stdout_is_tty = git_config_bool("command line", argv[1]);
- return get_colorbool(argv[0], argc == 2);
+ ret = get_colorbool(&location_opts, argv[0], argc == 2);
}
+out:
+ location_options_release(&location_opts);
+ free(comment);
free(value);
return ret;
}
+
+int cmd_config(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
+{
+ parse_opt_subcommand_fn *subcommand = NULL;
+ struct option subcommand_opts[] = {
+ OPT_SUBCOMMAND("list", &subcommand, cmd_config_list),
+ OPT_SUBCOMMAND("get", &subcommand, cmd_config_get),
+ OPT_SUBCOMMAND("set", &subcommand, cmd_config_set),
+ OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset),
+ OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section),
+ OPT_SUBCOMMAND("remove-section", &subcommand, cmd_config_remove_section),
+ OPT_SUBCOMMAND("edit", &subcommand, cmd_config_edit),
+ OPT_END(),
+ };
+
+ /*
+ * This is somewhat hacky: we first parse the command line while
+ * keeping all args intact in order to determine whether a subcommand
+ * has been specified. If so, we re-parse it a second time, but this
+ * time we drop KEEP_ARGV0. This is so that we don't munge the command
+ * line in case no subcommand was given, which would otherwise confuse
+ * us when parsing the legacy-style modes that don't use subcommands.
+ */
+ argc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT);
+ if (subcommand) {
+ argc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_UNKNOWN_OPT);
+ return subcommand(argc, argv, prefix);
+ }
+
+ return cmd_config_actions(argc, argv, prefix);
+}
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 2d4bb5e8d0..04d80887e0 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -3,14 +3,12 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "dir.h"
-#include "environment.h"
#include "gettext.h"
#include "path.h"
-#include "repository.h"
#include "parse-options.h"
#include "quote.h"
#include "packfile.h"
@@ -95,7 +93,10 @@ static char const * const count_objects_usage[] = {
NULL
};
-int cmd_count_objects(int argc, const char **argv, const char *prefix)
+int cmd_count_objects(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int human_readable = 0;
struct option opts[] = {
@@ -113,10 +114,10 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
usage_with_options(count_objects_usage, opts);
if (verbose) {
report_garbage = real_report_garbage;
- report_linked_checkout_garbage();
+ report_linked_checkout_garbage(the_repository);
}
- for_each_loose_file_in_objdir(get_object_directory(),
+ for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
count_loose, count_cruft, NULL, NULL);
if (verbose) {
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 3a6a750a8e..bc22f5c6d2 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "gettext.h"
@@ -115,7 +116,9 @@ static int read_request(FILE *fh, struct credential *c,
return error("client sent bogus timeout line: %s", item.buf);
*timeout = atoi(p);
- if (credential_read(c, fh) < 0)
+ credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL);
+
+ if (credential_read(c, fh, CREDENTIAL_OP_HELPER) < 0)
return -1;
return 0;
}
@@ -131,8 +134,18 @@ static void serve_one_client(FILE *in, FILE *out)
else if (!strcmp(action.buf, "get")) {
struct credential_cache_entry *e = lookup_credential(&c);
if (e) {
- fprintf(out, "username=%s\n", e->item.username);
- fprintf(out, "password=%s\n", e->item.password);
+ e->item.capa_authtype.request_initial = 1;
+ e->item.capa_authtype.request_helper = 1;
+
+ fprintf(out, "capability[]=authtype\n");
+ if (e->item.username)
+ fprintf(out, "username=%s\n", e->item.username);
+ if (e->item.password)
+ fprintf(out, "password=%s\n", e->item.password);
+ if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.authtype)
+ fprintf(out, "authtype=%s\n", e->item.authtype);
+ if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.credential)
+ fprintf(out, "credential=%s\n", e->item.credential);
if (e->item.password_expiry_utc != TIME_MAX)
fprintf(out, "password_expiry_utc=%"PRItime"\n",
e->item.password_expiry_utc);
@@ -157,8 +170,10 @@ static void serve_one_client(FILE *in, FILE *out)
else if (!strcmp(action.buf, "store")) {
if (timeout < 0)
warning("cache client didn't specify a timeout");
- else if (!c.username || !c.password)
+ else if ((!c.username || !c.password) && (!c.authtype && !c.credential))
warning("cache client gave us a partial credential");
+ else if (c.ephemeral)
+ warning("not storing ephemeral credential");
else {
remove_credential(&c, 0);
cache_credential(&c, timeout);
@@ -273,7 +288,10 @@ static void init_socket_directory(const char *path)
free(path_copy);
}
-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache_daemon(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct tempfile *socket_file;
const char *socket_path;
@@ -294,6 +312,8 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, usage, 0);
socket_path = argv[0];
+ if (!have_unix_sockets())
+ die(_("credential-cache--daemon unavailable; no unix socket support"));
if (!socket_path)
usage_with_options(usage, options);
@@ -314,7 +334,10 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
#else
-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache_daemon(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
{
const char * const usage[] = {
"git credential-cache--daemon [--debug] <socket-path>",
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 43b9d0e5b1..7f733cb756 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "credential.h"
#include "gettext.h"
#include "parse-options.h"
#include "path.h"
@@ -7,8 +8,6 @@
#ifndef NO_UNIX_SOCKETS
-#include "credential.h"
-#include "string-list.h"
#include "unix-socket.h"
#include "run-command.h"
@@ -31,7 +30,7 @@ static int connection_fatally_broken(int error)
static int connection_closed(int error)
{
- return (error == ECONNRESET);
+ return error == ECONNRESET || error == ECONNABORTED;
}
static int connection_fatally_broken(int error)
@@ -89,6 +88,8 @@ static void spawn_daemon(const char *socket)
die_errno("unable to read result code from cache daemon");
if (r != 3 || memcmp(buf, "ok\n", 3))
die("cache daemon did not start: %.*s", r, buf);
+
+ child_process_clear(&daemon);
close(daemon.out);
}
@@ -129,9 +130,20 @@ static char *get_socket_path(void)
return socket;
}
-int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+static void announce_capabilities(void)
{
- char *socket_path = NULL;
+ struct credential c = CREDENTIAL_INIT;
+ c.capa_authtype.request_initial = 1;
+ credential_announce_capabilities(&c, stdout);
+}
+
+int cmd_credential_cache(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
+{
+ const char *socket_path_arg = NULL;
+ char *socket_path;
int timeout = 900;
const char *op;
const char * const usage[] = {
@@ -141,7 +153,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_INTEGER(0, "timeout", &timeout,
"number of seconds to cache credentials"),
- OPT_STRING(0, "socket", &socket_path, "path",
+ OPT_STRING(0, "socket", &socket_path_arg, "path",
"path of cache-daemon socket"),
OPT_END()
};
@@ -151,6 +163,10 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
op = argv[0];
+ if (!have_unix_sockets())
+ die(_("credential-cache unavailable; no unix socket support"));
+
+ socket_path = xstrdup_or_null(socket_path_arg);
if (!socket_path)
socket_path = get_socket_path();
if (!socket_path)
@@ -162,15 +178,19 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
do_cache(socket_path, op, timeout, FLAG_RELAY);
else if (!strcmp(op, "store"))
do_cache(socket_path, op, timeout, FLAG_RELAY|FLAG_SPAWN);
+ else if (!strcmp(op, "capability"))
+ announce_capabilities();
else
; /* ignore unknown operation */
+ free(socket_path);
return 0;
}
#else
-int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache(int argc, const char **argv, const char *prefix,
+ struct repository *repo UNUSED)
{
const char * const usage[] = {
"git credential-cache [options] <action>",
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index 4a492411bb..e669e99dbf 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -170,7 +171,10 @@ static void lookup_credential(const struct string_list *fns, struct credential *
return; /* Found credential */
}
-int cmd_credential_store(int argc, const char **argv, const char *prefix)
+int cmd_credential_store(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char * const usage[] = {
"git credential-store [<options>] <action>",
@@ -205,7 +209,7 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix)
if (!fns.nr)
die("unable to set up default path; use --file");
- if (credential_read(&c, stdin) < 0)
+ if (credential_read(&c, stdin, CREDENTIAL_OP_HELPER) < 0)
die("unable to read credential");
if (!strcmp(op, "get"))
@@ -218,5 +222,6 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix)
; /* Ignore unknown operation. */
string_list_clear(&fns, 0);
+ credential_clear(&c);
return 0;
}
diff --git a/builtin/credential.c b/builtin/credential.c
index 7010752987..14c8c6608b 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "credential.h"
#include "builtin.h"
@@ -6,7 +8,10 @@
static const char usage_msg[] =
"git credential (fill|approve|reject)";
-int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_credential(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
const char *op;
struct credential c = CREDENTIAL_INIT;
@@ -17,18 +22,29 @@ int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
usage(usage_msg);
op = argv[1];
- if (credential_read(&c, stdin) < 0)
+ if (!strcmp(op, "capability")) {
+ credential_set_all_capabilities(&c, CREDENTIAL_OP_INITIAL);
+ credential_announce_capabilities(&c, stdout);
+ return 0;
+ }
+
+ if (credential_read(&c, stdin, CREDENTIAL_OP_INITIAL) < 0)
die("unable to read credential from stdin");
if (!strcmp(op, "fill")) {
- credential_fill(&c);
- credential_write(&c, stdout);
+ credential_fill(&c, 0);
+ credential_next_state(&c);
+ credential_write(&c, stdout, CREDENTIAL_OP_RESPONSE);
} else if (!strcmp(op, "approve")) {
+ credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
credential_approve(&c);
} else if (!strcmp(op, "reject")) {
+ credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
credential_reject(&c);
} else {
usage(usage_msg);
}
+
+ credential_clear(&c);
return 0;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index a9e375882b..7330a77b38 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "environment.h"
@@ -7,9 +7,7 @@
#include "lockfile.h"
#include "commit.h"
#include "tag.h"
-#include "blob.h"
#include "refs.h"
-#include "exec-cmd.h"
#include "object-name.h"
#include "parse-options.h"
#include "read-cache-ll.h"
@@ -56,6 +54,10 @@ static const char *diff_index_args[] = {
"diff-index", "--quiet", "HEAD", "--", NULL
};
+static const char *update_index_args[] = {
+ "update-index", "--unmerged", "-q", "--refresh", NULL
+};
+
struct commit_name {
struct hashmap_entry entry;
struct object_id peeled;
@@ -148,7 +150,7 @@ static void add_to_known_names(const char *path,
}
}
-static int get_name(const char *path, const struct object_id *oid,
+static int get_name(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
int is_tag = 0;
@@ -203,7 +205,7 @@ static int get_name(const char *path, const struct object_id *oid,
}
/* Is it annotated? */
- if (!peel_iterated_oid(oid, &peeled)) {
+ if (!peel_iterated_oid(the_repository, oid, &peeled)) {
is_annotated = !oideq(oid, &peeled);
} else {
oidcpy(&peeled, oid);
@@ -528,6 +530,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)
traverse_commit_list(&revs, process_commit, process_object, &pcd);
reset_revision_walk();
release_revisions(&revs);
+ strvec_clear(&args);
}
static void describe(const char *arg, int last_one)
@@ -561,13 +564,18 @@ static void describe(const char *arg, int last_one)
static int option_parse_exact_match(const struct option *opt, const char *arg,
int unset)
{
+ int *val = opt->value;
+
BUG_ON_OPT_ARG(arg);
- max_candidates = unset ? DEFAULT_CANDIDATES : 0;
+ *val = unset ? DEFAULT_CANDIDATES : 0;
return 0;
}
-int cmd_describe(int argc, const char **argv, const char *prefix)
+int cmd_describe(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED )
{
int contains = 0;
struct option options[] = {
@@ -578,7 +586,7 @@ 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_CALLBACK_F(0, "exact-match", NULL, NULL,
+ OPT_CALLBACK_F(0, "exact-match", &max_candidates, NULL,
N_("only output exact matches"),
PARSE_OPT_NOARG, option_parse_exact_match),
OPT_INTEGER(0, "candidates", &max_candidates,
@@ -616,6 +624,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
if (contains) {
struct string_list_item *item;
struct strvec args;
+ const char **argv_copy;
+ int ret;
strvec_init(&args);
strvec_pushl(&args, "name-rev",
@@ -634,17 +644,40 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
strvec_pushv(&args, argv);
else
strvec_push(&args, "HEAD");
- return cmd_name_rev(args.nr, args.v, prefix);
+
+ /*
+ * `cmd_name_rev()` modifies the array, so we'd leak its
+ * contained strings if we didn't do a copy here.
+ */
+ ALLOC_ARRAY(argv_copy, args.nr + 1);
+ for (size_t i = 0; i < args.nr; i++)
+ argv_copy[i] = args.v[i];
+ argv_copy[args.nr] = NULL;
+
+ ret = cmd_name_rev(args.nr, argv_copy, prefix, the_repository);
+
+ strvec_clear(&args);
+ free(argv_copy);
+ return ret;
}
hashmap_init(&names, commit_name_neq, NULL, 0);
- for_each_rawref(get_name, NULL);
+ refs_for_each_rawref(get_main_ref_store(the_repository), get_name,
+ NULL);
if (!hashmap_get_size(&names) && !always)
die(_("No names found, cannot describe anything."));
if (argc == 0) {
if (broken) {
struct child_process cp = CHILD_PROCESS_INIT;
+
+ strvec_pushv(&cp.args, update_index_args);
+ cp.git_cmd = 1;
+ cp.no_stdin = 1;
+ cp.no_stdout = 1;
+ run_command(&cp);
+
+ child_process_init(&cp);
strvec_pushv(&cp.args, diff_index_args);
cp.git_cmd = 1;
cp.no_stdin = 1;
@@ -667,14 +700,13 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
} else if (dirty) {
struct lock_file index_lock = LOCK_INIT;
struct rev_info revs;
- struct strvec args = STRVEC_INIT;
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,
+ refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED,
NULL, NULL, NULL);
fd = repo_hold_locked_index(the_repository,
&index_lock, 0);
@@ -682,12 +714,13 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
repo_update_index_if_able(the_repository, &index_lock);
repo_init_revisions(the_repository, &revs, prefix);
- strvec_pushv(&args, diff_index_args);
- if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
+
+ if (setup_revisions(ARRAY_SIZE(diff_index_args) - 1,
+ diff_index_args, &revs, NULL) != 1)
BUG("malformed internal diff-index command line");
run_diff_index(&revs, 0);
- if (!diff_result_code(&revs.diffopt))
+ if (!diff_result_code(&revs))
suffix = NULL;
else
suffix = dirty;
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index 4f22eb2b55..66a22d918e 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -11,14 +11,17 @@ static const char * const diagnose_usage[] = {
NULL
};
-int cmd_diagnose(int argc, const char **argv, const char *prefix)
+int cmd_diagnose(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct strbuf zip_path = STRBUF_INIT;
time_t now = time(NULL);
struct tm tm;
enum diagnose_mode mode = DIAGNOSE_STATS;
char *option_output = NULL;
- char *option_suffix = "%Y-%m-%d-%H%M";
+ const char *option_suffix = "%Y-%m-%d-%H%M";
char *prefixed_filename;
const struct option diagnose_options[] = {
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index f38912cd40..e0e0ccec23 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -3,22 +3,24 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#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 "submodule.h"
static const char diff_files_usage[] =
"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
"\n"
COMMON_DIFF_OPTIONS_HELP;
-int cmd_diff_files(int argc, const char **argv, const char *prefix)
+int cmd_diff_files(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info rev;
int result;
@@ -83,7 +85,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
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);
+ result = diff_result_code(&rev);
release_revisions(&rev);
return result;
}
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 220f341ffa..ad503624c0 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -1,14 +1,12 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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 "setup.h"
-#include "sparse-index.h"
-#include "submodule.h"
static const char diff_cache_usage[] =
"git diff-index [-m] [--cached] [--merge-base] "
@@ -16,7 +14,10 @@ static const char diff_cache_usage[] =
"\n"
COMMON_DIFF_OPTIONS_HELP;
-int cmd_diff_index(int argc, const char **argv, const char *prefix)
+int cmd_diff_index(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info rev;
unsigned int option = 0;
@@ -27,6 +28,10 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
usage(diff_cache_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;
prefix = precompose_argv_prefix(argc, argv, prefix);
@@ -73,7 +78,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
return -1;
}
run_diff_index(&rev, option);
- result = diff_result_code(&rev.diffopt);
+ result = diff_result_code(&rev);
release_revisions(&rev);
return result;
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 86be634286..4b6656bb9f 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "diff.h"
@@ -6,10 +6,9 @@
#include "gettext.h"
#include "hex.h"
#include "log-tree.h"
-#include "submodule.h"
#include "read-cache-ll.h"
-#include "repository.h"
#include "revision.h"
+#include "tmp-objdir.h"
#include "tree.h"
static struct rev_info log_tree_opt;
@@ -109,7 +108,10 @@ static void diff_tree_tweak_rev(struct rev_info *rev)
}
}
-int cmd_diff_tree(int argc, const char **argv, const char *prefix)
+int cmd_diff_tree(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
char line[1000];
struct object *tree1, *tree2;
@@ -207,7 +209,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
opt->diffopt.rotate_to_strict = 0;
opt->diffopt.no_free = 1;
if (opt->diffopt.detect_rename) {
- if (!the_index.cache)
+ if (the_repository->index->cache)
repo_read_index(the_repository);
opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE;
}
@@ -232,5 +234,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
diff_free(&opt->diffopt);
}
- return diff_result_code(&opt->diffopt);
+ return diff_result_code(opt);
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 0b313549c7..2fe92f373e 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -3,14 +3,13 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#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"
@@ -21,7 +20,6 @@
#include "revision.h"
#include "log-tree.h"
#include "setup.h"
-#include "submodule.h"
#include "oid-array.h"
#include "tree.h"
@@ -241,9 +239,9 @@ static void refresh_index_quietly(void)
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
if (fd < 0)
return;
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL,
+ refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL,
NULL);
repo_update_index_if_able(the_repository, &lock_file);
}
@@ -390,7 +388,15 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
sym->skip = map;
}
-int cmd_diff(int argc, const char **argv, const char *prefix)
+static void symdiff_release(struct symdiff *sdiff)
+{
+ bitmap_free(sdiff->skip);
+}
+
+int cmd_diff(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i;
struct rev_info rev;
@@ -467,6 +473,15 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
no_index = DIFF_NO_INDEX_IMPLICIT;
}
+ /*
+ * When operating outside of a Git repository we need to have a hash
+ * algorithm at hand so that we can generate the blob hashes. We
+ * default to SHA1 here, but may eventually want to change this to be
+ * configurable via a command line option.
+ */
+ if (nongit)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
prefix = precompose_argv_prefix(argc, argv, prefix);
@@ -474,8 +489,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &rev, prefix);
/* Set up defaults that will apply to both no-index and regular diffs. */
- rev.diffopt.stat_width = -1;
- rev.diffopt.stat_graph_width = -1;
+ init_diffstat_widths(&rev.diffopt);
rev.diffopt.flags.allow_external = 1;
rev.diffopt.flags.allow_textconv = 1;
@@ -608,11 +622,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
builtin_diff_combined(&rev, argc, argv,
ent.objects, ent.nr,
first_non_parent);
- result = diff_result_code(&rev.diffopt);
+ result = diff_result_code(&rev);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
release_revisions(&rev);
object_array_clear(&ent);
- UNLEAK(blob);
+ symdiff_release(&sdiff);
return result;
}
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 0f5eae9cd4..40e971e225 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -11,18 +11,19 @@
*
* Copyright (C) 2016 Johannes Schindelin
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#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 "repository.h"
#include "sparse-index.h"
#include "strvec.h"
#include "strbuf.h"
@@ -118,7 +119,7 @@ static int use_wt_file(const char *workdir, const char *name,
int fd = open(buf.buf, O_RDONLY);
if (fd >= 0 &&
- !index_fd(&the_index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
+ !index_fd(the_repository->index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
if (is_null_oid(oid)) {
oidcpy(oid, &wt_oid);
use = 1;
@@ -215,7 +216,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
struct child_process update_index = CHILD_PROCESS_INIT;
struct child_process diff_files = CHILD_PROCESS_INIT;
struct strbuf buf = STRBUF_INIT;
- const char *git_dir = absolute_path(get_git_dir());
+ const char *git_dir = absolute_path(repo_get_git_dir(the_repository));
FILE *fp;
strvec_pushl(&update_index.args,
@@ -339,7 +340,7 @@ static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
/* Write the file contents for the left and right sides of the difftool
* dir-diff representation for submodules and symlinks. Symlinks and submodules
* are written as regular text files so that external diff tools can diff them
- * as text files, resulting in behavior that is analogous to to what "git diff"
+ * as text files, resulting in behavior that is analogous to what "git diff"
* displays for symlink and submodule diffs.
*/
static void write_standin_files(struct pair_entry *entry,
@@ -375,10 +376,11 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct checkout lstate, rstate;
int err = 0;
struct child_process cmd = CHILD_PROCESS_INIT;
- struct hashmap wt_modified, tmp_modified;
+ struct hashmap wt_modified = HASHMAP_INIT(path_entry_cmp, NULL);
+ struct hashmap tmp_modified = HASHMAP_INIT(path_entry_cmp, NULL);
int indices_loaded = 0;
- workdir = get_git_work_tree();
+ workdir = repo_get_work_tree(the_repository);
/* Setup temp directories */
tmp = getenv("TMPDIR");
@@ -600,9 +602,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* in the common case of --symlinks and the difftool updating
* files through the symlink.
*/
- hashmap_init(&wt_modified, path_entry_cmp, NULL, wtindex.cache_nr);
- hashmap_init(&tmp_modified, path_entry_cmp, NULL, wtindex.cache_nr);
-
for (i = 0; i < wtindex.cache_nr; i++) {
struct hashmap_entry dummy;
const char *name = wtindex.cache[i]->name;
@@ -661,8 +660,17 @@ finish:
if (fp)
fclose(fp);
+ hashmap_clear_and_free(&working_tree_dups, struct working_tree_entry, entry);
+ hashmap_clear_and_free(&wt_modified, struct path_entry, entry);
+ hashmap_clear_and_free(&tmp_modified, struct path_entry, entry);
+ hashmap_clear_and_free(&submodules, struct pair_entry, entry);
+ hashmap_clear_and_free(&symlinks2, struct pair_entry, entry);
+ release_index(&wtindex);
free(lbase_dir);
free(rbase_dir);
+ strbuf_release(&info);
+ strbuf_release(&lpath);
+ strbuf_release(&rpath);
strbuf_release(&ldir);
strbuf_release(&rdir);
strbuf_release(&wtdir);
@@ -675,24 +683,23 @@ finish:
static int run_file_diff(int prompt, const char *prefix,
struct child_process *child)
{
- const char *env[] = {
- "GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
- NULL
- };
-
+ strvec_push(&child->env, "GIT_PAGER=");
+ strvec_push(&child->env, "GIT_EXTERNAL_DIFF=git-difftool--helper");
if (prompt > 0)
- env[2] = "GIT_DIFFTOOL_PROMPT=true";
+ strvec_push(&child->env, "GIT_DIFFTOOL_PROMPT=true");
else if (!prompt)
- env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
+ strvec_push(&child->env, "GIT_DIFFTOOL_NO_PROMPT=true");
child->git_cmd = 1;
child->dir = prefix;
- strvec_pushv(&child->env, env);
return run_command(child);
}
-int cmd_difftool(int argc, const char **argv, const char *prefix)
+int cmd_difftool(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
tool_help = 0, no_index = 0;
@@ -739,8 +746,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
if (!no_index){
setup_work_tree();
- setenv(GIT_DIR_ENVIRONMENT, absolute_path(get_git_dir()), 1);
- setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(get_git_work_tree()), 1);
+ setenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(the_repository)), 1);
+ setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(the_repository)), 1);
} else if (dir_diff)
die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 56dc69fac1..e17f262e8e 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007 Johannes E. Schindelin
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -25,7 +26,6 @@
#include "quote.h"
#include "remote.h"
#include "blob.h"
-#include "commit-slab.h"
static const char *fast_export_usage[] = {
N_("git fast-export [<rev-list-opts>]"),
@@ -33,9 +33,9 @@ static const char *fast_export_usage[] = {
};
static int progress;
-static enum { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
-static enum { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
-static enum { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
+static enum signed_tag_mode { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
+static enum tag_of_filtered_mode { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
+static enum reencode_mode { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
static int fake_missing_tagger;
static int use_done_feature;
static int no_data;
@@ -43,8 +43,8 @@ static int full_tree;
static int reference_excluded_commits;
static int show_original_ids;
static int mark_tags;
-static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
+static struct string_list extra_refs = STRING_LIST_INIT_DUP;
+static struct string_list tag_refs = STRING_LIST_INIT_DUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
static struct hashmap anonymized_seeds;
@@ -53,16 +53,18 @@ static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum signed_tag_mode *val = opt->value;
+
if (unset || !strcmp(arg, "abort"))
- signed_tag_mode = SIGNED_TAG_ABORT;
+ *val = SIGNED_TAG_ABORT;
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
- signed_tag_mode = VERBATIM;
+ *val = VERBATIM;
else if (!strcmp(arg, "warn"))
- signed_tag_mode = WARN;
+ *val = WARN;
else if (!strcmp(arg, "warn-strip"))
- signed_tag_mode = WARN_STRIP;
+ *val = WARN_STRIP;
else if (!strcmp(arg, "strip"))
- signed_tag_mode = STRIP;
+ *val = STRIP;
else
return error("Unknown signed-tags mode: %s", arg);
return 0;
@@ -71,12 +73,14 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
static int parse_opt_tag_of_filtered_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum tag_of_filtered_mode *val = opt->value;
+
if (unset || !strcmp(arg, "abort"))
- tag_of_filtered_mode = TAG_FILTERING_ABORT;
+ *val = TAG_FILTERING_ABORT;
else if (!strcmp(arg, "drop"))
- tag_of_filtered_mode = DROP;
+ *val = DROP;
else if (!strcmp(arg, "rewrite"))
- tag_of_filtered_mode = REWRITE;
+ *val = REWRITE;
else
return error("Unknown tag-of-filtered mode: %s", arg);
return 0;
@@ -85,21 +89,23 @@ static int parse_opt_tag_of_filtered_mode(const struct option *opt,
static int parse_opt_reencode_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum reencode_mode *val = opt->value;
+
if (unset) {
- reencode_mode = REENCODE_ABORT;
+ *val = REENCODE_ABORT;
return 0;
}
switch (git_parse_maybe_bool(arg)) {
case 0:
- reencode_mode = REENCODE_NO;
+ *val = REENCODE_NO;
break;
case 1:
- reencode_mode = REENCODE_YES;
+ *val = REENCODE_YES;
break;
default:
if (!strcasecmp(arg, "abort"))
- reencode_mode = REENCODE_ABORT;
+ *val = REENCODE_ABORT;
else
return error("Unknown reencoding mode: %s", arg);
}
@@ -131,8 +137,7 @@ static int anonymized_entry_cmp(const void *cmp_data UNUSED,
a = container_of(eptr, const struct anonymized_entry, hash);
if (keydata) {
const struct anonymized_entry_key *key = keydata;
- int equal = !strncmp(a->orig, key->orig, key->orig_len) &&
- !a->orig[key->orig_len];
+ int equal = !xstrncmpz(a->orig, key->orig, key->orig_len);
return !equal;
}
@@ -411,7 +416,7 @@ static char *generate_fake_oid(void)
struct object_id oid;
char *hex = xmallocz(GIT_MAX_HEXSZ);
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
put_be32(oid.hash + hashsz - 4, counter++);
return oid_to_hex_r(hex, &oid);
}
@@ -897,7 +902,7 @@ static void handle_tag(const char *name, struct tag *tag)
free(buf);
}
-static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
+static struct commit *get_commit(struct rev_cmdline_entry *e, const char *full_name)
{
switch (e->item->type) {
case OBJ_COMMIT:
@@ -928,14 +933,16 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
struct rev_cmdline_entry *e = info->rev + i;
struct object_id oid;
struct commit *commit;
- char *full_name;
+ char *full_name = NULL;
if (e->flags & UNINTERESTING)
continue;
if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
- &oid, &full_name, 0) != 1)
+ &oid, &full_name, 0) != 1) {
+ free(full_name);
continue;
+ }
if (refspecs.nr) {
char *private;
@@ -951,6 +958,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
warning("%s: Unexpected object of type %s, skipping.",
e->name,
type_name(e->item->type));
+ free(full_name);
continue;
}
@@ -959,10 +967,12 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
break;
case OBJ_BLOB:
export_blob(&commit->object.oid);
+ free(full_name);
continue;
default: /* OBJ_TAG (nested tags) is already handled */
warning("Tag points to object of unexpected type %s, skipping.",
type_name(commit->object.type));
+ free(full_name);
continue;
}
@@ -975,6 +985,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (!*revision_sources_at(&revision_sources, commit))
*revision_sources_at(&revision_sources, commit) = full_name;
+ else
+ free(full_name);
}
string_list_sort(&extra_refs);
@@ -1169,7 +1181,10 @@ static int parse_opt_anonymize_map(const struct option *opt,
return 0;
}
-int cmd_fast_export(int argc, const char **argv, const char *prefix)
+int cmd_fast_export(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info revs;
struct commit *commit;
@@ -1274,9 +1289,11 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
revs.diffopt.format_callback = show_filemodify;
revs.diffopt.format_callback_data = &paths_of_changed_objects;
revs.diffopt.flags.recursive = 1;
+
revs.diffopt.no_free = 1;
while ((commit = get_revision(&revs)))
handle_commit(commit, &revs, &paths_of_changed_objects);
+ revs.diffopt.no_free = 0;
handle_tags_and_duplicates(&extra_refs);
handle_tags_and_duplicates(&tag_refs);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 4dbb10aff3..457cdb40cc 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
#include "config.h"
#include "lockfile.h"
#include "object.h"
@@ -179,6 +179,7 @@ static unsigned long branch_load_count;
static int failure;
static FILE *pack_edges;
static unsigned int show_stats = 1;
+static unsigned int quiet;
static int global_argc;
static const char **global_argv;
static const char *global_prefix;
@@ -206,8 +207,8 @@ static unsigned int object_entry_alloc = 5000;
static struct object_entry_pool *blocks;
static struct hashmap object_table;
static struct mark_set *marks;
-static const char *export_marks_file;
-static const char *import_marks_file;
+static char *export_marks_file;
+static char *import_marks_file;
static int import_marks_file_from_stream;
static int import_marks_file_ignore_missing;
static int import_marks_file_done;
@@ -966,8 +967,7 @@ static int store_object(
if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
- } else if (find_sha1_pack(oid.hash,
- get_all_packs(the_repository))) {
+ } else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
e->type = type;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
@@ -1102,6 +1102,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
|| (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
cycle_packfile();
+ the_hash_algo->init_fn(&checkpoint.ctx);
hashfile_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
@@ -1166,8 +1167,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(&checkpoint);
- } else if (find_sha1_pack(oid.hash,
- get_all_packs(the_repository))) {
+ } else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
@@ -1235,20 +1235,6 @@ static void *gfi_unpack_entry(
return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
}
-static const char *get_mode(const char *str, uint16_t *modep)
-{
- unsigned char c;
- uint16_t mode = 0;
-
- while ((c = *str++) != ' ') {
- if (c < '0' || c > '7')
- return NULL;
- mode = (mode << 3) + (c - '0');
- }
- *modep = mode;
- return str;
-}
-
static void load_tree(struct tree_entry *root)
{
struct object_id *oid = &root->versions[1].oid;
@@ -1286,14 +1272,16 @@ static void load_tree(struct tree_entry *root)
t->entries[t->entry_count++] = e;
e->tree = NULL;
- c = get_mode(c, &e->versions[1].mode);
+ c = parse_mode(c, &e->versions[1].mode);
if (!c)
die("Corrupt mode in %s", oid_to_hex(oid));
e->versions[0].mode = e->versions[1].mode;
e->name = to_atom(c, strlen(c));
c += e->name->str_len + 1;
- oidread(&e->versions[0].oid, (unsigned char *)c);
- oidread(&e->versions[1].oid, (unsigned char *)c);
+ oidread(&e->versions[0].oid, (unsigned char *)c,
+ the_repository->hash_algo);
+ oidread(&e->versions[1].oid, (unsigned char *)c,
+ the_repository->hash_algo);
c += the_hash_algo->rawsz;
}
free(buf);
@@ -1399,7 +1387,7 @@ static void tree_content_replace(
{
if (!S_ISDIR(mode))
die("Root cannot be a non-directory");
- oidclr(&root->versions[0].oid);
+ oidclr(&root->versions[0].oid, the_repository->hash_algo);
oidcpy(&root->versions[1].oid, oid);
if (root->tree)
release_tree_content_recursive(root->tree);
@@ -1458,7 +1446,7 @@ static int tree_content_set(
if (S_ISDIR(e->versions[0].mode))
e->versions[0].mode |= NO_DELTA;
- oidclr(&root->versions[1].oid);
+ oidclr(&root->versions[1].oid, the_repository->hash_algo);
return 1;
}
if (!S_ISDIR(e->versions[1].mode)) {
@@ -1468,7 +1456,7 @@ static int tree_content_set(
if (!e->tree)
load_tree(e);
if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) {
- oidclr(&root->versions[1].oid);
+ oidclr(&root->versions[1].oid, the_repository->hash_algo);
return 1;
}
return 0;
@@ -1480,7 +1468,7 @@ static int tree_content_set(
e = new_tree_entry();
e->name = to_atom(p, n);
e->versions[0].mode = 0;
- oidclr(&e->versions[0].oid);
+ oidclr(&e->versions[0].oid, the_repository->hash_algo);
t->entries[t->entry_count++] = e;
if (*slash1) {
e->tree = new_tree_content(8);
@@ -1491,7 +1479,7 @@ static int tree_content_set(
e->versions[1].mode = mode;
oidcpy(&e->versions[1].oid, oid);
}
- oidclr(&root->versions[1].oid);
+ oidclr(&root->versions[1].oid, the_repository->hash_algo);
return 1;
}
@@ -1536,7 +1524,8 @@ static int tree_content_remove(
if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
for (n = 0; n < e->tree->entry_count; n++) {
if (e->tree->entries[n]->versions[1].mode) {
- oidclr(&root->versions[1].oid);
+ oidclr(&root->versions[1].oid,
+ the_repository->hash_algo);
return 1;
}
}
@@ -1555,8 +1544,8 @@ del_entry:
release_tree_content_recursive(e->tree);
e->tree = NULL;
e->versions[1].mode = 0;
- oidclr(&e->versions[1].oid);
- oidclr(&root->versions[1].oid);
+ oidclr(&e->versions[1].oid, the_repository->hash_algo);
+ oidclr(&root->versions[1].oid, the_repository->hash_algo);
return 1;
}
@@ -1614,16 +1603,30 @@ static int update_branch(struct branch *b)
struct ref_transaction *transaction;
struct object_id old_oid;
struct strbuf err = STRBUF_INIT;
-
+ static const char *replace_prefix = "refs/replace/";
+
+ if (starts_with(b->name, replace_prefix) &&
+ !strcmp(b->name + strlen(replace_prefix),
+ oid_to_hex(&b->oid))) {
+ if (!quiet)
+ warning("Dropping %s since it would point to "
+ "itself (i.e. to %s)",
+ b->name, oid_to_hex(&b->oid));
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, b->name, NULL, 0);
+ return 0;
+ }
if (is_null_oid(&b->oid)) {
if (b->delete)
- delete_ref(NULL, b->name, NULL, 0);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, b->name, NULL, 0);
return 0;
}
- if (read_ref(b->name, &old_oid))
- oidclr(&old_oid);
+ if (refs_read_ref(get_main_ref_store(the_repository), b->name, &old_oid))
+ oidclr(&old_oid, the_repository->hash_algo);
if (!force_update && !is_null_oid(&old_oid)) {
struct commit *old_cmit, *new_cmit;
+ int ret;
old_cmit = lookup_commit_reference_gently(the_repository,
&old_oid, 0);
@@ -1632,7 +1635,10 @@ static int update_branch(struct branch *b)
if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
- if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
+ ret = repo_in_merge_bases(the_repository, old_cmit, new_cmit);
+ if (ret < 0)
+ exit(128);
+ if (!ret) {
warning("Not updating %s"
" (new tip %s does not contain %s)",
b->name, oid_to_hex(&b->oid),
@@ -1640,10 +1646,11 @@ static int update_branch(struct branch *b)
return -1;
}
}
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction ||
ref_transaction_update(transaction, b->name, &b->oid, &old_oid,
- 0, msg, &err) ||
+ NULL, NULL, 0, msg, &err) ||
ref_transaction_commit(transaction, &err)) {
ref_transaction_free(transaction);
error("%s", err.buf);
@@ -1674,7 +1681,8 @@ static void dump_tags(void)
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction) {
failure |= error("%s", err.buf);
goto cleanup;
@@ -1684,7 +1692,8 @@ static void dump_tags(void)
strbuf_addf(&ref_name, "refs/tags/%s", t->name);
if (ref_transaction_update(transaction, ref_name.buf,
- &t->oid, NULL, 0, msg, &err)) {
+ &t->oid, NULL, NULL, NULL,
+ 0, msg, &err)) {
failure |= error("%s", err.buf);
goto cleanup;
}
@@ -2219,7 +2228,7 @@ static int parse_mapped_oid_hex(const char *hex, struct object_id *oid, const ch
*
* idnum ::= ':' bigint;
*
- * Return the first character after the value in *endptr.
+ * Update *endptr to point to the first character after the value.
*
* Complain if the following character is not what is expected,
* either a space or end of the string.
@@ -2252,8 +2261,8 @@ static uintmax_t parse_mark_ref_eol(const char *p)
}
/*
- * Parse the mark reference, demanding a trailing space. Return a
- * pointer to the space.
+ * Parse the mark reference, demanding a trailing space. Update *p to
+ * point to the first character after the space.
*/
static uintmax_t parse_mark_ref_space(const char **p)
{
@@ -2267,15 +2276,67 @@ static uintmax_t parse_mark_ref_space(const char **p)
return mark;
}
+/*
+ * Parse the path string into the strbuf. The path can either be quoted with
+ * escape sequences or unquoted without escape sequences. Unquoted strings may
+ * contain spaces only if `is_last_field` is nonzero; otherwise, it stops
+ * parsing at the first space.
+ */
+static void parse_path(struct strbuf *sb, const char *p, const char **endp,
+ int is_last_field, const char *field)
+{
+ if (*p == '"') {
+ if (unquote_c_style(sb, p, endp))
+ die("Invalid %s: %s", field, command_buf.buf);
+ if (strlen(sb->buf) != sb->len)
+ die("NUL in %s: %s", field, command_buf.buf);
+ } else {
+ /*
+ * Unless we are parsing the last field of a line,
+ * SP is the end of this field.
+ */
+ *endp = is_last_field
+ ? p + strlen(p)
+ : strchrnul(p, ' ');
+ strbuf_add(sb, p, *endp - p);
+ }
+}
+
+/*
+ * Parse the path string into the strbuf, and complain if this is not the end of
+ * the string. Unquoted strings may contain spaces.
+ */
+static void parse_path_eol(struct strbuf *sb, const char *p, const char *field)
+{
+ const char *end;
+
+ parse_path(sb, p, &end, 1, field);
+ if (*end)
+ die("Garbage after %s: %s", field, command_buf.buf);
+}
+
+/*
+ * Parse the path string into the strbuf, and ensure it is followed by a space.
+ * Unquoted strings may not contain spaces. Update *endp to point to the first
+ * character after the space.
+ */
+static void parse_path_space(struct strbuf *sb, const char *p,
+ const char **endp, const char *field)
+{
+ parse_path(sb, p, endp, 0, field);
+ if (**endp != ' ')
+ die("Missing space after %s: %s", field, command_buf.buf);
+ (*endp)++;
+}
+
static void file_change_m(const char *p, struct branch *b)
{
- static struct strbuf uq = STRBUF_INIT;
- const char *endp;
+ static struct strbuf path = STRBUF_INIT;
struct object_entry *oe;
struct object_id oid;
uint16_t mode, inline_data = 0;
- p = get_mode(p, &mode);
+ p = parse_mode(p, &mode);
if (!p)
die("Corrupt mode: %s", command_buf.buf);
switch (mode) {
@@ -2307,16 +2368,14 @@ static void file_change_m(const char *p, struct branch *b)
die("Missing space after SHA1: %s", command_buf.buf);
}
- strbuf_reset(&uq);
- if (!unquote_c_style(&uq, p, &endp)) {
- if (*endp)
- die("Garbage after path in: %s", command_buf.buf);
- p = uq.buf;
- }
+ strbuf_reset(&path);
+ parse_path_eol(&path, p, "path");
/* Git does not track empty, non-toplevel directories. */
- if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *p) {
- tree_content_remove(&b->branch_tree, p, NULL, 0);
+ if (S_ISDIR(mode) &&
+ is_empty_tree_oid(&oid, the_repository->hash_algo) &&
+ *path.buf) {
+ tree_content_remove(&b->branch_tree, path.buf, NULL, 0);
return;
}
@@ -2337,10 +2396,6 @@ static void file_change_m(const char *p, struct branch *b)
if (S_ISDIR(mode))
die("Directories cannot be specified 'inline': %s",
command_buf.buf);
- if (p != uq.buf) {
- strbuf_addstr(&uq, p);
- p = uq.buf;
- }
while (read_next_command() != EOF) {
const char *v;
if (skip_prefix(command_buf.buf, "cat-blob ", &v))
@@ -2366,74 +2421,48 @@ static void file_change_m(const char *p, struct branch *b)
command_buf.buf);
}
- if (!*p) {
+ if (!*path.buf) {
tree_content_replace(&b->branch_tree, &oid, mode, NULL);
return;
}
- tree_content_set(&b->branch_tree, p, &oid, mode, NULL);
+ tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL);
}
static void file_change_d(const char *p, struct branch *b)
{
- static struct strbuf uq = STRBUF_INIT;
- const char *endp;
+ static struct strbuf path = STRBUF_INIT;
- strbuf_reset(&uq);
- if (!unquote_c_style(&uq, p, &endp)) {
- if (*endp)
- die("Garbage after path in: %s", command_buf.buf);
- p = uq.buf;
- }
- tree_content_remove(&b->branch_tree, p, NULL, 1);
+ strbuf_reset(&path);
+ parse_path_eol(&path, p, "path");
+ tree_content_remove(&b->branch_tree, path.buf, NULL, 1);
}
-static void file_change_cr(const char *s, struct branch *b, int rename)
+static void file_change_cr(const char *p, struct branch *b, int rename)
{
- const char *d;
- static struct strbuf s_uq = STRBUF_INIT;
- static struct strbuf d_uq = STRBUF_INIT;
- const char *endp;
+ static struct strbuf source = STRBUF_INIT;
+ static struct strbuf dest = STRBUF_INIT;
struct tree_entry leaf;
- strbuf_reset(&s_uq);
- if (!unquote_c_style(&s_uq, s, &endp)) {
- if (*endp != ' ')
- die("Missing space after source: %s", command_buf.buf);
- } else {
- endp = strchr(s, ' ');
- if (!endp)
- die("Missing space after source: %s", command_buf.buf);
- strbuf_add(&s_uq, s, endp - s);
- }
- s = s_uq.buf;
-
- endp++;
- if (!*endp)
- die("Missing dest: %s", command_buf.buf);
-
- d = endp;
- strbuf_reset(&d_uq);
- if (!unquote_c_style(&d_uq, d, &endp)) {
- if (*endp)
- die("Garbage after dest in: %s", command_buf.buf);
- d = d_uq.buf;
- }
+ strbuf_reset(&source);
+ parse_path_space(&source, p, &p, "source");
+ strbuf_reset(&dest);
+ parse_path_eol(&dest, p, "dest");
memset(&leaf, 0, sizeof(leaf));
if (rename)
- tree_content_remove(&b->branch_tree, s, &leaf, 1);
+ tree_content_remove(&b->branch_tree, source.buf, &leaf, 1);
else
- tree_content_get(&b->branch_tree, s, &leaf, 1);
+ tree_content_get(&b->branch_tree, source.buf, &leaf, 1);
if (!leaf.versions[1].mode)
- die("Path %s not in branch", s);
- if (!*d) { /* C "path/to/subdir" "" */
+ die("Path %s not in branch", source.buf);
+ if (!*dest.buf) { /* C "path/to/subdir" "" */
tree_content_replace(&b->branch_tree,
&leaf.versions[1].oid,
leaf.versions[1].mode,
leaf.tree);
return;
}
- tree_content_set(&b->branch_tree, d,
+ tree_content_set(&b->branch_tree, dest.buf,
&leaf.versions[1].oid,
leaf.versions[1].mode,
leaf.tree);
@@ -2441,7 +2470,6 @@ static void file_change_cr(const char *s, struct branch *b, int rename)
static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout)
{
- static struct strbuf uq = STRBUF_INIT;
struct object_entry *oe;
struct branch *s;
struct object_id oid, commit_oid;
@@ -2506,10 +2534,6 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
die("Invalid ref name or SHA1 expression: %s", p);
if (inline_data) {
- if (p != uq.buf) {
- strbuf_addstr(&uq, p);
- p = uq.buf;
- }
read_next_command();
parse_and_store_blob(&last_blob, &oid, 0);
} else if (oe) {
@@ -2542,8 +2566,8 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
static void file_change_deleteall(struct branch *b)
{
release_tree_content_recursive(b->branch_tree.tree);
- oidclr(&b->branch_tree.versions[0].oid);
- oidclr(&b->branch_tree.versions[1].oid);
+ oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
+ oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
load_tree(&b->branch_tree);
b->num_notes = 0;
}
@@ -2562,8 +2586,8 @@ static void parse_from_commit(struct branch *b, char *buf, unsigned long size)
static void parse_from_existing(struct branch *b)
{
if (is_null_oid(&b->oid)) {
- oidclr(&b->branch_tree.versions[0].oid);
- oidclr(&b->branch_tree.versions[1].oid);
+ oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
+ oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
} else {
unsigned long size;
char *buf;
@@ -2808,8 +2832,7 @@ static void parse_new_tag(const char *arg)
enum object_type type;
const char *v;
- t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
- memset(t, 0, sizeof(struct tag));
+ t = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct tag));
t->name = mem_pool_strdup(&fi_mem_pool, arg);
if (last_tag)
last_tag->next_tag = t;
@@ -2887,9 +2910,9 @@ static void parse_reset_branch(const char *arg)
b = lookup_branch(arg);
if (b) {
- oidclr(&b->oid);
- oidclr(&b->branch_tree.versions[0].oid);
- oidclr(&b->branch_tree.versions[1].oid);
+ oidclr(&b->oid, the_repository->hash_algo);
+ oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
+ oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
if (b->branch_tree.tree) {
release_tree_content_recursive(b->branch_tree.tree);
b->branch_tree.tree = NULL;
@@ -3162,6 +3185,7 @@ static void print_ls(int mode, const unsigned char *hash, const char *path)
static void parse_ls(const char *p, struct branch *b)
{
+ static struct strbuf path = STRBUF_INIT;
struct tree_entry *root = NULL;
struct tree_entry leaf = {NULL};
@@ -3178,17 +3202,9 @@ static void parse_ls(const char *p, struct branch *b)
root->versions[1].mode = S_IFDIR;
load_tree(root);
}
- if (*p == '"') {
- static struct strbuf uq = STRBUF_INIT;
- const char *endp;
- strbuf_reset(&uq);
- if (unquote_c_style(&uq, p, &endp))
- die("Invalid path: %s", command_buf.buf);
- if (*endp)
- die("Garbage after path in: %s", command_buf.buf);
- p = uq.buf;
- }
- tree_content_get(root, p, &leaf, 1);
+ strbuf_reset(&path);
+ parse_path_eol(&path, p, "path");
+ tree_content_get(root, path.buf, &leaf, 1);
/*
* A directory in preparation would have a sha1 of zero
* until it is saved. Save, for simplicity.
@@ -3196,7 +3212,7 @@ static void parse_ls(const char *p, struct branch *b)
if (S_ISDIR(leaf.versions[1].mode))
store_tree(&leaf);
- print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, p);
+ print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, path.buf);
if (leaf.tree)
release_tree_content_recursive(leaf.tree);
if (!b || root != &b->branch_tree)
@@ -3269,6 +3285,7 @@ static void option_import_marks(const char *marks,
read_marks();
}
+ free(import_marks_file);
import_marks_file = make_fast_import_path(marks);
import_marks_file_from_stream = from_stream;
import_marks_file_ignore_missing = ignore_missing;
@@ -3311,6 +3328,7 @@ static void option_active_branches(const char *branches)
static void option_export_marks(const char *marks)
{
+ free(export_marks_file);
export_marks_file = make_fast_import_path(marks);
}
@@ -3352,6 +3370,8 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
free(f);
string_list_insert(list, s)->util = ms;
+
+ free(s);
}
static int parse_one_option(const char *option)
@@ -3381,6 +3401,7 @@ static int parse_one_option(const char *option)
option_export_pack_edges(option);
} else if (!strcmp(option, "quiet")) {
show_stats = 0;
+ quiet = 1;
} else if (!strcmp(option, "stats")) {
show_stats = 1;
} else if (!strcmp(option, "allow-unsafe-features")) {
@@ -3476,8 +3497,8 @@ static void git_pack_config(void)
if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
pack_idx_opts.version = indexversion_value;
if (pack_idx_opts.version > 2)
- git_die_config("pack.indexversion",
- "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
+ git_die_config(the_repository, "pack.indexversion",
+ "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
}
if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
max_packsize = packsizelimit_value;
@@ -3528,7 +3549,10 @@ static void parse_argv(void)
build_mark_map(&sub_marks_from, &sub_marks_to);
}
-int cmd_fast_import(int argc, const char **argv, const char *prefix)
+int cmd_fast_import(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
unsigned int i;
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 44c05ee86c..62e8c3aa6b 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
@@ -29,11 +30,11 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
; /* <oid>, leave oid as name */
} else {
/* <ref>, clear cruft from oid */
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
}
} else {
/* <ref>, clear cruft from get_oid_hex */
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
}
ref = alloc_ref(name);
@@ -43,12 +44,16 @@ 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 UNUSED)
+int cmd_fetch_pack(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
int i, ret;
- struct ref *ref = NULL;
+ struct ref *fetched_refs = NULL, *remote_refs = NULL;
const char *dest = NULL;
struct ref **sought = NULL;
+ struct ref **sought_to_free = NULL;
int nr_sought = 0, alloc_sought = 0;
int fd[2];
struct string_list pack_lockfiles = STRING_LIST_INIT_DUP;
@@ -228,19 +233,27 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
version = discover_version(&reader);
switch (version) {
case protocol_v2:
- get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL,
+ get_remote_refs(fd[1], &reader, &remote_refs, 0, NULL, NULL,
args.stateless_rpc);
break;
case protocol_v1:
case protocol_v0:
- get_remote_heads(&reader, &ref, 0, NULL, &shallow);
+ get_remote_heads(&reader, &remote_refs, 0, NULL, &shallow);
break;
case protocol_unknown_version:
BUG("unknown protocol version");
}
- ref = fetch_pack(&args, fd, ref, sought, nr_sought,
+ /*
+ * Create a shallow copy of `sought` so that we can free all of its entries.
+ * This is because `fetch_pack()` will modify the array to evict some
+ * entries, but won't free those.
+ */
+ DUP_ARRAY(sought_to_free, sought, nr_sought);
+
+ fetched_refs = fetch_pack(&args, fd, remote_refs, sought, nr_sought,
&shallow, pack_lockfiles_ptr, version);
+
if (pack_lockfiles.nr) {
int i;
@@ -260,7 +273,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
if (finish_connect(conn))
return 1;
- ret = !ref;
+ ret = !fetched_refs;
/*
* If the heads to pull were given, we should have consumed
@@ -270,11 +283,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
*/
ret |= report_unmatched_refs(sought, nr_sought);
- while (ref) {
+ for (struct ref *ref = fetched_refs; ref; ref = ref->next)
printf("%s %s\n",
oid_to_hex(&ref->old_oid), ref->name);
- ref = ref->next;
- }
+ for (size_t i = 0; i < nr_sought; i++)
+ free_one_ref(sought_to_free[i]);
+ free(sought_to_free);
+ free(sought);
+ free_refs(fetched_refs);
+ free_refs(remote_refs);
+ list_objects_filter_release(&args.filter_options);
+ oid_array_clear(&shallow);
+ string_list_clear(&pack_lockfiles, 0);
return ret;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index eed4a7cdb6..335083eb10 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1,13 +1,13 @@
/*
* "git fetch"
*/
+#define USE_THE_REPOSITORY_VARIABLE
#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-name.h"
@@ -26,7 +26,6 @@
#include "connected.h"
#include "strvec.h"
#include "utf8.h"
-#include "packfile.h"
#include "pager.h"
#include "path.h"
#include "pkt-line.h"
@@ -38,7 +37,6 @@
#include "shallow.h"
#include "trace.h"
#include "trace2.h"
-#include "worktree.h"
#include "bundle-uri.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -102,6 +100,7 @@ static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
struct fetch_config {
enum display_format display_format;
+ int all;
int prune;
int prune_tags;
int show_forced_updates;
@@ -115,6 +114,11 @@ static int git_fetch_config(const char *k, const char *v,
{
struct fetch_config *fetch_config = cb;
+ if (!strcmp(k, "fetch.all")) {
+ fetch_config->all = git_config_bool(k, v);
+ return 0;
+ }
+
if (!strcmp(k, "fetch.prune")) {
fetch_config->prune = git_config_bool(k, v);
return 0;
@@ -134,6 +138,7 @@ static int git_fetch_config(const char *k, const char *v,
int r = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
fetch_config->recurse_submodules = r;
+ return 0;
}
if (!strcmp(k, "submodule.fetchjobs")) {
@@ -176,7 +181,7 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
* "git fetch --refmap='' origin foo"
* can be used to tell the command not to store anywhere
*/
- refspec_append(&refmap, arg);
+ refspec_append(opt->value, arg);
return 0;
}
@@ -281,7 +286,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
return ent;
}
-static int add_one_refname(const char *refname,
+static int add_one_refname(const char *refname, const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *cbdata)
{
@@ -308,7 +313,7 @@ static void clear_item(struct refname_hash_entry *item)
static void add_already_queued_tags(const char *refname,
- const struct object_id *old_oid,
+ const struct object_id *old_oid UNUSED,
const struct object_id *new_oid,
void *cb_data)
{
@@ -335,7 +340,8 @@ static void find_non_local_tags(const struct ref *refs,
refname_hash_init(&remote_refs);
create_fetch_oidset(head, &fetch_oids);
- for_each_ref(add_one_refname, &existing_refs);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_one_refname,
+ &existing_refs);
/*
* If we already have a transaction, then we need to filter out all
@@ -444,18 +450,14 @@ static void filter_prefetch_refspec(struct refspec *rs)
continue;
if (!rs->items[i].dst ||
(rs->items[i].src &&
- !strncmp(rs->items[i].src,
- ref_namespace[NAMESPACE_TAGS].ref,
- strlen(ref_namespace[NAMESPACE_TAGS].ref)))) {
+ starts_with(rs->items[i].src,
+ ref_namespace[NAMESPACE_TAGS].ref))) {
int j;
- free(rs->items[i].src);
- free(rs->items[i].dst);
+ refspec_item_clear(&rs->items[i]);
- for (j = i + 1; j < rs->nr; j++) {
+ for (j = i + 1; j < rs->nr; j++)
rs->items[j - 1] = rs->items[j];
- rs->raw[j - 1] = rs->raw[j];
- }
rs->nr--;
i--;
continue;
@@ -577,11 +579,16 @@ static struct ref *get_ref_map(struct remote *remote,
}
}
- if (tags == TAGS_SET)
+ if (tags == TAGS_SET) {
+ struct refspec_item tag_refspec;
+
/* also fetch all tags */
- get_fetch_map(remote_refs, tag_refspec, &tail, 0);
- else if (tags == TAGS_DEFAULT && *autotags)
+ refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
+ get_fetch_map(remote_refs, &tag_refspec, &tail, 0);
+ refspec_item_clear(&tag_refspec);
+ } else if (tags == TAGS_DEFAULT && *autotags) {
find_non_local_tags(remote_refs, NULL, &ref_map, &tail);
+ }
/* Now append any refs to be updated opportunistically: */
*tail = orefs;
@@ -610,7 +617,9 @@ static struct ref *get_ref_map(struct remote *remote,
if (!existing_refs_populated) {
refname_hash_init(&existing_refs);
- for_each_ref(add_one_refname, &existing_refs);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_one_refname,
+ &existing_refs);
existing_refs_populated = 1;
}
@@ -655,7 +664,8 @@ static int s_update_ref(const char *action,
* lifecycle.
*/
if (!transaction) {
- transaction = our_transaction = ref_transaction_begin(&err);
+ transaction = our_transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction) {
ret = STORE_REF_ERROR_OTHER;
goto out;
@@ -664,7 +674,7 @@ static int s_update_ref(const char *action,
ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
check_old ? &ref->old_oid : NULL,
- 0, msg, &err);
+ NULL, NULL, 0, msg, &err);
if (ret) {
ret = STORE_REF_ERROR_OTHER;
goto out;
@@ -978,6 +988,8 @@ static int update_local_ref(struct ref *ref,
uint64_t t_before = getnanotime();
fast_forward = repo_in_merge_bases(the_repository, current,
updated);
+ if (fast_forward < 0)
+ exit(128);
forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else {
fast_forward = 1;
@@ -1146,7 +1158,7 @@ static int store_updated_refs(struct display_state *display_state,
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"),
+ rc = error(_("%s did not send all necessary objects"),
display_state->url);
goto abort;
}
@@ -1376,8 +1388,8 @@ static int prune_refs(struct display_state *display_state,
if (!dry_run) {
if (transaction) {
for (ref = stale_refs; ref; ref = ref->next) {
- result = ref_transaction_delete(transaction, ref->name, NULL, 0,
- "fetch: prune", &err);
+ result = ref_transaction_delete(transaction, ref->name, NULL,
+ NULL, 0, "fetch: prune", &err);
if (result)
goto cleanup;
}
@@ -1387,7 +1399,9 @@ static int prune_refs(struct display_state *display_state,
for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);
- result = delete_refs("fetch: prune", &refnames, 0);
+ result = refs_delete_refs(get_main_ref_store(the_repository),
+ "fetch: prune", &refnames,
+ 0);
string_list_clear(&refnames, 0);
}
}
@@ -1400,7 +1414,8 @@ static int prune_refs(struct display_state *display_state,
_("(none)"), ref->name,
&ref->new_oid, &ref->old_oid,
summary_width);
- warn_dangling_symref(stderr, dangling_msg, ref->name);
+ refs_warn_dangling_symref(get_main_ref_store(the_repository),
+ stderr, dangling_msg, ref->name);
}
}
@@ -1440,12 +1455,13 @@ static void set_option(struct transport *transport, const char *name, const char
die(_("option \"%s\" value \"%s\" is not valid for %s"),
name, value, transport->url);
if (r > 0)
- warning(_("option \"%s\" is ignored for %s\n"),
+ warning(_("option \"%s\" is ignored for %s"),
name, transport->url);
}
static int add_oid(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
@@ -1473,7 +1489,8 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
continue;
}
old_nr = oids->nr;
- for_each_glob_ref(add_oid, s, oids);
+ refs_for_each_glob_ref(get_main_ref_store(the_repository),
+ add_oid, s, oids);
if (old_nr == oids->nr)
warning("ignoring --negotiation-tip=%s because it does not match any refs",
s);
@@ -1649,9 +1666,10 @@ static int do_fetch(struct transport *transport,
config->display_format);
if (atomic_fetch) {
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction) {
- retcode = error("%s", err.buf);
+ retcode = -1;
goto cleanup;
}
}
@@ -1710,12 +1728,8 @@ static int do_fetch(struct transport *transport,
goto cleanup;
retcode = ref_transaction_commit(transaction, &err);
- if (retcode) {
- error("%s", err.buf);
- ref_transaction_free(transaction);
- transaction = NULL;
+ if (retcode)
goto cleanup;
- }
}
commit_fetch_head(&fetch_head);
@@ -1775,11 +1789,19 @@ static int do_fetch(struct transport *transport,
}
cleanup:
- if (retcode && transaction) {
- ref_transaction_abort(transaction, &err);
- error("%s", err.buf);
+ if (retcode) {
+ if (err.len) {
+ error("%s", err.buf);
+ strbuf_reset(&err);
+ }
+ if (transaction && ref_transaction_abort(transaction, &err) &&
+ err.len)
+ error("%s", err.buf);
+ transaction = NULL;
}
+ if (transaction)
+ ref_transaction_free(transaction);
display_state_release(&display_state);
close_fetch_head(&fetch_head);
strbuf_release(&err);
@@ -1955,6 +1977,8 @@ static int fetch_multiple(struct string_list *list, int max_children,
strvec_pushl(&argv, "-c", "fetch.bundleURI=",
"fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
+ for (i = 0; i < server_options.nr; i++)
+ strvec_pushf(&argv, "--server-option=%s", server_options.items[i].string);
add_options_to_argv(&argv, config);
if (max_children != 1 && list->nr != 1) {
@@ -2113,7 +2137,10 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
return exit_code;
}
-int cmd_fetch(int argc, const char **argv, const char *prefix)
+int cmd_fetch(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct fetch_config config = {
.display_format = DISPLAY_FORMAT_FULL,
@@ -2128,7 +2155,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
- int all = 0, multiple = 0;
+ int all = -1, multiple = 0;
int result = 0;
int prune_tags_ok = 1;
int enable_auto_gc = 1;
@@ -2185,8 +2212,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
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_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("ref"),
+ N_("deepen history of shallow clone, excluding ref")),
OPT_INTEGER(0, "deepen", &deepen_relative,
N_("deepen history of shallow clone")),
OPT_SET_INT_F(0, "unshallow", &unshallow,
@@ -2204,7 +2231,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
OPT_BOOL(0, "update-shallow", &update_shallow,
N_("accept refs that update .git/shallow")),
- OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
+ OPT_CALLBACK_F(0, "refmap", &refmap, N_("refmap"),
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_IPVERSION(&family),
@@ -2333,11 +2360,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
fetch_bundle_uri(the_repository, bundle_uri, NULL))
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+ if (all < 0) {
+ /*
+ * no --[no-]all given;
+ * only use config option if no remote was explicitly specified
+ */
+ all = (!argc) ? config.all : 0;
+ }
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
else if (argc > 1)
die(_("fetch --all does not make sense with refspecs"));
+
(void) for_each_remote(get_one_remote_for_fetch, &list);
/* do not do fetch_multiple() of one */
@@ -2374,6 +2410,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct oidset_iter iter;
const struct object_id *oid;
+ trace2_region_enter("fetch", "negotiate-only", the_repository);
if (!remote)
die(_("must supply remote when using --negotiate-only"));
gtransport = prepare_transport(remote, 1);
@@ -2382,6 +2419,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
} else {
warning(_("protocol does not support --negotiate-only, exiting"));
result = 1;
+ trace2_region_leave("fetch", "negotiate-only", the_repository);
goto cleanup;
}
if (server_options.nr)
@@ -2392,11 +2430,17 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
while ((oid = oidset_iter_next(&iter)))
printf("%s\n", oid_to_hex(oid));
oidset_clear(&acked_commits);
+ trace2_region_leave("fetch", "negotiate-only", the_repository);
} else if (remote) {
- if (filter_options.choice || repo_has_promisor_remote(the_repository))
+ if (filter_options.choice || repo_has_promisor_remote(the_repository)) {
+ trace2_region_enter("fetch", "setup-partial", the_repository);
fetch_one_setup_partial(remote);
+ trace2_region_leave("fetch", "setup-partial", the_repository);
+ }
+ trace2_region_enter("fetch", "fetch-one", the_repository);
result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
&config);
+ trace2_region_leave("fetch", "fetch-one", the_repository);
} else {
int max_children = max_jobs;
@@ -2416,7 +2460,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
max_children = config.parallel;
/* TODO should this also die if we have a previous partial-clone? */
+ trace2_region_enter("fetch", "fetch-multiple", the_repository);
result = fetch_multiple(&list, max_children, &config);
+ trace2_region_leave("fetch", "fetch-multiple", the_repository);
}
/*
@@ -2438,6 +2484,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
max_children = config.parallel;
add_options_to_argv(&options, &config);
+ trace2_region_enter_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
result = fetch_submodules(the_repository,
&options,
submodule_prefix,
@@ -2445,6 +2492,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
recurse_submodules_default,
verbosity < 0,
max_children);
+ trace2_region_leave_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
strvec_clear(&options);
}
@@ -2468,9 +2516,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (progress)
commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+ trace2_region_enter("fetch", "write-commit-graph", the_repository);
write_commit_graph_reachable(the_repository->objects->odb,
commit_graph_flags,
NULL);
+ trace2_region_leave("fetch", "write-commit-graph", the_repository);
}
if (enable_auto_gc) {
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 0f9855b680..189cd1096a 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "fmt-merge-msg.h"
@@ -9,9 +10,12 @@ static const char * const fmt_merge_msg_usage[] = {
NULL
};
-int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
+int cmd_fmt_merge_msg(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- const char *inpath = NULL;
+ char *inpath = NULL;
const char *message = NULL;
char *into_name = NULL;
int shortlog_len = -1;
@@ -66,5 +70,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
if (ret)
return ret;
write_in_full(STDOUT_FILENO, output.buf, output.len);
+
+ strbuf_release(&input);
+ strbuf_release(&output);
+ free(inpath);
return 0;
}
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 350bfa6e81..715745a262 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,13 +1,13 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "commit.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>]"),
@@ -17,18 +17,17 @@ static char const * const for_each_ref_usage[] = {
NULL
};
-int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
+int cmd_for_each_ref(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- int i;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
- int maxcount = 0, icase = 0, omit_empty = 0;
- struct ref_array array;
+ int icase = 0, include_root_refs = 0, from_stdin = 0;
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;
+ unsigned int flags = FILTER_REFS_REGULAR;
struct strvec vec = STRVEC_INIT;
struct option opts[] = {
@@ -40,11 +39,11 @@ 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,
+ OPT_BOOL(0, "omit-empty", &format.array_opts.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_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
OPT__COLOR(&format.use_color, N_("respect format colors")),
OPT_REF_FILTER_EXCLUDE(&filter),
@@ -58,18 +57,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
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_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")),
OPT_END(),
};
- memset(&array, 0, sizeof(array));
-
format.format = "%(objectname) %(objecttype)\t%(refname)";
git_config(git_default_config, NULL);
+ /* Set default (refname) sorting */
+ string_list_append(&sorting_options, "refname");
+
parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
- if (maxcount < 0) {
- error("invalid --count argument: `%d'", maxcount);
+ if (format.array_opts.max_count < 0) {
+ error("invalid --count argument: `%d'", format.array_opts.max_count);
usage_with_options(for_each_ref_usage, opts);
}
if (HAS_MULTI_BITS(format.quote_style)) {
@@ -100,28 +101,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
filter.name_patterns = argv;
}
+ if (include_root_refs)
+ flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD;
+
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)
- maxcount = array.nr;
- for (i = 0; i < maxcount; i++) {
- strbuf_reset(&err);
- strbuf_reset(&output);
- if (format_ref_array_item(array.items[i], &format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- if (output.len || !omit_empty)
- putchar('\n');
- }
+ filter_and_format_refs(&filter, flags, sorting, &format);
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
ref_filter_clear(&filter);
+ ref_format_clear(&format);
ref_sorting_release(sorting);
strvec_clear(&vec);
return 0;
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 28186b30f5..fae7f91cf1 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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"
@@ -29,9 +29,13 @@ static int run_command_on_repo(const char *path, int argc, const char ** argv)
return run_command(&child);
}
-int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
+int cmd_for_each_repo(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
static const char *config_key = NULL;
+ int keep_going = 0;
int i, result = 0;
const struct string_list *values;
int err;
@@ -39,6 +43,8 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
N_("config key storing a list of repository paths")),
+ OPT_BOOL(0, "keep-going", &keep_going,
+ N_("keep going even if command fails in a repository")),
OPT_END()
};
@@ -55,8 +61,14 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
else if (err)
return 0;
- for (i = 0; !result && i < values->nr; i++)
- result = run_command_on_repo(values->items[i].string, argc, argv);
+ for (i = 0; i < values->nr; i++) {
+ int ret = run_command_on_repo(values->items[i].string, argc, argv);
+ if (ret) {
+ if (!keep_going)
+ return ret;
+ result = 1;
+ }
+ }
return result;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 611925905e..7f4e2f0414 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1,7 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tree.h"
@@ -10,13 +10,10 @@
#include "refs.h"
#include "pack.h"
#include "cache-tree.h"
-#include "tree-walk.h"
#include "fsck.h"
#include "parse-options.h"
-#include "dir.h"
#include "progress.h"
#include "streaming.h"
-#include "decorate.h"
#include "packfile.h"
#include "object-file.h"
#include "object-name.h"
@@ -92,13 +89,16 @@ static int objerror(struct object *obj, const char *err)
return -1;
}
-static int fsck_error_func(struct fsck_options *o UNUSED,
- const struct object_id *oid,
- enum object_type object_type,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id UNUSED,
- const char *message)
+static int fsck_objects_error_func(struct fsck_options *o UNUSED,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
{
+ struct fsck_object_report *report = fsck_report;
+ const struct object_id *oid = report->oid;
+ enum object_type object_type = report->object_type;
+
switch (msg_type) {
case FSCK_WARN:
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
@@ -512,19 +512,19 @@ static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid
return 0;
}
-static int fsck_handle_reflog(const char *logname,
- const struct object_id *oid UNUSED,
- int flag UNUSED, void *cb_data)
+static int fsck_handle_reflog(const char *logname, void *cb_data)
{
struct strbuf refname = STRBUF_INIT;
strbuf_worktree_ref(cb_data, &refname, logname);
- for_each_reflog_ent(refname.buf, fsck_handle_reflog_ent, refname.buf);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ refname.buf, fsck_handle_reflog_ent,
+ refname.buf);
strbuf_release(&refname);
return 0;
}
-static int fsck_handle_ref(const char *refname, const struct object_id *oid,
+static int fsck_handle_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object *obj;
@@ -568,7 +568,8 @@ static void get_default_heads(void)
const char *head_points_at;
struct object_id head_oid;
- for_each_rawref(fsck_handle_ref, NULL);
+ refs_for_each_rawref(get_main_ref_store(the_repository),
+ fsck_handle_ref, NULL);
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
@@ -578,7 +579,7 @@ static void get_default_heads(void)
strbuf_worktree_ref(wt, &ref, "HEAD");
fsck_head_link(ref.buf, &head_points_at, &head_oid);
if (head_points_at && !is_null_oid(&head_oid))
- fsck_handle_ref(ref.buf, &head_oid, 0, NULL);
+ fsck_handle_ref(ref.buf, NULL, &head_oid, 0, NULL);
strbuf_release(&ref);
if (include_reflogs)
@@ -717,7 +718,9 @@ static int fsck_head_link(const char *head_ref_name,
if (verbose)
fprintf_ln(stderr, _("Checking %s link"), head_ref_name);
- *head_points_at = resolve_ref_unsafe(head_ref_name, 0, head_oid, NULL);
+ *head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ head_ref_name, 0, head_oid,
+ NULL);
if (!*head_points_at) {
errors_found |= ERROR_REFS;
return error(_("invalid %s"), head_ref_name);
@@ -922,7 +925,10 @@ static struct option fsck_opts[] = {
OPT_END(),
};
-int cmd_fsck(int argc, const char **argv, const char *prefix)
+int cmd_fsck(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i;
struct object_directory *odb;
@@ -938,7 +944,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
fsck_walk_options.walk = mark_object;
fsck_obj_options.walk = mark_used;
- fsck_obj_options.error_func = fsck_error_func;
+ fsck_obj_options.error_func = fsck_objects_error_func;
if (check_strict)
fsck_obj_options.strict = 1;
@@ -1050,7 +1056,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
* and may get overwritten by other calls
* while we're examining the index.
*/
- path = xstrdup(worktree_git_path(wt, "index"));
+ path = xstrdup(worktree_git_path(the_repository, wt, "index"));
read_index_from(&istate, path, get_worktree_git_dir(wt));
fsck_index(&istate, path, wt->is_current);
discard_index(&istate);
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 7e99c4d61b..f3f6bd330b 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1,19 +1,20 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "config.h"
-#include "environment.h"
+#include "dir.h"
#include "gettext.h"
#include "parse-options.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 "run-command.h"
#include "trace.h"
#include "trace2.h"
@@ -129,8 +130,9 @@ struct fsmonitor_cookie_item {
enum fsmonitor_cookie_item_result result;
};
-static int cookies_cmp(const void *data, const struct hashmap_entry *he1,
- const struct hashmap_entry *he2, const void *keydata)
+static int cookies_cmp(const void *data UNUSED,
+ const struct hashmap_entry *he1,
+ const struct hashmap_entry *he2, const void *keydata)
{
const struct fsmonitor_cookie_item *a =
container_of(he1, const struct fsmonitor_cookie_item, entry);
@@ -1206,9 +1208,9 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
* system event listener thread so that we have the IPC handle
* before we need it.
*/
- if (ipc_server_run_async(&state->ipc_server_data,
- state->path_ipc.buf, &ipc_opts,
- handle_client, state))
+ if (ipc_server_init_async(&state->ipc_server_data,
+ state->path_ipc.buf, &ipc_opts,
+ handle_client, state))
return error_errno(
_("could not start IPC thread pool on '%s'"),
state->path_ipc.buf);
@@ -1289,7 +1291,8 @@ static int fsmonitor_run_daemon(void)
/* Prepare to (recursively) watch the <worktree-root> directory. */
strbuf_init(&state.path_worktree_watch, 0);
- strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
+ strbuf_addstr(&state.path_worktree_watch,
+ absolute_path(repo_get_work_tree(the_repository)));
state.nr_paths_watching = 1;
strbuf_init(&state.alias.alias, 0);
@@ -1309,7 +1312,9 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_gitdir_watch, "/.git");
if (!is_directory(state.path_gitdir_watch.buf)) {
strbuf_reset(&state.path_gitdir_watch);
- strbuf_addstr(&state.path_gitdir_watch, absolute_path(get_git_dir()));
+ strbuf_addstr(&state.path_gitdir_watch,
+ absolute_path(repo_get_git_dir(the_repository)));
+ strbuf_strip_suffix(&state.path_gitdir_watch, "/.");
state.nr_paths_watching = 2;
}
@@ -1412,7 +1417,7 @@ done:
return err;
}
-static int try_to_run_foreground_daemon(int detach_console)
+static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
{
/*
* Technically, we don't need to probe for an existing daemon
@@ -1442,7 +1447,8 @@ static int try_to_run_foreground_daemon(int detach_console)
static start_bg_wait_cb bg_wait_cb;
-static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+ void *cb_data UNUSED)
{
enum ipc_active_state s = fsmonitor_ipc__get_state();
@@ -1518,7 +1524,10 @@ static int try_to_start_background_daemon(void)
}
}
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+int cmd_fsmonitor__daemon(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char *subcmd;
enum fsmonitor_reason reason;
@@ -1581,7 +1590,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 UNUSED)
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED)
{
struct option options[] = {
OPT_END()
diff --git a/builtin/gc.c b/builtin/gc.c
index 719cae9a88..34848626e4 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -9,13 +9,12 @@
*
* Copyright (c) 2006 Shawn O. Pearce
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#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 "lockfile.h"
@@ -49,20 +48,7 @@ static const char * const builtin_gc_usage[] = {
NULL
};
-static int pack_refs = 1;
-static int prune_reflogs = 1;
-static int cruft_packs = 1;
-static int aggressive_depth = 50;
-static int aggressive_window = 250;
-static int gc_auto_threshold = 6700;
-static int gc_auto_pack_limit = 50;
-static int detach_auto = 1;
static timestamp_t gc_log_expire_time;
-static const char *gc_log_expire = "1.day.ago";
-static const char *prune_expire = "2.weeks.ago";
-static const char *prune_worktrees_expire = "3.months.ago";
-static unsigned long big_pack_threshold;
-static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
static struct strvec reflog = STRVEC_INIT;
static struct strvec repack = STRVEC_INIT;
@@ -122,13 +108,6 @@ static void process_log_file_at_exit(void)
process_log_file();
}
-static void process_log_file_on_signal(int signo)
-{
- process_log_file();
- sigchain_pop(signo);
- raise(signo);
-}
-
static int gc_config_is_timestamp_never(const char *var)
{
const char *value;
@@ -142,48 +121,158 @@ static int gc_config_is_timestamp_never(const char *var)
return 0;
}
-static void gc_config(void)
+struct gc_config {
+ int pack_refs;
+ int prune_reflogs;
+ int cruft_packs;
+ unsigned long max_cruft_size;
+ int aggressive_depth;
+ int aggressive_window;
+ int gc_auto_threshold;
+ int gc_auto_pack_limit;
+ int detach_auto;
+ char *gc_log_expire;
+ char *prune_expire;
+ char *prune_worktrees_expire;
+ char *repack_filter;
+ char *repack_filter_to;
+ unsigned long big_pack_threshold;
+ unsigned long max_delta_cache_size;
+};
+
+#define GC_CONFIG_INIT { \
+ .pack_refs = 1, \
+ .prune_reflogs = 1, \
+ .cruft_packs = 1, \
+ .aggressive_depth = 50, \
+ .aggressive_window = 250, \
+ .gc_auto_threshold = 6700, \
+ .gc_auto_pack_limit = 50, \
+ .detach_auto = 1, \
+ .gc_log_expire = xstrdup("1.day.ago"), \
+ .prune_expire = xstrdup("2.weeks.ago"), \
+ .prune_worktrees_expire = xstrdup("3.months.ago"), \
+ .max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \
+}
+
+static void gc_config_release(struct gc_config *cfg)
+{
+ free(cfg->gc_log_expire);
+ free(cfg->prune_expire);
+ free(cfg->prune_worktrees_expire);
+ free(cfg->repack_filter);
+ free(cfg->repack_filter_to);
+}
+
+static void gc_config(struct gc_config *cfg)
{
const char *value;
+ char *owned = NULL;
if (!git_config_get_value("gc.packrefs", &value)) {
if (value && !strcmp(value, "notbare"))
- pack_refs = -1;
+ cfg->pack_refs = -1;
else
- pack_refs = git_config_bool("gc.packrefs", value);
+ cfg->pack_refs = git_config_bool("gc.packrefs", value);
}
if (gc_config_is_timestamp_never("gc.reflogexpire") &&
gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
- prune_reflogs = 0;
+ cfg->prune_reflogs = 0;
+
+ git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window);
+ git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth);
+ git_config_get_int("gc.auto", &cfg->gc_auto_threshold);
+ git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit);
+ git_config_get_bool("gc.autodetach", &cfg->detach_auto);
+ git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs);
+ git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size);
+
+ if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) {
+ free(cfg->prune_expire);
+ cfg->prune_expire = owned;
+ }
+
+ if (!repo_config_get_expiry(the_repository, "gc.worktreepruneexpire", &owned)) {
+ free(cfg->prune_worktrees_expire);
+ cfg->prune_worktrees_expire = owned;
+ }
+
+ if (!repo_config_get_expiry(the_repository, "gc.logexpiry", &owned)) {
+ free(cfg->gc_log_expire);
+ cfg->gc_log_expire = owned;
+ }
+
+ git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
+ git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
- git_config_get_int("gc.aggressivewindow", &aggressive_window);
- git_config_get_int("gc.aggressivedepth", &aggressive_depth);
- git_config_get_int("gc.auto", &gc_auto_threshold);
- git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
- git_config_get_bool("gc.autodetach", &detach_auto);
- git_config_get_bool("gc.cruftpacks", &cruft_packs);
- git_config_get_expiry("gc.pruneexpire", &prune_expire);
- git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
- git_config_get_expiry("gc.logexpiry", &gc_log_expire);
+ if (!git_config_get_string("gc.repackfilter", &owned)) {
+ free(cfg->repack_filter);
+ cfg->repack_filter = owned;
+ }
- git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
- git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
+ if (!git_config_get_string("gc.repackfilterto", &owned)) {
+ free(cfg->repack_filter_to);
+ cfg->repack_filter_to = owned;
+ }
git_config(git_default_config, NULL);
}
-struct maintenance_run_opts;
-static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
+enum schedule_priority {
+ SCHEDULE_NONE = 0,
+ SCHEDULE_WEEKLY = 1,
+ SCHEDULE_DAILY = 2,
+ SCHEDULE_HOURLY = 3,
+};
+
+static enum schedule_priority parse_schedule(const char *value)
+{
+ if (!value)
+ return SCHEDULE_NONE;
+ if (!strcasecmp(value, "hourly"))
+ return SCHEDULE_HOURLY;
+ if (!strcasecmp(value, "daily"))
+ return SCHEDULE_DAILY;
+ if (!strcasecmp(value, "weekly"))
+ return SCHEDULE_WEEKLY;
+ return SCHEDULE_NONE;
+}
+
+struct maintenance_run_opts {
+ int auto_flag;
+ int detach;
+ int quiet;
+ enum schedule_priority schedule;
+};
+#define MAINTENANCE_RUN_OPTS_INIT { \
+ .detach = -1, \
+}
+
+static int pack_refs_condition(UNUSED struct gc_config *cfg)
+{
+ /*
+ * The auto-repacking logic for refs is handled by the ref backends and
+ * exposed via `git pack-refs --auto`. We thus always return truish
+ * here and let the backend decide for us.
+ */
+ return 1;
+}
+
+static int maintenance_task_pack_refs(struct maintenance_run_opts *opts,
+ UNUSED struct gc_config *cfg)
{
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
+ if (opts->auto_flag)
+ strvec_push(&cmd.args, "--auto");
+
return run_command(&cmd);
}
-static int too_many_loose_objects(void)
+static int too_many_loose_objects(struct gc_config *cfg)
{
/*
* Quickly check if a "gc" is needed, by estimating how
@@ -202,7 +291,7 @@ static int too_many_loose_objects(void)
if (!dir)
return 0;
- auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
+ auto_threshold = DIV_ROUND_UP(cfg->gc_auto_threshold, 256);
while ((ent = readdir(dir)) != NULL) {
if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
ent->d_name[hexsz_loose] != '\0')
@@ -238,12 +327,12 @@ static struct packed_git *find_base_packs(struct string_list *packs,
return base;
}
-static int too_many_packs(void)
+static int too_many_packs(struct gc_config *cfg)
{
struct packed_git *p;
int cnt;
- if (gc_auto_pack_limit <= 0)
+ if (cfg->gc_auto_pack_limit <= 0)
return 0;
for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
@@ -257,7 +346,7 @@ static int too_many_packs(void)
*/
cnt++;
}
- return gc_auto_pack_limit < cnt;
+ return cfg->gc_auto_pack_limit < cnt;
}
static uint64_t total_ram(void)
@@ -291,7 +380,8 @@ static uint64_t total_ram(void)
return 0;
}
-static uint64_t estimate_repack_memory(struct packed_git *pack)
+static uint64_t estimate_repack_memory(struct gc_config *cfg,
+ struct packed_git *pack)
{
unsigned long nr_objects = repo_approximate_object_count(the_repository);
size_t os_cache, heap;
@@ -328,7 +418,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
*/
heap += delta_base_cache_limit;
/* and of course pack-objects has its own delta cache */
- heap += max_delta_cache_size;
+ heap += cfg->max_delta_cache_size;
return os_cache + heap;
}
@@ -339,22 +429,31 @@ static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
return 0;
}
-static void add_repack_all_option(struct string_list *keep_pack)
+static void add_repack_all_option(struct gc_config *cfg,
+ struct string_list *keep_pack)
{
- if (prune_expire && !strcmp(prune_expire, "now"))
+ if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now"))
strvec_push(&repack, "-a");
- else if (cruft_packs) {
+ else if (cfg->cruft_packs) {
strvec_push(&repack, "--cruft");
- if (prune_expire)
- strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
+ if (cfg->prune_expire)
+ strvec_pushf(&repack, "--cruft-expiration=%s", cfg->prune_expire);
+ if (cfg->max_cruft_size)
+ strvec_pushf(&repack, "--max-cruft-size=%lu",
+ cfg->max_cruft_size);
} else {
strvec_push(&repack, "-A");
- if (prune_expire)
- strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
+ if (cfg->prune_expire)
+ strvec_pushf(&repack, "--unpack-unreachable=%s", cfg->prune_expire);
}
if (keep_pack)
for_each_string_list(keep_pack, keep_one_pack, NULL);
+
+ if (cfg->repack_filter && *cfg->repack_filter)
+ strvec_pushf(&repack, "--filter=%s", cfg->repack_filter);
+ if (cfg->repack_filter_to && *cfg->repack_filter_to)
+ strvec_pushf(&repack, "--filter-to=%s", cfg->repack_filter_to);
}
static void add_repack_incremental_option(void)
@@ -362,13 +461,13 @@ static void add_repack_incremental_option(void)
strvec_push(&repack, "--no-write-bitmap-index");
}
-static int need_to_gc(void)
+static int need_to_gc(struct gc_config *cfg)
{
/*
* Setting gc.auto to 0 or negative can disable the
* automatic gc.
*/
- if (gc_auto_threshold <= 0)
+ if (cfg->gc_auto_threshold <= 0)
return 0;
/*
@@ -377,13 +476,13 @@ static int need_to_gc(void)
* we run "repack -A -d -l". Otherwise we tell the caller
* there is no need.
*/
- if (too_many_packs()) {
+ if (too_many_packs(cfg)) {
struct string_list keep_pack = STRING_LIST_INIT_NODUP;
- if (big_pack_threshold) {
- find_base_packs(&keep_pack, big_pack_threshold);
- if (keep_pack.nr >= gc_auto_pack_limit) {
- big_pack_threshold = 0;
+ if (cfg->big_pack_threshold) {
+ find_base_packs(&keep_pack, cfg->big_pack_threshold);
+ if (keep_pack.nr >= cfg->gc_auto_pack_limit) {
+ cfg->big_pack_threshold = 0;
string_list_clear(&keep_pack, 0);
find_base_packs(&keep_pack, 0);
}
@@ -392,7 +491,7 @@ static int need_to_gc(void)
uint64_t mem_have, mem_want;
mem_have = total_ram();
- mem_want = estimate_repack_memory(p);
+ mem_want = estimate_repack_memory(cfg, p);
/*
* Only allow 1/2 of memory for pack-objects, leave
@@ -403,14 +502,14 @@ static int need_to_gc(void)
string_list_clear(&keep_pack, 0);
}
- add_repack_all_option(&keep_pack);
+ add_repack_all_option(cfg, &keep_pack);
string_list_clear(&keep_pack, 0);
- } else if (too_many_loose_objects())
+ } else if (too_many_loose_objects(cfg))
add_repack_incremental_option();
else
return 0;
- if (run_hooks("pre-auto-gc"))
+ if (run_hooks(the_repository, "pre-auto-gc"))
return 0;
return 1;
}
@@ -532,7 +631,8 @@ done:
return ret;
}
-static void gc_before_repack(void)
+static void gc_before_repack(struct maintenance_run_opts *opts,
+ struct gc_config *cfg)
{
/*
* We may be called twice, as both the pre- and
@@ -543,10 +643,10 @@ static void gc_before_repack(void)
if (done++)
return;
- if (pack_refs && maintenance_task_pack_refs(NULL))
+ if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg))
die(FAILED_RUN, "pack-refs");
- if (prune_reflogs) {
+ if (cfg->prune_reflogs) {
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
@@ -556,10 +656,12 @@ static void gc_before_repack(void)
}
}
-int cmd_gc(int argc, const char **argv, const char *prefix)
+int cmd_gc(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
{
int aggressive = 0;
- int auto_gc = 0;
int quiet = 0;
int force = 0;
const char *name;
@@ -568,16 +670,25 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int keep_largest_pack = -1;
timestamp_t dummy;
struct child_process rerere_cmd = CHILD_PROCESS_INIT;
+ struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+ struct gc_config cfg = GC_CONFIG_INIT;
+ const char *prune_expire_sentinel = "sentinel";
+ const char *prune_expire_arg = prune_expire_sentinel;
+ int ret;
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
- { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
+ { OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"),
N_("prune unreferenced objects"),
- PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
- OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
+ PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire_arg },
+ OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
- OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
+ OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL(0, "detach", &opts.detach,
+ N_("perform garbage collection in the background")),
OPT_BOOL_F(0, "force", &force,
N_("force running gc even if there may be another gc running"),
PARSE_OPT_NOCOMPLETE),
@@ -595,84 +706,103 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
strvec_pushl(&rerere, "rerere", "gc", NULL);
- /* default expiry time, overwritten in gc_config */
- gc_config();
- if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
- die(_("failed to parse gc.logExpiry value %s"), gc_log_expire);
+ gc_config(&cfg);
+
+ if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time))
+ die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
- if (pack_refs < 0)
- pack_refs = !is_bare_repository();
+ if (cfg.pack_refs < 0)
+ cfg.pack_refs = !is_bare_repository();
argc = parse_options(argc, argv, prefix, builtin_gc_options,
builtin_gc_usage, 0);
if (argc > 0)
usage_with_options(builtin_gc_usage, builtin_gc_options);
- if (prune_expire && parse_expiry_date(prune_expire, &dummy))
- die(_("failed to parse prune expiry value %s"), prune_expire);
+ if (prune_expire_arg != prune_expire_sentinel) {
+ free(cfg.prune_expire);
+ cfg.prune_expire = xstrdup_or_null(prune_expire_arg);
+ }
+ if (cfg.prune_expire && parse_expiry_date(cfg.prune_expire, &dummy))
+ die(_("failed to parse prune expiry value %s"), cfg.prune_expire);
if (aggressive) {
strvec_push(&repack, "-f");
- if (aggressive_depth > 0)
- strvec_pushf(&repack, "--depth=%d", aggressive_depth);
- if (aggressive_window > 0)
- strvec_pushf(&repack, "--window=%d", aggressive_window);
+ if (cfg.aggressive_depth > 0)
+ strvec_pushf(&repack, "--depth=%d", cfg.aggressive_depth);
+ if (cfg.aggressive_window > 0)
+ strvec_pushf(&repack, "--window=%d", cfg.aggressive_window);
}
if (quiet)
strvec_push(&repack, "-q");
- if (auto_gc) {
+ if (opts.auto_flag) {
+ if (cfg.detach_auto && opts.detach < 0)
+ opts.detach = 1;
+
/*
* Auto-gc should be least intrusive as possible.
*/
- if (!need_to_gc())
- return 0;
+ if (!need_to_gc(&cfg)) {
+ ret = 0;
+ goto out;
+ }
+
if (!quiet) {
- if (detach_auto)
+ if (opts.detach > 0)
fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
else
fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
}
- if (detach_auto) {
- int ret = report_last_gc_error();
-
- if (ret == 1)
- /* Last gc --auto failed. Skip this one. */
- return 0;
- else if (ret)
- /* an I/O error occurred, already reported */
- return ret;
-
- if (lock_repo_for_gc(force, &pid))
- return 0;
- gc_before_repack(); /* dies on failure */
- delete_tempfile(&pidfile);
-
- /*
- * failure to daemonize is ok, we'll continue
- * in foreground
- */
- daemonized = !daemonize();
- }
} else {
struct string_list keep_pack = STRING_LIST_INIT_NODUP;
if (keep_largest_pack != -1) {
if (keep_largest_pack)
find_base_packs(&keep_pack, 0);
- } else if (big_pack_threshold) {
- find_base_packs(&keep_pack, big_pack_threshold);
+ } else if (cfg.big_pack_threshold) {
+ find_base_packs(&keep_pack, cfg.big_pack_threshold);
}
- add_repack_all_option(&keep_pack);
+ add_repack_all_option(&cfg, &keep_pack);
string_list_clear(&keep_pack, 0);
}
+ if (opts.detach > 0) {
+ ret = report_last_gc_error();
+ if (ret == 1) {
+ /* Last gc --auto failed. Skip this one. */
+ ret = 0;
+ goto out;
+
+ } else if (ret) {
+ /* an I/O error occurred, already reported */
+ goto out;
+ }
+
+ if (lock_repo_for_gc(force, &pid)) {
+ ret = 0;
+ goto out;
+ }
+
+ gc_before_repack(&opts, &cfg); /* dies on failure */
+ delete_tempfile(&pidfile);
+
+ /*
+ * failure to daemonize is ok, we'll continue
+ * in foreground
+ */
+ daemonized = !daemonize();
+ }
+
name = lock_repo_for_gc(force, &pid);
if (name) {
- if (auto_gc)
- return 0; /* be quiet on --auto */
+ if (opts.auto_flag) {
+ ret = 0;
+ goto out; /* be quiet on --auto */
+ }
+
die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
name, (uintmax_t)pid);
}
@@ -682,11 +812,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
git_path("gc.log"),
LOCK_DIE_ON_ERROR);
dup2(get_lock_file_fd(&log_lock), 2);
- sigchain_push_common(process_log_file_on_signal);
atexit(process_log_file_at_exit);
}
- gc_before_repack();
+ gc_before_repack(&opts, &cfg);
if (!repository_format_precious_objects) {
struct child_process repack_cmd = CHILD_PROCESS_INIT;
@@ -697,11 +826,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (run_command(&repack_cmd))
die(FAILED_RUN, repack.v[0]);
- if (prune_expire) {
+ if (cfg.prune_expire) {
struct child_process prune_cmd = CHILD_PROCESS_INIT;
/* run `git prune` even if using cruft packs */
- strvec_push(&prune, prune_expire);
+ strvec_push(&prune, cfg.prune_expire);
if (quiet)
strvec_push(&prune, "--no-progress");
if (repo_has_promisor_remote(the_repository))
@@ -714,10 +843,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
}
}
- if (prune_worktrees_expire) {
+ if (cfg.prune_worktrees_expire) {
struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT;
- strvec_push(&prune_worktrees, prune_worktrees_expire);
+ strvec_push(&prune_worktrees, cfg.prune_worktrees_expire);
prune_worktrees_cmd.git_cmd = 1;
strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v);
if (run_command(&prune_worktrees_cmd))
@@ -741,13 +870,15 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
NULL);
- if (auto_gc && too_many_loose_objects())
+ if (opts.auto_flag && too_many_loose_objects(&cfg))
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));
if (!daemonized)
unlink(git_path("gc.log"));
+out:
+ gc_config_release(&cfg);
return 0;
}
@@ -756,26 +887,6 @@ static const char *const builtin_maintenance_run_usage[] = {
NULL
};
-enum schedule_priority {
- SCHEDULE_NONE = 0,
- SCHEDULE_WEEKLY = 1,
- SCHEDULE_DAILY = 2,
- SCHEDULE_HOURLY = 3,
-};
-
-static enum schedule_priority parse_schedule(const char *value)
-{
- if (!value)
- return SCHEDULE_NONE;
- if (!strcasecmp(value, "hourly"))
- return SCHEDULE_HOURLY;
- if (!strcasecmp(value, "daily"))
- return SCHEDULE_DAILY;
- if (!strcasecmp(value, "weekly"))
- return SCHEDULE_WEEKLY;
- return SCHEDULE_NONE;
-}
-
static int maintenance_opt_schedule(const struct option *opt, const char *arg,
int unset)
{
@@ -792,12 +903,6 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
return 0;
}
-struct maintenance_run_opts {
- int auto_flag;
- int quiet;
- enum schedule_priority schedule;
-};
-
/* Remember to update object flag allocation in object.h */
#define SEEN (1u<<0)
@@ -807,6 +912,7 @@ struct cg_auto_data {
};
static int dfs_on_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data)
@@ -817,7 +923,7 @@ static int dfs_on_ref(const char *refname UNUSED,
struct commit_list *stack = NULL;
struct commit *commit;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
return 0;
@@ -863,7 +969,7 @@ static int dfs_on_ref(const char *refname UNUSED,
return result;
}
-static int should_write_commit_graph(void)
+static int should_write_commit_graph(struct gc_config *cfg UNUSED)
{
int result;
struct cg_auto_data data;
@@ -878,7 +984,8 @@ static int should_write_commit_graph(void)
if (data.limit < 0)
return 1;
- result = for_each_ref(dfs_on_ref, &data);
+ result = refs_for_each_ref(get_main_ref_store(the_repository),
+ dfs_on_ref, &data);
repo_clear_commit_marks(the_repository, SEEN);
@@ -899,7 +1006,8 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts)
return !!run_command(&child);
}
-static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
+static int maintenance_task_commit_graph(struct maintenance_run_opts *opts,
+ struct gc_config *cfg UNUSED)
{
prepare_repo_settings(the_repository);
if (!the_repository->settings.core_commit_graph)
@@ -933,7 +1041,8 @@ static int fetch_remote(struct remote *remote, void *cbdata)
return !!run_command(&child);
}
-static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
+static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
+ struct gc_config *cfg UNUSED)
{
if (for_each_remote(fetch_remote, opts)) {
error(_("failed to prefetch remotes"));
@@ -943,7 +1052,8 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
return 0;
}
-static int maintenance_task_gc(struct maintenance_run_opts *opts)
+static int maintenance_task_gc(struct maintenance_run_opts *opts,
+ struct gc_config *cfg UNUSED)
{
struct child_process child = CHILD_PROCESS_INIT;
@@ -956,6 +1066,7 @@ static int maintenance_task_gc(struct maintenance_run_opts *opts)
strvec_push(&child.args, "--quiet");
else
strvec_push(&child.args, "--no-quiet");
+ strvec_push(&child.args, "--no-detach");
return run_command(&child);
}
@@ -991,7 +1102,7 @@ static int loose_object_count(const struct object_id *oid UNUSED,
return 0;
}
-static int loose_object_auto_condition(void)
+static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
{
int count = 0;
@@ -1051,6 +1162,12 @@ static int pack_loose(struct maintenance_run_opts *opts)
pack_proc.in = -1;
+ /*
+ * git-pack-objects(1) ends up writing the pack hash to stdout, which
+ * we do not care for.
+ */
+ pack_proc.out = -1;
+
if (start_command(&pack_proc)) {
error(_("failed to start 'git pack-objects' process"));
return 1;
@@ -1076,12 +1193,13 @@ static int pack_loose(struct maintenance_run_opts *opts)
return result;
}
-static int maintenance_task_loose_objects(struct maintenance_run_opts *opts)
+static int maintenance_task_loose_objects(struct maintenance_run_opts *opts,
+ struct gc_config *cfg UNUSED)
{
return prune_packed(opts) || pack_loose(opts);
}
-static int incremental_repack_auto_condition(void)
+static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
{
struct packed_git *p;
int incremental_repack_auto_limit = 10;
@@ -1200,7 +1318,8 @@ static int multi_pack_index_repack(struct maintenance_run_opts *opts)
return 0;
}
-static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts)
+static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts,
+ struct gc_config *cfg UNUSED)
{
prepare_repo_settings(the_repository);
if (!the_repository->settings.core_multi_pack_index) {
@@ -1217,14 +1336,15 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
return 0;
}
-typedef int maintenance_task_fn(struct maintenance_run_opts *opts);
+typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
+ struct gc_config *cfg);
/*
* An auto condition function returns 1 if the task should run
* and 0 if the task should NOT run. See needs_to_gc() for an
* example.
*/
-typedef int maintenance_auto_fn(void);
+typedef int maintenance_auto_fn(struct gc_config *cfg);
struct maintenance_task {
const char *name;
@@ -1279,7 +1399,7 @@ static struct maintenance_task tasks[] = {
[TASK_PACK_REFS] = {
"pack-refs",
maintenance_task_pack_refs,
- NULL,
+ pack_refs_condition,
},
};
@@ -1291,7 +1411,8 @@ static int compare_tasks_by_selection(const void *a_, const void *b_)
return b->selected_order - a->selected_order;
}
-static int maintenance_run_tasks(struct maintenance_run_opts *opts)
+static int maintenance_run_tasks(struct maintenance_run_opts *opts,
+ struct gc_config *cfg)
{
int i, found_selected = 0;
int result = 0;
@@ -1315,6 +1436,13 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
}
free(lock_path);
+ /* Failure to daemonize is ok, we'll continue in foreground. */
+ if (opts->detach > 0) {
+ trace2_region_enter("maintenance", "detach", the_repository);
+ daemonize();
+ trace2_region_leave("maintenance", "detach", the_repository);
+ }
+
for (i = 0; !found_selected && i < TASK__COUNT; i++)
found_selected = tasks[i].selected_order >= 0;
@@ -1330,14 +1458,14 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
if (opts->auto_flag &&
(!tasks[i].auto_condition ||
- !tasks[i].auto_condition()))
+ !tasks[i].auto_condition(cfg)))
continue;
if (opts->schedule && tasks[i].schedule < opts->schedule)
continue;
trace2_region_enter("maintenance", tasks[i].name, r);
- if (tasks[i].fn(opts)) {
+ if (tasks[i].fn(opts, cfg)) {
error(_("task '%s' failed"), tasks[i].name);
result = 1;
}
@@ -1350,9 +1478,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
static void initialize_maintenance_strategy(void)
{
- char *config_str;
+ const char *config_str;
- if (git_config_get_string("maintenance.strategy", &config_str))
+ if (git_config_get_string_tmp("maintenance.strategy", &config_str))
return;
if (!strcasecmp(config_str, "incremental")) {
@@ -1374,7 +1502,6 @@ static void initialize_task_config(int schedule)
{
int i;
struct strbuf config_name = STRBUF_INIT;
- gc_config();
if (schedule)
initialize_maintenance_strategy();
@@ -1403,7 +1530,7 @@ static void initialize_task_config(int schedule)
strbuf_release(&config_name);
}
-static int task_option_parse(const struct option *opt,
+static int task_option_parse(const struct option *opt UNUSED,
const char *arg, int unset)
{
int i, num_selected = 0;
@@ -1437,10 +1564,13 @@ static int task_option_parse(const struct option *opt,
static int maintenance_run(int argc, const char **argv, const char *prefix)
{
int i;
- struct maintenance_run_opts opts;
+ struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+ struct gc_config cfg = GC_CONFIG_INIT;
struct option builtin_maintenance_run_options[] = {
OPT_BOOL(0, "auto", &opts.auto_flag,
N_("run tasks based on the state of the repository")),
+ OPT_BOOL(0, "detach", &opts.detach,
+ N_("perform maintenance in the background")),
OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"),
N_("run tasks based on frequency"),
maintenance_opt_schedule),
@@ -1451,7 +1581,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
PARSE_OPT_NONEG, task_option_parse),
OPT_END()
};
- memset(&opts, 0, sizeof(opts));
+ int ret;
opts.quiet = !isatty(2);
@@ -1466,12 +1596,16 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
if (opts.auto_flag && opts.schedule)
die(_("use at most one of --auto and --schedule=<frequency>"));
+ gc_config(&cfg);
initialize_task_config(opts.schedule);
if (argc != 0)
usage_with_options(builtin_maintenance_run_usage,
builtin_maintenance_run_options);
- return maintenance_run_tasks(&opts);
+
+ ret = maintenance_run_tasks(&opts, &cfg);
+ gc_config_release(&cfg);
+ return ret;
}
static char *get_maintpath(void)
@@ -1526,19 +1660,18 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
if (!found) {
int rc;
- char *user_config = NULL, *xdg_config = NULL;
+ char *global_config_file = NULL;
if (!config_file) {
- git_global_config(&user_config, &xdg_config);
- config_file = user_config;
- if (!user_config)
- die(_("$HOME not set"));
+ global_config_file = git_global_config();
+ config_file = global_config_file;
}
+ if (!config_file)
+ die(_("$HOME not set"));
rc = git_config_set_multivar_in_file_gently(
config_file, "maintenance.repo", maintpath,
- CONFIG_REGEX_NONE, 0);
- free(user_config);
- free(xdg_config);
+ CONFIG_REGEX_NONE, NULL, 0);
+ free(global_config_file);
if (rc)
die(_("unable to add '%s' value of '%s'"),
@@ -1595,18 +1728,18 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
if (found) {
int rc;
- char *user_config = NULL, *xdg_config = NULL;
+ char *global_config_file = NULL;
+
if (!config_file) {
- git_global_config(&user_config, &xdg_config);
- config_file = user_config;
- if (!user_config)
- die(_("$HOME not set"));
+ global_config_file = git_global_config();
+ config_file = global_config_file;
}
+ if (!config_file)
+ die(_("$HOME not set"));
rc = git_config_set_multivar_in_file_gently(
- config_file, key, NULL, maintpath,
+ config_file, key, NULL, maintpath, NULL,
CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
- free(user_config);
- free(xdg_config);
+ free(global_config_file);
if (rc &&
(!force || rc == CONFIG_NOTHING_SET))
@@ -1635,6 +1768,42 @@ static const char *get_frequency(enum schedule_priority schedule)
}
}
+static const char *extraconfig[] = {
+ "credential.interactive=false",
+ "core.askPass=true", /* 'true' returns success, but no output. */
+ NULL
+};
+
+static const char *get_extra_config_parameters(void) {
+ static const char *result = NULL;
+ struct strbuf builder = STRBUF_INIT;
+
+ if (result)
+ return result;
+
+ for (const char **s = extraconfig; s && *s; s++)
+ strbuf_addf(&builder, "-c %s ", *s);
+
+ result = strbuf_detach(&builder, NULL);
+ return result;
+}
+
+static const char *get_extra_launchctl_strings(void) {
+ static const char *result = NULL;
+ struct strbuf builder = STRBUF_INIT;
+
+ if (result)
+ return result;
+
+ for (const char **s = extraconfig; s && *s; s++) {
+ strbuf_addstr(&builder, "<string>-c</string>\n");
+ strbuf_addf(&builder, "<string>%s</string>\n", *s);
+ }
+
+ result = strbuf_detach(&builder, NULL);
+ return result;
+}
+
/*
* get_schedule_cmd` reads the GIT_TEST_MAINT_SCHEDULER environment variable
* to mock the schedulers that `git maintenance start` rely on.
@@ -1649,39 +1818,43 @@ static const char *get_frequency(enum schedule_priority schedule)
* * If $GIT_TEST_MAINT_SCHEDULER is set, return true.
* In this case, the *cmd value is read as input.
*
- * * if the input value *cmd is the key of one of the comma-separated list
- * item, then *is_available is set to true and *cmd is modified and becomes
+ * * if the input value cmd is the key of one of the comma-separated list
+ * item, then *is_available is set to true and *out is set to
* the mock command.
*
* * if the input value *cmd isn’t the key of any of the comma-separated list
- * item, then *is_available is set to false.
+ * item, then *is_available is set to false and *out is set to the original
+ * command.
*
* Ex.:
* GIT_TEST_MAINT_SCHEDULER not set
* +-------+-------------------------------------------------+
* | Input | Output |
- * | *cmd | return code | *cmd | *is_available |
+ * | *cmd | return code | *out | *is_available |
* +-------+-------------+-------------------+---------------+
- * | "foo" | false | "foo" (unchanged) | (unchanged) |
+ * | "foo" | false | "foo" (allocated) | (unchanged) |
* +-------+-------------+-------------------+---------------+
*
* GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.shâ€
* +-------+-------------------------------------------------+
* | Input | Output |
- * | *cmd | return code | *cmd | *is_available |
+ * | *cmd | return code | *out | *is_available |
* +-------+-------------+-------------------+---------------+
* | "foo" | true | "./mock.foo.sh" | true |
- * | "qux" | true | "qux" (unchanged) | false |
+ * | "qux" | true | "qux" (allocated) | false |
* +-------+-------------+-------------------+---------------+
*/
-static int get_schedule_cmd(const char **cmd, int *is_available)
+static int get_schedule_cmd(const char *cmd, int *is_available, char **out)
{
char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
struct string_list_item *item;
struct string_list list = STRING_LIST_INIT_NODUP;
- if (!testing)
+ if (!testing) {
+ if (out)
+ *out = xstrdup(cmd);
return 0;
+ }
if (is_available)
*is_available = 0;
@@ -1693,26 +1866,40 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
continue;
- if (!strcmp(*cmd, pair.items[0].string)) {
- *cmd = pair.items[1].string;
+ if (!strcmp(cmd, pair.items[0].string)) {
+ if (out)
+ *out = xstrdup(pair.items[1].string);
if (is_available)
*is_available = 1;
- string_list_clear(&list, 0);
- UNLEAK(testing);
- return 1;
+ string_list_clear(&pair, 0);
+ goto out;
}
+
+ string_list_clear(&pair, 0);
}
+ if (out)
+ *out = xstrdup(cmd);
+
+out:
string_list_clear(&list, 0);
free(testing);
return 1;
}
+static int get_random_minute(void)
+{
+ /* Use a static value when under tests. */
+ if (getenv("GIT_TEST_MAINT_SCHEDULER"))
+ return 13;
+
+ return git_rand() % 60;
+}
+
static int is_launchctl_available(void)
{
- const char *cmd = "launchctl";
int is_available;
- if (get_schedule_cmd(&cmd, &is_available))
+ if (get_schedule_cmd("launchctl", &is_available, NULL))
return is_available;
#ifdef __APPLE__
@@ -1750,12 +1937,12 @@ static char *launchctl_get_uid(void)
static int launchctl_boot_plist(int enable, const char *filename)
{
- const char *cmd = "launchctl";
+ char *cmd;
int result;
struct child_process child = CHILD_PROCESS_INIT;
char *uid = launchctl_get_uid();
- get_schedule_cmd(&cmd, NULL);
+ get_schedule_cmd("launchctl", NULL, &cmd);
strvec_split(&child.args, cmd);
strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid,
filename, NULL);
@@ -1768,6 +1955,7 @@ static int launchctl_boot_plist(int enable, const char *filename)
result = finish_command(&child);
+ free(cmd);
free(uid);
return result;
}
@@ -1819,9 +2007,10 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
static unsigned long lock_file_timeout_ms = ULONG_MAX;
struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
struct stat st;
- const char *cmd = "launchctl";
+ char *cmd;
+ int minute = get_random_minute();
- get_schedule_cmd(&cmd, NULL);
+ get_schedule_cmd("launchctl", NULL, &cmd);
preamble = "<?xml version=\"1.0\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">"
@@ -1831,7 +2020,9 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
"<array>\n"
"<string>%s/git</string>\n"
"<string>--exec-path=%s</string>\n"
+ "%s" /* For extra config parameters. */
"<string>for-each-repo</string>\n"
+ "<string>--keep-going</string>\n"
"<string>--config=maintenance.repo</string>\n"
"<string>maintenance</string>\n"
"<string>run</string>\n"
@@ -1839,35 +2030,37 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
"</array>\n"
"<key>StartCalendarInterval</key>\n"
"<array>\n";
- strbuf_addf(&plist, preamble, name, exec_path, exec_path, frequency);
+ strbuf_addf(&plist, preamble, name, exec_path, exec_path,
+ get_extra_launchctl_strings(), frequency);
switch (schedule) {
case SCHEDULE_HOURLY:
repeat = "<dict>\n"
"<key>Hour</key><integer>%d</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
"</dict>\n";
for (i = 1; i <= 23; i++)
- strbuf_addf(&plist, repeat, i);
+ strbuf_addf(&plist, repeat, i, minute);
break;
case SCHEDULE_DAILY:
repeat = "<dict>\n"
"<key>Day</key><integer>%d</integer>\n"
"<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
"</dict>\n";
for (i = 1; i <= 6; i++)
- strbuf_addf(&plist, repeat, i);
+ strbuf_addf(&plist, repeat, i, minute);
break;
case SCHEDULE_WEEKLY:
- strbuf_addstr(&plist,
- "<dict>\n"
- "<key>Day</key><integer>0</integer>\n"
- "<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
- "</dict>\n");
+ strbuf_addf(&plist,
+ "<dict>\n"
+ "<key>Day</key><integer>0</integer>\n"
+ "<key>Hour</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
+ "</dict>\n",
+ minute);
break;
default:
@@ -1909,6 +2102,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
free(filename);
free(name);
+ free(cmd);
strbuf_release(&plist);
strbuf_release(&plist2);
return 0;
@@ -1923,7 +2117,7 @@ static int launchctl_add_plists(void)
launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY);
}
-static int launchctl_update_schedule(int run_maintenance, int fd)
+static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return launchctl_add_plists();
@@ -1933,9 +2127,8 @@ static int launchctl_update_schedule(int run_maintenance, int fd)
static int is_schtasks_available(void)
{
- const char *cmd = "schtasks";
int is_available;
- if (get_schedule_cmd(&cmd, &is_available))
+ if (get_schedule_cmd("schtasks", &is_available, NULL))
return is_available;
#ifdef GIT_WINDOWS_NATIVE
@@ -1954,15 +2147,16 @@ static char *schtasks_task_name(const char *frequency)
static int schtasks_remove_task(enum schedule_priority schedule)
{
- const char *cmd = "schtasks";
+ char *cmd;
struct child_process child = CHILD_PROCESS_INIT;
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
- get_schedule_cmd(&cmd, NULL);
+ get_schedule_cmd("schtasks", NULL, &cmd);
strvec_split(&child.args, cmd);
strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL);
free(name);
+ free(cmd);
return run_command(&child);
}
@@ -1976,7 +2170,7 @@ static int schtasks_remove_tasks(void)
static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule)
{
- const char *cmd = "schtasks";
+ char *cmd;
int result;
struct child_process child = CHILD_PROCESS_INIT;
const char *xml;
@@ -1984,11 +2178,12 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
struct strbuf tfilename = STRBUF_INIT;
+ int minute = get_random_minute();
- get_schedule_cmd(&cmd, NULL);
+ get_schedule_cmd("schtasks", NULL, &cmd);
strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX",
- get_git_common_dir(), frequency);
+ repo_get_common_dir(the_repository), frequency);
tfile = xmks_tempfile(tfilename.buf);
strbuf_release(&tfilename);
@@ -2004,7 +2199,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
switch (schedule) {
case SCHEDULE_HOURLY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T01:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T01:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByDay>\n"
"<DaysInterval>1</DaysInterval>\n"
@@ -2013,12 +2208,13 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Interval>PT1H</Interval>\n"
"<Duration>PT23H</Duration>\n"
"<StopAtDurationEnd>false</StopAtDurationEnd>\n"
- "</Repetition>\n");
+ "</Repetition>\n",
+ minute);
break;
case SCHEDULE_DAILY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
@@ -2030,19 +2226,21 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Saturday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
- "</ScheduleByWeek>\n");
+ "</ScheduleByWeek>\n",
+ minute);
break;
case SCHEDULE_WEEKLY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
"<Sunday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
- "</ScheduleByWeek>\n");
+ "</ScheduleByWeek>\n",
+ minute);
break;
default:
@@ -2069,11 +2267,12 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Actions Context=\"Author\">\n"
"<Exec>\n"
"<Command>\"%s\\headless-git.exe\"</Command>\n"
- "<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
+ "<Arguments>--exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
"</Exec>\n"
"</Actions>\n"
"</Task>\n";
- fprintf(tfile->fp, xml, exec_path, exec_path, frequency);
+ fprintf(tfile->fp, xml, exec_path, exec_path,
+ get_extra_config_parameters(), frequency);
strvec_split(&child.args, cmd);
strvec_pushl(&child.args, "/create", "/tn", name, "/f", "/xml",
get_tempfile_path(tfile), NULL);
@@ -2088,6 +2287,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
delete_tempfile(&tfile);
free(name);
+ free(cmd);
return result;
}
@@ -2100,7 +2300,7 @@ static int schtasks_schedule_tasks(void)
schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY);
}
-static int schtasks_update_schedule(int run_maintenance, int fd)
+static int schtasks_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return schtasks_schedule_tasks();
@@ -2129,21 +2329,28 @@ static int check_crontab_process(const char *cmd)
static int is_crontab_available(void)
{
- const char *cmd = "crontab";
+ char *cmd;
int is_available;
+ int ret;
- if (get_schedule_cmd(&cmd, &is_available))
- return is_available;
+ if (get_schedule_cmd("crontab", &is_available, &cmd)) {
+ ret = is_available;
+ goto out;
+ }
#ifdef __APPLE__
/*
* macOS has cron, but it requires special permissions and will
* create a UI alert when attempting to run this command.
*/
- return 0;
+ ret = 0;
#else
- return check_crontab_process(cmd);
+ ret = check_crontab_process(cmd);
#endif
+
+out:
+ free(cmd);
+ return ret;
}
#define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
@@ -2151,7 +2358,7 @@ static int is_crontab_available(void)
static int crontab_update_schedule(int run_maintenance, int fd)
{
- const char *cmd = "crontab";
+ char *cmd;
int result = 0;
int in_old_region = 0;
struct child_process crontab_list = CHILD_PROCESS_INIT;
@@ -2159,16 +2366,19 @@ static int crontab_update_schedule(int run_maintenance, int fd)
FILE *cron_list, *cron_in;
struct strbuf line = STRBUF_INIT;
struct tempfile *tmpedit = NULL;
+ int minute = get_random_minute();
- get_schedule_cmd(&cmd, NULL);
+ get_schedule_cmd("crontab", NULL, &cmd);
strvec_split(&crontab_list.args, cmd);
strvec_push(&crontab_list.args, "-l");
crontab_list.in = -1;
crontab_list.out = dup(fd);
crontab_list.git_cmd = 0;
- if (start_command(&crontab_list))
- return error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
+ if (start_command(&crontab_list)) {
+ result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
+ goto out;
+ }
/* Ignore exit code, as an empty crontab will return error. */
finish_command(&crontab_list);
@@ -2213,11 +2423,11 @@ static int crontab_update_schedule(int run_maintenance, int fd)
"# replaced in the future by a Git command.\n\n");
strbuf_addf(&line_format,
- "%%s %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
- exec_path, exec_path);
- fprintf(cron_in, line_format.buf, "0", "1-23", "*", "hourly");
- fprintf(cron_in, line_format.buf, "0", "0", "1-6", "daily");
- fprintf(cron_in, line_format.buf, "0", "0", "0", "weekly");
+ "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
+ exec_path, exec_path, get_extra_config_parameters());
+ fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
+ fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
+ fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
strbuf_release(&line_format);
fprintf(cron_in, "\n%s\n", END_LINE);
@@ -2238,8 +2448,10 @@ static int crontab_update_schedule(int run_maintenance, int fd)
result = error(_("'crontab' died"));
else
fclose(cron_list);
+
out:
delete_tempfile(&tmpedit);
+ free(cmd);
return result;
}
@@ -2262,10 +2474,9 @@ static int real_is_systemd_timer_available(void)
static int is_systemd_timer_available(void)
{
- const char *cmd = "systemctl";
int is_available;
- if (get_schedule_cmd(&cmd, &is_available))
+ if (get_schedule_cmd("systemctl", &is_available, NULL))
return is_available;
return real_is_systemd_timer_available();
@@ -2276,77 +2487,54 @@ static char *xdg_config_home_systemd(const char *filename)
return xdg_config_home_for("systemd/user", filename);
}
-static int systemd_timer_enable_unit(int enable,
- enum schedule_priority schedule)
-{
- const char *cmd = "systemctl";
- struct child_process child = CHILD_PROCESS_INIT;
- const char *frequency = get_frequency(schedule);
-
- /*
- * Disabling the systemd unit while it is already disabled makes
- * systemctl print an error.
- * Let's ignore it since it means we already are in the expected state:
- * the unit is disabled.
- *
- * On the other hand, enabling a systemd unit which is already enabled
- * produces no error.
- */
- if (!enable)
- child.no_stderr = 1;
-
- get_schedule_cmd(&cmd, NULL);
- strvec_split(&child.args, cmd);
- strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
- "--now", NULL);
- strvec_pushf(&child.args, "git-maintenance@%s.timer", frequency);
-
- if (start_command(&child))
- return error(_("failed to start systemctl"));
- if (finish_command(&child))
- /*
- * Disabling an already disabled systemd unit makes
- * systemctl fail.
- * Let's ignore this failure.
- *
- * Enabling an enabled systemd unit doesn't fail.
- */
- if (enable)
- return error(_("failed to run systemctl"));
- return 0;
-}
+#define SYSTEMD_UNIT_FORMAT "git-maintenance@%s.%s"
-static int systemd_timer_delete_unit_templates(void)
+static int systemd_timer_delete_timer_file(enum schedule_priority priority)
{
int ret = 0;
- char *filename = xdg_config_home_systemd("git-maintenance@.timer");
- if (unlink(filename) && !is_missing_file_error(errno))
- ret = error_errno(_("failed to delete '%s'"), filename);
- FREE_AND_NULL(filename);
+ const char *frequency = get_frequency(priority);
+ char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+ char *filename = xdg_config_home_systemd(local_timer_name);
- filename = xdg_config_home_systemd("git-maintenance@.service");
if (unlink(filename) && !is_missing_file_error(errno))
ret = error_errno(_("failed to delete '%s'"), filename);
free(filename);
+ free(local_timer_name);
return ret;
}
-static int systemd_timer_delete_units(void)
+static int systemd_timer_delete_service_template(void)
{
- return systemd_timer_enable_unit(0, SCHEDULE_HOURLY) ||
- systemd_timer_enable_unit(0, SCHEDULE_DAILY) ||
- systemd_timer_enable_unit(0, SCHEDULE_WEEKLY) ||
- systemd_timer_delete_unit_templates();
+ int ret = 0;
+ char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+ char *filename = xdg_config_home_systemd(local_service_name);
+ if (unlink(filename) && !is_missing_file_error(errno))
+ ret = error_errno(_("failed to delete '%s'"), filename);
+
+ free(filename);
+ free(local_service_name);
+ return ret;
}
-static int systemd_timer_write_unit_templates(const char *exec_path)
+/*
+ * Write the schedule information into a git-maintenance@<schedule>.timer
+ * file using a custom minute. This timer file cannot use the templating
+ * system, so we generate a specific file for each.
+ */
+static int systemd_timer_write_timer_file(enum schedule_priority schedule,
+ int minute)
{
+ int res = -1;
char *filename;
FILE *file;
const char *unit;
+ char *schedule_pattern = NULL;
+ const char *frequency = get_frequency(schedule);
+ char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+ filename = xdg_config_home_systemd(local_timer_name);
- filename = xdg_config_home_systemd("git-maintenance@.timer");
if (safe_create_leading_directories(filename)) {
error(_("failed to create directories for '%s'"), filename);
goto error;
@@ -2355,6 +2543,23 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
if (!file)
goto error;
+ switch (schedule) {
+ case SCHEDULE_HOURLY:
+ schedule_pattern = xstrfmt("*-*-* 1..23:%02d:00", minute);
+ break;
+
+ case SCHEDULE_DAILY:
+ schedule_pattern = xstrfmt("Tue..Sun *-*-* 0:%02d:00", minute);
+ break;
+
+ case SCHEDULE_WEEKLY:
+ schedule_pattern = xstrfmt("Mon 0:%02d:00", minute);
+ break;
+
+ default:
+ BUG("Unhandled schedule_priority");
+ }
+
unit = "# This file was created and is maintained by Git.\n"
"# Any edits made in this file might be replaced in the future\n"
"# by a Git command.\n"
@@ -2363,12 +2568,12 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"Description=Optimize Git repositories data\n"
"\n"
"[Timer]\n"
- "OnCalendar=%i\n"
+ "OnCalendar=%s\n"
"Persistent=true\n"
"\n"
"[Install]\n"
"WantedBy=timers.target\n";
- if (fputs(unit, file) == EOF) {
+ if (fprintf(file, unit, schedule_pattern) < 0) {
error(_("failed to write to '%s'"), filename);
fclose(file);
goto error;
@@ -2377,9 +2582,36 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
error_errno(_("failed to flush '%s'"), filename);
goto error;
}
+
+ res = 0;
+
+error:
+ free(schedule_pattern);
+ free(local_timer_name);
free(filename);
+ return res;
+}
- filename = xdg_config_home_systemd("git-maintenance@.service");
+/*
+ * No matter the schedule, we use the same service and can make use of the
+ * templating system. When installing git-maintenance@<schedule>.timer,
+ * systemd will notice that git-maintenance@.service exists as a template
+ * and will use this file and insert the <schedule> into the template at
+ * the position of "%i".
+ */
+static int systemd_timer_write_service_template(const char *exec_path)
+{
+ int res = -1;
+ char *filename;
+ FILE *file;
+ const char *unit;
+ char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+
+ filename = xdg_config_home_systemd(local_service_name);
+ if (safe_create_leading_directories(filename)) {
+ error(_("failed to create directories for '%s'"), filename);
+ goto error;
+ }
file = fopen_or_warn(filename, "w");
if (!file)
goto error;
@@ -2393,7 +2625,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"\n"
"[Service]\n"
"Type=oneshot\n"
- "ExecStart=\"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%i\n"
+ "ExecStart=\"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
"LockPersonality=yes\n"
"MemoryDenyWriteExecute=yes\n"
"NoNewPrivileges=yes\n"
@@ -2403,7 +2635,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"RestrictSUIDSGID=yes\n"
"SystemCallArchitectures=native\n"
"SystemCallFilter=@system-service\n";
- if (fprintf(file, unit, exec_path, exec_path) < 0) {
+ if (fprintf(file, unit, exec_path, exec_path, get_extra_config_parameters()) < 0) {
error(_("failed to write to '%s'"), filename);
fclose(file);
goto error;
@@ -2412,29 +2644,128 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
error_errno(_("failed to flush '%s'"), filename);
goto error;
}
- free(filename);
- return 0;
+
+ res = 0;
error:
+ free(local_service_name);
free(filename);
- systemd_timer_delete_unit_templates();
- return -1;
+ return res;
+}
+
+static int systemd_timer_enable_unit(int enable,
+ enum schedule_priority schedule,
+ int minute)
+{
+ char *cmd = NULL;
+ struct child_process child = CHILD_PROCESS_INIT;
+ const char *frequency = get_frequency(schedule);
+ int ret;
+
+ /*
+ * Disabling the systemd unit while it is already disabled makes
+ * systemctl print an error.
+ * Let's ignore it since it means we already are in the expected state:
+ * the unit is disabled.
+ *
+ * On the other hand, enabling a systemd unit which is already enabled
+ * produces no error.
+ */
+ if (!enable) {
+ child.no_stderr = 1;
+ } else if (systemd_timer_write_timer_file(schedule, minute)) {
+ ret = -1;
+ goto out;
+ }
+
+ get_schedule_cmd("systemctl", NULL, &cmd);
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
+ "--now", NULL);
+ strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+ if (start_command(&child)) {
+ ret = error(_("failed to start systemctl"));
+ goto out;
+ }
+
+ if (finish_command(&child)) {
+ /*
+ * Disabling an already disabled systemd unit makes
+ * systemctl fail.
+ * Let's ignore this failure.
+ *
+ * Enabling an enabled systemd unit doesn't fail.
+ */
+ if (enable) {
+ ret = error(_("failed to run systemctl"));
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+out:
+ free(cmd);
+ return ret;
+}
+
+/*
+ * A previous version of Git wrote the timer units as template files.
+ * Clean these up, if they exist.
+ */
+static void systemd_timer_delete_stale_timer_templates(void)
+{
+ char *timer_template_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "timer");
+ char *filename = xdg_config_home_systemd(timer_template_name);
+
+ if (unlink(filename) && !is_missing_file_error(errno))
+ warning(_("failed to delete '%s'"), filename);
+
+ free(filename);
+ free(timer_template_name);
+}
+
+static int systemd_timer_delete_unit_files(void)
+{
+ systemd_timer_delete_stale_timer_templates();
+
+ /* Purposefully not short-circuited to make sure all are called. */
+ return systemd_timer_delete_timer_file(SCHEDULE_HOURLY) |
+ systemd_timer_delete_timer_file(SCHEDULE_DAILY) |
+ systemd_timer_delete_timer_file(SCHEDULE_WEEKLY) |
+ systemd_timer_delete_service_template();
+}
+
+static int systemd_timer_delete_units(void)
+{
+ int minute = get_random_minute();
+ /* Purposefully not short-circuited to make sure all are called. */
+ return systemd_timer_enable_unit(0, SCHEDULE_HOURLY, minute) |
+ systemd_timer_enable_unit(0, SCHEDULE_DAILY, minute) |
+ systemd_timer_enable_unit(0, SCHEDULE_WEEKLY, minute) |
+ systemd_timer_delete_unit_files();
}
static int systemd_timer_setup_units(void)
{
+ int minute = get_random_minute();
const char *exec_path = git_exec_path();
- int ret = systemd_timer_write_unit_templates(exec_path) ||
- systemd_timer_enable_unit(1, SCHEDULE_HOURLY) ||
- systemd_timer_enable_unit(1, SCHEDULE_DAILY) ||
- systemd_timer_enable_unit(1, SCHEDULE_WEEKLY);
+ int ret = systemd_timer_write_service_template(exec_path) ||
+ systemd_timer_enable_unit(1, SCHEDULE_HOURLY, minute) ||
+ systemd_timer_enable_unit(1, SCHEDULE_DAILY, minute) ||
+ systemd_timer_enable_unit(1, SCHEDULE_WEEKLY, minute);
+
if (ret)
systemd_timer_delete_units();
+ else
+ systemd_timer_delete_stale_timer_templates();
+
return ret;
}
-static int systemd_timer_update_schedule(int run_maintenance, int fd)
+static int systemd_timer_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return systemd_timer_setup_units();
@@ -2559,8 +2890,17 @@ static int update_background_schedule(const struct maintenance_start_opts *opts,
char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
+ if (errno == EEXIST)
+ error(_("unable to create '%s.lock': %s.\n\n"
+ "Another scheduled git-maintenance(1) process seems to be running in this\n"
+ "repository. Please make sure no other maintenance processes are running and\n"
+ "then try again. If it still fails, a git-maintenance(1) process may have\n"
+ "crashed in this repository earlier: remove the file manually to continue."),
+ absolute_path(lock_path), strerror(errno));
+ else
+ error_errno(_("cannot acquire lock for scheduled background maintenance"));
free(lock_path);
- return error(_("another process is scheduling background maintenance"));
+ return -1;
}
for (i = 1; i < ARRAY_SIZE(scheduler_fn); i++) {
@@ -2606,9 +2946,12 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
opts.scheduler = resolve_scheduler(opts.scheduler);
validate_scheduler(opts.scheduler);
+ if (update_background_schedule(&opts, 1))
+ die(_("failed to set up maintenance schedule"));
+
if (maintenance_register(ARRAY_SIZE(register_args)-1, register_args, NULL))
warning(_("failed to add repo to global config"));
- return update_background_schedule(&opts, 1);
+ return 0;
}
static const char *const builtin_maintenance_stop_usage[] = {
@@ -2633,7 +2976,10 @@ static const char * const builtin_maintenance_usage[] = {
NULL,
};
-int cmd_maintenance(int argc, const char **argv, const char *prefix)
+int cmd_maintenance(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option builtin_maintenance_options[] = {
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 20d0dfe9cf..6bec0d1854 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -4,7 +4,6 @@
#include "builtin.h"
#include "commit.h"
#include "tar.h"
-#include "quote.h"
static const char builtin_get_tar_commit_id_usage[] =
"git get-tar-commit-id";
@@ -13,7 +12,10 @@ 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 UNUSED, const char *prefix)
+int cmd_get_tar_commit_id(int argc,
+ const char **argv UNUSED,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
char buffer[HEADERSIZE];
struct ustar_header *header = (struct ustar_header *)buffer;
@@ -36,6 +38,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix
if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER)
return 1;
+ errno = 0;
len = strtol(content, &end, 10);
if (errno == ERANGE || end == content || len < 0)
return 1;
diff --git a/builtin/grep.c b/builtin/grep.c
index b71222330a..98b85c7fca 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -3,20 +3,17 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "abspath.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
#include "config.h"
-#include "blob.h"
-#include "tree.h"
-#include "commit.h"
#include "tag.h"
#include "tree-walk.h"
#include "parse-options.h"
#include "string-list.h"
#include "run-command.h"
-#include "userdiff.h"
#include "grep.h"
#include "quote.h"
#include "dir.h"
@@ -530,7 +527,7 @@ static int grep_submodule(struct grep_opt *opt,
strbuf_addstr(&base, filename);
strbuf_addch(&base, '/');
- init_tree_desc(&tree, data, size);
+ init_tree_desc(&tree, oid, data, size);
hit = grep_tree(&subopt, pathspec, &tree, &base, base.len,
object_type == OBJ_COMMIT);
strbuf_release(&base);
@@ -574,7 +571,9 @@ static int grep_cache(struct grep_opt *opt,
data = repo_read_object_file(the_repository, &ce->oid,
&type, &size);
- init_tree_desc(&tree, data, size);
+ if (!data)
+ die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
+ init_tree_desc(&tree, &ce->oid, data, size);
hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
strbuf_setlen(&name, name_base_len);
@@ -670,7 +669,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
oid_to_hex(&entry.oid));
strbuf_addch(base, '/');
- init_tree_desc(&sub, data, size);
+ init_tree_desc(&sub, &entry.oid, data, size);
hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
check_attr);
free(data);
@@ -714,7 +713,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
strbuf_add(&base, name, len);
strbuf_addch(&base, ':');
}
- init_tree_desc(&tree, data, size);
+ init_tree_desc(&tree, &obj->oid, data, size);
hit = grep_tree(opt, pathspec, &tree, &base, base.len,
obj->type == OBJ_COMMIT);
strbuf_release(&base);
@@ -812,14 +811,20 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
int from_stdin;
+ const char *filename = arg;
FILE *patterns;
int lno = 0;
struct strbuf sb = STRBUF_INIT;
BUG_ON_OPT_NEG(unset);
- from_stdin = !strcmp(arg, "-");
- patterns = from_stdin ? stdin : fopen(arg, "r");
+ if (!*filename)
+ ; /* leave it as-is */
+ else
+ filename = prefix_filename_except_for_dash(grep_prefix, filename);
+
+ from_stdin = !strcmp(filename, "-");
+ patterns = from_stdin ? stdin : fopen(filename, "r");
if (!patterns)
die_errno(_("cannot open '%s'"), arg);
while (strbuf_getline(&sb, patterns) == 0) {
@@ -833,6 +838,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
if (!from_stdin)
fclose(patterns);
strbuf_release(&sb);
+ if (filename != arg)
+ free((void *)filename);
return 0;
}
@@ -881,7 +888,10 @@ static int pattern_callback(const struct option *opt, const char *arg,
return 0;
}
-int cmd_grep(int argc, const char **argv, const char *prefix)
+int cmd_grep(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int hit = 0;
int cached = 0, untracked = 0, opt_exclude = -1;
@@ -896,6 +906,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int dummy;
int use_index = 1;
int allow_revs;
+ int ret;
struct option options[] = {
OPT_BOOL(0, "cached", &cached,
@@ -1107,7 +1118,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
struct object_id oid;
- struct object_context oc;
+ struct object_context oc = {0};
struct object *object;
if (!strcmp(arg, "--")) {
@@ -1126,6 +1137,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
&oid, &oc)) {
if (seen_dashdash)
die(_("unable to resolve revision: %s"), arg);
+ object_context_release(&oc);
break;
}
@@ -1133,7 +1145,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!seen_dashdash)
verify_non_filename(prefix, arg);
add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
- free(oc.path);
+ object_context_release(&oc);
}
/*
@@ -1161,8 +1173,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
* Optimize out the case where the amount of matches is limited to zero.
* We do this to keep results consistent with GNU grep(1).
*/
- if (opt.max_count == 0)
- return 1;
+ if (opt.max_count == 0) {
+ ret = 1;
+ goto out;
+ }
if (show_in_pager) {
if (num_threads > 1)
@@ -1256,10 +1270,14 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
hit |= wait_all();
if (hit && show_in_pager)
run_pager(&opt, prefix);
+
+ ret = !hit;
+
+out:
clear_pathspec(&pathspec);
string_list_clear(&path_list, 0);
free_grep_patterns(&opt);
object_array_clear(&list);
free_repos();
- return !hit;
+ return ret;
}
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 5ffec99dce..a25f0403f4 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -4,6 +4,7 @@
* Copyright (C) Linus Torvalds, 2005
* Copyright (C) Junio C Hamano, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -14,7 +15,6 @@
#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"
@@ -85,7 +85,10 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
strbuf_release(&unquoted);
}
-int cmd_hash_object(int argc, const char **argv, const char *prefix)
+int cmd_hash_object(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
static const char * const hash_object_usage[] = {
N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
@@ -124,6 +127,9 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
else
prefix = setup_git_directory_gently(&nongit);
+ if (nongit && !the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
if (vpath && prefix) {
vpath_free = prefix_filename(prefix, vpath);
vpath = vpath_free;
diff --git a/builtin/help.c b/builtin/help.c
index dc1fbe2b98..6a72d991a8 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -1,6 +1,8 @@
+
/*
* Builtin help command
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "exec-cmd.h"
@@ -52,7 +54,7 @@ static enum help_action {
HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
} cmd_mode;
-static const char *html_path;
+static char *html_path;
static int verbose = 1;
static enum help_format help_format = HELP_FORMAT_NONE;
static int exclude_guides;
@@ -409,6 +411,7 @@ static int git_help_config(const char *var, const char *value,
if (!strcmp(var, "help.htmlpath")) {
if (!value)
return config_error_nonbool(var);
+ free(html_path);
html_path = xstrdup(value);
return 0;
}
@@ -513,23 +516,24 @@ static void show_info_page(const char *page)
static void get_html_page_path(struct strbuf *page_path, const char *page)
{
struct stat st;
+ const char *path = html_path;
char *to_free = NULL;
- if (!html_path)
- html_path = to_free = system_path(GIT_HTML_PATH);
+ if (!path)
+ path = to_free = system_path(GIT_HTML_PATH);
/*
* Check that the page we're looking for exists.
*/
- if (!strstr(html_path, "://")) {
- if (stat(mkpath("%s/%s.html", html_path, page), &st)
+ if (!strstr(path, "://")) {
+ if (stat(mkpath("%s/%s.html", path, page), &st)
|| !S_ISREG(st.st_mode))
die("'%s/%s.html': documentation file not found.",
- html_path, page);
+ path, page);
}
strbuf_init(page_path, 0);
- strbuf_addf(page_path, "%s/%s.html", html_path, page);
+ strbuf_addf(page_path, "%s/%s.html", path, page);
free(to_free);
}
@@ -540,19 +544,19 @@ static void open_html(const char *path)
static void show_html_page(const char *page)
{
- struct strbuf page_path; /* it leaks but we exec bellow */
+ struct strbuf page_path; /* it leaks but we exec below */
get_html_page_path(&page_path, page);
open_html(page_path.buf);
}
-static const char *check_git_cmd(const char* cmd)
+static char *check_git_cmd(const char *cmd)
{
char *alias;
if (is_git_command(cmd))
- return cmd;
+ return xstrdup(cmd);
alias = alias_lookup(cmd);
if (alias) {
@@ -585,14 +589,13 @@ static const char *check_git_cmd(const char* cmd)
die(_("bad alias.%s string: %s"), cmd,
split_cmdline_strerror(count));
free(argv);
- UNLEAK(alias);
return alias;
}
if (exclude_guides)
return help_unknown_cmd(cmd);
- return cmd;
+ return xstrdup(cmd);
}
static void no_help_format(const char *opt_mode, enum help_format fmt)
@@ -631,10 +634,14 @@ static void opt_mode_usage(int argc, const char *opt_mode,
no_help_format(opt_mode, fmt);
}
-int cmd_help(int argc, const char **argv, const char *prefix)
+int cmd_help(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int nongit;
enum help_format parsed_help_format;
+ char *command = NULL;
const char *page;
argc = parse_options(argc, argv, prefix, builtin_help_options,
@@ -706,9 +713,9 @@ int cmd_help(int argc, const char **argv, const char *prefix)
if (help_format == HELP_FORMAT_NONE)
help_format = parse_help_format(DEFAULT_HELP_FORMAT);
- argv[0] = check_git_cmd(argv[0]);
+ command = check_git_cmd(argv[0]);
- page = cmd_to_page(argv[0]);
+ page = cmd_to_page(command);
switch (help_format) {
case HELP_FORMAT_NONE:
case HELP_FORMAT_MAN:
@@ -722,5 +729,6 @@ int cmd_help(int argc, const char **argv, const char *prefix)
break;
}
+ free(command);
return 0;
}
diff --git a/builtin/hook.c b/builtin/hook.c
index 09b51a6487..367ef3e0b8 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
#include "hook.h"
#include "parse-options.h"
-#include "strbuf.h"
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
@@ -59,7 +59,7 @@ static int run(int argc, const char **argv, const char *prefix)
hook_name = argv[0];
if (!ignore_missing)
opt.error_if_missing = 1;
- ret = run_hooks_opt(hook_name, &opt);
+ ret = run_hooks_opt(the_repository, hook_name, &opt);
if (ret < 0) /* error() return */
ret = 1;
return ret;
@@ -67,7 +67,10 @@ usage:
usage_with_options(builtin_hook_run_usage, run_options);
}
-int cmd_hook(int argc, const char **argv, const char *prefix)
+int cmd_hook(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option builtin_hook_options[] = {
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 006ffdc9c5..95babdc5ea 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "delta.h"
@@ -12,7 +13,6 @@
#include "tree.h"
#include "progress.h"
#include "fsck.h"
-#include "exec-cmd.h"
#include "strbuf.h"
#include "streaming.h"
#include "thread-utils.h"
@@ -21,12 +21,17 @@
#include "object-file.h"
#include "object-store-ll.h"
#include "oid-array.h"
+#include "oidset.h"
+#include "path.h"
#include "replace-object.h"
+#include "tree-walk.h"
#include "promisor-remote.h"
+#include "run-command.h"
#include "setup.h"
+#include "strvec.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>])";
+"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict[=<msg-id>=<severity>...]] [--fsck-objects[=<msg-id>=<severity>...]] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
struct object_entry {
struct pack_idx_entry idx;
@@ -95,7 +100,7 @@ static LIST_HEAD(done_head);
static size_t base_cache_used;
static size_t base_cache_limit;
-struct thread_local {
+struct thread_local_data {
pthread_t thread;
int pack_fd;
};
@@ -118,7 +123,7 @@ static struct object_entry *objects;
static struct object_stat *obj_stat;
static struct ofs_delta_entry *ofs_deltas;
static struct ref_delta_entry *ref_deltas;
-static struct thread_local nothread_data;
+static struct thread_local_data nothread_data;
static int nr_objects;
static int nr_ofs_deltas;
static int nr_ref_deltas;
@@ -149,7 +154,14 @@ static uint32_t input_crc32;
static int input_fd, output_fd;
static const char *curr_pack;
-static struct thread_local *thread_data;
+/*
+ * local_links is guarded by read_mutex, and record_local_links is read-only in
+ * a thread.
+ */
+static struct oidset local_links = OIDSET_INIT;
+static int record_local_links;
+
+static struct thread_local_data *thread_data;
static int nr_dispatched;
static int threads_active;
@@ -391,7 +403,7 @@ static NORETURN void bad_object(off_t offset, const char *format, ...)
(uintmax_t)offset, buf);
}
-static inline struct thread_local *get_thread_data(void)
+static inline struct thread_local_data *get_thread_data(void)
{
if (HAVE_THREADS) {
if (threads_active)
@@ -402,7 +414,7 @@ static inline struct thread_local *get_thread_data(void)
return &nothread_data;
}
-static void set_thread_data(struct thread_local *data)
+static void set_thread_data(struct thread_local_data *data)
{
if (threads_active)
pthread_setspecific(key, data);
@@ -530,7 +542,8 @@ static void *unpack_raw_entry(struct object_entry *obj,
switch (obj->type) {
case OBJ_REF_DELTA:
- oidread(ref_oid, fill(the_hash_algo->rawsz));
+ oidread(ref_oid, fill(the_hash_algo->rawsz),
+ the_repository->hash_algo);
use(the_hash_algo->rawsz);
break;
case OBJ_OFS_DELTA:
@@ -799,6 +812,44 @@ static int check_collison(struct object_entry *entry)
return 0;
}
+static void record_if_local_object(const struct object_id *oid)
+{
+ struct object_info info = OBJECT_INFO_INIT;
+ if (oid_object_info_extended(the_repository, oid, &info, 0))
+ /* Missing; assume it is a promisor object */
+ return;
+ if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
+ return;
+ oidset_insert(&local_links, oid);
+}
+
+static void do_record_local_links(struct object *obj)
+{
+ if (obj->type == OBJ_TREE) {
+ struct tree *tree = (struct tree *)obj;
+ struct tree_desc desc;
+ struct name_entry entry;
+ if (init_tree_desc_gently(&desc, &tree->object.oid,
+ tree->buffer, tree->size, 0))
+ /*
+ * Error messages are given when packs are
+ * verified, so do not print any here.
+ */
+ return;
+ while (tree_entry_gently(&desc, &entry))
+ record_if_local_object(&entry.oid);
+ } else if (obj->type == OBJ_COMMIT) {
+ struct commit *commit = (struct commit *) obj;
+ struct commit_list *parents = commit->parents;
+
+ for (; parents; parents = parents->next)
+ record_if_local_object(&parents->item->object.oid);
+ } else if (obj->type == OBJ_TAG) {
+ struct tag *tag = (struct tag *) obj;
+ record_if_local_object(get_tagged_oid(tag));
+ }
+}
+
static void sha1_object(const void *data, struct object_entry *obj_entry,
unsigned long size, enum object_type type,
const struct object_id *oid)
@@ -845,7 +896,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
free(has_data);
}
- if (strict || do_fsck_object) {
+ if (strict || do_fsck_object || record_local_links) {
read_lock();
if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(the_repository, oid);
@@ -877,6 +928,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("fsck error in packed object"));
if (strict && fsck_walk(obj, NULL, &fsck_options))
die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
+ if (record_local_links)
+ do_record_local_links(obj);
if (obj->type == OBJ_TREE) {
struct tree *item = (struct tree *) obj;
@@ -1166,6 +1219,7 @@ static void parse_pack_objects(unsigned char *hash)
struct ofs_delta_entry *ofs_delta = ofs_deltas;
struct object_id ref_delta_oid;
struct stat st;
+ git_hash_ctx tmp_ctx;
if (verbose)
progress = start_progress(
@@ -1202,8 +1256,10 @@ static void parse_pack_objects(unsigned char *hash)
/* Check pack integrity */
flush();
- the_hash_algo->final_fn(hash, &input_ctx);
- if (!hasheq(fill(the_hash_algo->rawsz), hash))
+ the_hash_algo->init_fn(&tmp_ctx);
+ the_hash_algo->clone_fn(&tmp_ctx, &input_ctx);
+ the_hash_algo->final_fn(hash, &tmp_ctx);
+ if (!hasheq(fill(the_hash_algo->rawsz), hash, the_repository->hash_algo))
die(_("pack is corrupted (SHA1 mismatch)"));
use(the_hash_algo->rawsz);
@@ -1254,6 +1310,7 @@ static void resolve_deltas(void)
base_cache_limit = delta_base_cache_limit * nr_threads;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread();
+ work_lock();
for (i = 0; i < nr_threads; i++) {
int ret = pthread_create(&thread_data[i].thread, NULL,
threaded_second_pass, thread_data + i);
@@ -1261,6 +1318,7 @@ static void resolve_deltas(void)
die(_("unable to create thread: %s"),
strerror(ret));
}
+ work_unlock();
for (i = 0; i < nr_threads; i++)
pthread_join(thread_data[i].thread, NULL);
cleanup_thread();
@@ -1304,11 +1362,11 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
stop_progress_msg(&progress, msg.buf);
strbuf_release(&msg);
finalize_hashfile(f, tail_hash, FSYNC_COMPONENT_PACK, 0);
- hashcpy(read_hash, pack_hash);
+ hashcpy(read_hash, pack_hash, the_repository->hash_algo);
fixup_pack_header_footer(output_fd, pack_hash,
curr_pack, nr_objects,
read_hash, consumed_bytes-the_hash_algo->rawsz);
- if (!hasheq(read_hash, tail_hash))
+ if (!hasheq(read_hash, tail_hash, the_repository->hash_algo))
die(_("Unexpected tail checksum for %s "
"(disk corruption?)"), curr_pack);
}
@@ -1369,7 +1427,7 @@ static struct object_entry *append_obj_to_pack(struct hashfile *f,
obj[1].idx.offset += write_compressed(f, buf, size);
obj[0].idx.crc32 = crc32_end(f);
hashflush(f);
- oidread(&obj->idx.oid, sha1);
+ oidread(&obj->idx.oid, sha1, the_repository->hash_algo);
return obj;
}
@@ -1500,7 +1558,7 @@ static void rename_tmp_packfile(const char **final_name,
struct strbuf *name, unsigned char *hash,
const char *ext, int make_read_only_if_same)
{
- if (*final_name != curr_name) {
+ if (!*final_name || strcmp(*final_name, curr_name)) {
if (!*final_name)
*final_name = odb_pack_name(name, hash, ext);
if (finalize_object_file(curr_name, *final_name))
@@ -1521,14 +1579,12 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
struct strbuf pack_name = STRBUF_INIT;
struct strbuf index_name = STRBUF_INIT;
struct strbuf rev_index_name = STRBUF_INIT;
- int err;
if (!from_stdin) {
close(input_fd);
} else {
fsync_component_or_die(FSYNC_COMPONENT_PACK, output_fd, curr_pack_name);
- err = close(output_fd);
- if (err)
+ if (close(output_fd))
die_errno(_("error while closing pack file"));
}
@@ -1563,17 +1619,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
- /*
- * Let's just mimic git-unpack-objects here and write
- * the last part of the input buffer to stdout.
- */
- while (input_len) {
- err = xwrite(1, input_buffer + input_offset, input_len);
- if (err <= 0)
- break;
- input_len -= err;
- input_offset += err;
- }
+ /* Write the last part of the buffer to stdout */
+ write_in_full(1, input_buffer + input_offset, input_len);
}
strbuf_release(&rev_index_name);
@@ -1725,11 +1772,66 @@ static void show_pack_info(int stat_only)
free(chain_histogram);
}
-int cmd_index_pack(int argc, const char **argv, const char *prefix)
+static void repack_local_links(void)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+ struct oidset_iter iter;
+ struct object_id *oid;
+ char *base_name;
+
+ if (!oidset_size(&local_links))
+ return;
+
+ base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository));
+
+ strvec_push(&cmd.args, "pack-objects");
+ strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort");
+ strvec_push(&cmd.args, base_name);
+ cmd.git_cmd = 1;
+ cmd.in = -1;
+ cmd.out = -1;
+ if (start_command(&cmd))
+ die(_("could not start pack-objects to repack local links"));
+
+ oidset_iter_init(&local_links, &iter);
+ while ((oid = oidset_iter_next(&iter))) {
+ if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ write_in_full(cmd.in, "\n", 1) < 0)
+ die(_("failed to feed local object to pack-objects"));
+ }
+ close(cmd.in);
+
+ out = xfdopen(cmd.out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ unsigned char binary[GIT_MAX_RAWSZ];
+ if (line.len != the_hash_algo->hexsz ||
+ !hex_to_bytes(binary, line.buf, line.len))
+ die(_("index-pack: Expecting full hex object ID lines only from pack-objects."));
+
+ /*
+ * pack-objects creates the .pack and .idx files, but not the
+ * .promisor file. Create the .promisor file, which is empty.
+ */
+ write_special_file("promisor", "", NULL, binary, NULL);
+ }
+
+ fclose(out);
+ if (finish_command(&cmd))
+ die(_("could not finish pack-objects to repack local links"));
+ strbuf_release(&line);
+ free(base_name);
+}
+
+int cmd_index_pack(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
const char *curr_index;
- const char *curr_rev_index = NULL;
+ char *curr_rev_index = NULL;
const char *index_name = NULL, *pack_name = NULL, *rev_index_name = NULL;
const char *keep_msg = NULL;
const char *promisor_msg = NULL;
@@ -1782,8 +1884,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
} else if (!strcmp(arg, "--check-self-contained-and-connected")) {
strict = 1;
check_self_contained_and_connected = 1;
- } else if (!strcmp(arg, "--fsck-objects")) {
+ } else if (skip_to_optional_arg(arg, "--fsck-objects", &arg)) {
do_fsck_object = 1;
+ fsck_set_msg_types(&fsck_options, arg);
} else if (!strcmp(arg, "--verify")) {
verify = 1;
} else if (!strcmp(arg, "--verify-stat")) {
@@ -1796,7 +1899,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
} else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
; /* nothing to do */
} else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
- ; /* already parsed */
+ record_local_links = 1;
} else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
@@ -1867,6 +1970,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
usage(index_pack_usage);
if (fix_thin_pack && !from_stdin)
die(_("the option '%s' requires '%s'"), "--fix-thin", "--stdin");
+ if (promisor_msg && pack_name)
+ die(_("--promisor cannot be used with a pack name"));
if (from_stdin && !startup_info->have_repository)
die(_("--stdin requires a git repository"));
if (from_stdin && hash_algo)
@@ -1874,6 +1979,15 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (!index_name && pack_name)
index_name = derive_filename(pack_name, "pack", "idx", &index_name_buf);
+ /*
+ * Packfiles and indices do not carry enough information to be able to
+ * identify their object hash. So when we are neither in a repository
+ * nor has the user told us which object hash to use we have no other
+ * choice but to guess the object hash.
+ */
+ if (!the_repository->hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
if (rev_index) {
opts.flags |= verify ? WRITE_REV_VERIFY : WRITE_REV;
@@ -1961,8 +2075,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
free((void *) curr_pack);
if (!index_name)
free((void *) curr_index);
- if (!rev_index_name)
- free((void *) curr_rev_index);
+ free(curr_rev_index);
+
+ repack_local_links();
/*
* Let the caller know this pack is not self contained
diff --git a/builtin/init-db.c b/builtin/init-db.c
index cb727c826f..096f96b9c4 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -3,14 +3,15 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
-#include "config.h"
#include "environment.h"
#include "gettext.h"
#include "object-file.h"
#include "parse-options.h"
#include "path.h"
+#include "refs.h"
#include "setup.h"
#include "strbuf.h"
@@ -57,6 +58,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
static const char *const init_db_usage[] = {
N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+ " [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"),
NULL
@@ -68,16 +70,23 @@ static const char *const init_db_usage[] = {
* On the other hand, it might just make lookup slower and messier. You
* be the judge. The default case is to have one DB per managed directory.
*/
-int cmd_init_db(int argc, const char **argv, const char *prefix)
+int cmd_init_db(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- const char *git_dir;
+ char *git_dir;
const char *real_git_dir = NULL;
- const char *work_tree;
+ char *real_git_dir_to_free = NULL;
+ char *work_tree = NULL;
const char *template_dir = NULL;
+ char *template_dir_to_free = NULL;
unsigned int flags = 0;
const char *object_format = NULL;
+ const char *ref_format = NULL;
const char *initial_branch = NULL;
int hash_algo = GIT_HASH_UNKNOWN;
+ enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
int init_shared_repository = -1;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
@@ -95,8 +104,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
N_("override the name of the initial branch")),
OPT_STRING(0, "object-format", &object_format, N_("hash"),
N_("specify the hash algorithm to use")),
+ OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_END()
};
+ int ret;
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
@@ -104,12 +116,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
if (real_git_dir && !is_absolute_path(real_git_dir))
- real_git_dir = real_pathdup(real_git_dir, 1);
+ real_git_dir = real_git_dir_to_free = real_pathdup(real_git_dir, 1);
- if (template_dir && *template_dir && !is_absolute_path(template_dir)) {
- template_dir = absolute_pathdup(template_dir);
- UNLEAK(template_dir);
- }
+ if (template_dir && *template_dir && !is_absolute_path(template_dir))
+ template_dir = template_dir_to_free = absolute_pathdup(template_dir);
if (argc == 1) {
int mkdir_tried = 0;
@@ -158,6 +168,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
die(_("unknown hash algorithm '%s'"), object_format);
}
+ if (ref_format) {
+ ref_storage_format = ref_storage_format_by_name(ref_format);
+ if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_format);
+ }
+
if (init_shared_repository != -1)
set_shared_repository(init_shared_repository);
@@ -177,7 +193,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
* Set up the default .git directory contents
*/
if (!git_dir)
- git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+ git_dir = xstrdup(DEFAULT_GIT_DIR_ENVIRONMENT);
/*
* When --separate-git-dir is used inside a linked worktree, take
@@ -198,6 +214,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (chdir(mainwt.buf) < 0)
die_errno(_("cannot chdir to %s"), mainwt.buf);
strbuf_release(&mainwt);
+ free(git_dir);
git_dir = strbuf_detach(&sb, NULL);
}
strbuf_release(&sb);
@@ -219,9 +236,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
set_git_work_tree(work_tree);
else
set_git_work_tree(git_work_tree_cfg);
- if (access(get_git_work_tree(), X_OK))
+ if (access(repo_get_work_tree(the_repository), X_OK))
die_errno (_("Cannot access work tree '%s'"),
- get_git_work_tree());
+ repo_get_work_tree(the_repository));
}
else {
if (real_git_dir)
@@ -230,11 +247,14 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
set_git_work_tree(work_tree);
}
- UNLEAK(real_git_dir);
- UNLEAK(git_dir);
- UNLEAK(work_tree);
-
flags |= INIT_DB_EXIST_OK;
- return init_db(git_dir, real_git_dir, template_dir, hash_algo,
- initial_branch, init_shared_repository, flags);
+ ret = init_db(git_dir, real_git_dir, template_dir, hash_algo,
+ ref_storage_format, initial_branch,
+ init_shared_repository, flags);
+
+ free(template_dir_to_free);
+ free(real_git_dir_to_free);
+ free(work_tree);
+ free(git_dir);
+ return ret;
}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index c5e8345265..44d8ccddc9 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -4,17 +4,18 @@
* Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
*
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "parse-options.h"
#include "string-list.h"
+#include "tempfile.h"
#include "trailer.h"
#include "config.h"
static const char * const git_interpret_trailers_usage[] = {
N_("git interpret-trailers [--in-place] [--trim-empty]\n"
- " [(--trailer <token>[(=|:)<value>])...]\n"
+ " [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"),
NULL
};
@@ -24,21 +25,24 @@ static enum trailer_if_exists if_exists;
static enum trailer_if_missing if_missing;
static int option_parse_where(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_where(&where, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_where(opt->value, arg);
}
static int option_parse_if_exists(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_if_exists(&if_exists, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_if_exists(opt->value, arg);
}
static int option_parse_if_missing(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_if_missing(&if_missing, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_if_missing(opt->value, arg);
}
static void new_trailers_clear(struct list_head *trailers)
@@ -88,7 +92,108 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
return 0;
}
-int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
+static struct tempfile *trailers_tempfile;
+
+static FILE *create_in_place_tempfile(const char *file)
+{
+ struct stat st;
+ struct strbuf filename_template = STRBUF_INIT;
+ const char *tail;
+ FILE *outfile;
+
+ if (stat(file, &st))
+ die_errno(_("could not stat %s"), file);
+ if (!S_ISREG(st.st_mode))
+ die(_("file %s is not a regular file"), file);
+ if (!(st.st_mode & S_IWUSR))
+ die(_("file %s is not writable by user"), file);
+
+ /* Create temporary file in the same directory as the original */
+ tail = strrchr(file, '/');
+ if (tail)
+ strbuf_add(&filename_template, file, tail - file + 1);
+ strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
+
+ trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
+ strbuf_release(&filename_template);
+ outfile = fdopen_tempfile(trailers_tempfile, "w");
+ if (!outfile)
+ die_errno(_("could not open temporary file"));
+
+ return outfile;
+}
+
+static void read_input_file(struct strbuf *sb, const char *file)
+{
+ if (file) {
+ if (strbuf_read_file(sb, file, 0) < 0)
+ die_errno(_("could not read input file '%s'"), file);
+ } else {
+ if (strbuf_read(sb, fileno(stdin), 0) < 0)
+ die_errno(_("could not read from stdin"));
+ }
+ strbuf_complete_line(sb);
+}
+
+static void interpret_trailers(const struct process_trailer_options *opts,
+ struct list_head *new_trailer_head,
+ const char *file)
+{
+ LIST_HEAD(head);
+ struct strbuf sb = STRBUF_INIT;
+ struct strbuf trailer_block_sb = STRBUF_INIT;
+ struct trailer_block *trailer_block;
+ FILE *outfile = stdout;
+
+ trailer_config_init();
+
+ read_input_file(&sb, file);
+
+ if (opts->in_place)
+ outfile = create_in_place_tempfile(file);
+
+ trailer_block = parse_trailers(opts, sb.buf, &head);
+
+ /* Print the lines before the trailer block */
+ if (!opts->only_trailers)
+ fwrite(sb.buf, 1, trailer_block_start(trailer_block), outfile);
+
+ if (!opts->only_trailers && !blank_line_before_trailer_block(trailer_block))
+ fprintf(outfile, "\n");
+
+
+ if (!opts->only_input) {
+ LIST_HEAD(config_head);
+ LIST_HEAD(arg_head);
+ parse_trailers_from_config(&config_head);
+ parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
+ list_splice(&config_head, &arg_head);
+ process_trailers_lists(&head, &arg_head);
+ }
+
+ /* Print trailer block. */
+ format_trailers(opts, &head, &trailer_block_sb);
+ free_trailers(&head);
+ fwrite(trailer_block_sb.buf, 1, trailer_block_sb.len, outfile);
+ strbuf_release(&trailer_block_sb);
+
+ /* Print the lines after the trailer block as is. */
+ if (!opts->only_trailers)
+ fwrite(sb.buf + trailer_block_end(trailer_block), 1,
+ sb.len - trailer_block_end(trailer_block), outfile);
+ trailer_block_release(trailer_block);
+
+ if (opts->in_place)
+ if (rename_tempfile(&trailers_tempfile, file))
+ die_errno(_("could not rename temporary file to %s"), file);
+
+ strbuf_release(&sb);
+}
+
+int cmd_interpret_trailers(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
LIST_HEAD(trailers);
@@ -97,19 +202,19 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
- OPT_CALLBACK(0, "where", NULL, N_("action"),
+ OPT_CALLBACK(0, "where", &where, N_("placement"),
N_("where to place the new trailer"), option_parse_where),
- OPT_CALLBACK(0, "if-exists", NULL, N_("action"),
+ OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
N_("action if trailer already exists"), option_parse_if_exists),
- OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
+ OPT_CALLBACK(0, "if-missing", &if_missing, N_("action"),
N_("action if trailer is missing"), option_parse_if_missing),
OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
- OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")),
- OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
- OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("set parsing options"),
+ OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
+ OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
+ OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
- OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")),
+ OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
N_("trailer(s) to add"), option_parse_trailer),
OPT_END()
@@ -129,11 +234,11 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
if (argc) {
int i;
for (i = 0; i < argc; i++)
- process_trailers(argv[i], &opts, &trailers);
+ interpret_trailers(&opts, &trailers, argv[i]);
} else {
if (opts.in_place)
die(_("no input file given for in-place editing"));
- process_trailers(NULL, &opts, &trailers);
+ interpret_trailers(&opts, &trailers, NULL);
}
new_trailers_clear(&trailers);
diff --git a/builtin/log.c b/builtin/log.c
index 5d808c92f4..368f6580a6 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -4,7 +4,8 @@
* (C) Copyright 2006 Linus Torvalds
* 2006 Junio Hamano
*/
-#include "git-compat-util.h"
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
#include "abspath.h"
#include "config.h"
#include "environment.h"
@@ -26,7 +27,6 @@
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
-#include "run-command.h"
#include "shortlog.h"
#include "remote.h"
#include "string-list.h"
@@ -36,10 +36,9 @@
#include "streaming.h"
#include "version.h"
#include "mailmap.h"
-#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
-#include "repository.h"
+
#include "commit-reach.h"
#include "range-diff.h"
#include "tmp-objdir.h"
@@ -50,22 +49,8 @@
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
#define FORMAT_PATCH_NAME_MAX_DEFAULT 64
-/* Set a default date-time format for git log ("log.date" config variable) */
-static const char *default_date_mode = NULL;
-
-static int default_abbrev_commit;
-static int default_show_root = 1;
-static int default_follow;
-static int default_show_signature;
-static int default_encode_email_headers = 1;
-static int decoration_style;
-static int decoration_given;
-static int use_mailmap_config = 1;
static unsigned int force_in_body_from;
static 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[] = {
@@ -113,33 +98,71 @@ static int parse_decoration_style(const char *value)
return -1;
}
+struct log_config {
+ int default_abbrev_commit;
+ int default_show_root;
+ int default_follow;
+ int default_show_signature;
+ int default_encode_email_headers;
+ int decoration_style;
+ int decoration_given;
+ int use_mailmap_config;
+ char *fmt_patch_subject_prefix;
+ int fmt_patch_name_max;
+ char *fmt_pretty;
+ char *default_date_mode;
+};
+
+static void log_config_init(struct log_config *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->default_show_root = 1;
+ cfg->default_encode_email_headers = 1;
+ cfg->use_mailmap_config = 1;
+ cfg->fmt_patch_subject_prefix = xstrdup("PATCH");
+ cfg->fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
+ cfg->decoration_style = auto_decoration_style();
+}
+
+static void log_config_release(struct log_config *cfg)
+{
+ free(cfg->default_date_mode);
+ free(cfg->fmt_pretty);
+ free(cfg->fmt_patch_subject_prefix);
+}
+
static int use_default_decoration_filter = 1;
static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
-static int clear_decorations_callback(const struct option *opt,
- const char *arg, int unset)
+static int clear_decorations_callback(const struct option *opt UNUSED,
+ const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
string_list_clear(&decorate_refs_include, 0);
string_list_clear(&decorate_refs_exclude, 0);
use_default_decoration_filter = 0;
return 0;
}
-static int decorate_callback(const struct option *opt, const char *arg, int unset)
+static int decorate_callback(const struct option *opt, const char *arg,
+ int unset)
{
+ struct log_config *cfg = opt->value;
+
if (unset)
- decoration_style = 0;
+ cfg->decoration_style = 0;
else if (arg)
- decoration_style = parse_decoration_style(arg);
+ cfg->decoration_style = parse_decoration_style(arg);
else
- decoration_style = DECORATE_SHORT_REFS;
+ cfg->decoration_style = DECORATE_SHORT_REFS;
- if (decoration_style < 0)
+ if (cfg->decoration_style < 0)
die(_("invalid --decorate option: %s"), arg);
- decoration_given = 1;
+ cfg->decoration_given = 1;
return 0;
}
@@ -159,33 +182,26 @@ static int log_line_range_callback(const struct option *option, const char *arg,
return 0;
}
-static void init_log_defaults(void)
-{
- init_diff_ui_defaults();
-
- decoration_style = auto_decoration_style();
-}
-
-static void cmd_log_init_defaults(struct rev_info *rev)
+static void cmd_log_init_defaults(struct rev_info *rev,
+ struct log_config *cfg)
{
- if (fmt_pretty)
- get_commit_format(fmt_pretty, rev);
- if (default_follow)
+ if (cfg->fmt_pretty)
+ get_commit_format(cfg->fmt_pretty, rev);
+ if (cfg->default_follow)
rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
+ init_diffstat_widths(&rev->diffopt);
rev->diffopt.flags.recursive = 1;
- rev->diffopt.stat_width = -1; /* use full terminal width */
- rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
- rev->abbrev_commit = default_abbrev_commit;
- rev->show_root_diff = default_show_root;
- rev->subject_prefix = fmt_patch_subject_prefix;
- rev->patch_name_max = fmt_patch_name_max;
- rev->show_signature = default_show_signature;
- rev->encode_email_headers = default_encode_email_headers;
rev->diffopt.flags.allow_textconv = 1;
+ rev->abbrev_commit = cfg->default_abbrev_commit;
+ rev->show_root_diff = cfg->default_show_root;
+ rev->subject_prefix = cfg->fmt_patch_subject_prefix;
+ rev->patch_name_max = cfg->fmt_patch_name_max;
+ rev->show_signature = cfg->default_show_signature;
+ rev->encode_email_headers = cfg->default_encode_email_headers;
- if (default_date_mode)
- parse_date_format(default_date_mode, &rev->date_mode);
+ if (cfg->default_date_mode)
+ parse_date_format(cfg->default_date_mode, &rev->date_mode);
}
static void set_default_decoration_filter(struct decoration_filter *decoration_filter)
@@ -233,7 +249,8 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
- struct rev_info *rev, struct setup_revision_opt *opt)
+ struct rev_info *rev, struct setup_revision_opt *opt,
+ struct log_config *cfg)
{
struct userformat_want w;
int quiet = 0, source = 0, mailmap;
@@ -258,7 +275,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
N_("pattern"), N_("only decorate refs that match <pattern>")),
OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
N_("pattern"), N_("do not decorate refs that match <pattern>")),
- OPT_CALLBACK_F(0, "decorate", NULL, NULL, N_("decorate options"),
+ OPT_CALLBACK_F(0, "decorate", cfg, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback),
OPT_CALLBACK('L', NULL, &line_cb, "range:file",
N_("trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
@@ -269,7 +286,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
line_cb.rev = rev;
line_cb.prefix = prefix;
- mailmap = use_mailmap_config;
+ mailmap = cfg->use_mailmap_config;
argc = parse_options(argc, argv, prefix,
builtin_log_options, builtin_log_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -314,8 +331,8 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
* "log --pretty=raw" is special; ignore UI oriented
* configuration variables such as decoration.
*/
- if (!decoration_given)
- decoration_style = 0;
+ if (!cfg->decoration_given)
+ cfg->decoration_style = 0;
if (!rev->abbrev_commit_given)
rev->abbrev_commit = 0;
}
@@ -326,24 +343,24 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
* Disable decoration loading if the format will not
* show them anyway.
*/
- decoration_style = 0;
- } else if (!decoration_style) {
+ cfg->decoration_style = 0;
+ } else if (!cfg->decoration_style) {
/*
* If we are going to show them, make sure we do load
* them here, but taking care not to override a
* specific style set by config or --decorate.
*/
- decoration_style = DECORATE_SHORT_REFS;
+ cfg->decoration_style = DECORATE_SHORT_REFS;
}
}
- if (decoration_style || rev->simplify_by_decoration) {
+ if (cfg->decoration_style || rev->simplify_by_decoration) {
set_default_decoration_filter(&decoration_filter);
- if (decoration_style)
+ if (cfg->decoration_style)
rev->show_decorations = 1;
- load_ref_decorations(&decoration_filter, decoration_style);
+ load_ref_decorations(&decoration_filter, cfg->decoration_style);
}
if (rev->line_level_traverse)
@@ -353,16 +370,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
}
static void cmd_log_init(int argc, const char **argv, const char *prefix,
- struct rev_info *rev, struct setup_revision_opt *opt)
+ struct rev_info *rev, struct setup_revision_opt *opt,
+ struct log_config *cfg)
{
- cmd_log_init_defaults(rev);
- cmd_log_init_finish(argc, argv, prefix, rev, opt);
-}
-
-static int cmd_log_deinit(int ret, struct rev_info *rev)
-{
- release_revisions(rev);
- return ret;
+ cmd_log_init_defaults(rev, cfg);
+ cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg);
}
/*
@@ -493,13 +505,7 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
struct commit *commit;
int saved_nrl = 0;
int saved_dcctc = 0;
-
- if (rev->remerge_diff) {
- rev->remerge_objdir = tmp_objdir_create("remerge-diff");
- if (!rev->remerge_objdir)
- die(_("unable to create temporary object directory"));
- tmp_objdir_replace_primary_odb(rev->remerge_objdir, 1);
- }
+ int result;
if (rev->early_output)
setup_early_output();
@@ -540,16 +546,12 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
rev->diffopt.degraded_cc_to_c = saved_dcctc;
rev->diffopt.needed_rename_limit = saved_nrl;
- if (rev->remerge_diff) {
- tmp_objdir_destroy(rev->remerge_objdir);
- rev->remerge_objdir = NULL;
- }
-
+ result = diff_result_code(rev);
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
rev->diffopt.flags.check_failed) {
- return 02;
+ result = 02;
}
- return diff_result_code(&rev->diffopt);
+ return result;
}
static int cmd_log_walk(struct rev_info *rev)
@@ -566,63 +568,79 @@ static int cmd_log_walk(struct rev_info *rev)
static int git_log_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ struct log_config *cfg = cb;
const char *slot_name;
- if (!strcmp(var, "format.pretty"))
- return git_config_string(&fmt_pretty, var, value);
- if (!strcmp(var, "format.subjectprefix"))
- return git_config_string(&fmt_patch_subject_prefix, var, value);
+ if (!strcmp(var, "format.pretty")) {
+ FREE_AND_NULL(cfg->fmt_pretty);
+ return git_config_string(&cfg->fmt_pretty, var, value);
+ }
+ if (!strcmp(var, "format.subjectprefix")) {
+ FREE_AND_NULL(cfg->fmt_patch_subject_prefix);
+ return git_config_string(&cfg->fmt_patch_subject_prefix, var, value);
+ }
if (!strcmp(var, "format.filenamemaxlength")) {
- fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
+ cfg->fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "format.encodeemailheaders")) {
- default_encode_email_headers = git_config_bool(var, value);
+ cfg->default_encode_email_headers = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.abbrevcommit")) {
- default_abbrev_commit = git_config_bool(var, value);
+ cfg->default_abbrev_commit = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "log.date"))
- return git_config_string(&default_date_mode, var, value);
+ if (!strcmp(var, "log.date")) {
+ FREE_AND_NULL(cfg->default_date_mode);
+ return git_config_string(&cfg->default_date_mode, var, value);
+ }
if (!strcmp(var, "log.decorate")) {
- decoration_style = parse_decoration_style(value);
- if (decoration_style < 0)
- decoration_style = 0; /* maybe warn? */
+ cfg->decoration_style = parse_decoration_style(value);
+ if (cfg->decoration_style < 0)
+ cfg->decoration_style = 0; /* maybe warn? */
return 0;
}
- if (!strcmp(var, "log.diffmerges"))
+ if (!strcmp(var, "log.diffmerges")) {
+ if (!value)
+ return config_error_nonbool(var);
return diff_merges_config(value);
+ }
if (!strcmp(var, "log.showroot")) {
- default_show_root = git_config_bool(var, value);
+ cfg->default_show_root = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.follow")) {
- default_follow = git_config_bool(var, value);
+ cfg->default_follow = git_config_bool(var, value);
return 0;
}
if (skip_prefix(var, "color.decorate.", &slot_name))
return parse_decorate_color_config(var, slot_name, value);
if (!strcmp(var, "log.mailmap")) {
- use_mailmap_config = git_config_bool(var, value);
+ cfg->use_mailmap_config = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.showsignature")) {
- default_show_signature = git_config_bool(var, value);
+ cfg->default_show_signature = git_config_bool(var, value);
return 0;
}
return git_diff_ui_config(var, value, ctx, cb);
}
-int cmd_whatchanged(int argc, const char **argv, const char *prefix)
+int cmd_whatchanged(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -632,10 +650,15 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
static void show_tagger(const char *buf, struct rev_info *rev)
@@ -653,7 +676,7 @@ static void show_tagger(const char *buf, struct rev_info *rev)
static int show_blob_object(const struct object_id *oid, struct rev_info *rev, const char *obj_name)
{
struct object_id oidc;
- struct object_context obj_context;
+ struct object_context obj_context = {0};
char *buf;
unsigned long size;
@@ -669,7 +692,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
if (!obj_context.path ||
!textconv_object(the_repository, obj_context.path,
obj_context.mode, &oidc, 1, &buf, &size)) {
- free(obj_context.path);
+ object_context_release(&obj_context);
return stream_blob_to_fd(1, oid, NULL, 0);
}
@@ -677,7 +700,8 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
die(_("git show %s: bad file"), obj_name);
write_or_die(1, buf, size);
- free(obj_context.path);
+ object_context_release(&obj_context);
+ free(buf);
return 0;
}
@@ -728,16 +752,21 @@ static void show_setup_revisions_tweak(struct rev_info *rev)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
}
-int cmd_show(int argc, const char **argv, const char *prefix)
+int cmd_show(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
+ struct log_config cfg;
struct rev_info rev;
unsigned int i;
struct setup_revision_opt opt;
struct pathspec match_all;
int ret = 0;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
@@ -756,10 +785,14 @@ int cmd_show(int argc, const char **argv, const char *prefix)
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_setup_revisions_tweak;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
- if (!rev.no_walk)
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ if (!rev.no_walk) {
+ ret = cmd_log_walk(&rev);
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
+ }
rev.diffopt.no_free = 1;
for (i = 0; i < rev.pending.nr && !ret; i++) {
@@ -829,20 +862,28 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.diffopt.no_free = 0;
diff_free(&rev.diffopt);
+ release_revisions(&rev);
+ log_config_release(&cfg);
- return cmd_log_deinit(ret, &rev);
+ return ret;
}
/*
* This is equivalent to "git log -g --abbrev-commit --pretty=oneline"
*/
-int cmd_log_reflog(int argc, const char **argv, const char *prefix)
+int cmd_log_reflog(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
@@ -851,14 +892,18 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
- cmd_log_init_defaults(&rev);
+ cmd_log_init_defaults(&rev, &cfg);
rev.abbrev_commit = 1;
rev.commit_format = CMIT_FMT_ONELINE;
rev.use_terminator = 1;
rev.always_show_header = 1;
- cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
+ cmd_log_init_finish(argc, argv, prefix, &rev, &opt, &cfg);
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
static void log_setup_revisions_tweak(struct rev_info *rev)
@@ -871,13 +916,19 @@ static void log_setup_revisions_tweak(struct rev_info *rev)
diff_merges_default_to_first_parent(rev);
}
-int cmd_log(int argc, const char **argv, const char *prefix)
+int cmd_log(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -887,42 +938,17 @@ int cmd_log(int argc, const char **argv, const char *prefix)
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
opt.tweak = log_setup_revisions_tweak;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
-}
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
-/* format-patch */
-
-static const char *fmt_patch_suffix = ".patch";
-static int numbered = 0;
-static int auto_number = 1;
-
-static char *default_attach = NULL;
-
-static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
-static struct string_list extra_to = STRING_LIST_INIT_NODUP;
-static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
-
-static void add_header(const char *value)
-{
- struct string_list_item *item;
- int len = strlen(value);
- while (len && value[len - 1] == '\n')
- len--;
+ ret = cmd_log_walk(&rev);
- if (!strncasecmp(value, "to: ", 4)) {
- item = string_list_append(&extra_to, value + 4);
- len -= 4;
- } else if (!strncasecmp(value, "cc: ", 4)) {
- item = string_list_append(&extra_cc, value + 4);
- len -= 4;
- } else {
- item = string_list_append(&extra_hdr, value);
- }
-
- item->string[len] = '\0';
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
+/* format-patch */
+
enum cover_setting {
COVER_UNSET,
COVER_OFF,
@@ -949,17 +975,61 @@ enum auto_base_setting {
AUTO_BASE_WHEN_ABLE
};
-static enum thread_level thread;
-static int do_signoff;
-static enum auto_base_setting auto_base;
-static char *from;
-static const char *signature = git_version_string;
-static const char *signature_file;
-static enum cover_setting config_cover_letter;
-static const char *config_output_directory;
-static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
-static int show_notes;
-static struct display_notes_opt notes_opt;
+struct format_config {
+ struct log_config log;
+ enum thread_level thread;
+ int do_signoff;
+ enum auto_base_setting auto_base;
+ char *base_commit;
+ char *from;
+ char *signature;
+ char *signature_file;
+ enum cover_setting config_cover_letter;
+ char *config_output_directory;
+ enum cover_from_description cover_from_description_mode;
+ int show_notes;
+ struct display_notes_opt notes_opt;
+ int numbered_cmdline_opt;
+ int numbered;
+ int auto_number;
+ char *default_attach;
+ struct string_list extra_hdr;
+ struct string_list extra_to;
+ struct string_list extra_cc;
+ int keep_subject;
+ int subject_prefix;
+ struct strbuf sprefix;
+ char *fmt_patch_suffix;
+};
+
+static void format_config_init(struct format_config *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+ log_config_init(&cfg->log);
+ cfg->cover_from_description_mode = COVER_FROM_MESSAGE;
+ cfg->auto_number = 1;
+ string_list_init_dup(&cfg->extra_hdr);
+ string_list_init_dup(&cfg->extra_to);
+ string_list_init_dup(&cfg->extra_cc);
+ strbuf_init(&cfg->sprefix, 0);
+ cfg->fmt_patch_suffix = xstrdup(".patch");
+}
+
+static void format_config_release(struct format_config *cfg)
+{
+ log_config_release(&cfg->log);
+ free(cfg->base_commit);
+ free(cfg->from);
+ free(cfg->signature);
+ free(cfg->signature_file);
+ free(cfg->config_output_directory);
+ free(cfg->default_attach);
+ string_list_clear(&cfg->extra_hdr, 0);
+ string_list_clear(&cfg->extra_to, 0);
+ string_list_clear(&cfg->extra_cc, 0);
+ strbuf_release(&cfg->sprefix);
+ free(cfg->fmt_patch_suffix);
+}
static enum cover_from_description parse_cover_from_description(const char *arg)
{
@@ -977,27 +1047,51 @@ static enum cover_from_description parse_cover_from_description(const char *arg)
die(_("%s: invalid cover from description mode"), arg);
}
+static void add_header(struct format_config *cfg, const char *value)
+{
+ struct string_list_item *item;
+ int len = strlen(value);
+ while (len && value[len - 1] == '\n')
+ len--;
+
+ if (!strncasecmp(value, "to: ", 4)) {
+ item = string_list_append(&cfg->extra_to, value + 4);
+ len -= 4;
+ } else if (!strncasecmp(value, "cc: ", 4)) {
+ item = string_list_append(&cfg->extra_cc, value + 4);
+ len -= 4;
+ } else {
+ item = string_list_append(&cfg->extra_hdr, value);
+ }
+
+ item->string[len] = '\0';
+}
+
static int git_format_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ struct format_config *cfg = cb;
+
if (!strcmp(var, "format.headers")) {
if (!value)
die(_("format.headers without value"));
- add_header(value);
+ add_header(cfg, value);
return 0;
}
- if (!strcmp(var, "format.suffix"))
- return git_config_string(&fmt_patch_suffix, var, value);
+ if (!strcmp(var, "format.suffix")) {
+ FREE_AND_NULL(cfg->fmt_patch_suffix);
+ return git_config_string(&cfg->fmt_patch_suffix, var, value);
+ }
if (!strcmp(var, "format.to")) {
if (!value)
return config_error_nonbool(var);
- string_list_append(&extra_to, value);
+ string_list_append(&cfg->extra_to, value);
return 0;
}
if (!strcmp(var, "format.cc")) {
if (!value)
return config_error_nonbool(var);
- string_list_append(&extra_cc, value);
+ string_list_append(&cfg->extra_cc, value);
return 0;
}
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
@@ -1006,69 +1100,76 @@ static int git_format_config(const char *var, const char *value,
}
if (!strcmp(var, "format.numbered")) {
if (value && !strcasecmp(value, "auto")) {
- auto_number = 1;
+ cfg->auto_number = 1;
return 0;
}
- numbered = git_config_bool(var, value);
- auto_number = auto_number && numbered;
+ cfg->numbered = git_config_bool(var, value);
+ cfg->auto_number = cfg->auto_number && cfg->numbered;
return 0;
}
if (!strcmp(var, "format.attach")) {
- if (value && *value)
- default_attach = xstrdup(value);
- else if (value && !*value)
- FREE_AND_NULL(default_attach);
- else
- default_attach = xstrdup(git_version_string);
+ if (value && *value) {
+ FREE_AND_NULL(cfg->default_attach);
+ cfg->default_attach = xstrdup(value);
+ } else if (value && !*value) {
+ FREE_AND_NULL(cfg->default_attach);
+ } else {
+ FREE_AND_NULL(cfg->default_attach);
+ cfg->default_attach = xstrdup(git_version_string);
+ }
return 0;
}
if (!strcmp(var, "format.thread")) {
if (value && !strcasecmp(value, "deep")) {
- thread = THREAD_DEEP;
+ cfg->thread = THREAD_DEEP;
return 0;
}
if (value && !strcasecmp(value, "shallow")) {
- thread = THREAD_SHALLOW;
+ cfg->thread = THREAD_SHALLOW;
return 0;
}
- thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
+ cfg->thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
return 0;
}
if (!strcmp(var, "format.signoff")) {
- do_signoff = git_config_bool(var, value);
+ cfg->do_signoff = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "format.signature"))
- return git_config_string(&signature, var, value);
- if (!strcmp(var, "format.signaturefile"))
- return git_config_pathname(&signature_file, var, value);
+ if (!strcmp(var, "format.signature")) {
+ FREE_AND_NULL(cfg->signature);
+ return git_config_string(&cfg->signature, var, value);
+ }
+ if (!strcmp(var, "format.signaturefile")) {
+ FREE_AND_NULL(cfg->signature_file);
+ return git_config_pathname(&cfg->signature_file, var, value);
+ }
if (!strcmp(var, "format.coverletter")) {
if (value && !strcasecmp(value, "auto")) {
- config_cover_letter = COVER_AUTO;
+ cfg->config_cover_letter = COVER_AUTO;
return 0;
}
- config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+ cfg->config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
return 0;
}
- if (!strcmp(var, "format.outputdirectory"))
- return git_config_string(&config_output_directory, var, value);
+ if (!strcmp(var, "format.outputdirectory")) {
+ FREE_AND_NULL(cfg->config_output_directory);
+ return git_config_string(&cfg->config_output_directory, var, value);
+ }
if (!strcmp(var, "format.useautobase")) {
if (value && !strcasecmp(value, "whenAble")) {
- auto_base = AUTO_BASE_WHEN_ABLE;
+ cfg->auto_base = AUTO_BASE_WHEN_ABLE;
return 0;
}
- auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
+ cfg->auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
return 0;
}
if (!strcmp(var, "format.from")) {
int b = git_parse_maybe_bool(value);
- free(from);
+ FREE_AND_NULL(cfg->from);
if (b < 0)
- from = xstrdup(value);
+ cfg->from = xstrdup(value);
else if (b)
- from = xstrdup(git_committer_info(IDENT_NO_DATE));
- else
- from = NULL;
+ cfg->from = xstrdup(git_committer_info(IDENT_NO_DATE));
return 0;
}
if (!strcmp(var, "format.forceinbodyfrom")) {
@@ -1078,15 +1179,15 @@ static int git_format_config(const char *var, const char *value,
if (!strcmp(var, "format.notes")) {
int b = git_parse_maybe_bool(value);
if (b < 0)
- enable_ref_display_notes(&notes_opt, &show_notes, value);
+ enable_ref_display_notes(&cfg->notes_opt, &cfg->show_notes, value);
else if (b)
- enable_default_display_notes(&notes_opt, &show_notes);
+ enable_default_display_notes(&cfg->notes_opt, &cfg->show_notes);
else
- disable_display_notes(&notes_opt, &show_notes);
+ disable_display_notes(&cfg->notes_opt, &cfg->show_notes);
return 0;
}
if (!strcmp(var, "format.coverfromdescription")) {
- cover_from_description_mode = parse_cover_from_description(value);
+ cfg->cover_from_description_mode = parse_cover_from_description(value);
return 0;
}
if (!strcmp(var, "format.mboxrd")) {
@@ -1107,7 +1208,7 @@ static int git_format_config(const char *var, const char *value,
if (!strcmp(var, "diff.noprefix"))
return 0;
- return git_log_config(var, value, ctx, cb);
+ return git_log_config(var, value, ctx, &cfg->log);
}
static const char *output_directory = NULL;
@@ -1186,7 +1287,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
o2->flags = flags2;
}
-static void gen_message_id(struct rev_info *info, char *base)
+static void gen_message_id(struct rev_info *info, const char *base)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
@@ -1195,7 +1296,7 @@ static void gen_message_id(struct rev_info *info, char *base)
info->message_id = strbuf_detach(&buf, NULL);
}
-static void print_signature(FILE *file)
+static void print_signature(const char *signature, FILE *file)
{
if (!signature || !*signature)
return;
@@ -1253,38 +1354,49 @@ static void show_diffstat(struct rev_info *rev,
fprintf(rev->diffopt.file, "\n");
}
+static void read_desc_file(struct strbuf *buf, const char *desc_file)
+{
+ if (strbuf_read_file(buf, desc_file, 0) < 0)
+ die_errno(_("unable to read branch description file '%s'"),
+ desc_file);
+}
+
static void prepare_cover_text(struct pretty_print_context *pp,
+ const char *description_file,
const char *branch_name,
struct strbuf *sb,
const char *encoding,
- int need_8bit_cte)
+ int need_8bit_cte,
+ const struct format_config *cfg)
{
const char *subject = "*** SUBJECT HERE ***";
const char *body = "*** BLURB HERE ***";
struct strbuf description_sb = STRBUF_INIT;
struct strbuf subject_sb = STRBUF_INIT;
- if (cover_from_description_mode == COVER_FROM_NONE)
+ if (cfg->cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
- if (branch_name && *branch_name)
+ if (description_file && *description_file)
+ read_desc_file(&description_sb, description_file);
+ else if (branch_name && *branch_name)
read_branch_desc(&description_sb, branch_name);
if (!description_sb.len)
goto do_pp;
- if (cover_from_description_mode == COVER_FROM_SUBJECT ||
- cover_from_description_mode == COVER_FROM_AUTO)
+ if (cfg->cover_from_description_mode == COVER_FROM_SUBJECT ||
+ cfg->cover_from_description_mode == COVER_FROM_AUTO)
body = format_subject(&subject_sb, description_sb.buf, " ");
- if (cover_from_description_mode == COVER_FROM_MESSAGE ||
- (cover_from_description_mode == COVER_FROM_AUTO &&
- subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+ if (cfg->cover_from_description_mode == COVER_FROM_MESSAGE ||
+ (cfg->cover_from_description_mode == COVER_FROM_AUTO &&
+ subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
body = description_sb.buf;
else
subject = subject_sb.buf;
do_pp:
- pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
+ pp_email_subject(pp, &subject, sb, encoding, need_8bit_cte);
pp_remainder(pp, &body, sb, 0);
strbuf_release(&description_sb);
@@ -1313,8 +1425,10 @@ static void get_notes_args(struct strvec *arg, struct rev_info *rev)
static void make_cover_letter(struct rev_info *rev, int use_separate_file,
struct commit *origin,
int nr, struct commit **list,
+ const char *description_file,
const char *branch_name,
- int quiet)
+ int quiet,
+ const struct format_config *cfg)
{
const char *committer;
struct shortlog log;
@@ -1324,6 +1438,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
int need_8bit_cte = 0;
struct pretty_print_context pp = {0};
struct commit *head = list[0];
+ char *to_free = NULL;
if (!cmit_fmt_is_mail(rev->commit_format))
die(_("cover letter needs email format"));
@@ -1345,16 +1460,19 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
}
if (!branch_name)
- branch_name = find_branch_name(rev);
+ branch_name = to_free = find_branch_name(rev);
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode.type = DATE_RFC2822;
pp.rev = rev;
- pp.print_email_subject = 1;
+ pp.encode_email_headers = rev->encode_email_headers;
pp_user_info(&pp, NULL, &sb, committer, encoding);
- prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
+ prepare_cover_text(&pp, description_file, branch_name, &sb,
+ encoding, need_8bit_cte, cfg);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
+ free(to_free);
+ free(pp.after_subject);
strbuf_release(&sb);
shortlog_init(&log);
@@ -1452,44 +1570,54 @@ static const char * const builtin_format_patch_usage[] = {
NULL
};
-static int keep_subject = 0;
+struct keep_callback_data {
+ struct format_config *cfg;
+ struct rev_info *revs;
+};
static int keep_callback(const struct option *opt, const char *arg, int unset)
{
+ struct keep_callback_data *data = opt->value;
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- ((struct rev_info *)opt->value)->total = -1;
- keep_subject = 1;
+ data->revs->total = -1;
+ data->cfg->keep_subject = 1;
return 0;
}
-static int subject_prefix = 0;
-
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct format_config *cfg = opt->value;
+
BUG_ON_OPT_NEG(unset);
- subject_prefix = 1;
- ((struct rev_info *)opt->value)->subject_prefix = arg;
+ cfg->subject_prefix = 1;
+ strbuf_reset(&cfg->sprefix);
+ strbuf_addstr(&cfg->sprefix, arg);
return 0;
}
-static int rfc_callback(const struct option *opt, const char *arg, int unset)
+static int rfc_callback(const struct option *opt, const char *arg,
+ int unset)
{
- BUG_ON_OPT_NEG(unset);
- BUG_ON_OPT_ARG(arg);
- return subject_prefix_callback(opt, "RFC PATCH", unset);
-}
+ const char **rfc = opt->value;
-static int numbered_cmdline_opt = 0;
+ *rfc = opt->value;
+ if (unset)
+ *rfc = NULL;
+ else
+ *rfc = arg ? arg : "RFC";
+ return 0;
+}
static int numbered_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct format_config *cfg = opt->value;
BUG_ON_OPT_ARG(arg);
- *(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;
+ cfg->numbered = cfg->numbered_cmdline_opt = unset ? 0 : 1;
if (unset)
- auto_number = 0;
+ cfg->auto_number = 0;
return 0;
}
@@ -1513,13 +1641,14 @@ static int output_directory_callback(const struct option *opt, const char *arg,
static int thread_callback(const struct option *opt, const char *arg, int unset)
{
- enum thread_level *thread = (enum thread_level *)opt->value;
+ struct format_config *cfg = opt->value;
+
if (unset)
- *thread = THREAD_UNSET;
+ cfg->thread = THREAD_UNSET;
else if (!arg || !strcmp(arg, "shallow"))
- *thread = THREAD_SHALLOW;
+ cfg->thread = THREAD_SHALLOW;
else if (!strcmp(arg, "deep"))
- *thread = THREAD_DEEP;
+ cfg->thread = THREAD_DEEP;
/*
* Please update _git_formatpatch() in git-completion.bash
* when you add new options.
@@ -1555,36 +1684,21 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int header_callback(const struct option *opt, const char *arg, int unset)
+static int header_callback(const struct option *opt, const char *arg,
+ int unset)
{
+ struct format_config *cfg = opt->value;
+
if (unset) {
- string_list_clear(&extra_hdr, 0);
- string_list_clear(&extra_to, 0);
- string_list_clear(&extra_cc, 0);
+ string_list_clear(&cfg->extra_hdr, 0);
+ string_list_clear(&cfg->extra_to, 0);
+ string_list_clear(&cfg->extra_cc, 0);
} else {
- add_header(arg);
+ add_header(cfg, arg);
}
return 0;
}
-static int to_callback(const struct option *opt, const char *arg, int unset)
-{
- if (unset)
- string_list_clear(&extra_to, 0);
- else
- string_list_append(&extra_to, arg);
- return 0;
-}
-
-static int cc_callback(const struct option *opt, const char *arg, int unset)
-{
- if (unset)
- string_list_clear(&extra_cc, 0);
- else
- string_list_append(&extra_cc, arg);
- return 0;
-}
-
static int from_callback(const struct option *opt, const char *arg, int unset)
{
char **from = opt->value;
@@ -1602,17 +1716,17 @@ static int from_callback(const struct option *opt, const char *arg, int unset)
static int base_callback(const struct option *opt, const char *arg, int unset)
{
- const char **base_commit = opt->value;
+ struct format_config *cfg = opt->value;
if (unset) {
- auto_base = AUTO_BASE_NEVER;
- *base_commit = NULL;
+ cfg->auto_base = AUTO_BASE_NEVER;
+ FREE_AND_NULL(cfg->base_commit);
} else if (!strcmp(arg, "auto")) {
- auto_base = AUTO_BASE_ALWAYS;
- *base_commit = NULL;
+ cfg->auto_base = AUTO_BASE_ALWAYS;
+ FREE_AND_NULL(cfg->base_commit);
} else {
- auto_base = AUTO_BASE_NEVER;
- *base_commit = arg;
+ cfg->auto_base = AUTO_BASE_NEVER;
+ cfg->base_commit = xstrdup(arg);
}
return 0;
}
@@ -1623,17 +1737,17 @@ struct base_tree_info {
struct object_id *patch_id;
};
-static struct commit *get_base_commit(const char *base_commit,
+static struct commit *get_base_commit(const struct format_config *cfg,
struct commit **list,
int total)
{
struct commit *base = NULL;
struct commit **rev;
- int i = 0, rev_nr = 0, auto_select, die_on_failure;
+ int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
- switch (auto_base) {
+ switch (cfg->auto_base) {
case AUTO_BASE_NEVER:
- if (base_commit) {
+ if (cfg->base_commit) {
auto_select = 0;
die_on_failure = 1;
} else {
@@ -1643,11 +1757,11 @@ static struct commit *get_base_commit(const char *base_commit,
break;
case AUTO_BASE_ALWAYS:
case AUTO_BASE_WHEN_ABLE:
- if (base_commit) {
+ if (cfg->base_commit) {
BUG("requested automatic base selection but a commit was provided");
} else {
auto_select = 1;
- die_on_failure = auto_base == AUTO_BASE_ALWAYS;
+ die_on_failure = cfg->auto_base == AUTO_BASE_ALWAYS;
}
break;
default:
@@ -1655,14 +1769,14 @@ static struct commit *get_base_commit(const char *base_commit,
}
if (!auto_select) {
- base = lookup_commit_reference_by_name(base_commit);
+ base = lookup_commit_reference_by_name(cfg->base_commit);
if (!base)
- die(_("unknown commit %s"), base_commit);
+ die(_("unknown commit %s"), cfg->base_commit);
} else {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
if (upstream) {
- struct commit_list *base_list;
+ struct commit_list *base_list = NULL;
struct commit *commit;
struct object_id oid;
@@ -1673,11 +1787,12 @@ static struct commit *get_base_commit(const char *base_commit,
return NULL;
}
commit = lookup_commit_or_die(&oid, "upstream base");
- 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 (repo_get_merge_bases_many(the_repository,
+ commit, total,
+ list,
+ &base_list) < 0 ||
+ /* There should be one and only one merge base. */
+ !base_list || base_list->next) {
if (die_on_failure) {
die(_("could not find exact merge base"));
} else {
@@ -1708,20 +1823,22 @@ 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 = repo_get_merge_bases(the_repository,
- rev[2 * i],
- rev[2 * i + 1]);
- if (!merge_base || merge_base->next) {
+ struct commit_list *merge_base = NULL;
+ if (repo_get_merge_bases(the_repository,
+ rev[2 * i],
+ rev[2 * i + 1], &merge_base) < 0 ||
+ !merge_base || merge_base->next) {
if (die_on_failure) {
die(_("failed to find exact merge base"));
} else {
+ free_commit_list(merge_base);
free(rev);
return NULL;
}
}
rev[i] = merge_base->item;
+ free_commit_list(merge_base);
}
if (rev_nr % 2)
@@ -1729,7 +1846,10 @@ static struct commit *get_base_commit(const char *base_commit,
rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
- if (!repo_in_merge_bases(the_repository, base, rev[0])) {
+ ret = repo_in_merge_bases(the_repository, base, rev[0]);
+ if (ret < 0)
+ exit(128);
+ if (!ret) {
if (die_on_failure) {
die(_("base commit should be the ancestor of revision list"));
} else {
@@ -1826,7 +1946,7 @@ static void print_bases(struct base_tree_info *bases, FILE *file)
free(bases->patch_id);
bases->nr_patch_id = 0;
bases->alloc_patch_id = 0;
- oidclr(&bases->base_commit);
+ oidclr(&bases->base_commit, the_repository->hash_algo);
}
static const char *diff_title(struct strbuf *sb,
@@ -1869,8 +1989,12 @@ static void infer_range_diff_ranges(struct strbuf *r1,
}
}
-int cmd_format_patch(int argc, const char **argv, const char *prefix)
+int cmd_format_patch(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
+ struct format_config cfg;
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
@@ -1893,8 +2017,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int quiet = 0;
const char *reroll_count = NULL;
char *cover_from_description_arg = NULL;
+ char *description_file = NULL;
char *branch_name = NULL;
- char *base_commit = NULL;
struct base_tree_info bases;
struct commit *base;
int show_progress = 0;
@@ -1905,17 +2029,25 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
- struct strbuf sprefix = STRBUF_INIT;
+ const char *rfc = NULL;
int creation_factor = -1;
+ const char *signature = git_version_string;
+ char *signature_to_free = NULL;
+ char *signature_file_arg = NULL;
+ struct keep_callback_data keep_callback_data = {
+ .cfg = &cfg,
+ .revs = &rev,
+ };
+ const char *fmt_patch_suffix = NULL;
const struct option builtin_format_patch_options[] = {
- OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
+ OPT_CALLBACK_F('n', "numbered", &cfg, NULL,
N_("use [PATCH n/m] even with a single patch"),
PARSE_OPT_NOARG, numbered_callback),
- OPT_CALLBACK_F('N', "no-numbered", &numbered, NULL,
+ OPT_CALLBACK_F('N', "no-numbered", &cfg, NULL,
N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
- OPT_BOOL('s', "signoff", &do_signoff, N_("add a Signed-off-by trailer")),
+ OPT_BOOL('s', "signoff", &cfg.do_signoff, N_("add a Signed-off-by trailer")),
OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
OPT_BOOL(0, "cover-letter", &cover_letter,
@@ -1928,21 +2060,23 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("start numbering patches at <n> instead of 1")),
OPT_STRING('v', "reroll-count", &reroll_count, N_("reroll-count"),
N_("mark the series as Nth re-roll")),
- OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
+ OPT_INTEGER(0, "filename-max-length", &cfg.log.fmt_patch_name_max,
N_("max length of output filename")),
- OPT_CALLBACK_F(0, "rfc", &rev, NULL,
- N_("use [RFC PATCH] instead of [PATCH]"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
+ OPT_CALLBACK_F(0, "rfc", &rfc, N_("rfc"),
+ N_("add <rfc> (default 'RFC') before 'PATCH'"),
+ PARSE_OPT_OPTARG, rfc_callback),
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
N_("cover-from-description-mode"),
N_("generate parts of a cover letter based on a branch's description")),
- OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
+ OPT_FILENAME(0, "description-file", &description_file,
+ N_("use branch description from file")),
+ OPT_CALLBACK_F(0, "subject-prefix", &cfg, N_("prefix"),
N_("use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
N_("dir"), N_("store resulting files in <dir>"),
PARSE_OPT_NONEG, output_directory_callback),
- OPT_CALLBACK_F('k', "keep-subject", &rev, NULL,
+ OPT_CALLBACK_F('k', "keep-subject", &keep_callback_data, NULL,
N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback),
OPT_BOOL(0, "no-binary", &no_binary_diff,
@@ -1955,11 +2089,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("show patch format instead of default (patch + stat)"),
1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Messaging")),
- OPT_CALLBACK(0, "add-header", NULL, N_("header"),
+ OPT_CALLBACK(0, "add-header", &cfg, N_("header"),
N_("add email header"), header_callback),
- OPT_CALLBACK(0, "to", NULL, N_("email"), N_("add To: header"), to_callback),
- OPT_CALLBACK(0, "cc", NULL, N_("email"), N_("add Cc: header"), cc_callback),
- OPT_CALLBACK_F(0, "from", &from, N_("ident"),
+ OPT_STRING_LIST(0, "to", &cfg.extra_to, N_("email"), N_("add To: header")),
+ OPT_STRING_LIST(0, "cc", &cfg.extra_cc, N_("email"), N_("add Cc: header")),
+ OPT_CALLBACK_F(0, "from", &cfg.from, N_("ident"),
N_("set From address to <ident> (or committer ident if absent)"),
PARSE_OPT_OPTARG, from_callback),
OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
@@ -1971,15 +2105,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("inline the patch"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
inline_callback),
- OPT_CALLBACK_F(0, "thread", &thread, N_("style"),
+ OPT_CALLBACK_F(0, "thread", &cfg, N_("style"),
N_("enable message threading, styles: shallow, deep"),
PARSE_OPT_OPTARG, thread_callback),
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_CALLBACK_F(0, "base", &base_commit, N_("base-commit"),
+ OPT_CALLBACK_F(0, "base", &cfg, N_("base-commit"),
N_("add prerequisite tree info to the patch series"),
0, base_callback),
- OPT_FILENAME(0, "signature-file", &signature_file,
+ OPT_FILENAME(0, "signature-file", &signature_file_arg,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_BOOL(0, "progress", &show_progress,
@@ -1996,36 +2130,33 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_END()
};
- extra_hdr.strdup_strings = 1;
- extra_to.strdup_strings = 1;
- extra_cc.strdup_strings = 1;
-
- init_log_defaults();
- init_display_notes(&notes_opt);
- git_config(git_format_config, NULL);
+ format_config_init(&cfg);
+ init_diff_ui_defaults();
+ init_display_notes(&cfg.notes_opt);
+ git_config(git_format_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
- rev.show_notes = show_notes;
- memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
+ rev.show_notes = cfg.show_notes;
+ memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
rev.commit_format = CMIT_FMT_EMAIL;
- rev.encode_email_headers = default_encode_email_headers;
+ rev.encode_email_headers = cfg.log.default_encode_email_headers;
rev.expand_tabs_in_log_default = 0;
rev.verbose_header = 1;
rev.diff = 1;
rev.max_parents = 1;
rev.diffopt.flags.recursive = 1;
rev.diffopt.no_free = 1;
- rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
+ strbuf_addstr(&cfg.sprefix, cfg.log.fmt_patch_subject_prefix);
if (format_no_prefix)
diff_set_noprefix(&rev.diffopt);
- if (default_attach) {
- rev.mime_boundary = default_attach;
+ if (cfg.default_attach) {
+ rev.mime_boundary = cfg.default_attach;
rev.no_inline = 1;
}
@@ -2041,52 +2172,63 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.force_in_body_from = force_in_body_from;
+ if (!fmt_patch_suffix)
+ fmt_patch_suffix = cfg.fmt_patch_suffix;
+
/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
- if (fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
- fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
+ if (cfg.log.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
+ cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
if (cover_from_description_arg)
- cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+ cfg.cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+
+ if (rfc && rfc[0]) {
+ cfg.subject_prefix = 1;
+ if (rfc[0] == '-')
+ strbuf_addf(&cfg.sprefix, " %s", rfc + 1);
+ else
+ strbuf_insertf(&cfg.sprefix, 0, "%s ", rfc);
+ }
if (reroll_count) {
- strbuf_addf(&sprefix, "%s v%s",
- rev.subject_prefix, reroll_count);
+ strbuf_addf(&cfg.sprefix, " v%s", reroll_count);
rev.reroll_count = reroll_count;
- rev.subject_prefix = sprefix.buf;
}
- for (i = 0; i < extra_hdr.nr; i++) {
- strbuf_addstr(&buf, extra_hdr.items[i].string);
+ rev.subject_prefix = cfg.sprefix.buf;
+
+ for (i = 0; i < cfg.extra_hdr.nr; i++) {
+ strbuf_addstr(&buf, cfg.extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
}
- if (extra_to.nr)
+ if (cfg.extra_to.nr)
strbuf_addstr(&buf, "To: ");
- for (i = 0; i < extra_to.nr; i++) {
+ for (i = 0; i < cfg.extra_to.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
- strbuf_addstr(&buf, extra_to.items[i].string);
- if (i + 1 < extra_to.nr)
+ strbuf_addstr(&buf, cfg.extra_to.items[i].string);
+ if (i + 1 < cfg.extra_to.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
- if (extra_cc.nr)
+ if (cfg.extra_cc.nr)
strbuf_addstr(&buf, "Cc: ");
- for (i = 0; i < extra_cc.nr; i++) {
+ for (i = 0; i < cfg.extra_cc.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
- strbuf_addstr(&buf, extra_cc.items[i].string);
- if (i + 1 < extra_cc.nr)
+ strbuf_addstr(&buf, cfg.extra_cc.items[i].string);
+ if (i + 1 < cfg.extra_cc.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
rev.extra_headers = to_free = strbuf_detach(&buf, NULL);
- if (from) {
- if (split_ident_line(&rev.from_ident, from, strlen(from)))
- die(_("invalid ident line: %s"), from);
+ if (cfg.from) {
+ if (split_ident_line(&rev.from_ident, cfg.from, strlen(cfg.from)))
+ die(_("invalid ident line: %s"), cfg.from);
}
if (start_number < 0)
@@ -2097,14 +2239,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
- if (numbered && keep_subject && !numbered_cmdline_opt)
- numbered = 0;
+ if (cfg.numbered && cfg.keep_subject && !cfg.numbered_cmdline_opt)
+ cfg.numbered = 0;
- if (numbered && keep_subject)
+ if (cfg.numbered && cfg.keep_subject)
die(_("options '%s' and '%s' cannot be used together"), "-n", "-k");
- if (keep_subject && subject_prefix)
+ if (cfg.keep_subject && cfg.subject_prefix)
die(_("options '%s' and '%s' cannot be used together"), "--subject-prefix/--rfc", "-k");
- rev.preserve_subject = keep_subject;
+ rev.preserve_subject = cfg.keep_subject;
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
if (argc > 1)
@@ -2131,7 +2273,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.always_show_header = 1;
rev.zero_commit = zero_commit;
- rev.patch_name_max = fmt_patch_name_max;
+ rev.patch_name_max = cfg.log.fmt_patch_name_max;
if (!rev.diffopt.flags.text && !no_binary_diff)
rev.diffopt.flags.binary = 1;
@@ -2152,7 +2294,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int saved;
if (!output_directory)
- output_directory = config_output_directory;
+ output_directory = cfg.config_output_directory;
output_directory = set_outdir(prefix, output_directory);
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
@@ -2201,8 +2343,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (check_head) {
const char *ref, *v;
- ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- NULL, NULL);
+ ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD",
+ RESOLVE_REF_READING,
+ NULL, NULL);
if (ref && skip_prefix(ref, "refs/heads/", &v))
branch_name = xstrdup(v);
else
@@ -2248,14 +2392,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
goto done;
total = nr;
if (cover_letter == -1) {
- if (config_cover_letter == COVER_AUTO)
+ if (cfg.config_cover_letter == COVER_AUTO)
cover_letter = (total > 1);
+ else if ((idiff_prev.nr || rdiff_prev) && (total > 1))
+ cover_letter = (cfg.config_cover_letter != COVER_OFF);
else
- cover_letter = (config_cover_letter == COVER_ON);
+ cover_letter = (cfg.config_cover_letter == COVER_ON);
}
- if (!keep_subject && auto_number && (total > 1 || cover_letter))
- numbered = 1;
- if (numbered)
+ if (!cfg.keep_subject && cfg.auto_number && (total > 1 || cover_letter))
+ cfg.numbered = 1;
+ if (cfg.numbered)
rev.total = total + start_number - 1;
if (idiff_prev.nr) {
@@ -2269,7 +2415,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
if (creation_factor < 0)
- creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
+ creation_factor = CREATION_FACTOR_FOR_THE_SAME_SERIES;
else if (!rdiff_prev)
die(_("the option '%s' requires '%s'"), "--creation-factor", "--range-diff");
@@ -2287,27 +2433,40 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
_("Range-diff against v%d:"));
}
+ /*
+ * The order of precedence is:
+ *
+ * 1. The `--signature` and `--no-signature` options.
+ * 2. The `--signature-file` option.
+ * 3. The `format.signature` config.
+ * 4. The `format.signatureFile` config.
+ * 5. Default `git_version_string`.
+ */
if (!signature) {
; /* --no-signature inhibits all signatures */
} else if (signature && signature != git_version_string) {
; /* non-default signature already set */
- } else if (signature_file) {
+ } else if (signature_file_arg || (cfg.signature_file && !cfg.signature)) {
struct strbuf buf = STRBUF_INIT;
+ const char *signature_file = signature_file_arg ?
+ signature_file_arg : cfg.signature_file;
if (strbuf_read_file(&buf, signature_file, 128) < 0)
die_errno(_("unable to read signature file '%s'"), signature_file);
- signature = strbuf_detach(&buf, NULL);
+ signature = signature_to_free = strbuf_detach(&buf, NULL);
+ } else if (cfg.signature) {
+ signature = cfg.signature;
}
memset(&bases, 0, sizeof(bases));
- base = get_base_commit(base_commit, list, nr);
+ base = get_base_commit(&cfg, list, nr);
if (base) {
reset_revision_walk();
clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);
}
- if (in_reply_to || thread || cover_letter) {
+ if (in_reply_to || cfg.thread || cover_letter) {
rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
string_list_init_dup(rev.ref_message_ids);
}
@@ -2318,19 +2477,19 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.numbered_files = just_numbers;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
- if (thread)
+ if (cfg.thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, !!output_directory,
- origin, nr, list, branch_name, quiet);
+ origin, nr, list, description_file, branch_name, quiet, &cfg);
print_bases(&bases, rev.diffopt.file);
- print_signature(rev.diffopt.file);
+ print_signature(signature, rev.diffopt.file);
total++;
start_number--;
/* interdiff/range-diff in cover-letter; omit from patches */
rev.idiff_oid1 = NULL;
rev.rdiff1 = NULL;
}
- rev.add_signoff = do_signoff;
+ rev.add_signoff = cfg.do_signoff;
if (show_progress)
progress = start_delayed_progress(_("Generating patches"), total);
@@ -2340,7 +2499,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
commit = list[nr];
rev.nr = total - nr + (start_number - 1);
/* Make the second and subsequent mails replies to the first */
- if (thread) {
+ if (cfg.thread) {
/* Have we already had a message ID? */
if (rev.message_id) {
/*
@@ -2364,7 +2523,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
* letter is a reply to the
* --in-reply-to, if specified.
*/
- if (thread == THREAD_SHALLOW
+ if (cfg.thread == THREAD_SHALLOW
&& rev.ref_message_ids->nr > 0
&& (!cover_letter || rev.nr > 1))
free(rev.message_id);
@@ -2397,17 +2556,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
mime_boundary_leader,
rev.mime_boundary);
else
- print_signature(rev.diffopt.file);
+ print_signature(signature, rev.diffopt.file);
}
- if (output_directory)
+ if (output_directory) {
fclose(rev.diffopt.file);
+ rev.diffopt.file = NULL;
+ }
}
stop_progress(&progress);
free(list);
- free(branch_name);
- string_list_clear(&extra_to, 0);
- string_list_clear(&extra_cc, 0);
- string_list_clear(&extra_hdr, 0);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
@@ -2417,13 +2574,19 @@ done:
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
- strbuf_release(&sprefix);
+ free(description_file);
+ free(signature_file_arg);
+ free(signature_to_free);
+ free(branch_name);
free(to_free);
free(rev.message_id);
if (rev.ref_message_ids)
string_list_clear(rev.ref_message_ids, 0);
free(rev.ref_message_ids);
- return cmd_log_deinit(0, &rev);
+ rev.diffopt.no_free = 0;
+ release_revisions(&rev);
+ format_config_release(&cfg);
+ return 0;
}
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
@@ -2462,7 +2625,10 @@ static void print_commit(char sign, struct commit *commit, int verbose,
}
}
-int cmd_cherry(int argc, const char **argv, const char *prefix)
+int cmd_cherry(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info revs;
struct patch_ids ids;
@@ -2530,16 +2696,16 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
commit_list_insert(commit, &list);
}
- while (list) {
+ for (struct commit_list *l = list; l; l = l->next) {
char sign = '+';
- commit = list->item;
+ commit = l->item;
if (has_commit_patch_id(commit, &ids))
sign = '-';
print_commit(sign, commit, verbose, abbrev, revs.diffopt.file);
- list = list->next;
}
+ free_commit_list(list);
free_patch_ids(&ids);
return 0;
}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a0229c3277..e016b0415d 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -5,8 +5,8 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
-#include "repository.h"
#include "config.h"
#include "convert.h"
#include "quote.h"
@@ -14,19 +14,15 @@
#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"
@@ -270,7 +266,6 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
struct strbuf sb = STRBUF_INIT;
while (strbuf_expand_step(&sb, &format)) {
- const char *end;
size_t len;
struct stat st;
@@ -278,12 +273,6 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
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))
@@ -312,8 +301,7 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
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_expand_bad_format(format, "ls-files");
}
strbuf_addch(&sb, line_terminator);
fwrite(sb.buf, sb.len, 1, stdout);
@@ -519,7 +507,7 @@ static int get_common_prefix_len(const char *common_prefix)
common_prefix_len = strlen(common_prefix);
/*
- * If the prefix has a trailing slash, strip it so that submodules wont
+ * If the prefix has a trailing slash, strip it so that submodules won't
* be pruned from the index.
*/
if (common_prefix[common_prefix_len - 1] == '/')
@@ -573,7 +561,10 @@ static int option_parse_exclude_standard(const struct option *opt,
return 0;
}
-int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
+int cmd_ls_files(int argc,
+ const char **argv,
+ const char *cmd_prefix,
+ struct repository *repo UNUSED)
{
int require_work_tree = 0, show_tag = 0, i;
char *max_prefix;
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index fc76575430..42f34e1236 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
@@ -5,12 +6,11 @@
#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"
+ N_("git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
" [--symref] [<repository> [<patterns>...]]"),
NULL
@@ -20,17 +20,16 @@ static const char * const ls_remote_usage[] = {
* Is there one among the list of patterns that match the tail part
* of the path?
*/
-static int tail_match(const char **pattern, const char *path)
+static int tail_match(const struct strvec *pattern, const char *path)
{
- const char *p;
char *pathbuf;
- if (!pattern)
+ if (!pattern->nr)
return 1; /* no restriction */
pathbuf = xstrfmt("/%s", path);
- while ((p = *(pattern++)) != NULL) {
- if (!wildmatch(p, pathbuf, 0)) {
+ for (size_t i = 0; i < pattern->nr; i++) {
+ if (!wildmatch(pattern->v[i], pathbuf, 0)) {
free(pathbuf);
return 1;
}
@@ -39,7 +38,10 @@ static int tail_match(const char **pattern, const char *path)
return 0;
}
-int cmd_ls_remote(int argc, const char **argv, const char *prefix)
+int cmd_ls_remote(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char *dest = NULL;
unsigned flags = 0;
@@ -48,7 +50,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
int status = 0;
int show_symref_target = 0;
const char *uploadpack = NULL;
- const char **pattern = NULL;
+ struct strvec pattern = STRVEC_INIT;
struct transport_ls_refs_options transport_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
int i;
@@ -58,6 +60,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
struct transport *transport;
const struct ref *ref;
struct ref_array ref_array;
+ struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct option options[] = {
@@ -68,7 +71,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
N_("path of git-upload-pack on the remote host"),
PARSE_OPT_HIDDEN },
OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS),
- OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS),
+ OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES),
+ OPT_BIT_F('h', "heads", &flags,
+ N_("deprecated synonym for --branches"), REF_BRANCHES,
+ PARSE_OPT_HIDDEN),
OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
OPT_BOOL(0, "get-url", &get_url,
N_("take url.<base>.insteadOf into account")),
@@ -88,19 +94,29 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION);
dest = argv[0];
+ /*
+ * TODO: This is buggy, but required for transport helpers. When a
+ * transport helper advertises a "refspec", then we'd add that to a
+ * list of refspecs via `refspec_append()`, which transitively depends
+ * on `the_hash_algo`. Thus, when the hash algorithm isn't properly set
+ * up, this would lead to a segfault.
+ *
+ * We really should fix this in the transport helper logic such that we
+ * lazily parse refspec capabilities _after_ we have learned about the
+ * remote's object format. Otherwise, we may end up misparsing refspecs
+ * depending on what object hash the remote uses.
+ */
+ if (!the_repository->hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
packet_trace_identity("ls-remote");
- if (argc > 1) {
- int i;
- CALLOC_ARRAY(pattern, argc);
- for (i = 1; i < argc; i++) {
- pattern[i - 1] = xstrfmt("*/%s", argv[i]);
- }
- }
+ for (int i = 1; i < argc; i++)
+ strvec_pushf(&pattern, "*/%s", argv[i]);
if (flags & REF_TAGS)
strvec_push(&transport_options.ref_prefixes, "refs/tags/");
- if (flags & REF_HEADS)
+ if (flags & REF_BRANCHES)
strvec_push(&transport_options.ref_prefixes, "refs/heads/");
remote = remote_get(dest);
@@ -109,11 +125,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
die("bad repository '%s'", dest);
die("No remote configured to list refs from.");
}
- if (!remote->url_nr)
- die("remote %s has no configured URL", dest);
if (get_url) {
- printf("%s\n", *remote->url);
+ printf("%s\n", remote->url.v[0]);
return 0;
}
@@ -130,24 +144,19 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
}
if (!dest && !quiet)
- fprintf(stderr, "From %s\n", *remote->url);
+ fprintf(stderr, "From %s\n", remote->url.v[0]);
for ( ; ref; ref = ref->next) {
struct ref_array_item *item;
if (!check_ref_type(ref, flags))
continue;
- if (!tail_match(pattern, ref->name))
+ if (!tail_match(&pattern, ref->name))
continue;
item = ref_array_push(&ref_array, ref->name, &ref->old_oid);
item->symref = xstrdup_or_null(ref->symref);
}
- if (sorting_options.nr) {
- struct ref_sorting *sorting;
-
- sorting = ref_sorting_options(&sorting_options);
- ref_array_sort(sorting, &ref_array);
- ref_sorting_release(sorting);
- }
+ sorting = ref_sorting_options(&sorting_options);
+ ref_array_sort(sorting, &ref_array);
for (i = 0; i < ref_array.nr; i++) {
const struct ref_array_item *ref = ref_array.items[i];
@@ -157,9 +166,14 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
status = 0; /* we found something */
}
+ string_list_clear(&server_options, 0);
+ ref_sorting_release(sorting);
ref_array_clear(&ref_array);
if (transport_disconnect(transport))
status = 1;
transport_ls_refs_options_release(&transport_options);
+
+ strvec_clear(&pattern);
+ string_list_clear(&server_options, 0);
return status;
}
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index f558db5f3b..8542b5d53e 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -3,15 +3,15 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+
#include "config.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 "parse-options.h"
@@ -102,19 +102,12 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
return 0;
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))
@@ -137,8 +130,7 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
strbuf_setlen(base, baselen);
strbuf_release(&sbuf);
} else
- die(_("bad ls-tree format: %%%.*s"),
- (int)(end - format + 1), format);
+ strbuf_expand_bad_format(format, "ls-tree");
}
strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
fwrite(sb.buf, sb.len, 1, stdout);
@@ -241,7 +233,8 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
return recurse;
}
-static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+static int show_tree_name_only(const struct object_id *oid UNUSED,
+ struct strbuf *base,
const char *pathname, unsigned mode,
void *context)
{
@@ -338,7 +331,10 @@ static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
},
};
-int cmd_ls_tree(int argc, const char **argv, const char *prefix)
+int cmd_ls_tree(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct object_id oid;
struct tree *tree;
@@ -376,6 +372,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
OPT_END()
};
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+ struct object_context obj_context = {0};
int ret;
git_config(git_default_config, NULL);
@@ -407,7 +404,9 @@ 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 (repo_get_oid(the_repository, argv[0], &oid))
+ if (get_oid_with_context(the_repository, argv[0],
+ GET_OID_HASH_ANY, &oid,
+ &obj_context))
die("Not a valid object name %s", argv[0]);
/*
@@ -447,5 +446,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
clear_pathspec(&options.pathspec);
+ object_context_release(&obj_context);
return ret;
}
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 53b55dd71c..e17dec27b1 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -2,11 +2,11 @@
* Another stupid program, this one parsing the headers of an
* email to figure out authorship and subject
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "environment.h"
#include "gettext.h"
-#include "utf8.h"
#include "strbuf.h"
#include "mailinfo.h"
#include "parse-options.h"
@@ -49,7 +49,10 @@ static int parse_opt_quoted_cr(const struct option *opt, const char *arg, int un
return 0;
}
-int cmd_mailinfo(int argc, const char **argv, const char *prefix)
+int cmd_mailinfo(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct metainfo_charset meta_charset;
struct mailinfo mi;
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 3af9ddb8ae..b8f7150ce9 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -113,8 +113,8 @@ static int populate_maildir_list(struct string_list *list, const char *path)
DIR *dir;
struct dirent *dent;
char *name = NULL;
- char *subs[] = { "cur", "new", NULL };
- char **sub;
+ const char *subs[] = { "cur", "new", NULL };
+ const char **sub;
int ret = -1;
for (sub = subs; *sub; ++sub) {
@@ -269,7 +269,10 @@ out:
return ret;
}
-int cmd_mailsplit(int argc, const char **argv, const char *prefix)
+int cmd_mailsplit(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int nr = 0, nr_prec = 4, num = 0;
int allow_bare = 0;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index e68b7fe45d..a20c93b11a 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -1,22 +1,22 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
- struct commit_list *result, *r;
+ struct commit_list *result = NULL, *r;
- result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
- rev_nr - 1, rev + 1);
+ if (repo_get_merge_bases_many_dirty(the_repository, rev[0],
+ rev_nr - 1, rev + 1, &result) < 0) {
+ free_commit_list(result);
+ return -1;
+ }
if (!result)
return 1;
@@ -77,13 +77,17 @@ static int handle_independent(int count, const char **args)
static int handle_octopus(int count, const char **args, int show_all)
{
struct commit_list *revs = NULL;
- struct commit_list *result, *rev;
+ struct commit_list *result = NULL, *rev;
int i;
for (i = count - 1; i >= 0; i--)
commit_list_insert(get_commit_reference(args[i]), &revs);
- result = get_octopus_merge_bases(revs);
+ if (get_octopus_merge_bases(revs, &result) < 0) {
+ free_commit_list(revs);
+ free_commit_list(result);
+ return 128;
+ }
free_commit_list(revs);
reduce_heads_replace(&result);
@@ -103,12 +107,16 @@ static int handle_octopus(int count, const char **args, int show_all)
static int handle_is_ancestor(int argc, const char **argv)
{
struct commit *one, *two;
+ int ret;
if (argc != 2)
die("--is-ancestor takes exactly two commits");
one = get_commit_reference(argv[0]);
two = get_commit_reference(argv[1]);
- if (repo_in_merge_bases(the_repository, one, two))
+ ret = repo_in_merge_bases(the_repository, one, two);
+ if (ret < 0)
+ exit(128);
+ if (ret)
return 0;
else
return 1;
@@ -135,7 +143,10 @@ static int handle_fork_point(int argc, const char **argv)
return 0;
}
-int cmd_merge_base(int argc, const char **argv, const char *prefix)
+int cmd_merge_base(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct commit **rev;
int rev_nr = 0;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index d7eb4c6540..cb42865eb5 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -1,5 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
+#include "diff.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store.h"
#include "config.h"
#include "gettext.h"
#include "setup.h"
@@ -25,16 +30,44 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
-int cmd_merge_file(int argc, const char **argv, const char *prefix)
+static int set_diff_algorithm(xpparam_t *xpp,
+ const char *alg)
+{
+ long diff_algorithm = parse_algorithm_value(alg);
+ if (diff_algorithm < 0)
+ return -1;
+ xpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
+ return 0;
+}
+
+static int diff_algorithm_cb(const struct option *opt,
+ const char *arg, int unset)
+{
+ xpparam_t *xpp = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ if (set_diff_algorithm(xpp, arg))
+ return error(_("option diff-algorithm accepts \"myers\", "
+ "\"minimal\", \"patience\" and \"histogram\""));
+
+ return 0;
+}
+
+int cmd_merge_file(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char *names[3] = { 0 };
mmfile_t mmfs[3] = { 0 };
mmbuffer_t result = { 0 };
xmparam_t xmp = { 0 };
- int ret = 0, i = 0, to_stdout = 0;
+ int ret = 0, i = 0, to_stdout = 0, object_id = 0;
int quiet = 0;
struct option options[] = {
OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
+ OPT_BOOL(0, "object-id", &object_id, N_("use object IDs instead of filenames")),
OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
XDL_MERGE_ZEALOUS_DIFF3),
@@ -44,6 +77,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
XDL_MERGE_FAVOR_THEIRS),
OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
XDL_MERGE_FAVOR_UNION),
+ OPT_CALLBACK_F(0, "diff-algorithm", &xmp.xpp, N_("<algorithm>"),
+ N_("choose a diff algorithm"),
+ PARSE_OPT_NONEG, diff_algorithm_cb),
OPT_INTEGER(0, "marker-size", &xmp.marker_size,
N_("for conflicts, use this marker size")),
OPT__QUIET(&quiet, N_("do not warn about conflicts")),
@@ -71,8 +107,12 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
return error_errno("failed to redirect stderr to /dev/null");
}
+ if (object_id)
+ setup_git_directory();
+
for (i = 0; i < 3; i++) {
char *fname;
+ struct object_id oid;
mmfile_t *mmf = mmfs + i;
if (!names[i])
@@ -80,12 +120,22 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
fname = prefix_filename(prefix, argv[i]);
- if (read_mmfile(mmf, fname))
+ if (object_id) {
+ if (repo_get_oid(the_repository, argv[i], &oid))
+ ret = error(_("object '%s' does not exist"),
+ argv[i]);
+ else if (!oideq(&oid, the_hash_algo->empty_blob))
+ read_mmblob(mmf, &oid);
+ else
+ read_mmfile(mmf, "/dev/null");
+ } else if (read_mmfile(mmf, fname)) {
ret = -1;
- else if (mmf->size > MAX_XDIFF_SIZE ||
- buffer_is_binary(mmf->ptr, mmf->size))
+ }
+ if (ret != -1 && (mmf->size > MAX_XDIFF_SIZE ||
+ buffer_is_binary(mmf->ptr, mmf->size))) {
ret = error("Cannot merge binary files: %s",
argv[i]);
+ }
free(fname);
if (ret)
@@ -99,20 +149,32 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
if (ret >= 0) {
- const char *filename = argv[0];
- char *fpath = prefix_filename(prefix, argv[0]);
- FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
-
- if (!f)
- ret = error_errno("Could not open %s for writing",
- filename);
- else if (result.size &&
- fwrite(result.ptr, result.size, 1, f) != 1)
- ret = error_errno("Could not write to %s", filename);
- else if (fclose(f))
- ret = error_errno("Could not close %s", filename);
+ if (object_id && !to_stdout) {
+ struct object_id oid;
+ if (result.size) {
+ if (write_object_file(result.ptr, result.size, OBJ_BLOB, &oid) < 0)
+ ret = error(_("Could not write object file"));
+ } else {
+ oidcpy(&oid, the_hash_algo->empty_blob);
+ }
+ if (ret >= 0)
+ printf("%s\n", oid_to_hex(&oid));
+ } else {
+ const char *filename = argv[0];
+ char *fpath = prefix_filename(prefix, argv[0]);
+ FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
+
+ if (!f)
+ ret = error_errno("Could not open %s for writing",
+ filename);
+ else if (result.size &&
+ fwrite(result.ptr, result.size, 1, f) != 1)
+ ret = error_errno("Could not write to %s", filename);
+ else if (fclose(f))
+ ret = error_errno("Could not close %s", filename);
+ free(fpath);
+ }
free(result.ptr);
- free(fpath);
}
if (ret > 127)
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 270d5f644a..a5b87ee3c5 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,8 +1,7 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "hex.h"
#include "read-cache-ll.h"
-#include "repository.h"
#include "run-command.h"
#include "sparse-index.h"
@@ -18,11 +17,11 @@ static int merge_entry(int pos, const char *path)
char ownbuf[4][60];
struct child_process cmd = CHILD_PROCESS_INIT;
- if (pos >= the_index.cache_nr)
+ if (pos >= the_repository->index->cache_nr)
die("git merge-index: %s not in the cache", path);
found = 0;
do {
- const struct cache_entry *ce = the_index.cache[pos];
+ const struct cache_entry *ce = the_repository->index->cache[pos];
int stage = ce_stage(ce);
if (strcmp(ce->name, path))
@@ -32,7 +31,7 @@ static int merge_entry(int pos, const char *path)
xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
arguments[stage] = hexbuf[stage];
arguments[stage + 4] = ownbuf[stage];
- } while (++pos < the_index.cache_nr);
+ } while (++pos < the_repository->index->cache_nr);
if (!found)
die("git merge-index: %s not in the cache", path);
@@ -51,7 +50,7 @@ static int merge_entry(int pos, const char *path)
static void merge_one_path(const char *path)
{
- int pos = index_name_pos(&the_index, path, strlen(path));
+ int pos = index_name_pos(the_repository->index, path, strlen(path));
/*
* If it already exists in the cache as stage0, it's
@@ -65,16 +64,19 @@ static void merge_all(void)
{
int i;
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
if (!ce_stage(ce))
continue;
i += merge_entry(i, ce->name)-1;
}
}
-int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_merge_index(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
int i, force_file = 0;
@@ -89,7 +91,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED)
repo_read_index(the_repository);
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
i = 1;
if (!strcmp(argv[i], "-o")) {
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 932924e5d0..1fcf53f005 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -7,15 +7,19 @@
*
* Pretend we resolved the heads, but declare our tree trumps everybody else.
*/
+#define USE_THE_REPOSITORY_VARIABLE
#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 UNUSED)
+int cmd_merge_ours(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_merge_ours_usage);
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 3366699657..1dd295558b 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -1,13 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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[] =
"git %s <base>... -- <head> <remote> ...";
@@ -24,9 +21,12 @@ 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 UNUSED)
+int cmd_merge_recursive(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
- const struct object_id *bases[21];
+ struct object_id bases[21];
unsigned bases_count = 0;
int i, failed;
struct object_id h1, h2;
@@ -34,7 +34,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
char *better1, *better2;
struct commit *result;
- init_merge_options(&o, the_repository);
+ init_basic_merge_options(&o, the_repository);
if (argv[0] && ends_with(argv[0], "-subtree"))
o.subtree_shift = "";
@@ -52,10 +52,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
continue;
}
if (bases_count < ARRAY_SIZE(bases)-1) {
- struct object_id *oid = xmalloc(sizeof(struct object_id));
- if (repo_get_oid(the_repository, argv[i], oid))
+ if (repo_get_oid(the_repository, argv[i], &bases[bases_count++]))
die(_("could not parse object '%s'"), argv[i]);
- bases[bases_count++] = oid;
}
else
warning(Q_("cannot handle more than %d base. "
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 0de42aecf4..c5ed472967 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
@@ -11,13 +11,12 @@
#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"
+#include "strvec.h"
static int line_termination = '\n';
@@ -364,7 +363,7 @@ static void trivial_merge_trees(struct tree_desc t[3], const char *base)
setup_traverse_info(&info, base);
info.fn = threeway_callback;
- traverse_trees(&the_index, 3, t, &info);
+ traverse_trees(the_repository->index, 3, t, &info);
}
static void *get_tree_descriptor(struct repository *r,
@@ -414,6 +413,7 @@ struct merge_tree_options {
int show_messages;
int name_only;
int use_stdin;
+ struct merge_options merge_options;
};
static int real_merge(struct merge_tree_options *o,
@@ -423,51 +423,66 @@ static int real_merge(struct merge_tree_options *o,
{
struct commit *parent1, *parent2;
struct commit_list *merge_bases = NULL;
- struct merge_options opt;
struct merge_result result = { 0 };
int show_messages = o->show_messages;
+ struct merge_options opt;
- parent1 = get_merge_parent(branch1);
- if (!parent1)
- help_unknown_ref(branch1, "merge-tree",
- _("not something we can merge"));
-
- parent2 = get_merge_parent(branch2);
- if (!parent2)
- help_unknown_ref(branch2, "merge-tree",
- _("not something we can merge"));
-
- init_merge_options(&opt, the_repository);
-
+ copy_merge_options(&opt, &o->merge_options);
opt.show_rename_progress = 0;
opt.branch1 = branch1;
opt.branch2 = branch2;
if (merge_base) {
- struct commit *base_commit;
struct tree *base_tree, *parent1_tree, *parent2_tree;
- base_commit = lookup_commit_reference_by_name(merge_base);
- if (!base_commit)
- die(_("could not lookup commit '%s'"), merge_base);
+ /*
+ * We actually only need the trees because we already
+ * have a merge base.
+ */
+ struct object_id base_oid, head_oid, merge_oid;
+
+ if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
+ die(_("could not parse as tree '%s'"), merge_base);
+ base_tree = parse_tree_indirect(&base_oid);
+ if (!base_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
+ if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
+ die(_("could not parse as tree '%s'"), branch1);
+ parent1_tree = parse_tree_indirect(&head_oid);
+ if (!parent1_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
+ if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
+ die(_("could not parse as tree '%s'"), branch2);
+ parent2_tree = parse_tree_indirect(&merge_oid);
+ if (!parent2_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
opt.ancestor = merge_base;
- 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 {
+ parent1 = get_merge_parent(branch1);
+ if (!parent1)
+ help_unknown_ref(branch1, "merge-tree",
+ _("not something we can merge"));
+
+ parent2 = get_merge_parent(branch2);
+ if (!parent2)
+ help_unknown_ref(branch2, "merge-tree",
+ _("not something we can merge"));
+
/*
* Get the merge bases, in reverse order; see comment above
* merge_incore_recursive in merge-ort.h
*/
- merge_bases = repo_get_merge_bases(the_repository, parent1,
- parent2);
+ if (repo_get_merge_bases(the_repository, parent1,
+ parent2, &merge_bases) < 0)
+ exit(128);
if (!merge_bases && !o->allow_unrelated_histories)
die(_("refusing to merge unrelated histories"));
merge_bases = reverse_commit_list(merge_bases);
merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+ free_commit_list(merge_bases);
}
if (result.clean < 0)
@@ -507,15 +522,21 @@ static int real_merge(struct merge_tree_options *o,
if (o->use_stdin)
putchar(line_termination);
merge_finalize(&opt, &result);
+ clear_merge_options(&opt);
return !result.clean; /* result.clean < 0 handled above */
}
-int cmd_merge_tree(int argc, const char **argv, const char *prefix)
+int cmd_merge_tree(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct merge_tree_options o = { .show_messages = -1 };
+ struct strvec xopts = STRVEC_INIT;
int expected_remaining_argc;
int original_argc;
const char *merge_base = NULL;
+ int ret;
const char * const merge_tree_usage[] = {
N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -546,16 +567,27 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
PARSE_OPT_NONEG),
OPT_STRING(0, "merge-base",
&merge_base,
- N_("commit"),
+ N_("tree-ish"),
N_("specify a merge-base for the merge")),
+ OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy")),
OPT_END()
};
+ /* Init merge options */
+ init_ui_merge_options(&o.merge_options, the_repository);
+
/* Parse arguments */
original_argc = argc - 1; /* ignoring argv[0] */
argc = parse_options(argc, argv, prefix, mt_options,
merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+ if (xopts.nr && o.mode == MODE_TRIVIAL)
+ die(_("--trivial-merge is incompatible with all other options"));
+ for (int x = 0; x < xopts.nr; x++)
+ if (parse_merge_opt(&o.merge_options, xopts.v[x]))
+ die(_("unknown strategy option: -X%s"), xopts.v[x]);
+
/* Handle --stdin */
if (o.use_stdin) {
struct strbuf buf = STRBUF_INIT;
@@ -563,7 +595,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (o.mode == MODE_TRIVIAL)
die(_("--trivial-merge is incompatible with all other options"));
if (merge_base)
- die(_("--merge-base is incompatible with --stdin"));
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--merge-base", "--stdin");
line_termination = '\0';
while (strbuf_getline_lf(&buf, stdin) != EOF) {
struct strbuf **split;
@@ -596,7 +629,9 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
strbuf_list_free(split);
}
strbuf_release(&buf);
- return 0;
+
+ ret = 0;
+ goto out;
}
/* Figure out which mode to use */
@@ -635,7 +670,11 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
- return real_merge(&o, merge_base, argv[0], argv[1], prefix);
+ ret = real_merge(&o, merge_base, argv[0], argv[1], prefix);
else
- return trivial_merge(argv[0], argv[1], argv[2]);
+ ret = trivial_merge(argv[0], argv[1], argv[2]);
+
+out:
+ strvec_clear(&xopts);
+ return ret;
}
diff --git a/builtin/merge.c b/builtin/merge.c
index de68910177..51038eaca8 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -5,9 +5,9 @@
*
* Based on git-merge.sh by Junio C Hamano.
*/
-
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+
#include "abspath.h"
#include "advice.h"
#include "config.h"
@@ -18,6 +18,7 @@
#include "object-name.h"
#include "parse-options.h"
#include "lockfile.h"
+#include "repository.h"
#include "run-command.h"
#include "hook.h"
#include "diff.h"
@@ -31,8 +32,6 @@
#include "unpack-trees.h"
#include "cache-tree.h"
#include "dir.h"
-#include "utf8.h"
-#include "log-tree.h"
#include "color.h"
#include "rerere.h"
#include "help.h"
@@ -42,10 +41,8 @@
#include "resolve-undo.h"
#include "remote.h"
#include "fmt-merge-msg.h"
-#include "gpg-interface.h"
#include "sequencer.h"
#include "string-list.h"
-#include "packfile.h"
#include "tag.h"
#include "alias.h"
#include "branch.h"
@@ -79,8 +76,7 @@ static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
static struct strategy **use_strategies;
static size_t use_strategies_nr, use_strategies_alloc;
-static const char **xopts;
-static size_t xopts_nr, xopts_alloc;
+static struct strvec xopts = STRVEC_INIT;
static const char *branch;
static char *branch_mergeoptions;
static int verbosity;
@@ -106,7 +102,7 @@ static struct strategy all_strategy[] = {
{ "subtree", NO_FAST_FORWARD | NO_TRIVIAL },
};
-static const char *pull_twohead, *pull_octopus;
+static char *pull_twohead, *pull_octopus;
enum ff_type {
FF_NO,
@@ -116,7 +112,7 @@ enum ff_type {
static enum ff_type fast_forward = FF_ALLOW;
-static const char *cleanup_arg;
+static char *cleanup_arg;
static enum commit_msg_cleanup_mode cleanup_mode;
static int option_parse_message(const struct option *opt,
@@ -170,7 +166,7 @@ static struct strategy *get_strategy(const char *name)
{
int i;
struct strategy *ret;
- static struct cmdnames main_cmds, other_cmds;
+ static struct cmdnames main_cmds = {0}, other_cmds = {0};
static int loaded;
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
@@ -188,22 +184,22 @@ static struct strategy *get_strategy(const char *name)
return &all_strategy[i];
if (!loaded) {
- struct cmdnames not_strategies;
+ struct cmdnames not_strategies = {0};
loaded = 1;
- memset(&not_strategies, 0, sizeof(struct cmdnames));
load_command_list("git-merge-", &main_cmds, &other_cmds);
for (i = 0; i < main_cmds.cnt; i++) {
int j, found = 0;
struct cmdname *ent = main_cmds.names[i];
for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
- if (!strncmp(ent->name, all_strategy[j].name, ent->len)
- && !all_strategy[j].name[ent->len])
+ if (!xstrncmpz(all_strategy[j].name, ent->name, ent->len))
found = 1;
if (!found)
add_cmdname(&not_strategies, ent->name, ent->len);
}
exclude_cmds(&main_cmds, &not_strategies);
+
+ cmdnames_release(&not_strategies);
}
if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name);
@@ -223,6 +219,9 @@ static struct strategy *get_strategy(const char *name)
CALLOC_ARRAY(ret, 1);
ret->name = xstrdup(name);
ret->attr = NO_TRIVIAL;
+
+ cmdnames_release(&main_cmds);
+ cmdnames_release(&other_cmds);
return ret;
}
@@ -232,7 +231,7 @@ static void append_strategy(struct strategy *s)
use_strategies[use_strategies_nr++] = s;
}
-static int option_parse_strategy(const struct option *opt,
+static int option_parse_strategy(const struct option *opt UNUSED,
const char *name, int unset)
{
if (unset)
@@ -242,29 +241,9 @@ static int option_parse_strategy(const struct option *opt,
return 0;
}
-static int option_parse_x(const struct option *opt,
- const char *arg, int unset)
-{
- if (unset)
- return 0;
-
- ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
- xopts[xopts_nr++] = xstrdup(arg);
- return 0;
-}
-
-static int option_parse_n(const struct option *opt,
- const char *arg, int unset)
-{
- BUG_ON_OPT_ARG(arg);
- show_diffstat = unset;
- return 0;
-}
-
static struct option builtin_merge_options[] = {
- OPT_CALLBACK_F('n', NULL, NULL, NULL,
- N_("do not show a diffstat at the end of the merge"),
- PARSE_OPT_NOARG, option_parse_n),
+ OPT_SET_INT('n', NULL, &show_diffstat,
+ N_("do not show a diffstat at the end of the merge"), 0),
OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")),
OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
@@ -285,10 +264,10 @@ static struct option builtin_merge_options[] = {
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_BOOL(0, "verify-signatures", &verify_signatures,
N_("verify that the named commit has a valid GPG signature")),
- OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+ OPT_CALLBACK('s', "strategy", NULL, N_("strategy"),
N_("merge strategy to use"), option_parse_strategy),
- OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
- N_("option for selected merge strategy"), option_parse_x),
+ OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy")),
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
@@ -326,7 +305,7 @@ static int save_state(struct object_id *stash)
int rc = -1;
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
repo_update_index_if_able(the_repository, &lock_file);
rollback_lock_file(&lock_file);
@@ -357,7 +336,8 @@ static void read_empty(const struct object_id *oid)
{
struct child_process cmd = CHILD_PROCESS_INIT;
- strvec_pushl(&cmd.args, "read-tree", "-m", "-u", empty_tree_oid_hex(),
+ strvec_pushl(&cmd.args, "read-tree", "-m", "-u",
+ empty_tree_oid_hex(the_repository->hash_algo),
oid_to_hex(oid), NULL);
cmd.git_cmd = 1;
@@ -398,7 +378,7 @@ static void restore_state(const struct object_id *head,
run_command(&cmd);
refresh_cache:
- discard_index(&the_index);
+ discard_index(the_repository->index);
if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
}
@@ -475,8 +455,10 @@ static void finish(struct commit *head_commit,
if (verbosity >= 0 && !merge_msg.len)
printf(_("No merge message -- not updating HEAD\n"));
else {
- update_ref(reflog_message.buf, "HEAD", new_head, head,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ reflog_message.buf, "HEAD", new_head,
+ head,
+ 0, UPDATE_REFS_DIE_ON_ERR);
/*
* We ignore errors in 'gc --auto', since the
* user should see them.
@@ -487,8 +469,7 @@ static void finish(struct commit *head_commit,
if (new_head && show_diffstat) {
struct diff_options opts;
repo_diff_setup(the_repository, &opts);
- opts.stat_width = -1; /* use full terminal width */
- opts.stat_graph_width = -1; /* respect statGraphWidth config */
+ init_diffstat_widths(&opts);
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
@@ -499,10 +480,10 @@ static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hooks_l("post-merge", squash ? "1" : "0", NULL);
+ run_hooks_l(the_repository, "post-merge", squash ? "1" : "0", NULL);
if (new_head)
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
strbuf_release(&reflog_message);
}
@@ -520,7 +501,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_branchname(&bname, remote, 0);
remote = bname.buf;
- oidclr(&branch_head);
+ oidclr(&branch_head, the_repository->hash_algo);
remote_head = get_merge_parent(remote);
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
@@ -574,7 +555,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
struct strbuf truname = STRBUF_INIT;
strbuf_addf(&truname, "refs/heads/%s", remote);
strbuf_setlen(&truname, truname.len - len);
- if (ref_exists(truname.buf)) {
+ if (refs_ref_exists(get_main_ref_store(the_repository), truname.buf)) {
strbuf_addf(msg,
"%s\t\tbranch '%s'%s of .\n",
oid_to_hex(&remote_head->object.oid),
@@ -637,17 +618,19 @@ static int git_merge_config(const char *k, const char *v,
return 0;
}
- if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
+ if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) {
show_diffstat = git_config_bool(k, v);
- else if (!strcmp(k, "merge.verifysignatures"))
+ } else if (!strcmp(k, "merge.verifysignatures")) {
verify_signatures = git_config_bool(k, v);
- else if (!strcmp(k, "pull.twohead"))
+ } else if (!strcmp(k, "pull.twohead")) {
+ FREE_AND_NULL(pull_twohead);
return git_config_string(&pull_twohead, k, v);
- else if (!strcmp(k, "pull.octopus"))
+ } else if (!strcmp(k, "pull.octopus")) {
+ FREE_AND_NULL(pull_octopus);
return git_config_string(&pull_octopus, k, v);
- else if (!strcmp(k, "commit.cleanup"))
+ } else if (!strcmp(k, "commit.cleanup")) {
return git_config_string(&cleanup_arg, k, v);
- else if (!strcmp(k, "merge.ff")) {
+ } else if (!strcmp(k, "merge.ff")) {
int boolval = git_parse_maybe_bool(v);
if (0 <= boolval) {
fast_forward = boolval ? FF_ALLOW : FF_NO;
@@ -684,8 +667,8 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
memset(&opts, 0, sizeof(opts));
opts.head_idx = 2;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.update = 1;
opts.verbose_update = 1;
opts.trivial_merges_only = 1;
@@ -701,10 +684,11 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
if (!trees[nr_trees++])
return -1;
opts.fn = threeway_merge;
- cache_tree_free(&the_index.cache_tree);
+ cache_tree_free(&the_repository->index->cache_tree);
for (i = 0; i < nr_trees; i++) {
parse_tree(trees[i]);
- init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+ init_tree_desc(t+i, &trees[i]->object.oid,
+ trees[i]->buffer, trees[i]->size);
}
if (unpack_trees(nr_trees, t, &opts))
return -1;
@@ -713,7 +697,9 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
static void write_tree_trivial(struct object_id *oid)
{
- if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(oid, the_repository->index,
+ repo_get_index_file(the_repository),
+ 0, NULL))
die(_("git write-tree failed to write a tree"));
}
@@ -726,7 +712,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
SKIP_IF_UNCHANGED, 0, NULL, NULL,
NULL) < 0)
- return error(_("Unable to write index."));
+ die(_("Unable to write index."));
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") ||
!strcmp(strategy, "ort")) {
@@ -742,16 +728,16 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
return 2;
}
- init_merge_options(&o, the_repository);
+ init_ui_merge_options(&o, the_repository);
if (!strcmp(strategy, "subtree"))
o.subtree_shift = "";
o.show_rename_progress =
show_progress == -1 ? isatty(2) : show_progress;
- for (x = 0; x < xopts_nr; x++)
- if (parse_merge_opt(&o, xopts[x]))
- die(_("unknown strategy option: -X%s"), xopts[x]);
+ for (x = 0; x < xopts.nr; x++)
+ if (parse_merge_opt(&o, xopts.v[x]))
+ die(_("unknown strategy option: -X%s"), xopts.v[x]);
o.branch1 = head_arg;
o.branch2 = merge_remote_util(remoteheads->item)->name;
@@ -767,17 +753,20 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
else
clean = merge_recursive(&o, head, remoteheads->item,
reversed, &result);
+ free_commit_list(reversed);
+ strbuf_release(&o.obuf);
+
if (clean < 0) {
rollback_lock_file(&lock);
return 2;
}
- if (write_locked_index(&the_index, &lock,
+ if (write_locked_index(the_repository->index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die(_("unable to write %s"), get_index_file());
+ die(_("unable to write %s"), repo_get_index_file(the_repository));
return clean ? 0 : 1;
} else {
return try_merge_command(the_repository,
- strategy, xopts_nr, xopts,
+ strategy, xopts.nr, xopts.v,
common, head_arg, remoteheads);
}
}
@@ -794,8 +783,8 @@ static int count_unmerged_entries(void)
{
int i, ret = 0;
- for (i = 0; i < the_index.cache_nr; i++)
- if (ce_stage(the_index.cache[i]))
+ for (i = 0; i < the_repository->index->cache_nr; i++)
+ if (ce_stage(the_repository->index->cache[i]))
ret++;
return ret;
@@ -848,14 +837,14 @@ static const char scissors_editor_comment[] =
N_("An empty message aborts the commit.\n");
static const char no_scissors_editor_comment[] =
-N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
+N_("Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n");
static void write_merge_heads(struct commit_list *);
static void prepare_to_commit(struct commit_list *remoteheads)
{
struct strbuf msg = STRBUF_INIT;
- const char *index_file = get_index_file();
+ const char *index_file = repo_get_index_file(the_repository);
if (!no_verify) {
int invoked_hook;
@@ -869,9 +858,10 @@ static void prepare_to_commit(struct commit_list *remoteheads)
* the editor and after we invoke run_status above.
*/
if (invoked_hook)
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
- read_index_from(&the_index, index_file, get_git_dir());
+ read_index_from(the_repository->index, index_file,
+ repo_get_git_dir(the_repository));
strbuf_addbuf(&msg, &merge_msg);
if (squash)
BUG("the control must not reach here under --squash");
@@ -879,23 +869,23 @@ 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, comment_line_char, "\n");
+ strbuf_commented_addf(&msg, comment_line_str, "\n");
}
- strbuf_commented_addf(&msg, comment_line_char,
+ strbuf_commented_addf(&msg, comment_line_str,
_(merge_editor_comment));
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
- strbuf_commented_addf(&msg, comment_line_char,
+ strbuf_commented_addf(&msg, comment_line_str,
_(scissors_editor_comment));
else
- strbuf_commented_addf(&msg, comment_line_char,
- _(no_scissors_editor_comment), comment_line_char);
+ strbuf_commented_addf(&msg, comment_line_str,
+ _(no_scissors_editor_comment), comment_line_str);
}
if (signoff)
- append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
+ append_signoff(&msg, ignored_log_message_bytes(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
- if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
- "prepare-commit-msg",
+ if (run_commit_hook(0 < option_edit, repo_get_index_file(the_repository),
+ NULL, "prepare-commit-msg",
git_path_merge_msg(the_repository), "merge", NULL))
abort_commit(remoteheads, NULL);
if (0 < option_edit) {
@@ -903,7 +893,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
abort_commit(remoteheads, NULL);
}
- if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(),
+ if (!no_verify && run_commit_hook(0 < option_edit, repo_get_index_file(the_repository),
NULL, "commit-msg",
git_path_merge_msg(the_repository), NULL))
abort_commit(remoteheads, NULL);
@@ -920,7 +910,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
{
struct object_id result_tree, result_commit;
- struct commit_list *parents, **pptr = &parents;
+ struct commit_list *parents = NULL, **pptr = &parents;
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
SKIP_IF_UNCHANGED, 0, NULL, NULL,
@@ -936,7 +926,9 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
&result_commit, NULL, sign_commit))
die(_("failed to write commit object"));
finish(head, remoteheads, &result_commit, "In-index merge");
+
remove_merge_branch_state(the_repository);
+ free_commit_list(parents);
return 0;
}
@@ -962,8 +954,10 @@ static int finish_automerge(struct commit *head,
die(_("failed to write commit object"));
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
finish(head, remoteheads, &result_commit, buf.buf);
+
strbuf_release(&buf);
remove_merge_branch_state(the_repository);
+ free_commit_list(parents);
return 0;
}
@@ -983,7 +977,7 @@ static int suggest_conflicts(void)
* Thus, we will get the cleanup mode which is returned when we _are_
* using an editor.
*/
- append_conflicts_hint(&the_index, &msgbuf,
+ append_conflicts_hint(the_repository->index, &msgbuf,
get_cleanup_mode(cleanup_arg, 1));
fputs(msgbuf.buf, fp);
strbuf_release(&msgbuf);
@@ -1278,7 +1272,7 @@ static int merging_a_throwaway_tag(struct commit *commit)
*/
tag_ref = xstrfmt("refs/tags/%s",
((struct tag *)merge_remote_util(commit)->obj)->tag);
- if (!read_ref(tag_ref, &oid) &&
+ if (!refs_read_ref(get_main_ref_store(the_repository), tag_ref, &oid) &&
oideq(&oid, &merge_remote_util(commit)->obj->oid))
is_throwaway_tag = 0;
else
@@ -1287,7 +1281,10 @@ static int merging_a_throwaway_tag(struct commit *commit)
return is_throwaway_tag;
}
-int cmd_merge(int argc, const char **argv, const char *prefix)
+int cmd_merge(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct object_id result_tree, stash, head_oid;
struct commit *head_commit;
@@ -1310,14 +1307,16 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* Check if we are _not_ on a detached HEAD, i.e. if there is a
* current branch.
*/
- branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ branch = branch_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &head_oid,
+ NULL);
if (branch)
skip_prefix(branch, "refs/heads/", &branch);
if (!pull_twohead) {
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
if (default_strategy && !strcmp(default_strategy, "ort"))
- pull_twohead = "ort";
+ pull_twohead = xstrdup("ort");
}
init_diff_ui_defaults();
@@ -1341,7 +1340,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (abort_current_merge) {
int nargc = 2;
const char *nargv[] = {"reset", "--merge", NULL};
- struct strbuf stash_oid = STRBUF_INIT;
+ char stash_oid_hex[GIT_MAX_HEXSZ + 1];
+ struct object_id stash_oid = {0};
if (orig_argc != 2)
usage_msg_opt(_("--abort expects no arguments"),
@@ -1350,17 +1350,19 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge to abort (MERGE_HEAD missing)."));
- if (read_oneliner(&stash_oid, git_path_merge_autostash(the_repository),
- READ_ONELINER_SKIP_IF_EMPTY))
- unlink(git_path_merge_autostash(the_repository));
+ if (!refs_read_ref(get_main_ref_store(the_repository), "MERGE_AUTOSTASH", &stash_oid))
+ refs_delete_ref(get_main_ref_store(the_repository),
+ "", "MERGE_AUTOSTASH", &stash_oid,
+ REF_NO_DEREF);
/* Invoke 'git reset --merge' */
- ret = cmd_reset(nargc, nargv, prefix);
+ ret = cmd_reset(nargc, nargv, prefix, the_repository);
- if (stash_oid.len)
- apply_autostash_oid(stash_oid.buf);
+ if (!is_null_oid(&stash_oid)) {
+ oid_to_hex_r(stash_oid_hex, &stash_oid);
+ apply_autostash_oid(stash_oid_hex);
+ }
- strbuf_release(&stash_oid);
goto done;
}
@@ -1386,7 +1388,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("There is no merge in progress (MERGE_HEAD missing)."));
/* Invoke 'git commit' */
- ret = cmd_commit(nargc, nargv, prefix);
+ ret = cmd_commit(nargc, nargv, prefix, the_repository);
goto done;
}
@@ -1404,14 +1406,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
- if (ref_exists("CHERRY_PICK_HEAD")) {
+ if (refs_ref_exists(get_main_ref_store(the_repository), "CHERRY_PICK_HEAD")) {
if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."));
else
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
}
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
if (option_edit < 0)
option_edit = default_edit_option();
@@ -1475,8 +1477,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid);
- update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "initial pull", "HEAD", remote_head_oid, NULL,
+ 0,
+ UPDATE_REFS_DIE_ON_ERR);
goto done;
}
@@ -1539,18 +1543,27 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!remoteheads)
; /* already up-to-date */
- else if (!remoteheads->next)
- common = repo_get_merge_bases(the_repository, head_commit,
- remoteheads->item);
- else {
+ else if (!remoteheads->next) {
+ if (repo_get_merge_bases(the_repository, head_commit,
+ remoteheads->item, &common) < 0) {
+ ret = 2;
+ goto done;
+ }
+ } else {
struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list);
- common = get_octopus_merge_bases(list);
+ if (get_octopus_merge_bases(list, &common) < 0) {
+ free(list);
+ ret = 2;
+ goto done;
+ }
free(list);
}
- update_ref("updating ORIG_HEAD", "ORIG_HEAD",
- &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "updating ORIG_HEAD", "ORIG_HEAD",
+ &head_commit->object.oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (remoteheads && !common) {
/* No common ancestors found. */
@@ -1589,13 +1602,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
if (autostash)
- create_autostash(the_repository,
- git_path_merge_autostash(the_repository));
+ create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
if (checkout_fast_forward(the_repository,
&head_commit->object.oid,
&commit->object.oid,
overwrite_ignore)) {
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
ret = 1;
goto done;
}
@@ -1614,7 +1626,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* We are not doing octopus, not fast-forward, and have
* only one common.
*/
- refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
if (allow_trivial && fast_forward != FF_ONLY) {
/*
* Must first ensure that index matches HEAD before
@@ -1653,17 +1665,21 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
struct commit_list *j;
for (j = remoteheads; j; j = j->next) {
- struct commit_list *common_one;
+ struct commit_list *common_one = NULL;
+ struct commit *common_item;
/*
* Here we *have* to calculate the individual
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
- common_one = repo_get_merge_bases(the_repository,
- head_commit,
- j->item);
- if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
+ if (repo_get_merge_bases(the_repository, head_commit,
+ j->item, &common_one) < 0)
+ exit(128);
+
+ common_item = common_one->item;
+ free_commit_list(common_one);
+ if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
up_to_date = 0;
break;
}
@@ -1678,8 +1694,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die_ff_impossible();
if (autostash)
- create_autostash(the_repository,
- git_path_merge_autostash(the_repository));
+ create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
/* We are going to make a new commit. */
git_committer_info(IDENT_STRICT);
@@ -1697,7 +1712,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* index and working tree polluted.
*/
if (save_state(&stash))
- oidclr(&stash);
+ oidclr(&stash, the_repository->hash_algo);
for (i = 0; i < use_strategies_nr; i++) {
int ret, cnt;
@@ -1764,7 +1779,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
fprintf(stderr, _("Merge with strategy %s failed.\n"),
use_strategies[0]->name);
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
ret = 2;
goto done;
} else if (best_strategy == wt_strategy)
@@ -1800,6 +1815,8 @@ done:
}
strbuf_release(&buf);
free(branch_to_free);
- discard_index(&the_index);
+ free(pull_twohead);
+ free(pull_octopus);
+ discard_index(the_repository->index);
return ret;
}
diff --git a/builtin/mktag.c b/builtin/mktag.c
index d8e0b5afc0..6e188dce50 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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-file.h"
#include "object-store-ll.h"
@@ -19,8 +19,7 @@ static int option_strict = 1;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
- const struct object_id *oid UNUSED,
- enum object_type object_type UNUSED,
+ void *fsck_report UNUSED,
enum fsck_msg_type msg_type,
enum fsck_msg_id msg_id UNUSED,
const char *message)
@@ -73,7 +72,10 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
return ret;
}
-int cmd_mktag(int argc, const char **argv, const char *prefix)
+int cmd_mktag(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
static struct option builtin_mktag_options[] = {
OPT_BOOL(0, "strict", &option_strict,
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 9a22d4e277..3c16faa40e 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -3,6 +3,7 @@
*
* Copyright (c) Junio C Hamano, 2006, 2009
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
@@ -150,7 +151,10 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)
free(to_free);
}
-int cmd_mktree(int ac, const char **av, const char *prefix)
+int cmd_mktree(int ac,
+ const char **av,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct strbuf sb = STRBUF_INIT;
struct object_id oid;
@@ -199,5 +203,6 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
used=0; /* reset tree entry buffer for re-use in batch mode */
}
strbuf_release(&sb);
+
return 0;
}
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index a72aebecaa..d159ed1314 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -1,13 +1,15 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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-ll.h"
+#include "replace-object.h"
+#include "repository.h"
#define BUILTIN_MIDX_WRITE_USAGE \
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
@@ -49,7 +51,7 @@ static char const * const builtin_multi_pack_index_usage[] = {
static struct opts_multi_pack_index {
char *object_dir;
const char *preferred_pack;
- const char *refs_snapshot;
+ char *refs_snapshot;
unsigned long batch_size;
unsigned flags;
int stdin_packs;
@@ -62,7 +64,7 @@ static int parse_object_dir(const struct option *opt, const char *arg,
char **value = opt->value;
free(*value);
if (unset)
- *value = xstrdup(get_object_directory());
+ *value = xstrdup(repo_get_object_directory(the_repository));
else
*value = real_pathdup(arg, 1);
return 0;
@@ -128,12 +130,15 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS),
+ OPT_BIT(0, "incremental", &opts.flags,
+ N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
N_("write multi-pack index containing only given indexes")),
OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
N_("refs snapshot for selecting bitmap commits")),
OPT_END(),
};
+ int ret;
opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
@@ -156,7 +161,6 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
if (opts.stdin_packs) {
struct string_list packs = STRING_LIST_INIT_DUP;
- int ret;
read_packs_from_stdin(&packs);
@@ -165,12 +169,17 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
opts.refs_snapshot, opts.flags);
string_list_clear(&packs, 0);
+ free(opts.refs_snapshot);
return ret;
}
- return write_midx_file(opts.object_dir, opts.preferred_pack,
- opts.refs_snapshot, opts.flags);
+
+ ret = write_midx_file(opts.object_dir, opts.preferred_pack,
+ opts.refs_snapshot, opts.flags);
+
+ free(opts.refs_snapshot);
+ return ret;
}
static int cmd_multi_pack_index_verify(int argc, const char **argv,
@@ -259,8 +268,10 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,
(size_t)opts.batch_size, opts.flags);
}
-int cmd_multi_pack_index(int argc, const char **argv,
- const char *prefix)
+int cmd_multi_pack_index(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int res;
parse_opt_subcommand_fn *fn = NULL;
@@ -273,6 +284,8 @@ int cmd_multi_pack_index(int argc, const char **argv,
};
struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
+ disable_replace_refs();
+
git_config(git_default_config, NULL);
if (the_repository &&
diff --git a/builtin/mv.c b/builtin/mv.c
index c596515ad0..472a278737 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,7 +3,8 @@
*
* Copyright (C) 2006 Johannes Schindelin
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "builtin.h"
#include "abspath.h"
#include "advice.h"
@@ -15,12 +16,12 @@
#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 "strvec.h"
#include "submodule.h"
#include "entry.h"
@@ -39,45 +40,35 @@ enum update_mode {
#define DUP_BASENAME 1
#define KEEP_TRAILING_SLASH 2
-static const char **internal_prefix_pathspec(const char *prefix,
- const char **pathspec,
- int count, unsigned flags)
+static void internal_prefix_pathspec(struct strvec *out,
+ const char *prefix,
+ const char **pathspec,
+ int count, unsigned flags)
{
- int i;
- const char **result;
int prefixlen = prefix ? strlen(prefix) : 0;
- ALLOC_ARRAY(result, count + 1);
/* Create an intermediate copy of the pathspec based on the flags */
- for (i = 0; i < count; i++) {
- int length = strlen(pathspec[i]);
- int to_copy = length;
- char *it;
+ for (int i = 0; i < count; i++) {
+ size_t length = strlen(pathspec[i]);
+ size_t to_copy = length;
+ const char *maybe_basename;
+ char *trimmed, *prefixed_path;
+
while (!(flags & KEEP_TRAILING_SLASH) &&
to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
to_copy--;
- it = xmemdupz(pathspec[i], to_copy);
- if (flags & DUP_BASENAME) {
- result[i] = xstrdup(basename(it));
- free(it);
- } else {
- result[i] = it;
- }
- }
- result[count] = NULL;
+ trimmed = xmemdupz(pathspec[i], to_copy);
+ maybe_basename = (flags & DUP_BASENAME) ? basename(trimmed) : trimmed;
+ prefixed_path = prefix_path(prefix, prefixlen, maybe_basename);
+ strvec_push(out, prefixed_path);
- /* Prefix the pathspec and free the old intermediate strings */
- for (i = 0; i < count; i++) {
- const char *match = prefix_path(prefix, prefixlen, result[i]);
- free((char *) result[i]);
- result[i] = match;
+ free(prefixed_path);
+ free(trimmed);
}
-
- return result;
}
-static const char *add_slash(const char *path)
+static char *add_slash(const char *path)
{
size_t len = strlen(path);
if (len && path[len - 1] != '/') {
@@ -87,46 +78,48 @@ static const char *add_slash(const char *path)
with_slash[len] = 0;
return with_slash;
}
- return path;
+ return xstrdup(path);
}
#define SUBMODULE_WITH_GITDIR ((const char *)1)
-static void prepare_move_submodule(const char *src, int first,
- const char **submodule_gitfile)
+static const char *submodule_gitfile_path(const char *src, int first)
{
struct strbuf submodule_dotgit = STRBUF_INIT;
- if (!S_ISGITLINK(the_index.cache[first]->ce_mode))
+ const char *path;
+
+ if (!S_ISGITLINK(the_repository->index->cache[first]->ce_mode))
die(_("Directory %s is in index and no submodule?"), src);
- if (!is_staging_gitmodules_ok(&the_index))
+ if (!is_staging_gitmodules_ok(the_repository->index))
die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+
strbuf_addf(&submodule_dotgit, "%s/.git", src);
- *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
- if (*submodule_gitfile)
- *submodule_gitfile = xstrdup(*submodule_gitfile);
- else
- *submodule_gitfile = SUBMODULE_WITH_GITDIR;
+
+ path = read_gitfile(submodule_dotgit.buf);
strbuf_release(&submodule_dotgit);
+ if (path)
+ return path;
+ return SUBMODULE_WITH_GITDIR;
}
static int index_range_of_same_dir(const char *src, int length,
int *first_p, int *last_p)
{
- const char *src_w_slash = add_slash(src);
+ char *src_w_slash = add_slash(src);
int first, last, len_w_slash = length + 1;
- first = index_name_pos(&the_index, src_w_slash, len_w_slash);
+ first = index_name_pos(the_repository->index, src_w_slash, len_w_slash);
if (first >= 0)
die(_("%.*s is in index"), len_w_slash, src_w_slash);
first = -1 - first;
- for (last = first; last < the_index.cache_nr; last++) {
- const char *path = the_index.cache[last]->name;
+ for (last = first; last < the_repository->index->cache_nr; last++) {
+ const char *path = the_repository->index->cache[last]->name;
if (strncmp(path, src_w_slash, len_w_slash))
break;
}
- if (src_w_slash != src)
- free((char *)src_w_slash);
+
+ free(src_w_slash);
*first_p = first;
*last_p = last;
return last - first;
@@ -142,17 +135,17 @@ static int index_range_of_same_dir(const char *src, int length,
static int empty_dir_has_sparse_contents(const char *name)
{
int ret = 0;
- const char *with_slash = add_slash(name);
+ char *with_slash = add_slash(name);
int length = strlen(with_slash);
- int pos = index_name_pos(&the_index, with_slash, length);
+ int pos = index_name_pos(the_repository->index, with_slash, length);
const struct cache_entry *ce;
if (pos < 0) {
pos = -pos - 1;
- if (pos >= the_index.cache_nr)
+ if (pos >= the_repository->index->cache_nr)
goto free_return;
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (strncmp(with_slash, ce->name, length))
goto free_return;
if (ce_skip_worktree(ce))
@@ -160,12 +153,36 @@ static int empty_dir_has_sparse_contents(const char *name)
}
free_return:
- if (with_slash != name)
- free((char *)with_slash);
+ free(with_slash);
return ret;
}
-int cmd_mv(int argc, const char **argv, const char *prefix)
+static void remove_empty_src_dirs(const char **src_dir, size_t src_dir_nr)
+{
+ size_t i;
+ struct strbuf a_src_dir = STRBUF_INIT;
+
+ for (i = 0; i < src_dir_nr; i++) {
+ int dummy;
+ strbuf_addstr(&a_src_dir, src_dir[i]);
+ /*
+ * if entries under a_src_dir are all moved away,
+ * recursively remove a_src_dir to cleanup
+ */
+ if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
+ &dummy, &dummy) < 1) {
+ remove_dir_recursively(&a_src_dir, 0);
+ }
+ strbuf_reset(&a_src_dir);
+ }
+
+ strbuf_release(&a_src_dir);
+}
+
+int cmd_mv(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i, flags, gitmodules_modified = 0;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0, ignore_sparse = 0;
@@ -178,18 +195,21 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "sparse", &ignore_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
OPT_END(),
};
- const char **source, **destination, **dest_path, **submodule_gitfile;
- const char *dst_w_slash;
- const char **src_dir = NULL;
- int src_dir_nr = 0, src_dir_alloc = 0;
- struct strbuf a_src_dir = STRBUF_INIT;
+ struct strvec sources = STRVEC_INIT;
+ struct strvec dest_paths = STRVEC_INIT;
+ struct strvec destinations = STRVEC_INIT;
+ struct strvec submodule_gitfiles_to_free = STRVEC_INIT;
+ const char **submodule_gitfiles;
+ char *dst_w_slash = NULL;
+ struct strvec src_dir = STRVEC_INIT;
enum update_mode *modes, dst_mode = 0;
struct stat st, dest_st;
- struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ struct string_list src_for_dst = STRING_LIST_INIT_DUP;
struct lock_file lock_file = LOCK_INIT;
struct cache_entry *ce;
- struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
- struct string_list dirty_paths = STRING_LIST_INIT_NODUP;
+ struct string_list only_match_skip_worktree = STRING_LIST_INIT_DUP;
+ struct string_list dirty_paths = STRING_LIST_INIT_DUP;
+ int ret;
git_config(git_default_config, NULL);
@@ -202,7 +222,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- source = internal_prefix_pathspec(prefix, argv, argc, 0);
+ internal_prefix_pathspec(&sources, prefix, argv, argc, 0);
CALLOC_ARRAY(modes, argc);
/*
@@ -213,45 +233,39 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
flags = KEEP_TRAILING_SLASH;
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
flags = 0;
- dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
- dst_w_slash = add_slash(dest_path[0]);
- submodule_gitfile = xcalloc(argc, sizeof(char *));
+ internal_prefix_pathspec(&dest_paths, prefix, argv + argc, 1, flags);
+ dst_w_slash = add_slash(dest_paths.v[0]);
+ submodule_gitfiles = xcalloc(argc, sizeof(char *));
- if (dest_path[0][0] == '\0')
+ if (dest_paths.v[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
- else if (!lstat(dest_path[0], &st) &&
- S_ISDIR(st.st_mode)) {
- destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
+ internal_prefix_pathspec(&destinations, dest_paths.v[0], argv, argc, DUP_BASENAME);
+ else if (!lstat(dest_paths.v[0], &st) && S_ISDIR(st.st_mode)) {
+ internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+ } else if (!path_in_sparse_checkout(dst_w_slash, the_repository->index) &&
+ empty_dir_has_sparse_contents(dst_w_slash)) {
+ internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+ dst_mode = SKIP_WORKTREE_DIR;
+ } else if (argc != 1) {
+ die(_("destination '%s' is not a directory"), dest_paths.v[0]);
} else {
- if (!path_in_sparse_checkout(dst_w_slash, &the_index) &&
- empty_dir_has_sparse_contents(dst_w_slash)) {
- destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
- dst_mode = SKIP_WORKTREE_DIR;
- } else if (argc != 1) {
- die(_("destination '%s' is not a directory"), dest_path[0]);
- } else {
- destination = dest_path;
- /*
- * <destination> is a file outside of sparse-checkout
- * cone. Insist on cone mode here for backward
- * compatibility. We don't want dst_mode to be assigned
- * for a file when the repo is using no-cone mode (which
- * is deprecated at this point) sparse-checkout. As
- * SPARSE here is only considering cone-mode situation.
- */
- if (!path_in_cone_mode_sparse_checkout(destination[0], &the_index))
- dst_mode = SPARSE;
- }
- }
- if (dst_w_slash != dest_path[0]) {
- free((char *)dst_w_slash);
- dst_w_slash = NULL;
+ strvec_pushv(&destinations, dest_paths.v);
+
+ /*
+ * <destination> is a file outside of sparse-checkout
+ * cone. Insist on cone mode here for backward
+ * compatibility. We don't want dst_mode to be assigned
+ * for a file when the repo is using no-cone mode (which
+ * is deprecated at this point) sparse-checkout. As
+ * SPARSE here is only considering cone-mode situation.
+ */
+ if (!path_in_cone_mode_sparse_checkout(destinations.v[0], the_repository->index))
+ dst_mode = SPARSE;
}
/* Checking */
for (i = 0; i < argc; i++) {
- const char *src = source[i], *dst = destination[i];
+ const char *src = sources.v[i], *dst = destinations.v[i];
int length;
const char *bad = NULL;
int skip_sparse = 0;
@@ -264,20 +278,22 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int pos;
const struct cache_entry *ce;
- pos = index_name_pos(&the_index, src, length);
+ pos = index_name_pos(the_repository->index, src, length);
if (pos < 0) {
- const char *src_w_slash = add_slash(src);
- if (!path_in_sparse_checkout(src_w_slash, &the_index) &&
+ char *src_w_slash = add_slash(src);
+ if (!path_in_sparse_checkout(src_w_slash, the_repository->index) &&
empty_dir_has_sparse_contents(src)) {
+ free(src_w_slash);
modes[i] |= SKIP_WORKTREE_DIR;
goto dir_check;
}
+ free(src_w_slash);
/* only error if existence is expected. */
if (!(modes[i] & SPARSE))
bad = _("bad source");
goto act_on_entry;
}
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (!ce_skip_worktree(ce)) {
bad = _("bad source");
goto act_on_entry;
@@ -287,7 +303,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
goto act_on_entry;
}
/* Check if dst exists in index */
- if (index_name_pos(&the_index, dst, strlen(dst)) < 0) {
+ if (index_name_pos(the_repository->index, dst, strlen(dst)) < 0) {
modes[i] |= SPARSE;
goto act_on_entry;
}
@@ -311,12 +327,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
dir_check:
if (S_ISDIR(st.st_mode)) {
- int j, dst_len, n;
- int first = index_name_pos(&the_index, src, length), last;
+ char *dst_with_slash;
+ size_t dst_with_slash_len;
+ int j, n;
+ int first = index_name_pos(the_repository->index, src, length), last;
if (first >= 0) {
- prepare_move_submodule(src, first,
- submodule_gitfile + i);
+ const char *path = submodule_gitfile_path(src, first);
+ if (path != SUBMODULE_WITH_GITDIR)
+ path = strvec_push(&submodule_gitfiles_to_free, path);
+ submodule_gitfiles[i] = path;
goto act_on_entry;
} else if (index_range_of_same_dir(src, length,
&first, &last) < 1) {
@@ -327,32 +347,35 @@ dir_check:
/* last - first >= 1 */
modes[i] |= WORKING_DIRECTORY;
- ALLOC_GROW(src_dir, src_dir_nr + 1, src_dir_alloc);
- src_dir[src_dir_nr++] = src;
+ strvec_push(&src_dir, src);
n = argc + last - first;
- REALLOC_ARRAY(source, n);
- REALLOC_ARRAY(destination, n);
REALLOC_ARRAY(modes, n);
- REALLOC_ARRAY(submodule_gitfile, n);
+ REALLOC_ARRAY(submodule_gitfiles, n);
- dst = add_slash(dst);
- dst_len = strlen(dst);
+ dst_with_slash = add_slash(dst);
+ dst_with_slash_len = strlen(dst_with_slash);
for (j = 0; j < last - first; j++) {
- const struct cache_entry *ce = the_index.cache[first + j];
+ const struct cache_entry *ce = the_repository->index->cache[first + j];
const char *path = ce->name;
- source[argc + j] = path;
- destination[argc + j] =
- prefix_path(dst, dst_len, path + length + 1);
+ char *prefixed_path = prefix_path(dst_with_slash, dst_with_slash_len, path + length + 1);
+
+ strvec_push(&sources, path);
+ strvec_push(&destinations, prefixed_path);
+
memset(modes + argc + j, 0, sizeof(enum update_mode));
modes[argc + j] |= ce_skip_worktree(ce) ? SPARSE : INDEX;
- submodule_gitfile[argc + j] = NULL;
+ submodule_gitfiles[argc + j] = NULL;
+
+ free(prefixed_path);
}
+
+ free(dst_with_slash);
argc += last - first;
goto act_on_entry;
}
- if (!(ce = index_file_exists(&the_index, src, length, 0))) {
+ if (!(ce = index_file_exists(the_repository->index, src, length, 0))) {
bad = _("not under version control");
goto act_on_entry;
}
@@ -388,7 +411,7 @@ dir_check:
if (ignore_sparse &&
(dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
- index_entry_exists(&the_index, dst, strlen(dst))) {
+ index_entry_exists(the_repository->index, dst, strlen(dst))) {
bad = _("destination exists in the index");
if (force) {
if (verbose)
@@ -405,12 +428,12 @@ dir_check:
* option as a way to have a successful run.
*/
if (!ignore_sparse &&
- !path_in_sparse_checkout(src, &the_index)) {
+ !path_in_sparse_checkout(src, the_repository->index)) {
string_list_append(&only_match_skip_worktree, src);
skip_sparse = 1;
}
if (!ignore_sparse &&
- !path_in_sparse_checkout(dst, &the_index)) {
+ !path_in_sparse_checkout(dst, the_repository->index)) {
string_list_append(&only_match_skip_worktree, dst);
skip_sparse = 1;
}
@@ -429,28 +452,30 @@ act_on_entry:
remove_entry:
if (--argc > 0) {
int n = argc - i;
- MOVE_ARRAY(source + i, source + i + 1, n);
- MOVE_ARRAY(destination + i, destination + i + 1, n);
+ strvec_remove(&sources, i);
+ strvec_remove(&destinations, i);
MOVE_ARRAY(modes + i, modes + i + 1, n);
- MOVE_ARRAY(submodule_gitfile + i,
- submodule_gitfile + i + 1, n);
+ MOVE_ARRAY(submodule_gitfiles + i,
+ submodule_gitfiles + i + 1, n);
i--;
}
}
if (only_match_skip_worktree.nr) {
advise_on_updating_sparse_paths(&only_match_skip_worktree);
- if (!ignore_errors)
- return 1;
+ if (!ignore_errors) {
+ ret = 1;
+ goto out;
+ }
}
for (i = 0; i < argc; i++) {
- const char *src = source[i], *dst = destination[i];
+ const char *src = sources.v[i], *dst = destinations.v[i];
enum update_mode mode = modes[i];
int pos;
int sparse_and_dirty = 0;
struct checkout state = CHECKOUT_INIT;
- state.istate = &the_index;
+ state.istate = the_repository->index;
if (force)
state.force = 1;
@@ -465,26 +490,26 @@ remove_entry:
continue;
die_errno(_("renaming '%s' failed"), src);
}
- if (submodule_gitfile[i]) {
+ if (submodule_gitfiles[i]) {
if (!update_path_in_gitmodules(src, dst))
gitmodules_modified = 1;
- if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
+ if (submodule_gitfiles[i] != SUBMODULE_WITH_GITDIR)
connect_work_tree_and_git_dir(dst,
- submodule_gitfile[i],
+ submodule_gitfiles[i],
1);
}
if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
continue;
- pos = index_name_pos(&the_index, src, strlen(src));
+ pos = index_name_pos(the_repository->index, src, strlen(src));
assert(pos >= 0);
if (!(mode & SPARSE) && !lstat(src, &st))
- sparse_and_dirty = ie_modified(&the_index,
- the_index.cache[pos],
+ sparse_and_dirty = ie_modified(the_repository->index,
+ the_repository->index->cache[pos],
&st,
0);
- rename_index_entry_at(&the_index, pos, dst);
+ rename_index_entry_at(the_repository->index, pos, dst);
if (ignore_sparse &&
core_apply_sparse_checkout &&
@@ -496,11 +521,11 @@ remove_entry:
* should be added in a future patch.
*/
if ((mode & SPARSE) &&
- path_in_sparse_checkout(dst, &the_index)) {
+ path_in_sparse_checkout(dst, the_repository->index)) {
/* from out-of-cone to in-cone */
- int dst_pos = index_name_pos(&the_index, dst,
+ int dst_pos = index_name_pos(the_repository->index, dst,
strlen(dst));
- struct cache_entry *dst_ce = the_index.cache[dst_pos];
+ struct cache_entry *dst_ce = the_repository->index->cache[dst_pos];
dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -508,11 +533,11 @@ remove_entry:
die(_("cannot checkout %s"), dst_ce->name);
} else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
!(mode & SPARSE) &&
- !path_in_sparse_checkout(dst, &the_index)) {
+ !path_in_sparse_checkout(dst, the_repository->index)) {
/* from in-cone to out-of-cone */
- int dst_pos = index_name_pos(&the_index, dst,
+ int dst_pos = index_name_pos(the_repository->index, dst,
strlen(dst));
- struct cache_entry *dst_ce = the_index.cache[dst_pos];
+ struct cache_entry *dst_ce = the_repository->index->cache[dst_pos];
/*
* if src is clean, it will suffice to remove it
@@ -536,41 +561,31 @@ remove_entry:
}
}
- /*
- * cleanup the empty src_dirs
- */
- for (i = 0; i < src_dir_nr; i++) {
- int dummy;
- strbuf_addstr(&a_src_dir, src_dir[i]);
- /*
- * if entries under a_src_dir are all moved away,
- * recursively remove a_src_dir to cleanup
- */
- if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
- &dummy, &dummy) < 1) {
- remove_dir_recursively(&a_src_dir, 0);
- }
- strbuf_reset(&a_src_dir);
- }
-
- strbuf_release(&a_src_dir);
- free(src_dir);
+ remove_empty_src_dirs(src_dir.v, src_dir.nr);
if (dirty_paths.nr)
advise_on_moving_dirty_path(&dirty_paths);
if (gitmodules_modified)
- stage_updated_gitmodules(&the_index);
+ stage_updated_gitmodules(the_repository->index);
- if (write_locked_index(&the_index, &lock_file,
+ if (write_locked_index(the_repository->index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
+ ret = 0;
+
+out:
+ strvec_clear(&src_dir);
+ free(dst_w_slash);
string_list_clear(&src_for_dst, 0);
string_list_clear(&dirty_paths, 0);
- UNLEAK(source);
- UNLEAK(dest_path);
- free(submodule_gitfile);
+ string_list_clear(&only_match_skip_worktree, 0);
+ strvec_clear(&sources);
+ strvec_clear(&dest_paths);
+ strvec_clear(&destinations);
+ strvec_clear(&submodule_gitfiles_to_free);
+ free(submodule_gitfiles);
free(modes);
- return 0;
+ return ret;
}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 2dd1807c4e..765eb20a93 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -1,8 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tag.h"
@@ -15,6 +15,7 @@
#include "commit-slab.h"
#include "commit-graph.h"
#include "wildmatch.h"
+#include "mem-pool.h"
/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
@@ -64,7 +65,7 @@ static void set_commit_cutoff(struct commit *commit)
static void adjust_cutoff_timestamp_for_slop(void)
{
if (cutoff) {
- /* check for undeflow */
+ /* check for underflow */
if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
cutoff = cutoff - CUTOFF_DATE_SLOP;
else
@@ -155,30 +156,25 @@ static struct rev_name *create_or_update_name(struct commit *commit,
return name;
}
-static char *get_parent_name(const struct rev_name *name, int parent_number)
+static char *get_parent_name(const struct rev_name *name, int parent_number,
+ struct mem_pool *string_pool)
{
- struct strbuf sb = STRBUF_INIT;
size_t len;
strip_suffix(name->tip_name, "^0", &len);
if (name->generation > 0) {
- strbuf_grow(&sb, len +
- 1 + decimal_width(name->generation) +
- 1 + decimal_width(parent_number));
- strbuf_addf(&sb, "%.*s~%d^%d", (int)len, name->tip_name,
- name->generation, parent_number);
+ return mem_pool_strfmt(string_pool, "%.*s~%d^%d",
+ (int)len, name->tip_name,
+ name->generation, parent_number);
} else {
- strbuf_grow(&sb, len +
- 1 + decimal_width(parent_number));
- strbuf_addf(&sb, "%.*s^%d", (int)len, name->tip_name,
- parent_number);
+ return mem_pool_strfmt(string_pool, "%.*s^%d",
+ (int)len, name->tip_name, parent_number);
}
- return strbuf_detach(&sb, NULL);
}
static void name_rev(struct commit *start_commit,
const char *tip_name, timestamp_t taggerdate,
- int from_tag, int deref)
+ int from_tag, int deref, struct mem_pool *string_pool)
{
struct prio_queue queue;
struct commit *commit;
@@ -195,9 +191,10 @@ static void name_rev(struct commit *start_commit,
if (!start_name)
return;
if (deref)
- start_name->tip_name = xstrfmt("%s^0", tip_name);
+ start_name->tip_name = mem_pool_strfmt(string_pool, "%s^0",
+ tip_name);
else
- start_name->tip_name = xstrdup(tip_name);
+ start_name->tip_name = mem_pool_strdup(string_pool, tip_name);
memset(&queue, 0, sizeof(queue)); /* Use the prio_queue as LIFO */
prio_queue_put(&queue, start_commit);
@@ -235,7 +232,8 @@ static void name_rev(struct commit *start_commit,
if (parent_number > 1)
parent_name->tip_name =
get_parent_name(name,
- parent_number);
+ parent_number,
+ string_pool);
else
parent_name->tip_name = name->tip_name;
ALLOC_GROW(parents_to_queue,
@@ -298,7 +296,8 @@ static void add_to_tip_table(const struct object_id *oid, const char *refname,
char *short_refname = NULL;
if (shorten_unambiguous)
- short_refname = shorten_unambiguous_ref(refname, 0);
+ short_refname = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ refname, 0);
else if (skip_prefix(refname, "refs/heads/", &refname))
; /* refname already advanced */
else
@@ -338,7 +337,7 @@ static int cmp_by_tag_and_age(const void *a_, const void *b_)
return a->taggerdate != b->taggerdate;
}
-static int name_ref(const char *path, const struct object_id *oid,
+static int name_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
struct object *o = parse_object(the_repository, oid);
@@ -415,7 +414,7 @@ static int name_ref(const char *path, const struct object_id *oid,
return 0;
}
-static void name_tips(void)
+static void name_tips(struct mem_pool *string_pool)
{
int i;
@@ -428,7 +427,7 @@ static void name_tips(void)
struct tip_table_entry *e = &tip_table.table[i];
if (e->commit) {
name_rev(e->commit, e->refname, e->taggerdate,
- e->from_tag, e->deref);
+ e->from_tag, e->deref, string_pool);
}
}
}
@@ -559,8 +558,12 @@ static void name_rev_line(char *p, struct name_ref_data *data)
strbuf_release(&buf);
}
-int cmd_name_rev(int argc, const char **argv, const char *prefix)
+int cmd_name_rev(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
+ struct mem_pool string_pool;
struct object_array revs = OBJECT_ARRAY_INIT;
int all = 0, annotate_stdin = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
@@ -587,6 +590,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ mem_pool_init(&string_pool, 0);
init_commit_rev_name(&rev_names);
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
@@ -647,8 +651,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
adjust_cutoff_timestamp_for_slop();
- for_each_ref(name_ref, &data);
- name_tips();
+ refs_for_each_ref(get_main_ref_store(the_repository), name_ref, &data);
+ name_tips(&string_pool);
if (annotate_stdin) {
struct strbuf sb = STRBUF_INIT;
@@ -676,6 +680,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
always, allow_undefined, data.name_only);
}
- UNLEAK(revs);
+ string_list_clear(&data.ref_filters, 0);
+ string_list_clear(&data.exclude_filters, 0);
+ mem_pool_discard(&string_pool, 0);
+ object_array_clear(&revs);
return 0;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 9f38863dd5..72c8a51cfa 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -6,10 +6,9 @@
* Based on git-notes.sh by Johannes Schindelin,
* and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
-#include "alloc.h"
#include "editor.h"
#include "environment.h"
#include "gettext.h"
@@ -18,8 +17,7 @@
#include "object-name.h"
#include "object-store-ll.h"
#include "path.h"
-#include "repository.h"
-#include "blob.h"
+
#include "pretty.h"
#include "refs.h"
#include "exec-cmd.h"
@@ -34,9 +32,9 @@
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] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-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>] [-e]"),
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-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>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"),
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>"),
@@ -116,7 +114,6 @@ struct note_msg {
};
struct note_data {
- int given;
int use_editor;
int stripspace;
char *edit_path;
@@ -181,7 +178,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, comment_line_char);
+ strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_str);
write_or_die(fd, cbuf.buf, cbuf.len);
strbuf_release(&cbuf);
@@ -195,7 +192,7 @@ static void write_commented_object(int fd, const struct object_id *object)
static void prepare_note_data(const struct object_id *object, struct note_data *d,
const struct object_id *old_note)
{
- if (d->use_editor || !d->given) {
+ if (d->use_editor || !d->msg_nr) {
int fd;
struct strbuf buf = STRBUF_INIT;
@@ -203,16 +200,16 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
d->edit_path = git_pathdup("NOTES_EDITMSG");
fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (d->given)
+ if (d->msg_nr)
write_or_die(fd, d->buf.buf, d->buf.len);
else if (old_note)
copy_obj_to_fd(fd, old_note);
strbuf_addch(&buf, '\n');
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_str);
strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
- comment_line_char);
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ comment_line_str);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_str);
write_or_die(fd, buf.buf, buf.len);
write_commented_object(fd, object);
@@ -225,7 +222,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
die(_("please supply the note contents using either -m or -F option"));
}
if (d->stripspace)
- strbuf_stripspace(&d->buf, comment_line_char);
+ strbuf_stripspace(&d->buf, comment_line_str);
}
}
@@ -266,7 +263,7 @@ static void concat_messages(struct note_data *d)
if ((d->stripspace == UNSPECIFIED &&
d->messages[i]->stripspace == STRIPSPACE) ||
d->stripspace == STRIPSPACE)
- strbuf_stripspace(&d->buf, 0);
+ strbuf_stripspace(&d->buf, NULL);
strbuf_reset(&msg);
}
strbuf_release(&msg);
@@ -492,6 +489,8 @@ static int add(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"),
N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg),
+ OPT_BOOL('e', "edit", &d.use_editor,
+ N_("edit note message in editor")),
OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"),
N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg),
@@ -517,7 +516,6 @@ static int add(int argc, const char **argv, const char *prefix)
if (d.msg_nr)
concat_messages(&d);
- d.given = !!d.buf.len;
object_ref = argc > 1 ? argv[1] : "HEAD";
@@ -530,7 +528,7 @@ static int add(int argc, const char **argv, const char *prefix)
if (note) {
if (!force) {
free_notes(t);
- if (d.given) {
+ if (d.msg_nr) {
free_note_data(&d);
return error(_("Cannot add notes. "
"Found existing notes for object %s. "
@@ -671,6 +669,8 @@ static int append_edit(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"),
N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg),
+ OPT_BOOL('e', "edit", &d.use_editor,
+ N_("edit note message in editor")),
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
OPT_CALLBACK_F(0, "separator", &separator,
@@ -692,14 +692,14 @@ static int append_edit(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
}
- if (d.msg_nr)
+ 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"
- "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"));
+ if (edit)
+ fprintf(stderr, _("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"));
+ }
object_ref = 1 < argc ? argv[1] : "HEAD";
@@ -718,9 +718,11 @@ static int append_edit(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
- if (prev_buf && size)
+ if (!prev_buf)
+ die(_("unable to read %s"), oid_to_hex(note));
+ if (size)
strbuf_add(&buf, prev_buf, size);
- if (d.buf.len && prev_buf && size)
+ if (d.buf.len && size)
append_separator(&buf);
strbuf_insert(&d.buf, 0, buf.buf, buf.len);
@@ -794,9 +796,9 @@ static int merge_abort(struct notes_merge_options *o)
* notes_merge_abort() to remove .git/NOTES_MERGE_WORKTREE.
*/
- if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
- if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
ret += error(_("failed to delete ref NOTES_MERGE_REF"));
if (notes_merge_abort(o))
ret += error(_("failed to remove 'git notes merge' worktree"));
@@ -807,7 +809,7 @@ static int merge_commit(struct notes_merge_options *o)
{
struct strbuf msg = STRBUF_INIT;
struct object_id oid, parent_oid;
- struct notes_tree *t;
+ struct notes_tree t = {0};
struct commit *partial;
struct pretty_print_context pretty_ctx;
void *local_ref_to_free;
@@ -828,17 +830,17 @@ static int merge_commit(struct notes_merge_options *o)
if (partial->parents)
oidcpy(&parent_oid, &partial->parents->item->object.oid);
else
- oidclr(&parent_oid);
+ oidclr(&parent_oid, the_repository->hash_algo);
- CALLOC_ARRAY(t, 1);
- init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
+ init_notes(&t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
o->local_ref = local_ref_to_free =
- resolve_refdup("NOTES_MERGE_REF", 0, &oid, NULL);
+ refs_resolve_refdup(get_main_ref_store(the_repository),
+ "NOTES_MERGE_REF", 0, &oid, NULL);
if (!o->local_ref)
die(_("failed to resolve NOTES_MERGE_REF"));
- if (notes_merge_commit(o, t, partial, &oid))
+ if (notes_merge_commit(o, &t, partial, &oid))
die(_("failed to finalize notes merge"));
/* Reuse existing commit message in reflog message */
@@ -847,11 +849,12 @@ static int merge_commit(struct notes_merge_options *o)
&pretty_ctx);
strbuf_trim(&msg);
strbuf_insertstr(&msg, 0, "notes: ");
- update_ref(msg.buf, o->local_ref, &oid,
- is_null_oid(&parent_oid) ? NULL : &parent_oid,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ o->local_ref, &oid,
+ is_null_oid(&parent_oid) ? NULL : &parent_oid,
+ 0, UPDATE_REFS_DIE_ON_ERR);
- free_notes(t);
+ free_notes(&t);
strbuf_release(&msg);
ret = merge_abort(o);
free(local_ref_to_free);
@@ -866,7 +869,7 @@ static int git_config_get_notes_strategy(const char *key,
if (git_config_get_string(key, &value))
return 1;
if (parse_notes_merge_strategy(value, strategy))
- git_die_config(key, _("unknown notes merge strategy %s"), value);
+ git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value);
free(value);
return 0;
@@ -898,6 +901,7 @@ static int merge(int argc, const char **argv, const char *prefix)
1, PARSE_OPT_NONEG),
OPT_END()
};
+ char *notes_ref;
argc = parse_options(argc, argv, prefix, options,
git_notes_merge_usage, 0);
@@ -925,7 +929,8 @@ static int merge(int argc, const char **argv, const char *prefix)
if (do_commit)
return merge_commit(&o);
- o.local_ref = default_notes_ref();
+ notes_ref = default_notes_ref(the_repository);
+ o.local_ref = notes_ref;
strbuf_addstr(&remote_ref, argv[0]);
expand_loose_notes_ref(&remote_ref);
o.remote_ref = remote_ref.buf;
@@ -954,32 +959,34 @@ static int merge(int argc, const char **argv, const char *prefix)
}
strbuf_addf(&msg, "notes: Merged notes from %s into %s",
- remote_ref.buf, default_notes_ref());
+ remote_ref.buf, notes_ref);
strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */
result = notes_merge(&o, t, &result_oid);
if (result >= 0) /* Merge resulted (trivially) in result_oid */
/* Update default notes ref with new commit */
- update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ notes_ref, &result_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else { /* Merge has unresolved conflicts */
struct worktree **worktrees;
const struct worktree *wt;
/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
- update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ "NOTES_MERGE_PARTIAL", &result_oid, NULL,
+ 0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
worktrees = get_worktrees();
wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
- default_notes_ref());
+ notes_ref);
if (wt)
die(_("a notes merge into %s is already in-progress at %s"),
- default_notes_ref(), wt->path);
+ notes_ref, wt->path);
free_worktrees(worktrees);
- if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
+ if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", notes_ref, NULL))
die(_("failed to store link to current notes ref (%s)"),
- default_notes_ref());
+ notes_ref);
fprintf(stderr, _("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"),
@@ -987,6 +994,7 @@ static int merge(int argc, const char **argv, const char *prefix)
}
free_notes(t);
+ free(notes_ref);
strbuf_release(&remote_ref);
strbuf_release(&msg);
return result < 0; /* return non-zero on conflicts */
@@ -1083,6 +1091,7 @@ static int prune(int argc, const char **argv, const char *prefix)
static int get_ref(int argc, const char **argv, const char *prefix)
{
struct option options[] = { OPT_END() };
+ char *notes_ref;
argc = parse_options(argc, argv, prefix, options,
git_notes_get_ref_usage, 0);
@@ -1091,11 +1100,16 @@ static int get_ref(int argc, const char **argv, const char *prefix)
usage_with_options(git_notes_get_ref_usage, options);
}
- puts(default_notes_ref());
+ notes_ref = default_notes_ref(the_repository);
+ puts(notes_ref);
+ free(notes_ref);
return 0;
}
-int cmd_notes(int argc, const char **argv, const char *prefix)
+int cmd_notes(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char *override_notes_ref = NULL;
parse_opt_subcommand_fn *fn = NULL;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index d2a162d528..676a586709 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1,15 +1,13 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
#include "config.h"
#include "attr.h"
#include "object.h"
-#include "blob.h"
#include "commit.h"
#include "tag.h"
-#include "tree.h"
#include "delta.h"
#include "pack.h"
#include "pack-revindex.h"
@@ -18,7 +16,6 @@
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
-#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "pack-objects.h"
#include "progress.h"
@@ -221,13 +218,19 @@ static int thin;
static int num_preferred_base;
static struct progress *progress_state;
-static struct packed_git *reuse_packfile;
+static struct bitmapped_pack *reuse_packfiles;
+static size_t reuse_packfiles_nr;
+static size_t reuse_packfiles_used_nr;
static uint32_t reuse_packfile_objects;
static struct bitmap *reuse_packfile_bitmap;
static int use_bitmap_index_default = 1;
static int use_bitmap_index = -1;
-static int allow_pack_reuse = 1;
+static enum {
+ NO_PACK_REUSE = 0,
+ SINGLE_PACK_REUSE,
+ MULTI_PACK_REUSE,
+} allow_pack_reuse = SINGLE_PACK_REUSE;
static enum {
WRITE_BITMAP_FALSE = 0,
WRITE_BITMAP_QUIET,
@@ -236,6 +239,7 @@ static enum {
static uint16_t write_bitmap_options = BITMAP_OPT_HASH_CACHE;
static int exclude_promisor_objects;
+static int exclude_promisor_objects_best_effort;
static int use_delta_islands;
@@ -768,7 +772,7 @@ static enum write_one_status write_one(struct hashfile *f,
return WRITE_ONE_WRITTEN;
}
-static int mark_tagged(const char *path UNUSED, const struct object_id *oid,
+static int mark_tagged(const char *path UNUSED, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id peeled;
@@ -776,7 +780,7 @@ static int mark_tagged(const char *path UNUSED, const struct object_id *oid,
if (entry)
entry->tagged = 1;
- if (!peel_iterated_oid(oid, &peeled)) {
+ if (!peel_iterated_oid(the_repository, oid, &peeled)) {
entry = packlist_find(&to_pack, &peeled);
if (entry)
entry->tagged = 1;
@@ -936,7 +940,8 @@ static struct object_entry **compute_write_order(void)
/*
* Mark objects that are at the tip of tags.
*/
- for_each_tag_ref(mark_tagged, NULL);
+ refs_for_each_tag_ref(get_main_ref_store(the_repository), mark_tagged,
+ NULL);
if (use_delta_islands) {
max_layers = compute_pack_layers(&to_pack);
@@ -1013,7 +1018,9 @@ static off_t find_reused_offset(off_t where)
return reused_chunks[lo-1].difference;
}
-static void write_reused_pack_one(size_t pos, struct hashfile *out,
+static void write_reused_pack_one(struct packed_git *reuse_packfile,
+ size_t pos, struct hashfile *out,
+ off_t pack_start,
struct pack_window **w_curs)
{
off_t offset, next, cur;
@@ -1023,7 +1030,8 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
offset = pack_pos_to_offset(reuse_packfile, pos);
next = pack_pos_to_offset(reuse_packfile, pos + 1);
- record_reused_object(offset, offset - hashfile_total(out));
+ record_reused_object(offset,
+ offset - (hashfile_total(out) - pack_start));
cur = offset;
type = unpack_object_header(reuse_packfile, w_curs, &cur, &size);
@@ -1065,7 +1073,7 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
fixup = find_reused_offset(offset) -
find_reused_offset(base_offset);
if (fixup) {
- unsigned char ofs_header[10];
+ unsigned char ofs_header[MAX_PACK_OBJECT_HEADER];
unsigned i, ofs_len;
off_t ofs = offset - base_offset - fixup;
@@ -1091,26 +1099,61 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
copy_pack_data(out, reuse_packfile, w_curs, offset, next - offset);
}
-static size_t write_reused_pack_verbatim(struct hashfile *out,
+static size_t write_reused_pack_verbatim(struct bitmapped_pack *reuse_packfile,
+ struct hashfile *out,
struct pack_window **w_curs)
{
size_t pos = 0;
+ size_t end;
+
+ if (reuse_packfile->bitmap_pos) {
+ /*
+ * We can't reuse whole chunks verbatim out of
+ * non-preferred packs since we can't guarantee that
+ * all duplicate objects were resolved in favor of
+ * that pack.
+ *
+ * Even if we have a whole eword_t worth of bits that
+ * could be reused, there may be objects between the
+ * objects corresponding to the first and last bit of
+ * that word which were selected from a different
+ * pack, causing us to send duplicate or unwanted
+ * objects.
+ *
+ * Handle non-preferred packs from within
+ * write_reused_pack(), which inspects and reuses
+ * individual bits.
+ */
+ return reuse_packfile->bitmap_pos / BITS_IN_EWORD;
+ }
+
+ /*
+ * Only read through the last word whose bits all correspond
+ * to objects in the given packfile, since we must stop at a
+ * word boundary.
+ *
+ * If there is no whole word to read (i.e. the packfile
+ * contains fewer than BITS_IN_EWORD objects), then we'll
+ * inspect bits one-by-one in write_reused_pack().
+ */
+ end = reuse_packfile->bitmap_nr / BITS_IN_EWORD;
+ if (reuse_packfile_bitmap->word_alloc < end)
+ BUG("fewer words than expected in reuse_packfile_bitmap");
- while (pos < reuse_packfile_bitmap->word_alloc &&
- reuse_packfile_bitmap->words[pos] == (eword_t)~0)
+ while (pos < end && reuse_packfile_bitmap->words[pos] == (eword_t)~0)
pos++;
if (pos) {
off_t to_write;
written = (pos * BITS_IN_EWORD);
- to_write = pack_pos_to_offset(reuse_packfile, written)
+ to_write = pack_pos_to_offset(reuse_packfile->p, written)
- sizeof(struct pack_header);
/* We're recording one chunk, not one object. */
record_reused_object(sizeof(struct pack_header), 0);
hashflush(out);
- copy_pack_data(out, reuse_packfile, w_curs,
+ copy_pack_data(out, reuse_packfile->p, w_curs,
sizeof(struct pack_header), to_write);
display_progress(progress_state, written);
@@ -1118,34 +1161,71 @@ static size_t write_reused_pack_verbatim(struct hashfile *out,
return pos;
}
-static void write_reused_pack(struct hashfile *f)
+static void write_reused_pack(struct bitmapped_pack *reuse_packfile,
+ struct hashfile *f)
{
- size_t i = 0;
+ size_t i = reuse_packfile->bitmap_pos / BITS_IN_EWORD;
uint32_t offset;
+ off_t pack_start = hashfile_total(f) - sizeof(struct pack_header);
struct pack_window *w_curs = NULL;
if (allow_ofs_delta)
- i = write_reused_pack_verbatim(f, &w_curs);
+ i = write_reused_pack_verbatim(reuse_packfile, f, &w_curs);
for (; i < reuse_packfile_bitmap->word_alloc; ++i) {
eword_t word = reuse_packfile_bitmap->words[i];
size_t pos = (i * BITS_IN_EWORD);
for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
+ uint32_t pack_pos;
if ((word >> offset) == 0)
break;
offset += ewah_bit_ctz64(word >> offset);
- /*
- * Can use bit positions directly, even for MIDX
- * bitmaps. See comment in try_partial_reuse()
- * for why.
- */
- write_reused_pack_one(pos + offset, f, &w_curs);
+ if (pos + offset < reuse_packfile->bitmap_pos)
+ continue;
+ if (pos + offset >= reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr)
+ goto done;
+
+ if (reuse_packfile->bitmap_pos) {
+ /*
+ * When doing multi-pack reuse on a
+ * non-preferred pack, translate bit positions
+ * from the MIDX pseudo-pack order back to their
+ * pack-relative positions before attempting
+ * reuse.
+ */
+ struct multi_pack_index *m = reuse_packfile->from_midx;
+ uint32_t midx_pos;
+ off_t pack_ofs;
+
+ if (!m)
+ BUG("non-zero bitmap position without MIDX");
+
+ midx_pos = pack_pos_to_midx(m, pos + offset);
+ pack_ofs = nth_midxed_offset(m, midx_pos);
+
+ if (offset_to_pack_pos(reuse_packfile->p,
+ pack_ofs, &pack_pos) < 0)
+ BUG("could not find expected object at offset %"PRIuMAX" in pack %s",
+ (uintmax_t)pack_ofs,
+ pack_basename(reuse_packfile->p));
+ } else {
+ /*
+ * Can use bit positions directly, even for MIDX
+ * bitmaps. See comment in try_partial_reuse()
+ * for why.
+ */
+ pack_pos = pos + offset;
+ }
+
+ write_reused_pack_one(reuse_packfile->p, pack_pos, f,
+ pack_start, &w_curs);
display_progress(progress_state, ++written);
}
}
+done:
unuse_pack(&w_curs);
}
@@ -1197,9 +1277,14 @@ static void write_pack_file(void)
offset = write_pack_header(f, nr_remaining);
- if (reuse_packfile) {
+ if (reuse_packfiles_nr) {
assert(pack_to_stdout);
- write_reused_pack(f);
+ for (j = 0; j < reuse_packfiles_nr; j++) {
+ reused_chunks_nr = 0;
+ write_reused_pack(&reuse_packfiles[j], f);
+ if (reused_chunks_nr)
+ reuse_packfiles_used_nr++;
+ }
offset = hashfile_total(f);
}
@@ -1244,6 +1329,7 @@ static void write_pack_file(void)
if (!pack_to_stdout) {
struct stat st;
struct strbuf tmpname = STRBUF_INIT;
+ struct bitmap_writer bitmap_writer;
char *idx_tmp_name = NULL;
/*
@@ -1269,9 +1355,11 @@ static void write_pack_file(void)
hash_to_hex(hash));
if (write_bitmap_index) {
- bitmap_writer_set_checksum(hash);
- bitmap_writer_build_type_index(
- &to_pack, written_list, nr_written);
+ bitmap_writer_init(&bitmap_writer,
+ the_repository, &to_pack);
+ bitmap_writer_set_checksum(&bitmap_writer, hash);
+ bitmap_writer_build_type_index(&bitmap_writer,
+ written_list);
}
if (cruft)
@@ -1288,12 +1376,17 @@ static void write_pack_file(void)
strbuf_addstr(&tmpname, "bitmap");
stop_progress(&progress_state);
- bitmap_writer_show_progress(progress);
- bitmap_writer_select_commits(indexed_commits, indexed_commits_nr, -1);
- if (bitmap_writer_build(&to_pack) < 0)
+ bitmap_writer_show_progress(&bitmap_writer,
+ progress);
+ bitmap_writer_select_commits(&bitmap_writer,
+ indexed_commits,
+ indexed_commits_nr);
+ if (bitmap_writer_build(&bitmap_writer) < 0)
die(_("failed to write bitmap index"));
- bitmap_writer_finish(written_list, nr_written,
+ bitmap_writer_finish(&bitmap_writer,
+ written_list,
tmpname.buf, write_bitmap_options);
+ bitmap_writer_free(&bitmap_writer);
write_bitmap_index = 0;
strbuf_setlen(&tmpname, tmpname_len);
}
@@ -1449,7 +1542,7 @@ static int want_object_in_pack_one(struct packed_git *p,
if (p == *found_pack)
offset = *found_offset;
else
- offset = find_pack_entry_one(oid->hash, p);
+ offset = find_pack_entry_one(oid, p);
if (offset) {
if (!*found_pack) {
@@ -1756,7 +1849,8 @@ static void add_pbase_object(struct tree_desc *tree,
tree = pbase_tree_get(&entry.oid);
if (!tree)
return;
- init_tree_desc(&sub, tree->tree_data, tree->tree_size);
+ init_tree_desc(&sub, &tree->oid,
+ tree->tree_data, tree->tree_size);
add_pbase_object(&sub, down, downlen, fullname);
pbase_tree_put(tree);
@@ -1816,7 +1910,8 @@ static void add_preferred_base_object(const char *name)
}
else {
struct tree_desc tree;
- init_tree_desc(&tree, it->pcache.tree_data, it->pcache.tree_size);
+ init_tree_desc(&tree, &it->pcache.oid,
+ it->pcache.tree_data, it->pcache.tree_size);
add_pbase_object(&tree, name, cmplen, name);
}
}
@@ -1998,7 +2093,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
oidread(&base_ref,
use_pack(p, &w_curs,
entry->in_pack_offset + used,
- NULL));
+ NULL),
+ the_repository->hash_algo);
have_base = 1;
}
entry->in_pack_header_size = used + the_hash_algo->rawsz;
@@ -3047,12 +3143,12 @@ static void add_tag_chain(const struct object_id *oid)
}
}
-static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid,
+static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id peeled;
- if (!peel_iterated_oid(oid, &peeled) && obj_is_packed(&peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled) && obj_is_packed(&peeled))
add_tag_chain(oid);
return 0;
}
@@ -3175,7 +3271,19 @@ static int git_pack_config(const char *k, const char *v,
return 0;
}
if (!strcmp(k, "pack.allowpackreuse")) {
- allow_pack_reuse = git_config_bool(k, v);
+ int res = git_parse_maybe_bool_text(v);
+ if (res < 0) {
+ if (!strcasecmp(v, "single"))
+ allow_pack_reuse = SINGLE_PACK_REUSE;
+ else if (!strcasecmp(v, "multi"))
+ allow_pack_reuse = MULTI_PACK_REUSE;
+ else
+ die(_("invalid pack.allowPackReuse value: '%s'"), v);
+ } else if (res) {
+ allow_pack_reuse = SINGLE_PACK_REUSE;
+ } else {
+ allow_pack_reuse = NO_PACK_REUSE;
+ }
return 0;
}
if (!strcmp(k, "pack.threads")) {
@@ -3204,7 +3312,7 @@ static int git_pack_config(const char *k, const char *v,
return 0;
}
if (!strcmp(k, "uploadpack.blobpackfileuri")) {
- struct configured_exclusion *ex = xmalloc(sizeof(*ex));
+ struct configured_exclusion *ex;
const char *oid_end, *pack_end;
/*
* Stores the pack hash. This is not a true object ID, but is
@@ -3212,6 +3320,10 @@ static int git_pack_config(const char *k, const char *v,
*/
struct object_id pack_hash;
+ if (!v)
+ return config_error_nonbool(k);
+
+ ex = xmalloc(sizeof(*ex));
if (parse_oid_hex(v, &ex->e.oid, &oid_end) ||
*oid_end != ' ' ||
parse_oid_hex(oid_end + 1, &pack_hash, &pack_end) ||
@@ -3603,7 +3715,6 @@ static void read_cruft_objects(void)
string_list_append(&discard_packs, buf.buf + 1);
else
string_list_append(&fresh_packs, buf.buf);
- strbuf_reset(&buf);
}
string_list_sort(&discard_packs);
@@ -3739,7 +3850,7 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
show_object(obj, name, data);
}
-static int option_parse_missing_action(const struct option *opt,
+static int option_parse_missing_action(const struct option *opt UNUSED,
const char *arg, int unset)
{
assert(arg);
@@ -3843,7 +3954,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
*/
static void add_unreachable_loose_objects(void)
{
- for_each_loose_file_in_objdir(get_object_directory(),
+ for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
add_loose_object,
NULL, NULL, NULL);
}
@@ -3859,7 +3970,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
while (p) {
if ((!p->pack_local || p->pack_keep ||
p->pack_keep_in_core) &&
- find_pack_entry_one(oid->hash, p)) {
+ find_pack_entry_one(oid, p)) {
last_found = p;
return 1;
}
@@ -3931,7 +4042,7 @@ static void loosen_unused_packed_objects(void)
*/
static int pack_options_allow_reuse(void)
{
- return allow_pack_reuse &&
+ return allow_pack_reuse != NO_PACK_REUSE &&
pack_to_stdout &&
!ignore_packed_keep_on_disk &&
!ignore_packed_keep_in_core &&
@@ -3944,13 +4055,18 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
if (!(bitmap_git = prepare_bitmap_walk(revs, 0)))
return -1;
- if (pack_options_allow_reuse() &&
- !reuse_partial_packfile_from_bitmap(
- bitmap_git,
- &reuse_packfile,
- &reuse_packfile_objects,
- &reuse_packfile_bitmap)) {
- assert(reuse_packfile_objects);
+ if (pack_options_allow_reuse())
+ reuse_partial_packfile_from_bitmap(bitmap_git,
+ &reuse_packfiles,
+ &reuse_packfiles_nr,
+ &reuse_packfile_bitmap,
+ allow_pack_reuse == MULTI_PACK_REUSE);
+
+ if (reuse_packfiles) {
+ reuse_packfile_objects = bitmap_popcount(reuse_packfile_bitmap);
+ if (!reuse_packfile_objects)
+ BUG("expected non-empty reuse bitmap");
+
nr_result += reuse_packfile_objects;
nr_seen += reuse_packfile_objects;
display_progress(progress_state, nr_seen);
@@ -3974,6 +4090,7 @@ static void record_recent_commit(struct commit *commit, void *data UNUSED)
}
static int mark_bitmap_preferred_tip(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *data UNUSED)
@@ -3981,7 +4098,7 @@ static int mark_bitmap_preferred_tip(const char *refname,
struct object_id peeled;
struct object *object;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
object = parse_object_or_die(oid, refname);
@@ -4001,7 +4118,9 @@ static void mark_bitmap_preferred_tips(void)
return;
for_each_string_list_item(item, preferred_tips) {
- for_each_ref_in(item->string, mark_bitmap_preferred_tip, NULL);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ item->string, mark_bitmap_preferred_tip,
+ NULL);
}
}
@@ -4120,34 +4239,37 @@ static void add_extra_kept_packs(const struct string_list *names)
static int option_parse_quiet(const struct option *opt, const char *arg,
int unset)
{
+ int *val = opt->value;
+
BUG_ON_OPT_ARG(arg);
if (!unset)
- progress = 0;
- else if (!progress)
- progress = 1;
+ *val = 0;
+ else if (!*val)
+ *val = 1;
return 0;
}
static int option_parse_index_version(const struct option *opt,
const char *arg, int unset)
{
+ struct pack_idx_option *popts = opt->value;
char *c;
const char *val = arg;
BUG_ON_OPT_NEG(unset);
- pack_idx_opts.version = strtoul(val, &c, 10);
- if (pack_idx_opts.version > 2)
+ popts->version = strtoul(val, &c, 10);
+ if (popts->version > 2)
die(_("unsupported index version %s"), val);
if (*c == ',' && c[1])
- pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
- if (*c || pack_idx_opts.off32_limit & 0x80000000)
+ popts->off32_limit = strtoul(c+1, &c, 0);
+ if (*c || popts->off32_limit & 0x80000000)
die(_("bad index version '%s'"), val);
return 0;
}
-static int option_parse_unpack_unreachable(const struct option *opt,
+static int option_parse_unpack_unreachable(const struct option *opt UNUSED,
const char *arg, int unset)
{
if (unset) {
@@ -4162,7 +4284,7 @@ static int option_parse_unpack_unreachable(const struct option *opt,
return 0;
}
-static int option_parse_cruft_expiration(const struct option *opt,
+static int option_parse_cruft_expiration(const struct option *opt UNUSED,
const char *arg, int unset)
{
if (unset) {
@@ -4176,7 +4298,22 @@ static int option_parse_cruft_expiration(const struct option *opt,
return 0;
}
-int cmd_pack_objects(int argc, const char **argv, const char *prefix)
+static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
+{
+ struct object_info info = OBJECT_INFO_INIT;
+ if (oid_object_info_extended(the_repository, &obj->oid, &info, 0))
+ BUG("should_include_obj should only be called on existing objects");
+ return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor;
+}
+
+static int is_not_in_promisor_pack(struct commit *commit, void *data) {
+ return is_not_in_promisor_pack_obj((struct object *) commit, data);
+}
+
+int cmd_pack_objects(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int use_internal_rev_list = 0;
int shallow = 0;
@@ -4190,7 +4327,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
LIST_OBJECTS_FILTER_INIT;
struct option pack_objects_options[] = {
- OPT_CALLBACK_F('q', "quiet", NULL, NULL,
+ OPT_CALLBACK_F('q', "quiet", &progress, NULL,
N_("do not show progress meter"),
PARSE_OPT_NOARG, option_parse_quiet),
OPT_SET_INT(0, "progress", &progress,
@@ -4200,7 +4337,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("similar to --all-progress when progress meter is shown")),
- OPT_CALLBACK_F(0, "index-version", NULL, N_("<version>[,<offset>]"),
+ OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"),
PARSE_OPT_NONEG, option_parse_index_version),
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
@@ -4285,6 +4422,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
option_parse_missing_action),
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
N_("do not pack objects in promisor packfiles")),
+ OPT_BOOL(0, "exclude-promisor-objects-best-effort",
+ &exclude_promisor_objects_best_effort,
+ N_("implies --missing=allow-any")),
OPT_BOOL(0, "delta-islands", &use_delta_islands,
N_("respect islands during delta compression")),
OPT_STRING_LIST(0, "uri-protocol", &uri_protocols,
@@ -4303,6 +4443,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
if (sparse < 0)
sparse = the_repository->settings.pack_use_sparse;
+ if (the_repository->settings.pack_use_multi_pack_reuse)
+ allow_pack_reuse = MULTI_PACK_REUSE;
}
reset_pack_idx_option(&pack_idx_opts);
@@ -4363,10 +4505,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
strvec_push(&rp, "--unpacked");
}
+ if (exclude_promisor_objects && exclude_promisor_objects_best_effort)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-promisor-objects", "--exclude-promisor-objects-best-effort");
if (exclude_promisor_objects) {
use_internal_rev_list = 1;
fetch_if_missing = 0;
strvec_push(&rp, "--exclude-promisor-objects");
+ } else if (exclude_promisor_objects_best_effort) {
+ use_internal_rev_list = 1;
+ fetch_if_missing = 0;
+ option_parse_missing_action(NULL, "allow-any", 0);
+ /* revs configured below */
}
if (unpack_unreachable || keep_unreachable || pack_loose_unreachable)
use_internal_rev_list = 1;
@@ -4383,7 +4533,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!HAVE_THREADS && delta_search_threads != 1)
warning(_("no threads support, ignoring --threads"));
- if (!pack_to_stdout && !pack_size_limit && !cruft)
+ if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
die(_("--max-pack-size cannot be used to build a pack for transfer"));
@@ -4400,12 +4550,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (filter_options.choice) {
- if (!pack_to_stdout)
- die(_("cannot use --filter without --stdout"));
- if (stdin_packs)
- die(_("cannot use --filter with --stdin-packs"));
- }
+ if (stdin_packs && filter_options.choice)
+ die(_("cannot use --filter with --stdin-packs"));
if (stdin_packs && use_internal_rev_list)
die(_("cannot use internal rev list with --stdin-packs"));
@@ -4415,8 +4561,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
die(_("cannot use internal rev list with --cruft"));
if (stdin_packs)
die(_("cannot use --stdin-packs with --cruft"));
- if (pack_size_limit)
- die(_("cannot use --max-pack-size with --cruft"));
}
/*
@@ -4492,12 +4636,17 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &revs, NULL);
list_objects_filter_copy(&revs.filter, &filter_options);
+ if (exclude_promisor_objects_best_effort) {
+ revs.include_check = is_not_in_promisor_pack;
+ revs.include_check_obj = is_not_in_promisor_pack_obj;
+ }
get_object_list(&revs, rp.nr, rp.v);
release_revisions(&revs);
}
cleanup_preferred_base();
if (include_tag && nr_result)
- for_each_tag_ref(add_ref_tag, NULL);
+ refs_for_each_tag_ref(get_main_ref_store(the_repository),
+ add_ref_tag, NULL);
stop_progress(&progress_state);
trace2_region_leave("pack-objects", "enumerate-objects",
the_repository);
@@ -4521,12 +4670,22 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
fprintf_ln(stderr,
_("Total %"PRIu32" (delta %"PRIu32"),"
" reused %"PRIu32" (delta %"PRIu32"),"
- " pack-reused %"PRIu32),
+ " pack-reused %"PRIu32" (from %"PRIuMAX")"),
written, written_delta, reused, reused_delta,
- reuse_packfile_objects);
+ reuse_packfile_objects,
+ (uintmax_t)reuse_packfiles_used_nr);
+
+ trace2_data_intmax("pack-objects", the_repository, "written", written);
+ trace2_data_intmax("pack-objects", the_repository, "written/delta", written_delta);
+ trace2_data_intmax("pack-objects", the_repository, "reused", reused);
+ trace2_data_intmax("pack-objects", the_repository, "reused/delta", reused_delta);
+ trace2_data_intmax("pack-objects", the_repository, "pack-reused", reuse_packfile_objects);
+ trace2_data_intmax("pack-objects", the_repository, "packs-reused", reuse_packfiles_used_nr);
cleanup:
+ clear_packing_data(&to_pack);
list_objects_filter_release(&filter_options);
+ string_list_clear(&keep_pack_list, 0);
strvec_clear(&rp);
return 0;
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 4c735ba069..d2c1c4e5ec 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -5,13 +5,15 @@
* This file is licensed under the GPL v2.
*
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
+
#include "packfile.h"
#include "object-store-ll.h"
+#include "strbuf.h"
#define BLKSIZE 512
@@ -68,6 +70,15 @@ static inline void llist_init(struct llist **list)
(*list)->size = 0;
}
+static void llist_free(struct llist *list)
+{
+ for (struct llist_item *i = list->front, *next; i; i = next) {
+ next = i->next;
+ llist_item_put(i);
+ }
+ free(list);
+}
+
static struct llist * llist_copy(struct llist *list)
{
struct llist *ret;
@@ -100,7 +111,7 @@ static inline struct llist_item *llist_insert(struct llist *list,
const unsigned char *oid)
{
struct llist_item *new_item = llist_item_get();
- oidread(&new_item->oid, oid);
+ oidread(&new_item->oid, oid, the_repository->hash_algo);
new_item->next = NULL;
if (after) {
@@ -155,7 +166,7 @@ redo_from_start:
l = (hint == NULL) ? list->front : hint;
prev = NULL;
while (l) {
- const int cmp = hashcmp(l->oid.hash, oid);
+ const int cmp = hashcmp(l->oid.hash, oid, the_repository->hash_algo);
if (cmp > 0) /* not in list, since sorted */
return prev;
if (!cmp) { /* found */
@@ -205,6 +216,14 @@ static inline struct pack_list * pack_list_insert(struct pack_list **pl,
return p;
}
+static void pack_list_free(struct pack_list *pl)
+{
+ for (struct pack_list *next; pl; pl = next) {
+ next = pl->next;
+ free(pl);
+ }
+}
+
static inline size_t pack_list_size(struct pack_list *pl)
{
size_t ret = 0;
@@ -258,7 +277,8 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
while (p1_off < p1->pack->num_objects * p1_step &&
p2_off < p2->pack->num_objects * p2_step)
{
- const int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off);
+ const int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off,
+ the_repository->hash_algo);
/* cmp ~ p1 - p2 */
if (cmp == 0) {
p1_hint = llist_sorted_remove(p1->unique_objects,
@@ -296,7 +316,8 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
while (p1_off < p1->num_objects * p1_step &&
p2_off < p2->num_objects * p2_step)
{
- int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off);
+ int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off,
+ the_repository->hash_algo);
/* cmp ~ p1 - p2 */
if (cmp == 0) {
ret++;
@@ -416,7 +437,8 @@ static void minimize(struct pack_list **min)
/* return if there are no objects missing from the unique set */
if (missing->size == 0) {
- free(missing);
+ llist_free(missing);
+ pack_list_free(non_unique);
return;
}
@@ -431,6 +453,8 @@ static void minimize(struct pack_list **min)
}
while (non_unique) {
+ struct pack_list *next;
+
/* sort the non_unique packs, greater size of remaining_objects first */
sort_pack_list(&non_unique);
if (non_unique->remaining_objects->size == 0)
@@ -441,8 +465,14 @@ static void minimize(struct pack_list **min)
for (pl = non_unique->next; pl && pl->remaining_objects->size > 0; pl = pl->next)
llist_sorted_difference_inplace(pl->remaining_objects, non_unique->remaining_objects);
- non_unique = non_unique->next;
+ next = non_unique->next;
+ free(non_unique);
+ non_unique = next;
}
+
+ pack_list_free(non_unique);
+ llist_free(unique_pack_objects);
+ llist_free(missing);
}
static void load_all_objects(void)
@@ -559,13 +589,10 @@ static void load_all(void)
}
}
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
-{
- int i;
- int i_still_use_this = 0;
- struct pack_list *min = NULL, *red, *pl;
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) {
+ int i; int i_still_use_this = 0; struct pack_list *min = NULL, *red, *pl;
struct llist *ignore;
- struct object_id *oid;
+ struct strbuf idx_name = STRBUF_INIT;
char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -625,11 +652,11 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
/* ignore objects given on stdin */
llist_init(&ignore);
if (!isatty(0)) {
+ struct object_id oid;
while (fgets(buf, sizeof(buf), stdin)) {
- oid = xmalloc(sizeof(*oid));
- if (get_oid_hex(buf, oid))
+ if (get_oid_hex(buf, &oid))
die("Bad object ID on stdin: %s", buf);
- llist_insert_sorted_unique(ignore, oid, NULL);
+ llist_insert_sorted_unique(ignore, &oid, NULL);
}
}
llist_sorted_difference_inplace(all_objects, ignore);
@@ -663,7 +690,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
pl = red = pack_list_difference(local_packs, min);
while (pl) {
printf("%s\n%s\n",
- sha1_pack_index_name(pl->pack->hash),
+ odb_pack_name(&idx_name, pl->pack->hash, "idx"),
pl->pack->pack_name);
pl = pl->next;
}
@@ -671,5 +698,9 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
fprintf(stderr, "%luMB of redundant packs in total.\n",
(unsigned long)pack_set_bytecount(red)/(1024*1024));
+ pack_list_free(red);
+ pack_list_free(min);
+ llist_free(ignore);
+ strbuf_release(&idx_name);
return 0;
}
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index bcf383cac9..2d83c1ed2a 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,30 +1,37 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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] [--include <pattern>] [--exclude <pattern>]"),
+ N_("git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]"),
NULL
};
-int cmd_pack_refs(int argc, const char **argv, const char *prefix)
+int cmd_pack_refs(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
- 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 ref_exclusions excludes = REF_EXCLUSIONS_INIT;
+ struct string_list included_refs = STRING_LIST_INIT_NODUP;
+ struct pack_refs_opts pack_refs_opts = {
+ .exclusions = &excludes,
+ .includes = &included_refs,
+ .flags = PACK_REFS_PRUNE,
+ };
+ struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
struct string_list_item *item;
+ int pack_all = 0;
+ int ret;
struct option opts[] = {
- OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
+ OPT_BOOL(0, "all", &pack_all, N_("pack everything")),
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+ OPT_BIT(0, "auto", &pack_refs_opts.flags, N_("auto-pack refs as needed"), PACK_REFS_AUTO),
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"),
@@ -38,11 +45,16 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
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)
+ if (pack_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);
+ ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
+
+ clear_ref_exclusions(&excludes);
+ string_list_clear(&included_refs, 0);
+ string_list_clear(&option_excluded_refs, 0);
+ return ret;
}
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b970..93b398e391 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "diff.h"
@@ -5,6 +6,7 @@
#include "hash.h"
#include "hex.h"
#include "parse-options.h"
+#include "setup.h"
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
{
@@ -69,7 +71,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
git_hash_ctx ctx;
the_hash_algo->init_fn(&ctx);
- oidclr(result);
+ oidclr(result, the_repository->hash_algo);
while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) {
char *line = line_buf->buf;
@@ -165,7 +167,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
}
if (!found_next)
- oidclr(next_oid);
+ oidclr(next_oid, the_repository->hash_algo);
flush_one_hunk(result, &ctx);
@@ -178,7 +180,7 @@ static void generate_id_list(int stable, int verbatim)
int patchlen;
struct strbuf line_buf = STRBUF_INIT;
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
while (!feof(stdin)) {
patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim);
flush_current_id(patchlen, &oid, &result);
@@ -213,7 +215,10 @@ static int git_patch_id_config(const char *var, const char *value,
return git_default_config(var, value, ctx, cb);
}
-int cmd_patch_id(int argc, const char **argv, const char *prefix)
+int cmd_patch_id(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
/* if nothing is set, default to unstable */
struct patch_id_opts config = {0, 0};
@@ -237,6 +242,18 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_patch_id_options,
patch_id_usage, 0);
+ /*
+ * We rely on `the_hash_algo` to compute patch IDs. This is dubious as
+ * it means that the hash algorithm now depends on the object hash of
+ * the repository, even though git-patch-id(1) clearly defines that
+ * patch IDs always use SHA1.
+ *
+ * NEEDSWORK: This hack should be removed in favor of converting
+ * the code that computes patch IDs to always use SHA1.
+ */
+ if (!the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
generate_id_list(opts ? opts > 1 : config.stable,
opts ? opts == 3 : config.verbatim);
return 0;
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index ca3578e158..4d63f26b0a 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -8,7 +8,10 @@ static const char * const prune_packed_usage[] = {
NULL
};
-int cmd_prune_packed(int argc, const char **argv, const char *prefix)
+int cmd_prune_packed(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int opts = isatty(2) ? PRUNE_PACKED_VERBOSE : 0;
const struct option prune_packed_options[] = {
diff --git a/builtin/prune.c b/builtin/prune.c
index 57fe31467f..2b1de01339 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "commit.h"
#include "diff.h"
@@ -147,7 +148,10 @@ static void remove_temporary_files(const char *path)
closedir(dir);
}
-int cmd_prune(int argc, const char **argv, const char *prefix)
+int cmd_prune(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info revs;
int exclude_promisor_objects = 0;
@@ -193,12 +197,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
revs.exclude_promisor_objects = 1;
}
- for_each_loose_file_in_objdir(get_object_directory(), prune_object,
- prune_cruft, prune_subdir, &revs);
+ for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ prune_object, prune_cruft, prune_subdir, &revs);
prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
- remove_temporary_files(get_object_directory());
- s = mkpathdup("%s/pack", get_object_directory());
+ remove_temporary_files(repo_get_object_directory(the_repository));
+ s = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
remove_temporary_files(s);
free(s);
diff --git a/builtin/pull.c b/builtin/pull.c
index be2b2c9ebc..edc56907aa 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -5,7 +5,8 @@
*
* Fetch one or more remote refs and merge it/them into the current HEAD.
*/
-#define USE_THE_INDEX_VARIABLE
+
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -14,7 +15,6 @@
#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"
@@ -24,15 +24,11 @@
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
-#include "revision.h"
#include "submodule.h"
#include "submodule-config.h"
-#include "tempfile.h"
-#include "lockfile.h"
#include "wt-status.h"
#include "commit-reach.h"
#include "sequencer.h"
-#include "packfile.h"
/**
* Parses the value of --rebase. If value is a false value, returns
@@ -76,48 +72,48 @@ static const char * const pull_usage[] = {
/* Shared options */
static int opt_verbosity;
-static char *opt_progress;
+static const char *opt_progress;
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
/* Options passed to git-merge or git-rebase */
static enum rebase_type opt_rebase = -1;
-static char *opt_diffstat;
-static char *opt_log;
-static char *opt_signoff;
-static char *opt_squash;
-static char *opt_commit;
-static char *opt_edit;
-static char *cleanup_arg;
+static const char *opt_diffstat;
+static const char *opt_log;
+static const char *opt_signoff;
+static const char *opt_squash;
+static const char *opt_commit;
+static const char *opt_edit;
+static const char *cleanup_arg;
static char *opt_ff;
-static char *opt_verify_signatures;
-static char *opt_verify;
+static const char *opt_verify_signatures;
+static const char *opt_verify;
static int opt_autostash = -1;
static int config_autostash;
static int check_trust_level = 1;
static struct strvec opt_strategies = STRVEC_INIT;
static struct strvec opt_strategy_opts = STRVEC_INIT;
-static char *opt_gpg_sign;
+static const char *opt_gpg_sign;
static int opt_allow_unrelated_histories;
/* Options passed to git-fetch */
-static char *opt_all;
-static char *opt_append;
-static char *opt_upload_pack;
+static const char *opt_all;
+static const char *opt_append;
+static const char *opt_upload_pack;
static int opt_force;
-static char *opt_tags;
-static char *opt_prune;
-static char *max_children;
+static const char *opt_tags;
+static const char *opt_prune;
+static const char *max_children;
static int opt_dry_run;
-static char *opt_keep;
-static char *opt_depth;
-static char *opt_unshallow;
-static char *opt_update_shallow;
-static char *opt_refmap;
-static char *opt_ipv4;
-static char *opt_ipv6;
+static const char *opt_keep;
+static const char *opt_depth;
+static const char *opt_unshallow;
+static const char *opt_update_shallow;
+static const char *opt_refmap;
+static const char *opt_ipv4;
+static const char *opt_ipv6;
static int opt_show_forced_updates = -1;
-static char *set_upstream;
+static const char *set_upstream;
static struct strvec opt_fetch = STRVEC_INIT;
static struct option pull_options[] = {
@@ -222,8 +218,8 @@ static struct option pull_options[] = {
OPT_PASSTHRU_ARGV(0, "shallow-since", &opt_fetch, N_("time"),
N_("deepen history of shallow repository based on time"),
0),
- OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("revision"),
- N_("deepen history of shallow clone, excluding rev"),
+ OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("ref"),
+ N_("deepen history of shallow clone, excluding ref"),
0),
OPT_PASSTHRU_ARGV(0, "deepen", &opt_fetch, N_("n"),
N_("deepen history of shallow clone"),
@@ -616,7 +612,7 @@ static int pull_into_void(const struct object_id *merge_head,
merge_head, 0))
return 1;
- if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+ if (refs_update_ref(get_main_ref_store(the_repository), "initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
return 1;
return 0;
@@ -820,7 +816,7 @@ static int get_octopus_merge_base(struct object_id *merge_base,
const struct object_id *merge_head,
const struct object_id *fork_point)
{
- struct commit_list *revs = NULL, *result;
+ struct commit_list *revs = NULL, *result = NULL;
commit_list_insert(lookup_commit_reference(the_repository, curr_head),
&revs);
@@ -830,7 +826,8 @@ static int get_octopus_merge_base(struct object_id *merge_base,
commit_list_insert(lookup_commit_reference(the_repository, fork_point),
&revs);
- result = get_octopus_merge_bases(revs);
+ if (get_octopus_merge_bases(revs, &result) < 0)
+ exit(128);
free_commit_list(revs);
reduce_heads_replace(&result);
@@ -931,6 +928,8 @@ static int get_can_ff(struct object_id *orig_head,
merge_head = lookup_commit_reference(the_repository, orig_merge_head);
ret = repo_is_descendant_of(the_repository, merge_head, list);
free_commit_list(list);
+ if (ret < 0)
+ exit(128);
return ret;
}
@@ -955,6 +954,8 @@ static int already_up_to_date(struct object_id *orig_head,
commit_list_insert(theirs, &list);
ok = repo_is_descendant_of(the_repository, ours, list);
free_commit_list(list);
+ if (ok < 0)
+ exit(128);
if (!ok)
return 0;
}
@@ -977,7 +978,10 @@ static void show_advice_pull_non_ff(void)
"invocation.\n"));
}
-int cmd_pull(int argc, const char **argv, const char *prefix)
+int cmd_pull(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repository UNUSED)
{
const char *repo, **refspecs;
struct oid_array merge_heads = OID_ARRAY_INIT;
@@ -1024,8 +1028,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
* "--rebase" can override a config setting of
* pull.ff=only.
*/
- if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only"))
- opt_ff = "--ff";
+ if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) {
+ free(opt_ff);
+ opt_ff = xstrdup("--ff");
+ }
}
if (opt_rebase < 0)
@@ -1038,13 +1044,13 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
die_conclude_merge();
if (repo_get_oid(the_repository, "HEAD", &orig_head))
- oidclr(&orig_head);
+ oidclr(&orig_head, the_repository->hash_algo);
if (opt_rebase) {
if (opt_autostash == -1)
opt_autostash = config_autostash;
- if (is_null_oid(&orig_head) && !is_index_unborn(&the_index))
+ if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))
die(_("Updating an unborn branch with changes added to the index."));
if (!opt_autostash)
@@ -1053,7 +1059,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
_("Please commit or stash them."), 1, 0);
if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
- oidclr(&rebase_fork_point);
+ oidclr(&rebase_fork_point, the_repository->hash_algo);
}
if (run_fetch(repo, refspecs))
@@ -1063,7 +1069,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
return 0;
if (repo_get_oid(the_repository, "HEAD", &curr_head))
- oidclr(&curr_head);
+ oidclr(&curr_head, the_repository->hash_algo);
if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
!oideq(&orig_head, &curr_head)) {
@@ -1135,7 +1141,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (can_ff) {
/* we can fast-forward this without invoking rebase */
- opt_ff = "--ff-only";
+ free(opt_ff);
+ opt_ff = xstrdup("--ff-only");
ret = run_merge();
} else {
ret = run_rebase(&newbase, &upstream);
diff --git a/builtin/push.c b/builtin/push.c
index 2e708383c2..51c609f208 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -1,20 +1,19 @@
/*
* "git push"
*/
+#define USE_THE_REPOSITORY_VARIABLE
#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 "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"
@@ -73,13 +72,15 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref,
const char *branch_name;
if (remote->push.nr) {
- struct refspec_item query;
- memset(&query, 0, sizeof(struct refspec_item));
- query.src = matched->name;
+ struct refspec_item query = {
+ .src = matched->name,
+ };
+
if (!query_refspecs(&remote->push, &query) && query.dst) {
refspec_appendf(refspec, "%s%s:%s",
query.force ? "+" : "",
query.src, query.dst);
+ free(query.dst);
return;
}
}
@@ -97,9 +98,8 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref,
refspec_append(refspec, ref);
}
-static void set_refspecs(const char **refs, int nr, const char *repo)
+static void set_refspecs(const char **refs, int nr, struct remote *remote)
{
- struct remote *remote = NULL;
struct ref *local_refs = NULL;
int i;
@@ -125,33 +125,16 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
local_refs = get_local_heads();
/* Does "ref" uniquely name our ref? */
- if (count_refspec_match(ref, local_refs, &matched) != 1) {
+ if (count_refspec_match(ref, local_refs, &matched) != 1)
refspec_append(&rs, ref);
- } else {
- /* lazily grab remote */
- if (!remote)
- remote = remote_get(repo);
- if (!remote)
- BUG("must get a remote for repo '%s'", repo);
-
+ else
refspec_append_mapped(&rs, ref, remote, matched);
- }
} else
refspec_append(&rs, ref);
}
free_refs(local_refs);
}
-static int push_url_of_remote(struct remote *remote, const char ***url_p)
-{
- if (remote->pushurl_nr) {
- *url_p = remote->pushurl;
- return remote->pushurl_nr;
- }
- *url_p = remote->url;
- return remote->url_nr;
-}
-
static NORETURN void die_push_simple(struct branch *branch,
struct remote *remote)
{
@@ -392,7 +375,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
if (!is_empty_cas(&cas)) {
if (!transport->smart_options)
die("underlying transport does not support --%s option",
- CAS_OPT_NAME);
+ "force-with-lease");
transport->smart_options->cas = &cas;
}
@@ -435,8 +418,7 @@ static int do_push(int flags,
struct remote *remote)
{
int i, errs;
- const char **url;
- int url_nr;
+ struct strvec *url;
struct refspec *push_refspec = &rs;
if (push_options->nr)
@@ -449,19 +431,10 @@ static int do_push(int flags,
setup_default_push_refspecs(&flags, remote);
}
errs = 0;
- url_nr = push_url_of_remote(remote, &url);
- if (url_nr) {
- for (i = 0; i < url_nr; i++) {
- struct transport *transport =
- transport_get(remote, url[i]);
- if (flags & TRANSPORT_PUSH_OPTIONS)
- transport->push_options = push_options;
- if (push_with_options(transport, push_refspec, flags))
- errs++;
- }
- } else {
+ url = push_url_of_remote(remote);
+ for (i = 0; i < url->nr; i++) {
struct transport *transport =
- transport_get(remote, NULL);
+ transport_get(remote, url->v[i]);
if (flags & TRANSPORT_PUSH_OPTIONS)
transport->push_options = push_options;
if (push_with_options(transport, push_refspec, flags))
@@ -526,39 +499,27 @@ static int git_push_config(const char *k, const char *v,
*flags |= TRANSPORT_PUSH_AUTO_UPSTREAM;
return 0;
} else if (!strcmp(k, "push.gpgsign")) {
- const char *value;
- if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_parse_maybe_bool(value)) {
- case 0:
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
- break;
- case 1:
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
- break;
- default:
- if (value && !strcasecmp(value, "if-asked"))
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
- else
- return error(_("invalid value for '%s'"), k);
- }
+ switch (git_parse_maybe_bool(v)) {
+ case 0:
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
+ break;
+ case 1:
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
+ break;
+ default:
+ if (!strcasecmp(v, "if-asked"))
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
+ else
+ return error(_("invalid value for '%s'"), k);
}
} else if (!strcmp(k, "push.recursesubmodules")) {
- const char *value;
- if (!git_config_get_value("push.recursesubmodules", &value))
- recurse_submodules = parse_push_recurse_submodules_arg(k, value);
+ recurse_submodules = parse_push_recurse_submodules_arg(k, v);
} else if (!strcmp(k, "submodule.recurse")) {
int val = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
recurse_submodules = val;
} else if (!strcmp(k, "push.pushoption")) {
- if (!v)
- return config_error_nonbool(k);
- else
- if (!*v)
- string_list_clear(&push_options_config, 0);
- else
- string_list_append(&push_options_config, v);
- return 0;
+ return parse_transport_option(k, v, &push_options_config);
} else if (!strcmp(k, "color.push")) {
push_use_color = git_config_colorbool(k, v);
return 0;
@@ -580,7 +541,10 @@ static int git_push_config(const char *k, const char *v,
return git_default_config(k, v, ctx, NULL);
}
-int cmd_push(int argc, const char **argv, const char *prefix)
+int cmd_push(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repository UNUSED)
{
int flags = 0;
int tags = 0;
@@ -604,7 +568,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
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),
- OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
+ OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option),
OPT_BIT(0, TRANS_OPT_FORCE_IF_INCLUDES, &flags,
@@ -639,8 +603,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
: &push_options_config);
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/--branches/--mirror/--tags");
+ die_for_incompatible_opt4(deleterefs, "--delete",
+ tags, "--tags",
+ flags & TRANSPORT_PUSH_ALL, "--all/--branches",
+ flags & TRANSPORT_PUSH_MIRROR, "--mirror");
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
@@ -654,10 +620,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
if (tags)
refspec_append(&rs, "refs/tags/*");
- if (argc > 0) {
+ if (argc > 0)
repo = argv[0];
- set_refspecs(argv + 1, argc - 1, repo);
- }
remote = pushremote_get(repo);
if (!remote) {
@@ -673,23 +637,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)
" git push <name>\n"));
}
+ if (argc > 0)
+ set_refspecs(argv + 1, argc - 1, remote);
+
if (remote->mirror)
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
if (flags & TRANSPORT_PUSH_ALL) {
- if (tags)
- die(_("options '%s' and '%s' cannot be used together"), "--all", "--tags");
if (argc >= 2)
die(_("--all can't be combined with refspecs"));
}
if (flags & TRANSPORT_PUSH_MIRROR) {
- if (tags)
- die(_("options '%s' and '%s' cannot be used together"), "--mirror", "--tags");
if (argc >= 2)
die(_("--mirror can't be combined with refspecs"));
}
- if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
- die(_("options '%s' and '%s' cannot be used together"), "--all", "--mirror");
if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
cas.use_force_if_includes = 1;
@@ -701,6 +662,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
rc = do_push(flags, push_options, remote);
string_list_clear(&push_options_cmdline, 0);
string_list_clear(&push_options_config, 0);
+ clear_cas_option(&cas);
if (rc == -1)
usage_with_options(push_usage, options);
else
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index e455a4795c..1b33ab66a7 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -1,11 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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[] = {
N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"),
@@ -14,7 +14,10 @@ N_("git range-diff [<options>] <base> <old-tip> <new-tip>"),
NULL
};
-int cmd_range_diff(int argc, const char **argv, const char *prefix)
+int cmd_range_diff(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct diff_options diffopt = { NULL };
struct strvec other_arg = STRVEC_INIT;
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 1fec702a04..d2a807a828 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -3,8 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -16,14 +15,11 @@
#include "tree-walk.h"
#include "cache-tree.h"
#include "unpack-trees.h"
-#include "dir.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"
static int nr_trees;
static int read_empty;
@@ -49,7 +45,7 @@ static const char * const read_tree_usage[] = {
NULL
};
-static int index_output_cb(const struct option *opt, const char *arg,
+static int index_output_cb(const struct option *opt UNUSED, const char *arg,
int unset)
{
BUG_ON_OPT_NEG(unset);
@@ -111,7 +107,10 @@ static int git_read_tree_config(const char *var, const char *value,
return git_default_config(var, value, ctx, cb);
}
-int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
+int cmd_read_tree(int argc,
+ const char **argv,
+ const char *cmd_prefix,
+ struct repository *repo UNUSED)
{
int i, stage = 0;
struct object_id oid;
@@ -161,8 +160,8 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
git_config(git_read_tree_config, NULL);
@@ -199,7 +198,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
die(_("You need to resolve your current index first"));
stage = opts.merge = 1;
}
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
@@ -227,7 +226,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
setup_work_tree();
if (opts.skip_sparse_checkout)
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
if (opts.merge) {
switch (stage - 1) {
@@ -239,7 +238,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
break;
case 2:
opts.fn = twoway_merge;
- opts.initial_checkout = is_index_unborn(&the_index);
+ opts.initial_checkout = is_index_unborn(the_repository->index);
break;
case 3:
default:
@@ -260,11 +259,12 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
if (nr_trees == 1 && !opts.prefix)
opts.skip_cache_tree_update = 1;
- cache_tree_free(&the_index.cache_tree);
+ cache_tree_free(&the_repository->index->cache_tree);
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];
- parse_tree(tree);
- init_tree_desc(t+i, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ return 128;
+ init_tree_desc(t+i, &tree->object.oid, tree->buffer, tree->size);
}
if (unpack_trees(nr_trees, t, &opts))
return 128;
@@ -283,7 +283,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
the_repository->index,
trees[0]);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die("unable to write new index file");
return 0;
}
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 50cb85751f..bbaca3c5d5 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -3,22 +3,18 @@
*
* Copyright (c) 2018 Pratik Karki
*/
-
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_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 "dir.h"
-#include "packfile.h"
#include "refs.h"
-#include "quote.h"
#include "config.h"
-#include "cache-tree.h"
#include "unpack-trees.h"
#include "lockfile.h"
#include "object-file.h"
@@ -62,7 +58,7 @@ enum empty_type {
EMPTY_UNSPECIFIED = -1,
EMPTY_DROP,
EMPTY_KEEP,
- EMPTY_ASK
+ EMPTY_STOP
};
enum action {
@@ -88,7 +84,7 @@ static const char *action_names[] = {
struct rebase_options {
enum rebase_type type;
enum empty_type empty;
- const char *default_backend;
+ char *default_backend;
const char *state_dir;
struct commit *upstream;
const char *upstream_name;
@@ -140,7 +136,7 @@ struct rebase_options {
.type = REBASE_UNSPECIFIED, \
.empty = EMPTY_UNSPECIFIED, \
.keep_empty = 1, \
- .default_backend = "merge", \
+ .default_backend = xstrdup("merge"), \
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
.exec = STRING_LIST_INIT_NODUP, \
@@ -149,7 +145,6 @@ struct rebase_options {
.reapply_cherry_picks = -1, \
.allow_empty_message = 1, \
.autosquash = -1, \
- .config_autosquash = -1, \
.rebase_merges = -1, \
.config_rebase_merges = -1, \
.update_refs = -1, \
@@ -157,6 +152,19 @@ struct rebase_options {
.strategy_opts = STRING_LIST_INIT_NODUP,\
}
+static void rebase_options_release(struct rebase_options *opts)
+{
+ free(opts->default_backend);
+ free(opts->reflog_action);
+ free(opts->head_name);
+ strvec_clear(&opts->git_am_opts);
+ free(opts->gpg_sign_opt);
+ string_list_clear(&opts->exec, 0);
+ free(opts->strategy);
+ string_list_clear(&opts->strategy_opts, 0);
+ strbuf_release(&opts->git_format_patch_opt);
+}
+
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
{
struct replay_opts replay = REPLAY_OPTS_INIT;
@@ -179,6 +187,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.committer_date_is_author_date =
opts->committer_date_is_author_date;
replay.ignore_date = opts->ignore_date;
+ free(replay.gpg_sign);
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.reflog_action = xstrdup(opts->reflog_action);
if (opts->strategy)
@@ -199,7 +208,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
return replay;
}
-static int edit_todo_file(unsigned flags)
+static int edit_todo_file(unsigned flags, struct replay_opts *opts)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT,
@@ -209,8 +218,9 @@ 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, comment_line_char);
- res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
+ strbuf_stripspace(&todo_list.buf, comment_line_str);
+ res = edit_todo_list(the_repository, opts, &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)))
res = error_errno(_("could not write '%s'"), todo_file);
@@ -257,7 +267,7 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,
if (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir()))
return error_errno(_("could not create temporary %s"), merge_dir());
- delete_reflog("REBASE_HEAD");
+ refs_delete_reflog(get_main_ref_store(the_repository), "REBASE_HEAD");
interactive = fopen(path_interactive(), "w");
if (!interactive)
@@ -300,9 +310,9 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
if (ret)
error(_("could not generate todo list"));
else {
- discard_index(&the_index);
- if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,
- &todo_list))
+ discard_index(the_repository->index);
+ if (todo_list_parse_insn_buffer(the_repository, &replay,
+ todo_list.buf.buf, &todo_list))
BUG("unusable todo list");
ret = complete_action(the_repository, &replay, flags,
@@ -357,9 +367,13 @@ static int run_sequencer_rebase(struct rebase_options *opts)
replay_opts_release(&replay_opts);
break;
}
- case ACTION_EDIT_TODO:
- ret = edit_todo_file(flags);
+ case ACTION_EDIT_TODO: {
+ struct replay_opts replay_opts = get_replay_opts(opts);
+
+ ret = edit_todo_file(flags, &replay_opts);
+ replay_opts_release(&replay_opts);
break;
+ }
case ACTION_SHOW_CURRENT_PATCH: {
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -376,20 +390,6 @@ static int run_sequencer_rebase(struct rebase_options *opts)
return ret;
}
-static void imply_merge(struct rebase_options *opts, const char *option);
-static int parse_opt_keep_empty(const struct option *opt, const char *arg,
- int unset)
-{
- struct rebase_options *opts = opt->value;
-
- BUG_ON_OPT_ARG(arg);
-
- imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
- opts->keep_empty = !unset;
- opts->type = REBASE_MERGE;
- return 0;
-}
-
static int is_merge(struct rebase_options *opts)
{
return opts->type == REBASE_MERGE;
@@ -528,13 +528,32 @@ static int rebase_write_basic_state(struct rebase_options *opts)
return 0;
}
+static int cleanup_autostash(struct rebase_options *opts)
+{
+ int ret;
+ struct strbuf dir = STRBUF_INIT;
+ const char *path = state_dir_path("autostash", opts);
+
+ if (!file_exists(path))
+ return 0;
+ ret = apply_autostash(path);
+ strbuf_addstr(&dir, opts->state_dir);
+ if (remove_dir_recursively(&dir, 0))
+ ret = error_errno(_("could not remove '%s'"), opts->state_dir);
+ strbuf_release(&dir);
+
+ return ret;
+}
+
static int finish_rebase(struct rebase_options *opts)
{
struct strbuf dir = STRBUF_INIT;
int ret = 0;
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
- unlink(git_path_auto_merge(the_repository));
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "AUTO_MERGE", NULL, REF_NO_DEREF);
apply_autostash(state_dir_path("autostash", opts));
/*
* We ignore errors in 'git maintenance run --auto', since the
@@ -586,18 +605,10 @@ static int move_to_original_branch(struct rebase_options *opts)
return ret;
}
-static const char *resolvemsg =
-N_("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\".");
-
static int run_am(struct rebase_options *opts)
{
struct child_process am = CHILD_PROCESS_INIT;
struct child_process format_patch = CHILD_PROCESS_INIT;
- struct strbuf revisions = STRBUF_INIT;
int status;
char *rebased_patches;
@@ -607,7 +618,7 @@ static int run_am(struct rebase_options *opts)
opts->reflog_action);
if (opts->action == ACTION_CONTINUE) {
strvec_push(&am.args, "--resolved");
- strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+ strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
if (opts->gpg_sign_opt)
strvec_push(&am.args, opts->gpg_sign_opt);
status = run_command(&am);
@@ -618,7 +629,7 @@ static int run_am(struct rebase_options *opts)
}
if (opts->action == ACTION_SKIP) {
strvec_push(&am.args, "--skip");
- strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+ strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
status = run_command(&am);
if (status)
return status;
@@ -630,13 +641,6 @@ static int run_am(struct rebase_options *opts)
return run_command(&am);
}
- strbuf_addf(&revisions, "%s...%s",
- oid_to_hex(opts->root ?
- /* this is now equivalent to !opts->upstream */
- &opts->onto->object.oid :
- &opts->upstream->object.oid),
- oid_to_hex(&opts->orig_head->object.oid));
-
rebased_patches = xstrdup(git_path("rebased-patches"));
format_patch.out = open(rebased_patches,
O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -644,7 +648,7 @@ static int run_am(struct rebase_options *opts)
status = error_errno(_("could not open '%s' for writing"),
rebased_patches);
free(rebased_patches);
- strvec_clear(&am.args);
+ child_process_clear(&am);
return status;
}
@@ -657,7 +661,12 @@ static int run_am(struct rebase_options *opts)
if (opts->git_format_patch_opt.len)
strvec_split(&format_patch.args,
opts->git_format_patch_opt.buf);
- strvec_push(&format_patch.args, revisions.buf);
+ strvec_pushf(&format_patch.args, "%s...%s",
+ oid_to_hex(opts->root ?
+ /* this is now equivalent to !opts->upstream */
+ &opts->onto->object.oid :
+ &opts->upstream->object.oid),
+ oid_to_hex(&opts->orig_head->object.oid));
if (opts->restrict_revision)
strvec_pushf(&format_patch.args, "^%s",
oid_to_hex(&opts->restrict_revision->object.oid));
@@ -667,7 +676,7 @@ static int run_am(struct rebase_options *opts)
struct reset_head_opts ropts = { 0 };
unlink(rebased_patches);
free(rebased_patches);
- strvec_clear(&am.args);
+ child_process_clear(&am);
ropts.oid = &opts->orig_head->object.oid;
ropts.branch = opts->head_name;
@@ -680,23 +689,21 @@ static int run_am(struct rebase_options *opts)
"As a result, git cannot rebase them."),
opts->revisions);
- strbuf_release(&revisions);
return status;
}
- strbuf_release(&revisions);
am.in = open(rebased_patches, O_RDONLY);
if (am.in < 0) {
status = error_errno(_("could not open '%s' for reading"),
rebased_patches);
free(rebased_patches);
- strvec_clear(&am.args);
+ child_process_clear(&am);
return status;
}
strvec_pushv(&am.args, opts->git_am_opts.v);
strvec_push(&am.args, "--rebasing");
- strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+ strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
strvec_push(&am.args, "--patch-format=mboxrd");
if (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)
strvec_push(&am.args, "--rerere-autoupdate");
@@ -724,11 +731,8 @@ static int run_specific_rebase(struct rebase_options *opts)
if (opts->type == REBASE_MERGE) {
/* Run sequencer-based rebase */
- setenv("GIT_CHERRY_PICK_HELP", resolvemsg, 1);
- if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
+ if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))
setenv("GIT_SEQUENCE_EDITOR", ":", 1);
- opts->autosquash = 0;
- }
if (opts->gpg_sign_opt) {
/* remove the leading "-S" */
char *tmp = xstrdup(opts->gpg_sign_opt + 2);
@@ -829,6 +833,7 @@ static int rebase_config(const char *var, const char *value,
}
if (!strcmp(var, "rebase.backend")) {
+ FREE_AND_NULL(opts->default_backend);
return git_config_string(&opts->default_backend, var, value);
}
@@ -893,7 +898,8 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
if (!upstream)
goto done;
- merge_bases = repo_get_merge_bases(the_repository, upstream, head);
+ if (repo_get_merge_bases(the_repository, upstream, head, &merge_bases) < 0)
+ exit(128);
if (!merge_bases || merge_bases->next)
goto done;
@@ -912,8 +918,9 @@ static void fill_branch_base(struct rebase_options *options,
{
struct commit_list *merge_bases = NULL;
- merge_bases = repo_get_merge_bases(the_repository, options->onto,
- options->orig_head);
+ if (repo_get_merge_bases(the_repository, options->onto,
+ options->orig_head, &merge_bases) < 0)
+ exit(128);
if (!merge_bases || merge_bases->next)
oidcpy(branch_base, null_oid());
else
@@ -977,10 +984,26 @@ static enum empty_type parse_empty_value(const char *value)
return EMPTY_DROP;
else if (!strcasecmp(value, "keep"))
return EMPTY_KEEP;
- else if (!strcasecmp(value, "ask"))
- return EMPTY_ASK;
+ else if (!strcasecmp(value, "stop"))
+ return EMPTY_STOP;
+ else if (!strcasecmp(value, "ask")) {
+ warning(_("--empty=ask is deprecated; use '--empty=stop' instead."));
+ return EMPTY_STOP;
+ }
- die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), value);
+ die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"stop\"."), value);
+}
+
+static int parse_opt_keep_empty(const struct option *opt, const char *arg,
+ int unset)
+{
+ struct rebase_options *opts = opt->value;
+
+ BUG_ON_OPT_ARG(arg);
+
+ imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
+ opts->keep_empty = !unset;
+ return 0;
}
static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
@@ -1058,10 +1081,14 @@ static int check_exec_cmd(const char *cmd)
return 0;
}
-int cmd_rebase(int argc, const char **argv, const char *prefix)
+int cmd_rebase(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rebase_options options = REBASE_OPTIONS_INIT;
const char *branch_name;
+ const char *strategy_opt = NULL;
int ret, flags, total_argc, in_progress = 0;
int keep_base = 0;
int ok_to_skip_pre_rebase = 0;
@@ -1147,7 +1174,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"instead of ignoring them"),
1, PARSE_OPT_HIDDEN),
OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
- OPT_CALLBACK_F(0, "empty", &options, "{drop,keep,ask}",
+ OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|stop)",
N_("how to handle commits that become empty"),
PARSE_OPT_NONEG, parse_opt_empty),
OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
@@ -1176,7 +1203,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
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,
+ OPT_STRING('s', "strategy", &strategy_opt,
N_("strategy"), N_("use the given merge strategy")),
OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
N_("option"),
@@ -1268,7 +1295,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
if (options.action != ACTION_NONE && !in_progress)
- die(_("No rebase in progress?"));
+ die(_("no rebase in progress"));
if (options.action == ACTION_EDIT_TODO && !is_merge(&options))
die(_("The --edit-todo action can only be used during "
@@ -1407,7 +1434,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
(options.action != ACTION_NONE) ||
(options.exec.nr > 0) ||
- (options.autosquash == -1 && options.config_autosquash == 1) ||
options.autosquash == 1) {
allow_preemptive_ff = 0;
}
@@ -1486,27 +1512,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
}
- if (options.strategy_opts.nr && !options.strategy)
- options.strategy = "ort";
-
- if (options.strategy) {
- options.strategy = xstrdup(options.strategy);
- switch (options.type) {
- case REBASE_APPLY:
- die(_("--strategy requires --merge or --interactive"));
- case REBASE_MERGE:
- /* compatible */
- break;
- case REBASE_UNSPECIFIED:
- options.type = REBASE_MERGE;
- break;
- default:
- BUG("unhandled rebase type (%d)", options.type);
- }
- }
-
- if (options.type == REBASE_MERGE)
- imply_merge(&options, "--merge");
+ if (strategy_opt)
+ options.strategy = xstrdup(strategy_opt);
+ else if (options.strategy_opts.nr && !options.strategy)
+ options.strategy = xstrdup("ort");
+ if (options.strategy)
+ imply_merge(&options, "--strategy");
if (options.root && !options.onto_name)
imply_merge(&options, "--root without --onto");
@@ -1524,8 +1535,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (is_merge(&options))
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"));
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)
@@ -1545,14 +1554,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
- if (options.autosquash == 1)
+ if (options.autosquash == 1) {
imply_merge(&options, "--autosquash");
- options.autosquash = (options.autosquash >= 0) ? options.autosquash :
- ((options.config_autosquash >= 0) ? options.config_autosquash : 0);
+ } else if (options.autosquash == -1) {
+ options.autosquash =
+ options.config_autosquash &&
+ (options.flags & REBASE_INTERACTIVE_EXPLICIT);
+ }
if (options.type == REBASE_UNSPECIFIED) {
if (!strcmp(options.default_backend, "merge"))
- imply_merge(&options, "--merge");
+ options.type = REBASE_MERGE;
else if (!strcmp(options.default_backend, "apply"))
options.type = REBASE_APPLY;
else
@@ -1578,7 +1590,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty == EMPTY_UNSPECIFIED) {
if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
- options.empty = EMPTY_ASK;
+ options.empty = EMPTY_STOP;
else if (options.exec.nr > 0)
options.empty = EMPTY_KEEP;
else
@@ -1653,7 +1665,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* Is it a local branch? */
strbuf_reset(&buf);
strbuf_addf(&buf, "refs/heads/%s", branch_name);
- if (!read_ref(buf.buf, &branch_oid)) {
+ if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) {
die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf);
options.orig_head =
@@ -1670,8 +1682,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else if (argc == 0) {
/* Do not need to switch branches, we are already on it. */
options.head_name =
- xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL,
- &flags));
+ xstrdup_or_null(refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL,
+ &flags));
if (!options.head_name)
die(_("No such ref: %s"), "HEAD");
if (flags & REF_ISSYMREF) {
@@ -1736,7 +1748,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (require_clean_work_tree(the_repository, "rebase",
_("Please commit or stash them."), 1, 1)) {
ret = -1;
- goto cleanup;
+ goto cleanup_autostash;
}
/*
@@ -1759,13 +1771,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.switch_to) {
ret = checkout_up_to_date(&options);
if (ret)
- goto cleanup;
+ goto cleanup_autostash;
}
if (!(options.flags & REBASE_NO_QUIET))
; /* be quiet */
else if (!strcmp(branch_name, "HEAD") &&
- resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+ refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag))
puts(_("HEAD is up to date."));
else
printf(_("Current branch %s is up to date.\n"),
@@ -1775,7 +1787,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else if (!(options.flags & REBASE_NO_QUIET))
; /* be quiet */
else if (!strcmp(branch_name, "HEAD") &&
- resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+ refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag))
puts(_("HEAD is up to date, rebase forced."));
else
printf(_("Current branch %s is up to date, rebase "
@@ -1784,9 +1796,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* If a hook exists, give it a chance to interrupt*/
if (!ok_to_skip_pre_rebase &&
- run_hooks_l("pre-rebase", options.upstream_arg,
- argc ? argv[0] : NULL, NULL))
- die(_("The pre-rebase hook refused to rebase."));
+ run_hooks_l(the_repository, "pre-rebase", options.upstream_arg,
+ argc ? argv[0] : NULL, NULL)) {
+ ret = error(_("The pre-rebase hook refused to rebase."));
+ goto cleanup_autostash;
+ }
if (options.flags & REBASE_DIFFSTAT) {
struct diff_options opts;
@@ -1803,8 +1817,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* We want color (if set), but no pager */
repo_diff_setup(the_repository, &opts);
- opts.stat_width = -1; /* use full terminal width */
- opts.stat_graph_width = -1; /* respect statGraphWidth config */
+ init_diffstat_widths(&opts);
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
@@ -1832,9 +1845,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
ropts.head_msg = msg.buf;
ropts.default_reflog_action = options.reflog_action;
- if (reset_head(the_repository, &ropts))
- die(_("Could not detach HEAD"));
- strbuf_release(&msg);
+ if (reset_head(the_repository, &ropts)) {
+ ret = error(_("Could not detach HEAD"));
+ goto cleanup_autostash;
+ }
/*
* If the onto is a proper descendant of the tip of the branch, then
@@ -1862,16 +1876,14 @@ run_rebase:
cleanup:
strbuf_release(&buf);
+ strbuf_release(&msg);
strbuf_release(&revisions);
- free(options.reflog_action);
- free(options.head_name);
- strvec_clear(&options.git_am_opts);
- free(options.gpg_sign_opt);
- string_list_clear(&options.exec, 0);
- free(options.strategy);
- string_list_clear(&options.strategy_opts, 0);
- strbuf_release(&options.git_format_patch_opt);
+ rebase_options_release(&options);
free(squash_onto_name);
free(keep_base_onto_name);
return !!ret;
+
+cleanup_autostash:
+ ret |= !!cleanup_autostash(&options);
+ goto cleanup;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 8c4f0cb90a..9d2c07f68d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1,6 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
-#include "repository.h"
+
#include "config.h"
#include "environment.h"
#include "gettext.h"
@@ -22,7 +23,6 @@
#include "connected.h"
#include "strvec.h"
#include "version.h"
-#include "tag.h"
#include "gpg-interface.h"
#include "sigchain.h"
#include "fsck.h"
@@ -89,7 +89,7 @@ static struct strbuf push_cert = STRBUF_INIT;
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 char *cert_nonce_seed;
static struct strvec hidden_refs = STRVEC_INIT;
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
@@ -142,6 +142,7 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
static int receive_pack_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ const char *msg_id;
int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
if (status)
@@ -168,22 +169,24 @@ static int receive_pack_config(const char *var, const char *value,
}
if (strcmp(var, "receive.fsck.skiplist") == 0) {
- const char *path;
+ char *path;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
fsck_msg_types.len ? ',' : '=', path);
- free((char *)path);
+ free(path);
return 0;
}
- if (skip_prefix(var, "receive.fsck.", &var)) {
- if (is_valid_msg_type(var, value))
+ if (skip_prefix(var, "receive.fsck.", &msg_id)) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (is_valid_msg_type(msg_id, value))
strbuf_addf(&fsck_msg_types, "%c%s=%s",
- fsck_msg_types.len ? ',' : '=', var, value);
+ fsck_msg_types.len ? ',' : '=', msg_id, value);
else
- warning("skipping unknown msg id '%s'", var);
+ warning("skipping unknown msg id '%s'", msg_id);
return 0;
}
@@ -298,7 +301,7 @@ static void show_ref(const char *path, const struct object_id *oid)
}
}
-static int show_ref_cb(const char *path_full, const struct object_id *oid,
+static int show_ref_cb(const char *path_full, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *data)
{
struct oidset *seen = data;
@@ -337,12 +340,26 @@ static void show_one_alternate_ref(const struct object_id *oid,
static void write_head_info(void)
{
static struct oidset seen = OIDSET_INIT;
+ struct strvec excludes_vector = STRVEC_INIT;
+ const char **exclude_patterns;
+
+ /*
+ * We need access to the reference names both with and without their
+ * namespace and thus cannot use `refs_for_each_namespaced_ref()`. We
+ * thus have to adapt exclude patterns to carry the namespace prefix
+ * ourselves.
+ */
+ exclude_patterns = get_namespaced_exclude_patterns(
+ hidden_refs_to_excludes(&hidden_refs),
+ get_git_namespace(), &excludes_vector);
refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
- hidden_refs_to_excludes(&hidden_refs),
- show_ref_cb, &seen);
+ exclude_patterns, show_ref_cb, &seen);
for_each_alternate_ref(show_one_alternate_ref, &seen);
+
oidset_clear(&seen);
+ strvec_clear(&excludes_vector);
+
if (!sent_capabilities)
show_ref("capabilities^{}", null_oid());
@@ -357,6 +374,7 @@ static void write_head_info(void)
struct command {
struct command *next;
const char *error_string;
+ char *error_string_owned;
struct ref_push_report *report;
unsigned int skip_update:1,
did_not_exist:1,
@@ -591,21 +609,6 @@ static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
return strbuf_detach(&buf, NULL);
}
-static char *find_header(const char *msg, size_t len, const char *key,
- const char **next_line)
-{
- size_t out_len;
- const char *val = find_header_mem(msg, len, key, &out_len);
-
- if (!val)
- return NULL;
-
- if (next_line)
- *next_line = val + out_len + 1;
-
- return xmemdupz(val, out_len);
-}
-
/*
* Return zero if a and b are equal up to n bytes and nonzero if they are not.
* This operation is guaranteed to run in constant time to avoid leaking data.
@@ -620,13 +623,14 @@ static int constant_memequal(const char *a, const char *b, size_t n)
return res;
}
-static const char *check_nonce(const char *buf, size_t len)
+static const char *check_nonce(const char *buf)
{
- char *nonce = find_header(buf, len, "nonce", NULL);
+ size_t noncelen;
+ const char *found = find_commit_header(buf, "nonce", &noncelen);
+ char *nonce = found ? xmemdupz(found, noncelen) : NULL;
timestamp_t stamp, ostamp;
char *bohmac, *expect = NULL;
const char *retval = NONCE_BAD;
- size_t noncelen;
if (!nonce) {
retval = NONCE_MISSING;
@@ -668,7 +672,6 @@ static const char *check_nonce(const char *buf, size_t len)
goto leave;
}
- noncelen = strlen(nonce);
expect = prepare_push_cert_nonce(service_dir, stamp);
if (noncelen != strlen(expect)) {
/* This is not even the right size. */
@@ -716,35 +719,28 @@ leave:
static int check_cert_push_options(const struct string_list *push_options)
{
const char *buf = push_cert.buf;
- int len = push_cert.len;
- char *option;
- const char *next_line;
+ const char *option;
+ size_t optionlen;
int options_seen = 0;
int retval = 1;
- if (!len)
+ if (!*buf)
return 1;
- while ((option = find_header(buf, len, "push-option", &next_line))) {
- len -= (next_line - buf);
- buf = next_line;
+ while ((option = find_commit_header(buf, "push-option", &optionlen))) {
+ buf = option + optionlen + 1;
options_seen++;
if (options_seen > push_options->nr
- || strcmp(option,
- push_options->items[options_seen - 1].string)) {
- retval = 0;
- goto leave;
- }
- free(option);
+ || xstrncmpz(push_options->items[options_seen - 1].string,
+ option, optionlen))
+ return 0;
}
if (options_seen != push_options->nr)
retval = 0;
-leave:
- free(option);
return retval;
}
@@ -761,7 +757,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
already_done = 1;
if (write_object_file(push_cert.buf, push_cert.len, OBJ_BLOB,
&push_cert_oid))
- oidclr(&push_cert_oid);
+ oidclr(&push_cert_oid, the_repository->hash_algo);
memset(&sigcheck, '\0', sizeof(sigcheck));
@@ -771,7 +767,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
check_signature(&sigcheck, push_cert.buf + bogs,
push_cert.len - bogs);
- nonce_status = check_nonce(push_cert.buf, bogs);
+ nonce_status = check_nonce(sigcheck.payload);
}
if (!is_null_oid(&push_cert_oid)) {
strvec_pushf(&proc->env, "GIT_PUSH_CERT=%s",
@@ -812,7 +808,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
struct child_process proc = CHILD_PROCESS_INIT;
struct async muxer;
int code;
- const char *hook_path = find_hook(hook_name);
+ const char *hook_path = find_hook(the_repository, hook_name);
if (!hook_path)
return 0;
@@ -942,7 +938,7 @@ static int run_update_hook(struct command *cmd)
{
struct child_process proc = CHILD_PROCESS_INIT;
int code;
- const char *hook_path = find_hook("update");
+ const char *hook_path = find_hook(the_repository, "update");
if (!hook_path)
return 0;
@@ -1088,7 +1084,7 @@ static int read_proc_receive_report(struct packet_reader *reader,
hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
if (!strcmp(head, "ng")) {
if (p)
- hint->error_string = xstrdup(p);
+ hint->error_string = hint->error_string_owned = xstrdup(p);
else
hint->error_string = "failed";
code = -1;
@@ -1118,7 +1114,7 @@ static int run_proc_receive_hook(struct command *commands,
int hook_use_push_options = 0;
int version = 0;
int code;
- const char *hook_path = find_hook("proc-receive");
+ const char *hook_path = find_hook(the_repository, "proc-receive");
if (!hook_path) {
rp_error("cannot find hook 'proc-receive'");
@@ -1269,7 +1265,7 @@ cleanup:
return code;
}
-static char *refuse_unconfigured_deny_msg =
+static const char *refuse_unconfigured_deny_msg =
N_("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"
@@ -1289,7 +1285,7 @@ static void refuse_unconfigured_deny(void)
rp_error("%s", _(refuse_unconfigured_deny_msg));
}
-static char *refuse_unconfigured_deny_delete_current_msg =
+static const char *refuse_unconfigured_deny_delete_current_msg =
N_("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"
@@ -1344,7 +1340,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
}
/*
- * NEEDSWORK: we should consolidate various implementions of "are we
+ * NEEDSWORK: we should consolidate various implementations of "are we
* on an unborn branch?" test into one, and make the unified one more
* robust. !get_sha1() based check used here and elsewhere would not
* allow us to tell an unborn branch from corrupt ref, for example.
@@ -1391,7 +1387,7 @@ static const char *push_to_deploy(unsigned char *sha1,
strvec_pushl(&child.args, "diff-index", "--quiet", "--cached",
"--ignore-submodules",
/* diff-index with either HEAD or an empty tree */
- head_has_history() ? "HEAD" : empty_tree_oid_hex(),
+ head_has_history() ? "HEAD" : empty_tree_oid_hex(the_repository->hash_algo),
"--", NULL);
strvec_pushv(&child.env, env->v);
child.no_stdin = 1;
@@ -1429,7 +1425,7 @@ static const char *push_to_checkout(unsigned char *hash,
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
strvec_pushv(&opt.env, env->v);
strvec_push(&opt.args, hash_to_hex(hash));
- if (run_hooks_opt(push_to_checkout_hook, &opt))
+ if (run_hooks_opt(the_repository, push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
@@ -1546,6 +1542,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
starts_with(name, "refs/heads/")) {
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
+ int ret2;
old_object = parse_object(the_repository, old_oid);
new_object = parse_object(the_repository, new_oid);
@@ -1559,7 +1556,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
old_commit = (struct commit *)old_object;
new_commit = (struct commit *)new_object;
- if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
+ ret2 = repo_in_merge_bases(the_repository, old_commit, new_commit);
+ if (ret2 < 0)
+ exit(128);
+ if (!ret2) {
rp_error("denying non-fast-forward %s"
" (you should pull first)", name);
ret = "non-fast-forward";
@@ -1582,7 +1582,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct strbuf err = STRBUF_INIT;
if (!parse_object(the_repository, old_oid)) {
old_oid = NULL;
- if (ref_exists(name)) {
+ if (refs_ref_exists(get_main_ref_store(the_repository), name)) {
rp_warning("allowing deletion of corrupt ref");
} else {
rp_warning("deleting a non-existent ref");
@@ -1592,7 +1592,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (ref_transaction_delete(transaction,
namespaced_name,
old_oid,
- 0, "push", &err)) {
+ NULL, 0,
+ "push", &err)) {
rp_error("%s", err.buf);
ret = "failed to delete";
} else {
@@ -1611,6 +1612,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (ref_transaction_update(transaction,
namespaced_name,
new_oid, old_oid,
+ NULL, NULL,
0, "push",
&err)) {
rp_error("%s", err.buf);
@@ -1632,7 +1634,7 @@ static void run_update_post_hook(struct command *commands)
struct child_process proc = CHILD_PROCESS_INIT;
const char *hook;
- hook = find_hook("post-update");
+ hook = find_hook(the_repository, "post-update");
if (!hook)
return;
@@ -1709,7 +1711,8 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
int flag;
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
- dst_name = resolve_ref_unsafe(buf.buf, 0, NULL, &flag);
+ dst_name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ buf.buf, 0, NULL, &flag);
check_aliased_update_internal(cmd, list, dst_name, flag);
strbuf_release(&buf);
}
@@ -1845,7 +1848,8 @@ static void execute_commands_non_atomic(struct command *commands,
if (!should_process_cmd(cmd) || cmd->run_proc_receive)
continue;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction) {
rp_error("%s", err.buf);
strbuf_reset(&err);
@@ -1873,7 +1877,8 @@ static void execute_commands_atomic(struct command *commands,
struct strbuf err = STRBUF_INIT;
const char *reported_error = "atomic push failure";
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction) {
rp_error("%s", err.buf);
strbuf_reset(&err);
@@ -1999,7 +2004,9 @@ static void execute_commands(struct command *commands,
check_aliased_updates(commands);
free(head_name_to_free);
- head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
+ head_name = head_name_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL,
+ NULL);
if (run_proc_receive &&
run_proc_receive_hook(commands, push_options))
@@ -2048,6 +2055,8 @@ static void free_commands(struct command *commands)
while (commands) {
struct command *next = commands->next;
+ ref_push_report_free(commands->report);
+ free(commands->error_string_owned);
free(commands);
commands = next;
}
@@ -2489,7 +2498,10 @@ static int delete_only(struct command *commands)
return 1;
}
-int cmd_receive_pack(int argc, const char **argv, const char *prefix)
+int cmd_receive_pack(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int advertise_refs = 0;
struct command *commands;
@@ -2601,17 +2613,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (auto_gc) {
struct child_process proc = CHILD_PROCESS_INIT;
- proc.no_stdin = 1;
- proc.stdout_to_stderr = 1;
- proc.err = use_sideband ? -1 : 0;
- proc.git_cmd = proc.close_object_store = 1;
- strvec_pushl(&proc.args, "gc", "--auto", "--quiet",
- NULL);
-
- if (!start_command(&proc)) {
- if (use_sideband)
- copy_to_sideband(proc.err, -1, NULL);
- finish_command(&proc);
+ if (prepare_auto_maintenance(1, &proc)) {
+ proc.no_stdin = 1;
+ proc.stdout_to_stderr = 1;
+ proc.err = use_sideband ? -1 : 0;
+
+ if (!start_command(&proc)) {
+ if (use_sideband)
+ copy_to_sideband(proc.err, -1, NULL);
+ finish_command(&proc);
+ }
}
}
if (auto_update_server_info)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index df63a5892e..22df6834f7 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,17 +1,21 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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 "refs.h"
#include "parse-options.h"
#define BUILTIN_REFLOG_SHOW_USAGE \
N_("git reflog [show] [<log-options>] [<ref>]")
+#define BUILTIN_REFLOG_LIST_USAGE \
+ N_("git reflog list")
+
#define BUILTIN_REFLOG_EXPIRE_USAGE \
N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
" [--rewrite] [--updateref] [--stale-fix]\n" \
@@ -29,6 +33,11 @@ static const char *const reflog_show_usage[] = {
NULL,
};
+static const char *const reflog_list_usage[] = {
+ BUILTIN_REFLOG_LIST_USAGE,
+ NULL,
+};
+
static const char *const reflog_expire_usage[] = {
BUILTIN_REFLOG_EXPIRE_USAGE,
NULL
@@ -46,6 +55,7 @@ static const char *const reflog_exists_usage[] = {
static const char *const reflog_usage[] = {
BUILTIN_REFLOG_SHOW_USAGE,
+ BUILTIN_REFLOG_LIST_USAGE,
BUILTIN_REFLOG_EXPIRE_USAGE,
BUILTIN_REFLOG_DELETE_USAGE,
BUILTIN_REFLOG_EXISTS_USAGE,
@@ -60,8 +70,7 @@ struct worktree_reflogs {
struct string_list reflogs;
};
-static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
- int flags UNUSED, void *cb_data)
+static int collect_reflog(const char *ref, void *cb_data)
{
struct worktree_reflogs *cb = cb_data;
struct worktree *worktree = cb->worktree;
@@ -96,8 +105,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
reflog_expire_cfg_tail = &reflog_expire_cfg;
for (ent = reflog_expire_cfg; ent; ent = ent->next)
- if (!strncmp(ent->pattern, pattern, len) &&
- ent->pattern[len] == '\0')
+ if (!xstrncmpz(ent->pattern, pattern, len))
return ent;
FLEX_ALLOC_MEM(ent, pattern, pattern, len);
@@ -236,19 +244,42 @@ static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
PARSE_OPT_KEEP_UNKNOWN_OPT);
- return cmd_log_reflog(argc, argv, prefix);
+ return cmd_log_reflog(argc, argv, prefix, the_repository);
+}
+
+static int show_reflog(const char *refname, void *cb_data UNUSED)
+{
+ printf("%s\n", refname);
+ return 0;
+}
+
+static int cmd_reflog_list(int argc, const char **argv, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ struct ref_store *ref_store;
+
+ argc = parse_options(argc, argv, prefix, options, reflog_list_usage, 0);
+ if (argc)
+ return error(_("%s does not accept arguments: '%s'"),
+ "list", argv[0]);
+
+ ref_store = get_main_ref_store(the_repository);
+
+ return refs_for_each_reflog(ref_store, show_reflog, NULL);
}
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
{
struct cmd_reflog_expire_cb cmd = { 0 };
timestamp_t now = time(NULL);
- int i, status, do_all, all_worktrees = 1;
+ int i, status, do_all, single_worktree = 0;
unsigned int flags = 0;
int verbose = 0;
reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
const struct option options[] = {
- OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
OPT_BIT(0, "rewrite", &flags,
N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
@@ -268,7 +299,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stale-fix", &cmd.stalefix,
N_("prune any reflog entries that point to broken commits")),
OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
- OPT_BOOL(1, "single-worktree", &all_worktrees,
+ OPT_BOOL(0, "single-worktree", &single_worktree,
N_("limits processing to reflogs from the current worktree only")),
OPT_END()
};
@@ -298,7 +329,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
struct rev_info revs;
repo_init_revisions(the_repository, &revs, prefix);
- revs.do_not_die_on_missing_tree = 1;
+ revs.do_not_die_on_missing_objects = 1;
revs.ignore_missing = 1;
revs.ignore_missing_links = 1;
if (verbose)
@@ -318,7 +349,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
- if (!all_worktrees && !(*p)->is_current)
+ if (single_worktree && !(*p)->is_current)
continue;
collected.worktree = *p;
refs_for_each_reflog(get_worktree_ref_store(*p),
@@ -333,11 +364,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
};
set_reflog_expiry_param(&cb.cmd, item->string);
- status |= reflog_expire(item->string, flags,
- reflog_expiry_prepare,
- should_prune_fn,
- reflog_expiry_cleanup,
- &cb);
+ status |= refs_reflog_expire(get_main_ref_store(the_repository),
+ item->string, flags,
+ reflog_expiry_prepare,
+ should_prune_fn,
+ reflog_expiry_cleanup,
+ &cb);
}
string_list_clear(&collected.reflogs, 0);
}
@@ -346,16 +378,17 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
char *ref;
struct expire_reflog_policy_cb cb = { .cmd = cmd };
- if (!dwim_log(argv[i], strlen(argv[i]), NULL, &ref)) {
+ if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
status |= error(_("%s points nowhere!"), argv[i]);
continue;
}
set_reflog_expiry_param(&cb.cmd, ref);
- status |= reflog_expire(ref, flags,
- reflog_expiry_prepare,
- should_prune_fn,
- reflog_expiry_cleanup,
- &cb);
+ status |= refs_reflog_expire(get_main_ref_store(the_repository),
+ ref, flags,
+ reflog_expiry_prepare,
+ should_prune_fn,
+ reflog_expiry_cleanup,
+ &cb);
free(ref);
}
return status;
@@ -368,7 +401,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
int verbose = 0;
const struct option options[] = {
- OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
OPT_BIT(0, "rewrite", &flags,
N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
@@ -406,18 +439,23 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
refname = argv[0];
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
die(_("invalid ref format: %s"), refname);
- return !reflog_exists(refname);
+ return !refs_reflog_exists(get_main_ref_store(the_repository),
+ refname);
}
/*
* main "reflog"
*/
-int cmd_reflog(int argc, const char **argv, const char *prefix)
+int cmd_reflog(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repository)
{
parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
+ OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
@@ -431,5 +469,5 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
if (fn)
return fn(argc - 1, argv + 1, prefix);
else
- return cmd_log_reflog(argc, argv, prefix);
+ return cmd_log_reflog(argc, argv, prefix, repository);
}
diff --git a/builtin/refs.c b/builtin/refs.c
new file mode 100644
index 0000000000..394b4101c6
--- /dev/null
+++ b/builtin/refs.c
@@ -0,0 +1,118 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "fsck.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "strbuf.h"
+#include "worktree.h"
+
+#define REFS_MIGRATE_USAGE \
+ N_("git refs migrate --ref-format=<format> [--dry-run]")
+
+#define REFS_VERIFY_USAGE \
+ N_("git refs verify [--strict] [--verbose]")
+
+static int cmd_refs_migrate(int argc, const char **argv, const char *prefix)
+{
+ const char * const migrate_usage[] = {
+ REFS_MIGRATE_USAGE,
+ NULL,
+ };
+ const char *format_str = NULL;
+ enum ref_storage_format format;
+ unsigned int flags = 0;
+ struct option options[] = {
+ OPT_STRING_F(0, "ref-format", &format_str, N_("format"),
+ N_("specify the reference format to convert to"),
+ PARSE_OPT_NONEG),
+ OPT_BIT(0, "dry-run", &flags,
+ N_("perform a non-destructive dry-run"),
+ REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN),
+ OPT_END(),
+ };
+ struct strbuf errbuf = STRBUF_INIT;
+ int err;
+
+ argc = parse_options(argc, argv, prefix, options, migrate_usage, 0);
+ if (argc)
+ usage(_("too many arguments"));
+ if (!format_str)
+ usage(_("missing --ref-format=<format>"));
+
+ format = ref_storage_format_by_name(format_str);
+ if (format == REF_STORAGE_FORMAT_UNKNOWN) {
+ err = error(_("unknown ref storage format '%s'"), format_str);
+ goto out;
+ }
+
+ if (the_repository->ref_storage_format == format) {
+ err = error(_("repository already uses '%s' format"),
+ ref_storage_format_to_name(format));
+ goto out;
+ }
+
+ if (repo_migrate_ref_storage_format(the_repository, format, flags, &errbuf) < 0) {
+ err = error("%s", errbuf.buf);
+ goto out;
+ }
+
+ err = 0;
+
+out:
+ strbuf_release(&errbuf);
+ return err;
+}
+
+static int cmd_refs_verify(int argc, const char **argv, const char *prefix)
+{
+ struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
+ struct worktree **worktrees;
+ const char * const verify_usage[] = {
+ REFS_VERIFY_USAGE,
+ NULL,
+ };
+ struct option options[] = {
+ OPT_BOOL(0, "verbose", &fsck_refs_options.verbose, N_("be verbose")),
+ OPT_BOOL(0, "strict", &fsck_refs_options.strict, N_("enable strict checking")),
+ OPT_END(),
+ };
+ int ret = 0;
+
+ argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
+ if (argc)
+ usage(_("'git refs verify' takes no arguments"));
+
+ git_config(git_fsck_config, &fsck_refs_options);
+ prepare_repo_settings(the_repository);
+
+ worktrees = get_worktrees();
+ for (size_t i = 0; worktrees[i]; i++)
+ ret |= refs_fsck(get_worktree_ref_store(worktrees[i]),
+ &fsck_refs_options, worktrees[i]);
+
+ fsck_options_clear(&fsck_refs_options);
+ free_worktrees(worktrees);
+ return ret;
+}
+
+int cmd_refs(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
+{
+ const char * const refs_usage[] = {
+ REFS_MIGRATE_USAGE,
+ REFS_VERIFY_USAGE,
+ NULL,
+ };
+ parse_opt_subcommand_fn *fn = NULL;
+ struct option opts[] = {
+ OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
+ OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, opts, refs_usage, 0);
+ return fn(argc, argv, prefix);
+}
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 282782eccd..33c8ae0fc7 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -195,7 +195,10 @@ static int command_loop(const char *child)
}
}
-int cmd_remote_ext(int argc, const char **argv, const char *prefix)
+int cmd_remote_ext(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
BUG_ON_NON_EMPTY_PREFIX(prefix);
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 9020fab9c5..ae896eda57 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -53,7 +53,10 @@ static void command_loop(int input_fd, int output_fd)
}
}
-int cmd_remote_fd(int argc, const char **argv, const char *prefix)
+int cmd_remote_fd(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int input_fd = -1;
int output_fd = -1;
diff --git a/builtin/remote.c b/builtin/remote.c
index d91bbe728d..9093600965 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -150,7 +151,7 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
else if (!strcmp(arg, "push"))
*mirror = MIRROR_PUSH;
else
- return error(_("unknown mirror argument: %s"), arg);
+ return error(_("unknown --mirror argument: %s"), arg);
return 0;
}
@@ -164,6 +165,7 @@ static int add(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url;
int i;
+ int result = 0;
struct option options[] = {
OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
@@ -230,8 +232,10 @@ static int add(int argc, const char **argv, const char *prefix)
fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
}
- if (fetch && fetch_remote(name))
- return 1;
+ if (fetch && fetch_remote(name)) {
+ result = 1;
+ goto out;
+ }
if (master) {
strbuf_reset(&buf);
@@ -240,15 +244,16 @@ static int add(int argc, const char **argv, const char *prefix)
strbuf_reset(&buf2);
strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
- if (create_symref(buf.buf, buf2.buf, "remote add"))
- return error(_("Could not setup master '%s'"), master);
+ if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
+ result = error(_("Could not setup master '%s'"), master);
}
+out:
strbuf_release(&buf);
strbuf_release(&buf2);
string_list_clear(&track, 0);
- return 0;
+ return result;
}
struct branch_info {
@@ -258,7 +263,7 @@ struct branch_info {
char *push_remote_name;
};
-static struct string_list branch_list = STRING_LIST_INIT_NODUP;
+static struct string_list branch_list = STRING_LIST_INIT_DUP;
static const char *abbrev_ref(const char *name, const char *prefix)
{
@@ -292,8 +297,8 @@ static int config_read_branches(const char *key, const char *value,
type = PUSH_REMOTE;
else
return 0;
- name = xmemdupz(key, key_len);
+ name = xmemdupz(key, key_len);
item = string_list_insert(&branch_list, name);
if (!item->util)
@@ -337,6 +342,7 @@ static int config_read_branches(const char *key, const char *value,
BUG("unexpected type=%d", type);
}
+ free(name);
return 0;
}
@@ -371,12 +377,12 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
for (i = 0; i < states->remote->fetch.nr; i++)
if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
die(_("Could not get fetch map for refspec %s"),
- states->remote->fetch.raw[i]);
+ states->remote->fetch.items[i].raw);
for (ref = fetch_map; ref; ref = ref->next) {
if (omit_name_by_refspec(ref->name, &states->remote->fetch))
string_list_append(&states->skipped, abbrev_branch(ref->name));
- else if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))
+ else if (!ref->peer_ref || !refs_ref_exists(get_main_ref_store(the_repository), ref->peer_ref->name))
string_list_append(&states->new_refs, abbrev_branch(ref->name));
else
string_list_append(&states->tracked, abbrev_branch(ref->name));
@@ -493,12 +499,13 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
{
struct ref *ref, *matches;
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
- struct refspec_item refspec;
+ struct refspec_item refspec = {
+ .force = 0,
+ .pattern = 1,
+ .src = (char *) "refs/heads/*",
+ .dst = (char *) "refs/heads/*",
+ };
- memset(&refspec, 0, sizeof(refspec));
- refspec.force = 0;
- refspec.pattern = 1;
- refspec.src = refspec.dst = "refs/heads/*";
get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
fetch_map, 1);
@@ -507,7 +514,6 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
free_refs(fetch_map);
free_refs(matches);
-
return 0;
}
@@ -543,6 +549,7 @@ struct branches_for_remote {
};
static int add_branch_for_removal(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data)
{
@@ -554,13 +561,16 @@ static int add_branch_for_removal(const char *refname,
refspec.dst = (char *)refname;
if (remote_find_tracking(branches->remote, &refspec))
return 0;
+ free(refspec.src);
/* don't delete a branch if another remote also uses it */
for (kr = branches->keep->list; kr; kr = kr->next) {
memset(&refspec, 0, sizeof(refspec));
refspec.dst = (char *)refname;
- if (!remote_find_tracking(kr->remote, &refspec))
+ if (!remote_find_tracking(kr->remote, &refspec)) {
+ free(refspec.src);
return 0;
+ }
}
/* don't delete non-remote-tracking refs */
@@ -585,7 +595,7 @@ struct rename_info {
uint32_t symrefs_nr;
};
-static int read_remote_branches(const char *refname,
+static int read_remote_branches(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data)
{
@@ -598,8 +608,9 @@ static int read_remote_branches(const char *refname,
strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, refname);
- symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
- NULL, &flag);
+ symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ refname, RESOLVE_REF_READING,
+ NULL, &flag);
if (symref && (flag & REF_ISSYMREF)) {
item->util = xstrdup(symref);
rename->symrefs_nr++;
@@ -618,16 +629,16 @@ static int migrate_file(struct remote *remote)
int i;
strbuf_addf(&buf, "remote.%s.url", remote->name);
- for (i = 0; i < remote->url_nr; i++)
- git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
+ for (i = 0; i < remote->url.nr; i++)
+ git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name);
- for (i = 0; i < remote->push.raw_nr; i++)
- git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
+ for (i = 0; i < remote->push.nr; i++)
+ git_config_set_multivar(buf.buf, remote->push.items[i].raw, "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
- for (i = 0; i < remote->fetch.raw_nr; i++)
- git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0);
+ for (i = 0; i < remote->fetch.nr; i++)
+ git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0);
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(git_path("remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES)
@@ -666,7 +677,11 @@ static int config_read_push_default(const char *key, const char *value,
static void handle_push_default(const char* old_name, const char* new_name)
{
struct push_default_info push_default = {
- old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 };
+ .old_name = old_name,
+ .scope = CONFIG_SCOPE_UNKNOWN,
+ .origin = STRBUF_INIT,
+ .linenr = -1,
+ };
git_config(config_read_push_default, &push_default);
if (push_default.scope >= CONFIG_SCOPE_COMMAND)
; /* pass */
@@ -686,6 +701,8 @@ static void handle_push_default(const char* old_name, const char* new_name)
push_default.origin.buf, push_default.linenr,
old_name);
}
+
+ strbuf_release(&push_default.origin);
}
@@ -703,6 +720,7 @@ static int mv(int argc, const char **argv, const char *prefix)
struct rename_info rename;
int i, refs_renamed_nr = 0, refspec_updated = 0;
struct progress *progress = NULL;
+ int result = 0;
argc = parse_options(argc, argv, prefix, options,
builtin_remote_rename_usage, 0);
@@ -735,20 +753,22 @@ static int mv(int argc, const char **argv, const char *prefix)
strbuf_addf(&buf, "remote.%s", rename.old_name);
strbuf_addf(&buf2, "remote.%s", rename.new_name);
- if (git_config_rename_section(buf.buf, buf2.buf) < 1)
- return error(_("Could not rename config section '%s' to '%s'"),
- buf.buf, buf2.buf);
+ if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1) {
+ result = error(_("Could not rename config section '%s' to '%s'"),
+ buf.buf, buf2.buf);
+ goto out;
+ }
- if (oldremote->fetch.raw_nr) {
+ if (oldremote->fetch.nr) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
- for (i = 0; i < oldremote->fetch.raw_nr; i++) {
+ for (i = 0; i < oldremote->fetch.nr; i++) {
char *ptr;
strbuf_reset(&buf2);
- strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
+ strbuf_addstr(&buf2, oldremote->fetch.items[i].raw);
ptr = strstr(buf2.buf, old_remote_context.buf);
if (ptr) {
refspec_updated = 1;
@@ -783,13 +803,14 @@ static int mv(int argc, const char **argv, const char *prefix)
}
if (!refspec_updated)
- return 0;
+ goto out;
/*
* First remove symrefs, then rename the rest, finally create
* the new symrefs.
*/
- for_each_ref(read_remote_branches, &rename);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ read_remote_branches, &rename);
if (show_progress) {
/*
* Count symrefs twice, since "renaming" them is done by
@@ -805,7 +826,7 @@ static int mv(int argc, const char **argv, const char *prefix)
if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
&referent))
continue;
- if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
die(_("deleting '%s' failed"), item->string);
strbuf_release(&referent);
@@ -823,7 +844,7 @@ static int mv(int argc, const char **argv, const char *prefix)
strbuf_reset(&buf2);
strbuf_addf(&buf2, "remote: renamed %s to %s",
item->string, buf.buf);
- if (rename_ref(item->string, buf.buf, buf2.buf))
+ if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
die(_("renaming '%s' failed"), item->string);
display_progress(progress, ++refs_renamed_nr);
}
@@ -843,16 +864,21 @@ static int mv(int argc, const char **argv, const char *prefix)
strbuf_reset(&buf3);
strbuf_addf(&buf3, "remote: renamed %s to %s",
item->string, buf.buf);
- if (create_symref(buf.buf, buf2.buf, buf3.buf))
+ if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
die(_("creating '%s' failed"), buf.buf);
display_progress(progress, ++refs_renamed_nr);
}
stop_progress(&progress);
- string_list_clear(&remote_branches, 1);
handle_push_default(rename.old_name, rename.new_name);
- return 0;
+out:
+ string_list_clear(&remote_branches, 1);
+ strbuf_release(&old_remote_context);
+ strbuf_release(&buf);
+ strbuf_release(&buf2);
+ strbuf_release(&buf3);
+ return result;
}
static int rm(int argc, const char **argv, const char *prefix)
@@ -917,11 +943,14 @@ static int rm(int argc, const char **argv, const char *prefix)
* refs, which are invalidated when deleting a branch.
*/
cb_data.remote = remote;
- result = for_each_ref(add_branch_for_removal, &cb_data);
+ result = refs_for_each_ref(get_main_ref_store(the_repository),
+ add_branch_for_removal, &cb_data);
strbuf_release(&buf);
if (!result)
- result = delete_refs("remote: remove", &branches, REF_NO_DEREF);
+ result = refs_delete_refs(get_main_ref_store(the_repository),
+ "remote: remove", &branches,
+ REF_NO_DEREF);
string_list_clear(&branches, 0);
if (skipped.nr) {
@@ -939,12 +968,21 @@ static int rm(int argc, const char **argv, const char *prefix)
if (!result) {
strbuf_addf(&buf, "remote.%s", remote->name);
- if (git_config_rename_section(buf.buf, NULL) < 1)
- return error(_("Could not remove config section '%s'"), buf.buf);
+ if (repo_config_rename_section(the_repository, buf.buf, NULL) < 1) {
+ result = error(_("Could not remove config section '%s'"), buf.buf);
+ goto out;
+ }
handle_push_default(remote->name, NULL);
}
+out:
+ for (struct known_remote *r = known_remotes.list; r;) {
+ struct known_remote *next = r->next;
+ free(r);
+ r = next;
+ }
+ strbuf_release(&buf);
return result;
}
@@ -966,6 +1004,7 @@ static void free_remote_ref_states(struct ref_states *states)
}
static int append_ref_to_tracked_list(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags, void *cb_data)
{
@@ -977,8 +1016,10 @@ static int append_ref_to_tracked_list(const char *refname,
memset(&refspec, 0, sizeof(refspec));
refspec.dst = (char *)refname;
- if (!remote_find_tracking(states->remote, &refspec))
+ if (!remote_find_tracking(states->remote, &refspec)) {
string_list_append(&states->tracked, abbrev_branch(refspec.src));
+ free(refspec.src);
+ }
return 0;
}
@@ -997,8 +1038,7 @@ static int get_remote_ref_states(const char *name,
struct transport *transport;
const struct ref *remote_refs;
- transport = transport_get(states->remote, states->remote->url_nr > 0 ?
- states->remote->url[0] : NULL);
+ transport = transport_get(states->remote, states->remote->url.v[0]);
remote_refs = transport_get_remote_refs(transport, NULL);
states->queried = 1;
@@ -1010,7 +1050,8 @@ static int get_remote_ref_states(const char *name,
get_push_ref_states(remote_refs, states);
transport_disconnect(transport);
} else {
- for_each_ref(append_ref_to_tracked_list, states);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_ref_to_tracked_list, states);
string_list_sort(&states->tracked);
get_push_ref_states_noquery(states);
}
@@ -1207,15 +1248,15 @@ static int get_one_entry(struct remote *remote, void *priv)
{
struct string_list *list = priv;
struct strbuf remote_info_buf = STRBUF_INIT;
- const char **url;
- int i, url_nr;
+ struct strvec *url;
+ int i;
- if (remote->url_nr > 0) {
+ if (remote->url.nr > 0) {
struct strbuf promisor_config = STRBUF_INIT;
const char *partial_clone_filter = NULL;
strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name);
- strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url[0]);
+ strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]);
if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter))
strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter);
@@ -1224,16 +1265,10 @@ static int get_one_entry(struct remote *remote, void *priv)
strbuf_detach(&remote_info_buf, NULL);
} else
string_list_append(list, remote->name)->util = NULL;
- if (remote->pushurl_nr) {
- url = remote->pushurl;
- url_nr = remote->pushurl_nr;
- } else {
- url = remote->url;
- url_nr = remote->url_nr;
- }
- for (i = 0; i < url_nr; i++)
+ url = push_url_of_remote(remote);
+ for (i = 0; i < url->nr; i++)
{
- strbuf_addf(&remote_info_buf, "%s (push)", url[i]);
+ strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]);
string_list_append(list, remote->name)->util =
strbuf_detach(&remote_info_buf, NULL);
}
@@ -1289,28 +1324,20 @@ static int show(int argc, const char **argv, const char *prefix)
for (; argc; argc--, argv++) {
int i;
- const char **url;
- int url_nr;
+ struct strvec *url;
get_remote_ref_states(*argv, &info.states, query_flag);
printf_ln(_("* remote %s"), *argv);
- printf_ln(_(" Fetch URL: %s"), info.states.remote->url_nr > 0 ?
- info.states.remote->url[0] : _("(no URL)"));
- if (info.states.remote->pushurl_nr) {
- url = info.states.remote->pushurl;
- url_nr = info.states.remote->pushurl_nr;
- } else {
- url = info.states.remote->url;
- url_nr = info.states.remote->url_nr;
- }
- for (i = 0; i < url_nr; i++)
+ printf_ln(_(" Fetch URL: %s"), info.states.remote->url.v[0]);
+ url = push_url_of_remote(info.states.remote);
+ for (i = 0; i < url->nr; i++)
/*
* TRANSLATORS: the colon ':' should align
* with the one in " Fetch URL: %s"
* translation.
*/
- printf_ln(_(" Push URL: %s"), url[i]);
+ printf_ln(_(" Push URL: %s"), url->v[i]);
if (!i)
printf_ln(_(" Push URL: %s"), _("(no URL)"));
if (no_query)
@@ -1407,7 +1434,7 @@ static int set_head(int argc, const char **argv, const char *prefix)
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (delete_ref(NULL, buf.buf, NULL, REF_NO_DEREF))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, buf.buf, NULL, REF_NO_DEREF))
result |= error(_("Could not delete %s"), buf.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
@@ -1415,9 +1442,9 @@ static int set_head(int argc, const char **argv, const char *prefix)
if (head_name) {
strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
/* make sure it's valid */
- if (!ref_exists(buf2.buf))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf))
result |= error(_("Not a valid ref: %s"), buf2.buf);
- else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
+ else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head"))
result |= error(_("Could not setup %s"), buf.buf);
else if (opt_a)
printf("%s/HEAD set to %s\n", argv[0], head_name);
@@ -1447,17 +1474,15 @@ static int prune_remote(const char *remote, int dry_run)
}
printf_ln(_("Pruning %s"), remote);
- printf_ln(_("URL: %s"),
- states.remote->url_nr
- ? states.remote->url[0]
- : _("(no URL)"));
+ printf_ln(_("URL: %s"), states.remote->url.v[0]);
for_each_string_list_item(item, &states.stale)
string_list_append(&refs_to_prune, item->util);
string_list_sort(&refs_to_prune);
if (!dry_run)
- result |= delete_refs("remote: prune", &refs_to_prune, 0);
+ result |= refs_delete_refs(get_main_ref_store(the_repository),
+ "remote: prune", &refs_to_prune, 0);
for_each_string_list_item(item, &states.stale) {
const char *refname = item->util;
@@ -1470,7 +1495,8 @@ static int prune_remote(const char *remote, int dry_run)
abbrev_ref(refname, "refs/remotes/"));
}
- warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
+ refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
+ stdout, dangling_msg, &refs_to_prune);
string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states);
@@ -1614,8 +1640,7 @@ static int get_url(int argc, const char **argv, const char *prefix)
int i, push_mode = 0, all_mode = 0;
const char *remotename = NULL;
struct remote *remote;
- const char **url;
- int url_nr;
+ struct strvec *url;
struct option options[] = {
OPT_BOOL('\0', "push", &push_mode,
N_("query push URLs rather than fetch URLs")),
@@ -1637,27 +1662,13 @@ static int get_url(int argc, const char **argv, const char *prefix)
exit(2);
}
- url_nr = 0;
- if (push_mode) {
- url = remote->pushurl;
- url_nr = remote->pushurl_nr;
- }
- /* else fetch mode */
-
- /* Use the fetch URL when no push URLs were found or requested. */
- if (!url_nr) {
- url = remote->url;
- url_nr = remote->url_nr;
- }
-
- if (!url_nr)
- die(_("no URLs configured for remote '%s'"), remotename);
+ url = push_mode ? push_url_of_remote(remote) : &remote->url;
if (all_mode) {
- for (i = 0; i < url_nr; i++)
- printf_ln("%s", url[i]);
+ for (i = 0; i < url->nr; i++)
+ printf_ln("%s", url->v[i]);
} else {
- printf_ln("%s", *url);
+ printf_ln("%s", url->v[0]);
}
return 0;
@@ -1672,8 +1683,7 @@ static int set_url(int argc, const char **argv, const char *prefix)
const char *oldurl = NULL;
struct remote *remote;
regex_t old_regex;
- const char **urlset;
- int urlset_nr;
+ struct strvec *urlset;
struct strbuf name_buf = STRBUF_INIT;
struct option options[] = {
OPT_BOOL('\0', "push", &push_mode,
@@ -1710,12 +1720,10 @@ static int set_url(int argc, const char **argv, const char *prefix)
if (push_mode) {
strbuf_addf(&name_buf, "remote.%s.pushurl", remotename);
- urlset = remote->pushurl;
- urlset_nr = remote->pushurl_nr;
+ urlset = &remote->pushurl;
} else {
strbuf_addf(&name_buf, "remote.%s.url", remotename);
- urlset = remote->url;
- urlset_nr = remote->url_nr;
+ urlset = &remote->url;
}
/* Special cases that add new entry. */
@@ -1732,8 +1740,8 @@ static int set_url(int argc, const char **argv, const char *prefix)
if (regcomp(&old_regex, oldurl, REG_EXTENDED))
die(_("Invalid old URL pattern: %s"), oldurl);
- for (i = 0; i < urlset_nr; i++)
- if (!regexec(&old_regex, urlset[i], 0, NULL, 0))
+ for (i = 0; i < urlset->nr; i++)
+ if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0))
matches++;
else
negative_matches++;
@@ -1754,7 +1762,10 @@ out:
return 0;
}
-int cmd_remote(int argc, const char **argv, const char *prefix)
+int cmd_remote(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
diff --git a/builtin/repack.c b/builtin/repack.c
index 97051479e4..d6bb37e84a 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "dir.h"
@@ -8,7 +9,6 @@
#include "path.h"
#include "run-command.h"
#include "server-info.h"
-#include "sigchain.h"
#include "strbuf.h"
#include "string-list.h"
#include "strvec.h"
@@ -21,13 +21,14 @@
#include "pack.h"
#include "pack-bitmap.h"
#include "refs.h"
+#include "list-objects-filter-options.h"
#define ALL_INTO_ONE 1
#define LOOSEN_UNREACHABLE 2
#define PACK_CRUFT 4
#define DELETE_PACK 1
-#define CRUFT_PACK 2
+#define RETAIN_PACK 2
static int pack_everything;
static int delta_base_offset = 1;
@@ -48,15 +49,16 @@ static const char incremental_bitmap_conflict_error[] = N_(
);
struct pack_objects_args {
- const char *window;
- const char *window_memory;
- const char *depth;
- const char *threads;
- const char *max_pack_size;
+ char *window;
+ char *window_memory;
+ char *depth;
+ char *threads;
+ unsigned long max_pack_size;
int no_reuse_delta;
int no_reuse_object;
int quiet;
int local;
+ struct list_objects_filter_options filter_options;
};
static int repack_config(const char *var, const char *value,
@@ -84,25 +86,171 @@ static int repack_config(const char *var, const char *value,
run_update_server_info = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "repack.cruftwindow"))
+ if (!strcmp(var, "repack.cruftwindow")) {
+ free(cruft_po_args->window);
return git_config_string(&cruft_po_args->window, var, value);
- if (!strcmp(var, "repack.cruftwindowmemory"))
+ }
+ if (!strcmp(var, "repack.cruftwindowmemory")) {
+ free(cruft_po_args->window_memory);
return git_config_string(&cruft_po_args->window_memory, var, value);
- if (!strcmp(var, "repack.cruftdepth"))
+ }
+ if (!strcmp(var, "repack.cruftdepth")) {
+ free(cruft_po_args->depth);
return git_config_string(&cruft_po_args->depth, var, value);
- if (!strcmp(var, "repack.cruftthreads"))
+ }
+ if (!strcmp(var, "repack.cruftthreads")) {
+ free(cruft_po_args->threads);
return git_config_string(&cruft_po_args->threads, var, value);
+ }
return git_default_config(var, value, ctx, cb);
}
+static void pack_objects_args_release(struct pack_objects_args *args)
+{
+ free(args->window);
+ free(args->window_memory);
+ free(args->depth);
+ free(args->threads);
+ list_objects_filter_release(&args->filter_options);
+}
+
+struct existing_packs {
+ struct string_list kept_packs;
+ struct string_list non_kept_packs;
+ struct string_list cruft_packs;
+};
+
+#define EXISTING_PACKS_INIT { \
+ .kept_packs = STRING_LIST_INIT_DUP, \
+ .non_kept_packs = STRING_LIST_INIT_DUP, \
+ .cruft_packs = STRING_LIST_INIT_DUP, \
+}
+
+static int has_existing_non_kept_packs(const struct existing_packs *existing)
+{
+ return existing->non_kept_packs.nr || existing->cruft_packs.nr;
+}
+
+static void pack_mark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
+}
+
+static void pack_unmark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
+}
+
+static int pack_is_marked_for_deletion(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & DELETE_PACK;
+}
+
+static void pack_mark_retained(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
+}
+
+static int pack_is_retained(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & RETAIN_PACK;
+}
+
+static void mark_packs_for_deletion_1(struct string_list *names,
+ struct string_list *list)
+{
+ struct string_list_item *item;
+ const int hexsz = the_hash_algo->hexsz;
+
+ for_each_string_list_item(item, list) {
+ char *sha1;
+ size_t len = strlen(item->string);
+ if (len < hexsz)
+ continue;
+ sha1 = item->string + len - hexsz;
+
+ if (pack_is_retained(item)) {
+ pack_unmark_for_deletion(item);
+ } else if (!string_list_has_string(names, sha1)) {
+ /*
+ * Mark this pack for deletion, which ensures
+ * that this pack won't be included in a MIDX
+ * (if `--write-midx` was given) and that we
+ * will actually delete this pack (if `-d` was
+ * given).
+ */
+ pack_mark_for_deletion(item);
+ }
+ }
+}
+
+static void retain_cruft_pack(struct existing_packs *existing,
+ struct packed_git *cruft)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+
+ strbuf_addstr(&buf, pack_basename(cruft));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ item = string_list_lookup(&existing->cruft_packs, buf.buf);
+ if (!item)
+ BUG("could not find cruft pack '%s'", pack_basename(cruft));
+
+ pack_mark_retained(item);
+ strbuf_release(&buf);
+}
+
+static void mark_packs_for_deletion(struct existing_packs *existing,
+ struct string_list *names)
+
+{
+ mark_packs_for_deletion_1(names, &existing->non_kept_packs);
+ mark_packs_for_deletion_1(names, &existing->cruft_packs);
+}
+
+static void remove_redundant_pack(const char *dir_name, const char *base_name)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+ strbuf_addf(&buf, "%s.pack", base_name);
+ if (m && midx_contains_pack(m, buf.buf))
+ clear_midx_file(the_repository);
+ strbuf_insertf(&buf, 0, "%s/", dir_name);
+ unlink_pack_path(buf.buf, 1);
+ strbuf_release(&buf);
+}
+
+static void remove_redundant_packs_1(struct string_list *packs)
+{
+ struct string_list_item *item;
+ for_each_string_list_item(item, packs) {
+ if (!pack_is_marked_for_deletion(item))
+ continue;
+ remove_redundant_pack(packdir, item->string);
+ }
+}
+
+static void remove_redundant_existing_packs(struct existing_packs *existing)
+{
+ remove_redundant_packs_1(&existing->non_kept_packs);
+ remove_redundant_packs_1(&existing->cruft_packs);
+}
+
+static void existing_packs_release(struct existing_packs *existing)
+{
+ string_list_clear(&existing->kept_packs, 0);
+ string_list_clear(&existing->non_kept_packs, 0);
+ string_list_clear(&existing->cruft_packs, 0);
+}
+
/*
- * Adds all packs hex strings (pack-$HASH) to either fname_nonkept_list
- * or fname_kept_list based on whether each pack has a corresponding
+ * Adds all packs hex strings (pack-$HASH) to either packs->non_kept
+ * or packs->kept based on whether each pack has a corresponding
* .keep file or not. Packs without a .keep file are not to be kept
* if we are going to pack everything into one file.
*/
-static void collect_pack_filenames(struct string_list *fname_nonkept_list,
- struct string_list *fname_kept_list,
+static void collect_pack_filenames(struct existing_packs *existing,
const struct string_list *extra_keep)
{
struct packed_git *p;
@@ -126,28 +274,16 @@ static void collect_pack_filenames(struct string_list *fname_nonkept_list,
strbuf_strip_suffix(&buf, ".pack");
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(fname_nonkept_list, buf.buf);
- if (p->is_cruft)
- item->util = (void*)(uintptr_t)CRUFT_PACK;
- }
+ string_list_append(&existing->kept_packs, buf.buf);
+ else if (p->is_cruft)
+ string_list_append(&existing->cruft_packs, buf.buf);
+ else
+ string_list_append(&existing->non_kept_packs, buf.buf);
}
- string_list_sort(fname_kept_list);
- strbuf_release(&buf);
-}
-
-static void remove_redundant_pack(const char *dir_name, const char *base_name)
-{
- struct strbuf buf = STRBUF_INIT;
- struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
- strbuf_addf(&buf, "%s.pack", base_name);
- if (m && midx_contains_pack(m, buf.buf))
- clear_midx_file(the_repository);
- strbuf_insertf(&buf, 0, "%s/", dir_name);
- unlink_pack_path(buf.buf, 1);
+ string_list_sort(&existing->kept_packs);
+ string_list_sort(&existing->non_kept_packs);
+ string_list_sort(&existing->cruft_packs);
strbuf_release(&buf);
}
@@ -165,7 +301,7 @@ static void prepare_pack_objects(struct child_process *cmd,
if (args->threads)
strvec_pushf(&cmd->args, "--threads=%s", args->threads);
if (args->max_pack_size)
- strvec_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
+ strvec_pushf(&cmd->args, "--max-pack-size=%lu", args->max_pack_size);
if (args->no_reuse_delta)
strvec_pushf(&cmd->args, "--no-reuse-delta");
if (args->no_reuse_object)
@@ -196,8 +332,9 @@ static int write_oid(const struct object_id *oid,
die(_("could not start pack-objects to repack promisor objects"));
}
- xwrite(cmd->in, oid_to_hex(oid), the_hash_algo->hexsz);
- xwrite(cmd->in, "\n", 1);
+ if (write_in_full(cmd->in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ write_in_full(cmd->in, "\n", 1) < 0)
+ die(_("failed to feed promisor objects to pack-objects"));
return 0;
}
@@ -238,6 +375,18 @@ static struct generated_pack_data *populate_pack_exts(const char *name)
return data;
}
+static int has_pack_ext(const struct generated_pack_data *data,
+ const char *ext)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(exts); i++) {
+ if (strcmp(exts[i].name, ext))
+ continue;
+ return !!data->tempfiles[i];
+ }
+ BUG("unknown pack extension: '%s'", ext);
+}
+
static void repack_promisor_objects(const struct pack_objects_args *args,
struct string_list *names)
{
@@ -294,15 +443,19 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
free(promisor_name);
}
+
fclose(out);
if (finish_command(&cmd))
die(_("could not finish pack-objects to repack promisor objects"));
+ strbuf_release(&line);
}
struct pack_geometry {
struct packed_git **pack;
uint32_t pack_nr, pack_alloc;
uint32_t split;
+
+ int split_factor;
};
static uint32_t geometry_pack_weight(struct packed_git *p)
@@ -324,17 +477,13 @@ static int geometry_cmp(const void *va, const void *vb)
return 0;
}
-static void init_pack_geometry(struct pack_geometry **geometry_p,
- struct string_list *existing_kept_packs,
+static void init_pack_geometry(struct pack_geometry *geometry,
+ struct existing_packs *existing,
const struct pack_objects_args *args)
{
struct packed_git *p;
- struct pack_geometry *geometry;
struct strbuf buf = STRBUF_INIT;
- *geometry_p = xcalloc(1, sizeof(struct pack_geometry));
- geometry = *geometry_p;
-
for (p = get_all_packs(the_repository); p; p = p->next) {
if (args->local && !p->pack_local)
/*
@@ -346,23 +495,24 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
if (!pack_kept_objects) {
/*
- * Any pack that has its pack_keep bit set will appear
- * in existing_kept_packs below, but this saves us from
- * doing a more expensive check.
+ * Any pack that has its pack_keep bit set will
+ * appear in existing->kept_packs below, but
+ * this saves us from doing a more expensive
+ * check.
*/
if (p->pack_keep)
continue;
/*
- * The pack may be kept via the --keep-pack option;
- * check 'existing_kept_packs' to determine whether to
- * ignore it.
+ * The pack may be kept via the --keep-pack
+ * option; check 'existing->kept_packs' to
+ * determine whether to ignore it.
*/
strbuf_reset(&buf);
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
- if (string_list_has_string(existing_kept_packs, buf.buf))
+ if (string_list_has_string(&existing->kept_packs, buf.buf))
continue;
}
if (p->is_cruft)
@@ -380,7 +530,7 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
strbuf_release(&buf);
}
-static void split_pack_geometry(struct pack_geometry *geometry, int factor)
+static void split_pack_geometry(struct pack_geometry *geometry)
{
uint32_t i;
uint32_t split;
@@ -399,12 +549,14 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
struct packed_git *ours = geometry->pack[i];
struct packed_git *prev = geometry->pack[i - 1];
- if (unsigned_mult_overflows(factor, geometry_pack_weight(prev)))
+ if (unsigned_mult_overflows(geometry->split_factor,
+ geometry_pack_weight(prev)))
die(_("pack %s too large to consider in geometric "
"progression"),
prev->pack_name);
- if (geometry_pack_weight(ours) < factor * geometry_pack_weight(prev))
+ if (geometry_pack_weight(ours) <
+ geometry->split_factor * geometry_pack_weight(prev))
break;
}
@@ -439,10 +591,12 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
for (i = split; i < geometry->pack_nr; i++) {
struct packed_git *ours = geometry->pack[i];
- if (unsigned_mult_overflows(factor, total_size))
+ if (unsigned_mult_overflows(geometry->split_factor,
+ total_size))
die(_("pack %s too large to roll up"), ours->pack_name);
- if (geometry_pack_weight(ours) < factor * total_size) {
+ if (geometry_pack_weight(ours) <
+ geometry->split_factor * total_size) {
if (unsigned_add_overflows(total_size,
geometry_pack_weight(ours)))
die(_("pack %s too large to roll up"),
@@ -492,13 +646,38 @@ static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
return NULL;
}
+static void geometry_remove_redundant_packs(struct pack_geometry *geometry,
+ struct string_list *names,
+ struct existing_packs *existing)
+{
+ struct strbuf buf = STRBUF_INIT;
+ uint32_t i;
+
+ for (i = 0; i < geometry->split; i++) {
+ struct packed_git *p = geometry->pack[i];
+ if (string_list_has_string(names, hash_to_hex(p->hash)))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if ((p->pack_keep) ||
+ (string_list_has_string(&existing->kept_packs, buf.buf)))
+ continue;
+
+ remove_redundant_pack(packdir, buf.buf);
+ }
+
+ strbuf_release(&buf);
+}
+
static void free_pack_geometry(struct pack_geometry *geometry)
{
if (!geometry)
return;
free(geometry->pack);
- free(geometry);
}
struct midx_snapshot_ref_data {
@@ -508,13 +687,14 @@ struct midx_snapshot_ref_data {
};
static int midx_snapshot_ref_one(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *_data)
{
struct midx_snapshot_ref_data *data = _data;
struct object_id peeled;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oidset_insert(&data->seen, oid))
@@ -547,11 +727,14 @@ static void midx_snapshot_refs(struct tempfile *f)
data.preferred = 1;
for_each_string_list_item(item, preferred)
- for_each_ref_in(item->string, midx_snapshot_ref_one, &data);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ item->string,
+ midx_snapshot_ref_one, &data);
data.preferred = 0;
}
- for_each_ref(midx_snapshot_ref_one, &data);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ midx_snapshot_ref_one, &data);
if (close_tempfile_gently(f)) {
int save_errno = errno;
@@ -564,20 +747,28 @@ static void midx_snapshot_refs(struct tempfile *f)
}
static void midx_included_packs(struct string_list *include,
- struct string_list *existing_nonkept_packs,
- struct string_list *existing_kept_packs,
+ struct existing_packs *existing,
struct string_list *names,
struct pack_geometry *geometry)
{
struct string_list_item *item;
+ struct strbuf buf = STRBUF_INIT;
- for_each_string_list_item(item, existing_kept_packs)
- string_list_insert(include, xstrfmt("%s.idx", item->string));
- for_each_string_list_item(item, names)
- string_list_insert(include, xstrfmt("pack-%s.idx", item->string));
- if (geometry) {
- struct strbuf buf = STRBUF_INIT;
+ for_each_string_list_item(item, &existing->kept_packs) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
+ }
+
+ for_each_string_list_item(item, names) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "pack-%s.idx", item->string);
+ string_list_insert(include, buf.buf);
+ }
+
+ if (geometry->split_factor) {
uint32_t i;
+
for (i = geometry->split; i < geometry->pack_nr; i++) {
struct packed_git *p = geometry->pack[i];
@@ -592,34 +783,52 @@ static void midx_included_packs(struct string_list *include,
if (!p->pack_local)
continue;
+ strbuf_reset(&buf);
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
strbuf_addstr(&buf, ".idx");
- string_list_insert(include, strbuf_detach(&buf, NULL));
- }
-
- for_each_string_list_item(item, existing_nonkept_packs) {
- if (!((uintptr_t)item->util & CRUFT_PACK)) {
- /*
- * no need to check DELETE_PACK, since we're not
- * doing an ALL_INTO_ONE repack
- */
- continue;
- }
- string_list_insert(include, xstrfmt("%s.idx", item->string));
+ string_list_insert(include, buf.buf);
}
} else {
- for_each_string_list_item(item, existing_nonkept_packs) {
- if ((uintptr_t)item->util & DELETE_PACK)
+ for_each_string_list_item(item, &existing->non_kept_packs) {
+ if (pack_is_marked_for_deletion(item))
continue;
- string_list_insert(include, xstrfmt("%s.idx", item->string));
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
}
}
+
+ for_each_string_list_item(item, &existing->cruft_packs) {
+ /*
+ * When doing a --geometric repack, there is no need to check
+ * for deleted packs, since we're by definition not doing an
+ * ALL_INTO_ONE repack (hence no packs will be deleted).
+ * Otherwise we must check for and exclude any packs which are
+ * enqueued for deletion.
+ *
+ * So we could omit the conditional below in the --geometric
+ * case, but doing so is unnecessary since no packs are marked
+ * as pending deletion (since we only call
+ * `mark_packs_for_deletion()` when doing an all-into-one
+ * repack).
+ */
+ if (pack_is_marked_for_deletion(item))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
+ }
+
+ strbuf_release(&buf);
}
static int write_midx_included_packs(struct string_list *include,
struct pack_geometry *geometry,
+ struct string_list *names,
const char *refs_snapshot,
int show_progress, int write_bitmaps)
{
@@ -649,6 +858,38 @@ static int write_midx_included_packs(struct string_list *include,
if (preferred)
strvec_pushf(&cmd.args, "--preferred-pack=%s",
pack_basename(preferred));
+ else if (names->nr) {
+ /* The largest pack was repacked, meaning that either
+ * one or two packs exist depending on whether the
+ * repository has a cruft pack or not.
+ *
+ * Select the non-cruft one as preferred to encourage
+ * pack-reuse among packs containing reachable objects
+ * over unreachable ones.
+ *
+ * (Note we could write multiple packs here if
+ * `--max-pack-size` was given, but any one of them
+ * will suffice, so pick the first one.)
+ */
+ for_each_string_list_item(item, names) {
+ struct generated_pack_data *data = item->util;
+ if (has_pack_ext(data, ".mtimes"))
+ continue;
+
+ strvec_pushf(&cmd.args, "--preferred-pack=pack-%s.pack",
+ item->string);
+ break;
+ }
+ } else {
+ /*
+ * No packs were kept, and no packs were written. The
+ * only thing remaining are .keep packs (unless
+ * --pack-kept-objects was given).
+ *
+ * Set the `--preferred-pack` arbitrarily here.
+ */
+ ;
+ }
if (refs_snapshot)
strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -694,18 +935,163 @@ static void remove_redundant_bitmaps(struct string_list *include,
strbuf_release(&path);
}
+static int finish_pack_objects_cmd(struct child_process *cmd,
+ struct string_list *names,
+ int local)
+{
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+
+ out = xfdopen(cmd->out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ struct string_list_item *item;
+
+ if (line.len != the_hash_algo->hexsz)
+ die(_("repack: Expecting full hex object ID lines only "
+ "from pack-objects."));
+ /*
+ * Avoid putting packs written outside of the repository in the
+ * list of names.
+ */
+ if (local) {
+ item = string_list_append(names, line.buf);
+ item->util = populate_pack_exts(line.buf);
+ }
+ }
+ fclose(out);
+
+ strbuf_release(&line);
+
+ return finish_command(cmd);
+}
+
+static int write_filtered_pack(const struct pack_objects_args *args,
+ const char *destination,
+ const char *pack_prefix,
+ struct existing_packs *existing,
+ struct string_list *names)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ struct string_list_item *item;
+ FILE *in;
+ int ret;
+ const char *caret;
+ const char *scratch;
+ int local = skip_prefix(destination, packdir, &scratch);
+
+ prepare_pack_objects(&cmd, args, destination);
+
+ strvec_push(&cmd.args, "--stdin-packs");
+
+ if (!pack_kept_objects)
+ strvec_push(&cmd.args, "--honor-pack-keep");
+ for_each_string_list_item(item, &existing->kept_packs)
+ strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
+
+ cmd.in = -1;
+
+ ret = start_command(&cmd);
+ if (ret)
+ return ret;
+
+ /*
+ * Here 'names' contains only the pack(s) that were just
+ * written, which is exactly the packs we want to keep. Also
+ * 'existing_kept_packs' already contains the packs in
+ * 'keep_pack_list'.
+ */
+ in = xfdopen(cmd.in, "w");
+ for_each_string_list_item(item, names)
+ fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "%s.pack\n", item->string);
+ caret = pack_kept_objects ? "" : "^";
+ for_each_string_list_item(item, &existing->kept_packs)
+ fprintf(in, "%s%s.pack\n", caret, item->string);
+ fclose(in);
+
+ return finish_pack_objects_cmd(&cmd, names, local);
+}
+
+static int existing_cruft_pack_cmp(const void *va, const void *vb)
+{
+ struct packed_git *a = *(struct packed_git **)va;
+ struct packed_git *b = *(struct packed_git **)vb;
+
+ if (a->pack_size < b->pack_size)
+ return -1;
+ if (a->pack_size > b->pack_size)
+ return 1;
+ return 0;
+}
+
+static void collapse_small_cruft_packs(FILE *in, size_t max_size,
+ struct existing_packs *existing)
+{
+ struct packed_git **existing_cruft, *p;
+ struct strbuf buf = STRBUF_INIT;
+ size_t total_size = 0;
+ size_t existing_cruft_nr = 0;
+ size_t i;
+
+ ALLOC_ARRAY(existing_cruft, existing->cruft_packs.nr);
+
+ for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (!(p->is_cruft && p->pack_local))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if (!string_list_has_string(&existing->cruft_packs, buf.buf))
+ continue;
+
+ if (existing_cruft_nr >= existing->cruft_packs.nr)
+ BUG("too many cruft packs (found %"PRIuMAX", but knew "
+ "of %"PRIuMAX")",
+ (uintmax_t)existing_cruft_nr + 1,
+ (uintmax_t)existing->cruft_packs.nr);
+ existing_cruft[existing_cruft_nr++] = p;
+ }
+
+ QSORT(existing_cruft, existing_cruft_nr, existing_cruft_pack_cmp);
+
+ for (i = 0; i < existing_cruft_nr; i++) {
+ size_t proposed;
+
+ p = existing_cruft[i];
+ proposed = st_add(total_size, p->pack_size);
+
+ if (proposed <= max_size) {
+ total_size = proposed;
+ fprintf(in, "-%s\n", pack_basename(p));
+ } else {
+ retain_cruft_pack(existing, p);
+ fprintf(in, "%s\n", pack_basename(p));
+ }
+ }
+
+ for (i = 0; i < existing->non_kept_packs.nr; i++)
+ fprintf(in, "-%s.pack\n",
+ existing->non_kept_packs.items[i].string);
+
+ strbuf_release(&buf);
+ free(existing_cruft);
+}
+
static int write_cruft_pack(const struct pack_objects_args *args,
const char *destination,
const char *pack_prefix,
const char *cruft_expiration,
struct string_list *names,
- struct string_list *existing_packs,
- struct string_list *existing_kept_packs)
+ struct existing_packs *existing)
{
struct child_process cmd = CHILD_PROCESS_INIT;
- struct strbuf line = STRBUF_INIT;
struct string_list_item *item;
- FILE *in, *out;
+ FILE *in;
int ret;
const char *scratch;
int local = skip_prefix(destination, packdir, &scratch);
@@ -719,7 +1105,6 @@ static int write_cruft_pack(const struct pack_objects_args *args,
strvec_push(&cmd.args, "--honor-pack-keep");
strvec_push(&cmd.args, "--non-empty");
- strvec_push(&cmd.args, "--max-pack-size=0");
cmd.in = -1;
@@ -743,47 +1128,44 @@ static int write_cruft_pack(const struct pack_objects_args *args,
in = xfdopen(cmd.in, "w");
for_each_string_list_item(item, names)
fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
- for_each_string_list_item(item, existing_packs)
- fprintf(in, "-%s.pack\n", item->string);
- for_each_string_list_item(item, existing_kept_packs)
+ if (args->max_pack_size && !cruft_expiration) {
+ collapse_small_cruft_packs(in, args->max_pack_size, existing);
+ } else {
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ }
+ for_each_string_list_item(item, &existing->kept_packs)
fprintf(in, "%s.pack\n", item->string);
fclose(in);
- out = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, out) != EOF) {
- struct string_list_item *item;
-
- if (line.len != the_hash_algo->hexsz)
- die(_("repack: Expecting full hex object ID lines only "
- "from pack-objects."));
- /*
- * avoid putting packs written outside of the repository in the
- * list of names
- */
- if (local) {
- item = string_list_append(names, line.buf);
- item->util = populate_pack_exts(line.buf);
- }
- }
- fclose(out);
-
- strbuf_release(&line);
+ return finish_pack_objects_cmd(&cmd, names, local);
+}
- return finish_command(&cmd);
+static const char *find_pack_prefix(const char *packdir, const char *packtmp)
+{
+ const char *pack_prefix;
+ if (!skip_prefix(packtmp, packdir, &pack_prefix))
+ die(_("pack prefix %s does not begin with objdir %s"),
+ packtmp, packdir);
+ if (*pack_prefix == '/')
+ pack_prefix++;
+ return pack_prefix;
}
-int cmd_repack(int argc, const char **argv, const char *prefix)
+int cmd_repack(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
struct string_list names = STRING_LIST_INIT_DUP;
- struct string_list existing_nonkept_packs = STRING_LIST_INIT_DUP;
- struct string_list existing_kept_packs = STRING_LIST_INIT_DUP;
- struct pack_geometry *geometry = NULL;
- struct strbuf line = STRBUF_INIT;
+ struct existing_packs existing = EXISTING_PACKS_INIT;
+ struct pack_geometry geometry = { 0 };
struct tempfile *refs_snapshot = NULL;
int i, ext, ret;
- FILE *out;
int show_progress;
/* variables to be filled by option parsing */
@@ -791,12 +1173,16 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
const char *unpack_unreachable = NULL;
int keep_unreachable = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
- struct pack_objects_args po_args = {NULL};
- struct pack_objects_args cruft_po_args = {NULL};
- int geometric_factor = 0;
+ struct pack_objects_args po_args = { 0 };
+ struct pack_objects_args cruft_po_args = { 0 };
int write_midx = 0;
const char *cruft_expiration = NULL;
const char *expire_to = NULL;
+ const char *filter_to = NULL;
+ const char *opt_window = NULL;
+ const char *opt_window_memory = NULL;
+ const char *opt_depth = NULL;
+ const char *opt_threads = NULL;
struct option builtin_repack_options[] = {
OPT_BIT('a', NULL, &pack_everything,
@@ -809,6 +1195,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
N_("with --cruft, expire objects older than this")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -828,58 +1216,58 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("with -A, do not loosen objects older than this")),
OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
N_("with -a, repack unreachable objects")),
- OPT_STRING(0, "window", &po_args.window, N_("n"),
+ OPT_STRING(0, "window", &opt_window, N_("n"),
N_("size of the window used for delta compression")),
- OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"),
+ OPT_STRING(0, "window-memory", &opt_window_memory, N_("bytes"),
N_("same as the above, but limit memory size instead of entries count")),
- OPT_STRING(0, "depth", &po_args.depth, N_("n"),
+ OPT_STRING(0, "depth", &opt_depth, N_("n"),
N_("limits the maximum delta depth")),
- OPT_STRING(0, "threads", &po_args.threads, N_("n"),
+ OPT_STRING(0, "threads", &opt_threads, N_("n"),
N_("limits the maximum number of threads")),
- OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"),
+ OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size,
N_("maximum size of each packfile")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
N_("repack objects in packs marked with .keep")),
OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
N_("do not repack this pack")),
- OPT_INTEGER('g', "geometric", &geometric_factor,
+ OPT_INTEGER('g', "geometric", &geometry.split_factor,
N_("find a geometric progression with factor <N>")),
OPT_BOOL('m', "write-midx", &write_midx,
N_("write a multi-pack index of the resulting packs")),
OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
N_("pack prefix to store a pack containing pruned objects")),
+ OPT_STRING(0, "filter-to", &filter_to, N_("dir"),
+ N_("pack prefix to store a pack containing filtered out objects")),
OPT_END()
};
+ list_objects_filter_init(&po_args.filter_options);
+
git_config(repack_config, &cruft_po_args);
argc = parse_options(argc, argv, prefix, builtin_repack_options,
git_repack_usage, 0);
+ po_args.window = xstrdup_or_null(opt_window);
+ po_args.window_memory = xstrdup_or_null(opt_window_memory);
+ po_args.depth = xstrdup_or_null(opt_depth);
+ po_args.threads = xstrdup_or_null(opt_threads);
+
if (delete_redundant && repository_format_precious_objects)
die(_("cannot delete packs in a precious-objects repo"));
- if (keep_unreachable &&
- (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
- die(_("options '%s' and '%s' cannot be used together"), "--keep-unreachable", "-A");
+ die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
+ keep_unreachable, "-k/--keep-unreachable",
+ pack_everything & PACK_CRUFT, "--cruft");
- if (pack_everything & PACK_CRUFT) {
+ if (pack_everything & PACK_CRUFT)
pack_everything |= ALL_INTO_ONE;
- if (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE))
- die(_("options '%s' and '%s' cannot be used together"), "--cruft", "-A");
- if (keep_unreachable)
- die(_("options '%s' and '%s' cannot be used together"), "--cruft", "-k");
- }
-
if (write_bitmaps < 0) {
if (!write_midx &&
(!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
write_bitmaps = 0;
- } else if (write_bitmaps &&
- git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0) &&
- git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0)) {
- write_bitmaps = 0;
}
if (pack_kept_objects < 0)
pack_kept_objects = write_bitmaps > 0 && !write_midx;
@@ -902,7 +1290,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (write_midx && write_bitmaps) {
struct strbuf path = STRBUF_INIT;
- strbuf_addf(&path, "%s/%s_XXXXXX", get_object_directory(),
+ strbuf_addf(&path, "%s/%s_XXXXXX", repo_get_object_directory(the_repository),
"bitmap-ref-tips");
refs_snapshot = xmks_tempfile(path.buf);
@@ -911,18 +1299,17 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strbuf_release(&path);
}
- packdir = mkpathdup("%s/pack", get_object_directory());
+ packdir = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
- collect_pack_filenames(&existing_nonkept_packs, &existing_kept_packs,
- &keep_pack_list);
+ collect_pack_filenames(&existing, &keep_pack_list);
- if (geometric_factor) {
+ if (geometry.split_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
- init_pack_geometry(&geometry, &existing_kept_packs, &po_args);
- split_pack_geometry(geometry, geometric_factor);
+ init_pack_geometry(&geometry, &existing, &po_args);
+ split_pack_geometry(&geometry);
}
prepare_pack_objects(&cmd, &po_args, packtmp);
@@ -936,7 +1323,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_pushf(&cmd.args, "--keep-pack=%s",
keep_pack_list.items[i].string);
strvec_push(&cmd.args, "--non-empty");
- if (!geometry) {
+ if (!geometry.split_factor) {
/*
* We need to grab all reachable objects, including those that
* are reachable from reflogs and the index.
@@ -965,7 +1352,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (pack_everything & ALL_INTO_ONE) {
repack_promisor_objects(&po_args, &names);
- if (existing_nonkept_packs.nr && delete_redundant &&
+ if (has_existing_non_kept_packs(&existing) &&
+ delete_redundant &&
!(pack_everything & PACK_CRUFT)) {
for_each_string_list_item(item, &names) {
strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
@@ -983,7 +1371,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--pack-loose-unreachable");
}
}
- } else if (geometry) {
+ } else if (geometry.split_factor) {
strvec_push(&cmd.args, "--stdin-packs");
strvec_push(&cmd.args, "--unpacked");
} else {
@@ -991,7 +1379,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--incremental");
}
- if (geometry)
+ if (po_args.filter_options.choice)
+ strvec_pushf(&cmd.args, "--filter=%s",
+ expand_list_objects_filter_spec(&po_args.filter_options));
+ else if (filter_to)
+ die(_("option '%s' can only be used along with '%s'"), "--filter-to", "--filter");
+
+ if (geometry.split_factor)
cmd.in = -1;
else
cmd.no_stdin = 1;
@@ -1000,32 +1394,21 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (ret)
goto cleanup;
- if (geometry) {
+ if (geometry.split_factor) {
FILE *in = xfdopen(cmd.in, "w");
/*
* The resulting pack should contain all objects in packs that
* are going to be rolled up, but exclude objects in packs which
* are being left alone.
*/
- for (i = 0; i < geometry->split; i++)
- fprintf(in, "%s\n", pack_basename(geometry->pack[i]));
- for (i = geometry->split; i < geometry->pack_nr; i++)
- fprintf(in, "^%s\n", pack_basename(geometry->pack[i]));
+ for (i = 0; i < geometry.split; i++)
+ fprintf(in, "%s\n", pack_basename(geometry.pack[i]));
+ for (i = geometry.split; i < geometry.pack_nr; i++)
+ fprintf(in, "^%s\n", pack_basename(geometry.pack[i]));
fclose(in);
}
- out = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, out) != EOF) {
- struct string_list_item *item;
-
- if (line.len != the_hash_algo->hexsz)
- die(_("repack: Expecting full hex object ID lines only from pack-objects."));
- item = string_list_append(&names, line.buf);
- item->util = populate_pack_exts(item->string);
- }
- strbuf_release(&line);
- fclose(out);
- ret = finish_command(&cmd);
+ ret = finish_pack_objects_cmd(&cmd, &names, 1);
if (ret)
goto cleanup;
@@ -1033,29 +1416,25 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
printf_ln(_("Nothing new to pack."));
if (pack_everything & PACK_CRUFT) {
- const char *pack_prefix;
- if (!skip_prefix(packtmp, packdir, &pack_prefix))
- die(_("pack prefix %s does not begin with objdir %s"),
- packtmp, packdir);
- if (*pack_prefix == '/')
- pack_prefix++;
+ const char *pack_prefix = find_pack_prefix(packdir, packtmp);
if (!cruft_po_args.window)
- cruft_po_args.window = po_args.window;
+ cruft_po_args.window = xstrdup_or_null(po_args.window);
if (!cruft_po_args.window_memory)
- cruft_po_args.window_memory = po_args.window_memory;
+ cruft_po_args.window_memory = xstrdup_or_null(po_args.window_memory);
if (!cruft_po_args.depth)
- cruft_po_args.depth = po_args.depth;
+ cruft_po_args.depth = xstrdup_or_null(po_args.depth);
if (!cruft_po_args.threads)
- cruft_po_args.threads = po_args.threads;
+ cruft_po_args.threads = xstrdup_or_null(po_args.threads);
+ if (!cruft_po_args.max_pack_size)
+ cruft_po_args.max_pack_size = po_args.max_pack_size;
cruft_po_args.local = po_args.local;
cruft_po_args.quiet = po_args.quiet;
ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
cruft_expiration, &names,
- &existing_nonkept_packs,
- &existing_kept_packs);
+ &existing);
if (ret)
goto cleanup;
@@ -1086,13 +1465,25 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
pack_prefix,
NULL,
&names,
- &existing_nonkept_packs,
- &existing_kept_packs);
+ &existing);
if (ret)
goto cleanup;
}
}
+ if (po_args.filter_options.choice) {
+ if (!filter_to)
+ filter_to = packtmp;
+
+ ret = write_filtered_pack(&po_args,
+ filter_to,
+ find_pack_prefix(packdir, packtmp),
+ &existing,
+ &names);
+ if (ret)
+ goto cleanup;
+ }
+
string_list_sort(&names);
close_object_store(the_repository->objects);
@@ -1131,31 +1522,14 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
}
/* End of pack replacement. */
- if (delete_redundant && pack_everything & ALL_INTO_ONE) {
- const int hexsz = the_hash_algo->hexsz;
- for_each_string_list_item(item, &existing_nonkept_packs) {
- char *sha1;
- size_t len = strlen(item->string);
- if (len < hexsz)
- continue;
- sha1 = item->string + len - hexsz;
- /*
- * Mark this pack for deletion, which ensures that this
- * pack won't be included in a MIDX (if `--write-midx`
- * was given) and that we will actually delete this pack
- * (if `-d` was given).
- */
- if (!string_list_has_string(&names, sha1))
- item->util = (void*)(uintptr_t)((size_t)item->util | DELETE_PACK);
- }
- }
+ if (delete_redundant && pack_everything & ALL_INTO_ONE)
+ mark_packs_for_deletion(&existing, &names);
if (write_midx) {
- struct string_list include = STRING_LIST_INIT_NODUP;
- midx_included_packs(&include, &existing_nonkept_packs,
- &existing_kept_packs, &names, geometry);
+ struct string_list include = STRING_LIST_INIT_DUP;
+ midx_included_packs(&include, &existing, &names, &geometry);
- ret = write_midx_included_packs(&include, geometry,
+ ret = write_midx_included_packs(&include, &geometry, &names,
refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
show_progress, write_bitmaps > 0);
@@ -1172,35 +1546,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant) {
int opts = 0;
- for_each_string_list_item(item, &existing_nonkept_packs) {
- if (!((uintptr_t)item->util & DELETE_PACK))
- continue;
- remove_redundant_pack(packdir, item->string);
- }
-
- if (geometry) {
- struct strbuf buf = STRBUF_INIT;
-
- uint32_t i;
- for (i = 0; i < geometry->split; i++) {
- struct packed_git *p = geometry->pack[i];
- if (string_list_has_string(&names,
- hash_to_hex(p->hash)))
- continue;
+ remove_redundant_existing_packs(&existing);
- strbuf_reset(&buf);
- strbuf_addstr(&buf, pack_basename(p));
- strbuf_strip_suffix(&buf, ".pack");
-
- if ((p->pack_keep) ||
- (string_list_has_string(&existing_kept_packs,
- buf.buf)))
- continue;
-
- remove_redundant_pack(packdir, buf.buf);
- }
- strbuf_release(&buf);
- }
+ if (geometry.split_factor)
+ geometry_remove_redundant_packs(&geometry, &names,
+ &existing);
if (show_progress)
opts |= PRUNE_PACKED_VERBOSE;
prune_packed_objects(opts);
@@ -1217,16 +1567,19 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
unsigned flags = 0;
- if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0))
- flags |= MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX;
- write_midx_file(get_object_directory(), NULL, NULL, flags);
+ if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
+ flags |= MIDX_WRITE_INCREMENTAL;
+ write_midx_file(repo_get_object_directory(the_repository),
+ NULL, NULL, flags);
}
cleanup:
+ string_list_clear(&keep_pack_list, 0);
string_list_clear(&names, 1);
- string_list_clear(&existing_nonkept_packs, 0);
- string_list_clear(&existing_kept_packs, 0);
- free_pack_geometry(geometry);
+ existing_packs_release(&existing);
+ free_pack_geometry(&geometry);
+ pack_objects_args_release(&po_args);
+ pack_objects_args_release(&cruft_po_args);
return ret;
}
diff --git a/builtin/replace.c b/builtin/replace.c
index da59600ad2..a4eaadff91 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -7,11 +7,10 @@
* and Carlos Rica <jasampler@gmail.com> that was itself based on
* git-tag.sh and mktag.c by Linus Torvalds.
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "editor.h"
-#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
@@ -22,7 +21,6 @@
#include "object-name.h"
#include "object-store-ll.h"
#include "replace-object.h"
-#include "repository.h"
#include "tag.h"
#include "wildmatch.h"
@@ -43,11 +41,13 @@ enum replace_format {
};
struct show_data {
+ struct repository *repo;
const char *pattern;
enum replace_format format;
};
-static int show_reference(struct repository *r, const char *refname,
+static int show_reference(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
@@ -62,11 +62,11 @@ static int show_reference(struct repository *r, const char *refname,
struct object_id object;
enum object_type obj_type, repl_type;
- if (repo_get_oid(r, refname, &object))
+ if (repo_get_oid(data->repo, refname, &object))
return error(_("failed to resolve '%s' as a valid ref"), refname);
- obj_type = oid_object_info(r, &object, NULL);
- repl_type = oid_object_info(r, oid, NULL);
+ obj_type = oid_object_info(data->repo, &object, NULL);
+ repl_type = oid_object_info(data->repo, oid, NULL);
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
oid_to_hex(oid), type_name(repl_type));
@@ -80,6 +80,7 @@ static int list_replace_refs(const char *pattern, const char *format)
{
struct show_data data;
+ data.repo = the_repository;
if (!pattern)
pattern = "*";
data.pattern = pattern;
@@ -99,7 +100,8 @@ static int list_replace_refs(const char *pattern, const char *format)
"valid formats are 'short', 'medium' and 'long'"),
format);
- for_each_replace_ref(the_repository, show_reference, (void *)&data);
+ refs_for_each_replace_ref(get_main_ref_store(the_repository),
+ show_reference, (void *)&data);
return 0;
}
@@ -130,7 +132,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
strbuf_addstr(&ref, oid_to_hex(&oid));
full_hex = ref.buf + base_len;
- if (read_ref(ref.buf, &oid)) {
+ if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) {
error(_("replace ref '%s' not found"), full_hex);
had_error = 1;
continue;
@@ -145,7 +147,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
static int delete_replace_ref(const char *name, const char *ref,
const struct object_id *oid)
{
- if (delete_ref(NULL, ref, oid, 0))
+ if (refs_delete_ref(get_main_ref_store(the_repository), NULL, ref, oid, 0))
return 1;
printf_ln(_("Deleted replace ref '%s'"), name);
return 0;
@@ -163,8 +165,8 @@ static int check_ref_valid(struct object_id *object,
if (check_refname_format(ref->buf, 0))
return error(_("'%s' is not a valid ref name"), ref->buf);
- if (read_ref(ref->buf, prev))
- oidclr(prev);
+ if (refs_read_ref(get_main_ref_store(the_repository), ref->buf, prev))
+ oidclr(prev, the_repository->hash_algo);
else if (!force)
return error(_("replace ref '%s' already exists"), ref->buf);
return 0;
@@ -198,10 +200,11 @@ static int replace_object_oid(const char *object_ref,
return -1;
}
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, repl, &prev,
- 0, NULL, &err) ||
+ NULL, NULL, 0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
res = error("%s", err.buf);
@@ -509,7 +512,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
static int convert_graft_file(int force)
{
- const char *graft_file = get_graft_file(the_repository);
+ const char *graft_file = repo_get_graft_file(the_repository);
FILE *fp = fopen_or_warn(graft_file, "r");
struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
struct strvec args = STRVEC_INIT;
@@ -540,7 +543,10 @@ static int convert_graft_file(int force)
return -1;
}
-int cmd_replace(int argc, const char **argv, const char *prefix)
+int cmd_replace(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int force = 0;
int raw = 0;
diff --git a/builtin/replay.c b/builtin/replay.c
new file mode 100644
index 0000000000..2d12a4e403
--- /dev/null
+++ b/builtin/replay.c
@@ -0,0 +1,461 @@
+/*
+ * "git replay" builtin command
+ */
+
+#include "git-compat-util.h"
+
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "environment.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "merge-ort.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "revision.h"
+#include "strmap.h"
+#include <oidset.h>
+#include <tree.h>
+
+static const char *short_commit_name(struct commit *commit)
+{
+ return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV);
+}
+
+static struct commit *peel_committish(const char *name)
+{
+ struct object *obj;
+ struct object_id oid;
+
+ if (repo_get_oid(the_repository, name, &oid))
+ return NULL;
+ obj = parse_object(the_repository, &oid);
+ return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
+ OBJ_COMMIT);
+}
+
+static char *get_author(const char *message)
+{
+ size_t len;
+ const char *a;
+
+ a = find_commit_header(message, "author", &len);
+ if (a)
+ return xmemdupz(a, len);
+
+ return NULL;
+}
+
+static struct commit *create_commit(struct tree *tree,
+ struct commit *based_on,
+ struct commit *parent)
+{
+ struct object_id ret;
+ struct object *obj = NULL;
+ struct commit_list *parents = NULL;
+ char *author;
+ char *sign_commit = NULL; /* FIXME: cli users might want to sign again */
+ struct commit_extra_header *extra = NULL;
+ struct strbuf msg = STRBUF_INIT;
+ const char *out_enc = get_commit_output_encoding();
+ const char *message = repo_logmsg_reencode(the_repository, based_on,
+ NULL, out_enc);
+ const char *orig_message = NULL;
+ const char *exclude_gpgsig[] = { "gpgsig", NULL };
+
+ commit_list_insert(parent, &parents);
+ extra = read_commit_extra_headers(based_on, exclude_gpgsig);
+ find_commit_subject(message, &orig_message);
+ strbuf_addstr(&msg, orig_message);
+ author = get_author(message);
+ reset_ident_date();
+ if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents,
+ &ret, author, NULL, sign_commit, extra)) {
+ error(_("failed to write commit object"));
+ goto out;
+ }
+
+ obj = parse_object(the_repository, &ret);
+
+out:
+ free_commit_extra_headers(extra);
+ free_commit_list(parents);
+ strbuf_release(&msg);
+ free(author);
+ return (struct commit *)obj;
+}
+
+struct ref_info {
+ struct commit *onto;
+ struct strset positive_refs;
+ struct strset negative_refs;
+ int positive_refexprs;
+ int negative_refexprs;
+};
+
+static void get_ref_information(struct rev_cmdline_info *cmd_info,
+ struct ref_info *ref_info)
+{
+ int i;
+
+ ref_info->onto = NULL;
+ strset_init(&ref_info->positive_refs);
+ strset_init(&ref_info->negative_refs);
+ ref_info->positive_refexprs = 0;
+ ref_info->negative_refexprs = 0;
+
+ /*
+ * When the user specifies e.g.
+ * git replay origin/main..mybranch
+ * git replay ^origin/next mybranch1 mybranch2
+ * we want to be able to determine where to replay the commits. In
+ * these examples, the branches are probably based on an old version
+ * of either origin/main or origin/next, so we want to replay on the
+ * newest version of that branch. In contrast we would want to error
+ * out if they ran
+ * git replay ^origin/master ^origin/next mybranch
+ * git replay mybranch~2..mybranch
+ * the first of those because there's no unique base to choose, and
+ * the second because they'd likely just be replaying commits on top
+ * of the same commit and not making any difference.
+ */
+ for (i = 0; i < cmd_info->nr; i++) {
+ struct rev_cmdline_entry *e = cmd_info->rev + i;
+ struct object_id oid;
+ const char *refexpr = e->name;
+ char *fullname = NULL;
+ int can_uniquely_dwim = 1;
+
+ if (*refexpr == '^')
+ refexpr++;
+ if (repo_dwim_ref(the_repository, refexpr, strlen(refexpr), &oid, &fullname, 0) != 1)
+ can_uniquely_dwim = 0;
+
+ if (e->flags & BOTTOM) {
+ if (can_uniquely_dwim)
+ strset_add(&ref_info->negative_refs, fullname);
+ if (!ref_info->negative_refexprs)
+ ref_info->onto = lookup_commit_reference_gently(the_repository,
+ &e->item->oid, 1);
+ ref_info->negative_refexprs++;
+ } else {
+ if (can_uniquely_dwim)
+ strset_add(&ref_info->positive_refs, fullname);
+ ref_info->positive_refexprs++;
+ }
+
+ free(fullname);
+ }
+}
+
+static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
+ const char *onto_name,
+ char **advance_name,
+ struct commit **onto,
+ struct strset **update_refs)
+{
+ struct ref_info rinfo;
+
+ get_ref_information(cmd_info, &rinfo);
+ if (!rinfo.positive_refexprs)
+ die(_("need some commits to replay"));
+ if (onto_name && *advance_name)
+ die(_("--onto and --advance are incompatible"));
+ else if (onto_name) {
+ *onto = peel_committish(onto_name);
+ if (rinfo.positive_refexprs <
+ strset_get_size(&rinfo.positive_refs))
+ die(_("all positive revisions given must be references"));
+ } else if (*advance_name) {
+ struct object_id oid;
+ char *fullname = NULL;
+
+ *onto = peel_committish(*advance_name);
+ if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name),
+ &oid, &fullname, 0) == 1) {
+ free(*advance_name);
+ *advance_name = fullname;
+ } else {
+ die(_("argument to --advance must be a reference"));
+ }
+ if (rinfo.positive_refexprs > 1)
+ die(_("cannot advance target with multiple sources because ordering would be ill-defined"));
+ } else {
+ int positive_refs_complete = (
+ rinfo.positive_refexprs ==
+ strset_get_size(&rinfo.positive_refs));
+ int negative_refs_complete = (
+ rinfo.negative_refexprs ==
+ strset_get_size(&rinfo.negative_refs));
+ /*
+ * We need either positive_refs_complete or
+ * negative_refs_complete, but not both.
+ */
+ if (rinfo.negative_refexprs > 0 &&
+ positive_refs_complete == negative_refs_complete)
+ die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+ if (negative_refs_complete) {
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+ const char *last_key = NULL;
+
+ if (rinfo.negative_refexprs == 0)
+ die(_("all positive revisions given must be references"));
+ else if (rinfo.negative_refexprs > 1)
+ die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+ else if (rinfo.positive_refexprs > 1)
+ die(_("cannot advance target with multiple source branches because ordering would be ill-defined"));
+
+ /* Only one entry, but we have to loop to get it */
+ strset_for_each_entry(&rinfo.negative_refs,
+ &iter, entry) {
+ last_key = entry->key;
+ }
+
+ free(*advance_name);
+ *advance_name = xstrdup_or_null(last_key);
+ } else { /* positive_refs_complete */
+ if (rinfo.negative_refexprs > 1)
+ die(_("cannot implicitly determine correct base for --onto"));
+ if (rinfo.negative_refexprs == 1)
+ *onto = rinfo.onto;
+ }
+ }
+ if (!*advance_name) {
+ *update_refs = xcalloc(1, sizeof(**update_refs));
+ **update_refs = rinfo.positive_refs;
+ memset(&rinfo.positive_refs, 0, sizeof(**update_refs));
+ }
+ strset_clear(&rinfo.negative_refs);
+ strset_clear(&rinfo.positive_refs);
+}
+
+static struct commit *mapped_commit(kh_oid_map_t *replayed_commits,
+ struct commit *commit,
+ struct commit *fallback)
+{
+ khint_t pos = kh_get_oid_map(replayed_commits, commit->object.oid);
+ if (pos == kh_end(replayed_commits))
+ return fallback;
+ return kh_value(replayed_commits, pos);
+}
+
+static struct commit *pick_regular_commit(struct commit *pickme,
+ kh_oid_map_t *replayed_commits,
+ struct commit *onto,
+ struct merge_options *merge_opt,
+ struct merge_result *result)
+{
+ struct commit *base, *replayed_base;
+ struct tree *pickme_tree, *base_tree;
+
+ base = pickme->parents->item;
+ replayed_base = mapped_commit(replayed_commits, base, onto);
+
+ result->tree = repo_get_commit_tree(the_repository, replayed_base);
+ pickme_tree = repo_get_commit_tree(the_repository, pickme);
+ base_tree = repo_get_commit_tree(the_repository, base);
+
+ merge_opt->branch1 = short_commit_name(replayed_base);
+ merge_opt->branch2 = short_commit_name(pickme);
+ merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2);
+
+ merge_incore_nonrecursive(merge_opt,
+ base_tree,
+ result->tree,
+ pickme_tree,
+ result);
+
+ free((char*)merge_opt->ancestor);
+ merge_opt->ancestor = NULL;
+ if (!result->clean)
+ return NULL;
+ return create_commit(result->tree, pickme, replayed_base);
+}
+
+int cmd_replay(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
+{
+ const char *advance_name_opt = NULL;
+ char *advance_name = NULL;
+ struct commit *onto = NULL;
+ const char *onto_name = NULL;
+ int contained = 0;
+
+ struct rev_info revs;
+ struct commit *last_commit = NULL;
+ struct commit *commit;
+ struct merge_options merge_opt;
+ struct merge_result result;
+ struct strset *update_refs = NULL;
+ kh_oid_map_t *replayed_commits;
+ int ret = 0;
+
+ const char * const replay_usage[] = {
+ N_("(EXPERIMENTAL!) git replay "
+ "([--contained] --onto <newbase> | --advance <branch>) "
+ "<revision-range>..."),
+ NULL
+ };
+ struct option replay_options[] = {
+ OPT_STRING(0, "advance", &advance_name_opt,
+ N_("branch"),
+ N_("make replay advance given branch")),
+ OPT_STRING(0, "onto", &onto_name,
+ N_("revision"),
+ N_("replay onto given commit")),
+ OPT_BOOL(0, "contained", &contained,
+ N_("advance all branches contained in revision-range")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, replay_options, replay_usage,
+ PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+ if (!onto_name && !advance_name_opt) {
+ error(_("option --onto or --advance is mandatory"));
+ usage_with_options(replay_usage, replay_options);
+ }
+
+ if (advance_name_opt && contained)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--advance", "--contained");
+ advance_name = xstrdup_or_null(advance_name_opt);
+
+ repo_init_revisions(the_repository, &revs, prefix);
+
+ /*
+ * Set desired values for rev walking options here. If they
+ * are changed by some user specified option in setup_revisions()
+ * below, we will detect that below and then warn.
+ *
+ * TODO: In the future we might want to either die(), or allow
+ * some options changing these values if we think they could
+ * be useful.
+ */
+ revs.reverse = 1;
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ revs.topo_order = 1;
+ revs.simplify_history = 0;
+
+ argc = setup_revisions(argc, argv, &revs, NULL);
+ if (argc > 1) {
+ ret = error(_("unrecognized argument: %s"), argv[1]);
+ goto cleanup;
+ }
+
+ /*
+ * Detect and warn if we override some user specified rev
+ * walking options.
+ */
+ if (revs.reverse != 1) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "reverse");
+ revs.reverse = 1;
+ }
+ if (revs.sort_order != REV_SORT_IN_GRAPH_ORDER) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "sort_order");
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ }
+ if (revs.topo_order != 1) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "topo_order");
+ revs.topo_order = 1;
+ }
+ if (revs.simplify_history != 0) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "simplify_history");
+ revs.simplify_history = 0;
+ }
+
+ determine_replay_mode(&revs.cmdline, onto_name, &advance_name,
+ &onto, &update_refs);
+
+ if (!onto) /* FIXME: Should handle replaying down to root commit */
+ die("Replaying down to root commit is not supported yet!");
+
+ if (prepare_revision_walk(&revs) < 0) {
+ ret = error(_("error preparing revisions"));
+ goto cleanup;
+ }
+
+ init_basic_merge_options(&merge_opt, the_repository);
+ memset(&result, 0, sizeof(result));
+ merge_opt.show_rename_progress = 0;
+ last_commit = onto;
+ replayed_commits = kh_init_oid_map();
+ while ((commit = get_revision(&revs))) {
+ const struct name_decoration *decoration;
+ khint_t pos;
+ int hr;
+
+ if (!commit->parents)
+ die(_("replaying down to root commit is not supported yet!"));
+ if (commit->parents->next)
+ die(_("replaying merge commits is not supported yet!"));
+
+ last_commit = pick_regular_commit(commit, replayed_commits, onto,
+ &merge_opt, &result);
+ if (!last_commit)
+ break;
+
+ /* Record commit -> last_commit mapping */
+ pos = kh_put_oid_map(replayed_commits, commit->object.oid, &hr);
+ if (hr == 0)
+ BUG("Duplicate rewritten commit: %s\n",
+ oid_to_hex(&commit->object.oid));
+ kh_value(replayed_commits, pos) = last_commit;
+
+ /* Update any necessary branches */
+ if (advance_name)
+ continue;
+ decoration = get_name_decoration(&commit->object);
+ if (!decoration)
+ continue;
+ while (decoration) {
+ if (decoration->type == DECORATION_REF_LOCAL &&
+ (contained || strset_contains(update_refs,
+ decoration->name))) {
+ printf("update %s %s %s\n",
+ decoration->name,
+ oid_to_hex(&last_commit->object.oid),
+ oid_to_hex(&commit->object.oid));
+ }
+ decoration = decoration->next;
+ }
+ }
+
+ /* In --advance mode, advance the target ref */
+ if (result.clean == 1 && advance_name) {
+ printf("update %s %s %s\n",
+ advance_name,
+ oid_to_hex(&last_commit->object.oid),
+ oid_to_hex(&onto->object.oid));
+ }
+
+ merge_finalize(&merge_opt, &result);
+ kh_destroy_oid_map(replayed_commits);
+ if (update_refs) {
+ strset_clear(update_refs);
+ free(update_refs);
+ }
+ ret = result.clean;
+
+cleanup:
+ release_revisions(&revs);
+ free(advance_name);
+
+ /* Return */
+ if (ret < 0)
+ exit(128);
+ return ret ? 0 : 1;
+}
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 07a9d37275..f7143c3f5d 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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"
@@ -49,7 +49,10 @@ static int diff_two(const char *file1, const char *label1,
return ret;
}
-int cmd_rerere(int argc, const char **argv, const char *prefix)
+int cmd_rerere(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct string_list merge_rr = STRING_LIST_INIT_DUP;
int i, autoupdate = -1, flags = 0;
@@ -74,11 +77,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[0], "forget")) {
struct pathspec pathspec;
+ int ret;
+
if (argc < 2)
warning(_("'git rerere forget' without paths is deprecated"));
parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
prefix, argv + 1);
- return rerere_forget(the_repository, &pathspec);
+
+ ret = rerere_forget(the_repository, &pathspec);
+
+ clear_pathspec(&pathspec);
+ return ret;
}
if (!strcmp(argv[0], "clear")) {
diff --git a/builtin/reset.c b/builtin/reset.c
index 4b018d20e3..7154f88826 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -7,7 +7,7 @@
*
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -16,10 +16,8 @@
#include "hash.h"
#include "hex.h"
#include "lockfile.h"
-#include "tag.h"
#include "object.h"
#include "pretty.h"
-#include "run-command.h"
#include "refs.h"
#include "diff.h"
#include "diffcore.h"
@@ -28,12 +26,12 @@
#include "object-name.h"
#include "parse-options.h"
#include "path.h"
+#include "repository.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"
@@ -69,8 +67,8 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.fn = oneway_merge;
opts.merge = 1;
init_checkout_metadata(&opts.meta, ref, oid, NULL);
@@ -119,6 +117,10 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
if (reset_type == MIXED || reset_type == HARD) {
tree = parse_tree_indirect(oid);
+ if (!tree) {
+ error(_("unable to read tree (%s)"), oid_to_hex(oid));
+ goto out;
+ }
prime_cache_tree(the_repository, the_repository->index, tree);
}
@@ -158,11 +160,11 @@ static void update_index_from_diff(struct diff_queue_struct *q,
struct cache_entry *ce;
if (!is_in_reset_tree && !intent_to_add) {
- remove_file_from_index(&the_index, one->path);
+ remove_file_from_index(the_repository->index, one->path);
continue;
}
- ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
+ ce = make_cache_entry(the_repository->index, one->mode, &one->oid, one->path,
0, 0);
/*
@@ -173,9 +175,9 @@ static void update_index_from_diff(struct diff_queue_struct *q,
* if this entry is outside the sparse cone - this is necessary
* to properly construct the reset sparse directory.
*/
- pos = index_name_pos(&the_index, one->path, strlen(one->path));
- if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
- (pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
+ pos = index_name_pos(the_repository->index, one->path, strlen(one->path));
+ if ((pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) ||
+ (pos < 0 && !path_in_sparse_checkout(one->path, the_repository->index)))
ce->ce_flags |= CE_SKIP_WORKTREE;
if (!ce)
@@ -185,7 +187,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
ce->ce_flags |= CE_INTENT_TO_ADD;
set_object_name_for_intent_to_add_entry(ce);
}
- add_index_entry(&the_index, ce,
+ add_index_entry(the_repository->index, ce,
ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}
@@ -207,8 +209,8 @@ static int read_from_tree(const struct pathspec *pathspec,
opt.change = diff_change;
opt.add_remove = diff_addremove;
- if (pathspec->nr && pathspec_needs_expanded_index(&the_index, pathspec))
- ensure_full_index(&the_index);
+ if (pathspec->nr && pathspec_needs_expanded_index(the_repository->index, pathspec))
+ ensure_full_index(the_repository->index);
if (do_diff_cache(tree_oid, &opt))
return 1;
@@ -234,7 +236,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,
static void die_if_unmerged_cache(int reset_type)
{
- if (is_merge() || unmerged_index(&the_index))
+ if (is_merge() || unmerged_index(the_repository->index))
die(_("Cannot do a %s reset in the middle of a merge."),
_(reset_type_names[reset_type]));
@@ -284,7 +286,9 @@ static void parse_args(struct pathspec *pathspec,
verify_filename(prefix, argv[0], 1);
}
}
- *rev_ret = rev;
+
+ /* treat '@' as a shortcut for 'HEAD' */
+ *rev_ret = !strcmp("@", rev) ? "HEAD" : rev;
parse_pathspec(pathspec, 0,
PATHSPEC_PREFER_FULL |
@@ -304,13 +308,16 @@ static int reset_refs(const char *rev, const struct object_id *oid)
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,
- UPDATE_REFS_MSG_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+ "ORIG_HEAD", orig, old_orig, 0,
+ UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
- delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
+ refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ "ORIG_HEAD", old_orig, 0);
set_reflog_message(&msg, "updating HEAD", rev);
- update_ref_status = update_ref(msg.buf, "HEAD", oid, orig, 0,
- UPDATE_REFS_MSG_ON_ERR);
+ update_ref_status = refs_update_ref(get_main_ref_store(the_repository),
+ msg.buf, "HEAD", oid, orig, 0,
+ UPDATE_REFS_MSG_ON_ERR);
strbuf_release(&msg);
return update_ref_status;
}
@@ -324,7 +331,10 @@ static int git_reset_config(const char *var, const char *value,
return git_default_config(var, value, ctx, cb);
}
-int cmd_reset(int argc, const char **argv, const char *prefix)
+int cmd_reset(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int reset_type = NONE, update_ref_status = 0, quiet = 0;
int no_refresh = 0;
@@ -435,7 +445,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
else
trace2_cmd_mode(reset_type_names[reset_type]);
- if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree()))
+ if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
setup_work_tree();
if (reset_type == MIXED && is_bare_repository())
@@ -467,12 +477,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
update_ref_status = 1;
goto cleanup;
}
- the_index.updated_skipworktree = 1;
- if (!no_refresh && get_git_work_tree()) {
+ the_repository->index->updated_skipworktree = 1;
+ if (!no_refresh && repo_get_work_tree(the_repository)) {
uint64_t t_begin, t_delta_in_ms;
t_begin = getnanotime();
- refresh_index(&the_index, flags, NULL, NULL,
+ refresh_index(the_repository->index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
if (!quiet && advice_enabled(ADVICE_RESET_NO_REFRESH_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
@@ -498,7 +508,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
free(ref);
}
- if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK))
die(_("Could not write new index file."));
}
@@ -513,7 +523,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (!pathspec.nr)
remove_branch_state(the_repository, 0);
- discard_index(&the_index);
+ discard_index(the_repository->index);
cleanup:
clear_pathspec(&pathspec);
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index ff715d6918..3078787115 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "commit.h"
@@ -7,13 +8,11 @@
#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-name.h"
#include "object-file.h"
#include "object-store-ll.h"
-#include "pack.h"
#include "pack-bitmap.h"
#include "log-tree.h"
#include "graph.h"
@@ -100,7 +99,48 @@ static off_t get_object_disk_usage(struct object *obj)
return size;
}
-static void finish_commit(struct commit *commit);
+static inline void finish_object__ma(struct object *obj)
+{
+ /*
+ * Whether or not we try to dynamically fetch missing objects
+ * from the server, we currently DO NOT have the object. We
+ * can either print, allow (ignore), or conditionally allow
+ * (ignore) them.
+ */
+ switch (arg_missing_action) {
+ case MA_ERROR:
+ die("missing %s object '%s'",
+ type_name(obj->type), oid_to_hex(&obj->oid));
+ return;
+
+ case MA_ALLOW_ANY:
+ return;
+
+ case MA_PRINT:
+ oidset_insert(&missing_objects, &obj->oid);
+ return;
+
+ case MA_ALLOW_PROMISOR:
+ if (is_promisor_object(&obj->oid))
+ return;
+ die("unexpected missing %s object '%s'",
+ type_name(obj->type), oid_to_hex(&obj->oid));
+ return;
+
+ default:
+ BUG("unhandled missing_action");
+ return;
+ }
+}
+
+static void finish_commit(struct commit *commit)
+{
+ free_commit_list(commit->parents);
+ commit->parents = NULL;
+ free_commit_buffer(the_repository->parsed_objects,
+ commit);
+}
+
static void show_commit(struct commit *commit, void *data)
{
struct rev_list_info *info = data;
@@ -108,6 +148,12 @@ static void show_commit(struct commit *commit, void *data)
display_progress(progress, ++progress_counter);
+ if (revs->do_not_die_on_missing_objects &&
+ oidset_contains(&revs->missing_commits, &commit->object.oid)) {
+ finish_object__ma(&commit->object);
+ return;
+ }
+
if (show_disk_usage)
total_disk_usage += get_object_disk_usage(&commit->object);
@@ -174,6 +220,7 @@ static void show_commit(struct commit *commit, void *data)
ctx.fmt = revs->commit_format;
ctx.output_encoding = get_log_output_encoding();
ctx.color = revs->diffopt.use_color;
+ ctx.rev = revs;
pretty_print_commit(&ctx, commit, &buf);
if (buf.len) {
if (revs->commit_format != CMIT_FMT_ONELINE)
@@ -219,48 +266,6 @@ static void show_commit(struct commit *commit, void *data)
finish_commit(commit);
}
-static void finish_commit(struct commit *commit)
-{
- free_commit_list(commit->parents);
- commit->parents = NULL;
- free_commit_buffer(the_repository->parsed_objects,
- commit);
-}
-
-static inline void finish_object__ma(struct object *obj)
-{
- /*
- * Whether or not we try to dynamically fetch missing objects
- * from the server, we currently DO NOT have the object. We
- * can either print, allow (ignore), or conditionally allow
- * (ignore) them.
- */
- switch (arg_missing_action) {
- case MA_ERROR:
- die("missing %s object '%s'",
- type_name(obj->type), oid_to_hex(&obj->oid));
- return;
-
- case MA_ALLOW_ANY:
- return;
-
- case MA_PRINT:
- oidset_insert(&missing_objects, &obj->oid);
- return;
-
- case MA_ALLOW_PROMISOR:
- if (is_promisor_object(&obj->oid))
- return;
- die("unexpected missing %s object '%s'",
- type_name(obj->type), oid_to_hex(&obj->oid));
- return;
-
- default:
- BUG("unhandled missing_action");
- return;
- }
-}
-
static int finish_object(struct object *obj, const char *name UNUSED,
void *cb_data)
{
@@ -480,6 +485,13 @@ static int try_bitmap_traversal(struct rev_info *revs,
if (revs->max_count >= 0)
return -1;
+ /*
+ * We can't know which commits were left/right in a single traversal,
+ * and we don't yet know how to traverse them separately.
+ */
+ if (revs->left_right)
+ return -1;
+
bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -504,10 +516,15 @@ static int try_bitmap_disk_usage(struct rev_info *revs,
size_from_bitmap = get_disk_usage_from_bitmap(bitmap_git, revs);
print_disk_usage(size_from_bitmap);
+
+ free_bitmap_index(bitmap_git);
return 0;
}
-int cmd_rev_list(int argc, const char **argv, const char *prefix)
+int cmd_rev_list(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct rev_info revs;
struct rev_list_info info;
@@ -542,6 +559,18 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
*
* Let "--missing" to conditionally set fetch_if_missing.
*/
+ /*
+ * NEEDSWORK: These loops that attempt to find presence of
+ * options without understanding that the options they are
+ * skipping are broken (e.g., it would not know "--grep
+ * --exclude-promisor-objects" is not triggering
+ * "--exclude-promisor-objects" option). We really need
+ * setup_revisions() to have a mechanism to allow and disallow
+ * some sets of options for different commands (like rev-list,
+ * replay, etc). Such a mechanism should do an early parsing
+ * of options and be able to manage the `--missing=...` and
+ * `--exclude-promisor-objects` options below.
+ */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--exclude-promisor-objects")) {
@@ -561,7 +590,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
}
if (arg_missing_action)
- revs.do_not_die_on_missing_tree = 1;
+ revs.do_not_die_on_missing_objects = 1;
argc = setup_revisions(argc, argv, &revs, &s_r_opt);
@@ -750,8 +779,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (arg_print_omitted)
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
- if (arg_missing_action == MA_PRINT)
+ if (arg_missing_action == MA_PRINT) {
oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
+ /* Add missing tips */
+ oidset_insert_from_set(&missing_objects, &revs.missing_commits);
+ oidset_clear(&revs.missing_commits);
+ }
traverse_commit_list_filtered(
&revs, show_commit, show_object, &info,
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index fde8861ca4..8401b4d7ab 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -3,8 +3,9 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+
#include "abspath.h"
#include "config.h"
#include "commit.h"
@@ -19,12 +20,15 @@
#include "path.h"
#include "diff.h"
#include "read-cache-ll.h"
+#include "repo-settings.h"
+#include "repository.h"
#include "revision.h"
#include "setup.h"
#include "split-index.h"
#include "submodule.h"
#include "commit-reach.h"
#include "shallow.h"
+#include "object-file-convert.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -159,8 +163,9 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
case 1: /* happy */
if (abbrev_ref) {
char *old = full;
- full = shorten_unambiguous_ref(full,
- abbrev_ref_strict);
+ full = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ full,
+ abbrev_ref_strict);
free(old);
}
show_with_type(type, full);
@@ -209,7 +214,7 @@ static int show_default(void)
return 0;
}
-static int show_reference(const char *refname, const struct object_id *oid,
+static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
if (ref_excluded(&ref_excludes, refname))
@@ -218,7 +223,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
return 0;
}
-static int anti_reference(const char *refname, const struct object_id *oid,
+static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
show_rev(REVERSED, oid, refname);
@@ -297,7 +302,7 @@ static int try_difference(const char *arg)
show_rev(NORMAL, &end_oid, end);
show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
if (symmetric) {
- struct commit_list *exclude;
+ struct commit_list *exclude = NULL;
struct commit *a, *b;
a = lookup_commit_reference(the_repository, &start_oid);
b = lookup_commit_reference(the_repository, &end_oid);
@@ -305,7 +310,8 @@ static int try_difference(const char *arg)
*dotdot = '.';
return 0;
}
- exclude = repo_get_merge_bases(the_repository, a, b);
+ if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
+ exit(128);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
show_rev(REVERSED, &commit->object.oid, NULL);
@@ -420,12 +426,12 @@ static char *findspace(const char *s)
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
- static int keep_dashdash = 0, stop_at_non_option = 0;
- static char const * const parseopt_usage[] = {
+ int keep_dashdash = 0, stop_at_non_option = 0;
+ char const * const parseopt_usage[] = {
N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
NULL
};
- static struct option parseopt_opts[] = {
+ struct option parseopt_opts[] = {
OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
N_("keep the `--` passed as an arg")),
OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
@@ -435,12 +441,11 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
N_("output in stuck long form")),
OPT_END(),
};
- static const char * const flag_chars = "*=?!";
-
struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
- const char **usage = NULL;
+ struct strvec longnames = STRVEC_INIT;
+ struct strvec usage = STRVEC_INIT;
struct option *opts = NULL;
- int onb = 0, osz = 0, unb = 0, usz = 0;
+ size_t opts_nr = 0, opts_alloc = 0;
strbuf_addstr(&parsed, "set --");
argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
@@ -450,16 +455,16 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
/* get the usage up to the first line with a -- on it */
for (;;) {
+ strbuf_reset(&sb);
if (strbuf_getline(&sb, stdin) == EOF)
die(_("premature end of input"));
- ALLOC_GROW(usage, unb + 1, usz);
if (!strcmp("--", sb.buf)) {
- if (unb < 1)
+ if (!usage.nr)
die(_("no usage string given before the `--' separator"));
- usage[unb] = NULL;
break;
}
- usage[unb++] = strbuf_detach(&sb, NULL);
+
+ strvec_push(&usage, sb.buf);
}
/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
@@ -471,10 +476,10 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
if (!sb.len)
continue;
- ALLOC_GROW(opts, onb + 1, osz);
- memset(opts + onb, 0, sizeof(opts[onb]));
+ ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
+ memset(opts + opts_nr, 0, sizeof(*opts));
- o = &opts[onb++];
+ o = &opts[opts_nr++];
help = findspace(sb.buf);
if (!help || sb.buf == help) {
o->type = OPTION_GROUP;
@@ -491,20 +496,22 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
o->callback = &parseopt_dump;
/* name(s) */
- s = strpbrk(sb.buf, flag_chars);
+ s = strpbrk(sb.buf, "*=?!");
if (!s)
s = help;
if (s == sb.buf)
die(_("missing opt-spec before option flags"));
- if (s - sb.buf == 1) /* short option only */
+ if (s - sb.buf == 1) { /* short option only */
o->short_name = *sb.buf;
- else if (sb.buf[1] != ',') /* long option only */
- o->long_name = xmemdupz(sb.buf, s - sb.buf);
- else {
+ } else if (sb.buf[1] != ',') { /* long option only */
+ o->long_name = strvec_pushf(&longnames, "%.*s",
+ (int)(s - sb.buf), sb.buf);
+ } else {
o->short_name = *sb.buf;
- o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
+ o->long_name = strvec_pushf(&longnames, "%.*s",
+ (int)(s - sb.buf - 2), sb.buf + 2);
}
/* flags */
@@ -534,9 +541,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
strbuf_release(&sb);
/* put an OPT_END() */
- ALLOC_GROW(opts, onb + 1, osz);
- memset(opts + onb, 0, sizeof(opts[onb]));
- argc = parse_options(argc, argv, prefix, opts, usage,
+ ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
+ memset(opts + opts_nr, 0, sizeof(*opts));
+ argc = parse_options(argc, argv, prefix, opts, usage.v,
(keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
(stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
PARSE_OPT_SHELL_EVAL);
@@ -544,7 +551,16 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
strbuf_addstr(&parsed, " --");
sq_quote_argv(&parsed, argv);
puts(parsed.buf);
+
strbuf_release(&parsed);
+ strbuf_release(&sb);
+ strvec_clear(&longnames);
+ strvec_clear(&usage);
+ for (size_t i = 0; i < opts_nr; i++) {
+ free((char *) opts[i].help);
+ free((char *) opts[i].argh);
+ }
+ free(opts);
return 0;
}
@@ -597,9 +613,12 @@ static int opt_with_value(const char *arg, const char *opt, const char **value)
static void handle_ref_opt(const char *pattern, const char *prefix)
{
if (pattern)
- for_each_glob_ref_in(show_reference, pattern, prefix, NULL);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ show_reference, pattern, prefix,
+ NULL);
else
- for_each_ref_in(prefix, show_reference, NULL);
+ refs_for_each_ref_in(get_main_ref_store(the_repository),
+ prefix, show_reference, NULL);
clear_ref_exclusions(&ref_excludes);
}
@@ -672,9 +691,14 @@ static void print_path(const char *path, const char *prefix, enum format_type fo
free(cwd);
}
-int cmd_rev_parse(int argc, const char **argv, const char *prefix)
+int cmd_rev_parse(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+ const struct git_hash_algo *output_algo = NULL;
+ const struct git_hash_algo *compat = NULL;
int did_repo_setup = 0;
int has_dashdash = 0;
int output_prefix = 0;
@@ -683,7 +707,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
const char *name = NULL;
struct object_context unused;
struct strbuf buf = STRBUF_INIT;
- const int hexsz = the_hash_algo->hexsz;
int seen_end_of_options = 0;
enum format_type format = FORMAT_DEFAULT;
@@ -746,6 +769,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
+ compat = the_repository->compat_hash_algo;
}
if (!strcmp(arg, "--")) {
@@ -833,6 +857,22 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
flags |= GET_OID_QUIETLY;
continue;
}
+ if (opt_with_value(arg, "--output-object-format", &arg)) {
+ if (!arg)
+ die(_("no object format specified"));
+ if (!strcmp(arg, the_hash_algo->name) ||
+ !strcmp(arg, "storage")) {
+ flags |= GET_OID_HASH_ANY;
+ output_algo = the_hash_algo;
+ continue;
+ }
+ else if (compat && !strcmp(arg, compat->name)) {
+ flags |= GET_OID_HASH_ANY;
+ output_algo = compat;
+ continue;
+ }
+ else die(_("unsupported object format: %s"), arg);
+ }
if (opt_with_value(arg, "--short", &arg)) {
filter &= ~(DO_FLAGS|DO_NOREV);
verify = 1;
@@ -842,8 +882,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
abbrev = strtoul(arg, NULL, 10);
if (abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
- else if (hexsz <= abbrev)
- abbrev = hexsz;
+ else if ((int)the_hash_algo->hexsz <= abbrev)
+ abbrev = the_hash_algo->hexsz;
continue;
}
if (!strcmp(arg, "--sq")) {
@@ -864,7 +904,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (opt_with_value(arg, "--abbrev-ref", &arg)) {
abbrev_ref = 1;
- abbrev_ref_strict = warn_ambiguous_refs;
+ abbrev_ref_strict =
+ repo_settings_get_warn_ambiguous_refs(the_repository);
if (arg) {
if (!strcmp(arg, "strict"))
abbrev_ref_strict = 1;
@@ -877,29 +918,38 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--all")) {
- for_each_ref(show_reference, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ show_reference, NULL);
clear_ref_exclusions(&ref_excludes);
continue;
}
if (skip_prefix(arg, "--disambiguate=", &arg)) {
- repo_for_each_abbrev(the_repository, arg,
+ repo_for_each_abbrev(the_repository, arg, the_hash_algo,
show_abbrev, NULL);
continue;
}
if (!strcmp(arg, "--bisect")) {
- for_each_fullref_in("refs/bisect/bad", show_reference, NULL);
- for_each_fullref_in("refs/bisect/good", anti_reference, NULL);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/bisect/bad",
+ NULL, show_reference,
+ NULL);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/bisect/good",
+ NULL, anti_reference,
+ NULL);
continue;
}
if (opt_with_value(arg, "--branches", &arg)) {
if (ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --branches"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--branches");
handle_ref_opt(arg, "refs/heads/");
continue;
}
if (opt_with_value(arg, "--tags", &arg)) {
if (ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --tags"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--tags");
handle_ref_opt(arg, "refs/tags/");
continue;
}
@@ -909,7 +959,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (opt_with_value(arg, "--remotes", &arg)) {
if (ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --remotes"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--remotes");
handle_ref_opt(arg, "refs/remotes/");
continue;
}
@@ -922,7 +973,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--show-toplevel")) {
- const char *work_tree = get_git_work_tree();
+ const char *work_tree = repo_get_work_tree(the_repository);
if (work_tree)
print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
else
@@ -947,7 +998,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
const char *pfx = prefix;
if (!is_inside_work_tree()) {
const char *work_tree =
- get_git_work_tree();
+ repo_get_work_tree(the_repository);
if (work_tree)
printf("%s\n", work_tree);
continue;
@@ -998,7 +1049,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--git-common-dir")) {
- print_path(get_git_common_dir(), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
+ print_path(repo_get_common_dir(the_repository), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
continue;
}
if (!strcmp(arg, "--is-inside-git-dir")) {
@@ -1025,8 +1076,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--shared-index-path")) {
if (repo_read_index(the_repository) < 0)
die(_("Could not read the index"));
- if (the_index.split_index) {
- const struct object_id *oid = &the_index.split_index->base_oid;
+ if (the_repository->index->split_index) {
+ const struct object_id *oid = &the_repository->index->split_index->base_oid;
const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
print_path(path, prefix, format, DEFAULT_RELATIVE);
}
@@ -1059,6 +1110,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(the_hash_algo->name);
continue;
}
+ if (!strcmp(arg, "--show-ref-format")) {
+ puts(ref_storage_format_to_name(the_repository->ref_storage_format));
+ continue;
+ }
if (!strcmp(arg, "--end-of-options")) {
seen_end_of_options = 1;
if (filter & (DO_FLAGS | DO_REVS))
@@ -1083,12 +1138,17 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!get_oid_with_context(the_repository, name,
flags, &oid, &unused)) {
+ object_context_release(&unused);
+ if (output_algo)
+ repo_oid_to_algop(the_repository, &oid,
+ output_algo, &oid);
if (verify)
revs_count++;
else
show_rev(type, &oid, name);
continue;
}
+ object_context_release(&unused);
if (verify)
die_no_single_rev(quiet);
if (has_dashdash)
diff --git a/builtin/revert.c b/builtin/revert.c
index e6f9a1ad26..b7917dddd3 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -1,13 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
#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"
#include "sequencer.h"
#include "branch.h"
@@ -45,6 +43,31 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
}
+enum empty_action {
+ EMPTY_COMMIT_UNSPECIFIED = -1,
+ STOP_ON_EMPTY_COMMIT, /* output errors and stop in the middle of a cherry-pick */
+ DROP_EMPTY_COMMIT, /* skip with a notice message */
+ KEEP_EMPTY_COMMIT, /* keep recording as empty commits */
+};
+
+static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
+{
+ int *opt_value = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ if (!strcmp(arg, "stop"))
+ *opt_value = STOP_ON_EMPTY_COMMIT;
+ else if (!strcmp(arg, "drop"))
+ *opt_value = DROP_EMPTY_COMMIT;
+ else if (!strcmp(arg, "keep"))
+ *opt_value = KEEP_EMPTY_COMMIT;
+ else
+ return error(_("invalid value for '%s': '%s'"), "--empty", arg);
+
+ return 0;
+}
+
static int option_parse_m(const struct option *opt,
const char *arg, int unset)
{
@@ -87,6 +110,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
+ const char sentinel_value;
+ const char *strategy = &sentinel_value;
+ const char *gpg_sign = &sentinel_value;
+ enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
int cmd = 0;
struct option base_options[] = {
OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
@@ -101,10 +128,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
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_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")),
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"),
+ { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END()
};
@@ -116,7 +143,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
- OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
+ OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("deprecated: use --empty=keep instead")),
+ OPT_CALLBACK_F(0, "empty", &empty_opt, "(stop|drop|keep)",
+ N_("how to handle commits that become empty"),
+ PARSE_OPT_NONEG, parse_opt_empty),
OPT_END(),
};
options = parse_options_concat(options, cp_extra);
@@ -136,6 +166,11 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
+ if (opts->action == REPLAY_PICK) {
+ opts->drop_redundant_commits = (empty_opt == DROP_EMPTY_COMMIT);
+ opts->keep_redundant_commits = opts->keep_redundant_commits || (empty_opt == KEEP_EMPTY_COMMIT);
+ }
+
/* implies allow_empty */
if (opts->keep_redundant_commits)
opts->allow_empty = 1;
@@ -147,7 +182,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
/* Check for incompatible command line arguments */
if (cmd) {
- char *this_operation;
+ const char *this_operation;
if (cmd == 'q')
this_operation = "--quit";
else if (cmd == 'c')
@@ -169,6 +204,8 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
"--ff", opts->allow_ff,
"--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
"--no-rerere-autoupdate", opts->allow_rerere_auto == RERERE_NOAUTOUPDATE,
+ "--keep-redundant-commits", opts->keep_redundant_commits,
+ "--empty", empty_opt != EMPTY_COMMIT_UNSPECIFIED,
NULL);
}
@@ -206,8 +243,14 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
usage_with_options(usage_str, options);
/* These option values will be free()d */
- opts->gpg_sign = xstrdup_or_null(opts->gpg_sign);
- opts->strategy = xstrdup_or_null(opts->strategy);
+ if (gpg_sign != &sentinel_value) {
+ free(opts->gpg_sign);
+ opts->gpg_sign = xstrdup_or_null(gpg_sign);
+ }
+ if (strategy != &sentinel_value) {
+ free(opts->strategy);
+ opts->strategy = xstrdup_or_null(strategy);
+ }
if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
free(options);
@@ -227,7 +270,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
return sequencer_pick_revisions(the_repository, opts);
}
-int cmd_revert(int argc, const char **argv, const char *prefix)
+int cmd_revert(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct replay_opts opts = REPLAY_OPTS_INIT;
int res;
@@ -241,7 +287,10 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
return res;
}
-int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
+int cmd_cherry_pick(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
{
struct replay_opts opts = REPLAY_OPTS_INIT;
int res;
diff --git a/builtin/rm.c b/builtin/rm.c
index dff819ae50..eaff027258 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,20 +3,19 @@
*
* Copyright (C) Linus Torvalds 2006
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
#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"
@@ -42,8 +41,8 @@ static int get_ours_cache_pos(const char *path, int pos)
{
int i = -pos - 1;
- while ((i < the_index.cache_nr) && !strcmp(the_index.cache[i]->name, path)) {
- if (ce_stage(the_index.cache[i]) == 2)
+ while ((i < the_repository->index->cache_nr) && !strcmp(the_repository->index->cache[i]->name, path)) {
+ if (ce_stage(the_repository->index->cache[i]) == 2)
return i;
i++;
}
@@ -79,13 +78,13 @@ static void submodules_absorb_gitdir_if_needed(void)
int pos;
const struct cache_entry *ce;
- pos = index_name_pos(&the_index, name, strlen(name));
+ pos = index_name_pos(the_repository->index, name, strlen(name));
if (pos < 0) {
pos = get_ours_cache_pos(name, pos);
if (pos < 0)
continue;
}
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (!S_ISGITLINK(ce->ce_mode) ||
!file_exists(ce->name) ||
@@ -123,7 +122,7 @@ static int check_local_mod(struct object_id *head, int index_only)
int local_changes = 0;
int staged_changes = 0;
- pos = index_name_pos(&the_index, name, strlen(name));
+ pos = index_name_pos(the_repository->index, name, strlen(name));
if (pos < 0) {
/*
* Skip unmerged entries except for populated submodules
@@ -133,11 +132,11 @@ static int check_local_mod(struct object_id *head, int index_only)
if (pos < 0)
continue;
- if (!S_ISGITLINK(the_index.cache[pos]->ce_mode) ||
+ if (!S_ISGITLINK(the_repository->index->cache[pos]->ce_mode) ||
is_empty_dir(name))
continue;
}
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (lstat(ce->name, &st) < 0) {
if (!is_missing_file_error(errno))
@@ -174,7 +173,7 @@ static int check_local_mod(struct object_id *head, int index_only)
* Is the index different from the file in the work tree?
* If it's a submodule, is its work tree modified?
*/
- if (ie_match_stat(&the_index, ce, &st, 0) ||
+ if (ie_match_stat(the_repository->index, ce, &st, 0) ||
(S_ISGITLINK(ce->ce_mode) &&
bad_to_remove_submodule(ce->name,
SUBMODULE_REMOVAL_DIE_ON_ERROR |
@@ -262,7 +261,10 @@ static struct option builtin_rm_options[] = {
OPT_END(),
};
-int cmd_rm(int argc, const char **argv, const char *prefix)
+int cmd_rm(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct lock_file lock_file = LOCK_INIT;
int i, ret = 0;
@@ -302,27 +304,27 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
+ refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
seen = xcalloc(pathspec.nr, 1);
- if (pathspec_needs_expanded_index(&the_index, &pathspec))
- ensure_full_index(&the_index);
+ if (pathspec_needs_expanded_index(the_repository->index, &pathspec))
+ ensure_full_index(the_repository->index);
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
if (!include_sparse &&
(ce_skip_worktree(ce) ||
- !path_in_sparse_checkout(ce->name, &the_index)))
+ !path_in_sparse_checkout(ce->name, the_repository->index)))
continue;
- if (!ce_path_match(&the_index, ce, &pathspec, seen))
+ if (!ce_path_match(the_repository->index, ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
- !is_staging_gitmodules_ok(&the_index))
+ !is_staging_gitmodules_ok(the_repository->index))
die(_("please stage your changes to .gitmodules or stash them to proceed"));
}
@@ -378,7 +380,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!force) {
struct object_id oid;
if (repo_get_oid(the_repository, "HEAD", &oid))
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
if (check_local_mod(&oid, index_only))
exit(1);
}
@@ -392,7 +394,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!quiet)
printf("rm '%s'\n", path);
- if (remove_file_from_index(&the_index, path))
+ if (remove_file_from_index(the_repository->index, path))
die(_("git rm: unable to remove %s"), path);
}
@@ -433,10 +435,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
}
strbuf_release(&buf);
if (gitmodules_modified)
- stage_updated_gitmodules(&the_index);
+ stage_updated_gitmodules(the_repository->index);
}
- if (write_locked_index(&the_index, &lock_file,
+ if (write_locked_index(the_repository->index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index cd6d9e4112..59b626aae8 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,19 +1,15 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
-#include "commit.h"
#include "hex.h"
-#include "refs.h"
#include "pkt-line.h"
-#include "sideband.h"
#include "run-command.h"
#include "remote.h"
#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
-#include "version.h"
#include "oid-array.h"
-#include "gpg-interface.h"
#include "gettext.h"
#include "protocol.h"
#include "parse-options.h"
@@ -135,27 +131,27 @@ static int send_pack_config(const char *k, const char *v,
const struct config_context *ctx, void *cb)
{
if (!strcmp(k, "push.gpgsign")) {
- const char *value;
- if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_parse_maybe_bool(value)) {
- case 0:
- args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
- break;
- case 1:
- args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
- break;
- default:
- if (value && !strcasecmp(value, "if-asked"))
- args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
- else
- return error(_("invalid value for '%s'"), k);
- }
+ switch (git_parse_maybe_bool(v)) {
+ case 0:
+ args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
+ break;
+ case 1:
+ args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
+ break;
+ default:
+ if (!strcasecmp(v, "if-asked"))
+ args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
+ else
+ return error(_("invalid value for '%s'"), k);
}
}
return git_default_config(k, v, ctx, cb);
}
-int cmd_send_pack(int argc, const char **argv, const char *prefix)
+int cmd_send_pack(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct refspec rs = REFSPEC_INIT_PUSH;
const char *remote_name = NULL;
@@ -208,7 +204,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
- OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
+ OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option),
OPT_BOOL(0, TRANS_OPT_FORCE_IF_INCLUDES, &force_if_includes,
@@ -341,7 +337,14 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
}
if (!ret && !transport_refs_pushed(remote_refs))
+ /* stable plumbing output; do not modify or localize */
fprintf(stderr, "Everything up-to-date\n");
+ string_list_clear(&push_options, 0);
+ free_refs(remote_refs);
+ free_refs(local_refs);
+ refspec_clear(&rs);
+ oid_array_clear(&shallow);
+ clear_cas_option(&cas);
return ret;
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 1307ed2b88..c86b75d981 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "commit.h"
@@ -5,7 +6,6 @@
#include "environment.h"
#include "gettext.h"
#include "string-list.h"
-#include "repository.h"
#include "revision.h"
#include "utf8.h"
#include "mailmap.h"
@@ -245,7 +245,6 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
- ctx.print_email_subject = 1;
ctx.date_mode = log->date_mode;
ctx.output_encoding = get_log_output_encoding();
@@ -379,7 +378,10 @@ void shortlog_finish_setup(struct shortlog *log)
string_list_sort(&log->trailers);
}
-int cmd_shortlog(int argc, const char **argv, const char *prefix)
+int cmd_shortlog(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct shortlog log = { STRING_LIST_INIT_NODUP };
struct rev_info rev;
@@ -405,6 +407,18 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
struct parse_opt_ctx_t ctx;
+ /*
+ * NEEDSWORK: Later on we'll call parse_revision_opt which relies on
+ * the hash algorithm being set but since we are operating outside of a
+ * Git repository we cannot determine one. This is only needed because
+ * parse_revision_opt expects hexsz for --abbrev which is irrelevant
+ * for shortlog outside of a git repository. For now explicitly set
+ * SHA1, but ideally the parsing machinery would be split between
+ * git/nongit so that we do not have to do this.
+ */
+ if (nongit && !the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
git_config(git_default_config, NULL);
shortlog_init(&log);
repo_init_revisions(the_repository, &rev, prefix);
@@ -436,7 +450,7 @@ parse_done:
usage_with_options(shortlog_usage, options);
}
- if (setup_revisions(argc, argv, &rev, NULL) != 1) {
+ if (!nongit && setup_revisions(argc, argv, &rev, NULL) != 1) {
error(_("unrecognized argument: %s"), argv[1]);
usage_with_options(shortlog_usage, options);
}
@@ -461,11 +475,8 @@ parse_done:
else
get_from_rev(&rev, &log);
- release_revisions(&rev);
-
shortlog_output(&log);
- if (log.file != stdout)
- fclose(log.file);
+ release_revisions(&rev);
return 0;
}
@@ -518,4 +529,5 @@ void shortlog_output(struct shortlog *log)
string_list_clear(&log->list, 1);
clear_mailmap(&log->mailmap);
string_list_clear(&log->format, 0);
+ string_list_clear(&log->trailers, 0);
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index b01ec761d2..cd6bdf63bc 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "environment.h"
@@ -10,7 +11,7 @@
#include "strvec.h"
#include "object-name.h"
#include "parse-options.h"
-#include "repository.h"
+
#include "dir.h"
#include "commit-slab.h"
#include "date.h"
@@ -410,7 +411,7 @@ static int append_ref(const char *refname, const struct object_id *oid,
return 0;
}
-static int append_head_ref(const char *refname, const struct object_id *oid,
+static int append_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id tmp;
@@ -425,7 +426,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
return append_ref(refname + ofs, oid, 0);
}
-static int append_remote_ref(const char *refname, const struct object_id *oid,
+static int append_remote_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id tmp;
@@ -451,7 +452,7 @@ static int append_tag_ref(const char *refname, const struct object_id *oid,
static const char *match_ref_pattern = NULL;
static int match_ref_slash = 0;
-static int append_matching_ref(const char *refname, const struct object_id *oid,
+static int append_matching_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
/* we want to allow pattern hold/<asterisk> to show all
@@ -468,7 +469,7 @@ static int append_matching_ref(const char *refname, const struct object_id *oid,
if (wildmatch(match_ref_pattern, tail, 0))
return 0;
if (starts_with(refname, "refs/heads/"))
- return append_head_ref(refname, oid, flag, cb_data);
+ return append_head_ref(refname, NULL, oid, flag, cb_data);
if (starts_with(refname, "refs/tags/"))
return append_tag_ref(refname, oid, flag, cb_data);
return append_ref(refname, oid, 0);
@@ -479,13 +480,15 @@ static void snarf_refs(int head, int remotes)
if (head) {
int orig_cnt = ref_name_cnt;
- for_each_ref(append_head_ref, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_head_ref, NULL);
sort_ref_range(orig_cnt, ref_name_cnt);
}
if (remotes) {
int orig_cnt = ref_name_cnt;
- for_each_ref(append_remote_ref, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_remote_ref, NULL);
sort_ref_range(orig_cnt, ref_name_cnt);
}
}
@@ -500,14 +503,14 @@ static int rev_is_head(const char *head, const char *name)
return !strcmp(head, name);
}
-static int show_merge_base(struct commit_list *seen, int num_rev)
+static int show_merge_base(const struct commit_list *seen, int num_rev)
{
int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
int exit_status = 1;
- while (seen) {
- struct commit *commit = pop_commit(&seen);
+ for (const struct commit_list *s = seen; s; s = s->next) {
+ struct commit *commit = s->item;
int flags = commit->object.flags & all_mask;
if (!(flags & UNINTERESTING) &&
((flags & all_revs) == all_revs)) {
@@ -549,7 +552,8 @@ static void append_one_rev(const char *av)
match_ref_pattern = av;
match_ref_slash = count_slashes(av);
- for_each_ref(append_matching_ref, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_matching_ref, NULL);
if (saved_matches == ref_name_cnt &&
ref_name_cnt < MAX_REVS)
error(_("no matching refs with %s"), av);
@@ -629,10 +633,13 @@ static int parse_reflog_param(const struct option *opt, const char *arg,
return 0;
}
-int cmd_show_branch(int ac, const char **av, const char *prefix)
+int cmd_show_branch(int ac,
+ const char **av,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct commit *rev[MAX_REVS], *commit;
- char *reflog_msg[MAX_REVS];
+ char *reflog_msg[MAX_REVS] = {0};
struct commit_list *list = NULL, *seen = NULL;
unsigned int rev_mask[MAX_REVS];
int num_rev, i, extra = 0;
@@ -689,6 +696,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
parse_reflog_param),
OPT_END()
};
+ const char **args_copy = NULL;
+ int ret;
init_commit_name_slab(&name_slab);
@@ -696,8 +705,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
/* If nothing is specified, try the default first */
if (ac == 1 && default_args.nr) {
+ DUP_ARRAY(args_copy, default_args.v, default_args.nr);
ac = default_args.nr;
- av = default_args.v;
+ av = args_copy;
}
ac = parse_options(ac, av, prefix, builtin_show_branch_options,
@@ -740,9 +750,11 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (ac == 0) {
static const char *fake_av[2];
- fake_av[0] = resolve_refdup("HEAD",
- RESOLVE_REF_READING, &oid,
- NULL);
+ fake_av[0] = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD",
+ RESOLVE_REF_READING,
+ &oid,
+ NULL);
fake_av[1] = NULL;
av = fake_av;
ac = 1;
@@ -775,7 +787,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
}
for (i = 0; i < reflog; i++) {
- char *logmsg;
+ char *logmsg = NULL;
char *nth_desc;
const char *msg;
char *end;
@@ -785,6 +797,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (read_ref_at(get_main_ref_store(the_repository),
ref, flags, 0, base + i, &oid, &logmsg,
&timestamp, &tz, NULL)) {
+ free(logmsg);
reflog = i;
break;
}
@@ -815,8 +828,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
snarf_refs(all_heads, all_remotes);
}
- head = resolve_refdup("HEAD", RESOLVE_REF_READING,
- &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ RESOLVE_REF_READING,
+ &head_oid, NULL);
if (with_current_branch && head) {
int has_head = 0;
@@ -836,7 +850,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (!ref_name_cnt) {
fprintf(stderr, "No revs to be shown.\n");
- exit(0);
+ ret = 0;
+ goto out;
}
for (num_rev = 0; ref_name[num_rev]; num_rev++) {
@@ -873,11 +888,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
commit_list_sort_by_date(&seen);
- if (merge_base)
- return show_merge_base(seen, num_rev);
+ if (merge_base) {
+ ret = show_merge_base(seen, num_rev);
+ goto out;
+ }
- if (independent)
- return show_independent(rev, num_rev, rev_mask);
+ if (independent) {
+ ret = show_independent(rev, num_rev, rev_mask);
+ goto out;
+ }
/* Show list; --more=-1 means list-only */
if (1 < num_rev || extra < 0) {
@@ -913,8 +932,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
putchar('\n');
}
}
- if (extra < 0)
- exit(0);
+ if (extra < 0) {
+ ret = 0;
+ goto out;
+ }
/* Sort topologically */
sort_in_topological_order(&seen, sort_order);
@@ -926,8 +947,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
- while (seen) {
- struct commit *commit = pop_commit(&seen);
+ for (struct commit_list *l = seen; l; l = l->next) {
+ struct commit *commit = l->item;
int this_flag = commit->object.flags;
int is_merge_point = ((this_flag & all_revs) == all_revs);
@@ -967,6 +988,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (shown_merge_point && --extra < 0)
break;
}
+
+ ret = 0;
+
+out:
+ for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++)
+ free(reflog_msg[i]);
+ free_commit_list(seen);
+ free_commit_list(list);
+ free(args_copy);
free(head);
- return 0;
+ return ret;
}
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 540dc3dad1..f164c01bbe 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -1,17 +1,20 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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>]",
NULL
};
-int cmd_show_index(int argc, const char **argv, const char *prefix)
+int cmd_show_index(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i;
unsigned nr;
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 5110814f79..285cd3e433 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,29 +1,36 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
#include "hex.h"
-#include "refs.h"
+#include "refs/refs-internal.h"
#include "object-name.h"
#include "object-store-ll.h"
#include "object.h"
-#include "tag.h"
#include "string-list.h"
#include "parse-options.h"
static const char * const show_ref_usage[] = {
- N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
- " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
- " [--heads] [--] [<pattern>...]"),
+ N_("git show-ref [--head] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+ " [--] [<pattern>...]"),
+ N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+ " [--] [<ref>...]"),
N_("git show-ref --exclude-existing[=<pattern>]"),
+ N_("git show-ref --exists <ref>"),
NULL
};
-static int deref_tags, show_head, tags_only, heads_only, found_match, verify,
- quiet, hash_only, abbrev, exclude_arg;
-static const char **pattern;
-static const char *exclude_existing_arg;
+struct show_one_options {
+ int quiet;
+ int hash_only;
+ int abbrev;
+ int deref_tags;
+};
-static void show_one(const char *refname, const struct object_id *oid)
+static void show_one(const struct show_one_options *opts,
+ const char *refname, const struct object_id *oid)
{
const char *hex;
struct object_id peeled;
@@ -32,33 +39,42 @@ static void show_one(const char *refname, const struct object_id *oid)
die("git show-ref: bad ref %s (%s)", refname,
oid_to_hex(oid));
- if (quiet)
+ if (opts->quiet)
return;
- hex = repo_find_unique_abbrev(the_repository, oid, abbrev);
- if (hash_only)
+ hex = repo_find_unique_abbrev(the_repository, oid, opts->abbrev);
+ if (opts->hash_only)
printf("%s\n", hex);
else
printf("%s %s\n", hex, refname);
- if (!deref_tags)
+ if (!opts->deref_tags)
return;
- if (!peel_iterated_oid(oid, &peeled)) {
- hex = repo_find_unique_abbrev(the_repository, &peeled, abbrev);
+ if (!peel_iterated_oid(the_repository, oid, &peeled)) {
+ hex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);
printf("%s %s^{}\n", hex, refname);
}
}
-static int show_ref(const char *refname, const struct object_id *oid,
- int flag UNUSED, void *cbdata UNUSED)
+struct show_ref_data {
+ const struct show_one_options *show_one_opts;
+ const char **patterns;
+ int found_match;
+ int show_head;
+};
+
+static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+ int flag UNUSED, void *cbdata)
{
- if (show_head && !strcmp(refname, "HEAD"))
+ struct show_ref_data *data = cbdata;
+
+ if (data->show_head && !strcmp(refname, "HEAD"))
goto match;
- if (pattern) {
+ if (data->patterns) {
int reflen = strlen(refname);
- const char **p = pattern, *m;
+ const char **p = data->patterns, *m;
while ((m = *p++) != NULL) {
int len = strlen(m);
if (len > reflen)
@@ -74,14 +90,15 @@ static int show_ref(const char *refname, const struct object_id *oid,
}
match:
- found_match++;
+ data->found_match++;
- show_one(refname, oid);
+ show_one(data->show_one_opts, refname, oid);
return 0;
}
static int add_existing(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cbdata)
{
@@ -90,6 +107,15 @@ static int add_existing(const char *refname,
return 0;
}
+struct exclude_existing_options {
+ /*
+ * We need an explicit `enabled` field because it is perfectly valid
+ * for `pattern` to be `NULL` even if `--exclude-existing` was given.
+ */
+ int enabled;
+ const char *pattern;
+};
+
/*
* read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
* and
@@ -99,13 +125,14 @@ static int add_existing(const char *refname,
* (4) ignore if refname is a ref that exists in the local repository;
* (5) otherwise output the line.
*/
-static int exclude_existing(const char *match)
+static int cmd_show_ref__exclude_existing(const struct exclude_existing_options *opts)
{
- static struct string_list existing_refs = STRING_LIST_INIT_DUP;
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
char buf[1024];
- int matchlen = match ? strlen(match) : 0;
+ int patternlen = opts->pattern ? strlen(opts->pattern) : 0;
- for_each_ref(add_existing, &existing_refs);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_existing,
+ &existing_refs);
while (fgets(buf, sizeof(buf), stdin)) {
char *ref;
int len = strlen(buf);
@@ -119,11 +146,11 @@ static int exclude_existing(const char *match)
for (ref = buf + len; buf < ref; ref--)
if (isspace(ref[-1]))
break;
- if (match) {
+ if (opts->pattern) {
int reflen = buf + len - ref;
- if (reflen < matchlen)
+ if (reflen < patternlen)
continue;
- if (strncmp(ref, match, matchlen))
+ if (strncmp(ref, opts->pattern, patternlen))
continue;
}
if (check_refname_format(ref, 0)) {
@@ -134,97 +161,183 @@ static int exclude_existing(const char *match)
printf("%s\n", buf);
}
}
+
+ string_list_clear(&existing_refs, 0);
+ return 0;
+}
+
+static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
+ const char **refs)
+{
+ if (!refs || !*refs)
+ die("--verify requires a reference");
+
+ while (*refs) {
+ struct object_id oid;
+
+ if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
+ !refs_read_ref(get_main_ref_store(the_repository), *refs, &oid)) {
+ show_one(show_one_opts, *refs, &oid);
+ }
+ else if (!show_one_opts->quiet)
+ die("'%s' - not a valid ref", *refs);
+ else
+ return 1;
+ refs++;
+ }
+
return 0;
}
+struct patterns_options {
+ int show_head;
+ int branches_only;
+ int tags_only;
+};
+
+static int cmd_show_ref__patterns(const struct patterns_options *opts,
+ const struct show_one_options *show_one_opts,
+ const char **patterns)
+{
+ struct show_ref_data show_ref_data = {
+ .show_one_opts = show_one_opts,
+ .show_head = opts->show_head,
+ };
+
+ if (patterns && *patterns)
+ show_ref_data.patterns = patterns;
+
+ if (opts->show_head)
+ refs_head_ref(get_main_ref_store(the_repository), show_ref,
+ &show_ref_data);
+ if (opts->branches_only || opts->tags_only) {
+ if (opts->branches_only)
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/heads/", NULL,
+ show_ref, &show_ref_data);
+ if (opts->tags_only)
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/tags/", NULL, show_ref,
+ &show_ref_data);
+ } else {
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ show_ref, &show_ref_data);
+ }
+ if (!show_ref_data.found_match)
+ return 1;
+
+ return 0;
+}
+
+static int cmd_show_ref__exists(const char **refs)
+{
+ struct strbuf unused_referent = STRBUF_INIT;
+ struct object_id unused_oid;
+ unsigned int unused_type;
+ int failure_errno = 0;
+ const char *ref;
+ int ret = 0;
+
+ if (!refs || !*refs)
+ die("--exists requires a reference");
+ ref = *refs++;
+ if (*refs)
+ die("--exists requires exactly one reference");
+
+ if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
+ &unused_oid, &unused_referent, &unused_type,
+ &failure_errno)) {
+ if (failure_errno == ENOENT || failure_errno == EISDIR) {
+ error(_("reference does not exist"));
+ ret = 2;
+ } else {
+ errno = failure_errno;
+ error_errno(_("failed to look up reference"));
+ ret = 1;
+ }
+
+ goto out;
+ }
+
+out:
+ strbuf_release(&unused_referent);
+ return ret;
+}
+
static int hash_callback(const struct option *opt, const char *arg, int unset)
{
- hash_only = 1;
+ struct show_one_options *opts = opt->value;
+ struct option abbrev_opt = *opt;
+
+ opts->hash_only = 1;
/* Use full length SHA1 if no argument */
if (!arg)
return 0;
- return parse_opt_abbrev_cb(opt, arg, unset);
+
+ abbrev_opt.value = &opts->abbrev;
+ return parse_opt_abbrev_cb(&abbrev_opt, arg, unset);
}
static int exclude_existing_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct exclude_existing_options *opts = opt->value;
BUG_ON_OPT_NEG(unset);
- exclude_arg = 1;
- *(const char **)opt->value = arg;
+ opts->enabled = 1;
+ opts->pattern = arg;
return 0;
}
-static const struct option show_ref_options[] = {
- OPT_BOOL(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
- OPT_BOOL(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
- OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
- "requires exact ref path")),
- OPT_HIDDEN_BOOL('h', NULL, &show_head,
- N_("show the HEAD reference, even if it would be filtered out")),
- OPT_BOOL(0, "head", &show_head,
- N_("show the HEAD reference, even if it would be filtered out")),
- OPT_BOOL('d', "dereference", &deref_tags,
- N_("dereference tags into object IDs")),
- OPT_CALLBACK_F('s', "hash", &abbrev, N_("n"),
- N_("only show SHA1 hash using <n> digits"),
- PARSE_OPT_OPTARG, &hash_callback),
- OPT__ABBREV(&abbrev),
- OPT__QUIET(&quiet,
- N_("do not print results to stdout (useful with --verify)")),
- OPT_CALLBACK_F(0, "exclude-existing", &exclude_existing_arg,
- N_("pattern"), N_("show refs from stdin that aren't in local repository"),
- PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback),
- OPT_END()
-};
-
-int cmd_show_ref(int argc, const char **argv, const char *prefix)
+int cmd_show_ref(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
{
+ struct exclude_existing_options exclude_existing_opts = {0};
+ struct patterns_options patterns_opts = {0};
+ struct show_one_options show_one_opts = {0};
+ int verify = 0, exists = 0;
+ const struct option show_ref_options[] = {
+ OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with --branches)")),
+ OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with --tags)")),
+ OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only,
+ N_("deprecated synonym for --branches")),
+ OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
+ OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
+ "requires exact ref path")),
+ OPT_HIDDEN_BOOL('h', NULL, &patterns_opts.show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL(0, "head", &patterns_opts.show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL('d', "dereference", &show_one_opts.deref_tags,
+ N_("dereference tags into object IDs")),
+ OPT_CALLBACK_F('s', "hash", &show_one_opts, N_("n"),
+ N_("only show SHA1 hash using <n> digits"),
+ PARSE_OPT_OPTARG, &hash_callback),
+ OPT__ABBREV(&show_one_opts.abbrev),
+ OPT__QUIET(&show_one_opts.quiet,
+ N_("do not print results to stdout (useful with --verify)")),
+ OPT_CALLBACK_F(0, "exclude-existing", &exclude_existing_opts,
+ N_("pattern"), N_("show refs from stdin that aren't in local repository"),
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback),
+ OPT_END()
+ };
+
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, show_ref_options,
show_ref_usage, 0);
- if (exclude_arg)
- return exclude_existing(exclude_existing_arg);
-
- pattern = argv;
- if (!*pattern)
- pattern = NULL;
-
- if (verify) {
- if (!pattern)
- die("--verify requires a reference");
- while (*pattern) {
- struct object_id oid;
-
- if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) &&
- !read_ref(*pattern, &oid)) {
- show_one(*pattern, &oid);
- }
- else if (!quiet)
- die("'%s' - not a valid ref", *pattern);
- else
- return 1;
- pattern++;
- }
- return 0;
- }
+ die_for_incompatible_opt3(exclude_existing_opts.enabled, "--exclude-existing",
+ verify, "--verify",
+ exists, "--exists");
- if (show_head)
- head_ref(show_ref, NULL);
- if (heads_only || tags_only) {
- if (heads_only)
- for_each_fullref_in("refs/heads/", show_ref, NULL);
- if (tags_only)
- for_each_fullref_in("refs/tags/", show_ref, NULL);
- } else {
- for_each_ref(show_ref, NULL);
- }
- if (!found_match) {
- if (verify && !quiet)
- die("No match");
- return 1;
- }
- return 0;
+ if (exclude_existing_opts.enabled)
+ return cmd_show_ref__exclude_existing(&exclude_existing_opts);
+ else if (verify)
+ return cmd_show_ref__verify(&show_one_opts, argv);
+ else if (exists)
+ return cmd_show_ref__exists(argv);
+ else
+ return cmd_show_ref__patterns(&patterns_opts, &show_one_opts, argv);
}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 5c8ffb1f75..698d93a9ec 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "dir.h"
@@ -7,15 +8,10 @@
#include "object-name.h"
#include "parse-options.h"
#include "pathspec.h"
-#include "repository.h"
-#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
-#include "cache-tree.h"
#include "lockfile.h"
-#include "resolve-undo.h"
#include "unpack-trees.h"
-#include "wt-status.h"
#include "quote.h"
#include "setup.h"
#include "sparse-index.h"
@@ -100,10 +96,11 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
printf("\n");
}
- return 0;
+ string_list_clear(&sl, 0);
+ } else {
+ write_patterns_to_file(stdout, &pl);
}
- write_patterns_to_file(stdout, &pl);
clear_pattern_list(&pl);
return 0;
@@ -209,11 +206,13 @@ static int update_working_directory(struct pattern_list *pl)
struct unpack_trees_options o;
struct lock_file lock_file = LOCK_INIT;
struct repository *r = the_repository;
+ struct pattern_list *old_pl;
/* If no branch has been checked out, there are no updates to make. */
if (is_index_unborn(r->index))
return UPDATE_SPARSITY_SUCCESS;
+ old_pl = r->index->sparse_checkout_patterns;
r->index->sparse_checkout_patterns = pl;
memset(&o, 0, sizeof(o));
@@ -245,7 +244,12 @@ static int update_working_directory(struct pattern_list *pl)
clean_tracked_sparse_directories(r);
- r->index->sparse_checkout_patterns = NULL;
+ if (r->index->sparse_checkout_patterns != pl) {
+ clear_pattern_list(r->index->sparse_checkout_patterns);
+ FREE_AND_NULL(r->index->sparse_checkout_patterns);
+ }
+ r->index->sparse_checkout_patterns = old_pl;
+
return result;
}
@@ -315,13 +319,14 @@ static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
fprintf(fp, "%s/\n", pattern);
free(pattern);
}
+
+ string_list_clear(&sl, 0);
}
static int write_patterns_and_update(struct pattern_list *pl)
{
char *sparse_filename;
FILE *fp;
- int fd;
struct lock_file lk = LOCK_INIT;
int result;
@@ -330,31 +335,31 @@ static int write_patterns_and_update(struct pattern_list *pl)
if (safe_create_leading_directories(sparse_filename))
die(_("failed to create directory for sparse-checkout file"));
- fd = hold_lock_file_for_update(&lk, sparse_filename,
- LOCK_DIE_ON_ERROR);
- free(sparse_filename);
+ hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
result = update_working_directory(pl);
if (result) {
rollback_lock_file(&lk);
- clear_pattern_list(pl);
update_working_directory(NULL);
- return result;
+ goto out;
}
- fp = xfdopen(fd, "w");
+ fp = fdopen_lock_file(&lk, "w");
+ if (!fp)
+ die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
if (core_sparse_checkout_cone)
write_cone_to_file(fp, pl);
else
write_patterns_to_file(fp, pl);
- fflush(fp);
- commit_lock_file(&lk);
+ if (commit_lock_file(&lk))
+ die_errno(_("unable to write %s"), sparse_filename);
+out:
clear_pattern_list(pl);
-
- return 0;
+ free(sparse_filename);
+ return result;
}
enum sparse_checkout_mode {
@@ -444,7 +449,6 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
char *sparse_filename;
int res;
struct object_id oid;
- struct strbuf pattern = STRBUF_INIT;
static struct option builtin_sparse_checkout_init_options[] = {
OPT_BOOL(0, "cone", &init_opts.cone_mode,
@@ -475,6 +479,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
/* If we already have a sparse-checkout file, use it. */
if (res >= 0) {
free(sparse_filename);
+ clear_pattern_list(&pl);
return update_working_directory(NULL);
}
@@ -495,10 +500,10 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
return 0;
}
- strbuf_addstr(&pattern, "/*");
- add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
- strbuf_addstr(&pattern, "!/*/");
- add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
+ free(sparse_filename);
+
+ add_pattern("/*", empty_base, 0, &pl, 0);
+ add_pattern("!/*/", empty_base, 0, &pl, 0);
pl.use_cone_patterns = init_opts.cone_mode;
return write_patterns_and_update(&pl);
@@ -517,6 +522,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
char *slash = strrchr(e->pattern, '/');
char *oldpattern = e->pattern;
size_t newlen;
+ struct pattern_entry *dup;
if (!slash || slash == e->pattern)
break;
@@ -527,8 +533,14 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
e->pattern = xstrndup(oldpattern, newlen);
hashmap_entry_init(&e->ent, fspathhash(e->pattern));
- if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
+ dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
+ if (!dup) {
hashmap_add(&pl->parent_hashmap, &e->ent);
+ } else {
+ free(e->pattern);
+ free(e);
+ e = dup;
+ }
}
}
@@ -585,15 +597,15 @@ static void add_patterns_from_input(struct pattern_list *pl,
strbuf_to_cone_pattern(&line, pl);
}
}
+ strbuf_release(&line);
} else {
if (file) {
struct strbuf line = STRBUF_INIT;
- while (!strbuf_getline(&line, file)) {
- size_t len;
- char *buf = strbuf_detach(&line, &len);
- add_pattern(buf, empty_base, 0, pl, 0);
- }
+ while (!strbuf_getline(&line, file))
+ add_pattern(line.buf, empty_base, 0, pl, 0);
+
+ strbuf_release(&line);
} else {
for (i = 0; i < argc; i++)
add_pattern(argv[i], empty_base, 0, pl, 0);
@@ -657,7 +669,7 @@ static void add_patterns_literal(int argc, const char **argv,
add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
}
-static int modify_pattern_list(int argc, const char **argv, int use_stdin,
+static int modify_pattern_list(struct strvec *args, int use_stdin,
enum modify_type m)
{
int result;
@@ -667,13 +679,13 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
switch (m) {
case ADD:
if (core_sparse_checkout_cone)
- add_patterns_cone_mode(argc, argv, pl, use_stdin);
+ add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
else
- add_patterns_literal(argc, argv, pl, use_stdin);
+ add_patterns_literal(args->nr, args->v, pl, use_stdin);
break;
case REPLACE:
- add_patterns_from_input(pl, argc, argv,
+ add_patterns_from_input(pl, args->nr, args->v,
use_stdin ? stdin : NULL);
break;
}
@@ -694,12 +706,12 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
return result;
}
-static void sanitize_paths(int argc, const char **argv,
+static void sanitize_paths(struct strvec *args,
const char *prefix, int skip_checks)
{
int i;
- if (!argc)
+ if (!args->nr)
return;
if (prefix && *prefix && core_sparse_checkout_cone) {
@@ -709,8 +721,11 @@ static void sanitize_paths(int argc, const char **argv,
*/
int prefix_len = strlen(prefix);
- for (i = 0; i < argc; i++)
- argv[i] = prefix_path(prefix, prefix_len, argv[i]);
+ for (i = 0; i < args->nr; i++) {
+ char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
+ strvec_replace(args, i, prefixed_path);
+ free(prefixed_path);
+ }
}
if (skip_checks)
@@ -720,20 +735,20 @@ static void sanitize_paths(int argc, const char **argv,
die(_("please run from the toplevel directory in non-cone mode"));
if (core_sparse_checkout_cone) {
- for (i = 0; i < argc; i++) {
- if (argv[i][0] == '/')
+ for (i = 0; i < args->nr; i++) {
+ if (args->v[i][0] == '/')
die(_("specify directories rather than patterns (no leading slash)"));
- if (argv[i][0] == '!')
+ if (args->v[i][0] == '!')
die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
- if (strpbrk(argv[i], "*?[]"))
+ if (strpbrk(args->v[i], "*?[]"))
die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
}
}
- for (i = 0; i < argc; i++) {
+ for (i = 0; i < args->nr; i++) {
struct cache_entry *ce;
struct index_state *index = the_repository->index;
- int pos = index_name_pos(index, argv[i], strlen(argv[i]));
+ int pos = index_name_pos(index, args->v[i], strlen(args->v[i]));
if (pos < 0)
continue;
@@ -742,9 +757,9 @@ static void sanitize_paths(int argc, const char **argv,
continue;
if (core_sparse_checkout_cone)
- die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), argv[i]);
+ die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
else
- warning(_("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)."), argv[i]);
+ warning(_("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)."), args->v[i]);
}
}
@@ -768,6 +783,8 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
N_("read patterns from standard in")),
OPT_END(),
};
+ struct strvec patterns = STRVEC_INIT;
+ int ret;
setup_work_tree();
if (!core_apply_sparse_checkout)
@@ -777,12 +794,16 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_add_options,
- builtin_sparse_checkout_add_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_add_usage, 0);
+
+ for (int i = 0; i < argc; i++)
+ strvec_push(&patterns, argv[i]);
+ sanitize_paths(&patterns, prefix, add_opts.skip_checks);
- sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
+ ret = modify_pattern_list(&patterns, add_opts.use_stdin, ADD);
- return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD);
+ strvec_clear(&patterns);
+ return ret;
}
static char const * const builtin_sparse_checkout_set_usage[] = {
@@ -815,6 +836,8 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
PARSE_OPT_NONEG),
OPT_END(),
};
+ struct strvec patterns = STRVEC_INIT;
+ int ret;
setup_work_tree();
repo_read_index(the_repository);
@@ -824,8 +847,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_set_options,
- builtin_sparse_checkout_set_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_set_usage, 0);
if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
return 1;
@@ -835,14 +857,19 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
* non-cone mode, if nothing is specified, manually select just the
* top-level directory (much as 'init' would do).
*/
- if (!core_sparse_checkout_cone && argc == 0) {
- argv = default_patterns;
- argc = default_patterns_nr;
+ if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
+ for (int i = 0; i < default_patterns_nr; i++)
+ strvec_push(&patterns, default_patterns[i]);
} else {
- sanitize_paths(argc, argv, prefix, set_opts.skip_checks);
+ for (int i = 0; i < argc; i++)
+ strvec_push(&patterns, argv[i]);
+ sanitize_paths(&patterns, prefix, set_opts.skip_checks);
}
- return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE);
+ ret = modify_pattern_list(&patterns, set_opts.use_stdin, REPLACE);
+
+ strvec_clear(&patterns);
+ return ret;
}
static char const * const builtin_sparse_checkout_reapply_usage[] = {
@@ -897,7 +924,6 @@ static int sparse_checkout_disable(int argc, const char **argv,
OPT_END(),
};
struct pattern_list pl;
- struct strbuf match_all = STRBUF_INIT;
/*
* We do not exit early if !core_apply_sparse_checkout; due to the
@@ -915,6 +941,11 @@ static int sparse_checkout_disable(int argc, const char **argv,
builtin_sparse_checkout_disable_options,
builtin_sparse_checkout_disable_usage, 0);
+ /*
+ * Disable the advice message for expanding a sparse index, as we
+ * are expecting to do that when disabling sparse-checkout.
+ */
+ give_advice_on_expansion = 0;
repo_read_index(the_repository);
memset(&pl, 0, sizeof(pl));
@@ -923,8 +954,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
pl.use_cone_patterns = 0;
core_apply_sparse_checkout = 1;
- strbuf_addstr(&match_all, "/*");
- add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0);
+ add_pattern("/*", empty_base, 0, &pl, 0);
prepare_repo_settings(the_repository);
the_repository->settings.sparse_index = 0;
@@ -996,8 +1026,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_check_rules_options,
- builtin_sparse_checkout_check_rules_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_check_rules_usage, 0);
if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
check_rules_opts.cone_mode = 1;
@@ -1018,10 +1047,14 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
ret = check_rules(&pl, check_rules_opts.null_termination);
clear_pattern_list(&pl);
+ free(check_rules_opts.rules_file);
return ret;
}
-int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
+int cmd_sparse_checkout(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option builtin_sparse_checkout_options[] = {
diff --git a/builtin/stash.c b/builtin/stash.c
index 53e8868ba1..1399a1bbe2 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "config.h"
@@ -20,13 +20,13 @@
#include "entry.h"
#include "preload-index.h"
#include "read-cache.h"
+#include "repository.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"
#include "reflog.h"
#include "add-interactive.h"
@@ -197,7 +197,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
commit = argv[0];
if (!commit) {
- if (!ref_exists(ref_stash)) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) {
fprintf_ln(stderr, _("No stash entries found."));
return -1;
}
@@ -245,7 +245,8 @@ static int do_clear_stash(void)
if (repo_get_oid(the_repository, ref_stash, &obj))
return 0;
- return delete_ref(NULL, ref_stash, &obj, 0);
+ return refs_delete_ref(get_main_ref_store(the_repository), NULL,
+ ref_stash, &obj, 0);
}
static int clear_stash(int argc, const char **argv, const char *prefix)
@@ -274,7 +275,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
struct lock_file lock_file = LOCK_INIT;
repo_read_index_preload(the_repository, NULL, 0);
- if (refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL))
+ if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL))
return -1;
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -285,11 +286,11 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
if (parse_tree(tree))
return -1;
- init_tree_desc(t, tree->buffer, tree->size);
+ init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size);
opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
+ opts.src_index = the_repository->index;
+ opts.dst_index = the_repository->index;
opts.merge = 1;
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
opts.update = update;
@@ -300,7 +301,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
if (unpack_trees(nr_trees, t, &opts))
return -1;
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
return error(_("unable to write new index file"));
return 0;
@@ -362,7 +363,7 @@ static int is_path_a_directory(const char *path)
}
static void add_diff_to_buf(struct diff_queue_struct *q,
- struct diff_options *options,
+ struct diff_options *options UNUSED,
void *data)
{
int i;
@@ -431,7 +432,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
state.force = 1;
state.quiet = 1;
state.refresh_cache = 1;
- state.istate = &the_index;
+ state.istate = the_repository->index;
/*
* Step 1: get a difference between orig_tree (which corresponding
@@ -455,7 +456,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
/* Look up the path's position in the current index. */
p = diff_queued_diff.queue[i];
- pos = index_name_pos(&the_index, p->two->path,
+ pos = index_name_pos(the_repository->index, p->two->path,
strlen(p->two->path));
/*
@@ -466,10 +467,10 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* path, but left it out of the working tree, then clear the
* SKIP_WORKTREE bit and write it to the working tree.
*/
- if (pos >= 0 && ce_skip_worktree(the_index.cache[pos])) {
+ if (pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) {
struct stat st;
- ce = the_index.cache[pos];
+ ce = the_repository->index->cache[pos];
if (!lstat(ce->name, &st)) {
/* Conflicting path present; relocate it */
struct strbuf new_path = STRBUF_INIT;
@@ -485,7 +486,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
" to make room.\n"),
ce->name, new_path.buf);
if (rename(ce->name, new_path.buf))
- die("Failed to move %s to %s\n",
+ die("Failed to move %s to %s",
ce->name, new_path.buf);
strbuf_release(&new_path);
}
@@ -505,12 +506,12 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
if (pos < 0)
option = ADD_CACHE_OK_TO_ADD;
- ce = make_cache_entry(&the_index,
+ ce = make_cache_entry(the_repository->index,
p->one->mode,
&p->one->oid,
p->one->path,
0, 0);
- add_index_entry(&the_index, ce, option);
+ add_index_entry(the_repository->index, ce, option);
}
}
diff_flush(&diff_opts);
@@ -519,9 +520,9 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* Step 4: write the new index to disk
*/
repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
- if (write_locked_index(&the_index, &lock,
+ if (write_locked_index(the_repository->index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die(_("Unable to write index."));
+ die(_("could not write index"));
}
static int do_apply_stash(const char *prefix, struct stash_info *info,
@@ -538,10 +539,10 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
repo_read_index_preload(the_repository, NULL, 0);
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
NULL, NULL, NULL))
- return -1;
+ return error(_("could not write index"));
- if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
- NULL))
+ if (write_index_as_tree(&c_tree, the_repository->index,
+ repo_get_index_file(the_repository), 0, NULL))
return error(_("cannot apply a stash in the middle of a merge"));
if (index) {
@@ -563,19 +564,19 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
return error(_("conflicts in index. "
"Try without --index."));
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
- if (write_index_as_tree(&index_tree, &the_index,
- get_index_file(), 0, NULL))
+ if (write_index_as_tree(&index_tree, the_repository->index,
+ repo_get_index_file(the_repository), 0, NULL))
return error(_("could not save index tree"));
reset_head();
- discard_index(&the_index);
+ discard_index(the_repository->index);
repo_read_index(the_repository);
}
}
- init_merge_options(&o, the_repository);
+ init_ui_merge_options(&o, the_repository);
o.branch1 = "Updated upstream";
o.branch2 = "Stashed changes";
@@ -641,9 +642,9 @@ restore_untracked:
cp.git_cmd = 1;
cp.dir = prefix;
strvec_pushf(&cp.env, GIT_WORK_TREE_ENVIRONMENT"=%s",
- absolute_path(get_git_work_tree()));
+ absolute_path(repo_get_work_tree(the_repository)));
strvec_pushf(&cp.env, GIT_DIR_ENVIRONMENT"=%s",
- absolute_path(get_git_dir()));
+ absolute_path(repo_get_git_dir(the_repository)));
strvec_push(&cp.args, "status");
run_command(&cp);
}
@@ -688,7 +689,8 @@ static int reject_reflog_ent(struct object_id *ooid UNUSED,
static int reflog_is_empty(const char *refname)
{
- return !for_each_reflog_ent(refname, reject_reflog_ent, NULL);
+ return !refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ refname, reject_reflog_ent, NULL);
}
static int do_drop_stash(struct stash_info *info, int quiet)
@@ -825,7 +827,7 @@ static int list_stash(int argc, const char **argv, const char *prefix)
git_stash_list_usage,
PARSE_OPT_KEEP_UNKNOWN_OPT);
- if (!ref_exists(ref_stash))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash))
return 0;
cp.git_cmd = 1;
@@ -871,12 +873,13 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op
tree[i] = parse_tree_indirect(oid[i]);
if (parse_tree(tree[i]) < 0)
die(_("failed to parse tree"));
- init_tree_desc(&tree_desc[i], tree[i]->buffer, tree[i]->size);
+ init_tree_desc(&tree_desc[i], &tree[i]->object.oid,
+ tree[i]->buffer, tree[i]->size);
}
unpack_tree_opt.head_idx = -1;
- unpack_tree_opt.src_index = &the_index;
- unpack_tree_opt.dst_index = &the_index;
+ unpack_tree_opt.src_index = the_repository->index;
+ unpack_tree_opt.dst_index = the_repository->index;
unpack_tree_opt.merge = 1;
unpack_tree_opt.fn = stash_worktree_untracked_merge;
@@ -973,8 +976,10 @@ static int show_stash(int argc, const char **argv, const char *prefix)
}
log_tree_diff_flush(&rev);
- ret = diff_result_code(&rev.diffopt);
+ ret = diff_result_code(&rev);
+
cleanup:
+ strvec_clear(&revision_args);
strvec_clear(&stash_args);
free_stash_info(&info);
release_revisions(&rev);
@@ -989,13 +994,19 @@ usage:
static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
int quiet)
{
+ struct stash_info info;
+ char revision[GIT_MAX_HEXSZ];
+
+ oid_to_hex_r(revision, w_commit);
+ assert_stash_like(&info, revision);
+
if (!stash_msg)
stash_msg = "Created via \"git stash store\".";
- if (update_ref(stash_msg, ref_stash, w_commit, NULL,
- REF_FORCE_CREATE_REFLOG,
- quiet ? UPDATE_REFS_QUIET_ON_ERR :
- UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), stash_msg, ref_stash, w_commit, NULL,
+ REF_FORCE_CREATE_REFLOG,
+ quiet ? UPDATE_REFS_QUIET_ON_ERR :
+ UPDATE_REFS_MSG_ON_ERR)) {
if (!quiet) {
fprintf_ln(stderr, _("Cannot update %s with %s"),
ref_stash, oid_to_hex(w_commit));
@@ -1011,13 +1022,14 @@ static int store_stash(int argc, const char **argv, const char *prefix)
int quiet = 0;
const char *stash_msg = NULL;
struct object_id obj;
- struct object_context dummy;
+ struct object_context dummy = {0};
struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet")),
OPT_STRING('m', "message", &stash_msg, "message",
N_("stash message")),
OPT_END()
};
+ int ret;
argc = parse_options(argc, argv, prefix, options,
git_stash_store_usage,
@@ -1036,10 +1048,15 @@ static int store_stash(int argc, const char **argv, const char *prefix)
if (!quiet)
fprintf_ln(stderr, _("Cannot update %s with %s"),
ref_stash, argv[0]);
- return -1;
+ ret = -1;
+ goto out;
}
- return do_store_stash(&obj, stash_msg, quiet);
+ ret = do_store_stash(&obj, stash_msg, quiet);
+
+out:
+ object_context_release(&dummy);
+ return ret;
}
static void add_pathspecs(struct strvec *args,
@@ -1111,13 +1128,13 @@ static int check_changes_tracked_files(const struct pathspec *ps)
diff_setup_done(&rev.diffopt);
run_diff_index(&rev, DIFF_INDEX_CACHED);
- if (diff_result_code(&rev.diffopt)) {
+ if (diff_result_code(&rev)) {
ret = 1;
goto done;
}
run_diff_files(&rev, 0);
- if (diff_result_code(&rev.diffopt)) {
+ if (diff_result_code(&rev)) {
ret = 1;
goto done;
}
@@ -1199,8 +1216,8 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
}
cp_diff_tree.git_cmd = 1;
- strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD",
- oid_to_hex(&info->w_tree), "--", NULL);
+ strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "--binary",
+ "-U1", "HEAD", oid_to_hex(&info->w_tree), "--", NULL);
if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
ret = -1;
goto done;
@@ -1359,7 +1376,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
repo_read_index_preload(the_repository, NULL, 0);
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
NULL, NULL, NULL) < 0) {
- ret = -1;
+ ret = error(_("could not write index"));
goto done;
}
@@ -1378,7 +1395,8 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
goto done;
}
- branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
+ branch_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
if (flags & REF_ISSYMREF)
skip_prefix(branch_ref, "refs/heads/", &branch_name);
head_short_sha1 = repo_find_unique_abbrev(the_repository,
@@ -1389,8 +1407,8 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
commit_list_insert(head_commit, &parents);
- if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0,
- NULL) ||
+ if (write_index_as_tree(&info->i_tree, the_repository->index,
+ repo_get_index_file(the_repository), 0, NULL) ||
commit_tree(commit_tree_label.buf, commit_tree_label.len,
&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
if (!quiet)
@@ -1400,6 +1418,9 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
goto done;
}
+ free_commit_list(parents);
+ parents = NULL;
+
if (include_untracked) {
if (save_untracked_files(info, &msg, untracked_files)) {
if (!quiet)
@@ -1445,11 +1466,6 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
else
strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name);
- /*
- * `parents` will be empty after calling `commit_tree()`, so there is
- * no need to call `free_commit_list()`
- */
- parents = NULL;
if (untracked_commit_option)
commit_list_insert(lookup_commit(the_repository,
&info->u_commit),
@@ -1471,6 +1487,7 @@ done:
strbuf_release(&commit_tree_label);
strbuf_release(&msg);
strbuf_release(&untracked_files);
+ free_commit_list(parents);
return ret;
}
@@ -1506,6 +1523,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
struct strbuf patch = STRBUF_INIT;
struct strbuf stash_msg_buf = STRBUF_INIT;
struct strbuf untracked_files = STRBUF_INIT;
+ struct strbuf out = STRBUF_INIT;
if (patch_mode && keep_index == -1)
keep_index = 1;
@@ -1534,9 +1552,9 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
char *ps_matched = xcalloc(ps->nr, 1);
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < the_index.cache_nr; i++)
- ce_path_match(&the_index, the_index.cache[i], ps,
+ ensure_full_index(the_repository->index);
+ for (i = 0; i < the_repository->index->cache_nr; i++)
+ ce_path_match(the_repository->index, the_repository->index->cache[i], ps,
ps_matched);
if (report_path_error(ps_matched, ps)) {
@@ -1550,7 +1568,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
NULL, NULL, NULL)) {
- ret = -1;
+ ret = error(_("could not write index"));
goto done;
}
@@ -1560,7 +1578,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
- if (!reflog_exists(ref_stash) && do_clear_stash()) {
+ if (!refs_reflog_exists(get_main_ref_store(the_repository), ref_stash) && do_clear_stash()) {
ret = -1;
if (!quiet)
fprintf_ln(stderr, _("Cannot initialize stash"));
@@ -1606,12 +1624,11 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
}
- discard_index(&the_index);
+ discard_index(the_repository->index);
if (ps->nr) {
struct child_process cp_add = CHILD_PROCESS_INIT;
struct child_process cp_diff = CHILD_PROCESS_INIT;
struct child_process cp_apply = CHILD_PROCESS_INIT;
- struct strbuf out = STRBUF_INIT;
cp_add.git_cmd = 1;
strvec_push(&cp_add.args, "add");
@@ -1656,7 +1673,28 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
}
- if (keep_index == 1 && !is_null_oid(&info.i_tree)) {
+ /*
+ * When keeping staged entries, we need to reset the working
+ * directory to match the state of our index. This can be
+ * skipped when the index is the empty tree, because there is
+ * nothing to reset in that case:
+ *
+ * - When the index has any file, regardless of whether
+ * staged or not, the tree cannot be empty by definition
+ * and thus we enter the condition.
+ *
+ * - When the index has no files, the only thing we need to
+ * care about is untracked files when `--include-untracked`
+ * is given. But as we already execute git-clean(1) further
+ * up to delete such untracked files we don't have to do
+ * anything here, either.
+ *
+ * We thus skip calling git-checkout(1) in this case, also
+ * because running it on an empty tree will cause it to fail
+ * due to the pathspec not matching anything.
+ */
+ if (keep_index == 1 && !is_null_oid(&info.i_tree) &&
+ !is_empty_tree_oid(&info.i_tree, the_repository->hash_algo)) {
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
@@ -1703,6 +1741,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
done:
strbuf_release(&patch);
+ strbuf_release(&out);
free_stash_info(&info);
strbuf_release(&stash_msg_buf);
strbuf_release(&untracked_files);
@@ -1720,7 +1759,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
int quiet = 0;
int pathspec_file_nul = 0;
const char *stash_msg = NULL;
- const char *pathspec_from_file = NULL;
+ char *pathspec_from_file = NULL;
struct pathspec ps;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
@@ -1782,7 +1821,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,
ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
include_untracked, only_staged);
+
clear_pathspec(&ps);
+ free(pathspec_from_file);
return ret;
}
@@ -1834,7 +1875,10 @@ static int save_stash(int argc, const char **argv, const char *prefix)
return ret;
}
-int cmd_stash(int argc, const char **argv, const char *prefix)
+int cmd_stash(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
pid_t pid = getpid();
const char *index_file;
@@ -1854,6 +1898,8 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
OPT_END()
};
+ const char **args_copy;
+ int ret;
git_config(git_stash_config, NULL);
@@ -1865,7 +1911,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- index_file = get_index_file();
+ index_file = repo_get_index_file(the_repository);
strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
(uintmax_t)pid);
@@ -1877,5 +1923,16 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
/* Assume 'stash push' */
strvec_push(&args, "push");
strvec_pushv(&args, argv);
- return !!push_stash(args.nr, args.v, prefix, 1);
+
+ /*
+ * `push_stash()` ends up modifying the array, which causes memory
+ * leaks if we didn't copy the array here.
+ */
+ DUP_ARRAY(args_copy, args.v, args.nr);
+
+ ret = !!push_stash(args.nr, args_copy, prefix, 1);
+
+ strvec_clear(&args);
+ free(args_copy);
+ return ret;
}
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 7b700a9fb1..e147f3ff92 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "environment.h"
@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)
size_t len;
msg = strbuf_detach(buf, &len);
- strbuf_add_commented_lines(buf, msg, len, comment_line_char);
+ strbuf_add_commented_lines(buf, msg, len, comment_line_str);
free(msg);
}
@@ -29,7 +30,10 @@ enum stripspace_mode {
COMMENT_LINES
};
-int cmd_stripspace(int argc, const char **argv, const char *prefix)
+int cmd_stripspace(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct strbuf buf = STRBUF_INIT;
enum stripspace_mode mode = STRIP_DEFAULT;
@@ -59,7 +63,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
strbuf_stripspace(&buf,
- mode == STRIP_COMMENTS ? comment_line_char : '\0');
+ mode == STRIP_COMMENTS ? comment_line_str : NULL);
else
comment_lines(&buf);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index cb42ce95b4..b6b5f1ebde 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1,10 +1,10 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
-#include "repository.h"
+
#include "config.h"
#include "parse-options.h"
#include "quote.h"
@@ -22,7 +22,6 @@
#include "remote.h"
#include "refs.h"
#include "refspec.h"
-#include "connect.h"
#include "revision.h"
#include "diffcore.h"
#include "diff.h"
@@ -208,18 +207,18 @@ static int module_list_compute(const char **argv,
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- for (i = 0; i < the_index.cache_nr; i++) {
- const struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ const struct cache_entry *ce = the_repository->index->cache[i];
- if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),
+ if (!match_pathspec(the_repository->index, pathspec, ce->name, ce_namelen(ce),
0, ps_matched, 1) ||
!S_ISGITLINK(ce->ce_mode))
continue;
ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
list->entries[list->nr++] = ce;
- while (i + 1 < the_index.cache_nr &&
- !strcmp(ce->name, the_index.cache[i + 1]->name))
+ while (i + 1 < the_repository->index->cache_nr &&
+ !strcmp(ce->name, the_repository->index->cache[i + 1]->name))
/*
* Skip entries with the same name in different stages
* to make sure an entry is returned only once.
@@ -258,11 +257,9 @@ static void module_list_active(struct module_list *list)
static char *get_up_path(const char *path)
{
- int i;
struct strbuf sb = STRBUF_INIT;
- for (i = count_slashes(path); i; i--)
- strbuf_addstr(&sb, "../");
+ strbuf_addstrings(&sb, "../", count_slashes(path));
/*
* Check if 'path' ends with slash or not
@@ -367,9 +364,13 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
if (!info->quiet)
printf(_("Entering '%s'\n"), displaypath);
- if (info->argv[0] && run_command(&cp))
- die(_("run_command returned non-zero status for %s\n."),
- displaypath);
+ if (info->argv[0]) {
+ if (run_command(&cp))
+ die(_("run_command returned non-zero status for %s\n."),
+ displaypath);
+ } else {
+ child_process_clear(&cp);
+ }
if (info->recursive) {
struct child_process cpr = CHILD_PROCESS_INIT;
@@ -380,8 +381,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
NULL);
- strvec_pushl(&cpr.args, "--super-prefix", NULL);
- strvec_pushf(&cpr.args, "%s/", displaypath);
+ strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath);
if (info->quiet)
strvec_push(&cpr.args, "--quiet");
@@ -613,6 +613,7 @@ static void print_status(unsigned int flags, char state, const char *path,
}
static int handle_submodule_head_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data)
@@ -676,12 +677,13 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
run_diff_files(&rev, 0);
- if (!diff_result_code(&rev.diffopt)) {
+ if (!diff_result_code(&rev)) {
print_status(flags, ' ', path, ce_oid,
displaypath);
} else if (!(flags & OPT_CACHED)) {
struct object_id oid;
- struct ref_store *refs = get_submodule_ref_store(path);
+ struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
+ path);
if (!refs) {
print_status(flags, '-', path, ce_oid, displaypath);
@@ -698,6 +700,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
if (flags & OPT_RECURSIVE) {
struct child_process cpr = CHILD_PROCESS_INIT;
+ int res;
cpr.git_cmd = 1;
cpr.dir = path;
@@ -705,8 +708,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
strvec_pushl(&cpr.args, "submodule--helper", "status",
"--recursive", NULL);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
+ strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath);
if (flags & OPT_CACHED)
strvec_push(&cpr.args, "--cached");
@@ -714,7 +716,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
if (flags & OPT_QUIET)
strvec_push(&cpr.args, "--quiet");
- if (run_command(&cpr))
+ res = run_command(&cpr);
+ if (res == SIGPIPE + 128)
+ raise(SIGPIPE);
+ else if (res)
die(_("failed to recurse into submodule '%s'"), path);
}
@@ -905,7 +910,8 @@ static void generate_submodule_summary(struct summary_cb *info,
if (!info->cached && oideq(&p->oid_dst, null_oid())) {
if (S_ISGITLINK(p->mod_dst)) {
- struct ref_store *refs = get_submodule_ref_store(p->sm_path);
+ struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
+ p->sm_path);
if (refs)
refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
@@ -914,13 +920,13 @@ static void generate_submodule_summary(struct summary_cb *info,
int fd = open(p->sm_path, O_RDONLY);
if (fd < 0 || fstat(fd, &st) < 0 ||
- index_fd(&the_index, &p->oid_dst, fd, &st, OBJ_BLOB,
+ index_fd(the_repository->index, &p->oid_dst, fd, &st, OBJ_BLOB,
p->sm_path, 0))
error(_("couldn't hash object from '%s'"), p->sm_path);
} else {
/* for a submodule removal (mode:0000000), don't warn */
if (p->mod_dst)
- warning(_("unexpected mode %o\n"), p->mod_dst);
+ warning(_("unexpected mode %o"), p->mod_dst);
}
}
@@ -1293,7 +1299,7 @@ static void sync_submodule(const char *path, const char *prefix,
submodule_to_gitdir(&sb, path);
strbuf_addstr(&sb, "/config");
- if (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))
+ if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
die(_("failed to update remote for submodule '%s'"),
path);
@@ -1306,9 +1312,7 @@ static void sync_submodule(const char *path, const char *prefix,
strvec_pushl(&cpr.args, "submodule--helper", "sync",
"--recursive", NULL);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
-
+ strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath);
if (flags & OPT_QUIET)
strvec_push(&cpr.args, "--quiet");
@@ -1461,7 +1465,7 @@ static void deinit_submodule(const char *path, const char *prefix,
* remove the whole section so we have a clean state when
* the user later decides to init this submodule again
*/
- git_config_rename_section_in_file(NULL, sub_key, NULL);
+ repo_config_rename_section_in_file(the_repository, NULL, sub_key, NULL);
if (!(flags & OPT_QUIET))
printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"),
sub->name, sub->url, displaypath);
@@ -1536,8 +1540,9 @@ struct module_clone_data {
const char *path;
const char *name;
const char *url;
- const char *depth;
+ int depth;
struct list_objects_filter_options *filter_options;
+ enum ref_storage_format ref_storage_format;
unsigned int quiet: 1;
unsigned int progress: 1;
unsigned int dissociate: 1;
@@ -1546,6 +1551,7 @@ struct module_clone_data {
};
#define MODULE_CLONE_DATA_INIT { \
.single_branch = -1, \
+ .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
}
struct submodule_alternate_setup {
@@ -1620,6 +1626,8 @@ static int add_possible_reference_from_superproject(
; /* nothing */
}
}
+
+ strbuf_release(&err);
strbuf_release(&sb);
}
@@ -1712,7 +1720,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
exit(128);
if (!is_absolute_path(clone_data->path))
- clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
+ clone_data_path = to_free = xstrfmt("%s/%s", repo_get_work_tree(the_repository),
clone_data->path);
if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
@@ -1735,8 +1743,8 @@ static int clone_submodule(const struct module_clone_data *clone_data,
strvec_push(&cp.args, "--quiet");
if (clone_data->progress)
strvec_push(&cp.args, "--progress");
- if (clone_data->depth && *(clone_data->depth))
- strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
+ if (clone_data->depth > 0)
+ strvec_pushf(&cp.args, "--depth=%d", clone_data->depth);
if (reference->nr) {
struct string_list_item *item;
@@ -1744,6 +1752,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
strvec_pushl(&cp.args, "--reference",
item->string, NULL);
}
+ if (clone_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(&cp.args, "--ref-format=%s",
+ ref_storage_format_to_name(clone_data->ref_storage_format));
if (clone_data->dissociate)
strvec_push(&cp.args, "--dissociate");
if (sm_gitdir && *sm_gitdir)
@@ -1838,6 +1849,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
struct string_list reference = STRING_LIST_INIT_NODUP;
struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT;
+ const char *ref_storage_format = NULL;
struct option module_clone_options[] = {
OPT_STRING(0, "prefix", &clone_data.prefix,
@@ -1855,10 +1867,11 @@ static int module_clone(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "reference", &reference,
N_("repo"),
N_("reference repository")),
+ OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &dissociate,
N_("use --reference only while cloning")),
- OPT_STRING(0, "depth", &clone_data.depth,
- N_("string"),
+ OPT_INTEGER(0, "depth", &clone_data.depth,
N_("depth for shallow clones")),
OPT__QUIET(&quiet, "suppress output for cloning a submodule"),
OPT_BOOL(0, "progress", &progress,
@@ -1881,6 +1894,11 @@ static int module_clone(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_clone_options,
git_submodule_helper_usage, 0);
+ if (ref_storage_format) {
+ clone_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+ if (clone_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_storage_format);
+ }
clone_data.dissociate = !!dissociate;
clone_data.quiet = !!quiet;
clone_data.progress = !!progress;
@@ -1980,6 +1998,7 @@ struct update_data {
struct submodule_update_strategy update_strategy;
struct list_objects_filter_options *filter_options;
struct module_list list;
+ enum ref_storage_format ref_storage_format;
int depth;
int max_jobs;
int single_branch;
@@ -2003,6 +2022,7 @@ struct update_data {
#define UPDATE_DATA_INIT { \
.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
.list = MODULE_LIST_INIT, \
+ .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
.recommend_shallow = -1, \
.references = STRING_LIST_INIT_DUP, \
.single_branch = -1, \
@@ -2012,6 +2032,7 @@ struct update_data {
static void update_data_release(struct update_data *ud)
{
free(ud->displaypath);
+ submodule_update_strategy_release(&ud->update_strategy);
module_list_release(&ud->list);
}
@@ -2138,6 +2159,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
expand_list_objects_filter_spec(suc->update_data->filter_options));
if (suc->update_data->require_init)
strvec_push(&child->args, "--require-init");
+ if (suc->update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(&child->args, "--ref-format=%s",
+ ref_storage_format_to_name(suc->update_data->ref_storage_format));
strvec_pushl(&child->args, "--path", sub->path, NULL);
strvec_pushl(&child->args, "--name", sub->name, NULL);
strvec_pushl(&child->args, "--url", url, NULL);
@@ -2275,6 +2299,7 @@ static int is_tip_reachable(const char *path, const struct object_id *oid)
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf rev = STRBUF_INIT;
char *hex = oid_to_hex(oid);
+ int reachable;
cp.git_cmd = 1;
cp.dir = path;
@@ -2284,9 +2309,12 @@ static int is_tip_reachable(const char *path, const struct object_id *oid)
prepare_submodule_repo_env(&cp.env);
if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len)
- return 0;
+ reachable = 0;
+ else
+ reachable = 1;
- return 1;
+ strbuf_release(&rev);
+ return reachable;
}
static int fetch_in_submodule(const char *module_path, int depth, int quiet,
@@ -2305,7 +2333,14 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet,
strvec_pushf(&cp.args, "--depth=%d", depth);
if (oid) {
char *hex = oid_to_hex(oid);
- char *remote = get_default_remote();
+ char *remote;
+ int code;
+
+ code = get_default_remote_submodule(module_path, &remote);
+ if (code) {
+ child_process_clear(&cp);
+ return code;
+ }
strvec_pushl(&cp.args, remote, hex, NULL);
free(remote);
@@ -2458,7 +2493,9 @@ static int remote_submodule_branch(const char *path, const char **branch)
}
if (!strcmp(*branch, ".")) {
- const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+ const char *refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL,
+ NULL);
if (!refname)
return die_message(_("No such ref: %s"), "HEAD");
@@ -2534,10 +2571,9 @@ static void update_data_to_args(const struct update_data *update_data,
enum submodule_update_type update_type = update_data->update_default;
strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
- if (update_data->displaypath) {
- strvec_push(args, "--super-prefix");
- strvec_pushf(args, "%s/", update_data->displaypath);
- }
+ if (update_data->displaypath)
+ strvec_pushf(args, "--super-prefix=%s/",
+ update_data->displaypath);
strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
if (update_data->quiet)
strvec_push(args, "--quiet");
@@ -2567,6 +2603,9 @@ static void update_data_to_args(const struct update_data *update_data,
for_each_string_list_item(item, &update_data->references)
strvec_pushl(args, "--reference", item->string, NULL);
}
+ if (update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(args, "--ref-format=%s",
+ ref_storage_format_to_name(update_data->ref_storage_format));
if (update_data->filter_options && update_data->filter_options->choice)
strvec_pushf(args, "--filter=%s",
expand_list_objects_filter_spec(
@@ -2598,7 +2637,8 @@ static int update_submodule(struct update_data *update_data)
if (update_data->just_cloned)
oidcpy(&update_data->suboid, null_oid());
- else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+ else if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
+ "HEAD", &update_data->suboid))
return die_message(_("Unable to find current revision in submodule path '%s'"),
update_data->displaypath);
@@ -2620,14 +2660,20 @@ static int update_submodule(struct update_data *update_data)
if (!update_data->nofetch) {
if (fetch_in_submodule(update_data->sm_path, update_data->depth,
- 0, NULL))
+ 0, NULL)) {
+ free(remote_ref);
return die_message(_("Unable to fetch in submodule path '%s'"),
update_data->sm_path);
+ }
}
- if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
- return die_message(_("Unable to find %s revision in submodule path '%s'"),
- remote_ref, update_data->sm_path);
+ if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
+ remote_ref, &update_data->oid)) {
+ ret = die_message(_("Unable to find %s revision in submodule path '%s'"),
+ remote_ref, update_data->sm_path);
+ free(remote_ref);
+ return ret;
+ }
free(remote_ref);
}
@@ -2740,6 +2786,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
struct update_data opt = UPDATE_DATA_INIT;
struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT;
+ const char *ref_storage_format = NULL;
int ret;
struct option module_update_options[] = {
OPT__SUPER_PREFIX(&opt.super_prefix),
@@ -2763,6 +2810,8 @@ static int module_update(int argc, const char **argv, const char *prefix)
SM_UPDATE_REBASE),
OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
N_("reference repository")),
+ OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &opt.dissociate,
N_("use --reference only while cloning")),
OPT_INTEGER(0, "depth", &opt.depth,
@@ -2806,6 +2855,12 @@ static int module_update(int argc, const char **argv, const char *prefix)
module_update_options);
}
+ if (ref_storage_format) {
+ opt.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+ if (opt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_storage_format);
+ }
+
opt.filter_options = &filter_options;
opt.prefix = prefix;
@@ -2876,7 +2931,8 @@ static int push_check(int argc, const char **argv, const char *prefix UNUSED)
argv++;
argc--;
/* Get the submodule's head ref and determine if it is detached */
- head = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
@@ -2926,7 +2982,9 @@ static int push_check(int argc, const char **argv, const char *prefix UNUSED)
rs->src);
}
}
+
refspec_clear(&refspec);
+ free_refs(local_refs);
}
free(head);
@@ -2968,7 +3026,7 @@ cleanup:
static int module_set_url(int argc, const char **argv, const char *prefix)
{
- int quiet = 0;
+ int quiet = 0, ret;
const char *newurl;
const char *path;
char *config_name;
@@ -2980,20 +3038,29 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
N_("git submodule set-url [--quiet] <path> <newurl>"),
NULL
};
+ const struct submodule *sub;
argc = parse_options(argc, argv, prefix, options, usage, 0);
if (argc != 2 || !(path = argv[0]) || !(newurl = argv[1]))
usage_with_options(usage, options);
- config_name = xstrfmt("submodule.%s.url", path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
+
+ if (!sub)
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
- config_set_in_gitmodules_file_gently(config_name, newurl);
- sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
+ config_name = xstrfmt("submodule.%s.url", sub->name);
+ ret = config_set_in_gitmodules_file_gently(config_name, newurl);
- free(config_name);
+ if (!ret) {
+ repo_read_gitmodules(the_repository, 0);
+ sync_submodule(sub->path, prefix, NULL, quiet ? OPT_QUIET : 0);
+ }
- return 0;
+ free(config_name);
+ return !!ret;
}
static int module_set_branch(int argc, const char **argv, const char *prefix)
@@ -3020,6 +3087,7 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
N_("git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
NULL
};
+ const struct submodule *sub;
argc = parse_options(argc, argv, prefix, options, usage, 0);
@@ -3032,7 +3100,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
if (argc != 1 || !(path = argv[0]))
usage_with_options(usage, options);
- config_name = xstrfmt("submodule.%s.branch", path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
+
+ if (!sub)
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
+
+ config_name = xstrfmt("submodule.%s.branch", sub->name);
ret = config_set_in_gitmodules_file_gently(config_name, opt_branch);
free(config_name);
@@ -3084,13 +3158,17 @@ struct add_data {
const char *sm_name;
const char *repo;
const char *realrepo;
+ enum ref_storage_format ref_storage_format;
int depth;
unsigned int force: 1;
unsigned int quiet: 1;
unsigned int progress: 1;
unsigned int dissociate: 1;
};
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+ .depth = -1, \
+ .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
+}
static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
{
@@ -3184,9 +3262,10 @@ static int add_submodule(const struct add_data *add_data)
string_list_append(&reference, p)->util = p;
}
+ clone_data.ref_storage_format = add_data->ref_storage_format;
clone_data.dissociate = add_data->dissociate;
if (add_data->depth >= 0)
- clone_data.depth = xstrfmt("%d", add_data->depth);
+ clone_data.depth = add_data->depth;
if (clone_submodule(&clone_data, &reference))
goto cleanup;
@@ -3209,6 +3288,7 @@ static int add_submodule(const struct add_data *add_data)
die(_("unable to checkout submodule '%s'"), add_data->sm_path);
}
ret = 0;
+
cleanup:
string_list_clear(&reference, 1);
return ret;
@@ -3307,21 +3387,21 @@ static void die_on_index_match(const char *path, int force)
char *ps_matched = xcalloc(ps.nr, 1);
/* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
/*
* Since there is only one pathspec, we just need to
* check ps_matched[0] to know if a cache entry matched.
*/
- for (i = 0; i < the_index.cache_nr; i++) {
- ce_path_match(&the_index, the_index.cache[i], &ps,
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ ce_path_match(the_repository->index, the_repository->index->cache[i], &ps,
ps_matched);
if (ps_matched[0]) {
if (!force)
die(_("'%s' already exists in the index"),
path);
- if (!S_ISGITLINK(the_index.cache[i]->ce_mode))
+ if (!S_ISGITLINK(the_repository->index->cache[i]->ce_mode))
die(_("'%s' already exists in the index "
"and is not a submodule"), path);
break;
@@ -3338,7 +3418,7 @@ static void die_on_repo_without_commits(const char *path)
strbuf_addstr(&sb, path);
if (is_nonbare_repository_dir(&sb)) {
struct object_id oid;
- if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
die(_("'%s' does not have a commit checked out"), path);
}
strbuf_release(&sb);
@@ -3348,6 +3428,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
{
int force = 0, quiet = 0, progress = 0, dissociate = 0;
struct add_data add_data = ADD_DATA_INIT;
+ const char *ref_storage_format = NULL;
char *to_free = NULL;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
@@ -3358,6 +3439,8 @@ static int module_add(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "progress", &progress, N_("force cloning progress")),
OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"),
N_("reference repository")),
+ OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")),
OPT_STRING(0, "name", &add_data.sm_name, N_("name"),
N_("sets the submodule's name to the given string "
@@ -3384,6 +3467,12 @@ static int module_add(int argc, const char **argv, const char *prefix)
if (argc == 0 || argc > 2)
usage_with_options(usage, options);
+ if (ref_storage_format) {
+ add_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+ if (add_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_storage_format);
+ }
+
add_data.repo = argv[0];
if (argc == 1)
add_data.sm_path = git_url_basename(add_data.repo, 0, 0);
@@ -3465,7 +3554,10 @@ cleanup:
return ret;
}
-int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
+int cmd_submodule__helper(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
const char *const usage[] = {
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index c9defe4d2e..299d23d76a 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -18,7 +19,8 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, i
const char *refname;
resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
- refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
+ refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ HEAD, resolve_flags, NULL, &flag);
if (!refname)
die("No such ref: %s", HEAD);
@@ -31,14 +33,19 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, i
if (print) {
char *to_free = NULL;
if (shorten)
- refname = to_free = shorten_unambiguous_ref(refname, 0);
+ refname = to_free = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ refname,
+ 0);
puts(refname);
free(to_free);
}
return 0;
}
-int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
+int cmd_symbolic_ref(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
const char *msg = NULL;
@@ -66,7 +73,8 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
die("deleting '%s' is not allowed", argv[0]);
- return delete_ref(NULL, argv[0], NULL, REF_NO_DEREF);
+ return refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, argv[0], NULL, REF_NO_DEREF);
}
switch (argc) {
@@ -79,7 +87,8 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
die("Refusing to point HEAD outside of refs/");
if (check_refname_format(argv[1], REFNAME_ALLOW_ONELEVEL) < 0)
die("Refusing to set '%s' to invalid ref '%s'", argv[0], argv[1]);
- ret = !!create_symref(argv[0], argv[1], msg);
+ ret = !!refs_update_symref(get_main_ref_store(the_repository),
+ argv[0], argv[1], msg);
break;
default:
usage_with_options(git_symbolic_ref_usage, options);
diff --git a/builtin/tag.c b/builtin/tag.c
index 3918eacbb5..5e1f904d35 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -5,7 +5,7 @@
* Carlos Rica <jasampler@gmail.com>
* Based on git-tag.sh and mktag.c by Linus Torvalds.
*/
-
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -18,7 +18,6 @@
#include "object-store-ll.h"
#include "path.h"
#include "tag.h"
-#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
#include "revision.h"
@@ -28,9 +27,12 @@
#include "ref-filter.h"
#include "date.h"
#include "write-or-die.h"
+#include "object-file-convert.h"
+#include "trailer.h"
static const char * const git_tag_usage[] = {
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+ " [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"),
N_("git tag -d <tagname>..."),
N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
@@ -44,18 +46,11 @@ 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)
{
- struct ref_array array;
- struct strbuf output = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
char *to_free = NULL;
- int i;
-
- memset(&array, 0, sizeof(array));
if (filter->lines == -1)
filter->lines = 0;
@@ -73,23 +68,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
if (verify_ref_format(format))
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++) {
- strbuf_reset(&output);
- strbuf_reset(&err);
- if (format_ref_array_item(array.items[i], format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- if (output.len || !omit_empty)
- putchar('\n');
- }
+ filter_and_format_refs(filter, FILTER_REFS_TAGS, sorting, format);
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
free(to_free);
return 0;
@@ -109,7 +89,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
for (p = argv; *p; p++) {
strbuf_reset(&ref);
strbuf_addf(&ref, "refs/tags/%s", *p);
- if (read_ref(ref.buf, &oid)) {
+ if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) {
error(_("tag '%s' not found."), *p);
had_error = 1;
continue;
@@ -138,13 +118,13 @@ static int delete_tags(const char **argv)
struct string_list_item *item;
result = for_each_tag_name(argv, collect_tags, (void *)&refs_to_delete);
- if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
+ if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF))
result = 1;
for_each_string_list_item(item, &refs_to_delete) {
const char *name = item->string;
struct object_id *oid = item->util;
- if (!ref_exists(name))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), name))
printf(_("Deleted tag '%s' (was %s)\n"),
item->string + 10,
repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
@@ -174,18 +154,53 @@ static int verify_tag(const char *name, const char *ref UNUSED,
return 0;
}
-static int do_sign(struct strbuf *buffer)
+static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
+ struct object_id *compat_oid_buf)
{
- return sign_buffer(buffer, buffer, get_signing_key());
+ const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+ struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
+ struct strbuf compat_buf = STRBUF_INIT;
+ char *keyid = get_signing_key();
+ int ret = -1;
+
+ if (sign_buffer(buffer, &sig, keyid))
+ goto out;
+
+ if (compat) {
+ const struct git_hash_algo *algo = the_repository->hash_algo;
+
+ if (convert_object_file(&compat_buf, algo, compat,
+ buffer->buf, buffer->len, OBJ_TAG, 1))
+ goto out;
+ if (sign_buffer(&compat_buf, &compat_sig, keyid))
+ goto out;
+ add_header_signature(&compat_buf, &sig, algo);
+ strbuf_addbuf(&compat_buf, &compat_sig);
+ hash_object_file(compat, compat_buf.buf, compat_buf.len,
+ OBJ_TAG, compat_oid_buf);
+ *compat_oid = compat_oid_buf;
+ }
+
+ if (compat_sig.len)
+ add_header_signature(buffer, &compat_sig, compat);
+
+ strbuf_addbuf(buffer, &sig);
+ ret = 0;
+out:
+ strbuf_release(&sig);
+ strbuf_release(&compat_sig);
+ strbuf_release(&compat_buf);
+ free(keyid);
+ return ret;
}
static const char tag_template[] =
N_("\nWrite a message for tag:\n %s\n"
- "Lines starting with '%c' will be ignored.\n");
+ "Lines starting with '%s' will be ignored.\n");
static const char tag_template_nocleanup[] =
N_("\nWrite a message for tag:\n %s\n"
- "Lines starting with '%c' will be kept; you may remove them"
+ "Lines starting with '%s' will be kept; you may remove them"
" yourself if you want to.\n");
static int git_tag_config(const char *var, const char *value,
@@ -249,9 +264,11 @@ static void write_tag_body(int fd, const struct object_id *oid)
static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
{
- if (sign && do_sign(buf) < 0)
+ struct object_id *compat_oid = NULL, compat_oid_buf;
+ if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0)
return error(_("unable to sign the tag"));
- if (write_object_file(buf->buf, buf->len, OBJ_TAG, result) < 0)
+ if (write_object_file_flags(buf->buf, buf->len, OBJ_TAG, result,
+ compat_oid, 0) < 0)
return error(_("unable to write tag file"));
return 0;
}
@@ -276,10 +293,12 @@ 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, char *path)
+ struct object_id *prev, struct object_id *result,
+ struct strvec *trailer_args, char *path)
{
enum object_type type;
struct strbuf header = STRBUF_INIT;
+ int should_edit;
type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
@@ -299,13 +318,15 @@ static void create_tag(const struct object_id *object, const char *object_ref,
tag,
git_committer_info(IDENT_STRICT));
- if (!opt->message_given || opt->use_editor) {
+ should_edit = opt->use_editor || !opt->message_given;
+ if (should_edit || trailer_args->nr) {
int fd;
/* write the template message before editing: */
fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (opt->message_given) {
+ if (opt->message_given && buf->len) {
+ strbuf_complete(buf, '\n');
write_or_die(fd, buf->buf, buf->len);
strbuf_reset(buf);
} else if (!is_null_oid(prev)) {
@@ -314,26 +335,35 @@ 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, comment_line_char,
- _(tag_template), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_str,
+ _(tag_template), tag, comment_line_str);
else
- strbuf_commented_addf(&buf, comment_line_char,
- _(tag_template_nocleanup), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_str,
+ _(tag_template_nocleanup), tag, comment_line_str);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
close(fd);
- if (launch_editor(path, buf, NULL)) {
- fprintf(stderr,
- _("Please supply the message using either -m or -F option.\n"));
- exit(1);
+ if (trailer_args->nr && amend_file_with_trailers(path, trailer_args))
+ die(_("unable to pass trailers to --trailers"));
+
+ if (should_edit) {
+ if (launch_editor(path, buf, NULL)) {
+ fprintf(stderr,
+ _("Please supply the message using either -m or -F option.\n"));
+ exit(1);
+ }
+ } else if (trailer_args->nr) {
+ strbuf_reset(buf);
+ if (strbuf_read_file(buf, path, 0) < 0)
+ die_errno(_("failed to read '%s'"), path);
}
}
if (opt->cleanup_mode != CLEANUP_NONE)
strbuf_stripspace(buf,
- opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
+ opt->cleanup_mode == CLEANUP_ALL ? comment_line_str : NULL);
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
@@ -428,7 +458,10 @@ static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
return check_refname_format(sb->buf, 0);
}
-int cmd_tag(int argc, const char **argv, const char *prefix)
+int cmd_tag(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf ref = STRBUF_INIT;
@@ -449,6 +482,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
+ struct strvec trailer_args = STRVEC_INIT;
int icase = 0;
int edit_flag = 0;
struct option options[] = {
@@ -465,6 +499,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('m', "message", &msg, N_("message"),
N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg),
OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+ OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"),
+ N_("add custom trailer(s)"), PARSE_OPT_NONEG),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
OPT_CLEANUP(&cleanup_arg),
@@ -481,7 +517,7 @@ 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,
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
N_("do not output a newline after empty formatted refs")),
OPT_REF_SORT(&sorting_options),
{
@@ -501,7 +537,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
setup_ref_filter_porcelain_msg();
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_tag_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
memset(&opt, 0, sizeof(opt));
filter.lines = -1;
@@ -528,7 +570,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
opt.sign = 1;
set_signing_key(keyid);
}
- create_tag_object = (opt.sign || annotate || msg.given || msgfile);
+ create_tag_object = (opt.sign || annotate || msg.given || msgfile ||
+ edit_flag || trailer_args.nr);
if ((create_tag_object || force) && (cmdmode != 0))
usage_with_options(git_tag_usage, options);
@@ -547,7 +590,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct column_options copts;
memset(&copts, 0, sizeof(copts));
copts.padding = 2;
- run_column_filter(colopts, &copts);
+ if (run_column_filter(colopts, &copts))
+ die(_("could not start 'git column'"));
}
filter.name_patterns = argv;
ret = list_tags(&filter, sorting, &format);
@@ -609,8 +653,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (strbuf_check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
- if (read_ref(ref.buf, &prev))
- oidclr(&prev);
+ if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
+ oidclr(&prev, the_repository->hash_algo);
else if (!force)
die(_("tag '%s' already exists"), tag);
@@ -633,12 +677,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
opt.sign = 1;
path = git_pathdup("TAG_EDITMSG");
create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
- path);
+ &trailer_args, path);
}
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, &object, &prev,
+ NULL, NULL,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err)) {
@@ -660,11 +706,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
cleanup:
ref_sorting_release(sorting);
ref_filter_clear(&filter);
+ ref_format_clear(&format);
strbuf_release(&buf);
strbuf_release(&ref);
strbuf_release(&reflog_msg);
strbuf_release(&msg.buf);
strbuf_release(&err);
+ strvec_clear(&trailer_args);
free(msgfile);
return ret;
}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index c129e2bb6c..6da2825753 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "hex.h"
@@ -25,7 +26,10 @@ static char *create_temp_file(struct object_id *oid)
return path;
}
-int cmd_unpack_file(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_unpack_file(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
struct object_id oid;
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 32505255a0..02b8d02f63 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "bulk-checkin.h"
#include "config.h"
@@ -10,12 +11,8 @@
#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"
#include "progress.h"
#include "decorate.h"
#include "fsck.h"
@@ -443,7 +440,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
struct object_id base_oid;
if (type == OBJ_REF_DELTA) {
- oidread(&base_oid, fill(the_hash_algo->rawsz));
+ oidread(&base_oid, fill(the_hash_algo->rawsz), the_repository->hash_algo);
use(the_hash_algo->rawsz);
delta_data = get_data(delta_size);
if (!delta_data)
@@ -455,7 +452,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
return; /* we are done */
else {
/* cannot resolve yet --- queue it */
- oidclr(&obj_list[nr].oid);
+ oidclr(&obj_list[nr].oid, the_repository->hash_algo);
add_delta_to_list(nr, &base_oid, 0, delta_data, delta_size);
return;
}
@@ -504,7 +501,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
* The delta base object is itself a delta that
* has not been resolved yet.
*/
- oidclr(&obj_list[nr].oid);
+ oidclr(&obj_list[nr].oid, the_repository->hash_algo);
add_delta_to_list(nr, null_oid(), base_offset,
delta_data, delta_size);
return;
@@ -605,10 +602,14 @@ static void unpack_all(void)
die("unresolved deltas left after unpacking");
}
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_unpack_objects(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
int i;
struct object_id oid;
+ git_hash_ctx tmp_ctx;
disable_replace_refs();
@@ -669,24 +670,21 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
the_hash_algo->init_fn(&ctx);
unpack_all();
the_hash_algo->update_fn(&ctx, buffer, offset);
- the_hash_algo->final_oid_fn(&oid, &ctx);
+ the_hash_algo->init_fn(&tmp_ctx);
+ the_hash_algo->clone_fn(&tmp_ctx, &ctx);
+ the_hash_algo->final_oid_fn(&oid, &tmp_ctx);
if (strict) {
write_rest();
if (fsck_finish(&fsck_options))
die(_("fsck error in pack objects"));
}
- if (!hasheq(fill(the_hash_algo->rawsz), oid.hash))
+ if (!hasheq(fill(the_hash_algo->rawsz), oid.hash,
+ the_repository->hash_algo))
die("final sha1 did not match");
use(the_hash_algo->rawsz);
/* Write the last part of the buffer to stdout */
- while (len) {
- int ret = xwrite(1, buffer + offset, len);
- if (ret <= 0)
- break;
- len -= ret;
- offset += ret;
- }
+ write_in_full(1, buffer + offset, len);
/* All done */
return has_errors;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index aee3cb8cbd..45b4a8b555 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "bulk-checkin.h"
#include "config.h"
@@ -22,7 +22,6 @@
#include "pathspec.h"
#include "dir.h"
#include "read-cache.h"
-#include "repository.h"
#include "setup.h"
#include "sparse-index.h"
#include "split-index.h"
@@ -247,16 +246,16 @@ done:
static int mark_ce_flags(const char *path, int flag, int mark)
{
int namelen = strlen(path);
- int pos = index_name_pos(&the_index, path, namelen);
+ int pos = index_name_pos(the_repository->index, path, namelen);
if (0 <= pos) {
- mark_fsmonitor_invalid(&the_index, the_index.cache[pos]);
+ mark_fsmonitor_invalid(the_repository->index, the_repository->index->cache[pos]);
if (mark)
- the_index.cache[pos]->ce_flags |= flag;
+ the_repository->index->cache[pos]->ce_flags |= flag;
else
- the_index.cache[pos]->ce_flags &= ~flag;
- the_index.cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
- cache_tree_invalidate_path(&the_index, path);
- the_index.cache_changed |= CE_ENTRY_CHANGED;
+ the_repository->index->cache[pos]->ce_flags &= ~flag;
+ the_repository->index->cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
+ cache_tree_invalidate_path(the_repository->index, path);
+ the_repository->index->cache_changed |= CE_ENTRY_CHANGED;
return 0;
}
return -1;
@@ -266,7 +265,7 @@ static int remove_one_path(const char *path)
{
if (!allow_remove)
return error("%s: does not exist and --remove not passed", path);
- if (remove_file_from_index(&the_index, path))
+ if (remove_file_from_index(the_repository->index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
@@ -291,24 +290,24 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
struct cache_entry *ce;
/* Was the old index entry already up-to-date? */
- if (old && !ce_stage(old) && !ie_match_stat(&the_index, old, st, 0))
+ if (old && !ce_stage(old) && !ie_match_stat(the_repository->index, old, st, 0))
return 0;
- ce = make_empty_cache_entry(&the_index, len);
+ ce = make_empty_cache_entry(the_repository->index, len);
memcpy(ce->name, path, len);
ce->ce_flags = create_ce_flags(0);
ce->ce_namelen = len;
- fill_stat_cache_info(&the_index, ce, st);
+ fill_stat_cache_info(the_repository->index, ce, st);
ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
- if (index_path(&the_index, &ce->oid, path, st,
+ if (index_path(the_repository->index, &ce->oid, path, st,
info_only ? 0 : HASH_WRITE_OBJECT)) {
discard_cache_entry(ce);
return -1;
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_index_entry(&the_index, ce, option)) {
+ if (add_index_entry(the_repository->index, ce, option)) {
discard_cache_entry(ce);
return error("%s: cannot add to the index - missing --add option?", path);
}
@@ -341,15 +340,16 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
static int process_directory(const char *path, int len, struct stat *st)
{
struct object_id oid;
- int pos = index_name_pos(&the_index, path, len);
+ int pos = index_name_pos(the_repository->index, path, len);
/* Exact match: file or existing gitlink */
if (pos >= 0) {
- const struct cache_entry *ce = the_index.cache[pos];
+ const struct cache_entry *ce = the_repository->index->cache[pos];
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
- if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, path,
+ "HEAD", &oid) < 0)
return 0;
return add_one_path(ce, path, len, st);
@@ -360,8 +360,8 @@ static int process_directory(const char *path, int len, struct stat *st)
/* Inexact match: is there perhaps a subdirectory match? */
pos = -pos-1;
- while (pos < the_index.cache_nr) {
- const struct cache_entry *ce = the_index.cache[pos++];
+ while (pos < the_repository->index->cache_nr) {
+ const struct cache_entry *ce = the_repository->index->cache[pos++];
if (strncmp(ce->name, path, len))
break;
@@ -375,7 +375,7 @@ static int process_directory(const char *path, int len, struct stat *st)
}
/* No match - should we add it as a gitlink? */
- if (!resolve_gitlink_ref(path, "HEAD", &oid))
+ if (!repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid))
return add_one_path(NULL, path, len, st);
/* Error out. */
@@ -391,8 +391,8 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path);
- pos = index_name_pos(&the_index, path, len);
- ce = pos < 0 ? NULL : the_index.cache[pos];
+ pos = index_name_pos(the_repository->index, path, len);
+ ce = pos < 0 ? NULL : the_repository->index->cache[pos];
if (ce && ce_skip_worktree(ce)) {
/*
* working directory version is assumed "good"
@@ -400,7 +400,7 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
* On the other hand, removing it from index should work
*/
if (!ignore_skip_worktree_entries && allow_remove &&
- remove_file_from_index(&the_index, path))
+ remove_file_from_index(the_repository->index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
@@ -428,7 +428,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
return error("Invalid path '%s'", path);
len = strlen(path);
- ce = make_empty_cache_entry(&the_index, len);
+ ce = make_empty_cache_entry(the_repository->index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, path, len);
@@ -439,7 +439,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
ce->ce_flags |= CE_VALID;
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_index_entry(&the_index, ce, option))
+ if (add_index_entry(the_repository->index, ce, option))
return error("%s: cannot add to the index - missing --add option?",
path);
report("add '%s'", path);
@@ -451,11 +451,11 @@ static void chmod_path(char flip, const char *path)
int pos;
struct cache_entry *ce;
- pos = index_name_pos(&the_index, path, strlen(path));
+ pos = index_name_pos(the_repository->index, path, strlen(path));
if (pos < 0)
goto fail;
- ce = the_index.cache[pos];
- if (chmod_index_entry(&the_index, ce, flip) < 0)
+ ce = the_repository->index->cache[pos];
+ if (chmod_index_entry(the_repository->index, ce, flip) < 0)
goto fail;
report("chmod %cx '%s'", flip, path);
@@ -498,7 +498,7 @@ static void update_one(const char *path)
}
if (force_remove) {
- if (remove_file_from_index(&the_index, path))
+ if (remove_file_from_index(the_repository->index, path))
die("git update-index: unable to remove %s", path);
report("remove '%s'", path);
return;
@@ -581,7 +581,7 @@ static void read_index_info(int nul_term_line)
if (!mode) {
/* mode == 0 means there is no such path -- remove */
- if (remove_file_from_index(&the_index, path_name))
+ if (remove_file_from_index(the_repository->index, path_name))
die("git update-index: unable to remove %s",
ptr);
}
@@ -609,9 +609,6 @@ static const char * const update_index_usage[] = {
NULL
};
-static struct object_id head_oid;
-static struct object_id merge_head_oid;
-
static struct cache_entry *read_one_ent(const char *which,
struct object_id *ent, const char *path,
int namelen, int stage)
@@ -625,12 +622,12 @@ static struct cache_entry *read_one_ent(const char *which,
error("%s: not in %s branch.", path, which);
return NULL;
}
- if (!the_index.sparse_index && mode == S_IFDIR) {
+ if (!the_repository->index->sparse_index && mode == S_IFDIR) {
if (which)
error("%s: not a blob in %s branch.", path, which);
return NULL;
}
- ce = make_empty_cache_entry(&the_index, namelen);
+ ce = make_empty_cache_entry(the_repository->index, namelen);
oidcpy(&ce->oid, &oid);
memcpy(ce->name, path, namelen);
@@ -642,84 +639,17 @@ static struct cache_entry *read_one_ent(const char *which,
static int unresolve_one(const char *path)
{
- int namelen = strlen(path);
- int pos;
- int ret = 0;
- struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
-
- /* See if there is such entry in the index. */
- pos = index_name_pos(&the_index, path, namelen);
- if (0 <= pos) {
- /* already merged */
- pos = unmerge_index_entry_at(&the_index, pos);
- if (pos < the_index.cache_nr) {
- const struct cache_entry *ce = the_index.cache[pos];
- if (ce_stage(ce) &&
- ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen))
- return 0;
- }
- /* no resolve-undo information; fall back */
- } else {
- /* If there isn't, either it is unmerged, or
- * resolved as "removed" by mistake. We do not
- * want to do anything in the former case.
- */
- pos = -pos-1;
- if (pos < the_index.cache_nr) {
- const struct cache_entry *ce = the_index.cache[pos];
- if (ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen)) {
- fprintf(stderr,
- "%s: skipping still unmerged path.\n",
- path);
- goto free_return;
- }
- }
- }
-
- /* Grab blobs from given path from HEAD and MERGE_HEAD,
- * stuff HEAD version in stage #2,
- * stuff MERGE_HEAD version in stage #3.
- */
- ce_2 = read_one_ent("our", &head_oid, path, namelen, 2);
- ce_3 = read_one_ent("their", &merge_head_oid, path, namelen, 3);
-
- if (!ce_2 || !ce_3) {
- ret = -1;
- goto free_return;
- }
- if (oideq(&ce_2->oid, &ce_3->oid) &&
- ce_2->ce_mode == ce_3->ce_mode) {
- fprintf(stderr, "%s: identical in both, skipping.\n",
- path);
- goto free_return;
- }
-
- remove_file_from_index(&the_index, path);
- if (add_index_entry(&the_index, ce_2, ADD_CACHE_OK_TO_ADD)) {
- error("%s: cannot add our version to the index.", path);
- ret = -1;
- goto free_return;
- }
- if (!add_index_entry(&the_index, ce_3, ADD_CACHE_OK_TO_ADD))
- return 0;
- error("%s: cannot add their version to the index.", path);
- ret = -1;
- free_return:
- discard_cache_entry(ce_2);
- discard_cache_entry(ce_3);
- return ret;
-}
-
-static void read_head_pointers(void)
-{
- if (read_ref("HEAD", &head_oid))
- die("No HEAD -- no initial commit yet?");
- if (read_ref("MERGE_HEAD", &merge_head_oid)) {
- fprintf(stderr, "Not in the middle of a merge.\n");
- exit(0);
- }
+ struct string_list_item *item;
+ int res = 0;
+
+ if (!the_repository->index->resolve_undo)
+ return res;
+ item = string_list_lookup(the_repository->index->resolve_undo, path);
+ if (!item)
+ return res; /* no resolve-undo record for the path */
+ res = unmerge_index_entry(the_repository->index, path, item->util, 0);
+ FREE_AND_NULL(item->util);
+ return res;
}
static int do_unresolve(int ac, const char **av,
@@ -728,11 +658,6 @@ static int do_unresolve(int ac, const char **av,
int i;
int err = 0;
- /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
- * are not doing a merge, so exit with success status.
- */
- read_head_pointers();
-
for (i = 1; i < ac; i++) {
const char *arg = av[i];
char *p = prefix_path(prefix, prefix_length, arg);
@@ -751,24 +676,25 @@ static int do_reupdate(const char **paths,
int pos;
int has_head = 1;
struct pathspec pathspec;
+ struct object_id head_oid;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, paths);
- if (read_ref("HEAD", &head_oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), "HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
* commit. Update everything in the index.
*/
has_head = 0;
redo:
- for (pos = 0; pos < the_index.cache_nr; pos++) {
- const struct cache_entry *ce = the_index.cache[pos];
+ for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+ const struct cache_entry *ce = the_repository->index->cache[pos];
struct cache_entry *old = NULL;
int save_nr;
char *path;
- if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL))
+ if (ce_stage(ce) || !ce_path_match(the_repository->index, ce, &pathspec, NULL))
continue;
if (has_head)
old = read_one_ent(NULL, &head_oid,
@@ -784,7 +710,7 @@ static int do_reupdate(const char **paths,
* to process each path individually
*/
if (S_ISSPARSEDIR(ce->ce_mode)) {
- ensure_full_index(&the_index);
+ ensure_full_index(the_repository->index);
goto redo;
}
@@ -792,12 +718,12 @@ static int do_reupdate(const char **paths,
* path anymore, in which case, under 'allow_remove',
* or worse yet 'allow_replace', active_nr may decrease.
*/
- save_nr = the_index.cache_nr;
+ save_nr = the_repository->index->cache_nr;
path = xstrdup(ce->name);
update_one(path);
free(path);
discard_cache_entry(old);
- if (save_nr != the_index.cache_nr)
+ if (save_nr != the_repository->index->cache_nr)
goto redo;
}
clear_pathspec(&pathspec);
@@ -813,9 +739,9 @@ static int refresh(struct refresh_params *o, unsigned int flag)
{
setup_work_tree();
repo_read_index(the_repository);
- *o->has_errors |= refresh_index(&the_index, o->flags | flag, NULL,
+ *o->has_errors |= refresh_index(the_repository->index, o->flags | flag, NULL,
NULL, NULL);
- if (has_racy_timestamp(&the_index)) {
+ if (has_racy_timestamp(the_repository->index)) {
/*
* Even if nothing else has changed, updating the file
* increases the chance that racy timestamps become
@@ -824,7 +750,7 @@ static int refresh(struct refresh_params *o, unsigned int flag)
* refresh_index() as these are no actual errors.
* cmd_status() does the same.
*/
- the_index.cache_changed |= SOMETHING_CHANGED;
+ the_repository->index->cache_changed |= SOMETHING_CHANGED;
}
return 0;
}
@@ -856,12 +782,12 @@ static int chmod_callback(const struct option *opt,
return 0;
}
-static int resolve_undo_clear_callback(const struct option *opt,
+static int resolve_undo_clear_callback(const struct option *opt UNUSED,
const char *arg, int unset)
{
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- resolve_undo_clear_index(&the_index);
+ resolve_undo_clear_index(the_repository->index);
return 0;
}
@@ -890,7 +816,7 @@ static int parse_new_style_cacheinfo(const char *arg,
}
static enum parse_opt_result cacheinfo_callback(
- struct parse_opt_ctx_t *ctx, const struct option *opt,
+ struct parse_opt_ctx_t *ctx, const struct option *opt UNUSED,
const char *arg, int unset)
{
struct object_id oid;
@@ -962,7 +888,7 @@ static enum parse_opt_result unresolve_callback(
*has_errors = do_unresolve(ctx->argc, ctx->argv,
prefix, prefix ? strlen(prefix) : 0);
if (*has_errors)
- the_index.cache_changed = 0;
+ the_repository->index->cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
@@ -983,14 +909,17 @@ static enum parse_opt_result reupdate_callback(
setup_work_tree();
*has_errors = do_reupdate(ctx->argv + 1, prefix);
if (*has_errors)
- the_index.cache_changed = 0;
+ the_repository->index->cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
return 0;
}
-int cmd_update_index(int argc, const char **argv, const char *prefix)
+int cmd_update_index(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int newfd, entries, has_errors = 0, nul_term_line = 0;
enum uc_mode untracked_cache = UC_UNSPECIFIED;
@@ -1090,6 +1019,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
resolve_undo_clear_callback),
OPT_INTEGER(0, "index-version", &preferred_index_format,
N_("write index in this format")),
+ OPT_SET_INT(0, "show-index-version", &preferred_index_format,
+ N_("report on-disk index format version"), -1),
OPT_BOOL(0, "split-index", &split_index,
N_("enable or disable split index")),
OPT_BOOL(0, "untracked-cache", &untracked_cache,
@@ -1128,7 +1059,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
if (entries < 0)
die("cache corrupted");
- the_index.updated_skipworktree = 1;
+ the_repository->index->updated_skipworktree = 1;
/*
* Custom copy of parse_options() because we want to handle
@@ -1182,15 +1113,20 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
if (preferred_index_format) {
- if (preferred_index_format < INDEX_FORMAT_LB ||
- INDEX_FORMAT_UB < preferred_index_format)
+ if (preferred_index_format < 0) {
+ printf(_("%d\n"), the_repository->index->version);
+ } else if (preferred_index_format < INDEX_FORMAT_LB ||
+ INDEX_FORMAT_UB < preferred_index_format) {
die("index-version %d not in range: %d..%d",
preferred_index_format,
INDEX_FORMAT_LB, INDEX_FORMAT_UB);
-
- if (the_index.version != preferred_index_format)
- the_index.cache_changed |= SOMETHING_CHANGED;
- the_index.version = preferred_index_format;
+ } else {
+ if (the_repository->index->version != preferred_index_format)
+ the_repository->index->cache_changed |= SOMETHING_CHANGED;
+ report(_("index-version: was %d, set to %d"),
+ the_repository->index->version, preferred_index_format);
+ the_repository->index->version = preferred_index_format;
+ }
}
if (read_from_stdin) {
@@ -1222,20 +1158,20 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
end_odb_transaction();
if (split_index > 0) {
- if (git_config_get_split_index() == 0)
+ if (repo_config_get_split_index(the_repository) == 0)
warning(_("core.splitIndex is set to false; "
"remove or change it, if you really want to "
"enable split index"));
- if (the_index.split_index)
- the_index.cache_changed |= SPLIT_INDEX_ORDERED;
+ if (the_repository->index->split_index)
+ the_repository->index->cache_changed |= SPLIT_INDEX_ORDERED;
else
- add_split_index(&the_index);
+ add_split_index(the_repository->index);
} else if (!split_index) {
- if (git_config_get_split_index() == 1)
+ if (repo_config_get_split_index(the_repository) == 1)
warning(_("core.splitIndex is set to true; "
"remove or change it, if you really want to "
"disable split index"));
- remove_split_index(&the_index);
+ remove_split_index(the_repository->index);
}
prepare_repo_settings(r);
@@ -1247,7 +1183,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
warning(_("core.untrackedCache is set to true; "
"remove or change it, if you really want to "
"disable the untracked cache"));
- remove_untracked_cache(&the_index);
+ remove_untracked_cache(the_repository->index);
report(_("Untracked cache disabled"));
break;
case UC_TEST:
@@ -1259,8 +1195,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
warning(_("core.untrackedCache is set to false; "
"remove or change it, if you really want to "
"enable the untracked cache"));
- add_untracked_cache(&the_index);
- report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
+ add_untracked_cache(the_repository->index);
+ report(_("Untracked cache enabled for '%s'"), repo_get_work_tree(the_repository));
break;
default:
BUG("bad untracked_cache value: %d", untracked_cache);
@@ -1289,7 +1225,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
"set it if you really want to "
"enable fsmonitor"));
}
- add_fsmonitor(&the_index);
+ add_fsmonitor(the_repository->index);
report(_("fsmonitor enabled"));
} else if (!fsmonitor) {
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
@@ -1297,17 +1233,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
warning(_("core.fsmonitor is set; "
"remove it if you really want to "
"disable fsmonitor"));
- remove_fsmonitor(&the_index);
+ remove_fsmonitor(the_repository->index);
report(_("fsmonitor disabled"));
}
- if (the_index.cache_changed || force_write) {
+ if (the_repository->index->cache_changed || force_write) {
if (newfd < 0) {
if (refresh_args.flags & REFRESH_QUIET)
exit(128);
- unable_to_lock_die(get_index_file(), lock_error);
+ unable_to_lock_die(repo_get_index_file(the_repository), lock_error);
}
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
}
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 242102273e..670e7812d6 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -6,12 +7,10 @@
#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[] = {
- N_("git update-ref [<options>] -d <refname> [<old-val>]"),
- N_("git update-ref [<options>] <refname> <new-val> [<old-val>]"),
+ N_("git update-ref [<options>] -d <refname> [<old-oid>]"),
+ N_("git update-ref [<options>] <refname> <new-oid> [<old-oid>]"),
N_("git update-ref [<options>] --stdin [-z]"),
NULL
};
@@ -78,14 +77,73 @@ static char *parse_refname(const char **next)
}
/*
- * The value being parsed is <oldvalue> (as opposed to <newvalue>; the
+ * Wrapper around parse_refname which skips the next delimiter.
+ */
+static char *parse_next_refname(const char **next)
+{
+ if (line_termination) {
+ /* Without -z, consume SP and use next argument */
+ if (!**next || **next == line_termination)
+ return NULL;
+ if (**next != ' ')
+ die("expected SP but got: %s", *next);
+ } else {
+ /* With -z, read the next NUL-terminated line */
+ if (**next)
+ return NULL;
+ }
+ /* Skip the delimiter */
+ (*next)++;
+
+ return parse_refname(next);
+}
+
+/*
+ * Wrapper around parse_arg which skips the next delimiter.
+ */
+static char *parse_next_arg(const char **next)
+{
+ struct strbuf arg = STRBUF_INIT;
+
+ if (line_termination) {
+ /* Without -z, consume SP and use next argument */
+ if (!**next || **next == line_termination)
+ return NULL;
+ if (**next != ' ')
+ die("expected SP but got: %s", *next);
+ } else {
+ /* With -z, read the next NUL-terminated line */
+ if (**next)
+ return NULL;
+ }
+ /* Skip the delimiter */
+ (*next)++;
+
+ if (line_termination) {
+ /* Without -z, use the next argument */
+ *next = parse_arg(*next, &arg);
+ } else {
+ /* With -z, use everything up to the next NUL */
+ strbuf_addstr(&arg, *next);
+ *next += arg.len;
+ }
+
+ if (arg.len)
+ return strbuf_detach(&arg, NULL);
+
+ strbuf_release(&arg);
+ return NULL;
+}
+
+/*
+ * The value being parsed is <old-oid> (as opposed to <new-oid>; the
* difference affects which error messages are generated):
*/
#define PARSE_SHA1_OLD 0x01
/*
* For backwards compatibility, accept an empty string for update's
- * <newvalue> in binary mode to be equivalent to specifying zeros.
+ * <new-oid> in binary mode to be equivalent to specifying zeros.
*/
#define PARSE_SHA1_ALLOW_EMPTY 0x02
@@ -123,7 +181,7 @@ static int parse_next_oid(const char **next, const char *end,
goto invalid;
} else {
/* Without -z, an empty value means all zeros: */
- oidclr(oid);
+ oidclr(oid, the_repository->hash_algo);
}
} else {
/* With -z, read the next NUL-terminated line */
@@ -141,9 +199,9 @@ static int parse_next_oid(const char **next, const char *end,
goto invalid;
} else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
/* With -z, treat an empty value as all zeros: */
- warning("%s %s: missing <newvalue>, treating as zero",
+ warning("%s %s: missing <new-oid>, treating as zero",
command, refname);
- oidclr(oid);
+ oidclr(oid, the_repository->hash_algo);
} else {
/*
* With -z, an empty non-required value means
@@ -159,14 +217,14 @@ static int parse_next_oid(const char **next, const char *end,
invalid:
die(flags & PARSE_SHA1_OLD ?
- "%s %s: invalid <oldvalue>: %s" :
- "%s %s: invalid <newvalue>: %s",
+ "%s %s: invalid <old-oid>: %s" :
+ "%s %s: invalid <new-oid>: %s",
command, refname, arg.buf);
eof:
die(flags & PARSE_SHA1_OLD ?
- "%s %s: unexpected end of input when reading <oldvalue>" :
- "%s %s: unexpected end of input when reading <newvalue>",
+ "%s %s: unexpected end of input when reading <old-oid>" :
+ "%s %s: unexpected end of input when reading <new-oid>",
command, refname);
}
@@ -195,7 +253,7 @@ static void parse_cmd_update(struct ref_transaction *transaction,
if (parse_next_oid(&next, end, &new_oid, "update", refname,
PARSE_SHA1_ALLOW_EMPTY))
- die("update %s: missing <newvalue>", refname);
+ die("update %s: missing <new-oid>", refname);
have_old = !parse_next_oid(&next, end, &old_oid, "update", refname,
PARSE_SHA1_OLD);
@@ -205,12 +263,68 @@ static void parse_cmd_update(struct ref_transaction *transaction,
if (ref_transaction_update(transaction, refname,
&new_oid, have_old ? &old_oid : NULL,
+ NULL, NULL,
+ update_flags | create_reflog_flag,
+ msg, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ strbuf_release(&err);
+}
+
+static void parse_cmd_symref_update(struct ref_transaction *transaction,
+ const char *next, const char *end UNUSED)
+{
+ char *refname, *new_target, *old_arg;
+ char *old_target = NULL;
+ struct strbuf err = STRBUF_INIT;
+ struct object_id old_oid;
+ int have_old_oid = 0;
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-update: missing <ref>");
+
+ new_target = parse_next_refname(&next);
+ if (!new_target)
+ die("symref-update %s: missing <new-target>", refname);
+
+ old_arg = parse_next_arg(&next);
+ if (old_arg) {
+ old_target = parse_next_arg(&next);
+ if (!old_target)
+ die("symref-update %s: expected old value", refname);
+
+ if (!strcmp(old_arg, "oid")) {
+ if (repo_get_oid(the_repository, old_target, &old_oid))
+ die("symref-update %s: invalid oid: %s", refname, old_target);
+
+ have_old_oid = 1;
+ } else if (!strcmp(old_arg, "ref")) {
+ if (check_refname_format(old_target, REFNAME_ALLOW_ONELEVEL))
+ die("symref-update %s: invalid ref: %s", refname, old_target);
+ } else {
+ die("symref-update %s: invalid arg '%s' for old value", refname, old_arg);
+ }
+ }
+
+ if (*next != line_termination)
+ die("symref-update %s: extra input: %s", refname, next);
+
+ if (ref_transaction_update(transaction, refname, NULL,
+ have_old_oid ? &old_oid : NULL,
+ new_target,
+ have_old_oid ? NULL : old_target,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
update_flags = default_flags;
free(refname);
+ free(old_arg);
+ free(old_target);
+ free(new_target);
strbuf_release(&err);
}
@@ -226,21 +340,50 @@ static void parse_cmd_create(struct ref_transaction *transaction,
die("create: missing <ref>");
if (parse_next_oid(&next, end, &new_oid, "create", refname, 0))
- die("create %s: missing <newvalue>", refname);
+ die("create %s: missing <new-oid>", refname);
if (is_null_oid(&new_oid))
- die("create %s: zero <newvalue>", refname);
+ die("create %s: zero <new-oid>", refname);
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
- if (ref_transaction_create(transaction, refname, &new_oid,
+ if (ref_transaction_create(transaction, refname, &new_oid, NULL,
+ update_flags | create_reflog_flag,
+ msg, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ strbuf_release(&err);
+}
+
+
+static void parse_cmd_symref_create(struct ref_transaction *transaction,
+ const char *next, const char *end UNUSED)
+{
+ struct strbuf err = STRBUF_INIT;
+ char *refname, *new_target;
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-create: missing <ref>");
+
+ new_target = parse_next_refname(&next);
+ if (!new_target)
+ die("symref-create %s: missing <new-target>", refname);
+
+ if (*next != line_termination)
+ die("symref-create %s: extra input: %s", refname, next);
+
+ if (ref_transaction_create(transaction, refname, NULL, new_target,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
update_flags = default_flags;
free(refname);
+ free(new_target);
strbuf_release(&err);
}
@@ -261,7 +404,7 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
have_old = 0;
} else {
if (is_null_oid(&old_oid))
- die("delete %s: zero <oldvalue>", refname);
+ die("delete %s: zero <old-oid>", refname);
have_old = 1;
}
@@ -270,14 +413,44 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
if (ref_transaction_delete(transaction, refname,
have_old ? &old_oid : NULL,
- update_flags, msg, &err))
+ NULL, update_flags, msg, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ strbuf_release(&err);
+}
+
+
+static void parse_cmd_symref_delete(struct ref_transaction *transaction,
+ const char *next, const char *end UNUSED)
+{
+ struct strbuf err = STRBUF_INIT;
+ char *refname, *old_target;
+
+ if (!(update_flags & REF_NO_DEREF))
+ die("symref-delete: cannot operate with deref mode");
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-delete: missing <ref>");
+
+ old_target = parse_next_refname(&next);
+
+ if (*next != line_termination)
+ die("symref-delete %s: extra input: %s", refname, next);
+
+ if (ref_transaction_delete(transaction, refname, NULL,
+ old_target, update_flags, msg, &err))
die("%s", err.buf);
update_flags = default_flags;
free(refname);
+ free(old_target);
strbuf_release(&err);
}
+
static void parse_cmd_verify(struct ref_transaction *transaction,
const char *next, const char *end)
{
@@ -291,17 +464,53 @@ static void parse_cmd_verify(struct ref_transaction *transaction,
if (parse_next_oid(&next, end, &old_oid, "verify", refname,
PARSE_SHA1_OLD))
- oidclr(&old_oid);
+ oidclr(&old_oid, the_repository->hash_algo);
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
if (ref_transaction_verify(transaction, refname, &old_oid,
- update_flags, &err))
+ NULL, update_flags, &err))
+ die("%s", err.buf);
+
+ update_flags = default_flags;
+ free(refname);
+ strbuf_release(&err);
+}
+
+static void parse_cmd_symref_verify(struct ref_transaction *transaction,
+ const char *next, const char *end UNUSED)
+{
+ struct strbuf err = STRBUF_INIT;
+ struct object_id old_oid;
+ char *refname, *old_target;
+
+ if (!(update_flags & REF_NO_DEREF))
+ die("symref-verify: cannot operate with deref mode");
+
+ refname = parse_refname(&next);
+ if (!refname)
+ die("symref-verify: missing <ref>");
+
+ /*
+ * old_ref is optional, if not provided, we need to ensure that the
+ * ref doesn't exist.
+ */
+ old_target = parse_next_refname(&next);
+ if (!old_target)
+ oidcpy(&old_oid, null_oid());
+
+ if (*next != line_termination)
+ die("symref-verify %s: extra input: %s", refname, next);
+
+ if (ref_transaction_verify(transaction, refname,
+ old_target ? NULL : &old_oid,
+ old_target, update_flags, &err))
die("%s", err.buf);
update_flags = default_flags;
free(refname);
+ free(old_target);
strbuf_release(&err);
}
@@ -311,8 +520,8 @@ static void report_ok(const char *command)
fflush(stdout);
}
-static void parse_cmd_option(struct ref_transaction *transaction,
- const char *next, const char *end)
+static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
+ const char *next, const char *end UNUSED)
{
const char *rest;
if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination)
@@ -321,8 +530,8 @@ static void parse_cmd_option(struct ref_transaction *transaction,
die("option unknown: %s", next);
}
-static void parse_cmd_start(struct ref_transaction *transaction,
- const char *next, const char *end)
+static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
+ const char *next, const char *end UNUSED)
{
if (*next != line_termination)
die("start: extra input: %s", next);
@@ -330,7 +539,7 @@ static void parse_cmd_start(struct ref_transaction *transaction,
}
static void parse_cmd_prepare(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -341,7 +550,7 @@ static void parse_cmd_prepare(struct ref_transaction *transaction,
}
static void parse_cmd_abort(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -352,7 +561,7 @@ static void parse_cmd_abort(struct ref_transaction *transaction,
}
static void parse_cmd_commit(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -380,15 +589,19 @@ static const struct parse_cmd {
unsigned args;
enum update_refs_state state;
} command[] = {
- { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
- { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
- { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
- { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
- { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
- { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
- { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
- { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
- { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
+ { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
+ { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
+ { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
+ { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
+ { "symref-update", parse_cmd_symref_update, 4, UPDATE_REFS_OPEN },
+ { "symref-create", parse_cmd_symref_create, 2, UPDATE_REFS_OPEN },
+ { "symref-delete", parse_cmd_symref_delete, 2, UPDATE_REFS_OPEN },
+ { "symref-verify", parse_cmd_symref_verify, 2, UPDATE_REFS_OPEN },
+ { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
+ { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
+ { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
+ { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
+ { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
};
static void update_refs_stdin(void)
@@ -398,7 +611,8 @@ static void update_refs_stdin(void)
struct ref_transaction *transaction;
int i, j;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction)
die("%s", err.buf);
@@ -465,7 +679,8 @@ static void update_refs_stdin(void)
* get a "start".
*/
state = cmd->state;
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction)
die("%s", err.buf);
@@ -498,7 +713,10 @@ static void update_refs_stdin(void)
strbuf_release(&input);
}
-int cmd_update_ref(int argc, const char **argv, const char *prefix)
+int cmd_update_ref(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char *refname, *oldval;
struct object_id oid, oldoid;
@@ -562,7 +780,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
* The empty string implies that the reference
* must not already exist:
*/
- oidclr(&oldoid);
+ oidclr(&oldoid, the_repository->hash_algo);
else if (repo_get_oid(the_repository, oldval, &oldoid))
die("%s: not a valid old SHA1", oldval);
}
@@ -572,11 +790,14 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
* For purposes of backwards compatibility, we treat
* NULL_SHA1 as "don't care" here:
*/
- return delete_ref(msg, refname,
- (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
- default_flags);
+ return refs_delete_ref(get_main_ref_store(the_repository),
+ msg, refname,
+ (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
+ default_flags);
else
- return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
- default_flags | create_reflog_flag,
- UPDATE_REFS_DIE_ON_ERR);
+ return refs_update_ref(get_main_ref_store(the_repository),
+ msg, refname, &oid,
+ oldval ? &oldoid : NULL,
+ default_flags | create_reflog_flag,
+ UPDATE_REFS_DIE_ON_ERR);
}
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 1dc3971ede..6769611a02 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -9,7 +10,10 @@ static const char * const update_server_info_usage[] = {
NULL
};
-int cmd_update_server_info(int argc, const char **argv, const char *prefix)
+int cmd_update_server_info(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int force = 0;
struct option options[] = {
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 1b09e5e1aa..9e9343f121 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -1,12 +1,12 @@
/*
* Copyright (c) 2006 Franck Bui-Huu
*/
+#define USE_THE_REPOSITORY_VARIABLE
#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"
@@ -18,10 +18,14 @@ static const char deadchild[] =
#define MAX_ARGS (64)
-int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
+int cmd_upload_archive_writer(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
struct strvec sent_argv = STRVEC_INIT;
const char *arg_cmd = "argument ";
+ int ret;
if (argc != 2 || !strcmp(argv[1], "-h"))
usage(upload_archive_usage);
@@ -46,8 +50,11 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
}
/* parse all options sent by the client */
- return write_archive(sent_argv.nr, sent_argv.v, prefix,
- the_repository, NULL, 1);
+ ret = write_archive(sent_argv.nr, sent_argv.v, prefix,
+ the_repository, NULL, 1);
+
+ strvec_clear(&sent_argv);
+ return ret;
}
__attribute__((format (printf, 1, 2)))
@@ -76,7 +83,10 @@ static ssize_t process_input(int child_fd, int band)
return sz;
}
-int cmd_upload_archive(int argc, const char **argv, const char *prefix)
+int cmd_upload_archive(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
{
struct child_process writer = CHILD_PROCESS_INIT;
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 272cddaafd..3b6c83fbce 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -8,6 +8,8 @@
#include "replace-object.h"
#include "upload-pack.h"
#include "serve.h"
+#include "commit.h"
+#include "environment.h"
static const char * const upload_pack_usage[] = {
N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
@@ -15,7 +17,10 @@ static const char * const upload_pack_usage[] = {
NULL
};
-int cmd_upload_pack(int argc, const char **argv, const char *prefix)
+int cmd_upload_pack(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
const char *dir;
int strict = 0;
@@ -37,8 +42,8 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
packet_trace_identity("upload-pack");
disable_replace_refs();
- /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
- xsetenv("GIT_NO_LAZY_FETCH", "1", 0);
+ save_commit_buffer = 0;
+ xsetenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 0);
argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
diff --git a/builtin/var.c b/builtin/var.c
index 8cf7dd9e2e..2ecaed51b4 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -3,7 +3,9 @@
*
* Copyright (C) Eric Biederman, 2005
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+
#include "attr.h"
#include "config.h"
#include "editor.h"
@@ -12,6 +14,7 @@
#include "refs.h"
#include "path.h"
#include "strbuf.h"
+#include "run-command.h"
static const char var_usage[] = "git var (-l | <variable>)";
@@ -46,12 +49,12 @@ static char *pager(int ident_flag UNUSED)
static char *default_branch(int ident_flag UNUSED)
{
- return xstrdup_or_null(git_default_branch_name(1));
+ return repo_default_branch_name(the_repository, 1);
}
static char *shell_path(int ident_flag UNUSED)
{
- return xstrdup(SHELL_PATH);
+ return git_shell_path();
}
static char *git_attr_val_system(int ident_flag UNUSED)
@@ -90,7 +93,7 @@ static char *git_config_val_global(int ident_flag UNUSED)
char *user, *xdg;
size_t unused;
- git_global_config(&user, &xdg);
+ git_global_config_paths(&user, &xdg);
if (xdg && *xdg) {
normalize_path_copy(xdg, xdg);
strbuf_addf(&buf, "%s\n", xdg);
@@ -209,7 +212,10 @@ static int show_config(const char *var, const char *value,
return git_default_config(var, value, ctx, cb);
}
-int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_var(int argc,
+ const char **argv,
+ const char *prefix UNUSED,
+ struct repository *repo UNUSED)
{
const struct git_var *git_var;
char *val;
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 9680b58701..779b7988ca 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -5,14 +5,12 @@
*
* Based on git-verify-tag
*/
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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"
#include "parse-options.h"
#include "gpg-interface.h"
@@ -53,7 +51,10 @@ static int verify_commit(const char *name, unsigned flags)
return run_gpg_verify((struct commit *)obj, flags);
}
-int cmd_verify_commit(int argc, const char **argv, const char *prefix)
+int cmd_verify_commit(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i = 1, verbose = 0, had_error = 0;
unsigned flags = 0;
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 011dddd2dc..34e4ed715f 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "gettext.h"
@@ -61,7 +62,10 @@ static const char * const verify_pack_usage[] = {
NULL
};
-int cmd_verify_pack(int argc, const char **argv, const char *prefix)
+int cmd_verify_pack(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int err = 0;
unsigned int flags = 0;
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index d8753270eb..a7f20618ff 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -5,11 +5,11 @@
*
* Based on git-verify-tag.sh
*/
+#define USE_THE_REPOSITORY_VARIABLE
#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"
@@ -20,7 +20,10 @@ static const char * const verify_tag_usage[] = {
NULL
};
-int cmd_verify_tag(int argc, const char **argv, const char *prefix)
+int cmd_verify_tag(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
int i = 1, verbose = 0, had_error = 0;
unsigned flags = 0;
@@ -66,5 +69,6 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
if (format.format)
pretty_print_ref(name, &oid, &format);
}
+ ref_format_clear(&format);
return had_error;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 10db70b7ec..dae63dedf4 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "abspath.h"
#include "advice.h"
@@ -17,7 +18,6 @@
#include "read-cache-ll.h"
#include "refs.h"
#include "remote.h"
-#include "repository.h"
#include "run-command.h"
#include "hook.h"
#include "sigchain.h"
@@ -49,14 +49,14 @@
_("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" \
+ _("If you meant to create a worktree containing a new unborn 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" \
+ _("If you meant to create a worktree containing a new unborn branch\n" \
"(branch with no commits) for this repository, you can do so\n" \
"using the --orphan flag:\n" \
"\n" \
@@ -219,7 +219,7 @@ static void prune_worktrees(void)
}
closedir(dir);
- strbuf_add_absolute_path(&main_path, get_git_common_dir());
+ strbuf_add_absolute_path(&main_path, repo_get_common_dir(the_repository));
/* massage main worktree absolute path to match 'gitdir' content */
strbuf_strip_suffix(&main_path, "/.");
string_list_append_nodup(&kept, strbuf_detach(&main_path, NULL));
@@ -365,12 +365,12 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
bare &&
git_config_set_multivar_in_file_gently(
- to_file, "core.bare", NULL, "true", 0))
+ to_file, "core.bare", NULL, "true", NULL, 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
if (!git_configset_get(&cs, "core.worktree") &&
git_config_set_in_file_gently(to_file,
- "core.worktree", NULL))
+ "core.worktree", NULL, NULL))
error(_("failed to unset '%s' in '%s'"),
"core.worktree", to_file);
@@ -414,9 +414,9 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
- struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;
+ struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;
const char *name;
- struct child_process cp = CHILD_PROCESS_INIT;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
int len, ret;
@@ -424,7 +424,8 @@ static int add_worktree(const char *path, const char *refname,
struct commit *commit = NULL;
int is_branch = 0;
struct strbuf sb_name = STRBUF_INIT;
- struct worktree **worktrees;
+ struct worktree **worktrees, *wt = NULL;
+ struct ref_store *wt_refs;
worktrees = get_worktrees();
check_candidate_path(path, opts->force, worktrees, "add");
@@ -433,7 +434,7 @@ static int add_worktree(const char *path, const char *refname,
/* is 'refname' a branch or commit? */
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
- ref_exists(symref.buf)) {
+ refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) {
is_branch = 1;
if (!opts->force)
die_if_checked_out(symref.buf, 0);
@@ -490,26 +491,37 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- strbuf_realpath(&realpath, sb_git.buf, 1);
- write_file(sb.buf, "%s", realpath.buf);
- strbuf_realpath(&realpath, get_git_common_dir(), 1);
- write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
- realpath.buf, name);
- /*
- * This is to keep resolve_ref() happy. We need a valid HEAD
- * or is_git_directory() will reject the directory. Any value which
- * looks like an object ID will do since it will be immediately
- * replaced by the symbolic-ref or update-ref invocation in the new
- * worktree.
- */
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
- write_file(sb.buf, "%s", oid_to_hex(null_oid()));
+ strbuf_realpath(&sb_path_realpath, path, 1);
+ strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);
+ write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));
+ write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
/*
+ * Set up the ref store of the worktree and create the HEAD reference.
+ */
+ wt = get_linked_worktree(name, 1);
+ if (!wt) {
+ ret = error(_("could not find created worktree '%s'"), name);
+ goto done;
+ }
+ wt_refs = get_worktree_ref_store(wt);
+
+ ret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);
+ if (ret)
+ goto done;
+
+ if (!is_branch && commit)
+ ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
+ NULL, 0, UPDATE_REFS_MSG_ON_ERR);
+ else
+ ret = refs_update_symref(wt_refs, "HEAD", symref.buf, NULL);
+ if (ret)
+ goto done;
+
+ /*
* If the current worktree has sparse-checkout enabled, then copy
* the sparse-checkout patterns from the current worktree.
*/
@@ -526,22 +538,6 @@ static int add_worktree(const char *path, const char *refname,
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 && commit) {
- strvec_pushl(&cp.args, "update-ref", "HEAD",
- oid_to_hex(&commit->object.oid), NULL);
- } else {
- 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);
- ret = run_command(&cp);
- if (ret)
- goto done;
if (opts->orphan &&
(ret = make_worktree_orphan(refname, opts, &child_env)))
@@ -577,16 +573,19 @@ done:
NULL);
opt.dir = path;
- ret = run_hooks_opt("post-checkout", &opt);
+ ret = run_hooks_opt(the_repository, "post-checkout", &opt);
}
strvec_clear(&child_env);
strbuf_release(&sb);
+ strbuf_release(&sb_tmp);
strbuf_release(&symref);
strbuf_release(&sb_repo);
+ strbuf_release(&sb_repo_realpath);
strbuf_release(&sb_git);
+ strbuf_release(&sb_path_realpath);
strbuf_release(&sb_name);
- strbuf_release(&realpath);
+ free_worktree(wt);
return ret;
}
@@ -608,7 +607,7 @@ static void print_preparing_worktree_line(int detach,
} else {
struct strbuf s = STRBUF_INIT;
if (!detach && !strbuf_check_branch_ref(&s, branch) &&
- ref_exists(s.buf))
+ refs_ref_exists(get_main_ref_store(the_repository), s.buf))
fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"),
branch);
else {
@@ -628,10 +627,11 @@ static void print_preparing_worktree_line(int detach,
*
* Returns 0 on failure and non-zero on success.
*/
-static int first_valid_ref(const char *refname,
- const struct object_id *oid,
- int flags,
- void *cb_data)
+static int first_valid_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
+ const struct object_id *oid UNUSED,
+ int flags UNUSED,
+ void *cb_data UNUSED)
{
return 1;
}
@@ -650,9 +650,9 @@ static int first_valid_ref(const char *refname,
*/
static int can_use_local_refs(const struct add_opts *opts)
{
- if (head_ref(first_valid_ref, NULL)) {
+ if (refs_head_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
return 1;
- } else if (for_each_branch_ref(first_valid_ref, NULL)) {
+ } else if (refs_for_each_branch_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
if (!opts->quiet) {
struct strbuf path = STRBUF_INIT;
struct strbuf contents = STRBUF_INIT;
@@ -660,7 +660,7 @@ static int can_use_local_refs(const struct add_opts *opts)
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_stripspace(&contents, NULL);
strbuf_strip_suffix(&contents, "\n");
warning(_("HEAD points to an invalid (or orphaned) reference.\n"
@@ -692,7 +692,7 @@ 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)) {
+ } else if (refs_for_each_remote_ref(get_main_ref_store(the_repository), 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"
@@ -730,27 +730,26 @@ static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
}
if (opt_track) {
- die(_("'%s' and '%s' cannot be used together"), "--orphan",
- "--track");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--track");
} else if (!opts->checkout) {
- die(_("'%s' and '%s' cannot be used together"), "--orphan",
- "--no-checkout");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--no-checkout");
}
return 1;
}
-static const char *dwim_branch(const char *path, const char **new_branch)
+static char *dwim_branch(const char *path, char **new_branch)
{
int n;
int branch_exists;
const char *s = worktree_basename(path, &n);
- const char *branchname = xstrndup(s, n);
+ char *branchname = xstrndup(s, n);
struct strbuf ref = STRBUF_INIT;
- UNLEAK(branchname);
-
branch_exists = !strbuf_check_branch_ref(&ref, branchname) &&
- ref_exists(ref.buf);
+ refs_ref_exists(get_main_ref_store(the_repository),
+ ref.buf);
strbuf_release(&ref);
if (branch_exists)
return branchname;
@@ -758,8 +757,7 @@ static const char *dwim_branch(const char *path, const char **new_branch)
*new_branch = branchname;
if (guess_remote) {
struct object_id oid;
- const char *remote =
- unique_tracking_name(*new_branch, &oid, NULL);
+ char *remote = unique_tracking_name(*new_branch, &oid, NULL);
return remote;
}
return NULL;
@@ -771,8 +769,10 @@ static int add(int ac, const char **av, const char *prefix)
const char *new_branch_force = NULL;
char *path;
const char *branch;
+ char *branch_to_free = NULL;
+ char *new_branch_to_free = NULL;
const char *new_branch = NULL;
- const char *opt_track = NULL;
+ char *opt_track = NULL;
const char *lock_reason = NULL;
int keep_locked = 0;
int used_new_branch_options;
@@ -784,7 +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(0, "orphan", &opts.orphan, N_("create unborn 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")),
@@ -806,16 +806,17 @@ static int add(int ac, const char **av, const char *prefix)
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"),
+ 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");
+ die(_("options '%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");
+ die(_("options '%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>"));
+ die(_("option '%s' and commit-ish cannot be used together"),
+ "--orphan");
if (lock_reason && !keep_locked)
die(_("the option '%s' requires '%s'"), "--reason", "--lock");
if (lock_reason)
@@ -840,7 +841,7 @@ static int add(int ac, const char **av, const char *prefix)
if (!opts.force &&
!strbuf_check_branch_ref(&symref, new_branch) &&
- ref_exists(symref.buf))
+ refs_ref_exists(get_main_ref_store(the_repository), symref.buf))
die_if_checked_out(symref.buf, 0);
strbuf_release(&symref);
}
@@ -848,35 +849,36 @@ static int add(int ac, const char **av, const char *prefix)
if (opts.orphan && !new_branch) {
int n;
const char *s = worktree_basename(path, &n);
- new_branch = xstrndup(s, n);
+ new_branch = new_branch_to_free = xstrndup(s, n);
} else if (opts.orphan) {
- // No-op
+ ; /* no-op */
} else if (opts.detach) {
- // Check HEAD
+ /* 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.
+ /* 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);
+ /* DWIM: Guess branch name from path. */
+ char *s = dwim_branch(path, &new_branch_to_free);
if (s)
- branch = s;
+ branch = branch_to_free = s;
+ new_branch = new_branch_to_free;
- // DWIM: Infer --orphan when repo has no refs.
+ /* 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;
+ char *remote;
commit = lookup_commit_reference_by_name(branch);
if (!commit) {
remote = unique_tracking_name(branch, &oid, NULL);
if (remote) {
new_branch = branch;
- branch = remote;
+ branch = new_branch_to_free = remote;
}
}
@@ -924,6 +926,9 @@ static int add(int ac, const char **av, const char *prefix)
ret = add_worktree(path, branch, &opts);
free(path);
+ free(opt_track);
+ free(branch_to_free);
+ free(new_branch_to_free);
return ret;
}
@@ -976,7 +981,9 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
- char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+ char *ref = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ wt->head_ref,
+ 0);
strbuf_addf(&sb, "[%s]", ref);
free(ref);
} else
@@ -1143,14 +1150,14 @@ static void validate_no_submodules(const struct worktree *wt)
struct strbuf path = STRBUF_INIT;
int i, found_submodules = 0;
- if (is_directory(worktree_git_path(wt, "modules"))) {
+ if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
/*
* There could be false positives, e.g. the "modules"
* directory exists but is empty. But it's a rare case and
* this simpler check is probably good enough for now.
*/
found_submodules = 1;
- } else if (read_index_from(&istate, worktree_git_path(wt, "index"),
+ } else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
get_worktree_git_dir(wt)) > 0) {
for (i = 0; i < istate.cache_nr; i++) {
struct cache_entry *ce = istate.cache[i];
@@ -1387,7 +1394,10 @@ static int repair(int ac, const char **av, const char *prefix)
return rc;
}
-int cmd_worktree(int ac, const char **av, const char *prefix)
+int cmd_worktree(int ac,
+ const char **av,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 66e83d0ecb..43f233e69b 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -3,23 +3,24 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.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>/]"),
NULL
};
-int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
+int cmd_write_tree(int argc,
+ const char **argv,
+ const char *cmd_prefix,
+ struct repository *repo UNUSED)
{
int flags = 0, ret;
const char *tree_prefix = NULL;
@@ -44,8 +45,9 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
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);
+ ret = write_index_as_tree(&oid, the_repository->index,
+ repo_get_index_file(the_repository),
+ flags, tree_prefix);
switch (ret) {
case 0:
printf("%s\n", oid_to_hex(&oid));
diff --git a/bulk-checkin.c b/bulk-checkin.c
index 73bff3a23d..2753d5bbe4 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -1,6 +1,9 @@
/*
* Copyright (c) 2011, Google Inc.
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "bulk-checkin.h"
#include "environment.h"
@@ -11,7 +14,6 @@
#include "csum-file.h"
#include "pack.h"
#include "strbuf.h"
-#include "string-list.h"
#include "tmp-objdir.h"
#include "packfile.h"
#include "object-file.h"
@@ -59,6 +61,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
if (state->nr_written == 0) {
close(state->f->fd);
+ free_hashfile(state->f);
unlink(state->pack_tmp_name);
goto clear_exit;
} else if (state->nr_written == 1) {
@@ -72,7 +75,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
close(fd);
}
- strbuf_addf(&packname, "%s/pack/pack-%s.", get_object_directory(),
+ strbuf_addf(&packname, "%s/pack/pack-%s.", repo_get_object_directory(the_repository),
hash_to_hex(hash));
finish_tmp_packfile(&packname, state->pack_tmp_name,
state->written, state->nr_written,
@@ -81,6 +84,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
free(state->written[i]);
clear_exit:
+ free(state->pack_tmp_name);
free(state->written);
memset(state, 0, sizeof(*state));
@@ -109,7 +113,7 @@ static void flush_batch_fsync(void)
* to ensure that the data in each new object file is durable before
* the final name is visible.
*/
- strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX", get_object_directory());
+ strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX", repo_get_object_directory(the_repository));
temp = xmks_tempfile(temp_path.buf);
fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
delete_tempfile(&temp);
@@ -155,10 +159,10 @@ static int already_written(struct bulk_checkin_packfile *state, struct object_id
* status before calling us just in case we ask it to call us again
* with a new pack.
*/
-static int stream_to_pack(struct bulk_checkin_packfile *state,
- git_hash_ctx *ctx, off_t *already_hashed_to,
- int fd, size_t size, enum object_type type,
- const char *path, unsigned flags)
+static int stream_blob_to_pack(struct bulk_checkin_packfile *state,
+ git_hash_ctx *ctx, off_t *already_hashed_to,
+ int fd, size_t size, const char *path,
+ unsigned flags)
{
git_zstream s;
unsigned char ibuf[16384];
@@ -170,7 +174,7 @@ static int stream_to_pack(struct bulk_checkin_packfile *state,
git_deflate_init(&s, pack_compression_level);
- hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), type, size);
+ hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);
s.next_out = obuf + hdrlen;
s.avail_out = sizeof(obuf) - hdrlen;
@@ -247,11 +251,10 @@ static void prepare_to_stream(struct bulk_checkin_packfile *state,
die_errno("unable to write pack header");
}
-static int deflate_to_pack(struct bulk_checkin_packfile *state,
- struct object_id *result_oid,
- int fd, size_t size,
- enum object_type type, const char *path,
- unsigned flags)
+static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
+ struct object_id *result_oid,
+ int fd, size_t size,
+ const char *path, unsigned flags)
{
off_t seekback, already_hashed_to;
git_hash_ctx ctx;
@@ -265,9 +268,10 @@ static int deflate_to_pack(struct bulk_checkin_packfile *state,
return error("cannot find the current offset");
header_len = format_object_header((char *)obuf, sizeof(obuf),
- type, size);
+ OBJ_BLOB, size);
the_hash_algo->init_fn(&ctx);
the_hash_algo->update_fn(&ctx, obuf, header_len);
+ the_hash_algo->init_fn(&checkpoint.ctx);
/* Note: idx is non-NULL when we are writing */
if ((flags & HASH_WRITE_OBJECT) != 0)
@@ -282,8 +286,8 @@ static int deflate_to_pack(struct bulk_checkin_packfile *state,
idx->offset = state->offset;
crc32_begin(state->f);
}
- if (!stream_to_pack(state, &ctx, &already_hashed_to,
- fd, size, type, path, flags))
+ if (!stream_blob_to_pack(state, &ctx, &already_hashed_to,
+ fd, size, path, flags))
break;
/*
* Writing this object to the current pack will make
@@ -350,12 +354,12 @@ void fsync_loose_object_bulk_checkin(int fd, const char *filename)
}
}
-int index_bulk_checkin(struct object_id *oid,
- int fd, size_t size, enum object_type type,
- const char *path, unsigned flags)
+int index_blob_bulk_checkin(struct object_id *oid,
+ int fd, size_t size,
+ const char *path, unsigned flags)
{
- int status = deflate_to_pack(&bulk_checkin_packfile, oid, fd, size, type,
- path, flags);
+ int status = deflate_blob_to_pack(&bulk_checkin_packfile, oid, fd, size,
+ path, flags);
if (!odb_transaction_nesting)
flush_bulk_checkin_packfile(&bulk_checkin_packfile);
return status;
diff --git a/bulk-checkin.h b/bulk-checkin.h
index 48fe9a6e91..aa7286a7b3 100644
--- a/bulk-checkin.h
+++ b/bulk-checkin.h
@@ -9,9 +9,9 @@
void prepare_loose_object_bulk_checkin(void);
void fsync_loose_object_bulk_checkin(int fd, const char *filename);
-int index_bulk_checkin(struct object_id *oid,
- int fd, size_t size, enum object_type type,
- const char *path, unsigned flags);
+int index_blob_bulk_checkin(struct object_id *oid,
+ int fd, size_t size,
+ const char *path, unsigned flags);
/*
* Tell the object database to optimize for adding
diff --git a/bundle-uri.c b/bundle-uri.c
index 4b5c49b93d..0df66e2872 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -1,16 +1,19 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "bundle-uri.h"
#include "bundle.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"
#include "pkt-line.h"
#include "config.h"
+#include "fetch-pack.h"
#include "remote.h"
+#include "trace2.h"
+#include "object-store-ll.h"
static struct {
enum bundle_list_heuristic heuristic;
@@ -20,7 +23,7 @@ static struct {
{ BUNDLE_HEURISTIC_CREATIONTOKEN, "creationToken" },
};
-static int compare_bundles(const void *hashmap_cmp_fn_data,
+static int compare_bundles(const void *hashmap_cmp_fn_data UNUSED,
const struct hashmap_entry *he1,
const struct hashmap_entry *he2,
const void *id)
@@ -45,7 +48,7 @@ void init_bundle_list(struct bundle_list *list)
}
static int clear_remote_bundle_info(struct remote_bundle_info *bundle,
- void *data)
+ void *data UNUSED)
{
FREE_AND_NULL(bundle->id);
FREE_AND_NULL(bundle->uri);
@@ -365,17 +368,23 @@ static int unbundle_from_file(struct repository *r, const char *file)
struct strbuf bundle_ref = STRBUF_INIT;
size_t bundle_prefix_len;
- if ((bundle_fd = read_bundle_header(file, &header)) < 0)
- return 1;
+ bundle_fd = read_bundle_header(file, &header);
+ if (bundle_fd < 0) {
+ result = 1;
+ goto cleanup;
+ }
/*
* Skip the reachability walk here, since we will be adding
* a reachable ref pointing to the new tips, which will reach
* the prerequisite commits.
*/
- if ((result = unbundle(r, &header, bundle_fd, NULL,
- VERIFY_BUNDLE_QUIET)))
- return 1;
+ result = unbundle(r, &header, bundle_fd, NULL,
+ VERIFY_BUNDLE_QUIET | (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0));
+ if (result) {
+ result = 1;
+ goto cleanup;
+ }
/*
* Convert all refs/heads/ from the bundle into refs/bundles/
@@ -396,13 +405,16 @@ static int unbundle_from_file(struct repository *r, const char *file)
strbuf_setlen(&bundle_ref, bundle_prefix_len);
strbuf_addstr(&bundle_ref, branch_name);
- has_old = !read_ref(bundle_ref.buf, &old_oid);
- update_ref("fetched bundle", bundle_ref.buf, oid,
- has_old ? &old_oid : NULL,
- REF_SKIP_OID_VERIFICATION,
- UPDATE_REFS_MSG_ON_ERR);
+ has_old = !refs_read_ref(get_main_ref_store(the_repository),
+ bundle_ref.buf, &old_oid);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "fetched bundle", bundle_ref.buf, oid,
+ has_old ? &old_oid : NULL,
+ 0, UPDATE_REFS_MSG_ON_ERR);
}
+cleanup:
+ strbuf_release(&bundle_ref);
bundle_header_release(&header);
return result;
}
@@ -779,7 +791,7 @@ static int unbundle_all_bundles(struct repository *r,
return 0;
}
-static int unlink_bundle(struct remote_bundle_info *info, void *data)
+static int unlink_bundle(struct remote_bundle_info *info, void *data UNUSED)
{
if (info->file)
unlink_or_warn(info->file);
@@ -796,6 +808,8 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
.id = xstrdup(""),
};
+ trace2_region_enter("fetch", "fetch-bundle-uri", the_repository);
+
init_bundle_list(&list);
/*
@@ -821,6 +835,7 @@ cleanup:
for_all_bundles_in_list(&list, unlink_bundle, NULL);
clear_bundle_list(&list);
clear_remote_bundle_info(&bundle, NULL);
+ trace2_region_leave("fetch", "fetch-bundle-uri", the_repository);
return result;
}
diff --git a/bundle.c b/bundle.c
index a9744da255..4773b51eb1 100644
--- a/bundle.c
+++ b/bundle.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "lockfile.h"
#include "bundle.h"
@@ -87,7 +89,12 @@ int read_bundle_header_fd(int fd, struct bundle_header *header,
goto abort;
}
- header->hash_algo = the_hash_algo;
+ /*
+ * The default hash format for bundles is SHA1, unless told otherwise
+ * by an "object-format=" capability, which is being handled in
+ * `parse_capability()`.
+ */
+ header->hash_algo = &hash_algos[GIT_HASH_SHA1];
/* The bundle header ends with an empty line */
while (!strbuf_getwholeline_fd(&buf, fd, '\n') &&
@@ -389,7 +396,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
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))
+ if (refs_read_ref_full(get_main_ref_store(the_repository), e->name, RESOLVE_REF_READING, &oid, &flag))
flag = 0;
display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
@@ -500,6 +507,7 @@ int create_bundle(struct repository *r, const char *path,
struct rev_info revs, revs_copy;
int min_version = 2;
struct bundle_prerequisites_info bpi;
+ int ret;
int i;
/* init revs to list objects for pack-objects later */
@@ -525,8 +533,8 @@ int create_bundle(struct repository *r, const char *path,
min_version = 3;
if (argc > 1) {
- error(_("unrecognized argument: %s"), argv[1]);
- goto err;
+ ret = error(_("unrecognized argument: %s"), argv[1]);
+ goto out;
}
bundle_to_stdout = !strcmp(path, "-");
@@ -591,23 +599,31 @@ int create_bundle(struct repository *r, const char *path,
/* write bundle refs */
ref_count = write_bundle_refs(bundle_fd, &revs_copy);
- if (!ref_count)
+ if (!ref_count) {
die(_("Refusing to create empty bundle."));
- else if (ref_count < 0)
- goto err;
+ } else if (ref_count < 0) {
+ ret = -1;
+ goto out;
+ }
/* write pack */
- if (write_pack_data(bundle_fd, &revs_copy, pack_options))
- goto err;
+ if (write_pack_data(bundle_fd, &revs_copy, pack_options)) {
+ ret = -1;
+ goto out;
+ }
if (!bundle_to_stdout) {
if (commit_lock_file(&lock))
die_errno(_("cannot create '%s'"), path);
}
- return 0;
-err:
+
+ ret = 0;
+
+out:
+ object_array_clear(&revs_copy.pending);
+ release_revisions(&revs);
rollback_lock_file(&lock);
- return -1;
+ return ret;
}
int unbundle(struct repository *r, struct bundle_header *header,
@@ -625,10 +641,11 @@ int unbundle(struct repository *r, struct bundle_header *header,
if (header->filter.choice)
strvec_push(&ip.args, "--promisor=from-bundle");
- if (extra_index_pack_args) {
+ if (flags & VERIFY_BUNDLE_FSCK)
+ strvec_push(&ip.args, "--fsck-objects");
+
+ if (extra_index_pack_args)
strvec_pushv(&ip.args, extra_index_pack_args->v);
- strvec_clear(extra_index_pack_args);
- }
ip.in = bundle_fd;
ip.no_stdout = 1;
diff --git a/bundle.h b/bundle.h
index 021adbdcbb..5ccc9a061a 100644
--- a/bundle.h
+++ b/bundle.h
@@ -33,6 +33,7 @@ int create_bundle(struct repository *r, const char *path,
enum verify_bundle_flags {
VERIFY_BUNDLE_VERBOSE = (1 << 0),
VERIFY_BUNDLE_QUIET = (1 << 1),
+ VERIFY_BUNDLE_FSCK = (1 << 2),
};
int verify_bundle(struct repository *r, struct bundle_header *header,
diff --git a/cache-tree.c b/cache-tree.c
index 641427ed41..c595e86120 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -1,5 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "environment.h"
+#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
#include "tree.h"
@@ -10,8 +12,8 @@
#include "object-store-ll.h"
#include "read-cache-ll.h"
#include "replace-object.h"
+#include "repository.h"
#include "promisor-remote.h"
-#include "sparse-index.h"
#include "trace.h"
#include "trace2.h"
@@ -423,7 +425,7 @@ static int update_one(struct cache_tree *it,
/*
* "sub" can be an empty tree if all subentries are i-t-a.
*/
- if (contains_ita && is_empty_tree_oid(oid))
+ if (contains_ita && is_empty_tree_oid(oid, the_repository->hash_algo))
continue;
strbuf_grow(&buffer, entlen + 100);
@@ -448,7 +450,7 @@ static int update_one(struct cache_tree *it,
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
OBJ_TREE, &it->oid);
} else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE,
- &it->oid, flags & WRITE_TREE_SILENT
+ &it->oid, NULL, flags & WRITE_TREE_SILENT
? HASH_SILENT : 0)) {
strbuf_release(&buffer);
return -1;
@@ -579,7 +581,8 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
if (0 <= it->entry_count) {
if (size < rawsz)
goto free_return;
- oidread(&it->oid, (const unsigned char *)buf);
+ oidread(&it->oid, (const unsigned char *)buf,
+ the_repository->hash_algo);
buf += rawsz;
size -= rawsz;
}
@@ -723,7 +726,8 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
- entries = read_index_from(index_state, index_path, get_git_dir());
+ entries = read_index_from(index_state, index_path,
+ repo_get_git_dir(the_repository));
if (entries < 0) {
ret = WRITE_TREE_UNREADABLE_INDEX;
goto out;
@@ -770,7 +774,7 @@ static void prime_cache_tree_rec(struct repository *r,
oidcpy(&it->oid, &tree->object.oid);
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
cnt = 0;
while (tree_entry(&desc, &entry)) {
if (!S_ISDIR(entry.mode))
@@ -779,8 +783,8 @@ static void prime_cache_tree_rec(struct repository *r,
struct cache_tree_sub *sub;
struct tree *subtree = lookup_tree(r, &entry.oid);
- if (!subtree->object.parsed)
- parse_tree(subtree);
+ if (parse_tree(subtree) < 0)
+ exit(128);
sub = cache_tree_sub(it, entry.path);
sub->cache_tree = cache_tree();
@@ -862,15 +866,15 @@ int cache_tree_matches_traversal(struct cache_tree *root,
return 0;
}
-static void verify_one_sparse(struct index_state *istate,
- struct strbuf *path,
- int pos)
+static int verify_one_sparse(struct index_state *istate,
+ struct strbuf *path,
+ int pos)
{
struct cache_entry *ce = istate->cache[pos];
-
if (!S_ISSPARSEDIR(ce->ce_mode))
- BUG("directory '%s' is present in index, but not sparse",
- path->buf);
+ return error(_("directory '%s' is present in index, but not sparse"),
+ path->buf);
+ return 0;
}
/*
@@ -879,6 +883,7 @@ static void verify_one_sparse(struct index_state *istate,
* 1 - Restart verification - a call to ensure_full_index() freed the cache
* tree that is being verified and verification needs to be restarted from
* the new toplevel cache tree.
+ * -1 - Verification failed.
*/
static int verify_one(struct repository *r,
struct index_state *istate,
@@ -888,18 +893,23 @@ static int verify_one(struct repository *r,
int i, pos, len = path->len;
struct strbuf tree_buf = STRBUF_INIT;
struct object_id new_oid;
+ int ret;
for (i = 0; i < it->subtree_nr; i++) {
strbuf_addf(path, "%s/", it->down[i]->name);
- if (verify_one(r, istate, it->down[i]->cache_tree, path))
- return 1;
+ ret = verify_one(r, istate, it->down[i]->cache_tree, path);
+ if (ret)
+ goto out;
+
strbuf_setlen(path, len);
}
if (it->entry_count < 0 ||
/* no verification on tests (t7003) that replace trees */
- lookup_replace_object(r, &it->oid) != &it->oid)
- return 0;
+ lookup_replace_object(r, &it->oid) != &it->oid) {
+ ret = 0;
+ goto out;
+ }
if (path->len) {
/*
@@ -909,12 +919,14 @@ static int verify_one(struct repository *r,
*/
int is_sparse = istate->sparse_index;
pos = index_name_pos(istate, path->buf, path->len);
- if (is_sparse && !istate->sparse_index)
- return 1;
+ if (is_sparse && !istate->sparse_index) {
+ ret = 1;
+ goto out;
+ }
if (pos >= 0) {
- verify_one_sparse(istate, path, pos);
- return 0;
+ ret = verify_one_sparse(istate, path, pos);
+ goto out;
}
pos = -pos - 1;
@@ -922,6 +934,11 @@ static int verify_one(struct repository *r,
pos = 0;
}
+ if (it->entry_count + pos > istate->cache_nr) {
+ ret = error(_("corrupted cache-tree has entries not present in index"));
+ goto out;
+ }
+
i = 0;
while (i < it->entry_count) {
struct cache_entry *ce = istate->cache[pos + i];
@@ -932,16 +949,23 @@ static int verify_one(struct repository *r,
unsigned mode;
int entlen;
- if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE))
- BUG("%s with flags 0x%x should not be in cache-tree",
- ce->name, ce->ce_flags);
+ if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE)) {
+ ret = error(_("%s with flags 0x%x should not be in cache-tree"),
+ ce->name, ce->ce_flags);
+ goto out;
+ }
+
name = ce->name + path->len;
slash = strchr(name, '/');
if (slash) {
entlen = slash - name;
+
sub = find_subtree(it, ce->name + path->len, entlen, 0);
- if (!sub || sub->cache_tree->entry_count < 0)
- BUG("bad subtree '%.*s'", entlen, name);
+ if (!sub || sub->cache_tree->entry_count < 0) {
+ ret = error(_("bad subtree '%.*s'"), entlen, name);
+ goto out;
+ }
+
oid = &sub->cache_tree->oid;
mode = S_IFDIR;
i += sub->cache_tree->entry_count;
@@ -954,27 +978,50 @@ static int verify_one(struct repository *r,
strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
strbuf_add(&tree_buf, oid->hash, r->hash_algo->rawsz);
}
+
hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, OBJ_TREE,
&new_oid);
- if (!oideq(&new_oid, &it->oid))
- BUG("cache-tree for path %.*s does not match. "
- "Expected %s got %s", len, path->buf,
- oid_to_hex(&new_oid), oid_to_hex(&it->oid));
+
+ if (!oideq(&new_oid, &it->oid)) {
+ ret = error(_("cache-tree for path %.*s does not match. "
+ "Expected %s got %s"), len, path->buf,
+ oid_to_hex(&new_oid), oid_to_hex(&it->oid));
+ goto out;
+ }
+
+ ret = 0;
+out:
strbuf_setlen(path, len);
strbuf_release(&tree_buf);
- return 0;
+ return ret;
}
-void cache_tree_verify(struct repository *r, struct index_state *istate)
+int cache_tree_verify(struct repository *r, struct index_state *istate)
{
struct strbuf path = STRBUF_INIT;
+ int ret;
- if (!istate->cache_tree)
- return;
- if (verify_one(r, istate, istate->cache_tree, &path)) {
+ if (!istate->cache_tree) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = verify_one(r, istate, istate->cache_tree, &path);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
strbuf_reset(&path);
- if (verify_one(r, istate, istate->cache_tree, &path))
+
+ ret = verify_one(r, istate, istate->cache_tree, &path);
+ if (ret < 0)
+ goto out;
+ if (ret > 0)
BUG("ensure_full_index() called twice while verifying cache tree");
}
+
+ ret = 0;
+
+out:
strbuf_release(&path);
+ return ret;
}
diff --git a/cache-tree.h b/cache-tree.h
index faae88be63..b82c4963e7 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -33,7 +33,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
int cache_tree_fully_valid(struct cache_tree *);
int cache_tree_update(struct index_state *, int);
-void cache_tree_verify(struct repository *, struct index_state *);
+int cache_tree_verify(struct repository *, struct index_state *);
/* bitmasks to write_index_as_tree flags */
#define WRITE_TREE_MISSING_OK 1
diff --git a/cbtree.c b/cbtree.c
index c1cc30a5dc..cf8cf75b89 100644
--- a/cbtree.c
+++ b/cbtree.c
@@ -12,7 +12,7 @@ static struct cb_node *cb_node_of(const void *p)
return (struct cb_node *)((uintptr_t)p - 1);
}
-/* locate the best match, does not do a final comparision */
+/* locate the best match, does not do a final comparison */
static struct cb_node *cb_internal_best_match(struct cb_node *p,
const uint8_t *k, size_t klen)
{
diff --git a/checkout.c b/checkout.c
index 4256e71a7c..0b1cf8b40b 100644
--- a/checkout.c
+++ b/checkout.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "object-name.h"
#include "remote.h"
@@ -45,8 +47,8 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
return 0;
}
-const char *unique_tracking_name(const char *name, struct object_id *oid,
- int *dwim_remotes_matched)
+char *unique_tracking_name(const char *name, struct object_id *oid,
+ int *dwim_remotes_matched)
{
struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
const char *default_remote = NULL;
diff --git a/checkout.h b/checkout.h
index 3c514a5ab4..55920e7aeb 100644
--- a/checkout.h
+++ b/checkout.h
@@ -1,15 +1,15 @@
#ifndef CHECKOUT_H
#define CHECKOUT_H
-#include "hash-ll.h"
+#include "hash.h"
/*
* Check if the branch name uniquely matches a branch name on a remote
* tracking branch. Return the name of the remote if such a branch
* exists, NULL otherwise.
*/
-const char *unique_tracking_name(const char *name,
- struct object_id *oid,
- int *dwim_remotes_matched);
+char *unique_tracking_name(const char *name,
+ struct object_id *oid,
+ int *dwim_remotes_matched);
#endif /* CHECKOUT_H */
diff --git a/chunk-format.c b/chunk-format.c
index 140dfa0dcc..2dde24e6a3 100644
--- a/chunk-format.c
+++ b/chunk-format.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "chunk-format.h"
#include "csum-file.h"
@@ -102,7 +104,8 @@ int read_table_of_contents(struct chunkfile *cf,
const unsigned char *mfile,
size_t mfile_size,
uint64_t toc_offset,
- int toc_length)
+ int toc_length,
+ unsigned expected_alignment)
{
int i;
uint32_t chunk_id;
@@ -120,6 +123,11 @@ int read_table_of_contents(struct chunkfile *cf,
error(_("terminating chunk id appears earlier than expected"));
return 1;
}
+ if (chunk_offset % expected_alignment != 0) {
+ error(_("chunk id %"PRIx32" not %d-byte aligned"),
+ chunk_id, expected_alignment);
+ return 1;
+ }
table_of_contents += CHUNK_TOC_ENTRY_SIZE;
next_chunk_offset = get_be64(table_of_contents + 4);
@@ -154,20 +162,28 @@ int read_table_of_contents(struct chunkfile *cf,
return 0;
}
+struct pair_chunk_data {
+ const unsigned char **p;
+ size_t *size;
+};
+
static int pair_chunk_fn(const unsigned char *chunk_start,
size_t chunk_size,
void *data)
{
- const unsigned char **p = data;
- *p = chunk_start;
+ struct pair_chunk_data *pcd = data;
+ *pcd->p = chunk_start;
+ *pcd->size = chunk_size;
return 0;
}
int pair_chunk(struct chunkfile *cf,
uint32_t chunk_id,
- const unsigned char **p)
+ const unsigned char **p,
+ size_t *size)
{
- return read_chunk(cf, chunk_id, pair_chunk_fn, p);
+ struct pair_chunk_data pcd = { .p = p, .size = size };
+ return read_chunk(cf, chunk_id, pair_chunk_fn, &pcd);
}
int read_chunk(struct chunkfile *cf,
diff --git a/chunk-format.h b/chunk-format.h
index c7794e84ad..212a0a6af1 100644
--- a/chunk-format.h
+++ b/chunk-format.h
@@ -1,7 +1,7 @@
#ifndef CHUNK_FORMAT_H
#define CHUNK_FORMAT_H
-#include "hash-ll.h"
+#include "hash.h"
struct hashfile;
struct chunkfile;
@@ -36,20 +36,23 @@ int read_table_of_contents(struct chunkfile *cf,
const unsigned char *mfile,
size_t mfile_size,
uint64_t toc_offset,
- int toc_length);
+ int toc_length,
+ unsigned expected_alignment);
#define CHUNK_NOT_FOUND (-2)
/*
* Find 'chunk_id' in the given chunkfile and assign the
* given pointer to the position in the mmap'd file where
- * that chunk begins.
+ * that chunk begins. Likewise the "size" parameter is filled
+ * with the size of the chunk.
*
* Returns CHUNK_NOT_FOUND if the chunk does not exist.
*/
int pair_chunk(struct chunkfile *cf,
uint32_t chunk_id,
- const unsigned char **p);
+ const unsigned char **p,
+ size_t *size);
typedef int (*chunk_read_fn)(const unsigned char *chunk_start,
size_t chunk_size, void *data);
diff --git a/ci/check-directional-formatting.bash b/ci/check-directional-formatting.bash
index e6211b141a..3cbbb7030e 100755
--- a/ci/check-directional-formatting.bash
+++ b/ci/check-directional-formatting.bash
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# This script verifies that the non-binary files tracked in the Git index do
# not contain any Unicode directional formatting: such formatting could be used
diff --git a/ci/check-whitespace.sh b/ci/check-whitespace.sh
new file mode 100755
index 0000000000..c40804394c
--- /dev/null
+++ b/ci/check-whitespace.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+#
+# Check that commits after a specified point do not contain new or modified
+# lines with whitespace errors. An optional formatted summary can be generated
+# by providing an output file path and url as additional arguments.
+#
+
+baseCommit=$1
+outputFile=$2
+url=$3
+
+if test "$#" -ne 1 && test "$#" -ne 3 || test -z "$1"
+then
+ echo "USAGE: $0 <BASE_COMMIT> [<OUTPUT_FILE> <URL>]"
+ exit 1
+fi
+
+problems=()
+commit=
+commitText=
+commitTextmd=
+goodParent=
+
+if ! git rev-parse --quiet --verify "${baseCommit}"
+then
+ echo "Invalid <BASE_COMMIT> '${baseCommit}'"
+ exit 1
+fi
+
+while read dash sha etc
+do
+ case "${dash}" in
+ "---") # Line contains commit information.
+ if test -z "${goodParent}"
+ then
+ # Assume the commit has no whitespace errors until detected otherwise.
+ goodParent=${sha}
+ fi
+
+ commit="${sha}"
+ commitText="${sha} ${etc}"
+ commitTextmd="[${sha}](${url}/commit/${sha}) ${etc}"
+ ;;
+ "")
+ ;;
+ *) # Line contains whitespace error information for current commit.
+ if test -n "${goodParent}"
+ then
+ problems+=("1) --- ${commitTextmd}")
+ echo ""
+ echo "--- ${commitText}"
+ goodParent=
+ fi
+
+ case "${dash}" in
+ *:[1-9]*:) # contains file and line number information
+ dashend=${dash#*:}
+ problems+=("[${dash}](${url}/blob/${commit}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}")
+ ;;
+ *)
+ problems+=("\`${dash} ${sha} ${etc}\`")
+ ;;
+ esac
+ echo "${dash} ${sha} ${etc}"
+ ;;
+ esac
+done <<< "$(git log --check --pretty=format:"---% h% s" "${baseCommit}"..)"
+
+if test ${#problems[*]} -gt 0
+then
+ if test -z "${goodParent}"
+ then
+ goodParent=${baseCommit: 0:7}
+ fi
+
+ echo "A whitespace issue was found in one or more of the commits."
+ echo "Run the following command to resolve whitespace issues:"
+ echo "git rebase --whitespace=fix ${goodParent}"
+
+ # If target output file is provided, write formatted output.
+ if test -n "$outputFile"
+ then
+ echo "🛑 Please review the Summary output for further information."
+ (
+ echo "### :x: A whitespace issue was found in one or more of the commits."
+ echo ""
+ echo "Run these commands to correct the problem:"
+ echo "1. \`git rebase --whitespace=fix ${goodParent}\`"
+ echo "1. \`git push --force\`"
+ echo ""
+ echo "Errors:"
+
+ for i in "${problems[@]}"
+ do
+ echo "${i}"
+ done
+ ) >"$outputFile"
+ fi
+
+ exit 2
+fi
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index 33039d516b..126e570eb4 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -1,49 +1,93 @@
-#!/usr/bin/env bash
+#!/bin/sh
#
# Install dependencies required to build and test Git on Linux and macOS
#
. ${0%/*}/lib.sh
-P4WHENCE=https://cdist2.perforce.com/perforce/r21.2
+begin_group "Install dependencies"
+
+P4WHENCE=https://cdist2.perforce.com/perforce/r23.2
LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
-UBUNTU_COMMON_PKGS="make libssl-dev libcurl4-openssl-dev libexpat-dev
- tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl
- libemail-valid-perl libio-socket-ssl-perl libnet-smtp-ssl-perl"
+JGITWHENCE=https://repo.eclipse.org/content/groups/releases//org/eclipse/jgit/org.eclipse.jgit.pgm/6.8.0.202311291450-r/org.eclipse.jgit.pgm-6.8.0.202311291450-r.sh
+
+# Make sudo a no-op and execute the command directly when running as root.
+# While using sudo would be fine on most platforms when we are root already,
+# some platforms like e.g. Alpine Linux do not have sudo available by default
+# and would thus break.
+if test "$(id -u)" -eq 0
+then
+ sudo () {
+ "$@"
+ }
+fi
+
+case "$distro" in
+alpine-*)
+ apk add --update shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
+ pcre2-dev python3 musl-libintl perl-utils ncurses \
+ apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \
+ bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null
+ ;;
+fedora-*)
+ dnf -yq update >/dev/null &&
+ dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
+ ;;
+ubuntu-*|ubuntu32-*)
+ # Required so that apt doesn't wait for user input on certain packages.
+ export DEBIAN_FRONTEND=noninteractive
+
+ case "$distro" in
+ ubuntu-*)
+ SVN='libsvn-perl subversion'
+ ;;
+ *)
+ SVN=
+ ;;
+ esac
-case "$runs_on_pool" in
-ubuntu-*)
sudo apt-get -q update
- sudo apt-get -q -y install language-pack-is libsvn-perl apache2 \
- $UBUNTU_COMMON_PKGS $CC_PACKAGE $PYTHON_PACKAGE
- mkdir --parents "$P4_PATH"
- pushd "$P4_PATH"
- wget --quiet "$P4WHENCE/bin.linux26x86_64/p4d"
- wget --quiet "$P4WHENCE/bin.linux26x86_64/p4"
- chmod u+x p4d
- chmod u+x p4
- popd
- mkdir --parents "$GIT_LFS_PATH"
- pushd "$GIT_LFS_PATH"
+ sudo apt-get -q -y install \
+ language-pack-is apache2 cvs cvsps git gnupg $SVN \
+ make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \
+ tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \
+ libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \
+ ${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
+
+ case "$distro" in
+ ubuntu-16.04)
+ # Does not support JGit, but we also don't really care about
+ # the others. We rather care whether Git still compiles and
+ # runs fine overall.
+ ;;
+ ubuntu-*)
+ mkdir --parents "$CUSTOM_PATH"
+
+ wget --quiet --directory-prefix="$CUSTOM_PATH" \
+ "$P4WHENCE/bin.linux26x86_64/p4d" "$P4WHENCE/bin.linux26x86_64/p4"
+ chmod a+x "$CUSTOM_PATH/p4d" "$CUSTOM_PATH/p4"
+
wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
- tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
- cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs .
- popd
+ tar -xzf "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" \
+ -C "$CUSTOM_PATH" --strip-components=1 "git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs"
+ rm "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+
+ wget --quiet "$JGITWHENCE" --output-document="$CUSTOM_PATH/jgit"
+ chmod a+x "$CUSTOM_PATH/jgit"
+ ;;
+ esac
;;
macos-*)
export HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1
# Uncomment this if you want to run perf tests:
# brew install gnu-time
brew link --force gettext
- mkdir -p $HOME/bin
- (
- cd $HOME/bin
- wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
- tar -xf helix-core-server.tgz &&
- sudo xattr -d com.apple.quarantine p4 p4d 2>/dev/null || true
- )
- PATH="$PATH:${HOME}/bin"
- export PATH
+
+ mkdir -p "$CUSTOM_PATH"
+ wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
+ tar -xf helix-core-server.tgz -C "$CUSTOM_PATH" p4 p4d &&
+ sudo xattr -d com.apple.quarantine "$CUSTOM_PATH/p4" "$CUSTOM_PATH/p4d" 2>/dev/null || true
+ rm helix-core-server.tgz
if test -n "$CC_PACKAGE"
then
@@ -55,6 +99,10 @@ macos-*)
esac
case "$jobname" in
+ClangFormat)
+ sudo apt-get -q update
+ sudo apt-get -q -y install clang-format
+ ;;
StaticAnalysis)
sudo apt-get -q update
sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \
@@ -71,10 +119,7 @@ Documentation)
test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
sudo gem install --version 1.5.8 asciidoctor
- ;;
-linux-gcc-default)
- sudo apt-get -q update
- sudo apt-get -q -y install $UBUNTU_COMMON_PKGS
+ sudo gem install concurrent-ruby
;;
esac
@@ -87,6 +132,7 @@ then
else
echo >&2 "WARNING: perforce wasn't installed, see above for clues why"
fi
+
if type git-lfs >/dev/null 2>&1
then
echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)"
@@ -94,3 +140,13 @@ then
else
echo >&2 "WARNING: git-lfs wasn't installed, see above for clues why"
fi
+
+if type jgit >/dev/null 2>&1
+then
+ echo "$(tput setaf 6)JGit Version$(tput sgr0)"
+ jgit version
+else
+ echo >&2 "WARNING: JGit wasn't installed, see above for clues why"
+fi
+
+end_group "Install dependencies"
diff --git a/ci/install-docker-dependencies.sh b/ci/install-docker-dependencies.sh
deleted file mode 100755
index 78b7e326da..0000000000
--- a/ci/install-docker-dependencies.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-#
-# Install dependencies required to build and test Git inside container
-#
-
-case "$jobname" in
-linux32)
- linux32 --32bit i386 sh -c '
- apt update >/dev/null &&
- apt install -y build-essential libcurl4-openssl-dev \
- libssl-dev libexpat-dev gettext python >/dev/null
- '
- ;;
-linux-musl)
- apk add --update build-base curl-dev openssl-dev expat-dev gettext \
- pcre2-dev python3 musl-libintl perl-utils ncurses >/dev/null
- ;;
-pedantic)
- dnf -yq update >/dev/null &&
- dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
- ;;
-esac
diff --git a/ci/install-sdk.ps1 b/ci/install-sdk.ps1
new file mode 100755
index 0000000000..66f24838a4
--- /dev/null
+++ b/ci/install-sdk.ps1
@@ -0,0 +1,12 @@
+param(
+ [string]$directory='git-sdk',
+ [string]$url='https://github.com/git-for-windows/git-sdk-64/releases/download/ci-artifacts/git-sdk-x86_64-minimal.zip'
+)
+
+Invoke-WebRequest "$url" -OutFile git-sdk.zip
+Expand-Archive -LiteralPath git-sdk.zip -DestinationPath "$directory"
+Remove-Item -Path git-sdk.zip
+
+New-Item -Path .git/info -ItemType Directory -Force
+New-Item -Path .git/info/exclude -ItemType File -Force
+Add-Content -Path .git/info/exclude -Value "/$directory"
diff --git a/ci/lib.sh b/ci/lib.sh
index bc0b23099d..930f98d722 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -1,16 +1,7 @@
# Library of functions shared by all CI scripts
-if test true != "$GITHUB_ACTIONS"
+if test true = "$GITHUB_ACTIONS"
then
- begin_group () { :; }
- end_group () { :; }
-
- group () {
- shift
- "$@"
- }
- set -x
-else
begin_group () {
need_to_end_group=t
echo "::group::$1" >&2
@@ -23,32 +14,55 @@ else
need_to_end_group=
echo '::endgroup::' >&2
}
- trap end_group EXIT
+elif test true = "$GITLAB_CI"
+then
+ begin_group () {
+ need_to_end_group=t
+ printf "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)[collapsed=true]\r\e[0K$1\n"
+ trap "end_group '$1'" EXIT
+ set -x
+ }
- group () {
+ end_group () {
+ test -n "$need_to_end_group" || return 0
set +x
- begin_group "$1"
- shift
- # work around `dash` not supporting `set -o pipefail`
- (
- "$@" 2>&1
- echo $? >exit.status
- ) |
- sed 's/^\(\([^ ]*\):\([0-9]*\):\([0-9]*:\) \)\(error\|warning\): /::\5 file=\2,line=\3::\1/'
- res=$(cat exit.status)
- rm exit.status
- end_group
- return $res
+ need_to_end_group=
+ printf "\e[0Ksection_end:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K\n"
+ trap - EXIT
}
+else
+ begin_group () { :; }
+ end_group () { :; }
- begin_group "CI setup"
+ set -x
fi
+group () {
+ group="$1"
+ shift
+ begin_group "$group"
+
+ # work around `dash` not supporting `set -o pipefail`
+ (
+ "$@" 2>&1
+ echo $? >exit.status
+ ) |
+ sed 's/^\(\([^ ]*\):\([0-9]*\):\([0-9]*:\) \)\(error\|warning\): /::\5 file=\2,line=\3::\1/'
+ res=$(cat exit.status)
+ rm exit.status
+
+ end_group "$group"
+ return $res
+}
+
+begin_group "CI setup"
+trap "end_group 'CI setup'" EXIT
+
# Set 'exit on error' for all CI scripts to let the caller know that
# something went wrong.
#
# We already enabled tracing executed commands earlier. This helps by showing
-# how # environment variables are set and and dependencies are installed.
+# how # environment variables are set and dependencies are installed.
set -e
skip_branch_tip_with_tag () {
@@ -71,10 +85,32 @@ skip_branch_tip_with_tag () {
fi
}
+# Check whether we can use the path passed via the first argument as Git
+# repository.
+is_usable_git_repository () {
+ # We require Git in our PATH, otherwise we cannot access repositories
+ # at all.
+ if ! command -v git >/dev/null
+ then
+ return 1
+ fi
+
+ # And the target directory needs to be a proper Git repository.
+ if ! git -C "$1" rev-parse 2>/dev/null
+ then
+ return 1
+ fi
+}
+
# Save some info about the current commit's tree, so we can skip the build
# job if we encounter the same tree again and can provide a useful info
# message.
save_good_tree () {
+ if ! is_usable_git_repository .
+ then
+ return
+ fi
+
echo "$(git rev-parse $CI_COMMIT^{tree}) $CI_COMMIT $CI_JOB_NUMBER $CI_JOB_ID" >>"$good_trees_file"
# limit the file size
tail -1000 "$good_trees_file" >"$good_trees_file".tmp
@@ -90,6 +126,11 @@ skip_good_tree () {
return
fi
+ if ! is_usable_git_repository .
+ then
+ return
+ fi
+
if ! good_tree_info="$(grep "^$(git rev-parse $CI_COMMIT^{tree}) " "$good_trees_file")"
then
# Haven't seen this tree yet, or no cached good trees file yet.
@@ -121,6 +162,11 @@ skip_good_tree () {
}
check_unignored_build_artifacts () {
+ if ! is_usable_git_repository .
+ then
+ return
+ fi
+
! git ls-files --other --exclude-standard --error-unmatch \
-- ':/*' 2>/dev/null ||
{
@@ -133,6 +179,26 @@ handle_failed_tests () {
return 1
}
+create_failed_test_artifacts () {
+ mkdir -p t/failed-test-artifacts
+
+ for test_exit in t/test-results/*.exit
+ do
+ test 0 != "$(cat "$test_exit")" || continue
+
+ test_name="${test_exit%.exit}"
+ test_name="${test_name##*/}"
+ printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n"
+ echo "The full logs are in the 'print test failures' step below."
+ echo "See also the 'failed-tests-*' artifacts attached to this run."
+ cat "t/test-results/$test_name.markup"
+
+ trash_dir="t/trash directory.$test_name"
+ cp "t/test-results/$test_name.out" t/failed-test-artifacts/
+ tar czf t/failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
+ done
+}
+
# GitHub Action doesn't set TERM, which is required by tput
export TERM=${TERM:-dumb}
@@ -156,11 +222,8 @@ then
# among *all* phases)
cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
- export GIT_PROVE_OPTS="--timer --jobs 10 --state=failed,slow,save"
- export GIT_TEST_OPTS="--verbose-log -x --write-junit-xml"
- MAKEFLAGS="$MAKEFLAGS --jobs=10"
- test windows_nt != "$CI_OS_NAME" ||
- GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
+ GIT_TEST_OPTS="--write-junit-xml"
+ JOBS=10
elif test true = "$GITHUB_ACTIONS"
then
CI_TYPE=github-actions
@@ -173,40 +236,78 @@ then
CC="${CC_PACKAGE:-${CC:-gcc}}"
DONT_SKIP_TAGS=t
handle_failed_tests () {
- mkdir -p t/failed-test-artifacts
echo "FAILED_TEST_ARTIFACTS=t/failed-test-artifacts" >>$GITHUB_ENV
+ create_failed_test_artifacts
+ return 1
+ }
+
+ cache_dir="$HOME/none"
+
+ GIT_TEST_OPTS="--github-workflow-markup"
+ JOBS=10
+elif test true = "$GITLAB_CI"
+then
+ CI_TYPE=gitlab-ci
+ CI_BRANCH="$CI_COMMIT_REF_NAME"
+ CI_COMMIT="$CI_COMMIT_SHA"
+
+ case "$OS,$CI_JOB_IMAGE" in
+ Windows_NT,*)
+ CI_OS_NAME=windows
+ JOBS=$NUMBER_OF_PROCESSORS
+ ;;
+ *,macos-*)
+ # GitLab CI has Python installed via multiple package managers,
+ # most notably via asdf and Homebrew. Ensure that our builds
+ # pick up the Homebrew one by prepending it to our PATH as the
+ # asdf one breaks tests.
+ export PATH="$(brew --prefix)/bin:$PATH"
+
+ CI_OS_NAME=osx
+ JOBS=$(nproc)
+ ;;
+ *,alpine:*|*,fedora:*|*,ubuntu:*)
+ CI_OS_NAME=linux
+ JOBS=$(nproc)
+ ;;
+ *)
+ echo "Could not identify OS image" >&2
+ env >&2
+ exit 1
+ ;;
+ esac
+ CI_REPO_SLUG="$CI_PROJECT_PATH"
+ CI_JOB_ID="$CI_JOB_ID"
+ CC="${CC_PACKAGE:-${CC:-gcc}}"
+ DONT_SKIP_TAGS=t
- for test_exit in t/test-results/*.exit
- do
- test 0 != "$(cat "$test_exit")" || continue
-
- test_name="${test_exit%.exit}"
- test_name="${test_name##*/}"
- printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n"
- echo "The full logs are in the 'print test failures' step below."
- echo "See also the 'failed-tests-*' artifacts attached to this run."
- cat "t/test-results/$test_name.markup"
-
- trash_dir="t/trash directory.$test_name"
- cp "t/test-results/$test_name.out" t/failed-test-artifacts/
- tar czf t/failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
- done
+ handle_failed_tests () {
+ create_failed_test_artifacts
return 1
}
cache_dir="$HOME/none"
- export GIT_PROVE_OPTS="--timer --jobs 10"
- export GIT_TEST_OPTS="--verbose-log -x --github-workflow-markup"
- MAKEFLAGS="$MAKEFLAGS --jobs=10"
- test windows != "$CI_OS_NAME" ||
- GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
+ distro=$(echo "$CI_JOB_IMAGE" | tr : -)
else
echo "Could not identify CI type" >&2
env >&2
exit 1
fi
+MAKEFLAGS="$MAKEFLAGS --jobs=$JOBS"
+GIT_PROVE_OPTS="--timer --jobs $JOBS"
+
+GIT_TEST_OPTS="$GIT_TEST_OPTS --verbose-log -x"
+case "$CI_OS_NAME" in
+windows|windows_nt)
+ GIT_TEST_OPTS="$GIT_TEST_OPTS --no-chain-lint --no-bin-wrappers"
+ ;;
+esac
+
+export GIT_TEST_OPTS
+export GIT_PROVE_OPTS
+
good_trees_file="$cache_dir/good-trees"
mkdir -p "$cache_dir"
@@ -225,21 +326,32 @@ export DEFAULT_TEST_TARGET=prove
export GIT_TEST_CLONE_2GB=true
export SKIP_DASHED_BUILT_INS=YesPlease
-case "$runs_on_pool" in
+case "$distro" in
ubuntu-*)
if test "$jobname" = "linux-gcc-default"
then
break
fi
- PYTHON_PACKAGE=python2
- if test "$jobname" = linux-gcc
+ # Python 2 is end of life, and Ubuntu 23.04 and newer don't actually
+ # have it anymore. We thus only test with Python 2 on older LTS
+ # releases.
+ if test "$distro" = "ubuntu-20.04"
then
+ PYTHON_PACKAGE=python2
+ else
PYTHON_PACKAGE=python3
fi
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE"
- export GIT_TEST_HTTPD=true
+ case "$distro" in
+ ubuntu-16.04)
+ # Apache is too old for HTTP/2.
+ ;;
+ *)
+ export GIT_TEST_HTTPD=true
+ ;;
+ esac
# The Linux build installs the defined dependency versions below.
# The OS X build installs much more recent versions, whichever
@@ -247,10 +359,6 @@ ubuntu-*)
# image.
# Keep that in mind when you encounter a broken OS X build!
export LINUX_GIT_LFS_VERSION="1.5.2"
-
- P4_PATH="$HOME/custom/p4"
- GIT_LFS_PATH="$HOME/custom/git-lfs"
- export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
;;
macos-*)
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
@@ -261,6 +369,9 @@ macos-*)
;;
esac
+CUSTOM_PATH="${CUSTOM_PATH:-$HOME/path}"
+export PATH="$CUSTOM_PATH:$PATH"
+
case "$jobname" in
linux32)
CC=gcc
@@ -271,10 +382,8 @@ linux-musl)
MAKEFLAGS="$MAKEFLAGS NO_REGEX=Yes ICONV_OMITS_BOM=Yes"
MAKEFLAGS="$MAKEFLAGS GIT_TEST_UTF8_LOCALE=C.UTF-8"
;;
-linux-leaks)
+linux-leaks|linux-reftable-leaks)
export SANITIZE=leak
- export GIT_TEST_PASSING_SANITIZE_LEAK=true
- export GIT_TEST_SANITIZE_LEAK_LOG=true
;;
linux-asan-ubsan)
export SANITIZE=address,undefined
@@ -285,5 +394,5 @@ esac
MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
-end_group
+end_group "CI setup"
set -x
diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh
index 57277eefcd..b1f80aeac3 100755
--- a/ci/print-test-failures.sh
+++ b/ci/print-test-failures.sh
@@ -8,7 +8,7 @@
# Tracing executed commands would produce too much noise in the loop below.
set +x
-cd t/
+cd "${TEST_OUTPUT_DIRECTORY:-t/}"
if ! ls test-results/*.exit >/dev/null 2>/dev/null
then
@@ -51,6 +51,12 @@ do
tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
continue
;;
+ gitlab-ci)
+ mkdir -p failed-test-artifacts
+ cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
+ tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
+ continue
+ ;;
*)
echo "Unhandled CI type: $CI_TYPE" >&2
exit 1
diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh
new file mode 100755
index 0000000000..af8065f349
--- /dev/null
+++ b/ci/run-build-and-minimal-fuzzers.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# Build and test Git's fuzzers
+#
+
+. ${0%/*}/lib.sh
+
+group "Build fuzzers" make \
+ NO_CURL=NoThanks \
+ CC=clang \
+ FUZZ_CXX=clang++ \
+ CFLAGS="-fsanitize=fuzzer-no-link,address" \
+ LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
+ fuzz-all
+
+for fuzzer in commit-graph config date pack-headers pack-idx ; do
+ begin_group "fuzz-$fuzzer"
+ ./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1
+ end_group "fuzz-$fuzzer"
+done
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 2528f25e31..2e28d02b20 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -25,7 +25,7 @@ linux-TEST-vars)
export GIT_TEST_COMMIT_GRAPH=1
export GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1
export GIT_TEST_MULTI_PACK_INDEX=1
- export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
+ export GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=1
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
export GIT_TEST_NO_WRITE_REV_INDEX=1
export GIT_TEST_CHECKOUT_WORKERS=2
@@ -37,6 +37,9 @@ linux-clang)
linux-sha256)
export GIT_TEST_DEFAULT_HASH=sha256
;;
+linux-reftable|linux-reftable-leaks|osx-reftable)
+ export GIT_TEST_DEFAULT_REF_FORMAT=reftable
+ ;;
pedantic)
# Don't run the tests; we only care about whether Git can be
# built.
diff --git a/ci/run-docker-build.sh b/ci/run-docker-build.sh
deleted file mode 100755
index 6cd832efb9..0000000000
--- a/ci/run-docker-build.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/sh
-#
-# Build and test Git inside container
-#
-# Usage:
-# run-docker-build.sh <host-user-id>
-#
-
-set -ex
-
-if test $# -ne 1 || test -z "$1"
-then
- echo >&2 "usage: run-docker-build.sh <host-user-id>"
- exit 1
-fi
-
-case "$jobname" in
-linux32)
- switch_cmd="linux32 --32bit i386"
- ;;
-linux-musl)
- switch_cmd=
- useradd () { adduser -D "$@"; }
- ;;
-*)
- exit 1
- ;;
-esac
-
-"${0%/*}/install-docker-dependencies.sh"
-
-# If this script runs inside a docker container, then all commands are
-# usually executed as root. Consequently, the host user might not be
-# able to access the test output files.
-# If a non 0 host user id is given, then create a user "ci" with that
-# user id to make everything accessible to the host user.
-HOST_UID=$1
-if test $HOST_UID -eq 0
-then
- # Just in case someone does want to run the test suite as root.
- CI_USER=root
-else
- CI_USER=ci
- if test "$(id -u $CI_USER 2>/dev/null)" = $HOST_UID
- then
- echo "user '$CI_USER' already exists with the requested ID $HOST_UID"
- else
- useradd -u $HOST_UID $CI_USER
- fi
-fi
-
-# Build and test
-command $switch_cmd su -m -l $CI_USER -c "
- set -ex
- export DEVELOPER='$DEVELOPER'
- export DEFAULT_TEST_TARGET='$DEFAULT_TEST_TARGET'
- export GIT_PROVE_OPTS='$GIT_PROVE_OPTS'
- export GIT_TEST_OPTS='$GIT_TEST_OPTS'
- export GIT_TEST_CLONE_2GB='$GIT_TEST_CLONE_2GB'
- export MAKEFLAGS='$MAKEFLAGS'
- export cache_dir='$cache_dir'
- cd /usr/src/git
- test -n '$cache_dir' && ln -s '$cache_dir/.prove' t/.prove
- make
- make test
-"
diff --git a/ci/run-docker.sh b/ci/run-docker.sh
deleted file mode 100755
index af89d1624a..0000000000
--- a/ci/run-docker.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/sh
-#
-# Download and run Docker image to build and test Git
-#
-
-. ${0%/*}/lib.sh
-
-case "$jobname" in
-linux32)
- CI_CONTAINER="daald/ubuntu32:xenial"
- ;;
-linux-musl)
- CI_CONTAINER=alpine
- ;;
-*)
- exit 1
- ;;
-esac
-
-docker pull "$CI_CONTAINER"
-
-# Use the following command to debug the docker build locally:
-# <host-user-id> must be 0 if podman is used as drop-in replacement for docker
-# $ docker run -itv "${PWD}:/usr/src/git" --entrypoint /bin/sh "$CI_CONTAINER"
-# root@container:/# export jobname=<jobname>
-# root@container:/# /usr/src/git/ci/run-docker-build.sh <host-user-id>
-
-container_cache_dir=/tmp/container-cache
-
-docker run \
- --interactive \
- --env DEVELOPER \
- --env DEFAULT_TEST_TARGET \
- --env GIT_PROVE_OPTS \
- --env GIT_TEST_OPTS \
- --env GIT_TEST_CLONE_2GB \
- --env MAKEFLAGS \
- --env jobname \
- --env cache_dir="$container_cache_dir" \
- --volume "${PWD}:/usr/src/git" \
- --volume "$cache_dir:$container_cache_dir" \
- "$CI_CONTAINER" \
- /usr/src/git/ci/run-docker-build.sh $(id -u $USER)
-
-check_unignored_build_artifacts
-
-save_good_tree
diff --git a/ci/run-style-check.sh b/ci/run-style-check.sh
new file mode 100755
index 0000000000..6cd4b1d934
--- /dev/null
+++ b/ci/run-style-check.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Perform style check
+#
+
+baseCommit=$1
+
+# Remove optional braces of control statements (if, else, for, and while)
+# according to the LLVM coding style. This avoids braces on simple
+# single-statement bodies of statements but keeps braces if one side of
+# if/else if/.../else cascade has multi-statement body.
+#
+# As this rule comes with a warning [1], we want to experiment with it
+# before adding it in-tree. since the CI job for the style check is allowed
+# to fail, appending the rule here allows us to validate its efficacy.
+# While also ensuring that end-users are not affected directly.
+#
+# [1]: https://clang.llvm.org/docs/ClangFormatStyleOptions.html#removebracesllvm
+{
+ cat .clang-format
+ echo "RemoveBracesLLVM: true"
+} >/tmp/clang-format-rules
+
+git clang-format --style=file:/tmp/clang-format-rules \
+ --diff --extensions c,h "$baseCommit"
diff --git a/ci/run-test-slice.sh b/ci/run-test-slice.sh
index a3c67956a8..e167e646f7 100755
--- a/ci/run-test-slice.sh
+++ b/ci/run-test-slice.sh
@@ -15,4 +15,9 @@ group "Run tests" make --quiet -C t T="$(cd t &&
tr '\n' ' ')" ||
handle_failed_tests
+# We only have one unit test at the moment, so run it in the first slice
+if [ "$1" == "0" ] ; then
+ group "Run unit tests" make --quiet -C t unit-tests-test-tool
+fi
+
check_unignored_build_artifacts
diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh
index de41888430..02b3af3941 100755
--- a/ci/test-documentation.sh
+++ b/ci/test-documentation.sh
@@ -11,6 +11,7 @@ filter_log () {
-e '/^ \* new asciidoc flags$/d' \
-e '/stripped namespace before processing/d' \
-e '/Attributed.*IDs for element/d' \
+ -e '/SyntaxWarning: invalid escape sequence/d' \
"$1"
}
diff --git a/color.c b/color.c
index b24b19566b..227a5ab2f4 100644
--- a/color.c
+++ b/color.c
@@ -3,7 +3,7 @@
#include "color.h"
#include "editor.h"
#include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
#include "pager.h"
#include "strbuf.h"
@@ -64,12 +64,16 @@ static int match_word(const char *word, int len, const char *match)
return !strncasecmp(word, match, len) && !match[len];
}
-static int get_hex_color(const char *in, unsigned char *out)
+static int get_hex_color(const char **inp, int width, unsigned char *out)
{
+ const char *in = *inp;
unsigned int val;
- val = (hexval(in[0]) << 4) | hexval(in[1]);
+
+ assert(width == 1 || width == 2);
+ val = (hexval(in[0]) << 4) | hexval(in[width - 1]);
if (val & ~0xff)
return -1;
+ *inp += width;
*out = val;
return 0;
}
@@ -135,11 +139,14 @@ static int parse_color(struct color *out, const char *name, int len)
return 0;
}
- /* Try a 24-bit RGB value */
- if (len == 7 && name[0] == '#') {
- if (!get_hex_color(name + 1, &out->red) &&
- !get_hex_color(name + 3, &out->green) &&
- !get_hex_color(name + 5, &out->blue)) {
+ /* Try a 24- or 12-bit RGB value prefixed with '#' */
+ if ((len == 7 || len == 4) && name[0] == '#') {
+ int width_per_color = (len == 7) ? 2 : 1;
+ const char *color = name + 1;
+
+ if (!get_hex_color(&color, width_per_color, &out->red) &&
+ !get_hex_color(&color, width_per_color, &out->green) &&
+ !get_hex_color(&color, width_per_color, &out->blue)) {
out->type = COLOR_RGB;
return 0;
}
diff --git a/color.h b/color.h
index bb28343be2..7ed259a35b 100644
--- a/color.h
+++ b/color.h
@@ -112,7 +112,8 @@ int want_color_fd(int fd, int var);
* Translate a Git color from 'value' into a string that the terminal can
* interpret and store it into 'dst'. The Git color values are of the form
* "foreground [background] [attr]" where fore- and background can be a color
- * name ("red"), a RGB code (#0xFF0000) or a 256-color-mode from the terminal.
+ * name ("red"), a RGB code (#FF0000 or #F00) or a 256-color-mode from the
+ * terminal.
*/
int color_parse(const char *value, char *dst);
int color_parse_mem(const char *value, int len, char *dst);
diff --git a/column.c b/column.c
index ff2f0abf39..50bbccc92e 100644
--- a/column.c
+++ b/column.c
@@ -182,6 +182,8 @@ void print_columns(const struct string_list *list, unsigned int colopts,
{
struct column_options nopts;
+ if (opts && (0 > opts->padding))
+ BUG("padding must be non-negative");
if (!list->nr)
return;
assert((colopts & COL_ENABLE_MASK) != COL_AUTO);
@@ -361,6 +363,8 @@ int run_column_filter(int colopts, const struct column_options *opts)
{
struct strvec *argv;
+ if (opts && (0 > opts->padding))
+ BUG("padding must be non-negative");
if (fd_out != -1)
return -1;
diff --git a/combine-diff.c b/combine-diff.c
index f90f442482..33d0ed7097 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1,8 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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"
@@ -338,6 +339,8 @@ static char *grab_blob(struct repository *r,
free_filespec(df);
} else {
blob = repo_read_object_file(r, oid, &type, size);
+ if (!blob)
+ die(_("unable to read %s"), oid_to_hex(oid));
if (type != OBJ_BLOB)
die("object '%s' is not a blob!", oid_to_hex(oid));
}
@@ -1065,7 +1068,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
elem->mode = canon_mode(st.st_mode);
} else if (S_ISDIR(st.st_mode)) {
struct object_id oid;
- if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, elem->path,
+ "HEAD", &oid) < 0)
result = grab_blob(opt->repo, &elem->oid,
elem->mode, &result_size,
NULL, NULL);
@@ -1181,7 +1185,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
result_file.ptr = result;
result_file.size = result_size;
- /* Even p_lno[cnt+1] is valid -- that is for the end line number
+ /*
+ * Even p_lno[cnt+1] is valid -- that is for the end line number
* for deletion hunk at the end.
*/
CALLOC_ARRAY(sline[0].p_lno, st_mult(st_add(cnt, 2), num_parent));
@@ -1216,7 +1221,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
free(result);
- for (lno = 0; lno < cnt; lno++) {
+ for (lno = 0; lno < cnt + 2; lno++) {
if (sline[lno].lost) {
struct lline *ll = sline[lno].lost;
while (ll) {
@@ -1389,9 +1394,8 @@ static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
{
struct combine_diff_path *paths = NULL;
int i, num_parent = parents->nr;
-
int output_format = opt->output_format;
- const char *orderfile = opt->orderfile;
+ char *orderfile = opt->orderfile;
opt->output_format = DIFF_FORMAT_NO_OUTPUT;
/* tell diff_tree to emit paths in sorted (=tree) order */
diff --git a/command-list.txt b/command-list.txt
index 54b2a50f5f..e0bb87b3b5 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -157,9 +157,11 @@ git-read-tree plumbingmanipulators
git-rebase mainporcelain history
git-receive-pack synchelpers
git-reflog ancillarymanipulators complete
+git-refs ancillarymanipulators complete
git-remote ancillarymanipulators complete
git-repack ancillarymanipulators complete
git-replace ancillarymanipulators complete
+git-replay plumbingmanipulators
git-request-pull foreignscminterface complete
git-rerere ancillaryinterrogators
git-reset mainporcelain history
diff --git a/commit-graph.c b/commit-graph.c
index 9e6eaa8a46..5bd89c0acd 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1,14 +1,15 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
+#include "csum-file.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
-#include "pack.h"
#include "packfile.h"
#include "commit.h"
#include "object.h"
#include "refs.h"
-#include "revision.h"
#include "hash-lookup.h"
#include "commit-graph.h"
#include "object-file.h"
@@ -275,31 +276,25 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
return ret;
}
-static int verify_commit_graph_lite(struct commit_graph *g)
+static int graph_read_oid_fanout(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
{
- /*
- * Basic validation shared between parse_commit_graph()
- * which'll be called every time the graph is used, and the
- * much more expensive verify_commit_graph() used by
- * "commit-graph verify".
- *
- * There should only be very basic checks here to ensure that
- * we don't e.g. segfault in fill_commit_in_graph(), but
- * because this is a very hot codepath nothing that e.g. loops
- * over g->num_commits, or runs a checksum on the commit-graph
- * itself.
- */
- if (!g->chunk_oid_fanout) {
- error("commit-graph is missing the OID Fanout chunk");
- return 1;
- }
- if (!g->chunk_oid_lookup) {
- error("commit-graph is missing the OID Lookup chunk");
- return 1;
- }
- if (!g->chunk_commit_data) {
- error("commit-graph is missing the Commit Data chunk");
- return 1;
+ struct commit_graph *g = data;
+ int i;
+
+ if (chunk_size != 256 * sizeof(uint32_t))
+ return error(_("commit-graph oid fanout chunk is wrong size"));
+ g->chunk_oid_fanout = (const uint32_t *)chunk_start;
+ g->num_commits = ntohl(g->chunk_oid_fanout[255]);
+
+ for (i = 0; i < 255; i++) {
+ uint32_t oid_fanout1 = ntohl(g->chunk_oid_fanout[i]);
+ uint32_t oid_fanout2 = ntohl(g->chunk_oid_fanout[i + 1]);
+
+ if (oid_fanout1 > oid_fanout2) {
+ error(_("commit-graph fanout values out of order"));
+ return 1;
+ }
}
return 0;
@@ -310,7 +305,40 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,
{
struct commit_graph *g = data;
g->chunk_oid_lookup = chunk_start;
- g->num_commits = chunk_size / g->hash_len;
+ if (chunk_size / g->hash_len != g->num_commits)
+ return error(_("commit-graph OID lookup chunk is the wrong size"));
+ return 0;
+}
+
+static int graph_read_commit_data(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct commit_graph *g = data;
+ if (chunk_size / GRAPH_DATA_WIDTH != g->num_commits)
+ return error(_("commit-graph commit data chunk is wrong size"));
+ g->chunk_commit_data = chunk_start;
+ return 0;
+}
+
+static int graph_read_generation_data(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct commit_graph *g = data;
+ if (chunk_size / sizeof(uint32_t) != g->num_commits)
+ return error(_("commit-graph generations chunk is wrong size"));
+ g->chunk_generation_data = chunk_start;
+ return 0;
+}
+
+static int graph_read_bloom_index(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct commit_graph *g = data;
+ if (chunk_size / 4 != g->num_commits) {
+ warning(_("commit-graph changed-path index chunk is too small"));
+ return -1;
+ }
+ g->chunk_bloom_indexes = chunk_start;
return 0;
}
@@ -318,15 +346,20 @@ static int graph_read_bloom_data(const unsigned char *chunk_start,
size_t chunk_size, void *data)
{
struct commit_graph *g = data;
- uint32_t hash_version;
- g->chunk_bloom_data = chunk_start;
- hash_version = get_be32(chunk_start);
- if (hash_version != 1)
- return 0;
+ if (chunk_size < BLOOMDATA_CHUNK_HEADER_SIZE) {
+ warning(_("ignoring too-small changed-path chunk"
+ " (%"PRIuMAX" < %"PRIuMAX") in commit-graph file"),
+ (uintmax_t)chunk_size,
+ (uintmax_t)BLOOMDATA_CHUNK_HEADER_SIZE);
+ return -1;
+ }
+
+ g->chunk_bloom_data = chunk_start;
+ g->chunk_bloom_data_size = chunk_size;
g->bloom_filter_settings = xmalloc(sizeof(struct bloom_filter_settings));
- g->bloom_filter_settings->hash_version = hash_version;
+ g->bloom_filter_settings->hash_version = get_be32(chunk_start);
g->bloom_filter_settings->num_hashes = get_be32(chunk_start + 4);
g->bloom_filter_settings->bits_per_entry = get_be32(chunk_start + 8);
g->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES;
@@ -391,29 +424,41 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,
cf = init_chunkfile(NULL);
if (read_table_of_contents(cf, graph->data, graph_size,
- GRAPH_HEADER_SIZE, graph->num_chunks))
+ GRAPH_HEADER_SIZE, graph->num_chunks, 1))
+ goto free_and_return;
+
+ if (read_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, graph_read_oid_fanout, graph)) {
+ error(_("commit-graph required OID fanout chunk missing or corrupted"));
goto free_and_return;
+ }
+ if (read_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, graph_read_oid_lookup, graph)) {
+ error(_("commit-graph required OID lookup chunk missing or corrupted"));
+ goto free_and_return;
+ }
+ if (read_chunk(cf, GRAPH_CHUNKID_DATA, graph_read_commit_data, graph)) {
+ error(_("commit-graph required commit data chunk missing or corrupted"));
+ goto free_and_return;
+ }
- pair_chunk(cf, GRAPH_CHUNKID_OIDFANOUT,
- (const unsigned char **)&graph->chunk_oid_fanout);
- read_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, graph_read_oid_lookup, graph);
- pair_chunk(cf, GRAPH_CHUNKID_DATA, &graph->chunk_commit_data);
- pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges);
- pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs);
+ pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges,
+ &graph->chunk_extra_edges_size);
+ pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,
+ &graph->chunk_base_graphs_size);
if (s->commit_graph_generation_version >= 2) {
- pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
- &graph->chunk_generation_data);
+ read_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
+ graph_read_generation_data, graph);
pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
- &graph->chunk_generation_data_overflow);
+ &graph->chunk_generation_data_overflow,
+ &graph->chunk_generation_data_overflow_size);
if (graph->chunk_generation_data)
graph->read_generation_data = 1;
}
- if (s->commit_graph_read_changed_paths) {
- pair_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
- &graph->chunk_bloom_indexes);
+ if (s->commit_graph_changed_paths_version) {
+ read_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
+ graph_read_bloom_index, graph);
read_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
graph_read_bloom_data, graph);
}
@@ -427,10 +472,8 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,
FREE_AND_NULL(graph->bloom_filter_settings);
}
- oidread(&graph->oid, graph->data + graph->data_len - graph->hash_len);
-
- if (verify_commit_graph_lite(graph))
- goto free_and_return;
+ oidread(&graph->oid, graph->data + graph->data_len - graph->hash_len,
+ the_repository->hash_algo);
free_chunkfile(cf);
return graph;
@@ -473,6 +516,56 @@ static struct commit_graph *load_commit_graph_v1(struct repository *r,
return g;
}
+/*
+ * returns 1 if and only if all graphs in the chain have
+ * corrected commit dates stored in the generation_data chunk.
+ */
+static int validate_mixed_generation_chain(struct commit_graph *g)
+{
+ int read_generation_data = 1;
+ struct commit_graph *p = g;
+
+ while (read_generation_data && p) {
+ read_generation_data = p->read_generation_data;
+ p = p->base_graph;
+ }
+
+ if (read_generation_data)
+ return 1;
+
+ while (g) {
+ g->read_generation_data = 0;
+ g = g->base_graph;
+ }
+
+ return 0;
+}
+
+static void validate_mixed_bloom_settings(struct commit_graph *g)
+{
+ struct bloom_filter_settings *settings = NULL;
+ for (; g; g = g->base_graph) {
+ if (!g->bloom_filter_settings)
+ continue;
+ if (!settings) {
+ settings = g->bloom_filter_settings;
+ continue;
+ }
+
+ if (g->bloom_filter_settings->bits_per_entry != settings->bits_per_entry ||
+ g->bloom_filter_settings->num_hashes != settings->num_hashes ||
+ g->bloom_filter_settings->hash_version != settings->hash_version) {
+ g->chunk_bloom_indexes = NULL;
+ g->chunk_bloom_data = NULL;
+ FREE_AND_NULL(g->bloom_filter_settings);
+
+ warning(_("disabling Bloom filters for commit-graph "
+ "layer '%s' due to incompatible settings"),
+ oid_to_hex(&g->oid));
+ }
+ }
+}
+
static int add_graph_to_chain(struct commit_graph *g,
struct commit_graph *chain,
struct object_id *oids,
@@ -485,12 +578,18 @@ static int add_graph_to_chain(struct commit_graph *g,
return 0;
}
+ if (g->chunk_base_graphs_size / g->hash_len < n) {
+ warning(_("commit-graph base graphs chunk is too small"));
+ return 0;
+ }
+
while (n) {
n--;
if (!cur_g ||
!oideq(&oids[n], &cur_g->oid) ||
- !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n))) {
+ !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n),
+ the_repository->hash_algo)) {
warning(_("commit-graph chain does not match"));
return 0;
}
@@ -498,8 +597,6 @@ static int add_graph_to_chain(struct commit_graph *g,
cur_g = cur_g->base_graph;
}
- g->base_graph = chain;
-
if (chain) {
if (unsigned_add_overflows(chain->num_commits,
chain->num_commits_in_base)) {
@@ -510,34 +607,46 @@ static int add_graph_to_chain(struct commit_graph *g,
g->num_commits_in_base = chain->num_commits + chain->num_commits_in_base;
}
+ g->base_graph = chain;
+
return 1;
}
-static struct commit_graph *load_commit_graph_chain(struct repository *r,
- struct object_directory *odb)
+int open_commit_graph_chain(const char *chain_file,
+ int *fd, struct stat *st)
+{
+ *fd = git_open(chain_file);
+ if (*fd < 0)
+ return 0;
+ if (fstat(*fd, st)) {
+ close(*fd);
+ return 0;
+ }
+ if (st->st_size < the_hash_algo->hexsz) {
+ close(*fd);
+ if (!st->st_size) {
+ /* treat empty files the same as missing */
+ errno = ENOENT;
+ } else {
+ warning(_("commit-graph chain file too small"));
+ errno = EINVAL;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,
+ int fd, struct stat *st,
+ int *incomplete_chain)
{
struct commit_graph *graph_chain = NULL;
struct strbuf line = STRBUF_INIT;
- struct stat st;
struct object_id *oids;
int i = 0, valid = 1, count;
- char *chain_name = get_commit_graph_chain_filename(odb);
- FILE *fp;
- int stat_res;
+ FILE *fp = xfdopen(fd, "r");
- fp = fopen(chain_name, "r");
- stat_res = stat(chain_name, &st);
- free(chain_name);
-
- if (!fp)
- return NULL;
- if (stat_res ||
- st.st_size <= the_hash_algo->hexsz) {
- fclose(fp);
- return NULL;
- }
-
- count = st.st_size / (the_hash_algo->hexsz + 1);
+ count = st->st_size / (the_hash_algo->hexsz + 1);
CALLOC_ARRAY(oids, count);
prepare_alt_odb(r);
@@ -566,6 +675,8 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
if (add_graph_to_chain(g, graph_chain, oids, i)) {
graph_chain = g;
valid = 1;
+ } else {
+ free_commit_graph(g);
}
break;
@@ -578,36 +689,33 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
}
}
+ validate_mixed_generation_chain(graph_chain);
+ validate_mixed_bloom_settings(graph_chain);
+
free(oids);
fclose(fp);
strbuf_release(&line);
+ *incomplete_chain = !valid;
return graph_chain;
}
-/*
- * returns 1 if and only if all graphs in the chain have
- * corrected commit dates stored in the generation_data chunk.
- */
-static int validate_mixed_generation_chain(struct commit_graph *g)
+static struct commit_graph *load_commit_graph_chain(struct repository *r,
+ struct object_directory *odb)
{
- int read_generation_data = 1;
- struct commit_graph *p = g;
-
- while (read_generation_data && p) {
- read_generation_data = p->read_generation_data;
- p = p->base_graph;
- }
-
- if (read_generation_data)
- return 1;
+ char *chain_file = get_commit_graph_chain_filename(odb);
+ struct stat st;
+ int fd;
+ struct commit_graph *g = NULL;
- while (g) {
- g->read_generation_data = 0;
- g = g->base_graph;
+ if (open_commit_graph_chain(chain_file, &fd, &st)) {
+ int incomplete;
+ /* ownership of fd is taken over by load function */
+ g = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);
}
- return 0;
+ free(chain_file);
+ return g;
}
struct commit_graph *read_commit_graph_one(struct repository *r,
@@ -618,8 +726,6 @@ struct commit_graph *read_commit_graph_one(struct repository *r,
if (!g)
g = load_commit_graph_chain(r, odb);
- validate_mixed_generation_chain(g);
-
return g;
}
@@ -723,19 +829,14 @@ struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r)
return NULL;
}
-static void close_commit_graph_one(struct commit_graph *g)
+void close_commit_graph(struct raw_object_store *o)
{
- if (!g)
+ if (!o->commit_graph)
return;
clear_commit_graph_data_slab(&commit_graph_data_slab);
- close_commit_graph_one(g->base_graph);
- free_commit_graph(g);
-}
-
-void close_commit_graph(struct raw_object_store *o)
-{
- close_commit_graph_one(o->commit_graph);
+ deinit_bloom_filters();
+ free_commit_graph(o->commit_graph);
o->commit_graph = NULL;
}
@@ -762,7 +863,8 @@ static void load_oid_from_graph(struct commit_graph *g,
lex_index = pos - g->num_commits_in_base;
- oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index));
+ oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index),
+ the_repository->hash_algo);
}
static struct commit_list **insert_parent_or_die(struct repository *r,
@@ -815,7 +917,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
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 + st_mult(8, offset_pos));
+ if (g->chunk_generation_data_overflow_size / sizeof(uint64_t) <= offset_pos)
+ die(_("commit-graph overflow generation data is too small"));
+ graph_data->generation = item->date +
+ get_be64(g->chunk_generation_data_overflow + sizeof(uint64_t) * offset_pos);
} else
graph_data->generation = item->date + offset;
} else
@@ -835,7 +940,7 @@ static int fill_commit_in_graph(struct repository *r,
struct commit_graph *g, uint32_t pos)
{
uint32_t edge_value;
- uint32_t *parent_data_ptr;
+ uint32_t parent_data_pos;
struct commit_list **pptr;
const unsigned char *commit_data;
uint32_t lex_index;
@@ -867,14 +972,21 @@ static int fill_commit_in_graph(struct repository *r,
return 1;
}
- parent_data_ptr = (uint32_t*)(g->chunk_extra_edges +
- st_mult(4, edge_value & GRAPH_EDGE_LAST_MASK));
+ parent_data_pos = edge_value & GRAPH_EDGE_LAST_MASK;
do {
- edge_value = get_be32(parent_data_ptr);
+ if (g->chunk_extra_edges_size / sizeof(uint32_t) <= parent_data_pos) {
+ error(_("commit-graph extra-edges pointer out of bounds"));
+ free_commit_list(item->parents);
+ item->parents = NULL;
+ item->object.parsed = 0;
+ return 0;
+ }
+ edge_value = get_be32(g->chunk_extra_edges +
+ sizeof(uint32_t) * parent_data_pos);
pptr = insert_parent_or_die(r, g,
edge_value & GRAPH_EDGE_LAST_MASK,
pptr);
- parent_data_ptr++;
+ parent_data_pos++;
} while (!(edge_value & GRAPH_LAST_EDGE));
return 1;
@@ -917,14 +1029,18 @@ int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c,
struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id)
{
+ static int commit_graph_paranoia = -1;
struct commit *commit;
uint32_t pos;
+ if (commit_graph_paranoia == -1)
+ commit_graph_paranoia = git_env_bool(GIT_COMMIT_GRAPH_PARANOIA, 0);
+
if (!prepare_commit_graph(repo))
return NULL;
if (!search_commit_pos_in_graph(id, repo->objects->commit_graph, &pos))
return NULL;
- if (!has_object(repo, id, 0))
+ if (commit_graph_paranoia && !has_object(repo, id, 0))
return NULL;
commit = lookup_commit(repo, id);
@@ -990,7 +1106,7 @@ static struct tree *load_tree_for_commit(struct repository *r,
commit_data = g->chunk_commit_data +
st_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);
- oidread(&oid, commit_data);
+ oidread(&oid, commit_data, the_repository->hash_algo);
set_commit_tree(c, lookup_tree(r, &oid));
return c->maybe_tree;
@@ -1058,6 +1174,7 @@ struct write_commit_graph_context {
int count_bloom_filter_not_computed;
int count_bloom_filter_trunc_empty;
int count_bloom_filter_trunc_large;
+ int count_bloom_filter_upgraded;
};
static int write_graph_chunk_fanout(struct hashfile *f,
@@ -1508,7 +1625,7 @@ static void compute_reachable_generation_numbers(
timestamp_t gen;
repo_parse_commit(info->r, c);
gen = info->get_generation(c, info->data);
- display_progress(info->progress, info->progress_cnt + 1);
+ display_progress(info->progress, ++info->progress_cnt);
if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY)
continue;
@@ -1578,12 +1695,14 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
-static timestamp_t get_generation_from_graph_data(struct commit *c, void *data)
+static timestamp_t get_generation_from_graph_data(struct commit *c,
+ void *data UNUSED)
{
return commit_graph_data_at(c)->generation;
}
-static void set_generation_v2(struct commit *c, timestamp_t t, void *data)
+static void set_generation_v2(struct commit *c, timestamp_t t,
+ void *data UNUSED)
{
struct commit_graph_data *g = commit_graph_data_at(c);
g->generation = t;
@@ -1597,7 +1716,6 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
.commits = &ctx->commits,
.get_generation = get_generation_from_graph_data,
.set_generation = set_generation_v2,
- .data = ctx,
};
if (ctx->report_progress)
@@ -1626,7 +1744,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
}
static void set_generation_in_graph_data(struct commit *c, timestamp_t t,
- void *data)
+ void *data UNUSED)
{
commit_graph_data_at(c)->generation = t;
}
@@ -1664,6 +1782,8 @@ static void trace2_bloom_filter_write_statistics(struct write_commit_graph_conte
ctx->count_bloom_filter_trunc_empty);
trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-large",
ctx->count_bloom_filter_trunc_large);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-upgraded",
+ ctx->count_bloom_filter_upgraded);
}
static void compute_bloom_filters(struct write_commit_graph_context *ctx)
@@ -1705,6 +1825,8 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
ctx->count_bloom_filter_trunc_empty++;
if (computed & BLOOM_TRUNC_LARGE)
ctx->count_bloom_filter_trunc_large++;
+ } else if (computed & BLOOM_UPGRADED) {
+ ctx->count_bloom_filter_upgraded++;
} else if (computed & BLOOM_NOT_COMPUTED)
ctx->count_bloom_filter_not_computed++;
ctx->total_bloom_filter_data_size += filter
@@ -1725,13 +1847,14 @@ struct refs_cb_data {
};
static int add_ref_to_set(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
struct object_id peeled;
struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)
oidset_insert(data->commits, oid);
@@ -1755,7 +1878,8 @@ int write_commit_graph_reachable(struct object_directory *odb,
data.progress = start_delayed_progress(
_("Collecting referenced commits"), 0);
- for_each_ref(add_ref_to_set, &data);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,
+ &data);
stop_progress(&data.progress);
@@ -1911,8 +2035,8 @@ static int write_graph_chunk_base(struct hashfile *f,
static int write_commit_graph_file(struct write_commit_graph_context *ctx)
{
uint32_t i;
- int fd;
struct hashfile *f;
+ struct tempfile *graph_layer; /* when ctx->split is non-zero */
struct lock_file lk = LOCK_INIT;
const unsigned hashsz = the_hash_algo->rawsz;
struct strbuf progress_title = STRBUF_INIT;
@@ -1931,7 +2055,6 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
}
if (safe_create_leading_directories(ctx->graph_name)) {
- UNLEAK(ctx->graph_name);
error(_("unable to create leading directories of %s"),
ctx->graph_name);
return -1;
@@ -1944,24 +2067,23 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
LOCK_DIE_ON_ERROR, 0444);
free(lock_name);
- fd = git_mkstemp_mode(ctx->graph_name, 0444);
- if (fd < 0) {
+ graph_layer = mks_tempfile_m(ctx->graph_name, 0444);
+ if (!graph_layer) {
error(_("unable to create temporary graph layer"));
return -1;
}
- if (adjust_shared_perm(ctx->graph_name)) {
+ if (adjust_shared_perm(get_tempfile_path(graph_layer))) {
error(_("unable to adjust shared permissions for '%s'"),
- ctx->graph_name);
+ get_tempfile_path(graph_layer));
return -1;
}
- f = hashfd(fd, ctx->graph_name);
+ f = hashfd(get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));
} else {
hold_lock_file_for_update_mode(&lk, ctx->graph_name,
LOCK_DIE_ON_ERROR, 0444);
- fd = get_lock_file_fd(&lk);
- f = hashfd(fd, get_lock_file_path(&lk));
+ f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
}
cf = init_chunkfile(f);
@@ -2042,8 +2164,6 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
char *final_graph_name;
int result;
- close(fd);
-
if (!chainf) {
error(_("unable to open commit-graph chain file"));
return -1;
@@ -2071,12 +2191,14 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
free(graph_name);
}
+ free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));
final_graph_name = get_split_graph_filename(ctx->odb,
ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
+ free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);
ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
- result = rename(ctx->graph_name, final_graph_name);
+ result = rename_tempfile(&graph_layer, final_graph_name);
for (i = 0; i < ctx->num_commit_graphs_after; i++)
fprintf(get_lock_file_fp(&lk), "%s\n", ctx->commit_graph_hash_after[i]);
@@ -2386,6 +2508,13 @@ int write_commit_graph(struct object_directory *odb,
}
if (!commit_graph_compatible(r))
return 0;
+ if (r->settings.commit_graph_changed_paths_version < -1
+ || r->settings.commit_graph_changed_paths_version > 2) {
+ warning(_("attempting to write a commit-graph, but "
+ "'commitGraph.changedPathsVersion' (%d) is not supported"),
+ r->settings.commit_graph_changed_paths_version);
+ return 0;
+ }
CALLOC_ARRAY(ctx, 1);
ctx->r = r;
@@ -2398,6 +2527,7 @@ int write_commit_graph(struct object_directory *odb,
ctx->write_generation_data = (get_configured_generation_version(r) == 2);
ctx->num_generation_data_overflows = 0;
+ bloom_settings.hash_version = r->settings.commit_graph_changed_paths_version;
bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY",
bloom_settings.bits_per_entry);
bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES",
@@ -2427,12 +2557,20 @@ int write_commit_graph(struct object_directory *odb,
g = ctx->r->objects->commit_graph;
/* We have changed-paths already. Keep them in the next graph */
- if (g && g->chunk_bloom_data) {
+ if (g && g->bloom_filter_settings) {
ctx->changed_paths = 1;
- ctx->bloom_settings = g->bloom_filter_settings;
+
+ /* don't propagate the hash_version unless unspecified */
+ if (bloom_settings.hash_version == -1)
+ bloom_settings.hash_version = g->bloom_filter_settings->hash_version;
+ bloom_settings.bits_per_entry = g->bloom_filter_settings->bits_per_entry;
+ bloom_settings.num_hashes = g->bloom_filter_settings->num_hashes;
+ bloom_settings.max_changed_paths = g->bloom_filter_settings->max_changed_paths;
}
}
+ bloom_settings.hash_version = bloom_settings.hash_version == 2 ? 2 : 1;
+
if (ctx->split) {
struct commit_graph *g = ctx->r->objects->commit_graph;
@@ -2462,7 +2600,8 @@ int write_commit_graph(struct object_directory *odb,
struct commit_graph *g = ctx->r->objects->commit_graph;
for (i = 0; i < g->num_commits; i++) {
struct object_id oid;
- oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i));
+ oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),
+ the_repository->hash_algo);
oid_array_append(&ctx->oids, &oid);
}
}
@@ -2515,6 +2654,9 @@ int write_commit_graph(struct object_directory *odb,
res = write_commit_graph_file(ctx);
+ if (ctx->changed_paths)
+ deinit_bloom_filters();
+
if (ctx->split)
mark_commit_graphs(ctx);
@@ -2522,23 +2664,21 @@ int write_commit_graph(struct object_directory *odb,
cleanup:
free(ctx->graph_name);
+ free(ctx->base_graph_name);
free(ctx->commits.list);
oid_array_clear(&ctx->oids);
clear_topo_level_slab(&topo_levels);
- if (ctx->commit_graph_filenames_after) {
- for (i = 0; i < ctx->num_commit_graphs_after; i++) {
- free(ctx->commit_graph_filenames_after[i]);
- free(ctx->commit_graph_hash_after[i]);
- }
-
- for (i = 0; i < ctx->num_commit_graphs_before; i++)
- free(ctx->commit_graph_filenames_before[i]);
+ for (i = 0; i < ctx->num_commit_graphs_before; i++)
+ free(ctx->commit_graph_filenames_before[i]);
+ free(ctx->commit_graph_filenames_before);
- free(ctx->commit_graph_filenames_after);
- free(ctx->commit_graph_filenames_before);
- free(ctx->commit_graph_hash_after);
+ for (i = 0; i < ctx->num_commit_graphs_after; i++) {
+ free(ctx->commit_graph_filenames_after[i]);
+ free(ctx->commit_graph_hash_after[i]);
}
+ free(ctx->commit_graph_filenames_after);
+ free(ctx->commit_graph_hash_after);
free(ctx);
@@ -2575,10 +2715,6 @@ static int verify_one_commit_graph(struct repository *r,
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)
- return verify_commit_graph_error;
-
if (!commit_graph_checksum_valid(g)) {
graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
@@ -2587,7 +2723,8 @@ static int verify_one_commit_graph(struct repository *r,
for (i = 0; i < g->num_commits; i++) {
struct commit *graph_commit;
- oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i));
+ oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),
+ the_repository->hash_algo);
if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
graph_report(_("commit-graph has incorrect OID order: %s then %s"),
@@ -2631,7 +2768,8 @@ static int verify_one_commit_graph(struct repository *r,
timestamp_t generation;
display_progress(progress, ++(*seen));
- oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i));
+ oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),
+ the_repository->hash_algo);
graph_commit = lookup_commit(r, &cur_oid);
odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));
@@ -2752,15 +2890,17 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
void free_commit_graph(struct commit_graph *g)
{
- if (!g)
- return;
- if (g->data) {
- munmap((void *)g->data, g->data_len);
- g->data = NULL;
+ while (g) {
+ struct commit_graph *next = g->base_graph;
+
+ if (g->data)
+ munmap((void *)g->data, g->data_len);
+ free(g->filename);
+ free(g->bloom_filter_settings);
+ free(g);
+
+ g = next;
}
- free(g->filename);
- free(g->bloom_filter_settings);
- free(g);
}
void disable_commit_graph(struct repository *r)
diff --git a/commit-graph.h b/commit-graph.h
index 5e534f0fcc..6781940195 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -9,6 +9,12 @@
#define GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS "GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS"
/*
+ * This environment variable controls whether commits looked up via the
+ * commit graph will be double checked to exist in the object database.
+ */
+#define GIT_COMMIT_GRAPH_PARANOIA "GIT_COMMIT_GRAPH_PARANOIA"
+
+/*
* This method is only used to enhance coverage of the commit-graph
* feature in the test suite with the GIT_TEST_COMMIT_GRAPH and
* GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS environment variables. Do not
@@ -26,6 +32,7 @@ struct string_list;
char *get_commit_graph_filename(struct object_directory *odb);
char *get_commit_graph_chain_filename(struct object_directory *odb);
int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);
/*
* Given a commit struct, try to fill the commit struct info, including:
@@ -93,10 +100,14 @@ struct commit_graph {
const unsigned char *chunk_commit_data;
const unsigned char *chunk_generation_data;
const unsigned char *chunk_generation_data_overflow;
+ size_t chunk_generation_data_overflow_size;
const unsigned char *chunk_extra_edges;
+ size_t chunk_extra_edges_size;
const unsigned char *chunk_base_graphs;
+ size_t chunk_base_graphs_size;
const unsigned char *chunk_bloom_indexes;
const unsigned char *chunk_bloom_data;
+ size_t chunk_bloom_data_size;
struct topo_level_slab *topo_levels;
struct bloom_filter_settings *bloom_filter_settings;
@@ -105,9 +116,14 @@ struct commit_graph {
struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
int fd, struct stat *st,
struct object_directory *odb);
+struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,
+ int fd, struct stat *st,
+ int *incomplete_chain);
struct commit_graph *read_commit_graph_one(struct repository *r,
struct object_directory *odb);
+struct repo_settings;
+
/*
* Callers should initialize the repo_settings with prepare_repo_settings()
* prior to calling parse_commit_graph().
diff --git a/commit-reach.c b/commit-reach.c
index 4b7c233fd4..c3518aa360 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -1,10 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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"
@@ -50,13 +51,14 @@ static int queue_has_nonstale(struct prio_queue *queue)
}
/* all input commits in one and twos[] must have been parsed! */
-static struct commit_list *paint_down_to_common(struct repository *r,
- struct commit *one, int n,
- struct commit **twos,
- timestamp_t min_generation)
+static int paint_down_to_common(struct repository *r,
+ struct commit *one, int n,
+ struct commit **twos,
+ timestamp_t min_generation,
+ int ignore_missing_commits,
+ struct commit_list **result)
{
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
- struct commit_list *result = NULL;
int i;
timestamp_t last_gen = GENERATION_NUMBER_INFINITY;
@@ -65,8 +67,8 @@ static struct commit_list *paint_down_to_common(struct repository *r,
one->object.flags |= PARENT1;
if (!n) {
- commit_list_append(one, &result);
- return result;
+ commit_list_append(one, result);
+ return 0;
}
prio_queue_put(&queue, one);
@@ -94,7 +96,7 @@ static struct commit_list *paint_down_to_common(struct repository *r,
if (flags == (PARENT1 | PARENT2)) {
if (!(commit->object.flags & RESULT)) {
commit->object.flags |= RESULT;
- commit_list_insert_by_date(commit, &result);
+ commit_list_insert_by_date(commit, result);
}
/* Mark parents of a found merge stale */
flags |= STALE;
@@ -105,67 +107,97 @@ static struct commit_list *paint_down_to_common(struct repository *r,
parents = parents->next;
if ((p->object.flags & flags) == flags)
continue;
- if (repo_parse_commit(r, p))
- return NULL;
+ if (repo_parse_commit(r, p)) {
+ clear_prio_queue(&queue);
+ free_commit_list(*result);
+ *result = NULL;
+ /*
+ * At this stage, we know that the commit is
+ * missing: `repo_parse_commit()` uses
+ * `OBJECT_INFO_DIE_IF_CORRUPT` and therefore
+ * corrupt commits would already have been
+ * dispatched with a `die()`.
+ */
+ if (ignore_missing_commits)
+ return 0;
+ return error(_("could not parse commit %s"),
+ oid_to_hex(&p->object.oid));
+ }
p->object.flags |= flags;
prio_queue_put(&queue, p);
}
}
clear_prio_queue(&queue);
- return result;
+ return 0;
}
-static struct commit_list *merge_bases_many(struct repository *r,
- struct commit *one, int n,
- struct commit **twos)
+static int merge_bases_many(struct repository *r,
+ struct commit *one, int n,
+ struct commit **twos,
+ struct commit_list **result)
{
struct commit_list *list = NULL;
- struct commit_list *result = NULL;
int i;
for (i = 0; i < n; i++) {
- if (one == twos[i])
+ if (one == twos[i]) {
/*
* We do not mark this even with RESULT so we do not
* have to clean it up.
*/
- return commit_list_insert(one, &result);
+ *result = commit_list_insert(one, result);
+ return 0;
+ }
}
+ if (!one)
+ return 0;
if (repo_parse_commit(r, one))
- return NULL;
+ return error(_("could not parse commit %s"),
+ oid_to_hex(&one->object.oid));
for (i = 0; i < n; i++) {
+ if (!twos[i])
+ return 0;
if (repo_parse_commit(r, twos[i]))
- return NULL;
+ return error(_("could not parse commit %s"),
+ oid_to_hex(&twos[i]->object.oid));
}
- list = paint_down_to_common(r, one, n, twos, 0);
+ if (paint_down_to_common(r, one, n, twos, 0, 0, &list)) {
+ free_commit_list(list);
+ return -1;
+ }
while (list) {
struct commit *commit = pop_commit(&list);
if (!(commit->object.flags & STALE))
- commit_list_insert_by_date(commit, &result);
+ commit_list_insert_by_date(commit, result);
}
- return result;
+ return 0;
}
-struct commit_list *get_octopus_merge_bases(struct commit_list *in)
+int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result)
{
- struct commit_list *i, *j, *k, *ret = NULL;
+ struct commit_list *i, *j, *k;
if (!in)
- return ret;
+ return 0;
- commit_list_insert(in->item, &ret);
+ commit_list_insert(in->item, result);
for (i = in->next; i; i = i->next) {
struct commit_list *new_commits = NULL, *end = NULL;
- for (j = ret; j; j = j->next) {
- struct commit_list *bases;
- bases = repo_get_merge_bases(the_repository, i->item,
- j->item);
+ for (j = *result; j; j = j->next) {
+ struct commit_list *bases = NULL;
+ if (repo_get_merge_bases(the_repository, i->item,
+ j->item, &bases) < 0) {
+ free_commit_list(bases);
+ free_commit_list(*result);
+ *result = NULL;
+ return -1;
+ }
if (!new_commits)
new_commits = bases;
else
@@ -173,9 +205,10 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
for (k = bases; k; k = k->next)
end = k;
}
- ret = new_commits;
+ free_commit_list(*result);
+ *result = new_commits;
}
- return ret;
+ return 0;
}
static int remove_redundant_no_gen(struct repository *r,
@@ -193,7 +226,7 @@ static int remove_redundant_no_gen(struct repository *r,
for (i = 0; i < cnt; i++)
repo_parse_commit(r, array[i]);
for (i = 0; i < cnt; i++) {
- struct commit_list *common;
+ struct commit_list *common = NULL;
timestamp_t min_generation = commit_graph_generation(array[i]);
if (redundant[i])
@@ -209,8 +242,16 @@ static int remove_redundant_no_gen(struct repository *r,
if (curr_generation < min_generation)
min_generation = curr_generation;
}
- common = paint_down_to_common(r, array[i], filled,
- work, min_generation);
+ if (paint_down_to_common(r, array[i], filled,
+ work, min_generation, 0, &common)) {
+ clear_commit_marks(array[i], all_flags);
+ clear_commit_marks_many(filled, work, all_flags);
+ free_commit_list(common);
+ free(work);
+ free(redundant);
+ free(filled_index);
+ return -1;
+ }
if (array[i]->object.flags & PARENT2)
redundant[i] = 1;
for (j = 0; j < filled; j++)
@@ -375,69 +416,77 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
return remove_redundant_no_gen(r, array, cnt);
}
-static struct commit_list *get_merge_bases_many_0(struct repository *r,
- struct commit *one,
- int n,
- struct commit **twos,
- int cleanup)
+static int get_merge_bases_many_0(struct repository *r,
+ struct commit *one,
+ int n,
+ struct commit **twos,
+ int cleanup,
+ struct commit_list **result)
{
struct commit_list *list;
struct commit **rslt;
- struct commit_list *result;
int cnt, i;
- result = merge_bases_many(r, one, n, twos);
+ if (merge_bases_many(r, one, n, twos, result) < 0)
+ return -1;
for (i = 0; i < n; i++) {
if (one == twos[i])
- return result;
+ return 0;
}
- if (!result || !result->next) {
+ if (!*result || !(*result)->next) {
if (cleanup) {
clear_commit_marks(one, all_flags);
clear_commit_marks_many(n, twos, all_flags);
}
- return result;
+ return 0;
}
/* There are more than one */
- cnt = commit_list_count(result);
+ cnt = commit_list_count(*result);
CALLOC_ARRAY(rslt, cnt);
- for (list = result, i = 0; list; list = list->next)
+ for (list = *result, i = 0; list; list = list->next)
rslt[i++] = list->item;
- free_commit_list(result);
+ free_commit_list(*result);
+ *result = NULL;
clear_commit_marks(one, all_flags);
clear_commit_marks_many(n, twos, all_flags);
cnt = remove_redundant(r, rslt, cnt);
- result = NULL;
+ if (cnt < 0) {
+ free(rslt);
+ return -1;
+ }
for (i = 0; i < cnt; i++)
- commit_list_insert_by_date(rslt[i], &result);
+ commit_list_insert_by_date(rslt[i], result);
free(rslt);
- return result;
+ return 0;
}
-struct commit_list *repo_get_merge_bases_many(struct repository *r,
- struct commit *one,
- int n,
- struct commit **twos)
+int repo_get_merge_bases_many(struct repository *r,
+ struct commit *one,
+ int n,
+ struct commit **twos,
+ struct commit_list **result)
{
- return get_merge_bases_many_0(r, one, n, twos, 1);
+ return get_merge_bases_many_0(r, one, n, twos, 1, result);
}
-struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
- struct commit *one,
- int n,
- struct commit **twos)
+int repo_get_merge_bases_many_dirty(struct repository *r,
+ struct commit *one,
+ int n,
+ struct commit **twos,
+ struct commit_list **result)
{
- return get_merge_bases_many_0(r, one, n, twos, 0);
+ return get_merge_bases_many_0(r, one, n, twos, 0, result);
}
-struct commit_list *repo_get_merge_bases(struct repository *r,
- struct commit *one,
- struct commit *two)
+int repo_get_merge_bases(struct repository *r,
+ struct commit *one,
+ struct commit *two,
+ struct commit_list **result)
{
- return get_merge_bases_many_0(r, one, 1, &two, 1);
+ return get_merge_bases_many_0(r, one, 1, &two, 1, result);
}
/*
@@ -460,11 +509,13 @@ int repo_is_descendant_of(struct repository *r,
} else {
while (with_commit) {
struct commit *other;
+ int ret;
other = with_commit->item;
with_commit = with_commit->next;
- if (repo_in_merge_bases_many(r, other, 1, &commit))
- return 1;
+ ret = repo_in_merge_bases_many(r, other, 1, &commit, 0);
+ if (ret)
+ return ret;
}
return 0;
}
@@ -474,17 +525,18 @@ int repo_is_descendant_of(struct repository *r,
* Is "commit" an ancestor of one of the "references"?
*/
int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
- int nr_reference, struct commit **reference)
+ int nr_reference, struct commit **reference,
+ int ignore_missing_commits)
{
- struct commit_list *bases;
+ struct commit_list *bases = NULL;
int ret = 0, i;
timestamp_t generation, max_generation = GENERATION_NUMBER_ZERO;
if (repo_parse_commit(r, commit))
- return ret;
+ return ignore_missing_commits ? 0 : -1;
for (i = 0; i < nr_reference; i++) {
if (repo_parse_commit(r, reference[i]))
- return ret;
+ return ignore_missing_commits ? 0 : -1;
generation = commit_graph_generation(reference[i]);
if (generation > max_generation)
@@ -495,10 +547,11 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
if (generation > max_generation)
return ret;
- bases = paint_down_to_common(r, commit,
- nr_reference, reference,
- generation);
- if (commit->object.flags & PARENT2)
+ if (paint_down_to_common(r, commit,
+ nr_reference, reference,
+ generation, ignore_missing_commits, &bases))
+ ret = -1;
+ else if (commit->object.flags & PARENT2)
ret = 1;
clear_commit_marks(commit, all_flags);
clear_commit_marks_many(nr_reference, reference, all_flags);
@@ -551,6 +604,10 @@ struct commit_list *reduce_heads(struct commit_list *heads)
}
}
num_head = remove_redundant(the_repository, array, num_head);
+ if (num_head < 0) {
+ free(array);
+ return NULL;
+ }
for (i = 0; i < num_head; i++)
tail = &commit_list_insert(array[i], tail)->next;
free(array);
@@ -593,6 +650,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
commit_list_insert(old_commit, &old_commit_list);
ret = repo_is_descendant_of(the_repository,
new_commit, old_commit_list);
+ if (ret < 0)
+ exit(128);
free_commit_list(old_commit_list);
return ret;
}
@@ -1049,6 +1108,10 @@ void ahead_behind(struct repository *r,
/* STALE is used here, PARENT2 is used by insert_no_dup(). */
repo_clear_commit_marks(r, PARENT2 | STALE);
+ while (prio_queue_peek(&queue)) {
+ struct commit *c = prio_queue_get(&queue);
+ free_bit_array(c);
+ }
clear_bit_arrays(&bit_arrays);
clear_prio_queue(&queue);
}
@@ -1164,4 +1227,131 @@ void tips_reachable_from_bases(struct repository *r,
done:
free(commits);
repo_clear_commit_marks(r, SEEN);
+ free_commit_list(stack);
+}
+
+/*
+ * This slab initializes integers to zero, so use "-1" for "tip is best" and
+ * "i + 1" for "bases[i] is best".
+ */
+define_commit_slab(best_branch_base, int);
+static struct best_branch_base best_branch_base;
+#define get_best(c) (*best_branch_base_at(&best_branch_base, (c)))
+#define set_best(c,v) (*best_branch_base_at(&best_branch_base, (c)) = (v))
+
+int get_branch_base_for_tip(struct repository *r,
+ struct commit *tip,
+ struct commit **bases,
+ size_t bases_nr)
+{
+ int best_index = -1;
+ struct commit *branch_point = NULL;
+ struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+ int found_missing_gen = 0;
+
+ if (!bases_nr)
+ return -1;
+
+ repo_parse_commit(r, tip);
+ if (commit_graph_generation(tip) == GENERATION_NUMBER_INFINITY)
+ found_missing_gen = 1;
+
+ /* Check for missing generation numbers. */
+ for (size_t i = 0; i < bases_nr; i++) {
+ struct commit *c = bases[i];
+ repo_parse_commit(r, c);
+ if (commit_graph_generation(c) == GENERATION_NUMBER_INFINITY)
+ found_missing_gen = 1;
+ }
+
+ if (found_missing_gen) {
+ struct commit **commits;
+ size_t commits_nr = bases_nr + 1;
+
+ CALLOC_ARRAY(commits, commits_nr);
+ COPY_ARRAY(commits, bases, bases_nr);
+ commits[bases_nr] = tip;
+ ensure_generations_valid(r, commits, commits_nr);
+ free(commits);
+ }
+
+ /* Initialize queue and slab now that generations are guaranteed. */
+ init_best_branch_base(&best_branch_base);
+ set_best(tip, -1);
+ prio_queue_put(&queue, tip);
+
+ for (size_t i = 0; i < bases_nr; i++) {
+ struct commit *c = bases[i];
+ int best = get_best(c);
+
+ /* Has this already been marked as best by another commit? */
+ if (best) {
+ if (best == -1) {
+ /* We agree at this position. Stop now. */
+ best_index = i + 1;
+ goto cleanup;
+ }
+ continue;
+ }
+
+ set_best(c, i + 1);
+ prio_queue_put(&queue, c);
+ }
+
+ while (queue.nr) {
+ struct commit *c = prio_queue_get(&queue);
+ int best_for_c = get_best(c);
+ int best_for_p, positive;
+ struct commit *parent;
+
+ /* Have we reached a known branch point? It's optimal. */
+ if (c == branch_point)
+ break;
+
+ repo_parse_commit(r, c);
+ if (!c->parents)
+ continue;
+
+ parent = c->parents->item;
+ repo_parse_commit(r, parent);
+ best_for_p = get_best(parent);
+
+ if (!best_for_p) {
+ /* 'parent' is new, so pass along best_for_c. */
+ set_best(parent, best_for_c);
+ prio_queue_put(&queue, parent);
+ continue;
+ }
+
+ if (best_for_p > 0 && best_for_c > 0) {
+ /* Collision among bases. Minimize. */
+ if (best_for_c < best_for_p)
+ set_best(parent, best_for_c);
+ continue;
+ }
+
+ /*
+ * At this point, we have reached a commit that is reachable
+ * from the tip, either from 'c' or from an earlier commit to
+ * have 'parent' as its first parent.
+ *
+ * Update 'best_index' to match the minimum of all base indices
+ * to reach 'parent'.
+ */
+
+ /* Exactly one is positive due to initial conditions. */
+ positive = (best_for_c < 0) ? best_for_p : best_for_c;
+
+ if (best_index < 0 || positive < best_index)
+ best_index = positive;
+
+ /* No matter what, track that the parent is reachable from tip. */
+ set_best(parent, -1);
+ branch_point = parent;
+ }
+
+cleanup:
+ clear_best_branch_base(&best_branch_base);
+ clear_prio_queue(&queue);
+ return best_index > 0 ? best_index - 1 : -1;
}
diff --git a/commit-reach.h b/commit-reach.h
index 35c4da4948..9a745b7e17 100644
--- a/commit-reach.h
+++ b/commit-reach.h
@@ -9,18 +9,21 @@ struct ref_filter;
struct object_id;
struct object_array;
-struct commit_list *repo_get_merge_bases(struct repository *r,
- struct commit *rev1,
- struct commit *rev2);
-struct commit_list *repo_get_merge_bases_many(struct repository *r,
- struct commit *one, int n,
- struct commit **twos);
+int repo_get_merge_bases(struct repository *r,
+ struct commit *rev1,
+ struct commit *rev2,
+ struct commit_list **result);
+int repo_get_merge_bases_many(struct repository *r,
+ struct commit *one, int n,
+ struct commit **twos,
+ struct commit_list **result);
/* To be used only when object flags after this call no longer matter */
-struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
- struct commit *one, int n,
- struct commit **twos);
+int repo_get_merge_bases_many_dirty(struct repository *r,
+ struct commit *one, int n,
+ struct commit **twos,
+ struct commit_list **result);
-struct commit_list *get_octopus_merge_bases(struct commit_list *in);
+int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result);
int repo_is_descendant_of(struct repository *r,
struct commit *commit,
@@ -30,7 +33,8 @@ int repo_in_merge_bases(struct repository *r,
struct commit *reference);
int repo_in_merge_bases_many(struct repository *r,
struct commit *commit,
- int nr_reference, struct commit **reference);
+ int nr_reference, struct commit **reference,
+ int ignore_missing_commits);
/*
* Takes a list of commits and returns a new list where those
@@ -135,4 +139,21 @@ void tips_reachable_from_bases(struct repository *r,
struct commit **tips, size_t tips_nr,
int mark);
+/*
+ * Given a 'tip' commit and a list potential 'bases', return the index 'i' that
+ * minimizes the number of commits in the first-parent history of 'tip' and not
+ * in the first-parent history of 'bases[i]'.
+ *
+ * Among a list of long-lived branches that are updated only by merges (with the
+ * first parent being the previous position of the branch), this would inform
+ * which branch was used to create the tip reference.
+ *
+ * Returns -1 if no common point is found in first-parent histories, which is
+ * rare, but possible with multiple root commits.
+ */
+int get_branch_base_for_tip(struct repository *r,
+ struct commit *tip,
+ struct commit **bases,
+ size_t bases_nr);
+
#endif
diff --git a/commit.c b/commit.c
index b3223478bc..cc03a93036 100644
--- a/commit.c
+++ b/commit.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "tag.h"
#include "commit.h"
@@ -8,7 +10,6 @@
#include "repository.h"
#include "object-name.h"
#include "object-store-ll.h"
-#include "pkt-line.h"
#include "utf8.h"
#include "diff.h"
#include "revision.h"
@@ -23,11 +24,12 @@
#include "advice.h"
#include "refs.h"
#include "commit-reach.h"
-#include "run-command.h"
#include "setup.h"
#include "shallow.h"
#include "tree.h"
#include "hook.h"
+#include "parse.h"
+#include "object-file-convert.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -83,12 +85,18 @@ struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
struct commit *lookup_commit_reference_by_name(const char *name)
{
+ return lookup_commit_reference_by_name_gently(name, 0);
+}
+
+struct commit *lookup_commit_reference_by_name_gently(const char *name,
+ int quiet)
+{
struct object_id oid;
struct commit *commit;
if (repo_get_oid_committish(the_repository, name, &oid))
return NULL;
- commit = lookup_commit_reference(the_repository, &oid);
+ commit = lookup_commit_reference_gently(the_repository, &oid, quiet);
if (repo_parse_commit(the_repository, commit))
return NULL;
return commit;
@@ -175,7 +183,7 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid)
commit_graft_oid_access);
}
-static void unparse_commit(struct repository *r, const struct object_id *oid)
+void unparse_commit(struct repository *r, const struct object_id *oid)
{
struct commit *c = lookup_commit(r, oid);
@@ -284,14 +292,14 @@ static int read_graft_file(struct repository *r, const char *graft_file)
void prepare_commit_graft(struct repository *r)
{
- char *graft_file;
+ const char *graft_file;
if (r->parsed_objects->commit_graft_prepared)
return;
if (!startup_info->have_repository)
return;
- graft_file = get_graft_file(r);
+ graft_file = repo_get_graft_file(r);
read_graft_file(r, graft_file);
/* make sure shallows are read */
is_repository_shallow(r);
@@ -316,18 +324,6 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
return ret;
}
-void reset_commit_grafts(struct repository *r)
-{
- int i;
-
- for (i = 0; i < r->parsed_objects->grafts_nr; i++) {
- unparse_commit(r, &r->parsed_objects->grafts[i]->oid);
- free(r->parsed_objects->grafts[i]);
- }
- r->parsed_objects->grafts_nr = 0;
- r->parsed_objects->commit_graft_prepared = 0;
-}
-
struct commit_buffer {
void *buffer;
unsigned long size;
@@ -572,8 +568,21 @@ int repo_parse_commit_internal(struct repository *r,
return -1;
if (item->object.parsed)
return 0;
- if (use_commit_graph && parse_commit_in_graph(r, item))
+ if (use_commit_graph && parse_commit_in_graph(r, item)) {
+ static int commit_graph_paranoia = -1;
+
+ if (commit_graph_paranoia == -1)
+ commit_graph_paranoia = git_env_bool(GIT_COMMIT_GRAPH_PARANOIA, 0);
+
+ if (commit_graph_paranoia && !has_object(r, &item->object.oid, 0)) {
+ unparse_commit(r, &item->object.oid);
+ return quiet_on_missing ? -1 :
+ error(_("commit %s exists in commit-graph but not in the object database"),
+ oid_to_hex(&item->object.oid));
+ }
+
return 0;
+ }
if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0)
return quiet_on_missing ? -1 :
@@ -586,7 +595,8 @@ int repo_parse_commit_internal(struct repository *r,
}
ret = parse_commit_buffer(r, item, buffer, size, 0);
- if (save_commit_buffer && !ret) {
+ if (save_commit_buffer && !ret &&
+ !get_cached_commit_buffer(r, item, NULL)) {
set_commit_buffer(r, item, buffer, size);
return 0;
}
@@ -667,7 +677,7 @@ unsigned commit_list_count(const struct commit_list *l)
return c;
}
-struct commit_list *copy_commit_list(struct commit_list *list)
+struct commit_list *copy_commit_list(const struct commit_list *list)
{
struct commit_list *head = NULL;
struct commit_list **pp = &head;
@@ -1040,7 +1050,7 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
{
struct object_id oid;
struct rev_collect revs;
- struct commit_list *bases;
+ struct commit_list *bases = NULL;
int i;
struct commit *ret = NULL;
char *full_refname;
@@ -1057,7 +1067,8 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
memset(&revs, 0, sizeof(revs));
revs.initial = 1;
- for_each_reflog_ent(full_refname, collect_one_reflog_ent, &revs);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ full_refname, collect_one_reflog_ent, &revs);
if (!revs.nr)
add_one_commit(&oid, &revs);
@@ -1065,8 +1076,9 @@ 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 = repo_get_merge_bases_many(the_repository, commit, revs.nr,
- revs.commit);
+ if (repo_get_merge_bases_many(the_repository, commit, revs.nr,
+ revs.commit, &bases) < 0)
+ exit(128);
/*
* There should be one and only one merge base, when we found
@@ -1100,12 +1112,11 @@ static const char *gpg_sig_headers[] = {
"gpgsig-sha256",
};
-int sign_with_header(struct strbuf *buf, const char *keyid)
+int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo)
{
- struct strbuf sig = STRBUF_INIT;
int inspos, copypos;
const char *eoh;
- const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
+ const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algo)];
int gpg_sig_header_len = strlen(gpg_sig_header);
/* find the end of the header */
@@ -1115,15 +1126,8 @@ int sign_with_header(struct strbuf *buf, const char *keyid)
else
inspos = eoh - buf->buf + 1;
- if (!keyid || !*keyid)
- keyid = get_signing_key();
- if (sign_buffer(buf, &sig, keyid)) {
- strbuf_release(&sig);
- return -1;
- }
-
- for (copypos = 0; sig.buf[copypos]; ) {
- const char *bol = sig.buf + copypos;
+ for (copypos = 0; sig->buf[copypos]; ) {
+ const char *bol = sig->buf + copypos;
const char *eol = strchrnul(bol, '\n');
int len = (eol - bol) + !!*eol;
@@ -1136,11 +1140,20 @@ int sign_with_header(struct strbuf *buf, const char *keyid)
inspos += len;
copypos += len;
}
- strbuf_release(&sig);
return 0;
}
-
+static int sign_commit_to_strbuf(struct strbuf *sig, struct strbuf *buf, const char *keyid)
+{
+ char *keyid_to_free = NULL;
+ int ret = 0;
+ if (!keyid || !*keyid)
+ keyid = keyid_to_free = get_signing_key();
+ if (sign_buffer(buf, sig, keyid))
+ ret = -1;
+ free(keyid_to_free);
+ return ret;
+}
int parse_signed_commit(const struct commit *commit,
struct strbuf *payload, struct strbuf *signature,
@@ -1249,7 +1262,7 @@ int remove_signature(struct strbuf *buf)
return sigs[0].start != NULL;
}
-static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
+static void handle_signed_tag(const struct commit *parent, struct commit_extra_header ***tail)
{
struct merge_remote_desc *desc;
struct commit_extra_header *mergetag;
@@ -1346,18 +1359,51 @@ void verify_merge_signature(struct commit *commit, int verbosity,
signature_check_clear(&signature_check);
}
-void append_merge_tag_headers(struct commit_list *parents,
+void append_merge_tag_headers(const struct commit_list *parents,
struct commit_extra_header ***tail)
{
while (parents) {
- struct commit *parent = parents->item;
+ const struct commit *parent = parents->item;
handle_signed_tag(parent, tail);
parents = parents->next;
}
}
+static int convert_commit_extra_headers(const struct commit_extra_header *orig,
+ struct commit_extra_header **result)
+{
+ const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+ const struct git_hash_algo *algo = the_repository->hash_algo;
+ struct commit_extra_header *extra = NULL, **tail = &extra;
+ struct strbuf out = STRBUF_INIT;
+ while (orig) {
+ struct commit_extra_header *new;
+ CALLOC_ARRAY(new, 1);
+ if (!strcmp(orig->key, "mergetag")) {
+ if (convert_object_file(&out, algo, compat,
+ orig->value, orig->len,
+ OBJ_TAG, 1)) {
+ free(new);
+ free_commit_extra_headers(extra);
+ return -1;
+ }
+ new->key = xstrdup("mergetag");
+ new->value = strbuf_detach(&out, &new->len);
+ } else {
+ new->key = xstrdup(orig->key);
+ new->len = orig->len;
+ new->value = xmemdupz(orig->value, orig->len);
+ }
+ *tail = new;
+ tail = &new->next;
+ orig = orig->next;
+ }
+ *result = extra;
+ return 0;
+}
+
static void add_extra_header(struct strbuf *buffer,
- struct commit_extra_header *extra)
+ const struct commit_extra_header *extra)
{
strbuf_addstr(buffer, extra->key);
if (extra->len)
@@ -1471,7 +1517,7 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
}
int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
- struct commit_list *parents, struct object_id *ret,
+ const struct commit_list *parents, struct object_id *ret,
const char *author, const char *sign_commit)
{
struct commit_extra_header *extra = NULL, **tail = &extra;
@@ -1599,77 +1645,174 @@ N_("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");
-int commit_tree_extended(const char *msg, size_t msg_len,
- const struct object_id *tree,
- struct commit_list *parents, struct object_id *ret,
- const char *author, const char *committer,
- const char *sign_commit,
- struct commit_extra_header *extra)
+static void write_commit_tree(struct strbuf *buffer, const char *msg, size_t msg_len,
+ const struct object_id *tree,
+ const struct object_id *parents, size_t parents_len,
+ const char *author, const char *committer,
+ const struct commit_extra_header *extra)
{
- int result;
int encoding_is_utf8;
- struct strbuf buffer;
-
- assert_oid_type(tree, OBJ_TREE);
-
- if (memchr(msg, '\0', msg_len))
- return error("a NUL byte in commit log message not allowed.");
+ size_t i;
/* Not having i18n.commitencoding is the same as having utf-8 */
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
- strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
- strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
+ strbuf_grow(buffer, 8192); /* should avoid reallocs for the headers */
+ strbuf_addf(buffer, "tree %s\n", oid_to_hex(tree));
/*
* NOTE! This ordering means that the same exact tree merged with a
* different order of parents will be a _different_ changeset even
* if everything else stays the same.
*/
- while (parents) {
- struct commit *parent = pop_commit(&parents);
- strbuf_addf(&buffer, "parent %s\n",
- oid_to_hex(&parent->object.oid));
- }
+ for (i = 0; i < parents_len; i++)
+ strbuf_addf(buffer, "parent %s\n", oid_to_hex(&parents[i]));
/* Person/date information */
if (!author)
author = git_author_info(IDENT_STRICT);
- strbuf_addf(&buffer, "author %s\n", author);
+ strbuf_addf(buffer, "author %s\n", author);
if (!committer)
committer = git_committer_info(IDENT_STRICT);
- strbuf_addf(&buffer, "committer %s\n", committer);
+ strbuf_addf(buffer, "committer %s\n", committer);
if (!encoding_is_utf8)
- strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
+ strbuf_addf(buffer, "encoding %s\n", git_commit_encoding);
while (extra) {
- add_extra_header(&buffer, extra);
+ add_extra_header(buffer, extra);
extra = extra->next;
}
- strbuf_addch(&buffer, '\n');
+ strbuf_addch(buffer, '\n');
/* And add the comment */
- strbuf_add(&buffer, msg, msg_len);
+ strbuf_add(buffer, msg, msg_len);
+}
- /* And check the encoding */
- if (encoding_is_utf8 && !verify_utf8(&buffer))
- fprintf(stderr, _(commit_utf8_warn));
+int commit_tree_extended(const char *msg, size_t msg_len,
+ const struct object_id *tree,
+ const struct commit_list *parents, struct object_id *ret,
+ const char *author, const char *committer,
+ const char *sign_commit,
+ const struct commit_extra_header *extra)
+{
+ struct repository *r = the_repository;
+ int result = 0;
+ int encoding_is_utf8;
+ struct strbuf buffer = STRBUF_INIT, compat_buffer = STRBUF_INIT;
+ struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
+ struct object_id *parent_buf = NULL, *compat_oid = NULL;
+ struct object_id compat_oid_buf;
+ size_t i, nparents;
+
+ /* Not having i18n.commitencoding is the same as having utf-8 */
+ encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
- if (sign_commit && sign_with_header(&buffer, sign_commit)) {
+ assert_oid_type(tree, OBJ_TREE);
+
+ if (memchr(msg, '\0', msg_len))
+ return error("a NUL byte in commit log message not allowed.");
+
+ nparents = commit_list_count(parents);
+ CALLOC_ARRAY(parent_buf, nparents);
+ i = 0;
+ for (const struct commit_list *p = parents; p; p = p->next)
+ oidcpy(&parent_buf[i++], &p->item->object.oid);
+
+ write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra);
+ if (sign_commit && sign_commit_to_strbuf(&sig, &buffer, sign_commit)) {
result = -1;
goto out;
}
+ if (r->compat_hash_algo) {
+ struct commit_extra_header *compat_extra = NULL;
+ struct object_id mapped_tree;
+ struct object_id *mapped_parents;
+
+ CALLOC_ARRAY(mapped_parents, nparents);
+
+ if (repo_oid_to_algop(r, tree, r->compat_hash_algo, &mapped_tree)) {
+ result = -1;
+ free(mapped_parents);
+ goto out;
+ }
+ for (i = 0; i < nparents; i++)
+ if (repo_oid_to_algop(r, &parent_buf[i], r->compat_hash_algo, &mapped_parents[i])) {
+ result = -1;
+ free(mapped_parents);
+ goto out;
+ }
+ if (convert_commit_extra_headers(extra, &compat_extra)) {
+ result = -1;
+ free(mapped_parents);
+ goto out;
+ }
+ write_commit_tree(&compat_buffer, msg, msg_len, &mapped_tree,
+ mapped_parents, nparents, author, committer, compat_extra);
+ free_commit_extra_headers(compat_extra);
+ free(mapped_parents);
+
+ if (sign_commit && sign_commit_to_strbuf(&compat_sig, &compat_buffer, sign_commit)) {
+ result = -1;
+ goto out;
+ }
+ }
+
+ if (sign_commit) {
+ struct sig_pairs {
+ struct strbuf *sig;
+ const struct git_hash_algo *algo;
+ } bufs [2] = {
+ { &compat_sig, r->compat_hash_algo },
+ { &sig, r->hash_algo },
+ };
+ int i;
+
+ /*
+ * We write algorithms in the order they were implemented in
+ * Git to produce a stable hash when multiple algorithms are
+ * used.
+ */
+ if (r->compat_hash_algo && hash_algo_by_ptr(bufs[0].algo) > hash_algo_by_ptr(bufs[1].algo))
+ SWAP(bufs[0], bufs[1]);
+
+ /*
+ * We traverse each algorithm in order, and apply the signature
+ * to each buffer.
+ */
+ for (i = 0; i < ARRAY_SIZE(bufs); i++) {
+ if (!bufs[i].algo)
+ continue;
+ add_header_signature(&buffer, bufs[i].sig, bufs[i].algo);
+ if (r->compat_hash_algo)
+ add_header_signature(&compat_buffer, bufs[i].sig, bufs[i].algo);
+ }
+ }
- result = write_object_file(buffer.buf, buffer.len, OBJ_COMMIT, ret);
+ /* And check the encoding. */
+ if (encoding_is_utf8 && (!verify_utf8(&buffer) || !verify_utf8(&compat_buffer)))
+ fprintf(stderr, _(commit_utf8_warn));
+
+ if (r->compat_hash_algo) {
+ hash_object_file(r->compat_hash_algo, compat_buffer.buf, compat_buffer.len,
+ OBJ_COMMIT, &compat_oid_buf);
+ compat_oid = &compat_oid_buf;
+ }
+
+ result = write_object_file_flags(buffer.buf, buffer.len, OBJ_COMMIT,
+ ret, compat_oid, 0);
out:
+ free(parent_buf);
strbuf_release(&buffer);
+ strbuf_release(&compat_buffer);
+ strbuf_release(&sig);
+ strbuf_release(&compat_sig);
return result;
}
define_commit_slab(merge_desc_slab, struct merge_remote_desc *);
static struct merge_desc_slab merge_desc_slab = COMMIT_SLAB_INIT(1, merge_desc_slab);
-struct merge_remote_desc *merge_remote_util(struct commit *commit)
+struct merge_remote_desc *merge_remote_util(const struct commit *commit)
{
return *merge_desc_slab_at(&merge_desc_slab, commit);
}
@@ -1725,20 +1868,12 @@ struct commit_list **commit_list_append(struct commit *commit,
return &new_commit->next;
}
-const char *find_header_mem(const char *msg, size_t len,
- const char *key, size_t *out_len)
+const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
{
int key_len = strlen(key);
const char *line = msg;
- /*
- * NEEDSWORK: It's possible for strchrnul() to scan beyond the range
- * given by len. However, current callers are safe because they compute
- * len by scanning a NUL-terminated block of memory starting at msg.
- * Nonetheless, it would be better to ensure the function does not look
- * at msg beyond the len provided by the caller.
- */
- while (line && line < msg + len) {
+ while (line) {
const char *eol = strchrnul(line, '\n');
if (line == eol)
@@ -1755,10 +1890,6 @@ const char *find_header_mem(const char *msg, size_t len,
return NULL;
}
-const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
-{
- return find_header_mem(msg, strlen(msg), key, out_len);
-}
/*
* Inspect the given string and determine the true "end" of the log message, in
* order to find where to put a new Signed-off-by trailer. Ignored are
@@ -1769,7 +1900,7 @@ const char *find_commit_header(const char *msg, const char *key, size_t *out_len
* Returns the number of bytes from the tail to ignore, to be fed as
* the second parameter to append_signoff().
*/
-size_t ignore_non_trailer(const char *buf, size_t len)
+size_t ignored_log_message_bytes(const char *buf, size_t len)
{
size_t boc = 0;
size_t bol = 0;
@@ -1784,7 +1915,8 @@ size_t ignore_non_trailer(const char *buf, size_t len)
else
next_line++;
- if (buf[bol] == comment_line_char || buf[bol] == '\n') {
+ if (starts_with_mem(buf + bol, cutoff - bol, comment_line_str) ||
+ buf[bol] == '\n') {
/* is this the first of the run of comments? */
if (!boc)
boc = bol;
@@ -1826,5 +1958,5 @@ int run_commit_hook(int editor_is_used, const char *index_file,
va_end(args);
opt.invoked_hook = invoked_hook;
- return run_hooks_opt(name, &opt);
+ return run_hooks_opt(the_repository, name, &opt);
}
diff --git a/commit.h b/commit.h
index 28928833c5..943e3d74b2 100644
--- a/commit.h
+++ b/commit.h
@@ -81,6 +81,8 @@ struct commit *lookup_commit_reference_gently(struct repository *r,
const struct object_id *oid,
int quiet);
struct commit *lookup_commit_reference_by_name(const char *name);
+struct commit *lookup_commit_reference_by_name_gently(const char *name,
+ int quiet);
/*
* Look up object named by "oid", dereference tag as necessary,
@@ -108,6 +110,8 @@ static inline int repo_parse_commit_no_graph(struct repository *r,
void parse_commit_or_die(struct commit *item);
+void unparse_commit(struct repository *r, const struct object_id *oid);
+
struct buffer_slab;
struct buffer_slab *allocate_commit_buffer_slab(void);
void free_commit_buffer_slab(struct buffer_slab *bs);
@@ -181,7 +185,7 @@ struct commit_list *commit_list_insert_by_date(struct commit *item,
void commit_list_sort_by_date(struct commit_list **list);
/* Shallow copy of the input list */
-struct commit_list *copy_commit_list(struct commit_list *list);
+struct commit_list *copy_commit_list(const struct commit_list *list);
/* Modify list in-place to reverse it, returning new head; list will be tail */
struct commit_list *reverse_commit_list(struct commit_list *list);
@@ -240,7 +244,6 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid);
int register_commit_graft(struct repository *r, struct commit_graft *, int);
void prepare_commit_graft(struct repository *r);
struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
-void reset_commit_grafts(struct repository *r);
struct commit *get_fork_point(const char *refname, struct commit *commit);
@@ -251,7 +254,10 @@ struct oid_array;
struct ref;
int for_each_commit_graft(each_commit_graft_fn, void *);
-int interactive_add(const char **argv, const char *prefix, int patch);
+int interactive_add(struct repository *repo,
+ const char **argv,
+ const char *prefix,
+ int patch);
struct commit_extra_header {
struct commit_extra_header *next;
@@ -260,19 +266,19 @@ struct commit_extra_header {
size_t len;
};
-void append_merge_tag_headers(struct commit_list *parents,
+void append_merge_tag_headers(const struct commit_list *parents,
struct commit_extra_header ***tail);
int commit_tree(const char *msg, size_t msg_len,
const struct object_id *tree,
- struct commit_list *parents, struct object_id *ret,
+ const struct commit_list *parents, struct object_id *ret,
const char *author, const char *sign_commit);
int commit_tree_extended(const char *msg, size_t msg_len,
const struct object_id *tree,
- struct commit_list *parents, struct object_id *ret,
+ const struct commit_list *parents, struct object_id *ret,
const char *author, const char *committer,
- const char *sign_commit, struct commit_extra_header *);
+ const char *sign_commit, const struct commit_extra_header *);
struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
@@ -280,22 +286,17 @@ void free_commit_extra_headers(struct commit_extra_header *extra);
/*
* Search the commit object contents given by "msg" for the header "key".
- * Reads up to "len" bytes of "msg".
* Returns a pointer to the start of the header contents, or NULL. The length
* of the header, up to the first newline, is returned via out_len.
*
* Note that some headers (like mergetag) may be multi-line. It is the caller's
* responsibility to parse further in this case!
*/
-const char *find_header_mem(const char *msg, size_t len,
- const char *key,
- size_t *out_len);
-
const char *find_commit_header(const char *msg, const char *key,
size_t *out_len);
-/* Find the end of the log message, the right place for a new trailer. */
-size_t ignore_non_trailer(const char *buf, size_t len);
+/* Find the number of bytes to ignore from the end of a log message. */
+size_t ignored_log_message_bytes(const char *buf, size_t len);
typedef int (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
void *cb_data);
@@ -306,7 +307,7 @@ struct merge_remote_desc {
struct object *obj; /* the named object, could be a tag */
char name[FLEX_ARRAY];
};
-struct merge_remote_desc *merge_remote_util(struct commit *);
+struct merge_remote_desc *merge_remote_util(const struct commit *);
void set_merge_remote_desc(struct commit *commit,
const char *name, struct object *obj);
@@ -370,5 +371,6 @@ int parse_buffer_signed_by_header(const char *buffer,
struct strbuf *payload,
struct strbuf *signature,
const struct git_hash_algo *algop);
+int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo);
#endif /* COMMIT_H */
diff --git a/common-main.c b/common-main.c
index 033778b3c5..8e68ac9e42 100644
--- a/common-main.c
+++ b/common-main.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "exec-cmd.h"
#include "gettext.h"
@@ -48,7 +50,7 @@ int main(int argc, const char **argv)
setlocale(LC_CTYPE, "");
git_setup_gettext();
- initialize_the_repository();
+ initialize_repository(the_repository);
attr_start();
diff --git a/compat/basename.c b/compat/basename.c
index 96bd9533b4..c33579ef61 100644
--- a/compat/basename.c
+++ b/compat/basename.c
@@ -10,7 +10,13 @@ char *gitbasename (char *path)
skip_dos_drive_prefix(&path);
if (!path || !*path)
- return ".";
+ /*
+ * basename(3P) is mis-specified because it returns a
+ * non-constant pointer even though it is specified to return a
+ * pointer to internal memory at times. The cast is a result of
+ * that.
+ */
+ return (char *) ".";
for (base = path; *path; path++) {
if (!is_dir_sep(*path))
@@ -34,7 +40,13 @@ char *gitdirname(char *path)
int dos_drive_prefix;
if (!p)
- return ".";
+ /*
+ * dirname(3P) is mis-specified because it returns a
+ * non-constant pointer even though it is specified to return a
+ * pointer to internal memory at times. The cast is a result of
+ * that.
+ */
+ return (char *) ".";
if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
goto dot;
diff --git a/compat/compiler.h b/compat/compiler.h
index 10dbb65937..e12e426404 100644
--- a/compat/compiler.h
+++ b/compat/compiler.h
@@ -1,7 +1,6 @@
#ifndef COMPILER_H
#define COMPILER_H
-#include "git-compat-util.h"
#include "strbuf.h"
#ifdef __GLIBC__
@@ -10,7 +9,7 @@
static inline void get_compiler_info(struct strbuf *info)
{
- int len = info->len;
+ size_t len = info->len;
#ifdef __clang__
strbuf_addf(info, "clang: %s\n", __clang_version__);
#elif defined(__GNUC__)
@@ -28,7 +27,7 @@ static inline void get_compiler_info(struct strbuf *info)
static inline void get_libc_info(struct strbuf *info)
{
- int len = info->len;
+ size_t len = info->len;
#ifdef __GLIBC__
strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
diff --git a/compat/disk.h b/compat/disk.h
index 6c979c27d8..23bc1bef86 100644
--- a/compat/disk.h
+++ b/compat/disk.h
@@ -1,7 +1,6 @@
#ifndef COMPAT_DISK_H
#define COMPAT_DISK_H
-#include "git-compat-util.h"
#include "abspath.h"
#include "gettext.h"
diff --git a/compat/fsmonitor/fsm-health-darwin.c b/compat/fsmonitor/fsm-health-darwin.c
index 5b1709d63f..c2afcbe6c8 100644
--- a/compat/fsmonitor/fsm-health-darwin.c
+++ b/compat/fsmonitor/fsm-health-darwin.c
@@ -4,21 +4,21 @@
#include "fsm-health.h"
#include "fsmonitor--daemon.h"
-int fsm_health__ctor(struct fsmonitor_daemon_state *state)
+int fsm_health__ctor(struct fsmonitor_daemon_state *state UNUSED)
{
return 0;
}
-void fsm_health__dtor(struct fsmonitor_daemon_state *state)
+void fsm_health__dtor(struct fsmonitor_daemon_state *state UNUSED)
{
return;
}
-void fsm_health__loop(struct fsmonitor_daemon_state *state)
+void fsm_health__loop(struct fsmonitor_daemon_state *state UNUSED)
{
return;
}
-void fsm_health__stop_async(struct fsmonitor_daemon_state *state)
+void fsm_health__stop_async(struct fsmonitor_daemon_state *state UNUSED)
{
}
diff --git a/compat/fsmonitor/fsm-health-win32.c b/compat/fsmonitor/fsm-health-win32.c
index 2d4e245beb..2aa8c219ac 100644
--- a/compat/fsmonitor/fsm-health-win32.c
+++ b/compat/fsmonitor/fsm-health-win32.c
@@ -4,6 +4,7 @@
#include "fsm-health.h"
#include "fsmonitor--daemon.h"
#include "gettext.h"
+#include "simple-ipc.h"
/*
* Every minute wake up and test our health.
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
index 6f3a95410c..fe149a1b37 100644
--- a/compat/fsmonitor/fsm-ipc-darwin.c
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "gettext.h"
@@ -17,7 +19,7 @@ const char *fsmonitor_ipc__get_path(struct repository *r)
git_SHA_CTX sha1ctx;
char *sock_dir = NULL;
struct strbuf ipc_file = STRBUF_INIT;
- unsigned char hash[GIT_MAX_RAWSZ];
+ unsigned char hash[GIT_SHA1_RAWSZ];
if (!r)
BUG("No repository passed into fsmonitor_ipc__get_path");
@@ -41,9 +43,10 @@ const char *fsmonitor_ipc__get_path(struct repository *r)
/* Create the socket file in either socketDir or $HOME */
if (sock_dir && *sock_dir) {
strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
- sock_dir, hash_to_hex(hash));
+ sock_dir, hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1]));
} else {
- strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s",
+ hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1]));
}
free(sock_dir);
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
index 8928fa93ce..41984ea48e 100644
--- a/compat/fsmonitor/fsm-ipc-win32.c
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -6,6 +6,6 @@
const char *fsmonitor_ipc__get_path(struct repository *r) {
static char *ret;
if (!ret)
- ret = git_pathdup("fsmonitor--daemon.ipc");
+ ret = repo_git_path(r, "fsmonitor--daemon.ipc");
return ret;
}
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 36c7e13281..dfa551459d 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -29,6 +29,7 @@
#include "fsmonitor--daemon.h"
#include "fsmonitor-path-utils.h"
#include "gettext.h"
+#include "simple-ipc.h"
#include "string-list.h"
#include "trace.h"
@@ -191,12 +192,12 @@ static void my_add_path(struct fsmonitor_batch *batch, const char *path)
}
-static void fsevent_callback(ConstFSEventStreamRef streamRef,
+static void fsevent_callback(ConstFSEventStreamRef streamRef UNUSED,
void *ctx,
size_t num_of_events,
void *event_paths,
const FSEventStreamEventFlags event_flags[],
- const FSEventStreamEventId event_ids[])
+ const FSEventStreamEventId event_ids[] UNUSED)
{
struct fsmonitor_daemon_state *state = ctx;
struct fsm_listen_data *data = state->listen_data;
@@ -515,6 +516,12 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
}
data->stream_started = 1;
+ /*
+ * Our fs event listener is now running, so it's safe to start
+ * serving client requests.
+ */
+ ipc_server_start_async(state->ipc_server_data);
+
pthread_mutex_lock(&data->dq_lock);
pthread_cond_wait(&data->dq_finished, &data->dq_lock);
pthread_mutex_unlock(&data->dq_lock);
diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c
index a361a7db20..9a6efc9bea 100644
--- a/compat/fsmonitor/fsm-listen-win32.c
+++ b/compat/fsmonitor/fsm-listen-win32.c
@@ -4,6 +4,7 @@
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
#include "gettext.h"
+#include "simple-ipc.h"
#include "trace2.h"
/*
@@ -289,8 +290,7 @@ void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
SetEvent(state->listen_data->hListener[LISTENER_SHUTDOWN]);
}
-static struct one_watch *create_watch(struct fsmonitor_daemon_state *state,
- const char *path)
+static struct one_watch *create_watch(const char *path)
{
struct one_watch *watch = NULL;
DWORD desired_access = FILE_LIST_DIRECTORY;
@@ -361,8 +361,7 @@ static void destroy_watch(struct one_watch *watch)
free(watch);
}
-static int start_rdcw_watch(struct fsm_listen_data *data,
- struct one_watch *watch)
+static int start_rdcw_watch(struct one_watch *watch)
{
DWORD dwNotifyFilter =
FILE_NOTIFY_CHANGE_FILE_NAME |
@@ -432,9 +431,9 @@ static int recv_rdcw_watch(struct one_watch *watch)
* but I observed ERROR_ACCESS_DENIED (0x05) errors during
* testing.
*
- * Note that we only get notificaiton events for events
+ * Note that we only get notification events for events
* *within* the directory, not *on* the directory itself.
- * (These might be properies of the parent directory, for
+ * (These might be properties of the parent directory, for
* example).
*
* NEEDSWORK: We might try to check for the deleted directory
@@ -735,13 +734,19 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
state->listen_error_code = 0;
- if (start_rdcw_watch(data, data->watch_worktree) == -1)
+ if (start_rdcw_watch(data->watch_worktree) == -1)
goto force_error_stop;
if (data->watch_gitdir &&
- start_rdcw_watch(data, data->watch_gitdir) == -1)
+ start_rdcw_watch(data->watch_gitdir) == -1)
goto force_error_stop;
+ /*
+ * Now that we've established the rdcw watches, we can start
+ * serving clients.
+ */
+ ipc_server_start_async(state->ipc_server_data);
+
for (;;) {
dwWait = WaitForMultipleObjects(data->nr_listener_handles,
data->hListener,
@@ -755,7 +760,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
}
if (result == -2) {
/* retryable error */
- if (start_rdcw_watch(data, data->watch_worktree) == -1)
+ if (start_rdcw_watch(data->watch_worktree) == -1)
goto force_error_stop;
continue;
}
@@ -763,7 +768,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
/* have data */
if (process_worktree_events(state) == LISTENER_SHUTDOWN)
goto force_shutdown;
- if (start_rdcw_watch(data, data->watch_worktree) == -1)
+ if (start_rdcw_watch(data->watch_worktree) == -1)
goto force_error_stop;
continue;
}
@@ -776,7 +781,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
}
if (result == -2) {
/* retryable error */
- if (start_rdcw_watch(data, data->watch_gitdir) == -1)
+ if (start_rdcw_watch(data->watch_gitdir) == -1)
goto force_error_stop;
continue;
}
@@ -784,7 +789,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
/* have data */
if (process_gitdir_events(state) == LISTENER_SHUTDOWN)
goto force_shutdown;
- if (start_rdcw_watch(data, data->watch_gitdir) == -1)
+ if (start_rdcw_watch(data->watch_gitdir) == -1)
goto force_error_stop;
continue;
}
@@ -821,16 +826,14 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
- data->watch_worktree = create_watch(state,
- state->path_worktree_watch.buf);
+ data->watch_worktree = create_watch(state->path_worktree_watch.buf);
if (!data->watch_worktree)
goto failed;
check_for_shortnames(data->watch_worktree);
if (state->nr_paths_watching > 1) {
- data->watch_gitdir = create_watch(state,
- state->path_gitdir_watch.buf);
+ data->watch_gitdir = create_watch(state->path_gitdir_watch.buf);
if (!data->watch_gitdir)
goto failed;
}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index c8a3e9dcdb..f4f9cc1f33 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -132,7 +132,8 @@ int fsmonitor__is_fs_remote(const char *path)
/*
* No-op for now.
*/
-int fsmonitor__get_alias(const char *path, struct alias_info *info)
+int fsmonitor__get_alias(const char *path UNUSED,
+ struct alias_info *info UNUSED)
{
return 0;
}
@@ -140,8 +141,8 @@ int fsmonitor__get_alias(const char *path, struct alias_info *info)
/*
* No-op for now.
*/
-char *fsmonitor__resolve_alias(const char *path,
- const struct alias_info *info)
+char *fsmonitor__resolve_alias(const char *path UNUSED,
+ const struct alias_info *info UNUSED)
{
return NULL;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index b6f6744494..0f2aa321f6 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc UNUSED)
{
enum fsmonitor_reason reason;
diff --git a/compat/mingw.c b/compat/mingw.c
index ec5280da16..63f36c893b 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../git-compat-util.h"
#include "win32.h"
#include <aclapi.h>
@@ -26,7 +28,6 @@ static const int delay[] = { 0, 1, 10, 20, 40 };
void open_in_gdb(void)
{
static struct child_process cp = CHILD_PROCESS_INIT;
- extern char *_pgmptr;
strvec_pushl(&cp.args, "mintty", "gdb", NULL);
strvec_pushf(&cp.args, "--pid=%d", getpid());
@@ -244,7 +245,8 @@ 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,
- const struct config_context *ctx, void *cb)
+ const struct config_context *ctx UNUSED,
+ void *cb UNUSED)
{
if (!strcmp(var, "core.hidedotfiles")) {
if (value && !strcasecmp(value, "dotgitonly"))
@@ -255,6 +257,8 @@ int mingw_core_config(const char *var, const char *value,
}
if (!strcmp(var, "core.unsetenvvars")) {
+ if (!value)
+ return config_error_nonbool(var);
free(unset_environment_variables);
unset_environment_variables = xstrdup(value);
return 0;
@@ -452,7 +456,7 @@ static int set_hidden_flag(const wchar_t *path, int set)
return -1;
}
-int mingw_mkdir(const char *path, int mode)
+int mingw_mkdir(const char *path, int mode UNUSED)
{
int ret;
wchar_t wpath[MAX_PATH];
@@ -498,7 +502,7 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
* to append to the file.
*/
handle = CreateFileW(wfilename, FILE_APPEND_DATA,
- FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
@@ -529,6 +533,70 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
}
/*
+ * Ideally, we'd use `_wopen()` to implement this functionality so that we
+ * don't have to reimplement it, but unfortunately we do not have tight control
+ * over the share mode there. And while `_wsopen()` and friends exist that give
+ * us _some_ control over the share mode, this family of functions doesn't give
+ * us the ability to enable FILE_SHARE_DELETE, either. But this is a strict
+ * requirement for us though so that we can unlink or rename over files that
+ * are held open by another process.
+ *
+ * We are thus forced to implement our own emulation of `open()`. To make our
+ * life simpler we only implement basic support for this, namely opening
+ * existing files for reading and/or writing. This means that newly created
+ * files won't have their sharing mode set up correctly, but for now I couldn't
+ * find any case where this matters. We may have to revisit that in the future
+ * though based on our needs.
+ */
+static int mingw_open_existing(const wchar_t *filename, int oflags, ...)
+{
+ SECURITY_ATTRIBUTES security_attributes = {
+ .nLength = sizeof(security_attributes),
+ .bInheritHandle = !(oflags & O_NOINHERIT),
+ };
+ HANDLE handle;
+ DWORD access;
+ int fd;
+
+ /* We only support basic flags. */
+ if (oflags & ~(O_ACCMODE | O_NOINHERIT)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ switch (oflags & O_ACCMODE) {
+ case O_RDWR:
+ access = GENERIC_READ | GENERIC_WRITE;
+ break;
+ case O_WRONLY:
+ access = GENERIC_WRITE;
+ break;
+ default:
+ access = GENERIC_READ;
+ break;
+ }
+
+ handle = CreateFileW(filename, access,
+ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+ &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ DWORD err = GetLastError();
+
+ /* See `mingw_open_append()` for why we have this conversion. */
+ if (err == ERROR_INVALID_PARAMETER)
+ err = ERROR_PATH_NOT_FOUND;
+
+ errno = err_win_to_posix(err);
+ return -1;
+ }
+
+ fd = _open_osfhandle((intptr_t)handle, oflags | O_BINARY);
+ if (fd < 0)
+ CloseHandle(handle);
+ return fd;
+}
+
+/*
* Does the pathname map to the local named pipe filesystem?
* That is, does it have a "//./pipe/" prefix?
*/
@@ -563,6 +631,8 @@ int mingw_open (const char *filename, int oflags, ...)
if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
open_fn = mingw_open_append;
+ else if (!(oflags & ~(O_ACCMODE | O_NOINHERIT)))
+ open_fn = mingw_open_existing;
else
open_fn = _wopen;
@@ -596,7 +666,7 @@ int mingw_open (const char *filename, int oflags, ...)
return fd;
}
-static BOOL WINAPI ctrl_ignore(DWORD type)
+static BOOL WINAPI ctrl_ignore(DWORD type UNUSED)
{
return TRUE;
}
@@ -705,13 +775,24 @@ ssize_t mingw_write(int fd, const void *buf, size_t len)
{
ssize_t result = write(fd, buf, len);
- if (result < 0 && errno == EINVAL && buf) {
+ if (result < 0 && (errno == EINVAL || errno == ENOSPC) && buf) {
+ int orig = errno;
+
/* check if fd is a pipe */
HANDLE h = (HANDLE) _get_osfhandle(fd);
- if (GetFileType(h) == FILE_TYPE_PIPE)
+ if (GetFileType(h) != FILE_TYPE_PIPE)
+ errno = orig;
+ else if (orig == EINVAL)
errno = EPIPE;
- else
- errno = EINVAL;
+ else {
+ DWORD buf_size;
+
+ if (!GetNamedPipeInfo(h, NULL, NULL, &buf_size, NULL))
+ buf_size = 4096;
+ if (len > buf_size)
+ return write(fd, buf, buf_size);
+ errno = orig;
+ }
}
return result;
@@ -767,7 +848,7 @@ static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
*/
static int has_valid_directory_prefix(wchar_t *wfilename)
{
- int n = wcslen(wfilename);
+ size_t n = wcslen(wfilename);
while (n > 0) {
wchar_t c = wfilename[--n];
@@ -876,7 +957,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
*/
static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
{
- int namelen;
+ size_t namelen;
char alt_name[PATH_MAX];
if (!do_lstat(follow, file_name, buf))
@@ -991,7 +1072,7 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
osfilehandle = CreateFileW(wfilename,
FILE_WRITE_ATTRIBUTES,
- 0 /*FileShare.None*/,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
(attrs != INVALID_FILE_ATTRIBUTES &&
@@ -1073,7 +1154,7 @@ int mkstemp(char *template)
return git_mkstemp_mode(template, 0600);
}
-int gettimeofday(struct timeval *tv, void *tz)
+int gettimeofday(struct timeval *tv, void *tz UNUSED)
{
FILETIME ft;
long long hnsec;
@@ -1259,7 +1340,8 @@ static const char *parse_interpreter(const char *cmd)
{
static char buf[100];
char *p, *opt;
- int n, fd;
+ ssize_t n; /* read() can return negative values */
+ int fd;
/* don't even try a .exe */
n = strlen(cmd);
@@ -1324,7 +1406,7 @@ static char *path_lookup(const char *cmd, int exe_only)
{
const char *path;
char *prog = NULL;
- int len = strlen(cmd);
+ size_t len = strlen(cmd);
int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
if (strpbrk(cmd, "/\\"))
@@ -1534,7 +1616,7 @@ static int is_msys2_sh(const char *cmd)
return ret;
}
- if (ends_with(cmd, "\\sh.exe")) {
+ if (ends_with(cmd, "\\sh.exe") || ends_with(cmd, "/sh.exe")) {
static char *sh;
if (!sh)
@@ -1941,7 +2023,7 @@ char *mingw_getenv(const char *name)
#define GETENV_MAX_RETAIN 64
static char *values[GETENV_MAX_RETAIN];
static int value_counter;
- int len_key, len_value;
+ size_t len_key, len_value;
wchar_t *w_key;
char *value;
wchar_t w_value[32768];
@@ -1953,7 +2035,8 @@ char *mingw_getenv(const char *name)
/* We cannot use xcalloc() here because that uses getenv() itself */
w_key = calloc(len_key, sizeof(wchar_t));
if (!w_key)
- die("Out of memory, (tried to allocate %u wchar_t's)", len_key);
+ die("Out of memory, (tried to allocate %"PRIuMAX" wchar_t's)",
+ (uintmax_t)len_key);
xutftowcs(w_key, name, len_key);
/* GetEnvironmentVariableW() only sets the last error upon failure */
SetLastError(ERROR_SUCCESS);
@@ -1968,7 +2051,8 @@ char *mingw_getenv(const char *name)
/* We cannot use xcalloc() here because that uses getenv() itself */
value = calloc(len_value, sizeof(char));
if (!value)
- die("Out of memory, (tried to allocate %u bytes)", len_value);
+ die("Out of memory, (tried to allocate %"PRIuMAX" bytes)",
+ (uintmax_t)len_value);
xwcstoutf(value, w_value, len_value);
/*
@@ -1986,7 +2070,7 @@ char *mingw_getenv(const char *name)
int mingw_putenv(const char *namevalue)
{
- int size;
+ size_t size;
wchar_t *wide, *equal;
BOOL result;
@@ -1996,7 +2080,8 @@ int mingw_putenv(const char *namevalue)
size = strlen(namevalue) * 2 + 1;
wide = calloc(size, sizeof(wchar_t));
if (!wide)
- die("Out of memory, (tried to allocate %u wchar_t's)", size);
+ die("Out of memory, (tried to allocate %" PRIuMAX " wchar_t's)",
+ (uintmax_t)size);
xutftowcs(wide, namevalue, size);
equal = wcschr(wide, L'=');
if (!equal)
@@ -2136,10 +2221,16 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
#undef rename
int mingw_rename(const char *pold, const char *pnew)
{
+ static int supports_file_rename_info_ex = 1;
DWORD attrs, gle;
int tries = 0;
wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
- if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
+ int wpnew_len;
+
+ if (xutftowcs_path(wpold, pold) < 0)
+ return -1;
+ wpnew_len = xutftowcs_path(wpnew, pnew);
+ if (wpnew_len < 0)
return -1;
/*
@@ -2150,11 +2241,84 @@ int mingw_rename(const char *pold, const char *pnew)
return 0;
if (errno != EEXIST)
return -1;
+
repeat:
- if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
- return 0;
+ if (supports_file_rename_info_ex) {
+ /*
+ * Our minimum required Windows version is still set to Windows
+ * Vista. We thus have to declare required infrastructure for
+ * FileRenameInfoEx ourselves until we bump _WIN32_WINNT to
+ * 0x0A00. Furthermore, we have to handle cases where the
+ * FileRenameInfoEx call isn't supported yet.
+ */
+#define FILE_RENAME_FLAG_REPLACE_IF_EXISTS 0x00000001
+#define FILE_RENAME_FLAG_POSIX_SEMANTICS 0x00000002
+ FILE_INFO_BY_HANDLE_CLASS FileRenameInfoEx = 22;
+ struct {
+ /*
+ * This is usually an unnamed union, but that is not
+ * part of ISO C99. We thus inline the field, as we
+ * really only care for the Flags field anyway.
+ */
+ DWORD Flags;
+ HANDLE RootDirectory;
+ DWORD FileNameLength;
+ /*
+ * The actual structure is defined with a single-character
+ * flex array so that the structure has to be allocated on
+ * the heap. As we declare this structure ourselves though
+ * we can avoid the allocation and define FileName to have
+ * MAX_PATH bytes.
+ */
+ WCHAR FileName[MAX_PATH];
+ } rename_info = { 0 };
+ HANDLE old_handle = INVALID_HANDLE_VALUE;
+ BOOL success;
+
+ old_handle = CreateFileW(wpold, DELETE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (old_handle == INVALID_HANDLE_VALUE) {
+ errno = err_win_to_posix(GetLastError());
+ return -1;
+ }
+
+ rename_info.Flags = FILE_RENAME_FLAG_REPLACE_IF_EXISTS |
+ FILE_RENAME_FLAG_POSIX_SEMANTICS;
+ rename_info.FileNameLength = wpnew_len * sizeof(WCHAR);
+ memcpy(rename_info.FileName, wpnew, wpnew_len * sizeof(WCHAR));
+
+ success = SetFileInformationByHandle(old_handle, FileRenameInfoEx,
+ &rename_info, sizeof(rename_info));
+ gle = GetLastError();
+ CloseHandle(old_handle);
+ if (success)
+ return 0;
+
+ /*
+ * When we see ERROR_INVALID_PARAMETER we can assume that the
+ * current system doesn't support FileRenameInfoEx. Keep us
+ * from using it in future calls and retry.
+ */
+ if (gle == ERROR_INVALID_PARAMETER) {
+ supports_file_rename_info_ex = 0;
+ goto repeat;
+ }
+
+ /*
+ * In theory, we shouldn't get ERROR_ACCESS_DENIED because we
+ * always open files with FILE_SHARE_DELETE But in practice we
+ * cannot assume that Git is the only one accessing files, and
+ * other applications may not set FILE_SHARE_DELETE. So we have
+ * to retry.
+ */
+ } else {
+ if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
+ return 0;
+ gle = GetLastError();
+ }
+
/* TODO: translate more errors */
- gle = GetLastError();
if (gle == ERROR_ACCESS_DENIED &&
(attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
@@ -2240,7 +2404,7 @@ char *mingw_query_user_email(void)
return get_extended_user_info(NameUserPrincipal);
}
-struct passwd *getpwuid(int uid)
+struct passwd *getpwuid(int uid UNUSED)
{
static unsigned initialized;
static char user_name[100];
@@ -2266,7 +2430,11 @@ struct passwd *getpwuid(int uid)
p->pw_name = user_name;
p->pw_gecos = get_extended_user_info(NameDisplay);
if (!p->pw_gecos)
- p->pw_gecos = "unknown";
+ /*
+ * Data returned by getpwuid(3P) is treated as internal and
+ * must never be written to or freed.
+ */
+ p->pw_gecos = (char *) "unknown";
p->pw_dir = NULL;
initialized = 1;
@@ -2288,7 +2456,7 @@ static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
* length to call the signal handler.
*/
-static unsigned __stdcall ticktack(void *dummy)
+static unsigned __stdcall ticktack(void *dummy UNUSED)
{
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
mingw_raise(SIGALRM);
@@ -2336,7 +2504,7 @@ static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *
return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
}
-int setitimer(int type, struct itimerval *in, struct itimerval *out)
+int setitimer(int type UNUSED, struct itimerval *in, struct itimerval *out)
{
static const struct timeval zero;
static int atexit_done;
@@ -2682,6 +2850,30 @@ static PSID get_current_user_sid(void)
return result;
}
+static BOOL user_sid_to_user_name(PSID sid, LPSTR *str)
+{
+ SID_NAME_USE pe_use;
+ DWORD len_user = 0, len_domain = 0;
+ BOOL translate_sid_to_user;
+
+ /*
+ * returns only FALSE, because the string pointers are NULL
+ */
+ LookupAccountSidA(NULL, sid, NULL, &len_user, NULL, &len_domain,
+ &pe_use);
+ /*
+ * Alloc needed space of the strings
+ */
+ ALLOC_ARRAY((*str), (size_t)len_domain + (size_t)len_user);
+ translate_sid_to_user = LookupAccountSidA(NULL, sid,
+ (*str) + len_domain, &len_user, *str, &len_domain, &pe_use);
+ if (!translate_sid_to_user)
+ FREE_AND_NULL(*str);
+ else
+ (*str)[len_domain] = '/';
+ return translate_sid_to_user;
+}
+
static int acls_supported(const char *path)
{
size_t offset = offset_1st_component(path);
@@ -2763,27 +2955,47 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
strbuf_addf(report, "'%s' is on a file system that does "
"not record ownership\n", path);
} else if (report) {
- LPSTR str1, str2, to_free1 = NULL, to_free2 = NULL;
+ PCSTR str1, str2, str3, str4;
+ LPSTR to_free1 = NULL, to_free3 = NULL,
+ to_local_free2 = NULL, to_local_free4 = NULL;
- if (ConvertSidToStringSidA(sid, &str1))
- to_free1 = str1;
+ if (user_sid_to_user_name(sid, &to_free1))
+ str1 = to_free1;
else
str1 = "(inconvertible)";
-
- if (!current_user_sid)
- str2 = "(none)";
- else if (!IsValidSid(current_user_sid))
- str2 = "(invalid)";
- else if (ConvertSidToStringSidA(current_user_sid, &str2))
- to_free2 = str2;
+ if (ConvertSidToStringSidA(sid, &to_local_free2))
+ str2 = to_local_free2;
else
str2 = "(inconvertible)";
+
+ if (!current_user_sid) {
+ str3 = "(none)";
+ str4 = "(none)";
+ }
+ else if (!IsValidSid(current_user_sid)) {
+ str3 = "(invalid)";
+ str4 = "(invalid)";
+ } else {
+ if (user_sid_to_user_name(current_user_sid,
+ &to_free3))
+ str3 = to_free3;
+ else
+ str3 = "(inconvertible)";
+ if (ConvertSidToStringSidA(current_user_sid,
+ &to_local_free4))
+ str4 = to_local_free4;
+ else
+ str4 = "(inconvertible)";
+ }
strbuf_addf(report,
"'%s' is owned by:\n"
- "\t'%s'\nbut the current user is:\n"
- "\t'%s'\n", path, str1, str2);
- LocalFree(to_free1);
- LocalFree(to_free2);
+ "\t%s (%s)\nbut the current user is:\n"
+ "\t%s (%s)\n",
+ path, str1, str2, str3, str4);
+ free(to_free1);
+ LocalFree(to_local_free2);
+ free(to_free3);
+ LocalFree(to_local_free4);
}
}
@@ -3022,7 +3234,8 @@ static void maybe_redirect_std_handles(void)
*/
int wmain(int argc, const wchar_t **wargv)
{
- int i, maxlen, exit_status;
+ int i, exit_status;
+ size_t maxlen;
char *buffer, **save;
const char **argv;
@@ -3101,3 +3314,24 @@ int uname(struct utsname *buf)
"%u", (v >> 16) & 0x7fff);
return 0;
}
+
+#ifndef NO_UNIX_SOCKETS
+int mingw_have_unix_sockets(void)
+{
+ SC_HANDLE scm, srvc;
+ SERVICE_STATUS_PROCESS status;
+ DWORD bytes;
+ int ret = 0;
+ scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+ if (scm) {
+ srvc = OpenServiceA(scm, "afunix", SERVICE_QUERY_STATUS);
+ if (srvc) {
+ if(QueryServiceStatusEx(srvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &bytes))
+ ret = status.dwCurrentState == SERVICE_RUNNING;
+ CloseServiceHandle(srvc);
+ }
+ CloseServiceHandle(scm);
+ }
+ return ret;
+}
+#endif
diff --git a/compat/mingw.h b/compat/mingw.h
index 6aec50e412..ebfb8ba423 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -122,17 +122,17 @@ struct utsname {
* trivial stubs
*/
-static inline int readlink(const char *path, char *buf, size_t bufsiz)
+static inline int readlink(const char *path UNUSED, char *buf UNUSED, size_t bufsiz UNUSED)
{ errno = ENOSYS; return -1; }
-static inline int symlink(const char *oldpath, const char *newpath)
+static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED)
{ errno = ENOSYS; return -1; }
-static inline int fchmod(int fildes, mode_t mode)
+static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED)
{ errno = ENOSYS; return -1; }
#ifndef __MINGW64_VERSION_MAJOR
static inline pid_t fork(void)
{ errno = ENOSYS; return -1; }
#endif
-static inline unsigned int alarm(unsigned int seconds)
+static inline unsigned int alarm(unsigned int seconds UNUSED)
{ return 0; }
static inline int fsync(int fd)
{ return _commit(fd); }
@@ -140,9 +140,9 @@ static inline void sync(void)
{}
static inline uid_t getuid(void)
{ return 1; }
-static inline struct passwd *getpwnam(const char *name)
+static inline struct passwd *getpwnam(const char *name UNUSED)
{ return NULL; }
-static inline int fcntl(int fd, int cmd, ...)
+static inline int fcntl(int fd UNUSED, int cmd, ...)
{
if (cmd == F_GETFD || cmd == F_SETFD)
return 0;
@@ -151,17 +151,17 @@ static inline int fcntl(int fd, int cmd, ...)
}
#define sigemptyset(x) (void)0
-static inline int sigaddset(sigset_t *set, int signum)
+static inline int sigaddset(sigset_t *set UNUSED, int signum UNUSED)
{ return 0; }
#define SIG_BLOCK 0
#define SIG_UNBLOCK 0
-static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+static inline int sigprocmask(int how UNUSED, const sigset_t *set UNUSED, sigset_t *oldset UNUSED)
{ return 0; }
static inline pid_t getppid(void)
{ return 1; }
static inline pid_t getpgid(pid_t pid)
{ return pid == 0 ? getpid() : pid; }
-static inline pid_t tcgetpgrp(int fd)
+static inline pid_t tcgetpgrp(int fd UNUSED)
{ return getpid(); }
/*
@@ -631,3 +631,9 @@ void open_in_gdb(void);
* Used by Pthread API implementation for Windows
*/
int err_win_to_posix(DWORD winerr);
+
+#ifndef NO_UNIX_SOCKETS
+int mingw_have_unix_sockets(void);
+#undef have_unix_sockets
+#define have_unix_sockets mingw_have_unix_sockets
+#endif
diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c
index 2c0ace7075..145255da43 100644
--- a/compat/nedmalloc/nedmalloc.c
+++ b/compat/nedmalloc/nedmalloc.c
@@ -31,6 +31,8 @@ DEALINGS IN THE SOFTWARE.
/*#pragma optimize("a", on)*/
#endif
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
/*#define FULLSANITYCHECKS*/
#include "nedmalloc.h"
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 0bd5c24250..f7cc7b3be5 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -4,6 +4,7 @@
*/
#define PRECOMPOSE_UNICODE_C
+#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "config.h"
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index d1bc09e49b..8d93a9b93f 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -17,6 +17,8 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
#if defined __TANDEM
/* This is currently duplicated from git-compat-utils.h */
# ifdef NO_INTPTR_T
@@ -848,7 +850,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
{
unsigned int table_size;
#ifndef _LIBC
- char *codeset_name;
+ const char *codeset_name;
#endif
memset (dfa, '\0', sizeof (re_dfa_t));
@@ -868,7 +870,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
if (table_size > pat_len)
break;
- dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
+ dfa->state_table = calloc (table_size, sizeof (struct re_state_table_entry));
dfa->state_hash_mask = table_size - 1;
dfa->mb_cur_max = MB_CUR_MAX;
@@ -936,7 +938,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
{
int i, j, ch;
- dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+ dfa->sb_char = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t));
if (BE (dfa->sb_char == NULL, 0))
return REG_ESPACE;
@@ -3079,9 +3081,9 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
_NL_COLLATE_SYMB_EXTRAMB);
}
#endif
- sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+ sbcset = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t));
#ifdef RE_ENABLE_I18N
- mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+ mbcset = (re_charset_t *) calloc (1, sizeof (re_charset_t));
#endif /* RE_ENABLE_I18N */
#ifdef RE_ENABLE_I18N
if (BE (sbcset == NULL || mbcset == NULL, 0))
@@ -3626,9 +3628,9 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
re_token_t br_token;
bin_tree_t *tree;
- sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+ sbcset = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t));
#ifdef RE_ENABLE_I18N
- mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+ mbcset = (re_charset_t *) calloc (1, sizeof (re_charset_t));
#endif /* RE_ENABLE_I18N */
#ifdef RE_ENABLE_I18N
diff --git a/compat/regex/regex_internal.c b/compat/regex/regex_internal.c
index ec51cf3446..ec5cc5d2dd 100644
--- a/compat/regex/regex_internal.c
+++ b/compat/regex/regex_internal.c
@@ -1628,7 +1628,7 @@ create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
reg_errcode_t err;
re_dfastate_t *newstate;
- newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ newstate = (re_dfastate_t *) calloc (1, sizeof (re_dfastate_t));
if (BE (newstate == NULL, 0))
return NULL;
err = re_node_set_init_copy (&newstate->nodes, nodes);
@@ -1678,7 +1678,7 @@ create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
reg_errcode_t err;
re_dfastate_t *newstate;
- newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ newstate = (re_dfastate_t *) calloc (1, sizeof (re_dfastate_t));
if (BE (newstate == NULL, 0))
return NULL;
err = re_node_set_init_copy (&newstate->nodes, nodes);
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index 49358ae475..2eeec82f40 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -292,7 +292,7 @@ compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
concerned.
If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
- and all groups is stroed in REGS. (For the "_2" variants, the offsets are
+ and all groups are stored in REGS. (For the "_2" variants, the offsets are
computed relative to the concatenation, not relative to the individual
strings.)
@@ -2796,8 +2796,8 @@ get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
continue; /* No. */
if (sub_top->path == NULL)
{
- sub_top->path = calloc (sizeof (state_array_t),
- sl_str - sub_top->str_idx + 1);
+ sub_top->path = calloc (sl_str - sub_top->str_idx + 1,
+ sizeof (state_array_t));
if (sub_top->path == NULL)
return REG_ESPACE;
}
@@ -3361,7 +3361,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
if (ndests == 0)
{
state->trtable = (re_dfastate_t **)
- calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ calloc (SBC_MAX, sizeof (re_dfastate_t *));
return 1;
}
return 0;
@@ -3457,7 +3457,7 @@ out_free:
discern by looking at the character code: allocate a
256-entry transition table. */
trtable = state->trtable =
- (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ (re_dfastate_t **) calloc (SBC_MAX, sizeof (re_dfastate_t *));
if (BE (trtable == NULL, 0))
goto out_free;
@@ -3488,7 +3488,7 @@ out_free:
transition tables, one starting at trtable[0] and one
starting at trtable[SBC_MAX]. */
trtable = state->word_trtable =
- (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
+ (re_dfastate_t **) calloc (2 * SBC_MAX, sizeof (re_dfastate_t *));
if (BE (trtable == NULL, 0))
goto out_free;
diff --git a/compat/sha1-chunked.c b/compat/sha1-chunked.c
index a4a6f930d7..0446f9983f 100644
--- a/compat/sha1-chunked.c
+++ b/compat/sha1-chunked.c
@@ -1,5 +1,5 @@
#include "git-compat-util.h"
-#include "hash-ll.h"
+#include "hash.h"
int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len)
{
diff --git a/compat/simple-ipc/ipc-shared.c b/compat/simple-ipc/ipc-shared.c
index e5e1dda8cc..d1c21b49bd 100644
--- a/compat/simple-ipc/ipc-shared.c
+++ b/compat/simple-ipc/ipc-shared.c
@@ -1,8 +1,5 @@
#include "git-compat-util.h"
#include "simple-ipc.h"
-#include "strbuf.h"
-#include "pkt-line.h"
-#include "thread-utils.h"
#ifndef SUPPORTS_SIMPLE_IPC
/*
@@ -19,11 +16,12 @@ int ipc_server_run(const char *path, const struct ipc_server_opts *opts,
struct ipc_server_data *server_data = NULL;
int ret;
- ret = ipc_server_run_async(&server_data, path, opts,
- application_cb, application_data);
+ ret = ipc_server_init_async(&server_data, path, opts,
+ application_cb, application_data);
if (ret)
return ret;
+ ipc_server_start_async(server_data);
ret = ipc_server_await(server_data);
ipc_server_free(server_data);
diff --git a/compat/simple-ipc/ipc-unix-socket.c b/compat/simple-ipc/ipc-unix-socket.c
index b2f4f22ce4..7db3b2a897 100644
--- a/compat/simple-ipc/ipc-unix-socket.c
+++ b/compat/simple-ipc/ipc-unix-socket.c
@@ -2,7 +2,6 @@
#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"
@@ -329,6 +328,7 @@ struct ipc_server_data {
int back_pos;
int front_pos;
+ int started;
int shutdown_requested;
int is_stopped;
};
@@ -713,7 +713,7 @@ static int accept_thread__wait_for_connection(
* Block SIGPIPE in this thread for the life of the thread. This
* avoids any stray SIGPIPE signals when closing pipe fds under
* extremely heavy loads (such as when the fifo queue is full and we
- * drop incomming connections).
+ * drop incoming connections).
*/
static void *accept_thread_proc(void *_accept_thread_data)
{
@@ -825,10 +825,10 @@ static int setup_listener_socket(
/*
* Start IPC server in a pool of background threads.
*/
-int ipc_server_run_async(struct ipc_server_data **returned_server_data,
- const char *path, const struct ipc_server_opts *opts,
- ipc_server_application_cb *application_cb,
- void *application_data)
+int ipc_server_init_async(struct ipc_server_data **returned_server_data,
+ const char *path, const struct ipc_server_opts *opts,
+ ipc_server_application_cb *application_cb,
+ void *application_data)
{
struct unix_ss_socket *server_socket = NULL;
struct ipc_server_data *server_data;
@@ -889,6 +889,12 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
server_data->accept_thread->fd_send_shutdown = sv[0];
server_data->accept_thread->fd_wait_shutdown = sv[1];
+ /*
+ * Hold work-available mutex so that no work can start until
+ * we unlock it.
+ */
+ pthread_mutex_lock(&server_data->work_available_mutex);
+
if (pthread_create(&server_data->accept_thread->pthread_id, NULL,
accept_thread_proc, server_data->accept_thread))
die_errno(_("could not start accept_thread '%s'"), path);
@@ -919,6 +925,15 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
return 0;
}
+void ipc_server_start_async(struct ipc_server_data *server_data)
+{
+ if (!server_data || server_data->started)
+ return;
+
+ server_data->started = 1;
+ pthread_mutex_unlock(&server_data->work_available_mutex);
+}
+
/*
* Gently tell the IPC server treads to shutdown.
* Can be run on any thread.
@@ -934,7 +949,9 @@ int ipc_server_stop_async(struct ipc_server_data *server_data)
trace2_region_enter("ipc-server", "server-stop-async", NULL);
- pthread_mutex_lock(&server_data->work_available_mutex);
+ /* If we haven't started yet, we are already holding lock. */
+ if (server_data->started)
+ pthread_mutex_lock(&server_data->work_available_mutex);
server_data->shutdown_requested = 1;
diff --git a/compat/simple-ipc/ipc-win32.c b/compat/simple-ipc/ipc-win32.c
index 8bfe51248e..a8fc812adf 100644
--- a/compat/simple-ipc/ipc-win32.c
+++ b/compat/simple-ipc/ipc-win32.c
@@ -371,6 +371,9 @@ struct ipc_server_data {
HANDLE hEventStopRequested;
struct ipc_server_thread_data *thread_list;
int is_stopped;
+
+ pthread_mutex_t startup_barrier;
+ int started;
};
enum connect_result {
@@ -526,6 +529,16 @@ static int use_connection(struct ipc_server_thread_data *server_thread_data)
return ret;
}
+static void wait_for_startup_barrier(struct ipc_server_data *server_data)
+{
+ /*
+ * Temporarily hold the startup_barrier mutex before starting,
+ * which lets us know that it's OK to start serving requests.
+ */
+ pthread_mutex_lock(&server_data->startup_barrier);
+ pthread_mutex_unlock(&server_data->startup_barrier);
+}
+
/*
* Thread proc for an IPC server worker thread. It handles a series of
* connections from clients. It cleans and reuses the hPipe between each
@@ -550,6 +563,8 @@ static void *server_thread_proc(void *_server_thread_data)
memset(&oConnect, 0, sizeof(oConnect));
oConnect.hEvent = hEventConnected;
+ wait_for_startup_barrier(server_thread_data->server_data);
+
for (;;) {
cr = wait_for_connection(server_thread_data, &oConnect);
@@ -752,10 +767,10 @@ static HANDLE create_new_pipe(wchar_t *wpath, int is_first)
return hPipe;
}
-int ipc_server_run_async(struct ipc_server_data **returned_server_data,
- const char *path, const struct ipc_server_opts *opts,
- ipc_server_application_cb *application_cb,
- void *application_data)
+int ipc_server_init_async(struct ipc_server_data **returned_server_data,
+ const char *path, const struct ipc_server_opts *opts,
+ ipc_server_application_cb *application_cb,
+ void *application_data)
{
struct ipc_server_data *server_data;
wchar_t wpath[MAX_PATH];
@@ -787,6 +802,13 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
strbuf_addstr(&server_data->buf_path, path);
wcscpy(server_data->wpath, wpath);
+ /*
+ * Hold the startup_barrier lock so that no threads will progress
+ * until ipc_server_start_async() is called.
+ */
+ pthread_mutex_init(&server_data->startup_barrier, NULL);
+ pthread_mutex_lock(&server_data->startup_barrier);
+
if (nr_threads < 1)
nr_threads = 1;
@@ -837,6 +859,15 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
return 0;
}
+void ipc_server_start_async(struct ipc_server_data *server_data)
+{
+ if (!server_data || server_data->started)
+ return;
+
+ server_data->started = 1;
+ pthread_mutex_unlock(&server_data->startup_barrier);
+}
+
int ipc_server_stop_async(struct ipc_server_data *server_data)
{
if (!server_data)
@@ -850,6 +881,13 @@ int ipc_server_stop_async(struct ipc_server_data *server_data)
* We DO NOT attempt to force them to drop an active connection.
*/
SetEvent(server_data->hEventStopRequested);
+
+ /*
+ * If we haven't yet told the threads they are allowed to run,
+ * do so now, so they can receive the shutdown event.
+ */
+ ipc_server_start_async(server_data);
+
return 0;
}
@@ -900,5 +938,7 @@ void ipc_server_free(struct ipc_server_data *server_data)
free(std);
}
+ pthread_mutex_destroy(&server_data->startup_barrier);
+
free(server_data);
}
diff --git a/compat/stub/procinfo.c b/compat/stub/procinfo.c
index 12c0a23c9e..3168cd5714 100644
--- a/compat/stub/procinfo.c
+++ b/compat/stub/procinfo.c
@@ -6,6 +6,6 @@
* Stub. See sample implementations in compat/linux/procinfo.c and
* compat/win32/trace2_win32_process_info.c.
*/
-void trace2_collect_process_info(enum trace2_process_info_reason reason)
+void trace2_collect_process_info(enum trace2_process_info_reason reason UNUSED)
{
}
diff --git a/compat/terminal.c b/compat/terminal.c
index 0afda730f2..d54efa1c5d 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -594,7 +594,7 @@ void restore_term(void)
{
}
-char *git_terminal_prompt(const char *prompt, int echo)
+char *git_terminal_prompt(const char *prompt, int echo UNUSED)
{
return getpass(prompt);
}
diff --git a/compat/vcbuild/include/unistd.h b/compat/vcbuild/include/unistd.h
index 3a959d124c..a261a925b7 100644
--- a/compat/vcbuild/include/unistd.h
+++ b/compat/vcbuild/include/unistd.h
@@ -14,7 +14,11 @@ typedef _mode_t mode_t;
#ifndef _SSIZE_T_
#define _SSIZE_T_
+#ifdef _WIN64
+typedef __int64 _ssize_t;
+#else
typedef long _ssize_t;
+#endif /* _WIN64 */
#ifndef _OFF_T_
#define _OFF_T_
diff --git a/compat/win32/headless.c b/compat/win32/headless.c
index 8b00dfe3bd..11392a0b9a 100644
--- a/compat/win32/headless.c
+++ b/compat/win32/headless.c
@@ -11,6 +11,8 @@
#include <stdlib.h>
#include <wchar.h>
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
/*
* If `dir` contains the path to a Git exec directory, extend `PATH` to
* include the corresponding `bin/` directory (which is where all those
diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
index ebf2f12eb6..966ef779b9 100644
--- a/compat/win32/path-utils.c
+++ b/compat/win32/path-utils.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../../git-compat-util.h"
+#include "../../environment.h"
int win32_has_dos_drive_prefix(const char *path)
{
@@ -50,3 +53,39 @@ int win32_offset_1st_component(const char *path)
return pos + is_dir_sep(*pos) - path;
}
+
+int win32_fspathncmp(const char *a, const char *b, size_t count)
+{
+ int diff;
+
+ for (;;) {
+ if (!count--)
+ return 0;
+ if (!*a)
+ return *b ? -1 : 0;
+ if (!*b)
+ return +1;
+
+ if (is_dir_sep(*a)) {
+ if (!is_dir_sep(*b))
+ return -1;
+ a++;
+ b++;
+ continue;
+ } else if (is_dir_sep(*b))
+ return +1;
+
+ diff = ignore_case ?
+ (unsigned char)tolower(*a) - (int)(unsigned char)tolower(*b) :
+ (unsigned char)*a - (int)(unsigned char)*b;
+ if (diff)
+ return diff;
+ a++;
+ b++;
+ }
+}
+
+int win32_fspathcmp(const char *a, const char *b)
+{
+ return win32_fspathncmp(a, b, (size_t)-1);
+}
diff --git a/compat/win32/path-utils.h b/compat/win32/path-utils.h
index 65fa3b9263..a561c700e7 100644
--- a/compat/win32/path-utils.h
+++ b/compat/win32/path-utils.h
@@ -29,5 +29,9 @@ static inline int win32_has_dir_sep(const char *path)
#define has_dir_sep(path) win32_has_dir_sep(path)
int win32_offset_1st_component(const char *path);
#define offset_1st_component win32_offset_1st_component
+int win32_fspathcmp(const char *a, const char *b);
+#define fspathcmp win32_fspathcmp
+int win32_fspathncmp(const char *a, const char *b, size_t count);
+#define fspathncmp win32_fspathncmp
#endif
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 85f8f7920c..58980a529c 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -21,7 +21,7 @@ static unsigned __stdcall win32_start_routine(void *arg)
return 0;
}
-int pthread_create(pthread_t *thread, const void *unused,
+int pthread_create(pthread_t *thread, const void *attr UNUSED,
void *(*start_routine)(void *), void *arg)
{
thread->arg = arg;
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index cc3221cb2c..e2b5c4f64c 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -18,7 +18,7 @@
*/
#define pthread_mutex_t CRITICAL_SECTION
-static inline int return_0(int i) {
+static inline int return_0(int i UNUSED) {
return 0;
}
#define pthread_mutex_init(a,b) return_0((InitializeCriticalSection((a)), 0))
@@ -70,7 +70,7 @@ static inline void NORETURN pthread_exit(void *ret)
}
typedef DWORD pthread_key_t;
-static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value))
+static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value) UNUSED)
{
return (*keyp = TlsAlloc()) == TLS_OUT_OF_INDEXES ? EAGAIN : 0;
}
diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c
index 0af18d8882..4e4794743a 100644
--- a/compat/win32/syslog.c
+++ b/compat/win32/syslog.c
@@ -2,7 +2,7 @@
static HANDLE ms_eventlog;
-void openlog(const char *ident, int logopt, int facility)
+void openlog(const char *ident, int logopt UNUSED, int facility UNUSED)
{
if (ms_eventlog)
return;
diff --git a/compat/win32/trace2_win32_process_info.c b/compat/win32/trace2_win32_process_info.c
index 3ef0936f6f..f147da706a 100644
--- a/compat/win32/trace2_win32_process_info.c
+++ b/compat/win32/trace2_win32_process_info.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../../git-compat-util.h"
#include "../../json-writer.h"
#include "../../repository.h"
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 519d51f2b6..a4ab4cb939 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -40,7 +40,7 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
return MAP_FAILED;
}
-int git_munmap(void *start, size_t length)
+int git_munmap(void *start, size_t length UNUSED)
{
return !UnmapViewOfFile(start);
}
diff --git a/compat/winansi.c b/compat/winansi.c
index f83610f684..1b3f916b9f 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -139,7 +139,7 @@ static void write_console(unsigned char *str, size_t len)
/* convert utf-8 to utf-16 */
int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
if (wlen < 0) {
- wchar_t *err = L"[invalid]";
+ const wchar_t *err = L"[invalid]";
WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
return;
}
@@ -340,7 +340,7 @@ enum {
TEXT = 0, ESCAPE = 033, BRACKET = '['
};
-static DWORD WINAPI console_thread(LPVOID unused)
+static DWORD WINAPI console_thread(LPVOID data UNUSED)
{
unsigned char buffer[BUFFER_SIZE];
DWORD bytes;
diff --git a/config.c b/config.c
index 3846a37be9..a11bb85da3 100644
--- a/config.c
+++ b/config.c
@@ -5,12 +5,16 @@
* Copyright (C) Johannes Schindelin, 2005
*
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
#include "date.h"
#include "branch.h"
#include "config.h"
+#include "parse.h"
#include "convert.h"
#include "environment.h"
#include "gettext.h"
@@ -18,6 +22,7 @@
#include "repository.h"
#include "lockfile.h"
#include "mailmap.h"
+#include "attr.h"
#include "exec-cmd.h"
#include "strbuf.h"
#include "quote.h"
@@ -28,15 +33,12 @@
#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"
@@ -96,7 +98,6 @@ static long config_file_ftell(struct config_source *conf)
return ftell(conf->u.file);
}
-
static int config_buf_fgetc(struct config_source *conf)
{
if (conf->u.buf.pos < conf->u.buf.len)
@@ -127,7 +128,7 @@ struct config_include_data {
config_fn_t fn;
void *data;
const struct config_options *opts;
- struct git_config_source *config_source;
+ const struct git_config_source *config_source;
struct repository *repo;
/*
@@ -299,17 +300,22 @@ done:
return ret;
}
-static int include_by_branch(const char *cond, size_t cond_len)
+static int include_by_branch(struct config_include_data *data,
+ const char *cond, size_t cond_len)
{
int flags;
int ret;
struct strbuf pattern = STRBUF_INIT;
- const char *refname = !the_repository->gitdir ?
- NULL : resolve_ref_unsafe("HEAD", 0, NULL, &flags);
- const char *shortname;
+ const char *refname, *shortname;
- if (!refname || !(flags & REF_ISSYMREF) ||
- !skip_prefix(refname, "refs/heads/", &shortname))
+ if (!data->repo || data->repo->ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ return 0;
+
+ refname = refs_resolve_ref_unsafe(get_main_ref_store(data->repo),
+ "HEAD", 0, NULL, &flags);
+ if (!refname ||
+ !(flags & REF_ISSYMREF) ||
+ !skip_prefix(refname, "refs/heads/", &shortname))
return 0;
strbuf_add(&pattern, cond, cond_len);
@@ -404,7 +410,7 @@ static int include_condition_is_true(const struct key_value_info *kvi,
else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
return include_by_gitdir(kvi, opts, cond, cond_len, 1);
else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
- return include_by_branch(cond, cond_len);
+ return include_by_branch(inc, cond, cond_len);
else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
&cond_len))
return include_by_remote_url(inc, cond, cond_len);
@@ -819,7 +825,8 @@ static int get_next_char(struct config_source *cs)
static char *parse_value(struct config_source *cs)
{
- int quote = 0, comment = 0, space = 0;
+ int quote = 0, comment = 0;
+ size_t trim_len = 0;
strbuf_reset(&cs->value);
for (;;) {
@@ -829,13 +836,17 @@ static char *parse_value(struct config_source *cs)
cs->linenr--;
return NULL;
}
+ if (trim_len)
+ strbuf_setlen(&cs->value, trim_len);
return cs->value.buf;
}
if (comment)
continue;
if (isspace(c) && !quote) {
+ if (!trim_len)
+ trim_len = cs->value.len;
if (cs->value.len)
- space++;
+ strbuf_addch(&cs->value, c);
continue;
}
if (!quote) {
@@ -844,8 +855,8 @@ static char *parse_value(struct config_source *cs)
continue;
}
}
- for (; space; space--)
- strbuf_addch(&cs->value, ' ');
+ if (trim_len)
+ trim_len = 0;
if (c == '\\') {
c = get_next_char(cs);
switch (c) {
@@ -871,7 +882,7 @@ static char *parse_value(struct config_source *cs)
continue;
}
if (c == '"') {
- quote = 1-quote;
+ quote = 1 - quote;
continue;
}
strbuf_addch(&cs->value, c);
@@ -1165,129 +1176,6 @@ static int git_parse_source(struct config_source *cs, config_fn_t fn,
return error_return;
}
-static uintmax_t get_unit_factor(const char *end)
-{
- if (!*end)
- return 1;
- else if (!strcasecmp(end, "k"))
- return 1024;
- else if (!strcasecmp(end, "m"))
- return 1024 * 1024;
- else if (!strcasecmp(end, "g"))
- return 1024 * 1024 * 1024;
- return 0;
-}
-
-static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
-{
- if (value && *value) {
- char *end;
- intmax_t val;
- intmax_t factor;
-
- if (max < 0)
- BUG("max must be a positive integer");
-
- errno = 0;
- val = strtoimax(value, &end, 0);
- if (errno == ERANGE)
- return 0;
- if (end == value) {
- errno = EINVAL;
- return 0;
- }
- factor = get_unit_factor(end);
- if (!factor) {
- errno = EINVAL;
- return 0;
- }
- if ((val < 0 && -max / factor > val) ||
- (val > 0 && max / factor < val)) {
- errno = ERANGE;
- return 0;
- }
- val *= factor;
- *ret = val;
- return 1;
- }
- errno = EINVAL;
- return 0;
-}
-
-static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
-{
- if (value && *value) {
- char *end;
- uintmax_t val;
- uintmax_t factor;
-
- /* negative values would be accepted by strtoumax */
- if (strchr(value, '-')) {
- errno = EINVAL;
- return 0;
- }
- errno = 0;
- val = strtoumax(value, &end, 0);
- if (errno == ERANGE)
- return 0;
- if (end == value) {
- errno = EINVAL;
- return 0;
- }
- factor = get_unit_factor(end);
- if (!factor) {
- errno = EINVAL;
- return 0;
- }
- if (unsigned_mult_overflows(factor, val) ||
- factor * val > max) {
- errno = ERANGE;
- return 0;
- }
- val *= factor;
- *ret = val;
- return 1;
- }
- errno = EINVAL;
- return 0;
-}
-
-int git_parse_int(const char *value, int *ret)
-{
- intmax_t tmp;
- if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
- return 0;
- *ret = tmp;
- return 1;
-}
-
-static int git_parse_int64(const char *value, int64_t *ret)
-{
- intmax_t tmp;
- if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
- return 0;
- *ret = tmp;
- return 1;
-}
-
-int git_parse_ulong(const char *value, unsigned long *ret)
-{
- uintmax_t tmp;
- if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
- return 0;
- *ret = tmp;
- return 1;
-}
-
-int git_parse_ssize_t(const char *value, ssize_t *ret)
-{
- intmax_t tmp;
- if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
- return 0;
- *ret = tmp;
- return 1;
-}
-
NORETURN
static void die_bad_number(const char *name, const char *value,
const struct key_value_info *kvi)
@@ -1363,21 +1251,13 @@ ssize_t git_config_ssize_t(const char *name, const char *value,
return ret;
}
-static int git_parse_maybe_bool_text(const char *value)
+double git_config_double(const char *name, const char *value,
+ const struct key_value_info *kvi)
{
- if (!value)
- return 1;
- if (!*value)
- return 0;
- if (!strcasecmp(value, "true")
- || !strcasecmp(value, "yes")
- || !strcasecmp(value, "on"))
- return 1;
- if (!strcasecmp(value, "false")
- || !strcasecmp(value, "no")
- || !strcasecmp(value, "off"))
- return 0;
- return -1;
+ double ret;
+ if (!git_parse_double(value, &ret))
+ die_bad_number(name, value, kvi);
+ return ret;
}
static const struct fsync_component_name {
@@ -1454,16 +1334,6 @@ next_name:
return (current & ~negative) | positive;
}
-int git_parse_maybe_bool(const char *value)
-{
- int v = git_parse_maybe_bool_text(value);
- if (0 <= v)
- return v;
- if (git_parse_int(value, &v))
- return !!v;
- return -1;
-}
-
int git_config_bool_or_int(const char *name, const char *value,
const struct key_value_info *kvi, int *is_bool)
{
@@ -1484,7 +1354,7 @@ int git_config_bool(const char *name, const char *value)
return v;
}
-int git_config_string(const char **dest, const char *var, const char *value)
+int git_config_string(char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
@@ -1492,7 +1362,7 @@ int git_config_string(const char **dest, const char *var, const char *value)
return 0;
}
-int git_config_pathname(const char **dest, const char *var, const char *value)
+int git_config_pathname(char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
@@ -1534,10 +1404,15 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "core.checkstat")) {
+ if (!value)
+ return config_error_nonbool(var);
if (!strcasecmp(value, "default"))
check_stat = 1;
else if (!strcasecmp(value, "minimal"))
check_stat = 0;
+ else
+ return error(_("invalid value for '%s': '%s'"),
+ var, value);
}
if (!strcmp(var, "core.quotepath")) {
@@ -1555,11 +1430,15 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.attributesfile"))
+ if (!strcmp(var, "core.attributesfile")) {
+ FREE_AND_NULL(git_attributes_file);
return git_config_pathname(&git_attributes_file, var, value);
+ }
- if (!strcmp(var, "core.hookspath"))
+ if (!strcmp(var, "core.hookspath")) {
+ FREE_AND_NULL(git_hooks_path);
return git_config_pathname(&git_hooks_path, var, value);
+ }
if (!strcmp(var, "core.bare")) {
is_bare_repository_cfg = git_config_bool(var, value);
@@ -1571,36 +1450,16 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.prefersymlinkrefs")) {
- prefer_symlink_refs = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.logallrefupdates")) {
- if (value && !strcasecmp(value, "always"))
- log_all_ref_updates = LOG_REFS_ALWAYS;
- else if (git_config_bool(var, value))
- log_all_ref_updates = LOG_REFS_NORMAL;
- else
- log_all_ref_updates = LOG_REFS_NONE;
- return 0;
- }
-
- if (!strcmp(var, "core.warnambiguousrefs")) {
- warn_ambiguous_refs = git_config_bool(var, value);
- return 0;
- }
-
if (!strcmp(var, "core.abbrev")) {
if (!value)
return config_error_nonbool(var);
if (!strcasecmp(value, "auto"))
default_abbrev = -1;
else if (!git_parse_maybe_bool_text(value))
- default_abbrev = the_hash_algo->hexsz;
+ default_abbrev = GIT_MAX_HEXSZ;
else {
int abbrev = git_config_int(var, value, ctx->kvi);
- if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz)
+ if (abbrev < minimum_abbrev)
return error(_("abbrev length out of range: %d"), abbrev);
default_abbrev = abbrev;
}
@@ -1695,36 +1554,41 @@ static int git_default_core_config(const char *var, const char *value,
}
if (!strcmp(var, "core.checkroundtripencoding")) {
- check_roundtrip_encoding = xstrdup(value);
- return 0;
- }
-
- if (!strcmp(var, "core.notesref")) {
- notes_ref_name = xstrdup(value);
- return 0;
+ FREE_AND_NULL(check_roundtrip_encoding);
+ return git_config_string(&check_roundtrip_encoding, var, value);
}
- if (!strcmp(var, "core.editor"))
+ if (!strcmp(var, "core.editor")) {
+ FREE_AND_NULL(editor_program);
return git_config_string(&editor_program, var, value);
+ }
- if (!strcmp(var, "core.commentchar")) {
+ if (!strcmp(var, "core.commentchar") ||
+ !strcmp(var, "core.commentstring")) {
if (!value)
return config_error_nonbool(var);
else if (!strcasecmp(value, "auto"))
auto_comment_line_char = 1;
- else if (value[0] && !value[1]) {
- comment_line_char = value[0];
+ else if (value[0]) {
+ if (strchr(value, '\n'))
+ return error(_("%s cannot contain newline"), var);
+ comment_line_str = value;
+ FREE_AND_NULL(comment_line_str_to_free);
auto_comment_line_char = 0;
} else
- return error(_("core.commentChar should only be one ASCII character"));
+ return error(_("%s must have at least one character"), var);
return 0;
}
- if (!strcmp(var, "core.askpass"))
+ if (!strcmp(var, "core.askpass")) {
+ FREE_AND_NULL(askpass_program);
return git_config_string(&askpass_program, var, value);
+ }
- if (!strcmp(var, "core.excludesfile"))
+ if (!strcmp(var, "core.excludesfile")) {
+ FREE_AND_NULL(excludes_file);
return git_config_pathname(&excludes_file, var, value);
+ }
if (!strcmp(var, "core.whitespace")) {
if (!value)
@@ -1767,6 +1631,8 @@ static int git_default_core_config(const char *var, const char *value,
}
if (!strcmp(var, "core.createobject")) {
+ if (!value)
+ return config_error_nonbool(var);
if (!strcmp(value, "rename"))
object_creation_mode = OBJECT_CREATION_USES_RENAMES;
else if (!strcmp(value, "link"))
@@ -1801,6 +1667,11 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
+ if (!strcmp(var, "core.maxtreedepth")) {
+ max_allowed_tree_depth = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return platform_core_config(var, value, ctx, cb);
}
@@ -1818,11 +1689,15 @@ static int git_default_sparse_config(const char *var, const char *value)
static int git_default_i18n_config(const char *var, const char *value)
{
- if (!strcmp(var, "i18n.commitencoding"))
+ if (!strcmp(var, "i18n.commitencoding")) {
+ FREE_AND_NULL(git_commit_encoding);
return git_config_string(&git_commit_encoding, var, value);
+ }
- if (!strcmp(var, "i18n.logoutputencoding"))
+ if (!strcmp(var, "i18n.logoutputencoding")) {
+ FREE_AND_NULL(git_log_output_encoding);
return git_config_string(&git_log_output_encoding, var, value);
+ }
/* Add other config variables here and to Documentation/config.txt. */
return 0;
@@ -1895,15 +1770,34 @@ static int git_default_push_config(const char *var, const char *value)
static int git_default_mailmap_config(const char *var, const char *value)
{
- if (!strcmp(var, "mailmap.file"))
+ if (!strcmp(var, "mailmap.file")) {
+ FREE_AND_NULL(git_mailmap_file);
return git_config_pathname(&git_mailmap_file, var, value);
- if (!strcmp(var, "mailmap.blob"))
+ }
+
+ if (!strcmp(var, "mailmap.blob")) {
+ FREE_AND_NULL(git_mailmap_blob);
return git_config_string(&git_mailmap_blob, var, value);
+ }
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
+static int git_default_attr_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "attr.tree")) {
+ FREE_AND_NULL(git_attr_tree);
+ return git_config_string(&git_attr_tree, var, value);
+ }
+
+ /*
+ * Add other attribute related config variables here and to
+ * Documentation/config/attr.txt.
+ */
+ return 0;
+}
+
int git_default_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
@@ -1927,6 +1821,9 @@ int git_default_config(const char *var, const char *value,
if (starts_with(var, "mailmap."))
return git_default_mailmap_config(var, value);
+ if (starts_with(var, "attr."))
+ return git_default_attr_config(var, value);
+
if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
return git_default_advice_config(var, value);
@@ -2112,7 +2009,27 @@ char *git_system_config(void)
return system_config;
}
-void git_global_config(char **user_out, char **xdg_out)
+char *git_global_config(void)
+{
+ char *user_config, *xdg_config;
+
+ git_global_config_paths(&user_config, &xdg_config);
+ if (!user_config) {
+ free(xdg_config);
+ return NULL;
+ }
+
+ if (access_or_warn(user_config, R_OK, 0) && xdg_config &&
+ !access_or_warn(xdg_config, R_OK, 0)) {
+ free(user_config);
+ return xdg_config;
+ } else {
+ free(xdg_config);
+ return user_config;
+ }
+}
+
+void git_global_config_paths(char **user_out, char **xdg_out)
{
char *user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
char *xdg_config = NULL;
@@ -2126,28 +2043,6 @@ void git_global_config(char **user_out, char **xdg_out)
*xdg_out = xdg_config;
}
-/*
- * Parse environment variable 'k' as a boolean (in various
- * possible spellings); if missing, use the default value 'def'.
- */
-int git_env_bool(const char *k, int def)
-{
- const char *v = getenv(k);
- return v ? git_config_bool(k, v) : def;
-}
-
-/*
- * Parse environment variable 'k' as ulong with possibly a unit
- * suffix; if missing, use the default value 'val'.
- */
-unsigned long git_env_ulong(const char *k, unsigned long val)
-{
- const char *v = getenv(k);
- if (v && !git_parse_ulong(v, &val))
- die(_("failed to parse %s"), k);
- return val;
-}
-
int git_config_system(void)
{
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
@@ -2187,7 +2082,7 @@ static int do_git_config_sequence(const struct config_options *opts,
data, CONFIG_SCOPE_SYSTEM,
NULL);
- git_global_config(&user_config, &xdg_config);
+ git_global_config_paths(&user_config, &xdg_config);
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
ret += git_config_from_file_with_options(fn, xdg_config, data,
@@ -2222,7 +2117,7 @@ static int do_git_config_sequence(const struct config_options *opts,
}
int config_with_options(config_fn_t fn, void *data,
- struct git_config_source *config_source,
+ const struct git_config_source *config_source,
struct repository *repo,
const struct config_options *opts)
{
@@ -2284,7 +2179,7 @@ static void configset_iter(struct config_set *set, config_fn_t fn, void *data)
}
}
-void read_early_config(config_fn_t cb, void *data)
+void read_early_config(struct repository *repo, config_fn_t cb, void *data)
{
struct config_options opts = {0};
struct strbuf commondir = STRBUF_INIT;
@@ -2292,9 +2187,9 @@ void read_early_config(config_fn_t cb, void *data)
opts.respect_includes = 1;
- if (have_git_dir()) {
- opts.commondir = get_git_common_dir();
- opts.git_dir = get_git_dir();
+ if (repo && repo->gitdir) {
+ opts.commondir = repo_get_common_dir(repo);
+ opts.git_dir = repo_get_git_dir(repo);
/*
* When setup_git_directory() was not yet asked to discover the
* GIT_DIR, we ask discover_git_directory() to figure out whether there
@@ -2314,10 +2209,6 @@ void read_early_config(config_fn_t cb, void *data)
strbuf_release(&gitdir);
}
-/*
- * Read config but only enumerate system and global settings.
- * Omit any repo-local, worktree-local, or command-line settings.
- */
void read_very_early_config(config_fn_t cb, void *data)
{
struct config_options opts = { 0 };
@@ -2521,7 +2412,7 @@ int git_configset_get_string(struct config_set *set, const char *key, char **des
{
const char *value;
if (!git_configset_get_value(set, key, &value, NULL))
- return git_config_string((const char **)dest, key, value);
+ return git_config_string(dest, key, value);
else
return 1;
}
@@ -2599,7 +2490,7 @@ int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *d
return 1;
}
-int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
+int git_configset_get_pathname(struct config_set *set, const char *key, char **dest)
{
const char *value;
if (!git_configset_get_value(set, key, &value, NULL))
@@ -2646,7 +2537,7 @@ static void git_config_check_init(struct repository *repo)
repo_read_config(repo);
}
-static void repo_config_clear(struct repository *repo)
+void repo_config_clear(struct repository *repo)
{
if (!repo->config || !repo->config->hash_initialized)
return;
@@ -2693,7 +2584,7 @@ int repo_config_get_string(struct repository *repo,
git_config_check_init(repo);
ret = git_configset_get_string(repo->config, key, dest);
if (ret < 0)
- git_die_config(key, NULL);
+ git_die_config(repo, key, NULL);
return ret;
}
@@ -2704,7 +2595,7 @@ int repo_config_get_string_tmp(struct repository *repo,
git_config_check_init(repo);
ret = git_configset_get_string_tmp(repo->config, key, dest);
if (ret < 0)
- git_die_config(key, NULL);
+ git_die_config(repo, key, NULL);
return ret;
}
@@ -2744,13 +2635,13 @@ int repo_config_get_maybe_bool(struct repository *repo,
}
int repo_config_get_pathname(struct repository *repo,
- const char *key, const char **dest)
+ const char *key, char **dest)
{
int ret;
git_config_check_init(repo);
ret = git_configset_get_pathname(repo->config, key, dest);
if (ret < 0)
- git_die_config(key, NULL);
+ git_die_config(repo, key, NULL);
return ret;
}
@@ -2776,98 +2667,28 @@ void git_protected_config(config_fn_t fn, void *data)
configset_iter(&protected_config, fn, data);
}
-/* Functions used historically to read configuration from 'the_repository' */
-void git_config(config_fn_t fn, void *data)
-{
- repo_config(the_repository, fn, data);
-}
-
-void git_config_clear(void)
-{
- repo_config_clear(the_repository);
-}
-
-int git_config_get(const char *key)
-{
- return repo_config_get(the_repository, key);
-}
-
-int git_config_get_value(const char *key, const char **value)
+int repo_config_get_expiry(struct repository *r, const char *key, char **output)
{
- return repo_config_get_value(the_repository, key, value);
-}
+ int ret = repo_config_get_string(r, key, output);
-int git_config_get_value_multi(const char *key, const struct string_list **dest)
-{
- return repo_config_get_value_multi(the_repository, key, dest);
-}
-
-int git_config_get_string_multi(const char *key,
- const struct string_list **dest)
-{
- return repo_config_get_string_multi(the_repository, key, dest);
-}
-
-int git_config_get_string(const char *key, char **dest)
-{
- return repo_config_get_string(the_repository, key, dest);
-}
-
-int git_config_get_string_tmp(const char *key, const char **dest)
-{
- return repo_config_get_string_tmp(the_repository, key, dest);
-}
-
-int git_config_get_int(const char *key, int *dest)
-{
- return repo_config_get_int(the_repository, key, dest);
-}
-
-int git_config_get_ulong(const char *key, unsigned long *dest)
-{
- return repo_config_get_ulong(the_repository, key, dest);
-}
-
-int git_config_get_bool(const char *key, int *dest)
-{
- return repo_config_get_bool(the_repository, key, dest);
-}
-
-int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
-{
- return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
-}
-
-int git_config_get_maybe_bool(const char *key, int *dest)
-{
- return repo_config_get_maybe_bool(the_repository, key, dest);
-}
-
-int git_config_get_pathname(const char *key, const char **dest)
-{
- return repo_config_get_pathname(the_repository, key, dest);
-}
-
-int git_config_get_expiry(const char *key, const char **output)
-{
- int ret = git_config_get_string(key, (char **)output);
if (ret)
return ret;
if (strcmp(*output, "now")) {
timestamp_t now = approxidate("now");
if (approxidate(*output) >= now)
- git_die_config(key, _("Invalid %s: '%s'"), key, *output);
+ git_die_config(r, key, _("Invalid %s: '%s'"), key, *output);
}
return ret;
}
-int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestamp_t now)
+int repo_config_get_expiry_in_days(struct repository *r, const char *key,
+ timestamp_t *expiry, timestamp_t now)
{
const char *expiry_string;
intmax_t days;
timestamp_t when;
- if (git_config_get_string_tmp(key, &expiry_string))
+ if (repo_config_get_string_tmp(r, key, &expiry_string))
return 1; /* no such thing */
if (git_parse_signed(expiry_string, &days, maximum_signed_value_of_type(int))) {
@@ -2883,21 +2704,21 @@ int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestam
return -1; /* thing exists but cannot be parsed */
}
-int git_config_get_split_index(void)
+int repo_config_get_split_index(struct repository *r)
{
int val;
- if (!git_config_get_maybe_bool("core.splitindex", &val))
+ if (!repo_config_get_maybe_bool(r, "core.splitindex", &val))
return val;
return -1; /* default value */
}
-int git_config_get_max_percent_split_change(void)
+int repo_config_get_max_percent_split_change(struct repository *r)
{
int val = -1;
- if (!git_config_get_int("splitindex.maxpercentchange", &val)) {
+ if (!repo_config_get_int(r, "splitindex.maxpercentchange", &val)) {
if (0 <= val && val <= 100)
return val;
@@ -2908,7 +2729,7 @@ int git_config_get_max_percent_split_change(void)
return -1; /* default value */
}
-int git_config_get_index_threads(int *dest)
+int repo_config_get_index_threads(struct repository *r, int *dest)
{
int is_bool, val;
@@ -2918,7 +2739,7 @@ int git_config_get_index_threads(int *dest)
return 0;
}
- if (!git_config_get_bool_or_int("index.threads", &is_bool, &val)) {
+ if (!repo_config_get_bool_or_int(r, "index.threads", &is_bool, &val)) {
if (is_bool)
*dest = val ? 0 : 1;
else
@@ -2939,8 +2760,7 @@ void git_die_config_linenr(const char *key, const char *filename, int linenr)
key, filename, linenr);
}
-NORETURN __attribute__((format(printf, 2, 3)))
-void git_die_config(const char *key, const char *err, ...)
+void git_die_config(struct repository *r, const char *key, const char *err, ...)
{
const struct string_list *values;
struct key_value_info *kv_info;
@@ -2952,7 +2772,7 @@ void git_die_config(const char *key, const char *err, ...)
error_fn(err, params);
va_end(params);
}
- if (git_config_get_value_multi(key, &values))
+ if (repo_config_get_value_multi(r, key, &values))
BUG("for key '%s' we must have a value to report on", key);
kv_info = values->items[values->nr - 1].util;
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
@@ -2997,7 +2817,7 @@ static int matches(const char *key, const char *value,
{
if (strcmp(key, store->key))
return 0; /* not ours */
- if (store->fixed_value)
+ if (store->fixed_value && value)
return !strcmp(store->fixed_value, value);
if (!store->value_pattern)
return 1; /* always matches */
@@ -3128,6 +2948,7 @@ static ssize_t write_section(int fd, const char *key,
}
static ssize_t write_pair(int fd, const char *key, const char *value,
+ const char *comment,
const struct config_store_data *store)
{
int i;
@@ -3168,7 +2989,11 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
strbuf_addch(&sb, value[i]);
break;
}
- strbuf_addf(&sb, "%s\n", quote);
+
+ if (comment)
+ strbuf_addf(&sb, "%s%s\n", quote, comment);
+ else
+ strbuf_addf(&sb, "%s\n", quote);
ret = write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb);
@@ -3256,21 +3081,21 @@ static void maybe_remove_section(struct config_store_data *store,
*end_offset = store->parsed[store->parsed_nr - 1].end;
}
-int git_config_set_in_file_gently(const char *config_filename,
- const char *key, const char *value)
+int repo_config_set_in_file_gently(struct repository *r, const char *config_filename,
+ const char *key, const char *comment, const char *value)
{
- return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
+ return repo_config_set_multivar_in_file_gently(r, config_filename, key, value, NULL, comment, 0);
}
-void git_config_set_in_file(const char *config_filename,
- const char *key, const char *value)
+void repo_config_set_in_file(struct repository *r, const char *config_filename,
+ const char *key, const char *value)
{
- git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+ repo_config_set_multivar_in_file(r, config_filename, key, value, NULL, 0);
}
-int git_config_set_gently(const char *key, const char *value)
+int repo_config_set_gently(struct repository *r, const char *key, const char *value)
{
- return git_config_set_multivar_gently(key, value, NULL, 0);
+ return repo_config_set_multivar_gently(r, key, value, NULL, 0);
}
int repo_config_set_worktree_gently(struct repository *r,
@@ -3279,21 +3104,73 @@ int repo_config_set_worktree_gently(struct repository *r,
/* Only use worktree-specific config if it is already enabled. */
if (r->repository_format_worktree_config) {
char *file = repo_git_path(r, "config.worktree");
- int ret = git_config_set_multivar_in_file_gently(
- file, key, value, NULL, 0);
+ int ret = repo_config_set_multivar_in_file_gently(
+ r, file, key, value, NULL, NULL, 0);
free(file);
return ret;
}
return repo_config_set_multivar_gently(r, key, value, NULL, 0);
}
-void git_config_set(const char *key, const char *value)
+void repo_config_set(struct repository *r, const char *key, const char *value)
{
- git_config_set_multivar(key, value, NULL, 0);
+ repo_config_set_multivar(r, key, value, NULL, 0);
trace2_cmd_set_config(key, value);
}
+char *git_config_prepare_comment_string(const char *comment)
+{
+ size_t leading_blanks;
+ char *prepared;
+
+ if (!comment)
+ return NULL;
+
+ if (strchr(comment, '\n'))
+ die(_("no multi-line comment allowed: '%s'"), comment);
+
+ /*
+ * If it begins with one or more leading whitespace characters
+ * followed by '#", the comment string is used as-is.
+ *
+ * If it begins with '#', a SP is inserted between the comment
+ * and the value the comment is about.
+ *
+ * Otherwise, the value is followed by a SP followed by '#'
+ * followed by SP and then the comment string comes.
+ */
+
+ leading_blanks = strspn(comment, " \t");
+ if (leading_blanks && comment[leading_blanks] == '#')
+ prepared = xstrdup(comment); /* use it as-is */
+ else if (comment[0] == '#')
+ prepared = xstrfmt(" %s", comment);
+ else
+ prepared = xstrfmt(" # %s", comment);
+
+ return prepared;
+}
+
+static void validate_comment_string(const char *comment)
+{
+ size_t leading_blanks;
+
+ if (!comment)
+ return;
+ /*
+ * The front-end must have massaged the comment string
+ * properly before calling us.
+ */
+ if (strchr(comment, '\n'))
+ BUG("multi-line comments are not permitted: '%s'", comment);
+
+ leading_blanks = strspn(comment, " \t");
+ if (!leading_blanks || comment[leading_blanks] != '#')
+ BUG("comment must begin with one or more SP followed by '#': '%s'",
+ comment);
+}
+
/*
* If value==NULL, unset in (remove from) config,
* if value_pattern!=NULL, disregard key/value pairs where value does not match.
@@ -3319,10 +3196,12 @@ void git_config_set(const char *key, const char *value)
* - the config file is removed and the lock file rename()d to it.
*
*/
-int git_config_set_multivar_in_file_gently(const char *config_filename,
- const char *key, const char *value,
- const char *value_pattern,
- unsigned flags)
+int repo_config_set_multivar_in_file_gently(struct repository *r,
+ const char *config_filename,
+ const char *key, const char *value,
+ const char *value_pattern,
+ const char *comment,
+ unsigned flags)
{
int fd = -1, in_fd = -1;
int ret;
@@ -3332,6 +3211,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
size_t contents_sz;
struct config_store_data store = CONFIG_STORE_INIT;
+ validate_comment_string(comment);
+
/* parse-key returns negative; flip the sign to feed exit(3) */
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
if (ret)
@@ -3340,7 +3221,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
store.multi_replace = (flags & CONFIG_FLAGS_MULTI_REPLACE) != 0;
if (!config_filename)
- config_filename = filename_buf = git_pathdup("config");
+ config_filename = filename_buf = repo_git_path(r, "config");
/*
* The lock serves a purpose in addition to locking: the new
@@ -3372,7 +3253,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
free(store.key);
store.key = xstrdup(key);
if (write_section(fd, key, &store) < 0 ||
- write_pair(fd, key, value, &store) < 0)
+ write_pair(fd, key, value, comment, &store) < 0)
goto write_err_out;
} else {
struct stat st;
@@ -3526,7 +3407,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
if (write_section(fd, key, &store) < 0)
goto write_err_out;
}
- if (write_pair(fd, key, value, &store) < 0)
+ if (write_pair(fd, key, value, comment, &store) < 0)
goto write_err_out;
}
@@ -3549,7 +3430,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
ret = 0;
/* Invalidate the config cache */
- git_config_clear();
+ repo_config_clear(r);
out_free:
rollback_lock_file(&lock);
@@ -3564,15 +3445,15 @@ out_free:
write_err_out:
ret = write_error(get_lock_file_path(&lock));
goto out_free;
-
}
-void git_config_set_multivar_in_file(const char *config_filename,
- const char *key, const char *value,
- const char *value_pattern, unsigned flags)
+void repo_config_set_multivar_in_file(struct repository *r,
+ const char *config_filename,
+ const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
{
- if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
- value_pattern, flags))
+ if (!repo_config_set_multivar_in_file_gently(r, config_filename, key, value,
+ value_pattern, NULL, flags))
return;
if (value)
die(_("could not set '%s' to '%s'"), key, value);
@@ -3580,32 +3461,27 @@ void git_config_set_multivar_in_file(const char *config_filename,
die(_("could not unset '%s'"), key);
}
-int git_config_set_multivar_gently(const char *key, const char *value,
- const char *value_pattern, unsigned flags)
-{
- return repo_config_set_multivar_gently(the_repository, key, value,
- value_pattern, flags);
-}
-
int repo_config_set_multivar_gently(struct repository *r, const char *key,
const char *value,
const char *value_pattern, unsigned flags)
{
char *file = repo_git_path(r, "config");
- int res = git_config_set_multivar_in_file_gently(file,
- key, value,
- value_pattern,
- flags);
+ int res = repo_config_set_multivar_in_file_gently(r, file,
+ key, value,
+ value_pattern,
+ NULL, flags);
free(file);
return res;
}
-void git_config_set_multivar(const char *key, const char *value,
- const char *value_pattern, unsigned flags)
+void repo_config_set_multivar(struct repository *r,
+ const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
{
- git_config_set_multivar_in_file(git_path("config"),
- key, value, value_pattern,
- flags);
+ char *file = repo_git_path(r, "config");
+ repo_config_set_multivar_in_file(r, file, key, value,
+ value_pattern, flags);
+ free(file);
}
static size_t section_name_match (const char *buf, const char *name)
@@ -3667,9 +3543,11 @@ static int section_name_is_ok(const char *name)
#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
/* if new_name == NULL, the section is removed instead */
-static int git_config_copy_or_rename_section_in_file(const char *config_filename,
- const char *old_name,
- const char *new_name, int copy)
+static int repo_config_copy_or_rename_section_in_file(
+ struct repository *r,
+ const char *config_filename,
+ const char *old_name,
+ const char *new_name, int copy)
{
int ret = 0, remove = 0;
char *filename_buf = NULL;
@@ -3690,7 +3568,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
}
if (!config_filename)
- config_filename = filename_buf = git_pathdup("config");
+ config_filename = filename_buf = repo_git_path(r, "config");
out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
if (out_fd < 0) {
@@ -3833,28 +3711,28 @@ out_no_rollback:
return ret;
}
-int git_config_rename_section_in_file(const char *config_filename,
- const char *old_name, const char *new_name)
+int repo_config_rename_section_in_file(struct repository *r, const char *config_filename,
+ const char *old_name, const char *new_name)
{
- return git_config_copy_or_rename_section_in_file(config_filename,
+ return repo_config_copy_or_rename_section_in_file(r, config_filename,
old_name, new_name, 0);
}
-int git_config_rename_section(const char *old_name, const char *new_name)
+int repo_config_rename_section(struct repository *r, const char *old_name, const char *new_name)
{
- return git_config_rename_section_in_file(NULL, old_name, new_name);
+ return repo_config_rename_section_in_file(r, NULL, old_name, new_name);
}
-int git_config_copy_section_in_file(const char *config_filename,
- const char *old_name, const char *new_name)
+int repo_config_copy_section_in_file(struct repository *r, const char *config_filename,
+ const char *old_name, const char *new_name)
{
- return git_config_copy_or_rename_section_in_file(config_filename,
+ return repo_config_copy_or_rename_section_in_file(r, config_filename,
old_name, new_name, 1);
}
-int git_config_copy_section(const char *old_name, const char *new_name)
+int repo_config_copy_section(struct repository *r, const char *old_name, const char *new_name)
{
- return git_config_copy_section_in_file(NULL, old_name, new_name);
+ return repo_config_copy_section_in_file(r, NULL, old_name, new_name);
}
/*
diff --git a/config.h b/config.h
index 6332d74904..5c730c4f89 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
#include "hashmap.h"
#include "string-list.h"
#include "repository.h"
-
+#include "parse.h"
/**
* The config API gives callers a way to access Git configuration files
@@ -26,7 +26,7 @@ struct object_id;
/* git_config_parse_key() returns these negated: */
#define CONFIG_INVALID_KEY 1
#define CONFIG_NO_SECTION_OR_NAME 2
-/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
+/* repo_config_set_gently(), repo_config_set_multivar_gently() return the above or these: */
#define CONFIG_NO_LOCK -1
#define CONFIG_INVALID_FILE 3
#define CONFIG_NO_WRITE 4
@@ -170,9 +170,9 @@ int git_default_config(const char *, const char *,
/**
* Read a specific file in git-config format.
- * This function takes the same callback and data parameters as `git_config`.
+ * This function takes the same callback and data parameters as `repo_config`.
*
- * Unlike git_config(), this function does not respect includes.
+ * Unlike repo_config(), this function does not respect includes.
*/
int git_config_from_file(config_fn_t fn, const char *, void *);
@@ -192,15 +192,26 @@ int git_config_from_blob_oid(config_fn_t fn, const char *name,
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);
-void read_early_config(config_fn_t cb, void *data);
+
+/*
+ * Read config when the Git directory has not yet been set up. In case
+ * `the_repository` has not yet been set up, try to discover the Git
+ * directory to read the configuration from.
+ */
+void read_early_config(struct repository *repo, config_fn_t cb, void *data);
+
+/*
+ * Read config but only enumerate system and global settings.
+ * Omit any repo-local, worktree-local, or command-line settings.
+ */
void read_very_early_config(config_fn_t cb, void *data);
/**
* Most programs will simply want to look up variables in all config files
* that Git knows about, using the normal precedence rules. To do this,
- * call `git_config` with a callback function and void data pointer.
+ * call `repo_config` with a callback function and void data pointer.
*
- * `git_config` will read all config sources in order of increasing
+ * `repo_config` will read all config sources in order of increasing
* priority. Thus a callback should typically overwrite previously-seen
* entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
* repo-specific `.git/config` contain `color.ui`, the config machinery
@@ -210,11 +221,11 @@ void read_very_early_config(config_fn_t cb, void *data);
*
* Unlike git_config_from_file(), this function respects includes.
*/
-void git_config(config_fn_t fn, void *);
+void repo_config(struct repository *r, config_fn_t fn, void *);
/**
* Lets the caller examine config while adjusting some of the default
- * behavior of `git_config`. It should almost never be used by "regular"
+ * behavior of `repo_config`. It should almost never be used by "regular"
* Git code that is looking up configuration variables.
* It is intended for advanced callers like `git-config`, which are
* intentionally tweaking the normal config-lookup process.
@@ -223,16 +234,16 @@ void git_config(config_fn_t fn, void *);
* - `config_source`
* If this parameter is non-NULL, it specifies the source to parse for
* configuration, rather than looking in the usual files. See `struct
- * git_config_source` in `config.h` for details. Regular `git_config` defaults
+ * git_config_source` in `config.h` for details. Regular `repo_config` defaults
* to `NULL`.
*
* - `opts`
* Specify options to adjust the behavior of parsing config files. See `struct
- * config_options` in `config.h` for details. As an example: regular `git_config`
+ * config_options` in `config.h` for details. As an example: regular `repo_config`
* sets `opts.respect_includes` to `1` by default.
*/
int config_with_options(config_fn_t fn, void *,
- struct git_config_source *config_source,
+ const struct git_config_source *config_source,
struct repository *repo,
const struct config_options *opts);
@@ -243,16 +254,6 @@ int config_with_options(config_fn_t fn, void *,
* The following helper functions aid in parsing string values
*/
-int git_parse_ssize_t(const char *, ssize_t *);
-int git_parse_ulong(const char *, unsigned long *);
-int git_parse_int(const char *value, int *ret);
-
-/**
- * Same as `git_config_bool`, except that it returns -1 on error rather
- * than dying.
- */
-int git_parse_maybe_bool(const char *);
-
/**
* Parse the string to an integer, including unit factors. Dies on error;
* otherwise, returns the parsed result.
@@ -272,6 +273,13 @@ ssize_t git_config_ssize_t(const char *, const char *,
const struct key_value_info *);
/**
+ * Identically to `git_config_double`, but for double-precision floating point
+ * values.
+ */
+double git_config_double(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.
*/
@@ -290,25 +298,26 @@ int git_config_bool(const char *, const char *);
* Allocates and copies the value string into the `dest` parameter; if no
* string is given, prints an error message and returns -1.
*/
-int git_config_string(const char **, const char *, const char *);
+int git_config_string(char **, const char *, const char *);
/**
* Similar to `git_config_string`, but expands `~` or `~user` into the
* user's home directory when found at the beginning of the path.
*/
-int git_config_pathname(const char **, const char *, const char *);
+int git_config_pathname(char **, const char *, const char *);
int git_config_expiry_date(timestamp_t *, const char *, const char *);
int git_config_color(char *, const char *, const char *);
-int git_config_set_in_file_gently(const char *, const char *, const char *);
+int repo_config_set_in_file_gently(struct repository *r, const char *config_filename,
+ const char *key, const char *comment, const char *value);
/**
* write config values to a specific config file, takes a key/value pair as
* parameter.
*/
-void git_config_set_in_file(const char *, const char *, const char *);
+void repo_config_set_in_file(struct repository *, const char *, const char *, const char *);
-int git_config_set_gently(const char *, const char *);
+int repo_config_set_gently(struct repository *r, const char *, const char *);
/**
* Write a config value that should apply to the current worktree. If
@@ -320,13 +329,13 @@ int repo_config_set_worktree_gently(struct repository *, const char *, const cha
/**
* write config values to `.git/config`, takes a key/value pair as parameter.
*/
-void git_config_set(const char *, const char *);
+void repo_config_set(struct repository *, const char *, const char *);
int git_config_parse_key(const char *, char **, size_t *);
/*
* The following macros specify flag bits that alter the behavior
- * of the git_config_set_multivar*() methods.
+ * of the repo_config_set_multivar*() methods.
*/
/*
@@ -343,10 +352,11 @@ int git_config_parse_key(const char *, char **, size_t *);
*/
#define CONFIG_FLAGS_FIXED_VALUE (1 << 1)
-int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
-void git_config_set_multivar(const char *, const char *, const char *, unsigned);
int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned);
-int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, unsigned);
+void repo_config_set_multivar(struct repository *r, const char *, const char *, const char *, unsigned);
+int repo_config_set_multivar_in_file_gently(struct repository *, const char *, const char *, const char *, const char *, const char *, unsigned);
+
+char *git_config_prepare_comment_string(const char *);
/**
* takes four parameters:
@@ -368,11 +378,12 @@ int git_config_set_multivar_in_file_gently(const char *, const char *, const cha
*
* It returns 0 on success.
*/
-void git_config_set_multivar_in_file(const char *config_filename,
- const char *key,
- const char *value,
- const char *value_pattern,
- unsigned flags);
+void repo_config_set_multivar_in_file(struct repository *r,
+ const char *config_filename,
+ const char *key,
+ const char *value,
+ const char *value_pattern,
+ unsigned flags);
/**
* rename or remove sections in the config file
@@ -380,13 +391,11 @@ void git_config_set_multivar_in_file(const char *config_filename,
* If NULL is passed through `new_name` parameter,
* the section will be removed from the config file.
*/
-int git_config_rename_section(const char *, const char *);
+int repo_config_rename_section(struct repository *, const char *, const char *);
-int git_config_rename_section_in_file(const char *, const char *, const char *);
-int git_config_copy_section(const char *, const char *);
-int git_config_copy_section_in_file(const char *, const char *, const char *);
-int git_env_bool(const char *, int);
-unsigned long git_env_ulong(const char *, unsigned long);
+int repo_config_rename_section_in_file(struct repository *, const char *, const char *, const char *);
+int repo_config_copy_section(struct repository *, const char *, const char *);
+int repo_config_copy_section_in_file(struct repository *, const char *, const char *, const char *);
int git_config_system(void);
int config_error_nonbool(const char *);
#if defined(__GNUC__)
@@ -394,7 +403,8 @@ int config_error_nonbool(const char *);
#endif
char *git_system_config(void);
-void git_global_config(char **user, char **xdg);
+char *git_global_config(void);
+void git_global_config_paths(char **user, char **xdg);
int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
@@ -550,43 +560,15 @@ int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned lon
int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
-int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
-
-/* Functions for reading a repository's config */
-struct repository;
-void repo_config(struct repository *repo, config_fn_t fn, void *data);
+int git_configset_get_pathname(struct config_set *cs, const char *key, char **dest);
/**
* Run only the discover part of the repo_config_get_*() functions
* below, in addition to 1 if not found, returns negative values on
* error (e.g. if the key itself is invalid).
*/
-RESULT_MUST_BE_USED
-int repo_config_get(struct repository *repo, const char *key);
-int repo_config_get_value(struct repository *repo,
- const char *key, const char **value);
-RESULT_MUST_BE_USED
-int repo_config_get_value_multi(struct repository *repo, const char *key,
- const struct string_list **dest);
-RESULT_MUST_BE_USED
-int repo_config_get_string_multi(struct repository *repo, const char *key,
- const struct string_list **dest);
-int repo_config_get_string(struct repository *repo,
- const char *key, char **dest);
-int repo_config_get_string_tmp(struct repository *repo,
- const char *key, const char **dest);
-int repo_config_get_int(struct repository *repo,
- const char *key, int *dest);
-int repo_config_get_ulong(struct repository *repo,
- const char *key, unsigned long *dest);
-int repo_config_get_bool(struct repository *repo,
- const char *key, int *dest);
-int repo_config_get_bool_or_int(struct repository *repo,
- const char *key, int *is_bool, int *dest);
-int repo_config_get_maybe_bool(struct repository *repo,
- const char *key, int *dest);
int repo_config_get_pathname(struct repository *repo,
- const char *key, const char **dest);
+ const char *key, char **dest);
/*
* Functions for reading protected config. By definition, protected
@@ -600,17 +582,17 @@ void git_protected_config(config_fn_t fn, void *data);
* -------------------------------
*
* For programs wanting to query for specific variables in a non-callback
- * manner, the config API provides two functions `git_config_get_value`
- * and `git_config_get_value_multi`. They both read values from an internal
+ * manner, the config API provides two functions `repo_config_get_value`
+ * and `repo_config_get_value_multi`. They both read values from an internal
* cache generated previously from reading the config files.
*
- * For those git_config_get*() functions that aren't documented,
+ * For those repo_config_get*() functions that aren't documented,
* consult the corresponding repo_config_get*() function's
* documentation.
*/
RESULT_MUST_BE_USED
-int git_config_get(const char *key);
+int repo_config_get(struct repository *r, const char *key);
/**
* Finds the highest-priority value for the configuration variable `key`,
@@ -619,7 +601,7 @@ int git_config_get(const char *key);
* `value`. The caller should not free or modify `value`, as it is owned
* by the cache.
*/
-int git_config_get_value(const char *key, const char **value);
+int repo_config_get_value(struct repository *r, const char *key, const char **value);
/**
* Finds and returns the value list, sorted in order of increasing priority
@@ -630,16 +612,16 @@ int git_config_get_value(const char *key, const char **value);
* owned by the cache.
*/
RESULT_MUST_BE_USED
-int git_config_get_value_multi(const char *key,
- const struct string_list **dest);
-RESULT_MUST_BE_USED
-int git_config_get_string_multi(const char *key,
+int repo_config_get_value_multi(struct repository *r, const char *key,
const struct string_list **dest);
+RESULT_MUST_BE_USED
+int repo_config_get_string_multi(struct repository *r, const char *key,
+ const struct string_list **dest);
/**
* Resets and invalidates the config cache.
*/
-void git_config_clear(void);
+void repo_config_clear(struct repository *repo);
/**
* Allocates and copies the retrieved string into the `dest` parameter for
@@ -647,14 +629,15 @@ void git_config_clear(void);
* error message and returns -1. When the configuration variable `key` is
* not found, returns 1 without touching `dest`.
*/
-int git_config_get_string(const char *key, char **dest);
+int repo_config_get_string(struct repository *r, const char *key, char **dest);
/**
- * Similar to `git_config_get_string`, but does not allocate any new
+ * Similar to `repo_config_get_string`, but does not allocate any new
* memory; on success `dest` will point to memory owned by the config
* machinery, which could be invalidated if it is discarded and reloaded.
*/
-int git_config_get_string_tmp(const char *key, const char **dest);
+int repo_config_get_string_tmp(struct repository *r,
+ const char *key, const char **dest);
/**
* Finds and parses the value to an integer for the configuration variable
@@ -662,12 +645,13 @@ int git_config_get_string_tmp(const char *key, const char **dest);
* `dest` and returns 0. When the configuration variable `key` is not found,
* returns 1 without touching `dest`.
*/
-int git_config_get_int(const char *key, int *dest);
+int repo_config_get_int(struct repository *r, const char *key, int *dest);
/**
- * Similar to `git_config_get_int` but for unsigned longs.
+ * Similar to `repo_config_get_int` but for unsigned longs.
*/
-int git_config_get_ulong(const char *key, unsigned long *dest);
+int repo_config_get_ulong(struct repository *r,
+ const char *key, unsigned long *dest);
/**
* Finds and parses the value into a boolean value, for the configuration
@@ -678,47 +662,45 @@ int git_config_get_ulong(const char *key, unsigned long *dest);
* configuration variable `key` is not found, returns 1 without touching
* `dest`.
*/
-int git_config_get_bool(const char *key, int *dest);
+int repo_config_get_bool(struct repository *r, const char *key, int *dest);
/**
- * Similar to `git_config_get_bool`, except that integers are copied as-is,
+ * Similar to `repo_config_get_bool`, except that integers are copied as-is,
* and `is_bool` flag is unset.
*/
-int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+int repo_config_get_bool_or_int(struct repository *r, const char *key,
+ int *is_bool, int *dest);
/**
- * Similar to `git_config_get_bool`, except that it returns -1 on error
+ * Similar to `repo_config_get_bool`, except that it returns -1 on error
* rather than dying.
*/
-int git_config_get_maybe_bool(const char *key, int *dest);
+int repo_config_get_maybe_bool(struct repository *r,
+ const char *key, int *dest);
-/**
- * Similar to `git_config_get_string`, but expands `~` or `~user` into
- * the user's home directory when found at the beginning of the path.
- */
-int git_config_get_pathname(const char *key, const char **dest);
-
-int git_config_get_index_threads(int *dest);
-int git_config_get_split_index(void);
-int git_config_get_max_percent_split_change(void);
+int repo_config_get_index_threads(struct repository *r, int *dest);
+int repo_config_get_split_index(struct repository *r);
+int repo_config_get_max_percent_split_change(struct repository *r);
/* This dies if the configured or default date is in the future */
-int git_config_get_expiry(const char *key, const char **output);
+int repo_config_get_expiry(struct repository *r, const char *key, char **output);
/* parse either "this many days" integer, or "5.days.ago" approxidate */
-int git_config_get_expiry_in_days(const char *key, timestamp_t *, timestamp_t now);
+int repo_config_get_expiry_in_days(struct repository *r, const char *key,
+ timestamp_t *, timestamp_t now);
/**
* First prints the error message specified by the caller in `err` and then
* dies printing the line number and the file name of the highest priority
* value for the configuration variable `key`.
*/
-NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+NORETURN void git_die_config(struct repository *r, const char *key, const char *err, ...)
+ __attribute__((format(printf, 3, 4)));
/**
* Helper function which formats the die error message according to the
* parameters entered. Used by `git_die_config()`. It can be used by callers
- * handling `git_config_get_value_multi()` to print the correct error message
+ * handling `repo_config_get_value_multi()` to print the correct error message
* for the desired value.
*/
NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
@@ -727,4 +709,140 @@ NORETURN void git_die_config_linenr(const char *key, const char *filename, int l
lookup_config(mapping, ARRAY_SIZE(mapping), var)
int lookup_config(const char **mapping, int nr_mapping, const char *var);
+# ifdef USE_THE_REPOSITORY_VARIABLE
+static inline void git_config(config_fn_t fn, void *data)
+{
+ repo_config(the_repository, fn, data);
+}
+
+static inline void git_config_clear(void)
+{
+ repo_config_clear(the_repository);
+}
+
+static inline int git_config_get(const char *key)
+{
+ return repo_config_get(the_repository, key);
+}
+
+static inline int git_config_get_value(const char *key, const char **value)
+{
+ return repo_config_get_value(the_repository, key, value);
+}
+
+static inline int git_config_get_value_multi(const char *key, const struct string_list **dest)
+{
+ return repo_config_get_value_multi(the_repository, key, dest);
+}
+
+static inline int git_config_get_string_multi(const char *key,
+ const struct string_list **dest)
+{
+ return repo_config_get_string_multi(the_repository, key, dest);
+}
+
+static inline int git_config_get_string(const char *key, char **dest)
+{
+ return repo_config_get_string(the_repository, key, dest);
+}
+
+static inline int git_config_get_string_tmp(const char *key, const char **dest)
+{
+ return repo_config_get_string_tmp(the_repository, key, dest);
+}
+
+static inline int git_config_get_int(const char *key, int *dest)
+{
+ return repo_config_get_int(the_repository, key, dest);
+}
+
+static inline int git_config_get_ulong(const char *key, unsigned long *dest)
+{
+ return repo_config_get_ulong(the_repository, key, dest);
+}
+
+static inline int git_config_get_bool(const char *key, int *dest)
+{
+ return repo_config_get_bool(the_repository, key, dest);
+}
+
+static inline int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
+{
+ return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
+}
+
+static inline int git_config_get_maybe_bool(const char *key, int *dest)
+{
+ return repo_config_get_maybe_bool(the_repository, key, dest);
+}
+
+static inline int git_config_get_pathname(const char *key, char **dest)
+{
+ return repo_config_get_pathname(the_repository, key, dest);
+}
+
+static inline void git_config_set_in_file(const char *config_filename,
+ const char *key, const char *value)
+{
+ repo_config_set_in_file(the_repository, config_filename, key, value);
+}
+
+static inline int git_config_set_gently(const char *key, const char *value)
+{
+ return repo_config_set_gently(the_repository, key, value);
+}
+
+static inline void git_config_set(const char *key, const char *value)
+{
+ repo_config_set(the_repository, key, value);
+}
+
+static inline int git_config_set_in_file_gently(
+ const char *config_filename,
+ const char *key,
+ const char *comment,
+ const char *value)
+{
+ return repo_config_set_in_file_gently(the_repository, config_filename,
+ key, comment, value);
+}
+
+static inline int git_config_set_multivar_in_file_gently(
+ const char *config_filename,
+ const char *key, const char *value,
+ const char *value_pattern,
+ const char *comment,
+ unsigned flags)
+{
+ return repo_config_set_multivar_in_file_gently(the_repository, config_filename,
+ key, value, value_pattern,
+ comment, flags);
+}
+
+static inline void git_config_set_multivar_in_file(
+ const char *config_filename,
+ const char *key,
+ const char *value,
+ const char *value_pattern,
+ unsigned flags)
+{
+ repo_config_set_multivar_in_file(the_repository, config_filename,
+ key, value, value_pattern, flags);
+}
+
+static inline int git_config_set_multivar_gently(const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
+{
+ return repo_config_set_multivar_gently(the_repository, key, value,
+ value_pattern, flags);
+}
+
+static inline void git_config_set_multivar(const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
+{
+ repo_config_set_multivar(the_repository, key, value,
+ value_pattern, flags);
+}
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+
#endif /* CONFIG_H */
diff --git a/config.mak.dev b/config.mak.dev
index 981304727c..8eca7fa228 100644
--- a/config.mak.dev
+++ b/config.mak.dev
@@ -10,7 +10,7 @@ endif
DEVELOPER_CFLAGS += -Wall
ifeq ($(filter no-pedantic,$(DEVOPTS)),)
DEVELOPER_CFLAGS += -pedantic
-ifneq (($or $(filter gcc5,$(COMPILER_FEATURES)),$(filter clang4,$(COMPILER_FEATURES))),)
+ifneq ($(or $(filter gcc5,$(COMPILER_FEATURES)),$(filter clang4,$(COMPILER_FEATURES))),)
DEVELOPER_CFLAGS += -Wpedantic
ifneq ($(filter gcc10,$(COMPILER_FEATURES)),)
ifeq ($(uname_S),MINGW)
@@ -37,6 +37,7 @@ DEVELOPER_CFLAGS += -Wpointer-arith
DEVELOPER_CFLAGS += -Wstrict-prototypes
DEVELOPER_CFLAGS += -Wunused
DEVELOPER_CFLAGS += -Wvla
+DEVELOPER_CFLAGS += -Wwrite-strings
DEVELOPER_CFLAGS += -fno-common
ifneq ($(filter clang4,$(COMPILER_FEATURES)),)
@@ -53,7 +54,6 @@ ifeq ($(filter extra-all,$(DEVOPTS)),)
DEVELOPER_CFLAGS += -Wno-empty-body
DEVELOPER_CFLAGS += -Wno-missing-field-initializers
DEVELOPER_CFLAGS += -Wno-sign-compare
-DEVELOPER_CFLAGS += -Wno-unused-parameter
endif
endif
@@ -69,7 +69,7 @@ DEVELOPER_CFLAGS += -Wno-missing-braces
endif
endif
-# Old versions of clang complain about initializaing a
+# Old versions of clang complain about initializing a
# struct-within-a-struct using just "{0}" rather than "{{0}}". This
# error is considered a false-positive and not worth fixing, because
# new clang versions do not, so just disable it.
diff --git a/config.mak.uname b/config.mak.uname
index 3bb03f423a..d5112168a4 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -8,7 +8,6 @@ uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
-uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
ifneq ($(findstring MINGW,$(uname_S)),)
@@ -65,9 +64,10 @@ ifeq ($(uname_S),Linux)
HAVE_PLATFORM_PROCINFO = YesPlease
COMPAT_OBJS += compat/linux/procinfo.o
# centos7/rhel7 provides gcc 4.8.5 and zlib 1.2.7.
- ifneq ($(findstring .el7.,$(uname_R)),)
+ ifneq ($(findstring .el7.,$(uname_R)),)
BASIC_CFLAGS += -std=c99
- endif
+ endif
+ LINK_FUZZ_PROGRAMS = YesPlease
endif
ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_ALLOCA_H = YesPlease
@@ -95,13 +95,13 @@ ifeq ($(uname_S),UnixWare)
NO_MEMMEM = YesPlease
endif
ifeq ($(uname_S),SCO_SV)
- ifeq ($(uname_R),3.2)
+ ifeq ($(uname_R),3.2)
CFLAGS = -O2
- endif
- ifeq ($(uname_R),5)
+ endif
+ ifeq ($(uname_R),5)
CC = cc
BASIC_CFLAGS += -Kthread
- endif
+ endif
NEEDS_SOCKET = YesPlease
NEEDS_NSL = YesPlease
NEEDS_SSL_WITH_CRYPTO = YesPlease
@@ -124,19 +124,19 @@ ifeq ($(uname_S),Darwin)
# - MacOS 10.0.* and MacOS 10.1.0 = Darwin 1.*
# - MacOS 10.x.* = Darwin (x+4).* for (1 <= x)
# i.e. "begins with [15678] and a dot" means "10.4.* or older".
- ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2)
+ ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2)
OLD_ICONV = UnfortunatelyYes
NO_APPLE_COMMON_CRYPTO = YesPlease
- endif
- ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
+ endif
+ ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
NO_STRLCPY = YesPlease
- endif
- ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 11 && echo 1),1)
+ endif
+ ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 11 && echo 1),1)
HAVE_GETDELIM = YesPlease
- endif
- ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 20 && echo 1),1)
+ endif
+ ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 20 && echo 1),1)
OPEN_RETURNS_EINTR = UnfortunatelyYes
- endif
+ endif
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
HAVE_DEV_TTY = YesPlease
@@ -152,22 +152,35 @@ ifeq ($(uname_S),Darwin)
# Workaround for `gettext` being keg-only and not even being linked via
# `brew link --force gettext`, should be obsolete as of
# https://github.com/Homebrew/homebrew-core/pull/53489
- ifeq ($(shell test -d /usr/local/opt/gettext/ && echo y),y)
+ ifeq ($(shell test -d /usr/local/opt/gettext/ && echo y),y)
BASIC_CFLAGS += -I/usr/local/include -I/usr/local/opt/gettext/include
BASIC_LDFLAGS += -L/usr/local/lib -L/usr/local/opt/gettext/lib
- ifeq ($(shell test -x /usr/local/opt/gettext/bin/msgfmt && echo y),y)
+ ifeq ($(shell test -x /usr/local/opt/gettext/bin/msgfmt && echo y),y)
MSGFMT = /usr/local/opt/gettext/bin/msgfmt
- endif
- endif
+ endif
+ # On newer ARM-based machines the default installation path has changed to
+ # /opt/homebrew. Include it in our search paths so that the user does not
+ # have to configure this manually.
+ #
+ # Note that we do not employ the same workaround as above where we manually
+ # add gettext. The issue was fixed more than three years ago by now, and at
+ # that point there haven't been any ARM-based Macs yet.
+ else ifeq ($(shell test -d /opt/homebrew/ && echo y),y)
+ BASIC_CFLAGS += -I/opt/homebrew/include
+ BASIC_LDFLAGS += -L/opt/homebrew/lib
+ ifeq ($(shell test -x /opt/homebrew/bin/msgfmt && echo y),y)
+ MSGFMT = /opt/homebrew/bin/msgfmt
+ endif
+ endif
# The builtin FSMonitor on MacOS builds upon Simple-IPC. Both require
# Unix domain sockets and PThreads.
- ifndef NO_PTHREADS
- ifndef NO_UNIX_SOCKETS
+ ifndef NO_PTHREADS
+ ifndef NO_UNIX_SOCKETS
FSMONITOR_DAEMON_BACKEND = darwin
FSMONITOR_OS_SETTINGS = darwin
- endif
- endif
+ endif
+ endif
BASIC_LDFLAGS += -framework CoreServices
endif
@@ -183,7 +196,7 @@ ifeq ($(uname_S),SunOS)
NO_REGEX = YesPlease
NO_MSGFMT_EXTENDED_OPTIONS = YesPlease
HAVE_DEV_TTY = YesPlease
- ifeq ($(uname_R),5.6)
+ ifeq ($(uname_R),5.6)
SOCKLEN_T = int
NO_HSTRERROR = YesPlease
NO_IPV6 = YesPlease
@@ -193,8 +206,8 @@ ifeq ($(uname_S),SunOS)
NO_STRLCPY = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
- endif
- ifeq ($(uname_R),5.7)
+ endif
+ ifeq ($(uname_R),5.7)
NEEDS_RESOLV = YesPlease
NO_IPV6 = YesPlease
NO_SOCKADDR_STORAGE = YesPlease
@@ -203,25 +216,25 @@ ifeq ($(uname_S),SunOS)
NO_STRLCPY = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
- endif
- ifeq ($(uname_R),5.8)
+ endif
+ ifeq ($(uname_R),5.8)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
- endif
- ifeq ($(uname_R),5.9)
+ endif
+ ifeq ($(uname_R),5.9)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
- endif
+ endif
INSTALL = /usr/ucb/install
TAR = gtar
BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__
endif
ifeq ($(uname_O),Cygwin)
- ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
+ ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
NO_D_TYPE_IN_DIRENT = YesPlease
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
@@ -232,9 +245,10 @@ ifeq ($(uname_O),Cygwin)
# On some boxes NO_MMAP is needed, and not so elsewhere.
# Try commenting this out if you suspect MMAP is more efficient
NO_MMAP = YesPlease
- else
+ else
NO_REGEX = UnfortunatelyYes
- endif
+ endif
+ HAVE_DEV_TTY = YesPlease
HAVE_ALLOCA_H = YesPlease
NEEDS_LIBICONV = YesPlease
NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
@@ -250,25 +264,25 @@ ifeq ($(uname_S),FreeBSD)
NEEDS_LIBICONV = YesPlease
# Versions up to 10.1 require OLD_ICONV; 10.2 and beyond don't.
# A typical version string looks like "10.2-RELEASE".
- ifeq ($(shell expr "$(uname_R)" : '[1-9]\.'),2)
+ ifeq ($(shell expr "$(uname_R)" : '[1-9]\.'),2)
OLD_ICONV = YesPlease
- endif
- ifeq ($(firstword $(subst -, ,$(uname_R))),10.0)
+ endif
+ ifeq ($(firstword $(subst -, ,$(uname_R))),10.0)
OLD_ICONV = YesPlease
- endif
- ifeq ($(firstword $(subst -, ,$(uname_R))),10.1)
+ endif
+ ifeq ($(firstword $(subst -, ,$(uname_R))),10.1)
OLD_ICONV = YesPlease
- endif
+ endif
NO_MEMMEM = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
USE_ST_TIMESPEC = YesPlease
- ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
+ ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
PTHREAD_LIBS = -pthread
NO_UINTMAX_T = YesPlease
NO_STRTOUMAX = YesPlease
- endif
+ endif
PYTHON_PATH = /usr/local/bin/python
PERL_PATH = /usr/local/bin/perl
HAVE_PATHS_H = YesPlease
@@ -304,9 +318,9 @@ ifeq ($(uname_S),MirBSD)
CSPRNG_METHOD = arc4random
endif
ifeq ($(uname_S),NetBSD)
- ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
+ ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
NEEDS_LIBICONV = YesPlease
- endif
+ endif
BASIC_CFLAGS += -I/usr/pkg/include
BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
USE_ST_TIMESPEC = YesPlease
@@ -330,14 +344,14 @@ ifeq ($(uname_S),AIX)
BASIC_CFLAGS += -D_LARGE_FILES
FILENO_IS_A_MACRO = UnfortunatelyYes
NEED_ACCESS_ROOT_HANDLER = UnfortunatelyYes
- ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
+ ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
NO_PTHREADS = YesPlease
- else
+ else
PTHREAD_LIBS = -lpthread
- endif
- ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3)
+ endif
+ ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3)
INLINE = ''
- endif
+ endif
GIT_TEST_CMP = cmp
endif
ifeq ($(uname_S),GNU)
@@ -397,29 +411,29 @@ ifeq ($(uname_S),HP-UX)
NO_SYS_SELECT_H = YesPlease
SNPRINTF_RETURNS_BOGUS = YesPlease
NO_NSEC = YesPlease
- ifeq ($(uname_R),B.11.00)
+ ifeq ($(uname_R),B.11.00)
NO_INET_NTOP = YesPlease
NO_INET_PTON = YesPlease
- endif
- ifeq ($(uname_R),B.10.20)
+ endif
+ ifeq ($(uname_R),B.10.20)
# Override HP-UX 11.x setting:
INLINE =
SOCKLEN_T = size_t
NO_PREAD = YesPlease
NO_INET_NTOP = YesPlease
NO_INET_PTON = YesPlease
- endif
+ endif
GIT_TEST_CMP = cmp
endif
ifeq ($(uname_S),Windows)
GIT_VERSION := $(GIT_VERSION).MSVC
pathsep = ;
# Assume that this is built in Git for Windows' SDK
- ifeq (MINGW32,$(MSYSTEM))
+ ifeq (MINGW32,$(MSYSTEM))
prefix = /mingw32
- else
+ else
prefix = /mingw64
- endif
+ endif
# Prepend MSVC 64-bit tool-chain to PATH.
#
# A regular Git Bash *does not* have cl.exe in its $PATH. As there is a
@@ -434,7 +448,6 @@ ifeq ($(uname_S),Windows)
NO_POLL = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_IPV6 = YesPlease
- NO_UNIX_SOCKETS = YesPlease
NO_SETENV = YesPlease
NO_STRCASESTR = YesPlease
NO_STRLCPY = YesPlease
@@ -537,16 +550,16 @@ ifeq ($(uname_S),Interix)
NO_MKDTEMP = YesPlease
NO_STRTOUMAX = YesPlease
NO_NSEC = YesPlease
- ifeq ($(uname_R),3.5)
+ ifeq ($(uname_R),3.5)
NO_INET_NTOP = YesPlease
NO_INET_PTON = YesPlease
NO_SOCKADDR_STORAGE = YesPlease
- endif
- ifeq ($(uname_R),5.2)
+ endif
+ ifeq ($(uname_R),5.2)
NO_INET_NTOP = YesPlease
NO_INET_PTON = YesPlease
NO_SOCKADDR_STORAGE = YesPlease
- endif
+ endif
endif
ifeq ($(uname_S),Minix)
NO_IPV6 = YesPlease
@@ -566,12 +579,12 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
# still not compile in c89 mode, due to non-const array initializations.
CC = cc -c99
# Build down-rev compatible objects that don't use our new getopt_long.
- ifeq ($(uname_R).$(uname_V),J06.21)
+ ifeq ($(uname_R).$(uname_V),J06.21)
CC += -WRVU=J06.20
- endif
- ifeq ($(uname_R).$(uname_V),L17.02)
+ endif
+ ifeq ($(uname_R).$(uname_V),L17.02)
CC += -WRVU=L16.05
- endif
+ endif
# Disable all optimization, seems to result in bad code, with -O or -O2
# or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects
# abends on "git push". Needs more investigation.
@@ -625,10 +638,23 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
SANE_TOOL_PATH = /usr/coreutils/bin:/usr/local/bin
SHELL_PATH = /usr/coreutils/bin/bash
endif
+ifeq ($(uname_S),OS/390)
+ NO_SYS_POLL_H = YesPlease
+ NO_STRCASESTR = YesPlease
+ NO_REGEX = YesPlease
+ NO_MMAP = YesPlease
+ NO_NSEC = YesPlease
+ NO_STRLCPY = YesPlease
+ NO_MEMMEM = YesPlease
+ NO_GECOS_IN_PWENT = YesPlease
+ HAVE_STRINGS_H = YesPlease
+ NEEDS_MODE_TRANSLATION = YesPlease
+ HAVE_ZOS_GET_EXECUTABLE_PATH = YesPlease
+endif
ifeq ($(uname_S),MINGW)
- ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
+ ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
$(error "Building with MSys is no longer supported")
- endif
+ endif
pathsep = ;
HAVE_ALLOCA_H = YesPlease
NO_PREAD = YesPlease
@@ -636,7 +662,6 @@ ifeq ($(uname_S),MINGW)
NO_LIBGEN_H = YesPlease
NO_POLL = YesPlease
NO_SYMLINK_HEAD = YesPlease
- NO_UNIX_SOCKETS = YesPlease
NO_SETENV = YesPlease
NO_STRCASESTR = YesPlease
NO_STRLCPY = YesPlease
@@ -687,22 +712,22 @@ ifeq ($(uname_S),MINGW)
# Enable DEP
BASIC_LDFLAGS += -Wl,--nxcompat
# Enable ASLR (unless debugging)
- ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
+ ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
BASIC_LDFLAGS += -Wl,--dynamicbase
- endif
- ifeq (MINGW32,$(MSYSTEM))
+ endif
+ ifeq (MINGW32,$(MSYSTEM))
prefix = /mingw32
HOST_CPU = i686
BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
- endif
- ifeq (MINGW64,$(MSYSTEM))
+ endif
+ ifeq (MINGW64,$(MSYSTEM))
prefix = /mingw64
HOST_CPU = x86_64
BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
- else
+ else
COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
BASIC_LDFLAGS += -Wl,--large-address-aware
- endif
+ endif
CC = gcc
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
-fstack-protector-strong
@@ -714,11 +739,11 @@ ifeq ($(uname_S),MINGW)
USE_GETTEXT_SCHEME = fallthrough
USE_LIBPCRE = YesPlease
USE_NED_ALLOCATOR = YesPlease
- ifeq (/mingw64,$(subst 32,64,$(prefix)))
+ ifeq (/mingw64,$(subst 32,64,$(prefix)))
# Move system config into top-level /etc/
ETC_GITCONFIG = ../etc/gitconfig
ETC_GITATTRIBUTES = ../etc/gitattributes
- endif
+ endif
endif
ifeq ($(uname_S),QNX)
COMPAT_CFLAGS += -DSA_RESTART=0
diff --git a/configure.ac b/configure.ac
index 276593cd9d..d1a96da14e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -94,7 +94,7 @@ AC_DEFUN([GIT_PARSE_WITH_SET_MAKE_VAR],
[AC_ARG_WITH([$1],
[AS_HELP_STRING([--with-$1=VALUE], $3)],
if test -n "$withval"; then
- if test "$withval" = "yes" -o "$withval" = "no"; then
+ if test "$withval" = "yes" || test "$withval" = "no"; then
AC_MSG_WARN([You likely do not want either 'yes' or 'no' as]
[a value for $1 ($2). Maybe you do...?])
fi
diff --git a/connect.c b/connect.c
index 0d77737a53..58f53d8dcb 100644
--- a/connect.c
+++ b/connect.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -38,8 +40,8 @@ static int check_ref(const char *name, unsigned int flags)
REFNAME_ALLOW_ONELEVEL))
return 0;
- /* REF_HEADS means that we want regular branch heads */
- if ((flags & REF_HEADS) && starts_with(name, "heads/"))
+ /* REF_BRANCHES means that we want regular branch heads */
+ if ((flags & REF_BRANCHES) && starts_with(name, "heads/"))
return 1;
/* REF_TAGS means that we want tags */
@@ -1483,6 +1485,7 @@ struct child_process *git_connect(int fd[2], const char *url,
free(hostandport);
free(path);
+ child_process_clear(conn);
free(conn);
strbuf_release(&cmd);
return NULL;
diff --git a/connected.c b/connected.c
index 8f89376dbc..a9e2e13995 100644
--- a/connected.c
+++ b/connected.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hex.h"
@@ -76,7 +78,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
for (p = get_all_packs(the_repository); p; p = p->next) {
if (!p->pack_promisor)
continue;
- if (find_pack_entry_one(oid->hash, p))
+ if (find_pack_entry_one(oid, p))
goto promisor_pack_found;
}
/*
@@ -142,7 +144,7 @@ no_promisor_pack_found:
* are sure the ref is good and not sending it to
* rev-list for verification.
*/
- if (new_pack && find_pack_entry_one(oid->hash, new_pack))
+ if (new_pack && find_pack_entry_one(oid, new_pack))
continue;
if (fprintf(rev_list_in, "%s\n", oid_to_hex(oid)) < 0)
diff --git a/contrib/README b/contrib/README
index 05f291c1f1..21d3d0e7de 100644
--- a/contrib/README
+++ b/contrib/README
@@ -23,7 +23,7 @@ This is the same way as how I have been treating gitk, and to a
lesser degree various foreign SCM interfaces, so you know the
drill.
-I expect that things that start their life in the contrib/ area
+I expect things that start their life in the contrib/ area
to graduate out of contrib/ once they mature, either by becoming
projects on their own, or moving to the toplevel directory. On
the other hand, I expect I'll be proposing removal of disused
@@ -31,7 +31,7 @@ and inactive ones from time to time.
If you have new things to add to this area, please first propose
it on the git mailing list, and after a list discussion proves
-there are some general interests (it does not have to be a
+there is general interest (it does not have to be a
list-wide consensus for a tool targeted to a relatively narrow
audience -- for example I do not work with projects whose
upstream is svn, so I have no use for git-svn myself, but it is
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 6b819e2fbd..8c71f5a1d0 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -970,16 +970,79 @@ if(BUILD_TESTING)
add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c)
target_link_libraries(test-fake-ssh common-main)
-#reftable-tests
-parse_makefile_for_sources(test-reftable_SOURCES "REFTABLE_TEST_OBJS")
-list(TRANSFORM test-reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+#unit-tests
+parse_makefile_for_sources(unit-test_SOURCES "UNIT_TEST_OBJS")
+list(TRANSFORM unit-test_SOURCES REPLACE "\\$\\(UNIT_TEST_DIR\\)/" "${CMAKE_SOURCE_DIR}/t/unit-tests/")
+add_library(unit-test-lib STATIC ${unit-test_SOURCES})
+
+parse_makefile_for_scripts(unit_test_PROGRAMS "UNIT_TEST_PROGRAMS" "")
+foreach(unit_test ${unit_test_PROGRAMS})
+ add_executable("${unit_test}" "${CMAKE_SOURCE_DIR}/t/unit-tests/${unit_test}.c")
+ target_link_libraries("${unit_test}" unit-test-lib common-main)
+ set_target_properties("${unit_test}"
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ if(MSVC)
+ set_target_properties("${unit_test}"
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ set_target_properties("${unit_test}"
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ endif()
+ list(APPEND PROGRAMS_BUILT "${unit_test}")
+
+ # t-basic intentionally fails tests, to validate the unit-test infrastructure.
+ # Therefore, it should only be run as part of t0080, which verifies that it
+ # fails only in the expected ways.
+ #
+ # All other unit tests should be run.
+ if(NOT ${unit_test} STREQUAL "t-basic")
+ add_test(NAME "t.unit-tests.${unit_test}"
+ COMMAND "./${unit_test}"
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t/unit-tests/bin)
+ endif()
+endforeach()
+
+parse_makefile_for_scripts(clar_test_SUITES "CLAR_TEST_SUITES" "")
+list(TRANSFORM clar_test_SUITES PREPEND "${CMAKE_SOURCE_DIR}/t/unit-tests/")
+list(TRANSFORM clar_test_SUITES APPEND ".c")
+add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h"
+ COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/t/unit-tests/generate-clar-decls.sh
+ "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h"
+ ${clar_test_SUITES}
+ DEPENDS ${CMAKE_SOURCE_DIR}/t/unit-tests/generate-clar-decls.sh
+ ${clar_test_SUITES}
+ VERBATIM)
+add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite"
+ COMMAND ${SH_EXE} "${CMAKE_SOURCE_DIR}/t/unit-tests/generate-clar-suites.sh"
+ "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h"
+ "${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite"
+ DEPENDS "${CMAKE_SOURCE_DIR}/t/unit-tests/generate-clar-suites.sh"
+ "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h"
+ VERBATIM)
+
+add_library(unit-tests-lib ${clar_test_SUITES}
+ "${CMAKE_SOURCE_DIR}/t/unit-tests/clar/clar.c"
+ "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h"
+ "${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite"
+)
+target_include_directories(unit-tests-lib PUBLIC "${CMAKE_BINARY_DIR}/t/unit-tests")
+add_executable(unit-tests "${CMAKE_SOURCE_DIR}/t/unit-tests/unit-test.c")
+target_link_libraries(unit-tests unit-tests-lib common-main)
+set_target_properties(unit-tests
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+if(MSVC)
+ set_target_properties(unit-tests
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ set_target_properties(unit-tests
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+endif()
#test-tool
parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
+add_library(test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)
list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/")
-add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES} ${test-reftable_SOURCES})
-target_link_libraries(test-tool common-main)
+add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES})
+target_link_libraries(test-tool test-lib common-main)
set_target_properties(test-fake-ssh test-tool
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/helper)
@@ -1028,6 +1091,7 @@ set(DIFF diff)
set(PYTHON_PATH /usr/bin/python)
set(TAR tar)
set(NO_CURL )
+set(NO_ICONV )
set(NO_EXPAT )
set(USE_LIBPCRE2 )
set(NO_PERL )
@@ -1041,6 +1105,10 @@ if(NOT CURL_FOUND)
set(NO_CURL 1)
endif()
+if(NOT Iconv_FOUND)
+ SET(NO_ICONV 1)
+endif()
+
if(NOT EXPAT_FOUND)
set(NO_EXPAT 1)
endif()
@@ -1064,6 +1132,7 @@ file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "DIFF='${DIFF}'\n")
file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PYTHON_PATH='${PYTHON_PATH}'\n")
file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TAR='${TAR}'\n")
file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_CURL='${NO_CURL}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_ICONV='${NO_ICONV}'\n")
file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_EXPAT='${NO_EXPAT}'\n")
file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PERL='${NO_PERL}'\n")
file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PTHREADS='${NO_PTHREADS}'\n")
@@ -1093,17 +1162,18 @@ if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH})
file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-completion.bash DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
endif()
-file(GLOB test_scipts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
+file(GLOB test_scripts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
#test
-foreach(tsh ${test_scipts})
- add_test(NAME ${tsh}
+foreach(tsh ${test_scripts})
+ string(REGEX REPLACE ".*/(.*)\\.sh" "\\1" test_name ${tsh})
+ add_test(NAME "t.suite.${test_name}"
COMMAND ${SH_EXE} ${tsh} --no-bin-wrappers --no-chain-lint -vx
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t)
endforeach()
# This test script takes an extremely long time and is known to time out even
# on fast machines because it requires in excess of one hour to run
-set_tests_properties("${CMAKE_SOURCE_DIR}/t/t7112-reset-submodule.sh" PROPERTIES TIMEOUT 4000)
+set_tests_properties("t.suite.t7112-reset-submodule" PROPERTIES TIMEOUT 4000)
endif()#BUILD_TESTING
diff --git a/contrib/coccinelle/refs.cocci b/contrib/coccinelle/refs.cocci
new file mode 100644
index 0000000000..31d9cad8f3
--- /dev/null
+++ b/contrib/coccinelle/refs.cocci
@@ -0,0 +1,103 @@
+// Migrate "refs.h" to not rely on `the_repository` implicitly anymore.
+@@
+@@
+(
+- resolve_ref_unsafe
++ refs_resolve_ref_unsafe
+|
+- resolve_refdup
++ refs_resolve_refdup
+|
+- read_ref_full
++ refs_read_ref_full
+|
+- read_ref
++ refs_read_ref
+|
+- ref_exists
++ refs_ref_exists
+|
+- head_ref
++ refs_head_ref
+|
+- for_each_ref
++ refs_for_each_ref
+|
+- for_each_ref_in
++ refs_for_each_ref_in
+|
+- for_each_fullref_in
++ refs_for_each_fullref_in
+|
+- for_each_tag_ref
++ refs_for_each_tag_ref
+|
+- for_each_branch_ref
++ refs_for_each_branch_ref
+|
+- for_each_remote_ref
++ refs_for_each_remote_ref
+|
+- for_each_glob_ref
++ refs_for_each_glob_ref
+|
+- for_each_glob_ref_in
++ refs_for_each_glob_ref_in
+|
+- head_ref_namespaced
++ refs_head_ref_namespaced
+|
+- for_each_namespaced_ref
++ refs_for_each_namespaced_ref
+|
+- for_each_rawref
++ refs_for_each_rawref
+|
+- safe_create_reflog
++ refs_create_reflog
+|
+- reflog_exists
++ refs_reflog_exists
+|
+- delete_ref
++ refs_delete_ref
+|
+- delete_refs
++ refs_delete_refs
+|
+- delete_reflog
++ refs_delete_reflog
+|
+- for_each_reflog_ent
++ refs_for_each_reflog_ent
+|
+- for_each_reflog_ent_reverse
++ refs_for_each_reflog_ent_reverse
+|
+- for_each_reflog
++ refs_for_each_reflog
+|
+- shorten_unambiguous_ref
++ refs_shorten_unambiguous_ref
+|
+- rename_ref
++ refs_rename_ref
+|
+- copy_existing_ref
++ refs_copy_existing_ref
+|
+- create_symref
++ refs_create_symref
+|
+- ref_transaction_begin
++ ref_store_transaction_begin
+|
+- update_ref
++ refs_update_ref
+|
+- reflog_expire
++ refs_reflog_expire
+)
+ (
++ get_main_ref_store(the_repository),
+ ...)
diff --git a/contrib/coccinelle/xstrncmpz.cocci b/contrib/coccinelle/xstrncmpz.cocci
new file mode 100644
index 0000000000..ccb39e2bc0
--- /dev/null
+++ b/contrib/coccinelle/xstrncmpz.cocci
@@ -0,0 +1,28 @@
+@@
+expression S, T, L;
+@@
+(
+- strncmp(S, T, L) || S[L]
++ !!xstrncmpz(S, T, L)
+|
+- strncmp(S, T, L) || S[L] != '\0'
++ !!xstrncmpz(S, T, L)
+|
+- strncmp(S, T, L) || T[L]
++ !!xstrncmpz(T, S, L)
+|
+- strncmp(S, T, L) || T[L] != '\0'
++ !!xstrncmpz(T, S, L)
+|
+- !strncmp(S, T, L) && !S[L]
++ !xstrncmpz(S, T, L)
+|
+- !strncmp(S, T, L) && S[L] == '\0'
++ !xstrncmpz(S, T, L)
+|
+- !strncmp(S, T, L) && !T[L]
++ !xstrncmpz(T, S, L)
+|
+- !strncmp(S, T, L) && T[L] == '\0'
++ !xstrncmpz(T, S, L)
+)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 55950057c8..3d4dff3185 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -28,17 +28,32 @@
# 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 ';'.
+# Note that "git" is optional --- '!f() { : commit; ...}; f' would complete
+# just like the 'git commit' command.
#
-# If you have a command that is not part of git, but you would still
-# like completion, you can use __git_complete:
+# To add completion for git subcommands that are implemented in external
+# scripts, define a function of the form '_git_${subcommand}' while replacing
+# all dashes with underscores, and the main git completion will make use of it.
+# For example, to add completion for 'git do-stuff' (which could e.g. live
+# in /usr/bin/git-do-stuff), name the completion function '_git_do_stuff'.
+# See _git_show, _git_bisect etc. below for more examples.
+#
+# If you have a shell command that is not part of git (and is not called as a
+# git subcommand), but you would still like git-style completion for it, use
+# __git_complete. For example, to use the same completion as for 'git log' also
+# for the 'gl' command:
#
# __git_complete gl git_log
#
-# Or if it's a main command (i.e. git or gitk):
+# Or if the 'gk' command should be completed the same as 'gitk':
#
# __git_complete gk gitk
#
+# The second parameter of __git_complete gives the completion function; it is
+# resolved as a function named "$2", or "__$2_main", or "_$2" in that order.
+# In the examples above, the actual functions used for completion will be
+# _git_log and __gitk_main.
+#
# Compatible with bash 3.2.57.
#
# You can set the following environment variables to influence the behavior of
@@ -121,6 +136,40 @@ __git ()
${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null
}
+# Helper function to read the first line of a file into a variable.
+# __git_eread requires 2 arguments, the file path and the name of the
+# variable, in that order.
+#
+# This is taken from git-prompt.sh.
+__git_eread ()
+{
+ test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
+}
+
+# Runs git in $__git_repo_path to determine whether a pseudoref exists.
+# 1: The pseudo-ref to search
+__git_pseudoref_exists ()
+{
+ local ref=$1
+ local head
+
+ __git_find_repo_path
+
+ # If the reftable is in use, we have to shell out to 'git rev-parse'
+ # to determine whether the ref exists instead of looking directly in
+ # the filesystem to determine whether the ref exists. Otherwise, use
+ # Bash builtins since executing Git commands are expensive on some
+ # platforms.
+ if __git_eread "$__git_repo_path/HEAD" head; then
+ if [ "$head" == "ref: refs/heads/.invalid" ]; then
+ __git show-ref --exists "$ref"
+ return $?
+ fi
+ fi
+
+ [ -f "$__git_repo_path/$ref" ]
+}
+
# Removes backslash escaping, single quotes and double quotes from a word,
# stores the result in the variable $dequoted_word.
# 1: The word to dequote.
@@ -419,16 +468,18 @@ fi
# This function is equivalent to
#
-# __gitcomp "$(git xxx --git-completion-helper) ..."
+# ___git_resolved_builtins=$(git xxx --git-completion-helper)
#
-# except that the output is cached. Accept 1-3 arguments:
+# except that the result of the execution is cached.
+#
+# Accept 1-3 arguments:
# 1: the git command to execute, this is also the cache key
+# (use "_" when the command contains spaces, e.g. "remote add"
+# becomes "remote_add")
# 2: extra options to be added on top (e.g. negative forms)
# 3: options to be excluded
-__gitcomp_builtin ()
+__git_resolve_builtins ()
{
- # spaces must be replaced with underscore for multi-word
- # commands, e.g. "git remote add" becomes remote_add.
local cmd="$1"
local incl="${2-}"
local excl="${3-}"
@@ -454,7 +505,24 @@ __gitcomp_builtin ()
eval "$var=\"$options\""
fi
- __gitcomp "$options"
+ ___git_resolved_builtins="$options"
+}
+
+# This function is equivalent to
+#
+# __gitcomp "$(git xxx --git-completion-helper) ..."
+#
+# except that the output is cached. Accept 1-3 arguments:
+# 1: the git command to execute, this is also the cache key
+# (use "_" when the command contains spaces, e.g. "remote add"
+# becomes "remote_add")
+# 2: extra options to be added on top (e.g. negative forms)
+# 3: options to be excluded
+__gitcomp_builtin ()
+{
+ __git_resolve_builtins "$1" "$2" "$3"
+
+ __gitcomp "$___git_resolved_builtins"
}
# Variation of __gitcomp_nl () that appends to the existing list of
@@ -521,6 +589,26 @@ __gitcomp_file ()
true
}
+# Find the current subcommand for commands that follow the syntax:
+#
+# git <command> <subcommand>
+#
+# 1: List of possible subcommands.
+# 2: Optional subcommand to return when none is found.
+__git_find_subcommand ()
+{
+ local subcommand subcommands="$1" default_subcommand="$2"
+
+ for subcommand in $subcommands; do
+ if [ "$subcommand" = "${words[__git_cmd_idx+1]}" ]; then
+ echo $subcommand
+ return
+ fi
+ done
+
+ echo $default_subcommand
+}
+
# Execute 'git ls-files', unless the --committable option is specified, in
# which case it runs 'git diff-index' to find out the files that can be
# committed. It return paths relative to the directory specified in the first
@@ -1183,7 +1271,7 @@ __git_aliased_command ()
:) : skip null command ;;
\'*) : skip opening quote after sh -c ;;
*)
- cur="$word"
+ cur="${word%;}"
break
esac
done
@@ -1448,12 +1536,32 @@ _git_bisect ()
{
__git_has_doubledash && return
- local subcommands="start bad good skip reset visualize replay log run"
- local subcommand="$(__git_find_on_cmdline "$subcommands")"
+ __git_find_repo_path
+
+ # If a bisection is in progress get the terms being used.
+ local term_bad term_good
+ if [ -f "$__git_repo_path"/BISECT_TERMS ]; then
+ term_bad=$(__git bisect terms --term-bad)
+ term_good=$(__git bisect terms --term-good)
+ fi
+
+ # We will complete any custom terms, but still always complete the
+ # more usual bad/new/good/old because git bisect gives a good error
+ # message if these are given when not in use, and that's better than
+ # silent refusal to complete if the user is confused.
+ #
+ # We want to recognize 'view' but not complete it, because it overlaps
+ # with 'visualize' too much and is just an alias for it.
+ #
+ local completable_subcommands="start bad new $term_bad good old $term_good terms skip reset visualize replay log run help"
+ local all_subcommands="$completable_subcommands view"
+
+ local subcommand="$(__git_find_on_cmdline "$all_subcommands")"
+
if [ -z "$subcommand" ]; then
__git_find_repo_path
if [ -f "$__git_repo_path"/BISECT_START ]; then
- __gitcomp "$subcommands"
+ __gitcomp "$completable_subcommands"
else
__gitcomp "replay start"
fi
@@ -1461,7 +1569,26 @@ _git_bisect ()
fi
case "$subcommand" in
- bad|good|reset|skip|start)
+ start)
+ case "$cur" in
+ --*)
+ __gitcomp "--first-parent --no-checkout --term-new --term-bad --term-old --term-good"
+ return
+ ;;
+ *)
+ __git_complete_refs
+ ;;
+ esac
+ ;;
+ terms)
+ __gitcomp "--term-good --term-old --term-bad --term-new"
+ return
+ ;;
+ visualize|view)
+ __git_complete_log_opts
+ return
+ ;;
+ bad|new|"$term_bad"|good|old|"$term_good"|reset|skip)
__git_complete_refs
;;
*)
@@ -1623,8 +1750,7 @@ __git_cherry_pick_inprogress_options=$__git_sequencer_inprogress_options
_git_cherry_pick ()
{
- __git_find_repo_path
- if [ -f "$__git_repo_path"/CHERRY_PICK_HEAD ]; then
+ if __git_pseudoref_exists CHERRY_PICK_HEAD; then
__gitcomp "$__git_cherry_pick_inprogress_options"
return
fi
@@ -1678,6 +1804,11 @@ _git_clone ()
__git_untracked_file_modes="all no normal"
+__git_trailer_tokens ()
+{
+ __git config --name-only --get-regexp '^trailer\..*\.key$' | cut -d. -f 2- | rev | cut -d. -f2- | rev
+}
+
_git_commit ()
{
case "$prev" in
@@ -1702,6 +1833,10 @@ _git_commit ()
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
return
;;
+ --trailer=*)
+ __gitcomp_nl "$(__git_trailer_tokens)" "" "${cur##--trailer=}" ":"
+ return
+ ;;
--*)
__gitcomp_builtin commit
return
@@ -1765,7 +1900,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
--output= --output-indicator-context=
--output-indicator-new= --output-indicator-old=
--ws-error-highlight=
- --pickaxe-all --pickaxe-regex
+ --pickaxe-all --pickaxe-regex --patch-with-raw
"
# Options for diff/difftool
@@ -2029,6 +2164,16 @@ __git_log_common_options="
--min-age= --until= --before=
--min-parents= --max-parents=
--no-min-parents --no-max-parents
+ --alternate-refs --ancestry-path
+ --author-date-order --basic-regexp
+ --bisect --boundary --exclude-first-parent-only
+ --exclude-hidden --extended-regexp
+ --fixed-strings --grep-reflog
+ --ignore-missing --left-only --perl-regexp
+ --reflog --regexp-ignore-case --remove-empty
+ --right-only --show-linear-break
+ --show-notes-by-default --show-pulls
+ --since-as-filter --single-worktree
"
# Options that go well for log and gitk (not shortlog)
__git_log_gitk_options="
@@ -2043,7 +2188,8 @@ __git_log_shortlog_options="
"
# Options accepted by log and show
__git_log_show_options="
- --diff-merges --diff-merges= --no-diff-merges --remerge-diff
+ --diff-merges --diff-merges= --no-diff-merges --dd --remerge-diff
+ --encoding=
"
__git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-combined cc remerge r"
@@ -2051,13 +2197,15 @@ __git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-c
__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:"
-_git_log ()
+# Complete porcelain (i.e. not git-rev-list) options and at least some
+# option arguments accepted by git-log. Note that this same set of options
+# are also accepted by some other git commands besides git-log.
+__git_complete_log_opts ()
{
- __git_has_doubledash && return
- __git_find_repo_path
+ COMPREPLY=()
local merge=""
- if [ -f "$__git_repo_path/MERGE_HEAD" ]; then
+ if __git_pseudoref_exists MERGE_HEAD; then
merge="--merge"
fi
case "$prev,$cur" in
@@ -2127,6 +2275,8 @@ _git_log ()
--no-walk --no-walk= --do-walk
--parents --children
--expand-tabs --expand-tabs= --no-expand-tabs
+ --clear-decorations --decorate-refs=
+ --decorate-refs-exclude=
$merge
$__git_diff_common_options
"
@@ -2148,6 +2298,16 @@ _git_log ()
return
;;
esac
+}
+
+_git_log ()
+{
+ __git_has_doubledash && return
+ __git_find_repo_path
+
+ __git_complete_log_opts
+ [ ${#COMPREPLY[@]} -eq 0 ] || return
+
__git_complete_revlist
}
@@ -2364,13 +2524,30 @@ _git_rebase ()
_git_reflog ()
{
- local subcommands="show delete expire"
- local subcommand="$(__git_find_on_cmdline "$subcommands")"
+ local subcommands subcommand
- if [ -z "$subcommand" ]; then
- __gitcomp "$subcommands"
- else
- __git_complete_refs
+ __git_resolve_builtins "reflog"
+
+ subcommands="$___git_resolved_builtins"
+ subcommand="$(__git_find_subcommand "$subcommands" "show")"
+
+ case "$subcommand,$cur" in
+ show,--*)
+ __gitcomp "
+ $__git_log_common_options
+ "
+ return
+ ;;
+ $subcommand,--*)
+ __gitcomp_builtin "reflog_$subcommand"
+ return
+ ;;
+ esac
+
+ __git_complete_refs
+
+ if [ $((cword - __git_cmd_idx)) -eq 1 ]; then
+ __gitcompappend "$subcommands" "" "$cur" " "
fi
}
@@ -2553,6 +2730,33 @@ __git_compute_config_vars ()
__git_config_vars="$(git help --config-for-completion)"
}
+__git_config_vars_all=
+__git_compute_config_vars_all ()
+{
+ test -n "$__git_config_vars_all" ||
+ __git_config_vars_all="$(git --no-pager help --config)"
+}
+
+__git_compute_first_level_config_vars_for_section ()
+{
+ local section="$1"
+ __git_compute_config_vars
+ local this_section="__git_first_level_config_vars_for_section_${section}"
+ test -n "${!this_section}" ||
+ printf -v "__git_first_level_config_vars_for_section_${section}" %s \
+ "$(echo "$__git_config_vars" | awk -F. "/^${section}\.[a-z]/ { print \$2 }")"
+}
+
+__git_compute_second_level_config_vars_for_section ()
+{
+ local section="$1"
+ __git_compute_config_vars_all
+ local this_section="__git_second_level_config_vars_for_section_${section}"
+ test -n "${!this_section}" ||
+ printf -v "__git_second_level_config_vars_for_section_${section}" %s \
+ "$(echo "$__git_config_vars_all" | awk -F. "/^${section}\.</ { print \$3 }")"
+}
+
__git_config_sections=
__git_compute_config_sections ()
{
@@ -2697,73 +2901,50 @@ __git_complete_config_variable_name ()
done
case "$cur_" in
- branch.*.*)
+ branch.*.*|guitool.*.*|difftool.*.*|man.*.*|mergetool.*.*|remote.*.*|submodule.*.*|url.*.*)
local pfx="${cur_%.*}."
cur_="${cur_##*.}"
- __gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_" "$sfx"
+ local section="${pfx%.*.}"
+ __git_compute_second_level_config_vars_for_section "${section}"
+ local this_section="__git_second_level_config_vars_for_section_${section}"
+ __gitcomp "${!this_section}" "$pfx" "$cur_" "$sfx"
return
;;
branch.*)
local pfx="${cur_%.*}."
cur_="${cur_#*.}"
+ local section="${pfx%.}"
__gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")"
- __gitcomp_nl_append $'autoSetupMerge\nautoSetupRebase\n' "$pfx" "$cur_" "${sfx- }"
- return
- ;;
- guitool.*.*)
- local pfx="${cur_%.*}."
- cur_="${cur_##*.}"
- __gitcomp "
- argPrompt cmd confirm needsFile noConsole noRescan
- prompt revPrompt revUnmerged title
- " "$pfx" "$cur_" "$sfx"
- return
- ;;
- difftool.*.*)
- local pfx="${cur_%.*}."
- cur_="${cur_##*.}"
- __gitcomp "cmd path" "$pfx" "$cur_" "$sfx"
- return
- ;;
- man.*.*)
- local pfx="${cur_%.*}."
- cur_="${cur_##*.}"
- __gitcomp "cmd path" "$pfx" "$cur_" "$sfx"
- return
- ;;
- mergetool.*.*)
- local pfx="${cur_%.*}."
- cur_="${cur_##*.}"
- __gitcomp "cmd path trustExitCode" "$pfx" "$cur_" "$sfx"
+ __git_compute_first_level_config_vars_for_section "${section}"
+ local this_section="__git_first_level_config_vars_for_section_${section}"
+ __gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
return
;;
pager.*)
local pfx="${cur_%.*}."
cur_="${cur_#*.}"
__git_compute_all_commands
- __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" "${sfx- }"
- return
- ;;
- remote.*.*)
- local pfx="${cur_%.*}."
- cur_="${cur_##*.}"
- __gitcomp "
- url proxy fetch push mirror skipDefaultUpdate
- receivepack uploadpack tagOpt pushurl
- " "$pfx" "$cur_" "$sfx"
+ __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" "${sfx:- }"
return
;;
remote.*)
local pfx="${cur_%.*}."
cur_="${cur_#*.}"
+ local section="${pfx%.}"
__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
- __gitcomp_nl_append "pushDefault" "$pfx" "$cur_" "${sfx- }"
+ __git_compute_first_level_config_vars_for_section "${section}"
+ local this_section="__git_first_level_config_vars_for_section_${section}"
+ __gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
return
;;
- url.*.*)
+ submodule.*)
local pfx="${cur_%.*}."
- cur_="${cur_##*.}"
- __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" "$sfx"
+ cur_="${cur_#*.}"
+ local section="${pfx%.}"
+ __gitcomp_nl "$(__git config -f "$(__git rev-parse --show-toplevel)/.gitmodules" --get-regexp 'submodule.*.path' | awk -F. '{print $2}')" "$pfx" "$cur_" "."
+ __git_compute_first_level_config_vars_for_section "${section}"
+ local this_section="__git_first_level_config_vars_for_section_${section}"
+ __gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
return
;;
*.*)
@@ -2808,22 +2989,42 @@ __git_complete_config_variable_name_and_value ()
_git_config ()
{
- case "$prev" in
- --get|--get-all|--unset|--unset-all)
- __gitcomp_nl "$(__git_config_get_set_variables)"
+ local subcommands subcommand
+
+ __git_resolve_builtins "config"
+
+ subcommands="$___git_resolved_builtins"
+ subcommand="$(__git_find_subcommand "$subcommands")"
+
+ if [ -z "$subcommand" ]
+ then
+ __gitcomp "$subcommands"
return
- ;;
- *.*)
- __git_complete_config_variable_value
+ fi
+
+ case "$cur" in
+ --*)
+ __gitcomp_builtin "config_$subcommand"
return
;;
esac
- case "$cur" in
- --*)
- __gitcomp_builtin config
+
+ case "$subcommand" in
+ get)
+ __gitcomp_nl "$(__git_config_get_set_variables)"
;;
- *)
- __git_complete_config_variable_name
+ set)
+ case "$prev" in
+ *.*)
+ __git_complete_config_variable_value
+ ;;
+ *)
+ __git_complete_config_variable_name
+ ;;
+ esac
+ ;;
+ unset)
+ __gitcomp_nl "$(__git_config_get_set_variables)"
;;
esac
}
@@ -2942,7 +3143,7 @@ _git_restore ()
__gitcomp_builtin restore
;;
*)
- if __git rev-parse --verify --quiet HEAD >/dev/null; then
+ if __git_pseudoref_exists HEAD; then
__git_complete_index_file "--modified"
fi
esac
@@ -2952,8 +3153,7 @@ __git_revert_inprogress_options=$__git_sequencer_inprogress_options
_git_revert ()
{
- __git_find_repo_path
- if [ -f "$__git_repo_path"/REVERT_HEAD ]; then
+ if __git_pseudoref_exists REVERT_HEAD; then
__gitcomp "$__git_revert_inprogress_options"
return
fi
@@ -3074,12 +3274,119 @@ __gitcomp_directories ()
COMPREPLY+=("$c/")
_found=1
fi
- done < <(git ls-tree -z -d --name-only HEAD $_tmp_dir)
+ done < <(__git ls-tree -z -d --name-only HEAD $_tmp_dir)
if [[ $_found == 0 ]] && [[ "$cur" =~ /$ ]]; then
# No possible further completions any deeper, so assume we're at
# a leaf directory and just consider it complete
__gitcomp_direct_append "$cur "
+ elif [[ $_found == 0 ]]; then
+ # No possible completions found. Avoid falling back to
+ # bash's default file and directory completion, because all
+ # valid completions have already been searched and the
+ # fallbacks can do nothing but mislead. In fact, they can
+ # mislead in three different ways:
+ # 1) Fallback file completion makes no sense when asking
+ # for directory completions, as this function does.
+ # 2) Fallback directory completion is bad because
+ # e.g. "/pro" is invalid and should NOT complete to
+ # "/proc".
+ # 3) Fallback file/directory completion only completes
+ # on paths that exist in the current working tree,
+ # i.e. which are *already* part of their
+ # sparse-checkout. Thus, normal file and directory
+ # completion is always useless for "git
+ # sparse-checkout add" and is also problematic for
+ # "git sparse-checkout set" unless using it to
+ # strictly narrow the checkout.
+ COMPREPLY=( "" )
+ fi
+}
+
+# In non-cone mode, the arguments to {set,add} are supposed to be
+# patterns, relative to the toplevel directory. These can be any kind
+# of general pattern, like 'subdir/*.c' and we can't complete on all
+# of those. However, if the user presses Tab to get tab completion, we
+# presume that they are trying to provide a pattern that names a specific
+# path.
+__gitcomp_slash_leading_paths ()
+{
+ local dequoted_word pfx="" cur_ toplevel
+
+ # Since we are dealing with a sparse-checkout, subdirectories may not
+ # exist in the local working copy. Therefore, we want to run all
+ # ls-files commands relative to the repository toplevel.
+ toplevel="$(git rev-parse --show-toplevel)/"
+
+ __git_dequote "$cur"
+
+ # If the paths provided by the user already start with '/', then
+ # they are considered relative to the toplevel of the repository
+ # already. If they do not start with /, then we need to adjust
+ # them to start with the appropriate prefix.
+ case "$cur" in
+ /*)
+ cur="${cur:1}"
+ ;;
+ *)
+ pfx="$(__git rev-parse --show-prefix)"
+ esac
+
+ # Since sparse-index is limited to cone-mode, in non-cone-mode the
+ # list of valid paths is precisely the cached files in the index.
+ #
+ # NEEDSWORK:
+ # 1) We probably need to take care of cases where ls-files
+ # responds with special quoting.
+ # 2) We probably need to take care of cases where ${cur} has
+ # some kind of special quoting.
+ # 3) On top of any quoting from 1 & 2, we have to provide an extra
+ # level of quoting for any paths that contain a '*', '?', '\',
+ # '[', ']', or leading '#' or '!' since those will be
+ # interpreted by sparse-checkout as something other than a
+ # literal path character.
+ # Since there are two types of quoting here, this might get really
+ # complex. For now, just punt on all of this...
+ completions="$(__git -C "${toplevel}" -c core.quotePath=false \
+ ls-files --cached -- "${pfx}${cur}*" \
+ | sed -e s%^%/% -e 's%$% %')"
+ # Note, above, though that we needed all of the completions to be
+ # prefixed with a '/', and we want to add a space so that bash
+ # completion will actually complete an entry and let us move on to
+ # the next one.
+
+ # Return what we've found.
+ if test -n "$completions"; then
+ # We found some completions; return them
+ local IFS=$'\n'
+ COMPREPLY=($completions)
+ else
+ # Do NOT fall back to bash-style all-local-files-and-dirs
+ # when we find no match. Such options are worse than
+ # useless:
+ # 1. "git sparse-checkout add" needs paths that are NOT
+ # currently in the working copy. "git
+ # sparse-checkout set" does as well, except in the
+ # special cases when users are only trying to narrow
+ # their sparse checkout to a subset of what they
+ # already have.
+ #
+ # 2. A path like '.config' is ambiguous as to whether
+ # the user wants all '.config' files throughout the
+ # tree, or just the one under the current directory.
+ # It would result in a warning from the
+ # sparse-checkout command due to this. As such, all
+ # completions of paths should be prefixed with a
+ # '/'.
+ #
+ # 3. We don't want paths prefixed with a '/' to
+ # complete files in the system root directory, we
+ # want it to complete on files relative to the
+ # repository root.
+ #
+ # As such, make sure that NO completions are offered rather
+ # than falling back to bash's default completions.
+ COMPREPLY=( "" )
fi
}
@@ -3087,6 +3394,7 @@ _git_sparse_checkout ()
{
local subcommands="list init set disable add reapply"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
+ local using_cone=true
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
return
@@ -3097,9 +3405,18 @@ _git_sparse_checkout ()
__gitcomp_builtin sparse-checkout_$subcommand "" "--"
;;
set,*|add,*)
- if [ "$(__git config core.sparseCheckoutCone)" == "true" ] ||
- [ -n "$(__git_find_on_cmdline --cone)" ]; then
+ if [[ "$(__git config core.sparseCheckout)" == "true" &&
+ "$(__git config core.sparseCheckoutCone)" == "false" &&
+ -z "$(__git_find_on_cmdline --cone)" ]]; then
+ using_cone=false
+ fi
+ if [[ -n "$(__git_find_on_cmdline --no-cone)" ]]; then
+ using_cone=false
+ fi
+ if [[ "$using_cone" == "true" ]]; then
__gitcomp_directories
+ else
+ __gitcomp_slash_leading_paths
fi
esac
}
@@ -3298,6 +3615,17 @@ _git_svn ()
fi
}
+_git_symbolic_ref () {
+ case "$cur" in
+ --*)
+ __gitcomp_builtin symbolic-ref
+ return
+ ;;
+ esac
+
+ __git_complete_refs
+}
+
_git_tag ()
{
local i c="$__git_cmd_idx" f=0
@@ -3346,7 +3674,7 @@ __git_complete_worktree_paths ()
# Generate completion reply from worktree list skipping the first
# entry: it's the path of the main worktree, which can't be moved,
# removed, locked, etc.
- __gitcomp_nl "$(git worktree list --porcelain |
+ __gitcomp_nl "$(__git worktree list --porcelain |
sed -n -e '2,$ s/^worktree //p')"
}
@@ -3370,7 +3698,7 @@ _git_worktree ()
# Here we are not completing an --option, it's either the
# path or a ref.
case "$prev" in
- -b|-B) # Complete refs for branch to be created/reseted.
+ -b|-B) # Complete refs for branch to be created/reset.
__git_complete_refs
;;
-*) # The previous word is an -o|--option without an
@@ -3582,7 +3910,7 @@ __gitk_main ()
__git_find_repo_path
local merge=""
- if [ -f "$__git_repo_path/MERGE_HEAD" ]; then
+ if __git_pseudoref_exists MERGE_HEAD; then
merge="--merge"
fi
case "$cur" in
diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index cac6f61881..f5877bd7a1 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -272,6 +272,7 @@ _git ()
{
local _ret=1
local cur cword prev
+ local __git_repo_path
cur=${words[CURRENT]}
prev=${words[CURRENT-1]}
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 2c030050ae..6186c474ba 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -8,8 +8,8 @@
# To enable:
#
# 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
-# 2) Add the following line to your .bashrc/.zshrc:
-# source ~/.git-prompt.sh
+# 2) Add the following line to your .bashrc/.zshrc/.profile:
+# . ~/.git-prompt.sh # dot path/to/this-file
# 3a) Change your PS1 to call __git_ps1 as
# command-substitution:
# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
@@ -30,6 +30,8 @@
# Optionally, you can supply a third argument with a printf
# format string to finetune the output of the branch status
#
+# See notes below about compatibility with other shells.
+#
# The repository status will be displayed only if you are currently in a
# git repository. The %s token is the placeholder for the shown status.
#
@@ -106,42 +108,82 @@
# directory is set up to be ignored by git, then set
# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
# repository level by setting bash.hideIfPwdIgnored to "false".
+#
+# Compatibility with other shells (beyond bash/zsh):
+#
+# We require posix-ish shell plus "local" support, which is most
+# shells (even pdksh), but excluding ksh93 (because no "local").
+#
+# Prompt integration might differ between shells, but the gist is
+# to load it once on shell init with '. path/to/git-prompt.sh',
+# set GIT_PS1* vars once as needed, and either place $(__git_ps1..)
+# inside PS1 once (0/1 args), or, before each prompt is displayed,
+# call __git_ps1 (2/3 args) which sets PS1 with the status embedded.
+#
+# Many shells support the 1st method of command substitution,
+# though some might need to first enable cmd substitution in PS1.
+#
+# When using colors, each escape sequence is wrapped between byte
+# values 1 and 2 (control chars SOH, STX, respectively), which are
+# invisible at the output, but for bash/readline they mark 0-width
+# strings (SGR color sequences) when calculating the on-screen
+# prompt width, to maintain correct input editing at the prompt.
+#
+# To replace or disable the 0-width markers, set GIT_PS1_COLOR_PRE
+# and GIT_PS1_COLOR_POST to other markers, or empty (nul) to not
+# use markers. For instance, some shells support '\[' and '\]' as
+# start/end markers in PS1 - when invoking __git_ps1 with 3/4 args,
+# but it may or may not work in command substitution mode. YMMV.
+#
+# If the shell doesn't support 0-width markers and editing behaves
+# incorrectly when using colors in __git_ps1, then, other than
+# disabling color, it might be solved using multi-line prompt,
+# where the git status is not at the last line, e.g.:
+# PS1='\n\w \u@\h$(__git_ps1 " (%s)")\n\$ '
# check whether printf supports -v
__git_printf_supports_v=
printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
+# like __git_SOH=$'\001' etc but works also in shells without $'...'
+eval "$(printf '
+ __git_SOH="\001" __git_STX="\002" __git_ESC="\033"
+ __git_LF="\n" __git_CRLF="\r\n"
+')"
+
# stores the divergence from upstream in $p
# used by GIT_PS1_SHOWUPSTREAM
__git_ps1_show_upstream ()
{
local key value
- local svn_remote svn_url_pattern count n
+ local svn_remotes="" svn_url_pattern="" count n
local upstream_type=git legacy="" verbose="" name=""
+ local LF="$__git_LF"
- svn_remote=()
# get some config options from git-config
local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
while read -r key value; do
case "$key" in
bash.showupstream)
GIT_PS1_SHOWUPSTREAM="$value"
- if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+ if [ -z "${GIT_PS1_SHOWUPSTREAM}" ]; then
p=""
return
fi
;;
svn-remote.*.url)
- svn_remote[$((${#svn_remote[@]} + 1))]="$value"
+ svn_remotes=${svn_remotes}${value}${LF} # URI\nURI\n...
svn_url_pattern="$svn_url_pattern\\|$value"
upstream_type=svn+git # default upstream type is SVN if available, else git
;;
esac
- done <<< "$output"
+ done <<-OUTPUT
+ $output
+ OUTPUT
# parse configuration values
local option
- for option in ${GIT_PS1_SHOWUPSTREAM}; do
+ for option in ${GIT_PS1_SHOWUPSTREAM-}; do
case "$option" in
git|svn) upstream_type="$option" ;;
verbose) verbose=1 ;;
@@ -154,33 +196,45 @@ __git_ps1_show_upstream ()
case "$upstream_type" in
git) upstream_type="@{upstream}" ;;
svn*)
- # get the upstream from the "git-svn-id: ..." in a commit message
- # (git-svn uses essentially the same procedure internally)
- local -a svn_upstream
- svn_upstream=($(git log --first-parent -1 \
- --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
- if [[ 0 -ne ${#svn_upstream[@]} ]]; then
- svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
- svn_upstream=${svn_upstream%@*}
- local n_stop="${#svn_remote[@]}"
- for ((n=1; n <= n_stop; n++)); do
- svn_upstream=${svn_upstream#${svn_remote[$n]}}
- done
+ # successful svn-upstream resolution:
+ # - get the list of configured svn-remotes ($svn_remotes set above)
+ # - get the last commit which seems from one of our svn-remotes
+ # - confirm that it is from one of the svn-remotes
+ # - use $GIT_SVN_ID if set, else "git-svn"
- if [[ -z "$svn_upstream" ]]; then
+ # get upstream from "git-svn-id: UPSTRM@N HASH" in a commit message
+ # (git-svn uses essentially the same procedure internally)
+ local svn_upstream="$(
+ git log --first-parent -1 \
+ --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null
+ )"
+
+ if [ -n "$svn_upstream" ]; then
+ # extract the URI, assuming --grep matched the last line
+ svn_upstream=${svn_upstream##*$LF} # last line
+ svn_upstream=${svn_upstream#*: } # UPSTRM@N HASH
+ svn_upstream=${svn_upstream%@*} # UPSTRM
+
+ case ${LF}${svn_remotes} in
+ *"${LF}${svn_upstream}${LF}"*)
+ # grep indeed matched the last line - it's our remote
# default branch name for checkouts with no layout:
upstream_type=${GIT_SVN_ID:-git-svn}
- else
+ ;;
+ *)
+ # the commit message includes one of our remotes, but
+ # it's not at the last line. is $svn_upstream junk?
upstream_type=${svn_upstream#/}
- fi
- elif [[ "svn+git" = "$upstream_type" ]]; then
+ ;;
+ esac
+ elif [ "svn+git" = "$upstream_type" ]; then
upstream_type="@{upstream}"
fi
;;
esac
# Find how many commits we are ahead/behind our upstream
- if [[ -z "$legacy" ]]; then
+ if [ -z "$legacy" ]; then
count="$(git rev-list --count --left-right \
"$upstream_type"...HEAD 2>/dev/null)"
else
@@ -192,8 +246,8 @@ __git_ps1_show_upstream ()
for commit in $commits
do
case "$commit" in
- "<"*) ((behind++)) ;;
- *) ((ahead++)) ;;
+ "<"*) behind=$((behind+1)) ;;
+ *) ahead=$((ahead+1)) ;;
esac
done
count="$behind $ahead"
@@ -203,7 +257,7 @@ __git_ps1_show_upstream ()
fi
# calculate the result
- if [[ -z "$verbose" ]]; then
+ if [ -z "$verbose" ]; then
case "$count" in
"") # no upstream
p="" ;;
@@ -229,10 +283,10 @@ __git_ps1_show_upstream ()
*) # diverged from upstream
upstream="|u+${count#* }-${count% *}" ;;
esac
- if [[ -n "$count" && -n "$name" ]]; then
+ if [ -n "$count" ] && [ -n "$name" ]; then
__git_ps1_upstream_name=$(git rev-parse \
--abbrev-ref "$upstream_type" 2>/dev/null)
- if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+ if [ "$pcmode" = yes ] && [ "$ps1_expanded" = yes ]; then
upstream="$upstream \${__git_ps1_upstream_name}"
else
upstream="$upstream ${__git_ps1_upstream_name}"
@@ -251,25 +305,29 @@ __git_ps1_show_upstream ()
# their own color.
__git_ps1_colorize_gitstring ()
{
- if [[ -n ${ZSH_VERSION-} ]]; then
+ if [ -n "${ZSH_VERSION-}" ]; then
local c_red='%F{red}'
local c_green='%F{green}'
local c_lblue='%F{blue}'
local c_clear='%f'
else
- # Using \001 and \002 around colors is necessary to prevent
- # issues with command line editing/browsing/completion!
- 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'
+ # \001 (SOH) and \002 (STX) are 0-width substring markers
+ # which bash/readline identify while calculating the prompt
+ # on-screen width - to exclude 0-screen-width esc sequences.
+ local c_pre="${GIT_PS1_COLOR_PRE-$__git_SOH}${__git_ESC}["
+ local c_post="m${GIT_PS1_COLOR_POST-$__git_STX}"
+
+ local c_red="${c_pre}31${c_post}"
+ local c_green="${c_pre}32${c_post}"
+ local c_lblue="${c_pre}1;34${c_post}"
+ local c_clear="${c_pre}0${c_post}"
fi
- local bad_color=$c_red
- local ok_color=$c_green
+ local bad_color="$c_red"
+ local ok_color="$c_green"
local flags_color="$c_lblue"
local branch_color=""
- if [ $detached = no ]; then
+ if [ "$detached" = no ]; then
branch_color="$ok_color"
else
branch_color="$bad_color"
@@ -298,7 +356,7 @@ __git_ps1_colorize_gitstring ()
# variable, in that order.
__git_eread ()
{
- test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
+ test -r "$1" && IFS=$__git_CRLF read -r "$2" <"$1"
}
# see if a cherry-pick or revert is in progress, if the user has committed a
@@ -346,7 +404,7 @@ __git_sequencer_status ()
__git_ps1 ()
{
# preserve exit status
- local exit=$?
+ local exit="$?"
local pcmode=no
local detached=no
local ps1pc_start='\u@\h:\w '
@@ -365,7 +423,7 @@ __git_ps1 ()
;;
0|1) printf_format="${1:-$printf_format}"
;;
- *) return $exit
+ *) return "$exit"
;;
esac
@@ -403,37 +461,40 @@ __git_ps1 ()
# incorrect.)
#
local ps1_expanded=yes
- [ -z "${ZSH_VERSION-}" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
+ [ -z "${ZSH_VERSION-}" ] || eval '[[ -o PROMPT_SUBST ]]' || ps1_expanded=no
[ -z "${BASH_VERSION-}" ] || shopt -q promptvars || ps1_expanded=no
local repo_info rev_parse_exit_code
repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
- --is-bare-repository --is-inside-work-tree \
+ --is-bare-repository --is-inside-work-tree --show-ref-format \
--short HEAD 2>/dev/null)"
rev_parse_exit_code="$?"
if [ -z "$repo_info" ]; then
- return $exit
+ return "$exit"
fi
+ local LF="$__git_LF"
local short_sha=""
if [ "$rev_parse_exit_code" = "0" ]; then
- short_sha="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
+ short_sha="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
fi
- local inside_worktree="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
- local bare_repo="${repo_info##*$'\n'}"
- repo_info="${repo_info%$'\n'*}"
- local inside_gitdir="${repo_info##*$'\n'}"
- local g="${repo_info%$'\n'*}"
+ local ref_format="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
+ local inside_worktree="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
+ local bare_repo="${repo_info##*$LF}"
+ repo_info="${repo_info%$LF*}"
+ local inside_gitdir="${repo_info##*$LF}"
+ local g="${repo_info%$LF*}"
if [ "true" = "$inside_worktree" ] &&
[ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
[ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
git check-ignore -q .
then
- return $exit
+ return "$exit"
fi
local sparse=""
@@ -479,12 +540,27 @@ __git_ps1 ()
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
local head=""
- if ! __git_eread "$g/HEAD" head; then
- return $exit
- fi
- # is it a symbolic ref?
- b="${head#ref: }"
- if [ "$head" = "$b" ]; then
+
+ case "$ref_format" in
+ files)
+ if ! __git_eread "$g/HEAD" head; then
+ return "$exit"
+ fi
+
+ case $head in
+ "ref: "*)
+ head="${head#ref: }"
+ ;;
+ *)
+ head=""
+ esac
+ ;;
+ *)
+ head="$(git symbolic-ref HEAD 2>/dev/null)"
+ ;;
+ esac
+
+ if test -z "$head"; then
detached=yes
b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
@@ -502,6 +578,8 @@ __git_ps1 ()
b="$short_sha..."
b="($b)"
+ else
+ b="$head"
fi
fi
fi
@@ -511,8 +589,8 @@ __git_ps1 ()
fi
local conflict="" # state indicator for unresolved conflicts
- if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] &&
- [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
+ if [ "${GIT_PS1_SHOWCONFLICTSTATE-}" = "yes" ] &&
+ [ "$(git ls-files --unmerged 2>/dev/null)" ]; then
conflict="|CONFLICT"
fi
@@ -564,10 +642,10 @@ __git_ps1 ()
fi
fi
- local z="${GIT_PS1_STATESEPARATOR-" "}"
+ local z="${GIT_PS1_STATESEPARATOR- }"
b=${b##refs/heads/}
- if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+ if [ "$pcmode" = yes ] && [ "$ps1_expanded" = yes ]; then
__git_ps1_branch_name=$b
b="\${__git_ps1_branch_name}"
fi
@@ -579,7 +657,7 @@ __git_ps1 ()
local f="$h$w$i$s$u$p"
local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}"
- if [ $pcmode = yes ]; then
+ if [ "$pcmode" = yes ]; then
if [ "${__git_printf_supports_v-}" != yes ]; then
gitstring=$(printf -- "$printf_format" "$gitstring")
else
@@ -590,5 +668,5 @@ __git_ps1 ()
printf -- "$printf_format" "$gitstring"
fi
- return $exit
+ return "$exit"
}
diff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh
index 4ec419f900..6ce9603568 100755
--- a/contrib/coverage-diff.sh
+++ b/contrib/coverage-diff.sh
@@ -74,8 +74,7 @@ do
sort >uncovered_lines.txt
comm -12 uncovered_lines.txt new_lines.txt |
- sed -e 's/$/\)/' |
- sed -e 's/^/ /' >uncovered_new_lines.txt
+ sed -e 's/$/\)/' -e 's/^/ /' >uncovered_new_lines.txt
grep -q '[^[:space:]]' <uncovered_new_lines.txt &&
echo $file >>coverage-data.txt &&
@@ -91,11 +90,7 @@ cat coverage-data.txt
echo "Commits introducing uncovered code:"
-commit_list=$(cat coverage-data.txt |
- grep -E '^[0-9a-f]{7,} ' |
- awk '{print $1;}' |
- sort |
- uniq)
+commit_list=$(awk '/^[0-9a-f]{7,}/ { print $1 }' coverage-data.txt | sort -u)
(
for commit in $commit_list
diff --git a/contrib/credential/libsecret/git-credential-libsecret.c b/contrib/credential/libsecret/git-credential-libsecret.c
index ef681f29d5..90034d0cf1 100644
--- a/contrib/credential/libsecret/git-credential-libsecret.c
+++ b/contrib/credential/libsecret/git-credential-libsecret.c
@@ -39,6 +39,8 @@ struct credential {
char *path;
char *username;
char *password;
+ char *password_expiry_utc;
+ char *oauth_refresh_token;
};
#define CREDENTIAL_INIT { 0 }
@@ -52,8 +54,29 @@ struct credential_operation {
#define CREDENTIAL_OP_END { NULL, NULL }
+static void credential_clear(struct credential *c);
+
/* ----------------- Secret Service functions ----------------- */
+static const SecretSchema schema = {
+ "org.git.Password",
+ /* Ignore schema name during search for backwards compatibility */
+ SECRET_SCHEMA_DONT_MATCH_NAME,
+ {
+ /*
+ * libsecret assumes attribute values are non-confidential and
+ * unchanging, so we can't include oauth_refresh_token or
+ * password_expiry_utc.
+ */
+ { "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "object", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { NULL, 0 },
+ }
+};
+
static char *make_label(struct credential *c)
{
if (c->port)
@@ -101,7 +124,7 @@ static int keyring_get(struct credential *c)
attributes = make_attr_list(c);
items = secret_service_search_sync(service,
- SECRET_SCHEMA_COMPAT_NETWORK,
+ &schema,
attributes,
SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
NULL,
@@ -117,6 +140,7 @@ static int keyring_get(struct credential *c)
SecretItem *item;
SecretValue *secret;
const char *s;
+ gchar **parts;
item = items->data;
secret = secret_item_get_secret(item);
@@ -130,8 +154,30 @@ static int keyring_get(struct credential *c)
s = secret_value_get_text(secret);
if (s) {
- g_free(c->password);
- c->password = g_strdup(s);
+ /*
+ * Passwords and other attributes encoded in following format:
+ * hunter2
+ * password_expiry_utc=1684189401
+ * oauth_refresh_token=xyzzy
+ */
+ parts = g_strsplit(s, "\n", 0);
+ if (g_strv_length(parts) >= 1) {
+ g_free(c->password);
+ c->password = g_strdup(parts[0]);
+ } else {
+ g_free(c->password);
+ c->password = g_strdup("");
+ }
+ for (int i = 1; i < g_strv_length(parts); i++) {
+ if (g_str_has_prefix(parts[i], "password_expiry_utc=")) {
+ g_free(c->password_expiry_utc);
+ c->password_expiry_utc = g_strdup(&parts[i][20]);
+ } else if (g_str_has_prefix(parts[i], "oauth_refresh_token=")) {
+ g_free(c->oauth_refresh_token);
+ c->oauth_refresh_token = g_strdup(&parts[i][20]);
+ }
+ }
+ g_strfreev(parts);
}
g_hash_table_unref(attributes);
@@ -148,6 +194,7 @@ static int keyring_store(struct credential *c)
char *label = NULL;
GHashTable *attributes = NULL;
GError *error = NULL;
+ GString *secret = NULL;
/*
* Sanity check that what we are storing is actually sensible.
@@ -162,13 +209,23 @@ static int keyring_store(struct credential *c)
label = make_label(c);
attributes = make_attr_list(c);
- secret_password_storev_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+ secret = g_string_new(c->password);
+ if (c->password_expiry_utc) {
+ g_string_append_printf(secret, "\npassword_expiry_utc=%s",
+ c->password_expiry_utc);
+ }
+ if (c->oauth_refresh_token) {
+ g_string_append_printf(secret, "\noauth_refresh_token=%s",
+ c->oauth_refresh_token);
+ }
+ secret_password_storev_sync(&schema,
attributes,
NULL,
label,
- c->password,
+ secret->str,
NULL,
&error);
+ g_string_free(secret, TRUE);
g_free(label);
g_hash_table_unref(attributes);
@@ -185,6 +242,7 @@ static int keyring_erase(struct credential *c)
{
GHashTable *attributes = NULL;
GError *error = NULL;
+ struct credential existing = CREDENTIAL_INIT;
/*
* Sanity check that we actually have something to match
@@ -197,8 +255,22 @@ static int keyring_erase(struct credential *c)
if (!c->protocol && !c->host && !c->path && !c->username)
return EXIT_FAILURE;
+ if (c->password) {
+ existing.host = g_strdup(c->host);
+ existing.path = g_strdup(c->path);
+ existing.port = c->port;
+ existing.protocol = g_strdup(c->protocol);
+ existing.username = g_strdup(c->username);
+ keyring_get(&existing);
+ if (existing.password && strcmp(c->password, existing.password)) {
+ credential_clear(&existing);
+ return EXIT_SUCCESS;
+ }
+ credential_clear(&existing);
+ }
+
attributes = make_attr_list(c);
- secret_password_clearv_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+ secret_password_clearv_sync(&schema,
attributes,
NULL,
&error);
@@ -238,6 +310,8 @@ static void credential_clear(struct credential *c)
g_free(c->path);
g_free(c->username);
g_free(c->password);
+ g_free(c->password_expiry_utc);
+ g_free(c->oauth_refresh_token);
credential_init(c);
}
@@ -284,11 +358,19 @@ static int credential_read(struct credential *c)
} else if (!strcmp(key, "username")) {
g_free(c->username);
c->username = g_strdup(value);
+ } else if (!strcmp(key, "password_expiry_utc")) {
+ g_free(c->password_expiry_utc);
+ c->password_expiry_utc = g_strdup(value);
} else if (!strcmp(key, "password")) {
g_free(c->password);
c->password = g_strdup(value);
while (*value)
*value++ = '\0';
+ } else if (!strcmp(key, "oauth_refresh_token")) {
+ g_free(c->oauth_refresh_token);
+ c->oauth_refresh_token = g_strdup(value);
+ while (*value)
+ *value++ = '\0';
}
/*
* Ignore other lines; we don't know what they mean, but
@@ -314,6 +396,10 @@ static void credential_write(const struct credential *c)
/* only write username/password, if set */
credential_write_item(stdout, "username", c->username);
credential_write_item(stdout, "password", c->password);
+ credential_write_item(stdout, "password_expiry_utc",
+ c->password_expiry_utc);
+ credential_write_item(stdout, "oauth_refresh_token",
+ c->oauth_refresh_token);
}
static void usage(const char *name)
diff --git a/contrib/credential/osxkeychain/Makefile b/contrib/credential/osxkeychain/Makefile
index 4b3a08a2ba..238f5f8c36 100644
--- a/contrib/credential/osxkeychain/Makefile
+++ b/contrib/credential/osxkeychain/Makefile
@@ -8,7 +8,8 @@ CFLAGS = -g -O2 -Wall
-include ../../../config.mak
git-credential-osxkeychain: git-credential-osxkeychain.o
- $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -Wl,-framework -Wl,Security
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) \
+ -framework Security -framework CoreFoundation
git-credential-osxkeychain.o: git-credential-osxkeychain.c
$(CC) -c $(CFLAGS) $<
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index 5f2e5f16c8..1c8310d7fe 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -3,14 +3,52 @@
#include <stdlib.h>
#include <Security/Security.h>
-static SecProtocolType protocol;
-static char *host;
-static char *path;
-static char *username;
-static char *password;
-static UInt16 port;
-
-__attribute__((format (printf, 1, 2)))
+#define ENCODING kCFStringEncodingUTF8
+static CFStringRef protocol; /* Stores constant strings - not memory managed */
+static CFStringRef host;
+static CFNumberRef port;
+static CFStringRef path;
+static CFStringRef username;
+static CFDataRef password;
+static CFDataRef password_expiry_utc;
+static CFDataRef oauth_refresh_token;
+static int state_seen;
+
+static void clear_credential(void)
+{
+ if (host) {
+ CFRelease(host);
+ host = NULL;
+ }
+ if (port) {
+ CFRelease(port);
+ port = NULL;
+ }
+ if (path) {
+ CFRelease(path);
+ path = NULL;
+ }
+ if (username) {
+ CFRelease(username);
+ username = NULL;
+ }
+ if (password) {
+ CFRelease(password);
+ password = NULL;
+ }
+ if (password_expiry_utc) {
+ CFRelease(password_expiry_utc);
+ password_expiry_utc = NULL;
+ }
+ if (oauth_refresh_token) {
+ CFRelease(oauth_refresh_token);
+ oauth_refresh_token = NULL;
+ }
+}
+
+#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1
+
+__attribute__((format (printf, 1, 2), __noreturn__))
static void die(const char *err, ...)
{
char msg[4096];
@@ -19,70 +57,202 @@ static void die(const char *err, ...)
vsnprintf(msg, sizeof(msg), err, params);
fprintf(stderr, "%s\n", msg);
va_end(params);
+ clear_credential();
exit(1);
}
-static void *xstrdup(const char *s1)
+static void *xmalloc(size_t len)
{
- void *ret = strdup(s1);
+ void *ret = malloc(len);
if (!ret)
die("Out of memory");
return ret;
}
-#define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x
-#define KEYCHAIN_ARGS \
- NULL, /* default keychain */ \
- KEYCHAIN_ITEM(host), \
- 0, NULL, /* account domain */ \
- KEYCHAIN_ITEM(username), \
- KEYCHAIN_ITEM(path), \
- port, \
- protocol, \
- kSecAuthenticationTypeDefault
-
-static void write_item(const char *what, const char *buf, int len)
+static CFDictionaryRef create_dictionary(CFAllocatorRef allocator, ...)
+{
+ va_list args;
+ const void *key;
+ CFMutableDictionaryRef result;
+
+ result = CFDictionaryCreateMutable(allocator,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+
+ va_start(args, allocator);
+ while ((key = va_arg(args, const void *)) != NULL) {
+ const void *value;
+ value = va_arg(args, const void *);
+ if (value)
+ CFDictionarySetValue(result, key, value);
+ }
+ va_end(args);
+
+ return result;
+}
+
+#define CREATE_SEC_ATTRIBUTES(...) \
+ create_dictionary(kCFAllocatorDefault, \
+ kSecClass, kSecClassInternetPassword, \
+ kSecAttrServer, host, \
+ kSecAttrAccount, username, \
+ kSecAttrPath, path, \
+ kSecAttrPort, port, \
+ kSecAttrProtocol, protocol, \
+ kSecAttrAuthenticationType, \
+ kSecAttrAuthenticationTypeDefault, \
+ __VA_ARGS__);
+
+static void write_item(const char *what, const char *buf, size_t len)
{
printf("%s=", what);
fwrite(buf, 1, len, stdout);
putchar('\n');
}
-static void find_username_in_item(SecKeychainItemRef item)
+static void find_username_in_item(CFDictionaryRef item)
{
- SecKeychainAttributeList list;
- SecKeychainAttribute attr;
+ CFStringRef account_ref;
+ char *username_buf;
+ CFIndex buffer_len;
- list.count = 1;
- list.attr = &attr;
- attr.tag = kSecAccountItemAttr;
+ account_ref = CFDictionaryGetValue(item, kSecAttrAccount);
+ if (!account_ref)
+ {
+ write_item("username", "", 0);
+ return;
+ }
- if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL))
+ username_buf = (char *)CFStringGetCStringPtr(account_ref, ENCODING);
+ if (username_buf)
+ {
+ write_item("username", username_buf, strlen(username_buf));
return;
+ }
- write_item("username", attr.data, attr.length);
- SecKeychainItemFreeContent(&list, NULL);
+ /* If we can't get a CString pointer then
+ * we need to allocate our own buffer */
+ buffer_len = CFStringGetMaximumSizeForEncoding(
+ CFStringGetLength(account_ref), ENCODING) + 1;
+ username_buf = xmalloc(buffer_len);
+ if (CFStringGetCString(account_ref,
+ username_buf,
+ buffer_len,
+ ENCODING)) {
+ write_item("username", username_buf, strlen(username_buf));
+ }
+ free(username_buf);
}
-static void find_internet_password(void)
+static OSStatus find_internet_password(void)
{
- void *buf;
- UInt32 len;
- SecKeychainItemRef item;
+ CFDictionaryRef attrs;
+ CFDictionaryRef item;
+ CFDataRef data;
+ OSStatus result;
- if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item))
- return;
+ attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitOne,
+ kSecReturnAttributes, kCFBooleanTrue,
+ kSecReturnData, kCFBooleanTrue,
+ NULL);
+ result = SecItemCopyMatching(attrs, (CFTypeRef *)&item);
+ if (result) {
+ goto out;
+ }
+
+ data = CFDictionaryGetValue(item, kSecValueData);
- write_item("password", buf, len);
+ write_item("password",
+ (const char *)CFDataGetBytePtr(data),
+ CFDataGetLength(data));
if (!username)
find_username_in_item(item);
- SecKeychainItemFreeContent(NULL, buf);
+ CFRelease(item);
+
+ write_item("capability[]", "state", strlen("state"));
+ write_item("state[]", "osxkeychain:seen=1", strlen("osxkeychain:seen=1"));
+
+out:
+ CFRelease(attrs);
+
+ /* We consider not found to not be an error */
+ if (result == errSecItemNotFound)
+ result = errSecSuccess;
+
+ return result;
+}
+
+static OSStatus delete_ref(const void *itemRef)
+{
+ CFArrayRef item_ref_list;
+ CFDictionaryRef delete_query;
+ OSStatus result;
+
+ item_ref_list = CFArrayCreate(kCFAllocatorDefault,
+ &itemRef,
+ 1,
+ &kCFTypeArrayCallBacks);
+ delete_query = create_dictionary(kCFAllocatorDefault,
+ kSecClass, kSecClassInternetPassword,
+ kSecMatchItemList, item_ref_list,
+ NULL);
+
+ if (password) {
+ /* We only want to delete items with a matching password */
+ CFIndex capacity;
+ CFMutableDictionaryRef query;
+ CFDataRef data;
+
+ capacity = CFDictionaryGetCount(delete_query) + 1;
+ query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
+ capacity,
+ delete_query);
+ CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
+ result = SecItemCopyMatching(query, (CFTypeRef *)&data);
+ if (!result) {
+ CFDataRef kc_password;
+ const UInt8 *raw_data;
+ const UInt8 *line;
+
+ /* Don't match appended metadata */
+ raw_data = CFDataGetBytePtr(data);
+ line = memchr(raw_data, '\n', CFDataGetLength(data));
+ if (line)
+ kc_password = CFDataCreateWithBytesNoCopy(
+ kCFAllocatorDefault,
+ raw_data,
+ line - raw_data,
+ kCFAllocatorNull);
+ else
+ kc_password = data;
+
+ if (CFEqual(kc_password, password))
+ result = SecItemDelete(delete_query);
+
+ if (line)
+ CFRelease(kc_password);
+ CFRelease(data);
+ }
+
+ CFRelease(query);
+ } else {
+ result = SecItemDelete(delete_query);
+ }
+
+ CFRelease(delete_query);
+ CFRelease(item_ref_list);
+
+ return result;
}
-static void delete_internet_password(void)
+static OSStatus delete_internet_password(void)
{
- SecKeychainItemRef item;
+ CFDictionaryRef attrs;
+ CFArrayRef refs;
+ OSStatus result;
/*
* Require at least a protocol and host for removal, which is what git
@@ -90,25 +260,72 @@ static void delete_internet_password(void)
* Keychain manager.
*/
if (!protocol || !host)
- return;
+ return -1;
- if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item))
- return;
+ attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitAll,
+ kSecReturnRef, kCFBooleanTrue,
+ NULL);
+ result = SecItemCopyMatching(attrs, (CFTypeRef *)&refs);
+ CFRelease(attrs);
+
+ if (!result) {
+ for (CFIndex i = 0; !result && i < CFArrayGetCount(refs); i++)
+ result = delete_ref(CFArrayGetValueAtIndex(refs, i));
+
+ CFRelease(refs);
+ }
- SecKeychainItemDelete(item);
+ /* We consider not found to not be an error */
+ if (result == errSecItemNotFound)
+ result = errSecSuccess;
+
+ return result;
}
-static void add_internet_password(void)
+static OSStatus add_internet_password(void)
{
+ CFMutableDataRef data;
+ CFDictionaryRef attrs;
+ OSStatus result;
+
+ if (state_seen)
+ return errSecSuccess;
+
/* Only store complete credentials */
if (!protocol || !host || !username || !password)
- return;
+ return -1;
- if (SecKeychainAddInternetPassword(
- KEYCHAIN_ARGS,
- KEYCHAIN_ITEM(password),
- NULL))
- return;
+ data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password);
+ if (password_expiry_utc) {
+ CFDataAppendBytes(data,
+ (const UInt8 *)STRING_WITH_LENGTH("\npassword_expiry_utc="));
+ CFDataAppendBytes(data,
+ CFDataGetBytePtr(password_expiry_utc),
+ CFDataGetLength(password_expiry_utc));
+ }
+ if (oauth_refresh_token) {
+ CFDataAppendBytes(data,
+ (const UInt8 *)STRING_WITH_LENGTH("\noauth_refresh_token="));
+ CFDataAppendBytes(data,
+ CFDataGetBytePtr(oauth_refresh_token),
+ CFDataGetLength(oauth_refresh_token));
+ }
+
+ attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, data,
+ NULL);
+
+ result = SecItemAdd(attrs, NULL);
+ if (result == errSecDuplicateItem) {
+ CFDictionaryRef query;
+ query = CREATE_SEC_ATTRIBUTES(NULL);
+ result = SecItemUpdate(query, attrs);
+ CFRelease(query);
+ }
+
+ CFRelease(data);
+ CFRelease(attrs);
+
+ return result;
}
static void read_credential(void)
@@ -131,36 +348,64 @@ static void read_credential(void)
if (!strcmp(buf, "protocol")) {
if (!strcmp(v, "imap"))
- protocol = kSecProtocolTypeIMAP;
+ protocol = kSecAttrProtocolIMAP;
else if (!strcmp(v, "imaps"))
- protocol = kSecProtocolTypeIMAPS;
+ protocol = kSecAttrProtocolIMAPS;
else if (!strcmp(v, "ftp"))
- protocol = kSecProtocolTypeFTP;
+ protocol = kSecAttrProtocolFTP;
else if (!strcmp(v, "ftps"))
- protocol = kSecProtocolTypeFTPS;
+ protocol = kSecAttrProtocolFTPS;
else if (!strcmp(v, "https"))
- protocol = kSecProtocolTypeHTTPS;
+ protocol = kSecAttrProtocolHTTPS;
else if (!strcmp(v, "http"))
- protocol = kSecProtocolTypeHTTP;
+ protocol = kSecAttrProtocolHTTP;
else if (!strcmp(v, "smtp"))
- protocol = kSecProtocolTypeSMTP;
- else /* we don't yet handle other protocols */
+ protocol = kSecAttrProtocolSMTP;
+ else {
+ /* we don't yet handle other protocols */
+ clear_credential();
exit(0);
+ }
}
else if (!strcmp(buf, "host")) {
char *colon = strchr(v, ':');
if (colon) {
+ UInt16 port_i;
*colon++ = '\0';
- port = atoi(colon);
+ port_i = atoi(colon);
+ port = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberShortType,
+ &port_i);
}
- host = xstrdup(v);
+ host = CFStringCreateWithCString(kCFAllocatorDefault,
+ v,
+ ENCODING);
}
else if (!strcmp(buf, "path"))
- path = xstrdup(v);
+ path = CFStringCreateWithCString(kCFAllocatorDefault,
+ v,
+ ENCODING);
else if (!strcmp(buf, "username"))
- username = xstrdup(v);
+ username = CFStringCreateWithCString(
+ kCFAllocatorDefault,
+ v,
+ ENCODING);
else if (!strcmp(buf, "password"))
- password = xstrdup(v);
+ password = CFDataCreate(kCFAllocatorDefault,
+ (UInt8 *)v,
+ strlen(v));
+ else if (!strcmp(buf, "password_expiry_utc"))
+ password_expiry_utc = CFDataCreate(kCFAllocatorDefault,
+ (UInt8 *)v,
+ strlen(v));
+ else if (!strcmp(buf, "oauth_refresh_token"))
+ oauth_refresh_token = CFDataCreate(kCFAllocatorDefault,
+ (UInt8 *)v,
+ strlen(v));
+ else if (!strcmp(buf, "state[]")) {
+ if (!strcmp(v, "osxkeychain:seen=1"))
+ state_seen = 1;
+ }
/*
* Ignore other lines; we don't know what they mean, but
* this future-proofs us when later versions of git do
@@ -173,21 +418,30 @@ static void read_credential(void)
int main(int argc, const char **argv)
{
+ OSStatus result = 0;
const char *usage =
"usage: git credential-osxkeychain <get|store|erase>";
if (!argv[1])
die("%s", usage);
+ if (open(argv[0], O_RDONLY | O_EXLOCK) == -1)
+ die("failed to lock %s", argv[0]);
+
read_credential();
if (!strcmp(argv[1], "get"))
- find_internet_password();
+ result = find_internet_password();
else if (!strcmp(argv[1], "store"))
- add_internet_password();
+ result = add_internet_password();
else if (!strcmp(argv[1], "erase"))
- delete_internet_password();
+ result = delete_internet_password();
/* otherwise, ignore unknown action */
+ if (result)
+ die("failed to %s: %d", argv[1], (int)result);
+
+ clear_credential();
+
return 0;
}
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 96f10613ae..4be0d58cd8 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -35,7 +35,7 @@ static void *xmalloc(size_t size)
}
static WCHAR *wusername, *password, *protocol, *host, *path, target[1024],
- *password_expiry_utc;
+ *password_expiry_utc, *oauth_refresh_token;
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
{
@@ -109,7 +109,18 @@ static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
return match_part_with_last(ptarget, want, delim, 1);
}
-static int match_cred(const CREDENTIALW *cred)
+static int match_cred_password(const CREDENTIALW *cred) {
+ int ret;
+ WCHAR *cred_password = xmalloc(cred->CredentialBlobSize);
+ wcsncpy_s(cred_password, cred->CredentialBlobSize,
+ (LPCWSTR)cred->CredentialBlob,
+ cred->CredentialBlobSize / sizeof(WCHAR));
+ ret = !wcscmp(cred_password, password);
+ free(cred_password);
+ return ret;
+}
+
+static int match_cred(const CREDENTIALW *cred, int match_password)
{
LPCWSTR target = cred->TargetName;
if (wusername && wcscmp(wusername, cred->UserName ? cred->UserName : L""))
@@ -119,7 +130,8 @@ static int match_cred(const CREDENTIALW *cred)
match_part(&target, protocol, L"://") &&
match_part_last(&target, wusername, L"@") &&
match_part(&target, host, L"/") &&
- match_part(&target, path, L"");
+ match_part(&target, path, L"") &&
+ (!match_password || match_cred_password(cred));
}
static void get_credential(void)
@@ -128,18 +140,38 @@ static void get_credential(void)
DWORD num_creds;
int i;
CREDENTIAL_ATTRIBUTEW *attr;
+ WCHAR *secret;
+ WCHAR *line;
+ WCHAR *remaining_lines;
+ WCHAR *part;
+ WCHAR *remaining_parts;
if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
return;
/* search for the first credential that matches username */
for (i = 0; i < num_creds; ++i)
- if (match_cred(creds[i])) {
+ if (match_cred(creds[i], 0)) {
write_item("username", creds[i]->UserName,
creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
- write_item("password",
- (LPCWSTR)creds[i]->CredentialBlob,
- creds[i]->CredentialBlobSize / sizeof(WCHAR));
+ if (creds[i]->CredentialBlobSize > 0) {
+ secret = xmalloc(creds[i]->CredentialBlobSize);
+ wcsncpy_s(secret, creds[i]->CredentialBlobSize, (LPCWSTR)creds[i]->CredentialBlob, creds[i]->CredentialBlobSize / sizeof(WCHAR));
+ line = wcstok_s(secret, L"\r\n", &remaining_lines);
+ write_item("password", line, line ? wcslen(line) : 0);
+ while(line != NULL) {
+ part = wcstok_s(line, L"=", &remaining_parts);
+ if (!wcscmp(part, L"oauth_refresh_token")) {
+ write_item("oauth_refresh_token", remaining_parts, remaining_parts ? wcslen(remaining_parts) : 0);
+ }
+ line = wcstok_s(NULL, L"\r\n", &remaining_lines);
+ }
+ free(secret);
+ } else {
+ 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")) {
@@ -158,16 +190,26 @@ static void store_credential(void)
{
CREDENTIALW cred;
CREDENTIAL_ATTRIBUTEW expiry_attr;
+ WCHAR *secret;
+ int wlen;
if (!wusername || !password)
return;
+ if (oauth_refresh_token) {
+ wlen = _scwprintf(L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
+ secret = xmalloc(sizeof(WCHAR) * wlen);
+ _snwprintf_s(secret, sizeof(WCHAR) * wlen, wlen, L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
+ } else {
+ secret = _wcsdup(password);
+ }
+
cred.Flags = 0;
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = target;
cred.Comment = L"saved by git-credential-wincred";
- cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR);
- cred.CredentialBlob = (LPVOID)password;
+ cred.CredentialBlobSize = wcslen(secret) * sizeof(WCHAR);
+ cred.CredentialBlob = (LPVOID)_wcsdup(secret);
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
cred.AttributeCount = 0;
cred.Attributes = NULL;
@@ -182,6 +224,8 @@ static void store_credential(void)
cred.TargetAlias = NULL;
cred.UserName = wusername;
+ free(secret);
+
if (!CredWriteW(&cred, 0))
die("CredWrite failed");
}
@@ -196,7 +240,7 @@ static void erase_credential(void)
return;
for (i = 0; i < num_creds; ++i) {
- if (match_cred(creds[i]))
+ if (match_cred(creds[i], password != NULL))
CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);
}
@@ -253,6 +297,8 @@ static void read_credential(void)
password = utf8_to_utf16_dup(v);
else if (!strcmp(buf, "password_expiry_utc"))
password_expiry_utc = utf8_to_utf16_dup(v);
+ else if (!strcmp(buf, "oauth_refresh_token"))
+ oauth_refresh_token = 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
diff --git a/contrib/diff-highlight/DiffHighlight.pm b/contrib/diff-highlight/DiffHighlight.pm
index 376f577737..636add6968 100644
--- a/contrib/diff-highlight/DiffHighlight.pm
+++ b/contrib/diff-highlight/DiffHighlight.pm
@@ -1,6 +1,6 @@
package DiffHighlight;
-use 5.008;
+use 5.008001;
use warnings FATAL => 'all';
use strict;
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 40c4b0d111..3f69675961 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -9,7 +9,7 @@ The <mode> parameter is one of:
diff: elements are diff hunks. Arguments are given to diff.
-merge: elements are merge conflicts. Arguments are ignored.
+merge: elements are merge conflicts. Arguments are given to ls-files -u.
grep: elements are grep hits. Arguments are given to git grep or, if
configured, to the command in `jump.grepCmd`.
@@ -44,13 +44,13 @@ open_editor() {
mode_diff() {
git diff --no-prefix --relative "$@" |
perl -ne '
- if (m{^\+\+\+ (.*)}) { $file = $1; next }
+ if (m{^\+\+\+ (.*)}) { $file = $1 eq "/dev/null" ? undef : $1; next }
defined($file) or next;
if (m/^@@ .*?\+(\d+)/) { $line = $1; next }
defined($line) or next;
if (/^ /) { $line++; next }
if (/^[-+]\s*(.*)/) {
- print "$file:$line: $1\n";
+ print "$file:$line:1: $1\n";
$line = undef;
}
'
diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py
deleted file mode 100755
index 7eb1b24cc7..0000000000
--- a/contrib/hg-to-git/hg-to-git.py
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/env python
-
-""" hg-to-git.py - A Mercurial to GIT converter
-
- Copyright (C)2007 Stelian Pop <stelian@popies.net>
-
- 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, 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/>.
-"""
-
-import os, os.path, sys
-import tempfile, pickle, getopt
-import re
-
-if sys.hexversion < 0x02030000:
- # The behavior of the pickle module changed significantly in 2.3
- sys.stderr.write("hg-to-git.py: requires Python 2.3 or later.\n")
- sys.exit(1)
-
-# Maps hg version -> git version
-hgvers = {}
-# List of children for each hg revision
-hgchildren = {}
-# List of parents for each hg revision
-hgparents = {}
-# Current branch for each hg revision
-hgbranch = {}
-# Number of new changesets converted from hg
-hgnewcsets = 0
-
-#------------------------------------------------------------------------------
-
-def usage():
-
- print("""\
-%s: [OPTIONS] <hgprj>
-
-options:
- -s, --gitstate=FILE: name of the state to be saved/read
- for incrementals
- -n, --nrepack=INT: number of changesets that will trigger
- a repack (default=0, -1 to deactivate)
- -v, --verbose: be verbose
-
-required:
- hgprj: name of the HG project to import (directory)
-""" % sys.argv[0])
-
-#------------------------------------------------------------------------------
-
-def getgitenv(user, date):
- env = ''
- elems = re.compile('(.*?)\s+<(.*)>').match(user)
- if elems:
- env += 'export GIT_AUTHOR_NAME="%s" ;' % elems.group(1)
- env += 'export GIT_COMMITTER_NAME="%s" ;' % elems.group(1)
- env += 'export GIT_AUTHOR_EMAIL="%s" ;' % elems.group(2)
- env += 'export GIT_COMMITTER_EMAIL="%s" ;' % elems.group(2)
- else:
- env += 'export GIT_AUTHOR_NAME="%s" ;' % user
- env += 'export GIT_COMMITTER_NAME="%s" ;' % user
- env += 'export GIT_AUTHOR_EMAIL= ;'
- env += 'export GIT_COMMITTER_EMAIL= ;'
-
- env += 'export GIT_AUTHOR_DATE="%s" ;' % date
- env += 'export GIT_COMMITTER_DATE="%s" ;' % date
- return env
-
-#------------------------------------------------------------------------------
-
-state = ''
-opt_nrepack = 0
-verbose = False
-
-try:
- opts, args = getopt.getopt(sys.argv[1:], 's:t:n:v', ['gitstate=', 'tempdir=', 'nrepack=', 'verbose'])
- for o, a in opts:
- if o in ('-s', '--gitstate'):
- state = a
- state = os.path.abspath(state)
- if o in ('-n', '--nrepack'):
- opt_nrepack = int(a)
- if o in ('-v', '--verbose'):
- verbose = True
- if len(args) != 1:
- raise Exception('params')
-except:
- usage()
- sys.exit(1)
-
-hgprj = args[0]
-os.chdir(hgprj)
-
-if state:
- if os.path.exists(state):
- if verbose:
- print('State does exist, reading')
- f = open(state, 'r')
- hgvers = pickle.load(f)
- else:
- print('State does not exist, first run')
-
-sock = os.popen('hg tip --template "{rev}"')
-tip = sock.read()
-if sock.close():
- sys.exit(1)
-if verbose:
- print('tip is', tip)
-
-# Calculate the branches
-if verbose:
- print('analysing the branches...')
-hgchildren["0"] = ()
-hgparents["0"] = (None, None)
-hgbranch["0"] = "master"
-for cset in range(1, int(tip) + 1):
- hgchildren[str(cset)] = ()
- prnts = os.popen('hg log -r %d --template "{parents}"' % cset).read().strip().split(' ')
- prnts = map(lambda x: x[:x.find(':')], prnts)
- if prnts[0] != '':
- parent = prnts[0].strip()
- else:
- parent = str(cset - 1)
- hgchildren[parent] += ( str(cset), )
- if len(prnts) > 1:
- mparent = prnts[1].strip()
- hgchildren[mparent] += ( str(cset), )
- else:
- mparent = None
-
- hgparents[str(cset)] = (parent, mparent)
-
- if mparent:
- # For merge changesets, take either one, preferably the 'master' branch
- if hgbranch[mparent] == 'master':
- hgbranch[str(cset)] = 'master'
- else:
- hgbranch[str(cset)] = hgbranch[parent]
- else:
- # Normal changesets
- # For first children, take the parent branch, for the others create a new branch
- if hgchildren[parent][0] == str(cset):
- hgbranch[str(cset)] = hgbranch[parent]
- else:
- hgbranch[str(cset)] = "branch-" + str(cset)
-
-if "0" not in hgvers:
- print('creating repository')
- os.system('git init')
-
-# loop through every hg changeset
-for cset in range(int(tip) + 1):
-
- # incremental, already seen
- if str(cset) in hgvers:
- continue
- hgnewcsets += 1
-
- # get info
- log_data = os.popen('hg log -r %d --template "{tags}\n{date|date}\n{author}\n"' % cset).readlines()
- tag = log_data[0].strip()
- date = log_data[1].strip()
- user = log_data[2].strip()
- parent = hgparents[str(cset)][0]
- mparent = hgparents[str(cset)][1]
-
- #get comment
- (fdcomment, filecomment) = tempfile.mkstemp()
- csetcomment = os.popen('hg log -r %d --template "{desc}"' % cset).read().strip()
- os.write(fdcomment, csetcomment)
- os.close(fdcomment)
-
- print('-----------------------------------------')
- print('cset:', cset)
- print('branch:', hgbranch[str(cset)])
- print('user:', user)
- print('date:', date)
- print('comment:', csetcomment)
- if parent:
- print('parent:', parent)
- if mparent:
- print('mparent:', mparent)
- if tag:
- print('tag:', tag)
- print('-----------------------------------------')
-
- # checkout the parent if necessary
- if cset != 0:
- if hgbranch[str(cset)] == "branch-" + str(cset):
- print('creating new branch', hgbranch[str(cset)])
- os.system('git checkout -b %s %s' % (hgbranch[str(cset)], hgvers[parent]))
- else:
- print('checking out branch', hgbranch[str(cset)])
- os.system('git checkout %s' % hgbranch[str(cset)])
-
- # merge
- if mparent:
- if hgbranch[parent] == hgbranch[str(cset)]:
- otherbranch = hgbranch[mparent]
- else:
- otherbranch = hgbranch[parent]
- print('merging', otherbranch, 'into', hgbranch[str(cset)])
- os.system(getgitenv(user, date) + 'git merge --no-commit -s ours "" %s %s' % (hgbranch[str(cset)], otherbranch))
-
- # remove everything except .git and .hg directories
- os.system('find . \( -path "./.hg" -o -path "./.git" \) -prune -o ! -name "." -print | xargs rm -rf')
-
- # repopulate with checkouted files
- os.system('hg update -C %d' % cset)
-
- # add new files
- os.system('git ls-files -x .hg --others | git update-index --add --stdin')
- # delete removed files
- os.system('git ls-files -x .hg --deleted | git update-index --remove --stdin')
-
- # commit
- os.system(getgitenv(user, date) + 'git commit --allow-empty --allow-empty-message -a -F %s' % filecomment)
- os.unlink(filecomment)
-
- # tag
- if tag and tag != 'tip':
- os.system(getgitenv(user, date) + 'git tag %s' % tag)
-
- # delete branch if not used anymore...
- if mparent and len(hgchildren[str(cset)]):
- print("Deleting unused branch:", otherbranch)
- os.system('git branch -d %s' % otherbranch)
-
- # retrieve and record the version
- vvv = os.popen('git show --quiet --pretty=format:%H').read()
- print('record', cset, '->', vvv)
- hgvers[str(cset)] = vvv
-
-if hgnewcsets >= opt_nrepack and opt_nrepack != -1:
- os.system('git repack -a -d')
-
-# write the state for incrementals
-if state:
- if verbose:
- print('Writing state')
- f = open(state, 'w')
- pickle.dump(hgvers, f)
-
-# vim: et ts=8 sw=4 sts=4
diff --git a/contrib/hg-to-git/hg-to-git.txt b/contrib/hg-to-git/hg-to-git.txt
deleted file mode 100644
index 91f8fe6410..0000000000
--- a/contrib/hg-to-git/hg-to-git.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-hg-to-git.py is able to convert a Mercurial repository into a git one,
-and preserves the branches in the process (unlike tailor)
-
-hg-to-git.py can probably be greatly improved (it's a rather crude
-combination of shell and python) but it does already work quite well for
-me. Features:
- - supports incremental conversion
- (for keeping a git repo in sync with a hg one)
- - supports hg branches
- - converts hg tags
-
-Note that the git repository will be created 'in place' (at the same
-location as the source hg repo). You will have to manually remove the
-'.hg' directory after the conversion.
-
-Also note that the incremental conversion uses 'simple' hg changesets
-identifiers (ordinals, as opposed to SHA-1 ids), and since these ids
-are not stable across different repositories the hg-to-git.py state file
-is forever tied to one hg repository.
-
-Stelian Pop <stelian@popies.net>
diff --git a/contrib/mw-to-git/Git/Mediawiki.pm b/contrib/mw-to-git/Git/Mediawiki.pm
index 917d9e2d32..ff7811225e 100644
--- a/contrib/mw-to-git/Git/Mediawiki.pm
+++ b/contrib/mw-to-git/Git/Mediawiki.pm
@@ -1,6 +1,6 @@
package Git::Mediawiki;
-use 5.008;
+use 5.008001;
use strict;
use POSIX;
use Git;
diff --git a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
index 6187ec67fa..7139995a40 100755
--- a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
+++ b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
@@ -161,7 +161,7 @@ test_expect_success 'git push properly warns about insufficient permissions' '
git add foo.forbidden &&
git commit -m "add a file" &&
git push 2>actual &&
- test_i18ngrep "foo.forbidden is not a permitted file" actual
+ test_grep "foo.forbidden is not a permitted file" actual
)
'
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 7db4c45676..15ae86db1b 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -33,19 +33,19 @@ git subtree split --prefix=<prefix> [<commit>]
git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <refspec>
--
-h,help show the help
-q,quiet quiet
-d,debug show debug messages
+h,help! show the help
+q,quiet! quiet
+d,debug! show debug messages
P,prefix= the name of the subdir to split out
options for 'split' (also: 'push')
annotate= add a prefix to commit message of new commits
-b,branch= create a new branch from the split subtree
+b,branch!= create a new branch from the split subtree
ignore-joins ignore prior --rejoin commits
onto= try connecting new tree to an existing one
rejoin merge the new branch back into HEAD
options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
squash merge subtree changes as a single commit
-m,message= use the given message as the commit message for the merge commit
+m,message!= use the given message as the commit message for the merge commit
"
indent=0
@@ -373,7 +373,8 @@ try_remove_previous () {
# Usage: process_subtree_split_trailer SPLIT_HASH MAIN_HASH [REPOSITORY]
process_subtree_split_trailer () {
- assert test $# = 2 -o $# = 3
+ assert test $# -ge 2
+ assert test $# -le 3
b="$1"
sq="$2"
repository=""
@@ -402,7 +403,8 @@ process_subtree_split_trailer () {
# Usage: find_latest_squash DIR [REPOSITORY]
find_latest_squash () {
- assert test $# = 1 -o $# = 2
+ assert test $# -ge 1
+ assert test $# -le 2
dir="$1"
repository=""
if test "$#" = 2
@@ -455,7 +457,8 @@ find_latest_squash () {
# Usage: find_existing_splits DIR REV [REPOSITORY]
find_existing_splits () {
- assert test $# = 2 -o $# = 3
+ assert test $# -ge 2
+ assert test $# -le 3
debug "Looking for prior splits..."
local indent=$(($indent + 1))
@@ -489,13 +492,13 @@ find_existing_splits () {
;;
END)
debug "Main is: '$main'"
- if test -z "$main" -a -n "$sub"
+ if test -z "$main" && test -n "$sub"
then
# squash commits refer to a subtree
debug " Squash: $sq from $sub"
cache_set "$sq" "$sub"
fi
- if test -n "$main" -a -n "$sub"
+ if test -n "$main" && test -n "$sub"
then
debug " Prior: $main -> $sub"
cache_set $main $sub
@@ -638,10 +641,16 @@ subtree_for_commit () {
while read mode type tree name
do
assert test "$name" = "$dir"
- assert test "$type" = "tree" -o "$type" = "commit"
- test "$type" = "commit" && continue # ignore submodules
- echo $tree
- break
+
+ case "$type" in
+ commit)
+ continue;; # ignore submodules
+ tree)
+ echo $tree
+ break;;
+ *)
+ die "fatal: tree entry is of type ${type}, expected tree or commit";;
+ esac
done || exit $?
}
@@ -778,6 +787,22 @@ ensure_valid_ref_format () {
die "fatal: '$1' does not look like a ref"
}
+# Usage: check if a commit from another subtree should be
+# ignored from processing for splits
+should_ignore_subtree_split_commit () {
+ assert test $# = 1
+ local rev="$1"
+ if test -n "$(git log -1 --grep="git-subtree-dir:" $rev)"
+ then
+ if test -z "$(git log -1 --grep="git-subtree-mainline:" $rev)" &&
+ test -z "$(git log -1 --grep="git-subtree-dir: $arg_prefix$" $rev)"
+ then
+ return 0
+ fi
+ fi
+ return 1
+}
+
# Usage: process_split_commit REV PARENTS
process_split_commit () {
assert test $# = 2
@@ -916,12 +941,12 @@ cmd_split () {
if test $# -eq 0
then
rev=$(git rev-parse HEAD)
- elif test $# -eq 1 -o $# -eq 2
+ elif test $# -eq 1 || test $# -eq 2
then
rev=$(git rev-parse -q --verify "$1^{commit}") ||
die "fatal: '$1' does not refer to a commit"
else
- die "fatal: you must provide exactly one revision, and optionnally a repository. Got: '$*'"
+ die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'"
fi
repository=""
if test "$#" = 2
@@ -963,7 +988,19 @@ cmd_split () {
eval "$grl" |
while read rev parents
do
- process_split_commit "$rev" "$parents"
+ if should_ignore_subtree_split_commit "$rev"
+ then
+ continue
+ fi
+ parsedparents=''
+ for parent in $parents
+ do
+ if ! should_ignore_subtree_split_commit "$parent"
+ then
+ parsedparents="$parsedparents$parent "
+ fi
+ done
+ process_split_commit "$rev" "$parsedparents"
done || exit $?
latest_new=$(cache_get latest_new) || exit $?
@@ -1006,8 +1043,11 @@ cmd_split () {
# Usage: cmd_merge REV [REPOSITORY]
cmd_merge () {
- test $# -eq 1 -o $# -eq 2 ||
+ if test $# -lt 1 || test $# -gt 2
+ then
die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'"
+ fi
+
rev=$(git rev-parse -q --verify "$1^{commit}") ||
die "fatal: '$1' does not refer to a commit"
repository=""
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 341c169eca..3c6103f6d2 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -47,7 +47,7 @@ last_commit_subject () {
# pre-2.32.0 versions of 'git subtree' would write the hash of the tag
# (sub1 below), instead of the commit (sub1^{commit}) in the
# "git-subtree-split" trailer.
-# We immitate this behaviour below using a replace ref.
+# We imitate this behaviour below using a replace ref.
# This function creates 3 repositories:
# - $1
# - $1-sub (added as subtree "sub" in $1)
@@ -63,7 +63,7 @@ test_create_pre2_32_repo () {
git -C "$1" log -1 --format=%B HEAD^2 >msg &&
test_commit -C "$1-sub" --annotate sub2 &&
git clone --no-local "$1" "$1-clone" &&
- new_commit=$(cat msg | sed -e "s/$commit/$tag/" | git -C "$1-clone" commit-tree HEAD^2^{tree}) &&
+ new_commit=$(sed -e "s/$commit/$tag/" msg | git -C "$1-clone" commit-tree HEAD^2^{tree}) &&
git -C "$1-clone" replace HEAD^2 $new_commit
}
@@ -71,7 +71,7 @@ test_expect_success 'shows short help text for -h' '
test_expect_code 129 git subtree -h >out 2>err &&
test_must_be_empty err &&
grep -e "^ *or: git subtree pull" out &&
- grep -e --annotate out
+ grep -F -e "--[no-]annotate" out
'
#
@@ -385,6 +385,46 @@ test_expect_success 'split sub dir/ with --rejoin' '
)
'
+# Tests that commits from other subtrees are not processed as
+# part of a split.
+#
+# This test performs the following:
+# - Creates Repo with subtrees 'subA' and 'subB'
+# - Creates commits in the repo including changes to subtrees
+# - Runs the following 'split' and commit' commands in order:
+# - Perform 'split' on subtree A
+# - Perform 'split' on subtree B
+# - Create new commits with changes to subtree A and B
+# - Perform split on subtree A
+# - Check that the commits in subtree B are not processed
+# as part of the subtree A split
+test_expect_success 'split with multiple subtrees' '
+ subtree_test_create_repo "$test_count" &&
+ subtree_test_create_repo "$test_count/subA" &&
+ subtree_test_create_repo "$test_count/subB" &&
+ test_create_commit "$test_count" main1 &&
+ test_create_commit "$test_count/subA" subA1 &&
+ test_create_commit "$test_count/subA" subA2 &&
+ test_create_commit "$test_count/subA" subA3 &&
+ test_create_commit "$test_count/subB" subB1 &&
+ git -C "$test_count" fetch ./subA HEAD &&
+ git -C "$test_count" subtree add --prefix=subADir FETCH_HEAD &&
+ git -C "$test_count" fetch ./subB HEAD &&
+ git -C "$test_count" subtree add --prefix=subBDir FETCH_HEAD &&
+ test_create_commit "$test_count" subADir/main-subA1 &&
+ test_create_commit "$test_count" subBDir/main-subB1 &&
+ git -C "$test_count" subtree split --prefix=subADir \
+ --squash --rejoin -m "Sub A Split 1" &&
+ git -C "$test_count" subtree split --prefix=subBDir \
+ --squash --rejoin -m "Sub B Split 1" &&
+ test_create_commit "$test_count" subADir/main-subA2 &&
+ test_create_commit "$test_count" subBDir/main-subB2 &&
+ git -C "$test_count" subtree split --prefix=subADir \
+ --squash --rejoin -m "Sub A Split 2" &&
+ test "$(git -C "$test_count" subtree split --prefix=subBDir \
+ --squash --rejoin -d -m "Sub B Split 1" 2>&1 | grep -w "\[1\]")" = ""
+'
+
test_expect_success 'split sub dir/ with --rejoin from scratch' '
subtree_test_create_repo "$test_count" &&
test_create_commit "$test_count" main1 &&
diff --git a/contrib/vscode/init.sh b/contrib/vscode/init.sh
index 521d303722..f2d61bb0e6 100755
--- a/contrib/vscode/init.sh
+++ b/contrib/vscode/init.sh
@@ -92,7 +92,6 @@ cat >.vscode/settings.json.new <<\EOF ||
"isexe",
"iskeychar",
"kompare",
- "mksnpath",
"mktag",
"mktree",
"mmblob",
diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 888c34a521..989197aace 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -79,7 +79,7 @@ trap cleanup $siglist
# create the links to the original repo. explicitly exclude index, HEAD and
# logs/HEAD from the list since they are purely related to the current working
# directory, and should not be shared.
-for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
+for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn reftable
do
# create a containing directory if needed
case $x in
diff --git a/convert.c b/convert.c
index a8870baff3..c9a31eb4f0 100644
--- a/convert.c
+++ b/convert.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "config.h"
@@ -322,6 +324,9 @@ static void trace_encoding(const char *context, const char *path,
struct strbuf trace = STRBUF_INIT;
int i;
+ if (!trace_want(&coe))
+ return;
+
strbuf_addf(&trace, "%s (%s, considered %s):\n", context, path, encoding);
for (i = 0; i < len && buf; ++i) {
strbuf_addf(
@@ -345,30 +350,32 @@ static int check_roundtrip(const char *enc_name)
* space separated encodings (eg. "UTF-16, ASCII, CP1125").
* Search for the given encoding in that string.
*/
- const char *found = strcasestr(check_roundtrip_encoding, enc_name);
+ const char *encoding = check_roundtrip_encoding ?
+ check_roundtrip_encoding : "SHIFT-JIS";
+ const char *found = strcasestr(encoding, enc_name);
const char *next;
int len;
if (!found)
return 0;
next = found + strlen(enc_name);
- len = strlen(check_roundtrip_encoding);
+ len = strlen(encoding);
return (found && (
/*
- * check that the found encoding is at the
- * beginning of check_roundtrip_encoding or
- * that it is prefixed with a space or comma
+ * Check that the found encoding is at the beginning of
+ * encoding or that it is prefixed with a space or
+ * comma.
*/
- found == check_roundtrip_encoding || (
+ found == encoding || (
(isspace(found[-1]) || found[-1] == ',')
)
) && (
/*
- * check that the found encoding is at the
- * end of check_roundtrip_encoding or
- * that it is suffixed with a space or comma
+ * Check that the found encoding is at the end of
+ * encoding or that it is suffixed with a space
+ * or comma.
*/
- next == check_roundtrip_encoding + len || (
- next < check_roundtrip_encoding + len &&
+ next == encoding + len || (
+ next < encoding + len &&
(isspace(next[0]) || next[0] == ',')
)
));
@@ -956,7 +963,7 @@ int async_query_available_blobs(const char *cmd, struct string_list *available_p
while ((line = packet_read_line(process->out, NULL))) {
const char *path;
if (skip_prefix(line, "pathname=", &path))
- string_list_insert(available_paths, xstrdup(path));
+ string_list_insert(available_paths, path);
else
; /* ignore unknown keys */
}
@@ -979,9 +986,9 @@ done:
static struct convert_driver {
const char *name;
struct convert_driver *next;
- const char *smudge;
- const char *clean;
- const char *process;
+ char *smudge;
+ char *clean;
+ char *process;
int required;
} *user_convert, **user_convert_tail;
@@ -1028,7 +1035,7 @@ static int read_convert_config(const char *var, const char *value,
if (parse_config_key(var, "filter", &name, &namelen, &key) < 0 || !name)
return 0;
for (drv = user_convert; drv; drv = drv->next)
- if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
+ if (!xstrncmpz(drv->name, name, namelen))
break;
if (!drv) {
CALLOC_ARRAY(drv, 1);
@@ -1046,14 +1053,20 @@ static int read_convert_config(const char *var, const char *value,
* The command-line will not be interpolated in any way.
*/
- if (!strcmp("smudge", key))
+ if (!strcmp("smudge", key)) {
+ FREE_AND_NULL(drv->smudge);
return git_config_string(&drv->smudge, var, value);
+ }
- if (!strcmp("clean", key))
+ if (!strcmp("clean", key)) {
+ FREE_AND_NULL(drv->clean);
return git_config_string(&drv->clean, var, value);
+ }
- if (!strcmp("process", key))
+ if (!strcmp("process", key)) {
+ FREE_AND_NULL(drv->process);
return git_config_string(&drv->process, var, value);
+ }
if (!strcmp("required", key)) {
drv->required = git_config_bool(var, value);
@@ -1358,6 +1371,9 @@ void reset_parsed_attributes(void)
for (drv = user_convert; drv; drv = next) {
next = drv->next;
free((void *)drv->name);
+ free((void *)drv->smudge);
+ free((void *)drv->clean);
+ free((void *)drv->process);
free(drv);
}
user_convert = NULL;
diff --git a/convert.h b/convert.h
index d925589444..0a6e4086b8 100644
--- a/convert.h
+++ b/convert.h
@@ -4,7 +4,7 @@
#ifndef CONVERT_H
#define CONVERT_H
-#include "hash-ll.h"
+#include "hash.h"
#include "string-list.h"
struct index_state;
diff --git a/credential.c b/credential.c
index d664754163..6dea3859ec 100644
--- a/credential.c
+++ b/credential.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
@@ -11,6 +13,8 @@
#include "strbuf.h"
#include "urlmatch.h"
#include "git-compat-util.h"
+#include "trace2.h"
+#include "repository.h"
void credential_init(struct credential *c)
{
@@ -20,18 +24,68 @@ void credential_init(struct credential *c)
void credential_clear(struct credential *c)
{
+ credential_clear_secrets(c);
free(c->protocol);
free(c->host);
free(c->path);
free(c->username);
- free(c->password);
free(c->oauth_refresh_token);
+ free(c->authtype);
string_list_clear(&c->helpers, 0);
strvec_clear(&c->wwwauth_headers);
+ strvec_clear(&c->state_headers);
+ strvec_clear(&c->state_headers_to_send);
credential_init(c);
}
+void credential_next_state(struct credential *c)
+{
+ strvec_clear(&c->state_headers_to_send);
+ SWAP(c->state_headers, c->state_headers_to_send);
+}
+
+void credential_clear_secrets(struct credential *c)
+{
+ FREE_AND_NULL(c->password);
+ FREE_AND_NULL(c->credential);
+}
+
+static void credential_set_capability(struct credential_capability *capa,
+ enum credential_op_type op_type)
+{
+ switch (op_type) {
+ case CREDENTIAL_OP_INITIAL:
+ capa->request_initial = 1;
+ break;
+ case CREDENTIAL_OP_HELPER:
+ capa->request_helper = 1;
+ break;
+ case CREDENTIAL_OP_RESPONSE:
+ capa->response = 1;
+ break;
+ }
+}
+
+
+void credential_set_all_capabilities(struct credential *c,
+ enum credential_op_type op_type)
+{
+ credential_set_capability(&c->capa_authtype, op_type);
+ credential_set_capability(&c->capa_state, op_type);
+}
+
+static void announce_one(struct credential_capability *cc, const char *name, FILE *fp) {
+ if (cc->request_initial)
+ fprintf(fp, "capability %s\n", name);
+}
+
+void credential_announce_capabilities(struct credential *c, FILE *fp) {
+ fprintf(fp, "version 0\n");
+ announce_one(&c->capa_authtype, "authtype", fp);
+ announce_one(&c->capa_state, "state", fp);
+}
+
int credential_match(const struct credential *want,
const struct credential *have, int match_password)
{
@@ -40,7 +94,8 @@ int credential_match(const struct credential *want,
CHECK(host) &&
CHECK(path) &&
CHECK(username) &&
- (!match_password || CHECK(password));
+ (!match_password || CHECK(password)) &&
+ (!match_password || CHECK(credential));
#undef CHECK
}
@@ -88,8 +143,8 @@ static int proto_is_http(const char *s)
static void credential_describe(struct credential *c, struct strbuf *out);
static void credential_format(struct credential *c, struct strbuf *out);
-static int select_all(const struct urlmatch_item *a,
- const struct urlmatch_item *b)
+static int select_all(const struct urlmatch_item *a UNUSED,
+ const struct urlmatch_item *b UNUSED)
{
return 0;
}
@@ -198,17 +253,58 @@ static char *credential_ask_one(const char *what, struct credential *c,
return xstrdup(r);
}
-static void credential_getpass(struct credential *c)
+static int credential_getpass(struct credential *c)
{
+ int interactive;
+ char *value;
+ if (!git_config_get_maybe_bool("credential.interactive", &interactive) &&
+ !interactive) {
+ trace2_data_intmax("credential", the_repository,
+ "interactive/skipped", 1);
+ return -1;
+ }
+ if (!git_config_get_string("credential.interactive", &value)) {
+ int same = !strcmp(value, "never");
+ free(value);
+ if (same) {
+ trace2_data_intmax("credential", the_repository,
+ "interactive/skipped", 1);
+ return -1;
+ }
+ }
+
+ trace2_region_enter("credential", "interactive", the_repository);
if (!c->username)
c->username = credential_ask_one("Username", c,
PROMPT_ASKPASS|PROMPT_ECHO);
if (!c->password)
c->password = credential_ask_one("Password", c,
PROMPT_ASKPASS);
+ trace2_region_leave("credential", "interactive", the_repository);
+
+ return 0;
}
-int credential_read(struct credential *c, FILE *fp)
+int credential_has_capability(const struct credential_capability *capa,
+ enum credential_op_type op_type)
+{
+ /*
+ * We're checking here if each previous step indicated that we had the
+ * capability. If it did, then we want to pass it along; conversely, if
+ * it did not, we don't want to report that to our caller.
+ */
+ switch (op_type) {
+ case CREDENTIAL_OP_HELPER:
+ return capa->request_initial;
+ case CREDENTIAL_OP_RESPONSE:
+ return capa->request_initial && capa->request_helper;
+ default:
+ return 0;
+ }
+}
+
+int credential_read(struct credential *c, FILE *fp,
+ enum credential_op_type op_type)
{
struct strbuf line = STRBUF_INIT;
@@ -233,6 +329,9 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "password")) {
free(c->password);
c->password = xstrdup(value);
+ } else if (!strcmp(key, "credential")) {
+ free(c->credential);
+ c->credential = xstrdup(value);
} else if (!strcmp(key, "protocol")) {
free(c->protocol);
c->protocol = xstrdup(value);
@@ -242,8 +341,19 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "path")) {
free(c->path);
c->path = xstrdup(value);
+ } else if (!strcmp(key, "ephemeral")) {
+ c->ephemeral = !!git_config_bool("ephemeral", value);
} else if (!strcmp(key, "wwwauth[]")) {
strvec_push(&c->wwwauth_headers, value);
+ } else if (!strcmp(key, "state[]")) {
+ strvec_push(&c->state_headers, value);
+ } else if (!strcmp(key, "capability[]")) {
+ if (!strcmp(value, "authtype"))
+ credential_set_capability(&c->capa_authtype, op_type);
+ else if (!strcmp(value, "state"))
+ credential_set_capability(&c->capa_state, op_type);
+ } else if (!strcmp(key, "continue")) {
+ c->multistage = !!git_config_bool("continue", value);
} else if (!strcmp(key, "password_expiry_utc")) {
errno = 0;
c->password_expiry_utc = parse_timestamp(value, NULL, 10);
@@ -252,6 +362,9 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "oauth_refresh_token")) {
free(c->oauth_refresh_token);
c->oauth_refresh_token = xstrdup(value);
+ } else if (!strcmp(key, "authtype")) {
+ free(c->authtype);
+ c->authtype = xstrdup(value);
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
} else if (!strcmp(key, "quit")) {
@@ -280,8 +393,20 @@ static void credential_write_item(FILE *fp, const char *key, const char *value,
fprintf(fp, "%s=%s\n", key, value);
}
-void credential_write(const struct credential *c, FILE *fp)
+void credential_write(const struct credential *c, FILE *fp,
+ enum credential_op_type op_type)
{
+ if (credential_has_capability(&c->capa_authtype, op_type))
+ credential_write_item(fp, "capability[]", "authtype", 0);
+ if (credential_has_capability(&c->capa_state, op_type))
+ credential_write_item(fp, "capability[]", "state", 0);
+
+ if (credential_has_capability(&c->capa_authtype, op_type)) {
+ credential_write_item(fp, "authtype", c->authtype, 0);
+ credential_write_item(fp, "credential", c->credential, 0);
+ if (c->ephemeral)
+ credential_write_item(fp, "ephemeral", "1", 0);
+ }
credential_write_item(fp, "protocol", c->protocol, 1);
credential_write_item(fp, "host", c->host, 1);
credential_write_item(fp, "path", c->path, 0);
@@ -295,6 +420,12 @@ void credential_write(const struct credential *c, FILE *fp)
}
for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
+ if (credential_has_capability(&c->capa_state, op_type)) {
+ if (c->multistage)
+ credential_write_item(fp, "continue", "1", 0);
+ for (size_t i = 0; i < c->state_headers_to_send.nr; i++)
+ credential_write_item(fp, "state[]", c->state_headers_to_send.v[i], 0);
+ }
}
static int run_credential_helper(struct credential *c,
@@ -317,14 +448,14 @@ static int run_credential_helper(struct credential *c,
fp = xfdopen(helper.in, "w");
sigchain_push(SIGPIPE, SIG_IGN);
- credential_write(c, fp);
+ credential_write(c, fp, want_output ? CREDENTIAL_OP_HELPER : CREDENTIAL_OP_RESPONSE);
fclose(fp);
sigchain_pop(SIGPIPE);
if (want_output) {
int r;
fp = xfdopen(helper.out, "r");
- r = credential_read(c, fp);
+ r = credential_read(c, fp, CREDENTIAL_OP_HELPER);
fclose(fp);
if (r < 0) {
finish_command(&helper);
@@ -357,32 +488,45 @@ static int credential_do(struct credential *c, const char *helper,
return r;
}
-void credential_fill(struct credential *c)
+void credential_fill(struct credential *c, int all_capabilities)
{
int i;
- if (c->username && c->password)
+ if ((c->username && c->password) || c->credential)
return;
+ credential_next_state(c);
+ c->multistage = 0;
+
credential_apply_config(c);
+ if (all_capabilities)
+ credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL);
for (i = 0; i < c->helpers.nr; i++) {
credential_do(c, c->helpers.items[i].string, "get");
+
if (c->password_expiry_utc < time(NULL)) {
- /* Discard expired password */
- FREE_AND_NULL(c->password);
+ /*
+ * Don't use credential_clear() here: callers such as
+ * cmd_credential() expect to still be able to call
+ * credential_write() on a struct credential whose
+ * secrets have expired.
+ */
+ credential_clear_secrets(c);
/* Reset expiry to maintain consistency */
c->password_expiry_utc = TIME_MAX;
}
- if (c->username && c->password)
+ if ((c->username && c->password) || c->credential) {
+ strvec_clear(&c->wwwauth_headers);
return;
+ }
if (c->quit)
die("credential helper '%s' told us to quit",
c->helpers.items[i].string);
}
- credential_getpass(c);
- if (!c->username && !c->password)
+ if (credential_getpass(c) ||
+ (!c->username && !c->password && !c->credential))
die("unable to get password from user");
}
@@ -392,9 +536,11 @@ void credential_approve(struct credential *c)
if (c->approved)
return;
- if (!c->username || !c->password || c->password_expiry_utc < time(NULL))
+ if (((!c->username || !c->password) && !c->credential) || c->password_expiry_utc < time(NULL))
return;
+ credential_next_state(c);
+
credential_apply_config(c);
for (i = 0; i < c->helpers.nr; i++)
@@ -406,13 +552,15 @@ void credential_reject(struct credential *c)
{
int i;
+ credential_next_state(c);
+
credential_apply_config(c);
for (i = 0; i < c->helpers.nr; i++)
credential_do(c, c->helpers.items[i].string, "erase");
+ credential_clear_secrets(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;
diff --git a/credential.h b/credential.h
index acc41adf54..5f9e6ff2ef 100644
--- a/credential.h
+++ b/credential.h
@@ -5,8 +5,8 @@
#include "strvec.h"
/**
- * The credentials API provides an abstracted way of gathering username and
- * password credentials from the user.
+ * The credentials API provides an abstracted way of gathering
+ * authentication credentials from the user.
*
* Typical setup
* -------------
@@ -93,13 +93,35 @@
* -----------------------------------------------------------------------
*/
+/*
+ * These values define the kind of operation we're performing and the
+ * capabilities at each stage. The first is either an external request (via git
+ * credential fill) or an internal request (e.g., via the HTTP) code. The
+ * second is the call to the credential helper, and the third is the response
+ * we're providing.
+ *
+ * At each stage, we will emit the capability only if the previous stage
+ * supported it.
+ */
+enum credential_op_type {
+ CREDENTIAL_OP_INITIAL = 1,
+ CREDENTIAL_OP_HELPER = 2,
+ CREDENTIAL_OP_RESPONSE = 3,
+};
+
+struct credential_capability {
+ unsigned request_initial:1,
+ request_helper:1,
+ response:1;
+};
/**
- * This struct represents a single username/password combination
- * along with any associated context. All string fields should be
- * heap-allocated (or NULL if they are not known or not applicable).
- * The meaning of the individual context fields is the same as
- * their counterparts in the helper protocol.
+ * This struct represents a single login credential (typically a
+ * username/password combination) along with any associated
+ * context. All string fields should be heap-allocated (or NULL if
+ * they are not known or not applicable). The meaning of the
+ * individual context fields is the same as their counterparts in
+ * the helper protocol.
*
* This struct should always be initialized with `CREDENTIAL_INIT` or
* `credential_init`.
@@ -124,6 +146,16 @@ struct credential {
struct strvec wwwauth_headers;
/**
+ * A `strvec` of state headers received from credential helpers.
+ */
+ struct strvec state_headers;
+
+ /**
+ * A `strvec` of state headers to send to credential helpers.
+ */
+ struct strvec state_headers_to_send;
+
+ /**
* 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.
@@ -131,24 +163,38 @@ struct credential {
unsigned header_is_last_match:1;
unsigned approved:1,
+ ephemeral:1,
configured:1,
+ multistage: 1,
quit:1,
use_http_path:1,
username_from_proto:1;
+ struct credential_capability capa_authtype;
+ struct credential_capability capa_state;
+
char *username;
char *password;
+ char *credential;
char *protocol;
char *host;
char *path;
char *oauth_refresh_token;
timestamp_t password_expiry_utc;
+
+ /**
+ * The authorization scheme to use. If this is NULL, libcurl is free to
+ * negotiate any scheme it likes.
+ */
+ char *authtype;
};
#define CREDENTIAL_INIT { \
.helpers = STRING_LIST_INIT_DUP, \
.password_expiry_utc = TIME_MAX, \
.wwwauth_headers = STRVEC_INIT, \
+ .state_headers = STRVEC_INIT, \
+ .state_headers_to_send = STRVEC_INIT, \
}
/* Initialize a credential structure, setting all fields to empty. */
@@ -162,13 +208,17 @@ void credential_clear(struct credential *);
/**
* Instruct the credential subsystem to fill the username and
- * password fields of the passed credential struct by first
- * consulting helpers, then asking the user. After this function
- * returns, the username and password fields of the credential are
- * guaranteed to be non-NULL. If an error occurs, the function will
- * die().
+ * password (or authtype and credential) fields of the passed
+ * credential struct by first consulting helpers, then asking the
+ * user. After this function returns, either the username and
+ * password fields or the credential field of the credential are
+ * guaranteed to be non-NULL. If an error occurs, the function
+ * will die().
+ *
+ * If all_capabilities is set, this is an internal user that is prepared
+ * to deal with all known capabilities, and we should advertise that fact.
*/
-void credential_fill(struct credential *);
+void credential_fill(struct credential *, int all_capabilities);
/**
* Inform the credential subsystem that the provided credentials
@@ -184,15 +234,53 @@ void credential_approve(struct credential *);
* have been rejected. This will cause the credential subsystem to
* notify any helpers of the rejection (which allows them, for
* example, to purge the invalid credentials from storage). It
- * will also free() the username and password fields of the
- * credential and set them to NULL (readying the credential for
- * another call to `credential_fill`). Any errors from helpers are
- * ignored.
+ * will also free() the username, password, and credential fields
+ * of the credential and set them to NULL (readying the credential
+ * for another call to `credential_fill`). Any errors from helpers
+ * are ignored.
*/
void credential_reject(struct credential *);
-int credential_read(struct credential *, FILE *);
-void credential_write(const struct credential *, FILE *);
+/**
+ * Enable all of the supported credential flags in this credential.
+ */
+void credential_set_all_capabilities(struct credential *c,
+ enum credential_op_type op_type);
+
+/**
+ * Clear the secrets in this credential, but leave other data intact.
+ *
+ * This is useful for resetting credentials in preparation for a subsequent
+ * stage of filling.
+ */
+void credential_clear_secrets(struct credential *c);
+
+/**
+ * Print a list of supported capabilities and version numbers to standard
+ * output.
+ */
+void credential_announce_capabilities(struct credential *c, FILE *fp);
+
+/**
+ * Prepares the credential for the next iteration of the helper protocol by
+ * updating the state headers to send with the ones read by the last iteration
+ * of the protocol.
+ *
+ * Except for internal callers, this should be called exactly once between
+ * reading credentials with `credential_fill` and writing them.
+ */
+void credential_next_state(struct credential *c);
+
+/**
+ * Return true if the capability is enabled for an operation of op_type.
+ */
+int credential_has_capability(const struct credential_capability *capa,
+ enum credential_op_type op_type);
+
+int credential_read(struct credential *, FILE *,
+ enum credential_op_type);
+void credential_write(const struct credential *, FILE *,
+ enum credential_op_type);
/*
* Parse a url into a credential struct, replacing any existing contents.
diff --git a/csum-file.c b/csum-file.c
index cd01713244..c203ebf11b 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -7,6 +7,9 @@
* files. Useful when you write a file that you want to be
* able to verify hasn't been messed with afterwards.
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "progress.h"
#include "csum-file.h"
@@ -47,13 +50,13 @@ void hashflush(struct hashfile *f)
if (offset) {
if (!f->skip_hash)
- the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
+ the_hash_algo->unsafe_update_fn(&f->ctx, f->buffer, offset);
flush(f, f->buffer, offset);
f->offset = 0;
}
}
-static void free_hashfile(struct hashfile *f)
+void free_hashfile(struct hashfile *f)
{
free(f->buffer);
free(f->check_buffer);
@@ -68,12 +71,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
hashflush(f);
if (f->skip_hash)
- hashclr(f->buffer);
+ hashclr(f->buffer, the_repository->hash_algo);
else
- the_hash_algo->final_fn(f->buffer, &f->ctx);
+ the_hash_algo->unsafe_final_fn(f->buffer, &f->ctx);
if (result)
- hashcpy(result, f->buffer);
+ hashcpy(result, f->buffer, the_repository->hash_algo);
if (flags & CSUM_HASH_IN_STREAM)
flush(f, f->buffer, the_hash_algo->rawsz);
if (flags & CSUM_FSYNC)
@@ -99,6 +102,15 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
return fd;
}
+void discard_hashfile(struct hashfile *f)
+{
+ if (0 <= f->check_fd)
+ close(f->check_fd);
+ if (0 <= f->fd)
+ close(f->fd);
+ free_hashfile(f);
+}
+
void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
{
while (count) {
@@ -116,7 +128,7 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
* f->offset is necessarily zero.
*/
if (!f->skip_hash)
- the_hash_algo->update_fn(&f->ctx, buf, nr);
+ the_hash_algo->unsafe_update_fn(&f->ctx, buf, nr);
flush(f, buf, nr);
} else {
/*
@@ -162,7 +174,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
f->name = name;
f->do_crc = 0;
f->skip_hash = 0;
- the_hash_algo->init_fn(&f->ctx);
+ the_hash_algo->unsafe_init_fn(&f->ctx);
f->buffer_len = buffer_len;
f->buffer = xmalloc(buffer_len);
@@ -196,7 +208,7 @@ void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpo
{
hashflush(f);
checkpoint->offset = f->total;
- the_hash_algo->clone_fn(&checkpoint->ctx, &f->ctx);
+ the_hash_algo->unsafe_clone_fn(&checkpoint->ctx, &f->ctx);
}
int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
@@ -207,7 +219,7 @@ int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint
lseek(f->fd, offset, SEEK_SET) != offset)
return -1;
f->total = offset;
- f->ctx = checkpoint->ctx;
+ the_hash_algo->unsafe_clone_fn(&f->ctx, &checkpoint->ctx);
f->offset = 0; /* hashflush() was called in checkpoint */
return 0;
}
@@ -233,9 +245,9 @@ int hashfile_checksum_valid(const unsigned char *data, size_t total_len)
if (total_len < the_hash_algo->rawsz)
return 0; /* say "too short"? */
- the_hash_algo->init_fn(&ctx);
- the_hash_algo->update_fn(&ctx, data, data_len);
- the_hash_algo->final_fn(got, &ctx);
+ the_hash_algo->unsafe_init_fn(&ctx);
+ the_hash_algo->unsafe_update_fn(&ctx, data, data_len);
+ the_hash_algo->unsafe_final_fn(got, &ctx);
- return hasheq(got, data + data_len);
+ return hasheq(got, data + data_len, the_repository->hash_algo);
}
diff --git a/csum-file.h b/csum-file.h
index bc5bec27ac..7c73da0a40 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -1,7 +1,7 @@
#ifndef CSUM_FILE_H
#define CSUM_FILE_H
-#include "hash-ll.h"
+#include "hash.h"
#include "write-or-die.h"
struct progress;
@@ -46,7 +46,18 @@ int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
struct hashfile *hashfd(int fd, const char *name);
struct hashfile *hashfd_check(const char *name);
struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
+
+/*
+ * Free the hashfile without flushing its contents to disk. This only
+ * needs to be called when not calling `finalize_hashfile()`.
+ */
+void free_hashfile(struct hashfile *f);
+
+/*
+ * Finalize the hashfile by flushing data to disk and free'ing it.
+ */
int finalize_hashfile(struct hashfile *, unsigned char *, enum fsync_component, unsigned int);
+void discard_hashfile(struct hashfile *);
void hashwrite(struct hashfile *, const void *, unsigned int);
void hashflush(struct hashfile *f);
void crc32_begin(struct hashfile *);
diff --git a/daemon.c b/daemon.c
index 17d331b2f3..a40e435c63 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,7 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
#include "environment.h"
+#include "gettext.h"
#include "path.h"
#include "pkt-line.h"
#include "protocol.h"
@@ -1175,13 +1178,13 @@ static int service_loop(struct socketlist *socklist)
struct credentials;
-static void drop_privileges(struct credentials *cred)
+static void drop_privileges(struct credentials *cred UNUSED)
{
/* nothing */
}
-static struct credentials *prepare_credentials(const char *user_name,
- const char *group_name)
+static struct credentials *prepare_credentials(const char *user_name UNUSED,
+ const char *group_name UNUSED)
{
die("--user not supported on this platform");
}
@@ -1306,17 +1309,20 @@ int cmd_main(int argc, const char **argv)
continue;
}
if (skip_prefix(arg, "--timeout=", &v)) {
- timeout = atoi(v);
+ if (strtoul_ui(v, 10, &timeout))
+ die(_("invalid timeout '%s', expecting a non-negative integer"), v);
continue;
}
if (skip_prefix(arg, "--init-timeout=", &v)) {
- init_timeout = atoi(v);
+ if (strtoul_ui(v, 10, &init_timeout))
+ die(_("invalid init-timeout '%s', expecting a non-negative integer"), v);
continue;
}
if (skip_prefix(arg, "--max-connections=", &v)) {
- max_connections = atoi(v);
+ if (strtol_i(v, 10, &max_connections))
+ die(_("invalid max-connections '%s', expecting an integer"), v);
if (max_connections < 0)
- max_connections = 0; /* unlimited */
+ max_connections = 0; /* unlimited */
continue;
}
if (!strcmp(arg, "--strict-paths")) {
diff --git a/date.c b/date.c
index 619ada5b20..bee9fe8f10 100644
--- a/date.c
+++ b/date.c
@@ -207,13 +207,13 @@ void show_date_relative(timestamp_t time, struct strbuf *timebuf)
(diff + 183) / 365);
}
-struct date_mode *date_mode_from_type(enum date_mode_type type)
+struct date_mode date_mode_from_type(enum date_mode_type type)
{
- static struct date_mode mode = DATE_MODE_INIT;
+ struct date_mode mode = DATE_MODE_INIT;
if (type == DATE_STRFTIME)
BUG("cannot create anonymous strftime date_mode struct");
mode.type = type;
- return &mode;
+ return mode;
}
static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)
@@ -283,7 +283,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm
strbuf_addf(buf, " %+05d", tz);
}
-const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
+const char *show_date(timestamp_t time, int tz, struct date_mode mode)
{
struct tm *tm;
struct tm tmbuf = { 0 };
@@ -291,13 +291,13 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
int human_tz = -1;
static struct strbuf timebuf = STRBUF_INIT;
- if (mode->type == DATE_UNIX) {
+ if (mode.type == DATE_UNIX) {
strbuf_reset(&timebuf);
strbuf_addf(&timebuf, "%"PRItime, time);
return timebuf.buf;
}
- if (mode->type == DATE_HUMAN) {
+ if (mode.type == DATE_HUMAN) {
struct timeval now;
get_time(&now);
@@ -306,22 +306,22 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
human_tz = local_time_tzoffset(now.tv_sec, &human_tm);
}
- if (mode->local)
+ if (mode.local)
tz = local_tzoffset(time);
- if (mode->type == DATE_RAW) {
+ if (mode.type == DATE_RAW) {
strbuf_reset(&timebuf);
strbuf_addf(&timebuf, "%"PRItime" %+05d", time, tz);
return timebuf.buf;
}
- if (mode->type == DATE_RELATIVE) {
+ if (mode.type == DATE_RELATIVE) {
strbuf_reset(&timebuf);
show_date_relative(time, &timebuf);
return timebuf.buf;
}
- if (mode->local)
+ if (mode.local)
tm = time_to_tm_local(time, &tmbuf);
else
tm = time_to_tm(time, tz, &tmbuf);
@@ -331,35 +331,39 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
}
strbuf_reset(&timebuf);
- if (mode->type == DATE_SHORT)
+ if (mode.type == DATE_SHORT)
strbuf_addf(&timebuf, "%04d-%02d-%02d", tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mday);
- else if (mode->type == DATE_ISO8601)
+ else if (mode.type == DATE_ISO8601)
strbuf_addf(&timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+05d",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
tz);
- else if (mode->type == DATE_ISO8601_STRICT) {
- char sign = (tz >= 0) ? '+' : '-';
- tz = abs(tz);
- strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+ else if (mode.type == DATE_ISO8601_STRICT) {
+ strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec,
- sign, tz / 100, tz % 100);
- } else if (mode->type == DATE_RFC2822)
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ if (tz == 0) {
+ strbuf_addch(&timebuf, 'Z');
+ } else {
+ strbuf_addch(&timebuf, tz >= 0 ? '+' : '-');
+ tz = abs(tz);
+ strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100);
+ }
+ } else if (mode.type == DATE_RFC2822)
strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
weekday_names[tm->tm_wday], tm->tm_mday,
month_names[tm->tm_mon], tm->tm_year + 1900,
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
- else if (mode->type == DATE_STRFTIME)
- strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
- !mode->local);
+ else if (mode.type == DATE_STRFTIME)
+ strbuf_addftime(&timebuf, mode.strftime_fmt, tm, tz,
+ !mode.local);
else
- show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);
+ show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode.local);
return timebuf.buf;
}
@@ -864,6 +868,10 @@ static int match_object_header_date(const char *date, timestamp_t *timestamp, in
return 0;
}
+
+/* timestamp of 2099-12-31T23:59:59Z, including 32 leap days */
+static const timestamp_t timestamp_max = (((timestamp_t)2100 - 1970) * 365 + 32) * 24 * 60 * 60 - 1;
+
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
(i.e. English) day/month names, and it doesn't work correctly with %z. */
int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
@@ -933,8 +941,14 @@ int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
}
}
- if (!tm_gmt)
+ if (!tm_gmt) {
+ if (*offset > 0 && *offset * 60 > *timestamp)
+ return -1;
+ if (*offset < 0 && -*offset * 60 > timestamp_max - *timestamp)
+ return -1;
*timestamp -= *offset * 60;
+ }
+
return 0; /* success */
}
diff --git a/date.h b/date.h
index 6136212a19..0747864fd7 100644
--- a/date.h
+++ b/date.h
@@ -22,8 +22,8 @@ enum date_mode_type {
struct date_mode {
enum date_mode_type type;
- const char *strftime_fmt;
int local;
+ const char *strftime_fmt;
};
#define DATE_MODE_INIT { \
@@ -36,14 +36,14 @@ struct date_mode {
* show_date(t, tz, DATE_MODE(NORMAL));
*/
#define DATE_MODE(t) date_mode_from_type(DATE_##t)
-struct date_mode *date_mode_from_type(enum date_mode_type type);
+struct date_mode date_mode_from_type(enum date_mode_type type);
/**
* Format <'time', 'timezone'> into static memory according to 'mode'
* and return it. The mode is an initialized "struct date_mode"
* (usually from the DATE_MODE() macro).
*/
-const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
+const char *show_date(timestamp_t time, int timezone, struct date_mode mode);
/**
* Parse a date format for later use with show_date().
diff --git a/decorate.h b/decorate.h
index cdeb17c9df..08af658d34 100644
--- a/decorate.h
+++ b/decorate.h
@@ -3,7 +3,7 @@
/*
* A data structure that associates Git objects to void pointers. See
- * t/helper/test-example-decorate.c for a demonstration of how to use these
+ * t/unit-tests/t-example-decorate.c for a demonstration of how to use these
* functions.
*/
diff --git a/delta-islands.c b/delta-islands.c
index 5de5759f3f..8443551259 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -1,18 +1,15 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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"
#include "pack.h"
#include "tree-walk.h"
#include "diff.h"
-#include "revision.h"
-#include "list-objects.h"
#include "progress.h"
#include "refs.h"
#include "khash.h"
@@ -289,7 +286,7 @@ void resolve_tree_islands(struct repository *r,
if (!tree || parse_tree(tree) < 0)
die(_("bad tree object %s"), oid_to_hex(&ent->idx.oid));
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
struct object *obj;
@@ -318,7 +315,7 @@ struct island_load_data {
size_t nr;
size_t alloc;
};
-static const char *core_island_name;
+static char *core_island_name;
static void free_config_regexes(struct island_load_data *ild)
{
@@ -393,7 +390,7 @@ static void add_ref_to_island(kh_str_t *remote_islands, const char *island_name,
rl->hash += sha_core;
}
-static int find_island_for_ref(const char *refname, const struct object_id *oid,
+static int find_island_for_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb)
{
struct island_load_data *ild = cb;
@@ -493,7 +490,8 @@ void load_delta_islands(struct repository *r, int progress)
git_config(island_config_callback, &ild);
ild.remote_islands = kh_init_str();
- for_each_ref(find_island_for_ref, &ild);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ find_island_for_ref, &ild);
free_config_regexes(&ild);
deduplicate_islands(ild.remote_islands, r);
free_remote_islands(ild.remote_islands);
diff --git a/diagnose.c b/diagnose.c
index 8430064000..cc2d535b60 100644
--- a/diagnose.c
+++ b/diagnose.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "diagnose.h"
#include "compat/disk.h"
@@ -71,42 +73,6 @@ static int dir_file_stats(struct object_directory *object_dir, void *data)
return 0;
}
-/*
- * Get the d_type of a dirent. If the d_type is unknown, derive it from
- * stat.st_mode.
- *
- * Note that 'path' is assumed to have a trailing slash. It is also modified
- * in-place during the execution of the function, but is then reverted to its
- * original value before returning.
- */
-static unsigned char get_dtype(struct dirent *e, struct strbuf *path)
-{
- struct stat st;
- unsigned char dtype = DTYPE(e);
- size_t base_path_len;
-
- if (dtype != DT_UNKNOWN)
- return dtype;
-
- /* d_type unknown in dirent, try to fall back on lstat results */
- base_path_len = path->len;
- strbuf_addstr(path, e->d_name);
- if (lstat(path->buf, &st))
- goto cleanup;
-
- /* determine d_type from st_mode */
- if (S_ISREG(st.st_mode))
- dtype = DT_REG;
- else if (S_ISDIR(st.st_mode))
- dtype = DT_DIR;
- else if (S_ISLNK(st.st_mode))
- dtype = DT_LNK;
-
-cleanup:
- strbuf_setlen(path, base_path_len);
- return dtype;
-}
-
static int count_files(struct strbuf *path)
{
DIR *dir = opendir(path->buf);
@@ -117,7 +83,7 @@ static int count_files(struct strbuf *path)
return 0;
while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
- if (get_dtype(e, path) == DT_REG)
+ if (get_dtype(e, path, 0) == DT_REG)
count++;
closedir(dir);
@@ -146,7 +112,7 @@ static void loose_objs_stats(struct strbuf *buf, const char *path)
base_path_len = count_path.len;
while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
- if (get_dtype(e, &count_path) == DT_DIR &&
+ if (get_dtype(e, &count_path, 0) == DT_DIR &&
strlen(e->d_name) == 2 &&
!hex_to_bytes(&c, e->d_name, 1)) {
strbuf_setlen(&count_path, base_path_len);
@@ -191,7 +157,7 @@ static int add_directory_to_archiver(struct strvec *archiver_args,
strbuf_add_absolute_path(&abspath, at_root ? "." : path);
strbuf_addch(&abspath, '/');
- dtype = get_dtype(e, &abspath);
+ dtype = get_dtype(e, &abspath, 0);
strbuf_setlen(&buf, len);
strbuf_addstr(&buf, e->d_name);
diff --git a/diff-lib.c b/diff-lib.c
index 5848e4f9ca..3cf353946f 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -1,8 +1,10 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "quote.h"
#include "commit.h"
#include "diff.h"
#include "diffcore.h"
@@ -38,7 +40,13 @@
*/
static int check_removed(const struct cache_entry *ce, struct stat *st)
{
- if (lstat(ce->name, st) < 0) {
+ int stat_err;
+
+ if (!(ce->ce_flags & CE_FSMONITOR_VALID))
+ stat_err = lstat(ce->name, st);
+ else
+ stat_err = fake_lstat(ce, st);
+ if (stat_err < 0) {
if (!is_missing_file_error(errno))
return -1;
return 1;
@@ -61,7 +69,8 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
* a directory --- the blob was removed!
*/
if (!S_ISGITLINK(ce->ce_mode) &&
- resolve_gitlink_ref(ce->name, "HEAD", &sub))
+ repo_resolve_gitlink_ref(the_repository, ce->name,
+ "HEAD", &sub))
return 1;
}
return 0;
@@ -122,7 +131,16 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
if (diff_can_quit_early(&revs->diffopt))
break;
- if (!ce_path_match(istate, ce, &revs->prune_data, NULL))
+ /*
+ * NEEDSWORK:
+ * Here we filter with pathspec but the result is further
+ * filtered out when --relative is in effect. To end-users,
+ * a pathspec element that matched only to paths outside the
+ * current directory is like not matching anything at all;
+ * the handling of ps_matched[] here may become problematic
+ * if/when we add the "--error-unmatch" option to "git diff".
+ */
+ if (!ce_path_match(istate, ce, &revs->prune_data, revs->ps_matched))
continue;
if (revs->diffopt.prefix &&
@@ -145,7 +163,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
dpath->next = NULL;
memcpy(dpath->path, ce->name, path_len);
dpath->path[path_len] = '\0';
- oidclr(&dpath->oid);
+ oidclr(&dpath->oid, the_repository->hash_algo);
memset(&(dpath->parent[0]), 0,
sizeof(struct combine_diff_parent)*5);
@@ -290,8 +308,7 @@ static void diff_index_show_file(struct rev_info *revs,
oid, oid_valid, ce->name, dirty_submodule);
}
-static int get_stat_data(const struct index_state *istate,
- const struct cache_entry *ce,
+static int get_stat_data(const struct cache_entry *ce,
const struct object_id **oidp,
unsigned int *modep,
int cached, int match_missing,
@@ -334,7 +351,6 @@ static void show_new_file(struct rev_info *revs,
const struct object_id *oid;
unsigned int mode;
unsigned dirty_submodule = 0;
- struct index_state *istate = revs->diffopt.repo->index;
if (new_file && S_ISSPARSEDIR(new_file->ce_mode)) {
diff_tree_oid(NULL, &new_file->oid, new_file->name, &revs->diffopt);
@@ -345,7 +361,7 @@ static void show_new_file(struct rev_info *revs,
* New file in the index: it might actually be different in
* the working tree.
*/
- if (get_stat_data(istate, new_file, &oid, &mode, cached, match_missing,
+ if (get_stat_data(new_file, &oid, &mode, cached, match_missing,
&dirty_submodule, &revs->diffopt) < 0)
return;
@@ -361,7 +377,6 @@ static int show_modified(struct rev_info *revs,
unsigned int mode, oldmode;
const struct object_id *oid;
unsigned dirty_submodule = 0;
- struct index_state *istate = revs->diffopt.repo->index;
assert(S_ISSPARSEDIR(old_entry->ce_mode) ==
S_ISSPARSEDIR(new_entry->ce_mode));
@@ -377,7 +392,7 @@ static int show_modified(struct rev_info *revs,
return 0;
}
- if (get_stat_data(istate, new_entry, &oid, &mode, cached, match_missing,
+ if (get_stat_data(new_entry, &oid, &mode, cached, match_missing,
&dirty_submodule, &revs->diffopt) < 0) {
if (report_missing)
diff_index_show_file(revs, "-", old_entry,
@@ -397,7 +412,7 @@ static int show_modified(struct rev_info *revs,
memcpy(p->path, new_entry->name, pathlen);
p->path[pathlen] = 0;
p->mode = mode;
- oidclr(&p->oid);
+ oidclr(&p->oid, the_repository->hash_algo);
memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
p->parent[0].status = DIFF_STATUS_MODIFIED;
p->parent[0].mode = new_entry->ce_mode;
@@ -557,7 +572,7 @@ static int diff_cache(struct rev_info *revs,
opts.pathspec = &revs->diffopt.pathspec;
opts.pathspec->recursive = 1;
- init_tree_desc(&t, tree->buffer, tree->size);
+ init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
return unpack_trees(1, &t, &opts);
}
@@ -565,14 +580,12 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
{
int i;
struct commit *mb_child[2] = {0};
- struct commit_list *merge_bases;
+ struct commit_list *merge_bases = NULL;
for (i = 0; i < revs->pending.nr; i++) {
struct object *obj = revs->pending.objects[i].item;
if (obj->flags)
die(_("--merge-base does not work with ranges"));
- if (obj->type != OBJ_COMMIT)
- die(_("--merge-base only works with commits"));
}
/*
@@ -594,7 +607,8 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
mb_child[1] = lookup_commit_reference(the_repository, &oid);
}
- merge_bases = repo_get_merge_bases(the_repository, mb_child[0], mb_child[1]);
+ if (repo_get_merge_bases(the_repository, mb_child[0], mb_child[1], &merge_bases) < 0)
+ exit(128);
if (!merge_bases)
die(_("no merge base found"));
if (merge_bases->next)
@@ -647,11 +661,13 @@ int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
repo_init_revisions(opt->repo, &revs, NULL);
copy_pathspec(&revs.prune_data, &opt->pathspec);
- diff_setup_done(&revs.diffopt);
+ diff_free(&revs.diffopt);
revs.diffopt = *opt;
+ revs.diffopt.no_free = 1;
if (diff_cache(&revs, tree_oid, NULL, 1))
exit(128);
+
release_revisions(&revs);
return 0;
}
@@ -686,7 +702,7 @@ int index_differs_from(struct repository *r,
return (has_changes != 0);
}
-static struct strbuf *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data)
+static const char *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data)
{
return data;
}
@@ -701,7 +717,7 @@ void show_interdiff(const struct object_id *oid1, const struct object_id *oid2,
opts.output_format = DIFF_FORMAT_PATCH;
opts.output_prefix = idiff_prefix_cb;
strbuf_addchars(&prefix, ' ', indent);
- opts.output_prefix_data = &prefix;
+ opts.output_prefix_data = prefix.buf;
diff_setup_done(&opts);
diff_tree_oid(oid1, oid2, "", &opts);
diff --git a/diff-merges.c b/diff-merges.c
index ec97616db1..45507588a2 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -131,6 +131,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
} else if (!strcmp(arg, "--cc")) {
set_dense_combined(revs);
revs->merges_imply_patch = 1;
+ } else if (!strcmp(arg, "--dd")) {
+ set_first_parent(revs);
+ revs->merges_imply_patch = 1;
} else if (!strcmp(arg, "--remerge-diff")) {
set_remerge_diff(revs);
revs->merges_imply_patch = 1;
diff --git a/diff-no-index.c b/diff-no-index.c
index e7041b89e3..c5fb06e6d1 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -8,13 +8,10 @@
#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 "parse-options.h"
#include "string-list.h"
#include "dir.h"
@@ -365,7 +362,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);
+ ret = diff_result_code(revs);
out:
for (i = 0; i < ARRAY_SIZE(to_free); i++)
diff --git a/diff.c b/diff.c
index bccb018da4..dceac20d18 100644
--- a/diff.c
+++ b/diff.c
@@ -1,6 +1,9 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "base85.h"
@@ -9,6 +12,7 @@
#include "environment.h"
#include "gettext.h"
#include "tempfile.h"
+#include "revision.h"
#include "quote.h"
#include "diff.h"
#include "diffcore.h"
@@ -16,18 +20,17 @@
#include "hex.h"
#include "xdiff-interface.h"
#include "color.h"
-#include "attr.h"
#include "run-command.h"
#include "utf8.h"
#include "object-store-ll.h"
#include "userdiff.h"
-#include "submodule-config.h"
#include "submodule.h"
#include "hashmap.h"
#include "mem-pool.h"
#include "merge-ll.h"
#include "string-list.h"
#include "strvec.h"
+#include "tmp-objdir.h"
#include "graph.h"
#include "oid-array.h"
#include "packfile.h"
@@ -58,13 +61,16 @@ static int diff_color_moved_default;
static int diff_color_moved_ws_default;
static int diff_context_default = 3;
static int diff_interhunk_context_default;
-static const char *diff_word_regex_cfg;
-static const char *external_diff_cmd_cfg;
-static const char *diff_order_file_cfg;
+static char *diff_word_regex_cfg;
+static struct external_diff external_diff_cfg;
+static char *diff_order_file_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
+static char *diff_src_prefix;
+static char *diff_dst_prefix;
static int diff_relative;
+static int diff_stat_name_width;
static int diff_stat_graph_width;
static int diff_dirstat_permille_default = 30;
static struct diff_options default_diff_options;
@@ -371,7 +377,10 @@ int git_diff_ui_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "diff.colormovedws")) {
- unsigned cm = parse_color_moved_ws(value);
+ unsigned cm;
+ if (!value)
+ return config_error_nonbool(var);
+ cm = parse_color_moved_ws(value);
if (cm & COLOR_MOVED_WS_ERROR)
return -1;
diff_color_moved_ws_default = cm;
@@ -406,25 +415,48 @@ int git_diff_ui_config(const char *var, const char *value,
diff_no_prefix = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.srcprefix")) {
+ FREE_AND_NULL(diff_src_prefix);
+ return git_config_string(&diff_src_prefix, var, value);
+ }
+ if (!strcmp(var, "diff.dstprefix")) {
+ FREE_AND_NULL(diff_dst_prefix);
+ return git_config_string(&diff_dst_prefix, var, value);
+ }
if (!strcmp(var, "diff.relative")) {
diff_relative = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.statnamewidth")) {
+ diff_stat_name_width = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
if (!strcmp(var, "diff.statgraphwidth")) {
diff_stat_graph_width = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "diff.external"))
- return git_config_string(&external_diff_cmd_cfg, var, value);
+ return git_config_string(&external_diff_cfg.cmd, var, value);
+ if (!strcmp(var, "diff.trustexitcode")) {
+ external_diff_cfg.trust_exit_code = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp(var, "diff.wordregex"))
return git_config_string(&diff_word_regex_cfg, var, value);
- if (!strcmp(var, "diff.orderfile"))
+ if (!strcmp(var, "diff.orderfile")) {
+ FREE_AND_NULL(diff_order_file_cfg);
return git_config_pathname(&diff_order_file_cfg, var, value);
+ }
- if (!strcmp(var, "diff.ignoresubmodules"))
+ if (!strcmp(var, "diff.ignoresubmodules")) {
+ if (!value)
+ return config_error_nonbool(var);
handle_ignore_submodules_arg(&default_diff_options, value);
+ }
if (!strcmp(var, "diff.submodule")) {
+ if (!value)
+ return config_error_nonbool(var);
if (parse_submodule_params(&default_diff_options, value))
warning(_("Unknown value for 'diff.submodule' config variable: '%s'"),
value);
@@ -432,9 +464,12 @@ int git_diff_ui_config(const char *var, const char *value,
}
if (!strcmp(var, "diff.algorithm")) {
+ if (!value)
+ return config_error_nonbool(var);
diff_algorithm = parse_algorithm_value(value);
if (diff_algorithm < 0)
- return -1;
+ return error(_("unknown value for config '%s': %s"),
+ var, value);
return 0;
}
@@ -468,9 +503,13 @@ int git_diff_basic_config(const char *var, const char *value,
}
if (!strcmp(var, "diff.wserrorhighlight")) {
- int val = parse_ws_error_highlight(value);
+ int val;
+ if (!value)
+ return config_error_nonbool(var);
+ val = parse_ws_error_highlight(value);
if (val < 0)
- return -1;
+ return error(_("unknown value for config '%s': %s"),
+ var, value);
ws_error_highlight_default = val;
return 0;
}
@@ -485,6 +524,8 @@ int git_diff_basic_config(const char *var, const char *value,
if (!strcmp(var, "diff.dirstat")) {
struct strbuf errmsg = STRBUF_INIT;
+ if (!value)
+ return config_error_nonbool(var);
default_diff_options.dirstat_permille = diff_dirstat_permille_default;
if (parse_dirstat_params(&default_diff_options, value, &errmsg))
warning(_("Found errors in 'diff.dirstat' config variable:\n%s"),
@@ -518,18 +559,22 @@ static char *quote_two(const char *one, const char *two)
return strbuf_detach(&res, NULL);
}
-static const char *external_diff(void)
+static const struct external_diff *external_diff(void)
{
- static const char *external_diff_cmd = NULL;
+ static struct external_diff external_diff_env, *external_diff_ptr;
static int done_preparing = 0;
if (done_preparing)
- return external_diff_cmd;
- external_diff_cmd = xstrdup_or_null(getenv("GIT_EXTERNAL_DIFF"));
- if (!external_diff_cmd)
- external_diff_cmd = external_diff_cmd_cfg;
+ return external_diff_ptr;
+ external_diff_env.cmd = xstrdup_or_null(getenv("GIT_EXTERNAL_DIFF"));
+ if (git_env_bool("GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE", 0))
+ external_diff_env.trust_exit_code = 1;
+ if (external_diff_env.cmd)
+ external_diff_ptr = &external_diff_env;
+ else if (external_diff_cfg.cmd)
+ external_diff_ptr = &external_diff_cfg;
done_preparing = 1;
- return external_diff_cmd;
+ return external_diff_ptr;
}
/*
@@ -2272,12 +2317,9 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
const char *diff_line_prefix(struct diff_options *opt)
{
- struct strbuf *msgbuf;
- if (!opt->output_prefix)
- return "";
-
- msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
- return msgbuf->buf;
+ return opt->output_prefix ?
+ opt->output_prefix(opt, opt->output_prefix_data) :
+ "";
}
static unsigned long sane_truncate_line(char *line, unsigned long len)
@@ -2704,12 +2746,14 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
number_width = decimal_width(max_change) > number_width ?
decimal_width(max_change) : number_width;
+ if (options->stat_name_width == -1)
+ options->stat_name_width = diff_stat_name_width;
if (options->stat_graph_width == -1)
options->stat_graph_width = diff_stat_graph_width;
/*
- * Guarantee 3/8*16==6 for the graph part
- * and 5/8*16==10 for the filename part
+ * Guarantee 3/8*16 == 6 for the graph part
+ * and 5/8*16 == 10 for the filename part
*/
if (width < 16 + 6 + number_width)
width = 16 + 6 + number_width;
@@ -3403,8 +3447,8 @@ void diff_set_noprefix(struct diff_options *options)
void diff_set_default_prefix(struct diff_options *options)
{
- options->a_prefix = "a/";
- options->b_prefix = "b/";
+ options->a_prefix = diff_src_prefix ? diff_src_prefix : "a/";
+ options->b_prefix = diff_dst_prefix ? diff_dst_prefix : "b/";
}
struct userdiff_driver *get_textconv(struct repository *r,
@@ -3522,6 +3566,7 @@ static void builtin_diff(const char *name_a,
show_submodule_diff_summary(o, one->path ? one->path : two->path,
&one->oid, &two->oid,
two->dirty_submodule);
+ o->found_changes = 1;
return;
} else if (o->submodule_format == DIFF_SUBMODULE_INLINE_DIFF &&
(!one->mode || S_ISGITLINK(one->mode)) &&
@@ -3530,6 +3575,7 @@ static void builtin_diff(const char *name_a,
show_submodule_inline_diff(o, one->path ? one->path : two->path,
&one->oid, &two->oid,
two->dirty_submodule);
+ o->found_changes = 1;
return;
}
@@ -3628,6 +3674,7 @@ static void builtin_diff(const char *name_a,
emit_diff_symbol(o, DIFF_SYMBOL_BINARY_FILES,
sb.buf, sb.len, 0);
strbuf_release(&sb);
+ o->found_changes = 1;
goto free_ab_and_return;
}
if (fill_mmfile(o->repo, &mf1, one) < 0 ||
@@ -3732,7 +3779,7 @@ static void builtin_diff(const char *name_a,
return;
}
-static char *get_compact_summary(const struct diff_filepair *p, int is_renamed)
+static const char *get_compact_summary(const struct diff_filepair *p, int is_renamed)
{
if (!is_renamed) {
if (p->status == DIFF_STATUS_ADDED) {
@@ -4044,7 +4091,7 @@ static int reuse_worktree_file(struct index_state *istate,
static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
{
struct strbuf buf = STRBUF_INIT;
- char *dirty = "";
+ const char *dirty = "";
/* Are we looking at the work tree? */
if (s->dirty_submodule)
@@ -4343,7 +4390,7 @@ static void add_external_diff_name(struct repository *r,
* infile2 infile2-sha1 infile2-mode [ rename-to ]
*
*/
-static void run_external_diff(const char *pgm,
+static void run_external_diff(const struct external_diff *pgm,
const char *name,
const char *other,
struct diff_filespec *one,
@@ -4353,8 +4400,21 @@ static void run_external_diff(const char *pgm,
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct diff_queue_struct *q = &diff_queued_diff;
+ int quiet = !(o->output_format & DIFF_FORMAT_PATCH);
+ int rc;
+
+ /*
+ * Trivial equality is handled by diff_unmodified_pair() before
+ * we get here. If we don't need to show the diff and the
+ * external diff program lacks the ability to tell us whether
+ * it's empty then we consider it non-empty without even asking.
+ */
+ if (!pgm->trust_exit_code && quiet) {
+ o->found_changes = 1;
+ return;
+ }
- strvec_push(&cmd.args, pgm);
+ strvec_push(&cmd.args, pgm->cmd);
strvec_push(&cmd.args, name);
if (one && two) {
@@ -4362,7 +4422,8 @@ static void run_external_diff(const char *pgm,
add_external_diff_name(o->repo, &cmd.args, two);
if (other) {
strvec_push(&cmd.args, other);
- strvec_push(&cmd.args, xfrm_msg);
+ if (xfrm_msg)
+ strvec_push(&cmd.args, xfrm_msg);
}
}
@@ -4373,7 +4434,15 @@ static void run_external_diff(const char *pgm,
diff_free_filespec_data(one);
diff_free_filespec_data(two);
cmd.use_shell = 1;
- if (run_command(&cmd))
+ cmd.no_stdout = quiet;
+ rc = run_command(&cmd);
+ if (!pgm->trust_exit_code && rc == 0)
+ o->found_changes = 1;
+ else if (pgm->trust_exit_code && rc == 0)
+ ; /* nothing */
+ else if (pgm->trust_exit_code && rc == 1)
+ o->found_changes = 1;
+ else
die(_("external diff died, stopping at %s"), name);
remove_tempfile();
@@ -4479,7 +4548,7 @@ static void fill_metainfo(struct strbuf *msg,
}
}
-static void run_diff_cmd(const char *pgm,
+static void run_diff_cmd(const struct external_diff *pgm,
const char *name,
const char *other,
const char *attr_path,
@@ -4497,8 +4566,8 @@ static void run_diff_cmd(const char *pgm,
if (o->flags.allow_external || !o->ignore_driver_algorithm)
drv = userdiff_find_by_path(o->repo->index, attr_path);
- if (o->flags.allow_external && drv && drv->external)
- pgm = drv->external;
+ if (o->flags.allow_external && drv && drv->external.cmd)
+ pgm = &drv->external;
if (msg) {
/*
@@ -4522,8 +4591,12 @@ static void run_diff_cmd(const char *pgm,
builtin_diff(name, other ? other : name,
one, two, xfrm_msg, must_show_header,
o, complete_rewrite);
+ if (p->status == DIFF_STATUS_COPIED ||
+ p->status == DIFF_STATUS_RENAMED)
+ o->found_changes = 1;
} else {
fprintf(o->file, "* Unmerged path %s\n", name);
+ o->found_changes = 1;
}
}
@@ -4533,7 +4606,7 @@ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *is
if (!one->oid_valid) {
struct stat st;
if (one->is_stdin) {
- oidclr(&one->oid);
+ oidclr(&one->oid, the_repository->hash_algo);
return;
}
if (lstat(one->path, &st) < 0)
@@ -4543,7 +4616,7 @@ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *is
}
}
else
- oidclr(&one->oid);
+ oidclr(&one->oid, the_repository->hash_algo);
}
static void strip_prefix(int prefix_length, const char **namep, const char **otherp)
@@ -4563,7 +4636,7 @@ static void strip_prefix(int prefix_length, const char **namep, const char **oth
static void run_diff(struct diff_filepair *p, struct diff_options *o)
{
- const char *pgm = external_diff();
+ const struct external_diff *pgm = external_diff();
struct strbuf msg;
struct diff_filespec *one = p->one;
struct diff_filespec *two = p->two;
@@ -4704,7 +4777,7 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
if (diff_indent_heuristic)
DIFF_XDL_SET(options, INDENT_HEURISTIC);
- options->orderfile = diff_order_file_cfg;
+ options->orderfile = xstrdup_or_null(diff_order_file_cfg);
if (!options->flags.ignore_submodule_set)
options->flags.ignore_untracked_in_submodules = 1;
@@ -4890,12 +4963,20 @@ void diff_setup_done(struct diff_options *options)
options->flags.exit_with_status = 1;
}
+ /*
+ * External diffs could declare non-identical contents equal
+ * (think diff --ignore-space-change).
+ */
+ if (options->flags.allow_external && options->flags.exit_with_status)
+ options->flags.diff_from_contents = 1;
+
options->diff_path_counter = 0;
if (options->flags.follow_renames)
diff_check_follow_pathspec(&options->pathspec, 1);
- if (!options->use_color || external_diff())
+ if (!options->use_color ||
+ (options->flags.allow_external && external_diff()))
options->color_moved = 0;
if (options->filter_not) {
@@ -5316,7 +5397,6 @@ static int diff_opt_line_prefix(const struct option *opt,
BUG_ON_OPT_NEG(unset);
options->line_prefix = optarg;
- options->line_prefix_length = strlen(options->line_prefix);
graph_setup_line_prefix(options);
return 0;
}
@@ -5339,6 +5419,8 @@ static int diff_opt_default_prefix(const struct option *opt,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(optarg);
+ FREE_AND_NULL(diff_src_prefix);
+ FREE_AND_NULL(diff_dst_prefix);
diff_set_default_prefix(options);
return 0;
}
@@ -5388,9 +5470,13 @@ static int diff_opt_ignore_regex(const struct option *opt,
regex_t *regex;
BUG_ON_OPT_NEG(unset);
+
regex = xmalloc(sizeof(*regex));
- if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE))
+ if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE)) {
+ free(regex);
return error(_("invalid regex given to -I: '%s'"), arg);
+ }
+
ALLOC_GROW(options->ignore_regex, options->ignore_regex_nr + 1,
options->ignore_regex_alloc);
options->ignore_regex[options->ignore_regex_nr++] = regex;
@@ -5567,7 +5653,7 @@ struct option *add_diff_options(const struct option *opts,
OPT_BITOP(0, "shortstat", &options->output_format,
N_("output only the last line of --stat"),
DIFF_FORMAT_SHORTSTAT, DIFF_FORMAT_NO_OUTPUT),
- OPT_CALLBACK_F('X', "dirstat", options, N_("<param1,param2>..."),
+ 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,
diff_opt_dirstat),
@@ -5575,8 +5661,8 @@ struct option *add_diff_options(const struct option *opts,
N_("synonym for --dirstat=cumulative"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
diff_opt_dirstat),
- OPT_CALLBACK_F(0, "dirstat-by-file", options, N_("<param1,param2>..."),
- N_("synonym for --dirstat=files,param1,param2..."),
+ OPT_CALLBACK_F(0, "dirstat-by-file", options, N_("<param1>,<param2>..."),
+ N_("synonym for --dirstat=files,<param1>,<param2>..."),
PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
diff_opt_dirstat),
OPT_BIT_F(0, "check", &options->output_format,
@@ -5893,11 +5979,18 @@ void diff_free_filepair(struct diff_filepair *p)
free(p);
}
-void diff_free_queue(struct diff_queue_struct *q)
+void diff_queue_init(struct diff_queue_struct *q)
+{
+ struct diff_queue_struct blank = DIFF_QUEUE_INIT;
+ memcpy(q, &blank, sizeof(*q));
+}
+
+void diff_queue_clear(struct diff_queue_struct *q)
{
for (int i = 0; i < q->nr; i++)
diff_free_filepair(q->queue[i]);
free(q->queue);
+ diff_queue_init(q);
}
const char *diff_aligned_abbrev(const struct object_id *oid, int len)
@@ -6368,7 +6461,7 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
the_hash_algo->init_fn(&ctx);
memset(&data, 0, sizeof(struct patch_id_t));
data.ctx = &ctx;
- oidclr(oid);
+ oidclr(oid, the_repository->hash_algo);
for (i = 0; i < q->nr; i++) {
xpparam_t xpp;
@@ -6461,8 +6554,7 @@ int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int
struct diff_queue_struct *q = &diff_queued_diff;
int result = diff_get_patch_id(options, oid, diff_header_only);
- diff_free_queue(q);
- DIFF_QUEUE_CLEAR(q);
+ diff_queue_clear(q);
return result;
}
@@ -6613,8 +6705,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
static void diff_free_file(struct diff_options *options)
{
- if (options->close_file)
+ if (options->close_file && options->file) {
fclose(options->file);
+ options->file = NULL;
+ }
}
static void diff_free_ignore_regex(struct diff_options *options)
@@ -6625,7 +6719,9 @@ static void diff_free_ignore_regex(struct diff_options *options)
regfree(options->ignore_regex[i]);
free(options->ignore_regex[i]);
}
- free(options->ignore_regex);
+
+ FREE_AND_NULL(options->ignore_regex);
+ options->ignore_regex_nr = 0;
}
void diff_free(struct diff_options *options)
@@ -6633,6 +6729,17 @@ void diff_free(struct diff_options *options)
if (options->no_free)
return;
+ if (options->objfind) {
+ oidset_clear(options->objfind);
+ FREE_AND_NULL(options->objfind);
+ }
+
+ FREE_AND_NULL(options->orderfile);
+ for (size_t i = 0; i < options->anchors_nr; i++)
+ free(options->anchors[i]);
+ FREE_AND_NULL(options->anchors);
+ options->anchors_nr = options->anchors_alloc = 0;
+
diff_free_file(options);
diff_free_ignore_regex(options);
clear_pathspec(&options->pathspec);
@@ -6730,8 +6837,7 @@ void diff_flush(struct diff_options *options)
}
free_queue:
- diff_free_queue(q);
- DIFF_QUEUE_CLEAR(q);
+ diff_queue_clear(q);
diff_free(options);
/*
@@ -6762,9 +6868,7 @@ static void diffcore_apply_filter(struct diff_options *options)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
- struct diff_queue_struct outq;
-
- DIFF_QUEUE_CLEAR(&outq);
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
if (!options->filter)
return;
@@ -6857,8 +6961,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
- struct diff_queue_struct outq;
- DIFF_QUEUE_CLEAR(&outq);
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
@@ -6929,6 +7032,13 @@ void diff_queued_diff_prefetch(void *repository)
oid_array_clear(&to_fetch);
}
+void init_diffstat_widths(struct diff_options *options)
+{
+ options->stat_width = -1; /* use full terminal width */
+ options->stat_name_width = -1; /* respect diff.statNameWidth config */
+ options->stat_graph_width = -1; /* respect diff.statGraphWidth config */
+}
+
void diffcore_std(struct diff_options *options)
{
int output_formats_to_prefetch = DIFF_FORMAT_DIFFSTAT |
@@ -6982,10 +7092,16 @@ void diffcore_std(struct diff_options *options)
options->found_follow = 0;
}
-int diff_result_code(struct diff_options *opt)
+int diff_result_code(struct rev_info *revs)
{
+ struct diff_options *opt = &revs->diffopt;
int result = 0;
+ if (revs->remerge_diff) {
+ tmp_objdir_destroy(revs->remerge_objdir);
+ revs->remerge_objdir = NULL;
+ }
+
diff_warn_rename_limit("diff.renameLimit",
opt->needed_rename_limit,
opt->degraded_cc_to_c);
@@ -7192,7 +7308,7 @@ size_t fill_textconv(struct repository *r,
if (!driver) {
if (!DIFF_FILE_VALID(df)) {
- *outbuf = "";
+ *outbuf = (char *) "";
return 0;
}
if (diff_populate_filespec(r, df, NULL))
diff --git a/diff.h b/diff.h
index caf1528bf0..5c8de79535 100644
--- a/diff.h
+++ b/diff.h
@@ -4,7 +4,7 @@
#ifndef DIFF_H
#define DIFF_H
-#include "hash-ll.h"
+#include "hash.h"
#include "pathspec.h"
#include "strbuf.h"
@@ -94,7 +94,7 @@ typedef void (*add_remove_fn_t)(struct diff_options *options,
typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
struct diff_options *options, void *data);
-typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
+typedef const char *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
#define DIFF_FORMAT_RAW 0x0001
#define DIFF_FORMAT_DIFFSTAT 0x0002
@@ -235,7 +235,7 @@ enum diff_submodule_format {
* diffcore library with.
*/
struct diff_options {
- const char *orderfile;
+ char *orderfile;
/*
* "--rotate-to=<file>" would start showing at <file> and when
@@ -274,7 +274,6 @@ struct diff_options {
const char *single_follow;
const char *a_prefix, *b_prefix;
const char *line_prefix;
- size_t line_prefix_length;
/**
* collection of boolean options that affects the operation, but some do
@@ -573,6 +572,7 @@ int git_config_rename(const char *var, const char *value);
#define DIFF_PICKAXE_IGNORE_CASE 32
+void init_diffstat_widths(struct diff_options *);
void diffcore_std(struct diff_options *);
void diffcore_fix_diff_index(void);
@@ -647,7 +647,7 @@ 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 diff_result_code(struct rev_info *);
int diff_no_index(struct rev_info *,
int implicit_no_index, int, const char **);
diff --git a/diffcore-break.c b/diffcore-break.c
index f57ece2757..c4c2173f30 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -1,8 +1,10 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "diff.h"
#include "diffcore.h"
#include "hash.h"
#include "object.h"
@@ -129,7 +131,7 @@ static int should_break(struct repository *r,
void diffcore_break(struct repository *r, int break_score)
{
struct diff_queue_struct *q = &diff_queued_diff;
- struct diff_queue_struct outq;
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
/* When the filepair has this much edit (insert and delete),
* it is first considered to be a rewrite and broken into a
@@ -176,8 +178,6 @@ void diffcore_break(struct repository *r, int break_score)
if (!merge_score)
merge_score = DEFAULT_MERGE_SCORE;
- DIFF_QUEUE_CLEAR(&outq);
-
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
int score;
@@ -264,8 +264,8 @@ static void merge_broken(struct diff_filepair *p,
* in the resulting tree.
*/
d->one->rename_used++;
- diff_free_filespec_data(d->two);
- diff_free_filespec_data(c->one);
+ free_filespec(d->two);
+ free_filespec(c->one);
free(d);
free(c);
}
@@ -273,11 +273,9 @@ static void merge_broken(struct diff_filepair *p,
void diffcore_merge_broken(void)
{
struct diff_queue_struct *q = &diff_queued_diff;
- struct diff_queue_struct outq;
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
int i, j;
- DIFF_QUEUE_CLEAR(&outq);
-
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (!p)
diff --git a/diffcore-delta.c b/diffcore-delta.c
index c30b56e983..ba6cbee76b 100644
--- a/diffcore-delta.c
+++ b/diffcore-delta.c
@@ -1,5 +1,4 @@
#include "git-compat-util.h"
-#include "diff.h"
#include "diffcore.h"
/*
@@ -159,6 +158,10 @@ static struct spanhash_top *hash_chars(struct repository *r,
n = 0;
accum1 = accum2 = 0;
}
+ if (n > 0) {
+ hashval = (accum1 + accum2 * 0x61) % HASHBASE;
+ hash = add_spanhash(hash, hashval, n);
+ }
QSORT(hash->data, (size_t)1ul << hash->alloc_log2, spanhash_cmp);
return hash;
}
diff --git a/diffcore-order.c b/diffcore-order.c
index e7d20ebd2d..912513d3e6 100644
--- a/diffcore-order.c
+++ b/diffcore-order.c
@@ -14,8 +14,7 @@ static void prepare_order(const char *orderfile)
{
int cnt, pass;
struct strbuf sb = STRBUF_INIT;
- void *map;
- char *cp, *endp;
+ const char *cp, *endp;
ssize_t sz;
if (order)
@@ -24,14 +23,13 @@ static void prepare_order(const char *orderfile)
sz = strbuf_read_file(&sb, orderfile, 0);
if (sz < 0)
die_errno(_("failed to read orderfile '%s'"), orderfile);
- map = strbuf_detach(&sb, NULL);
- endp = (char *) map + sz;
+ endp = sb.buf + sz;
for (pass = 0; pass < 2; pass++) {
cnt = 0;
- cp = map;
+ cp = sb.buf;
while (cp < endp) {
- char *ep;
+ const char *ep;
for (ep = cp; ep < endp && *ep != '\n'; ep++)
;
/* cp to ep has one line */
@@ -40,12 +38,7 @@ static void prepare_order(const char *orderfile)
else if (pass == 0)
cnt++;
else {
- if (*ep == '\n') {
- *ep = 0;
- order[cnt] = cp;
- } else {
- order[cnt] = xmemdupz(cp, ep - cp);
- }
+ order[cnt] = xmemdupz(cp, ep - cp);
cnt++;
}
if (ep < endp)
@@ -57,6 +50,8 @@ static void prepare_order(const char *orderfile)
ALLOC_ARRAY(order, cnt);
}
}
+
+ strbuf_release(&sb);
}
static int match_order(const char *path)
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index b195fa4eb3..43fef8e8ba 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -182,9 +182,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
regex_t *regexp, kwset_t kws, pickaxe_fn fn)
{
int i;
- struct diff_queue_struct outq;
-
- DIFF_QUEUE_CLEAR(&outq);
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
if (o->pickaxe_opts & DIFF_PICKAXE_ALL) {
/* Showing the whole changeset if needle exists */
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 5a6e2bcac7..1b1c1a6a1f 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -2,6 +2,9 @@
*
* Copyright (C) 2005 Junio C Hamano
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
@@ -406,7 +409,7 @@ static const char *get_highest_rename_path(struct strintmap *counts)
return highest_destination_dir;
}
-static char *UNKNOWN_DIR = "/"; /* placeholder -- short, illegal directory */
+static const char *UNKNOWN_DIR = "/"; /* placeholder -- short, illegal directory */
static int dir_rename_already_determinable(struct strintmap *counts)
{
@@ -429,8 +432,8 @@ static int dir_rename_already_determinable(struct strintmap *counts)
}
static void increment_count(struct dir_rename_info *info,
- char *old_dir,
- char *new_dir)
+ const char *old_dir,
+ const char *new_dir)
{
struct strintmap *counts;
struct strmap_entry *e;
@@ -930,7 +933,7 @@ static int find_basename_matches(struct diff_options *options,
* spend more cycles to find similarities between files, so it may
* be less likely that this heuristic is wanted. If someone is
* doing break detection, that means they do not want filename
- * similarity to imply any form of content similiarity, and thus
+ * similarity to imply any form of content similarity, and thus
* this heuristic would definitely be incompatible.
*/
@@ -1385,7 +1388,7 @@ void diffcore_rename_extended(struct diff_options *options,
int detect_rename = options->detect_rename;
int minimum_score = options->rename_score;
struct diff_queue_struct *q = &diff_queued_diff;
- struct diff_queue_struct outq;
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
struct diff_score *mx;
int i, j, rename_count, skip_unmodified = 0;
int num_destinations, dst_cnt;
@@ -1422,7 +1425,7 @@ void diffcore_rename_extended(struct diff_options *options,
strcmp(options->single_follow, p->two->path))
continue; /* not interested */
else if (!options->flags.rename_empty &&
- is_empty_blob_oid(&p->two->oid))
+ is_empty_blob_oid(&p->two->oid, the_repository->hash_algo))
continue;
else if (add_rename_dst(p) < 0) {
warning("skipping rename detection, detected"
@@ -1432,7 +1435,7 @@ void diffcore_rename_extended(struct diff_options *options,
}
}
else if (!options->flags.rename_empty &&
- is_empty_blob_oid(&p->one->oid))
+ is_empty_blob_oid(&p->one->oid, the_repository->hash_algo))
continue;
else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) {
/*
@@ -1531,7 +1534,7 @@ void diffcore_rename_extended(struct diff_options *options,
* - remove ones not found in relevant_sources
* and
* - remove ones in relevant_sources which are needed only
- * for directory renames IF no ancestory directory
+ * for directory renames IF no ancestry directory
* actually needs to know any more individual path
* renames under them
*/
@@ -1635,7 +1638,6 @@ void diffcore_rename_extended(struct diff_options *options,
* are recorded in rename_dst. The original list is still in *q.
*/
trace2_region_enter("diff", "write back to queue", options->repo);
- DIFF_QUEUE_CLEAR(&outq);
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
struct diff_filepair *pair_to_free = NULL;
diff --git a/diffcore-rotate.c b/diffcore-rotate.c
index 533986cf63..73ca20b331 100644
--- a/diffcore-rotate.c
+++ b/diffcore-rotate.c
@@ -10,7 +10,7 @@
void diffcore_rotate(struct diff_options *opt)
{
struct diff_queue_struct *q = &diff_queued_diff;
- struct diff_queue_struct outq;
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
int rotate_to, i;
if (!q->nr)
@@ -31,7 +31,6 @@ void diffcore_rotate(struct diff_options *opt)
return;
}
- DIFF_QUEUE_CLEAR(&outq);
rotate_to = i;
for (i = rotate_to; i < q->nr; i++)
diff --git a/diffcore.h b/diffcore.h
index 5ffe4ec788..2feb325031 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -4,7 +4,7 @@
#ifndef DIFFCORE_H
#define DIFFCORE_H
-#include "hash-ll.h"
+#include "hash.h"
struct diff_options;
struct mem_pool;
@@ -153,18 +153,16 @@ struct diff_queue_struct {
int nr;
};
-#define DIFF_QUEUE_CLEAR(q) \
- do { \
- (q)->queue = NULL; \
- (q)->nr = (q)->alloc = 0; \
- } while (0)
+#define DIFF_QUEUE_INIT { 0 }
+
+void diff_queue_init(struct diff_queue_struct *q);
+void diff_queue_clear(struct diff_queue_struct *q);
extern struct diff_queue_struct diff_queued_diff;
struct diff_filepair *diff_queue(struct diff_queue_struct *,
struct diff_filespec *,
struct diff_filespec *);
void diff_q(struct diff_queue_struct *, struct diff_filepair *);
-void diff_free_queue(struct diff_queue_struct *q);
/* dir_rename_relevance: the reason we want rename information for a dir */
enum dir_rename_relevance {
diff --git a/dir-iterator.c b/dir-iterator.c
index 278b04243a..de619846f2 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -2,11 +2,20 @@
#include "dir.h"
#include "iterator.h"
#include "dir-iterator.h"
+#include "string-list.h"
struct dir_iterator_level {
DIR *dir;
/*
+ * The directory entries of the current level. This list will only be
+ * populated when the iterator is ordered. In that case, `dir` will be
+ * set to `NULL`.
+ */
+ struct string_list entries;
+ size_t entries_idx;
+
+ /*
* The length of the directory part of path at this level
* (including a trailing '/'):
*/
@@ -43,6 +52,31 @@ struct dir_iterator_int {
unsigned int flags;
};
+static int next_directory_entry(DIR *dir, const char *path,
+ struct dirent **out)
+{
+ struct dirent *de;
+
+repeat:
+ errno = 0;
+ de = readdir(dir);
+ if (!de) {
+ if (errno) {
+ warning_errno("error reading directory '%s'",
+ path);
+ return -1;
+ }
+
+ return 1;
+ }
+
+ if (is_dot_or_dotdot(de->d_name))
+ goto repeat;
+
+ *out = de;
+ return 0;
+}
+
/*
* Push a level in the iter stack and initialize it with information from
* the directory pointed by iter->base->path. It is assumed that this
@@ -72,6 +106,35 @@ static int push_level(struct dir_iterator_int *iter)
return -1;
}
+ string_list_init_dup(&level->entries);
+ level->entries_idx = 0;
+
+ /*
+ * When the iterator is sorted we read and sort all directory entries
+ * directly.
+ */
+ if (iter->flags & DIR_ITERATOR_SORTED) {
+ struct dirent *de;
+
+ while (1) {
+ int ret = next_directory_entry(level->dir, iter->base.path.buf, &de);
+ if (ret < 0) {
+ if (errno != ENOENT &&
+ iter->flags & DIR_ITERATOR_PEDANTIC)
+ return -1;
+ continue;
+ } else if (ret > 0) {
+ break;
+ }
+
+ string_list_append(&level->entries, de->d_name);
+ }
+ string_list_sort(&level->entries);
+
+ closedir(level->dir);
+ level->dir = NULL;
+ }
+
return 0;
}
@@ -88,21 +151,22 @@ static int pop_level(struct dir_iterator_int *iter)
warning_errno("error closing directory '%s'",
iter->base.path.buf);
level->dir = NULL;
+ string_list_clear(&level->entries, 0);
return --iter->levels_nr;
}
/*
* Populate iter->base with the necessary information on the next iteration
- * entry, represented by the given dirent de. Return 0 on success and -1
+ * entry, represented by the given name. Return 0 on success and -1
* otherwise, setting errno accordingly.
*/
static int prepare_next_entry_data(struct dir_iterator_int *iter,
- struct dirent *de)
+ const char *name)
{
int err, saved_errno;
- strbuf_addstr(&iter->base.path, de->d_name);
+ strbuf_addstr(&iter->base.path, name);
/*
* We have to reset these because the path strbuf might have
* been realloc()ed at the previous strbuf_addstr().
@@ -139,27 +203,34 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
struct dirent *de;
struct dir_iterator_level *level =
&iter->levels[iter->levels_nr - 1];
+ const char *name;
strbuf_setlen(&iter->base.path, level->prefix_len);
- errno = 0;
- de = readdir(level->dir);
- if (!de) {
- if (errno) {
- warning_errno("error reading directory '%s'",
- iter->base.path.buf);
+ if (level->dir) {
+ int ret = next_directory_entry(level->dir, iter->base.path.buf, &de);
+ if (ret < 0) {
if (iter->flags & DIR_ITERATOR_PEDANTIC)
goto error_out;
- } else if (pop_level(iter) == 0) {
- return dir_iterator_abort(dir_iterator);
+ continue;
+ } else if (ret > 0) {
+ if (pop_level(iter) == 0)
+ return dir_iterator_abort(dir_iterator);
+ continue;
}
- continue;
- }
- if (is_dot_or_dotdot(de->d_name))
- continue;
+ name = de->d_name;
+ } else {
+ if (level->entries_idx >= level->entries.nr) {
+ if (pop_level(iter) == 0)
+ return dir_iterator_abort(dir_iterator);
+ continue;
+ }
- if (prepare_next_entry_data(iter, de)) {
+ name = level->entries.items[level->entries_idx++].string;
+ }
+
+ if (prepare_next_entry_data(iter, name)) {
if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
goto error_out;
continue;
@@ -188,6 +259,8 @@ int dir_iterator_abort(struct dir_iterator *dir_iterator)
warning_errno("error closing directory '%s'",
iter->base.path.buf);
}
+
+ string_list_clear(&level->entries, 0);
}
free(iter->levels);
diff --git a/dir-iterator.h b/dir-iterator.h
index 479e1ec784..6d438809b6 100644
--- a/dir-iterator.h
+++ b/dir-iterator.h
@@ -54,8 +54,11 @@
* and ITER_ERROR is returned immediately. In both cases, a meaningful
* warning is emitted. Note: ENOENT errors are always ignored so that
* the API users may remove files during iteration.
+ *
+ * - DIR_ITERATOR_SORTED: sort directory entries alphabetically.
*/
#define DIR_ITERATOR_PEDANTIC (1 << 0)
+#define DIR_ITERATOR_SORTED (1 << 1)
struct dir_iterator {
/* The current path: */
diff --git a/dir.c b/dir.c
index 6e3853d67d..7f35a3e317 100644
--- a/dir.c
+++ b/dir.c
@@ -5,6 +5,9 @@
* Copyright (C) Linus Torvalds, 2005-2006
* Junio Hamano, 2005-2006
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
@@ -16,8 +19,8 @@
#include "object-file.h"
#include "object-store-ll.h"
#include "path.h"
-#include "attr.h"
#include "refs.h"
+#include "repository.h"
#include "wildmatch.h"
#include "pathspec.h"
#include "utf8.h"
@@ -31,6 +34,13 @@
#include "symlinks.h"
#include "trace2.h"
#include "tree.h"
+#include "hex.h"
+
+ /*
+ * The maximum size of a pattern/exclude file. If the file exceeds this size
+ * we will ignore it.
+ */
+#define PATTERN_MAX_FILE_SIZE (100 * 1024 * 1024)
/*
* Tells read_directory_recursive how a file or directory should be treated.
@@ -86,7 +96,7 @@ int count_slashes(const char *s)
return cnt;
}
-int fspathcmp(const char *a, const char *b)
+int git_fspathcmp(const char *a, const char *b)
{
return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
}
@@ -96,7 +106,7 @@ int fspatheq(const char *a, const char *b)
return !fspathcmp(a, b);
}
-int fspathncmp(const char *a, const char *b, size_t count)
+int git_fspathncmp(const char *a, const char *b, size_t count)
{
return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);
}
@@ -727,6 +737,17 @@ static char *dup_and_filter_pattern(const char *pattern)
return result;
}
+static void clear_pattern_entry_hashmap(struct hashmap *map)
+{
+ struct hashmap_iter iter;
+ struct pattern_entry *entry;
+
+ hashmap_for_each_entry(map, &iter, entry, ent) {
+ free(entry->pattern);
+ }
+ hashmap_clear_and_free(map, struct pattern_entry, ent);
+}
+
static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern *given)
{
struct pattern_entry *translated;
@@ -800,6 +821,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
if (given->patternlen > 2 &&
!strcmp(given->pattern + given->patternlen - 2, "/*")) {
+ struct pattern_entry *old;
+
if (!(given->flags & PATTERN_FLAG_NEGATIVE)) {
/* Not a cone pattern. */
warning(_("unrecognized pattern: '%s'"), given->pattern);
@@ -825,7 +848,11 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
}
hashmap_add(&pl->parent_hashmap, &translated->ent);
- hashmap_remove(&pl->recursive_hashmap, &translated->ent, &data);
+ old = hashmap_remove_entry(&pl->recursive_hashmap, translated, ent, &data);
+ if (old) {
+ free(old->pattern);
+ free(old);
+ }
free(data);
return;
}
@@ -856,8 +883,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
clear_hashmaps:
warning(_("disabling cone pattern matching"));
- hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent);
- hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent);
+ clear_pattern_entry_hashmap(&pl->recursive_hashmap);
+ clear_pattern_entry_hashmap(&pl->parent_hashmap);
pl->use_cone_patterns = 0;
}
@@ -909,12 +936,7 @@ void add_pattern(const char *string, const char *base,
int nowildcardlen;
parse_path_pattern(&string, &patternlen, &flags, &nowildcardlen);
- if (flags & PATTERN_FLAG_MUSTBEDIR) {
- FLEXPTR_ALLOC_MEM(pattern, pattern, string, patternlen);
- } else {
- pattern = xmalloc(sizeof(*pattern));
- pattern->pattern = string;
- }
+ FLEX_ALLOC_MEM(pattern, pattern, string, patternlen);
pattern->patternlen = patternlen;
pattern->nowildcardlen = nowildcardlen;
pattern->base = base;
@@ -956,9 +978,8 @@ void clear_pattern_list(struct pattern_list *pl)
for (i = 0; i < pl->nr; i++)
free(pl->patterns[i]);
free(pl->patterns);
- free(pl->filebuf);
- hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent);
- hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent);
+ clear_pattern_entry_hashmap(&pl->recursive_hashmap);
+ clear_pattern_entry_hashmap(&pl->parent_hashmap);
memset(pl, 0, sizeof(*pl));
}
@@ -1035,6 +1056,8 @@ static void do_invalidate_gitignore(struct untracked_cache_dir *dir)
{
int i;
dir->valid = 0;
+ for (size_t i = 0; i < dir->untracked_nr; i++)
+ free(dir->untracked[i]);
dir->untracked_nr = 0;
for (i = 0; i < dir->dirs_nr; i++)
do_invalidate_gitignore(dir->dirs[i]);
@@ -1062,6 +1085,8 @@ static void invalidate_directory(struct untracked_cache *uc,
uc->dir_invalidated++;
dir->valid = 0;
+ for (size_t i = 0; i < dir->untracked_nr; i++)
+ free(dir->untracked[i]);
dir->untracked_nr = 0;
for (i = 0; i < dir->dirs_nr; i++)
dir->dirs[i]->recurse = 0;
@@ -1149,7 +1174,14 @@ static int add_patterns(const char *fname, const char *base, int baselen,
}
}
+ if (size > PATTERN_MAX_FILE_SIZE) {
+ warning("ignoring excessively large pattern file: %s", fname);
+ free(buf);
+ return -1;
+ }
+
add_patterns_from_buffer(buf, size, base, baselen, pl);
+ free(buf);
return 0;
}
@@ -1157,16 +1189,15 @@ static int add_patterns_from_buffer(char *buf, size_t size,
const char *base, int baselen,
struct pattern_list *pl)
{
+ char *orig = buf;
int i, lineno = 1;
char *entry;
hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
- pl->filebuf = buf;
-
if (skip_utf8_bom(&buf, size))
- size -= buf - pl->filebuf;
+ size -= buf - orig;
entry = buf;
@@ -1205,7 +1236,15 @@ int add_patterns_from_blob_to_list(
if (r != 1)
return r;
+ if (size > PATTERN_MAX_FILE_SIZE) {
+ warning("ignoring excessively large pattern blob: %s",
+ oid_to_hex(oid));
+ free(buf);
+ return -1;
+ }
+
add_patterns_from_buffer(buf, size, base, baselen, pl);
+ free(buf);
return 0;
}
@@ -1656,7 +1695,7 @@ static void prep_exclude(struct dir_struct *dir,
}
/* Try to read per-directory file */
- oidclr(&oid_stat.oid);
+ oidclr(&oid_stat.oid, the_repository->hash_algo);
oid_stat.valid = 0;
if (dir->exclude_per_dir &&
/*
@@ -2101,8 +2140,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
*/
state = path_none;
} else {
- int i;
- for (i = old_ignored_nr + 1; i<dir->ignored_nr; ++i)
+ for (int i = old_ignored_nr; i < dir->ignored_nr; i++)
FREE_AND_NULL(dir->ignored[i]);
dir->ignored_nr = old_ignored_nr;
}
@@ -2114,8 +2152,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
*/
if ((dir->flags & DIR_SHOW_IGNORED_TOO) &&
!(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
- int i;
- for (i = old_untracked_nr + 1; i<dir->nr; ++i)
+ for (int i = old_untracked_nr; i < dir->nr; i++)
FREE_AND_NULL(dir->entries[i]);
dir->nr = old_untracked_nr;
}
@@ -2191,7 +2228,8 @@ static int exclude_matches_pathspec(const char *path, int pathlen,
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
for (i = 0; i < pathspec->nr; i++) {
const struct pathspec_item *item = &pathspec->items[i];
@@ -2247,6 +2285,39 @@ static int get_index_dtype(struct index_state *istate,
return DT_UNKNOWN;
}
+unsigned char get_dtype(struct dirent *e, struct strbuf *path,
+ int follow_symlink)
+{
+ struct stat st;
+ unsigned char dtype = DTYPE(e);
+ size_t base_path_len;
+
+ if (dtype != DT_UNKNOWN && !(follow_symlink && dtype == DT_LNK))
+ return dtype;
+
+ /*
+ * d_type unknown or unfollowed symlink, try to fall back on [l]stat
+ * results. If [l]stat fails, explicitly set DT_UNKNOWN.
+ */
+ base_path_len = path->len;
+ strbuf_addstr(path, e->d_name);
+ if ((follow_symlink && stat(path->buf, &st)) ||
+ (!follow_symlink && lstat(path->buf, &st)))
+ goto cleanup;
+
+ /* determine d_type from st_mode */
+ if (S_ISREG(st.st_mode))
+ dtype = DT_REG;
+ else if (S_ISDIR(st.st_mode))
+ dtype = DT_DIR;
+ else if (S_ISLNK(st.st_mode))
+ dtype = DT_LNK;
+
+cleanup:
+ strbuf_setlen(path, base_path_len);
+ return dtype;
+}
+
static int resolve_dtype(int dtype, struct index_state *istate,
const char *path, int len)
{
@@ -2770,7 +2841,7 @@ static const char *get_ident_string(void)
return sb.buf;
if (uname(&uts) < 0)
die_errno(_("failed to get kernel name and information"));
- strbuf_addf(&sb, "Location %s, system %s", get_git_work_tree(),
+ strbuf_addf(&sb, "Location %s, system %s", repo_get_work_tree(the_repository),
uts.sysname);
return sb.buf;
}
@@ -2801,14 +2872,14 @@ static void set_untracked_ident(struct untracked_cache *uc)
static unsigned new_untracked_cache_flags(struct index_state *istate)
{
struct repository *repo = istate->repo;
- char *val;
+ const char *val;
/*
* This logic is coordinated with the setting of these flags in
* wt-status.c#wt_status_collect_untracked(), and the evaluation
* of the config setting in commit.c#git_status_config()
*/
- if (!repo_config_get_string(repo, "status.showuntrackedfiles", &val) &&
+ if (!repo_config_get_string_tmp(repo, "status.showuntrackedfiles", &val) &&
!strcmp(val, "all"))
return 0;
@@ -3285,7 +3356,8 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
struct object_id submodule_head;
if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
- !resolve_gitlink_ref(path->buf, "HEAD", &submodule_head)) {
+ !repo_resolve_gitlink_ref(the_repository, path->buf,
+ "HEAD", &submodule_head)) {
/* Do not descend and nuke a nested git work tree. */
if (kept_up)
*kept_up = 1;
@@ -3505,6 +3577,8 @@ static void write_one_dir(struct untracked_cache_dir *untracked,
* for safety..
*/
if (!untracked->valid) {
+ for (size_t i = 0; i < untracked->untracked_nr; i++)
+ free(untracked->untracked[i]);
untracked->untracked_nr = 0;
untracked->check_only = 0;
}
@@ -3728,7 +3802,7 @@ static void read_oid(size_t pos, void *cb)
rd->data = rd->end + 1;
return;
}
- oidread(&ud->exclude_oid, rd->data);
+ oidread(&ud->exclude_oid, rd->data, the_repository->hash_algo);
rd->data += the_hash_algo->rawsz;
}
@@ -3736,7 +3810,7 @@ static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data,
const unsigned char *sha1)
{
stat_data_from_disk(&oid_stat->stat, data);
- oidread(&oid_stat->oid, sha1);
+ oidread(&oid_stat->oid, sha1, the_repository->hash_algo);
oid_stat->valid = 1;
}
@@ -3837,6 +3911,8 @@ static void invalidate_one_directory(struct untracked_cache *uc,
{
uc->dir_invalidated++;
ucd->valid = 0;
+ for (size_t i = 0; i < ucd->untracked_nr; i++)
+ free(ucd->untracked[i]);
ucd->untracked_nr = 0;
}
@@ -3897,6 +3973,26 @@ void untracked_cache_invalidate_path(struct index_state *istate,
path, strlen(path));
}
+void untracked_cache_invalidate_trimmed_path(struct index_state *istate,
+ const char *path,
+ int safe_path)
+{
+ size_t len = strlen(path);
+
+ if (!len)
+ BUG("untracked_cache_invalidate_trimmed_path given zero length path");
+
+ if (path[len - 1] != '/') {
+ untracked_cache_invalidate_path(istate, path, safe_path);
+ } else {
+ struct strbuf tmp = STRBUF_INIT;
+
+ strbuf_add(&tmp, path, len - 1);
+ untracked_cache_invalidate_path(istate, tmp.buf, safe_path);
+ strbuf_release(&tmp);
+ }
+}
+
void untracked_cache_remove_from_index(struct index_state *istate,
const char *path)
{
diff --git a/dir.h b/dir.h
index e761f0fea0..a3a2f00f5d 100644
--- a/dir.h
+++ b/dir.h
@@ -1,7 +1,7 @@
#ifndef DIR_H
#define DIR_H
-#include "hash-ll.h"
+#include "hash.h"
#include "hashmap.h"
#include "pathspec.h"
#include "statinfo.h"
@@ -62,7 +62,6 @@ struct path_pattern {
*/
struct pattern_list *pl;
- const char *pattern;
int patternlen;
int nowildcardlen;
const char *base;
@@ -74,6 +73,8 @@ struct path_pattern {
* and from -1 decrementing for patterns from CLI args.
*/
int srcpos;
+
+ char pattern[FLEX_ARRAY];
};
/* used for hashmaps for cone patterns */
@@ -94,9 +95,6 @@ struct pattern_list {
int nr;
int alloc;
- /* remember pointer to exclude file contents so we can free() */
- char *filebuf;
-
/* origin of list, e.g. path to filename, or descriptive string */
const char *src;
@@ -363,6 +361,22 @@ struct dir_struct {
struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp);
+/*
+ * Get the d_type of a dirent. If the d_type is unknown, derive it from
+ * stat.st_mode using the path to the dirent's containing directory (path) and
+ * the name of the dirent itself.
+ *
+ * If 'follow_symlink' is 1, this function will attempt to follow DT_LNK types
+ * using 'stat'. Links are *not* followed recursively, so a symlink pointing
+ * to another symlink will still resolve to 'DT_LNK'.
+ *
+ * Note that 'path' is assumed to have a trailing slash. It is also modified
+ * in-place during the execution of the function, but is then reverted to its
+ * original value before returning.
+ */
+unsigned char get_dtype(struct dirent *e, struct strbuf *path,
+ int follow_symlink);
+
/*Count the number of slashes for string s*/
int count_slashes(const char *s);
@@ -527,9 +541,9 @@ int remove_dir_recursively(struct strbuf *path, int flag);
*/
int remove_path(const char *path);
-int fspathcmp(const char *a, const char *b);
+int git_fspathcmp(const char *a, const char *b);
int fspatheq(const char *a, const char *b);
-int fspathncmp(const char *a, const char *b, size_t count);
+int git_fspathncmp(const char *a, const char *b, size_t count);
unsigned int fspathhash(const char *str);
/*
@@ -567,6 +581,13 @@ int cmp_dir_entry(const void *p1, const void *p2);
int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in);
void untracked_cache_invalidate_path(struct index_state *, const char *, int safe_path);
+/*
+ * Invalidate the untracked-cache for this path, but first strip
+ * off a trailing slash, if present.
+ */
+void untracked_cache_invalidate_trimmed_path(struct index_state *,
+ const char *path,
+ int safe_path);
void untracked_cache_remove_from_index(struct index_state *, const char *);
void untracked_cache_add_to_index(struct index_state *, const char *);
diff --git a/editor.c b/editor.c
index b67b802ddf..6b9ce81d5f 100644
--- a/editor.c
+++ b/editor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
@@ -104,16 +106,15 @@ static int launch_specified_editor(const char *editor, const char *path,
sigchain_pop(SIGQUIT);
if (sig == SIGINT || sig == SIGQUIT)
raise(sig);
- if (ret)
- return error("There was a problem with the editor '%s'.",
- editor);
-
if (print_waiting_for_editor && !is_terminal_dumb())
/*
* Erase the entire line to avoid wasting the
* vertical space.
*/
term_clear_line();
+ if (ret)
+ return error("there was a problem with the editor '%s'",
+ editor);
}
if (!buffer)
@@ -134,14 +135,17 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
return launch_specified_editor(git_sequence_editor(), path, buffer, env);
}
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+int strbuf_edit_interactively(struct repository *r,
+ struct strbuf *buffer, const char *path,
const char *const *env)
{
- char *path2 = NULL;
+ struct strbuf sb = STRBUF_INIT;
int fd, res = 0;
- if (!is_absolute_path(path))
- path = path2 = xstrdup(git_path("%s", path));
+ if (!is_absolute_path(path)) {
+ strbuf_repo_git_path(&sb, r, "%s", path);
+ path = sb.buf;
+ }
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
@@ -158,6 +162,6 @@ int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
unlink(path);
}
- free(path2);
+ strbuf_release(&sb);
return res;
}
diff --git a/editor.h b/editor.h
index 8016bb5e00..f1c41df378 100644
--- a/editor.h
+++ b/editor.h
@@ -1,6 +1,7 @@
#ifndef EDITOR_H
#define EDITOR_H
+struct repository;
struct strbuf;
const char *git_editor(void);
@@ -28,7 +29,7 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
*
* If `path` is relative, it refers to a file in the `.git` directory.
*/
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
- const char *const *env);
+int strbuf_edit_interactively(struct repository *r, struct strbuf *buffer,
+ const char *path, const char *const *env);
#endif
diff --git a/entry.c b/entry.c
index 29df651f87..3143b9996b 100644
--- a/entry.c
+++ b/entry.c
@@ -1,5 +1,6 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "blob.h"
#include "object-store-ll.h"
#include "dir.h"
#include "environment.h"
@@ -168,6 +169,11 @@ static int remove_available_paths(struct string_list_item *item, void *cb_data)
return !available;
}
+static int string_is_not_null(struct string_list_item *item, void *data UNUSED)
+{
+ return !!item->string;
+}
+
int finish_delayed_checkout(struct checkout *state, int show_progress)
{
int errs = 0;
@@ -185,12 +191,12 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
progress = start_delayed_progress(_("Filtering content"), dco->paths.nr);
while (dco->filters.nr > 0) {
for_each_string_list_item(filter, &dco->filters) {
- struct string_list available_paths = STRING_LIST_INIT_NODUP;
+ struct string_list available_paths = STRING_LIST_INIT_DUP;
if (!async_query_available_blobs(filter->string, &available_paths)) {
/* Filter reported an error */
errs = 1;
- filter->string = "";
+ filter->string = NULL;
continue;
}
if (available_paths.nr <= 0) {
@@ -200,7 +206,7 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
* filter from the list (see
* "string_list_remove_empty_items" call below).
*/
- filter->string = "";
+ filter->string = NULL;
continue;
}
@@ -226,7 +232,7 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
* Do not ask the filter for available blobs,
* again, as the filter is likely buggy.
*/
- filter->string = "";
+ filter->string = NULL;
continue;
}
ce = index_file_exists(state->istate, path->string,
@@ -239,8 +245,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
} else
errs = 1;
}
+
+ string_list_clear(&available_paths, 0);
}
- string_list_remove_empty_items(&dco->filters, 0);
+
+ filter_string_list(&dco->filters, 0, string_is_not_null, NULL);
}
stop_progress(&progress);
string_list_clear(&dco->filters, 0);
@@ -595,3 +604,8 @@ void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
return;
schedule_dir_for_removal(ce->name, ce_namelen(ce));
}
+
+int remove_or_warn(unsigned int mode, const char *file)
+{
+ return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
+}
diff --git a/entry.h b/entry.h
index 7329f918a9..ca3ed35bc0 100644
--- a/entry.h
+++ b/entry.h
@@ -62,4 +62,10 @@ int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st)
void update_ce_after_write(const struct checkout *state, struct cache_entry *ce,
struct stat *st);
+/*
+ * Calls the correct function out of {unlink,rmdir}_or_warn based on
+ * the supplied file mode.
+ */
+int remove_or_warn(unsigned int mode, const char *path);
+
#endif /* ENTRY_H */
diff --git a/environment.c b/environment.c
index f98d76f080..a2ce998081 100644
--- a/environment.c
+++ b/environment.c
@@ -7,6 +7,9 @@
* even if you might want to know where the git directory etc
* are.
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "branch.h"
@@ -19,15 +22,9 @@
#include "fmt-merge-msg.h"
#include "commit.h"
#include "strvec.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;
@@ -37,17 +34,15 @@ int has_symlinks = 1;
int minimum_abbrev = 4, default_abbrev = -1;
int ignore_case;
int assume_unchanged;
-int prefer_symlink_refs;
int is_bare_repository_cfg = -1; /* unspecified */
-int warn_ambiguous_refs = 1;
int warn_on_object_refname_ambiguity = 1;
int repository_format_precious_objects;
-const char *git_commit_encoding;
-const char *git_log_output_encoding;
+char *git_commit_encoding;
+char *git_log_output_encoding;
char *apply_default_whitespace;
char *apply_default_ignorewhitespace;
-const char *git_attributes_file;
-const char *git_hooks_path;
+char *git_attributes_file;
+char *git_hooks_path;
int zlib_compression_level = Z_BEST_SPEED;
int pack_compression_level = Z_DEFAULT_COMPRESSION;
int fsync_object_files = -1;
@@ -58,13 +53,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;
-const char *editor_program;
-const char *askpass_program;
-const char *excludes_file;
+char *editor_program;
+char *askpass_program;
+char *excludes_file;
enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
-char *check_roundtrip_encoding = "SHIFT-JIS";
+char *check_roundtrip_encoding;
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;
@@ -72,7 +67,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
#endif
enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
-char *notes_ref_name;
int grafts_keep_true_parents;
int core_apply_sparse_checkout;
int core_sparse_checkout_cone;
@@ -80,7 +74,20 @@ int sparse_expect_files_outside_of_patterns;
int merge_log_config = -1;
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
unsigned long pack_size_limit_cfg;
-enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
+int max_allowed_tree_depth =
+#ifdef _MSC_VER
+ /*
+ * When traversing into too-deep trees, Visual C-compiled Git seems to
+ * run into some internal stack overflow detection in the
+ * `RtlpAllocateHeap()` function that is called from within
+ * `git_inflate_init()`'s call tree. The following value seems to be
+ * low enough to avoid that by letting Git exit with an error before
+ * the stack overflow can occur.
+ */
+ 512;
+#else
+ 2048;
+#endif
#ifndef PROTECT_HFS_DEFAULT
#define PROTECT_HFS_DEFAULT 0
@@ -96,7 +103,8 @@ int protect_ntfs = PROTECT_NTFS_DEFAULT;
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
*/
-char comment_line_char = '#';
+const char *comment_line_str = "#";
+char *comment_line_str_to_free;
int auto_comment_line_char;
/* Parallel index stat data preload? */
@@ -105,8 +113,6 @@ int core_preload_index = 1;
/* This is set by setup_git_dir_gently() and/or git_default_config() */
char *git_work_tree_cfg;
-static char *git_namespace;
-
/*
* Repository-local GIT_* environment variables; see environment.h for details.
*/
@@ -129,27 +135,6 @@ const char * const local_repo_env[] = {
NULL
};
-static char *expand_namespace(const char *raw_namespace)
-{
- struct strbuf buf = STRBUF_INIT;
- struct strbuf **components, **c;
-
- if (!raw_namespace || !*raw_namespace)
- return xstrdup("");
-
- strbuf_addstr(&buf, raw_namespace);
- components = strbuf_split(&buf, '/');
- strbuf_reset(&buf);
- for (c = components; *c; c++)
- if (strcmp((*c)->buf, "/") != 0)
- strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
- strbuf_list_free(components);
- if (check_refname_format(buf.buf, 0))
- die(_("bad git namespace path \"%s\""), raw_namespace);
- strbuf_addch(&buf, '/');
- return strbuf_detach(&buf, NULL);
-}
-
const char *getenv_safe(struct strvec *argv, const char *name)
{
const char *value = getenv(name);
@@ -161,44 +146,10 @@ const char *getenv_safe(struct strvec *argv, const char *name)
return argv->v[argv->nr - 1];
}
-void setup_git_env(const char *git_dir)
-{
- char *git_replace_ref_base;
- const char *shallow_file;
- const char *replace_ref_base;
- struct set_gitdir_args args = { NULL };
- struct strvec to_free = STRVEC_INIT;
-
- args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT);
- args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT);
- args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
- args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
- args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
- if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
- args.disable_ref_updates = 1;
- }
-
- repo_set_gitdir(the_repository, git_dir, &args);
- strvec_clear(&to_free);
-
- if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
- 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/");
- update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
-
- free(git_namespace);
- git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
- shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
- if (shallow_file)
- set_alternate_shallow_file(the_repository, shallow_file, 0);
-}
-
int is_bare_repository(void)
{
/* if core.bare is not 'false', let's see if there is a work tree */
- return is_bare_repository_cfg && !get_git_work_tree();
+ return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
}
int have_git_dir(void)
@@ -207,156 +158,45 @@ int have_git_dir(void)
|| the_repository->gitdir;
}
-const char *get_git_dir(void)
-{
- if (!the_repository->gitdir)
- BUG("git environment hasn't been setup");
- return the_repository->gitdir;
-}
-
-const char *get_git_common_dir(void)
-{
- if (!the_repository->commondir)
- BUG("git environment hasn't been setup");
- return the_repository->commondir;
-}
-
const char *get_git_namespace(void)
{
- if (!git_namespace)
- BUG("git environment hasn't been setup");
- return git_namespace;
-}
+ static const char *namespace;
-const char *strip_namespace(const char *namespaced_ref)
-{
- const char *out;
- if (skip_prefix(namespaced_ref, get_git_namespace(), &out))
- return out;
- return NULL;
-}
+ struct strbuf buf = STRBUF_INIT;
+ struct strbuf **components, **c;
+ const char *raw_namespace;
-static int git_work_tree_initialized;
+ if (namespace)
+ return namespace;
-/*
- * Note. This works only before you used a work tree. This was added
- * primarily to support git-clone to work in a new repository it just
- * created, and is not meant to flip between different work trees.
- */
-void set_git_work_tree(const char *new_work_tree)
-{
- if (git_work_tree_initialized) {
- struct strbuf realpath = STRBUF_INIT;
-
- strbuf_realpath(&realpath, new_work_tree, 1);
- new_work_tree = realpath.buf;
- if (strcmp(new_work_tree, the_repository->worktree))
- die("internal error: work tree has already been set\n"
- "Current worktree: %s\nNew worktree: %s",
- the_repository->worktree, new_work_tree);
- strbuf_release(&realpath);
- return;
+ raw_namespace = getenv(GIT_NAMESPACE_ENVIRONMENT);
+ if (!raw_namespace || !*raw_namespace) {
+ namespace = "";
+ return namespace;
}
- git_work_tree_initialized = 1;
- repo_set_worktree(the_repository, new_work_tree);
-}
-
-const char *get_git_work_tree(void)
-{
- return the_repository->worktree;
-}
-
-const char *get_object_directory(void)
-{
- if (!the_repository->objects->odb)
- BUG("git environment hasn't been setup");
- return the_repository->objects->odb->path;
-}
-
-int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
-{
- int fd;
- /*
- * we let the umask do its job, don't try to be more
- * restrictive except to remove write permission.
- */
- int mode = 0444;
- git_path_buf(temp_filename, "objects/%s", pattern);
- fd = git_mkstemp_mode(temp_filename->buf, mode);
- if (0 <= fd)
- return fd;
-
- /* slow path */
- /* some mkstemp implementations erase temp_filename on failure */
- git_path_buf(temp_filename, "objects/%s", pattern);
- safe_create_leading_directories(temp_filename->buf);
- return xmkstemp_mode(temp_filename->buf, mode);
-}
-
-int odb_pack_keep(const char *name)
-{
- int fd;
-
- fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
- if (0 <= fd)
- return fd;
-
- /* slow path */
- safe_create_leading_directories_const(name);
- return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
-}
-
-char *get_index_file(void)
-{
- if (!the_repository->index_file)
- BUG("git environment hasn't been setup");
- return the_repository->index_file;
-}
-
-char *get_graft_file(struct repository *r)
-{
- if (!r->graft_file)
- BUG("git environment hasn't been setup");
- return r->graft_file;
-}
-static void set_git_dir_1(const char *path)
-{
- xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
- setup_git_env(path);
-}
+ strbuf_addstr(&buf, raw_namespace);
+ components = strbuf_split(&buf, '/');
+ strbuf_reset(&buf);
+ for (c = components; *c; c++)
+ if (strcmp((*c)->buf, "/") != 0)
+ strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
+ strbuf_list_free(components);
+ if (check_refname_format(buf.buf, 0))
+ die(_("bad git namespace path \"%s\""), raw_namespace);
+ strbuf_addch(&buf, '/');
-static void update_relative_gitdir(const char *name UNUSED,
- const char *old_cwd,
- const char *new_cwd,
- void *data UNUSED)
-{
- char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
- struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
+ namespace = strbuf_detach(&buf, NULL);
- trace_printf_key(&trace_setup_key,
- "setup: move $GIT_DIR to '%s'",
- path);
- set_git_dir_1(path);
- if (tmp_objdir)
- tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd);
- free(path);
+ return namespace;
}
-void set_git_dir(const char *path, int make_realpath)
+const char *strip_namespace(const char *namespaced_ref)
{
- struct strbuf realpath = STRBUF_INIT;
-
- if (make_realpath) {
- strbuf_realpath(&realpath, path, 1);
- path = realpath.buf;
- }
-
- set_git_dir_1(path);
- if (!is_absolute_path(path))
- chdir_notify_register(NULL, update_relative_gitdir, NULL);
-
- strbuf_release(&realpath);
+ const char *out;
+ if (skip_prefix(namespaced_ref, get_git_namespace(), &out))
+ return out;
+ return NULL;
}
const char *get_log_output_encoding(void)
diff --git a/environment.h b/environment.h
index c5377473c6..923e12661e 100644
--- a/environment.h
+++ b/environment.h
@@ -1,21 +1,7 @@
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_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
- * in argv to be freed later.
- */
-const char *getenv_safe(struct strvec *argv, const char *name);
+#include "repo-settings.h"
/* Double-check local_repo_env below if you add to this list. */
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
@@ -36,6 +22,7 @@ const char *getenv_safe(struct strvec *argv, const char *name);
#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 NO_LAZY_FETCH_ENVIRONMENT "GIT_NO_LAZY_FETCH"
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
@@ -57,6 +44,13 @@ const char *getenv_safe(struct strvec *argv, const char *name);
#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
/*
+ * Environment variable used to propagate the --no-advice global option to the
+ * advice_enabled() helper, even when run in a subprocess.
+ * This is an internal variable that should not be set by the user.
+ */
+#define GIT_ADVICE_ENVIRONMENT "GIT_ADVICE"
+
+/*
* 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
@@ -78,6 +72,8 @@ const char *getenv_safe(struct strvec *argv, const char *name);
*/
#define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
+#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+
/*
* Repository-local GIT_* environment variables; these will be cleared
* when git spawns a sub-process that runs inside another repository.
@@ -86,6 +82,50 @@ const char *getenv_safe(struct strvec *argv, const char *name);
*/
extern const char * const local_repo_env[];
+struct strvec;
+
+/*
+ * Wrapper of getenv() that returns a strdup value. This value is kept
+ * in argv to be freed later.
+ */
+const char *getenv_safe(struct strvec *argv, const char *name);
+
+/*
+ * 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);
+
+/*
+ * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
+ */
+int use_optional_locks(void);
+
+const char *get_git_namespace(void);
+const char *strip_namespace(const char *namespaced_ref);
+
+/*
+ * TODO: All the below state either explicitly or implicitly relies on
+ * `the_repository`. We should eventually get rid of these and make the
+ * dependency on a repository explicit:
+ *
+ * - `setup_git_env()` ideally shouldn't exist as it modifies global state,
+ * namely the environment. The current process shouldn't ever access that
+ * state via envvars though, but should instead consult a `struct
+ * repository`. When spawning new processes, we would ideally also pass a
+ * `struct repository` and then set up the environment variables for the
+ * child process, only.
+ *
+ * - `have_git_dir()` should not have to exist at all. Instead, we should
+ * decide on whether or not we have a `struct repository`.
+ *
+ * - All the global config variables should become tied to a repository. Like
+ * this, we'd correctly honor repository-local configuration and be able to
+ * distinguish configuration values from different repositories.
+ *
+ * Please do not add new global config variables here.
+ */
+# ifdef USE_THE_REPOSITORY_VARIABLE
void setup_git_env(const char *git_dir);
/*
@@ -94,21 +134,19 @@ void setup_git_env(const char *git_dir);
*/
int have_git_dir(void);
+/*
+ * 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 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;
@@ -118,13 +156,11 @@ 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 char *git_attributes_file;
+extern char *git_hooks_path;
extern int zlib_compression_level;
extern int pack_compression_level;
extern size_t packed_git_window_size;
@@ -132,16 +168,7 @@ extern size_t packed_git_limit;
extern size_t delta_base_cache_limit;
extern unsigned long big_file_threshold;
extern unsigned long pack_size_limit_cfg;
-
-/*
- * 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 max_allowed_tree_depth;
extern int core_preload_index;
extern int precomposed_unicode;
@@ -152,25 +179,13 @@ 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
};
+extern enum rebase_setup_type autorebase;
enum push_default_type {
PUSH_DEFAULT_NOTHING = 0,
@@ -180,52 +195,35 @@ enum push_default_type {
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 char *git_commit_encoding;
+extern char *git_log_output_encoding;
-extern const char *editor_program;
-extern const char *askpass_program;
-extern const char *excludes_file;
+extern char *editor_program;
+extern char *askpass_program;
+extern char *excludes_file;
/*
- * Should we print an ellipsis after an abbreviated SHA-1 value
- * when doing diff-raw output or indicating a detached HEAD?
+ * The character that begins a commented line in user-editable file
+ * that is subject to stripspace.
*/
-int print_sha1_ellipsis(void);
+extern const char *comment_line_str;
+extern char *comment_line_str_to_free;
+extern int auto_comment_line_char;
-#endif
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+#endif /* ENVIRONMENT_H */
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
index 7b525b1ecd..55928dada8 100644
--- a/ewah/bitmap.c
+++ b/ewah/bitmap.c
@@ -138,6 +138,49 @@ void bitmap_or(struct bitmap *self, const struct bitmap *other)
self->words[i] |= other->words[i];
}
+int ewah_bitmap_is_subset(struct ewah_bitmap *self, struct bitmap *other)
+{
+ struct ewah_iterator it;
+ eword_t word;
+ size_t i;
+
+ ewah_iterator_init(&it, self);
+
+ for (i = 0; i < other->word_alloc; i++) {
+ if (!ewah_iterator_next(&word, &it)) {
+ /*
+ * If we reached the end of `self`, and haven't
+ * rejected `self` as a possible subset of
+ * `other` yet, then we are done and `self` is
+ * indeed a subset of `other`.
+ */
+ return 1;
+ }
+ if (word & ~other->words[i]) {
+ /*
+ * Otherwise, compare the next two pairs of
+ * words. If the word from `self` has bit(s) not
+ * in the word from `other`, `self` is not a
+ * subset of `other`.
+ */
+ return 0;
+ }
+ }
+
+ /*
+ * If we got to this point, there may be zero or more words
+ * remaining in `self`, with no remaining words left in `other`.
+ * If there are any bits set in the remaining word(s) in `self`,
+ * then `self` is not a subset of `other`.
+ */
+ while (ewah_iterator_next(&word, &it))
+ if (word)
+ return 0;
+
+ /* `self` is definitely a subset of `other` */
+ return 1;
+}
+
void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
{
size_t original_size = self->word_alloc;
@@ -169,6 +212,29 @@ size_t bitmap_popcount(struct bitmap *self)
return count;
}
+size_t ewah_bitmap_popcount(struct ewah_bitmap *self)
+{
+ struct ewah_iterator it;
+ eword_t word;
+ size_t count = 0;
+
+ ewah_iterator_init(&it, self);
+
+ while (ewah_iterator_next(&word, &it))
+ count += ewah_bit_popcount64(word);
+
+ return count;
+}
+
+int bitmap_is_empty(struct bitmap *self)
+{
+ size_t i;
+ for (i = 0; i < self->word_alloc; i++)
+ if (self->words[i])
+ return 0;
+ return 1;
+}
+
int bitmap_equals(struct bitmap *self, struct bitmap *other)
{
struct bitmap *big, *small;
@@ -195,6 +261,25 @@ int bitmap_equals(struct bitmap *self, struct bitmap *other)
return 1;
}
+int bitmap_equals_ewah(struct bitmap *self, struct ewah_bitmap *other)
+{
+ struct ewah_iterator it;
+ eword_t word;
+ size_t i = 0;
+
+ ewah_iterator_init(&it, other);
+
+ while (ewah_iterator_next(&word, &it))
+ if (word != (i < self->word_alloc ? self->words[i++] : 0))
+ return 0;
+
+ for (; i < self->word_alloc; i++)
+ if (self->words[i])
+ return 0;
+
+ return 1;
+}
+
int bitmap_is_subset(struct bitmap *self, struct bitmap *other)
{
size_t common_size, i;
diff --git a/ewah/ewok.h b/ewah/ewok.h
index 7eb8b9b630..5e357e2493 100644
--- a/ewah/ewok.h
+++ b/ewah/ewok.h
@@ -179,7 +179,14 @@ void bitmap_unset(struct bitmap *self, size_t pos);
int bitmap_get(struct bitmap *self, size_t pos);
void bitmap_free(struct bitmap *self);
int bitmap_equals(struct bitmap *self, struct bitmap *other);
+int bitmap_equals_ewah(struct bitmap *self, struct ewah_bitmap *other);
+
+/*
+ * Both `bitmap_is_subset()` and `ewah_bitmap_is_subset()` return 1 if the set
+ * of bits in 'self' are a subset of the bits in 'other'. Returns 0 otherwise.
+ */
int bitmap_is_subset(struct bitmap *self, struct bitmap *other);
+int ewah_bitmap_is_subset(struct ewah_bitmap *self, struct bitmap *other);
struct ewah_bitmap * bitmap_to_ewah(struct bitmap *bitmap);
struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah);
@@ -189,5 +196,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other);
void bitmap_or(struct bitmap *self, const struct bitmap *other);
size_t bitmap_popcount(struct bitmap *self);
+size_t ewah_bitmap_popcount(struct ewah_bitmap *self);
+int bitmap_is_empty(struct bitmap *self);
#endif
diff --git a/exec-cmd.c b/exec-cmd.c
index 1d597e84ea..507e67d528 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -4,7 +4,6 @@
#include "exec-cmd.h"
#include "gettext.h"
#include "path.h"
-#include "quote.h"
#include "run-command.h"
#include "strvec.h"
#include "trace.h"
@@ -151,6 +150,25 @@ static int git_get_exec_path_darwin(struct strbuf *buf)
}
#endif /* HAVE_NS_GET_EXECUTABLE_PATH */
+#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+/*
+ * Resolves the executable path from current program's directory and name.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_zos(struct strbuf *buf)
+{
+ char *dir = __getprogramdir();
+ char *exe = getprogname();
+ if (dir && exe) {
+ strbuf_addf(buf, "%s/%s", dir, exe);
+ return 0;
+ }
+ return -1;
+}
+
+#endif /* HAVE_ZOS_GET_EXECUTABLE_PATH */
+
#ifdef HAVE_WPGMPTR
/*
* Resolves the executable path by using the global variable _wpgmptr.
@@ -207,6 +225,10 @@ static int git_get_exec_path(struct strbuf *buf, const char *argv0)
git_get_exec_path_wpgmptr(buf) &&
#endif /* HAVE_WPGMPTR */
+#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+ git_get_exec_path_zos(buf) &&
+#endif /*HAVE_ZOS_GET_EXECUTABLE_PATH */
+
git_get_exec_path_from_argv0(buf, argv0)) {
return -1;
}
diff --git a/fetch-pack.c b/fetch-pack.c
index 26999e3b65..fe1fb3c1b7 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "repository.h"
#include "config.h"
@@ -10,7 +12,6 @@
#include "pkt-line.h"
#include "commit.h"
#include "tag.h"
-#include "exec-cmd.h"
#include "pack.h"
#include "sideband.h"
#include "fetch-pack.h"
@@ -18,7 +19,6 @@
#include "run-command.h"
#include "connect.h"
#include "trace2.h"
-#include "transport.h"
#include "version.h"
#include "oid-array.h"
#include "oidset.h"
@@ -122,29 +122,41 @@ static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
cb(negotiator, cache.items[i]);
}
-static struct commit *deref_without_lazy_fetch_extended(const struct object_id *oid,
- int mark_tags_complete,
- enum object_type *type,
- unsigned int oi_flags)
+static void die_in_commit_graph_only(const struct object_id *oid)
{
- struct object_info info = { .typep = type };
+ die(_("You are attempting to fetch %s, which is in the commit graph file but not in the object database.\n"
+ "This is probably due to repo corruption.\n"
+ "If you are attempting to repair this repo corruption by refetching the missing object, use 'git fetch --refetch' with the missing object."),
+ oid_to_hex(oid));
+}
+
+static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
+ int mark_tags_complete_and_check_obj_db)
+{
+ enum object_type type;
+ struct object_info info = { .typep = &type };
struct commit *commit;
commit = lookup_commit_in_graph(the_repository, oid);
- if (commit)
+ if (commit) {
+ if (mark_tags_complete_and_check_obj_db) {
+ if (!has_object(the_repository, oid, 0))
+ die_in_commit_graph_only(oid);
+ }
return commit;
+ }
while (1) {
if (oid_object_info_extended(the_repository, oid, &info,
- oi_flags))
+ OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK))
return NULL;
- if (*type == OBJ_TAG) {
+ if (type == OBJ_TAG) {
struct tag *tag = (struct tag *)
parse_object(the_repository, oid);
if (!tag->tagged)
return NULL;
- if (mark_tags_complete)
+ if (mark_tags_complete_and_check_obj_db)
tag->object.flags |= COMPLETE;
oid = &tag->tagged->oid;
} else {
@@ -152,7 +164,7 @@ static struct commit *deref_without_lazy_fetch_extended(const struct object_id *
}
}
- if (*type == OBJ_COMMIT) {
+ if (type == OBJ_COMMIT) {
struct commit *commit = lookup_commit(the_repository, oid);
if (!commit || repo_parse_commit(the_repository, commit))
return NULL;
@@ -162,16 +174,6 @@ static struct commit *deref_without_lazy_fetch_extended(const struct object_id *
return NULL;
}
-
-static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
- int mark_tags_complete)
-{
- enum object_type type;
- unsigned flags = OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK;
- return deref_without_lazy_fetch_extended(oid, mark_tags_complete,
- &type, flags);
-}
-
static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
const struct object_id *oid)
{
@@ -183,6 +185,7 @@ static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
}
static int rev_list_insert_ref_oid(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data)
@@ -292,7 +295,8 @@ static void mark_tips(struct fetch_negotiator *negotiator,
int i;
if (!negotiation_tips) {
- for_each_rawref(rev_list_insert_ref_oid, negotiator);
+ refs_for_each_rawref(get_main_ref_store(the_repository),
+ rev_list_insert_ref_oid, negotiator);
return;
}
@@ -609,6 +613,7 @@ static int mark_complete(const struct object_id *oid)
}
static int mark_complete_oid(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
@@ -734,11 +739,6 @@ static void mark_alternate_complete(struct fetch_negotiator *negotiator UNUSED,
mark_complete(&obj->oid);
}
-struct loose_object_iter {
- struct oidset *loose_object_set;
- struct ref *refs;
-};
-
/*
* Mark recent commits available locally and reachable from a local ref as
* COMPLETE.
@@ -795,7 +795,8 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
*/
trace2_region_enter("fetch-pack", "mark_complete_local_refs", NULL);
if (!args->deepen) {
- for_each_rawref(mark_complete_oid, NULL);
+ refs_for_each_rawref(get_main_ref_store(the_repository),
+ mark_complete_oid, NULL);
for_each_cached_alternate(NULL, mark_alternate_complete);
commit_list_sort_by_date(&complete);
if (cutoff)
@@ -959,12 +960,7 @@ static int get_pack(struct fetch_pack_args *args,
strvec_push(&cmd.args, alternate_shallow_file);
}
- if (fetch_fsck_objects >= 0
- ? fetch_fsck_objects
- : transfer_fsck_objects >= 0
- ? transfer_fsck_objects
- : 0)
- fsck_objects = 1;
+ fsck_objects = fetch_pack_fsck_objects();
if (do_keep || args->from_promisor || index_pack_args || fsck_objects) {
if (pack_lockfiles || fsck_objects)
@@ -1043,8 +1039,10 @@ static int get_pack(struct fetch_pack_args *args,
if (!is_well_formed)
die(_("fetch-pack: invalid index-pack output"));
- if (pack_lockfile)
+ if (pack_lockfiles && pack_lockfile)
string_list_append_nodup(pack_lockfiles, pack_lockfile);
+ else
+ free(pack_lockfile);
parse_gitmodules_oids(cmd.out, gitmodules_oids);
close(cmd.out);
}
@@ -1618,7 +1616,7 @@ static void receive_packfile_uris(struct packet_reader *reader,
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
if (reader->pktlen < the_hash_algo->hexsz ||
reader->line[the_hash_algo->hexsz] != ' ')
- die("expected '<hash> <uri>', got: %s\n", reader->line);
+ die("expected '<hash> <uri>', got: %s", reader->line);
string_list_append(uris, reader->line);
}
@@ -1843,7 +1841,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
string_list_append_nodup(pack_lockfiles,
xstrfmt("%s/pack/pack-%s.keep",
- get_object_directory(),
+ repo_get_object_directory(the_repository),
packname));
}
string_list_clear(&packfile_uris, 0);
@@ -1862,23 +1860,27 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
static int fetch_pack_config_cb(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ const char *msg_id;
+
if (strcmp(var, "fetch.fsck.skiplist") == 0) {
- const char *path;
+ char *path ;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
fsck_msg_types.len ? ',' : '=', path);
- free((char *)path);
+ free(path);
return 0;
}
- if (skip_prefix(var, "fetch.fsck.", &var)) {
- if (is_valid_msg_type(var, value))
+ if (skip_prefix(var, "fetch.fsck.", &msg_id)) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (is_valid_msg_type(msg_id, value))
strbuf_addf(&fsck_msg_types, "%c%s=%s",
- fsck_msg_types.len ? ',' : '=', var, value);
+ fsck_msg_types.len ? ',' : '=', msg_id, value);
else
- warning("Skipping unknown msg id '%s'", var);
+ warning("Skipping unknown msg id '%s'", msg_id);
return 0;
}
@@ -2047,6 +2049,16 @@ static const struct object_id *iterate_ref_map(void *cb_data)
return &ref->old_oid;
}
+int fetch_pack_fsck_objects(void)
+{
+ fetch_pack_setup();
+ if (fetch_fsck_objects >= 0)
+ return fetch_fsck_objects;
+ if (transfer_fsck_objects >= 0)
+ return transfer_fsck_objects;
+ return 0;
+}
+
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[],
const struct ref *ref,
@@ -2214,10 +2226,13 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
the_repository, "%d",
negotiation_round);
}
- trace2_region_enter("fetch-pack", "negotiate_using_fetch", the_repository);
+ trace2_region_leave("fetch-pack", "negotiate_using_fetch", the_repository);
trace2_data_intmax("negotiate_using_fetch", the_repository,
"total_rounds", negotiation_round);
+
clear_common_flag(acked_commits);
+ object_array_clear(&nt_object_array);
+ negotiator.release(&negotiator);
strbuf_release(&req_buf);
}
diff --git a/fetch-pack.h b/fetch-pack.h
index 8c7752fc82..b5c579cdae 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -2,7 +2,6 @@
#define FETCH_PACK_H
#include "string-list.h"
-#include "run-command.h"
#include "protocol.h"
#include "list-objects-filter-options.h"
#include "oidset.h"
@@ -102,4 +101,9 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
*/
int report_unmatched_refs(struct ref **sought, int nr_sought);
+/*
+ * Return true if checks for broken objects in received pack are required.
+ */
+int fetch_pack_fsck_objects(void);
+
#endif
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index 66e47449a0..6acb37b480 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -321,7 +323,7 @@ static void credit_people(struct strbuf *out,
skip_prefix(me, them->items->string, &me) &&
starts_with(me, " <")))
return;
- strbuf_addf(out, "\n%c %s ", comment_line_char, label);
+ strbuf_addf(out, "\n%s %s ", comment_line_str, label);
add_people_count(out, them);
}
@@ -447,7 +449,7 @@ static void fmt_merge_msg_title(struct strbuf *out,
const char *current_branch)
{
int i = 0;
- char *sep = "";
+ const char *sep = "";
strbuf_addstr(out, "Merge ");
for (i = 0; i < srcs.nr; i++) {
@@ -510,7 +512,7 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
if (sig->len) {
strbuf_addch(tagbuf, '\n');
strbuf_add_commented_lines(tagbuf, sig->buf, sig->len,
- comment_line_char);
+ comment_line_str);
}
}
@@ -557,7 +559,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_add_commented_lines(&tagline,
origins.items[first_tag].string,
strlen(origins.items[first_tag].string),
- comment_line_char);
+ comment_line_str);
strbuf_insert(&tagbuf, 0, tagline.buf,
tagline.len);
strbuf_release(&tagline);
@@ -566,7 +568,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_add_commented_lines(&tagbuf,
origins.items[i].string,
strlen(origins.items[i].string),
- comment_line_char);
+ comment_line_str);
fmt_tag_signature(&tagbuf, &sig, buf, len);
}
strbuf_release(&payload);
@@ -661,7 +663,9 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
/* learn the commit that we merge into and the current branch name */
current_branch = current_branch_to_free =
- resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL);
+ refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING, &head_oid,
+ NULL);
if (!current_branch)
die("No current branch");
diff --git a/fsck.c b/fsck.c
index 2b1e348005..3756f52459 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "date.h"
#include "dir.h"
@@ -16,14 +18,14 @@
#include "refs.h"
#include "url.h"
#include "utf8.h"
-#include "decorate.h"
#include "oidset.h"
#include "packfile.h"
#include "submodule-config.h"
#include "config.h"
-#include "credential.h"
#include "help.h"
+static ssize_t max_tree_entry_len = 4096;
+
#define STR(x) #x
#define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
static struct {
@@ -154,15 +156,29 @@ void fsck_set_msg_type(struct fsck_options *options,
const char *msg_id_str, const char *msg_type_str)
{
int msg_id = parse_msg_id(msg_id_str);
- enum fsck_msg_type msg_type = parse_msg_type(msg_type_str);
+ char *to_free = NULL;
+ enum fsck_msg_type msg_type;
if (msg_id < 0)
die("Unhandled message id: %s", msg_id_str);
+ if (msg_id == FSCK_MSG_LARGE_PATHNAME) {
+ const char *colon = strchr(msg_type_str, ':');
+ if (colon) {
+ msg_type_str = to_free =
+ xmemdupz(msg_type_str, colon - msg_type_str);
+ colon++;
+ if (!git_parse_ssize_t(colon, &max_tree_entry_len))
+ die("unable to parse max tree entry len: %s", colon);
+ }
+ }
+ msg_type = parse_msg_type(msg_type_str);
+
if (msg_type != FSCK_ERROR && msg_id_info[msg_id].msg_type == FSCK_FATAL)
die("Cannot demote %s to %s", msg_id_str, msg_type_str);
fsck_set_msg_type_from_ids(options, msg_id, msg_type);
+ free(to_free);
}
void fsck_set_msg_types(struct fsck_options *options, const char *values)
@@ -189,7 +205,8 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
if (!strcmp(buf, "skiplist")) {
if (equal == len)
die("skiplist requires a path");
- oidset_parse_file(&options->skiplist, buf + equal + 1);
+ oidset_parse_file(&options->skip_oids, buf + equal + 1,
+ the_repository->hash_algo);
buf += len + 1;
continue;
}
@@ -206,15 +223,18 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
static int object_on_skiplist(struct fsck_options *opts,
const struct object_id *oid)
{
- return opts && oid && oidset_contains(&opts->skiplist, oid);
+ return opts && oid && oidset_contains(&opts->skip_oids, oid);
}
-__attribute__((format (printf, 5, 6)))
-static int report(struct fsck_options *options,
- const struct object_id *oid, enum object_type object_type,
- enum fsck_msg_id msg_id, const char *fmt, ...)
+/*
+ * Provide the common functionality for either fscking refs or objects.
+ * It will get the current msg error type and call the error_func callback
+ * which is registered in the "fsck_options" struct.
+ */
+static int fsck_vreport(struct fsck_options *options,
+ void *fsck_report,
+ enum fsck_msg_id msg_id, const char *fmt, va_list ap)
{
- va_list ap;
struct strbuf sb = STRBUF_INIT;
enum fsck_msg_type msg_type = fsck_msg_type(msg_id, options);
int result;
@@ -222,9 +242,6 @@ static int report(struct fsck_options *options,
if (msg_type == FSCK_IGNORE)
return 0;
- if (object_on_skiplist(options, oid))
- return 0;
-
if (msg_type == FSCK_FATAL)
msg_type = FSCK_ERROR;
else if (msg_type == FSCK_INFO)
@@ -233,16 +250,49 @@ static int report(struct fsck_options *options,
prepare_msg_ids();
strbuf_addf(&sb, "%s: ", msg_id_info[msg_id].camelcased);
- va_start(ap, fmt);
strbuf_vaddf(&sb, fmt, ap);
- result = options->error_func(options, oid, object_type,
+ result = options->error_func(options, fsck_report,
msg_type, msg_id, sb.buf);
strbuf_release(&sb);
+
+ return result;
+}
+
+__attribute__((format (printf, 5, 6)))
+static int report(struct fsck_options *options,
+ const struct object_id *oid, enum object_type object_type,
+ enum fsck_msg_id msg_id, const char *fmt, ...)
+{
+ va_list ap;
+ struct fsck_object_report report = {
+ .oid = oid,
+ .object_type = object_type
+ };
+ int result;
+
+ if (object_on_skiplist(options, oid))
+ return 0;
+
+ va_start(ap, fmt);
+ result = fsck_vreport(options, &report, msg_id, fmt, ap);
va_end(ap);
return result;
}
+int fsck_report_ref(struct fsck_options *options,
+ struct fsck_ref_report *report,
+ enum fsck_msg_id msg_id,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+ va_start(ap, fmt);
+ result = fsck_vreport(options, report, msg_id, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
void fsck_enable_object_names(struct fsck_options *options)
{
if (!options->object_names)
@@ -313,7 +363,8 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
return -1;
name = fsck_get_object_name(options, &tree->object.oid);
- if (init_tree_desc_gently(&desc, tree->buffer, tree->size, 0))
+ if (init_tree_desc_gently(&desc, &tree->object.oid,
+ tree->buffer, tree->size, 0))
return -1;
while (tree_entry_gently(&desc, &entry)) {
struct object *obj;
@@ -578,12 +629,14 @@ static int fsck_tree(const struct object_id *tree_oid,
int has_bad_modes = 0;
int has_dup_entries = 0;
int not_properly_sorted = 0;
+ int has_large_name = 0;
struct tree_desc desc;
unsigned o_mode;
const char *o_name;
struct name_stack df_dup_candidates = { NULL };
- if (init_tree_desc_gently(&desc, buffer, size, TREE_DESC_RAW_MODES)) {
+ if (init_tree_desc_gently(&desc, tree_oid, buffer, size,
+ TREE_DESC_RAW_MODES)) {
retval += report(options, tree_oid, OBJ_TREE,
FSCK_MSG_BAD_TREE,
"cannot be parsed as a tree");
@@ -607,6 +660,7 @@ static int fsck_tree(const struct object_id *tree_oid,
has_dotdot |= !strcmp(name, "..");
has_dotgit |= is_hfs_dotgit(name) || is_ntfs_dotgit(name);
has_zero_pad |= *(char *)desc.buffer == '0';
+ has_large_name |= tree_entry_len(&desc.entry) > max_tree_entry_len;
if (is_hfs_dotgitmodules(name) || is_ntfs_dotgitmodules(name)) {
if (!S_ISLNK(mode))
@@ -749,6 +803,10 @@ static int fsck_tree(const struct object_id *tree_oid,
retval += report(options, tree_oid, OBJ_TREE,
FSCK_MSG_TREE_NOT_SORTED,
"not properly sorted");
+ if (has_large_name)
+ retval += report(options, tree_oid, OBJ_TREE,
+ FSCK_MSG_LARGE_PATHNAME,
+ "contains excessively large pathname");
return retval;
}
@@ -1026,138 +1084,6 @@ done:
return ret;
}
-static int starts_with_dot_slash(const char *const path)
-{
- return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
- PATH_MATCH_XPLATFORM);
-}
-
-static int starts_with_dot_dot_slash(const char *const path)
-{
- return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
- PATH_MATCH_XPLATFORM);
-}
-
-static int submodule_url_is_relative(const char *url)
-{
- return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
-}
-
-/*
- * Count directory components that a relative submodule URL should chop
- * from the remote_url it is to be resolved against.
- *
- * In other words, this counts "../" components at the start of a
- * submodule URL.
- *
- * Returns the number of directory components to chop and writes a
- * pointer to the next character of url after all leading "./" and
- * "../" components to out.
- */
-static int count_leading_dotdots(const char *url, const char **out)
-{
- int result = 0;
- while (1) {
- if (starts_with_dot_dot_slash(url)) {
- result++;
- url += strlen("../");
- continue;
- }
- if (starts_with_dot_slash(url)) {
- url += strlen("./");
- continue;
- }
- *out = url;
- return result;
- }
-}
-/*
- * Check whether a transport is implemented by git-remote-curl.
- *
- * If it is, returns 1 and writes the URL that would be passed to
- * git-remote-curl to the "out" parameter.
- *
- * Otherwise, returns 0 and leaves "out" untouched.
- *
- * Examples:
- * http::https://example.com/repo.git -> 1, https://example.com/repo.git
- * https://example.com/repo.git -> 1, https://example.com/repo.git
- * git://example.com/repo.git -> 0
- *
- * This is for use in checking for previously exploitable bugs that
- * required a submodule URL to be passed to git-remote-curl.
- */
-static int url_to_curl_url(const char *url, const char **out)
-{
- /*
- * We don't need to check for case-aliases, "http.exe", and so
- * on because in the default configuration, is_transport_allowed
- * prevents URLs with those schemes from being cloned
- * automatically.
- */
- if (skip_prefix(url, "http::", out) ||
- skip_prefix(url, "https::", out) ||
- skip_prefix(url, "ftp::", out) ||
- skip_prefix(url, "ftps::", out))
- return 1;
- if (starts_with(url, "http://") ||
- starts_with(url, "https://") ||
- starts_with(url, "ftp://") ||
- starts_with(url, "ftps://")) {
- *out = url;
- return 1;
- }
- return 0;
-}
-
-static int check_submodule_url(const char *url)
-{
- const char *curl_url;
-
- if (looks_like_command_line_option(url))
- return -1;
-
- if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
- char *decoded;
- const char *next;
- int has_nl;
-
- /*
- * This could be appended to an http URL and url-decoded;
- * check for malicious characters.
- */
- decoded = url_decode(url);
- has_nl = !!strchr(decoded, '\n');
-
- free(decoded);
- if (has_nl)
- return -1;
-
- /*
- * URLs which escape their root via "../" can overwrite
- * the host field and previous components, resolving to
- * URLs like https::example.com/submodule.git and
- * https:///example.com/submodule.git that were
- * susceptible to CVE-2020-11008.
- */
- if (count_leading_dotdots(url, &next) > 0 &&
- (*next == ':' || *next == '/'))
- return -1;
- }
-
- else if (url_to_curl_url(url, &curl_url)) {
- struct credential c = CREDENTIAL_INIT;
- int ret = 0;
- if (credential_from_url_gently(&c, curl_url, 1) ||
- !*c.host)
- ret = -1;
- credential_clear(&c);
- return ret;
- }
-
- return 0;
-}
-
struct fsck_gitmodules_data {
const struct object_id *oid;
struct fsck_options *options;
@@ -1289,7 +1215,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
}
int fsck_buffer(const struct object_id *oid, enum object_type type,
- void *data, unsigned long size,
+ const void *data, unsigned long size,
struct fsck_options *options)
{
if (type == OBJ_BLOB)
@@ -1307,13 +1233,15 @@ int fsck_buffer(const struct object_id *oid, enum object_type type,
type);
}
-int fsck_error_function(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type UNUSED,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id UNUSED,
- const char *message)
+int fsck_objects_error_function(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
{
+ struct fsck_object_report *report = fsck_report;
+ const struct object_id *oid = report->oid;
+
if (msg_type == FSCK_WARN) {
warning("object %s: %s", fsck_describe_object(o, oid), message);
return 0;
@@ -1322,6 +1250,32 @@ int fsck_error_function(struct fsck_options *o,
return 1;
}
+int fsck_refs_error_function(struct fsck_options *options UNUSED,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
+{
+ struct fsck_ref_report *report = fsck_report;
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addstr(&sb, report->path);
+
+ if (report->oid)
+ strbuf_addf(&sb, " -> (%s)", oid_to_hex(report->oid));
+ else if (report->referent)
+ strbuf_addf(&sb, " -> (%s)", report->referent);
+
+ if (msg_type == FSCK_WARN)
+ warning("%s: %s", sb.buf, message);
+ else
+ ret = error("%s: %s", sb.buf, message);
+
+ strbuf_release(&sb);
+ return ret;
+}
+
static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
enum fsck_msg_id msg_missing, enum fsck_msg_id msg_type,
struct fsck_options *options, const char *blob_type)
@@ -1377,25 +1331,40 @@ int fsck_finish(struct fsck_options *options)
return ret;
}
+void fsck_options_clear(struct fsck_options *options)
+{
+ free(options->msg_type);
+ oidset_clear(&options->skip_oids);
+ oidset_clear(&options->gitmodules_found);
+ oidset_clear(&options->gitmodules_done);
+ oidset_clear(&options->gitattributes_found);
+ oidset_clear(&options->gitattributes_done);
+ kh_clear_oid_map(options->object_names);
+}
+
int git_fsck_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
struct fsck_options *options = cb;
+ const char *msg_id;
+
if (strcmp(var, "fsck.skiplist") == 0) {
- const char *path;
+ char *path;
struct strbuf sb = STRBUF_INIT;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&sb, "skiplist=%s", path);
- free((char *)path);
+ free(path);
fsck_set_msg_types(options, sb.buf);
strbuf_release(&sb);
return 0;
}
- if (skip_prefix(var, "fsck.", &var)) {
- fsck_set_msg_type(options, var, value);
+ if (skip_prefix(var, "fsck.", &msg_id)) {
+ if (!value)
+ return config_error_nonbool(var);
+ fsck_set_msg_type(options, msg_id, value);
return 0;
}
@@ -1406,16 +1375,17 @@ int git_fsck_config(const char *var, const char *value,
* Custom error callbacks that are used in more than one place.
*/
-int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id,
- const char *message)
+int fsck_objects_error_cb_print_missing_gitmodules(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message)
{
if (msg_id == FSCK_MSG_GITMODULES_MISSING) {
- puts(oid_to_hex(oid));
+ struct fsck_object_report *report = fsck_report;
+ puts(oid_to_hex(report->oid));
return 0;
}
- return fsck_error_function(o, oid, object_type, msg_type, msg_id, message);
+ return fsck_objects_error_function(o, fsck_report,
+ msg_type, msg_id, message);
}
diff --git a/fsck.h b/fsck.h
index 6359ba359b..a44c231a5f 100644
--- a/fsck.h
+++ b/fsck.h
@@ -31,6 +31,10 @@ enum fsck_msg_type {
FUNC(BAD_NAME, ERROR) \
FUNC(BAD_OBJECT_SHA1, ERROR) \
FUNC(BAD_PARENT_SHA1, ERROR) \
+ FUNC(BAD_REF_CONTENT, ERROR) \
+ FUNC(BAD_REF_FILETYPE, ERROR) \
+ FUNC(BAD_REF_NAME, ERROR) \
+ FUNC(BAD_REFERENT_NAME, ERROR) \
FUNC(BAD_TIMEZONE, ERROR) \
FUNC(BAD_TREE, ERROR) \
FUNC(BAD_TREE_SHA1, ERROR) \
@@ -73,6 +77,7 @@ enum fsck_msg_type {
FUNC(NULL_SHA1, WARN) \
FUNC(ZERO_PADDED_FILEMODE, WARN) \
FUNC(NUL_IN_COMMIT, WARN) \
+ FUNC(LARGE_PATHNAME, WARN) \
/* infos (reported as warnings, but ignored by default) */ \
FUNC(BAD_FILEMODE, INFO) \
FUNC(GITMODULES_PARSE, INFO) \
@@ -81,6 +86,10 @@ enum fsck_msg_type {
FUNC(MAILMAP_SYMLINK, INFO) \
FUNC(BAD_TAG_NAME, INFO) \
FUNC(MISSING_TAGGER_ENTRY, INFO) \
+ FUNC(SYMLINK_REF, INFO) \
+ FUNC(REF_MISSING_NEWLINE, INFO) \
+ FUNC(SYMREF_TARGET_IS_NOT_A_REF, INFO) \
+ FUNC(TRAILING_REF_CONTENT, INFO) \
/* ignored (elevated when requested) */ \
FUNC(EXTRA_HEADER_ENTRY, IGNORE)
@@ -113,29 +122,49 @@ int is_valid_msg_type(const char *msg_id, const char *msg_type);
typedef int (*fsck_walk_func)(struct object *obj, enum object_type object_type,
void *data, struct fsck_options *options);
-/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
+/*
+ * Callback for reporting errors either for objects or refs. The "fsck_report"
+ * is a generic pointer that can be used to pass any information.
+ */
typedef int (*fsck_error)(struct fsck_options *o,
- const struct object_id *oid, enum object_type object_type,
+ void *fsck_report,
enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
const char *message);
-int fsck_error_function(struct fsck_options *o,
- const struct object_id *oid, enum object_type object_type,
- enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
- const char *message);
-int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id,
- const char *message);
+int fsck_objects_error_function(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
+ const char *message);
+int fsck_objects_error_cb_print_missing_gitmodules(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message);
+
+int fsck_refs_error_function(struct fsck_options *options,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message);
+
+struct fsck_object_report {
+ const struct object_id *oid;
+ enum object_type object_type;
+};
+
+struct fsck_ref_report {
+ const char *path;
+ const struct object_id *oid;
+ const char *referent;
+};
struct fsck_options {
fsck_walk_func walk;
fsck_error error_func;
- unsigned strict:1;
+ unsigned strict;
+ unsigned verbose;
enum fsck_msg_type *msg_type;
- struct oidset skiplist;
+ struct oidset skip_oids;
struct oidset gitmodules_found;
struct oidset gitmodules_done;
struct oidset gitattributes_found;
@@ -144,12 +173,12 @@ struct fsck_options {
};
#define FSCK_OPTIONS_DEFAULT { \
- .skiplist = OIDSET_INIT, \
+ .skip_oids = OIDSET_INIT, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
- .error_func = fsck_error_function \
+ .error_func = fsck_objects_error_function \
}
#define FSCK_OPTIONS_STRICT { \
.strict = 1, \
@@ -157,7 +186,7 @@ struct fsck_options {
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
- .error_func = fsck_error_function, \
+ .error_func = fsck_objects_error_function, \
}
#define FSCK_OPTIONS_MISSING_GITMODULES { \
.strict = 1, \
@@ -165,7 +194,10 @@ struct fsck_options {
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
- .error_func = fsck_error_cb_print_missing_gitmodules, \
+ .error_func = fsck_objects_error_cb_print_missing_gitmodules, \
+}
+#define FSCK_REFS_OPTIONS_DEFAULT { \
+ .error_func = fsck_refs_error_function, \
}
/* descend in all linked child objects
@@ -189,7 +221,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
* struct.
*/
int fsck_buffer(const struct object_id *oid, enum object_type,
- void *data, unsigned long size,
+ const void *data, unsigned long size,
struct fsck_options *options);
/*
@@ -209,6 +241,21 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
int fsck_finish(struct fsck_options *options);
/*
+ * Clear the fsck_options struct, freeing any allocated memory.
+ */
+void fsck_options_clear(struct fsck_options *options);
+
+/*
+ * Report an error or warning for refs.
+ */
+__attribute__((format (printf, 4, 5)))
+int fsck_report_ref(struct fsck_options *options,
+ struct fsck_ref_report *report,
+ enum fsck_msg_id msg_id,
+ const char *fmt, ...);
+
+
+/*
* Subsystem for storing human-readable names for each object.
*
* If fsck_enable_object_names() has not been called, all other functions are
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 70d776c54f..5cbbec8d94 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -3,9 +3,7 @@
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
-#include "dir.h"
-#include "run-command.h"
-#include "simple-ipc.h"
+#include "hashmap.h"
#include "thread-utils.h"
#include "fsmonitor-path-utils.h"
@@ -99,7 +97,7 @@ struct fsmonitor_daemon_state {
* to only mean an external GITDIR referenced by a ".git" file.
*
* The platform FS event backends will receive watch-specific
- * relative paths (except for those OS's that always emit absolute
+ * relative paths (except for those OSes that always emit absolute
* paths). We use the following enum and routines to classify each
* path so that we know how to handle it. There is a slight asymmetry
* here because ".git/" is inside the working directory and the
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 88575aa54c..f1b1631111 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -1,5 +1,6 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "fsmonitor-ll.h"
#include "gettext.h"
#include "simple-ipc.h"
#include "fsmonitor-ipc.h"
@@ -20,7 +21,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(struct repository *r)
+const char *fsmonitor_ipc__get_path(struct repository *r UNUSED)
{
return NULL;
}
@@ -30,14 +31,14 @@ enum ipc_active_state fsmonitor_ipc__get_state(void)
return IPC_STATE__OTHER_ERROR;
}
-int fsmonitor_ipc__send_query(const char *since_token,
- struct strbuf *answer)
+int fsmonitor_ipc__send_query(const char *since_token UNUSED,
+ struct strbuf *answer UNUSED)
{
return -1;
}
-int fsmonitor_ipc__send_command(const char *command,
- struct strbuf *answer)
+int fsmonitor_ipc__send_command(const char *command UNUSED,
+ struct strbuf *answer UNUSED)
{
return -1;
}
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index b62acf44ae..a6587a8972 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -7,7 +7,7 @@
#include "fsmonitor-path-utils.h"
/*
- * We keep this structure defintion private and have getters
+ * We keep this structure definition private and have getters
* for all fields so that we can lazy load it as needed.
*/
struct fsmonitor_settings {
@@ -62,7 +62,8 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r,
+ int ipc MAYBE_UNUSED)
{
if (!r->worktree) {
/*
@@ -102,6 +103,7 @@ static struct fsmonitor_settings *alloc_settings(void)
static void lookup_fsmonitor_settings(struct repository *r)
{
const char *const_str;
+ char *to_free = NULL;
int bool_value;
if (r->settings.fsmonitor)
@@ -128,8 +130,9 @@ static void lookup_fsmonitor_settings(struct repository *r)
break;
case -1: /* config value set to an arbitrary string */
- if (repo_config_get_pathname(r, "core.fsmonitor", &const_str))
+ if (repo_config_get_pathname(r, "core.fsmonitor", &to_free))
return; /* should not happen */
+ const_str = to_free;
break;
default: /* should not happen */
@@ -140,6 +143,7 @@ static void lookup_fsmonitor_settings(struct repository *r)
fsm_settings__set_hook(r, const_str);
else
fsm_settings__set_disabled(r);
+ free(to_free);
}
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
diff --git a/fsmonitor.c b/fsmonitor.c
index f670c50937..309a2541cb 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "dir.h"
@@ -5,6 +7,8 @@
#include "ewah/ewok.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "name-hash.h"
+#include "repository.h"
#include "run-command.h"
#include "strbuf.h"
#include "trace2.h"
@@ -166,7 +170,7 @@ static int query_fsmonitor_hook(struct repository *r,
strvec_pushf(&cp.args, "%d", version);
strvec_pushf(&cp.args, "%s", last_update);
cp.use_shell = 1;
- cp.dir = get_git_work_tree();
+ cp.dir = repo_get_work_tree(the_repository);
trace2_region_enter("fsm_hook", "query", NULL);
@@ -183,79 +187,282 @@ static int query_fsmonitor_hook(struct repository *r,
return result;
}
-static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
+/*
+ * Invalidate the FSM bit on this CE. This is like mark_fsmonitor_invalid()
+ * but we've already handled the untracked-cache, so let's not repeat that
+ * work. This also lets us have a different trace message so that we can
+ * see everything that was done as part of the refresh-callback.
+ */
+static void invalidate_ce_fsm(struct cache_entry *ce)
{
- int i, len = strlen(name);
- int pos = index_name_pos(istate, name, len);
+ if (ce->ce_flags & CE_FSMONITOR_VALID) {
+ trace_printf_key(&trace_fsmonitor,
+ "fsmonitor_refresh_callback INV: '%s'",
+ ce->name);
+ ce->ce_flags &= ~CE_FSMONITOR_VALID;
+ }
+}
+
+static size_t handle_path_with_trailing_slash(
+ struct index_state *istate, const char *name, int pos);
+
+/*
+ * Use the name-hash to do a case-insensitive cache-entry lookup with
+ * the pathname and invalidate the cache-entry.
+ *
+ * Returns the number of cache-entries that we invalidated.
+ */
+static size_t handle_using_name_hash_icase(
+ struct index_state *istate, const char *name)
+{
+ struct cache_entry *ce = NULL;
+ ce = index_file_exists(istate, name, strlen(name), 1);
+ if (!ce)
+ return 0;
+
+ /*
+ * A case-insensitive search in the name-hash using the
+ * observed pathname found a cache-entry, so the observed path
+ * is case-incorrect. Invalidate the cache-entry and use the
+ * correct spelling from the cache-entry to invalidate the
+ * untracked-cache. Since we now have sparse-directories in
+ * the index, the observed pathname may represent a regular
+ * file or a sparse-index directory.
+ *
+ * Note that we should not have seen FSEvents for a
+ * sparse-index directory, but we handle it just in case.
+ *
+ * Either way, we know that there are not any cache-entries for
+ * children inside the cone of the directory, so we don't need to
+ * do the usual scan.
+ */
trace_printf_key(&trace_fsmonitor,
- "fsmonitor_refresh_callback '%s' (pos %d)",
- name, pos);
+ "fsmonitor_refresh_callback MAP: '%s' '%s'",
+ name, ce->name);
- if (name[len - 1] == '/') {
- /*
- * The daemon can decorate directory events, such as
- * moves or renames, with a trailing slash if the OS
- * FS Event contains sufficient information, such as
- * MacOS.
- *
- * Use this to invalidate the entire cone under that
- * directory.
- *
- * We do not expect an exact match because the index
- * does not normally contain directory entries, so we
- * start at the insertion point and scan.
- */
- if (pos < 0)
- pos = -pos - 1;
+ /*
+ * NEEDSWORK: We used the name-hash to find the correct
+ * case-spelling of the pathname in the cache-entry[], so
+ * technically this is a tracked file or a sparse-directory.
+ * It should not have any entries in the untracked-cache, so
+ * we should not need to use the case-corrected spelling to
+ * invalidate the untracked-cache. So we may not need to
+ * do this. For now, I'm going to be conservative and always
+ * do it; we can revisit this later.
+ */
+ untracked_cache_invalidate_trimmed_path(istate, ce->name, 0);
- /* Mark all entries for the folder invalid */
- for (i = pos; i < istate->cache_nr; i++) {
- if (!starts_with(istate->cache[i]->name, name))
- break;
- istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
- }
+ invalidate_ce_fsm(ce);
+ return 1;
+}
+
+/*
+ * Use the dir-name-hash to find the correct-case spelling of the
+ * directory. Use the canonical spelling to invalidate all of the
+ * cache-entries within the matching cone.
+ *
+ * Returns the number of cache-entries that we invalidated.
+ */
+static size_t handle_using_dir_name_hash_icase(
+ struct index_state *istate, const char *name)
+{
+ struct strbuf canonical_path = STRBUF_INIT;
+ int pos;
+ size_t len = strlen(name);
+ size_t nr_in_cone;
+
+ if (name[len - 1] == '/')
+ len--;
+ if (!index_dir_find(istate, name, len, &canonical_path))
+ return 0; /* name is untracked */
+
+ if (!memcmp(name, canonical_path.buf, canonical_path.len)) {
+ strbuf_release(&canonical_path);
/*
- * We need to remove the traling "/" from the path
- * for the untracked cache.
+ * NEEDSWORK: Our caller already tried an exact match
+ * and failed to find one. They called us to do an
+ * ICASE match, so we should never get an exact match,
+ * so we could promote this to a BUG() here if we
+ * wanted to. It doesn't hurt anything to just return
+ * 0 and go on because we should never get here. Or we
+ * could just get rid of the memcmp() and this "if"
+ * clause completely.
*/
- name[len - 1] = '\0';
- } else if (pos >= 0) {
+ BUG("handle_using_dir_name_hash_icase(%s) did not exact match",
+ name);
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "fsmonitor_refresh_callback MAP: '%s' '%s'",
+ name, canonical_path.buf);
+
+ /*
+ * The dir-name-hash only tells us the corrected spelling of
+ * the prefix. We have to use this canonical path to do a
+ * lookup in the cache-entry array so that we repeat the
+ * original search using the case-corrected spelling.
+ */
+ strbuf_addch(&canonical_path, '/');
+ pos = index_name_pos(istate, canonical_path.buf,
+ canonical_path.len);
+ nr_in_cone = handle_path_with_trailing_slash(
+ istate, canonical_path.buf, pos);
+ strbuf_release(&canonical_path);
+ return nr_in_cone;
+}
+
+/*
+ * The daemon sent an observed pathname without a trailing slash.
+ * (This is the normal case.) We do not know if it is a tracked or
+ * untracked file, a sparse-directory, or a populated directory (on a
+ * platform such as Windows where FSEvents are not qualified).
+ *
+ * The pathname contains the observed case reported by the FS. We
+ * do not know it is case-correct or -incorrect.
+ *
+ * Assume it is case-correct and try an exact match.
+ *
+ * Return the number of cache-entries that we invalidated.
+ */
+static size_t handle_path_without_trailing_slash(
+ struct index_state *istate, const char *name, int pos)
+{
+ /*
+ * Mark the untracked cache dirty for this path (regardless of
+ * whether or not we find an exact match for it in the index).
+ * Since the path is unqualified (no trailing slash hint in the
+ * FSEvent), it may refer to a file or directory. So we should
+ * not assume one or the other and should always let the untracked
+ * cache decide what needs to invalidated.
+ */
+ untracked_cache_invalidate_trimmed_path(istate, name, 0);
+
+ if (pos >= 0) {
/*
- * We have an exact match for this path and can just
- * invalidate it.
+ * An exact match on a tracked file. We assume that we
+ * do not need to scan forward for a sparse-directory
+ * cache-entry with the same pathname, nor for a cone
+ * at that directory. (That is, assume no D/F conflicts.)
*/
- istate->cache[pos]->ce_flags &= ~CE_FSMONITOR_VALID;
+ invalidate_ce_fsm(istate->cache[pos]);
+ return 1;
} else {
+ size_t nr_in_cone;
+ struct strbuf work_path = STRBUF_INIT;
+
/*
- * The path is not a tracked file -or- it is a
- * directory event on a platform that cannot
- * distinguish between file and directory events in
- * the event handler, such as Windows.
- *
- * Scan as if it is a directory and invalidate the
- * cone under it. (But remember to ignore items
- * between "name" and "name/", such as "name-" and
- * "name.".
+ * The negative "pos" gives us the suggested insertion
+ * point for the pathname (without the trailing slash).
+ * We need to see if there is a directory with that
+ * prefix, but there can be lots of pathnames between
+ * "foo" and "foo/" like "foo-" or "foo-bar", so we
+ * don't want to do our own scan.
*/
+ strbuf_add(&work_path, name, strlen(name));
+ strbuf_addch(&work_path, '/');
+ pos = index_name_pos(istate, work_path.buf, work_path.len);
+ nr_in_cone = handle_path_with_trailing_slash(
+ istate, work_path.buf, pos);
+ strbuf_release(&work_path);
+ return nr_in_cone;
+ }
+}
+
+/*
+ * The daemon can decorate directory events, such as a move or rename,
+ * by adding a trailing slash to the observed name. Use this to
+ * explicitly invalidate the entire cone under that directory.
+ *
+ * The daemon can only reliably do that if the OS FSEvent contains
+ * sufficient information in the event.
+ *
+ * macOS FSEvents have enough information.
+ *
+ * Other platforms may or may not be able to do it (and it might
+ * depend on the type of event (for example, a daemon could lstat() an
+ * observed pathname after a rename, but not after a delete)).
+ *
+ * If we find an exact match in the index for a path with a trailing
+ * slash, it means that we matched a sparse-index directory in a
+ * cone-mode sparse-checkout (since that's the only time we have
+ * directories in the index). We should never see this in practice
+ * (because sparse directories should not be present and therefore
+ * not generating FS events). Either way, we can treat them in the
+ * same way and just invalidate the cache-entry and the untracked
+ * cache (and in this case, the forward cache-entry scan won't find
+ * anything and it doesn't hurt to let it run).
+ *
+ * Return the number of cache-entries that we invalidated. We will
+ * use this later to determine if we need to attempt a second
+ * case-insensitive search on case-insensitive file systems. That is,
+ * if the search using the observed-case in the FSEvent yields any
+ * results, we assume the prefix is case-correct. If there are no
+ * matches, we still don't know if the observed path is simply
+ * untracked or case-incorrect.
+ */
+static size_t handle_path_with_trailing_slash(
+ struct index_state *istate, const char *name, int pos)
+{
+ int i;
+ size_t nr_in_cone = 0;
+
+ /*
+ * Mark the untracked cache dirty for this directory path
+ * (regardless of whether or not we find an exact match for it
+ * in the index or find it to be proper prefix of one or more
+ * files in the index), since the FSEvent is hinting that
+ * there may be changes on or within the directory.
+ */
+ untracked_cache_invalidate_trimmed_path(istate, name, 0);
+
+ if (pos < 0)
pos = -pos - 1;
- for (i = pos; i < istate->cache_nr; i++) {
- if (!starts_with(istate->cache[i]->name, name))
- break;
- if ((unsigned char)istate->cache[i]->name[len] > '/')
- break;
- if (istate->cache[i]->name[len] == '/')
- istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
- }
+ /* Mark all entries for the folder invalid */
+ for (i = pos; i < istate->cache_nr; i++) {
+ if (!starts_with(istate->cache[i]->name, name))
+ break;
+ invalidate_ce_fsm(istate->cache[i]);
+ nr_in_cone++;
}
+ return nr_in_cone;
+}
+
+static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
+{
+ int len = strlen(name);
+ int pos = index_name_pos(istate, name, len);
+ size_t nr_in_cone;
+
+ trace_printf_key(&trace_fsmonitor,
+ "fsmonitor_refresh_callback '%s' (pos %d)",
+ name, pos);
+
+ if (name[len - 1] == '/')
+ nr_in_cone = handle_path_with_trailing_slash(istate, name, pos);
+ else
+ nr_in_cone = handle_path_without_trailing_slash(istate, name, pos);
+
/*
- * Mark the untracked cache dirty even if it wasn't found in the index
- * as it could be a new untracked file.
+ * If we did not find an exact match for this pathname or any
+ * cache-entries with this directory prefix and we're on a
+ * case-insensitive file system, try again using the name-hash
+ * and dir-name-hash.
*/
- untracked_cache_invalidate_path(istate, name, 0);
+ if (!nr_in_cone && ignore_case) {
+ nr_in_cone = handle_using_name_hash_icase(istate, name);
+ if (!nr_in_cone)
+ nr_in_cone = handle_using_dir_name_hash_icase(
+ istate, name);
+ }
+
+ if (nr_in_cone)
+ trace_printf_key(&trace_fsmonitor,
+ "fsmonitor_refresh_callback CNT: %d",
+ (int)nr_in_cone);
}
/*
diff --git a/gettext.c b/gettext.c
index f27e94407b..57facbc21e 100644
--- a/gettext.c
+++ b/gettext.c
@@ -7,9 +7,7 @@
#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
-#include "strbuf.h"
#include "utf8.h"
-#include "config.h"
#ifndef NO_GETTEXT
# include <libintl.h>
diff --git a/git-archimport.perl b/git-archimport.perl
index b7c173c345..f5a317b899 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -54,7 +54,7 @@ and can contain multiple, unrelated branches.
=cut
-use 5.008;
+use 5.008001;
use strict;
use warnings;
use Getopt::Std;
diff --git a/git-compat-util.h b/git-compat-util.h
index 3e7a59b5ff..a06d4f3809 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -195,6 +195,19 @@ struct strbuf;
#define _NETBSD_SOURCE 1
#define _SGI_SOURCE 1
+/*
+ * UNUSED marks a function parameter that is always unused. It also
+ * can be used to annotate a function, a variable, or a type that is
+ * always unused.
+ *
+ * A callback interface may dictate that a function accepts a
+ * parameter at that position, but the implementation of the function
+ * may not need to use the parameter. In such a case, mark the parameter
+ * with UNUSED.
+ *
+ * When a parameter may be used or unused, depending on conditional
+ * compilation, consider using MAYBE_UNUSED instead.
+ */
#if GIT_GNUC_PREREQ(4, 5)
#define UNUSED __attribute__((unused)) \
__attribute__((deprecated ("parameter declared as UNUSED")))
@@ -218,6 +231,18 @@ struct strbuf;
#define GIT_WINDOWS_NATIVE
#endif
+#if defined(NO_UNIX_SOCKETS) || !defined(GIT_WINDOWS_NATIVE)
+static inline int _have_unix_sockets(void)
+{
+#if defined(NO_UNIX_SOCKETS)
+ return 0;
+#else
+ return 1;
+#endif
+}
+#define have_unix_sockets _have_unix_sockets
+#endif
+
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
@@ -225,6 +250,7 @@ struct strbuf;
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h> /* for strcasecmp() */
@@ -390,6 +416,7 @@ char *gitdirname(char *);
#ifndef NO_OPENSSL
#ifdef __APPLE__
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
#define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
#include <AvailabilityMacros.h>
#undef DEPRECATED_ATTRIBUTE
@@ -492,6 +519,14 @@ static inline int git_offset_1st_component(const char *path)
#define offset_1st_component git_offset_1st_component
#endif
+#ifndef fspathcmp
+#define fspathcmp git_fspathcmp
+#endif
+
+#ifndef fspathncmp
+#define fspathncmp git_fspathncmp
+#endif
+
#ifndef is_valid_path
#define is_valid_path(path) 1
#endif
@@ -627,6 +662,17 @@ static inline int git_has_dir_sep(const char *path)
#define RESULT_MUST_BE_USED
#endif
+/*
+ * MAYBE_UNUSED marks a function parameter that may be unused, but
+ * whose use is not an error. It also can be used to annotate a
+ * function, a variable, or a type that may be unused.
+ *
+ * Depending on a configuration, all uses of such a thing may become
+ * #ifdef'ed away. Marking it with UNUSED would give a warning in a
+ * compilation where it is indeed used, and not marking it at all
+ * would give a warning in a compilation where it is unused. In such
+ * a case, MAYBE_UNUSED is the appropriate annotation to use.
+ */
#define MAYBE_UNUSED __attribute__((__unused__))
#include "compat/bswap.h"
@@ -684,11 +730,11 @@ report_fn get_warn_routine(void);
void set_die_is_recursing_routine(int (*routine)(void));
/*
- * If the string "str" begins with the string found in "prefix", return 1.
+ * If the string "str" begins with the string found in "prefix", return true.
* The "out" parameter is set to "str + strlen(prefix)" (i.e., to the point in
* the string right after the prefix).
*
- * Otherwise, return 0 and leave "out" untouched.
+ * Otherwise, return false and leave "out" untouched.
*
* Examples:
*
@@ -699,57 +745,58 @@ void set_die_is_recursing_routine(int (*routine)(void));
* [skip prefix if present, otherwise use whole string]
* skip_prefix(name, "refs/heads/", &name);
*/
-static inline int skip_prefix(const char *str, const char *prefix,
- const char **out)
+static inline bool skip_prefix(const char *str, const char *prefix,
+ const char **out)
{
do {
if (!*prefix) {
*out = str;
- return 1;
+ return true;
}
} while (*str++ == *prefix++);
- return 0;
+ return false;
}
/*
* 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".
*/
-static inline int skip_prefix_mem(const char *buf, size_t len,
- const char *prefix,
- const char **out, size_t *outlen)
+static inline bool skip_prefix_mem(const char *buf, size_t len,
+ const char *prefix,
+ const char **out, size_t *outlen)
{
size_t prefix_len = strlen(prefix);
if (prefix_len <= len && !memcmp(buf, prefix, prefix_len)) {
*out = buf + prefix_len;
*outlen = len - prefix_len;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
- * If buf ends with suffix, return 1 and subtract the length of the suffix
- * from *len. Otherwise, return 0 and leave *len untouched.
+ * If buf ends with suffix, return true and subtract the length of the suffix
+ * from *len. Otherwise, return false and leave *len untouched.
*/
-static inline int strip_suffix_mem(const char *buf, size_t *len,
- const char *suffix)
+static inline bool strip_suffix_mem(const char *buf, size_t *len,
+ const char *suffix)
{
size_t suflen = strlen(suffix);
if (*len < suflen || memcmp(buf + (*len - suflen), suffix, suflen))
- return 0;
+ return false;
*len -= suflen;
- return 1;
+ return true;
}
/*
- * If str ends with suffix, return 1 and set *len to the size of the string
- * without the suffix. Otherwise, return 0 and set *len to the size of the
+ * If str ends with suffix, return true and set *len to the size of the string
+ * without the suffix. Otherwise, return false and set *len to the size of the
* string.
*
* Note that we do _not_ NUL-terminate str to the new length.
*/
-static inline int strip_suffix(const char *str, const char *suffix, size_t *len)
+static inline bool strip_suffix(const char *str, const char *suffix,
+ size_t *len)
{
*len = strlen(str);
return strip_suffix_mem(str, len, suffix);
@@ -1013,6 +1060,15 @@ static inline unsigned long cast_size_t_to_ulong(size_t a)
return (unsigned long)a;
}
+static inline uint32_t cast_size_t_to_uint32_t(size_t a)
+{
+ if (a != (uint32_t)a)
+ die("object too large to read on this platform: %"
+ PRIuMAX" is cut off to %u",
+ (uintmax_t)a, (uint32_t)a);
+ return (uint32_t)a;
+}
+
static inline int cast_size_t_to_int(size_t a)
{
if (a > INT_MAX)
@@ -1471,26 +1527,6 @@ int cmd_main(int, const char **);
int common_exit(const char *file, int line, int code);
#define exit(code) exit(common_exit(__FILE__, __LINE__, (code)))
-/*
- * You can mark a stack variable with UNLEAK(var) to avoid it being
- * reported as a leak by tools like LSAN or valgrind. The argument
- * should generally be the variable itself (not its address and not what
- * it points to). It's safe to use this on pointers which may already
- * have been freed, or on pointers which may still be in use.
- *
- * Use this _only_ for a variable that leaks by going out of scope at
- * program exit (so only from cmd_* functions or their direct helpers).
- * Normal functions, especially those which may be called multiple
- * times, should actually free their memory. This is only meant as
- * an annotation, and does nothing in non-leak-checking builds.
- */
-#ifdef SUPPRESS_ANNOTATED_LEAKS
-void unleak_memory(const void *ptr, size_t len);
-#define UNLEAK(var) unleak_memory(&(var), sizeof(var))
-#else
-#define UNLEAK(var) do {} while (0)
-#endif
-
#define z_const
#include <zlib.h>
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index 289d4bc684..1e03ba94d1 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -1,6 +1,6 @@
#!/usr/bin/perl
-use 5.008;
+use 5.008001;
use strict;
use warnings;
use Getopt::Std;
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 7bf3c12d67..211ec8459a 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -13,7 +13,7 @@
# The head revision is on branch "origin" by default.
# You can change that with the '-o' option.
-use 5.008;
+use 5.008001;
use strict;
use warnings;
use Getopt::Long;
@@ -329,7 +329,7 @@ sub conn {
# Use a HTTP Proxy. Only works for HTTP proxies that
# don't require user authentication
#
- # See: http://www.ietf.org/rfc/rfc2817.txt
+ # See: https://www.ietf.org/rfc/rfc2817.txt
$s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
die "Socket to $proxyhost: $!\n" unless defined $s;
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index 7b757360e2..124f598bdc 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -15,7 +15,7 @@
####
####
-use 5.008;
+use 5.008001;
use strict;
use warnings;
use bytes;
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
index e4e820e680..dd0c9a5b7f 100755
--- a/git-difftool--helper.sh
+++ b/git-difftool--helper.sh
@@ -91,6 +91,19 @@ then
# ignore the error from the above --- run_merge_tool
# will diagnose unusable tool by itself
run_merge_tool "$merge_tool" false
+
+ status=$?
+ if test $status -ge 126
+ then
+ # Command not found (127), not executable (126) or
+ # exited via a signal (>= 128).
+ exit $status
+ fi
+
+ if test "$GIT_DIFFTOOL_TRUST_EXIT_CODE" = true
+ then
+ exit $status
+ fi
else
# Launch the merge tool on each path provided by 'git diff'
while test $# -gt 6
diff --git a/git-gui/.gitattributes b/git-gui/.gitattributes
index 59cd41dbff..118d56cfbd 100644
--- a/git-gui/.gitattributes
+++ b/git-gui/.gitattributes
@@ -3,3 +3,4 @@
git-gui.sh encoding=UTF-8
/po/*.po encoding=UTF-8
/GIT-VERSION-GEN eol=lf
+Makefile whitespace=!indent,trail,space
diff --git a/git-gui/Makefile b/git-gui/Makefile
index a0d5a4b28e..667c39ed56 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -107,12 +107,12 @@ endif
ifeq ($(uname_S),Darwin)
TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app
- ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n)
+ ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n)
TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app
- ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n)
+ ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n)
TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app
- endif
- endif
+ endif
+ endif
TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app)
endif
@@ -138,29 +138,14 @@ GITGUI_SCRIPT := $$0
GITGUI_RELATIVE :=
GITGUI_MACOSXAPP :=
-ifeq ($(uname_O),Cygwin)
- GITGUI_SCRIPT := `cygpath --windows --absolute "$(GITGUI_SCRIPT)"`
-
- # Is this a Cygwin Tcl/Tk binary? If so it knows how to do
- # POSIX path translation just like cygpath does and we must
- # keep libdir in POSIX format so Cygwin packages of git-gui
- # work no matter where the user installs them.
- #
- ifeq ($(shell echo 'puts [file normalize /]' | '$(TCL_PATH_SQ)'),$(shell cygpath --mixed --absolute /))
- gg_libdir_sed_in := $(gg_libdir)
- else
- gg_libdir_sed_in := $(shell cygpath --windows --absolute "$(gg_libdir)")
- endif
-else
- ifeq ($(exedir),$(gg_libdir))
- GITGUI_RELATIVE := 1
- endif
- gg_libdir_sed_in := $(gg_libdir)
+ifeq ($(exedir),$(gg_libdir))
+ GITGUI_RELATIVE := 1
endif
+gg_libdir_sed_in := $(gg_libdir)
ifeq ($(uname_S),Darwin)
- ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y)
+ ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y)
GITGUI_MACOSXAPP := YesPlease
- endif
+ endif
endif
ifneq (,$(findstring MINGW,$(uname_S)))
ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
@@ -235,9 +220,9 @@ ifdef NO_MSGFMT
MSGFMT ?= $(TCL_PATH) po/po2msg.sh
else
MSGFMT ?= msgfmt
- ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0)
+ ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0)
MSGFMT := $(TCL_PATH) po/po2msg.sh
- endif
+ endif
endif
msgsdir = $(gg_libdir)/msgs
diff --git a/git-gui/README.md b/git-gui/README.md
index 5ce2122fbc..948e9250d5 100644
--- a/git-gui/README.md
+++ b/git-gui/README.md
@@ -42,8 +42,8 @@ You probably need to have root/admin permissions to install.
# Contributing
-The project is currently maintained by Pratyush Yadav over at
-https://github.com/prati0100/git-gui. Even though the project is hosted at
+The project is currently maintained by Johannes Sixt at
+https://github.com/j6t/git-gui. Even though the project is hosted at
GitHub, the development does not happen over GitHub Issues and Pull Requests.
Instead, an email based workflow is used. The Git mailing list
[git@vger.kernel.org](mailto:git@vger.kernel.org) is where the patches are
@@ -88,7 +88,7 @@ that you first use `git-format-patch` to generate the emails, audit them, and
then send them via `git-send-email`.
A pretty good guide to configuring and using `git-send-email` can be found
-[here](https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/)
+[here](https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/).
### Using your email client
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 201524c34e..8fe7538e72 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -24,7 +24,7 @@ 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/>.}]
+along with this program; if not, see <https://www.gnu.org/licenses/>.}]
######################################################################
##
@@ -46,6 +46,132 @@ catch {rename send {}} ; # What an evil concept...
######################################################################
##
+## Enabling platform-specific code paths
+
+proc is_MacOSX {} {
+ if {[tk windowingsystem] eq {aqua}} {
+ return 1
+ }
+ return 0
+}
+
+proc is_Windows {} {
+ if {$::tcl_platform(platform) eq {windows}} {
+ return 1
+ }
+ return 0
+}
+
+set _iscygwin {}
+proc is_Cygwin {} {
+ global _iscygwin
+ if {$_iscygwin eq {}} {
+ if {[string match "CYGWIN_*" $::tcl_platform(os)]} {
+ set _iscygwin 1
+ } else {
+ set _iscygwin 0
+ }
+ }
+ return $_iscygwin
+}
+
+######################################################################
+##
+## PATH lookup
+
+set _search_path {}
+proc _which {what args} {
+ global env _search_exe _search_path
+
+ if {$_search_path eq {}} {
+ if {[is_Windows]} {
+ set gitguidir [file dirname [info script]]
+ regsub -all ";" $gitguidir "\\;" gitguidir
+ set env(PATH) "$gitguidir;$env(PATH)"
+ set _search_path [split $env(PATH) {;}]
+ # Skip empty `PATH` elements
+ set _search_path [lsearch -all -inline -not -exact \
+ $_search_path ""]
+ set _search_exe .exe
+ } else {
+ set _search_path [split $env(PATH) :]
+ set _search_exe {}
+ }
+ }
+
+ if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
+ set suffix {}
+ } else {
+ set suffix $_search_exe
+ }
+
+ foreach p $_search_path {
+ set p [file join $p $what$suffix]
+ if {[file exists $p]} {
+ return [file normalize $p]
+ }
+ }
+ return {}
+}
+
+proc sanitize_command_line {command_line from_index} {
+ set i $from_index
+ while {$i < [llength $command_line]} {
+ set cmd [lindex $command_line $i]
+ if {[llength [file split $cmd]] < 2} {
+ set fullpath [_which $cmd]
+ if {$fullpath eq ""} {
+ throw {NOT-FOUND} "$cmd not found in PATH"
+ }
+ lset command_line $i $fullpath
+ }
+
+ # handle piped commands, e.g. `exec A | B`
+ for {incr i} {$i < [llength $command_line]} {incr i} {
+ if {[lindex $command_line $i] eq "|"} {
+ incr i
+ break
+ }
+ }
+ }
+ return $command_line
+}
+
+# Override `exec` to avoid unsafe PATH lookup
+
+rename exec real_exec
+
+proc exec {args} {
+ # skip options
+ for {set i 0} {$i < [llength $args]} {incr i} {
+ set arg [lindex $args $i]
+ if {$arg eq "--"} {
+ incr i
+ break
+ }
+ if {[string range $arg 0 0] ne "-"} {
+ break
+ }
+ }
+ set args [sanitize_command_line $args $i]
+ uplevel 1 real_exec $args
+}
+
+# Override `open` to avoid unsafe PATH lookup
+
+rename open real_open
+
+proc open {args} {
+ set arg0 [lindex $args 0]
+ if {[string range $arg0 0 0] eq "|"} {
+ set command_line [string trim [string range $arg0 1 end]]
+ lset args 0 "| [sanitize_command_line $command_line 0]"
+ }
+ uplevel 1 real_open $args
+}
+
+######################################################################
+##
## locate our library
if { [info exists ::env(GIT_GUI_LIB_DIR) ] } {
@@ -163,8 +289,6 @@ set _isbare {}
set _gitexec {}
set _githtmldir {}
set _reponame {}
-set _iscygwin {}
-set _search_path {}
set _shellpath {@@SHELL_PATH@@}
set _trace [lsearch -exact $argv --trace]
@@ -211,14 +335,7 @@ proc gitexec {args} {
if {[catch {set _gitexec [git --exec-path]} err]} {
error "Git not installed?\n\n$err"
}
- if {[is_Cygwin]} {
- set _gitexec [exec cygpath \
- --windows \
- --absolute \
- $_gitexec]
- } else {
- set _gitexec [file normalize $_gitexec]
- }
+ set _gitexec [file normalize $_gitexec]
}
if {$args eq {}} {
return $_gitexec
@@ -233,14 +350,7 @@ proc githtmldir {args} {
# Git not installed or option not yet supported
return {}
}
- if {[is_Cygwin]} {
- set _githtmldir [exec cygpath \
- --windows \
- --absolute \
- $_githtmldir]
- } else {
- set _githtmldir [file normalize $_githtmldir]
- }
+ set _githtmldir [file normalize $_githtmldir]
}
if {$args eq {}} {
return $_githtmldir
@@ -252,40 +362,6 @@ proc reponame {} {
return $::_reponame
}
-proc is_MacOSX {} {
- if {[tk windowingsystem] eq {aqua}} {
- return 1
- }
- return 0
-}
-
-proc is_Windows {} {
- if {$::tcl_platform(platform) eq {windows}} {
- return 1
- }
- return 0
-}
-
-proc is_Cygwin {} {
- global _iscygwin
- if {$_iscygwin eq {}} {
- if {$::tcl_platform(platform) eq {windows}} {
- if {[catch {set p [exec cygpath --windir]} err]} {
- set _iscygwin 0
- } else {
- set _iscygwin 1
- # Handle MSys2 which is only cygwin when MSYSTEM is MSYS.
- if {[info exists ::env(MSYSTEM)] && $::env(MSYSTEM) ne "MSYS"} {
- set _iscygwin 0
- }
- }
- } else {
- set _iscygwin 0
- }
- }
- return $_iscygwin
-}
-
proc is_enabled {option} {
global enabled_options
if {[catch {set on $enabled_options($option)}]} {return 0}
@@ -448,44 +524,6 @@ proc _git_cmd {name} {
return $v
}
-proc _which {what args} {
- global env _search_exe _search_path
-
- if {$_search_path eq {}} {
- if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
- set _search_path [split [exec cygpath \
- --windows \
- --path \
- --absolute \
- $env(PATH)] {;}]
- set _search_exe .exe
- } elseif {[is_Windows]} {
- set gitguidir [file dirname [info script]]
- regsub -all ";" $gitguidir "\\;" gitguidir
- set env(PATH) "$gitguidir;$env(PATH)"
- set _search_path [split $env(PATH) {;}]
- set _search_exe .exe
- } else {
- set _search_path [split $env(PATH) :]
- set _search_exe {}
- }
- }
-
- if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
- set suffix {}
- } else {
- set suffix $_search_exe
- }
-
- foreach p $_search_path {
- set p [file join $p $what$suffix]
- if {[file exists $p]} {
- return [file normalize $p]
- }
- }
- return {}
-}
-
# Test a file for a hashbang to identify executable scripts on Windows.
proc is_shellscript {filename} {
if {![file exists $filename]} {return 0}
@@ -623,31 +661,8 @@ proc git_write {args} {
}
proc githook_read {hook_name args} {
- set pchook [gitdir hooks $hook_name]
- lappend args 2>@1
-
- # On Windows [file executable] might lie so we need to ask
- # the shell if the hook is executable. Yes that's annoying.
- #
- if {[is_Windows]} {
- upvar #0 _sh interp
- if {![info exists interp]} {
- set interp [_which sh]
- }
- if {$interp eq {}} {
- error "hook execution requires sh (not in PATH)"
- }
-
- set scr {if test -x "$1";then exec "$@";fi}
- set sh_c [list $interp -c $scr $interp $pchook]
- return [_open_stdout_stderr [concat $sh_c $args]]
- }
-
- if {[file executable $pchook]} {
- return [_open_stdout_stderr [concat [list $pchook] $args]]
- }
-
- return {}
+ set cmd [concat git hook run --ignore-missing $hook_name -- $args 2>@1]
+ return [_open_stdout_stderr $cmd]
}
proc kill_file_process {fd} {
@@ -1259,9 +1274,6 @@ if {$_gitdir eq "."} {
set _gitdir [pwd]
}
-if {![file isdirectory $_gitdir] && [is_Cygwin]} {
- catch {set _gitdir [exec cygpath --windows $_gitdir]}
-}
if {![file isdirectory $_gitdir]} {
catch {wm withdraw .}
error_popup [strcat [mc "Git directory not found:"] "\n\n$_gitdir"]
@@ -1273,11 +1285,7 @@ apply_config
# v1.7.0 introduced --show-toplevel to return the canonical work-tree
if {[package vcompare $_git_version 1.7.0] >= 0} {
- if { [is_Cygwin] } {
- catch {set _gitworktree [exec cygpath --windows [git rev-parse --show-toplevel]]}
- } else {
- set _gitworktree [git rev-parse --show-toplevel]
- }
+ set _gitworktree [git rev-parse --show-toplevel]
} else {
# try to set work tree from environment, core.worktree or use
# cdup to obtain a relative path to the top of the worktree. If
@@ -1502,24 +1510,8 @@ proc rescan {after {honor_trustmtime 1}} {
}
}
-if {[is_Cygwin]} {
- set is_git_info_exclude {}
- proc have_info_exclude {} {
- global is_git_info_exclude
-
- if {$is_git_info_exclude eq {}} {
- if {[catch {exec test -f [gitdir info exclude]}]} {
- set is_git_info_exclude 0
- } else {
- set is_git_info_exclude 1
- }
- }
- return $is_git_info_exclude
- }
-} else {
- proc have_info_exclude {} {
- return [file readable [gitdir info exclude]]
- }
+proc have_info_exclude {} {
+ return [file readable [gitdir info exclude]]
}
proc rescan_stage2 {fd after} {
@@ -2259,7 +2251,9 @@ proc do_git_gui {} {
# Get the system-specific explorer app/command.
proc get_explorer {} {
- if {[is_Cygwin] || [is_Windows]} {
+ if {[is_Cygwin]} {
+ set explorer "/bin/cygstart.exe --explore"
+ } elseif {[is_Windows]} {
set explorer "explorer.exe"
} elseif {[is_MacOSX]} {
set explorer "open"
@@ -2307,7 +2301,7 @@ proc do_quit {{rc {1}}} {
#
set save [gitdir GITGUI_MSG]
if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} {
- file rename -force [gitdir GITGUI_BCK] $save
+ catch { file rename -force [gitdir GITGUI_BCK] $save }
set GITGUI_BCK_exists 0
} elseif {[$ui_comm edit modified]} {
set msg [string trim [$ui_comm get 0.0 end]]
@@ -2373,7 +2367,7 @@ proc do_quit {{rc {1}}} {
set ret_code $rc
# Briefly enable send again, working around Tk bug
- # http://sourceforge.net/tracker/?func=detail&atid=112997&aid=1821174&group_id=12997
+ # https://sourceforge.net/p/tktoolkit/bugs/2343/
tk appname [appname]
destroy .
@@ -3053,16 +3047,12 @@ if {[is_MacOSX]} {
set doc_path [githtmldir]
if {$doc_path ne {}} {
set doc_path [file join $doc_path index.html]
-
- if {[is_Cygwin]} {
- set doc_path [exec cygpath --mixed $doc_path]
- }
}
if {[file isfile $doc_path]} {
set doc_url "file:$doc_path"
} else {
- set doc_url {http://www.kernel.org/pub/software/scm/git/docs/}
+ set doc_url {https://www.kernel.org/pub/software/scm/git/docs/}
}
proc start_browser {url} {
@@ -4028,60 +4018,6 @@ set file_lists($ui_workdir) [list]
wm title . "[appname] ([reponame]) [file normalize $_gitworktree]"
focus -force $ui_comm
-# -- Warn the user about environmental problems. Cygwin's Tcl
-# does *not* pass its env array onto any processes it spawns.
-# This means that git processes get none of our environment.
-#
-if {[is_Cygwin]} {
- set ignored_env 0
- set suggest_user {}
- set msg [mc "Possible environment issues exist.
-
-The following environment variables are probably
-going to be ignored by any Git subprocess run
-by %s:
-
-" [appname]]
- foreach name [array names env] {
- switch -regexp -- $name {
- {^GIT_INDEX_FILE$} -
- {^GIT_OBJECT_DIRECTORY$} -
- {^GIT_ALTERNATE_OBJECT_DIRECTORIES$} -
- {^GIT_DIFF_OPTS$} -
- {^GIT_EXTERNAL_DIFF$} -
- {^GIT_PAGER$} -
- {^GIT_TRACE$} -
- {^GIT_CONFIG$} -
- {^GIT_(AUTHOR|COMMITTER)_DATE$} {
- append msg " - $name\n"
- incr ignored_env
- }
- {^GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL)$} {
- append msg " - $name\n"
- incr ignored_env
- set suggest_user $name
- }
- }
- }
- if {$ignored_env > 0} {
- append msg [mc "
-This is due to a known issue with the
-Tcl binary distributed by Cygwin."]
-
- if {$suggest_user ne {}} {
- append msg [mc "
-
-A good replacement for %s
-is placing values for the user.name and
-user.email settings into your personal
-~/.gitconfig file.
-" $suggest_user]
- }
- warn_popup $msg
- }
- unset ignored_env msg suggest_user name
-}
-
# -- Only initialize complex UI if we are going to stay running.
#
if {[is_enabled transport]} {
diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl
index af1fee7c75..d23abedcb3 100644
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -174,9 +174,6 @@ constructor pick {} {
-foreground blue \
-underline 1
set home $::env(HOME)
- if {[is_Cygwin]} {
- set home [exec cygpath --windows --absolute $home]
- }
set home "[file normalize $home]/"
set hlen [string length $home]
foreach p $sorted_recent {
@@ -374,18 +371,6 @@ proc _objdir {path} {
return $objdir
}
- if {[is_Cygwin]} {
- set objdir [file join $path .git objects.lnk]
- if {[file isfile $objdir]} {
- return [win32_read_lnk $objdir]
- }
-
- set objdir [file join $path objects.lnk]
- if {[file isfile $objdir]} {
- return [win32_read_lnk $objdir]
- }
- }
-
return {}
}
@@ -623,12 +608,6 @@ method _do_clone2 {} {
}
set giturl $origin_url
- if {[is_Cygwin] && [file isdirectory $giturl]} {
- set giturl [exec cygpath --unix --absolute $giturl]
- if {$clone_type eq {shared}} {
- set objdir [exec cygpath --unix --absolute $objdir]
- }
- }
if {[file exists $local_path]} {
error_popup [mc "Location %s already exists." $local_path]
@@ -668,11 +647,7 @@ method _do_clone2 {} {
fconfigure $f_cp -translation binary -encoding binary
cd $objdir
while {[gets $f_in line] >= 0} {
- if {[is_Cygwin]} {
- puts $f_cp [exec cygpath --unix --absolute $line]
- } else {
- puts $f_cp [file normalize $line]
- }
+ puts $f_cp [file normalize $line]
}
close $f_in
close $f_cp
diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl
index 11379f8ad3..208dc2817c 100644
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -207,8 +207,17 @@ You must stage at least 1 file before you can commit.
# -- A message is required.
#
- set msg [string trim [$ui_comm get 1.0 end]]
+ set msg [$ui_comm get 1.0 end]
+ # Strip trailing whitespace
regsub -all -line {[ \t\r]+$} $msg {} msg
+ # Strip comment lines
+ regsub -all {(^|\n)#[^\n]*} $msg {\1} msg
+ # Strip leading empty lines
+ regsub {^\n*} $msg {} msg
+ # Compress consecutive empty lines
+ regsub -all {\n{3,}} $msg "\n\n" msg
+ # Strip trailing empty line
+ regsub {\n\n$} $msg "\n" msg
if {$msg eq {}} {
error_popup [mc "Please supply a commit message.
diff --git a/git-gui/lib/encoding.tcl b/git-gui/lib/encoding.tcl
index 32668fc9c6..d2e0fa60c3 100644
--- a/git-gui/lib/encoding.tcl
+++ b/git-gui/lib/encoding.tcl
@@ -3,7 +3,7 @@
# (Copied from gitk, commit fd8ccbec4f0161)
# This list of encoding names and aliases is distilled from
-# http://www.iana.org/assignments/character-sets.
+# https://www.iana.org/assignments/character-sets.
# Not all of them are supported by Tcl.
set encoding_aliases {
{ ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl
index e688b016ef..8b8c16b1d6 100644
--- a/git-gui/lib/mergetool.tcl
+++ b/git-gui/lib/mergetool.tcl
@@ -272,8 +272,25 @@ proc merge_resolve_tool2 {} {
}
}
default {
- error_popup [mc "Unsupported merge tool '%s'" $tool]
- return
+ set tool_cmd [get_config mergetool.$tool.cmd]
+ if {$tool_cmd ne {}} {
+ if {([string first {[} $tool_cmd] != -1) || ([string first {]} $tool_cmd] != -1)} {
+ error_popup [mc "Unable to process square brackets in \"mergetool.%s.cmd\" configuration option.
+
+Please remove the square brackets." $tool]
+ return
+ } else {
+ set cmdline {}
+ foreach command_part $tool_cmd {
+ lappend cmdline [subst -nobackslashes -nocommands $command_part]
+ }
+ }
+ } else {
+ error_popup [mc "Unsupported merge tool '%s'.
+
+To use this tool, configure \"mergetool.%s.cmd\" as shown in the git-config manual page." $tool $tool]
+ return
+ }
}
}
diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl
index 97d1d7aa02..674a41f5e0 100644
--- a/git-gui/lib/shortcut.tcl
+++ b/git-gui/lib/shortcut.tcl
@@ -27,13 +27,10 @@ proc do_windows_shortcut {} {
}
proc do_cygwin_shortcut {} {
- global argv0 _gitworktree
+ global argv0 _gitworktree oguilib
if {[catch {
set desktop [exec cygpath \
- --windows \
- --absolute \
- --long-name \
--desktop]
}]} {
set desktop .
@@ -48,19 +45,19 @@ proc do_cygwin_shortcut {} {
set fn ${fn}.lnk
}
if {[catch {
- set sh [exec cygpath \
- --windows \
- --absolute \
- /bin/sh.exe]
- set me [exec cygpath \
- --unix \
- --absolute \
- $argv0]
- win32_create_lnk $fn [list \
- $sh -c \
- "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \
- ] \
- [file normalize $_gitworktree]
+ set repodir [file normalize $_gitworktree]
+ set shargs {-c \
+ "CHERE_INVOKING=1 \
+ source /etc/profile; \
+ git gui"}
+ exec /bin/mkshortcut.exe \
+ --arguments $shargs \
+ --desc "git-gui on $repodir" \
+ --icon $oguilib/git-gui.ico \
+ --name $fn \
+ --show min \
+ --workingdir $repodir \
+ /bin/sh.exe
} err]} {
error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"]
}
diff --git a/git-gui/po/README b/git-gui/po/README
index 2514bc22ab..116233100d 100644
--- a/git-gui/po/README
+++ b/git-gui/po/README
@@ -39,7 +39,7 @@ in your language?
If you do not know what your language should be named, you need to find
it. This currently follows ISO 639-1 two letter codes:
- http://www.loc.gov/standards/iso639-2/php/code_list.php
+ https://www.loc.gov/standards/iso639-2/php/code_list.php
For example, if you are preparing a translation for Afrikaans, the
language code is "af". If there already is a translation for your
diff --git a/git-gui/po/fr.po b/git-gui/po/fr.po
index 0aff18691d..878df65399 100644
--- a/git-gui/po/fr.po
+++ b/git-gui/po/fr.po
@@ -1646,7 +1646,7 @@ msgstr "Dépôt Git (sous projet)"
#: lib/diff.tcl:222
msgid "* Binary file (not showing content)."
-msgstr "* Fichier binaire (pas d'apperçu du contenu)."
+msgstr "* Fichier binaire (pas d'aperçu du contenu)."
#: lib/diff.tcl:227
#, tcl-format
diff --git a/git-gui/po/sv.po b/git-gui/po/sv.po
index 1b4ad8368e..de65c18584 100644
--- a/git-gui/po/sv.po
+++ b/git-gui/po/sv.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the git-gui package.
#
# Mikael Magnusson <mikachu@gmail.com>, 2008.
-# Peter Krefting <peter@softwolves.pp.se>, 2007-2008, 2015.
+# Peter Krefting <peter@softwolves.pp.se>, 2007-2023.
#
msgid ""
msgstr ""
-"Project-Id-Version: sv\n"
+"Project-Id-Version: git-gui 0.21.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-03-27 10:15+0100\n"
-"PO-Revision-Date: 2015-03-27 10:24+0100\n"
+"POT-Creation-Date: 2023-10-26 21:17+0100\n"
+"PO-Revision-Date: 2023-10-26 21:23+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -18,35 +18,35 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Gtranslator 2.91.6\n"
+"X-Generator: Gtranslator 3.38.0\n"
-#: git-gui.sh:861
+#: git-gui.sh:884
#, tcl-format
msgid "Invalid font specified in %s:"
msgstr "Ogiltigt teckensnitt angivet i %s:"
-#: git-gui.sh:915
+#: git-gui.sh:939
msgid "Main Font"
msgstr "Huvudteckensnitt"
-#: git-gui.sh:916
+#: git-gui.sh:940
msgid "Diff/Console Font"
msgstr "Diff/konsolteckensnitt"
-#: git-gui.sh:931 git-gui.sh:945 git-gui.sh:958 git-gui.sh:1048
-#: git-gui.sh:1067 git-gui.sh:3125
+#: git-gui.sh:955 git-gui.sh:969 git-gui.sh:982 git-gui.sh:1072 git-gui.sh:1091
+#: git-gui.sh:3233
msgid "git-gui: fatal error"
msgstr "git-gui: ödesdigert fel"
-#: git-gui.sh:932
+#: git-gui.sh:956
msgid "Cannot find git in PATH."
msgstr "Hittar inte git i PATH."
-#: git-gui.sh:959
+#: git-gui.sh:983
msgid "Cannot parse Git version string:"
msgstr "Kan inte tolka versionssträng från Git:"
-#: git-gui.sh:984
+#: git-gui.sh:1008
#, tcl-format
msgid ""
"Git version cannot be determined.\n"
@@ -59,53 +59,53 @@ msgid ""
msgstr ""
"Kan inte avgöra Gits version.\n"
"\n"
-"%s säger att dess version är \"%s\".\n"
+"%s säger att dess version är â€%sâ€.\n"
"\n"
"%s kräver minst Git 1.5.0 eller senare.\n"
"\n"
-"Anta att \"%s\" är version 1.5.0?\n"
+"Anta att â€%s†är version 1.5.0?\n"
-#: git-gui.sh:1281
+#: git-gui.sh:1302
msgid "Git directory not found:"
msgstr "Git-katalogen hittades inte:"
-#: git-gui.sh:1315
+#: git-gui.sh:1332
msgid "Cannot move to top of working directory:"
msgstr "Kan inte gå till början på arbetskatalogen:"
-#: git-gui.sh:1323
+#: git-gui.sh:1340
msgid "Cannot use bare repository:"
msgstr "Kan inte använda naket arkiv:"
-#: git-gui.sh:1331
+#: git-gui.sh:1348
msgid "No working directory"
msgstr "Ingen arbetskatalog"
-#: git-gui.sh:1503 lib/checkout_op.tcl:306
+#: git-gui.sh:1523 lib/checkout_op.tcl:306
msgid "Refreshing file status..."
msgstr "Uppdaterar filstatus..."
-#: git-gui.sh:1563
+#: git-gui.sh:1567
msgid "Scanning for modified files ..."
msgstr "Söker efter ändrade filer..."
-#: git-gui.sh:1639
+#: git-gui.sh:1651
msgid "Calling prepare-commit-msg hook..."
msgstr ""
"Anropar kroken för förberedelse av incheckningsmeddelande (prepare-commit-"
"msg)..."
-#: git-gui.sh:1656
+#: git-gui.sh:1668
msgid "Commit declined by prepare-commit-msg hook."
msgstr ""
"Incheckningen avvisades av kroken för förberedelse av incheckningsmeddelande "
"(prepare-commit-msg)."
-#: git-gui.sh:1814 lib/browser.tcl:252
+#: git-gui.sh:1826 lib/browser.tcl:252
msgid "Ready."
msgstr "Klar."
-#: git-gui.sh:1978
+#: git-gui.sh:1990
#, tcl-format
msgid ""
"Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files."
@@ -113,524 +113,811 @@ msgstr ""
"Visningsgräns (gui.maxfilesdisplayed = %s) nådd, visare inte samtliga %s "
"filer."
-#: git-gui.sh:2101
+#: git-gui.sh:2113
msgid "Unmodified"
msgstr "Oförändrade"
-#: git-gui.sh:2103
+#: git-gui.sh:2115
msgid "Modified, not staged"
msgstr "Förändrade, ej köade"
-#: git-gui.sh:2104 git-gui.sh:2116
+#: git-gui.sh:2116 git-gui.sh:2128
msgid "Staged for commit"
msgstr "Köade för incheckning"
-#: git-gui.sh:2105 git-gui.sh:2117
+#: git-gui.sh:2117 git-gui.sh:2129
msgid "Portions staged for commit"
msgstr "Delar köade för incheckning"
-#: git-gui.sh:2106 git-gui.sh:2118
+#: git-gui.sh:2118 git-gui.sh:2130
msgid "Staged for commit, missing"
msgstr "Köade för incheckning, saknade"
-#: git-gui.sh:2108
+#: git-gui.sh:2120
msgid "File type changed, not staged"
msgstr "Filtyp ändrad, ej köade"
-#: git-gui.sh:2109 git-gui.sh:2110
+#: git-gui.sh:2121 git-gui.sh:2122
msgid "File type changed, old type staged for commit"
msgstr "Filtyp ändrad, gammal typ köade för incheckning"
-#: git-gui.sh:2111
+#: git-gui.sh:2123
msgid "File type changed, staged"
msgstr "Filtyp ändrad, köade"
-#: git-gui.sh:2112
+#: git-gui.sh:2124
msgid "File type change staged, modification not staged"
msgstr "Filtypsändringar köade, innehållsändringar ej köade"
-#: git-gui.sh:2113
+#: git-gui.sh:2125
msgid "File type change staged, file missing"
msgstr "Filtypsändringar köade, fil saknas"
-#: git-gui.sh:2115
+#: git-gui.sh:2127
msgid "Untracked, not staged"
msgstr "Ej spårade, ej köade"
-#: git-gui.sh:2120
+#: git-gui.sh:2132
msgid "Missing"
msgstr "Saknade"
-#: git-gui.sh:2121
+#: git-gui.sh:2133
msgid "Staged for removal"
msgstr "Köade för borttagning"
-#: git-gui.sh:2122
+#: git-gui.sh:2134
msgid "Staged for removal, still present"
msgstr "Köade för borttagning, fortfarande närvarande"
-#: git-gui.sh:2124 git-gui.sh:2125 git-gui.sh:2126 git-gui.sh:2127
-#: git-gui.sh:2128 git-gui.sh:2129
+#: git-gui.sh:2136 git-gui.sh:2137 git-gui.sh:2138 git-gui.sh:2139
+#: git-gui.sh:2140 git-gui.sh:2141
msgid "Requires merge resolution"
msgstr "Kräver konflikthantering efter sammanslagning"
-#: git-gui.sh:2164
-msgid "Starting gitk... please wait..."
-msgstr "Startar gitk... vänta..."
-
-#: git-gui.sh:2176
+#: git-gui.sh:2186
msgid "Couldn't find gitk in PATH"
msgstr "Hittade inte gitk i PATH."
-#: git-gui.sh:2235
+#: git-gui.sh:2233 git-gui.sh:2269
+#, tcl-format
+msgid "Starting %s... please wait..."
+msgstr "Startar %s... vänta..."
+
+#: git-gui.sh:2248
msgid "Couldn't find git gui in PATH"
msgstr "Hittade inte git gui i PATH."
-#: git-gui.sh:2654 lib/choose_repository.tcl:41
+#: git-gui.sh:2751 lib/choose_repository.tcl:53
msgid "Repository"
msgstr "Arkiv"
-#: git-gui.sh:2655
+#: git-gui.sh:2752
msgid "Edit"
msgstr "Redigera"
-#: git-gui.sh:2657 lib/choose_rev.tcl:567
+#: git-gui.sh:2754 lib/choose_rev.tcl:567
msgid "Branch"
msgstr "Gren"
-#: git-gui.sh:2660 lib/choose_rev.tcl:554
+#: git-gui.sh:2757 lib/choose_rev.tcl:554
msgid "Commit@@noun"
msgstr "Incheckning"
-#: git-gui.sh:2663 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170
+#: git-gui.sh:2760 lib/merge.tcl:127 lib/merge.tcl:174
msgid "Merge"
msgstr "Slå ihop"
-#: git-gui.sh:2664 lib/choose_rev.tcl:563
+#: git-gui.sh:2761 lib/choose_rev.tcl:563
msgid "Remote"
msgstr "Fjärrarkiv"
-#: git-gui.sh:2667
+#: git-gui.sh:2764
msgid "Tools"
msgstr "Verktyg"
-#: git-gui.sh:2676
+#: git-gui.sh:2773
msgid "Explore Working Copy"
msgstr "Utforska arbetskopia"
-#: git-gui.sh:2682
+#: git-gui.sh:2788
msgid "Git Bash"
msgstr "Git Bash"
-#: git-gui.sh:2692
+#: git-gui.sh:2797
msgid "Browse Current Branch's Files"
msgstr "Bläddra i grenens filer"
-#: git-gui.sh:2696
+#: git-gui.sh:2801
msgid "Browse Branch Files..."
msgstr "Bläddra filer på gren..."
-#: git-gui.sh:2701
+#: git-gui.sh:2806
msgid "Visualize Current Branch's History"
msgstr "Visualisera grenens historik"
-#: git-gui.sh:2705
+#: git-gui.sh:2810
msgid "Visualize All Branch History"
msgstr "Visualisera alla grenars historik"
-#: git-gui.sh:2712
+#: git-gui.sh:2817
#, tcl-format
msgid "Browse %s's Files"
msgstr "Bläddra i filer för %s"
-#: git-gui.sh:2714
+#: git-gui.sh:2819
#, tcl-format
msgid "Visualize %s's History"
msgstr "Visualisera historik för %s"
-#: git-gui.sh:2719 lib/database.tcl:40 lib/database.tcl:66
+#: git-gui.sh:2824 lib/database.tcl:40
msgid "Database Statistics"
msgstr "Databasstatistik"
-#: git-gui.sh:2722 lib/database.tcl:33
+#: git-gui.sh:2827 lib/database.tcl:33
msgid "Compress Database"
msgstr "Komprimera databas"
-#: git-gui.sh:2725
+#: git-gui.sh:2830
msgid "Verify Database"
msgstr "Verifiera databas"
-#: git-gui.sh:2732 git-gui.sh:2736 git-gui.sh:2740 lib/shortcut.tcl:8
-#: lib/shortcut.tcl:40 lib/shortcut.tcl:72
+#: git-gui.sh:2837 git-gui.sh:2841 git-gui.sh:2845
msgid "Create Desktop Icon"
msgstr "Skapa skrivbordsikon"
-#: git-gui.sh:2748 lib/choose_repository.tcl:193 lib/choose_repository.tcl:201
+#: git-gui.sh:2853 lib/choose_repository.tcl:206 lib/choose_repository.tcl:214
msgid "Quit"
msgstr "Avsluta"
-#: git-gui.sh:2756
+#: git-gui.sh:2861
msgid "Undo"
msgstr "Ã…ngra"
-#: git-gui.sh:2759
+#: git-gui.sh:2864
msgid "Redo"
msgstr "Gör om"
-#: git-gui.sh:2763 git-gui.sh:3368
+#: git-gui.sh:2868 git-gui.sh:3493
msgid "Cut"
msgstr "Klipp ut"
-#: git-gui.sh:2766 git-gui.sh:3371 git-gui.sh:3445 git-gui.sh:3530
+#: git-gui.sh:2871 git-gui.sh:3496 git-gui.sh:3572 git-gui.sh:3665
#: lib/console.tcl:69
msgid "Copy"
msgstr "Kopiera"
-#: git-gui.sh:2769 git-gui.sh:3374
+#: git-gui.sh:2874 git-gui.sh:3499
msgid "Paste"
msgstr "Klistra in"
-#: git-gui.sh:2772 git-gui.sh:3377 lib/remote_branch_delete.tcl:39
-#: lib/branch_delete.tcl:28
+#: git-gui.sh:2877 git-gui.sh:3502 lib/branch_delete.tcl:28
+#: lib/remote_branch_delete.tcl:39
msgid "Delete"
msgstr "Ta bort"
-#: git-gui.sh:2776 git-gui.sh:3381 git-gui.sh:3534 lib/console.tcl:71
+#: git-gui.sh:2881 git-gui.sh:3506 git-gui.sh:3669 lib/console.tcl:71
msgid "Select All"
msgstr "Markera alla"
-#: git-gui.sh:2785
+#: git-gui.sh:2890
msgid "Create..."
msgstr "Skapa..."
-#: git-gui.sh:2791
+#: git-gui.sh:2896
msgid "Checkout..."
msgstr "Checka ut..."
-#: git-gui.sh:2797
+#: git-gui.sh:2902
msgid "Rename..."
msgstr "Byt namn..."
-#: git-gui.sh:2802
+#: git-gui.sh:2907
msgid "Delete..."
msgstr "Ta bort..."
-#: git-gui.sh:2807
+#: git-gui.sh:2912
msgid "Reset..."
msgstr "Återställ..."
-#: git-gui.sh:2817
+#: git-gui.sh:2922
msgid "Done"
msgstr "Färdig"
-#: git-gui.sh:2819
+#: git-gui.sh:2924
msgid "Commit@@verb"
msgstr "Checka in"
-#: git-gui.sh:2828 git-gui.sh:3309
-msgid "New Commit"
-msgstr "Ny incheckning"
-
-#: git-gui.sh:2836 git-gui.sh:3316
+#: git-gui.sh:2933 git-gui.sh:3432
msgid "Amend Last Commit"
msgstr "Lägg till föregående incheckning"
-#: git-gui.sh:2846 git-gui.sh:3270 lib/remote_branch_delete.tcl:101
+#: git-gui.sh:2943 git-gui.sh:3393 lib/remote_branch_delete.tcl:101
msgid "Rescan"
msgstr "Sök på nytt"
-#: git-gui.sh:2852
+#: git-gui.sh:2949
msgid "Stage To Commit"
msgstr "Köa för incheckning"
-#: git-gui.sh:2858
+#: git-gui.sh:2955
msgid "Stage Changed Files To Commit"
msgstr "Köa ändrade filer för incheckning"
-#: git-gui.sh:2864
+#: git-gui.sh:2961
msgid "Unstage From Commit"
msgstr "Ta bort från incheckningskö"
-#: git-gui.sh:2870 lib/index.tcl:442
+#: git-gui.sh:2967 lib/index.tcl:521
msgid "Revert Changes"
msgstr "Återställ ändringar"
-#: git-gui.sh:2878 git-gui.sh:3581 git-gui.sh:3612
+#: git-gui.sh:2975 git-gui.sh:3732 git-gui.sh:3763
msgid "Show Less Context"
msgstr "Visa mindre sammanhang"
-#: git-gui.sh:2882 git-gui.sh:3585 git-gui.sh:3616
+#: git-gui.sh:2979 git-gui.sh:3736 git-gui.sh:3767
msgid "Show More Context"
msgstr "Visa mer sammanhang"
-#: git-gui.sh:2889 git-gui.sh:3283 git-gui.sh:3392
+#: git-gui.sh:2986 git-gui.sh:3406 git-gui.sh:3517
msgid "Sign Off"
msgstr "Skriv under"
-#: git-gui.sh:2905
+#: git-gui.sh:3002
msgid "Local Merge..."
msgstr "Lokal sammanslagning..."
-#: git-gui.sh:2910
+#: git-gui.sh:3007
msgid "Abort Merge..."
msgstr "Avbryt sammanslagning..."
-#: git-gui.sh:2922 git-gui.sh:2950
+#: git-gui.sh:3019 git-gui.sh:3047
msgid "Add..."
msgstr "Lägg till..."
-#: git-gui.sh:2926
+#: git-gui.sh:3023
msgid "Push..."
msgstr "Sänd..."
-#: git-gui.sh:2930
+#: git-gui.sh:3027
msgid "Delete Branch..."
msgstr "Ta bort gren..."
-#: git-gui.sh:2940 git-gui.sh:3563
+#: git-gui.sh:3037 git-gui.sh:3698
msgid "Options..."
msgstr "Alternativ..."
-#: git-gui.sh:2951
+#: git-gui.sh:3048
msgid "Remove..."
msgstr "Ta bort..."
-#: git-gui.sh:2960 lib/choose_repository.tcl:55
+#: git-gui.sh:3057 lib/choose_repository.tcl:67
msgid "Help"
msgstr "Hjälp"
-#: git-gui.sh:2964 git-gui.sh:2968 lib/choose_repository.tcl:49
-#: lib/choose_repository.tcl:58 lib/about.tcl:14
+#: git-gui.sh:3061 git-gui.sh:3065 lib/about.tcl:14
+#: lib/choose_repository.tcl:61 lib/choose_repository.tcl:70
#, tcl-format
msgid "About %s"
msgstr "Om %s"
-#: git-gui.sh:2992
+#: git-gui.sh:3085
msgid "Online Documentation"
msgstr "Webbdokumentation"
-#: git-gui.sh:2995 lib/choose_repository.tcl:52 lib/choose_repository.tcl:61
+#: git-gui.sh:3088 lib/choose_repository.tcl:64 lib/choose_repository.tcl:73
msgid "Show SSH Key"
msgstr "Visa SSH-nyckel"
-#: git-gui.sh:3014 git-gui.sh:3146
+#: git-gui.sh:3118 git-gui.sh:3250
+msgid "usage:"
+msgstr "användning:"
+
+#: git-gui.sh:3122 git-gui.sh:3254
msgid "Usage"
msgstr "Användning"
-#: git-gui.sh:3095 lib/blame.tcl:573
+#: git-gui.sh:3203 lib/blame.tcl:576
msgid "Error"
msgstr "Fel"
-#: git-gui.sh:3126
+#: git-gui.sh:3234
#, tcl-format
msgid "fatal: cannot stat path %s: No such file or directory"
msgstr ""
"ödesdigert: kunde inte ta status på sökvägen %s: Fil eller katalog saknas"
-#: git-gui.sh:3159
+#: git-gui.sh:3267
msgid "Current Branch:"
msgstr "Aktuell gren:"
-#: git-gui.sh:3185
-msgid "Staged Changes (Will Commit)"
-msgstr "Köade ändringar (kommer att checkas in)"
-
-#: git-gui.sh:3205
+#: git-gui.sh:3292
msgid "Unstaged Changes"
msgstr "Oköade ändringar"
-#: git-gui.sh:3276
+#: git-gui.sh:3314
+msgid "Staged Changes (Will Commit)"
+msgstr "Köade ändringar (kommer att checkas in)"
+
+#: git-gui.sh:3399
msgid "Stage Changed"
msgstr "Köa ändrade"
-#: git-gui.sh:3295 lib/transport.tcl:137 lib/transport.tcl:229
+#: git-gui.sh:3418 lib/transport.tcl:137
msgid "Push"
msgstr "Sänd"
-#: git-gui.sh:3330
+#: git-gui.sh:3445
msgid "Initial Commit Message:"
msgstr "Inledande incheckningsmeddelande:"
-#: git-gui.sh:3331
+#: git-gui.sh:3446
msgid "Amended Commit Message:"
msgstr "Utökat incheckningsmeddelande:"
-#: git-gui.sh:3332
+#: git-gui.sh:3447
msgid "Amended Initial Commit Message:"
msgstr "Utökat inledande incheckningsmeddelande:"
-#: git-gui.sh:3333
+#: git-gui.sh:3448
msgid "Amended Merge Commit Message:"
msgstr "Utökat incheckningsmeddelande för sammanslagning:"
-#: git-gui.sh:3334
+#: git-gui.sh:3449
msgid "Merge Commit Message:"
msgstr "Incheckningsmeddelande för sammanslagning:"
-#: git-gui.sh:3335
+#: git-gui.sh:3450
msgid "Commit Message:"
msgstr "Incheckningsmeddelande:"
-#: git-gui.sh:3384 git-gui.sh:3538 lib/console.tcl:73
+#: git-gui.sh:3509 git-gui.sh:3673 lib/console.tcl:73
msgid "Copy All"
msgstr "Kopiera alla"
-#: git-gui.sh:3408 lib/blame.tcl:105
+#: git-gui.sh:3533 lib/blame.tcl:106
msgid "File:"
msgstr "Fil:"
-#: git-gui.sh:3526
+#: git-gui.sh:3581 lib/choose_repository.tcl:1054
+msgid "Open"
+msgstr "Öppna"
+
+#: git-gui.sh:3661
msgid "Refresh"
msgstr "Uppdatera"
-#: git-gui.sh:3547
+#: git-gui.sh:3682
msgid "Decrease Font Size"
msgstr "Minska teckensnittsstorlek"
-#: git-gui.sh:3551
+#: git-gui.sh:3686
msgid "Increase Font Size"
msgstr "Öka teckensnittsstorlek"
-#: git-gui.sh:3559 lib/blame.tcl:294
+#: git-gui.sh:3694 lib/blame.tcl:296
msgid "Encoding"
msgstr "Teckenkodning"
-#: git-gui.sh:3570
+#: git-gui.sh:3705
msgid "Apply/Reverse Hunk"
msgstr "Använd/återställ del"
-#: git-gui.sh:3575
+#: git-gui.sh:3710
msgid "Apply/Reverse Line"
msgstr "Använd/återställ rad"
-#: git-gui.sh:3594
+#: git-gui.sh:3716 git-gui.sh:3826 git-gui.sh:3837
+msgid "Revert Hunk"
+msgstr "Återställ del"
+
+#: git-gui.sh:3721 git-gui.sh:3833 git-gui.sh:3844
+msgid "Revert Line"
+msgstr "Återställ rad"
+
+#: git-gui.sh:3726 git-gui.sh:3823
+msgid "Undo Last Revert"
+msgstr "Ångra senaste återställning"
+
+#: git-gui.sh:3745
msgid "Run Merge Tool"
msgstr "Starta verktyg för sammanslagning"
-#: git-gui.sh:3599
+#: git-gui.sh:3750
msgid "Use Remote Version"
msgstr "Använd versionen från fjärrarkivet"
-#: git-gui.sh:3603
+#: git-gui.sh:3754
msgid "Use Local Version"
msgstr "Använd lokala versionen"
-#: git-gui.sh:3607
+#: git-gui.sh:3758
msgid "Revert To Base"
msgstr "Återställ till basversionen"
-#: git-gui.sh:3625
+#: git-gui.sh:3776
msgid "Visualize These Changes In The Submodule"
msgstr "Visualisera ändringarna i undermodulen"
-#: git-gui.sh:3629
+#: git-gui.sh:3780
msgid "Visualize Current Branch History In The Submodule"
msgstr "Visualisera grenens historik i undermodulen"
-#: git-gui.sh:3633
+#: git-gui.sh:3784
msgid "Visualize All Branch History In The Submodule"
msgstr "Visualisera alla grenars historik i undermodulen"
-#: git-gui.sh:3638
+#: git-gui.sh:3789
msgid "Start git gui In The Submodule"
msgstr "Starta git gui i undermodulen"
-#: git-gui.sh:3673
+#: git-gui.sh:3825
msgid "Unstage Hunk From Commit"
msgstr "Ta bort del ur incheckningskö"
-#: git-gui.sh:3675
+#: git-gui.sh:3829
msgid "Unstage Lines From Commit"
msgstr "Ta bort rader ur incheckningskö"
-#: git-gui.sh:3677
+#: git-gui.sh:3830 git-gui.sh:3841
+msgid "Revert Lines"
+msgstr "Återställ rader"
+
+#: git-gui.sh:3832
msgid "Unstage Line From Commit"
msgstr "Ta bort rad ur incheckningskö"
-#: git-gui.sh:3680
+#: git-gui.sh:3836
msgid "Stage Hunk For Commit"
msgstr "Ställ del i incheckningskö"
-#: git-gui.sh:3682
+#: git-gui.sh:3840
msgid "Stage Lines For Commit"
msgstr "Ställ rader i incheckningskö"
-#: git-gui.sh:3684
+#: git-gui.sh:3843
msgid "Stage Line For Commit"
msgstr "Ställ rad i incheckningskö"
-#: git-gui.sh:3709
+#: git-gui.sh:3893
msgid "Initializing..."
msgstr "Initierar..."
-#: git-gui.sh:3852
+#: lib/about.tcl:26
+msgid "git-gui - a graphical user interface for Git."
+msgstr "git-gui - ett grafiskt användargränssnitt för Git."
+
+#: lib/blame.tcl:74
#, tcl-format
-msgid ""
-"Possible environment issues exist.\n"
-"\n"
-"The following environment variables are probably\n"
-"going to be ignored by any Git subprocess run\n"
-"by %s:\n"
-"\n"
-msgstr ""
-"Det finns möjliga problem med miljövariabler.\n"
-"\n"
-"Följande miljövariabler kommer troligen att\n"
-"ignoreras av alla Git-underprocesser som körs\n"
-"av %s:\n"
-"\n"
+msgid "%s (%s): File Viewer"
+msgstr "%s (%s): Filvisare"
+
+#: lib/blame.tcl:80
+msgid "Commit:"
+msgstr "Incheckning:"
+
+#: lib/blame.tcl:282
+msgid "Copy Commit"
+msgstr "Kopiera incheckning"
+
+#: lib/blame.tcl:286
+msgid "Find Text..."
+msgstr "Sök text..."
+
+#: lib/blame.tcl:290
+msgid "Goto Line..."
+msgstr "GÃ¥ till rad..."
+
+#: lib/blame.tcl:299
+msgid "Do Full Copy Detection"
+msgstr "Gör full kopieringsigenkänning"
+
+#: lib/blame.tcl:303
+msgid "Show History Context"
+msgstr "Visa historiksammanhang"
+
+#: lib/blame.tcl:306
+msgid "Blame Parent Commit"
+msgstr "Klandra föräldraincheckning"
+
+#: lib/blame.tcl:469
+#, tcl-format
+msgid "Reading %s..."
+msgstr "Läser %s..."
+
+#: lib/blame.tcl:597
+msgid "Loading copy/move tracking annotations..."
+msgstr "Läser annoteringar för kopiering/flyttning..."
+
+#: lib/blame.tcl:614
+msgid "lines annotated"
+msgstr "rader annoterade"
+
+#: lib/blame.tcl:816
+msgid "Loading original location annotations..."
+msgstr "Läser in annotering av originalplacering..."
+
+#: lib/blame.tcl:819
+msgid "Annotation complete."
+msgstr "Annotering fullbordad."
+
+#: lib/blame.tcl:850
+msgid "Busy"
+msgstr "Upptagen"
+
+#: lib/blame.tcl:851
+msgid "Annotation process is already running."
+msgstr "Annoteringsprocess körs redan."
+
+#: lib/blame.tcl:890
+msgid "Running thorough copy detection..."
+msgstr "Kör grundlig kopieringsigenkänning..."
+
+#: lib/blame.tcl:958
+msgid "Loading annotation..."
+msgstr "Läser in annotering..."
+
+#: lib/blame.tcl:1011
+msgid "Author:"
+msgstr "Författare:"
+
+#: lib/blame.tcl:1015
+msgid "Committer:"
+msgstr "Incheckare:"
+
+#: lib/blame.tcl:1020
+msgid "Original File:"
+msgstr "Ursprunglig fil:"
+
+#: lib/blame.tcl:1068
+msgid "Cannot find HEAD commit:"
+msgstr "Hittar inte incheckning för HEAD:"
+
+#: lib/blame.tcl:1123
+msgid "Cannot find parent commit:"
+msgstr "Hittar inte föräldraincheckning:"
+
+#: lib/blame.tcl:1138
+msgid "Unable to display parent"
+msgstr "Kan inte visa förälder"
+
+#: lib/blame.tcl:1139 lib/diff.tcl:345
+msgid "Error loading diff:"
+msgstr "Fel vid inläsning av differens:"
+
+#: lib/blame.tcl:1280
+msgid "Originally By:"
+msgstr "Ursprungligen av:"
+
+#: lib/blame.tcl:1286
+msgid "In File:"
+msgstr "I filen:"
+
+#: lib/blame.tcl:1291
+msgid "Copied Or Moved Here By:"
+msgstr "Kopierad eller flyttad hit av:"
+
+#: lib/branch_checkout.tcl:16
+#, tcl-format
+msgid "%s (%s): Checkout Branch"
+msgstr "%s (%s): Checka ut gren"
+
+#: lib/branch_checkout.tcl:21
+msgid "Checkout Branch"
+msgstr "Checka ut gren"
+
+#: lib/branch_checkout.tcl:26
+msgid "Checkout"
+msgstr "Checka ut"
+
+#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 lib/branch_delete.tcl:34
+#: lib/branch_rename.tcl:32 lib/browser.tcl:292 lib/checkout_op.tcl:580
+#: lib/choose_font.tcl:45 lib/merge.tcl:178 lib/option.tcl:127
+#: lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 lib/tools_dlg.tcl:41
+#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/transport.tcl:141
+msgid "Cancel"
+msgstr "Avbryt"
+
+#: lib/branch_checkout.tcl:35 lib/browser.tcl:297 lib/tools_dlg.tcl:321
+msgid "Revision"
+msgstr "Revision"
+
+#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:310
+msgid "Options"
+msgstr "Alternativ"
+
+#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92
+msgid "Fetch Tracking Branch"
+msgstr "Hämta spårande gren"
+
+#: lib/branch_checkout.tcl:47
+msgid "Detach From Local Branch"
+msgstr "Koppla bort från lokal gren"
+
+#: lib/branch_create.tcl:23
+#, tcl-format
+msgid "%s (%s): Create Branch"
+msgstr "%s (%s): Skapa gren"
+
+#: lib/branch_create.tcl:28
+msgid "Create New Branch"
+msgstr "Skapa ny gren"
+
+#: lib/branch_create.tcl:33 lib/choose_repository.tcl:386
+msgid "Create"
+msgstr "Skapa"
+
+#: lib/branch_create.tcl:42
+msgid "Branch Name"
+msgstr "Namn på gren"
+
+#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51
+msgid "Name:"
+msgstr "Namn:"
+
+#: lib/branch_create.tcl:57
+msgid "Match Tracking Branch Name"
+msgstr "Använd namn på spårad gren"
+
+#: lib/branch_create.tcl:66
+msgid "Starting Revision"
+msgstr "Inledande revision"
+
+#: lib/branch_create.tcl:72
+msgid "Update Existing Branch:"
+msgstr "Uppdatera befintlig gren:"
+
+#: lib/branch_create.tcl:75
+msgid "No"
+msgstr "Nej"
+
+#: lib/branch_create.tcl:80
+msgid "Fast Forward Only"
+msgstr "Endast snabbspolning"
+
+#: lib/branch_create.tcl:85 lib/checkout_op.tcl:572
+msgid "Reset"
+msgstr "Återställ"
+
+#: lib/branch_create.tcl:97
+msgid "Checkout After Creation"
+msgstr "Checka ut när skapad"
+
+#: lib/branch_create.tcl:132
+msgid "Please select a tracking branch."
+msgstr "Välj en gren att spåra."
+
+#: lib/branch_create.tcl:141
+#, tcl-format
+msgid "Tracking branch %s is not a branch in the remote repository."
+msgstr "Den spårade grenen %s är inte en gren i fjärrarkivet."
+
+#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92
+msgid "Please supply a branch name."
+msgstr "Ange ett namn för grenen."
+
+#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112
+#, tcl-format
+msgid "'%s' is not an acceptable branch name."
+msgstr "â€%s†kan inte användas som namn pÃ¥ grenen."
+
+#: lib/branch_delete.tcl:16
+#, tcl-format
+msgid "%s (%s): Delete Branch"
+msgstr "%s (%s): Ta bort gren"
+
+#: lib/branch_delete.tcl:21
+msgid "Delete Local Branch"
+msgstr "Ta bort lokal gren"
+
+#: lib/branch_delete.tcl:39
+msgid "Local Branches"
+msgstr "Lokala grenar"
+
+#: lib/branch_delete.tcl:51
+msgid "Delete Only If Merged Into"
+msgstr "Ta bara bort om sammanslagen med"
+
+#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120
+msgid "Always (Do not perform merge checks)"
+msgstr "Alltid (utför inte sammanslagningstest)"
-#: git-gui.sh:3881
+#: lib/branch_delete.tcl:103
+#, tcl-format
+msgid "The following branches are not completely merged into %s:"
+msgstr "Följande grenar är inte till fullo sammanslagna med %s:"
+
+#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218
msgid ""
+"Recovering deleted branches is difficult.\n"
"\n"
-"This is due to a known issue with the\n"
-"Tcl binary distributed by Cygwin."
+"Delete the selected branches?"
msgstr ""
+"Det kan vara svårt att återställa borttagna grenar.\n"
"\n"
-"Detta beror på ett känt problem med\n"
-"Tcl-binären som följer med Cygwin."
+"Ta bort de valda grenarna?"
-#: git-gui.sh:3886
+#: lib/branch_delete.tcl:131
+#, tcl-format
+msgid " - %s:"
+msgstr " - %s:"
+
+#: lib/branch_delete.tcl:141
#, tcl-format
msgid ""
-"\n"
-"\n"
-"A good replacement for %s\n"
-"is placing values for the user.name and\n"
-"user.email settings into your personal\n"
-"~/.gitconfig file.\n"
+"Failed to delete branches:\n"
+"%s"
msgstr ""
-"\n"
-"\n"
-"Du kan ersätta %s\n"
-"med att lägga in värden för inställningarna\n"
-"user.name och user.email i din personliga\n"
-"~/.gitconfig-fil.\n"
+"Kunde inte ta bort grenar:\n"
+"%s"
-#: lib/line.tcl:17
-msgid "Goto Line:"
-msgstr "GÃ¥ till rad:"
+#: lib/branch_rename.tcl:15
+#, tcl-format
+msgid "%s (%s): Rename Branch"
+msgstr "%s (%s): Byt namn på gren"
-#: lib/line.tcl:23
-msgid "Go"
-msgstr "GÃ¥"
+#: lib/branch_rename.tcl:23
+msgid "Rename Branch"
+msgstr "Byt namn på gren"
-#: lib/console.tcl:59
-msgid "Working... please wait..."
-msgstr "Arbetar... vänta..."
+#: lib/branch_rename.tcl:28
+msgid "Rename"
+msgstr "Byt namn"
-#: lib/console.tcl:81 lib/checkout_op.tcl:146 lib/sshkey.tcl:55
-#: lib/database.tcl:30
-msgid "Close"
-msgstr "Stäng"
+#: lib/branch_rename.tcl:38
+msgid "Branch:"
+msgstr "Gren:"
-#: lib/console.tcl:186
-msgid "Success"
-msgstr "Lyckades"
+#: lib/branch_rename.tcl:46
+msgid "New Name:"
+msgstr "Nytt namn:"
-#: lib/console.tcl:200
-msgid "Error: Command Failed"
-msgstr "Fel: Kommando misslyckades"
+#: lib/branch_rename.tcl:81
+msgid "Please select a branch to rename."
+msgstr "Välj en gren att byta namn på."
+
+#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202
+#, tcl-format
+msgid "Branch '%s' already exists."
+msgstr "Grenen â€%s†finns redan."
+
+#: lib/branch_rename.tcl:123
+#, tcl-format
+msgid "Failed to rename '%s'."
+msgstr "Kunde inte byta namn pÃ¥ â€%sâ€."
+
+#: lib/browser.tcl:17
+msgid "Starting..."
+msgstr "Startar..."
+
+#: lib/browser.tcl:27
+#, tcl-format
+msgid "%s (%s): File Browser"
+msgstr "%s (%s): Filbläddrare"
+
+#: lib/browser.tcl:132 lib/browser.tcl:149
+#, tcl-format
+msgid "Loading %s..."
+msgstr "Läser %s..."
+
+#: lib/browser.tcl:193
+msgid "[Up To Parent]"
+msgstr "[Upp till förälder]"
+
+#: lib/browser.tcl:275
+#, tcl-format
+msgid "%s (%s): Browse Branch Files"
+msgstr "%s (%s): Bläddra filer på grenen"
+
+#: lib/browser.tcl:282
+msgid "Browse Branch Files"
+msgstr "Bläddra filer på grenen"
+
+#: lib/browser.tcl:288 lib/choose_repository.tcl:401
+#: lib/choose_repository.tcl:488 lib/choose_repository.tcl:497
+#: lib/choose_repository.tcl:1069
+msgid "Browse"
+msgstr "Bläddra"
#: lib/checkout_op.tcl:85
#, tcl-format
@@ -642,21 +929,21 @@ msgstr "Hämtar %s från %s"
msgid "fatal: Cannot resolve %s"
msgstr "ödesdigert: Kunde inte slå upp %s"
+#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30
+#: lib/sshkey.tcl:58
+msgid "Close"
+msgstr "Stäng"
+
#: lib/checkout_op.tcl:175
#, tcl-format
msgid "Branch '%s' does not exist."
-msgstr "Grenen \"%s\" finns inte."
+msgstr "Grenen â€%s†finns inte."
#: lib/checkout_op.tcl:194
#, tcl-format
msgid "Failed to configure simplified git-pull for '%s'."
msgstr "Kunde inte konfigurera förenklad git-pull för '%s'."
-#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102
-#, tcl-format
-msgid "Branch '%s' already exists."
-msgstr "Grenen \"%s\" finns redan."
-
#: lib/checkout_op.tcl:229
#, tcl-format
msgid ""
@@ -665,7 +952,7 @@ msgid ""
"It cannot fast-forward to %s.\n"
"A merge is required."
msgstr ""
-"Grenen \"%s\" finns redan.\n"
+"Grenen â€%s†finns redan.\n"
"\n"
"Den kan inte snabbspolas till %s.\n"
"En sammanslagning krävs."
@@ -673,12 +960,12 @@ msgstr ""
#: lib/checkout_op.tcl:243
#, tcl-format
msgid "Merge strategy '%s' not supported."
-msgstr "Sammanslagningsstrategin \"%s\" stöds inte."
+msgstr "Sammanslagningsstrategin â€%s†stöds inte."
#: lib/checkout_op.tcl:262
#, tcl-format
msgid "Failed to update '%s'."
-msgstr "Misslyckades med att uppdatera \"%s\"."
+msgstr "Misslyckades med att uppdatera â€%sâ€."
#: lib/checkout_op.tcl:274
msgid "Staging area (index) is already locked."
@@ -703,27 +990,27 @@ msgstr ""
#: lib/checkout_op.tcl:345
#, tcl-format
msgid "Updating working directory to '%s'..."
-msgstr "Uppdaterar arbetskatalogen till \"%s\"..."
+msgstr "Uppdaterar arbetskatalogen till â€%sâ€..."
#: lib/checkout_op.tcl:346
msgid "files checked out"
msgstr "filer utcheckade"
-#: lib/checkout_op.tcl:376
+#: lib/checkout_op.tcl:377
#, tcl-format
msgid "Aborted checkout of '%s' (file level merging is required)."
-msgstr "Avbryter utcheckning av \"%s\" (sammanslagning på filnivå krävs)."
+msgstr "Avbryter utcheckning av â€%s†(sammanslagning pÃ¥ filnivÃ¥ krävs)."
-#: lib/checkout_op.tcl:377
+#: lib/checkout_op.tcl:378
msgid "File level merge required."
msgstr "Sammanslagning på filnivå krävs."
-#: lib/checkout_op.tcl:381
+#: lib/checkout_op.tcl:382
#, tcl-format
msgid "Staying on branch '%s'."
-msgstr "Stannar på grenen \"%s\"."
+msgstr "Stannar pÃ¥ grenen â€%sâ€."
-#: lib/checkout_op.tcl:452
+#: lib/checkout_op.tcl:453
msgid ""
"You are no longer on a local branch.\n"
"\n"
@@ -732,47 +1019,33 @@ msgid ""
msgstr ""
"Du är inte längre på en lokal gren.\n"
"\n"
-"Om du ville vara på en gren skapar du en nu, baserad på \"Denna frånkopplade "
-"utcheckning\"."
+"Om du ville vara pÃ¥ en gren skapar du en nu, baserad pÃ¥ â€Denna frÃ¥nkopplade "
+"utcheckningâ€."
-#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507
+#: lib/checkout_op.tcl:504 lib/checkout_op.tcl:508
#, tcl-format
msgid "Checked out '%s'."
-msgstr "Checkade ut \"%s\"."
+msgstr "Checkade ut â€%sâ€."
-#: lib/checkout_op.tcl:535
+#: lib/checkout_op.tcl:536
#, tcl-format
msgid "Resetting '%s' to '%s' will lose the following commits:"
-msgstr ""
-"Om du återställer \"%s\" till \"%s\" går följande incheckningar förlorade:"
+msgstr "Om du Ã¥terställer â€%s†till â€%s†gÃ¥r följande incheckningar förlorade:"
-#: lib/checkout_op.tcl:557
+#: lib/checkout_op.tcl:558
msgid "Recovering lost commits may not be easy."
msgstr "Det kanske inte är så enkelt att återskapa förlorade incheckningar."
-#: lib/checkout_op.tcl:562
+#: lib/checkout_op.tcl:563
#, tcl-format
msgid "Reset '%s'?"
-msgstr "Återställa \"%s\"?"
+msgstr "Ã…terställa â€%sâ€?"
-#: lib/checkout_op.tcl:567 lib/merge.tcl:166 lib/tools_dlg.tcl:336
+#: lib/checkout_op.tcl:568 lib/merge.tcl:170 lib/tools_dlg.tcl:336
msgid "Visualize"
msgstr "Visualisera"
-#: lib/checkout_op.tcl:571 lib/branch_create.tcl:85
-msgid "Reset"
-msgstr "Återställ"
-
-#: lib/checkout_op.tcl:579 lib/transport.tcl:141 lib/remote_add.tcl:34
-#: lib/browser.tcl:292 lib/merge.tcl:174 lib/branch_checkout.tcl:30
-#: lib/choose_font.tcl:45 lib/option.tcl:127 lib/tools_dlg.tcl:41
-#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/branch_rename.tcl:32
-#: lib/remote_branch_delete.tcl:43 lib/branch_create.tcl:37
-#: lib/branch_delete.tcl:34
-msgid "Cancel"
-msgstr "Avbryt"
-
-#: lib/checkout_op.tcl:635
+#: lib/checkout_op.tcl:636
#, tcl-format
msgid ""
"Failed to set current branch.\n"
@@ -789,440 +1062,577 @@ msgstr ""
"\n"
"Detta skulle inte ha hänt. %s kommer nu stängas och ge upp."
-#: lib/transport.tcl:6 lib/remote_add.tcl:132
-#, tcl-format
-msgid "fetch %s"
-msgstr "hämta %s"
+#: lib/choose_font.tcl:41
+msgid "Select"
+msgstr "Välj"
-#: lib/transport.tcl:7
-#, tcl-format
-msgid "Fetching new changes from %s"
-msgstr "Hämtar nya ändringar från %s"
+#: lib/choose_font.tcl:55
+msgid "Font Family"
+msgstr "Teckensnittsfamilj"
-#: lib/transport.tcl:18
-#, tcl-format
-msgid "remote prune %s"
-msgstr "fjärrborttagning %s"
+#: lib/choose_font.tcl:76
+msgid "Font Size"
+msgstr "Storlek"
-#: lib/transport.tcl:19
-#, tcl-format
-msgid "Pruning tracking branches deleted from %s"
-msgstr "Tar bort spårande grenar som tagits bort från %s"
+#: lib/choose_font.tcl:93
+msgid "Font Example"
+msgstr "Exempel"
-#: lib/transport.tcl:25
-msgid "fetch all remotes"
-msgstr "hämta alla fjärrarkiv"
+#: lib/choose_font.tcl:105
+msgid ""
+"This is example text.\n"
+"If you like this text, it can be your font."
+msgstr ""
+"Detta är en exempeltext.\n"
+"Om du tycker om den här texten kan den vara ditt teckensnitt."
-#: lib/transport.tcl:26
-msgid "Fetching new changes from all remotes"
-msgstr "Hämtar nya ändringar från alla fjärrarkiv"
+#: lib/choose_repository.tcl:45
+msgid "Git Gui"
+msgstr "Git Gui"
-#: lib/transport.tcl:40
-msgid "remote prune all remotes"
-msgstr "rensa alla fjärrarkiv"
+#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:391
+msgid "Create New Repository"
+msgstr "Skapa nytt arkiv"
-#: lib/transport.tcl:41
-msgid "Pruning tracking branches deleted from all remotes"
-msgstr "Rensar spårande grenar som tagits bort, från alla fjärrarkiv"
+#: lib/choose_repository.tcl:110
+msgid "New..."
+msgstr "Nytt..."
-#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110
-#: lib/remote_add.tcl:162
-#, tcl-format
-msgid "push %s"
-msgstr "sänd %s"
+#: lib/choose_repository.tcl:117 lib/choose_repository.tcl:475
+msgid "Clone Existing Repository"
+msgstr "Klona befintligt arkiv"
-#: lib/transport.tcl:55
+#: lib/choose_repository.tcl:128
+msgid "Clone..."
+msgstr "Klona..."
+
+#: lib/choose_repository.tcl:135 lib/choose_repository.tcl:1059
+msgid "Open Existing Repository"
+msgstr "Öppna befintligt arkiv"
+
+#: lib/choose_repository.tcl:141
+msgid "Open..."
+msgstr "Öppna..."
+
+#: lib/choose_repository.tcl:154
+msgid "Recent Repositories"
+msgstr "Senaste arkiven"
+
+#: lib/choose_repository.tcl:164
+msgid "Open Recent Repository:"
+msgstr "Öppna tidigare arkiv:"
+
+#: lib/choose_repository.tcl:328 lib/choose_repository.tcl:335
+#: lib/choose_repository.tcl:342
#, tcl-format
-msgid "Pushing changes to %s"
-msgstr "Sänder ändringar till %s"
+msgid "Failed to create repository %s:"
+msgstr "Kunde inte skapa arkivet %s:"
-#: lib/transport.tcl:93
+#: lib/choose_repository.tcl:396
+msgid "Directory:"
+msgstr "Katalog:"
+
+#: lib/choose_repository.tcl:426 lib/choose_repository.tcl:552
+#: lib/choose_repository.tcl:1093
+msgid "Git Repository"
+msgstr "Gitarkiv"
+
+#: lib/choose_repository.tcl:451
#, tcl-format
-msgid "Mirroring to %s"
-msgstr "Speglar till %s"
+msgid "Directory %s already exists."
+msgstr "Katalogen %s finns redan."
-#: lib/transport.tcl:111
+#: lib/choose_repository.tcl:455
#, tcl-format
-msgid "Pushing %s %s to %s"
-msgstr "Sänder %s %s till %s"
+msgid "File %s already exists."
+msgstr "Filen %s finns redan."
-#: lib/transport.tcl:132
-msgid "Push Branches"
-msgstr "Sänd grenar"
+#: lib/choose_repository.tcl:470
+msgid "Clone"
+msgstr "Klona"
-#: lib/transport.tcl:147
-msgid "Source Branches"
-msgstr "Källgrenar"
+#: lib/choose_repository.tcl:483
+msgid "Source Location:"
+msgstr "Plats för källkod:"
-#: lib/transport.tcl:162
-msgid "Destination Repository"
-msgstr "Destinationsarkiv"
+#: lib/choose_repository.tcl:492
+msgid "Target Directory:"
+msgstr "MÃ¥lkatalog:"
-#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51
-msgid "Remote:"
-msgstr "Fjärrarkiv:"
+#: lib/choose_repository.tcl:502
+msgid "Clone Type:"
+msgstr "Typ av klon:"
-#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72
-msgid "Arbitrary Location:"
-msgstr "Godtycklig plats:"
+#: lib/choose_repository.tcl:507
+msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
+msgstr "Standard (snabb, semiredundant, hårda länkar)"
-#: lib/transport.tcl:205
-msgid "Transfer Options"
-msgstr "Överföringsalternativ"
+#: lib/choose_repository.tcl:512
+msgid "Full Copy (Slower, Redundant Backup)"
+msgstr "Full kopia (långsammare, redundant säkerhetskopia)"
-#: lib/transport.tcl:207
-msgid "Force overwrite existing branch (may discard changes)"
-msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)"
+#: lib/choose_repository.tcl:517
+msgid "Shared (Fastest, Not Recommended, No Backup)"
+msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)"
-#: lib/transport.tcl:211
-msgid "Use thin pack (for slow network connections)"
-msgstr "Använd tunt paket (för långsamma nätverksanslutningar)"
+#: lib/choose_repository.tcl:524
+msgid "Recursively clone submodules too"
+msgstr "Klona även rekursivt undermoduler"
-#: lib/transport.tcl:215
-msgid "Include tags"
-msgstr "Ta med taggar"
+#: lib/choose_repository.tcl:558 lib/choose_repository.tcl:605
+#: lib/choose_repository.tcl:744 lib/choose_repository.tcl:818
+#: lib/choose_repository.tcl:1099 lib/choose_repository.tcl:1107
+#, tcl-format
+msgid "Not a Git repository: %s"
+msgstr "Inte ett Gitarkiv: %s"
-#: lib/remote_add.tcl:20
-msgid "Add Remote"
-msgstr "Lägg till fjärrarkiv"
+#: lib/choose_repository.tcl:594
+msgid "Standard only available for local repository."
+msgstr "Standard är endast tillgängligt för lokala arkiv."
-#: lib/remote_add.tcl:25
-msgid "Add New Remote"
-msgstr "Lägg till nytt fjärrarkiv"
+#: lib/choose_repository.tcl:598
+msgid "Shared only available for local repository."
+msgstr "Delat är endast tillgängligt för lokala arkiv."
-#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37
-msgid "Add"
-msgstr "Lägg till"
+#: lib/choose_repository.tcl:613
+#, tcl-format
+msgid "Location %s already exists."
+msgstr "Platsen %s finns redan."
-#: lib/remote_add.tcl:39
-msgid "Remote Details"
-msgstr "Detaljer för fjärrarkiv"
+#: lib/choose_repository.tcl:624
+msgid "Failed to configure origin"
+msgstr "Kunde inte konfigurera ursprung"
-#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44
-msgid "Name:"
-msgstr "Namn:"
+#: lib/choose_repository.tcl:636
+msgid "Counting objects"
+msgstr "Räknar objekt"
-#: lib/remote_add.tcl:50
-msgid "Location:"
-msgstr "Plats:"
+#: lib/choose_repository.tcl:637
+msgid "buckets"
+msgstr "hinkar"
-#: lib/remote_add.tcl:60
-msgid "Further Action"
-msgstr "Ytterligare åtgärd"
+#: lib/choose_repository.tcl:657
+#, tcl-format
+msgid "Unable to copy objects/info/alternates: %s"
+msgstr "Kunde inte kopiera objekt/info/alternativ: %s"
-#: lib/remote_add.tcl:63
-msgid "Fetch Immediately"
-msgstr "Hämta omedelbart"
+#: lib/choose_repository.tcl:694
+#, tcl-format
+msgid "Nothing to clone from %s."
+msgstr "Ingenting att klona från %s."
-#: lib/remote_add.tcl:69
-msgid "Initialize Remote Repository and Push"
-msgstr "Initiera fjärrarkiv och sänd till"
+#: lib/choose_repository.tcl:696 lib/choose_repository.tcl:916
+#: lib/choose_repository.tcl:928
+msgid "The 'master' branch has not been initialized."
+msgstr "Grenen â€master†har inte initierats."
-#: lib/remote_add.tcl:75
-msgid "Do Nothing Else Now"
-msgstr "Gör ingent mer nu"
+#: lib/choose_repository.tcl:709
+msgid "Hardlinks are unavailable. Falling back to copying."
+msgstr "Hårda länkar är inte tillgängliga. Faller tillbaka på kopiering."
-#: lib/remote_add.tcl:100
-msgid "Please supply a remote name."
-msgstr "Ange ett namn för fjärrarkivet."
+#: lib/choose_repository.tcl:723
+#, tcl-format
+msgid "Cloning from %s"
+msgstr "Klonar från %s"
-#: lib/remote_add.tcl:113
+#: lib/choose_repository.tcl:754
+msgid "Copying objects"
+msgstr "Kopierar objekt"
+
+#: lib/choose_repository.tcl:755
+msgid "KiB"
+msgstr "KiB"
+
+#: lib/choose_repository.tcl:779
#, tcl-format
-msgid "'%s' is not an acceptable remote name."
-msgstr "\"%s\" kan inte användas som namn på fjärrarkivet."
+msgid "Unable to copy object: %s"
+msgstr "Kunde inte kopiera objekt: %s"
-#: lib/remote_add.tcl:124
+#: lib/choose_repository.tcl:791
+msgid "Linking objects"
+msgstr "Länkar objekt"
+
+#: lib/choose_repository.tcl:792
+msgid "objects"
+msgstr "objekt"
+
+#: lib/choose_repository.tcl:800
#, tcl-format
-msgid "Failed to add remote '%s' of location '%s'."
-msgstr "Kunde inte lägga till fjärrarkivet \"%s\" på platsen \"%s\"."
+msgid "Unable to hardlink object: %s"
+msgstr "Kunde inte hårdlänka objekt: %s"
-#: lib/remote_add.tcl:133
+#: lib/choose_repository.tcl:857
+msgid "Cannot fetch branches and objects. See console output for details."
+msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer."
+
+#: lib/choose_repository.tcl:868
+msgid "Cannot fetch tags. See console output for details."
+msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer."
+
+#: lib/choose_repository.tcl:892
+msgid "Cannot determine HEAD. See console output for details."
+msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer."
+
+#: lib/choose_repository.tcl:901
#, tcl-format
-msgid "Fetching the %s"
-msgstr "Hämtar %s"
+msgid "Unable to cleanup %s"
+msgstr "Kunde inte städa upp %s"
-#: lib/remote_add.tcl:156
+#: lib/choose_repository.tcl:907
+msgid "Clone failed."
+msgstr "Kloning misslyckades."
+
+#: lib/choose_repository.tcl:914
+msgid "No default branch obtained."
+msgstr "Hämtade ingen standardgren."
+
+#: lib/choose_repository.tcl:925
#, tcl-format
-msgid "Do not know how to initialize repository at location '%s'."
-msgstr "Vet inte hur arkivet på platsen \"%s\" skall initieras."
+msgid "Cannot resolve %s as a commit."
+msgstr "Kunde inte slå upp %s till någon incheckning."
-#: lib/remote_add.tcl:163
+#: lib/choose_repository.tcl:952
+msgid "Creating working directory"
+msgstr "Skapar arbetskatalog"
+
+#: lib/choose_repository.tcl:953 lib/index.tcl:77 lib/index.tcl:146
+#: lib/index.tcl:220 lib/index.tcl:589
+msgid "files"
+msgstr "filer"
+
+#: lib/choose_repository.tcl:982
+msgid "Initial file checkout failed."
+msgstr "Inledande filutcheckning misslyckades."
+
+#: lib/choose_repository.tcl:1026
+msgid "Cloning submodules"
+msgstr "Klonar undermoduler"
+
+#: lib/choose_repository.tcl:1041
+msgid "Cannot clone submodules."
+msgstr "Kan inte klona undermoduler."
+
+#: lib/choose_repository.tcl:1064
+msgid "Repository:"
+msgstr "Arkiv:"
+
+#: lib/choose_repository.tcl:1113
#, tcl-format
-msgid "Setting up the %s (at %s)"
-msgstr "Konfigurerar %s (på %s)"
+msgid "Failed to open repository %s:"
+msgstr "Kunde inte öppna arkivet %s:"
-#: lib/browser.tcl:17
-msgid "Starting..."
-msgstr "Startar..."
+#: lib/choose_rev.tcl:52
+msgid "This Detached Checkout"
+msgstr "Denna frånkopplade utcheckning"
-#: lib/browser.tcl:27
-msgid "File Browser"
-msgstr "Filbläddrare"
+#: lib/choose_rev.tcl:60
+msgid "Revision Expression:"
+msgstr "Revisionsuttryck:"
-#: lib/browser.tcl:132 lib/browser.tcl:149
+#: lib/choose_rev.tcl:72
+msgid "Local Branch"
+msgstr "Lokal gren"
+
+#: lib/choose_rev.tcl:77
+msgid "Tracking Branch"
+msgstr "Spårande gren"
+
+#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544
+msgid "Tag"
+msgstr "Tagg"
+
+#: lib/choose_rev.tcl:321
#, tcl-format
-msgid "Loading %s..."
-msgstr "Läser %s..."
+msgid "Invalid revision: %s"
+msgstr "Ogiltig revision: %s"
-#: lib/browser.tcl:193
-msgid "[Up To Parent]"
-msgstr "[Upp till förälder]"
+#: lib/choose_rev.tcl:342
+msgid "No revision selected."
+msgstr "Ingen revision vald."
-#: lib/browser.tcl:275 lib/browser.tcl:282
-msgid "Browse Branch Files"
-msgstr "Bläddra filer på grenen"
+#: lib/choose_rev.tcl:350
+msgid "Revision expression is empty."
+msgstr "Revisionsuttrycket är tomt."
-#: lib/browser.tcl:288 lib/choose_repository.tcl:422
-#: lib/choose_repository.tcl:509 lib/choose_repository.tcl:518
-#: lib/choose_repository.tcl:1074
-msgid "Browse"
-msgstr "Bläddra"
+#: lib/choose_rev.tcl:537
+msgid "Updated"
+msgstr "Uppdaterad"
-#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321
-msgid "Revision"
-msgstr "Revision"
+#: lib/choose_rev.tcl:565
+msgid "URL"
+msgstr "Webbadress"
-#: lib/merge.tcl:13
+#: lib/commit.tcl:9
msgid ""
-"Cannot merge while amending.\n"
+"There is nothing to amend.\n"
"\n"
-"You must finish amending this commit before starting any type of merge.\n"
+"You are about to create the initial commit. There is no commit before this "
+"to amend.\n"
msgstr ""
-"Kan inte slå ihop vid utökning.\n"
+"Det finns ingenting att utöka.\n"
"\n"
-"Du måste göra färdig utökningen av incheckningen innan du påbörjar någon "
-"slags sammanslagning.\n"
+"Du håller på att skapa den inledande incheckningen. Det finns ingen tidigare "
+"incheckning att utöka.\n"
-#: lib/merge.tcl:27
+#: lib/commit.tcl:18
+msgid ""
+"Cannot amend while merging.\n"
+"\n"
+"You are currently in the middle of a merge that has not been fully "
+"completed. You cannot amend the prior commit unless you first abort the "
+"current merge activity.\n"
+msgstr ""
+"Kan inte utöka vid sammanslagning.\n"
+"\n"
+"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte "
+"utöka tidigare incheckningar om du inte först avbryter den pågående "
+"sammanslagningen.\n"
+
+#: lib/commit.tcl:56
+msgid "Error loading commit data for amend:"
+msgstr "Fel vid inläsning av incheckningsdata för utökning:"
+
+#: lib/commit.tcl:83
+msgid "Unable to obtain your identity:"
+msgstr "Kunde inte hämta din identitet:"
+
+#: lib/commit.tcl:88
+msgid "Invalid GIT_COMMITTER_IDENT:"
+msgstr "Felaktig GIT_COMMITTER_IDENT:"
+
+#: lib/commit.tcl:138
+#, tcl-format
+msgid "warning: Tcl does not support encoding '%s'."
+msgstr "varning: Tcl stöder inte teckenkodningen â€%sâ€."
+
+#: lib/commit.tcl:158
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
"Another Git program has modified this repository since the last scan. A "
-"rescan must be performed before a merge can be performed.\n"
+"rescan must be performed before another commit can be created.\n"
"\n"
"The rescan will be automatically started now.\n"
msgstr ""
"Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n"
"\n"
"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste "
-"utföra en ny sökning innan du kan utföra en sammanslagning.\n"
+"utföra en ny sökning innan du kan göra en ny incheckning.\n"
"\n"
"Sökningen kommer att startas automatiskt nu.\n"
-#: lib/merge.tcl:45
+#: lib/commit.tcl:182
#, tcl-format
msgid ""
-"You are in the middle of a conflicted merge.\n"
-"\n"
-"File %s has merge conflicts.\n"
+"Unmerged files cannot be committed.\n"
"\n"
-"You must resolve them, stage the file, and commit to complete the current "
-"merge. Only then can you begin another merge.\n"
+"File %s has merge conflicts. You must resolve them and stage the file "
+"before committing.\n"
msgstr ""
-"Du är mitt i en sammanslagning med konflikter.\n"
-"\n"
-"Filen %s har sammanslagningskonflikter.\n"
+"Osammanslagna filer kan inte checkas in.\n"
"\n"
-"Du måste lösa dem, köa filen och checka in för att fullborda den aktuella "
-"sammanslagningen. När du gjort det kan du påbörja en ny sammanslagning.\n"
+"Filen %s har sammanslagningskonflikter. Du måste lösa dem och köa filen "
+"innan du checkar in den.\n"
-#: lib/merge.tcl:55
+#: lib/commit.tcl:190
#, tcl-format
msgid ""
-"You are in the middle of a change.\n"
-"\n"
-"File %s is modified.\n"
+"Unknown file state %s detected.\n"
"\n"
-"You should complete the current commit before starting a merge. Doing so "
-"will help you abort a failed merge, should the need arise.\n"
+"File %s cannot be committed by this program.\n"
msgstr ""
-"Du är mitt i en ändring.\n"
-"\n"
-"Filen %s har ändringar.\n"
+"Okänd filstatus %s upptäckt.\n"
"\n"
-"Du bör fullborda den aktuella incheckningen innan du påbörjar en "
-"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad "
-"sammanslagning, om det skulle vara nödvändigt.\n"
-
-#: lib/merge.tcl:108
-#, tcl-format
-msgid "%s of %s"
-msgstr "%s av %s"
-
-#: lib/merge.tcl:122
-#, tcl-format
-msgid "Merging %s and %s..."
-msgstr "Slår ihop %s och %s..."
-
-#: lib/merge.tcl:133
-msgid "Merge completed successfully."
-msgstr "Sammanslagningen avslutades framgångsrikt."
-
-#: lib/merge.tcl:135
-msgid "Merge failed. Conflict resolution is required."
-msgstr "Sammanslagningen misslyckades. Du måste lösa konflikterna."
-
-#: lib/merge.tcl:160
-#, tcl-format
-msgid "Merge Into %s"
-msgstr "Slå ihop i %s"
-
-#: lib/merge.tcl:179
-msgid "Revision To Merge"
-msgstr "Revisioner att slå ihop"
+"Filen %s kan inte checkas in av programmet.\n"
-#: lib/merge.tcl:214
+#: lib/commit.tcl:198
msgid ""
-"Cannot abort while amending.\n"
+"No changes to commit.\n"
"\n"
-"You must finish amending this commit.\n"
+"You must stage at least 1 file before you can commit.\n"
msgstr ""
-"Kan inte avbryta vid utökning.\n"
+"Inga ändringar att checka in.\n"
"\n"
-"Du måste göra dig färdig med att utöka incheckningen.\n"
+"Du måste köa åtminstone en fil innan du kan checka in.\n"
-#: lib/merge.tcl:224
+#: lib/commit.tcl:213
msgid ""
-"Abort merge?\n"
+"Please supply a commit message.\n"
"\n"
-"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n"
+"A good commit message has the following format:\n"
"\n"
-"Continue with aborting the current merge?"
+"- First line: Describe in one sentence what you did.\n"
+"- Second line: Blank\n"
+"- Remaining lines: Describe why this change is good.\n"
msgstr ""
-"Avbryt sammanslagning?\n"
+"Ange ett incheckningsmeddelande.\n"
"\n"
-"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gå "
-"förlorade.\n"
+"Ett bra incheckningsmeddelande har följande format:\n"
"\n"
-"GÃ¥ vidare med att avbryta den aktuella sammanslagningen?"
+"- Första raden: Beskriv i en mening vad du gjorde.\n"
+"- Andra raden: Tom\n"
+"- Följande rader: Beskriv varför det här är en bra ändring.\n"
+
+#: lib/commit.tcl:244
+msgid "Calling pre-commit hook..."
+msgstr "Anropar kroken före incheckning (pre-commit)..."
+
+#: lib/commit.tcl:259
+msgid "Commit declined by pre-commit hook."
+msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)."
-#: lib/merge.tcl:230
+#: lib/commit.tcl:278
msgid ""
-"Reset changes?\n"
-"\n"
-"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n"
-"\n"
-"Continue with resetting the current changes?"
+"You are about to commit on a detached head. This is a potentially dangerous "
+"thing to do because if you switch to another branch you will lose your "
+"changes and it can be difficult to retrieve them later from the reflog. You "
+"should probably cancel this commit and create a new branch to continue.\n"
+" \n"
+" Do you really want to proceed with your Commit?"
msgstr ""
-"Återställ ändringar?\n"
-"\n"
-"Om du återställer ändringarna kommer *ALLA* ej incheckade ändringar att gå "
-"förlorade.\n"
-"\n"
-"Gå vidare med att återställa de aktuella ändringarna?"
+"Du är på väg att checka in på ett frånkopplat huvud. Det kan potentiellt "
+"vara farligt, eftersom du kommer förlora dina ändringar om du växlar till en "
+"annan gren och det kan vara svårt att hämta dem senare från ref-loggen. Du "
+"bör troligen avbryta incheckningen och skapa en ny gren för att fortsätta.\n"
+" \n"
+" Vill du verkligen fortsätta checka in?"
-#: lib/merge.tcl:241
-msgid "Aborting"
-msgstr "Avbryter"
+#: lib/commit.tcl:299
+msgid "Calling commit-msg hook..."
+msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..."
-#: lib/merge.tcl:241
-msgid "files reset"
-msgstr "filer återställda"
+#: lib/commit.tcl:314
+msgid "Commit declined by commit-msg hook."
+msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)."
-#: lib/merge.tcl:269
-msgid "Abort failed."
-msgstr "Misslyckades avbryta."
+#: lib/commit.tcl:327
+msgid "Committing changes..."
+msgstr "Checkar in ändringar..."
-#: lib/merge.tcl:271
-msgid "Abort completed. Ready."
-msgstr "Avbrytning fullbordad. Redo."
+#: lib/commit.tcl:344
+msgid "write-tree failed:"
+msgstr "write-tree misslyckades:"
-#: lib/tools.tcl:75
-#, tcl-format
-msgid "Running %s requires a selected file."
-msgstr "För att starta %s måste du välja en fil."
+#: lib/commit.tcl:345 lib/commit.tcl:395 lib/commit.tcl:422
+msgid "Commit failed."
+msgstr "Incheckningen misslyckades."
-#: lib/tools.tcl:91
+#: lib/commit.tcl:362
#, tcl-format
-msgid "Are you sure you want to run %1$s on file \"%2$s\"?"
-msgstr "Är du säker på att du vill starta %1$s med filen \"%2$s\"?"
+msgid "Commit %s appears to be corrupt"
+msgstr "Incheckningen %s verkar vara trasig"
-#: lib/tools.tcl:95
-#, tcl-format
-msgid "Are you sure you want to run %s?"
-msgstr "Är du säker på att du vill starta %s?"
+#: lib/commit.tcl:367
+msgid ""
+"No changes to commit.\n"
+"\n"
+"No files were modified by this commit and it was not a merge commit.\n"
+"\n"
+"A rescan will be automatically started now.\n"
+msgstr ""
+"Inga ändringar att checka in.\n"
+"\n"
+"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n"
+"\n"
+"En sökning kommer att startas automatiskt nu.\n"
-#: lib/tools.tcl:116
-#, tcl-format
-msgid "Tool: %s"
-msgstr "Verktyg: %s"
+#: lib/commit.tcl:374
+msgid "No changes to commit."
+msgstr "Inga ändringar att checka in."
-#: lib/tools.tcl:117
-#, tcl-format
-msgid "Running: %s"
-msgstr "Exekverar: %s"
+#: lib/commit.tcl:394
+msgid "commit-tree failed:"
+msgstr "commit-tree misslyckades:"
-#: lib/tools.tcl:155
-#, tcl-format
-msgid "Tool completed successfully: %s"
-msgstr "Verktyget avslutades framgångsrikt: %s"
+#: lib/commit.tcl:421
+msgid "update-ref failed:"
+msgstr "update-ref misslyckades:"
-#: lib/tools.tcl:157
+#: lib/commit.tcl:515
#, tcl-format
-msgid "Tool failed: %s"
-msgstr "Verktyget misslyckades: %s"
+msgid "Created commit %s: %s"
+msgstr "Skapade incheckningen %s: %s"
-#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21
-msgid "Checkout Branch"
-msgstr "Checka ut gren"
+#: lib/console.tcl:59
+msgid "Working... please wait..."
+msgstr "Arbetar... vänta..."
-#: lib/branch_checkout.tcl:26
-msgid "Checkout"
-msgstr "Checka ut"
+#: lib/console.tcl:186
+msgid "Success"
+msgstr "Lyckades"
-#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69
-msgid "Options"
-msgstr "Alternativ"
+#: lib/console.tcl:200
+msgid "Error: Command Failed"
+msgstr "Fel: Kommando misslyckades"
-#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92
-msgid "Fetch Tracking Branch"
-msgstr "Hämta spårande gren"
+#: lib/database.tcl:42
+msgid "Number of loose objects"
+msgstr "Antal lösa objekt"
-#: lib/branch_checkout.tcl:47
-msgid "Detach From Local Branch"
-msgstr "Koppla bort från lokal gren"
+#: lib/database.tcl:43
+msgid "Disk space used by loose objects"
+msgstr "Diskutrymme använt av lösa objekt"
-#: lib/spellcheck.tcl:57
-msgid "Unsupported spell checker"
-msgstr "Stavningskontrollprogrammet stöds inte"
+#: lib/database.tcl:44
+msgid "Number of packed objects"
+msgstr "Antal packade objekt"
-#: lib/spellcheck.tcl:65
-msgid "Spell checking is unavailable"
-msgstr "Stavningskontroll är ej tillgänglig"
+#: lib/database.tcl:45
+msgid "Number of packs"
+msgstr "Antal paket"
-#: lib/spellcheck.tcl:68
-msgid "Invalid spell checking configuration"
-msgstr "Ogiltig inställning för stavningskontroll"
+#: lib/database.tcl:46
+msgid "Disk space used by packed objects"
+msgstr "Diskutrymme använt av packade objekt"
-#: lib/spellcheck.tcl:70
-#, tcl-format
-msgid "Reverting dictionary to %s."
-msgstr "Återställer ordlistan till %s."
+#: lib/database.tcl:47
+msgid "Packed objects waiting for pruning"
+msgstr "Packade objekt som väntar på städning"
-#: lib/spellcheck.tcl:73
-msgid "Spell checker silently failed on startup"
-msgstr "Stavningskontroll misslyckades tyst vid start"
+#: lib/database.tcl:48
+msgid "Garbage files"
+msgstr "Skräpfiler"
-#: lib/spellcheck.tcl:80
-msgid "Unrecognized spell checker"
-msgstr "Stavningskontrollprogrammet känns inte igen"
+#: lib/database.tcl:57 lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220
+#: lib/option.tcl:282
+#, tcl-format
+msgid "%s:"
+msgstr "%s:"
-#: lib/spellcheck.tcl:186
-msgid "No Suggestions"
-msgstr "Inga förslag"
+#: lib/database.tcl:66
+#, tcl-format
+msgid "%s (%s): Database Statistics"
+msgstr "%s (%s): Databasstatistik"
-#: lib/spellcheck.tcl:388
-msgid "Unexpected EOF from spell checker"
-msgstr "Oväntat filslut från stavningskontroll"
+#: lib/database.tcl:72
+msgid "Compressing the object database"
+msgstr "Komprimerar objektdatabasen"
-#: lib/spellcheck.tcl:392
-msgid "Spell Checker Failed"
-msgstr "Stavningskontroll misslyckades"
+#: lib/database.tcl:83
+msgid "Verifying the object database with fsck-objects"
+msgstr "Verifierar objektdatabasen med fsck-objects"
-#: lib/status_bar.tcl:87
+#: lib/database.tcl:107
#, tcl-format
-msgid "%s ... %*i of %*i %s (%3i%%)"
-msgstr "%s... %*i av %*i %s (%3i%%)"
+msgid ""
+"This repository currently has approximately %i loose objects.\n"
+"\n"
+"To maintain optimal performance it is strongly recommended that you compress "
+"the database.\n"
+"\n"
+"Compress the database now?"
+msgstr ""
+"Arkivet har för närvarande omkring %i lösa objekt.\n"
+"\n"
+"För att bibehålla optimal prestanda rekommenderas det å det bestämdaste att "
+"du komprimerar databasen.\n"
+"\n"
+"Komprimera databasen nu?"
+
+#: lib/date.tcl:25
+#, tcl-format
+msgid "Invalid date from Git: %s"
+msgstr "Ogiltigt datum från Git: %s"
#: lib/diff.tcl:77
#, tcl-format
@@ -1252,7 +1662,7 @@ msgstr ""
msgid "Loading diff of %s..."
msgstr "Läser differens för %s..."
-#: lib/diff.tcl:140
+#: lib/diff.tcl:143
msgid ""
"LOCAL: deleted\n"
"REMOTE:\n"
@@ -1260,7 +1670,7 @@ msgstr ""
"LOKAL: borttagen\n"
"FJÄRR:\n"
-#: lib/diff.tcl:145
+#: lib/diff.tcl:148
msgid ""
"REMOTE: deleted\n"
"LOCAL:\n"
@@ -1268,32 +1678,32 @@ msgstr ""
"FJÄRR: borttagen\n"
"LOKAL:\n"
-#: lib/diff.tcl:152
+#: lib/diff.tcl:155
msgid "LOCAL:\n"
msgstr "LOKAL:\n"
-#: lib/diff.tcl:155
+#: lib/diff.tcl:158
msgid "REMOTE:\n"
msgstr "FJÄRR:\n"
-#: lib/diff.tcl:217 lib/diff.tcl:355
+#: lib/diff.tcl:220 lib/diff.tcl:344
#, tcl-format
msgid "Unable to display %s"
msgstr "Kan inte visa %s"
-#: lib/diff.tcl:218
+#: lib/diff.tcl:221
msgid "Error loading file:"
msgstr "Fel vid läsning av fil:"
-#: lib/diff.tcl:225
+#: lib/diff.tcl:227
msgid "Git Repository (subproject)"
msgstr "Gitarkiv (underprojekt)"
-#: lib/diff.tcl:237
+#: lib/diff.tcl:239
msgid "* Binary file (not showing content)."
msgstr "* Binärfil (visar inte innehållet)."
-#: lib/diff.tcl:242
+#: lib/diff.tcl:244
#, tcl-format
msgid ""
"* Untracked file is %d bytes.\n"
@@ -1302,7 +1712,7 @@ msgstr ""
"* Den ospårade filen är %d byte.\n"
"* Visar endast inledande %d byte.\n"
-#: lib/diff.tcl:248
+#: lib/diff.tcl:250
#, tcl-format
msgid ""
"\n"
@@ -1313,75 +1723,444 @@ msgstr ""
"* Den ospårade filen klipptes här av %s.\n"
"* För att se hela filen, använd ett externt redigeringsprogram.\n"
-#: lib/diff.tcl:356 lib/blame.tcl:1128
-msgid "Error loading diff:"
-msgstr "Fel vid inläsning av differens:"
-
-#: lib/diff.tcl:578
+#: lib/diff.tcl:583
msgid "Failed to unstage selected hunk."
msgstr "Kunde inte ta bort den valda delen från kön."
-#: lib/diff.tcl:585
+#: lib/diff.tcl:591
+msgid "Failed to revert selected hunk."
+msgstr "Kunde inte återställa den valda delen."
+
+#: lib/diff.tcl:594
msgid "Failed to stage selected hunk."
msgstr "Kunde inte lägga till den valda delen till kön."
-#: lib/diff.tcl:664
+#: lib/diff.tcl:687
msgid "Failed to unstage selected line."
msgstr "Kunde inte ta bort den valda raden från kön."
-#: lib/diff.tcl:672
+#: lib/diff.tcl:696
+msgid "Failed to revert selected line."
+msgstr "Kunde inte återställa den valda raden."
+
+#: lib/diff.tcl:700
msgid "Failed to stage selected line."
msgstr "Kunde inte lägga till den valda raden till kön."
-#: lib/remote.tcl:200
-msgid "Push to"
-msgstr "Sänd till"
+#: lib/diff.tcl:889
+msgid "Failed to undo last revert."
+msgstr "Kunde inte ångra den senaste återställningen."
-#: lib/remote.tcl:218
-msgid "Remove Remote"
-msgstr "Ta bort fjärrarkiv"
+#: lib/encoding.tcl:443
+msgid "Default"
+msgstr "Standard"
-#: lib/remote.tcl:223
-msgid "Prune from"
-msgstr "Ta bort från"
+#: lib/encoding.tcl:448
+#, tcl-format
+msgid "System (%s)"
+msgstr "Systemets (%s)"
-#: lib/remote.tcl:228
-msgid "Fetch from"
-msgstr "Hämta från"
+#: lib/encoding.tcl:459 lib/encoding.tcl:465
+msgid "Other"
+msgstr "Annan"
-#: lib/choose_font.tcl:41
-msgid "Select"
-msgstr "Välj"
+#: lib/error.tcl:20
+#, tcl-format
+msgid "%s: error"
+msgstr "%s: fel"
-#: lib/choose_font.tcl:55
-msgid "Font Family"
-msgstr "Teckensnittsfamilj"
+#: lib/error.tcl:36
+#, tcl-format
+msgid "%s: warning"
+msgstr "%s: varning"
-#: lib/choose_font.tcl:76
-msgid "Font Size"
-msgstr "Storlek"
+#: lib/error.tcl:80
+#, tcl-format
+msgid "%s hook failed:"
+msgstr "%s-krok misslyckades:"
-#: lib/choose_font.tcl:93
-msgid "Font Example"
-msgstr "Exempel"
+#: lib/error.tcl:96
+msgid "You must correct the above errors before committing."
+msgstr "Du måste rätta till felen ovan innan du checkar in."
-#: lib/choose_font.tcl:105
+#: lib/error.tcl:116
+#, tcl-format
+msgid "%s (%s): error"
+msgstr "%s (%s): fel"
+
+#: lib/index.tcl:6
+msgid "Unable to unlock the index."
+msgstr "Kunde inte låsa upp indexet."
+
+#: lib/index.tcl:30
+msgid "Index Error"
+msgstr "Indexfel"
+
+#: lib/index.tcl:32
msgid ""
-"This is example text.\n"
-"If you like this text, it can be your font."
+"Updating the Git index failed. A rescan will be automatically started to "
+"resynchronize git-gui."
msgstr ""
-"Detta är en exempeltext.\n"
-"Om du tycker om den här texten kan den vara ditt teckensnitt."
+"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas "
+"automatiskt för att synkronisera om git-gui."
+
+#: lib/index.tcl:43
+msgid "Continue"
+msgstr "Fortsätt"
+
+#: lib/index.tcl:46
+msgid "Unlock Index"
+msgstr "LÃ¥s upp index"
+
+#: lib/index.tcl:326
+msgid "Unstaging selected files from commit"
+msgstr "Tar bort valda filer från incheckningskön"
+
+#: lib/index.tcl:330
+#, tcl-format
+msgid "Unstaging %s from commit"
+msgstr "Tar bort %s från incheckningskön"
+
+#: lib/index.tcl:369
+msgid "Ready to commit."
+msgstr "Redo att checka in."
+
+#: lib/index.tcl:378
+msgid "Adding selected files"
+msgstr "Lägger till valda filer"
+
+#: lib/index.tcl:382
+#, tcl-format
+msgid "Adding %s"
+msgstr "Lägger till %s"
+
+#: lib/index.tcl:412
+#, tcl-format
+msgid "Stage %d untracked files?"
+msgstr "Köa %d ospårade filer?"
+
+#: lib/index.tcl:420
+msgid "Adding all changed files"
+msgstr "Lägger till alla ändrade filer"
+
+#: lib/index.tcl:503
+#, tcl-format
+msgid "Revert changes in file %s?"
+msgstr "Återställ ändringarna i filen %s?"
+
+#: lib/index.tcl:508
+#, tcl-format
+msgid "Revert changes in these %i files?"
+msgstr "Återställ ändringarna i dessa %i filer?"
+
+#: lib/index.tcl:517
+msgid "Any unstaged changes will be permanently lost by the revert."
+msgstr ""
+"Alla oköade ändringar kommer permanent gå förlorade vid återställningen."
+
+#: lib/index.tcl:520 lib/index.tcl:564
+msgid "Do Nothing"
+msgstr "Gör ingenting"
+
+#: lib/index.tcl:546
+#, tcl-format
+msgid "Delete untracked file %s?"
+msgstr "Ta bort den ospårade filen %s?"
+
+#: lib/index.tcl:551
+#, tcl-format
+msgid "Delete these %i untracked files?"
+msgstr "Ta bort dessa %i ospårade filer?"
+
+#: lib/index.tcl:561
+msgid "Files will be permanently deleted."
+msgstr "Filerna kommer tas bort permanent."
+
+#: lib/index.tcl:565
+msgid "Delete Files"
+msgstr "Ta bort filer"
+
+#: lib/index.tcl:588
+msgid "Deleting"
+msgstr "Tar bort"
+
+#: lib/index.tcl:667
+msgid "Encountered errors deleting files:\n"
+msgstr "Fel uppstod vid borttagning av filer:\n"
+
+#: lib/index.tcl:676
+#, tcl-format
+msgid "None of the %d selected files could be deleted."
+msgstr "Ingen av de %d valda filerna kunde tas bort."
+
+#: lib/index.tcl:681
+#, tcl-format
+msgid "%d of the %d selected files could not be deleted."
+msgstr "%d av de %d valda filerna kunde inte tas bort."
+
+#: lib/index.tcl:728
+msgid "Reverting selected files"
+msgstr "Återställer valda filer"
+
+#: lib/index.tcl:732
+#, tcl-format
+msgid "Reverting %s"
+msgstr "Återställer %s"
+
+#: lib/line.tcl:17
+msgid "Goto Line:"
+msgstr "GÃ¥ till rad:"
+
+#: lib/line.tcl:23
+msgid "Go"
+msgstr "GÃ¥"
+
+#: lib/merge.tcl:13
+msgid ""
+"Cannot merge while amending.\n"
+"\n"
+"You must finish amending this commit before starting any type of merge.\n"
+msgstr ""
+"Kan inte slå ihop vid utökning.\n"
+"\n"
+"Du måste göra färdig utökningen av incheckningen innan du påbörjar någon "
+"slags sammanslagning.\n"
+
+#: lib/merge.tcl:27
+msgid ""
+"Last scanned state does not match repository state.\n"
+"\n"
+"Another Git program has modified this repository since the last scan. A "
+"rescan must be performed before a merge can be performed.\n"
+"\n"
+"The rescan will be automatically started now.\n"
+msgstr ""
+"Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n"
+"\n"
+"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste "
+"utföra en ny sökning innan du kan utföra en sammanslagning.\n"
+"\n"
+"Sökningen kommer att startas automatiskt nu.\n"
+
+#: lib/merge.tcl:45
+#, tcl-format
+msgid ""
+"You are in the middle of a conflicted merge.\n"
+"\n"
+"File %s has merge conflicts.\n"
+"\n"
+"You must resolve them, stage the file, and commit to complete the current "
+"merge. Only then can you begin another merge.\n"
+msgstr ""
+"Du är mitt i en sammanslagning med konflikter.\n"
+"\n"
+"Filen %s har sammanslagningskonflikter.\n"
+"\n"
+"Du måste lösa dem, köa filen och checka in för att fullborda den aktuella "
+"sammanslagningen. När du gjort det kan du påbörja en ny sammanslagning.\n"
+
+#: lib/merge.tcl:55
+#, tcl-format
+msgid ""
+"You are in the middle of a change.\n"
+"\n"
+"File %s is modified.\n"
+"\n"
+"You should complete the current commit before starting a merge. Doing so "
+"will help you abort a failed merge, should the need arise.\n"
+msgstr ""
+"Du är mitt i en ändring.\n"
+"\n"
+"Filen %s har ändringar.\n"
+"\n"
+"Du bör fullborda den aktuella incheckningen innan du påbörjar en "
+"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad "
+"sammanslagning, om det skulle vara nödvändigt.\n"
+
+#: lib/merge.tcl:108
+#, tcl-format
+msgid "%s of %s"
+msgstr "%s av %s"
+
+#: lib/merge.tcl:126
+#, tcl-format
+msgid "Merging %s and %s..."
+msgstr "Slår ihop %s och %s..."
+
+#: lib/merge.tcl:137
+msgid "Merge completed successfully."
+msgstr "Sammanslagningen avslutades framgångsrikt."
+
+#: lib/merge.tcl:139
+msgid "Merge failed. Conflict resolution is required."
+msgstr "Sammanslagningen misslyckades. Du måste lösa konflikterna."
+
+#: lib/merge.tcl:156
+#, tcl-format
+msgid "%s (%s): Merge"
+msgstr "%s (%s): Sammanslagning"
+
+#: lib/merge.tcl:164
+#, tcl-format
+msgid "Merge Into %s"
+msgstr "Slå ihop i %s"
+
+#: lib/merge.tcl:183
+msgid "Revision To Merge"
+msgstr "Revisioner att slå ihop"
+
+#: lib/merge.tcl:218
+msgid ""
+"Cannot abort while amending.\n"
+"\n"
+"You must finish amending this commit.\n"
+msgstr ""
+"Kan inte avbryta vid utökning.\n"
+"\n"
+"Du måste göra dig färdig med att utöka incheckningen.\n"
+
+#: lib/merge.tcl:228
+msgid ""
+"Abort merge?\n"
+"\n"
+"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n"
+"\n"
+"Continue with aborting the current merge?"
+msgstr ""
+"Avbryt sammanslagning?\n"
+"\n"
+"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gå "
+"förlorade.\n"
+"\n"
+"GÃ¥ vidare med att avbryta den aktuella sammanslagningen?"
+
+#: lib/merge.tcl:234
+msgid ""
+"Reset changes?\n"
+"\n"
+"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n"
+"\n"
+"Continue with resetting the current changes?"
+msgstr ""
+"Återställ ändringar?\n"
+"\n"
+"Om du återställer ändringarna kommer *ALLA* ej incheckade ändringar att gå "
+"förlorade.\n"
+"\n"
+"Gå vidare med att återställa de aktuella ändringarna?"
+
+#: lib/merge.tcl:246
+msgid "Aborting"
+msgstr "Avbryter"
+
+#: lib/merge.tcl:247
+msgid "files reset"
+msgstr "filer återställda"
+
+#: lib/merge.tcl:277
+msgid "Abort failed."
+msgstr "Misslyckades avbryta."
+
+#: lib/merge.tcl:279
+msgid "Abort completed. Ready."
+msgstr "Avbrytning fullbordad. Redo."
+
+#: lib/mergetool.tcl:8
+msgid "Force resolution to the base version?"
+msgstr "Tvinga lösning att använda basversionen?"
+
+#: lib/mergetool.tcl:9
+msgid "Force resolution to this branch?"
+msgstr "Tvinga lösning att använda den aktuella grenen?"
+
+#: lib/mergetool.tcl:10
+msgid "Force resolution to the other branch?"
+msgstr "Tvinga lösning att använda den andra grenen?"
+
+#: lib/mergetool.tcl:14
+#, tcl-format
+msgid ""
+"Note that the diff shows only conflicting changes.\n"
+"\n"
+"%s will be overwritten.\n"
+"\n"
+"This operation can be undone only by restarting the merge."
+msgstr ""
+"Observera att diffen endast visar de ändringar som står i konflikt.\n"
+"\n"
+"%s kommer att skrivas över.\n"
+"\n"
+"Du måste starta om sammanslagningen för att göra den här operationen ogjord."
+
+#: lib/mergetool.tcl:45
+#, tcl-format
+msgid "File %s seems to have unresolved conflicts, still stage?"
+msgstr "Filen %s verkar innehålla olösta konflikter. Vill du köa ändå?"
+
+#: lib/mergetool.tcl:60
+#, tcl-format
+msgid "Adding resolution for %s"
+msgstr "Lägger till lösning för %s"
+
+#: lib/mergetool.tcl:141
+msgid "Cannot resolve deletion or link conflicts using a tool"
+msgstr "Kan inte lösa borttagnings- eller länkkonflikter med ett verktyg"
+
+#: lib/mergetool.tcl:146
+msgid "Conflict file does not exist"
+msgstr "Konfliktfil existerar inte"
+
+#: lib/mergetool.tcl:246
+#, tcl-format
+msgid "Not a GUI merge tool: '%s'"
+msgstr "Inte ett grafiskt verktyg för sammanslagning: %s"
+
+#: lib/mergetool.tcl:275
+#, tcl-format
+msgid "Unsupported merge tool '%s'"
+msgstr "Verktyget â€%s†för sammanslagning stöds inte"
+
+#: lib/mergetool.tcl:310
+msgid "Merge tool is already running, terminate it?"
+msgstr "Verktyget för sammanslagning körs redan. Vill du avsluta det?"
+
+#: lib/mergetool.tcl:330
+#, tcl-format
+msgid ""
+"Error retrieving versions:\n"
+"%s"
+msgstr ""
+"Fel vid hämtning av versioner:\n"
+"%s"
+
+#: lib/mergetool.tcl:350
+#, tcl-format
+msgid ""
+"Could not start the merge tool:\n"
+"\n"
+"%s"
+msgstr ""
+"Kunde inte starta verktyg för sammanslagning:\n"
+"\n"
+"%s"
+
+#: lib/mergetool.tcl:354
+msgid "Running merge tool..."
+msgstr "Kör verktyg för sammanslagning..."
+
+#: lib/mergetool.tcl:382 lib/mergetool.tcl:390
+msgid "Merge tool failed."
+msgstr "Verktyget för sammanslagning misslyckades."
#: lib/option.tcl:11
#, tcl-format
msgid "Invalid global encoding '%s'"
-msgstr "Den globala teckenkodningen \"%s\" är ogiltig"
+msgstr "Den globala teckenkodningen â€%s†är ogiltig"
#: lib/option.tcl:19
#, tcl-format
msgid "Invalid repo encoding '%s'"
-msgstr "Arkivets teckenkodning \"%s\" är ogiltig"
+msgstr "Arkivets teckenkodning â€%s†är ogiltig"
#: lib/option.tcl:119
msgid "Restore Defaults"
@@ -1521,239 +2300,89 @@ msgstr "Inställningar"
msgid "Failed to completely save options:"
msgstr "Misslyckades med att helt spara alternativ:"
-#: lib/mergetool.tcl:8
-msgid "Force resolution to the base version?"
-msgstr "Tvinga lösning att använda basversionen?"
-
-#: lib/mergetool.tcl:9
-msgid "Force resolution to this branch?"
-msgstr "Tvinga lösning att använda den aktuella grenen?"
+#: lib/remote_add.tcl:20
+#, tcl-format
+msgid "%s (%s): Add Remote"
+msgstr "%s (%s): Lägg till fjärrarkiv"
-#: lib/mergetool.tcl:10
-msgid "Force resolution to the other branch?"
-msgstr "Tvinga lösning att använda den andra grenen?"
+#: lib/remote_add.tcl:25
+msgid "Add New Remote"
+msgstr "Lägg till nytt fjärrarkiv"
-#: lib/mergetool.tcl:14
-#, tcl-format
-msgid ""
-"Note that the diff shows only conflicting changes.\n"
-"\n"
-"%s will be overwritten.\n"
-"\n"
-"This operation can be undone only by restarting the merge."
-msgstr ""
-"Observera att diffen endast visar de ändringar som står i konflikt.\n"
-"\n"
-"%s kommer att skrivas över.\n"
-"\n"
-"Du måste starta om sammanslagningen för att göra den här operationen ogjord."
+#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37
+msgid "Add"
+msgstr "Lägg till"
-#: lib/mergetool.tcl:45
-#, tcl-format
-msgid "File %s seems to have unresolved conflicts, still stage?"
-msgstr "Filen %s verkar innehålla olösta konflikter. Vill du köa ändå?"
+#: lib/remote_add.tcl:39
+msgid "Remote Details"
+msgstr "Detaljer för fjärrarkiv"
-#: lib/mergetool.tcl:60
-#, tcl-format
-msgid "Adding resolution for %s"
-msgstr "Lägger till lösning för %s"
+#: lib/remote_add.tcl:50
+msgid "Location:"
+msgstr "Plats:"
-#: lib/mergetool.tcl:141
-msgid "Cannot resolve deletion or link conflicts using a tool"
-msgstr "Kan inte lösa borttagnings- eller länkkonflikter med ett verktyg"
+#: lib/remote_add.tcl:60
+msgid "Further Action"
+msgstr "Ytterligare åtgärd"
-#: lib/mergetool.tcl:146
-msgid "Conflict file does not exist"
-msgstr "Konfliktfil existerar inte"
+#: lib/remote_add.tcl:63
+msgid "Fetch Immediately"
+msgstr "Hämta omedelbart"
-#: lib/mergetool.tcl:246
-#, tcl-format
-msgid "Not a GUI merge tool: '%s'"
-msgstr "Inte ett grafiskt verktyg för sammanslagning: %s"
+#: lib/remote_add.tcl:69
+msgid "Initialize Remote Repository and Push"
+msgstr "Initiera fjärrarkiv och sänd till"
-#: lib/mergetool.tcl:275
-#, tcl-format
-msgid "Unsupported merge tool '%s'"
-msgstr "Verktyget \"%s\" för sammanslagning stöds inte"
+#: lib/remote_add.tcl:75
+msgid "Do Nothing Else Now"
+msgstr "Gör ingent mer nu"
-#: lib/mergetool.tcl:310
-msgid "Merge tool is already running, terminate it?"
-msgstr "Verktyget för sammanslagning körs redan. Vill du avsluta det?"
+#: lib/remote_add.tcl:100
+msgid "Please supply a remote name."
+msgstr "Ange ett namn för fjärrarkivet."
-#: lib/mergetool.tcl:330
+#: lib/remote_add.tcl:113
#, tcl-format
-msgid ""
-"Error retrieving versions:\n"
-"%s"
-msgstr ""
-"Fel vid hämtning av versioner:\n"
-"%s"
+msgid "'%s' is not an acceptable remote name."
+msgstr "â€%s†kan inte användas som namn pÃ¥ fjärrarkivet."
-#: lib/mergetool.tcl:350
+#: lib/remote_add.tcl:124
#, tcl-format
-msgid ""
-"Could not start the merge tool:\n"
-"\n"
-"%s"
-msgstr ""
-"Kunde inte starta verktyg för sammanslagning:\n"
-"\n"
-"%s"
-
-#: lib/mergetool.tcl:354
-msgid "Running merge tool..."
-msgstr "Kör verktyg för sammanslagning..."
-
-#: lib/mergetool.tcl:382 lib/mergetool.tcl:390
-msgid "Merge tool failed."
-msgstr "Verktyget för sammanslagning misslyckades."
-
-#: lib/tools_dlg.tcl:22
-msgid "Add Tool"
-msgstr "Lägg till verktyg"
-
-#: lib/tools_dlg.tcl:28
-msgid "Add New Tool Command"
-msgstr "Lägg till nytt verktygskommando"
-
-#: lib/tools_dlg.tcl:34
-msgid "Add globally"
-msgstr "Lägg till globalt"
-
-#: lib/tools_dlg.tcl:46
-msgid "Tool Details"
-msgstr "Detaljer för verktyg"
-
-#: lib/tools_dlg.tcl:49
-msgid "Use '/' separators to create a submenu tree:"
-msgstr "Använd \"/\"-avdelare för att skapa ett undermenyträd:"
-
-#: lib/tools_dlg.tcl:60
-msgid "Command:"
-msgstr "Kommando:"
-
-#: lib/tools_dlg.tcl:71
-msgid "Show a dialog before running"
-msgstr "Visa dialog innan programmet startas"
-
-#: lib/tools_dlg.tcl:77
-msgid "Ask the user to select a revision (sets $REVISION)"
-msgstr "Be användaren välja en version (sätter $REVISION)"
-
-#: lib/tools_dlg.tcl:82
-msgid "Ask the user for additional arguments (sets $ARGS)"
-msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)"
-
-#: lib/tools_dlg.tcl:89
-msgid "Don't show the command output window"
-msgstr "Visa inte kommandots utdatafönster"
-
-#: lib/tools_dlg.tcl:94
-msgid "Run only if a diff is selected ($FILENAME not empty)"
-msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)"
-
-#: lib/tools_dlg.tcl:118
-msgid "Please supply a name for the tool."
-msgstr "Ange ett namn för verktyget."
+msgid "Failed to add remote '%s' of location '%s'."
+msgstr "Kunde inte lägga till fjärrarkivet â€%s†pÃ¥ platsen â€%sâ€."
-#: lib/tools_dlg.tcl:126
+#: lib/remote_add.tcl:132 lib/transport.tcl:6
#, tcl-format
-msgid "Tool '%s' already exists."
-msgstr "Verktyget \"%s\" finns redan."
+msgid "fetch %s"
+msgstr "hämta %s"
-#: lib/tools_dlg.tcl:148
+#: lib/remote_add.tcl:133
#, tcl-format
-msgid ""
-"Could not add tool:\n"
-"%s"
-msgstr ""
-"Kunde inte lägga till verktyget:\n"
-"%s"
-
-#: lib/tools_dlg.tcl:187
-msgid "Remove Tool"
-msgstr "Ta bort verktyg"
-
-#: lib/tools_dlg.tcl:193
-msgid "Remove Tool Commands"
-msgstr "Ta bort verktygskommandon"
-
-#: lib/tools_dlg.tcl:198
-msgid "Remove"
-msgstr "Ta bort"
-
-#: lib/tools_dlg.tcl:231
-msgid "(Blue denotes repository-local tools)"
-msgstr "(Blått anger verktyg lokala för arkivet)"
+msgid "Fetching the %s"
+msgstr "Hämtar %s"
-#: lib/tools_dlg.tcl:292
+#: lib/remote_add.tcl:156
#, tcl-format
-msgid "Run Command: %s"
-msgstr "Kör kommandot: %s"
-
-#: lib/tools_dlg.tcl:306
-msgid "Arguments"
-msgstr "Argument"
-
-#: lib/tools_dlg.tcl:341
-msgid "OK"
-msgstr "OK"
-
-#: lib/search.tcl:48
-msgid "Find:"
-msgstr "Sök:"
-
-#: lib/search.tcl:50
-msgid "Next"
-msgstr "Nästa"
-
-#: lib/search.tcl:51
-msgid "Prev"
-msgstr "Föreg"
-
-#: lib/search.tcl:52
-msgid "RegExp"
-msgstr "Reg.uttr."
-
-#: lib/search.tcl:54
-msgid "Case"
-msgstr "Skiftläge"
-
-#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23
-msgid "Rename Branch"
-msgstr "Byt namn på gren"
-
-#: lib/branch_rename.tcl:28
-msgid "Rename"
-msgstr "Byt namn"
-
-#: lib/branch_rename.tcl:38
-msgid "Branch:"
-msgstr "Gren:"
-
-#: lib/branch_rename.tcl:46
-msgid "New Name:"
-msgstr "Nytt namn:"
-
-#: lib/branch_rename.tcl:81
-msgid "Please select a branch to rename."
-msgstr "Välj en gren att byta namn på."
+msgid "Do not know how to initialize repository at location '%s'."
+msgstr "Vet inte hur arkivet pÃ¥ platsen â€%s†skall initieras."
-#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154
-msgid "Please supply a branch name."
-msgstr "Ange ett namn för grenen."
+#: lib/remote_add.tcl:162 lib/transport.tcl:54 lib/transport.tcl:92
+#: lib/transport.tcl:110
+#, tcl-format
+msgid "push %s"
+msgstr "sänd %s"
-#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165
+#: lib/remote_add.tcl:163
#, tcl-format
-msgid "'%s' is not an acceptable branch name."
-msgstr "\"%s\" kan inte användas som namn på grenen."
+msgid "Setting up the %s (at %s)"
+msgstr "Konfigurerar %s (på %s)"
-#: lib/branch_rename.tcl:123
+#: lib/remote_branch_delete.tcl:29
#, tcl-format
-msgid "Failed to rename '%s'."
-msgstr "Kunde inte byta namn på \"%s\"."
+msgid "%s (%s): Delete Branch Remotely"
+msgstr "%s (%s): Ta bort gren från fjärrarkiv"
-#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
+#: lib/remote_branch_delete.tcl:34
msgid "Delete Branch Remotely"
msgstr "Ta bort gren från fjärrarkiv"
@@ -1761,6 +2390,14 @@ msgstr "Ta bort gren från fjärrarkiv"
msgid "From Repository"
msgstr "Från arkiv"
+#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:165
+msgid "Remote:"
+msgstr "Fjärrarkiv:"
+
+#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:187
+msgid "Arbitrary Location:"
+msgstr "Godtycklig plats:"
+
#: lib/remote_branch_delete.tcl:88
msgid "Branches"
msgstr "Grenar"
@@ -1773,13 +2410,9 @@ msgstr "Ta endast bort om"
msgid "Merged Into:"
msgstr "Sammanslagen i:"
-#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53
-msgid "Always (Do not perform merge checks)"
-msgstr "Alltid (utför inte sammanslagningstest)"
-
#: lib/remote_branch_delete.tcl:153
msgid "A branch is required for 'Merged Into'."
-msgstr "En gren krävs för \"Sammanslagen i\"."
+msgstr "En gren krävs för â€Sammanslagen iâ€."
#: lib/remote_branch_delete.tcl:185
#, tcl-format
@@ -1805,16 +2438,6 @@ msgstr ""
msgid "Please select one or more branches to delete."
msgstr "Välj en eller flera grenar att ta bort."
-#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115
-msgid ""
-"Recovering deleted branches is difficult.\n"
-"\n"
-"Delete the selected branches?"
-msgstr ""
-"Det kan vara svårt att återställa borttagna grenar.\n"
-"\n"
-"Ta bort de valda grenarna?"
-
#: lib/remote_branch_delete.tcl:227
#, tcl-format
msgid "Deleting branches from %s"
@@ -1829,384 +2452,122 @@ msgstr "Inget arkiv markerat."
msgid "Scanning %s..."
msgstr "Söker %s..."
-#: lib/choose_repository.tcl:33
-msgid "Git Gui"
-msgstr "Git Gui"
-
-#: lib/choose_repository.tcl:92 lib/choose_repository.tcl:412
-msgid "Create New Repository"
-msgstr "Skapa nytt arkiv"
-
-#: lib/choose_repository.tcl:98
-msgid "New..."
-msgstr "Nytt..."
-
-#: lib/choose_repository.tcl:105 lib/choose_repository.tcl:496
-msgid "Clone Existing Repository"
-msgstr "Klona befintligt arkiv"
-
-#: lib/choose_repository.tcl:116
-msgid "Clone..."
-msgstr "Klona..."
-
-#: lib/choose_repository.tcl:123 lib/choose_repository.tcl:1064
-msgid "Open Existing Repository"
-msgstr "Öppna befintligt arkiv"
-
-#: lib/choose_repository.tcl:129
-msgid "Open..."
-msgstr "Öppna..."
-
-#: lib/choose_repository.tcl:142
-msgid "Recent Repositories"
-msgstr "Senaste arkiven"
-
-#: lib/choose_repository.tcl:148
-msgid "Open Recent Repository:"
-msgstr "Öppna tidigare arkiv:"
-
-#: lib/choose_repository.tcl:316 lib/choose_repository.tcl:323
-#: lib/choose_repository.tcl:330
-#, tcl-format
-msgid "Failed to create repository %s:"
-msgstr "Kunde inte skapa arkivet %s:"
-
-#: lib/choose_repository.tcl:407 lib/branch_create.tcl:33
-msgid "Create"
-msgstr "Skapa"
-
-#: lib/choose_repository.tcl:417
-msgid "Directory:"
-msgstr "Katalog:"
-
-#: lib/choose_repository.tcl:447 lib/choose_repository.tcl:573
-#: lib/choose_repository.tcl:1098
-msgid "Git Repository"
-msgstr "Gitarkiv"
-
-#: lib/choose_repository.tcl:472
-#, tcl-format
-msgid "Directory %s already exists."
-msgstr "Katalogen %s finns redan."
-
-#: lib/choose_repository.tcl:476
-#, tcl-format
-msgid "File %s already exists."
-msgstr "Filen %s finns redan."
-
-#: lib/choose_repository.tcl:491
-msgid "Clone"
-msgstr "Klona"
-
-#: lib/choose_repository.tcl:504
-msgid "Source Location:"
-msgstr "Plats för källkod:"
-
-#: lib/choose_repository.tcl:513
-msgid "Target Directory:"
-msgstr "MÃ¥lkatalog:"
-
-#: lib/choose_repository.tcl:523
-msgid "Clone Type:"
-msgstr "Typ av klon:"
-
-#: lib/choose_repository.tcl:528
-msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
-msgstr "Standard (snabb, semiredundant, hårda länkar)"
-
-#: lib/choose_repository.tcl:533
-msgid "Full Copy (Slower, Redundant Backup)"
-msgstr "Full kopia (långsammare, redundant säkerhetskopia)"
-
-#: lib/choose_repository.tcl:538
-msgid "Shared (Fastest, Not Recommended, No Backup)"
-msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)"
-
-#: lib/choose_repository.tcl:545
-msgid "Recursively clone submodules too"
-msgstr "Klona även rekursivt undermoduler"
-
-#: lib/choose_repository.tcl:579 lib/choose_repository.tcl:626
-#: lib/choose_repository.tcl:772 lib/choose_repository.tcl:842
-#: lib/choose_repository.tcl:1104 lib/choose_repository.tcl:1112
-#, tcl-format
-msgid "Not a Git repository: %s"
-msgstr "Inte ett Gitarkiv: %s"
-
-#: lib/choose_repository.tcl:615
-msgid "Standard only available for local repository."
-msgstr "Standard är endast tillgängligt för lokala arkiv."
-
-#: lib/choose_repository.tcl:619
-msgid "Shared only available for local repository."
-msgstr "Delat är endast tillgängligt för lokala arkiv."
-
-#: lib/choose_repository.tcl:640
-#, tcl-format
-msgid "Location %s already exists."
-msgstr "Platsen %s finns redan."
-
-#: lib/choose_repository.tcl:651
-msgid "Failed to configure origin"
-msgstr "Kunde inte konfigurera ursprung"
-
-#: lib/choose_repository.tcl:663
-msgid "Counting objects"
-msgstr "Räknar objekt"
-
-#: lib/choose_repository.tcl:664
-msgid "buckets"
-msgstr "hinkar"
-
-#: lib/choose_repository.tcl:688
-#, tcl-format
-msgid "Unable to copy objects/info/alternates: %s"
-msgstr "Kunde inte kopiera objekt/info/alternativ: %s"
-
-#: lib/choose_repository.tcl:724
-#, tcl-format
-msgid "Nothing to clone from %s."
-msgstr "Ingenting att klona från %s."
-
-#: lib/choose_repository.tcl:726 lib/choose_repository.tcl:940
-#: lib/choose_repository.tcl:952
-msgid "The 'master' branch has not been initialized."
-msgstr "Grenen \"master\" har inte initierats."
-
-#: lib/choose_repository.tcl:739
-msgid "Hardlinks are unavailable. Falling back to copying."
-msgstr "Hårda länkar är inte tillgängliga. Faller tillbaka på kopiering."
-
-#: lib/choose_repository.tcl:751
-#, tcl-format
-msgid "Cloning from %s"
-msgstr "Klonar från %s"
-
-#: lib/choose_repository.tcl:782
-msgid "Copying objects"
-msgstr "Kopierar objekt"
-
-#: lib/choose_repository.tcl:783
-msgid "KiB"
-msgstr "KiB"
-
-#: lib/choose_repository.tcl:807
-#, tcl-format
-msgid "Unable to copy object: %s"
-msgstr "Kunde inte kopiera objekt: %s"
-
-#: lib/choose_repository.tcl:817
-msgid "Linking objects"
-msgstr "Länkar objekt"
-
-#: lib/choose_repository.tcl:818
-msgid "objects"
-msgstr "objekt"
-
-#: lib/choose_repository.tcl:826
-#, tcl-format
-msgid "Unable to hardlink object: %s"
-msgstr "Kunde inte hårdlänka objekt: %s"
-
-#: lib/choose_repository.tcl:881
-msgid "Cannot fetch branches and objects. See console output for details."
-msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer."
-
-#: lib/choose_repository.tcl:892
-msgid "Cannot fetch tags. See console output for details."
-msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer."
-
-#: lib/choose_repository.tcl:916
-msgid "Cannot determine HEAD. See console output for details."
-msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer."
-
-#: lib/choose_repository.tcl:925
-#, tcl-format
-msgid "Unable to cleanup %s"
-msgstr "Kunde inte städa upp %s"
-
-#: lib/choose_repository.tcl:931
-msgid "Clone failed."
-msgstr "Kloning misslyckades."
+#: lib/remote.tcl:200
+msgid "Push to"
+msgstr "Sänd till"
-#: lib/choose_repository.tcl:938
-msgid "No default branch obtained."
-msgstr "Hämtade ingen standardgren."
+#: lib/remote.tcl:218
+msgid "Remove Remote"
+msgstr "Ta bort fjärrarkiv"
-#: lib/choose_repository.tcl:949
-#, tcl-format
-msgid "Cannot resolve %s as a commit."
-msgstr "Kunde inte slå upp %s till någon incheckning."
+#: lib/remote.tcl:223
+msgid "Prune from"
+msgstr "Ta bort från"
-#: lib/choose_repository.tcl:961
-msgid "Creating working directory"
-msgstr "Skapar arbetskatalog"
+#: lib/remote.tcl:228
+msgid "Fetch from"
+msgstr "Hämta från"
-#: lib/choose_repository.tcl:962 lib/index.tcl:70 lib/index.tcl:136
-#: lib/index.tcl:207
-msgid "files"
-msgstr "filer"
+#: lib/remote.tcl:249 lib/remote.tcl:253 lib/remote.tcl:258 lib/remote.tcl:264
+msgid "All"
+msgstr "Alla"
-#: lib/choose_repository.tcl:981
-msgid "Cannot clone submodules."
-msgstr "Kan inte klona undermoduler."
+#: lib/search.tcl:48
+msgid "Find:"
+msgstr "Sök:"
-#: lib/choose_repository.tcl:990
-msgid "Cloning submodules"
-msgstr "Klonar undermoduler"
+#: lib/search.tcl:50
+msgid "Next"
+msgstr "Nästa"
-#: lib/choose_repository.tcl:1015
-msgid "Initial file checkout failed."
-msgstr "Inledande filutcheckning misslyckades."
+#: lib/search.tcl:51
+msgid "Prev"
+msgstr "Föreg"
-#: lib/choose_repository.tcl:1059
-msgid "Open"
-msgstr "Öppna"
+#: lib/search.tcl:52
+msgid "RegExp"
+msgstr "Reg.uttr."
-#: lib/choose_repository.tcl:1069
-msgid "Repository:"
-msgstr "Arkiv:"
+#: lib/search.tcl:54
+msgid "Case"
+msgstr "Skiftläge"
-#: lib/choose_repository.tcl:1118
+#: lib/shortcut.tcl:8 lib/shortcut.tcl:40 lib/shortcut.tcl:72
#, tcl-format
-msgid "Failed to open repository %s:"
-msgstr "Kunde inte öppna arkivet %s:"
-
-#: lib/about.tcl:26
-msgid "git-gui - a graphical user interface for Git."
-msgstr "git-gui - ett grafiskt användargränssnitt för Git."
-
-#: lib/blame.tcl:73
-msgid "File Viewer"
-msgstr "Filvisare"
-
-#: lib/blame.tcl:79
-msgid "Commit:"
-msgstr "Incheckning:"
-
-#: lib/blame.tcl:280
-msgid "Copy Commit"
-msgstr "Kopiera incheckning"
+msgid "%s (%s): Create Desktop Icon"
+msgstr "%s (%s): Skapa skrivbordsikon"
-#: lib/blame.tcl:284
-msgid "Find Text..."
-msgstr "Sök text..."
+#: lib/shortcut.tcl:24 lib/shortcut.tcl:62
+msgid "Cannot write shortcut:"
+msgstr "Kan inte skriva genväg:"
-#: lib/blame.tcl:288
-msgid "Goto Line..."
-msgstr "GÃ¥ till rad..."
+#: lib/shortcut.tcl:137
+msgid "Cannot write icon:"
+msgstr "Kan inte skriva ikon:"
-#: lib/blame.tcl:297
-msgid "Do Full Copy Detection"
-msgstr "Gör full kopieringsigenkänning"
+#: lib/spellcheck.tcl:57
+msgid "Unsupported spell checker"
+msgstr "Stavningskontrollprogrammet stöds inte"
-#: lib/blame.tcl:301
-msgid "Show History Context"
-msgstr "Visa historiksammanhang"
+#: lib/spellcheck.tcl:65
+msgid "Spell checking is unavailable"
+msgstr "Stavningskontroll är ej tillgänglig"
-#: lib/blame.tcl:304
-msgid "Blame Parent Commit"
-msgstr "Klandra föräldraincheckning"
+#: lib/spellcheck.tcl:68
+msgid "Invalid spell checking configuration"
+msgstr "Ogiltig inställning för stavningskontroll"
-#: lib/blame.tcl:466
+#: lib/spellcheck.tcl:70
#, tcl-format
-msgid "Reading %s..."
-msgstr "Läser %s..."
-
-#: lib/blame.tcl:594
-msgid "Loading copy/move tracking annotations..."
-msgstr "Läser annoteringar för kopiering/flyttning..."
-
-#: lib/blame.tcl:614
-msgid "lines annotated"
-msgstr "rader annoterade"
-
-#: lib/blame.tcl:806
-msgid "Loading original location annotations..."
-msgstr "Läser in annotering av originalplacering..."
-
-#: lib/blame.tcl:809
-msgid "Annotation complete."
-msgstr "Annotering fullbordad."
-
-#: lib/blame.tcl:839
-msgid "Busy"
-msgstr "Upptagen"
-
-#: lib/blame.tcl:840
-msgid "Annotation process is already running."
-msgstr "Annoteringsprocess körs redan."
-
-#: lib/blame.tcl:879
-msgid "Running thorough copy detection..."
-msgstr "Kör grundlig kopieringsigenkänning..."
-
-#: lib/blame.tcl:947
-msgid "Loading annotation..."
-msgstr "Läser in annotering..."
-
-#: lib/blame.tcl:1000
-msgid "Author:"
-msgstr "Författare:"
-
-#: lib/blame.tcl:1004
-msgid "Committer:"
-msgstr "Incheckare:"
-
-#: lib/blame.tcl:1009
-msgid "Original File:"
-msgstr "Ursprunglig fil:"
-
-#: lib/blame.tcl:1057
-msgid "Cannot find HEAD commit:"
-msgstr "Hittar inte incheckning för HEAD:"
+msgid "Reverting dictionary to %s."
+msgstr "Återställer ordlistan till %s."
-#: lib/blame.tcl:1112
-msgid "Cannot find parent commit:"
-msgstr "Hittar inte föräldraincheckning:"
+#: lib/spellcheck.tcl:73
+msgid "Spell checker silently failed on startup"
+msgstr "Stavningskontroll misslyckades tyst vid start"
-#: lib/blame.tcl:1127
-msgid "Unable to display parent"
-msgstr "Kan inte visa förälder"
+#: lib/spellcheck.tcl:80
+msgid "Unrecognized spell checker"
+msgstr "Stavningskontrollprogrammet känns inte igen"
-#: lib/blame.tcl:1269
-msgid "Originally By:"
-msgstr "Ursprungligen av:"
+#: lib/spellcheck.tcl:186
+msgid "No Suggestions"
+msgstr "Inga förslag"
-#: lib/blame.tcl:1275
-msgid "In File:"
-msgstr "I filen:"
+#: lib/spellcheck.tcl:388
+msgid "Unexpected EOF from spell checker"
+msgstr "Oväntat filslut från stavningskontroll"
-#: lib/blame.tcl:1280
-msgid "Copied Or Moved Here By:"
-msgstr "Kopierad eller flyttad hit av:"
+#: lib/spellcheck.tcl:392
+msgid "Spell Checker Failed"
+msgstr "Stavningskontroll misslyckades"
-#: lib/sshkey.tcl:31
+#: lib/sshkey.tcl:34
msgid "No keys found."
msgstr "Inga nycklar hittades."
-#: lib/sshkey.tcl:34
+#: lib/sshkey.tcl:37
#, tcl-format
msgid "Found a public key in: %s"
msgstr "Hittade öppen nyckel i: %s"
-#: lib/sshkey.tcl:40
+#: lib/sshkey.tcl:43
msgid "Generate Key"
msgstr "Skapa nyckel"
-#: lib/sshkey.tcl:58
+#: lib/sshkey.tcl:61
msgid "Copy To Clipboard"
msgstr "Kopiera till Urklipp"
-#: lib/sshkey.tcl:72
+#: lib/sshkey.tcl:75
msgid "Your OpenSSH Public Key"
msgstr "Din öppna OpenSSH-nyckel"
-#: lib/sshkey.tcl:80
+#: lib/sshkey.tcl:83
msgid "Generating..."
msgstr "Skapar..."
-#: lib/sshkey.tcl:86
+#: lib/sshkey.tcl:89
#, tcl-format
msgid ""
"Could not start ssh-keygen:\n"
@@ -2217,520 +2578,232 @@ msgstr ""
"\n"
"%s"
-#: lib/sshkey.tcl:113
+#: lib/sshkey.tcl:116
msgid "Generation failed."
msgstr "Misslyckades med att skapa."
-#: lib/sshkey.tcl:120
+#: lib/sshkey.tcl:123
msgid "Generation succeeded, but no keys found."
msgstr "Lyckades skapa nyckeln, men hittar inte någon nyckel."
-#: lib/sshkey.tcl:123
+#: lib/sshkey.tcl:126
#, tcl-format
msgid "Your key is in: %s"
msgstr "Din nyckel finns i: %s"
-#: lib/branch_create.tcl:23
-msgid "Create Branch"
-msgstr "Skapa gren"
-
-#: lib/branch_create.tcl:28
-msgid "Create New Branch"
-msgstr "Skapa ny gren"
-
-#: lib/branch_create.tcl:42
-msgid "Branch Name"
-msgstr "Namn på gren"
-
-#: lib/branch_create.tcl:57
-msgid "Match Tracking Branch Name"
-msgstr "Använd namn på spårad gren"
-
-#: lib/branch_create.tcl:66
-msgid "Starting Revision"
-msgstr "Inledande revision"
-
-#: lib/branch_create.tcl:72
-msgid "Update Existing Branch:"
-msgstr "Uppdatera befintlig gren:"
-
-#: lib/branch_create.tcl:75
-msgid "No"
-msgstr "Nej"
-
-#: lib/branch_create.tcl:80
-msgid "Fast Forward Only"
-msgstr "Endast snabbspolning"
-
-#: lib/branch_create.tcl:97
-msgid "Checkout After Creation"
-msgstr "Checka ut när skapad"
-
-#: lib/branch_create.tcl:132
-msgid "Please select a tracking branch."
-msgstr "Välj en gren att spåra."
-
-#: lib/branch_create.tcl:141
+#: lib/status_bar.tcl:263
#, tcl-format
-msgid "Tracking branch %s is not a branch in the remote repository."
-msgstr "Den spårade grenen %s är inte en gren i fjärrarkivet."
-
-#: lib/shortcut.tcl:21 lib/shortcut.tcl:62
-msgid "Cannot write shortcut:"
-msgstr "Kan inte skriva genväg:"
-
-#: lib/shortcut.tcl:137
-msgid "Cannot write icon:"
-msgstr "Kan inte skriva ikon:"
-
-#: lib/choose_rev.tcl:52
-msgid "This Detached Checkout"
-msgstr "Denna frånkopplade utcheckning"
-
-#: lib/choose_rev.tcl:60
-msgid "Revision Expression:"
-msgstr "Revisionsuttryck:"
-
-#: lib/choose_rev.tcl:72
-msgid "Local Branch"
-msgstr "Lokal gren"
-
-#: lib/choose_rev.tcl:77
-msgid "Tracking Branch"
-msgstr "Spårande gren"
-
-#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544
-msgid "Tag"
-msgstr "Tagg"
+msgid "%s ... %*i of %*i %s (%3i%%)"
+msgstr "%s... %*i av %*i %s (%3i%%)"
-#: lib/choose_rev.tcl:321
+#: lib/tools_dlg.tcl:22
#, tcl-format
-msgid "Invalid revision: %s"
-msgstr "Ogiltig revision: %s"
+msgid "%s (%s): Add Tool"
+msgstr "%s (%s): Lägg till verktyg"
-#: lib/choose_rev.tcl:342
-msgid "No revision selected."
-msgstr "Ingen revision vald."
+#: lib/tools_dlg.tcl:28
+msgid "Add New Tool Command"
+msgstr "Lägg till nytt verktygskommando"
-#: lib/choose_rev.tcl:350
-msgid "Revision expression is empty."
-msgstr "Revisionsuttrycket är tomt."
+#: lib/tools_dlg.tcl:34
+msgid "Add globally"
+msgstr "Lägg till globalt"
-#: lib/choose_rev.tcl:537
-msgid "Updated"
-msgstr "Uppdaterad"
+#: lib/tools_dlg.tcl:46
+msgid "Tool Details"
+msgstr "Detaljer för verktyg"
-#: lib/choose_rev.tcl:565
-msgid "URL"
-msgstr "Webbadress"
+#: lib/tools_dlg.tcl:49
+msgid "Use '/' separators to create a submenu tree:"
+msgstr "Använd â€/â€-avdelare för att skapa ett undermenyträd:"
-#: lib/commit.tcl:9
-msgid ""
-"There is nothing to amend.\n"
-"\n"
-"You are about to create the initial commit. There is no commit before this "
-"to amend.\n"
-msgstr ""
-"Det finns ingenting att utöka.\n"
-"\n"
-"Du håller på att skapa den inledande incheckningen. Det finns ingen tidigare "
-"incheckning att utöka.\n"
+#: lib/tools_dlg.tcl:60
+msgid "Command:"
+msgstr "Kommando:"
-#: lib/commit.tcl:18
-msgid ""
-"Cannot amend while merging.\n"
-"\n"
-"You are currently in the middle of a merge that has not been fully "
-"completed. You cannot amend the prior commit unless you first abort the "
-"current merge activity.\n"
-msgstr ""
-"Kan inte utöka vid sammanslagning.\n"
-"\n"
-"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte "
-"utöka tidigare incheckningar om du inte först avbryter den pågående "
-"sammanslagningen.\n"
+#: lib/tools_dlg.tcl:71
+msgid "Show a dialog before running"
+msgstr "Visa dialog innan programmet startas"
-#: lib/commit.tcl:48
-msgid "Error loading commit data for amend:"
-msgstr "Fel vid inläsning av incheckningsdata för utökning:"
+#: lib/tools_dlg.tcl:77
+msgid "Ask the user to select a revision (sets $REVISION)"
+msgstr "Be användaren välja en version (sätter $REVISION)"
-#: lib/commit.tcl:75
-msgid "Unable to obtain your identity:"
-msgstr "Kunde inte hämta din identitet:"
+#: lib/tools_dlg.tcl:82
+msgid "Ask the user for additional arguments (sets $ARGS)"
+msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)"
-#: lib/commit.tcl:80
-msgid "Invalid GIT_COMMITTER_IDENT:"
-msgstr "Felaktig GIT_COMMITTER_IDENT:"
+#: lib/tools_dlg.tcl:89
+msgid "Don't show the command output window"
+msgstr "Visa inte kommandots utdatafönster"
-#: lib/commit.tcl:129
-#, tcl-format
-msgid "warning: Tcl does not support encoding '%s'."
-msgstr "varning: Tcl stöder inte teckenkodningen \"%s\"."
+#: lib/tools_dlg.tcl:94
+msgid "Run only if a diff is selected ($FILENAME not empty)"
+msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)"
-#: lib/commit.tcl:149
-msgid ""
-"Last scanned state does not match repository state.\n"
-"\n"
-"Another Git program has modified this repository since the last scan. A "
-"rescan must be performed before another commit can be created.\n"
-"\n"
-"The rescan will be automatically started now.\n"
-msgstr ""
-"Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n"
-"\n"
-"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste "
-"utföra en ny sökning innan du kan göra en ny incheckning.\n"
-"\n"
-"Sökningen kommer att startas automatiskt nu.\n"
+#: lib/tools_dlg.tcl:118
+msgid "Please supply a name for the tool."
+msgstr "Ange ett namn för verktyget."
-#: lib/commit.tcl:173
+#: lib/tools_dlg.tcl:126
#, tcl-format
-msgid ""
-"Unmerged files cannot be committed.\n"
-"\n"
-"File %s has merge conflicts. You must resolve them and stage the file "
-"before committing.\n"
-msgstr ""
-"Osammanslagna filer kan inte checkas in.\n"
-"\n"
-"Filen %s har sammanslagningskonflikter. Du måste lösa dem och köa filen "
-"innan du checkar in den.\n"
+msgid "Tool '%s' already exists."
+msgstr "Verktyget â€%s†finns redan."
-#: lib/commit.tcl:181
+#: lib/tools_dlg.tcl:148
#, tcl-format
msgid ""
-"Unknown file state %s detected.\n"
-"\n"
-"File %s cannot be committed by this program.\n"
-msgstr ""
-"Okänd filstatus %s upptäckt.\n"
-"\n"
-"Filen %s kan inte checkas in av programmet.\n"
-
-#: lib/commit.tcl:189
-msgid ""
-"No changes to commit.\n"
-"\n"
-"You must stage at least 1 file before you can commit.\n"
-msgstr ""
-"Inga ändringar att checka in.\n"
-"\n"
-"Du måste köa åtminstone en fil innan du kan checka in.\n"
-
-#: lib/commit.tcl:204
-msgid ""
-"Please supply a commit message.\n"
-"\n"
-"A good commit message has the following format:\n"
-"\n"
-"- First line: Describe in one sentence what you did.\n"
-"- Second line: Blank\n"
-"- Remaining lines: Describe why this change is good.\n"
-msgstr ""
-"Ange ett incheckningsmeddelande.\n"
-"\n"
-"Ett bra incheckningsmeddelande har följande format:\n"
-"\n"
-"- Första raden: Beskriv i en mening vad du gjorde.\n"
-"- Andra raden: Tom\n"
-"- Följande rader: Beskriv varför det här är en bra ändring.\n"
-
-#: lib/commit.tcl:235
-msgid "Calling pre-commit hook..."
-msgstr "Anropar kroken före incheckning (pre-commit)..."
-
-#: lib/commit.tcl:250
-msgid "Commit declined by pre-commit hook."
-msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)."
-
-#: lib/commit.tcl:269
-msgid ""
-"You are about to commit on a detached head. This is a potentially dangerous "
-"thing to do because if you switch to another branch you will lose your "
-"changes and it can be difficult to retrieve them later from the reflog. You "
-"should probably cancel this commit and create a new branch to continue.\n"
-" \n"
-" Do you really want to proceed with your Commit?"
+"Could not add tool:\n"
+"%s"
msgstr ""
-"Du är på väg att checka in på ett frånkopplat huvud. Det kan potentiellt "
-"vara farligt, eftersom du kommer förlora dina ändringar om du växlar till en "
-"annan gren och det kan vara svårt att hämta dem senare från ref-loggen. Du "
-"bör troligen avbryta incheckningen och skapa en ny gren för att fortsätta.\n"
-" \n"
-" Vill du verkligen fortsätta checka in?"
-
-#: lib/commit.tcl:290
-msgid "Calling commit-msg hook..."
-msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..."
-
-#: lib/commit.tcl:305
-msgid "Commit declined by commit-msg hook."
-msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)."
-
-#: lib/commit.tcl:318
-msgid "Committing changes..."
-msgstr "Checkar in ändringar..."
-
-#: lib/commit.tcl:334
-msgid "write-tree failed:"
-msgstr "write-tree misslyckades:"
-
-#: lib/commit.tcl:335 lib/commit.tcl:379 lib/commit.tcl:400
-msgid "Commit failed."
-msgstr "Incheckningen misslyckades."
+"Kunde inte lägga till verktyget:\n"
+"%s"
-#: lib/commit.tcl:352
+#: lib/tools_dlg.tcl:187
#, tcl-format
-msgid "Commit %s appears to be corrupt"
-msgstr "Incheckningen %s verkar vara trasig"
+msgid "%s (%s): Remove Tool"
+msgstr "%s (%s): Ta bort verktyg"
-#: lib/commit.tcl:357
-msgid ""
-"No changes to commit.\n"
-"\n"
-"No files were modified by this commit and it was not a merge commit.\n"
-"\n"
-"A rescan will be automatically started now.\n"
-msgstr ""
-"Inga ändringar att checka in.\n"
-"\n"
-"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n"
-"\n"
-"En sökning kommer att startas automatiskt nu.\n"
-
-#: lib/commit.tcl:364
-msgid "No changes to commit."
-msgstr "Inga ändringar att checka in."
+#: lib/tools_dlg.tcl:193
+msgid "Remove Tool Commands"
+msgstr "Ta bort verktygskommandon"
-#: lib/commit.tcl:378
-msgid "commit-tree failed:"
-msgstr "commit-tree misslyckades:"
+#: lib/tools_dlg.tcl:198
+msgid "Remove"
+msgstr "Ta bort"
-#: lib/commit.tcl:399
-msgid "update-ref failed:"
-msgstr "update-ref misslyckades:"
+#: lib/tools_dlg.tcl:231
+msgid "(Blue denotes repository-local tools)"
+msgstr "(Blått anger verktyg lokala för arkivet)"
-#: lib/commit.tcl:492
+#: lib/tools_dlg.tcl:283
#, tcl-format
-msgid "Created commit %s: %s"
-msgstr "Skapade incheckningen %s: %s"
+msgid "%s (%s):"
+msgstr "%s (%s):"
-#: lib/branch_delete.tcl:16
-msgid "Delete Branch"
-msgstr "Ta bort gren"
-
-#: lib/branch_delete.tcl:21
-msgid "Delete Local Branch"
-msgstr "Ta bort lokal gren"
+#: lib/tools_dlg.tcl:292
+#, tcl-format
+msgid "Run Command: %s"
+msgstr "Kör kommandot: %s"
-#: lib/branch_delete.tcl:39
-msgid "Local Branches"
-msgstr "Lokala grenar"
+#: lib/tools_dlg.tcl:306
+msgid "Arguments"
+msgstr "Argument"
-#: lib/branch_delete.tcl:51
-msgid "Delete Only If Merged Into"
-msgstr "Ta bara bort om sammanslagen med"
+#: lib/tools_dlg.tcl:341
+msgid "OK"
+msgstr "OK"
-#: lib/branch_delete.tcl:103
+#: lib/tools.tcl:76
#, tcl-format
-msgid "The following branches are not completely merged into %s:"
-msgstr "Följande grenar är inte till fullo sammanslagna med %s:"
+msgid "Running %s requires a selected file."
+msgstr "För att starta %s måste du välja en fil."
-#: lib/branch_delete.tcl:141
+#: lib/tools.tcl:92
#, tcl-format
-msgid ""
-"Failed to delete branches:\n"
-"%s"
-msgstr ""
-"Kunde inte ta bort grenar:\n"
-"%s"
-
-#: lib/index.tcl:6
-msgid "Unable to unlock the index."
-msgstr "Kunde inte låsa upp indexet."
-
-#: lib/index.tcl:17
-msgid "Index Error"
-msgstr "Indexfel"
-
-#: lib/index.tcl:19
-msgid ""
-"Updating the Git index failed. A rescan will be automatically started to "
-"resynchronize git-gui."
-msgstr ""
-"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas "
-"automatiskt för att synkronisera om git-gui."
-
-#: lib/index.tcl:30
-msgid "Continue"
-msgstr "Fortsätt"
-
-#: lib/index.tcl:33
-msgid "Unlock Index"
-msgstr "LÃ¥s upp index"
+msgid "Are you sure you want to run %1$s on file \"%2$s\"?"
+msgstr "Är du säker pÃ¥ att du vill starta %1$s med filen â€%2$sâ€?"
-#: lib/index.tcl:298
+#: lib/tools.tcl:96
#, tcl-format
-msgid "Unstaging %s from commit"
-msgstr "Tar bort %s för incheckningskön"
-
-#: lib/index.tcl:337
-msgid "Ready to commit."
-msgstr "Redo att checka in."
+msgid "Are you sure you want to run %s?"
+msgstr "Är du säker på att du vill starta %s?"
-#: lib/index.tcl:350
+#: lib/tools.tcl:118
#, tcl-format
-msgid "Adding %s"
-msgstr "Lägger till %s"
+msgid "Tool: %s"
+msgstr "Verktyg: %s"
-#: lib/index.tcl:380
+#: lib/tools.tcl:119
#, tcl-format
-msgid "Stage %d untracked files?"
-msgstr "Köa %d ospårade filer?"
+msgid "Running: %s"
+msgstr "Exekverar: %s"
-#: lib/index.tcl:428
+#: lib/tools.tcl:158
#, tcl-format
-msgid "Revert changes in file %s?"
-msgstr "Återställ ändringarna i filen %s?"
+msgid "Tool completed successfully: %s"
+msgstr "Verktyget avslutades framgångsrikt: %s"
-#: lib/index.tcl:430
+#: lib/tools.tcl:160
#, tcl-format
-msgid "Revert changes in these %i files?"
-msgstr "Återställ ändringarna i dessa %i filer?"
-
-#: lib/index.tcl:438
-msgid "Any unstaged changes will be permanently lost by the revert."
-msgstr ""
-"Alla oköade ändringar kommer permanent gå förlorade vid återställningen."
-
-#: lib/index.tcl:441
-msgid "Do Nothing"
-msgstr "Gör ingenting"
-
-#: lib/index.tcl:459
-msgid "Reverting selected files"
-msgstr "Återställer valda filer"
+msgid "Tool failed: %s"
+msgstr "Verktyget misslyckades: %s"
-#: lib/index.tcl:463
+#: lib/transport.tcl:7
#, tcl-format
-msgid "Reverting %s"
-msgstr "Återställer %s"
-
-#: lib/encoding.tcl:443
-msgid "Default"
-msgstr "Standard"
+msgid "Fetching new changes from %s"
+msgstr "Hämtar nya ändringar från %s"
-#: lib/encoding.tcl:448
+#: lib/transport.tcl:18
#, tcl-format
-msgid "System (%s)"
-msgstr "Systemets (%s)"
-
-#: lib/encoding.tcl:459 lib/encoding.tcl:465
-msgid "Other"
-msgstr "Annan"
+msgid "remote prune %s"
+msgstr "fjärrborttagning %s"
-#: lib/date.tcl:25
+#: lib/transport.tcl:19
#, tcl-format
-msgid "Invalid date from Git: %s"
-msgstr "Ogiltigt datum från Git: %s"
-
-#: lib/database.tcl:42
-msgid "Number of loose objects"
-msgstr "Antal lösa objekt"
-
-#: lib/database.tcl:43
-msgid "Disk space used by loose objects"
-msgstr "Diskutrymme använt av lösa objekt"
-
-#: lib/database.tcl:44
-msgid "Number of packed objects"
-msgstr "Antal packade objekt"
-
-#: lib/database.tcl:45
-msgid "Number of packs"
-msgstr "Antal paket"
-
-#: lib/database.tcl:46
-msgid "Disk space used by packed objects"
-msgstr "Diskutrymme använt av packade objekt"
+msgid "Pruning tracking branches deleted from %s"
+msgstr "Tar bort spårande grenar som tagits bort från %s"
-#: lib/database.tcl:47
-msgid "Packed objects waiting for pruning"
-msgstr "Packade objekt som väntar på städning"
+#: lib/transport.tcl:25
+msgid "fetch all remotes"
+msgstr "hämta alla fjärrarkiv"
-#: lib/database.tcl:48
-msgid "Garbage files"
-msgstr "Skräpfiler"
+#: lib/transport.tcl:26
+msgid "Fetching new changes from all remotes"
+msgstr "Hämtar nya ändringar från alla fjärrarkiv"
-#: lib/database.tcl:72
-msgid "Compressing the object database"
-msgstr "Komprimerar objektdatabasen"
+#: lib/transport.tcl:40
+msgid "remote prune all remotes"
+msgstr "rensa alla fjärrarkiv"
-#: lib/database.tcl:83
-msgid "Verifying the object database with fsck-objects"
-msgstr "Verifierar objektdatabasen med fsck-objects"
+#: lib/transport.tcl:41
+msgid "Pruning tracking branches deleted from all remotes"
+msgstr "Rensar spårande grenar som tagits bort, från alla fjärrarkiv"
-#: lib/database.tcl:107
+#: lib/transport.tcl:55
#, tcl-format
-msgid ""
-"This repository currently has approximately %i loose objects.\n"
-"\n"
-"To maintain optimal performance it is strongly recommended that you compress "
-"the database.\n"
-"\n"
-"Compress the database now?"
-msgstr ""
-"Arkivet har för närvarande omkring %i lösa objekt.\n"
-"\n"
-"För att bibehålla optimal prestanda rekommenderas det å det bestämdaste att "
-"du komprimerar databasen.\n"
-"\n"
-"Komprimera databasen nu?"
-
-#: lib/error.tcl:20 lib/error.tcl:116
-msgid "error"
-msgstr "fel"
-
-#: lib/error.tcl:36
-msgid "warning"
-msgstr "varning"
-
-#: lib/error.tcl:96
-msgid "You must correct the above errors before committing."
-msgstr "Du måste rätta till felen ovan innan du checkar in."
+msgid "Pushing changes to %s"
+msgstr "Sänder ändringar till %s"
-#~ msgid "Displaying only %s of %s files."
-#~ msgstr "Visar endast %s av %s filer."
+#: lib/transport.tcl:93
+#, tcl-format
+msgid "Mirroring to %s"
+msgstr "Speglar till %s"
-#~ msgid "Case-Sensitive"
-#~ msgstr "Skilj på VERSALER/gemener"
+#: lib/transport.tcl:111
+#, tcl-format
+msgid "Pushing %s %s to %s"
+msgstr "Sänder %s %s till %s"
-#~ msgid "Cannot use funny .git directory:"
-#~ msgstr "Kan inte använda underlig .git-katalog:"
+#: lib/transport.tcl:132
+msgid "Push Branches"
+msgstr "Sänd grenar"
-#~ msgid "Preferences..."
-#~ msgstr "Inställningar..."
+#: lib/transport.tcl:147
+msgid "Source Branches"
+msgstr "Källgrenar"
-#~ msgid "Always (Do not perform merge test.)"
-#~ msgstr "Alltid (utför inte sammanslagningstest)."
+#: lib/transport.tcl:162
+msgid "Destination Repository"
+msgstr "Destinationsarkiv"
-#~ msgid "URL:"
-#~ msgstr "Webbadress:"
+#: lib/transport.tcl:205
+msgid "Transfer Options"
+msgstr "Överföringsalternativ"
-#~ msgid "Delete Remote Branch"
-#~ msgstr "Ta bort fjärrgren"
+#: lib/transport.tcl:207
+msgid "Force overwrite existing branch (may discard changes)"
+msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)"
-#~ msgid ""
-#~ "Unable to start gitk:\n"
-#~ "\n"
-#~ "%s does not exist"
-#~ msgstr ""
-#~ "Kan inte starta gitk:\n"
-#~ "\n"
-#~ "%s finns inte"
+#: lib/transport.tcl:211
+msgid "Use thin pack (for slow network connections)"
+msgstr "Använd tunt paket (för långsamma nätverksanslutningar)"
-#~ msgid "Apple"
-#~ msgstr "Äpple"
+#: lib/transport.tcl:215
+msgid "Include tags"
+msgstr "Ta med taggar"
-#~ msgid "Not connected to aspell"
-#~ msgstr "Inte ansluten till aspell"
+#: lib/transport.tcl:229
+#, tcl-format
+msgid "%s (%s): Push"
+msgstr "%s (%s): Sänd"
diff --git a/git-instaweb.sh b/git-instaweb.sh
index c68f49454c..8dbe21d588 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -432,7 +432,7 @@ mongoose_conf() {
# Mongoose web server configuration file.
# Lines starting with '#' and empty lines are ignored.
# For detailed description of every option, visit
-# http://code.google.com/p/mongoose/wiki/MongooseManual
+# https://code.google.com/p/mongoose/wiki/MongooseManual
root $root
ports $port
@@ -458,7 +458,7 @@ plackup_conf () {
#!$PERL
# gitweb - simple web interface to track changes in git repositories
-# PSGI wrapper and server starter (see http://plackperl.org)
+# PSGI wrapper and server starter (see https://plackperl.org)
use strict;
@@ -612,7 +612,7 @@ python_conf() {
ln -sf "$root/static" "$fqgitdir/gitweb/$httpd_only/"
# generate a standalone 'python http.server' script in $fqgitdir/gitweb
- # This asumes that python is in user's $PATH
+ # This assumes that python is in user's $PATH
# This script is Python 2 and 3 compatible
cat > "$fqgitdir/gitweb/gitweb.py" <<EOF
#!/usr/bin/env python
diff --git a/git-p4.py b/git-p4.py
index d26a980e5a..c0ca7becaf 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -54,7 +54,7 @@ import time
import zipfile
import zlib
-# On python2.7 where raw_input() and input() are both availble,
+# On python2.7 where raw_input() and input() are both available,
# we want raw_input's semantics, but aliased to input for python3
# compatibility
# support basestring in python3
@@ -689,8 +689,8 @@ def setP4ExecBit(file, mode):
if not isModeExec(mode):
p4Type = getP4OpenedType(file)
- p4Type = re.sub('^([cku]?)x(.*)', '\\1\\2', p4Type)
- p4Type = re.sub('(.*?\+.*?)x(.*?)', '\\1\\2', p4Type)
+ p4Type = re.sub(r'^([cku]?)x(.*)', r'\1\2', p4Type)
+ p4Type = re.sub(r'(.*?\+.*?)x(.*?)', r'\1\2', p4Type)
if p4Type[-1] == "+":
p4Type = p4Type[0:-1]
@@ -701,7 +701,7 @@ def getP4OpenedType(file):
"""Returns the perforce file type for the given file."""
result = p4_read_pipe(["opened", wildcard_encode(file)])
- match = re.match(".*\((.+)\)( \*exclusive\*)?\r?$", result)
+ match = re.match(r".*\((.+)\)( \*exclusive\*)?\r?$", result)
if match:
return match.group(1)
else:
@@ -757,7 +757,7 @@ def parseDiffTreeEntry(entry):
global _diff_tree_pattern
if not _diff_tree_pattern:
- _diff_tree_pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
+ _diff_tree_pattern = re.compile(r':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
match = _diff_tree_pattern.match(entry)
if match:
@@ -918,9 +918,9 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
if len(result) > 0:
data = result[0].get('data')
if data:
- m = re.search('Too many rows scanned \(over (\d+)\)', data)
+ m = re.search(r'Too many rows scanned \(over (\d+)\)', data)
if not m:
- m = re.search('Request too large \(over (\d+)\)', data)
+ m = re.search(r'Request too large \(over (\d+)\)', data)
if m:
limit = int(m.group(1))
@@ -1452,7 +1452,7 @@ def wildcard_encode(path):
def wildcard_present(path):
- m = re.search("[*#@%]", path)
+ m = re.search(r"[*#@%]", path)
return m is not None
@@ -1522,6 +1522,10 @@ class LargeFileSystem(object):
file is stored in the large file system and handles all necessary
steps.
"""
+ # symlinks aren't processed by smudge/clean filters
+ if git_mode == "120000":
+ return (git_mode, contents)
+
if self.exceedsLargeFileThreshold(relPath, contents) or self.hasLargeFileExtension(relPath):
contentTempFile = self.generateTempFile(contents)
pointer_git_mode, contents, localLargeFile = self.generatePointer(contentTempFile)
@@ -1800,7 +1804,7 @@ class P4Submit(Command, P4UserMap):
status from the script will abort the process.
The purpose of the hook is to edit the message file in place, and it is not
- supressed by the `--no-verify` option. This hook is called even if
+ suppressed by the `--no-verify` option. This hook is called even if
`--prepare-p4-only` is set.
The `p4-changelist` hook is executed after the changelist message has been
@@ -3044,7 +3048,7 @@ class P4Sync(Command, P4UserMap):
# Preserve everything in relative path name except leading
# //depot/; just look at first prefix as they all should
# be in the same depot.
- depot = re.sub("^(//[^/]+/).*", r'\1', prefixes[0])
+ depot = re.sub(r"^(//[^/]+/).*", r'\1', prefixes[0])
if p4PathStartsWith(path, depot):
path = path[len(depot):]
@@ -3249,17 +3253,19 @@ class P4Sync(Command, P4UserMap):
if self.stream_have_file_info:
if "depotFile" in self.stream_file:
f = self.stream_file["depotFile"]
- # force a failure in fast-import, else an empty
- # commit will be made
- self.gitStream.write("\n")
- self.gitStream.write("die-now\n")
- self.gitStream.close()
- # ignore errors, but make sure it exits first
- self.importProcess.wait()
- if f:
- die("Error from p4 print for %s: %s" % (f, err))
- else:
- die("Error from p4 print: %s" % err)
+ try:
+ # force a failure in fast-import, else an empty
+ # commit will be made
+ self.gitStream.write("\n")
+ self.gitStream.write("die-now\n")
+ self.gitStream.close()
+ # ignore errors, but make sure it exits first
+ self.importProcess.wait()
+ finally:
+ if f:
+ die("Error from p4 print for %s: %s" % (f, err))
+ else:
+ die("Error from p4 print: %s" % err)
if 'depotFile' in marshalled and self.stream_have_file_info:
# start of a new file - output the old one first
@@ -3599,7 +3605,7 @@ class P4Sync(Command, P4UserMap):
commitFound = True
else:
gitCommit = read_pipe(["git", "rev-list", "--max-count=1",
- "--reverse", ":/\[git-p4:.*change = %d\]" % changelist], ignore_error=True)
+ "--reverse", r":/\[git-p4:.*change = %d\]" % changelist], ignore_error=True)
if len(gitCommit) == 0:
print("importing label %s: could not find git commit for changelist %d" % (name, changelist))
else:
@@ -4178,7 +4184,7 @@ class P4Sync(Command, P4UserMap):
if len(self.changesFile) == 0:
revision = "#head"
- p = re.sub("\.\.\.$", "", p)
+ p = re.sub(r"\.\.\.$", "", p)
if not p.endswith("/"):
p += "/"
@@ -4247,7 +4253,8 @@ class P4Sync(Command, P4UserMap):
if self.tempBranches != []:
for branch in self.tempBranches:
read_pipe(["git", "update-ref", "-d", branch])
- os.rmdir(os.path.join(os.environ.get("GIT_DIR", ".git"), self.tempBranchLocation))
+ if len(read_pipe(["git", "for-each-ref", self.tempBranchLocation])) > 0:
+ die("There are unexpected temporary branches")
# Create a symbolic ref p4/HEAD pointing to p4/<branch> to allow
# a convenient shortcut refname "p4".
@@ -4287,7 +4294,7 @@ class P4Rebase(Command):
die("Cannot find upstream branchpoint for rebase")
# the branchpoint may be p4/foo~3, so strip off the parent
- upstream = re.sub("~[0-9]+$", "", upstream)
+ upstream = re.sub(r"~[0-9]+$", "", upstream)
print("Rebasing the current branch onto %s" % upstream)
oldHead = read_pipe(["git", "rev-parse", "HEAD"]).strip()
@@ -4316,8 +4323,8 @@ class P4Clone(P4Sync):
def defaultDestination(self, args):
# TODO: use common prefix of args?
depotPath = args[0]
- depotDir = re.sub("(@[^@]*)$", "", depotPath)
- depotDir = re.sub("(#[^#]*)$", "", depotDir)
+ depotDir = re.sub(r"(@[^@]*)$", "", depotPath)
+ depotDir = re.sub(r"(#[^#]*)$", "", depotDir)
depotDir = re.sub(r"\.\.\.$", "", depotDir)
depotDir = re.sub(r"/$", "", depotDir)
return os.path.split(depotDir)[1]
diff --git a/git-quiltimport.sh b/git-quiltimport.sh
index e3d3909743..eb34cda409 100755
--- a/git-quiltimport.sh
+++ b/git-quiltimport.sh
@@ -148,7 +148,7 @@ do
if [ -z "$dry_run" ] ; then
git apply --index -C1 ${level:+"$level"} "$tmp_patch" &&
tree=$(git write-tree) &&
- commit=$( (echo "$SUBJECT"; echo; cat "$tmp_msg") | git commit-tree $tree -p $commit) &&
+ commit=$( { echo "$SUBJECT"; echo; cat "$tmp_msg"; } | git commit-tree $tree -p $commit) &&
git update-ref -m "quiltimport: $patch_name" HEAD $commit || exit 4
fi
done 3<"$QUILT_SERIES"
diff --git a/git-send-email.perl b/git-send-email.perl
index 288ea1ae80..c835d4c11a 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -16,7 +16,7 @@
# and second line is the subject of the message.
#
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
use Getopt::Long;
@@ -28,9 +28,10 @@ Getopt::Long::Configure qw/ pass_through /;
sub usage {
print <<EOT;
-git send-email' [<options>] <file|directory>
-git send-email' [<options>] <format-patch options>
+git send-email [<options>] <file|directory>
+git send-email [<options>] <format-patch options>
git send-email --dump-aliases
+git send-email --translate-aliases
Composing:
--from <str> * Email From:
@@ -46,6 +47,8 @@ git send-email --dump-aliases
--compose-encoding <str> * Encoding to assume for introduction.
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
--transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
+ --[no-]mailmap * Use mailmap file to map all email addresses to canonical
+ real names and email addresses.
Sending:
--envelope-sender <str> * Email envelope sender.
@@ -99,6 +102,10 @@ git send-email --dump-aliases
Information:
--dump-aliases * Dump configured aliases and exit.
+ --translate-aliases * Translate aliases read from standard
+ input according to the configured email
+ alias file(s), outputting the result to
+ standard output.
EOT
exit(1);
@@ -119,13 +126,16 @@ sub completion_helper {
foreach my $key (keys %$original_opts) {
unless (exists $not_for_completion{$key}) {
- $key =~ s/!$//;
+ my $negatable = ($key =~ s/!$//);
if ($key =~ /[:=][si]$/) {
$key =~ s/[:=][si]$//;
push (@send_email_opts, "--$_=") foreach (split (/\|/, $key));
} else {
push (@send_email_opts, "--$_") foreach (split (/\|/, $key));
+ if ($negatable) {
+ push (@send_email_opts, "--no-$_") foreach (split (/\|/, $key));
+ }
}
}
}
@@ -209,6 +219,7 @@ my $format_patch;
my $compose_filename;
my $force = 0;
my $dump_aliases = 0;
+my $translate_aliases = 0;
# Variables to prevent short format-patch options from being captured
# as abbreviated send-email options
@@ -228,7 +239,7 @@ sub system_or_msg {
my @sprintf_args = ($cmd_name ? $cmd_name : $args->[0], $exit_code);
if (defined $msg) {
# Quiet the 'redundant' warning category, except we
- # need to support down to Perl 5.8, so we can't do a
+ # need to support down to Perl 5.8.1, so we can't do a
# "no warnings 'redundant'", since that category was
# introduced in perl 5.22, and asking for it will die
# on older perls.
@@ -269,12 +280,14 @@ my (@suppress_cc);
my ($auto_8bit_encoding);
my ($compose_encoding);
my ($sendmail_cmd);
+my ($mailmap_file, $mailmap_blob);
# Variables with corresponding config settings & hardcoded defaults
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
my $thread = 1;
my $chain_reply_to = 0;
my $use_xmailer = 1;
my $validate = 1;
+my $mailmap = 0;
my $target_xfer_encoding = 'auto';
my $forbid_sendmail_variables = 1;
@@ -291,6 +304,7 @@ my %config_bool_settings = (
"annotate" => \$annotate,
"xmailer" => \$use_xmailer,
"forbidsendmailvariables" => \$forbid_sendmail_variables,
+ "mailmap" => \$mailmap,
);
my %config_settings = (
@@ -324,6 +338,8 @@ my %config_settings = (
my %config_path_settings = (
"aliasesfile" => \@alias_files,
"smtpsslcertpath" => \$smtp_ssl_cert_path,
+ "mailmap.file" => \$mailmap_file,
+ "mailmap.blob" => \$mailmap_blob,
);
# Handle Uncouth Termination
@@ -473,11 +489,14 @@ my $git_completion_helper;
my %dump_aliases_options = (
"h" => \$help,
"dump-aliases" => \$dump_aliases,
+ "translate-aliases" => \$translate_aliases,
);
$rc = GetOptions(%dump_aliases_options);
usage() unless $rc;
die __("--dump-aliases incompatible with other options\n")
- if !$help and $dump_aliases and @ARGV;
+ if !$help and ($dump_aliases or $translate_aliases) and @ARGV;
+die __("--dump-aliases and --translate-aliases are mutually exclusive\n")
+ if !$help and $dump_aliases and $translate_aliases;
my %options = (
"sender|from=s" => \$sender,
"in-reply-to=s" => \$initial_in_reply_to,
@@ -491,7 +510,6 @@ my %options = (
"bcc=s" => \@getopt_bcc,
"no-bcc" => \$no_bcc,
"chain-reply-to!" => \$chain_reply_to,
- "no-chain-reply-to" => sub {$chain_reply_to = 0},
"sendmail-cmd=s" => \$sendmail_cmd,
"smtp-server=s" => \$smtp_server,
"smtp-server-option=s" => \@smtp_server_options,
@@ -506,36 +524,29 @@ my %options = (
"smtp-auth=s" => \$smtp_auth,
"no-smtp-auth" => sub {$smtp_auth = 'none'},
"annotate!" => \$annotate,
- "no-annotate" => sub {$annotate = 0},
"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,
"signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
- "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
- "cc-cover|cc-cover!" => \$cover_cc,
- "no-cc-cover" => sub {$cover_cc = 0},
- "to-cover|to-cover!" => \$cover_to,
- "no-to-cover" => sub {$cover_to = 0},
+ "cc-cover!" => \$cover_cc,
+ "to-cover!" => \$cover_to,
"confirm=s" => \$confirm,
"dry-run" => \$dry_run,
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
- "no-thread" => sub {$thread = 0},
"validate!" => \$validate,
- "no-validate" => sub {$validate = 0},
"transfer-encoding=s" => \$target_xfer_encoding,
+ "mailmap!" => \$mailmap,
+ "use-mailmap!" => \$mailmap,
"format-patch!" => \$format_patch,
- "no-format-patch" => sub {$format_patch = 0},
"8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding,
"force" => \$force,
"xmailer!" => \$use_xmailer,
- "no-xmailer" => sub {$use_xmailer = 0},
"batch-size=i" => \$batch_size,
"relogin-delay=i" => \$relogin_delay,
"git-completion-helper" => \$git_completion_helper,
@@ -731,6 +742,16 @@ if ($dump_aliases) {
exit(0);
}
+if ($translate_aliases) {
+ while (<STDIN>) {
+ my @addr_list = parse_address_line($_);
+ @addr_list = expand_aliases(@addr_list);
+ @addr_list = sanitize_address_list(@addr_list);
+ print "$_\n" for @addr_list;
+ }
+ exit(0);
+}
+
# is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
# $f is a revision list specification to be passed to format-patch.
sub is_format_patch_arg {
@@ -799,30 +820,6 @@ $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) {
- 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) {
@@ -861,6 +858,9 @@ if ($compose) {
my $tpl_subject = $initial_subject || '';
my $tpl_in_reply_to = $initial_in_reply_to || '';
my $tpl_reply_to = $reply_to || '';
+ my $tpl_to = join(',', @initial_to);
+ my $tpl_cc = join(',', @initial_cc);
+ my $tpl_bcc = join(', ', @initial_bcc);
print $c <<EOT1, Git::prefix_lines("GIT: ", __(<<EOT2)), <<EOT3;
From $tpl_sender # This line is ignored.
@@ -872,6 +872,9 @@ for the patch you are writing.
Clear the body content if you don't wish to send a summary.
EOT2
From: $tpl_sender
+To: $tpl_to
+Cc: $tpl_cc
+Bcc: $tpl_bcc
Reply-To: $tpl_reply_to
Subject: $tpl_subject
In-Reply-To: $tpl_in_reply_to
@@ -888,73 +891,65 @@ EOT3
do_edit($compose_filename);
}
+ open my $c2, ">", $compose_filename . ".final"
+ or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
+
open $c, "<", $compose_filename
or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
+ my $need_8bit_cte = file_has_nonascii($compose_filename);
+ my $in_body = 0;
+ my $summary_empty = 1;
if (!defined $compose_encoding) {
$compose_encoding = "UTF-8";
}
-
- my %parsed_email;
- while (my $line = <$c>) {
- next if $line =~ m/^GIT:/;
- parse_header_line($line, \%parsed_email);
- if ($line =~ /^$/) {
- $parsed_email{'body'} = filter_body($c);
+ while(<$c>) {
+ next if m/^GIT:/;
+ if ($in_body) {
+ $summary_empty = 0 unless (/^\n$/);
+ } elsif (/^\n$/) {
+ $in_body = 1;
+ if ($need_8bit_cte) {
+ print $c2 "MIME-Version: 1.0\n",
+ "Content-Type: text/plain; ",
+ "charset=$compose_encoding\n",
+ "Content-Transfer-Encoding: 8bit\n";
+ }
+ } elsif (/^MIME-Version:/i) {
+ $need_8bit_cte = 0;
+ } elsif (/^Subject:\s*(.+)\s*$/i) {
+ $initial_subject = $1;
+ my $subject = $initial_subject;
+ $_ = "Subject: " .
+ quote_subject($subject, $compose_encoding) .
+ "\n";
+ } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
+ $initial_in_reply_to = $1;
+ next;
+ } elsif (/^Reply-To:\s*(.+)\s*$/i) {
+ $reply_to = $1;
+ } elsif (/^From:\s*(.+)\s*$/i) {
+ $sender = $1;
+ next;
+ } elsif (/^To:\s*(.+)\s*$/i) {
+ @initial_to = parse_address_line($1);
+ next;
+ } elsif (/^Cc:\s*(.+)\s*$/i) {
+ @initial_cc = parse_address_line($1);
+ next;
+ } elsif (/^Bcc:/i) {
+ @initial_bcc = parse_address_line($1);
+ next;
}
+ print $c2 $_;
}
close $c;
+ close $c2;
- open my $c2, ">", $compose_filename . ".final"
- or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
-
-
- if ($parsed_email{'From'}) {
- $sender = delete($parsed_email{'From'});
- }
- if ($parsed_email{'In-Reply-To'}) {
- $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
- }
- if ($parsed_email{'Reply-To'}) {
- $reply_to = delete($parsed_email{'Reply-To'});
- }
- if ($parsed_email{'Subject'}) {
- $initial_subject = delete($parsed_email{'Subject'});
- print $c2 "Subject: " .
- quote_subject($initial_subject, $compose_encoding) .
- "\n";
- }
-
- if ($parsed_email{'MIME-Version'}) {
- print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
- "Content-Type: $parsed_email{'Content-Type'};\n",
- "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
- delete($parsed_email{'MIME-Version'});
- delete($parsed_email{'Content-Type'});
- delete($parsed_email{'Content-Transfer-Encoding'});
- } elsif (file_has_nonascii($compose_filename)) {
- my $content_type = (delete($parsed_email{'Content-Type'}) or
- "text/plain; charset=$compose_encoding");
- print $c2 "MIME-Version: 1.0\n",
- "Content-Type: $content_type\n",
- "Content-Transfer-Encoding: 8bit\n";
- }
- # Preserve unknown headers
- foreach my $key (keys %parsed_email) {
- next if $key eq 'body';
- print $c2 "$key: $parsed_email{$key}";
- }
-
- if ($parsed_email{'body'}) {
- print $c2 "\n$parsed_email{'body'}\n";
- delete($parsed_email{'body'});
- } else {
+ if ($summary_empty) {
print __("Summary email is empty, skipping it\n");
$compose = -1;
}
-
- close $c2;
-
} elsif ($annotate) {
do_edit(@files);
}
@@ -1009,32 +1004,6 @@ sub ask {
return;
}
-sub parse_header_line {
- my $lines = shift;
- my $parsed_line = shift;
- my $addr_pat = join "|", qw(To Cc Bcc);
-
- foreach (split(/\n/, $lines)) {
- if (/^($addr_pat):\s*(.+)$/i) {
- $parsed_line->{$1} = [ parse_address_line($2) ];
- } elsif (/^([^:]*):\s*(.+)\s*$/i) {
- $parsed_line->{$1} = $2;
- }
- }
-}
-
-sub filter_body {
- my $c = shift;
- my $body = "";
- while (my $body_line = <$c>) {
- if ($body_line !~ m/^GIT:/) {
- $body .= $body_line;
- }
- }
- return $body;
-}
-
-
my %broken_encoding;
sub file_declares_8bit_cte {
@@ -1144,6 +1113,16 @@ if ($compose && $compose > 0) {
our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
$needs_confirm, $message_num, $ask_default);
+sub mailmap_address_list {
+ return @_ unless @_ and $mailmap;
+ my @options = ();
+ push(@options, "--mailmap-file=$mailmap_file") if $mailmap_file;
+ push(@options, "--mailmap-blob=$mailmap_blob") if $mailmap_blob;
+ my @addr_list = Git::command('check-mailmap', @options, @_);
+ s/^<(.*)>$/$1/ for @addr_list;
+ return @addr_list;
+}
+
sub extract_valid_address {
my $address = shift;
my $local_part_regexp = qr/[^<>"\s@]+/;
@@ -1353,6 +1332,7 @@ sub process_address_list {
@addr_list = expand_aliases(@addr_list);
@addr_list = sanitize_address_list(@addr_list);
@addr_list = validate_address_list(@addr_list);
+ @addr_list = mailmap_address_list(@addr_list);
return @addr_list;
}
@@ -1723,9 +1703,11 @@ EOF
$smtp->code =~ /250|200/ or die sprintf(__("Failed to send %s\n"), $subject).$smtp->message;
}
if ($quiet) {
- printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
+ printf($dry_run ? __("Dry-Sent %s") : __("Sent %s"), $subject);
+ print "\n";
} else {
- print($dry_run ? __("Dry-OK. Log says:\n") : __("OK. Log says:\n"));
+ print($dry_run ? __("Dry-OK. Log says:") : __("OK. Log says:"));
+ print "\n";
if (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {
print "Server: $smtp_server\n";
print "MAIL FROM:<$raw_from>\n";
@@ -1745,19 +1727,16 @@ EOF
print $header, "\n";
if ($smtp) {
print __("Result: "), $smtp->code, ' ',
- ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
+ ($smtp->message =~ /\n([^\n]+\n)$/s);
} else {
- print __("Result: OK\n");
+ print __("Result: OK");
}
+ print "\n";
}
return 1;
}
-$in_reply_to = $initial_in_reply_to;
-$references = $initial_in_reply_to || '';
-$message_num = 0;
-
sub pre_process_file {
my ($t, $quiet) = @_;
@@ -1907,9 +1886,9 @@ sub pre_process_file {
$what, $_) unless $quiet;
next;
}
- push @cc, $c;
+ push @cc, $sc;
printf(__("(body) Adding cc: %s from line '%s'\n"),
- $c, $_) unless $quiet;
+ $sc, $_) unless $quiet;
}
}
close $fh;
@@ -2023,6 +2002,38 @@ sub process_file {
return 1;
}
+sub initialize_modified_loop_vars {
+ $in_reply_to = $initial_in_reply_to;
+ $references = $initial_in_reply_to || '';
+ $message_num = 0;
+}
+
+if ($validate) {
+ # FIFOs can only be read once, exclude them from validation.
+ my @real_files = ();
+ foreach my $f (@files) {
+ unless (-p $f) {
+ 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";
+ initialize_modified_loop_vars();
+ 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};
+}
+
+initialize_modified_loop_vars();
foreach my $t (@files) {
while (!process_file($t)) {
# user edited the file
diff --git a/git-submodule.sh b/git-submodule.sh
index 7f9582d923..03c5a220a2 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -94,6 +94,14 @@ cmd_add()
--reference=*)
reference_path="${1#--reference=}"
;;
+ --ref-format)
+ case "$2" in '') usage ;; esac
+ ref_format="--ref-format=$2"
+ shift
+ ;;
+ --ref-format=*)
+ ref_format="$1"
+ ;;
--dissociate)
dissociate=1
;;
@@ -129,7 +137,18 @@ cmd_add()
usage
fi
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add ${quiet:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add \
+ ${quiet:+--quiet} \
+ ${force:+--force} \
+ ${progress:+"--progress"} \
+ ${branch:+--branch "$branch"} \
+ ${reference_path:+--reference "$reference_path"} \
+ ${ref_format:+"$ref_format"} \
+ ${dissociate:+--dissociate} \
+ ${custom_name:+--name "$custom_name"} \
+ ${depth:+"$depth"} \
+ -- \
+ "$@"
}
#
@@ -160,7 +179,11 @@ cmd_foreach()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach \
+ ${quiet:+--quiet} \
+ ${recursive:+--recursive} \
+ -- \
+ "$@"
}
#
@@ -191,7 +214,10 @@ cmd_init()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init ${quiet:+--quiet} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init \
+ ${quiet:+--quiet} \
+ -- \
+ "$@"
}
#
@@ -227,7 +253,12 @@ cmd_deinit()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${quiet:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
+ ${quiet:+--quiet} \
+ ${force:+--force} \
+ ${deinit_all:+--all} \
+ -- \
+ "$@"
}
#
@@ -268,6 +299,14 @@ cmd_update()
-r|--rebase)
rebase=1
;;
+ --ref-format)
+ case "$2" in '') usage ;; esac
+ ref_format="--ref-format=$2"
+ shift
+ ;;
+ --ref-format=*)
+ ref_format="$1"
+ ;;
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
@@ -349,6 +388,7 @@ cmd_update()
${rebase:+--rebase} \
${merge:+--merge} \
${checkout:+--checkout} \
+ ${ref_format:+"$ref_format"} \
${reference:+"$reference"} \
${dissociate:+"--dissociate"} \
${depth:+"$depth"} \
@@ -399,7 +439,12 @@ cmd_set_branch() {
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${quiet:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch \
+ ${quiet:+--quiet} \
+ ${branch:+--branch "$branch"} \
+ ${default:+--default} \
+ -- \
+ "$@"
}
#
@@ -428,7 +473,10 @@ cmd_set_url() {
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${quiet:+--quiet} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url \
+ ${quiet:+--quiet} \
+ -- \
+ "$@"
}
#
@@ -480,7 +528,13 @@ cmd_summary() {
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary \
+ ${files:+--files} \
+ ${cached:+--cached} \
+ ${for_status:+--for-status} \
+ ${summary_limit:+-n $summary_limit} \
+ -- \
+ "$@"
}
#
# List all submodules, prefixed with:
@@ -521,8 +575,14 @@ cmd_status()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${quiet:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status \
+ ${quiet:+--quiet} \
+ ${cached:+--cached} \
+ ${recursive:+--recursive} \
+ -- \
+ "$@"
}
+
#
# Sync remote urls for submodules
# This makes the value for remote.$remote.url match the value
@@ -554,7 +614,11 @@ cmd_sync()
esac
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync \
+ ${quiet:+--quiet} \
+ ${recursive:+--recursive} \
+ -- \
+ "$@"
}
cmd_absorbgitdirs()
diff --git a/git-svn.perl b/git-svn.perl
index 4e8878f035..01e7a70de1 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
# Copyright (C) 2006, Eric Wong <normalperson@yhbt.net>
# License: GPL v2 or later
-use 5.008;
+use 5.008001;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
use strict;
use vars qw/ $AUTHOR $VERSION
@@ -219,11 +219,11 @@ my %cmd = (
"Set an SVN repository to a git tree-ish",
{ 'stdin' => \$_stdin, %cmt_opts, %fc_opts, } ],
'create-ignore' => [ \&cmd_create_ignore,
- 'Create a .gitignore per svn:ignore',
+ "Create a .gitignore per directory with SVN ignore properties",
{ 'revision|r=i' => \$_revision
} ],
'mkdirs' => [ \&cmd_mkdirs ,
- "recreate empty directories after a checkout",
+ "Recreate empty directories after a checkout",
{ 'revision|r=i' => \$_revision } ],
'propget' => [ \&cmd_propget,
'Print the value of a property on a file or directory',
@@ -234,7 +234,7 @@ my %cmd = (
'proplist' => [ \&cmd_proplist,
'List all properties of a file or directory',
{ 'revision|r=i' => \$_revision } ],
- 'show-ignore' => [ \&cmd_show_ignore, "Show svn:ignore listings",
+ 'show-ignore' => [ \&cmd_show_ignore, "Show .gitignore patterns from SVN ignore properties",
{ 'revision|r=i' => \$_revision
} ],
'show-externals' => [ \&cmd_show_externals, "Show svn:externals listings",
@@ -1279,12 +1279,20 @@ sub cmd_show_ignore {
$gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
- my $s = $props->{'svn:ignore'} or return;
- $s =~ s/[\r\n]+/\n/g;
- $s =~ s/^\n+//;
- chomp $s;
- $s =~ s#^#$path#gm;
- print STDOUT "$s\n";
+ if (my $s = $props->{'svn:ignore'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ $s =~ s#^#$path#gm;
+ print STDOUT "$s\n";
+ }
+ if (my $s = $props->{'svn:global-ignores'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ $s =~ s#^#$path**/#gm;
+ print STDOUT "$s\n";
+ }
});
}
@@ -1315,16 +1323,25 @@ sub cmd_create_ignore {
# which git won't track
mkpath([$path]) unless -d $path;
my $ignore = $path . '.gitignore';
- my $s = $props->{'svn:ignore'} or return;
open(GITIGNORE, '>', $ignore)
or fatal("Failed to open `$ignore' for writing: $!");
- $s =~ s/[\r\n]+/\n/g;
- $s =~ s/^\n+//;
- chomp $s;
- # Prefix all patterns so that the ignore doesn't apply
- # to sub-directories.
- $s =~ s#^#/#gm;
- print GITIGNORE "$s\n";
+ if (my $s = $props->{'svn:ignore'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ # Prefix all patterns so that the ignore doesn't apply
+ # to sub-directories.
+ $s =~ s#^#/#gm;
+ print GITIGNORE "$s\n";
+ }
+ if (my $s = $props->{'svn:global-ignores'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ # Global ignores apply to sub-directories, so they are
+ # not prefixed.
+ print GITIGNORE "$s\n";
+ }
close(GITIGNORE)
or fatal("Failed to close `$ignore': $!");
command_noisy('add', '-f', $ignore);
diff --git a/git.c b/git.c
index c67e44dd82..46b3c740c5 100644
--- a/git.c
+++ b/git.c
@@ -1,9 +1,12 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "builtin.h"
#include "config.h"
#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "help.h"
+#include "object-file.h"
#include "pager.h"
#include "read-cache-ll.h"
#include "run-command.h"
@@ -28,16 +31,17 @@
struct cmd_struct {
const char *cmd;
- int (*fn)(int, const char **, const char *);
+ int (*fn)(int, const char **, const char *, struct repository *);
unsigned int option;
};
const char git_usage_string[] =
N_("git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
- " [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
- " [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
- " [--config-env=<name>=<envvar>] <command> [<args>]");
+ " [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\n"
+ " [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+ " [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\n"
+ " <command> [<args>]");
const char git_more_info_string[] =
N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -139,6 +143,13 @@ void setup_auto_pager(const char *cmd, int def)
commit_pager_choice();
}
+static void print_system_path(const char *path)
+{
+ char *s_path = system_path(path);
+ puts(s_path);
+ free(s_path);
+}
+
static int handle_options(const char ***argv, int *argc, int *envchanged)
{
const char **orig_argv = *argv;
@@ -169,15 +180,15 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
exit(0);
}
} else if (!strcmp(cmd, "--html-path")) {
- puts(system_path(GIT_HTML_PATH));
+ print_system_path(GIT_HTML_PATH);
trace2_cmd_name("_query_");
exit(0);
} else if (!strcmp(cmd, "--man-path")) {
- puts(system_path(GIT_MAN_PATH));
+ print_system_path(GIT_MAN_PATH);
trace2_cmd_name("_query_");
exit(0);
} else if (!strcmp(cmd, "--info-path")) {
- puts(system_path(GIT_INFO_PATH));
+ print_system_path(GIT_INFO_PATH);
trace2_cmd_name("_query_");
exit(0);
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
@@ -186,6 +197,11 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
use_pager = 0;
if (envchanged)
*envchanged = 1;
+ } else if (!strcmp(cmd, "--no-lazy-fetch")) {
+ fetch_if_missing = 0;
+ setenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
} else if (!strcmp(cmd, "--no-replace-objects")) {
disable_replace_refs();
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
@@ -331,6 +347,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
setenv(GIT_ATTR_SOURCE_ENVIRONMENT, cmd, 1);
if (envchanged)
*envchanged = 1;
+ } else if (!strcmp(cmd, "--no-advice")) {
+ setenv(GIT_ADVICE_ENVIRONMENT, "0", 1);
+ if (envchanged)
+ *envchanged = 1;
} else {
fprintf(stderr, _("unknown option: %s\n"), cmd);
usage(git_usage_string);
@@ -342,7 +362,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
return (*argv) - orig_argv;
}
-static int handle_alias(int *argcp, const char ***argv)
+static int handle_alias(struct strvec *args)
{
int envchanged = 0, ret = 0, saved_errno = errno;
int count, option_count;
@@ -350,10 +370,10 @@ static int handle_alias(int *argcp, const char ***argv)
const char *alias_command;
char *alias_string;
- alias_command = (*argv)[0];
+ alias_command = args->v[0];
alias_string = alias_lookup(alias_command);
if (alias_string) {
- if (*argcp > 1 && !strcmp((*argv)[1], "-h"))
+ if (args->nr > 1 && !strcmp(args->v[1], "-h"))
fprintf_ln(stderr, _("'%s' is aliased to '%s'"),
alias_command, alias_string);
if (alias_string[0] == '!') {
@@ -370,11 +390,9 @@ static int handle_alias(int *argcp, const char ***argv)
child.wait_after_clean = 1;
child.trace2_child_class = "shell_alias";
strvec_push(&child.args, alias_string + 1);
- strvec_pushv(&child.args, (*argv) + 1);
+ strvec_pushv(&child.args, args->v + 1);
trace2_cmd_alias(alias_command, child.args.v);
- trace2_cmd_list_config();
- trace2_cmd_list_env_vars();
trace2_cmd_name("_run_shell_alias_");
ret = run_command(&child);
@@ -405,17 +423,13 @@ static int handle_alias(int *argcp, const char ***argv)
trace_argv_printf(new_argv,
"trace: alias expansion: %s =>",
alias_command);
-
- REALLOC_ARRAY(new_argv, count + *argcp);
- /* insert after command name */
- COPY_ARRAY(new_argv + count, *argv + 1, *argcp);
-
trace2_cmd_alias(alias_command, new_argv);
- trace2_cmd_list_config();
- trace2_cmd_list_env_vars();
- *argv = new_argv;
- *argcp += count - 1;
+ /* Replace the alias with the new arguments. */
+ strvec_splice(args, 0, 1, new_argv, count);
+
+ free(alias_string);
+ free(new_argv);
ret = 1;
}
@@ -425,9 +439,10 @@ static int handle_alias(int *argcp, const char ***argv)
return ret;
}
-static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
+static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct repository *repo)
{
int status, help;
+ int no_repo = 1;
struct stat st;
const char *prefix;
int run_setup = (p->option & (RUN_SETUP | RUN_SETUP_GENTLY));
@@ -439,9 +454,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
if (run_setup & RUN_SETUP) {
prefix = setup_git_directory();
+ no_repo = 0;
} else if (run_setup & RUN_SETUP_GENTLY) {
- int nongit_ok;
- prefix = setup_git_directory_gently(&nongit_ok);
+ prefix = setup_git_directory_gently(&no_repo);
} else {
prefix = NULL;
}
@@ -462,12 +477,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
trace_argv_printf(argv, "trace: built-in: git");
trace2_cmd_name(p->cmd);
- trace2_cmd_list_config();
- trace2_cmd_list_env_vars();
- validate_cache_entries(the_repository->index);
- status = p->fn(argc, argv, prefix);
- validate_cache_entries(the_repository->index);
+ validate_cache_entries(repo->index);
+ status = p->fn(argc, argv, prefix, no_repo ? NULL : repo);
+ validate_cache_entries(repo->index);
if (status)
return status;
@@ -589,11 +602,13 @@ static struct cmd_struct commands[] = {
{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
+ { "refs", cmd_refs, RUN_SETUP },
{ "remote", cmd_remote, RUN_SETUP },
{ "remote-ext", cmd_remote_ext, NO_PARSEOPT },
{ "remote-fd", cmd_remote_fd, NO_PARSEOPT },
{ "repack", cmd_repack, RUN_SETUP },
{ "replace", cmd_replace, RUN_SETUP },
+ { "replay", cmd_replay, RUN_SETUP },
{ "rerere", cmd_rerere, RUN_SETUP },
{ "reset", cmd_reset, RUN_SETUP },
{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
@@ -681,47 +696,57 @@ void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
}
#ifdef STRIP_EXTENSION
-static void strip_extension(const char **argv)
+static void strip_extension(struct strvec *args)
{
size_t len;
- if (strip_suffix(argv[0], STRIP_EXTENSION, &len))
- argv[0] = xmemdupz(argv[0], len);
+ if (strip_suffix(args->v[0], STRIP_EXTENSION, &len)) {
+ char *stripped = xmemdupz(args->v[0], len);
+ strvec_replace(args, 0, stripped);
+ free(stripped);
+ }
}
#else
#define strip_extension(cmd)
#endif
-static void handle_builtin(int argc, const char **argv)
+static void handle_builtin(struct strvec *args)
{
- struct strvec args = STRVEC_INIT;
const char *cmd;
struct cmd_struct *builtin;
- strip_extension(argv);
- cmd = argv[0];
+ strip_extension(args);
+ cmd = args->v[0];
/* Turn "git cmd --help" into "git help --exclude-guides cmd" */
- if (argc > 1 && !strcmp(argv[1], "--help")) {
- int i;
+ if (args->nr > 1 && !strcmp(args->v[1], "--help")) {
+ const char *exclude_guides_arg[] = { "--exclude-guides" };
+
+ strvec_replace(args, 1, args->v[0]);
+ strvec_replace(args, 0, "help");
+ cmd = "help";
+ strvec_splice(args, 2, 0, exclude_guides_arg,
+ ARRAY_SIZE(exclude_guides_arg));
+ }
- argv[1] = argv[0];
- argv[0] = cmd = "help";
+ builtin = get_builtin(cmd);
+ if (builtin) {
+ const char **argv_copy = NULL;
+ int ret;
- for (i = 0; i < argc; i++) {
- strvec_push(&args, argv[i]);
- if (!i)
- strvec_push(&args, "--exclude-guides");
- }
+ /*
+ * `run_builtin()` will modify the argv array, so we need to
+ * create a shallow copy such that we can free all of its
+ * strings.
+ */
+ if (args->nr)
+ DUP_ARRAY(argv_copy, args->v, args->nr + 1);
- argc++;
- argv = args.v;
+ ret = run_builtin(builtin, args->nr, argv_copy, the_repository);
+ strvec_clear(args);
+ free(argv_copy);
+ exit(ret);
}
-
- builtin = get_builtin(cmd);
- if (builtin)
- exit(run_builtin(builtin, argc, argv));
- strvec_clear(&args);
}
static void execv_dashed_external(const char **argv)
@@ -767,10 +792,10 @@ static void execv_dashed_external(const char **argv)
exit(128);
}
-static int run_argv(int *argcp, const char ***argv)
+static int run_argv(struct strvec *args)
{
int done_alias = 0;
- struct string_list cmd_list = STRING_LIST_INIT_NODUP;
+ struct string_list cmd_list = STRING_LIST_INIT_DUP;
struct string_list_item *seen;
while (1) {
@@ -784,8 +809,8 @@ static int run_argv(int *argcp, const char ***argv)
* process.
*/
if (!done_alias)
- handle_builtin(*argcp, *argv);
- else if (get_builtin(**argv)) {
+ handle_builtin(args);
+ else if (get_builtin(args->v[0])) {
struct child_process cmd = CHILD_PROCESS_INIT;
int i;
@@ -801,8 +826,8 @@ static int run_argv(int *argcp, const char ***argv)
commit_pager_choice();
strvec_push(&cmd.args, "git");
- for (i = 0; i < *argcp; i++)
- strvec_push(&cmd.args, (*argv)[i]);
+ for (i = 0; i < args->nr; i++)
+ strvec_push(&cmd.args, args->v[i]);
trace_argv_printf(cmd.args.v, "trace: exec:");
@@ -817,13 +842,13 @@ static int run_argv(int *argcp, const char ***argv)
i = run_command(&cmd);
if (i >= 0 || errno != ENOENT)
exit(i);
- die("could not execute builtin %s", **argv);
+ die("could not execute builtin %s", args->v[0]);
}
/* .. then try the external ones */
- execv_dashed_external(*argv);
+ execv_dashed_external(args->v);
- seen = unsorted_string_list_lookup(&cmd_list, *argv[0]);
+ seen = unsorted_string_list_lookup(&cmd_list, args->v[0]);
if (seen) {
int i;
struct strbuf sb = STRBUF_INIT;
@@ -840,14 +865,14 @@ static int run_argv(int *argcp, const char ***argv)
" not terminate:%s"), cmd_list.items[0].string, sb.buf);
}
- string_list_append(&cmd_list, *argv[0]);
+ string_list_append(&cmd_list, args->v[0]);
/*
* It could be an alias -- this works around the insanity
* of overriding "git log" with "git show" by having
* alias.log = show
*/
- if (!handle_alias(argcp, argv))
+ if (!handle_alias(args))
break;
done_alias = 1;
}
@@ -859,6 +884,7 @@ static int run_argv(int *argcp, const char ***argv)
int cmd_main(int argc, const char **argv)
{
+ struct strvec args = STRVEC_INIT;
const char *cmd;
int done_help = 0;
@@ -884,8 +910,10 @@ int cmd_main(int argc, const char **argv)
* that one cannot handle it.
*/
if (skip_prefix(cmd, "git-", &cmd)) {
- argv[0] = cmd;
- handle_builtin(argc, argv);
+ strvec_push(&args, cmd);
+ strvec_pushv(&args, argv + 1);
+ handle_builtin(&args);
+ strvec_clear(&args);
die(_("cannot handle %s as a builtin"), cmd);
}
@@ -918,25 +946,34 @@ int cmd_main(int argc, const char **argv)
*/
setup_path();
+ for (size_t i = 0; i < argc; i++)
+ strvec_push(&args, argv[i]);
+
while (1) {
- int was_alias = run_argv(&argc, &argv);
+ int was_alias = run_argv(&args);
if (errno != ENOENT)
break;
if (was_alias) {
fprintf(stderr, _("expansion of alias '%s' failed; "
"'%s' is not a git command\n"),
- cmd, argv[0]);
+ cmd, args.v[0]);
+ strvec_clear(&args);
exit(1);
}
if (!done_help) {
- cmd = argv[0] = help_unknown_cmd(cmd);
+ char *assumed = help_unknown_cmd(cmd);
+ strvec_replace(&args, 0, assumed);
+ free(assumed);
+ cmd = args.v[0];
done_help = 1;
- } else
+ } else {
break;
+ }
}
fprintf(stderr, _("failed to run command '%s': %s\n"),
cmd, strerror(errno));
+ strvec_clear(&args);
return 1;
}
diff --git a/gitk-git/Makefile b/gitk-git/Makefile
index 5bdd52a6eb..e1f0aff4a1 100644
--- a/gitk-git/Makefile
+++ b/gitk-git/Makefile
@@ -33,9 +33,9 @@ ifdef NO_MSGFMT
MSGFMT ?= $(TCL_PATH) po/po2msg.sh
else
MSGFMT ?= msgfmt
- ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0)
+ ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0)
MSGFMT := $(TCL_PATH) po/po2msg.sh
- endif
+ endif
endif
PO_TEMPLATE = po/gitk.pot
diff --git a/gitk-git/gitk b/gitk-git/gitk
index df3ba2ea99..7a087f123d 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -11956,7 +11956,7 @@ proc formatdate {d} {
}
# This list of encoding names and aliases is distilled from
-# http://www.iana.org/assignments/character-sets.
+# https://www.iana.org/assignments/character-sets.
# Not all of them are supported by Tcl.
set encoding_aliases {
{ ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
@@ -12472,7 +12472,7 @@ if {[tk windowingsystem] eq "aqua"} {
catch {
# follow the XDG base directory specification by default. See
- # http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
if {[info exists env(XDG_CONFIG_HOME)] && $env(XDG_CONFIG_HOME) ne ""} {
# XDG_CONFIG_HOME environment variable is set
set config_file [file join $env(XDG_CONFIG_HOME) git gitk]
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index a58e6b3c44..5bfa4968c4 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -29,7 +29,7 @@ Requirements
------------
- Core git tools
- - Perl 5.8
+ - Perl 5.8.1
- Perl modules: CGI, Encode, Fcntl, File::Find, File::Basename.
- web server
@@ -203,7 +203,7 @@ You can specify the following configuration variables when building GIT:
created. [Default: /etc/gitweb.conf]
* HIGHLIGHT_BIN
Path to the highlight executable to use (must be the one from
- http://www.andre-simon.de due to assumptions about parameters and output).
+ http://andre-simon.de/zip/download.php due to assumptions about parameters and output).
Useful if highlight is not installed on your webserver's PATH.
[Default: highlight]
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index e66eb3d9ba..b09a8d0523 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -7,7 +7,7 @@
#
# This program is licensed under the GPLv2
-use 5.008;
+use 5.008001;
use strict;
use warnings;
# handle ACL in file access tests
@@ -122,9 +122,9 @@ our $favicon = "++GITWEB_FAVICON++";
our $javascript = "++GITWEB_JS++";
# URI and label (title) of GIT logo link
-#our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/";
+#our $logo_url = "https://www.kernel.org/pub/software/scm/git/docs/";
#our $logo_label = "git documentation";
-our $logo_url = "http://git-scm.com/";
+our $logo_url = "https://git-scm.com/";
our $logo_label = "git homepage";
# source of projects list
@@ -197,7 +197,7 @@ our @diff_opts = ('-M'); # taken from git_commit
our $prevent_xss = 0;
# Path to the highlight executable to use (must be the one from
-# http://www.andre-simon.de due to assumptions about parameters and output).
+# http://andre-simon.de/zip/download.php due to assumptions about parameters and output).
# Useful if highlight is not installed on your webserver's PATH.
# [Default: highlight]
our $highlight_bin = "++HIGHLIGHT_BIN++";
@@ -269,7 +269,7 @@ our %avatar_size = (
# Leave it undefined (or set to 'undef') to turn off load checking.
our $maxload = 300;
-# configuration for 'highlight' (http://www.andre-simon.de/)
+# configuration for 'highlight' (http://andre-simon.de/doku/highlight/en/highlight.php)
# match by basename
our %highlight_basename = (
#'Program' => 'py',
@@ -728,9 +728,11 @@ our $per_request_config = 1;
sub read_config_file {
my $filename = shift;
return unless defined $filename;
- # die if there are errors parsing config file
if (-e $filename) {
do $filename;
+ # die if there is a problem accessing the file
+ die $! if $!;
+ # die if there are errors parsing config file
die $@ if $@;
return 1;
}
@@ -8193,7 +8195,7 @@ sub git_feed {
my $have_blame = gitweb_check_feature('blame');
# Atom: http://www.atomenabled.org/developers/syndication/
- # RSS: http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
+ # RSS: https://web.archive.org/web/20030729001534/http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
if ($format ne 'rss' && $format ne 'atom') {
die_error(400, "Unknown web feed format");
}
@@ -8324,10 +8326,10 @@ XML
my %co = %{$commitlist[$i]};
my $commit = $co{'id'};
# we read 150, we always show 30 and the ones more recent than 48 hours
- if (($i >= 20) && ((time - $co{'author_epoch'}) > 48*60*60)) {
+ if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) {
last;
}
- my %cd = parse_date($co{'author_epoch'}, $co{'author_tz'});
+ my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
# get list of changed files
open my $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
diff --git a/gitweb/static/gitweb.css b/gitweb/static/gitweb.css
index 3212601032..48d2e51015 100644
--- a/gitweb/static/gitweb.css
+++ b/gitweb/static/gitweb.css
@@ -667,7 +667,7 @@ div.remote {
}
-/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
+/* Style definition generated by highlight 2.4.5, http://andre-simon.de/doku/highlight/en/highlight.php */
/* Highlighting theme definition: */
diff --git a/gitweb/static/js/lib/common-lib.js b/gitweb/static/js/lib/common-lib.js
index 018bbb7d4c..99e3eb8c3d 100644
--- a/gitweb/static/js/lib/common-lib.js
+++ b/gitweb/static/js/lib/common-lib.js
@@ -123,8 +123,8 @@ function addCssRule(selector, style) {
* NOTE that there are limits and differences compared to native
* getElementsByClassName as defined by e.g.:
* https://developer.mozilla.org/en/DOM/document.getElementsByClassName
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#dom-getelementsbyclassname
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#dom-document-getelementsbyclassname
+ * https://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#dom-getelementsbyclassname
+ * https://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#dom-document-getelementsbyclassname
*
* Namely, this implementation supports only single class name as
* argument and not set of space-separated tokens representing classes,
@@ -133,11 +133,11 @@ function addCssRule(selector, style) {
* (via getElementsByTagName).
*
* Based on
- * http://code.google.com/p/getelementsbyclassname/
+ * https://code.google.com/p/getelementsbyclassname/
* http://www.dustindiaz.com/getelementsbyclass/
- * http://stackoverflow.com/questions/1818865/do-we-have-getelementsbyclassname-in-javascript
+ * https://stackoverflow.com/questions/1818865/do-we-have-getelementsbyclassname-in-javascript
*
- * See also http://ejohn.org/blog/getelementsbyclassname-speed-comparison/
+ * See also https://johnresig.com/blog/getelementsbyclassname-speed-comparison/
*
* @param {String} class: name of _single_ class to find
* @param {String} [taghint] limit search to given tags
diff --git a/gpg-interface.c b/gpg-interface.c
index 48f43c5a21..07335987a6 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit.h"
#include "config.h"
@@ -12,7 +14,6 @@
#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 *);
@@ -28,7 +29,9 @@ static void gpg_interface_lazy_init(void)
}
static char *configured_signing_key;
-static const char *ssh_default_key_command, *ssh_allowed_signers, *ssh_revocation_file;
+static char *ssh_default_key_command;
+static char *ssh_allowed_signers;
+static char *ssh_revocation_file;
static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
struct gpg_format {
@@ -42,8 +45,8 @@ struct gpg_format {
size_t signature_size);
int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
const char *signing_key);
- const char *(*get_default_key)(void);
- const char *(*get_key_id)(void);
+ char *(*get_default_key)(void);
+ char *(*get_key_id)(void);
};
static const char *openpgp_verify_args[] = {
@@ -83,9 +86,9 @@ static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
const char *signing_key);
-static const char *get_default_ssh_signing_key(void);
+static char *get_default_ssh_signing_key(void);
-static const char *get_ssh_key_id(void);
+static char *get_ssh_key_id(void);
static struct gpg_format gpg_format[] = {
{
@@ -397,7 +400,7 @@ static void parse_ssh_output(struct signature_check *sigc)
* Note that "PRINCIPAL" can contain whitespace, "RSA" and
* "SHA256" part could be a different token that names of
* the algorithms used, and "FINGERPRINT" is a hexadecimal
- * string. By finding the last occurence of " with ", we can
+ * string. By finding the last occurrence of " with ", we can
* reliably parse out the PRINCIPAL.
*/
sigc->result = 'B';
@@ -484,7 +487,7 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
if (sigc->payload_timestamp)
strbuf_addf(&verify_time, "-Overify-time=%s",
- show_date(sigc->payload_timestamp, 0, &verify_date_mode));
+ show_date(sigc->payload_timestamp, 0, verify_date_mode));
/* Find the principal from the signers */
strvec_pushl(&ssh_keygen.args, fmt->program,
@@ -587,8 +590,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, NULL);
+ strbuf_stripspace(&ssh_keygen_err, NULL);
/* 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);
@@ -726,7 +729,7 @@ static int git_gpg_config(const char *var, const char *value,
void *cb UNUSED)
{
struct gpg_format *fmt = NULL;
- char *fmtname = NULL;
+ const char *fmtname = NULL;
char *trust;
int ret;
@@ -762,23 +765,14 @@ static int git_gpg_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "gpg.ssh.defaultkeycommand")) {
- if (!value)
- return config_error_nonbool(var);
+ if (!strcmp(var, "gpg.ssh.defaultkeycommand"))
return git_config_string(&ssh_default_key_command, var, value);
- }
- if (!strcmp(var, "gpg.ssh.allowedsignersfile")) {
- if (!value)
- return config_error_nonbool(var);
+ if (!strcmp(var, "gpg.ssh.allowedsignersfile"))
return git_config_pathname(&ssh_allowed_signers, var, value);
- }
- if (!strcmp(var, "gpg.ssh.revocationfile")) {
- if (!value)
- return config_error_nonbool(var);
+ if (!strcmp(var, "gpg.ssh.revocationfile"))
return git_config_pathname(&ssh_revocation_file, var, value);
- }
if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
fmtname = "openpgp";
@@ -791,7 +785,7 @@ static int git_gpg_config(const char *var, const char *value,
if (fmtname) {
fmt = get_format_by_name(fmtname);
- return git_config_string(&fmt->program, var, value);
+ return git_config_string((char **) &fmt->program, var, value);
}
return 0;
@@ -853,7 +847,7 @@ static char *get_ssh_key_fingerprint(const char *signing_key)
}
/* Returns the first public key from an ssh-agent to use for signing */
-static const char *get_default_ssh_signing_key(void)
+static char *get_default_ssh_signing_key(void)
{
struct child_process ssh_default_key = CHILD_PROCESS_INIT;
int ret = -1;
@@ -905,12 +899,16 @@ static const char *get_default_ssh_signing_key(void)
return default_key;
}
-static const char *get_ssh_key_id(void) {
- return get_ssh_key_fingerprint(get_signing_key());
+static char *get_ssh_key_id(void)
+{
+ char *signing_key = get_signing_key();
+ char *key_id = get_ssh_key_fingerprint(signing_key);
+ free(signing_key);
+ return key_id;
}
/* Returns a textual but unique representation of the signing key */
-const char *get_signing_key_id(void)
+char *get_signing_key_id(void)
{
gpg_interface_lazy_init();
@@ -922,17 +920,17 @@ const char *get_signing_key_id(void)
return get_signing_key();
}
-const char *get_signing_key(void)
+char *get_signing_key(void)
{
gpg_interface_lazy_init();
if (configured_signing_key)
- return configured_signing_key;
+ return xstrdup(configured_signing_key);
if (use_format->get_default_key) {
return use_format->get_default_key();
}
- return git_committer_info(IDENT_STRICT | IDENT_NO_DATE);
+ return xstrdup(git_committer_info(IDENT_STRICT | IDENT_NO_DATE));
}
const char *gpg_trust_level_to_str(enum signature_trust_level level)
@@ -1088,7 +1086,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
if (strstr(signer_stderr.buf, "usage:"))
error(_("ssh-keygen -Y sign is needed for ssh signing (available in openssh version 8.2p1+)"));
- error("%s", signer_stderr.buf);
+ ret = error("%s", signer_stderr.buf);
goto out;
}
diff --git a/gpg-interface.h b/gpg-interface.h
index 143cdc1c02..e09f12e8d0 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -66,7 +66,7 @@ size_t parse_signed_buffer(const char *buf, size_t size);
* Create a detached signature for the contents of "buffer" and append
* it after "signature"; "buffer" and "signature" can be the same
* strbuf instance, which would cause the detached signature appended
- * at the end.
+ * at the end. Returns 0 on success, non-zero on failure.
*/
int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
const char *signing_key);
@@ -80,13 +80,13 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
const char *gpg_trust_level_to_str(enum signature_trust_level level);
void set_signing_key(const char *);
-const char *get_signing_key(void);
+char *get_signing_key(void);
/*
* Returns a textual unique representation of the signing key in use
* Either a GPG KeyID or a SSH Key Fingerprint
*/
-const char *get_signing_key_id(void);
+char *get_signing_key_id(void);
int check_signature(struct signature_check *sigc,
const char *signature, size_t slen);
void print_signature_buffer(const struct signature_check *sigc,
diff --git a/graph.c b/graph.c
index 2a9dc430fa..bf000fdbe1 100644
--- a/graph.c
+++ b/graph.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "config.h"
@@ -74,10 +76,7 @@ static void graph_show_line_prefix(const struct diff_options *diffopt)
if (!diffopt || !diffopt->line_prefix)
return;
- fwrite(diffopt->line_prefix,
- sizeof(char),
- diffopt->line_prefix_length,
- diffopt->file);
+ fputs(diffopt->line_prefix, diffopt->file);
}
static const char **column_colors;
@@ -310,22 +309,28 @@ struct git_graph {
* stored as an index into the array column_colors.
*/
unsigned short default_column_color;
+
+ /*
+ * Scratch buffer for generating prefixes to be used with
+ * diff_output_prefix_callback().
+ */
+ struct strbuf prefix_buf;
};
-static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void *data)
+static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
{
struct git_graph *graph = data;
- static struct strbuf msgbuf = STRBUF_INIT;
assert(opt);
- strbuf_reset(&msgbuf);
+ if (!graph)
+ return opt->line_prefix;
+
+ strbuf_reset(&graph->prefix_buf);
if (opt->line_prefix)
- strbuf_add(&msgbuf, opt->line_prefix,
- opt->line_prefix_length);
- if (graph)
- graph_padding_line(graph, &msgbuf);
- return &msgbuf;
+ strbuf_addstr(&graph->prefix_buf, opt->line_prefix);
+ graph_padding_line(graph, &graph->prefix_buf);
+ return graph->prefix_buf.buf;
}
static const struct diff_options *default_diffopt;
@@ -339,7 +344,6 @@ void graph_setup_line_prefix(struct diff_options *diffopt)
diffopt->output_prefix = diff_output_prefix_callback;
}
-
struct git_graph *graph_init(struct rev_info *opt)
{
struct git_graph *graph = xmalloc(sizeof(struct git_graph));
@@ -396,6 +400,7 @@ struct git_graph *graph_init(struct rev_info *opt)
* The diff output prefix callback, with this we can make
* all the diff output to align with the graph lines.
*/
+ strbuf_init(&graph->prefix_buf, 0);
opt->diffopt.output_prefix = diff_output_prefix_callback;
opt->diffopt.output_prefix_data = graph;
@@ -411,6 +416,7 @@ void graph_clear(struct git_graph *graph)
free(graph->new_columns);
free(graph->mapping);
free(graph->old_mapping);
+ strbuf_release(&graph->prefix_buf);
free(graph);
}
diff --git a/graph.h b/graph.h
index e88632a014..3fd1dcb2e9 100644
--- a/graph.h
+++ b/graph.h
@@ -130,7 +130,7 @@ void graph_setup_line_prefix(struct diff_options *diffopt);
* This functions must be called BEFORE graph_init() is called.
*
* NOTE: This function isn't used in Git outside graph.c but it is used
- * by CGit (http://git.zx2c4.com/cgit/) to use HTML for colors.
+ * by CGit (https://git.zx2c4.com/cgit/) to use HTML for colors.
*/
void graph_set_column_colors(const char **colors, unsigned short colors_max);
@@ -196,7 +196,7 @@ int graph_is_commit_finished(struct git_graph const *graph);
* graph_update() is called.
*
* NOTE: This function isn't used in Git outside graph.c but it is used
- * by CGit (http://git.zx2c4.com/cgit/) to wrap HTML around graph lines.
+ * by CGit (https://git.zx2c4.com/cgit/) to wrap HTML around graph lines.
*/
int graph_next_line(struct git_graph *graph, struct strbuf *sb);
diff --git a/grep.c b/grep.c
index 0904d55b24..e95cded414 100644
--- a/grep.c
+++ b/grep.c
@@ -9,7 +9,6 @@
#include "xdiff-interface.h"
#include "diff.h"
#include "diffcore.h"
-#include "commit.h"
#include "quote.h"
#include "help.h"
@@ -17,7 +16,7 @@ static int grep_source_load(struct grep_source *gs);
static int grep_source_is_binary(struct grep_source *gs,
struct index_state *istate);
-static void std_output(struct grep_opt *opt, const void *buf, size_t size)
+static void std_output(struct grep_opt *opt UNUSED, const void *buf, size_t size)
{
fwrite(buf, size, 1, stdout);
}
@@ -246,7 +245,7 @@ static int is_fixed(const char *s, size_t len)
#ifdef USE_LIBPCRE2
#define GREP_PCRE2_DEBUG_MALLOC 0
-static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
+static void *pcre2_malloc(PCRE2_SIZE size, void *memory_data UNUSED)
{
void *pointer = malloc(size);
#if GREP_PCRE2_DEBUG_MALLOC
@@ -256,7 +255,7 @@ static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
return pointer;
}
-static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
+static void pcre2_free(void *pointer, void *memory_data UNUSED)
{
#if GREP_PCRE2_DEBUG_MALLOC
static int count = 1;
@@ -452,18 +451,20 @@ static void free_pcre2_pattern(struct grep_pat *p)
pcre2_general_context_free(p->pcre2_general_context);
}
#else /* !USE_LIBPCRE2 */
-static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
+static void compile_pcre2_pattern(struct grep_pat *p UNUSED,
+ const struct grep_opt *opt UNUSED)
{
die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
}
-static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
- regmatch_t *match, int eflags)
+static int pcre2match(struct grep_pat *p UNUSED, const char *line UNUSED,
+ const char *eol UNUSED, regmatch_t *match UNUSED,
+ int eflags UNUSED)
{
return 1;
}
-static void free_pcre2_pattern(struct grep_pat *p)
+static void free_pcre2_pattern(struct grep_pat *p UNUSED)
{
}
@@ -620,7 +621,7 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
*list = p->next;
x = compile_pattern_or(list);
if (!*list || (*list)->token != GREP_CLOSE_PAREN)
- die("unmatched parenthesis");
+ die("unmatched ( for expression group");
*list = (*list)->next;
return x;
default:
@@ -755,6 +756,7 @@ static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr *y
assert(x->node == GREP_NODE_OR);
if (x->u.binary.right &&
x->u.binary.right->node == GREP_NODE_TRUE) {
+ free(x->u.binary.right);
x->u.binary.right = y;
break;
}
@@ -791,7 +793,7 @@ void compile_grep_patterns(struct grep_opt *opt)
if (p)
opt->pattern_expression = compile_pattern_expr(&p);
if (p)
- die("incomplete pattern expression: %s", p->pattern);
+ die("incomplete pattern expression group: %s", p->pattern);
if (opt->no_body_match && opt->pattern_expression)
opt->pattern_expression = grep_not_expr(opt->pattern_expression);
@@ -842,11 +844,11 @@ static void free_grep_pat(struct grep_pat *pattern)
free_pcre2_pattern(p);
else
regfree(&p->regexp);
- free(p->pattern);
break;
default:
break;
}
+ free(p->pattern);
free(p);
}
}
@@ -905,15 +907,17 @@ static int patmatch(struct grep_pat *p,
const char *line, const char *eol,
regmatch_t *match, int eflags)
{
- int hit;
-
if (p->pcre2_pattern)
- hit = !pcre2match(p, line, eol, match, eflags);
- else
- hit = !regexec_buf(&p->regexp, line, eol - line, 1, match,
- eflags);
+ return !pcre2match(p, line, eol, match, eflags);
- return hit;
+ switch (regexec_buf(&p->regexp, line, eol - line, 1, match, eflags)) {
+ case 0:
+ return 1;
+ case REG_NOMATCH:
+ return 0;
+ default:
+ return -1;
+ }
}
static void strip_timestamp(const char *bol, const char **eol_p)
@@ -951,6 +955,8 @@ static int headerless_match_one_pattern(struct grep_pat *p,
again:
hit = patmatch(p, bol, eol, pmatch, eflags);
+ if (hit < 0)
+ hit = 0;
if (hit && p->word_regexp) {
if ((pmatch[0].rm_so < 0) ||
@@ -1460,6 +1466,8 @@ static int look_ahead(struct grep_opt *opt,
regmatch_t m;
hit = patmatch(p, bol, bol + *left_p, &m, 0);
+ if (hit < 0)
+ return -1;
if (!hit || m.rm_so < 0 || m.rm_eo < 0)
continue;
if (earliest < 0 || m.rm_so < earliest)
@@ -1654,9 +1662,13 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
if (try_lookahead
&& !(last_hit
&& (show_function ||
- lno <= last_hit + opt->post_context))
- && look_ahead(opt, &left, &lno, &bol))
- break;
+ lno <= last_hit + opt->post_context))) {
+ hit = look_ahead(opt, &left, &lno, &bol);
+ if (hit < 0)
+ try_lookahead = 0;
+ else if (hit)
+ break;
+ }
eol = end_of_line(bol, &left);
if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol))
@@ -1734,7 +1746,8 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
peek_eol = end_of_line(peek_bol, &peek_left);
}
- if (match_funcname(opt, gs, peek_bol, peek_eol))
+ if (peek_bol >= gs->buf + gs->size ||
+ match_funcname(opt, gs, peek_bol, peek_eol))
show_function = 0;
}
if (show_function ||
diff --git a/hash-ll.h b/hash-ll.h
deleted file mode 100644
index 10d84cc208..0000000000
--- a/hash-ll.h
+++ /dev/null
@@ -1,309 +0,0 @@
-#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
diff --git a/hash-lookup.c b/hash-lookup.c
index 9f0f95e2b9..5f808caa51 100644
--- a/hash-lookup.c
+++ b/hash-lookup.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "hash.h"
#include "hash-lookup.h"
@@ -112,7 +114,8 @@ int bsearch_hash(const unsigned char *hash, const uint32_t *fanout_nbo,
while (lo < hi) {
unsigned mi = lo + (hi - lo) / 2;
- int cmp = hashcmp(table + mi * stride, hash);
+ int cmp = hashcmp(table + mi * stride, hash,
+ the_repository->hash_algo);
if (!cmp) {
if (result)
diff --git a/hash.h b/hash.h
index 615ae0691d..756166ce5e 100644
--- a/hash.h
+++ b/hash.h
@@ -1,102 +1,444 @@
#ifndef HASH_H
#define HASH_H
-#include "hash-ll.h"
-#include "repository.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(SHA1_APPLE_UNSAFE)
+# include <CommonCrypto/CommonDigest.h>
+# define platform_SHA_CTX_unsafe CC_SHA1_CTX
+# define platform_SHA1_Init_unsafe CC_SHA1_Init
+# define platform_SHA1_Update_unsafe CC_SHA1_Update
+# define platform_SHA1_Final_unsafe CC_SHA1_Final
+#elif defined(SHA1_OPENSSL_UNSAFE)
+# include <openssl/sha.h>
+# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
+# define SHA1_NEEDS_CLONE_HELPER_UNSAFE
+# include "sha1/openssl.h"
+# define platform_SHA_CTX_unsafe openssl_SHA1_CTX
+# define platform_SHA1_Init_unsafe openssl_SHA1_Init
+# define platform_SHA1_Clone_unsafe openssl_SHA1_Clone
+# define platform_SHA1_Update_unsafe openssl_SHA1_Update
+# define platform_SHA1_Final_unsafe openssl_SHA1_Final
+# else
+# define platform_SHA_CTX_unsafe SHA_CTX
+# define platform_SHA1_Init_unsafe SHA1_Init
+# define platform_SHA1_Update_unsafe SHA1_Update
+# define platform_SHA1_Final_unsafe SHA1_Final
+# endif
+#elif defined(SHA1_BLK_UNSAFE)
+# include "block-sha1/sha1.h"
+# define platform_SHA_CTX_unsafe blk_SHA_CTX
+# define platform_SHA1_Init_unsafe blk_SHA1_Init
+# define platform_SHA1_Update_unsafe blk_SHA1_Update
+# define platform_SHA1_Final_unsafe blk_SHA1_Final
+#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
+
+#ifndef platform_SHA_CTX_unsafe
+# define platform_SHA_CTX_unsafe platform_SHA_CTX
+# define platform_SHA1_Init_unsafe platform_SHA1_Init
+# define platform_SHA1_Update_unsafe platform_SHA1_Update
+# define platform_SHA1_Final_unsafe platform_SHA1_Final
+# ifdef platform_SHA1_Clone
+# define platform_SHA1_Clone_unsafe platform_SHA1_Clone
+# endif
+# ifdef SHA1_NEEDS_CLONE_HELPER
+# define SHA1_NEEDS_CLONE_HELPER_UNSAFE
+# endif
+#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
+
+#define git_SHA_CTX_unsafe platform_SHA_CTX_unsafe
+#define git_SHA1_Init_unsafe platform_SHA1_Init_unsafe
+#define git_SHA1_Update_unsafe platform_SHA1_Update_unsafe
+#define git_SHA1_Final_unsafe platform_SHA1_Final_unsafe
+
+#ifdef platform_SHA1_Clone
+#define git_SHA1_Clone platform_SHA1_Clone
+#endif
+#ifdef platform_SHA1_Clone_unsafe
+# define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe
+#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
-#define the_hash_algo the_repository->hash_algo
+#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 SHA1_NEEDS_CLONE_HELPER_UNSAFE
+static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst,
+ const git_SHA_CTX_unsafe *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+#endif
-static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
+#ifndef SHA256_NEEDS_CLONE_HELPER
+static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
{
- return hashcmp_algop(sha1, sha2, the_hash_algo);
+ memcpy(dst, src, sizeof(*dst));
}
+#endif
-static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
+/*
+ * 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_HASH_ANY 020000
+
+#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.
+ */
+};
+
+#ifdef USE_THE_REPOSITORY_VARIABLE
+# include "repository.h"
+# define the_hash_algo the_repository->hash_algo
+#endif
+
+/* A suitably aligned type for stack allocations of hash contexts. */
+union git_hash_ctx {
+ git_SHA_CTX sha1;
+ git_SHA_CTX_unsafe sha1_unsafe;
+
+ 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 non-cryptographic hash initialization function. */
+ git_hash_init_fn unsafe_init_fn;
+
+ /* The non-cryptographic hash context cloning function. */
+ git_hash_clone_fn unsafe_clone_fn;
+
+ /* The non-cryptographic hash update function. */
+ git_hash_update_fn unsafe_update_fn;
+
+ /* The non-cryptographic hash finalization function. */
+ git_hash_final_fn unsafe_final_fn;
+
+ /* The non-cryptographic hash finalization function. */
+ git_hash_final_oid_fn unsafe_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)
{
- const struct git_hash_algo *algop;
- if (!oid1->algo)
- algop = the_hash_algo;
- else
- algop = &hash_algos[oid1->algo];
- return hashcmp_algop(oid1->hash, oid2->hash, algop);
+ return p - hash_algos;
}
-static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
+const struct object_id *null_oid(void);
+
+static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
{
- return hasheq_algop(sha1, sha2, the_hash_algo);
+ /*
+ * 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 oideq(const struct object_id *oid1, const struct object_id *oid2)
+static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
{
- const struct git_hash_algo *algop;
- if (!oid1->algo)
- algop = the_hash_algo;
- else
- algop = &hash_algos[oid1->algo];
- return hasheq_algop(oid1->hash, oid2->hash, 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 is_null_oid(const struct object_id *oid)
+static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src,
+ const struct git_hash_algo *algop)
{
- return oideq(oid, null_oid());
+ memcpy(sha_dst, sha_src, algop->rawsz);
}
-static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
+static inline void hashclr(unsigned char *hash, const struct git_hash_algo *algop)
{
- memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
+ memset(hash, 0, algop->rawsz);
}
-/* 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)
+static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
{
- size_t hashsz;
+ return memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ);
+}
- if (!src->algo)
- hashsz = the_hash_algo->rawsz;
- else
- hashsz = hash_algos[src->algo].rawsz;
+static inline int oideq(const struct object_id *oid1, const struct object_id *oid2)
+{
+ return !memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ);
+}
- memcpy(dst->hash, src->hash, hashsz);
- memset(dst->hash + hashsz, 0, GIT_MAX_RAWSZ - hashsz);
+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 void hashclr(unsigned char *hash)
+static inline void oidread(struct object_id *oid, const unsigned char *hash,
+ const struct git_hash_algo *algop)
{
- memset(hash, 0, the_hash_algo->rawsz);
+ memcpy(oid->hash, hash, algop->rawsz);
+ if (algop->rawsz < GIT_MAX_RAWSZ)
+ memset(oid->hash + algop->rawsz, 0, GIT_MAX_RAWSZ - algop->rawsz);
+ oid->algo = hash_algo_by_ptr(algop);
}
-static inline void oidclr(struct object_id *oid)
+static inline void oidclr(struct object_id *oid,
+ const struct git_hash_algo *algop)
{
memset(oid->hash, 0, GIT_MAX_RAWSZ);
- oid->algo = hash_algo_by_ptr(the_hash_algo);
+ oid->algo = hash_algo_by_ptr(algop);
}
-static inline void oidread(struct object_id *oid, const unsigned char *hash)
+static inline struct object_id *oiddup(const struct object_id *src)
{
- memcpy(oid->hash, hash, the_hash_algo->rawsz);
- oid->algo = hash_algo_by_ptr(the_hash_algo);
+ struct object_id *dst = xmalloc(sizeof(struct object_id));
+ oidcpy(dst, src);
+ return dst;
}
-static inline int is_empty_blob_sha1(const unsigned char *sha1)
+static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
{
- return hasheq(sha1, the_hash_algo->empty_blob->hash);
+ oid->algo = hash_algo_by_ptr(algop);
}
-static inline int is_empty_blob_oid(const struct object_id *oid)
+/*
+ * 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)
{
- return oideq(oid, the_hash_algo->empty_blob);
+ /*
+ * 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;
}
-static inline int is_empty_tree_sha1(const unsigned char *sha1)
+static inline int is_null_oid(const struct object_id *oid)
+{
+ static const unsigned char null_hash[GIT_MAX_RAWSZ];
+ return !memcmp(oid->hash, null_hash, GIT_MAX_RAWSZ);
+}
+
+const char *empty_tree_oid_hex(const struct git_hash_algo *algop);
+
+static inline int is_empty_blob_oid(const struct object_id *oid,
+ const struct git_hash_algo *algop)
{
- return hasheq(sha1, the_hash_algo->empty_tree->hash);
+ return oideq(oid, algop->empty_blob);
}
-static inline int is_empty_tree_oid(const struct object_id *oid)
+static inline int is_empty_tree_oid(const struct object_id *oid,
+ const struct git_hash_algo *algop)
{
- return oideq(oid, the_hash_algo->empty_tree);
+ return oideq(oid, algop->empty_tree);
}
#endif
diff --git a/help.c b/help.c
index 6d2ebfbd2a..8a830ba35c 100644
--- a/help.c
+++ b/help.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "builtin.h"
@@ -14,6 +16,11 @@
#include "parse-options.h"
#include "prompt.h"
#include "fsmonitor-ipc.h"
+#include "repository.h"
+
+#ifndef NO_CURL
+#include "git-curl-compat.h" /* For LIBCURL_VERSION only */
+#endif
struct category_description {
uint32_t category;
@@ -157,7 +164,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)
cmds->names[cmds->cnt++] = ent;
}
-static void clean_cmdnames(struct cmdnames *cmds)
+void cmdnames_release(struct cmdnames *cmds)
{
int i;
for (i = 0; i < cmds->cnt; ++i)
@@ -359,8 +366,8 @@ void list_all_main_cmds(struct string_list *list)
for (i = 0; i < main_cmds.cnt; i++)
string_list_append(list, main_cmds.names[i]->name);
- clean_cmdnames(&main_cmds);
- clean_cmdnames(&other_cmds);
+ cmdnames_release(&main_cmds);
+ cmdnames_release(&other_cmds);
}
void list_all_other_cmds(struct string_list *list)
@@ -375,8 +382,8 @@ void list_all_other_cmds(struct string_list *list)
for (i = 0; i < other_cmds.cnt; i++)
string_list_append(list, other_cmds.names[i]->name);
- clean_cmdnames(&main_cmds);
- clean_cmdnames(&other_cmds);
+ cmdnames_release(&main_cmds);
+ cmdnames_release(&other_cmds);
}
void list_cmds_by_category(struct string_list *list,
@@ -464,8 +471,11 @@ static int get_alias(const char *var, const char *value,
{
struct string_list *list = data;
- if (skip_prefix(var, "alias.", &var))
+ if (skip_prefix(var, "alias.", &var)) {
+ if (!value)
+ return config_error_nonbool(var);
string_list_append(list, var)->util = xstrdup(value);
+ }
return 0;
}
@@ -536,8 +546,10 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
return 0;
}
-static int autocorrect;
-static struct cmdnames aliases;
+struct help_unknown_cmd_config {
+ int autocorrect;
+ struct cmdnames aliases;
+};
#define AUTOCORRECT_PROMPT (-3)
#define AUTOCORRECT_NEVER (-2)
@@ -545,28 +557,29 @@ static struct cmdnames aliases;
static int git_unknown_cmd_config(const char *var, const char *value,
const struct config_context *ctx,
- void *cb UNUSED)
+ void *cb)
{
+ struct help_unknown_cmd_config *cfg = cb;
const char *p;
if (!strcmp(var, "help.autocorrect")) {
if (!value)
return config_error_nonbool(var);
if (!strcmp(value, "never")) {
- autocorrect = AUTOCORRECT_NEVER;
+ cfg->autocorrect = AUTOCORRECT_NEVER;
} else if (!strcmp(value, "immediate")) {
- autocorrect = AUTOCORRECT_IMMEDIATELY;
+ cfg->autocorrect = AUTOCORRECT_IMMEDIATELY;
} else if (!strcmp(value, "prompt")) {
- autocorrect = AUTOCORRECT_PROMPT;
+ cfg->autocorrect = AUTOCORRECT_PROMPT;
} else {
int v = git_config_int(var, value, ctx->kvi);
- autocorrect = (v < 0)
+ cfg->autocorrect = (v < 0)
? AUTOCORRECT_IMMEDIATELY : v;
}
}
/* Also use aliases for command lookup */
if (skip_prefix(var, "alias.", &p))
- add_cmdname(&aliases, p, strlen(p));
+ add_cmdname(&cfg->aliases, p, strlen(p));
return 0;
}
@@ -599,32 +612,30 @@ static const char bad_interpreter_advice[] =
N_("'%s' appears to be a git command, but we were not\n"
"able to execute it. Maybe git-%s is broken?");
-const char *help_unknown_cmd(const char *cmd)
+char *help_unknown_cmd(const char *cmd)
{
+ struct help_unknown_cmd_config cfg = { 0 };
int i, n, best_similarity = 0;
- struct cmdnames main_cmds, other_cmds;
+ struct cmdnames main_cmds = { 0 };
+ struct cmdnames other_cmds = { 0 };
struct cmdname_help *common_cmds;
- memset(&main_cmds, 0, sizeof(main_cmds));
- memset(&other_cmds, 0, sizeof(other_cmds));
- memset(&aliases, 0, sizeof(aliases));
-
- read_early_config(git_unknown_cmd_config, NULL);
+ read_early_config(the_repository, git_unknown_cmd_config, &cfg);
/*
* Disable autocorrection prompt in a non-interactive session
*/
- if ((autocorrect == AUTOCORRECT_PROMPT) && (!isatty(0) || !isatty(2)))
- autocorrect = AUTOCORRECT_NEVER;
+ if ((cfg.autocorrect == AUTOCORRECT_PROMPT) && (!isatty(0) || !isatty(2)))
+ cfg.autocorrect = AUTOCORRECT_NEVER;
- if (autocorrect == AUTOCORRECT_NEVER) {
+ if (cfg.autocorrect == AUTOCORRECT_NEVER) {
fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd);
exit(1);
}
load_command_list("git-", &main_cmds, &other_cmds);
- add_cmd_list(&main_cmds, &aliases);
+ add_cmd_list(&main_cmds, &cfg.aliases);
add_cmd_list(&main_cmds, &other_cmds);
QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);
uniq(&main_cmds);
@@ -683,20 +694,19 @@ const char *help_unknown_cmd(const char *cmd)
n++)
; /* still counting */
}
- if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {
- const char *assumed = main_cmds.names[0]->name;
- main_cmds.names[0] = NULL;
- clean_cmdnames(&main_cmds);
+ if (cfg.autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {
+ char *assumed = xstrdup(main_cmds.names[0]->name);
+
fprintf_ln(stderr,
_("WARNING: You called a Git command named '%s', "
"which does not exist."),
cmd);
- if (autocorrect == AUTOCORRECT_IMMEDIATELY)
+ if (cfg.autocorrect == AUTOCORRECT_IMMEDIATELY)
fprintf_ln(stderr,
_("Continuing under the assumption that "
"you meant '%s'."),
assumed);
- else if (autocorrect == AUTOCORRECT_PROMPT) {
+ else if (cfg.autocorrect == AUTOCORRECT_PROMPT) {
char *answer;
struct strbuf msg = STRBUF_INIT;
strbuf_addf(&msg, _("Run '%s' instead [y/N]? "), assumed);
@@ -709,9 +719,13 @@ const char *help_unknown_cmd(const char *cmd)
fprintf_ln(stderr,
_("Continuing in %0.1f seconds, "
"assuming that you meant '%s'."),
- (float)autocorrect/10.0, assumed);
- sleep_millisec(autocorrect * 100);
+ (float)cfg.autocorrect/10.0, assumed);
+ sleep_millisec(cfg.autocorrect * 100);
}
+
+ cmdnames_release(&cfg.aliases);
+ cmdnames_release(&main_cmds);
+ cmdnames_release(&other_cmds);
return assumed;
}
@@ -754,10 +768,19 @@ void get_version_info(struct strbuf *buf, int show_build_options)
if (fsmonitor_ipc__is_supported())
strbuf_addstr(buf, "feature: fsmonitor--daemon\n");
+#if defined LIBCURL_VERSION
+ strbuf_addf(buf, "libcurl: %s\n", LIBCURL_VERSION);
+#endif
+#if defined OPENSSL_VERSION_TEXT
+ strbuf_addf(buf, "OpenSSL: %s\n", OPENSSL_VERSION_TEXT);
+#endif
+#if defined ZLIB_VERSION
+ strbuf_addf(buf, "zlib: %s\n", ZLIB_VERSION);
+#endif
}
}
-int cmd_version(int argc, const char **argv, const char *prefix)
+int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repository UNUSED)
{
struct strbuf buf = STRBUF_INIT;
int build_options = 0;
@@ -786,7 +809,7 @@ struct similar_ref_cb {
struct string_list *similar_refs;
};
-static int append_similar_ref(const char *refname,
+static int append_similar_ref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data)
{
@@ -797,7 +820,7 @@ static int append_similar_ref(const char *refname,
if (starts_with(refname, "refs/remotes/") &&
!strcmp(branch, cb->base_ref))
string_list_append_nodup(cb->similar_refs,
- shorten_unambiguous_ref(refname, 1));
+ refs_shorten_unambiguous_ref(get_main_ref_store(the_repository), refname, 1));
return 0;
}
@@ -808,7 +831,8 @@ static struct string_list guess_refs(const char *ref)
ref_cb.base_ref = ref;
ref_cb.similar_refs = &similar_refs;
- for_each_ref(append_similar_ref, &ref_cb);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_similar_ref, &ref_cb);
return similar_refs;
}
diff --git a/help.h b/help.h
index af073a7a02..67207b3073 100644
--- a/help.h
+++ b/help.h
@@ -13,6 +13,8 @@ struct cmdnames {
} **names;
};
+void cmdnames_release(struct cmdnames *cmds);
+
static inline void mput_char(char c, unsigned int num)
{
while (num--)
@@ -30,7 +32,7 @@ void list_all_other_cmds(struct string_list *list);
void list_cmds_by_category(struct string_list *list,
const char *category);
void list_cmds_by_config(struct string_list *list);
-const char *help_unknown_cmd(const char *cmd);
+char *help_unknown_cmd(const char *cmd);
void load_command_list(const char *prefix,
struct cmdnames *main_cmds,
struct cmdnames *other_cmds);
diff --git a/hex-ll.c b/hex-ll.c
new file mode 100644
index 0000000000..4d7ece1de5
--- /dev/null
+++ b/hex-ll.c
@@ -0,0 +1,49 @@
+#include "git-compat-util.h"
+#include "hex-ll.h"
+
+const signed char hexval_table[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
+ 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
+ -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
+ -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
+};
+
+int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
+{
+ for (; len; len--, hex += 2) {
+ unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+
+ if (val & ~0xff)
+ return -1;
+ *binary++ = val;
+ }
+ return 0;
+}
diff --git a/hex-ll.h b/hex-ll.h
new file mode 100644
index 0000000000..a381fa8556
--- /dev/null
+++ b/hex-ll.h
@@ -0,0 +1,27 @@
+#ifndef HEX_LL_H
+#define HEX_LL_H
+
+extern const signed char hexval_table[256];
+static inline unsigned int hexval(unsigned char c)
+{
+ return hexval_table[c];
+}
+
+/*
+ * Convert two consecutive hexadecimal digits into a char. Return a
+ * negative value on error. Don't run over the end of short strings.
+ */
+static inline int hex2chr(const char *s)
+{
+ unsigned int val = hexval(s[0]);
+ return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
+}
+
+/*
+ * Read `len` pairs of hexadecimal digits from `hex` and write the
+ * values to `binary` as `len` bytes. Return 0 on success, or -1 if
+ * the input does not consist of hex digits).
+ */
+int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
+
+#endif
diff --git a/hex.c b/hex.c
index 01f17fe5c9..5ca78a7744 100644
--- a/hex.c
+++ b/hex.c
@@ -1,54 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
- 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
- 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
- -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
- -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
- -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
- -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
- -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
- -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
- -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
- -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
- -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
-};
-
-int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
-{
- for (; len; len--, hex += 2) {
- unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
-
- if (val & ~0xff)
- return -1;
- *binary++ = val;
- }
- return 0;
-}
-
static int get_hash_hex_algop(const char *hex, unsigned char *hash,
const struct git_hash_algo *algop)
{
@@ -72,8 +27,12 @@ int get_oid_hex_algop(const char *hex, struct object_id *oid,
const struct git_hash_algo *algop)
{
int ret = get_hash_hex_algop(hex, oid->hash, algop);
- if (!ret)
+ if (!ret) {
oid_set_algo(oid, algop);
+ if (algop->rawsz != GIT_MAX_RAWSZ)
+ memset(oid->hash + algop->rawsz, 0,
+ GIT_MAX_RAWSZ - algop->rawsz);
+ }
return ret;
}
diff --git a/hex.h b/hex.h
index 87abf66602..e9ccb54065 100644
--- a/hex.h
+++ b/hex.h
@@ -1,23 +1,8 @@
#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]);
-}
+#include "hash.h"
+#include "hex-ll.h"
/*
* Try to read a hash (specified by the_hash_algo) in hexadecimal
@@ -28,20 +13,9 @@ static inline int hex2chr(const char *s)
* 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
@@ -57,7 +31,6 @@ int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
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 */
/*
@@ -67,13 +40,9 @@ char *oid_to_hex(const struct object_id *oid); /* same static buffer */
* 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
@@ -83,4 +52,19 @@ int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end
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
+#ifdef USE_THE_REPOSITORY_VARIABLE
+
+/* Like get_oid_hex_algop, but for `the_hash_algo`. */
+int get_hash_hex(const char *hex, unsigned char *hash);
+int get_oid_hex(const char *hex, struct object_id *oid);
+
+/* Like parse_oid_hex_algop, but uses `the_hash_algo`. */
+int parse_oid_hex(const char *hex, struct object_id *oid, const char **end);
+
+/*
+ * Same as `hash_to_hex_algop()`, but uses `the_hash_algo`.
+ */
+char *hash_to_hex(const unsigned char *hash);
+
+#endif /* USE_THE_REPOSITORY_VARIABLE */
+#endif /* HEX_H */
diff --git a/hook.c b/hook.c
index 7e90787bca..a9320cb0ce 100644
--- a/hook.c
+++ b/hook.c
@@ -10,14 +10,14 @@
#include "environment.h"
#include "setup.h"
-const char *find_hook(const char *name)
+const char *find_hook(struct repository *r, const char *name)
{
static struct strbuf path = STRBUF_INIT;
int found_hook;
strbuf_reset(&path);
- strbuf_git_path(&path, "hooks/%s", name);
+ strbuf_repo_git_path(&path, r, "hooks/%s", name);
found_hook = access(path.buf, X_OK) >= 0;
#ifdef STRIP_EXTENSION
if (!found_hook) {
@@ -48,9 +48,9 @@ const char *find_hook(const char *name)
return path.buf;
}
-int hook_exists(const char *name)
+int hook_exists(struct repository *r, const char *name)
{
- return !!find_hook(name);
+ return !!find_hook(r, name);
}
static int pick_next_hook(struct child_process *cp,
@@ -121,7 +121,8 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options)
strvec_clear(&options->args);
}
-int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
+int run_hooks_opt(struct repository *r, const char *hook_name,
+ struct run_hooks_opt *options)
{
struct strbuf abs_path = STRBUF_INIT;
struct hook_cb_data cb_data = {
@@ -129,7 +130,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
.hook_name = hook_name,
.options = options,
};
- const char *const hook_path = find_hook(hook_name);
+ const char *const hook_path = find_hook(r, hook_name);
int ret = 0;
const struct run_process_parallel_opts opts = {
.tr2_category = "hook",
@@ -173,14 +174,14 @@ cleanup:
return ret;
}
-int run_hooks(const char *hook_name)
+int run_hooks(struct repository *r, const char *hook_name)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
- return run_hooks_opt(hook_name, &opt);
+ return run_hooks_opt(r, hook_name, &opt);
}
-int run_hooks_l(const char *hook_name, ...)
+int run_hooks_l(struct repository *r, const char *hook_name, ...)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
va_list ap;
@@ -191,5 +192,5 @@ int run_hooks_l(const char *hook_name, ...)
strvec_push(&opt.args, arg);
va_end(ap);
- return run_hooks_opt(hook_name, &opt);
+ return run_hooks_opt(r, hook_name, &opt);
}
diff --git a/hook.h b/hook.h
index 19ab9a5806..11863fa734 100644
--- a/hook.h
+++ b/hook.h
@@ -2,6 +2,8 @@
#define HOOK_H
#include "strvec.h"
+struct repository;
+
struct run_hooks_opt
{
/* Environment vars to be set for each hook */
@@ -55,12 +57,12 @@ struct hook_cb_data {
* or disabled. Note that this points to static storage that will be
* overwritten by further calls to find_hook and run_hook_*.
*/
-const char *find_hook(const char *name);
+const char *find_hook(struct repository *r, const char *name);
/**
* A boolean version of find_hook()
*/
-int hook_exists(const char *hookname);
+int hook_exists(struct repository *r, const char *hookname);
/**
* Takes a `hook_name`, resolves it to a path with find_hook(), and
@@ -70,13 +72,14 @@ int hook_exists(const char *hookname);
* Returns the status code of the run hook, or a negative value on
* error().
*/
-int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
+int run_hooks_opt(struct repository *r, const char *hook_name,
+ struct run_hooks_opt *options);
/**
* A wrapper for run_hooks_opt() which provides a dummy "struct
* run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
*/
-int run_hooks(const char *hook_name);
+int run_hooks(struct repository *r, const char *hook_name);
/**
* Like run_hooks(), a wrapper for run_hooks_opt().
@@ -86,5 +89,6 @@ int run_hooks(const char *hook_name);
* argument. These things will be used as positional arguments to the
* hook. This function behaves like the old run_hook_le() API.
*/
-int run_hooks_l(const char *hook_name, ...);
+LAST_ARG_MUST_BE_NULL
+int run_hooks_l(struct repository *r, const char *hook_name, ...);
#endif
diff --git a/http-backend.c b/http-backend.c
index ff07b87e64..73eec4ea3d 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -38,6 +40,7 @@ struct rpc_service {
static struct rpc_service rpc_service[] = {
{ "upload-pack", "uploadpack", 1, 1 },
{ "receive-pack", "receivepack", 0, -1 },
+ { "upload-archive", "uploadarchive", 0, -1 },
};
static struct string_list *get_parameters(void)
@@ -509,7 +512,7 @@ static void run_service(const char **argv, int buffer_input)
exit(1);
}
-static int show_text_ref(const char *name, const struct object_id *oid,
+static int show_text_ref(const char *name, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
const char *name_nons = strip_namespace(name);
@@ -558,21 +561,23 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
} else {
select_getanyfile(hdr);
- for_each_namespaced_ref(NULL, show_text_ref, &buf);
+ refs_for_each_namespaced_ref(get_main_ref_store(the_repository),
+ NULL, show_text_ref, &buf);
send_strbuf(hdr, "text/plain", &buf);
}
strbuf_release(&buf);
}
-static int show_head_ref(const char *refname, const struct object_id *oid,
+static int show_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
struct strbuf *buf = cb_data;
if (flag & REF_ISSYMREF) {
- const char *target = resolve_ref_unsafe(refname,
- RESOLVE_REF_READING,
- NULL, NULL);
+ const char *target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ refname,
+ RESOLVE_REF_READING,
+ NULL, NULL);
if (target)
strbuf_addf(buf, "ref: %s\n", strip_namespace(target));
@@ -588,14 +593,15 @@ static void get_head(struct strbuf *hdr, char *arg UNUSED)
struct strbuf buf = STRBUF_INIT;
select_getanyfile(hdr);
- head_ref_namespaced(show_head_ref, &buf);
+ refs_head_ref_namespaced(get_main_ref_store(the_repository),
+ show_head_ref, &buf);
send_strbuf(hdr, "text/plain", &buf);
strbuf_release(&buf);
}
static void get_info_packs(struct strbuf *hdr, char *arg UNUSED)
{
- size_t objdirlen = strlen(get_object_directory());
+ size_t objdirlen = strlen(repo_get_object_directory(the_repository));
struct strbuf buf = STRBUF_INIT;
struct packed_git *p;
size_t cnt = 0;
@@ -639,10 +645,15 @@ static void check_content_type(struct strbuf *hdr, const char *accepted_type)
static void service_rpc(struct strbuf *hdr, char *service_name)
{
- const char *argv[] = {NULL, "--stateless-rpc", ".", NULL};
+ struct strvec argv = STRVEC_INIT;
struct rpc_service *svc = select_service(hdr, service_name);
struct strbuf buf = STRBUF_INIT;
+ strvec_push(&argv, svc->name);
+ if (strcmp(service_name, "git-upload-archive"))
+ strvec_push(&argv, "--stateless-rpc");
+ strvec_push(&argv, ".");
+
strbuf_reset(&buf);
strbuf_addf(&buf, "application/x-git-%s-request", svc->name);
check_content_type(hdr, buf.buf);
@@ -655,9 +666,9 @@ static void service_rpc(struct strbuf *hdr, char *service_name)
end_headers(hdr);
- argv[0] = svc->name;
- run_service(argv, svc->buffer_input);
+ run_service(argv.v, svc->buffer_input);
strbuf_release(&buf);
+ strvec_clear(&argv);
}
static int dead;
@@ -723,6 +734,7 @@ static struct service_cmd {
{"GET", "/objects/pack/pack-[0-9a-f]{64}\\.idx$", get_idx_file},
{"POST", "/git-upload-pack$", service_rpc},
+ {"POST", "/git-upload-archive$", service_rpc},
{"POST", "/git-receive-pack$", service_rpc}
};
@@ -743,7 +755,7 @@ static int bad_request(struct strbuf *hdr, const struct service_cmd *c)
int cmd_main(int argc UNUSED, const char **argv UNUSED)
{
- char *method = getenv("REQUEST_METHOD");
+ const char *method = getenv("REQUEST_METHOD");
const char *proto_header;
char *dir;
struct service_cmd *cmd = NULL;
diff --git a/http-fetch.c b/http-fetch.c
index fffda59267..02ab80533f 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -1,12 +1,14 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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 "url.h"
#include "urlmatch.h"
#include "trace2.h"
@@ -104,6 +106,7 @@ int cmd_main(int argc, const char **argv)
int nongit;
struct object_id packfile_hash;
struct strvec index_pack_args = STRVEC_INIT;
+ int ret;
setup_git_directory_gently(&nongit);
@@ -127,8 +130,12 @@ int cmd_main(int argc, const char **argv)
} else if (skip_prefix(argv[arg], "--packfile=", &p)) {
const char *end;
+ if (nongit)
+ die(_("not a git repository"));
+
packfile = 1;
- if (parse_oid_hex(p, &packfile_hash, &end) || *end)
+ if (parse_oid_hex_algop(p, &packfile_hash, &end,
+ the_repository->hash_algo) || *end)
die(_("argument to --packfile must be a valid hash (got '%s')"), p);
} else if (skip_prefix(argv[arg], "--index-pack-arg=", &p)) {
strvec_push(&index_pack_args, p);
@@ -151,8 +158,8 @@ int cmd_main(int argc, const char **argv)
fetch_single_packfile(&packfile_hash, argv[arg],
index_pack_args.v);
-
- return 0;
+ ret = 0;
+ goto out;
}
if (index_pack_args.nr)
@@ -164,7 +171,12 @@ int cmd_main(int argc, const char **argv)
commit_id = (char **) &argv[arg++];
commits = 1;
}
- return fetch_using_walker(argv[arg], get_verbosely, get_recover,
- commits, commit_id, write_ref,
- commits_on_stdin);
+
+ ret = fetch_using_walker(argv[arg], get_verbosely, get_recover,
+ commits, commit_id, write_ref,
+ commits_on_stdin);
+
+out:
+ strvec_clear(&index_pack_args);
+ return ret;
}
diff --git a/http-push.c b/http-push.c
index a704f490fd..4d24e6b8d4 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "hex.h"
@@ -6,10 +8,8 @@
#include "tag.h"
#include "blob.h"
#include "http.h"
-#include "refs.h"
#include "diff.h"
#include "revision.h"
-#include "exec-cmd.h"
#include "remote.h"
#include "list-objects.h"
#include "setup.h"
@@ -17,6 +17,7 @@
#include "strvec.h"
#include "tree.h"
#include "tree-walk.h"
+#include "url.h"
#include "packfile.h"
#include "object-store-ll.h"
#include "commit-reach.h"
@@ -274,7 +275,7 @@ static void start_fetch_loose(struct transfer_request *request)
if (!start_active_slot(slot)) {
fprintf(stderr, "Unable to start GET request\n");
repo->can_update_info_refs = 0;
- release_http_object_request(obj_req);
+ release_http_object_request(&obj_req);
release_request(request);
}
}
@@ -308,7 +309,7 @@ static void start_fetch_packed(struct transfer_request *request)
struct transfer_request *check_request = request_queue_head;
struct http_pack_request *preq;
- target = find_sha1_pack(request->obj->oid.hash, repo->packs);
+ target = find_oid_pack(&request->obj->oid, repo->packs);
if (!target) {
fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", oid_to_hex(&request->obj->oid));
repo->can_update_info_refs = 0;
@@ -374,7 +375,7 @@ static void start_put(struct transfer_request *request)
/* Set it up */
git_deflate_init(&stream, zlib_compression_level);
size = git_deflate_bound(&stream, len + hdrlen);
- strbuf_init(&request->buffer.buf, size);
+ strbuf_grow(&request->buffer.buf, size);
request->buffer.posn = 0;
/* Compress it */
@@ -436,9 +437,11 @@ static void start_move(struct transfer_request *request)
if (start_active_slot(slot)) {
request->slot = slot;
request->state = RUN_MOVE;
+ request->headers = dav_headers;
} else {
request->state = ABORTED;
FREE_AND_NULL(request->url);
+ curl_slist_free_all(dav_headers);
}
}
@@ -511,6 +514,8 @@ static void release_request(struct transfer_request *request)
}
free(request->url);
+ free(request->dest);
+ strbuf_release(&request->buffer.buf);
free(request);
}
@@ -577,9 +582,10 @@ static void finish_request(struct transfer_request *request)
if (obj_req->rename == 0)
request->obj->flags |= (LOCAL | REMOTE);
+ release_http_object_request(&obj_req);
+
/* Try fetching packed if necessary */
if (request->obj->flags & LOCAL) {
- release_http_object_request(obj_req);
release_request(request);
} else
start_fetch_packed(request);
@@ -648,12 +654,10 @@ static void add_fetch_request(struct object *obj)
return;
obj->flags |= FETCHING;
- request = xmalloc(sizeof(*request));
+ CALLOC_ARRAY(request, 1);
request->obj = obj;
- request->url = NULL;
- request->lock = NULL;
- request->headers = NULL;
request->state = NEED_FETCH;
+ strbuf_init(&request->buffer.buf, 0);
request->next = request_queue_head;
request_queue_head = request;
@@ -677,19 +681,18 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
get_remote_object_list(obj->oid.hash[0]);
if (obj->flags & (REMOTE | PUSHING))
return 0;
- target = find_sha1_pack(obj->oid.hash, repo->packs);
+ target = find_oid_pack(&obj->oid, repo->packs);
if (target) {
obj->flags |= REMOTE;
return 0;
}
obj->flags |= PUSHING;
- request = xmalloc(sizeof(*request));
+ CALLOC_ARRAY(request, 1);
request->obj = obj;
- request->url = NULL;
request->lock = lock;
- request->headers = NULL;
request->state = NEED_PUSH;
+ strbuf_init(&request->buffer.buf, 0);
request->next = request_queue_head;
request_queue_head = request;
@@ -911,6 +914,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
result = XML_Parse(parser, in_buffer.buf,
in_buffer.len, 1);
free(ctx.name);
+ free(ctx.cdata);
if (result != XML_STATUS_OK) {
fprintf(stderr, "XML error: %s\n",
XML_ErrorString(
@@ -1017,6 +1021,7 @@ static void remote_ls(const char *path, int flags,
/* extract hex from sharded "xx/x{38}" filename */
static int get_oid_hex_from_objpath(const char *path, struct object_id *oid)
{
+ memset(oid->hash, 0, GIT_MAX_RAWSZ);
oid->algo = hash_algo_by_ptr(the_hash_algo);
if (strlen(path) != the_hash_algo->hexsz + 1)
@@ -1167,6 +1172,7 @@ static void remote_ls(const char *path, int flags,
result = XML_Parse(parser, in_buffer.buf,
in_buffer.len, 1);
free(ctx.name);
+ free(ctx.cdata);
if (result != XML_STATUS_OK) {
fprintf(stderr, "XML error: %s\n",
@@ -1180,6 +1186,7 @@ static void remote_ls(const char *path, int flags,
}
free(ls.path);
+ free(ls.dentry_name);
free(url);
strbuf_release(&out_buffer.buf);
strbuf_release(&in_buffer);
@@ -1308,7 +1315,7 @@ static struct object_list **process_tree(struct tree *tree,
obj->flags |= SEEN;
p = add_one_object(obj, p);
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry))
switch (object_type(entry.mode)) {
@@ -1368,9 +1375,13 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
}
while (objects) {
+ struct object_list *next = objects->next;
+
if (!(objects->item->flags & UNINTERESTING))
count += add_send_request(objects->item, lock);
- objects = objects->next;
+
+ free(objects);
+ objects = next;
}
return count;
@@ -1396,6 +1407,7 @@ static int update_remote(const struct object_id *oid, struct remote_lock *lock)
if (start_active_slot(slot)) {
run_active_slot(slot);
strbuf_release(&out_buffer.buf);
+ curl_slist_free_all(dav_headers);
if (results.curl_result != CURLE_OK) {
fprintf(stderr,
"PUT error: curl result=%d, HTTP code=%ld\n",
@@ -1405,6 +1417,7 @@ static int update_remote(const struct object_id *oid, struct remote_lock *lock)
}
} else {
strbuf_release(&out_buffer.buf);
+ curl_slist_free_all(dav_headers);
fprintf(stderr, "Unable to start PUT request\n");
return 0;
}
@@ -1514,6 +1527,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
results.curl_result, results.http_code);
}
}
+ curl_slist_free_all(dav_headers);
}
strbuf_release(&buffer.buf);
}
@@ -1553,7 +1567,7 @@ static void fetch_symref(const char *path, char **symref, struct object_id *oid)
free(url);
FREE_AND_NULL(*symref);
- oidclr(oid);
+ oidclr(oid, the_repository->hash_algo);
if (buffer.len == 0)
return;
@@ -1576,8 +1590,11 @@ static int verify_merge_base(struct object_id *head_oid, struct ref *remote)
struct commit *head = lookup_commit_or_die(head_oid, "HEAD");
struct commit *branch = lookup_commit_or_die(&remote->old_oid,
remote->name);
+ int ret = repo_in_merge_bases(the_repository, branch, head);
- return repo_in_merge_bases(the_repository, branch, head);
+ if (ret < 0)
+ exit(128);
+ return ret;
}
static int delete_remote_branch(const char *pattern, int force)
@@ -1702,7 +1719,7 @@ int cmd_main(int argc, const char **argv)
int rc = 0;
int i;
int new_refs;
- struct ref *ref, *local_refs;
+ struct ref *ref, *local_refs = NULL;
CALLOC_ARRAY(repo, 1);
@@ -1852,6 +1869,7 @@ int cmd_main(int argc, const char **argv)
if (oideq(&ref->old_oid, &ref->peer_ref->new_oid)) {
if (push_verbosely)
+ /* stable plumbing output; do not modify or localize */
fprintf(stderr, "'%s': up-to-date\n", ref->name);
if (helper_status)
printf("ok %s up to date\n", ref->name);
@@ -1872,6 +1890,7 @@ int cmd_main(int argc, const char **argv)
* commits at the remote end and likely
* we were not up to date to begin with.
*/
+ /* stable plumbing output; do not modify or localize */
error("remote '%s' is not an ancestor of\n"
"local '%s'.\n"
"Maybe you are not up-to-date and "
@@ -1965,6 +1984,7 @@ int cmd_main(int argc, const char **argv)
cleanup:
if (info_ref_lock)
unlock_remote(info_ref_lock);
+ free(repo->url);
free(repo);
http_cleanup();
@@ -1976,5 +1996,8 @@ int cmd_main(int argc, const char **argv)
request = next_request;
}
+ refspec_clear(&rs);
+ free_refs(local_refs);
+
return rc;
}
diff --git a/http-walker.c b/http-walker.c
index 78d99f7c4b..43cde0ebe5 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -1,6 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "repository.h"
-#include "commit.h"
#include "hex.h"
#include "walker.h"
#include "http.h"
@@ -73,7 +74,7 @@ static void start_object_request(struct object_request *obj_req)
obj_req->state = ACTIVE;
if (!start_active_slot(slot)) {
obj_req->state = ABORTED;
- release_http_object_request(req);
+ release_http_object_request(&req);
return;
}
}
@@ -109,7 +110,7 @@ static void process_object_response(void *callback_data)
if (obj_req->repo->next) {
obj_req->repo =
obj_req->repo->next;
- release_http_object_request(obj_req->req);
+ release_http_object_request(&obj_req->req);
start_object_request(obj_req);
return;
}
@@ -146,14 +147,14 @@ static int fill_active_slot(void *data UNUSED)
return 0;
}
-static void prefetch(struct walker *walker, unsigned char *sha1)
+static void prefetch(struct walker *walker, const struct object_id *oid)
{
struct object_request *newreq;
struct walker_data *data = walker->data;
newreq = xmalloc(sizeof(*newreq));
newreq->walker = walker;
- oidread(&newreq->oid, sha1);
+ oidcpy(&newreq->oid, oid);
newreq->repo = data->alt;
newreq->state = WAITING;
newreq->req = NULL;
@@ -421,7 +422,8 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)
return ret;
}
-static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
+static int http_fetch_pack(struct walker *walker, struct alt_base *repo,
+ const struct object_id *oid)
{
struct packed_git *target;
int ret;
@@ -430,7 +432,7 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigne
if (fetch_indices(walker, repo))
return -1;
- target = find_sha1_pack(sha1, repo->packs);
+ target = find_oid_pack(oid, repo->packs);
if (!target)
return -1;
close_pack_index(target);
@@ -439,7 +441,7 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigne
fprintf(stderr, "Getting pack %s\n",
hash_to_hex(target->hash));
fprintf(stderr, " which contains %s\n",
- hash_to_hex(sha1));
+ oid_to_hex(oid));
}
preq = new_http_pack_request(target->hash, repo->base);
@@ -476,9 +478,9 @@ static void abort_object_request(struct object_request *obj_req)
release_object_request(obj_req);
}
-static int fetch_object(struct walker *walker, unsigned char *hash)
+static int fetch_object(struct walker *walker, const struct object_id *oid)
{
- char *hex = hash_to_hex(hash);
+ char *hex = oid_to_hex(oid);
int ret = 0;
struct object_request *obj_req = NULL;
struct http_object_request *req;
@@ -486,7 +488,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
list_for_each(pos, head) {
obj_req = list_entry(pos, struct object_request, node);
- if (hasheq(obj_req->oid.hash, hash))
+ if (oideq(&obj_req->oid, oid))
break;
}
if (!obj_req)
@@ -494,7 +496,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
if (repo_has_object_file(the_repository, &obj_req->oid)) {
if (obj_req->req)
- abort_http_object_request(obj_req->req);
+ abort_http_object_request(&obj_req->req);
abort_object_request(obj_req);
return 0;
}
@@ -542,25 +544,25 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
strbuf_release(&buf);
}
- release_http_object_request(req);
+ release_http_object_request(&obj_req->req);
release_object_request(obj_req);
return ret;
}
-static int fetch(struct walker *walker, unsigned char *hash)
+static int fetch(struct walker *walker, const struct object_id *oid)
{
struct walker_data *data = walker->data;
struct alt_base *altbase = data->alt;
- if (!fetch_object(walker, hash))
+ if (!fetch_object(walker, oid))
return 0;
while (altbase) {
- if (!http_fetch_pack(walker, altbase, hash))
+ if (!http_fetch_pack(walker, altbase, oid))
return 0;
fetch_alternates(walker, data->alt->base);
altbase = altbase->next;
}
- return error("Unable to find %s under %s", hash_to_hex(hash),
+ return error("Unable to find %s under %s", oid_to_hex(oid),
data->alt->base);
}
@@ -578,8 +580,18 @@ static void cleanup(struct walker *walker)
if (data) {
alt = data->alt;
while (alt) {
+ struct packed_git *pack;
+
alt_next = alt->next;
+ pack = alt->packs;
+ while (pack) {
+ struct packed_git *pack_next = pack->next;
+ close_pack(pack);
+ free(pack);
+ pack = pack_next;
+ }
+
free(alt->base);
free(alt);
diff --git a/http.c b/http.c
index d1901dbcdc..58242b9d2d 100644
--- a/http.c
+++ b/http.c
@@ -1,10 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "git-curl-compat.h"
#include "hex.h"
#include "http.h"
#include "config.h"
#include "pack.h"
-#include "sideband.h"
#include "run-command.h"
#include "url.h"
#include "urlmatch.h"
@@ -15,10 +16,10 @@
#include "trace.h"
#include "transport.h"
#include "packfile.h"
-#include "protocol.h"
#include "string-list.h"
#include "object-file.h"
#include "object-store-ll.h"
+#include "tempfile.h"
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
static int trace_curl_data = 1;
@@ -40,11 +41,11 @@ char curl_errorstr[CURL_ERROR_SIZE];
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 char *curl_http_version;
+static char *ssl_cert;
+static char *ssl_cert_type;
+static char *ssl_cipherlist;
+static char *ssl_version;
static struct {
const char *name;
long ssl_version;
@@ -61,23 +62,23 @@ static struct {
{ "tlsv1.3", CURL_SSLVERSION_TLSv1_3 },
#endif
};
-static const char *ssl_key;
-static const char *ssl_key_type;
-static const char *ssl_capath;
-static const char *curl_no_proxy;
+static char *ssl_key;
+static char *ssl_key_type;
+static char *ssl_capath;
+static char *curl_no_proxy;
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
-static const char *ssl_pinnedkey;
+static char *ssl_pinnedkey;
#endif
-static const char *ssl_cainfo;
+static char *ssl_cainfo;
static long curl_low_speed_limit = -1;
static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv;
-static const char *curl_http_proxy;
-static const char *http_proxy_authmethod;
+static char *curl_http_proxy;
+static char *http_proxy_authmethod;
-static const char *http_proxy_ssl_cert;
-static const char *http_proxy_ssl_key;
-static const char *http_proxy_ssl_ca_info;
+static char *http_proxy_ssl_cert;
+static char *http_proxy_ssl_key;
+static char *http_proxy_ssl_ca_info;
static struct credential proxy_cert_auth = CREDENTIAL_INIT;
static int proxy_ssl_cert_password_required;
@@ -97,7 +98,7 @@ static struct {
*/
};
#ifdef CURLGSSAPI_DELEGATION_FLAG
-static const char *curl_deleg;
+static char *curl_deleg;
static struct {
const char *name;
long curl_deleg_param;
@@ -108,13 +109,20 @@ static struct {
};
#endif
+enum proactive_auth {
+ PROACTIVE_AUTH_NONE = 0,
+ PROACTIVE_AUTH_IF_CREDENTIALS,
+ PROACTIVE_AUTH_AUTO,
+ PROACTIVE_AUTH_BASIC,
+};
+
static struct credential proxy_auth = CREDENTIAL_INIT;
static const char *curl_proxyuserpwd;
-static const char *curl_cookie_file;
+static char *curl_cookie_file;
static int curl_save_cookies;
struct credential http_auth = CREDENTIAL_INIT;
-static int http_proactive_auth;
-static const char *user_agent;
+static enum proactive_auth http_proactive_auth;
+static char *user_agent;
static int curl_empty_auth = -1;
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
@@ -130,7 +138,6 @@ static unsigned long empty_auth_useless =
| CURLAUTH_DIGEST;
static struct curl_slist *pragma_header;
-static struct curl_slist *no_pragma_header;
static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
static struct curl_slist *host_resolutions;
@@ -149,6 +156,12 @@ static int http_schannel_check_revoke = 1;
*/
static int http_schannel_use_ssl_cainfo;
+static int always_auth_proactively(void)
+{
+ return http_proactive_auth != PROACTIVE_AUTH_NONE &&
+ http_proactive_auth != PROACTIVE_AUTH_IF_CREDENTIALS;
+}
+
size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
{
size_t size = eltsize * nmemb;
@@ -301,6 +314,11 @@ size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
return nmemb;
}
+static struct curl_slist *object_request_headers(void)
+{
+ return curl_slist_append(http_copy_default_headers(), "Pragma:");
+}
+
static void closedown_active_slot(struct active_request_slot *slot)
{
active_requests--;
@@ -535,6 +553,20 @@ static int http_options(const char *var, const char *value,
return 0;
}
+ if (!strcmp("http.proactiveauth", var)) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (!strcmp(value, "auto"))
+ http_proactive_auth = PROACTIVE_AUTH_AUTO;
+ else if (!strcmp(value, "basic"))
+ http_proactive_auth = PROACTIVE_AUTH_BASIC;
+ else if (!strcmp(value, "none"))
+ http_proactive_auth = PROACTIVE_AUTH_NONE;
+ else
+ warning(_("Unknown value for http.proactiveauth"));
+ return 0;
+ }
+
/* Fall back on the default ones */
return git_default_config(var, value, ctx, data);
}
@@ -559,42 +591,78 @@ static int curl_empty_auth_enabled(void)
return 0;
}
+struct curl_slist *http_append_auth_header(const struct credential *c,
+ struct curl_slist *headers)
+{
+ if (c->authtype && c->credential) {
+ struct strbuf auth = STRBUF_INIT;
+ strbuf_addf(&auth, "Authorization: %s %s",
+ c->authtype, c->credential);
+ headers = curl_slist_append(headers, auth.buf);
+ strbuf_release(&auth);
+ }
+ return headers;
+}
+
static void init_curl_http_auth(CURL *result)
{
- if (!http_auth.username || !*http_auth.username) {
- if (curl_empty_auth_enabled())
+ if ((!http_auth.username || !*http_auth.username) &&
+ (!http_auth.credential || !*http_auth.credential)) {
+ int empty_auth = curl_empty_auth_enabled();
+ if ((empty_auth != -1 && !always_auth_proactively()) || empty_auth == 1) {
curl_easy_setopt(result, CURLOPT_USERPWD, ":");
- return;
+ return;
+ } else if (!always_auth_proactively()) {
+ return;
+ } else if (http_proactive_auth == PROACTIVE_AUTH_BASIC) {
+ strvec_push(&http_auth.wwwauth_headers, "Basic");
+ }
}
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 1);
- curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
- curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+ if (http_auth.password) {
+ if (always_auth_proactively()) {
+ /*
+ * We got a credential without an authtype and we don't
+ * know what's available. Since our only two options at
+ * the moment are auto (which defaults to basic) and
+ * basic, use basic for now.
+ */
+ curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ }
+ curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
+ curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+ }
}
/* *var must be free-able */
-static void var_override(const char **var, char *value)
+static void var_override(char **var, char *value)
{
if (value) {
- free((void *)*var);
+ free(*var);
*var = xstrdup(value);
}
}
static void set_proxyauth_name_password(CURL *result)
{
+ if (proxy_auth.password) {
curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
proxy_auth.username);
curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
proxy_auth.password);
+ } else if (proxy_auth.authtype && proxy_auth.credential) {
+ curl_easy_setopt(result, CURLOPT_PROXYHEADER,
+ http_append_auth_header(&proxy_auth, NULL));
+ }
}
static void init_curl_proxy_auth(CURL *result)
{
if (proxy_auth.username) {
- if (!proxy_auth.password)
- credential_fill(&proxy_auth);
+ if (!proxy_auth.password && !proxy_auth.credential)
+ credential_fill(&proxy_auth, 1);
set_proxyauth_name_password(result);
}
@@ -628,7 +696,7 @@ static int has_cert_password(void)
cert_auth.host = xstrdup("");
cert_auth.username = xstrdup("");
cert_auth.path = xstrdup(ssl_cert);
- credential_fill(&cert_auth);
+ credential_fill(&cert_auth, 0);
}
return 1;
}
@@ -643,7 +711,7 @@ static int has_proxy_cert_password(void)
proxy_cert_auth.host = xstrdup("");
proxy_cert_auth.username = xstrdup("");
proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
- credential_fill(&proxy_cert_auth);
+ credential_fill(&proxy_cert_auth, 0);
}
return 1;
}
@@ -733,6 +801,7 @@ static int redact_sensitive_header(struct strbuf *header, size_t offset)
strbuf_setlen(header, sensitive_header - header->buf);
strbuf_addbuf(header, &redacted_header);
+ strbuf_release(&redacted_header);
ret = 1;
}
return ret;
@@ -1025,7 +1094,7 @@ static CURL *get_curl_handle(void)
#endif
}
- if (http_proactive_auth)
+ if (http_proactive_auth != PROACTIVE_AUTH_NONE)
init_curl_http_auth(result);
if (getenv("GIT_SSL_VERSION"))
@@ -1160,6 +1229,8 @@ static CURL *get_curl_handle(void)
*/
curl_easy_setopt(result, CURLOPT_PROXY, "");
} else if (curl_http_proxy) {
+ struct strbuf proxy = STRBUF_INIT;
+
if (starts_with(curl_http_proxy, "socks5h"))
curl_easy_setopt(result,
CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
@@ -1198,7 +1269,27 @@ static CURL *get_curl_handle(void)
if (!proxy_auth.host)
die("Invalid proxy URL '%s'", curl_http_proxy);
- curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
+ strbuf_addstr(&proxy, proxy_auth.host);
+ if (proxy_auth.path) {
+ curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
+
+ if (ver->version_num < 0x075400)
+ die("libcurl 7.84 or later is required to support paths in proxy URLs");
+
+ if (!starts_with(proxy_auth.protocol, "socks"))
+ die("Invalid proxy URL '%s': only SOCKS proxies support paths",
+ curl_http_proxy);
+
+ if (strcasecmp(proxy_auth.host, "localhost"))
+ die("Invalid proxy URL '%s': host must be localhost if a path is present",
+ curl_http_proxy);
+
+ strbuf_addch(&proxy, '/');
+ strbuf_add_percentencode(&proxy, proxy_auth.path, 0);
+ }
+ curl_easy_setopt(result, CURLOPT_PROXY, proxy.buf);
+ strbuf_release(&proxy);
+
var_override(&curl_no_proxy, getenv("NO_PROXY"));
var_override(&curl_no_proxy, getenv("no_proxy"));
curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy);
@@ -1210,11 +1301,13 @@ static CURL *get_curl_handle(void)
return result;
}
-static void set_from_env(const char **var, const char *envname)
+static void set_from_env(char **var, const char *envname)
{
const char *val = getenv(envname);
- if (val)
- *var = val;
+ if (val) {
+ FREE_AND_NULL(*var);
+ *var = xstrdup(val);
+ }
}
void http_init(struct remote *remote, const char *url, int proactive_auth)
@@ -1267,7 +1360,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
die("curl_global_init failed");
- http_proactive_auth = proactive_auth;
+ if (proactive_auth && http_proactive_auth == PROACTIVE_AUTH_NONE)
+ http_proactive_auth = PROACTIVE_AUTH_IF_CREDENTIALS;
if (remote && remote->http_proxy)
curl_http_proxy = xstrdup(remote->http_proxy);
@@ -1277,8 +1371,6 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
pragma_header = curl_slist_append(http_copy_default_headers(),
"Pragma: no-cache");
- no_pragma_header = curl_slist_append(http_copy_default_headers(),
- "Pragma:");
{
char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
@@ -1362,9 +1454,6 @@ void http_cleanup(void)
curl_slist_free_all(pragma_header);
pragma_header = NULL;
- curl_slist_free_all(no_pragma_header);
- no_pragma_header = NULL;
-
curl_slist_free_all(host_resolutions);
host_resolutions = NULL;
@@ -1444,7 +1533,16 @@ struct active_request_slot *get_active_slot(void)
slot->finished = NULL;
slot->callback_data = NULL;
slot->callback_func = NULL;
+
+ if (curl_cookie_file && !strcmp(curl_cookie_file, "-")) {
+ warning(_("refusing to read cookies from http.cookiefile '-'"));
+ FREE_AND_NULL(curl_cookie_file);
+ }
curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
+ if (curl_save_cookies && (!curl_cookie_file || !curl_cookie_file[0])) {
+ curl_save_cookies = 0;
+ warning(_("ignoring http.savecookies for empty http.cookiefile"));
+ }
if (curl_save_cookies)
curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
@@ -1472,7 +1570,7 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
- if (http_auth.password || curl_empty_auth_enabled())
+ if (http_auth.password || http_auth.credential || curl_empty_auth_enabled())
init_curl_http_auth(slot->curl);
return slot;
@@ -1611,7 +1709,7 @@ void run_active_slot(struct active_request_slot *slot)
* The value of slot->finished we set before the loop was used
* to set our "finished" variable when our request completed.
*
- * 1. The slot may not have been reused for another requst
+ * 1. The slot may not have been reused for another request
* yet, in which case it still has &finished.
*
* 2. The slot may already be in-use to serve another request,
@@ -1761,8 +1859,15 @@ static int handle_curl_result(struct slot_results *results)
} else if (missing_target(results))
return HTTP_MISSING_TARGET;
else if (results->http_code == 401) {
- if (http_auth.username && http_auth.password) {
+ if ((http_auth.username && http_auth.password) ||\
+ (http_auth.authtype && http_auth.credential)) {
+ if (http_auth.multistage) {
+ credential_clear_secrets(&http_auth);
+ return HTTP_REAUTH;
+ }
credential_reject(&http_auth);
+ if (always_auth_proactively())
+ http_proactive_auth = PROACTIVE_AUTH_NONE;
return HTTP_NOAUTH;
} else {
http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
@@ -1903,7 +2008,7 @@ static void write_accept_language(struct strbuf *buf)
* MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than
* that, q-value will be smaller than 0.001, the minimum q-value the
* HTTP specification allows. See
- * http://tools.ietf.org/html/rfc7231#section-5.3.1 for q-value.
+ * https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1 for q-value.
*/
const int MAX_DECIMAL_PLACES = 3;
const int MAX_LANGUAGE_TAGS = 1000;
@@ -1949,7 +2054,7 @@ static void write_accept_language(struct strbuf *buf)
/* add '*' */
REALLOC_ARRAY(language_tags, num_langs + 1);
- language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */
+ language_tags[num_langs++] = xstrdup("*");
/* compute decimal_places */
for (max_q = 1, decimal_places = 0;
@@ -1979,8 +2084,7 @@ static void write_accept_language(struct strbuf *buf)
}
}
- /* free language tags -- last one is a static '*' */
- for (i = 0; i < num_langs - 1; i++)
+ for (i = 0; i < num_langs; i++)
free(language_tags[i]);
free(language_tags);
}
@@ -2069,11 +2173,15 @@ static int http_request(const char *url,
/* Add additional headers here */
if (options && options->extra_headers) {
const struct string_list_item *item;
- for_each_string_list_item(item, options->extra_headers) {
- headers = curl_slist_append(headers, item->string);
+ if (options && options->extra_headers) {
+ for_each_string_list_item(item, options->extra_headers) {
+ headers = curl_slist_append(headers, item->string);
+ }
}
}
+ headers = http_append_auth_header(&http_auth, headers);
+
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
@@ -2155,7 +2263,13 @@ static int http_request_reauth(const char *url,
void *result, int target,
struct http_get_options *options)
{
- int ret = http_request(url, result, target, options);
+ int i = 3;
+ int ret;
+
+ if (always_auth_proactively())
+ credential_fill(&http_auth, 1);
+
+ ret = http_request(url, result, target, options);
if (ret != HTTP_OK && ret != HTTP_REAUTH)
return ret;
@@ -2168,35 +2282,37 @@ static int http_request_reauth(const char *url,
}
}
- if (ret != HTTP_REAUTH)
- return ret;
-
- /*
- * The previous request may have put cruft into our output stream; we
- * should clear it out before making our next request.
- */
- switch (target) {
- case HTTP_REQUEST_STRBUF:
- strbuf_reset(result);
- break;
- case HTTP_REQUEST_FILE:
- if (fflush(result)) {
- error_errno("unable to flush a file");
- return HTTP_START_FAILED;
+ while (ret == HTTP_REAUTH && --i) {
+ /*
+ * The previous request may have put cruft into our output stream; we
+ * should clear it out before making our next request.
+ */
+ switch (target) {
+ case HTTP_REQUEST_STRBUF:
+ strbuf_reset(result);
+ break;
+ case HTTP_REQUEST_FILE: {
+ FILE *f = result;
+ if (fflush(f)) {
+ error_errno("unable to flush a file");
+ return HTTP_START_FAILED;
+ }
+ rewind(f);
+ if (ftruncate(fileno(f), 0) < 0) {
+ error_errno("unable to truncate a file");
+ return HTTP_START_FAILED;
+ }
+ break;
}
- rewind(result);
- if (ftruncate(fileno(result), 0) < 0) {
- error_errno("unable to truncate a file");
- return HTTP_START_FAILED;
+ default:
+ BUG("Unknown http_request target");
}
- break;
- default:
- BUG("Unknown http_request target");
- }
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 1);
- return http_request(url, result, target, options);
+ ret = http_request(url, result, target, options);
+ }
+ return ret;
}
int http_get_strbuf(const char *url,
@@ -2275,8 +2391,24 @@ static char *fetch_pack_index(unsigned char *hash, const char *base_url)
strbuf_addf(&buf, "objects/pack/pack-%s.idx", hash_to_hex(hash));
url = strbuf_detach(&buf, NULL);
- strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(hash));
- tmp = strbuf_detach(&buf, NULL);
+ /*
+ * Don't put this into packs/, since it's just temporary and we don't
+ * want to confuse it with our local .idx files. We'll generate our
+ * own index if we choose to download the matching packfile.
+ *
+ * It's tempting to use xmks_tempfile() here, but it's important that
+ * the file not exist, otherwise http_get_file() complains. So we
+ * create a filename that should be unique, and then just register it
+ * as a tempfile so that it will get cleaned up on exit.
+ *
+ * In theory we could hold on to the tempfile and delete these as soon
+ * as we download the matching pack, but it would take a bit of
+ * refactoring. Leaving them until the process ends is probably OK.
+ */
+ tmp = xstrfmt("%s/tmp_pack_%s.idx",
+ repo_get_object_directory(the_repository),
+ hash_to_hex(hash));
+ register_tempfile(tmp);
if (http_get_file(url, tmp, NULL) != HTTP_OK) {
error("Unable to get pack index %s", url);
@@ -2290,15 +2422,17 @@ static char *fetch_pack_index(unsigned char *hash, const char *base_url)
static int fetch_and_setup_pack_index(struct packed_git **packs_head,
unsigned char *sha1, const char *base_url)
{
- struct packed_git *new_pack;
+ struct packed_git *new_pack, *p;
char *tmp_idx = NULL;
int ret;
- if (has_pack_index(sha1)) {
- new_pack = parse_pack_index(sha1, sha1_pack_index_name(sha1));
- if (!new_pack)
- return -1; /* parse_pack_index() already issued error message */
- goto add_pack;
+ /*
+ * If we already have the pack locally, no need to fetch its index or
+ * even add it to list; we already have all of its objects.
+ */
+ for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (hasheq(p->hash, sha1, the_repository->hash_algo))
+ return 0;
}
tmp_idx = fetch_pack_index(sha1, base_url);
@@ -2314,15 +2448,12 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
}
ret = verify_pack_index(new_pack);
- if (!ret) {
+ if (!ret)
close_pack_index(new_pack);
- ret = finalize_object_file(tmp_idx, sha1_pack_index_name(sha1));
- }
free(tmp_idx);
if (ret)
return -1;
-add_pack:
new_pack->next = *packs_head;
*packs_head = new_pack;
return 0;
@@ -2362,6 +2493,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
cleanup:
free(url);
+ strbuf_release(&buf);
return ret;
}
@@ -2373,6 +2505,7 @@ void release_http_pack_request(struct http_pack_request *preq)
}
preq->slot = NULL;
strbuf_release(&preq->tmpfile);
+ curl_slist_free_all(preq->headers);
free(preq->url);
free(preq);
}
@@ -2448,7 +2581,8 @@ struct http_pack_request *new_direct_http_pack_request(
preq->url = url;
- strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(packed_git_hash));
+ odb_pack_name(&preq->tmpfile, packed_git_hash, "pack");
+ strbuf_addstr(&preq->tmpfile, ".temp");
preq->packfile = fopen(preq->tmpfile.buf, "a");
if (!preq->packfile) {
error("Unable to open local file %s for pack",
@@ -2457,11 +2591,11 @@ struct http_pack_request *new_direct_http_pack_request(
}
preq->slot = get_active_slot();
+ preq->headers = object_request_headers();
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEDATA, preq->packfile);
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
- curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
- no_pragma_header);
+ curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers);
/*
* If there is data present from a previous transfer attempt,
@@ -2612,6 +2746,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
* file; also rewind to the beginning of the local file.
*/
if (prev_read == -1) {
+ git_inflate_end(&freq->stream);
memset(&freq->stream, 0, sizeof(freq->stream));
git_inflate_init(&freq->stream);
the_hash_algo->init_fn(&freq->c);
@@ -2627,13 +2762,14 @@ struct http_object_request *new_http_object_request(const char *base_url,
}
freq->slot = get_active_slot();
+ freq->headers = object_request_headers();
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEDATA, freq);
curl_easy_setopt(freq->slot->curl, CURLOPT_FAILONERROR, 0);
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
- curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
+ curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, freq->headers);
/*
* If we have successfully processed data from a previous fetch
@@ -2684,7 +2820,6 @@ int finish_http_object_request(struct http_object_request *freq)
return -1;
}
- git_inflate_end(&freq->stream);
the_hash_algo->final_oid_fn(&freq->real_oid, &freq->c);
if (freq->zret != Z_STREAM_END) {
unlink_or_warn(freq->tmpfile.buf);
@@ -2701,15 +2836,17 @@ int finish_http_object_request(struct http_object_request *freq)
return freq->rename;
}
-void abort_http_object_request(struct http_object_request *freq)
+void abort_http_object_request(struct http_object_request **freq_p)
{
+ struct http_object_request *freq = *freq_p;
unlink_or_warn(freq->tmpfile.buf);
- release_http_object_request(freq);
+ release_http_object_request(freq_p);
}
-void release_http_object_request(struct http_object_request *freq)
+void release_http_object_request(struct http_object_request **freq_p)
{
+ struct http_object_request *freq = *freq_p;
if (freq->localfile != -1) {
close(freq->localfile);
freq->localfile = -1;
@@ -2721,5 +2858,10 @@ void release_http_object_request(struct http_object_request *freq)
release_active_slot(freq->slot);
freq->slot = NULL;
}
+ curl_slist_free_all(freq->headers);
strbuf_release(&freq->tmpfile);
+ git_inflate_end(&freq->stream);
+
+ free(freq);
+ *freq_p = NULL;
}
diff --git a/http.h b/http.h
index 3a409bccd4..46e334c2c2 100644
--- a/http.h
+++ b/http.h
@@ -10,7 +10,6 @@ struct packed_git;
#include "strbuf.h"
#include "remote.h"
-#include "url.h"
#define DEFAULT_MAX_REQUESTS 5
@@ -176,6 +175,9 @@ int http_get_file(const char *url, const char *filename,
int http_fetch_ref(const char *base, struct ref *ref);
+struct curl_slist *http_append_auth_header(const struct credential *c,
+ struct curl_slist *headers);
+
/* Helpers for fetching packs */
int http_get_info_packs(const char *base_url,
struct packed_git **packs_head);
@@ -197,6 +199,7 @@ struct http_pack_request {
FILE *packfile;
struct strbuf tmpfile;
struct active_request_slot *slot;
+ struct curl_slist *headers;
};
struct http_pack_request *new_http_pack_request(
@@ -230,14 +233,15 @@ struct http_object_request {
int zret;
int rename;
struct active_request_slot *slot;
+ struct curl_slist *headers;
};
struct http_object_request *new_http_object_request(
const char *base_url, const struct object_id *oid);
void process_http_object_request(struct http_object_request *freq);
int finish_http_object_request(struct http_object_request *freq);
-void abort_http_object_request(struct http_object_request *freq);
-void release_http_object_request(struct http_object_request *freq);
+void abort_http_object_request(struct http_object_request **freq);
+void release_http_object_request(struct http_object_request **freq);
/*
* Instead of using environment variables to determine if curl tracing happens,
diff --git a/ident.c b/ident.c
index cc7afdbf81..caf41fb2a9 100644
--- a/ident.c
+++ b/ident.c
@@ -46,9 +46,9 @@ static struct passwd *xgetpwuid_self(int *is_bogus)
pw = getpwuid(getuid());
if (!pw) {
static struct passwd fallback;
- fallback.pw_name = "unknown";
+ fallback.pw_name = (char *) "unknown";
#ifndef NO_GECOS_IN_PWENT
- fallback.pw_gecos = "Unknown";
+ fallback.pw_gecos = (char *) "Unknown";
#endif
pw = &fallback;
if (is_bogus)
diff --git a/imap-send.c b/imap-send.c
index 06386e0b3b..488c06e613 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -18,21 +18,19 @@
* 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "credential.h"
-#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
#ifdef USE_CURL_FOR_IMAP_SEND
#include "http.h"
#endif
@@ -69,44 +67,26 @@ static void imap_warn(const char *, ...);
static char *next_arg(char **);
-__attribute__((format (printf, 3, 4)))
-static int nfsnprintf(char *buf, int blen, const char *fmt, ...);
-
-static int nfvasprintf(char **strp, const char *fmt, va_list ap)
-{
- int len;
- char tmp[8192];
-
- len = vsnprintf(tmp, sizeof(tmp), fmt, ap);
- if (len < 0)
- die("Fatal: Out of memory");
- if (len >= sizeof(tmp))
- die("imap command overflow!");
- *strp = xmemdupz(tmp, len);
- return len;
-}
-
struct imap_server_conf {
- const char *name;
- const char *tunnel;
- const char *host;
+ char *tunnel;
+ char *host;
int port;
- const char *folder;
- const char *user;
- const char *pass;
+ char *folder;
+ char *user;
+ char *pass;
int use_ssl;
int ssl_verify;
int use_html;
- const char *auth_method;
-};
-
-static struct imap_server_conf server = {
- .ssl_verify = 1,
+ char *auth_method;
};
struct imap_socket {
int fd[2];
+#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
+ void *ssl;
+#else
SSL *ssl;
+#endif
};
struct imap_buffer {
@@ -128,6 +108,7 @@ struct imap {
};
struct imap_store {
+ const struct imap_server_conf *cfg;
/* currently open mailbox */
const char *name; /* foreign! maybe preset? */
int uidvalidity;
@@ -206,10 +187,14 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
else
fprintf(stderr, "%s: unexpected EOF\n", func);
}
+ /* mark as used to appease -Wunused-parameter with NO_OPENSSL */
+ (void)sock;
}
#ifdef NO_OPENSSL
-static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+static int ssl_socket_connect(struct imap_socket *sock UNUSED,
+ const struct imap_server_conf *cfg UNUSED,
+ int use_tls_only UNUSED)
{
fprintf(stderr, "SSL requested but SSL support not compiled in\n");
return -1;
@@ -264,7 +249,9 @@ static int verify_hostname(X509 *cert, const char *hostname)
cname, hostname);
}
-static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+static int ssl_socket_connect(struct imap_socket *sock,
+ const struct imap_server_conf *cfg,
+ int use_tls_only)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
const SSL_METHOD *meth;
@@ -293,7 +280,7 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
if (use_tls_only)
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
- if (verify)
+ if (cfg->ssl_verify)
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
if (!SSL_CTX_set_default_verify_paths(ctx)) {
@@ -320,9 +307,9 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
* OpenSSL does not document this function, but the implementation
* returns 1 on success, 0 on failure after calling SSLerr().
*/
- ret = SSL_set_tlsext_host_name(sock->ssl, server.host);
+ ret = SSL_set_tlsext_host_name(sock->ssl, cfg->host);
if (ret != 1)
- warning("SSL_set_tlsext_host_name(%s) failed.", server.host);
+ warning("SSL_set_tlsext_host_name(%s) failed.", cfg->host);
#endif
ret = SSL_connect(sock->ssl);
@@ -331,12 +318,12 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
return -1;
}
- if (verify) {
+ if (cfg->ssl_verify) {
/* make sure the hostname matches that of the certificate */
cert = SSL_get_peer_certificate(sock->ssl);
if (!cert)
return error("unable to get peer certificate.");
- if (verify_hostname(cert, server.host) < 0)
+ if (verify_hostname(cert, cfg->host) < 0)
return -1;
}
@@ -497,30 +484,17 @@ static char *next_arg(char **s)
return ret;
}
-__attribute__((format (printf, 3, 4)))
-static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
-{
- int ret;
- va_list va;
-
- va_start(va, fmt);
- if (blen <= 0 || (unsigned)(ret = vsnprintf(buf, blen, fmt, va)) >= (unsigned)blen)
- BUG("buffer too small. Please report a bug.");
- va_end(va);
- return ret;
-}
-
static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
struct imap_cmd_cb *cb,
const char *fmt, va_list ap)
{
struct imap *imap = ctx->imap;
struct imap_cmd *cmd;
- int n, bufl;
- char buf[1024];
+ int n;
+ struct strbuf buf = STRBUF_INIT;
cmd = xmalloc(sizeof(struct imap_cmd));
- nfvasprintf(&cmd->cmd, fmt, ap);
+ cmd->cmd = xstrvfmt(fmt, ap);
cmd->tag = ++imap->nexttag;
if (cb)
@@ -532,27 +506,30 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
get_cmd_result(ctx, NULL);
if (!cmd->cb.data)
- bufl = nfsnprintf(buf, sizeof(buf), "%d %s\r\n", cmd->tag, cmd->cmd);
+ strbuf_addf(&buf, "%d %s\r\n", cmd->tag, cmd->cmd);
else
- bufl = nfsnprintf(buf, sizeof(buf), "%d %s{%d%s}\r\n",
- cmd->tag, cmd->cmd, cmd->cb.dlen,
- CAP(LITERALPLUS) ? "+" : "");
+ strbuf_addf(&buf, "%d %s{%d%s}\r\n", cmd->tag, cmd->cmd,
+ cmd->cb.dlen, CAP(LITERALPLUS) ? "+" : "");
+ if (buf.len > INT_MAX)
+ die("imap command overflow!");
if (0 < verbosity) {
if (imap->num_in_progress)
printf("(%d in progress) ", imap->num_in_progress);
if (!starts_with(cmd->cmd, "LOGIN"))
- printf(">>> %s", buf);
+ printf(">>> %s", buf.buf);
else
printf(">>> %d LOGIN <user> <pass>\n", cmd->tag);
}
- if (socket_write(&imap->buf.sock, buf, bufl) != bufl) {
+ if (socket_write(&imap->buf.sock, buf.buf, buf.len) != buf.len) {
free(cmd->cmd);
free(cmd);
if (cb)
free(cb->data);
+ strbuf_release(&buf);
return NULL;
}
+ strbuf_release(&buf);
if (cmd->cb.data) {
if (CAP(LITERALPLUS)) {
n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen);
@@ -691,12 +668,12 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
return RESP_BAD;
}
if (!strcmp("UIDVALIDITY", arg)) {
- if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg))) {
+ if (!(arg = next_arg(&s)) || strtol_i(arg, 10, &ctx->uidvalidity) || !ctx->uidvalidity) {
fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n");
return RESP_BAD;
}
} else if (!strcmp("UIDNEXT", arg)) {
- if (!(arg = next_arg(&s)) || !(imap->uidnext = atoi(arg))) {
+ if (!(arg = next_arg(&s)) || strtol_i(arg, 10, &imap->uidnext) || !imap->uidnext) {
fprintf(stderr, "IMAP error: malformed NEXTUID status\n");
return RESP_BAD;
}
@@ -709,8 +686,8 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
for (; isspace((unsigned char)*p); p++);
fprintf(stderr, "*** IMAP ALERT *** %s\n", p);
} else if (cb && cb->ctx && !strcmp("APPENDUID", arg)) {
- if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg)) ||
- !(arg = next_arg(&s)) || !(*(int *)cb->ctx = atoi(arg))) {
+ if (!(arg = next_arg(&s)) || strtol_i(arg, 10, &ctx->uidvalidity) || !ctx->uidvalidity ||
+ !(arg = next_arg(&s)) || strtol_i(arg, 10, (int *)cb->ctx) || !cb->ctx) {
fprintf(stderr, "IMAP error: malformed APPENDUID status\n");
return RESP_BAD;
}
@@ -796,7 +773,10 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
if (!tcmd)
return DRV_OK;
} else {
- tag = atoi(arg);
+ if (strtol_i(arg, 10, &tag)) {
+ fprintf(stderr, "IMAP error: malformed tag %s\n", arg);
+ return RESP_BAD;
+ }
for (pcmdp = &imap->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next)
if (cmdp->tag == tag)
goto gottag;
@@ -856,7 +836,7 @@ static void imap_close_store(struct imap_store *ctx)
/*
* hexchar() and cram() functions are based on the code from the isync
- * project (http://isync.sf.net/).
+ * project (https://isync.sourceforge.io/).
*/
static char hexchar(unsigned int b)
{
@@ -904,7 +884,9 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)
#else
-static char *cram(const char *challenge_64, const char *user, const char *pass)
+static char *cram(const char *challenge_64 UNUSED,
+ const char *user UNUSED,
+ const char *pass UNUSED)
{
die("If you want to use CRAM-MD5 authenticate method, "
"you have to build git-imap-send with OpenSSL library.");
@@ -917,7 +899,7 @@ static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
int ret;
char *response;
- response = cram(prompt, server.user, server.pass);
+ response = cram(prompt, ctx->cfg->user, ctx->cfg->pass);
ret = socket_write(&ctx->imap->buf.sock, response, strlen(response));
if (ret != strlen(response))
@@ -939,7 +921,7 @@ static void server_fill_credential(struct imap_server_conf *srvc, struct credent
cred->username = xstrdup_or_null(srvc->user);
cred->password = xstrdup_or_null(srvc->pass);
- credential_fill(cred);
+ credential_fill(cred, 1);
if (!srvc->user)
srvc->user = xstrdup(cred->username);
@@ -957,6 +939,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
CALLOC_ARRAY(ctx, 1);
+ ctx->cfg = srvc;
ctx->imap = CALLOC_ARRAY(imap, 1);
imap->buf.sock.fd[0] = imap->buf.sock.fd[1] = -1;
imap->in_progress_append = &imap->in_progress;
@@ -1057,7 +1040,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
imap->buf.sock.fd[1] = dup(s);
if (srvc->use_ssl &&
- ssl_socket_connect(&imap->buf.sock, 0, srvc->ssl_verify)) {
+ ssl_socket_connect(&imap->buf.sock, srvc, 0)) {
close(s);
goto bail;
}
@@ -1090,8 +1073,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
if (!srvc->use_ssl && CAP(STARTTLS)) {
if (imap_exec(ctx, NULL, "STARTTLS") != RESP_OK)
goto bail;
- if (ssl_socket_connect(&imap->buf.sock, 1,
- srvc->ssl_verify))
+ if (ssl_socket_connect(&imap->buf.sock, srvc, 1))
goto bail;
/* capabilities may have changed, so get the new capabilities */
if (imap_exec(ctx, NULL, "CAPABILITY") != RESP_OK)
@@ -1237,9 +1219,9 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
static void wrap_in_html(struct strbuf *msg)
{
struct strbuf buf = STRBUF_INIT;
- static char *content_type = "Content-Type: text/html;\n";
- static char *pre_open = "<pre>\n";
- static char *pre_close = "</pre>\n";
+ static const char *content_type = "Content-Type: text/html;\n";
+ static const char *pre_open = "<pre>\n";
+ static const char *pre_close = "</pre>\n";
const char *body = strstr(msg->buf, "\n\n");
if (!body)
@@ -1321,39 +1303,46 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
static int git_imap_config(const char *var, const char *val,
const struct config_context *ctx, void *cb)
{
-
- if (!strcmp("imap.sslverify", var))
- server.ssl_verify = git_config_bool(var, val);
- else if (!strcmp("imap.preformattedhtml", var))
- server.use_html = git_config_bool(var, val);
- else if (!strcmp("imap.folder", var))
- return git_config_string(&server.folder, var, val);
- else if (!strcmp("imap.user", var))
- return git_config_string(&server.user, var, val);
- else if (!strcmp("imap.pass", var))
- return git_config_string(&server.pass, var, val);
- else if (!strcmp("imap.tunnel", var))
- return git_config_string(&server.tunnel, var, val);
- 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, ctx->kvi);
- else if (!strcmp("imap.host", var)) {
+ struct imap_server_conf *cfg = cb;
+
+ if (!strcmp("imap.sslverify", var)) {
+ cfg->ssl_verify = git_config_bool(var, val);
+ } else if (!strcmp("imap.preformattedhtml", var)) {
+ cfg->use_html = git_config_bool(var, val);
+ } else if (!strcmp("imap.folder", var)) {
+ FREE_AND_NULL(cfg->folder);
+ return git_config_string(&cfg->folder, var, val);
+ } else if (!strcmp("imap.user", var)) {
+ FREE_AND_NULL(cfg->folder);
+ return git_config_string(&cfg->user, var, val);
+ } else if (!strcmp("imap.pass", var)) {
+ FREE_AND_NULL(cfg->folder);
+ return git_config_string(&cfg->pass, var, val);
+ } else if (!strcmp("imap.tunnel", var)) {
+ FREE_AND_NULL(cfg->folder);
+ return git_config_string(&cfg->tunnel, var, val);
+ } else if (!strcmp("imap.authmethod", var)) {
+ FREE_AND_NULL(cfg->folder);
+ return git_config_string(&cfg->auth_method, var, val);
+ } else if (!strcmp("imap.port", var)) {
+ cfg->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'");
+ return config_error_nonbool(var);
} else {
if (starts_with(val, "imap:"))
val += 5;
else if (starts_with(val, "imaps:")) {
val += 6;
- server.use_ssl = 1;
+ cfg->use_ssl = 1;
}
if (starts_with(val, "//"))
val += 2;
- server.host = xstrdup(val);
+ cfg->host = xstrdup(val);
}
- } else
+ } else {
return git_default_config(var, val, ctx, cb);
+ }
return 0;
}
@@ -1519,12 +1508,16 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
int cmd_main(int argc, const char **argv)
{
+ struct imap_server_conf server = {
+ .ssl_verify = 1,
+ };
struct strbuf all_msgs = STRBUF_INIT;
int total;
int nongit_ok;
+ int ret;
setup_git_directory_gently(&nongit_ok);
- git_config(git_imap_config, NULL);
+ git_config(git_imap_config, &server);
argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
@@ -1548,42 +1541,56 @@ int cmd_main(int argc, const char **argv)
if (!server.folder) {
fprintf(stderr, "no imap store specified\n");
- return 1;
+ ret = 1;
+ goto out;
}
if (!server.host) {
if (!server.tunnel) {
fprintf(stderr, "no imap host specified\n");
- return 1;
+ ret = 1;
+ goto out;
}
- server.host = "tunnel";
+ server.host = xstrdup("tunnel");
}
/* read the messages */
if (strbuf_read(&all_msgs, 0, 0) < 0) {
error_errno(_("could not read from stdin"));
- return 1;
+ ret = 1;
+ goto out;
}
if (all_msgs.len == 0) {
fprintf(stderr, "nothing to send\n");
- return 1;
+ ret = 1;
+ goto out;
}
total = count_messages(&all_msgs);
if (!total) {
fprintf(stderr, "no messages to send\n");
- return 1;
+ ret = 1;
+ goto out;
}
/* write it to the imap server */
if (server.tunnel)
- return append_msgs_to_imap(&server, &all_msgs, total);
-
+ ret = append_msgs_to_imap(&server, &all_msgs, total);
#ifdef USE_CURL_FOR_IMAP_SEND
- if (use_curl)
- return curl_append_msgs_to_imap(&server, &all_msgs, total);
+ else if (use_curl)
+ ret = curl_append_msgs_to_imap(&server, &all_msgs, total);
#endif
-
- return append_msgs_to_imap(&server, &all_msgs, total);
+ else
+ ret = append_msgs_to_imap(&server, &all_msgs, total);
+
+out:
+ free(server.tunnel);
+ free(server.host);
+ free(server.folder);
+ free(server.user);
+ free(server.pass);
+ free(server.auth_method);
+ strbuf_release(&all_msgs);
+ return ret;
}
diff --git a/json-writer.c b/json-writer.c
index 005c820aa4..25b9201f9c 100644
--- a/json-writer.c
+++ b/json-writer.c
@@ -46,10 +46,7 @@ static void append_quoted_string(struct strbuf *out, const char *in)
static void indent_pretty(struct json_writer *jw)
{
- int k;
-
- for (k = 0; k < jw->open_stack.len; k++)
- strbuf_addstr(&jw->json, " ");
+ strbuf_addstrings(&jw->json, " ", jw->open_stack.len);
}
/*
diff --git a/json-writer.h b/json-writer.h
index 209355e0f1..04413bd1af 100644
--- a/json-writer.h
+++ b/json-writer.h
@@ -3,8 +3,8 @@
/*
* JSON data structures are defined at:
- * [1] http://www.ietf.org/rfc/rfc7159.txt
- * [2] http://json.org/
+ * [1] https://www.ietf.org/rfc/rfc7159.txt
+ * [2] https://www.json.org/
*
* The JSON-writer API allows one to build JSON data structures using a
* simple wrapper around a "struct strbuf" buffer. It is intended as a
diff --git a/kwset.c b/kwset.c
index bbfcf815a5..695e47b7cc 100644
--- a/kwset.c
+++ b/kwset.c
@@ -18,7 +18,7 @@
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/>. */
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
/* Written August 1989 by Mike Haertel.
The author may be reached (Email) at the address mike@ai.mit.edu,
diff --git a/kwset.h b/kwset.h
index d42a793a30..c722664e5a 100644
--- a/kwset.h
+++ b/kwset.h
@@ -20,7 +20,7 @@
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/>. */
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
/* Written August 1989 by Mike Haertel.
The author may be reached (Email) at the address mike@ai.mit.edu,
diff --git a/line-log.c b/line-log.c
index 24a1ecb677..bc67b75d10 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1,8 +1,8 @@
#include "git-compat-util.h"
+#include "diffcore.h"
#include "line-range.h"
#include "hex.h"
#include "tag.h"
-#include "blob.h"
#include "tree.h"
#include "diff.h"
#include "commit.h"
@@ -12,8 +12,6 @@
#include "xdiff-interface.h"
#include "strbuf.h"
#include "log-tree.h"
-#include "graph.h"
-#include "userdiff.h"
#include "line-log.h"
#include "setup.h"
#include "strvec.h"
@@ -250,8 +248,10 @@ static void line_log_data_init(struct line_log_data *r)
static void line_log_data_clear(struct line_log_data *r)
{
range_set_release(&r->ranges);
+ free(r->path);
if (r->pair)
diff_free_filepair(r->pair);
+ diff_ranges_release(&r->diff);
}
static void free_line_log_data(struct line_log_data *r)
@@ -573,7 +573,8 @@ parse_lines(struct repository *r, struct commit *commit,
struct line_log_data *p;
for_each_string_list_item(item, args) {
- const char *name_part, *range_part;
+ const char *name_part;
+ char *range_part;
char *full_name;
struct diff_filespec *spec;
long begin = 0, end = 0;
@@ -617,6 +618,7 @@ parse_lines(struct repository *r, struct commit *commit,
free_filespec(spec);
FREE_AND_NULL(ends);
+ free(range_part);
}
for (p = ranges; p; p = p->next)
@@ -762,15 +764,13 @@ static void parse_pathspec_from_ranges(struct pathspec *pathspec,
{
struct line_log_data *r;
struct strvec array = STRVEC_INIT;
- const char **paths;
for (r = range; r; r = r->next)
strvec_push(&array, r->path);
- paths = strvec_detach(&array);
- parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL, "", paths);
- /* strings are now owned by pathspec */
- free(paths);
+ parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL, "", array.v);
+
+ strvec_clear(&array);
}
void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args)
@@ -783,21 +783,22 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list
add_line_range(rev, commit, range);
parse_pathspec_from_ranges(&rev->diffopt.pathspec, range);
+
+ free_line_log_data(range);
}
static void move_diff_queue(struct diff_queue_struct *dst,
struct diff_queue_struct *src)
{
assert(src != dst);
- memcpy(dst, src, sizeof(struct diff_queue_struct));
- DIFF_QUEUE_CLEAR(src);
+ memcpy(dst, src, sizeof(*dst));
+ diff_queue_init(src);
}
static void filter_diffs_for_paths(struct line_log_data *range, int keep_deletions)
{
int i;
- struct diff_queue_struct outq;
- DIFF_QUEUE_CLEAR(&outq);
+ struct diff_queue_struct outq = DIFF_QUEUE_INIT;
for (i = 0; i < diff_queued_diff.nr; i++) {
struct diff_filepair *p = diff_queued_diff.queue[i];
@@ -852,12 +853,12 @@ static void queue_diffs(struct line_log_data *range,
clear_pathspec(&opt->pathspec);
parse_pathspec_from_ranges(&opt->pathspec, range);
}
- DIFF_QUEUE_CLEAR(&diff_queued_diff);
+ diff_queue_clear(&diff_queued_diff);
diff_tree_oid(parent_tree_oid, tree_oid, "", opt);
if (opt->detect_rename && diff_might_be_rename()) {
/* must look at the full tree diff to detect renames */
clear_pathspec(&opt->pathspec);
- DIFF_QUEUE_CLEAR(&diff_queued_diff);
+ diff_queue_clear(&diff_queued_diff);
diff_tree_oid(parent_tree_oid, tree_oid, "", opt);
@@ -899,18 +900,6 @@ static void print_line(const char *prefix, char first,
fputs("\\ No newline at end of file\n", file);
}
-static char *output_prefix(struct diff_options *opt)
-{
- char *prefix = "";
-
- if (opt->output_prefix) {
- struct strbuf *sb = opt->output_prefix(opt, opt->output_prefix_data);
- prefix = sb->buf;
- }
-
- return prefix;
-}
-
static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range)
{
unsigned int i, j = 0;
@@ -920,7 +909,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
struct diff_ranges *diff = &range->diff;
struct diff_options *opt = &rev->diffopt;
- char *prefix = output_prefix(opt);
+ const char *prefix = diff_line_prefix(opt);
const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
@@ -929,7 +918,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
const char *c_context = diff_get_color(opt->use_color, DIFF_CONTEXT);
if (!pair || !diff)
- return;
+ goto out;
if (pair->one->oid_valid)
fill_line_ends(rev->diffopt.repo, pair->one, &p_lines, &p_ends);
@@ -1004,6 +993,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
c_context, c_reset, opt->file);
}
+out:
free(p_ends);
free(t_ends);
}
@@ -1014,7 +1004,10 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
*/
static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
{
- fprintf(rev->diffopt.file, "%s\n", output_prefix(&rev->diffopt));
+ const char *prefix = diff_line_prefix(&rev->diffopt);
+
+ fprintf(rev->diffopt.file, "%s\n", prefix);
+
while (range) {
dump_diff_hacky_one(rev, range);
range = range->next;
@@ -1034,6 +1027,7 @@ static int process_diff_filepair(struct rev_info *rev,
struct range_set tmp;
struct diff_ranges diff;
mmfile_t file_parent, file_target;
+ char *parent_data_to_free = NULL;
assert(pair->two->path);
while (rg) {
@@ -1058,7 +1052,7 @@ static int process_diff_filepair(struct rev_info *rev,
file_parent.ptr = pair->one->data;
file_parent.size = pair->one->size;
} else {
- file_parent.ptr = "";
+ file_parent.ptr = parent_data_to_free = xstrdup("");
file_parent.size = 0;
}
@@ -1077,6 +1071,7 @@ static int process_diff_filepair(struct rev_info *rev,
diff_ranges_release(&diff);
+ free(parent_data_to_free);
return ((*diff_out)->parent.nr > 0);
}
@@ -1093,7 +1088,7 @@ static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
static void free_diffqueues(int n, struct diff_queue_struct *dq)
{
for (int i = 0; i < n; i++)
- diff_free_queue(&dq[i]);
+ diff_queue_clear(&dq[i]);
free(dq);
}
@@ -1128,10 +1123,18 @@ static int process_all_files(struct line_log_data **range_out,
while (rg && strcmp(rg->path, pair->two->path))
rg = rg->next;
assert(rg);
+ if (rg->pair)
+ diff_free_filepair(rg->pair);
rg->pair = diff_filepair_dup(queue->queue[i]);
+ diff_ranges_release(&rg->diff);
memcpy(&rg->diff, pairdiff, sizeof(struct diff_ranges));
+ FREE_AND_NULL(pairdiff);
+ }
+
+ if (pairdiff) {
+ diff_ranges_release(pairdiff);
+ free(pairdiff);
}
- free(pairdiff);
}
return changed;
@@ -1196,7 +1199,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
if (parent)
add_line_range(rev, parent, parent_range);
free_line_log_data(parent_range);
- diff_free_queue(&queue);
+ diff_queue_clear(&queue);
return changed;
}
@@ -1209,12 +1212,13 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
struct commit_list *p;
int i;
int nparents = commit_list_count(commit->parents);
+ int ret;
if (nparents > 1 && rev->first_parent_only)
nparents = 1;
ALLOC_ARRAY(diffqueues, nparents);
- ALLOC_ARRAY(cand, nparents);
+ CALLOC_ARRAY(cand, nparents);
ALLOC_ARRAY(parents, nparents);
p = commit->parents;
@@ -1226,7 +1230,6 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
for (i = 0; i < nparents; i++) {
int changed;
- cand[i] = NULL;
changed = process_all_files(&cand[i], rev, &diffqueues[i], range);
if (!changed) {
/*
@@ -1234,13 +1237,11 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
* don't follow any other path in history
*/
add_line_range(rev, parents[i], cand[i]);
- clear_commit_line_range(rev, commit);
+ free_commit_list(commit->parents);
commit_list_append(parents[i], &commit->parents);
- free(parents);
- free(cand);
- free_diffqueues(nparents, diffqueues);
- /* NEEDSWORK leaking like a sieve */
- return 0;
+
+ ret = 0;
+ goto out;
}
}
@@ -1248,18 +1249,25 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
* No single parent took the blame. We add the candidates
* from the above loop to the parents.
*/
- for (i = 0; i < nparents; i++) {
+ for (i = 0; i < nparents; i++)
add_line_range(rev, parents[i], cand[i]);
- }
+ ret = 1;
+
+out:
clear_commit_line_range(rev, commit);
free(parents);
+ for (i = 0; i < nparents; i++) {
+ if (!cand[i])
+ continue;
+ line_log_data_clear(cand[i]);
+ free(cand[i]);
+ }
free(cand);
free_diffqueues(nparents, diffqueues);
- return 1;
+ return ret;
/* NEEDSWORK evil merge detection stuff */
- /* NEEDSWORK leaking like a sieve */
}
int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit)
diff --git a/line-log.h b/line-log.h
index 4291da8d79..e9dadbc1a5 100644
--- a/line-log.h
+++ b/line-log.h
@@ -1,8 +1,6 @@
#ifndef LINE_LOG_H
#define LINE_LOG_H
-#include "diffcore.h"
-
struct rev_info;
struct commit;
struct string_list;
diff --git a/line-range.c b/line-range.c
index 47bf0d6f1a..b99f0d9895 100644
--- a/line-range.c
+++ b/line-range.c
@@ -1,7 +1,6 @@
#include "git-compat-util.h"
#include "line-range.h"
#include "xdiff-interface.h"
-#include "strbuf.h"
#include "userdiff.h"
/*
@@ -235,6 +234,8 @@ static const char *parse_range_funcname(
}
regfree(&regexp);
+ if (xecfg)
+ xdiff_clear_find_func(xecfg);
free(xecfg);
free(pattern);
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 8a08b7af49..fa72e81e4a 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -1,11 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "commit.h"
#include "config.h"
#include "gettext.h"
-#include "revision.h"
-#include "strvec.h"
-#include "list-objects.h"
-#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "promisor-remote.h"
#include "trace.h"
@@ -255,16 +252,14 @@ void parse_list_objects_filter(
const char *arg)
{
struct strbuf errbuf = STRBUF_INIT;
- int parse_error;
if (!filter_options->filter_spec.buf)
BUG("filter_options not properly initialized");
if (!filter_options->choice) {
+ if (gently_parse_list_objects_filter(filter_options, arg, &errbuf))
+ die("%s", errbuf.buf);
strbuf_addstr(&filter_options->filter_spec, arg);
-
- parse_error = gently_parse_list_objects_filter(
- filter_options, arg, &errbuf);
} else {
struct list_objects_filter_options *sub;
@@ -274,18 +269,17 @@ void parse_list_objects_filter(
*/
transform_to_combine_type(filter_options);
- strbuf_addch(&filter_options->filter_spec, '+');
- filter_spec_append_urlencode(filter_options, arg);
ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
filter_options->sub_alloc);
sub = &filter_options->sub[filter_options->sub_nr - 1];
list_objects_filter_init(sub);
- parse_error = gently_parse_list_objects_filter(sub, arg,
- &errbuf);
+ if (gently_parse_list_objects_filter(sub, arg, &errbuf))
+ die("%s", errbuf.buf);
+
+ strbuf_addch(&filter_options->filter_spec, '+');
+ filter_spec_append_urlencode(filter_options, arg);
}
- if (parse_error)
- die("%s", errbuf.buf);
}
int opt_parse_list_objects_filter(const struct option *opt,
diff --git a/list-objects-filter.c b/list-objects-filter.c
index 9327ccd505..dc598a081b 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -1,15 +1,12 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "dir.h"
#include "gettext.h"
#include "hex.h"
-#include "tag.h"
#include "commit.h"
-#include "tree.h"
-#include "blob.h"
#include "diff.h"
-#include "tree-walk.h"
#include "revision.h"
-#include "list-objects.h"
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "oidmap.h"
@@ -547,6 +544,8 @@ static void filter_sparse_oid__init(
filter->filter_data = d;
filter->filter_object_fn = filter_sparse;
filter->free_fn = filter_sparse_free;
+
+ object_context_release(&oc);
}
/*
@@ -716,15 +715,6 @@ static void filter_combine__free(void *filter_data)
free(d);
}
-static void add_all(struct oidset *dest, struct oidset *src) {
- struct oidset_iter iter;
- struct object_id *src_oid;
-
- oidset_iter_init(src, &iter);
- while ((src_oid = oidset_iter_next(&iter)) != NULL)
- oidset_insert(dest, src_oid);
-}
-
static void filter_combine__finalize_omits(
struct oidset *omits,
void *filter_data)
@@ -733,7 +723,7 @@ static void filter_combine__finalize_omits(
size_t sub;
for (sub = 0; sub < d->nr; sub++) {
- add_all(omits, &d->sub[sub].omits);
+ oidset_insert_from_set(omits, &d->sub[sub].omits);
oidset_clear(&d->sub[sub].omits);
}
}
diff --git a/list-objects.c b/list-objects.c
index e60a6cd5b4..985d008799 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "tag.h"
#include "commit.h"
@@ -14,6 +16,7 @@
#include "packfile.h"
#include "object-store-ll.h"
#include "trace.h"
+#include "environment.h"
struct traversal_context {
struct rev_info *revs;
@@ -21,6 +24,7 @@ struct traversal_context {
show_commit_fn show_commit;
void *show_data;
struct filter *filter;
+ int depth;
};
static void show_commit(struct traversal_context *ctx,
@@ -37,6 +41,9 @@ static void show_object(struct traversal_context *ctx,
{
if (!ctx->show_object)
return;
+ if (ctx->revs->unpacked && has_object_pack(&object->oid))
+ return;
+
ctx->show_object(object, name, ctx->show_data);
}
@@ -97,7 +104,7 @@ static void process_tree_contents(struct traversal_context *ctx,
enum interesting match = ctx->revs->diffopt.pathspec.nr == 0 ?
all_entries_interesting : entry_not_interesting;
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
if (match != all_entries_interesting) {
@@ -118,7 +125,9 @@ static void process_tree_contents(struct traversal_context *ctx,
entry.path, oid_to_hex(&tree->object.oid));
}
t->object.flags |= NOT_USER_GIVEN;
+ ctx->depth++;
process_tree(ctx, t, base, entry.path);
+ ctx->depth--;
}
else if (S_ISGITLINK(entry.mode))
; /* ignore gitlink */
@@ -156,6 +165,9 @@ static void process_tree(struct traversal_context *ctx,
!revs->include_check_obj(&tree->object, revs->include_check_data))
return;
+ if (ctx->depth > max_allowed_tree_depth)
+ die("exceeded maximum allowed tree depth");
+
failed_parse = parse_tree_gently(tree, 1);
if (failed_parse) {
if (revs->ignore_missing_links)
@@ -170,7 +182,7 @@ static void process_tree(struct traversal_context *ctx,
is_promisor_object(&obj->oid))
return;
- if (!revs->do_not_die_on_missing_tree)
+ if (!revs->do_not_die_on_missing_objects)
die("bad tree object %s", oid_to_hex(&obj->oid));
}
@@ -349,6 +361,7 @@ static void traverse_non_commits(struct traversal_context *ctx,
if (!path)
path = "";
if (obj->type == OBJ_TREE) {
+ ctx->depth = 0;
process_tree(ctx, (struct tree *)obj, base, path);
continue;
}
@@ -381,6 +394,9 @@ static void do_traverse(struct traversal_context *ctx)
*/
if (!ctx->revs->tree_objects)
; /* do not bother loading tree */
+ else if (ctx->revs->do_not_die_on_missing_objects &&
+ oidset_contains(&ctx->revs->missing_commits, &commit->object.oid))
+ ;
else if (repo_get_commit_tree(the_repository, commit)) {
struct tree *tree = repo_get_commit_tree(the_repository,
commit);
diff --git a/list.h b/list.h
index 362a4cd7f5..98428010f4 100644
--- a/list.h
+++ b/list.h
@@ -19,7 +19,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
- * <http://www.gnu.org/licenses/>.
+ * <https://www.gnu.org/licenses/>.
*/
#ifndef LIST_H
diff --git a/lockfile.h b/lockfile.h
index 90af4e66b2..1bb9926497 100644
--- a/lockfile.h
+++ b/lockfile.h
@@ -321,11 +321,11 @@ static inline int commit_lock_file_to(struct lock_file *lk, const char *path)
* Roll back `lk`: close the file descriptor and/or file pointer and
* remove the lockfile. It is a NOOP to call `rollback_lock_file()`
* for a `lock_file` object that has already been committed or rolled
- * back.
+ * back. No error will be returned in this case.
*/
-static inline void rollback_lock_file(struct lock_file *lk)
+static inline int rollback_lock_file(struct lock_file *lk)
{
- delete_tempfile(&lk->tempfile);
+ return delete_tempfile(&lk->tempfile);
}
#endif /* LOCKFILE_H */
diff --git a/log-tree.c b/log-tree.c
index 208c69cbb7..83cc4b1cfb 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1,7 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit-reach.h"
#include "config.h"
#include "diff.h"
+#include "diffcore.h"
#include "environment.h"
#include "hex.h"
#include "object-name.h"
@@ -28,6 +31,7 @@
#include "tree.h"
#include "wildmatch.h"
#include "write-or-die.h"
+#include "pager.h"
static struct decoration name_decoration = { "object names" };
static int decoration_loaded;
@@ -142,7 +146,7 @@ static int ref_filter_match(const char *refname,
return 1;
}
-static int add_ref_decoration(const char *refname, const struct object_id *oid,
+static int add_ref_decoration(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED,
void *cb_data)
{
@@ -228,15 +232,43 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)
for_each_string_list_item(item, filter->exclude_ref_config_pattern) {
normalize_glob_ref(item, NULL, item->string);
}
+
+ /* normalize_glob_ref duplicates the strings */
+ filter->exclude_ref_pattern->strdup_strings = 1;
+ filter->include_ref_pattern->strdup_strings = 1;
+ filter->exclude_ref_config_pattern->strdup_strings = 1;
}
decoration_loaded = 1;
decoration_flags = flags;
- for_each_ref(add_ref_decoration, filter);
- head_ref(add_ref_decoration, filter);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_ref_decoration, filter);
+ refs_head_ref(get_main_ref_store(the_repository),
+ add_ref_decoration, filter);
for_each_commit_graft(add_graft_decoration, filter);
}
}
+void load_branch_decorations(void)
+{
+ if (!decoration_loaded) {
+ struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
+ struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
+ struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
+ struct decoration_filter decoration_filter = {
+ .include_ref_pattern = &decorate_refs_include,
+ .exclude_ref_pattern = &decorate_refs_exclude,
+ .exclude_ref_config_pattern = &decorate_refs_exclude_config,
+ };
+
+ string_list_append(&decorate_refs_include, "refs/heads/");
+ load_ref_decorations(&decoration_filter, 0);
+
+ string_list_clear(&decorate_refs_exclude, 0);
+ string_list_clear(&decorate_refs_exclude_config, 0);
+ string_list_clear(&decorate_refs_include, 0);
+ }
+}
+
static void show_parents(struct commit *commit, int abbrev, FILE *file)
{
struct commit_list *p;
@@ -276,7 +308,8 @@ static const struct name_decoration *current_pointed_by_HEAD(const struct name_d
return NULL;
/* Now resolve and find the matching current branch */
- branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags);
+ branch_name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &rru_flags);
if (!branch_name || !(rru_flags & REF_ISSYMREF))
return NULL;
@@ -303,26 +336,43 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio
/*
* The caller makes sure there is no funny color before calling.
- * format_decorations_extended makes sure the same after return.
+ * format_decorations ensures the same after return.
*/
-void format_decorations_extended(struct strbuf *sb,
+void format_decorations(struct strbuf *sb,
const struct commit *commit,
int use_color,
- const char *prefix,
- const char *separator,
- const char *suffix)
+ const struct decoration_options *opts)
{
const struct name_decoration *decoration;
const struct name_decoration *current_and_HEAD;
- const char *color_commit =
- diff_get_color(use_color, DIFF_COMMIT);
- const char *color_reset =
- decorate_get_color(use_color, DECORATION_NONE);
+ const char *color_commit, *color_reset;
+
+ const char *prefix = " (";
+ const char *suffix = ")";
+ const char *separator = ", ";
+ const char *pointer = " -> ";
+ const char *tag = "tag: ";
decoration = get_name_decoration(&commit->object);
if (!decoration)
return;
+ if (opts) {
+ if (opts->prefix)
+ prefix = opts->prefix;
+ if (opts->suffix)
+ suffix = opts->suffix;
+ if (opts->separator)
+ separator = opts->separator;
+ if (opts->pointer)
+ pointer = opts->pointer;
+ if (opts->tag)
+ tag = opts->tag;
+ }
+
+ color_commit = diff_get_color(use_color, DIFF_COMMIT);
+ color_reset = decorate_get_color(use_color, DECORATION_NONE);
+
current_and_HEAD = current_pointed_by_HEAD(decoration);
while (decoration) {
/*
@@ -331,31 +381,44 @@ void format_decorations_extended(struct strbuf *sb,
* appeared, skipping the entry for current.
*/
if (decoration != current_and_HEAD) {
- strbuf_addstr(sb, color_commit);
- strbuf_addstr(sb, prefix);
- strbuf_addstr(sb, color_reset);
- strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
- if (decoration->type == DECORATION_REF_TAG)
- strbuf_addstr(sb, "tag: ");
+ const char *color =
+ decorate_get_color(use_color, decoration->type);
+
+ if (*prefix) {
+ strbuf_addstr(sb, color_commit);
+ strbuf_addstr(sb, prefix);
+ strbuf_addstr(sb, color_reset);
+ }
+
+ if (*tag && decoration->type == DECORATION_REF_TAG) {
+ strbuf_addstr(sb, color);
+ strbuf_addstr(sb, tag);
+ strbuf_addstr(sb, color_reset);
+ }
+ strbuf_addstr(sb, color);
show_name(sb, decoration);
+ strbuf_addstr(sb, color_reset);
if (current_and_HEAD &&
decoration->type == DECORATION_REF_HEAD) {
- strbuf_addstr(sb, " -> ");
+ strbuf_addstr(sb, color_commit);
+ strbuf_addstr(sb, pointer);
strbuf_addstr(sb, color_reset);
strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
show_name(sb, current_and_HEAD);
+ strbuf_addstr(sb, color_reset);
}
- strbuf_addstr(sb, color_reset);
prefix = separator;
}
decoration = decoration->next;
}
- strbuf_addstr(sb, color_commit);
- strbuf_addstr(sb, suffix);
- strbuf_addstr(sb, color_reset);
+ if (*suffix) {
+ strbuf_addstr(sb, color_commit);
+ strbuf_addstr(sb, suffix);
+ strbuf_addstr(sb, color_reset);
+ }
}
void show_decorations(struct rev_info *opt, struct commit *commit)
@@ -370,21 +433,11 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
}
if (!opt->show_decorations)
return;
- format_decorations(&sb, commit, opt->diffopt.use_color);
+ format_decorations(&sb, commit, opt->diffopt.use_color, NULL);
fputs(sb.buf, opt->diffopt.file);
strbuf_release(&sb);
}
-static unsigned int digits_in_number(unsigned int number)
-{
- unsigned int i = 10, result = 1;
- while (i <= number) {
- i *= 10;
- result++;
- }
- return result;
-}
-
void fmt_output_subject(struct strbuf *filename,
const char *subject,
struct rev_info *info)
@@ -428,7 +481,7 @@ void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt)
strbuf_addf(sb, "Subject: [%s%s%0*d/%d] ",
opt->subject_prefix,
*opt->subject_prefix ? " " : "",
- digits_in_number(opt->total),
+ decimal_width(opt->total),
opt->nr, opt->total);
} else if (opt->total == 0 && opt->subject_prefix && *opt->subject_prefix) {
strbuf_addf(sb, "Subject: [%s] ",
@@ -439,16 +492,19 @@ void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt)
}
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
- const char **extra_headers_p,
+ char **extra_headers_p,
int *need_8bit_cte_p,
int maybe_multipart)
{
- const char *extra_headers = opt->extra_headers;
+ struct strbuf headers = STRBUF_INIT;
const char *name = oid_to_hex(opt->zero_commit ?
null_oid() : &commit->object.oid);
*need_8bit_cte_p = 0; /* unknown */
+ if (opt->extra_headers && *opt->extra_headers)
+ strbuf_addstr(&headers, opt->extra_headers);
+
fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
graph_show_oneline(opt->graph);
if (opt->message_id) {
@@ -465,16 +521,13 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
graph_show_oneline(opt->graph);
}
if (opt->mime_boundary && maybe_multipart) {
- static struct strbuf subject_buffer = STRBUF_INIT;
static struct strbuf buffer = STRBUF_INIT;
struct strbuf filename = STRBUF_INIT;
*need_8bit_cte_p = -1; /* NEVER */
- strbuf_reset(&subject_buffer);
strbuf_reset(&buffer);
- strbuf_addf(&subject_buffer,
- "%s"
+ strbuf_addf(&headers,
"MIME-Version: 1.0\n"
"Content-Type: multipart/mixed;"
" boundary=\"%s%s\"\n"
@@ -485,10 +538,8 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
"Content-Type: text/plain; "
"charset=UTF-8; format=fixed\n"
"Content-Transfer-Encoding: 8bit\n\n",
- extra_headers ? extra_headers : "",
mime_boundary_leader, opt->mime_boundary,
mime_boundary_leader, opt->mime_boundary);
- extra_headers = subject_buffer.buf;
if (opt->numbered_files)
strbuf_addf(&filename, "%d", opt->nr);
@@ -508,7 +559,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
opt->diffopt.stat_sep = buffer.buf;
strbuf_release(&filename);
}
- *extra_headers_p = extra_headers;
+ *extra_headers_p = headers.len ? strbuf_detach(&headers, NULL) : NULL;
}
static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
@@ -641,13 +692,57 @@ static void next_commentary_block(struct rev_info *opt, struct strbuf *sb)
opt->shown_dashes = 1;
}
+static void show_diff_of_diff(struct rev_info *opt)
+{
+ if (!cmit_fmt_is_mail(opt->commit_format))
+ return;
+
+ if (opt->idiff_oid1) {
+ struct diff_queue_struct dq;
+
+ memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
+ diff_queue_init(&diff_queued_diff);
+
+ fprintf_ln(opt->diffopt.file, "\n%s", opt->idiff_title);
+ show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2,
+ &opt->diffopt);
+
+ memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
+ }
+
+ if (opt->rdiff1) {
+ struct diff_queue_struct dq;
+ struct diff_options opts;
+ struct range_diff_options range_diff_opts = {
+ .creation_factor = opt->creation_factor,
+ .dual_color = 1,
+ .diffopt = &opts
+ };
+
+ memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
+ diff_queue_init(&diff_queued_diff);
+
+ fprintf_ln(opt->diffopt.file, "\n%s", opt->rdiff_title);
+ /*
+ * Pass minimum required diff-options to range-diff; others
+ * can be added later if deemed desirable.
+ */
+ repo_diff_setup(the_repository, &opts);
+ opts.file = opt->diffopt.file;
+ opts.use_color = opt->diffopt.use_color;
+ diff_setup_done(&opts);
+ show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts);
+
+ memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
+ }
+}
+
void show_log(struct rev_info *opt)
{
struct strbuf msgbuf = STRBUF_INIT;
struct log_info *log = opt->loginfo;
struct commit *commit = log->commit, *parent = log->parent;
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz;
- const char *extra_headers = opt->extra_headers;
struct pretty_print_context ctx = {0};
opt->loginfo = NULL;
@@ -708,10 +803,9 @@ void show_log(struct rev_info *opt)
*/
if (cmit_fmt_is_mail(opt->commit_format)) {
- log_write_email_headers(opt, commit, &extra_headers,
+ log_write_email_headers(opt, commit, &ctx.after_subject,
&ctx.need_8bit_cte, 1);
ctx.rev = opt;
- ctx.print_email_subject = 1;
} else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), opt->diffopt.file);
if (opt->commit_format != CMIT_FMT_ONELINE)
@@ -746,7 +840,7 @@ void show_log(struct rev_info *opt)
*/
show_reflog_message(opt->reflog_info,
opt->commit_format == CMIT_FMT_ONELINE,
- &opt->date_mode,
+ opt->date_mode,
opt->date_mode_explicit);
if (opt->commit_format == CMIT_FMT_ONELINE)
return;
@@ -777,7 +871,6 @@ void show_log(struct rev_info *opt)
ctx.date_mode = opt->date_mode;
ctx.date_mode_explicit = opt->date_mode_explicit;
ctx.abbrev = opt->diffopt.abbrev;
- ctx.after_subject = extra_headers;
ctx.preserve_subject = opt->preserve_subject;
ctx.encode_email_headers = opt->encode_email_headers;
ctx.reflog_info = opt->reflog_info;
@@ -826,47 +919,7 @@ void show_log(struct rev_info *opt)
strbuf_release(&msgbuf);
free(ctx.notes_message);
-
- if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
- struct diff_queue_struct dq;
-
- memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
- DIFF_QUEUE_CLEAR(&diff_queued_diff);
-
- next_commentary_block(opt, NULL);
- fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title);
- show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2,
- &opt->diffopt);
-
- memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
- }
-
- if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) {
- struct diff_queue_struct dq;
- struct diff_options opts;
- struct range_diff_options range_diff_opts = {
- .creation_factor = opt->creation_factor,
- .dual_color = 1,
- .diffopt = &opts
- };
-
- memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
- DIFF_QUEUE_CLEAR(&diff_queued_diff);
-
- next_commentary_block(opt, NULL);
- fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title);
- /*
- * Pass minimum required diff-options to range-diff; others
- * can be added later if deemed desirable.
- */
- repo_diff_setup(the_repository, &opts);
- opts.file = opt->diffopt.file;
- opts.use_color = opt->diffopt.use_color;
- diff_setup_done(&opts);
- show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts);
-
- memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
- }
+ free(ctx.after_subject);
}
int log_tree_diff_flush(struct rev_info *opt)
@@ -895,12 +948,7 @@ int log_tree_diff_flush(struct rev_info *opt)
* diff/diffstat output for readability.
*/
int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
- if (opt->diffopt.output_prefix) {
- struct strbuf *msg = NULL;
- msg = opt->diffopt.output_prefix(&opt->diffopt,
- opt->diffopt.output_prefix_data);
- fwrite(msg->buf, msg->len, 1, opt->diffopt.file);
- }
+ fputs(diff_line_prefix(&opt->diffopt), opt->diffopt.file);
/*
* We may have shown three-dashes line early
@@ -980,7 +1028,7 @@ static int do_remerge_diff(struct rev_info *opt,
struct object_id *oid)
{
struct merge_options o;
- struct commit_list *bases;
+ struct commit_list *bases = NULL;
struct merge_result res = {0};
struct pretty_print_context ctx = {0};
struct commit *parent1 = parents->item;
@@ -988,8 +1036,19 @@ static int do_remerge_diff(struct rev_info *opt,
struct strbuf parent1_desc = STRBUF_INIT;
struct strbuf parent2_desc = STRBUF_INIT;
+ /*
+ * Lazily prepare a temporary object directory and rotate it
+ * into the alternative object store list as the primary.
+ */
+ if (opt->remerge_diff && !opt->remerge_objdir) {
+ opt->remerge_objdir = tmp_objdir_create("remerge-diff");
+ if (!opt->remerge_objdir)
+ return error(_("unable to create temporary object directory"));
+ tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
+ }
+
/* Setup merge options */
- init_merge_options(&o, the_repository);
+ init_ui_merge_options(&o, the_repository);
o.show_rename_progress = 0;
o.record_conflict_msgs_as_headers = 1;
o.msg_header_prefix = "remerge";
@@ -1005,7 +1064,8 @@ static int do_remerge_diff(struct rev_info *opt,
/* Parse the relevant commits and get the merge bases */
parse_commit_or_die(parent1);
parse_commit_or_die(parent2);
- bases = repo_get_merge_bases(the_repository, parent1, parent2);
+ if (repo_get_merge_bases(the_repository, parent1, parent2, &bases) < 0)
+ exit(128);
/* Re-merge the parents */
merge_incore_recursive(&o, bases, parent1, parent2, &res);
@@ -1016,16 +1076,14 @@ static int do_remerge_diff(struct rev_info *opt,
log_tree_diff_flush(opt);
/* Cleanup */
+ free_commit_list(bases);
cleanup_additional_headers(&opt->diffopt);
strbuf_release(&parent1_desc);
strbuf_release(&parent2_desc);
merge_finalize(&o, &res);
/* Clean up the contents of the temporary object directory */
- if (opt->remerge_objdir)
- tmp_objdir_discard_objects(opt->remerge_objdir);
- else
- BUG("did a remerge diff without remerge_objdir?!?");
+ tmp_objdir_discard_objects(opt->remerge_objdir);
return !opt->loginfo;
}
@@ -1134,9 +1192,12 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
}
if (opt->track_linear && !opt->linear && opt->reverse_output_stage)
fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
+ if (shown)
+ show_diff_of_diff(opt);
opt->loginfo = NULL;
maybe_flush_or_die(opt->diffopt.file, "stdout");
opt->diffopt.no_free = no_free;
+
diff_free(&opt->diffopt);
return shown;
}
diff --git a/log-tree.h b/log-tree.h
index bdb6432815..ebe491c543 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,23 +13,27 @@ struct decoration_filter {
struct string_list *exclude_ref_config_pattern;
};
+struct decoration_options {
+ char *prefix;
+ char *suffix;
+ char *separator;
+ char *pointer;
+ char *tag;
+};
+
int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);
int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);
void show_log(struct rev_info *opt);
-void format_decorations_extended(struct strbuf *sb, const struct commit *commit,
- int use_color,
- const char *prefix,
- const char *separator,
- const char *suffix);
-#define format_decorations(strbuf, commit, color) \
- format_decorations_extended((strbuf), (commit), (color), " (", ", ", ")")
+void format_decorations(struct strbuf *sb, const struct commit *commit,
+ int use_color, const struct decoration_options *opts);
void show_decorations(struct rev_info *opt, struct commit *commit);
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
- const char **extra_headers_p,
+ char **extra_headers_p,
int *need_8bit_cte_p,
int maybe_multipart);
void load_ref_decorations(struct decoration_filter *filter, int flags);
+void load_branch_decorations(void);
void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *);
void fmt_output_subject(struct strbuf *, const char *subject, struct rev_info *);
diff --git a/loose.c b/loose.c
new file mode 100644
index 0000000000..897ba389da
--- /dev/null
+++ b/loose.c
@@ -0,0 +1,260 @@
+#include "git-compat-util.h"
+#include "hash.h"
+#include "path.h"
+#include "object-store.h"
+#include "hex.h"
+#include "repository.h"
+#include "wrapper.h"
+#include "gettext.h"
+#include "loose.h"
+#include "lockfile.h"
+#include "oidtree.h"
+
+static const char *loose_object_header = "# loose-object-idx\n";
+
+static inline int should_use_loose_object_map(struct repository *repo)
+{
+ return repo->compat_hash_algo && repo->gitdir;
+}
+
+void loose_object_map_init(struct loose_object_map **map)
+{
+ struct loose_object_map *m;
+ m = xmalloc(sizeof(**map));
+ m->to_compat = kh_init_oid_map();
+ m->to_storage = kh_init_oid_map();
+ *map = m;
+}
+
+static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const struct object_id *value)
+{
+ khiter_t pos;
+ int ret;
+ struct object_id *stored;
+
+ pos = kh_put_oid_map(map, *key, &ret);
+
+ /* This item already exists in the map. */
+ if (ret == 0)
+ return 0;
+
+ stored = xmalloc(sizeof(*stored));
+ oidcpy(stored, value);
+ kh_value(map, pos) = stored;
+ return 1;
+}
+
+static int insert_loose_map(struct object_directory *odb,
+ const struct object_id *oid,
+ const struct object_id *compat_oid)
+{
+ struct loose_object_map *map = odb->loose_map;
+ int inserted = 0;
+
+ inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
+ inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
+ if (inserted)
+ oidtree_insert(odb->loose_objects_cache, compat_oid);
+
+ return inserted;
+}
+
+static int load_one_loose_object_map(struct repository *repo, struct object_directory *dir)
+{
+ struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
+ FILE *fp;
+
+ if (!dir->loose_map)
+ loose_object_map_init(&dir->loose_map);
+ if (!dir->loose_objects_cache) {
+ ALLOC_ARRAY(dir->loose_objects_cache, 1);
+ oidtree_init(dir->loose_objects_cache);
+ }
+
+ insert_loose_map(dir, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
+ insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
+ insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
+
+ strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
+ fp = fopen(path.buf, "rb");
+ if (!fp) {
+ strbuf_release(&path);
+ return 0;
+ }
+
+ errno = 0;
+ if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header))
+ goto err;
+ while (!strbuf_getline_lf(&buf, fp)) {
+ const char *p;
+ struct object_id oid, compat_oid;
+ if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) ||
+ *p++ != ' ' ||
+ parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) ||
+ p != buf.buf + buf.len)
+ goto err;
+ insert_loose_map(dir, &oid, &compat_oid);
+ }
+
+ strbuf_release(&buf);
+ strbuf_release(&path);
+ return errno ? -1 : 0;
+err:
+ strbuf_release(&buf);
+ strbuf_release(&path);
+ return -1;
+}
+
+int repo_read_loose_object_map(struct repository *repo)
+{
+ struct object_directory *dir;
+
+ if (!should_use_loose_object_map(repo))
+ return 0;
+
+ prepare_alt_odb(repo);
+
+ for (dir = repo->objects->odb; dir; dir = dir->next) {
+ if (load_one_loose_object_map(repo, dir) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int repo_write_loose_object_map(struct repository *repo)
+{
+ kh_oid_map_t *map = repo->objects->odb->loose_map->to_compat;
+ struct lock_file lock;
+ int fd;
+ khiter_t iter;
+ struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
+
+ if (!should_use_loose_object_map(repo))
+ return 0;
+
+ strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
+ fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
+ iter = kh_begin(map);
+ if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
+ goto errout;
+
+ for (; iter != kh_end(map); iter++) {
+ if (kh_exist(map, iter)) {
+ if (oideq(&kh_key(map, iter), repo->hash_algo->empty_tree) ||
+ oideq(&kh_key(map, iter), repo->hash_algo->empty_blob))
+ continue;
+ strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
+ if (write_in_full(fd, buf.buf, buf.len) < 0)
+ goto errout;
+ strbuf_reset(&buf);
+ }
+ }
+ strbuf_release(&buf);
+ if (commit_lock_file(&lock) < 0) {
+ error_errno(_("could not write loose object index %s"), path.buf);
+ strbuf_release(&path);
+ return -1;
+ }
+ strbuf_release(&path);
+ return 0;
+errout:
+ rollback_lock_file(&lock);
+ strbuf_release(&buf);
+ error_errno(_("failed to write loose object index %s"), path.buf);
+ strbuf_release(&path);
+ return -1;
+}
+
+static int write_one_object(struct repository *repo, const struct object_id *oid,
+ const struct object_id *compat_oid)
+{
+ struct lock_file lock;
+ int fd;
+ struct stat st;
+ struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
+
+ strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
+ hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
+
+ fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd < 0)
+ goto errout;
+ if (fstat(fd, &st) < 0)
+ goto errout;
+ if (!st.st_size && write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
+ goto errout;
+
+ strbuf_addf(&buf, "%s %s\n", oid_to_hex(oid), oid_to_hex(compat_oid));
+ if (write_in_full(fd, buf.buf, buf.len) < 0)
+ goto errout;
+ if (close(fd))
+ goto errout;
+ adjust_shared_perm(path.buf);
+ rollback_lock_file(&lock);
+ strbuf_release(&buf);
+ strbuf_release(&path);
+ return 0;
+errout:
+ error_errno(_("failed to write loose object index %s"), path.buf);
+ close(fd);
+ rollback_lock_file(&lock);
+ strbuf_release(&buf);
+ strbuf_release(&path);
+ return -1;
+}
+
+int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
+ const struct object_id *compat_oid)
+{
+ int inserted = 0;
+
+ if (!should_use_loose_object_map(repo))
+ return 0;
+
+ inserted = insert_loose_map(repo->objects->odb, oid, compat_oid);
+ if (inserted)
+ return write_one_object(repo, oid, compat_oid);
+ return 0;
+}
+
+int repo_loose_object_map_oid(struct repository *repo,
+ const struct object_id *src,
+ const struct git_hash_algo *to,
+ struct object_id *dest)
+{
+ struct object_directory *dir;
+ kh_oid_map_t *map;
+ khiter_t pos;
+
+ for (dir = repo->objects->odb; dir; dir = dir->next) {
+ struct loose_object_map *loose_map = dir->loose_map;
+ if (!loose_map)
+ continue;
+ map = (to == repo->compat_hash_algo) ?
+ loose_map->to_compat :
+ loose_map->to_storage;
+ pos = kh_get_oid_map(map, *src);
+ if (pos < kh_end(map)) {
+ oidcpy(dest, kh_value(map, pos));
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void loose_object_map_clear(struct loose_object_map **map)
+{
+ struct loose_object_map *m = *map;
+ struct object_id *oid;
+
+ if (!m)
+ return;
+
+ kh_foreach_value(m->to_compat, oid, free(oid));
+ kh_foreach_value(m->to_storage, oid, free(oid));
+ kh_destroy_oid_map(m->to_compat);
+ kh_destroy_oid_map(m->to_storage);
+ free(m);
+ *map = NULL;
+}
diff --git a/loose.h b/loose.h
new file mode 100644
index 0000000000..28512306e5
--- /dev/null
+++ b/loose.h
@@ -0,0 +1,24 @@
+#ifndef LOOSE_H
+#define LOOSE_H
+
+#include "khash.h"
+
+struct repository;
+
+struct loose_object_map {
+ kh_oid_map_t *to_compat;
+ kh_oid_map_t *to_storage;
+};
+
+void loose_object_map_init(struct loose_object_map **map);
+void loose_object_map_clear(struct loose_object_map **map);
+int repo_loose_object_map_oid(struct repository *repo,
+ const struct object_id *src,
+ const struct git_hash_algo *dest_algo,
+ struct object_id *dest);
+int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
+ const struct object_id *compat_oid);
+int repo_read_loose_object_map(struct repository *repo);
+int repo_write_loose_object_map(struct repository *repo);
+
+#endif
diff --git a/ls-refs.c b/ls-refs.c
index 0e49b932c3..c824aea714 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@@ -5,7 +7,6 @@
#include "hex.h"
#include "repository.h"
#include "refs.h"
-#include "remote.h"
#include "strvec.h"
#include "ls-refs.h"
#include "pkt-line.h"
@@ -76,7 +77,7 @@ struct ls_refs_data {
unsigned unborn : 1;
};
-static int send_ref(const char *refname, const struct object_id *oid,
+static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
struct ls_refs_data *data = cb_data;
@@ -96,9 +97,11 @@ static int send_ref(const char *refname, const struct object_id *oid,
strbuf_addf(&data->buf, "unborn %s", refname_nons);
if (data->symrefs && flag & REF_ISSYMREF) {
struct object_id unused;
- const char *symref_target = resolve_ref_unsafe(refname, 0,
- &unused,
- &flag);
+ const char *symref_target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ refname,
+ 0,
+ &unused,
+ &flag);
if (!symref_target)
die("'%s' is a symref but it is not?", refname);
@@ -109,7 +112,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
if (data->peel && oid) {
struct object_id peeled;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
strbuf_addf(&data->buf, " peeled:%s", oid_to_hex(&peeled));
}
@@ -127,12 +130,12 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
int oid_is_null;
strbuf_addf(&namespaced, "%sHEAD", get_git_namespace());
- if (!resolve_ref_unsafe(namespaced.buf, 0, &oid, &flag))
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), namespaced.buf, 0, &oid, &flag))
return; /* bad ref */
oid_is_null = is_null_oid(&oid);
if (!oid_is_null ||
(data->unborn && data->symrefs && (flag & REF_ISSYMREF)))
- send_ref(namespaced.buf, oid_is_null ? NULL : &oid, flag, data);
+ send_ref(namespaced.buf, NULL, oid_is_null ? NULL : &oid, flag, data);
strbuf_release(&namespaced);
}
diff --git a/mailinfo.c b/mailinfo.c
index 931505363c..d1f42bd7e3 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1,7 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
#include "utf8.h"
#include "strbuf.h"
#include "mailinfo.h"
@@ -58,12 +60,13 @@ static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)
static const char *unquote_comment(struct strbuf *outbuf, const char *in)
{
- int c;
int take_next_literally = 0;
+ int depth = 1;
strbuf_addch(outbuf, '(');
- while ((c = *in++) != 0) {
+ while (*in) {
+ int c = *in++;
if (take_next_literally == 1) {
take_next_literally = 0;
} else {
@@ -72,11 +75,14 @@ static const char *unquote_comment(struct strbuf *outbuf, const char *in)
take_next_literally = 1;
continue;
case '(':
- in = unquote_comment(outbuf, in);
+ strbuf_addch(outbuf, '(');
+ depth++;
continue;
case ')':
strbuf_addch(outbuf, ')');
- return in;
+ if (!--depth)
+ return in;
+ continue;
}
}
@@ -88,10 +94,10 @@ static const char *unquote_comment(struct strbuf *outbuf, const char *in)
static const char *unquote_quoted_string(struct strbuf *outbuf, const char *in)
{
- int c;
int take_next_literally = 0;
- while ((c = *in++) != 0) {
+ while (*in) {
+ int c = *in++;
if (take_next_literally == 1) {
take_next_literally = 0;
} else {
@@ -342,9 +348,8 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)
strbuf_trim(subject);
}
-#define MAX_HDR_PARSED 10
-static const char *header[MAX_HDR_PARSED] = {
- "From","Subject","Date",
+static const char * const header[] = {
+ "From", "Subject", "Date",
};
static inline int skip_header(const struct strbuf *line, const char *hdr,
@@ -579,7 +584,7 @@ static int check_header(struct mailinfo *mi,
struct strbuf sb = STRBUF_INIT;
/* search for the interesting parts */
- for (i = 0; header[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(header); i++) {
if ((!hdr_data[i] || overwrite) &&
parse_header(line, header[i], mi, &sb)) {
handle_header(&hdr_data[i], &sb);
@@ -621,7 +626,7 @@ static int is_inbody_header(const struct mailinfo *mi,
{
int i;
const char *val;
- for (i = 0; header[i]; i++)
+ for (i = 0; i < ARRAY_SIZE(header); i++)
if (!mi->s_hdr_data[i] && skip_header(line, header[i], &val))
return 1;
return 0;
@@ -768,7 +773,7 @@ static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line)
return is_format_patch_separator(line->buf + 1, line->len - 1);
if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
int i;
- for (i = 0; header[i]; i++)
+ for (i = 0; i < ARRAY_SIZE(header); i++)
if (!strcmp("Subject", header[i])) {
handle_header(&mi->s_hdr_data[i], line);
return 1;
@@ -820,7 +825,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
* We may have already read "secondary headers"; purge
* them to give ourselves a clean restart.
*/
- for (i = 0; header[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(header); i++) {
if (mi->s_hdr_data[i])
strbuf_release(mi->s_hdr_data[i]);
FREE_AND_NULL(mi->s_hdr_data[i]);
@@ -1151,7 +1156,7 @@ static void handle_info(struct mailinfo *mi)
struct strbuf *hdr;
int i;
- for (i = 0; header[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(header); i++) {
/* only print inbody headers if we output a patch file */
if (mi->patch_lines && mi->s_hdr_data[i])
hdr = mi->s_hdr_data[i];
@@ -1202,8 +1207,8 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
return -1;
}
- mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
- mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
+ mi->p_hdr_data = xcalloc(ARRAY_SIZE(header), sizeof(*(mi->p_hdr_data)));
+ mi->s_hdr_data = xcalloc(ARRAY_SIZE(header), sizeof(*(mi->s_hdr_data)));
do {
peek = fgetc(mi->input);
@@ -1253,6 +1258,8 @@ static int git_mailinfo_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "mailinfo.quotedcr")) {
+ if (!value)
+ return config_error_nonbool(var);
if (mailinfo_parse_quoted_cr_action(value, &mi->quoted_cr) != 0)
return error(_("bad action '%s' for '%s'"), value, var);
return 0;
@@ -1284,8 +1291,21 @@ void clear_mailinfo(struct mailinfo *mi)
strbuf_release(&mi->inbody_header_accum);
free(mi->message_id);
- strbuf_list_free(mi->p_hdr_data);
- strbuf_list_free(mi->s_hdr_data);
+ for (size_t i = 0; i < ARRAY_SIZE(header); i++) {
+ if (!mi->p_hdr_data[i])
+ continue;
+ strbuf_release(mi->p_hdr_data[i]);
+ free(mi->p_hdr_data[i]);
+ }
+ free(mi->p_hdr_data);
+
+ for (size_t i = 0; i < ARRAY_SIZE(header); i++) {
+ if (!mi->s_hdr_data[i])
+ continue;
+ strbuf_release(mi->s_hdr_data[i]);
+ free(mi->s_hdr_data[i]);
+ }
+ free(mi->s_hdr_data);
while (mi->content < mi->content_top) {
free(*(mi->content_top));
diff --git a/mailmap.c b/mailmap.c
index 3d6a5e9400..9f9fa3199a 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "string-list.h"
@@ -6,8 +8,8 @@
#include "object-store-ll.h"
#include "setup.h"
-const char *git_mailmap_file;
-const char *git_mailmap_blob;
+char *git_mailmap_file;
+char *git_mailmap_blob;
struct mailmap_info {
char *name;
@@ -140,11 +142,8 @@ static void read_mailmap_line(struct string_list *map, char *buffer)
add_mapping(map, name1, email1, name2, email2);
}
-/* Flags for read_mailmap_file() */
-#define MAILMAP_NOFOLLOW (1<<0)
-
-static int read_mailmap_file(struct string_list *map, const char *filename,
- unsigned flags)
+int read_mailmap_file(struct string_list *map, const char *filename,
+ unsigned flags)
{
char buffer[1024];
FILE *f;
@@ -184,7 +183,7 @@ static void read_mailmap_string(struct string_list *map, char *buf)
}
}
-static int read_mailmap_blob(struct string_list *map, const char *name)
+int read_mailmap_blob(struct string_list *map, const char *name)
{
struct object_id oid;
char *buf;
@@ -199,8 +198,10 @@ static int read_mailmap_blob(struct string_list *map, const char *name)
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)
+ if (type != OBJ_BLOB) {
+ free(buf);
return error("mailmap is not a blob: %s", name);
+ }
read_mailmap_string(map, buf);
@@ -216,7 +217,7 @@ int read_mailmap(struct string_list *map)
map->cmp = namemap_cmp;
if (!git_mailmap_blob && is_bare_repository())
- git_mailmap_blob = "HEAD:.mailmap";
+ git_mailmap_blob = xstrdup("HEAD:.mailmap");
if (!startup_info->have_repository || !is_bare_repository())
err |= read_mailmap_file(map, ".mailmap",
diff --git a/mailmap.h b/mailmap.h
index 0f8fd2c586..908365e1bf 100644
--- a/mailmap.h
+++ b/mailmap.h
@@ -3,8 +3,15 @@
struct string_list;
-extern const char *git_mailmap_file;
-extern const char *git_mailmap_blob;
+extern char *git_mailmap_file;
+extern char *git_mailmap_blob;
+
+/* Flags for read_mailmap_file() */
+#define MAILMAP_NOFOLLOW (1<<0)
+
+int read_mailmap_file(struct string_list *map, const char *filename,
+ unsigned flags);
+int read_mailmap_blob(struct string_list *map, const char *name);
int read_mailmap(struct string_list *map);
void clear_mailmap(struct string_list *map);
diff --git a/match-trees.c b/match-trees.c
index 0885ac681c..147b03abf1 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "hex.h"
#include "match-trees.h"
@@ -63,7 +65,7 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
die("unable to read tree (%s)", oid_to_hex(hash));
if (type != OBJ_TREE)
die("%s is not a tree", oid_to_hex(hash));
- init_tree_desc(desc, buffer, size);
+ init_tree_desc(desc, hash, buffer, size);
return buffer;
}
@@ -194,7 +196,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
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);
+ init_tree_desc(&desc, oid1, buf, sz);
rewrite_here = NULL;
while (desc.size) {
@@ -229,7 +231,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
oid_to_hex(oid1));
if (*subpath) {
struct object_id tree_oid;
- oidread(&tree_oid, rewrite_here);
+ oidread(&tree_oid, rewrite_here, the_repository->hash_algo);
status = splice_tree(&tree_oid, subpath, oid2, &subtree);
if (status)
return status;
@@ -237,7 +239,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
} else {
rewrite_with = oid2;
}
- hashcpy(rewrite_here, rewrite_with->hash);
+ hashcpy(rewrite_here, rewrite_with->hash, the_repository->hash_algo);
status = write_object_file(buf, sz, OBJ_TREE, result);
free(buf);
return status;
@@ -292,18 +294,22 @@ void shift_tree(struct repository *r,
unsigned short mode;
if (!*del_prefix)
- return;
+ goto out;
if (get_tree_entry(r, hash2, del_prefix, shifted, &mode))
die("cannot find path %s in tree %s",
del_prefix, oid_to_hex(hash2));
- return;
+ goto out;
}
if (!*add_prefix)
- return;
+ goto out;
splice_tree(hash1, add_prefix, hash2, shifted);
+
+out:
+ free(add_prefix);
+ free(del_prefix);
}
/*
diff --git a/mem-pool.c b/mem-pool.c
index c34846d176..a3ba38831d 100644
--- a/mem-pool.c
+++ b/mem-pool.c
@@ -4,6 +4,7 @@
#include "git-compat-util.h"
#include "mem-pool.h"
+#include "gettext.h"
#define BLOCK_GROWTH_SIZE (1024 * 1024 - sizeof(struct mp_block))
@@ -89,9 +90,7 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
struct mp_block *p = NULL;
void *r;
- /* round up to a 'GIT_MAX_ALIGNMENT' alignment */
- if (len & (GIT_MAX_ALIGNMENT - 1))
- len += GIT_MAX_ALIGNMENT - (len & (GIT_MAX_ALIGNMENT - 1));
+ len = DIV_ROUND_UP(len, GIT_MAX_ALIGNMENT) * GIT_MAX_ALIGNMENT;
if (pool->mp_block &&
pool->mp_block->end - pool->mp_block->next_free >= len)
@@ -99,9 +98,9 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
if (!p) {
if (len >= (pool->block_alloc / 2))
- return mem_pool_alloc_block(pool, len, pool->mp_block);
-
- p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
+ p = mem_pool_alloc_block(pool, len, pool->mp_block);
+ else
+ p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
}
r = p->next_free;
@@ -109,6 +108,47 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
return r;
}
+static char *mem_pool_strvfmt(struct mem_pool *pool, const char *fmt,
+ va_list ap)
+{
+ struct mp_block *block = pool->mp_block;
+ char *next_free = block ? block->next_free : NULL;
+ size_t available = block ? block->end - block->next_free : 0;
+ va_list cp;
+ int len, len2;
+ size_t size;
+ char *ret;
+
+ va_copy(cp, ap);
+ len = vsnprintf(next_free, available, fmt, cp);
+ va_end(cp);
+ if (len < 0)
+ die(_("unable to format message: %s"), fmt);
+
+ size = st_add(len, 1); /* 1 for NUL */
+ ret = mem_pool_alloc(pool, size);
+
+ /* Shortcut; relies on mem_pool_alloc() not touching buffer contents. */
+ if (ret == next_free)
+ return ret;
+
+ len2 = vsnprintf(ret, size, fmt, ap);
+ if (len2 != len)
+ BUG("your vsnprintf is broken (returns inconsistent lengths)");
+ return ret;
+}
+
+char *mem_pool_strfmt(struct mem_pool *pool, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = mem_pool_strvfmt(pool, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size)
{
size_t len = st_mult(count, size);
diff --git a/mem-pool.h b/mem-pool.h
index fe7507f022..321d86a63c 100644
--- a/mem-pool.h
+++ b/mem-pool.h
@@ -48,6 +48,12 @@ char *mem_pool_strdup(struct mem_pool *pool, const char *str);
char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len);
/*
+ * Allocate memory from the memory pool and format a string into it.
+ */
+__attribute__((format (printf, 2, 3)))
+char *mem_pool_strfmt(struct mem_pool *pool, const char *fmt, ...);
+
+/*
* Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'
* pool will be empty and not contain any memory. It still needs to be free'd
* with a call to `mem_pool_discard`.
diff --git a/merge-blobs.c b/merge-blobs.c
index 9293cbf75c..0ad0390fea 100644
--- a/merge-blobs.c
+++ b/merge-blobs.c
@@ -1,6 +1,6 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "run-command.h"
-#include "xdiff-interface.h"
#include "merge-ll.h"
#include "blob.h"
#include "merge-blobs.h"
diff --git a/merge-ll.c b/merge-ll.c
index 8fcf2d3710..62fc625552 100644
--- a/merge-ll.c
+++ b/merge-ll.c
@@ -4,6 +4,8 @@
* Copyright (c) 2007 Junio C Hamano
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "convert.h"
@@ -13,6 +15,7 @@
#include "merge-ll.h"
#include "quote.h"
#include "strbuf.h"
+#include "gettext.h"
struct ll_merge_driver;
@@ -29,7 +32,7 @@ struct ll_merge_driver {
const char *name;
const char *description;
ll_merge_fn fn;
- const char *recursive;
+ char *recursive;
struct ll_merge_driver *next;
char *cmdline;
};
@@ -128,7 +131,9 @@ static enum ll_merge_result ll_xdl_merge(const struct ll_merge_driver *drv_unuse
xmp.level = XDL_MERGE_ZEALOUS;
xmp.favor = opts->variant;
xmp.xpp.flags = opts->xdl_opts;
- if (git_xmerge_style >= 0)
+ if (opts->conflict_style >= 0)
+ xmp.style = opts->conflict_style;
+ else if (git_xmerge_style >= 0)
xmp.style = git_xmerge_style;
if (marker_size > 0)
xmp.marker_size = marker_size;
@@ -185,9 +190,9 @@ static void create_temp(mmfile_t *src, char *path, size_t len)
static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
mmbuffer_t *result,
const char *path,
- mmfile_t *orig, const char *orig_name UNUSED,
- mmfile_t *src1, const char *name1 UNUSED,
- mmfile_t *src2, const char *name2 UNUSED,
+ mmfile_t *orig, const char *orig_name,
+ mmfile_t *src1, const char *name1,
+ mmfile_t *src2, const char *name2,
const struct ll_merge_options *opts,
int marker_size)
{
@@ -222,6 +227,12 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
strbuf_addf(&cmd, "%d", marker_size);
else if (skip_prefix(format, "P", &format))
sq_quote_buf(&cmd, path);
+ else if (skip_prefix(format, "S", &format))
+ sq_quote_buf(&cmd, orig_name ? orig_name : "");
+ else if (skip_prefix(format, "X", &format))
+ sq_quote_buf(&cmd, name1 ? name1 : "");
+ else if (skip_prefix(format, "Y", &format))
+ sq_quote_buf(&cmd, name2 ? name2 : "");
else
strbuf_addch(&cmd, '%');
}
@@ -260,7 +271,7 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
* merge.default and merge.driver configuration items
*/
static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
-static const char *default_ll_merge;
+static char *default_ll_merge;
static int read_merge_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
@@ -286,7 +297,7 @@ static int read_merge_config(const char *var, const char *value,
* after seeing merge.<name>.var1.
*/
for (fn = ll_user_merge; fn; fn = fn->next)
- if (!strncmp(fn->name, name, namelen) && !fn->name[namelen])
+ if (!xstrncmpz(fn->name, name, namelen))
break;
if (!fn) {
CALLOC_ARRAY(fn, 1);
@@ -296,12 +307,17 @@ static int read_merge_config(const char *var, const char *value,
ll_user_merge_tail = &(fn->next);
}
- if (!strcmp("name", key))
- return git_config_string(&fn->description, var, value);
+ if (!strcmp("name", key)) {
+ /*
+ * The description is leaking, but that's okay as we want to
+ * keep around the merge drivers anyway.
+ */
+ return git_config_string((char **) &fn->description, var, value);
+ }
if (!strcmp("driver", key)) {
if (!value)
- return error("%s: lacks value", var);
+ return config_error_nonbool(var);
/*
* merge.<name>.driver specifies the command line:
*
@@ -315,7 +331,12 @@ static int read_merge_config(const char *var, const char *value,
* %B - temporary file name for the other branches' version.
* %L - conflict marker length
* %P - the original path (safely quoted for the shell)
+ * %S - the revision for the merge base
+ * %X - the revision for our version
+ * %Y - the revision for their version
*
+ * If the file is not named identically in all versions, then each
+ * revision is joined with the corresponding path, separated by a colon.
* The external merge driver should write the results in the
* file named by %A, and signal that it has done with zero exit
* status.
@@ -390,7 +411,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
const struct ll_merge_options *opts)
{
struct attr_check *check = load_merge_attributes();
- static const struct ll_merge_options default_opts;
+ static const struct ll_merge_options default_opts = LL_MERGE_OPTIONS_INIT;
const char *ll_driver_name = NULL;
int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
const struct ll_merge_driver *driver;
@@ -407,7 +428,10 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
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);
+ if (strtol_i(check->items[1].value, 10, &marker_size)) {
+ marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
+ warning(_("invalid marker-size '%s', expecting an integer"), check->items[1].value);
+ }
if (marker_size <= 0)
marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
}
@@ -434,7 +458,10 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
check = attr_check_initl("conflict-marker-size", NULL);
git_check_attr(istate, path, check);
if (check->items[0].value) {
- marker_size = atoi(check->items[0].value);
+ if (strtol_i(check->items[0].value, 10, &marker_size)) {
+ marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
+ warning(_("invalid marker-size '%s', expecting an integer"), check->items[0].value);
+ }
if (marker_size <= 0)
marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
}
diff --git a/merge-ll.h b/merge-ll.h
index e4a20e81a3..d038ee0c1e 100644
--- a/merge-ll.h
+++ b/merge-ll.h
@@ -78,10 +78,15 @@ struct ll_merge_options {
*/
unsigned extra_marker_size;
+ /* Override the global conflict style. */
+ int conflict_style;
+
/* Extra xpparam_t flags as defined in xdiff/xdiff.h. */
long xdl_opts;
};
+#define LL_MERGE_OPTIONS_INIT { .conflict_style = -1 }
+
enum ll_merge_result {
LL_MERGE_ERROR = -1,
LL_MERGE_OK = 0,
diff --git a/merge-ort-wrappers.c b/merge-ort-wrappers.c
index 4acedf3c33..d6f6135996 100644
--- a/merge-ort-wrappers.c
+++ b/merge-ort-wrappers.c
@@ -48,7 +48,7 @@ int merge_ort_nonrecursive(struct merge_options *opt,
int merge_ort_recursive(struct merge_options *opt,
struct commit *side1,
struct commit *side2,
- struct commit_list *merge_bases,
+ const struct commit_list *merge_bases,
struct commit **result)
{
struct tree *head = repo_get_commit_tree(opt->repo, side1);
diff --git a/merge-ort-wrappers.h b/merge-ort-wrappers.h
index 0c4c57adbb..90af1f69c5 100644
--- a/merge-ort-wrappers.h
+++ b/merge-ort-wrappers.h
@@ -19,7 +19,7 @@ int merge_ort_nonrecursive(struct merge_options *opt,
int merge_ort_recursive(struct merge_options *opt,
struct commit *h1,
struct commit *h2,
- struct commit_list *ancestors,
+ const struct commit_list *ancestors,
struct commit **result);
#endif
diff --git a/merge-ort.c b/merge-ort.c
index e5e22e3583..11029c10be 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -14,12 +14,14 @@
* "cale", "peedy", or "ins" instead of "ort"?)
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "merge-ort.h"
#include "alloc.h"
+#include "advice.h"
#include "attr.h"
-#include "blob.h"
#include "cache-tree.h"
#include "commit.h"
#include "commit-reach.h"
@@ -39,11 +41,10 @@
#include "path.h"
#include "promisor-remote.h"
#include "read-cache-ll.h"
+#include "refs.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"
@@ -545,15 +546,34 @@ enum conflict_and_info_types {
CONFLICT_SUBMODULE_MAY_HAVE_REWINDS,
CONFLICT_SUBMODULE_NULL_MERGE_BASE,
+ /* INSERT NEW ENTRIES HERE */
+
+ /*
+ * Keep this entry after all regular conflict and info types; only
+ * errors (failures causing immediate abort of the merge) should
+ * come after this.
+ */
+ NB_REGULAR_CONFLICT_TYPES,
+
+ /*
+ * Something is seriously wrong; cannot even perform merge;
+ * Keep this group _last_ other than NB_TOTAL_TYPES
+ */
+ ERROR_SUBMODULE_CORRUPT,
+ ERROR_THREEWAY_CONTENT_MERGE_FAILED,
+ ERROR_OBJECT_WRITE_FAILED,
+ ERROR_OBJECT_READ_FAILED,
+ ERROR_OBJECT_NOT_A_BLOB,
+
/* Keep this entry _last_ in the list */
- NB_CONFLICT_TYPES,
+ NB_TOTAL_TYPES,
};
/*
* Short description of conflict type, relied upon by external tools.
*
* We can add more entries, but DO NOT change any of these strings. Also,
- * Order MUST match conflict_info_and_types.
+ * please ensure the order matches what is used in conflict_info_and_types.
*/
static const char *type_short_descriptions[] = {
/*** "Simple" conflicts and informational messages ***/
@@ -596,7 +616,19 @@ static const char *type_short_descriptions[] = {
[CONFLICT_SUBMODULE_MAY_HAVE_REWINDS] =
"CONFLICT (submodule may have rewinds)",
[CONFLICT_SUBMODULE_NULL_MERGE_BASE] =
- "CONFLICT (submodule lacks merge base)"
+ "CONFLICT (submodule lacks merge base)",
+
+ /* Something is seriously wrong; cannot even perform merge */
+ [ERROR_SUBMODULE_CORRUPT] =
+ "ERROR (submodule corrupt)",
+ [ERROR_THREEWAY_CONTENT_MERGE_FAILED] =
+ "ERROR (three-way content merge failed)",
+ [ERROR_OBJECT_WRITE_FAILED] =
+ "ERROR (object write failed)",
+ [ERROR_OBJECT_READ_FAILED] =
+ "ERROR (object read failed)",
+ [ERROR_OBJECT_NOT_A_BLOB] =
+ "ERROR (object is not a blob)",
};
struct logical_conflict_info {
@@ -657,8 +689,7 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
*/
strmap_clear_func(&opti->conflicted, 0);
- if (opti->attr_index.cache_nr) /* true iff opt->renormalize */
- discard_index(&opti->attr_index);
+ discard_index(&opti->attr_index);
/* Free memory used by various renames maps */
for (i = MERGE_SIDE1; i <= MERGE_SIDE2; ++i) {
@@ -721,23 +752,6 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
renames->callback_data_nr = renames->callback_data_alloc = 0;
}
-__attribute__((format (printf, 2, 3)))
-static int err(struct merge_options *opt, const char *err, ...)
-{
- va_list params;
- struct strbuf sb = STRBUF_INIT;
-
- strbuf_addstr(&sb, "error: ");
- va_start(params, err);
- strbuf_vaddf(&sb, err, params);
- va_end(params);
-
- error("%s", sb.buf);
- strbuf_release(&sb);
-
- return -1;
-}
-
static void format_commit(struct strbuf *sb,
int indent,
struct repository *repo,
@@ -777,7 +791,8 @@ static void path_msg(struct merge_options *opt,
/* Sanity checks */
assert(omittable_hint ==
- !starts_with(type_short_descriptions[type], "CONFLICT") ||
+ (!starts_with(type_short_descriptions[type], "CONFLICT") &&
+ !starts_with(type_short_descriptions[type], "ERROR")) ||
type == CONFLICT_DIR_RENAME_SUGGESTED);
if (opt->record_conflict_msgs_as_headers && omittable_hint)
return; /* Do not record mere hints in headers */
@@ -1132,7 +1147,7 @@ static void collect_rename_info(struct merge_options *opt,
* Update dir_rename_mask (determines ignore-rename-source validity)
*
* dir_rename_mask helps us keep track of when directory rename
- * detection may be relevant. Basically, whenver a directory is
+ * detection may be relevant. Basically, whenever a directory is
* removed on one side of history, and a file is added to that
* directory on the other side of history, directory rename
* detection is relevant (meaning we have to detect renames for all
@@ -1676,12 +1691,14 @@ static int collect_merge_info(struct merge_options *opt,
info.data = opt;
info.show_all_errors = 1;
- parse_tree(merge_base);
- parse_tree(side1);
- parse_tree(side2);
- init_tree_desc(t + 0, merge_base->buffer, merge_base->size);
- init_tree_desc(t + 1, side1->buffer, side1->size);
- init_tree_desc(t + 2, side2->buffer, side2->size);
+ if (parse_tree(merge_base) < 0 ||
+ parse_tree(side1) < 0 ||
+ parse_tree(side2) < 0)
+ return -1;
+ init_tree_desc(t + 0, &merge_base->object.oid,
+ merge_base->buffer, merge_base->size);
+ init_tree_desc(t + 1, &side1->object.oid, side1->buffer, side1->size);
+ init_tree_desc(t + 2, &side2->object.oid, side2->buffer, side2->size);
trace2_region_enter("merge", "traverse_trees", opt->repo);
ret = traverse_trees(NULL, 3, t, &info);
@@ -1727,7 +1744,14 @@ static int find_first_merges(struct repository *repo,
die("revision walk setup failed");
while ((commit = get_revision(&revs)) != NULL) {
struct object *o = &(commit->object);
- if (repo_in_merge_bases(repo, b, commit))
+ int ret = repo_in_merge_bases(repo, b, commit);
+
+ if (ret < 0) {
+ object_array_clear(&merges);
+ release_revisions(&revs);
+ return ret;
+ }
+ if (ret > 0)
add_object_array(o, NULL, &merges);
}
reset_revision_walk();
@@ -1742,9 +1766,17 @@ static int find_first_merges(struct repository *repo,
contains_another = 0;
for (j = 0; j < merges.nr; j++) {
struct commit *m2 = (struct commit *) merges.objects[j].item;
- if (i != j && repo_in_merge_bases(repo, m2, m1)) {
- contains_another = 1;
- break;
+ if (i != j) {
+ int ret = repo_in_merge_bases(repo, m2, m1);
+ if (ret < 0) {
+ object_array_clear(&merges);
+ release_revisions(&revs);
+ return ret;
+ }
+ if (ret > 0) {
+ contains_another = 1;
+ break;
+ }
}
}
@@ -1766,7 +1798,7 @@ static int merge_submodule(struct merge_options *opt,
{
struct repository subrepo;
struct strbuf sb = STRBUF_INIT;
- int ret = 0;
+ int ret = 0, ret2;
struct commit *commit_o, *commit_a, *commit_b;
int parent_count;
struct object_array merges;
@@ -1813,8 +1845,28 @@ static int merge_submodule(struct merge_options *opt,
}
/* check whether both changes are forward */
- if (!repo_in_merge_bases(&subrepo, commit_o, commit_a) ||
- !repo_in_merge_bases(&subrepo, commit_o, commit_b)) {
+ ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_a);
+ if (ret2 < 0) {
+ path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0,
+ path, NULL, NULL, NULL,
+ _("error: failed to merge submodule %s "
+ "(repository corrupt)"),
+ path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (ret2 > 0)
+ ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_b);
+ if (ret2 < 0) {
+ path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0,
+ path, NULL, NULL, NULL,
+ _("error: failed to merge submodule %s "
+ "(repository corrupt)"),
+ path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (!ret2) {
path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0,
path, NULL, NULL, NULL,
_("Failed to merge submodule %s "
@@ -1824,7 +1876,17 @@ static int merge_submodule(struct merge_options *opt,
}
/* Case #1: a is contained in b or vice versa */
- if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
+ ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);
+ if (ret2 < 0) {
+ path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0,
+ path, NULL, NULL, NULL,
+ _("error: failed to merge submodule %s "
+ "(repository corrupt)"),
+ path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (ret2 > 0) {
oidcpy(result, b);
path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
path, NULL, NULL, NULL,
@@ -1833,7 +1895,17 @@ static int merge_submodule(struct merge_options *opt,
ret = 1;
goto cleanup;
}
- if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
+ ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);
+ if (ret2 < 0) {
+ path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0,
+ path, NULL, NULL, NULL,
+ _("error: failed to merge submodule %s "
+ "(repository corrupt)"),
+ path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (ret2 > 0) {
oidcpy(result, a);
path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
path, NULL, NULL, NULL,
@@ -1858,6 +1930,14 @@ static int merge_submodule(struct merge_options *opt,
parent_count = find_first_merges(&subrepo, path, commit_a, commit_b,
&merges);
switch (parent_count) {
+ case -1:
+ path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0,
+ path, NULL, NULL, NULL,
+ _("error: failed to merge submodule %s "
+ "(repository corrupt)"),
+ path);
+ ret = -1;
+ break;
case 0:
path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
path, NULL, NULL, NULL,
@@ -1919,6 +1999,7 @@ static void initialize_attr_index(struct merge_options *opt)
struct index_state *attr_index = &opt->priv->attr_index;
struct cache_entry *ce;
+ attr_index->repo = opt->repo;
attr_index->initialized = 1;
if (!opt->renormalize)
@@ -1974,7 +2055,7 @@ static int merge_3way(struct merge_options *opt,
mmbuffer_t *result_buf)
{
mmfile_t orig, src1, src2;
- struct ll_merge_options ll_opts = {0};
+ struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
char *base, *name1, *name2;
enum ll_merge_result merge_status;
@@ -1984,6 +2065,7 @@ static int merge_3way(struct merge_options *opt,
ll_opts.renormalize = opt->renormalize;
ll_opts.extra_marker_size = extra_marker_size;
ll_opts.xdl_opts = opt->xdl_opts;
+ ll_opts.conflict_style = opt->conflict_style;
if (opt->priv->call_depth) {
ll_opts.virtual_ancestor = 1;
@@ -2057,7 +2139,7 @@ static int handle_content_merge(struct merge_options *opt,
* merges, which happens for example with rename/rename(2to1) and
* rename/add conflicts.
*/
- unsigned clean = 1;
+ int clean = 1;
/*
* handle_content_merge() needs both files to be of the same type, i.e.
@@ -2121,19 +2203,28 @@ static int handle_content_merge(struct merge_options *opt,
pathnames, extra_marker_size,
&result_buf);
- if ((merge_status < 0) || !result_buf.ptr)
- ret = err(opt, _("Failed to execute internal merge"));
+ if ((merge_status < 0) || !result_buf.ptr) {
+ path_msg(opt, ERROR_THREEWAY_CONTENT_MERGE_FAILED, 0,
+ pathnames[0], pathnames[1], pathnames[2], NULL,
+ _("error: failed to execute internal merge for %s"),
+ path);
+ ret = -1;
+ }
if (!ret &&
write_object_file(result_buf.ptr, result_buf.size,
- OBJ_BLOB, &result->oid))
- ret = err(opt, _("Unable to add %s to database"),
- path);
-
+ OBJ_BLOB, &result->oid)) {
+ path_msg(opt, ERROR_OBJECT_WRITE_FAILED, 0,
+ pathnames[0], pathnames[1], pathnames[2], NULL,
+ _("error: unable to add %s to database"), path);
+ ret = -1;
+ }
free(result_buf.ptr);
+
if (ret)
return -1;
- clean &= (merge_status == 0);
+ if (merge_status > 0)
+ clean = 0;
path_msg(opt, INFO_AUTO_MERGING, 1, path, NULL, NULL, NULL,
_("Auto-merging %s"), path);
} else if (S_ISGITLINK(a->mode)) {
@@ -2141,6 +2232,8 @@ static int handle_content_merge(struct merge_options *opt,
clean = merge_submodule(opt, pathnames[0],
two_way ? null_oid() : &o->oid,
&a->oid, &b->oid, &result->oid);
+ if (clean < 0)
+ return -1;
if (opt->priv->call_depth && two_way && !clean) {
result->mode = o->mode;
oidcpy(&result->oid, &o->oid);
@@ -2617,7 +2710,7 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
struct conflict_info *dir_ci;
char *cur_dir = dirs_to_insert.items[i].string;
- CALLOC_ARRAY(dir_ci, 1);
+ dir_ci = mem_pool_calloc(&opt->priv->pool, 1, sizeof(*dir_ci));
dir_ci->merged.directory_name = parent_name;
len = strlen(parent_name);
@@ -2661,7 +2754,7 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
oidcpy(&ci->stages[i].oid, null_oid());
}
- // Now we want to focus on new_ci, so reassign ci to it
+ /* Now we want to focus on new_ci, so reassign ci to it. */
ci = new_ci;
}
@@ -2745,6 +2838,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
* Finally, record the new location.
*/
pair->two->path = new_path;
+
+ string_list_clear(&dirs_to_insert, 0);
}
/*** Function Grouping: functions related to regular rename detection ***/
@@ -3342,10 +3437,7 @@ static int collect_renames(struct merge_options *opt,
return clean;
}
-static int detect_and_process_renames(struct merge_options *opt,
- struct tree *merge_base,
- struct tree *side1,
- struct tree *side2)
+static int detect_and_process_renames(struct merge_options *opt)
{
struct diff_queue_struct combined = { 0 };
struct rename_info *renames = &opt->priv->renames;
@@ -3444,7 +3536,7 @@ simple_cleanup:
/* Free memory for renames->pairs[] and combined */
for (s = MERGE_SIDE1; s <= MERGE_SIDE2; s++) {
free(renames->pairs[s].queue);
- DIFF_QUEUE_CLEAR(&renames->pairs[s]);
+ diff_queue_init(&renames->pairs[s]);
}
for (i = 0; i < combined.nr; i++)
pool_diff_free_filepair(&opt->priv->pool, combined.queue[i]);
@@ -3511,17 +3603,25 @@ static int sort_dirs_next_to_their_children(const char *one, const char *two)
static int read_oid_strbuf(struct merge_options *opt,
const struct object_id *oid,
- struct strbuf *dst)
+ struct strbuf *dst,
+ const char *path)
{
void *buf;
enum object_type type;
unsigned long size;
buf = repo_read_object_file(the_repository, oid, &type, &size);
- if (!buf)
- return err(opt, _("cannot read object %s"), oid_to_hex(oid));
+ if (!buf) {
+ path_msg(opt, ERROR_OBJECT_READ_FAILED, 0,
+ path, NULL, NULL, NULL,
+ _("error: cannot read object %s"), oid_to_hex(oid));
+ return -1;
+ }
if (type != OBJ_BLOB) {
free(buf);
- return err(opt, _("object %s is not a blob"), oid_to_hex(oid));
+ path_msg(opt, ERROR_OBJECT_NOT_A_BLOB, 0,
+ path, NULL, NULL, NULL,
+ _("error: object %s is not a blob"), oid_to_hex(oid));
+ return -1;
}
strbuf_attach(dst, buf, size, size + 1);
return 0;
@@ -3545,8 +3645,8 @@ static int blob_unchanged(struct merge_options *opt,
if (oideq(&base->oid, &side->oid))
return 1;
- if (read_oid_strbuf(opt, &base->oid, &basebuf) ||
- read_oid_strbuf(opt, &side->oid, &sidebuf))
+ if (read_oid_strbuf(opt, &base->oid, &basebuf, path) ||
+ read_oid_strbuf(opt, &side->oid, &sidebuf, path))
goto error_return;
/*
* Note: binary | is used so that both renormalizations are
@@ -3737,7 +3837,7 @@ static int write_completed_directory(struct merge_options *opt,
* src/moduleB 2
*
* which is used to know that xtract.c & token.txt are from the
- * toplevel dirctory, while umm.c & stuff.h & baz.c are from the
+ * toplevel directory, while umm.c & stuff.h & baz.c are from the
* src/moduleB directory. Again, following the example above,
* once we need to process src/moduleB, then info->offsets is
* updated to
@@ -4399,10 +4499,12 @@ static int checkout(struct merge_options *opt,
unpack_opts.verbose_update = (opt->verbosity > 2);
unpack_opts.fn = twoway_merge;
unpack_opts.preserve_ignored = 0; /* FIXME: !opts->overwrite_ignore */
- parse_tree(prev);
- init_tree_desc(&trees[0], prev->buffer, prev->size);
- parse_tree(next);
- init_tree_desc(&trees[1], next->buffer, next->size);
+ if (parse_tree(prev) < 0)
+ return -1;
+ init_tree_desc(&trees[0], &prev->object.oid, prev->buffer, prev->size);
+ if (parse_tree(next) < 0)
+ return -1;
+ init_tree_desc(&trees[1], &next->object.oid, next->buffer, next->size);
ret = unpack_trees(2, trees, &unpack_opts);
clear_unpack_trees_porcelain(&unpack_opts);
@@ -4579,7 +4681,7 @@ static void print_submodule_conflict_suggestion(struct string_list *csub) {
" - commit the resulting index in the superproject\n"),
tmp.buf, subs.buf);
- printf("%s", msg.buf);
+ advise_if_enabled(ADVICE_SUBMODULE_MERGE_CONFLICT, "%s", msg.buf);
strbuf_release(&subs);
strbuf_release(&tmp);
@@ -4594,6 +4696,7 @@ void merge_display_update_messages(struct merge_options *opt,
struct hashmap_iter iter;
struct strmap_entry *e;
struct string_list olist = STRING_LIST_INIT_NODUP;
+ FILE *o = stdout;
if (opt->record_conflict_msgs_as_headers)
BUG("Either display conflict messages or record them as headers, not both");
@@ -4610,6 +4713,10 @@ void merge_display_update_messages(struct merge_options *opt,
}
string_list_sort(&olist);
+ /* Print to stderr if we hit errors rather than just conflicts */
+ if (result->clean < 0)
+ o = stderr;
+
/* Iterate over the items, printing them */
for (int path_nr = 0; path_nr < olist.nr; ++path_nr) {
struct string_list *conflicts = olist.items[path_nr].util;
@@ -4617,25 +4724,31 @@ void merge_display_update_messages(struct merge_options *opt,
struct logical_conflict_info *info =
conflicts->items[i].util;
+ /* On failure, ignore regular conflict types */
+ if (result->clean < 0 &&
+ info->type < NB_REGULAR_CONFLICT_TYPES)
+ continue;
+
if (detailed) {
- printf("%lu", (unsigned long)info->paths.nr);
- putchar('\0');
+ fprintf(o, "%lu", (unsigned long)info->paths.nr);
+ fputc('\0', o);
for (int n = 0; n < info->paths.nr; n++) {
- fputs(info->paths.v[n], stdout);
- putchar('\0');
+ fputs(info->paths.v[n], o);
+ fputc('\0', o);
}
- fputs(type_short_descriptions[info->type],
- stdout);
- putchar('\0');
+ fputs(type_short_descriptions[info->type], o);
+ fputc('\0', o);
}
- puts(conflicts->items[i].string);
+ fputs(conflicts->items[i].string, o);
+ fputc('\n', o);
if (detailed)
- putchar('\0');
+ fputc('\0', o);
}
}
string_list_clear(&olist, 0);
- print_submodule_conflict_suggestion(&opti->conflicted_submodules);
+ if (result->clean >= 0)
+ print_submodule_conflict_suggestion(&opti->conflicted_submodules);
/* Also include needed rename limit adjustment now */
diff_warn_rename_limit("merge.renamelimit",
@@ -4683,9 +4796,6 @@ void merge_switch_to_result(struct merge_options *opt,
{
assert(opt->priv == NULL);
if (result->clean >= 0 && update_worktree_and_index) {
- const char *filename;
- FILE *fp;
-
trace2_region_enter("merge", "checkout", opt->repo);
if (checkout(opt, head, result->tree)) {
/* failure to function */
@@ -4711,10 +4821,17 @@ void merge_switch_to_result(struct merge_options *opt,
trace2_region_leave("merge", "record_conflicted", opt->repo);
trace2_region_enter("merge", "write_auto_merge", opt->repo);
- filename = git_path_auto_merge(opt->repo);
- fp = xfopen(filename, "w");
- fprintf(fp, "%s\n", oid_to_hex(&result->tree->object.oid));
- fclose(fp);
+ if (refs_update_ref(get_main_ref_store(opt->repo), "", "AUTO_MERGE",
+ &result->tree->object.oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_MSG_ON_ERR)) {
+ /* failure to function */
+ opt->priv = NULL;
+ result->clean = -1;
+ merge_finalize(opt, result);
+ trace2_region_leave("merge", "write_auto_merge",
+ opt->repo);
+ return;
+ }
trace2_region_leave("merge", "write_auto_merge", opt->repo);
}
if (display_update_msgs)
@@ -4902,8 +5019,7 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
trace2_region_leave("merge", "allocate/init", opt->repo);
}
-static void merge_check_renames_reusable(struct merge_options *opt,
- struct merge_result *result,
+static void merge_check_renames_reusable(struct merge_result *result,
struct tree *merge_base,
struct tree *side1,
struct tree *side2)
@@ -4948,6 +5064,26 @@ static void merge_check_renames_reusable(struct merge_options *opt,
/*** Function Grouping: merge_incore_*() and their internal variants ***/
+static void move_opt_priv_to_result_priv(struct merge_options *opt,
+ struct merge_result *result)
+{
+ /*
+ * opt->priv and result->priv are a bit weird. opt->priv contains
+ * information that we can re-use in subsequent merge operations to
+ * enable our cached renames optimization. The best way to provide
+ * that to subsequent merges is putting it in result->priv.
+ * However, putting it directly there would mean retrofitting lots
+ * of functions in this file to also take a merge_result pointer,
+ * which is ugly and annoying. So, we just make sure at the end of
+ * the merge (the outer merge if there are internal recursive ones)
+ * to move it.
+ */
+ assert(opt->priv && !result->priv);
+ result->priv = opt->priv;
+ result->_properly_initialized = RESULT_INITIALIZED;
+ opt->priv = NULL;
+}
+
/*
* Originally from merge_trees_internal(); heavily adapted, though.
*/
@@ -4973,18 +5109,18 @@ redo:
* TRANSLATORS: The %s arguments are: 1) tree hash of a merge
* base, and 2-3) the trees for the two trees we're merging.
*/
- err(opt, _("collecting merge info failed for trees %s, %s, %s"),
+ error(_("collecting merge info failed for trees %s, %s, %s"),
oid_to_hex(&merge_base->object.oid),
oid_to_hex(&side1->object.oid),
oid_to_hex(&side2->object.oid));
result->clean = -1;
+ move_opt_priv_to_result_priv(opt, result);
return;
}
trace2_region_leave("merge", "collect_merge_info", opt->repo);
trace2_region_enter("merge", "renames", opt->repo);
- result->clean = detect_and_process_renames(opt, merge_base,
- side1, side2);
+ result->clean = detect_and_process_renames(opt);
trace2_region_leave("merge", "renames", opt->repo);
if (opt->priv->renames.redo_after_renames == 2) {
trace2_region_enter("merge", "reset_maps", opt->repo);
@@ -5003,32 +5139,37 @@ redo:
if (result->clean >= 0) {
result->tree = parse_tree_indirect(&working_tree_oid);
+ if (!result->tree)
+ die(_("unable to read tree (%s)"),
+ oid_to_hex(&working_tree_oid));
/* existence of conflicted entries implies unclean */
result->clean &= strmap_empty(&opt->priv->conflicted);
}
- if (!opt->priv->call_depth) {
- result->priv = opt->priv;
- result->_properly_initialized = RESULT_INITIALIZED;
- opt->priv = NULL;
- }
+ if (!opt->priv->call_depth || result->clean < 0)
+ move_opt_priv_to_result_priv(opt, result);
}
/*
* Originally from merge_recursive_internal(); somewhat adapted, though.
*/
static void merge_ort_internal(struct merge_options *opt,
- struct commit_list *merge_bases,
+ const struct commit_list *_merge_bases,
struct commit *h1,
struct commit *h2,
struct merge_result *result)
{
+ struct commit_list *merge_bases = copy_commit_list(_merge_bases);
struct commit *next;
struct commit *merged_merge_bases;
const char *ancestor_name;
struct strbuf merge_base_abbrev = STRBUF_INIT;
if (!merge_bases) {
- merge_bases = repo_get_merge_bases(the_repository, h1, h2);
+ if (repo_get_merge_bases(the_repository, h1, h2,
+ &merge_bases) < 0) {
+ result->clean = -1;
+ goto out;
+ }
/* See merge-ort.h:merge_incore_recursive() declaration NOTE */
merge_bases = reverse_commit_list(merge_bases);
}
@@ -5071,7 +5212,7 @@ static void merge_ort_internal(struct merge_options *opt,
opt->branch2 = "Temporary merge branch 2";
merge_ort_internal(opt, NULL, prev, next, result);
if (result->clean < 0)
- return;
+ goto out;
opt->branch1 = saved_b1;
opt->branch2 = saved_b2;
opt->priv->call_depth--;
@@ -5094,6 +5235,9 @@ static void merge_ort_internal(struct merge_options *opt,
result);
strbuf_release(&merge_base_abbrev);
opt->ancestor = NULL; /* avoid accidental re-use of opt->ancestor */
+
+out:
+ free_commit_list(merge_bases);
}
void merge_incore_nonrecursive(struct merge_options *opt,
@@ -5106,7 +5250,7 @@ void merge_incore_nonrecursive(struct merge_options *opt,
trace2_region_enter("merge", "merge_start", opt->repo);
assert(opt->ancestor != NULL);
- merge_check_renames_reusable(opt, result, merge_base, side1, side2);
+ merge_check_renames_reusable(result, merge_base, side1, side2);
merge_start(opt, result);
/*
* Record the trees used in this merge, so if there's a next merge in
@@ -5123,7 +5267,7 @@ void merge_incore_nonrecursive(struct merge_options *opt,
}
void merge_incore_recursive(struct merge_options *opt,
- struct commit_list *merge_bases,
+ const struct commit_list *merge_bases,
struct commit *side1,
struct commit *side2,
struct merge_result *result)
diff --git a/merge-ort.h b/merge-ort.h
index ce56ec1a78..82f2b3222d 100644
--- a/merge-ort.h
+++ b/merge-ort.h
@@ -2,7 +2,7 @@
#define MERGE_ORT_H
#include "merge-recursive.h"
-#include "hash-ll.h"
+#include "hash.h"
struct commit;
struct tree;
@@ -59,7 +59,7 @@ struct merge_result {
* first", 2006-08-09)
*/
void merge_incore_recursive(struct merge_options *opt,
- struct commit_list *merge_bases,
+ const struct commit_list *merge_bases,
struct commit *side1,
struct commit *side2,
struct merge_result *result);
diff --git a/merge-recursive.c b/merge-recursive.c
index 6a4081bb0f..ed64a4c537 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -3,13 +3,13 @@
* Fredrik Kuivinen.
* The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "merge-recursive.h"
-#include "advice.h"
#include "alloc.h"
-#include "attr.h"
-#include "blob.h"
#include "cache-tree.h"
#include "commit.h"
#include "commit-reach.h"
@@ -32,8 +32,6 @@
#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"
@@ -244,7 +242,8 @@ enum rename_type {
struct stage_data {
struct diff_filespec stages[4]; /* mostly for oid & mode; maybe path */
struct rename_conflict_info *rename_conflict_info;
- unsigned processed:1;
+ unsigned processed:1,
+ rename_conflict_info_owned:1;
};
struct rename {
@@ -313,6 +312,7 @@ static inline void setup_rename_conflict_info(enum rename_type rename_type,
ci->ren1->dst_entry->processed = 0;
ci->ren1->dst_entry->rename_conflict_info = ci;
+ ci->ren1->dst_entry->rename_conflict_info_owned = 1;
if (ren2) {
ci->ren2->dst_entry->rename_conflict_info = ci;
}
@@ -410,8 +410,9 @@ static inline int merge_detect_rename(struct merge_options *opt)
static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
{
- parse_tree(tree);
- init_tree_desc(desc, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ exit(128);
+ init_tree_desc(desc, &tree->object.oid, tree->buffer, tree->size);
}
static int unpack_trees_start(struct merge_options *opt,
@@ -1052,13 +1053,14 @@ static int merge_3way(struct merge_options *opt,
const int extra_marker_size)
{
mmfile_t orig, src1, src2;
- struct ll_merge_options ll_opts = {0};
+ struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
char *base, *name1, *name2;
enum ll_merge_result merge_status;
ll_opts.renormalize = opt->renormalize;
ll_opts.extra_marker_size = extra_marker_size;
ll_opts.xdl_opts = opt->xdl_opts;
+ ll_opts.conflict_style = opt->conflict_style;
if (opt->priv->call_depth) {
ll_opts.virtual_ancestor = 1;
@@ -1144,7 +1146,13 @@ static int find_first_merges(struct repository *repo,
die("revision walk setup failed");
while ((commit = get_revision(&revs)) != NULL) {
struct object *o = &(commit->object);
- if (repo_in_merge_bases(repo, b, commit))
+ int ret = repo_in_merge_bases(repo, b, commit);
+ if (ret < 0) {
+ object_array_clear(&merges);
+ release_revisions(&revs);
+ return ret;
+ }
+ if (ret)
add_object_array(o, NULL, &merges);
}
reset_revision_walk();
@@ -1159,9 +1167,17 @@ static int find_first_merges(struct repository *repo,
contains_another = 0;
for (j = 0; j < merges.nr; j++) {
struct commit *m2 = (struct commit *) merges.objects[j].item;
- if (i != j && repo_in_merge_bases(repo, m2, m1)) {
- contains_another = 1;
- break;
+ if (i != j) {
+ int ret = repo_in_merge_bases(repo, m2, m1);
+ if (ret < 0) {
+ object_array_clear(&merges);
+ release_revisions(&revs);
+ return ret;
+ }
+ if (ret > 0) {
+ contains_another = 1;
+ break;
+ }
}
}
@@ -1197,7 +1213,7 @@ static int merge_submodule(struct merge_options *opt,
const struct object_id *b)
{
struct repository subrepo;
- int ret = 0;
+ int ret = 0, ret2;
struct commit *commit_base, *commit_a, *commit_b;
int parent_count;
struct object_array merges;
@@ -1234,14 +1250,32 @@ static int merge_submodule(struct merge_options *opt,
}
/* check whether both changes are forward */
- if (!repo_in_merge_bases(&subrepo, commit_base, commit_a) ||
- !repo_in_merge_bases(&subrepo, commit_base, commit_b)) {
+ ret2 = repo_in_merge_bases(&subrepo, commit_base, commit_a);
+ if (ret2 < 0) {
+ output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (ret2 > 0)
+ ret2 = repo_in_merge_bases(&subrepo, commit_base, commit_b);
+ if (ret2 < 0) {
+ output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (!ret2) {
output(opt, 1, _("Failed to merge submodule %s (commits don't follow merge-base)"), path);
goto cleanup;
}
/* Case #1: a is contained in b or vice versa */
- if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
+ ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);
+ if (ret2 < 0) {
+ output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (ret2) {
oidcpy(result, b);
if (show(opt, 3)) {
output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
@@ -1254,7 +1288,13 @@ static int merge_submodule(struct merge_options *opt,
ret = 1;
goto cleanup;
}
- if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
+ ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);
+ if (ret2 < 0) {
+ output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+ ret = -1;
+ goto cleanup;
+ }
+ if (ret2) {
oidcpy(result, a);
if (show(opt, 3)) {
output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
@@ -1283,6 +1323,10 @@ static int merge_submodule(struct merge_options *opt,
parent_count = find_first_merges(&subrepo, &merges, path,
commit_a, commit_b);
switch (parent_count) {
+ case -1:
+ output(opt, 1,_("Failed to merge submodule %s (repository corrupt)"), path);
+ ret = -1;
+ break;
case 0:
output(opt, 1, _("Failed to merge submodule %s (merge following commits not found)"), path);
break;
@@ -1383,12 +1427,12 @@ static int merge_mode_and_contents(struct merge_options *opt,
extra_marker_size);
if ((merge_status < 0) || !result_buf.ptr)
- ret = err(opt, _("Failed to execute internal merge"));
+ ret = err(opt, _("failed to execute internal merge"));
if (!ret &&
write_object_file(result_buf.ptr, result_buf.size,
OBJ_BLOB, &result->blob.oid))
- ret = err(opt, _("Unable to add %s to database"),
+ ret = err(opt, _("unable to add %s to database"),
a->path);
free(result_buf.ptr);
@@ -1397,11 +1441,14 @@ static int merge_mode_and_contents(struct merge_options *opt,
/* FIXME: bug, what if modes didn't match? */
result->clean = (merge_status == 0);
} else if (S_ISGITLINK(a->mode)) {
- result->clean = merge_submodule(opt, &result->blob.oid,
- o->path,
- &o->oid,
- &a->oid,
- &b->oid);
+ int clean = merge_submodule(opt, &result->blob.oid,
+ o->path,
+ &o->oid,
+ &a->oid,
+ &b->oid);
+ if (clean < 0)
+ return -1;
+ result->clean = clean;
} else if (S_ISLNK(a->mode)) {
switch (opt->recursive_variant) {
case MERGE_VARIANT_NORMAL:
@@ -3013,6 +3060,10 @@ static void final_cleanup_rename(struct string_list *rename)
for (i = 0; i < rename->nr; i++) {
re = rename->items[i].util;
diff_free_filepair(re->pair);
+ if (re->src_entry->rename_conflict_info_owned)
+ FREE_AND_NULL(re->src_entry->rename_conflict_info);
+ if (re->dst_entry->rename_conflict_info_owned)
+ FREE_AND_NULL(re->dst_entry->rename_conflict_info);
}
string_list_clear(rename, 1);
free(rename);
@@ -3585,15 +3636,16 @@ static int merge_trees_internal(struct merge_options *opt,
static int merge_recursive_internal(struct merge_options *opt,
struct commit *h1,
struct commit *h2,
- struct commit_list *merge_bases,
+ const struct commit_list *_merge_bases,
struct commit **result)
{
+ struct commit_list *merge_bases = copy_commit_list(_merge_bases);
struct commit_list *iter;
struct commit *merged_merge_bases;
struct tree *result_tree;
- int clean;
const char *ancestor_name;
struct strbuf merge_base_abbrev = STRBUF_INIT;
+ int ret;
if (show(opt, 4)) {
output(opt, 4, _("Merging:"));
@@ -3602,7 +3654,11 @@ static int merge_recursive_internal(struct merge_options *opt,
}
if (!merge_bases) {
- merge_bases = repo_get_merge_bases(the_repository, h1, h2);
+ if (repo_get_merge_bases(the_repository, h1, h2,
+ &merge_bases) < 0) {
+ ret = -1;
+ goto out;
+ }
merge_bases = reverse_commit_list(merge_bases);
}
@@ -3652,14 +3708,18 @@ static int merge_recursive_internal(struct merge_options *opt,
opt->branch1 = "Temporary merge branch 1";
opt->branch2 = "Temporary merge branch 2";
if (merge_recursive_internal(opt, merged_merge_bases, iter->item,
- NULL, &merged_merge_bases) < 0)
- return -1;
+ NULL, &merged_merge_bases) < 0) {
+ ret = -1;
+ goto out;
+ }
opt->branch1 = saved_b1;
opt->branch2 = saved_b2;
opt->priv->call_depth--;
- if (!merged_merge_bases)
- return err(opt, _("merge returned no commit"));
+ if (!merged_merge_bases) {
+ ret = err(opt, _("merge returned no commit"));
+ goto out;
+ }
}
/*
@@ -3676,17 +3736,16 @@ static int merge_recursive_internal(struct merge_options *opt,
repo_read_index(opt->repo);
opt->ancestor = ancestor_name;
- clean = merge_trees_internal(opt,
- repo_get_commit_tree(opt->repo, h1),
- repo_get_commit_tree(opt->repo, h2),
- repo_get_commit_tree(opt->repo,
- merged_merge_bases),
- &result_tree);
- strbuf_release(&merge_base_abbrev);
+ ret = merge_trees_internal(opt,
+ repo_get_commit_tree(opt->repo, h1),
+ repo_get_commit_tree(opt->repo, h2),
+ repo_get_commit_tree(opt->repo,
+ merged_merge_bases),
+ &result_tree);
opt->ancestor = NULL; /* avoid accidental re-use of opt->ancestor */
- if (clean < 0) {
+ if (ret < 0) {
flush_output(opt);
- return clean;
+ goto out;
}
if (opt->priv->call_depth) {
@@ -3695,7 +3754,11 @@ static int merge_recursive_internal(struct merge_options *opt,
commit_list_insert(h1, &(*result)->parents);
commit_list_insert(h2, &(*result)->parents->next);
}
- return clean;
+
+out:
+ strbuf_release(&merge_base_abbrev);
+ free_commit_list(merge_bases);
+ return ret;
}
static int merge_start(struct merge_options *opt, struct tree *head)
@@ -3750,6 +3813,9 @@ static void merge_finalize(struct merge_options *opt)
if (show(opt, 2))
diff_warn_rename_limit("merge.renamelimit",
opt->priv->needed_rename_limit, 0);
+ hashmap_clear_and_free(&opt->priv->current_file_dir_set,
+ struct path_hashmap_entry, e);
+ string_list_clear(&opt->priv->df_conflict_file_set, 0);
FREE_AND_NULL(opt->priv);
}
@@ -3774,7 +3840,7 @@ int merge_trees(struct merge_options *opt,
int merge_recursive(struct merge_options *opt,
struct commit *h1,
struct commit *h2,
- struct commit_list *merge_bases,
+ const struct commit_list *merge_bases,
struct commit **result)
{
int clean;
@@ -3816,7 +3882,7 @@ int merge_recursive_generic(struct merge_options *opt,
const struct object_id *head,
const struct object_id *merge,
int num_merge_bases,
- const struct object_id **merge_bases,
+ const struct object_id *merge_bases,
struct commit **result)
{
int clean;
@@ -3829,10 +3895,10 @@ int merge_recursive_generic(struct merge_options *opt,
int i;
for (i = 0; i < num_merge_bases; ++i) {
struct commit *base;
- if (!(base = get_ref(opt->repo, merge_bases[i],
- oid_to_hex(merge_bases[i]))))
+ if (!(base = get_ref(opt->repo, &merge_bases[i],
+ oid_to_hex(&merge_bases[i]))))
return err(opt, _("Could not parse object '%s'"),
- oid_to_hex(merge_bases[i]));
+ oid_to_hex(&merge_bases[i]));
commit_list_insert(base, &ca);
}
if (num_merge_bases == 1)
@@ -3842,6 +3908,7 @@ int merge_recursive_generic(struct merge_options *opt,
repo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR);
clean = merge_recursive(opt, head_commit, next_commit, ca,
result);
+ free_commit_list(ca);
if (clean < 0) {
rollback_lock_file(&lock);
return clean;
@@ -3854,7 +3921,7 @@ int merge_recursive_generic(struct merge_options *opt,
return clean ? 0 : 1;
}
-static void merge_recursive_config(struct merge_options *opt)
+static void merge_recursive_config(struct merge_options *opt, int ui)
{
char *value = NULL;
int renormalize = 0;
@@ -3883,11 +3950,20 @@ static void merge_recursive_config(struct merge_options *opt)
} /* avoid erroring on values from future versions of git */
free(value);
}
+ if (ui) {
+ if (!git_config_get_string("diff.algorithm", &value)) {
+ long diff_algorithm = parse_algorithm_value(value);
+ if (diff_algorithm < 0)
+ die(_("unknown value for config '%s': %s"), "diff.algorithm", value);
+ opt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
+ free(value);
+ }
+ }
git_config(git_xmerge_config, NULL);
}
-void init_merge_options(struct merge_options *opt,
- struct repository *repo)
+static void init_merge_options(struct merge_options *opt,
+ struct repository *repo, int ui)
{
const char *merge_verbosity;
memset(opt, 0, sizeof(struct merge_options));
@@ -3904,7 +3980,9 @@ void init_merge_options(struct merge_options *opt,
opt->renormalize = 0;
- merge_recursive_config(opt);
+ opt->conflict_style = -1;
+
+ merge_recursive_config(opt, ui);
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
if (merge_verbosity)
opt->verbosity = strtol(merge_verbosity, NULL, 10);
@@ -3912,6 +3990,34 @@ void init_merge_options(struct merge_options *opt,
opt->buffer_output = 0;
}
+void init_ui_merge_options(struct merge_options *opt,
+ struct repository *repo)
+{
+ init_merge_options(opt, repo, 1);
+}
+
+void init_basic_merge_options(struct merge_options *opt,
+ struct repository *repo)
+{
+ init_merge_options(opt, repo, 0);
+}
+
+/*
+ * For now, members of merge_options do not need deep copying, but
+ * it may change in the future, in which case we would need to update
+ * this, and also make a matching change to clear_merge_options() to
+ * release the resources held by a copied instance.
+ */
+void copy_merge_options(struct merge_options *dst, struct merge_options *src)
+{
+ *dst = *src;
+}
+
+void clear_merge_options(struct merge_options *opt UNUSED)
+{
+ ; /* no-op as our copy is shallow right now */
+}
+
int parse_merge_opt(struct merge_options *opt, const char *s)
{
const char *arg;
diff --git a/merge-recursive.h b/merge-recursive.h
index b88000e3c2..0b91f28f90 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -31,6 +31,7 @@ struct merge_options {
/* xdiff-related options (patience, ignore whitespace, ours/theirs) */
long xdl_opts;
+ int conflict_style;
enum {
MERGE_VARIANT_NORMAL = 0,
MERGE_VARIANT_OURS,
@@ -53,7 +54,13 @@ struct merge_options {
struct merge_options_internal *priv;
};
-void init_merge_options(struct merge_options *opt, struct repository *repo);
+/* for use by porcelain commands */
+void init_ui_merge_options(struct merge_options *opt, struct repository *repo);
+/* for use by plumbing commands */
+void init_basic_merge_options(struct merge_options *opt, struct repository *repo);
+
+void copy_merge_options(struct merge_options *dst, struct merge_options *src);
+void clear_merge_options(struct merge_options *opt);
/* parse the option in s and update the relevant field of opt */
int parse_merge_opt(struct merge_options *opt, const char *s);
@@ -100,7 +107,7 @@ int merge_trees(struct merge_options *opt,
int merge_recursive(struct merge_options *opt,
struct commit *h1,
struct commit *h2,
- struct commit_list *merge_bases,
+ const struct commit_list *merge_bases,
struct commit **result);
/*
@@ -119,7 +126,7 @@ int merge_recursive_generic(struct merge_options *opt,
const struct object_id *head,
const struct object_id *merge,
int num_merge_bases,
- const struct object_id **merge_bases,
+ const struct object_id *merge_bases,
struct commit **result);
#endif
diff --git a/merge.c b/merge.c
index b60925459c..fe3efa4b24 100644
--- a/merge.c
+++ b/merge.c
@@ -1,6 +1,6 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "diff.h"
-#include "diffcore.h"
#include "gettext.h"
#include "hash.h"
#include "hex.h"
@@ -13,7 +13,6 @@
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
-#include "dir.h"
static const char *merge_argument(struct commit *commit)
{
@@ -80,8 +79,12 @@ int checkout_fast_forward(struct repository *r,
return -1;
}
for (i = 0; i < nr_trees; i++) {
- parse_tree(trees[i]);
- init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+ if (parse_tree(trees[i]) < 0) {
+ rollback_lock_file(&lock_file);
+ return -1;
+ }
+ init_tree_desc(t+i, &trees[i]->object.oid,
+ trees[i]->buffer, trees[i]->size);
}
memset(&opts, 0, sizeof(opts));
diff --git a/mergetools/vimdiff b/mergetools/vimdiff
index 06937acbf5..ffc9be86c8 100644
--- a/mergetools/vimdiff
+++ b/mergetools/vimdiff
@@ -72,7 +72,6 @@ gen_cmd_aux () {
nested=0
nested_min=100
-
# Step 1:
#
# Increase/decrease "start"/"end" indices respectively to get rid of
@@ -87,7 +86,7 @@ gen_cmd_aux () {
IFS=#
for c in $(echo "$LAYOUT" | sed 's:.:&#:g')
do
- if test "$c" = " "
+ if test -z "$c" || test "$c" = " "
then
continue
fi
@@ -326,7 +325,7 @@ gen_cmd () {
fi
# If this is a single window diff with all the buffers
- if ! echo "$tab" | grep ",\|/" >/dev/null
+ if ! echo "$tab" | grep -E ",|/" >/dev/null
then
CMD="$CMD | silent execute 'bufdo diffthis'"
fi
@@ -371,9 +370,17 @@ diff_cmd_help () {
merge_cmd () {
- layout=$(git config mergetool.vimdiff.layout)
+ TOOL=$1
- case "$1" in
+ layout=$(git config "mergetool.$TOOL.layout")
+
+ # backward compatibility:
+ if test -z "$layout"
+ then
+ layout=$(git config mergetool.vimdiff.layout)
+ fi
+
+ case "$TOOL" in
*vimdiff)
if test -z "$layout"
then
@@ -404,7 +411,7 @@ merge_cmd () {
-f "$FINAL_CMD" '"$LOCAL"' '"$BASE"' '"$REMOTE"' '"$MERGED"'
else
# If there is no BASE (example: a merge conflict in a new file
- # with the same name created in both braches which didn't exist
+ # with the same name created in both branches which didn't exist
# before), close all BASE windows using vim's "quit" command
FINAL_CMD=$(echo "$FINAL_CMD" | \
diff --git a/mergetools/vscode b/mergetools/vscode
new file mode 100644
index 0000000000..3b39b458d6
--- /dev/null
+++ b/mergetools/vscode
@@ -0,0 +1,19 @@
+diff_cmd () {
+ "$merge_tool_path" --wait --diff "$LOCAL" "$REMOTE"
+}
+
+diff_cmd_help () {
+ echo "Use Visual Studio Code (requires a graphical session)"
+}
+
+merge_cmd () {
+ "$merge_tool_path" --wait --merge "$REMOTE" "$LOCAL" "$BASE" "$MERGED"
+}
+
+merge_cmd_help () {
+ echo "Use Visual Studio Code (requires a graphical session)"
+}
+
+translate_merge_tool_path () {
+ echo code
+}
diff --git a/midx-write.c b/midx-write.c
new file mode 100644
index 0000000000..b3a5f6c516
--- /dev/null
+++ b/midx-write.c
@@ -0,0 +1,1777 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "config.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "hash-lookup.h"
+#include "midx.h"
+#include "progress.h"
+#include "trace2.h"
+#include "run-command.h"
+#include "chunk-format.h"
+#include "pack-bitmap.h"
+#include "refs.h"
+#include "revision.h"
+#include "list-objects.h"
+#include "path.h"
+#include "pack-revindex.h"
+
+#define PACK_EXPIRED UINT_MAX
+#define BITMAP_POS_UNKNOWN (~((uint32_t)0))
+#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
+#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
+
+extern int midx_checksum_valid(struct multi_pack_index *m);
+extern void clear_midx_files_ext(const char *object_dir, const char *ext,
+ const char *keep_hash);
+extern void clear_incremental_midx_files_ext(const char *object_dir,
+ const char *ext,
+ const char **keep_hashes,
+ uint32_t hashes_nr);
+extern int cmp_idx_or_pack_name(const char *idx_or_pack_name,
+ const char *idx_name);
+
+static size_t write_midx_header(struct hashfile *f,
+ unsigned char num_chunks,
+ uint32_t num_packs)
+{
+ hashwrite_be32(f, MIDX_SIGNATURE);
+ hashwrite_u8(f, MIDX_VERSION);
+ hashwrite_u8(f, oid_version(the_hash_algo));
+ hashwrite_u8(f, num_chunks);
+ hashwrite_u8(f, 0); /* unused */
+ hashwrite_be32(f, num_packs);
+
+ return MIDX_HEADER_SIZE;
+}
+
+struct pack_info {
+ uint32_t orig_pack_int_id;
+ char *pack_name;
+ struct packed_git *p;
+
+ uint32_t bitmap_pos;
+ uint32_t bitmap_nr;
+
+ unsigned expired : 1;
+};
+
+static void fill_pack_info(struct pack_info *info,
+ struct packed_git *p, const char *pack_name,
+ uint32_t orig_pack_int_id)
+{
+ memset(info, 0, sizeof(struct pack_info));
+
+ info->orig_pack_int_id = orig_pack_int_id;
+ info->pack_name = xstrdup(pack_name);
+ info->p = p;
+ info->bitmap_pos = BITMAP_POS_UNKNOWN;
+}
+
+static int pack_info_compare(const void *_a, const void *_b)
+{
+ struct pack_info *a = (struct pack_info *)_a;
+ struct pack_info *b = (struct pack_info *)_b;
+ return strcmp(a->pack_name, b->pack_name);
+}
+
+static int idx_or_pack_name_cmp(const void *_va, const void *_vb)
+{
+ const char *pack_name = _va;
+ const struct pack_info *compar = _vb;
+
+ return cmp_idx_or_pack_name(pack_name, compar->pack_name);
+}
+
+struct write_midx_context {
+ struct pack_info *info;
+ size_t nr;
+ size_t alloc;
+ struct multi_pack_index *m;
+ struct multi_pack_index *base_midx;
+ struct progress *progress;
+ unsigned pack_paths_checked;
+
+ struct pack_midx_entry *entries;
+ size_t entries_nr;
+
+ uint32_t *pack_perm;
+ uint32_t *pack_order;
+ unsigned large_offsets_needed:1;
+ uint32_t num_large_offsets;
+
+ int preferred_pack_idx;
+
+ int incremental;
+ uint32_t num_multi_pack_indexes_before;
+
+ struct string_list *to_include;
+};
+
+static int should_include_pack(const struct write_midx_context *ctx,
+ const char *file_name)
+{
+ /*
+ * Note that at most one of ctx->m and ctx->to_include are set,
+ * so we are testing midx_contains_pack() and
+ * string_list_has_string() independently (guarded by the
+ * appropriate NULL checks).
+ *
+ * We could support passing to_include while reusing an existing
+ * MIDX, but don't currently since the reuse process drags
+ * forward all packs from an existing MIDX (without checking
+ * whether or not they appear in the to_include list).
+ *
+ * If we added support for that, these next two conditional
+ * should be performed independently (likely checking
+ * to_include before the existing MIDX).
+ */
+ if (ctx->m && midx_contains_pack(ctx->m, file_name))
+ return 0;
+ else if (ctx->base_midx && midx_contains_pack(ctx->base_midx,
+ file_name))
+ return 0;
+ else if (ctx->to_include &&
+ !string_list_has_string(ctx->to_include, file_name))
+ return 0;
+ return 1;
+}
+
+static void add_pack_to_midx(const char *full_path, size_t full_path_len,
+ const char *file_name, void *data)
+{
+ struct write_midx_context *ctx = data;
+ struct packed_git *p;
+
+ if (ends_with(file_name, ".idx")) {
+ display_progress(ctx->progress, ++ctx->pack_paths_checked);
+
+ if (!should_include_pack(ctx, file_name))
+ return;
+
+ ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
+ p = add_packed_git(full_path, full_path_len, 0);
+ if (!p) {
+ warning(_("failed to add packfile '%s'"),
+ full_path);
+ return;
+ }
+
+ if (open_pack_index(p)) {
+ warning(_("failed to open pack-index '%s'"),
+ full_path);
+ close_pack(p);
+ free(p);
+ return;
+ }
+
+ fill_pack_info(&ctx->info[ctx->nr], p, file_name, ctx->nr);
+ ctx->nr++;
+ }
+}
+
+struct pack_midx_entry {
+ struct object_id oid;
+ uint32_t pack_int_id;
+ time_t pack_mtime;
+ uint64_t offset;
+ unsigned preferred : 1;
+};
+
+static int midx_oid_compare(const void *_a, const void *_b)
+{
+ const struct pack_midx_entry *a = (const struct pack_midx_entry *)_a;
+ const struct pack_midx_entry *b = (const struct pack_midx_entry *)_b;
+ int cmp = oidcmp(&a->oid, &b->oid);
+
+ if (cmp)
+ return cmp;
+
+ /* Sort objects in a preferred pack first when multiple copies exist. */
+ if (a->preferred > b->preferred)
+ return -1;
+ if (a->preferred < b->preferred)
+ return 1;
+
+ if (a->pack_mtime > b->pack_mtime)
+ return -1;
+ else if (a->pack_mtime < b->pack_mtime)
+ return 1;
+
+ return a->pack_int_id - b->pack_int_id;
+}
+
+static int nth_midxed_pack_midx_entry(struct multi_pack_index *m,
+ struct pack_midx_entry *e,
+ uint32_t pos)
+{
+ if (pos >= m->num_objects + m->num_objects_in_base)
+ return 1;
+
+ nth_midxed_object_oid(&e->oid, m, pos);
+ e->pack_int_id = nth_midxed_pack_int_id(m, pos);
+ e->offset = nth_midxed_offset(m, pos);
+
+ /* consider objects in midx to be from "old" packs */
+ e->pack_mtime = 0;
+ return 0;
+}
+
+static void fill_pack_entry(uint32_t pack_int_id,
+ struct packed_git *p,
+ uint32_t cur_object,
+ struct pack_midx_entry *entry,
+ int preferred)
+{
+ if (nth_packed_object_id(&entry->oid, p, cur_object) < 0)
+ die(_("failed to locate object %d in packfile"), cur_object);
+
+ entry->pack_int_id = pack_int_id;
+ entry->pack_mtime = p->mtime;
+
+ entry->offset = nth_packed_object_offset(p, cur_object);
+ entry->preferred = !!preferred;
+}
+
+struct midx_fanout {
+ struct pack_midx_entry *entries;
+ size_t nr, alloc;
+};
+
+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);
+}
+
+static void midx_fanout_sort(struct midx_fanout *fanout)
+{
+ QSORT(fanout->entries, fanout->nr, midx_oid_compare);
+}
+
+static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
+ struct multi_pack_index *m,
+ uint32_t cur_fanout,
+ int preferred_pack)
+{
+ uint32_t start = m->num_objects_in_base, end;
+ uint32_t cur_object;
+
+ if (m->base_midx)
+ midx_fanout_add_midx_fanout(fanout, m->base_midx, cur_fanout,
+ preferred_pack);
+
+ if (cur_fanout)
+ start += ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
+ end = m->num_objects_in_base + ntohl(m->chunk_oid_fanout[cur_fanout]);
+
+ for (cur_object = start; cur_object < end; cur_object++) {
+ if ((preferred_pack > -1) &&
+ (preferred_pack == nth_midxed_pack_int_id(m, cur_object))) {
+ /*
+ * Objects from preferred packs are added
+ * separately.
+ */
+ continue;
+ }
+
+ midx_fanout_grow(fanout, fanout->nr + 1);
+ nth_midxed_pack_midx_entry(m,
+ &fanout->entries[fanout->nr],
+ cur_object);
+ fanout->entries[fanout->nr].preferred = 0;
+ fanout->nr++;
+ }
+}
+
+static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
+ struct pack_info *info,
+ uint32_t cur_pack,
+ int preferred,
+ uint32_t cur_fanout)
+{
+ struct packed_git *pack = info[cur_pack].p;
+ uint32_t start = 0, end;
+ uint32_t cur_object;
+
+ if (cur_fanout)
+ start = get_pack_fanout(pack, cur_fanout - 1);
+ end = get_pack_fanout(pack, cur_fanout);
+
+ for (cur_object = start; cur_object < end; cur_object++) {
+ midx_fanout_grow(fanout, fanout->nr + 1);
+ fill_pack_entry(cur_pack,
+ info[cur_pack].p,
+ cur_object,
+ &fanout->entries[fanout->nr],
+ preferred);
+ fanout->nr++;
+ }
+}
+
+/*
+ * It is possible to artificially get into a state where there are many
+ * duplicate copies of objects. That can create high memory pressure if
+ * we are to create a list of all objects before de-duplication. To reduce
+ * this memory pressure without a significant performance drop, automatically
+ * group objects by the first byte of their object id. Use the IDX fanout
+ * tables to group the data, copy to a local array, then sort.
+ *
+ * Copy only the de-duplicated entries (selected by most-recent modified time
+ * of a packfile containing the object).
+ */
+static void compute_sorted_entries(struct write_midx_context *ctx,
+ uint32_t start_pack)
+{
+ uint32_t cur_fanout, cur_pack, cur_object;
+ size_t alloc_objects, total_objects = 0;
+ struct midx_fanout fanout = { 0 };
+
+ for (cur_pack = start_pack; cur_pack < ctx->nr; cur_pack++)
+ total_objects = st_add(total_objects,
+ ctx->info[cur_pack].p->num_objects);
+
+ /*
+ * As we de-duplicate by fanout value, we expect the fanout
+ * slices to be evenly distributed, with some noise. Hence,
+ * allocate slightly more than one 256th.
+ */
+ alloc_objects = fanout.alloc = total_objects > 3200 ? total_objects / 200 : 16;
+
+ ALLOC_ARRAY(fanout.entries, fanout.alloc);
+ ALLOC_ARRAY(ctx->entries, alloc_objects);
+ ctx->entries_nr = 0;
+
+ for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
+ fanout.nr = 0;
+
+ if (ctx->m && !ctx->incremental)
+ midx_fanout_add_midx_fanout(&fanout, ctx->m, cur_fanout,
+ ctx->preferred_pack_idx);
+
+ for (cur_pack = start_pack; cur_pack < ctx->nr; cur_pack++) {
+ int preferred = cur_pack == ctx->preferred_pack_idx;
+ midx_fanout_add_pack_fanout(&fanout,
+ ctx->info, cur_pack,
+ preferred, cur_fanout);
+ }
+
+ if (-1 < ctx->preferred_pack_idx && ctx->preferred_pack_idx < start_pack)
+ midx_fanout_add_pack_fanout(&fanout, ctx->info,
+ ctx->preferred_pack_idx, 1,
+ cur_fanout);
+
+ midx_fanout_sort(&fanout);
+
+ /*
+ * The batch is now sorted by OID and then mtime (descending).
+ * Take only the first duplicate.
+ */
+ for (cur_object = 0; cur_object < fanout.nr; cur_object++) {
+ if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
+ &fanout.entries[cur_object].oid))
+ continue;
+ if (ctx->incremental && ctx->base_midx &&
+ midx_has_oid(ctx->base_midx,
+ &fanout.entries[cur_object].oid))
+ continue;
+
+ ALLOC_GROW(ctx->entries, st_add(ctx->entries_nr, 1),
+ alloc_objects);
+ memcpy(&ctx->entries[ctx->entries_nr],
+ &fanout.entries[cur_object],
+ sizeof(struct pack_midx_entry));
+ ctx->entries_nr++;
+ }
+ }
+
+ free(fanout.entries);
+}
+
+static int write_midx_pack_names(struct hashfile *f, void *data)
+{
+ struct write_midx_context *ctx = data;
+ uint32_t i;
+ unsigned char padding[MIDX_CHUNK_ALIGNMENT];
+ size_t written = 0;
+
+ for (i = 0; i < ctx->nr; i++) {
+ size_t writelen;
+
+ if (ctx->info[i].expired)
+ continue;
+
+ if (i && strcmp(ctx->info[i].pack_name, ctx->info[i - 1].pack_name) <= 0)
+ BUG("incorrect pack-file order: %s before %s",
+ ctx->info[i - 1].pack_name,
+ ctx->info[i].pack_name);
+
+ writelen = strlen(ctx->info[i].pack_name) + 1;
+ hashwrite(f, ctx->info[i].pack_name, writelen);
+ written += writelen;
+ }
+
+ /* add padding to be aligned */
+ i = MIDX_CHUNK_ALIGNMENT - (written % MIDX_CHUNK_ALIGNMENT);
+ if (i < MIDX_CHUNK_ALIGNMENT) {
+ memset(padding, 0, sizeof(padding));
+ hashwrite(f, padding, i);
+ }
+
+ return 0;
+}
+
+static int write_midx_bitmapped_packs(struct hashfile *f, void *data)
+{
+ struct write_midx_context *ctx = data;
+ size_t i;
+
+ for (i = 0; i < ctx->nr; i++) {
+ struct pack_info *pack = &ctx->info[i];
+ if (pack->expired)
+ continue;
+
+ if (pack->bitmap_pos == BITMAP_POS_UNKNOWN && pack->bitmap_nr)
+ BUG("pack '%s' has no bitmap position, but has %d bitmapped object(s)",
+ pack->pack_name, pack->bitmap_nr);
+
+ hashwrite_be32(f, pack->bitmap_pos);
+ hashwrite_be32(f, pack->bitmap_nr);
+ }
+ return 0;
+}
+
+static int write_midx_oid_fanout(struct hashfile *f,
+ void *data)
+{
+ struct write_midx_context *ctx = data;
+ struct pack_midx_entry *list = ctx->entries;
+ struct pack_midx_entry *last = ctx->entries + ctx->entries_nr;
+ uint32_t count = 0;
+ uint32_t i;
+
+ /*
+ * Write the first-level table (the list is sorted,
+ * but we use a 256-entry lookup to be able to avoid
+ * having to do eight extra binary search iterations).
+ */
+ for (i = 0; i < 256; i++) {
+ struct pack_midx_entry *next = list;
+
+ while (next < last && next->oid.hash[0] == i) {
+ count++;
+ next++;
+ }
+
+ hashwrite_be32(f, count);
+ list = next;
+ }
+
+ return 0;
+}
+
+static int write_midx_oid_lookup(struct hashfile *f,
+ void *data)
+{
+ struct write_midx_context *ctx = data;
+ unsigned char hash_len = the_hash_algo->rawsz;
+ struct pack_midx_entry *list = ctx->entries;
+ uint32_t i;
+
+ for (i = 0; i < ctx->entries_nr; i++) {
+ struct pack_midx_entry *obj = list++;
+
+ if (i < ctx->entries_nr - 1) {
+ struct pack_midx_entry *next = list;
+ if (oidcmp(&obj->oid, &next->oid) >= 0)
+ BUG("OIDs not in order: %s >= %s",
+ oid_to_hex(&obj->oid),
+ oid_to_hex(&next->oid));
+ }
+
+ hashwrite(f, obj->oid.hash, (int)hash_len);
+ }
+
+ return 0;
+}
+
+static int write_midx_object_offsets(struct hashfile *f,
+ void *data)
+{
+ struct write_midx_context *ctx = data;
+ struct pack_midx_entry *list = ctx->entries;
+ uint32_t i, nr_large_offset = 0;
+
+ for (i = 0; i < ctx->entries_nr; i++) {
+ struct pack_midx_entry *obj = list++;
+
+ if (ctx->pack_perm[obj->pack_int_id] == PACK_EXPIRED)
+ BUG("object %s is in an expired pack with int-id %d",
+ oid_to_hex(&obj->oid),
+ obj->pack_int_id);
+
+ hashwrite_be32(f, ctx->pack_perm[obj->pack_int_id]);
+
+ if (ctx->large_offsets_needed && obj->offset >> 31)
+ hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
+ else if (!ctx->large_offsets_needed && obj->offset >> 32)
+ BUG("object %s requires a large offset (%"PRIx64") but the MIDX is not writing large offsets!",
+ oid_to_hex(&obj->oid),
+ obj->offset);
+ else
+ hashwrite_be32(f, (uint32_t)obj->offset);
+ }
+
+ return 0;
+}
+
+static int write_midx_large_offsets(struct hashfile *f,
+ void *data)
+{
+ struct write_midx_context *ctx = data;
+ struct pack_midx_entry *list = ctx->entries;
+ struct pack_midx_entry *end = ctx->entries + ctx->entries_nr;
+ uint32_t nr_large_offset = ctx->num_large_offsets;
+
+ while (nr_large_offset) {
+ struct pack_midx_entry *obj;
+ uint64_t offset;
+
+ if (list >= end)
+ BUG("too many large-offset objects");
+
+ obj = list++;
+ offset = obj->offset;
+
+ if (!(offset >> 31))
+ continue;
+
+ hashwrite_be64(f, offset);
+
+ nr_large_offset--;
+ }
+
+ return 0;
+}
+
+static int write_midx_revindex(struct hashfile *f,
+ void *data)
+{
+ struct write_midx_context *ctx = data;
+ uint32_t i, nr_base;
+
+ if (ctx->incremental && ctx->base_midx)
+ nr_base = ctx->base_midx->num_objects +
+ ctx->base_midx->num_objects_in_base;
+ else
+ nr_base = 0;
+
+ for (i = 0; i < ctx->entries_nr; i++)
+ hashwrite_be32(f, ctx->pack_order[i] + nr_base);
+
+ return 0;
+}
+
+struct midx_pack_order_data {
+ uint32_t nr;
+ uint32_t pack;
+ off_t offset;
+};
+
+static int midx_pack_order_cmp(const void *va, const void *vb)
+{
+ const struct midx_pack_order_data *a = va, *b = vb;
+ if (a->pack < b->pack)
+ return -1;
+ else if (a->pack > b->pack)
+ return 1;
+ else if (a->offset < b->offset)
+ return -1;
+ else if (a->offset > b->offset)
+ return 1;
+ else
+ return 0;
+}
+
+static uint32_t *midx_pack_order(struct write_midx_context *ctx)
+{
+ struct midx_pack_order_data *data;
+ uint32_t *pack_order, base_objects = 0;
+ uint32_t i;
+
+ trace2_region_enter("midx", "midx_pack_order", the_repository);
+
+ if (ctx->incremental && ctx->base_midx)
+ base_objects = ctx->base_midx->num_objects +
+ ctx->base_midx->num_objects_in_base;
+
+ ALLOC_ARRAY(pack_order, ctx->entries_nr);
+ ALLOC_ARRAY(data, ctx->entries_nr);
+
+ for (i = 0; i < ctx->entries_nr; i++) {
+ struct pack_midx_entry *e = &ctx->entries[i];
+ data[i].nr = i;
+ data[i].pack = ctx->pack_perm[e->pack_int_id];
+ if (!e->preferred)
+ data[i].pack |= (1U << 31);
+ data[i].offset = e->offset;
+ }
+
+ QSORT(data, ctx->entries_nr, midx_pack_order_cmp);
+
+ for (i = 0; i < ctx->entries_nr; i++) {
+ struct pack_midx_entry *e = &ctx->entries[data[i].nr];
+ struct pack_info *pack = &ctx->info[ctx->pack_perm[e->pack_int_id]];
+ if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
+ pack->bitmap_pos = i + base_objects;
+ pack->bitmap_nr++;
+ pack_order[i] = data[i].nr;
+ }
+ for (i = 0; i < ctx->nr; i++) {
+ struct pack_info *pack = &ctx->info[ctx->pack_perm[i]];
+ if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
+ pack->bitmap_pos = 0;
+ }
+ free(data);
+
+ trace2_region_leave("midx", "midx_pack_order", the_repository);
+
+ return pack_order;
+}
+
+static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
+ struct write_midx_context *ctx)
+{
+ struct strbuf buf = STRBUF_INIT;
+ char *tmp_file;
+
+ trace2_region_enter("midx", "write_midx_reverse_index", the_repository);
+
+ strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash));
+
+ tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
+ midx_hash, WRITE_REV);
+
+ if (finalize_object_file(tmp_file, buf.buf))
+ die(_("cannot store reverse index file"));
+
+ strbuf_release(&buf);
+ free(tmp_file);
+
+ trace2_region_leave("midx", "write_midx_reverse_index", the_repository);
+}
+
+static void prepare_midx_packing_data(struct packing_data *pdata,
+ struct write_midx_context *ctx)
+{
+ uint32_t i;
+
+ trace2_region_enter("midx", "prepare_midx_packing_data", the_repository);
+
+ memset(pdata, 0, sizeof(struct packing_data));
+ prepare_packing_data(the_repository, pdata);
+
+ for (i = 0; i < ctx->entries_nr; i++) {
+ uint32_t pos = ctx->pack_order[i];
+ struct pack_midx_entry *from = &ctx->entries[pos];
+ struct object_entry *to = packlist_alloc(pdata, &from->oid);
+
+ oe_set_in_pack(pdata, to,
+ ctx->info[ctx->pack_perm[from->pack_int_id]].p);
+ }
+
+ trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
+}
+
+static int add_ref_to_pending(const char *refname, const char *referent UNUSED,
+ const struct object_id *oid,
+ int flag, void *cb_data)
+{
+ struct rev_info *revs = (struct rev_info*)cb_data;
+ struct object_id peeled;
+ struct object *object;
+
+ if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
+ warning("symbolic ref is dangling: %s", refname);
+ return 0;
+ }
+
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
+ oid = &peeled;
+
+ object = parse_object_or_die(oid, refname);
+ if (object->type != OBJ_COMMIT)
+ return 0;
+
+ add_pending_object(revs, object, "");
+ if (bitmap_is_preferred_refname(revs->repo, refname))
+ object->flags |= NEEDS_BITMAP;
+ return 0;
+}
+
+struct bitmap_commit_cb {
+ struct commit **commits;
+ size_t commits_nr, commits_alloc;
+
+ struct write_midx_context *ctx;
+};
+
+static const struct object_id *bitmap_oid_access(size_t index,
+ const void *_entries)
+{
+ const struct pack_midx_entry *entries = _entries;
+ return &entries[index].oid;
+}
+
+static void bitmap_show_commit(struct commit *commit, void *_data)
+{
+ struct bitmap_commit_cb *data = _data;
+ int pos = oid_pos(&commit->object.oid, data->ctx->entries,
+ data->ctx->entries_nr,
+ bitmap_oid_access);
+ if (pos < 0)
+ return;
+
+ ALLOC_GROW(data->commits, data->commits_nr + 1, data->commits_alloc);
+ data->commits[data->commits_nr++] = commit;
+}
+
+static int read_refs_snapshot(const char *refs_snapshot,
+ struct rev_info *revs)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct object_id oid;
+ FILE *f = xfopen(refs_snapshot, "r");
+
+ while (strbuf_getline(&buf, f) != EOF) {
+ struct object *object;
+ int preferred = 0;
+ char *hex = buf.buf;
+ const char *end = NULL;
+
+ if (buf.len && *buf.buf == '+') {
+ preferred = 1;
+ hex = &buf.buf[1];
+ }
+
+ if (parse_oid_hex(hex, &oid, &end) < 0)
+ die(_("could not parse line: %s"), buf.buf);
+ if (*end)
+ die(_("malformed line: %s"), buf.buf);
+
+ object = parse_object_or_die(&oid, NULL);
+ if (preferred)
+ object->flags |= NEEDS_BITMAP;
+
+ add_pending_object(revs, object, "");
+ }
+
+ fclose(f);
+ strbuf_release(&buf);
+ return 0;
+}
+static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p,
+ const char *refs_snapshot,
+ struct write_midx_context *ctx)
+{
+ struct rev_info revs;
+ struct bitmap_commit_cb cb = {0};
+
+ trace2_region_enter("midx", "find_commits_for_midx_bitmap",
+ the_repository);
+
+ cb.ctx = ctx;
+
+ repo_init_revisions(the_repository, &revs, NULL);
+ if (refs_snapshot) {
+ read_refs_snapshot(refs_snapshot, &revs);
+ } else {
+ setup_revisions(0, NULL, &revs, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_ref_to_pending, &revs);
+ }
+
+ /*
+ * Skipping promisor objects here is intentional, since it only excludes
+ * them from the list of reachable commits that we want to select from
+ * when computing the selection of MIDX'd commits to receive bitmaps.
+ *
+ * Reachability bitmaps do require that their objects be closed under
+ * reachability, but fetching any objects missing from promisors at this
+ * point is too late. But, if one of those objects can be reached from
+ * an another object that is included in the bitmap, then we will
+ * complain later that we don't have reachability closure (and fail
+ * appropriately).
+ */
+ fetch_if_missing = 0;
+ revs.exclude_promisor_objects = 1;
+
+ if (prepare_revision_walk(&revs))
+ die(_("revision walk setup failed"));
+
+ traverse_commit_list(&revs, bitmap_show_commit, NULL, &cb);
+ if (indexed_commits_nr_p)
+ *indexed_commits_nr_p = cb.commits_nr;
+
+ release_revisions(&revs);
+
+ trace2_region_leave("midx", "find_commits_for_midx_bitmap",
+ the_repository);
+
+ return cb.commits;
+}
+
+static int write_midx_bitmap(const char *midx_name,
+ const unsigned char *midx_hash,
+ struct packing_data *pdata,
+ struct commit **commits,
+ uint32_t commits_nr,
+ uint32_t *pack_order,
+ unsigned flags)
+{
+ int ret, i;
+ uint16_t options = 0;
+ struct bitmap_writer writer;
+ struct pack_idx_entry **index;
+ char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
+ hash_to_hex(midx_hash));
+
+ trace2_region_enter("midx", "write_midx_bitmap", the_repository);
+
+ if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
+ options |= BITMAP_OPT_HASH_CACHE;
+
+ if (flags & MIDX_WRITE_BITMAP_LOOKUP_TABLE)
+ options |= BITMAP_OPT_LOOKUP_TABLE;
+
+ /*
+ * Build the MIDX-order index based on pdata.objects (which is already
+ * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
+ * this order).
+ */
+ ALLOC_ARRAY(index, pdata->nr_objects);
+ for (i = 0; i < pdata->nr_objects; i++)
+ index[i] = &pdata->objects[i].idx;
+
+ bitmap_writer_init(&writer, the_repository, pdata);
+ bitmap_writer_show_progress(&writer, flags & MIDX_PROGRESS);
+ bitmap_writer_build_type_index(&writer, index);
+
+ /*
+ * bitmap_writer_finish expects objects in lex order, but pack_order
+ * gives us exactly that. use it directly instead of re-sorting the
+ * array.
+ *
+ * This changes the order of objects in 'index' between
+ * bitmap_writer_build_type_index and bitmap_writer_finish.
+ *
+ * The same re-ordering takes place in the single-pack bitmap code via
+ * write_idx_file(), which is called by finish_tmp_packfile(), which
+ * happens between bitmap_writer_build_type_index() and
+ * bitmap_writer_finish().
+ */
+ for (i = 0; i < pdata->nr_objects; i++)
+ index[pack_order[i]] = &pdata->objects[i].idx;
+
+ bitmap_writer_select_commits(&writer, commits, commits_nr);
+ ret = bitmap_writer_build(&writer);
+ if (ret < 0)
+ goto cleanup;
+
+ bitmap_writer_set_checksum(&writer, midx_hash);
+ bitmap_writer_finish(&writer, index, bitmap_name, options);
+
+cleanup:
+ free(index);
+ free(bitmap_name);
+ bitmap_writer_free(&writer);
+
+ trace2_region_leave("midx", "write_midx_bitmap", the_repository);
+
+ return ret;
+}
+
+static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
+ const char *object_dir)
+{
+ struct multi_pack_index *result = NULL;
+ struct multi_pack_index *cur;
+ char *obj_dir_real = real_pathdup(object_dir, 1);
+ struct strbuf cur_path_real = STRBUF_INIT;
+
+ /* Ensure the given object_dir is local, or a known alternate. */
+ find_odb(r, obj_dir_real);
+
+ for (cur = get_multi_pack_index(r); cur; cur = cur->next) {
+ strbuf_realpath(&cur_path_real, cur->object_dir, 1);
+ if (!strcmp(obj_dir_real, cur_path_real.buf)) {
+ result = cur;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ free(obj_dir_real);
+ strbuf_release(&cur_path_real);
+ return result;
+}
+
+static int fill_packs_from_midx(struct write_midx_context *ctx,
+ const char *preferred_pack_name, uint32_t flags)
+{
+ struct multi_pack_index *m;
+
+ for (m = ctx->m; m; m = m->base_midx) {
+ uint32_t i;
+
+ for (i = 0; i < m->num_packs; i++) {
+ ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
+
+ /*
+ * If generating a reverse index, need to have
+ * packed_git's loaded to compare their
+ * mtimes and object count.
+ *
+ * If a preferred pack is specified, need to
+ * have packed_git's loaded to ensure the chosen
+ * preferred pack has a non-zero object count.
+ */
+ if (flags & MIDX_WRITE_REV_INDEX ||
+ preferred_pack_name) {
+ if (prepare_midx_pack(the_repository, m,
+ m->num_packs_in_base + i)) {
+ error(_("could not load pack"));
+ return 1;
+ }
+
+ if (open_pack_index(m->packs[i]))
+ die(_("could not open index for %s"),
+ m->packs[i]->pack_name);
+ }
+
+ fill_pack_info(&ctx->info[ctx->nr++], m->packs[i],
+ m->pack_names[i],
+ m->num_packs_in_base + i);
+ }
+ }
+ return 0;
+}
+
+static struct {
+ const char *non_split;
+ const char *split;
+} midx_exts[] = {
+ {NULL, MIDX_EXT_MIDX},
+ {MIDX_EXT_BITMAP, MIDX_EXT_BITMAP},
+ {MIDX_EXT_REV, MIDX_EXT_REV},
+};
+
+static int link_midx_to_chain(struct multi_pack_index *m)
+{
+ struct strbuf from = STRBUF_INIT;
+ struct strbuf to = STRBUF_INIT;
+ int ret = 0;
+ size_t i;
+
+ if (!m || m->has_chain) {
+ /*
+ * Either no MIDX previously existed, or it was already
+ * part of a MIDX chain. In both cases, we have nothing
+ * to link, so return early.
+ */
+ goto done;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(midx_exts); i++) {
+ const unsigned char *hash = get_midx_checksum(m);
+
+ get_midx_filename_ext(&from, m->object_dir, hash,
+ midx_exts[i].non_split);
+ get_split_midx_filename_ext(&to, m->object_dir, hash,
+ midx_exts[i].split);
+
+ if (link(from.buf, to.buf) < 0 && errno != ENOENT) {
+ ret = error_errno(_("unable to link '%s' to '%s'"),
+ from.buf, to.buf);
+ goto done;
+ }
+
+ strbuf_reset(&from);
+ strbuf_reset(&to);
+ }
+
+done:
+ strbuf_release(&from);
+ strbuf_release(&to);
+ return ret;
+}
+
+static void clear_midx_files(const char *object_dir,
+ const char **hashes,
+ uint32_t hashes_nr,
+ unsigned incremental)
+{
+ /*
+ * if incremental:
+ * - remove all non-incremental MIDX files
+ * - remove any incremental MIDX files not in the current one
+ *
+ * if non-incremental:
+ * - remove all incremental MIDX files
+ * - remove any non-incremental MIDX files not matching the current
+ * hash
+ */
+ struct strbuf buf = STRBUF_INIT;
+ const char *exts[] = { MIDX_EXT_BITMAP, MIDX_EXT_REV, MIDX_EXT_MIDX };
+ uint32_t i, j;
+
+ for (i = 0; i < ARRAY_SIZE(exts); i++) {
+ clear_incremental_midx_files_ext(object_dir, exts[i],
+ hashes, hashes_nr);
+ for (j = 0; j < hashes_nr; j++)
+ clear_midx_files_ext(object_dir, exts[i], hashes[j]);
+ }
+
+ if (incremental)
+ get_midx_filename(&buf, object_dir);
+ else
+ get_midx_chain_filename(&buf, object_dir);
+
+ if (unlink(buf.buf) && errno != ENOENT)
+ die_errno(_("failed to clear multi-pack-index at %s"), buf.buf);
+
+ strbuf_release(&buf);
+}
+
+static int write_midx_internal(const char *object_dir,
+ struct string_list *packs_to_include,
+ struct string_list *packs_to_drop,
+ const char *preferred_pack_name,
+ const char *refs_snapshot,
+ unsigned flags)
+{
+ struct strbuf midx_name = STRBUF_INIT;
+ unsigned char midx_hash[GIT_MAX_RAWSZ];
+ uint32_t i, start_pack;
+ struct hashfile *f = NULL;
+ struct lock_file lk;
+ struct tempfile *incr;
+ struct write_midx_context ctx = { 0 };
+ int bitmapped_packs_concat_len = 0;
+ int pack_name_concat_len = 0;
+ int dropped_packs = 0;
+ int result = 0;
+ const char **keep_hashes = NULL;
+ struct chunkfile *cf;
+
+ trace2_region_enter("midx", "write_midx_internal", the_repository);
+
+ ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
+ if (ctx.incremental && (flags & MIDX_WRITE_BITMAP))
+ die(_("cannot write incremental MIDX with bitmap"));
+
+ if (ctx.incremental)
+ strbuf_addf(&midx_name,
+ "%s/pack/multi-pack-index.d/tmp_midx_XXXXXX",
+ object_dir);
+ else
+ get_midx_filename(&midx_name, object_dir);
+ if (safe_create_leading_directories(midx_name.buf))
+ die_errno(_("unable to create leading directories of %s"),
+ midx_name.buf);
+
+ if (!packs_to_include || ctx.incremental) {
+ struct multi_pack_index *m = lookup_multi_pack_index(the_repository,
+ object_dir);
+ if (m && !midx_checksum_valid(m)) {
+ warning(_("ignoring existing multi-pack-index; checksum mismatch"));
+ m = NULL;
+ }
+
+ if (m) {
+ /*
+ * Only reference an existing MIDX when not filtering
+ * which packs to include, since all packs and objects
+ * are copied blindly from an existing MIDX if one is
+ * present.
+ */
+ if (ctx.incremental)
+ ctx.base_midx = m;
+ else if (!packs_to_include)
+ ctx.m = m;
+ }
+ }
+
+ ctx.nr = 0;
+ ctx.alloc = ctx.m ? ctx.m->num_packs + ctx.m->num_packs_in_base : 16;
+ ctx.info = NULL;
+ ALLOC_ARRAY(ctx.info, ctx.alloc);
+
+ if (ctx.incremental) {
+ struct multi_pack_index *m = ctx.base_midx;
+ while (m) {
+ ctx.num_multi_pack_indexes_before++;
+ m = m->base_midx;
+ }
+ } else if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
+ flags) < 0) {
+ goto cleanup;
+ }
+
+ start_pack = ctx.nr;
+
+ ctx.pack_paths_checked = 0;
+ if (flags & MIDX_PROGRESS)
+ ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
+ else
+ ctx.progress = NULL;
+
+ ctx.to_include = packs_to_include;
+
+ for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
+ stop_progress(&ctx.progress);
+
+ if ((ctx.m && ctx.nr == ctx.m->num_packs + ctx.m->num_packs_in_base) &&
+ !ctx.incremental &&
+ !(packs_to_include || packs_to_drop)) {
+ struct bitmap_index *bitmap_git;
+ int bitmap_exists;
+ int want_bitmap = flags & MIDX_WRITE_BITMAP;
+
+ bitmap_git = prepare_midx_bitmap_git(ctx.m);
+ bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git);
+ free_bitmap_index(bitmap_git);
+
+ if (bitmap_exists || !want_bitmap) {
+ /*
+ * The correct MIDX already exists, and so does a
+ * corresponding bitmap (or one wasn't requested).
+ */
+ if (!want_bitmap)
+ clear_midx_files_ext(object_dir, "bitmap", NULL);
+ goto cleanup;
+ }
+ }
+
+ if (ctx.incremental && !ctx.nr)
+ goto cleanup; /* nothing to do */
+
+ if (preferred_pack_name) {
+ ctx.preferred_pack_idx = -1;
+
+ 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;
+ break;
+ }
+ }
+
+ if (ctx.preferred_pack_idx == -1)
+ warning(_("unknown preferred pack: '%s'"),
+ preferred_pack_name);
+ } else if (ctx.nr &&
+ (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
+ struct packed_git *oldest = ctx.info[ctx.preferred_pack_idx].p;
+ ctx.preferred_pack_idx = 0;
+
+ if (packs_to_drop && packs_to_drop->nr)
+ BUG("cannot write a MIDX bitmap during expiration");
+
+ /*
+ * set a preferred pack when writing a bitmap to ensure that
+ * the pack from which the first object is selected in pseudo
+ * pack-order has all of its objects selected from that pack
+ * (and not another pack containing a duplicate)
+ */
+ for (i = 1; i < ctx.nr; i++) {
+ struct packed_git *p = ctx.info[i].p;
+
+ if (!oldest->num_objects || p->mtime < oldest->mtime) {
+ oldest = p;
+ ctx.preferred_pack_idx = i;
+ }
+ }
+
+ if (!oldest->num_objects) {
+ /*
+ * If all packs are empty; unset the preferred index.
+ * This is acceptable since there will be no duplicate
+ * objects to resolve, so the preferred value doesn't
+ * matter.
+ */
+ ctx.preferred_pack_idx = -1;
+ }
+ } else {
+ /*
+ * otherwise don't mark any pack as preferred to avoid
+ * interfering with expiration logic below
+ */
+ ctx.preferred_pack_idx = -1;
+ }
+
+ if (ctx.preferred_pack_idx > -1) {
+ struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p;
+ if (!preferred->num_objects) {
+ error(_("cannot select preferred pack %s with no objects"),
+ preferred->pack_name);
+ result = 1;
+ goto cleanup;
+ }
+ }
+
+ compute_sorted_entries(&ctx, start_pack);
+
+ ctx.large_offsets_needed = 0;
+ for (i = 0; i < ctx.entries_nr; i++) {
+ if (ctx.entries[i].offset > 0x7fffffff)
+ ctx.num_large_offsets++;
+ if (ctx.entries[i].offset > 0xffffffff)
+ ctx.large_offsets_needed = 1;
+ }
+
+ QSORT(ctx.info, ctx.nr, pack_info_compare);
+
+ if (packs_to_drop && packs_to_drop->nr) {
+ int drop_index = 0;
+ int missing_drops = 0;
+
+ for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
+ int cmp = strcmp(ctx.info[i].pack_name,
+ packs_to_drop->items[drop_index].string);
+
+ if (!cmp) {
+ drop_index++;
+ ctx.info[i].expired = 1;
+ } else if (cmp > 0) {
+ error(_("did not see pack-file %s to drop"),
+ packs_to_drop->items[drop_index].string);
+ drop_index++;
+ missing_drops++;
+ i--;
+ } else {
+ ctx.info[i].expired = 0;
+ }
+ }
+
+ if (missing_drops) {
+ result = 1;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * pack_perm stores a permutation between pack-int-ids from the
+ * previous multi-pack-index to the new one we are writing:
+ *
+ * pack_perm[old_id] = new_id
+ */
+ ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
+ for (i = 0; i < ctx.nr; i++) {
+ if (ctx.info[i].expired) {
+ dropped_packs++;
+ ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
+ } else {
+ ctx.pack_perm[ctx.info[i].orig_pack_int_id] = i - dropped_packs;
+ }
+ }
+
+ for (i = 0; i < ctx.nr; i++) {
+ if (ctx.info[i].expired)
+ continue;
+ pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1;
+ bitmapped_packs_concat_len += 2 * sizeof(uint32_t);
+ }
+
+ /* Check that the preferred pack wasn't expired (if given). */
+ if (preferred_pack_name) {
+ struct pack_info *preferred = bsearch(preferred_pack_name,
+ ctx.info, ctx.nr,
+ sizeof(*ctx.info),
+ idx_or_pack_name_cmp);
+ if (preferred) {
+ uint32_t perm = ctx.pack_perm[preferred->orig_pack_int_id];
+ if (perm == PACK_EXPIRED)
+ warning(_("preferred pack '%s' is expired"),
+ preferred_pack_name);
+ }
+ }
+
+ if (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT)
+ pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
+ (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
+
+ if (ctx.nr - dropped_packs == 0) {
+ error(_("no pack files to index."));
+ result = 1;
+ goto cleanup;
+ }
+
+ if (!ctx.entries_nr) {
+ if (flags & MIDX_WRITE_BITMAP)
+ warning(_("refusing to write multi-pack .bitmap without any objects"));
+ flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
+ }
+
+ if (ctx.incremental) {
+ struct strbuf lock_name = STRBUF_INIT;
+
+ get_midx_chain_filename(&lock_name, object_dir);
+ hold_lock_file_for_update(&lk, lock_name.buf, LOCK_DIE_ON_ERROR);
+ strbuf_release(&lock_name);
+
+ incr = mks_tempfile_m(midx_name.buf, 0444);
+ if (!incr) {
+ error(_("unable to create temporary MIDX layer"));
+ return -1;
+ }
+
+ if (adjust_shared_perm(get_tempfile_path(incr))) {
+ error(_("unable to adjust shared permissions for '%s'"),
+ get_tempfile_path(incr));
+ return -1;
+ }
+
+ f = hashfd(get_tempfile_fd(incr), get_tempfile_path(incr));
+ } else {
+ hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
+ f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
+ }
+
+ cf = init_chunkfile(f);
+
+ add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
+ write_midx_pack_names);
+ add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
+ write_midx_oid_fanout);
+ add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
+ st_mult(ctx.entries_nr, the_hash_algo->rawsz),
+ write_midx_oid_lookup);
+ add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
+ st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH),
+ write_midx_object_offsets);
+
+ if (ctx.large_offsets_needed)
+ add_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS,
+ 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,
+ st_mult(ctx.entries_nr, sizeof(uint32_t)),
+ write_midx_revindex);
+ add_chunk(cf, MIDX_CHUNKID_BITMAPPEDPACKS,
+ bitmapped_packs_concat_len,
+ write_midx_bitmapped_packs);
+ }
+
+ write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs);
+ write_chunkfile(cf, &ctx);
+
+ finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA,
+ CSUM_FSYNC | CSUM_HASH_IN_STREAM);
+ free_chunkfile(cf);
+
+ if (flags & MIDX_WRITE_REV_INDEX &&
+ git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
+ write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
+
+ if (flags & MIDX_WRITE_BITMAP) {
+ struct packing_data pdata;
+ struct commit **commits;
+ uint32_t commits_nr;
+
+ if (!ctx.entries_nr)
+ BUG("cannot write a bitmap without any objects");
+
+ prepare_midx_packing_data(&pdata, &ctx);
+
+ commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, &ctx);
+
+ /*
+ * The previous steps translated the information from
+ * 'entries' into information suitable for constructing
+ * bitmaps. We no longer need that array, so clear it to
+ * reduce memory pressure.
+ */
+ FREE_AND_NULL(ctx.entries);
+ ctx.entries_nr = 0;
+
+ if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata,
+ commits, commits_nr, ctx.pack_order,
+ flags) < 0) {
+ error(_("could not write multi-pack bitmap"));
+ result = 1;
+ clear_packing_data(&pdata);
+ free(commits);
+ goto cleanup;
+ }
+
+ clear_packing_data(&pdata);
+ free(commits);
+ }
+ /*
+ * NOTE: Do not use ctx.entries beyond this point, since it might
+ * have been freed in the previous if block.
+ */
+
+ CALLOC_ARRAY(keep_hashes, ctx.num_multi_pack_indexes_before + 1);
+
+ if (ctx.incremental) {
+ FILE *chainf = fdopen_lock_file(&lk, "w");
+ struct strbuf final_midx_name = STRBUF_INIT;
+ struct multi_pack_index *m = ctx.base_midx;
+
+ if (!chainf) {
+ error_errno(_("unable to open multi-pack-index chain file"));
+ return -1;
+ }
+
+ if (link_midx_to_chain(ctx.base_midx) < 0)
+ return -1;
+
+ get_split_midx_filename_ext(&final_midx_name, object_dir,
+ midx_hash, MIDX_EXT_MIDX);
+
+ if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
+ error_errno(_("unable to rename new multi-pack-index layer"));
+ return -1;
+ }
+
+ strbuf_release(&final_midx_name);
+
+ keep_hashes[ctx.num_multi_pack_indexes_before] =
+ xstrdup(hash_to_hex(midx_hash));
+
+ for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
+ uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
+
+ keep_hashes[j] = xstrdup(hash_to_hex(get_midx_checksum(m)));
+ m = m->base_midx;
+ }
+
+ for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
+ fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]);
+ } else {
+ keep_hashes[ctx.num_multi_pack_indexes_before] =
+ xstrdup(hash_to_hex(midx_hash));
+ }
+
+ if (ctx.m || ctx.base_midx)
+ close_object_store(the_repository->objects);
+
+ if (commit_lock_file(&lk) < 0)
+ die_errno(_("could not write multi-pack-index"));
+
+ clear_midx_files(object_dir, keep_hashes,
+ ctx.num_multi_pack_indexes_before + 1,
+ ctx.incremental);
+
+cleanup:
+ for (i = 0; i < ctx.nr; i++) {
+ if (ctx.info[i].p) {
+ close_pack(ctx.info[i].p);
+ free(ctx.info[i].p);
+ }
+ free(ctx.info[i].pack_name);
+ }
+
+ free(ctx.info);
+ free(ctx.entries);
+ free(ctx.pack_perm);
+ free(ctx.pack_order);
+ if (keep_hashes) {
+ for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
+ free((char *)keep_hashes[i]);
+ free(keep_hashes);
+ }
+ strbuf_release(&midx_name);
+
+ trace2_region_leave("midx", "write_midx_internal", the_repository);
+
+ return result;
+}
+
+int write_midx_file(const char *object_dir,
+ const char *preferred_pack_name,
+ const char *refs_snapshot,
+ unsigned flags)
+{
+ return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name,
+ refs_snapshot, flags);
+}
+
+int write_midx_file_only(const char *object_dir,
+ struct string_list *packs_to_include,
+ const char *preferred_pack_name,
+ const char *refs_snapshot,
+ unsigned flags)
+{
+ return write_midx_internal(object_dir, packs_to_include, NULL,
+ preferred_pack_name, refs_snapshot, flags);
+}
+
+int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags)
+{
+ uint32_t i, *count, result = 0;
+ struct string_list packs_to_drop = STRING_LIST_INIT_DUP;
+ struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
+ struct progress *progress = NULL;
+
+ if (!m)
+ return 0;
+
+ if (m->base_midx)
+ die(_("cannot expire packs from an incremental multi-pack-index"));
+
+ CALLOC_ARRAY(count, m->num_packs);
+
+ if (flags & MIDX_PROGRESS)
+ progress = start_delayed_progress(_("Counting referenced objects"),
+ m->num_objects);
+ for (i = 0; i < m->num_objects; i++) {
+ int pack_int_id = nth_midxed_pack_int_id(m, i);
+ count[pack_int_id]++;
+ display_progress(progress, i + 1);
+ }
+ stop_progress(&progress);
+
+ if (flags & MIDX_PROGRESS)
+ progress = start_delayed_progress(_("Finding and deleting unreferenced packfiles"),
+ m->num_packs);
+ for (i = 0; i < m->num_packs; i++) {
+ char *pack_name;
+ display_progress(progress, i + 1);
+
+ if (count[i])
+ continue;
+
+ if (prepare_midx_pack(r, m, i))
+ continue;
+
+ if (m->packs[i]->pack_keep || m->packs[i]->is_cruft)
+ continue;
+
+ pack_name = xstrdup(m->packs[i]->pack_name);
+ close_pack(m->packs[i]);
+
+ string_list_insert(&packs_to_drop, m->pack_names[i]);
+ unlink_pack_path(pack_name, 0);
+ free(pack_name);
+ }
+ stop_progress(&progress);
+
+ free(count);
+
+ if (packs_to_drop.nr)
+ result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags);
+
+ string_list_clear(&packs_to_drop, 0);
+
+ return result;
+}
+
+struct repack_info {
+ timestamp_t mtime;
+ uint32_t referenced_objects;
+ uint32_t pack_int_id;
+};
+
+static int compare_by_mtime(const void *a_, const void *b_)
+{
+ const struct repack_info *a, *b;
+
+ a = (const struct repack_info *)a_;
+ b = (const struct repack_info *)b_;
+
+ if (a->mtime < b->mtime)
+ return -1;
+ if (a->mtime > b->mtime)
+ return 1;
+ return 0;
+}
+
+static int want_included_pack(struct repository *r,
+ struct multi_pack_index *m,
+ int pack_kept_objects,
+ uint32_t pack_int_id)
+{
+ struct packed_git *p;
+ if (prepare_midx_pack(r, m, pack_int_id))
+ return 0;
+ p = m->packs[pack_int_id];
+ if (!pack_kept_objects && p->pack_keep)
+ return 0;
+ if (p->is_cruft)
+ return 0;
+ if (open_pack_index(p) || !p->num_objects)
+ return 0;
+ return 1;
+}
+
+static void fill_included_packs_all(struct repository *r,
+ struct multi_pack_index *m,
+ unsigned char *include_pack)
+{
+ uint32_t i;
+ int pack_kept_objects = 0;
+
+ repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
+
+ for (i = 0; i < m->num_packs; i++) {
+ if (!want_included_pack(r, m, pack_kept_objects, i))
+ continue;
+
+ include_pack[i] = 1;
+ }
+}
+
+static void fill_included_packs_batch(struct repository *r,
+ struct multi_pack_index *m,
+ unsigned char *include_pack,
+ size_t batch_size)
+{
+ uint32_t i;
+ size_t total_size;
+ struct repack_info *pack_info;
+ int pack_kept_objects = 0;
+
+ CALLOC_ARRAY(pack_info, m->num_packs);
+
+ repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
+
+ for (i = 0; i < m->num_packs; i++) {
+ pack_info[i].pack_int_id = i;
+
+ if (prepare_midx_pack(r, m, i))
+ continue;
+
+ pack_info[i].mtime = m->packs[i]->mtime;
+ }
+
+ for (i = 0; i < m->num_objects; i++) {
+ uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
+ pack_info[pack_int_id].referenced_objects++;
+ }
+
+ QSORT(pack_info, m->num_packs, compare_by_mtime);
+
+ total_size = 0;
+ for (i = 0; total_size < batch_size && i < m->num_packs; i++) {
+ int pack_int_id = pack_info[i].pack_int_id;
+ struct packed_git *p = m->packs[pack_int_id];
+ size_t expected_size;
+
+ if (!want_included_pack(r, m, pack_kept_objects, pack_int_id))
+ continue;
+
+ expected_size = st_mult(p->pack_size,
+ pack_info[i].referenced_objects);
+ expected_size /= p->num_objects;
+
+ if (expected_size >= batch_size)
+ continue;
+
+ total_size += expected_size;
+ include_pack[pack_int_id] = 1;
+ }
+
+ free(pack_info);
+}
+
+int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, unsigned flags)
+{
+ int result = 0;
+ uint32_t i, packs_to_repack = 0;
+ unsigned char *include_pack;
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ FILE *cmd_in;
+ struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
+
+ /*
+ * When updating the default for these configuration
+ * variables in builtin/repack.c, these must be adjusted
+ * to match.
+ */
+ int delta_base_offset = 1;
+ int use_delta_islands = 0;
+
+ if (!m)
+ return 0;
+ if (m->base_midx)
+ die(_("cannot repack an incremental multi-pack-index"));
+
+ CALLOC_ARRAY(include_pack, m->num_packs);
+
+ if (batch_size)
+ fill_included_packs_batch(r, m, include_pack, batch_size);
+ else
+ fill_included_packs_all(r, m, include_pack);
+
+ for (i = 0; i < m->num_packs; i++) {
+ if (include_pack[i])
+ packs_to_repack++;
+ }
+ if (packs_to_repack <= 1)
+ goto cleanup;
+
+ repo_config_get_bool(r, "repack.usedeltabaseoffset", &delta_base_offset);
+ repo_config_get_bool(r, "repack.usedeltaislands", &use_delta_islands);
+
+ strvec_push(&cmd.args, "pack-objects");
+
+ strvec_pushf(&cmd.args, "%s/pack/pack", object_dir);
+
+ if (delta_base_offset)
+ strvec_push(&cmd.args, "--delta-base-offset");
+ if (use_delta_islands)
+ strvec_push(&cmd.args, "--delta-islands");
+
+ if (flags & MIDX_PROGRESS)
+ strvec_push(&cmd.args, "--progress");
+ else
+ strvec_push(&cmd.args, "-q");
+
+ cmd.git_cmd = 1;
+ cmd.in = cmd.out = -1;
+
+ if (start_command(&cmd)) {
+ error(_("could not start pack-objects"));
+ result = 1;
+ goto cleanup;
+ }
+
+ cmd_in = xfdopen(cmd.in, "w");
+
+ for (i = 0; i < m->num_objects; i++) {
+ struct object_id oid;
+ uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
+
+ if (!include_pack[pack_int_id])
+ continue;
+
+ nth_midxed_object_oid(&oid, m, i);
+ fprintf(cmd_in, "%s\n", oid_to_hex(&oid));
+ }
+ fclose(cmd_in);
+
+ if (finish_command(&cmd)) {
+ error(_("could not finish pack-objects"));
+ result = 1;
+ goto cleanup;
+ }
+
+ result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags);
+
+cleanup:
+ free(include_pack);
+ return result;
+}
diff --git a/midx.c b/midx.c
index 931f557350..e82d4f2e65 100644
--- a/midx.c
+++ b/midx.c
@@ -1,49 +1,27 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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-file.h"
-#include "object-store-ll.h"
#include "hash-lookup.h"
#include "midx.h"
#include "progress.h"
#include "trace2.h"
-#include "run-command.h"
-#include "repository.h"
#include "chunk-format.h"
-#include "pack.h"
#include "pack-bitmap.h"
-#include "refs.h"
-#include "revision.h"
-#include "list-objects.h"
-
-#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
-#define MIDX_VERSION 1
-#define MIDX_BYTE_FILE_VERSION 4
-#define MIDX_BYTE_HASH_VERSION 5
-#define MIDX_BYTE_NUM_CHUNKS 6
-#define MIDX_BYTE_NUM_PACKS 8
-#define MIDX_HEADER_SIZE 12
-#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
-
-#define MIDX_CHUNK_ALIGNMENT 4
-#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
-#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
-#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
-#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
-#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
-#define MIDX_CHUNKID_REVINDEX 0x52494458 /* "RIDX" */
-#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
-#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
-#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
-#define MIDX_LARGE_OFFSET_NEEDED 0x80000000
+#include "pack-revindex.h"
-#define PACK_EXPIRED UINT_MAX
+int midx_checksum_valid(struct multi_pack_index *m);
+void clear_midx_files_ext(const char *object_dir, const char *ext,
+ const char *keep_hash);
+void clear_incremental_midx_files_ext(const char *object_dir, const char *ext,
+ char **keep_hashes,
+ uint32_t hashes_nr);
+int cmp_idx_or_pack_name(const char *idx_or_pack_name,
+ const char *idx_name);
const unsigned char *get_midx_checksum(struct multi_pack_index *m)
{
@@ -52,18 +30,21 @@ const unsigned char *get_midx_checksum(struct multi_pack_index *m)
void get_midx_filename(struct strbuf *out, const char *object_dir)
{
- strbuf_addf(out, "%s/pack/multi-pack-index", object_dir);
+ get_midx_filename_ext(out, object_dir, NULL, NULL);
}
-void get_midx_rev_filename(struct strbuf *out, struct multi_pack_index *m)
+void get_midx_filename_ext(struct strbuf *out, const char *object_dir,
+ const unsigned char *hash, const char *ext)
{
- get_midx_filename(out, m->object_dir);
- strbuf_addf(out, "-%s.rev", hash_to_hex(get_midx_checksum(m)));
+ strbuf_addf(out, "%s/pack/multi-pack-index", object_dir);
+ if (ext)
+ strbuf_addf(out, "-%s.%s", hash_to_hex(hash), ext);
}
static int midx_read_oid_fanout(const unsigned char *chunk_start,
size_t chunk_size, void *data)
{
+ int i;
struct multi_pack_index *m = data;
m->chunk_oid_fanout = (uint32_t *)chunk_start;
@@ -71,10 +52,51 @@ static int midx_read_oid_fanout(const unsigned char *chunk_start,
error(_("multi-pack-index OID fanout is of the wrong size"));
return 1;
}
+ for (i = 0; i < 255; i++) {
+ uint32_t oid_fanout1 = ntohl(m->chunk_oid_fanout[i]);
+ uint32_t oid_fanout2 = ntohl(m->chunk_oid_fanout[i+1]);
+
+ if (oid_fanout1 > oid_fanout2) {
+ error(_("oid fanout out of order: fanout[%d] = %"PRIx32" > %"PRIx32" = fanout[%d]"),
+ i, oid_fanout1, oid_fanout2, i + 1);
+ return 1;
+ }
+ }
+ m->num_objects = ntohl(m->chunk_oid_fanout[255]);
+ return 0;
+}
+
+static int midx_read_oid_lookup(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct multi_pack_index *m = data;
+ m->chunk_oid_lookup = chunk_start;
+
+ if (chunk_size != st_mult(m->hash_len, m->num_objects)) {
+ error(_("multi-pack-index OID lookup chunk is the wrong size"));
+ return 1;
+ }
+ return 0;
+}
+
+static int midx_read_object_offsets(const unsigned char *chunk_start,
+ size_t chunk_size, void *data)
+{
+ struct multi_pack_index *m = data;
+ m->chunk_object_offsets = chunk_start;
+
+ if (chunk_size != st_mult(m->num_objects, MIDX_CHUNK_OFFSET_WIDTH)) {
+ error(_("multi-pack-index object offset chunk is the wrong size"));
+ return 1;
+ }
return 0;
}
-struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local)
+#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
+
+static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir,
+ const char *midx_name,
+ int local)
{
struct multi_pack_index *m = NULL;
int fd;
@@ -82,31 +104,26 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
size_t midx_size;
void *midx_map = NULL;
uint32_t hash_version;
- struct strbuf midx_name = STRBUF_INIT;
uint32_t i;
const char *cur_pack_name;
struct chunkfile *cf = NULL;
- get_midx_filename(&midx_name, object_dir);
-
- fd = git_open(midx_name.buf);
+ fd = git_open(midx_name);
if (fd < 0)
goto cleanup_fail;
if (fstat(fd, &st)) {
- error_errno(_("failed to read %s"), midx_name.buf);
+ error_errno(_("failed to read %s"), midx_name);
goto cleanup_fail;
}
midx_size = xsize_t(st.st_size);
if (midx_size < MIDX_MIN_SIZE) {
- error(_("multi-pack-index file %s is too small"), midx_name.buf);
+ error(_("multi-pack-index file %s is too small"), midx_name);
goto cleanup_fail;
}
- strbuf_release(&midx_name);
-
midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
@@ -137,36 +154,50 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
m->num_packs = get_be32(m->data + MIDX_BYTE_NUM_PACKS);
+ m->preferred_pack_idx = -1;
+
cf = init_chunkfile(NULL);
if (read_table_of_contents(cf, m->data, midx_size,
- MIDX_HEADER_SIZE, m->num_chunks))
+ MIDX_HEADER_SIZE, m->num_chunks,
+ MIDX_CHUNK_ALIGNMENT))
goto cleanup_fail;
- if (pair_chunk(cf, MIDX_CHUNKID_PACKNAMES, &m->chunk_pack_names) == CHUNK_NOT_FOUND)
- die(_("multi-pack-index missing required pack-name chunk"));
- if (read_chunk(cf, MIDX_CHUNKID_OIDFANOUT, midx_read_oid_fanout, m) == CHUNK_NOT_FOUND)
- die(_("multi-pack-index missing required OID fanout chunk"));
- if (pair_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, &m->chunk_oid_lookup) == CHUNK_NOT_FOUND)
- die(_("multi-pack-index missing required OID lookup chunk"));
- if (pair_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, &m->chunk_object_offsets) == CHUNK_NOT_FOUND)
- die(_("multi-pack-index missing required object offsets chunk"));
-
- pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets);
+ if (pair_chunk(cf, MIDX_CHUNKID_PACKNAMES, &m->chunk_pack_names, &m->chunk_pack_names_len))
+ die(_("multi-pack-index required pack-name chunk missing or corrupted"));
+ if (read_chunk(cf, MIDX_CHUNKID_OIDFANOUT, midx_read_oid_fanout, m))
+ die(_("multi-pack-index required OID fanout chunk missing or corrupted"));
+ if (read_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, midx_read_oid_lookup, m))
+ die(_("multi-pack-index required OID lookup chunk missing or corrupted"));
+ if (read_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, midx_read_object_offsets, m))
+ die(_("multi-pack-index required object offsets chunk missing or corrupted"));
+
+ pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets,
+ &m->chunk_large_offsets_len);
+ if (git_env_bool("GIT_TEST_MIDX_READ_BTMP", 1))
+ pair_chunk(cf, MIDX_CHUNKID_BITMAPPEDPACKS,
+ (const unsigned char **)&m->chunk_bitmapped_packs,
+ &m->chunk_bitmapped_packs_len);
if (git_env_bool("GIT_TEST_MIDX_READ_RIDX", 1))
- pair_chunk(cf, MIDX_CHUNKID_REVINDEX, &m->chunk_revindex);
-
- m->num_objects = ntohl(m->chunk_oid_fanout[255]);
+ pair_chunk(cf, MIDX_CHUNKID_REVINDEX, &m->chunk_revindex,
+ &m->chunk_revindex_len);
CALLOC_ARRAY(m->pack_names, m->num_packs);
CALLOC_ARRAY(m->packs, m->num_packs);
cur_pack_name = (const char *)m->chunk_pack_names;
for (i = 0; i < m->num_packs; i++) {
+ const char *end;
+ size_t avail = m->chunk_pack_names_len -
+ (cur_pack_name - (const char *)m->chunk_pack_names);
+
m->pack_names[i] = cur_pack_name;
- cur_pack_name += strlen(cur_pack_name) + 1;
+ end = memchr(cur_pack_name, '\0', avail);
+ if (!end)
+ die(_("multi-pack-index pack-name chunk is too short"));
+ cur_pack_name = end + 1;
if (i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0)
die(_("multi-pack-index pack names out of order: '%s' before '%s'"),
@@ -182,7 +213,6 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
cleanup_fail:
free(m);
- strbuf_release(&midx_name);
free_chunkfile(cf);
if (midx_map)
munmap(midx_map, midx_size);
@@ -191,6 +221,169 @@ cleanup_fail:
return NULL;
}
+void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir)
+{
+ strbuf_addf(buf, "%s/pack/multi-pack-index.d", object_dir);
+}
+
+void get_midx_chain_filename(struct strbuf *buf, const char *object_dir)
+{
+ get_midx_chain_dirname(buf, object_dir);
+ strbuf_addstr(buf, "/multi-pack-index-chain");
+}
+
+void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+ const unsigned char *hash, const char *ext)
+{
+ get_midx_chain_dirname(buf, object_dir);
+ strbuf_addf(buf, "/multi-pack-index-%s.%s", hash_to_hex(hash), ext);
+}
+
+static int open_multi_pack_index_chain(const char *chain_file,
+ int *fd, struct stat *st)
+{
+ *fd = git_open(chain_file);
+ if (*fd < 0)
+ return 0;
+ if (fstat(*fd, st)) {
+ close(*fd);
+ return 0;
+ }
+ if (st->st_size < the_hash_algo->hexsz) {
+ close(*fd);
+ if (!st->st_size) {
+ /* treat empty files the same as missing */
+ errno = ENOENT;
+ } else {
+ warning(_("multi-pack-index chain file too small"));
+ errno = EINVAL;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static int add_midx_to_chain(struct multi_pack_index *midx,
+ struct multi_pack_index *midx_chain)
+{
+ if (midx_chain) {
+ if (unsigned_add_overflows(midx_chain->num_packs,
+ midx_chain->num_packs_in_base)) {
+ warning(_("pack count in base MIDX too high: %"PRIuMAX),
+ (uintmax_t)midx_chain->num_packs_in_base);
+ return 0;
+ }
+ if (unsigned_add_overflows(midx_chain->num_objects,
+ midx_chain->num_objects_in_base)) {
+ warning(_("object count in base MIDX too high: %"PRIuMAX),
+ (uintmax_t)midx_chain->num_objects_in_base);
+ return 0;
+ }
+ midx->num_packs_in_base = midx_chain->num_packs +
+ midx_chain->num_packs_in_base;
+ midx->num_objects_in_base = midx_chain->num_objects +
+ midx_chain->num_objects_in_base;
+ }
+
+ midx->base_midx = midx_chain;
+ midx->has_chain = 1;
+
+ return 1;
+}
+
+static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
+ int local,
+ int fd, struct stat *st,
+ int *incomplete_chain)
+{
+ struct multi_pack_index *midx_chain = NULL;
+ struct strbuf buf = STRBUF_INIT;
+ int valid = 1;
+ uint32_t i, count;
+ FILE *fp = xfdopen(fd, "r");
+
+ count = st->st_size / (the_hash_algo->hexsz + 1);
+
+ for (i = 0; i < count; i++) {
+ struct multi_pack_index *m;
+ struct object_id layer;
+
+ if (strbuf_getline_lf(&buf, fp) == EOF)
+ break;
+
+ if (get_oid_hex(buf.buf, &layer)) {
+ warning(_("invalid multi-pack-index chain: line '%s' "
+ "not a hash"),
+ buf.buf);
+ valid = 0;
+ break;
+ }
+
+ valid = 0;
+
+ strbuf_reset(&buf);
+ get_split_midx_filename_ext(&buf, object_dir, layer.hash,
+ MIDX_EXT_MIDX);
+ m = load_multi_pack_index_one(object_dir, buf.buf, local);
+
+ if (m) {
+ if (add_midx_to_chain(m, midx_chain)) {
+ midx_chain = m;
+ valid = 1;
+ } else {
+ close_midx(m);
+ }
+ }
+ if (!valid) {
+ warning(_("unable to find all multi-pack index files"));
+ break;
+ }
+ }
+
+ fclose(fp);
+ strbuf_release(&buf);
+
+ *incomplete_chain = !valid;
+ return midx_chain;
+}
+
+static struct multi_pack_index *load_multi_pack_index_chain(const char *object_dir,
+ int local)
+{
+ struct strbuf chain_file = STRBUF_INIT;
+ struct stat st;
+ int fd;
+ struct multi_pack_index *m = NULL;
+
+ get_midx_chain_filename(&chain_file, object_dir);
+ if (open_multi_pack_index_chain(chain_file.buf, &fd, &st)) {
+ int incomplete;
+ /* ownership of fd is taken over by load function */
+ m = load_midx_chain_fd_st(object_dir, local, fd, &st,
+ &incomplete);
+ }
+
+ strbuf_release(&chain_file);
+ return m;
+}
+
+struct multi_pack_index *load_multi_pack_index(const char *object_dir,
+ int local)
+{
+ struct strbuf midx_name = STRBUF_INIT;
+ struct multi_pack_index *m;
+
+ get_midx_filename(&midx_name, object_dir);
+
+ m = load_multi_pack_index_one(object_dir, midx_name.buf, local);
+ if (!m)
+ m = load_multi_pack_index_chain(object_dir, local);
+
+ strbuf_release(&midx_name);
+
+ return m;
+}
+
void close_midx(struct multi_pack_index *m)
{
uint32_t i;
@@ -199,6 +392,7 @@ void close_midx(struct multi_pack_index *m)
return;
close_midx(m->next);
+ close_midx(m->base_midx);
munmap((unsigned char *)m->data, m->data_len);
@@ -211,14 +405,50 @@ void close_midx(struct multi_pack_index *m)
free(m);
}
-int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id)
+static uint32_t midx_for_object(struct multi_pack_index **_m, uint32_t pos)
+{
+ struct multi_pack_index *m = *_m;
+ while (m && pos < m->num_objects_in_base)
+ m = m->base_midx;
+
+ if (!m)
+ BUG("NULL multi-pack-index for object position: %"PRIu32, pos);
+
+ if (pos >= m->num_objects + m->num_objects_in_base)
+ die(_("invalid MIDX object position, MIDX is likely corrupt"));
+
+ *_m = m;
+
+ return pos - m->num_objects_in_base;
+}
+
+static uint32_t midx_for_pack(struct multi_pack_index **_m,
+ uint32_t pack_int_id)
+{
+ struct multi_pack_index *m = *_m;
+ while (m && pack_int_id < m->num_packs_in_base)
+ m = m->base_midx;
+
+ if (!m)
+ BUG("NULL multi-pack-index for pack ID: %"PRIu32, pack_int_id);
+
+ if (pack_int_id >= m->num_packs + m->num_packs_in_base)
+ die(_("bad pack-int-id: %u (%u total packs)"),
+ pack_int_id, m->num_packs + m->num_packs_in_base);
+
+ *_m = m;
+
+ return pack_int_id - m->num_packs_in_base;
+}
+
+int prepare_midx_pack(struct repository *r, struct multi_pack_index *m,
+ uint32_t pack_int_id)
{
struct strbuf pack_name = STRBUF_INIT;
+ struct strbuf key = STRBUF_INIT;
struct packed_git *p;
- if (pack_int_id >= m->num_packs)
- die(_("bad pack-int-id: %u (%u total packs)"),
- pack_int_id, m->num_packs);
+ pack_int_id = midx_for_pack(&m, pack_int_id);
if (m->packs[pack_int_id])
return 0;
@@ -226,34 +456,101 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t
strbuf_addf(&pack_name, "%s/pack/%s", m->object_dir,
m->pack_names[pack_int_id]);
- p = add_packed_git(pack_name.buf, pack_name.len, m->local);
+ /* pack_map holds the ".pack" name, but we have the .idx */
+ strbuf_addbuf(&key, &pack_name);
+ strbuf_strip_suffix(&key, ".idx");
+ strbuf_addstr(&key, ".pack");
+ p = hashmap_get_entry_from_hash(&r->objects->pack_map,
+ strhash(key.buf), key.buf,
+ struct packed_git, packmap_ent);
+ if (!p) {
+ p = add_packed_git(pack_name.buf, pack_name.len, m->local);
+ if (p) {
+ install_packed_git(r, p);
+ list_add_tail(&p->mru, &r->objects->packed_git_mru);
+ }
+ }
+
strbuf_release(&pack_name);
+ strbuf_release(&key);
if (!p)
return 1;
p->multi_pack_index = 1;
m->packs[pack_int_id] = p;
- install_packed_git(r, p);
- list_add_tail(&p->mru, &r->objects->packed_git_mru);
return 0;
}
-int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result)
+struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
+ uint32_t pack_int_id)
{
- return bsearch_hash(oid->hash, m->chunk_oid_fanout, m->chunk_oid_lookup,
- the_hash_algo->rawsz, result);
+ uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
+ return m->packs[local_pack_int_id];
+}
+
+#define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t))
+
+int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
+ struct bitmapped_pack *bp, uint32_t pack_int_id)
+{
+ uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
+
+ if (!m->chunk_bitmapped_packs)
+ return error(_("MIDX does not contain the BTMP chunk"));
+
+ if (prepare_midx_pack(r, m, pack_int_id))
+ return error(_("could not load bitmapped pack %"PRIu32), pack_int_id);
+
+ bp->p = m->packs[local_pack_int_id];
+ bp->bitmap_pos = get_be32((char *)m->chunk_bitmapped_packs +
+ MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id);
+ bp->bitmap_nr = get_be32((char *)m->chunk_bitmapped_packs +
+ MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id +
+ sizeof(uint32_t));
+ bp->pack_int_id = pack_int_id;
+ bp->from_midx = m;
+
+ return 0;
+}
+
+int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result)
+{
+ int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout,
+ m->chunk_oid_lookup, the_hash_algo->rawsz,
+ result);
+ if (result)
+ *result += m->num_objects_in_base;
+ return ret;
+}
+
+int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result)
+{
+ for (; m; m = m->base_midx)
+ if (bsearch_one_midx(oid, m, result))
+ return 1;
+ return 0;
+}
+
+int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid)
+{
+ return bsearch_midx(oid, m, NULL);
}
struct object_id *nth_midxed_object_oid(struct object_id *oid,
struct multi_pack_index *m,
uint32_t n)
{
- if (n >= m->num_objects)
+ if (n >= m->num_objects + m->num_objects_in_base)
return NULL;
- oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n));
+ n = midx_for_object(&m, n);
+
+ oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n),
+ the_repository->hash_algo);
return oid;
}
@@ -262,6 +559,8 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
const unsigned char *offset_data;
uint32_t offset32;
+ pos = midx_for_object(&m, pos);
+
offset_data = m->chunk_object_offsets + (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH;
offset32 = get_be32(offset_data + sizeof(uint32_t));
@@ -270,8 +569,9 @@ 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 +
- st_mult(sizeof(uint64_t), offset32));
+ if (offset32 >= m->chunk_large_offsets_len / sizeof(uint64_t))
+ die(_("multi-pack-index large offset out of bounds"));
+ return get_be64(m->chunk_large_offsets + sizeof(uint64_t) * offset32);
}
return offset32;
@@ -279,8 +579,10 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
{
- return get_be32(m->chunk_object_offsets +
- (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
+ pos = midx_for_object(&m, pos);
+
+ return m->num_packs_in_base + get_be32(m->chunk_object_offsets +
+ (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
}
int fill_midx_entry(struct repository *r,
@@ -295,14 +597,12 @@ int fill_midx_entry(struct repository *r,
if (!bsearch_midx(oid, m, &pos))
return 0;
- if (pos >= m->num_objects)
- return 0;
-
+ midx_for_object(&m, pos);
pack_int_id = nth_midxed_pack_int_id(m, pos);
if (prepare_midx_pack(r, m, pack_int_id))
return 0;
- p = m->packs[pack_int_id];
+ p = m->packs[pack_int_id - m->num_packs_in_base];
/*
* We are about to tell the caller where they can locate the
@@ -325,8 +625,8 @@ int fill_midx_entry(struct repository *r,
}
/* Match "foo.idx" against either "foo.pack" _or_ "foo.idx". */
-static int cmp_idx_or_pack_name(const char *idx_or_pack_name,
- const char *idx_name)
+int cmp_idx_or_pack_name(const char *idx_or_pack_name,
+ const char *idx_name)
{
/* Skip past any initial matching prefix. */
while (*idx_name && *idx_name == *idx_or_pack_name) {
@@ -356,7 +656,8 @@ static int cmp_idx_or_pack_name(const char *idx_or_pack_name,
return strcmp(idx_or_pack_name, idx_name);
}
-int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name)
+static int midx_contains_pack_1(struct multi_pack_index *m,
+ const char *idx_or_pack_name)
{
uint32_t first = 0, last = m->num_packs;
@@ -379,6 +680,34 @@ int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name)
return 0;
}
+int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name)
+{
+ for (; m; m = m->base_midx)
+ if (midx_contains_pack_1(m, idx_or_pack_name))
+ return 1;
+ return 0;
+}
+
+int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id)
+{
+ if (m->preferred_pack_idx == -1) {
+ uint32_t midx_pos;
+ if (load_midx_revindex(m) < 0) {
+ m->preferred_pack_idx = -2;
+ return -1;
+ }
+
+ midx_pos = pack_pos_to_midx(m, m->num_objects_in_base);
+
+ m->preferred_pack_idx = nth_midxed_pack_int_id(m, midx_pos);
+
+ } else if (m->preferred_pack_idx == -2)
+ return -1; /* no revindex */
+
+ *pack_int_id = m->preferred_pack_idx;
+ return 0;
+}
+
int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local)
{
struct multi_pack_index *m;
@@ -407,1213 +736,14 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i
return 0;
}
-static size_t write_midx_header(struct hashfile *f,
- unsigned char num_chunks,
- uint32_t num_packs)
-{
- hashwrite_be32(f, MIDX_SIGNATURE);
- hashwrite_u8(f, MIDX_VERSION);
- hashwrite_u8(f, oid_version(the_hash_algo));
- hashwrite_u8(f, num_chunks);
- hashwrite_u8(f, 0); /* unused */
- hashwrite_be32(f, num_packs);
-
- return MIDX_HEADER_SIZE;
-}
-
-struct pack_info {
- uint32_t orig_pack_int_id;
- char *pack_name;
- struct packed_git *p;
- unsigned expired : 1;
-};
-
-static int pack_info_compare(const void *_a, const void *_b)
-{
- struct pack_info *a = (struct pack_info *)_a;
- struct pack_info *b = (struct pack_info *)_b;
- return strcmp(a->pack_name, b->pack_name);
-}
-
-static int idx_or_pack_name_cmp(const void *_va, const void *_vb)
-{
- const char *pack_name = _va;
- const struct pack_info *compar = _vb;
-
- return cmp_idx_or_pack_name(pack_name, compar->pack_name);
-}
-
-struct write_midx_context {
- struct pack_info *info;
- size_t nr;
- size_t alloc;
- struct multi_pack_index *m;
- struct progress *progress;
- unsigned pack_paths_checked;
-
- struct pack_midx_entry *entries;
- size_t entries_nr;
-
- uint32_t *pack_perm;
- uint32_t *pack_order;
- unsigned large_offsets_needed:1;
- uint32_t num_large_offsets;
-
- int preferred_pack_idx;
-
- struct string_list *to_include;
-};
-
-static void add_pack_to_midx(const char *full_path, size_t full_path_len,
- const char *file_name, void *data)
-{
- struct write_midx_context *ctx = data;
-
- if (ends_with(file_name, ".idx")) {
- display_progress(ctx->progress, ++ctx->pack_paths_checked);
- /*
- * Note that at most one of ctx->m and ctx->to_include are set,
- * so we are testing midx_contains_pack() and
- * string_list_has_string() independently (guarded by the
- * appropriate NULL checks).
- *
- * We could support passing to_include while reusing an existing
- * MIDX, but don't currently since the reuse process drags
- * forward all packs from an existing MIDX (without checking
- * whether or not they appear in the to_include list).
- *
- * If we added support for that, these next two conditional
- * should be performed independently (likely checking
- * to_include before the existing MIDX).
- */
- if (ctx->m && midx_contains_pack(ctx->m, file_name))
- return;
- else if (ctx->to_include &&
- !string_list_has_string(ctx->to_include, file_name))
- return;
-
- ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
-
- ctx->info[ctx->nr].p = add_packed_git(full_path,
- full_path_len,
- 0);
-
- if (!ctx->info[ctx->nr].p) {
- warning(_("failed to add packfile '%s'"),
- full_path);
- return;
- }
-
- if (open_pack_index(ctx->info[ctx->nr].p)) {
- warning(_("failed to open pack-index '%s'"),
- full_path);
- close_pack(ctx->info[ctx->nr].p);
- FREE_AND_NULL(ctx->info[ctx->nr].p);
- return;
- }
-
- ctx->info[ctx->nr].pack_name = xstrdup(file_name);
- ctx->info[ctx->nr].orig_pack_int_id = ctx->nr;
- ctx->info[ctx->nr].expired = 0;
- ctx->nr++;
- }
-}
-
-struct pack_midx_entry {
- struct object_id oid;
- uint32_t pack_int_id;
- time_t pack_mtime;
- uint64_t offset;
- unsigned preferred : 1;
-};
-
-static int midx_oid_compare(const void *_a, const void *_b)
-{
- const struct pack_midx_entry *a = (const struct pack_midx_entry *)_a;
- const struct pack_midx_entry *b = (const struct pack_midx_entry *)_b;
- int cmp = oidcmp(&a->oid, &b->oid);
-
- if (cmp)
- return cmp;
-
- /* Sort objects in a preferred pack first when multiple copies exist. */
- if (a->preferred > b->preferred)
- return -1;
- if (a->preferred < b->preferred)
- return 1;
-
- if (a->pack_mtime > b->pack_mtime)
- return -1;
- else if (a->pack_mtime < b->pack_mtime)
- return 1;
-
- return a->pack_int_id - b->pack_int_id;
-}
-
-static int nth_midxed_pack_midx_entry(struct multi_pack_index *m,
- struct pack_midx_entry *e,
- uint32_t pos)
-{
- if (pos >= m->num_objects)
- return 1;
-
- nth_midxed_object_oid(&e->oid, m, pos);
- e->pack_int_id = nth_midxed_pack_int_id(m, pos);
- e->offset = nth_midxed_offset(m, pos);
-
- /* consider objects in midx to be from "old" packs */
- e->pack_mtime = 0;
- return 0;
-}
-
-static void fill_pack_entry(uint32_t pack_int_id,
- struct packed_git *p,
- uint32_t cur_object,
- struct pack_midx_entry *entry,
- int preferred)
-{
- if (nth_packed_object_id(&entry->oid, p, cur_object) < 0)
- die(_("failed to locate object %d in packfile"), cur_object);
-
- entry->pack_int_id = pack_int_id;
- entry->pack_mtime = p->mtime;
-
- entry->offset = nth_packed_object_offset(p, cur_object);
- entry->preferred = !!preferred;
-}
-
-struct midx_fanout {
- struct pack_midx_entry *entries;
- size_t nr, alloc;
-};
-
-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);
-}
-
-static void midx_fanout_sort(struct midx_fanout *fanout)
-{
- QSORT(fanout->entries, fanout->nr, midx_oid_compare);
-}
-
-static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
- struct multi_pack_index *m,
- uint32_t cur_fanout,
- int preferred_pack)
-{
- uint32_t start = 0, end;
- uint32_t cur_object;
-
- if (cur_fanout)
- start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
- end = ntohl(m->chunk_oid_fanout[cur_fanout]);
-
- for (cur_object = start; cur_object < end; cur_object++) {
- if ((preferred_pack > -1) &&
- (preferred_pack == nth_midxed_pack_int_id(m, cur_object))) {
- /*
- * Objects from preferred packs are added
- * separately.
- */
- continue;
- }
-
- midx_fanout_grow(fanout, fanout->nr + 1);
- nth_midxed_pack_midx_entry(m,
- &fanout->entries[fanout->nr],
- cur_object);
- fanout->entries[fanout->nr].preferred = 0;
- fanout->nr++;
- }
-}
-
-static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
- struct pack_info *info,
- uint32_t cur_pack,
- int preferred,
- uint32_t cur_fanout)
-{
- struct packed_git *pack = info[cur_pack].p;
- uint32_t start = 0, end;
- uint32_t cur_object;
-
- if (cur_fanout)
- start = get_pack_fanout(pack, cur_fanout - 1);
- end = get_pack_fanout(pack, cur_fanout);
-
- for (cur_object = start; cur_object < end; cur_object++) {
- midx_fanout_grow(fanout, fanout->nr + 1);
- fill_pack_entry(cur_pack,
- info[cur_pack].p,
- cur_object,
- &fanout->entries[fanout->nr],
- preferred);
- fanout->nr++;
- }
-}
-
-/*
- * It is possible to artificially get into a state where there are many
- * duplicate copies of objects. That can create high memory pressure if
- * we are to create a list of all objects before de-duplication. To reduce
- * this memory pressure without a significant performance drop, automatically
- * group objects by the first byte of their object id. Use the IDX fanout
- * tables to group the data, copy to a local array, then sort.
- *
- * Copy only the de-duplicated entries (selected by most-recent modified time
- * of a packfile containing the object).
- */
-static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
- struct pack_info *info,
- uint32_t nr_packs,
- size_t *nr_objects,
- int preferred_pack)
-{
- uint32_t cur_fanout, cur_pack, cur_object;
- 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 = st_add(total_objects,
- info[cur_pack].p->num_objects);
-
- /*
- * As we de-duplicate by fanout value, we expect the fanout
- * slices to be evenly distributed, with some noise. Hence,
- * allocate slightly more than one 256th.
- */
- alloc_objects = fanout.alloc = total_objects > 3200 ? total_objects / 200 : 16;
-
- ALLOC_ARRAY(fanout.entries, fanout.alloc);
- ALLOC_ARRAY(deduplicated_entries, alloc_objects);
- *nr_objects = 0;
-
- for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
- fanout.nr = 0;
-
- if (m)
- midx_fanout_add_midx_fanout(&fanout, m, cur_fanout,
- preferred_pack);
-
- for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++) {
- int preferred = cur_pack == preferred_pack;
- midx_fanout_add_pack_fanout(&fanout,
- info, cur_pack,
- preferred, cur_fanout);
- }
-
- if (-1 < preferred_pack && preferred_pack < start_pack)
- midx_fanout_add_pack_fanout(&fanout, info,
- preferred_pack, 1,
- cur_fanout);
-
- midx_fanout_sort(&fanout);
-
- /*
- * The batch is now sorted by OID and then mtime (descending).
- * Take only the first duplicate.
- */
- for (cur_object = 0; cur_object < fanout.nr; cur_object++) {
- if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
- &fanout.entries[cur_object].oid))
- continue;
-
- 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));
- (*nr_objects)++;
- }
- }
-
- free(fanout.entries);
- return deduplicated_entries;
-}
-
-static int write_midx_pack_names(struct hashfile *f, void *data)
-{
- struct write_midx_context *ctx = data;
- uint32_t i;
- unsigned char padding[MIDX_CHUNK_ALIGNMENT];
- size_t written = 0;
-
- for (i = 0; i < ctx->nr; i++) {
- size_t writelen;
-
- if (ctx->info[i].expired)
- continue;
-
- if (i && strcmp(ctx->info[i].pack_name, ctx->info[i - 1].pack_name) <= 0)
- BUG("incorrect pack-file order: %s before %s",
- ctx->info[i - 1].pack_name,
- ctx->info[i].pack_name);
-
- writelen = strlen(ctx->info[i].pack_name) + 1;
- hashwrite(f, ctx->info[i].pack_name, writelen);
- written += writelen;
- }
-
- /* add padding to be aligned */
- i = MIDX_CHUNK_ALIGNMENT - (written % MIDX_CHUNK_ALIGNMENT);
- if (i < MIDX_CHUNK_ALIGNMENT) {
- memset(padding, 0, sizeof(padding));
- hashwrite(f, padding, i);
- }
-
- return 0;
-}
-
-static int write_midx_oid_fanout(struct hashfile *f,
- void *data)
-{
- struct write_midx_context *ctx = data;
- struct pack_midx_entry *list = ctx->entries;
- struct pack_midx_entry *last = ctx->entries + ctx->entries_nr;
- uint32_t count = 0;
- uint32_t i;
-
- /*
- * Write the first-level table (the list is sorted,
- * but we use a 256-entry lookup to be able to avoid
- * having to do eight extra binary search iterations).
- */
- for (i = 0; i < 256; i++) {
- struct pack_midx_entry *next = list;
-
- while (next < last && next->oid.hash[0] == i) {
- count++;
- next++;
- }
-
- hashwrite_be32(f, count);
- list = next;
- }
-
- return 0;
-}
-
-static int write_midx_oid_lookup(struct hashfile *f,
- void *data)
-{
- struct write_midx_context *ctx = data;
- unsigned char hash_len = the_hash_algo->rawsz;
- struct pack_midx_entry *list = ctx->entries;
- uint32_t i;
-
- for (i = 0; i < ctx->entries_nr; i++) {
- struct pack_midx_entry *obj = list++;
-
- if (i < ctx->entries_nr - 1) {
- struct pack_midx_entry *next = list;
- if (oidcmp(&obj->oid, &next->oid) >= 0)
- BUG("OIDs not in order: %s >= %s",
- oid_to_hex(&obj->oid),
- oid_to_hex(&next->oid));
- }
-
- hashwrite(f, obj->oid.hash, (int)hash_len);
- }
-
- return 0;
-}
-
-static int write_midx_object_offsets(struct hashfile *f,
- void *data)
-{
- struct write_midx_context *ctx = data;
- struct pack_midx_entry *list = ctx->entries;
- uint32_t i, nr_large_offset = 0;
-
- for (i = 0; i < ctx->entries_nr; i++) {
- struct pack_midx_entry *obj = list++;
-
- if (ctx->pack_perm[obj->pack_int_id] == PACK_EXPIRED)
- BUG("object %s is in an expired pack with int-id %d",
- oid_to_hex(&obj->oid),
- obj->pack_int_id);
-
- hashwrite_be32(f, ctx->pack_perm[obj->pack_int_id]);
-
- if (ctx->large_offsets_needed && obj->offset >> 31)
- hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
- else if (!ctx->large_offsets_needed && obj->offset >> 32)
- BUG("object %s requires a large offset (%"PRIx64") but the MIDX is not writing large offsets!",
- oid_to_hex(&obj->oid),
- obj->offset);
- else
- hashwrite_be32(f, (uint32_t)obj->offset);
- }
-
- return 0;
-}
-
-static int write_midx_large_offsets(struct hashfile *f,
- void *data)
-{
- struct write_midx_context *ctx = data;
- struct pack_midx_entry *list = ctx->entries;
- struct pack_midx_entry *end = ctx->entries + ctx->entries_nr;
- uint32_t nr_large_offset = ctx->num_large_offsets;
-
- while (nr_large_offset) {
- struct pack_midx_entry *obj;
- uint64_t offset;
-
- if (list >= end)
- BUG("too many large-offset objects");
-
- obj = list++;
- offset = obj->offset;
-
- if (!(offset >> 31))
- continue;
-
- hashwrite_be64(f, offset);
-
- nr_large_offset--;
- }
-
- return 0;
-}
-
-static int write_midx_revindex(struct hashfile *f,
- void *data)
-{
- struct write_midx_context *ctx = data;
- uint32_t i;
-
- for (i = 0; i < ctx->entries_nr; i++)
- hashwrite_be32(f, ctx->pack_order[i]);
-
- return 0;
-}
-
-struct midx_pack_order_data {
- uint32_t nr;
- uint32_t pack;
- off_t offset;
-};
-
-static int midx_pack_order_cmp(const void *va, const void *vb)
-{
- const struct midx_pack_order_data *a = va, *b = vb;
- if (a->pack < b->pack)
- return -1;
- else if (a->pack > b->pack)
- return 1;
- else if (a->offset < b->offset)
- return -1;
- else if (a->offset > b->offset)
- return 1;
- else
- return 0;
-}
-
-static uint32_t *midx_pack_order(struct write_midx_context *ctx)
-{
- struct midx_pack_order_data *data;
- uint32_t *pack_order;
- uint32_t i;
-
- trace2_region_enter("midx", "midx_pack_order", the_repository);
-
- ALLOC_ARRAY(data, ctx->entries_nr);
- for (i = 0; i < ctx->entries_nr; i++) {
- struct pack_midx_entry *e = &ctx->entries[i];
- data[i].nr = i;
- data[i].pack = ctx->pack_perm[e->pack_int_id];
- if (!e->preferred)
- data[i].pack |= (1U << 31);
- data[i].offset = e->offset;
- }
-
- QSORT(data, ctx->entries_nr, midx_pack_order_cmp);
-
- ALLOC_ARRAY(pack_order, ctx->entries_nr);
- for (i = 0; i < ctx->entries_nr; i++)
- pack_order[i] = data[i].nr;
- free(data);
-
- trace2_region_leave("midx", "midx_pack_order", the_repository);
-
- return pack_order;
-}
-
-static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
- struct write_midx_context *ctx)
-{
- struct strbuf buf = STRBUF_INIT;
- const char *tmp_file;
-
- trace2_region_enter("midx", "write_midx_reverse_index", the_repository);
-
- strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash));
-
- tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
- midx_hash, WRITE_REV);
-
- if (finalize_object_file(tmp_file, buf.buf))
- die(_("cannot store reverse index file"));
-
- strbuf_release(&buf);
-
- trace2_region_leave("midx", "write_midx_reverse_index", the_repository);
-}
-
-static void clear_midx_files_ext(const char *object_dir, const char *ext,
- unsigned char *keep_hash);
-
-static int midx_checksum_valid(struct multi_pack_index *m)
+int midx_checksum_valid(struct multi_pack_index *m)
{
return hashfile_checksum_valid(m->data, m->data_len);
}
-static void prepare_midx_packing_data(struct packing_data *pdata,
- struct write_midx_context *ctx)
-{
- uint32_t i;
-
- trace2_region_enter("midx", "prepare_midx_packing_data", the_repository);
-
- memset(pdata, 0, sizeof(struct packing_data));
- prepare_packing_data(the_repository, pdata);
-
- for (i = 0; i < ctx->entries_nr; i++) {
- struct pack_midx_entry *from = &ctx->entries[ctx->pack_order[i]];
- struct object_entry *to = packlist_alloc(pdata, &from->oid);
-
- oe_set_in_pack(pdata, to,
- ctx->info[ctx->pack_perm[from->pack_int_id]].p);
- }
-
- trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
-}
-
-static int add_ref_to_pending(const char *refname,
- const struct object_id *oid,
- int flag, void *cb_data)
-{
- struct rev_info *revs = (struct rev_info*)cb_data;
- struct object_id peeled;
- struct object *object;
-
- if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
- warning("symbolic ref is dangling: %s", refname);
- return 0;
- }
-
- if (!peel_iterated_oid(oid, &peeled))
- oid = &peeled;
-
- object = parse_object_or_die(oid, refname);
- if (object->type != OBJ_COMMIT)
- return 0;
-
- add_pending_object(revs, object, "");
- if (bitmap_is_preferred_refname(revs->repo, refname))
- object->flags |= NEEDS_BITMAP;
- return 0;
-}
-
-struct bitmap_commit_cb {
- struct commit **commits;
- size_t commits_nr, commits_alloc;
-
- struct write_midx_context *ctx;
-};
-
-static const struct object_id *bitmap_oid_access(size_t index,
- const void *_entries)
-{
- const struct pack_midx_entry *entries = _entries;
- return &entries[index].oid;
-}
-
-static void bitmap_show_commit(struct commit *commit, void *_data)
-{
- struct bitmap_commit_cb *data = _data;
- int pos = oid_pos(&commit->object.oid, data->ctx->entries,
- data->ctx->entries_nr,
- bitmap_oid_access);
- if (pos < 0)
- return;
-
- ALLOC_GROW(data->commits, data->commits_nr + 1, data->commits_alloc);
- data->commits[data->commits_nr++] = commit;
-}
-
-static int read_refs_snapshot(const char *refs_snapshot,
- struct rev_info *revs)
-{
- struct strbuf buf = STRBUF_INIT;
- struct object_id oid;
- FILE *f = xfopen(refs_snapshot, "r");
-
- while (strbuf_getline(&buf, f) != EOF) {
- struct object *object;
- int preferred = 0;
- char *hex = buf.buf;
- const char *end = NULL;
-
- if (buf.len && *buf.buf == '+') {
- preferred = 1;
- hex = &buf.buf[1];
- }
-
- if (parse_oid_hex(hex, &oid, &end) < 0)
- die(_("could not parse line: %s"), buf.buf);
- if (*end)
- die(_("malformed line: %s"), buf.buf);
-
- object = parse_object_or_die(&oid, NULL);
- if (preferred)
- object->flags |= NEEDS_BITMAP;
-
- add_pending_object(revs, object, "");
- }
-
- fclose(f);
- strbuf_release(&buf);
- return 0;
-}
-
-static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p,
- const char *refs_snapshot,
- struct write_midx_context *ctx)
-{
- struct rev_info revs;
- struct bitmap_commit_cb cb = {0};
-
- trace2_region_enter("midx", "find_commits_for_midx_bitmap",
- the_repository);
-
- cb.ctx = ctx;
-
- repo_init_revisions(the_repository, &revs, NULL);
- if (refs_snapshot) {
- read_refs_snapshot(refs_snapshot, &revs);
- } else {
- setup_revisions(0, NULL, &revs, NULL);
- for_each_ref(add_ref_to_pending, &revs);
- }
-
- /*
- * Skipping promisor objects here is intentional, since it only excludes
- * them from the list of reachable commits that we want to select from
- * when computing the selection of MIDX'd commits to receive bitmaps.
- *
- * Reachability bitmaps do require that their objects be closed under
- * reachability, but fetching any objects missing from promisors at this
- * point is too late. But, if one of those objects can be reached from
- * an another object that is included in the bitmap, then we will
- * complain later that we don't have reachability closure (and fail
- * appropriately).
- */
- fetch_if_missing = 0;
- revs.exclude_promisor_objects = 1;
-
- if (prepare_revision_walk(&revs))
- die(_("revision walk setup failed"));
-
- traverse_commit_list(&revs, bitmap_show_commit, NULL, &cb);
- if (indexed_commits_nr_p)
- *indexed_commits_nr_p = cb.commits_nr;
-
- release_revisions(&revs);
-
- trace2_region_leave("midx", "find_commits_for_midx_bitmap",
- the_repository);
-
- return cb.commits;
-}
-
-static int write_midx_bitmap(const char *midx_name,
- const unsigned char *midx_hash,
- struct packing_data *pdata,
- struct commit **commits,
- uint32_t commits_nr,
- uint32_t *pack_order,
- unsigned flags)
-{
- int ret, i;
- uint16_t options = 0;
- struct pack_idx_entry **index;
- char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
- hash_to_hex(midx_hash));
-
- trace2_region_enter("midx", "write_midx_bitmap", the_repository);
-
- if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
- options |= BITMAP_OPT_HASH_CACHE;
-
- if (flags & MIDX_WRITE_BITMAP_LOOKUP_TABLE)
- options |= BITMAP_OPT_LOOKUP_TABLE;
-
- /*
- * Build the MIDX-order index based on pdata.objects (which is already
- * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
- * this order).
- */
- ALLOC_ARRAY(index, pdata->nr_objects);
- for (i = 0; i < pdata->nr_objects; i++)
- index[i] = &pdata->objects[i].idx;
-
- bitmap_writer_show_progress(flags & MIDX_PROGRESS);
- bitmap_writer_build_type_index(pdata, index, pdata->nr_objects);
-
- /*
- * bitmap_writer_finish expects objects in lex order, but pack_order
- * gives us exactly that. use it directly instead of re-sorting the
- * array.
- *
- * This changes the order of objects in 'index' between
- * bitmap_writer_build_type_index and bitmap_writer_finish.
- *
- * The same re-ordering takes place in the single-pack bitmap code via
- * write_idx_file(), which is called by finish_tmp_packfile(), which
- * happens between bitmap_writer_build_type_index() and
- * bitmap_writer_finish().
- */
- for (i = 0; i < pdata->nr_objects; i++)
- index[pack_order[i]] = &pdata->objects[i].idx;
-
- bitmap_writer_select_commits(commits, commits_nr, -1);
- ret = bitmap_writer_build(pdata);
- if (ret < 0)
- goto cleanup;
-
- bitmap_writer_set_checksum(midx_hash);
- bitmap_writer_finish(index, pdata->nr_objects, bitmap_name, options);
-
-cleanup:
- free(index);
- free(bitmap_name);
-
- trace2_region_leave("midx", "write_midx_bitmap", the_repository);
-
- return ret;
-}
-
-static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
- const char *object_dir)
-{
- struct multi_pack_index *result = NULL;
- struct multi_pack_index *cur;
- char *obj_dir_real = real_pathdup(object_dir, 1);
- struct strbuf cur_path_real = STRBUF_INIT;
-
- /* Ensure the given object_dir is local, or a known alternate. */
- find_odb(r, obj_dir_real);
-
- for (cur = get_multi_pack_index(r); cur; cur = cur->next) {
- strbuf_realpath(&cur_path_real, cur->object_dir, 1);
- if (!strcmp(obj_dir_real, cur_path_real.buf)) {
- result = cur;
- goto cleanup;
- }
- }
-
-cleanup:
- free(obj_dir_real);
- strbuf_release(&cur_path_real);
- return result;
-}
-
-static int write_midx_internal(const char *object_dir,
- struct string_list *packs_to_include,
- struct string_list *packs_to_drop,
- const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags)
-{
- struct strbuf midx_name = STRBUF_INIT;
- unsigned char midx_hash[GIT_MAX_RAWSZ];
- uint32_t i;
- struct hashfile *f = NULL;
- struct lock_file lk;
- struct write_midx_context ctx = { 0 };
- int pack_name_concat_len = 0;
- int dropped_packs = 0;
- int result = 0;
- struct chunkfile *cf;
-
- trace2_region_enter("midx", "write_midx_internal", the_repository);
-
- get_midx_filename(&midx_name, object_dir);
- if (safe_create_leading_directories(midx_name.buf))
- die_errno(_("unable to create leading directories of %s"),
- midx_name.buf);
-
- if (!packs_to_include) {
- /*
- * Only reference an existing MIDX when not filtering which
- * packs to include, since all packs and objects are copied
- * blindly from an existing MIDX if one is present.
- */
- ctx.m = lookup_multi_pack_index(the_repository, object_dir);
- }
-
- if (ctx.m && !midx_checksum_valid(ctx.m)) {
- warning(_("ignoring existing multi-pack-index; checksum mismatch"));
- ctx.m = NULL;
- }
-
- ctx.nr = 0;
- ctx.alloc = ctx.m ? ctx.m->num_packs : 16;
- ctx.info = NULL;
- ALLOC_ARRAY(ctx.info, ctx.alloc);
-
- if (ctx.m) {
- for (i = 0; i < ctx.m->num_packs; i++) {
- ALLOC_GROW(ctx.info, ctx.nr + 1, ctx.alloc);
-
- ctx.info[ctx.nr].orig_pack_int_id = i;
- ctx.info[ctx.nr].pack_name = xstrdup(ctx.m->pack_names[i]);
- ctx.info[ctx.nr].p = ctx.m->packs[i];
- ctx.info[ctx.nr].expired = 0;
-
- if (flags & MIDX_WRITE_REV_INDEX) {
- /*
- * If generating a reverse index, need to have
- * packed_git's loaded to compare their
- * mtimes and object count.
- */
- if (prepare_midx_pack(the_repository, ctx.m, i)) {
- error(_("could not load pack"));
- result = 1;
- goto cleanup;
- }
-
- if (open_pack_index(ctx.m->packs[i]))
- die(_("could not open index for %s"),
- ctx.m->packs[i]->pack_name);
- ctx.info[ctx.nr].p = ctx.m->packs[i];
- }
-
- ctx.nr++;
- }
- }
-
- ctx.pack_paths_checked = 0;
- if (flags & MIDX_PROGRESS)
- ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
- else
- ctx.progress = NULL;
-
- ctx.to_include = packs_to_include;
-
- for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
- stop_progress(&ctx.progress);
-
- if ((ctx.m && ctx.nr == ctx.m->num_packs) &&
- !(packs_to_include || packs_to_drop)) {
- struct bitmap_index *bitmap_git;
- int bitmap_exists;
- int want_bitmap = flags & MIDX_WRITE_BITMAP;
-
- bitmap_git = prepare_midx_bitmap_git(ctx.m);
- bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git);
- free_bitmap_index(bitmap_git);
-
- if (bitmap_exists || !want_bitmap) {
- /*
- * The correct MIDX already exists, and so does a
- * corresponding bitmap (or one wasn't requested).
- */
- if (!want_bitmap)
- clear_midx_files_ext(object_dir, ".bitmap",
- NULL);
- goto cleanup;
- }
- }
-
- if (preferred_pack_name) {
- 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;
- break;
- }
- }
-
- if (ctx.preferred_pack_idx == -1)
- warning(_("unknown preferred pack: '%s'"),
- preferred_pack_name);
- } else if (ctx.nr &&
- (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
- struct packed_git *oldest = ctx.info[ctx.preferred_pack_idx].p;
- ctx.preferred_pack_idx = 0;
-
- if (packs_to_drop && packs_to_drop->nr)
- BUG("cannot write a MIDX bitmap during expiration");
-
- /*
- * set a preferred pack when writing a bitmap to ensure that
- * the pack from which the first object is selected in pseudo
- * pack-order has all of its objects selected from that pack
- * (and not another pack containing a duplicate)
- */
- for (i = 1; i < ctx.nr; i++) {
- struct packed_git *p = ctx.info[i].p;
-
- if (!oldest->num_objects || p->mtime < oldest->mtime) {
- oldest = p;
- ctx.preferred_pack_idx = i;
- }
- }
-
- if (!oldest->num_objects) {
- /*
- * If all packs are empty; unset the preferred index.
- * This is acceptable since there will be no duplicate
- * objects to resolve, so the preferred value doesn't
- * matter.
- */
- ctx.preferred_pack_idx = -1;
- }
- } else {
- /*
- * otherwise don't mark any pack as preferred to avoid
- * interfering with expiration logic below
- */
- ctx.preferred_pack_idx = -1;
- }
-
- if (ctx.preferred_pack_idx > -1) {
- struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p;
- if (!preferred->num_objects) {
- error(_("cannot select preferred pack %s with no objects"),
- preferred->pack_name);
- result = 1;
- goto cleanup;
- }
- }
-
- ctx.entries = get_sorted_entries(ctx.m, ctx.info, ctx.nr, &ctx.entries_nr,
- ctx.preferred_pack_idx);
-
- ctx.large_offsets_needed = 0;
- for (i = 0; i < ctx.entries_nr; i++) {
- if (ctx.entries[i].offset > 0x7fffffff)
- ctx.num_large_offsets++;
- if (ctx.entries[i].offset > 0xffffffff)
- ctx.large_offsets_needed = 1;
- }
-
- QSORT(ctx.info, ctx.nr, pack_info_compare);
-
- if (packs_to_drop && packs_to_drop->nr) {
- int drop_index = 0;
- int missing_drops = 0;
-
- for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
- int cmp = strcmp(ctx.info[i].pack_name,
- packs_to_drop->items[drop_index].string);
-
- if (!cmp) {
- drop_index++;
- ctx.info[i].expired = 1;
- } else if (cmp > 0) {
- error(_("did not see pack-file %s to drop"),
- packs_to_drop->items[drop_index].string);
- drop_index++;
- missing_drops++;
- i--;
- } else {
- ctx.info[i].expired = 0;
- }
- }
-
- if (missing_drops) {
- result = 1;
- goto cleanup;
- }
- }
-
- /*
- * pack_perm stores a permutation between pack-int-ids from the
- * previous multi-pack-index to the new one we are writing:
- *
- * pack_perm[old_id] = new_id
- */
- ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
- for (i = 0; i < ctx.nr; i++) {
- if (ctx.info[i].expired) {
- dropped_packs++;
- ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
- } else {
- ctx.pack_perm[ctx.info[i].orig_pack_int_id] = i - dropped_packs;
- }
- }
-
- for (i = 0; i < ctx.nr; i++) {
- if (!ctx.info[i].expired)
- pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1;
- }
-
- /* Check that the preferred pack wasn't expired (if given). */
- if (preferred_pack_name) {
- struct pack_info *preferred = bsearch(preferred_pack_name,
- ctx.info, ctx.nr,
- sizeof(*ctx.info),
- idx_or_pack_name_cmp);
- if (preferred) {
- uint32_t perm = ctx.pack_perm[preferred->orig_pack_int_id];
- if (perm == PACK_EXPIRED)
- warning(_("preferred pack '%s' is expired"),
- preferred_pack_name);
- }
- }
-
- if (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT)
- pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
- (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
-
- hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
- f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
-
- if (ctx.nr - dropped_packs == 0) {
- error(_("no pack files to index."));
- result = 1;
- goto cleanup;
- }
-
- if (!ctx.entries_nr) {
- if (flags & MIDX_WRITE_BITMAP)
- warning(_("refusing to write multi-pack .bitmap without any objects"));
- flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
- }
-
- cf = init_chunkfile(f);
-
- add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
- write_midx_pack_names);
- add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
- write_midx_oid_fanout);
- add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
- st_mult(ctx.entries_nr, the_hash_algo->rawsz),
- write_midx_oid_lookup);
- add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
- st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH),
- write_midx_object_offsets);
-
- if (ctx.large_offsets_needed)
- add_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS,
- 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,
- st_mult(ctx.entries_nr, sizeof(uint32_t)),
- write_midx_revindex);
- }
-
- write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs);
- write_chunkfile(cf, &ctx);
-
- finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA,
- CSUM_FSYNC | CSUM_HASH_IN_STREAM);
- free_chunkfile(cf);
-
- if (flags & MIDX_WRITE_REV_INDEX &&
- git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
- write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
-
- if (flags & MIDX_WRITE_BITMAP) {
- struct packing_data pdata;
- struct commit **commits;
- uint32_t commits_nr;
-
- if (!ctx.entries_nr)
- BUG("cannot write a bitmap without any objects");
-
- prepare_midx_packing_data(&pdata, &ctx);
-
- commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, &ctx);
-
- /*
- * The previous steps translated the information from
- * 'entries' into information suitable for constructing
- * bitmaps. We no longer need that array, so clear it to
- * reduce memory pressure.
- */
- FREE_AND_NULL(ctx.entries);
- ctx.entries_nr = 0;
-
- if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata,
- commits, commits_nr, ctx.pack_order,
- flags) < 0) {
- error(_("could not write multi-pack bitmap"));
- result = 1;
- goto cleanup;
- }
- }
- /*
- * NOTE: Do not use ctx.entries beyond this point, since it might
- * have been freed in the previous if block.
- */
-
- if (ctx.m)
- close_object_store(the_repository->objects);
-
- if (commit_lock_file(&lk) < 0)
- die_errno(_("could not write multi-pack-index"));
-
- clear_midx_files_ext(object_dir, ".bitmap", midx_hash);
- clear_midx_files_ext(object_dir, ".rev", midx_hash);
-
-cleanup:
- for (i = 0; i < ctx.nr; i++) {
- if (ctx.info[i].p) {
- close_pack(ctx.info[i].p);
- free(ctx.info[i].p);
- }
- free(ctx.info[i].pack_name);
- }
-
- free(ctx.info);
- free(ctx.entries);
- free(ctx.pack_perm);
- free(ctx.pack_order);
- strbuf_release(&midx_name);
-
- trace2_region_leave("midx", "write_midx_internal", the_repository);
-
- return result;
-}
-
-int write_midx_file(const char *object_dir,
- const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags)
-{
- return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name,
- refs_snapshot, flags);
-}
-
-int write_midx_file_only(const char *object_dir,
- struct string_list *packs_to_include,
- const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags)
-{
- return write_midx_internal(object_dir, packs_to_include, NULL,
- preferred_pack_name, refs_snapshot, flags);
-}
-
struct clear_midx_data {
- char *keep;
+ char **keep;
+ uint32_t keep_nr;
const char *ext;
};
@@ -1621,32 +751,63 @@ static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUS
const char *file_name, void *_data)
{
struct clear_midx_data *data = _data;
+ uint32_t i;
if (!(starts_with(file_name, "multi-pack-index-") &&
ends_with(file_name, data->ext)))
return;
- if (data->keep && !strcmp(data->keep, file_name))
- return;
-
+ for (i = 0; i < data->keep_nr; i++) {
+ if (!strcmp(data->keep[i], file_name))
+ return;
+ }
if (unlink(full_path))
die_errno(_("failed to remove %s"), full_path);
}
-static void clear_midx_files_ext(const char *object_dir, const char *ext,
- unsigned char *keep_hash)
+void clear_midx_files_ext(const char *object_dir, const char *ext,
+ const char *keep_hash)
{
struct clear_midx_data data;
memset(&data, 0, sizeof(struct clear_midx_data));
- if (keep_hash)
- data.keep = xstrfmt("multi-pack-index-%s%s",
- hash_to_hex(keep_hash), ext);
+ if (keep_hash) {
+ ALLOC_ARRAY(data.keep, 1);
+
+ data.keep[0] = xstrfmt("multi-pack-index-%s.%s", keep_hash, ext);
+ data.keep_nr = 1;
+ }
data.ext = ext;
for_each_file_in_pack_dir(object_dir,
clear_midx_file_ext,
&data);
+ if (keep_hash)
+ free(data.keep[0]);
+ free(data.keep);
+}
+
+void clear_incremental_midx_files_ext(const char *object_dir, const char *ext,
+ char **keep_hashes,
+ uint32_t hashes_nr)
+{
+ struct clear_midx_data data;
+ uint32_t i;
+
+ memset(&data, 0, sizeof(struct clear_midx_data));
+
+ ALLOC_ARRAY(data.keep, hashes_nr);
+ for (i = 0; i < hashes_nr; i++)
+ data.keep[i] = xstrfmt("multi-pack-index-%s.%s", keep_hashes[i],
+ ext);
+ data.keep_nr = hashes_nr;
+ data.ext = ext;
+
+ for_each_file_in_pack_subdir(object_dir, "multi-pack-index.d",
+ clear_midx_file_ext, &data);
+
+ for (i = 0; i < hashes_nr; i++)
+ free(data.keep[i]);
free(data.keep);
}
@@ -1664,8 +825,8 @@ void clear_midx_file(struct repository *r)
if (remove_path(midx.buf))
die(_("failed to clear multi-pack-index at %s"), midx.buf);
- clear_midx_files_ext(r->objects->odb->path, ".bitmap", NULL);
- clear_midx_files_ext(r->objects->odb->path, ".rev", NULL);
+ clear_midx_files_ext(r->objects->odb->path, MIDX_EXT_BITMAP, NULL);
+ clear_midx_files_ext(r->objects->odb->path, MIDX_EXT_REV, NULL);
strbuf_release(&midx);
}
@@ -1715,6 +876,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
uint32_t i;
struct progress *progress = NULL;
struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+ struct multi_pack_index *curr;
verify_midx_error = 0;
if (!m) {
@@ -1737,8 +899,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
if (flags & MIDX_PROGRESS)
progress = start_delayed_progress(_("Looking for referenced packfiles"),
- m->num_packs);
- for (i = 0; i < m->num_packs; i++) {
+ m->num_packs + m->num_packs_in_base);
+ for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) {
if (prepare_midx_pack(r, m, i))
midx_report("failed to load pack in position %d", i);
@@ -1746,15 +908,6 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
}
stop_progress(&progress);
- for (i = 0; i < 255; i++) {
- uint32_t oid_fanout1 = ntohl(m->chunk_oid_fanout[i]);
- uint32_t oid_fanout2 = ntohl(m->chunk_oid_fanout[i + 1]);
-
- if (oid_fanout1 > oid_fanout2)
- midx_report(_("oid fanout out of order: fanout[%d] = %"PRIx32" > %"PRIx32" = fanout[%d]"),
- i, oid_fanout1, oid_fanout2, i + 1);
- }
-
if (m->num_objects == 0) {
midx_report(_("the midx contains no oid"));
/*
@@ -1767,17 +920,20 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
if (flags & MIDX_PROGRESS)
progress = start_sparse_progress(_("Verifying OID order in multi-pack-index"),
m->num_objects - 1);
- for (i = 0; i < m->num_objects - 1; i++) {
- struct object_id oid1, oid2;
- nth_midxed_object_oid(&oid1, m, i);
- nth_midxed_object_oid(&oid2, m, i + 1);
+ for (curr = m; curr; curr = curr->base_midx) {
+ for (i = 0; i < m->num_objects - 1; i++) {
+ struct object_id oid1, oid2;
- if (oidcmp(&oid1, &oid2) >= 0)
- midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
- i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+ nth_midxed_object_oid(&oid1, m, m->num_objects_in_base + i);
+ nth_midxed_object_oid(&oid2, m, m->num_objects_in_base + i + 1);
- midx_display_sparse_progress(progress, i + 1);
+ if (oidcmp(&oid1, &oid2) >= 0)
+ midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
+ i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+
+ midx_display_sparse_progress(progress, i + 1);
+ }
}
stop_progress(&progress);
@@ -1787,8 +943,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
* each of the objects and only require 1 packfile to be open at a
* time.
*/
- ALLOC_ARRAY(pairs, m->num_objects);
- for (i = 0; i < m->num_objects; i++) {
+ ALLOC_ARRAY(pairs, m->num_objects + m->num_objects_in_base);
+ for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
pairs[i].pos = i;
pairs[i].pack_int_id = nth_midxed_pack_int_id(m, i);
}
@@ -1802,16 +958,18 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
if (flags & MIDX_PROGRESS)
progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects);
- for (i = 0; i < m->num_objects; i++) {
+ for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
struct object_id oid;
struct pack_entry e;
off_t m_offset, p_offset;
if (i > 0 && pairs[i-1].pack_int_id != pairs[i].pack_int_id &&
- m->packs[pairs[i-1].pack_int_id])
- {
- close_pack_fd(m->packs[pairs[i-1].pack_int_id]);
- close_pack_index(m->packs[pairs[i-1].pack_int_id]);
+ nth_midxed_pack(m, pairs[i-1].pack_int_id)) {
+ uint32_t pack_int_id = pairs[i-1].pack_int_id;
+ struct packed_git *p = nth_midxed_pack(m, pack_int_id);
+
+ close_pack_fd(p);
+ close_pack_index(p);
}
nth_midxed_object_oid(&oid, m, pairs[i].pos);
@@ -1829,7 +987,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
}
m_offset = e.offset;
- p_offset = find_pack_entry_one(oid.hash, e.p);
+ p_offset = find_pack_entry_one(&oid, e.p);
if (m_offset != p_offset)
midx_report(_("incorrect object offset for oid[%d] = %s: %"PRIx64" != %"PRIx64),
@@ -1845,256 +1003,3 @@ cleanup:
return verify_midx_error;
}
-
-int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags)
-{
- uint32_t i, *count, result = 0;
- struct string_list packs_to_drop = STRING_LIST_INIT_DUP;
- struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
- struct progress *progress = NULL;
-
- if (!m)
- return 0;
-
- CALLOC_ARRAY(count, m->num_packs);
-
- if (flags & MIDX_PROGRESS)
- progress = start_delayed_progress(_("Counting referenced objects"),
- m->num_objects);
- for (i = 0; i < m->num_objects; i++) {
- int pack_int_id = nth_midxed_pack_int_id(m, i);
- count[pack_int_id]++;
- display_progress(progress, i + 1);
- }
- stop_progress(&progress);
-
- if (flags & MIDX_PROGRESS)
- progress = start_delayed_progress(_("Finding and deleting unreferenced packfiles"),
- m->num_packs);
- for (i = 0; i < m->num_packs; i++) {
- char *pack_name;
- display_progress(progress, i + 1);
-
- if (count[i])
- continue;
-
- if (prepare_midx_pack(r, m, i))
- continue;
-
- if (m->packs[i]->pack_keep || m->packs[i]->is_cruft)
- continue;
-
- pack_name = xstrdup(m->packs[i]->pack_name);
- close_pack(m->packs[i]);
-
- string_list_insert(&packs_to_drop, m->pack_names[i]);
- unlink_pack_path(pack_name, 0);
- free(pack_name);
- }
- stop_progress(&progress);
-
- free(count);
-
- if (packs_to_drop.nr)
- result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags);
-
- string_list_clear(&packs_to_drop, 0);
-
- return result;
-}
-
-struct repack_info {
- timestamp_t mtime;
- uint32_t referenced_objects;
- uint32_t pack_int_id;
-};
-
-static int compare_by_mtime(const void *a_, const void *b_)
-{
- const struct repack_info *a, *b;
-
- a = (const struct repack_info *)a_;
- b = (const struct repack_info *)b_;
-
- if (a->mtime < b->mtime)
- return -1;
- if (a->mtime > b->mtime)
- return 1;
- return 0;
-}
-
-static int fill_included_packs_all(struct repository *r,
- struct multi_pack_index *m,
- unsigned char *include_pack)
-{
- uint32_t i, count = 0;
- int pack_kept_objects = 0;
-
- repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
-
- for (i = 0; i < m->num_packs; i++) {
- if (prepare_midx_pack(r, m, i))
- continue;
- if (!pack_kept_objects && m->packs[i]->pack_keep)
- continue;
- if (m->packs[i]->is_cruft)
- continue;
-
- include_pack[i] = 1;
- count++;
- }
-
- return count < 2;
-}
-
-static int fill_included_packs_batch(struct repository *r,
- struct multi_pack_index *m,
- unsigned char *include_pack,
- size_t batch_size)
-{
- uint32_t i, packs_to_repack;
- size_t total_size;
- struct repack_info *pack_info;
- int pack_kept_objects = 0;
-
- CALLOC_ARRAY(pack_info, m->num_packs);
-
- repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
-
- for (i = 0; i < m->num_packs; i++) {
- pack_info[i].pack_int_id = i;
-
- if (prepare_midx_pack(r, m, i))
- continue;
-
- pack_info[i].mtime = m->packs[i]->mtime;
- }
-
- for (i = 0; i < m->num_objects; i++) {
- uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
- pack_info[pack_int_id].referenced_objects++;
- }
-
- QSORT(pack_info, m->num_packs, compare_by_mtime);
-
- total_size = 0;
- packs_to_repack = 0;
- for (i = 0; total_size < batch_size && i < m->num_packs; i++) {
- int pack_int_id = pack_info[i].pack_int_id;
- struct packed_git *p = m->packs[pack_int_id];
- size_t expected_size;
-
- if (!p)
- continue;
- if (!pack_kept_objects && p->pack_keep)
- continue;
- if (p->is_cruft)
- continue;
- if (open_pack_index(p) || !p->num_objects)
- continue;
-
- expected_size = st_mult(p->pack_size,
- pack_info[i].referenced_objects);
- expected_size /= p->num_objects;
-
- if (expected_size >= batch_size)
- continue;
-
- packs_to_repack++;
- total_size += expected_size;
- include_pack[pack_int_id] = 1;
- }
-
- free(pack_info);
-
- if (packs_to_repack < 2)
- return 1;
-
- return 0;
-}
-
-int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, unsigned flags)
-{
- int result = 0;
- uint32_t i;
- unsigned char *include_pack;
- struct child_process cmd = CHILD_PROCESS_INIT;
- FILE *cmd_in;
- struct strbuf base_name = STRBUF_INIT;
- struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
-
- /*
- * When updating the default for these configuration
- * variables in builtin/repack.c, these must be adjusted
- * to match.
- */
- int delta_base_offset = 1;
- int use_delta_islands = 0;
-
- if (!m)
- return 0;
-
- CALLOC_ARRAY(include_pack, m->num_packs);
-
- if (batch_size) {
- if (fill_included_packs_batch(r, m, include_pack, batch_size))
- goto cleanup;
- } else if (fill_included_packs_all(r, m, include_pack))
- goto cleanup;
-
- repo_config_get_bool(r, "repack.usedeltabaseoffset", &delta_base_offset);
- repo_config_get_bool(r, "repack.usedeltaislands", &use_delta_islands);
-
- strvec_push(&cmd.args, "pack-objects");
-
- strbuf_addstr(&base_name, object_dir);
- strbuf_addstr(&base_name, "/pack/pack");
- strvec_push(&cmd.args, base_name.buf);
-
- if (delta_base_offset)
- strvec_push(&cmd.args, "--delta-base-offset");
- if (use_delta_islands)
- strvec_push(&cmd.args, "--delta-islands");
-
- if (flags & MIDX_PROGRESS)
- strvec_push(&cmd.args, "--progress");
- else
- strvec_push(&cmd.args, "-q");
-
- strbuf_release(&base_name);
-
- cmd.git_cmd = 1;
- cmd.in = cmd.out = -1;
-
- if (start_command(&cmd)) {
- error(_("could not start pack-objects"));
- result = 1;
- goto cleanup;
- }
-
- cmd_in = xfdopen(cmd.in, "w");
-
- for (i = 0; i < m->num_objects; i++) {
- struct object_id oid;
- uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
-
- if (!include_pack[pack_int_id])
- continue;
-
- nth_midxed_object_oid(&oid, m, i);
- fprintf(cmd_in, "%s\n", oid_to_hex(&oid));
- }
- fclose(cmd_in);
-
- if (finish_command(&cmd)) {
- error(_("could not finish pack-objects"));
- result = 1;
- goto cleanup;
- }
-
- result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags);
-
-cleanup:
- free(include_pack);
- return result;
-}
diff --git a/midx.h b/midx.h
index 5578cd7b83..42d4f8d149 100644
--- a/midx.h
+++ b/midx.h
@@ -1,16 +1,36 @@
#ifndef MIDX_H
#define MIDX_H
-#include "repository.h"
#include "string-list.h"
struct object_id;
struct pack_entry;
struct repository;
+struct bitmapped_pack;
+
+#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
+#define MIDX_VERSION 1
+#define MIDX_BYTE_FILE_VERSION 4
+#define MIDX_BYTE_HASH_VERSION 5
+#define MIDX_BYTE_NUM_CHUNKS 6
+#define MIDX_BYTE_NUM_PACKS 8
+#define MIDX_HEADER_SIZE 12
+
+#define MIDX_CHUNK_ALIGNMENT 4
+#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
+#define MIDX_CHUNKID_BITMAPPEDPACKS 0x42544d50 /* "BTMP" */
+#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
+#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
+#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
+#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
+#define MIDX_CHUNKID_REVINDEX 0x52494458 /* "RIDX" */
+#define MIDX_CHUNKID_BASE 0x42415345 /* "BASE" */
+#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
+#define MIDX_LARGE_OFFSET_NEEDED 0x80000000
#define GIT_TEST_MULTI_PACK_INDEX "GIT_TEST_MULTI_PACK_INDEX"
-#define GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP \
- "GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP"
+#define GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL \
+ "GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL"
struct multi_pack_index {
struct multi_pack_index *next;
@@ -28,15 +48,26 @@ struct multi_pack_index {
unsigned char num_chunks;
uint32_t num_packs;
uint32_t num_objects;
+ int preferred_pack_idx;
int local;
+ int has_chain;
const unsigned char *chunk_pack_names;
+ size_t chunk_pack_names_len;
+ const uint32_t *chunk_bitmapped_packs;
+ size_t chunk_bitmapped_packs_len;
const uint32_t *chunk_oid_fanout;
const unsigned char *chunk_oid_lookup;
const unsigned char *chunk_object_offsets;
const unsigned char *chunk_large_offsets;
+ size_t chunk_large_offsets_len;
const unsigned char *chunk_revindex;
+ size_t chunk_revindex_len;
+
+ struct multi_pack_index *base_midx;
+ uint32_t num_objects_in_base;
+ uint32_t num_packs_in_base;
const char **pack_names;
struct packed_git **packs;
@@ -48,21 +79,41 @@ struct multi_pack_index {
#define MIDX_WRITE_BITMAP (1 << 2)
#define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3)
#define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)
+#define MIDX_WRITE_INCREMENTAL (1 << 5)
+
+#define MIDX_EXT_REV "rev"
+#define MIDX_EXT_BITMAP "bitmap"
+#define MIDX_EXT_MIDX "midx"
const unsigned char *get_midx_checksum(struct multi_pack_index *m);
void get_midx_filename(struct strbuf *out, const char *object_dir);
-void get_midx_rev_filename(struct strbuf *out, struct multi_pack_index *m);
+void get_midx_filename_ext(struct strbuf *out, const char *object_dir,
+ const unsigned char *hash, const char *ext);
+void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir);
+void get_midx_chain_filename(struct strbuf *buf, const char *object_dir);
+void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+ const unsigned char *hash, const char *ext);
struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local);
int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id);
-int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result);
+struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
+ uint32_t pack_int_id);
+int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
+ struct bitmapped_pack *bp, uint32_t pack_int_id);
+int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result);
+int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result);
+int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid);
off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos);
uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos);
struct object_id *nth_midxed_object_oid(struct object_id *oid,
struct multi_pack_index *m,
uint32_t n);
int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m);
-int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name);
+int midx_contains_pack(struct multi_pack_index *m,
+ const char *idx_or_pack_name);
+int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id);
int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local);
/*
diff --git a/name-hash.c b/name-hash.c
index 251f036eef..95528e3bcd 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -5,6 +5,9 @@
*
* Copyright (C) 2008 Linus Torvalds
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@@ -685,13 +688,20 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen
return slow_same_name(name, namelen, ce->name, len);
}
-int index_dir_exists(struct index_state *istate, const char *name, int namelen)
+int index_dir_find(struct index_state *istate, const char *name, int namelen,
+ struct strbuf *canonical_path)
{
struct dir_entry *dir;
lazy_init_name_hash(istate);
expand_to_path(istate, name, namelen, 0);
dir = find_dir_entry(istate, name, namelen);
+
+ if (canonical_path && dir && dir->nr) {
+ strbuf_reset(canonical_path);
+ strbuf_add(canonical_path, dir->name, dir->namelen);
+ }
+
return dir && dir->nr;
}
diff --git a/name-hash.h b/name-hash.h
index b1b4b0fb33..0cbfc42863 100644
--- a/name-hash.h
+++ b/name-hash.h
@@ -4,7 +4,12 @@
struct cache_entry;
struct index_state;
-int index_dir_exists(struct index_state *istate, const char *name, int namelen);
+
+int index_dir_find(struct index_state *istate, const char *name, int namelen,
+ struct strbuf *canonical_path);
+
+#define index_dir_exists(i, n, l) index_dir_find((i), (n), (l), NULL)
+
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);
diff --git a/negotiator/default.c b/negotiator/default.c
index 9a5b696327..c479da9b09 100644
--- a/negotiator/default.c
+++ b/negotiator/default.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "default.h"
#include "../commit.h"
@@ -36,7 +38,7 @@ static void rev_list_push(struct negotiation_state *ns,
}
}
-static int clear_marks(const char *refname, const struct object_id *oid,
+static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
{
@@ -192,6 +194,7 @@ void default_negotiator_init(struct fetch_negotiator *negotiator)
ns->rev_list.compare = compare_commits_by_commit_date;
if (marked)
- for_each_ref(clear_marks, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ clear_marks, NULL);
marked = 1;
}
diff --git a/negotiator/noop.c b/negotiator/noop.c
index 7b72937686..65e3c20008 100644
--- a/negotiator/noop.c
+++ b/negotiator/noop.c
@@ -1,24 +1,25 @@
#include "git-compat-util.h"
#include "noop.h"
-#include "../commit.h"
#include "../fetch-negotiator.h"
-static void known_common(struct fetch_negotiator *n, struct commit *c)
+static void known_common(struct fetch_negotiator *n UNUSED,
+ struct commit *c UNUSED)
{
/* do nothing */
}
-static void add_tip(struct fetch_negotiator *n, struct commit *c)
+static void add_tip(struct fetch_negotiator *n UNUSED,
+ struct commit *c UNUSED)
{
/* do nothing */
}
-static const struct object_id *next(struct fetch_negotiator *n)
+static const struct object_id *next(struct fetch_negotiator *n UNUSED)
{
return NULL;
}
-static int ack(struct fetch_negotiator *n, struct commit *c)
+static int ack(struct fetch_negotiator *n UNUSED, struct commit *c UNUSED)
{
/*
* This negotiator does not emit any commits, so there is no commit to
@@ -28,7 +29,7 @@ static int ack(struct fetch_negotiator *n, struct commit *c)
return 0;
}
-static void release(struct fetch_negotiator *n)
+static void release(struct fetch_negotiator *n UNUSED)
{
/* nothing to release */
}
diff --git a/negotiator/skipping.c b/negotiator/skipping.c
index 5b91520430..abedb70a48 100644
--- a/negotiator/skipping.c
+++ b/negotiator/skipping.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "skipping.h"
#include "../commit.h"
@@ -73,7 +75,7 @@ static struct entry *rev_list_push(struct data *data, struct commit *commit, int
return entry;
}
-static int clear_marks(const char *refname, const struct object_id *oid,
+static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
{
@@ -237,7 +239,7 @@ static int ack(struct fetch_negotiator *n, struct commit *c)
{
int known_to_be_common = !!(c->object.flags & COMMON);
if (!(c->object.flags & SEEN))
- die("received ack for commit %s not sent as 'have'\n",
+ die("received ack for commit %s not sent as 'have'",
oid_to_hex(&c->object.oid));
mark_common(n->data, c);
return known_to_be_common;
@@ -245,8 +247,11 @@ static int ack(struct fetch_negotiator *n, struct commit *c)
static void release(struct fetch_negotiator *n)
{
- clear_prio_queue(&((struct data *)n->data)->rev_list);
- FREE_AND_NULL(n->data);
+ struct data *data = n->data;
+ for (int i = 0; i < data->rev_list.nr; i++)
+ free(data->rev_list.array[i].data);
+ clear_prio_queue(&data->rev_list);
+ FREE_AND_NULL(data);
}
void skipping_negotiator_init(struct fetch_negotiator *negotiator)
@@ -261,6 +266,7 @@ void skipping_negotiator_init(struct fetch_negotiator *negotiator)
data->rev_list.compare = compare;
if (marked)
- for_each_ref(clear_marks, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ clear_marks, NULL);
marked = 1;
}
diff --git a/notes-cache.c b/notes-cache.c
index 0e1d5b1ac7..ecfdf6e43b 100644
--- a/notes-cache.c
+++ b/notes-cache.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "notes-cache.h"
#include "object-store-ll.h"
@@ -17,7 +19,7 @@ static int notes_cache_match_validity(struct repository *r,
struct strbuf msg = STRBUF_INIT;
int ret;
- if (read_ref(ref, &oid) < 0)
+ if (refs_read_ref(get_main_ref_store(the_repository), ref, &oid) < 0)
return 0;
commit = lookup_commit_reference_gently(r, &oid, 1);
@@ -66,8 +68,8 @@ int notes_cache_write(struct notes_cache *c)
if (commit_tree(c->validity, strlen(c->validity), &tree_oid, NULL,
&commit_oid, NULL, NULL) < 0)
return -1;
- if (update_ref("update notes cache", c->tree.update_ref, &commit_oid,
- NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0)
+ if (refs_update_ref(get_main_ref_store(the_repository), "update notes cache", c->tree.update_ref, &commit_oid,
+ NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0)
return -1;
return 0;
diff --git a/notes-merge.c b/notes-merge.c
index 8799b522a5..dadbbabf86 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "commit.h"
@@ -240,7 +242,7 @@ static void diff_tree_local(struct notes_merge_options *o,
* (will be overwritten by following addition)
*/
if (oideq(&mp->local, &uninitialized))
- oidclr(&mp->local);
+ oidclr(&mp->local, the_repository->hash_algo);
} else if (is_null_oid(&p->one->oid)) { /* addition */
/*
* Either this is a true addition (1), or it is part
@@ -556,13 +558,13 @@ int notes_merge(struct notes_merge_options *o,
assert(o->local_ref && o->remote_ref);
assert(!strcmp(o->local_ref, local_tree->ref));
- oidclr(result_oid);
+ oidclr(result_oid, the_repository->hash_algo);
trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
o->local_ref, o->remote_ref);
/* Dereference o->local_ref into local_sha1 */
- if (read_ref_full(o->local_ref, 0, &local_oid, NULL))
+ if (refs_read_ref_full(get_main_ref_store(the_repository), o->local_ref, 0, &local_oid, NULL))
die("Failed to resolve local notes ref '%s'", o->local_ref);
else if (!check_refname_format(o->local_ref, 0) &&
is_null_oid(&local_oid))
@@ -579,7 +581,7 @@ int notes_merge(struct notes_merge_options *o,
* unborn ref, perform the merge using an empty notes tree.
*/
if (!check_refname_format(o->remote_ref, 0)) {
- oidclr(&remote_oid);
+ oidclr(&remote_oid, the_repository->hash_algo);
remote = NULL;
} else {
die("Failed to resolve remote notes ref '%s'",
@@ -607,7 +609,8 @@ int notes_merge(struct notes_merge_options *o,
assert(local && remote);
/* Find merge bases */
- bases = repo_get_merge_bases(the_repository, local, remote);
+ if (repo_get_merge_bases(the_repository, local, remote, &bases) < 0)
+ exit(128);
if (!bases) {
base_oid = null_oid();
base_tree_oid = the_hash_algo->empty_tree;
@@ -660,6 +663,7 @@ int notes_merge(struct notes_merge_options *o,
commit_list_insert(local, &parents);
create_notes_commit(o->repo, local_tree, parents, o->commit_msg.buf,
o->commit_msg.len, result_oid);
+ free_commit_list(parents);
}
found_result:
diff --git a/notes-utils.c b/notes-utils.c
index 97c031c26e..ac66b82dd3 100644
--- a/notes-utils.c
+++ b/notes-utils.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
@@ -5,15 +7,15 @@
#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,
- struct commit_list *parents,
+ const struct commit_list *parents,
const char *msg, size_t msg_len,
struct object_id *result_oid)
{
+ struct commit_list *parents_to_free = NULL;
struct object_id tree_oid;
assert(t->initialized);
@@ -24,11 +26,12 @@ void create_notes_commit(struct repository *r,
if (!parents) {
/* Deduce parent commit from t->ref */
struct object_id parent_oid;
- if (!read_ref(t->ref, &parent_oid)) {
+ if (!refs_read_ref(get_main_ref_store(the_repository), t->ref, &parent_oid)) {
struct commit *parent = lookup_commit(r, &parent_oid);
if (repo_parse_commit(r, parent))
die("Failed to find/parse commit %s", t->ref);
- commit_list_insert(parent, &parents);
+ commit_list_insert(parent, &parents_to_free);
+ parents = parents_to_free;
}
/* else: t->ref points to nothing, assume root/orphan commit */
}
@@ -36,6 +39,8 @@ void create_notes_commit(struct repository *r,
if (commit_tree(msg, msg_len, &tree_oid, parents, result_oid, NULL,
NULL))
die("Failed to commit notes tree to database");
+
+ free_commit_list(parents_to_free);
}
void commit_notes(struct repository *r, struct notes_tree *t, const char *msg)
@@ -56,8 +61,9 @@ void commit_notes(struct repository *r, struct notes_tree *t, const char *msg)
create_notes_commit(r, t, NULL, buf.buf, buf.len, &commit_oid);
strbuf_insertstr(&buf, 0, "notes: ");
- update_ref(buf.buf, t->update_ref, &commit_oid, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository), buf.buf,
+ t->update_ref, &commit_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
strbuf_release(&buf);
}
@@ -112,6 +118,8 @@ static int notes_rewrite_config(const char *k, const char *v,
}
return 0;
} else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) {
+ if (!v)
+ return config_error_nonbool(k);
/* note that a refs/ prefix is implied in the
* underlying for_each_glob_ref */
if (starts_with(v, "refs/notes/"))
@@ -185,6 +193,7 @@ void finish_copy_notes_for_rewrite(struct repository *r,
for (i = 0; c->trees[i]; i++) {
commit_notes(r, c->trees[i], msg);
free_notes(c->trees[i]);
+ free(c->trees[i]);
}
free(c->trees);
free(c);
diff --git a/notes-utils.h b/notes-utils.h
index d9b3c09eaf..c54b1fe141 100644
--- a/notes-utils.h
+++ b/notes-utils.h
@@ -20,7 +20,7 @@ struct repository;
*/
void create_notes_commit(struct repository *r,
struct notes_tree *t,
- struct commit_list *parents,
+ const struct commit_list *parents,
const char *msg, size_t msg_len,
struct object_id *result_oid);
diff --git a/notes.c b/notes.c
index 1ef2a331ce..f4f18daf07 100644
--- a/notes.c
+++ b/notes.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -5,8 +7,6 @@
#include "notes.h"
#include "object-name.h"
#include "object-store-ll.h"
-#include "blob.h"
-#include "tree.h"
#include "utf8.h"
#include "strbuf.h"
#include "tree-walk.h"
@@ -151,7 +151,7 @@ static struct leaf_node *note_tree_find(struct notes_tree *t,
void **p = note_tree_search(t, &tree, &n, key_sha1);
if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) {
struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p);
- if (hasheq(key_sha1, l->key_oid.hash))
+ if (hasheq(key_sha1, l->key_oid.hash, the_repository->hash_algo))
return l;
}
return NULL;
@@ -355,7 +355,7 @@ static void add_non_note(struct notes_tree *t, char *path,
n->next = NULL;
n->path = path;
n->mode = mode;
- oidread(&n->oid, sha1);
+ oidread(&n->oid, sha1, the_repository->hash_algo);
t->prev_non_note = n;
if (!t->first_non_note) {
@@ -429,6 +429,8 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
hashsz - prefix_len))
goto handle_non_note; /* entry.path is not a SHA1 */
+ memset(object_oid.hash + hashsz, 0, GIT_MAX_RAWSZ - hashsz);
+
type = PTR_TYPE_NOTE;
} else if (path_len == 2) {
/* This is potentially an internal node */
@@ -930,7 +932,7 @@ out:
return ret;
}
-static int string_list_add_one_ref(const char *refname,
+static int string_list_add_one_ref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cb)
{
@@ -947,7 +949,8 @@ void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
{
assert(list->strdup_strings);
if (has_glob_specials(glob)) {
- for_each_glob_ref(string_list_add_one_ref, glob, list);
+ refs_for_each_glob_ref(get_main_ref_store(the_repository),
+ string_list_add_one_ref, glob, list);
} else {
struct object_id oid;
if (repo_get_oid(the_repository, glob, &oid))
@@ -989,15 +992,16 @@ static int notes_display_config(const char *k, const char *v,
return 0;
}
-const char *default_notes_ref(void)
+char *default_notes_ref(struct repository *repo)
{
- const char *notes_ref = NULL;
+ char *notes_ref = NULL;
+
if (!notes_ref)
- notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);
+ notes_ref = xstrdup_or_null(getenv(GIT_NOTES_REF_ENVIRONMENT));
if (!notes_ref)
- notes_ref = notes_ref_name; /* value of core.notesRef config */
+ repo_config_get_string(repo, "core.notesref", &notes_ref);
if (!notes_ref)
- notes_ref = GIT_NOTES_DEFAULT_REF;
+ notes_ref = xstrdup(GIT_NOTES_DEFAULT_REF);
return notes_ref;
}
@@ -1007,13 +1011,14 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
struct object_id oid, object_oid;
unsigned short mode;
struct leaf_node root_tree;
+ char *to_free = NULL;
if (!t)
t = &default_notes_tree;
assert(!t->initialized);
if (!notes_ref)
- notes_ref = default_notes_ref();
+ notes_ref = to_free = default_notes_ref(the_repository);
update_ref_namespace(NAMESPACE_NOTES, xstrdup(notes_ref));
if (!combine_notes)
@@ -1030,16 +1035,19 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
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))
+ goto out;
+ if (flags & NOTES_INIT_WRITABLE && refs_read_ref(get_main_ref_store(the_repository), notes_ref, &object_oid))
die("Cannot use notes ref %s", notes_ref);
if (get_tree_entry(the_repository, &object_oid, "", &oid, &mode))
die("Failed to read notes tree referenced by %s (%s)",
notes_ref, oid_to_hex(&object_oid));
- oidclr(&root_tree.key_oid);
+ oidclr(&root_tree.key_oid, the_repository->hash_algo);
oidcpy(&root_tree.val_oid, &oid);
load_subtree(t, &root_tree, t->root, 0);
+
+out:
+ free(to_free);
}
struct notes_tree **load_notes_trees(struct string_list *refs, int flags)
@@ -1061,6 +1069,12 @@ void init_display_notes(struct display_notes_opt *opt)
{
memset(opt, 0, sizeof(*opt));
opt->use_default_notes = -1;
+ string_list_init_dup(&opt->extra_notes_refs);
+}
+
+void release_display_notes(struct display_notes_opt *opt)
+{
+ string_list_clear(&opt->extra_notes_refs, 0);
}
void enable_default_display_notes(struct display_notes_opt *opt, int *show_notes)
@@ -1074,19 +1088,15 @@ void enable_ref_display_notes(struct display_notes_opt *opt, int *show_notes,
struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, ref);
expand_notes_ref(&buf);
- string_list_append(&opt->extra_notes_refs,
- strbuf_detach(&buf, NULL));
+ string_list_append_nodup(&opt->extra_notes_refs,
+ strbuf_detach(&buf, NULL));
*show_notes = 1;
}
void disable_display_notes(struct display_notes_opt *opt, int *show_notes)
{
opt->use_default_notes = -1;
- /* we have been strdup'ing ourselves, so trick
- * string_list into free()ing strings */
- opt->extra_notes_refs.strdup_strings = 1;
string_list_clear(&opt->extra_notes_refs, 0);
- opt->extra_notes_refs.strdup_strings = 0;
*show_notes = 0;
}
@@ -1100,7 +1110,7 @@ void load_display_notes(struct display_notes_opt *opt)
if (!opt || opt->use_default_notes > 0 ||
(opt->use_default_notes == -1 && !opt->extra_notes_refs.nr)) {
- string_list_append(&display_notes_refs, default_notes_ref());
+ string_list_append_nodup(&display_notes_refs, default_notes_ref(the_repository));
display_ref_env = getenv(GIT_NOTES_DISPLAY_REF_ENVIRONMENT);
if (display_ref_env) {
string_list_add_refs_from_colon_sep(&display_notes_refs,
@@ -1147,8 +1157,8 @@ int remove_note(struct notes_tree *t, const unsigned char *object_sha1)
if (!t)
t = &default_notes_tree;
assert(t->initialized);
- oidread(&l.key_oid, object_sha1);
- oidclr(&l.val_oid);
+ oidread(&l.key_oid, object_sha1, the_repository->hash_algo);
+ oidclr(&l.val_oid, the_repository->hash_algo);
note_tree_remove(t, t->root, 0, &l);
if (is_null_oid(&l.val_oid)) /* no note was removed */
return 1;
@@ -1218,11 +1228,16 @@ void prune_notes(struct notes_tree *t, int flags)
for_each_note(t, 0, prune_notes_helper, &l);
while (l) {
+ struct note_delete_list *next;
+
if (flags & NOTES_PRUNE_VERBOSE)
printf("%s\n", hash_to_hex(l->sha1));
if (!(flags & NOTES_PRUNE_DRYRUN))
remove_note(t, l->sha1);
- l = l->next;
+
+ next = l->next;
+ free(l);
+ l = next;
}
}
diff --git a/notes.h b/notes.h
index 064fd7143a..6dc6d7b265 100644
--- a/notes.h
+++ b/notes.h
@@ -4,6 +4,7 @@
#include "string-list.h"
struct object_id;
+struct repository;
struct strbuf;
/*
@@ -70,7 +71,7 @@ extern struct notes_tree {
* 3. The value of the core.notesRef config variable, if set
* 4. GIT_NOTES_DEFAULT_REF (i.e. "refs/notes/commits")
*/
-const char *default_notes_ref(void);
+char *default_notes_ref(struct repository *repo);
/*
* Flags controlling behaviour of notes tree initialization
@@ -276,6 +277,11 @@ struct display_notes_opt {
void init_display_notes(struct display_notes_opt *opt);
/*
+ * Release resources acquired by the display_notes_opt.
+ */
+void release_display_notes(struct display_notes_opt *opt);
+
+/*
* This family of functions enables or disables the display of notes. In
* particular, 'enable_default_display_notes' will display the default notes,
* 'enable_ref_display_notes' will display the notes ref 'ref' and
diff --git a/object-file-convert.c b/object-file-convert.c
new file mode 100644
index 0000000000..3887d6d57b
--- /dev/null
+++ b/object-file-convert.c
@@ -0,0 +1,279 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "strbuf.h"
+#include "hex.h"
+#include "repository.h"
+#include "hash.h"
+#include "hash.h"
+#include "object.h"
+#include "loose.h"
+#include "commit.h"
+#include "gpg-interface.h"
+#include "object-file-convert.h"
+
+int repo_oid_to_algop(struct repository *repo, const struct object_id *src,
+ const struct git_hash_algo *to, struct object_id *dest)
+{
+ /*
+ * If the source algorithm is not set, then we're using the
+ * default hash algorithm for that object.
+ */
+ const struct git_hash_algo *from =
+ src->algo ? &hash_algos[src->algo] : repo->hash_algo;
+
+ if (from == to) {
+ if (src != dest)
+ oidcpy(dest, src);
+ return 0;
+ }
+ if (repo_loose_object_map_oid(repo, src, to, dest)) {
+ /*
+ * We may have loaded the object map at repo initialization but
+ * another process (perhaps upstream of a pipe from us) may have
+ * written a new object into the map. If the object is missing,
+ * let's reload the map to see if the object has appeared.
+ */
+ repo_read_loose_object_map(repo);
+ if (repo_loose_object_map_oid(repo, src, to, dest))
+ return -1;
+ }
+ return 0;
+}
+
+static int decode_tree_entry_raw(struct object_id *oid, const char **path,
+ size_t *len, const struct git_hash_algo *algo,
+ const char *buf, unsigned long size)
+{
+ uint16_t mode;
+ const unsigned hashsz = algo->rawsz;
+
+ if (size < hashsz + 3 || buf[size - (hashsz + 1)]) {
+ return -1;
+ }
+
+ *path = parse_mode(buf, &mode);
+ if (!*path || !**path)
+ return -1;
+ *len = strlen(*path) + 1;
+
+ oidread(oid, (const unsigned char *)*path + *len, algo);
+ return 0;
+}
+
+static int convert_tree_object(struct strbuf *out,
+ const struct git_hash_algo *from,
+ const struct git_hash_algo *to,
+ const char *buffer, size_t size)
+{
+ const char *p = buffer, *end = buffer + size;
+
+ while (p < end) {
+ struct object_id entry_oid, mapped_oid;
+ const char *path = NULL;
+ size_t pathlen;
+
+ if (decode_tree_entry_raw(&entry_oid, &path, &pathlen, from, p,
+ end - p))
+ return error(_("failed to decode tree entry"));
+ if (repo_oid_to_algop(the_repository, &entry_oid, to, &mapped_oid))
+ return error(_("failed to map tree entry for %s"), oid_to_hex(&entry_oid));
+ strbuf_add(out, p, path - p);
+ strbuf_add(out, path, pathlen);
+ strbuf_add(out, mapped_oid.hash, to->rawsz);
+ p = path + pathlen + from->rawsz;
+ }
+ return 0;
+}
+
+static int convert_tag_object(struct strbuf *out,
+ const struct git_hash_algo *from,
+ const struct git_hash_algo *to,
+ const char *buffer, size_t size)
+{
+ struct strbuf payload = STRBUF_INIT, oursig = STRBUF_INIT, othersig = STRBUF_INIT;
+ const int entry_len = from->hexsz + 7;
+ size_t payload_size;
+ struct object_id oid, mapped_oid;
+ const char *p;
+
+ /* Consume the object line */
+ if ((entry_len >= size) ||
+ memcmp(buffer, "object ", 7) || buffer[entry_len] != '\n')
+ return error("bogus tag object");
+ if (parse_oid_hex_algop(buffer + 7, &oid, &p, from) < 0)
+ return error("bad tag object ID");
+ if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
+ return error("unable to map tree %s in tag object",
+ oid_to_hex(&oid));
+ size -= ((p + 1) - buffer);
+ buffer = p + 1;
+
+ /* Is there a signature for our algorithm? */
+ payload_size = parse_signed_buffer(buffer, size);
+ if (payload_size != size) {
+ /* Yes, there is. */
+ strbuf_add(&oursig, buffer + payload_size, size - payload_size);
+ }
+
+ /* Now, is there a signature for the other algorithm? */
+ parse_buffer_signed_by_header(buffer, payload_size, &payload, &othersig, to);
+ /*
+ * Our payload is now in payload and we may have up to two signatrures
+ * in oursig and othersig.
+ */
+
+ /* Add some slop for longer signature header in the new algorithm. */
+ strbuf_grow(out, (7 + to->hexsz + 1) + size + 7);
+ strbuf_addf(out, "object %s\n", oid_to_hex(&mapped_oid));
+ strbuf_addbuf(out, &payload);
+ if (oursig.len)
+ add_header_signature(out, &oursig, from);
+ strbuf_addbuf(out, &othersig);
+
+ strbuf_release(&payload);
+ strbuf_release(&othersig);
+ strbuf_release(&oursig);
+ return 0;
+}
+
+static int convert_commit_object(struct strbuf *out,
+ const struct git_hash_algo *from,
+ const struct git_hash_algo *to,
+ const char *buffer, size_t size)
+{
+ const char *tail = buffer;
+ const char *bufptr = buffer;
+ const int tree_entry_len = from->hexsz + 5;
+ const int parent_entry_len = from->hexsz + 7;
+ struct object_id oid, mapped_oid;
+ const char *p, *eol;
+
+ tail += size;
+
+ while ((bufptr < tail) && (*bufptr != '\n')) {
+ eol = memchr(bufptr, '\n', tail - bufptr);
+ if (!eol)
+ return error(_("bad %s in commit"), "line");
+
+ if (((bufptr + 5) < eol) && !memcmp(bufptr, "tree ", 5))
+ {
+ if (((bufptr + tree_entry_len) != eol) ||
+ parse_oid_hex_algop(bufptr + 5, &oid, &p, from) ||
+ (p != eol))
+ return error(_("bad %s in commit"), "tree");
+
+ if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
+ return error(_("unable to map %s %s in commit object"),
+ "tree", oid_to_hex(&oid));
+ strbuf_addf(out, "tree %s\n", oid_to_hex(&mapped_oid));
+ }
+ else if (((bufptr + 7) < eol) && !memcmp(bufptr, "parent ", 7))
+ {
+ if (((bufptr + parent_entry_len) != eol) ||
+ parse_oid_hex_algop(bufptr + 7, &oid, &p, from) ||
+ (p != eol))
+ return error(_("bad %s in commit"), "parent");
+
+ if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
+ return error(_("unable to map %s %s in commit object"),
+ "parent", oid_to_hex(&oid));
+
+ strbuf_addf(out, "parent %s\n", oid_to_hex(&mapped_oid));
+ }
+ else if (((bufptr + 9) < eol) && !memcmp(bufptr, "mergetag ", 9))
+ {
+ struct strbuf tag = STRBUF_INIT, new_tag = STRBUF_INIT;
+
+ /* Recover the tag object from the mergetag */
+ strbuf_add(&tag, bufptr + 9, (eol - (bufptr + 9)) + 1);
+
+ bufptr = eol + 1;
+ while ((bufptr < tail) && (*bufptr == ' ')) {
+ eol = memchr(bufptr, '\n', tail - bufptr);
+ if (!eol) {
+ strbuf_release(&tag);
+ return error(_("bad %s in commit"), "mergetag continuation");
+ }
+ strbuf_add(&tag, bufptr + 1, (eol - (bufptr + 1)) + 1);
+ bufptr = eol + 1;
+ }
+
+ /* Compute the new tag object */
+ if (convert_tag_object(&new_tag, from, to, tag.buf, tag.len)) {
+ strbuf_release(&tag);
+ strbuf_release(&new_tag);
+ return -1;
+ }
+
+ /* Write the new mergetag */
+ strbuf_addstr(out, "mergetag");
+ strbuf_add_lines(out, " ", new_tag.buf, new_tag.len);
+ strbuf_release(&tag);
+ strbuf_release(&new_tag);
+ }
+ else if (((bufptr + 7) < tail) && !memcmp(bufptr, "author ", 7))
+ strbuf_add(out, bufptr, (eol - bufptr) + 1);
+ else if (((bufptr + 10) < tail) && !memcmp(bufptr, "committer ", 10))
+ strbuf_add(out, bufptr, (eol - bufptr) + 1);
+ else if (((bufptr + 9) < tail) && !memcmp(bufptr, "encoding ", 9))
+ strbuf_add(out, bufptr, (eol - bufptr) + 1);
+ else if (((bufptr + 6) < tail) && !memcmp(bufptr, "gpgsig", 6))
+ strbuf_add(out, bufptr, (eol - bufptr) + 1);
+ else {
+ /* Unknown line fail it might embed an oid */
+ return -1;
+ }
+ /* Consume any trailing continuation lines */
+ bufptr = eol + 1;
+ while ((bufptr < tail) && (*bufptr == ' ')) {
+ eol = memchr(bufptr, '\n', tail - bufptr);
+ if (!eol)
+ return error(_("bad %s in commit"), "continuation");
+ strbuf_add(out, bufptr, (eol - bufptr) + 1);
+ bufptr = eol + 1;
+ }
+ }
+ if (bufptr < tail)
+ strbuf_add(out, bufptr, tail - bufptr);
+ return 0;
+}
+
+int convert_object_file(struct strbuf *outbuf,
+ const struct git_hash_algo *from,
+ const struct git_hash_algo *to,
+ const void *buf, size_t len,
+ enum object_type type,
+ int gentle)
+{
+ int ret;
+
+ /* Don't call this function when no conversion is necessary */
+ if ((from == to) || (type == OBJ_BLOB))
+ BUG("Refusing noop object file conversion");
+
+ switch (type) {
+ case OBJ_COMMIT:
+ ret = convert_commit_object(outbuf, from, to, buf, len);
+ break;
+ case OBJ_TREE:
+ ret = convert_tree_object(outbuf, from, to, buf, len);
+ break;
+ case OBJ_TAG:
+ ret = convert_tag_object(outbuf, from, to, buf, len);
+ break;
+ default:
+ /* Not implemented yet, so fail. */
+ ret = -1;
+ break;
+ }
+ if (!ret)
+ return 0;
+ if (gentle) {
+ strbuf_release(outbuf);
+ return ret;
+ }
+ die(_("Failed to convert object from %s to %s"),
+ from->name, to->name);
+}
diff --git a/object-file-convert.h b/object-file-convert.h
new file mode 100644
index 0000000000..a4f802aa8e
--- /dev/null
+++ b/object-file-convert.h
@@ -0,0 +1,24 @@
+#ifndef OBJECT_CONVERT_H
+#define OBJECT_CONVERT_H
+
+struct repository;
+struct object_id;
+struct git_hash_algo;
+struct strbuf;
+#include "object.h"
+
+int repo_oid_to_algop(struct repository *repo, const struct object_id *src,
+ const struct git_hash_algo *to, struct object_id *dest);
+
+/*
+ * Convert an object file from one hash algorithm to another algorithm.
+ * Return -1 on failure, 0 on success.
+ */
+int convert_object_file(struct strbuf *outbuf,
+ const struct git_hash_algo *from,
+ const struct git_hash_algo *to,
+ const void *buf, size_t len,
+ enum object_type type,
+ int gentle);
+
+#endif /* OBJECT_CONVERT_H */
diff --git a/object-file.c b/object-file.c
index 7dc0c4bfbb..891eaa2b4b 100644
--- a/object-file.c
+++ b/object-file.c
@@ -6,6 +6,9 @@
* This handles basic git object files - packing, unpacking,
* creation etc.
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
@@ -15,24 +18,16 @@
#include "hex.h"
#include "string-list.h"
#include "lockfile.h"
-#include "delta.h"
#include "pack.h"
-#include "blob.h"
#include "commit.h"
#include "run-command.h"
-#include "tag.h"
-#include "tree.h"
-#include "tree-walk.h"
#include "refs.h"
-#include "pack-revindex.h"
-#include "hash-lookup.h"
#include "bulk-checkin.h"
#include "repository.h"
#include "replace-object.h"
#include "streaming.h"
#include "dir.h"
#include "list.h"
-#include "mergesort.h"
#include "quote.h"
#include "packfile.h"
#include "object-file.h"
@@ -43,35 +38,24 @@
#include "setup.h"
#include "submodule.h"
#include "fsck.h"
+#include "loose.h"
+#include "object-file-convert.h"
/* The maximum size for an object header. */
#define MAX_HEADER_LEN 32
-
-#define EMPTY_TREE_SHA1_BIN_LITERAL \
- "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
- "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
-#define EMPTY_TREE_SHA256_BIN_LITERAL \
- "\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1" \
- "\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5" \
- "\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc" \
- "\x53\x21"
-
-#define EMPTY_BLOB_SHA1_BIN_LITERAL \
- "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
- "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
-#define EMPTY_BLOB_SHA256_BIN_LITERAL \
- "\x47\x3a\x0f\x4c\x3b\xe8\xa9\x36\x81\xa2" \
- "\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43" \
- "\x6f\xe1\x41\xf7\x74\x91\x20\xa3\x03\x72" \
- "\x18\x13"
-
static const struct object_id empty_tree_oid = {
- .hash = EMPTY_TREE_SHA1_BIN_LITERAL,
+ .hash = {
+ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
+ 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04
+ },
.algo = GIT_HASH_SHA1,
};
static const struct object_id empty_blob_oid = {
- .hash = EMPTY_BLOB_SHA1_BIN_LITERAL,
+ .hash = {
+ 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b,
+ 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91
+ },
.algo = GIT_HASH_SHA1,
};
static const struct object_id null_oid_sha1 = {
@@ -79,11 +63,21 @@ static const struct object_id null_oid_sha1 = {
.algo = GIT_HASH_SHA1,
};
static const struct object_id empty_tree_oid_sha256 = {
- .hash = EMPTY_TREE_SHA256_BIN_LITERAL,
+ .hash = {
+ 0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1,
+ 0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5,
+ 0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc,
+ 0x53, 0x21
+ },
.algo = GIT_HASH_SHA256,
};
static const struct object_id empty_blob_oid_sha256 = {
- .hash = EMPTY_BLOB_SHA256_BIN_LITERAL,
+ .hash = {
+ 0x47, 0x3a, 0x0f, 0x4c, 0x3b, 0xe8, 0xa9, 0x36, 0x81, 0xa2,
+ 0x67, 0xe3, 0xb1, 0xe9, 0xa7, 0xdc, 0xda, 0x11, 0x85, 0x43,
+ 0x6f, 0xe1, 0x41, 0xf7, 0x74, 0x91, 0x20, 0xa3, 0x03, 0x72,
+ 0x18, 0x13
+ },
.algo = GIT_HASH_SHA256,
};
static const struct object_id null_oid_sha256 = {
@@ -118,6 +112,33 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
oid->algo = GIT_HASH_SHA1;
}
+static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx)
+{
+ git_SHA1_Init_unsafe(&ctx->sha1_unsafe);
+}
+
+static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src)
+{
+ git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe);
+}
+
+static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data,
+ size_t len)
+{
+ git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len);
+}
+
+static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx)
+{
+ git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe);
+}
+
+static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx)
+{
+ git_SHA1_Final_unsafe(oid->hash, &ctx->sha1_unsafe);
+ memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
+ oid->algo = GIT_HASH_SHA1;
+}
static void git_hash_sha256_init(git_hash_ctx *ctx)
{
@@ -192,6 +213,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
.update_fn = git_hash_unknown_update,
.final_fn = git_hash_unknown_final,
.final_oid_fn = git_hash_unknown_final_oid,
+ .unsafe_init_fn = git_hash_unknown_init,
+ .unsafe_clone_fn = git_hash_unknown_clone,
+ .unsafe_update_fn = git_hash_unknown_update,
+ .unsafe_final_fn = git_hash_unknown_final,
+ .unsafe_final_oid_fn = git_hash_unknown_final_oid,
.empty_tree = NULL,
.empty_blob = NULL,
.null_oid = NULL,
@@ -207,6 +233,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
.update_fn = git_hash_sha1_update,
.final_fn = git_hash_sha1_final,
.final_oid_fn = git_hash_sha1_final_oid,
+ .unsafe_init_fn = git_hash_sha1_init_unsafe,
+ .unsafe_clone_fn = git_hash_sha1_clone_unsafe,
+ .unsafe_update_fn = git_hash_sha1_update_unsafe,
+ .unsafe_final_fn = git_hash_sha1_final_unsafe,
+ .unsafe_final_oid_fn = git_hash_sha1_final_oid_unsafe,
.empty_tree = &empty_tree_oid,
.empty_blob = &empty_blob_oid,
.null_oid = &null_oid_sha1,
@@ -222,6 +253,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
.update_fn = git_hash_sha256_update,
.final_fn = git_hash_sha256_final,
.final_oid_fn = git_hash_sha256_final_oid,
+ .unsafe_init_fn = git_hash_sha256_init,
+ .unsafe_clone_fn = git_hash_sha256_clone,
+ .unsafe_update_fn = git_hash_sha256_update,
+ .unsafe_final_fn = git_hash_sha256_final,
+ .unsafe_final_oid_fn = git_hash_sha256_final_oid,
.empty_tree = &empty_tree_oid_sha256,
.empty_blob = &empty_blob_oid_sha256,
.null_oid = &null_oid_sha256,
@@ -233,16 +269,10 @@ const struct object_id *null_oid(void)
return the_hash_algo->null_oid;
}
-const char *empty_tree_oid_hex(void)
+const char *empty_tree_oid_hex(const struct git_hash_algo *algop)
{
static char buf[GIT_MAX_HEXSZ + 1];
- return oid_to_hex_r(buf, the_hash_algo->empty_tree);
-}
-
-const char *empty_blob_oid_hex(void)
-{
- static char buf[GIT_MAX_HEXSZ + 1];
- return oid_to_hex_r(buf, the_hash_algo->empty_blob);
+ return oid_to_hex_r(buf, algop->empty_tree);
}
int hash_algo_by_name(const char *name)
@@ -280,30 +310,28 @@ int hash_algo_by_length(int len)
* to write them into the object store (e.g. a browse-only
* application).
*/
-static struct cached_object {
+static struct cached_object_entry {
struct object_id oid;
- enum object_type type;
- void *buf;
- unsigned long size;
+ struct cached_object {
+ enum object_type type;
+ const void *buf;
+ unsigned long size;
+ } value;
} *cached_objects;
static int cached_object_nr, cached_object_alloc;
-static struct cached_object empty_tree = {
- .oid = {
- .hash = EMPTY_TREE_SHA1_BIN_LITERAL,
- },
- .type = OBJ_TREE,
- .buf = "",
-};
-
-static struct cached_object *find_cached_object(const struct object_id *oid)
+static const struct cached_object *find_cached_object(const struct object_id *oid)
{
+ static const struct cached_object empty_tree = {
+ .type = OBJ_TREE,
+ .buf = "",
+ };
int i;
- struct cached_object *co = cached_objects;
+ const struct cached_object_entry *co = cached_objects;
for (i = 0; i < cached_object_nr; i++, co++) {
if (oideq(&co->oid, oid))
- return co;
+ return &co->value;
}
if (oideq(oid, the_hash_algo->empty_tree))
return &empty_tree;
@@ -428,6 +456,39 @@ enum scld_error safe_create_leading_directories_const(const char *path)
return result;
}
+int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
+{
+ int fd;
+ /*
+ * we let the umask do its job, don't try to be more
+ * restrictive except to remove write permission.
+ */
+ int mode = 0444;
+ git_path_buf(temp_filename, "objects/%s", pattern);
+ fd = git_mkstemp_mode(temp_filename->buf, mode);
+ if (0 <= fd)
+ return fd;
+
+ /* slow path */
+ /* some mkstemp implementations erase temp_filename on failure */
+ git_path_buf(temp_filename, "objects/%s", pattern);
+ safe_create_leading_directories(temp_filename->buf);
+ return xmkstemp_mode(temp_filename->buf, mode);
+}
+
+int odb_pack_keep(const char *name)
+{
+ int fd;
+
+ fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (0 <= fd)
+ return fd;
+
+ /* slow path */
+ safe_create_leading_directories_const(name);
+ return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
+}
+
static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
{
int i;
@@ -1092,9 +1153,11 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
void *buf, unsigned long size,
enum object_type type)
{
+ const struct git_hash_algo *algo =
+ oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
struct object_id real_oid;
- hash_object_file(r->hash_algo, buf, size, type, &real_oid);
+ hash_object_file(algo, buf, size, type, &real_oid);
return !oideq(oid, &real_oid) ? -1 : 0;
}
@@ -1450,7 +1513,7 @@ static int loose_object_info(struct repository *r,
int allow_unknown = flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
if (oi->delta_base_oid)
- oidclr(oi->delta_base_oid);
+ oidclr(oi->delta_base_oid, the_repository->hash_algo);
/*
* If we don't care about type or size, then we don't
@@ -1559,7 +1622,7 @@ static int do_oid_object_info_extended(struct repository *r,
struct object_info *oi, unsigned flags)
{
static struct object_info blank_oi = OBJECT_INFO_INIT;
- struct cached_object *co;
+ const struct cached_object *co;
struct pack_entry e;
int rtype;
const struct object_id *real = oid;
@@ -1584,7 +1647,7 @@ static int do_oid_object_info_extended(struct repository *r,
if (oi->disk_sizep)
*(oi->disk_sizep) = 0;
if (oi->delta_base_oid)
- oidclr(oi->delta_base_oid);
+ oidclr(oi->delta_base_oid, the_repository->hash_algo);
if (oi->type_name)
strbuf_addstr(oi->type_name, type_name(co->type));
if (oi->contentp)
@@ -1660,10 +1723,101 @@ static int do_oid_object_info_extended(struct repository *r,
return 0;
}
+static int oid_object_info_convert(struct repository *r,
+ const struct object_id *input_oid,
+ struct object_info *input_oi, unsigned flags)
+{
+ const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo];
+ int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT;
+ struct strbuf type_name = STRBUF_INIT;
+ struct object_id oid, delta_base_oid;
+ struct object_info new_oi, *oi;
+ unsigned long size;
+ void *content;
+ int ret;
+
+ if (repo_oid_to_algop(r, input_oid, the_hash_algo, &oid)) {
+ if (do_die)
+ die(_("missing mapping of %s to %s"),
+ oid_to_hex(input_oid), the_hash_algo->name);
+ return -1;
+ }
+
+ /* Is new_oi needed? */
+ oi = input_oi;
+ if (input_oi && (input_oi->delta_base_oid || input_oi->sizep ||
+ input_oi->contentp)) {
+ new_oi = *input_oi;
+ /* Does delta_base_oid need to be converted? */
+ if (input_oi->delta_base_oid)
+ new_oi.delta_base_oid = &delta_base_oid;
+ /* Will the attributes differ when converted? */
+ if (input_oi->sizep || input_oi->contentp) {
+ new_oi.contentp = &content;
+ new_oi.sizep = &size;
+ new_oi.type_name = &type_name;
+ }
+ oi = &new_oi;
+ }
+
+ ret = oid_object_info_extended(r, &oid, oi, flags);
+ if (ret)
+ return -1;
+ if (oi == input_oi)
+ return ret;
+
+ if (new_oi.contentp) {
+ struct strbuf outbuf = STRBUF_INIT;
+ enum object_type type;
+
+ type = type_from_string_gently(type_name.buf, type_name.len,
+ !do_die);
+ if (type == -1)
+ return -1;
+ if (type != OBJ_BLOB) {
+ ret = convert_object_file(&outbuf,
+ the_hash_algo, input_algo,
+ content, size, type, !do_die);
+ free(content);
+ if (ret == -1)
+ return -1;
+ size = outbuf.len;
+ content = strbuf_detach(&outbuf, NULL);
+ }
+ if (input_oi->sizep)
+ *input_oi->sizep = size;
+ if (input_oi->contentp)
+ *input_oi->contentp = content;
+ else
+ free(content);
+ if (input_oi->type_name)
+ *input_oi->type_name = type_name;
+ else
+ strbuf_release(&type_name);
+ }
+ if (new_oi.delta_base_oid == &delta_base_oid) {
+ if (repo_oid_to_algop(r, &delta_base_oid, input_algo,
+ input_oi->delta_base_oid)) {
+ if (do_die)
+ die(_("missing mapping of %s to %s"),
+ oid_to_hex(&delta_base_oid),
+ input_algo->name);
+ return -1;
+ }
+ }
+ input_oi->whence = new_oi.whence;
+ input_oi->u = new_oi.u;
+ return ret;
+}
+
int oid_object_info_extended(struct repository *r, const struct object_id *oid,
struct object_info *oi, unsigned flags)
{
int ret;
+
+ if (oid->algo && (hash_algo_by_ptr(r->hash_algo) != oid->algo))
+ return oid_object_info_convert(r, oid, oi, flags);
+
obj_read_lock();
ret = do_oid_object_info_extended(r, oid, oi, flags);
obj_read_unlock();
@@ -1690,7 +1844,8 @@ int oid_object_info(struct repository *r,
int pretend_object_file(void *buf, unsigned long len, enum object_type type,
struct object_id *oid)
{
- struct cached_object *co;
+ struct cached_object_entry *co;
+ char *co_buf;
hash_object_file(the_hash_algo, buf, len, type, oid);
if (repo_has_object_file_with_flags(the_repository, oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
@@ -1698,10 +1853,11 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
return 0;
ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
co = &cached_objects[cached_object_nr++];
- co->size = len;
- co->type = type;
- co->buf = xmalloc(len);
- memcpy(co->buf, buf, len);
+ co->value.size = len;
+ co->value.type = type;
+ co_buf = xmalloc(len);
+ memcpy(co_buf, buf, len);
+ co->value.buf = co_buf;
oidcpy(&co->oid, oid);
return 0;
}
@@ -1813,17 +1969,77 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
}
+static int check_collision(const char *filename_a, const char *filename_b)
+{
+ char buf_a[4096], buf_b[4096];
+ int fd_a = -1, fd_b = -1;
+ int ret = 0;
+
+ fd_a = open(filename_a, O_RDONLY);
+ if (fd_a < 0) {
+ ret = error_errno(_("unable to open %s"), filename_a);
+ goto out;
+ }
+
+ fd_b = open(filename_b, O_RDONLY);
+ if (fd_b < 0) {
+ ret = error_errno(_("unable to open %s"), filename_b);
+ goto out;
+ }
+
+ while (1) {
+ ssize_t sz_a, sz_b;
+
+ sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a));
+ if (sz_a < 0) {
+ ret = error_errno(_("unable to read %s"), filename_a);
+ goto out;
+ }
+
+ sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b));
+ if (sz_b < 0) {
+ ret = error_errno(_("unable to read %s"), filename_b);
+ goto out;
+ }
+
+ if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) {
+ ret = error(_("files '%s' and '%s' differ in contents"),
+ filename_a, filename_b);
+ goto out;
+ }
+
+ if (sz_a < sizeof(buf_a))
+ break;
+ }
+
+out:
+ if (fd_a > -1)
+ close(fd_a);
+ if (fd_b > -1)
+ close(fd_b);
+ return ret;
+}
+
/*
* Move the just written object into its final resting place.
*/
int finalize_object_file(const char *tmpfile, const char *filename)
{
+ return finalize_object_file_flags(tmpfile, filename, 0);
+}
+
+int finalize_object_file_flags(const char *tmpfile, const char *filename,
+ enum finalize_object_file_flags flags)
+{
+ struct stat st;
int ret = 0;
if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
goto try_rename;
else if (link(tmpfile, filename))
ret = errno;
+ else
+ unlink_or_warn(tmpfile);
/*
* Coda hack - coda doesn't like cross-directory links,
@@ -1838,16 +2054,24 @@ int finalize_object_file(const char *tmpfile, const char *filename)
*/
if (ret && ret != EEXIST) {
try_rename:
- if (!rename(tmpfile, filename))
+ if (!stat(filename, &st))
+ ret = EEXIST;
+ else if (!rename(tmpfile, filename))
goto out;
- ret = errno;
+ else
+ ret = errno;
}
- unlink_or_warn(tmpfile);
if (ret) {
if (ret != EEXIST) {
+ int saved_errno = errno;
+ unlink_or_warn(tmpfile);
+ errno = saved_errno;
return error_errno(_("unable to write file %s"), filename);
}
- /* FIXME!!! Collision check here ? */
+ if (!(flags & FOF_SKIP_COLLISION_CHECK) &&
+ check_collision(tmpfile, filename))
+ return -1;
+ unlink_or_warn(tmpfile);
}
out:
@@ -1952,9 +2176,12 @@ static int start_loose_object_common(struct strbuf *tmp_file,
const char *filename, unsigned flags,
git_zstream *stream,
unsigned char *buf, size_t buflen,
- git_hash_ctx *c,
+ git_hash_ctx *c, git_hash_ctx *compat_c,
char *hdr, int hdrlen)
{
+ struct repository *repo = the_repository;
+ const struct git_hash_algo *algo = repo->hash_algo;
+ const struct git_hash_algo *compat = repo->compat_hash_algo;
int fd;
fd = create_tmpfile(tmp_file, filename);
@@ -1964,7 +2191,7 @@ static int start_loose_object_common(struct strbuf *tmp_file,
else if (errno == EACCES)
return error(_("insufficient permission for adding "
"an object to repository database %s"),
- get_object_directory());
+ repo_get_object_directory(the_repository));
else
return error_errno(
_("unable to create temporary file"));
@@ -1974,14 +2201,18 @@ static int start_loose_object_common(struct strbuf *tmp_file,
git_deflate_init(stream, zlib_compression_level);
stream->next_out = buf;
stream->avail_out = buflen;
- the_hash_algo->init_fn(c);
+ algo->init_fn(c);
+ if (compat && compat_c)
+ compat->init_fn(compat_c);
/* Start to feed header to zlib stream */
stream->next_in = (unsigned char *)hdr;
stream->avail_in = hdrlen;
while (git_deflate(stream, 0) == Z_OK)
; /* nothing */
- the_hash_algo->update_fn(c, hdr, hdrlen);
+ algo->update_fn(c, hdr, hdrlen);
+ if (compat && compat_c)
+ compat->update_fn(compat_c, hdr, hdrlen);
return fd;
}
@@ -1990,16 +2221,21 @@ static int start_loose_object_common(struct strbuf *tmp_file,
* Common steps for the inner git_deflate() loop for writing loose
* objects. Returns what git_deflate() returns.
*/
-static int write_loose_object_common(git_hash_ctx *c,
+static int write_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
git_zstream *stream, const int flush,
unsigned char *in0, const int fd,
unsigned char *compressed,
const size_t compressed_len)
{
+ struct repository *repo = the_repository;
+ const struct git_hash_algo *algo = repo->hash_algo;
+ const struct git_hash_algo *compat = repo->compat_hash_algo;
int ret;
ret = git_deflate(stream, flush ? Z_FINISH : 0);
- the_hash_algo->update_fn(c, in0, stream->next_in - in0);
+ algo->update_fn(c, in0, stream->next_in - in0);
+ if (compat && compat_c)
+ compat->update_fn(compat_c, in0, stream->next_in - in0);
if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
die_errno(_("unable to write loose object file"));
stream->next_out = compressed;
@@ -2014,15 +2250,21 @@ static int write_loose_object_common(git_hash_ctx *c,
* - End the compression of zlib stream.
* - Get the calculated oid to "oid".
*/
-static int end_loose_object_common(git_hash_ctx *c, git_zstream *stream,
- struct object_id *oid)
+static int end_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
+ git_zstream *stream, struct object_id *oid,
+ struct object_id *compat_oid)
{
+ struct repository *repo = the_repository;
+ const struct git_hash_algo *algo = repo->hash_algo;
+ const struct git_hash_algo *compat = repo->compat_hash_algo;
int ret;
ret = git_deflate_end_gently(stream);
if (ret != Z_OK)
return ret;
- the_hash_algo->final_oid_fn(oid, c);
+ algo->final_oid_fn(oid, c);
+ if (compat && compat_c)
+ compat->final_oid_fn(compat_oid, compat_c);
return Z_OK;
}
@@ -2046,7 +2288,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
fd = start_loose_object_common(&tmp_file, filename.buf, flags,
&stream, compressed, sizeof(compressed),
- &c, hdr, hdrlen);
+ &c, NULL, hdr, hdrlen);
if (fd < 0)
return -1;
@@ -2056,14 +2298,14 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
do {
unsigned char *in0 = stream.next_in;
- ret = write_loose_object_common(&c, &stream, 1, in0, fd,
+ ret = write_loose_object_common(&c, NULL, &stream, 1, in0, fd,
compressed, sizeof(compressed));
} while (ret == Z_OK);
if (ret != Z_STREAM_END)
die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
ret);
- ret = end_loose_object_common(&c, &stream, &parano_oid);
+ ret = end_loose_object_common(&c, NULL, &stream, &parano_oid, NULL);
if (ret != Z_OK)
die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
ret);
@@ -2082,7 +2324,8 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
warning_errno(_("failed utime() on %s"), tmp_file.buf);
}
- return finalize_object_file(tmp_file.buf, filename.buf);
+ return finalize_object_file_flags(tmp_file.buf, filename.buf,
+ FOF_SKIP_COLLISION_CHECK);
}
static int freshen_loose_object(const struct object_id *oid)
@@ -2108,10 +2351,12 @@ static int freshen_packed_object(const struct object_id *oid)
int stream_loose_object(struct input_stream *in_stream, size_t len,
struct object_id *oid)
{
+ const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+ struct object_id compat_oid;
int fd, ret, err = 0, flush = 0;
unsigned char compressed[4096];
git_zstream stream;
- git_hash_ctx c;
+ git_hash_ctx c, compat_c;
struct strbuf tmp_file = STRBUF_INIT;
struct strbuf filename = STRBUF_INIT;
int dirlen;
@@ -2122,7 +2367,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
prepare_loose_object_bulk_checkin();
/* Since oid is not determined, save tmp file to odb path. */
- strbuf_addf(&filename, "%s/", get_object_directory());
+ strbuf_addf(&filename, "%s/", repo_get_object_directory(the_repository));
hdrlen = format_object_header(hdr, sizeof(hdr), OBJ_BLOB, len);
/*
@@ -2135,7 +2380,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
*/
fd = start_loose_object_common(&tmp_file, filename.buf, 0,
&stream, compressed, sizeof(compressed),
- &c, hdr, hdrlen);
+ &c, &compat_c, hdr, hdrlen);
if (fd < 0) {
err = -1;
goto cleanup;
@@ -2153,7 +2398,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
if (in_stream->is_finished)
flush = 1;
}
- ret = write_loose_object_common(&c, &stream, flush, in0, fd,
+ ret = write_loose_object_common(&c, &compat_c, &stream, flush, in0, fd,
compressed, sizeof(compressed));
/*
* Unlike write_loose_object(), we do not have the entire
@@ -2169,14 +2414,14 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
/*
* Common steps for write_loose_object and stream_loose_object to
- * end writing loose oject:
+ * end writing loose object:
*
* - End the compression of zlib stream.
* - Get the calculated oid.
*/
if (ret != Z_STREAM_END)
die(_("unable to stream deflate new object (%d)"), ret);
- ret = end_loose_object_common(&c, &stream, oid);
+ ret = end_loose_object_common(&c, &compat_c, &stream, oid, &compat_oid);
if (ret != Z_OK)
die(_("deflateEnd on stream object failed (%d)"), ret);
close_loose_object(fd, tmp_file.buf);
@@ -2202,7 +2447,10 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
strbuf_release(&dir);
}
- err = finalize_object_file(tmp_file.buf, filename.buf);
+ err = finalize_object_file_flags(tmp_file.buf, filename.buf,
+ FOF_SKIP_COLLISION_CHECK);
+ if (!err && compat)
+ err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
cleanup:
strbuf_release(&tmp_file);
strbuf_release(&filename);
@@ -2211,19 +2459,42 @@ cleanup:
int write_object_file_flags(const void *buf, unsigned long len,
enum object_type type, struct object_id *oid,
- unsigned flags)
+ struct object_id *compat_oid_in, unsigned flags)
{
+ struct repository *repo = the_repository;
+ const struct git_hash_algo *algo = repo->hash_algo;
+ const struct git_hash_algo *compat = repo->compat_hash_algo;
+ struct object_id compat_oid;
char hdr[MAX_HEADER_LEN];
int hdrlen = sizeof(hdr);
+ /* Generate compat_oid */
+ if (compat) {
+ if (compat_oid_in)
+ oidcpy(&compat_oid, compat_oid_in);
+ else if (type == OBJ_BLOB)
+ hash_object_file(compat, buf, len, type, &compat_oid);
+ else {
+ struct strbuf converted = STRBUF_INIT;
+ convert_object_file(&converted, algo, compat,
+ buf, len, type, 0);
+ hash_object_file(compat, converted.buf, converted.len,
+ type, &compat_oid);
+ strbuf_release(&converted);
+ }
+ }
+
/* Normally if we have it in the pack then we do not bother writing
* it out into .git/objects/??/?{38} file.
*/
- write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,
- &hdrlen);
+ write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
if (freshen_packed_object(oid) || freshen_loose_object(oid))
return 0;
- return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
+ if (write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags))
+ return -1;
+ if (compat)
+ return repo_add_loose_object_map(repo, oid, &compat_oid);
+ return 0;
}
int write_object_file_literally(const void *buf, unsigned long len,
@@ -2231,7 +2502,27 @@ int write_object_file_literally(const void *buf, unsigned long len,
unsigned flags)
{
char *header;
+ struct repository *repo = the_repository;
+ const struct git_hash_algo *algo = repo->hash_algo;
+ const struct git_hash_algo *compat = repo->compat_hash_algo;
+ struct object_id compat_oid;
int hdrlen, status = 0;
+ int compat_type = -1;
+
+ if (compat) {
+ compat_type = type_from_string_gently(type, -1, 1);
+ if (compat_type == OBJ_BLOB)
+ hash_object_file(compat, buf, len, compat_type,
+ &compat_oid);
+ else if (compat_type != -1) {
+ struct strbuf converted = STRBUF_INIT;
+ convert_object_file(&converted, algo, compat,
+ buf, len, compat_type, 0);
+ hash_object_file(compat, converted.buf, converted.len,
+ compat_type, &compat_oid);
+ strbuf_release(&converted);
+ }
+ }
/* type string, SP, %lu of the length plus NUL must fit this */
hdrlen = strlen(type) + MAX_HEADER_LEN;
@@ -2244,6 +2535,8 @@ int write_object_file_literally(const void *buf, unsigned long len,
if (freshen_packed_object(oid) || freshen_loose_object(oid))
goto cleanup;
status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
+ if (compat_type != -1)
+ return repo_add_loose_object_map(repo, oid, &compat_oid);
cleanup:
free(header);
@@ -2252,9 +2545,12 @@ cleanup:
int force_object_loose(const struct object_id *oid, time_t mtime)
{
+ struct repository *repo = the_repository;
+ const struct git_hash_algo *compat = repo->compat_hash_algo;
void *buf;
unsigned long len;
struct object_info oi = OBJECT_INFO_INIT;
+ struct object_id compat_oid;
enum object_type type;
char hdr[MAX_HEADER_LEN];
int hdrlen;
@@ -2267,8 +2563,15 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
oi.contentp = &buf;
if (oid_object_info_extended(the_repository, oid, &oi, 0))
return error(_("cannot read object for %s"), oid_to_hex(oid));
+ if (compat) {
+ if (repo_oid_to_algop(repo, oid, compat, &compat_oid))
+ return error(_("cannot map object %s to %s"),
+ oid_to_hex(oid), compat->name);
+ }
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
+ if (!ret && compat)
+ ret = repo_add_loose_object_map(the_repository, oid, &compat_oid);
free(buf);
return ret;
@@ -2307,23 +2610,23 @@ int repo_has_object_file(struct repository *r,
* give more context.
*/
static int hash_format_check_report(struct fsck_options *opts UNUSED,
- const struct object_id *oid UNUSED,
- enum object_type object_type UNUSED,
- enum fsck_msg_type msg_type UNUSED,
- enum fsck_msg_id msg_id UNUSED,
- const char *message)
+ void *fsck_report UNUSED,
+ enum fsck_msg_type msg_type UNUSED,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
{
error(_("object fails fsck: %s"), message);
return 1;
}
static int index_mem(struct index_state *istate,
- struct object_id *oid, void *buf, size_t size,
+ struct object_id *oid,
+ const void *buf, size_t size,
enum object_type type,
const char *path, unsigned flags)
{
+ struct strbuf nbuf = STRBUF_INIT;
int ret = 0;
- int re_allocated = 0;
int write_object = flags & HASH_WRITE_OBJECT;
if (!type)
@@ -2333,11 +2636,10 @@ static int index_mem(struct index_state *istate,
* Convert blobs to git internal format
*/
if ((type == OBJ_BLOB) && path) {
- struct strbuf nbuf = STRBUF_INIT;
if (convert_to_git(istate, path, buf, size, &nbuf,
get_conv_flags(flags))) {
- buf = strbuf_detach(&nbuf, &size);
- re_allocated = 1;
+ buf = nbuf.buf;
+ size = nbuf.len;
}
}
if (flags & HASH_FORMAT_CHECK) {
@@ -2354,8 +2656,8 @@ static int index_mem(struct index_state *istate,
ret = write_object_file(buf, size, type, oid);
else
hash_object_file(the_hash_algo, buf, size, type, oid);
- if (re_allocated)
- free(buf);
+
+ strbuf_release(&nbuf);
return ret;
}
@@ -2446,11 +2748,11 @@ static int index_core(struct index_state *istate,
* binary blobs, they generally do not want to get any conversion, and
* callers should avoid this code path when filters are requested.
*/
-static int index_stream(struct object_id *oid, int fd, size_t size,
- enum object_type type, const char *path,
- unsigned flags)
+static int index_blob_stream(struct object_id *oid, int fd, size_t size,
+ const char *path,
+ unsigned flags)
{
- return index_bulk_checkin(oid, fd, size, type, path, flags);
+ return index_blob_bulk_checkin(oid, fd, size, path, flags);
}
int index_fd(struct index_state *istate, struct object_id *oid,
@@ -2472,8 +2774,8 @@ int index_fd(struct index_state *istate, struct object_id *oid,
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
type, path, flags);
else
- ret = index_stream(oid, fd, xsize_t(st->st_size), type, path,
- flags);
+ ret = index_blob_stream(oid, fd, xsize_t(st->st_size), path,
+ flags);
close(fd);
return ret;
}
@@ -2505,7 +2807,7 @@ int index_path(struct index_state *istate, struct object_id *oid,
strbuf_release(&sb);
break;
case S_IFDIR:
- return resolve_gitlink_ref(path, "HEAD", oid);
+ return repo_resolve_gitlink_ref(the_repository, path, "HEAD", oid);
default:
return error(_("%s: unsupported file type"), path);
}
@@ -2579,6 +2881,8 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
!hex_to_bytes(oid.hash + 1, de->d_name,
the_hash_algo->rawsz - 1)) {
oid_set_algo(&oid, the_hash_algo);
+ memset(oid.hash + the_hash_algo->rawsz, 0,
+ GIT_MAX_RAWSZ - the_hash_algo->rawsz);
if (obj_cb) {
r = obj_cb(&oid, path->buf, data);
if (r)
@@ -2789,6 +3093,7 @@ int read_loose_object(const char *path,
if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
NULL) != ULHR_OK) {
error(_("unable to unpack header of %s"), path);
+ git_inflate_end(&stream);
goto out;
}
diff --git a/object-file.h b/object-file.h
index d6414610f8..81b30d269c 100644
--- a/object-file.h
+++ b/object-file.h
@@ -117,7 +117,13 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
*/
int stream_object_signature(struct repository *r, const struct object_id *oid);
+enum finalize_object_file_flags {
+ FOF_SKIP_COLLISION_CHECK = 1,
+};
+
int finalize_object_file(const char *tmpfile, const char *filename);
+int finalize_object_file_flags(const char *tmpfile, const char *filename,
+ enum finalize_object_file_flags flags);
/* Helper to check and "touch" a file */
int check_and_freshen_file(const char *fn, int freshen);
diff --git a/object-name.c b/object-name.c
index 0bfa29dbbf..c892fbe80a 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "object-name.h"
#include "advice.h"
@@ -8,7 +10,6 @@
#include "tag.h"
#include "commit.h"
#include "tree.h"
-#include "blob.h"
#include "tree-walk.h"
#include "refs.h"
#include "remote.h"
@@ -19,14 +20,16 @@
#include "pretty.h"
#include "object-store-ll.h"
#include "read-cache-ll.h"
+#include "repo-settings.h"
#include "repository.h"
#include "setup.h"
-#include "submodule.h"
#include "midx.h"
#include "commit-reach.h"
#include "date.h"
+#include "object-file-convert.h"
-static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *);
+static int get_oid_oneline(struct repository *r, const char *, struct object_id *,
+ const struct commit_list *);
typedef int (*disambiguate_hint_fn)(struct repository *, const struct object_id *, void *);
@@ -49,6 +52,7 @@ struct disambiguate_state {
static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
{
+ /* The hash algorithm of current has already been filtered */
if (ds->always_call_fn) {
ds->ambiguous = ds->fn(ds->repo, current, ds->cb_data) ? 1 : 0;
return;
@@ -132,26 +136,32 @@ static int match_hash(unsigned len, const unsigned char *a, const unsigned char
static void unique_in_midx(struct multi_pack_index *m,
struct disambiguate_state *ds)
{
- uint32_t num, i, first = 0;
- const struct object_id *current = NULL;
- num = m->num_objects;
+ for (; m; m = m->base_midx) {
+ uint32_t num, i, first = 0;
+ const struct object_id *current = NULL;
+ int len = ds->len > ds->repo->hash_algo->hexsz ?
+ ds->repo->hash_algo->hexsz : ds->len;
- if (!num)
- return;
+ if (!m->num_objects)
+ continue;
- bsearch_midx(&ds->bin_pfx, m, &first);
+ num = m->num_objects + m->num_objects_in_base;
- /*
- * At this point, "first" is the location of the lowest object
- * with an object name that could match "bin_pfx". See if we have
- * 0, 1 or more objects that actually match(es).
- */
- for (i = first; i < num && !ds->ambiguous; i++) {
- struct object_id oid;
- current = nth_midxed_object_oid(&oid, m, i);
- if (!match_hash(ds->len, ds->bin_pfx.hash, current->hash))
- break;
- update_candidates(ds, current);
+ bsearch_one_midx(&ds->bin_pfx, m, &first);
+
+ /*
+ * At this point, "first" is the location of the lowest
+ * object with an object name that could match
+ * "bin_pfx". See if we have 0, 1 or more objects that
+ * actually match(es).
+ */
+ for (i = first; i < num && !ds->ambiguous; i++) {
+ struct object_id oid;
+ current = nth_midxed_object_oid(&oid, m, i);
+ if (!match_hash(len, ds->bin_pfx.hash, current->hash))
+ break;
+ update_candidates(ds, current);
+ }
}
}
@@ -159,6 +169,8 @@ static void unique_in_pack(struct packed_git *p,
struct disambiguate_state *ds)
{
uint32_t num, i, first = 0;
+ int len = ds->len > ds->repo->hash_algo->hexsz ?
+ ds->repo->hash_algo->hexsz : ds->len;
if (p->multi_pack_index)
return;
@@ -177,7 +189,7 @@ static void unique_in_pack(struct packed_git *p,
for (i = first; i < num && !ds->ambiguous; i++) {
struct object_id oid;
nth_packed_object_id(&oid, p, i);
- if (!match_hash(ds->len, ds->bin_pfx.hash, oid.hash))
+ if (!match_hash(len, ds->bin_pfx.hash, oid.hash))
break;
update_candidates(ds, &oid);
}
@@ -188,6 +200,10 @@ static void find_short_packed_object(struct disambiguate_state *ds)
struct multi_pack_index *m;
struct packed_git *p;
+ /* Skip, unless oids from the storage hash algorithm are wanted */
+ if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
+ return;
+
for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous;
m = m->next)
unique_in_midx(m, ds);
@@ -326,11 +342,12 @@ int set_disambiguate_hint_config(const char *var, const char *value)
static int init_object_disambiguation(struct repository *r,
const char *name, int len,
+ const struct git_hash_algo *algo,
struct disambiguate_state *ds)
{
int i;
- if (len < MINIMUM_ABBREV || len > the_hash_algo->hexsz)
+ if (len < MINIMUM_ABBREV || len > GIT_MAX_HEXSZ)
return -1;
memset(ds, 0, sizeof(*ds));
@@ -357,6 +374,7 @@ static int init_object_disambiguation(struct repository *r,
ds->len = len;
ds->hex_pfx[len] = '\0';
ds->repo = r;
+ ds->bin_pfx.algo = algo ? hash_algo_by_ptr(algo) : GIT_HASH_UNKNOWN;
prepare_alt_odb(r);
return 0;
}
@@ -491,9 +509,10 @@ static int repo_collect_ambiguous(struct repository *r UNUSED,
return collect_ambiguous(oid, data);
}
-static int sort_ambiguous(const void *a, const void *b, void *ctx)
+static int sort_ambiguous(const void *va, const void *vb, void *ctx)
{
struct repository *sort_ambiguous_repo = ctx;
+ const struct object_id *a = va, *b = vb;
int a_type = oid_object_info(sort_ambiguous_repo, a, NULL);
int b_type = oid_object_info(sort_ambiguous_repo, b, NULL);
int a_type_sort;
@@ -503,8 +522,12 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)
* Sorts by hash within the same object type, just as
* oid_array_for_each_unique() would do.
*/
- if (a_type == b_type)
- return oidcmp(a, b);
+ if (a_type == b_type) {
+ if (a->algo == b->algo)
+ return oidcmp(a, b);
+ else
+ return a->algo > b->algo ? 1 : -1;
+ }
/*
* Between object types show tags, then commits, and finally
@@ -533,8 +556,12 @@ static enum get_oid_result get_short_oid(struct repository *r,
int status;
struct disambiguate_state ds;
int quietly = !!(flags & GET_OID_QUIETLY);
+ const struct git_hash_algo *algo = r->hash_algo;
+
+ if (flags & GET_OID_HASH_ANY)
+ algo = NULL;
- if (init_object_disambiguation(r, name, len, &ds) < 0)
+ if (init_object_disambiguation(r, name, len, algo, &ds) < 0)
return -1;
if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
@@ -588,7 +615,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
if (!ds.ambiguous)
ds.fn = NULL;
- repo_for_each_abbrev(r, ds.hex_pfx, collect_ambiguous, &collect);
+ repo_for_each_abbrev(r, ds.hex_pfx, algo, collect_ambiguous, &collect);
sort_ambiguous_oid_array(r, &collect);
if (oid_array_for_each(&collect, show_ambiguous_object, &out))
@@ -610,13 +637,14 @@ static enum get_oid_result get_short_oid(struct repository *r,
}
int repo_for_each_abbrev(struct repository *r, const char *prefix,
+ const struct git_hash_algo *algo,
each_abbrev_fn fn, void *cb_data)
{
struct oid_array collect = OID_ARRAY_INIT;
struct disambiguate_state ds;
int ret;
- if (init_object_disambiguation(r, prefix, strlen(prefix), &ds) < 0)
+ if (init_object_disambiguation(r, prefix, strlen(prefix), algo, &ds) < 0)
return -1;
ds.always_call_fn = 1;
@@ -686,37 +714,40 @@ static int repo_extend_abbrev_len(struct repository *r UNUSED,
static void find_abbrev_len_for_midx(struct multi_pack_index *m,
struct min_abbrev_data *mad)
{
- int match = 0;
- uint32_t num, first = 0;
- struct object_id oid;
- const struct object_id *mad_oid;
+ for (; m; m = m->base_midx) {
+ int match = 0;
+ uint32_t num, first = 0;
+ struct object_id oid;
+ const struct object_id *mad_oid;
- if (!m->num_objects)
- return;
+ if (!m->num_objects)
+ continue;
- num = m->num_objects;
- mad_oid = mad->oid;
- match = bsearch_midx(mad_oid, m, &first);
+ num = m->num_objects + m->num_objects_in_base;
+ mad_oid = mad->oid;
+ match = bsearch_one_midx(mad_oid, m, &first);
- /*
- * first is now the position in the packfile where we would insert
- * mad->hash if it does not exist (or the position of mad->hash if
- * it does exist). Hence, we consider a maximum of two objects
- * nearby for the abbreviation length.
- */
- mad->init_len = 0;
- if (!match) {
- if (nth_midxed_object_oid(&oid, m, first))
- extend_abbrev_len(&oid, mad);
- } else if (first < num - 1) {
- if (nth_midxed_object_oid(&oid, m, first + 1))
- extend_abbrev_len(&oid, mad);
- }
- if (first > 0) {
- if (nth_midxed_object_oid(&oid, m, first - 1))
- extend_abbrev_len(&oid, mad);
+ /*
+ * first is now the position in the packfile where we
+ * would insert mad->hash if it does not exist (or the
+ * position of mad->hash if it does exist). Hence, we
+ * consider a maximum of two objects nearby for the
+ * abbreviation length.
+ */
+ mad->init_len = 0;
+ if (!match) {
+ if (nth_midxed_object_oid(&oid, m, first))
+ extend_abbrev_len(&oid, mad);
+ } else if (first < num - 1) {
+ if (nth_midxed_object_oid(&oid, m, first + 1))
+ extend_abbrev_len(&oid, mad);
+ }
+ if (first > 0) {
+ if (nth_midxed_object_oid(&oid, m, first - 1))
+ extend_abbrev_len(&oid, mad);
+ }
+ mad->init_len = mad->cur_len;
}
- mad->init_len = mad->cur_len;
}
static void find_abbrev_len_for_pack(struct packed_git *p,
@@ -787,10 +818,12 @@ void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
const struct object_id *oid, int len)
{
+ const struct git_hash_algo *algo =
+ oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
struct disambiguate_state ds;
struct min_abbrev_data mad;
struct object_id oid_ret;
- const unsigned hexsz = r->hash_algo->hexsz;
+ const unsigned hexsz = algo->hexsz;
if (len < 0) {
unsigned long count = repo_approximate_object_count(r);
@@ -815,7 +848,7 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
}
oid_to_hex_r(hex, oid);
- if (len == hexsz || !len)
+ if (len >= hexsz || !len)
return hexsz;
mad.repo = r;
@@ -826,7 +859,7 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
find_abbrev_len_packed(&mad);
- if (init_object_disambiguation(r, hex, mad.cur_len, &ds) < 0)
+ if (init_object_disambiguation(r, hex, mad.cur_len, algo, &ds) < 0)
return -1;
ds.fn = repo_extend_abbrev_len;
@@ -927,7 +960,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
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) {
+ if (repo_settings_get_warn_ambiguous_refs(r) && warn_on_object_refname_ambiguity) {
refs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0);
if (refs_found > 0) {
warning(warn_msg, len, str);
@@ -988,7 +1021,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
if (!refs_found)
return -1;
- if (warn_ambiguous_refs && !(flags & GET_OID_QUIETLY) &&
+ if (repo_settings_get_warn_ambiguous_refs(r) && !(flags & GET_OID_QUIETLY) &&
(refs_found > 1 ||
!get_short_oid(r, str, len, &tmp_oid, GET_OID_QUIETLY)))
warning(warn_msg, len, str);
@@ -1036,6 +1069,15 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
len, str,
show_date(co_time, co_tz, DATE_MODE(RFC2822)));
}
+ } else if (nth == co_cnt && !is_null_oid(oid)) {
+ /*
+ * We were asked for the Nth reflog (counting
+ * from 0), but there were only N entries.
+ * read_ref_at() will have returned "1" to tell
+ * us it did not find an entry, but it did
+ * still fill in the oid with the "old" value,
+ * which we can use.
+ */
} else {
if (flags & GET_OID_QUIETLY) {
exit(128);
@@ -1221,6 +1263,8 @@ static int peel_onion(struct repository *r, const char *name, int len,
prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
commit_list_insert((struct commit *)o, &list);
ret = get_oid_oneline(r, prefix, oid, list);
+
+ free_commit_list(list);
free(prefix);
return ret;
}
@@ -1332,7 +1376,7 @@ struct handle_one_ref_cb {
struct commit_list **list;
};
-static int handle_one_ref(const char *path, const struct object_id *oid,
+static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -1355,9 +1399,10 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
static int get_oid_oneline(struct repository *r,
const char *prefix, struct object_id *oid,
- struct commit_list *list)
+ const struct commit_list *list)
{
- struct commit_list *backup = NULL, *l;
+ struct commit_list *copy = NULL;
+ const struct commit_list *l;
int found = 0;
int negative = 0;
regex_t regex;
@@ -1378,14 +1423,14 @@ static int get_oid_oneline(struct repository *r,
for (l = list; l; l = l->next) {
l->item->object.flags |= ONELINE_SEEN;
- commit_list_insert(l->item, &backup);
+ commit_list_insert(l->item, &copy);
}
- while (list) {
+ while (copy) {
const char *p, *buf;
struct commit *commit;
int matches;
- commit = pop_most_recent_commit(&list, ONELINE_SEEN);
+ commit = pop_most_recent_commit(&copy, ONELINE_SEEN);
if (!parse_object(r, &commit->object.oid))
continue;
buf = repo_get_commit_buffer(r, commit, NULL);
@@ -1400,10 +1445,9 @@ static int get_oid_oneline(struct repository *r,
}
}
regfree(&regex);
- free_commit_list(list);
- for (l = backup; l; l = l->next)
+ for (l = list; l; l = l->next)
clear_commit_marks(l->item, ONELINE_SEEN);
- free_commit_list(backup);
+ free_commit_list(copy);
return found ? 0 : -1;
}
@@ -1481,7 +1525,7 @@ int repo_get_oid_mb(struct repository *r,
struct object_id *oid)
{
struct commit *one, *two;
- struct commit_list *mbs;
+ struct commit_list *mbs = NULL;
struct object_id oid_tmp;
const char *dots;
int st;
@@ -1509,7 +1553,10 @@ int repo_get_oid_mb(struct repository *r,
two = lookup_commit_reference_gently(r, &oid_tmp, 0);
if (!two)
return -1;
- mbs = repo_get_merge_bases(r, one, two);
+ if (repo_get_merge_bases(r, one, two, &mbs) < 0) {
+ free_commit_list(mbs);
+ return -1;
+ }
if (!mbs || mbs->next)
st = -1;
else {
@@ -1723,6 +1770,12 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
return check_refname_format(sb->buf, 0);
}
+void object_context_release(struct object_context *ctx)
+{
+ free(ctx->path);
+ strbuf_release(&ctx->symlink_path);
+}
+
/*
* This is like "get_oid_basic()", except it allows "object ID expressions",
* notably "xyz^" for "parent of xyz"
@@ -1730,7 +1783,9 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
int repo_get_oid(struct repository *r, const char *name, struct object_id *oid)
{
struct object_context unused;
- return get_oid_with_context(r, name, 0, oid, &unused);
+ int ret = get_oid_with_context(r, name, 0, oid, &unused);
+ object_context_release(&unused);
+ return ret;
}
/*
@@ -1768,8 +1823,10 @@ int repo_get_oid_committish(struct repository *r,
struct object_id *oid)
{
struct object_context unused;
- return get_oid_with_context(r, name, GET_OID_COMMITTISH,
- oid, &unused);
+ int ret = get_oid_with_context(r, name, GET_OID_COMMITTISH,
+ oid, &unused);
+ object_context_release(&unused);
+ return ret;
}
int repo_get_oid_treeish(struct repository *r,
@@ -1777,8 +1834,10 @@ int repo_get_oid_treeish(struct repository *r,
struct object_id *oid)
{
struct object_context unused;
- return get_oid_with_context(r, name, GET_OID_TREEISH,
- oid, &unused);
+ int ret = get_oid_with_context(r, name, GET_OID_TREEISH,
+ oid, &unused);
+ object_context_release(&unused);
+ return ret;
}
int repo_get_oid_commit(struct repository *r,
@@ -1786,8 +1845,10 @@ int repo_get_oid_commit(struct repository *r,
struct object_id *oid)
{
struct object_context unused;
- return get_oid_with_context(r, name, GET_OID_COMMIT,
- oid, &unused);
+ int ret = get_oid_with_context(r, name, GET_OID_COMMIT,
+ oid, &unused);
+ object_context_release(&unused);
+ return ret;
}
int repo_get_oid_tree(struct repository *r,
@@ -1795,8 +1856,10 @@ int repo_get_oid_tree(struct repository *r,
struct object_id *oid)
{
struct object_context unused;
- return get_oid_with_context(r, name, GET_OID_TREE,
- oid, &unused);
+ int ret = get_oid_with_context(r, name, GET_OID_TREE,
+ oid, &unused);
+ object_context_release(&unused);
+ return ret;
}
int repo_get_oid_blob(struct repository *r,
@@ -1804,8 +1867,10 @@ int repo_get_oid_blob(struct repository *r,
struct object_id *oid)
{
struct object_context unused;
- return get_oid_with_context(r, name, GET_OID_BLOB,
- oid, &unused);
+ int ret = get_oid_with_context(r, name, GET_OID_BLOB,
+ oid, &unused);
+ object_context_release(&unused);
+ return ret;
}
/* Must be called only when object_name:filename doesn't exist. */
@@ -1971,7 +2036,10 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
refs_for_each_ref(get_main_ref_store(repo), handle_one_ref, &cb);
refs_head_ref(get_main_ref_store(repo), handle_one_ref, &cb);
commit_list_sort_by_date(&list);
- return get_oid_oneline(repo, name + 2, oid, list);
+ ret = get_oid_oneline(repo, name + 2, oid, list);
+
+ free_commit_list(list);
+ return ret;
}
if (namelen < 3 ||
name[2] != ':' ||
@@ -2083,6 +2151,7 @@ void maybe_die_on_misspelt_object_name(struct repository *r,
struct object_id oid;
get_oid_with_context_1(r, name, GET_OID_ONLY_TO_DIE | GET_OID_QUIETLY,
prefix, &oid, &oc);
+ object_context_release(&oc);
}
enum get_oid_result get_oid_with_context(struct repository *repo,
diff --git a/object-name.h b/object-name.h
index 9ae5223071..8dba4a47a4 100644
--- a/object-name.h
+++ b/object-name.h
@@ -22,6 +22,8 @@ struct object_context {
char *path;
};
+void object_context_release(struct object_context *ctx);
+
/*
* Return an abbreviated sha1 unique within this repository's object database.
* The result will be at least `len` characters long, and will be NUL
@@ -67,7 +69,8 @@ enum get_oid_result get_oid_with_context(struct repository *repo, const char *st
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 repo_for_each_abbrev(struct repository *r, const char *prefix,
+ const struct git_hash_algo *algo, each_abbrev_fn, void *);
int set_disambiguate_hint_config(const char *var, const char *value);
diff --git a/object-store-ll.h b/object-store-ll.h
index 26a3895c82..53b8e693b1 100644
--- a/object-store-ll.h
+++ b/object-store-ll.h
@@ -26,6 +26,9 @@ struct object_directory {
uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
struct oidtree *loose_objects_cache;
+ /* Map between object IDs for loose objects. */
+ struct loose_object_map *loose_map;
+
/*
* This is a temporary object store created by the tmp_objdir
* facility. Disable ref updates since the objects in the store
@@ -229,6 +232,21 @@ struct raw_object_store *raw_object_store_new(void);
void raw_object_store_clear(struct raw_object_store *o);
/*
+ * 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);
+
+/*
* 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.
*/
@@ -252,11 +270,11 @@ void hash_object_file(const struct git_hash_algo *algo, const void *buf,
int write_object_file_flags(const void *buf, unsigned long len,
enum object_type type, struct object_id *oid,
- unsigned flags);
+ struct object_id *comapt_oid_in, unsigned flags);
static inline int write_object_file(const void *buf, unsigned long len,
enum object_type type, struct object_id *oid)
{
- return write_object_file_flags(buf, len, type, oid, 0);
+ return write_object_file_flags(buf, len, type, oid, NULL, 0);
}
int write_object_file_literally(const void *buf, unsigned long len,
diff --git a/object.c b/object.c
index 2c61e4c862..94ea8fb8d2 100644
--- a/object.c
+++ b/object.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hex.h"
@@ -13,6 +15,7 @@
#include "alloc.h"
#include "packfile.h"
#include "commit-graph.h"
+#include "loose.h"
unsigned int get_max_object_index(void)
{
@@ -47,8 +50,7 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)
len = strlen(str);
for (i = 1; i < ARRAY_SIZE(object_type_strings); i++)
- if (!strncmp(str, object_type_strings[i], len) &&
- object_type_strings[i][len] == '\0')
+ if (!xstrncmpz(object_type_strings[i], str, len))
return i;
if (gentle)
@@ -207,6 +209,29 @@ struct object *lookup_object_by_type(struct repository *r,
}
}
+enum peel_status peel_object(struct repository *r,
+ const struct object_id *name,
+ struct object_id *oid)
+{
+ struct object *o = lookup_unknown_object(r, name);
+
+ if (o->type == OBJ_NONE) {
+ int type = oid_object_info(r, name, NULL);
+ if (type < 0 || !object_as_type(o, type, 0))
+ return PEEL_INVALID;
+ }
+
+ if (o->type != OBJ_TAG)
+ return PEEL_NON_TAG;
+
+ o = deref_tag_noverify(r, o);
+ if (!o)
+ return PEEL_INVALID;
+
+ oidcpy(oid, &o->oid);
+ return PEEL_PEELED;
+}
+
struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
{
struct object *obj;
@@ -272,6 +297,7 @@ struct object *parse_object_with_flags(struct repository *r,
enum parse_object_flags flags)
{
int skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK);
+ int discard_tree = !!(flags & PARSE_OBJECT_DISCARD_TREE);
unsigned long size;
enum object_type type;
int eaten;
@@ -299,6 +325,17 @@ struct object *parse_object_with_flags(struct repository *r,
return lookup_object(r, oid);
}
+ /*
+ * If the caller does not care about the tree buffer and does not
+ * care about checking the hash, we can simply verify that we
+ * have the on-disk object with the correct type.
+ */
+ if (skip_hash && discard_tree &&
+ (!obj || obj->type == OBJ_TREE) &&
+ oid_object_info(r, oid, NULL) == OBJ_TREE) {
+ return &lookup_tree(r, oid)->object;
+ }
+
buffer = repo_read_object_file(r, oid, &type, &size);
if (buffer) {
if (!skip_hash &&
@@ -312,6 +349,8 @@ struct object *parse_object_with_flags(struct repository *r,
buffer, &eaten);
if (!eaten)
free(buffer);
+ if (discard_tree && type == OBJ_TREE)
+ free_tree_buffer((struct tree *)obj);
return obj;
}
return NULL;
@@ -506,11 +545,12 @@ void repo_clear_commit_marks(struct repository *r, unsigned int flags)
}
}
-struct parsed_object_pool *parsed_object_pool_new(void)
+struct parsed_object_pool *parsed_object_pool_new(struct repository *repo)
{
struct parsed_object_pool *o = xmalloc(sizeof(*o));
memset(o, 0, sizeof(*o));
+ o->repo = repo;
o->blob_state = allocate_alloc_state();
o->tree_state = allocate_alloc_state();
o->commit_state = allocate_alloc_state();
@@ -540,6 +580,7 @@ void free_object_directory(struct object_directory *odb)
{
free(odb->path);
odb_clear_loose_cache(odb);
+ loose_object_map_clear(&odb->loose_map);
free(odb);
}
@@ -574,11 +615,30 @@ void raw_object_store_clear(struct raw_object_store *o)
INIT_LIST_HEAD(&o->packed_git_mru);
close_object_store(o);
+
+ /*
+ * `close_object_store()` only closes the packfiles, but doesn't free
+ * them. We thus have to do this manually.
+ */
+ for (struct packed_git *p = o->packed_git, *next; p; p = next) {
+ next = p->next;
+ free(p);
+ }
o->packed_git = NULL;
hashmap_clear(&o->pack_map);
}
+void parsed_object_pool_reset_commit_grafts(struct parsed_object_pool *o)
+{
+ for (int i = 0; i < o->grafts_nr; i++) {
+ unparse_commit(o->repo, &o->grafts[i]->oid);
+ free(o->grafts[i]);
+ }
+ o->grafts_nr = 0;
+ o->commit_graft_prepared = 0;
+}
+
void parsed_object_pool_clear(struct parsed_object_pool *o)
{
/*
@@ -610,6 +670,7 @@ void parsed_object_pool_clear(struct parsed_object_pool *o)
free_commit_buffer_slab(o->buffer_slab);
o->buffer_slab = NULL;
+ parsed_object_pool_reset_commit_grafts(o);
clear_alloc_state(o->blob_state);
clear_alloc_state(o->tree_state);
clear_alloc_state(o->commit_state);
diff --git a/object.h b/object.h
index 114d45954d..17f32f1103 100644
--- a/object.h
+++ b/object.h
@@ -1,12 +1,13 @@
#ifndef OBJECT_H
#define OBJECT_H
-#include "hash-ll.h"
+#include "hash.h"
struct buffer_slab;
struct repository;
struct parsed_object_pool {
+ struct repository *repo;
struct object **obj_hash;
int nr_objs, obj_hash_size;
@@ -31,8 +32,9 @@ struct parsed_object_pool {
struct buffer_slab *buffer_slab;
};
-struct parsed_object_pool *parsed_object_pool_new(void);
+struct parsed_object_pool *parsed_object_pool_new(struct repository *repo);
void parsed_object_pool_clear(struct parsed_object_pool *o);
+void parsed_object_pool_reset_commit_grafts(struct parsed_object_pool *o);
struct object_list {
struct object *item;
@@ -62,7 +64,7 @@ void object_array_init(struct object_array *array);
/*
* object flag allocation:
- * revision.h: 0---------10 15 23------27
+ * revision.h: 0---------10 15 23------27
* fetch-pack.c: 01 67
* negotiator/default.c: 2--5
* walker.c: 0-2
@@ -75,12 +77,14 @@ void object_array_init(struct object_array *array);
* commit-reach.c: 16-----19
* sha1-name.c: 20
* list-objects-filter.c: 21
+ * bloom.c: 2122
* builtin/fsck.c: 0--3
* builtin/gc.c: 0
* builtin/index-pack.c: 2021
* reflog.c: 10--12
* builtin/show-branch.c: 0-------------------------------------------26
* builtin/unpack-objects.c: 2021
+ * pack-bitmap.h: 2122
*/
#define FLAG_BITS 28
@@ -190,6 +194,24 @@ void *create_object(struct repository *r, const struct object_id *oid, void *obj
void *object_as_type(struct object *obj, enum object_type type, int quiet);
+
+static inline const char *parse_mode(const char *str, uint16_t *modep)
+{
+ unsigned char c;
+ unsigned int mode = 0;
+
+ if (*str == ' ')
+ return NULL;
+
+ while ((c = *str++) != ' ') {
+ if (c < '0' || c > '7')
+ return NULL;
+ mode = (mode << 3) + (c - '0');
+ }
+ *modep = mode;
+ return str;
+}
+
/*
* Returns the object, having parsed it to find out what it is.
*
@@ -197,6 +219,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet);
*/
enum parse_object_flags {
PARSE_OBJECT_SKIP_HASH_CHECK = 1 << 0,
+ PARSE_OBJECT_DISCARD_TREE = 1 << 1,
};
struct object *parse_object(struct repository *r, const struct object_id *oid);
struct object *parse_object_with_flags(struct repository *r,
@@ -237,6 +260,41 @@ struct object *lookup_unknown_object(struct repository *r, const struct object_i
struct object *lookup_object_by_type(struct repository *r, const struct object_id *oid,
enum object_type type);
+enum peel_status {
+ /* object was peeled successfully: */
+ PEEL_PEELED = 0,
+
+ /*
+ * object cannot be peeled because the named object (or an
+ * object referred to by a tag in the peel chain), does not
+ * exist.
+ */
+ PEEL_INVALID = -1,
+
+ /* object cannot be peeled because it is not a tag: */
+ PEEL_NON_TAG = -2,
+
+ /* ref_entry contains no peeled value because it is a symref: */
+ PEEL_IS_SYMREF = -3,
+
+ /*
+ * ref_entry cannot be peeled because it is broken (i.e., the
+ * symbolic reference cannot even be resolved to an object
+ * name):
+ */
+ PEEL_BROKEN = -4
+};
+
+/*
+ * Peel the named object; i.e., if the object is a tag, resolve the
+ * tag recursively until a non-tag is found. If successful, store the
+ * result to oid and return PEEL_PEELED. If the object is not a tag
+ * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,
+ * and leave oid unchanged.
+ */
+enum peel_status peel_object(struct repository *r,
+ const struct object_id *name, struct object_id *oid);
+
struct object_list *object_list_insert(struct object *item,
struct object_list **list_p);
diff --git a/oid-array.c b/oid-array.c
index 8e4717746c..9cac974395 100644
--- a/oid-array.c
+++ b/oid-array.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "oid-array.h"
#include "hash-lookup.h"
@@ -6,12 +8,20 @@ void oid_array_append(struct oid_array *array, const struct object_id *oid)
{
ALLOC_GROW(array->oid, array->nr + 1, array->alloc);
oidcpy(&array->oid[array->nr++], oid);
+ if (!oid->algo)
+ oid_set_algo(&array->oid[array->nr - 1], the_hash_algo);
array->sorted = 0;
}
-static int void_hashcmp(const void *a, const void *b)
+static int void_hashcmp(const void *va, const void *vb)
{
- return oidcmp(a, b);
+ const struct object_id *a = va, *b = vb;
+ int ret;
+ if (a->algo == b->algo)
+ ret = oidcmp(a, b);
+ else
+ ret = a->algo > b->algo ? 1 : -1;
+ return ret;
}
void oid_array_sort(struct oid_array *array)
diff --git a/oidmap.h b/oidmap.h
index 05c673eb7c..fad412827a 100644
--- a/oidmap.h
+++ b/oidmap.h
@@ -1,7 +1,7 @@
#ifndef OIDMAP_H
#define OIDMAP_H
-#include "hash-ll.h"
+#include "hash.h"
#include "hashmap.h"
/*
diff --git a/oidset.c b/oidset.c
index d1e5376316..8d36aef8dc 100644
--- a/oidset.c
+++ b/oidset.c
@@ -23,6 +23,16 @@ int oidset_insert(struct oidset *set, const struct object_id *oid)
return !added;
}
+void oidset_insert_from_set(struct oidset *dest, struct oidset *src)
+{
+ struct oidset_iter iter;
+ struct object_id *src_oid;
+
+ oidset_iter_init(src, &iter);
+ while ((src_oid = oidset_iter_next(&iter)))
+ oidset_insert(dest, src_oid);
+}
+
int oidset_remove(struct oidset *set, const struct object_id *oid)
{
khiter_t pos = kh_get_oid_set(&set->set, *oid);
@@ -38,12 +48,14 @@ void oidset_clear(struct oidset *set)
oidset_init(set, 0);
}
-void oidset_parse_file(struct oidset *set, const char *path)
+void oidset_parse_file(struct oidset *set, const char *path,
+ const struct git_hash_algo *algop)
{
- oidset_parse_file_carefully(set, path, NULL, NULL);
+ oidset_parse_file_carefully(set, path, algop, NULL, NULL);
}
void oidset_parse_file_carefully(struct oidset *set, const char *path,
+ const struct git_hash_algo *algop,
oidset_parse_tweak_fn fn, void *cbdata)
{
FILE *fp;
@@ -69,7 +81,7 @@ void oidset_parse_file_carefully(struct oidset *set, const char *path,
if (!sb.len)
continue;
- if (parse_oid_hex(sb.buf, &oid, &p) || *p != '\0')
+ if (parse_oid_hex_algop(sb.buf, &oid, &p, algop) || *p != '\0')
die("invalid object name: %s", sb.buf);
if (fn && fn(&oid, cbdata))
continue;
diff --git a/oidset.h b/oidset.h
index ba4a5a2cd3..0106b6f278 100644
--- a/oidset.h
+++ b/oidset.h
@@ -48,6 +48,12 @@ int oidset_contains(const struct oidset *set, const struct object_id *oid);
int oidset_insert(struct oidset *set, const struct object_id *oid);
/**
+ * Insert all the oids that are in set 'src' into set 'dest'; a copy
+ * is made of each oid inserted into set 'dest'.
+ */
+void oidset_insert_from_set(struct oidset *dest, struct oidset *src);
+
+/**
* Remove the oid from the set.
*
* Returns 1 if the oid was present in the set, 0 otherwise.
@@ -74,7 +80,8 @@ void oidset_clear(struct oidset *set);
* are allowed. Leading whitespace and empty or white-space only lines are
* ignored.
*/
-void oidset_parse_file(struct oidset *set, const char *path);
+void oidset_parse_file(struct oidset *set, const char *path,
+ const struct git_hash_algo *algop);
/*
* Similar to the above, but with a callback which can (1) return non-zero to
@@ -83,6 +90,7 @@ void oidset_parse_file(struct oidset *set, const char *path);
*/
typedef int (*oidset_parse_tweak_fn)(struct object_id *, void *);
void oidset_parse_file_carefully(struct oidset *set, const char *path,
+ const struct git_hash_algo *algop,
oidset_parse_tweak_fn fn, void *cbdata);
struct oidset_iter {
diff --git a/oidtree.c b/oidtree.c
index daef175dc7..151568f74f 100644
--- a/oidtree.c
+++ b/oidtree.c
@@ -42,12 +42,12 @@ void oidtree_insert(struct oidtree *ot, const struct object_id *oid)
* Clear the padding and copy the result in separate steps to
* respect the 4-byte alignment needed by struct object_id.
*/
- oidcpy_with_padding(&k, oid);
+ oidcpy(&k, oid);
memcpy(on->k, &k, sizeof(k));
/*
* n.b. Current callers won't get us duplicates, here. If a
- * future caller causes duplicates, there'll be a a small leak
+ * future caller causes duplicates, there'll be a small leak
* that won't be freed until oidtree_clear. Currently it's not
* worth maintaining a free list
*/
@@ -60,7 +60,7 @@ int oidtree_contains(struct oidtree *ot, const struct object_id *oid)
struct object_id k;
size_t klen = sizeof(k);
- oidcpy_with_padding(&k, oid);
+ oidcpy(&k, oid);
if (oid->algo == GIT_HASH_UNKNOWN)
klen -= sizeof(oid->algo);
diff --git a/oidtree.h b/oidtree.h
index 55c83513fd..77898f510a 100644
--- a/oidtree.h
+++ b/oidtree.h
@@ -2,7 +2,7 @@
#define OIDTREE_H
#include "cbtree.h"
-#include "hash-ll.h"
+#include "hash.h"
#include "mem-pool.h"
struct oidtree {
diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore
index 9acb74412e..a877c11f42 100644
--- a/oss-fuzz/.gitignore
+++ b/oss-fuzz/.gitignore
@@ -1,3 +1,5 @@
fuzz-commit-graph
+fuzz-config
+fuzz-date
fuzz-pack-headers
fuzz-pack-idx
diff --git a/oss-fuzz/dummy-cmd-main.c b/oss-fuzz/dummy-cmd-main.c
new file mode 100644
index 0000000000..8ef776d06f
--- /dev/null
+++ b/oss-fuzz/dummy-cmd-main.c
@@ -0,0 +1,14 @@
+#include "git-compat-util.h"
+
+/*
+ * When linking the fuzzers, we link against common-main.o to pick up some
+ * symbols. However, even though we ignore common-main:main(), we still need to
+ * provide all the symbols it references. In the fuzzers' case, we need to
+ * provide a dummy cmd_main() for the linker to be happy. It will never be
+ * executed.
+ */
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED) {
+ BUG("We should not execute cmd_main() from a fuzz target");
+ return 1;
+}
diff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c
index 2992079dd9..fbb77fec19 100644
--- a/oss-fuzz/fuzz-commit-graph.c
+++ b/oss-fuzz/fuzz-commit-graph.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit-graph.h"
#include "repository.h"
@@ -11,15 +13,17 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
struct commit_graph *g;
- initialize_the_repository();
+ initialize_repository(the_repository);
+
/*
* Initialize the_repository with commit-graph settings that would
* normally be read from the repository's gitdir. We want to avoid
* touching the disk to keep the individual fuzz-test cases as fast as
* possible.
*/
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
the_repository->settings.commit_graph_generation_version = 2;
- the_repository->settings.commit_graph_read_changed_paths = 1;
+ the_repository->settings.commit_graph_changed_paths_version = 1;
g = parse_commit_graph(&the_repository->settings, (void *)data, size);
repo_clear(the_repository);
free_commit_graph(g);
diff --git a/oss-fuzz/fuzz-config.c b/oss-fuzz/fuzz-config.c
new file mode 100644
index 0000000000..94027f5b97
--- /dev/null
+++ b/oss-fuzz/fuzz-config.c
@@ -0,0 +1,33 @@
+#include "git-compat-util.h"
+#include "config.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
+static int config_parser_callback(const char *, const char *,
+ const struct config_context *, void *);
+
+static int config_parser_callback(const char *key, const char *value,
+ const struct config_context *ctx UNUSED,
+ void *data UNUSED)
+{
+ /*
+ * Visit every byte of memory we are given to make sure the parser
+ * gave it to us appropriately. We need to unconditionally return 0,
+ * but we also want to prevent the strlen from being optimized away.
+ */
+ size_t c = strlen(key);
+
+ if (value)
+ c += strlen(value);
+ return c == SIZE_MAX;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, const size_t size)
+{
+ struct config_options config_opts = { 0 };
+
+ config_opts.error_action = CONFIG_ERROR_SILENT;
+ git_config_from_mem(config_parser_callback, CONFIG_ORIGIN_BLOB,
+ "fuzztest-config", (const char *)data, size, NULL,
+ CONFIG_SCOPE_UNKNOWN, &config_opts);
+ return 0;
+}
diff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c
new file mode 100644
index 0000000000..9619dae40e
--- /dev/null
+++ b/oss-fuzz/fuzz-date.c
@@ -0,0 +1,49 @@
+#include "git-compat-util.h"
+#include "date.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ int local;
+ int num;
+ char *str;
+ int16_t tz;
+ timestamp_t ts;
+ enum date_mode_type dmtype;
+ struct date_mode dm;
+
+ if (size <= 4)
+ /*
+ * we use the first byte to fuzz dmtype and the
+ * second byte to fuzz local, then the next two
+ * bytes to fuzz tz offset. The remainder
+ * (at least one byte) is fed as input to
+ * approxidate_careful().
+ */
+ return 0;
+
+ local = !!(*data++ & 0x10);
+ num = *data++ % DATE_UNIX;
+ if (num >= DATE_STRFTIME)
+ num++;
+ dmtype = (enum date_mode_type)num;
+ size -= 2;
+
+ tz = *data++;
+ tz = (tz << 8) | *data++;
+ size -= 2;
+
+ str = xmemdupz(data, size);
+
+ ts = approxidate_careful(str, &num);
+ free(str);
+
+ dm = date_mode_from_type(dmtype);
+ dm.local = local;
+ show_date(ts, (int)tz, dm);
+
+ date_mode_release(&dm);
+
+ return 0;
+}
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index f6757c3cbf..49758e2525 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -1,15 +1,14 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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 "revision.h"
-#include "list-objects.h"
#include "progress.h"
-#include "pack-revindex.h"
#include "pack.h"
#include "pack-bitmap.h"
#include "hash-lookup.h"
@@ -20,6 +19,12 @@
#include "trace2.h"
#include "tree.h"
#include "tree-walk.h"
+#include "pseudo-merge.h"
+#include "oid-array.h"
+#include "config.h"
+#include "alloc.h"
+#include "refs.h"
+#include "strmap.h"
struct bitmapped_commit {
struct commit *commit;
@@ -28,52 +33,97 @@ struct bitmapped_commit {
int flags;
int xor_offset;
uint32_t commit_pos;
+ unsigned pseudo_merge : 1;
};
-struct bitmap_writer {
- struct ewah_bitmap *commits;
- struct ewah_bitmap *trees;
- struct ewah_bitmap *blobs;
- struct ewah_bitmap *tags;
+static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer)
+{
+ return writer->selected_nr - writer->pseudo_merges_nr;
+}
- kh_oid_map_t *bitmaps;
- struct packing_data *to_pack;
+void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
+ struct packing_data *pdata)
+{
+ memset(writer, 0, sizeof(struct bitmap_writer));
+ if (writer->bitmaps)
+ BUG("bitmap writer already initialized");
+ writer->bitmaps = kh_init_oid_map();
+ writer->pseudo_merge_commits = kh_init_oid_map();
+ writer->to_pack = pdata;
- struct bitmapped_commit *selected;
- unsigned int selected_nr, selected_alloc;
+ string_list_init_dup(&writer->pseudo_merge_groups);
- struct progress *progress;
- int show_progress;
- unsigned char pack_checksum[GIT_MAX_RAWSZ];
-};
+ load_pseudo_merges_from_config(r, &writer->pseudo_merge_groups);
+}
+
+static void free_pseudo_merge_commit_idx(struct pseudo_merge_commit_idx *idx)
+{
+ if (!idx)
+ return;
+ free(idx->pseudo_merge);
+ free(idx);
+}
+
+static void pseudo_merge_group_release_cb(void *payload, const char *name UNUSED)
+{
+ pseudo_merge_group_release(payload);
+ free(payload);
+}
+
+void bitmap_writer_free(struct bitmap_writer *writer)
+{
+ uint32_t i;
+ struct pseudo_merge_commit_idx *idx;
+
+ if (!writer)
+ return;
-static struct bitmap_writer writer;
+ ewah_free(writer->commits);
+ ewah_free(writer->trees);
+ ewah_free(writer->blobs);
+ ewah_free(writer->tags);
+
+ kh_destroy_oid_map(writer->bitmaps);
+
+ kh_foreach_value(writer->pseudo_merge_commits, idx,
+ free_pseudo_merge_commit_idx(idx));
+ kh_destroy_oid_map(writer->pseudo_merge_commits);
+ string_list_clear_func(&writer->pseudo_merge_groups,
+ pseudo_merge_group_release_cb);
+
+ for (i = 0; i < writer->selected_nr; i++) {
+ struct bitmapped_commit *bc = &writer->selected[i];
+ if (bc->write_as != bc->bitmap)
+ ewah_free(bc->write_as);
+ ewah_free(bc->bitmap);
+ }
+ free(writer->selected);
+}
-void bitmap_writer_show_progress(int show)
+void bitmap_writer_show_progress(struct bitmap_writer *writer, int show)
{
- writer.show_progress = show;
+ writer->show_progress = show;
}
/**
* Build the initial type index for the packfile or multi-pack-index
*/
-void bitmap_writer_build_type_index(struct packing_data *to_pack,
- struct pack_idx_entry **index,
- uint32_t index_nr)
+void bitmap_writer_build_type_index(struct bitmap_writer *writer,
+ struct pack_idx_entry **index)
{
uint32_t i;
- writer.commits = ewah_new();
- writer.trees = ewah_new();
- writer.blobs = ewah_new();
- writer.tags = ewah_new();
- ALLOC_ARRAY(to_pack->in_pack_pos, to_pack->nr_objects);
+ writer->commits = ewah_new();
+ writer->trees = ewah_new();
+ writer->blobs = ewah_new();
+ writer->tags = ewah_new();
+ ALLOC_ARRAY(writer->to_pack->in_pack_pos, writer->to_pack->nr_objects);
- for (i = 0; i < index_nr; ++i) {
+ for (i = 0; i < writer->to_pack->nr_objects; ++i) {
struct object_entry *entry = (struct object_entry *)index[i];
enum object_type real_type;
- oe_set_in_pack_pos(to_pack, entry, i);
+ oe_set_in_pack_pos(writer->to_pack, entry, i);
switch (oe_type(entry)) {
case OBJ_COMMIT:
@@ -84,26 +134,26 @@ void bitmap_writer_build_type_index(struct packing_data *to_pack,
break;
default:
- real_type = oid_object_info(to_pack->repo,
+ real_type = oid_object_info(writer->to_pack->repo,
&entry->idx.oid, NULL);
break;
}
switch (real_type) {
case OBJ_COMMIT:
- ewah_set(writer.commits, i);
+ ewah_set(writer->commits, i);
break;
case OBJ_TREE:
- ewah_set(writer.trees, i);
+ ewah_set(writer->trees, i);
break;
case OBJ_BLOB:
- ewah_set(writer.blobs, i);
+ ewah_set(writer->blobs, i);
break;
case OBJ_TAG:
- ewah_set(writer.tags, i);
+ ewah_set(writer->tags, i);
break;
default:
@@ -114,27 +164,49 @@ void bitmap_writer_build_type_index(struct packing_data *to_pack,
}
}
+int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer,
+ const struct object_id *oid)
+{
+ return kh_get_oid_map(writer->bitmaps, *oid) != kh_end(writer->bitmaps);
+}
+
/**
* Compute the actual bitmaps
*/
-static inline void push_bitmapped_commit(struct commit *commit)
+void bitmap_writer_push_commit(struct bitmap_writer *writer,
+ struct commit *commit, unsigned pseudo_merge)
{
- if (writer.selected_nr >= writer.selected_alloc) {
- writer.selected_alloc = (writer.selected_alloc + 32) * 2;
- REALLOC_ARRAY(writer.selected, writer.selected_alloc);
+ if (writer->selected_nr >= writer->selected_alloc) {
+ writer->selected_alloc = (writer->selected_alloc + 32) * 2;
+ REALLOC_ARRAY(writer->selected, writer->selected_alloc);
+ }
+
+ if (!pseudo_merge) {
+ int hash_ret;
+ khiter_t hash_pos = kh_put_oid_map(writer->bitmaps,
+ commit->object.oid,
+ &hash_ret);
+
+ if (!hash_ret)
+ die(_("duplicate entry when writing bitmap index: %s"),
+ oid_to_hex(&commit->object.oid));
+ kh_value(writer->bitmaps, hash_pos) = NULL;
}
- writer.selected[writer.selected_nr].commit = commit;
- writer.selected[writer.selected_nr].bitmap = NULL;
- writer.selected[writer.selected_nr].flags = 0;
+ writer->selected[writer->selected_nr].commit = commit;
+ writer->selected[writer->selected_nr].bitmap = NULL;
+ writer->selected[writer->selected_nr].write_as = NULL;
+ writer->selected[writer->selected_nr].flags = 0;
+ writer->selected[writer->selected_nr].pseudo_merge = pseudo_merge;
- writer.selected_nr++;
+ writer->selected_nr++;
}
-static uint32_t find_object_pos(const struct object_id *oid, int *found)
+static uint32_t find_object_pos(struct bitmap_writer *writer,
+ const struct object_id *oid, int *found)
{
- struct object_entry *entry = packlist_find(writer.to_pack, oid);
+ struct object_entry *entry = packlist_find(writer->to_pack, oid);
if (!entry) {
if (found)
@@ -146,30 +218,34 @@ static uint32_t find_object_pos(const struct object_id *oid, int *found)
if (found)
*found = 1;
- return oe_in_pack_pos(writer.to_pack, entry);
+ return oe_in_pack_pos(writer->to_pack, entry);
}
-static void compute_xor_offsets(void)
+static void compute_xor_offsets(struct bitmap_writer *writer)
{
static const int MAX_XOR_OFFSET_SEARCH = 10;
int i, next = 0;
- while (next < writer.selected_nr) {
- struct bitmapped_commit *stored = &writer.selected[next];
-
+ while (next < writer->selected_nr) {
+ struct bitmapped_commit *stored = &writer->selected[next];
int best_offset = 0;
struct ewah_bitmap *best_bitmap = stored->bitmap;
struct ewah_bitmap *test_xor;
+ if (stored->pseudo_merge)
+ goto next;
+
for (i = 1; i <= MAX_XOR_OFFSET_SEARCH; ++i) {
int curr = next - i;
if (curr < 0)
break;
+ if (writer->selected[curr].pseudo_merge)
+ continue;
test_xor = ewah_pool_new();
- ewah_xor(writer.selected[curr].bitmap, stored->bitmap, test_xor);
+ ewah_xor(writer->selected[curr].bitmap, stored->bitmap, test_xor);
if (test_xor->buffer_size < best_bitmap->buffer_size) {
if (best_bitmap != stored->bitmap)
@@ -182,6 +258,7 @@ static void compute_xor_offsets(void)
}
}
+next:
stored->xor_offset = best_offset;
stored->write_as = best_bitmap;
@@ -194,10 +271,18 @@ struct bb_commit {
struct bitmap *commit_mask;
struct bitmap *bitmap;
unsigned selected:1,
- maximal:1;
+ maximal:1,
+ pseudo_merge:1;
unsigned idx; /* within selected array */
};
+static void clear_bb_commit(struct bb_commit *commit)
+{
+ free_commit_list(commit->reverse_edges);
+ bitmap_free(commit->commit_mask);
+ bitmap_free(commit->bitmap);
+}
+
define_commit_slab(bb_data, struct bb_commit);
struct bitmap_builder {
@@ -225,17 +310,18 @@ static void bitmap_builder_init(struct bitmap_builder *bb,
revs.first_parent_only = 1;
for (i = 0; i < writer->selected_nr; i++) {
- struct commit *c = writer->selected[i].commit;
- struct bb_commit *ent = bb_data_at(&bb->data, c);
+ struct bitmapped_commit *bc = &writer->selected[i];
+ struct bb_commit *ent = bb_data_at(&bb->data, bc->commit);
ent->selected = 1;
ent->maximal = 1;
+ ent->pseudo_merge = bc->pseudo_merge;
ent->idx = i;
ent->commit_mask = bitmap_new();
bitmap_set(ent->commit_mask, i);
- add_pending_object(&revs, &c->object, "");
+ add_pending_object(&revs, &bc->commit->object, "");
}
if (prepare_revision_walk(&revs))
@@ -339,12 +425,13 @@ next:
static void bitmap_builder_clear(struct bitmap_builder *bb)
{
- clear_bb_data(&bb->data);
+ deep_clear_bb_data(&bb->data, clear_bb_commit);
free(bb->commits);
bb->commits_nr = bb->commits_alloc = 0;
}
-static int fill_bitmap_tree(struct bitmap *bitmap,
+static int fill_bitmap_tree(struct bitmap_writer *writer,
+ struct bitmap *bitmap,
struct tree *tree)
{
int found;
@@ -356,7 +443,7 @@ static int fill_bitmap_tree(struct bitmap *bitmap,
* If our bit is already set, then there is nothing to do. Both this
* tree and all of its children will be set.
*/
- pos = find_object_pos(&tree->object.oid, &found);
+ pos = find_object_pos(writer, &tree->object.oid, &found);
if (!found)
return -1;
if (bitmap_get(bitmap, pos))
@@ -366,17 +453,17 @@ static int fill_bitmap_tree(struct bitmap *bitmap,
if (parse_tree(tree) < 0)
die("unable to load tree object %s",
oid_to_hex(&tree->object.oid));
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
switch (object_type(entry.mode)) {
case OBJ_TREE:
- if (fill_bitmap_tree(bitmap,
+ if (fill_bitmap_tree(writer, bitmap,
lookup_tree(the_repository, &entry.oid)) < 0)
return -1;
break;
case OBJ_BLOB:
- pos = find_object_pos(&entry.oid, &found);
+ pos = find_object_pos(writer, &entry.oid, &found);
if (!found)
return -1;
bitmap_set(bitmap, pos);
@@ -392,8 +479,10 @@ static int fill_bitmap_tree(struct bitmap *bitmap,
}
static int reused_bitmaps_nr;
+static int reused_pseudo_merge_bitmaps_nr;
-static int fill_bitmap_commit(struct bb_commit *ent,
+static int fill_bitmap_commit(struct bitmap_writer *writer,
+ struct bb_commit *ent,
struct commit *commit,
struct prio_queue *queue,
struct prio_queue *tree_queue,
@@ -412,31 +501,46 @@ static int fill_bitmap_commit(struct bb_commit *ent,
struct commit *c = prio_queue_get(queue);
if (old_bitmap && mapping) {
- struct ewah_bitmap *old = bitmap_for_commit(old_bitmap, c);
+ struct ewah_bitmap *old;
+ struct bitmap *remapped = bitmap_new();
+
+ if (commit->object.flags & BITMAP_PSEUDO_MERGE)
+ old = pseudo_merge_bitmap_for_commit(old_bitmap, c);
+ else
+ old = bitmap_for_commit(old_bitmap, c);
/*
* If this commit has an old bitmap, then translate that
* bitmap and add its bits to this one. No need to walk
* parents or the tree for this commit.
*/
- if (old && !rebuild_bitmap(mapping, old, ent->bitmap)) {
- reused_bitmaps_nr++;
+ if (old && !rebuild_bitmap(mapping, old, remapped)) {
+ bitmap_or(ent->bitmap, remapped);
+ bitmap_free(remapped);
+ if (commit->object.flags & BITMAP_PSEUDO_MERGE)
+ reused_pseudo_merge_bitmaps_nr++;
+ else
+ reused_bitmaps_nr++;
continue;
}
+ bitmap_free(remapped);
}
/*
* Mark ourselves and queue our tree. The commit
* walk ensures we cover all parents.
*/
- pos = find_object_pos(&c->object.oid, &found);
- if (!found)
- return -1;
- bitmap_set(ent->bitmap, pos);
- prio_queue_put(tree_queue,
- repo_get_commit_tree(the_repository, c));
+ if (!(c->object.flags & BITMAP_PSEUDO_MERGE)) {
+ pos = find_object_pos(writer, &c->object.oid, &found);
+ if (!found)
+ return -1;
+ bitmap_set(ent->bitmap, pos);
+ 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);
+ pos = find_object_pos(writer, &p->item->object.oid,
+ &found);
if (!found)
return -1;
if (!bitmap_get(ent->bitmap, pos)) {
@@ -447,29 +551,33 @@ static int fill_bitmap_commit(struct bb_commit *ent,
}
while (tree_queue->nr) {
- if (fill_bitmap_tree(ent->bitmap,
+ if (fill_bitmap_tree(writer, ent->bitmap,
prio_queue_get(tree_queue)) < 0)
return -1;
}
return 0;
}
-static void store_selected(struct bb_commit *ent, struct commit *commit)
+static void store_selected(struct bitmap_writer *writer,
+ struct bb_commit *ent, struct commit *commit)
{
- struct bitmapped_commit *stored = &writer.selected[ent->idx];
+ struct bitmapped_commit *stored = &writer->selected[ent->idx];
khiter_t hash_pos;
- int hash_ret;
stored->bitmap = bitmap_to_ewah(ent->bitmap);
- hash_pos = kh_put_oid_map(writer.bitmaps, commit->object.oid, &hash_ret);
- if (hash_ret == 0)
- die("Duplicate entry when writing index: %s",
+ if (ent->pseudo_merge)
+ return;
+
+ hash_pos = kh_get_oid_map(writer->bitmaps, commit->object.oid);
+ if (hash_pos == kh_end(writer->bitmaps))
+ die(_("attempted to store non-selected commit: '%s'"),
oid_to_hex(&commit->object.oid));
- kh_value(writer.bitmaps, hash_pos) = stored;
+
+ kh_value(writer->bitmaps, hash_pos) = stored;
}
-int bitmap_writer_build(struct packing_data *to_pack)
+int bitmap_writer_build(struct bitmap_writer *writer)
{
struct bitmap_builder bb;
size_t i;
@@ -480,37 +588,35 @@ int bitmap_writer_build(struct packing_data *to_pack)
uint32_t *mapping;
int closed = 1; /* until proven otherwise */
- writer.bitmaps = kh_init_oid_map();
- writer.to_pack = to_pack;
-
- if (writer.show_progress)
- writer.progress = start_progress("Building bitmaps", writer.selected_nr);
+ if (writer->show_progress)
+ writer->progress = start_progress("Building bitmaps",
+ writer->selected_nr);
trace2_region_enter("pack-bitmap-write", "building_bitmaps_total",
the_repository);
- old_bitmap = prepare_bitmap_git(to_pack->repo);
+ old_bitmap = prepare_bitmap_git(writer->to_pack->repo);
if (old_bitmap)
- mapping = create_bitmap_mapping(old_bitmap, to_pack);
+ mapping = create_bitmap_mapping(old_bitmap, writer->to_pack);
else
mapping = NULL;
- bitmap_builder_init(&bb, &writer, old_bitmap);
+ bitmap_builder_init(&bb, writer, old_bitmap);
for (i = bb.commits_nr; i > 0; i--) {
struct commit *commit = bb.commits[i-1];
struct bb_commit *ent = bb_data_at(&bb.data, commit);
struct commit *child;
int reused = 0;
- if (fill_bitmap_commit(ent, commit, &queue, &tree_queue,
+ if (fill_bitmap_commit(writer, ent, commit, &queue, &tree_queue,
old_bitmap, mapping) < 0) {
closed = 0;
break;
}
if (ent->selected) {
- store_selected(ent, commit);
+ store_selected(writer, ent, commit);
nr_stored++;
- display_progress(writer.progress, nr_stored);
+ display_progress(writer->progress, nr_stored);
}
while ((child = pop_commit(&ent->reverse_edges))) {
@@ -540,11 +646,14 @@ int bitmap_writer_build(struct packing_data *to_pack)
the_repository);
trace2_data_intmax("pack-bitmap-write", the_repository,
"building_bitmaps_reused", reused_bitmaps_nr);
+ trace2_data_intmax("pack-bitmap-write", the_repository,
+ "building_bitmaps_pseudo_merge_reused",
+ reused_pseudo_merge_bitmaps_nr);
- stop_progress(&writer.progress);
+ stop_progress(&writer->progress);
if (closed)
- compute_xor_offsets();
+ compute_xor_offsets(writer);
return closed ? 0 : -1;
}
@@ -582,9 +691,9 @@ static int date_compare(const void *_a, const void *_b)
return (long)b->date - (long)a->date;
}
-void bitmap_writer_select_commits(struct commit **indexed_commits,
- unsigned int indexed_commits_nr,
- int max_bitmaps)
+void bitmap_writer_select_commits(struct bitmap_writer *writer,
+ struct commit **indexed_commits,
+ unsigned int indexed_commits_nr)
{
unsigned int i = 0, j, next;
@@ -592,12 +701,15 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
if (indexed_commits_nr < 100) {
for (i = 0; i < indexed_commits_nr; ++i)
- push_bitmapped_commit(indexed_commits[i]);
+ bitmap_writer_push_commit(writer, indexed_commits[i], 0);
+
+ select_pseudo_merges(writer);
+
return;
}
- if (writer.show_progress)
- writer.progress = start_progress("Selecting bitmap commits", 0);
+ if (writer->show_progress)
+ writer->progress = start_progress("Selecting bitmap commits", 0);
for (;;) {
struct commit *chosen = NULL;
@@ -607,11 +719,6 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
if (i + next >= indexed_commits_nr)
break;
- if (max_bitmaps > 0 && writer.selected_nr >= max_bitmaps) {
- writer.selected_nr = max_bitmaps;
- break;
- }
-
if (next == 0) {
chosen = indexed_commits[i];
} else {
@@ -630,13 +737,15 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
}
}
- push_bitmapped_commit(chosen);
+ bitmap_writer_push_commit(writer, chosen, 0);
i += next + 1;
- display_progress(writer.progress, i);
+ display_progress(writer->progress, i);
}
- stop_progress(&writer.progress);
+ stop_progress(&writer->progress);
+
+ select_pseudo_merges(writer);
}
@@ -662,19 +771,21 @@ static const struct object_id *oid_access(size_t pos, const void *table)
return &index[pos]->oid;
}
-static void write_selected_commits_v1(struct hashfile *f,
- uint32_t *commit_positions,
- off_t *offsets)
+static void write_selected_commits_v1(struct bitmap_writer *writer,
+ struct hashfile *f, off_t *offsets)
{
int i;
- for (i = 0; i < writer.selected_nr; ++i) {
- struct bitmapped_commit *stored = &writer.selected[i];
+ for (i = 0; i < bitmap_writer_nr_selected_commits(writer); ++i) {
+ struct bitmapped_commit *stored = &writer->selected[i];
+ if (stored->pseudo_merge)
+ BUG("unexpected pseudo-merge among selected: %s",
+ oid_to_hex(&stored->commit->object.oid));
if (offsets)
offsets[i] = hashfile_total(f);
- hashwrite_be32(f, commit_positions[i]);
+ hashwrite_be32(f, stored->commit_pos);
hashwrite_u8(f, stored->xor_offset);
hashwrite_u8(f, stored->flags);
@@ -682,31 +793,155 @@ static void write_selected_commits_v1(struct hashfile *f,
}
}
+static void write_pseudo_merges(struct bitmap_writer *writer,
+ struct hashfile *f)
+{
+ struct oid_array commits = OID_ARRAY_INIT;
+ struct bitmap **commits_bitmap = NULL;
+ off_t *pseudo_merge_ofs = NULL;
+ off_t start, table_start, next_ext;
+
+ uint32_t base = bitmap_writer_nr_selected_commits(writer);
+ size_t i, j = 0;
+
+ CALLOC_ARRAY(commits_bitmap, writer->pseudo_merges_nr);
+ CALLOC_ARRAY(pseudo_merge_ofs, writer->pseudo_merges_nr);
+
+ for (i = 0; i < writer->pseudo_merges_nr; i++) {
+ struct bitmapped_commit *merge = &writer->selected[base + i];
+ struct commit_list *p;
+
+ if (!merge->pseudo_merge)
+ BUG("found non-pseudo merge commit at %"PRIuMAX, (uintmax_t)i);
+
+ commits_bitmap[i] = bitmap_new();
+
+ for (p = merge->commit->parents; p; p = p->next)
+ bitmap_set(commits_bitmap[i],
+ find_object_pos(writer, &p->item->object.oid,
+ NULL));
+ }
+
+ start = hashfile_total(f);
+
+ for (i = 0; i < writer->pseudo_merges_nr; i++) {
+ struct ewah_bitmap *commits_ewah = bitmap_to_ewah(commits_bitmap[i]);
+
+ pseudo_merge_ofs[i] = hashfile_total(f);
+
+ dump_bitmap(f, commits_ewah);
+ dump_bitmap(f, writer->selected[base+i].write_as);
+
+ ewah_free(commits_ewah);
+ }
+
+ next_ext = st_add(hashfile_total(f),
+ st_mult(kh_size(writer->pseudo_merge_commits),
+ sizeof(uint64_t)));
+
+ table_start = hashfile_total(f);
+
+ commits.alloc = kh_size(writer->pseudo_merge_commits);
+ CALLOC_ARRAY(commits.oid, commits.alloc);
+
+ for (i = kh_begin(writer->pseudo_merge_commits); i != kh_end(writer->pseudo_merge_commits); i++) {
+ if (!kh_exist(writer->pseudo_merge_commits, i))
+ continue;
+ oid_array_append(&commits, &kh_key(writer->pseudo_merge_commits, i));
+ }
+
+ oid_array_sort(&commits);
+
+ /* write lookup table (non-extended) */
+ for (i = 0; i < commits.nr; i++) {
+ int hash_pos;
+ struct pseudo_merge_commit_idx *c;
+
+ hash_pos = kh_get_oid_map(writer->pseudo_merge_commits,
+ commits.oid[i]);
+ if (hash_pos == kh_end(writer->pseudo_merge_commits))
+ BUG("could not find pseudo-merge commit %s",
+ oid_to_hex(&commits.oid[i]));
+
+ c = kh_value(writer->pseudo_merge_commits, hash_pos);
+
+ hashwrite_be32(f, find_object_pos(writer, &commits.oid[i],
+ NULL));
+ if (c->nr == 1)
+ hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[0]]);
+ else if (c->nr > 1) {
+ if (next_ext & ((uint64_t)1<<63))
+ die(_("too many pseudo-merges"));
+ hashwrite_be64(f, next_ext | ((uint64_t)1<<63));
+ next_ext = st_add3(next_ext,
+ sizeof(uint32_t),
+ st_mult(c->nr, sizeof(uint64_t)));
+ } else
+ BUG("expected commit '%s' to have at least one "
+ "pseudo-merge", oid_to_hex(&commits.oid[i]));
+ }
+
+ /* write lookup table (extended) */
+ for (i = 0; i < commits.nr; i++) {
+ int hash_pos;
+ struct pseudo_merge_commit_idx *c;
+
+ hash_pos = kh_get_oid_map(writer->pseudo_merge_commits,
+ commits.oid[i]);
+ if (hash_pos == kh_end(writer->pseudo_merge_commits))
+ BUG("could not find pseudo-merge commit %s",
+ oid_to_hex(&commits.oid[i]));
+
+ c = kh_value(writer->pseudo_merge_commits, hash_pos);
+ if (c->nr == 1)
+ continue;
+
+ hashwrite_be32(f, c->nr);
+ for (j = 0; j < c->nr; j++)
+ hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[j]]);
+ }
+
+ /* write positions for all pseudo merges */
+ for (i = 0; i < writer->pseudo_merges_nr; i++)
+ hashwrite_be64(f, pseudo_merge_ofs[i]);
+
+ hashwrite_be32(f, writer->pseudo_merges_nr);
+ hashwrite_be32(f, kh_size(writer->pseudo_merge_commits));
+ hashwrite_be64(f, table_start - start);
+ hashwrite_be64(f, hashfile_total(f) - start + sizeof(uint64_t));
+
+ for (i = 0; i < writer->pseudo_merges_nr; i++)
+ bitmap_free(commits_bitmap[i]);
+
+ oid_array_clear(&commits);
+ free(pseudo_merge_ofs);
+ free(commits_bitmap);
+}
+
static int table_cmp(const void *_va, const void *_vb, void *_data)
{
- uint32_t *commit_positions = _data;
- uint32_t a = commit_positions[*(uint32_t *)_va];
- uint32_t b = commit_positions[*(uint32_t *)_vb];
+ struct bitmap_writer *writer = _data;
+ struct bitmapped_commit *a = &writer->selected[*(uint32_t *)_va];
+ struct bitmapped_commit *b = &writer->selected[*(uint32_t *)_vb];
- if (a > b)
- return 1;
- else if (a < b)
+ if (a->commit_pos < b->commit_pos)
return -1;
+ else if (a->commit_pos > b->commit_pos)
+ return 1;
return 0;
}
-static void write_lookup_table(struct hashfile *f,
- uint32_t *commit_positions,
+static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f,
off_t *offsets)
{
uint32_t i;
uint32_t *table, *table_inv;
- ALLOC_ARRAY(table, writer.selected_nr);
- ALLOC_ARRAY(table_inv, writer.selected_nr);
+ ALLOC_ARRAY(table, bitmap_writer_nr_selected_commits(writer));
+ ALLOC_ARRAY(table_inv, bitmap_writer_nr_selected_commits(writer));
- for (i = 0; i < writer.selected_nr; i++)
+ for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++)
table[i] = i;
/*
@@ -714,17 +949,17 @@ static void write_lookup_table(struct hashfile *f,
* bitmap corresponds to j'th bitmapped commit (among the selected
* commits) in lex order of OIDs.
*/
- QSORT_S(table, writer.selected_nr, table_cmp, commit_positions);
+ QSORT_S(table, bitmap_writer_nr_selected_commits(writer), table_cmp, writer);
/* table_inv helps us discover that relationship (i'th bitmap
* to j'th commit by j = table_inv[i])
*/
- for (i = 0; i < writer.selected_nr; i++)
+ for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++)
table_inv[table[i]] = i;
trace2_region_enter("pack-bitmap-write", "writing_lookup_table", the_repository);
- for (i = 0; i < writer.selected_nr; i++) {
- struct bitmapped_commit *selected = &writer.selected[table[i]];
+ for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {
+ struct bitmapped_commit *selected = &writer->selected[table[i]];
uint32_t xor_offset = selected->xor_offset;
uint32_t xor_row;
@@ -745,7 +980,7 @@ static void write_lookup_table(struct hashfile *f,
xor_row = 0xffffffff;
}
- hashwrite_be32(f, commit_positions[table[i]]);
+ hashwrite_be32(f, writer->selected[table[i]].commit_pos);
hashwrite_be64(f, (uint64_t)offsets[table[i]]);
hashwrite_be32(f, xor_row);
}
@@ -767,13 +1002,14 @@ static void write_hash_cache(struct hashfile *f,
}
}
-void bitmap_writer_set_checksum(const unsigned char *sha1)
+void bitmap_writer_set_checksum(struct bitmap_writer *writer,
+ const unsigned char *sha1)
{
- hashcpy(writer.pack_checksum, sha1);
+ hashcpy(writer->pack_checksum, sha1, the_repository->hash_algo);
}
-void bitmap_writer_finish(struct pack_idx_entry **index,
- uint32_t index_nr,
+void bitmap_writer_finish(struct bitmap_writer *writer,
+ struct pack_idx_entry **index,
const char *filename,
uint16_t options)
{
@@ -781,7 +1017,6 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
static uint16_t flags = BITMAP_OPT_FULL_DAG;
struct strbuf tmp_file = STRBUF_INIT;
struct hashfile *f;
- uint32_t *commit_positions = NULL;
off_t *offsets = NULL;
uint32_t i;
@@ -789,42 +1024,47 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
int fd = odb_mkstemp(&tmp_file, "pack/tmp_bitmap_XXXXXX");
+ if (writer->pseudo_merges_nr)
+ options |= BITMAP_OPT_PSEUDO_MERGES;
+
f = hashfd(fd, tmp_file.buf);
memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE));
header.version = htons(default_version);
header.options = htons(flags | options);
- header.entry_count = htonl(writer.selected_nr);
- hashcpy(header.checksum, writer.pack_checksum);
+ header.entry_count = htonl(bitmap_writer_nr_selected_commits(writer));
+ hashcpy(header.checksum, writer->pack_checksum, the_repository->hash_algo);
hashwrite(f, &header, sizeof(header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz);
- dump_bitmap(f, writer.commits);
- dump_bitmap(f, writer.trees);
- dump_bitmap(f, writer.blobs);
- dump_bitmap(f, writer.tags);
+ dump_bitmap(f, writer->commits);
+ dump_bitmap(f, writer->trees);
+ dump_bitmap(f, writer->blobs);
+ dump_bitmap(f, writer->tags);
if (options & BITMAP_OPT_LOOKUP_TABLE)
- CALLOC_ARRAY(offsets, index_nr);
+ CALLOC_ARRAY(offsets, writer->to_pack->nr_objects);
- ALLOC_ARRAY(commit_positions, writer.selected_nr);
-
- for (i = 0; i < writer.selected_nr; i++) {
- struct bitmapped_commit *stored = &writer.selected[i];
- int commit_pos = oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
+ for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {
+ struct bitmapped_commit *stored = &writer->selected[i];
+ int commit_pos = oid_pos(&stored->commit->object.oid, index,
+ writer->to_pack->nr_objects,
+ oid_access);
if (commit_pos < 0)
BUG(_("trying to write commit not in index"));
-
- commit_positions[i] = commit_pos;
+ stored->commit_pos = commit_pos;
}
- write_selected_commits_v1(f, commit_positions, offsets);
+ write_selected_commits_v1(writer, f, offsets);
+
+ if (options & BITMAP_OPT_PSEUDO_MERGES)
+ write_pseudo_merges(writer, f);
if (options & BITMAP_OPT_LOOKUP_TABLE)
- write_lookup_table(f, commit_positions, offsets);
+ write_lookup_table(writer, f, offsets);
if (options & BITMAP_OPT_HASH_CACHE)
- write_hash_cache(f, index, index_nr);
+ write_hash_cache(f, index, writer->to_pack->nr_objects);
finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
@@ -836,6 +1076,5 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
die_errno("unable to rename temporary bitmap file to '%s'", filename);
strbuf_release(&tmp_file);
- free(commit_positions);
free(offsets);
}
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 878f378016..683f467051 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit.h"
#include "gettext.h"
@@ -20,6 +22,7 @@
#include "list-objects-filter-options.h"
#include "midx.h"
#include "config.h"
+#include "pseudo-merge.h"
/*
* An entry on the bitmap index, representing the bitmap for a given
@@ -51,13 +54,6 @@ struct bitmap_index {
struct packed_git *pack;
struct multi_pack_index *midx;
- /*
- * Mark the first `reuse_objects` in the packfile as reused:
- * they will be sent as-is without using them for repacking
- * calculations
- */
- uint32_t reuse_objects;
-
/* mmapped buffer of the whole bitmap index */
unsigned char *map;
size_t map_size; /* size of the mmaped buffer */
@@ -93,6 +89,9 @@ struct bitmap_index {
*/
unsigned char *table_lookup;
+ /* This contains the pseudo-merge cache within 'map' (if found). */
+ struct pseudo_merge_map pseudo_merges;
+
/*
* Extended index.
*
@@ -117,6 +116,13 @@ struct bitmap_index {
unsigned int version;
};
+static int pseudo_merges_satisfied_nr;
+static int pseudo_merges_cascades_nr;
+static int existing_bitmaps_hits_nr;
+static int existing_bitmaps_misses_nr;
+static int roots_with_bitmaps_nr;
+static int roots_without_bitmaps_nr;
+
static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st)
{
struct ewah_bitmap *parent;
@@ -136,17 +142,13 @@ static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st)
return composed;
}
-/*
- * Read a bitmap from the current read position on the mmaped
- * index, and increase the read position accordingly
- */
-static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
+struct ewah_bitmap *read_bitmap(const unsigned char *map,
+ size_t map_size, size_t *map_pos)
{
struct ewah_bitmap *b = ewah_pool_new();
- ssize_t bitmap_size = ewah_read_mmap(b,
- index->map + index->map_pos,
- index->map_size - index->map_pos);
+ ssize_t bitmap_size = ewah_read_mmap(b, map + *map_pos,
+ map_size - *map_pos);
if (bitmap_size < 0) {
error(_("failed to load bitmap index (corrupted?)"));
@@ -154,10 +156,20 @@ static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
return NULL;
}
- index->map_pos += bitmap_size;
+ *map_pos += bitmap_size;
+
return b;
}
+/*
+ * Read a bitmap from the current read position on the mmaped
+ * index, and increase the read position accordingly
+ */
+static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
+{
+ return read_bitmap(index->map, index->map_size, &index->map_pos);
+}
+
static uint32_t bitmap_num_objects(struct bitmap_index *index)
{
if (index->midx)
@@ -206,6 +218,46 @@ static int load_bitmap_header(struct bitmap_index *index)
index->table_lookup = (void *)(index_end - table_size);
index_end -= table_size;
}
+
+ if (flags & BITMAP_OPT_PSEUDO_MERGES) {
+ unsigned char *pseudo_merge_ofs;
+ size_t table_size;
+ uint32_t i;
+
+ if (sizeof(table_size) > index_end - index->map - header_size)
+ return error(_("corrupted bitmap index file (too short to fit pseudo-merge table header)"));
+
+ table_size = get_be64(index_end - 8);
+ if (table_size > index_end - index->map - header_size)
+ return error(_("corrupted bitmap index file (too short to fit pseudo-merge table)"));
+
+ if (git_env_bool("GIT_TEST_USE_PSEUDO_MERGES", 1)) {
+ const unsigned char *ext = (index_end - table_size);
+
+ index->pseudo_merges.map = index->map;
+ index->pseudo_merges.map_size = index->map_size;
+ index->pseudo_merges.commits = ext + get_be64(index_end - 16);
+ index->pseudo_merges.commits_nr = get_be32(index_end - 20);
+ index->pseudo_merges.nr = get_be32(index_end - 24);
+
+ if (st_add(st_mult(index->pseudo_merges.nr,
+ sizeof(uint64_t)),
+ 24) > table_size)
+ return error(_("corrupted bitmap index file, pseudo-merge table too short"));
+
+ CALLOC_ARRAY(index->pseudo_merges.v,
+ index->pseudo_merges.nr);
+
+ pseudo_merge_ofs = index_end - 24 -
+ (index->pseudo_merges.nr * sizeof(uint64_t));
+ for (i = 0; i < index->pseudo_merges.nr; i++) {
+ index->pseudo_merges.v[i].at = get_be64(pseudo_merge_ofs);
+ pseudo_merge_ofs += sizeof(uint64_t);
+ }
+ }
+
+ index_end -= table_size;
+ }
}
index->entry_count = ntohl(header->entry_count);
@@ -316,9 +368,8 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
char *midx_bitmap_filename(struct multi_pack_index *midx)
{
struct strbuf buf = STRBUF_INIT;
-
- get_midx_filename(&buf, midx->object_dir);
- strbuf_addf(&buf, "-%s.bitmap", hash_to_hex(get_midx_checksum(midx)));
+ get_midx_filename_ext(&buf, midx->object_dir, get_midx_checksum(midx),
+ MIDX_EXT_BITMAP);
return strbuf_detach(&buf, NULL);
}
@@ -338,7 +389,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
struct stat st;
char *bitmap_name = midx_bitmap_filename(midx);
int fd = git_open(bitmap_name);
- uint32_t i;
+ uint32_t i, preferred_pack;
struct packed_git *preferred;
if (fd < 0) {
@@ -375,7 +426,8 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
if (load_bitmap_header(bitmap_git) < 0)
goto cleanup;
- if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum)) {
+ if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum,
+ the_repository->hash_algo)) {
error(_("checksum doesn't match in MIDX and bitmap"));
goto cleanup;
}
@@ -393,7 +445,12 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
}
}
- preferred = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)];
+ if (midx_preferred_pack(bitmap_git->midx, &preferred_pack) < 0) {
+ warning(_("could not determine MIDX preferred pack"));
+ goto cleanup;
+ }
+
+ preferred = bitmap_git->midx->packs[preferred_pack];
if (!is_pack_valid(preferred)) {
warning(_("preferred pack (%s) is invalid"),
preferred->pack_name);
@@ -878,7 +935,7 @@ static inline int bitmap_position_packfile(struct bitmap_index *bitmap_git,
const struct object_id *oid)
{
uint32_t pos;
- off_t offset = find_pack_entry_one(oid->hash, bitmap_git->pack);
+ off_t offset = find_pack_entry_one(oid, bitmap_git->pack);
if (!offset)
return -1;
@@ -963,6 +1020,22 @@ static void show_commit(struct commit *commit UNUSED,
{
}
+static unsigned apply_pseudo_merges_for_commit_1(struct bitmap_index *bitmap_git,
+ struct bitmap *result,
+ struct commit *commit,
+ uint32_t commit_pos)
+{
+ int ret;
+
+ ret = apply_pseudo_merges_for_commit(&bitmap_git->pseudo_merges,
+ result, commit, commit_pos);
+
+ if (ret)
+ pseudo_merges_satisfied_nr += ret;
+
+ return ret;
+}
+
static int add_to_include_set(struct bitmap_index *bitmap_git,
struct include_data *data,
struct commit *commit,
@@ -978,11 +1051,19 @@ static int add_to_include_set(struct bitmap_index *bitmap_git,
partial = bitmap_for_commit(bitmap_git, commit);
if (partial) {
+ existing_bitmaps_hits_nr++;
+
bitmap_or_ewah(data->base, partial);
return 0;
}
+ existing_bitmaps_misses_nr++;
+
bitmap_set(data->base, bitmap_pos);
+ if (apply_pseudo_merges_for_commit_1(bitmap_git, data->base, commit,
+ bitmap_pos))
+ return 0;
+
return 1;
}
@@ -1033,8 +1114,12 @@ static int add_commit_to_bitmap(struct bitmap_index *bitmap_git,
{
struct ewah_bitmap *or_with = bitmap_for_commit(bitmap_git, commit);
- if (!or_with)
+ if (!or_with) {
+ existing_bitmaps_misses_nr++;
return 0;
+ }
+
+ existing_bitmaps_hits_nr++;
if (!*base)
*base = ewah_to_bitmap(or_with);
@@ -1101,12 +1186,27 @@ static void show_boundary_commit(struct commit *commit, void *_data)
}
}
-static void show_boundary_object(struct object *object,
- const char *name, void *data)
+static void show_boundary_object(struct object *object UNUSED,
+ const char *name UNUSED,
+ void *data UNUSED)
{
BUG("should not be called");
}
+static unsigned cascade_pseudo_merges_1(struct bitmap_index *bitmap_git,
+ struct bitmap *result,
+ struct bitmap *roots)
+{
+ int ret = cascade_pseudo_merges(&bitmap_git->pseudo_merges,
+ result, roots);
+ if (ret) {
+ pseudo_merges_cascades_nr++;
+ pseudo_merges_satisfied_nr += ret;
+ }
+
+ return ret;
+}
+
static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
struct rev_info *revs,
struct object_list *roots)
@@ -1116,6 +1216,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
unsigned int i;
unsigned int tmp_blobs, tmp_trees, tmp_tags;
int any_missing = 0;
+ int existing_bitmaps = 0;
cb.bitmap_git = bitmap_git;
cb.base = bitmap_new();
@@ -1123,6 +1224,25 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
revs->ignore_missing_links = 1;
+ if (bitmap_git->pseudo_merges.nr) {
+ struct bitmap *roots_bitmap = bitmap_new();
+ struct object_list *objects = NULL;
+
+ for (objects = roots; objects; objects = objects->next) {
+ struct object *object = objects->item;
+ int pos;
+
+ pos = bitmap_position(bitmap_git, &object->oid);
+ if (pos < 0)
+ continue;
+
+ bitmap_set(roots_bitmap, pos);
+ }
+
+ if (!cascade_pseudo_merges_1(bitmap_git, cb.base, roots_bitmap))
+ bitmap_free(roots_bitmap);
+ }
+
/*
* OR in any existing reachability bitmaps among `roots` into
* `cb.base`.
@@ -1134,8 +1254,10 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
continue;
if (add_commit_to_bitmap(bitmap_git, &cb.base,
- (struct commit *)object))
+ (struct commit *)object)) {
+ existing_bitmaps = 1;
continue;
+ }
any_missing = 1;
}
@@ -1143,6 +1265,9 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
if (!any_missing)
goto cleanup;
+ if (existing_bitmaps)
+ cascade_pseudo_merges_1(bitmap_git, cb.base, NULL);
+
tmp_blobs = revs->blob_objects;
tmp_trees = revs->tree_objects;
tmp_tags = revs->tag_objects;
@@ -1198,6 +1323,44 @@ cleanup:
return cb.base;
}
+struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_git,
+ struct commit *commit)
+{
+ struct commit_list *p;
+ struct bitmap *parents;
+ struct pseudo_merge *match = NULL;
+
+ if (!bitmap_git->pseudo_merges.nr)
+ return NULL;
+
+ parents = bitmap_new();
+
+ for (p = commit->parents; p; p = p->next) {
+ int pos = bitmap_position(bitmap_git, &p->item->object.oid);
+ if (pos < 0 || pos >= bitmap_num_objects(bitmap_git))
+ goto done;
+
+ bitmap_set(parents, pos);
+ }
+
+ match = pseudo_merge_for_parents(&bitmap_git->pseudo_merges,
+ parents);
+
+done:
+ bitmap_free(parents);
+ if (match)
+ return pseudo_merge_bitmap(&bitmap_git->pseudo_merges, match);
+
+ return NULL;
+}
+
+static void unsatisfy_all_pseudo_merges(struct bitmap_index *bitmap_git)
+{
+ uint32_t i;
+ for (i = 0; i < bitmap_git->pseudo_merges.nr; i++)
+ bitmap_git->pseudo_merges.v[i].satisfied = 0;
+}
+
static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
struct rev_info *revs,
struct object_list *roots,
@@ -1205,9 +1368,32 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
{
struct bitmap *base = NULL;
int needs_walk = 0;
+ unsigned existing_bitmaps = 0;
struct object_list *not_mapped = NULL;
+ unsatisfy_all_pseudo_merges(bitmap_git);
+
+ if (bitmap_git->pseudo_merges.nr) {
+ struct bitmap *roots_bitmap = bitmap_new();
+ struct object_list *objects = NULL;
+
+ for (objects = roots; objects; objects = objects->next) {
+ struct object *object = objects->item;
+ int pos;
+
+ pos = bitmap_position(bitmap_git, &object->oid);
+ if (pos < 0)
+ continue;
+
+ bitmap_set(roots_bitmap, pos);
+ }
+
+ base = bitmap_new();
+ cascade_pseudo_merges_1(bitmap_git, base, roots_bitmap);
+ bitmap_free(roots_bitmap);
+ }
+
/*
* Go through all the roots for the walk. The ones that have bitmaps
* on the bitmap index will be `or`ed together to form an initial
@@ -1218,11 +1404,21 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
*/
while (roots) {
struct object *object = roots->item;
+
roots = roots->next;
+ if (base) {
+ int pos = bitmap_position(bitmap_git, &object->oid);
+ if (pos > 0 && bitmap_get(base, pos)) {
+ object->flags |= SEEN;
+ continue;
+ }
+ }
+
if (object->type == OBJ_COMMIT &&
add_commit_to_bitmap(bitmap_git, &base, (struct commit *)object)) {
object->flags |= SEEN;
+ existing_bitmaps = 1;
continue;
}
@@ -1238,6 +1434,9 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
roots = not_mapped;
+ if (existing_bitmaps)
+ cascade_pseudo_merges_1(bitmap_git, base, NULL);
+
/*
* Let's iterate through all the roots that don't have bitmaps to
* check if we can determine them to be reachable from the existing
@@ -1258,8 +1457,12 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
object->flags &= ~UNINTERESTING;
add_pending_object(revs, object, "");
needs_walk = 1;
+
+ roots_without_bitmaps_nr++;
} else {
object->flags |= SEEN;
+
+ roots_with_bitmaps_nr++;
}
}
@@ -1279,6 +1482,8 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
base = fill_in_bitmap(bitmap_git, revs, base, seen);
}
+ object_list_free(&not_mapped);
+
return base;
}
@@ -1404,7 +1609,7 @@ static int in_bitmapped_pack(struct bitmap_index *bitmap_git,
if (bsearch_midx(&object->oid, bitmap_git->midx, NULL))
return 1;
} else {
- if (find_pack_entry_one(object->oid.hash, bitmap_git->pack) > 0)
+ if (find_pack_entry_one(&object->oid, bitmap_git->pack) > 0)
return 1;
}
}
@@ -1665,6 +1870,30 @@ static int can_filter_bitmap(struct list_objects_filter_options *filter)
return !filter_bitmap(NULL, NULL, NULL, filter);
}
+
+static void filter_packed_objects_from_bitmap(struct bitmap_index *bitmap_git,
+ struct bitmap *result)
+{
+ struct eindex *eindex = &bitmap_git->ext_index;
+ uint32_t objects_nr;
+ size_t i, pos;
+
+ objects_nr = bitmap_num_objects(bitmap_git);
+ pos = objects_nr / BITS_IN_EWORD;
+
+ if (pos > result->word_alloc)
+ pos = result->word_alloc;
+
+ memset(result->words, 0x00, sizeof(eword_t) * pos);
+ for (i = pos * BITS_IN_EWORD; i < objects_nr; i++)
+ bitmap_unset(result, i);
+
+ for (i = 0; i < eindex->count; ++i) {
+ if (has_object_pack(&eindex->objects[i]->oid))
+ bitmap_unset(result, objects_nr + i);
+ }
+}
+
struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
int filter_provided_objects)
{
@@ -1787,12 +2016,28 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
wants_bitmap,
&revs->filter);
+ if (revs->unpacked)
+ filter_packed_objects_from_bitmap(bitmap_git, wants_bitmap);
+
bitmap_git->result = wants_bitmap;
bitmap_git->haves = haves_bitmap;
object_list_free(&wants);
object_list_free(&haves);
+ trace2_data_intmax("bitmap", the_repository, "pseudo_merges_satisfied",
+ pseudo_merges_satisfied_nr);
+ trace2_data_intmax("bitmap", the_repository, "pseudo_merges_cascades",
+ pseudo_merges_cascades_nr);
+ trace2_data_intmax("bitmap", the_repository, "bitmap/hits",
+ existing_bitmaps_hits_nr);
+ trace2_data_intmax("bitmap", the_repository, "bitmap/misses",
+ existing_bitmaps_misses_nr);
+ trace2_data_intmax("bitmap", the_repository, "bitmap/roots_with_bitmap",
+ roots_with_bitmaps_nr);
+ trace2_data_intmax("bitmap", the_repository, "bitmap/roots_without_bitmap",
+ roots_without_bitmaps_nr);
+
return bitmap_git;
cleanup:
@@ -1806,49 +2051,30 @@ cleanup:
* -1 means "stop trying further objects"; 0 means we may or may not have
* reused, but you can keep feeding bits.
*/
-static int try_partial_reuse(struct packed_git *pack,
- size_t pos,
+static int try_partial_reuse(struct bitmap_index *bitmap_git,
+ struct bitmapped_pack *pack,
+ size_t bitmap_pos,
+ uint32_t pack_pos,
+ off_t offset,
struct bitmap *reuse,
struct pack_window **w_curs)
{
- off_t offset, delta_obj_offset;
+ off_t delta_obj_offset;
enum object_type type;
unsigned long size;
- /*
- * try_partial_reuse() is called either on (a) objects in the
- * bitmapped pack (in the case of a single-pack bitmap) or (b)
- * objects in the preferred pack of a multi-pack bitmap.
- * Importantly, the latter can pretend as if only a single pack
- * exists because:
- *
- * - The first pack->num_objects bits of a MIDX bitmap are
- * reserved for the preferred pack, and
- *
- * - Ties due to duplicate objects are always resolved in
- * favor of the preferred pack.
- *
- * Therefore we do not need to ever ask the MIDX for its copy of
- * an object by OID, since it will always select it from the
- * preferred pack. Likewise, the selected copy of the base
- * object for any deltas will reside in the same pack.
- *
- * This means that we can reuse pos when looking up the bit in
- * the reuse bitmap, too, since bits corresponding to the
- * preferred pack precede all bits from other packs.
- */
-
- if (pos >= pack->num_objects)
- return -1; /* not actually in the pack or MIDX preferred pack */
+ if (pack_pos >= pack->p->num_objects)
+ return -1; /* not actually in the pack */
- offset = delta_obj_offset = pack_pos_to_offset(pack, pos);
- type = unpack_object_header(pack, w_curs, &offset, &size);
+ delta_obj_offset = offset;
+ type = unpack_object_header(pack->p, w_curs, &offset, &size);
if (type < 0)
return -1; /* broken packfile, punt */
if (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA) {
off_t base_offset;
uint32_t base_pos;
+ uint32_t base_bitmap_pos;
/*
* Find the position of the base object so we can look it up
@@ -1858,24 +2084,48 @@ static int try_partial_reuse(struct packed_git *pack,
* and the normal slow path will complain about it in
* more detail.
*/
- base_offset = get_delta_base(pack, w_curs, &offset, type,
+ base_offset = get_delta_base(pack->p, w_curs, &offset, type,
delta_obj_offset);
if (!base_offset)
return 0;
- if (offset_to_pack_pos(pack, base_offset, &base_pos) < 0)
- return 0;
- /*
- * We assume delta dependencies always point backwards. This
- * lets us do a single pass, and is basically always true
- * due to the way OFS_DELTAs work. You would not typically
- * find REF_DELTA in a bitmapped pack, since we only bitmap
- * packs we write fresh, and OFS_DELTA is the default). But
- * let's double check to make sure the pack wasn't written with
- * odd parameters.
- */
- if (base_pos >= pos)
- return 0;
+ offset_to_pack_pos(pack->p, base_offset, &base_pos);
+
+ if (bitmap_is_midx(bitmap_git)) {
+ /*
+ * Cross-pack deltas are rejected for now, but could
+ * theoretically be supported in the future.
+ *
+ * We would need to ensure that we're sending both
+ * halves of the delta/base pair, regardless of whether
+ * or not the two cross a pack boundary. If they do,
+ * then we must convert the delta to an REF_DELTA to
+ * refer back to the base in the other pack.
+ * */
+ if (midx_pair_to_pack_pos(bitmap_git->midx,
+ pack->pack_int_id,
+ base_offset,
+ &base_bitmap_pos) < 0) {
+ return 0;
+ }
+ } else {
+ if (offset_to_pack_pos(pack->p, base_offset,
+ &base_pos) < 0)
+ return 0;
+ /*
+ * We assume delta dependencies always point backwards.
+ * This lets us do a single pass, and is basically
+ * always true due to the way OFS_DELTAs work. You would
+ * not typically find REF_DELTA in a bitmapped pack,
+ * since we only bitmap packs we write fresh, and
+ * OFS_DELTA is the default). But let's double check to
+ * make sure the pack wasn't written with odd
+ * parameters.
+ */
+ if (base_pos >= pack_pos)
+ return 0;
+ base_bitmap_pos = pack->bitmap_pos + base_pos;
+ }
/*
* And finally, if we're not sending the base as part of our
@@ -1885,77 +2135,91 @@ static int try_partial_reuse(struct packed_git *pack,
* to REF_DELTA on the fly. Better to just let the normal
* object_entry code path handle it.
*/
- if (!bitmap_get(reuse, base_pos))
+ if (!bitmap_get(reuse, base_bitmap_pos))
return 0;
}
/*
* If we got here, then the object is OK to reuse. Mark it.
*/
- bitmap_set(reuse, pos);
+ bitmap_set(reuse, bitmap_pos);
return 0;
}
-uint32_t midx_preferred_pack(struct bitmap_index *bitmap_git)
+static void reuse_partial_packfile_from_bitmap_1(struct bitmap_index *bitmap_git,
+ struct bitmapped_pack *pack,
+ struct bitmap *reuse)
{
- struct multi_pack_index *m = bitmap_git->midx;
- if (!m)
- BUG("midx_preferred_pack: requires non-empty MIDX");
- return nth_midxed_pack_int_id(m, pack_pos_to_midx(bitmap_git->midx, 0));
-}
-
-int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
- struct packed_git **packfile_out,
- 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;
struct pack_window *w_curs = NULL;
- size_t i = 0;
- uint32_t offset;
- uint32_t objects_nr;
+ size_t pos = pack->bitmap_pos / BITS_IN_EWORD;
- assert(result);
+ if (!pack->bitmap_pos) {
+ /*
+ * If we're processing the first (in the case of a MIDX, the
+ * preferred pack) or the only (in the case of single-pack
+ * bitmaps) pack, then we can reuse whole words at a time.
+ *
+ * This is because we know that any deltas in this range *must*
+ * have their bases chosen from the same pack, since:
+ *
+ * - In the single pack case, there is no other pack to choose
+ * them from.
+ *
+ * - In the MIDX case, the first pack is the preferred pack, so
+ * all ties are broken in favor of that pack (i.e. the one
+ * we're currently processing). So any duplicate bases will be
+ * resolved in favor of the pack we're processing.
+ */
+ while (pos < result->word_alloc &&
+ pos < pack->bitmap_nr / BITS_IN_EWORD &&
+ result->words[pos] == (eword_t)~0)
+ pos++;
+ memset(reuse->words, 0xFF, pos * sizeof(eword_t));
+ }
- load_reverse_index(r, bitmap_git);
+ for (; pos < result->word_alloc; pos++) {
+ eword_t word = result->words[pos];
+ size_t offset;
- if (bitmap_is_midx(bitmap_git))
- pack = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)];
- else
- pack = bitmap_git->pack;
- objects_nr = pack->num_objects;
+ for (offset = 0; offset < BITS_IN_EWORD; offset++) {
+ size_t bit_pos;
+ uint32_t pack_pos;
+ off_t ofs;
- while (i < result->word_alloc && result->words[i] == (eword_t)~0)
- i++;
+ if (word >> offset == 0)
+ break;
- /*
- * Don't mark objects not in the packfile or preferred pack. This bitmap
- * marks objects eligible for reuse, but the pack-reuse code only
- * understands how to reuse a single pack. Since the preferred pack is
- * guaranteed to have all bases for its deltas (in a multi-pack bitmap),
- * we use it instead of another pack. In single-pack bitmaps, the choice
- * is made for us.
- */
- if (i > objects_nr / BITS_IN_EWORD)
- i = objects_nr / BITS_IN_EWORD;
+ offset += ewah_bit_ctz64(word >> offset);
- reuse = bitmap_word_alloc(i);
- memset(reuse->words, 0xFF, i * sizeof(eword_t));
+ bit_pos = pos * BITS_IN_EWORD + offset;
+ if (bit_pos < pack->bitmap_pos)
+ continue;
+ if (bit_pos >= pack->bitmap_pos + pack->bitmap_nr)
+ goto done;
- for (; i < result->word_alloc; ++i) {
- eword_t word = result->words[i];
- size_t pos = (i * BITS_IN_EWORD);
+ if (bitmap_is_midx(bitmap_git)) {
+ uint32_t midx_pos;
- for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
- if ((word >> offset) == 0)
- break;
+ midx_pos = pack_pos_to_midx(bitmap_git->midx, bit_pos);
+ ofs = nth_midxed_offset(bitmap_git->midx, midx_pos);
- offset += ewah_bit_ctz64(word >> offset);
- if (try_partial_reuse(pack, pos + offset,
- reuse, &w_curs) < 0) {
+ if (offset_to_pack_pos(pack->p, ofs, &pack_pos) < 0)
+ BUG("could not find object in pack %s "
+ "at offset %"PRIuMAX" in MIDX",
+ pack_basename(pack->p), (uintmax_t)ofs);
+ } else {
+ pack_pos = cast_size_t_to_uint32_t(st_sub(bit_pos, pack->bitmap_pos));
+ if (pack_pos >= pack->p->num_objects)
+ BUG("advanced beyond the end of pack %s (%"PRIuMAX" > %"PRIu32")",
+ pack_basename(pack->p), (uintmax_t)pack_pos,
+ pack->p->num_objects);
+
+ ofs = pack_pos_to_offset(pack->p, pack_pos);
+ }
+
+ if (try_partial_reuse(bitmap_git, pack, bit_pos,
+ pack_pos, ofs, reuse, &w_curs) < 0) {
/*
* try_partial_reuse indicated we couldn't reuse
* any bits, so there is no point in trying more
@@ -1972,11 +2236,112 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
done:
unuse_pack(&w_curs);
+}
- *entries = bitmap_popcount(reuse);
- if (!*entries) {
- bitmap_free(reuse);
+static int bitmapped_pack_cmp(const void *va, const void *vb)
+{
+ const struct bitmapped_pack *a = va;
+ const struct bitmapped_pack *b = vb;
+
+ if (a->bitmap_pos < b->bitmap_pos)
return -1;
+ if (a->bitmap_pos > b->bitmap_pos)
+ return 1;
+ return 0;
+}
+
+void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
+ struct bitmapped_pack **packs_out,
+ size_t *packs_nr_out,
+ struct bitmap **reuse_out,
+ int multi_pack_reuse)
+{
+ struct repository *r = the_repository;
+ struct bitmapped_pack *packs = NULL;
+ struct bitmap *result = bitmap_git->result;
+ struct bitmap *reuse;
+ size_t i;
+ size_t packs_nr = 0, packs_alloc = 0;
+ size_t word_alloc;
+ uint32_t objects_nr = 0;
+
+ assert(result);
+
+ load_reverse_index(r, bitmap_git);
+
+ if (!bitmap_is_midx(bitmap_git) || !bitmap_git->midx->chunk_bitmapped_packs)
+ multi_pack_reuse = 0;
+
+ if (multi_pack_reuse) {
+ for (i = 0; i < bitmap_git->midx->num_packs; i++) {
+ struct bitmapped_pack pack;
+ if (nth_bitmapped_pack(r, bitmap_git->midx, &pack, i) < 0) {
+ warning(_("unable to load pack: '%s', disabling pack-reuse"),
+ bitmap_git->midx->pack_names[i]);
+ free(packs);
+ return;
+ }
+
+ if (!pack.bitmap_nr)
+ continue;
+
+ ALLOC_GROW(packs, packs_nr + 1, packs_alloc);
+ memcpy(&packs[packs_nr++], &pack, sizeof(pack));
+
+ objects_nr += pack.p->num_objects;
+ }
+
+ QSORT(packs, packs_nr, bitmapped_pack_cmp);
+ } else {
+ struct packed_git *pack;
+ uint32_t pack_int_id;
+
+ if (bitmap_is_midx(bitmap_git)) {
+ uint32_t preferred_pack_pos;
+
+ if (midx_preferred_pack(bitmap_git->midx, &preferred_pack_pos) < 0) {
+ warning(_("unable to compute preferred pack, disabling pack-reuse"));
+ return;
+ }
+
+ pack = bitmap_git->midx->packs[preferred_pack_pos];
+ pack_int_id = preferred_pack_pos;
+ } else {
+ pack = bitmap_git->pack;
+ /*
+ * Any value for 'pack_int_id' will do here. When we
+ * process the pack via try_partial_reuse(), we won't
+ * use the `pack_int_id` field since we have a non-MIDX
+ * bitmap.
+ *
+ * Use '-1' as a sentinel value to make it clear
+ * that we do not expect to read this field.
+ */
+ pack_int_id = -1;
+ }
+
+ ALLOC_GROW(packs, packs_nr + 1, packs_alloc);
+ packs[packs_nr].p = pack;
+ packs[packs_nr].pack_int_id = pack_int_id;
+ packs[packs_nr].bitmap_nr = pack->num_objects;
+ packs[packs_nr].bitmap_pos = 0;
+ packs[packs_nr].from_midx = bitmap_git->midx;
+
+ objects_nr = packs[packs_nr++].bitmap_nr;
+ }
+
+ word_alloc = objects_nr / BITS_IN_EWORD;
+ if (objects_nr % BITS_IN_EWORD)
+ word_alloc++;
+ reuse = bitmap_word_alloc(word_alloc);
+
+ for (i = 0; i < packs_nr; i++)
+ reuse_partial_packfile_from_bitmap_1(bitmap_git, &packs[i], reuse);
+
+ if (bitmap_is_empty(reuse)) {
+ free(packs);
+ bitmap_free(reuse);
+ return;
}
/*
@@ -1984,9 +2349,9 @@ done:
* need to be handled separately.
*/
bitmap_and_not(result, reuse);
- *packfile_out = pack;
+ *packs_out = packs;
+ *packs_nr_out = packs_nr;
*reuse_out = reuse;
- return 0;
}
int bitmap_walk_contains(struct bitmap_index *bitmap_git,
@@ -2267,6 +2632,132 @@ cleanup:
return 0;
}
+static void bit_pos_to_object_id(struct bitmap_index *bitmap_git,
+ uint32_t bit_pos,
+ struct object_id *oid)
+{
+ uint32_t index_pos;
+
+ if (bitmap_is_midx(bitmap_git))
+ index_pos = pack_pos_to_midx(bitmap_git->midx, bit_pos);
+ else
+ index_pos = pack_pos_to_index(bitmap_git->pack, bit_pos);
+
+ nth_bitmap_object_oid(bitmap_git, oid, index_pos);
+}
+
+int test_bitmap_pseudo_merges(struct repository *r)
+{
+ struct bitmap_index *bitmap_git;
+ uint32_t i;
+
+ bitmap_git = prepare_bitmap_git(r);
+ if (!bitmap_git || !bitmap_git->pseudo_merges.nr)
+ goto cleanup;
+
+ for (i = 0; i < bitmap_git->pseudo_merges.nr; i++) {
+ struct pseudo_merge *merge;
+ struct ewah_bitmap *commits_bitmap, *merge_bitmap;
+
+ merge = use_pseudo_merge(&bitmap_git->pseudo_merges,
+ &bitmap_git->pseudo_merges.v[i]);
+ commits_bitmap = merge->commits;
+ merge_bitmap = pseudo_merge_bitmap(&bitmap_git->pseudo_merges,
+ merge);
+
+ printf("at=%"PRIuMAX", commits=%"PRIuMAX", objects=%"PRIuMAX"\n",
+ (uintmax_t)merge->at,
+ (uintmax_t)ewah_bitmap_popcount(commits_bitmap),
+ (uintmax_t)ewah_bitmap_popcount(merge_bitmap));
+ }
+
+cleanup:
+ free_bitmap_index(bitmap_git);
+ return 0;
+}
+
+static void dump_ewah_object_ids(struct bitmap_index *bitmap_git,
+ struct ewah_bitmap *bitmap)
+
+{
+ struct ewah_iterator it;
+ eword_t word;
+ uint32_t pos = 0;
+
+ ewah_iterator_init(&it, bitmap);
+
+ while (ewah_iterator_next(&word, &it)) {
+ struct object_id oid;
+ uint32_t offset;
+
+ for (offset = 0; offset < BITS_IN_EWORD; offset++) {
+ if (!(word >> offset))
+ break;
+
+ offset += ewah_bit_ctz64(word >> offset);
+
+ bit_pos_to_object_id(bitmap_git, pos + offset, &oid);
+ printf("%s\n", oid_to_hex(&oid));
+ }
+ pos += BITS_IN_EWORD;
+ }
+}
+
+int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n)
+{
+ struct bitmap_index *bitmap_git;
+ struct pseudo_merge *merge;
+ int ret = 0;
+
+ bitmap_git = prepare_bitmap_git(r);
+ if (!bitmap_git || !bitmap_git->pseudo_merges.nr)
+ goto cleanup;
+
+ if (n >= bitmap_git->pseudo_merges.nr) {
+ ret = error(_("pseudo-merge index out of range "
+ "(%"PRIu32" >= %"PRIuMAX")"),
+ n, (uintmax_t)bitmap_git->pseudo_merges.nr);
+ goto cleanup;
+ }
+
+ merge = use_pseudo_merge(&bitmap_git->pseudo_merges,
+ &bitmap_git->pseudo_merges.v[n]);
+ dump_ewah_object_ids(bitmap_git, merge->commits);
+
+cleanup:
+ free_bitmap_index(bitmap_git);
+ return ret;
+}
+
+int test_bitmap_pseudo_merge_objects(struct repository *r, uint32_t n)
+{
+ struct bitmap_index *bitmap_git;
+ struct pseudo_merge *merge;
+ int ret = 0;
+
+ bitmap_git = prepare_bitmap_git(r);
+ if (!bitmap_git || !bitmap_git->pseudo_merges.nr)
+ goto cleanup;
+
+ if (n >= bitmap_git->pseudo_merges.nr) {
+ ret = error(_("pseudo-merge index out of range "
+ "(%"PRIu32" >= %"PRIuMAX")"),
+ n, (uintmax_t)bitmap_git->pseudo_merges.nr);
+ goto cleanup;
+ }
+
+ merge = use_pseudo_merge(&bitmap_git->pseudo_merges,
+ &bitmap_git->pseudo_merges.v[n]);
+
+ dump_ewah_object_ids(bitmap_git,
+ pseudo_merge_bitmap(&bitmap_git->pseudo_merges,
+ merge));
+
+cleanup:
+ free_bitmap_index(bitmap_git);
+ return ret;
+}
+
int rebuild_bitmap(const uint32_t *reposition,
struct ewah_bitmap *source,
struct bitmap *dest)
@@ -2373,6 +2864,7 @@ void free_bitmap_index(struct bitmap_index *b)
*/
close_midx_revindex(b->midx);
}
+ free_pseudo_merge_map(&b->pseudo_merges);
free(b);
}
diff --git a/pack-bitmap.h b/pack-bitmap.h
index 5273a6a019..d7f4b8b8e9 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -21,6 +21,7 @@ struct bitmap_disk_header {
unsigned char checksum[GIT_MAX_RAWSZ];
};
+#define BITMAP_PSEUDO_MERGE (1u<<21)
#define NEEDS_BITMAP (1u<<22)
/*
@@ -36,6 +37,7 @@ enum pack_bitmap_opts {
BITMAP_OPT_FULL_DAG = 0x1,
BITMAP_OPT_HASH_CACHE = 0x4,
BITMAP_OPT_LOOKUP_TABLE = 0x10,
+ BITMAP_OPT_PSEUDO_MERGES = 0x20,
};
enum pack_bitmap_flags {
@@ -52,6 +54,16 @@ typedef int (*show_reachable_fn)(
struct bitmap_index;
+struct bitmapped_pack {
+ struct packed_git *p;
+
+ uint32_t bitmap_pos;
+ uint32_t bitmap_nr;
+
+ struct multi_pack_index *from_midx; /* MIDX only */
+ uint32_t pack_int_id; /* MIDX only */
+};
+
struct bitmap_index *prepare_bitmap_git(struct repository *r);
struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx);
void count_bitmap_commit_list(struct bitmap_index *, uint32_t *commits,
@@ -62,17 +74,20 @@ 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);
+int test_bitmap_pseudo_merges(struct repository *r);
+int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n);
+int test_bitmap_pseudo_merge_objects(struct repository *r, uint32_t n);
#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);
-int reuse_partial_packfile_from_bitmap(struct bitmap_index *,
- struct packed_git **packfile,
- uint32_t *entries,
- struct bitmap **reuse_out);
+void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
+ struct bitmapped_pack **packs_out,
+ size_t *packs_nr_out,
+ struct bitmap **reuse_out,
+ int multi_pack_reuse);
int rebuild_existing_bitmaps(struct bitmap_index *, struct packing_data *mapping,
kh_oid_map_t *reused_bitmaps, int show_progress);
void free_bitmap_index(struct bitmap_index *);
@@ -88,11 +103,38 @@ int bitmap_has_oid_in_uninteresting(struct bitmap_index *, const struct object_i
off_t get_disk_usage_from_bitmap(struct bitmap_index *, struct rev_info *);
-void bitmap_writer_show_progress(int show);
-void bitmap_writer_set_checksum(const unsigned char *sha1);
-void bitmap_writer_build_type_index(struct packing_data *to_pack,
- struct pack_idx_entry **index,
- uint32_t index_nr);
+struct bitmap_writer {
+ struct ewah_bitmap *commits;
+ struct ewah_bitmap *trees;
+ struct ewah_bitmap *blobs;
+ struct ewah_bitmap *tags;
+
+ kh_oid_map_t *bitmaps;
+ struct packing_data *to_pack;
+
+ struct bitmapped_commit *selected;
+ unsigned int selected_nr, selected_alloc;
+
+ struct string_list pseudo_merge_groups;
+ kh_oid_map_t *pseudo_merge_commits; /* oid -> pseudo merge(s) */
+ uint32_t pseudo_merges_nr;
+
+ struct progress *progress;
+ int show_progress;
+ unsigned char pack_checksum[GIT_MAX_RAWSZ];
+};
+
+void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
+ struct packing_data *pdata);
+void bitmap_writer_show_progress(struct bitmap_writer *writer, int show);
+void bitmap_writer_set_checksum(struct bitmap_writer *writer,
+ const unsigned char *sha1);
+void bitmap_writer_build_type_index(struct bitmap_writer *writer,
+ struct pack_idx_entry **index);
+int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer,
+ const struct object_id *oid);
+void bitmap_writer_push_commit(struct bitmap_writer *writer,
+ struct commit *commit, unsigned pseudo_merge);
uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
struct packing_data *mapping);
int rebuild_bitmap(const uint32_t *reposition,
@@ -100,13 +142,17 @@ int rebuild_bitmap(const uint32_t *reposition,
struct bitmap *dest);
struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git,
struct commit *commit);
-void bitmap_writer_select_commits(struct commit **indexed_commits,
- unsigned int indexed_commits_nr, int max_bitmaps);
-int bitmap_writer_build(struct packing_data *to_pack);
-void bitmap_writer_finish(struct pack_idx_entry **index,
- uint32_t index_nr,
+struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_git,
+ struct commit *commit);
+void bitmap_writer_select_commits(struct bitmap_writer *writer,
+ struct commit **indexed_commits,
+ unsigned int indexed_commits_nr);
+int bitmap_writer_build(struct bitmap_writer *writer);
+void bitmap_writer_finish(struct bitmap_writer *writer,
+ struct pack_idx_entry **index,
const char *filename,
uint16_t options);
+void bitmap_writer_free(struct bitmap_writer *writer);
char *midx_bitmap_filename(struct multi_pack_index *midx);
char *pack_bitmap_filename(struct packed_git *p);
@@ -117,4 +163,6 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname);
int verify_bitmap_files(struct repository *r);
+struct ewah_bitmap *read_bitmap(const unsigned char *map,
+ size_t map_size, size_t *map_pos);
#endif
diff --git a/pack-check.c b/pack-check.c
index 977f619618..e883dae3f2 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -1,9 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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-file.h"
@@ -79,10 +80,11 @@ static int verify_packfile(struct repository *r,
} while (offset < pack_sig_ofs);
r->hash_algo->final_fn(hash, &ctx);
pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL);
- if (!hasheq(hash, pack_sig))
+ if (!hasheq(hash, pack_sig, the_repository->hash_algo))
err = error("%s pack checksum mismatch",
p->pack_name);
- if (!hasheq(index_base + index_size - r->hash_algo->hexsz, pack_sig))
+ if (!hasheq(index_base + index_size - r->hash_algo->hexsz, pack_sig,
+ the_repository->hash_algo))
err = error("%s pack checksum does not match its index",
p->pack_name);
unuse_pack(w_curs);
diff --git a/pack-objects.c b/pack-objects.c
index 1b8052bece..a9d9855063 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -3,7 +3,7 @@
#include "pack.h"
#include "pack-objects.h"
#include "packfile.h"
-#include "config.h"
+#include "parse.h"
static uint32_t locate_object_entry_hash(struct packing_data *pdata,
const struct object_id *oid,
@@ -151,6 +151,21 @@ void prepare_packing_data(struct repository *r, struct packing_data *pdata)
init_recursive_mutex(&pdata->odb_lock);
}
+void clear_packing_data(struct packing_data *pdata)
+{
+ if (!pdata)
+ return;
+
+ free(pdata->cruft_mtime);
+ free(pdata->in_pack);
+ free(pdata->in_pack_by_idx);
+ free(pdata->in_pack_pos);
+ free(pdata->index);
+ free(pdata->layer);
+ free(pdata->objects);
+ free(pdata->tree_depth);
+}
+
struct object_entry *packlist_alloc(struct packing_data *pdata,
const struct object_id *oid)
{
diff --git a/pack-objects.h b/pack-objects.h
index 0d78db40cb..b9898a4e64 100644
--- a/pack-objects.h
+++ b/pack-objects.h
@@ -169,6 +169,7 @@ struct packing_data {
};
void prepare_packing_data(struct repository *r, struct packing_data *pdata);
+void clear_packing_data(struct packing_data *pdata);
/* Protect access to object database */
static inline void packing_data_lock(struct packing_data *pdata)
diff --git a/pack-revindex.c b/pack-revindex.c
index 7fffcad912..22d3c23464 100644
--- a/pack-revindex.c
+++ b/pack-revindex.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "pack-revindex.h"
@@ -6,7 +8,7 @@
#include "packfile.h"
#include "strbuf.h"
#include "trace2.h"
-#include "config.h"
+#include "parse.h"
#include "midx.h"
#include "csum-file.h"
@@ -343,6 +345,17 @@ int verify_pack_revindex(struct packed_git *p)
return res;
}
+static int can_use_midx_ridx_chunk(struct multi_pack_index *m)
+{
+ if (!m->chunk_revindex)
+ return 0;
+ if (m->chunk_revindex_len != st_mult(sizeof(uint32_t), m->num_objects)) {
+ error(_("multi-pack-index reverse-index chunk is the wrong size"));
+ return 0;
+ }
+ return 1;
+}
+
int load_midx_revindex(struct multi_pack_index *m)
{
struct strbuf revindex_name = STRBUF_INIT;
@@ -351,7 +364,7 @@ int load_midx_revindex(struct multi_pack_index *m)
if (m->revindex_data)
return 0;
- if (m->chunk_revindex) {
+ if (can_use_midx_ridx_chunk(m)) {
/*
* If the MIDX `m` has a `RIDX` chunk, then use its contents for
* the reverse index instead of trying to load a separate `.rev`
@@ -370,7 +383,8 @@ int load_midx_revindex(struct multi_pack_index *m)
trace2_data_string("load_midx_revindex", the_repository,
"source", "rev");
- get_midx_rev_filename(&revindex_name, m);
+ get_midx_filename_ext(&revindex_name, m->object_dir,
+ get_midx_checksum(m), MIDX_EXT_REV);
ret = load_revindex_from_disk(revindex_name.buf,
m->num_objects,
@@ -509,19 +523,15 @@ static int midx_pack_order_cmp(const void *va, const void *vb)
return 0;
}
-int midx_to_pack_pos(struct multi_pack_index *m, uint32_t at, uint32_t *pos)
+static int midx_key_to_pack_pos(struct multi_pack_index *m,
+ struct midx_pack_key *key,
+ uint32_t *pos)
{
- struct midx_pack_key key;
uint32_t *found;
- if (!m->revindex_data)
- BUG("midx_to_pack_pos: reverse index not yet loaded");
- if (m->num_objects <= at)
- BUG("midx_to_pack_pos: out-of-bounds object at %"PRIu32, at);
-
- key.pack = nth_midxed_pack_int_id(m, at);
- key.offset = nth_midxed_offset(m, at);
- key.midx = m;
+ if (key->pack >= m->num_packs)
+ BUG("MIDX pack lookup out of bounds (%"PRIu32" >= %"PRIu32")",
+ key->pack, m->num_packs);
/*
* The preferred pack sorts first, so determine its identifier by
* looking at the first object in pseudo-pack order.
@@ -531,14 +541,43 @@ int midx_to_pack_pos(struct multi_pack_index *m, uint32_t at, uint32_t *pos)
* implicitly is preferred (and includes all its objects, since ties are
* broken first by pack identifier).
*/
- key.preferred_pack = nth_midxed_pack_int_id(m, pack_pos_to_midx(m, 0));
+ if (midx_preferred_pack(key->midx, &key->preferred_pack) < 0)
+ return error(_("could not determine preferred pack"));
- found = bsearch(&key, m->revindex_data, m->num_objects,
- sizeof(*m->revindex_data), midx_pack_order_cmp);
+ found = bsearch(key, m->revindex_data, m->num_objects,
+ sizeof(*m->revindex_data),
+ midx_pack_order_cmp);
if (!found)
- return error("bad offset for revindex");
+ return -1;
*pos = found - m->revindex_data;
return 0;
}
+
+int midx_to_pack_pos(struct multi_pack_index *m, uint32_t at, uint32_t *pos)
+{
+ struct midx_pack_key key;
+
+ if (!m->revindex_data)
+ BUG("midx_to_pack_pos: reverse index not yet loaded");
+ if (m->num_objects <= at)
+ BUG("midx_to_pack_pos: out-of-bounds object at %"PRIu32, at);
+
+ key.pack = nth_midxed_pack_int_id(m, at);
+ key.offset = nth_midxed_offset(m, at);
+ key.midx = m;
+
+ return midx_key_to_pack_pos(m, &key, pos);
+}
+
+int midx_pair_to_pack_pos(struct multi_pack_index *m, uint32_t pack_int_id,
+ off_t ofs, uint32_t *pos)
+{
+ struct midx_pack_key key = {
+ .pack = pack_int_id,
+ .offset = ofs,
+ .midx = m,
+ };
+ return midx_key_to_pack_pos(m, &key, pos);
+}
diff --git a/pack-revindex.h b/pack-revindex.h
index 6dd47efea1..422c2487ae 100644
--- a/pack-revindex.h
+++ b/pack-revindex.h
@@ -142,4 +142,7 @@ uint32_t pack_pos_to_midx(struct multi_pack_index *m, uint32_t pos);
*/
int midx_to_pack_pos(struct multi_pack_index *midx, uint32_t at, uint32_t *pos);
+int midx_pair_to_pack_pos(struct multi_pack_index *midx, uint32_t pack_id,
+ off_t ofs, uint32_t *pos);
+
#endif
diff --git a/pack-write.c b/pack-write.c
index b19ddf15b2..8c7dfddc5a 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@@ -6,11 +8,12 @@
#include "csum-file.h"
#include "remote.h"
#include "chunk-format.h"
+#include "object-file.h"
#include "pack-mtimes.h"
-#include "oidmap.h"
#include "pack-objects.h"
#include "pack-revindex.h"
#include "path.h"
+#include "repository.h"
#include "strbuf.h"
void reset_pack_idx_option(struct pack_idx_option *opts)
@@ -210,15 +213,15 @@ static void write_rev_trailer(struct hashfile *f, const unsigned char *hash)
hashwrite(f, hash, the_hash_algo->rawsz);
}
-const char *write_rev_file(const char *rev_name,
- struct pack_idx_entry **objects,
- uint32_t nr_objects,
- const unsigned char *hash,
- unsigned flags)
+char *write_rev_file(const char *rev_name,
+ struct pack_idx_entry **objects,
+ uint32_t nr_objects,
+ const unsigned char *hash,
+ unsigned flags)
{
uint32_t *pack_order;
uint32_t i;
- const char *ret;
+ char *ret;
if (!(flags & WRITE_REV) && !(flags & WRITE_REV_VERIFY))
return NULL;
@@ -236,13 +239,14 @@ const char *write_rev_file(const char *rev_name,
return ret;
}
-const char *write_rev_file_order(const char *rev_name,
- uint32_t *pack_order,
- uint32_t nr_objects,
- const unsigned char *hash,
- unsigned flags)
+char *write_rev_file_order(const char *rev_name,
+ uint32_t *pack_order,
+ uint32_t nr_objects,
+ const unsigned char *hash,
+ unsigned flags)
{
struct hashfile *f;
+ char *path;
int fd;
if ((flags & WRITE_REV) && (flags & WRITE_REV_VERIFY))
@@ -252,12 +256,13 @@ const char *write_rev_file_order(const char *rev_name,
if (!rev_name) {
struct strbuf tmp_file = STRBUF_INIT;
fd = odb_mkstemp(&tmp_file, "pack/tmp_rev_XXXXXX");
- rev_name = strbuf_detach(&tmp_file, NULL);
+ path = strbuf_detach(&tmp_file, NULL);
} else {
unlink(rev_name);
fd = xopen(rev_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
+ path = xstrdup(rev_name);
}
- f = hashfd(fd, rev_name);
+ f = hashfd(fd, path);
} else if (flags & WRITE_REV_VERIFY) {
struct stat statbuf;
if (stat(rev_name, &statbuf)) {
@@ -268,22 +273,24 @@ const char *write_rev_file_order(const char *rev_name,
die_errno(_("could not stat: %s"), rev_name);
}
f = hashfd_check(rev_name);
- } else
+ path = xstrdup(rev_name);
+ } else {
return NULL;
+ }
write_rev_header(f);
write_rev_index_positions(f, pack_order, nr_objects);
write_rev_trailer(f, hash);
- if (rev_name && adjust_shared_perm(rev_name) < 0)
- die(_("failed to make %s readable"), rev_name);
+ if (adjust_shared_perm(path) < 0)
+ die(_("failed to make %s readable"), path);
finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
CSUM_HASH_IN_STREAM | CSUM_CLOSE |
((flags & WRITE_IDX_VERIFY) ? 0 : CSUM_FSYNC));
- return rev_name;
+ return path;
}
static void write_mtimes_header(struct hashfile *f)
@@ -429,7 +436,8 @@ void fixup_pack_header_footer(int pack_fd,
if (partial_pack_offset == 0) {
unsigned char hash[GIT_MAX_RAWSZ];
the_hash_algo->final_fn(hash, &old_hash_ctx);
- if (!hasheq(hash, partial_pack_hash))
+ if (!hasheq(hash, partial_pack_hash,
+ the_repository->hash_algo))
die("Unexpected checksum for %s "
"(disk corruption?)", pack_name);
/*
@@ -471,7 +479,7 @@ char *index_pack_lockfile(int ip_out, int *is_well_formed)
packname[len-1] = 0;
if (skip_prefix(packname, "keep\t", &name))
return xstrfmt("%s/pack/pack-%s.keep",
- get_object_directory(), name);
+ repo_get_object_directory(the_repository), name);
return NULL;
}
if (is_well_formed)
@@ -525,9 +533,9 @@ static void rename_tmp_packfile(struct strbuf *name_prefix, const char *source,
size_t name_prefix_len = name_prefix->len;
strbuf_addstr(name_prefix, ext);
- if (rename(source, name_prefix->buf))
- die_errno("unable to rename temporary file to '%s'",
- name_prefix->buf);
+ if (finalize_object_file(source, name_prefix->buf))
+ die("unable to rename temporary file to '%s'",
+ name_prefix->buf);
strbuf_setlen(name_prefix, name_prefix_len);
}
@@ -546,7 +554,7 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
unsigned char hash[],
char **idx_tmp_name)
{
- const char *rev_tmp_name = NULL;
+ char *rev_tmp_name = NULL;
char *mtimes_tmp_name = NULL;
if (adjust_shared_perm(pack_tmp_name))
@@ -572,7 +580,7 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
if (mtimes_tmp_name)
rename_tmp_packfile(name_buffer, mtimes_tmp_name, "mtimes");
- free((char *)rev_tmp_name);
+ free(rev_tmp_name);
free(mtimes_tmp_name);
}
diff --git a/pack.h b/pack.h
index 3ab9e3f60c..02bbdfb19c 100644
--- a/pack.h
+++ b/pack.h
@@ -96,8 +96,8 @@ struct ref;
void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought);
-const char *write_rev_file(const char *rev_name, struct pack_idx_entry **objects, uint32_t nr_objects, const unsigned char *hash, unsigned flags);
-const char *write_rev_file_order(const char *rev_name, uint32_t *pack_order, uint32_t nr_objects, const unsigned char *hash, unsigned flags);
+char *write_rev_file(const char *rev_name, struct pack_idx_entry **objects, uint32_t nr_objects, const unsigned char *hash, unsigned flags);
+char *write_rev_file_order(const char *rev_name, uint32_t *pack_order, uint32_t nr_objects, const unsigned char *hash, unsigned flags);
/*
* The "hdr" output buffer should be at least this big, which will handle sizes
diff --git a/packfile.c b/packfile.c
index 9cc0a2e37a..9560f0a33c 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@@ -9,7 +11,6 @@
#include "mergesort.h"
#include "packfile.h"
#include "delta.h"
-#include "streaming.h"
#include "hash-lookup.h"
#include "commit.h"
#include "object.h"
@@ -29,23 +30,11 @@ char *odb_pack_name(struct strbuf *buf,
const char *ext)
{
strbuf_reset(buf);
- strbuf_addf(buf, "%s/pack/pack-%s.%s", get_object_directory(),
+ strbuf_addf(buf, "%s/pack/pack-%s.%s", repo_get_object_directory(the_repository),
hash_to_hex(hash), ext);
return buf->buf;
}
-char *sha1_pack_name(const unsigned char *sha1)
-{
- static struct strbuf buf = STRBUF_INIT;
- return odb_pack_name(&buf, sha1, "pack");
-}
-
-char *sha1_pack_index_name(const unsigned char *sha1)
-{
- static struct strbuf buf = STRBUF_INIT;
- return odb_pack_name(&buf, sha1, "idx");
-}
-
static unsigned int pack_used_ctr;
static unsigned int pack_mmap_calls;
static unsigned int peak_pack_open_windows;
@@ -236,14 +225,23 @@ static struct packed_git *alloc_packed_git(int extra)
return p;
}
+static char *pack_path_from_idx(const char *idx_path)
+{
+ size_t len;
+ if (!strip_suffix(idx_path, ".idx", &len))
+ BUG("idx path does not end in .idx: %s", idx_path);
+ return xstrfmt("%.*s.pack", (int)len, idx_path);
+}
+
struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
{
- const char *path = sha1_pack_name(sha1);
+ char *path = pack_path_from_idx(idx_path);
size_t alloc = st_add(strlen(path), 1);
struct packed_git *p = alloc_packed_git(alloc);
memcpy(p->pack_name, path, alloc); /* includes NUL */
- hashcpy(p->hash, sha1);
+ free(path);
+ hashcpy(p->hash, sha1, the_repository->hash_algo);
if (check_packed_git_idx(idx_path, p)) {
free(p);
return NULL;
@@ -597,7 +595,7 @@ static int open_packed_git_1(struct packed_git *p)
if (read_result != hashsz)
return error("packfile %s signature is unavailable", p->pack_name);
idx_hash = ((unsigned char *)p->index_data) + p->index_size - hashsz * 2;
- if (!hasheq(hash, idx_hash))
+ if (!hasheq(hash, idx_hash, the_repository->hash_algo))
return error("packfile %s does not match index", p->pack_name);
return 0;
}
@@ -752,7 +750,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
p->mtime = st.st_mtime;
if (path_len < the_hash_algo->hexsz ||
get_hash_hex(path + path_len - the_hash_algo->hexsz, p->hash))
- hashclr(p->hash);
+ hashclr(p->hash, the_repository->hash_algo);
return p;
}
@@ -814,9 +812,10 @@ static void report_pack_garbage(struct string_list *list)
report_helper(list, seen_bits, first, list->nr);
}
-void for_each_file_in_pack_dir(const char *objdir,
- each_file_in_pack_dir_fn fn,
- void *data)
+void for_each_file_in_pack_subdir(const char *objdir,
+ const char *subdir,
+ each_file_in_pack_dir_fn fn,
+ void *data)
{
struct strbuf path = STRBUF_INIT;
size_t dirnamelen;
@@ -825,6 +824,8 @@ void for_each_file_in_pack_dir(const char *objdir,
strbuf_addstr(&path, objdir);
strbuf_addstr(&path, "/pack");
+ if (subdir)
+ strbuf_addf(&path, "/%s", subdir);
dir = opendir(path.buf);
if (!dir) {
if (errno != ENOENT)
@@ -846,6 +847,13 @@ void for_each_file_in_pack_dir(const char *objdir,
strbuf_release(&path);
}
+void for_each_file_in_pack_dir(const char *objdir,
+ each_file_in_pack_dir_fn fn,
+ void *data)
+{
+ for_each_file_in_pack_subdir(objdir, NULL, fn, data);
+}
+
struct prepare_pack_data {
struct repository *r;
struct string_list *garbage;
@@ -879,7 +887,8 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
if (!report_garbage)
return;
- if (!strcmp(file_name, "multi-pack-index"))
+ if (!strcmp(file_name, "multi-pack-index") ||
+ !strcmp(file_name, "multi-pack-index.d"))
return;
if (starts_with(file_name, "multi-pack-index") &&
(ends_with(file_name, ".bitmap") || ends_with(file_name, ".rev")))
@@ -1063,7 +1072,7 @@ struct packed_git *get_all_packs(struct repository *r)
prepare_packed_git(r);
for (m = r->objects->multi_pack_index; m; m = m->next) {
uint32_t i;
- for (i = 0; i < m->num_packs; i++)
+ for (i = 0; i < m->num_packs + m->num_packs_in_base; i++)
prepare_midx_pack(r, m, i);
}
@@ -1230,7 +1239,9 @@ off_t get_delta_base(struct packed_git *p,
*curpos += used;
} else if (type == OBJ_REF_DELTA) {
/* The base entry _must_ be in the same pack */
- base_offset = find_pack_entry_one(base_info, p);
+ struct object_id oid;
+ oidread(&oid, base_info, the_repository->hash_algo);
+ base_offset = find_pack_entry_one(&oid, p);
*curpos += the_hash_algo->rawsz;
} else
die("I am totally screwed");
@@ -1252,7 +1263,7 @@ static int get_delta_base_oid(struct packed_git *p,
{
if (type == OBJ_REF_DELTA) {
unsigned char *base = use_pack(p, w_curs, curpos, NULL);
- oidread(oid, base);
+ oidread(oid, base, the_repository->hash_algo);
return 0;
} else if (type == OBJ_OFS_DELTA) {
uint32_t base_pos;
@@ -1594,7 +1605,7 @@ int packed_object_info(struct repository *r, struct packed_git *p,
goto out;
}
} else
- oidclr(oi->delta_base_oid);
+ oidclr(oi->delta_base_oid, the_repository->hash_algo);
}
oi->whence = in_delta_base_cache(p, obj_offset) ? OI_DBCACHED :
@@ -1918,10 +1929,12 @@ int nth_packed_object_id(struct object_id *oid,
return -1;
index += 4 * 256;
if (p->index_version == 1) {
- oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4));
+ oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4),
+ the_repository->hash_algo);
} else {
index += 8;
- oidread(oid, index + st_mult(hashsz, n));
+ oidread(oid, index + st_mult(hashsz, n),
+ the_repository->hash_algo);
}
return 0;
}
@@ -1960,11 +1973,10 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
}
}
-off_t find_pack_entry_one(const unsigned char *sha1,
- struct packed_git *p)
+off_t find_pack_entry_one(const struct object_id *oid,
+ struct packed_git *p)
{
const unsigned char *index = p->index_data;
- struct object_id oid;
uint32_t result;
if (!index) {
@@ -1972,8 +1984,7 @@ off_t find_pack_entry_one(const unsigned char *sha1,
return 0;
}
- hashcpy(oid.hash, sha1);
- if (bsearch_pack(&oid, p, &result))
+ if (bsearch_pack(oid, p, &result))
return nth_packed_object_offset(p, result);
return 0;
}
@@ -1999,13 +2010,13 @@ int is_pack_valid(struct packed_git *p)
return !open_packed_git(p);
}
-struct packed_git *find_sha1_pack(const unsigned char *sha1,
- struct packed_git *packs)
+struct packed_git *find_oid_pack(const struct object_id *oid,
+ struct packed_git *packs)
{
struct packed_git *p;
for (p = packs; p; p = p->next) {
- if (find_pack_entry_one(sha1, p))
+ if (find_pack_entry_one(oid, p))
return p;
}
return NULL;
@@ -2022,7 +2033,7 @@ static int fill_pack_entry(const struct object_id *oid,
oidset_contains(&p->bad_objects, oid))
return 0;
- offset = find_pack_entry_one(oid->hash, p);
+ offset = find_pack_entry_one(oid, p);
if (!offset)
return 0;
@@ -2137,14 +2148,6 @@ int has_object_kept_pack(const struct object_id *oid, unsigned flags)
return find_kept_pack_entry(the_repository, oid, flags, &e);
}
-int has_pack_index(const unsigned char *sha1)
-{
- struct stat st;
- if (stat(sha1_pack_index_name(sha1), &st))
- return 0;
- return 1;
-}
-
int for_each_object_in_pack(struct packed_git *p,
each_packed_object_fn cb, void *data,
enum for_each_object_flags flags)
@@ -2250,7 +2253,8 @@ static int add_promisor_object(const struct object_id *oid,
struct tree *tree = (struct tree *)obj;
struct tree_desc desc;
struct name_entry entry;
- if (init_tree_desc_gently(&desc, tree->buffer, tree->size, 0))
+ if (init_tree_desc_gently(&desc, &tree->object.oid,
+ tree->buffer, tree->size, 0))
/*
* Error messages are given when packs are
* verified, so do not print any here.
diff --git a/packfile.h b/packfile.h
index c3692308b8..08f88a7ff5 100644
--- a/packfile.h
+++ b/packfile.h
@@ -32,29 +32,28 @@ struct pack_entry {
char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext);
/*
- * Return the name of the (local) packfile with the specified sha1 in
- * its name. The return value is a pointer to memory that is
- * overwritten each time this function is called.
- */
-char *sha1_pack_name(const unsigned char *sha1);
-
-/*
- * Return the name of the (local) pack index file with the specified
- * sha1 in its name. The return value is a pointer to memory that is
- * overwritten each time this function is called.
- */
-char *sha1_pack_index_name(const unsigned char *sha1);
-
-/*
* Return the basename of the packfile, omitting any containing directory
* (e.g., "pack-1234abcd[...].pack").
*/
const char *pack_basename(struct packed_git *p);
+/*
+ * Parse the pack idx file found at idx_path and create a packed_git struct
+ * which can be used with find_pack_entry_one().
+ *
+ * You probably don't want to use this function! It skips most of the normal
+ * sanity checks (including whether we even have the matching .pack file),
+ * and does not add the resulting packed_git struct to the internal list of
+ * packs. You probably want add_packed_git() instead.
+ */
struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
typedef void each_file_in_pack_dir_fn(const char *full_path, size_t full_path_len,
- const char *file_pach, void *data);
+ const char *file_name, void *data);
+void for_each_file_in_pack_subdir(const char *objdir,
+ const char *subdir,
+ each_file_in_pack_dir_fn fn,
+ void *data);
void for_each_file_in_pack_dir(const char *objdir,
each_file_in_pack_dir_fn fn,
void *data);
@@ -80,8 +79,13 @@ struct packed_git *get_all_packs(struct repository *r);
*/
unsigned long repo_approximate_object_count(struct repository *r);
-struct packed_git *find_sha1_pack(const unsigned char *sha1,
- struct packed_git *packs);
+/*
+ * Find the pack within the "packs" list whose index contains the object "oid".
+ * For general object lookups, you probably don't want this; use
+ * find_pack_entry() instead.
+ */
+struct packed_git *find_oid_pack(const struct object_id *oid,
+ struct packed_git *packs);
void pack_report(void);
@@ -101,6 +105,8 @@ int close_pack_fd(struct packed_git *p);
uint32_t get_pack_fanout(struct packed_git *p, uint32_t value);
+struct raw_object_store;
+
unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
void close_pack_windows(struct packed_git *);
void close_pack(struct packed_git *);
@@ -148,10 +154,10 @@ int nth_packed_object_id(struct object_id *, struct packed_git *, uint32_t n);
off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
/*
- * If the object named sha1 is present in the specified packfile,
+ * If the object named by oid is present in the specified packfile,
* return its offset within the packfile; otherwise, return 0.
*/
-off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *);
+off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *);
int is_pack_valid(struct packed_git *);
void *unpack_entry(struct repository *r, struct packed_git *, off_t, enum object_type *, unsigned long *);
@@ -187,8 +193,6 @@ int find_kept_pack_entry(struct repository *r, const struct object_id *oid, unsi
int has_object_pack(const struct object_id *oid);
int has_object_kept_pack(const struct object_id *oid, unsigned flags);
-int has_pack_index(const unsigned char *sha1);
-
/*
* Return 1 if an object in a promisor packfile is or refers to the given
* object, 0 otherwise.
@@ -203,7 +207,7 @@ int is_promisor_object(const struct object_id *oid);
*
* This function should not be used directly. It is exposed here only so that we
* have a convenient entry-point for fuzz testing. For real uses, you should
- * probably use open_pack_index() or parse_pack_index() instead.
+ * probably use open_pack_index() instead.
*/
int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
size_t idx_size, struct packed_git *p);
diff --git a/pager.c b/pager.c
index b8822a9381..40b664f893 100644
--- a/pager.c
+++ b/pager.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "editor.h"
@@ -13,7 +15,8 @@ int pager_use_color = 1;
#endif
static struct child_process pager_process;
-static const char *pager_program;
+static char *pager_program;
+static int old_fd1 = -1, old_fd2 = -1;
/* Is the value coming back from term_columns() just a guess? */
static int term_columns_guessed;
@@ -23,10 +26,11 @@ static void close_pager_fds(void)
{
/* signal EOF to pager */
close(1);
- close(2);
+ if (old_fd2 != -1)
+ close(2);
}
-static void wait_for_pager_atexit(void)
+static void finish_pager(void)
{
fflush(stdout);
fflush(stderr);
@@ -34,8 +38,37 @@ static void wait_for_pager_atexit(void)
finish_command(&pager_process);
}
+static void wait_for_pager_atexit(void)
+{
+ if (old_fd1 == -1)
+ return;
+
+ finish_pager();
+}
+
+void wait_for_pager(void)
+{
+ if (old_fd1 == -1)
+ return;
+
+ finish_pager();
+ sigchain_pop_common();
+ unsetenv("GIT_PAGER_IN_USE");
+ dup2(old_fd1, 1);
+ close(old_fd1);
+ old_fd1 = -1;
+ if (old_fd2 != -1) {
+ dup2(old_fd2, 2);
+ close(old_fd2);
+ old_fd2 = -1;
+ }
+}
+
static void wait_for_pager_signal(int signo)
{
+ if (old_fd1 == -1)
+ return;
+
close_pager_fds();
finish_command_in_signal(&pager_process);
sigchain_pop(signo);
@@ -61,7 +94,8 @@ const char *git_pager(int stdout_is_tty)
pager = getenv("GIT_PAGER");
if (!pager) {
if (!pager_program)
- read_early_config(core_pager_config, NULL);
+ read_early_config(the_repository,
+ core_pager_config, NULL);
pager = pager_program;
}
if (!pager)
@@ -111,6 +145,7 @@ void prepare_pager_args(struct child_process *pager_process, const char *pager)
void setup_pager(void)
{
+ static int once = 0;
const char *pager = git_pager(isatty(1));
if (!pager)
@@ -137,17 +172,23 @@ void setup_pager(void)
pager_process.in = -1;
strvec_push(&pager_process.env, "GIT_PAGER_IN_USE");
if (start_command(&pager_process))
- return;
+ die("unable to execute pager '%s'", pager);
/* original process continues, but writes to the pipe */
+ old_fd1 = dup(1);
dup2(pager_process.in, 1);
- if (isatty(2))
+ if (isatty(2)) {
+ old_fd2 = dup(2);
dup2(pager_process.in, 2);
+ }
close(pager_process.in);
- /* this makes sure that the parent terminates after the pager */
sigchain_push_common(wait_for_pager_signal);
- atexit(wait_for_pager_atexit);
+
+ if (!once) {
+ once++;
+ atexit(wait_for_pager_atexit);
+ }
}
int pager_in_use(void)
@@ -196,6 +237,8 @@ int term_columns(void)
*/
void term_clear_line(void)
{
+ if (!isatty(2))
+ return;
if (is_terminal_dumb())
/*
* Fall back to print a terminal width worth of space
@@ -258,7 +301,7 @@ int check_pager_config(const char *cmd)
data.want = -1;
data.value = NULL;
- read_early_config(pager_command_config, &data);
+ read_early_config(the_repository, pager_command_config, &data);
if (data.value)
pager_program = data.value;
diff --git a/pager.h b/pager.h
index b77433026d..103ecac476 100644
--- a/pager.h
+++ b/pager.h
@@ -5,6 +5,7 @@ struct child_process;
const char *git_pager(int stdout_is_tty);
void setup_pager(void);
+void wait_for_pager(void);
int pager_in_use(void);
int term_columns(void);
void term_clear_line(void);
diff --git a/parallel-checkout.c b/parallel-checkout.c
index b5a714c711..01736f1352 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "entry.h"
@@ -429,13 +431,7 @@ static void send_one_item(int fd, struct parallel_checkout_item *pc_item)
fixed_portion->ident = pc_item->ca.ident;
fixed_portion->name_len = name_len;
fixed_portion->working_tree_encoding_len = working_tree_encoding_len;
- /*
- * We pad the unused bytes in the hash array because, otherwise,
- * Valgrind would complain about passing uninitialized bytes to a
- * write() syscall. The warning doesn't represent any real risk here,
- * but it could hinder the detection of actual errors.
- */
- oidcpy_with_padding(&fixed_portion->oid, &pc_item->ce->oid);
+ oidcpy(&fixed_portion->oid, &pc_item->ce->oid);
variant = data + sizeof(*fixed_portion);
if (working_tree_encoding_len) {
diff --git a/parse-options-cb.c b/parse-options-cb.c
index a24521dee0..166d35e0eb 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "parse-options.h"
#include "branch.h"
@@ -7,6 +9,7 @@
#include "environment.h"
#include "gettext.h"
#include "object-name.h"
+#include "setup.h"
#include "string-list.h"
#include "strvec.h"
#include "oid-array.h"
@@ -29,8 +32,6 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
opt->long_name);
if (v && v < MINIMUM_ABBREV)
v = MINIMUM_ABBREV;
- else if (v > the_hash_algo->hexsz)
- v = the_hash_algo->hexsz;
}
*(int *)(opt->value) = v;
return 0;
@@ -227,7 +228,9 @@ int parse_opt_strvec(const struct option *opt, const char *arg, int unset)
return 0;
}
-int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
+int parse_opt_noop_cb(const struct option *opt UNUSED,
+ const char *arg UNUSED,
+ int unset UNUSED)
{
return 0;
}
diff --git a/parse-options.c b/parse-options.c
index 60224cf8d0..33bfba0ed4 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -1,11 +1,10 @@
#include "git-compat-util.h"
#include "parse-options.h"
#include "abspath.h"
-#include "config.h"
-#include "commit.h"
-#include "color.h"
+#include "parse.h"
#include "gettext.h"
#include "strbuf.h"
+#include "string-list.h"
#include "utf8.h"
static int disallow_abbreviated_options;
@@ -61,50 +60,18 @@ static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p,
return 0;
}
-static void fix_filename(const char *prefix, char **file)
+static char *fix_filename(const char *prefix, const char *file)
{
if (!file || !*file)
- ; /* leave as NULL */
+ return NULL;
else
- *file = prefix_filename_except_for_dash(prefix, *file);
+ return prefix_filename_except_for_dash(prefix, file);
}
-static enum parse_opt_result opt_command_mode_error(
- const struct option *opt,
- const struct option *all_opts,
- enum opt_parsed flags)
-{
- const struct option *that;
- struct strbuf that_name = STRBUF_INIT;
-
- /*
- * Find the other option that was used to set the variable
- * already, and report that this is not compatible with it.
- */
- for (that = all_opts; that->type != OPTION_END; that++) {
- if (that == opt ||
- !(that->flags & PARSE_OPT_CMDMODE) ||
- that->value != opt->value ||
- that->defval != *(int *)opt->value)
- continue;
-
- if (that->long_name)
- strbuf_addf(&that_name, "--%s", that->long_name);
- else
- strbuf_addf(&that_name, "-%c", that->short_name);
- error(_("%s is incompatible with %s"),
- optname(opt, flags), that_name.buf);
- strbuf_release(&that_name);
- return PARSE_OPT_ERROR;
- }
- return error(_("%s : incompatible with something else"),
- optname(opt, flags));
-}
-
-static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
- const struct option *opt,
- const struct option *all_opts,
- enum opt_parsed flags)
+static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
+ const struct option *opt,
+ enum opt_parsed flags,
+ const char **argp)
{
const char *s, *arg;
const int unset = flags & OPT_UNSET;
@@ -117,14 +84,6 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG))
return error(_("%s takes no value"), optname(opt, flags));
- /*
- * Giving the same mode option twice, although unnecessary,
- * is not a grave error, so let it pass.
- */
- if ((opt->flags & PARSE_OPT_CMDMODE) &&
- *(int *)opt->value && *(int *)opt->value != opt->defval)
- return opt_command_mode_error(opt, all_opts, flags);
-
switch (opt->type) {
case OPTION_LOWLEVEL_CALLBACK:
return opt->ll_callback(p, opt, NULL, unset);
@@ -170,18 +129,24 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
return 0;
case OPTION_FILENAME:
+ {
+ const char *value;
+
+ FREE_AND_NULL(*(char **)opt->value);
+
err = 0;
+
if (unset)
- *(const char **)opt->value = NULL;
+ value = NULL;
else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
- *(const char **)opt->value = (const char *)opt->defval;
+ value = (const char *) opt->defval;
else
- err = get_arg(p, opt, flags, (const char **)opt->value);
+ err = get_arg(p, opt, flags, &value);
if (!err)
- fix_filename(p->prefix, (char **)opt->value);
+ *(char **)opt->value = fix_filename(p->prefix, value);
return err;
-
+ }
case OPTION_CALLBACK:
{
const char *p_arg = NULL;
@@ -199,6 +164,8 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
p_unset = 0;
p_arg = arg;
}
+ if (opt->flags & PARSE_OPT_CMDMODE)
+ *argp = p_arg;
if (opt->callback)
return (*opt->callback)(opt, p_arg, p_unset) ? (-1) : 0;
else
@@ -246,16 +213,92 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
}
}
+struct parse_opt_cmdmode_list {
+ int value, *value_ptr;
+ const struct option *opt;
+ const char *arg;
+ enum opt_parsed flags;
+ struct parse_opt_cmdmode_list *next;
+};
+
+static void build_cmdmode_list(struct parse_opt_ctx_t *ctx,
+ const struct option *opts)
+{
+ ctx->cmdmode_list = NULL;
+
+ for (; opts->type != OPTION_END; opts++) {
+ struct parse_opt_cmdmode_list *elem = ctx->cmdmode_list;
+ int *value_ptr = opts->value;
+
+ if (!(opts->flags & PARSE_OPT_CMDMODE) || !value_ptr)
+ continue;
+
+ while (elem && elem->value_ptr != value_ptr)
+ elem = elem->next;
+ if (elem)
+ continue;
+
+ CALLOC_ARRAY(elem, 1);
+ elem->value_ptr = value_ptr;
+ elem->value = *value_ptr;
+ elem->next = ctx->cmdmode_list;
+ ctx->cmdmode_list = elem;
+ }
+}
+
+static char *optnamearg(const struct option *opt, const char *arg,
+ enum opt_parsed flags)
+{
+ if (flags & OPT_SHORT)
+ return xstrfmt("-%c%s", opt->short_name, arg ? arg : "");
+ return xstrfmt("--%s%s%s%s", flags & OPT_UNSET ? "no-" : "",
+ opt->long_name, arg ? "=" : "", arg ? arg : "");
+}
+
+static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
+ const struct option *opt,
+ enum opt_parsed flags)
+{
+ const char *arg = NULL;
+ enum parse_opt_result result = do_get_value(p, opt, flags, &arg);
+ struct parse_opt_cmdmode_list *elem = p->cmdmode_list;
+ char *opt_name, *other_opt_name;
+
+ for (; elem; elem = elem->next) {
+ if (*elem->value_ptr == elem->value)
+ continue;
+
+ if (elem->opt &&
+ (elem->opt->flags | opt->flags) & PARSE_OPT_CMDMODE)
+ break;
+
+ elem->opt = opt;
+ elem->arg = arg;
+ elem->flags = flags;
+ elem->value = *elem->value_ptr;
+ }
+
+ if (result || !elem)
+ return result;
+
+ opt_name = optnamearg(opt, arg, flags);
+ other_opt_name = optnamearg(elem->opt, elem->arg, elem->flags);
+ error(_("options '%s' and '%s' cannot be used together"),
+ opt_name, other_opt_name);
+ free(opt_name);
+ free(other_opt_name);
+ return -1;
+}
+
static enum parse_opt_result parse_short_opt(struct parse_opt_ctx_t *p,
const struct option *options)
{
- const struct option *all_opts = options;
const struct option *numopt = NULL;
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
- return get_value(p, options, all_opts, OPT_SHORT);
+ return get_value(p, options, OPT_SHORT);
}
/*
@@ -313,98 +356,107 @@ static int is_alias(struct parse_opt_ctx_t *ctx,
return 0;
}
+struct parsed_option {
+ const struct option *option;
+ enum opt_parsed flags;
+};
+
+static void register_abbrev(struct parse_opt_ctx_t *p,
+ const struct option *option, enum opt_parsed flags,
+ struct parsed_option *abbrev,
+ struct parsed_option *ambiguous)
+{
+ if (p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)
+ return;
+ if (abbrev->option &&
+ !(abbrev->flags == flags && is_alias(p, abbrev->option, option))) {
+ /*
+ * If this is abbreviated, it is
+ * ambiguous. So when there is no
+ * exact match later, we need to
+ * error out.
+ */
+ ambiguous->option = abbrev->option;
+ ambiguous->flags = abbrev->flags;
+ }
+ abbrev->option = option;
+ abbrev->flags = flags;
+}
+
static enum parse_opt_result parse_long_opt(
struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
- const struct option *all_opts = options;
const char *arg_end = strchrnul(arg, '=');
- const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
- enum opt_parsed abbrev_flags = OPT_LONG, ambiguous_flags = OPT_LONG;
+ const char *arg_start = arg;
+ enum opt_parsed flags = OPT_LONG;
+ int arg_starts_with_no_no = 0;
+ struct parsed_option abbrev = { .option = NULL, .flags = OPT_LONG };
+ struct parsed_option ambiguous = { .option = NULL, .flags = OPT_LONG };
+
+ if (skip_prefix(arg_start, "no-", &arg_start)) {
+ if (skip_prefix(arg_start, "no-", &arg_start))
+ arg_starts_with_no_no = 1;
+ else
+ flags |= OPT_UNSET;
+ }
for (; options->type != OPTION_END; options++) {
const char *rest, *long_name = options->long_name;
- enum opt_parsed flags = OPT_LONG, opt_flags = OPT_LONG;
+ enum opt_parsed opt_flags = OPT_LONG;
+ int allow_unset = !(options->flags & PARSE_OPT_NONEG);
if (options->type == OPTION_SUBCOMMAND)
continue;
if (!long_name)
continue;
-again:
- if (!skip_prefix(arg, long_name, &rest))
- rest = NULL;
- if (!rest) {
- /* abbreviated? */
- if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT) &&
- !strncmp(long_name, arg, arg_end - arg)) {
-is_abbreviated:
- if (abbrev_option &&
- !is_alias(p, abbrev_option, options)) {
- /*
- * If this is abbreviated, it is
- * ambiguous. So when there is no
- * exact match later, we need to
- * error out.
- */
- ambiguous_option = abbrev_option;
- ambiguous_flags = abbrev_flags;
- }
- if (!(flags & OPT_UNSET) && *arg_end)
- p->opt = arg_end + 1;
- abbrev_option = options;
- abbrev_flags = flags ^ opt_flags;
- continue;
- }
- /* negation allowed? */
- if (options->flags & PARSE_OPT_NONEG)
- continue;
- /* negated and abbreviated very much? */
- if (starts_with("no-", arg)) {
- flags |= OPT_UNSET;
- goto is_abbreviated;
- }
- /* negated? */
- if (!starts_with(arg, "no-")) {
- if (skip_prefix(long_name, "no-", &long_name)) {
- opt_flags |= OPT_UNSET;
- goto again;
- }
- continue;
- }
- flags |= OPT_UNSET;
- if (!skip_prefix(arg + 3, long_name, &rest)) {
- /* abbreviated and negated? */
- if (starts_with(long_name, arg + 3))
- goto is_abbreviated;
- else
- continue;
- }
- }
- if (*rest) {
- if (*rest != '=')
+ if (skip_prefix(long_name, "no-", &long_name))
+ opt_flags |= OPT_UNSET;
+ else if (arg_starts_with_no_no)
+ continue;
+
+ if (((flags ^ opt_flags) & OPT_UNSET) && !allow_unset)
+ continue;
+
+ if (skip_prefix(arg_start, long_name, &rest)) {
+ if (*rest == '=')
+ p->opt = rest + 1;
+ else if (*rest)
continue;
- p->opt = rest + 1;
+ return get_value(p, options, flags ^ opt_flags);
}
- return get_value(p, options, all_opts, flags ^ opt_flags);
+
+ /* abbreviated? */
+ if (!strncmp(long_name, arg_start, arg_end - arg_start))
+ register_abbrev(p, options, flags ^ opt_flags,
+ &abbrev, &ambiguous);
+
+ /* negated and abbreviated very much? */
+ if (allow_unset && starts_with("no-", arg))
+ register_abbrev(p, options, OPT_UNSET ^ opt_flags,
+ &abbrev, &ambiguous);
}
- if (disallow_abbreviated_options && (ambiguous_option || abbrev_option))
+ if (disallow_abbreviated_options && (ambiguous.option || abbrev.option))
die("disallowed abbreviated or ambiguous option '%.*s'",
(int)(arg_end - arg), arg);
- if (ambiguous_option) {
+ if (ambiguous.option) {
error(_("ambiguous option: %s "
"(could be --%s%s or --%s%s)"),
arg,
- (ambiguous_flags & OPT_UNSET) ? "no-" : "",
- ambiguous_option->long_name,
- (abbrev_flags & OPT_UNSET) ? "no-" : "",
- abbrev_option->long_name);
+ (ambiguous.flags & OPT_UNSET) ? "no-" : "",
+ ambiguous.option->long_name,
+ (abbrev.flags & OPT_UNSET) ? "no-" : "",
+ abbrev.option->long_name);
return PARSE_OPT_HELP;
}
- if (abbrev_option)
- return get_value(p, abbrev_option, all_opts, abbrev_flags);
+ if (abbrev.option) {
+ if (*arg_end)
+ p->opt = arg_end + 1;
+ return get_value(p, abbrev.option, abbrev.flags);
+ }
return PARSE_OPT_UNKNOWN;
}
@@ -412,13 +464,11 @@ static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p,
const char *arg,
const struct option *options)
{
- const struct option *all_opts = options;
-
for (; options->type != OPTION_END; options++) {
if (!(options->flags & PARSE_OPT_NODASH))
continue;
if (options->short_name == arg[0] && arg[1] == '\0')
- return get_value(p, options, all_opts, OPT_SHORT);
+ return get_value(p, options, OPT_SHORT);
}
return PARSE_OPT_ERROR;
}
@@ -573,6 +623,7 @@ static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
(flags & PARSE_OPT_KEEP_ARGV0))
BUG("Can't keep argv0 if you don't have it");
parse_options_check(options);
+ build_cmdmode_list(ctx, options);
}
void parse_options_start(struct parse_opt_ctx_t *ctx,
@@ -893,13 +944,18 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
continue;
}
- if (!arg[2] /* "--" */ ||
- !strcmp(arg + 2, "end-of-options")) {
+ if (!arg[2] /* "--" */) {
if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
ctx->argc--;
ctx->argv++;
}
break;
+ } else if (!strcmp(arg + 2, "end-of-options")) {
+ if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) {
+ ctx->argc--;
+ ctx->argv++;
+ }
+ break;
}
if (internal_help && !strcmp(arg + 2, "help-all"))
@@ -1005,6 +1061,11 @@ int parse_options(int argc, const char **argv,
precompose_argv_prefix(argc, argv, NULL);
free_preprocessed_options(real_options);
free(ctx.alias_groups);
+ for (struct parse_opt_cmdmode_list *elem = ctx.cmdmode_list; elem;) {
+ struct parse_opt_cmdmode_list *next = elem->next;
+ free(elem);
+ elem = next;
+ }
return parse_options_end(&ctx);
}
@@ -1023,14 +1084,37 @@ static int usage_argh(const struct option *opts, FILE *outfile)
return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
}
-#define USAGE_OPTS_WIDTH 24
-#define USAGE_GAP 2
+static int usage_indent(FILE *outfile)
+{
+ return fprintf(outfile, " ");
+}
+
+#define USAGE_OPTS_WIDTH 26
+
+static void usage_padding(FILE *outfile, size_t pos)
+{
+ if (pos < USAGE_OPTS_WIDTH)
+ fprintf(outfile, "%*s", USAGE_OPTS_WIDTH - (int)pos, "");
+ else
+ fprintf(outfile, "\n%*s", USAGE_OPTS_WIDTH, "");
+}
+
+static const struct option *find_option_by_long_name(const struct option *opts,
+ const char *long_name)
+{
+ for (; opts->type != OPTION_END; opts++) {
+ if (opts->long_name && !strcmp(opts->long_name, long_name))
+ return opts;
+ }
+ return NULL;
+}
static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *ctx,
const char * const *usagestr,
const struct option *opts,
int full, int err)
{
+ const struct option *all_opts = opts;
FILE *outfile = err ? stderr : stdout;
int need_newline;
@@ -1111,8 +1195,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
for (; opts->type != OPTION_END; opts++) {
size_t pos;
- int pad;
const char *cp, *np;
+ const char *positive_name = NULL;
if (opts->type == OPTION_SUBCOMMAND)
continue;
@@ -1131,7 +1215,7 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
need_newline = 0;
}
- pos = fprintf(outfile, " ");
+ pos = usage_indent(outfile);
if (opts->short_name) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(outfile, "%c", opts->short_name);
@@ -1140,8 +1224,15 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
}
if (opts->long_name && opts->short_name)
pos += fprintf(outfile, ", ");
- if (opts->long_name)
- pos += fprintf(outfile, "--%s", opts->long_name);
+ if (opts->long_name) {
+ const char *long_name = opts->long_name;
+ if ((opts->flags & PARSE_OPT_NONEG) ||
+ skip_prefix(long_name, "no-", &positive_name))
+ pos += fprintf(outfile, "--%s", long_name);
+ else
+ pos += fprintf(outfile, "--[no-]%s", long_name);
+ }
+
if (opts->type == OPTION_NUMBER)
pos += utf8_fprintf(outfile, _("-NUM"));
@@ -1149,29 +1240,31 @@ 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 + 1)
- pad = -1;
- else if (pos <= USAGE_OPTS_WIDTH)
- pad = USAGE_OPTS_WIDTH - pos;
- else {
- fputc('\n', outfile);
- pad = USAGE_OPTS_WIDTH;
- }
if (opts->type == OPTION_ALIAS) {
- fprintf(outfile, "%*s", pad + USAGE_GAP, "");
+ usage_padding(outfile, pos);
fprintf_ln(outfile, _("alias of --%s"),
(const char *)opts->value);
continue;
}
- for (cp = _(opts->help); *cp; cp = np) {
+ for (cp = opts->help ? _(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;
+ usage_padding(outfile, pos);
+ fwrite(cp, 1, np - cp, outfile);
+ pos = 0;
+ }
+ fputc('\n', outfile);
+
+ if (positive_name) {
+ if (find_option_by_long_name(all_opts, positive_name))
+ continue;
+ pos = usage_indent(outfile);
+ pos += fprintf(outfile, "--%s", positive_name);
+ usage_padding(outfile, pos);
+ fprintf_ln(outfile, _("opposite of --no-%s"),
+ positive_name);
}
}
fputc('\n', outfile);
diff --git a/parse-options.h b/parse-options.h
index 4a66ec3bf5..ae15342390 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -355,7 +355,7 @@ struct option {
.type = OPTION_ALIAS, \
.short_name = (s), \
.long_name = (l), \
- .value = (source_long_name), \
+ .value = (char *)(source_long_name), \
}
#define OPT_SUBCOMMAND_F(l, v, fn, f) { \
@@ -445,6 +445,8 @@ static inline void die_for_incompatible_opt3(int opt1, const char *opt1_name,
/*----- incremental advanced APIs -----*/
+struct parse_opt_cmdmode_list;
+
/*
* It's okay for the caller to consume argv/argc in the usual way.
* Other fields of that structure are private to parse-options and should not
@@ -459,6 +461,7 @@ struct parse_opt_ctx_t {
unsigned has_subcommands;
const char *prefix;
const char **alias_groups; /* must be in groups of 3 elements! */
+ struct parse_opt_cmdmode_list *cmdmode_list;
};
void parse_options_start(struct parse_opt_ctx_t *ctx,
diff --git a/parse.c b/parse.c
new file mode 100644
index 0000000000..7a60a4f816
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,211 @@
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "parse.h"
+
+static uintmax_t get_unit_factor(const char *end)
+{
+ if (!*end)
+ return 1;
+ else if (!strcasecmp(end, "k"))
+ return 1024;
+ else if (!strcasecmp(end, "m"))
+ return 1024 * 1024;
+ else if (!strcasecmp(end, "g"))
+ return 1024 * 1024 * 1024;
+ return 0;
+}
+
+int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
+{
+ if (value && *value) {
+ char *end;
+ intmax_t val;
+ intmax_t factor;
+
+ if (max < 0)
+ BUG("max must be a positive integer");
+
+ errno = 0;
+ val = strtoimax(value, &end, 0);
+ if (errno == ERANGE)
+ return 0;
+ if (end == value) {
+ errno = EINVAL;
+ return 0;
+ }
+ factor = get_unit_factor(end);
+ if (!factor) {
+ errno = EINVAL;
+ return 0;
+ }
+ if ((val < 0 && -max / factor > val) ||
+ (val > 0 && max / factor < val)) {
+ errno = ERANGE;
+ return 0;
+ }
+ val *= factor;
+ *ret = val;
+ return 1;
+ }
+ errno = EINVAL;
+ return 0;
+}
+
+static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
+{
+ if (value && *value) {
+ char *end;
+ uintmax_t val;
+ uintmax_t factor;
+
+ /* negative values would be accepted by strtoumax */
+ if (strchr(value, '-')) {
+ errno = EINVAL;
+ return 0;
+ }
+ errno = 0;
+ val = strtoumax(value, &end, 0);
+ if (errno == ERANGE)
+ return 0;
+ if (end == value) {
+ errno = EINVAL;
+ return 0;
+ }
+ factor = get_unit_factor(end);
+ if (!factor) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (unsigned_mult_overflows(factor, val) ||
+ factor * val > max) {
+ errno = ERANGE;
+ return 0;
+ }
+ val *= factor;
+ *ret = val;
+ return 1;
+ }
+ errno = EINVAL;
+ return 0;
+}
+
+int git_parse_int(const char *value, int *ret)
+{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+int git_parse_int64(const char *value, int64_t *ret)
+{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+int git_parse_ulong(const char *value, unsigned long *ret)
+{
+ uintmax_t tmp;
+ if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+int git_parse_ssize_t(const char *value, ssize_t *ret)
+{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+int git_parse_double(const char *value, double *ret)
+{
+ char *end;
+ double val;
+ uintmax_t factor;
+
+ if (!value || !*value) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ errno = 0;
+ val = strtod(value, &end);
+ if (errno == ERANGE)
+ return 0;
+ if (end == value) {
+ errno = EINVAL;
+ return 0;
+ }
+ factor = get_unit_factor(end);
+ if (!factor) {
+ errno = EINVAL;
+ return 0;
+ }
+ val *= factor;
+ *ret = val;
+ return 1;
+}
+
+int git_parse_maybe_bool_text(const char *value)
+{
+ if (!value)
+ return 1;
+ if (!*value)
+ return 0;
+ if (!strcasecmp(value, "true")
+ || !strcasecmp(value, "yes")
+ || !strcasecmp(value, "on"))
+ return 1;
+ if (!strcasecmp(value, "false")
+ || !strcasecmp(value, "no")
+ || !strcasecmp(value, "off"))
+ return 0;
+ return -1;
+}
+
+int git_parse_maybe_bool(const char *value)
+{
+ int v = git_parse_maybe_bool_text(value);
+ if (0 <= v)
+ return v;
+ if (git_parse_int(value, &v))
+ return !!v;
+ return -1;
+}
+
+/*
+ * Parse environment variable 'k' as a boolean (in various
+ * possible spellings); if missing, use the default value 'def'.
+ */
+int git_env_bool(const char *k, int def)
+{
+ const char *v = getenv(k);
+ int val;
+ if (!v)
+ return def;
+ val = git_parse_maybe_bool(v);
+ if (val < 0)
+ die(_("bad boolean environment value '%s' for '%s'"),
+ v, k);
+ return val;
+}
+
+/*
+ * Parse environment variable 'k' as ulong with possibly a unit
+ * suffix; if missing, use the default value 'val'.
+ */
+unsigned long git_env_ulong(const char *k, unsigned long val)
+{
+ const char *v = getenv(k);
+ if (v && !git_parse_ulong(v, &val))
+ die(_("failed to parse %s"), k);
+ return val;
+}
diff --git a/parse.h b/parse.h
new file mode 100644
index 0000000000..6bb9a54d9a
--- /dev/null
+++ b/parse.h
@@ -0,0 +1,21 @@
+#ifndef PARSE_H
+#define PARSE_H
+
+int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);
+int git_parse_ssize_t(const char *, ssize_t *);
+int git_parse_ulong(const char *, unsigned long *);
+int git_parse_int(const char *value, int *ret);
+int git_parse_int64(const char *value, int64_t *ret);
+int git_parse_double(const char *value, double *ret);
+
+/**
+ * Same as `git_config_bool`, except that it returns -1 on error rather
+ * than dying.
+ */
+int git_parse_maybe_bool(const char *);
+int git_parse_maybe_bool_text(const char *value);
+
+int git_env_bool(const char *, int);
+unsigned long git_env_ulong(const char *, unsigned long);
+
+#endif /* PARSE_H */
diff --git a/patch-ids.c b/patch-ids.c
index c3e1a0dd21..a5683b462c 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -2,7 +2,6 @@
#include "diff.h"
#include "commit.h"
#include "hash.h"
-#include "hash-lookup.h"
#include "hex.h"
#include "patch-ids.h"
diff --git a/path.c b/path.c
index b84c2d1c44..93491bab14 100644
--- a/path.c
+++ b/path.c
@@ -1,11 +1,13 @@
/*
* Utilities for paths and pathnames
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#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"
@@ -28,9 +30,7 @@ static int get_st_mode_bits(const char *path, int *mode)
return 0;
}
-static char bad_path[] = "/bad-path/";
-
-static struct strbuf *get_pathname(void)
+struct strbuf *get_pathname(void)
{
static struct strbuf pathname_array[4] = {
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -59,21 +59,6 @@ static void strbuf_cleanup_path(struct strbuf *sb)
strbuf_remove(sb, 0, path - sb->buf);
}
-char *mksnpath(char *buf, size_t n, const char *fmt, ...)
-{
- va_list args;
- unsigned len;
-
- va_start(args, fmt);
- len = vsnprintf(buf, n, fmt, args);
- va_end(args);
- if (len >= n) {
- strlcpy(buf, bad_path, n);
- return buf;
- }
- return (char *)cleanup_path(buf);
-}
-
static int dir_prefix(const char *buf, const char *dir)
{
int len = strlen(dir);
@@ -380,15 +365,15 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,
strbuf_addstr(buf, LOCK_SUFFIX);
}
-void report_linked_checkout_garbage(void)
+void report_linked_checkout_garbage(struct repository *r)
{
struct strbuf sb = STRBUF_INIT;
const struct common_dir *p;
int len;
- if (!the_repository->different_commondir)
+ if (!r->different_commondir)
return;
- strbuf_addf(&sb, "%s/", get_git_dir());
+ strbuf_addf(&sb, "%s/", r->gitdir);
len = sb.len;
for (p = common_list; p->path; p++) {
const char *path = p->path;
@@ -432,9 +417,9 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
}
-static void do_git_path(const struct repository *repo,
- const struct worktree *wt, struct strbuf *buf,
- const char *fmt, va_list args)
+void repo_git_pathv(const struct repository *repo,
+ const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args)
{
int gitdir_len;
strbuf_worktree_gitdir(buf, repo, wt);
@@ -453,7 +438,7 @@ char *repo_git_path(const struct repository *repo,
struct strbuf path = STRBUF_INIT;
va_list args;
va_start(args, fmt);
- do_git_path(repo, NULL, &path, fmt, args);
+ repo_git_pathv(repo, NULL, &path, fmt, args);
va_end(args);
return strbuf_detach(&path, NULL);
}
@@ -464,46 +449,8 @@ void strbuf_repo_git_path(struct strbuf *sb,
{
va_list args;
va_start(args, fmt);
- do_git_path(repo, NULL, sb, fmt, args);
- va_end(args);
-}
-
-char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
-{
- va_list args;
- strbuf_reset(buf);
- va_start(args, fmt);
- do_git_path(the_repository, NULL, buf, fmt, args);
- va_end(args);
- return buf->buf;
-}
-
-void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- do_git_path(the_repository, NULL, sb, fmt, args);
- va_end(args);
-}
-
-const char *git_path(const char *fmt, ...)
-{
- struct strbuf *pathname = get_pathname();
- va_list args;
- va_start(args, fmt);
- do_git_path(the_repository, NULL, pathname, fmt, args);
- va_end(args);
- return pathname->buf;
-}
-
-char *git_pathdup(const char *fmt, ...)
-{
- struct strbuf path = STRBUF_INIT;
- va_list args;
- va_start(args, fmt);
- do_git_path(the_repository, NULL, &path, fmt, args);
+ repo_git_pathv(repo, NULL, sb, fmt, args);
va_end(args);
- return strbuf_detach(&path, NULL);
}
char *mkpathdup(const char *fmt, ...)
@@ -527,12 +474,17 @@ const char *mkpath(const char *fmt, ...)
return cleanup_path(pathname->buf);
}
-const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
+const char *worktree_git_path(struct repository *r,
+ const struct worktree *wt, const char *fmt, ...)
{
struct strbuf *pathname = get_pathname();
va_list args;
+
+ if (wt && wt->repo != r)
+ BUG("worktree not connected to expected repository");
+
va_start(args, fmt);
- do_git_path(the_repository, wt, pathname, fmt, args);
+ repo_git_pathv(r, wt, pathname, fmt, args);
va_end(args);
return pathname->buf;
}
@@ -632,26 +584,16 @@ int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
return err;
}
-static void do_git_common_path(const struct repository *repo,
- struct strbuf *buf,
- const char *fmt,
- va_list args)
-{
- strbuf_addstr(buf, repo->commondir);
- if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
- strbuf_addch(buf, '/');
- strbuf_vaddf(buf, fmt, args);
- strbuf_cleanup_path(buf);
-}
-
-const char *git_common_path(const char *fmt, ...)
+void repo_common_pathv(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt,
+ va_list args)
{
- struct strbuf *pathname = get_pathname();
- va_list args;
- va_start(args, fmt);
- do_git_common_path(the_repository, pathname, fmt, args);
- va_end(args);
- return pathname->buf;
+ strbuf_addstr(sb, repo->commondir);
+ if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
+ strbuf_addch(sb, '/');
+ strbuf_vaddf(sb, fmt, args);
+ strbuf_cleanup_path(sb);
}
void strbuf_git_common_path(struct strbuf *sb,
@@ -660,62 +602,10 @@ void strbuf_git_common_path(struct strbuf *sb,
{
va_list args;
va_start(args, fmt);
- do_git_common_path(repo, sb, fmt, args);
+ repo_common_pathv(repo, sb, fmt, args);
va_end(args);
}
-int validate_headref(const char *path)
-{
- struct stat st;
- char buffer[256];
- const char *refname;
- struct object_id oid;
- int fd;
- ssize_t len;
-
- if (lstat(path, &st) < 0)
- return -1;
-
- /* Make sure it is a "refs/.." symlink */
- if (S_ISLNK(st.st_mode)) {
- len = readlink(path, buffer, sizeof(buffer)-1);
- if (len >= 5 && !memcmp("refs/", buffer, 5))
- return 0;
- return -1;
- }
-
- /*
- * Anything else, just open it and try to see if it is a symbolic ref.
- */
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return -1;
- len = read_in_full(fd, buffer, sizeof(buffer)-1);
- close(fd);
-
- if (len < 0)
- return -1;
- buffer[len] = '\0';
-
- /*
- * Is it a symbolic ref?
- */
- if (skip_prefix(buffer, "ref:", &refname)) {
- while (isspace(*refname))
- refname++;
- if (starts_with(refname, "refs/"))
- return 0;
- }
-
- /*
- * Is this a detached HEAD?
- */
- if (!get_oid_hex(buffer, &oid))
- return 0;
-
- return -1;
-}
-
static struct passwd *getpw_str(const char *username, size_t len)
{
struct passwd *pw;
@@ -873,7 +763,7 @@ const char *enter_repo(const char *path, int strict)
return NULL;
}
-static int calc_shared_perm(int mode)
+int calc_shared_perm(int mode)
{
int tweak;
@@ -1590,7 +1480,5 @@ REPO_GIT_PATH_FUNC(merge_msg, "MERGE_MSG")
REPO_GIT_PATH_FUNC(merge_rr, "MERGE_RR")
REPO_GIT_PATH_FUNC(merge_mode, "MERGE_MODE")
REPO_GIT_PATH_FUNC(merge_head, "MERGE_HEAD")
-REPO_GIT_PATH_FUNC(merge_autostash, "MERGE_AUTOSTASH")
-REPO_GIT_PATH_FUNC(auto_merge, "AUTO_MERGE")
REPO_GIT_PATH_FUNC(fetch_head, "FETCH_HEAD")
REPO_GIT_PATH_FUNC(shallow, "shallow")
diff --git a/path.h b/path.h
index 639372edd9..e91d19fff6 100644
--- a/path.h
+++ b/path.h
@@ -4,6 +4,7 @@
struct repository;
struct strbuf;
struct string_list;
+struct worktree;
/*
* The result to all functions which return statically allocated memory may be
@@ -24,13 +25,7 @@ char *mkpathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
/*
- * Construct a path and place the result in the provided buffer `buf`.
- */
-char *mksnpath(char *buf, size_t n, const char *fmt, ...)
- __attribute__((format (printf, 3, 4)));
-
-/*
- * The `git_common_path` family of functions will construct a path into a
+ * The `strbuf_git_common_path` family of functions will construct a path into a
* repository's common git directory, which is shared by all worktrees.
*/
@@ -42,17 +37,13 @@ void strbuf_git_common_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
+void repo_common_pathv(const struct repository *repo,
+ struct strbuf *buf,
+ const char *fmt,
+ va_list args);
/*
- * Return a statically allocated path into the main repository's
- * (the_repository) common git directory.
- */
-const char *git_common_path(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-
-/*
- * The `git_path` family of functions will construct a path into a repository's
+ * The `repo_git_path` family of functions will construct a path into a repository's
* git directory.
*
* These functions will perform adjustments to the resultant path to account
@@ -72,6 +63,14 @@ char *repo_git_path(const struct repository *repo,
__attribute__((format (printf, 2, 3)));
/*
+ * Print a path into the git directory of repository `repo` into the provided
+ * buffer.
+ */
+void repo_git_pathv(const struct repository *repo,
+ const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args);
+
+/*
* Construct a path into the git directory of repository `repo` and append it
* to the provided buffer `sb`.
*/
@@ -81,32 +80,14 @@ void strbuf_repo_git_path(struct strbuf *sb,
__attribute__((format (printf, 3, 4)));
/*
- * Return a statically allocated path into the main repository's
- * (the_repository) git directory.
- */
-const char *git_path(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-/*
- * Return a path into the main repository's (the_repository) git directory.
- */
-char *git_pathdup(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and place it in the provided buffer `buf`, the contents of the buffer will
- * be overridden.
+ * Similar to repo_git_path() but can produce paths for a specified
+ * worktree instead of current one. When no worktree is given, then the path is
+ * computed relative to main worktree of the given repository.
*/
-char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
- __attribute__((format (printf, 2, 3)));
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and append it to the provided buffer `sb`.
- */
-void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
- __attribute__((format (printf, 2, 3)));
+const char *worktree_git_path(struct repository *r,
+ const struct worktree *wt,
+ const char *fmt, ...)
+ __attribute__((format (printf, 3, 4)));
/*
* Return a path into the worktree of repository `repo`.
@@ -144,24 +125,15 @@ int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
-void report_linked_checkout_garbage(void);
+void report_linked_checkout_garbage(struct repository *r);
/*
* You can define a static memoized git path like:
*
- * static GIT_PATH_FUNC(git_path_foo, "FOO")
+ * static REPO_GIT_PATH_FUNC(git_path_foo, "FOO")
*
* or use one of the global ones below.
*/
-#define GIT_PATH_FUNC(func, filename) \
- const char *func(void) \
- { \
- static char *ret; \
- if (!ret) \
- ret = git_pathdup(filename); \
- return ret; \
- }
-
#define REPO_GIT_PATH_FUNC(var, filename) \
const char *git_path_##var(struct repository *r) \
{ \
@@ -175,14 +147,12 @@ const char *git_path_merge_msg(struct repository *r);
const char *git_path_merge_rr(struct repository *r);
const char *git_path_merge_mode(struct repository *r);
const char *git_path_merge_head(struct repository *r);
-const char *git_path_merge_autostash(struct repository *r);
-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 calc_shared_perm(int mode);
int adjust_shared_perm(const char *path);
char *interpolate_path(const char *path, int real_home);
@@ -247,4 +217,99 @@ char *xdg_cache_home(const char *filename);
*/
void safe_create_dir(const char *dir, int share);
+/*
+ * Do not use this function. It is only exported to other subsystems until we
+ * can get rid of the below block of functions that implicitly rely on
+ * `the_repository`.
+ */
+struct strbuf *get_pathname(void);
+
+# ifdef USE_THE_REPOSITORY_VARIABLE
+# include "strbuf.h"
+# include "repository.h"
+
+/*
+ * Return a statically allocated path into the main repository's
+ * (the_repository) common git directory.
+ */
+__attribute__((format (printf, 1, 2)))
+static inline const char *git_common_path(const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ repo_common_pathv(the_repository, pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+/*
+ * Construct a path into the main repository's (the_repository) git directory
+ * and place it in the provided buffer `buf`, the contents of the buffer will
+ * be overridden.
+ */
+__attribute__((format (printf, 2, 3)))
+static inline char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
+{
+ va_list args;
+ strbuf_reset(buf);
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, buf, fmt, args);
+ va_end(args);
+ return buf->buf;
+}
+
+/*
+ * Construct a path into the main repository's (the_repository) git directory
+ * and append it to the provided buffer `sb`.
+ */
+__attribute__((format (printf, 2, 3)))
+static inline void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, sb, fmt, args);
+ va_end(args);
+}
+
+/*
+ * Return a statically allocated path into the main repository's
+ * (the_repository) git directory.
+ */
+__attribute__((format (printf, 1, 2)))
+static inline const char *git_path(const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+#define GIT_PATH_FUNC(func, filename) \
+ const char *func(void) \
+ { \
+ static char *ret; \
+ if (!ret) \
+ ret = git_pathdup(filename); \
+ return ret; \
+ }
+
+/*
+ * Return a path into the main repository's (the_repository) git directory.
+ */
+__attribute__((format (printf, 1, 2)))
+static inline char *git_pathdup(const char *fmt, ...)
+{
+ struct strbuf path = STRBUF_INIT;
+ va_list args;
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, &path, fmt, args);
+ va_end(args);
+ return strbuf_detach(&path, NULL);
+}
+
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+
#endif /* PATH_H */
diff --git a/pathspec.c b/pathspec.c
index 3a3a5724c4..0fc6f84a6e 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -1,6 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
-#include "config.h"
+#include "parse.h"
#include "dir.h"
#include "environment.h"
#include "gettext.h"
@@ -109,16 +111,37 @@ static struct pathspec_magic {
{ PATHSPEC_ATTR, '\0', "attr" },
};
-static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
+static void prefix_magic(struct strbuf *sb, int prefixlen,
+ unsigned magic, const char *element)
{
- int i;
- strbuf_addstr(sb, ":(");
- for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
- if (magic & pathspec_magic[i].bit) {
- if (sb->buf[sb->len - 1] != '(')
- strbuf_addch(sb, ',');
- strbuf_addstr(sb, pathspec_magic[i].name);
+ /* No magic was found in element, just add prefix magic */
+ if (!magic) {
+ strbuf_addf(sb, ":(prefix:%d)", prefixlen);
+ return;
+ }
+
+ /*
+ * At this point, we know that parse_element_magic() was able
+ * to extract some pathspec magic from element. So we know
+ * element is correctly formatted in either shorthand or
+ * longhand form
+ */
+ if (element[1] != '(') {
+ /* Process an element in shorthand form (e.g. ":!/<match>") */
+ strbuf_addstr(sb, ":(");
+ for (int i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+ if ((magic & pathspec_magic[i].bit) &&
+ pathspec_magic[i].mnemonic) {
+ if (sb->buf[sb->len - 1] != '(')
+ strbuf_addch(sb, ',');
+ strbuf_addstr(sb, pathspec_magic[i].name);
+ }
}
+ } else {
+ /* For the longhand form, we copy everything up to the final ')' */
+ size_t len = strchr(element, ')') - element;
+ strbuf_add(sb, element, len);
+ }
strbuf_addf(sb, ",prefix:%d)", prefixlen);
}
@@ -467,9 +490,14 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
match = prefix_path_gently(prefix, prefixlen,
&prefixlen, copyfrom);
if (!match) {
- const char *hint_path = get_git_work_tree();
+ const char *hint_path;
+
+ if (!have_git_dir())
+ die(_("'%s' is outside the directory tree"),
+ copyfrom);
+ hint_path = repo_get_work_tree(the_repository);
if (!hint_path)
- hint_path = get_git_dir();
+ hint_path = repo_get_git_dir(the_repository);
die(_("%s: '%s' is outside repository at '%s'"), elt,
copyfrom, absolute_path(hint_path));
}
@@ -488,7 +516,7 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
struct strbuf sb = STRBUF_INIT;
/* Preserve the actual prefix length of each pattern */
- prefix_magic(&sb, prefixlen, element_magic);
+ prefix_magic(&sb, prefixlen, element_magic, elt);
strbuf_addstr(&sb, match);
item->original = strbuf_detach(&sb, NULL);
diff --git a/pathspec.h b/pathspec.h
index fec4399bbc..de537cff3c 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -23,7 +23,7 @@ struct index_state;
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
/**
- * See glossary-context.txt for the syntax of pathspec.
+ * See glossary-content.txt for the syntax of pathspec.
* In memory, a pathspec set is represented by "struct pathspec" and is
* prepared by parse_pathspec().
*/
diff --git a/perl/FromCPAN/Error.pm b/perl/FromCPAN/Error.pm
index d82b71325c..5b97e0315d 100644
--- a/perl/FromCPAN/Error.pm
+++ b/perl/FromCPAN/Error.pm
@@ -1025,7 +1025,7 @@ C<:warndie> handlers added by Paul Evans <leonerd@leonerd.org.uk>
=head1 MAINTAINER
-Shlomi Fish, L<http://www.shlomifish.org/> .
+Shlomi Fish, L<https://www.shlomifish.org/> .
=head1 PAST MAINTAINERS
diff --git a/perl/Git.pm b/perl/Git.pm
index 117765dc73..667152c6c6 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -7,7 +7,7 @@ Git - Perl interface to the Git version control system
package Git;
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
@@ -187,7 +187,7 @@ sub repository {
try {
# Note that "--is-bare-repository" must come first, as
# --git-dir output could contain newlines.
- $out = $search->command([qw(rev-parse --is-bare-repository --git-dir)],
+ $out = $search->command([qw(rev-parse --is-bare-repository --absolute-git-dir)],
STDERR => 0);
} catch Git::Error::Command with {
throw Error::Simple("fatal: not a git repository: $opts{Directory}");
@@ -196,12 +196,12 @@ sub repository {
chomp $out;
my ($bare, $dir) = split /\n/, $out, 2;
- require Cwd;
- if ($bare ne 'true') {
- require File::Spec;
- File::Spec->file_name_is_absolute($dir) or $dir = $opts{Directory} . '/' . $dir;
- $opts{Repository} = Cwd::abs_path($dir);
+ # We know this is an absolute path, because we used
+ # --absolute-git-dir above.
+ $opts{Repository} = $dir;
+ if ($bare ne 'true') {
+ require Cwd;
# If --git-dir went ok, this shouldn't die either.
my $prefix = $search->command_oneline('rev-parse', '--show-prefix');
$dir = Cwd::abs_path($opts{Directory}) . '/';
@@ -214,8 +214,6 @@ sub repository {
$opts{WorkingCopy} = $dir;
$opts{WorkingSubdir} = $prefix;
- } else {
- $opts{Repository} = Cwd::abs_path($dir);
}
delete $opts{Directory};
@@ -418,7 +416,7 @@ argument is required if you want to see the command name in the error message,
and it is the fourth value returned by C<command_bidi_pipe()>. The call idiom
is:
- my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check');
+ my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe(qw(cat-file --batch-check));
print $out "000000000\n";
while (<$in>) { ... }
$r->command_close_bidi_pipe($pid, $in, $out, $ctx);
@@ -431,7 +429,7 @@ C<PIPE_IN> and C<PIPE_OUT> may be C<undef> if they have been closed prior to
calling this function. This may be useful in a query-response type of
commands where caller first writes a query and later reads response, eg:
- my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check');
+ my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe(qw(cat-file --batch-check));
print $out "000000000\n";
close $out;
while (<$in>) { ... }
diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm
index 895e759c57..475e90a6df 100644
--- a/perl/Git/I18N.pm
+++ b/perl/Git/I18N.pm
@@ -1,5 +1,5 @@
package Git::I18N;
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
BEGIN {
@@ -111,7 +111,7 @@ L<Locale::Messages>'s ngettext function or passthrough fallback function.
=head2 N__($)
No-operation that only returns its argument. Use this if you want xgettext to
-extract the text to the pot template but do not want to trigger retrival of the
+extract the text to the pot template but do not want to trigger retrieval of the
translation at run time.
=head1 AUTHOR
diff --git a/perl/Git/LoadCPAN.pm b/perl/Git/LoadCPAN.pm
index 0c360bc799..8c7fa805f9 100644
--- a/perl/Git/LoadCPAN.pm
+++ b/perl/Git/LoadCPAN.pm
@@ -1,5 +1,5 @@
package Git::LoadCPAN;
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
diff --git a/perl/Git/LoadCPAN/Error.pm b/perl/Git/LoadCPAN/Error.pm
index 5d84c20288..5cecb0fcd6 100644
--- a/perl/Git/LoadCPAN/Error.pm
+++ b/perl/Git/LoadCPAN/Error.pm
@@ -1,5 +1,5 @@
package Git::LoadCPAN::Error;
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
use Git::LoadCPAN (
diff --git a/perl/Git/LoadCPAN/Mail/Address.pm b/perl/Git/LoadCPAN/Mail/Address.pm
index 340e88a7a5..9f808090a6 100644
--- a/perl/Git/LoadCPAN/Mail/Address.pm
+++ b/perl/Git/LoadCPAN/Mail/Address.pm
@@ -1,5 +1,5 @@
package Git::LoadCPAN::Mail::Address;
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
use Git::LoadCPAN (
diff --git a/perl/Git/Packet.pm b/perl/Git/Packet.pm
index d144f5168f..d896e69523 100644
--- a/perl/Git/Packet.pm
+++ b/perl/Git/Packet.pm
@@ -1,5 +1,5 @@
package Git::Packet;
-use 5.008;
+use 5.008001;
use strict;
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
BEGIN {
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 6ce2e283c8..b0913ca1b6 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -763,7 +763,7 @@ sub prop_walk {
# this needs to be updated.
++$interesting_props if /^svn:(?:ignore|keywords|executable
|eol-style|mime-type
- |externals|needs-lock)$/x;
+ |externals|needs-lock|global-ignores)$/x;
}
&$sub($self, $p, $props) if $interesting_props;
@@ -1752,7 +1752,7 @@ sub tie_for_persistent_memoization {
END {
# Force cache writeout explicitly instead of waiting for
# global destruction to avoid segfault in Storable:
- # http://rt.cpan.org/Public/Bug/Display.html?id=36087
+ # https://rt.cpan.org/Public/Bug/Display.html?id=36087
unmemoize_svn_mergeinfo_functions();
}
diff --git a/pkt-line.c b/pkt-line.c
index af83a19f4d..24479eae4d 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -4,6 +4,7 @@
#include "gettext.h"
#include "hex.h"
#include "run-command.h"
+#include "sideband.h"
#include "trace.h"
#include "write-or-die.h"
@@ -462,8 +463,32 @@ enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
}
if ((options & PACKET_READ_CHOMP_NEWLINE) &&
- len && buffer[len-1] == '\n')
- len--;
+ len && buffer[len-1] == '\n') {
+ if (options & PACKET_READ_USE_SIDEBAND) {
+ int band = *buffer & 0xff;
+ switch (band) {
+ case 1:
+ /* Chomp newline for payload */
+ len--;
+ break;
+ case 2:
+ case 3:
+ /*
+ * Do not chomp newline for progress and error
+ * message.
+ */
+ break;
+ default:
+ /*
+ * Bad sideband, let's leave it to
+ * demultiplex_sideband() to catch this error.
+ */
+ break;
+ }
+ } else {
+ len--;
+ }
+ }
buffer[len] = 0;
if (options & PACKET_READ_REDACT_URI_PATH &&
@@ -592,17 +617,19 @@ void packet_reader_init(struct packet_reader *reader, int fd,
reader->options = options;
reader->me = "git";
reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
+ strbuf_init(&reader->scratch, 0);
}
enum packet_read_status packet_reader_read(struct packet_reader *reader)
{
- struct strbuf scratch = STRBUF_INIT;
-
if (reader->line_peeked) {
reader->line_peeked = 0;
return reader->status;
}
+ if (reader->use_sideband)
+ reader->options |= PACKET_READ_USE_SIDEBAND;
+
/*
* Consume all progress packets until a primary payload packet is
* received
@@ -620,7 +647,7 @@ enum packet_read_status packet_reader_read(struct packet_reader *reader)
break;
if (demultiplex_sideband(reader->me, reader->status,
reader->buffer, reader->pktlen, 1,
- &scratch, &sideband_type))
+ &reader->scratch, &sideband_type))
break;
}
diff --git a/pkt-line.h b/pkt-line.h
index 954eec8719..3b33cc64f3 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -2,7 +2,6 @@
#define PKTLINE_H
#include "strbuf.h"
-#include "sideband.h"
/*
* Write a packetized stream, where each line is preceded by
@@ -85,6 +84,7 @@ void packet_fflush(FILE *f);
#define PACKET_READ_DIE_ON_ERR_PACKET (1u<<2)
#define PACKET_READ_GENTLE_ON_READ_ERROR (1u<<3)
#define PACKET_READ_REDACT_URI_PATH (1u<<4)
+#define PACKET_READ_USE_SIDEBAND (1u<<5)
int packet_read(int fd, char *buffer, unsigned size, int options);
/*
@@ -194,6 +194,9 @@ struct packet_reader {
/* hash algorithm in use */
const struct git_hash_algo *hash_algo;
+
+ /* hold temporary sideband message */
+ struct strbuf scratch;
};
/*
diff --git a/po/README.md b/po/README.md
index 3e4f897d93..ec08aa24ad 100644
--- a/po/README.md
+++ b/po/README.md
@@ -412,7 +412,7 @@ There are some conventions that l10n contributors must follow:
- Do not use non-ASCII characters in the subject of a commit.
- The length of commit subject (first line of the commit log) should
- be less than 50 characters, and the length of other lines of the
+ be no more than 50 characters, and the length of other lines of the
commit log should be no more than 72 characters.
- Add "Signed-off-by" trailer to your commit log, like other commits
diff --git a/po/TEAMS b/po/TEAMS
index 87df7c6962..9a6a15cd9a 100644
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -7,8 +7,8 @@ Leader: Alexander Shopov <ash@kambanaria.org>
Language: ca (Catalan)
Repository: https://github.com/Softcatala/git-po
-Leader: Jordi Mas <jmas@softcatala.org>
-Members: Alex Henrie <alexhenrie24@gmail.com>
+Leader: Mikel Forcada <mikel.forcada@gmail.com>
+Members: Jordi Mas <jmas@softcatala.org>
Language: de (German)
Repository: https://github.com/ralfth/git
@@ -18,11 +18,11 @@ Members: Matthias Rüster <matthias.ruester@gmail.com>
Language: el (Greek)
Repository: https://github.com/vyruss/git-po-el
-Leader: Jimmy Angelakos <vyruss@hellug.gr>
+Members: Jimmy Angelakos <vyruss@hellug.gr>
Language: es (Spanish)
Repository: https://github.com/ChrisADR/git-po
-Leader: Christopher Díaz <christopher.diaz.riv@gmail.com>
+Members: Christopher Díaz <christopher.diaz.riv@gmail.com>
Language: fr (French)
Repository: https://github.com/jnavila/git
@@ -34,25 +34,25 @@ Repository: https://github.com/bagasme/git-po
Leader: Bagas Sanjaya <bagasdotme@gmail.com>
Language: is (Icelandic)
-Leader: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Members: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Language: it (Italian)
Repository: https://github.com/AlessandroMenti/git-po
-Leader: Alessandro Menti <alessandro.menti@alessandromenti.it>
+Members: Alessandro Menti <alessandro.menti@alessandromenti.it>
Language: ko (Korean)
Repository: https://github.com/git-l10n-ko/git-l10n-ko/
-Leader: Gwan-gyeong Mun <elongbug@gmail.com>
-Members: Changwoo Ryu <cwryu@debian.org>
+Members: Gwan-gyeong Mun <elongbug@gmail.com>
+ Changwoo Ryu <cwryu@debian.org>
Sihyeon Jang <uneedsihyeon@gmail.com>
Language: pl (Polish)
Repository: https://github.com/Arusekk/git-po
-Leader: Arusekk <arek_koz@o2.pl>
+Members: Arusekk <arek_koz@o2.pl>
Language: pt_PT (Portuguese - Portugal)
Repository: https://gitlab.com/alexandre1985/git-pt/
-Leader: Daniel Santos <dacs.git@brilhante.top>
+Members: Daniel Santos <dacs.git@brilhante.top>
Language: ru (Russian)
Repository: https://github.com/DJm00n/git-po-ru/
@@ -73,9 +73,10 @@ 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>
+Repository: https://github.com/Nekosha/git-po/
+Leader: Vũ Tiến Hưng <newcomerminecraft@gmail.com>
+Members: Trần Ngá»c Quân <vnwildman AT gmail.com>
+ Nguyá»…n Thái Ngá»c Duy <pclouds AT gmail.com>
Language: zh_CN (Simplified Chinese)
Repository: https://github.com/dyrone/git/
diff --git a/po/bg.po b/po/bg.po
index 61214c4b1c..1f7222dd93 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,7 +1,7 @@
# Bulgarian translation of git po-file.
-# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Alexander Shopov <ash@kambanaria.org>.
# This file is distributed under the same license as the git package.
-# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023.
+# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024.
# ========================
# DICTIONARY TO MERGE IN GIT GUI
# ------------------------
@@ -136,11 +136,13 @@
# island marks граници на групите
# reflog журнал на указателите
# hash контролна Ñума, изчиÑлÑване на контролна Ñума
-# fanout Ð¾Ñ‚ÐºÑŠÑ (разперване???)
+# fanout Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° разпределÑне
# idx - index of pack file, 1 index per 1 packfile
# midx, multi-pack index - файл Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети
# overlay mode - припокриващ режим (при изтеглÑнe)
# incremental file нараÑтващ файл
+# commit-graph граф Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ
+# commit-graph chain верига на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ
# split (commit-graphr) раздробен (граф Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ)
# clobber (a tag) презапиÑвам (етикет)
# blame извеждане на авторÑтво
@@ -187,6 +189,9 @@
# timestamp времево клеймо
# bare repository голо хранилище
# resolve-undo отмÑна на разрешените подаваниÑ
+# resolve conflict коригирам конфликт
+# resolve reference уÑтановÑване на обекта, Ñочен от указателÑ, проÑледÑване на указателÑ
+# cannot resolve reference не може да Ñе открие към какво Ñочи указателÑÑ‚
# maintenance задачи по поддръжка
# GLE поÑледна грешка в нишката - от GetLatError: https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
# lookup table таблица ÑÑŠÑ ÑъответÑтвиÑ
@@ -201,13 +206,42 @@
# superproject Ñвръхпроект
# rev-index обратен Ð¸Ð½Ð´ÐµÐºÑ (reverse index)
# dererging branches раздалечили Ñе клони
+# master/main branch оÑновен клон
+# unborn/orphan branch неродѐн клон (а не неÑъздаден) - клон без никакви подаваниÑ, включително и началното
+# parse анализ, анализирам
+# reinitialize repository занулÑване на хранилището и инициализиране
+# replay изпълнÑване/прилагане наново
+# BTMP chunk Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° побитова маÑка
+# OID fanout chunk Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° разпределÑнето
+# OID lookup chunk Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° търÑенето
+# autostash автоматично Ñкатано
+# symref файл Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ» (regular file that stores a string that begins with ref: refs/)
+# human-readable четим от хора
+# pseudoref пÑевдоуказател, напр. MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD или REBASE_HEAD
+# pseudo-merge пÑевдо Ñливанe
+# reftable таблица Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ð¸
+# its referent '%s' ÑÐ¾Ñ‡ÐµÑ‰Ð¸Ñ Ð³Ð¾ „%s“
+# dry run пробно изпълнение
+# mailmap файл за ÑъответÑтвиÑта на имената и адреÑите на е-поща
+# unit test поединичен теÑÑ‚
+# test suite група теÑтове
+#
# ------------------------
# „$var“ - може да не Ñработва за shell има gettext и eval_gettext - проверка - намират Ñе леÑно по „$
# ------------------------
+# Ñ‚Ð°Ð±ÑƒÐ»Ð°Ñ†Ð¸Ñ Ð² началото на реда Ñе Ð·Ð°Ð¼ÐµÐ½Ñ Ñ Ñ‡ÐµÑ‚Ð¸Ñ€Ð¸ интервала
+# по подобен начин отÑтъпът на примерна команда е четири интервала
+# ------------------------
+#
# FIXME
-# HEAD as a reference vs head of a branch
-# git update-index -h извежда Ñамо един ред, а не цÑлата помощ за опциите
# git fetch --al работи подобно на --all
+#
+# ----
+#
+# TODO
+# ПричаÑтно-Ñтрадателни форми (бъде отворен) -> Възвратно-Ñтрадателни форми (Ñе отвори)
+# <ТЕРМИÐ> -> ТЕРМИÐ
+#
# ------------------------
# export PO_FILE=bg.po
# msgattrib --only-fuzzy $PO_FILE > todo1.po
@@ -217,10 +251,10 @@
# 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.41\n"
+"Project-Id-Version: git 2.45\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-19 19:48+0200\n"
-"PO-Revision-Date: 2023-05-19 20:57+0300\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 13:20+0200\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
@@ -234,7 +268,7 @@ msgid "Huh (%s)?"
msgstr "ÐеуÑпешен анализ — „%s“."
msgid "could not read index"
-msgstr "индекÑÑŠÑ‚ не може да бъде прочетен"
+msgstr "индекÑÑŠÑ‚ не може да Ñе прочете"
msgid "binary"
msgstr "двоично"
@@ -253,7 +287,7 @@ msgid "could not stage '%s'"
msgstr "неуÑпешно добавÑне в индекÑа на „%s“"
msgid "could not write index"
-msgstr "индекÑÑŠÑ‚ не може да бъде запиÑан"
+msgstr "индекÑÑŠÑ‚ не може да Ñе запише"
#, c-format
msgid "updated %d path\n"
@@ -273,7 +307,7 @@ msgid "Revert"
msgstr "ОтмÑна"
msgid "Could not parse HEAD^{tree}"
-msgstr "УказателÑÑ‚ „HEAD^{tree}“ не може да бъде анализиран"
+msgstr "УказателÑÑ‚ „HEAD^{tree}“ не може да Ñе анализира"
#, c-format
msgid "reverted %d path\n"
@@ -376,7 +410,7 @@ msgid "path"
msgstr "път"
msgid "could not refresh index"
-msgstr "индекÑÑŠÑ‚ не може да бъде обновен"
+msgstr "индекÑÑŠÑ‚ не може да Ñе обнови"
#, c-format
msgid "Bye.\n"
@@ -402,8 +436,8 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"staging."
msgstr ""
-"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче ще бъде незабавно "
-"добавено към индекÑа."
+"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче незабавно ще Ñе "
+"добави към индекÑа."
msgid ""
"y - stage this hunk\n"
@@ -438,8 +472,8 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"stashing."
msgstr ""
-"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче ще бъде незабавно "
-"Ñкътано."
+"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче незабавно ще Ñе "
+"Ñкатае."
msgid ""
"y - stash this hunk\n"
@@ -474,8 +508,8 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"unstaging."
msgstr ""
-"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче ще бъде незабавно "
-"извадено от индекÑа."
+"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче незабавно ще Ñе "
+"извади от индекÑа."
msgid ""
"y - unstage this hunk\n"
@@ -511,8 +545,8 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"applying."
msgstr ""
-"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче ще бъде незабавно "
-"набелÑзано за прилагане."
+"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче незабавно ще Ñе "
+"набележи за прилагане."
msgid ""
"y - apply this hunk to index\n"
@@ -549,8 +583,8 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"discarding."
msgstr ""
-"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче ще бъде незабавно "
-"набелÑзано за занулÑване."
+"Ðко кръпката може да Ñе приложи чиÑто, редактираното парче незабавно ще Ñе "
+"набележи за занулÑване."
msgid ""
"y - discard this hunk from worktree\n"
@@ -722,13 +756,13 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"———\n"
"За да пропуÑнете редовете, започващи Ñ â€ž%c“: заменете знака Ñ â€ž “ (Ñтават "
"контекÑÑ‚)\n"
"За да пропуÑнете редовете, започващи Ñ â€ž%c“: изтрийте ги.\n"
-"Редовете, които започват Ñ â€ž%c“ ще бъдат пропуÑнати.\n"
+"Редовете, които започват Ñ â€ž%s“ ще Ñе пропуÑнат.\n"
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
@@ -736,7 +770,7 @@ msgid ""
"aborted and the hunk is left unchanged.\n"
msgstr ""
"Ðко е невъзможно чиÑто прилагане на кода, ще може пак да редактирате. Ðко\n"
-"изтриете вÑички редове от парчето код, то ще бъде оÑтавено непроменено, а\n"
+"изтриете вÑички редове от парчето код, то ще Ñе оÑтави непроменено, а\n"
"редактирането — отказано.\n"
msgid "could not parse hunk header"
@@ -755,8 +789,8 @@ msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
"Редактираното парче не може да Ñе приложи. Да Ñе продължи ли Ñ "
-"редактирането? (текущите редакции ще Ñе отменÑÑ‚ при отказ!): „y“ (да)/ "
-"„n“ (не)? "
+"редактирането? (текущите редакции ще Ñе отменÑÑ‚ при отказ!): „y“ (да)/ „n“ "
+"(не)? "
msgid "The selected hunks do not apply to the index!"
msgstr "Избраните парчета не може да Ñе добавÑÑ‚ в индекÑа!"
@@ -776,6 +810,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j — без решение за парчето, към Ñледващото парче без решение\n"
@@ -786,7 +821,13 @@ msgstr ""
"/ — търÑене на парче, напаÑващо към даден регулÑрен израз\n"
"s — разделÑне на текущото парче на по-малки\n"
"e — ръчно редактиране на текущото парче\n"
-"? — извеждане не помощта\n"
+"p — извеждане на текущото парче\n"
+"P — извеждане на текущото парче през програма за прелиÑтване\n"
+"? — извеждане на помощта\n"
+
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "Очаква Ñе Ñамо един знак, а не „%s“"
msgid "No previous hunk"
msgstr "ÐÑма друго парче преди това"
@@ -827,18 +868,28 @@ msgid "No hunk matches the given pattern"
msgstr "Ðикое парче не напаÑва на регулÑÑ€Ð½Ð¸Ñ Ð¸Ð·Ñ€Ð°Ð·"
msgid "Sorry, cannot split this hunk"
-msgstr "Това парче не може да бъде разделено"
+msgstr "Това парче не може да Ñе раздели"
#, c-format
msgid "Split into %d hunks."
msgstr "РазделÑне на %d парчета."
msgid "Sorry, cannot edit this hunk"
-msgstr "Това парче не може да бъде редактирано"
+msgstr "Това парче не може да Ñе редактира"
+
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Ðепозната команда „%s“ (за помощ натиÑнете „?“)"
msgid "'git apply' failed"
msgstr "неуÑпешно изпълнение на „git apply“"
+msgid "No changes."
+msgstr "ÐÑма промѐни."
+
+msgid "Only binary files changed."
+msgstr "Променени Ñа Ñамо двоични файлове."
+
#, c-format
msgid ""
"\n"
@@ -850,8 +901,8 @@ msgstr ""
" git config advice.%s false"
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sподÑказка: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sподÑказка:%s%.*s%s\n"
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr "Отбирането на Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ðµ блокирано от неÑлети файлове."
@@ -868,9 +919,8 @@ msgstr "Издърпването е блокирано от неÑлети фаÐ
msgid "Reverting is not possible because you have unmerged files."
msgstr "ОтмÑната е блокирана от неÑлети файлове."
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "ДейÑтвието „%s“ е блокирано от неÑлети файлове."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "Пребазирането е блокирано от неÑлети файлове."
msgid ""
"Fix them up in the work tree, and then use 'git add/rm <file>'\n"
@@ -902,11 +952,11 @@ msgid ""
msgstr ""
"Раздалечили Ñе клони не може да Ñе превъртÑÑ‚. Ползвайте:\n"
"\n"
-" git merge --no-ff\n"
+" git merge --no-ff\n"
"\n"
"или:\n"
"\n"
-" git rebase\n"
+" git rebase\n"
msgid "Not possible to fast-forward, aborting."
msgstr "Ðе може да Ñе извърши превъртане, преуÑтановÑване на дейÑтвието."
@@ -953,9 +1003,8 @@ msgstr ""
"Бележка: преминаване към „%s“.\n"
"\n"
"УказателÑÑ‚ „HEAD“ не е Ñвързан. Може да разглеждате, да правите произволни\n"
-"промѐни и да ги подавате. Ðко изтеглите нещо друго, вÑички промѐни ще "
-"бъдат\n"
-"забравени и никой клон нÑма да Ñе промѐни.\n"
+"промѐни и да ги подавате. Ðко изтеглите нещо друго, вÑички промѐни ще Ñе\n"
+"забравÑÑ‚ и никой клон нÑма да Ñе промѐни.\n"
"\n"
"Ðко иÑкате да Ñъздадете нов клон, за да запазите подаваниÑта Ñи, може да\n"
"направите това като зададете име на клон към опциÑта „-c“ на командата\n"
@@ -1019,9 +1068,15 @@ msgstr "опциите „%s“ и „%s“ Ñа неÑъвмеÑтими"
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“ не може за бъде компилиран"
+msgstr "РегулÑрниÑÑ‚ израз за времевото клеймо „%s“ не може да Ñе компилира "
#, c-format
msgid "regexec returned %d for input: %s"
@@ -1126,11 +1181,11 @@ msgstr "кръпката е Ñ Ð¸Ð·Ñ†Ñло повредени данни на Ñ
#, c-format
msgid "unable to read symlink %s"
-msgstr "Ñимволната връзка „%s“ не може да бъде прочетена"
+msgstr "Ñимволната връзка „%s“ не може да Ñе прочете"
#, c-format
msgid "unable to open or read %s"
-msgstr "файлът „%s“ не може да бъде отворен или прочетен"
+msgstr "файлът „%s“ не може да Ñе отвори или прочете"
#, c-format
msgid "invalid start of line: '%c'"
@@ -1183,12 +1238,11 @@ msgstr "кръпката ÑъответÑтва на „%s“, който трÑ
#, c-format
msgid "the necessary postimage %s for '%s' cannot be read"
msgstr ""
-"необходимиÑÑ‚ резултат Ñлед операциÑта — „%s“ за „%s“ не може да бъде "
-"прочетен"
+"необходимиÑÑ‚ резултат Ñлед операциÑта — „%s“ за „%s“ не може да Ñе прочете"
#, c-format
msgid "binary patch does not apply to '%s'"
-msgstr "двоичната кръпка не може да бъде приложена върху „%s“"
+msgstr "двоичната кръпка не може да Ñе приложи върху „%s“"
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
@@ -1206,7 +1260,7 @@ msgstr "„%s“ не може да Ñе изтегли"
#, c-format
msgid "failed to read %s"
-msgstr "файлът „%s“ не може да бъде прочетен"
+msgstr "файлът „%s“ не може да Ñе прочете"
#, c-format
msgid "reading from '%s' beyond a symbolic link"
@@ -1233,7 +1287,7 @@ msgstr "Тройно Ñливане…\n"
#, c-format
msgid "cannot read the current contents of '%s'"
-msgstr "текущото Ñъдържание на „%s“ не може да бъде прочетено"
+msgstr "текущото Ñъдържание на „%s“ не може да Ñе прочете"
#, c-format
msgid "Failed to perform three-way merge...\n"
@@ -1289,7 +1343,7 @@ msgstr "заÑегнатиÑÑ‚ файл „%s“ е Ñлед Ñимволна в
#, c-format
msgid "%s: patch does not apply"
-msgstr "Кръпката „%s“ не може да бъде приложена"
+msgstr "Кръпката „%s“ не може да Ñе приложи"
#, c-format
msgid "Checking patch %s..."
@@ -1364,12 +1418,8 @@ msgstr[0] "Прилагане на кръпката „%%s“ Ñ %d отхвър
msgstr[1] "Прилагане на кръпката „%%s“ Ñ %d отхвърлени парчета…"
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "Ñъкращаване на името на файла Ñ Ð¾Ñ‚Ñ…Ð²ÑŠÑ€Ð»ÐµÐ½Ð¸Ñ‚Ðµ парчета на „%.*s.rej“"
-
-#, c-format
msgid "cannot open %s"
-msgstr "„%s“ не може да бъде отворен"
+msgstr "„%s“ не може да Ñе отвори"
#, c-format
msgid "cannot unlink '%s'"
@@ -1392,11 +1442,11 @@ msgstr ""
"Ðа входа нÑма непразни кръпки (те Ñе приемат при Ð¾Ð¿Ñ†Ð¸Ñ â€ž--allow-empty“)"
msgid "unable to read index file"
-msgstr "индекÑÑŠÑ‚ не може да бъде запиÑан"
+msgstr "индекÑÑŠÑ‚ не може да Ñе запише"
#, c-format
msgid "can't open patch '%s': %s"
-msgstr "кръпката „%s“ не може да бъде отворена: %s"
+msgstr "кръпката „%s“ не може да Ñе отвори: %s"
#, c-format
msgid "squelched %d whitespace error"
@@ -1419,7 +1469,7 @@ msgstr[1] ""
"Добавени Ñа %d реда Ñлед корекциÑта на грешките в знаците за интервали."
msgid "Unable to write new index file"
-msgstr "ÐовиÑÑ‚ Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ може да бъде запиÑан"
+msgstr "ÐовиÑÑ‚ Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ може да Ñе запише"
msgid "don't apply changes matching the given path"
msgstr "без прилагане на промѐните напаÑващи на Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ð¿ÑŠÑ‚"
@@ -1449,7 +1499,7 @@ 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 "проверка дали кръпката може да бъде приложена към Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ"
+msgstr "проверка дали кръпката може да Ñе приложи към Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ"
msgid "mark new files with `git add --intent-to-add`"
msgstr "отбелÑзване на новите файлове Ñ â€žgit add --intent-to-add“"
@@ -1462,14 +1512,22 @@ msgstr "прилагане на кръпка, коÑто Ð¿Ñ€Ð¾Ð¼ÐµÐ½Ñ Ð¸ фаÐ
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr ""
-"кръпката да бъде приложена. ОпциÑта Ñе комбинира Ñ â€ž--check“/„--stat“/„--"
-"summary“"
+"кръпката Ñе приложи. ОпциÑта Ñе комбинира Ñ â€ž--check“/„--stat“/„--summary“"
msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr ""
"пробване Ñ Ñ‚Ñ€Ð¾Ð¹Ð½Ð¾ Ñливане, ако това не Ñработи — Ñтандартно прилагане на "
"кръпка"
+msgid "for conflicts, use our version"
+msgstr "при конфликти да Ñе ползва локалната верÑиÑ"
+
+msgid "for conflicts, use their version"
+msgstr "при конфликти да Ñе ползва чуждата верÑиÑ"
+
+msgid "for conflicts, use a union version"
+msgstr "при конфликти да Ñе ползва обединена верÑиÑ"
+
msgid "build a temporary index based on embedded index information"
msgstr ""
"Ñъздаване на временен Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база на включената Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° индекÑа"
@@ -1517,9 +1575,12 @@ msgstr "добавÑне на тази ÐÐЧÐЛÐÐ_ДИРЕКТОРИЯ къÐ
msgid "don't return error for empty patches"
msgstr "да не Ñе връща грешка при празни кръпки"
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "опциите „--ours“, „--theirs“ и „--union“ изиÑкват опциÑта „--3way“"
+
#, c-format
msgid "cannot stream blob %s"
-msgstr "обектът-BLOB „%s“ не може да бъде обработен"
+msgstr "обектът-BLOB „%s“ не може да Ñе обработи"
#, c-format
msgid "unsupported file mode: 0%o (SHA1: %s)"
@@ -1531,10 +1592,10 @@ msgstr "грешка при декомпреÑиране Ñ â€ždeflate“ (%d)"
#, c-format
msgid "unable to start '%s' filter"
-msgstr "филтърът „%s“ не може да бъде Ñтартиран"
+msgstr "филтърът „%s“ не може да Ñе Ñтартира"
msgid "unable to redirect descriptor"
-msgstr "деÑкрипторът не може да бъде пренаÑочен"
+msgstr "деÑкрипторът не може да Ñе пренаÑочи"
#, c-format
msgid "'%s' filter reported error"
@@ -1566,7 +1627,7 @@ msgstr "git archive --remote ХРÐÐИЛИЩЕ [--exec КОМÐÐДÐ] --list"
#, c-format
msgid "cannot read '%s'"
-msgstr "файлът „%s“ не може да бъде прочетен"
+msgstr "файлът „%s“ не може да Ñе прочете"
#, c-format
msgid "pathspec '%s' matches files outside the current directory"
@@ -1589,6 +1650,10 @@ msgid "not a tree object: %s"
msgstr "не е обект-дърво: %s"
#, c-format
+msgid "failed to unpack tree object %s"
+msgstr "неуÑпешно разпакетиране на обект-дърво „%s“"
+
+#, c-format
msgid "File not found: %s"
msgstr "Файлът „%s“ липÑва"
@@ -1673,6 +1738,10 @@ msgid "Unexpected option --output"
msgstr "Ðеочаквана Ð¾Ð¿Ñ†Ð¸Ñ â€ž--output“"
#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "излишна Ð¾Ð¿Ñ†Ð¸Ñ Ð¸Ð»Ð¸ ÑтойноÑÑ‚ на ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¸Ñ Ñ€ÐµÐ´: „%s“"
+
+#, c-format
msgid "Unknown archive format '%s'"
msgstr "Ðепознат формат на архив: „%s“"
@@ -1714,12 +1783,24 @@ msgstr "преÑкачане на прекалено Ð³Ð¾Ð»ÐµÐ¼Ð¸Ñ Ñ„Ð°Ð¹Ð» зÐ
msgid "ignoring overly large gitattributes blob '%s'"
msgstr "преÑкачане на прекалено Ð³Ð¾Ð»ÐµÐ¼Ð¸Ñ Ð¾Ð±ÐµÐºÑ‚-BLOB за атрибути на git: „%s“"
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr ""
+"опциÑта „--attr-source“ и променливата „GIT_ATTR_SOURCE“ изиÑкват хранилище"
+
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr ""
"неправилна ÑтойноÑÑ‚ за опциÑта „--attr-source“ или променливата "
"„GIT_ATTR_SOURCE“"
#, c-format
+msgid "unable to stat '%s'"
+msgstr "„stat“ не може да Ñе изпълни върху „%s“"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "обектът „%s“ не може да бъде прочетен"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Ðеправилно цитирано Ñъдържание във файла „%s“: %s"
@@ -1771,7 +1852,7 @@ msgid ""
"So we cannot be sure the first %s commit is between %s and %s.\n"
"We continue anyway."
msgstr ""
-"базата за Ñливане между „%s“ и [%s] трÑбва да бъде преÑкочена.\n"
+"базата за Ñливане между „%s“ и [%s] трÑбва да Ñе преÑкочи.\n"
"Ðе може да Ñме Ñигурни, че първото %s подаване е между „%s“ и „%s“.\n"
"Двоичното търÑене продължава."
@@ -1785,11 +1866,15 @@ msgstr "необходима е верÑÐ¸Ñ â€ž%s“"
#, c-format
msgid "could not create file '%s'"
-msgstr "файлът „%s“ не може да бъде Ñъздаден"
+msgstr "файлът „%s“ не може да Ñе Ñъздаде"
+
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "дейÑтвието „show“ не може да Ñе изпълни за обект „%s“"
#, c-format
msgid "could not read file '%s'"
-msgstr "файлът „%s“ не може да бъде прочетен"
+msgstr "файлът „%s“ не може да Ñе прочете"
msgid "reading bisect refs failed"
msgstr "неуÑпешно прочитане на указателите за двоично търÑене"
@@ -1844,7 +1929,7 @@ msgstr "нÑма път на име „%s“ в „%s“"
#, c-format
msgid "cannot read blob %s for path %s"
-msgstr "обектът-BLOB „%s“ в Ð¿ÑŠÑ‚Ñ %s не може да бъде прочетен"
+msgstr "обектът-BLOB „%s“ в Ð¿ÑŠÑ‚Ñ %s не може да Ñе прочете"
msgid ""
"cannot inherit upstream tracking configuration of multiple refs when "
@@ -1871,7 +1956,7 @@ msgid "branch '%s' set up to track:"
msgstr "клонът „%s“ ще Ñледи:"
msgid "unable to write upstream branch configuration"
-msgstr "наÑтройките за ÑÐ»ÐµÐ´ÐµÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½ не може да бъдат запиÑани"
+msgstr "наÑтройките за ÑÐ»ÐµÐ´ÐµÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½ не може да Ñе запишат"
msgid ""
"\n"
@@ -1940,15 +2025,21 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "„%s“ не е позволено име за клон"
+msgid "See `man git check-ref-format`"
+msgstr ""
+"Вижте Ñтраницата в ръководÑтвото:\n"
+"\n"
+" git check-ref-format"
+
#, c-format
msgid "a branch named '%s' already exists"
msgstr "вече ÑъщеÑтвува клон Ñ Ð¸Ð¼Ðµ „%s“."
-# FIXME
#, 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 ""
-"не може принудително да обновите клона „%s“, който е изтеглен в Ð¿ÑŠÑ‚Ñ â€ž%s“"
+"не може принудително да обновите клона „%s“, който Ñе ползва от работното "
+"дърво в „%s“"
#, c-format
msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -2007,8 +2098,8 @@ msgid "submodule '%s': cannot create branch '%s'"
msgstr "подмодул „%s“: клонът „%s“ не може да Ñе Ñъздаде"
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "„%s“ вече е изтеглен в „%s“"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "„%s“ вече Ñе ползва от работното дърво в „%s“"
msgid "git add [<options>] [--] <pathspec>..."
msgstr "git add [ОПЦИЯ…] [--] ПЪТ…"
@@ -2017,50 +2108,29 @@ msgstr "git add [ОПЦИЯ…] [--] ПЪТ…"
msgid "cannot chmod %cx '%s'"
msgstr "права̀та на „%2$s“ не може да Ñе зададат да Ñа %1$cx"
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "неочакван изходен код при генериране на разлика: %c"
-
-msgid "updating files failed"
-msgstr "неуÑпешно обновÑване на файловете"
-
-#, c-format
-msgid "remove '%s'\n"
-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 ""
-"ÐаÑтройката „add.interactive.useBuiltin“ е премахната!\n"
-"За подробноÑти Ñ Ð¿Ð¾Ñ‚ÑŠÑ€Ñете в изхода от „git help config“."
-
-msgid "Could not read the index"
-msgstr "ИндекÑÑŠÑ‚ не може да бъде прочетен"
-
-msgid "Could not write patch"
-msgstr "Кръпката не може да бъде запиÑана"
+msgid "could not read the index"
+msgstr "индекÑÑŠÑ‚ не може да Ñе прочете"
msgid "editing patch failed"
msgstr "неуÑпешно редактиране на кръпка"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Ðе може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за файла „%s“"
+msgid "could not stat '%s'"
+msgstr "неуÑпешно изпълнение на „stat“ върху „%s“"
-msgid "Empty patch. Aborted."
-msgstr "Празна кръпка, преуÑтановÑване на дейÑтвието."
+msgid "empty patch. aborted"
+msgstr "празна кръпка, преуÑтановÑване на дейÑтвието"
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Кръпката „%s“ не може да бъде приложена"
+msgid "could not apply '%s'"
+msgstr "кръпката „%s“ не може да Ñе приложи"
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
-"Следните пътища ще бъдат игнорирани Ñпоред нÑкой от файловете „.gitignore“:\n"
+"Следните пътища ще Ñе игнорират Ñпоред нÑкой от файловете „.gitignore“:\n"
msgid "dry run"
msgstr "пробно изпълнение"
@@ -2087,7 +2157,7 @@ msgid "renormalize EOL of tracked files (implies -u)"
msgstr "уеднаквÑване на знаците за край на файл (включва опциÑта „-u“)"
msgid "record only the fact that the path will be added later"
-msgstr "отбелÑзване Ñамо на факта, че пътÑÑ‚ ще бъде добавен по-къÑно"
+msgstr "отбелÑзване Ñамо на факта, че пътÑÑ‚ ще Ñе добави по-къÑно"
msgid "add changes from all tracked and untracked files"
msgstr "добавÑне на вÑички промѐни в Ñледените и неÑледените файлове"
@@ -2101,7 +2171,7 @@ msgid "don't add, only refresh the index"
msgstr "без добавÑне на нови файлове, Ñамо обновÑване на индекÑа"
msgid "just skip files which cannot be added because of errors"
-msgstr "преÑкачане на файловете, които не може да бъдат добавени поради грешки"
+msgstr "преÑкачане на файловете, които не може да Ñе добавÑÑ‚ поради грешки"
msgid "check if - even missing - files are ignored in dry run"
msgstr ""
@@ -2152,15 +2222,8 @@ msgstr ""
msgid "adding embedded git repository: %s"
msgstr "добавÑне на вградено хранилище: %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"
-"\n"
-" git config advice.addIgnoredFile false"
+msgid "Use -f if you really want to add them."
+msgstr "Използвайте „-f“, за да ги добавите"
msgid "adding files failed"
msgstr "неуÑпешно добавÑне на файлове"
@@ -2177,19 +2240,15 @@ msgstr "опциÑта „%s“ и път Ñа неÑъвмеÑтими"
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"
-"\n"
-" git config advice.addEmptyPathspec false"
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "ВероÑтно иÑкахте да използвате „git add .“?"
msgid "index file corrupt"
msgstr "файлът Ñ Ð¸Ð½Ð´ÐµÐºÑа е повреден"
+msgid "unable to write new index file"
+msgstr "неуÑпешно запиÑване на Ð½Ð¾Ð²Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ"
+
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "неправилно дейÑтвие „%s“ за „%s“"
@@ -2200,7 +2259,7 @@ msgstr "неправилна ÑтойноÑÑ‚ за „%s“: „%s“"
#, c-format
msgid "could not read '%s'"
-msgstr "файлът „%s“ не може да бъде прочетен"
+msgstr "файлът „%s“ не може да Ñе прочете"
msgid "could not parse author script"
msgstr "Ñкриптът за автор не може да Ñе анализира"
@@ -2226,11 +2285,11 @@ msgstr "неуÑпешно изпълнение на „fseek“"
#, c-format
msgid "could not open '%s' for reading"
-msgstr "файлът не може да бъде прочетен: „%s“"
+msgstr "файлът не може да Ñе прочете: „%s“"
#, c-format
msgid "could not open '%s' for writing"
-msgstr "„%s“ не може да бъде отворен за запиÑ"
+msgstr "„%s“ не може да Ñе отвори за запиÑ"
#, c-format
msgid "could not parse patch '%s'"
@@ -2238,7 +2297,7 @@ msgstr "кръпката „%s“ не може да Ñе анализира"
msgid "Only one StGIT patch series can be applied at once"
msgstr ""
-"Само една поредица от кръпки от „StGIT“ може да бъде прилагана в даден момент"
+"Само една поредица от кръпки от „StGIT“ може да Ñе приложи в даден момент"
msgid "invalid timestamp"
msgstr "неправилна ÑтойноÑÑ‚ за времево клеймо"
@@ -2250,35 +2309,36 @@ msgid "invalid timezone offset"
msgstr "неправилно отмеÑтване на чаÑÐ¾Ð²Ð¸Ñ Ð¿Ð¾ÑÑ"
msgid "Patch format detection failed."
-msgstr "Форматът на кръпката не може да бъде определен."
+msgstr "Форматът на кръпката не може да Ñе определи."
#, c-format
msgid "failed to create directory '%s'"
-msgstr "директориÑта „%s“ не може да бъде Ñъздадена"
+msgstr "директориÑта „%s“ не може да Ñе Ñъздаде"
msgid "Failed to split patches."
-msgstr "Кръпките не може да бъдат разделени."
+msgstr "Кръпките не може да Ñе разделÑÑ‚."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
msgstr ""
"След коригирането на този проблем изпълнете:\n"
"\n"
-" %s --continue“"
+" %s --continue“\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
msgstr ""
"Ðко предпочитате да преÑкочите тази кръпка, изпълнете:\n"
"\n"
-" %s --skip"
+" %s --skip\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
"За да включите празната кръпка като празно подаване, изпълнете:\n"
"\n"
-" %s --allow-empty"
+" %s --allow-empty\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
@@ -2302,7 +2362,7 @@ msgstr "грешен ред Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ‡Ð½Ð¾ÑÑ‚: %.*s"
#, c-format
msgid "unable to parse commit %s"
-msgstr "подаването не може да бъде анализирано: %s"
+msgstr "подаването не може да Ñе анализира: %s"
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr ""
@@ -2332,7 +2392,7 @@ msgid "applying to an empty history"
msgstr "прилагане върху празна иÑториÑ"
msgid "failed to write commit object"
-msgstr "обектът за подаването не може да бъде запиÑан"
+msgstr "обектът за подаването не може да Ñе запише"
#, c-format
msgid "cannot resume: %s does not exist."
@@ -2352,12 +2412,11 @@ msgstr ""
"на вÑичко:"
msgid "unable to write index file"
-msgstr "индекÑÑŠÑ‚ не може да бъде запиÑан"
+msgstr "индекÑÑŠÑ‚ не може да Ñе запише"
#, c-format
msgid "Dirty index: cannot apply patches (dirty: %s)"
-msgstr ""
-"ИндекÑÑŠÑ‚ не е чиÑÑ‚: кръпките не може да бъдат приложени (замърÑени Ñа: %s)"
+msgstr "ИндекÑÑŠÑ‚ не е чиÑÑ‚: кръпките не може да Ñе приложат (замърÑени Ñа: %s)"
#, c-format
msgid "Skipping: %.*s"
@@ -2409,15 +2468,12 @@ msgstr ""
"След ÐºÐ¾Ñ€ÐµÐºÑ†Ð¸Ñ Ð½Ð° конфликтите изпълнете „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 "индекÑÑŠÑ‚ не може да бъде изчиÑтен"
+msgstr "индекÑÑŠÑ‚ не може да Ñе изчиÑти"
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
@@ -2431,17 +2487,13 @@ msgstr ""
#, 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“ и „%s=%s“ Ñа неÑъвмеÑтими"
+msgstr "„%s“ не може да Ñе прочете"
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
-msgstr "git am [ОПЦИЯ…] [(ФÐЙЛ_С_ПОЩР| ДИРЕКТОРИЯ_С_ПОЩÐ)…]"
+msgstr "git am [ОПЦИЯ…] [(ФÐЙЛ_С_ПОЩÐ|ДИРЕКТОРИЯ_С_ПОЩÐ)…]"
msgid "git am [<options>] (--continue | --skip | --abort)"
-msgstr "git am [ОПЦИЯ…] (--continue | --skip | --abort)"
+msgstr "git am [ОПЦИЯ…] (--continue|--skip|--abort)"
msgid "run interactively"
msgstr "интерактивна работа"
@@ -2479,11 +2531,6 @@ msgid "pass --keep-cr flag to git-mailsplit for mbox format"
msgstr ""
"подаване на опциÑта „--keep-cr“ на командата „git-mailsplit“ за формат „mbox“"
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"без подаване на опциÑта „--keep-cr“ на командата „git-mailsplit“ незавиÑимо "
-"от „am.keepcr“"
-
msgid "strip everything before a scissors line"
msgstr "пропуÑкане на вÑичко преди реда за отрÑзване"
@@ -2526,6 +2573,9 @@ msgstr ""
msgid "show the patch being applied"
msgstr "показване на прилаганата кръпка"
+msgid "try to apply current patch again"
+msgstr "нов опит за прилагане на текущата кръпка"
+
msgid "record the empty patch as an empty commit"
msgstr "прилагане на празна кръпка като празно подаване"
@@ -2581,10 +2631,7 @@ msgid "git apply [<options>] [<patch>...]"
msgstr "git apply [ОПЦИЯ…] [КРЪПКÐ…]"
msgid "could not redirect output"
-msgstr "изходът не може да бъде пренаÑочен"
-
-msgid "git archive: Remote with no URL"
-msgstr "git archive: ЛипÑва Ð°Ð´Ñ€ÐµÑ Ð·Ð° отдалеченото хранилище"
+msgstr "изходът не може да Ñе пренаÑочи"
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr ""
@@ -2601,12 +2648,12 @@ msgid "git archive: expected a flush"
msgstr "git archive: очакваше Ñе изчиÑтване на буферите чрез „flush“"
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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] [ЛОШО [ДОБРО…]] [--] "
-"[ПЪТ…]"
+"git bisect start [--term-(new,bad)=УПРÐВЛЯВÐЩÐ_ДУМР--term-(old,"
+"good)=УПРÐВЛЯВÐЩÐ_ДУМÐ] [--no-checkout] [--first-parent] [ЛОШО [ДОБРО…]] "
+"[--] [ПЪТ…]"
msgid "git bisect (good|bad) [<rev>...]"
msgstr "git bisect (good|bad) [ВЕРСИЯ…]"
@@ -2620,8 +2667,8 @@ msgstr "git bisect reset [ПОДÐÐ’ÐÐЕ]"
msgid "git bisect replay <logfile>"
msgstr "git bisect replay ИМЕ_ÐÐ_ФÐЙЛ"
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run КОМÐÐДÐ…"
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run КОМÐÐДÐ… [ÐРГУМЕÐТ…]"
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2633,7 +2680,7 @@ msgstr "във файла „%s“ не може да Ñе пише"
#, c-format
msgid "cannot open file '%s' for reading"
-msgstr "файлът „%s“ не може да бъде отворен за четене"
+msgstr "файлът „%s“ не може да Ñе отвори за четене"
#, c-format
msgid "'%s' is not a valid term"
@@ -2662,8 +2709,8 @@ msgstr "„%s“ не е подаване"
msgid ""
"could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
msgstr ""
-"първоначално указаното „%s“ в ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“ не може да бъде\n"
-"изтеглено. Пробвайте да изпълните командата „git bisect reset ПОДÐÐ’ÐÐЕ“."
+"първоначално указаното „%s“ в ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“ не може да Ñе\n"
+"изтегли. Пробвайте да изпълните командата „git bisect reset ПОДÐÐ’ÐÐЕ“."
#, c-format
msgid "Bad bisect_write argument: %s"
@@ -2743,9 +2790,6 @@ msgstr ""
"на „git bisect terms“ е подаден неправилен аргумент „%s“\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“ не може да Ñе отвори за добавÑне"
@@ -3034,7 +3078,7 @@ msgid "Blaming lines"
msgstr "Редове Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ñтво"
msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
-msgstr "git branch [ОПЦИЯ…] [-r | -a] [--merged] [--no-merged]"
+msgstr "git branch [ОПЦИЯ…] [-r|-a] [--merged] [--no-merged]"
msgid ""
"git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
@@ -3045,61 +3089,65 @@ 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) ИМЕ_ÐÐ_КЛОÐ…"
+msgstr "git branch [ОПЦИЯ…] [-r] (-d|-D) ИМЕ_ÐÐ_КЛОÐ…"
msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
-msgstr "git branch [ОПЦИЯ…] (-m | -M) [СТÐР_КЛОÐ] ÐОВ_КЛОÐ"
+msgstr "git branch [ОПЦИЯ…] (-m|-M) [СТÐР_КЛОÐ] ÐОВ_КЛОÐ"
msgid "git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"
-msgstr "git branch [ОПЦИЯ…] (-c | -C) [СТÐР_КЛОÐ] ÐОВ_КЛОÐ"
+msgstr "git branch [ОПЦИЯ…] (-c|-C) [СТÐР_КЛОÐ] ÐОВ_КЛОÐ"
msgid "git branch [<options>] [-r | -a] [--points-at]"
-msgstr "git branch [ОПЦИЯ…] [-r | -a] [--points-at]"
+msgstr "git branch [ОПЦИЯ…] [-r|-a] [--points-at]"
msgid "git branch [<options>] [-r | -a] [--format]"
-msgstr "git branch [ОПЦИЯ…] [-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."
+" '%s', but not yet merged to HEAD"
msgstr ""
"изтриване на клона „%s“, който е ÑлÑÑ‚ към „%s“,\n"
-" но още не е ÑлÑÑ‚ към върха „HEAD“."
+" но още не е ÑлÑÑ‚ към върха „HEAD“"
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
"отказване на изтриване на клона „%s“, който не е ÑлÑÑ‚ към\n"
-" „%s“, но е ÑлÑÑ‚ към върха „HEAD“."
+" „%s“, но е ÑлÑÑ‚ към върха „HEAD“"
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Обектът-подаване за „%s“ не може да бъде открит"
+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'."
+msgid "the branch '%s' is not fully merged"
+msgstr "клонът „%s“ не е ÑлÑÑ‚ напълно"
+
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
msgstr ""
-"Клонът „%s“ не е ÑлÑÑ‚ напълно. Ðко Ñте Ñигурни, че иÑкате\n"
-"да го изтриете, изпълнете „git branch -D %s“."
+"Ðко Ñте Ñигурни, че иÑкате да го изтриете, изпълнете:\n"
+"\n"
+" git branch -D %s"
-msgid "Update of config-file failed"
-msgstr "ÐеуÑпешно обновÑване на ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»"
+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“"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"не може да изтриете клона „%s“, който Ñе ползва от работното дърво в „%s“"
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "ÑледÑщиÑÑ‚ клон „%s“ не може да бъде открит."
+msgid "remote-tracking branch '%s' not found"
+msgstr "ÑледÑщиÑÑ‚ клон „%s“ липÑва"
#, c-format
msgid ""
@@ -3110,8 +3158,8 @@ msgstr ""
"Пробвахте ли опциÑта „--remote“?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "клонът „%s“ не може да бъде открит."
+msgid "branch '%s' not found"
+msgstr "клонът „%s“ липÑва"
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -3129,65 +3177,65 @@ msgstr "подаването, Ñочено от ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“, Ð
#, c-format
msgid "HEAD (%s) points outside of refs/heads/"
-msgstr "„HEAD“ (%s) Ñочи извън директориÑта „refs/heads“"
+msgstr "„HEAD“ (%s) Ñочи извън директориÑта „refs/heads/“"
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "Клонът „%s“ Ñе пребазира върху „%s“"
+msgid "branch %s is being rebased at %s"
+msgstr "клонът „%s“ Ñе пребазира върху „%s“"
#, c-format
-msgid "Branch %s is being bisected at %s"
-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“"
+msgid "invalid branch name: '%s'"
+msgstr "неправилно име на клон: „%s“"
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Ð’ клона „%s“ вÑе още нÑма подаваниÑ."
+msgid "no commit on branch '%s' yet"
+msgstr "в клона „%s“ вÑе още нÑма подаваниÑ"
#, c-format
-msgid "No branch named '%s'."
-msgstr "ЛипÑва клон на име „%s“."
+msgid "no branch named '%s'"
+msgstr "липÑва клон на име „%s“"
-msgid "Branch rename failed"
-msgstr "ÐеуÑпешно преименуване на клон"
+msgid "branch rename failed"
+msgstr "неуÑпешно преименуване на клон"
-msgid "Branch copy failed"
-msgstr "ÐеуÑпешно копиране на клон"
+msgid "branch copy failed"
+msgstr "неуÑпешно копиране на клон"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Клонът Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»Ð½Ð¾ име „%s“ е копиран"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "клонът Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»Ð½Ð¾ име „%s“ е копиран"
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Клонът Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»Ð½Ð¾ име „%s“ е преименуван"
+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 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 renamed, but update of config-file failed"
+msgstr "клонът е преименуван, но конфигурационниÑÑ‚ файл не е обновен"
-msgid "Branch is copied, 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"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Въведете опиÑание на клона.\n"
" %s\n"
-"Редовете, които започват Ñ â€ž%c“, ще бъдат пропуÑнати.\n"
+"Редовете, които започват Ñ â€ž%s“, ще бъдат пропуÑнати.\n"
msgid "Generic options"
msgstr "Общи наÑтройки"
@@ -3294,8 +3342,8 @@ msgstr "рекурÑивно обхождане подмодулите"
msgid "format to use for the output"
msgstr "ФОРМÐТ за изхода"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Ðе може да Ñе открие към какво Ñочи указателÑÑ‚ „HEAD“"
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "указателÑÑ‚ „HEAD“ не Ñочи към обект"
msgid "HEAD not found below refs/heads!"
msgstr "Ð’ директориÑта „refs/heads“ липÑва файл „HEAD“"
@@ -3314,16 +3362,16 @@ msgstr ""
msgid "branch name required"
msgstr "Ðеобходимо е име на клон"
-msgid "Cannot give description to detached HEAD"
-msgstr "Ðе може да зададете опиÑание на неÑвързан „HEAD“"
+msgid "cannot give description to detached HEAD"
+msgstr "не може да зададете опиÑание на неÑвързан „HEAD“"
msgid "cannot edit description of more than one branch"
-msgstr "Ðе може да редактирате опиÑанието на повече от един клон едновременно"
+msgstr "не може да редактирате опиÑанието на повече от един клон едновременно"
-msgid "cannot copy the current branch while not on any."
+msgid "cannot copy the current branch while not on any"
msgstr "не може да копирате Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½, защото Ñте извън който и да е клон"
-msgid "cannot rename the current branch while not on any."
+msgid "cannot rename the current branch while not on any"
msgstr ""
"не може да преименувате Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½, защото Ñте извън който и да е клон"
@@ -3338,32 +3386,31 @@ msgstr "прекалено много аргументи към командат
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
-"Следеното от „HEAD“ не може да Ñе зададе да е „%s“, защото то не Ñочи към "
-"никой клон."
+"Ñледеното от „HEAD“ не може да Ñе зададе да е „%s“, защото то не Ñочи към "
+"никой клон"
#, c-format
msgid "no such branch '%s'"
-msgstr "ÐÑма клон на име „%s“."
+msgstr "нÑма клон на име „%s“."
#, c-format
msgid "branch '%s' does not exist"
-msgstr "Ðе ÑъщеÑтвува клон на име „%s“."
+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“ не може да махне, защото то не Ñочи към никой клон."
+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 "branch '%s' has no upstream information"
+msgstr "нÑма Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐºÐ»Ð¾Ð½ÑŠÑ‚ „%s“ да Ñледи нÑкой друг"
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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"
@@ -3371,7 +3418,7 @@ msgstr ""
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
"опциÑта „--set-upstream“ вече не Ñе поддържа. Използвайте „--track“ или „--"
"set-upstream-to“"
@@ -3393,10 +3440,12 @@ 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"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) ПЪТ] [(-s | --suffix) ФОРМÐТ]\n"
+"git bugreport [(-o|--output-directory) ПЪТ]\n"
+" [(-s|--suffix) ФОРМÐТ|--no-suffix]\n"
" [--diagnose[=РЕЖИМ]]"
msgid ""
@@ -3450,6 +3499,10 @@ msgid "specify a strftime format suffix for the filename(s)"
msgstr "укажете ÑуфикÑа на файловете във формат за „strftime“"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "непозната Ð¾Ð¿Ñ†Ð¸Ñ â€ž%s“"
+
+#, c-format
msgid "could not create leading directories for '%s'"
msgstr "родителÑките директории на „%s“ не може да бъдат Ñъздадени"
@@ -3475,11 +3528,11 @@ msgid ""
"git bundle create [-q | --quiet | --progress]\n"
" [--version=<version>] <file> <git-rev-list-args>"
msgstr ""
-"git bundle create [-q | --quiet | --progress ]\n"
+"git bundle create [-q|--quiet|--progress ]\n"
" [--version=ВЕРСИЯ] ФÐЙЛ ОПЦИЯ_ЗÐ_git-rev-list…"
msgid "git bundle verify [-q | --quiet] <file>"
-msgstr "git bundle verify [-q | --quiet] ФÐЙЛ"
+msgstr "git bundle verify [-q|--quiet] ФÐЙЛ"
msgid "git bundle list-heads <file> [<refname>...]"
msgstr "git bundle list-heads ФÐЙЛ [ИМЕ_ÐÐ_УКÐЗÐТЕЛ…]"
@@ -3511,6 +3564,9 @@ msgstr "За Ñъздаването на пратка е необходимо Ñ…
msgid "do not show bundle details"
msgstr "без подробна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° пратките"
+msgid "need a repository to verify a bundle"
+msgstr "за проверката на пратка е необходимо хранилище"
+
#, c-format
msgid "%s is okay\n"
msgstr "Пратката „%s“ е наред\n"
@@ -3550,28 +3606,27 @@ msgid "git cat-file <type> <object>"
msgstr "git cat-file ВИД ОБЕКТ"
msgid "git cat-file (-e | -p) <object>"
-msgstr "git cat-file (-e | -p) ОБЕКТ"
+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] ОБЕКТ"
+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]"
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
msgstr ""
+"git cat-file (--textconv|--filters)\n"
+" [ВЕРСИЯ:ПЪТ|ДЪРВО|--path=ПЪТ|ДЪРВО ВЕРСИЯ]"
+
+msgid ""
"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>]"
+" [--textconv | --filters] [-Z]"
msgstr ""
-"git cat-file (--textconv | --filters)\n"
-" [ВЕРСИЯ:ПЪТ|ДЪРВО | --path=ПЪТ|ДЪРВО ВЕРСИЯ]"
+"git cat-file (--batch|--batch-check|--batch-command) [--batch-all-objects]\n"
+" [--buffer] [--follow-symlinks] [--unordered]\n"
+" [--textconv|--filters] [-Z]"
msgid "Check object existence or emit object contents"
msgstr "Проверка за ÑъщеÑтвуването на обекта или извеждане на Ñъдържанието му"
@@ -3587,8 +3642,8 @@ msgstr "Извеждане на атрибутите на обектите (Ñ Ð
msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
msgstr ""
-"показване на обекти от този ВИД: „blob“ (BLOB), „tree“ (дърво), "
-"„commit“ (подаване), „tag“ (етикет и т.н.…)"
+"показване на обекти от този ВИД: „blob“ (BLOB), „tree“ (дърво), „commit“ "
+"(подаване), „tag“ (етикет и т.н.…)"
msgid "show object size"
msgstr "извеждане на размера на обект"
@@ -3615,6 +3670,9 @@ msgstr "като „--batch“, но без извеждане на Ñъдърж
msgid "stdin is NUL-terminated"
msgstr "ÑтандартниÑÑ‚ вход да ползва Ð½ÑƒÐ»ÐµÐ²Ð¸Ñ Ð·Ð½Ð°Ðº „NUL“ за разделител"
+msgid "stdin and stdout is NUL-terminated"
+msgstr "Ñтандартните вход и изход да ползват Ð½ÑƒÐ»ÐµÐ²Ð¸Ñ Ð·Ð½Ð°Ðº „NUL“ за разделител"
+
msgid "read commands from stdin"
msgstr "изчитане на командите от ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´"
@@ -3689,14 +3747,12 @@ msgid ""
"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
"<pathname>..."
msgstr ""
-"git check-attr [--source УКÐЗÐТЕЛ_КЪМ_ДЪРВО] [-a | --all | ÐТРИБУТ…] [--] "
-"ПЪТ…"
+"git check-attr [--source УКÐЗÐТЕЛ_КЪМ_ДЪРВО] [-a|--all|ÐТРИБУТ…] [--] ПЪТ…"
msgid ""
"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
msgstr ""
-"git check-attr --stdin [-z] [--source УКÐЗÐТЕЛ_КЪМ_ДЪРВО] [-a | --all | "
-"ÐТРИБУТ…]"
+"git check-attr --stdin [-z] [--source УКÐЗÐТЕЛ_КЪМ_ДЪРВО] [-a|--all|ÐТРИБУТ…]"
msgid "report all attributes set on file"
msgstr "извеждане на вÑички атрибути, зададени върху файл"
@@ -3749,9 +3805,17 @@ msgstr "git check-mailmap [ОПЦИЯ…] КОÐТÐКТ…"
msgid "also read contacts from stdin"
msgstr "четене на контакти и от ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "контактът не може да бъде анализиран: %s"
+msgid "read additional mailmap entries from file"
+msgstr ""
+"изчитане на допълнителните ÑъответÑÑ‚Ð²Ð¸Ñ Ð½Ð° имена и адреÑи на е-поща от ФÐЙЛ"
+
+msgid "blob"
+msgstr "обект-BLOB"
+
+msgid "read additional mailmap entries from blob"
+msgstr ""
+"изчитане на допълнителните ÑъответÑÑ‚Ð²Ð¸Ñ Ð½Ð° имена и адреÑи на е-поща от обект-"
+"BLOB"
msgid "no contacts specified"
msgstr "не Ñа указани контакти"
@@ -3876,9 +3940,17 @@ msgid "'%s' or '%s' cannot be used with %s"
msgstr "опциÑта „%3$s“ е неÑъвмеÑтима както Ñ â€ž%1$s“, така и Ñ â€ž%2$s“"
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "„%s“, „%s“ и „%s“ Ñа неÑъвмеÑтими Ñ Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñнето на дърво"
+
+#, c-format
msgid "path '%s' is unmerged"
msgstr "пътÑÑ‚ „%s“ не е ÑлÑÑ‚"
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "дървото не може да бъде прочетено (%s)"
+
msgid "you need to resolve your current index first"
msgstr "първо трÑбва да коригирате индекÑа Ñи"
@@ -4098,6 +4170,10 @@ msgid "'%s' cannot be used with switching branches"
msgstr "опциÑта „%s“ е неÑъвмеÑтима Ñ Ð¿Ñ€ÐµÐ¼Ð¸Ð½Ð°Ð²Ð°Ð½ÐµÑ‚Ð¾ от един клон към друг"
#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "„%s“ изиÑква пътища, които да Ñе изтеглÑÑ‚"
+
+#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "опциÑта „%s“ е неÑъвмеÑтима Ñ â€ž%s“"
@@ -4114,6 +4190,10 @@ msgstr ""
msgid "missing branch or commit argument"
msgstr "липÑва аргумент — клон или подаване"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "непознат вид конфликт „%s“"
+
msgid "perform a 3-way merge with the new branch"
msgstr "извършване на тройно Ñливане Ñ Ð½Ð¾Ð²Ð¸Ñ ÐºÐ»Ð¾Ð½"
@@ -4134,8 +4214,8 @@ msgstr "принудително изтеглÑне (вашите промѐн
msgid "new-branch"
msgstr "ÐОВ_КЛОÐ"
-msgid "new unparented branch"
-msgstr "нов клон без родител"
+msgid "new unborn branch"
+msgstr "нов неродѐн клон"
msgid "update ignored files (default)"
msgstr "обновÑване на игнорираните файлове (Ñтандартно)"
@@ -4165,7 +4245,7 @@ msgstr "липÑва име на клон, използвайте опциÑта
#, c-format
msgid "could not resolve %s"
-msgstr "„%s“ не може да бъде открит"
+msgstr "„%s“ не може да бъде проÑледен"
msgid "invalid path specification"
msgstr "указан е неправилен път"
@@ -4240,7 +4320,7 @@ 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] [--] [ПЪТ…]"
+msgstr "git clean [-d] [-f] [-i] [-n] [-q] [-e ШÐБЛОÐ] [-x|-X] [--] [ПЪТ…]"
#, c-format
msgid "Removing %s\n"
@@ -4373,23 +4453,10 @@ 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“ е зададена като иÑтина, което изиÑква нÑÐºÐ¾Ñ "
-"от опциите „-i“, „-n“ или „-f“. ÐÑма да Ñе извърши изчиÑтване"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"ÐаÑтройката „clean.requireForce“ не е зададена, но Ñтандартно е иÑтина, "
-"което изиÑква нÑÐºÐ¾Ñ Ð¾Ñ‚ опциите „-i“, „-n“ или „-f“. ÐÑма да Ñе извърши "
-"изчиÑтване"
-
-msgid "-x and -X cannot be used together"
-msgstr "опциите „-x“ и „-X“ Ñа неÑъвмеÑтими"
+"ÐаÑтройката „clean.requireForce“ е зададена, което изиÑква опциÑта „-f“. "
+"ÐÑма да Ñе извърши изчиÑтване"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [ОПЦИЯ…] [--] ХРÐÐИЛИЩЕ [ДИРЕКТОРИЯ]"
@@ -4403,7 +4470,7 @@ msgstr "без Ñъздаване на работно дърво"
msgid "create a bare repository"
msgstr "Ñъздаване на голо хранилище"
-msgid "create a mirror repository (implies bare)"
+msgid "create a mirror repository (implies --bare)"
msgstr ""
"Ñъздаване на хранилище-огледало (включва опциÑта „--bare“ за голо хранилище)"
@@ -4482,6 +4549,9 @@ msgstr "СЛУЖЕБÐÐ_ДИРЕКТОРИЯ"
msgid "separate git dir from working tree"
msgstr "отделна СЛУЖЕБÐÐ_ДИРЕКТОРИЯ за git извън работното дърво"
+msgid "specify the reference format to use"
+msgstr "указване на форма̀та за указател"
+
msgid "key=value"
msgstr "КЛЮЧ=СТОЙÐОСТ"
@@ -4494,12 +4564,6 @@ msgstr "Ñпецифични за Ñървъра"
msgid "option to transmit"
msgstr "Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð° преноÑ"
-msgid "use IPv4 addresses only"
-msgstr "Ñамо адреÑи IPv4"
-
-msgid "use IPv6 addresses only"
-msgstr "Ñамо адреÑи IPv6"
-
msgid "apply partial clone filters to submodules"
msgstr "прилагане на филтрите за непълно хранилище към подмодулите"
@@ -4549,6 +4613,14 @@ msgid "failed to unlink '%s'"
msgstr "неуÑпешно изтриване на „%s“"
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "твърдата връзка не може да Ñе провери при „%s“"
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "твърдата връзка е различна от източника „%s“"
+
+#, c-format
msgid "failed to create link '%s'"
msgstr "връзката „%s“ не може да бъде Ñъздадена"
@@ -4615,12 +4687,9 @@ 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 "unknown ref storage format '%s'"
+msgstr "непознат формат на Ñъхранение: „%s“"
#, c-format
msgid "repository '%s' does not exist"
@@ -4743,6 +4812,10 @@ msgstr "поле в знаци отдÑÑно"
msgid "padding space between columns"
msgstr "поле в знаци между колоните"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s трÑбва да е неотрицателно"
+
msgid "--command must be the first argument"
msgstr "опциÑта „--command“ трÑбва да е първиÑÑ‚ аргумент"
@@ -4758,11 +4831,11 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir ДИРЕКТОРИЯ] [--append]\n"
-" [--split[=СТРÐТЕГИЯ]] [--reachable | --stdin-packs | "
-"--stdin-commits]\n"
+" [--split[=СТРÐТЕГИЯ]] [--reachable|--stdin-packs|--"
+"stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters БРОЙ] [--"
"[no-]progress]\n"
" ОПЦИИ_ЗÐ_РÐЗДЕЛЯÐЕ"
@@ -4775,13 +4848,17 @@ 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 "could not open commit-graph chain '%s'"
+msgstr "веригата на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта не може да Ñе отвори: „%s“"
+
+#, c-format
msgid "unrecognized --split argument, %s"
msgstr "непознат аргумент към „--split“: %s"
@@ -4892,7 +4969,7 @@ 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"
+"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"
@@ -4900,13 +4977,13 @@ msgid ""
" [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
" [--] [<pathspec>...]"
msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u РЕЖИМ] [--amend]\n"
-" [--dry-run] [(-c | -C | --squash) ПОДÐÐ’ÐÐЕ | --fixup [(amend|"
-"reword):]ПОДÐÐ’ÐÐЕ)]\n"
-" [-F ФÐЙЛ | -m СЪОБЩЕÐИЕ] [--reset-author] [--allow-empty]\n"
+"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"
+" [-i|-o] [--pathspec-from-file=ФÐЙЛ [--pathspec-file-nul]]\n"
" [(--trailer ЛЕКСЕМÐ[(=|:)СТОЙÐОСТ])…] [-"
"S[ИДЕÐТИФИКÐТОР_ÐÐ_КЛЮЧ]]\n"
" [--] [ПЪТ…]"
@@ -4972,6 +5049,9 @@ msgstr ""
" git cherry-pick --skip\n"
"\n"
+msgid "updating files failed"
+msgstr "неуÑпешно обновÑване на файловете"
+
msgid "failed to unpack HEAD tree object"
msgstr "върховото дърво (HEAD tree object) не може да бъде извадено от пакет"
@@ -4990,9 +5070,6 @@ 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 "по време на Ñливане не може да Ñе извърши чаÑтично подаване."
@@ -5031,7 +5108,7 @@ msgstr ""
"използвани вÑички подобни знаци"
#, c-format
-msgid "could not lookup commit %s"
+msgid "could not lookup commit '%s'"
msgstr "Ñледното подаване не може да бъде открито: %s"
#, c-format
@@ -5065,35 +5142,35 @@ msgstr "шаблонът за подаване не може да бъде заÐ
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Въведете Ñъобщението за подаване на промѐните. Редовете, които започват\n"
-"Ñ â€ž%c“, ще бъдат пропуÑнати.\n"
+"Ñ â€ž%s“, ще бъдат пропуÑнати.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Въведете Ñъобщението за подаване на промѐните. Редовете, които започват\n"
-"Ñ â€ž%c“, ще бъдат пропуÑнати, а празно Ñъобщение преуÑтановÑва подаването.\n"
+"Ñ â€ž%s“, ще бъдат пропуÑнати, а празно Ñъобщение преуÑтановÑва подаването.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Въведете Ñъобщението за подаване на промѐните. Редовете, които започват\n"
-"Ñ â€ž%c“, Ñъщо ще бъдат включени — може да ги изтриете вие.\n"
+"Ñ â€ž%s“, Ñъщо ще бъдат включени — може да ги изтриете вие.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Въведете Ñъобщението за подаване на промѐните. Редовете, които започват\n"
-"Ñ â€ž%c“, Ñъщо ще бъдат включени — може да ги изтриете вие. Празно \n"
+"Ñ â€ž%s“, Ñъщо ще бъдат включени — може да ги изтриете вие. Празно \n"
"Ñъобщение преуÑтановÑва подаването.\n"
msgid ""
@@ -5239,9 +5316,9 @@ msgid ""
"show ignored files, optional modes: traditional, matching, no. (Default: "
"traditional)"
msgstr ""
-"извеждане на игнорираните файлове. Възможните РЕЖИМи Ñа "
-"„traditional“ (традиционен), „matching“ (напаÑващи), „no“ (без игнорираните "
-"файлове). СтандартниÑÑ‚ РЕЖИМ е: „traditional“."
+"извеждане на игнорираните файлове. Възможните РЕЖИМи Ñа „traditional“ "
+"(традиционен), „matching“ (напаÑващи), „no“ (без игнорираните файлове). "
+"СтандартниÑÑ‚ РЕЖИМ е: „traditional“."
msgid "when"
msgstr "КОГÐ"
@@ -5251,8 +5328,8 @@ msgid ""
"(Default: all)"
msgstr ""
"игнориране на промѐните в подмодулите. ÐžÐ¿Ñ†Ð¸Ñ Ñ Ð½ÐµÐ·Ð°Ð´ÑŠÐ»Ð¶Ð¸Ñ‚ÐµÐ»Ð½Ð° ÑтойноÑÑ‚ — "
-"една от „all“ (вÑички), „dirty“ (тези Ñ Ð½ÐµÐ¿Ð¾Ð´Ð°Ð´ÐµÐ½Ð¸ промѐни), "
-"„untracked“ (неÑледени)"
+"една от „all“ (вÑички), „dirty“ (тези Ñ Ð½ÐµÐ¿Ð¾Ð´Ð°Ð´ÐµÐ½Ð¸ промѐни), „untracked“ "
+"(неÑледени)"
msgid "list untracked files in columns"
msgstr "извеждане на неÑледените файлове в колони"
@@ -5404,24 +5481,65 @@ msgstr "Ðеизвършване на подаване поради празно
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"хранилището е обновено, но новиÑÑ‚ файл за Ð¸Ð½Ð´ÐµÐºÑ â€žnew_index“\n"
-"не е запиÑан. Проверете дали диÑкът не е препълнен или не Ñте\n"
-"превишили диÑковата Ñи квота. За възÑтановÑване изпълнете:\n"
+"хранилището е обновено, но новиÑÑ‚ файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ е запиÑан.\n"
+"Проверете дали диÑкът не е препълнен или не Ñте превишили\n"
+"диÑковата Ñи квота. За възÑтановÑване изпълнете:\n"
"\n"
" git restore --staged :/"
-msgid "git config [<options>]"
-msgstr "git config [ОПЦИЯ…]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [ОПЦИЯ_ЗÐ_ФÐЙЛ] [ОПЦИЯ_ЗÐ_ИЗВЕЖДÐÐЕ] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "непознат аргумент към „--type“: %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [ОПЦИЯ_ЗÐ_ФÐЙЛ] [ОПЦИЯ_ЗÐ_ИЗВЕЖДÐÐЕ] [--includes] [--all] [--"
+"regexp] [--value=СТОЙÐОСТ] [--fixed-value] [--default=СТÐÐДÐРТÐО] ИМЕ"
-msgid "only one type at a time"
-msgstr "Ñамо по един вид"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [ОПЦИЯ_ЗÐ_ФÐЙЛ] [--type=ВИД] [--all] [--value=СТОЙÐОСТ] [--"
+"fixed-value] ИМЕ СТОЙÐОСТ"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [ОПЦИЯ_ЗÐ_ФÐЙЛ] [--all] [--value=СТОЙÐОСТ] [--fixed-value]"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [ОПЦИЯ_ЗÐ_ФÐЙЛ] СТÐРО_ИМЕ ÐОВО_ИМЕ"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [ОПЦИЯ_ЗÐ_ФÐЙЛ] ИМЕ"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [ОПЦИЯ_ЗÐ_ФÐЙЛ]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr ""
+"git config [ОПЦИЯ_ЗÐ_ФÐЙЛ] --get-colorbool ИМЕ [СТÐÐД_ИЗХОД_ÐÐ_ТЕРМИÐÐЛ]"
+
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [ОПЦИЯ_ЗÐ_ФÐЙЛ] [ОПЦИЯ_ЗÐ_ИЗВЕЖДÐÐЕ] [--includes] [--all] [--"
+"regexp=РЕГ_ИЗР][--value=СТОЙÐОСТ] [--fixed-value] [--default=СТÐÐДÐРТÐО] ИМЕ"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [ОПЦИЯ_ЗÐ_ФÐЙЛ] [--type=ВИД] [--comment=СЪОБЩЕÐИЕ] [--all] [--"
+"value=СТОЙÐОСТ] [--fixed-value] ИМЕ СТОЙÐОСТ"
msgid "Config file location"
msgstr "МеÑтоположение на ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»"
@@ -5448,57 +5566,6 @@ 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 "извеждане на ÑтойноÑтта за ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð°Ð´Ñ€ÐµÑ: РÐЗДЕЛ[.ПРОМЕÐЛИВÐ] ÐДРЕС"
-
-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 "извеждане на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер (ÑтандартниÑÑ‚ изход е терминал)"
-
msgid "Type"
msgstr "Вид"
@@ -5526,8 +5593,8 @@ msgstr "СТОЙÐОСТТРе път (до файл или директориÑ
msgid "value is an expiry date"
msgstr "ÑтойноÑтта е период на валидноÑÑ‚/запазване"
-msgid "Other"
-msgstr "Други"
+msgid "Display options"
+msgstr "Опции за извеждането"
msgid "terminate values with NUL byte"
msgstr "разделÑне на ÑтойноÑтите Ñ Ð½ÑƒÐ»ÐµÐ²Ð¸Ñ Ð·Ð½Ð°Ðº „NUL“"
@@ -5535,9 +5602,6 @@ msgstr "разделÑне на ÑтойноÑтите Ñ Ð½ÑƒÐ»ÐµÐ²Ð¸Ñ Ð·Ð½Ð°Ð
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 ""
"извеждане на мÑÑтото на задаване на наÑтройката (файл, Ñтандартен вход, "
@@ -5545,15 +5609,18 @@ msgstr ""
msgid "show scope of config (worktree, local, global, system, command)"
msgstr ""
-"извеждане на обхвата на наÑтройката „worktree“ (работно дърво), "
-"„local“ (хранилище), „global“ (потребител), „system“ (ÑиÑтема), "
-"„command“ (команда)"
+"извеждане на обхвата на наÑтройката „worktree“ (работно дърво), „local“ "
+"(хранилище), „global“ (потребител), „system“ (ÑиÑтема), „command“ (команда)"
-msgid "value"
-msgstr "СТОЙÐОСТ"
+msgid "show config keys in addition to their values"
+msgstr "извеждане на ключовете в наÑтройките заедно ÑÑŠÑ ÑтойноÑтите им"
-msgid "with --get, use default value when missing entry"
-msgstr "Ñ â€ž--get“ Ñе използва Ñтандартна СТОЙÐОСТ при липÑваща"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "непознат аргумент към „--type“: %s"
+
+msgid "only one type at a time"
+msgstr "Ñамо по един вид"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5630,45 +5697,73 @@ msgstr ""
"повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ раздела „CONFIGURATION FILE“ в\n"
"„git help worktree“"
-msgid "--get-color and variable type are incoherent"
-msgstr "опциÑта „--get-color“ не ÑъответÑтва на вида на променливата"
+msgid "Other"
+msgstr "Други"
+
+msgid "respect include directives on lookup"
+msgstr "при търÑене да Ñе уважат и директивите за включване"
-msgid "only one action at a time"
-msgstr "Ñамо по едно дейÑтвие"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде прочетен"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr ""
-"опциÑта „--name-only“ е приложима Ñамо към опциите „--list“ и „--get-regexp“"
+msgid "error processing config file(s)"
+msgstr "грешка при обработката на конфигурационен файл"
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
+msgid "Filter options"
+msgstr "Опции за филтриране"
+
+msgid "return all values for multi-valued config options"
+msgstr "връщане на вÑички ÑтойноÑти за опциите, поддържащи много ÑтойноÑти"
+
+msgid "interpret the name as a regular expression"
+msgstr "третиране на името като регулÑрен израз"
+
+msgid "show config with values matching the pattern"
+msgstr "извеждане на наÑтройките ÑÑŠÑ ÑтойноÑти напаÑващи на ШÐБЛОÐа"
+
+msgid "use string equality when comparing values to value pattern"
msgstr ""
-"опциÑта „--show-origin“ е приложима Ñамо към опциите „--get“, „--get-all“, "
-"„--get-regexp“ и „--list“"
+"ползване на равенÑтво на низ при ÑравнÑване на ÑтойноÑÑ‚ Ñ Ð¨ÐБЛОÐ_ЗÐ_СТОЙÐОСТ"
-msgid "--default is only applicable to --get"
-msgstr "опциÑта „--default“ е приложима Ñамо към опциÑта „--get“"
+msgid "URL"
+msgstr "ÐдреÑ"
+
+msgid "show config matching the given URL"
+msgstr "извеждане на наÑтройките напаÑващи на Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ð°Ð´Ñ€ÐµÑ"
+
+msgid "value"
+msgstr "СТОЙÐОСТ"
+
+msgid "use default value when missing entry"
+msgstr "ползване на Ñтандартна СТОЙÐОСТ при липÑваща"
msgid "--fixed-value only applies with 'value-pattern'"
-msgstr "опциÑта „--fixed-value“ е приложима Ñамо ÑÑŠÑ Ð¨ÐБЛОÐ_ЗÐ_СТОЙÐОСТ"
+msgstr "опциÑта „--fixed-value“ изиÑква ШÐБЛОÐ_ЗÐ_СТОЙÐОСТ"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде прочетен"
+msgid "--default= cannot be used with --all or --url="
+msgstr "опциÑта „--default=“ е неÑъвмеÑтима Ñ â€ž--all“, „--url=“"
-msgid "error processing config file(s)"
-msgstr "грешка при обработката на конфигурационен файл"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "опциÑта „--url=“ е неÑъвмеÑтима Ñ â€ž--all“, „--regexp“, „--value“"
-msgid "editing stdin is not supported"
-msgstr "не Ñе поддържа редактиране на ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´"
+msgid "Filter"
+msgstr "Филтриране"
-msgid "editing blobs is not supported"
-msgstr "не Ñе поддържа редактиране на обекти-BLOB"
+msgid "replace multi-valued config option with new value"
+msgstr "замÑна на наÑтройка, приемаща много ÑтойноÑти, Ñ Ð½Ð¾Ð²Ð° ÑтойноÑÑ‚"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде Ñъздаден"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr "низ за подаване четим от хора (при нужда отпред Ñе Ð´Ð¾Ð±Ð°Ð²Ñ â€ž#“)"
+
+msgid "add a new line without altering any existing values"
+msgstr "добавÑне на нов ред без промÑна на ÑъщеÑтвуващи ÑтойноÑти"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "опциÑта „--fixed-value“ изиÑква опциÑта „--value=ШÐБЛОÐ_ЗÐ_СТОЙÐОСТ“"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "опциитe „--append“ и „--value=ШÐБЛОÐ_ЗÐ_СТОЙÐОСТ“ Ñа неÑъвмеÑтими"
#, c-format
msgid ""
@@ -5683,8 +5778,94 @@ msgstr ""
msgid "no such section: %s"
msgstr "такъв раззел нÑма: %s"
+msgid "editing stdin is not supported"
+msgstr "не Ñе поддържа редактиране на ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´"
+
+msgid "editing blobs is not supported"
+msgstr "не Ñе поддържа редактиране на обекти-BLOB"
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде Ñъздаден"
+
+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 ""
+"извеждане на ÑтойноÑтите за РЕГУЛЯРÐиÑ_ИЗРÐЗ: name-regex "
+"[ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "извеждане на ÑтойноÑтта за ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð°Ð´Ñ€ÐµÑ: РÐЗДЕЛ[.ПРОМЕÐЛИВÐ] ÐДРЕС"
+
+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 "open an editor"
+msgstr "отварÑне на редактор"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "намиране на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер [СТÐÐДÐРТÐО]"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "извеждане на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер (СТÐÐД_ИЗХОД_ÐÐ_ТЕРМИÐÐЛ)"
+
+msgid "with --get, use default value when missing entry"
+msgstr "Ñ â€ž--get“ Ñе използва Ñтандартна СТОЙÐОСТ при липÑваща"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "опциÑта „--get-color“ не ÑъответÑтва на вида на променливата"
+
+msgid "no action specified"
+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 "--comment is only applicable to add/set/replace operations"
+msgstr ""
+"опциÑта „--comment“ е ÑъвмеÑтима Ñамо Ñ Ð´ÐµÐ¹ÑтвиÑта „add“ (добавÑне)/„set“ "
+"(задаване)/„replace“ (замÑна)"
+
msgid "print sizes in human readable format"
-msgstr "извеждане на размерите на обектите във формат леÑно четим от хора"
+msgstr "извеждане на размерите на обектите във формат четим от хора"
#, c-format
msgid ""
@@ -5857,7 +6038,7 @@ msgid ""
"git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
" [--mode=<mode>]"
msgstr ""
-"git diagnose [(-o | --output-directory) ПЪТ] [(-s | --suffix) ФОРМÐТ]\n"
+"git diagnose [(-o|--output-directory) ПЪТ] [(-s|--suffix) ФОРМÐТ]\n"
" [--diagnose[=РЕЖИМ]]"
msgid "specify a destination for the diagnostics archive"
@@ -6100,7 +6281,7 @@ msgid "git fetch [<options>] <group>"
msgstr "git fetch [ОПЦИЯ…] ГРУПÐ"
msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
-msgstr "git fetch --multiple [ОПЦИЯ…] [(ХРÐÐИЛИЩЕ | ГРУПÐ)…]"
+msgstr "git fetch --multiple [ОПЦИЯ…] [(ХРÐÐИЛИЩЕ|ГРУПÐ)…]"
msgid "git fetch --all [<options>]"
msgstr "git fetch --all [ОПЦИЯ…]"
@@ -6182,8 +6363,8 @@ msgstr ""
" git config fetch.showForcedUpdates false\n"
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "хранилището „%s“ не изпрати вÑички необходими обекти\n"
+msgid "%s did not send all necessary objects"
+msgstr "хранилището „%s“ не изпрати вÑички необходими обекти"
#, c-format
msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -6222,8 +6403,8 @@ msgid "option \"%s\" value \"%s\" is not valid for %s"
msgstr "ÑтойноÑтта „%2$s“ за опциÑта „%1$s“ не е ÑъвмеÑтима Ñ â€ž%3$s“"
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "опциÑта „%s“ Ñе преÑкача при „%s“\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "опциÑта „%s“ Ñе преÑкача при „%s“"
#, c-format
msgid "%s is not a valid object"
@@ -6442,8 +6623,7 @@ 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 ФÐЙЛ]"
+msgstr "git fmt-merge-msg [-m СЪОБЩЕÐИЕ] [--log[=БРОЙ]|--no-log] [--file ФÐЙЛ]"
msgid "populate log with at most <n> entries from shortlog"
msgstr ""
@@ -6513,6 +6693,9 @@ msgstr "извеждане Ñамо на указателите, които не
msgid "read reference patterns from stdin"
msgstr "изчитане на шаблоните за указатели от ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´"
+msgid "also include HEAD ref and pseudorefs"
+msgstr "включване и на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“ както и пÑевдо указателите"
+
msgid "unknown arguments supplied with --stdin"
msgstr "непознат аргумент към опциÑта „--stdin“"
@@ -6525,12 +6708,16 @@ msgstr "наÑтройка"
msgid "config key storing a list of repository paths"
msgstr "наÑтройка, коÑто Ñъдържа ÑпиÑък Ñ Ð¿ÑŠÑ‚Ð¸Ñ‰Ð° към хранилища"
+msgid "keep going even if command fails in a repository"
+msgstr ""
+"продължаване на дейÑтвието дори и командата да е неуÑпешна в нÑкое хранилище"
+
msgid "missing --config=<config>"
msgstr "липÑва --config=ÐÐСТРОЙКÐ"
#, c-format
msgid "got bad config --config=%s"
-msgstr "получена е неправилена наÑтройка „--config=%s“"
+msgstr "получена е неправилна наÑтройка „--config=%s“"
msgid "unknown"
msgstr "непознат"
@@ -6676,7 +6863,7 @@ msgstr "%s: неÑвързаниÑÑ‚ връх „HEAD“ не Ñочи към н
#, c-format
msgid "notice: %s points to an unborn branch (%s)"
-msgstr "предупреждение: „%s“ Ñочи към вÑе още неÑъщеÑтвуващ клон (%s)"
+msgstr "предупреждение: „%s“ Ñочи към неродѐн клон (%s)"
#, c-format
msgid "Checking cache tree of %s"
@@ -6888,12 +7075,18 @@ msgstr "окаÑтрÑне на обектите, към които нищо нÐ
msgid "pack unreferenced objects separately"
msgstr "пакетиране на обектите, към които нищо не Ñочи, отделно"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "Ñ â€ž--cruft“ размерът на новите ненужни пакети Ñе ограничава"
+
msgid "be more thorough (increased runtime)"
msgstr "изчерпателно търÑене на боклука (за Ñметка на повече време работа)"
msgid "enable auto-gc mode"
msgstr "включване на автоматичното Ñъбиране на боклука (auto-gc)"
+msgid "perform garbage collection in the background"
+msgstr "Ñъбиране на боклука във фонов режим"
+
msgid "force running gc even if there may be another gc running"
msgstr ""
"изрично Ñтартиране на Ñъбирането на боклука, дори и ако вече работи друго "
@@ -6998,6 +7191,9 @@ msgstr "задачата „%s“ не може да Ñе избере повеÑ
msgid "run tasks based on the state of the repository"
msgstr "изпълнÑване на задачи Ñпоред ÑÑŠÑтоÑнието на хранилището"
+msgid "perform maintenance in the background"
+msgstr "извършване на дейноÑтите по поддръжка на заден фон"
+
msgid "frequency"
msgstr "чеÑтота"
@@ -7070,12 +7266,6 @@ msgstr ""
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“"
@@ -7084,6 +7274,12 @@ msgstr "неуÑпешно изтриване на „%s“"
msgid "failed to flush '%s'"
msgstr "грешка при изчиÑтването на буферите при запиÑването на „%s“"
+msgid "failed to start systemctl"
+msgstr "неуÑпешно Ñтартиране на „systemctl“"
+
+msgid "failed to run systemctl"
+msgstr "неуÑпешно изпълнение на „systemctl“"
+
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "непознат аргумент към „--scheduler“: %s"
@@ -7107,6 +7303,9 @@ msgstr "ПЛÐÐИРÐЩ_МОДУЛ"
msgid "scheduler to trigger git maintenance run"
msgstr "ПЛÐÐИРÐЩиÑÑ‚_МОДУЛ, който да изпълнÑва задачите"
+msgid "failed to set up maintenance schedule"
+msgstr "неуÑпешно наÑрочване на задачите по поддръжка"
+
msgid "failed to add repo to global config"
msgstr "неуÑпешно добавÑне на хранилище към файла Ñ Ð³Ð»Ð¾Ð±Ð°Ð»Ð½Ð¸ наÑтройки"
@@ -7134,8 +7333,8 @@ msgid "no threads support, ignoring %s"
msgstr "липÑва поддръжка за нишки. „%s“ ще Ñе пренебрегне"
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "дървото не може да бъде прочетено (%s)"
+msgid "unable to read tree %s"
+msgstr "дървото не може да бъде прочетено: %s"
#, c-format
msgid "unable to grep from object of type %s"
@@ -7182,7 +7381,7 @@ msgstr ""
msgid "search in subdirectories (default)"
msgstr "търÑене в поддиректориите (Ñтандартно)"
-msgid "descend at most <depth> levels"
+msgid "descend at most <n> levels"
msgstr "навлизане макÑимално на тази ДЪЛБОЧИÐРв дървото"
msgid "use extended POSIX regular expressions"
@@ -7335,7 +7534,7 @@ 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"
+"git hash-object [-t ВИД] [-w] [--path=ФÐЙЛ|--no-filters]\n"
" [--stdin [--literally]] [--] ФÐЙЛ…"
msgid "git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"
@@ -7559,10 +7758,6 @@ msgstr ""
"СЪВПÐДЕÐИЕ ÐРСТОЙÐОСТИТЕ ЗРСУМИТЕ ЗРSHA1: „%s“ ÐРДВРРÐЗЛИЧÐИ ОБЕКТÐ!"
#, c-format
-msgid "unable to read %s"
-msgstr "обектът „%s“ не може да бъде прочетен"
-
-#, c-format
msgid "cannot read existing object info %s"
msgstr "ÑъщеÑтвуващиÑÑ‚ обект в „%s“ не може да бъде прочетен"
@@ -7701,89 +7896,16 @@ msgstr "опциÑта „--verify“ изиÑква име на пакетен
msgid "fsck error in pack objects"
msgstr "грешка при проверка Ñ â€žfsck“ на пакетните обекти"
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "не може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за шаблона „%s“"
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "директориÑта „%s“ не може да бъде отворена"
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "връзката „%s“ не може да бъде прочетена"
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "не може да Ñе Ñъздаде Ñимволна връзка „%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"
-
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
-"git init [-q | --quiet] [--bare] [--template=ДИРЕКТОРИЯ_С_ШÐБЛОÐИ]\n"
+"git init [-q|--quiet] [--bare] [--template=ДИРЕКТОРИЯ_С_ШÐБЛОÐИ]\n"
" [--separate-git-dir ДИРЕКТОРИЯ_ÐÐ_GIT] [--object-format=ФОРМÐТ]\n"
-" [-b КЛОР| --initial-branch=КЛОÐ]\n"
+" [-b КЛОÐ|--initial-branch=КЛОÐ]\n"
" [--shared[=ПРÐÐ’ÐÌ€]] [ДИРЕКТОРИЯ]"
msgid "permissions"
@@ -7828,19 +7950,48 @@ msgstr "опциÑта „--separate-git-dir“ е неÑъвмеÑтима Ñ Ð
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer ЛЕКСЕМÐ[(=|:)СТОЙÐОСТ])…]\n"
+" [(--trailer (КЛЮЧ|СИÐОÐИМ)[(=|:)СТОЙÐОСТ])…]\n"
" [--parse] [ФÐЙЛ…]"
+#, c-format
+msgid "could not stat %s"
+msgstr "Ðе може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за „%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 read input file '%s'"
+msgstr "входниÑÑ‚ файл „%s“ не може да бъде прочетен"
+
+msgid "could not read from stdin"
+msgstr "от ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´ не може да Ñе чете"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "временниÑÑ‚ файл не може да Ñе преименува на „%s“"
+
msgid "edit files in place"
msgstr "директно редактиране на файловете"
msgid "trim empty trailers"
msgstr "изчиÑтване на празните епилози"
+msgid "placement"
+msgstr "меÑтоположение"
+
msgid "where to place the new trailer"
msgstr "къде да Ñе поÑтави новиÑÑ‚ епилог"
@@ -7853,17 +8004,19 @@ msgstr "дейÑтвие при липÑващ епилог"
msgid "output only the trailers"
msgstr "извеждане Ñамо на епилозите"
-msgid "do not apply config rules"
-msgstr "без прилагане на правилата за наÑтройките"
+msgid "do not apply trailer.* configuration variables"
+msgstr "без прилагане на конфигуриращи променливи, завършващи Ñ ÐµÐ¿Ð¸Ð»Ð¾Ð³.*"
-msgid "join whitespace-continued values"
-msgstr "Ñливане на ÑтойноÑтите поÑледване от знаци за интервали"
+msgid "reformat multiline trailer values as single-line values"
+msgstr ""
+"форматиране на епилози, които заемат повече от един ред, в ÑтойноÑти на един "
+"ред"
-msgid "set parsing options"
-msgstr "опции при анализ"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "пÑевдоним на комбинациÑта „--only-trailers --only-input --unfold“"
-msgid "do not treat --- specially"
-msgstr "„---“ нÑма Ñпециално значение"
+msgid "do not treat \"---\" as the end of input"
+msgstr "„---“ не отбелÑзва ÐºÑ€Ð°Ñ Ð½Ð° входа"
msgid "trailer(s) to add"
msgstr "епилози за добавÑне"
@@ -7920,9 +8073,6 @@ msgstr "опциÑта „-LДИÐПÐЗОÐ:ФÐЙЛ“ не може да Ñе
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: повреден файл"
@@ -7952,6 +8102,10 @@ msgstr "трÑбва да зададете точно един диапазон"
msgid "not a range"
msgstr "не е диапазон"
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "файлът Ñ Ð¾Ð¿Ð¸Ñанието на клона „%s“ не може да бъде прочетен"
+
msgid "cover letter needs email format"
msgstr "придружаващото пиÑмо трÑбва да е форматирано като е-пиÑмо"
@@ -7963,7 +8117,7 @@ msgid "insane in-reply-to: %s"
msgstr "неправилен формат на заглавната чаÑÑ‚ за отговор „in-reply-to“: %s"
msgid "git format-patch [<options>] [<since> | <revision-range>]"
-msgstr "git format-patch [ОПЦИЯ…] [ОТ | ДИÐПÐЗОÐ_ÐÐ_ВЕРСИИТЕ]"
+msgstr "git format-patch [ОПЦИЯ…] [ОТ|ДИÐПÐЗОÐ_ÐÐ_ВЕРСИИТЕ]"
msgid "two output directories?"
msgstr "може да укажете макÑимум една Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð·Ð° изход"
@@ -8043,8 +8197,11 @@ msgstr "отбелÑзване, че това е N-тата поредна реÐ
msgid "max length of output filename"
msgstr "макÑимална дължина на име на вÑеки пакетен файл"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "използване на „[RFC PATCH]“ вмеÑто „[PATCH]“"
+msgid "rfc"
+msgstr "ПРЕФИКС"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "добавÑне на този ПРЕФИКС (Ñтандартно е „RFC“) пред „PATCH“"
msgid "cover-from-description-mode"
msgstr "режим-придружаващо-пиÑмо-по-опиÑание"
@@ -8054,6 +8211,9 @@ msgstr ""
"генериране на чаÑтите на придружаващото пиÑмо на базата на опиÑанието на "
"клона"
+msgid "use branch description from file"
+msgstr "ползване на опиÑание на клон от файл"
+
msgid "use [<prefix>] instead of [PATCH]"
msgstr "използване на този „[ПРЕФИКС]“ вмеÑто „[PATCH]“"
@@ -8121,8 +8281,8 @@ msgstr "включване на кръпката в текÑта на пиÑма
msgid "enable message threading, styles: shallow, deep"
msgstr ""
-"използване на нишки за ÑъобщениÑта. СТИЛът е „shallow“ (плитък) или "
-"„deep“ (дълбок)"
+"използване на нишки за ÑъобщениÑта. СТИЛът е „shallow“ (плитък) или „deep“ "
+"(дълбок)"
msgid "signature"
msgstr "подпиÑ"
@@ -8226,16 +8386,8 @@ msgstr ""
"ОТДÐЛЕЧЕÐ_КЛОÐ.\n"
#, c-format
-msgid "bad ls-files format: element '%s' does not start with '('"
-msgstr "неправилен формат за „ls-tree“: елементът „%s“ не започва Ñ â€ž(“"
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "неправилен формат за „ls-tree“: елементът „%s“ не завършва Ñ â€ž)“"
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "неправилен формат за „ls-tree“: %%%.*s"
+msgid "could not get object info about '%s'"
+msgstr "не може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° обекта „%s“"
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [ОПЦИЯ…] [ФÐЙЛ…]"
@@ -8289,7 +8441,7 @@ msgid "show resolve-undo information"
msgstr "извеждане на информациÑта за отмÑна на разрешените подаваниÑ"
msgid "skip files matching pattern"
-msgstr "преÑкачане на файловете напаÑващи ШÐБЛОÐа"
+msgstr "преÑкачане на файловете напаÑващи на ШÐБЛОÐа"
msgid "read exclude patterns from <file>"
msgstr "изчитане на шаблоните за игнориране от ФÐЙЛ"
@@ -8332,13 +8484,13 @@ msgstr ""
"deduplicate“/„--eol“"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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] [ХРÐÐИЛИЩЕ [ШÐБЛОÐ]]"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=КОМÐÐДÐ]\n"
+" [-q|--quiet] [--exit-code] [--get-url] [--sort=КЛЮЧ]\n"
+" [--symref] [ХРÐÐИЛИЩЕ [ШÐБЛОÐ…]]"
msgid "do not print remote URL"
msgstr "без извеждане на адреÑите на отдалечените хранилища"
@@ -8352,8 +8504,11 @@ msgstr "път към командата „git-upload-pack“ на отдале
msgid "limit to tags"
msgstr "Ñамо етикетите"
-msgid "limit to heads"
-msgstr "Ñамо върховете"
+msgid "limit to branches"
+msgstr "Ñамо клоните"
+
+msgid "deprecated synonym for --branches"
+msgstr "оÑтарÑл Ñиноним на „--branches“"
msgid "do not show peeled tags"
msgstr "без проÑледÑване на непреките етикети"
@@ -8370,22 +8525,6 @@ msgstr "извеждане на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð·Ð°ÐµÐ´Ð½Ð¾ Ñ Ð¾Ð±ÐµÐºÑ‚Ð°
msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
msgstr "git ls-tree [ОПЦИЯ…] УКÐЗÐТЕЛ_КЪМ_ДЪРВО [ПЪТ…]"
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "не може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° обекта „%s“"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "неправилен формат за „ls-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 "извеждане Ñамо на дървета"
@@ -8467,10 +8606,10 @@ msgid "empty mbox: '%s'"
msgstr "празна пощенÑка ÐºÑƒÑ‚Ð¸Ñ mbox: „%s“"
msgid "git merge-base [-a | --all] <commit> <commit>..."
-msgstr "git merge-base [-a | --all] ПОДÐÐ’ÐÐЕ ПОДÐÐ’ÐÐЕ…"
+msgstr "git merge-base [-a|--all] ПОДÐÐ’ÐÐЕ ПОДÐÐ’ÐÐЕ…"
msgid "git merge-base [-a | --all] --octopus <commit>..."
-msgstr "git merge-base [-a | --all] --octopus ПОДÐÐ’ÐÐЕ…"
+msgstr "git merge-base [-a|--all] --octopus ПОДÐÐ’ÐÐЕ…"
msgid "git merge-base --is-ancestor <commit> <commit>"
msgstr "git merge-base --is-ancestor ПОДÐÐ’ÐÐЕ_1 ПОДÐÐ’ÐÐЕ_2"
@@ -8504,23 +8643,31 @@ msgstr ""
"git merge-file [ОПЦИЯ…] [-L ИМЕ_1 [-L ОРИГИÐÐЛ [-L ИМЕ_2]]] ФÐЙЛ_1 ОРИГ_ФÐЙЛ "
"ФÐЙЛ_2"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"опциÑта приема Ñледните варианти за алгоритъм за разлики: „myers“ (по "
+"МайерÑ), „minimal“ (минимизиране на разликите), „patience“ (паÑианÑ) и "
+"„histogram“ (хиÑтограмен)"
+
msgid "send results to standard output"
msgstr "извеждане на резултатите на ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð¸Ð·Ñ…Ð¾Ð´"
+msgid "use object IDs instead of filenames"
+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 "<algorithm>"
+msgstr "ÐЛГОРИТЪМ"
-msgid "for conflicts, use a union version"
-msgstr "при конфликти да Ñе ползва обединена верÑиÑ"
+msgid "choose a diff algorithm"
+msgstr "избор на ÐЛГОРИТЪМа за разлики"
msgid "for conflicts, use this marker size"
msgstr "при конфликти да Ñе ползва маркер Ñ Ñ‚Ð°ÐºÑŠÐ² БРОЙ знаци"
@@ -8532,6 +8679,13 @@ msgid "set labels for file1/orig-file/file2"
msgstr "задаване на етикети за ФÐЙЛ_1/ОРИГИÐÐЛ/ФÐЙЛ_2"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "обектът „%s“ не ÑъщеÑтвува"
+
+msgid "Could not write object file"
+msgstr "Файлът Ñ Ð¾Ð±ÐµÐºÑ‚Ð¸ не може да Ñе запише"
+
+#, c-format
msgid "unknown option %s"
msgstr "непозната опциÑ: „%s“"
@@ -8550,12 +8704,16 @@ msgstr "поддържа Ñе Ñамо Ñливане на точно две иÑ
#, c-format
msgid "could not resolve ref '%s'"
-msgstr "указателÑÑ‚ „%s“ не може да бъде изтрит"
+msgstr "указателÑÑ‚ „%s“ не може да бъде проÑледен"
#, c-format
msgid "Merging %s with %s\n"
msgstr "Сливане на „%s“ Ñ â€ž%s“\n"
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "„%s“ не може да Ñе анализира като дърво"
+
msgid "not something we can merge"
msgstr "не може да Ñе Ñлее"
@@ -8593,11 +8751,18 @@ msgstr "извършване на множеÑтво ÑливаниÑ, по ед
msgid "specify a merge-base for the merge"
msgstr "база за Ñливането"
+msgid "option=value"
+msgstr "ОПЦИЯ=СТОЙÐОСТ"
+
+msgid "option for selected merge strategy"
+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 "unknown strategy option: -X%s"
+msgstr "непозната Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð° ÑтратегиÑ: -X%s"
#, c-format
msgid "malformed input line: '%s'."
@@ -8641,7 +8806,7 @@ 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 "Ñъздаване на едно подаване вмеÑто извършване на Ñливане"
@@ -8667,12 +8832,6 @@ 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 "СЪОБЩЕÐИЕ при подаването ÑÑŠÑ Ñливане (при ÑъщинÑки ÑливаниÑ)"
@@ -8736,10 +8895,6 @@ 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“ не може да бъде запиÑан"
@@ -8766,10 +8921,10 @@ msgstr "Празно Ñъобщение предотвратÑва подаваÐ
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Редовете, които започват Ñ â€ž%c“, ще бъдат пропуÑнати, а празно\n"
+"Редовете, които започват Ñ â€ž%s“, ще бъдат пропуÑнати, а празно\n"
"Ñъобщение преуÑтановÑва подаването.\n"
msgid "Empty commit message."
@@ -8935,9 +9090,6 @@ msgstr "обектът Ñ ÐµÑ‚Ð¸ÐºÐµÑ‚ не може да бъде прочетÐ
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "обектът „%s“ е Ñ ÐµÑ‚Ð¸ÐºÐµÑ‚ за %s, но е %s"
-msgid "could not read from stdin"
-msgstr "от ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´ не може да Ñе чете"
-
msgid "tag on stdin did not pass our strict fsck check"
msgstr "етикетът на ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´ не преминава Ñтрогата проверка Ñ â€žfsck“"
@@ -8990,6 +9142,9 @@ msgstr ""
msgid "write multi-pack bitmap"
msgstr "запазване на многопакетната битова маÑка"
+msgid "write a new incremental MIDX"
+msgstr "запазване на нов файл Ñ Ð½Ð°Ñ€Ð°Ñтващ Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети"
+
msgid "write multi-pack index containing only given indexes"
msgstr ""
"запазване на битовата маÑка за множеÑтво пакети, Ñъдържаща Ñамо дадените "
@@ -9044,8 +9199,8 @@ msgstr "целта ÑъщеÑтвува"
msgid "can not move directory into itself"
msgstr "Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ðµ може да Ñе премеÑти в Ñебе Ñи"
-msgid "cannot move directory over file"
-msgstr "Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ðµ може да Ñе премеÑти върху файл"
+msgid "destination already exists"
+msgstr "целта ÑъщеÑтвува"
msgid "source directory is empty"
msgstr "първоначалната Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ðµ празна"
@@ -9126,22 +9281,26 @@ msgid "git notes [--ref <notes-ref>] [list [<object>]]"
msgstr "git notes [--ref УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ] [list [ОБЕКТ]]"
msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
msgstr ""
-"git notes [--ref УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ] add [-f] [--allow-empty] [-m СЪОБЩЕÐИЕ "
-"| -F ФÐЙЛ | (-c | -C) ОБЕКТ] [ОБЕКТ]"
+"git notes [--ref УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ] add [-f] [--allow-empty] [--"
+"[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m "
+"СЪОБЩЕÐИЕ|-F ФÐЙЛ|(-c|-C) ОБЕКТ] [ОБЕКТ]"
msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
msgstr ""
"git notes [--ref УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ] copy [-f] ОБЕКТ_ИЗТОЧÐИК ОБЕКТ_ЦЕЛ"
msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
msgstr ""
-"git notes [--ref УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ] append [--allow-empty] [-m СЪОБЩЕÐИЕ | "
-"-F ФÐЙЛ | (-c | -C) ОБЕКТ] [ОБЕКТ]"
+"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] [ОБЕКТ]"
@@ -9152,7 +9311,7 @@ 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 СТРÐТЕГИЯ] "
+"git notes [--ref УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ] merge [-v|-q] [-s СТРÐТЕГИЯ] "
"УКÐЗÐТЕЛ_ЗÐ_БЕЛЕЖКÐ"
msgid "git notes [--ref <notes-ref>] remove [<object>...]"
@@ -9203,10 +9362,6 @@ 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“ не може да Ñе прочете"
@@ -9276,6 +9431,15 @@ 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 "
@@ -9364,9 +9528,8 @@ msgid ""
"cat_sort_uniq)"
msgstr ""
"коригиране на конфликтите при Ñливане на бележките чрез тази СТРÐТЕГИЯ — "
-"„manual“ (ръчно), „ours“ (вашата верÑиÑ), „theirs“ (чуждата верÑиÑ), "
-"„union“ (обединÑване), „cat_sort_uniq“ (обединÑване, подреждане, уникални "
-"резултати)"
+"„manual“ (ръчно), „ours“ (вашата верÑиÑ), „theirs“ (чуждата верÑиÑ), „union“ "
+"(обединÑване), „cat_sort_uniq“ (обединÑване, подреждане, уникални резултати)"
msgid "Committing unmerged notes"
msgstr "Подаване на неÑлети бележки"
@@ -9440,12 +9603,12 @@ msgstr "непозната подкоманда: „%s“"
msgid "git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"
msgstr ""
-"git pack-objects --stdout [ОПЦИЯ…] [< СПИСЪК_С_УКÐЗÐТЕЛИ | < СПИСЪК_С_ОБЕКТИ]"
+"git pack-objects --stdout [ОПЦИЯ…] [< СПИСЪК_С_УКÐЗÐТЕЛИ|< СПИСЪК_С_ОБЕКТИ]"
msgid ""
"git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"
msgstr ""
-"git pack-objects [ОПЦИЯ…] ПРЕФИКС_ÐÐ_ИМЕТО [< СПИСЪК_С_УКÐЗÐТЕЛИ | < "
+"git pack-objects [ОПЦИЯ…] ПРЕФИКС_ÐÐ_ИМЕТО [< СПИСЪК_С_УКÐЗÐТЕЛИ|< "
"СПИСЪК_С_ОБЕКТИ]"
#, c-format
@@ -9555,6 +9718,11 @@ msgid "inconsistency with delta count"
msgstr "неправилен брой разлики"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr ""
+"неправилна ÑтойноÑÑ‚ за преизползването на пакети „pack.allowPackReuse“: „%s“"
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -9566,8 +9734,8 @@ msgstr ""
msgid ""
"object already configured in another uploadpack.blobpackfileuri (got '%s')"
msgstr ""
-"вече има наÑтройка за обекта в друг ред „uploadpack."
-"blobpackfileuri“ (получена е „%s“)"
+"вече има наÑтройка за обекта в друг ред „uploadpack.blobpackfileuri“ "
+"(получена е „%s“)"
#, c-format
msgid "could not get type of object %s in pack %s"
@@ -9582,13 +9750,13 @@ msgid "packfile %s cannot be accessed"
msgstr "пакетниÑÑ‚ файл „%s“ не може да бъде доÑтъпен"
msgid "Enumerating cruft objects"
-msgstr "ИзброÑване на излишните обекти"
+msgstr "ИзброÑване на ненужните обекти"
msgid "unable to add cruft objects"
-msgstr "неуÑпешно добавÑне на излишни обекти"
+msgstr "неуÑпешно добавÑне на ненужни обекти"
msgid "Traversing cruft objects"
-msgstr "Обхождане на излишните обекти"
+msgstr "Обхождане на ненужните обекти"
#, c-format
msgid ""
@@ -9608,7 +9776,7 @@ msgstr ""
msgid "could not load cruft pack .mtimes"
msgstr ""
-"времената на промÑна (.mtimes) на пакета Ñ Ð¸Ð·Ð»Ð¸ÑˆÐ½Ð¸ файлове не може да Ñе "
+"времената на промÑна (.mtimes) на пакета Ñ Ð½ÐµÐ½ÑƒÐ¶Ð½Ð¸ файлове не може да Ñе "
"заредÑÑ‚"
msgid "cannot open pack index"
@@ -9727,10 +9895,10 @@ msgid "unpack unreachable objects newer than <time>"
msgstr "разпакетиране на недоÑтижимите обекти, които Ñа по-нови от това ВРЕМЕ"
msgid "create a cruft pack"
-msgstr "Ñъздаване на пакет Ñ Ð¸Ð·Ð»Ð¸ÑˆÐ½Ð¸Ñ‚Ðµ обекти"
+msgstr "Ñъздаване на пакет Ñ Ð½ÐµÐ½ÑƒÐ¶Ð½Ð¸Ñ‚Ðµ обекти"
msgid "expire cruft objects older than <time>"
-msgstr "обÑвÑване на излишните обекти по-Ñтари от това ВРЕМЕ за оÑтарели"
+msgstr "обÑвÑване на ненужните обекти по-Ñтари от това ВРЕМЕ за оÑтарели"
msgid "use the sparse reachability algorithm"
msgstr "използване на алгоритъм за чаÑтична доÑтижимоÑÑ‚"
@@ -9808,9 +9976,6 @@ msgstr ""
"опциÑта „--thin“не може да Ñе използва за Ñъздаване на пакетни файлове Ñ "
"индекÑ"
-msgid "cannot use --filter without --stdout"
-msgstr "опциÑта „--filter“ изиÑква „--stdout“"
-
msgid "cannot use --filter with --stdin-packs"
msgstr "опциите „--filter“ и „--stdin-packs“ Ñа неÑъвмеÑтими"
@@ -9824,19 +9989,16 @@ msgstr "вътрешниÑÑ‚ ÑпиÑък на верÑии и опциÑта â€
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>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Общо: %<PRIu32> (разлики: %<PRIu32>), преизползвани: %<PRIu32> (разлики: "
-"%<PRIu32>), преизползвани при пакетиране: %<PRIu32>"
+"%<PRIu32>), преизползвани при пакетиране: %<PRIu32> (от %<PRIuMAX>)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9854,8 +10016,12 @@ msgstr ""
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]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--auto] [--include ШÐБЛОÐ] [--exclude "
+"ШÐБЛОÐ]"
msgid "pack everything"
msgstr "пакетиране на вÑичко"
@@ -9863,14 +10029,23 @@ msgstr "пакетиране на вÑичко"
msgid "prune loose refs (default)"
msgstr "окаÑтрÑне на недоÑтижимите указатели (Ñтандартно)"
+msgid "auto-pack refs as needed"
+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]"
+msgstr "git patch-id [--stable|--unstable|--verbatim]"
msgid "use the unstable patch-id algorithm"
-msgstr "използване на неÑтабилен алгоритъм за идентифициране на кръпка"
+msgstr "използване на неÑÑ‚Ð°Ð±Ð¸Ð»Ð½Ð¸Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚ÑŠÐ¼ за идентифициране на кръпка"
msgid "use the stable patch-id algorithm"
-msgstr "използване на Ñтабилен алгоритъм за идентифициране на кръпка"
+msgstr "използване на ÑÑ‚Ð°Ð±Ð¸Ð»Ð½Ð¸Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚ÑŠÐ¼ за идентифициране на кръпка"
msgid "don't strip whitespace from the patch"
msgstr "без махане на празните знаци в кръпката"
@@ -9922,6 +10097,12 @@ 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."
@@ -10023,7 +10204,7 @@ msgstr ""
"приоритет пред наÑтройките.\n"
msgid "Updating an unborn branch with changes added to the index."
-msgstr "ОбновÑване на вÑе още неÑъздаден клон Ñ Ð¿Ñ€Ð¾Ð¼ÐµÌ€Ð½Ð¸Ñ‚Ðµ от индекÑа"
+msgstr "ОбновÑване на неродѐн клон Ñ Ð¿Ñ€Ð¾Ð¼ÐµÌ€Ð½Ð¸Ñ‚Ðµ от индекÑа"
msgid "pull with rebase"
msgstr "издърпване Ñ Ð¿Ñ€ÐµÐ±Ð°Ð·Ð¸Ñ€Ð°Ð½Ðµ"
@@ -10171,8 +10352,8 @@ msgstr ""
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
-"Ðе Ñте указали верÑÐ¸Ñ Ð·Ð° подаване, а наÑтройката „push.default“ е "
-"„nothing“ (нищо без изрично указана верÑÐ¸Ñ Ð´Ð° не Ñе изтлаÑква)"
+"Ðе Ñте указали верÑÐ¸Ñ Ð·Ð° подаване, а наÑтройката „push.default“ е „nothing“ "
+"(нищо без изрично указана верÑÐ¸Ñ Ð´Ð° не Ñе изтлаÑква)"
#, c-format
msgid ""
@@ -10187,35 +10368,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 ""
-"ОбновÑването е отхвърлено, защото върхът на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ Ð²Ð¸ клон е преди върха "
-"на\n"
+"ОбновÑването е отхвърлено, защото върхът на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ Ð²Ð¸ клон Ñледва върха на\n"
"Ð¾Ñ‚Ð´Ð°Ð»ÐµÑ‡ÐµÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½. ВнеÑете отдалечените промѐни (напр. Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ñ‚Ð° „git "
"pull…“),\n"
-"преди отново да изтлаÑкате промѐните. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ раздела\n"
-"„Note about fast-forwards“ в Ñтраницата от ръководÑтвото „git push --help“."
+"преди отново да изтлаÑкате промѐните.\n"
+"За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ раздела „Note about fast-forwards“ в Ñтраницата "
+"от\n"
+"ръководÑтвото „git push --help“."
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-"ОбновÑването е отхвърлено, защото върхът на изтлаÑÐºÐ²Ð°Ð½Ð¸Ñ ÐºÐ»Ð¾Ð½ е преди върха\n"
+"ОбновÑването е отхвърлено, защото върхът на изтлаÑÐºÐ²Ð°Ð½Ð¸Ñ ÐºÐ»Ð¾Ð½ Ñледва върха\n"
"на Ð¾Ñ‚Ð´Ð°Ð»ÐµÑ‡ÐµÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½. Преминете към клона и внеÑете отдалечените промѐни "
"(напр.\n"
-"Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ñ‚Ð° „git pull…“), преди отново да изтлаÑкате промѐните. За повече\n"
-"Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð³Ð»ÐµÐ´Ð½ÐµÑ‚Ðµ раздела „Note about fast-forwards“ в Ñтраницата от\n"
+"Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ñ‚Ð° „git pull…“), преди отново да изтлаÑкате промѐните.\n"
+"За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ раздела „Note about fast-forwards“ в Ñтраницата "
+"от\n"
"ръководÑтвото „git push --help“."
msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
"ОбновÑването е отхвърлено, защото хранилището, към което изтлаÑквате, "
@@ -10245,14 +10428,17 @@ msgstr ""
"да го променÑте да Ñочи към подобен обект.\n"
msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-"ОбновÑването е отхвърлено, защото върхът на ÑледÑÑ‰Ð¸Ñ ÐºÐ»Ð¾Ð½ е обновÑван Ñлед\n"
-"поÑледното изтеглÑне. ВнеÑете отдалечените промѐни (напр. Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ñ‚Ð°\n"
-"„git pull…“), преди отново принудително да изтлаÑкате промѐните.\n"
+"ОбновÑването е отхвърлено, защото върхът на Ð¾Ñ‚Ð´Ð°Ð»ÐµÑ‡ÐµÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½ Ñъдържа "
+"промени\n"
+"Ñлед поÑледното изтеглÑне. ВнеÑете отдалечените промѐни (напр. Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ñ‚Ð°\n"
+"„git pull…“), преди отново да изтлаÑкате промѐните.\n"
+"За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ раздела „Note about fast-forwards“ в Ñтраницата\n"
+"от ръководÑтвото „git push --help“."
#, c-format
msgid "Pushing to %s\n"
@@ -10414,9 +10600,9 @@ msgid ""
" [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]\n"
" (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
msgstr ""
-"git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=ПРЕФИКС)\n"
-" [-u | -i]] [--index-output=ФÐЙЛ] [--no-sparse-checkout]\n"
-" (--empty | УКÐЗÐТЕЛ_КЪМ_ДЪРВО_1 [УКÐЗÐТЕЛ_КЪМ_ДЪРВО_2 "
+"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>"
@@ -10477,7 +10663,7 @@ msgid ""
"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase> | --keep-base] "
"[<upstream> [<branch>]]"
msgstr ""
-"git rebase [-i] [ОПЦИЯ…] [--exec КОМÐÐДÐ] [--onto ÐОВÐ_БÐЗР| --keep-base] "
+"git rebase [-i] [ОПЦИЯ…] [--exec КОМÐÐДÐ] [--onto ÐОВÐ_БÐЗÐ|--keep-base] "
"[КЛОÐ_ИЗТОЧÐИК [КЛОÐ]]"
msgid ""
@@ -10522,19 +10708,6 @@ msgstr "неправилната ÑтойноÑÑ‚ на „allow_rerere_autoupdat
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"
-"За да откажете пребазирането и да Ñе върнете към първоначалното ÑÑŠÑтоÑние,\n"
-"изпълнете „git rebase --abort“."
-
#, c-format
msgid ""
"\n"
@@ -10563,13 +10736,17 @@ msgstr "не може да Ñе премине към „%s“"
msgid "apply options and merge options cannot be used together"
msgstr "опциите за прилагане и Ñливане Ñа неÑъвмеÑтими"
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr ""
+"комбинациÑта „--empty=ask“ е оÑтарÑла. ВмеÑто Ð½ÐµÑ Ð¿Ð¾Ð»Ð·Ð²Ð°Ð¹Ñ‚Ðµ „--empty=stop“."
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
-"неправилна ÑтойноÑÑ‚ „%s“: вариантите Ñа „drop“ (преÑкачане), "
-"„keep“ (запазване) и „ask“ (питане)"
+"неправилна празна ÑтойноÑÑ‚ „%s“: вариантите Ñа „drop“ (преÑкачане), „keep“ "
+"(запазване) и „stop“ (Ñпиране)"
msgid ""
"--rebase-merges with an empty string argument is deprecated and will stop "
@@ -10762,8 +10939,8 @@ msgstr ""
"„preserve“.\n"
"Тази ÑтойноÑÑ‚ вече не Ñе поддържа, заменете Ñ Ñ â€žmerges“."
-msgid "No rebase in progress?"
-msgstr "Изглежда в момента не тече пребазиране"
+msgid "no rebase in progress"
+msgstr "изглежда в момента не тече пребазиране"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
@@ -10809,17 +10986,6 @@ msgstr ""
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 ""
-"опциите за прилагане Ñа неÑъвмеÑтими Ñ â€žrebase.autoSquash“. Пробвайте да "
-"добавите опциÑта „--no-autosquash“"
-
msgid ""
"apply options are incompatible with rebase.rebaseMerges. Consider adding --"
"no-rebase-merges"
@@ -10975,6 +11141,9 @@ msgstr "трÑбва да укажете директориÑ"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [ОПЦИЯ…] [УКÐЗÐТЕЛ]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10983,7 +11152,7 @@ msgid ""
msgstr ""
"git reflog expire [--expire=ВРЕМЕ] [--expire-unreachable=ВРЕМЕ]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
-" [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
+" [--dry-run|-n] [--verbose] [--all [--single-worktree]|"
"УКÐЗÐТЕЛ…]"
msgid ""
@@ -10991,7 +11160,7 @@ msgid ""
" [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
msgstr ""
"git reflog delete [--rewrite] [--updateref]\n"
-" [--dry-run | -n] [--verbose] УКÐЗÐТЕЛ@{УТОЧÐЕÐИЕ}…"
+" [--dry-run|-n] [--verbose] УКÐЗÐТЕЛ@{УТОЧÐЕÐИЕ}…"
msgid "git reflog exists <ref>"
msgstr "git reflog exists УКÐЗÐТЕЛ"
@@ -11000,6 +11169,10 @@ msgstr "git reflog exists УКÐЗÐТЕЛ"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "неправилно времево клеймо „%s“ подадено към „--%s“"
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "„%s“ не приема аргументи: „%s“"
+
msgid "do not actually prune any entries"
msgstr "без окаÑтрÑне на запиÑи"
@@ -11055,11 +11228,36 @@ msgstr "не е указан журнал Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð·Ð° изтриÐ
msgid "invalid ref format: %s"
msgstr "неправилен формат на указател: %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=ФОРМÐТ [--dry-run]"
+
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+msgid "specify the reference format to convert to"
+msgstr "указване на форма̀та за указател, към който да Ñе конвертира"
+
+msgid "perform a non-destructive dry-run"
+msgstr "пробно изпълнение — без промÑна на данни"
+
+msgid "missing --ref-format=<format>"
+msgstr "липÑва опциÑта --ref-format=ФОРМÐТ"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "хранилището вече ползва форма̀та „%s“"
+
+msgid "enable strict checking"
+msgstr "Ñтроги проверки"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "командата „git refs verify“ не приема аргументи"
+
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] [--"
+"git remote add [-t КЛОÐ] [-m ОСÐОВЕÐ_КЛОÐ] [-f] [--tags|--no-tags] [--"
"mirror=<fetch|push>] ИМЕ ÐДРЕС"
msgid "git remote rename [--[no-]progress] <old> <new>"
@@ -11069,19 +11267,18 @@ msgid "git remote remove <name>"
msgstr "git remote remove ИМЕ"
msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"
-msgstr "git remote set-head ИМЕ (-a | --auto | -d | --delete | КЛОÐ)"
+msgstr "git remote set-head ИМЕ (-a|--auto|-d|--delete|КЛОÐ)"
msgid "git remote [-v | --verbose] show [-n] <name>"
-msgstr "git remote [-v | --verbose] show [-n] ИМЕ"
+msgstr "git remote [-v|--verbose] show [-n] ИМЕ"
msgid "git remote prune [-n | --dry-run] <name>"
-msgstr "git remote prune [-n | --dry-run] ИМЕ"
+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] [(ГРУПР| "
-"ОТДÐЛЕЧЕÐО_ХРÐÐИЛИЩЕ)…]"
+"git remote [-v|--verbose] update [-p|--prune] [(ГРУПÐ|ОТДÐЛЕЧЕÐО_ХРÐÐИЛИЩЕ)…]"
msgid "git remote set-branches [--add] <name> <branch>..."
msgstr "git remote set-branches [--add] ИМЕ КЛОÐ…"
@@ -11114,7 +11311,7 @@ msgid "git remote prune [<options>] <name>"
msgstr "git remote prune [ОПЦИЯ…] ИМЕ"
msgid "git remote update [<options>] [<group> | <remote>]..."
-msgstr "git remote update [ОПЦИЯ…] [ГРУПР| ОТДÐЛЕЧЕÐО_ХРÐÐИЛИЩЕ…]"
+msgstr "git remote update [ОПЦИЯ…] [ГРУПÐ|ОТДÐЛЕЧЕÐО_ХРÐÐИЛИЩЕ…]"
#, c-format
msgid "Updating %s"
@@ -11132,17 +11329,18 @@ msgstr ""
"ползвайте „--mirror=fetch“ или „--mirror=push“"
#, c-format
-msgid "unknown mirror argument: %s"
+msgid "unknown --mirror argument: %s"
msgstr "неправилна ÑтойноÑÑ‚ за „--mirror“: %s"
msgid "fetch the remote branches"
msgstr "отдалечените клони не може да бъдат доÑтавени"
-msgid "import all tags and associated objects when fetching"
-msgstr "внаÑÑне на вÑички етикети и принадлежащите им обекти при доÑтавÑне"
-
-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“)"
msgid "branch(es) to track"
msgstr "клон/и за Ñледене"
@@ -11342,9 +11540,6 @@ msgstr "◠отдалечено хранилище „%s“"
msgid " Fetch URL: %s"
msgstr " ÐÐ´Ñ€ÐµÑ Ð·Ð° доÑтавÑне: %s"
-msgid "(no URL)"
-msgstr "(без адреÑ)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -11353,6 +11548,9 @@ msgstr "(без адреÑ)"
msgid " Push URL: %s"
msgstr " ÐÐ´Ñ€ÐµÑ Ð·Ð° изтлаÑкване: %s"
+msgid "(no URL)"
+msgstr "(без адреÑ)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " клон Ñочен от HEAD: %s"
@@ -11462,10 +11660,6 @@ msgstr "запитване към адреÑите за изтлаÑкване,
msgid "return all URLs"
msgstr "извеждане на вÑички адреÑи"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "не е зададен Ð°Ð´Ñ€ÐµÑ Ð·Ð° отдалеченото хранилище „%s“"
-
msgid "manipulate push URLs"
msgstr "промÑна на адреÑите за изтлаÑкване"
@@ -11508,6 +11702,10 @@ msgstr ""
"командата „pack-objects“ не може да Ñе Ñтартира за препакетирането на "
"гарантиращите обекти"
+msgid "failed to feed promisor objects to pack-objects"
+msgstr ""
+"гарантиращите обекти не може да Ñе подадат на командата „git pack-objects“"
+
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"repack: от „pack-objects“ Ñе изиÑкват редове Ñамо Ñ Ð¿ÑŠÐ»Ð½Ð¸ шеÑтнайÑетични "
@@ -11541,6 +11739,10 @@ msgstr "временниÑÑ‚ файл ÑÑŠÑ Ñнимка на указателÐ
msgid "could not remove stale bitmap: %s"
msgstr "изтриването на оÑтарÑлата битова маÑка „%s“ е невъзможно"
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "името на Ð¿Ð°ÐºÐµÑ‚Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» „%s“ не започва Ñ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñта за обекти Ñ â€ž%s“"
+
msgid "pack everything in a single pack"
msgstr "пакетиране на вÑичко в пакет"
@@ -11551,7 +11753,7 @@ msgstr ""
msgid "same as -a, pack unreachable cruft objects separately"
msgstr ""
-"Ñъщото като опциÑта „-a“. ÐедоÑтижимите излишни обекти да Ñе пакетират "
+"Ñъщото като опциÑта „-a“. ÐедоÑтижимите ненужни обекти да Ñе пакетират "
"отделно"
msgid "approxidate"
@@ -11626,19 +11828,22 @@ msgid "write a multi-pack index of the resulting packs"
msgstr "запазване на многопакетен Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° Ñъздадените пакети"
msgid "pack prefix to store a pack containing pruned objects"
-msgstr "Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ Ð½Ð° името на Ð¿Ð°ÐºÐµÑ‚Ð½Ð¸Ñ Ð·Ð° пакети за окаÑтрени обекти"
+msgstr "Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ Ð½Ð° имената на пакетите за окаÑтрени обекти"
+
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ Ð½Ð° имената на пакетите за филтрирани обекти"
msgid "cannot delete packs in a precious-objects repo"
msgstr "пакетите в хранилище Ñ Ð²Ð°Ð¶Ð½Ð¸ обекти не може да Ñе триÑÑ‚"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "опциÑта „%s“ изиÑква „%s“"
+
msgid "Nothing new to pack."
msgstr "Ðищо ново за пакетиране"
#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "името на Ð¿Ð°ÐºÐµÑ‚Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» „%s“ не започва Ñ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñта за обекти Ñ â€ž%s“"
-
-#, c-format
msgid "renaming pack to '%s' failed"
msgstr "неуÑпешно преименуване на Ð¿Ð°ÐºÐµÑ‚Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» на „%s“"
@@ -11838,9 +12043,79 @@ msgstr "опциÑта „--convert-graft-file“ не приема аргуме
msgid "only one pattern can be given with -l"
msgstr "опциÑта „-l“ приема точно един шаблон"
+msgid "need some commits to replay"
+msgstr "необходимо е да има Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð·Ð° прилагане отново"
+
+msgid "--onto and --advance are incompatible"
+msgstr "опциите „--onto“ и „--advance“ Ñа неÑъвмеÑтими"
+
+msgid "all positive revisions given must be references"
+msgstr "вÑички зададени положителни верÑии трÑбва да Ñа указатели"
+
+msgid "argument to --advance must be a reference"
+msgstr "аргументът към „--advance“ трÑбва да е указател"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"цели Ñ Ð¼Ð½Ð¾Ð¶ÐµÑтво източници не може да Ñе придвижат напред, защото подредбата "
+"не е добре дефинирана"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"не може да Ñе определи дали това дейÑтвие е за „--advance“ или „--onto“"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"цели Ñ Ð¼Ð½Ð¾Ð¶ÐµÑтво клони-източници не може да Ñе придвижат напред, защото "
+"подредбата не е добре дефинирана"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "правилната база за „--onto“ не може да Ñе определи"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(ЕКСПЕРИМЕÐТÐЛÐО!) git replay ([--contained] --onto ÐОВÐ_БÐЗР| --advance "
+"КЛОÐ) ДИÐПÐЗОÐ_ПОДÐÐ’ÐÐИЯ…"
+
+msgid "make replay advance given branch"
+msgstr "прилагането наново придвижва Ð´Ð°Ð´ÐµÐ½Ð¸Ñ ÐšÐ›ÐžÐ Ð½Ð°Ð¿Ñ€ÐµÐ´"
+
+msgid "replay onto given commit"
+msgstr "прилагането наново върху даденото ПОДÐÐ’ÐÐЕ"
+
+msgid "advance all branches contained in revision-range"
+msgstr "придвижване на вÑички КЛОÐи в ДИÐПÐЗОÐа_ПОДÐÐ’ÐÐИЯ"
+
+msgid "option --onto or --advance is mandatory"
+msgstr "изиÑква Ñе нÑÐºÐ¾Ñ Ð¾Ñ‚ опциите „--onto“ или „--advance“"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"нÑкои опции за проÑледÑване на указатели ще бъдат променени, защото битът "
+"„%s“ в Ñтруктурата „struct rev_info“ има превеÑ"
+
+msgid "error preparing revisions"
+msgstr "грешка при подготовката на верÑии"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "не Ñе поддържа прилагане наново и на началното подаване!"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "не Ñе поддържа прилагане наново и на Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ ÑÑŠÑ Ñливане!"
+
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
-msgstr "git rerere [clear | forget ПЪТ… | diff | status | remaining | gc]"
+msgstr "git rerere [clear|forget ПЪТ…|diff|status|remaining|gc]"
msgid "register clean resolutions in index"
msgstr "региÑтриране на чиÑти корекции на конфликти в индекÑа"
@@ -11854,8 +12129,7 @@ msgstr "неуÑпешно генериране на разлика за „%sâ€
msgid ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
-msgstr ""
-"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [ПОДÐÐ’ÐÐЕ]"
+msgstr "git reset [--mixed|--soft|--hard|--merge|--keep] [-q] [ПОДÐÐ’ÐÐЕ]"
msgid "git reset [-q] [<tree-ish>] [--] <pathspec>..."
msgstr "git reset [-q] [УКÐЗÐТЕЛ_КЪМ_ДЪРВО] [--] ПЪТИЩÐ…"
@@ -12042,22 +12316,23 @@ msgstr "опциÑта „--default“ изиÑква аргумент"
msgid "--prefix requires an argument"
msgstr "опциÑта „--prefix“ изиÑква аргумент"
+msgid "no object format specified"
+msgstr "не е указан формат на обект"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "неподдържан формат на обект: „%s“"
+
#, 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 "тази команда трÑбва да Ñе изпълни в работно дърво"
+msgid "Could not read the index"
+msgstr "ИндекÑÑŠÑ‚ не може да бъде прочетен"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "непознат режим за „--show-object-format“: „%s“"
@@ -12070,7 +12345,7 @@ msgstr ""
" [-S[ИДЕÐТИФИКÐТОР_ÐÐ_КЛЮЧ]] ПОДÐÐ’ÐÐЕ…"
msgid "git revert (--continue | --skip | --abort | --quit)"
-msgstr "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"
@@ -12080,7 +12355,7 @@ msgstr ""
" [-S[ИДЕÐТИФИКÐТОР_ÐÐ_КЛЮЧ]] ПОДÐÐ’ÐÐЕ…"
msgid "git cherry-pick (--continue | --skip | --abort | --quit)"
-msgstr "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"
@@ -12129,8 +12404,8 @@ msgstr "запазване на първоначално празните под
msgid "allow commits with empty messages"
msgstr "позволÑване на празни ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ подаване"
-msgid "keep redundant, empty commits"
-msgstr "запазване на излишните, празни подаваниÑ"
+msgid "deprecated: use --empty=keep instead"
+msgstr "ОСТÐРЯЛО: вмеÑто това ползвайте „--empty=keep“"
msgid "use the 'reference' format to refer to commits"
msgstr "указване на Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð²ÑŠÐ² формат за указател"
@@ -12146,7 +12421,7 @@ msgid ""
" [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]"
msgstr ""
-"git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
+"git rm [-f|--force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
" [--quiet] [--pathspec-from-file=ФÐЙЛ [--pathspec-file-nul]]\n"
" [--] [ПЪТ…]"
@@ -12233,8 +12508,8 @@ msgstr ""
"git send-pack [--mirror] [--dry-run] [--force]\n"
" [--receive-pack=ПÐКЕТ]\n"
" [--verbose] [--thin] [--atomic]\n"
-" [--[no-]signed | --signed=(true|false|if-asked)]\n"
-" [ХОСТ:]ДИРЕКТОРИЯ (--all | УКÐЗÐТЕЛ…)"
+" [--[no-]signed|--signed=(true|false|if-asked)]\n"
+" [ХОСТ:]ДИРЕКТОРИЯ (--all|УКÐЗÐТЕЛ…)"
msgid "remote name"
msgstr "име на отдалечено хранилище"
@@ -12302,14 +12577,14 @@ msgid ""
" [--no-name | --sha1-name] [--topics]\n"
" [(<rev> | <glob>)...]"
msgstr ""
-"git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
-" [--current] [--color[=КОГÐ] | --no-color] [--sparse]\n"
-" [--more=<n> | --list | --independent | --merge-base]\n"
-" [--no-name | --sha1-name] [--topics]\n"
-" [(РЕВИЗИЯ | УКÐЗÐТЕЛ)…]"
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order|--date-order]\n"
+" [--current] [--color[=КОГÐ]|--no-color] [--sparse]\n"
+" [--more=<n>|--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] [УКÐЗÐТЕЛ]"
+msgstr "git show-branch (-g|--reflog)[=БРОЙ[,БÐЗÐ]] [--list] [УКÐЗÐТЕЛ]"
#, c-format
msgid "ignoring %s; cannot handle more than %d ref"
@@ -12408,25 +12683,46 @@ 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>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d|--dereference]\n"
+" [-s|--hash[=БРОЙ]] [--abbrev[=БРОЙ]] [--branches] [--tags]\n"
+" [--] [ШÐБЛОÐ…]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=БРОЙ]] [--abbrev[=БРОЙ]] [--tags]\n"
-" [--heads] [--] [ШÐБЛОÐ…]"
+"git show-ref --verify [-q|--quiet] [-d|--dereference]\n"
+" [-s|--hash[=БРОЙ]] [--abbrev[=БРОЙ]]\n"
+" [--] [ШÐБЛОÐ…]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=ШÐБЛОÐ]"
-msgid "only show tags (can be combined with heads)"
-msgstr "извеждане на етикетите (може да Ñе комбинира Ñ Ð²ÑŠÑ€Ñ…Ð¾Ð²ÐµÑ‚Ðµ)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists УКÐЗÐТЕЛ"
+
+msgid "reference does not exist"
+msgstr "указателÑÑ‚ не ÑъщеÑтвува"
+
+msgid "failed to look up reference"
+msgstr "Ñоченото от ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð»Ð¸Ð¿Ñва"
-msgid "only show heads (can be combined with tags)"
-msgstr "извеждане на върховете (може да Ñе комбинира Ñ ÐµÑ‚Ð¸ÐºÐµÑ‚Ð¸Ñ‚Ðµ)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "извеждане на етикетите (може да Ñе комбинира Ñ â€ž--branches“ за клони)"
+
+msgid "only show branches (can be combined with --tags)"
+msgstr "извеждане на клоните (може да Ñе комбинира Ñ â€ž--tags“ за етикети)"
+
+msgid "check for reference existence without resolving"
+msgstr "проверка за ÑъщеÑтвуване на указател без проÑледÑването му"
msgid "stricter reference checking, requires exact ref path"
-msgstr "Ñтрога проверка на указателите, изиÑква Ñе указател Ñ Ð¿ÑŠÐ»ÐµÐ½ път"
+msgstr "по-Ñтрога проверка за указатели, изиÑква точен път на указател"
msgid "show the HEAD reference, even if it would be filtered out"
msgstr "задължително извеждане и на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ HEAD"
@@ -12451,8 +12747,7 @@ 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) ОПЦИЯ…"
+"git sparse-checkout (init|list|set|add|reapply|disable|check-rules) ОПЦИЯ…"
msgid "this worktree is not sparse"
msgstr "това работно дърво не е чаÑтично"
@@ -12476,6 +12771,10 @@ msgstr "директориÑта „%s“ не може да бъде изтри
msgid "failed to create directory for sparse-checkout file"
msgstr "директориÑта за чаÑтично изтеглÑне „%s“ не може да бъде Ñъздадена"
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "обектът „%s“ не може да бъде отворен Ñ â€žfdopen“"
+
msgid "failed to initialize worktree config"
msgstr "наÑтройките на работното дърво не може да Ñе инициализират"
@@ -12549,7 +12848,7 @@ msgstr ""
"ръководÑтвото на командата „git-sparse-checkout“)."
msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
-msgstr "git sparse-checkout add [--skip-checks] (--stdin | ШÐБЛОÐ…)"
+msgstr "git sparse-checkout add [--skip-checks] (--stdin|ШÐБЛОÐ…)"
msgid ""
"skip some sanity checks on the given paths that might give false positives"
@@ -12568,7 +12867,7 @@ msgid ""
"(--stdin | <patterns>)"
msgstr ""
"git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
-"(--stdin | ШÐБЛОÐ…)"
+"(--stdin|ШÐБЛОÐ…)"
msgid "must be in a sparse-checkout to reapply sparsity patterns"
msgstr ""
@@ -12603,23 +12902,23 @@ msgid ""
"git stash show [-u | --include-untracked | --only-untracked] [<diff-"
"options>] [<stash>]"
msgstr ""
-"git stash show [-u | --include-untracked | --only-untracked] "
-"[ОПЦИЯ_ЗÐ_РÐЗЛИКÐ…] [СКÐТÐÐО]"
+"git stash show [-u|--include-untracked|--only-untracked] [ОПЦИЯ_ЗÐ_РÐЗЛИКÐ…] "
+"[СКÐТÐÐО]"
msgid "git stash drop [-q | --quiet] [<stash>]"
-msgstr "git stash drop [-q | --quiet] [СКÐТÐÐО]"
+msgstr "git stash drop [-q|--quiet] [СКÐТÐÐО]"
msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
-msgstr "git stash pop [--index] [-q | --quiet] [СКÐТÐÐО]"
+msgstr "git stash pop [--index] [-q|--quiet] [СКÐТÐÐО]"
msgid "git stash apply [--index] [-q | --quiet] [<stash>]"
-msgstr "git stash apply [--index] [-q | --quiet] [СКÐТÐÐО]"
+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] ПОДÐÐ’ÐÐЕ"
+msgstr "git stash store [-m|--message СЪОБЩЕÐИЕ] [-q|--quiet] ПОДÐÐ’ÐÐЕ"
msgid ""
"git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
@@ -12629,10 +12928,9 @@ msgid ""
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]]"
msgstr ""
-"git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
-"| --quiet]\n"
-" [-u | --include-untracked] [-a | --all] [(-m | --message) "
-"СЪОБЩЕÐИЕ]\n"
+"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"
" [--] [ПЪТ…]]"
@@ -12641,9 +12939,9 @@ msgid ""
"--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] [СЪОБЩЕÐИЕ]"
+"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 [СЪОБЩЕÐИЕ]"
@@ -12935,8 +13233,8 @@ msgid "couldn't hash object from '%s'"
msgstr "неуÑпешно изчиÑлÑване на контролната Ñума на обект от „%s“"
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "неочакван режим „%o“\n"
+msgid "unexpected mode %o"
+msgstr "неочакван режим „%o“"
msgid "use the commit stored in the index instead of the submodule HEAD"
msgstr ""
@@ -13022,7 +13320,7 @@ msgstr "премахване на региÑтрациите на вÑички Ð
msgid ""
"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"
-msgstr "git submodule deinit [--quiet] [-f | --force] [--all | [--] [ПЪТ…]]"
+msgstr "git submodule deinit [--quiet] [-f|--force] [--all|[--] [ПЪТ…]]"
msgid "Use '--all' if you really want to deinitialize all submodules"
msgstr "Използвайте „--all“, за да премахнете вÑички подмодули"
@@ -13062,14 +13360,14 @@ msgstr ""
"друг подмодул"
#, 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 "clone of '%s' into submodule path '%s' failed"
+msgstr "ÐеуÑпешно клониране на адреÑа „%s“ в Ð¿ÑŠÑ‚Ñ â€ž%s“ като подмодул"
+
+#, c-format
msgid "could not get submodule directory for '%s'"
msgstr "директориÑта на подмодула „%s“ не може да бъде получена"
@@ -13124,6 +13422,10 @@ msgid "Skipping submodule '%s'"
msgstr "ПреÑкачане на подмодула „%s“"
#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "не може да Ñе клонира подмодул „%s“ без адреÑ"
+
+#, c-format
msgid "Failed to clone '%s'. Retry scheduled"
msgstr "ÐеуÑпешен опит за клониране на „%s“. ÐаÑрочен е втори опит"
@@ -13257,6 +13559,9 @@ msgstr ""
"shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
"[--] [ПЪТ…]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Ðе може да Ñе открие към какво Ñочи указателÑÑ‚ „HEAD“"
+
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [ОПЦИЯ…] [ПЪТ…]"
@@ -13427,11 +13732,12 @@ msgstr "причина за обновÑването"
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
-"git tag [-a | -s | -u ИДЕÐТИФИКÐТОР_ÐÐ_КЛЮЧ] [-f] [-m СЪОБЩЕÐИЕ | -F ФÐЙЛ] [-"
-"e]\n"
-" ЕТИКЕТ [ПОДÐÐ’ÐÐЕ | ОБЕКТ]"
+"git tag [-a|-s|-u ИДЕÐТИФИКÐТОР_ÐÐ_КЛЮЧ] [-f] [-m СЪОБЩЕÐИЕ|-F ФÐЙЛ] [-e]\n"
+" [(--trailer ЛЕКСЕМÐ[(=|:)СТОЙÐОСТ])…]\n"
+" ЕТИКЕТ [ПОДÐÐ’ÐÐЕ|ОБЕКТ]"
msgid "git tag -d <tagname>..."
msgstr "git tag -d ЕТИКЕТ…"
@@ -13443,7 +13749,7 @@ msgid ""
" [--merged <commit>] [--no-merged <commit>] [<pattern>...]"
msgstr ""
"git tag [-n[БРОЙ]] -l [--contains ПОДÐÐ’ÐÐЕ] [--no-contains ПОДÐÐ’ÐÐЕ]\n"
-" [--points-at ОБЕКТ] [--column[=ОПЦИЯ…] | --no-column]\n"
+" [--points-at ОБЕКТ] [--column[=ОПЦИЯ…]|--no-column]\n"
" [--create-reflog] [--sort=<key>] [--format=ФОРМÐТ]\n"
" [--merged ПОДÐÐ’ÐÐЕ] [--no-merged ПОДÐÐ’ÐÐЕ] [ШÐБЛОÐ…]"
@@ -13463,25 +13769,25 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Въведете Ñъобщение за етикета.\n"
" %s\n"
-"Редовете, които започват Ñ â€ž%c“, ще бъдат пропуÑнати.\n"
+"Редовете, които започват Ñ â€ž%s“, ще бъдат пропуÑнати.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Въведете Ñъобщение за етикет.\n"
" %s\n"
-"Редовете, които започват Ñ â€ž%c“, Ñъщо ще бъдат включени — може да ги "
+"Редовете, които започват Ñ â€ž%s“, Ñъщо ще бъдат включени — може да ги "
"изтриете вие.\n"
msgid "unable to sign the tag"
@@ -13567,6 +13873,9 @@ msgstr "извеждане Ñамо на неÑлетите етикети"
msgid "print only tags of the object"
msgstr "извеждане Ñамо на етикетите на ОБЕКТÐ"
+msgid "could not start 'git column'"
+msgstr "неуÑпешно изпълнение на „git column“"
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "опциÑта „%s“ изиÑква режим на ÑпиÑък"
@@ -13744,6 +14053,9 @@ msgstr ""
msgid "write index in this format"
msgstr "запиÑване на индекÑа в този формат"
+msgid "report on-disk index format version"
+msgstr "извеждане на верÑиÑта на форма̀та на индекÑа на диÑка"
+
msgid "enable or disable split index"
msgstr "включване или изключване на разделÑнето на индекÑа"
@@ -13769,6 +14081,14 @@ msgstr "отбелÑзване на файловете, че може да Ñе
msgid "clear fsmonitor valid bit"
msgstr "изчиÑтване на флага за Ñледенето чрез файловата ÑиÑтема"
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "верÑÐ¸Ñ Ð½Ð° индекÑ: бе %d, променена на %d"
+
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -13821,11 +14141,14 @@ msgstr ""
msgid "fsmonitor disabled"
msgstr "Ñледенето чрез файловата ÑиÑтема е изключено"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [ОПЦИЯ…] -d ИМЕ_ÐÐ_УКÐЗÐТЕЛ [СТÐРÐ_СТОЙÐОСТ]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr ""
+"git update-ref [ОПЦИЯ…] -d ИМЕ_ÐÐ_УКÐЗÐТЕЛ [СТÐР_ИДЕÐТИФИКÐТОР_ÐÐ_ОБЕКТ]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr "git update-ref [ОПЦИЯ…] ИМЕ_ÐÐ_УКÐЗÐТЕЛ ÐОВÐ_СТОЙÐОСТ [СТÐРÐ_СТОЙÐОСТ]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr ""
+"git update-ref [ОПЦИЯ…] ИМЕ_ÐÐ_УКÐЗÐТЕЛ ÐОВ_ИДЕÐТИФИКÐТОР_ÐÐ_ОБЕКТ "
+"[СТÐР_ИДЕÐТИФИКÐТОР_ÐÐ_ОБЕКТ]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [ОПЦИЯ…] --stdin [-z]"
@@ -13868,7 +14191,7 @@ msgid "interrupt transfer after <n> seconds of inactivity"
msgstr "транÑферът да Ñе преуÑтанови Ñлед този БРОЙ Ñекунди"
msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
-msgstr "git verify-commit [-v | --verbose] [--raw] ПОДÐÐ’ÐÐЕ…"
+msgstr "git verify-commit [-v|--verbose] [--raw] ПОДÐÐ’ÐÐЕ…"
msgid "print commit contents"
msgstr "извеждане на Ñъдържанието на подаването"
@@ -13877,7 +14200,7 @@ 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…"
+msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] [--] ПÐКЕТ.idx…"
msgid "verbose"
msgstr "извеждане на подробна информациÑ"
@@ -13886,20 +14209,20 @@ msgid "show statistics only"
msgstr "извеждане Ñамо на ÑтатиÑтиката"
msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
-msgstr "git verify-tag [-v | --verbose] [--format=ФОРМÐТ] [--raw] ЕТИКЕТ…"
+msgstr "git verify-tag [-v|--verbose] [--format=ФОРМÐТ] [--raw] ЕТИКЕТ…"
msgid "print tag contents"
msgstr "извеждане на Ñъдържанието на ЕТИКЕТи"
msgid ""
"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-" [-b <new-branch>] <path> [<commit-ish>]"
+" [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
msgstr ""
"git worktree add [-f] [--detach] [--checkout] [--lock [--reason ÐИЗ]]\n"
-" [-b ÐОВ_КЛОÐ] ПЪТ [УКÐЗÐТЕЛ_КЪМ_ПОДÐÐ’ÐÐЕ]"
+" [--orphan] [(-b|-B) ÐОВ_КЛОÐ] ПЪТ [УКÐЗÐТЕЛ_КЪМ_ПОДÐÐ’ÐÐЕ]"
msgid "git worktree list [-v | --porcelain [-z]]"
-msgstr "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 ПРИЧИÐÐ] ФОРМÐТ"
@@ -13919,6 +14242,37 @@ 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 unborn 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 unborn 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"
@@ -13977,6 +14331,10 @@ msgid "initializing"
msgstr "инициализациÑ"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "Ñъздаденото в „%s“ работно дърво липÑва"
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "ПриготвÑне на работното дърво (нов клон „%s“)"
@@ -13991,9 +14349,33 @@ 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 path: „%s“\n"
+"HEAD contents: „%s“"
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to override or fetch a remote first"
+msgstr ""
+"Ðе ÑъщеÑтвуват никакви локални или отдалечени указатели, въпреки че има\n"
+"поне едно Ñледено хранилище. Работата Ñпира.\n"
+"Ползвайте комбинациÑта „add -f“ за принудително дейÑтвие или първо "
+"доÑтавете\n"
+"обектите от отдалеченото хранилище"
+
msgid "checkout <branch> even if already checked out in other worktree"
msgstr "ИзтеглÑне КЛОÐа, дори и да е изтеглен в друго работно дърво"
@@ -14003,6 +14385,9 @@ msgstr "Ñъздаване на нов клон"
msgid "create or reset a branch"
msgstr "Ñъздаване или занулÑване на клони"
+msgid "create unborn branch"
+msgstr "Ñъздаване на неродѐн клон"
+
msgid "populate the new working tree"
msgstr "подготвÑне на новото работно дърво"
@@ -14022,6 +14407,10 @@ msgstr "опит за напаÑване на името на Ð½Ð¾Ð²Ð¸Ñ ÐºÐ»Ð¾Ð
msgid "options '%s', '%s', and '%s' cannot be used together"
msgstr "опциите „%s“, „%s“ и „%s“ Ñа неÑъвмеÑтими"
+#, c-format
+msgid "option '%s' and commit-ish cannot be used together"
+msgstr "опциите „%s“ и указателите към Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ñа неÑъвмеÑтими"
+
msgid "added with --lock"
msgstr "добавена Ñ â€ž--lock“"
@@ -14233,9 +14622,6 @@ 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"
@@ -14258,6 +14644,14 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
msgstr[0] "Пратката изиÑква ÑÐ»ÐµÐ´Ð½Ð¸Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»:"
msgstr[1] "Пратката изиÑква Ñледните %<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 "неуÑпешно дублиране на деÑкриптора на пратката Ñ â€ždup“"
@@ -14294,6 +14688,10 @@ msgid "terminating chunk id appears earlier than expected"
msgstr "идентификаторът за краен Ð¾Ñ‚ÐºÑŠÑ Ñе ÑвÑва по-рано от очакваното"
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "откъÑÑŠÑ‚ Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ‚Ð¾Ñ€ %<PRIx32> не е подравнен по %d-байта"
+
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "неправилно отмеÑтване на откъÑ/и %<PRIx64> и %<PRIx64>"
@@ -14347,9 +14745,9 @@ msgstr "Събиране на Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ñ Ð
msgid "Move objects and refs by archive"
msgstr "МеÑтене на обекти и указатели по архиви"
-msgid "Provide content or type and size information for repository objects"
+msgid "Provide contents or details of repository objects"
msgstr ""
-"ПредоÑтавÑне на Ñъдържанието или вида и размерите на обекти от хранилище"
+"ПредоÑтавÑне на Ñъдържанието или друга Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð° обекти от хранилище"
msgid "Display gitattributes information"
msgstr "Извеждане на информациÑта за атрибутите на git (gitattributes)"
@@ -14430,9 +14828,7 @@ msgid "A really simple server for Git repositories"
msgstr "Силно опроÑтен Ñървър за хранилища на Git"
msgid "Give an object a human readable name based on an available ref"
-msgstr ""
-"Задаване на име удобно за потребителите на обект въз оÑнова на наличен "
-"указател"
+msgstr "Задаване на четимо от хора име на обект въз оÑнова на наличен указател"
msgid "Generate a zip archive of diagnostic information"
msgstr "Създаване на архив във формат zip Ñ Ð´Ð¸Ð°Ð³Ð½Ð¾Ñтична информациÑ"
@@ -14496,10 +14892,9 @@ msgstr "Извеждане на редовете напаÑващи на шабÐ
msgid "A portable graphical interface to Git"
msgstr "Графичен Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÑŠÐ¼ 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 ""
-"ИзчиÑлÑване на идентификатор на обект и евентуално Ñъздаване на обект-BLOB "
-"от файл"
+"ИзчиÑлÑване на идентификатор на обект и евентуално Ñъздаване на обект от файл"
msgid "Display help information about Git"
msgstr "Извеждане на помощта за Git"
@@ -14637,6 +15032,9 @@ msgstr "Получаване на изтлаÑканото в хранилище
msgid "Manage reflog information"
msgstr "Управление на информациÑта в журнала на указателите"
+msgid "Low-level access to refs"
+msgstr "ДоÑтъп от ниÑко ниво до указателите"
+
msgid "Manage set of tracked repositories"
msgstr "Управление на набор от Ñледени хранилища"
@@ -14646,6 +15044,11 @@ msgstr "Пакетиране на непакетираните обекти в Ñ
msgid "Create, list, delete refs to replace objects"
msgstr "Създаване, извеждане, изтриване на указатели за замÑна на обекти"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"ЕКСПЕРИМЕÐТÐЛÐО: прилагане на Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð²ÑŠÑ€Ñ…Ñƒ нова база, работи и Ñ Ð³Ð¾Ð»Ð¸ "
+"хранилища"
+
msgid "Generates a summary of pending changes"
msgstr "Обобщение на предÑтоÑщите промѐни"
@@ -14767,7 +15170,7 @@ msgstr "Проверка на подпиÑите GPG върху етикетит
msgid "Display version information about Git"
msgstr "Извеждане на верÑиÑта на Git"
-msgid "Show logs with difference each commit introduces"
+msgid "Show logs with differences each commit introduces"
msgstr "Извеждане на журнал Ñ Ñ€Ð°Ð·Ð»Ð¸ÐºÐ¸Ñ‚Ðµ, въведени Ñ Ð²ÑÑко подаване"
msgid "Manage multiple working trees"
@@ -14884,6 +15287,36 @@ msgstr "ИнÑтрумент за управление на големи храÐ
msgid "commit-graph file is too small"
msgstr "файлът за гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е твърде малък"
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "откъÑÑŠÑ‚ за разпределÑнето в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е прекалено малък"
+
+msgid "commit-graph fanout values out of order"
+msgstr ""
+"ÑтойноÑтите за Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° разпределÑне в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта не Ñа подредени"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "откъÑÑŠÑ‚ за търÑенето в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е прекалено малък"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr ""
+"откъÑÑŠÑ‚ за данните за подаваниÑта в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÐµÐ½ размер"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "откъÑÑŠÑ‚ за поколениÑта в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÐµÐ½ размер"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr ""
+"откъÑÑŠÑ‚ за индекÑа Ñ Ð¿Ñ€Ð¾Ð¼ÐµÌ€Ð½Ð¸ в пътищата в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е прекалено "
+"малък"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"преÑкачане на прекалено малък Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° индекÑа Ñ Ð¿Ñ€Ð¾Ð¼ÐµÌ€Ð½Ð¸ (%<PRIuMAX> < "
+"%<PRIuMAX>) в пътищата в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта"
+
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "отпечатъкът на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта %X не Ñъвпада Ñ %X"
@@ -14900,13 +15333,44 @@ msgstr "верÑиÑта на контролната Ñума на гра̀фа
msgid "commit-graph file is too small to hold %u chunks"
msgstr "файлът Ñ Ð³Ñ€Ð°Ì€Ñ„Ð° на подаваниÑта е твърде малък, за да Ñъдържа %u откъÑи"
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr ""
+"откъÑÑŠÑ‚ за разпределÑнето необходимо на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта липÑва или е "
+"повреден"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr ""
+"откъÑÑŠÑ‚ за търÑенето необходимо на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта липÑва или е повреден"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr ""
+"откъÑÑŠÑ‚ за данните необходими на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта липÑва или е повреден"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"изключване на филтрите на Блум за Ñлой „%s“ на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта поради "
+"неÑъвмеÑтими наÑтройки"
+
msgid "commit-graph has no base graphs chunk"
msgstr "базовиÑÑ‚ Ð¾Ñ‚ÐºÑŠÑ Ð»Ð¸Ð¿Ñва в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта"
+msgid "commit-graph base graphs chunk is too small"
+msgstr "базовиÑÑ‚ Ð¾Ñ‚ÐºÑŠÑ Ð² гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е прекалено малък"
+
msgid "commit-graph chain does not match"
msgstr "веригата на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта не Ñъвпада"
#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "броÑÑ‚ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð² оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð³Ñ€Ð°Ñ„ е прекалено голÑм: %<PRIuMAX>"
+
+msgid "commit-graph chain file too small"
+msgstr "веригата на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е твърде малка"
+
+#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr ""
"грешка във веригата на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта: ред „%s“ не е контролна Ñума"
@@ -14924,8 +15388,15 @@ msgstr "подаването „%s“ не може да бъде открито
msgid "commit-graph requires overflow generation data but has none"
msgstr ""
-"графът Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта изиÑква генериране на данни за отмеÑтването, но такива "
-"липÑват"
+"графът Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта изиÑква данни за прелелите поколениÑ, но такива липÑват"
+
+msgid "commit-graph overflow generation data is too small"
+msgstr "прекалено малко данни за прелелите Ð¿Ð¾ÐºÐ¾Ð»ÐµÐ½Ð¸Ñ Ð² гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr ""
+"указателÑÑ‚ за допълнителните ребра в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е извън Ð¿Ð¾Ð·Ð²Ð¾Ð»ÐµÐ½Ð¸Ñ "
+"диапазон"
msgid "Loading known commits in commit graph"
msgstr "Зареждане на познатите Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð² гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта"
@@ -14969,7 +15440,8 @@ msgid "Finding extra edges in commit graph"
msgstr "Откриване на още върхове в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта"
msgid "failed to write correct number of base graph ids"
-msgstr "правилниÑÑ‚ брой на базовите идентификатори не може да Ñе запише"
+msgstr ""
+"правилниÑÑ‚ брой на идентификаторите в оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð³Ñ€Ð°Ñ„ не може да Ñе запише"
msgid "unable to create temporary graph layer"
msgstr "не може да бъде Ñъздаден временен Ñлой за гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта"
@@ -14993,6 +15465,15 @@ 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 "ТърÑене на подаваниÑта ÑÑŠÑ ÑливаниÑ"
@@ -15004,6 +15485,14 @@ msgstr ""
"опит за Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта, но наÑтройката „core.commitGraph“ е "
"изключена"
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"опит за Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта, но наÑтройката „commitGraph."
+"changedPathsVersion“ (%d) не Ñе поддържа"
+
msgid "too many commits to write graph"
msgstr "прекалено много Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð·Ð° запиÑване на гра̀фа"
@@ -15019,16 +15508,13 @@ msgstr ""
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
msgstr ""
-"неправилна ÑтойноÑÑ‚ за Ð¾Ñ‚ÐºÑŠÑ Ð² гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта: fanout[%d] = %u, а "
-"трÑбва да е %u"
+"неправилна ÑтойноÑÑ‚ за Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° разпределÑне в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта: "
+"fanout[%d] = %u, а трÑбва да е %u"
#, c-format
msgid "failed to parse commit %s from commit-graph"
msgstr "подаване „%s“ в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта не може да Ñе анализира"
-msgid "Verifying commits in commit graph"
-msgstr "Проверка на подаваниÑта в гра̀фа"
-
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
msgstr ""
@@ -15054,20 +15540,6 @@ 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“ в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е 0, а другаде "
-"не е"
-
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"номерът на поколението на подаване „%s“ в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта не е 0, а "
-"другаде е"
-
-#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr ""
"номерът на поколението на подаване „%s“ в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта е %<PRIuMAX> < "
@@ -15080,6 +15552,21 @@ msgstr ""
"%<PRIuMAX>"
#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта Ñъдържа както нулеви, така и ненулеви Ð¿Ð¾ÐºÐ¾Ð»ÐµÐ½Ð¸Ñ (напр. "
+"подаваниÑта „%s“ и „%s“)"
+
+msgid "Verifying commits in commit graph"
+msgstr "Проверка на подаваниÑта в гра̀фа"
+
+#, c-format
+msgid "could not parse commit %s"
+msgstr "подаването „%s“ не може да бъде анализирано"
+
+#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s не е подаване!"
@@ -15106,6 +15593,12 @@ msgstr ""
" git config advice.graftFileDeprecated false"
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"подаването „%s“ приÑÑŠÑтва в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта, но липÑва в базата от данни "
+"за обектите"
+
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr ""
"Подаването „%s“ е Ñ Ð½ÐµÐ´Ð¾Ð²ÐµÑ€ÐµÐ½ Ð¿Ð¾Ð´Ð¿Ð¸Ñ Ð¾Ñ‚ GPG, който твърди, че е на „%s“."
@@ -15525,8 +16018,13 @@ msgstr "дължината на Ñъкращаване е извън диапаÐ
msgid "bad zlib compression level %d"
msgstr "неправилно ниво на компреÑиране: %d"
-msgid "core.commentChar should only be one ASCII character"
-msgstr "наÑтройката „core.commentChar“ трÑбва да е Ñамо един знак от ASCII"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s не може да Ñъдържа нови редове"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s трÑбва да Ñъдържа поне един знак"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15551,9 +16049,9 @@ msgstr "неправилна ÑтойноÑÑ‚ за „%s“: „%s“"
msgid "must be one of nothing, matching, simple, upstream or current"
msgstr ""
"трÑбва да е една от Ñледните ÑтойноÑти: „nothing“ (без изтлаÑкване при липÑа "
-"на указател), „matching“ (вÑички клони ÑÑŠÑ Ñъвпадащи имена), "
-"„simple“ (клонът ÑÑŠÑ Ñъщото име, от който Ñе издърпва), „upstream“ (клонът, "
-"от който Ñе издърпва) или „current“ (клонът ÑÑŠÑ Ñъщото име)"
+"на указател), „matching“ (вÑички клони ÑÑŠÑ Ñъвпадащи имена), „simple“ "
+"(клонът ÑÑŠÑ Ñъщото име, от който Ñе издърпва), „upstream“ (клонът, от който "
+"Ñе издърпва) или „current“ (клонът ÑÑŠÑ Ñъщото име)"
#, c-format
msgid "unable to load config blob object '%s'"
@@ -15567,10 +16065,6 @@ msgstr "указателÑÑ‚ „%s“ не Ñочи към обект-BLOB"
msgid "unable to resolve config blob '%s'"
msgstr "обектът-BLOB „%s“ Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¸ не може да бъде открит"
-#, c-format
-msgid "failed to parse %s"
-msgstr "„%s“ не може да бъде анализиран"
-
msgid "unable to parse command-line config"
msgstr "неправилни наÑтройки от ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¸Ñ Ñ€ÐµÐ´"
@@ -15608,6 +16102,10 @@ msgid "failed to write new configuration file %s"
msgstr "новиÑÑ‚ конфигурационен файл „%s“ не може да бъде запазен"
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "коментари на повече от един ред не Ñа позволени: „%s“"
+
+#, c-format
msgid "could not lock config file %s"
msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде заключен"
@@ -16055,9 +16553,6 @@ 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“ не може да бъде получен"
@@ -16067,6 +16562,12 @@ msgstr "липÑва база за Ñливане"
msgid "multiple merge bases found"
msgstr "много бази за Ñливане"
+msgid "cannot compare stdin to a directory"
+msgstr "ÑтандартниÑÑ‚ вход не може да Ñе Ñравни Ñ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "именован канал не може да Ñе Ñравни Ñ Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ"
+
msgid "git diff --no-index [<options>] <path> <path>"
msgstr "git diff --no-index [ОПЦИЯ…] ПЪТ ПЪТ"
@@ -16092,8 +16593,8 @@ msgid ""
"'dimmed-zebra', 'plain'"
msgstr ""
"наÑтройката за цвÑÑ‚ за премеÑтване трÑбва да е една от: „no“ (без), "
-"„default“ (Ñтандартно), „blocks“ (парчета), „zebra“ (райе), „dimmed-"
-"zebra“ (тъмно райе), „plain“ (обикновено)"
+"„default“ (Ñтандартно), „blocks“ (парчета), „zebra“ (райе), „dimmed-zebra“ "
+"(тъмно райе), „plain“ (обикновено)"
#, c-format
msgid ""
@@ -16119,6 +16620,10 @@ msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "Ðепозната ÑтойноÑÑ‚ „%s“ за наÑтройката „diff.submodule“"
#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "непозната ÑтойноÑÑ‚ за наÑтройката „%s“: „%s“"
+
+#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
@@ -16131,6 +16636,13 @@ msgid "external diff died, stopping at %s"
msgstr ""
"външната програма за разлики завърши неуÑпешно. Спиране на работата при „%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“ Ñа неÑъвмеÑтими"
@@ -16144,9 +16656,6 @@ msgid ""
"options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
msgstr "опциите „%s“ и „%s“ Ñа неÑъвмеÑтими, използвайте „%s“ Ñ â€ž%s“ и „%s“"
-msgid "--follow requires exactly one pathspec"
-msgstr "опциÑта „--follow“ изиÑква точно един път"
-
#, c-format
msgid "invalid --stat value: %s"
msgstr "неправилна ÑтойноÑÑ‚ за „--stat“: %s"
@@ -16193,14 +16702,6 @@ msgstr "неправилен аргумент за „--color-moved“: „%s“
msgid "invalid mode '%s' in --color-moved-ws"
msgstr "неправилен режим „%s“ за „ --color-moved-ws“"
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"опциÑта приема Ñледните варианти за алгоритъм за разлики: „myers“ (по "
-"МайерÑ), „minimal“ (минимизиране на разликите), „patience“ (паÑианÑ) и "
-"„histogram“ (хиÑтограмен)"
-
#, c-format
msgid "invalid argument to %s"
msgstr "неправилен аргумент към „%s“"
@@ -16244,8 +16745,8 @@ msgstr "„--stat“ във формат за четене от програма
msgid "output only the last line of --stat"
msgstr "извеждане Ñамо на поÑÐ»ÐµÐ´Ð½Ð¸Ñ Ñ€ÐµÐ´ на „--stat“"
-msgid "<param1,param2>..."
-msgstr "ПÐРÐМЕТЪР_1, ПÐРÐМЕТЪР_2, …"
+msgid "<param1>,<param2>..."
+msgstr "ПÐРÐМЕТЪР_1,ПÐРÐМЕТЪР_2,…"
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
@@ -16254,8 +16755,8 @@ msgstr "извеждане на разпределението на промѐ
msgid "synonym for --dirstat=cumulative"
msgstr "пÑевдоним на „--dirstat=cumulative“"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "пÑевдоним на „--dirstat=ФÐЙЛ…,ПÐРÐМЕТЪР_1,ПÐРÐМЕТЪР_2,…“"
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "пÑевдоним на „--dirstat=files,ПÐРÐМЕТЪР_1,ПÐРÐМЕТЪР_2,…“"
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
@@ -16439,12 +16940,6 @@ msgstr "разлика чрез алгоритъм за подредба катÐ
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "разлика по хиÑÑ‚Ð¾Ð³Ñ€Ð°Ð¼Ð½Ð¸Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚ÑŠÐ¼"
-msgid "<algorithm>"
-msgstr "ÐЛГОРИТЪМ"
-
-msgid "choose a diff algorithm"
-msgstr "избор на ÐЛГОРИТЪМа за разлики"
-
msgid "<text>"
msgstr "ТЕКСТ"
@@ -16913,23 +17408,21 @@ msgstr ""
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 <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>]\n"
-"git [-v | --version] [-h | --help] [-C ПЪТ] [-c ИМЕ=СТОЙÐОСТ]\n"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <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=ИМЕ=ПРОМЕÐЛИВÐ_ÐÐ_СРЕДÐТÐ] КОМÐÐДР[ÐРГ…]"
+" [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--no-lazy-"
+"fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=ПЪТ]\n"
+" [--work-tree=ПЪТ] [--namespace=ИМЕ] [--config-"
+"env=ИМЕ=ПРОМЕÐЛИВÐ_ÐÐ_СРЕДÐТÐ]\n"
+" КОМÐÐДР[ÐРГ…]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -17283,13 +17776,13 @@ msgstr ""
"За да изключите това предупреждение, изпълнете:\n"
" git config advice.ignoredHook false"
+msgid "not a git repository"
+msgstr "не е хранилище на Git"
+
#, 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 ""
@@ -17301,6 +17794,9 @@ msgstr "Управлението на делегирането не Ñе подÐ
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "Задаването на поÑтоÑнен публичен ключ не Ñе поддържа от cURL < 7.39.0"
+msgid "Unknown value for http.proactiveauth"
+msgstr "Ðепозната ÑтойноÑÑ‚ за „http.proactiveauth“"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "„CURLSSLOPT_NO_REVOKE“ не Ñе поддържа от cURL < 7.44.0"
@@ -17320,6 +17816,12 @@ msgstr ""
"РеализациÑта на SSL не може да Ñе зададе да е „%s“, защото вече е зададена "
"друга"
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "отказ от прочитане на биÑквитките от „http.cookiefile“: „-“"
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "преÑкачане на „http.savecookies“ за празен „http.cookiefile“"
+
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -17464,6 +17966,17 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "Файлът-ключалка „%s.lock“ не може да бъде Ñъздаден: %s"
+msgid "unable to create temporary object directory"
+msgstr "не може да бъде Ñъздадена Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð·Ð° временни обекти"
+
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "индекÑÑŠÑ‚ Ñ Ð½ÐµÐ¿Ð°ÐºÐµÑ‚Ð¸Ñ€Ð°Ð½Ð¸ обекти не може да Ñе запише: %s"
+
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "грешка при запиÑа на индекÑа Ñ Ð½ÐµÐ¿Ð°ÐºÐµÑ‚Ð¸Ñ€Ð°Ð½Ð¸ обекти „%s“"
+
#, c-format
msgid "unexpected line: '%s'"
msgstr "неочакван ред: „%s“"
@@ -17475,6 +17988,10 @@ msgid "quoted CRLF detected"
msgstr "цитирани знаци CRLF"
#, c-format
+msgid "unable to format message: %s"
+msgstr "Ñъобщението не може да Ñе форматира: %s"
+
+#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (не е изтеглен)"
@@ -17487,6 +18004,10 @@ msgid "Failed to merge submodule %s (commits not present)"
msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (нÑма подаваниÑ)"
#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "ГРЕШКÐ: неуÑпешно Ñливане на подмодула „%s“ (хранилището е Ñ Ð³Ñ€ÐµÑˆÐºÐ¸)"
+
+#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr ""
"Подмодулът „%s“ не може да бъде ÑлÑÑ‚ (базата за Ñливане не предшеÑтва "
@@ -17513,12 +18034,13 @@ msgstr ""
"ÐеуÑпешно Ñливане на подмодула „%s“, но Ñа открити множеÑтво решениÑ:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "ÐеуÑпешно вътрешно Ñливане"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "ГРЕШКÐ: неуÑпешно вътрешно Ñливане за „%s“"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "„%s“ не може да Ñе добави в базата Ñ Ð´Ð°Ð½Ð½Ð¸"
+msgid "error: unable to add %s to database"
+msgstr "ГРЕШКÐ: „%s“ не може да Ñе добави в базата от данни"
#, c-format
msgid "Auto-merging %s"
@@ -17614,12 +18136,12 @@ msgstr ""
"е изтрит в „%s“."
#, c-format
-msgid "cannot read object %s"
-msgstr "обектът „%s“ не може да Ñе прочете"
+msgid "error: cannot read object %s"
+msgstr "ГРЕШКÐ: обектът „%s“ не може да Ñе прочете"
#, c-format
-msgid "object %s is not a blob"
-msgstr "обектът „%s“ не е BLOB"
+msgid "error: object %s is not a blob"
+msgstr "ГРЕШКÐ: обектът „%s“ не е BLOB"
#, c-format
msgid ""
@@ -17762,6 +18284,10 @@ msgstr ""
"не е ÑÑно какво да Ñе прави Ñ Ð¾Ð±ÐµÐºÑ‚Ð° „%2$s“ (%3$s) Ñ Ð¿Ñ€Ð°Ð²Ð°Ì€ за доÑтъп „%1$06o“"
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (хранилището е Ñ Ð³Ñ€ÐµÑˆÐºÐ¸)"
+
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "Превъртане на подмодула „%s“ до Ñледното подаване:"
@@ -17803,6 +18329,13 @@ msgstr ""
msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (открити Ñа множеÑтво ÑливаниÑ)"
+msgid "failed to execute internal merge"
+msgstr "неуÑпешно вътрешно Ñливане"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "„%s“ не може да Ñе добави в базата от данни"
+
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr "Грешка: за да не Ñе изтрие неÑледениÑÑ‚ файл „%s“, Ñе запиÑва в „%s“."
@@ -17905,6 +18438,14 @@ msgstr ""
"КОÐФЛИКТ (преименуване/преименуване): „%s“ е преименуван на „%s“ в клон "
"„%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"
+
msgid "modify"
msgstr "промÑна"
@@ -17966,55 +18507,6 @@ msgstr "ÐеуÑпешен анализ на обекта „%s“"
msgid "failed to read the cache"
msgstr "кешът не може да бъде прочетен"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "неправилен размер на Ð¾Ñ‚ÐºÑŠÑ (OID fanout) на индекÑа за множеÑтво пакети"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "файлът Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети „%s“ е твърде малък"
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr "отпечатъкът на индекÑа за множеÑтво пакети 0x%08x не Ñъвпада Ñ 0x%08x"
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "непозната верÑÐ¸Ñ Ð½Ð° Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети — %d"
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr ""
-"верÑиÑта на контролната Ñума на индекÑа за множеÑтво пакети %u не Ñъвпада Ñ "
-"%u"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "липÑва Ð¾Ñ‚ÐºÑŠÑ (pack-name) от Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "липÑва Ð¾Ñ‚ÐºÑŠÑ (OID fanout) от Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "липÑва Ð¾Ñ‚ÐºÑŠÑ (OID lookup) от Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "липÑва Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° отмеÑтваниÑта на обекти от Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr ""
-"неправилна подредба на имената в Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети: „%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 ""
-"индекÑÑŠÑ‚ за множеÑтво пакети Ñъдържа 64-битови отмеÑтваниÑ, но размерът на "
-"„off_t“ е недоÑтатъчен"
-
#, c-format
msgid "failed to add packfile '%s'"
msgstr "пакетниÑÑ‚ файл „%s“ не може да бъде добавен"
@@ -18038,11 +18530,6 @@ msgstr "редът не може да Ñе анализира: „%s“"
msgid "malformed line: %s"
msgstr "неправилен ред: „%s“."
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr ""
-"индекÑÑŠÑ‚ за множеÑтво пакети Ñе преÑкача, защото Ñумата за проверка не "
-"Ñъвпада"
-
msgid "could not load pack"
msgstr "пакетът не може да Ñе зареди"
@@ -18050,6 +18537,23 @@ msgstr "пакетът не може да Ñе зареди"
msgid "could not open index for %s"
msgstr "индекÑÑŠÑ‚ за „%s“ не може да Ñе отвори"
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "не може да Ñе Ñъздаде връзка „%s“, коÑто да Ñочи към „%s“"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "индекÑÑŠÑ‚ за множеÑтво пакети не може да бъде изчиÑтен при „%s“"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr ""
+"нараÑтващиÑÑ‚ Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети Ñ Ð±Ð¸Ñ‚Ð¾Ð²Ð° маÑка не може да Ñе запише"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"индекÑÑŠÑ‚ за множеÑтво пакети Ñе преÑкача, защото Ñумата за проверка не "
+"Ñъвпада"
+
msgid "Adding packfiles to multi-pack-index"
msgstr "ДобавÑне на пакетни файлове към Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети"
@@ -18077,24 +18581,44 @@ msgid "refusing to write multi-pack .bitmap without any objects"
msgstr ""
"многопакетната битова маÑка без никакви обекти не може да бъде запазена"
+msgid "unable to create temporary MIDX layer"
+msgstr "не може да Ñе Ñъздаде временен Ñлой за индекÑа за множеÑтво пакети"
+
msgid "could not write multi-pack bitmap"
msgstr "многопакетната битова маÑка не може да бъде запазена"
+msgid "unable to open multi-pack-index chain file"
+msgstr "файлът Ñ Ð²ÐµÑ€Ð¸Ð³Ð°Ñ‚Ð° на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта не може да Ñе отвори"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "Ñлой в индекÑа за множеÑтво пакети не може да Ñе преименува"
+
msgid "could not write multi-pack-index"
-msgstr "индекÑÑŠÑ‚ за множеÑтво пакети не може да бъде запазен"
+msgstr "индекÑÑŠÑ‚ за множеÑтво пакети не може да Ñе запази"
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "индекÑÑŠÑ‚ за множеÑтво пакети не може да бъде изчиÑтен при „%s“"
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"пакети за нараÑÑ‚Ð²Ð°Ñ‰Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети не може да Ñе обÑвÑÑ‚ за "
+"оÑтарели"
-msgid "multi-pack-index file exists, but failed to parse"
-msgstr "файлът Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети, но не може да бъде анализиран"
+msgid "Counting referenced objects"
+msgstr "ПреброÑване на Ñвързаните обекти"
-msgid "incorrect checksum"
-msgstr "неправилна Ñума за проверка"
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "ТърÑене и изтриване на неÑвързаните пакетни файлове"
-msgid "Looking for referenced packfiles"
-msgstr "ТърÑене на указаните пакетни файлове"
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "нараÑтващиÑÑ‚ Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети не може да Ñе препакетира"
+
+msgid "could not start pack-objects"
+msgstr "командата „pack-objects“ не може да бъде Ñтартирана"
+
+msgid "could not finish pack-objects"
+msgstr "командата „pack-objects“ не може да бъде завършена"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr ""
+"неправилен размер на откъÑа за разпределÑнето в индекÑа за множеÑтво пакети"
#, c-format
msgid ""
@@ -18103,6 +18627,119 @@ msgstr ""
"неправилна подредба на откъÑи (OID fanout): fanout[%d] = %<PRIx32> > "
"%<PRIx32> = fanout[%d]"
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "неправилен размер на откъÑа за търÑенето в индекÑа за множеÑтво пакети"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr ""
+"неправилен размер на откъÑа за отмеÑтваниÑта в индекÑа за множеÑтво пакети"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "файлът Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети „%s“ е твърде малък"
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "отпечатъкът на индекÑа за множеÑтво пакети 0x%08x не Ñъвпада Ñ 0x%08x"
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "непозната верÑÐ¸Ñ Ð½Ð° Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети — %d"
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr ""
+"верÑиÑта на контролната Ñума на индекÑа за множеÑтво пакети %u не Ñъвпада Ñ "
+"%u"
+
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr ""
+"откъÑÑŠÑ‚ за имена на пакети в индекÑа за множеÑтво пакети липÑва или е "
+"повреден"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"откъÑÑŠÑ‚ за разпределÑнето в индекÑа за множеÑтво пакети липÑва или е повреден"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr "откъÑÑŠÑ‚ за търÑене в Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети липÑва или е повреден"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"откъÑÑŠÑ‚ за отмеÑÑ‚Ð²Ð°Ð½Ð¸Ñ Ð² Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети липÑва или е повреден"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr ""
+"откъÑÑŠÑ‚ за име на пакет в Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети липÑва или е повреден"
+
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr ""
+"неправилна подредба на имената в Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети: „%s“ Ñе поÑви "
+"преди „%s“"
+
+msgid "multi-pack-index chain file too small"
+msgstr "файлът Ñ Ð²ÐµÑ€Ð¸Ð³Ð°Ñ‚Ð° за индекÑа за множеÑтво пакети е твърде малък"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr ""
+"броÑÑ‚ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð² оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети е прекалено голÑм: "
+"%<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr ""
+"броÑÑ‚ обекти в оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети е прекалено голÑм: "
+"%<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr ""
+"грешка във веригата на индекÑа за множеÑтво пакети: ред „%s“ не е контролна "
+"Ñума"
+
+msgid "unable to find all multi-pack index files"
+msgstr "нÑкои файлове на индекÑа за множеÑтво пакети не може да бъдат открити"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr ""
+"неправилна Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð½Ð° обект в индекÑа за множеÑтво пакети. ВероÑтно "
+"индекÑÑŠÑ‚ е повреден"
+
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr ""
+"неправилен идентификатор на пакет (pack-int-id): %u (от общо %u пакети)"
+
+msgid "MIDX does not contain the BTMP chunk"
+msgstr ""
+"липÑва Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° побитова маÑка във файла за индекÑа за множеÑтво пакети"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "пакетът за битови маÑки %<PRIu32> не може да Ñе отвори"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr ""
+"индекÑÑŠÑ‚ за множеÑтво пакети Ñъдържа 64-битови отмеÑтваниÑ, но размерът на "
+"„off_t“ е недоÑтатъчен"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr ""
+"ÑтойноÑтта на отмеÑтването в индекÑа за множеÑтво пакети е извън диапазона"
+
+msgid "multi-pack-index file exists, but failed to parse"
+msgstr ""
+"файлът Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети ÑъщеÑтвува, но не може да бъде "
+"анализиран"
+
+msgid "incorrect checksum"
+msgstr "неправилна Ñума за проверка"
+
+msgid "Looking for referenced packfiles"
+msgstr "ТърÑене на указаните пакетни файлове"
+
msgid "the midx contains no oid"
msgstr "във файла Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети нÑма идентификатори на обекти"
@@ -18134,18 +18771,6 @@ msgstr "индекÑÑŠÑ‚ на пакета „%s“ не може да бъде
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"
@@ -18200,6 +18825,25 @@ msgstr ""
msgid "Bad %s value: '%s'"
msgstr "Зададена е лоша ÑтойноÑÑ‚ на променливата „%s“: „%s“"
+msgid "failed to decode tree entry"
+msgstr "запиÑÑŠÑ‚ в дърво не може да Ñе декодира"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "не може да Ñе открие ÑъответÑтвието на запиÑа в дърво за „%s“"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "неправилен Ð·Ð°Ð¿Ð¸Ñ â€ž%s“ в подаването"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "не може да Ñе открие ÑъответÑтвието на „%s %s“ в обекта-подаване"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "ÐеуÑпешно преобразуване на „%s“ към „%s“"
+
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
msgstr ""
@@ -18306,6 +18950,18 @@ msgid "packed object %s (stored in %s) is corrupt"
msgstr "пакетираниÑÑ‚ обект „%s“ (в „%s“) е повреден"
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "липÑва ÑъответÑтвие на „%s“ към „%s“"
+
+#, c-format
+msgid "unable to open %s"
+msgstr "обектът „%s“ не може да бъде отворен"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "Ñъдържанието на файловете „%s“ и „%s“ е различно"
+
+#, c-format
msgid "unable to write file %s"
msgstr "файлът „%s“ не може да бъде запиÑан"
@@ -18360,6 +19016,10 @@ msgid "cannot read object for %s"
msgstr "обектът за „%s“ не може да Ñе прочете"
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "липÑва ÑъответÑтвие на обекта „%s“ към „%s“"
+
+#, c-format
msgid "object fails fsck: %s"
msgstr "„fsck“ откри грешка в обект: „%s“"
@@ -18387,10 +19047,6 @@ 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)"
@@ -18584,6 +19240,17 @@ msgstr "обектът „%s“ не може да бъде анализиран
msgid "hash mismatch %s"
msgstr "разлика в контролната Ñума: „%s“"
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "повтарÑщ Ñе Ð·Ð°Ð¿Ð¸Ñ Ð¿Ñ€Ð¸ запазване на Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки: „%s“"
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "опит за ÑъхранÑване на подаване, което не е избрано: „%s“"
+
+msgid "too many pseudo-merges"
+msgstr "прекалено много пÑевдо ÑливаниÑ"
+
msgid "trying to write commit not in index"
msgstr "опит за запиÑване на обект за подаване извън индекÑа"
@@ -18611,6 +19278,22 @@ msgstr ""
"повреден файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки (прекалено е малък дори и за "
"таблицата ÑÑŠÑ ÑъответÑтвиÑ)"
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"повреден файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки (прекалено е малък дори и за "
+"заглавната чаÑÑ‚ на таблицата за пÑевдо ÑливаниÑта)"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"повреден файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки (прекалено е малък дори и за "
+"таблицата Ñ Ð¿Ñевдо ÑливаниÑ)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr ""
+"повреден Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки, таблицата Ñ Ð¿Ñевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ðµ "
+"прекалено малка"
+
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "повтарÑщ Ñе Ð·Ð°Ð¿Ð¸Ñ Ð² Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки: „%s“"
@@ -18647,6 +19330,11 @@ msgstr "задължителниÑÑ‚ обратен Ð¸Ð½Ð´ÐµÐºÑ Ð»Ð¸Ð¿Ñва в
msgid "could not open pack %s"
msgstr "пакетът „%s“ не може да Ñе отвори"
+msgid "could not determine MIDX preferred pack"
+msgstr ""
+"предпочитаниÑÑ‚ пакет за файла Ñ Ð¸Ð½Ð´ÐµÐºÑа за множеÑтво пакети не може да Ñе "
+"определи"
+
#, c-format
msgid "preferred pack (%s) is invalid"
msgstr "предпочитаниÑÑ‚ пакет „%s“ е неправилен"
@@ -18674,6 +19362,16 @@ msgstr ""
"маÑка на подаване „%s“"
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr ""
+"пакетът не може да Ñе зареди: „%s“, преизползването на пакети Ñе изключва"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr ""
+"предпочитаниÑÑ‚ пакет не може да Ñе определи, преизползването на пакети Ñе "
+"изключва"
+
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "обектът „%s“ липÑва в битовата маÑка на видовете"
@@ -18703,6 +19401,10 @@ msgid "mismatch in bitmap results"
msgstr "различие в резултатите от битовите маÑки"
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "индекÑÑŠÑ‚ за пÑевдо Ñливане е извън диапазона (%<PRIu32> ≥ %<PRIuMAX>)"
+
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "„%s“ липÑва в пакет „%s“ при отмеÑтване %<PRIuMAX>"
@@ -18768,6 +19470,13 @@ msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr ""
"неправилна Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð² Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑ Ð¿Ñ€Ð¸ %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr ""
+"неправилен размер на Ð¾Ñ‚ÐºÑŠÑ Ð·Ð° обратен Ð¸Ð½Ð´ÐµÐºÑ Ð² индекÑа за множеÑтво пакети"
+
+msgid "could not determine preferred pack"
+msgstr "предпочитаниÑÑ‚ пакет не може да Ñе определи"
+
msgid "cannot both write and verify reverse index"
msgstr "обратниÑÑ‚ Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ може едновременно да Ñе запиÑва и да Ñе проверÑва"
@@ -18810,8 +19519,8 @@ msgstr "неправилна дата на Ñрок: „%s“"
#, c-format
msgid "option `%s' expects \"always\", \"auto\", or \"never\""
msgstr ""
-"опциÑта „%s“ изиÑква нÑÐºÐ¾Ñ Ð¾Ñ‚ ÑтойноÑтите: „always“ (винаги), "
-"„auto“ (автоматично) или „never“ (никога)"
+"опциÑта „%s“ изиÑква нÑÐºÐ¾Ñ Ð¾Ñ‚ ÑтойноÑтите: „always“ (винаги), „auto“ "
+"(автоматично) или „never“ (никога)"
#, c-format
msgid "malformed object name '%s'"
@@ -18826,14 +19535,6 @@ 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“ не приема аргументи"
@@ -18917,6 +19618,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-ЧИСЛО"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "обратното на „--no-%s“"
+
msgid "expiry-date"
msgstr "период на валидноÑÑ‚/запазване"
@@ -18948,6 +19653,14 @@ msgstr ""
"знак „NUL“"
#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "неправилна булева ÑтойноÑÑ‚ „%s“ за „%s“"
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "„%s“ не може да бъде анализиран"
+
+#, c-format
msgid "Could not make %s writable by group"
msgstr "Ðе може да Ñе дадат права̀ за Ð·Ð°Ð¿Ð¸Ñ Ð² директориÑта „%s“ на групата"
@@ -18995,6 +19708,10 @@ msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s: опциите „literal“ и „glob“ Ñа неÑъвмеÑтими"
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "„%s“ е извън дървото на директориите"
+
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s: „%s“ е извън хранилището при „%s“"
@@ -19069,6 +19786,9 @@ msgstr "не може да Ñе Ñъздаде нишка за изпълненÐ
msgid "unable to parse --pretty format"
msgstr "аргументът към опциÑта „--pretty“ не може да Ñе анализира"
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "отложеното доÑтавÑне е изключено, нÑкои обекти може и да липÑват"
+
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "хранилище-гарант: неуÑпешно Ñъздаване на Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð·Ð° доÑтавÑне"
@@ -19095,6 +19815,66 @@ msgstr "object-info: Ñлед аргументите Ñе очаква изчиÑ
msgid "Removing duplicate objects"
msgstr "Изтриване на повтарÑщите Ñе обекти"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr ""
+"регулÑрниÑÑ‚ израз за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð·Ð° „%s“, не може да бъде зареден: „%s“"
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s трÑбва да е неотрицателно, ще Ñе ползва Ñтандартната ÑтойноÑÑ‚"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s трÑбва да е между 0 и 1, ще Ñе ползва Ñтандартната ÑтойноÑÑ‚"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s трÑбва да е положително, ще Ñе ползва Ñтандартната ÑтойноÑÑ‚"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "в групата за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ â€ž%s“ липÑва задължителен шаблон"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr "в групата за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ â€ž%s“ има неÑтабилен праг пред ÑтабилниÑ"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"регулÑрниÑÑ‚ израз за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð² ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» Ñъдържа повече "
+"от макÑимално поддържаните прихващащи групи (max=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"опит за четене на разширено пÑевдо Ñливане извън диапазона (%<PRIuMAX> ≥ "
+"%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"прекалено кратък Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° разширено пÑевдо Ñливане (%<PRIuMAX> ≥ %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr "липÑва пÑевдо Ñливане за подаване „%s“ при отмеÑтване %<PRIuMAX>"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"четене за група за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ð´ границите (%<PRIu32> ≥ %<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "четене зад границите (%<PRIuMAX> ≥ %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "таблицата Ñ Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ‚Ðµ пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð·Ð° „%s“ не може да Ñе прочете"
+
msgid "could not start `log`"
msgstr "командата за журнала Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ â€žlog“ не може да Ñе Ñтартира"
@@ -19126,6 +19906,13 @@ 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“ вече ÑъщеÑтвува в индекÑа)"
@@ -19148,10 +19935,6 @@ 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“ ÑъщеÑтвува и като файл, и като директориÑ"
@@ -19269,10 +20052,6 @@ msgid "failed to convert to a sparse-index"
msgstr "индекÑÑŠÑ‚ не може да бъде превърнат в чаÑтичен"
#, c-format
-msgid "could not stat '%s'"
-msgstr "неуÑпешно изпълнение на „stat“ върху „%s“"
-
-#, c-format
msgid "unable to open git dir: %s"
msgstr "не може да Ñе отвори директориÑта на git: %s"
@@ -19288,6 +20067,14 @@ msgstr "права̀та за доÑтъп до „%s“ не може да бъ
msgid "%s: cannot drop to stage #0"
msgstr "%s: не може да Ñе премине към етап â„–0"
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "неочакван изходен код при генериране на разлика: %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"
@@ -19337,7 +20124,7 @@ msgstr ""
" e, edit ПОДÐÐ’ÐÐЕ — прилагане на подаването и Ñпиране при него за още "
"промѐни\n"
" s, squash ПОДÐÐ’ÐÐЕ — вкарване на подаването в предходното му\n"
-" f, fixup [-C | -c] ПОДÐÐ’ÐÐЕ\n"
+" f, fixup [-C|-c] ПОДÐÐ’ÐÐЕ\n"
" — вкарване на подаването в предходното му, без ÑмÑна на\n"
" Ñъобщението. С „-C“ Ñе използва Ñамо Ñъобщението на\n"
" наÑтоÑщото, а Ñ â€ž-c“ оÑвен това Ñе Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¾Ñ€ÑŠÑ‚\n"
@@ -19349,7 +20136,7 @@ msgstr ""
" d, drop ПОДÐÐ’ÐÐЕ — преÑкачане на подаването\n"
" l, label ЕТИКЕТ — задаване на етикет на указаното от HEAD\n"
" t, reset ЕТИКЕТ — занулÑване на HEAD към ЕТИКЕТа\n"
-" m, merge [-C ПОДÐÐ’ÐÐЕ | -c ПОДÐÐ’ÐÐЕ] ЕТИКЕТ [# ЕДИÐ_РЕД]\n"
+" m, merge [-C ПОДÐÐ’ÐÐЕ|-c ПОДÐÐ’ÐÐЕ] ЕТИКЕТ [# ЕДИÐ_РЕД]\n"
" — Ñъздаване на подаване ÑÑŠÑ Ñливане ÑÑŠÑ Ñъобщението от\n"
" първоначалното подаване (или Ñъобщението от ЕДИÐ_РЕД,\n"
" ако не е зададено подаване ÑÑŠÑ Ñливане. С опциÑта\n"
@@ -19490,6 +20277,22 @@ 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)"
@@ -19518,6 +20321,10 @@ msgid "expected format: %%(ahead-behind:<committish>)"
msgstr "очакван формат: %%(ahead-behind:ПОДÐÐ’ÐÐЕ)"
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "очакван формат: %%(is-base:ПОДÐÐ’ÐÐЕ)"
+
+#, c-format
msgid "malformed field name: %.*s"
msgstr "неправилно име на обект: „%.*s“"
@@ -19563,6 +20370,9 @@ 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“)"
@@ -19624,6 +20434,9 @@ msgstr "КЛЮЧ"
msgid "field name to sort on"
msgstr "име на полето, по което да е подредбата"
+msgid "exclude refs which match pattern"
+msgstr "преÑкачана на указателите напаÑващи на ШÐБЛОÐа"
+
#, c-format
msgid "not a reflog: %s"
msgstr "„%s“ не е журнал Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ"
@@ -19656,7 +20469,7 @@ msgstr ""
" git config --global init.defaultBranch ИМЕ\n"
"\n"
"ЧеÑто ползвани варианти вмеÑто „master“ Ñа „main“, „trunk“ и „development“.\n"
-"За да преименувата току що Ñъздаден клон, изпълнете:\n"
+"За да преименувате току що Ñъздаден клон, изпълнете:\n"
"\n"
" git branch -m ИМЕ\n"
@@ -19670,7 +20483,7 @@ msgstr "неправилно име на клон: „%s = %s“"
#, c-format
msgid "ignoring dangling symref %s"
-msgstr "игнориране на указател на обект извън клон „%s“"
+msgstr "игнориране на файл Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ» на обект извън клон „%s“"
#, c-format
msgid "log for ref %s has gap after %s"
@@ -19684,11 +20497,20 @@ msgstr "журналът Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта за ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€ž%s
msgid "log for %s is empty"
msgstr "журналът Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта за ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€ž%s“ е празен"
+msgid "refusing to force and skip creation of reflog"
+msgstr ""
+"принудителна Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð±ÐµÐ· Ñъздаване на журнал на указателите нÑма да Ñе "
+"приеме"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "указател не може да Ñе обнови Ñ Ð³Ñ€ÐµÑˆÐ½Ð¾ име „%s“"
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "пÑевдо указателÑÑ‚ „%s“ нÑма да Ñе обнови"
+
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "неуÑпешно обновÑване на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ (update_ref) „%s“: %s"
@@ -19711,10 +20533,6 @@ 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"
@@ -19723,6 +20541,104 @@ msgid "could not delete references: %s"
msgstr "Указателите не може да бъдат изтрити: %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "Пробната Ð¼Ð¸Ð³Ñ€Ð°Ñ†Ð¸Ñ Ð½Ð° указатели завърши, резултатите Ñа в „%s“\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "временната Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð·Ð° Ð¼Ð¸Ð³Ñ€Ð°Ñ†Ð¸Ñ â€ž%s“ не може да Ñе изтрие"
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "мигрираните указатели Ñа в „%s“"
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"указателÑÑ‚ „%s“ не може да Ñе заключи: очакваше Ñе файл Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ» Ñ Ñ†ÐµÐ» "
+"„%s“, но вмеÑто това е обикновен указател"
+
+#, c-format
+msgid "cannot open directory %s"
+msgstr "директориÑта „%s“ не може да бъде отворена"
+
+msgid "Checking references consistency"
+msgstr "Проверка на валидноÑтта на указателите"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "опаÑно име на указател: %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "опит за Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° указател „%s“ към обект, който не ÑъщеÑтвува: %s"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "опит за запиÑване на обект, който не е подаване — %s, в клона „%s“"
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"не Ñа позволени повече от една промѐни (включително чрез ÑÐ¾Ñ‡ÐµÑ‰Ð¸Ñ Ð³Ð¾ „%s“) на "
+"ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr ""
+"указателÑÑ‚ „%s“ не може да Ñе заключи: не може да Ñе открие към какво Ñочи "
+"указателÑÑ‚ „%s“"
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "указателÑÑ‚ „%s“ не може да Ñе заключи: грешка при четене на указателÑ"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"не Ñа позволени повече от една промѐни на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€ž%s“ (включително през "
+"ÑÐ¸Ð¼Ð²Ð¾Ð»Ð½Ð¸Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ» „%s“)"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "указателÑÑ‚ „%s“ не може да Ñе заключи:cуказателÑÑ‚ вече ÑъщеÑтвува"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr ""
+"указателÑÑ‚ „%s“ не може да Ñе заключи: указателÑÑ‚ липÑва, а Ñе очаква „%s“"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr ""
+"указателÑÑ‚ „%s“ не може да Ñе заключи: той Ñочи към „%s“, а Ñе очаква да "
+"Ñочи към „%s“"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "таблица Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ð¸: подготовка на транзакциÑ: %s"
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "таблица Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ð¸: неуÑпешна транзакциÑ: %s"
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "Ñтекът не може да Ñе Ñвие: %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "името на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€ž%s“ не може да бъде открито"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "името на указател „%s“ е Ñимволен указател, не може да Ñе копира"
+
+#, c-format
msgid "invalid refspec '%s'"
msgstr "неправилен указател: „%s“"
@@ -19733,6 +20649,10 @@ msgstr ""
"„%s“"
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "непозната ÑтойноÑÑ‚ за „--object-format“: „%s“"
+
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "„%sinfo/refs“ е неизползваемо, проверете дали е хранилище на git"
@@ -20074,7 +20994,8 @@ msgstr[1] ""
"ТекущиÑÑ‚ клон Ñе е раздалечил от „%s“,\n"
"двата имат Ñъответно по %d и %d неÑъвпадащи подаваниÑ.\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 " (Ñлейте Ð¾Ñ‚Ð´Ð°Ð»ÐµÑ‡ÐµÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½ в Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸Ñ Ñ‡Ñ€ÐµÐ· „git pull“)\n"
#, c-format
@@ -20187,12 +21108,27 @@ msgstr ""
"липÑва"
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
+msgid "%s exists but is a symbolic ref"
+msgstr "„%s“ ÑъщеÑтвува и не е Ñимволна връзка"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"„--merge“ изиÑква нÑкой от пÑевдо указателите „MERGE_HEAD“, "
+"„CHERRY_PICK_HEAD“, „REVERT_HEAD“ или „REBASE_HEAD“"
+
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
msgstr "подаването „%s“ към опциÑта „--ancestry-path“ не може да бъде получено"
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 "ТекущиÑÑ‚ клон е повреден"
@@ -20281,8 +21217,18 @@ msgstr "при клониране да Ñе Ñъздава пълна работ
msgid "only download metadata for the branch that will be checked out"
msgstr "да Ñе ÑвалÑÑ‚ метаданните Ñамо за изтеглÑÐ½Ð¸Ñ ÐºÐ»Ð¾Ð½"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [ОПЦИЯ…] [--] ХРÐÐИЛИЩЕ [ДИРЕКТОРИЯ]"
+msgid "create repository within 'src' directory"
+msgstr "Ñъздаване на хранилище в Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ â€žsrc“"
+
+msgid "specify if tags should be fetched during clone"
+msgstr "указва дали етикетите да Ñе доÑтавÑÑ‚ при клониране"
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch ОСÐОВЕÐ_КЛОÐ] [--full-clone]\n"
+" [--[no-]src] [--[no-]tags] ÐДРЕС [ЗÐЧИСЛЕÐÐ_ДИРЕКТОРИЯ]"
#, c-format
msgid "cannot deduce worktree name from '%s'"
@@ -20301,6 +21247,10 @@ msgid "could not configure remote in '%s'"
msgstr "отдалеченото хранилище в „%s“ не може да Ñе наÑтрои"
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "етикетите в „%s“ не може Ñа Ñе изключат"
+
+#, c-format
msgid "could not configure '%s'"
msgstr "„%s“ не може да Ñе наÑтрои"
@@ -20323,7 +21273,7 @@ msgid "reconfigure all registered enlistments"
msgstr "пренаÑтройване на вÑички зачиÑлени директории"
msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | ЗÐЧИСЛЕÐÐ_ДИРЕКТОРИЯ]"
+msgstr "scalar reconfigure [--all|ЗÐЧИСЛЕÐÐ_ДИРЕКТОРИЯ]"
msgid "--all or <enlistment>, but not both"
msgstr "опциÑта „--all“ и указването на зачиÑлена Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ðµ Ñа ÑъвмеÑтими"
@@ -20333,12 +21283,29 @@ msgid "could not remove stale scalar.repo '%s'"
msgstr "оÑтарÑлото Ñкаларно хранилище (scalar.repo) „%s“ не може да Ñе изтрие"
#, c-format
-msgid "removing stale scalar.repo '%s'"
+msgid "removed stale scalar.repo '%s'"
msgstr "изтриване на оÑтарÑлото Ñкаларно хранилище (scalar.repo) „%s“"
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "вече нÑма хранилище на git в „%s“"
+msgid "repository at '%s' has different owner"
+msgstr "хранилището „%s“ Ñе притежава от друг"
+
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "хранилището в „%s“ е Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÐµÐ½ формат"
+
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "в „%s“ липÑва хранилище на git"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"за да преуÑтановите региÑтрациÑта на хранилището в Scalar, изпълнете\n"
+"\n"
+" git config --global --unset --fixed-value scalar.repo \"%s\""
msgid ""
"scalar run <task> [<enlistment>]\n"
@@ -20367,7 +21334,7 @@ msgid "include Git's build options"
msgstr "включване и на опциите за компилиране на git"
msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v|--verbose] [--build-options]"
msgid "-C requires a <directory>"
msgstr "„-C“ изиÑква ДИРЕКТОРИЯ"
@@ -20453,6 +21420,19 @@ msgid "unknown action: %d"
msgstr "неизвеÑтно дейÑтвие: %d"
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"
+"За да откажете пребазирането и да Ñе върнете към първоначалното ÑÑŠÑтоÑние,\n"
+"изпълнете „git rebase --abort“."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -20703,10 +21683,6 @@ 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“ не може да бъде анализирано"
@@ -20775,10 +21751,6 @@ 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“"
@@ -20812,12 +21784,58 @@ msgstr ""
"командата „update-ref“ изиÑква пълно име на указател, напр. „refs/heads/%s“"
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "неправилна команда „%.*s“"
+msgid "'%s' does not accept merge commits"
+msgstr "„%s“ не приема Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ ÑÑŠÑ Ñливане"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"„pick“ не приема подаване ÑÑŠÑ Ñливане. Ðко иÑкате да приложите\n"
+"Ñливането наново изпълнате:\n"
+"\n"
+" git merge -C ПОДÐÐ’ÐÐЕ"
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"„reword“ не приема подаване ÑÑŠÑ Ñливане. Ðко иÑкате да приложите\n"
+"Ñливането наново и да промените Ñъобщението при подаване, изпълнете\n"
+"\n"
+" git merge -C ПОДÐÐ’ÐÐЕ"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"„edit“ не приема подаване ÑÑŠÑ Ñливане. Ðко иÑкате да приложите\n"
+"Ñливането наново, изпълнете\n"
+"\n"
+" git merge -C ПОДÐÐ’ÐÐЕ\n"
+"\n"
+"а Ñлед него задайте „break“, за да получите контрол и да изпълнете:\n"
+"\n"
+" git commit --amend && git rebase --continue"
+
+msgid "cannot squash merge commit into another commit"
+msgstr "подаване ÑÑŠÑ Ñливане не може да Ñе вкара в друго"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "„%s“ не приема аргументи: „%s“"
+msgid "invalid command '%.*s'"
+msgstr "неправилна команда „%.*s“"
#, c-format
msgid "missing arguments for %s"
@@ -20873,14 +21891,14 @@ msgstr "в момента вече Ñе извършва отмÑна на поÐ
#, c-format
msgid "try \"git revert (--continue | %s--abort | --quit)\""
-msgstr "използвайте „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)“"
+msgstr "използвайте „git cherry-pick (--continue|%s--abort|--quit)“"
#, c-format
msgid "could not create sequencer directory '%s'"
@@ -20942,9 +21960,8 @@ msgstr ""
msgid "cannot read HEAD"
msgstr "указателÑÑ‚ „HEAD“ не може да бъде прочетен"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "„%s“ не може да Ñе копира като „%s“"
+msgid "could not write commit message file"
+msgstr "файлът ÑÑŠÑ Ñъобщението за подаване не може да бъде запиÑан"
#, c-format
msgid ""
@@ -21114,6 +22131,9 @@ msgstr "Конфликти при прилагането на автоматич
msgid "Autostash exists; creating a new stash entry."
msgstr "Вече има Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° автоматично Ñкатано, затова Ñе Ñъздава нов запиÑ."
+msgid "autostash reference is a symref"
+msgstr "указателÑÑ‚ за автоматично Ñкатано e файл Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»"
+
msgid "could not detach HEAD"
msgstr "указателÑÑ‚ „HEAD“ не може да Ñе отдели"
@@ -21148,14 +22168,14 @@ msgstr ""
" 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 "Rebasing (%d/%d)%s"
+msgstr "Пребазиране (%d/%d)%s"
+
+#, c-format
msgid "unknown command %d"
msgstr "непозната команда %d"
@@ -21290,6 +22310,10 @@ msgstr ""
"не може да Ñе зададе текуща работна Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð¿Ñ€Ð¸ неправилни наÑтройки"
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "„%s“ вече ÑъщеÑтвува като „%s“"
+
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "Очаква Ñе верÑÐ¸Ñ Ð½Ð° хранилището на git <= %d, а не %d"
@@ -21346,6 +22370,22 @@ msgstr "процеÑÑŠÑ‚ не може да Ñе върне към предишÐ
msgid "failed to stat '%*s%s%s'"
msgstr "не може да бъде получена Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за „%*s%s%s“"
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "пътÑÑ‚ за безопаÑна Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ (safe.directory) „%s“ не е абÑолютен"
+
+#, 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"
+" git config --global --add safe.directory %s"
+
msgid "Unable to read current working directory"
msgstr "Текущата работна Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ðµ може да бъде прочетена"
@@ -21370,18 +22410,6 @@ msgstr ""
"„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"
-" git config --global --add safe.directory %s"
-
-#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
msgstr ""
"голото хранилище „%s“ не може да Ñе ползва („safe.bareRepository“ е „%s“)"
@@ -21402,12 +22430,106 @@ msgid "setsid failed"
msgstr "неуÑпешно изпълнение на „setsid“"
#, c-format
+msgid "cannot stat template '%s'"
+msgstr "не може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за шаблона „%s“"
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "директориÑта „%s“ не може да бъде отворена"
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "връзката „%s“ не може да бъде прочетена"
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "не може да Ñе Ñъздаде Ñимволна връзка „%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 "re-init: ignored --initial-branch=%s"
+msgstr "re-init: „--initial-branch=%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 ""
+"опит за занулÑване на хранилището и инициализиране Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð½Ð° контролна Ñума"
+
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr ""
+"опит за занулÑване на хранилището и инициализиране Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡ÐµÐ½ формат на "
+"ÑъхранÑване"
+
+#, c-format
+msgid "%s already exists"
+msgstr "ДиректориÑта „%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 "разделѐн Ð¸Ð½Ð´ÐµÐºÑ Ð½Ðµ може да Ñе ползва чаÑтичен индекÑ"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "неправилен формат за „%s“: елементът „%s“ не започва Ñ â€ž(“"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "неправилен формат за „%s“: елементът „%s“ не завършва Ñ â€ž)“"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "неправилен формат за „%s“: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
msgid "%u.%2.2u GiB"
@@ -21599,6 +22721,14 @@ msgid "submodule git dir '%s' is inside git dir '%.*s'"
msgstr "„%s“ (Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ð° подмодул) е в директориÑта на git: „%.*s“"
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr "„%.*s“ в Ð¿ÑŠÑ‚Ñ Ð·Ð° подмодул „%s“ не трÑбва да е Ñимволна връзка"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "пътÑÑ‚ за подмодул „%s“ не трÑбва да е Ñимволна връзка"
+
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
@@ -21637,10 +22767,6 @@ msgstr "не може да бъде получена Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€Ðµ
msgid "no remote configured to get bundle URIs from"
msgstr "не е наÑтроено отдалечено хранилище за ÑпиÑъците Ñ Ð°Ð´Ñ€ÐµÑи на пратки"
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "не е зададен никакъв Ð°Ð´Ñ€ÐµÑ Ð·Ð° отдалеченото хранилище„%s“"
-
msgid "could not get the bundle-uri list"
msgstr "ÑпиÑъкът Ñ Ð°Ð´Ñ€ÐµÑи на пратки не може да Ñе получи"
@@ -21655,12 +22781,6 @@ msgstr ""
"какъв брой запиÑи в кеша на обектите-дървета да Ñе отбележат като невалидни "
"(Ñтандартно е 0)"
-msgid "unhandled options"
-msgstr "неподдържани опции"
-
-msgid "error preparing revisions"
-msgstr "грешка при подготовката на верÑии"
-
#, c-format
msgid "commit %s is not marked reachable"
msgstr "подаването „%s“ не е отбелÑзано като доÑтижимо"
@@ -21729,6 +22849,24 @@ msgstr "лекÑема"
msgid "command token to send to the server"
msgstr "командна лекÑема за пращане"
+msgid "unit-test [<options>]"
+msgstr "unit-test [ОПЦИЯ…]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "незабавен изход Ñлед Ð¿ÑŠÑ€Ð²Ð¸Ñ Ð½ÐµÑƒÑпешен теÑÑ‚"
+
+msgid "suite[::test]"
+msgstr "ГРУПÐ[::ТЕСТ]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "изпълнение на тази ГРУПРили конкретен теÑÑ‚ Ñ Ð¸Ð¼Ðµ ГРУПÐ::ТЕСТ"
+
+msgid "suite"
+msgstr "ГРУПÐ"
+
+msgid "exclude test suite <suite>"
+msgstr "преÑкачане на тази ГРУПРтеÑтове"
+
#, c-format
msgid "running trailer command '%s' failed"
msgstr "неуÑпешно изпълнение на завършващата команда „%s“"
@@ -21741,29 +22879,6 @@ msgstr "непозната ÑтойноÑÑ‚ „%s“ за наÑтройката
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 "Ðе може да Ñе получи Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за „%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 "неуÑпешен пълен Ð·Ð°Ð¿Ð¸Ñ ÐºÑŠÐ¼ наÑрещната помощна програма"
@@ -21817,9 +22932,6 @@ 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“"
@@ -21870,7 +22982,7 @@ msgstr ""
"изброÑване на указателите"
#, c-format
-msgid "helper %s does not support 'force'"
+msgid "helper %s does not support '--force'"
msgstr "наÑрещната помощна програма „%s“ не поддържа опциÑта „--force“"
msgid "couldn't run fast-export"
@@ -21955,10 +23067,6 @@ msgid "support for protocol v2 not implemented yet"
msgstr "протокол верÑÐ¸Ñ 2 вÑе още не Ñе поддържа"
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "непозната ÑтойноÑÑ‚ за наÑтройката „%s“: „%s“"
-
-#, c-format
msgid "transport '%s' not allowed"
msgstr "преноÑÑŠÑ‚ по „%s“ не е позволен"
@@ -22008,9 +23116,12 @@ msgstr "операциÑта „bundle-uri“ (адреÑи на пратки) Ð
msgid "could not retrieve server-advertised bundle-uri list"
msgstr ""
-"ÑпъÑъкът Ñ Ð°Ð´Ñ€ÐµÑи на пратки обÑвени за налични от Ñървъра не може да Ñе "
+"ÑпиÑъкът Ñ Ð°Ð´Ñ€ÐµÑи на пратки обÑвени за налични от Ñървъра не може да Ñе "
"получи "
+msgid "operation not supported by protocol"
+msgstr "опциÑта не Ñе поддържа от протокола"
+
msgid "too-short tree object"
msgstr "прекалено кратък обект-дърво"
@@ -22285,6 +23396,10 @@ msgstr "неправилен номер на порт"
msgid "invalid '..' path segment"
msgstr "неправилна чаÑÑ‚ от Ð¿ÑŠÑ‚Ñ â€ž..“"
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "ГРЕШКÐ: Ñъобщението не може да Ñе форматира: %s\n"
+
msgid "usage: "
msgstr "употреба: "
@@ -22399,6 +23514,9 @@ msgstr "нÑма доÑтъп до „%s“"
msgid "unable to get current working directory"
msgstr "текущата работна Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ðµ недоÑтъпна"
+msgid "unable to get random bytes"
+msgstr "не може да Ñе получат Ñлучайни байтове"
+
msgid "Unmerged paths:"
msgstr "ÐеÑлети пътища:"
@@ -22763,7 +23881,7 @@ msgid ""
"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."
@@ -22851,6 +23969,10 @@ msgstr "оÑвен това в индекÑа има неподадени про
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "не може да извършите „%s“, защото в индекÑа има неподадени промѐни."
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "непознат Ñтил „%s“ за „%s“"
+
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22947,6 +24069,9 @@ msgstr "„%s.final“ Ñъдържа подготвеното е-пиÑмо.\n"
msgid "--dump-aliases incompatible with other options\n"
msgstr "опциÑта „--dump-aliases“ е неÑъвмеÑтима Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ‚Ðµ опции\n"
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "опциите „--dump-aliases“ и „--translate-aliases“ Ñа неÑъвмеÑтими\n"
+
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -23044,13 +24169,13 @@ msgstr ""
"Изтрийте вÑичко, ако не иÑкате да изпратите обобщаващо пиÑмо.\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"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "„%s“ не може да Ñе отвори: %s"
+
msgid "Summary email is empty, skipping it\n"
msgstr "Обобщаващото пиÑмо е празно и Ñе преÑкача\n"
@@ -23102,8 +24227,8 @@ msgstr "ГРЕШКÐ: не може да Ñе извлече Ð°Ð´Ñ€ÐµÑ Ð¾Ñ‚ „
#. at this point.
msgid "What to do with this address? ([q]uit|[d]rop|[e]dit): "
msgstr ""
-"Какво да Ñе направи Ñ Ñ‚Ð¾Ð·Ð¸ адреÑ? „q“ (Ñпиране), „d“ (изтриване), "
-"„e“ (редактиране): "
+"Какво да Ñе направи Ñ Ñ‚Ð¾Ð·Ð¸ адреÑ? „q“ (Ñпиране), „d“ (изтриване), „e“ "
+"(редактиране): "
#, perl-format
msgid "CA path \"%s\" does not exist"
@@ -23165,24 +24290,24 @@ msgid "Failed to send %s\n"
msgstr "„%s“ не може да бъде изпратен\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Проба за изпращане на „%s“\n"
+msgid "Dry-Sent %s"
+msgstr "Проба за изпращане на „%s“"
#, perl-format
-msgid "Sent %s\n"
-msgstr "Изпращане на „%s“\n"
+msgid "Sent %s"
+msgstr "Изпращане на „%s“"
-msgid "Dry-OK. Log says:\n"
-msgstr "УÑпех при пробата. От журнала:\n"
+msgid "Dry-OK. Log says:"
+msgstr "УÑпех при пробата. От журнала:"
-msgid "OK. Log says:\n"
-msgstr "УÑпех. От журнала:\n"
+msgid "OK. Log says:"
+msgstr "УÑпех. От журнала:"
msgid "Result: "
msgstr "Резултат: "
-msgid "Result: OK\n"
-msgstr "Резултат: уÑпех\n"
+msgid "Result: OK"
+msgstr "Резултат: уÑпех"
#, perl-format
msgid "can't open file %s"
diff --git a/po/ca.po b/po/ca.po
index 6d64d7259a..ace9b3ca46 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -1,7 +1,7 @@
# Catalan translations for Git.
# This file is distributed under the same license as the Git package.
# Alex Henrie <alexhenrie24@gmail.com>, 2014-2016.
-# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2023
+# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2024
#
# Terminologia
#
@@ -14,6 +14,7 @@
# bundle | farcell
# check out | agafar
# chunk | fragment
+# commit | comissió
# cover letter | carta de presentació
# cruft | superflu
# delta | diferència
@@ -28,6 +29,7 @@
# hint | consell
# hook | lligam
# hunk | tros
+# multi-pack-index | índex multipaquet
# not supported | no està admès
# pull | baixar
# push | pujar
@@ -54,6 +56,7 @@
# Anglès | Català
# -----------------+---------------------------------
# blame | «blame»
+# fanout | «fanout»
# HEAD | HEAD (f, la branca actual) - (no s'apostrofa)
# cherry pick | «cherry pick»
# promisor | «promisor»
@@ -68,192 +71,244 @@
#
# 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
+# - Usem la convenció valenciana per a «per / per a», que inclou l'ús de «per a» davant d'infinitiu
#
msgid ""
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\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"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 09:03+0200\n"
+"Last-Translator: Mikel Forcada <mikel.forcada@gmail.com>\n"
"Language-Team: Catalan\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 2.3.1\n"
+"X-Generator: Poedit 3.2.2\n"
+#: add-interactive.c
#, c-format
msgid "Huh (%s)?"
msgstr "Perdó (%s)?"
+#: add-interactive.c builtin/merge.c builtin/rebase.c reset.c sequencer.c
msgid "could not read index"
msgstr "no s'ha pogut llegir l'índex"
+#: add-interactive.c
msgid "binary"
msgstr "binari"
+#: add-interactive.c
msgid "nothing"
msgstr "res"
+#: add-interactive.c
msgid "unchanged"
msgstr "sense canvis"
+#: add-interactive.c
msgid "Update"
msgstr "Actualitza"
+#: add-interactive.c
#, c-format
msgid "could not stage '%s'"
msgstr "no s'ha pogut fer «stage» «%s»"
+#: add-interactive.c builtin/stash.c reset.c sequencer.c
msgid "could not write index"
msgstr "no s'ha pogut escriure l'índex"
+#: add-interactive.c
#, c-format
msgid "updated %d path\n"
msgid_plural "updated %d paths\n"
msgstr[0] "actualitzat %d camí\n"
msgstr[1] "actualitzats %d camins\n"
+#: add-interactive.c
#, c-format
msgid "note: %s is untracked now.\n"
msgstr "nota: %s està ara sense seguiment.\n"
+#: add-interactive.c apply.c builtin/checkout.c builtin/reset.c
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "make_cache_entry ha fallat per al camí «%s»"
+#: add-interactive.c
msgid "Revert"
msgstr "Reverteix"
+#: add-interactive.c
msgid "Could not parse HEAD^{tree}"
msgstr "No s'ha pogut analitzar HEAD^{tree}"
+#: add-interactive.c
#, c-format
msgid "reverted %d path\n"
msgid_plural "reverted %d paths\n"
msgstr[0] "revertit %d camí\n"
msgstr[1] "revertits %d camins\n"
+#: add-interactive.c
#, c-format
msgid "No untracked files.\n"
msgstr "Sense fitxers no seguits.\n"
+#: add-interactive.c
msgid "Add untracked"
msgstr "Afegeix sense seguiment"
+#: add-interactive.c
#, c-format
msgid "added %d path\n"
msgid_plural "added %d paths\n"
msgstr[0] "afegit %d camí\n"
msgstr[1] "afegits %d camins\n"
+#: add-interactive.c
#, c-format
msgid "ignoring unmerged: %s"
msgstr "s'està ignorant allò no fusionat: %s"
+#: add-interactive.c
#, c-format
msgid "Only binary files changed.\n"
msgstr "Només han canviat fitxers binaris.\n"
+#: add-interactive.c
#, c-format
msgid "No changes.\n"
msgstr "Sense canvis.\n"
+#: add-interactive.c
msgid "Patch update"
msgstr "Actualització del pedaç"
+#: add-interactive.c
msgid "Review diff"
msgstr "Reviseu les diferències"
+#: add-interactive.c
msgid "show paths with changes"
msgstr "mostra els camins amb canvis"
+#: add-interactive.c
msgid "add working tree state to the staged set of changes"
msgstr "afegeix l'estat de l'arbre de treball al conjunt de canvis «staged»"
+#: add-interactive.c
msgid "revert staged set of changes back to the HEAD version"
msgstr "reverteix el conjunt de canvis «staged» a la versió HEAD"
+#: add-interactive.c
msgid "pick hunks and update selectively"
msgstr "selecciona els trossos i actualitza selectivament"
+#: add-interactive.c
msgid "view diff between HEAD and index"
msgstr "visualitza les diferències entre HEAD i l'índex"
+#: add-interactive.c
msgid "add contents of untracked files to the staged set of changes"
msgstr "afegeix contingut de fitxers no seguits al conjunt de canvis «staged»"
+#: add-interactive.c
msgid "Prompt help:"
msgstr "Mostra ajuda:"
+#: add-interactive.c
msgid "select a single item"
msgstr "seleccioneu un únic ítem"
+#: add-interactive.c
msgid "select a range of items"
msgstr "seleccioneu un rang d'ítems"
+#: add-interactive.c
msgid "select multiple ranges"
msgstr "seleccioneu rangs múltiples"
+#: add-interactive.c
msgid "select item based on unique prefix"
msgstr "seleccioneu un ítem basant-se en un prefix únic"
+#: add-interactive.c
msgid "unselect specified items"
msgstr "desselecciona els ítems especificats"
+#: add-interactive.c
msgid "choose all items"
msgstr "trieu tots els ítems"
+#: add-interactive.c
msgid "(empty) finish selecting"
msgstr "(buit) finalitza la selecció"
+#: add-interactive.c
msgid "select a numbered item"
msgstr "seleccioneu un ítem numerat"
+#: add-interactive.c
msgid "(empty) select nothing"
msgstr "(buit) no seleccionis res"
+#: add-interactive.c builtin/clean.c
msgid "*** Commands ***"
msgstr "*** Ordres ***"
+#: add-interactive.c builtin/clean.c
msgid "What now"
msgstr "I ara què"
+#: add-interactive.c
msgid "staged"
msgstr "staged"
+#: add-interactive.c
msgid "unstaged"
msgstr "unstaged"
+#: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
+#: builtin/diagnose.c builtin/fetch.c builtin/hook.c builtin/merge.c
+#: builtin/pull.c builtin/submodule--helper.c
msgid "path"
msgstr "camí"
+#: add-interactive.c
msgid "could not refresh index"
msgstr "no s'ha pogut actualitzar l'índex"
+#: add-interactive.c builtin/clean.c
#, c-format
msgid "Bye.\n"
msgstr "Adeu.\n"
+#: add-patch.c
#, c-format
msgid "Stage mode change [y,n,q,a,d%s,?]? "
msgstr "Canvia el mode de «stage» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Stage deletion [y,n,q,a,d%s,?]? "
msgstr "Suprimeix «stage» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Stage addition [y,n,q,a,d%s,?]? "
msgstr "Afegeix a «stage» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Stage this hunk [y,n,q,a,d%s,?]? "
msgstr "Fer un «stage» d'aquest tros [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"staging."
@@ -261,6 +316,7 @@ msgstr ""
"Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
"«staging»."
+#: add-patch.c
msgid ""
"y - stage this hunk\n"
"n - do not stage this hunk\n"
@@ -272,24 +328,30 @@ msgstr ""
"n - no facis «stage» d'aquest tros\n"
"q - surt; no facis «stage» d'aquest tros ni de cap altre restant\n"
"a - fes «stage» d'aquest tros i de tota la resta de trossos del fitxer\n"
-"d - no facis «stage» d'aquest tros ni de cap altre restant del fitxer\n"
+"d - no facis «stage» d'aquest tros ni de cap altre tros posterior del "
+"fitxer\n"
+#: add-patch.c
#, c-format
msgid "Stash mode change [y,n,q,a,d%s,?]? "
msgstr "Canvia el mode de «stash» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Stash deletion [y,n,q,a,d%s,?]? "
msgstr "Suprimeix «stash» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Stash addition [y,n,q,a,d%s,?]? "
msgstr "Afegeix a «stash» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Stash this hunk [y,n,q,a,d%s,?]? "
msgstr "Fer un «stash» d'aquest tros [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"stashing."
@@ -297,6 +359,7 @@ msgstr ""
"Si el pedaç s'aplica de forma neta, el tros editat es marcarà immediatament "
"per a «stashing»."
+#: add-patch.c
msgid ""
"y - stash this hunk\n"
"n - do not stash this hunk\n"
@@ -308,24 +371,30 @@ msgstr ""
"n - no facis «stash» d'aquest tros\n"
"q - surt; no facis «stash» d'aquest tros ni de cap altre restant\n"
"a - fes «stash» d'aquest tros i de tota la resta de trossos del fitxer\n"
-"d - no facis «stash» d'aquest tros ni de cap altre restant del fitxer\n"
+"d - no facis «stash» d'aquest tros ni de cap altre tros posterior del "
+"fitxer\n"
+#: add-patch.c
#, c-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
msgstr "Canvia el mode de «unstage» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Unstage deletion [y,n,q,a,d%s,?]? "
msgstr "Suprimeix «Unstage» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Unstage addition [y,n,q,a,d%s,?]? "
msgstr "Afegeix a «unstage» [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
msgstr "Fer un «unstage» d'aquest tros [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"unstaging."
@@ -333,6 +402,7 @@ msgstr ""
"Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
"«unstaging»."
+#: add-patch.c
msgid ""
"y - unstage this hunk\n"
"n - do not unstage this hunk\n"
@@ -346,22 +416,27 @@ msgstr ""
"a - fes «unstage» d'aquest tros i de tota la resta de trossos del fitxer\n"
"d - no facis «unstage» d'aquest tros ni de cap altre restant del fitxer\n"
+#: add-patch.c
#, c-format
msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
msgstr "Aplica el canvi de mode a l'índex [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
msgstr "Aplica la supressió a l'índex [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply addition to index [y,n,q,a,d%s,?]? "
msgstr "Aplica l'addició a l'índex [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
msgstr "Aplica aquest tros a l'índex [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"applying."
@@ -369,6 +444,7 @@ msgstr ""
"Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
"aplicar-lo."
+#: add-patch.c
msgid ""
"y - apply this hunk to index\n"
"n - do not apply this hunk to index\n"
@@ -382,22 +458,27 @@ msgstr ""
"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
+#: add-patch.c
#, c-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta el canvi de mode de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta suprimir de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta l'addició de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta aquest tros de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"discarding."
@@ -405,6 +486,7 @@ msgstr ""
"Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
"ser descartat."
+#: add-patch.c
msgid ""
"y - discard this hunk from worktree\n"
"n - do not discard this hunk from worktree\n"
@@ -418,26 +500,31 @@ msgstr ""
"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\n"
+#: add-patch.c
#, c-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Descarta el canvi de mode de l'índex i de l'arbre de treball [y,n,q,a,"
"d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta suprimir de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Descarta l'addició de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Descarta aquest tros de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"y - discard this hunk from index and worktree\n"
"n - do not discard this hunk from index and worktree\n"
@@ -451,23 +538,28 @@ msgstr ""
"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\n"
+#: add-patch.c
#, c-format
msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Aplica el canvi de mode a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica la supressió a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica l'addició a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica aquest tros a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"y - apply this hunk to index and worktree\n"
"n - do not apply this hunk to index and worktree\n"
@@ -481,22 +573,27 @@ msgstr ""
"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
+#: add-patch.c
#, c-format
msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica el canvi de mode a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica la supressió a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica l'addició a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
#, c-format
msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica aquest tros a l'arbre de treball [y,n,q,a,d%s,?]? "
+#: add-patch.c
msgid ""
"y - apply this hunk to worktree\n"
"n - do not apply this hunk to worktree\n"
@@ -510,23 +607,29 @@ msgstr ""
"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
+#: add-patch.c
#, c-format
msgid "could not parse hunk header '%.*s'"
msgstr "no s'ha pogut analitzar la capçalera del tros «%.*s»"
+#: add-patch.c
msgid "could not parse diff"
msgstr "no s'ha pogut analitzar el diff"
+#: add-patch.c
msgid "could not parse colored diff"
msgstr "no s'ha pogut analitzar el diff acolorit"
+#: add-patch.c
#, c-format
msgid "failed to run '%s'"
msgstr "no s'ha pogut executar «%s»"
+#: add-patch.c
msgid "mismatched output from interactive.diffFilter"
msgstr "sortida no coincident des d'interactive.diffFilter"
+#: add-patch.c
msgid ""
"Your filter must maintain a one-to-one correspondence\n"
"between its input and output lines."
@@ -534,6 +637,7 @@ msgstr ""
"El filtre ha de mantenir una correspondència d'un a un\n"
"entre les línies d'entrada i sortida."
+#: add-patch.c
#, c-format
msgid ""
"expected context line #%d in\n"
@@ -542,6 +646,7 @@ msgstr ""
"s'esperava la línia amb contingut #%d a\n"
"%.*s"
+#: add-patch.c
#, c-format
msgid ""
"hunks do not overlap:\n"
@@ -554,22 +659,25 @@ msgstr ""
"\tno acaben amb:\n"
"%.*s"
+#: add-patch.c
msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
msgstr ""
"Mode d'edició de trossos manual - vegeu més avall per a una guia ràpida.\n"
+#: add-patch.c
#, 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"Per a eliminar les línies «%c», convertiu-les en línies ' ' (context).\n"
"Per a eliminar les línies «%c», suprimiu-les.\n"
-"Les línies que comencin per %c s'eliminaran.\n"
+"Les línies que comencin per %s s'eliminaran.\n"
+#: 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"
@@ -579,9 +687,11 @@ msgstr ""
"de nou. Si s'eliminen totes les línies del tros, llavors l'edició s'avorta\n"
"i el tros es deixa sense cap canvi.\n"
+#: add-patch.c
msgid "could not parse hunk header"
msgstr "no s'ha pogut analitzar la capçalera del tros"
+#: add-patch.c
msgid "'git apply --cached' failed"
msgstr "«git apply --cached» ha fallat"
@@ -591,21 +701,26 @@ msgstr "«git apply --cached» ha fallat"
#. (saying "n" for "no" discards!) if the translation
#. of the word "no" does not start with n.
#.
+#: add-patch.c
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
"El tros editat no s'aplica. Editeu-lo de nou (si responeu «no» es "
"descartarà) [y/n]? "
+#: add-patch.c
msgid "The selected hunks do not apply to the index!"
msgstr "Els trossos seleccionats no s'apliquen a l'índex!"
+#: add-patch.c
msgid "Apply them to the worktree anyway? "
msgstr "Voleu aplicar-los igualment a l'arbre de treball? "
+#: add-patch.c
msgid "Nothing was applied.\n"
msgstr "No s'ha aplicat res.\n"
+#: add-patch.c
msgid ""
"j - leave this hunk undecided, see next undecided hunk\n"
"J - leave this hunk undecided, see next hunk\n"
@@ -615,69 +730,105 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
-"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"
-"g - selecciona el tros on voleu anar\n"
-"/ - cerca un tros que coincideixi amb l'expressió regular donada\n"
-"s - divideix el tros actual en trossos més petits\n"
+"j - deixa aquest tros sense decidir, veges el tros següent no decidit \n"
+"J - deixa aquest tros sense decidir, veges el tros següent\n"
+"k - deixa aquest tros sense decidir, veges el tros anterior no decidit ºn\n"
+"K - deixa aquest tros sense decidir, veges el tros anterior\n"
+"g - selecciona un tros a on anar\n"
+"/ - cerca un tros que concorde amb l'expressió regular donada\n"
+"s - divideix el tros actual en trossos més menuts\n"
"e - edita manualment el tros actual\n"
-"? - mostra l'ajuda\n"
+"p - imprimeix el tros actual, «P» per a usar el paginador\n"
+"? - imprimeix l'ajuda\n"
+#: add-patch.c
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "S'espera una lletra, s'ha obtingut «%s»"
+
+#: add-patch.c
msgid "No previous hunk"
msgstr "Sense tros previ"
+#: add-patch.c
msgid "No next hunk"
msgstr "No hi ha tros següent"
+#: add-patch.c
msgid "No other hunks to goto"
msgstr "No hi ha altres trossos on anar-hi"
+#: add-patch.c
msgid "go to which hunk (<ret> to see more)? "
-msgstr "ves a quin tros (<ret> per a veure'n més)? "
+msgstr "ves a quin tros (<intro> per a veure'n més)? "
+#: add-patch.c
msgid "go to which hunk? "
msgstr "ves a quin tros? "
+#: add-patch.c
#, c-format
msgid "Invalid number: '%s'"
msgstr "Número no vàlid: «%s»"
+#: add-patch.c
#, c-format
msgid "Sorry, only %d hunk available."
msgid_plural "Sorry, only %d hunks available."
msgstr[0] "Només %d tros disponible."
msgstr[1] "Només %d trossos disponibles."
+#: add-patch.c
msgid "No other hunks to search"
msgstr "No hi ha cap altre tros a cercar"
+#: add-patch.c
msgid "search for regex? "
msgstr "cerca per expressió regular? "
+#: add-patch.c
#, c-format
msgid "Malformed search regexp %s: %s"
msgstr "Expressió regular de cerca mal formada %s: %s"
+#: add-patch.c
msgid "No hunk matches the given pattern"
msgstr "No hi ha trossos que coincideixin amb el patró donat"
+#: add-patch.c
msgid "Sorry, cannot split this hunk"
msgstr "No es pot dividir aquest tros"
+#: add-patch.c
#, c-format
msgid "Split into %d hunks."
msgstr "Divideix en %d trossos."
+#: add-patch.c
msgid "Sorry, cannot edit this hunk"
msgstr "No es pot editar aquest tros"
+#: add-patch.c
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Ordre desconeguda: «%s» (useu «?» per a obtenir ajuda)"
+
+#: add-patch.c
msgid "'git apply' failed"
msgstr "«git apply» ha fallat"
+#: add-patch.c
+msgid "No changes."
+msgstr "No hi ha canvis."
+
+#: add-patch.c
+msgid "Only binary files changed."
+msgstr "Només han canviat els fitxers binaris."
+
+#: advice.c
#, c-format
msgid ""
"\n"
@@ -686,28 +837,36 @@ msgstr ""
"\n"
"Desactiva aquest missatge amb «git config advice.%s false»"
+#: advice.c
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sconsell: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sconsell:%s%.*s%s\n"
+#: advice.c
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr "Fer «cherry pick» no és possible perquè teniu fitxers sense fusionar."
+#: advice.c
msgid "Committing is not possible because you have unmerged files."
msgstr "Cometre no és possible perquè teniu fitxers sense fusionar."
+#: advice.c
msgid "Merging is not possible because you have unmerged files."
msgstr "Fusionar no és possible perquè teniu fitxers sense fusionar."
+#: advice.c
msgid "Pulling is not possible because you have unmerged files."
msgstr "Baixar no és possible perquè teniu fitxers sense fusionar."
+#: advice.c
msgid "Reverting is not possible because you have unmerged files."
msgstr "Revertir no és possible perquè teniu fitxers sense fusionar."
+#: advice.c
msgid "Rebasing is not possible because you have unmerged files."
msgstr "Fer «rebase» no és possible perquè teniu fitxers sense fusionar."
+#: advice.c
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."
@@ -716,18 +875,23 @@ msgstr ""
"«git add/rm <fitxer>» segons sigui apropiat per a\n"
"marcar la resolució i feu una comissió."
+#: advice.c
msgid "Exiting because of an unresolved conflict."
msgstr "S'està sortint a causa d'un conflicte no resolt."
+#: advice.c builtin/merge.c
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "No heu conclòs la vostra fusió (MERGE_HEAD existeix)."
+#: advice.c
msgid "Please, commit your changes before merging."
msgstr "Cometeu els vostres canvis abans de fusionar."
+#: advice.c
msgid "Exiting because of unfinished merge."
msgstr "S'està sortint a causa d'una fusió no terminada."
+#: advice.c
msgid ""
"Diverging branches can't be fast-forwarded, you need to either:\n"
"\n"
@@ -745,9 +909,11 @@ msgstr ""
"\n"
"\tgit rebase\n"
+#: advice.c
msgid "Not possible to fast-forward, aborting."
msgstr "No és possible avançar ràpidament, s'està avortant."
+#: advice.c
#, c-format
msgid ""
"The following paths and/or pathspecs matched paths that exist\n"
@@ -758,6 +924,7 @@ msgstr ""
"amb camins que existeixen fora de la vostra definició de\n"
"«sparse-checkout», així que no serà actualitzaran en l'índex:\n"
+#: advice.c
msgid ""
"If you intend to update such entries, try one of the following:\n"
"* Use the --sparse option.\n"
@@ -767,6 +934,7 @@ msgstr ""
"* Utilitzeu l'opció --sparse.\n"
"* Inhabiliteu o modifiqueu les regles de dispersió."
+#: advice.c
#, c-format
msgid ""
"Note: switching to '%s'.\n"
@@ -807,6 +975,7 @@ msgstr ""
"«false»\n"
"\n"
+#: advice.c
#, c-format
msgid ""
"The following paths have been moved outside the\n"
@@ -817,6 +986,7 @@ msgstr ""
"definició de sparse-checkout però no són dispersos\n"
"a causa de modificacions en local.\n"
+#: advice.c
msgid ""
"To correct the sparsity of these paths, do the following:\n"
"* Use \"git add --sparse <paths>\" to update the index\n"
@@ -826,79 +996,108 @@ msgstr ""
"* Useu «git add --sparse <paths>» per a actualitzar l'índex\n"
"* Useu «git sparse-checkout reapply» per a aplicar les regles de dispersió"
+#: alias.c
msgid "cmdline ends with \\"
msgstr "la línia d'ordres acaba amb \\"
+#: alias.c
msgid "unclosed quote"
msgstr "cometes no tancades"
+#: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c
+#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c
msgid "too many arguments"
msgstr "hi ha massa arguments"
+#: apply.c
#, c-format
msgid "unrecognized whitespace option '%s'"
msgstr "opció d'espai en blanc «%s» no reconeguda"
+#: apply.c
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
msgstr "opció ignora l'espai en blanc «%s» no reconeguda"
+#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c
+#: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c
+#: builtin/describe.c builtin/diff-tree.c builtin/difftool.c
+#: builtin/fast-export.c builtin/fetch.c builtin/help.c builtin/index-pack.c
+#: builtin/init-db.c builtin/log.c builtin/ls-files.c builtin/merge-base.c
+#: builtin/merge-tree.c builtin/merge.c builtin/pack-objects.c builtin/rebase.c
+#: builtin/repack.c builtin/replay.c builtin/reset.c builtin/rev-list.c
+#: builtin/rev-parse.c builtin/show-branch.c builtin/stash.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/worktree.c parse-options.c
+#: range-diff.c revision.c
#, c-format
msgid "options '%s' and '%s' cannot be used together"
msgstr "les opcions «%s» i «%s» no es poden usar juntes"
+#: apply.c
#, c-format
msgid "'%s' outside a repository"
msgstr "«%s» fora d'un repositori"
+#: apply.c
msgid "failed to read patch"
msgstr "s'ha produït un error en llegir el pedaç"
+#: apply.c
msgid "patch too large"
msgstr "el pedaç és massa gran"
+#: apply.c
#, c-format
msgid "Cannot prepare timestamp regexp %s"
msgstr "No es pot preparar l'expressió regular de marca de temps %s"
+#: apply.c
#, c-format
msgid "regexec returned %d for input: %s"
msgstr "regexec ha retornat %d per a l'entrada: %s"
+#: apply.c
#, c-format
msgid "unable to find filename in patch at line %d"
msgstr "no s'ha pogut trobar el nom de fitxer en el pedaç a la línia %d"
+#: apply.c
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
msgstr ""
"git apply: git-diff incorrecte - s'esperava /dev/null, s'ha rebut %s en la "
"línia %d"
+#: apply.c
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
msgstr ""
"git apply: git-diff incorrecte - nom de fitxer nou inconsistent en la línia "
"%d"
+#: apply.c
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
msgstr ""
"git apply: git-diff incorrecte - nom de fitxer antic inconsistent en la "
"línia %d"
+#: apply.c
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
msgstr "git apply: git-diff incorrecte - s'esperava /dev/null en la línia %d"
+#: apply.c
#, c-format
msgid "invalid mode on line %d: %s"
msgstr "mode no vàlid en la línia %d: %s"
+#: apply.c
#, c-format
msgid "inconsistent header lines %d and %d"
msgstr "línies de capçalera %d i %d inconsistents"
+#: apply.c
#, c-format
msgid ""
"git diff header lacks filename information when removing %d leading pathname "
@@ -913,75 +1112,93 @@ msgstr[1] ""
"a la capçalera de git diff li manca informació de nom de fitxer en eliminar "
"%d components de nom de camí inicial (línia %d)"
+#: apply.c
#, c-format
msgid "git diff header lacks filename information (line %d)"
msgstr ""
"a la capçalera de git diff li manca informació de nom de fitxer (línia %d)"
+#: apply.c
#, c-format
msgid "recount: unexpected line: %.*s"
msgstr "recompte: línia inesperada: %.*s"
+#: apply.c
#, c-format
msgid "patch fragment without header at line %d: %.*s"
msgstr "fragment de pedaç sense capçalera a la línia %d: %.*s"
+#: apply.c
msgid "new file depends on old contents"
msgstr "el fitxer nou depèn dels continguts antics"
+#: apply.c
msgid "deleted file still has contents"
msgstr "el fitxer suprimit encara té continguts"
+#: apply.c
#, c-format
msgid "corrupt patch at line %d"
msgstr "pedaç malmès a la línia %d"
+#: apply.c
#, c-format
msgid "new file %s depends on old contents"
msgstr "el fitxer nou %s depèn dels continguts antics"
+#: apply.c
#, c-format
msgid "deleted file %s still has contents"
msgstr "el fitxer suprimit %s encara té continguts"
+#: apply.c
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr "** advertència: el fitxer %s queda buit però no se suprimeix"
+#: apply.c
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr "pedaç binari malmès a la línia %d: %.*s"
+#: apply.c
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr "pedaç binari no reconegut a la línia %d"
+#: apply.c
#, c-format
msgid "patch with only garbage at line %d"
msgstr "pedaç amb només escombraries a la línia %d"
+#: apply.c
#, c-format
msgid "unable to read symlink %s"
msgstr "no s'ha pogut llegir l'enllaç simbòlic %s"
+#: apply.c
#, c-format
msgid "unable to open or read %s"
msgstr "no s'ha pogut obrir o llegir %s"
+#: apply.c
#, c-format
msgid "invalid start of line: '%c'"
msgstr "inici de línia no vàlid: «%c»"
+#: apply.c
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
msgstr[0] "El tros #%d ha tingut èxit a %d (desplaçament d'%d línia)."
msgstr[1] "El tros #%d ha tingut èxit a %d (desplaçament de %d línies)."
+#: apply.c
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr "El context s'ha reduït a (%ld/%ld) per a aplicar el fragment a %d"
+#: apply.c
#, c-format
msgid ""
"while searching for:\n"
@@ -990,19 +1207,23 @@ msgstr ""
"tot cercant:\n"
"%.*s"
+#: apply.c
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "manquen les dades de pedaç binari de «%s»"
+#: apply.c
#, c-format
msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'"
msgstr "no es pot aplicar al revés un pedaç binari sense el tros revés a «%s»"
+#: apply.c
#, c-format
msgid "cannot apply binary patch to '%s' without full index line"
msgstr ""
"no es pot aplicar un pedaç binari a «%s» sense la línia d'índex completa"
+#: apply.c
#, c-format
msgid ""
"the patch applies to '%s' (%s), which does not match the current contents."
@@ -1010,235 +1231,287 @@ msgstr ""
"el pedaç s'aplica a «%s» (%s), el qual no coincideix amb els continguts "
"actuals."
+#: apply.c
#, c-format
msgid "the patch applies to an empty '%s' but it is not empty"
msgstr "el pedaç s'aplica a un «%s» buit però no és buit"
+#: apply.c
#, c-format
msgid "the necessary postimage %s for '%s' cannot be read"
msgstr "no es pot llegir la postimatge %s necessària per a «%s»"
+#: apply.c
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "el pedaç binari no s'aplica a «%s»"
+#: apply.c
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
"el pedaç binari a «%s» crea un resultat incorrecte (s'esperava %s, s'ha "
"rebut %s)"
+#: apply.c
#, c-format
msgid "patch failed: %s:%ld"
msgstr "el pedaç ha fallat: %s:%ld"
+#: apply.c builtin/mv.c
#, c-format
msgid "cannot checkout %s"
msgstr "no es pot agafar %s"
+#: apply.c midx.c pack-mtimes.c pack-revindex.c setup.c
#, c-format
msgid "failed to read %s"
msgstr "s'ha produït un error en llegir %s"
+#: apply.c
#, c-format
msgid "reading from '%s' beyond a symbolic link"
msgstr "s'està llegint de «%s» més enllà d'un enllaç simbòlic"
+#: apply.c
#, c-format
msgid "path %s has been renamed/deleted"
msgstr "el camí %s s'ha canviat de nom / s'ha suprimit"
+#: apply.c
#, c-format
msgid "%s: does not exist in index"
msgstr "%s: no existeix en l'índex"
+#: apply.c
#, c-format
msgid "%s: does not match index"
msgstr "%s: no coincideix amb l'índex"
+#: apply.c
msgid "repository lacks the necessary blob to perform 3-way merge."
msgstr ""
"al repositori li manca el blob necessari per a fer a una fusió de 3 vies."
+#: apply.c
#, c-format
msgid "Performing three-way merge...\n"
msgstr "S'està fent una fusió de 3 vies...\n"
+#: apply.c
#, c-format
msgid "cannot read the current contents of '%s'"
msgstr "no es poden llegir els continguts actuals de «%s»"
+#: apply.c
#, c-format
msgid "Failed to perform three-way merge...\n"
msgstr "S'ha produït un error en fer una fusió de tres vies...\n"
+#: apply.c
#, c-format
msgid "Applied patch to '%s' with conflicts.\n"
msgstr "S'ha aplicat el pedaç a «%s» amb conflictes.\n"
+#: apply.c
#, c-format
msgid "Applied patch to '%s' cleanly.\n"
msgstr "S'ha aplicat el pedaç a «%s» netament.\n"
+#: apply.c
#, c-format
msgid "Falling back to direct application...\n"
msgstr "S'està usant alternativament l'aplicació directa...\n"
+#: apply.c
msgid "removal patch leaves file contents"
msgstr "el pedaç d'eliminació deixa els continguts dels fitxers"
+#: apply.c
#, c-format
msgid "%s: wrong type"
msgstr "%s: tipus erroni"
+#: apply.c
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s és del tipus %o, s'esperava %o"
+#: apply.c read-cache.c
#, c-format
msgid "invalid path '%s'"
msgstr "camí no vàlid: «%s»"
+#: apply.c
#, c-format
msgid "%s: already exists in index"
msgstr "%s: ja existeix en l'índex"
+#: apply.c
#, c-format
msgid "%s: already exists in working directory"
msgstr "%s: ja existeix en el directori de treball"
+#: apply.c
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "el mode nou (%o) de %s no coincideix amb el mode antic (%o)"
+#: apply.c
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr "el mode nou (%o) de %s no coincideix amb el mode antic (%o) de %s"
+#: apply.c
#, c-format
msgid "affected file '%s' is beyond a symbolic link"
msgstr "el fitxer afectat «%s» és més enllà d'un enllaç simbòlic"
+#: apply.c
#, c-format
msgid "%s: patch does not apply"
msgstr "%s: el pedaç no s'aplica"
+#: apply.c
#, c-format
msgid "Checking patch %s..."
msgstr "S'està comprovant el pedaç %s..."
+#: apply.c
#, c-format
msgid "sha1 information is lacking or useless for submodule %s"
msgstr "falta la informació sha1 o és inútil per al submòdul %s"
+#: apply.c
#, c-format
msgid "mode change for %s, which is not in current HEAD"
msgstr "canvi de mode per a %s, el qual no està en la HEAD actual"
+#: apply.c
#, c-format
msgid "sha1 information is lacking or useless (%s)."
msgstr "falta informació sha1 o és inútil (%s)."
+#: apply.c
#, c-format
msgid "could not add %s to temporary index"
msgstr "no s'ha pogut afegir %s a l'índex temporal"
+#: apply.c
#, c-format
msgid "could not write temporary index to %s"
msgstr "no s'ha pogut escriure l'índex temporal a %s"
+#: apply.c
#, c-format
msgid "unable to remove %s from index"
msgstr "no s'ha pogut eliminar %s de l'índex"
+#: apply.c
#, c-format
msgid "corrupt patch for submodule %s"
msgstr "pedaç malmès per al submòdul %s"
+#: apply.c
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "no s'ha pogut fer stat al fitxer novament creat «%s»"
+#: apply.c
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr ""
"no s'ha pogut crear un magatzem de suport per al fitxer novament creat %s"
+#: apply.c
#, c-format
msgid "unable to add cache entry for %s"
msgstr "no s'ha pogut afegir una entrada de cau per a %s"
+#: apply.c builtin/bisect.c builtin/gc.c
#, c-format
msgid "failed to write to '%s'"
msgstr "no s'ha pogut escriure a «%s»"
+#: apply.c
#, c-format
msgid "closing file '%s'"
msgstr "s'està tancant el fitxer «%s»"
+#: apply.c
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "no s'ha pogut escriure el fitxer «%s» mode %o"
+#: apply.c
#, c-format
msgid "Applied patch %s cleanly."
msgstr "El pedaç %s s'ha aplicat netament."
+#: apply.c
msgid "internal error"
msgstr "error intern"
+#: apply.c
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] "S'està aplicant el pedaç %%s amb %d rebuig..."
msgstr[1] "S'està aplicant el pedaç %%s amb %d rebutjos..."
-#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "s'està truncant el nom del fitxer .rej a %.*s.rej"
-
+#: apply.c
#, c-format
msgid "cannot open %s"
msgstr "no es pot obrir %s"
+#: apply.c rerere.c
#, c-format
msgid "cannot unlink '%s'"
msgstr "no es pot fer «unlink» de «%s»"
+#: apply.c
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "El tros #%d s'ha aplicat netament."
+#: apply.c
#, c-format
msgid "Rejected hunk #%d."
msgstr "S'ha rebutjat el tros #%d."
+#: apply.c
#, c-format
msgid "Skipped patch '%s'."
msgstr "S'ha omès el pedaç «%s»."
+#: apply.c
msgid "No valid patches in input (allow with \"--allow-empty\")"
msgstr "No hi ha pedaços vàlids a l'entrada (permeteu-los amb «--allow-empty»)"
+#: apply.c t/helper/test-cache-tree.c
msgid "unable to read index file"
msgstr "no es pot llegir el fitxer d'índex"
+#: apply.c
#, c-format
msgid "can't open patch '%s': %s"
msgstr "no es pot obrir el pedaç «%s»: %s"
+#: apply.c
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "s'ha silenciat %d error d'espai en blanc"
msgstr[1] "s'han silenciat %d errors d'espai en blanc"
+#: apply.c
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
msgstr[0] "%d línia afegeix errors d'espai en blanc."
msgstr[1] "%d línies afegeixen errors d'espai en blanc."
+#: apply.c
#, c-format
msgid "%d line applied after fixing whitespace errors."
msgid_plural "%d lines applied after fixing whitespace errors."
@@ -1247,283 +1520,398 @@ msgstr[0] ""
msgstr[1] ""
"S'han aplicat %d línies després d'arreglar els errors d'espai en blanc."
+#: apply.c builtin/mv.c builtin/rm.c
msgid "Unable to write new index file"
msgstr "No s'ha pogut escriure un fitxer d'índex nou"
+#: apply.c
msgid "don't apply changes matching the given path"
msgstr "no apliquis els canvis que coincideixin amb el camí donat"
+#: apply.c
msgid "apply changes matching the given path"
msgstr "aplica els canvis que coincideixin amb el camí donat"
+#: apply.c builtin/am.c
msgid "num"
msgstr "nombre"
+#: apply.c
msgid "remove <num> leading slashes from traditional diff paths"
msgstr ""
"elimina <nombre> barres obliqües inicials dels camins de diferència "
"tradicionals"
+#: apply.c
msgid "ignore additions made by the patch"
msgstr "ignora afegiments fets pel pedaç"
+#: apply.c
msgid "instead of applying the patch, output diffstat for the input"
msgstr ""
"en lloc d'aplicar el pedaç, emet les estadístiques de diferència de l'entrada"
+#: apply.c
msgid "show number of added and deleted lines in decimal notation"
msgstr "mostra el nombre de línies afegides i suprimides en notació decimal"
+#: apply.c
msgid "instead of applying the patch, output a summary for the input"
msgstr "en lloc d'aplicar el pedaç, emet un resum de l'entrada"
+#: apply.c
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "en lloc d'aplicar el pedaç, determina si el pedaç és aplicable"
+#: apply.c
msgid "make sure the patch is applicable to the current index"
msgstr "assegura que el pedaç sigui aplicable a l'índex actual"
+#: apply.c
msgid "mark new files with `git add --intent-to-add`"
msgstr "marca els fitxers nous amb «git add --intent-to-add»"
+#: apply.c
msgid "apply a patch without touching the working tree"
msgstr "aplica un pedaç sense tocar l'arbre de treball"
+#: apply.c
msgid "accept a patch that touches outside the working area"
msgstr "accepta un pedaç que toqui fora de l'àrea de treball"
+#: apply.c
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "aplica el pedaç també (useu amb --stat/--summary/--check)"
+#: apply.c
msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr ""
"intenta una fusió de tres vies, si falla intenta llavors un pedaç normal"
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "en conflictes, usa la nostra versió"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "en conflictes, usa la seva versió"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "en conflictes, usa una versió d'unió"
+
+#: apply.c
msgid "build a temporary index based on embedded index information"
msgstr "construeix un índex temporal basat en la informació d'índex incrustada"
+#: apply.c builtin/checkout-index.c
msgid "paths are separated with NUL character"
msgstr "els camins se separen amb el caràcter NUL"
+#: apply.c
msgid "ensure at least <n> lines of context match"
msgstr "assegura't que almenys <n> línies de context coincideixin"
+#: apply.c builtin/am.c builtin/interpret-trailers.c builtin/pack-objects.c
+#: builtin/rebase.c
msgid "action"
msgstr "acció"
+#: apply.c
msgid "detect new or modified lines that have whitespace errors"
msgstr ""
"detecta les línies noves o modificades que tinguin errors d'espai en blanc"
+#: apply.c
msgid "ignore changes in whitespace when finding context"
msgstr "ignora els canvis d'espai en blanc en cercar context"
+#: apply.c
msgid "apply the patch in reverse"
msgstr "aplica el pedaç al revés"
+#: apply.c
msgid "don't expect at least one line of context"
msgstr "no esperis almenys una línia de context"
+#: apply.c
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "deixa els trossos rebutjats en fitxers *.rej corresponents"
+#: apply.c
msgid "allow overlapping hunks"
msgstr "permet trossos superposats"
+#: apply.c
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "tolera una línia nova incorrectament detectada al final del fitxer"
+#: apply.c
msgid "do not trust the line counts in the hunk headers"
msgstr "no confiïs en els recomptes de línia en les capçaleres dels trossos"
+#: apply.c builtin/am.c
msgid "root"
msgstr "arrel"
+#: apply.c
msgid "prepend <root> to all filenames"
msgstr "anteposa <arrel> a tots els noms de fitxer"
+#: apply.c
msgid "don't return error for empty patches"
msgstr "no retornis l'error per als pedaços buits"
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, i --union requereixen --3way"
+
+#: archive-tar.c archive-zip.c
#, c-format
msgid "cannot stream blob %s"
msgstr "no es pot transmetre el blob %s"
+#: archive-tar.c archive-zip.c
#, c-format
msgid "unsupported file mode: 0%o (SHA1: %s)"
msgstr "mode de fitxer no compatible: 0%o (SHA1: %s)"
+#: archive-tar.c archive-zip.c builtin/pack-objects.c
#, c-format
msgid "deflate error (%d)"
msgstr "error de deflació (%d)"
+#: archive-tar.c
#, c-format
msgid "unable to start '%s' filter"
msgstr "no s'ha pogut iniciar el filtre «%s»"
+#: archive-tar.c
msgid "unable to redirect descriptor"
msgstr "no s'ha pogut redirigir el descriptor"
+#: archive-tar.c
#, c-format
msgid "'%s' filter reported error"
msgstr "«%s» error reportat pel filtre"
+#: archive-zip.c
#, c-format
msgid "path is not valid UTF-8: %s"
msgstr "el camí no és vàlid en UTF-8: %s"
+#: archive-zip.c
#, c-format
msgid "path too long (%d chars, SHA1: %s): %s"
msgstr "el camí és massa llarg (%d caràcters, SHA1: %s): %s"
+#: archive-zip.c
#, c-format
msgid "timestamp too large for this system: %<PRIuMAX>"
msgstr "marca de temps massa gran per a aquest sistema: %<PRIuMAX>"
+#: archive.c
msgid "git archive [<options>] <tree-ish> [<path>...]"
msgstr "git archive [<opcions>] <arbre> [<camí>...]"
+#: archive.c
msgid ""
"git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
msgstr ""
"git archive --remote <repositori> [--exec <ordre>] [<opcions>] <arbre> "
"[<camí>...]"
+#: archive.c
msgid "git archive --remote <repo> [--exec <cmd>] --list"
msgstr "git archive --remote <repositori> [--exec <ordre>] --list"
+#: archive.c builtin/gc.c builtin/notes.c builtin/tag.c
#, c-format
msgid "cannot read '%s'"
msgstr "no es pot llegir «%s»"
+#: archive.c
#, c-format
msgid "pathspec '%s' matches files outside the current directory"
msgstr ""
"l'especificació de camí «%s» coincideix amb fitxers fora del directori actual"
+#: archive.c builtin/add.c builtin/rm.c
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "l'especificació de camí «%s» no ha coincidit amb cap fitxer"
+#: archive.c
#, c-format
msgid "no such ref: %.*s"
msgstr "no existeix la referència: %.*s"
+#: archive.c
#, c-format
msgid "not a valid object name: %s"
msgstr "no és un nom d'objecte vàlid: %s"
+#: archive.c t/helper/test-cache-tree.c
#, c-format
msgid "not a tree object: %s"
msgstr "no és un objecte d'arbre: %s"
+#: archive.c
+#, c-format
+msgid "failed to unpack tree object %s"
+msgstr "s'ha produït un error en desempaquetar l'objecte d'arbre %s"
+
+#: archive.c
#, c-format
msgid "File not found: %s"
msgstr "Fitxer no trobat: %s"
+#: archive.c
#, c-format
msgid "Not a regular file: %s"
msgstr "No és un fitxer normal: %s"
+#: archive.c
#, c-format
msgid "unclosed quote: '%s'"
msgstr "cometes no tancades: «%s»"
+#: archive.c
#, c-format
msgid "missing colon: '%s'"
msgstr "falten els dos punts: «%s»"
+#: archive.c
#, c-format
msgid "empty file name: '%s'"
msgstr "nom de fitxer buit: «%s»"
+#: archive.c
msgid "fmt"
msgstr "format"
+#: archive.c
msgid "archive format"
msgstr "format d'arxiu"
+#: archive.c builtin/log.c parse-options.h
msgid "prefix"
msgstr "prefix"
+#: archive.c
msgid "prepend prefix to each pathname in the archive"
msgstr "anteposa el prefix a cada nom de camí en l'arxiu"
+#: archive.c builtin/blame.c builtin/commit-tree.c builtin/config.c
+#: builtin/fast-export.c builtin/gc.c builtin/grep.c builtin/hash-object.c
+#: builtin/ls-files.c builtin/notes.c builtin/read-tree.c parse-options.h
msgid "file"
msgstr "fitxer"
+#: archive.c
msgid "add untracked file to archive"
msgstr "inclou els fitxers no seguits a l'arxiu"
+#: archive.c
msgid "path:content"
msgstr "camí: contingut"
+#: archive.c builtin/archive.c
msgid "write the archive to this file"
msgstr "escriu l'arxiu a aquest fitxer"
+#: archive.c
msgid "read .gitattributes in working directory"
msgstr "llegeix .gitattributes en el directori de treball"
+#: archive.c
msgid "report archived files on stderr"
msgstr "informa de fitxers arxivats en stderr"
+#: archive.c builtin/clone.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c
msgid "time"
msgstr "data"
+#: archive.c
msgid "set modification time of archive entries"
msgstr "estableix l'hora de modificació de les entrades de l'arxiu"
+#: archive.c
msgid "set compression level"
msgstr "estableix el nivell de compressió"
+#: archive.c
msgid "list supported archive formats"
msgstr "llista els formats d'arxiu admesos"
+#: archive.c builtin/archive.c builtin/clone.c builtin/submodule--helper.c
msgid "repo"
msgstr "repositori"
+#: archive.c builtin/archive.c
msgid "retrieve the archive from remote repository <repo>"
msgstr "recupera l'arxiu del repositori remot <repositori>"
+#: archive.c builtin/archive.c builtin/difftool.c builtin/notes.c
msgid "command"
msgstr "ordre"
+#: archive.c builtin/archive.c
msgid "path to the remote git-upload-archive command"
msgstr "camí a l'ordre git-upload-archive remota"
+#: archive.c
msgid "Unexpected option --remote"
msgstr "Opció inesperada --remote"
+#: archive.c builtin/add.c builtin/checkout.c builtin/clone.c builtin/commit.c
+#: builtin/fast-export.c builtin/index-pack.c builtin/log.c builtin/reset.c
+#: builtin/rm.c builtin/stash.c builtin/worktree.c fetch-pack.c http-fetch.c
+#: revision.c
#, c-format
msgid "the option '%s' requires '%s'"
msgstr "l'opció «%s» requereix «%s»"
+#: archive.c
msgid "Unexpected option --output"
msgstr "Opció inesperada --output"
+#: archive.c t/unit-tests/unit-test.c
+#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "paràmetre extra de la línia d'ordres «%s»"
+
+#: archive.c
#, c-format
msgid "Unknown archive format '%s'"
msgstr "Format d'arxiu desconegut «%s»"
+#: archive.c
#, c-format
msgid "Argument not supported for format '%s': -%d"
msgstr "Argument no admès per al format «%s»: -%d"
+#: attr.c
#, c-format
msgid "%.*s is not a valid attribute name"
msgstr "%.*s no és un nom d'atribut vàlid"
+#: attr.c
msgid "unable to add additional attribute"
msgstr "no s'ha pogut afegir l'atribut addicional"
+#: attr.c
#, c-format
msgid "ignoring overly long attributes line %d"
msgstr "s'ignorarà la línia d'atributs massa llarga %d"
+#: attr.c
#, c-format
msgid "%s not allowed: %s:%d"
msgstr "%s no està permès: %s:%d"
+#: attr.c
msgid ""
"Negative patterns are ignored in git attributes\n"
"Use '\\!' for literal leading exclamation."
@@ -1531,33 +1919,56 @@ msgstr ""
"Els patrons negatius s'ignoren en els atributs de git\n"
"Useu «\\!» per exclamació capdavantera literal."
+#: attr.c
#, c-format
msgid "cannot fstat gitattributes file '%s'"
msgstr "no es pot fer fstat gitattributes al fitxer «%s»"
+#: attr.c
#, c-format
msgid "ignoring overly large gitattributes file '%s'"
-msgstr "s'ignorarà el fitxer «%s» gitattributes per ser massa gran"
+msgstr "s'ignorarà el fitxer «%s» gitattributes per a ser massa gran"
+#: attr.c
#, c-format
msgid "ignoring overly large gitattributes blob '%s'"
-msgstr "s'ignorarà el blob «%s» gitattributes per ser massa gran"
+msgstr "s'ignorarà el blob «%s» gitattributes per a ser massa gran"
+
+#: attr.c
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "no es pot usar --attr-source o GIT_ATTR_SOURCE sense repository"
+#: attr.c
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "--attr-source incorrecte o GIT_ATTR_SOURCE"
+#: attr.c read-cache.c
+#, c-format
+msgid "unable to stat '%s'"
+msgstr "no s'ha pogut fer «stat» a «%s»"
+
+#: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
+#, c-format
+msgid "unable to read %s"
+msgstr "no s'ha pogut llegir %s"
+
+#: bisect.c
#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Comentari amb cometes errònies en el fitxer «%s»: %s"
+#: bisect.c
#, c-format
msgid "We cannot bisect more!\n"
msgstr "No podem bisecar més!\n"
+#: bisect.c
#, c-format
msgid "Not a valid commit name %s"
msgstr "No és un nom de comissió vàlid %s"
+#: bisect.c
#, c-format
msgid ""
"The merge base %s is bad.\n"
@@ -1566,6 +1977,7 @@ msgstr ""
"La base de fusió %s és errònia.\n"
"Això vol dir que el defecte s'ha arreglat entre %s i [%s].\n"
+#: bisect.c
#, c-format
msgid ""
"The merge base %s is new.\n"
@@ -1574,6 +1986,7 @@ msgstr ""
"La base de fusió %s és nova.\n"
"La propietat s'ha canviat entre %s i [%s].\n"
+#: bisect.c
#, c-format
msgid ""
"The merge base %s is %s.\n"
@@ -1582,6 +1995,7 @@ msgstr ""
"La base de fusió %s és %s.\n"
"Això vol dir que la primera comissió «%s» és entre %s i [%s].\n"
+#: bisect.c
#, c-format
msgid ""
"Some %s revs are not ancestors of the %s rev.\n"
@@ -1592,6 +2006,7 @@ msgstr ""
"git bisect no pot funcionar correctament en aquest cas.\n"
"Potser heu confós les revisions %s i %s?\n"
+#: bisect.c
#, c-format
msgid ""
"the merge base between %s and [%s] must be skipped.\n"
@@ -1603,29 +2018,41 @@ msgstr ""
"%s.\n"
"Continuem de totes maneres."
+#: bisect.c
#, c-format
msgid "Bisecting: a merge base must be tested\n"
msgstr "Bisecant: s'ha de provar una base de fusió\n"
+#: bisect.c
#, c-format
msgid "a %s revision is needed"
msgstr "es necessita una revisió %s"
+#: bisect.c
#, c-format
msgid "could not create file '%s'"
msgstr "no s'ha pogut crear el fitxer «%s»"
+#: bisect.c builtin/notes.c
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "no s'ha pogut iniciar «show» per a l'objecte «%s»"
+
+#: bisect.c builtin/merge.c
#, c-format
msgid "could not read file '%s'"
msgstr "no s'ha pogut llegir el fitxer «%s»"
+#: bisect.c
msgid "reading bisect refs failed"
msgstr "la lectura de les referències de bisecció ha fallat"
+#: bisect.c
#, c-format
msgid "%s was both %s and %s\n"
msgstr "%s era ambdós %s i %s\n"
+#: bisect.c
#, c-format
msgid ""
"No testable commit found.\n"
@@ -1634,6 +2061,7 @@ msgstr ""
"No s'ha trobat cap comissió comprovable.\n"
"Potser heu començat amb paràmetres de camí incorrectes?\n"
+#: bisect.c
#, c-format
msgid "(roughly %d step)"
msgid_plural "(roughly %d steps)"
@@ -1643,36 +2071,46 @@ msgstr[1] "(aproximadament %d passos)"
#. TRANSLATORS: the last %s will be replaced with "(roughly %d
#. steps)" translation.
#.
+#: bisect.c
#, 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] "Bisecant: manca %d revisió a provar després d'aquesta %s\n"
msgstr[1] "Bisecant: manquen %d revisions a provar després d'aquesta %s\n"
+#: blame.c
msgid "--contents and --reverse do not blend well."
msgstr "--contents i --reverse no funcionen bé juntes."
+#: blame.c
msgid "--reverse and --first-parent together require specified latest commit"
msgstr ""
"--reverse i --first-parent junts requereixen una última comissió especificada"
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
+#: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
+#: remote.c sequencer.c submodule.c
msgid "revision walk setup failed"
msgstr "la configuració del recorregut de revisions ha fallat"
+#: blame.c
msgid ""
"--reverse --first-parent together require range along first-parent chain"
msgstr ""
"--reverse --first-parent junts requereixen un rang de la cadena de pares "
"primers"
+#: blame.c
#, c-format
msgid "no such path %s in %s"
msgstr "no hi ha tal camí %s en %s"
+#: blame.c
#, c-format
msgid "cannot read blob %s for path %s"
msgstr "no es pot llegir el blob %s per al camí %s"
+#: branch.c
msgid ""
"cannot inherit upstream tracking configuration of multiple refs when "
"rebasing is requested"
@@ -1680,25 +2118,31 @@ msgstr ""
"no es pot heretar la configuració del seguiment de la font de múltiples "
"referències quan es demana fer «rebase»"
+#: branch.c
#, c-format
msgid "not setting branch '%s' as its own upstream"
msgstr "no s'està establert la branca «%s» com a la seva pròpia font"
+#: branch.c
#, c-format
msgid "branch '%s' set up to track '%s' by rebasing."
msgstr "la branca «%s» està configurada per a seguir «%s» fent «rebase»."
+#: branch.c
#, c-format
msgid "branch '%s' set up to track '%s'."
msgstr "la branca «%s» està configurada per a seguir «%s»."
+#: branch.c
#, c-format
msgid "branch '%s' set up to track:"
msgstr "la branca «%s» està configurada per a seguir:"
+#: branch.c
msgid "unable to write upstream branch configuration"
msgstr "no es pot escriure la configuració de la branca font"
+#: branch.c
msgid ""
"\n"
"After fixing the error cause you may try to fix up\n"
@@ -1708,18 +2152,21 @@ msgstr ""
"Després de corregir la causa de l'error, podeu intentar\n"
"corregir la informació de seguiment remot executant:"
+#: branch.c
#, c-format
msgid "asked to inherit tracking from '%s', but no remote is set"
msgstr ""
"s'ha demanat que hereti el seguiment de «%s», però no s'ha establert cap "
"remot"
+#: branch.c
#, c-format
msgid "asked to inherit tracking from '%s', but no merge configuration is set"
msgstr ""
"s'ha demanat que hereti el seguiment de «%s», però no s'ha establert cap "
"configuració de fusionat"
+#: branch.c
#, c-format
msgid "not tracking: ambiguous information for ref '%s'"
msgstr "no s'està seguint: informació ambigua per a la referència «%s»"
@@ -1735,6 +2182,7 @@ msgstr "no s'està seguint: informació ambigua per a la referència «%s»"
#. you'll probably want to swap the "%s" and leading " " space
#. around.
#.
+#: branch.c object-name.c
#, c-format
msgid " %s\n"
msgstr " %s\n"
@@ -1742,6 +2190,7 @@ msgstr " %s\n"
#. TRANSLATORS: The second argument is a \n-delimited list of
#. duplicate refspecs, composed above.
#.
+#: branch.c
#, c-format
msgid ""
"There are multiple remotes whose fetch refspecs map to the remote\n"
@@ -1762,30 +2211,40 @@ msgstr ""
"els diferents refspecs remots s'assignen a diferents espais de noms\n"
"de seguiment."
+#: branch.c
#, c-format
msgid "'%s' is not a valid branch name"
msgstr "«%s» no és un nom de branca vàlid"
+#: branch.c builtin/branch.c
+msgid "See `man git check-ref-format`"
+msgstr "Vegeu `man git check-ref-format`"
+
+#: branch.c
#, c-format
msgid "a branch named '%s' already exists"
msgstr "ja existeix una branca amb nom «%s»"
+#: branch.c
#, c-format
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»"
+#: branch.c
#, c-format
msgid "cannot set up tracking information; starting point '%s' is not a branch"
msgstr ""
"no es pot configurar la informació de seguiment; el punt inicial «%s» no és "
"una branca"
+#: branch.c
#, c-format
msgid "the requested upstream branch '%s' does not exist"
msgstr "la branca font demanada «%s» no existeix"
+#: branch.c
msgid ""
"\n"
"If you are planning on basing your work on an upstream\n"
@@ -1806,22 +2265,27 @@ msgstr ""
"«git push -u» per a establir la configuració font\n"
"mentre pugeu."
+#: branch.c builtin/replace.c
#, c-format
msgid "not a valid object name: '%s'"
msgstr "no és un nom d'objecte vàlid: «%s»"
+#: branch.c
#, c-format
msgid "ambiguous object name: '%s'"
msgstr "nom d'objecte ambigu: «%s»"
+#: branch.c
#, c-format
msgid "not a valid branch point: '%s'"
msgstr "no és un punt de ramificació vàlid: «%s»"
+#: branch.c
#, c-format
msgid "submodule '%s': unable to find submodule"
msgstr "submòdul «%s»: no es pot trobar el submòdul"
+#: branch.c
#, c-format
msgid ""
"You may try updating the submodules using 'git checkout --no-recurse-"
@@ -1830,108 +2294,131 @@ msgstr ""
"Podeu provar d'actualitzar els submòduls utilitzant «git checkout --no-"
"recurse-submodules %s && git submodule update --init»"
+#: branch.c
#, c-format
msgid "submodule '%s': cannot create branch '%s'"
msgstr "submòdul «%s»: no es pot crear la branca: «%s»"
+#: branch.c
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "«%s» ja s'ha agafat a «%s»"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "«%s» ja s'utilitza en l'arbre de treball a «%s»"
+#: builtin/add.c
msgid "git add [<options>] [--] <pathspec>..."
-msgstr "git add [<opcions>] [--] <especificació-de-camí>..."
+msgstr "git add [<opcions>] [--] <especificació-camí>..."
+#: builtin/add.c
#, c-format
msgid "cannot chmod %cx '%s'"
msgstr "no es pot fer chmod %cx «%s»"
+#: builtin/add.c
msgid "Unstaged changes after refreshing the index:"
msgstr "Canvis «unstaged» després d'actualitzar l'índex:"
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"s'ha eliminat la configuració add.interactive.useBuiltin\n"
-"Per a més detalls, vegeu la seva entrada a «git help config»."
-
-msgid "Could not read the index"
-msgstr "No s'ha pogut llegir l'índex"
-
-msgid "Could not write patch"
-msgstr "No s'ha pogut escriure el pedaç"
+#: builtin/add.c
+msgid "could not read the index"
+msgstr "no s'ha pogut llegir l'índex"
+#: builtin/add.c
msgid "editing patch failed"
msgstr "l'edició del pedaç ha fallat"
+#: builtin/add.c read-cache.c
#, c-format
-msgid "Could not stat '%s'"
-msgstr "No s'ha pogut fer stat a «%s»"
+msgid "could not stat '%s'"
+msgstr "no s'ha pogut fer stat a «%s»"
-msgid "Empty patch. Aborted."
-msgstr "El pedaç és buit. S'ha avortat."
+#: builtin/add.c
+msgid "empty patch. aborted"
+msgstr "pedaç buit. interromput"
+#: builtin/add.c
#, c-format
-msgid "Could not apply '%s'"
-msgstr "No s'ha pogut aplicar «%s»"
+msgid "could not apply '%s'"
+msgstr "no s'ha pogut aplicar «%s»"
+#: builtin/add.c
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
"Els camins següents s'ignoren per un dels vostres fitxers .gitignore:\n"
+#: builtin/add.c builtin/clean.c builtin/fetch.c builtin/mv.c
+#: builtin/prune-packed.c builtin/pull.c builtin/push.c builtin/remote.c
+#: builtin/rm.c builtin/send-pack.c
msgid "dry run"
msgstr "fes una prova"
+#: builtin/add.c builtin/check-ignore.c builtin/commit.c
+#: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
+#: builtin/read-tree.c builtin/refs.c
msgid "be verbose"
msgstr "sigues detallat"
+#: builtin/add.c
msgid "interactive picking"
msgstr "selecció interactiva"
+#: builtin/add.c builtin/checkout.c builtin/reset.c
msgid "select hunks interactively"
msgstr "selecciona els trossos interactivament"
+#: builtin/add.c
msgid "edit current diff and apply"
msgstr "edita la diferència actual i aplica-la"
+#: builtin/add.c
msgid "allow adding otherwise ignored files"
msgstr "permet afegir fitxers que d'altra manera s'ignoren"
+#: builtin/add.c
msgid "update tracked files"
msgstr "actualitza els fitxers seguits"
+#: builtin/add.c
msgid "renormalize EOL of tracked files (implies -u)"
msgstr "torna a normalitzar EOL dels fitxers seguits (implica -u)"
+#: builtin/add.c
msgid "record only the fact that the path will be added later"
msgstr "registra només el fet que el camí s'afegirà més tard"
+#: builtin/add.c
msgid "add changes from all tracked and untracked files"
msgstr "afegeix els canvis de tots els fitxers seguits i no seguits"
+#: builtin/add.c
msgid "ignore paths removed in the working tree (same as --no-all)"
msgstr ""
"ignora els camins eliminats en l'arbre de treball (el mateix que --no-all)"
+#: builtin/add.c
msgid "don't add, only refresh the index"
msgstr "no afegeixis, només actualitza l'índex"
+#: builtin/add.c
msgid "just skip files which cannot be added because of errors"
msgstr "només omet els fitxers que no es poden afegir a causa d'errors"
+#: builtin/add.c
msgid "check if - even missing - files are ignored in dry run"
msgstr ""
"comprova si els fitxers, fins i tot els absents, s'ignoren en fer una prova"
+#: builtin/add.c builtin/mv.c builtin/rm.c
msgid "allow updating entries outside of the sparse-checkout cone"
msgstr "permet actualitzar les entrades fora del con del «sparse-checkout»"
+#: builtin/add.c builtin/update-index.c
msgid "override the executable bit of the listed files"
msgstr "sobreescriu el bit executable dels fitxers llistats"
+#: builtin/add.c
msgid "warn when adding an embedded repository"
msgstr "avisa'm quan s'afegeixi un repositori incrustat"
+#: builtin/add.c
#, c-format
msgid ""
"You've added another git repository inside your current repository.\n"
@@ -1962,158 +2449,197 @@ msgstr ""
"\n"
"Vegeu «git help submodule» per a més informació."
+#: builtin/add.c
#, c-format
msgid "adding embedded git repository: %s"
msgstr "s'està afegint un repositori incrustat: %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 ""
-"Utilitzeu -f si realment voleu afegir-los.\n"
-"Desactiveu aquest missatge executant\n"
-"«git config advice.addIgnoredFile false»"
+#: builtin/add.c
+msgid "Use -f if you really want to add them."
+msgstr "\"Useu -f si realment voleu afegir-los."
+#: builtin/add.c
msgid "adding files failed"
msgstr "l'afegiment de fitxers ha fallat"
+#: builtin/add.c
#, c-format
msgid "--chmod param '%s' must be either -x or +x"
msgstr "el paràmetre --chmod «%s» ha de ser o -x o +x"
+#: builtin/add.c builtin/checkout.c builtin/commit.c builtin/reset.c
+#: builtin/rm.c builtin/stash.c
#, c-format
msgid "'%s' and pathspec arguments cannot be used together"
msgstr "«%s» i l'especificació de camí no es poden usar juntes"
+#: builtin/add.c
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "No s'ha especificat res, no s'ha afegit res.\n"
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Potser voleu dir «git add .»?\n"
-"Desactiveu aquest missatge executant\n"
-"«git config advice.addEmptyPathspec false»"
+#: builtin/add.c
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Que potser volíeu dir «git add.»?"
+#: builtin/add.c builtin/check-ignore.c builtin/checkout.c builtin/clean.c
+#: builtin/commit.c builtin/diff-tree.c builtin/grep.c builtin/mv.c
+#: builtin/reset.c builtin/rm.c builtin/submodule--helper.c read-cache.c
+#: rerere.c submodule.c
msgid "index file corrupt"
msgstr "fitxer d'índex malmès"
+#: builtin/add.c builtin/am.c builtin/checkout.c builtin/clone.c
+#: builtin/commit.c builtin/stash.c merge.c rerere.c
+msgid "unable to write new index file"
+msgstr "no s'ha pogut escriure un fitxer d'índex nou"
+
+#: builtin/am.c builtin/mailinfo.c mailinfo.c
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "acció «%s» incorrecta per a «%s»"
+#: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c builtin/revert.c config.c diff-merges.c gpg-interface.c
+#: ls-refs.c parallel-checkout.c sequencer.c setup.c
#, c-format
msgid "invalid value for '%s': '%s'"
msgstr "valor no vàlid per a «%s»: «%s»"
+#: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
#, c-format
msgid "could not read '%s'"
msgstr "no s'ha pogut llegir «%s»"
+#: builtin/am.c
msgid "could not parse author script"
msgstr "no s'ha pogut analitzar l'script d'autor"
+#: builtin/am.c builtin/replace.c commit.c sequencer.c
#, c-format
msgid "could not parse %s"
msgstr "no s'ha pogut analitzar %s"
+#: builtin/am.c
#, c-format
msgid "'%s' was deleted by the applypatch-msg hook"
msgstr "s'ha suprimit «%s» pel lligam applypatch-msg"
+#: builtin/am.c
#, c-format
msgid "Malformed input line: '%s'."
msgstr "Línia d'entrada mal formada: «%s»."
+#: builtin/am.c
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
msgstr "S'ha produït un error en copiar les notes de «%s» a «%s»"
+#: builtin/am.c
msgid "fseek failed"
msgstr "fseek ha fallat"
+#: builtin/am.c builtin/rebase.c sequencer.c wrapper.c
#, c-format
msgid "could not open '%s' for reading"
msgstr "no s'ha pogut obrir «%s» per a lectura"
+#: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c
#, c-format
msgid "could not open '%s' for writing"
msgstr "no s'ha pogut obrir «%s» per a escriptura"
+#: builtin/am.c
#, c-format
msgid "could not parse patch '%s'"
msgstr "no s'ha pogut analitzar el pedaç «%s»"
+#: builtin/am.c
msgid "Only one StGIT patch series can be applied at once"
msgstr "Només una sèrie de pedaços StGIT es pot aplicar a la vegada"
+#: builtin/am.c
msgid "invalid timestamp"
msgstr "marca de temps no vàlida"
+#: builtin/am.c
msgid "invalid Date line"
msgstr "línia Date no vàlida"
+#: builtin/am.c
msgid "invalid timezone offset"
msgstr "desplaçament del fus horari no vàlid"
+#: builtin/am.c
msgid "Patch format detection failed."
msgstr "La detecció de format de pedaç ha fallat."
+#: builtin/am.c builtin/clone.c
#, c-format
msgid "failed to create directory '%s'"
msgstr "s'ha produït un error en crear el directori «%s»"
+#: builtin/am.c
msgid "Failed to split patches."
msgstr "S'ha produït un error en dividir els pedaços."
+#: builtin/am.c
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Quan hàgiu resolt aquest problema, executeu «%s --continue»."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "Quan hàgiu resolt aquest problema, executeu «%s --continue».\n"
+#: builtin/am.c
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "Si preferiu ometre aquest pedaç, executeu «%s --skip» en lloc d'això."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr ""
+"Si preferiu ometre aquest pedaç, executeu «%s --skip» en lloc d'això.\n"
+#: builtin/am.c
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
"Per a enregistrar un pedaç buit com a comissió buida, executeu «%s --allow-"
-"empty»."
+"empty».\n"
+#: builtin/am.c
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
msgstr ""
"Per a restaurar la branca original i deixar d'apedaçar, executeu «%s --"
"abort»."
+#: builtin/am.c
msgid "Patch sent with format=flowed; space at the end of lines might be lost."
msgstr ""
"Pedaç enviat amb format=flowed; es pot perdre l'espai al final de les línies."
+#: builtin/am.c
#, c-format
msgid "missing author line in commit %s"
msgstr "manca la línia d'autor en la comissió %s"
+#: builtin/am.c
#, c-format
msgid "invalid ident line: %.*s"
msgstr "línia d'identitat no vàlida: %.*s"
+#: builtin/am.c builtin/checkout.c builtin/clone.c commit-graph.c
#, c-format
msgid "unable to parse commit %s"
msgstr "no s'ha pogut analitzar la comissió %s"
+#: builtin/am.c
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr ""
"Al repositori li manquen els blobs necessaris per a retrocedir a una fusió "
"de 3 vies."
+#: builtin/am.c
msgid "Using index info to reconstruct a base tree..."
msgstr "S'està usant la informació d'índex per a reconstruir un arbre base..."
+#: builtin/am.c
msgid ""
"Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."
@@ -2121,25 +2647,32 @@ msgstr ""
"Heu editat el vostre pedaç a mà?\n"
"No s'aplica als blobs recordats en el seu índex."
+#: builtin/am.c
msgid "Falling back to patching base and 3-way merge..."
msgstr "S'està retrocedint a apedaçar la base i una fusió de 3 vies..."
+#: builtin/am.c
msgid "Failed to merge in the changes."
msgstr "S'ha produït un error en fusionar els canvis."
+#: builtin/am.c builtin/merge.c sequencer.c
msgid "git write-tree failed to write a tree"
msgstr "git write-tree ha fallat en escriure un arbre"
+#: builtin/am.c
msgid "applying to an empty history"
msgstr "s'està aplicant a una història buida"
+#: builtin/am.c builtin/commit.c builtin/merge.c builtin/replay.c sequencer.c
msgid "failed to write commit object"
msgstr "s'ha produït un error en escriure l'objecte de comissió"
+#: builtin/am.c
#, c-format
msgid "cannot resume: %s does not exist."
msgstr "no es pot reprendre: %s no existeix."
+#: builtin/am.c
msgid "Commit Body is:"
msgstr "El cos de la comissió és:"
@@ -2147,48 +2680,60 @@ msgstr "El cos de la comissió és:"
#. in your translation. The program will only accept English
#. input at this point.
#.
+#: builtin/am.c
#, c-format
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "
msgstr ""
"Voleu aplicar-lo? [y]es/[n]o/[e]dita/[v]isualitza el pedaç/[a]ccepta'ls "
"tots: "
+#: builtin/am.c builtin/commit.c
msgid "unable to write index file"
msgstr "no s'ha pogut escriure el fitxer d'índex"
+#: builtin/am.c
#, c-format
msgid "Dirty index: cannot apply patches (dirty: %s)"
msgstr "Ãndex brut: no es poden aplicar pedaços (bruts: %s)"
+#: builtin/am.c
#, c-format
msgid "Skipping: %.*s"
msgstr "S'està ometent: %.*s"
+#: builtin/am.c
#, c-format
msgid "Creating an empty commit: %.*s"
msgstr "S'està creant una comissió buida: %.*s"
+#: builtin/am.c
msgid "Patch is empty."
msgstr "El pedaç està buit."
+#: builtin/am.c
#, c-format
msgid "Applying: %.*s"
msgstr "S'està aplicant: %.*s"
+#: builtin/am.c
msgid "No changes -- Patch already applied."
msgstr "Sense canvis -- El pedaç ja s'ha aplicat."
+#: builtin/am.c
#, c-format
msgid "Patch failed at %s %.*s"
msgstr "El pedaç ha fallat a %s %.*s"
+#: builtin/am.c
msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
msgstr ""
"Useu «git am --show-current-patch=diff» per a veure el pedaç que ha fallat"
+#: builtin/am.c
msgid "No changes - recorded it as an empty commit."
msgstr "No hi ha canvis - enregistrat com una comissió buida."
+#: builtin/am.c
msgid ""
"No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
@@ -2198,6 +2743,7 @@ msgstr ""
"Si no hi ha res per a fer «stage», probablement alguna altra cosa ja ha\n"
"introduït els mateixos canvis; potser voleu ometre aquest pedaç."
+#: builtin/am.c
msgid ""
"You still have unmerged paths in your index.\n"
"You should 'git add' each file with resolved conflicts to mark them as "
@@ -2210,16 +2756,16 @@ msgstr ""
"Podeu executar «git rm» en un fitxer per a acceptar «suprimit per ells» pel "
"fitxer."
-msgid "unable to write new index file"
-msgstr "no s'ha pogut escriure un fitxer d'índex nou"
-
+#: builtin/am.c builtin/reset.c
#, c-format
msgid "Could not parse object '%s'."
msgstr "No s'ha pogut analitzar l'objecte «%s»."
+#: builtin/am.c
msgid "failed to clean index"
msgstr "s'ha produït un error en netejar l'índex"
+#: builtin/am.c
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
@@ -2227,113 +2773,155 @@ msgstr ""
"Sembla que heu mogut HEAD després de l'última fallada de «am».\n"
"No s'està rebobinant a ORIG_HEAD"
+#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c
#, c-format
msgid "failed to read '%s'"
msgstr "s'ha produït un error en llegir «%s»"
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "les opcions «%s=%s» i «%s=%s» no es poden usar juntes"
-
+#: builtin/am.c
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<opcions>] [(<bústia> | <directori-de-correu>)...]"
+#: builtin/am.c
msgid "git am [<options>] (--continue | --skip | --abort)"
msgstr "git am [<opcions>] (--continue | --skip | --abort)"
+#: builtin/am.c
msgid "run interactively"
msgstr "executa interactivament"
+#: builtin/am.c
msgid "bypass pre-applypatch and applypatch-msg hooks"
msgstr "evita els lligams pre-applypatch i applypatch-msg"
+#: builtin/am.c
msgid "historical option -- no-op"
msgstr "opció històrica -- no-op"
+#: builtin/am.c
msgid "allow fall back on 3way merging if needed"
msgstr "permet retrocedir a una fusió de 3 vies si és necessari"
+#: builtin/am.c builtin/init-db.c builtin/prune-packed.c builtin/repack.c
+#: builtin/stash.c
msgid "be quiet"
msgstr "silenciós"
+#: builtin/am.c
msgid "add a Signed-off-by trailer to the commit message"
msgstr "afegeix un «trailer» tipus «Signed-off-by» al missatge de comissió"
+#: builtin/am.c
msgid "recode into utf8 (default)"
msgstr "recodifica en utf8 (per defecte)"
+#: builtin/am.c
msgid "pass -k flag to git-mailinfo"
msgstr "passa l'indicador -k a git-mailinfo"
+#: builtin/am.c
msgid "pass -b flag to git-mailinfo"
msgstr "passa l'indicador -b a git-mailinfo"
+#: builtin/am.c
msgid "pass -m flag to git-mailinfo"
msgstr "passa l'indicador -m a git-mailinfo"
+#: builtin/am.c
msgid "pass --keep-cr flag to git-mailsplit for mbox format"
msgstr "passa l'indicador --keep-cr a git-mailsplit per al format mbox"
+#: builtin/am.c
msgid "strip everything before a scissors line"
msgstr "elimina tot abans d'una línia de tisores"
+#: builtin/am.c
msgid "pass it through git-mailinfo"
msgstr "passa-ho a través del git-mailinfo"
+#: builtin/am.c
msgid "pass it through git-apply"
msgstr "passa-ho a través de git-apply"
+#: builtin/am.c builtin/commit.c builtin/fmt-merge-msg.c builtin/grep.c
+#: builtin/merge.c builtin/pull.c builtin/rebase.c builtin/repack.c
+#: builtin/show-branch.c builtin/show-ref.c builtin/tag.c parse-options.h
msgid "n"
msgstr "n"
+#: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
+#: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
+#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
msgid "format"
msgstr "format"
+#: builtin/am.c
msgid "format the patch(es) are in"
msgstr "el format en el qual estan els pedaços"
+#: builtin/am.c
msgid "override error message when patch failure occurs"
msgstr "sobreescriu el missatge d'error si falla l'aplicació del pedaç"
+#: builtin/am.c
msgid "continue applying patches after resolving a conflict"
msgstr "segueix aplicant pedaços després de resoldre un conflicte"
+#: builtin/am.c
msgid "synonyms for --continue"
msgstr "sinònims de --continue"
+#: builtin/am.c
msgid "skip the current patch"
msgstr "omet el pedaç actual"
+#: builtin/am.c
msgid "restore the original branch and abort the patching operation"
msgstr "restaura la branca original i interromp l'operació d'apedaçament"
+#: builtin/am.c
msgid "abort the patching operation but keep HEAD where it is"
msgstr "interromp l'operació d'apedaçament però manté HEAD on és"
+#: builtin/am.c
msgid "show the patch being applied"
msgstr "mostra el pedaç que s'està aplicant"
+#: builtin/am.c
+msgid "try to apply current patch again"
+msgstr "intenta aplicar el pedaç actual de nou"
+
+#: builtin/am.c
msgid "record the empty patch as an empty commit"
msgstr "registra el pedaç buit com una comissió buida"
+#: builtin/am.c
msgid "lie about committer date"
msgstr "menteix sobre la data del comitent"
+#: builtin/am.c
msgid "use current timestamp for author date"
msgstr "usa la marca de temps actual per a la data d'autor"
+#: builtin/am.c builtin/commit-tree.c builtin/commit.c builtin/merge.c
+#: builtin/pull.c builtin/rebase.c builtin/revert.c builtin/tag.c
msgid "key-id"
msgstr "ID de clau"
+#: builtin/am.c builtin/rebase.c
msgid "GPG-sign commits"
msgstr "signa les comissions amb GPG"
+#: builtin/am.c
msgid "how to handle empty patches"
msgstr "com gestionar les comissions buides"
+#: builtin/am.c
msgid "(internal use for git-rebase)"
msgstr "(ús intern per a git-rebase)"
+#: builtin/am.c
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."
@@ -2341,15 +2929,18 @@ msgstr ""
"Fa molt que l'opció -b/--binary no fa res, i\n"
"s'eliminarà. No l'useu més."
+#: builtin/am.c
msgid "failed to read the index"
msgstr "s'ha produït un error en llegir l'índex"
+#: builtin/am.c
#, c-format
msgid "previous rebase directory %s still exists but mbox given."
msgstr ""
"un directori de «rebase» anterior %s encara existeix però s'ha donat una "
"bústia."
+#: builtin/am.c
#, c-format
msgid ""
"Stray %s directory found.\n"
@@ -2358,91 +2949,112 @@ msgstr ""
"S'ha trobat un directori %s extraviat.\n"
"Useu «git am --abort» per a eliminar-lo."
+#: builtin/am.c
msgid "Resolve operation not in progress, we are not resuming."
msgstr "Una operació de resolució no està en curs; no reprenem."
+#: builtin/am.c
msgid "interactive mode requires patches on the command line"
msgstr "el mode interactiu requereix pedaços a la línia d'ordres"
+#: builtin/apply.c
msgid "git apply [<options>] [<patch>...]"
msgstr "git apply [<opcions>] [<pedaç>...]"
+#: builtin/archive.c diagnose.c
msgid "could not redirect output"
msgstr "no s'ha pogut redirigir la sortida"
-msgid "git archive: Remote with no URL"
-msgstr "git archive: Remot sense URL"
-
+#: builtin/archive.c
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive: s'esperava ACK/NAK, s'ha rebut un paquet de buidatge"
+#: builtin/archive.c
#, c-format
msgid "git archive: NACK %s"
msgstr "git archive: %s NACK"
+#: builtin/archive.c
msgid "git archive: protocol error"
msgstr "git archive: error de protocol"
+#: builtin/archive.c
msgid "git archive: expected a flush"
msgstr "git archive: s'esperava una neteja"
+#: builtin/bisect.c
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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> --term-{old,good}=<term>] [--no-"
+"git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>] [--no-"
"checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]"
+#: builtin/bisect.c
msgid "git bisect (good|bad) [<rev>...]"
-msgstr "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<revisió>...]"
+#: builtin/bisect.c
msgid "git bisect skip [(<rev>|<range>)...]"
-msgstr "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<revisió>|<rang>)...]"
+#: builtin/bisect.c
msgid "git bisect reset [<commit>]"
msgstr "git bisect reset [<comissió>]"
+#: builtin/bisect.c
msgid "git bisect replay <logfile>"
-msgstr "git bisect replay <logfile>"
+msgstr "git bisect replay "
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <ordre>..."
+#: builtin/bisect.c
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <ordre> [<arg>...]"
+#: builtin/bisect.c
#, c-format
msgid "cannot open file '%s' in mode '%s'"
msgstr "no es pot obrir el fitxer «%s» en mode «%s»"
+#: builtin/bisect.c
#, c-format
msgid "could not write to file '%s'"
msgstr "no s'ha pogut escriure el fitxer «%s»"
+#: builtin/bisect.c
#, c-format
msgid "cannot open file '%s' for reading"
msgstr "no es pot obrir «%s» per a lectura"
+#: builtin/bisect.c
#, c-format
msgid "'%s' is not a valid term"
msgstr "«%s» no és un terme vàlid"
+#: builtin/bisect.c
#, c-format
msgid "can't use the builtin command '%s' as a term"
msgstr "no es pot usar l'ordre interna «%s» com a terme"
+#: builtin/bisect.c
#, c-format
msgid "can't change the meaning of the term '%s'"
msgstr "no es pot canviar el significat del terme «%s»"
+#: builtin/bisect.c
msgid "please use two different terms"
msgstr "useu dos termes diferents"
+#: builtin/bisect.c
#, c-format
msgid "We are not bisecting.\n"
msgstr "No estem bisecant.\n"
+#: builtin/bisect.c
#, c-format
msgid "'%s' is not a valid commit"
msgstr "«%s» no és una comissió vàlida"
+#: builtin/bisect.c
#, c-format
msgid ""
"could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
@@ -2450,22 +3062,27 @@ msgstr ""
"no s'ha pogut agafar la HEAD original «%s». Proveu «git bisect reset "
"<comissió>»."
+#: builtin/bisect.c
#, c-format
msgid "Bad bisect_write argument: %s"
msgstr "Argument «bisect_write» incorrecte: %s"
+#: builtin/bisect.c
#, c-format
msgid "couldn't get the oid of the rev '%s'"
msgstr "no s'ha pogut obtenir l'oid de la revisió «%s»"
+#: builtin/bisect.c
#, c-format
msgid "couldn't open the file '%s'"
msgstr "no s'ha pogut obrir el fitxer «%s»"
+#: builtin/bisect.c
#, c-format
msgid "Invalid command: you're currently in a %s/%s bisect"
msgstr "Ordre no vàlida: esteu actualment en una bisecció %s/%s"
+#: builtin/bisect.c
#, c-format
msgid ""
"You need to give me at least one %s and %s revision.\n"
@@ -2474,6 +3091,7 @@ msgstr ""
"Heu de donar com a mínim un %s i una revisió %s.\n"
"Podeu usar «git bisect %s» i «git bisect %s» per a això."
+#: builtin/bisect.c
#, c-format
msgid ""
"You need to start by \"git bisect start\".\n"
@@ -2484,6 +3102,7 @@ msgstr ""
"Heu de donar com a mínim un %s i una revisió %s.\n"
"Podeu usar «git bisect %s» i «git bisect %s» per a això."
+#: builtin/bisect.c
#, c-format
msgid "bisecting only with a %s commit"
msgstr "bisecant amb només una comissió %s"
@@ -2492,12 +3111,15 @@ msgstr "bisecant amb només una comissió %s"
#. translation. The program will only accept English input
#. at this point.
#.
+#: builtin/bisect.c
msgid "Are you sure [Y/n]? "
msgstr "N'esteu segur [Y/n]? "
+#: builtin/bisect.c
msgid "status: waiting for both good and bad commits\n"
msgstr "estat: s'estan esperant les comissions bones i dolentes\n"
+#: 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"
@@ -2507,13 +3129,16 @@ msgstr[1] ""
"estat: s'està esperant una comissió incorrecta, es coneixen %d comissions "
"bones\n"
+#: builtin/bisect.c
msgid "status: waiting for good commit(s), bad commit known\n"
msgstr ""
"estat: s'està esperant comissions bones, es coneix una comissió incorrecta\n"
+#: builtin/bisect.c
msgid "no terms defined"
msgstr "cap terme definit"
+#: builtin/bisect.c
#, c-format
msgid ""
"Your current terms are %s for the old state\n"
@@ -2522,6 +3147,7 @@ msgstr ""
"Els termes actuals són %s per a l'estat antic\n"
"i %s per al nou estat.\n"
+#: builtin/bisect.c
#, c-format
msgid ""
"invalid argument %s for 'git bisect terms'.\n"
@@ -2530,39 +3156,45 @@ msgstr ""
"argument no vàlid %s per a «git bisect terms».\n"
"Les opcions admeses són: --term-good|--term-old i --term-bad|--term-new."
-msgid "revision walk setup failed\n"
-msgstr "la configuració del recorregut de revisions ha fallat\n"
-
+#: builtin/bisect.c
#, c-format
msgid "could not open '%s' for appending"
msgstr "no s'ha pogut obrir «%s» per a afegir-hi"
+#: builtin/bisect.c
msgid "'' is not a valid term"
msgstr "«%s» no és un terme vàlid"
+#: builtin/bisect.c
#, c-format
msgid "unrecognized option: '%s'"
msgstr "opció no reconeguda: «%s»"
+#: builtin/bisect.c
#, c-format
msgid "'%s' does not appear to be a valid revision"
msgstr "«%s» no sembla ser una revisió vàlida"
+#: builtin/bisect.c
msgid "bad HEAD - I need a HEAD"
msgstr "HEAD incorrecte - cal una HEAD"
+#: builtin/bisect.c
#, c-format
msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
msgstr ""
"l'agafament de «%s» ha fallat. Proveu «git bisect start <branca-vàlida>»."
+#: builtin/bisect.c
msgid "bad HEAD - strange symbolic ref"
msgstr "HEAD incorrecte - referència simbòlica estranya"
+#: builtin/bisect.c
#, c-format
msgid "invalid ref: '%s'"
msgstr "referència no és vàlida: «%s»"
+#: builtin/bisect.c
msgid "You need to start by \"git bisect start\"\n"
msgstr "Cal començar per «git bisect start»\n"
@@ -2570,215 +3202,278 @@ msgstr "Cal començar per «git bisect start»\n"
#. translation. The program will only accept English input
#. at this point.
#.
+#: builtin/bisect.c
msgid "Do you want me to do it for you [Y/n]? "
msgstr "Voleu que ho faci per vostè [Y/n]? "
+#: builtin/bisect.c
msgid "Please call `--bisect-state` with at least one argument"
msgstr "Executeu «--bisect-state» amb almenys un argument"
+#: builtin/bisect.c
#, c-format
msgid "'git bisect %s' can take only one argument."
msgstr "«git bisect %s» només pot acceptar un argument."
+#: builtin/bisect.c
#, c-format
msgid "Bad rev input: %s"
msgstr "Entrada amb revisió errònia: %s"
+#: builtin/bisect.c
#, c-format
msgid "Bad rev input (not a commit): %s"
msgstr "Entrada de revisió errònia (no és una comissió): %s"
+#: builtin/bisect.c
msgid "We are not bisecting."
msgstr "No estem bisecant."
+#: builtin/bisect.c
#, c-format
msgid "'%s'?? what are you talking about?"
msgstr "«%s»? Què voleu dir?"
+#: builtin/bisect.c
#, c-format
msgid "cannot read file '%s' for replaying"
msgstr "no es pot llegir «%s» per a reproducció"
+#: builtin/bisect.c
#, c-format
msgid "running %s\n"
msgstr "s'està executant %s\n"
+#: builtin/bisect.c
msgid "bisect run failed: no command provided."
msgstr "ha fallat l'execució de bisect: no s'ha proporcionat cap ordre."
+#: builtin/bisect.c
#, c-format
msgid "unable to verify %s on good revision"
msgstr "no s'ha pogut verificar «%s» en una bona revisió"
+#: builtin/bisect.c
#, c-format
msgid "bogus exit code %d for good revision"
msgstr "codi d'error de sortida %d per a una bona revisió"
+#: builtin/bisect.c
#, c-format
msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
msgstr ""
"l'execució de la de bisecció ha fallat: codi de sortida %d de %s és < 0 o >= "
"128"
+#: builtin/bisect.c
#, c-format
msgid "cannot open file '%s' for writing"
msgstr "no es pot obrir «%s» per a escriptura"
+#: builtin/bisect.c
msgid "bisect run cannot continue any more"
msgstr "l'execució de la bisecció no pot continuar més"
+#: builtin/bisect.c
msgid "bisect run success"
msgstr "execució de bisecció amb èxit"
+#: builtin/bisect.c
msgid "bisect found first bad commit"
msgstr "la bisecció ha trobat una primera comissió errònia"
+#: builtin/bisect.c
#, c-format
msgid "bisect run failed: 'git bisect %s' exited with error code %d"
msgstr ""
"ha fallat l'execució del bisect: «git bisect %s» ha sortit amb el codi "
"d'error %d"
+#: builtin/bisect.c
#, c-format
msgid "'%s' requires either no argument or a commit"
msgstr "«%s» no requereix cap argument ni comissió"
+#: builtin/bisect.c
#, c-format
msgid "'%s' requires 0 or 1 argument"
msgstr "%s requereix 0 o 1 arguments"
+#: builtin/bisect.c
#, c-format
msgid "'%s' requires 0 arguments"
msgstr "«%s» requereix 0 arguments"
+#: builtin/bisect.c
msgid "no logfile given"
msgstr "no s'ha donat cap fitxer de registre"
+#: builtin/bisect.c
#, c-format
msgid "'%s' failed: no command provided."
msgstr "«%s» ha fallat: no s'ha proporcionat cap ordre."
+#: builtin/bisect.c
msgid "need a command"
msgstr "cal una subordre"
+#: builtin/bisect.c builtin/cat-file.c
#, c-format
msgid "unknown command: '%s'"
msgstr "ordre desconeguda: «%s»"
+#: builtin/blame.c
msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
-msgstr "git blame [<opcions>] [<opcions-de-revisió>] [<revisió>] [--] fitxer"
+msgstr "git blame [<opcions>] [<opcions-revisió>] [<revisió>] [--] fitxer"
+#: builtin/blame.c
msgid "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
-msgstr "git annotate [<opcions>] [<rev-opts>] [<rev>] [--] <fitxer>"
+msgstr "git annotate [<opcions>] [<opcions-revisió>] [<rev>] [--] <fitxer>"
+#: builtin/blame.c
msgid "<rev-opts> are documented in git-rev-list(1)"
-msgstr "es documenten les <opcions-de-revisió> en git-rev-list(1)"
+msgstr "es documenten les <opcions-revisió> en git-rev-list(1)"
+#: builtin/blame.c
#, c-format
msgid "expecting a color: %s"
msgstr "s'esperava un color: %s"
+#: builtin/blame.c
msgid "must end with a color"
msgstr "ha d'acabar amb un color"
+#: builtin/blame.c
#, c-format
msgid "cannot find revision %s to ignore"
msgstr "no s'ha pogut trobar la revisió %s a ignorar"
+#: builtin/blame.c
msgid "show blame entries as we find them, incrementally"
msgstr "mostra les entrades «blame» mentre les trobem, incrementalment"
+#: builtin/blame.c
msgid "do not show object names of boundary commits (Default: off)"
msgstr ""
"no mostris els noms d'objectes de les comissions de frontera (per defecte: "
"desactivat)"
+#: builtin/blame.c
msgid "do not treat root commits as boundaries (Default: off)"
msgstr ""
"no tractis les comissions arrel com de frontera (per defecte: desactivat)"
+#: builtin/blame.c
msgid "show work cost statistics"
msgstr "mostra les estadístiques del cost de treball"
+#: builtin/blame.c builtin/checkout.c builtin/clone.c builtin/commit-graph.c
+#: builtin/fetch.c builtin/merge.c builtin/multi-pack-index.c builtin/pull.c
+#: builtin/push.c builtin/remote.c builtin/send-pack.c
msgid "force progress reporting"
msgstr "força l'informe de progrés"
+#: builtin/blame.c
msgid "show output score for blame entries"
msgstr "mostra la puntuació de sortida de les entrades «blame»"
+#: builtin/blame.c
msgid "show original filename (Default: auto)"
msgstr "mostra el nom de fitxer original (per defecte: automàtic)"
+#: builtin/blame.c
msgid "show original linenumber (Default: off)"
msgstr "mostra el número de línia original (per defecte: desactivat)"
+#: builtin/blame.c
msgid "show in a format designed for machine consumption"
msgstr "presenta en un format dissenyat per a ser consumit per una màquina"
+#: builtin/blame.c
msgid "show porcelain format with per-line commit information"
msgstr "mostra en format de porcellana amb informació de comissió per línia"
+#: builtin/blame.c
msgid "use the same output mode as git-annotate (Default: off)"
msgstr ""
"usa el mateix mode de sortida que git-annotate (per defecte: desactivat)"
+#: builtin/blame.c
msgid "show raw timestamp (Default: off)"
msgstr "mostra la marca de temps en cru (per defecte: desactivat)"
+#: builtin/blame.c
msgid "show long commit SHA1 (Default: off)"
msgstr "mostra l'SHA1 de la comissió en format llarg (per defecte: desactivat)"
+#: builtin/blame.c
msgid "suppress author name and timestamp (Default: off)"
msgstr "omet el nom d'autor i la marca de temps (per defecte: desactivat)"
+#: builtin/blame.c
msgid "show author email instead of name (Default: off)"
msgstr ""
"mostra el correu electrònic de l'autor en comptes del nom (per defecte: "
"desactivat)"
+#: builtin/blame.c
msgid "ignore whitespace differences"
msgstr "ignora les diferències d'espai en blanc"
+#: builtin/blame.c builtin/log.c
msgid "rev"
msgstr "rev"
+#: builtin/blame.c
msgid "ignore <rev> when blaming"
-msgstr "ignora <rev> en fer «blame»"
+msgstr "ignora ñ- en fer «blame»"
+#: builtin/blame.c
msgid "ignore revisions from <file>"
msgstr "ignora les revisions de <fitxer>"
+#: builtin/blame.c
msgid "color redundant metadata from previous line differently"
msgstr ""
"acoloreix les metadades redundants de la línia anterior de manera diferent"
+#: builtin/blame.c
msgid "color lines by age"
msgstr "acoloreix les línies per antiguitat"
+#: builtin/blame.c
msgid "spend extra cycles to find better match"
msgstr "gasta cicles extres per a trobar una coincidència millor"
+#: builtin/blame.c
msgid "use revisions from <file> instead of calling git-rev-list"
msgstr "usa les revisions de <fitxer> en lloc d'invocar git-rev-list"
+#: builtin/blame.c
msgid "use <file>'s contents as the final image"
msgstr "usa els continguts de <fitxer> com a la imatge final"
+#: builtin/blame.c
msgid "score"
msgstr "puntuació"
+#: builtin/blame.c
msgid "find line copies within and across files"
msgstr "troba còpies de línia dins i a través dels fitxers"
+#: builtin/blame.c
msgid "find line movements within and across files"
msgstr "troba moviments de línia dins i a través dels fitxers"
+#: builtin/blame.c
msgid "range"
msgstr "rang"
+#: builtin/blame.c
msgid "process only line range <start>,<end> or function :<funcname>"
-msgstr "processa només el rang <start>,<end> o la funció :<funcname>"
+msgstr "processa només el rang <inici>,<final> o la funció :<nom-funció>"
+#: builtin/blame.c
msgid "--progress can't be used with --incremental or porcelain formats"
msgstr ""
"no es pot usar --progress amb els formats --incremental o de porcellana"
@@ -2791,21 +3486,26 @@ msgstr ""
#. your language may need more or fewer display
#. columns.
#.
+#: builtin/blame.c
msgid "4 years, 11 months ago"
msgstr "fa 4 anys i 11 mesos"
+#: builtin/blame.c
#, c-format
msgid "file %s has only %lu line"
msgid_plural "file %s has only %lu lines"
msgstr[0] "el fitxer %s té només %lu línia"
msgstr[1] "el fitxer %s té només %lu línies"
+#: builtin/blame.c
msgid "Blaming lines"
msgstr "S'està fent un «blame»"
+#: builtin/branch.c
msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
msgstr "git branch [<opcions>] [-r | -a] [--merged | --no-merged]"
+#: builtin/branch.c
msgid ""
"git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
"point>]"
@@ -2813,68 +3513,83 @@ msgstr ""
"git branch [<opcions>] [-f] [--recurse-submodules] <branch-name> [<start-"
"point>]"
+#: builtin/branch.c
msgid "git branch [<options>] [-l] [<pattern>...]"
msgstr "git branch [<opcions>] [-l] [<patró>...]"
+#: builtin/branch.c
msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..."
msgstr "git branch [<opcions>] [-r] (-d | -D) <nom-de-branca>..."
+#: builtin/branch.c
msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
msgstr "git branch [<opcions>] (-m | -M) [<branca-antiga>] <branca-nova>"
+#: builtin/branch.c
msgid "git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"
msgstr "git branch [<opcions>] (-c | -C) [<branca-antiga>] <branca-nova>"
+#: builtin/branch.c
msgid "git branch [<options>] [-r | -a] [--points-at]"
msgstr "git branch [<opcions>] [-r | -a] [--points-at]"
+#: builtin/branch.c
msgid "git branch [<options>] [-r | -a] [--format]"
msgstr "git branch [<opcions>] [-r | -a] [--format]"
+#: builtin/branch.c
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
-"s'està suprimint la branca «%s» que s'ha\n"
-" fusionat a «%s», però encara no\n"
-" s'ha fusionat a HEAD."
+"s'està suprimint la branca «%s» que s'ha fusionat a\n"
+" «%s», però encara no s'ha fusionat a HEAD"
+#: builtin/branch.c
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
-"no s'està suprimint la branca «%s» que encara no\n"
-" s'ha fusionat a «%s», encara que està\n"
-" fusionada a HEAD."
+"no s'està suprimint la branca «%s» que encara no s'ha fusionat a\n"
+" «%s», encara que s'hagi fusionat a HEAD"
+#: builtin/branch.c
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "No s'ha pogut trobar l'objecte de comissió de «%s»"
+msgid "couldn't look up commit object for '%s'"
+msgstr "no s'ha pogut cercar l'objecte de comissió per a «%s»"
+#: builtin/branch.c
#, 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 ""
-"La branca «%s» no està totalment fusionada.\n"
-"Si esteu segur que la voleu suprimir, executeu «git branch -D %s»."
+msgid "the branch '%s' is not fully merged"
+msgstr "la branca «%s» no està completament fusionada"
+
+#: builtin/branch.c
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "Si esteu segur que voleu suprimir-la, executeu «git branch -D %s»"
-msgid "Update of config-file failed"
-msgstr "L'actualització del fitxer de configuració ha fallat"
+#: builtin/branch.c
+msgid "update of config-file failed"
+msgstr "ha fallat l'actualització del fitxer de configuració"
+#: builtin/branch.c
msgid "cannot use -a with -d"
msgstr "no es pot usar -a amb -d"
+#: builtin/branch.c
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "No es pot suprimir la branca «%s» agafada a «%s»"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"no es pot suprimir la branca «%s» utilitzada per l'arbre de treball a «%s»"
+#: builtin/branch.c
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "no s'ha trobat la branca amb seguiment remot «%s»."
+msgid "remote-tracking branch '%s' not found"
+msgstr "no s'ha trobat la branca de seguiment remot «%s»"
+#: builtin/branch.c
#, c-format
msgid ""
"branch '%s' not found.\n"
@@ -2883,198 +3598,257 @@ msgstr ""
"no s'ha trobat la branca «%s».\n"
"Us heu oblidat de --remote?"
+#: builtin/branch.c
#, c-format
-msgid "branch '%s' not found."
-msgstr "no s'ha trobat la branca «%s»."
+msgid "branch '%s' not found"
+msgstr "no s'ha trobat la branca «%s»"
+#: builtin/branch.c
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
msgstr "S'ha suprimit la branca amb seguiment remot %s (era %s).\n"
+#: builtin/branch.c
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "S'ha suprimit la branca %s (era %s).\n"
+#: builtin/branch.c builtin/tag.c
msgid "unable to parse format string"
msgstr "no s'ha pogut analitzar la cadena de format"
+#: builtin/branch.c
msgid "could not resolve HEAD"
msgstr "no s'ha pogut resoldre HEAD"
+#: builtin/branch.c
#, c-format
msgid "HEAD (%s) points outside of refs/heads/"
msgstr "HEAD (%s) apunta fora de refs/heads/"
+#: builtin/branch.c
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "S'està fent «rebase» en la branca %s a %s"
+msgid "branch %s is being rebased at %s"
+msgstr "a la branca %s se li està fent a «rebase» a %s"
+#: builtin/branch.c
#, c-format
-msgid "Branch %s is being bisected at %s"
-msgstr "La branca %s s'està bisecant a %s"
+msgid "branch %s is being bisected at %s"
+msgstr "la branca %s s'està bisecant a %s"
+#: builtin/branch.c
#, c-format
msgid "HEAD of working tree %s is not updated"
msgstr "HEAD de l'arbre de treball %s no està actualitzat"
+#: builtin/branch.c
#, c-format
-msgid "Invalid branch name: '%s'"
-msgstr "Nom de branca no vàlid: «%s»"
+msgid "invalid branch name: '%s'"
+msgstr "el nom de la branca no és vàlid: «%s»"
+#: builtin/branch.c
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Encara no hi ha cap comissió en la branca «%s»."
+msgid "no commit on branch '%s' yet"
+msgstr "encara no hi ha cap comissió a la branca «%s»"
+#: builtin/branch.c
#, c-format
-msgid "No branch named '%s'."
-msgstr "No hi ha cap branca amb nom «%s»."
+msgid "no branch named '%s'"
+msgstr "no hi ha cap branca anomenada «%s»"
-msgid "Branch rename failed"
-msgstr "El canvi de nom de branca ha fallat"
+#: builtin/branch.c
+msgid "branch rename failed"
+msgstr "ha fallat el canvi de nom de la branca"
-msgid "Branch copy failed"
-msgstr "La còpia de la branca ha fallat"
+#: builtin/branch.c
+msgid "branch copy failed"
+msgstr "ha fallat la còpia de la branca"
+#: builtin/branch.c
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "S'ha creat una còpia d'una branca mal anomenada «%s»"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "s'ha creat una còpia d'una branca mal anomenada «%s»"
+#: builtin/branch.c
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "S'ha canviat el nom de la branca mal anomenada «%s»"
+msgid "renamed a misnamed branch '%s' away"
+msgstr "s'ha canviat el nom d'una branca «%s» mal anomenada"
+#: builtin/branch.c
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "S'ha canviat el nom de la branca a %s, però HEAD no està actualitzat!"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "s'ha canviat el nom de la branca a %s, però HEAD no s'ha actualitzat"
-msgid "Branch is renamed, but update of config-file failed"
+#: builtin/branch.c
+msgid "branch is renamed, but update of config-file failed"
msgstr ""
-"La branca està canviada de nom, però l'actualització del fitxer de "
-"configuració ha fallat"
+"s'ha canviat el nom de la branca, però ha fallat l'actualització del fitxer "
+"de configuració"
-msgid "Branch is copied, but update of config-file failed"
+#: builtin/branch.c
+msgid "branch is copied, but update of config-file failed"
msgstr ""
-"La branca està copiada, però l'actualització del fitxer de configuració ha "
-"fallat"
+"s'ha copiat la branca, però ha fallat l'actualització del fitxer de "
+"configuració"
+#: builtin/branch.c
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Editeu la descripció de la branca\n"
" %s\n"
-"S'eliminaran les línies que comencin amb «%c».\n"
+"S'eliminaran les línies que comencin amb «%s».\n"
+"\"\n"
+#: builtin/branch.c
msgid "Generic options"
msgstr "Opcions genèriques"
+#: builtin/branch.c
msgid "show hash and subject, give twice for upstream branch"
msgstr "mostra el hash i l'assumpte, useu-lo dues vegades per a la branca font"
+#: builtin/branch.c
msgid "suppress informational messages"
msgstr "omet els missatges informatius"
+#: builtin/branch.c builtin/checkout.c builtin/submodule--helper.c
msgid "set branch tracking configuration"
msgstr "estableix la configuració del seguiment de la branca"
+#: builtin/branch.c
msgid "do not use"
msgstr "no usar"
+#: builtin/branch.c
msgid "upstream"
msgstr "font"
+#: builtin/branch.c
msgid "change the upstream info"
msgstr "canvia la informació de font"
+#: builtin/branch.c
msgid "unset the upstream info"
msgstr "treu la informació de la font"
+#: builtin/branch.c
msgid "use colored output"
msgstr "usa sortida amb colors"
+#: builtin/branch.c
msgid "act on remote-tracking branches"
msgstr "actua en branques amb seguiment remot"
+#: builtin/branch.c
msgid "print only branches that contain the commit"
msgstr "imprimeix només les branques que continguin la comissió"
+#: builtin/branch.c
msgid "print only branches that don't contain the commit"
msgstr "imprimeix només les branques que no continguin la comissió"
+#: builtin/branch.c
msgid "Specific git-branch actions:"
msgstr "Accions de git-branch específiques:"
+#: builtin/branch.c
msgid "list both remote-tracking and local branches"
msgstr "llista les branques amb seguiment remot i les locals"
+#: builtin/branch.c
msgid "delete fully merged branch"
msgstr "suprimeix la branca si està completament fusionada"
+#: builtin/branch.c
msgid "delete branch (even if not merged)"
msgstr "suprimeix la branca (encara que no estigui fusionada)"
+#: builtin/branch.c
msgid "move/rename a branch and its reflog"
-msgstr "mou/canvia de nom una branca i el seu registre de referència"
+msgstr "mou/canvia de nom una branca i el seu registre de referències"
+#: builtin/branch.c
msgid "move/rename a branch, even if target exists"
msgstr "mou/canvia de nom una branca, encara que el destí existeixi"
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
msgid "do not output a newline after empty formatted refs"
msgstr "no emetis cap línia nova després de refs amb format buit"
+#: builtin/branch.c
msgid "copy a branch and its reflog"
-msgstr "copia una branca i el seu registre de referència"
+msgstr "copia una branca i el seu registre de referències"
+#: builtin/branch.c
msgid "copy a branch, even if target exists"
msgstr "copia una branca, encara que el destí existeixi"
+#: builtin/branch.c
msgid "list branch names"
msgstr "llista els noms de branca"
+#: builtin/branch.c
msgid "show current branch name"
msgstr "mostra el nom de la branca actual"
+#: builtin/branch.c builtin/submodule--helper.c
msgid "create the branch's reflog"
-msgstr "crea el registre de referència de la branca"
+msgstr "crea el registre de referències de la branca"
+#: builtin/branch.c
msgid "edit the description for the branch"
msgstr "edita la descripció de la branca"
+#: builtin/branch.c
msgid "force creation, move/rename, deletion"
msgstr "força creació, moviment/canvi de nom, supressió"
+#: builtin/branch.c
msgid "print only branches that are merged"
msgstr "imprimeix només les branques que s'han fusionat"
+#: builtin/branch.c
msgid "print only branches that are not merged"
msgstr "imprimeix només les branques que no s'han fusionat"
+#: builtin/branch.c
msgid "list branches in columns"
msgstr "llista les branques en columnes"
+#: builtin/branch.c builtin/for-each-ref.c builtin/notes.c builtin/tag.c
msgid "object"
msgstr "objecte"
+#: builtin/branch.c
msgid "print only branches of the object"
msgstr "imprimeix només les branques de l'objecte"
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
msgid "sorting and filtering are case insensitive"
msgstr "ordenació i filtratge distingeixen entre majúscules i minúscules"
+#: builtin/branch.c builtin/ls-files.c
msgid "recurse through submodules"
msgstr "inclou recursivament els submòduls"
+#: builtin/branch.c builtin/for-each-ref.c builtin/ls-files.c builtin/ls-tree.c
+#: builtin/tag.c builtin/verify-tag.c
msgid "format to use for the output"
msgstr "format a usar en la sortida"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "S'ha produït un error en resoldre HEAD com a referència vàlida."
+#: builtin/branch.c
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "no s'ha pogut resoldre HEAD com a referència vàlida"
+#: builtin/branch.c builtin/clone.c
msgid "HEAD not found below refs/heads!"
msgstr "HEAD no trobat sota refs/heads!"
+#: builtin/branch.c
msgid ""
"branch with --recurse-submodules can only be used if submodule."
"propagateBranches is enabled"
@@ -3082,96 +3856,122 @@ msgstr ""
"la branca amb --recurse-submodules només es pot utilitzar si submodule."
"propagateBranches està habilitat"
+#: builtin/branch.c
msgid "--recurse-submodules can only be used to create branches"
msgstr "--recurse-submodules només es pot utilitzar per a crear branques"
+#: builtin/branch.c
msgid "branch name required"
msgstr "cal el nom de branca"
-msgid "Cannot give description to detached HEAD"
-msgstr "No es pot donar descripció a una HEAD separada"
+#: builtin/branch.c
+msgid "cannot give description to detached HEAD"
+msgstr "no s'ha pogut donar la descripció al HEAD separat"
+#: builtin/branch.c
msgid "cannot edit description of more than one branch"
msgstr "no es pot editar la descripció de més d'una branca"
-msgid "cannot copy the current branch while not on any."
-msgstr "no es pot copiar branca actual mentre no s'és a cap."
+#: builtin/branch.c
+msgid "cannot copy the current branch while not on any"
+msgstr "no es pot copiar la branca actual mentre no pertanyi a cap"
-msgid "cannot rename the current branch while not on any."
-msgstr "no es pot canviar el nom de la branca actual mentre no s'és a cap."
+#: builtin/branch.c
+msgid "cannot rename the current branch while not on any"
+msgstr ""
+"no s'ha pogut canviar el nom de la branca actual mentre no pertanyi a cap"
+#: builtin/branch.c
msgid "too many branches for a copy operation"
msgstr "hi ha massa branques per a una operació de còpia"
+#: builtin/branch.c
msgid "too many arguments for a rename operation"
msgstr "hi ha massa arguments per a una operació de canvi de nom"
+#: builtin/branch.c
msgid "too many arguments to set new upstream"
msgstr "hi ha massa arguments per a establir una nova font"
+#: builtin/branch.c
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
-"no s'ha pogut establir la font de HEAD com a %s quan no assenyala cap branca."
+"no s'ha pogut configurar la font de HEAD a %s quan no apunta a cap branca"
+#: builtin/branch.c
#, c-format
msgid "no such branch '%s'"
msgstr "no existeix la branca «%s»"
+#: builtin/branch.c
#, c-format
msgid "branch '%s' does not exist"
msgstr "la branca «%s» no existeix"
+#: builtin/branch.c
msgid "too many arguments to unset upstream"
msgstr "hi ha massa arguments per a desassignar la font"
-msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr ""
-"no s'ha pogut desassignar la font de HEAD perquè no assenyala cap branca."
+#: builtin/branch.c
+msgid "could not unset upstream of HEAD when it does not point to any branch"
+msgstr "no s'ha pogut desassignar la font del HEAD quan no apunta a cap branca"
+#: builtin/branch.c
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "La branca «%s» no té informació de font"
+msgid "branch '%s' has no upstream information"
+msgstr "la branca «%s» no té informació de la font"
+#: builtin/branch.c
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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 ""
-"Les opcions -a i -r a «git branch» no prenen un nom de branca.\n"
-"Volíeu usar -a|-r --list <patró>?"
+"les opcions -a, i -r, a «git branch» no prenen un nom de branca.\n"
+"Volíeu utilitzar: -a|-r --list <patró>?"
+#: builtin/branch.c
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
-"l'opció --set-upstream ja no s'admet. En lloc seu, useu «--track» o «--set-"
-"upstream-to»."
+"l'opció «--set-upstream» ja no és admesa. Utilitzeu en comptes «--track» o "
+"«--set-upstream-to»"
+#: builtin/bugreport.c
msgid "git version:\n"
msgstr "versió de git:\n"
+#: builtin/bugreport.c
#, c-format
msgid "uname() failed with error '%s' (%d)\n"
msgstr "uname() ha fallat amb l'error «%s» (%d)\n"
+#: builtin/bugreport.c
msgid "compiler info: "
msgstr "informació del compilador: "
+#: builtin/bugreport.c
msgid "libc info: "
msgstr "informació de la libc: "
+#: builtin/bugreport.c
msgid "not run from a git repository - no hooks to show\n"
msgstr ""
"no s'està executant en un repositori de git - no hi ha lligams a mostrar\n"
+#: builtin/bugreport.c
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <camí>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
+#: builtin/bugreport.c
msgid ""
"Thank you for filling out a Git bug report!\n"
"Please answer the following questions to help us understand your issue.\n"
@@ -3205,42 +4005,59 @@ msgstr ""
"Reviseu la resta de l'informe d'error de sota.\n"
"Podeu eliminar qualsevol línia que vulgueu.\n"
+#: builtin/bugreport.c builtin/commit.c builtin/fast-export.c builtin/rebase.c
+#: parse-options.h
msgid "mode"
msgstr "mode"
+#: builtin/bugreport.c
msgid ""
"create an additional zip archive of detailed diagnostics (default 'stats')"
msgstr ""
"crea un arxiu zip addicional amb diagnòstics detallats (per defecte «stats»)"
+#: builtin/bugreport.c
msgid "specify a destination for the bugreport file(s)"
msgstr "especifiqueu una destinació per al fitxer de l'informe d'error"
+#: builtin/bugreport.c
msgid "specify a strftime format suffix for the filename(s)"
msgstr "especifiqueu un sufix en format strftime per al nom de fitxer"
+#: builtin/bugreport.c
+#, c-format
+msgid "unknown argument `%s'"
+msgstr "argument desconegut «%s»"
+
+#: builtin/bugreport.c builtin/diagnose.c
#, c-format
msgid "could not create leading directories for '%s'"
msgstr "no s'han pogut crear els directoris principals de «%s»"
+#: builtin/bugreport.c builtin/diagnose.c
#, c-format
msgid "unable to create diagnostics archive %s"
msgstr "no s'ha pogut crear l'arxiu de diagnòstic %s"
+#: builtin/bugreport.c
msgid "System Info"
msgstr "Informació del sistema"
+#: builtin/bugreport.c
msgid "Enabled Hooks"
msgstr "Habilita els lligams"
+#: builtin/bugreport.c
#, c-format
msgid "unable to write to %s"
msgstr "no s'ha pogut escriure a %s"
+#: builtin/bugreport.c
#, c-format
msgid "Created new report at '%s'.\n"
msgstr "S'ha creat un nou informe a «%s».\n"
+#: builtin/bundle.c
msgid ""
"git bundle create [-q | --quiet | --progress]\n"
" [--version=<version>] <file> <git-rev-list-args>"
@@ -3248,83 +4065,120 @@ msgstr ""
"git bundle create [-q | --quiet | --progress]\n"
" [--version=<versió>] <fitxer> <git-rev-list-args>"
+#: builtin/bundle.c
msgid "git bundle verify [-q | --quiet] <file>"
msgstr "git bundle verify [-q | --quiet] <fitxer>"
+#: builtin/bundle.c
msgid "git bundle list-heads <file> [<refname>...]"
-msgstr "git bundle list-heads <fitxer> [<refname>...]"
+msgstr "git bundle list-heads <fitxer> [<nom-referència>...]"
+#: builtin/bundle.c
msgid "git bundle unbundle [--progress] <file> [<refname>...]"
-msgstr "git bundle unbundle [--progress] <fitxer> [<refname>...]"
+msgstr "git bundle unbundle [--progress] <fitxer> [<nom-referència>...]"
+#: builtin/bundle.c
msgid "need a <file> argument"
msgstr "necessita un argument <fitxer>"
+#: builtin/bundle.c builtin/pack-objects.c
msgid "do not show progress meter"
msgstr "no mostris l'indicador de progrés"
+#: builtin/bundle.c builtin/pack-objects.c
msgid "show progress meter"
msgstr "mostra l'indicador de progrés"
+#: builtin/bundle.c
msgid "historical; same as --progress"
msgstr "històric; el mateix que --progress"
+#: builtin/bundle.c
msgid "historical; does nothing"
msgstr "històric; no fa res"
+#: builtin/bundle.c
msgid "specify bundle format version"
msgstr "especifica la versió del format del farcell"
+#: builtin/bundle.c
msgid "Need a repository to create a bundle."
msgstr "Cal un repositori per a crear un farcell."
+#: builtin/bundle.c
msgid "do not show bundle details"
msgstr "no mostris els detalls del farcell"
+#: builtin/bundle.c bundle.c
+msgid "need a repository to verify a bundle"
+msgstr "cal un repositori per a verificar un farcell"
+
+#: builtin/bundle.c
#, c-format
msgid "%s is okay\n"
msgstr "%s està bé\n"
+#: builtin/bundle.c
msgid "Need a repository to unbundle."
msgstr "Cal un repositori per a desfer un farcell."
+#: builtin/bundle.c
msgid "Unbundling objects"
msgstr "S'estan desagrupant objectes"
+#: builtin/cat-file.c merge-recursive.c
#, c-format
msgid "cannot read object %s '%s'"
msgstr "no es pot llegir l'objecte %s «%s»"
+#: builtin/cat-file.c
msgid "flush is only for --buffer mode"
msgstr "flush només és per al mode --buffer"
+#: builtin/cat-file.c
msgid "empty command in input"
msgstr "ordre buida en l'entrada"
+#: builtin/cat-file.c
#, c-format
msgid "whitespace before command: '%s'"
msgstr "espai en blanc abans de l'ordre: «%s»"
+#: builtin/cat-file.c
#, c-format
msgid "%s requires arguments"
msgstr "%s requereix arguments"
+#: builtin/cat-file.c
#, c-format
msgid "%s takes no arguments"
-msgstr "%s no accepta cap valor"
+msgstr "%s no accepta arguments"
+#: builtin/cat-file.c
msgid "only one batch option may be specified"
msgstr "només es pot especificar una opció per lots"
+#: builtin/cat-file.c
msgid "git cat-file <type> <object>"
msgstr "git cat-file <tipus> <objecte>"
+#: builtin/cat-file.c
msgid "git cat-file (-e | -p) <object>"
msgstr "git cat-file (-e | -p) <objecte>"
+#: builtin/cat-file.c
msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <objecte>"
+#: builtin/cat-file.c
+msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+
+#: builtin/cat-file.c
msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
@@ -3336,121 +4190,147 @@ msgstr ""
" [--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"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
-
+#: builtin/cat-file.c
msgid "Check object existence or emit object contents"
msgstr "Comprova l'existència de l'objecte o emet el contingut de l'objecte"
+#: builtin/cat-file.c
msgid "check if <object> exists"
msgstr "comprova si <objecte> existeix"
+#: builtin/cat-file.c
msgid "pretty-print <object> content"
msgstr "impressió embellida del contingut de l'<objecte>"
+#: builtin/cat-file.c
msgid "Emit [broken] object attributes"
msgstr "Emet els atributs [broken] de l'objecte"
+#: builtin/cat-file.c
msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
msgstr ""
"mostra el tipus d'objecte (un dels següents: «blob», «tree», «commit», "
"«tag», ...)"
+#: builtin/cat-file.c
msgid "show object size"
msgstr "mostra la mida de l'objecte"
+#: builtin/cat-file.c
msgid "allow -s and -t to work with broken/corrupt objects"
msgstr "permet que -s i -t funcionin amb objectes trencats/malmesos"
+#: builtin/cat-file.c builtin/log.c
msgid "use mail map file"
msgstr "usa el fitxer de mapa de correu"
+#: builtin/cat-file.c
msgid "Batch objects requested on stdin (or --batch-all-objects)"
msgstr "Objectes de lots sol·licitats a stdin (o --batch-all-objects)"
+#: builtin/cat-file.c
msgid "show full <object> or <rev> contents"
msgstr "mostra el contingut complet de <objecte> o <rev>"
+#: builtin/cat-file.c
msgid "like --batch, but don't emit <contents>"
msgstr "com a --batch, però no emetis <contents>"
+#: builtin/cat-file.c
msgid "stdin is NUL-terminated"
msgstr "l'entrada és acabada amb NUL"
+#: builtin/cat-file.c
msgid "stdin and stdout is NUL-terminated"
msgstr "stdin i stdout estan terminats amb NUL"
+#: builtin/cat-file.c
msgid "read commands from stdin"
msgstr "llegeix les ordres de stdin"
+#: builtin/cat-file.c
msgid "with --batch[-check]: ignores stdin, batches all known objects"
msgstr ""
"amb --batch[-check]: ignora stdin, posa en lots tots els objectes coneguts"
+#: builtin/cat-file.c
msgid "Change or optimize batch output"
msgstr "Canvia o optimitza la sortida per lots"
+#: builtin/cat-file.c
msgid "buffer --batch output"
msgstr "posa la sortida de --batch en memòria intermèdia"
+#: builtin/cat-file.c
msgid "follow in-tree symlinks"
msgstr "segueix els enllaços simbòlics en l'arbre"
+#: builtin/cat-file.c
msgid "do not order objects before emitting them"
msgstr "no ordenis els objectes abans d'emetre'ls"
+#: builtin/cat-file.c
msgid ""
"Emit object (blob or tree) with conversion or filter (stand-alone, or with "
"batch)"
msgstr ""
"Emet l'objecte (blob o arbre) amb conversió o filtre (stand-alone, o amb lot)"
+#: builtin/cat-file.c
msgid "run textconv on object's content"
msgstr "executar textconv al contingut de l'objecte"
+#: builtin/cat-file.c
msgid "run filters on object's content"
msgstr "executa els filtres al contingut de l'objecte"
+#: builtin/cat-file.c
msgid "blob|tree"
msgstr "blob|tree"
+#: builtin/cat-file.c
msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
msgstr "useu un <camí> per a (--textconv | --filters); no amb «batch»"
+#: builtin/cat-file.c
#, c-format
msgid "'%s=<%s>' needs '%s' or '%s'"
msgstr "«%s=<%s>» necessita «%s» o «%s»"
+#: builtin/cat-file.c
msgid "path|tree-ish"
msgstr "path|tree-ish"
+#: builtin/cat-file.c
#, c-format
msgid "'%s' requires a batch mode"
msgstr "«%s» requereix un mode batch"
+#: builtin/cat-file.c
#, c-format
msgid "'-%c' is incompatible with batch mode"
msgstr "«-%c» és incompatible amb el model batch"
+#: builtin/cat-file.c
msgid "batch modes take no arguments"
msgstr "el mode batch no accepta cap argument"
+#: builtin/cat-file.c
#, c-format
msgid "<rev> required with '%s'"
msgstr "<rev> requerida amb «%s»"
+#: builtin/cat-file.c
#, c-format
msgid "<object> required with '-%c'"
msgstr "<objecte> requerit amb «-%c»"
+#: builtin/cat-file.c
#, c-format
msgid "only two arguments allowed in <type> <object> mode, not %d"
msgstr "només es permeten dos arguments en el mode <tipus> <objecte>, no %d"
+#: builtin/check-attr.c
msgid ""
"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
"<pathname>..."
@@ -3458,194 +4338,269 @@ msgstr ""
"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
"<pathname>..."
+#: builtin/check-attr.c
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 "informa de tots els atributs establerts en el fitxer"
+#: builtin/check-attr.c
msgid "use .gitattributes only from the index"
msgstr "usa .gitattributes només des de l'índex"
+#: builtin/check-attr.c builtin/check-ignore.c builtin/hash-object.c
msgid "read file names from stdin"
msgstr "llegeix els noms de fitxer de stdin"
+#: builtin/check-attr.c builtin/check-ignore.c
msgid "terminate input and output records by a NUL character"
msgstr "acaba els registres d'entrada i de sortida amb un caràcter NUL"
+#: builtin/check-attr.c
msgid "<tree-ish>"
msgstr "<tree-ish>"
+#: builtin/check-attr.c
msgid "which tree-ish to check attributes at"
msgstr "a quin tree-ish s'han de comprovar els atributs"
+#: builtin/check-ignore.c builtin/checkout.c builtin/gc.c builtin/worktree.c
msgid "suppress progress reporting"
msgstr "omet els informes de progrés"
+#: builtin/check-ignore.c
msgid "show non-matching input paths"
msgstr "mostra els camins d'entrada que no coincideixin"
+#: builtin/check-ignore.c
msgid "ignore index when checking"
msgstr "ignora l'índex en comprovar"
+#: builtin/check-ignore.c
msgid "cannot specify pathnames with --stdin"
msgstr "no es poden especificar noms de camí amb --stdin"
+#: builtin/check-ignore.c
msgid "-z only makes sense with --stdin"
msgstr "-z només té sentit amb --stdin"
+#: builtin/check-ignore.c
msgid "no path specified"
msgstr "cap camí especificat"
+#: builtin/check-ignore.c
msgid "--quiet is only valid with a single pathname"
msgstr "--quiet només és vàlid amb un sol nom de camí"
+#: builtin/check-ignore.c
msgid "cannot have both --quiet and --verbose"
msgstr "no es poden especificar --quiet i --verbose alhora"
+#: builtin/check-ignore.c
msgid "--non-matching is only valid with --verbose"
msgstr "--non-matching és vàlid només amb --verbose"
+#: builtin/check-mailmap.c
msgid "git check-mailmap [<options>] <contact>..."
msgstr "git check-mailmap [<opcions>] <contacte>..."
+#: builtin/check-mailmap.c
msgid "also read contacts from stdin"
msgstr "també llegeix els contactes des de stdin"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "no s'ha pogut analitzar el contacte: %s"
+# no traduïsc mailmap
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from file"
+msgstr "llegeix les entrades mailmap addicionals del fitxer"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "blob"
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "llegeix entrades mailmap addicionals del blob"
+
+#: builtin/check-mailmap.c
msgid "no contacts specified"
msgstr "no hi ha contactes especificats"
+#: builtin/checkout--worker.c
msgid "git checkout--worker [<options>]"
msgstr "git checkout--worker [<opcions>]"
+#: builtin/checkout--worker.c builtin/checkout-index.c builtin/column.c
+#: builtin/submodule--helper.c builtin/worktree.c
msgid "string"
msgstr "cadena"
+#: builtin/checkout--worker.c builtin/checkout-index.c
msgid "when creating files, prepend <string>"
msgstr "en crear fitxers, anteposa <cadena>"
+#: builtin/checkout-index.c
msgid "git checkout-index [<options>] [--] [<file>...]"
msgstr "git checkout-index [<opcions>] [--] [<fitxer>...]"
+#: builtin/checkout-index.c
msgid "stage should be between 1 and 3 or all"
msgstr "«stage» ha de ser entre 1 i 3 o all"
+#: builtin/checkout-index.c
msgid "check out all files in the index"
msgstr "agafa tots els fitxers en l'índex"
+#: builtin/checkout-index.c
msgid "do not skip files with skip-worktree set"
msgstr "no ometis els fitxers amb skip-worktree establert"
+#: builtin/checkout-index.c
msgid "force overwrite of existing files"
msgstr "força la sobreescriptura de fitxers existents"
+#: builtin/checkout-index.c
msgid "no warning for existing files and files not in index"
msgstr ""
"cap advertència per a fitxers existents i fitxers que no siguin a l'índex"
+#: builtin/checkout-index.c
msgid "don't checkout new files"
msgstr "no agafis fitxers nous"
+#: builtin/checkout-index.c
msgid "update stat information in the index file"
msgstr "actualitza la informació d'estadístiques en el fitxer d'índex"
+#: builtin/checkout-index.c
msgid "read list of paths from the standard input"
msgstr "llegeix la llista de camins des de l'entrada estàndard"
+#: builtin/checkout-index.c
msgid "write the content to temporary files"
msgstr "escriu el contingut a fitxers temporals"
+#: builtin/checkout-index.c
msgid "copy out the files from named stage"
msgstr "copia els fitxers des de «stage» amb nom"
+#: builtin/checkout.c
msgid "git checkout [<options>] <branch>"
msgstr "git checkout [<opcions>] <branca>"
+#: builtin/checkout.c
msgid "git checkout [<options>] [<branch>] -- <file>..."
msgstr "git checkout [<opcions>] [<branca>] -- <fitxer>..."
+#: builtin/checkout.c
msgid "git switch [<options>] [<branch>]"
msgstr "git switch [<opcions>] [<branca>]"
+#: builtin/checkout.c
msgid "git restore [<options>] [--source=<branch>] <file>..."
msgstr "git restore [<opcions>] [--source=<branca>] <fitxer>..."
+#: builtin/checkout.c
#, c-format
msgid "path '%s' does not have our version"
msgstr "el camí «%s» no té la nostra versió"
+#: builtin/checkout.c
#, c-format
msgid "path '%s' does not have their version"
msgstr "el camí «%s» no té la seva versió"
+#: builtin/checkout.c
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "el camí «%s» no té totes les versions necessàries"
+#: builtin/checkout.c
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "el camí «%s» no té les versions necessàries"
+#: builtin/checkout.c
#, c-format
msgid "path '%s': cannot merge"
msgstr "camí «%s»: no es pot fusionar"
+#: builtin/checkout.c
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "No s'ha pogut afegir el resultat de fusió per a «%s»"
+#: builtin/checkout.c
#, c-format
msgid "Recreated %d merge conflict"
msgid_plural "Recreated %d merge conflicts"
msgstr[0] "Recreat un conflicte de fusió"
msgstr[1] "Recreats %d conflictes de fusió"
+#: builtin/checkout.c
#, c-format
msgid "Updated %d path from %s"
msgid_plural "Updated %d paths from %s"
-msgstr[0] "S'ha actualitzat %d camí des de %s"
-msgstr[1] "S'han actualitzat %d camins des de %s"
+msgstr[0] "S'ha actualitzat %d camí a partir de %s"
+msgstr[1] "S'han actualitzat %d camins a partir de %s"
+#: builtin/checkout.c
#, c-format
msgid "Updated %d path from the index"
msgid_plural "Updated %d paths from the index"
-msgstr[0] "S'ha actualitzat un camí des de l'índex"
-msgstr[1] "S'ha actualitzat %d camins des de l'índex"
+msgstr[0] "S'ha actualitzat %d camí a partir de l'índex"
+msgstr[1] "S'han actualitzat %d camins a partir de l'índex"
+#: builtin/checkout.c
#, c-format
msgid "'%s' cannot be used with updating paths"
msgstr "«%s» no es pot usar amb actualització de camins"
+#: builtin/checkout.c
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
msgstr ""
"No es poden actualitzar els camins i canviar a la branca «%s» a la vegada."
+#: builtin/checkout.c
#, c-format
msgid "neither '%s' or '%s' is specified"
msgstr "no s'ha especificat ni «%s» ni «%s»"
+#: builtin/checkout.c
#, c-format
msgid "'%s' must be used when '%s' is not specified"
msgstr "«%s» s'ha d'utilitzar quan no s'especifica «%s»"
+#: builtin/checkout.c
#, c-format
msgid "'%s' or '%s' cannot be used with %s"
msgstr "«%s» o «%s» no poden utilitzar-se amb %s"
+#: builtin/checkout.c
+#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "«%s», «%s» o «%s» no es poden utilitzar en agafar un arbre"
+
+#: builtin/checkout.c
#, c-format
msgid "path '%s' is unmerged"
msgstr "el camí «%s» està sense fusionar"
+#: builtin/checkout.c builtin/grep.c builtin/merge-tree.c builtin/reset.c
+#: merge-ort.c reset.c sequencer.c tree-walk.c
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "no s'ha pogut llegir l'arbre (%s)"
+
+#: builtin/checkout.c
msgid "you need to resolve your current index first"
msgstr "heu de primer resoldre el vostre índex actual"
+#: builtin/checkout.c
#, c-format
msgid ""
"cannot continue with staged changes in the following files:\n"
@@ -3654,40 +4609,50 @@ msgstr ""
"no es pot continuar amb els canvis «staged» als fitxers següents:\n"
"%s"
+#: builtin/checkout.c
#, c-format
msgid "Can not do reflog for '%s': %s\n"
-msgstr "No es pot fer reflog per a «%s»: %s\n"
+msgstr "No es pot fer «reflog» per a «%s»: %s\n"
+#: builtin/checkout.c
msgid "HEAD is now at"
msgstr "HEAD ara és a"
+#: builtin/checkout.c builtin/clone.c
msgid "unable to update HEAD"
msgstr "no s'ha pogut actualitzar HEAD"
+#: builtin/checkout.c
#, c-format
msgid "Reset branch '%s'\n"
msgstr "Restableix la branca «%s»\n"
+#: builtin/checkout.c
#, c-format
msgid "Already on '%s'\n"
msgstr "Ja esteu en «%s»\n"
+#: builtin/checkout.c
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "S'ha canviat i restablert a la branca «%s»\n"
+#: builtin/checkout.c
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "S'ha canviat a la branca nova «%s»\n"
+#: builtin/checkout.c
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "S'ha canviat a la branca «%s»\n"
+#: builtin/checkout.c
#, c-format
msgid " ... and %d more.\n"
msgstr " ... i %d més.\n"
+#: builtin/checkout.c
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -3710,6 +4675,7 @@ msgstr[1] ""
"\n"
"%s\n"
+#: builtin/checkout.c
#, c-format
msgid ""
"If you want to keep it by creating a new branch, this may be a good time\n"
@@ -3736,15 +4702,19 @@ msgstr[1] ""
" git branch <nom-de-branca-nova> %s\n"
"\n"
+#: builtin/checkout.c
msgid "internal error in revision walk"
msgstr "error intern en el passeig per revisions"
+#: builtin/checkout.c
msgid "Previous HEAD position was"
msgstr "La posició de HEAD anterior era"
+#: builtin/checkout.c
msgid "You are on a branch yet to be born"
msgstr "Sou en una branca que encara ha de néixer"
+#: builtin/checkout.c
#, c-format
msgid ""
"'%s' could be both a local file and a tracking branch.\n"
@@ -3753,6 +4723,7 @@ msgstr ""
"«%s» podria ser tant un fitxer local com una branca de seguiment.\n"
"Useu -- (i opcionalment --no-guess) per a desambiguar-ho"
+#: builtin/checkout.c
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"
@@ -3772,47 +4743,58 @@ msgstr ""
"remota, p. ex. «origin» al remot, considereu configurar l'opció\n"
"checkout.defaultRemote=origin en la vostra configuració."
+#: builtin/checkout.c
#, c-format
msgid "'%s' matched multiple (%d) remote tracking branches"
msgstr "«%s» coincideixen múltiples (%d) branques de seguiment remotes"
+#: builtin/checkout.c
msgid "only one reference expected"
msgstr "només s'esperava una referència"
+#: builtin/checkout.c
#, c-format
msgid "only one reference expected, %d given."
msgstr "s'esperava només una referència, s'han donat %d."
+#: builtin/checkout.c builtin/worktree.c
#, c-format
msgid "invalid reference: %s"
msgstr "referència no vàlida: %s"
+#: builtin/checkout.c
#, c-format
msgid "reference is not a tree: %s"
msgstr "la referència no és un arbre: %s"
+#: builtin/checkout.c
#, c-format
msgid "a branch is expected, got tag '%s'"
msgstr "s'espera una branca, s'ha obtingut l'etiqueta «%s»"
+#: builtin/checkout.c
#, c-format
msgid "a branch is expected, got remote branch '%s'"
msgstr "s'espera una branca, s'ha obtingut la branca remota «%s»"
+#: builtin/checkout.c
#, c-format
msgid "a branch is expected, got '%s'"
msgstr "s'espera una branca, s'ha obtingut «%s»"
+#: builtin/checkout.c
#, c-format
msgid "a branch is expected, got commit '%s'"
msgstr "s'espera una branca, s'ha obtingut la comissió «%s»"
+#: builtin/checkout.c
msgid ""
"If you want to detach HEAD at the commit, try again with the --detach option."
msgstr ""
"Si voleu desacoblar HEAD a la comissió, torneu-ho a provar amb l'opció --"
"detach."
+#: builtin/checkout.c
msgid ""
"cannot switch branch while merging\n"
"Consider \"git merge --quit\" or \"git worktree add\"."
@@ -3820,6 +4802,7 @@ msgstr ""
"no es pot canviar de branca mentre es fusiona\n"
"Considereu usar «git merge --quit» o «git worktree add»."
+#: builtin/checkout.c
msgid ""
"cannot switch branch in the middle of an am session\n"
"Consider \"git am --quit\" or \"git worktree add\"."
@@ -3827,6 +4810,7 @@ msgstr ""
"no es pot canviar de branca en mig d'una sessió «am»\n"
"Considereu usar «git am --quit» o «git worktree add»."
+#: builtin/checkout.c
msgid ""
"cannot switch branch while rebasing\n"
"Consider \"git rebase --quit\" or \"git worktree add\"."
@@ -3834,6 +4818,7 @@ msgstr ""
"no es pot canviar de branca mentre es fa «rebase»\n"
"Considereu usar «git rebase --quit» o «git worktree add»."
+#: builtin/checkout.c
msgid ""
"cannot switch branch while cherry-picking\n"
"Consider \"git cherry-pick --quit\" or \"git worktree add\"."
@@ -3841,6 +4826,7 @@ msgstr ""
"no es pot canviar de branca mentre es fa «cherry-pick»\n"
"Considereu usar «git cherry-pick --quit» o «git worktree add»."
+#: builtin/checkout.c
msgid ""
"cannot switch branch while reverting\n"
"Consider \"git revert --quit\" or \"git worktree add\"."
@@ -3848,95 +4834,133 @@ msgstr ""
"no es pot canviar de branca mentre s'està revertint\n"
"Considereu «git revert --quit» o «git worktree add»."
+#: builtin/checkout.c
msgid "you are switching branch while bisecting"
msgstr "s'està canviant la branca mentre es fa una bisecció"
+#: builtin/checkout.c
msgid "paths cannot be used with switching branches"
msgstr "els camins no es poden usar amb canvi de branca"
+#: builtin/checkout.c
#, c-format
msgid "'%s' cannot be used with switching branches"
msgstr "«%s» no es pot usar amb canvi de branca"
+# és com si faltara un objecte directe per a agafar
+#: builtin/checkout.c
+#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "«%s» necessita els camins per a agafar"
+
+#: builtin/checkout.c
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "«%s» no es pot usar amb «%s»"
+#: builtin/checkout.c
#, c-format
msgid "'%s' cannot take <start-point>"
msgstr "«%s» no pot prendre <start-point>"
+#: builtin/checkout.c
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr "No es pot canviar la branca a la no comissió «%s»"
+#: builtin/checkout.c
msgid "missing branch or commit argument"
msgstr "manca branca o argument de comissió"
+#: builtin/checkout.c
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "estil de conflicte desconegut «%s»"
+
+#: builtin/checkout.c
msgid "perform a 3-way merge with the new branch"
msgstr "realitza una fusió de 3 vies amb la branca nova"
+#: builtin/checkout.c builtin/log.c parse-options.h
msgid "style"
msgstr "estil"
+#: builtin/checkout.c
msgid "conflict style (merge, diff3, or zdiff3)"
msgstr "estil de conflicte (merge, diff3, o zdiff3)"
+#: builtin/checkout.c builtin/worktree.c
msgid "detach HEAD at named commit"
msgstr "separa HEAD a la comissió anomenada"
+#: builtin/checkout.c
msgid "force checkout (throw away local modifications)"
msgstr "agafa a la força (descarta qualsevol modificació local)"
+#: builtin/checkout.c
msgid "new-branch"
msgstr "branca-nova"
-msgid "new unparented branch"
-msgstr "branca òrfena nova"
+#: builtin/checkout.c
+msgid "new unborn branch"
+msgstr "branca no nascuda nova"
+#: builtin/checkout.c builtin/merge.c
msgid "update ignored files (default)"
msgstr "actualitza els fitxers ignorats (per defecte)"
+#: builtin/checkout.c
msgid "do not check if another worktree is holding the given ref"
msgstr "no comprovis si un altre arbre de treball té la referència donada"
+#: builtin/checkout.c
msgid "checkout our version for unmerged files"
msgstr "agafa la versió nostra dels fitxers sense fusionar"
+#: builtin/checkout.c
msgid "checkout their version for unmerged files"
msgstr "agafa la versió seva dels fitxers sense fusionar"
+#: builtin/checkout.c
msgid "do not limit pathspecs to sparse entries only"
msgstr "no limitis les especificacions de camí només a entrades disperses"
+#: builtin/checkout.c
#, c-format
msgid "options '-%c', '-%c', and '%s' cannot be used together"
msgstr "les opcions «-%c», «-%c», i «%s» no es poden usar juntes"
+#: builtin/checkout.c
msgid "--track needs a branch name"
msgstr "--track necessita un nom de branca"
+#: builtin/checkout.c
#, c-format
msgid "missing branch name; try -%c"
msgstr "falta el nom de la branca; proveu -%c"
+#: builtin/checkout.c
#, c-format
msgid "could not resolve %s"
msgstr "no es pot resoldre %s"
+#: builtin/checkout.c
msgid "invalid path specification"
msgstr "especificació de camí no vàlida"
+#: builtin/checkout.c
#, c-format
msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
msgstr ""
"«%s» no és una comissió i la branca «%s» no es pot crear a partir d'aquesta "
"comissió"
+#: builtin/checkout.c
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
msgstr "git checkout: --detach no accepta un argument de camí «%s»"
+#: builtin/checkout.c
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
@@ -3944,54 +4968,72 @@ msgstr ""
"git checkout: --ours/--theirs, --force i --merge són incompatibles en\n"
"agafar de l'índex."
+#: builtin/checkout.c
msgid "you must specify path(s) to restore"
msgstr "heu d'especificar el camí o camins a restaurar"
+#: builtin/checkout.c builtin/clone.c builtin/remote.c builtin/replay.c
+#: builtin/submodule--helper.c builtin/worktree.c
msgid "branch"
msgstr "branca"
+#: builtin/checkout.c
msgid "create and checkout a new branch"
msgstr "crea i agafa una branca nova"
+#: builtin/checkout.c
msgid "create/reset and checkout a branch"
msgstr "crea/restableix i agafa una branca"
+#: builtin/checkout.c
msgid "create reflog for new branch"
-msgstr "crea un registre de referència per a la branca nova"
+msgstr "crea un registre de referències per a la branca nova"
+#: builtin/checkout.c
msgid "second guess 'git checkout <no-such-branch>' (default)"
msgstr "segona deducció «git checkout <no-such-branch>» (per defecte)"
+#: builtin/checkout.c
msgid "use overlay mode (default)"
msgstr "utilitza el mode de superposició (per defecte)"
+#: builtin/checkout.c
msgid "create and switch to a new branch"
msgstr "crea i canvia a una branca nova"
+#: builtin/checkout.c
msgid "create/reset and switch to a branch"
msgstr "crea/restableix i canvia a una branca"
+#: builtin/checkout.c
msgid "second guess 'git switch <no-such-branch>'"
msgstr "segona deducció «git switch <no-such-branch>»"
+#: builtin/checkout.c
msgid "throw away local modifications"
msgstr "descarta les modificacions locals"
+#: builtin/checkout.c
msgid "which tree-ish to checkout from"
msgstr "des de quin arbre agafar"
+#: builtin/checkout.c
msgid "restore the index"
msgstr "restaura l'índex"
+#: builtin/checkout.c
msgid "restore the working tree (default)"
msgstr "restaura l'arbre de treball (per defecte)"
+#: builtin/checkout.c
msgid "ignore unmerged entries"
msgstr "ignora les entrades sense fusionar"
+#: builtin/checkout.c
msgid "use overlay mode"
msgstr "utilitza el mode de superposició"
+#: builtin/clean.c
msgid ""
"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] "
"[<pathspec>...]"
@@ -3999,36 +5041,45 @@ msgstr ""
"git clean [-d] [-f] [-i] [-n] [-q] [-e <patró>] [-x | -X] [--] "
"[<pathspec>...]"
+#: builtin/clean.c
#, c-format
msgid "Removing %s\n"
msgstr "S'està eliminant %s\n"
+#: builtin/clean.c
#, c-format
msgid "Would remove %s\n"
msgstr "Eliminaria %s\n"
+#: builtin/clean.c
#, c-format
msgid "Skipping repository %s\n"
msgstr "S'està ometent el repositori %s\n"
+#: builtin/clean.c
#, c-format
msgid "Would skip repository %s\n"
msgstr "Ometria el repositori %s\n"
+#: builtin/clean.c midx.c
#, c-format
msgid "failed to remove %s"
msgstr "s'ha produït un error en eliminar %s"
+#: builtin/clean.c
#, c-format
msgid "could not lstat %s\n"
msgstr "no s'ha pogut fer lstat %s\n"
+#: builtin/clean.c
msgid "Refusing to remove current working directory\n"
msgstr "S'ha rebutjat suprimir el directori de treball actual\n"
+#: builtin/clean.c
msgid "Would refuse to remove current working directory\n"
msgstr "Es rebutjarà eliminar el directori de treball actual\n"
+#: builtin/clean.c
#, c-format
msgid ""
"Prompt help:\n"
@@ -4041,6 +5092,7 @@ msgstr ""
"foo - selecciona un ítem basat en un prefix únic\n"
" - (buit) no seleccionis res\n"
+#: builtin/clean.c
#, c-format
msgid ""
"Prompt help:\n"
@@ -4061,26 +5113,32 @@ msgstr ""
"* - tria tots els ítems\n"
" - (buit) finalitza la selecció\n"
+#: builtin/clean.c
#, c-format
msgid "Huh (%s)?\n"
msgstr "Perdó (%s)?\n"
+#: builtin/clean.c
#, c-format
msgid "Input ignore patterns>> "
msgstr "Introduïu els patrons a ignorar>> "
+#: builtin/clean.c
#, c-format
msgid "WARNING: Cannot find items matched by: %s"
msgstr "ADVERTÈNCIA: No es poden trobar ítems que coincideixin amb: %s"
+#: builtin/clean.c
msgid "Select items to delete"
msgstr "Selecciona els ítems a suprimir"
#. TRANSLATORS: Make sure to keep [y/N] as is
+#: builtin/clean.c
#, c-format
msgid "Remove %s [y/N]? "
msgstr "Voleu eliminar %s [y/N]? "
+#: builtin/clean.c
msgid ""
"clean - start cleaning\n"
"filter by pattern - exclude items from deletion\n"
@@ -4098,216 +5156,286 @@ msgstr ""
"help - aquesta pantalla\n"
"? - ajuda de selecció manual"
+#: builtin/clean.c
msgid "Would remove the following item:"
msgid_plural "Would remove the following items:"
msgstr[0] "Eliminaria l'ítem següent:"
msgstr[1] "Eliminaria els ítems següents:"
+#: builtin/clean.c
msgid "No more files to clean, exiting."
msgstr "No hi ha més fitxers a netejar; s'està sortint."
+#: builtin/clean.c
msgid "do not print names of files removed"
msgstr "no imprimeixis els noms dels fitxers eliminats"
+#: builtin/clean.c
msgid "force"
msgstr "força"
+#: builtin/clean.c
msgid "interactive cleaning"
msgstr "neteja interactiva"
+#: builtin/clean.c
msgid "remove whole directories"
msgstr "elimina directoris sencers"
+#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c
+#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c
+#: builtin/show-ref.c ref-filter.h
msgid "pattern"
msgstr "patró"
+#: builtin/clean.c
msgid "add <pattern> to ignore rules"
msgstr "afegiu <patró> per a ignorar les regles"
+#: builtin/clean.c
msgid "remove ignored files, too"
msgstr "elimina els fitxers ignorats, també"
+#: builtin/clean.c
msgid "remove only ignored files"
msgstr "elimina només els fitxers ignorats"
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
+#: builtin/clean.c
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"clean.requireForce està establerta en cert i ni -i, -n ni -f s'han indicat; "
-"refusant netejar"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce és per defecte cert i ni -i, -n ni -f s'han indicat; "
-"refusant netejar"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x i -X no es poden usar junts"
+"clean.requireForce està establert a cert i no s'ha indicat -f : es rebutja "
+"netejar"
+#: builtin/clone.c
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<opcions>] [--] <repositori> [<directori>]"
+#: builtin/clone.c
msgid "don't clone shallow repository"
msgstr "no clonis un repositori superficial"
+#: builtin/clone.c
msgid "don't create a checkout"
msgstr "no facis cap agafament"
+#: builtin/clone.c builtin/init-db.c
msgid "create a bare repository"
msgstr "crea un repositori nu"
-msgid "create a mirror repository (implies bare)"
-msgstr "crea un repositori mirall (implica bare)"
+#: builtin/clone.c
+msgid "create a mirror repository (implies --bare)"
+msgstr "crear un repositori mirall (implica --bare)"
+#: builtin/clone.c
msgid "to clone from a local repository"
msgstr "per a clonar des d'un repositori local"
+#: builtin/clone.c
msgid "don't use local hardlinks, always copy"
msgstr "no usis enllaços durs locals, sempre copia"
+#: builtin/clone.c
msgid "setup as shared repository"
msgstr "configura com a repositori compartit"
+#: builtin/clone.c
msgid "pathspec"
msgstr "especificació de camí"
+#: builtin/clone.c
msgid "initialize submodules in the clone"
msgstr "inicialitza els submòduls en el clon"
+#: builtin/clone.c
msgid "number of submodules cloned in parallel"
msgstr "nombre de submòduls clonats en paral·lel"
+#: builtin/clone.c builtin/init-db.c
msgid "template-directory"
msgstr "directori-de-plantilla"
+#: builtin/clone.c builtin/init-db.c
msgid "directory from which templates will be used"
msgstr "directori des del qual s'usaran les plantilles"
+#: builtin/clone.c builtin/submodule--helper.c
msgid "reference repository"
msgstr "repositori de referència"
+#: builtin/clone.c builtin/submodule--helper.c
msgid "use --reference only while cloning"
msgstr "usa --reference només en clonar"
+#: 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 "nom"
+#: builtin/clone.c
msgid "use <name> instead of 'origin' to track upstream"
msgstr "usa <nom> en lloc d'«origin» per a seguir la font"
+#: builtin/clone.c
msgid "checkout <branch> instead of the remote's HEAD"
msgstr "agafa <branca> en lloc de la HEAD del remot"
+#: builtin/clone.c
msgid "path to git-upload-pack on the remote"
msgstr "camí a git-upload-pack en el remot"
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
msgid "depth"
msgstr "profunditat"
+#: builtin/clone.c
msgid "create a shallow clone of that depth"
msgstr "crea un clon superficial d'aquesta profunditat"
+#: builtin/clone.c
msgid "create a shallow clone since a specific time"
msgstr "crea un clon superficial des d'una data específica"
+#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c
+#: builtin/replay.c
msgid "revision"
msgstr "revisió"
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
msgid "deepen history of shallow clone, excluding rev"
msgstr "aprofundeix la història d'un clon superficial, excloent una revisió"
+#: builtin/clone.c builtin/submodule--helper.c
msgid "clone only one branch, HEAD or --branch"
msgstr "clona només una branca, HEAD o --branch"
+#: builtin/clone.c
msgid "don't clone any tags, and make later fetches not to follow them"
msgstr ""
"no cloneu cap etiqueta, i feu que els «fetch» següents no les segueixin"
+#: builtin/clone.c
msgid "any cloned submodules will be shallow"
msgstr "qualsevol submòdul clonat serà superficial"
+#: builtin/clone.c builtin/init-db.c
msgid "gitdir"
msgstr "directori de git"
+#: builtin/clone.c builtin/init-db.c
msgid "separate git dir from working tree"
msgstr "separa el directori de git de l'arbre de treball"
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
+msgid "specify the reference format to use"
+msgstr "especifiqueu el format de referència a usar"
+
+#: builtin/clone.c
msgid "key=value"
msgstr "clau=valor"
+#: builtin/clone.c
msgid "set config inside the new repository"
msgstr "estableix la configuració dins del repositori nou"
+#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
+#: builtin/push.c builtin/send-pack.c
msgid "server-specific"
msgstr "específic al servidor"
+#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
+#: builtin/push.c builtin/send-pack.c
msgid "option to transmit"
msgstr "opció a transmetre"
+#: builtin/clone.c
msgid "apply partial clone filters to submodules"
msgstr "aplica els filtres de clonatge parcial als submòduls"
+#: builtin/clone.c
msgid "any cloned submodules will use their remote-tracking branch"
msgstr "qualsevol submòdul clonat utilitzarà la seva branca de seguiment remot"
+#: builtin/clone.c
msgid "initialize sparse-checkout file to include only files at root"
msgstr ""
"inicialitza el fitxer «sparse-checkout» per a incloure només els fitxers a "
"l'arrel"
+#: builtin/clone.c
msgid "uri"
msgstr "uri"
+#: builtin/clone.c
msgid "a URI for downloading bundles before fetching from origin remote"
msgstr "un URI per a baixar paquets abans d'obtenir des del remot origen"
+#: builtin/clone.c
#, c-format
msgid "info: Could not add alternate for '%s': %s\n"
msgstr "info: No s'ha pogut afegir un alternatiu per a «%s»: %s\n"
+#: builtin/clone.c builtin/diff.c builtin/rm.c grep.c setup.c
#, c-format
msgid "failed to stat '%s'"
msgstr "s'ha produït un error en fer stat a «%s»"
+#: builtin/clone.c
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s existeix i no és directori"
+#: builtin/clone.c
#, c-format
msgid "'%s' is a symlink, refusing to clone with --local"
msgstr "«%s» és un enllaç simbòlic, es rebutja clonar amb --local"
+#: builtin/clone.c
#, c-format
msgid "failed to start iterator over '%s'"
msgstr "no s'ha pogut iniciar l'iterador sobre «%s»"
+#: builtin/clone.c
#, c-format
msgid "symlink '%s' exists, refusing to clone with --local"
msgstr "l'enllaç simbòlic «%s» existeix, es rebutja a clonar amb --local"
+#: builtin/clone.c compat/precompose_utf8.c
#, c-format
msgid "failed to unlink '%s'"
msgstr "s'ha produït un error en desenllaçar «%s»"
+#: builtin/clone.c
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "no es pot comprovar l'enllaç físic en «%s»"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "l'enllaç físic és diferent de la font en «%s»"
+
+#: builtin/clone.c
#, c-format
msgid "failed to create link '%s'"
msgstr "s'ha produït un error en crear l'enllaç «%s»"
+#: builtin/clone.c
#, c-format
msgid "failed to copy file to '%s'"
msgstr "s'ha produït un error en copiar el fitxer a «%s»"
+#: builtin/clone.c refs/files-backend.c
#, c-format
msgid "failed to iterate over '%s'"
msgstr "no s'ha pogut iterar sobre «%s»"
+#: builtin/clone.c
#, c-format
msgid "done.\n"
msgstr "fet.\n"
+#: builtin/clone.c
msgid ""
"Clone succeeded, but checkout failed.\n"
"You can inspect what was checked out with 'git status'\n"
@@ -4317,85 +5445,106 @@ msgstr ""
"Podeu inspeccionar el que s'ha agafat amb «git status»\n"
"i tornar-ho a provar amb «git restore --source=HEAD :/»\n"
+#: builtin/clone.c
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "No s'ha pogut trobar la branca remota %s per a clonar."
+#: builtin/clone.c fetch-pack.c
msgid "remote did not send all necessary objects"
msgstr "el remot no ha enviat tots els objectes necessaris"
+#: builtin/clone.c
#, c-format
msgid "unable to update %s"
msgstr "no s'ha pogut actualitzar %s"
+#: builtin/clone.c
msgid "failed to initialize sparse-checkout"
msgstr "no s'ha pogut inicialitzar «sparse-checkout»"
+#: builtin/clone.c
msgid "remote HEAD refers to nonexistent ref, unable to checkout"
msgstr ""
-"la HEAD remot es refereix a una referència que no existeix, no s'ha pogut "
+"el HEAD remot es refereix a una referència que no existeix, no s'ha pogut "
"agafar"
+#: builtin/clone.c
msgid "unable to checkout working tree"
msgstr "no s'ha pogut agafar l'arbre de treball"
+#: builtin/clone.c
msgid "unable to write parameters to config file"
msgstr "no s'han pogut escriure els paràmetres al fitxer de configuració"
+#: builtin/clone.c
msgid "cannot repack to clean up"
msgstr "no es pot reempaquetar per a netejar"
+#: builtin/clone.c
msgid "cannot unlink temporary alternates file"
msgstr "no es pot desenllaçar el fitxer d'alternatives temporal"
+#: builtin/clone.c
msgid "Too many arguments."
msgstr "Hi ha massa arguments."
+#: builtin/clone.c scalar.c
msgid "You must specify a repository to clone."
msgstr "Heu d'especificar un repositori per a clonar."
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr ""
-"--bundle-uri és incompatible amb --depth, --shallow-since i --shallow-exclude"
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "el format d'emmagatzematge de referència «%s» és desconegut"
+#: builtin/clone.c
#, c-format
msgid "repository '%s' does not exist"
msgstr "el repositori «%s» no existeix"
+#: builtin/clone.c builtin/fetch.c
#, c-format
msgid "depth %s is not a positive number"
msgstr "la profunditat %s no és un nombre positiu"
+#: builtin/clone.c
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "el camí destí «%s» ja existeix i no és un directori buit."
+#: builtin/clone.c
#, c-format
msgid "repository path '%s' already exists and is not an empty directory."
msgstr "el camí destí «%s» ja existeix i no és un directori buit."
+#: builtin/clone.c
#, c-format
msgid "working tree '%s' already exists."
msgstr "l'arbre de treball «%s» ja existeix."
+#: builtin/clone.c builtin/difftool.c builtin/log.c builtin/worktree.c
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "no s'han pogut crear els directoris inicials de «%s»"
+#: builtin/clone.c
#, c-format
msgid "could not create work tree dir '%s'"
msgstr "no s'ha pogut crear el directori d'arbre de treball «%s»"
+#: builtin/clone.c
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "S'està clonant al repositori nu «%s»...\n"
+#: builtin/clone.c
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "S'està clonant a «%s»...\n"
+#: builtin/clone.c
msgid ""
"clone --recursive is not compatible with both --reference and --reference-if-"
"able"
@@ -4403,221 +5552,293 @@ msgstr ""
"clone --recursive no és compatible amb ambdós --reference i --reference-if-"
"able"
+#: builtin/clone.c builtin/remote.c
#, c-format
msgid "'%s' is not a valid remote name"
msgstr "«%s» no és un nom de remot vàlid"
+#: builtin/clone.c
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth s'ignora en els clons locals; useu file:// en lloc d'això."
+#: builtin/clone.c
msgid "--shallow-since is ignored in local clones; use file:// instead."
msgstr ""
"--shallow-since s'ignora en els clons locals; useu file:// en lloc d'això."
+#: builtin/clone.c
msgid "--shallow-exclude is ignored in local clones; use file:// instead."
msgstr ""
"--shallow-exclude s'ignora en els clons locals; useu file:// en lloc d'això."
+#: builtin/clone.c
msgid "--filter is ignored in local clones; use file:// instead."
msgstr "--filter s'ignora en els clons locals; useu file:// en lloc d'això."
+#: builtin/clone.c fetch-pack.c
msgid "source repository is shallow, reject to clone."
msgstr "el repositori font és superficial, es rebutja clonar-ho."
+#: builtin/clone.c
msgid "source repository is shallow, ignoring --local"
msgstr "el repositori font és superficial, s'està ignorant --local"
+#: builtin/clone.c
msgid "--local is ignored"
msgstr "--local s'ignora"
+#: builtin/clone.c
msgid "cannot clone from filtered bundle"
msgstr "no es pot clonar des del farell filtrat"
+#: builtin/clone.c
msgid "failed to initialize the repo, skipping bundle URI"
msgstr "no s'ha pogut inicialitzar el repositori, s'omet l'URI del paquet"
+#: builtin/clone.c
#, c-format
msgid "failed to fetch objects from bundle URI '%s'"
msgstr "no s'han pogut obtenir els objectes de l'URI del paquet «%s»"
+#: builtin/clone.c
msgid "failed to fetch advertised bundles"
msgstr "no s'han pogut obtenir els paquets anunciats"
+#: builtin/clone.c
msgid "remote transport reported error"
msgstr "el transport remot ha informat d'un error"
+#: builtin/clone.c
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "La branca remota %s no es troba en la font %s"
+#: builtin/clone.c
msgid "You appear to have cloned an empty repository."
msgstr "Sembla que heu clonat un repositori buit."
+#: builtin/column.c
msgid "git column [<options>]"
msgstr "git column [<opcions>]"
+#: builtin/column.c
msgid "lookup config vars"
msgstr "cerca les variables de configuració"
+#: builtin/column.c
msgid "layout to use"
msgstr "disposició a usar"
+#: builtin/column.c
msgid "maximum width"
msgstr "amplada màxima"
+#: builtin/column.c
msgid "padding space on left border"
msgstr "espai de farciment al marge esquerre"
+#: builtin/column.c
msgid "padding space on right border"
msgstr "espai de farciment al marge dret"
+#: builtin/column.c
msgid "padding space between columns"
msgstr "espai de farciment entre columnes"
+#: builtin/column.c
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s ha de ser no negatiu"
+
+#: builtin/column.c
msgid "--command must be the first argument"
msgstr "--command ha de ser el primer argument"
+#: builtin/commit-graph.c
msgid ""
"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
msgstr ""
"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
+#: builtin/commit-graph.c
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>"
+" <split-options>"
msgstr ""
"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>"
+" <split-options>"
+#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
msgid "dir"
msgstr "directori"
+#: builtin/commit-graph.c
msgid "the object directory to store the graph"
msgstr "el directori d'objectes a emmagatzemar al graf"
+#: builtin/commit-graph.c
msgid "if the commit-graph is split, only verify the tip file"
msgstr ""
"si el graf de comissions està dividit només, verifica el fitxer de consell"
+#: builtin/commit-graph.c
#, c-format
msgid "Could not open commit-graph '%s'"
msgstr "No s'ha pogut obrir el graf de comissions «%s»"
+#: builtin/commit-graph.c
+#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "no s'ha pogut obrir la cadena «%s» del graf de comissions"
+
+#: builtin/commit-graph.c
#, c-format
msgid "unrecognized --split argument, %s"
msgstr "argument --split no reconegut, %s"
+#: builtin/commit-graph.c
#, c-format
msgid "unexpected non-hex object ID: %s"
msgstr "ID de l'objecte no hexadecimal inesperat: %s"
+#: builtin/commit-graph.c
#, c-format
msgid "invalid object: %s"
msgstr "no és un objecte vàlid: %s"
+#: builtin/commit-graph.c parse-options-cb.c
#, c-format
msgid "option `%s' expects a numerical value"
msgstr "l'opció «%s» espera un valor numèric"
+#: builtin/commit-graph.c
msgid "start walk at all refs"
msgstr "comença el recorregut en totes les referències"
+#: builtin/commit-graph.c
msgid "scan pack-indexes listed by stdin for commits"
msgstr "explora els índexs del paquet llistats per a stdin per a comissions"
+#: builtin/commit-graph.c
msgid "start walk at commits listed by stdin"
msgstr "comença el recorregut per les comissions llistades per stdin"
+#: builtin/commit-graph.c
msgid "include all commits already in the commit-graph file"
msgstr "inclou ja totes les comissions al fitxer del graf de comissions"
+#: builtin/commit-graph.c
msgid "enable computation for changed paths"
msgstr "habilita la computació per als camins canviats"
+#: builtin/commit-graph.c
msgid "allow writing an incremental commit-graph file"
msgstr "permet escriure un fitxer de graf de comissions incrementals"
+#: builtin/commit-graph.c
msgid "maximum number of commits in a non-base split commit-graph"
msgstr ""
"nombre màxim de comissions en un graf de comissions separades sense base"
+#: builtin/commit-graph.c
msgid "maximum ratio between two levels of a split commit-graph"
msgstr "ràtio màxima entre dos nivells d'un graf de comissions dividit"
+#: builtin/commit-graph.c
msgid "only expire files older than a given date-time"
msgstr "fes caducar només els objectes més antics que l'hora i data donades"
+#: builtin/commit-graph.c
msgid "maximum number of changed-path Bloom filters to compute"
-msgstr "nombre màxim de canvis de camí en filtres Bloom a calcular"
+msgstr "nombre màxim de canvis de camí en filtres de Bloom a calcular"
+#: builtin/commit-graph.c
msgid "use at most one of --reachable, --stdin-commits, or --stdin-packs"
-msgstr "usa com a màxim un --reachable, --stdin-commits, o --stdin-packs"
+msgstr "usa com a màxim un entre --reachable, --stdin-commits, o --stdin-packs"
+#: builtin/commit-graph.c
msgid "Collecting commits from input"
msgstr "S'estan recollint les comissions de l'entrada"
+#: builtin/commit-tree.c
msgid "git commit-tree <tree> [(-p <parent>)...]"
-msgstr "git commit-tree <tree> [(-p <pare>)...]"
+msgstr "git commit-tree <arbre> [(-p <pare>)...]"
+#: builtin/commit-tree.c
msgid ""
"git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
" [(-F <file>)...] <tree>"
msgstr ""
"git commit-tree [(-p <pare>)...] [-S[<keyid>]] [(-m <missatge>)...]\n"
-" [(-F <fitxer>)...] <tree>"
+" [(-F <fitxer>)...] <arbre>"
+#: builtin/commit-tree.c
#, c-format
msgid "duplicate parent %s ignored"
msgstr "s'han ignorat el pare %s duplicat"
+#: builtin/commit-tree.c builtin/log.c
#, c-format
msgid "not a valid object name %s"
msgstr "no és un nom d'objecte vàlid %s"
+#: builtin/commit-tree.c
#, c-format
msgid "git commit-tree: failed to read '%s'"
msgstr "git commit-tree: ha fallat en llegir «%s»"
+#: builtin/commit-tree.c
#, c-format
msgid "git commit-tree: failed to close '%s'"
msgstr "git commit-tree: ha fallat en tancar «%s»"
+#: builtin/commit-tree.c
msgid "parent"
msgstr "pare"
+#: builtin/commit-tree.c
msgid "id of a parent commit object"
msgstr "id d'un objecte de comissió pare"
+#: builtin/commit-tree.c builtin/commit.c builtin/merge.c builtin/notes.c
+#: builtin/stash.c builtin/tag.c
msgid "message"
msgstr "missatge"
+#: builtin/commit-tree.c builtin/commit.c
msgid "commit message"
msgstr "missatge de comissió"
+#: builtin/commit-tree.c
msgid "read commit log message from file"
msgstr "llegeix el missatge de registre de comissió des d'un fitxer"
+#: builtin/commit-tree.c builtin/commit.c builtin/merge.c builtin/pull.c
+#: builtin/revert.c
msgid "GPG sign commit"
msgstr "signa la comissió amb GPG"
+#: builtin/commit-tree.c
msgid "must give exactly one tree"
msgstr "ha de donar exactament un arbre"
+#: builtin/commit-tree.c
msgid "git commit-tree: failed to read"
msgstr "git commit-tree: ha fallat en llegir"
+#: builtin/commit.c
msgid ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -4627,17 +5848,19 @@ msgid ""
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <comissió> | --fixup [(amend|"
-"reword):]<comissió>)]\n"
+"reword):]<comissió>]\n"
" [-F <fitxer> | -m <msg>] [--reset-author] [--allow-empty]\n"
-" [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
-" [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+" [--allow-empty-message] [--no-verify] [-e] [--author=<autor>]\n"
+" [--date=<data>] [--cleanup=<mode>] [--[no-]status]\n"
" [-i | -o] [--pathspec-from-file=<fitxer> [--pathspec-file-nul]]\n"
-" [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
-" [--] [<pathspec>...]"
+" [(--trailer <token>[(=|:)<valor>])...] [-S[<id-clau>]]\n"
+" [--] [<especificació-camí>...]"
+#: builtin/commit.c
msgid "git status [<options>] [--] [<pathspec>...]"
msgstr "git status [<opcions>] [--] [<pathspec>...]"
+#: builtin/commit.c
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"
@@ -4647,6 +5870,7 @@ msgstr ""
"deixaria buida. Podeu repetir la vostra ordre amb --allow-empty, o\n"
"podeu eliminar la comissió per complet amb «git reset HEAD^».\n"
+#: builtin/commit.c
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
@@ -4661,12 +5885,15 @@ msgstr ""
" git commit --allow-empty\n"
"\n"
+#: builtin/commit.c
msgid "Otherwise, please use 'git rebase --skip'\n"
msgstr "Altrament, si us plau useu «git rebase --skip»\n"
+#: builtin/commit.c
msgid "Otherwise, please use 'git cherry-pick --skip'\n"
msgstr "Altrament, si us plau useu «git cherry-pick --skip»\n"
+#: builtin/commit.c
msgid ""
"and then use:\n"
"\n"
@@ -4688,60 +5915,74 @@ msgstr ""
" git cherry-pick --skip\n"
"\n"
+#: builtin/commit.c read-cache.c
msgid "updating files failed"
msgstr "s'ha produït un error en actualitzar els fitxers"
+#: builtin/commit.c
msgid "failed to unpack HEAD tree object"
msgstr "s'ha produït un error en desempaquetar l'objecte d'arbre HEAD"
+#: builtin/commit.c
msgid "No paths with --include/--only does not make sense."
msgstr "--include/--only no té sentit sense camí."
+#: builtin/commit.c
msgid "unable to create temporary index"
msgstr "no s'ha pogut crear un índex temporal"
+#: builtin/commit.c
msgid "interactive add failed"
msgstr "l'afegiment interactiu ha fallat"
+#: builtin/commit.c
msgid "unable to update temporary index"
msgstr "no s'ha pogut actualitzar l'índex temporal"
+#: builtin/commit.c
msgid "Failed to update main cache tree"
msgstr "S'ha produït un error en actualitzar l'arbre principal de memòria cau"
-msgid "unable to write new_index file"
-msgstr "no s'ha pogut escriure el fitxer new_index"
-
+#: builtin/commit.c
msgid "cannot do a partial commit during a merge."
msgstr "no es pot fer una comissió parcial durant una fusió."
+#: builtin/commit.c
msgid "cannot do a partial commit during a cherry-pick."
msgstr "no es pot fer una comissió parcial durant un «cherry pick»."
+#: builtin/commit.c
msgid "cannot do a partial commit during a rebase."
msgstr "no es pot fer una comissió parcial durant un «rebase»."
+#: builtin/commit.c
msgid "cannot read the index"
msgstr "no es pot llegir l'índex"
+#: builtin/commit.c
msgid "unable to write temporary index file"
msgstr "no s'ha pogut escriure un fitxer d'índex temporal"
+#: builtin/commit.c
#, c-format
msgid "commit '%s' lacks author header"
msgstr "a la comissió «%s» li manca la capçalera d'autor"
+#: builtin/commit.c
#, c-format
msgid "commit '%s' has malformed author line"
msgstr "la comissió «%s» té una línia d'autor mal formada"
+#: builtin/commit.c
msgid "malformed --author parameter"
msgstr "paràmetre --author mal format"
+#: builtin/commit.c ident.c
#, c-format
msgid "invalid date format: %s"
msgstr "format de data no vàlid: %s"
+#: builtin/commit.c
msgid ""
"unable to select a comment character that is not used\n"
"in the current commit message"
@@ -4749,74 +5990,88 @@ msgstr ""
"no es pot seleccionar un caràcter de comentari que\n"
"no sigui usat en el missatge de comissió actual"
+#: builtin/commit.c
#, c-format
msgid "could not lookup commit '%s'"
msgstr "no s'ha pogut cercar la comissió «%s»"
+#: builtin/commit.c builtin/shortlog.c
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(s'està llegint el missatge de registre des de l'entrada estàndard)\n"
+#: builtin/commit.c
msgid "could not read log from standard input"
msgstr "no s'ha pogut llegir el registre des de l'entrada estàndard"
+#: builtin/commit.c
#, c-format
msgid "could not read log file '%s'"
msgstr "no s'ha pogut llegir el fitxer de registre «%s»"
+#: builtin/commit.c
#, c-format
msgid "options '%s' and '%s:%s' cannot be used together"
msgstr "les opcions «%s» i «%s:%s» no es poden usar juntes"
+#: builtin/commit.c
msgid "could not read SQUASH_MSG"
msgstr "no s'ha pogut llegir SQUASH_MSG"
+#: builtin/commit.c
msgid "could not read MERGE_MSG"
msgstr "no s'ha pogut llegir MERGE_MSG"
+#: builtin/commit.c bundle.c rerere.c sequencer.c
#, c-format
msgid "could not open '%s'"
msgstr "no s'ha pogut obrir «%s»"
+#: builtin/commit.c
msgid "could not write commit template"
msgstr "no s'ha pogut escriure la plantilla de comissió"
+#: builtin/commit.c
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
-"Introduïu el missatge de comissió per als vostres canvis.\n"
-"S'ignoraran les línies que comencin amb «%c».\n"
+"Introduïu el missatge de comissió per als vostres canvis. \n"
+"S'ignoraran les línies que comencin amb «%s».\n"
+#: builtin/commit.c
#, 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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Introduïu el missatge de comissió dels vostres canvis.\n"
-"S'ignoraran les línies que comencin amb «%c». Un missatge de\n"
+"S'ignoraran les línies que comencin amb «%s». Un missatge de\n"
"comissió buit avorta la comissió.\n"
+#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Introduïu el missatge de comissió pels vostres canvis. Es mantindran\n"
-"les línies que comencin amb «%c»; podeu eliminar-les si voleu.\n"
+"les línies que comencin amb «%s»; podeu eliminar-les vosaltres mateixos\n"
+"si voleu.\n"
+#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Introduïu el missatge de comissió dels vostres canvis.\n"
-"Es mantindran les línies que comencin amb «%c»; podeu eliminar-les "
-"vosaltres\n"
-"mateixos si voleu. Un missatge buit avorta la comissió.\n"
+"Es mantindran les línies que comencin amb «%s»; podeu eliminar-les \n"
+"vosaltres mateixos si voleu. Un missatge buit avorta la comissió.\n"
+#: builtin/commit.c
msgid ""
"\n"
"It looks like you may be committing a merge.\n"
@@ -4830,6 +6085,7 @@ msgstr ""
"\tgit update-ref -d MERGE_HEAD\n"
"i intenteu-ho de nou.\n"
+#: builtin/commit.c
msgid ""
"\n"
"It looks like you may be committing a cherry-pick.\n"
@@ -4843,111 +6099,142 @@ msgstr ""
"\tgit update-ref -d CHERRY_PICK_HEAD\n"
"i intenteu-ho de nou.\n"
+#: builtin/commit.c
#, c-format
msgid "%sAuthor: %.*s <%.*s>"
msgstr "%sAutor: %.*s <%.*s>"
+#: builtin/commit.c
#, c-format
msgid "%sDate: %s"
msgstr "%sData: %s"
+#: builtin/commit.c
#, c-format
msgid "%sCommitter: %.*s <%.*s>"
msgstr "%sComitent: %.*s <%.*s>"
+#: builtin/commit.c
msgid "Cannot read index"
msgstr "No es pot llegir l'índex"
+#: builtin/commit.c builtin/tag.c
msgid "unable to pass trailers to --trailers"
msgstr "no s'han pogut passar els «trailers» a --trailers"
+#: builtin/commit.c
msgid "Error building trees"
msgstr "Error en construir els arbres"
+#: builtin/commit.c builtin/tag.c
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "Especifiqueu el missatge usant l'opció -m o l'opció -F.\n"
+#: builtin/commit.c
#, c-format
msgid "--author '%s' is not 'Name <email>' and matches no existing author"
msgstr ""
"--author «%s» no és «Nom <adreça-electrònica>» i no coincideix amb\n"
"cap autor existent"
+#: builtin/commit.c
#, c-format
msgid "Invalid ignored mode '%s'"
msgstr "Mode d'ignorància no vàlid «%s»"
+#: builtin/commit.c
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Mode de fitxers no seguits no vàlid «%s»"
+#: builtin/commit.c
msgid "You are in the middle of a merge -- cannot reword."
msgstr "Esteu enmig d'una fusió -- no es pot fer «reword»."
+#: builtin/commit.c
msgid "You are in the middle of a cherry-pick -- cannot reword."
msgstr "Esteu enmig d'un «cherry pick» -- no es pot fer «reword»."
+#: builtin/commit.c
#, c-format
msgid "reword option of '%s' and path '%s' cannot be used together"
msgstr "les opcions de «reword» «%s» i camí «%s» no es poden usar juntes"
+#: builtin/commit.c
#, c-format
msgid "reword option of '%s' and '%s' cannot be used together"
msgstr "les opcions de «reword» «%s» i «%s» no es poden usar juntes"
+#: builtin/commit.c
msgid "You have nothing to amend."
msgstr "No teniu res a esmenar."
+#: builtin/commit.c
msgid "You are in the middle of a merge -- cannot amend."
msgstr "Esteu enmig d'una fusió -- no es pot esmenar."
+#: builtin/commit.c
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr "Esteu enmig d'un «cherry pick» -- no es pot esmenar."
+#: builtin/commit.c
msgid "You are in the middle of a rebase -- cannot amend."
msgstr "Esteu enmig d'un «rebase» -- no es pot esmenar."
+#: builtin/commit.c
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr "--reset-author només es pot usar amb -C, -c o --amend."
+#: builtin/commit.c
#, c-format
msgid "unknown option: --fixup=%s:%s"
msgstr "opció desconeguda: --fixup=%s:%s"
+#: builtin/commit.c
#, c-format
msgid "paths '%s ...' with -a does not make sense"
msgstr "els camins «%s ...» amb -a no tenen sentit"
+#: builtin/commit.c
msgid "show status concisely"
msgstr "mostra l'estat concisament"
+#: builtin/commit.c
msgid "show branch information"
msgstr "mostra la informació de branca"
+#: builtin/commit.c
msgid "show stash information"
msgstr "mostra la informació de «stash»"
+#: builtin/commit.c
msgid "compute full ahead/behind values"
msgstr "calcula els valors complets endavant/darrere"
+#: builtin/commit.c
msgid "version"
msgstr "versió"
+#: builtin/commit.c builtin/fetch.c builtin/push.c builtin/worktree.c
msgid "machine-readable output"
msgstr "sortida llegible per una màquina"
+#: builtin/commit.c
msgid "show status in long format (default)"
msgstr "mostra l'estat en format llarg (per defecte)"
+#: builtin/commit.c
msgid "terminate entries with NUL"
msgstr "acaba les entrades amb NUL"
+#: builtin/commit.c
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
"mostra els fitxers no seguits, modes opcionals: all, normal, no. (Per "
"defecte: all)"
+#: builtin/commit.c
msgid ""
"show ignored files, optional modes: traditional, matching, no. (Default: "
"traditional)"
@@ -4955,9 +6242,11 @@ msgstr ""
"mostra els fitxers ignorats, modes opcionals: traditional, matching, no. "
"(Per defecte: traditional, matching, no.)"
+#: builtin/commit.c parse-options.h
msgid "when"
msgstr "quan"
+#: builtin/commit.c
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
@@ -4965,340 +6254,433 @@ msgstr ""
"ignora els canvis als submòduls, opcional quan: all, dirty, untracked. (Per "
"defecte: all)"
+#: builtin/commit.c
msgid "list untracked files in columns"
msgstr "mostra els fitxers no seguits en columnes"
+#: builtin/commit.c
msgid "do not detect renames"
msgstr "no detectis canvis de noms"
+#: builtin/commit.c
msgid "detect renames, optionally set similarity index"
msgstr "detecta canvis de noms, i opcionalment estableix un índex de semblança"
+#: builtin/commit.c
msgid "Unsupported combination of ignored and untracked-files arguments"
msgstr ""
"No s'admet la combinació d'arguments d'ignorància i de fitxers no seguits"
+#: builtin/commit.c
msgid "suppress summary after successful commit"
msgstr "omet el resum després d'una comissió reeixida"
+#: builtin/commit.c
msgid "show diff in commit message template"
msgstr "mostra la diferència en la plantilla de missatge de comissió"
+#: builtin/commit.c
msgid "Commit message options"
msgstr "Opcions de missatge de comissió"
+#: builtin/commit.c builtin/merge.c builtin/tag.c
msgid "read message from file"
msgstr "llegeix el missatge des d'un fitxer"
+#: builtin/commit.c
msgid "author"
msgstr "autor"
+#: builtin/commit.c
msgid "override author for commit"
msgstr "sobreescriu l'autor de la comissió"
+#: builtin/commit.c builtin/gc.c
msgid "date"
msgstr "data"
+#: builtin/commit.c
msgid "override date for commit"
msgstr "sobreescriu la data de la comissió"
+#: builtin/commit.c parse-options.h ref-filter.h
msgid "commit"
msgstr "comissió"
+#: builtin/commit.c
msgid "reuse and edit message from specified commit"
msgstr "reusa i edita el missatge de la comissió especificada"
+#: builtin/commit.c
msgid "reuse message from specified commit"
msgstr "reusa el missatge de la comissió especificada"
#. TRANSLATORS: Leave "[(amend|reword):]" as-is,
#. and only translate <commit>.
#.
+#: builtin/commit.c
msgid "[(amend|reword):]commit"
msgstr "[(amend|reword):]commit"
+#: builtin/commit.c
msgid ""
"use autosquash formatted message to fixup or amend/reword specified commit"
msgstr ""
-"usa un missatge amb format de «squash» automàtic per a esmenar la comissió "
-"especificada"
+"usa un missatge amb format de «squash» automàtic per a fer amend/reword de "
+"la comissió especificada"
+#: builtin/commit.c
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
"usa un missatge amb format de «squash» automàtic per a fer «squash» de la "
"comissió especificada"
+#: builtin/commit.c
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr "l'autor de la comissió soc jo ara (s'usa amb -C/-c/--amend)"
+#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c
msgid "trailer"
msgstr "remolc"
+#: builtin/commit.c builtin/tag.c
msgid "add custom trailer(s)"
msgstr "afegeix un «trailer» personalitzat"
+#: builtin/commit.c builtin/log.c builtin/merge.c builtin/pull.c
+#: builtin/revert.c
msgid "add a Signed-off-by trailer"
msgstr "afegeix un «trailer» tipus «Signed-off-by»"
+#: builtin/commit.c
msgid "use specified template file"
msgstr "usa el fitxer de plantilla especificat"
+#: builtin/commit.c
msgid "force edit of commit"
msgstr "força l'edició de la comissió"
+#: builtin/commit.c
msgid "include status in commit message template"
msgstr "inclou l'estat en la plantilla de missatge de comissió"
+#: builtin/commit.c
msgid "Commit contents options"
msgstr "Opcions per al contingut de les comissions"
+#: builtin/commit.c
msgid "commit all changed files"
msgstr "comet tots els fitxers canviats"
+#: builtin/commit.c
msgid "add specified files to index for commit"
msgstr "afegeix els fitxers especificats a l'índex per a cometre"
+#: builtin/commit.c
msgid "interactively add files"
msgstr "afegeix els fitxers interactivament"
+#: builtin/commit.c
msgid "interactively add changes"
msgstr "afegeix els canvis interactivament"
+#: builtin/commit.c
msgid "commit only specified files"
msgstr "comet només els fitxers especificats"
+#: builtin/commit.c
msgid "bypass pre-commit and commit-msg hooks"
msgstr "evita els lligams de precomissió i missatge de comissió"
+#: builtin/commit.c
msgid "show what would be committed"
msgstr "mostra què es cometria"
+#: builtin/commit.c
msgid "amend previous commit"
msgstr "esmena la comissió anterior"
+#: builtin/commit.c
msgid "bypass post-rewrite hook"
msgstr "evita el lligam de post escriptura"
+#: builtin/commit.c
msgid "ok to record an empty change"
msgstr "està bé registrar un canvi buit"
+#: builtin/commit.c
msgid "ok to record a change with an empty message"
msgstr "està bé registrar un canvi amb missatge buit"
+#: builtin/commit.c sequencer.c
msgid "could not parse HEAD commit"
msgstr "no s'ha pogut analitzar la comissió HEAD"
+#: builtin/commit.c
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Fitxer MERGE_HEAD malmès (%s)"
+#: builtin/commit.c
msgid "could not read MERGE_MODE"
msgstr "no s'ha pogut llegir MERGE_MODE"
+#: builtin/commit.c
#, c-format
msgid "could not read commit message: %s"
msgstr "no s'ha pogut llegir el missatge de comissió: %s"
+#: builtin/commit.c
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "S'està avortant la comissió a causa d'un missatge de comissió buit.\n"
+#: builtin/commit.c
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "S'està avortant la comissió; no heu editat el missatge.\n"
+#: builtin/commit.c
#, c-format
msgid "Aborting commit due to empty commit message body.\n"
msgstr ""
"S'està interrompent la comissió a causa d'un missatge de comissió buit.\n"
+#: builtin/commit.c
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
"s'ha actualitzat el repositori, però no s'ha pogut escriure\n"
-" el fitxer «new_index». Comproveu que el disc no està ple i\n"
-"que la quota no s'ha excedit, i després, feu\n"
-"«git restore --staged :/» per a recuperar-lo."
+"el fitxer d'índex nou. Comproveu que el disc no està ple i\n"
+"la quota no s'ha excedit, i després feu «git restore --staged :/n»\n"
+"per a recuperar-ho."
-msgid "git config [<options>]"
-msgstr "git config [<opcions>]"
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<opció-fitxer>] [<opció-presentació>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "argument --type no reconegut, %s"
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<opció-fitxer>] [<opció-presentació>] [--includes] [--all] "
+"[--regexp] [--value=<valor>] [--fixed-value] [--default=<default>] <nom>"
-msgid "only one type at a time"
-msgstr "només un tipus cada cop"
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<opció-fitxer>] [--type=<tipus>] [--all] [--value=<valor>] "
+"[--fixed-value] <nom> <valor>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<opció-fitxer>] [--all] [--value=<valor>] [--fixed-value] "
+"<name> <valor>"
+#: builtin/config.c
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<opció-fitxer>] <nom-vell> <nom-nou>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<opció-fitxer>] <nom>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<opció-fitxer>]"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<opció-fitxer>] --get-colorbool <nom> [<stdout-is-tty>]"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<opció-fitxer>] [<opció-presentació>] [--includes] [--all] "
+"[--regexp=<expr-reg>] [--value=<valor>] [--fixed-value] [--"
+"default=<default>] <nom>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<opció-fitxer>] [--type=<tipus>] [--comment=<missatge>] [--"
+"all] [--value=<valor>] [--fixed-value] <nom> <valor>"
+
+#: builtin/config.c
msgid "Config file location"
msgstr "Ubicació del fitxer de configuració"
+#: builtin/config.c
msgid "use global config file"
msgstr "usa el fitxer de configuració global"
+#: builtin/config.c
msgid "use system config file"
msgstr "usa el fitxer de configuració del sistema"
+#: builtin/config.c
msgid "use repository config file"
msgstr "usa el fitxer de configuració del repositori"
+#: builtin/config.c
msgid "use per-worktree config file"
msgstr "usa un fitxer de configuració per repositori"
+#: builtin/config.c builtin/gc.c
msgid "use given config file"
msgstr "usa el fitxer de configuració donat"
+#: builtin/config.c
msgid "blob-id"
msgstr "ID de blob"
+#: builtin/config.c
msgid "read config from given blob object"
msgstr "llegeix la configuració de l'objecte de blob donat"
-msgid "Action"
-msgstr "Acció"
-
-msgid "get value: name [value-pattern]"
-msgstr "obtén valor: nom [value-pattern]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "obtén tots els valors: clau [value-pattern]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "obtén valors de regexp: name-regex [value-pattern]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "obtén el valor específic per a l'URL: secció[.variable] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr ""
-"reemplaça totes les variables que coincideixen: nom valor [value-pattern]"
-
-msgid "add a new variable: name value"
-msgstr "afegeix una variable nova: nom valor"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "elimina una variable: nom [value-pattern]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "elimina totes les coincidències: nom [value-pattern]"
-
-msgid "rename section: old-name new-name"
-msgstr "canvia el nom de secció: nom-antic nom-nou"
-
-msgid "remove a section: name"
-msgstr "elimina una secció: nom"
-
-msgid "list all"
-msgstr "llista'ls tots"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr ""
-"usa la igualtat de les cadenes quan es comparen els valors amb «value-"
-"pattern»"
-
-msgid "open an editor"
-msgstr "obre un editor"
-
-msgid "find the color configured: slot [default]"
-msgstr "troba el color configurat: ranura [per defecte]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "troba el paràmetre de color: ranura [stdout-és-tty]"
-
+#: builtin/config.c
msgid "Type"
msgstr "Tipus"
+#: builtin/config.c builtin/hash-object.c
msgid "type"
msgstr "tipus"
+#: builtin/config.c
msgid "value is given this type"
msgstr "el valor és d'aquest tipus que s'ha donat"
+#: builtin/config.c
msgid "value is \"true\" or \"false\""
msgstr "el valor és «true» o «false»"
+#: builtin/config.c
msgid "value is decimal number"
msgstr "el valor és un nombre decimal"
+#: builtin/config.c
msgid "value is --bool or --int"
msgstr "el valor és --bool o --int"
+#: builtin/config.c
msgid "value is --bool or string"
msgstr "el valor és --bool o string"
+#: builtin/config.c
msgid "value is a path (file or directory name)"
msgstr "el valor és un camí (nom de fitxer o directori)"
+#: builtin/config.c
msgid "value is an expiry date"
msgstr "el valor és una data de venciment"
-msgid "Other"
-msgstr "Altre"
+#: builtin/config.c
+msgid "Display options"
+msgstr "Opcions de visualització"
+#: builtin/config.c
msgid "terminate values with NUL byte"
msgstr "acaba els valors amb un octet NUL"
+#: builtin/config.c
msgid "show variable names only"
msgstr "mostra només els noms de variable"
-msgid "respect include directives on lookup"
-msgstr "respecta les directives d'inclusió en cercar"
-
+#: builtin/config.c
msgid "show origin of config (file, standard input, blob, command line)"
msgstr ""
"mostra l'origen de la configuració (fitxer, entrada estàndard, blob, línia "
"d'ordres)"
+#: builtin/config.c
msgid "show scope of config (worktree, local, global, system, command)"
msgstr ""
"mostra l'abast de la configuració («worktree», «local», «global», «system», "
"«command»)"
-msgid "value"
-msgstr "valor"
+#: builtin/config.c
+msgid "show config keys in addition to their values"
+msgstr "mostra les claus de configuració a més dels seus valors"
-msgid "with --get, use default value when missing entry"
-msgstr "amb --get utilitza el valor per defecte quan falti una entrada"
+#: builtin/config.c
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "argument --type no reconegut, %s"
+#: builtin/config.c
+msgid "only one type at a time"
+msgstr "només un tipus cada cop"
+
+#: builtin/config.c
#, c-format
msgid "wrong number of arguments, should be %d"
msgstr "nombre d'arguments erroni, ha de ser %d"
+#: builtin/config.c
#, c-format
msgid "wrong number of arguments, should be from %d to %d"
msgstr "nombre d'arguments erroni, ha de ser %d a %d"
+#: builtin/config.c
#, c-format
msgid "invalid key pattern: %s"
msgstr "patró de la clau no vàlid: %s"
+#: builtin/config.c config.c
#, c-format
msgid "invalid pattern: %s"
msgstr "patró no vàlid: %s"
+#: builtin/config.c
#, c-format
msgid "failed to format default config value: %s"
msgstr ""
"s'ha produït un error en formatar el valor per defecte de la configuració: %s"
+#: builtin/config.c
#, c-format
msgid "cannot parse color '%s'"
msgstr "no es pot analitzar el color «%s»"
+#: builtin/config.c
msgid "unable to parse default color value"
msgstr "no s'ha pogut analitzar el valor de color per defecte"
+#: builtin/config.c
msgid "not in a git directory"
msgstr "no és en un directori git"
+#: builtin/config.c
msgid "writing to stdin is not supported"
msgstr "no s'admet escriure a stdin"
+#: builtin/config.c
msgid "writing config blobs is not supported"
msgstr "no s'admet l'escriptura de blobs de configuració"
+#: builtin/config.c
#, c-format
msgid ""
"# This is Git's per-user configuration file.\n"
@@ -5313,21 +6695,27 @@ msgstr ""
"#\tname = %s\n"
"#\temail = %s\n"
+#: builtin/config.c
msgid "only one config file at a time"
msgstr "només un fitxer de configuració cada cop"
+#: builtin/config.c
msgid "--local can only be used inside a git repository"
msgstr "--local només es pot usar dins d'un repositori git"
+#: builtin/config.c
msgid "--blob can only be used inside a git repository"
msgstr "--blob només es pot usar dins d'un repositori git"
+#: builtin/config.c
msgid "--worktree can only be used inside a git repository"
msgstr "--worktree només es pot usar dins d'un repositori git"
+#: builtin/config.c builtin/gc.c
msgid "$HOME not set"
msgstr "$HOME no està establerta"
+#: builtin/config.c
msgid ""
"--worktree cannot be used with multiple working trees unless the config\n"
"extension worktreeConfig is enabled. Please read \"CONFIGURATION FILE\"\n"
@@ -5337,44 +6725,102 @@ msgstr ""
"l'extensió de configuració worktreeConfig estigui habilitada. Llegiu la "
"secció «CONFIGURATION FILE» a «git help worktree» per a més detalls"
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color i el tipus de variable són incoherents"
+#: builtin/config.c
+msgid "Other"
+msgstr "Altre"
-msgid "only one action at a time"
-msgstr "només una acció cada cop"
+#: builtin/config.c
+msgid "respect include directives on lookup"
+msgstr "respecta les directives d'inclusió en cercar"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only només és aplicable a --list o --get-regexp"
+#: builtin/config.c
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "no s'ha pogut llegir el fitxer de configuració «%s»"
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
+#: builtin/config.c
+msgid "error processing config file(s)"
+msgstr "s'ha produït un error en processar els fitxers de configuració"
+
+#: builtin/config.c
+msgid "Filter options"
+msgstr "Opcions de filtre"
+
+# multi-valued → multivalor?
+#: builtin/config.c
+msgid "return all values for multi-valued config options"
+msgstr "retorna tots els valors per a les opcions de configuració multivalor"
+
+#: builtin/config.c
+msgid "interpret the name as a regular expression"
+msgstr "interpreta el nom com una expressió regular"
+
+#: builtin/config.c
+msgid "show config with values matching the pattern"
+msgstr "mostra la configuració amb els valors coincidents amb el patró"
+
+#: builtin/config.c
+msgid "use string equality when comparing values to value pattern"
msgstr ""
-"--show-origin només és aplicable a --get, --get-all, --get-regexp, i --list"
+"usa la igualtat de cadenes quan es comparen els valors amb el patró de valor"
-msgid "--default is only applicable to --get"
-msgstr "--default només és aplicable a --get"
+#: builtin/config.c
+msgid "URL"
+msgstr "URL"
+#: builtin/config.c
+msgid "show config matching the given URL"
+msgstr "mostra la configuració coincident amb l'URL indicat"
+
+#: builtin/config.c
+msgid "value"
+msgstr "valor"
+
+#: builtin/config.c
+msgid "use default value when missing entry"
+msgstr "utilitza el valor per defecte quan falti una entrada"
+
+#: builtin/config.c
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value només s'aplica amb «value-pattern»"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "no s'ha pogut llegir el fitxer de configuració «%s»"
+#: builtin/config.c
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= no es pot utilitzar amb --all o --url="
-msgid "error processing config file(s)"
-msgstr "s'ha produït un error en processar els fitxers de configuració"
+#: builtin/config.c
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= no es pot usar amb --all, --regexp o --value"
-msgid "editing stdin is not supported"
-msgstr "no hi ha compatibilitat per a l'edició a stdin"
+#: builtin/config.c
+msgid "Filter"
+msgstr "Filtra"
-msgid "editing blobs is not supported"
-msgstr "no hi ha compatibilitat per l'edició de blobs"
+# multi-valued → multivalor?
+#: builtin/config.c
+msgid "replace multi-valued config option with new value"
+msgstr "reemplaça l'opció de configuració multivalor amb el valor nou"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "no es pot crear el fitxer de configuració %s"
+#: builtin/config.c
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr ""
+"cadena de comentari llegible per humans (es farà que comence per\n"
+"# si cal)"
+
+#: builtin/config.c
+msgid "add a new line without altering any existing values"
+msgstr "afegeix una línia nova sense alterar cap dels valors existents"
+
+# only applies → només funciona?
+#: builtin/config.c
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value només s'aplica amb --value=<patró>"
+
+#: builtin/config.c
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "no es pot utilitzar --append amb --value=<patró>"
+#: builtin/config.c
#, c-format
msgid ""
"cannot overwrite multiple values with a single value\n"
@@ -5383,13 +6829,128 @@ msgstr ""
"no es poden sobreescriure múltiples valors amb un sol valor\n"
" Useu una expressió regular, --add o --replace-all per a canviar %s."
+#: builtin/config.c
#, c-format
msgid "no such section: %s"
msgstr "no existeix la secció: %s"
+#: builtin/config.c
+msgid "editing stdin is not supported"
+msgstr "no hi ha compatibilitat per a l'edició a stdin"
+
+#: builtin/config.c
+msgid "editing blobs is not supported"
+msgstr "no hi ha compatibilitat per l'edició de blobs"
+
+#: builtin/config.c
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "no es pot crear el fitxer de configuració %s"
+
+#: builtin/config.c
+msgid "Action"
+msgstr "Acció"
+
+#: builtin/config.c
+msgid "get value: name [<value-pattern>]"
+msgstr "get value: nom [<patró-valors>]"
+
+#: builtin/config.c
+msgid "get all values: key [<value-pattern>]"
+msgstr "obté tots els valors: clau [<patró-valors>]"
+
+# he traduit el nom del paràmetre
+#: builtin/config.c
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr ""
+"obté els valors per a l'expressió regular: expressio-regular-nom [<patró-"
+"valors>]"
+
+#: builtin/config.c
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "obtén el valor específic per a l'URL: secció[.variable] URL"
+
+# he traduït els noms dels paràmetres
+#: builtin/config.c
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr ""
+"reemplaça totes les variables que coincideixin: nom valor [<patró-valors>]"
+
+#: builtin/config.c
+msgid "add a new variable: name value"
+msgstr "afegeix una variable nova: nom valor"
+
+# cal traduir name?
+#: builtin/config.c
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "elimina una variable: nom [<patró-valors>]"
+
+#: builtin/config.c
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "elimina totes les coincidències: nom [<patró-valors>]"
+
+#: builtin/config.c
+msgid "rename section: old-name new-name"
+msgstr "canvia el nom de secció: nom-antic nom-nou"
+
+#: builtin/config.c
+msgid "remove a section: name"
+msgstr "elimina una secció: nom"
+
+#: builtin/config.c
+msgid "list all"
+msgstr "llista'ls tots"
+
+#: builtin/config.c
+msgid "open an editor"
+msgstr "obre un editor"
+
+# slot → ??? ; <default> → ???
+#: builtin/config.c
+msgid "find the color configured: slot [<default>]"
+msgstr "troba el color configurat: slot [<default>]"
+
+#: builtin/config.c
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "troba la configuració de color: slot [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid "with --get, use default value when missing entry"
+msgstr "amb --get utilitza el valor per defecte quan falti una entrada"
+
+#: builtin/config.c
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color i el tipus de variable són incoherents"
+
+#: builtin/config.c
+msgid "no action specified"
+msgstr "no s'ha especificat cap acció"
+
+#: builtin/config.c
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only només és aplicable a --list o --get-regexp"
+
+#: builtin/config.c
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin només és aplicable a --get, --get-all, --get-regexp, i --list"
+
+#: builtin/config.c
+msgid "--default is only applicable to --get"
+msgstr "--default només és aplicable a --get"
+
+# add/set/replace sense traduir, entenc
+#: builtin/config.c
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment només es pot aplicar a operacions add/set/replace"
+
+#: builtin/count-objects.c
msgid "print sizes in human readable format"
msgstr "imprimeix les mides en un format llegible pels humans"
+#: builtin/credential-cache--daemon.c
#, c-format
msgid ""
"The permissions on your socket directory are too loose; other\n"
@@ -5403,67 +6964,83 @@ msgstr ""
"\n"
"\tchmod 0700 %s"
+#: builtin/credential-cache--daemon.c
msgid "print debugging messages to stderr"
msgstr "imprimeix els missatges de depuració a stderr"
+#: builtin/credential-cache--daemon.c
msgid "credential-cache--daemon unavailable; no unix socket support"
msgstr ""
"credential-cache--daemon no disponible; no hi ha compatibilitat amb sòcols "
"d'unix"
+#: builtin/credential-cache.c
msgid "credential-cache unavailable; no unix socket support"
msgstr ""
"credencial-cache no disponible; no hi ha compatibilitat amb els sòcols d'unix"
+#: builtin/credential-store.c
#, c-format
msgid "unable to get credential storage lock in %d ms"
msgstr ""
"no s'ha pogut obtenir el bloqueig de l'emmagatzematge de credencials en %d ms"
+#: builtin/describe.c
msgid ""
"git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
msgstr ""
"git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
+#: builtin/describe.c
msgid ""
"git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
msgstr ""
"git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
+#: builtin/describe.c
msgid "git describe <blob>"
msgstr "git describe <blob>"
+#: builtin/describe.c
msgid "head"
msgstr "davant per"
+#: builtin/describe.c
msgid "lightweight"
msgstr "lleuger"
+#: builtin/describe.c
msgid "annotated"
msgstr "anotat"
+#: builtin/describe.c
#, c-format
msgid "annotated tag %s not available"
msgstr "l'etiqueta anotada %s no és disponible"
+#: builtin/describe.c
#, c-format
msgid "tag '%s' is externally known as '%s'"
msgstr "l'etiqueta «%s» es coneix externament com a «%s»"
+#: builtin/describe.c
#, c-format
msgid "no tag exactly matches '%s'"
msgstr "cap etiqueta coincideix exactament amb «%s»"
+#: builtin/describe.c
#, c-format
msgid "No exact match on refs or tags, searching to describe\n"
msgstr ""
"No hi ha cap coincidència exacta en la cerca de referències o etiquetes per "
"a descriure\n"
+#: builtin/describe.c
#, c-format
msgid "finished search at %s\n"
msgstr "s'ha finalitzat la cerca a %s\n"
+#: builtin/describe.c
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
@@ -5472,6 +7049,7 @@ msgstr ""
"Cap etiqueta anotada pot descriure «%s».\n"
"No obstant això, hi havia etiquetes no anotades: proveu --tags."
+#: builtin/describe.c
#, c-format
msgid ""
"No tags can describe '%s'.\n"
@@ -5480,10 +7058,12 @@ msgstr ""
"Cap etiqueta pot descriure «%s».\n"
"Proveu --always, o creeu algunes etiquetes."
+#: builtin/describe.c
#, c-format
msgid "traversed %lu commits\n"
msgstr "%lu comissions recorregudes\n"
+#: builtin/describe.c
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
@@ -5492,67 +7072,87 @@ msgstr ""
"s'han trobat més de %i etiquetes: s'han llistat les %i més recents\n"
"s'ha renunciat la cerca a %s\n"
+#: builtin/describe.c
#, c-format
msgid "describe %s\n"
msgstr "descriu %s\n"
+#: builtin/describe.c
#, c-format
msgid "Not a valid object name %s"
msgstr "%s no és un nom d'objecte vàlid"
+#: builtin/describe.c
#, c-format
msgid "%s is neither a commit nor blob"
msgstr "%s no és una comissió o un blob"
+#: builtin/describe.c
msgid "find the tag that comes after the commit"
msgstr "troba l'etiqueta que vingui després de la comissió"
+#: builtin/describe.c
msgid "debug search strategy on stderr"
msgstr "estratègia de cerca de depuració en stderr"
+#: builtin/describe.c
msgid "use any ref"
msgstr "usa qualsevol referència"
+#: builtin/describe.c
msgid "use any tag, even unannotated"
msgstr "usa qualsevol etiqueta, fins i tot aquelles sense anotar"
+#: builtin/describe.c
msgid "always use long format"
msgstr "sempre usa el format llarg"
+#: builtin/describe.c
msgid "only follow first parent"
msgstr "només segueix el primer pare"
+#: builtin/describe.c
msgid "only output exact matches"
msgstr "emet només coincidències exactes"
+#: builtin/describe.c
msgid "consider <n> most recent tags (default: 10)"
msgstr "considera les <n> etiquetes més recents (per defecte: 10)"
+#: builtin/describe.c
msgid "only consider tags matching <pattern>"
msgstr "només considera les etiquetes que coincideixen amb <patró>"
+#: builtin/describe.c
msgid "do not consider tags matching <pattern>"
msgstr "no consideris les etiquetes que no coincideixen amb <patró>"
+#: builtin/describe.c builtin/name-rev.c
msgid "show abbreviated commit object as fallback"
msgstr "mostra l'objecte de comissió abreviat com a sistema alternatiu"
+#: builtin/describe.c
msgid "mark"
msgstr "marca"
+#: builtin/describe.c
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
msgstr "annexa <marca> en l'arbre de treball brut (per defecte: «-dirty»)"
+#: builtin/describe.c
msgid "append <mark> on broken working tree (default: \"-broken\")"
msgstr "annexa <marca> en l'arbre de treball brut (per defecte: «-broken»)"
+#: builtin/describe.c
msgid "No names found, cannot describe anything."
msgstr "No s'ha trobat cap nom, no es pot descriure res."
+#: builtin/describe.c
#, c-format
msgid "option '%s' and commit-ishes cannot be used together"
-msgstr "les opcions «%s» i de comissió no es poden usar juntes"
+msgstr "opció «%s» i les de comissió no es poden usar juntes"
+#: builtin/diagnose.c
msgid ""
"git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
" [--mode=<mode>]"
@@ -5560,67 +7160,85 @@ msgstr ""
"git diagnose [(-o | --output-directory) <camí>] [(-s | --suffix) <format>]\n"
" [--mode=<mode>]"
+#: builtin/diagnose.c
msgid "specify a destination for the diagnostics archive"
msgstr "especifiqueu una destinació per a l'arxiu de diagnòstic"
+#: builtin/diagnose.c
msgid "specify a strftime format suffix for the filename"
msgstr "especifiqueu un sufix en format strftime per al nom de fitxer"
+#: builtin/diagnose.c
msgid "specify the content of the diagnostic archive"
msgstr "especifica el contingut de l'arxiu de diagnòstic"
+#: builtin/diff-tree.c
msgid "--merge-base only works with two commits"
msgstr "--merge-base només funciona amb dues comissions"
+#: builtin/diff.c
#, c-format
msgid "'%s': not a regular file or symlink"
msgstr "«%s»: no és ni fitxer regular ni enllaç simbòlic"
+#: builtin/diff.c
msgid "no merge given, only parents."
msgstr "no s'ha donat cap fusió, només els pares."
+#: builtin/diff.c
#, c-format
msgid "invalid option: %s"
msgstr "opció no vàlida: %s"
+#: builtin/diff.c
#, c-format
msgid "%s...%s: no merge base"
msgstr "%s...%s: sense una base de fusió"
+#: builtin/diff.c
msgid "Not a git repository"
msgstr "No és un repositori de git"
+#: builtin/diff.c builtin/grep.c
#, c-format
msgid "invalid object '%s' given."
msgstr "s'ha donat un objecte no vàlid «%s»."
+#: builtin/diff.c
#, c-format
msgid "more than two blobs given: '%s'"
msgstr "s'ha donat més de dos blobs: «%s»"
+#: builtin/diff.c
#, c-format
msgid "unhandled object '%s' given."
msgstr "s'ha donat l'objecte no gestionat «%s»."
+#: builtin/diff.c
#, c-format
msgid "%s...%s: multiple merge bases, using %s"
msgstr "%s...%s: múltiples bases de fusió, utilitzant %s"
+#: builtin/difftool.c
msgid "git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"
msgstr "git difftool [<opcions>] [<comissió> [<comissió>]] [--] [<camí>...]"
+#: builtin/difftool.c
#, c-format
msgid "could not read symlink %s"
msgstr "no s'ha pogut llegir l'enllaç simbòlic %s"
+#: builtin/difftool.c
#, c-format
msgid "could not read symlink file %s"
msgstr "no s'ha pogut llegir el fitxer d'enllaç simbòlic %s"
+#: builtin/difftool.c
#, c-format
msgid "could not read object %s for symlink %s"
msgstr "no es pot llegir l'objecte %s per l'enllaç simbòlic %s"
+#: builtin/difftool.c
msgid ""
"combined diff formats ('-c' and '--cc') are not supported in\n"
"directory diff mode ('-d' and '--dir-diff')."
@@ -5628,50 +7246,64 @@ msgstr ""
"els formats de diff combinats («-c» i «--cc») no s'admeten\n"
"en el mode diff de directoris («-d» i «--dir-diff»)."
+#: builtin/difftool.c
#, c-format
msgid "both files modified: '%s' and '%s'."
msgstr "s'han modificat ambdós fitxers: «%s» i «%s»."
+#: builtin/difftool.c
msgid "working tree file has been left."
msgstr "s'ha deixat un fitxer de l'arbre de treball."
+#: builtin/difftool.c sequencer.c
#, c-format
msgid "could not copy '%s' to '%s'"
msgstr "no s'ha pogut copiar «%s» a «%s»"
+#: builtin/difftool.c
#, c-format
msgid "temporary files exist in '%s'."
msgstr "existeix un fitxer temporal a «%s»."
+#: builtin/difftool.c
msgid "you may want to cleanup or recover these."
msgstr "podeu netejar o recuperar-los."
+#: builtin/difftool.c
#, c-format
msgid "failed: %d"
msgstr "ha fallat: %d"
+#: builtin/difftool.c
msgid "use `diff.guitool` instead of `diff.tool`"
msgstr "usa «diff.guitool» en lloc de «diff.tool»"
+#: builtin/difftool.c
msgid "perform a full-directory diff"
msgstr "fes un diff de tot el directori"
+#: builtin/difftool.c
msgid "do not prompt before launching a diff tool"
msgstr "no preguntis abans d'executar l'eina diff"
+#: builtin/difftool.c
msgid "use symlinks in dir-diff mode"
msgstr "utilitza enllaços simbòlics en mode dir-diff"
+#: builtin/difftool.c
msgid "tool"
msgstr "eina"
+#: builtin/difftool.c
msgid "use the specified diff tool"
msgstr "utilitza l'eina de diff especificada"
+#: builtin/difftool.c
msgid "print a list of diff tools that may be used with `--tool`"
msgstr ""
"imprimeix una llista de totes les eines diff que podeu usar amb «--tool»"
+#: builtin/difftool.c
msgid ""
"make 'git-difftool' exit when an invoked diff tool returns a non-zero exit "
"code"
@@ -5679,187 +7311,241 @@ msgstr ""
"fes que «git-difftool» surti quan l'eina de diff invocada torna un codi de "
"sortida diferent de zero"
+#: builtin/difftool.c
msgid "specify a custom command for viewing diffs"
msgstr "especifiqueu una ordre personalitzada per a veure diffs"
+#: builtin/difftool.c
msgid "passed to `diff`"
msgstr "passa-ho a «diff»"
+#: builtin/difftool.c
msgid "difftool requires worktree or --no-index"
msgstr "difftool requereix worktree o --no-index"
+#: builtin/difftool.c
msgid "no <tool> given for --tool=<tool>"
msgstr "no s'ha proporcionat l'<eina> per a --tool=<eina>"
+#: builtin/difftool.c
msgid "no <cmd> given for --extcmd=<cmd>"
msgstr "no s'ha proporcionat l'<ordre> per a --extcmd=<ordre>"
+#: builtin/fast-export.c
msgid "git fast-export [<rev-list-opts>]"
msgstr "git fast-export [<rev-list-opts>]"
+#: builtin/fast-export.c
msgid "Error: Cannot export nested tags unless --mark-tags is specified."
msgstr ""
"Error: no es poden exportar les etiquetes imbricades a menys que "
"s'especifiqui --mark-tags."
+#: builtin/fast-export.c
msgid "--anonymize-map token cannot be empty"
msgstr "el testimoni de --anonymize-map no pot estar buit"
+#: builtin/fast-export.c
msgid "show progress after <n> objects"
msgstr "mostra el progrés després de <n> objectes"
+#: builtin/fast-export.c
msgid "select handling of signed tags"
msgstr "selecciona la gestió de les etiquetes signades"
+#: builtin/fast-export.c
msgid "select handling of tags that tag filtered objects"
msgstr "selecciona la gestió de les etiquetes que etiquetin objectes filtrats"
+#: builtin/fast-export.c
msgid "select handling of commit messages in an alternate encoding"
msgstr ""
-"selecciona la gestió dels missatges de publicació en una codificació "
+"selecciona la gestió dels missatges de comissió en una codificació "
"alternativa"
+#: builtin/fast-export.c
msgid "dump marks to this file"
msgstr "bolca les marques a aquest fitxer"
+#: builtin/fast-export.c
msgid "import marks from this file"
msgstr "importa les marques d'aquest fitxer"
+#: builtin/fast-export.c
msgid "import marks from this file if it exists"
msgstr "importa marques d'aquest fitxer si existeix"
+#: builtin/fast-export.c
msgid "fake a tagger when tags lack one"
msgstr "fingeix un etiquetador quan en falti un a les etiquetes"
+#: builtin/fast-export.c
msgid "output full tree for each commit"
msgstr "imprimeix l'arbre complet de per a cada comissió"
+#: builtin/fast-export.c
msgid "use the done feature to terminate the stream"
msgstr "usa la característica fet per a acabar el flux"
+#: builtin/fast-export.c
msgid "skip output of blob data"
msgstr "omet la sortida de dades de blob"
+#: builtin/fast-export.c builtin/log.c
msgid "refspec"
msgstr "especificació de referència"
+#: builtin/fast-export.c
msgid "apply refspec to exported refs"
msgstr "aplica l'especificació de referència a les referències exportades"
+#: builtin/fast-export.c
msgid "anonymize output"
msgstr "anonimitza la sortida"
+#: builtin/fast-export.c
msgid "from:to"
msgstr "des de:a"
+#: builtin/fast-export.c
msgid "convert <from> to <to> in anonymized output"
msgstr "converteix <from> a <to> en una sortida anònima"
+#: builtin/fast-export.c
msgid "reference parents which are not in fast-export stream by object id"
msgstr ""
"referència els pares que no estan en flux d'exportació ràpida per "
"identificador d'objecte"
+#: builtin/fast-export.c
msgid "show original object ids of blobs/commits"
msgstr "mostra els ID dels objectes originals dels blobs i comissions"
+#: builtin/fast-export.c
msgid "label tags with mark ids"
msgstr "marca les etiquetes amb els identificadors de marca"
+#: builtin/fast-import.c
#, c-format
msgid "Missing from marks for submodule '%s'"
msgstr "Falten les marques «from» per al submòdul «%s»"
+#: builtin/fast-import.c
#, c-format
msgid "Missing to marks for submodule '%s'"
msgstr "Falten les marques per al submòdul «%s»"
+#: builtin/fast-import.c
#, c-format
msgid "Expected 'mark' command, got %s"
msgstr "S'esperava l'ordre «mark», s'ha rebut %s"
+#: builtin/fast-import.c
#, c-format
msgid "Expected 'to' command, got %s"
msgstr "S'esperava l'ordre «to», s'ha rebut «%s»"
+#: builtin/fast-import.c
msgid "Expected format name:filename for submodule rewrite option"
msgstr ""
"S'esperava el format «nom:nom de fitxer» per a l'opció de reescriptura de "
"submòdul"
+#: builtin/fast-import.c
#, c-format
msgid "feature '%s' forbidden in input without --allow-unsafe-features"
msgstr ""
"característica «%s» prohibida a l'entrada sense --allow-unsafe-features"
+#: builtin/fetch-pack.c
#, c-format
msgid "Lockfile created but not reported: %s"
msgstr "S'ha creat el fitxer de bloqueig però no s'ha informat: %s"
+#: builtin/fetch.c
msgid "git fetch [<options>] [<repository> [<refspec>...]]"
-msgstr ""
-"git fetch [<opcions>] [<repositori> [<especificació-de-referència>...]]"
+msgstr "git fetch [<opcions>] [<repositori> [<especificació-referència>...]]"
+#: builtin/fetch.c
msgid "git fetch [<options>] <group>"
msgstr "git fetch [<opcions>] <grup>"
+#: builtin/fetch.c
msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
msgstr "git fetch --multiple [<opcions>] [(<repositori> | <grup>)...]"
+#: builtin/fetch.c
msgid "git fetch --all [<options>]"
msgstr "git fetch --all [<opcions>]"
+#: builtin/fetch.c
msgid "fetch.parallel cannot be negative"
msgstr "fetch.parallel no pot ser negatiu"
+#: builtin/fetch.c
msgid "couldn't find remote ref HEAD"
msgstr "no s'ha pogut trobar la referència HEAD remota"
+#: builtin/fetch.c
#, c-format
msgid "From %.*s\n"
msgstr "De %.*s\n"
+#: builtin/fetch.c
#, c-format
msgid "object %s not found"
msgstr "objecte %s no trobat"
+#: builtin/fetch.c
msgid "[up to date]"
msgstr "[al dia]"
+#: builtin/fetch.c
msgid "[rejected]"
msgstr "[rebutjat]"
+#: builtin/fetch.c
msgid "can't fetch into checked-out branch"
msgstr "no es pot obtenir en la branca actual"
+#: builtin/fetch.c
msgid "[tag update]"
msgstr "[actualització d'etiqueta]"
+#: builtin/fetch.c
msgid "unable to update local ref"
msgstr "no s'ha pogut actualitzar la referència local"
+#: builtin/fetch.c
msgid "would clobber existing tag"
msgstr "s'adjuntaria l'etiqueta existent"
+#: builtin/fetch.c
msgid "[new tag]"
msgstr "[etiqueta nova]"
+#: builtin/fetch.c
msgid "[new branch]"
msgstr "[branca nova]"
+#: builtin/fetch.c
msgid "[new ref]"
msgstr "[referència nova]"
+#: builtin/fetch.c
msgid "forced update"
msgstr "actualització forçada"
+#: builtin/fetch.c
msgid "non-fast-forward"
msgstr "sense avanç ràpid"
+#: builtin/fetch.c builtin/grep.c sequencer.c
#, c-format
msgid "cannot open '%s'"
msgstr "no es pot obrir «%s»"
+#: builtin/fetch.c
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"
@@ -5871,6 +7557,7 @@ msgstr ""
"utilitzeu\n"
"«--show-forced-updates» o executeu «git config fetch.showForcedUpdates true»"
+#: builtin/fetch.c
#, c-format
msgid ""
"it took %.2f seconds to check forced updates; you can use\n"
@@ -5882,15 +7569,18 @@ msgstr ""
"utilitzar «--no-show-forced-updates» o executar «git config \n"
"fetch.showForcedUpdates false» per a evitar aquesta comprovació.\n"
+#: builtin/fetch.c
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s no ha enviat tots els objectes necessaris\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s no ha enviat tot els objectes necessaris"
+#: builtin/fetch.c
#, c-format
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"
+#: builtin/fetch.c
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -5900,43 +7590,54 @@ msgstr ""
" intenteu executar «git remote prune %s» per a eliminar\n"
" qualsevol branca antiga o conflictiva"
+#: builtin/fetch.c
#, c-format
msgid " (%s will become dangling)"
-msgstr " (%s es tornarà penjant)"
+msgstr " (%s es tornarà despenjat)"
+#: builtin/fetch.c
#, c-format
msgid " (%s has become dangling)"
-msgstr " (%s s'ha tornat penjant)"
+msgstr " (%s s'ha quedat despenjat)"
+#: builtin/fetch.c
msgid "[deleted]"
msgstr "[suprimit]"
+#: builtin/fetch.c builtin/remote.c
msgid "(none)"
msgstr "(cap)"
+#: builtin/fetch.c
#, c-format
msgid "refusing to fetch into branch '%s' checked out at '%s'"
msgstr "s'ha rebutjat l'obtenció en la branca «%s» agafada a «%s»"
+#: builtin/fetch.c
#, c-format
msgid "option \"%s\" value \"%s\" is not valid for %s"
msgstr "l'opció «%s» amb valor «%s» no és vàlida per a %s"
+#: builtin/fetch.c
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "s'ignora l'opció «%s» per a %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "l'opció «%s» s'ignora per a «%s»"
+#: builtin/fetch.c object-file.c
#, c-format
msgid "%s is not a valid object"
msgstr "%s no és un objecte vàlid"
+#: builtin/fetch.c
#, c-format
msgid "the object %s does not exist"
msgstr "l'objecte %s no existeix"
+#: builtin/fetch.c
msgid "multiple branches detected, incompatible with --set-upstream"
msgstr "s'han detectat múltiples branques, incompatible amb --set-upstream"
+#: builtin/fetch.c
#, c-format
msgid ""
"could not set upstream of HEAD to '%s' from '%s' when it does not point to "
@@ -5945,16 +7646,20 @@ msgstr ""
"no s'ha pogut establir la font de HEAD a «%s» des de «%s» quan no assenyala "
"cap branca."
+#: builtin/fetch.c
msgid "not setting upstream for a remote remote-tracking branch"
msgstr ""
"no s'està configurant la font per a una branca remota amb seguiment remot"
+#: builtin/fetch.c
msgid "not setting upstream for a remote tag"
msgstr "no s'està configurant la font d'una etiqueta remota"
+#: builtin/fetch.c
msgid "unknown branch type"
msgstr "tipus de branca desconegut"
+#: builtin/fetch.c
msgid ""
"no source branch found;\n"
"you need to specify exactly one branch with the --set-upstream option"
@@ -5962,18 +7667,22 @@ msgstr ""
"no s'ha trobat cap branca d'origen.\n"
"heu d'especificar exactament una branca amb l'opció --set-upstream"
+#: builtin/fetch.c
#, c-format
msgid "Fetching %s\n"
msgstr "S'està obtenint %s\n"
+#: builtin/fetch.c
#, c-format
msgid "could not fetch %s"
msgstr "no s'ha pogut obtenir %s"
+#: builtin/fetch.c
#, c-format
msgid "could not fetch '%s' (exit code: %d)\n"
msgstr "no s'ha pogut obtenir «%s» (codi de sortida: %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"
@@ -5981,82 +7690,107 @@ msgstr ""
"no s'ha especificat cap repositori remot. Especifiqueu un URL o\n"
"un nom remot del qual s'han d'obtenir les revisions noves"
+#: builtin/fetch.c
msgid "you need to specify a tag name"
msgstr "necessiteu especificar un nom d'etiqueta"
+#: builtin/fetch.c builtin/pull.c
msgid "fetch from all remotes"
msgstr "obtén de tots els remots"
+#: builtin/fetch.c builtin/pull.c
msgid "set upstream for git pull/fetch"
msgstr "estableix la font per a git pull/fetch"
+#: builtin/fetch.c builtin/pull.c
msgid "append to .git/FETCH_HEAD instead of overwriting"
msgstr "annexa a .git/FETCH_HEAD en lloc de sobreescriure'l"
+#: builtin/fetch.c
msgid "use atomic transaction to update references"
msgstr "usa una transacció atòmica per a actualitzar les referències"
+#: builtin/fetch.c builtin/pull.c
msgid "path to upload pack on remote end"
msgstr "camí al qual pujar el paquet al costat remot"
+#: builtin/fetch.c
msgid "force overwrite of local reference"
msgstr "força la sobreescriptura de la referència local"
+#: builtin/fetch.c
msgid "fetch from multiple remotes"
msgstr "obtén de múltiples remots"
+#: builtin/fetch.c builtin/pull.c
msgid "fetch all tags and associated objects"
msgstr "obtén totes les etiquetes i tots els objectes associats"
+#: builtin/fetch.c
msgid "do not fetch all tags (--no-tags)"
msgstr "no obtinguis les etiquetes (--no-tags)"
+#: builtin/fetch.c
msgid "number of submodules fetched in parallel"
msgstr "nombre de submòduls obtinguts en paral·lel"
+#: builtin/fetch.c
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/"
+#: builtin/fetch.c builtin/pull.c
msgid "prune remote-tracking branches no longer on remote"
msgstr "poda les branques amb seguiment remot que ja no estiguin en el remot"
+#: builtin/fetch.c
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"
+#: builtin/fetch.c builtin/pull.c
msgid "on-demand"
msgstr "sota demanda"
+#: builtin/fetch.c
msgid "control recursive fetching of submodules"
msgstr "controla l'obtenció recursiva de submòduls"
+#: builtin/fetch.c
msgid "write fetched references to the FETCH_HEAD file"
msgstr "escriu les referències obtingudes al fitxer FETCH_HEAD"
+#: builtin/fetch.c builtin/pull.c
msgid "keep downloaded pack"
msgstr "retén el paquet baixat"
+#: builtin/fetch.c
msgid "allow updating of HEAD ref"
msgstr "permet l'actualització de la referència HEAD"
+#: builtin/fetch.c builtin/pull.c
msgid "deepen history of shallow clone"
msgstr "aprofundeix la història d'un clon superficial"
+#: builtin/fetch.c builtin/pull.c
msgid "deepen history of shallow repository based on time"
msgstr "aprofundeix la història d'un clon superficial basat en una data"
+#: builtin/fetch.c builtin/pull.c
msgid "convert to a complete repository"
msgstr "converteix en un repositori complet"
+#: builtin/fetch.c
msgid "re-fetch without negotiating common commits"
msgstr "tornar a obtenir sense negociar comissions comunes"
+#: builtin/fetch.c
msgid "prepend this to submodule path output"
msgstr "anteposa això a la sortida de camí del submòdul"
+#: builtin/fetch.c
msgid ""
"default for recursive fetching of submodules (lower priority than config "
"files)"
@@ -6064,68 +7798,88 @@ msgstr ""
"per defecte per a l'obtenció recursiva de submòduls (prioritat més baixa que "
"els fitxers de configuració)"
+#: builtin/fetch.c builtin/pull.c
msgid "accept refs that update .git/shallow"
msgstr "accepta les referències que actualitzin .git/shallow"
+#: builtin/fetch.c builtin/pull.c
msgid "refmap"
msgstr "mapa de referències"
+#: builtin/fetch.c builtin/pull.c
msgid "specify fetch refmap"
msgstr "específica l'obtenció del mapa de referències"
+#: builtin/fetch.c builtin/pull.c
msgid "report that we have only objects reachable from this object"
msgstr "informa que només hi ha objectes abastables des d'aquest objecte"
+#: builtin/fetch.c
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ó"
+#: builtin/fetch.c
msgid "run 'maintenance --auto' after fetching"
msgstr "executa «maintenance --auto» després d'obtenir"
+#: builtin/fetch.c builtin/pull.c
msgid "check for forced-updates on all updated branches"
msgstr ""
"comprova si hi ha actualitzacions forçades a totes les branques actualitzades"
+#: builtin/fetch.c
msgid "write the commit-graph after fetching"
msgstr "escriu el graf de comissions després de recollir"
+#: builtin/fetch.c
msgid "accept refspecs from stdin"
msgstr "llegeix les especificacions de referència des de stdin"
+#: builtin/fetch.c
msgid "--negotiate-only needs one or more --negotiation-tip=*"
msgstr "--negotiate-only necessita un o més --negotiation-tip=*"
+#: builtin/fetch.c
msgid "negative depth in --deepen is not supported"
msgstr "no s'admet una profunditat negativa en --deepen"
+#: builtin/fetch.c
msgid "--unshallow on a complete repository does not make sense"
msgstr "--unshallow en un repositori complet no té sentit"
+#: builtin/fetch.c
#, c-format
msgid "failed to fetch bundles from '%s'"
msgstr "no s'han pogut obtenir els paquets de «%s»"
+#: builtin/fetch.c
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all no accepta un argument de repositori"
+#: builtin/fetch.c
msgid "fetch --all does not make sense with refspecs"
msgstr "fetch --all no té sentit amb especificacions de referència"
+#: builtin/fetch.c
#, c-format
msgid "no such remote or remote group: %s"
msgstr "no existeix un remot ni un grup remot: %s"
+#: builtin/fetch.c
msgid "fetching a group and specifying refspecs does not make sense"
msgstr "obtenir un grup i especificar referències no té sentit"
+#: builtin/fetch.c
msgid "must supply remote when using --negotiate-only"
msgstr "s'ha de subministrar el remot en usar --negotiate-only"
+#: builtin/fetch.c
msgid "protocol does not support --negotiate-only, exiting"
msgstr "el protocol no admet --negotiate-only, se surt"
+#: builtin/fetch.c
msgid ""
"--filter can only be used with the remote configured in extensions."
"partialclone"
@@ -6133,125 +7887,170 @@ msgstr ""
"--filter només es pot utilitzar amb el remot configurat en extensions."
"partialclone"
+#: builtin/fetch.c
msgid "--atomic can only be used when fetching from one remote"
msgstr "l'opció --atomic només es pot usar quan s'obté des d'un remot"
+#: builtin/fetch.c
msgid "--stdin can only be used when fetching from one remote"
msgstr "l'opció --stdin només es pot usar quan s'obté des d'un remot"
+#: builtin/fmt-merge-msg.c
msgid ""
"git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"
msgstr ""
"git fmt-merge-msg [-m <missatge>] [--log[=<n>] | --no-log] [--file <fitxer>]"
+#: builtin/fmt-merge-msg.c
msgid "populate log with at most <n> entries from shortlog"
msgstr "emplena el registre amb <n> entrades del registre curt com a màxim"
+#: builtin/fmt-merge-msg.c
msgid "alias for --log (deprecated)"
msgstr "àlies per a --log (en desús)"
+#: builtin/fmt-merge-msg.c
msgid "text"
msgstr "text"
+#: builtin/fmt-merge-msg.c
msgid "use <text> as start of message"
msgstr "usa <text> com a inici de missatge"
+#: builtin/fmt-merge-msg.c
msgid "use <name> instead of the real target branch"
msgstr "usa <nom> en lloc de la branca de destí real"
+#: builtin/fmt-merge-msg.c
msgid "file to read from"
msgstr "fitxer del qual llegir"
+#: builtin/for-each-ref.c
msgid "git for-each-ref [<options>] [<pattern>]"
msgstr "git for-each-ref [<opcions>] [<patró>]"
+#: builtin/for-each-ref.c
msgid "git for-each-ref [--points-at <object>]"
msgstr "git for-each-ref [--points-at <objecte>]"
+#: builtin/for-each-ref.c
msgid "git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"
msgstr "git for-each-ref [--merged [<comissió>]] [--no-merged [<comissió>]]"
+#: builtin/for-each-ref.c
msgid "git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"
msgstr ""
"git for-each-ref [--contains [<comissió>]] [--no-contains [<comissió>]]"
+#: builtin/for-each-ref.c
msgid "quote placeholders suitably for shells"
msgstr ""
"posa els marcadors de posició entre cometes adequades per a intèrprets "
"d'ordres"
+#: builtin/for-each-ref.c
msgid "quote placeholders suitably for perl"
msgstr "posa els marcadors de posició entre cometes adequades per al perl"
+#: builtin/for-each-ref.c
msgid "quote placeholders suitably for python"
msgstr "posa els marcadors de posició entre cometes adequades per al python"
+#: builtin/for-each-ref.c
msgid "quote placeholders suitably for Tcl"
msgstr "posa els marcadors de posició entre cometes adequades per al Tcl"
+#: builtin/for-each-ref.c
msgid "show only <n> matched refs"
msgstr "mostra només <n> referències coincidents"
+#: builtin/for-each-ref.c builtin/tag.c
msgid "respect format colors"
msgstr "respecta els colors del format"
+#: builtin/for-each-ref.c
msgid "print only refs which points at the given object"
msgstr "imprimeix només les referències que assenyalin l'objecte donat"
+#: builtin/for-each-ref.c
msgid "print only refs that are merged"
msgstr "imprimeix només les referències que s'han fusionat"
+#: builtin/for-each-ref.c
msgid "print only refs that are not merged"
msgstr "imprimeix només les referències que no s'han fusionat"
+#: builtin/for-each-ref.c
msgid "print only refs which contain the commit"
msgstr "imprimeix només les referències que continguin la comissió"
+#: builtin/for-each-ref.c
msgid "print only refs which don't contain the commit"
msgstr "imprimeix només les referències que no continguin la comissió"
+#: builtin/for-each-ref.c
msgid "read reference patterns from stdin"
msgstr "llegeix els patrons de referència de l'entrada estàndard"
+#: builtin/for-each-ref.c
+msgid "also include HEAD ref and pseudorefs"
+msgstr "inclou també la referència HEAD i les pseudoreferències"
+
+#: builtin/for-each-ref.c
msgid "unknown arguments supplied with --stdin"
msgstr "s'han proporcionat arguments desconeguts amb --stdin"
+#: builtin/for-each-repo.c
msgid "git for-each-repo --config=<config> [--] <arguments>"
msgstr "git for-each-repo --config=<config> [--] <arguments>"
+#: builtin/for-each-repo.c
msgid "config"
msgstr "config"
+#: builtin/for-each-repo.c
msgid "config key storing a list of repository paths"
msgstr "clau de configuració emmagatzemant una llista de camins de repositori"
+#: builtin/for-each-repo.c
+msgid "keep going even if command fails in a repository"
+msgstr "continua fins i tot si l'ordre falla en un repositori"
+
+#: builtin/for-each-repo.c
msgid "missing --config=<config>"
msgstr "falta --config=<config>"
+#: builtin/for-each-repo.c
#, c-format
msgid "got bad config --config=%s"
msgstr "s'ha obtingut una configuració incorrecta --config=%s"
+#: builtin/fsck.c
msgid "unknown"
msgstr "desconegut"
#. TRANSLATORS: e.g. error in tree 01bfda: <more explanation>
+#: builtin/fsck.c
#, c-format
msgid "error in %s %s: %s"
msgstr "error en %s %s: %s"
#. TRANSLATORS: e.g. warning in tree 01bfda: <more explanation>
+#: builtin/fsck.c
#, c-format
msgid "warning in %s %s: %s"
msgstr "avís en %s %s: %s"
+#: builtin/fsck.c
#, c-format
msgid "broken link from %7s %s"
msgstr "enllaç trencat de %7s %s"
+#: builtin/fsck.c
msgid "wrong object type in link"
msgstr "tipus d'objecte incorrecte en l'enllaç"
+#: builtin/fsck.c
#, c-format
msgid ""
"broken link from %7s %s\n"
@@ -6260,147 +8059,186 @@ msgstr ""
"enllaç trencat des de %7s %s\n"
" fins a %7s %s"
+#: builtin/fsck.c builtin/prune.c connected.c
msgid "Checking connectivity"
msgstr "S'està comprovant la connectivitat"
+#: builtin/fsck.c
#, c-format
msgid "missing %s %s"
msgstr "%s %s manca"
+#: builtin/fsck.c
#, c-format
msgid "unreachable %s %s"
msgstr "%s %s inabastable"
+#: builtin/fsck.c
#, c-format
msgid "dangling %s %s"
msgstr "%s %s sense assignació"
+#: builtin/fsck.c
msgid "could not create lost-found"
msgstr "no s'ha pogut crear el trobat-perdut"
+#: builtin/fsck.c builtin/gc.c builtin/rebase.c rebase-interactive.c rerere.c
+#: sequencer.c
#, c-format
msgid "could not write '%s'"
msgstr "no s'ha pogut escriure «%s»"
+#: builtin/fsck.c
#, c-format
msgid "could not finish '%s'"
msgstr "no s'ha pogut finalitzar «%s»"
+#: builtin/fsck.c
#, c-format
msgid "Checking %s"
msgstr "S'està comprovant %s"
+#: builtin/fsck.c
#, c-format
msgid "Checking connectivity (%d objects)"
msgstr "S'està comprovant la connectivitat (%d objectes)"
+#: builtin/fsck.c
#, c-format
msgid "Checking %s %s"
msgstr "S'està comprovant %s %s"
+#: builtin/fsck.c
msgid "broken links"
msgstr "enllaços trencats"
+#: builtin/fsck.c
#, c-format
msgid "root %s"
msgstr "arrel %s"
+#: builtin/fsck.c
#, c-format
msgid "tagged %s %s (%s) in %s"
msgstr "marcat %s %s (%s) a %s"
+#: builtin/fsck.c
#, c-format
msgid "%s: object corrupt or missing"
msgstr "%s: objecte corrupte o no trobat"
+#: builtin/fsck.c
#, c-format
msgid "%s: invalid reflog entry %s"
-msgstr "%s: entrada de referència no vàlida %s"
+msgstr "%s: entrada de registre de referències no vàlida %s"
+#: builtin/fsck.c
#, c-format
msgid "Checking reflog %s->%s"
-msgstr "S'està comprovant reflog %s->%s"
+msgstr "S'està comprovant el registre de referències %s->%s"
+#: builtin/fsck.c
#, c-format
msgid "%s: invalid sha1 pointer %s"
msgstr "%s: punter %s sha1 no vàlid"
+#: builtin/fsck.c
#, c-format
msgid "%s: not a commit"
msgstr "%s: no és una comissió"
+#: builtin/fsck.c
msgid "notice: No default references"
msgstr "avís: no hi ha referències per defecte"
+#: builtin/fsck.c
#, c-format
msgid "%s: hash-path mismatch, found at: %s"
msgstr "%s: el resum del camí no coincideix, trobat a: %s"
+#: builtin/fsck.c
#, c-format
msgid "%s: object corrupt or missing: %s"
msgstr "%s: objecte corrupte o no trobat: %s"
+#: builtin/fsck.c
#, c-format
msgid "%s: object is of unknown type '%s': %s"
msgstr "%s: l'objecte és de tipus desconegut «%s»: %s"
+#: builtin/fsck.c
#, c-format
msgid "%s: object could not be parsed: %s"
msgstr "%s: no s'ha pogut analitzar l'objecte: %s"
+#: builtin/fsck.c
#, c-format
msgid "bad sha1 file: %s"
msgstr "fitxer sha1 malmès: %s"
+#: builtin/fsck.c
msgid "Checking object directory"
msgstr "S'està comprovant el directori d'objecte"
+#: builtin/fsck.c
msgid "Checking object directories"
msgstr "S'estan comprovant els directoris d'objecte"
+#: builtin/fsck.c
#, c-format
msgid "Checking %s link"
msgstr "S'està comprovant l'enllaç %s"
+#: builtin/fsck.c builtin/index-pack.c
#, c-format
msgid "invalid %s"
msgstr "%s no vàlid"
+#: builtin/fsck.c
#, c-format
msgid "%s points to something strange (%s)"
msgstr "%s apunta a una cosa estranya (%s)"
+#: builtin/fsck.c
#, c-format
msgid "%s: detached HEAD points at nothing"
msgstr "%s: la HEAD separada no apunta a res"
+#: builtin/fsck.c
#, c-format
msgid "notice: %s points to an unborn branch (%s)"
msgstr "avís: %s apunta a una branca no nascuda (%s)"
+#: builtin/fsck.c
#, c-format
msgid "Checking cache tree of %s"
msgstr "S'està comprovant l'arbre de la memòria cau %s"
+#: builtin/fsck.c
#, c-format
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"
+#: builtin/fsck.c
msgid "non-tree in cache-tree"
msgstr "un no arbre en l'arbre de la memòria cau"
+#: builtin/fsck.c
#, c-format
msgid "%s: invalid sha1 pointer in resolve-undo of %s"
msgstr "%s: punter sha1 no vàlid a «resolve-undo» de %s"
+#: builtin/fsck.c
#, 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»"
+#: builtin/fsck.c
#, c-format
msgid "invalid rev-index for pack '%s'"
msgstr "rev-index no vàlid per al paquet «%s»"
+#: builtin/fsck.c
msgid ""
"git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
" [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
@@ -6412,159 +8250,205 @@ msgstr ""
" [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
" [--[no-]name-objects] [<objecte>...]"
+#: builtin/fsck.c
msgid "show unreachable objects"
msgstr "mostra els objectes inabastables"
+#: builtin/fsck.c
msgid "show dangling objects"
-msgstr "mostra els objectes penjants"
+msgstr "mostra els objectes despenjats"
+#: builtin/fsck.c
msgid "report tags"
msgstr "informa de les etiquetes"
+#: builtin/fsck.c
msgid "report root nodes"
msgstr "informa dels nodes d'arrel"
+#: builtin/fsck.c
msgid "make index objects head nodes"
-msgstr "fes dels objectes d'índex nodes cap"
+msgstr "fes dels objectes d'índex nodes HEAD"
+#: builtin/fsck.c
msgid "make reflogs head nodes (default)"
-msgstr "fes que els registres de referències siguin nodes cap (per defecte)"
+msgstr "fes que els registres de referències siguin nodes HEAD (per defecte)"
+#: builtin/fsck.c
msgid "also consider packs and alternate objects"
msgstr "també considera els paquets i els objectes alternatius"
+#: builtin/fsck.c
msgid "check only connectivity"
msgstr "comprova només la connectivitat"
+#: builtin/fsck.c builtin/mktag.c
msgid "enable more strict checking"
msgstr "habilita la comprovació més estricta"
+#: builtin/fsck.c
msgid "write dangling objects in .git/lost-found"
-msgstr "escriu objectes penjants a .git/lost-found"
+msgstr "escriu objectes despenjats a .git/lost-found"
+#: builtin/fsck.c builtin/prune.c
msgid "show progress"
msgstr "mostra el progrés"
+#: builtin/fsck.c
msgid "show verbose names for reachable objects"
msgstr "mostra els noms detallats dels objectes abastables"
+#: builtin/fsck.c builtin/index-pack.c
msgid "Checking objects"
msgstr "S'estan comprovant els objectes"
+#: builtin/fsck.c
#, c-format
msgid "%s: object missing"
msgstr "%s: falta l'objecte"
+#: builtin/fsck.c
#, c-format
msgid "invalid parameter: expected sha1, got '%s'"
msgstr "paràmetre no vàlid: s'esperava sha1, s'ha obtingut «%s»"
+#: builtin/fsmonitor--daemon.c
msgid "git fsmonitor--daemon start [<options>]"
msgstr "git fsmonitor--daemon start [<opcions>]"
+#: builtin/fsmonitor--daemon.c
msgid "git fsmonitor--daemon run [<options>]"
msgstr "git fsmonitor--daemon run [<opcions>]"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "value of '%s' out of range: %d"
msgstr "el valor de «%s» està fora de rang: %d"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "value of '%s' not bool or int: %d"
msgstr "valor de «%s» no és booleà ni enter: %d"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "fsmonitor-daemon is watching '%s'\n"
msgstr "fsmonitor-daemon està veient «%s»\n"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "fsmonitor-daemon is not watching '%s'\n"
msgstr "fsmonitor-daemon no està vigilant «%s»\n"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "could not create fsmonitor cookie '%s'"
msgstr "no s'ha pogut crear la galeta fsmonitor «%s»"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "fsmonitor: cookie_result '%d' != SEEN"
msgstr "fsmonitor: cookie_result «%d» != SEEN"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "could not start IPC thread pool on '%s'"
msgstr "no s'ha pogut iniciar el grup de fils IPC a «%s»"
+#: builtin/fsmonitor--daemon.c
msgid "could not start fsmonitor listener thread"
msgstr "no s'ha pogut iniciar el fil receptor del fsmonitor"
+#: builtin/fsmonitor--daemon.c
msgid "could not start fsmonitor health thread"
msgstr "no s'ha pogut iniciar el fil de salut del fsmonitor"
+#: builtin/fsmonitor--daemon.c
msgid "could not initialize listener thread"
msgstr "no s'ha pogut inicialitzar el fil receptor"
+#: builtin/fsmonitor--daemon.c
msgid "could not initialize health thread"
msgstr "no s'ha pogut inicialitzar el fil de salut"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "could not cd home '%s'"
msgstr "no s'ha pogut fer cd home «%s»"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "fsmonitor--daemon is already running '%s'"
msgstr "fsmonitor--daemon is already running «%s»"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "running fsmonitor-daemon in '%s'\n"
msgstr "s'està executant fsmonitor-daemon en «%s»\n"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "starting fsmonitor-daemon in '%s'\n"
msgstr "s'està iniciant fsmonitor-daemon a «%s»\n"
+#: builtin/fsmonitor--daemon.c
msgid "daemon failed to start"
msgstr "el dimoni ha fallat en iniciar"
+#: builtin/fsmonitor--daemon.c
msgid "daemon not online yet"
msgstr "el dimoni encara no està en línia"
+#: builtin/fsmonitor--daemon.c
msgid "daemon terminated"
msgstr "s'ha finalitzat el dimoni"
+#: builtin/fsmonitor--daemon.c
msgid "detach from console"
msgstr "separat de la consola"
+#: builtin/fsmonitor--daemon.c
msgid "use <n> ipc worker threads"
msgstr "usa <n> fils de treball ipc"
+#: builtin/fsmonitor--daemon.c
msgid "max seconds to wait for background daemon startup"
msgstr "màxim de segons a esperar a l'inici del dimoni en segon pla"
+#: builtin/fsmonitor--daemon.c
#, c-format
msgid "invalid 'ipc-threads' value (%d)"
msgstr "valor «ipc-threads» no vàlid (%d)"
+#: builtin/fsmonitor--daemon.c t/helper/test-cache-tree.c
#, c-format
msgid "Unhandled subcommand '%s'"
msgstr "Subordre no gestionada «%s»"
+#: builtin/fsmonitor--daemon.c
msgid "fsmonitor--daemon not supported on this platform"
msgstr "fsmonitor--daemon no és compatible amb aquesta plataforma"
+#: builtin/gc.c
msgid "git gc [<options>]"
msgstr "git gc [<opcions>]"
+#: builtin/gc.c
#, c-format
msgid "Failed to fstat %s: %s"
msgstr "S'ha produït un error en fer fstat %s: %s"
+#: builtin/gc.c
#, c-format
msgid "failed to parse '%s' value '%s'"
msgstr "no s'ha pogut analitzar «%s» valor «%s»"
+#: builtin/gc.c setup.c
#, c-format
msgid "cannot stat '%s'"
msgstr "no es pot fer stat en «%s»"
+#: builtin/gc.c
#, c-format
msgid ""
"The last gc run reported the following. Please correct the root cause\n"
@@ -6579,240 +8463,322 @@ msgstr ""
"\n"
"%s"
+#: builtin/gc.c
msgid "prune unreferenced objects"
msgstr "poda objectes sense referència"
+#: builtin/gc.c
msgid "pack unreferenced objects separately"
msgstr "empaqueta els objectes no referenciats de forma separada"
+#: builtin/gc.c builtin/repack.c
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "amb --cruft, limiteu la mida dels paquets cruft nous"
+
+#: builtin/gc.c
msgid "be more thorough (increased runtime)"
msgstr "sigues més exhaustiu (el temps d'execució augmenta)"
+#: builtin/gc.c
msgid "enable auto-gc mode"
msgstr "habilita el mode de recollida d'escombraries automàtica"
+#: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "fes la recollida de memòria brossa en segon pla"
+
+#: builtin/gc.c
msgid "force running gc even if there may be another gc running"
msgstr ""
"força l'execució de gc encara que hi pugui haver un altre gc executant-se"
+#: builtin/gc.c
msgid "repack all other packs except the largest pack"
msgstr "reempaqueta tots els altres paquets excepte el paquet més gran"
+#: builtin/gc.c
#, c-format
msgid "failed to parse gc.logExpiry value %s"
msgstr "no s'ha pogut analitzar el valor %s de gc.logExpiry"
+#: builtin/gc.c
#, c-format
msgid "failed to parse prune expiry value %s"
msgstr "no s'ha pogut analitzar el valor de venciment de la poda %s"
+#: builtin/gc.c
#, c-format
msgid "Auto packing the repository in background for optimum performance.\n"
msgstr ""
"S'està empaquetant el repositori automàticament en el rerefons per a un "
"rendiment òptim.\n"
+#: builtin/gc.c
#, c-format
msgid "Auto packing the repository for optimum performance.\n"
msgstr ""
"S'està empaquetant automàticament el repositori per a un rendiment òptim.\n"
+#: builtin/gc.c
#, c-format
msgid "See \"git help gc\" for manual housekeeping.\n"
msgstr "Vegeu «git help gc» per a neteja manual.\n"
+#: builtin/gc.c
#, c-format
msgid ""
"gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
msgstr ""
"gc ja s'està executant en la màquina «%s» pid %<PRIuMAX> (useu --force si no)"
+#: builtin/gc.c
msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
"Hi ha massa objectes solts inabastables; executeu «git prune» per a eliminar-"
"los."
+#: builtin/gc.c
msgid ""
"git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"
msgstr ""
"git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"
+#: builtin/gc.c
msgid "--no-schedule is not allowed"
msgstr "--no-schedule no està permès"
+#: builtin/gc.c
#, c-format
msgid "unrecognized --schedule argument '%s'"
msgstr "argument --schedule no reconegut, «%s»"
+#: builtin/gc.c
msgid "failed to write commit-graph"
msgstr "s'ha produït un error en escriure el graf de comissions"
+#: builtin/gc.c
msgid "failed to prefetch remotes"
msgstr "s'ha produït un error en preobtenir els remots"
+#: builtin/gc.c
msgid "failed to start 'git pack-objects' process"
msgstr "no s'ha pogut iniciar el procés «git pack-objects»"
+#: builtin/gc.c
msgid "failed to finish 'git pack-objects' process"
msgstr "no s'ha pogut finalitzar el procés «git pack-objects»"
+#: builtin/gc.c
msgid "failed to write multi-pack-index"
msgstr "no s'ha pogut escriure l'índex del multipaquet"
+#: builtin/gc.c
msgid "'git multi-pack-index expire' failed"
msgstr "ha fallat el venciment de «git multi-pack-index expire»"
+#: builtin/gc.c
msgid "'git multi-pack-index repack' failed"
msgstr "ha fallat l'execució de «git multi-pack-index repack»"
+#: builtin/gc.c
msgid ""
"skipping incremental-repack task because core.multiPackIndex is disabled"
msgstr ""
"s'està ometent la tasca incremental-repack perquè core.multiPackIndex està "
"desactivat"
+#: builtin/gc.c
#, c-format
msgid "lock file '%s' exists, skipping maintenance"
msgstr "el fitxer de bloqueig «%s» existeix, s'omet el manteniment"
+#: builtin/gc.c
#, c-format
msgid "task '%s' failed"
msgstr "la tasca «%s» ha fallat"
+#: builtin/gc.c
#, c-format
msgid "'%s' is not a valid task"
msgstr "«%s» no és una tasca vàlida"
+#: builtin/gc.c
#, c-format
msgid "task '%s' cannot be selected multiple times"
msgstr "la tasca «%s» no es pot seleccionar múltiples vegades"
+#: builtin/gc.c
msgid "run tasks based on the state of the repository"
msgstr "executa les tasques basades en l'estat del repositori"
+#: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "fes el manteniment en segon pla"
+
+#: builtin/gc.c
msgid "frequency"
msgstr "freqüència"
+#: builtin/gc.c
msgid "run tasks based on frequency"
msgstr "executa les tasques basant-se en freqüència"
+#: builtin/gc.c
msgid "do not report progress or other information over stderr"
-msgstr "no informeu sobre el progrés o altra informació as stderr"
+msgstr "no informeu sobre el progrés o altra informació a stderr"
+#: builtin/gc.c
msgid "task"
msgstr "tasca"
+#: builtin/gc.c
msgid "run a specific task"
msgstr "executa una tasca específica"
+#: builtin/gc.c
msgid "use at most one of --auto and --schedule=<frequency>"
-msgstr "usa com a màxim un entre --auto i --schedule=<frequency>"
+msgstr "usa com a màxim un entre --auto i --schedule=<freqüència>"
+#: builtin/gc.c
#, c-format
msgid "unable to add '%s' value of '%s'"
msgstr "no es pot afegir el valor «%s» de «%s»"
+#: builtin/gc.c
msgid "return success even if repository was not registered"
msgstr "retorna èxit encara que el repositori no estigui registrat"
+#: builtin/gc.c
#, c-format
msgid "unable to unset '%s' value of '%s'"
msgstr "no es pot desassignar el valor «%s» de «%s»"
+#: builtin/gc.c
#, c-format
msgid "repository '%s' is not registered"
msgstr "el repositori «%s» no està registrat"
+#: builtin/gc.c
#, c-format
msgid "failed to expand path '%s'"
msgstr "s'ha produït un error en expandir el camí «%s»"
+#: builtin/gc.c
msgid "failed to start launchctl"
msgstr "s'ha produït un error en iniciar launchctl"
+#: builtin/gc.c
#, c-format
msgid "failed to create directories for '%s'"
msgstr "s'ha produït un error en crear els directoris per a «%s»"
+#: builtin/gc.c
#, c-format
msgid "failed to bootstrap service %s"
msgstr "s'ha produït un error en arrencar el servei %s"
+#: builtin/gc.c
msgid "failed to create temp xml file"
msgstr "no s'han pogut crear un fitxer xml temporal"
+#: builtin/gc.c
msgid "failed to start schtasks"
msgstr "s'ha produït un error en iniciar schtasks"
+#: builtin/gc.c
msgid "failed to run 'crontab -l'; your system might not support 'cron'"
msgstr ""
"no s'ha pogut executar «crontab -l»; el vostre sistema podria no admetre "
"«cron»"
+#: builtin/gc.c
msgid "failed to create crontab temporary file"
msgstr "no s'ha pogut crear un fitxer temporal crontab"
+#: builtin/gc.c
msgid "failed to open temporary file"
msgstr "no s'ha pogut obrir el fitxer temporal"
+#: builtin/gc.c
msgid "failed to run 'crontab'; your system might not support 'cron'"
msgstr ""
"no s'ha pogut executar «crontab»; el vostre sistema podria no admetre «cron»"
+#: builtin/gc.c
msgid "'crontab' died"
msgstr "«crontab» ha mort"
-msgid "failed to start systemctl"
-msgstr "s'ha produït un error en iniciar systemctl"
-
-msgid "failed to run systemctl"
-msgstr "s'ha produït un error en executar systemctl"
-
+#: builtin/gc.c builtin/worktree.c
#, c-format
msgid "failed to delete '%s'"
msgstr "s'ha produït un error en suprimir «%s»"
+#: builtin/gc.c rerere.c
#, c-format
msgid "failed to flush '%s'"
msgstr "no s'ha pogut buidar «%s»"
+#: builtin/gc.c
+msgid "failed to start systemctl"
+msgstr "s'ha produït un error en iniciar systemctl"
+
+#: builtin/gc.c
+msgid "failed to run systemctl"
+msgstr "s'ha produït un error en executar systemctl"
+
+#: builtin/gc.c
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "l'argument --scheduler no reconegut «%s»"
+#: builtin/gc.c
msgid "neither systemd timers nor crontab are available"
msgstr "ni els temporitzadors de systemd ni de crontab estan disponibles"
+#: builtin/gc.c
#, c-format
msgid "%s scheduler is not available"
msgstr "el planificador %s no està disponible"
+#: builtin/gc.c
msgid "another process is scheduling background maintenance"
msgstr "un altre procés està planificant un manteniment en segon pla"
+#: builtin/gc.c
msgid "git maintenance start [--scheduler=<scheduler>]"
msgstr "git maintenance start [--scheduler=<scheduler>]"
+#: builtin/gc.c
msgid "scheduler"
msgstr "planificador"
+#: builtin/gc.c
msgid "scheduler to trigger git maintenance run"
msgstr "planificador per a activar l'execució de manteniment del git"
+#: builtin/gc.c
+msgid "failed to set up maintenance schedule"
+msgstr "no s'ha pogut configurar la planificació del manteniment"
+
+#: builtin/gc.c
msgid "failed to add repo to global config"
msgstr "no s'ha pogut afegir un repositori a la configuració global"
+#: builtin/gc.c
msgid "git maintenance <subcommand> [<options>]"
-msgstr "git maintenance <subcommand> [<opcions>]"
+msgstr "git maintenance <subordre> [<opcions>]"
+#: builtin/grep.c
msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
msgstr "git grep [<opcions>] [-e] <patró> [<revisió>...] [[--] <camí>...]"
+#: builtin/grep.c
#, c-format
msgid "grep: failed to create thread: %s"
msgstr "grep: s'ha produït un error en crear fil: %s"
+#: builtin/grep.c
#, c-format
msgid "invalid number of threads specified (%d) for %s"
msgstr "s'ha especificat un nombre de fils no vàlid (%d) per a %s"
@@ -6822,199 +8788,261 @@ msgstr "s'ha especificat un nombre de fils no vàlid (%d) per a %s"
#. variable for tweaking threads, currently
#. grep.threads
#.
+#: builtin/grep.c builtin/index-pack.c builtin/pack-objects.c
#, c-format
msgid "no threads support, ignoring %s"
msgstr "no s'admeten fils, s'ignorarà %s"
+#: builtin/grep.c
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "no s'ha pogut llegir l'arbre (%s)"
+msgid "unable to read tree %s"
+msgstr "no s'ha pogut llegir l'arbre %s"
+#: builtin/grep.c
#, c-format
msgid "unable to grep from object of type %s"
msgstr "no es pot fer grep des d'un objecte de tipus %s"
+#: builtin/grep.c
#, c-format
msgid "switch `%c' expects a numerical value"
msgstr "l'opció «%c» espera un valor numèric"
+#: builtin/grep.c
msgid "search in index instead of in the work tree"
msgstr "cerca en l'índex en lloc de l'arbre de treball"
+#: builtin/grep.c
msgid "find in contents not managed by git"
msgstr "cerca en continguts no gestionats per git"
+#: builtin/grep.c
msgid "search in both tracked and untracked files"
msgstr "cerca tant en fitxers seguits com en no seguits"
+#: builtin/grep.c
msgid "ignore files specified via '.gitignore'"
msgstr "ignora els fitxers especificats mitjançant «.gitignore»"
+#: builtin/grep.c
msgid "recursively search in each submodule"
msgstr "cerca recursivament a cada submòdul"
+#: builtin/grep.c
msgid "show non-matching lines"
msgstr "mostra les línies no coincidents"
+#: builtin/grep.c
msgid "case insensitive matching"
msgstr "coincidència no distingeix entre majúscules i minúscules"
+#: builtin/grep.c
msgid "match patterns only at word boundaries"
msgstr "coincideix amb els patrons només als límits de paraula"
+#: builtin/grep.c
msgid "process binary files as text"
msgstr "processa els fitxers binaris com a text"
+#: builtin/grep.c
msgid "don't match patterns in binary files"
msgstr "no cerquis els patrons en els fitxers binaris"
+#: builtin/grep.c
msgid "process binary files with textconv filters"
msgstr "processa els fitxers binaris amb filtres de textconv"
+#: builtin/grep.c
msgid "search in subdirectories (default)"
msgstr "cerca als subdirectoris (per defecte)"
-msgid "descend at most <depth> levels"
-msgstr "descendeix com a màxim <profunditat> nivells"
+#: builtin/grep.c
+msgid "descend at most <n> levels"
+msgstr "descendeix com a màxim <n> nivells"
+#: builtin/grep.c
msgid "use extended POSIX regular expressions"
msgstr "usa les expressions regulars POSIX ampliades"
+#: builtin/grep.c
msgid "use basic POSIX regular expressions (default)"
msgstr "usa les expressions regulars POSIX bàsiques (per defecte)"
+#: builtin/grep.c
msgid "interpret patterns as fixed strings"
msgstr "interpreta els patrons com a cadenes fixes"
+#: builtin/grep.c
msgid "use Perl-compatible regular expressions"
msgstr "usa les expressions regulars compatibles amb Perl"
+#: builtin/grep.c
msgid "show line numbers"
msgstr "mostra els números de línia"
+#: builtin/grep.c
msgid "show column number of first match"
msgstr "mostra el nombre de columna de la primera coincidència"
+#: builtin/grep.c
msgid "don't show filenames"
msgstr "no mostris els noms de fitxer"
+#: builtin/grep.c
msgid "show filenames"
msgstr "mostra els noms de fitxer"
+#: builtin/grep.c
msgid "show filenames relative to top directory"
msgstr "mostra els noms de fitxer relatius al directori superior"
+#: builtin/grep.c
msgid "show only filenames instead of matching lines"
msgstr "mostra només els noms de fitxer en lloc de les línies coincidents"
+#: builtin/grep.c
msgid "synonym for --files-with-matches"
msgstr "sinònim de --files-with-matches"
+#: builtin/grep.c
msgid "show only the names of files without match"
msgstr "mostra només els noms dels fitxers sense coincidència"
+#: builtin/grep.c
msgid "print NUL after filenames"
msgstr "imprimeix NUL després dels noms de fitxer"
+#: builtin/grep.c
msgid "show only matching parts of a line"
msgstr "mostra només les parts de coincidents de la línia"
+#: builtin/grep.c
msgid "show the number of matches instead of matching lines"
msgstr "mostra el nombre de coincidències en lloc de les línies coincidents"
+#: builtin/grep.c
msgid "highlight matches"
msgstr "ressalta les coincidències"
+#: builtin/grep.c
msgid "print empty line between matches from different files"
msgstr "imprimeix una línia buida entre coincidències de fitxers distints"
+#: builtin/grep.c
msgid "show filename only once above matches from same file"
msgstr ""
"mostra el nom de fitxer només una vegada a dalt de les coincidències del "
"mateix fitxer"
+#: builtin/grep.c
msgid "show <n> context lines before and after matches"
msgstr "mostra <n> línies de context abans i després d'una coincidència"
+#: builtin/grep.c
msgid "show <n> context lines before matches"
msgstr "mostra <n> línies de context abans d'una coincidència"
+#: builtin/grep.c
msgid "show <n> context lines after matches"
msgstr "mostra <n> línies de context després d'una coincidència"
+#: builtin/grep.c
msgid "use <n> worker threads"
msgstr "usa <n> fils de treball"
+#: builtin/grep.c
msgid "shortcut for -C NUM"
msgstr "drecera per a -C NUM"
+#: builtin/grep.c
msgid "show a line with the function name before matches"
msgstr "mostra una línia amb el nom de funció abans de les coincidències"
+#: builtin/grep.c
msgid "show the surrounding function"
msgstr "mostra la funció circumdant"
+#: builtin/grep.c
msgid "read patterns from file"
msgstr "llegeix els patrons des d'un fitxer"
+#: builtin/grep.c
msgid "match <pattern>"
msgstr "coincideix amb <patró>"
+#: builtin/grep.c
msgid "combine patterns specified with -e"
msgstr "combina els patrons especificats amb -e"
+#: builtin/grep.c
msgid "indicate hit with exit status without output"
msgstr "indica coincidència amb estat de sortida sense sortida textual"
+#: builtin/grep.c
msgid "show only matches from files that match all patterns"
msgstr ""
"mostra només les coincidències dels fitxers que coincideixin amb tots els "
"patrons"
+#: builtin/grep.c
msgid "pager"
msgstr "paginador"
+#: builtin/grep.c
msgid "show matching files in the pager"
msgstr "mostra els fitxers coincidents en el paginador"
+#: builtin/grep.c
msgid "allow calling of grep(1) (ignored by this build)"
msgstr "permet la invocació de grep(1) (ignorat per aquesta compilació)"
+#: builtin/grep.c
msgid "maximum number of results per file"
msgstr "nombre màxim de resultats per fitxer"
+#: builtin/grep.c
msgid "no pattern given"
msgstr "no s'ha donat cap patró"
+#: builtin/grep.c
msgid "--no-index or --untracked cannot be used with revs"
msgstr "--no-index o --untracked no es pot usar amb revisions"
+#: builtin/grep.c
#, c-format
msgid "unable to resolve revision: %s"
msgstr "no s'ha pogut resoldre la revisió: %s"
+#: builtin/grep.c
msgid "--untracked not supported with --recurse-submodules"
msgstr "--untracked no s'admet amb --recurse-submodules"
+#: builtin/grep.c
msgid "invalid option combination, ignoring --threads"
msgstr "combinació d'opcions no vàlida, s'està ignorant --threads"
+#: builtin/grep.c builtin/pack-objects.c
msgid "no threads support, ignoring --threads"
msgstr "no s'admeten fils, s'ignorarà --threads"
+#: builtin/grep.c builtin/index-pack.c builtin/pack-objects.c
#, c-format
msgid "invalid number of threads specified (%d)"
msgstr "s'ha especificat un nombre de fils no vàlid (%d)"
+#: builtin/grep.c
msgid "--open-files-in-pager only works on the worktree"
msgstr "--open-files-in-pager només funciona en l'arbre de treball"
+#: builtin/grep.c
msgid "--[no-]exclude-standard cannot be used for tracked contents"
msgstr "--[no-]exclude-standard no es pot utilitzar per als continguts seguits"
+#: builtin/grep.c
msgid "both --cached and trees are given"
msgstr "ambdós --cached i arbres venen donats"
+#: builtin/hash-object.c
msgid ""
"git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
" [--stdin [--literally]] [--] <file>..."
@@ -7022,91 +9050,117 @@ msgstr ""
"git hash-object [-t <tipus>] [-w] [--path=<fitxer> | --no-filters]\n"
" [--stdin [--literally]] [--] <fitxer>..."
+#: builtin/hash-object.c
msgid "git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"
msgstr "git hash-object [-t <tipus>] [-w] --stdin-paths [--no-filters]"
+#: builtin/hash-object.c
msgid "object type"
msgstr "tipus d'objecte"
+#: builtin/hash-object.c
msgid "write the object into the object database"
msgstr "escriu l'objecte a la base de dades d'objectes"
+#: builtin/hash-object.c
msgid "read the object from stdin"
msgstr "llegeix l'objecte des de stdin"
+#: builtin/hash-object.c
msgid "store file as is without filters"
msgstr "emmagatzema el fitxer tal com és sense filtres"
+#: builtin/hash-object.c
msgid ""
"just hash any random garbage to create corrupt objects for debugging Git"
msgstr ""
"només suma qualsevol brossa aleatòria per a crear objectes malmesos per a "
"depurar al Git"
+#: builtin/hash-object.c
msgid "process file as it were from this path"
msgstr "processa el fitxer com si fos d'aquest camí"
+#: builtin/help.c
msgid "print all available commands"
msgstr "imprimeix totes les ordres disponibles"
+#: builtin/help.c
msgid "show external commands in --all"
msgstr "mostra les ordres externes a --all"
+#: builtin/help.c
msgid "show aliases in --all"
msgstr "mostra els àlies a --all"
+#: builtin/help.c
msgid "exclude guides"
msgstr "exclou guies"
+#: builtin/help.c
msgid "show man page"
msgstr "mostra la pàgina de manual"
+#: builtin/help.c
msgid "show manual in web browser"
msgstr "mostra la pàgina de manual en el navegador web"
+#: builtin/help.c
msgid "show info page"
msgstr "mostra la pàgina d'informació"
+#: builtin/help.c
msgid "print command description"
msgstr "imprimeix la descripció de l'ordre"
+#: builtin/help.c
msgid "print list of useful guides"
msgstr "imprimeix la llista de guies útils"
+#: builtin/help.c
msgid "print list of user-facing repository, command and file interfaces"
msgstr ""
"imprimeix la llista de repositoris, ordres i interfícies de fitxers que veu "
"l'usuari"
+#: builtin/help.c
msgid "print list of file formats, protocols and other developer interfaces"
msgstr ""
"mostra la llista de formats de fitxer, protocols i altres interfícies de "
"desenvolupador"
+#: builtin/help.c
msgid "print all configuration variable names"
msgstr "imprimeix tots els noms de les variables de configuració"
+#: builtin/help.c
msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<ordre>|<doc>]"
+#: builtin/help.c
#, c-format
msgid "unrecognized help format '%s'"
msgstr "format d'ajuda no reconegut «%s»"
+#: builtin/help.c
msgid "Failed to start emacsclient."
msgstr "S'ha produït un error en iniciar emacsclient."
+#: builtin/help.c
msgid "Failed to parse emacsclient version."
msgstr "S'ha produït un error en analitzar la versió d'emacsclient."
+#: builtin/help.c
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
msgstr "la versió d'emacsclient «%d» és massa vella (< 22)."
+#: builtin/help.c
#, c-format
msgid "failed to exec '%s'"
msgstr "s'ha produït un error en executar «%s»"
+#: builtin/help.c
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
@@ -7115,6 +9169,7 @@ msgstr ""
"«%s»: camí a un visualitzador de manuals no compatible.\n"
"Considereu usar «man.<eina>.cmd» en lloc d'això."
+#: builtin/help.c
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
@@ -7123,41 +9178,51 @@ msgstr ""
"«%s»: ordre per a un visualitzador de manuals compatible.\n"
"Considereu usar «man.<eina>.path» en lloc d'això."
+#: builtin/help.c
#, c-format
msgid "'%s': unknown man viewer."
msgstr "«%s»: visualitzador de manuals desconegut."
+#: builtin/help.c
msgid "no man viewer handled the request"
msgstr "cap visualitzador de manuals ha gestionat la sol·licitud"
+#: builtin/help.c
msgid "no info viewer handled the request"
msgstr "cap visualitzador d'informació ha gestionat la sol·licitud"
+#: builtin/help.c git.c
#, c-format
msgid "'%s' is aliased to '%s'"
msgstr "«%s» és un àlies de «%s»"
+#: builtin/help.c git.c
#, c-format
msgid "bad alias.%s string: %s"
msgstr "cadena «alias.%s» incorrecte: %s"
+#: builtin/help.c
#, c-format
msgid "the '%s' option doesn't take any non-option arguments"
msgstr "l'opció «%s» no pren cap argument que no sigui una opció"
+#: builtin/help.c
msgid ""
"the '--no-[external-commands|aliases]' options can only be used with '--all'"
msgstr ""
"les opcions «--no-[external-commands|aliases]» només es poden utilitzar amb "
"«--all»"
+#: builtin/help.c
#, c-format
msgid "usage: %s%s"
msgstr "ús: %s%s"
+#: builtin/help.c
msgid "'git help config' for more information"
msgstr "«git help config» per a més informació"
+#: builtin/hook.c
msgid ""
"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
"args>]"
@@ -7165,75 +9230,95 @@ msgstr ""
"git hook run [--ignore-missing] [--to-stdin=<camí>] <hook-name> [-- <hook-"
"args>]"
+#: builtin/hook.c
msgid "silently ignore missing requested <hook-name>"
msgstr "ignora silenciosament la sol·licitud <hook-name> perduda"
+#: builtin/hook.c
msgid "file to read into hooks' stdin"
msgstr "fitxer per a llegir a l'entrada estàndard dels lligams"
+#: builtin/index-pack.c
#, c-format
msgid "object type mismatch at %s"
msgstr "hi ha una discordança de tipus d'objecte a %s"
+#: builtin/index-pack.c
#, c-format
msgid "did not receive expected object %s"
msgstr "no s'ha rebut l'objecte esperat %s"
+#: builtin/index-pack.c
#, c-format
msgid "object %s: expected type %s, found %s"
msgstr "objecte %s: s'esperava el tipus %s, s'ha trobat %s"
+#: builtin/index-pack.c
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "no es pot omplir %d octet"
msgstr[1] "no es poden omplir %d octets"
+#: builtin/index-pack.c
msgid "early EOF"
msgstr "EOF prematur"
+#: builtin/index-pack.c
msgid "read error on input"
msgstr "error de lectura d'entrada"
+#: builtin/index-pack.c
msgid "used more bytes than were available"
msgstr "s'han usat més octets que hi havia disponibles"
+#: builtin/index-pack.c builtin/pack-objects.c
msgid "pack too large for current definition of off_t"
msgstr "paquet massa gran per a la definició actual d'off_t"
+#: builtin/index-pack.c
#, c-format
msgid "pack exceeds maximum allowed size (%s)"
msgstr "el paquet supera la mida màxima permesa (%s)"
+#: builtin/index-pack.c
msgid "pack signature mismatch"
msgstr "hi ha una discordança de signatura de paquet"
+#: builtin/index-pack.c
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr "la versió de paquet %<PRIu32> no és compatible"
+#: builtin/index-pack.c
#, c-format
msgid "pack has bad object at offset %<PRIuMAX>: %s"
msgstr "el paquet té un objecte incorrecte a la posició %<PRIuMAX>: %s"
+#: builtin/index-pack.c
#, c-format
msgid "inflate returned %d"
msgstr "la inflació ha retornat %d"
+#: builtin/index-pack.c
msgid "offset value overflow for delta base object"
msgstr ""
"desbordament de valor de desplaçament per a l'objecte base de diferències"
+#: builtin/index-pack.c
msgid "delta base offset is out of bound"
msgstr "el desplaçament de base de diferències està fora de límits"
+#: builtin/index-pack.c
#, c-format
msgid "unknown object type %d"
msgstr "tipus d'objecte desconegut %d"
+#: builtin/index-pack.c
msgid "cannot pread pack file"
msgstr "no es pot fer pread en el fitxer empaquetat"
+#: builtin/index-pack.c
#, c-format
msgid "premature end of pack file, %<PRIuMAX> byte missing"
msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
@@ -7241,189 +9326,234 @@ msgstr[0] "el final del fitxer empaquetat és prematur, manca %<PRIuMAX> octet"
msgstr[1] ""
"el final del fitxer empaquetat és prematur, manquen %<PRIuMAX> octets"
+#: builtin/index-pack.c
msgid "serious inflate inconsistency"
msgstr "hi ha una inconsistència seriosa d'inflació"
+#: builtin/index-pack.c
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "S'HA TROBAT UNA COL·LISIÓ SHA1 AMB %s !"
-#, c-format
-msgid "unable to read %s"
-msgstr "no s'ha pogut llegir %s"
-
+#: builtin/index-pack.c
#, c-format
msgid "cannot read existing object info %s"
msgstr "no es pot llegir la informació d'objecte existent %s"
+#: builtin/index-pack.c
#, c-format
msgid "cannot read existing object %s"
msgstr "no es pot llegir l'objecte existent %s"
+#: builtin/index-pack.c
#, c-format
msgid "invalid blob object %s"
msgstr "objecte de blob no vàlid %s"
+#: builtin/index-pack.c
msgid "fsck error in packed object"
msgstr "fsck error en un objecte empaquetat"
+#: builtin/index-pack.c
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "No tots els objectes fills de %s són abastables"
+#: builtin/index-pack.c
msgid "failed to apply delta"
msgstr "s'ha produït un error en aplicar la diferència"
+#: builtin/index-pack.c
msgid "Receiving objects"
msgstr "S'estan rebent objectes"
+#: builtin/index-pack.c
msgid "Indexing objects"
msgstr "S'estan indexant objectes"
+#: builtin/index-pack.c
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "el paquet és malmès (discordança SHA1)"
+#: builtin/index-pack.c
msgid "cannot fstat packfile"
msgstr "no es pot fer fstat en el fitxer de paquet"
+#: builtin/index-pack.c
msgid "pack has junk at the end"
msgstr "el paquet té brossa al seu final"
+#: builtin/index-pack.c
msgid "confusion beyond insanity in parse_pack_objects()"
msgstr "confusió més enllà de la bogeria en parse_pack_objects()"
+#: builtin/index-pack.c
msgid "Resolving deltas"
msgstr "S'estan resolent les diferències"
+#: builtin/index-pack.c builtin/pack-objects.c
#, c-format
msgid "unable to create thread: %s"
msgstr "no s'ha pogut crear fil: %s"
+#: builtin/index-pack.c
msgid "confusion beyond insanity"
msgstr "confusió més enllà de la bogeria"
+#: builtin/index-pack.c
#, c-format
msgid "completed with %d local object"
msgid_plural "completed with %d local objects"
msgstr[0] "s'ha completat amb %d objecte local"
msgstr[1] "s'ha completat amb %d objectes locals"
+#: builtin/index-pack.c
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr "Suma de verificació final no esperada per a %s (corrupció de disc?)"
+#: builtin/index-pack.c
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] "el paquet té %d diferència no resolta"
msgstr[1] "el paquet té %d diferències no resoltes"
+#: builtin/index-pack.c
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "no s'ha pogut desinflar l'objecte annexat (%d)"
+#: builtin/index-pack.c
#, c-format
msgid "local object %s is corrupt"
msgstr "l'objecte local %s és malmès"
+#: builtin/index-pack.c
#, c-format
msgid "packfile name '%s' does not end with '.%s'"
msgstr "el nom del fitxer de paquet «%s» no acaba amb «.%s»"
+#: builtin/index-pack.c
#, c-format
msgid "cannot write %s file '%s'"
msgstr "no es pot escriure «%s» al fitxer «%s»"
+#: builtin/index-pack.c
#, c-format
msgid "cannot close written %s file '%s'"
msgstr "no s'ha pogut tancar el fitxer %s escrit «%s»"
+#: builtin/index-pack.c
#, c-format
msgid "unable to rename temporary '*.%s' file to '%s'"
msgstr "no s'ha pogut canviar el nom del fitxer temporal «*.%s» a «%s»"
+#: builtin/index-pack.c
msgid "error while closing pack file"
msgstr "error en tancar el fitxer empaquetat"
+#: builtin/index-pack.c builtin/pack-objects.c
#, c-format
msgid "bad pack.indexVersion=%<PRIu32>"
msgstr "bad pack.indexVersion=%<PRIu32>"
+#: builtin/index-pack.c
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "No es pot obrir el fitxer empaquetat existent «%s»"
+#: builtin/index-pack.c
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "No es pot obrir el fitxer d'índex de paquets existent de «%s»"
+#: builtin/index-pack.c
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] "sense diferències: %d objecte"
msgstr[1] "sense diferències: %d objectes"
+#: builtin/index-pack.c
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
msgstr[0] "longitud de cadena = %d: %lu objecte"
msgstr[1] "longitud de cadena = %d: %lu objectes"
+#: builtin/index-pack.c
msgid "Cannot come back to cwd"
msgstr "No es pot tornar al directori de treball actual"
+#: builtin/index-pack.c
#, c-format
msgid "bad %s"
msgstr "%s incorrecte"
+#: builtin/index-pack.c builtin/init-db.c setup.c
#, c-format
msgid "unknown hash algorithm '%s'"
msgstr "algorisme de resum desconegut «%s»"
+#: builtin/index-pack.c
msgid "--stdin requires a git repository"
msgstr "--stdin requereix un repositori git"
+#: builtin/index-pack.c
msgid "--verify with no packfile name given"
msgstr "s'ha donat --verify sense nom de fitxer de paquet"
+#: builtin/index-pack.c builtin/unpack-objects.c
msgid "fsck error in pack objects"
msgstr "error fsck als objectes del paquet"
+#: builtin/init-db.c
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
-" [--shared[=<permissions>]] [<directory>]"
+" [--shared[=<permissions>]] [<directori>]"
+#: builtin/init-db.c
msgid "permissions"
msgstr "permisos"
+#: builtin/init-db.c
msgid "specify that the git repository is to be shared amongst several users"
msgstr ""
"especifica que el repositori de git es compartirà entre diversos usuaris"
+#: builtin/init-db.c
msgid "override the name of the initial branch"
msgstr "sobreescriu el nom de la branca inicial"
+#: builtin/init-db.c builtin/verify-pack.c
msgid "hash"
msgstr "resum"
+#: builtin/init-db.c builtin/show-index.c builtin/verify-pack.c
msgid "specify the hash algorithm to use"
msgstr "especifiqueu l'algorisme de resum a usar"
+#: builtin/init-db.c
#, c-format
msgid "cannot mkdir %s"
msgstr "no es pot mkdir %s"
+#: builtin/init-db.c
#, c-format
msgid "cannot chdir to %s"
msgstr "no es pot canviar de directori a %s"
+#: builtin/init-db.c
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -7432,166 +9562,252 @@ msgstr ""
"no es permet %s (o --work-tree=<directori>) sense especificar %s (o --git-"
"dir=<directori>)"
+#: builtin/init-db.c
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "No es pot accedir a l'arbre de treball «%s»"
+#: builtin/init-db.c
msgid "--separate-git-dir incompatible with bare repository"
msgstr "--separate-git-dir és incompatible amb un repositori nu"
+#: builtin/interpret-trailers.c
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<clau>|<alies-clau>)[(=|:)<valor>])...]\n"
" [--parse] [<fitxer>...]"
+#: builtin/interpret-trailers.c wrapper.c
+#, c-format
+msgid "could not stat %s"
+msgstr "no s'ha pogut fer stat a %s"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "el fitxer %s no és un fitxer regular"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "el fitxer %s no és gravable per l'usuari"
+
+#: builtin/interpret-trailers.c
+msgid "could not open temporary file"
+msgstr "no s'ha pogut obrir el fitxer temporal"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "no s'ha pogut llegir el fitxer d'entrada «%s»"
+
+#: builtin/interpret-trailers.c builtin/mktag.c imap-send.c
+msgid "could not read from stdin"
+msgstr "no s'ha pogut llegir des de stdin"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "no s'ha pogut canviar el nom del fitxer temporal a %s"
+
+#: builtin/interpret-trailers.c
msgid "edit files in place"
msgstr "edita els fitxers in situ"
+#: builtin/interpret-trailers.c
msgid "trim empty trailers"
msgstr "escurça els remolcs buits"
+#: builtin/interpret-trailers.c
+msgid "placement"
+msgstr "posicionament"
+
+#: builtin/interpret-trailers.c
msgid "where to place the new trailer"
msgstr "on ubicar el «trailer» nou"
+#: builtin/interpret-trailers.c
msgid "action if trailer already exists"
msgstr "acció si el «trailer» ja existeix"
+#: builtin/interpret-trailers.c
msgid "action if trailer is missing"
msgstr "acció si el «trailer» falta"
+#: builtin/interpret-trailers.c
msgid "output only the trailers"
msgstr "mostra només els «trailer»"
-msgid "do not apply config rules"
-msgstr "no apliquis les regles de configuració"
+#: builtin/interpret-trailers.c
+msgid "do not apply trailer.* configuration variables"
+msgstr "no apliquis les variables de configuració trailer.*"
-msgid "join whitespace-continued values"
-msgstr "uneix els valors continus amb espais en blanc"
+#: builtin/interpret-trailers.c
+msgid "reformat multiline trailer values as single-line values"
+msgstr ""
+"reformata els valors del tràiler multilínia com a valors de línia única"
-msgid "set parsing options"
-msgstr "estableix les opcions d'anàlisi"
+#: builtin/interpret-trailers.c
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "àlies per a --only-trailers --only-input --unfold"
-msgid "do not treat --- specially"
-msgstr "no tractis --- especialment"
+#: builtin/interpret-trailers.c
+msgid "do not treat \"---\" as the end of input"
+msgstr "no tractis «---» com el final de l'entrada"
+#: builtin/interpret-trailers.c
msgid "trailer(s) to add"
msgstr "remolcs a afegir"
+#: builtin/interpret-trailers.c
msgid "--trailer with --only-input does not make sense"
msgstr "--trailer amb --only-input no té sentit"
+#: builtin/interpret-trailers.c
msgid "no input file given for in-place editing"
msgstr "no s'ha donat cap fitxer d'entrada per a edició in situ"
+#: builtin/log.c
msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
msgstr "git log [<opcions>] [<rang-de-revisions>] [[--] <camí>...]"
+#: builtin/log.c
msgid "git show [<options>] <object>..."
msgstr "git show [<opcions>] <objecte>..."
+#: builtin/log.c
#, c-format
msgid "invalid --decorate option: %s"
msgstr "opció --decorate no vàlida: %s"
+#: builtin/log.c diff.c
msgid "suppress diff output"
msgstr "omet la sortida de diferències"
+#: builtin/log.c
msgid "show source"
msgstr "mostra la font"
+#: builtin/log.c
msgid "clear all previously-defined decoration filters"
msgstr "neteja tots els filtres de decoració prèviament definits"
+#: builtin/log.c
msgid "only decorate refs that match <pattern>"
msgstr "només decora les referències que coincideixin amb <patró>"
+#: builtin/log.c
msgid "do not decorate refs that match <pattern>"
msgstr "no decoris les referències que coincideixen amb <patró>"
+#: builtin/log.c
msgid "decorate options"
msgstr "opcions de decoració"
+#: builtin/log.c
msgid ""
"trace the evolution of line range <start>,<end> or function :<funcname> in "
"<file>"
msgstr ""
-"traça l'evolució del rang de línia <start>,<end> o funcions :<funcname> a "
-"<fitxer>"
+"traça l'evolució del rang de línia <inici>,<final> o funcions :<nom-funció> "
+"a <fitxer>"
+#: builtin/log.c builtin/replay.c builtin/shortlog.c bundle.c
#, c-format
msgid "unrecognized argument: %s"
msgstr "argument no reconegut: %s"
+#: builtin/log.c
msgid "-L<range>:<file> cannot be used with pathspec"
-msgstr "-L<range>:<fitxer> no es pot usar amb una especificació de camí"
+msgstr "-L<rang>:<fitxer> no es pot usar amb una especificació de camí"
+#: builtin/log.c
#, c-format
msgid "Final output: %d %s\n"
msgstr "Sortida final: %d %s\n"
-msgid "unable to create temporary object directory"
-msgstr "no s'ha pogut crear el directori temporal de l'objecte"
-
+#: builtin/log.c
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: fitxer incorrecte"
+#: builtin/log.c
#, c-format
msgid "could not read object %s"
msgstr "no s'ha pogut llegir l'objecte %s"
+#: builtin/log.c
#, c-format
msgid "unknown type: %d"
msgstr "tipus desconegut: %d"
+#: builtin/log.c
#, c-format
msgid "%s: invalid cover from description mode"
msgstr "%s: cobertura no vàlida des del mode descripció"
+#: builtin/log.c
msgid "format.headers without value"
msgstr "format.headers sense valor"
+#: builtin/log.c
#, c-format
msgid "cannot open patch file %s"
msgstr "no s'ha pogut obrir el fitxer de pedaç %s"
+#: builtin/log.c
msgid "need exactly one range"
msgstr "necessita exactament un interval"
+#: builtin/log.c
msgid "not a range"
msgstr "no és un interval"
+#: builtin/log.c
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "no es pot llegir el fitxer de descripció de la branca «%s»"
+
+#: builtin/log.c
msgid "cover letter needs email format"
msgstr "la carta de presentació necessita un format de correu electrònic"
+#: builtin/log.c
msgid "failed to create cover-letter file"
msgstr "s'ha produït un error en crear el fitxer de carta de presentació"
+#: builtin/log.c
#, c-format
msgid "insane in-reply-to: %s"
msgstr "in-reply-to boig: %s"
+#: builtin/log.c
msgid "git format-patch [<options>] [<since> | <revision-range>]"
msgstr "git format-patch [<opcions>] [<des-de> | <rang-de-revisions>]"
+#: builtin/log.c
msgid "two output directories?"
msgstr "dos directoris de sortida?"
+#: builtin/log.c
#, c-format
msgid "unknown commit %s"
msgstr "comissió desconeguda %s"
+#: builtin/log.c builtin/replace.c
#, c-format
msgid "failed to resolve '%s' as a valid ref"
msgstr "s'ha produït un error en resoldre «%s» com a referència vàlida"
+#: builtin/log.c
msgid "could not find exact merge base"
msgstr "no s'ha pogut trobar la base exacta de la fusió"
+#: builtin/log.c
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"
@@ -7602,225 +9818,302 @@ msgstr ""
"branca remota. També podeu especificar la comissió base amb --base=<base-"
"commit-id> manualment"
+#: builtin/log.c
msgid "failed to find exact merge base"
msgstr "no s'ha pogut trobar la base exacta de la fusió"
+#: builtin/log.c
msgid "base commit should be the ancestor of revision list"
msgstr "la comissió base ha de ser l'avantpassat de la llista de revisions"
+#: builtin/log.c
msgid "base commit shouldn't be in revision list"
msgstr "la comissió base no ha de ser en la llista de revisions"
+#: builtin/log.c
msgid "cannot get patch id"
msgstr "no es pot obtenir l'id del pedaç"
+#: builtin/log.c
msgid "failed to infer range-diff origin of current series"
msgstr ""
"no s'ha pogut inferir el rang de diferències d'origen de les sèries actuals"
+#: builtin/log.c
#, c-format
msgid "using '%s' as range-diff origin of current series"
msgstr "utilitzant «%s» com a origen de rang de diferències de la sèrie actual"
+#: builtin/log.c
msgid "use [PATCH n/m] even with a single patch"
msgstr "usa [PATCH n/m] fins i tot amb un sol pedaç"
+#: builtin/log.c
msgid "use [PATCH] even with multiple patches"
msgstr "usa [PATCH] fins i tot amb múltiples pedaços"
+#: builtin/log.c
msgid "print patches to standard out"
msgstr "imprimeix els pedaços a la sortida estàndard"
+#: builtin/log.c
msgid "generate a cover letter"
msgstr "genera una carta de presentació"
+#: builtin/log.c
msgid "use simple number sequence for output file names"
msgstr "usa una seqüència de números per als noms dels fitxers de sortida"
+#: builtin/log.c
msgid "sfx"
msgstr "sufix"
+#: builtin/log.c
msgid "use <sfx> instead of '.patch'"
msgstr "usa <sufix> en lloc de «.patch»"
+#: builtin/log.c
msgid "start numbering patches at <n> instead of 1"
msgstr "comença numerant els pedaços a <n> en lloc d'1"
+#: builtin/log.c
msgid "reroll-count"
msgstr "reroll-count"
+#: builtin/log.c
msgid "mark the series as Nth re-roll"
msgstr "marca la sèrie com a l'enèsima llançada"
+#: builtin/log.c
msgid "max length of output filename"
msgstr "mida màxima del nom del fitxer de sortida"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "useu [RFC PATCH] en comptes de [PATCH]"
+#: builtin/log.c
+msgid "rfc"
+msgstr "rfc"
+
+#: builtin/log.c
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "afig <rfc> (per defecte «RFC») abans de «PATCH»"
+#: builtin/log.c
msgid "cover-from-description-mode"
msgstr "cover-from-description-mode"
+#: builtin/log.c
msgid "generate parts of a cover letter based on a branch's description"
msgstr ""
"genera parts d'una carta de presentació basant-se en la descripció d'una "
"branca"
+#: builtin/log.c
+msgid "use branch description from file"
+msgstr "utilitza la descripció de la branca des del fitxer"
+
+#: builtin/log.c
msgid "use [<prefix>] instead of [PATCH]"
msgstr "useu [<prefix>] en comptes de [PATCH]"
+#: builtin/log.c
msgid "store resulting files in <dir>"
msgstr "emmagatzema els fitxers resultants a <directori>"
+#: builtin/log.c
msgid "don't strip/add [PATCH]"
msgstr "no despullis/afegeixis [PATCH]"
+#: builtin/log.c
msgid "don't output binary diffs"
msgstr "no emetis diferències binàries"
+#: builtin/log.c
msgid "output all-zero hash in From header"
msgstr "emet un resum de tots zeros en la capçalera From"
+#: builtin/log.c
msgid "don't include a patch matching a commit upstream"
msgstr "no incloguis pedaços que coincideixin amb comissions a la font"
+#: builtin/log.c
msgid "show patch format instead of default (patch + stat)"
msgstr ""
"mostra el format de pedaç en lloc del per defecte (pedaç + estadístiques)"
+#: builtin/log.c
msgid "Messaging"
msgstr "Missatgeria"
+#: builtin/log.c
msgid "header"
msgstr "capçalera"
+#: builtin/log.c
msgid "add email header"
msgstr "afegeix una capçalera de correu electrònic"
+#: builtin/log.c
msgid "email"
msgstr "correu electrònic"
+#: builtin/log.c
msgid "add To: header"
msgstr "afegeix la capçalera To:"
+#: builtin/log.c
msgid "add Cc: header"
msgstr "afegeix la capçalera Cc:"
+#: builtin/log.c
msgid "ident"
msgstr "identitat"
+#: builtin/log.c
msgid "set From address to <ident> (or committer ident if absent)"
msgstr ""
"estableix l'adreça From a <identitat> (o la identitat del comitent si manca)"
+#: builtin/log.c
msgid "message-id"
msgstr "ID de missatge"
+#: builtin/log.c
msgid "make first mail a reply to <message-id>"
msgstr "fes que el primer missatge sigui una resposta a <ID de missatge>"
+#: builtin/log.c
msgid "boundary"
msgstr "límit"
+#: builtin/log.c
msgid "attach the patch"
msgstr "adjunta el pedaç"
+#: builtin/log.c
msgid "inline the patch"
msgstr "posa el pedaç en el cos"
+#: builtin/log.c
msgid "enable message threading, styles: shallow, deep"
msgstr "habilita l'enfilada de missatges, estils: shallow, deep"
+#: builtin/log.c
msgid "signature"
msgstr "signatura"
+#: builtin/log.c
msgid "add a signature"
msgstr "afegeix una signatura"
+#: builtin/log.c
msgid "base-commit"
msgstr "comissió base"
+#: builtin/log.c
msgid "add prerequisite tree info to the patch series"
msgstr "afegeix la informació d'arbre requerida a la sèrie de pedaços"
+#: builtin/log.c
msgid "add a signature from a file"
msgstr "afegeix una signatura des d'un fitxer"
+#: builtin/log.c
msgid "don't print the patch filenames"
msgstr "no imprimeixis els noms de fitxer del pedaç"
+#: builtin/log.c
msgid "show progress while generating patches"
msgstr "mostra el progrés durant la generació de pedaços"
+#: builtin/log.c
msgid "show changes against <rev> in cover letter or single patch"
msgstr ""
-"mostra els canvis contra <rev> a la carta de presentació o a un sol pedaç"
+"mostra els canvis contra <revisió> a la carta de presentació o a un sol pedaç"
+#: builtin/log.c
msgid "show changes against <refspec> in cover letter or single patch"
msgstr ""
"mostra els canvis contra <refspec> a la carta de presentació o a un sol pedaç"
+#: builtin/log.c builtin/range-diff.c
msgid "percentage by which creation is weighted"
msgstr "percentatge pel qual la creació és ponderada"
+#: builtin/log.c
msgid "show in-body From: even if identical to the e-mail header"
msgstr ""
"mostra en el cos el remitent: encara que sigui idèntic a la capçalera del "
"correu electrònic"
+#: builtin/log.c
#, c-format
msgid "invalid ident line: %s"
msgstr "línia d'identitat no vàlida: %s"
+#: builtin/log.c
msgid "--name-only does not make sense"
msgstr "--name-only no té sentit"
+#: builtin/log.c
msgid "--name-status does not make sense"
msgstr "--name-status no té sentit"
+#: builtin/log.c
msgid "--check does not make sense"
msgstr "--check no té sentit"
+#: builtin/log.c
msgid "--remerge-diff does not make sense"
msgstr "--remerge-diff no té sentit"
+#: builtin/log.c builtin/submodule--helper.c rerere.c submodule.c
#, c-format
msgid "could not create directory '%s'"
msgstr "no s'ha pogut crear el directori «%s»"
+#: builtin/log.c
msgid "--interdiff requires --cover-letter or single patch"
msgstr "--interdiff requereix --cover-letter o un sol pedaç"
+#: builtin/log.c
msgid "Interdiff:"
msgstr "Interdiff:"
+#: builtin/log.c
#, c-format
msgid "Interdiff against v%d:"
msgstr "Interdiff contra v%d:"
+#: builtin/log.c
msgid "--range-diff requires --cover-letter or single patch"
msgstr "--range-diff requereix --cover-letter o un sol pedaç"
+#: builtin/log.c
msgid "Range-diff:"
msgstr "Diferència de l'interval:"
+#: builtin/log.c
#, c-format
msgid "Range-diff against v%d:"
msgstr "Diferència de l'interval contra el v%d:"
+#: builtin/log.c
#, c-format
msgid "unable to read signature file '%s'"
msgstr "no s'ha pogut llegir el fitxer de signatura «%s»"
+#: builtin/log.c
msgid "Generating patches"
msgstr "S'estan generant els pedaços"
+#: builtin/log.c
msgid "failed to create output files"
msgstr "no s'han pogut crear els fitxers de sortida"
+#: builtin/log.c
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr "git cherry [-v] [<font> [<cap> [<límit>]]]"
+#: builtin/log.c
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -7828,108 +10121,126 @@ msgstr ""
"No s'ha pogut trobar una branca remota seguida. Especifiqueu <font> "
"manualment.\n"
+#: builtin/ls-files.c builtin/ls-tree.c
#, 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 «(»"
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "format incorrecte del ls-files: l'element «%s» no acaba amb «)»"
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "format incorrecte de ls-files: %%%.*s"
-
+#: builtin/ls-files.c
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<opcions>] [<fitxer>...]"
+#: builtin/ls-files.c builtin/merge-tree.c
msgid "separate paths with the NUL character"
msgstr "separa els camins amb el caràcter NUL"
+#: builtin/ls-files.c
msgid "identify the file status with tags"
msgstr "identifica l'estat de fitxer amb etiquetes"
+#: builtin/ls-files.c
msgid "use lowercase letters for 'assume unchanged' files"
msgstr "usa lletres minúscules per als fitxers «assume unchanged»"
+#: builtin/ls-files.c
msgid "use lowercase letters for 'fsmonitor clean' files"
msgstr "usa lletres minúscules per als fitxers «fsmonitor clean»"
+#: builtin/ls-files.c
msgid "show cached files in the output (default)"
msgstr ""
"mostra en la sortida els fitxers desats en la memòria cau (per defecte)"
+#: builtin/ls-files.c
msgid "show deleted files in the output"
msgstr "mostra en la sortida els fitxers suprimits"
+#: builtin/ls-files.c
msgid "show modified files in the output"
msgstr "mostra en la sortida els fitxers modificats"
+#: builtin/ls-files.c
msgid "show other files in the output"
msgstr "mostra en la sortida els altres fitxers"
+#: builtin/ls-files.c
msgid "show ignored files in the output"
msgstr "mostra en la sortida els fitxers ignorats"
+#: builtin/ls-files.c
msgid "show staged contents' object name in the output"
msgstr "mostra en la sortida el nom d'objecte dels continguts «stage»"
+#: builtin/ls-files.c
msgid "show files on the filesystem that need to be removed"
msgstr "mostra els fitxers en el sistema de fitxers que s'han d'eliminar"
+#: builtin/ls-files.c
msgid "show 'other' directories' names only"
msgstr "mostra només els noms dels directoris «other»"
+#: builtin/ls-files.c
msgid "show line endings of files"
msgstr "mostra els terminadors de línia dels fitxers"
+#: builtin/ls-files.c
msgid "don't show empty directories"
msgstr "no mostris els directoris buits"
+#: builtin/ls-files.c
msgid "show unmerged files in the output"
msgstr "mostra en la sortida els fitxers sense fusionar"
+#: builtin/ls-files.c
msgid "show resolve-undo information"
msgstr "mostra la informació de resolució de desfet"
+#: builtin/ls-files.c
msgid "skip files matching pattern"
msgstr "omet els fitxers coincidents amb el patró"
+#: builtin/ls-files.c
msgid "read exclude patterns from <file>"
msgstr "llegeix els patrons des de <fitxer>"
+#: builtin/ls-files.c
msgid "read additional per-directory exclude patterns in <file>"
msgstr "llegeix els patrons addicionals d'exclusió per directori en <fitxer>"
+#: builtin/ls-files.c
msgid "add the standard git exclusions"
msgstr "afegeix les exclusions estàndards de git"
+#: builtin/ls-files.c
msgid "make the output relative to the project top directory"
msgstr "fes que la sortida sigui relativa al directori superior del projecte"
+#: builtin/ls-files.c
msgid "if any <file> is not in the index, treat this as an error"
msgstr "si qualsevol <fitxer> no és en l'índex, tracta-ho com a error"
+#: builtin/ls-files.c builtin/merge-tree.c
msgid "tree-ish"
msgstr "arbre"
+#: builtin/ls-files.c
msgid "pretend that paths removed since <tree-ish> are still present"
msgstr ""
"pretén que els camins eliminats després de <arbre> encara siguin presents"
+#: builtin/ls-files.c
msgid "show debugging data"
msgstr "mostra les dades de depuració"
+#: builtin/ls-files.c
msgid "suppress duplicate entries"
msgstr "suprimeix les entrades duplicades"
+#: builtin/ls-files.c
msgid "show sparse directories in the presence of a sparse index"
msgstr "mostra els directoris dispersos en presència d'un índex dispers"
+#: builtin/ls-files.c
msgid ""
"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
"--eol"
@@ -7937,163 +10248,202 @@ msgstr ""
"--format no es pot usar amb -s, -o, -k, -t, --resolve-undo, --deduplicate, --"
"eol"
+#: builtin/ls-remote.c
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<exec>]\n"
-" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-" [--symref] [<repository> [<patterns>...]]"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
+" [-q | --quiet] [--exit-code] [--get-url] [--sort=<clau>]\n"
+" [--symref] [<repositori> [<patrons>...]]"
+#: builtin/ls-remote.c
msgid "do not print remote URL"
msgstr "no imprimeixis l'URL remot"
+#: builtin/ls-remote.c builtin/rebase.c
msgid "exec"
msgstr "executable"
+#: builtin/ls-remote.c
msgid "path of git-upload-pack on the remote host"
msgstr "camí a git-upload-pack en la màquina remota"
+#: builtin/ls-remote.c
msgid "limit to tags"
msgstr "limita a etiquetes"
-msgid "limit to heads"
-msgstr "limita a «heads»"
+# limita-ho?
+#: builtin/ls-remote.c
+msgid "limit to branches"
+msgstr "limita a les branques"
+
+#: builtin/ls-remote.c builtin/show-ref.c
+msgid "deprecated synonym for --branches"
+msgstr "sinònim de «--branches» en desús"
+#: builtin/ls-remote.c
msgid "do not show peeled tags"
msgstr "no mostris les etiquetes pelades"
+#: builtin/ls-remote.c
msgid "take url.<base>.insteadOf into account"
msgstr "tingues en compte url.<base>.insteadOf"
+#: builtin/ls-remote.c
msgid "exit with exit code 2 if no matching refs are found"
msgstr "surt amb codi de sortida 2 si no es troba cap referència coincident"
+#: builtin/ls-remote.c
msgid "show underlying ref in addition to the object pointed by it"
msgstr "mostra la referència subjacent a més de l'objecte que assenyali"
+#: builtin/ls-tree.c
msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
msgstr "git ls-tree [<opcions>] <arbre> [<camí>...]"
-#, 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 «(»"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "format incorrecte del ls-tree: l'element '%s' no acaba en «(»"
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "format incorrecte de ls-tree: %%%.*s"
-
+#: builtin/ls-tree.c
msgid "only show trees"
msgstr "mostra només els arbres"
+#: builtin/ls-tree.c
msgid "recurse into subtrees"
msgstr "inclou recursivament als subarbres"
+#: builtin/ls-tree.c
msgid "show trees when recursing"
msgstr "mostra els arbres quan es treballa recursivament"
+#: builtin/ls-tree.c
msgid "terminate entries with NUL byte"
msgstr "acaba les entrades amb un octet NUL"
+#: builtin/ls-tree.c
msgid "include object size"
msgstr "mida de l'objecte d'inclusió"
+#: builtin/ls-tree.c
msgid "list only filenames"
msgstr "llista només els noms de fitxer"
+#: builtin/ls-tree.c
msgid "list only objects"
msgstr "llista només els objectes"
+#: builtin/ls-tree.c
msgid "use full path names"
msgstr "usa els noms de camí complets"
+#: builtin/ls-tree.c
msgid "list entire tree; not just current directory (implies --full-name)"
msgstr ""
"llista l'arbre sencer; no només el directori actual (implica --full-name)"
+#: builtin/ls-tree.c
msgid "--format can't be combined with other format-altering options"
msgstr "--format no es pot combinar amb altres opcions d'alteració de format"
#. TRANSLATORS: keep <> in "<" mail ">" info.
+#: builtin/mailinfo.c
msgid "git mailinfo [<options>] <msg> <patch> < mail >info"
msgstr "git mailinfo [<opcions>] <msg> <pedaç> < mail >info"
+#: builtin/mailinfo.c
msgid "keep subject"
msgstr "mantén l'assumpte"
+#: builtin/mailinfo.c
msgid "keep non patch brackets in subject"
msgstr "mantén els parèntesis que no són del pedaç en l'assumpte"
+#: builtin/mailinfo.c
msgid "copy Message-ID to the end of commit message"
msgstr "copia el Message-ID al final del missatge de comissió"
+#: builtin/mailinfo.c
msgid "re-code metadata to i18n.commitEncoding"
msgstr "torna a codificar les metadades a i18n.commitEncoding"
+#: builtin/mailinfo.c
msgid "disable charset re-coding of metadata"
msgstr "inhabilita la recodificació del joc de caràcters de les metadades"
+#: builtin/mailinfo.c
msgid "encoding"
msgstr "codificació"
+#: builtin/mailinfo.c
msgid "re-code metadata to this encoding"
msgstr "recodifica les metadades en aquesta codificació"
+#: builtin/mailinfo.c
msgid "use scissors"
msgstr "usa les tisores"
+#: builtin/mailinfo.c
msgid "<action>"
msgstr "<acció>"
+#: builtin/mailinfo.c
msgid "action when quoted CR is found"
msgstr "acció quan es troba un CR entre cometes"
+#: builtin/mailinfo.c
msgid "use headers in message's body"
msgstr "utilitza les capçaleres en el cos del missatge"
+#: builtin/mailsplit.c
msgid "reading patches from stdin/tty..."
msgstr "s'estan llegint pedaços de stdin/tty..."
+#: builtin/mailsplit.c
#, c-format
msgid "empty mbox: '%s'"
msgstr "mbox buit: «%s»"
+#: builtin/merge-base.c
msgid "git merge-base [-a | --all] <commit> <commit>..."
msgstr "git merge-base [-a | --all] <comissió> <comissió>..."
+#: builtin/merge-base.c
msgid "git merge-base [-a | --all] --octopus <commit>..."
msgstr "git merge-base [-a | --all] --octopus <comissió>..."
+#: builtin/merge-base.c
msgid "git merge-base --is-ancestor <commit> <commit>"
msgstr "git merge-base --is-ancestor <comissió> <comissió>"
+#: builtin/merge-base.c
msgid "git merge-base --independent <commit>..."
msgstr "git merge-base --independent <comissió>..."
+#: builtin/merge-base.c
msgid "git merge-base --fork-point <ref> [<commit>]"
msgstr "git merge-base --fork-point <referència> [<comissió>]"
+#: builtin/merge-base.c
msgid "output all common ancestors"
msgstr "emet tots els avantpassats comuns"
+#: builtin/merge-base.c
msgid "find ancestors for a single n-way merge"
msgstr "troba els avantpassats per a una sola fusió d'n vies"
+#: builtin/merge-base.c
msgid "list revs not reachable from others"
msgstr "llista les revisions no abastables d'altres"
+#: builtin/merge-base.c
msgid "is the first one ancestor of the other?"
msgstr "és la primera un avantpassat de l'altre?"
+#: builtin/merge-base.c
msgid "find where <commit> forked from reflog of <ref>"
msgstr ""
"troba on <comissió> s'ha bifurcat del registre de referències de <referència>"
+#: builtin/merge-file.c
msgid ""
"git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> "
"<orig-file> <file2>"
@@ -8101,250 +10451,342 @@ msgstr ""
"git merge-file [<opcions>] [-L <nom1> [-L <original> [-L <nom2>]]] <fitxer1> "
"<fitxer-original> <fitxer2>"
+#: builtin/merge-file.c diff.c
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"l'opció diff-algorithm accepta «myers», «minimal», «patience» i «histogram»"
+
+#: builtin/merge-file.c
msgid "send results to standard output"
msgstr "envia els resultats a la sortida estàndard"
+#: builtin/merge-file.c
+msgid "use object IDs instead of filenames"
+msgstr "utilitza els ID dels objectes en comptes dels noms de fitxer"
+
+#: builtin/merge-file.c
msgid "use a diff3 based merge"
msgstr "usa una fusió basada en diff3"
+#: builtin/merge-file.c
msgid "use a zealous diff3 based merge"
msgstr "usa una fusió basada en zealous diff3"
-msgid "for conflicts, use our version"
-msgstr "en conflictes, usa la nostra versió"
-
-msgid "for conflicts, use their version"
-msgstr "en conflictes, usa la seva versió"
+#: builtin/merge-file.c diff.c
+msgid "<algorithm>"
+msgstr "<algorisme>"
-msgid "for conflicts, use a union version"
-msgstr "en conflictes, usa una versió d'unió"
+#: builtin/merge-file.c diff.c
+msgid "choose a diff algorithm"
+msgstr "trieu un algorisme per al diff"
+#: builtin/merge-file.c
msgid "for conflicts, use this marker size"
msgstr "en conflictes, usa aquesta mida de marcador"
+#: builtin/merge-file.c
msgid "do not warn about conflicts"
msgstr "no avisis de conflictes"
+#: builtin/merge-file.c
msgid "set labels for file1/orig-file/file2"
msgstr "estableix les etiquetes per a fitxer1/fitxer-original/fitxer2"
+#: builtin/merge-file.c
+#, c-format
+msgid "object '%s' does not exist"
+msgstr "l'objecte «%s» no existeix"
+
+#: builtin/merge-file.c
+msgid "Could not write object file"
+msgstr "No s'ha pogut escriure el fitxer de l'objecte"
+
+#: builtin/merge-recursive.c
#, c-format
msgid "unknown option %s"
msgstr "opció desconeguda %s"
+#: builtin/merge-recursive.c
#, c-format
msgid "could not parse object '%s'"
msgstr "no s'ha pogut analitzar l'objecte «%s»"
+#: builtin/merge-recursive.c
#, c-format
msgid "cannot handle more than %d base. Ignoring %s."
msgid_plural "cannot handle more than %d bases. Ignoring %s."
msgstr[0] "no es pot gestionar més d'%d base. S'està ignorant %s."
msgstr[1] "no es poden gestionar més de %d bases. S'està ignorant %s."
+#: builtin/merge-recursive.c
msgid "not handling anything other than two heads merge."
msgstr "no s'està gestionant res a part de la fusió de dos caps."
+#: builtin/merge-recursive.c
#, c-format
msgid "could not resolve ref '%s'"
msgstr "no s'ha pogut resoldre la referència «%s»"
+#: builtin/merge-recursive.c
#, c-format
msgid "Merging %s with %s\n"
msgstr "S'està fusionant %s amb %s\n"
+#: builtin/merge-tree.c
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "no s'ha pogut analitzar com a arbre «%s»"
+
+#: builtin/merge-tree.c builtin/merge.c
msgid "not something we can merge"
msgstr "no és quelcom que puguem fusionar"
+#: builtin/merge-tree.c builtin/merge.c
msgid "refusing to merge unrelated histories"
msgstr "s'està refusant fusionar històries no relacionades"
+#: builtin/merge-tree.c
msgid "failure to merge"
msgstr "s'ha produït un error en fusionar"
+#: builtin/merge-tree.c
msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
-msgstr "git merge-tree [--write-tree] [<opcions>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<opcions>] <branca1> <branca2>"
+#: builtin/merge-tree.c
msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
-msgstr "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <base-tree> <branca1> <branca2>"
+#: builtin/merge-tree.c
msgid "do a real merge instead of a trivial merge"
msgstr "fes una fusió real en lloc d'una fusió trivial"
+#: builtin/merge-tree.c
msgid "do a trivial merge only"
msgstr "fes només una fusió trivial"
+#: builtin/merge-tree.c
msgid "also show informational/conflict messages"
msgstr "també mostra missatges informatius i de conflictes"
+#: builtin/merge-tree.c
msgid "list filenames without modes/oids/stages"
msgstr "llista els noms de fitxer sense modes/oids/stages"
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
msgid "allow merging unrelated histories"
msgstr "permet fusionar històries no relacionades"
+#: builtin/merge-tree.c
msgid "perform multiple merges, one per line of input"
msgstr "realitza múltiples fusions, una per línia d'entrada"
+#: builtin/merge-tree.c
msgid "specify a merge-base for the merge"
msgstr "cal especificar una referència base per a la fusió"
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option=value"
+msgstr "opció=valor"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option for selected merge strategy"
+msgstr "opció per a l'estratègia de fusió seleccionada"
+
+#: builtin/merge-tree.c
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge és incompatible amb totes les altres opcions"
-msgid "--merge-base is incompatible with --stdin"
-msgstr "--merge-base és incompatible amb --stdin"
+#: builtin/merge-tree.c builtin/merge.c
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "opció d'estratègia desconeguda: -X%s"
+#: builtin/merge-tree.c builtin/notes.c
#, c-format
msgid "malformed input line: '%s'."
msgstr "línia d'entrada mal formada: «%s»."
+#: builtin/merge-tree.c
#, c-format
msgid "merging cannot continue; got unclean result of %d"
msgstr "la fusió no pot continuar; s'ha obtingut un resultat no net de %d"
+#: builtin/merge.c
msgid "git merge [<options>] [<commit>...]"
msgstr "git merge [<opcions>] [<comissió>...]"
+#: builtin/merge.c
msgid "switch `m' requires a value"
msgstr "l'opció «m» requereix un valor"
+#: builtin/merge.c
#, c-format
msgid "option `%s' requires a value"
msgstr "l'opció «%s» requereix un valor"
+#: builtin/merge.c
#, c-format
msgid "Could not find merge strategy '%s'.\n"
msgstr "No s'ha pogut trobar l'estratègia de fusió «%s».\n"
+#: builtin/merge.c
#, c-format
msgid "Available strategies are:"
msgstr "Les estratègies disponibles són:"
+#: builtin/merge.c
#, c-format
msgid "Available custom strategies are:"
msgstr "Les estratègies personalitzades disponibles són:"
+#: builtin/merge.c builtin/pull.c
msgid "do not show a diffstat at the end of the merge"
msgstr "no mostris les estadístiques de diferència al final de la fusió"
+#: builtin/merge.c builtin/pull.c
msgid "show a diffstat at the end of the merge"
msgstr "mostra les estadístiques de diferència al final de la fusió"
+#: builtin/merge.c builtin/pull.c
msgid "(synonym to --stat)"
msgstr "(sinònim de --stat)"
+#: builtin/merge.c builtin/pull.c
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr ""
"afegeix (com a màxim <n>) entrades del registre curt al missatge de comissió "
"de fusió"
+#: builtin/merge.c builtin/pull.c
msgid "create a single commit instead of doing a merge"
msgstr "crea una única comissió en lloc de fusionar"
+#: builtin/merge.c builtin/pull.c
msgid "perform a commit if the merge succeeds (default)"
msgstr "realitza una comissió si la fusió té èxit (per defecte)"
+#: builtin/merge.c builtin/pull.c
msgid "edit message before committing"
msgstr "edita el missatge abans de cometre"
+#: builtin/merge.c
msgid "allow fast-forward (default)"
msgstr "permet l'avanç ràpid (per defecte)"
+#: builtin/merge.c builtin/pull.c
msgid "abort if fast-forward is not possible"
msgstr "avorta si l'avanç ràpid no és possible"
+#: builtin/merge.c builtin/pull.c
msgid "verify that the named commit has a valid GPG signature"
msgstr "verifica que la comissió anomenada tingui una signatura GPG vàlida"
+#: builtin/merge.c builtin/notes.c builtin/pull.c builtin/rebase.c
+#: builtin/revert.c
msgid "strategy"
msgstr "estratègia"
+#: builtin/merge.c builtin/pull.c
msgid "merge strategy to use"
msgstr "estratègia de fusió a usar"
-msgid "option=value"
-msgstr "opció=valor"
-
-msgid "option for selected merge strategy"
-msgstr "opció per a l'estratègia de fusió seleccionada"
-
+#: builtin/merge.c
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "missatge de comissió de fusió (per a una fusió no d'avanç ràpid)"
+#: builtin/merge.c
msgid "use <name> instead of the real target"
msgstr "usa <nom> en lloc de destí real"
+#: builtin/merge.c
msgid "abort the current in-progress merge"
msgstr "avorta la fusió en curs actual"
+#: builtin/merge.c
msgid "--abort but leave index and working tree alone"
msgstr "--abort però deixa l'índex i l'arbre de treball intactes"
+#: builtin/merge.c
msgid "continue the current in-progress merge"
msgstr "continua la fusió actual en curs"
+#: builtin/merge.c
msgid "bypass pre-merge-commit and commit-msg hooks"
msgstr "evita els lligams pre-merge-commit i commit-msg"
+#: builtin/merge.c
msgid "could not run stash."
msgstr "no s'ha pogut executar «stash»."
+#: builtin/merge.c
msgid "stash failed"
msgstr "l'«stash» ha fallat"
+#: builtin/merge.c
#, c-format
msgid "not a valid object: %s"
msgstr "no és un objecte vàlid: %s"
+#: builtin/merge.c
msgid "read-tree failed"
msgstr "read-tree ha fallat"
+#: builtin/merge.c
msgid "Already up to date. (nothing to squash)"
msgstr "Ja està actualitzat. (res a fer «squash»)"
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
msgid "Already up to date."
msgstr "Ja està al dia."
+#: builtin/merge.c
#, c-format
msgid "Squash commit -- not updating HEAD\n"
msgstr "Comissió «squash» -- no s'està actualitzant HEAD\n"
+#: builtin/merge.c
#, c-format
msgid "No merge message -- not updating HEAD\n"
msgstr "Cap missatge de fusió -- no s'està actualitzant HEAD\n"
+#: builtin/merge.c
#, c-format
msgid "'%s' does not point to a commit"
msgstr "«%s» no assenyala una comissió"
+#: builtin/merge.c
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Cadena branch.%s.mergeoptions incorrecta: %s"
+#: builtin/merge.c merge-recursive.c
msgid "Unable to write index."
msgstr "No s'ha pogut escriure l'índex."
+#: builtin/merge.c
msgid "Not handling anything other than two heads merge."
msgstr "No s'està gestionant res a part de la fusió de dos caps."
-#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "opció d'estratègia desconeguda: -X%s"
-
+#: builtin/merge.c builtin/sparse-checkout.c
#, c-format
msgid "unable to write %s"
msgstr "no s'ha pogut escriure %s"
+#: builtin/merge.c
#, c-format
msgid "Could not read from '%s'"
msgstr "No s'ha pogut llegir de «%s»"
+#: builtin/merge.c
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
"No s'està cometent la fusió; useu «git commit» per a completar la fusió.\n"
+#: builtin/merge.c
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"
@@ -8354,70 +10796,89 @@ msgstr ""
"necessària, especialment si es fusiona una branca amb funcionalitat nova.\n"
"\n"
+#: builtin/merge.c
msgid "An empty message aborts the commit.\n"
msgstr "Un missatge buit interromp la comissió.\n"
+# will be ignored → es descartaran?
+#: builtin/merge.c
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Les línies que comencen amb «%c» seran ignorades i un missatge buit "
-"interromp la comissió.\n"
+"Les línies que comencin amb «%s» s'ignoraran, i un missatge buit\n"
+"avorta la comissió.\n"
+#: builtin/merge.c
msgid "Empty commit message."
msgstr "El missatge de comissió és buit."
+#: builtin/merge.c
#, c-format
msgid "Wonderful.\n"
msgstr "Meravellós.\n"
+#: builtin/merge.c
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
"La fusió automàtica ha fallat; arregleu els conflictes i després cometeu el "
"resultat.\n"
+#: builtin/merge.c
msgid "No current branch."
msgstr "No hi ha cap branca actual."
+#: builtin/merge.c
msgid "No remote for the current branch."
msgstr "No hi ha cap remot per a la branca actual."
+#: builtin/merge.c
msgid "No default upstream defined for the current branch."
msgstr "No hi ha cap font per defecte definida per a la branca actual."
+#: builtin/merge.c
#, c-format
msgid "No remote-tracking branch for %s from %s"
msgstr "No hi ha cap branca amb seguiment remot per a %s de %s"
+#: builtin/merge.c
#, c-format
msgid "Bad value '%s' in environment '%s'"
msgstr "Valor incorrecte «%s» en l'entorn «%s»"
+#: builtin/merge.c editor.c read-cache.c wrapper.c
#, c-format
msgid "could not close '%s'"
msgstr "no s'ha pogut tancar «%s»"
+#: builtin/merge.c
#, c-format
msgid "not something we can merge in %s: %s"
msgstr "no és quelcom que puguem fusionar en %s: %s"
+#: builtin/merge.c
msgid "--abort expects no arguments"
msgstr "--abort no espera cap argument"
+#: builtin/merge.c
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "No hi ha fusió a avortar (manca MERGE_HEAD)."
+#: builtin/merge.c
msgid "--quit expects no arguments"
msgstr "--quit no espera cap argument"
+#: builtin/merge.c
msgid "--continue expects no arguments"
msgstr "--continue no espera cap argument"
+#: builtin/merge.c
msgid "There is no merge in progress (MERGE_HEAD missing)."
msgstr "No hi ha cap fusió en curs (manca MERGE_HEAD)."
+#: builtin/merge.c
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you merge."
@@ -8425,6 +10886,7 @@ msgstr ""
"No heu conclòs la vostra fusió (MERGE_HEAD existeix).\n"
"Cometeu els vostres canvis abans de fusionar."
+#: builtin/merge.c
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."
@@ -8432,31 +10894,39 @@ msgstr ""
"No heu conclòs el vostre «cherry pick» (CHERRY_PICK_HEAD existeix).\n"
"Cometeu els vostres canvis abans de fusionar."
+#: builtin/merge.c
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr "No heu conclòs el vostre «cherry pick» (CHERRY_PICK_HEAD existeix)."
+#: builtin/merge.c
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr ""
"No hi ha una comissió especificada i merge.defaultToUpstream no està "
"establert."
+#: builtin/merge.c
msgid "Squash commit into empty head not supported yet"
msgstr "Una comissió «squash» a una HEAD buida encara no es permet"
+#: builtin/merge.c
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr "Una comissió no d'avanç ràpid no té sentit a una HEAD buida"
+#: builtin/merge.c
#, c-format
msgid "%s - not something we can merge"
msgstr "%s - no és una cosa que puguem fusionar"
+#: builtin/merge.c
msgid "Can merge only exactly one commit into empty head"
msgstr "Es pot fusionar només una comissió a una HEAD buida"
+#: builtin/merge.c
#, c-format
msgid "Updating %s..%s\n"
msgstr "S'estan actualitzant %s..%s\n"
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by merge:\n"
@@ -8465,126 +10935,159 @@ msgstr ""
"Els canvis locals als fitxers següents se sobreescriuran per la fusió:\n"
" %s"
+#: builtin/merge.c
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "S'està intentant una fusió molt trivial en l'índex...\n"
+#: builtin/merge.c
#, c-format
msgid "Nope.\n"
msgstr "No.\n"
+#: builtin/merge.c
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "S'està rebobinant l'arbre a la pristina...\n"
+#: builtin/merge.c
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "S'està intentant l'estratègia de fusió %s...\n"
+#: builtin/merge.c
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Cap estratègia de fusió ha gestionat la fusió.\n"
+#: builtin/merge.c
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "L'estratègia de fusió %s ha fallat.\n"
+#: builtin/merge.c
#, c-format
msgid "Using the %s strategy to prepare resolving by hand.\n"
msgstr "S'està usant l'estratègia %s per a preparar la resolució a mà.\n"
+#: builtin/merge.c
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
"La fusió automàtica ha sortit bé; s'ha aturat abans de cometre com s'havia "
"demanat\n"
+#: builtin/merge.c
#, c-format
msgid "When finished, apply stashed changes with `git stash pop`\n"
msgstr "Quan acabi, aplica els canvis «stashed» amb «git stash pop»\n"
+#: builtin/mktag.c
#, c-format
msgid "warning: tag input does not pass fsck: %s"
msgstr "avís: l'entrada d'etiqueta no passa fsck: %s"
+#: builtin/mktag.c
#, c-format
msgid "error: tag input does not pass fsck: %s"
msgstr "error: l'entrada d'etiqueta no passa fsck: %s"
+#: builtin/mktag.c
#, c-format
msgid "%d (FSCK_IGNORE?) should never trigger this callback"
msgstr "%d (FSCK_IGNORE?) no hauria d'activar mai aquesta crida de retorn"
+#: builtin/mktag.c
#, c-format
msgid "could not read tagged object '%s'"
msgstr "no s'ha pogut llegir l'objecte etiquetat «%s»"
+#: builtin/mktag.c
#, c-format
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "l'objecte «%s» s'ha etiquetat com a «%s», però és del tipus «%s»"
-msgid "could not read from stdin"
-msgstr "no s'ha pogut llegir des de stdin"
-
+#: builtin/mktag.c
msgid "tag on stdin did not pass our strict fsck check"
msgstr "l'etiqueta a stdin no ha passat la comprovació estricta del fsck"
+#: builtin/mktag.c
msgid "tag on stdin did not refer to a valid object"
msgstr "l'etiqueta a stdin no apunta a un objecte vàlid"
+#: builtin/mktag.c builtin/tag.c
msgid "unable to write tag file"
msgstr "no s'ha pogut escriure el fitxer d'etiqueta"
+#: builtin/mktree.c
msgid "input is NUL terminated"
msgstr "l'entrada és acabada amb NUL"
+#: builtin/mktree.c builtin/write-tree.c
msgid "allow missing objects"
msgstr "permet els objectes absents"
+#: builtin/mktree.c
msgid "allow creation of more than one tree"
msgstr "permet la creació de més d'un arbre"
+#: builtin/multi-pack-index.c
msgid ""
"git multi-pack-index [<options>] write [--preferred-pack=<pack>][--refs-"
"snapshot=<path>]"
msgstr ""
-"git multi-pack-index [<opcions>] write [--preferred-pack=<pack>][--refs-"
+"git multi-pack-index [<opcions>] write [--preferred-pack=<paquet>][--refs-"
"snapshot=<camí>]"
+#: builtin/multi-pack-index.c
msgid "git multi-pack-index [<options>] verify"
msgstr "git multi-pack-index [<opcions>] verify"
+#: builtin/multi-pack-index.c
msgid "git multi-pack-index [<options>] expire"
msgstr "git multi-pack-index [<opcions>] expire"
+#: builtin/multi-pack-index.c
msgid "git multi-pack-index [<options>] repack [--batch-size=<size>]"
msgstr "git multi-pack-index [<opcions>] repack [--batch-size=<mida>]"
+#: builtin/multi-pack-index.c
msgid "directory"
msgstr "directori"
+#: builtin/multi-pack-index.c
msgid "object directory containing set of packfile and pack-index pairs"
msgstr ""
"directori de l'objecte que conté el conjunt de parells de fitxers i índexs "
"de paquets"
+#: builtin/multi-pack-index.c
msgid "preferred-pack"
msgstr "paquet preferit"
+#: builtin/multi-pack-index.c
msgid "pack for reuse when computing a multi-pack bitmap"
msgstr ""
"empaqueta per a reutilitzar quan es calcula un mapa de bits multipaquet"
+#: builtin/multi-pack-index.c
msgid "write multi-pack bitmap"
msgstr "escriu un map de bits multipaquet"
+#: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "escriu un nou MIDX incremental"
+
+#: builtin/multi-pack-index.c
msgid "write multi-pack index containing only given indexes"
msgstr "escriu un índex multipaquet que contingui només els índexs donats"
+#: builtin/multi-pack-index.c
msgid "refs snapshot for selecting bitmap commits"
msgstr ""
"instantània de referències per a seleccionar les comissions de mapa de bits"
+#: builtin/multi-pack-index.c
msgid ""
"during repack, collect pack-files of smaller size into a batch that is "
"larger than this size"
@@ -8592,245 +11095,309 @@ msgstr ""
"durant el reempaquetament, recull els fitxers de paquets de mida més petita "
"en un lot que és més gran que aquesta mida"
+#: builtin/mv.c
msgid "git mv [<options>] <source>... <destination>"
msgstr "git mv [<opcions>] <origen>... <destí>"
+#: builtin/mv.c
#, c-format
msgid "Directory %s is in index and no submodule?"
msgstr "El directori %s és en l'índex i no hi ha cap submòdul?"
+#: builtin/mv.c
msgid "Please stage your changes to .gitmodules or stash them to proceed"
msgstr ""
"Feu «stage» dels vostres canvis a .gitmodules o feu «stash» dels mateixos "
"per a procedir"
+#: builtin/mv.c
#, c-format
msgid "%.*s is in index"
msgstr "%.*s és en l'índex"
+#: builtin/mv.c
msgid "force move/rename even if target exists"
msgstr "força el moviment / canvi de nom encara que el destí existeixi"
+#: builtin/mv.c
msgid "skip move/rename errors"
msgstr "omet els errors de moviment / canvi de nom"
+#: builtin/mv.c
#, c-format
msgid "destination '%s' is not a directory"
msgstr "el destí «%s» no és un directori"
+#: builtin/mv.c
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
msgstr "S'està comprovant el canvi de nom de «%s» a «%s»\n"
+#: builtin/mv.c
msgid "bad source"
msgstr "origen incorrecte"
+#: builtin/mv.c
msgid "destination exists"
msgstr "el destí existeix"
+#: builtin/mv.c
msgid "can not move directory into itself"
msgstr "no es pot moure un directori a dins d'ell mateix"
-msgid "cannot move directory over file"
-msgstr "no es pot moure un directori sobre un fitxer"
+#: builtin/mv.c
+msgid "destination already exists"
+msgstr "la destinació ja existeix"
+#: builtin/mv.c
msgid "source directory is empty"
msgstr "el directori d'origen està buit"
+#: builtin/mv.c
msgid "not under version control"
msgstr "no està sota control de versions"
+#: builtin/mv.c
msgid "conflicted"
msgstr "en conflicte"
+#: builtin/mv.c
#, c-format
msgid "overwriting '%s'"
msgstr "s'està sobreescrivint «%s»"
+#: builtin/mv.c
msgid "Cannot overwrite"
msgstr "No es pot sobreescriure"
+#: builtin/mv.c
msgid "multiple sources for the same target"
msgstr "múltiples orígens per al mateix destí"
+#: builtin/mv.c
msgid "destination directory does not exist"
msgstr "el directori destí no existeix"
+#: builtin/mv.c
msgid "destination exists in the index"
msgstr "el destí existeix a l'índex"
+#: builtin/mv.c
#, c-format
msgid "%s, source=%s, destination=%s"
msgstr "%s, origen=%s, destí=%s"
+#: builtin/mv.c
#, c-format
msgid "Renaming %s to %s\n"
msgstr "S'està canviant el nom de %s a %s\n"
+#: builtin/mv.c builtin/remote.c
#, c-format
msgid "renaming '%s' failed"
msgstr "el canvi del nom de «%s» ha fallat"
+#: builtin/name-rev.c
msgid "git name-rev [<options>] <commit>..."
msgstr "git name-rev [<opcions>] <comissió>..."
+#: builtin/name-rev.c
msgid "git name-rev [<options>] --all"
msgstr "git name-rev [<opcions>] --all"
+#: builtin/name-rev.c
msgid "git name-rev [<options>] --annotate-stdin"
msgstr "git name-rev [<opcions>] --annotate-stdin"
+#: builtin/name-rev.c
msgid "print only ref-based names (no object names)"
msgstr "imprimeix només els noms basats en referències (no els noms d'objecte)"
+#: builtin/name-rev.c
msgid "only use tags to name the commits"
msgstr "només usa les etiquetes per a anomenar les comissions"
+#: builtin/name-rev.c
msgid "only use refs matching <pattern>"
msgstr "només usa les referències que coincideixin amb <patró>"
+#: builtin/name-rev.c
msgid "ignore refs matching <pattern>"
msgstr "ignora les referències que coincideixin amb <patró>"
+#: builtin/name-rev.c
msgid "list all commits reachable from all refs"
msgstr "llista totes les comissions abastables de totes les referències"
+#: builtin/name-rev.c
msgid "deprecated: use --annotate-stdin instead"
msgstr "obsolet: useu en comptes --annotate-stdin"
+#: builtin/name-rev.c
msgid "annotate text from stdin"
msgstr "anota el text de stdin"
+#: builtin/name-rev.c
msgid "allow to print `undefined` names (default)"
msgstr "permet imprimir els noms «undefined» (per defecte)"
+#: builtin/name-rev.c
msgid "dereference tags in the input (internal use)"
msgstr "desreferencia les etiquetes en l'entrada (ús intern)"
+#: builtin/notes.c
msgid "git notes [--ref <notes-ref>] [list [<object>]]"
msgstr "git notes [--ref <referència-de-notes>] [llista [<objecte>]]"
+#: builtin/notes.c
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 <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
-"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
-"| -C) <object>] [<object>]"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <fitxer> | (-"
+"c | -C) <object>] [<object>]"
+#: builtin/notes.c
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>"
+"git notes [--ref <referència-de-notes>] copy [-f] <objecte-de> <objecte-a>"
+#: builtin/notes.c
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 <notes-ref>] append [--allow-empty] [--[no-]separator|--"
-"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
-"| -C) <object>] [<object>]"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <fitxer> | (-"
+"c | -C) <objecte>] [<objecte>]"
+#: builtin/notes.c
msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
msgstr ""
"git notes [--ref <referència-de-notes>] edit [--allow-empty] [<objecte>]"
+#: builtin/notes.c
msgid "git notes [--ref <notes-ref>] show [<object>]"
msgstr "git notes [--ref <referència-de-notes>] show [<objecte>]"
+#: builtin/notes.c
msgid ""
"git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"
msgstr ""
"git notes [--ref <referència-de-notes>] merge [-v | -q] [-s <estratègia>] "
"<referència-de-notes>"
+#: builtin/notes.c
msgid "git notes [--ref <notes-ref>] remove [<object>...]"
msgstr "git notes [--ref <referència-de-notes>] remove [<objecte>...]"
+#: builtin/notes.c
msgid "git notes [--ref <notes-ref>] prune [-n] [-v]"
msgstr "git notes [--ref <referència-de-notes>] prune [-n] [-v]"
+#: builtin/notes.c
msgid "git notes [--ref <notes-ref>] get-ref"
msgstr "git notes [--ref <referència-de-notes>] get-ref"
+#: builtin/notes.c
msgid "git notes [list [<object>]]"
msgstr "git notes [llista [<objecte>]]"
+#: builtin/notes.c
msgid "git notes add [<options>] [<object>]"
msgstr "git notes add [<opcions>] [<objecte>]"
+#: builtin/notes.c
msgid "git notes copy [<options>] <from-object> <to-object>"
-msgstr "git notes copy [<opcions>] <d'objecte> <a-objecte>"
+msgstr "git notes copy [<opcions>] <objecte-de> <objecte-a>"
+#: builtin/notes.c
msgid "git notes copy --stdin [<from-object> <to-object>]..."
-msgstr "git notes copy --stdin [<d'objecte> <a-objecte>]..."
+msgstr "git notes copy --stdin [<objecte-de> <objecte-a>]..."
+#: builtin/notes.c
msgid "git notes append [<options>] [<object>]"
msgstr "git notes append [<opcions>] [<objecte>]"
+#: builtin/notes.c
msgid "git notes edit [<object>]"
msgstr "git notes edit [<objecte>]"
+#: builtin/notes.c
msgid "git notes show [<object>]"
msgstr "git notes show [<objecte>]"
+#: builtin/notes.c
msgid "git notes merge [<options>] <notes-ref>"
msgstr "git notes merge [<opcions>] <referència-de-notes>"
+#: builtin/notes.c
msgid "git notes merge --commit [<options>]"
msgstr "git notes merge --commit [<opcions>]"
+#: builtin/notes.c
msgid "git notes merge --abort [<options>]"
msgstr "git notes merge --abort [<opcions>]"
+#: builtin/notes.c
msgid "git notes remove [<object>]"
msgstr "git notes remove [<objecte>]"
+#: builtin/notes.c
msgid "git notes prune [<options>]"
msgstr "git notes prune [<opcions>]"
+#: builtin/notes.c
msgid "Write/edit the notes for the following object:"
msgstr "Escriviu/editeu les notes per l'objecte següent:"
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "no s'ha pogut iniciar «show» per a l'objecte «%s»"
-
+#: builtin/notes.c
msgid "could not read 'show' output"
msgstr "no s'ha pogut llegir la sortida de «show»"
+#: builtin/notes.c
#, c-format
msgid "failed to finish 'show' for object '%s'"
msgstr "s'ha produït un error en finalitzar «show» per a l'objecte «%s»"
+#: builtin/notes.c
msgid "please supply the note contents using either -m or -F option"
msgstr ""
"especifiqueu el contingut de la nota fent servir l'opció -m o l'opció -F"
+#: builtin/notes.c
msgid "unable to write note object"
msgstr "no s'ha pogut escriure l'objecte de nota"
+#: builtin/notes.c
#, c-format
msgid "the note contents have been left in %s"
msgstr "s'han deixat els continguts de la nota en %s"
+#: builtin/notes.c builtin/tag.c
#, c-format
msgid "could not open or read '%s'"
msgstr "no s'ha pogut obrir o llegir «%s»"
+#: builtin/notes.c
#, c-format
msgid "failed to resolve '%s' as a valid ref."
msgstr "s'ha produït un error en resoldre «%s» com a referència vàlida."
+#: builtin/notes.c
#, c-format
msgid "failed to read object '%s'."
msgstr "s'ha produït un error en llegir l'objecte «%s»."
+#: builtin/notes.c
#, c-format
msgid "cannot read note data from non-blob object '%s'."
msgstr "no es poden llegir les dades de node de l'objecte no de blob «%s»."
+#: builtin/notes.c
#, c-format
msgid "failed to copy notes from '%s' to '%s'"
msgstr "s'ha produït un error en copiar les notes de «%s» a «%s»"
@@ -8838,41 +11405,53 @@ msgstr "s'ha produït un error en copiar les notes de «%s» a «%s»"
#. TRANSLATORS: the first %s will be replaced by a git
#. notes command: 'add', 'merge', 'remove', etc.
#.
+#: builtin/notes.c
#, c-format
msgid "refusing to %s notes in %s (outside of refs/notes/)"
msgstr "s'està refusant %s les notes en %s (fora de refs/notes/)"
+#: builtin/notes.c
#, c-format
msgid "no note found for object %s."
msgstr "no s'ha trobat cap nota per a l'objecte %s."
+#: builtin/notes.c
msgid "note contents as a string"
msgstr "anota els continguts com a cadena"
+#: builtin/notes.c
msgid "note contents in a file"
msgstr "anota els continguts en un fitxer"
+#: builtin/notes.c
msgid "reuse and edit specified note object"
msgstr "reusa i edita l'objecte de nota especificat"
+#: builtin/notes.c
msgid "reuse specified note object"
msgstr "reusa l'objecte de nota especificat"
+#: builtin/notes.c
msgid "allow storing empty note"
msgstr "permet l'emmagatzematge d'una nota buida"
+#: builtin/notes.c
msgid "replace existing notes"
msgstr "reemplaça les notes existents"
+#: builtin/notes.c
msgid "<paragraph-break>"
msgstr "<paragraph-break>"
+#: builtin/notes.c
msgid "insert <paragraph-break> between paragraphs"
msgstr "insereix <paragraph-break> entre paràgrafs"
+#: builtin/notes.c
msgid "remove unnecessary whitespace"
msgstr "elimina l'espai en blanc innecessari"
+#: builtin/notes.c
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -8881,24 +11460,30 @@ msgstr ""
"No es poden afegir les notes. S'han trobat notes existents de l'objecte %s. "
"Useu «-f» per a sobreescriure les notes existents"
+#: builtin/notes.c
#, c-format
msgid "Overwriting existing notes for object %s\n"
msgstr "S'estan sobreescrivint les notes existents de l'objecte %s\n"
+#: builtin/notes.c
#, c-format
msgid "Removing note for object %s\n"
msgstr "S'està eliminant la nota de l'objecte %s\n"
+#: builtin/notes.c
msgid "read objects from stdin"
msgstr "llegeix els objectes des de stdin"
+#: builtin/notes.c
msgid "load rewriting config for <command> (implies --stdin)"
msgstr ""
"carrega la configuració de reescriptura per a <ordre> (implica --stdin)"
+#: builtin/notes.c
msgid "too few arguments"
msgstr "massa pocs arguments"
+#: builtin/notes.c
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -8907,10 +11492,12 @@ msgstr ""
"No es poden copiar les notes. S'han trobat notes existents de l'objecte %s. "
"Useu «-f» per a sobreescriure les notes existents"
+#: builtin/notes.c
#, c-format
msgid "missing notes on source object %s. Cannot copy."
msgstr "manquen notes a l'objecte font %s. No es pot copiar."
+#: builtin/notes.c
#, c-format
msgid ""
"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -8919,41 +11506,53 @@ msgstr ""
"Es desaconsellen les opcions -m/-F/-c/-C en favor de la subordre «edit».\n"
"Useu «git notes add -f -m/-F/-c/-C» en lloc d'això.\n"
+#: builtin/notes.c
msgid "failed to delete ref NOTES_MERGE_PARTIAL"
msgstr "s'ha produït un error en suprimir la referència NOTES_MERGE_PARTIAL"
+#: builtin/notes.c
msgid "failed to delete ref NOTES_MERGE_REF"
msgstr "s'ha produït un error en suprimir la referència NOTES_MERGE_REF"
+#: builtin/notes.c
msgid "failed to remove 'git notes merge' worktree"
msgstr ""
"s'ha produït un error en eliminar l'arbre de treball de «git notes merge»"
+#: builtin/notes.c
msgid "failed to read ref NOTES_MERGE_PARTIAL"
msgstr "s'ha produït un error en llegir la referència NOTES_MERGE_PARTIAL"
+#: builtin/notes.c
msgid "could not find commit from NOTES_MERGE_PARTIAL."
msgstr "no s'ha pogut trobar cap comissió de NOTES_MERGE_PARTIAL."
+#: builtin/notes.c
msgid "could not parse commit from NOTES_MERGE_PARTIAL."
msgstr "no s'ha pogut analitzar la comissió de NOTES_MERGE_PARTIAL."
+#: builtin/notes.c
msgid "failed to resolve NOTES_MERGE_REF"
msgstr "s'ha produït un error en resoldre NOTES_MERGE_REF"
+#: builtin/notes.c
msgid "failed to finalize notes merge"
msgstr "s'ha produït un error en finalitzar la fusió de notes"
+#: builtin/notes.c
#, c-format
msgid "unknown notes merge strategy %s"
msgstr "estratègia de fusió de notes desconeguda %s"
+#: builtin/notes.c
msgid "General options"
msgstr "Opcions generals"
+#: builtin/notes.c
msgid "Merge options"
msgstr "Opcions de fusió"
+#: builtin/notes.c
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
@@ -8961,38 +11560,48 @@ msgstr ""
"resol els conflictes de nota usant l'estratègia donada (manual/ours/theirs/"
"union/cat_sort_uniq)"
+#: builtin/notes.c
msgid "Committing unmerged notes"
msgstr "S'estan cometent les notes sense fusionar"
+#: builtin/notes.c
msgid "finalize notes merge by committing unmerged notes"
msgstr "finalitza la fusió de notes cometent les notes sense fusionar"
+#: builtin/notes.c
msgid "Aborting notes merge resolution"
msgstr "S'està avortant la resolució de fusió de notes"
+#: builtin/notes.c
msgid "abort notes merge"
msgstr "avorta la fusió de notes"
+#: builtin/notes.c
msgid "cannot mix --commit, --abort or -s/--strategy"
msgstr "no es pot combinar --commit, --abort i -s/--strategy"
+#: builtin/notes.c
msgid "must specify a notes ref to merge"
msgstr "cal especificar una referència de notes a fusionar"
+#: builtin/notes.c
#, c-format
msgid "unknown -s/--strategy: %s"
msgstr "-s/--strategy desconeguda: %s"
+#: builtin/notes.c
#, c-format
msgid "a notes merge into %s is already in-progress at %s"
msgstr "una fusió de notes a %s ja està en curs a %s"
+#: builtin/notes.c
#, c-format
msgid "failed to store link to current notes ref (%s)"
msgstr ""
"s'ha produït un error en emmagatzemar l'enllaç a la referència de notes "
"actual (%s)"
+#: builtin/notes.c
#, c-format
msgid ""
"Automatic notes merge failed. Fix conflicts in %s and commit the result with "
@@ -9003,44 +11612,56 @@ msgstr ""
"cometeu el resultat amb «git notes merge --commit», o avorteu la fusió amb "
"«git notes merge --abort».\n"
+#: builtin/notes.c builtin/tag.c
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
msgstr "S'ha produït un error en resoldre «%s» com a referència vàlida."
+#: builtin/notes.c
#, c-format
msgid "Object %s has no note\n"
msgstr "L'objecte %s no té cap nota\n"
+#: builtin/notes.c
msgid "attempt to remove non-existent note is not an error"
msgstr "l'intent d'eliminar una nota no existent no és un error"
+#: builtin/notes.c
msgid "read object names from the standard input"
msgstr "llegeix els noms d'objecte des de l'entrada estàndard"
+#: builtin/notes.c builtin/prune.c builtin/worktree.c
msgid "do not remove, show only"
msgstr "no eliminis, només mostra"
+#: builtin/notes.c
msgid "report pruned notes"
msgstr "informa de notes podades"
+#: builtin/notes.c
msgid "notes-ref"
msgstr "referència de notes"
+#: builtin/notes.c
msgid "use notes from <notes-ref>"
msgstr "usa les notes de <referència-de-notes>"
+#: builtin/notes.c builtin/remote.c parse-options.c
#, c-format
msgid "unknown subcommand: `%s'"
msgstr "subordre desconeguda: «%s»"
+#: builtin/pack-objects.c
msgid "git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"
msgstr "git pack-objects --stdout [<opcions>] [< <ref-list> | < <object-list>]"
+#: builtin/pack-objects.c
msgid ""
"git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"
msgstr ""
"git pack-objects [<opcions>] <base-name> [< <ref-list> | < <object-list>]"
+#: builtin/pack-objects.c
#, c-format
msgid ""
"write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
@@ -9049,104 +11670,135 @@ msgstr ""
"write_reuse_object: no s'ha pogut localitzar %s, s'esperava a la posició "
"%<PRIuMAX> al paquet %s"
+#: builtin/pack-objects.c
#, c-format
msgid "bad packed object CRC for %s"
msgstr "CRC de l'objecte empaquetat malmès per a %s"
+#: builtin/pack-objects.c
#, c-format
msgid "corrupt packed object for %s"
msgstr "objecte empaquetat corrupte per a %s"
+#: builtin/pack-objects.c
#, c-format
msgid "recursive delta detected for object %s"
msgstr "diferència recursiva detectada per a l'objecte %s"
+#: builtin/pack-objects.c
#, c-format
msgid "ordered %u objects, expected %<PRIu32>"
msgstr "ordenats %u objectes, s'esperaven %<PRIu32>"
+#: builtin/pack-objects.c
#, c-format
msgid "expected object at offset %<PRIuMAX> in pack %s"
msgstr "objecte esperat a la posició %<PRIuMAX> al paquet %s"
+#: builtin/pack-objects.c
msgid "disabling bitmap writing, packs are split due to pack.packSizeLimit"
msgstr ""
"s'està inhabilitant l'escriptura de mapes de bits, es divideixen els paquets "
"a causa de pack.packSizeLimit"
+#: builtin/pack-objects.c
msgid "Writing objects"
msgstr "S'estan escrivint els objectes"
+#: builtin/pack-objects.c builtin/update-index.c
#, c-format
msgid "failed to stat %s"
msgstr "s'ha produït un error en fer stat a %s"
+#: builtin/pack-objects.c object-file.c
#, c-format
msgid "failed utime() on %s"
msgstr "ha fallat utime() a %s"
+#: builtin/pack-objects.c
msgid "failed to write bitmap index"
msgstr "s'ha produït un error en escriure l'índex de mapa de bits"
+#: builtin/pack-objects.c
#, c-format
msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
msgstr "escrits %<PRIu32> objectes mentre s'esperaven %<PRIu32>"
+#: builtin/pack-objects.c builtin/repack.c
msgid "disabling bitmap writing, as some objects are not being packed"
msgstr ""
"s'està inhabilitant l'escriptura de mapes de bits, perquè alguns objectes no "
"s'empaqueten"
+#: builtin/pack-objects.c
#, c-format
msgid "delta base offset overflow in pack for %s"
msgstr "desbordament del desplaçament base de diferències en paquet per a %s"
+#: builtin/pack-objects.c
#, c-format
msgid "delta base offset out of bound for %s"
msgstr "desplaçament base de diferències fora dels límits per a %s"
+#: builtin/pack-objects.c
msgid "Counting objects"
msgstr "S'estan comptant els objectes"
+#: builtin/pack-objects.c pack-bitmap.c
#, c-format
msgid "unable to get size of %s"
msgstr "no s'ha pogut obtenir la mida de %s"
+#: builtin/pack-objects.c
#, c-format
msgid "unable to parse object header of %s"
msgstr "no s'ha pogut analitzar la capçalera de l'objecte de %s"
+#: builtin/pack-objects.c
#, c-format
msgid "object %s cannot be read"
msgstr "no es pot llegir l'objecte %s"
+#: builtin/pack-objects.c
#, c-format
msgid "object %s inconsistent object length (%<PRIuMAX> vs %<PRIuMAX>)"
msgstr ""
"l'objecte %s té una longitud d'objecte inconsistent (%<PRIuMAX> vs "
"%<PRIuMAX>)"
+#: builtin/pack-objects.c
msgid "suboptimal pack - out of memory"
msgstr "paquet subòptim - sense memòria"
+#: builtin/pack-objects.c
#, c-format
msgid "Delta compression using up to %d threads"
msgstr "Compressió de diferències usant fins a %d fils"
+#: builtin/pack-objects.c
#, c-format
msgid "unable to pack objects reachable from tag %s"
msgstr "no s'han pogut empaquetar els objectes abastables des de l'etiqueta %s"
+#: builtin/pack-objects.c commit-graph.c
#, c-format
msgid "unable to get type of object %s"
msgstr "no s'ha pogut obtenir el tipus de l'objecte: %s"
+#: builtin/pack-objects.c
msgid "Compressing objects"
msgstr "S'estan comprimint els objectes"
+#: builtin/pack-objects.c
msgid "inconsistency with delta count"
msgstr "inconsistència amb el comptador de diferències"
+#: builtin/pack-objects.c
+#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "valor pack.allowPackReuse value no vàlid: «%s»"
+
+#: builtin/pack-objects.c
#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
@@ -9155,6 +11807,7 @@ msgstr ""
"el valor de uploadpack.blobpackfileuri ha de tenir la forma «<object-hash> "
"<pack-hash> <uri>» (s'ha rebut «%s»)"
+#: builtin/pack-objects.c
#, c-format
msgid ""
"object already configured in another uploadpack.blobpackfileuri (got '%s')"
@@ -9162,27 +11815,34 @@ msgstr ""
"l'objecte ja està configurat en un altre uploadpack.blobpackfileuri (s'ha "
"rebut «%s»)"
+#: builtin/pack-objects.c
#, c-format
msgid "could not get type of object %s in pack %s"
msgstr "no s'ha pogut obtenir el tipus de l'objecte %s al paquet %s"
+#: builtin/pack-objects.c
#, c-format
msgid "could not find pack '%s'"
msgstr "no s'ha pogut trobar el paquet «%s»"
+#: builtin/pack-objects.c
#, c-format
msgid "packfile %s cannot be accessed"
msgstr "no es pot accedir al fitxer de paquet %s"
+#: builtin/pack-objects.c
msgid "Enumerating cruft objects"
msgstr "S'estan enumerant els objectes superflus"
+#: builtin/pack-objects.c
msgid "unable to add cruft objects"
msgstr "no s'han pogut afegir els objectes superflus"
+#: builtin/pack-objects.c
msgid "Traversing cruft objects"
msgstr "S'estan recorrent els objectes superflus"
+#: builtin/pack-objects.c
#, c-format
msgid ""
"expected edge object ID, got garbage:\n"
@@ -9191,6 +11851,7 @@ msgstr ""
"s'esperava un identificador vora de l'objecte, s'ha rebut brossa:\n"
" %s"
+#: builtin/pack-objects.c
#, c-format
msgid ""
"expected object ID, got garbage:\n"
@@ -9199,230 +11860,289 @@ msgstr ""
"s'esperava un identificador d'objecte, s'ha rebut brossa:\n"
" %s"
+#: builtin/pack-objects.c reachable.c
msgid "could not load cruft pack .mtimes"
msgstr "no s'ha pogut carregar superflus del paquet superflu"
+#: builtin/pack-objects.c
msgid "cannot open pack index"
msgstr "no s'ha pogut obrir l'índex del paquet"
+#: builtin/pack-objects.c
#, c-format
msgid "loose object at %s could not be examined"
msgstr "no s'ha pogut examinar l'objecte solt a %s"
+#: builtin/pack-objects.c
msgid "unable to force loose object"
msgstr "no s'ha pogut forçar l'objecte solt"
+#: builtin/pack-objects.c
#, c-format
msgid "not a rev '%s'"
msgstr "«%s» no és una revisió"
+#: builtin/pack-objects.c builtin/rev-parse.c
#, c-format
msgid "bad revision '%s'"
msgstr "revisió incorrecta «%s»"
+#: builtin/pack-objects.c
msgid "unable to add recent objects"
msgstr "no s'han pogut afegir els objectes recents"
+#: builtin/pack-objects.c
#, c-format
msgid "unsupported index version %s"
msgstr "versió d'índex no compatible %s"
+#: builtin/pack-objects.c
#, c-format
msgid "bad index version '%s'"
msgstr "versió d'índex incorrecta «%s»"
+#: builtin/pack-objects.c
msgid "show progress meter during object writing phase"
msgstr "mostra l'indicador de progrés durant la fase d'escriptura d'objectes"
+#: builtin/pack-objects.c
msgid "similar to --all-progress when progress meter is shown"
msgstr "similar a --all-progress quan l'indicador de progrés es mostra"
+#: builtin/pack-objects.c
msgid "<version>[,<offset>]"
msgstr "<versió>[,<desplaçament>]"
+#: builtin/pack-objects.c
msgid "write the pack index file in the specified idx format version"
msgstr ""
"escriu el fitxer d'índex de paquet en la versió de format d'índex "
"especificada"
+#: builtin/pack-objects.c
msgid "maximum size of each output pack file"
msgstr "mida màxima de cada fitxer empaquetat de sortida"
+#: builtin/pack-objects.c
msgid "ignore borrowed objects from alternate object store"
msgstr ""
"ignora els objectes manllevats d'un emmagatzematge d'objectes alternatiu"
+#: builtin/pack-objects.c
msgid "ignore packed objects"
msgstr "ignora els objectes empaquetats"
+#: builtin/pack-objects.c
msgid "limit pack window by objects"
msgstr "limita la finestra d'empaquetament per objectes"
+#: builtin/pack-objects.c
msgid "limit pack window by memory in addition to object limit"
msgstr ""
"limita la finestra d'empaquetament per memòria a més del límit d'objectes"
+#: builtin/pack-objects.c
msgid "maximum length of delta chain allowed in the resulting pack"
msgstr ""
"longitud màxima de la cadena de diferències permesa en el paquet resultant"
+#: builtin/pack-objects.c
msgid "reuse existing deltas"
msgstr "reusa les diferències existents"
+#: builtin/pack-objects.c
msgid "reuse existing objects"
msgstr "reusa els objectes existents"
+#: builtin/pack-objects.c
msgid "use OFS_DELTA objects"
msgstr "usa objectes OFS_DELTA"
+#: builtin/pack-objects.c
msgid "use threads when searching for best delta matches"
msgstr "usa fils en cercar les millors coincidències de diferències"
+#: builtin/pack-objects.c
msgid "do not create an empty pack output"
msgstr "no creïs una emissió de paquet buit"
+#: builtin/pack-objects.c
msgid "read revision arguments from standard input"
msgstr "llegeix els arguments de revisió des de l'entrada estàndard"
+#: builtin/pack-objects.c
msgid "limit the objects to those that are not yet packed"
msgstr "limita els objectes a aquells que encara no estan empaquetats"
+#: builtin/pack-objects.c
msgid "include objects reachable from any reference"
msgstr "inclou els objectes abastables de qualsevol referència"
+#: builtin/pack-objects.c
msgid "include objects referred by reflog entries"
msgstr ""
"inclou els objectes als quals facin referència les entrades del registre de "
"referències"
+#: builtin/pack-objects.c
msgid "include objects referred to by the index"
msgstr "inclou els objectes als quals faci referència l'índex"
+#: builtin/pack-objects.c
msgid "read packs from stdin"
msgstr "llegeix els paquets des de stdin"
+#: builtin/pack-objects.c
msgid "output pack to stdout"
msgstr "emet el paquet a stdout"
+#: builtin/pack-objects.c
msgid "include tag objects that refer to objects to be packed"
msgstr ""
"inclou els objectes d'etiqueta que facin referència als objectes a empaquetar"
+#: builtin/pack-objects.c
msgid "keep unreachable objects"
msgstr "retén els objectes inabastables"
+#: builtin/pack-objects.c
msgid "pack loose unreachable objects"
msgstr "empaqueta els objectes inabastables solts"
+#: builtin/pack-objects.c
msgid "unpack unreachable objects newer than <time>"
msgstr "desempaqueta els objectes inabastables més nous que <data>"
+#: builtin/pack-objects.c
msgid "create a cruft pack"
msgstr "crea un paquet superflu"
+#: builtin/pack-objects.c
msgid "expire cruft objects older than <time>"
msgstr "fes caducar els objectes superflus més antics que <data>"
+#: builtin/pack-objects.c
msgid "use the sparse reachability algorithm"
msgstr "utilitza l'algorisme d'accessibilitat dispers"
+#: builtin/pack-objects.c
msgid "create thin packs"
msgstr "crea paquets prims"
+#: builtin/pack-objects.c
msgid "create packs suitable for shallow fetches"
msgstr "crea paquets adequats per a les obtencions superficials"
+#: builtin/pack-objects.c
msgid "ignore packs that have companion .keep file"
msgstr "ignora els paquets que tinguin un fitxer .keep corresponent"
+#: builtin/pack-objects.c
msgid "ignore this pack"
msgstr "ignora aquest paquet"
+#: builtin/pack-objects.c
msgid "pack compression level"
msgstr "nivell de compressió de paquet"
+#: builtin/pack-objects.c
msgid "do not hide commits by grafts"
msgstr "no amaguis les comissions per empelt"
+#: builtin/pack-objects.c
msgid "use a bitmap index if available to speed up counting objects"
msgstr ""
"usa un índex de mapa de bits, si està disponible, per a accelerar el "
"recompte d'objectes"
+#: builtin/pack-objects.c
msgid "write a bitmap index together with the pack index"
msgstr "escriu un índex de mapa de bits juntament amb l'índex de paquet"
+#: builtin/pack-objects.c
msgid "write a bitmap index if possible"
msgstr "escriu un índex de mapa de bits si és possible"
+#: builtin/pack-objects.c
msgid "handling for missing objects"
msgstr "gestió dels objectes absents"
+#: builtin/pack-objects.c
msgid "do not pack objects in promisor packfiles"
msgstr "no empaquetis els objectes als fitxers de paquet «promisor»"
+#: builtin/pack-objects.c
msgid "respect islands during delta compression"
msgstr "respecta les illes durant la compressió delta"
+#: builtin/pack-objects.c
msgid "protocol"
msgstr "protocol"
+#: builtin/pack-objects.c
msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
msgstr ""
"exclou qualsevol uploadpack.blobpackfileuri configurat amb aquest protocol"
+#: builtin/pack-objects.c
#, c-format
msgid "delta chain depth %d is too deep, forcing %d"
msgstr "la profunditat de la cadena delta %d és massa profunda, forçant %d"
+#: builtin/pack-objects.c
#, c-format
msgid "pack.deltaCacheLimit is too high, forcing %d"
msgstr "pack.deltaCacheLimit és massa alt, forçant %d"
+#: builtin/pack-objects.c config.c
#, c-format
msgid "bad pack compression level %d"
msgstr "nivell de compressió de paquet %d erroni"
+#: builtin/pack-objects.c
msgid "--max-pack-size cannot be used to build a pack for transfer"
msgstr ""
"--max-pack-size no es pot utilitzar per a construir un paquet per a la "
"transferència"
+#: builtin/pack-objects.c
msgid "minimum pack size limit is 1 MiB"
msgstr "el límit mínim de mida del paquet és 1 MiB"
+#: builtin/pack-objects.c
msgid "--thin cannot be used to build an indexable pack"
msgstr "--thin no es pot utilitzar per a construir un paquet indexable"
-msgid "cannot use --filter without --stdout"
-msgstr "no es pot utilitzar --filter sense --stdout"
-
+#: builtin/pack-objects.c
msgid "cannot use --filter with --stdin-packs"
msgstr "no es pot utilitzar --filter sense --stdin-packs"
+#: builtin/pack-objects.c
msgid "cannot use internal rev list with --stdin-packs"
msgstr "no es pot utilitzar la llista de revisió interna amb --stdin-packs"
+#: builtin/pack-objects.c
msgid "cannot use internal rev list with --cruft"
msgstr "no es pot utilitzar la llista de revisió interna amb --cruft"
+#: builtin/pack-objects.c
msgid "cannot use --stdin-packs with --cruft"
msgstr "no es pot --stdin-packs amb --cruft"
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "no es pot usar --max-pack-size amb --cruft"
-
+#: builtin/pack-objects.c
msgid "Enumerating objects"
msgstr "S'estan enumerant els objectes"
+#: builtin/pack-objects.c
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Total %<PRIu32> (%<PRIu32> diferències), reusats %<PRIu32> (%<PRIu32> "
-"diferències), paquets reusats %<PRIu32>"
+"diferències), paquets reusats %<PRIu32> (de %<PRIuMAX>)"
+#: builtin/pack-redundant.c
msgid ""
"'git pack-redundant' is nominated for removal.\n"
"If you still use this command, please add an extra\n"
@@ -9436,91 +12156,124 @@ msgstr ""
"i feu-nos saber que encara l'useu enviant un correu electrònic\n"
"a <git@vger.kernel.org>. Gràcies.\n"
+#: builtin/pack-redundant.c
msgid "refusing to run without --i-still-use-this"
msgstr "es rebutja a executar sense --i-still-use-this"
+#: builtin/pack-refs.c
msgid ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <patró>] [--exclude <patró>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <patró>] [--exclude "
+"<patró>]"
+#: builtin/pack-refs.c
msgid "pack everything"
msgstr "empaqueta-ho tot"
+#: builtin/pack-refs.c
msgid "prune loose refs (default)"
msgstr "poda les referències soltes (per defecte)"
+#: builtin/pack-refs.c
+msgid "auto-pack refs as needed"
+msgstr "auto-empaqueta referències si cal"
+
+#: builtin/pack-refs.c
msgid "references to include"
msgstr "referències a incloure"
+#: builtin/pack-refs.c
msgid "references to exclude"
msgstr "referències a excloure"
+#: builtin/patch-id.c
msgid "git patch-id [--stable | --unstable | --verbatim]"
msgstr "git patch-id [--stable | --unstable | --verbatim]"
+#: builtin/patch-id.c
msgid "use the unstable patch-id algorithm"
msgstr "utilitza l'algorisme inestable de patch-id"
+#: builtin/patch-id.c
msgid "use the stable patch-id algorithm"
msgstr "utilitza l'algorisme estable de patch-id"
+#: builtin/patch-id.c
msgid "don't strip whitespace from the patch"
msgstr "no eliminis els espais en blanc del pedaç"
+#: builtin/prune.c
msgid "git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"
-msgstr "git prune [-n] [-v] [--progress] [--expire <data>] [--] [<head>...]"
+msgstr "git prune [-n] [-v] [--progress] [--expire <data>] [--] [<cap>...]"
+#: builtin/prune.c
msgid "report pruned objects"
msgstr "informa d'objectes podats"
+#: builtin/prune.c
msgid "expire objects older than <time>"
msgstr "fes caducar els objectes més antics que <data>"
+#: builtin/prune.c
msgid "limit traversal to objects outside promisor packfiles"
msgstr ""
"limita el recorregut als objectes fora dels fitxers de paquet «promisor»"
+#: builtin/prune.c
msgid "cannot prune in a precious-objects repo"
msgstr "no es pot podar en un repositori d'objectes preciosos"
+#: builtin/pull.c
msgid "git pull [<options>] [<repository> [<refspec>...]]"
-msgstr "git pull [<opcions>] [<repositori> [<especificació-de-referència>...]]"
+msgstr "git pull [<opcions>] [<repositori> [<especificació-referència>...]]"
+#: builtin/pull.c
msgid "control for recursive fetching of submodules"
msgstr "controla l'obtenció recursiva de submòduls"
+#: builtin/pull.c
msgid "Options related to merging"
msgstr "Opcions relacionades amb fusionar"
+#: builtin/pull.c
msgid "incorporate changes by rebasing rather than merging"
msgstr "incorpora els canvis fent «rebase» en lloc de fusionar"
+#: builtin/pull.c builtin/revert.c
msgid "allow fast-forward"
msgstr "permet l'avanç ràpid"
+#: builtin/pull.c
msgid "control use of pre-merge-commit and commit-msg hooks"
msgstr "controla l'ús dels lligams pre-merge-commit i commit-msg"
+#: builtin/pull.c parse-options.h
msgid "automatically stash/stash pop before and after"
msgstr "fes «stash» i «stash pop» automàticament abans i després"
+#: builtin/pull.c
msgid "Options related to fetching"
msgstr "Opcions relacionades amb obtenir"
+#: builtin/pull.c
msgid "force overwrite of local branch"
msgstr "força la sobreescriptura de la branca local"
+#: builtin/pull.c
msgid "number of submodules pulled in parallel"
msgstr "nombre de submòduls baixats en paral·lel"
+#: builtin/pull.c parse-options.h
msgid "use IPv4 addresses only"
msgstr "usa només adreces IPv4"
+#: builtin/pull.c parse-options.h
msgid "use IPv6 addresses only"
msgstr "usa només adreces IPv6"
+#: builtin/pull.c
msgid ""
"There is no candidate for rebasing against among the refs that you just "
"fetched."
@@ -9528,11 +12281,13 @@ msgstr ""
"No hi ha cap candidat sobre el qual fer «rebase» entre les referències que "
"acabeu d'obtenir."
+#: builtin/pull.c
msgid ""
"There are no candidates for merging among the refs that you just fetched."
msgstr ""
"No hi ha candidats per a fusionar entre les referències que acabeu d'obtenir."
+#: builtin/pull.c
msgid ""
"Generally this means that you provided a wildcard refspec which had no\n"
"matches on the remote end."
@@ -9540,6 +12295,7 @@ msgstr ""
"Generalment això vol dir que heu proveït una especificació de\n"
"referència de comodí que no tenia cap coincidència en el costat remot."
+#: builtin/pull.c
#, c-format
msgid ""
"You asked to pull from the remote '%s', but did not specify\n"
@@ -9550,33 +12306,42 @@ msgstr ""
"Perquè aquest no és el remot configurat per defecte per a la vostra\n"
"branca actual, heu d'especificar una branca en la línia d'ordres."
+#: builtin/pull.c builtin/rebase.c
msgid "You are not currently on a branch."
msgstr "Actualment no sou en cap branca."
+#: builtin/pull.c
msgid "Please specify which branch you want to rebase against."
msgstr "Especifiqueu sobre quina branca voleu fer «rebase»."
+#: builtin/pull.c
msgid "Please specify which branch you want to merge with."
msgstr "Especifiqueu amb quina branca voleu fusionar."
+#: builtin/pull.c
msgid "See git-pull(1) for details."
msgstr "Vegeu git-pull(1) per a més informació."
+#: builtin/pull.c builtin/rebase.c
msgid "<remote>"
msgstr "<remot>"
+#: builtin/pull.c scalar.c
msgid "<branch>"
msgstr "<branca>"
+#: builtin/pull.c builtin/rebase.c
msgid "There is no tracking information for the current branch."
msgstr "No hi ha cap informació de seguiment per a la branca actual."
+#: builtin/pull.c
msgid ""
"If you wish to set tracking information for this branch you can do so with:"
msgstr ""
"Si voleu establir la informació de seguiment per a aquesta branca, podeu fer-"
"ho amb:"
+#: builtin/pull.c
#, c-format
msgid ""
"Your configuration specifies to merge with the ref '%s'\n"
@@ -9585,13 +12350,16 @@ msgstr ""
"La vostra configuració especifica fusionar amb la referència «%s»\n"
"del remot, però no s'ha obtingut tal referència."
+#: builtin/pull.c
#, c-format
msgid "unable to access commit %s"
msgstr "no s'ha pogut accedir a la comissió %s"
+#: builtin/pull.c
msgid "ignoring --verify-signatures for rebase"
msgstr "s'està ignorant --verify-signatures en fer «rebase»"
+#: builtin/pull.c
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"
@@ -9621,26 +12389,31 @@ msgstr ""
"--no-rebase o --ff-only en la línia d'ordres per a sobreescriure el valor\n"
"per defecte de la configuració en aquesta execució.\n"
+#: builtin/pull.c
msgid "Updating an unborn branch with changes added to the index."
msgstr ""
"S'està actualitzant una branca no nascuda amb canvis afegits a l'índex."
+#: builtin/pull.c
msgid "pull with rebase"
msgstr "baixar fent «rebase»"
+#: builtin/pull.c builtin/rebase.c
msgid "Please commit or stash them."
msgstr "Cometeu-los o emmagatzemeu-los."
+#: builtin/pull.c
#, c-format
msgid ""
"fetch updated the current branch head.\n"
"fast-forwarding your working tree from\n"
"commit %s."
msgstr ""
-"l'obtenció ha actualitzat HEAD de la branca actual.\n"
+"l'obtenció ha actualitzat el HEAD de la branca actual.\n"
"s'està avançant ràpidament el vostre arbre de treball des de\n"
"la comissió %s."
+#: builtin/pull.c
#, c-format
msgid ""
"Cannot fast-forward your working tree.\n"
@@ -9658,32 +12431,41 @@ msgstr ""
"$ git reset --hard\n"
"per a recuperar."
+#: builtin/pull.c
msgid "Cannot merge multiple branches into empty head."
msgstr "No es poden fusionar múltiples branques a una HEAD buida."
+#: builtin/pull.c
msgid "Cannot rebase onto multiple branches."
msgstr "No es pot fer «rebase» sobre múltiples branques."
+#: builtin/pull.c
msgid "Cannot fast-forward to multiple branches."
msgstr "No es pot fer un avançament ràpid a branques múltiples."
+#: builtin/pull.c
msgid "Need to specify how to reconcile divergent branches."
msgstr "Cal especificar com reconciliar les branques divergents."
+#: builtin/pull.c
msgid "cannot rebase with locally recorded submodule modifications"
msgstr ""
"no es pot fer «rebase» amb modificacions als submòduls enregistrades "
"localment"
+#: builtin/push.c
msgid "git push [<options>] [<repository> [<refspec>...]]"
-msgstr "git push [<opcions>] [<repositori> [<especificació-de-referència>...]]"
+msgstr "git push [<opcions>] [<repositori> [<especificació-referència>...]]"
+#: builtin/push.c
msgid "tag shorthand without <tag>"
-msgstr "abreviatura d'etiqueta sense <tag>"
+msgstr "abreviatura d'etiqueta sense <etiqueta>"
+#: builtin/push.c
msgid "--delete only accepts plain target ref names"
msgstr "--delete només accepta noms de referència de destí senzills"
+#: builtin/push.c
msgid ""
"\n"
"To choose either option permanently, see push.default in 'git help config'.\n"
@@ -9692,6 +12474,7 @@ msgstr ""
"Per a triar qualsevol de les opcions permanentment, vegeu push.default a "
"«git help config».\n"
+#: builtin/push.c
msgid ""
"\n"
"To avoid automatically configuring an upstream branch when its name\n"
@@ -9703,6 +12486,7 @@ msgstr ""
"no coincideix amb el de la branca local, vegeu l'opció «simple» de\n"
"«branch.autoSetupMerge» a «git help config».\n"
+#: builtin/push.c
#, c-format
msgid ""
"The upstream branch of your current branch does not match\n"
@@ -9727,6 +12511,7 @@ msgstr ""
" git push %s HEAD\n"
"%s%s"
+#: builtin/push.c
#, c-format
msgid ""
"You are not currently on a branch.\n"
@@ -9741,6 +12526,7 @@ msgstr ""
"\n"
" git push %s HEAD:<nom-de-branca-remota>\n"
+#: builtin/push.c
msgid ""
"\n"
"To have this happen automatically for branches without a tracking\n"
@@ -9751,6 +12537,7 @@ msgstr ""
"seguiment\n"
"font, vegeu «push.autoSetupRemote» a «git help config».\n"
+#: builtin/push.c
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
@@ -9765,17 +12552,20 @@ msgstr ""
" git push --set-upstream %s %s\n"
"%s"
+#: builtin/push.c
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr ""
"La branca actual %s té múltiples branques fonts, s'està refusant pujar."
+#: builtin/push.c
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
"No heu especificat cap especificació de referència a pujar, i push.default "
"és «nothing»."
+#: builtin/push.c
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
@@ -9786,6 +12576,7 @@ msgstr ""
"branca actual «%s», sense dir-me què pujar per a actualitzar\n"
"quina branca remota."
+#: builtin/push.c
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"
@@ -9797,6 +12588,7 @@ msgstr ""
"remots useu «git pull» abans de tornar a pujar.\n"
"Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
+#: builtin/push.c
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"
@@ -9808,6 +12600,7 @@ msgstr ""
"utilitzeu «git pull» abans de tornar a pujar.\n"
"Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
+#: builtin/push.c
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"
@@ -9817,15 +12610,17 @@ msgid ""
msgstr ""
"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"
+"localment. Això sol ser causat per un altre repositori que ha 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."
+#: builtin/push.c
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
"S'han rebutjat les actualitzacions perquè l'etiqueta ja existeix en el remot."
+#: builtin/push.c
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"
@@ -9836,6 +12631,7 @@ msgstr ""
"a fer que assenyali un objecte no de comissió, sense usar l'opció\n"
"«--force».\n"
+#: builtin/push.c
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"
@@ -9847,14 +12643,17 @@ msgstr ""
"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."
+#: builtin/push.c
#, c-format
msgid "Pushing to %s\n"
msgstr "S'està pujant a %s\n"
+#: builtin/push.c
#, c-format
msgid "failed to push some refs to '%s'"
msgstr "s'ha produït un error en pujar algunes referències a «%s»"
+#: builtin/push.c
msgid ""
"recursing into submodule with push.recurseSubmodules=only; using on-demand "
"instead"
@@ -9862,71 +12661,93 @@ msgstr ""
"cerca recursivament en el submòdul amb push.recurseSubmodules=only; "
"utilitzant «on-demand» en el seu lloc"
+#: builtin/push.c builtin/send-pack.c submodule-config.c
#, c-format
msgid "invalid value for '%s'"
msgstr "valor no vàlid per a «%s»"
+#: builtin/push.c builtin/submodule--helper.c
msgid "repository"
msgstr "repositori"
+#: builtin/push.c
msgid "push all branches"
msgstr "puja totes les referències"
+#: builtin/push.c builtin/send-pack.c
msgid "mirror all refs"
msgstr "reflecteix totes les referències"
+#: builtin/push.c
msgid "delete refs"
msgstr "suprimeix les referències"
+#: builtin/push.c
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)"
+#: builtin/push.c builtin/send-pack.c
msgid "force updates"
msgstr "força les actualitzacions"
+#: builtin/push.c builtin/send-pack.c
msgid "<refname>:<expect>"
-msgstr "<nom-de-referència>:<esperat>"
+msgstr "<nom-referència>:<esperat>"
+#: builtin/push.c builtin/send-pack.c
msgid "require old value of ref to be at this value"
msgstr "requereix que el valor antic de la referència sigui d'aquest valor"
+#: builtin/push.c builtin/send-pack.c
msgid "require remote updates to be integrated locally"
msgstr "requereix que les actualitzacions remotes s'integrin localment"
+#: builtin/push.c
msgid "control recursive pushing of submodules"
msgstr "controla la pujada recursiva dels submòduls"
+#: builtin/push.c builtin/send-pack.c
msgid "use thin pack"
msgstr "usa el paquet prim"
+#: builtin/push.c builtin/send-pack.c
msgid "receive pack program"
msgstr "programa que rep els paquets"
+#: builtin/push.c
msgid "set upstream for git pull/status"
msgstr "estableix la font per a git pull/status"
+#: builtin/push.c
msgid "prune locally removed refs"
msgstr "poda les referències eliminades localment"
+#: builtin/push.c
msgid "bypass pre-push hook"
msgstr "evita el lligam de prepujada"
+#: builtin/push.c
msgid "push missing but relevant tags"
msgstr "puja les etiquetes absents però rellevants"
+#: builtin/push.c builtin/send-pack.c
msgid "GPG sign the push"
msgstr "signa la pujada amb GPG"
+#: builtin/push.c builtin/send-pack.c
msgid "request atomic transaction on remote side"
msgstr "demana una transacció atòmica al costat remot"
+#: builtin/push.c
msgid "--delete doesn't make sense without any refs"
msgstr "--delete no té sentit sense referències"
+#: builtin/push.c t/helper/test-bundle-uri.c
#, c-format
msgid "bad repository '%s'"
msgstr "repositori incorrecte «%s»"
+#: builtin/push.c
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
@@ -9948,54 +12769,70 @@ msgstr ""
"\n"
" git push <nom>\n"
+#: builtin/push.c
msgid "--all can't be combined with refspecs"
msgstr "--all no es pot combinar amb especificacions de referència"
+#: builtin/push.c
msgid "--mirror can't be combined with refspecs"
msgstr "--mirror no es pot combinar amb especificacions de referència"
+#: builtin/push.c
msgid "push options must not have new line characters"
msgstr "les opcions de pujada no han de tenir caràcters de línia nova"
+#: builtin/range-diff.c
msgid "git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"
msgstr "git range-diff [<opcions>] <old-base>..<old-tip> <new-base>..<new-tip>"
+#: builtin/range-diff.c
msgid "git range-diff [<options>] <old-tip>...<new-tip>"
msgstr "git range-diff [<opcions>] <old-tip>...<new-tip>"
+#: builtin/range-diff.c
msgid "git range-diff [<options>] <base> <old-tip> <new-tip>"
msgstr "git range-diff [<opcions>] <base> <old-tip> <new-tip>"
+#: builtin/range-diff.c
msgid "use simple diff colors"
msgstr "utilitza colors simples de diff"
+#: builtin/range-diff.c
msgid "notes"
msgstr "notes"
+#: builtin/range-diff.c
msgid "passed to 'git log'"
msgstr "passa-ho a «git log»"
+#: builtin/range-diff.c
msgid "only emit output related to the first range"
msgstr "emet només la sortida relacionada amb el primer interval"
+#: builtin/range-diff.c
msgid "only emit output related to the second range"
msgstr "emet només la sortida relacionada amb el segon interval"
+#: builtin/range-diff.c
#, c-format
msgid "not a revision: '%s'"
msgstr "«%s» no és una revisió"
+#: builtin/range-diff.c
#, c-format
msgid "not a commit range: '%s'"
msgstr "no és un rang de comissions: «%s»"
+#: builtin/range-diff.c
#, c-format
msgid "not a symmetric range: '%s'"
msgstr "no és un rang simètric: «%s»"
+#: builtin/range-diff.c
msgid "need two commit ranges"
msgstr "calen dos rangs de comissió"
+#: builtin/read-tree.c
msgid ""
"git read-tree [(-m [--trivial] [--aggressive] | --reset | --"
"prefix=<prefix>)\n"
@@ -10007,60 +12844,79 @@ msgstr ""
" [-u | -i]] [--index-output=<fitxer>] [--no-sparse-checkout]\n"
" (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
+#: builtin/read-tree.c
msgid "write resulting index to <file>"
msgstr "escriu l'índex resultant al <fitxer>"
+#: builtin/read-tree.c
msgid "only empty the index"
msgstr "només buida l'índex"
+#: builtin/read-tree.c
msgid "Merging"
msgstr "S'està fusionant"
+#: builtin/read-tree.c
msgid "perform a merge in addition to a read"
msgstr "realitza una fusió a més d'una lectura"
+#: builtin/read-tree.c
msgid "3-way merge if no file level merging required"
msgstr "fusió de 3 vies si no cal fusió a nivell de fitxers"
+#: builtin/read-tree.c
msgid "3-way merge in presence of adds and removes"
msgstr "fusió de 3 vies en presència d'afegiments i eliminacions"
+#: builtin/read-tree.c
msgid "same as -m, but discard unmerged entries"
msgstr "el mateix que -m, però descarta les entrades no fusionades"
+#: builtin/read-tree.c
msgid "<subdirectory>/"
msgstr "<subdirectori>/"
+#: builtin/read-tree.c
msgid "read the tree into the index under <subdirectory>/"
msgstr "llegeix l'arbre a l'índex sota <subdirectori>/"
+#: builtin/read-tree.c
msgid "update working tree with merge result"
msgstr "actualitza l'arbre de treball amb el resultat de fusió"
+#: builtin/read-tree.c
msgid "gitignore"
msgstr "gitignore"
+#: builtin/read-tree.c
msgid "allow explicitly ignored files to be overwritten"
msgstr "permet que els fitxers explícitament ignorats se sobreescriguin"
+#: builtin/read-tree.c
msgid "don't check the working tree after merging"
msgstr "no comprovis l'arbre de treball després de fusionar"
+#: builtin/read-tree.c
msgid "don't update the index or the work tree"
msgstr "no actualitzis l'índex ni l'arbre de treball"
+#: builtin/read-tree.c
msgid "skip applying sparse checkout filter"
msgstr "omet l'aplicació del filtre d'agafament parcial"
+#: builtin/read-tree.c
msgid "debug unpack-trees"
msgstr "depura unpack-trees"
+#: builtin/read-tree.c
msgid "suppress feedback messages"
msgstr "suprimeix els missatges de retroacció"
+#: builtin/read-tree.c
msgid "You need to resolve your current index first"
msgstr "Primer heu de resoldre el vostre índex actual"
+#: builtin/rebase.c
msgid ""
"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase> | --keep-base] "
"[<upstream> [<branch>]]"
@@ -10068,64 +12924,61 @@ msgstr ""
"git rebase [-i] [options] [--exec <ordre>] [--onto <newbase> | --keep-base] "
"[<upstream> [<branca>]]"
+#: builtin/rebase.c
msgid ""
"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]"
msgstr ""
"git rebase [-i] [options] [--exec <ordre>] [--onto <newbase>] --root "
"[<branca>]"
+#: builtin/rebase.c sequencer.c
#, c-format
msgid "could not read '%s'."
msgstr "no s'ha pogut llegir «%s»."
+#: builtin/rebase.c
#, c-format
msgid "could not create temporary %s"
msgstr "no s'ha pogut crear el fitxer temporal %s"
+#: builtin/rebase.c
msgid "could not mark as interactive"
msgstr "no s'ha pogut marcar com a interactiu"
+#: builtin/rebase.c
msgid "could not generate todo list"
msgstr "no s'ha pogut generar la llista per a fer"
+#: builtin/rebase.c
msgid "a base commit must be provided with --upstream or --onto"
msgstr "s'ha de proporcionar una comissió base amb --upstream o --onto"
+#: builtin/rebase.c
#, c-format
msgid "%s requires the merge backend"
msgstr "%s requereix un rerefons de fusió"
+#: builtin/rebase.c
#, c-format
msgid "invalid onto: '%s'"
msgstr "no vàlid a: «%s»"
+#: builtin/rebase.c
#, c-format
msgid "invalid orig-head: '%s'"
msgstr "orig-head no és vàlid: «%s»"
+#: builtin/rebase.c
#, c-format
msgid "ignoring invalid allow_rerere_autoupdate: '%s'"
msgstr "s'ignora allow_rerere_autoupdate no vàlid: «%s»"
+#: builtin/rebase.c builtin/rm.c sequencer.c
#, c-format
msgid "could not remove '%s'"
msgstr "no s'ha pogut eliminar «%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 ""
-"Resoleu tots els conflictes manualment, marqueu-los com a resolts amb\n"
-"«git add/rm <fitxers_amb_conflicte>», llavors executeu «git rebase --"
-"continue».\n"
-"Alternativament podeu ometre aquesta comissió: executeu «git rebase --"
-"skip».\n"
-"Per a avortar i tornar a l'estat anterior abans de l'ordre «git rebase», "
-"executeu «git rebase --abort»."
-
+#: builtin/rebase.c
#, c-format
msgid ""
"\n"
@@ -10144,24 +12997,34 @@ msgstr ""
"\n"
"Com a resultat, git no pot fer un «rebase» d'elles."
+#: builtin/rebase.c
#, c-format
msgid "Unknown rebase-merges mode: %s"
msgstr "Mode de fusió de rebase desconegut: %s"
+#: builtin/rebase.c
#, c-format
msgid "could not switch to %s"
msgstr "no s'ha pogut commutar a %s"
+#: builtin/rebase.c
msgid "apply options and merge options cannot be used together"
msgstr "les opcions apply i merge no es poden usar juntes"
+#: builtin/rebase.c
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask és obslolet; utilitzeu '--empty=stop' en el seu lloc."
+
+#: builtin/rebase.c
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
-"tipus buit no reconegut «%s»; els valors vàlids són «drop», «keep» i «ask»."
+"tipus buit «%s» no reconegut; els valors vàlids són \"drop\", \"keep\" i "
+"\"stop\"."
+#: 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 "
@@ -10171,6 +13034,7 @@ msgstr ""
"funcionar en una versió futura del Git. Utilitzeu --rebase-merges sense un "
"argument, que fa el mateix."
+#: builtin/rebase.c
#, c-format
msgid ""
"%s\n"
@@ -10187,6 +13051,7 @@ msgstr ""
" git rebase '<branca>'\n"
"\n"
+#: builtin/rebase.c
#, c-format
msgid ""
"If you wish to set tracking information for this branch you can do so with:\n"
@@ -10200,128 +13065,169 @@ msgstr ""
" git branch --set-upstream-to=%s/<branca> %s\n"
"\n"
+#: builtin/rebase.c
msgid "exec commands cannot contain newlines"
msgstr "les ordres exec no poden contenir línies noves"
+#: builtin/rebase.c
msgid "empty exec command"
msgstr "ordre exec buida"
+#: builtin/rebase.c
msgid "rebase onto given branch instead of upstream"
msgstr "fes un «rebase» en la branca donada en comptes de la font"
+#: builtin/rebase.c
msgid "use the merge-base of upstream and branch as the current base"
msgstr "utilitza la base de fusió de la font i la branca com a base actual"
+#: builtin/rebase.c
msgid "allow pre-rebase hook to run"
msgstr "permet al lligam pre-rebase executar-se"
+#: builtin/rebase.c
msgid "be quiet. implies --no-stat"
msgstr "silenciós. Implica --no-stat"
+#: builtin/rebase.c
msgid "display a diffstat of what changed upstream"
msgstr "mostra un «diffstat» del que ha canviat a la font"
+#: builtin/rebase.c
msgid "do not show diffstat of what changed upstream"
msgstr "no mostris «diffstat» del que ha canviat a la font"
+#: builtin/rebase.c
msgid "add a Signed-off-by trailer to each commit"
msgstr "afegeix un «trailer» tipus «Signed-off-by» a cada comissió"
+#: builtin/rebase.c
msgid "make committer date match author date"
msgstr "fes que la data del «committer» coincideixi amb la data de l'autor"
+#: builtin/rebase.c
msgid "ignore author date and use current date"
msgstr "ignora la data de l'autor i utilitza la data actual"
+#: builtin/rebase.c
msgid "synonym of --reset-author-date"
msgstr "sinònim de --reset-author-date"
+#: builtin/rebase.c
msgid "passed to 'git apply'"
msgstr "passa-ho a «git apply»"
+#: builtin/rebase.c
msgid "ignore changes in whitespace"
msgstr "ignora els canvis d'espais en blanc"
+#: builtin/rebase.c
msgid "cherry-pick all commits, even if unchanged"
msgstr "«cherry pick» totes les comissions, inclús les no canviades"
+#: builtin/rebase.c
msgid "continue"
msgstr "continua"
+#: builtin/rebase.c
msgid "skip current patch and continue"
msgstr "omet el pedaç actual i continua"
+#: builtin/rebase.c
msgid "abort and check out the original branch"
msgstr "interromp i agafa la branca original"
+#: builtin/rebase.c
msgid "abort but keep HEAD where it is"
msgstr "interromp però manté HEAD on és"
+#: builtin/rebase.c
msgid "edit the todo list during an interactive rebase"
msgstr "edita la llista de coses a fer durant un «rebase» interactiu"
+#: builtin/rebase.c
msgid "show the patch file being applied or merged"
msgstr "mostra el pedaç que s'està aplicant o fusionant"
+#: builtin/rebase.c
msgid "use apply strategies to rebase"
msgstr "utilitza estratègies d'aplicació per a fer «rebase»"
+#: builtin/rebase.c
msgid "use merging strategies to rebase"
msgstr "utilitza estratègies de fusió per a fer «rebase»"
+#: builtin/rebase.c
msgid "let the user edit the list of commits to rebase"
msgstr "permet a l'usuari editar la llista de comissions a fer «rebase»"
+#: builtin/rebase.c
msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
msgstr "(SUPRIMIT) era: intenta recrear fusions en lloc d'ignorar-les"
+#: builtin/rebase.c builtin/revert.c
msgid "how to handle commits that become empty"
msgstr "com gestionar les comissions que queden buides"
+#: builtin/rebase.c
msgid "keep commits which start empty"
msgstr "manté les comissions que comencen en blanc"
+#: builtin/rebase.c
msgid "move commits that begin with squash!/fixup! under -i"
msgstr "mou les comissions que comencen amb squash!/fixup! sota -i"
+#: builtin/rebase.c
msgid "update branches that point to commits that are being rebased"
msgstr ""
"actualitza les branques que apunten a comissions a les quals se'ls està fent "
"«rebase»"
+#: builtin/rebase.c
msgid "add exec lines after each commit of the editable list"
msgstr "afegeix línies d'exec després de cada comissió de la llista editable"
+#: builtin/rebase.c
msgid "allow rebasing commits with empty messages"
msgstr "permet fer «rebase» de les comissions amb missatges buits"
+#: builtin/rebase.c
msgid "try to rebase merges instead of skipping them"
msgstr "intenta fer «rebase» de les fusions en comptes d'ometre-les"
+#: builtin/rebase.c
msgid "use 'merge-base --fork-point' to refine upstream"
msgstr "usa «merge-base --fork-point» per a refinar la font"
+#: builtin/rebase.c
msgid "use the given merge strategy"
msgstr "utilitza l'estratègia de fusió donada"
+#: builtin/rebase.c builtin/revert.c
msgid "option"
msgstr "opció"
+#: builtin/rebase.c
msgid "pass the argument through to the merge strategy"
msgstr "passa l'argument a l'estratègia de fusió"
+#: builtin/rebase.c
msgid "rebase all reachable commits up to the root(s)"
msgstr "fes «rebase» de totes les comissions accessibles fins a l'arrel"
+#: builtin/rebase.c
msgid "automatically re-schedule any `exec` that fails"
msgstr "torna a planificar automàticament qualsevol «exec» que falli"
+#: builtin/rebase.c
msgid "apply all changes, even those already present upstream"
msgstr "aplica tots els canvis, fins i tot els que ja estan a la font"
+#: builtin/rebase.c
msgid "It looks like 'git am' is in progress. Cannot rebase."
msgstr "Sembla que «git am» està en curs. No es pot fer «rebase»."
+#: builtin/rebase.c
msgid ""
"`rebase --preserve-merges` (-p) is no longer supported.\n"
"Use `git rebase --abort` to terminate current rebase.\n"
@@ -10331,6 +13237,7 @@ msgstr ""
"Utilitzeu «git rebase --abort» per a finalitzar el «rebase» actual.\n"
"O bé baixeu a la versió v2.33, o anterior, per a completar el «rebase»."
+#: builtin/rebase.c
msgid ""
"--preserve-merges was replaced by --rebase-merges\n"
"Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
@@ -10340,15 +13247,19 @@ msgstr ""
"Nota: la configuració «pull.rebase» també podria estar establerta a\n"
"+-«preserve», que ja no s'admet; utilitzeu «merge» en el seu lloc"
-msgid "No rebase in progress?"
-msgstr "No hi ha un «rebase» en curs?"
+#: builtin/rebase.c
+msgid "no rebase in progress"
+msgstr "no hi ha cap «rebase» en curs"
+#: builtin/rebase.c
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr "L'acció --edit-todo només es pot usar durant un «rebase» interactiu."
+#: builtin/rebase.c
msgid "Cannot read HEAD"
msgstr "No es pot llegir HEAD"
+#: builtin/rebase.c
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
@@ -10356,13 +13267,16 @@ msgstr ""
"Heu d'editar tots els conflictes de fusió i després\n"
"marcar-los com a resolts fent servir git add"
+#: builtin/rebase.c
msgid "could not discard worktree changes"
msgstr "no s'han pogut descartar els canvis de l'arbre de treball"
+#: builtin/rebase.c
#, c-format
msgid "could not move back to %s"
msgstr "no s'ha pogut tornar a %s"
+#: builtin/rebase.c
#, c-format
msgid ""
"It seems that there is already a %s directory, and\n"
@@ -10382,19 +13296,11 @@ msgstr ""
"i després executeu aquesta ordre de nou. S'atura l'operació en cas que\n"
"tingueu quelcom valuós.\n"
+#: builtin/rebase.c
msgid "switch `C' expects a numerical value"
msgstr "«switch» «c» espera un valor numèric"
-msgid "--strategy requires --merge or --interactive"
-msgstr "--strategy requereix --merge o --interactive"
-
-msgid ""
-"apply options are incompatible with rebase.autoSquash. Consider adding --no-"
-"autosquash"
-msgstr ""
-"les opcions «apply» són incompatibles amb rebase.autoSquash. Considereu "
-"afegir-hi --no-autosquash"
-
+#: builtin/rebase.c
msgid ""
"apply options are incompatible with rebase.rebaseMerges. Consider adding --"
"no-rebase-merges"
@@ -10402,6 +13308,7 @@ msgstr ""
"les opcions «apply» són incompatibles amb rebase.rebaseMerges. Considereu "
"afegir-hi --no-rebase-merges"
+#: builtin/rebase.c
msgid ""
"apply options are incompatible with rebase.updateRefs. Consider adding --no-"
"update-refs"
@@ -10409,84 +13316,106 @@ msgstr ""
"les opcions «apply» són incompatibles amb rebase.updateRefs. Considereu "
"afegir-hi --no-update-refs"
+#: builtin/rebase.c
#, c-format
msgid "Unknown rebase backend: %s"
msgstr "Rerefons de «rebase» desconegut: %s"
+#: builtin/rebase.c
msgid "--reschedule-failed-exec requires --exec or --interactive"
msgstr "--reschedule-failed-exec requereix --exec o --interactive"
+#: builtin/rebase.c
#, c-format
msgid "invalid upstream '%s'"
msgstr "font no vàlida: «%s»"
+#: builtin/rebase.c
msgid "Could not create new root commit"
msgstr "No s'ha pogut crear una comissió arrel nova"
+#: builtin/rebase.c
#, c-format
msgid "no such branch/commit '%s'"
msgstr "no existeix aquesta branca o comissió «%s»"
+#: builtin/rebase.c builtin/submodule--helper.c
#, c-format
msgid "No such ref: %s"
msgstr "No hi ha tal referència: %s"
+#: builtin/rebase.c
msgid "Could not resolve HEAD to a commit"
msgstr "No s'ha pogut resoldre HEAD com a una comissió"
+#: builtin/rebase.c
#, c-format
msgid "'%s': need exactly one merge base with branch"
msgstr "«%s»: necessita exactament una base de fusió amb branca"
+#: builtin/rebase.c
#, c-format
msgid "'%s': need exactly one merge base"
msgstr "«%s»: necessita exactament una base de fusió"
+#: builtin/rebase.c
#, c-format
msgid "Does not point to a valid commit '%s'"
msgstr "No apunta a una comissió vàlida «%s»"
+#: builtin/rebase.c
msgid "HEAD is up to date."
msgstr "HEAD està al dia."
+#: builtin/rebase.c
#, c-format
msgid "Current branch %s is up to date.\n"
msgstr "La branca actual %s està al dia.\n"
+#: builtin/rebase.c
msgid "HEAD is up to date, rebase forced."
msgstr "La branca actual està al dia, «rebase» forçat."
+#: builtin/rebase.c
#, c-format
msgid "Current branch %s is up to date, rebase forced.\n"
msgstr "La branca actual %s està al dia; «rebase» forçat.\n"
+#: builtin/rebase.c
msgid "The pre-rebase hook refused to rebase."
msgstr "El lligam pre-rebase ha refusat a fer «rebase»."
+#: builtin/rebase.c
#, c-format
msgid "Changes to %s:\n"
msgstr "Canvis a %s:\n"
+#: builtin/rebase.c
#, c-format
msgid "Changes from %s to %s:\n"
msgstr "Canvis de %s a %s:\n"
+#: builtin/rebase.c
#, c-format
msgid "First, rewinding head to replay your work on top of it...\n"
msgstr ""
"Primer, s'està rebobinant HEAD per a reproduir el vostre treball al "
"damunt...\n"
+#: builtin/rebase.c
msgid "Could not detach HEAD"
msgstr "No s'ha pogut separar HEAD"
+#: builtin/rebase.c
#, c-format
msgid "Fast-forwarded %s to %s.\n"
msgstr "Avanç ràpid %s a %s.\n"
+#: builtin/receive-pack.c
msgid "git receive-pack <git-dir>"
msgstr "git receive-pack <git-dir>"
+#: builtin/receive-pack.c
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"
@@ -10517,6 +13446,7 @@ msgstr ""
"per defecte, establiu la variable de configuració\n"
"«receive.denyCurrentBranch» a «refuse»."
+#: builtin/receive-pack.c
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"
@@ -10538,15 +13468,23 @@ msgstr ""
"\n"
"Per a silenciar aquest missatge, podeu establir-la a «refuse»."
+#: builtin/receive-pack.c
msgid "quiet"
msgstr "silenciós"
+#: builtin/receive-pack.c
msgid "you must specify a directory"
msgstr "heu d'especificar un directori"
+#: builtin/reflog.c
msgid "git reflog [show] [<log-options>] [<ref>]"
-msgstr "git reflog [show] [<log-options>] [<ref>]"
+msgstr "git reflog [show] [<opcions-registre>] [<referència>]"
+#: builtin/reflog.c
+msgid "git reflog list"
+msgstr "git reflog list"
+
+#: builtin/reflog.c
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10558,39 +13496,57 @@ msgstr ""
" [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
"<refs>...]"
+#: builtin/reflog.c
msgid ""
"git reflog delete [--rewrite] [--updateref]\n"
" [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
msgstr ""
"git reflog delete [--rewrite] [--updateref]\n"
-" [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
+" [--dry-run | -n] [--verbose] "
+"<referència>@{<especificador>}..."
+#: builtin/reflog.c
msgid "git reflog exists <ref>"
msgstr "git reflog exists <referència>"
+#: builtin/reflog.c
#, c-format
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "marca de temps «%s» donada a «--%s» no és vàlida"
+#: builtin/reflog.c sequencer.c
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s no accepta arguments: «%s»"
+
+#: builtin/reflog.c
msgid "do not actually prune any entries"
msgstr "no eliminis cap entrada"
+#: builtin/reflog.c
msgid ""
"rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"
msgstr "reescriu l'antic SHA1 amb el nou SHA1 de l'entrada que ara precedeix"
+#: builtin/reflog.c
msgid "update the reference to the value of the top reflog entry"
-msgstr "actualitza la referència al valor de l'entrada de reflog superior"
+msgstr ""
+"actualitza la referència al valor de l'entrada de registre de referència "
+"superior"
+#: builtin/reflog.c
msgid "print extra information on screen"
msgstr "imprimeix informació extra a la pantalla"
+#: builtin/reflog.c
msgid "timestamp"
msgstr "marca de temps"
+#: builtin/reflog.c
msgid "prune entries older than the specified time"
msgstr "poda les entrades més antigues que el temps especificat"
+#: builtin/reflog.c
msgid ""
"prune entries older than <time> that are not reachable from the current tip "
"of the branch"
@@ -10598,30 +13554,75 @@ msgstr ""
"poda les entrades més antigues de <data> que no es poden accedir des de la "
"punta actual de la branca"
+#: builtin/reflog.c
msgid "prune any reflog entries that point to broken commits"
-msgstr "poda qualsevol entrada de reflog que apunti a comissions trencades"
+msgstr ""
+"poda qualsevol entrada del registre de referències que apunti a comissions "
+"trencades"
+#: builtin/reflog.c
msgid "process the reflogs of all references"
-msgstr "processa els reflogs de totes les referències"
+msgstr "processa els registres de referències de totes les referències"
+#: builtin/reflog.c
msgid "limits processing to reflogs from the current worktree only"
-msgstr "limita el processament a reflogs només de l'arbre de treball actual"
+msgstr ""
+"limita el processament només a registres de referències de l'arbre de "
+"treball actual"
+#: builtin/reflog.c
#, c-format
msgid "Marking reachable objects..."
msgstr "S'estan marcant els objectes abastables..."
+#: builtin/reflog.c
#, c-format
msgid "%s points nowhere!"
msgstr "%s no apunta a enlloc"
+#: builtin/reflog.c
msgid "no reflog specified to delete"
-msgstr "no s'ha especificat cap registre de referència per a suprimir"
+msgstr "no s'ha especificat cap registre de referències per a suprimir"
+#: builtin/reflog.c
#, c-format
msgid "invalid ref format: %s"
msgstr "format de referència no vàlid: %s"
+#: builtin/refs.c
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+
+#: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+#: builtin/refs.c
+msgid "specify the reference format to convert to"
+msgstr "especifiqueu el format de referència al qual voleu convertir"
+
+#: builtin/refs.c
+msgid "perform a non-destructive dry-run"
+msgstr "fes una prova no destructiva"
+
+#: builtin/refs.c
+msgid "missing --ref-format=<format>"
+msgstr "falta --ref-format=<format>"
+
+#: builtin/refs.c
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "el repositori ja usa el format «%s»"
+
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "habilita la comprovació estricta"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' no accepta arguments"
+
+#: builtin/remote.c
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10629,67 +13630,87 @@ msgstr ""
"git remote add [-t <branca>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <nom> <url>"
+#: builtin/remote.c
msgid "git remote rename [--[no-]progress] <old> <new>"
-msgstr "git remote rename [--[no-]progress] <old> <new>"
+msgstr "git remote rename [--[no-]progress] <vell> <nou>"
+#: builtin/remote.c
msgid "git remote remove <name>"
msgstr "git remote remove <nom>"
+#: builtin/remote.c
msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"
msgstr "git remote set-head <nom> (-a | --auto | -d | --delete | <branca>)"
+#: builtin/remote.c
msgid "git remote [-v | --verbose] show [-n] <name>"
msgstr "git remote [-v | --verbose] show [-n] <nom>"
+#: builtin/remote.c
msgid "git remote prune [-n | --dry-run] <name>"
msgstr "git remote prune [-n | --dry-run] <nom>"
+#: builtin/remote.c
msgid ""
"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
msgstr ""
"git remote [-v | --verbose] update [-p | --prune] [(<grup> | <remot>)...]"
+#: builtin/remote.c
msgid "git remote set-branches [--add] <name> <branch>..."
msgstr "git remote set-branches [--add] <nom> <branca>..."
+#: builtin/remote.c
msgid "git remote get-url [--push] [--all] <name>"
msgstr "git remote get-url [--push] [--all] <nom>"
+#: builtin/remote.c
msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
-msgstr "git remote set-url [--push] <nom> <url-nou> [<url-antic>]"
+msgstr "<git remote set-url [--push] <nom> <url-nou> [<url-vell>]"
+#: builtin/remote.c
msgid "git remote set-url --add <name> <newurl>"
msgstr "git remote set-url --add <nom> <url-nou>"
+#: builtin/remote.c
msgid "git remote set-url --delete <name> <url>"
msgstr "git remote set-url --delete <nom> <url>"
+#: builtin/remote.c
msgid "git remote add [<options>] <name> <url>"
msgstr "git remote add [<opcions>] <nom> <url>"
+#: builtin/remote.c
msgid "git remote set-branches <name> <branch>..."
msgstr "git remote set-branches <nom> <branca>..."
+#: builtin/remote.c
msgid "git remote set-branches --add <name> <branch>..."
msgstr "git remote set-branches --add <nom> <branca>..."
+#: builtin/remote.c
msgid "git remote show [<options>] <name>"
msgstr "git remote show [<opcions>] <nom>"
+#: builtin/remote.c
msgid "git remote prune [<options>] <name>"
msgstr "git remote prune [<opcions>] <nom>"
+#: builtin/remote.c
msgid "git remote update [<options>] [<group> | <remote>]..."
msgstr "git remote update [<opcions>] [<grup> | <remot>]..."
+#: builtin/remote.c
#, c-format
msgid "Updating %s"
msgstr "S'està actualitzant %s"
+#: builtin/remote.c
#, c-format
msgid "Could not fetch %s"
msgstr "No s'ha pogut obtenir %s"
+#: builtin/remote.c
msgid ""
"--mirror is dangerous and deprecated; please\n"
"\t use --mirror=fetch or --mirror=push instead"
@@ -10698,13 +13719,16 @@ msgstr ""
"\t useu --mirror=fetch o\n"
"\t --mirror=push en lloc d'això"
+#: builtin/remote.c
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "argument de «mirror» desconegut: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "argument de «--mirror» desconegut: %s"
+#: builtin/remote.c
msgid "fetch the remote branches"
msgstr "obtén les branques remotes"
+#: builtin/remote.c
msgid ""
"import all tags and associated objects when fetching\n"
"or do not fetch any tag at all (--no-tags)"
@@ -10712,57 +13736,72 @@ msgstr ""
"importa totes les etiquetes i objectes associats en obtenir\n"
"o no obtingueu cap etiqueta (--no-tags)"
+#: builtin/remote.c
msgid "branch(es) to track"
msgstr "branques a seguir"
+#: builtin/remote.c
msgid "master branch"
msgstr "branca mestra"
+#: builtin/remote.c
msgid "set up remote as a mirror to push to or fetch from"
msgstr "estableix el remot com a mirall al qual pujar o del qual obtenir"
+#: builtin/remote.c
msgid "specifying a master branch makes no sense with --mirror"
msgstr "especificar una branca mestra no té sentit amb --mirror"
+#: builtin/remote.c
msgid "specifying branches to track makes sense only with fetch mirrors"
msgstr ""
"especificar les branques a seguir té sentit només amb miralls d'obtenció"
+#: builtin/remote.c
#, c-format
msgid "remote %s already exists."
msgstr "el remot %s ja existeix."
+#: builtin/remote.c
#, c-format
msgid "Could not setup master '%s'"
msgstr "No s'ha pogut configurar la mestra «%s»"
+#: builtin/remote.c trailer.c
#, c-format
msgid "more than one %s"
msgstr "més d'un %s"
+#: builtin/remote.c
#, c-format
msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
msgstr "no s'ha gestionat branch.%s.rebase=%s; assumint «true»"
+#: builtin/remote.c
#, c-format
msgid "Could not get fetch map for refspec %s"
msgstr ""
"No s'ha pogut obtenir el mapa d'obtenció de l'especificació de referència %s"
+#: builtin/remote.c
msgid "(matching)"
msgstr "(coincident)"
+#: builtin/remote.c
msgid "(delete)"
msgstr "(suprimir)"
+#: builtin/remote.c
#, c-format
msgid "could not set '%s'"
msgstr "no s'ha pogut establir «%s»"
+#: builtin/remote.c config.c
#, c-format
msgid "could not unset '%s'"
msgstr "no s'ha pogut desassignar «%s»"
+#: builtin/remote.c
#, c-format
msgid ""
"The %s configuration remote.pushDefault in:\n"
@@ -10773,14 +13812,17 @@ msgstr ""
"\t%s:%d\n"
"ara anomena un remot no existent «%s»"
+#: builtin/remote.c
#, c-format
msgid "No such remote: '%s'"
msgstr "No existeix el remot «%s»"
+#: builtin/remote.c
#, c-format
msgid "Could not rename config section '%s' to '%s'"
msgstr "No s'ha pogut canviar el nom de la secció de configuració «%s» a «%s»"
+#: builtin/remote.c
#, c-format
msgid ""
"Not updating non-default fetch refspec\n"
@@ -10792,17 +13834,21 @@ msgstr ""
"\t%s\n"
"\tActualitzeu la configuració manualment si és necessari."
+#: builtin/remote.c
msgid "Renaming remote references"
msgstr "S'està canviant el nom de les referències remotes"
+#: builtin/remote.c
#, c-format
msgid "deleting '%s' failed"
msgstr "la supressió de «%s» ha fallat"
+#: builtin/remote.c
#, c-format
msgid "creating '%s' failed"
msgstr "la creació de «%s» ha fallat"
+#: builtin/remote.c
msgid ""
"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
"to delete it, use:"
@@ -10817,246 +13863,307 @@ msgstr[1] ""
"eliminat;\n"
"per a suprimir-les, useu:"
+#: builtin/remote.c
#, c-format
msgid "Could not remove config section '%s'"
msgstr "No s'ha pogut eliminar la secció de configuració «%s»"
+#: builtin/remote.c
#, c-format
msgid " new (next fetch will store in remotes/%s)"
msgstr " nou (la pròxima obtenció emmagatzemarà a remotes/%s)"
+#: builtin/remote.c
msgid " tracked"
msgstr " seguit"
+#: builtin/remote.c
msgid " skipped"
msgstr " omès"
+#: builtin/remote.c
msgid " stale (use 'git remote prune' to remove)"
msgstr " estancat (useu «git remote prune» per a eliminar)"
+#: builtin/remote.c
msgid " ???"
msgstr " ???"
+#: builtin/remote.c
#, c-format
msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
msgstr "branch.%s.merge no vàlid; no es pot fer «rebase» sobre > 1 branca"
+#: builtin/remote.c
#, c-format
msgid "rebases interactively onto remote %s"
msgstr "es fa «rebase» interactivament sobre el remot %s"
+#: builtin/remote.c
#, c-format
msgid "rebases interactively (with merges) onto remote %s"
msgstr "es fa «rebase» interactivament (amb fusions) sobre el remot %s"
+#: builtin/remote.c
#, c-format
msgid "rebases onto remote %s"
msgstr "es fa «rebase» sobre el remot %s"
+#: builtin/remote.c
#, c-format
msgid " merges with remote %s"
msgstr " es fusiona amb el remot %s"
+#: builtin/remote.c
#, c-format
msgid "merges with remote %s"
msgstr "es fusiona amb el remot %s"
+#: builtin/remote.c
#, c-format
msgid "%-*s and with remote %s\n"
msgstr "%-*s i amb el remot %s\n"
+#: builtin/remote.c
msgid "create"
msgstr "crea"
+#: builtin/remote.c
msgid "delete"
msgstr "suprimeix"
+#: builtin/remote.c
msgid "up to date"
msgstr "al dia"
+#: builtin/remote.c
msgid "fast-forwardable"
msgstr "avanç ràpid possible"
+#: builtin/remote.c
msgid "local out of date"
msgstr "local no actualitzat"
+#: builtin/remote.c
#, c-format
msgid " %-*s forces to %-*s (%s)"
msgstr " %-*s força a %-*s (%s)"
+#: builtin/remote.c
#, c-format
msgid " %-*s pushes to %-*s (%s)"
msgstr " %-*s puja a %-*s (%s)"
+#: builtin/remote.c
#, c-format
msgid " %-*s forces to %s"
msgstr " %-*s força a %s"
+#: builtin/remote.c
#, c-format
msgid " %-*s pushes to %s"
msgstr " %-*s puja a %s"
+#: builtin/remote.c
msgid "do not query remotes"
msgstr "no consultis els remots"
+#: builtin/remote.c
#, c-format
msgid "* remote %s"
msgstr "* remot %s"
+#: builtin/remote.c
#, c-format
msgid " Fetch URL: %s"
msgstr " URL d'obtenció: %s"
-msgid "(no URL)"
-msgstr "(sense URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
#.
+#: builtin/remote.c
#, c-format
msgid " Push URL: %s"
msgstr " URL de pujada: %s"
+#: builtin/remote.c
+msgid "(no URL)"
+msgstr "(sense URL)"
+
+#: builtin/remote.c
#, c-format
msgid " HEAD branch: %s"
msgstr " Branca de HEAD: %s"
+#: builtin/remote.c
msgid "(not queried)"
msgstr "(no consultat)"
+#: builtin/remote.c
msgid "(unknown)"
msgstr "(desconegut)"
+#: builtin/remote.c
#, c-format
msgid ""
" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
msgstr ""
" Branca de HEAD (la HEAD remot és ambigua, pot ser un dels següents):\n"
+#: builtin/remote.c
#, c-format
msgid " Remote branch:%s"
msgid_plural " Remote branches:%s"
msgstr[0] " Branca remota:%s"
msgstr[1] " Branques remotes:%s"
+#: builtin/remote.c
msgid " (status not queried)"
msgstr " (estat no consultat)"
+#: builtin/remote.c
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
msgstr[0] " Branca local configurada per a «git pull»:"
msgstr[1] " Branques locals configurades per a «git pull»:"
+#: builtin/remote.c
msgid " Local refs will be mirrored by 'git push'"
msgstr " «git push» reflectirà les referències locals"
+#: builtin/remote.c
#, c-format
msgid " Local ref configured for 'git push'%s:"
msgid_plural " Local refs configured for 'git push'%s:"
msgstr[0] " Referència local configurada per a «git push»%s:"
msgstr[1] " Referències locals configurades per a «git push»%s:"
+#: builtin/remote.c
msgid "set refs/remotes/<name>/HEAD according to remote"
msgstr "estableix refs/remotes/<nom>/HEAD segons el remot"
+#: builtin/remote.c
msgid "delete refs/remotes/<name>/HEAD"
msgstr "suprimeix refs/remotes/<nom>/HEAD"
+#: builtin/remote.c
msgid "Cannot determine remote HEAD"
msgstr "No es pot determinar la HEAD remota"
+#: builtin/remote.c
msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
msgstr "Múltiples branques de HEAD remotes. Trieu-ne una explícitament amb:"
+#: builtin/remote.c
#, c-format
msgid "Could not delete %s"
msgstr "No s'ha pogut suprimir %s"
+#: builtin/remote.c
#, c-format
msgid "Not a valid ref: %s"
msgstr "No és una referència vàlida: %s"
+#: builtin/remote.c
#, c-format
msgid "Could not setup %s"
msgstr "No s'ha pogut configurar %s"
+#: builtin/remote.c
#, c-format
msgid " %s will become dangling!"
-msgstr " %s es tornarà penjant!"
+msgstr " %s es quedara despenjat!"
+#: builtin/remote.c
#, c-format
msgid " %s has become dangling!"
-msgstr " %s s'ha tornat penjant!"
+msgstr " %s s'ha quedat despenjat!"
+#: builtin/remote.c
#, c-format
msgid "Pruning %s"
msgstr "S'està podant %s"
+#: builtin/remote.c
#, c-format
msgid "URL: %s"
msgstr "URL: %s"
+#: builtin/remote.c
#, c-format
msgid " * [would prune] %s"
msgstr " * [podaria] %s"
+#: builtin/remote.c
#, c-format
msgid " * [pruned] %s"
msgstr " * [podat] %s"
+#: builtin/remote.c
msgid "prune remotes after fetching"
msgstr "poda els remots després d'obtenir-los"
+#: builtin/remote.c
#, c-format
msgid "No such remote '%s'"
msgstr "No hi ha tal remot «%s»"
+#: builtin/remote.c
msgid "add branch"
msgstr "afegeix branca"
+#: builtin/remote.c
msgid "no remote specified"
msgstr "cap remot especificat"
+#: builtin/remote.c
msgid "query push URLs rather than fetch URLs"
msgstr "consulta els URL de pujada en lloc dels URL d'obtenció"
+#: builtin/remote.c
msgid "return all URLs"
msgstr "retorna tots els URL"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "cap URL configurat per al remot «%s»"
-
+#: builtin/remote.c
msgid "manipulate push URLs"
msgstr "manipula els URL de pujada"
+#: builtin/remote.c
msgid "add URL"
msgstr "afegeix URL"
+#: builtin/remote.c
msgid "delete URLs"
msgstr "suprimeix els URL"
+#: builtin/remote.c
msgid "--add --delete doesn't make sense"
msgstr "--add --delete no té sentit"
+#: builtin/remote.c
#, c-format
msgid "Invalid old URL pattern: %s"
msgstr "Patró d'URL antic no vàlid: %s"
+#: builtin/remote.c
#, c-format
msgid "No such URL found: %s"
msgstr "No s'ha trobat tal URL: %s"
+#: builtin/remote.c
msgid "Will not delete all non-push URLs"
msgstr "No se suprimiran tots els URL no de pujada"
+#: builtin/remote.c
msgid "be verbose; must be placed before a subcommand"
msgstr "sigues detallat; s'ha de col·locar abans d'una subordre"
+#: builtin/repack.c
msgid "git repack [<options>]"
msgstr "git repack [<opcions>]"
+#: builtin/repack.c
msgid ""
"Incremental repacks are incompatible with bitmap indexes. Use\n"
"--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
@@ -11066,164 +14173,225 @@ msgstr ""
"--no-write-bitmap-index o inhabiliteu el paràmetre de configuració pack."
"writeBitmaps."
+#: builtin/repack.c
msgid "could not start pack-objects to repack promisor objects"
msgstr ""
"no s'ha pogut iniciar pack-objects per a tornar a empaquetar els objectes "
"«promisor»"
+#: builtin/repack.c
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "no s'ha pogut alimentar pack-objects amb objectes «promisor»"
+
+#: builtin/repack.c
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"repack: s'esperen només línies amb l'id d'objecte hexadecimal complet des de "
"pack-objects."
+#: builtin/repack.c
msgid "could not finish pack-objects to repack promisor objects"
msgstr ""
"no s'ha pogut finalitzar pack-objects per a tornar a empaquetar els objectes "
"«promisor»"
+#: builtin/repack.c
#, c-format
msgid "cannot open index for %s"
msgstr "no s'ha pogut obrir l'índex per a %s"
+#: builtin/repack.c
#, c-format
msgid "pack %s too large to consider in geometric progression"
msgstr ""
"el paquet %s és massa gran per a considerar-ho en progressió geomètrica"
+#: builtin/repack.c
#, c-format
msgid "pack %s too large to roll up"
msgstr "el paquet %s és massa gran per a enrotllar-lo"
+#: builtin/repack.c
#, c-format
msgid "could not open tempfile %s for writing"
msgstr "no s'ha pogut obrir el fitxer temporal «%s» per a escriptura"
+#: builtin/repack.c
msgid "could not close refs snapshot tempfile"
msgstr ""
"no s'ha pogut tancar el fitxer temporal amb la instantània de referències"
+#: builtin/repack.c
#, c-format
msgid "could not remove stale bitmap: %s"
msgstr "no s'ha pogut eliminar el mapa de bits estancat: %s"
+#: builtin/repack.c
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "el prefix de paquet %s no comença amb objdir %s"
+
+#: builtin/repack.c
msgid "pack everything in a single pack"
msgstr "empaqueta-ho tot en un únic paquet"
+#: builtin/repack.c
msgid "same as -a, and turn unreachable objects loose"
msgstr "el mateix que -a, i solta els objectes inabastables"
+#: builtin/repack.c
msgid "same as -a, pack unreachable cruft objects separately"
msgstr ""
"el mateix que -a, empaqueta els objectes superflus inabastables de forma "
"separada"
+#: builtin/repack.c
msgid "approxidate"
msgstr "data aproximada"
+#: builtin/repack.c
msgid "with --cruft, expire objects older than this"
msgstr "amb --cruft, vencen els objectes més antics que aquest"
+#: builtin/repack.c
msgid "remove redundant packs, and run git-prune-packed"
msgstr "elimina els paquets redundants, i executeu git-prune-packed"
+#: builtin/repack.c
msgid "pass --no-reuse-delta to git-pack-objects"
msgstr "passa --no-reuse-delta a git-pack-objects"
+#: builtin/repack.c
msgid "pass --no-reuse-object to git-pack-objects"
msgstr "passa --no-reuse-object a git-pack-objects"
+#: builtin/repack.c
msgid "do not run git-update-server-info"
msgstr "no executis git-update-server-info"
+#: builtin/repack.c
msgid "pass --local to git-pack-objects"
msgstr "passa --local a git-pack-objects"
+#: builtin/repack.c
msgid "write bitmap index"
msgstr "escriu índex de mapa de bits"
+#: builtin/repack.c
msgid "pass --delta-islands to git-pack-objects"
msgstr "passa --delta-islands a git-pack-objects"
+#: builtin/repack.c
msgid "with -A, do not loosen objects older than this"
msgstr "amb -A, no soltis els objectes més antics que aquest"
+#: builtin/repack.c
msgid "with -a, repack unreachable objects"
msgstr "amb -a, reempaqueta els objectes inabastables"
+#: builtin/repack.c
msgid "size of the window used for delta compression"
msgstr "mida de la finestra que s'usa per a compressió de diferències"
+#: builtin/repack.c
msgid "bytes"
msgstr "octets"
+#: builtin/repack.c
msgid "same as the above, but limit memory size instead of entries count"
msgstr ""
"el mateix que l'anterior, però limita la mida de memòria en lloc del nombre "
"d'entrades"
+#: builtin/repack.c
msgid "limits the maximum delta depth"
msgstr "limita la profunditat màxima de les diferències"
+#: builtin/repack.c
msgid "limits the maximum number of threads"
msgstr "limita el nombre màxim de fils"
+#: builtin/repack.c
msgid "maximum size of each packfile"
msgstr "mida màxima de cada fitxer de paquet"
+#: builtin/repack.c
msgid "repack objects in packs marked with .keep"
msgstr "reempaqueta els objectes en paquets marcats amb .keep"
+#: builtin/repack.c
msgid "do not repack this pack"
msgstr "no reempaquetis aquest paquet"
+#: builtin/repack.c
msgid "find a geometric progression with factor <N>"
msgstr "troba una progressió geomètrica amb el factor <N>"
+#: builtin/repack.c
msgid "write a multi-pack index of the resulting packs"
msgstr "escriu un índex multipaquet dels paquets resultants"
+#: builtin/repack.c
msgid "pack prefix to store a pack containing pruned objects"
msgstr ""
"prefix del paquet per a emmagatzemar un paquet que contingui objectes podats"
+#: builtin/repack.c
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr ""
+"prefix del paquet per a emmagatzemar un paquet que contingui objectes "
+"filtrats"
+
+#: builtin/repack.c
msgid "cannot delete packs in a precious-objects repo"
msgstr "no es poden suprimir paquets en un repositori d'objectes preciosos"
+#: builtin/repack.c
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "l'opció «%s» només es pot utilitzar juntament amb «%s»"
+
+#: builtin/repack.c
msgid "Nothing new to pack."
msgstr "Res nou a empaquetar."
-#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "el prefix de paquet %s no comença amb objdir %s"
-
+#: builtin/repack.c
#, c-format
msgid "renaming pack to '%s' failed"
msgstr "el canvi del nom a «%s» ha fallat"
+#: builtin/repack.c
#, c-format
msgid "pack-objects did not write a '%s' file for pack %s-%s"
msgstr ""
"els objectes de paquet no han escrit a un fitxer «%s» per al paquet %s-%s"
+#: builtin/repack.c sequencer.c
#, c-format
msgid "could not unlink: %s"
msgstr "no s'ha pogut desenllaçar: «%s»"
+#: builtin/replace.c
msgid "git replace [-f] <object> <replacement>"
msgstr "git replace [-f] <objecte> <reemplaçament>"
+#: builtin/replace.c
msgid "git replace [-f] --edit <object>"
msgstr "git replace [-f] --edit <objecte>"
+#: builtin/replace.c
msgid "git replace [-f] --graft <commit> [<parent>...]"
msgstr "git replace [-f] --graft <comissió> [<pare>...]"
+#: builtin/replace.c
msgid "git replace -d <object>..."
msgstr "git replace -d <objecte>..."
+#: builtin/replace.c
msgid "git replace [--format=<format>] [-l [<pattern>]]"
msgstr "git replace [--format=<format>] [-l [<patró>]]"
+#: builtin/replace.c
#, c-format
msgid ""
"invalid replace format '%s'\n"
@@ -11232,22 +14400,27 @@ msgstr ""
"format de reemplaçament no vàlid «%s»\n"
"els formats vàlids són «short» «medium» i «long»"
+#: builtin/replace.c
#, c-format
msgid "replace ref '%s' not found"
msgstr "no s'ha trobat la referència de reemplaçament '«%s»"
+#: builtin/replace.c
#, c-format
msgid "Deleted replace ref '%s'"
msgstr "S'ha suprimit la referència «%s»"
+#: builtin/replace.c
#, c-format
msgid "'%s' is not a valid ref name"
msgstr "«%s» no és un nom de referència vàlid"
+#: builtin/replace.c
#, c-format
msgid "replace ref '%s' already exists"
msgstr "la referència de reemplaçament «%s» ja existeix"
+#: builtin/replace.c
#, c-format
msgid ""
"Objects must be of the same type.\n"
@@ -11258,59 +14431,75 @@ msgstr ""
"«%s» apunta a un objecte substituït del tipus «%s»\n"
"mentre que «%s» apunta a un objecte de substitució del tipus «%s»."
+#: builtin/replace.c
#, c-format
msgid "unable to open %s for writing"
msgstr "no s'ha pogut obrir %s per a escriptura"
+#: builtin/replace.c
msgid "cat-file reported failure"
msgstr "cat-file ha informat d'un error"
+#: builtin/replace.c
#, c-format
msgid "unable to open %s for reading"
msgstr "no s'ha pogut obrir %s per a lectura"
+#: builtin/replace.c
msgid "unable to spawn mktree"
msgstr "no s'ha pogut engendrar el mktree"
+#: builtin/replace.c
msgid "unable to read from mktree"
msgstr "no s'ha pogut llegir des de mktree"
+#: builtin/replace.c
msgid "mktree reported failure"
msgstr "mktree ha informat d'una fallada"
+#: builtin/replace.c
msgid "mktree did not return an object name"
msgstr "mktree no ha retornat un nom d'objecte"
+#: builtin/replace.c
#, c-format
msgid "unable to fstat %s"
msgstr "no s'ha pogut fer fstat %s"
+#: builtin/replace.c
msgid "unable to write object to database"
msgstr "no s'ha pogut escriure l'objecte a la base de dades"
+#: builtin/replace.c
#, c-format
msgid "unable to get object type for %s"
msgstr "no s'ha pogut obtenir el tipus d'objecte per a %s"
+#: builtin/replace.c
msgid "editing object file failed"
msgstr "l'edició del fitxer d'objecte ha fallat"
+#: builtin/replace.c
#, c-format
msgid "new object is the same as the old one: '%s'"
msgstr "l'objecte nou és el mateix que l'antic: «%s»"
+#: builtin/replace.c
#, c-format
msgid "could not parse %s as a commit"
msgstr "no s'ha pogut analitzar %s com a comissió"
+#: builtin/replace.c
#, c-format
msgid "bad mergetag in commit '%s'"
msgstr "etiqueta de fusió incorrecta en la comissió «%s»"
+#: builtin/replace.c
#, c-format
msgid "malformed mergetag in commit '%s'"
msgstr "etiqueta de fusió mal formada en la comissió «%s»"
+#: builtin/replace.c
#, c-format
msgid ""
"original commit '%s' contains mergetag '%s' that is discarded; use --edit "
@@ -11319,25 +14508,31 @@ msgstr ""
"la comissió original «%s» conté l'etiqueta de fusió «%s» que es descarta; "
"useu --edit en lloc de --graft"
+#: builtin/replace.c
#, c-format
msgid "the original commit '%s' has a gpg signature"
msgstr "la comissió original «%s» té una signatura gpg"
+#: builtin/replace.c
msgid "the signature will be removed in the replacement commit!"
msgstr "s'eliminarà la signatura en la comissió de reemplaçament!"
+#: builtin/replace.c
#, c-format
msgid "could not write replacement commit for: '%s'"
msgstr "no s'ha pogut escriure la comissió de reemplaçament per a: «%s»"
+#: builtin/replace.c
#, c-format
msgid "graft for '%s' unnecessary"
msgstr "«graft» per a «%s» innecessari"
+#: builtin/replace.c
#, c-format
msgid "new commit is the same as the old one: '%s'"
msgstr "la comissió nova és la mateixa que l'antiga: «%s»"
+#: builtin/replace.c
#, c-format
msgid ""
"could not convert the following graft(s):\n"
@@ -11346,166 +14541,303 @@ msgstr ""
"no s'han pogut convertir els següents «grafts»:\n"
"%s"
+#: builtin/replace.c
msgid "list replace refs"
msgstr "llista les referències de reemplaçament"
+#: builtin/replace.c
msgid "delete replace refs"
msgstr "suprimeix les referències de reemplaçament"
+#: builtin/replace.c
msgid "edit existing object"
msgstr "edita un objecte existent"
+#: builtin/replace.c
msgid "change a commit's parents"
msgstr "canvia els pares d'una comissió"
+#: builtin/replace.c
msgid "convert existing graft file"
msgstr "converteix el fitxer «graft» existent"
+#: builtin/replace.c
msgid "replace the ref if it exists"
msgstr "reemplaça la referència si existeix"
+#: builtin/replace.c
msgid "do not pretty-print contents for --edit"
msgstr "no imprimeixis bellament els continguts per a --edit"
+#: builtin/replace.c
msgid "use this format"
msgstr "usa aquest format"
+#: builtin/replace.c
msgid "--format cannot be used when not listing"
msgstr "no es pot utilitzar «--format» quan no s'està llistant"
+#: builtin/replace.c
msgid "-f only makes sense when writing a replacement"
msgstr "-f només té sentit quan s'escriu un reemplaçament"
+#: builtin/replace.c
msgid "--raw only makes sense with --edit"
msgstr "--raw només té sentit amb --edit"
+#: builtin/replace.c
msgid "-d needs at least one argument"
msgstr "-d necessita almenys un argument"
+#: builtin/replace.c
msgid "bad number of arguments"
msgstr "nombre incorrecte d'arguments"
+#: builtin/replace.c
msgid "-e needs exactly one argument"
msgstr "-e necessita exactament un argument"
+#: builtin/replace.c
msgid "-g needs at least one argument"
msgstr "-g necessita almenys un argument"
+#: builtin/replace.c
msgid "--convert-graft-file takes no argument"
msgstr "--convert-graft-file arguments"
+#: builtin/replace.c
msgid "only one pattern can be given with -l"
msgstr "només es pot especificar un patró amb -l"
+#: builtin/replay.c
+msgid "need some commits to replay"
+msgstr "calen algunes comissions per tornar a reproduir"
+
+#: builtin/replay.c
+msgid "--onto and --advance are incompatible"
+msgstr "--onto i --advance són incompatibles"
+
+#: builtin/replay.c
+msgid "all positive revisions given must be references"
+msgstr "totes les revisions positives que s'han donat han de ser referències"
+
+#: builtin/replay.c
+msgid "argument to --advance must be a reference"
+msgstr "l'argument per a --advance ha de ser una referència"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"no es pot avançar l'objectiu amb múltiples fonts perquè l'ordenació no "
+"estaria definida correctament"
+
+#: builtin/replay.c
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"no es pot determinar implícitament si aquesta és una operació --advance o --"
+"onto"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"no es pot avançar l'objectiu amb múltiples branques d'origen perquè "
+"l'ordenació no estaria definida correctament"
+
+#: builtin/replay.c
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "no es pot determinar implícitament la base correcta per a --onto"
+
+#: builtin/replay.c
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+
+#: builtin/replay.c
+msgid "make replay advance given branch"
+msgstr "fes avançar la repetició de la branca donada"
+
+#: builtin/replay.c
+msgid "replay onto given commit"
+msgstr "torna a reproduir a la comissió donada"
+
+#: builtin/replay.c
+msgid "advance all branches contained in revision-range"
+msgstr "avança totes les branques contingudes a l'interval de revisions"
+
+#: builtin/replay.c
+msgid "option --onto or --advance is mandatory"
+msgstr "l'opció --onto o --advance és obligatòria"
+
+#: builtin/replay.c
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"algunes opcions de referència se sobreescriuran de forma forçada com a «%s» "
+"bits a «struct rev_info»"
+
+#: builtin/replay.c
+msgid "error preparing revisions"
+msgstr "s'ha produït un error en preparar les revisions"
+
+#: builtin/replay.c
+msgid "replaying down to root commit is not supported yet!"
+msgstr "encara no s'admet la reproducció cap avall en una comissió arrel"
+
+#: builtin/replay.c
+msgid "replaying merge commits is not supported yet!"
+msgstr "encara no s'admet la repetició de les comissions de fusió"
+
+#: builtin/rerere.c
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
msgstr ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
+#: builtin/rerere.c
msgid "register clean resolutions in index"
msgstr "registra les resolucions netes en l'índex"
+#: builtin/rerere.c
msgid "'git rerere forget' without paths is deprecated"
msgstr "«git rerere forget» sense camins està en desús"
+#: builtin/rerere.c
#, c-format
msgid "unable to generate diff for '%s'"
msgstr "no s'ha pogut generar el diff per a «%s»"
+#: builtin/reset.c
msgid ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
msgstr ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<comissió>]"
+#: builtin/reset.c
msgid "git reset [-q] [<tree-ish>] [--] <pathspec>..."
msgstr "git reset [-q] [<tree-ish>] [--] <pathspec>..."
+#: builtin/reset.c
msgid ""
"git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
msgstr ""
"git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
+#: builtin/reset.c
msgid "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
msgstr "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
+#: builtin/reset.c
msgid "mixed"
msgstr "mixt"
+#: builtin/reset.c
msgid "soft"
msgstr "suau"
+#: builtin/reset.c
msgid "hard"
msgstr "dur"
+#: builtin/reset.c
msgid "merge"
msgstr "fusió"
+#: builtin/reset.c
msgid "keep"
msgstr "reteniment"
+#: builtin/reset.c
msgid "You do not have a valid HEAD."
msgstr "No teniu una HEAD vàlida."
+#: builtin/reset.c
msgid "Failed to find tree of HEAD."
msgstr "S'ha produït un error en trobar l'arbre de HEAD."
+#: builtin/reset.c
#, c-format
msgid "Failed to find tree of %s."
msgstr "S'ha produït un error en cercar l'arbre de %s."
+#: builtin/reset.c
#, c-format
msgid "HEAD is now at %s"
msgstr "HEAD ara és a %s"
+#: builtin/reset.c
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
msgstr "No es pot fer un restabliment de %s enmig d'una fusió."
+#: builtin/reset.c builtin/stash.c
msgid "be quiet, only report errors"
msgstr "sigues silenciós, només informa d'errors"
+#: builtin/reset.c
msgid "skip refreshing the index after reset"
msgstr "omet l'actualització de l'índex després de reiniciar"
+#: builtin/reset.c
msgid "reset HEAD and index"
msgstr "restableix HEAD i l'índex"
+#: builtin/reset.c
msgid "reset only HEAD"
msgstr "restableix només HEAD"
+#: builtin/reset.c
msgid "reset HEAD, index and working tree"
msgstr "restableix HEAD, l'índex i l'arbre de treball"
+#: builtin/reset.c
msgid "reset HEAD but keep local changes"
msgstr "restableix HEAD però retén els canvis locals"
+#: builtin/reset.c
msgid "record only the fact that removed paths will be added later"
msgstr "registra només el fet que els camins eliminats s'afegiran després"
+#: builtin/reset.c
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
msgstr "S'ha produït un error en resoldre «%s» com a revisió vàlida."
+#: builtin/reset.c
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
msgstr "S'ha produït un error en resoldre «%s» com a arbre vàlid."
+#: builtin/reset.c
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
"--mixed amb camins està en desús; useu «git reset -- <camins>» en lloc "
"d'això."
+#: builtin/reset.c
#, c-format
msgid "Cannot do %s reset with paths."
msgstr "No es pot restablir de %s amb camins."
+#: builtin/reset.c
#, c-format
msgid "%s reset is not allowed in a bare repository"
msgstr "el restabliment de %s no es permet en un repositori nu"
+#: builtin/reset.c
msgid "Unstaged changes after reset:"
msgstr "Canvis «unstaged» després del restabliment:"
+#: builtin/reset.c
#, c-format
msgid ""
"It took %.2f seconds to refresh the index after reset. You can use\n"
@@ -11515,52 +14847,67 @@ msgstr ""
"usar\n"
".--no-refresh' per a evitar això."
+#: builtin/reset.c
#, c-format
msgid "Could not reset index file to revision '%s'."
msgstr "No s'ha pogut restablir el fitxer d'índex a la revisió «%s»."
+#: builtin/reset.c
msgid "Could not write new index file."
msgstr "No s'ha pogut escriure el fitxer d'índex nou."
+#: builtin/rev-list.c
#, c-format
msgid "unable to get disk usage of %s"
msgstr "no s'ha pogut obtenir l'ús del disc de %s"
+#: builtin/rev-list.c
#, c-format
msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
msgstr "valor no vàlid per a «%s»: «%s», l'únic format permès és «%s»"
+#: builtin/rev-list.c
msgid "rev-list does not support display of notes"
msgstr "el rev-list no permet mostrar notes"
+#: builtin/rev-list.c
#, c-format
msgid "marked counting and '%s' cannot be used together"
msgstr "«marked counting» i «%s» no es poden usar junts"
+#: builtin/rev-parse.c
msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
msgstr "git rev-parse --parseopt [<opcions>] -- [<arguments>...]"
+#: builtin/rev-parse.c
msgid "keep the `--` passed as an arg"
msgstr "retén el «--» passat com a argument"
+#: builtin/rev-parse.c
msgid "stop parsing after the first non-option argument"
msgstr "deixa d'analitzar després del primer argument que no sigui d'opció"
+#: builtin/rev-parse.c
msgid "output in stuck long form"
msgstr "emet en forma llarga enganxada"
+#: builtin/rev-parse.c
msgid "premature end of input"
msgstr "final prematur de l'entrada"
+#: builtin/rev-parse.c
msgid "no usage string given before the `--' separator"
msgstr "no s'ha indicat cap cadena d'ús abans del separador «--»"
+#: builtin/rev-parse.c
msgid "missing opt-spec before option flags"
msgstr "manca l'opció opt-spec abans de les altres opcions"
+#: builtin/rev-parse.c
msgid "Needed a single revision"
msgstr "Cal una sola revisió"
+#: builtin/rev-parse.c
msgid ""
"git rev-parse --parseopt [<options>] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
@@ -11575,52 +14922,68 @@ msgstr ""
"Executeu «git rev-parse --parseopt -h» per a més informació sobre el primer "
"ús."
+#: builtin/rev-parse.c
msgid "--resolve-git-dir requires an argument"
msgstr "--resolve-git-dir requereix un argument"
+#: builtin/rev-parse.c
#, c-format
msgid "not a gitdir '%s'"
msgstr "no és un directori git «%s»"
+#: builtin/rev-parse.c
msgid "--git-path requires an argument"
msgstr "--git-path requereix un argument"
+#: builtin/rev-parse.c
msgid "-n requires an argument"
msgstr "-n requereix un argument"
+#: builtin/rev-parse.c
msgid "--path-format requires an argument"
msgstr "--path-format requereix un argument"
+#: builtin/rev-parse.c
#, c-format
msgid "unknown argument to --path-format: %s"
msgstr "argument no vàlid per a --path-format: %s"
+#: builtin/rev-parse.c
msgid "--default requires an argument"
msgstr "--default requereix un argument"
+#: builtin/rev-parse.c
msgid "--prefix requires an argument"
msgstr "--prefix requereix un argument"
+#: builtin/rev-parse.c
+msgid "no object format specified"
+msgstr "no s'ha especificat cap format d'objecte"
+
+#: builtin/rev-parse.c
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "format d'objecte no compatible: %s"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "mode desconegut per a --abbrev-ref: %s"
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden no es pot utilitzar juntament amb --branches"
-
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden no es pot utilitzar juntament amb --tags"
-
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden no es pot utilitzar juntament amb --remotes"
-
+#: builtin/rev-parse.c setup.c
msgid "this operation must be run in a work tree"
msgstr "aquesta operació s'ha d'executar en un arbre de treball"
+#: builtin/rev-parse.c
+msgid "Could not read the index"
+msgstr "No s'ha pogut llegir l'índex"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "mode desconegut per a --show-object-format: %s"
+#: builtin/revert.c
msgid ""
"git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
"<commit>..."
@@ -11628,9 +14991,11 @@ msgstr ""
"git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
"<comissió>..."
+#: builtin/revert.c
msgid "git revert (--continue | --skip | --abort | --quit)"
msgstr "git revert (--continue | --skip | --abort | --quit)"
+#: builtin/revert.c
msgid ""
"git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
" [-S[<keyid>]] <commit>..."
@@ -11638,68 +15003,89 @@ msgstr ""
"git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
" [-S[<keyid>]] <comissió>..."
+#: builtin/revert.c
msgid "git cherry-pick (--continue | --skip | --abort | --quit)"
msgstr "git cherry-pick (--continue | --skip | --abort | --quit)"
+#: builtin/revert.c
#, c-format
msgid "option `%s' expects a number greater than zero"
msgstr "l'opció «%s» espera un nombre major que zero"
+#: builtin/revert.c
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s: %s no es pot usar amb %s"
+#: builtin/revert.c
msgid "end revert or cherry-pick sequence"
msgstr "acaba la seqüència de reversió o el «cherry pick»"
+#: builtin/revert.c
msgid "resume revert or cherry-pick sequence"
msgstr "reprèn la seqüència de reversió o el «cherry pick»"
+#: builtin/revert.c
msgid "cancel revert or cherry-pick sequence"
msgstr "cancel·la la seqüència de reversió o el «cherry pick»"
+#: builtin/revert.c
msgid "skip current commit and continue"
msgstr "omet la comissió actual i continua"
+#: builtin/revert.c
msgid "don't automatically commit"
msgstr "no cometis automàticament"
+#: builtin/revert.c
msgid "edit the commit message"
msgstr "edita el missatge de comissió"
+#: builtin/revert.c
msgid "parent-number"
msgstr "número del pare"
+#: builtin/revert.c
msgid "select mainline parent"
msgstr "selecciona la línia principal del pare"
+#: builtin/revert.c
msgid "merge strategy"
msgstr "estratègia de fusió"
+#: builtin/revert.c
msgid "option for merge strategy"
msgstr "opció d'estratègia de fusió"
+#: builtin/revert.c
msgid "append commit name"
msgstr "nom de la comissió a annexar"
+#: builtin/revert.c
msgid "preserve initially empty commits"
msgstr "conserva les comissions inicialment buides"
+#: builtin/revert.c
msgid "allow commits with empty messages"
msgstr "permet les comissions amb missatges buits"
-msgid "keep redundant, empty commits"
-msgstr "retén les comissions redundants i buides"
+#: builtin/revert.c
+msgid "deprecated: use --empty=keep instead"
+msgstr "obsolet: utilitzeu --empty=keep en el seu lloc"
+#: builtin/revert.c
msgid "use the 'reference' format to refer to commits"
msgstr "useu el format «referència» per a referir-vos a les comissions"
+#: builtin/revert.c
msgid "revert failed"
msgstr "la reversió ha fallat"
+#: builtin/revert.c
msgid "cherry-pick failed"
msgstr "el «cherry pick» ha fallat"
+#: builtin/rm.c
msgid ""
"git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
" [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
@@ -11709,6 +15095,7 @@ msgstr ""
" [--quiet] [--pathspec-from-file=<fitxer> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]"
+#: builtin/rm.c
msgid ""
"the following file has staged content different from both the\n"
"file and the HEAD:"
@@ -11716,12 +15103,13 @@ msgid_plural ""
"the following files have staged content different from both the\n"
"file and the HEAD:"
msgstr[0] ""
-"el fitxer següent té contingut «staged» diferent al fitxer\n"
-"i a HEAD:"
+"el fitxer següent té contingut «staged» diferent del fitxer\n"
+"i de HEAD:"
msgstr[1] ""
"els fitxers següents tenen contingut «staged» diferent al fitxer\n"
"i a HEAD:"
+#: builtin/rm.c
msgid ""
"\n"
"(use -f to force removal)"
@@ -11729,11 +15117,13 @@ msgstr ""
"\n"
"(useu -f per a forçar l'eliminació)"
+#: builtin/rm.c
msgid "the following file has changes staged in the index:"
msgid_plural "the following files have changes staged in the index:"
msgstr[0] "el fitxer següent té canvis «staged» en l'índex:"
msgstr[1] "els fitxers següents tenen canvis «staged» en l'índex:"
+#: builtin/rm.c
msgid ""
"\n"
"(use --cached to keep the file, or -f to force removal)"
@@ -11741,42 +15131,53 @@ msgstr ""
"\n"
"(useu --cached per a mantenir el fitxer, o -f per a forçar l'eliminació)"
+#: builtin/rm.c
msgid "the following file has local modifications:"
msgid_plural "the following files have local modifications:"
msgstr[0] "el fitxer següent té modificacions locals:"
msgstr[1] "els fitxers següents tenen modificacions locals:"
+#: builtin/rm.c
msgid "do not list removed files"
msgstr "no llistis els fitxers eliminats"
+#: builtin/rm.c
msgid "only remove from the index"
msgstr "només elimina de l'índex"
+#: builtin/rm.c
msgid "override the up-to-date check"
msgstr "passa per alt la comprovació d'actualitat"
+#: builtin/rm.c
msgid "allow recursive removal"
msgstr "permet l'eliminació recursiva"
+#: builtin/rm.c
msgid "exit with a zero status even if nothing matched"
msgstr "surt amb estat zero encara que res hagi coincidit"
+#: builtin/rm.c
msgid "No pathspec was given. Which files should I remove?"
msgstr ""
"No s'ha indicat cap especificació de camí. Quins fitxers s'han de suprimir?"
+#: builtin/rm.c
msgid "please stage your changes to .gitmodules or stash them to proceed"
msgstr ""
"feu un «stage» dels canvis a .gitmodules o feu un «stash» per a continuar"
+#: builtin/rm.c
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr "no s'eliminarà «%s» recursivament sense -r"
+#: builtin/rm.c
#, c-format
msgid "git rm: unable to remove %s"
msgstr "git rm: no s'ha pogut eliminar %s"
+#: builtin/send-pack.c
msgid ""
"git send-pack [--mirror] [--dry-run] [--force]\n"
" [--receive-pack=<git-receive-pack>]\n"
@@ -11788,69 +15189,89 @@ msgstr ""
" [--receive-pack=<git-receive-pack>]\n"
" [--verbose] [--thin] [--atomic]\n"
" [--[no-]signed | --signed=(true|false|if-asked)]\n"
-" [<host>:]<directory> (--all | <ref>...)"
+" [<host>:]<directori> (--all | <referència>...)"
+#: builtin/send-pack.c
msgid "remote name"
msgstr "nom del remot"
+#: builtin/send-pack.c
msgid "push all refs"
msgstr "puja totes les referències"
+#: builtin/send-pack.c
msgid "use stateless RPC protocol"
msgstr "usa el protocol RPC sense estat"
+#: builtin/send-pack.c
msgid "read refs from stdin"
msgstr "llegeix les referències des de stdin"
+#: builtin/send-pack.c
msgid "print status from remote helper"
msgstr "imprimeix l'estat des de l'ajudant remot"
+#: builtin/shortlog.c
msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
msgstr "git shortlog [<opcions>] [<rang-de-revisions>] [[--] <camí>...]"
+#: builtin/shortlog.c
msgid "git log --pretty=short | git shortlog [<options>]"
msgstr "git log --pretty=short | git shortlog [<opcions>]"
+#: builtin/shortlog.c
msgid "using multiple --group options with stdin is not supported"
msgstr "no s'admet l'ús de múltiples opcions --group amb stdin"
+#: builtin/shortlog.c
#, c-format
msgid "using %s with stdin is not supported"
msgstr "no s'admet l'ús de %s amb stdin"
+#: builtin/shortlog.c
#, c-format
msgid "unknown group type: %s"
msgstr "tipus de grup desconegut: %s"
+#: builtin/shortlog.c
msgid "group by committer rather than author"
msgstr "agrupa per «committer» en comptes de per autor"
+#: builtin/shortlog.c
msgid "sort output according to the number of commits per author"
msgstr "ordena la sortida segons el nombre de comissions per autor"
+#: builtin/shortlog.c
msgid "suppress commit descriptions, only provides commit count"
msgstr ""
"omet les descripcions de les comissions, només proveeix el recompte de "
"comissions"
+#: builtin/shortlog.c
msgid "show the email address of each author"
msgstr "mostra l'adreça electrònica de cada autor"
+#: builtin/shortlog.c
msgid "<w>[,<i1>[,<i2>]]"
msgstr "<w>[,<i1>[,<i2>]]"
+#: builtin/shortlog.c
msgid "linewrap output"
msgstr "ajusta les línies de la sortida"
+#: builtin/shortlog.c
msgid "field"
msgstr "camp"
+#: builtin/shortlog.c
msgid "group by field"
msgstr "agrupa per camp"
+#: builtin/shortlog.c
msgid "too many arguments given outside repository"
msgstr "hi ha massa arguments donats fora del repositori"
+#: builtin/show-branch.c
msgid ""
"git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
" [--current] [--color[=<when>] | --no-color] [--sparse]\n"
@@ -11862,143 +15283,208 @@ msgstr ""
" [--current] [--color[=<when>] | --no-color] [--sparse]\n"
" [--more=<n> | --list | --independent | --merge-base]\n"
" [--no-name | --sha1-name] [--topics]\n"
-" [(<rev> | <glob>)...]"
+" [(<revisió> | <glob>)...]"
+#: builtin/show-branch.c
msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<referència>]"
+#: builtin/show-branch.c
#, c-format
msgid "ignoring %s; cannot handle more than %d ref"
msgid_plural "ignoring %s; cannot handle more than %d refs"
msgstr[0] "s'està ignorant %s; no es pot gestionar més de %d referència"
msgstr[1] "s'està ignorant %s; no es poden gestionar més de %d referències"
+#: builtin/show-branch.c
#, c-format
msgid "no matching refs with %s"
msgstr "no hi ha referències coincidents amb %s"
+#: builtin/show-branch.c
msgid "show remote-tracking and local branches"
msgstr "mostra les branques amb seguiment remot i les locals"
+#: builtin/show-branch.c
msgid "show remote-tracking branches"
msgstr "mostra les branques amb seguiment remot"
+#: builtin/show-branch.c
msgid "color '*!+-' corresponding to the branch"
msgstr "colora «*!+-» corresponent a la branca"
+#: builtin/show-branch.c
msgid "show <n> more commits after the common ancestor"
msgstr "mostra <n> comissions després de l'avantpassat comú"
+#: builtin/show-branch.c
msgid "synonym to more=-1"
msgstr "sinònim de more=-1"
+#: builtin/show-branch.c
msgid "suppress naming strings"
msgstr "omet anomenar cadenes"
+#: builtin/show-branch.c
msgid "include the current branch"
msgstr "inclou la branca actual"
+#: builtin/show-branch.c
msgid "name commits with their object names"
msgstr "anomena les comissions amb els seus noms d'objecte"
+#: builtin/show-branch.c
msgid "show possible merge bases"
msgstr "mostra les bases de fusió possibles"
+#: builtin/show-branch.c
msgid "show refs unreachable from any other ref"
msgstr "mostra les referències inabastables de qualsevol altra referència"
+#: builtin/show-branch.c
msgid "show commits in topological order"
msgstr "mostra les comissions en ordre topològic"
+#: builtin/show-branch.c
msgid "show only commits not on the first branch"
msgstr "mostra només les comissions que no siguin en la primera branca"
+#: builtin/show-branch.c
msgid "show merges reachable from only one tip"
msgstr "mostra les fusions abastables de només una punta"
+#: builtin/show-branch.c
msgid "topologically sort, maintaining date order where possible"
msgstr "ordena topològicament, mantenint l'ordre de dates on sigui possible"
+#: builtin/show-branch.c
msgid "<n>[,<base>]"
msgstr "<n>[,<base>]"
+#: builtin/show-branch.c
msgid "show <n> most recent ref-log entries starting at base"
msgstr "mostra les <n> entrades més recents començant a la base"
+#: builtin/show-branch.c
msgid "no branches given, and HEAD is not valid"
msgstr "no s'ha donat cap branca, i HEAD no és vàlid"
+#: builtin/show-branch.c
msgid "--reflog option needs one branch name"
msgstr "l'opció --reflog necessita un nom de branca"
+#: builtin/show-branch.c
#, 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] "es pot mostrar només %d entrada a la vegada."
msgstr[1] "es poden mostrar només %d entrades a la vegada."
+#: builtin/show-branch.c
#, c-format
msgid "no such ref %s"
msgstr "no hi ha tal referència %s"
+#: builtin/show-branch.c
#, c-format
msgid "cannot handle more than %d rev."
msgid_plural "cannot handle more than %d revs."
msgstr[0] "no es pot gestionar més d'%d revisió."
msgstr[1] "no es poden gestionar més de %d revisions."
+#: builtin/show-branch.c
#, c-format
msgid "'%s' is not a valid ref."
msgstr "«%s» no és una referència vàlida."
+#: builtin/show-branch.c
#, c-format
msgid "cannot find commit %s (%s)"
msgstr "no es pot trobar la comissió %s (%s)"
+#: builtin/show-index.c
msgid "hash-algorithm"
msgstr "algorisme de resum"
+#: builtin/show-index.c
msgid "Unknown hash algorithm"
msgstr "Algorisme de resum desconegut"
+#: builtin/show-ref.c
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<patró>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<patró>...]"
+#: builtin/show-ref.c
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
+msgstr ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<referència>...]"
+
+#: builtin/show-ref.c
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<patró>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "mostra només les etiquetes (es pot combinar amb heads)"
+#: builtin/show-ref.c
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <referència>"
+
+#: builtin/show-ref.c
+msgid "reference does not exist"
+msgstr "la referència no existeix"
+
+#: builtin/show-ref.c
+msgid "failed to look up reference"
+msgstr "s'ha produït en cercar la referència"
+
+#: builtin/show-ref.c
+msgid "only show tags (can be combined with --branches)"
+msgstr "mostra només les etiquetes (es pot combinar amb --branches)"
-msgid "only show heads (can be combined with tags)"
-msgstr "mostra només els caps (es pot combinar amb tags)"
+#: builtin/show-ref.c
+msgid "only show branches (can be combined with --tags)"
+msgstr "mostra només les branques (es pot combinar amb --tags)"
+#: builtin/show-ref.c
+msgid "check for reference existence without resolving"
+msgstr "comprova l'existència de referència sense resoldre"
+
+#: builtin/show-ref.c
msgid "stricter reference checking, requires exact ref path"
msgstr ""
"comprovació de referència més estricta, requereix el camí de referència "
"exacte"
+#: builtin/show-ref.c
msgid "show the HEAD reference, even if it would be filtered out"
msgstr "mostra la referència HEAD, encara que es filtrés"
+#: builtin/show-ref.c
msgid "dereference tags into object IDs"
msgstr "desreferencia les etiquetes a ID d'objecte"
+#: builtin/show-ref.c
msgid "only show SHA1 hash using <n> digits"
msgstr "mostra el resum SHA1 usant només <n> xifres"
+#: builtin/show-ref.c
msgid "do not print results to stdout (useful with --verify)"
msgstr "no imprimeixis els resultats a stdout (útil amb --verify)"
+#: builtin/show-ref.c
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"
+#: builtin/sparse-checkout.c
msgid ""
"git sparse-checkout (init | list | set | add | reapply | disable | check-"
"rules) [<options>]"
@@ -12006,14 +15492,17 @@ msgstr ""
"git sparse-checkout (init | list | set | add | reapply | disable | check-"
"rules) [<opcions>]"
+#: builtin/sparse-checkout.c
msgid "this worktree is not sparse"
msgstr "aquest arbre de treball no és dispers"
+#: builtin/sparse-checkout.c
msgid "this worktree is not sparse (sparse-checkout file may not exist)"
msgstr ""
"aquest arbre de treball no és dispers (pot ser que el fitxer sparse-checkout "
"no existeixi)"
+#: builtin/sparse-checkout.c
#, c-format
msgid ""
"directory '%s' contains untracked files, but is not in the sparse-checkout "
@@ -12022,53 +15511,73 @@ msgstr ""
"el directori «%s» conté fitxers no seguits, però no està en el con de sparse-"
"checkout"
+#: builtin/sparse-checkout.c
#, c-format
msgid "failed to remove directory '%s'"
msgstr "s'ha produït un error en suprimir el directori «%s»"
+#: builtin/sparse-checkout.c
msgid "failed to create directory for sparse-checkout file"
msgstr "no s'ha pogut crear el directori per al fitxer sparse-checkout"
+#: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "no he pogut fer fdopen de «%s»"
+
+#: builtin/sparse-checkout.c
msgid "failed to initialize worktree config"
msgstr "no s'ha pogut inicialitzar la configuració de l'arbre de treball"
+#: builtin/sparse-checkout.c
msgid "failed to modify sparse-index config"
msgstr "no s'ha pogut modificar la configuració de l'índex dispers"
+#: builtin/sparse-checkout.c
msgid "initialize the sparse-checkout in cone mode"
msgstr "inicialitza el «sparse-checkout» en mode con"
+#: builtin/sparse-checkout.c
msgid "toggle the use of a sparse index"
msgstr "commuta l'ús d'un índex dispers"
+#: builtin/sparse-checkout.c commit-graph.c midx-write.c sequencer.c
#, c-format
msgid "unable to create leading directories of %s"
msgstr "no s'han pogut crear els directoris inicials de «%s»"
+#: builtin/sparse-checkout.c
#, c-format
msgid "failed to open '%s'"
msgstr "s'ha produït un error en obrir «%s»"
+#: builtin/sparse-checkout.c
#, c-format
msgid "could not normalize path %s"
msgstr "no s'ha pogut normalitzar el camí %s"
+#: builtin/sparse-checkout.c
#, c-format
msgid "unable to unquote C-style string '%s'"
msgstr "no s'han pogut treure les cometes a la cadena amb estil C «%s»"
+#: builtin/sparse-checkout.c
msgid "unable to load existing sparse-checkout patterns"
msgstr "no s'han pogut carregar els patrons de «sparse-checkout» existents"
+#: builtin/sparse-checkout.c
msgid "existing sparse-checkout patterns do not use cone mode"
msgstr "els patrons de «sparse-checkout» existents no usen el mode con"
+#: builtin/sparse-checkout.c
msgid "please run from the toplevel directory in non-cone mode"
msgstr "executeu des del directori de nivell superior en mode que no sigui con"
+#: builtin/sparse-checkout.c
msgid "specify directories rather than patterns (no leading slash)"
msgstr "especifica els directoris en lloc dels patrons (sense barra inclinada)"
+#: builtin/sparse-checkout.c
msgid ""
"specify directories rather than patterns. If your directory starts with a "
"'!', pass --skip-checks"
@@ -12076,6 +15585,7 @@ msgstr ""
"especifica els directoris en lloc dels patrons. Si el vostre directori "
"comença amb un «!», passeu --skip-checks"
+#: builtin/sparse-checkout.c
msgid ""
"specify directories rather than patterns. If your directory really has any "
"of '*?[]\\' in it, pass --skip-checks"
@@ -12083,6 +15593,7 @@ msgstr ""
"especifica els directoris en lloc dels patrons. Si el vostre directori "
"realment té alguna de «*?[]\\», useu --skip-checks"
+#: builtin/sparse-checkout.c
#, c-format
msgid ""
"'%s' is not a directory; to treat it as a directory anyway, rerun with --"
@@ -12091,6 +15602,7 @@ msgstr ""
"«%s» no és un directori; per a tractar-lo com un directori, torneu a "
"executar amb --skip-checks"
+#: builtin/sparse-checkout.c
#, c-format
msgid ""
"pass a leading slash before paths such as '%s' if you want a single file "
@@ -12099,35 +15611,43 @@ msgstr ""
"passa una barra d'inici abans dels camins com ara «%s» si voleu un sol "
"fitxer (vegeu «NON-CONE PROBLEMS» al manual de git-sparse-checkout)."
+#: builtin/sparse-checkout.c
msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
-msgstr "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
+msgstr "git sparse-checkout add [--skip-checks] (--stdin | <patrons>)"
+#: builtin/sparse-checkout.c
msgid ""
"skip some sanity checks on the given paths that might give false positives"
msgstr ""
"omet alguns controls de sanitat en els camins donats que podrien donar "
"falsos positius"
+#: builtin/sparse-checkout.c
msgid "read patterns from standard in"
msgstr "llegeix els patrons de l'entrada estàndard"
+#: builtin/sparse-checkout.c
msgid "no sparse-checkout to add to"
msgstr "no hi ha un sparse-checkout a afegir"
+#: builtin/sparse-checkout.c
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 | <patterns>)"
+"(--stdin | <patrons>)"
+#: builtin/sparse-checkout.c
msgid "must be in a sparse-checkout to reapply sparsity patterns"
msgstr ""
"ha d'estar en un sparse-checkout per a tornar a aplicar patrons de dispersió"
+#: builtin/sparse-checkout.c
msgid "error while refreshing working directory"
msgstr "s'ha produït un error en actualitzar el directori de treball"
+#: builtin/sparse-checkout.c
msgid ""
"git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
"file <file>]"
@@ -12135,20 +15655,25 @@ msgstr ""
"git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
"file <fitxer>]"
+#: builtin/sparse-checkout.c
msgid "terminate input and output files by a NUL character"
msgstr "acaba els fitxers d'entrada i de sortida amb un caràcter NUL"
+#: builtin/sparse-checkout.c
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"
+#: builtin/sparse-checkout.c
msgid "use patterns in <file> instead of the current ones."
msgstr "utilitza patrons en <file> en lloc dels actuals."
+#: builtin/stash.c
msgid "git stash list [<log-options>]"
-msgstr "git stash list [<log-options>]"
+msgstr "git stash list [<opcions-registre>]"
+#: builtin/stash.c
msgid ""
"git stash show [-u | --include-untracked | --only-untracked] [<diff-"
"options>] [<stash>]"
@@ -12156,22 +15681,28 @@ msgstr ""
"git stash show [-u | --include-untracked | --only-untracked] [<diff-"
"options>] [<stash>]"
+#: builtin/stash.c
msgid "git stash drop [-q | --quiet] [<stash>]"
msgstr "git stash drop [-q | --quiet] [<stash>]"
+#: builtin/stash.c
msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
msgstr "git stash pop [--index] [-q | --quiet] [<stash>]"
+#: builtin/stash.c
msgid "git stash apply [--index] [-q | --quiet] [<stash>]"
msgstr "git stash apply [--index] [-q | --quiet] [<stash>]"
+#: builtin/stash.c
msgid "git stash branch <branchname> [<stash>]"
msgstr "git stash branch <nom-de-branca> [<stash>]"
+#: builtin/stash.c
msgid "git stash store [(-m | --message) <message>] [-q | --quiet] <commit>"
msgstr ""
"git stash store [(-m | --message) <missatge>] [-q | --quiet] <comissió>"
+#: builtin/stash.c
msgid ""
"git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
"| --quiet]\n"
@@ -12187,6 +15718,7 @@ msgstr ""
" [--pathspec-from-file=<fitxer> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]]"
+#: builtin/stash.c
msgid ""
"git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | "
"--quiet]\n"
@@ -12196,27 +15728,34 @@ msgstr ""
"--quiet]\n"
" [-u | --include-untracked] [-a | --all] [<missatge>]"
+#: builtin/stash.c
msgid "git stash create [<message>]"
msgstr "git stash create [<missatge>]"
+#: builtin/stash.c
#, c-format
msgid "'%s' is not a stash-like commit"
msgstr "«%s» no és una comissió de tipus «stash»"
+#: builtin/stash.c
#, c-format
msgid "Too many revisions specified:%s"
msgstr "S'han especificat massa revisions:%s"
+#: builtin/stash.c
msgid "No stash entries found."
msgstr "No s'ha trobat cap entrada «stash»."
+#: builtin/stash.c
#, c-format
msgid "%s is not a valid reference"
msgstr "«%s» no és una referència vàlida"
+#: builtin/stash.c
msgid "git stash clear with arguments is unimplemented"
msgstr "git stash clear amb paràmetres no està implementat"
+#: builtin/stash.c
#, c-format
msgid ""
"WARNING: Untracked file in way of tracked file! Renaming\n"
@@ -12227,154 +15766,202 @@ msgstr ""
" %s -> %s\n"
" per a fer-ne espai.\n"
+#: builtin/stash.c
msgid "cannot apply a stash in the middle of a merge"
msgstr "no es pot aplicar un «stash» enmig d'una fusió"
+#: builtin/stash.c
#, c-format
msgid "could not generate diff %s^!."
msgstr "no s'ha pogut generar diff %s^!."
+#: builtin/stash.c
msgid "conflicts in index. Try without --index."
msgstr "hi ha conflictes en l'índex. Proveu-ho sense --index."
+#: builtin/stash.c
msgid "could not save index tree"
msgstr "no s'ha pogut desar l'arbre d'índex"
+#: builtin/stash.c
#, c-format
msgid "Merging %s with %s"
msgstr "S'està fusionant %s amb %s"
+#: builtin/stash.c
msgid "Index was not unstashed."
msgstr "L'índex no estava «unstashed»."
+#: builtin/stash.c
msgid "could not restore untracked files from stash"
msgstr "no s'han pogut restaurar els fitxers no seguits des del «stash»"
+#: builtin/stash.c
msgid "attempt to recreate the index"
msgstr "intenta tornar a crear l'índex"
+#: builtin/stash.c
#, c-format
msgid "Dropped %s (%s)"
msgstr "Descartada %s (%s)"
+#: builtin/stash.c
#, c-format
msgid "%s: Could not drop stash entry"
msgstr "%s: no s'ha pogut descartar l'entrada «stash»"
+#: builtin/stash.c
#, c-format
msgid "'%s' is not a stash reference"
msgstr "«%s» no és una referència «stash»"
+#: builtin/stash.c
msgid "The stash entry is kept in case you need it again."
-msgstr "Es conserva l'entrada «stash» en cas que la necessiteu altra vegada."
+msgstr ""
+"Es conserva l'entrada «stash» en cas que la necessiteu una altra vegada."
+#: builtin/stash.c
msgid "No branch name specified"
msgstr "Cap nom de branca especificat"
+#: builtin/stash.c
msgid "failed to parse tree"
msgstr "s'ha produït un error en analitzar l'arbre"
+#: builtin/stash.c
msgid "failed to unpack trees"
msgstr "s'ha produït un error en desempaquetar els arbres"
+#: builtin/stash.c
msgid "include untracked files in the stash"
msgstr "inclou els fitxers no seguits a «stash»"
+#: builtin/stash.c
msgid "only show untracked files in the stash"
msgstr "mostra només els fitxers no seguits a «stash»"
+#: builtin/stash.c
#, c-format
msgid "Cannot update %s with %s"
msgstr "No es pot actualitzar %s amb %s"
+#: builtin/stash.c
msgid "stash message"
msgstr "missatge «stash»"
+#: builtin/stash.c
msgid "\"git stash store\" requires one <commit> argument"
msgstr "«git stash store» requereix un argument <comissió>"
+#: builtin/stash.c
msgid "No staged changes"
msgstr "No hi ha canvis a «stage»"
+#: builtin/stash.c
msgid "No changes selected"
msgstr "No hi ha canvis seleccionats"
+#: builtin/stash.c
msgid "You do not have the initial commit yet"
msgstr "Encara no teniu la comissió inicial"
+#: builtin/stash.c
msgid "Cannot save the current index state"
msgstr "No es pot desar l'estat d'índex actual"
+#: builtin/stash.c
msgid "Cannot save the untracked files"
msgstr "No es poden desar els fitxers no seguits"
+#: builtin/stash.c
msgid "Cannot save the current worktree state"
msgstr "No es pot desar l'estat d'arbre de treball actual"
+#: builtin/stash.c
msgid "Cannot save the current staged state"
msgstr "No es pot desar l'estat «stage» actual"
+#: builtin/stash.c
msgid "Cannot record working tree state"
msgstr "No es pot registrar l'estat de l'arbre de treball"
+#: builtin/stash.c
msgid "Can't use --patch and --include-untracked or --all at the same time"
msgstr "No es poden usar --patch i --include-untracked o --all a la vegada"
+#: builtin/stash.c
msgid "Can't use --staged and --include-untracked or --all at the same time"
msgstr "No es poden usar --staged i --include-untracked o --all a la vegada"
+#: builtin/stash.c
msgid "Did you forget to 'git add'?"
msgstr "Heu oblidat de fer «git add»?"
+#: builtin/stash.c
msgid "No local changes to save"
msgstr "No hi ha canvis locals a desar"
+#: builtin/stash.c
msgid "Cannot initialize stash"
msgstr "No es pot inicialitzar el magatzem"
+#: builtin/stash.c
msgid "Cannot save the current status"
msgstr "No es pot desar l'estat actual"
+#: builtin/stash.c
#, c-format
msgid "Saved working directory and index state %s"
msgstr "S'han desat el directori de treball i l'estat d'índex %s"
+#: builtin/stash.c
msgid "Cannot remove worktree changes"
msgstr "No es poden eliminar els canvis de l'arbre de treball"
+#: builtin/stash.c
msgid "keep index"
msgstr "mantén l'índex"
+#: builtin/stash.c
msgid "stash staged changes only"
msgstr "fes «stash» només dels canvis «staged»"
+#: builtin/stash.c
msgid "stash in patch mode"
msgstr "fes «stash» en mode pedaç"
+#: builtin/stash.c
msgid "quiet mode"
msgstr "mode silenciós"
+#: builtin/stash.c
msgid "include untracked files in stash"
msgstr "inclou els fitxers no seguits a «stash»"
+#: builtin/stash.c
msgid "include ignore files"
msgstr "inclou els fitxers ignorats"
+#: builtin/stripspace.c
msgid "skip and remove all lines starting with comment character"
msgstr ""
"omet i elimina totes les línies que comencin amb el caràcter de comentari"
+#: builtin/stripspace.c
msgid "prepend comment character and space to each line"
msgstr "anteposa el caràcter de comentari i un espai a cada línia"
+#: builtin/submodule--helper.c
#, c-format
msgid "Expecting a full ref name, got %s"
msgstr "S'espera un nom de referència ple, s'ha rebut %s"
+#: builtin/submodule--helper.c
#, c-format
msgid "could not get a repository handle for submodule '%s'"
msgstr "no s'ha pogut obtenir el gestor del repositori pel submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"could not look up configuration '%s'. Assuming this repository is its own "
@@ -12383,14 +15970,17 @@ msgstr ""
"no s'ha pogut trobar la configuració «%s». S'assumeix que aquest repositori "
"és el seu repositori font autoritzat."
+#: builtin/submodule--helper.c
#, c-format
msgid "No url found for submodule path '%s' in .gitmodules"
msgstr "No s'ha trobat cap url per al camí de submòdul «%s» a .gitmodules"
+#: builtin/submodule--helper.c
#, c-format
msgid "Entering '%s'\n"
msgstr "S'està entrant a «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"run_command returned non-zero status for %s\n"
@@ -12399,6 +15989,7 @@ msgstr ""
"run_command ha retornat un estat diferent de zero per a %s\n"
"."
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"run_command returned non-zero status while recursing in the nested "
@@ -12409,56 +16000,70 @@ msgstr ""
"recursivament als submòduls imbricats de %s\n"
"."
+#: builtin/submodule--helper.c
msgid "suppress output of entering each submodule command"
msgstr "omet la sortida en entrar a cada ordre del submòdul"
+#: builtin/submodule--helper.c
msgid "recurse into nested submodules"
msgstr "cerca recursivament als submòduls imbricats"
+#: builtin/submodule--helper.c
msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
msgstr "git submodule foreach [--quiet] [--recursive] [--] <ordre>"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to register url for submodule path '%s'"
msgstr "S'ha produït un error en registrar l'url per al camí de submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule '%s' (%s) registered for path '%s'\n"
msgstr "S'ha registrat el submòdul «%s» (%s) per al camí «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "warning: command update mode suggested for submodule '%s'\n"
msgstr ""
"advertència: se suggereix el mode d'actualització per ordre per al submòdul "
"«%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to register update mode for submodule path '%s'"
msgstr ""
"S'ha produït un error en registrar el mode d'actualització per al camí de "
"submòdul «%s»"
+#: builtin/submodule--helper.c
msgid "suppress output for initializing a submodule"
msgstr "omet la sortida en inicialitzar un submòdul"
+#: builtin/submodule--helper.c
msgid "git submodule init [<options>] [<path>]"
msgstr "git submodule init [<opcions>] [<camí>]"
+#: builtin/submodule--helper.c
#, c-format
msgid "no submodule mapping found in .gitmodules for path '%s'"
msgstr "no s'ha trobat cap mapatge de submòdul a .gitmodules per al camí «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "could not resolve HEAD ref inside the submodule '%s'"
msgstr "no s'ha pogut resoldre la referència a HEAD dins del submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "failed to recurse into submodule '%s'"
msgstr "s'ha produït un error en cercar recursivament al submòdul «%s»"
+#: builtin/submodule--helper.c
msgid "suppress submodule status output"
msgstr "suprimeix la sortida de l'estat del submòdul"
+#: builtin/submodule--helper.c
msgid ""
"use commit stored in the index instead of the one stored in the submodule "
"HEAD"
@@ -12466,69 +16071,87 @@ msgstr ""
"utilitza la comissió emmagatzemada a l'índex en lloc de l'emmagatzemada al "
"HEAD del submòdul"
+#: builtin/submodule--helper.c
msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
msgstr "git submodule status [--quiet] [--cached] [--recursive] [<camí>...]"
+#: builtin/submodule--helper.c
#, c-format
msgid "* %s %s(blob)->%s(submodule)"
msgstr "* %s %s(blob)->%s(submòdul)"
+#: builtin/submodule--helper.c
#, c-format
msgid "* %s %s(submodule)->%s(blob)"
msgstr "* %s %s(submòdul)->%s(blob)"
+#: builtin/submodule--helper.c
#, c-format
msgid "%s"
msgstr "%s"
+#: builtin/submodule--helper.c
#, c-format
msgid "couldn't hash object from '%s'"
msgstr "no s'ha pogut fer el resum de l'objecte de «%s»"
+#: builtin/submodule--helper.c
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "mode inesperat %o\n"
+msgid "unexpected mode %o"
+msgstr "mode %o inesperat"
+#: builtin/submodule--helper.c
msgid "use the commit stored in the index instead of the submodule HEAD"
msgstr ""
"utilitza la comissió emmagatzemada a l'índex en lloc de l'emmagatzemada al "
"HEAD del submòdul"
+#: builtin/submodule--helper.c
msgid "compare the commit in the index with that in the submodule HEAD"
msgstr ""
"compara la comissió emmagatzemada a l'índex en lloc de l'emmagatzemada al "
"HEAD del submòdul"
+#: builtin/submodule--helper.c
msgid "skip submodules with 'ignore_config' value set to 'all'"
msgstr "omet els submòduls amb el valor «ignore_config» establert a «all»"
+#: builtin/submodule--helper.c
msgid "limit the summary size"
msgstr "limita la mida del resum"
+#: builtin/submodule--helper.c
msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
msgstr "git submodule summary [<opcions>] [<comissió>] [--] [<camí>]"
+#: builtin/submodule--helper.c
msgid "could not fetch a revision for HEAD"
msgstr "no s'ha pogut obtenir una revisió per a HEAD"
+#: builtin/submodule--helper.c
#, c-format
msgid "Synchronizing submodule url for '%s'\n"
msgstr "S'està sincronitzant l'url del submòdul per a «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "failed to register url for submodule path '%s'"
msgstr "s'ha produït un error en registrar l'url per al camí del submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "failed to update remote for submodule '%s'"
msgstr "s'ha produït un error en actualitzar el remot pel submòdul «%s»"
+#: builtin/submodule--helper.c
msgid "suppress output of synchronizing submodule url"
msgstr "omet la sortida de la sincronització de l'URL del submòdul"
+#: builtin/submodule--helper.c
msgid "git submodule sync [--quiet] [--recursive] [<path>]"
msgstr "git submodule sync [--quiet] [--recursive] [<camí>]"
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"Submodule work tree '%s' contains a .git directory. This will be replaced "
@@ -12537,6 +16160,7 @@ msgstr ""
"L'arbre de treball del submòdul «%s» conté un directori .git. Aquest es "
"reemplaçarà amb un fitxer a .git mitjançant l'ús d'«absorbgitdirs»."
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"Submodule work tree '%s' contains local modifications; use '-f' to discard "
@@ -12545,38 +16169,47 @@ msgstr ""
"L'arbre de treball del submòdul «%s» conté modificacions locals; useu «-f» "
"per a descartar-les"
+#: builtin/submodule--helper.c
#, c-format
msgid "Cleared directory '%s'\n"
msgstr "S'ha esborrat el directori «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "Could not remove submodule work tree '%s'\n"
msgstr "No s'ha pogut eliminar l'arbre de treball de submòdul «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "could not create empty submodule directory %s"
msgstr "no s'ha pogut crear el directori de submòdul buit %s"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
msgstr "S'ha desregistrat el submòdul «%s» (%s) per al camí «%s»\n"
+#: builtin/submodule--helper.c
msgid "remove submodule working trees even if they contain local changes"
msgstr ""
"elimina els arbres de treball dels submòduls fins i tot si contenen canvis "
"locals"
+#: builtin/submodule--helper.c
msgid "unregister all submodules"
msgstr "desregistra tots els submòduls"
+#: builtin/submodule--helper.c
msgid ""
"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"
msgstr ""
"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<camí>...]]"
+#: builtin/submodule--helper.c
msgid "Use '--all' if you really want to deinitialize all submodules"
msgstr "Useu «--all» si realment voleu desinicialitzar tots els submòduls"
+#: builtin/submodule--helper.c
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"
@@ -12589,138 +16222,172 @@ msgstr ""
"submodule.alternateErrorStrategy a «info» o bé cloneu amb\n"
"«--reference-if-able' en comptes de «--reference»."
+#: builtin/submodule--helper.c
#, c-format
msgid "could not get a repository handle for gitdir '%s'"
msgstr "no s'ha pogut obtenir el gestor del repositori per al gitdir «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "submodule '%s' cannot add alternate: %s"
msgstr "el submòdul «%s» no pot afegir un alternatiu: %s"
+#: builtin/submodule--helper.c
#, c-format
msgid "Value '%s' for submodule.alternateErrorStrategy is not recognized"
msgstr "No es reconeix el valor «%s» per a submodule.alternateErrorStrategy"
+#: builtin/submodule--helper.c
#, c-format
msgid "Value '%s' for submodule.alternateLocation is not recognized"
msgstr "No es reconeix el valor «%s» per a submodule.alternateLocation"
+#: builtin/submodule--helper.c submodule.c
#, c-format
msgid "refusing to create/use '%s' in another submodule's git dir"
msgstr "s'ha rebutjat crear/usar «%s» en el directori git d'un altre submòdul"
-#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "el clonatge de «%s» al camí de submòdul «%s» ha fallat"
-
+#: builtin/submodule--helper.c
#, c-format
msgid "directory not empty: '%s'"
msgstr "directori no buit: «%s»"
+#: builtin/submodule--helper.c
+#, c-format
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "el clonatge de «%s» al camí de submòdul «%s» ha fallat"
+
+#: builtin/submodule--helper.c
#, c-format
msgid "could not get submodule directory for '%s'"
msgstr "no s'ha pogut obtenir el directori de submòdul per a «%s»"
+#: builtin/submodule--helper.c
msgid "alternative anchor for relative paths"
msgstr "àncora alternativa per als camins relatius"
+#: builtin/submodule--helper.c
msgid "where the new submodule will be cloned to"
msgstr "a on es clonarà el submòdul nou"
+#: builtin/submodule--helper.c
msgid "name of the new submodule"
msgstr "nom del submòdul nou"
+#: builtin/submodule--helper.c
msgid "url where to clone the submodule from"
msgstr "url del qual clonar el submòdul"
+#: builtin/submodule--helper.c
msgid "depth for shallow clones"
msgstr "profunditat dels clons superficials"
+#: builtin/submodule--helper.c
msgid "force cloning progress"
msgstr "força el progrés del clonatge"
+#: builtin/submodule--helper.c
msgid "disallow cloning into non-empty directory"
msgstr "no permetis clonar en un directori no buit"
+#: builtin/submodule--helper.c
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=<camí>] [--quiet] [--reference "
-"<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
+"<repositori>] [--name <nom>] [--depth <depth>] [--single-branch] [--filter "
"<filter-spec>] --url <url> --path <camí>"
+#: builtin/submodule--helper.c
#, c-format
msgid "Invalid update mode '%s' configured for submodule path '%s'"
msgstr ""
"Mode d'actualització «%s» configurat no vàlid per al camí de submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule path '%s' not initialized"
msgstr "El camí de submòdul «%s» no està inicialitzat"
+#: builtin/submodule--helper.c
msgid "Maybe you want to use 'update --init'?"
msgstr "Potser voleu usar «update --init»?"
+#: builtin/submodule--helper.c
#, c-format
msgid "Skipping unmerged submodule %s"
msgstr "S'està ometent el submòdul no fusionat %s"
+#: builtin/submodule--helper.c
#, c-format
msgid "Skipping submodule '%s'"
msgstr "S'està ometent el submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "cannot clone submodule '%s' without a URL"
msgstr "no es pot clonar el submòdul «%s» sense un URL"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to clone '%s'. Retry scheduled"
msgstr "S'ha produït un error en clonar «%s». S'ha programat un reintent"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to clone '%s' a second time, aborting"
msgstr "S'ha produït un error per segon cop en clonar «%s», s'està avortant"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to checkout '%s' in submodule path '%s'"
msgstr "No s'ha pogut agafar «%s» en el camí de submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to rebase '%s' in submodule path '%s'"
msgstr "No s'ha pogut fer «rebase» «%s» en el camí de submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to merge '%s' in submodule path '%s'"
msgstr "No s'ha pogut fusionar «%s» en el camí de submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Execution of '%s %s' failed in submodule path '%s'"
msgstr "L'execució de «%s %s» ha fallat en el camí de submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule path '%s': checked out '%s'\n"
msgstr "Camí de submòdul «%s»: s'ha agafat «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule path '%s': rebased into '%s'\n"
msgstr "Camí de submòdul «%s»: s'ha fet «rebase» en «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule path '%s': merged in '%s'\n"
msgstr "Camí de submòdul «%s»: s'ha fusionat en «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "Submodule path '%s': '%s %s'\n"
msgstr "El camí de submòdul «%s»: '%s %s'\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to fetch in submodule path '%s'; trying to directly fetch %s:"
msgstr ""
"No s'ha pogut obtenir en el camí de submòdul «$%s»; s'està intentant obtenir "
"directament %s:"
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"Fetched in submodule path '%s', but it did not contain %s. Direct fetching "
@@ -12729,10 +16396,12 @@ msgstr ""
"S'ha obtingut en un camí de submòdul «%s», però no contenia %s. L'obtenció "
"directa d'aquesta comissió ha fallat."
+#: builtin/submodule--helper.c
#, c-format
msgid "could not initialize submodule at path '%s'"
msgstr "no s'ha pogut inicialitzar el submòdul al camí «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12741,62 +16410,80 @@ msgstr ""
"La branca de submòdul (%s) està configurada per a heretar la branca del "
"superprojecte, però el superprojecte no és en cap branca"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to find current revision in submodule path '%s'"
msgstr "No s'ha pogut trobar la revisió actual al camí del submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to fetch in submodule path '%s'"
msgstr "No s'ha pogut obtenir el camí del submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Unable to find %s revision in submodule path '%s'"
msgstr "No s'ha pogut trobar la revisió %s en el camí del submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to recurse into submodule path '%s'"
msgstr ""
"s'ha produït un error en cercar recursivament al camí del submòdul «%s»"
+#: builtin/submodule--helper.c
msgid "force checkout updates"
msgstr "força les actualitzacions"
+#: builtin/submodule--helper.c
msgid "initialize uninitialized submodules before update"
msgstr "inicialitza els submòduls sense inicialitzar abans d'actualitzar"
+#: builtin/submodule--helper.c
msgid "use SHA-1 of submodule's remote tracking branch"
msgstr "usa el SHA-1 de la branca de seguiment remota del submòdul"
+#: builtin/submodule--helper.c
msgid "traverse submodules recursively"
msgstr "recorre els submòduls recursivament"
+#: builtin/submodule--helper.c
msgid "don't fetch new objects from the remote site"
msgstr "no obtinguis els objectes nous del lloc remot"
+#: builtin/submodule--helper.c
msgid "use the 'checkout' update strategy (default)"
msgstr "utilitza l'estratègia d'actualització «checkout» (predeterminada)"
+#: builtin/submodule--helper.c
msgid "use the 'merge' update strategy"
msgstr "utilitza l'estratègia d'actualització de «merge»"
+#: builtin/submodule--helper.c
msgid "use the 'rebase' update strategy"
msgstr "utilitza l'estratègia d'actualització de «rebase»"
+#: builtin/submodule--helper.c
msgid "create a shallow clone truncated to the specified number of revisions"
msgstr "crea un clon superficial truncat al nombre de revisions especificat"
+#: builtin/submodule--helper.c
msgid "parallel jobs"
msgstr "tasques paral·leles"
+#: builtin/submodule--helper.c
msgid "whether the initial clone should follow the shallow recommendation"
msgstr "si el clonatge inicial ha de seguir la recomanació de superficialitat"
+#: builtin/submodule--helper.c
msgid "don't print cloning progress"
msgstr "no imprimeixis el progrés del clonatge"
+#: builtin/submodule--helper.c
msgid "disallow cloning into non-empty directory, implies --init"
msgstr "no permetis clonar en un directori no buit, implica --init"
+#: builtin/submodule--helper.c
msgid ""
"git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
"[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12805,65 +16492,86 @@ msgid ""
msgstr ""
"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] "
+"shallow] [--reference <repositori>] [--recursive] [--[no-]single-branch] "
"[--] [<camí>...]"
+#: builtin/submodule--helper.c submodule.c
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "S'ha produït un error en resoldre HEAD com a referència vàlida."
+
+#: builtin/submodule--helper.c
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<opcions>] [<camí>...]"
+#: builtin/submodule--helper.c
msgid "suppress output for setting url of a submodule"
msgstr "omet la sortida en configurar un URL d'un submòdul"
+#: builtin/submodule--helper.c
msgid "git submodule set-url [--quiet] <path> <newurl>"
-msgstr "git submodule set-url [--quiet] <camí> <newurl>"
+msgstr "git submodule set-url [--quiet] <camí> <url-nou>"
+#: builtin/submodule--helper.c
msgid "set the default tracking branch to master"
msgstr "estableix la branca de seguiment per defecte a «master»"
+#: builtin/submodule--helper.c
msgid "set the default tracking branch"
msgstr "estableix la branca de seguiment per defecte"
+#: builtin/submodule--helper.c
msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <camí>"
+#: builtin/submodule--helper.c
msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <branca> <camí>"
+#: builtin/submodule--helper.c
msgid "--branch or --default required"
msgstr "cal --branch o --default"
+#: builtin/submodule--helper.c
msgid "print only error messages"
msgstr "mostra només els missatges d'error"
+#: builtin/submodule--helper.c
msgid "force creation"
msgstr "força la creació"
+#: builtin/submodule--helper.c
msgid "show whether the branch would be created"
msgstr "mostra si es crearà la branca"
+#: builtin/submodule--helper.c
msgid ""
"git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
"quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
msgstr ""
"git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
-"quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
+"quiet] [-t|--track] [-n|--dry-run] <nom> <oid-inicial> <nom-inicial>"
+#: builtin/submodule--helper.c
#, c-format
msgid "creating branch '%s'"
msgstr "s'està creant la branca «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Adding existing repo at '%s' to the index\n"
msgstr "S'està afegint el repositori existent a «%s» a l'índex\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "'%s' already exists and is not a valid git repo"
msgstr "«%s» ja existeix i no és un repositori de git vàlid"
+#: builtin/submodule--helper.c
#, c-format
msgid "A git directory for '%s' is found locally with remote(s):\n"
msgstr "S'ha trobat un directori de git per a «%s» localment amb els remots:\n"
+#: builtin/submodule--helper.c
#, c-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from\n"
@@ -12881,46 +16589,58 @@ msgstr ""
"o no esteu segur de què vol dir això, trieu un altre nom amb l'opció «--"
"name»."
+#: builtin/submodule--helper.c
#, c-format
msgid "Reactivating local git directory for submodule '%s'\n"
msgstr "S'està reactivant el directori de git local per al submòdul «%s»\n"
+#: builtin/submodule--helper.c
#, c-format
msgid "unable to checkout submodule '%s'"
msgstr "no s'ha pogut agafar el submòdul «%s»"
+#: builtin/submodule--helper.c
msgid "please make sure that the .gitmodules file is in the working tree"
msgstr "assegureu-vos que el fitxer .gitmodules és a l'arbre de treball"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to add submodule '%s'"
msgstr "S'ha produït un error en afegir el submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "Failed to register submodule '%s'"
msgstr "S'ha produït un error en registrar el submòdul «%s»"
+#: builtin/submodule--helper.c
#, c-format
msgid "'%s' already exists in the index"
msgstr "«%s» ja existeix en l'índex"
+#: builtin/submodule--helper.c
#, c-format
msgid "'%s' already exists in the index and is not a submodule"
msgstr "«%s» ja existeix en l'índex i no és submòdul"
+#: builtin/submodule--helper.c read-cache.c
#, c-format
msgid "'%s' does not have a commit checked out"
msgstr "«%s» no té una comissió comprovada"
+#: builtin/submodule--helper.c
msgid "branch of repository to add as submodule"
msgstr "la branca del repositori a afegir com a submòdul"
+#: builtin/submodule--helper.c
msgid "allow adding an otherwise ignored submodule path"
msgstr "permet afegir un camí de submòdul que si no s'hagués ignorat"
+#: builtin/submodule--helper.c
msgid "borrow the objects from reference repositories"
msgstr "manlleva els objectes dels repositoris de referències"
+#: builtin/submodule--helper.c
msgid ""
"sets the submodule's name to the given string instead of defaulting to its "
"path"
@@ -12928,62 +16648,81 @@ msgstr ""
"estableix el nom del submòdul a la cadena donada en lloc de per defecte al "
"seu camí"
+#: builtin/submodule--helper.c
msgid "git submodule add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule add [<opcions>] [--] <repository> [<camí>]"
+msgstr "git submodule add [<opcions>] [--] <repositori> [<camí>]"
+#: builtin/submodule--helper.c
msgid "Relative path can only be used from the toplevel of the working tree"
msgstr ""
"El camí relatiu només es pot usar des del nivell superior de l'arbre de "
"treball"
+#: builtin/submodule--helper.c
#, c-format
msgid "repo URL: '%s' must be absolute or begin with ./|../"
msgstr "URL de repositori: «%s» ha de ser absolut o començar amb ./|../"
+#: builtin/submodule--helper.c
#, c-format
msgid "'%s' is not a valid submodule name"
msgstr "«%s» no és un nom de submòdul vàlid"
+#: builtin/submodule--helper.c
msgid "git submodule--helper <command>"
-msgstr "git submodule--helper <command>"
+msgstr "git submodule--helper <ordre>"
+#: builtin/symbolic-ref.c
msgid "git symbolic-ref [-m <reason>] <name> <ref>"
-msgstr "git symbolic-ref [-m <reason>] <name> <ref>"
+msgstr "git symbolic-ref [-m <raó>] <nom> <referència>"
+#: builtin/symbolic-ref.c
msgid "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
-msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
+msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <nom>"
+#: builtin/symbolic-ref.c
msgid "git symbolic-ref --delete [-q] <name>"
-msgstr "git symbolic-ref --delete [-q] <name>"
+msgstr "git symbolic-ref --delete [-q] <nom>"
+#: builtin/symbolic-ref.c
msgid "suppress error message for non-symbolic (detached) refs"
msgstr "omet el missatge d'error de referències no simbòliques (separades)"
+#: builtin/symbolic-ref.c
msgid "delete symbolic ref"
msgstr "suprimeix la referència simbòlica"
+#: builtin/symbolic-ref.c
msgid "shorten ref output"
msgstr "escurça la sortida de referències"
+#: builtin/symbolic-ref.c
msgid "recursively dereference (default)"
msgstr "desreferencia recursivament (per defecte)"
+#: builtin/symbolic-ref.c builtin/update-ref.c
msgid "reason"
msgstr "raó"
+#: builtin/symbolic-ref.c builtin/update-ref.c
msgid "reason of the update"
msgstr "raó de l'actualització"
+#: builtin/tag.c
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
-"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <fitxer>] [-e]\n"
-" <tagname> [<comissió> | <objecte>]"
+"git tag [-a | -s | -u <id-clau>] [-f] [-m <missatge> | -F <fitxer>] [-e]\n"
+" [(--trailer <token>[(=|:)<valor>])...]\n"
+" <nom-etiqueta> [<comissió> | <objecte>]"
+#: builtin/tag.c
msgid "git tag -d <tagname>..."
-msgstr "git tag -d <nom-d'etiqueta>..."
+msgstr "git tag -d <nom-etiqueta>..."
+#: builtin/tag.c
msgid ""
"git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
" [--points-at <object>] [--column[=<options>] | --no-column]\n"
@@ -12992,49 +16731,56 @@ msgid ""
msgstr ""
"git tag [-n[<num>]] -l [--contains <comissió>] [--no-contains <comissió>]\n"
" [--points-at <objecte>] [--column[=<opcions>] | --no-column]\n"
-" [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+" [--create-reflog] [--sort=<clau>] [--format=<format>]\n"
" [--merged <comissió>] [--no-merged <comissió>] [<patró>...]"
+#: builtin/tag.c
msgid "git tag -v [--format=<format>] <tagname>..."
-msgstr "git tag -v [--format=<format>] <nom-d'etiqueta>..."
+msgstr "git tag -v [--format=<format>] <nom-etiqueta>..."
+#: builtin/tag.c
#, c-format
msgid "tag '%s' not found."
msgstr "no s'ha trobat l'etiqueta «%s»."
+#: builtin/tag.c
#, c-format
msgid "Deleted tag '%s' (was %s)\n"
msgstr "S'ha suprimit l'etiqueta «%s» (era %s)\n"
+#: builtin/tag.c
#, c-format
msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
-"Escriviu el missatge de l'etiqueta:\n"
+"Escriviu un missatge per a l'etiqueta:\n"
" %s\n"
-"Les línies que comencin amb «%c» s'ignoraran.\n"
+"S'ignoraran les línies que comencen amb «%s».\n"
+#: builtin/tag.c
#, 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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
-"Escriviu el missatge de l'etiqueta:\n"
+"Escriviu un missatge per a l'etiqueta:\n"
" %s\n"
-"Les línies que comencin amb «%c» es retindran; podeu eliminar-les per vós "
-"mateix si voleu.\n"
+"Es mantindran les línies que comencin amb «%s»; les podeu eliminar si "
+"voleu.\n"
+#: builtin/tag.c
msgid "unable to sign the tag"
msgstr "no s'ha pogut signar l'etiqueta"
+#: builtin/tag.c
#, c-format
msgid ""
"You have created a nested tag. The object referred to by your new tag is\n"
@@ -13048,264 +16794,361 @@ msgstr ""
"\n"
"\tgit tag -f %s %s^{}"
+#: builtin/tag.c
msgid "bad object type."
msgstr "el tipus d'objecte és incorrecte."
+#: builtin/tag.c
msgid "no tag message?"
msgstr "no hi ha cap missatge d'etiqueta?"
+#: builtin/tag.c
#, c-format
msgid "The tag message has been left in %s\n"
msgstr "S'ha deixat el missatge de l'etiqueta en %s\n"
+#: builtin/tag.c
msgid "list tag names"
msgstr "llista els noms d'etiqueta"
+#: builtin/tag.c
msgid "print <n> lines of each tag message"
msgstr "imprimeix <n> línies de cada missatge d'etiqueta"
+#: builtin/tag.c
msgid "delete tags"
msgstr "suprimeix les etiquetes"
+#: builtin/tag.c
msgid "verify tags"
msgstr "verifica les etiquetes"
+#: builtin/tag.c
msgid "Tag creation options"
msgstr "Opcions de creació d'etiquetes"
+#: builtin/tag.c
msgid "annotated tag, needs a message"
msgstr "etiqueta anotada, necessita un missatge"
+#: builtin/tag.c
msgid "tag message"
msgstr "missatge d'etiqueta"
+#: builtin/tag.c
msgid "force edit of tag message"
msgstr "força l'edició del missatge de l'etiqueta"
+#: builtin/tag.c
msgid "annotated and GPG-signed tag"
msgstr "etiqueta anotada i signada per GPG"
+#: builtin/tag.c
msgid "use another key to sign the tag"
msgstr "usa una altra clau per a signar l'etiqueta"
+#: builtin/tag.c
msgid "replace the tag if exists"
msgstr "reemplaça l'etiqueta si existeix"
+#: builtin/tag.c builtin/update-ref.c
msgid "create a reflog"
msgstr "crea un registre de referències"
+#: builtin/tag.c
msgid "Tag listing options"
msgstr "Opcions de llistat d'etiquetes"
+#: builtin/tag.c
msgid "show tag list in columns"
msgstr "mostra la llista d'etiquetes en columnes"
+#: builtin/tag.c
msgid "print only tags that contain the commit"
msgstr "imprimeix només les etiquetes que continguin la comissió"
+#: builtin/tag.c
msgid "print only tags that don't contain the commit"
msgstr "imprimeix només les etiquetes que no continguin la comissió"
+#: builtin/tag.c
msgid "print only tags that are merged"
msgstr "imprimeix només les etiquetes que s'han fusionat"
+#: builtin/tag.c
msgid "print only tags that are not merged"
msgstr "imprimeix només les etiquetes que no s'han fusionat"
+#: builtin/tag.c
msgid "print only tags of the object"
msgstr "imprimeix només les etiquetes de l'objecte"
+#: builtin/tag.c
+msgid "could not start 'git column'"
+msgstr "no s'ha pogut iniciar «git column»"
+
+#: builtin/tag.c
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "l'opció «%s» només està permesa en mode de llista"
+#: builtin/tag.c
#, c-format
msgid "'%s' is not a valid tag name."
msgstr "«%s» no és un nom d'etiqueta vàlid."
+#: builtin/tag.c
#, c-format
msgid "tag '%s' already exists"
msgstr "l'etiqueta «%s» ja existeix"
+#: builtin/tag.c sequencer.c
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Mode de neteja no vàlid %s"
+#: builtin/tag.c
#, c-format
msgid "Updated tag '%s' (was %s)\n"
msgstr "Etiqueta «%s» actualitzada (era %s)\n"
+#: builtin/unpack-objects.c
msgid "pack exceeds maximum allowed size"
msgstr "el paquet supera la mida màxima permesa"
+#: builtin/unpack-objects.c
msgid "failed to write object in stream"
msgstr "no s'ha pogut escriure l'objecte al flux"
+#: builtin/unpack-objects.c
#, c-format
msgid "inflate returned (%d)"
msgstr "inflate ha retornat (%d)"
+#: builtin/unpack-objects.c
msgid "invalid blob object from stream"
msgstr "l'objecte blob del flux no és vàlid"
+#: builtin/unpack-objects.c
msgid "Unpacking objects"
msgstr "S'estan desempaquetant els objectes"
+#: builtin/update-index.c
#, c-format
msgid "failed to create directory %s"
msgstr "s'ha produït un error en crear el directori %s"
+#: builtin/update-index.c
#, c-format
msgid "failed to delete file %s"
msgstr "s'ha produït un error en suprimir el fitxer %s"
+#: builtin/update-index.c
#, c-format
msgid "failed to delete directory %s"
msgstr "s'ha produït un error en suprimir el directori %s"
+#: builtin/update-index.c
#, c-format
msgid "Testing mtime in '%s' "
msgstr "S'està provant mtime en «%s» "
+#: builtin/update-index.c
msgid "directory stat info does not change after adding a new file"
msgstr ""
"la informació de stat de directori no canvia després d'afegir un fitxer nou"
+#: builtin/update-index.c
msgid "directory stat info does not change after adding a new directory"
msgstr ""
"la informació de stat de directori no canvia després d'afegir un directori "
"nou"
+#: builtin/update-index.c
msgid "directory stat info changes after updating a file"
msgstr ""
"la informació de stat de directori canvia després d'actualitzar un fitxer"
+#: builtin/update-index.c
msgid "directory stat info changes after adding a file inside subdirectory"
msgstr ""
"la informació de stat de directori canvia després d'afegir un fitxer dins "
"d'un subdirectori"
+#: builtin/update-index.c
msgid "directory stat info does not change after deleting a file"
msgstr ""
"la informació de stat de directori no canvia després de suprimir un fitxer"
+#: builtin/update-index.c
msgid "directory stat info does not change after deleting a directory"
msgstr ""
"la informació de stat de directori no canvia després de suprimir un directori"
+#: builtin/update-index.c
msgid " OK"
msgstr " D'acord"
+#: builtin/update-index.c
msgid "git update-index [<options>] [--] [<file>...]"
msgstr "git update-index [<opcions>] [--] [<fitxer>...]"
+#: builtin/update-index.c
msgid "continue refresh even when index needs update"
msgstr ""
"continua l'actualització encara que l'índex necessiti una actualització"
+#: builtin/update-index.c
msgid "refresh: ignore submodules"
msgstr "actualitza: ignora els submòduls"
+#: builtin/update-index.c
msgid "do not ignore new files"
msgstr "no ignoris els fitxers nous"
+#: builtin/update-index.c
msgid "let files replace directories and vice-versa"
msgstr "deixa que els fitxers reemplacin els directoris i viceversa"
+#: builtin/update-index.c
msgid "notice files missing from worktree"
msgstr "tingues en compte els fitxers absents de l'arbre de treball"
+#: builtin/update-index.c
msgid "refresh even if index contains unmerged entries"
msgstr "actualitza encara que l'índex contingui entrades no fusionades"
+#: builtin/update-index.c
msgid "refresh stat information"
msgstr "actualitza la informació d'estadístiques"
+#: builtin/update-index.c
msgid "like --refresh, but ignore assume-unchanged setting"
msgstr "com --refresh, però ignora el paràmetre assume-unchanged"
+#: builtin/update-index.c
msgid "<mode>,<object>,<path>"
msgstr "<mode>,<objecte>,<camí>"
+#: builtin/update-index.c
msgid "add the specified entry to the index"
msgstr "afegeix l'entrada especificada a l'índex"
+#: builtin/update-index.c
msgid "mark files as \"not changing\""
msgstr "marca els fitxers com a «no canviant»"
+#: builtin/update-index.c
msgid "clear assumed-unchanged bit"
msgstr "esborra el bit assumed-unchanged"
+#: builtin/update-index.c
msgid "mark files as \"index-only\""
msgstr "marca els fitxers com a «només índex»"
+#: builtin/update-index.c
msgid "clear skip-worktree bit"
msgstr "esborra el bit skip-worktree"
+#: builtin/update-index.c
msgid "do not touch index-only entries"
msgstr "no toquis les entrades de només índex"
+#: builtin/update-index.c
msgid "add to index only; do not add content to object database"
msgstr ""
"només afegeix a l'índex; no afegeixis el contingut a la base de dades "
"d'objectes"
+#: builtin/update-index.c
msgid "remove named paths even if present in worktree"
msgstr ""
"elimina els camins anomenats encara que estiguin presents en l'arbre de "
"treball"
+#: builtin/update-index.c
msgid "with --stdin: input lines are terminated by null bytes"
msgstr "amb --stdin: les línies d'entrada acaben amb octets nuls"
+#: builtin/update-index.c
msgid "read list of paths to be updated from standard input"
msgstr "llegeix la llista de camins a actualitzar des de l'entrada estàndard"
+#: builtin/update-index.c
msgid "add entries from standard input to the index"
msgstr "afegeix les entrades de l'entrada estàndard a l'índex"
+#: builtin/update-index.c
msgid "repopulate stages #2 and #3 for the listed paths"
msgstr "reemplena les «stage» #2 i #3 per als camins llistats"
+#: builtin/update-index.c
msgid "only update entries that differ from HEAD"
msgstr "només actualitza les entrades que difereixin de HEAD"
+#: builtin/update-index.c
msgid "ignore files missing from worktree"
msgstr "ignora els fitxers absents de l'arbre de treball"
+#: builtin/update-index.c
msgid "report actions to standard output"
msgstr "informa de les accions en la sortida estàndard"
+#: builtin/update-index.c
msgid "(for porcelains) forget saved unresolved conflicts"
msgstr "(per a porcellanes) oblida't dels conflictes no resolts ni desats"
+#: builtin/update-index.c
msgid "write index in this format"
msgstr "escriu l'índex en aquest format"
+#: builtin/update-index.c
+msgid "report on-disk index format version"
+msgstr "informa sobre la versió del format de l'índex del disc"
+
+#: builtin/update-index.c
msgid "enable or disable split index"
msgstr "habilita o inhabilita l'índex dividit"
+#: builtin/update-index.c
msgid "enable/disable untracked cache"
msgstr "habilita/inhabilita la memòria cau no seguida"
+#: builtin/update-index.c
msgid "test if the filesystem supports untracked cache"
msgstr "prova si el sistema de fitxers admet la memòria cau no seguida"
+#: builtin/update-index.c
msgid "enable untracked cache without testing the filesystem"
msgstr "habilita la memòria cau no seguida sense provar el sistema de fitxers"
+#: builtin/update-index.c
msgid "write out the index even if is not flagged as changed"
msgstr "escriu l'índex encara que no estigui marcat com a canviat"
+#: builtin/update-index.c
msgid "enable or disable file system monitor"
msgstr "habilita o inhabilita el monitor del sistema de fitxers"
+#: builtin/update-index.c
msgid "mark files as fsmonitor valid"
msgstr "marca els fitxers com a vàlids pel fsmonitor"
+#: builtin/update-index.c
msgid "clear fsmonitor valid bit"
msgstr "esborra el bit de validesa del fsmonitor"
+#: builtin/update-index.c
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#: builtin/update-index.c
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version: era %d, s'ha establert a %d"
+
+#: builtin/update-index.c
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -13313,6 +17156,7 @@ msgstr ""
"core.splitIndex està establert a fals; elimineu-lo o canviar-lo, si realment "
"voleu habilitar l'índex dividit"
+#: builtin/update-index.c
msgid ""
"core.splitIndex is set to true; remove or change it, if you really want to "
"disable split index"
@@ -13320,6 +17164,7 @@ msgstr ""
"core.splitIndex està establert a cert; elimineu-lo o canvieu-lo, si realment "
"voleu inhabilitar l'índex dividit"
+#: builtin/update-index.c
msgid ""
"core.untrackedCache is set to true; remove or change it, if you really want "
"to disable the untracked cache"
@@ -13327,9 +17172,11 @@ msgstr ""
"core.untrackedCache està establert a cert; elimineu-lo o canvieu-lo, si "
"realment voleu inhabilitar el cau no seguit"
+#: builtin/update-index.c
msgid "Untracked cache disabled"
msgstr "La memòria cau no seguida està inhabilitada"
+#: builtin/update-index.c
msgid ""
"core.untrackedCache is set to false; remove or change it, if you really want "
"to enable the untracked cache"
@@ -13337,96 +17184,124 @@ msgstr ""
"core.untrackedCache està establert a fals; elimineu-lo o canviar-lo, si "
"realment voleu habilitar el cau no seguit"
+#: builtin/update-index.c
#, c-format
msgid "Untracked cache enabled for '%s'"
msgstr "La memòria cau no seguida està habilitada per a «%s»"
+#: builtin/update-index.c
msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
msgstr ""
"core.fsmonitor està establert a fals; establiu-lo a cert si realment voleu "
"habilitar fsmonitor"
+#: builtin/update-index.c
msgid "fsmonitor enabled"
msgstr "fsmonitor habilitat"
+#: builtin/update-index.c
msgid ""
"core.fsmonitor is set; remove it if you really want to disable fsmonitor"
msgstr ""
"core.fsmonitor està establert a cert; elimineu-lo si realment voleu "
"inhabilitar fsmonitor"
+#: builtin/update-index.c
msgid "fsmonitor disabled"
msgstr "fsmonitor inhabilitat"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<opcions>] -d <nom-de-referència> [<valor-antic>]"
+#: builtin/update-ref.c
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<opcions>] -d <nom-referència> [<oid-vell>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr ""
-"git update-ref [<opcions>] <nom-de-referència> <valor-nou> [<valor-antic>]"
+#: builtin/update-ref.c
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<opcions>] <nom-referència> <oid-nou> [<oid-vell>]"
+#: builtin/update-ref.c
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<opcions>] --stdin [-z]"
+#: builtin/update-ref.c
msgid "delete the reference"
msgstr "suprimeix la referència"
+#: builtin/update-ref.c
msgid "update <refname> not the one it points to"
-msgstr "actualitza <nom de referència>, no la que apunti"
+msgstr "actualitza <nom-referència>, no la que apunti"
+#: builtin/update-ref.c
msgid "stdin has NUL-terminated arguments"
msgstr "stdin té arguments acabats amb NUL"
+#: builtin/update-ref.c
msgid "read updates from stdin"
msgstr "llegeix les actualitzacions des de stdin"
+#: builtin/update-server-info.c
msgid "update the info files from scratch"
msgstr "actualitza els fitxers d'informació des de zero"
+#: builtin/upload-pack.c
msgid ""
"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
" [--advertise-refs] <directory>"
msgstr ""
"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
-" [--advertise-refs] <directory>"
+" [--advertise-refs] <directori>"
+#: builtin/upload-pack.c t/helper/test-serve-v2.c
msgid "quit after a single request/response exchange"
msgstr "surt després d'un sol intercanvi de sol·licitud/resposta"
+#: builtin/upload-pack.c
msgid "serve up the info/refs for git-http-backend"
msgstr "serveix les info/refs per a git-http-backend"
+#: builtin/upload-pack.c
msgid "do not try <directory>/.git/ if <directory> is no Git directory"
msgstr ""
"no intentis <directori>/.git/ si <directori> no és cap directori del Git"
+#: builtin/upload-pack.c
msgid "interrupt transfer after <n> seconds of inactivity"
msgstr "interromp la transferència després de <n> segons d'inactivitat"
+#: builtin/verify-commit.c
msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
msgstr "git verify-commit [-v | --verbose] [--raw] <comissió>..."
+#: builtin/verify-commit.c
msgid "print commit contents"
msgstr "imprimeix els continguts de la comissió"
+#: builtin/verify-commit.c builtin/verify-tag.c
msgid "print raw gpg status output"
msgstr "imprimeix la sortida crua de l'estat gpg"
+#: builtin/verify-pack.c
msgid "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
-msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
+msgstr ""
+"git verify-pack [-v | --verbose] [-s | --stat-only] [--] <paquet>.idx..."
+#: builtin/verify-pack.c
msgid "verbose"
msgstr "detallat"
+#: builtin/verify-pack.c
msgid "show statistics only"
msgstr "mostra només estadístiques"
+#: builtin/verify-tag.c
msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
-msgstr "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
+msgstr ""
+"git verify-tag [-v | --verbose] [--format=<format>] [--raw] <etiqueta>..."
+#: builtin/verify-tag.c
msgid "print tag contents"
msgstr "imprimeix els continguts de l'etiqueta"
+#: builtin/worktree.c
msgid ""
"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
" [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
@@ -13434,76 +17309,92 @@ msgstr ""
"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <cadena>]]\n"
" [--orphan] [(-b | -B) <new-branch>] <camí> [<commit-ish>]"
+#: builtin/worktree.c
msgid "git worktree list [-v | --porcelain [-z]]"
msgstr "git worktree list [-v | --porcelain [-z]]"
+#: builtin/worktree.c
msgid "git worktree lock [--reason <string>] <worktree>"
-msgstr "git worktree lock [--reason <string>] <worktree>"
+msgstr "git worktree lock [--reason <cadena>] <arbre-treball>"
+#: builtin/worktree.c
msgid "git worktree move <worktree> <new-path>"
-msgstr "git worktree move <arbre de treball> <camí-nou>"
+msgstr "git worktree move <arbre-treball> <camí-nou>"
+#: builtin/worktree.c
msgid "git worktree prune [-n] [-v] [--expire <expire>]"
msgstr "git worktree prune [-n] [-v] [--expire <expire>]"
+#: builtin/worktree.c
msgid "git worktree remove [-f] <worktree>"
-msgstr "git worktree remove [-f] <worktree>"
+msgstr "git worktree remove [-f] <arbre-treball>"
+#: builtin/worktree.c
msgid "git worktree repair [<path>...]"
msgstr "git worktree repair [<camí>...]"
+#: builtin/worktree.c
msgid "git worktree unlock <worktree>"
-msgstr "git worktree unlock <worktree>"
+msgstr "git worktree unlock <arbre-treball>"
+#: builtin/worktree.c
msgid "No possible source branch, inferring '--orphan'"
msgstr "No hi ha cap branca d'origen possible, inferint «--orphan»"
+#: builtin/worktree.c
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"Si voleu crear un arbre de treball que contingui una branca no nascuda\n"
+"nova (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"
+#: builtin/worktree.c
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"Si voleu crear un arbre de treball que contingui una branca no nascuda\n"
+"nova (branca sense comissions) per a aquest repositori, podeu fer-ho\n"
"utilitzant l'argument --orphan:\n"
"\n"
" git worktree add --orphan %s\n"
+#: builtin/worktree.c
#, c-format
msgid "Removing %s/%s: %s"
msgstr "S'està eliminant %s/%s: %s"
+#: builtin/worktree.c
msgid "report pruned working trees"
msgstr "informa dels arbres de treball podats"
+#: builtin/worktree.c
msgid "expire working trees older than <time>"
msgstr "fes caducar els arbres de treball més antics que <data>"
+#: builtin/worktree.c
#, c-format
msgid "'%s' already exists"
msgstr "«%s» ja existeix"
+#: builtin/worktree.c
#, c-format
msgid "unusable worktree destination '%s'"
msgstr "destinació de l'arbre de treball no utilitzable «%s»"
+#: builtin/worktree.c
#, c-format
msgid ""
"'%s' is a missing but locked worktree;\n"
@@ -13513,6 +17404,7 @@ msgstr ""
"useu «%s -f -f» per a sobreescriure-ho, o «unlock» i «prune» o «remove» per "
"a netejar"
+#: builtin/worktree.c
#, c-format
msgid ""
"'%s' is a missing but already registered worktree;\n"
@@ -13521,50 +17413,66 @@ msgstr ""
"manca «%s» però ja està registrat a l'arbre de treball;\n"
"useu «%s» per a sobreescriure-ho, o «prune» o «remove» per a netejar"
+#: builtin/worktree.c
#, c-format
msgid "failed to copy '%s' to '%s'; sparse-checkout may not work correctly"
msgstr ""
"no s'ha pogut copiar «%s» a «%s»; «sparse-checkout» pot no funcionar "
"correctament"
+#: builtin/worktree.c
#, c-format
msgid "failed to copy worktree config from '%s' to '%s'"
msgstr ""
"no s'ha pogut copiar la configuració de l'arbre de treball de «%s» a «%s»"
+#: builtin/worktree.c
#, c-format
msgid "failed to unset '%s' in '%s'"
msgstr "no s'ha pogut desassignar «%s» a «%s»"
+#: builtin/worktree.c
#, c-format
msgid "could not create directory of '%s'"
msgstr "no s'ha pogut crear directori de «%s»"
+#: builtin/worktree.c
msgid "initializing"
msgstr "s'està inicialitzant"
+#: builtin/worktree.c
+#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "no s'ha pogut trobar l'arbre de treball creat «%s»"
+
+#: builtin/worktree.c
#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "S'està preparant l'arbre de treball (branca nova «%s»)"
+#: builtin/worktree.c
#, c-format
msgid "Preparing worktree (resetting branch '%s'; was at %s)"
msgstr ""
"S'està preparant l'arbre de treball (s'està reiniciant la branca «%s»; "
"estava a %s)"
+#: builtin/worktree.c
#, c-format
msgid "Preparing worktree (checking out '%s')"
msgstr "S'està preparant l'arbre de treball (s'està agafant «%s»)"
+#: builtin/worktree.c
#, c-format
msgid "unreachable: invalid reference: %s"
msgstr "no accessible: referència no vàlida: %s"
+#: builtin/worktree.c
#, c-format
msgid "Preparing worktree (detached HEAD %s)"
msgstr "S'està preparant l'arbre de treball (HEAD %s separat)"
+#: builtin/worktree.c
#, c-format
msgid ""
"HEAD points to an invalid (or orphaned) reference.\n"
@@ -13575,108 +17483,128 @@ msgstr ""
"Camí HEAD: «%s»\n"
"Contingut 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"
+"present, stopping; use 'add -f' to override 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"
+"No hi ha referències locals o remotes malgrat hi existeix almenys un\n"
+"remot, aturada; useu «add -f» per a anul·lar o obtenir primer un remot"
+#: builtin/worktree.c
msgid "checkout <branch> even if already checked out in other worktree"
msgstr "agafa <branca> encara que sigui agafada en altre arbre de treball"
+#: builtin/worktree.c
msgid "create a new branch"
msgstr "crea una branca nova"
+#: builtin/worktree.c
msgid "create or reset a branch"
msgstr "crea o restableix una branca"
-msgid "create unborn/orphaned branch"
-msgstr "crea una branca no nascuda/òrfena"
+#: builtin/worktree.c
+msgid "create unborn branch"
+msgstr "crea una branca no nascuda"
+#: builtin/worktree.c
msgid "populate the new working tree"
msgstr "emplena l'arbre de treball nou"
+#: builtin/worktree.c
msgid "keep the new working tree locked"
msgstr "mantén l'arbre de treball nou bloquejat"
+#: builtin/worktree.c
msgid "reason for locking"
msgstr "raó per a bloquejar"
+#: builtin/worktree.c
msgid "set up tracking mode (see git-branch(1))"
msgstr "configura el mode de seguiment (vegeu git-branch(1))"
+#: builtin/worktree.c
msgid "try to match the new branch name with a remote-tracking branch"
msgstr ""
"prova de fer coincidir el nom de la branca nova amb una branca amb seguiment "
"remot"
+#: builtin/worktree.c diff.c parse-options.c
#, c-format
msgid "options '%s', '%s', and '%s' cannot be used together"
msgstr "les opcions «%s», «%s», i «%s» no es poden usar juntes"
+#: builtin/worktree.c
#, 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 "option '%s' and commit-ish cannot be used together"
+msgstr "opció «%s» i les de comissió no es poden usar juntes"
+#: builtin/worktree.c
msgid "added with --lock"
msgstr "afegit amb --lock"
+#: builtin/worktree.c
msgid "--[no-]track can only be used if a new branch is created"
msgstr "--[no-]track només es pot usar si es crea una branca nova"
+#: builtin/worktree.c
msgid "show extended annotations and reasons, if available"
msgstr "mostra les anotacions esteses i les raons, si estan disponibles"
+#: builtin/worktree.c
msgid "add 'prunable' annotation to worktrees older than <time>"
msgstr ""
"afegeix l'anotació «prunable» als arbres de treball més antics que <data>"
+#: builtin/worktree.c
msgid "terminate records with a NUL character"
msgstr "finalitza els registres amb un caràcter NUL"
+#: builtin/worktree.c
#, c-format
msgid "'%s' is not a working tree"
msgstr "«%s» no és un arbre de treball"
+#: builtin/worktree.c
msgid "The main working tree cannot be locked or unlocked"
msgstr "No es pot bloquejar ni desbloquejar l'arbre de treball principal"
+#: builtin/worktree.c
#, c-format
msgid "'%s' is already locked, reason: %s"
msgstr "«%s» ja està bloquejat, raó: «%s»"
+#: builtin/worktree.c
#, c-format
msgid "'%s' is already locked"
msgstr "«%s» ja està bloquejat"
+#: builtin/worktree.c
#, c-format
msgid "'%s' is not locked"
msgstr "«%s» no està bloquejat"
+#: builtin/worktree.c
msgid "working trees containing submodules cannot be moved or removed"
msgstr ""
"els arbres de treball que contenen submòduls no es poden moure ni eliminar"
+#: builtin/worktree.c
msgid "force move even if worktree is dirty or locked"
msgstr ""
"força el moviment encara que l'arbre de treball estigui brut o bloquejat"
+#: builtin/worktree.c
#, c-format
msgid "'%s' is a main working tree"
msgstr "«%s» és un arbre de treball principal"
+#: builtin/worktree.c
#, c-format
msgid "could not figure out destination name from '%s'"
msgstr "no s'ha pogut deduir el nom de destí des de «%s»"
+#: builtin/worktree.c
#, c-format
msgid ""
"cannot move a locked working tree, lock reason: %s\n"
@@ -13685,6 +17613,7 @@ msgstr ""
"no es pot moure un arbre de treball bloquejat, raó del bloqueig: %s\n"
"useu primer «move -f -f» per a sobreescriure'l o desbloquejar-lo primer"
+#: builtin/worktree.c
msgid ""
"cannot move a locked working tree;\n"
"use 'move -f -f' to override or unlock first"
@@ -13692,31 +17621,38 @@ msgstr ""
"no es pot moure un arbre de treball bloquejat;\n"
"useu primer «move -f -f» per a sobreescriure'l o desbloquejar-lo primer"
+#: builtin/worktree.c
#, c-format
msgid "validation failed, cannot move working tree: %s"
msgstr "la validació ha fallat, no es pot moure l'arbre de treball: %s"
+#: builtin/worktree.c
#, c-format
msgid "failed to move '%s' to '%s'"
msgstr "s'ha produït un error en moure «%s» a «%s»"
+#: builtin/worktree.c
#, c-format
msgid "failed to run 'git status' on '%s'"
msgstr "no s'ha pogut executar «git status» a «%s»"
+#: builtin/worktree.c
#, c-format
msgid "'%s' contains modified or untracked files, use --force to delete it"
msgstr ""
"«%s» conté fitxers modificats o no seguits, useu --force per a suprimir-los"
+#: builtin/worktree.c
#, c-format
msgid "failed to run 'git status' on '%s', code %d"
msgstr "no s'ha pogut executar «git status» a «%s», codi %d"
+#: builtin/worktree.c
msgid "force removal even if worktree is dirty or locked"
msgstr ""
"força l'eliminació encara que l'arbre de treball estigui brut o bloquejat"
+#: builtin/worktree.c
#, c-format
msgid ""
"cannot remove a locked working tree, lock reason: %s\n"
@@ -13725,6 +17661,7 @@ msgstr ""
"no es pot suprimir un arbre de treball bloquejat, raó del bloqueig: %s\n"
"useu primer «remove -f -f» per a sobreescriure'l o desbloquejar-lo"
+#: builtin/worktree.c
msgid ""
"cannot remove a locked working tree;\n"
"use 'remove -f -f' to override or unlock first"
@@ -13732,109 +17669,135 @@ msgstr ""
"no es pot suprimir un arbre de treball bloquejat;\n"
"useu primer «remove -f -f» per a sobreescriure'l o desbloquejar-lo"
+#: builtin/worktree.c
#, c-format
msgid "validation failed, cannot remove working tree: %s"
msgstr "la validació ha fallat, no es pot suprimir l'arbre de treball: %s"
+#: builtin/worktree.c
#, c-format
msgid "repair: %s: %s"
msgstr "repara: %s: %s"
+#: builtin/worktree.c
#, c-format
msgid "error: %s: %s"
msgstr "error: %s: %s"
+#: builtin/write-tree.c
msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
msgstr "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+#: builtin/write-tree.c
msgid "<prefix>/"
msgstr "<prefix>/"
+#: builtin/write-tree.c
msgid "write tree object for a subdirectory <prefix>"
msgstr "escriu l'objecte d'arbre per a un subdirectori <prefix>"
+#: builtin/write-tree.c
msgid "only useful for debugging"
msgstr "només útil per a la depuració"
+#: bulk-checkin.c
msgid "core.fsyncMethod = batch is unsupported on this platform"
msgstr "core.fsyncMethod = batch no és compatible amb aquesta plataforma"
+#: bundle-uri.c
#, c-format
msgid "could not parse bundle list key %s with value '%s'"
msgstr ""
"no s'ha pogut analitzar la clau de llista de paquets %s amb el valor «%s»"
+#: bundle-uri.c
#, c-format
msgid "bundle list at '%s' has no mode"
msgstr "la llista de farcells a «%s» no té mode"
+#: bundle-uri.c
msgid "failed to create temporary file"
msgstr "no s'ha pogut crear un fitxer temporal"
+#: bundle-uri.c
msgid "insufficient capabilities"
msgstr "capacitats insuficients"
+#: bundle-uri.c
#, c-format
msgid "file downloaded from '%s' is not a bundle"
msgstr "el fitxer baixat de «%s» no és un paquet"
+#: bundle-uri.c
msgid "failed to store maximum creation token"
msgstr "no s'ha pogut emmagatzemar el testimoni de creació màxim"
+#: bundle-uri.c
#, c-format
msgid "unrecognized bundle mode from URI '%s'"
msgstr "no s'ha reconegut el model del farcell de l'URI «%s»"
+#: bundle-uri.c
#, c-format
msgid "exceeded bundle URI recursion limit (%d)"
msgstr "s'ha excedit el límit de recursió URI del paquet (%d)"
+#: bundle-uri.c
#, c-format
msgid "failed to download bundle from URI '%s'"
msgstr "no s'ha pogut baixar el paquet de l'URI «%s»"
+#: bundle-uri.c
#, c-format
msgid "file at URI '%s' is not a bundle or bundle list"
msgstr "el fitxer a l'URI «%s» no és farcell o una llista de farcells"
+#: bundle-uri.c
#, c-format
msgid "bundle-uri: unexpected argument: '%s'"
msgstr "bundle-uri: argument inesperat: «%s»"
+#: bundle-uri.c
msgid "bundle-uri: expected flush after arguments"
msgstr "bundle-uri: s'esperava una neteja després dels arguments"
+#: bundle-uri.c
msgid "bundle-uri: got an empty line"
msgstr "bundle-uri: té una línia buida"
+#: bundle-uri.c
msgid "bundle-uri: line is not of the form 'key=value'"
msgstr "bundle-uri: la línia no és de la forma «key=value»"
+#: bundle-uri.c
msgid "bundle-uri: line has empty key or value"
msgstr "bundle-uri: la línia té una clau o un valor buit"
+#: bundle.c
#, c-format
msgid "unrecognized bundle hash algorithm: %s"
msgstr "algoritme de resum del farcell desconegut: %s"
+#: bundle.c
#, c-format
msgid "unknown capability '%s'"
msgstr "funcionalitat «%s» desconeguda"
+#: bundle.c
#, c-format
msgid "'%s' does not look like a v2 or v3 bundle file"
msgstr "«%s» no sembla un fitxer de farcell v2 o v3"
+#: bundle.c
#, c-format
msgid "unrecognized header: %s%s (%d)"
msgstr "capçalera no reconeguda: %s%s (%d)"
+#: bundle.c
msgid "Repository lacks these prerequisite commits:"
msgstr "Al repositori li manquen aquestes comissions prerequerides:"
-msgid "need a repository to verify a bundle"
-msgstr "cal un repositori per a verificar un farcell"
-
+#: bundle.c
msgid ""
"some prerequisite commits exist in the object store, but are not connected "
"to the repository's history"
@@ -13842,730 +17805,1050 @@ msgstr ""
"hi ha algunes comissions requerides al magatzem d'objectes, però no estan "
"connectades a l'historial del repositori"
+#: bundle.c
#, c-format
msgid "The bundle contains this ref:"
msgid_plural "The bundle contains these %<PRIuMAX> refs:"
msgstr[0] "El farcell conté aquesta referència:"
msgstr[1] "El farcell conté aquestes %<PRIuMAX> referències:"
+#: bundle.c
msgid "The bundle records a complete history."
msgstr "El farcell registra una història completa."
+#: bundle.c
#, c-format
msgid "The bundle requires this ref:"
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:"
+#: bundle.c
#, c-format
msgid "The bundle uses this hash algorithm: %s"
msgstr "El farcell utilitza aquest algoritme de resum: %s"
+#: bundle.c
#, c-format
msgid "The bundle uses this filter: %s"
msgstr "El farcell utilitza aquest filtre: %s"
+#: bundle.c
msgid "unable to dup bundle descriptor"
msgstr "no s'ha pogut duplicar el descriptor del farcell"
+#: bundle.c
msgid "Could not spawn pack-objects"
msgstr "No s'ha pogut engendrar el pack-objects"
+#: bundle.c
msgid "pack-objects died"
msgstr "el pack-objects s'ha mort"
+#: bundle.c
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "les opcions de la llista de revisions exclouen la referència «%s»"
+#: bundle.c
#, c-format
msgid "unsupported bundle version %d"
msgstr "versió del farcell no compatible %d"
+#: bundle.c
#, c-format
msgid "cannot write bundle version %d with algorithm %s"
msgstr "no es pot escriure la versió del farcell %d amb l'algorisme %s"
+#: bundle.c
msgid "Refusing to create empty bundle."
msgstr "S'està refusant crear un farcell buit."
+#: bundle.c
#, c-format
msgid "cannot create '%s'"
msgstr "no es pot crear «%s»"
+#: bundle.c
msgid "index-pack died"
msgstr "l'index-pack s'ha mort"
+#: chunk-format.c
msgid "terminating chunk id appears earlier than expected"
msgstr ""
"l'identificador de fragment de finalització apareix abans del que s'esperava"
+#: chunk-format.c
+#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "ID del fragment %<PRIx32> no alineat a %d-octets"
+
+#: chunk-format.c
#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "desplaçament incorrecte del fragment %<PRIx64> i %<PRIx64>"
+#: chunk-format.c
#, c-format
msgid "duplicate chunk ID %<PRIx32> found"
msgstr "s'ha trobat un ID del fragment %<PRIx32> duplicat"
+#: chunk-format.c
#, c-format
msgid "final chunk has non-zero id %<PRIx32>"
msgstr "el fragment final té un id %<PRIx32> que no és zero"
+#: chunk-format.c
msgid "invalid hash version"
msgstr "especificació de resum no vàlida"
+#: color.c
#, c-format
msgid "invalid color value: %.*s"
msgstr "valor de color no vàlid: %.*s"
+#: command-list.h
msgid "Add file contents to the index"
msgstr "Afegeix els continguts dels fitxers a l'índex"
+#: command-list.h
msgid "Apply a series of patches from a mailbox"
msgstr "Aplica una sèrie de pedaços des d'una bústia de correu"
+#: command-list.h
msgid "Annotate file lines with commit information"
msgstr "Anota les línies del fitxer amb la informació de la comissió"
+#: command-list.h
msgid "Apply a patch to files and/or to the index"
msgstr "Aplica un pedaç a fitxer i/o a l'índex"
+#: command-list.h
msgid "Import a GNU Arch repository into Git"
msgstr "Importa un repositori GNU Arch a Git"
+#: command-list.h
msgid "Create an archive of files from a named tree"
msgstr "Crea un arxiu de fitxers des d'un arbre amb nom"
+#: command-list.h
msgid "Use binary search to find the commit that introduced a bug"
msgstr "Troba per cerca binària el canvi que hagi introduït un defecte"
+#: command-list.h
msgid "Show what revision and author last modified each line of a file"
msgstr ""
"Mostra quina revisió i autor ha modificat per últim cop cada línia d'un "
"fitxer"
+#: command-list.h
msgid "List, create, or delete branches"
msgstr "Llista, crea o suprimeix branques"
+#: command-list.h
msgid "Collect information for user to file a bug report"
msgstr "Recopila la informació per a l'usuari per a enviar un informe d'error"
+#: command-list.h
msgid "Move objects and refs by archive"
msgstr "Mou els objectes i les referències per arxiu"
-msgid "Provide content or type and size information for repository objects"
-msgstr ""
-"Proveeix contingut o informació del tipus i mida per als objectes del "
-"repositori"
+#: command-list.h
+msgid "Provide contents or details of repository objects"
+msgstr "Proporcioneu el contingut o els detalls dels objectes del repositori"
+#: command-list.h
msgid "Display gitattributes information"
msgstr "Mostra la informació de .gitattributes"
+#: command-list.h
msgid "Debug gitignore / exclude files"
msgstr "Depura gitignore / fitxers d'exclusió"
+#: command-list.h
msgid "Show canonical names and email addresses of contacts"
msgstr "Mostra els noms canònics i les adreces electròniques dels contactes"
+#: command-list.h
msgid "Ensures that a reference name is well formed"
msgstr "Assegura que un nom de referència està ben format"
+#: command-list.h
msgid "Switch branches or restore working tree files"
msgstr "Canvia de branca o restaura els fitxers de l'arbre de treball"
+#: command-list.h
msgid "Copy files from the index to the working tree"
msgstr "Copia fitxers des de l'índex a l'arbre de treball"
+#: command-list.h
msgid "Find commits yet to be applied to upstream"
msgstr "Troba les comissions que encara s'han d'aplicar a la font"
+#: command-list.h
msgid "Apply the changes introduced by some existing commits"
msgstr "Aplica els canvis introduïts per algunes comissions existents"
+#: command-list.h
msgid "Graphical alternative to git-commit"
msgstr "Alternativa gràfica a git-commit"
+#: command-list.h
msgid "Remove untracked files from the working tree"
msgstr "Elimina els fitxers no seguits de l'arbre de treball"
+#: command-list.h
msgid "Clone a repository into a new directory"
msgstr "Clona un repositori a un directori nou"
+#: command-list.h
msgid "Display data in columns"
msgstr "Mostra les dades en columnes"
+#: command-list.h
msgid "Record changes to the repository"
msgstr "Registra els canvis al repositori"
+#: command-list.h
msgid "Write and verify Git commit-graph files"
msgstr "Escriu i verifica els fitxers commit-graph de Git"
+#: command-list.h
msgid "Create a new commit object"
msgstr "Crea un objecte de comissió nou"
+#: command-list.h
msgid "Get and set repository or global options"
msgstr "Obté o estableix opcions de repositori o globals"
+#: command-list.h
msgid "Count unpacked number of objects and their disk consumption"
msgstr "Compta el nombre d'objectes desempaquetats i el seu consum de disc"
+#: command-list.h
msgid "Retrieve and store user credentials"
msgstr "Recupera i desa les credencials d'usuari"
+#: command-list.h
msgid "Helper to temporarily store passwords in memory"
msgstr "Ajudant per a emmagatzemar temporalment les contrasenyes en memòria"
+#: command-list.h
msgid "Helper to store credentials on disk"
msgstr "Ajudant per a emmagatzemar credencials a disc"
+#: command-list.h
msgid "Export a single commit to a CVS checkout"
msgstr "Exporta en una sola comissió a CVS checkout"
+#: command-list.h
msgid "Salvage your data out of another SCM people love to hate"
msgstr "Salveu les vostres dades d'un altre SMC al que la gent li agrada odiar"
+#: command-list.h
msgid "A CVS server emulator for Git"
msgstr "Un emulador de servidor CVS per al Git"
+#: command-list.h
msgid "A really simple server for Git repositories"
msgstr "Un servidor realment senzill per a repositoris Git"
+#: command-list.h
msgid "Give an object a human readable name based on an available ref"
msgstr ""
"Dona un nom llegible per a humans basant-se en les referències disponibles"
+#: command-list.h
msgid "Generate a zip archive of diagnostic information"
msgstr "Genera un arxiu zip d'informació de diagnòstic"
+#: command-list.h
msgid "Show changes between commits, commit and working tree, etc"
msgstr ""
"Mostra els canvis entre comissions, la comissió i l'arbre de treball, etc"
+#: command-list.h
msgid "Compares files in the working tree and the index"
msgstr "Compara fitxers en l'arbre de treball i l'índex"
+#: command-list.h
msgid "Compare a tree to the working tree or index"
msgstr "Compara un arbre amb l'arbre de treball o l'índex"
+#: command-list.h
msgid "Compares the content and mode of blobs found via two tree objects"
msgstr ""
"Compara el contingut i el mode dels blobs trobats a través de dos objectes "
"d'arbre"
+#: command-list.h
msgid "Show changes using common diff tools"
msgstr "Mostra els canvis usant eines diff comunes"
+#: command-list.h
msgid "Git data exporter"
msgstr "Exportador de dades del Git"
+#: command-list.h
msgid "Backend for fast Git data importers"
msgstr "Rerefons per a importadors ràpids de dades de Git"
+#: command-list.h
msgid "Download objects and refs from another repository"
msgstr "Baixa objectes i referències d'un altre repositori"
+#: command-list.h
msgid "Receive missing objects from another repository"
msgstr "Rep els objectes que manquen des d'un altre repositori"
+#: command-list.h
msgid "Rewrite branches"
msgstr "Torna a escriure les branques"
+#: command-list.h
msgid "Produce a merge commit message"
msgstr "Produeix un missatge de comissió de fusió"
+#: command-list.h
msgid "Output information on each ref"
msgstr "Mostra la informació en cada referència"
+#: command-list.h
msgid "Run a Git command on a list of repositories"
msgstr "Executa una ordre Git en una llista de repositoris"
+#: command-list.h
msgid "Prepare patches for e-mail submission"
msgstr "Prepara pedaços per a enviar-los per correu electrònic"
+#: command-list.h
msgid "Verifies the connectivity and validity of the objects in the database"
msgstr "Verifica la connectivitat i validesa dels objectes a la base de dades"
+#: command-list.h
msgid "Cleanup unnecessary files and optimize the local repository"
msgstr "Neteja els fitxers innecessaris i optimitza el repositori local"
+#: command-list.h
msgid "Extract commit ID from an archive created using git-archive"
msgstr "Extreu l'ID de la comissió d'un arxiu creat amb el git-archive"
+#: command-list.h
msgid "Print lines matching a pattern"
msgstr "Imprimeix les línies coincidents amb un patró"
+#: command-list.h
msgid "A portable graphical interface to Git"
msgstr "Una interfície gràfica portable per al Git"
+#: command-list.h
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"
+#: command-list.h
msgid "Display help information about Git"
msgstr "Mostra informació d'ajuda del Git"
+#: command-list.h
msgid "Run git hooks"
msgstr "Executa els lligams del git"
+#: command-list.h
msgid "Server side implementation of Git over HTTP"
msgstr "Implementació al servidor del Git sobre HTTP"
+#: command-list.h
msgid "Download from a remote Git repository via HTTP"
msgstr "Baixa des d'un repositori Git remot via HTTP"
+#: command-list.h
msgid "Push objects over HTTP/DAV to another repository"
msgstr "Pujar objectes sobre HTTP/DAV a un altre repositori"
+#: command-list.h
msgid "Send a collection of patches from stdin to an IMAP folder"
msgstr ""
"Envia una col·lecció de pedaços des de l'entrada estàndard a una carpeta IMAP"
+#: command-list.h
msgid "Build pack index file for an existing packed archive"
msgstr ""
"Construeix el fitxer d'índex del paquet per a un arxiu empaquetat existent"
+#: command-list.h
msgid "Create an empty Git repository or reinitialize an existing one"
msgstr "Crea un repositori de Git buit o reinicialitza un existent"
+#: command-list.h
msgid "Instantly browse your working repository in gitweb"
msgstr "Navegueu instantàniament pel vostre repositori de treball a gitweb"
+#: command-list.h
msgid "Add or parse structured information in commit messages"
msgstr ""
"Afegeix o analitza la informació estructurada en els missatges de comissió"
+#: command-list.h
msgid "Show commit logs"
msgstr "Mostra els registres de comissió"
+#: command-list.h
msgid "Show information about files in the index and the working tree"
msgstr "Mostra informació sobre els fitxers a l'índex i a l'arbre de treball"
+#: command-list.h
msgid "List references in a remote repository"
msgstr "Mostra les referències d'un repositori remot"
+#: command-list.h
msgid "List the contents of a tree object"
msgstr "Mostra els continguts d'un objecte de l'arbre"
+#: command-list.h
msgid "Extracts patch and authorship from a single e-mail message"
msgstr "Extreu el pedaç i l'autoria d'un sol missatge de correu electrònic"
+#: command-list.h
msgid "Simple UNIX mbox splitter program"
msgstr "Programa de divisió mbox simple per a UNIX"
+#: command-list.h
msgid "Run tasks to optimize Git repository data"
msgstr "Executa tasques per a optimitzar les dades del repositori Git"
+#: command-list.h
msgid "Join two or more development histories together"
msgstr "Uneix dues o més històries de desenvolupament"
+#: command-list.h
msgid "Find as good common ancestors as possible for a merge"
msgstr "Troba els millors avantpassats comuns possibles per a una fusió"
+#: command-list.h
msgid "Run a three-way file merge"
msgstr "Executa una fusió de fitxers de tres vies"
+#: command-list.h
msgid "Run a merge for files needing merging"
msgstr "Executa una fusió per als fitxers que cal fusionar"
+#: command-list.h
msgid "The standard helper program to use with git-merge-index"
msgstr "El programa d'ajuda estàndard a utilitzar amb git-merge-index"
+#: command-list.h
msgid "Perform merge without touching index or working tree"
msgstr "Realitza la fusió sense tocar l'índex o l'arbre de treball"
+#: command-list.h
msgid "Run merge conflict resolution tools to resolve merge conflicts"
msgstr ""
"Executa eines de resolució de conflictes per a resoldre conflictes de fusió"
+#: command-list.h
msgid "Creates a tag object with extra validation"
msgstr "Crea un objecte etiqueta amb validació addicional"
+#: command-list.h
msgid "Build a tree-object from ls-tree formatted text"
msgstr "Construeix un objecte en arbre a partir de text formatat amb ls-tree"
+#: command-list.h
msgid "Write and verify multi-pack-indexes"
-msgstr "Escriu i verifica els índexs dels paquets multipaquet"
+msgstr "Escriu i verifica els índexs multipaquet"
+#: command-list.h
msgid "Move or rename a file, a directory, or a symlink"
msgstr "Mou o canvia de nom a un fitxer, directori o enllaç simbòlic"
+#: command-list.h
msgid "Find symbolic names for given revs"
msgstr "Cerca noms simbòlics per a les revisions donades"
+#: command-list.h
msgid "Add or inspect object notes"
msgstr "Afegeix o inspecciona notes de l'objecte"
+#: command-list.h
msgid "Import from and submit to Perforce repositories"
msgstr "Importa des de i envia a repositoris Perforce"
+#: command-list.h
msgid "Create a packed archive of objects"
msgstr "Crea un arxiu empaquetat d'objectes"
+#: command-list.h
msgid "Find redundant pack files"
msgstr "Troba fitxers empaquetats redundants"
+#: command-list.h
msgid "Pack heads and tags for efficient repository access"
msgstr ""
"Empaqueta els caps i les etiquetes per a un accés eficient al repositori"
+#: command-list.h
msgid "Compute unique ID for a patch"
msgstr "Calcula un identificador únic per a cada pedaç"
+#: command-list.h
msgid "Prune all unreachable objects from the object database"
msgstr "Poda tots els objectes no accessibles de la base de dades d'objectes"
+#: command-list.h
msgid "Remove extra objects that are already in pack files"
msgstr "Elimina els objectes extres que ja estan en fitxers empaquetats"
+#: command-list.h
msgid "Fetch from and integrate with another repository or a local branch"
msgstr "Obtén i integra amb un altre repositori o una branca local"
+#: command-list.h
msgid "Update remote refs along with associated objects"
msgstr ""
"Actualitza les referències remotes juntament amb els objectes associats"
+#: command-list.h
msgid "Applies a quilt patchset onto the current branch"
msgstr "Aplica un conjunt de pedaços a la branca actual"
+#: command-list.h
msgid "Compare two commit ranges (e.g. two versions of a branch)"
msgstr "Compara dos rangs de comissions (p. ex. dues versions d'una branca)"
+#: command-list.h
msgid "Reads tree information into the index"
msgstr "Llegeix la informació de l'arbre a l'índex"
+#: command-list.h
msgid "Reapply commits on top of another base tip"
msgstr "Torna a aplicar les comissions sobre un altre punt de basament"
+#: command-list.h
msgid "Receive what is pushed into the repository"
msgstr "Rep el que s'envia al repositori"
+#: command-list.h
msgid "Manage reflog information"
msgstr "Gestiona la informació del registre de referències"
+# Baix nivell / nivell baix
+#: command-list.h
+msgid "Low-level access to refs"
+msgstr "Accés de baix nivell a referències"
+
+#: command-list.h
msgid "Manage set of tracked repositories"
msgstr "Gestiona el conjunt de repositoris seguits"
+#: command-list.h
msgid "Pack unpacked objects in a repository"
msgstr "Empaqueta els objectes desempaquetats en un repositori"
+#: command-list.h
msgid "Create, list, delete refs to replace objects"
msgstr "Crea, llista i esborra referències per a substituir objectes"
+#: command-list.h
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"EXPERIMENTAL: torna a reproduir comissions sobre una nova base, també "
+"funciona amb repositoris nus"
+
+#: command-list.h
msgid "Generates a summary of pending changes"
msgstr "Genera un resum dels canvis pendents"
+#: command-list.h
msgid "Reuse recorded resolution of conflicted merges"
msgstr "Reutilitza la resolució registrada dels conflictes de fusió"
+#: command-list.h
msgid "Reset current HEAD to the specified state"
msgstr "Restableix la HEAD actual a l'estat especificat"
+#: command-list.h
msgid "Restore working tree files"
msgstr "Restaura els fitxers de l'arbre de treball"
+#: command-list.h
msgid "Lists commit objects in reverse chronological order"
msgstr "Mostra les comissions en ordre topològic invers"
+#: command-list.h
msgid "Pick out and massage parameters"
msgstr "Trieu i personalitzeu els paràmetres"
+#: command-list.h
msgid "Revert some existing commits"
msgstr "Reverteix comissions existents"
+#: command-list.h
msgid "Remove files from the working tree and from the index"
msgstr "Elimina fitxers de l'arbre de treball i de l'índex"
+#: command-list.h
msgid "Send a collection of patches as emails"
msgstr "Envia una col·lecció de pedaços com a correus electrònics"
+#: command-list.h
msgid "Push objects over Git protocol to another repository"
msgstr "Puja objectes sobre el protocol Git a un altre repositori"
+#: command-list.h
msgid "Git's i18n setup code for shell scripts"
msgstr ""
"Codi de configuració i18n del Git per als scripts de l'intèrpret d'ordres"
+#: command-list.h
msgid "Common Git shell script setup code"
msgstr "Codi de scripts de configuració comuns pel Git shell"
+#: command-list.h
msgid "Restricted login shell for Git-only SSH access"
msgstr "Intèrpret d'ordres d'entrada restringit només per a accés SSH al Git"
+#: command-list.h
msgid "Summarize 'git log' output"
msgstr "Resumeix la sortida «git log»"
+#: command-list.h
msgid "Show various types of objects"
msgstr "Mostra diversos tipus d'objectes"
+#: command-list.h
msgid "Show branches and their commits"
msgstr "Mostra les branques i les seves comissions"
+#: command-list.h
msgid "Show packed archive index"
msgstr "Mostra l'índex d'arxius empaquetat"
+#: command-list.h
msgid "List references in a local repository"
msgstr "Llista les referències en un repositori local"
+#: command-list.h
msgid "Reduce your working tree to a subset of tracked files"
msgstr "Redueix l'arbre de treball a un subconjunt de fitxers seguits"
+#: command-list.h
msgid "Add file contents to the staging area"
msgstr "Afegeix el contingut del fitxer a l'àrea de «staging»"
+#: command-list.h
msgid "Stash the changes in a dirty working directory away"
msgstr "Fes «stash» dels canvis en un directori de treball brut"
+#: command-list.h
msgid "Show the working tree status"
msgstr "Mostra l'estat de l'arbre de treball"
+#: command-list.h
msgid "Remove unnecessary whitespace"
msgstr "Elimina l'espai en blanc innecessari"
+#: command-list.h
msgid "Initialize, update or inspect submodules"
msgstr "Inicialitza, actualitza o inspecciona submòduls"
+#: command-list.h
msgid "Bidirectional operation between a Subversion repository and Git"
msgstr "Operació bidireccional entre un repositori a Subversion i Git"
+#: command-list.h
msgid "Switch branches"
msgstr "Commuta entre branques"
+#: command-list.h
msgid "Read, modify and delete symbolic refs"
msgstr "Llegeix, modifica i suprimeix referències simbòliques"
+#: command-list.h
msgid "Create, list, delete or verify a tag object signed with GPG"
msgstr ""
"Crea, llista, suprimeix o verifica un objecte d'etiqueta signat amb GPG"
+#: command-list.h
msgid "Creates a temporary file with a blob's contents"
msgstr "Crea un fitxer temporal amb els continguts dels blobs"
+#: command-list.h
msgid "Unpack objects from a packed archive"
msgstr "Desempaqueta objectes d'un arxiu empaquetat"
+#: command-list.h
msgid "Register file contents in the working tree to the index"
msgstr "Registra els continguts del fitxer en l'arbre de treball a l'índex"
+#: command-list.h
msgid "Update the object name stored in a ref safely"
msgstr ""
"Actualitza el nom de l'objecte emmagatzemat en una referència de forma segura"
+#: command-list.h
msgid "Update auxiliary info file to help dumb servers"
msgstr ""
"Actualitza el fitxer d'informació auxiliar per a ajudar als servidors ximples"
+#: command-list.h
msgid "Send archive back to git-archive"
msgstr "Envia l'arxiu de tornada al git-archive"
+#: command-list.h
msgid "Send objects packed back to git-fetch-pack"
msgstr "Envia els objectes empaquetats de tornada al git-fetch-pack"
+#: command-list.h
msgid "Show a Git logical variable"
msgstr "Mostra una variable lògica del Git"
+#: command-list.h
msgid "Check the GPG signature of commits"
msgstr "Verifica la signatura GPG de les comissions"
+#: command-list.h
msgid "Validate packed Git archive files"
msgstr "Valida els fitxers d'arxius Git empaquetats"
+#: command-list.h
msgid "Check the GPG signature of tags"
msgstr "Verifica la signatura GPG de les etiquetes"
+#: command-list.h
msgid "Display version information about Git"
msgstr "Mostra informació de la versió del Git"
-msgid "Show logs with difference each commit introduces"
-msgstr "Mostra registres amb la diferència introduïda per cada comissió"
+#: command-list.h
+msgid "Show logs with differences each commit introduces"
+msgstr "Mostra els registres amb les diferències que introdueix cada comissió"
+#: command-list.h
msgid "Manage multiple working trees"
msgstr "Gestiona múltiples arbres de treball"
+#: command-list.h
msgid "Create a tree object from the current index"
msgstr "Crea un objecte arbre des de l'índex actual"
+#: command-list.h
msgid "Defining attributes per path"
msgstr "La definició d'atributs per camí"
+#: command-list.h
msgid "Git command-line interface and conventions"
msgstr "Interfície i convencions de la línia d'ordres del Git"
+#: command-list.h
msgid "A Git core tutorial for developers"
msgstr "Un tutorial bàsic del Git per a desenvolupadors"
+#: command-list.h
msgid "Providing usernames and passwords to Git"
msgstr "Proporcionar noms d'usuari i contrasenyes a Git"
+#: command-list.h
msgid "Git for CVS users"
msgstr "Git per a usuaris del CVS"
+#: command-list.h
msgid "Tweaking diff output"
msgstr "Ajustament de la sortida de diferències"
+#: command-list.h
msgid "A useful minimum set of commands for Everyday Git"
msgstr "Un conjunt mínim útil d'ordres diàries del Git"
+#: command-list.h
msgid "Frequently asked questions about using Git"
msgstr "Preguntes freqüents sobre l'ús del Git"
+#: command-list.h
msgid "The bundle file format"
msgstr "El format del fitxer de farcell"
+#: command-list.h
msgid "Chunk-based file formats"
msgstr "Formats de fitxer basats en blocs"
+#: command-list.h
msgid "Git commit-graph format"
msgstr "Format de graf de comissions del Git"
+#: command-list.h
msgid "Git index format"
msgstr "Format de l'índex del Git"
+#: command-list.h
msgid "Git pack format"
msgstr "format de paquet del Git"
+#: command-list.h
msgid "Git cryptographic signature formats"
msgstr "Formats de signatura criptogràfica del Git"
+#: command-list.h
msgid "A Git Glossary"
msgstr "Un glossari de Git"
+#: command-list.h
msgid "Hooks used by Git"
msgstr "Lligams utilitzats pel Git"
+#: command-list.h
msgid "Specifies intentionally untracked files to ignore"
msgstr "Especifica els fitxers intencionalment no seguits a ignorar"
+#: command-list.h
msgid "The Git repository browser"
msgstr "El navegador de repositoris Git"
+#: command-list.h
msgid "Map author/committer names and/or E-Mail addresses"
msgstr "Assigna noms d'autor i comitent i/o adreces de correu electrònic"
+#: command-list.h
msgid "Defining submodule properties"
msgstr "La definició de les propietats de submòduls"
+#: command-list.h
msgid "Git namespaces"
msgstr "Espais de noms del Git"
+#: command-list.h
msgid "Protocol v0 and v1 capabilities"
msgstr "Capacitats de protocol v0 i v1"
+#: command-list.h
msgid "Things common to various protocols"
msgstr "Coses comunes en diversos protocols"
+#: command-list.h
msgid "Git HTTP-based protocols"
msgstr "Protocols basats en HTTP del Git"
+#: command-list.h
msgid "How packs are transferred over-the-wire"
msgstr "Com es transfereixen els paquets en la xarxa"
+#: command-list.h
msgid "Git Wire Protocol, Version 2"
msgstr "Protocol Git Wire, versió 2"
+#: command-list.h
msgid "Helper programs to interact with remote repositories"
msgstr "Programes d'ajuda per a interactuar amb repositoris remots"
+#: command-list.h
msgid "Git Repository Layout"
msgstr "Disposició del repositori del Git"
+#: command-list.h
msgid "Specifying revisions and ranges for Git"
msgstr "L'especificació de revisions i rangs per al Git"
+#: command-list.h
msgid "Mounting one repository inside another"
msgstr "Muntant un repositori dins un altre"
+#: command-list.h
msgid "A tutorial introduction to Git"
msgstr "Un tutorial d'introducció al Git"
+#: command-list.h
msgid "A tutorial introduction to Git: part two"
msgstr "Un tutorial d'introducció al Git: segona part"
+#: command-list.h
msgid "Git web interface (web frontend to Git repositories)"
msgstr "Interfície web del Git (interfície web pels repositoris Git)"
+#: command-list.h
msgid "An overview of recommended workflows with Git"
msgstr "Una visió de conjunt de fluxos de treball recomanats amb Git"
+#: command-list.h
msgid "A tool for managing large Git repositories"
msgstr "Una eina per a gestionar dipòsits Git grans"
+#: commit-graph.c
msgid "commit-graph file is too small"
msgstr "el fitxer del graf de comissions és massa petit"
+#: commit-graph.c
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr ""
+"el fragment de «fanout» de l'oid del graf de comissions és de mida incorrecta"
+
+#: commit-graph.c
+msgid "commit-graph fanout values out of order"
+msgstr "valors de graf de comissions de «fanout» estan fora d'ordre"
+
+#: commit-graph.c
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "el fragment de cerca OID és de mida incorrecta"
+
+#: commit-graph.c
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "el fragment de dades del graf de comissions és de mida incorrecta"
+
+#: commit-graph.c
+msgid "commit-graph generations chunk is wrong size"
+msgstr ""
+"el fragment de les generacions del graf de comissions és de mida incorrecta"
+
+#: commit-graph.c
+msgid "commit-graph changed-path index chunk is too small"
+msgstr ""
+"el fragment d'índex del canvi del camí del graf de comissions és massa petit"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"s'ignorarà un fragment massa petit de camí canviat (%<PRIuMAX> < %<PRIuMAX>) "
+"al fitxer del graf de comissions"
+
+#: commit-graph.c
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr ""
"la signatura del graf de comissions %X no coincideix amb la signatura %X"
+#: commit-graph.c
#, c-format
msgid "commit-graph version %X does not match version %X"
msgstr "la versió del graf de comissions %X no coincideix amb la versió %X"
+#: commit-graph.c
#, c-format
msgid "commit-graph hash version %X does not match version %X"
msgstr ""
"la versió del resum del graf de comissions %X no coincideix amb la versió %X"
+#: commit-graph.c
#, c-format
msgid "commit-graph file is too small to hold %u chunks"
msgstr ""
"el fitxer del graf de comissions és massa petit per a guardar %u fragments"
+#: commit-graph.c
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr ""
+"manca o està malmès el fragment del «fanout» OID requerit al graf de "
+"comissions"
+
+#: commit-graph.c
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr ""
+"manca o està malmès el fragment de cerca d'OID requerit al graf de comissions"
+
+#: commit-graph.c
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr ""
+"manca o està corromput el fragment de dades de publicació requerit al graf "
+"de comissions"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"s'han inhabilitat els filtres de Bloom per a la capa del graf de comissions "
+"«%s»\n"
+"perquè els paràmetres són incompatibles"
+
+#: commit-graph.c
msgid "commit-graph has no base graphs chunk"
msgstr "el fragment del graf de comissions no té grafs de base"
+#: commit-graph.c
+msgid "commit-graph base graphs chunk is too small"
+msgstr "el fragment de grafs base de la gràfica de comissió és massa petit"
+
+#: commit-graph.c
msgid "commit-graph chain does not match"
msgstr "la cadena del graf de comissions no coincideix"
+#: commit-graph.c
#, c-format
msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "el nombre de comissions en el graf base és massa alt: %<PRIuMAX>"
+#: commit-graph.c
+msgid "commit-graph chain file too small"
+msgstr "el fitxer de cadena del graf de comissions és massa petit"
+
+#: commit-graph.c
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr ""
"la cadena del graf de comissions no és vàlida: la línia «%s» no és un hash"
+#: commit-graph.c
msgid "unable to find all commit-graph files"
msgstr "no es poden trobar tots els fitxers del graf de comissions"
+#: commit-graph.c
msgid "invalid commit position. commit-graph is likely corrupt"
msgstr ""
"posició de la comissió no vàlida. Probablement el graf de comissions està "
"malmès"
+#: commit-graph.c
#, c-format
msgid "could not find commit %s"
msgstr "no s'ha pogut trobar la comissió %s"
+#: commit-graph.c
msgid "commit-graph requires overflow generation data but has none"
msgstr ""
"el graf de comissions requereix dades de generació de desbordaments però no "
"en té cap"
+#: commit-graph.c
+msgid "commit-graph overflow generation data is too small"
+msgstr ""
+"les dades de generació de desbordament del graf de comissions són massa "
+"petites"
+
+#: commit-graph.c
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "punter de vores extra del graf de comissió està fora dels límits"
+
+#: commit-graph.c
msgid "Loading known commits in commit graph"
msgstr "S'estan carregant comissions conegudes al graf de comissions"
+#: commit-graph.c
msgid "Expanding reachable commits in commit graph"
msgstr "S'estan expandint les comissions abastables al graf de comissions"
+#: commit-graph.c
msgid "Clearing commit marks in commit graph"
msgstr "S'estan esborrant les marques de comissions al graf de comissions"
+#: commit-graph.c
msgid "Computing commit graph topological levels"
msgstr "S'estan calculant els nivells topològics del graf de comissions"
+#: commit-graph.c
msgid "Computing commit graph generation numbers"
msgstr "S'estan calculant els nombres de generació del graf de comissions"
+#: commit-graph.c
msgid "Computing commit changed paths Bloom filters"
msgstr ""
-"S'estan calculant els canvis les rutes de la comissió en els filtres Bloom"
+"S'estan calculant els canvis les rutes de la comissió en els filtres de Bloom"
+#: commit-graph.c
msgid "Collecting referenced commits"
msgstr "S'estan recollint els objectes referenciats"
+#: commit-graph.c
#, c-format
msgid "Finding commits for commit graph in %<PRIuMAX> pack"
msgid_plural "Finding commits for commit graph in %<PRIuMAX> packs"
@@ -14574,149 +18857,189 @@ msgstr[0] ""
msgstr[1] ""
"S'estan cercant les comissions pel graf de comissions en %<PRIuMAX> paquets"
+#: commit-graph.c
#, c-format
msgid "error adding pack %s"
msgstr "error en afegir paquet %s"
+#: commit-graph.c
#, c-format
msgid "error opening index for %s"
msgstr "s'ha produït un error en obrir l'índex per «%s»"
+#: commit-graph.c
msgid "Finding commits for commit graph among packed objects"
msgstr ""
"S'estan cercant les comissions pel graf de comissions entre els objectes "
"empaquetats"
+#: commit-graph.c
msgid "Finding extra edges in commit graph"
msgstr "S'estan cercant les vores addicionals al graf de comissions"
+#: commit-graph.c
msgid "failed to write correct number of base graph ids"
msgstr ""
"s'ha produït un error en escriure el nombre correcte d'ids base del graf"
+#: commit-graph.c
msgid "unable to create temporary graph layer"
msgstr "no s'ha pogut crear una capa de graf temporal"
+#: commit-graph.c midx-write.c
#, c-format
msgid "unable to adjust shared permissions for '%s'"
msgstr "no s'han pogut ajustar els permisos compartits per a «%s»"
+#: commit-graph.c
#, c-format
msgid "Writing out commit graph in %d pass"
msgid_plural "Writing out commit graph in %d passes"
msgstr[0] "S'està escrivint el graf de comissions en %d pas"
msgstr[1] "S'està escrivint el graf de comissions en %d passos"
+#: commit-graph.c
msgid "unable to open commit-graph chain file"
msgstr "no s'ha pogut obrir el fitxer d'encadenament del graf de comissions"
+#: commit-graph.c
msgid "failed to rename base commit-graph file"
msgstr "no s'ha pogut canviar el nom del fitxer base del graf de comissions"
+#: commit-graph.c
msgid "failed to rename temporary commit-graph file"
msgstr ""
"no s'ha pogut canviar el nom del fitxer temporal del graf de comissions"
+#: commit-graph.c
#, c-format
msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
msgstr "no es poden fusionar els gràfics amb %<PRIuMAX>, %<PRIuMAX>entregues"
+#: commit-graph.c
#, c-format
msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
msgstr "no es pot fusionar el graf %s, hi ha massa comissions: %<PRIuMAX>"
+#: commit-graph.c
msgid "Scanning merged commits"
msgstr "S'estan escanejant les comissions fusionades"
+#: commit-graph.c
msgid "Merging commit-graph"
msgstr "S'està fusionant el graf de comissions"
+#: commit-graph.c
msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr ""
"s'està intentant escriure un graf de comissions, però «core.commitGraph» "
"està desactivat"
+#: commit-graph.c
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph."
+"changedPathsVersion' (%d) is not supported"
+msgstr ""
+"s'ha intentat escriure un graf de comissió, però no s'admet 'commitGraph."
+"changedPathsVersion' (%d)"
+
+#: commit-graph.c
msgid "too many commits to write graph"
msgstr "massa comissions per a escriure un graf"
+#: commit-graph.c
msgid "the commit-graph file has incorrect checksum and is likely corrupt"
msgstr ""
"el fitxer commit-graph (graf de comissions) té una suma de verificació "
"incorrecta i probablement és corrupte"
+#: commit-graph.c
#, c-format
msgid "commit-graph has incorrect OID order: %s then %s"
msgstr "el graf de comissions té una ordre OID incorrecta; %s llavors %s"
+#: commit-graph.c
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
msgstr ""
"el graf de comissions té un valor de «fanout» incorrecte: fanout[%d] = %u != "
"%u"
+#: commit-graph.c
#, c-format
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"
+#: commit-graph.c
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
msgstr ""
"no s'han pogut analitzar la comissió %s de la base de dades d'objectes per "
"al graf de comissions"
+#: commit-graph.c
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
msgstr ""
"OID de l'arbre arrel per a comissions %s en el graf de comissions és %s != %s"
+#: commit-graph.c
#, c-format
msgid "commit-graph parent list for commit %s is too long"
msgstr ""
"la llista de pares del graf de comissions per a la comissió %s és massa "
"llarga"
+#: commit-graph.c
#, c-format
msgid "commit-graph parent for %s is %s != %s"
msgstr "el pare pel graf de comissions %s és %s != %s"
+#: commit-graph.c
#, c-format
msgid "commit-graph parent list for commit %s terminates early"
msgstr "la llista pare del graf de comissions per %s acaba aviat"
-#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr ""
-"el graf de comissions té nombre de generació zero per a la comissió %s, però "
-"té no zero en altres llocs"
-
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"el graf de comissions té un nombre de generació diferent de zero per a "
-"comissió %s però té zero en altres llocs"
-
+#: commit-graph.c
#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr ""
"generació del graf de comissions per a la comissió %s és %<PRIuMAX> < "
"%<PRIuMAX>"
+#: commit-graph.c
#, c-format
msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
msgstr ""
"la data d'enviament per a la comissió %s en el graf de comissions és "
"%<PRIuMAX> != %<PRIuMAX>"
+#: commit-graph.c
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"El graf de comissió té tant generacions zero com no nul·les (p. ex., "
+"comissions «%s» i «%s»)"
+
+#: commit-graph.c
msgid "Verifying commits in commit graph"
msgstr "S'estan verificant les comissions al graf de comissions"
+#: commit-reach.c sequencer.c
+#, c-format
+msgid "could not parse commit %s"
+msgstr "no s'ha pogut analitzar la comissió %s"
+
+#: commit.c
#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s no és una comissió!"
+#: commit.c
msgid ""
"Support for <GIT_DIR>/info/grafts is deprecated\n"
"and will be removed in a future Git version.\n"
@@ -14736,22 +19059,34 @@ msgstr ""
"Desactiveu aquest missatge executant\n"
"«git config advice.graftFileDeprecated false»"
+#: commit.c
+#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"la comissió %s existeix al graf de comissions però no a la base de dades "
+"d'objectes"
+
+#: commit.c
#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr "La comissió %s té una signatura GPG no fiable, suposadament de %s."
+#: commit.c
#, c-format
msgid "Commit %s has a bad GPG signature allegedly by %s."
msgstr "La comissió %s té una signatura GPG incorrecta suposadament de %s."
+#: commit.c
#, c-format
msgid "Commit %s does not have a GPG signature."
msgstr "La comissió %s no té signatura GPG."
+#: commit.c
#, c-format
msgid "Commit %s has a good GPG signature by %s\n"
msgstr "La comissió %s té una signatura GPG bona de %s\n"
+#: commit.c
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"
@@ -14762,203 +19097,260 @@ msgstr ""
"la variable de configuració i18n.commitencoding a la codificació que\n"
"usi el vostre projecte.\n"
+#: compat/compiler.h
msgid "no compiler information available\n"
msgstr "no hi ha informació disponible del compilador\n"
+#: compat/compiler.h
msgid "no libc information available\n"
msgstr "no hi ha informació disponible de libc\n"
+#: compat/disk.h
#, c-format
msgid "could not determine free disk size for '%s'"
msgstr "no s'ha pogut determinar l'espai de disc lliure per a «%s»"
+#: compat/disk.h
#, c-format
msgid "could not get info for '%s'"
msgstr "no s'ha pogut obtenir la informació per a «%s»"
+#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "[GLE %ld] health thread could not open '%ls'"
msgstr "[GLE %ld] el fil de salut no ha pogut obrir «%ls»"
+#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "[GLE %ld] health thread getting BHFI for '%ls'"
msgstr "[GLE %ld] s'està obtenint BHFI del fil de salut per a «%ls»"
+#: compat/fsmonitor/fsm-health-win32.c compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "could not convert to wide characters: '%s'"
msgstr "no s'ha pogut convertir a caràcters amples: «%s»"
+#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "BHFI changed '%ls'"
msgstr "S'ha canviat BHFI «%ls»"
+#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "unhandled case in 'has_worktree_moved': %d"
msgstr "cas no gestionat a «has_worktree_moved»: %d"
+#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "health thread wait failed [GLE %ld]"
msgstr "ha fallat l'espera del fil de salut [GLE %ld]"
+#: compat/fsmonitor/fsm-ipc-darwin.c
#, c-format
msgid "Invalid path: %s"
msgstr "Camí no vàlid: «%s»"
+#: compat/fsmonitor/fsm-listen-darwin.c
msgid "Unable to create FSEventStream."
msgstr "No s'ha pogut crear el FSEventStream."
+#: compat/fsmonitor/fsm-listen-darwin.c
msgid "Failed to start the FSEventStream"
msgstr "No s'ha pogut iniciar el FSEventStream"
+#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
msgstr "[GLE %ld] no s'ha pogut convertir el camí a UTF-8: «%.*ls»"
+#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "[GLE %ld] could not watch '%s'"
msgstr "[GLE %ld] no s'ha pogut vigilar «%s»"
+#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "[GLE %ld] could not get longname of '%s'"
msgstr "[GLE %ld] no s'ha pogut obtenir el nom llarg de «%s»"
+#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
msgstr "Ha fallat ReadDirectoryChangedW a «%s» [GLE %ld]"
+#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
msgstr "Ha fallat GetOverlappedResult a «%s» [GLE %ld]"
+#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "could not read directory changes [GLE %ld]"
msgstr "no s'han pogut llegir els canvis de directori [GLE %ld]"
+#: compat/fsmonitor/fsm-path-utils-darwin.c
#, c-format
msgid "opendir('%s') failed"
msgstr "ha fallat opendir(«%s»)"
+#: compat/fsmonitor/fsm-path-utils-darwin.c
#, c-format
msgid "lstat('%s') failed"
msgstr "ha fallat lstat(«%s»)"
+#: compat/fsmonitor/fsm-path-utils-darwin.c
#, c-format
msgid "strbuf_readlink('%s') failed"
msgstr "ha fallat strbuf_readlink(«%s»)"
+#: compat/fsmonitor/fsm-path-utils-darwin.c
#, c-format
msgid "closedir('%s') failed"
msgstr "ha fallat closedir(«%s»)"
+#: compat/fsmonitor/fsm-path-utils-win32.c
#, c-format
msgid "[GLE %ld] unable to open for read '%ls'"
msgstr "[GLE %ld] no s'ha pogut obrir per a llegir «%ls»"
+#: compat/fsmonitor/fsm-path-utils-win32.c
#, c-format
msgid "[GLE %ld] unable to get protocol information for '%ls'"
msgstr "[GLE %ld] no s'ha pogut obtenir la informació del protocol per a «%ls»"
+#: compat/mingw.c
#, c-format
msgid "failed to copy SID (%ld)"
msgstr "no s'ha pogut copiar el SID (%ld)"
+#: compat/mingw.c
#, c-format
msgid "failed to get owner for '%s' (%ld)"
msgstr "no s'ha pogut obtenir el propietari de «%s» (%ld)"
+#: compat/obstack.c
msgid "memory exhausted"
msgstr "memòria esgotada"
+#: compat/regex/regcomp.c
msgid "Success"
msgstr "Èxit"
+#: compat/regex/regcomp.c
msgid "No match"
msgstr "Cap coincidència"
+#: compat/regex/regcomp.c
msgid "Invalid regular expression"
msgstr "Expressió regular no vàlida"
+#: compat/regex/regcomp.c
msgid "Invalid collation character"
msgstr "El caràcter de col·lació no és vàlid"
+#: compat/regex/regcomp.c
msgid "Invalid character class name"
msgstr "Nom de la classe del caràcter no vàlid"
+#: compat/regex/regcomp.c
msgid "Trailing backslash"
msgstr "Barra inversa del final"
+#: compat/regex/regcomp.c
msgid "Invalid back reference"
msgstr "Referència anterior no vàlida"
+#: compat/regex/regcomp.c
msgid "Unmatched [ or [^"
msgstr "[ o [^ no emparellat"
+#: compat/regex/regcomp.c
msgid "Unmatched ( or \\("
msgstr "( o \\( no emparellat"
+#: compat/regex/regcomp.c
msgid "Unmatched \\{"
msgstr "\\{ no emparellat"
+#: compat/regex/regcomp.c
msgid "Invalid content of \\{\\}"
msgstr "Contingut no vàlid de \\{\\}"
+#: compat/regex/regcomp.c
msgid "Invalid range end"
msgstr "Fi d'interval no vàlid"
+#: compat/regex/regcomp.c
msgid "Memory exhausted"
msgstr "Memòria esgotada"
+#: compat/regex/regcomp.c
msgid "Invalid preceding regular expression"
msgstr "Expressió regular anterior no vàlida"
+#: compat/regex/regcomp.c
msgid "Premature end of regular expression"
msgstr "Fi prematur d'expressió regular"
+#: compat/regex/regcomp.c
msgid "Regular expression too big"
msgstr "Expressió regular és massa gran"
+#: compat/regex/regcomp.c
msgid "Unmatched ) or \\)"
-msgstr ") o \\) no no emparellat"
+msgstr ") o \\) no emparellat"
+#: compat/regex/regcomp.c
msgid "No previous regular expression"
msgstr "No hi ha expressió regular anterior"
+#: compat/simple-ipc/ipc-unix-socket.c compat/simple-ipc/ipc-win32.c
msgid "could not send IPC command"
msgstr "no s'ha pogut enviar l'ordre IPC"
+#: compat/simple-ipc/ipc-unix-socket.c compat/simple-ipc/ipc-win32.c
msgid "could not read IPC response"
msgstr "no s'ha pogut llegir la resposta IPC"
+#: compat/simple-ipc/ipc-unix-socket.c
#, c-format
msgid "could not start accept_thread '%s'"
msgstr "no s'ha pogut començar un fil «accept_thread» «%s»"
+#: compat/simple-ipc/ipc-unix-socket.c
#, c-format
msgid "could not start worker[0] for '%s'"
msgstr "no s'ha pogut iniciar el fil[0] per a «%s»"
+#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "ConnectNamedPipe failed for '%s' (%lu)"
msgstr "Ha fallat ConnectNamedPipe per a «%s» (%lu)"
+#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "could not create fd from pipe for '%s'"
msgstr "no s'ha pogut crear un fd a partir de la canonada per a «%s»"
+#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "could not start thread[0] for '%s'"
msgstr "no s'ha pogut iniciar el fil[0] per a «%s»"
+#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "wait for hEvent failed for '%s'"
msgstr "ha fallat l'espera de hEvent per a «%s»"
+#: compat/terminal.c
msgid "cannot resume in the background, please use 'fg' to resume"
msgstr "no es pot reprendre en segon pla, si us plau useu «fg» per a reprendre"
+#: compat/terminal.c
msgid "cannot restore terminal settings"
msgstr "no es poden restaurar els paràmetres del terminal"
+#: config.c
#, c-format
msgid ""
"exceeded maximum include depth (%d) while including\n"
@@ -14973,17 +19365,21 @@ msgstr ""
"\t%s\n"
"Això pot ser degut a inclusions circulars."
+#: config.c
#, c-format
msgid "could not expand include path '%s'"
msgstr "no s'ha pogut expandir el camí d'inclusió «%s»"
+#: config.c
msgid "relative config includes must come from files"
msgstr "les inclusions de configuració relatives han de venir de fitxers"
+#: config.c
msgid "relative config include conditionals must come from files"
msgstr ""
"els condicionals d'inclusió de configuració relatius han de venir de fitxers"
+#: config.c
msgid ""
"remote URLs cannot be configured in file directly or indirectly included by "
"includeIf.hasconfig:remote.*.url"
@@ -14991,277 +19387,353 @@ msgstr ""
"URL remots no es poden configurar en un fitxer directament o indirectament "
"inclòs per «includeIf.hasconfig:remote.*.url»"
+#: config.c
#, c-format
msgid "invalid config format: %s"
msgstr "format de configuració no vàlid: %s"
+#: config.c
#, c-format
msgid "missing environment variable name for configuration '%.*s'"
msgstr "falta el nom de la variable d'entorn per a la configuració «%.*s»"
+#: config.c
#, c-format
msgid "missing environment variable '%s' for configuration '%.*s'"
msgstr "falta la variable d'entorn «%s» per a la configuració «%.*s»"
+#: config.c
#, c-format
msgid "key does not contain a section: %s"
msgstr "la clau no conté una secció: «%s»"
+#: config.c
#, c-format
msgid "key does not contain variable name: %s"
msgstr "la clau no conté un nom de variable: «%s»"
+#: config.c sequencer.c
#, c-format
msgid "invalid key: %s"
msgstr "clau no vàlida: %s"
+#: config.c
#, c-format
msgid "invalid key (newline): %s"
msgstr "clau no vàlida (línia nova): %s"
+#: config.c
msgid "empty config key"
msgstr "clau de configuració buida"
+#: config.c
#, c-format
msgid "bogus config parameter: %s"
msgstr "paràmetre de configuració erroni: %s"
+#: config.c
#, c-format
msgid "bogus format in %s"
msgstr "format erroni a %s"
+#: config.c
#, c-format
msgid "bogus count in %s"
msgstr "comptatge erroni a %s"
+#: config.c
#, c-format
msgid "too many entries in %s"
msgstr "hi ha massa arguments a %s"
+#: config.c
#, c-format
msgid "missing config key %s"
msgstr "falta la clau de configuració %s"
+#: config.c
#, c-format
msgid "missing config value %s"
msgstr "falta el valor de configuració %s"
+#: config.c
#, c-format
msgid "bad config line %d in blob %s"
msgstr "línia de configuració %d errònia en el blob %s"
+#: config.c
#, c-format
msgid "bad config line %d in file %s"
msgstr "línia de configuració %d errònia en el fitxer %s"
+#: config.c
#, c-format
msgid "bad config line %d in standard input"
msgstr "línia de configuració %d errònia en l'entrada estàndard"
+#: config.c
#, c-format
msgid "bad config line %d in submodule-blob %s"
msgstr "línia de configuració %d errònia en el blob de submòdul %s"
+#: config.c
#, c-format
msgid "bad config line %d in command line %s"
msgstr "línia de configuració %d errònia en la línia d'ordres %s"
+#: config.c
#, c-format
msgid "bad config line %d in %s"
msgstr "línia de configuració %d errònia en %s"
+#: config.c
msgid "out of range"
msgstr "fora de rang"
+#: config.c
msgid "invalid unit"
msgstr "unitat no vàlida"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s': %s"
msgstr "valor de configuració numèric erroni «%s» per «%s»: %s"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
msgstr "valor de configuració numèric erroni «%s» per «%s» en el blob %s: %s"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s' in file %s: %s"
msgstr "valor de configuració numèric «%s» erroni per «%s» en el fitxer %s: %s"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s' in standard input: %s"
msgstr ""
"valor de configuració numèric «%s» erroni per «%s» en l'entrada estàndard: %s"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
msgstr ""
"valor de configuració numèric «%s» erroni per «%s» en el blob de submòdul "
"%s: %s"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
msgstr ""
"valor de configuració numèric «%s» erroni per «%s» en la línia d'ordres %s: "
"%s"
+#: config.c
#, c-format
msgid "bad numeric config value '%s' for '%s' in %s: %s"
msgstr "valor de configuració numèric incorrecte «%s» per «%s» en %s: %s"
+#: config.c
#, c-format
msgid "invalid value for variable %s"
msgstr "valor no vàlid per a la variable %s"
+#: config.c
#, c-format
msgid "ignoring unknown core.fsync component '%s'"
msgstr "s'ignora el component core.fsync «%s» desconegut"
+#: config.c
#, c-format
msgid "bad boolean config value '%s' for '%s'"
msgstr "valor de configuració booleà erroni «%s» per a «%s»"
+#: config.c
#, c-format
msgid "failed to expand user dir in: '%s'"
msgstr "s'ha produït un error en expandir el directori d'usuari en: «%s»"
+#: config.c
#, c-format
msgid "'%s' for '%s' is not a valid timestamp"
msgstr "«%s» per a «%s» no és una marca de temps vàlida"
+#: config.c
#, c-format
msgid "abbrev length out of range: %d"
msgstr "la longitud d'«abbrev» està fora de rang: %d"
+#: config.c
#, c-format
msgid "bad zlib compression level %d"
msgstr "nivell de compressió de zlib incorrecte %d"
-msgid "core.commentChar should only be one ASCII character"
-msgstr "core.commentChar només hauria de ser un caràcter ASCII"
+# newline → línia nova o salt de línia?
+#: config.c
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s no pot contenir una nova línia"
+
+#: config.c
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s ha de tenir almenys un caràcter"
+#: config.c
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
msgstr "s'ignora el valor desconegut «%s» de core.fsyncMethod"
+#: config.c
msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
msgstr "core.fsyncObjectFiles és obsolet; useu core.fsync"
+#: config.c
#, c-format
msgid "invalid mode for object creation: %s"
msgstr "mode de creació d'objecte no vàlid: %s"
+#: config.c
#, c-format
msgid "malformed value for %s"
msgstr "valor no vàlid per a %s"
+#: config.c
#, c-format
msgid "malformed value for %s: %s"
msgstr "valor no vàlid per a %s: %s"
+#: config.c
msgid "must be one of nothing, matching, simple, upstream or current"
msgstr ""
"ha de ser un dels elements següents: nothing, matching, simple, upstream o "
"current"
+#: config.c
#, c-format
msgid "unable to load config blob object '%s'"
msgstr "no s'ha pogut carregar l'objecte blob de configuració «%s»"
+#: config.c
#, c-format
msgid "reference '%s' does not point to a blob"
msgstr "la referència «%s» no assenyala a un blob"
+#: config.c
#, c-format
msgid "unable to resolve config blob '%s'"
msgstr "no s'ha pogut resoldre el blob de configuració: «%s»"
-#, c-format
-msgid "failed to parse %s"
-msgstr "s'ha produït un error en analitzar %s"
-
+#: config.c
msgid "unable to parse command-line config"
msgstr "no s'ha pogut analitzar la configuració de la línia d'ordres"
+#: config.c
msgid "unknown error occurred while reading the configuration files"
msgstr "un error desconegut ha ocorregut en llegir els fitxers de configuració"
+#: config.c
#, c-format
msgid "Invalid %s: '%s'"
msgstr "%s no vàlid: «%s»"
+#: config.c
#, c-format
msgid "splitIndex.maxPercentChange value '%d' should be between 0 and 100"
msgstr "valor «%d» a splitIndex.maxPercentChange ha d'estar entre 0 i 100"
+#: config.c
#, c-format
msgid "unable to parse '%s' from command-line config"
msgstr "no s'ha pogut analitzar «%s» de la configuració de la línia d'ordres"
+#: config.c
#, c-format
msgid "bad config variable '%s' in file '%s' at line %d"
msgstr "variable de configuració «%s» errònia en el fitxer «%s» a la línia %d"
+#: config.c
#, c-format
msgid "invalid section name '%s'"
msgstr "nom de secció no vàlid «%s»"
+#: config.c
#, c-format
msgid "%s has multiple values"
msgstr "%s té múltiples valors"
+#: config.c
#, c-format
msgid "failed to write new configuration file %s"
msgstr "no es pot escriure un nou fitxer de configuració %s"
+#: config.c
+#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "no es permet el comentari multi-línia: «%s»"
+
+#: config.c
#, c-format
msgid "could not lock config file %s"
msgstr "no s'ha pogut blocar el fitxer de configuració %s"
+#: config.c
#, c-format
msgid "opening %s"
msgstr "s'està obrint %s"
+#: config.c
#, c-format
msgid "invalid config file %s"
msgstr "fitxer de configuració no vàlid %s"
+#: config.c
#, c-format
msgid "fstat on %s failed"
msgstr "ha fallat «fstat» a %s"
+#: config.c
#, c-format
msgid "unable to mmap '%s'%s"
msgstr "no s'ha pogut fer «mmap» «%s»%s"
+#: config.c
#, c-format
msgid "chmod on %s failed"
msgstr "ha fallat chmod a %s"
+#: config.c
#, c-format
msgid "could not write config file %s"
msgstr "no s'ha pogut escriure el fitxer de configuració «%s»"
+#: config.c
#, c-format
msgid "could not set '%s' to '%s'"
msgstr "no s'ha pogut establir «%s» a «%s»"
+#: config.c
#, c-format
msgid "invalid section name: %s"
msgstr "nom de secció no vàlida: %s"
+#: config.c
#, 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>"
+#: config.c
#, c-format
msgid "missing value for '%s'"
msgstr "falta el valor per «%s»"
+#: connect.c
msgid "the remote end hung up upon initial contact"
msgstr "el costat remot ha penjat en el moment de contacte inicial"
+#: connect.c
msgid ""
"Could not read from remote repository.\n"
"\n"
@@ -15273,77 +19745,97 @@ msgstr ""
"Assegureu-vos que tingueu els permisos\n"
"d'accés correctes i que el repositori existeixi."
+#: connect.c
#, c-format
msgid "server doesn't support '%s'"
msgstr "el servidor no és compatible amb «%s»"
+#: connect.c
#, c-format
msgid "server doesn't support feature '%s'"
msgstr "el servidor no és compatible amb la característica «%s»"
+#: connect.c
msgid "expected flush after capabilities"
msgstr "s'esperava un buidatge després de les capacitats"
+#: connect.c
#, c-format
msgid "ignoring capabilities after first line '%s'"
msgstr "ignora les capacitats després de la primera línia «%s»"
+#: connect.c
msgid "protocol error: unexpected capabilities^{}"
msgstr "error de protocol: unexpected capabilities^{}"
+#: connect.c
#, c-format
msgid "protocol error: expected shallow sha-1, got '%s'"
msgstr ""
"s'ha produït un error de protocol: s'esperava shallow sha-1, s'ha rebut «%s»"
+#: connect.c
msgid "repository on the other end cannot be shallow"
msgstr "el repositori de l'altre extrem no pot ser shallow"
+#: connect.c
msgid "invalid packet"
msgstr "paquet no vàlid"
+#: connect.c
#, c-format
msgid "protocol error: unexpected '%s'"
msgstr "s'ha produït un error de protocol: no s'esperava «%s»"
+#: connect.c
#, c-format
msgid "unknown object format '%s' specified by server"
msgstr "format d'objecte «%s» especificat pel servidor desconegut"
+#: connect.c
#, c-format
msgid "error on bundle-uri response line %d: %s"
msgstr "error a la línia de resposta de bundle-uri %d: %s"
+#: connect.c
msgid "expected flush after bundle-uri listing"
msgstr "s'esperava un buidatge després del llistat de bundle-uri"
+#: connect.c
msgid "expected response end packet after ref listing"
msgstr ""
"s'esperava un paquet de final de resposta després del llistat de referències"
+#: connect.c
#, c-format
msgid "invalid ls-refs response: %s"
msgstr "resposta de ls-refs no vàlida: %s"
+#: connect.c
msgid "expected flush after ref listing"
msgstr "s'esperava una neteja després del llistat de referències"
+#: connect.c
#, c-format
msgid "protocol '%s' is not supported"
msgstr "el protocol «%s» no és compatible"
+#: connect.c
msgid "unable to set SO_KEEPALIVE on socket"
msgstr "no s'ha pogut establir SO_KEEPALIVE al sòcol"
+#: connect.c
#, c-format
msgid "Looking up %s ... "
msgstr "S'està cercant %s..."
+#: connect.c
#, c-format
msgid "unable to look up %s (port %s) (%s)"
msgstr "no s'ha pogut trobar %s (port %s) (%s)"
#. TRANSLATORS: this is the end of "Looking up %s ... "
+#: connect.c
#, c-format
msgid ""
"done.\n"
@@ -15352,6 +19844,7 @@ msgstr ""
"fet.\n"
"S'està connectant a %s (port %s) ... "
+#: connect.c
#, c-format
msgid ""
"unable to connect to %s:\n"
@@ -15361,72 +19854,91 @@ msgstr ""
"%s"
#. TRANSLATORS: this is the end of "Connecting to %s (port %s) ... "
+#: connect.c
msgid "done."
msgstr "fet."
+#: connect.c
#, c-format
msgid "unable to look up %s (%s)"
msgstr "no s'ha pogut trobar %s (%s)"
+#: connect.c
#, c-format
msgid "unknown port %s"
msgstr "port desconegut %s"
+#: connect.c
#, c-format
msgid "strange hostname '%s' blocked"
msgstr "s'ha bloquejat el nom estrany d'amfitrió «%s»"
+#: connect.c
#, c-format
msgid "strange port '%s' blocked"
msgstr "s'ha bloquejat el port estrany «%s»"
+#: connect.c
#, c-format
msgid "cannot start proxy %s"
msgstr "no s'ha pogut iniciar servidor intermediari «%s»"
+#: connect.c
msgid "no path specified; see 'git help pull' for valid url syntax"
msgstr ""
"no s'ha especificat un camí; vegeu «git help pull» per la sintaxi vàlida per "
"URL"
+#: connect.c
msgid "newline is forbidden in git:// hosts and repo paths"
msgstr ""
"la línia nova està prohibida en els servidors git:// i els camins de "
"repositori"
+#: connect.c
msgid "ssh variant 'simple' does not support -4"
msgstr "la variant «simple» de ssh no és compatible amb -4"
+#: connect.c
msgid "ssh variant 'simple' does not support -6"
msgstr "la variant «simple» de ssh no és compatible amb -6"
+#: connect.c
msgid "ssh variant 'simple' does not support setting port"
msgstr "la variant «simple» de ssh no permet definir el port"
+#: connect.c
#, c-format
msgid "strange pathname '%s' blocked"
msgstr "s'ha bloquejat el nom de fitxer estrany «%s»"
+#: connect.c
msgid "unable to fork"
msgstr "no s'ha pogut bifurcar"
+#: connected.c
msgid "Could not run 'git rev-list'"
msgstr "No s'ha pogut executar «git rev-list»"
+#: connected.c
msgid "failed write to rev-list"
msgstr "escriptura fallada al rev-list"
+#: connected.c
msgid "failed to close rev-list's stdin"
msgstr "s'ha produït un error en tancar l'stdin del rev-list"
+#: convert.c
#, c-format
msgid "illegal crlf_action %d"
msgstr "crlf_action %d il·legal"
+#: convert.c
#, c-format
msgid "CRLF would be replaced by LF in %s"
msgstr "CRLF es reemplaçà per LF en %s"
+#: convert.c
#, c-format
msgid ""
"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
@@ -15435,10 +19947,12 @@ msgstr ""
"a la còpia de treball de «%s», CRLF serà substituït per LF, la propera "
"vegada que el Git ho modifiqui"
+#: convert.c
#, c-format
msgid "LF would be replaced by CRLF in %s"
msgstr "LF es reemplaçà per CRLF en %s"
+#: convert.c
#, c-format
msgid ""
"in the working copy of '%s', LF will be replaced by CRLF the next time Git "
@@ -15447,64 +19961,79 @@ msgstr ""
"a la còpia de treball de «%s», LF serà substituït per CRLF la propera vegada "
"que Git ho modifiqui"
+#: convert.c
#, c-format
msgid "BOM is prohibited in '%s' if encoded as %s"
msgstr "BOM està prohibida a «%s» si està codificada com a %s"
+#: convert.c
#, c-format
msgid ""
"The file '%s' contains a byte order mark (BOM). Please use UTF-%.*s as "
"working-tree-encoding."
msgstr ""
-"El fitxer «%s» conté una marca d'ordre de byte (BOM). Utilitzeu UTF-%.*s com "
-"a codificacions d'arbre de treball."
+"El fitxer «%s» conté una marca d'ordre de octets (BOM). Utilitzeu UTF-%.*s "
+"com a codificacions d'arbre de treball."
+#: convert.c
#, c-format
msgid "BOM is required in '%s' if encoded as %s"
msgstr "La BOM és necessària en «%s» si està codificada com a %s"
+#: convert.c
#, 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 ""
-"Falta una marca d'ordre de byte (BOM) al fitxer «%s». Useu UTF-%sBE o UTF-"
-"%sLE (depenent de l'ordre de byte) com a codificacions d'arbre de treball."
+"Falta una marca d'ordre d'octets (BOM) al fitxer «%s». Useu UTF-%sBE o UTF-"
+"%sLE (depenent de l'ordre dels octets) com a codificacions d'arbre de "
+"treball."
+#: convert.c
#, c-format
msgid "failed to encode '%s' from %s to %s"
msgstr "s'ha produït un error en codificar «%s» des de %s a %s"
+#: convert.c
#, c-format
msgid "encoding '%s' from %s to %s and back is not the same"
msgstr "codificar «%s» des de %s a %s i cap enrere no és el mateix"
+#: convert.c
#, c-format
msgid "cannot fork to run external filter '%s'"
msgstr "no es pot bifurcar per a executar el filtre extern «%s»"
+#: convert.c
#, c-format
msgid "cannot feed the input to external filter '%s'"
msgstr "no es pot alimentar l'entrada al filtre extern «%s»"
+#: convert.c
#, c-format
msgid "external filter '%s' failed %d"
msgstr "el filtre extern «%s» ha fallat %d"
+#: convert.c
#, c-format
msgid "read from external filter '%s' failed"
msgstr "la lectura del filtre extern «%s» ha fallat"
+#: convert.c
#, c-format
msgid "external filter '%s' failed"
msgstr "el filtre extern «%s» ha fallat"
+#: convert.c
msgid "unexpected filter type"
msgstr "tipus de filtre inesperat"
+#: convert.c
msgid "path name too long for external filter"
msgstr "el nom del camí és massa gran per al filtre extern"
+#: convert.c
#, c-format
msgid ""
"external filter '%s' is not available anymore although not all paths have "
@@ -15513,80 +20042,97 @@ msgstr ""
"el filtre extern «%s» ja no està disponible encara que no s'han filtrat tots "
"els camins"
+#: convert.c
msgid "true/false are no valid working-tree-encodings"
msgstr "cert/fals no són codificacions d'arbre de treball vàlides"
+#: convert.c
#, c-format
msgid "%s: clean filter '%s' failed"
msgstr "%s: el filtre de netejat «%s» ha fallat"
+#: convert.c
#, c-format
msgid "%s: smudge filter %s failed"
msgstr "%s: ha fallat el filtre smudge %s"
+#: credential.c
#, c-format
msgid "skipping credential lookup for key: credential.%s"
msgstr "s'està ometent la cerca de credencials per una clau: credential.%s"
+#: credential.c
msgid "refusing to work with credential missing host field"
msgstr ""
"s'ha rebutjat treballar amb credencials que no tenen el camp d'amfitrió"
+#: credential.c
msgid "refusing to work with credential missing protocol field"
msgstr ""
"s'ha rebutjat treballar amb credencials que no tenen el camp de protocol"
+#: credential.c
#, c-format
msgid "url contains a newline in its %s component: %s"
msgstr "url conté una línia nova en %s component: %s"
+#: credential.c
#, c-format
msgid "url has no scheme: %s"
msgstr "l'url no té esquema: %s"
+#: credential.c
#, c-format
msgid "credential url cannot be parsed: %s"
msgstr "no s'ha pogut analitzar l'URL de credencials: %s"
+#: date.c
msgid "in the future"
msgstr "en el futur"
+#: date.c
#, c-format
msgid "%<PRIuMAX> second ago"
msgid_plural "%<PRIuMAX> seconds ago"
msgstr[0] "fa %<PRIuMAX> segon"
msgstr[1] "fa %<PRIuMAX> segons"
+#: date.c
#, c-format
msgid "%<PRIuMAX> minute ago"
msgid_plural "%<PRIuMAX> minutes ago"
msgstr[0] "fa %<PRIuMAX> minut"
msgstr[1] "fa %<PRIuMAX> minuts"
+#: date.c
#, c-format
msgid "%<PRIuMAX> hour ago"
msgid_plural "%<PRIuMAX> hours ago"
msgstr[0] "fa %<PRIuMAX> hora"
msgstr[1] "fa %<PRIuMAX> hores"
+#: date.c
#, c-format
msgid "%<PRIuMAX> day ago"
msgid_plural "%<PRIuMAX> days ago"
msgstr[0] "fa %<PRIuMAX> dia"
msgstr[1] "fa %<PRIuMAX> dies"
+#: date.c
#, c-format
msgid "%<PRIuMAX> week ago"
msgid_plural "%<PRIuMAX> weeks ago"
msgstr[0] "fa %<PRIuMAX> setmana"
msgstr[1] "fa %<PRIuMAX> setmanes"
+#: date.c
#, c-format
msgid "%<PRIuMAX> month ago"
msgid_plural "%<PRIuMAX> months ago"
msgstr[0] "fa %<PRIuMAX> mes"
msgstr[1] "fa %<PRIuMAX> mesos"
+#: date.c
#, c-format
msgid "%<PRIuMAX> year"
msgid_plural "%<PRIuMAX> years"
@@ -15594,90 +20140,109 @@ msgstr[0] "%<PRIuMAX> any"
msgstr[1] "%<PRIuMAX> anys"
#. TRANSLATORS: "%s" is "<n> years"
+#: date.c
#, c-format
msgid "%s, %<PRIuMAX> month ago"
msgid_plural "%s, %<PRIuMAX> months ago"
msgstr[0] "fa %s i %<PRIuMAX> mes"
msgstr[1] "fa %s i %<PRIuMAX> mesos"
+#: date.c
#, c-format
msgid "%<PRIuMAX> year ago"
msgid_plural "%<PRIuMAX> years ago"
msgstr[0] "fa %<PRIuMAX> any"
msgstr[1] "fa %<PRIuMAX> anys"
+#: delta-islands.c
msgid "Propagating island marks"
msgstr "S'estan propagant les marques d'illa"
+#: delta-islands.c
#, c-format
msgid "bad tree object %s"
msgstr "objecte d'arbre malmès %s"
+#: delta-islands.c
#, c-format
msgid "failed to load island regex for '%s': %s"
msgstr ""
"s'ha produït un error en carregar l'expressió regular de l'illa per «%s»: %s"
+#: delta-islands.c
#, c-format
msgid "island regex from config has too many capture groups (max=%d)"
msgstr ""
"l'expressió regular de l'illa des de la configuració té massa grups de "
"captura (màx=%d)"
+#: delta-islands.c
#, c-format
msgid "Marked %d islands, done.\n"
msgstr "Marcades %d illes, fet.\n"
+#: diagnose.c
#, c-format
msgid "invalid --%s value '%s'"
msgstr "no és vàlid --%s amb valor «%s»"
+#: diagnose.c
#, c-format
msgid "could not archive missing directory '%s'"
msgstr "no s'ha pogut arxivar el directori que falta «%s»"
+#: diagnose.c dir.c
#, c-format
msgid "could not open directory '%s'"
msgstr "no s'ha pogut obrir el directori «%s»"
+#: diagnose.c
#, c-format
msgid "skipping '%s', which is neither file nor directory"
msgstr "s'omet «%s», que no és ni fitxer ni directori"
+#: diagnose.c
msgid "could not duplicate stdout"
msgstr "no s'ha pogut duplicar stdout"
+#: diagnose.c
#, c-format
msgid "could not add directory '%s' to archiver"
msgstr "no s'ha pogut afegir el directori «%s» a l'arxivador"
+#: diagnose.c
msgid "failed to write archive"
msgstr "s'ha produït un error en escriure arxiu"
+#: diff-lib.c
msgid "--merge-base does not work with ranges"
msgstr "--merge-base no funciona amb intervals"
-msgid "--merge-base only works with commits"
-msgstr "--merge-base només funciona amb comissions"
-
+#: diff-lib.c
msgid "unable to get HEAD"
msgstr "no s'ha pogut obtenir HEAD"
+#: diff-lib.c
msgid "no merge base found"
msgstr "no s'ha trobat una base de fusió"
+#: diff-lib.c
msgid "multiple merge bases found"
msgstr "s'han trobat múltiples bases de fusió"
+#: diff-no-index.c
msgid "cannot compare stdin to a directory"
msgstr "no es pot comparar stdin amb un directori"
+#: diff-no-index.c
msgid "cannot compare a named pipe to a directory"
msgstr "no es pot comparar una canonada amb nom amb un directori"
+#: diff-no-index.c
msgid "git diff --no-index [<options>] <path> <path>"
msgstr "git diff --no-index [<opcions>] <camí> <camí>"
+#: diff-no-index.c
msgid ""
"Not a git repository. Use --no-index to compare two paths outside a working "
"tree"
@@ -15685,16 +20250,19 @@ msgstr ""
"No és un repositori Git. Useu --no-index per a comparar dos camins fora del "
"directori de treball"
+#: diff.c
#, c-format
msgid " Failed to parse dirstat cut-off percentage '%s'\n"
msgstr ""
" S'ha produït un error en analitzar el percentatge limitant de dirstat "
"«%s»\n"
+#: diff.c
#, c-format
msgid " Unknown dirstat parameter '%s'\n"
msgstr " Paràmetre de dirstat desconegut «%s»\n"
+#: diff.c
msgid ""
"color moved setting must be one of 'no', 'default', 'blocks', 'zebra', "
"'dimmed-zebra', 'plain'"
@@ -15702,6 +20270,7 @@ msgstr ""
"el paràmetre de color en moviment ha de ser «no», «default», «blocks», "
"«zebra», «dimmed-zebra» o «plain»"
+#: diff.c
#, c-format
msgid ""
"unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', "
@@ -15711,6 +20280,7 @@ msgstr ""
"«ignore-space-change», «ignore-space-at-eol», «ignore-all-space», «allow-"
"indentation-change»"
+#: diff.c
msgid ""
"color-moved-ws: allow-indentation-change cannot be combined with other "
"whitespace modes"
@@ -15718,11 +20288,18 @@ msgstr ""
"color-moved-ws: allow-indentation-change no es pot combinar amb altres modes "
"d'espai en blanc"
+#: diff.c
#, c-format
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr ""
"Valor desconegut de la variable de configuració de «diff.submodule»: «%s»"
+#: diff.c merge-recursive.c transport.c
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "valor desconegut per al config «%s»': %s"
+
+#: diff.c
#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
@@ -15731,39 +20308,48 @@ msgstr ""
"S'han trobat errors en la variable de configuració «diff.dirstat»:\n"
"%s"
+#: diff.c
#, c-format
msgid "external diff died, stopping at %s"
msgstr "el diff external s'ha mort, s'està aturant a %s"
+#: diff.c
msgid "--follow requires exactly one pathspec"
msgstr "--follow requereix exactament una especificació de camí"
+#: diff.c
#, c-format
msgid "pathspec magic not supported by --follow: %s"
msgstr "el «pathspec» màgic no està suportat per --follow: %s"
+#: diff.c parse-options.c
#, 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"
+#: diff.c
#, c-format
msgid "options '%s' and '%s' cannot be used together, use '%s' with '%s'"
msgstr "les opcions «%s» i «%s» no es poden usar juntes, useu «%s» amb «%s»"
+#: diff.c
#, c-format
msgid ""
"options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
msgstr ""
"les opcions «%s» i «%s» no es poden usar juntes, useu «%s» amb «%s» i «%s»"
+#: diff.c
#, c-format
msgid "invalid --stat value: %s"
msgstr "valor --stat no vàlid: %s"
+#: diff.c parse-options.c
#, c-format
msgid "%s expects a numerical value"
msgstr "%s espera un valor numèric"
+#: diff.c
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -15772,153 +20358,189 @@ msgstr ""
"S'ha produït un error en analitzar el paràmetre d'opció de --dirstat/-X:\n"
"%s"
+#: diff.c
#, c-format
msgid "unknown change class '%c' in --diff-filter=%s"
msgstr "classe de canvi «%c» desconeguda a --diff-filter=%s"
+#: diff.c
#, c-format
msgid "unknown value after ws-error-highlight=%.*s"
msgstr "valor desconegut després de ws-error-highlight=%.*s"
+#: diff.c
#, c-format
msgid "unable to resolve '%s'"
msgstr "no s'ha pogut resoldre «%s»"
+#: diff.c
#, c-format
msgid "%s expects <n>/<m> form"
msgstr "%s espera una forma <n>/<m>"
+#: diff.c
#, c-format
msgid "%s expects a character, got '%s'"
msgstr "%s esperava un caràcter, s'ha rebut «%s»"
+#: diff.c
#, c-format
msgid "bad --color-moved argument: %s"
msgstr "argument --color-moved incorrecte: %s"
+#: diff.c
#, c-format
msgid "invalid mode '%s' in --color-moved-ws"
msgstr "mode «%s» no vàlid en --color-moved-ws"
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"l'opció diff-algorithm accepta «myers», «minimal», «patience» i «histogram»"
-
+#: diff.c
#, c-format
msgid "invalid argument to %s"
msgstr "argument no vàlid a %s"
+#: diff.c
#, c-format
msgid "invalid regex given to -I: '%s'"
msgstr "expressió regular donada a -I: no vàlida: «%s»"
+#: diff.c
#, c-format
msgid "failed to parse --submodule option parameter: '%s'"
msgstr ""
"s'ha produït un error en analitzar el paràmetre d'opció de --submodule: «%s»"
+#: diff.c
#, c-format
msgid "bad --word-diff argument: %s"
msgstr "argument --word-diff incorrecte: %s"
+#: diff.c
msgid "Diff output format options"
msgstr "Opcions del format de sortida del diff"
+#: diff.c
msgid "generate patch"
msgstr "genera el pedaç"
+#: diff.c
msgid "<n>"
msgstr "<n>"
+#: diff.c
msgid "generate diffs with <n> lines context"
msgstr "genera diffs amb <n> línies de context"
+#: diff.c
msgid "generate the diff in raw format"
msgstr "genera el diff en format cru"
+#: diff.c
msgid "synonym for '-p --raw'"
msgstr "sinònim de «-p --raw»"
+#: diff.c
msgid "synonym for '-p --stat'"
msgstr "sinònim de «-p --stat»"
+#: diff.c
msgid "machine friendly --stat"
msgstr "llegible per una màquina --stat"
+#: diff.c
msgid "output only the last line of --stat"
msgstr "mostra només l'última línia de --stat"
-msgid "<param1,param2>..."
-msgstr "<param1,param2>..."
+#: diff.c
+msgid "<param1>,<param2>..."
+msgstr "<param1>,<param2>..."
+#: diff.c
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
msgstr ""
"genera la distribució de la quantitat relativa de canvis per a cada "
"subdirectori"
+#: diff.c
msgid "synonym for --dirstat=cumulative"
msgstr "sinònim de --dirstat=cumulative"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "sinònim de --dirstat=files,param1,param2..."
+#: diff.c
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "sinònim de --dirstat=files,<param1>,<param2>..."
+#: diff.c
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
"avisa si els canvis introdueixen marcadors en conflicte o errors d'espai en "
"blanc"
+#: diff.c
msgid "condensed summary such as creations, renames and mode changes"
msgstr "resum condensat com ara creacions, canvis de nom i mode"
+#: diff.c
msgid "show only names of changed files"
msgstr "mostra només els noms de fitxers canviats"
+#: diff.c
msgid "show only names and status of changed files"
msgstr "mostra només els noms i l'estat dels fitxers canviats"
+#: diff.c
msgid "<width>[,<name-width>[,<count>]]"
msgstr "<amplada>[<amplada-nom>[,<recompte>]]"
+#: diff.c
msgid "generate diffstat"
msgstr "genera diffstat"
+#: diff.c
msgid "<width>"
msgstr "<amplada>"
+#: diff.c
msgid "generate diffstat with a given width"
msgstr "genera diffstat amb una amplada donada"
+#: diff.c
msgid "generate diffstat with a given name width"
msgstr "genera diffstat amb un nom d'amplada donat"
+#: diff.c
msgid "generate diffstat with a given graph width"
msgstr "genera diffstat amb una amplada de graf donada"
+#: diff.c
msgid "<count>"
msgstr "<comptador>"
+#: diff.c
msgid "generate diffstat with limited lines"
msgstr "genera diffstat amb línies limitades"
+#: diff.c
msgid "generate compact summary in diffstat"
msgstr "genera un resum compacte a diffstat"
+#: diff.c
msgid "output a binary diff that can be applied"
msgstr "diff amb sortida binària que pot ser aplicada"
+#: diff.c
msgid "show full pre- and post-image object names on the \"index\" lines"
msgstr ""
"mostra els noms complets dels objectes pre i post-imatge a les línies «index»"
+#: diff.c
msgid "show colored diff"
msgstr "mostra un diff amb colors"
+#: diff.c
msgid "<kind>"
msgstr "<kind>"
+#: diff.c
msgid ""
"highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
"diff"
@@ -15926,6 +20548,7 @@ msgstr ""
"ressalta els errors d'espai en blanc a les línies «context», «old» o «new» "
"al diff"
+#: diff.c
msgid ""
"do not munge pathnames and use NULs as output field terminators in --raw or "
"--numstat"
@@ -15933,74 +20556,96 @@ msgstr ""
"no consolidis els noms de camí i utilitza NULs com a terminadors de camp de "
"sortida en --raw o --numstat"
+#: diff.c
msgid "<prefix>"
msgstr "<prefix>"
+#: diff.c
msgid "show the given source prefix instead of \"a/\""
msgstr "mostra el prefix d'origen donat en lloc de «a/»"
+#: diff.c
msgid "show the given destination prefix instead of \"b/\""
msgstr "mostra el prefix de destinació indicat en lloc de «b/»"
+#: diff.c
msgid "prepend an additional prefix to every line of output"
msgstr "afegir un prefix addicional per a cada línia de sortida"
+#: diff.c
msgid "do not show any source or destination prefix"
msgstr "no mostris cap prefix d'origen o destí"
+#: diff.c
msgid "use default prefixes a/ and b/"
msgstr "utilitza els prefixos per defecte a/ i b/"
+#: diff.c
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 "
"línies"
+#: diff.c
msgid "<char>"
-msgstr "<char>"
+msgstr "<caràcter>"
+#: diff.c
msgid "specify the character to indicate a new line instead of '+'"
msgstr ""
"especifiqueu el caràcter per a indicar una línia nova en comptes de «+»"
+#: diff.c
msgid "specify the character to indicate an old line instead of '-'"
msgstr ""
"especifiqueu el caràcter per a indicar una línia antiga en comptes de «-»"
+#: diff.c
msgid "specify the character to indicate a context instead of ' '"
msgstr "especifiqueu el caràcter per a indicar context en comptes de « »"
+#: diff.c
msgid "Diff rename options"
msgstr "Opcions de canvi de nom del diff"
+#: diff.c
msgid "<n>[/<m>]"
msgstr "<n>[/<m>]"
+#: diff.c
msgid "break complete rewrite changes into pairs of delete and create"
msgstr ""
"divideix els canvis de reescriptura completa en parells de suprimir i crear"
+#: diff.c
msgid "detect renames"
msgstr "detecta els canvis de noms"
+#: diff.c
msgid "omit the preimage for deletes"
msgstr "omet les preimatges per les supressions"
+#: diff.c
msgid "detect copies"
msgstr "detecta còpies"
+#: diff.c
msgid "use unmodified files as source to find copies"
msgstr "usa els fitxers no modificats com a font per a trobar còpies"
+#: diff.c
msgid "disable rename detection"
msgstr "inhabilita la detecció de canvis de nom"
+#: diff.c
msgid "use empty blobs as rename source"
msgstr "usa els blobs buits com a font de canvi de nom"
+#: diff.c
msgid "continue listing the history of a file beyond renames"
msgstr "continua llistant l'històric d'un fitxer més enllà dels canvis de nom"
+#: diff.c
msgid ""
"prevent rename/copy detection if the number of rename/copy targets exceeds "
"given limit"
@@ -16008,124 +20653,154 @@ msgstr ""
"evita la detecció de canvi de nom/còpia si el nombre d'objectius de canvi de "
"nom/còpia supera el límit indicat"
+#: diff.c
msgid "Diff algorithm options"
msgstr "Opcions de l'algorisme Diff"
+#: diff.c
msgid "produce the smallest possible diff"
msgstr "produeix el diff més petit possible"
+#: diff.c
msgid "ignore whitespace when comparing lines"
msgstr "ignora els espais en blanc en comparar línies"
+#: diff.c
msgid "ignore changes in amount of whitespace"
msgstr "ignora els canvis en la quantitat d'espai en blanc"
+#: diff.c
msgid "ignore changes in whitespace at EOL"
msgstr "ignora els canvis d'espai en blanc al final de la línia"
+#: diff.c
msgid "ignore carrier-return at the end of line"
msgstr "ignora els retorns de línia al final de la línia"
+#: diff.c
msgid "ignore changes whose lines are all blank"
msgstr "ignora els canvis en línies que estan en blanc"
+#: diff.c
msgid "<regex>"
-msgstr "<regex>"
+msgstr "<expr-reg>"
+#: diff.c
msgid "ignore changes whose all lines match <regex>"
-msgstr "ignora els canvis en les línies que coincideixen amb <regex>"
+msgstr "ignora els canvis en les línies que coincideixen amb <expr-reg>"
+#: diff.c
msgid "heuristic to shift diff hunk boundaries for easy reading"
msgstr ""
"heurística per a desplaçar els límits del tros de diferència per a una "
"lectura fàcil"
+#: diff.c
msgid "generate diff using the \"patience diff\" algorithm"
msgstr "genera diff usant l'algorisme «patience diff»"
+#: diff.c
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "genera diff usant l'algorisme «histogram diff»"
-msgid "<algorithm>"
-msgstr "<algorisme>"
-
-msgid "choose a diff algorithm"
-msgstr "trieu un algorisme per al diff"
-
+#: diff.c
msgid "<text>"
msgstr "<text>"
+#: diff.c
msgid "generate diff using the \"anchored diff\" algorithm"
msgstr "genera diff usant l'algorisme «anchored diff»"
+#: diff.c
msgid "<mode>"
msgstr "<mode>"
+#: diff.c
msgid "show word diff, using <mode> to delimit changed words"
msgstr ""
"mostra el diff de paraules usant <mode> per a delimitar les paraules "
"modificades"
+#: diff.c
msgid "use <regex> to decide what a word is"
-msgstr "utilitza <regex> per a decidir què és una paraula"
+msgstr "utilitza <expr-reg> per a decidir què és una paraula"
+#: diff.c
msgid "equivalent to --word-diff=color --word-diff-regex=<regex>"
-msgstr "equivalent a --word-diff=color --word-diff-regex=<regex>"
+msgstr "equivalent a --word-diff=color --word-diff-regex=<expr-reg>"
+#: diff.c
msgid "moved lines of code are colored differently"
msgstr "les línies de codi que s'han mogut s'acoloreixen diferent"
+#: diff.c
msgid "how white spaces are ignored in --color-moved"
msgstr "com s'ignoren els espais en blanc a --color-moved"
+#: diff.c
msgid "Other diff options"
msgstr "Altres opcions diff"
+#: diff.c
msgid "when run from subdir, exclude changes outside and show relative paths"
msgstr ""
"quan s'executa des d'un subdirectori, exclou els canvis de fora i mostra els "
"camins relatius"
+#: diff.c
msgid "treat all files as text"
msgstr "tracta tots els fitxers com a text"
+#: diff.c
msgid "swap two inputs, reverse the diff"
msgstr "intercanvia les dues entrades, inverteix el diff"
+#: diff.c
msgid "exit with 1 if there were differences, 0 otherwise"
msgstr "surt amb 1 si hi ha diferències, 0 en cas contrari"
+#: diff.c
msgid "disable all output of the program"
msgstr "inhabilita totes les sortides del programa"
+#: diff.c
msgid "allow an external diff helper to be executed"
msgstr "permet executar un ajudant de diff extern"
+#: diff.c
msgid "run external text conversion filters when comparing binary files"
msgstr ""
"executa els filtres externs de conversió de text en comparar fitxers binaris"
+#: diff.c
msgid "<when>"
msgstr "<quan>"
+#: diff.c
msgid "ignore changes to submodules in the diff generation"
msgstr "ignora els canvis als submòduls en la generació del diff"
+#: diff.c
msgid "<format>"
msgstr "<format>"
+#: diff.c
msgid "specify how differences in submodules are shown"
msgstr "especifiqueu com es mostren els canvis als submòduls"
+#: diff.c
msgid "hide 'git add -N' entries from the index"
msgstr "amaga les entrades «git add -N» de l'índex"
+#: diff.c
msgid "treat 'git add -N' entries as real in the index"
msgstr "tracta les entrades «git add -N» com a reals a l'índex"
+#: diff.c
msgid "<string>"
msgstr "<cadena>"
+#: diff.c
msgid ""
"look for differences that change the number of occurrences of the specified "
"string"
@@ -16133,6 +20808,7 @@ msgstr ""
"cerca les diferències que canvien el nombre d'ocurrències de la cadena "
"especificada"
+#: diff.c
msgid ""
"look for differences that change the number of occurrences of the specified "
"regex"
@@ -16140,27 +20816,35 @@ msgstr ""
"cerca les diferències que canvien el nombre d'ocurrències de l'expressió "
"regular especificada"
+#: diff.c
msgid "show all changes in the changeset with -S or -G"
msgstr "mostra tots els canvis amb el conjunt de canvis amb -S o -G"
+#: diff.c
msgid "treat <string> in -S as extended POSIX regular expression"
msgstr "tracta <cadena> a -S com a expressió regular POSIX ampliada"
+#: diff.c
msgid "control the order in which files appear in the output"
msgstr "controla l'ordre amb el qual els fitxers apareixen en la sortida"
+#: diff.c
msgid "<path>"
msgstr "<camí>"
+#: diff.c
msgid "show the change in the specified path first"
msgstr "mostra el canvi primer al camí especificat"
+#: diff.c
msgid "skip the output to the specified path"
msgstr "omet la sortida al camí especificat"
+#: diff.c
msgid "<object-id>"
msgstr "<id de l'objecte>"
+#: diff.c
msgid ""
"look for differences that change the number of occurrences of the specified "
"object"
@@ -16168,26 +20852,33 @@ msgstr ""
"cerca les diferències que canvien el nombre d'ocurrències de l'objecte "
"especificat"
+#: diff.c
msgid "[(A|C|D|M|R|T|U|X|B)...[*]]"
msgstr "[(A|C|D|M|R|T|U|X|B)...[*]]"
+#: diff.c
msgid "select files by diff type"
msgstr "seleccioneu els fitxers per tipus de diff"
+#: diff.c
msgid "<file>"
msgstr "<fitxer>"
+#: diff.c
msgid "output to a specific file"
msgstr "sortida a un fitxer específic"
+#: diff.c
msgid "exhaustive rename detection was skipped due to too many files."
msgstr ""
"s'ha omès la detecció de canvi de nom exhaustiva perquè hi ha massa fitxers."
+#: diff.c
msgid "only found copies from modified paths due to too many files."
msgstr ""
"només s'han trobat còpies des de camins modificats perquè de massa fitxers."
+#: diff.c
#, c-format
msgid ""
"you may want to set your %s variable to at least %d and retry the command."
@@ -16195,50 +20886,62 @@ msgstr ""
"potser voleu establir la vostra variable %s a almenys %d i tornar a intentar "
"l'ordre."
+#: diffcore-order.c
#, c-format
msgid "failed to read orderfile '%s'"
msgstr "s'ha produït un error en llegir el fitxer d'ordres «%s»"
+#: diffcore-rename.c
msgid "Performing inexact rename detection"
msgstr "S'està realitzant una detecció inexacta de canvis de nom"
+#: diffcore-rotate.c
#, c-format
msgid "No such path '%s' in the diff"
msgstr "No existeix el camí «%s» al diff"
+#: dir.c
#, c-format
msgid "pathspec '%s' did not match any file(s) known to git"
msgstr ""
"l'especificació de camí «%s» no ha coincidit amb cap fitxer que git conegui"
+#: dir.c
#, c-format
msgid "unrecognized pattern: '%s'"
msgstr "patró no reconegut: «%s»"
+#: dir.c
#, c-format
msgid "unrecognized negative pattern: '%s'"
msgstr "patró negatiu no reconegut: «%s»"
+#: dir.c
#, c-format
msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
msgstr ""
"el vostre fitxer «sparse-checkout» pot tenir problemes el patró «%s» es "
"repeteix"
+#: dir.c
msgid "disabling cone pattern matching"
msgstr "inhabilita la coincidència de patrons «cone»"
+#: dir.c
#, c-format
msgid "cannot use %s as an exclude file"
msgstr "no es pot usar %s com a fitxer d'exclusió"
+#: dir.c
msgid "failed to get kernel name and information"
msgstr "s'ha produït un error en obtenir el nombre i la informació del nucli"
+#: dir.c
msgid "untracked cache is disabled on this system or location"
msgstr ""
"la memòria cau no seguida està inhabilitada en aquest sistema o ubicació"
+#: dir.c
msgid ""
"No directory name could be guessed.\n"
"Please specify a directory on the command line"
@@ -16246,191 +20949,243 @@ msgstr ""
"No s'ha pogut deduir cap nom de directori.\n"
"Especifiqueu un directori en la línia d'ordres"
+#: dir.c
#, c-format
msgid "index file corrupt in repo %s"
msgstr "el fitxer d'índex al repositori %s és malmès"
+#: dir.c
#, c-format
msgid "could not create directories for %s"
msgstr "no s'han pogut crear directoris per %s"
+#: dir.c
#, c-format
msgid "could not migrate git directory from '%s' to '%s'"
msgstr "no s'ha pogut migrar el directori de «%s» a «%s»"
+#: editor.c
#, c-format
msgid "hint: Waiting for your editor to close the file...%c"
msgstr "consell: s'està esperant que el vostre editor tanqui el fitxer...%c"
+#: editor.c sequencer.c wrapper.c
#, c-format
msgid "could not write to '%s'"
msgstr "no s'ha pogut escriure a «%s»"
+#: editor.c
#, c-format
msgid "could not edit '%s'"
msgstr "no s'ha pogut editar «%s»"
+#: entry.c
msgid "Filtering content"
msgstr "S'està filtrant el contingut"
+#: entry.c
#, c-format
msgid "could not stat file '%s'"
msgstr "no s'ha pogut fer «stat» sobre el fitxer «%s»"
+#: environment.c
#, c-format
msgid "bad git namespace path \"%s\""
msgstr "camí d'espai de noms git incorrecte «%s»"
+#: exec-cmd.c
#, c-format
msgid "too many args to run %s"
msgstr "hi ha massa arguments per a executar %s"
+#: fetch-pack.c
msgid "git fetch-pack: expected shallow list"
msgstr "git fetch-pack: llista shallow esperada"
+#: fetch-pack.c
msgid "git fetch-pack: expected a flush packet after shallow list"
msgstr ""
"git fetch-pack: s'esperava un paquet de buidatge després d'una llista shallow"
+#: fetch-pack.c
msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
msgstr "git fetch-pack: s'esperava ACK/NAK, s'ha rebut un paquet de buidatge"
+#: fetch-pack.c
#, c-format
msgid "git fetch-pack: expected ACK/NAK, got '%s'"
msgstr "git fetch-pack: s'esperava ACK/NAK, s'ha rebut «%s»"
+#: fetch-pack.c
msgid "unable to write to remote"
msgstr "no s'ha pogut escriure al remot"
+#: fetch-pack.c
msgid "Server supports filter"
msgstr "El servidor accepta filtratge"
+#: fetch-pack.c
#, c-format
msgid "invalid shallow line: %s"
msgstr "línia de shallow no vàlida: %s"
+#: fetch-pack.c
#, c-format
msgid "invalid unshallow line: %s"
msgstr "línia d'unshallow no vàlida: %s"
+#: fetch-pack.c
#, c-format
msgid "object not found: %s"
msgstr "objecte no trobat: %s"
+#: fetch-pack.c
#, c-format
msgid "error in object: %s"
msgstr "error en objecte: %s"
+#: fetch-pack.c
#, c-format
msgid "no shallow found: %s"
msgstr "no s'ha trobat cap shallow: %s"
+#: fetch-pack.c
#, c-format
msgid "expected shallow/unshallow, got %s"
msgstr "s'esperava shallow/unshallow, s'ha rebut %s"
+#: fetch-pack.c
#, c-format
msgid "got %s %d %s"
msgstr "s'ha rebut %s %d %s"
+#: fetch-pack.c
#, c-format
msgid "invalid commit %s"
msgstr "comissió no vàlida %s"
+#: fetch-pack.c
msgid "giving up"
msgstr "s'abandona"
+#: fetch-pack.c progress.h
msgid "done"
msgstr "fet"
+#: fetch-pack.c
#, c-format
msgid "got %s (%d) %s"
msgstr "s'ha rebut %s (%d) %s"
+#: fetch-pack.c
#, c-format
msgid "Marking %s as complete"
msgstr "S'està marcant %s com a complet"
+#: fetch-pack.c
#, c-format
msgid "already have %s (%s)"
msgstr "ja es té %s (%s)"
+#: fetch-pack.c
msgid "fetch-pack: unable to fork off sideband demultiplexer"
msgstr "fetch-pack: no s'ha pogut bifurcar del desmultiplexor de banda lateral"
+#: fetch-pack.c
msgid "protocol error: bad pack header"
msgstr "error de protocol: capçalera de paquet errònia"
+#: fetch-pack.c
#, c-format
msgid "fetch-pack: unable to fork off %s"
msgstr "fetch-pack: no es pot bifurcar de %s"
+#: fetch-pack.c
msgid "fetch-pack: invalid index-pack output"
msgstr "fetch-pack: sortida d'index-pack no vàlida"
+#: fetch-pack.c
#, c-format
msgid "%s failed"
msgstr "%s ha fallat"
+#: fetch-pack.c
msgid "error in sideband demultiplexer"
msgstr "error en desmultiplexor de banda lateral"
+#: fetch-pack.c
#, c-format
msgid "Server version is %.*s"
msgstr "La versió del servidor és %.*s"
+#: fetch-pack.c
#, c-format
msgid "Server supports %s"
msgstr "El servidor accepta %s"
+#: fetch-pack.c
msgid "Server does not support shallow clients"
msgstr "El servidor no permet clients superficials"
+#: fetch-pack.c
msgid "Server does not support --shallow-since"
msgstr "El servidor no admet --shallow-since"
+#: fetch-pack.c
msgid "Server does not support --shallow-exclude"
msgstr "El servidor no admet --shallow-exclude"
+#: fetch-pack.c
msgid "Server does not support --deepen"
msgstr "El servidor no admet --deepen"
+#: fetch-pack.c
msgid "Server does not support this repository's object format"
msgstr ""
"El servidor no és compatible amb el format d'objecte d'aquest repositori"
+#: fetch-pack.c
msgid "no common commits"
msgstr "cap comissió en comú"
+#: fetch-pack.c
msgid "git fetch-pack: fetch failed."
msgstr "git fetch-pack: l'obtenció ha fallat."
+#: fetch-pack.c
#, c-format
msgid "mismatched algorithms: client %s; server %s"
msgstr "algoritmes no coincidents: client %s; servidor %s"
+#: fetch-pack.c
#, c-format
msgid "the server does not support algorithm '%s'"
msgstr "el servidor no és compatible amb l'algorisme «%s»"
+#: fetch-pack.c
msgid "Server does not support shallow requests"
msgstr "El servidor no permet sol·licituds superficials"
+#: fetch-pack.c
msgid "unable to write request to remote"
msgstr "no s'ha pogut escriure la sol·licitud al remot"
+#: fetch-pack.c
#, c-format
msgid "expected '%s', received '%s'"
msgstr "s'esperava «%s», s'ha rebut «%s»"
+#: fetch-pack.c
#, c-format
msgid "expected '%s'"
msgstr "s'esperava «%s»"
+#: fetch-pack.c
#, c-format
msgid "unexpected acknowledgment line: '%s'"
msgstr "línia de confirmació inesperada: «%s»"
+#: fetch-pack.c
#, c-format
msgid "error processing acks: %d"
msgstr "s'ha produït un error en processar els acks: %d"
@@ -16438,6 +21193,7 @@ msgstr "s'ha produït un error en processar els acks: %d"
#. TRANSLATORS: The parameter will be 'ready', a protocol
#. keyword.
#.
+#: fetch-pack.c
#, c-format
msgid "expected packfile to be sent after '%s'"
msgstr "s'esperava que el fitxer de paquet s'enviés després de «%s»"
@@ -16445,74 +21201,93 @@ msgstr "s'esperava que el fitxer de paquet s'enviés després de «%s»"
#. TRANSLATORS: The parameter will be 'ready', a protocol
#. keyword.
#.
+#: fetch-pack.c
#, c-format
msgid "expected no other sections to be sent after no '%s'"
msgstr "no s'esperava que cap altra secció s'enviés després de «%s»"
+#: fetch-pack.c
#, c-format
msgid "error processing shallow info: %d"
msgstr "s'ha produït un error en processar la informació superficial: %d"
+#: fetch-pack.c
#, c-format
msgid "expected wanted-ref, got '%s'"
msgstr "s'esperava wanted-ref, s'ha rebut «%s»"
+#: fetch-pack.c
#, c-format
msgid "unexpected wanted-ref: '%s'"
msgstr "wanted-ref inesperat: «%s»"
+#: fetch-pack.c
#, c-format
msgid "error processing wanted refs: %d"
msgstr "s'ha produït un error en processar les referències desitjades: %d"
+#: fetch-pack.c
msgid "git fetch-pack: expected response end packet"
msgstr "git fetch-pack: s'esperava un paquet de final de resposta"
+#: fetch-pack.c
msgid "no matching remote head"
msgstr "no hi ha cap HEAD remot coincident"
+#: fetch-pack.c
msgid "unexpected 'ready' from remote"
msgstr "«ready» no esperat des del remot"
+#: fetch-pack.c
#, c-format
msgid "no such remote ref %s"
msgstr "no existeix la referència remota %s"
+#: fetch-pack.c
#, c-format
msgid "Server does not allow request for unadvertised object %s"
msgstr "El servidor no permet sol·licitar objectes no anunciats %s"
+#: fsmonitor-ipc.c
#, c-format
msgid "fsmonitor_ipc__send_query: invalid path '%s'"
msgstr "fsmonitor_ipc__send_query: camí no vàlid «%s»"
+#: fsmonitor-ipc.c
#, c-format
msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
msgstr "fsmonitor_ipc__send_query: error no especificat en «%s»"
+#: fsmonitor-ipc.c
msgid "fsmonitor--daemon is not running"
msgstr "fsmonitor--daemon no s'està executant"
+#: fsmonitor-ipc.c
#, c-format
msgid "could not send '%s' command to fsmonitor--daemon"
msgstr "no s'ha pogut enviar l'ordre «%s» a fsmonitor--daemon"
+#: fsmonitor-settings.c
#, c-format
msgid "bare repository '%s' is incompatible with fsmonitor"
msgstr "el repositori nu «%s» és incompatible amb fsmonitor"
+#: fsmonitor-settings.c
#, c-format
msgid "repository '%s' is incompatible with fsmonitor due to errors"
msgstr "el repositori «%s» és incompatible amb fsmonitor a causa d'errors"
+#: fsmonitor-settings.c
#, c-format
msgid "remote repository '%s' is incompatible with fsmonitor"
msgstr "el repositori remot «%s» no és compatible amb fsmonitor"
+#: fsmonitor-settings.c
#, c-format
msgid "virtual repository '%s' is incompatible with fsmonitor"
msgstr "el repositori virtual «%s» és incompatible amb fsmonitor"
+#: fsmonitor-settings.c
#, c-format
msgid ""
"socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
@@ -16521,21 +21296,27 @@ msgstr ""
"el directori del sòcol «%s» és incompatible amb fsmonitor a causa de la "
"manca de compatibilitat amb els sòcols Unix"
+#: git.c
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 <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>]"
-
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
+msgstr ""
+"git [-v | --version] [-h | --help] [-C <camí>] [-c <nom>=<valor>]\n"
+" [--exec-path[=<camí>]] [--html-path] [--man-path] [--info-path]\n"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<camí>]\n"
+" [--work-tree=<camí>] [--namespace=<nom>] [--config-"
+"env=<nom>=<variable-d-entorn>]\n"
+" <ordre> [<arguments>]"
+
+#: git.c
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"
@@ -16547,38 +21328,47 @@ msgstr ""
"«git help <concepte>» per a llegir sobre una subordre o concepte\n"
"específic. Vegeu «git help git» per a una visió general del sistema."
+#: git.c help.c
#, c-format
msgid "unsupported command listing type '%s'"
msgstr "tipus de llistat de l'ordre no compatible «%s»"
+#: git.c
#, c-format
msgid "no directory given for '%s' option\n"
msgstr "no s'ha especificat un directori per a l'opció «%s»\n"
+#: git.c
#, c-format
msgid "no namespace given for --namespace\n"
msgstr "no s'ha especificat un nom d'espai per --namespace\n"
+#: git.c
#, c-format
msgid "-c expects a configuration string\n"
msgstr "-c espera una cadena de configuració\n"
+#: git.c
#, c-format
msgid "no config key given for --config-env\n"
msgstr "no s'ha indicat cap clau de configuració per a --config-env\n"
+#: git.c
#, c-format
msgid "no attribute source given for --attr-source\n"
msgstr "no s'ha donat d'atribut font per a --attr-source\n"
+#: git.c
#, c-format
msgid "unknown option: %s\n"
msgstr "opció desconeguda: %s\n"
+#: git.c
#, c-format
msgid "while expanding alias '%s': '%s'"
msgstr "en expandir l'àlies «%s»: «%s»"
+#: git.c
#, c-format
msgid ""
"alias '%s' changes environment variables.\n"
@@ -16587,31 +21377,39 @@ msgstr ""
"l'àlies «%s» canvia variables d'entorn.\n"
"Podeu utilitzar «!git» a l'àlies per a fer-ho"
+#: git.c
#, c-format
msgid "empty alias for %s"
msgstr "àlies buit per a %s"
+#: git.c
#, c-format
msgid "recursive alias: %s"
msgstr "àlies recursiu: %s"
+#: git.c
msgid "write failure on standard output"
msgstr "fallada d'escriptura en la sortida estàndard"
+#: git.c
msgid "unknown write failure on standard output"
msgstr "fallada d'escriptura desconeguda en la sortida estàndard"
+#: git.c
msgid "close failed on standard output"
msgstr "ha fallat el tancament en la sortida estàndard"
+#: git.c
#, c-format
msgid "alias loop detected: expansion of '%s' does not terminate:%s"
msgstr "bucle d'àlies detectat expansió de «%s» no acaba:%s"
+#: git.c
#, c-format
msgid "cannot handle %s as a builtin"
msgstr "no es pot gestionar %s com a integrat"
+#: git.c
#, c-format
msgid ""
"usage: %s\n"
@@ -16620,21 +21418,26 @@ msgstr ""
"ús: %s\n"
"\n"
+#: git.c
#, c-format
msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
msgstr "ha fallat l'expansió de l'àlies «%s»; «%s» no és una ordre git\n"
+#: git.c
#, c-format
msgid "failed to run command '%s': %s\n"
msgstr "s'ha produït un error en executar l'ordre «%s»: %s\n"
+#: gpg-interface.c
msgid "could not create temporary file"
msgstr "no s'ha pogut crear el fitxer temporal"
+#: gpg-interface.c
#, c-format
msgid "failed writing detached signature to '%s'"
msgstr "s'ha produït un error en escriure la clau de signatura separada a «%s»"
+#: gpg-interface.c
msgid ""
"gpg.ssh.allowedSignersFile needs to be configured and exist for ssh "
"signature verification"
@@ -16642,6 +21445,7 @@ msgstr ""
"gpg.ssh.allowedSignersFile s'ha de configurar i existeix per a la "
"verificació de la signatura ssh"
+#: gpg-interface.c
msgid ""
"ssh-keygen -Y find-principals/verify is needed for ssh signature "
"verification (available in openssh version 8.2p1+)"
@@ -16649,32 +21453,39 @@ msgstr ""
"ssh-keygen -Y find-principals/verify és necessari per a la verificació de la "
"signatura ssh (disponible a opensh versió 8.2p1+)"
+#: gpg-interface.c
#, c-format
msgid "ssh signing revocation file configured but not found: %s"
msgstr "fitxer de revocació de la signatura ssh configurat però no trobat: %s"
+#: gpg-interface.c
#, c-format
msgid "bad/incompatible signature '%s'"
msgstr "la signatura «%s» és incompatible o està malmesa"
+#: gpg-interface.c
#, c-format
msgid "failed to get the ssh fingerprint for key '%s'"
msgstr "no s'ha pogut obtenir l'empremta ssh de la clau «%s»"
+#: gpg-interface.c
msgid ""
"either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"
msgstr ""
"o bé user.signingkey o gpg.ssh.defaultKeyCommand han de ser configurats"
+#: gpg-interface.c
#, c-format
msgid "gpg.ssh.defaultKeyCommand succeeded but returned no keys: %s %s"
msgstr ""
"gpg.ssh.defaultKeyCommand ha tingut èxit però no ha retornat cap clau: %s %s"
+#: gpg-interface.c
#, c-format
msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
msgstr "gpg.ssh.defaultKeyCommand ha fallat: %s %s"
+#: gpg-interface.c
#, c-format
msgid ""
"gpg failed to sign the data:\n"
@@ -16683,17 +21494,21 @@ msgstr ""
"gpg ha fallat en signar les dades:\n"
"%s"
+#: gpg-interface.c
msgid "user.signingKey needs to be set for ssh signing"
msgstr "user.signingKey s'ha d'establir per a signar amb ssh"
+#: gpg-interface.c
#, c-format
msgid "failed writing ssh signing key to '%s'"
msgstr "s'ha produït un error en escriure la clau de signatura ssh a «%s»"
+#: gpg-interface.c
#, c-format
msgid "failed writing ssh signing key buffer to '%s'"
msgstr "s'ha produït un error en escriure la clau de signatura ssh a «%s»"
+#: gpg-interface.c
msgid ""
"ssh-keygen -Y sign is needed for ssh signing (available in openssh version "
"8.2p1+)"
@@ -16701,102 +21516,132 @@ msgstr ""
"ssh-keygen -Y sign és necessari per a signar amb ssh (disponible a openssh "
"versió 8.2p1+)"
+#: gpg-interface.c
#, c-format
msgid "failed reading ssh signing data buffer from '%s'"
msgstr "s'ha produït un error en llegir la signatura ssh des de «%s»"
+#: graph.c
#, c-format
msgid "ignored invalid color '%.*s' in log.graphColors"
msgstr "ignora el color no vàlid «%.*s» a log.graphColors"
+#: grep.c
msgid ""
"given pattern contains NULL byte (via -f <file>). This is only supported "
"with -P under PCRE v2"
msgstr ""
-"el patró indicat conté byte NULL (via -f <fitxer>). Això només és compatible "
-"amb -P sota PCRE v2"
+"el patró indicat conté l'octet NULL (via -f <fitxer>). Això només és "
+"compatible amb -P sota PCRE v2"
+#: grep.c
#, c-format
msgid "'%s': unable to read %s"
msgstr "«%s»: no s'ha pogut llegir %s"
+#: grep.c
#, c-format
msgid "'%s': short read"
msgstr "«%s»: lectura curta"
+#: help.c
msgid "start a working area (see also: git help tutorial)"
msgstr "començar una àrea de treball (vegeu també: git help tutorial)"
+#: help.c
msgid "work on the current change (see also: git help everyday)"
msgstr "treballar en el canvi actual (vegeu també: git help everyday)"
+#: help.c
msgid "examine the history and state (see also: git help revisions)"
msgstr "examinar la història i l'estat (vegeu també: git help revisions)"
+#: help.c
msgid "grow, mark and tweak your common history"
msgstr "fer créixer, marcar i ajustar la vostra història comuna"
+#: help.c
msgid "collaborate (see also: git help workflows)"
msgstr "col·laborar (vegeu també: git help workflow)"
+#: help.c
msgid "Main Porcelain Commands"
msgstr "Ordres principals de porcellana"
+#: help.c
msgid "Ancillary Commands / Manipulators"
msgstr "Ordres auxiliars / manipuladors"
+#: help.c
msgid "Ancillary Commands / Interrogators"
msgstr "Ordres auxiliars / interrogadors"
+#: help.c
msgid "Interacting with Others"
msgstr "Interaccionar amb altres"
+#: help.c
msgid "Low-level Commands / Manipulators"
msgstr "Ordres de baix nivell / Manipuladors"
+#: help.c
msgid "Low-level Commands / Interrogators"
msgstr "Ordres de baix nivell / Interrogadors"
+#: help.c
msgid "Low-level Commands / Syncing Repositories"
msgstr "Ordres de baix nivell / Sincronització de repositoris"
+#: help.c
msgid "Low-level Commands / Internal Helpers"
msgstr "Ordres de baix nivell / Ajudants interns"
+#: help.c
msgid "User-facing repository, command and file interfaces"
msgstr "Repositori, ordre i interfície de fitxers que veu l'usuari"
+#: help.c
msgid "Developer-facing file formats, protocols and other interfaces"
-msgstr "Formats de fitxers, protocols i interfícies que veu el desenvolupador"
+msgstr "Formats de fitxer, protocols i interfícies que veu el desenvolupador"
+#: help.c
#, c-format
msgid "available git commands in '%s'"
msgstr "ordres de git disponibles en «%s»"
+#: help.c
msgid "git commands available from elsewhere on your $PATH"
msgstr "ordres de git disponibles d'altres llocs en el vostre $PATH"
+#: help.c
msgid "These are common Git commands used in various situations:"
msgstr "Aquestes són ordres habituals del Git usades en diverses situacions:"
+#: help.c
msgid "The Git concept guides are:"
msgstr "Les guies de Git de conceptes són:"
+#: help.c
msgid "User-facing repository, command and file interfaces:"
msgstr "Repositori, ordre i interfície de fitxers que veu l'usuari:"
+#: help.c
msgid "File formats, protocols and other developer interfaces:"
msgstr "Formats de fitxer, protocols i altres interfícies de desenvolupador:"
+#: help.c
msgid "External commands"
msgstr "Ordres externes"
+#: help.c
msgid "Command aliases"
msgstr "Àlies d'ordres"
+#: help.c
msgid "See 'git help <command>' to read about a specific subcommand"
msgstr "Vegeu «git help <ordre>» per a llegir sobre una subordre específica"
+#: help.c
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -16805,31 +21650,38 @@ msgstr ""
"«%s» sembla una ordre de git, però no hem pogut\n"
"executar-la. Pot ser que git-%s estigui malmès?"
+#: help.c
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
msgstr "git: «%s» no és una ordre de git. Vegeu «git --help»."
+#: help.c
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Ai. El vostre sistema no informa de cap ordre de Git."
+#: help.c
#, c-format
msgid "WARNING: You called a Git command named '%s', which does not exist."
msgstr ""
"ADVERTÈNCIA: Heu invocat una ordre de Git amb nom «%s», la qual no existeix."
+#: help.c
#, c-format
msgid "Continuing under the assumption that you meant '%s'."
msgstr "El procés continuarà, pressuposant que volíeu dir «%s»."
+#: help.c
#, c-format
msgid "Run '%s' instead [y/N]? "
msgstr "Voleu executar «%s» en el seu lloc? [y/N]? "
+#: help.c
#, c-format
msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
msgstr ""
"El procés continuarà en %0.1f segons, pressuposant que volíeu dir «%s»."
+#: help.c
msgid ""
"\n"
"The most similar command is"
@@ -16843,13 +21695,16 @@ msgstr[1] ""
"\n"
"Les ordres més similars són"
+#: help.c
msgid "git version [--build-options]"
msgstr "git version [--build-options]"
+#: help.c
#, c-format
msgid "%s: %s - %s"
msgstr "%s: %s - %s"
+#: help.c
msgid ""
"\n"
"Did you mean this?"
@@ -16863,6 +21718,7 @@ msgstr[1] ""
"\n"
"Volíeu dir un d'aquests?"
+#: hook.c
#, c-format
msgid ""
"The '%s' hook was ignored because it's not set as executable.\n"
@@ -16871,40 +21727,62 @@ msgstr ""
"El lligam «%s» s'ha ignorat perquè no s'ha establert com a executable.\n"
"Podeu desactivar aquest avís amb «git config advice.ignoredHook false»."
+#: http-fetch.c
+msgid "not a git repository"
+msgstr "no és un repositori de git"
+
+#: http-fetch.c
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "l'argument a --packfile ha de ser un resum vàlid (s'ha obtingut «%s»)"
-msgid "not a git repository"
-msgstr "no és un repositori de git"
-
+#: http.c
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
msgstr "valor negatiu per http.postBuffer; utilitzant el valor %d"
+#: http.c
msgid "Delegation control is not supported with cURL < 7.22.0"
msgstr "No s'admet el control de delegació amb el cURL < 7.22.0"
+#: http.c
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "No s'admet la fixació de clau pública amb cURL < 7.39.0"
+#: http.c
+msgid "Unknown value for http.proactiveauth"
+msgstr "Valor desconegut de http.proactiveauth"
+
+#: http.c
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE no està admès amb cURL < 7.44.0"
+#: http.c
#, c-format
msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
msgstr "El rerefons SSL «%s» no està admès. Els rerefons SSL admesos:"
+#: http.c
#, c-format
msgid "Could not set SSL backend to '%s': cURL was built without SSL backends"
msgstr ""
"No s'ha pogut establir el rerefons SSL a «%s»: cURL es va construir sense "
"rerefons SSL"
+#: http.c
#, c-format
msgid "Could not set SSL backend to '%s': already set"
msgstr "No s'ha pogut establir el rerefons SSL a «%s»: ja establert"
+#: http.c
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "res'ha rebutjat llegir galetes del http.cookiefile «-»"
+
+#: http.c
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "s'està ignorant http.savecookies per al http.cookiefile buit"
+
+#: http.c
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -16915,12 +21793,15 @@ msgstr ""
" petició: %s\n"
" redirecció: %s"
+#: ident.c
msgid "Author identity unknown\n"
msgstr "Identitat de l'autor desconeguda\n"
+#: ident.c
msgid "Committer identity unknown\n"
msgstr "Es desconeix la identitat del comitent\n"
+#: ident.c
msgid ""
"\n"
"*** Please tell me who you are.\n"
@@ -16945,88 +21826,110 @@ msgstr ""
"per a establir la identitat predeterminada del vostre compte.\n"
"Ometeu --global per a establir la identitat només en aquest repositori.\n"
+#: ident.c
msgid "no email was given and auto-detection is disabled"
msgstr ""
"no s'ha proporcionat cap adreça electrònica i la detecció automàtica està "
"inhabilitada"
+#: ident.c
#, c-format
msgid "unable to auto-detect email address (got '%s')"
msgstr ""
"no s'ha pogut detectar automàticament una adreça electrònica vàlida (s'ha "
"rebut «%s»)"
+#: ident.c
msgid "no name was given and auto-detection is disabled"
msgstr ""
"no s'ha proporcionat cap nom i la detecció automàtica està inhabilitada"
+#: ident.c
#, c-format
msgid "unable to auto-detect name (got '%s')"
msgstr "no s'ha pogut detectar automàticament el nom (s'ha rebut «%s»)"
+#: ident.c
#, c-format
msgid "empty ident name (for <%s>) not allowed"
msgstr "nom d'identitat buit (per <%s>) no és permès"
+#: ident.c
#, c-format
msgid "name consists only of disallowed characters: %s"
msgstr "el nom conté només caràcters no permesos: %s"
+#: list-objects-filter-options.c
msgid "expected 'tree:<depth>'"
msgstr "s'esperava «tree:<profunditat>»"
+#: list-objects-filter-options.c
msgid "sparse:path filters support has been dropped"
msgstr "sparse: s'ha eliminat la implementació de filtres de camí sparse"
+#: list-objects-filter-options.c
#, c-format
msgid "'%s' for 'object:type=<type>' is not a valid object type"
msgstr "«%s» per a «object:type=<tipus>» no és un tipus d'objecte vàlid"
+#: list-objects-filter-options.c
#, c-format
msgid "invalid filter-spec '%s'"
msgstr "filtre d'especificació no vàlid: «%s»"
+#: list-objects-filter-options.c
#, c-format
msgid "must escape char in sub-filter-spec: '%c'"
msgstr "cal escapar el caràcter en el sub-filter-spec «%c»"
+#: list-objects-filter-options.c
msgid "expected something after combine:"
msgstr "s'esperava alguna cosa després de combinar:"
+#: list-objects-filter-options.c
msgid "multiple filter-specs cannot be combined"
msgstr "no es poden combinar múltiples especificacions de filtratge"
+#: list-objects-filter-options.c
msgid "unable to upgrade repository format to support partial clone"
msgstr ""
"no s'ha pogut actualitzar el format del repositori perquè sigui compatible "
"amb un clonatge parcial"
+#: list-objects-filter-options.h
msgid "args"
msgstr "arguments"
+#: list-objects-filter-options.h
msgid "object filtering"
msgstr "filtratge d'objecte"
+#: list-objects-filter.c
#, c-format
msgid "unable to access sparse blob in '%s'"
msgstr "no s'ha pogut accedir a un blob dispers en «%s»"
+#: list-objects-filter.c
#, c-format
msgid "unable to parse sparse filter data in %s"
msgstr "no s'han pogut analitzar les dades disperses filtrades %s"
+#: list-objects.c
#, c-format
msgid "entry '%s' in tree %s has tree mode, but is not a tree"
msgstr "l'entrada «%s» a l'arbre %s té mode d'arbre, però no és un arbre"
+#: list-objects.c
#, c-format
msgid "entry '%s' in tree %s has blob mode, but is not a blob"
msgstr "l'entrada «%s» a l'arbre %s té mode blob, però no és un blob"
+#: list-objects.c
#, c-format
msgid "unable to load root tree for commit %s"
msgstr "no s'ha pogut carregar l'arrel de l'arbre per la comissió %s"
+#: lockfile.c
#, c-format
msgid ""
"Unable to create '%s.lock': %s.\n"
@@ -17046,46 +21949,82 @@ msgstr ""
"ha fallat en aquest repositori abans:\n"
"elimineu el fitxer manualment per a continuar."
+#: lockfile.c
#, c-format
msgid "Unable to create '%s.lock': %s"
msgstr "No s'ha pogut crear «%s.lock»: %s"
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "no s'ha pogut crear el directori temporal de l'objecte"
+
+#: loose.c
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "no s'ha pogut escriure l'índex d'objecte solt %s"
+
+#: loose.c
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "no s'ha pogut escriure l'índex d'objectes solts %s"
+
+#: ls-refs.c
#, c-format
msgid "unexpected line: '%s'"
msgstr "línia inesperada: «%s»"
+#: ls-refs.c
msgid "expected flush after ls-refs arguments"
msgstr "s'esperava una neteja després dels arguments ls-refs"
+#: mailinfo.c
msgid "quoted CRLF detected"
msgstr "CRLF entre cometes detectat"
+#: mem-pool.c strbuf.c wrapper.c
+#, c-format
+msgid "unable to format message: %s"
+msgstr "no es pot formatar el missatge: %s"
+
+#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "S'ha produït un error en fusionar el submòdul %s (no està agafat)"
+#: merge-ort.c
#, c-format
msgid "Failed to merge submodule %s (no merge base)"
msgstr "S'ha produït un error en fusionar el submòdul %s (no hi ha fusió base)"
+#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (commits not present)"
msgstr "S'ha produït un error en fusionar el submòdul %s (no hi ha comissions)"
+# corrupt → malmès OK per a repositori?
+#: merge-ort.c
+#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "error: no s'ha pogut fusionar el submòdul %s (repositori malmès)"
+
+#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr ""
"S'ha produït un error en fusionar el submòdul %s (les comissions no "
"segueixen merge-base)"
+#: merge-ort.c
#, c-format
msgid "Note: Fast-forwarding submodule %s to %s"
msgstr "Nota: avançament ràpid del submòdul %s a %s"
+#: merge-ort.c
#, c-format
msgid "Failed to merge submodule %s"
msgstr "S'ha produït un error en fusionar el submòdul «%s»"
+#: merge-ort.c
#, c-format
msgid ""
"Failed to merge submodule %s, but a possible merge resolution exists: %s"
@@ -17093,6 +22032,7 @@ msgstr ""
"S'ha produït un error en fusionar el submòdul %s, però existeix una solució "
"possible: %s"
+#: merge-ort.c
#, c-format
msgid ""
"Failed to merge submodule %s, but multiple possible merges exist:\n"
@@ -17102,17 +22042,22 @@ msgstr ""
"solucions possibles:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "S'ha produït un error en executar la fusió interna"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "no s'ha pogut executar la fusió interna per a %s"
+#: merge-ort.c
#, c-format
-msgid "Unable to add %s to database"
-msgstr "No s'ha pogut afegir %s a la base de dades"
+msgid "error: unable to add %s to database"
+msgstr "error: no es pot afegir %s a la base de dades"
+#: merge-ort.c merge-recursive.c
#, c-format
msgid "Auto-merging %s"
msgstr "S'està autofusionant %s"
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"CONFLICT (implicit dir rename): Existing file/dir at %s in the way of "
@@ -17122,6 +22067,7 @@ msgstr ""
"existent a %s en forma de canvi del nom del directori implícit, posant-hi "
"els camins següents a: %s."
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"CONFLICT (implicit dir rename): Cannot map more than one path to %s; "
@@ -17131,6 +22077,7 @@ msgstr ""
"camí a %s; els canvis del nom del directori implícits han intentat posar "
"aquests camins a: %s segons"
+#: merge-ort.c
#, c-format
msgid ""
"CONFLICT (directory rename split): Unclear where to rename %s to; it was "
@@ -17141,6 +22088,7 @@ msgstr ""
"%s; s'han canviat de nom a múltiples altres directoris, sense una destinació "
"per a la majoria dels fitxers."
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
@@ -17149,6 +22097,7 @@ msgstr ""
"AVÃS: S'està evitant aplicar el canvi de nom %s -> %s a %s, perquè %s ell "
"mateix ja havia canviat de nom."
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"Path updated: %s added in %s inside a directory that was renamed in %s; "
@@ -17157,6 +22106,7 @@ msgstr ""
"Pedaç actualitzat: %s afegit a %s dins d'un directori que va canviar de nom "
"a %s; movent-lo a %s."
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"Path updated: %s renamed to %s in %s, inside a directory that was renamed in "
@@ -17165,6 +22115,7 @@ msgstr ""
"Pedaç actualitzat: %s canviat al nom %s a %s, dins d'un directori que va "
"canviar de nom a %s; movent-lo a %s."
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"CONFLICT (file location): %s added in %s inside a directory that was renamed "
@@ -17173,6 +22124,7 @@ msgstr ""
"CONFLICTE (ubicació del fitxer): %s afegit a %s dins d'un directori que va "
"canviar de nom a %s suggerint que potser hauria de moure's a %s."
+#: merge-ort.c merge-recursive.c
#, c-format
msgid ""
"CONFLICT (file location): %s renamed to %s in %s, inside a directory that "
@@ -17182,11 +22134,13 @@ msgstr ""
"directori que va canviar de nom a %s, suggerint que potser hauria de moure's "
"a %s."
+#: merge-ort.c
#, c-format
msgid "CONFLICT (rename/rename): %s renamed to %s in %s and to %s in %s."
msgstr ""
"CONFLICTE (canvi de nom/canvi de nom): %s ara té el nom %s a %s i %s a %s."
+#: merge-ort.c
#, c-format
msgid ""
"CONFLICT (rename involved in collision): rename of %s -> %s has content "
@@ -17197,20 +22151,24 @@ msgstr ""
"%s té conflictes de contingut i col·lisiona amb un altre camí; això pot "
"donar lloc a marcadors de conflicte imbricats."
+#: merge-ort.c
#, c-format
msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s."
msgstr ""
"CONFLICTE (canvi de nom/supressió): %s ara té el nom %s a %s, però s'ha "
"suprimit a %s."
+#: merge-ort.c
#, c-format
-msgid "cannot read object %s"
-msgstr "no es pot llegir l'objecte %s"
+msgid "error: cannot read object %s"
+msgstr "error: no es pot llegir l'objecte %s"
+#: merge-ort.c
#, c-format
-msgid "object %s is not a blob"
-msgstr "l'objecte %s no és un blob"
+msgid "error: object %s is not a blob"
+msgstr "error: l'objecte %s no és un blob"
+#: merge-ort.c
#, c-format
msgid ""
"CONFLICT (file/directory): directory in the way of %s from %s; moving it to "
@@ -17219,6 +22177,7 @@ msgstr ""
"CONFLICTE (fitxer/directori): directori en el camí de %s des de %s; en "
"comptes es mou a %s."
+#: merge-ort.c
#, c-format
msgid ""
"CONFLICT (distinct types): %s had different types on each side; renamed both "
@@ -17227,6 +22186,7 @@ msgstr ""
"CONFLICTE (tipus diferents): %s tenia diferents tipus a cada costat; se'ls "
"ha canviat el nom per tal que cadascun pugui ser registrat en algun lloc."
+#: merge-ort.c
#, c-format
msgid ""
"CONFLICT (distinct types): %s had different types on each side; renamed one "
@@ -17236,19 +22196,24 @@ msgstr ""
"canviat el nom d'un d'ells per tal que cadascun pugui ser registrat en algun "
"lloc."
+#: merge-ort.c merge-recursive.c
msgid "content"
msgstr "contingut"
+#: merge-ort.c merge-recursive.c
msgid "add/add"
msgstr "afegiment/afegiment"
+#: merge-ort.c merge-recursive.c
msgid "submodule"
msgstr "submòdul"
+#: merge-ort.c merge-recursive.c
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
msgstr "CONFLICTE (%s): Conflicte de fusió en %s"
+#: merge-ort.c
#, c-format
msgid ""
"CONFLICT (modify/delete): %s deleted in %s and modified in %s. Version %s "
@@ -17263,6 +22228,7 @@ msgstr ""
#. commit that needs to be merged. For example:
#. - go to submodule (mysubmodule), and either merge commit abc1234"
#.
+#: merge-ort.c
#, c-format
msgid ""
" - go to submodule (%s), and either merge commit %s\n"
@@ -17271,6 +22237,7 @@ msgstr ""
" - aneu al submòdul (%s), i fusioneu la comissió %s\n"
" o actualitzeu-la a una comissió existent que ha fusionat aquests canvis\n"
+#: merge-ort.c
#, c-format
msgid ""
"Recursive merging with submodules currently only supports trivial cases.\n"
@@ -17298,75 +22265,98 @@ 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.
#.
+#: merge-ort.c
#, c-format
msgid "collecting merge info failed for trees %s, %s, %s"
msgstr ""
"ha fallat la recollida de la informació de fusió per als arbres %s, %s, %s"
+#: merge-recursive.c
msgid "(bad commit)\n"
msgstr "(comissió errònia)\n"
+#: merge-recursive.c
#, c-format
msgid "add_cacheinfo failed for path '%s'; merge aborting."
msgstr "add_cacheinfo ha fallat per al camí «%s»; interrompent la fusió."
+#: merge-recursive.c
#, c-format
msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
msgstr ""
"add_cacheinfo ha fallat al refrescar el camí «%s»; interrompent la fusió."
+#: merge-recursive.c
#, c-format
msgid "failed to create path '%s'%s"
msgstr "s'ha produït un error en crear el camí «%s»%s"
+#: merge-recursive.c
#, c-format
msgid "Removing %s to make room for subdirectory\n"
msgstr "S'està eliminant %s per a fer espai per al subdirectori\n"
+#: merge-recursive.c
msgid ": perhaps a D/F conflict?"
msgstr ": potser un conflicte D/F?"
+#: merge-recursive.c
#, c-format
msgid "refusing to lose untracked file at '%s'"
msgstr "s'està refusant perdre el fitxer no seguit a «%s»"
+#: merge-recursive.c
#, c-format
msgid "blob expected for %s '%s'"
msgstr "blob esperat per a %s «%s»"
+#: merge-recursive.c
#, c-format
msgid "failed to open '%s': %s"
msgstr "s'ha produït un error en obrir «%s»: %s"
+#: merge-recursive.c
#, c-format
msgid "failed to symlink '%s': %s"
msgstr "s'ha produït un error en fer l'enllaç simbòlic «%s»: %s"
+#: merge-recursive.c
#, c-format
msgid "do not know what to do with %06o %s '%s'"
msgstr "no se sap què fer amb %06o %s «%s»"
+#: merge-recursive.c
+#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "No s'ha pogut fusionar el submòdul %s (repositori malmès)"
+
+#: merge-recursive.c
#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "Avançament ràpid del submòdul %s a la següent comissió:"
+#: merge-recursive.c
#, c-format
msgid "Fast-forwarding submodule %s"
msgstr "Avançament ràpid al submòdul %s"
+#: merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (merge following commits not found)"
msgstr ""
"Ha fallat en fusionar el submòdul %s (no s'ha trobat les comissions següents)"
+#: merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (not fast-forward)"
msgstr ""
"S'ha produït un error en fusionar el submòdul %s (sense avançament ràpid)"
+#: merge-recursive.c
msgid "Found a possible merge resolution for the submodule:\n"
msgstr "S'ha trobat una possible resolució de fusió pel submòdul:\n"
+#: merge-recursive.c
#, c-format
msgid ""
"If this is correct simply add it to the index for example\n"
@@ -17383,18 +22373,30 @@ msgstr ""
"\n"
"que acceptarà aquest suggeriment.\n"
+#: merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (multiple merges found)"
msgstr ""
"S'ha produït un error en fusionar el submòdul %s (s'han trobat múltiples "
"fusions)"
+#: merge-recursive.c
+msgid "failed to execute internal merge"
+msgstr "no s'ha pogut executar la fusió interna"
+
+#: merge-recursive.c
+#, c-format
+msgid "unable to add %s to database"
+msgstr "no s'ha pogut afegir %s a la base de dades"
+
+#: merge-recursive.c
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
"Error: s'està refusant perdre el fitxer no seguit a %s; en comptes s'ha "
"escrit a %s."
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -17403,6 +22405,7 @@ msgstr ""
"CONFLICTE: (%s/supressió): %s suprimit en %s i %s en %s. La versió %s de %s "
"s'ha deixat en l'arbre."
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s to %s in %s. Version %s of %s "
@@ -17411,6 +22414,7 @@ msgstr ""
"CONFLICTE: (%s/supressió): %s suprimit en %s i %s a %s en %s. La versió %s "
"de %s s'ha deixat en l'arbre."
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -17419,6 +22423,7 @@ msgstr ""
"CONFLICTE: (%s/supressió): %s suprimit en %s i %s en %s. La versió %s de %s "
"s'ha deixat en l'arbre a %s."
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s to %s in %s. Version %s of %s "
@@ -17427,38 +22432,46 @@ msgstr ""
"CONFLICTE: (%s/supressió): %s suprimit en %s i %s a %s en %s. La versió %s "
"de %s s'ha deixat en l'arbre a %s."
+#: merge-recursive.c
msgid "rename"
msgstr "canvi de nom"
+#: merge-recursive.c
msgid "renamed"
msgstr "canviat de nom"
+#: merge-recursive.c
#, c-format
msgid "Refusing to lose dirty file at %s"
msgstr "S'està refusant a perdre el fitxer brut a %s"
+#: merge-recursive.c
#, c-format
msgid "Refusing to lose untracked file at %s, even though it's in the way."
msgstr ""
"S'està refusant perdre el fitxer no seguit a «%s», malgrat que està en mig "
"de l'operació."
+#: merge-recursive.c
#, c-format
msgid "CONFLICT (rename/add): Rename %s->%s in %s. Added %s in %s"
msgstr ""
"CONFLICTE (canvi de nom/afegiment): Canvi de nom %s->%s a %s. S'ha afegit "
"%s a %s"
+#: merge-recursive.c
#, c-format
msgid "%s is a directory in %s adding as %s instead"
msgstr "%s és un directori en %s; s'està afegint com a %s en lloc d'això"
+#: merge-recursive.c
#, c-format
msgid "Refusing to lose untracked file at %s; adding as %s instead"
msgstr ""
"S'està refusant perdre el fitxer no seguit a %s; en comptes, s'està afegint "
"com a %s"
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename "
@@ -17467,15 +22480,18 @@ msgstr ""
"CONFLICTE (canvi de nom/canvi de nom): Canvi de nom «%s»->«%s» en la branca "
"«%s» canvi de nom «%s»->«%s» en «%s»%s"
+#: merge-recursive.c
msgid " (left unresolved)"
msgstr " (deixat sense resolució)"
+#: merge-recursive.c
#, c-format
msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
msgstr ""
"CONFLICTE (canvi de nom/canvi de nom): Canvi de nom %s->%s en %s. Canvi de "
"nom %s->%s en %s"
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (directory rename split): Unclear where to place %s because "
@@ -17486,6 +22502,7 @@ msgstr ""
"%s perquè el directori %s s'han canviat de nom a múltiples altres "
"directoris, sense una destinació per a la majoria dels fitxers."
+#: merge-recursive.c
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename directory %s->%s in %s. Rename directory %s-"
@@ -17494,255 +22511,426 @@ msgstr ""
"CONFLICTE (canvi de nom/canvi de nom): canvi de nom %s->%s en %s. Canvi de "
"nom de directori %s->%s en %s"
+#: merge-recursive.c
+#, c-format
+msgid "cannot read object %s"
+msgstr "no es pot llegir l'objecte %s"
+
+#: merge-recursive.c
+#, c-format
+msgid "object %s is not a blob"
+msgstr "l'objecte %s no és un blob"
+
+#: merge-recursive.c
msgid "modify"
msgstr "modificació"
+#: merge-recursive.c
msgid "modified"
msgstr "modificat"
+#: merge-recursive.c
#, c-format
msgid "Skipped %s (merged same as existing)"
msgstr "S'ha omès %s (el fusionat és igual a l'existent)"
+#: merge-recursive.c
#, c-format
msgid "Adding as %s instead"
msgstr "S'està afegint com a %s en lloc d'això"
+#: merge-recursive.c
#, c-format
msgid "Removing %s"
msgstr "S'està eliminant %s"
+#: merge-recursive.c
msgid "file/directory"
msgstr "fitxer/directori"
+#: merge-recursive.c
msgid "directory/file"
msgstr "directori/fitxer"
+#: merge-recursive.c
#, c-format
msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
msgstr ""
"CONFLICTE (%s): Hi ha un directori amb nom %s en %s. S'està afegint %s com a "
"%s"
+#: merge-recursive.c
#, c-format
msgid "Adding %s"
msgstr "S'està afegint %s"
+#: merge-recursive.c
#, c-format
msgid "CONFLICT (add/add): Merge conflict in %s"
msgstr "CONFLICTE (afegiment/afegiment): Conflicte de fusió en %s"
+#: merge-recursive.c
#, c-format
msgid "merging of trees %s and %s failed"
msgstr "la fusió dels arbres %s i %s ha fallat"
+#: merge-recursive.c
msgid "Merging:"
msgstr "S'està fusionant:"
+#: merge-recursive.c
#, c-format
msgid "found %u common ancestor:"
msgid_plural "found %u common ancestors:"
msgstr[0] "s'ha trobat %u avantpassat en comú:"
msgstr[1] "s'han trobat %u avantpassats en comú:"
+#: merge-recursive.c
msgid "merge returned no commit"
msgstr "la fusió no ha retornat cap comissió"
+#: merge-recursive.c
#, c-format
msgid "Could not parse object '%s'"
msgstr "No s'ha pogut analitzar l'objecte «%s»"
+#: merge.c
msgid "failed to read the cache"
msgstr "s'ha produït un error en llegir la memòria cau"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "l'OID de l'índex multipaquet és d'una mida incorrecta"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "el fitxer de l'índex multipaquet %s és massa petit"
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr ""
-"la signatura de l'índex multipaquet 0x%08x no coincideix amb la signatura "
-"0x%08x"
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "no es reconeix la versió %d de l'índex multipaquet"
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr ""
-"la versió del resum índex multipaquet %u no coincideix amb la versió %u"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "falta un fragment de nom de paquet necessari al multi-index"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "falta un fragment «fanout» OID necessari al multi-pack-index"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "falta un fragment de cerca «fanout» OID necessari al multi-pack-index"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "falta un fragment necessari dels desplaçaments al multi-pack-index"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr ""
-"els noms de paquet de l'índex multipaquet estan desordenats «%s» abans de "
-"«%s»"
-
-#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "pack-int-id: %u incorrecte (%u paquets en total)"
-
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr ""
-"l'índex multipaquet emmagatzema un desplaçament de 64 bits, però off_t és "
-"massa petit"
-
+#: midx-write.c
#, c-format
msgid "failed to add packfile '%s'"
msgstr "no s'ha pogut afegir el fitxer de paquet «%s»"
+#: midx-write.c
#, c-format
msgid "failed to open pack-index '%s'"
msgstr "no s'ha pogut obrir l'índex del paquet «%s»"
+#: midx-write.c
#, c-format
msgid "failed to locate object %d in packfile"
msgstr "no s'ha pogut localitzar l'objecte %d en el fitxer de paquet"
+#: midx-write.c
msgid "cannot store reverse index file"
msgstr "no es pot emmagatzemar el fitxer d'índex invers"
+#: midx-write.c
#, c-format
msgid "could not parse line: %s"
msgstr "no s'ha pogut analitzar la línia: %s"
+#: midx-write.c
#, c-format
msgid "malformed line: %s"
msgstr "línia mal formada: %s"
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr ""
-"s'està ignorant l'índex multipaquet existent; la suma de verificació no "
-"coincideix"
-
+#: midx-write.c
msgid "could not load pack"
msgstr "no s'ha pogut carregar el paquet"
+#: midx-write.c
#, c-format
msgid "could not open index for %s"
msgstr "s'ha produït un error en obrir l'índex per «%s»"
+#: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "no s'ha pogut enllaçar «%s» a «%s»"
+
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "no s'ha pogut netejar l'índex multipaquet a %s"
+
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "no es pot escriure un MIDX incremental amb mapa de bits"
+
+#: midx-write.c
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"s'està ignorant l'índex multipaquet existent; la suma de verificació no "
+"coincideix"
+
+#: midx-write.c
msgid "Adding packfiles to multi-pack-index"
msgstr "S'estan afegint fitxers empaquetats a l'índex multipaquet"
+#: midx-write.c
#, c-format
msgid "unknown preferred pack: '%s'"
msgstr "paquet preferit desconegut: «%s»"
+#: midx-write.c
#, c-format
msgid "cannot select preferred pack %s with no objects"
msgstr "no es pot seleccionar un paquet preferit %s sense objectes"
+#: midx-write.c
#, c-format
msgid "did not see pack-file %s to drop"
msgstr "no s'ha vist caure el fitxer empaquetat %s"
+#: midx-write.c
#, c-format
msgid "preferred pack '%s' is expired"
msgstr "el paquet preferit «%s» ha caducat"
+#: midx-write.c
msgid "no pack files to index."
msgstr "no hi ha fitxers empaquetats a indexar."
+#: midx-write.c
msgid "refusing to write multi-pack .bitmap without any objects"
msgstr "s'està refusant a escriure el .bitmap multipaquet sense cap objecte"
+#: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "no s'ha pogut crear una capa MIDX temporal"
+
+#: midx-write.c
msgid "could not write multi-pack bitmap"
msgstr "no s'han pogut escriure els mapes de bits dels multipaquets"
+#: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "no s'ha pogut obrir el fitxer de cadenes multi-path-index"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "no s'ha pogut canviar el nom de la capa multi-pack-index"
+
+#: midx-write.c
msgid "could not write multi-pack-index"
msgstr "no s'ha pogut escriure l'índex multipaquet"
+#: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "no es pot fer caducar paquets d'un multi-pack-index incremental"
+
+#: midx-write.c
+msgid "Counting referenced objects"
+msgstr "S'estan comptant els objectes referenciats"
+
+#: midx-write.c
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "S'estan cercant i suprimint els fitxers de paquets no referenciats"
+
+#: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "no es pot reempaquetar un multi-pack-index incremental"
+
+#: midx-write.c
+msgid "could not start pack-objects"
+msgstr "no s'ha pogut iniciar el pack-objects"
+
+#: midx-write.c
+msgid "could not finish pack-objects"
+msgstr "no s'ha pogut finalitzar el pack-objects"
+
+#: midx.c
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "l'OID «fanout» de l'índex multipaquet és d'una mida incorrecta"
+
+#: midx.c
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "no s'ha pogut netejar l'índex multipaquet a %s"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr ""
+"oid «fanout» desordenat: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+
+#: midx.c
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "El fragment de cerca OID índex multipaquet és de mida incorrecta"
+
+#: midx.c
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr ""
+"el fragment de desplaçament de l'objecte índex multipaquet és d'una mida "
+"incorrecta"
+
+#: midx.c
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "el fitxer de l'índex multipaquet %s és massa petit"
+
+#: midx.c
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr ""
+"la signatura de l'índex multipaquet 0x%08x no coincideix amb la signatura "
+"0x%08x"
+
+#: midx.c
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "no es reconeix la versió %d de l'índex multipaquet"
+
+#: midx.c
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr ""
+"la versió del resum índex multipaquet %u no coincideix amb la versió %u"
+
+#: midx.c
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr ""
+"manca o està malmès el fragment del nom de paquet requerit de l'índex "
+"multipaquet"
+#: midx.c
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"manca o està malmès el fragment del «fanout» OID requerit a l'índex "
+"multipaquet"
+
+#: midx.c
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr ""
+"manca o està malmès el fragment de cerca d'OID necessari a l'índex "
+"multipaquet"
+
+#: midx.c
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"manca o està malmès el fragment de l'índex multipaquet dels objectes "
+"requerits"
+
+#: midx.c
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "el fragment de nom de l'índex multipaquet és massa curt"
+
+#: midx.c
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr ""
+"els noms de paquet de l'índex multipaquet estan desordenats «%s» abans de "
+"«%s»"
+
+#: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "el fitxer de cadena multi-pack-index és massa petit"
+
+#: midx.c
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "el recompte de paquets en el MIDX de base és massa alt: %<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "el recompte de objectes en el MIDX de base és massa alt: %<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "cadena multi-pack-index invàlida: la línia «%s» no és un hash"
+
+# tots els fitxers multi-pack-index ?
+#: midx.c
+msgid "unable to find all multi-pack index files"
+msgstr "no s'han pogut trobar tots els fitxers d'índex multi-pack"
+
+#: midx.c
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr ""
+"posició invàlida de l'objecte MIDX; probablement el MIDX s'ha corromput"
+
+#: midx.c
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "pack-int-id: %u incorrecte (%u paquets en total)"
+
+#: midx.c
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX no conté el fragment BTMP"
+
+#: midx.c
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "no s'ha pogut carregar el paquet amb bits %<PRIu32>"
+
+#: midx.c
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr ""
+"l'índex multipaquet emmagatzema un desplaçament de 64 bits, però off_t és "
+"massa petit"
+
+#: midx.c
+msgid "multi-pack-index large offset out of bounds"
+msgstr "desplaçament gran de l'índex multipaquet està fora dels límits"
+
+#: midx.c
msgid "multi-pack-index file exists, but failed to parse"
msgstr ""
"el fitxer de l'índex multipaquet existeix, però no s'ha pogut analitzar"
+#: midx.c
msgid "incorrect checksum"
msgstr "suma de verificació incorrecta"
+#: midx.c
msgid "Looking for referenced packfiles"
msgstr "S'estan cercant fitxers empaquetats referenciats"
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr "oid fanout desordenat: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-
+#: midx.c
msgid "the midx contains no oid"
msgstr "el midx no conté cap oid"
+#: midx.c
msgid "Verifying OID order in multi-pack-index"
msgstr "S'està verificant l'ordre OID a l'índex multipaquet"
+#: midx.c
#, c-format
msgid "oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"
msgstr "oid lookup desordenat: oid[%d] = %s >= %s = oid[%d]"
+#: midx.c
msgid "Sorting objects by packfile"
msgstr "S'estan ordenant els objectes per fitxer empaquetats"
+#: midx.c
msgid "Verifying object offsets"
msgstr "S'estan verificant els desplaçaments dels objectes"
+#: midx.c
#, c-format
msgid "failed to load pack entry for oid[%d] = %s"
msgstr "no s'ha pogut carregar l'entrada del paquet per a oid[%d] = %s"
+#: midx.c
#, c-format
msgid "failed to load pack-index for packfile %s"
msgstr "no s'ha pogut carregar l'índex del paquet per al fitxer empaquetat %s"
+#: midx.c
#, c-format
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr ""
"desplaçament incorrecte de l'objecte per a oid[%d] = %s: %<PRIx64> != "
"%<PRIx64>"
-msgid "Counting referenced objects"
-msgstr "S'estan comptant els objectes referenciats"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "S'estan cercant i suprimint els fitxers de paquets no referenciats"
-
-msgid "could not start pack-objects"
-msgstr "no s'ha pogut iniciar el pack-objects"
-
-msgid "could not finish pack-objects"
-msgstr "no s'ha pogut finalitzar el pack-objects"
-
+#: name-hash.c
#, c-format
msgid "unable to create lazy_dir thread: %s"
msgstr "no s'ha pogut crear el fil «lazy_dir» :%s"
+#: name-hash.c
#, c-format
msgid "unable to create lazy_name thread: %s"
msgstr "no s'ha pogut crear un fil «lazy_name»: %s"
+#: name-hash.c
#, c-format
msgid "unable to join lazy_name thread: %s"
msgstr "no s'ha pogut unir el fil «lazy_name»: %s"
+#: notes-merge.c
#, c-format
msgid ""
"You have not concluded your previous notes merge (%s exists).\n"
@@ -17753,17 +22941,21 @@ msgstr ""
"Useu «git notes merge --commit» o «git notes merge --abort» per a cometre/"
"avortar la fusió prèvia abans de començar una fusió de notes nova."
+#: notes-merge.c
#, c-format
msgid "You have not concluded your notes merge (%s exists)."
msgstr "No heu conclòs la vostra fusió de notes (%s existeix)."
+#: notes-utils.c
msgid "Cannot commit uninitialized/unreferenced notes tree"
msgstr "No es pot cometre un arbre de notes no inicialitzat / no referenciat"
+#: notes-utils.c
#, c-format
msgid "Bad notes.rewriteMode value: '%s'"
msgstr "Valor de notes.rewriteMode erroni: «%s»"
+#: notes-utils.c
#, c-format
msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
msgstr "S'està refusant reescriure les notes en %s (fora de refs/notes/)"
@@ -17772,217 +22964,310 @@ msgstr "S'està refusant reescriure les notes en %s (fora de refs/notes/)"
#. the environment variable, the second %s is
#. its value.
#.
+#: notes-utils.c
#, c-format
msgid "Bad %s value: '%s'"
msgstr "Valor erroni de %s: «%s»"
+#: object-file-convert.c
+msgid "failed to decode tree entry"
+msgstr "no s'ha pogut descodificar una entrada d'arbre"
+
+#: object-file-convert.c
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "no s'ha pogut mapar l'entrada d'arbre per a %s"
+
+#: object-file-convert.c
+#, c-format
+msgid "bad %s in commit"
+msgstr "%s és incorrecte en la comissió"
+
+#: object-file-convert.c
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "no es pot mapar %s %s en l'objecte de comissió"
+
+#: object-file-convert.c
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "No s'ha pogut convertir l'objecte de %s a %s"
+
+#: object-file.c
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
msgstr ""
"no existeix el directori d'objecte %s; comproveu .git/objects/info/alternates"
+#: object-file.c
#, c-format
msgid "unable to normalize alternate object path: %s"
msgstr "no s'ha pogut normalitzar el camí a l'objecte alternatiu: %s"
+#: object-file.c
#, c-format
msgid "%s: ignoring alternate object stores, nesting too deep"
msgstr ""
"%s: s'estan ignorant els emmagatzematges alternatius d'objectes, imbricació "
"massa profunda"
+#: object-file.c
msgid "unable to fdopen alternates lockfile"
msgstr "no s'ha pogut fer «fdopen» al fitxer de bloqueig alternatiu"
+#: object-file.c
msgid "unable to read alternates file"
msgstr "no es pot llegir el fitxer «alternates»"
+#: object-file.c
msgid "unable to move new alternates file into place"
msgstr "no s'ha pogut moure el nou fitxer «alternates» al lloc"
+#: object-file.c
#, c-format
msgid "path '%s' does not exist"
msgstr "el camí «%s» no existeix"
+#: object-file.c
#, c-format
msgid "reference repository '%s' as a linked checkout is not supported yet."
msgstr ""
"encara no s'admet el repositori de referència «%s» com a agafament enllaçat."
+#: object-file.c
#, c-format
msgid "reference repository '%s' is not a local repository."
msgstr "el repositori de referència «%s» no és un repositori local."
+#: object-file.c
#, c-format
msgid "reference repository '%s' is shallow"
msgstr "el repositori de referència «%s» és superficial"
+#: object-file.c
#, c-format
msgid "reference repository '%s' is grafted"
msgstr "el repositori de referència «%s» és empeltat"
+#: object-file.c
#, c-format
msgid "could not find object directory matching %s"
msgstr "no s'ha pogut trobar el directori de l'objecte que coincideixi amb %s"
+#: object-file.c
#, c-format
msgid "invalid line while parsing alternate refs: %s"
msgstr ""
"línia no vàlida quan s'analitzaven les referències de l'«alternate»: %s"
+#: object-file.c
#, c-format
msgid "attempting to mmap %<PRIuMAX> over limit %<PRIuMAX>"
msgstr "s'està intentant fer mmap %<PRIuMAX> per sobre del límit %<PRIuMAX>"
+#: object-file.c
#, c-format
msgid "mmap failed%s"
msgstr "mmap ha fallat%s"
+#: object-file.c
#, c-format
msgid "object file %s is empty"
msgstr "el tipus d'objecte %s és buit"
+#: object-file.c
#, c-format
msgid "corrupt loose object '%s'"
msgstr "objecte solt corrupte «%s»"
+#: object-file.c
#, c-format
msgid "garbage at end of loose object '%s'"
msgstr "brossa al final de l'objecte solt «%s»"
+#: object-file.c
#, c-format
msgid "unable to open loose object %s"
msgstr "no s'ha pogut obrir l'objecte solt %s"
+#: object-file.c
#, c-format
msgid "unable to parse %s header"
msgstr "no s'ha pogut analitzar la capçalera %s"
+#: object-file.c
msgid "invalid object type"
msgstr "tipus d'objecte és incorrecte"
+#: object-file.c
#, c-format
msgid "unable to unpack %s header"
msgstr "no s'ha pogut desempaquetar la capçalera %s"
+#: object-file.c
#, c-format
msgid "header for %s too long, exceeds %d bytes"
-msgstr "la capçalera per a %s és massa llarga, supera els %d bytes"
+msgstr "la capçalera per a %s és massa llarga, supera els %d octets"
+#: object-file.c
#, c-format
msgid "loose object %s (stored in %s) is corrupt"
msgstr "l'objecte solt %s (emmagatzemat a %s) és corrupte"
+#: object-file.c
#, c-format
msgid "replacement %s not found for %s"
msgstr "no s'ha trobat el reemplaçament %s per a %s"
+#: object-file.c
#, c-format
msgid "packed object %s (stored in %s) is corrupt"
msgstr "l'objecte empaquetat %s (emmagatzemat a %s) és corrupte"
+#: object-file.c
+#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "manca el mapatge de %s a %s"
+
+#: object-file.c
+#, c-format
+msgid "unable to open %s"
+msgstr "no s'ha pogut obrir %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "els fitxers «%s» i «%s» difereixen en el contingut"
+
+#: object-file.c
#, c-format
msgid "unable to write file %s"
msgstr "no s'ha pogut escriure al fitxer %s"
+#: object-file.c
#, c-format
msgid "unable to set permission to '%s'"
msgstr "no s'ha pogut establir el permís a «%s»"
+#: object-file.c
msgid "error when closing loose object file"
msgstr "error en tancar el fitxer d'objecte solt"
+#: object-file.c
#, c-format
msgid "insufficient permission for adding an object to repository database %s"
msgstr ""
"permisos insuficients per a afegir un objecte a la base de dades del "
"repositori %s"
+#: object-file.c
msgid "unable to create temporary file"
msgstr "no s'ha pogut crear un fitxer temporal"
+#: object-file.c
msgid "unable to write loose object file"
msgstr "no s'ha pogut escriure el fitxer d'objecte solt"
+#: object-file.c
#, c-format
msgid "unable to deflate new object %s (%d)"
msgstr "no s'ha pogut desinflar l'object nou %s (%d)"
+#: object-file.c
#, c-format
msgid "deflateEnd on object %s failed (%d)"
msgstr "ha fallat deflateEnd a l'objecte %s(%d)"
+#: object-file.c
#, c-format
msgid "confused by unstable object source data for %s"
msgstr "confós per la font de dades inestable de l'objecte per a %s"
+#: object-file.c
#, c-format
msgid "write stream object %ld != %<PRIuMAX>"
msgstr "escriu l'objecte de flux %ld != %<PRIuMAX>"
+#: object-file.c
#, c-format
msgid "unable to stream deflate new object (%d)"
msgstr "no s'ha pogut desinflar l'object nou (%d)"
+#: object-file.c
#, c-format
msgid "deflateEnd on stream object failed (%d)"
msgstr "ha fallat deflateEnd a l'objecte del flux (%d)"
+#: object-file.c
#, c-format
msgid "unable to create directory %s"
msgstr "s'ha produït un error en crear el directori %s"
+#: object-file.c
#, c-format
msgid "cannot read object for %s"
msgstr "no es pot llegir l'objecte per a %s"
+#: object-file.c
+#, c-format
+msgid "cannot map object %s to %s"
+msgstr "no és possible mapar l'objecte %s a %s"
+
+#: object-file.c
#, c-format
msgid "object fails fsck: %s"
msgstr "l'objecte ha fallat fsck: %s"
+#: object-file.c
msgid "refusing to create malformed object"
msgstr "es rebutja crear un objecte mal format"
+#: object-file.c
#, c-format
msgid "read error while indexing %s"
msgstr "error de lectura mentre s'indexava %s"
+#: object-file.c
#, c-format
msgid "short read while indexing %s"
msgstr "lectura curta mentre s'indexa %s"
+#: object-file.c
#, c-format
msgid "%s: failed to insert into database"
msgstr "%s: no s'han pogut inserir a la base de dades"
+#: object-file.c
#, c-format
msgid "%s: unsupported file type"
msgstr "%s: tipus de fitxer no suportat"
+#: object-file.c
#, c-format
msgid "%s is not a valid '%s' object"
msgstr "%s no és un objecte de «%s» vàlid"
-#, c-format
-msgid "unable to open %s"
-msgstr "no s'ha pogut obrir %s"
-
+#: object-file.c
#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "no coincideix el resum per a %s (s'esperava %s)"
+#: object-file.c
#, c-format
msgid "unable to mmap %s"
msgstr "no s'ha pogut fer «mmap» %s"
+#: object-file.c
#, c-format
msgid "unable to unpack header of %s"
msgstr "no s'ha pogut desempaquetar la capçalera de %s"
+#: object-file.c
#, c-format
msgid "unable to parse header of %s"
msgstr "no s'ha pogut analitzar la capçalera de %s"
+#: object-file.c
#, c-format
msgid "unable to unpack contents of %s"
msgstr "no s'han pogut desempaquetar els continguts de %s"
@@ -17991,6 +23276,7 @@ msgstr "no s'han pogut desempaquetar els continguts de %s"
#. output shown when we cannot look up or parse the
#. object in question. E.g. "deadbeef [bad object]".
#.
+#: object-name.c
#, c-format
msgid "%s [bad object]"
msgstr "%s [objecte incorrecte]"
@@ -18000,6 +23286,7 @@ msgstr "%s [objecte incorrecte]"
#. *
#. "deadbeef commit 2021-01-01 - Some Commit Message"
#.
+#: object-name.c
#, c-format
msgid "%s commit %s - %s"
msgstr "%s comissió %s - %s"
@@ -18015,6 +23302,7 @@ msgstr "%s comissió %s - %s"
#. The third argument is the "tag" string
#. from object.c.
#.
+#: object-name.c
#, c-format
msgid "%s tag %s - %s"
msgstr "%s etiqueta %s - %s"
@@ -18025,6 +23313,7 @@ msgstr "%s etiqueta %s - %s"
#. *
#. "deadbeef [bad tag, could not parse it]"
#.
+#: object-name.c
#, c-format
msgid "%s [bad tag, could not parse it]"
msgstr "%s [etiqueta malmesa, no s'ha pogut analitzar]"
@@ -18032,6 +23321,7 @@ msgstr "%s [etiqueta malmesa, no s'ha pogut analitzar]"
#. TRANSLATORS: This is a line of ambiguous <type>
#. object output. E.g. "deadbeef tree".
#.
+#: object-name.c
#, c-format
msgid "%s tree"
msgstr "arbre %s"
@@ -18039,10 +23329,12 @@ msgstr "arbre %s"
#. TRANSLATORS: This is a line of ambiguous <type>
#. object output. E.g. "deadbeef blob".
#.
+#: object-name.c
#, c-format
msgid "%s blob"
msgstr "blob %s"
+#: object-name.c
#, c-format
msgid "short object ID %s is ambiguous"
msgstr "l'id d'objecte curt %s és ambigu"
@@ -18051,6 +23343,7 @@ msgstr "l'id d'objecte curt %s és ambigu"
#. objects composed in show_ambiguous_object(). See
#. its "TRANSLATORS" comments for details.
#.
+#: object-name.c
#, c-format
msgid ""
"The candidates are:\n"
@@ -18059,6 +23352,7 @@ msgstr ""
"Els candidats són:\n"
"%s"
+#: object-name.c
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"
@@ -18082,18 +23376,22 @@ msgstr ""
"suprimiu-les. Desactiveu aquest missatge executant\n"
"«git config advice.objectNameWarning false»"
+#: object-name.c
#, c-format
msgid "log for '%.*s' only goes back to %s"
msgstr "registre per a «%.*s» només retorna a %s"
+#: object-name.c
#, c-format
msgid "log for '%.*s' only has %d entries"
msgstr "registre per a «%.*s» només té %d entrades"
+#: object-name.c
#, c-format
msgid "path '%s' exists on disk, but not in '%.*s'"
msgstr "el camí «%s» existeix al disc, però no a «%.*s»"
+#: object-name.c
#, c-format
msgid ""
"path '%s' exists, but not '%s'\n"
@@ -18102,10 +23400,12 @@ msgstr ""
"el camí «%s» existeix, però no «%s»\n"
"consell: volíeu dir «%.*s:%s» conegut com a «%.*s:./%s»?"
+#: object-name.c
#, c-format
msgid "path '%s' does not exist in '%.*s'"
msgstr "el camí «%s» no existeix en «%.*s»"
+#: object-name.c
#, c-format
msgid ""
"path '%s' is in the index, but not at stage %d\n"
@@ -18114,6 +23414,7 @@ msgstr ""
"el camí «%s» està a l'índex, però no a «stage» %d\n"
".consell: volíeu dir «:%d:%s»?"
+#: object-name.c
#, c-format
msgid ""
"path '%s' is in the index, but not '%s'\n"
@@ -18122,320 +23423,455 @@ msgstr ""
"el camí «%s» està a l'índex, però no a «%s»\n"
".consell: volíeu dir «:%d:%s» conegut com a «:%d:./%s»?"
+#: object-name.c
#, c-format
msgid "path '%s' exists on disk, but not in the index"
msgstr "el camí «%s» existeix al disc, però no a l'índex"
+#: object-name.c
#, c-format
msgid "path '%s' does not exist (neither on disk nor in the index)"
msgstr "el camí «%s» no existeix (ni al disc ni a l'índex)"
+#: object-name.c
msgid "relative path syntax can't be used outside working tree"
msgstr ""
"la sintaxi de camí relatiu no es pot utilitzar fora de l'arbre de treball"
+#: object-name.c
#, c-format
msgid "<object>:<path> required, only <object> '%s' given"
msgstr "<objecte>:<camí> requerit, només s'ha donat <objecte> «%s»"
+#: object-name.c
#, c-format
msgid "invalid object name '%.*s'."
msgstr "nom d'objecte no vàlid «%.*s»."
+#: object.c
#, c-format
msgid "invalid object type \"%s\""
msgstr "tipus d'objecte «%s» no vàlid"
+#: object.c
#, c-format
msgid "object %s is a %s, not a %s"
msgstr "l'objecte %s és %s, no pas %s"
+#: object.c
#, c-format
msgid "object %s has unknown type id %d"
msgstr "l'objecte %s té un identificador de tipus %d desconegut"
+#: object.c
#, c-format
msgid "unable to parse object: %s"
msgstr "no s'ha pogut analitzar l'objecte: %s"
+#: object.c
#, c-format
msgid "hash mismatch %s"
msgstr "el resum no coincideix %s"
+#: pack-bitmap-write.c
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "entrada duplicada en escriure l'índex de mapa de bits: %s"
+
+#: pack-bitmap-write.c
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "s'ha intentat emmagatzemar una comissió no seleccionada: «%s»"
+
+#: pack-bitmap-write.c
+msgid "too many pseudo-merges"
+msgstr "massa pseudo-fusions"
+
+#: pack-bitmap-write.c
msgid "trying to write commit not in index"
-msgstr "s'està intentant no escriure la publicació a l'índex"
+msgstr "s'està intentant no escriure la comissió a l'índex"
+#: pack-bitmap.c
msgid "failed to load bitmap index (corrupted?)"
msgstr ""
"s'ha produït un error en carregar l'índex de mapa de bits (està malmès?)"
+#: pack-bitmap.c
msgid "corrupted bitmap index (too small)"
msgstr "índex de mapa de bits malmès (massa petit)"
+#: pack-bitmap.c
msgid "corrupted bitmap index file (wrong header)"
msgstr "fitxer d'índex de mapa de bits malmès (capçalera incorrecta)"
+#: pack-bitmap.c
#, c-format
msgid "unsupported version '%d' for bitmap index file"
msgstr "versió «%d» no admesa per al fitxer d'índex de mapa de bits"
+#: pack-bitmap.c
msgid "corrupted bitmap index file (too short to fit hash cache)"
msgstr ""
"fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se a la "
"memòria cau de hash)"
+#: pack-bitmap.c
msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr ""
"fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se a la "
"taula de cerca)"
+# 2 línies OK?
+#: pack-bitmap.c
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"fitxer d'índex de mapes de bits malmès (massa curt per a ajustar-se\n"
+"a la capçalera de la taula de pseudo-fusions)"
+
+# 2 línies OK?
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se\n"
+"a la taula de pseudo-fusions)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr ""
+"fitxer d'índex de mapa de bits malmès, taula de pseudo-fusions massa curta"
+
+#: pack-bitmap.c
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "entrada duplicada a l'índex del mapa de bits: «%s»"
+#: pack-bitmap.c
#, c-format
msgid "corrupt ewah bitmap: truncated header for entry %d"
msgstr "mapa de bits ewah malmès: capçalera truncada per a l'entrada %d"
+#: pack-bitmap.c
#, c-format
msgid "corrupt ewah bitmap: commit index %u out of range"
msgstr "mapa de bits ewah malmès: l'índex de comissió %u està fora de rang"
+#: pack-bitmap.c
msgid "corrupted bitmap pack index"
msgstr "índex de paquets de mapa de bits malmès"
+#: pack-bitmap.c
msgid "invalid XOR offset in bitmap pack index"
msgstr "el desplaçament XOR a l'índex de mapa de bits no és vàlid"
+#: pack-bitmap.c
msgid "cannot fstat bitmap file"
msgstr "no es pot fer fstat en el fitxer de mapa de bits"
+#: pack-bitmap.c
msgid "checksum doesn't match in MIDX and bitmap"
msgstr "la suma de verificació no coincideix amb el MIDX i el mapa de bits"
+#: pack-bitmap.c
msgid "multi-pack bitmap is missing required reverse index"
msgstr "falta l'índex invers necessari al mapa de bits multipaquet"
+#: pack-bitmap.c
#, c-format
msgid "could not open pack %s"
msgstr "no s'ha pogut obrir el paquet %s"
+#: pack-bitmap.c t/helper/test-read-midx.c
+msgid "could not determine MIDX preferred pack"
+msgstr "no s'ha pogut determinar el paquet preferit MIDX"
+
+#: pack-bitmap.c
#, c-format
msgid "preferred pack (%s) is invalid"
msgstr "el paquet preferit (%s) no és vàlid"
+#: pack-bitmap.c
msgid "corrupt bitmap lookup table: triplet position out of index"
msgstr ""
"taula de cerca de mapa de bits malmesa: posició la tripleta fora de l'índex"
+#: pack-bitmap.c
msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
msgstr ""
"taula de cerca de mapa de bits malmesa: la cadena xor excedeix el nombre "
"d'entrades"
+#: pack-bitmap.c
#, c-format
msgid "corrupt bitmap lookup table: commit index %u out of range"
msgstr ""
"taula de cerca de mapa de bits malmesa: l'índex de comissió %u està fora de "
"rang"
+#: pack-bitmap.c
#, c-format
msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
msgstr ""
"mapa de bits ewah malmès: capçalera truncada per al mapa de bits de la "
"comissió «%s»"
+#: pack-bitmap.c
+#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr ""
+"no s'ha pogut carregar el paquet: «%s», s'està inhabilitant lareutilització "
+"de paquets"
+
+# s'inhabilita / s'està inhabilitant?
+#: pack-bitmap.c
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "no s'ha pogut calcular el paquet preferit, s'inhabilita pack-reuse"
+
+#: pack-bitmap.c
#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "no s'ha trobat l'objecte «%s» als tipus de mapes de bits"
+#: pack-bitmap.c
#, c-format
msgid "object '%s' does not have a unique type"
msgstr "l'objecte «%s» no té un tipus únic"
+#: pack-bitmap.c
#, c-format
msgid "object '%s': real type '%s', expected: '%s'"
msgstr "objecte «%s»: tipus real «%s», s'esperava: «%s»"
+#: pack-bitmap.c
#, c-format
msgid "object not in bitmap: '%s'"
msgstr "objecte no trobat al mapa de bits: «%s»"
+#: pack-bitmap.c
msgid "failed to load bitmap indexes"
msgstr "s'ha produït un error en carregar l'índex de mapa de bits"
+#: pack-bitmap.c
msgid "you must specify exactly one commit to test"
msgstr "heu d'especificar exactament una comissió a provar"
+#: pack-bitmap.c
#, c-format
msgid "commit '%s' doesn't have an indexed bitmap"
msgstr "la comissió «%s» no té un mapa de bits indexat"
+#: pack-bitmap.c
msgid "mismatch in bitmap results"
msgstr "no coincideix en els resultats del mapa de bits"
+#: pack-bitmap.c
+#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "l'índex de pseudo-fusions és fora de rang (%<PRIu32> >= %<PRIuMAX>)"
+
+#: pack-bitmap.c
#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "no s'ha pogut trobar «%s» al paquet «%s» al desplaçament %<PRIuMAX>"
+#: pack-bitmap.c
#, c-format
msgid "unable to get disk usage of '%s'"
msgstr "no s'ha pogut obtenir l'ús del disc de «%s»"
+#: pack-bitmap.c
#, 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"
+#: pack-mtimes.c
#, c-format
msgid "mtimes file %s is too small"
msgstr "el fitxer mtimes %s és massa petit"
+#: pack-mtimes.c
#, c-format
msgid "mtimes file %s has unknown signature"
msgstr "el fitxer mtimes %s té una signatura desconeguda"
+#: pack-mtimes.c
#, c-format
msgid "mtimes file %s has unsupported version %<PRIu32>"
msgstr "el fitxer mtimes %s té la versió %<PRIu32> no admesa"
+#: pack-mtimes.c
#, c-format
msgid "mtimes file %s has unsupported hash id %<PRIu32>"
msgstr "el fitxer mtimes %s té un ID de resum %<PRIu32> no admès"
+#: pack-mtimes.c
#, c-format
msgid "mtimes file %s is corrupt"
msgstr "el fitxer mtimes %s està malmès"
+#: pack-revindex.c
#, c-format
msgid "reverse-index file %s is too small"
msgstr "el fitxer d'índex invers %s és massa petit"
+#: pack-revindex.c
#, c-format
msgid "reverse-index file %s is corrupt"
msgstr "el fitxer d'índex invers %s està malmès"
+#: pack-revindex.c
#, c-format
msgid "reverse-index file %s has unknown signature"
msgstr "el fitxer d'índex invers %s té una signatura desconeguda"
+#: pack-revindex.c
#, c-format
msgid "reverse-index file %s has unsupported version %<PRIu32>"
msgstr "el fitxer d'índex invers %s té la versió %<PRIu32> no admesa"
+#: pack-revindex.c
#, c-format
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"
+#: pack-revindex.c
msgid "invalid checksum"
msgstr "suma de verificació no vàlida"
+#: pack-revindex.c
#, 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>"
+#: pack-revindex.c
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr ""
+"el fragment de l'index invers de l'índex multipaquet és de mida incorrecta"
+
+#: pack-revindex.c
+msgid "could not determine preferred pack"
+msgstr "no s'ha pogut determinar el paquet preferit"
+
+#: pack-write.c
msgid "cannot both write and verify reverse index"
msgstr "no es pot escriure i verificar l'índex invers"
+#: pack-write.c
#, c-format
msgid "could not stat: %s"
msgstr "no s'ha pogut fer stat a: %s"
+#: pack-write.c
#, c-format
msgid "failed to make %s readable"
msgstr "s'ha produït un error en fer %s llegible"
+#: pack-write.c
#, c-format
msgid "could not write '%s' promisor file"
msgstr "no s'ha pogut escriure «%s» al fitxer «promisor»"
+#: packfile.c
msgid "offset before end of packfile (broken .idx?)"
msgstr "desplaçament abans de la fi del fitxer de paquet (.idx trencat?)"
+#: packfile.c
#, c-format
msgid "packfile %s cannot be mapped%s"
msgstr "el fitxer de paquet %s no es pot mapar%s"
+#: packfile.c
#, c-format
msgid "offset before start of pack index for %s (corrupt index?)"
msgstr ""
"desplaçament abans d'inici d'índex de paquet per a %s (índex corromput?)"
+#: packfile.c
#, c-format
msgid "offset beyond end of pack index for %s (truncated index?)"
msgstr ""
"desplaçament més enllà de la fi d'índex de paquet per a %s (índex truncat?)"
+#: parse-options-cb.c
#, c-format
msgid "malformed expiration date '%s'"
msgstr "data de venciment «%s» mal formada"
+#: parse-options-cb.c
#, c-format
msgid "option `%s' expects \"always\", \"auto\", or \"never\""
msgstr "l'opció «%s» espera «always», «auto» o «never»"
+#: parse-options-cb.c
#, c-format
msgid "malformed object name '%s'"
msgstr "nom d'objecte «%s» mal format"
+#: parse-options-cb.c
#, c-format
msgid "option `%s' expects \"%s\" or \"%s\""
msgstr "l'opció «%s» espera «%s» o «%s»"
+#: parse-options.c
#, c-format
msgid "%s requires a value"
msgstr "%s requereix un valor"
-#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s és incompatible amb %s"
-
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s: és incompatible amb alguna altra cosa"
-
+#: parse-options.c
#, c-format
msgid "%s takes no value"
msgstr "%s no accepta cap valor"
+#: parse-options.c
#, c-format
msgid "%s isn't available"
msgstr "%s no és disponible"
+#: parse-options.c
#, c-format
msgid "%s expects a non-negative integer value with an optional k/m/g suffix"
msgstr "%s espera un valor enter no negatiu amb un sufix opcional k/m/g"
+#: parse-options.c
#, c-format
msgid "ambiguous option: %s (could be --%s%s or --%s%s)"
msgstr "opció ambigua: %s (pot ser --%s%s o --%s%s)"
+#: parse-options.c
#, c-format
msgid "did you mean `--%s` (with two dashes)?"
msgstr "voleu dir «--%s» (amb dos guionets)?"
+#: parse-options.c
#, c-format
msgid "alias of --%s"
msgstr "àlies de --%s"
+#: parse-options.c
msgid "need a subcommand"
msgstr "cal una subordre"
+#: parse-options.c
#, c-format
msgid "unknown option `%s'"
msgstr "opció desconeguda «%s»"
+#: parse-options.c
#, c-format
msgid "unknown switch `%c'"
msgstr "opció «%c» desconeguda"
+#: parse-options.c
#, c-format
msgid "unknown non-ascii option in string: `%s'"
msgstr "opció no ascii desconeguda en la cadena: «%s»"
+#: parse-options.c
msgid "..."
msgstr "..."
+#: parse-options.c
#, c-format
msgid "usage: %s"
msgstr "ús: %s"
@@ -18443,6 +23879,7 @@ msgstr "ús: %s"
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation.
#.
+#: parse-options.c
#, c-format
msgid " or: %s"
msgstr " o: %s"
@@ -18466,71 +23903,105 @@ msgstr " o: %s"
#. translated) N_() usage string, which contained embedded
#. newlines before we split it up.
#.
+#: parse-options.c
#, c-format
msgid "%*s%s"
msgstr "%*s%s"
+#: parse-options.c
#, c-format
msgid " %s"
msgstr " %s"
+#: parse-options.c
msgid "-NUM"
msgstr "-NUM"
+#: parse-options.c
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "oposat a --no-%s"
+
+#: parse-options.h
msgid "expiry-date"
msgstr "data-de-caducitat"
+#: parse-options.h
msgid "no-op (backward compatibility)"
msgstr "operació nul·la (per a compatibilitat amb versions anteriors)"
+#: parse-options.h
msgid "be more verbose"
msgstr "sigues més detallat"
+#: parse-options.h
msgid "be more quiet"
msgstr "sigues més discret"
+#: parse-options.h
msgid "use <n> digits to display object names"
msgstr "usa <n> xifres per a mostrar els noms d'objecte"
+#: parse-options.h
msgid "prefixed path to initial superproject"
msgstr "camí prefixat al superprojecte inicial"
+#: parse-options.h
msgid "how to strip spaces and #comments from message"
msgstr "com suprimir els espais i #comentaris del missatge"
+#: parse-options.h
msgid "read pathspec from file"
msgstr "llegeix l'especificació del camí del fitxer"
+#: parse-options.h
msgid ""
"with --pathspec-from-file, pathspec elements are separated with NUL character"
msgstr ""
"amb --pathspec-from-file els elements d'especificació del camí estan "
"separats amb el caràcter NUL"
+#: parse.c
+#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "el valor «%s» booleà de l'entorn és incorrecte per a «%s»"
+
+#: parse.c
+#, c-format
+msgid "failed to parse %s"
+msgstr "s'ha produït un error en analitzar %s"
+
+#: path.c
#, c-format
msgid "Could not make %s writable by group"
msgstr "No s'ha pogut fer %s escrivible pel grup"
+#: pathspec.c
msgid "Escape character '\\' not allowed as last character in attr value"
msgstr ""
"El caràcter d'escapament «\\» no està permès com a últim caràcter en un "
"valor d'un atribut"
+#: pathspec.c
msgid "Only one 'attr:' specification is allowed."
msgstr "Només es permet una especificació «attr:»."
+#: pathspec.c
msgid "attr spec must not be empty"
msgstr "una especificació d'atribut no pot estar buida"
+#: pathspec.c
#, c-format
msgid "invalid attribute name %s"
msgstr "nom d'atribut no vàlid %s"
+#: pathspec.c
msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
msgstr ""
"els paràmetres d'especificació de camí «glob» i «noglob» globals són "
"incompatibles"
+#: pathspec.c
msgid ""
"global 'literal' pathspec setting is incompatible with all other global "
"pathspec settings"
@@ -18538,134 +24009,273 @@ msgstr ""
"el paràmetre d'especificació de camí «literal» global és incompatible amb "
"tots els altres paràmetres d'especificació de camí globals"
+#: pathspec.c
msgid "invalid parameter for pathspec magic 'prefix'"
msgstr "paràmetre no vàlid per a la màgia d'especificació de camí «prefix»"
+#: pathspec.c
#, c-format
msgid "Invalid pathspec magic '%.*s' in '%s'"
msgstr "Màgia d'especificació de camí no vàlida «%.*s» en «%s»"
+#: pathspec.c
#, c-format
msgid "Missing ')' at the end of pathspec magic in '%s'"
msgstr "«)» mancant al final de la màgia d'especificació de camí en «%s»"
+#: pathspec.c
#, c-format
msgid "Unimplemented pathspec magic '%c' in '%s'"
msgstr "Màgia d'especificació de camí no implementada «%c» en «%s»"
+#: pathspec.c
#, c-format
msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s: «literal» i «glob» són incompatibles"
+#: pathspec.c
+#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "«%s» és fora de l'arbre de directoris"
+
+#: pathspec.c
#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s: «%s» està fora del repositori en «%s»"
+#: pathspec.c
#, c-format
msgid "'%s' (mnemonic: '%c')"
msgstr "«%s» (mnemònic: «%c»)"
+#: pathspec.c
#, c-format
msgid "%s: pathspec magic not supported by this command: %s"
msgstr ""
"%s: aquesta ordre no està admesa amb la màgia d'especificació de camí: %s"
+#: pathspec.c
#, c-format
msgid "pathspec '%s' is beyond a symbolic link"
msgstr "l'especificació de camí «%s» és més enllà d'un enllaç simbòlic"
+#: pathspec.c
#, c-format
msgid "line is badly quoted: %s"
msgstr "la línia no està ben envoltada per cometes: %s"
+#: pkt-line.c
msgid "unable to write flush packet"
msgstr "no s'ha pogut escriure el paquet de buidatge"
+#: pkt-line.c
msgid "unable to write delim packet"
msgstr "no s'ha pogut escriure el paquet delim"
+#: pkt-line.c
msgid "unable to write response end packet"
msgstr "no s'ha pogut escriure el paquet de final de resposta"
+#: pkt-line.c
msgid "flush packet write failed"
msgstr "s'ha produït un error en escriure el paquet de buidatge"
+#: pkt-line.c
msgid "protocol error: impossibly long line"
msgstr "error de protocol: longitud de línia impossible"
+#: pkt-line.c
msgid "packet write with format failed"
msgstr "ha fallat l'escriptura del paquet amb format"
+#: pkt-line.c
msgid "packet write failed - data exceeds max packet size"
msgstr ""
"no s'ha pogut escriure el paquet - les dades excedeixen la mida màxima del "
"paquet"
+#: pkt-line.c
#, c-format
msgid "packet write failed: %s"
msgstr "no s'ha pogut escriure el paquet: %s"
+#: pkt-line.c
msgid "read error"
msgstr "error de lectura"
+#: pkt-line.c
msgid "the remote end hung up unexpectedly"
msgstr "el remot ha penjat inesperadament"
+#: pkt-line.c
#, c-format
msgid "protocol error: bad line length character: %.4s"
msgstr "error de protocol: caràcter de longitud de línia erroni: %.4s"
+#: pkt-line.c
#, c-format
msgid "protocol error: bad line length %d"
msgstr "error de protocol: longitud de línia errònia %d"
+#: pkt-line.c sideband.c
#, c-format
msgid "remote error: %s"
msgstr "error remot: %s"
+#: preload-index.c
msgid "Refreshing index"
msgstr "S'està actualitzant l'índex"
+#: preload-index.c
#, c-format
msgid "unable to create threaded lstat: %s"
msgstr "no s'han pogut crear lstat amb fils %s"
+#: pretty.c
msgid "unable to parse --pretty format"
msgstr "no s'ha pogut analitzar el format --pretty"
+# lazy → tardà as in “lazy evaluationâ€
+# 2 línies OK?
+#: promisor-remote.c
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr ""
+"s'ha inhabilitat l'obtenció tardana; por ser que alguns objectes\n"
+"no estiguin disponibles"
+
+#: promisor-remote.c
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote: no es pot bifurcar el subprocés d'obtenció"
+#: promisor-remote.c
msgid "promisor-remote: could not write to fetch subprocess"
msgstr "promisor-remote: no s'ha pogut escriure per al subprocés d'obtenció"
+#: promisor-remote.c
msgid "promisor-remote: could not close stdin to fetch subprocess"
msgstr "promisor-remote: no s'ha pogut tancar stdin al subprocés d'obtenció"
+#: promisor-remote.c
#, c-format
msgid "promisor remote name cannot begin with '/': %s"
msgstr "el nom remot «promisor» no pot començar amb «/»: %s"
+#: promisor-remote.c
#, c-format
msgid "could not fetch %s from promisor remote"
msgstr "no s'ha pogut obtenir «%s» del «promisor» remot"
+#: protocol-caps.c
msgid "object-info: expected flush after arguments"
msgstr "object-info: s'esperava una neteja després dels arguments"
+#: prune-packed.c
msgid "Removing duplicate objects"
msgstr "S'estan eliminant els objectes duplicats"
+#: pseudo-merge.c
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr ""
+"no s'ha pogut carregar l'expressió regular de pseudo-fusió per a %s: «%s»"
+
+# gerundi → futur?
+# default → valor predeterminat?
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s ha de ser no negatiu, s'usarà el valor predeterminat"
+
+# gerundi → futur?
+# default → valor predeterminat?
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s ha d'estar entre 0 i 1, s'usarà el valor predeterminat"
+
+# gerundi → futur?
+# default → valor predeterminat?
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s ha de ser positiu, s'usarà el valor predeterminat"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "manca un patró requerit al grup de pseudo-fusió «%s»"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"el grup de pseudo-fusió «%s» té un llindar inestable abans de l'estable"
+
+#: pseudo-merge.c
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"l'expressió regular de pseudo-fusions procedent de la configuració\n"
+"té massa grups de captura (màxim=%<PRIuMAX>)"
+
+# lectura ampliada o pseudo-fusions ampliades?
+# read → lectura / llegit?
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"la lectura de pseudo-fusions ampliades és fora de rang (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"l'entrada de pseudo-fusions ampliades és massa curta (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr ""
+"no s'ha pogut trobar una pseudo-fusió per a la comissió %s\n"
+"a la posició %<PRIuMAX>"
+
+# consulta ampliada o pseudo-fusions ampliades?
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"la consulta de pseudo-fusions ampliades és fora de rang (%<PRIu32> >= "
+"%<PRIu32>)"
+
+# read → lectura?
+#: pseudo-merge.c
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "lectura fora de rang: (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr ""
+"no s'ha pogut llegir la taula de pseudo-fusions ampliada per a la comissió %s"
+
+#: range-diff.c
msgid "could not start `log`"
msgstr "no s'ha pogut iniciar «log»"
+#: range-diff.c
msgid "could not read `log` output"
msgstr "no s'ha pogut llegir la sortida de «log»"
+#: range-diff.c sequencer.c
#, c-format
msgid "could not parse commit '%s'"
msgstr "no s'ha pogut analitzar la comissió «%s»"
+#: range-diff.c
#, c-format
msgid ""
"could not parse first line of `log` output: did not start with 'commit ': "
@@ -18674,55 +24284,64 @@ msgstr ""
"no s'ha pogut analitzar la primera línia de la sortida «log»: no començava "
"amb «commit»: «%s»"
+#: range-diff.c
#, c-format
msgid "could not parse git header '%.*s'"
msgstr "no s'ha pogut llegir la capçalera de la gif «%.*s»"
+#: range-diff.c
msgid "failed to generate diff"
msgstr "s'ha produït un error en generar el diff"
+#: range-diff.c
#, c-format
msgid "could not parse log for '%s'"
msgstr "no s'ha pogut llegir el fitxer de registre per a «%s»"
+#: reachable.c
#, c-format
msgid "invalid extra cruft tip: '%s'"
msgstr "punta extra extra no vàlida: «%s»"
+#: reachable.c
msgid "unable to enumerate additional recent objects"
msgstr "no s'han pogut enumerar els objectes recents addicionals"
+#: read-cache.c
#, 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)"
+#: read-cache.c
msgid "cannot create an empty blob in the object database"
msgstr "no es pot crear un blob buit a la base de dades d'objectes"
+#: read-cache.c
#, c-format
msgid "%s: can only add regular files, symbolic links or git-directories"
msgstr ""
"%s: només pot afegir fitxers normals, enllaços simbòlics o directoris git"
+#: read-cache.c
#, c-format
msgid "unable to index file '%s'"
msgstr "no es pot llegir indexar el fitxer «%s»"
+#: read-cache.c
#, c-format
msgid "unable to add '%s' to index"
msgstr "no s'ha pogut afegir «%s» a l'índex"
-#, c-format
-msgid "unable to stat '%s'"
-msgstr "no s'ha pogut fer «stat» a «%s»"
-
+#: read-cache.c
#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "«%s» apareix com a fitxer i com a directori"
+#: read-cache.c
msgid "Refresh index"
msgstr "Actualitza l'índex"
+#: read-cache.c
#, c-format
msgid ""
"index.version set, but the value is invalid.\n"
@@ -18731,6 +24350,7 @@ msgstr ""
"index.version està establerta, però el valor no és vàlid.\n"
"S'està usant la versió %i"
+#: read-cache.c
#, c-format
msgid ""
"GIT_INDEX_VERSION set, but the value is invalid.\n"
@@ -18739,118 +24359,143 @@ msgstr ""
"GIT_INDEX_VERSION està establerta, però el valor no és vàlid.\n"
"S'està usant la versió %i"
+#: read-cache.c
#, c-format
msgid "bad signature 0x%08x"
msgstr "signatura malmesa 0x%08x"
+#: read-cache.c
#, c-format
msgid "bad index version %d"
msgstr "versió d'índex incorrecta %d"
+#: read-cache.c
msgid "bad index file sha1 signature"
msgstr "signatura sha1 malmesa al fitxer d'índex"
+#: read-cache.c
#, c-format
msgid "index uses %.4s extension, which we do not understand"
msgstr "l'índex usa l'extensió %.4s, que no es pot entendre"
+#: read-cache.c
#, c-format
msgid "ignoring %.4s extension"
msgstr "s'està ignorant l'extensió %.4s"
+#: read-cache.c
#, c-format
msgid "unknown index entry format 0x%08x"
msgstr "format d'entrada d'índex desconeguda «0x%08x»"
+#: read-cache.c
#, c-format
msgid "malformed name field in the index, near path '%s'"
msgstr "camp del nom mal formatat l'índex, camí a prop «%s»"
+#: read-cache.c
msgid "unordered stage entries in index"
msgstr "entrades «stage» no ordenades en l'índex"
+#: read-cache.c
#, c-format
msgid "multiple stage entries for merged file '%s'"
msgstr "múltiples entrades «stage» per al fitxer fusionat «%s»"
+#: read-cache.c
#, c-format
msgid "unordered stage entries for '%s'"
msgstr "entrades «stage» no ordenades per a «%s»"
+#: read-cache.c
#, c-format
msgid "unable to create load_cache_entries thread: %s"
msgstr "no s'ha pogut crear fil «load_cache_entries»: %s"
+#: read-cache.c
#, c-format
msgid "unable to join load_cache_entries thread: %s"
msgstr "no s'ha pogut unir al fil «load_cache_entries»: %s"
+#: read-cache.c
#, c-format
msgid "%s: index file open failed"
msgstr "%s: ha fallat l'obertura del fitxer d'índex"
+#: read-cache.c
#, c-format
msgid "%s: cannot stat the open index"
msgstr "%s: no es pot fer «stat» a l'índex obert"
+#: read-cache.c
#, c-format
msgid "%s: index file smaller than expected"
msgstr "%s: fitxer d'índex més petit que s'esperava"
+#: read-cache.c
#, c-format
msgid "%s: unable to map index file%s"
msgstr "%s: no es pot mapar el fitxer d'índex%s"
+#: read-cache.c
#, c-format
msgid "unable to create load_index_extensions thread: %s"
msgstr "no s'ha pogut crear un fil «load_index_extensions»: %s"
+#: read-cache.c
#, c-format
msgid "unable to join load_index_extensions thread: %s"
msgstr "no s'ha pogut unir un fil «load_index_extensions»: %s"
+#: read-cache.c
#, c-format
msgid "could not freshen shared index '%s'"
msgstr "no s'ha pogut refrescar l'índex compartit «%s»"
+#: read-cache.c
#, c-format
msgid "broken index, expect %s in %s, got %s"
msgstr "índex malmès, s'esperava %s a %s, s'ha rebut %s"
+#: read-cache.c
msgid "cannot write split index for a sparse index"
msgstr "no es pot escriure l'índex dividit per a un índex dispers"
+#: read-cache.c
msgid "failed to convert to a sparse-index"
msgstr "s'ha produït un error en convertir a un índex dispers"
-#, c-format
-msgid "could not stat '%s'"
-msgstr "no s'ha pogut fer stat a «%s»"
-
+#: read-cache.c
#, c-format
msgid "unable to open git dir: %s"
msgstr "no s'ha pogut obrir el directori git: %s"
+#: read-cache.c
#, c-format
msgid "unable to unlink: %s"
msgstr "no s'ha pogut desenllaçar: %s"
+#: read-cache.c
#, c-format
msgid "cannot fix permission bits on '%s'"
msgstr "no s'han pogut corregir els bits de permisos en «%s»"
+#: read-cache.c
#, c-format
msgid "%s: cannot drop to stage #0"
msgstr "%s: no es pot baixar fins al «stage» #0"
+#: read-cache.c
#, c-format
msgid "unexpected diff status %c"
msgstr "estat de diff inesperat %c"
+#: read-cache.c
#, c-format
msgid "remove '%s'\n"
msgstr "elimina «%s»\n"
+#: rebase-interactive.c
msgid ""
"You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
"continue'.\n"
@@ -18860,6 +24505,7 @@ msgstr ""
"continue».\n"
"O bé, podeu avortar el «rebase» amb «git rebase --abort».\n"
+#: rebase-interactive.c
#, c-format
msgid ""
"unrecognized setting %s for option rebase.missingCommitsCheck. Ignoring."
@@ -18867,6 +24513,7 @@ msgstr ""
"no s'ha reconegut el paràmetre %s per rebase.missingCommitsCheck. S'està "
"ignorant."
+#: rebase-interactive.c
msgid ""
"\n"
"Commands:\n"
@@ -18919,20 +24566,22 @@ msgstr ""
" (o línia única, si no hi ha cap comissió de fusió original "
"especificada).\n"
" Useu -c <comissió> per a reescriure el missatge de la comissió.\n"
-"u, update-ref <ref> = segueix un marcador de posició per a actualitzar "
-"<ref>\n"
+"u, update-ref <referència> = segueix un marcador de posició per a "
+"actualitzar <ref>\n"
" a aquesta posició en les comissions noves. La <ref> "
"s'actualitza\n"
" al final del «rebase»\n"
"\n"
"Es pot canviar l'ordre d'aquestes línies; s'executen de dalt a baix.\n"
+#: rebase-interactive.c
#, c-format
msgid "Rebase %s onto %s (%d command)"
msgid_plural "Rebase %s onto %s (%d commands)"
msgstr[0] "Fes «rebase» de %s a %s (%d ordre)"
msgstr[1] "Fes «rebase» de %s a %s (%d ordres)"
+#: rebase-interactive.c
msgid ""
"\n"
"Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
@@ -18941,6 +24590,7 @@ msgstr ""
"No elimineu cap línia. Useu «drop» explícitament per a eliminar una "
"comissió.\n"
+#: rebase-interactive.c
msgid ""
"\n"
"If you remove a line here THAT COMMIT WILL BE LOST.\n"
@@ -18948,6 +24598,7 @@ msgstr ""
"\n"
"Si elimineu una línia aquí, ES PERDRÀ AQUELLA COMISSIÓ.\n"
+#: rebase-interactive.c
msgid ""
"\n"
"You are editing the todo file of an ongoing interactive rebase.\n"
@@ -18961,19 +24612,22 @@ msgstr ""
" git rebase --continue\n"
"\n"
+#: rebase-interactive.c
msgid ""
"\n"
"However, if you remove everything, the rebase will be aborted.\n"
"\n"
msgstr ""
"\n"
-"No obstant això, si elimineu tot, s'avortarà el «rebase».\n"
+"No obstant això, si ho elimineu tot, s'avortarà el «rebase».\n"
"\n"
+#: rebase-interactive.c
#, c-format
msgid "could not write '%s'."
msgstr "no s'ha pogut escriure a «%s»."
+#: rebase-interactive.c
#, c-format
msgid ""
"Warning: some commits may have been dropped accidentally.\n"
@@ -18983,6 +24637,7 @@ msgstr ""
"accidentalment.\n"
"Les comissions descartades (més nova a més vella):\n"
+#: rebase-interactive.c
#, c-format
msgid ""
"To avoid this message, use \"drop\" to explicitly remove a commit.\n"
@@ -18999,113 +24654,146 @@ msgstr ""
"d'advertències.\n"
"Els comportaments possibles són: ignore, warn, error.\n"
+#: rebase.c
#, c-format
msgid "%s: 'preserve' superseded by 'merges'"
msgstr "%s: «conserva» substituït per «fusiona»"
+#: ref-filter.c wt-status.c
msgid "gone"
msgstr "no hi és"
+#: ref-filter.c
#, c-format
msgid "ahead %d"
msgstr "davant per %d"
+#: ref-filter.c
#, c-format
msgid "behind %d"
msgstr "darrere per %d"
+#: ref-filter.c
#, c-format
msgid "ahead %d, behind %d"
msgstr "davant per %d, darrere per %d"
+#: ref-filter.c
#, c-format
msgid "%%(%.*s) does not take arguments"
msgstr "%%(%.*s) no accepta arguments"
+#: ref-filter.c
#, c-format
msgid "unrecognized %%(%.*s) argument: %s"
msgstr "argument %%(%.*s) desconegut: %s"
+#: ref-filter.c
#, c-format
msgid "expected format: %%(color:<color>)"
msgstr "format esperat: %%(color:<color>)"
+#: ref-filter.c
#, c-format
msgid "unrecognized color: %%(color:%s)"
msgstr "color no reconegut: %%(color:%s)"
+#: ref-filter.c
#, c-format
msgid "Integer value expected refname:lstrip=%s"
msgstr "Valor enter esperat pel nom de referència:lstrip=%s"
+#: ref-filter.c
#, c-format
msgid "Integer value expected refname:rstrip=%s"
msgstr "Valor enter esperat pel nom de referència:rstrip=%s"
+#: ref-filter.c
#, c-format
msgid "expected %%(trailers:key=<value>)"
-msgstr "s'esperava %%(trailers:key=<value>)"
+msgstr "s'esperava %%(trailers:key=<valor>)"
+#: ref-filter.c
#, c-format
msgid "unknown %%(trailers) argument: %s"
msgstr "argument %%(trailers) desconegut: %s"
+#: ref-filter.c
#, c-format
msgid "positive value expected contents:lines=%s"
msgstr "valor positiu esperat conté:lines=%s"
+#: ref-filter.c
#, c-format
msgid "argument expected for %s"
msgstr "s'esperava un argument per a %s"
+#: ref-filter.c
#, c-format
msgid "positive value expected %s=%s"
msgstr "valor positiu esperat %s=%s"
+#: ref-filter.c
#, c-format
msgid "cannot fully parse %s=%s"
msgstr "no es pot analitzar completament %s=%s"
+#: ref-filter.c
#, c-format
msgid "value expected %s="
msgstr "s'esperava un valor %s="
+#: ref-filter.c
#, c-format
msgid "positive value expected '%s' in %%(%s)"
msgstr "valor positiu esperat «%s» a %%(%s)"
+#: ref-filter.c
#, c-format
msgid "expected format: %%(align:<width>,<position>)"
msgstr "format esperat: %%(align:<amplada>,<posició>)"
+#: ref-filter.c
#, c-format
msgid "unrecognized position:%s"
msgstr "posició no reconeguda:%s"
+#: ref-filter.c
#, c-format
msgid "unrecognized width:%s"
msgstr "amplada no reconeguda:%s"
+#: ref-filter.c
#, c-format
msgid "unrecognized %%(%s) argument: %s"
msgstr "argument %%(%s) desconegut: %s"
+#: ref-filter.c
#, c-format
msgid "positive width expected with the %%(align) atom"
msgstr "amplada positiva esperada amb l'àtom %%(align)"
+#: ref-filter.c
#, c-format
msgid "expected format: %%(ahead-behind:<committish>)"
msgstr "format esperat: %%(ahead-behind:<committish>)"
+#: ref-filter.c
+#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "format esperat: %%(is-base:<committish>)"
+
+#: ref-filter.c
#, c-format
msgid "malformed field name: %.*s"
msgstr "nom de camp mal format: %.*s"
+#: ref-filter.c
#, c-format
msgid "unknown field name: %.*s"
msgstr "nom de camp desconegut: %.*s"
+#: ref-filter.c
#, c-format
msgid ""
"not a git repository, but the field '%.*s' requires access to object data"
@@ -19113,117 +24801,147 @@ msgstr ""
"no és un repositori git, però el camp «%.*s» requereix accés a les dades de "
"l'objecte"
+#: ref-filter.c
#, c-format
msgid "format: %%(%s) atom used without a %%(%s) atom"
msgstr "format: l'àtom %%(%s) usat sense un àtom %%(%s)"
+#: ref-filter.c
#, c-format
msgid "format: %%(then) atom used more than once"
msgstr "format: s'ha usat l'àtom %%(then) més d'un cop"
+#: ref-filter.c
#, c-format
msgid "format: %%(then) atom used after %%(else)"
msgstr "format: s'ha usat l'àtom %%(then) després de %%(else)"
+#: ref-filter.c
#, c-format
msgid "format: %%(else) atom used more than once"
msgstr "format: s'ha usat l'àtom %%(else) més d'un cop"
+#: ref-filter.c
#, c-format
msgid "format: %%(end) atom used without corresponding atom"
msgstr "format: s'ha usat l'àtom %%(end) sense l'àtom corresponent"
+#: ref-filter.c
#, c-format
msgid "malformed format string %s"
msgstr "cadena de format mal format %s"
+#: ref-filter.c
#, c-format
msgid "this command reject atom %%(%.*s)"
msgstr "aquesta ordre rebutja l'àtom %%(%.*s)"
+#: ref-filter.c
#, c-format
msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
msgstr "no es pot usar --format=%.*s amb --python, --shell, --tcl"
+#: ref-filter.c
msgid "failed to run 'describe'"
msgstr "no s'ha pogut executar «describe»"
+#: ref-filter.c
#, c-format
msgid "(no branch, rebasing %s)"
msgstr "(sense branca, s'està fent «rebase» %s)"
+#: ref-filter.c
#, c-format
msgid "(no branch, rebasing detached HEAD %s)"
msgstr "(sense branca, s'està fent «rebase» d'un «HEAD» separat %s)"
+#: ref-filter.c
#, c-format
msgid "(no branch, bisect started on %s)"
msgstr "(sense branca, bisecció començada en %s)"
+#: ref-filter.c
#, c-format
msgid "(HEAD detached at %s)"
msgstr "(HEAD separat a %s)"
+#: ref-filter.c
#, c-format
msgid "(HEAD detached from %s)"
msgstr "(HEAD separat des de %s)"
+#: ref-filter.c
msgid "(no branch)"
msgstr "(sense branca)"
+#: ref-filter.c
#, c-format
msgid "missing object %s for %s"
msgstr "manca l'objecte %s per a %s"
+#: ref-filter.c
#, c-format
msgid "parse_object_buffer failed on %s for %s"
msgstr "parse_object_buffer ha fallat en %s per a %s"
+#: ref-filter.c
#, c-format
msgid "malformed object at '%s'"
msgstr "objecte mal format a «%s»"
+#: ref-filter.c
#, c-format
msgid "ignoring ref with broken name %s"
msgstr "s'està ignorant la referència amb nom malmès %s"
+#: ref-filter.c refs.c
#, c-format
msgid "ignoring broken ref %s"
msgstr "s'està ignorant la referència malmesa %s"
+#: ref-filter.c
#, c-format
msgid "format: %%(end) atom missing"
msgstr "format: manca l'àtom %%(end)"
+#: ref-filter.c
#, c-format
msgid "malformed object name %s"
msgstr "nom d'objecte %s mal format"
+#: ref-filter.c
#, c-format
msgid "option `%s' must point to a commit"
msgstr "l'opció «%s» ha d'apuntar a una comissió"
+#: ref-filter.h
msgid "key"
msgstr "clau"
+#: ref-filter.h
msgid "field name to sort on"
msgstr "nom del camp en el qual ordenar"
+#: ref-filter.h
msgid "exclude refs which match pattern"
msgstr "exclou refs que coincideixin amb el patró"
+#: reflog.c
#, c-format
msgid "not a reflog: %s"
-msgstr "no és un registre de referència: %s"
+msgstr "no és un registre de referències: %s"
+#: reflog.c
#, c-format
msgid "no reflog for '%s'"
-msgstr "cap registre de referència per a «%s»"
+msgstr "cap registre de referències per a «%s»"
+#: refs.c
#, c-format
msgid "%s does not point to a valid object!"
msgstr "%s no apunta a un objecte vàlid"
+#: refs.c
#, c-format
msgid ""
"Using '%s' as the name for the initial branch. This default branch name\n"
@@ -19251,235 +24969,438 @@ msgstr ""
"\n"
"\tgit branch -m <nom>\n"
+#: refs.c
#, c-format
msgid "could not retrieve `%s`"
msgstr "no s'ha pogut recuperar «%s»"
+#: refs.c
#, c-format
msgid "invalid branch name: %s = %s"
msgstr "nom de branca no vàlida: %s = %s"
+#: refs.c
#, c-format
msgid "ignoring dangling symref %s"
-msgstr "s'està ignorant symref penjant %s"
+msgstr "s'està ignorant referència simbòlica despenjada %s"
+#: refs.c
#, c-format
msgid "log for ref %s has gap after %s"
msgstr "registre per a ref %s té un buit després de %s"
+#: refs.c
#, c-format
msgid "log for ref %s unexpectedly ended on %s"
msgstr "registre per als ref %s ha acabat inesperadament a %s"
+#: refs.c
#, c-format
msgid "log for %s is empty"
msgstr "el registre per a %s és buit"
+#: refs.c
+msgid "refusing to force and skip creation of reflog"
+msgstr ""
+"s'ha rebutjat l'acció forçada i l'omissió de crear un registre de referències"
+
+#: refs.c
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "s'està refusant la referència amb nom malmès «%s»"
+#: refs.c
+#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "s'ha rebutjat l'actualització de la pseudoreferència «%s»"
+
+#: refs.c
#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "ha fallat update_ref per a la ref «%s»: %s"
+#: refs.c
#, c-format
msgid "multiple updates for ref '%s' not allowed"
msgstr "no es permeten múltiples actualitzacions per a la referència «%s»"
+#: refs.c
msgid "ref updates forbidden inside quarantine environment"
msgstr "no està permès actualitzar les referències en un entorn de quarantena"
+#: refs.c
msgid "ref updates aborted by hook"
msgstr "les actualitzacions de referències s'han avortat per un lligam"
+#: refs.c
#, c-format
msgid "'%s' exists; cannot create '%s'"
msgstr "«%s» existeix; no es pot crear «%s»"
+#: refs.c
#, c-format
msgid "cannot process '%s' and '%s' at the same time"
msgstr "no es poden processar «%s» i «%s» a la vegada"
-#, c-format
-msgid "could not remove reference %s"
-msgstr "no s'ha pogut eliminar la referència %s"
-
+#: refs.c
#, c-format
msgid "could not delete reference %s: %s"
msgstr "no s'ha pogut suprimir la referència %s: %s"
+#: refs.c
#, c-format
msgid "could not delete references: %s"
msgstr "no s'han pogut suprimir les referències: %s"
+# 2 línies OK?
+#: refs.c
+#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr ""
+"S'ha acabat la prova no destructiva de migració de referències;\n"
+"el resultat es pot trobar a «%s»\n"
+
+# migració OK?
+#: refs.c
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "no s'ha pogut eliminar el directori temporal de migració «%s»"
+
+# migrar OK?
+#: refs.c
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "les referències migrades es poden trobar en «%s»"
+
+#: refs/files-backend.c refs/reftable-backend.c
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"no puc bloquejar la referència«%s»: s'esperava una referència\n"
+"simbòlica amb destinació «%s» però és una referència regular"
+
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "no es pot obrir el directori «%s»"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "S'està comprovant la consistència de les referències"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "el nom de referència és perillós: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr ""
+"s'està intentant escriure la referència «%s» amb l'objecte que no existeix %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr ""
+"s'està intentant escriure un objecte no de comissió %s en la branca «%s»"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"no es permeten actualitzacions múltiples de «HEAD» (inclosa una feta a "
+"través del\n"
+"seu referent «%s»)"
+
+# bloquejar → blocar
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr ""
+"no es pot bloquejar la referència «%s»: no s'ha pogut resoldre la referència "
+"«%s»"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "no es pot bloquejar la referència «%s»: error en llegir la referència"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"no es permeten les actualitzacions múltiples per a «%s» (inclosa una a\n"
+"través de la referència simbòlica «%s»"
+
+# bloquejar→blocar?
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "no puc bloquejar la referència «%s»: la referència ja existeix"
+
+# massa llarg?
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr ""
+"no puc bloquejar la referència «%s»: manca la referència però s'esperava %s"
+
+# blocar→bloquejar?
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "no puc bloquejar la referència «%s»: és en %s però s'esperava %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "taula de referències: prepara transacció: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "taula de referències: fallada de transacció: %s"
+
+# stack→pila OK?
+#: refs/reftable-backend.c
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "no es pot compactar la pila: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s not found"
+msgstr "no s'ha trobat el nom de referència %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr ""
+"el nom de referència %s és una referència simbòlica: no es permet copiar"
+
+#: refspec.c
#, c-format
msgid "invalid refspec '%s'"
msgstr "refspec no vàlida: «%s»"
+#: remote-curl.c
#, c-format
msgid "invalid quoting in push-option value: '%s'"
msgstr "citació no vàlida en el valor de l'opció de pujada: «%s»"
+# object-format no traduït perquè és part de --show-object-format
+#: remote-curl.c
+#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "valor desconegut per a l'object-format: %s"
+
+#: remote-curl.c
#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs no vàlides: és un repositori git?"
+#: remote-curl.c
msgid "invalid server response; expected service, got flush packet"
msgstr ""
"resposta del servidor no és vàlida; el servei esperat, ha rebut in paquet de "
"neteja"
+#: remote-curl.c
#, c-format
msgid "invalid server response; got '%s'"
msgstr "resposta del servidor no vàlida; s'ha obtingut «%s»"
+#: remote-curl.c
#, c-format
msgid "repository '%s' not found"
msgstr "no s'ha trobat el repositori «%s»"
+#: remote-curl.c
#, c-format
msgid "Authentication failed for '%s'"
msgstr "S'ha produït un error en autenticar per «%s»"
+#: remote-curl.c
#, c-format
msgid "unable to access '%s' with http.pinnedPubkey configuration: %s"
msgstr "no es pot accedir a «%s» la configuració de http.pinnedPubkey :%s"
+#: remote-curl.c
#, c-format
msgid "unable to access '%s': %s"
msgstr "no s'ha pogut accedir a «%s»: %s"
+#: remote-curl.c
#, c-format
msgid "redirecting to %s"
msgstr "s'està redirigint a %s"
+#: remote-curl.c
msgid "shouldn't have EOF when not gentle on EOF"
msgstr "no hauria de tenir EOF quan s'és lax amb els EOF"
+#: remote-curl.c
msgid "remote server sent unexpected response end packet"
msgstr "el servidor remot ha enviat un paquet de final de resposta inesperat"
+#: remote-curl.c
msgid "unable to rewind rpc post data - try increasing http.postBuffer"
msgstr ""
"no s'han pogut rebobinar les dades de publicació rpc - proveu d'augmentar "
"http.postBuffer"
+#: remote-curl.c
#, c-format
msgid "remote-curl: bad line length character: %.4s"
msgstr "remote-curl: caràcter de longitud de línia erroni: %.4s"
+#: remote-curl.c
msgid "remote-curl: unexpected response end packet"
msgstr "remote-curl: paquet final de resposta inesperat"
+#: remote-curl.c
#, c-format
msgid "RPC failed; %s"
msgstr "RPC ha fallat; %s"
+#: remote-curl.c
msgid "cannot handle pushes this big"
msgstr "no es pot gestionar pujades tan grans"
+#: remote-curl.c
#, c-format
msgid "cannot deflate request; zlib deflate error %d"
msgstr "no es pot descomprimir la sol·licitud; error de deflate zlib %d"
+#: remote-curl.c
#, c-format
msgid "cannot deflate request; zlib end error %d"
msgstr ""
"no es pot descomprimir la sol·licitud; error de finalització de zlib %d"
+#: remote-curl.c
#, c-format
msgid "%d bytes of length header were received"
-msgstr "s'han rebut %d bytes de longitud de capçalera"
+msgstr "s'han rebut %d octets de longitud de capçalera"
+#: remote-curl.c
#, c-format
msgid "%d bytes of body are still expected"
-msgstr "encara s'esperen %d bytes del cos"
+msgstr "encara s'esperen %d octets del cos"
+#: remote-curl.c
msgid "dumb http transport does not support shallow capabilities"
msgstr "el transport ximple http no admet capacitats superficials"
+#: remote-curl.c
msgid "fetch failed."
msgstr "l'obtenció ha fallat."
+#: remote-curl.c
msgid "cannot fetch by sha1 over smart http"
msgstr "no s'ha pogut obtenir per sha1 a través de l'http intel·ligent"
+#: remote-curl.c
#, c-format
msgid "protocol error: expected sha/ref, got '%s'"
msgstr "error de protocol: s'esperava sha/ref, s'ha obtingut «%s»"
+#: remote-curl.c
#, c-format
msgid "http transport does not support %s"
msgstr "El transport http no admet %s"
+#: remote-curl.c
msgid "protocol error: expected '<url> <path>', missing space"
msgstr ""
"s'ha produït un error de protocol: s'esperava «<url> <camí>», falta espai"
+#: remote-curl.c
#, c-format
msgid "failed to download file at URL '%s'"
msgstr "no s'ha pogut baixar el fitxer a l'URL «%s»"
+#: remote-curl.c
msgid "git-http-push failed"
msgstr "git-http-push ha fallat"
+#: remote-curl.c
msgid "remote-curl: usage: git remote-curl <remote> [<url>]"
-msgstr "remote-curl: ús: git remote-curl <remote> [<url>]"
+msgstr "remote-curl: ús: git remote-curl <remot> [<url>]"
+#: remote-curl.c
msgid "remote-curl: error reading command stream from git"
msgstr "remote-curl: error en llegir el flux d'ordres del git"
+#: remote-curl.c
msgid "remote-curl: fetch attempted without a local repo"
msgstr "remote-curl: s'ha intentat l'obtenció sense un repositori local"
+#: remote-curl.c
#, c-format
msgid "remote-curl: unknown command '%s' from git"
msgstr "remote-curl: ordre «%s» desconeguda del git"
+#: remote.c
#, c-format
msgid "config remote shorthand cannot begin with '/': %s"
msgstr ""
"l'abreviatura del fitxer de configuració remot no pot començar amb «/»: %s"
+#: remote.c
msgid "more than one receivepack given, using the first"
msgstr "més d'un paquet de recepció donat, usant el primer"
+#: remote.c
msgid "more than one uploadpack given, using the first"
msgstr "més d'un paquet de càrrega donat, usant el primer"
+#: remote.c
#, c-format
msgid "unrecognized value transfer.credentialsInUrl: '%s'"
msgstr "valor no conegut per a transfer.credentialsInUrl: «%s»"
+#: remote.c
#, c-format
msgid "URL '%s' uses plaintext credentials"
msgstr "L'URL «%s» utilitza credencials en text pla"
+#: remote.c
#, c-format
msgid "Cannot fetch both %s and %s to %s"
msgstr "No es poden obtenir ambdós %s i %s a %s"
+#: remote.c
#, c-format
msgid "%s usually tracks %s, not %s"
msgstr "%s generalment segueix %s, no %s"
+#: remote.c
#, c-format
msgid "%s tracks both %s and %s"
msgstr "%s segueix ambdós %s i %s"
+#: remote.c
#, c-format
msgid "key '%s' of pattern had no '*'"
msgstr "la clau «%s» del patró no té «*»"
+#: remote.c
#, c-format
msgid "value '%s' of pattern has no '*'"
msgstr "el valor «%s» del patró no té «*»"
+#: remote.c
#, c-format
msgid "src refspec %s does not match any"
msgstr "l'especificació de referència font %s no coincideix amb cap referència"
+#: remote.c
#, c-format
msgid "src refspec %s matches more than one"
msgstr ""
@@ -19489,6 +25410,7 @@ msgstr ""
#. <remote> <src>:<dst>" push, and "being pushed ('%s')" is
#. the <src>.
#.
+#: remote.c
#, c-format
msgid ""
"The destination you provided is not a full refname (i.e.,\n"
@@ -19511,6 +25433,7 @@ msgstr ""
"\n"
"Res d'això ha funcionat. Cal que proporcioneu una referència completa."
+#: remote.c
#, c-format
msgid ""
"The <src> part of the refspec is a commit object.\n"
@@ -19522,6 +25445,7 @@ msgstr ""
"Voleu crear una branca nova empenyent a\n"
"«%s:refs/heads/%s»?"
+#: remote.c
#, c-format
msgid ""
"The <src> part of the refspec is a tag object.\n"
@@ -19529,8 +25453,9 @@ msgid ""
"'%s:refs/tags/%s'?"
msgstr ""
"La part <src> de l'especificació de la referència és un objecte d'etiqueta.\n"
-"Voleu crear una etiqueta pujant-la a «%srefs/tags/%s»?"
+"Voleu crear una etiqueta pujant-la a «%s:refs/tags/%s»?"
+#: remote.c
#, c-format
msgid ""
"The <src> part of the refspec is a tree object.\n"
@@ -19538,8 +25463,9 @@ msgid ""
"'%s:refs/tags/%s'?"
msgstr ""
"La part <src> de l'especificació de la referència és un objecte d'arbre.\n"
-"Voleu crear una etiqueta pujant-la a «%srefs/tags/%s»?"
+"Voleu crear una etiqueta pujant-la a «%s:refs/tags/%s»?"
+#: remote.c
#, c-format
msgid ""
"The <src> part of the refspec is a blob object.\n"
@@ -19550,93 +25476,116 @@ msgstr ""
"Voleu posar una etiqueta al blob nou mitjançant la pujada a\n"
"?«%s:refs/tags/%s»?"
+#: remote.c
#, c-format
msgid "%s cannot be resolved to branch"
msgstr "«%s» no es pot resoldre a una branca"
+#: remote.c
#, c-format
msgid "unable to delete '%s': remote ref does not exist"
msgstr "no s'ha pogut suprimir «%s»: la referència remota no existeix"
+#: remote.c
#, c-format
msgid "dst refspec %s matches more than one"
msgstr ""
"l'especificació de la referència dst %s coincideixen amb més d'una referència"
+#: remote.c
#, c-format
msgid "dst ref %s receives from more than one src"
msgstr "l'especificació de la referència dst %s rep més d'una referència src"
+#: remote.c
msgid "HEAD does not point to a branch"
msgstr "HEAD no assenyala cap branca"
+#: remote.c
#, c-format
msgid "no such branch: '%s'"
msgstr "no existeix la branca: «%s»"
+#: remote.c
#, c-format
msgid "no upstream configured for branch '%s'"
msgstr "cap font configurada per a la branca «%s»"
+#: remote.c
#, c-format
msgid "upstream branch '%s' not stored as a remote-tracking branch"
msgstr "la branca font «%s» no s'emmagatzema com a branca amb seguiment remot"
+#: remote.c
#, c-format
msgid "push destination '%s' on remote '%s' has no local tracking branch"
msgstr ""
"el destí de pujada «%s» en el remot «%s» no té cap branca amb seguiment remot"
+#: remote.c
#, c-format
msgid "branch '%s' has no remote for pushing"
msgstr "la branca «%s» no té cap remot al qual pujar"
+#: remote.c
#, c-format
msgid "push refspecs for '%s' do not include '%s'"
msgstr "les especificacions de referència de pujada «%s» no inclouen «%s»"
+#: remote.c
msgid "push has no destination (push.default is 'nothing')"
msgstr "push no té destí (push.default és «nothing»)"
+#: remote.c
msgid "cannot resolve 'simple' push to a single destination"
msgstr "no es pot resoldre una pujada «simple» a un sol destí"
+#: remote.c
#, c-format
msgid "couldn't find remote ref %s"
msgstr "no s'ha pogut trobar la referència remota %s"
+#: remote.c
#, c-format
msgid "* Ignoring funny ref '%s' locally"
msgstr "* S'estan ignorant les referències «%s» localment"
+#: remote.c
#, c-format
msgid "Your branch is based on '%s', but the upstream is gone.\n"
msgstr "La vostra branca està basada en «%s», però la font no hi és.\n"
+#: remote.c
msgid " (use \"git branch --unset-upstream\" to fixup)\n"
msgstr " (useu «git branch --unset-upstream» per a arreglar-ho)\n"
+#: remote.c
#, c-format
msgid "Your branch is up to date with '%s'.\n"
msgstr "La vostra branca està al dia amb «%s».\n"
+#: remote.c
#, c-format
msgid "Your branch and '%s' refer to different commits.\n"
-msgstr "La vostra branca i «%s» es refereixen a diferents comissions.\n"
+msgstr "La vostra branca i «%s» es refereixen a comissions.\n"
+#: remote.c
#, c-format
msgid " (use \"%s\" for details)\n"
msgstr " (useu «%s» per a detalls)\n"
+#: remote.c
#, 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] "La vostra branca està %2$d comissió per davant de «%1$s».\n"
msgstr[1] "La vostra branca està %2$d comissions per davant de «%1$s».\n"
+#: remote.c
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (useu «git push» per a publicar les vostres comissions locals)\n"
+#: remote.c
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -19648,9 +25597,11 @@ msgstr[1] ""
"La vostra branca està %2$d comissions per darrere de «%1$s», i pot avançar-"
"se ràpidament.\n"
+#: remote.c
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (useu «git pull» per a actualitzar la vostra branca local)\n"
+#: remote.c
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -19665,270 +25616,396 @@ msgstr[1] ""
"La vostra branca i «%s» han divergit,\n"
"i tenen %d i %d comissions distintes cada una, respectivament.\n"
+#: remote.c
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"
+#: remote.c
#, c-format
msgid "cannot parse expected object name '%s'"
msgstr "no es pot analitzar el nom de l'objecte esperat «%s»"
+#: remote.c
#, c-format
msgid "cannot strip one component off url '%s'"
msgstr "no es pot despullar un component de l'url «%s»"
+#: replace-object.c
#, c-format
msgid "bad replace ref name: %s"
msgstr "nom de la referència reemplaçada incorrecte: %s"
+#: replace-object.c
#, c-format
msgid "duplicate replace ref: %s"
msgstr "duplica les referències reemplaçades: %s"
+#: replace-object.c
#, c-format
msgid "replace depth too high for object %s"
msgstr "la profunditat de reemplaçament és massa alta per l'objecte %s"
+#: rerere.c
msgid "corrupt MERGE_RR"
msgstr "MERGE_RR corrupte"
+#: rerere.c
msgid "unable to write rerere record"
msgstr "no s'ha pogut escriure el registre «rerere»"
+#: rerere.c
#, c-format
msgid "there were errors while writing '%s' (%s)"
msgstr "s'han produït errors en escriure «%s» (%s)"
+#: rerere.c
#, c-format
msgid "could not parse conflict hunks in '%s'"
msgstr "no s'han pogut analitzar els pedaços en conflicte a «%s»"
+#: rerere.c
#, c-format
msgid "failed utime() on '%s'"
msgstr "s'ha produït un error en fer «failed utime()» a «%s»"
+#: rerere.c
#, c-format
msgid "writing '%s' failed"
msgstr "s'ha produït un error en escriure «%s»"
+#: rerere.c
#, c-format
msgid "Staged '%s' using previous resolution."
msgstr "«Staged» «%s» utilitzant una resolució anterior."
+#: rerere.c
#, c-format
msgid "Recorded resolution for '%s'."
msgstr "Es recorda la resolució per a «%s»."
+#: rerere.c
#, c-format
msgid "Resolved '%s' using previous resolution."
msgstr "S'ha resolt «%s» usant una resolució anterior."
+#: rerere.c
#, c-format
msgid "cannot unlink stray '%s'"
msgstr "no es pot desenllaçar «%s» (extraviat)"
+#: rerere.c
#, c-format
msgid "Recorded preimage for '%s'"
msgstr "Imatge prèvia registrada per a «%s»"
+#: rerere.c
#, c-format
msgid "failed to update conflicted state in '%s'"
msgstr "ha fallat en actualitzar l'estat en conflicte a «%s»"
+#: rerere.c
#, c-format
msgid "no remembered resolution for '%s'"
msgstr "no hi ha cap resolució recordada per a «%s»"
+#: rerere.c
#, c-format
msgid "Updated preimage for '%s'"
msgstr "Imatge prèvia actualitzada per a «%s»"
+#: rerere.c
#, c-format
msgid "Forgot resolution for '%s'\n"
msgstr "S'ha oblidat la resolució per a «%s»\n"
+#: rerere.c
msgid "unable to open rr-cache directory"
msgstr "no s'ha pogut obrir el directori rr-cache"
+#: rerere.h
msgid "update the index with reused conflict resolution if possible"
msgstr ""
"actualitza l'índex amb la resolució de conflictes reusada si és possible"
+#: reset.c
msgid "could not determine HEAD revision"
msgstr "no s'ha pogut determinar la revisió de HEAD"
+#: reset.c sequencer.c
#, c-format
msgid "failed to find tree of %s"
msgstr "s'ha produït un error en cercar l'arbre de %s"
+#: revision.c
#, c-format
msgid "unsupported section for hidden refs: %s"
msgstr "secció d'índex no compatible per a les referències ocultes: %s"
+#: revision.c
msgid "--exclude-hidden= passed more than once"
msgstr "--exclude-hidden= passat més d'una vegada"
+#: revision.c
#, c-format
msgid "resolve-undo records `%s` which is missing"
msgstr "resolve-undo indica «%s» que manquen"
+#: revision.c
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "no s'ha pogut obtenir la comissió per a l'argument d'ancestry-path %s"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s existeix però és una referència simbòlica"
+
+#: revision.c
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge requereix una de les pseudoreferències MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD o REBASE_HEAD"
+#: revision.c
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr ""
+"no s'ha pogut obtenir una comissió per a l'argument %s d'--ancestry-path"
+
+#: revision.c
msgid "--unpacked=<packfile> no longer supported"
msgstr "--unpacked=<packfile> ja no s'admet"
+#: revision.c
#, c-format
msgid "invalid option '%s' in --stdin mode"
msgstr "opció no vàlida: «%s» en mode --stdin"
+#: revision.c
msgid "your current branch appears to be broken"
msgstr "la vostra branca actual sembla malmesa"
+#: revision.c
#, c-format
msgid "your current branch '%s' does not have any commits yet"
msgstr "la branca actual «%s» encara no té cap comissió"
+#: revision.c
msgid "object filtering requires --objects"
msgstr "el filtratge d'objectes requereix --objects"
+#: revision.c
msgid "-L does not yet support diff formats besides -p and -s"
msgstr "-L no és encara compatible amb formats que no siguin «-p» o «-s»"
+#: run-command.c
#, c-format
msgid "cannot create async thread: %s"
msgstr "no s'ha pogut crear fil «async»: %s"
+#: scalar.c worktree.c
#, c-format
msgid "'%s' does not exist"
msgstr "«%s» no existeix"
+#: scalar.c
#, c-format
msgid "could not switch to '%s'"
msgstr "no s'ha pogut commutar a «%s»"
+#: scalar.c
msgid "need a working directory"
msgstr "cal un directori de treball"
+#: scalar.c
msgid "Scalar enlistments require a worktree"
msgstr "Els allistaments escalars requereixen un arbre de treball"
+#: scalar.c
#, c-format
msgid "could not configure %s=%s"
msgstr "no s'ha pogut configurar %s=%s"
+#: scalar.c
msgid "could not configure log.excludeDecoration"
msgstr "no s'ha pogut configurar log.excludeDecoration"
+#: scalar.c
msgid "could not add enlistment"
msgstr "no s'ha afegit a l'allistament"
+#: scalar.c
msgid "could not set recommended config"
msgstr "no s'ha pogut establir la configuració recomanada"
+#: scalar.c
msgid "could not turn on maintenance"
msgstr "no s'ha pogut activar el manteniment"
+#: scalar.c
msgid "could not start the FSMonitor daemon"
msgstr "no s'ha pogut iniciar el dimoni del fsmonitor"
+#: scalar.c
msgid "could not turn off maintenance"
msgstr "no s'ha pogut desactivar el manteniment"
+#: scalar.c
msgid "could not remove enlistment"
msgstr "no s'ha pogut eliminar l'allistament"
+#: scalar.c
#, c-format
msgid "remote HEAD is not a branch: '%.*s'"
msgstr "la HEAD remota no és una branca: «%.*s»"
+#: scalar.c
msgid "failed to get default branch name from remote; using local default"
msgstr ""
"no s'ha pogut obtenir el nom de la branca per defecte del remot; s'usa ela "
"predeterminada localment"
+#: scalar.c
msgid "failed to get default branch name"
msgstr "s'ha produït un error en obtenir el nom de branca predeterminada"
+#: scalar.c
msgid "failed to unregister repository"
msgstr "s'ha produït un error en desregistrar el repositori"
+#: scalar.c
msgid "failed to stop the FSMonitor daemon"
msgstr "no s'ha pogut aturar el dimoni del FSMonitor"
+#: scalar.c
msgid "failed to delete enlistment directory"
msgstr "s'ha produït un error en suprimir l'allistament del directori"
+#: scalar.c
msgid "branch to checkout after clone"
msgstr "branca a agafar després de clonar"
+#: scalar.c
msgid "when cloning, create full working directory"
msgstr "quan es clona, crear un directori de treball complet"
+#: scalar.c
msgid "only download metadata for the branch that will be checked out"
msgstr "només baixa les metadades per a la branca que s'agafarà"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<opcions>] [--] <repositori> [<dir>]"
+#: scalar.c
+msgid "create repository within 'src' directory"
+msgstr "crea un repositori dins del directori «src»"
+#: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "especifica si les etiquetes s'han d'obtenir durant el clon"
+
+# Deixem <enlistment> sense traduir de moment
+#: scalar.c
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <branca-principal>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+
+#: scalar.c
#, c-format
msgid "cannot deduce worktree name from '%s'"
msgstr "no es pot deduir el nom de l'arbre de treball de «%s»"
+#: scalar.c
#, c-format
msgid "directory '%s' exists already"
msgstr "el directori «%s» ja existeix"
+#: scalar.c
#, c-format
msgid "failed to get default branch for '%s'"
msgstr "s'ha produït un error en obtenir la branca per defecte per a «%s»"
+#: scalar.c
#, c-format
msgid "could not configure remote in '%s'"
msgstr "no s'ha pogut configurar el remot a «%s»"
+#: scalar.c
+#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "no s'han pogut inhabilitar les etiquetes en «%s»"
+
+#: scalar.c
#, c-format
msgid "could not configure '%s'"
msgstr "no s'ha pogut configurar «%s»"
+#: scalar.c
msgid "partial clone failed; attempting full clone"
msgstr "ha fallat la clonació parcial; s'està intentant la clonació completa"
+#: scalar.c
msgid "could not configure for full clone"
msgstr "no s'ha pogut configurar per a una clonació completa"
+#: scalar.c
msgid "scalar diagnose [<enlistment>]"
msgstr "scalar diagnose [<enlistment>]"
+#: scalar.c
msgid "`scalar list` does not take arguments"
msgstr "«scalar list» no accepta arguments"
+#: scalar.c
msgid "scalar register [<enlistment>]"
msgstr "scalar register [<enlistment>]"
+#: scalar.c
msgid "reconfigure all registered enlistments"
msgstr "reconfigura tots els allistaments registrats"
+#: scalar.c
msgid "scalar reconfigure [--all | <enlistment>]"
msgstr "scalar reconfigure [--all | <enlistment>]"
+#: scalar.c
msgid "--all or <enlistment>, but not both"
msgstr "--all o <enlistment>, però no ambdós"
+#: scalar.c
#, c-format
msgid "could not remove stale scalar.repo '%s'"
msgstr "no s'ha pogut suprimir el scalar.repo «%s» estancat"
+#: scalar.c
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "s'està eliminant el scalar.repo «%s» estancat"
+msgid "removed stale scalar.repo '%s'"
+msgstr "s'ha eliminat l'scalar.repo estancat «%s»"
+#: scalar.c
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "no existeix un repositori de git a: «%s»"
+msgid "repository at '%s' has different owner"
+msgstr "el dipòsit a «%s» té un propietari diferent"
+#: scalar.c
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "el dipòsit a «%s» té un problema de format"
+
+#: scalar.c
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "no s'ha trobat el dipòsit a «%s»"
+
+#: scalar.c
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"per a desregistrar aquest dipòsit de l'escalar, executeu\n"
+"\tgit config --global --unset --fixed-value scalar.repo «%s»"
+
+#: scalar.c
msgid ""
"scalar run <task> [<enlistment>]\n"
"Tasks:\n"
@@ -19936,77 +26013,97 @@ msgstr ""
"scalar run <task> {<enlistment>]\n"
"Tasques:\n"
+#: scalar.c
#, c-format
msgid "no such task: '%s'"
msgstr "no existeix la tasca: «%s»"
+#: scalar.c
msgid "scalar unregister [<enlistment>]"
msgstr "scalar unregister [<enlistment>]"
+#: scalar.c
msgid "scalar delete <enlistment>"
msgstr "supressió de l'escalar <enlistment>"
+#: scalar.c
msgid "refusing to delete current working directory"
msgstr "s'ha rebutjat suprimir el directori de treball actual"
+#: scalar.c
msgid "include Git version"
msgstr "inclou la versió del Git"
+#: scalar.c
msgid "include Git's build options"
msgstr "inclou les opcions de construcció del Git"
+#: scalar.c
msgid "scalar verbose [-v | --verbose] [--build-options]"
msgstr "scalar verbose [-v | --verbose] [--build-options]"
+#: scalar.c
msgid "-C requires a <directory>"
-msgstr "-C requereix un <directory>"
+msgstr "-C requereix un <directori>"
+#: scalar.c
#, c-format
msgid "could not change to '%s'"
msgstr "no s'ha pogut canviar a «%s»"
+#: scalar.c
msgid "-c requires a <key>=<value> argument"
-msgstr "-c requereix un argument <key>=<value>"
+msgstr "-c requereix un argument <clau>=<valor>"
+#: scalar.c
msgid ""
"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
"\n"
"Commands:\n"
msgstr ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<opcions>]\n"
+"scalar [-C <directori>] [-c <clau>=<valor>] <ordre> [<opcions>]\n"
"\n"
"Ordres:\n"
+#: send-pack.c
msgid "unexpected flush packet while reading remote unpack status"
msgstr ""
"paquet de buidatge no esperat quan estava llegint l'estat del "
"desempaquetament remot"
+#: send-pack.c
#, c-format
msgid "unable to parse remote unpack status: %s"
msgstr "no s'ha pogut analitzar l'estat del desempaquetament remot: %s"
+#: send-pack.c
#, c-format
msgid "remote unpack failed: %s"
msgstr "s'ha produït un error en el desempaquetament remot: %s"
+#: send-pack.c
msgid "failed to sign the push certificate"
msgstr "s'ha produït un error en signar el certificat de pujada"
+#: send-pack.c
msgid "send-pack: unable to fork off fetch subprocess"
msgstr "send-pack: no es pot bifurcar obtenint un subprocés"
+#: send-pack.c
msgid "push negotiation failed; proceeding anyway with push"
msgstr ""
"ha fallat la negociació de la pujada; s'està procedint igualment amb "
"l'empenta"
+#: send-pack.c
msgid "the receiving end does not support this repository's hash algorithm"
msgstr "el receptor de destí no admet l'algorisme de resum del repositori"
+#: send-pack.c
msgid "the receiving end does not support --signed push"
msgstr "el destí receptor no admet pujar --signed"
+#: send-pack.c
msgid ""
"not sending a push certificate since the receiving end does not support --"
"signed push"
@@ -20014,33 +26111,58 @@ msgstr ""
"no s'està enviant una certificació de pujada perquè el destí receptor no "
"admet pujar --signed"
+#: send-pack.c
msgid "the receiving end does not support --atomic push"
msgstr "el destí receptor no admet pujar --atomic"
+#: send-pack.c
msgid "the receiving end does not support push options"
msgstr "el receptor al destí no admet opcions de pujada"
+#: sequencer.c
#, c-format
msgid "invalid commit message cleanup mode '%s'"
msgstr "mode de neteja «%s» no vàlid en la comissió del missatge"
+#: sequencer.c
#, c-format
msgid "could not delete '%s'"
msgstr "no s'ha pogut suprimir «%s»"
+#: sequencer.c
msgid "revert"
msgstr "revertir"
+#: sequencer.c
msgid "cherry-pick"
msgstr "cherry-pick"
+#: sequencer.c
msgid "rebase"
msgstr "rebase"
+#: sequencer.c
#, c-format
msgid "unknown action: %d"
msgstr "acció desconeguda: %d"
+#: sequencer.c
+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 ""
+"Resoleu tots els conflictes manualment, marqueu-los com a resolts amb\n"
+"«git add/rm <fitxers_amb_conflicte>», llavors executeu «git rebase --"
+"continue».\n"
+"Alternativament podeu ometre aquesta comissió: executeu «git rebase --"
+"skip».\n"
+"Per a avortar i tornar a l'estat anterior abans de l'ordre «git rebase», "
+"executeu «git rebase --abort»."
+
+#: sequencer.c
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
@@ -20048,6 +26170,7 @@ msgstr ""
"després de resoldre els conflictes, marqueu els camins\n"
"corregits amb «git add <camins>» o «git rm <camins>»"
+#: sequencer.c
msgid ""
"After resolving the conflicts, mark them with\n"
"\"git add/rm <pathspec>\", then run\n"
@@ -20063,6 +26186,7 @@ msgstr ""
"Per a interrompre i tornar a l'estat anterior abans de «git cherry-pick»,\n"
"executeu «git cherry-pick --abort»."
+#: sequencer.c
msgid ""
"After resolving the conflicts, mark them with\n"
"\"git add/rm <pathspec>\", then run\n"
@@ -20078,68 +26202,86 @@ msgstr ""
"Per a interrompre i tornar a l'estat anterior abans de «git revert»,\n"
"executeu «git revert --abort»."
+#: sequencer.c
#, c-format
msgid "could not lock '%s'"
msgstr "no s'ha pogut bloquejar «%s»"
+#: sequencer.c
#, c-format
msgid "could not write eol to '%s'"
msgstr "no s'ha pogut escriure el terminador de línia a «%s»"
+#: sequencer.c
#, c-format
msgid "failed to finalize '%s'"
msgstr "s'ha produït un error en finalitzar «%s»"
+#: sequencer.c
#, c-format
msgid "your local changes would be overwritten by %s."
msgstr "els vostres canvis locals se sobreescriurien per %s."
+#: sequencer.c
msgid "commit your changes or stash them to proceed."
msgstr "cometeu els vostres canvis o feu un «stash» per a procedir."
#. TRANSLATORS: %s will be "revert", "cherry-pick" or
#. "rebase".
#.
+#: sequencer.c
#, c-format
msgid "%s: Unable to write new index file"
msgstr "%s: No s'ha pogut escriure un fitxer d'índex nou"
+#: sequencer.c
msgid "unable to update cache tree"
msgstr "no s'ha pogut actualitzar l'arbre cau"
+#: sequencer.c
msgid "could not resolve HEAD commit"
msgstr "no s'ha pogut resoldre la comissió HEAD"
+#: sequencer.c
#, c-format
msgid "no key present in '%.*s'"
msgstr "no hi ha una clau a «%.*s»"
+#: sequencer.c
#, c-format
msgid "unable to dequote value of '%s'"
msgstr "no s'han pogut treure les cometes del valor de «%s»"
+#: sequencer.c
msgid "'GIT_AUTHOR_NAME' already given"
msgstr "Ja s'ha donat «GIT_AUTHOR_NAME»"
+#: sequencer.c
msgid "'GIT_AUTHOR_EMAIL' already given"
msgstr "Ja s'ha donat «GIT_AUTHOR_EMAIL»"
+#: sequencer.c
msgid "'GIT_AUTHOR_DATE' already given"
msgstr "Ja s'ha donat «GIT_AUTHOR_DATE»"
+#: sequencer.c
#, c-format
msgid "unknown variable '%s'"
msgstr "variable «%s» desconeguda"
+#: sequencer.c
msgid "missing 'GIT_AUTHOR_NAME'"
msgstr "falta «GIT_AUTHOR_NAME»"
+#: sequencer.c
msgid "missing 'GIT_AUTHOR_EMAIL'"
msgstr "falta «GIT_AUTHOR_EMAIL»"
+#: sequencer.c
msgid "missing 'GIT_AUTHOR_DATE'"
msgstr "falta «GIT_AUTHOR_DATE»"
+#: sequencer.c
#, c-format
msgid ""
"you have staged changes in your working tree\n"
@@ -20169,9 +26311,11 @@ msgstr ""
"\n"
" git rebase --continue\n"
+#: sequencer.c
msgid "'prepare-commit-msg' hook failed"
msgstr "el lligam «prepare-commit-msg» ha fallat"
+#: sequencer.c
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -20198,6 +26342,7 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
+#: sequencer.c
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -20223,263 +26368,369 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
+#: sequencer.c
msgid "couldn't look up newly created commit"
msgstr "no s'ha pogut trobar la comissió novament creada"
+#: sequencer.c
msgid "could not parse newly created commit"
msgstr "no s'ha pogut analitzar la comissió novament creada"
+#: sequencer.c
msgid "unable to resolve HEAD after creating commit"
msgstr "no s'ha pogut resoldre HEAD després de crear la comissió"
+#: sequencer.c
msgid "detached HEAD"
msgstr "HEAD separat"
+#: sequencer.c
msgid " (root-commit)"
msgstr " (comissió arrel)"
+#: sequencer.c
msgid "could not parse HEAD"
msgstr "no s'ha pogut analitzar HEAD"
+#: sequencer.c
#, c-format
msgid "HEAD %s is not a commit!"
msgstr "HEAD %s no és una comissió!"
+#: sequencer.c
msgid "unable to parse commit author"
msgstr "no s'ha pogut analitzar l'autor de la comissió"
+#: sequencer.c
#, c-format
msgid "unable to read commit message from '%s'"
msgstr "no s'ha pogut llegir el missatge de comissió des de «%s»"
+#: sequencer.c
#, c-format
msgid "invalid author identity '%s'"
msgstr "identitat d'autor no vàlida: «%s»"
+#: sequencer.c
msgid "corrupt author: missing date information"
msgstr "autor malmès: falta la informació de la data"
+#: sequencer.c
#, c-format
msgid "could not update %s"
msgstr "no s'ha pogut actualitzar %s"
-#, c-format
-msgid "could not parse commit %s"
-msgstr "no s'ha pogut analitzar la comissió %s"
-
+#: sequencer.c
#, c-format
msgid "could not parse parent commit %s"
msgstr "no s'ha pogut analitzar la comissió pare %s"
+#: sequencer.c
#, c-format
msgid "unknown command: %d"
msgstr "ordre desconeguda: %d"
+#: sequencer.c
msgid "This is the 1st commit message:"
msgstr "Aquest és el missatge de la 1a comissió:"
+#: sequencer.c
#, c-format
msgid "This is the commit message #%d:"
msgstr "Aquest és el missatge de la #%d comissió:"
+#: sequencer.c
msgid "The 1st commit message will be skipped:"
msgstr "El missatge de la primera comissió s'ometrà:"
+#: sequencer.c
#, c-format
msgid "The commit message #%d will be skipped:"
msgstr "El missatge de la comissió núm. #%d s'ometrà:"
+#: sequencer.c
#, c-format
msgid "This is a combination of %d commits."
msgstr "Això és una combinació de %d comissions."
+#: sequencer.c
#, c-format
msgid "cannot write '%s'"
msgstr "no es pot escriure «%s»"
+#: sequencer.c
msgid "need a HEAD to fixup"
msgstr "cal un HEAD per a reparar-ho"
+#: sequencer.c
msgid "could not read HEAD"
msgstr "no s'ha pogut llegir HEAD"
+#: sequencer.c
msgid "could not read HEAD's commit message"
msgstr "no s'ha pogut llegir el missatge de comissió de HEAD"
+#: sequencer.c
#, c-format
msgid "could not read commit message of %s"
msgstr "no s'ha pogut llegir el missatge de comissió: %s"
+#: sequencer.c
msgid "your index file is unmerged."
msgstr "el vostre fitxer d'índex està sense fusionar."
+#: sequencer.c
msgid "cannot fixup root commit"
msgstr "no es pot arreglar la comissió arrel"
+#: sequencer.c
#, c-format
msgid "commit %s is a merge but no -m option was given."
msgstr "la comissió %s és una fusió però no s'ha donat cap opció -m."
+#: sequencer.c
#, c-format
msgid "commit %s does not have parent %d"
msgstr "la comissió %s no té pare %d"
+#: sequencer.c
#, c-format
msgid "cannot get commit message for %s"
msgstr "no es pot obtenir el missatge de comissió de %s"
#. TRANSLATORS: The first %s will be a "todo" command like
#. "revert" or "pick", the second %s a SHA1.
+#: sequencer.c
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s: no es pot analitzar la comissió pare %s"
-#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "no s'ha pogut canviar el nom «%s» a «%s»"
-
+#: sequencer.c
#, c-format
msgid "could not revert %s... %s"
msgstr "no s'ha pogut revertir %s... %s"
+#: sequencer.c
#, c-format
msgid "could not apply %s... %s"
msgstr "no s'ha pogut aplicar %s... %s"
+#: sequencer.c
#, c-format
msgid "dropping %s %s -- patch contents already upstream\n"
msgstr "descartant %s %s -- el contingut del pedaç ja està a la font\n"
+#: sequencer.c
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s: s'ha produït un error en llegir l'índex"
+#: sequencer.c
#, c-format
msgid "git %s: failed to refresh the index"
msgstr "git %s: s'ha produït un error en actualitzar l'índex"
+#: sequencer.c
#, c-format
msgid "'%s' is not a valid label"
msgstr "«%s» no és una etiqueta vàlida"
+#: sequencer.c
#, c-format
msgid "'%s' is not a valid refname"
msgstr "«%s» no és un nom de referència vàlid"
+#: sequencer.c
#, c-format
msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
msgstr ""
"«update-ref» requereix un refname plenament qualificat, p. ex. refs/heads/%s"
+#: sequencer.c
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "ordre no vàlida «%.*s»"
+msgid "'%s' does not accept merge commits"
+msgstr "%s no accepta comissions de fusió"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"«pick» no accepta una comissió de fusió. Si volíeu\n"
+"reproduir la fusió, utilitzeu «merge -C» en la comissió."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"«reword» no accepta una comissió de fusió. Si volíeu\n"
+"reproduir la fusió i fer «reword» del missatge de comissió,\n"
+"utilitzeu «merge -c» en la comissió"
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+#: sequencer.c
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"«edit» no accepta una comissió de fusió. Si volíeu\n"
+"reproduir la fusió, utilitzeu «merge -C» en la comissió\n"
+" i després «break» per a recuperar el control perquè pugueu\n"
+"feu «git commit --amend && git rebase --continue»."
+
+#: sequencer.c
+msgid "cannot squash merge commit into another commit"
+msgstr "no es pot fer «squash» d'una comissió de fusió en una altra comissió"
+
+#: sequencer.c
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s no accepta arguments: «%s»"
+msgid "invalid command '%.*s'"
+msgstr "ordre no vàlida «%.*s»"
+#: sequencer.c
#, c-format
msgid "missing arguments for %s"
msgstr "falten els arguments per a %s"
+#: sequencer.c
#, c-format
msgid "could not parse '%s'"
msgstr "no s'ha pogut analitzar «%s»"
+#: sequencer.c
#, c-format
msgid "invalid line %d: %.*s"
msgstr "línia no vàlida %d: %.*s"
+#: sequencer.c
#, c-format
msgid "cannot '%s' without a previous commit"
msgstr "no es pot «%s» sense una comissió prèvia"
+#: sequencer.c
msgid "cancelling a cherry picking in progress"
msgstr "s'està cancel·lant un «cherry pick» en curs"
+#: sequencer.c
msgid "cancelling a revert in progress"
msgstr "s'està cancel·lant la reversió en curs"
+#: sequencer.c
msgid "please fix this using 'git rebase --edit-todo'."
msgstr "corregiu-ho usant «git rebase --edit-todo»."
+#: sequencer.c
#, c-format
msgid "unusable instruction sheet: '%s'"
msgstr "full d'instruccions inusable: «%s»"
+#: sequencer.c
msgid "no commits parsed."
msgstr "no s'ha analitzat cap comissió."
+#: sequencer.c
msgid "cannot cherry-pick during a revert."
msgstr "no es pot fer «cherry pick» durant una reversió."
+#: sequencer.c
msgid "cannot revert during a cherry-pick."
msgstr "no es pot revertir durant un «cherry pick»."
+#: sequencer.c
msgid "unusable squash-onto"
msgstr "«squash-onto» no usable"
+#: sequencer.c
#, c-format
msgid "malformed options sheet: '%s'"
msgstr "full d'opcions mal format: «%s»"
+#: sequencer.c
msgid "empty commit set passed"
msgstr "conjunt de comissions buit passat"
+#: sequencer.c
msgid "revert is already in progress"
msgstr "una reversió ja està en curs"
+#: sequencer.c
#, c-format
msgid "try \"git revert (--continue | %s--abort | --quit)\""
msgstr "intenteu «git revert (--continue | %s--abort | --quit)»"
+#: sequencer.c
msgid "cherry-pick is already in progress"
msgstr "un «cherry pick» ja està en curs"
+#: sequencer.c
#, c-format
msgid "try \"git cherry-pick (--continue | %s--abort | --quit)\""
msgstr "intenteu «git cherry-pick (--continue | %s--abort | --quit)»"
+#: sequencer.c
#, c-format
msgid "could not create sequencer directory '%s'"
msgstr "no s'ha pogut crear el directori de seqüenciador «%s»"
+#: sequencer.c
msgid "no cherry-pick or revert in progress"
msgstr "ni hi ha cap «cherry pick» ni cap reversió en curs"
+#: sequencer.c
msgid "cannot resolve HEAD"
msgstr "no es pot resoldre HEAD"
+#: sequencer.c
msgid "cannot abort from a branch yet to be born"
msgstr "no es pot avortar des d'una branca que encara ha de nàixer"
+#: sequencer.c
#, c-format
msgid "cannot read '%s': %s"
msgstr "no es pot llegir «%s»: %s"
+#: sequencer.c
msgid "unexpected end of file"
msgstr "final de fitxer inesperat"
+#: sequencer.c
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
msgstr "el fitxer HEAD emmagatzemat abans de fer «cherry pick» «%s» és malmès"
+#: sequencer.c
msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
-msgstr "Sembla que heu mogut HEAD sense rebobinar, comproveu-ho HEAD"
+msgstr "Sembla que heu mogut HEAD. No es fa el rebobinat, comproveu-ho HEAD"
+#: sequencer.c
msgid "no revert in progress"
msgstr "no hi ha cap reversió en curs"
+#: sequencer.c
msgid "no cherry-pick in progress"
msgstr "ni hi ha cap «cherry pick» en curs"
+#: sequencer.c
msgid "failed to skip the commit"
msgstr "s'ha produït un error en ometre la comissió"
+#: sequencer.c
msgid "there is nothing to skip"
msgstr "no hi ha res a ometre"
+#: sequencer.c
#, c-format
msgid ""
"have you committed already?\n"
@@ -20488,13 +26739,15 @@ msgstr ""
"heu fet ja una comissió?\n"
"proveu «git %s --continue»"
+#: sequencer.c
msgid "cannot read HEAD"
msgstr "no es pot llegir HEAD"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "no s'ha pogut copiar «%s» a «%s»"
+#: sequencer.c
+msgid "could not write commit message file"
+msgstr "no s'ha pogut escriure el fitxer de missatge de comissió"
+#: sequencer.c
#, c-format
msgid ""
"You can amend the commit now, with\n"
@@ -20513,18 +26766,22 @@ msgstr ""
"\n"
" git rebase --continue\n"
+#: sequencer.c
#, c-format
msgid "Could not apply %s... %.*s"
msgstr "No s'ha pogut aplicar %s... %.*s"
+#: sequencer.c
#, c-format
msgid "Could not merge %.*s"
msgstr "No s'ha pogut fusionar %.*s"
+#: sequencer.c
#, c-format
msgid "Executing: %s\n"
msgstr "S'està executant: %s\n"
+#: sequencer.c
#, c-format
msgid ""
"execution failed: %s\n"
@@ -20539,9 +26796,11 @@ msgstr ""
" git rebase --continue\n"
"\n"
+#: sequencer.c
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"
+#: sequencer.c
#, c-format
msgid ""
"execution succeeded: %s\n"
@@ -20558,52 +26817,65 @@ msgstr ""
" git rebase --continue\n"
"\n"
+#: sequencer.c
#, c-format
msgid "illegal label name: '%.*s'"
msgstr "nom d'etiqueta no permès: «%.*s»"
+#: sequencer.c
#, c-format
msgid "could not resolve '%s'"
msgstr "no s'ha pogut resoldre «%s»"
+#: sequencer.c
msgid "writing fake root commit"
msgstr "s'està escrivint una comissió arrel falsa"
+#: sequencer.c
msgid "writing squash-onto"
msgstr "s'està escrivint «squash-onto»"
+#: sequencer.c
msgid "cannot merge without a current revision"
msgstr "no es pot fusionar sense una revisió actual"
+#: sequencer.c
#, c-format
msgid "unable to parse '%.*s'"
msgstr "no s'ha pogut analitzar «%.*s»"
+#: sequencer.c
#, c-format
msgid "nothing to merge: '%.*s'"
msgstr "no hi ha res per a fusionar «%.*s»"
+#: sequencer.c
msgid "octopus merge cannot be executed on top of a [new root]"
msgstr ""
"no es pot executar la fusió «octopus» a la part superior d'una [arrel nova]"
+#: sequencer.c
#, c-format
msgid "could not get commit message of '%s'"
msgstr "no s'ha pogut llegir el missatge de comissió de «%s»"
+#: sequencer.c
#, c-format
msgid "could not even attempt to merge '%.*s'"
msgstr "no s'ha pogut fusionar «%.*s»"
+#: sequencer.c
msgid "merge: Unable to write new index file"
msgstr "fusió: no s'ha pogut escriure un fitxer d'índex nou"
+#: sequencer.c
#, c-format
msgid ""
"another 'rebase' process appears to be running; '%s.lock' already exists"
msgstr ""
"sembla que s'està executant un altre procés «rebase»: «%s.lock» ja existeix"
+#: sequencer.c
#, c-format
msgid ""
"Updated the following refs with %s:\n"
@@ -20612,6 +26884,7 @@ msgstr ""
"S'han actualitzat els següents refs amb %s:\n"
"%s"
+#: sequencer.c
#, c-format
msgid ""
"Failed to update the following refs with %s:\n"
@@ -20620,32 +26893,40 @@ msgstr ""
"No s'han pogut actualitzar les referències següents amb %s:\n"
"%s"
+#: sequencer.c
msgid "Cannot autostash"
msgstr "No es pot fer un «stash» automàticament"
+#: sequencer.c
#, c-format
msgid "Unexpected stash response: '%s'"
msgstr "Resposta de «stash» inesperada: «%s»"
+#: sequencer.c
#, c-format
msgid "Could not create directory for '%s'"
msgstr "No s'ha pogut crear el directori per a «%s»"
+#: sequencer.c
#, c-format
msgid "Created autostash: %s\n"
msgstr "S'ha creat un «stash» automàticament: %s\n"
+#: sequencer.c
msgid "could not reset --hard"
msgstr "no s'ha pogut fer reset --hard"
+#: sequencer.c
#, c-format
msgid "Applied autostash.\n"
msgstr "S'ha aplicat el «stash» automàticament.\n"
+#: sequencer.c
#, c-format
msgid "cannot store %s"
msgstr "no es pot emmagatzemar %s"
+#: sequencer.c
#, c-format
msgid ""
"%s\n"
@@ -20656,24 +26937,34 @@ msgstr ""
"Els vostres canvis estan segurs en el «stash».\n"
"Podeu executar «git stash pop» o «git stash drop» en qualsevol moment.\n"
+#: sequencer.c
msgid "Applying autostash resulted in conflicts."
msgstr "L'aplicació del «stash» automàticament ha donat conflictes."
+#: sequencer.c
msgid "Autostash exists; creating a new stash entry."
msgstr ""
"El «stash» automàtic ja existeix; s'està creant una entrada «stash» nova."
+#: sequencer.c
+msgid "autostash reference is a symref"
+msgstr "la referència d'autostash és un symref"
+
+#: sequencer.c
msgid "could not detach HEAD"
msgstr "no s'ha pogut separar HEAD"
+#: sequencer.c
#, c-format
msgid "Stopped at HEAD\n"
msgstr "Aturat a HEAD\n"
+#: sequencer.c
#, c-format
msgid "Stopped at %s\n"
msgstr "Aturat a %s\n"
+#: sequencer.c
#, c-format
msgid ""
"Could not execute the todo command\n"
@@ -20694,46 +26985,58 @@ msgstr ""
" git rebase --edit-todo\n"
" git rebase --continue\n"
-#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "S'està fent «rebase» (%d/%d)%s"
-
+#: sequencer.c
#, c-format
msgid "Stopped at %s... %.*s\n"
msgstr "Aturat a %s... %.*s\n"
+#: sequencer.c
+#, c-format
+msgid "Rebasing (%d/%d)%s"
+msgstr "S'està fent «rebase» (%d/%d)%s"
+
+#: sequencer.c
#, c-format
msgid "unknown command %d"
msgstr "ordre %d desconeguda"
+#: sequencer.c
msgid "could not read orig-head"
msgstr "no s'ha pogut llegir orig-head"
+#: sequencer.c
msgid "could not read 'onto'"
msgstr "no s'ha pogut llegir «onto»"
+#: sequencer.c
#, c-format
msgid "could not update HEAD to %s"
msgstr "no s'ha pogut actualitzar HEAD a %s"
+#: sequencer.c
#, c-format
msgid "Successfully rebased and updated %s.\n"
msgstr "S'ha fet «rebase» i actualitzat %s amb èxit.\n"
+#: sequencer.c
msgid "cannot rebase: You have unstaged changes."
msgstr "no es pot fer «rebase»: teniu canvis «unstaged»."
+#: sequencer.c
msgid "cannot amend non-existing commit"
msgstr "no es pot esmenar una comissió no existent"
+#: sequencer.c
#, c-format
msgid "invalid file: '%s'"
msgstr "fitxer no vàlid: «%s»"
+#: sequencer.c
#, c-format
msgid "invalid contents: '%s'"
msgstr "contingut no vàlid: «%s»"
+#: sequencer.c
msgid ""
"\n"
"You have uncommitted changes in your working tree. Please, commit them\n"
@@ -20743,57 +27046,73 @@ msgstr ""
"Teniu canvis no comesos en el vostre arbre de treball. \n"
"Cometeu-los primer i després executeu «git rebase --continue» de nou."
+#: sequencer.c
#, c-format
msgid "could not write file: '%s'"
msgstr "no s'ha pogut escriure el fitxer: «%s»"
+#: sequencer.c
msgid "could not remove CHERRY_PICK_HEAD"
msgstr "no s'ha pogut eliminar CHERRY_PICK_HEAD"
+#: sequencer.c
msgid "could not commit staged changes."
msgstr "no s'han pogut cometre els canvis «staged»."
+#: sequencer.c
#, c-format
msgid "%s: can't cherry-pick a %s"
msgstr "%s: no es pot fer «cherry pick» a %s"
+#: sequencer.c
#, c-format
msgid "%s: bad revision"
msgstr "%s: revisió incorrecta"
+#: sequencer.c
msgid "can't revert as initial commit"
msgstr "no es pot revertir com a comissió inicial"
+#: sequencer.c
#, c-format
msgid "skipped previously applied commit %s"
msgstr "omet les comissions aplicades anteriorment %s"
+#: sequencer.c
msgid "use --reapply-cherry-picks to include skipped commits"
msgstr "useu --reapply-cherry-picks per a incloure les comissions omeses"
+#: sequencer.c
msgid "make_script: unhandled options"
msgstr "make_script: opcions no gestionades"
+#: sequencer.c
msgid "make_script: error preparing revisions"
msgstr "make_script: s'ha produït un error en preparar les revisions"
+#: sequencer.c
msgid "nothing to do"
msgstr "res a fer"
+#: sequencer.c
msgid "could not skip unnecessary pick commands"
msgstr "no s'han pogut ometre les ordres «picks» no necessàries"
+#: sequencer.c
msgid "the script was already rearranged."
msgstr "l'script ja estava endreçat."
+#: sequencer.c
#, c-format
msgid "update-refs file at '%s' is invalid"
msgstr "el fitxer update-refs a «%s» no és vàlid"
+#: setup.c
#, c-format
msgid "'%s' is outside repository at '%s'"
msgstr "«%s» està fora del repositori a «%s»"
+#: setup.c
#, c-format
msgid ""
"%s: no such path in the working tree.\n"
@@ -20803,6 +27122,7 @@ msgstr ""
"Useu «git <ordre> -- <camí>...» per a especificar camins que no existeixin "
"localment."
+#: setup.c
#, c-format
msgid ""
"ambiguous argument '%s': unknown revision or path not in the working tree.\n"
@@ -20814,10 +27134,12 @@ msgstr ""
"Useu «--» per a separar els camins de les revisions:\n"
"«git <ordre> [<revisió>...] -- [<fitxer>...]»"
+#: setup.c
#, c-format
msgid "option '%s' must come before non-option arguments"
msgstr "l'opció «%s» ha d'aparèixer abans que els arguments opcionals"
+#: setup.c
#, c-format
msgid ""
"ambiguous argument '%s': both revision and filename\n"
@@ -20828,104 +27150,137 @@ msgstr ""
"Useu «--» per a separar els camins de les revisions:\n"
"«git <ordre> [<revisió>...] -- [<fitxer>...]»"
+#: setup.c
msgid "unable to set up work tree using invalid config"
msgstr ""
"no s'ha pogut configurar un arbre de treball utilitzant una configuració no "
"vàlida"
+#: setup.c
+#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "«%s» ja especificat com a «%s»"
+
+#: setup.c
#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "S'esperava una versió de repositori de git <= %d, s'ha trobat %d"
+#: setup.c
msgid "unknown repository extension found:"
msgid_plural "unknown repository extensions found:"
msgstr[0] "s'ha trobat una extensió de repositori desconeguda:"
msgstr[1] "s'han trobat extensions de repositori desconegudes:"
+#: setup.c
msgid "repo version is 0, but v1-only extension found:"
msgid_plural "repo version is 0, but v1-only extensions found:"
msgstr[0] "el repositori és versió 0, però només s'han trobat una extensió v1:"
msgstr[1] "el repositori és versió 0, però només s'han trobat extensions v1:"
+#: setup.c
#, c-format
msgid "error opening '%s'"
msgstr "s'ha produït un error en obrir «%s»"
+#: setup.c
#, c-format
msgid "too large to be a .git file: '%s'"
msgstr "massa gran per a ser un fitxer .git: «%s»"
+#: setup.c
#, c-format
msgid "error reading %s"
msgstr "error en llegir %s"
+#: setup.c
#, c-format
msgid "invalid gitfile format: %s"
msgstr "format gitfile no vàlid: %s"
+#: setup.c
#, c-format
msgid "no path in gitfile: %s"
msgstr "sense camí al gitfile: %s"
+#: setup.c
#, c-format
msgid "not a git repository: %s"
msgstr "no és un repositori de git: %s"
+#: setup.c
#, c-format
msgid "'$%s' too big"
msgstr "«$%s» massa gran"
+#: setup.c
#, c-format
msgid "not a git repository: '%s'"
msgstr "no és un repositori de git: «%s»"
+#: setup.c
#, c-format
msgid "cannot chdir to '%s'"
msgstr "no es pot canviar de directori a «%s»"
+#: setup.c
msgid "cannot come back to cwd"
msgstr "no es pot tornar al directori de treball actual"
+#: setup.c
#, c-format
msgid "failed to stat '%*s%s%s'"
msgstr "s'ha produït un error en fer stat a «%*s%s%s»"
+#: setup.c
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "el safe.directory «%s» no és absolut"
+
+#: 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'ha detectat una propietat dubtosa al repositori a «%s»\n"
+"%sPer a afegir una excepció per a aquest directori, executeu:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
+#: setup.c
msgid "Unable to read current working directory"
msgstr "No s'ha pogut llegir el directori de treball actual"
+#: setup.c
#, c-format
msgid "cannot change to '%s'"
msgstr "no es pot canviar a «%s»"
+#: setup.c
#, c-format
msgid "not a git repository (or any of the parent directories): %s"
msgstr "no és un repositori de git (ni cap dels directoris pares): %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 ""
-"no és un repositori de git (ni cap pare fins al punt de muntatge %s)\n"
+"no és un repositori de git (ni existeix cap pare fins al punt de muntatge "
+"%s)\n"
"S'atura a la frontera de sistema de fitxers (GIT_DISCOVERY_ACROSS_FILESYSTEM "
"no està establert)."
-#, 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'ha detectat una propietat dubtosa al repositori a «%s»\n"
-"%sPer a afegir una excepció per a aquest directori, executeu:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-
+#: setup.c
#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
msgstr "no es pot utilitzar el dipòsit nu «%s» (safe.bareRepository és «%s»)"
+#: setup.c
#, c-format
msgid ""
"problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -20936,179 +27291,246 @@ msgstr ""
"El propietari dels fitxers sempre ha de tenir permisos de lectura i "
"escriptura."
+#: setup.c
msgid "fork failed"
msgstr "el «fork» ha fallat"
+#: setup.c
msgid "setsid failed"
msgstr "«setsid» ha fallat"
+#: setup.c
#, c-format
msgid "cannot stat template '%s'"
msgstr "no es pot fer stat en la plantilla «%s»"
+#: setup.c
#, c-format
msgid "cannot opendir '%s'"
msgstr "no es pot fer opendir en el directori «%s»"
+#: setup.c
#, c-format
msgid "cannot readlink '%s'"
msgstr "no es pot fer readlink en «%s»"
+#: setup.c
#, c-format
msgid "cannot symlink '%s' '%s'"
msgstr "no es pot fer symlink en «%s» «%s»"
+#: setup.c
#, c-format
msgid "cannot copy '%s' to '%s'"
msgstr "no es pot copiar «%s» a «%s»"
+#: setup.c
#, c-format
msgid "ignoring template %s"
msgstr "s'està ignorant la plantilla %s"
+#: setup.c
#, c-format
msgid "templates not found in %s"
msgstr "plantilles no trobades a %s"
+#: setup.c
#, c-format
msgid "not copying templates from '%s': %s"
msgstr "no s'estan copiant plantilles de «%s»: %s"
+#: setup.c
#, c-format
msgid "invalid initial branch name: '%s'"
msgstr "nom de branca inicial no vàlid: «%s»"
+#: setup.c
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "reinicialització: s'ha ignorat --initial-branch=%s"
+
+#: setup.c
#, c-format
msgid "unable to handle file type %d"
msgstr "no s'ha pogut gestionar el tipus de fitxer %d"
+#: setup.c
#, c-format
msgid "unable to move %s to %s"
msgstr "no s'ha pogut moure %s a %s"
+#: setup.c
msgid "attempt to reinitialize repository with different hash"
msgstr "s'ha intentat reinicialitzar el repositori amb un resum diferent"
+#: setup.c
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr ""
+"s'ha intentat reactivar el repositori amb un format d'emmagatzematge de "
+"referència diferent"
+
+#: setup.c
#, 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"
-
+#: setup.c
#, 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"
+#: setup.c
#, c-format
msgid "Reinitialized existing Git repository in %s%s\n"
msgstr "S'ha reinicialitzat el repositori existent del Git en %s%s\n"
+#: setup.c
#, 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"
+#: setup.c
#, c-format
msgid "Initialized empty Git repository in %s%s\n"
msgstr "S'ha inicialitzat un repositori buit del Git en %s%s\n"
+#: sparse-index.c
#, c-format
msgid "index entry is a directory, but not sparse (%08x)"
msgstr "l'entrada d'índex és un directori, però no dispers (%08x)"
+#: split-index.c
msgid "cannot use split index with a sparse index"
msgstr "no es pot utilitzar l'índex partit amb un índex dispers"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "format %s incorrecte: l'element «%s» no comença amb «(»"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "format %s incorrecte: l'element «%s» no acaba en «)»"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "format %s incorrecte: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
+#: strbuf.c
#, c-format
msgid "%u.%2.2u GiB"
msgstr "%u.%2.2u GiB"
#. TRANSLATORS: IEC 80000-13:2008 gibibyte/second
+#: strbuf.c
#, c-format
msgid "%u.%2.2u GiB/s"
msgstr "%u.%2.2u GiB/s"
#. TRANSLATORS: IEC 80000-13:2008 mebibyte
+#: strbuf.c
#, c-format
msgid "%u.%2.2u MiB"
msgstr "%u.%2.2u MiB"
#. TRANSLATORS: IEC 80000-13:2008 mebibyte/second
+#: strbuf.c
#, c-format
msgid "%u.%2.2u MiB/s"
msgstr "%u.%2.2u MiB/s"
#. TRANSLATORS: IEC 80000-13:2008 kibibyte
+#: strbuf.c
#, c-format
msgid "%u.%2.2u KiB"
msgstr "%u.%2.2u KiB"
#. TRANSLATORS: IEC 80000-13:2008 kibibyte/second
+#: strbuf.c
#, c-format
msgid "%u.%2.2u KiB/s"
msgstr "%u.%2.2u KiB/s"
#. TRANSLATORS: IEC 80000-13:2008 byte
+#: strbuf.c
#, c-format
msgid "%u byte"
msgid_plural "%u bytes"
-msgstr[0] "%u byte"
-msgstr[1] "%u bytes"
+msgstr[0] "%u octet"
+msgstr[1] "%u octets"
#. TRANSLATORS: IEC 80000-13:2008 byte/second
+#: strbuf.c
#, c-format
msgid "%u byte/s"
msgid_plural "%u bytes/s"
-msgstr[0] "%u byte/s"
-msgstr[1] "%u bytes/s"
+msgstr[0] "%u octet/s"
+msgstr[1] "%u octets/s"
+#: submodule-config.c
#, c-format
msgid "ignoring suspicious submodule name: %s"
msgstr "s'està ignorant el nom de submòdul sospitós %s"
+#: submodule-config.c
msgid "negative values not allowed for submodule.fetchJobs"
msgstr "no es permeten els valors negatius a submodule.fetchJobs"
+#: submodule-config.c
#, c-format
msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
msgstr ""
"s'està ignorant «%s» que pot interpretar-se com a una opció de línia "
"d'ordres: %s"
+#: submodule-config.c
#, c-format
msgid "Could not update .gitmodules entry %s"
msgstr "No s'ha pogut actualitzar l'entrada de .gitmodules %s"
+#: submodule.c
msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
msgstr ""
"No es pot canviar un .gitmodules no fusionat, primer resoleu els conflictes "
"de fusió"
+#: submodule.c
#, c-format
msgid "Could not find section in .gitmodules where path=%s"
msgstr "No s'ha pogut trobar la secció en .gitmodules on path=%s"
+#: submodule.c
#, c-format
msgid "Could not remove .gitmodules entry for %s"
msgstr "No s'ha pogut eliminar l'entrada de .gitmodules per a %s"
+#: submodule.c
msgid "staging updated .gitmodules failed"
msgstr "l'allistament del .gitmodules actualitzat ha fallat"
+#: submodule.c
#, c-format
msgid "in unpopulated submodule '%s'"
msgstr "al submòdul sense popular «%s»"
+#: submodule.c
#, c-format
msgid "Pathspec '%s' is in submodule '%.*s'"
msgstr "L'especificació «%s» és en el submòdul «%.*s»"
+#: submodule.c
#, c-format
msgid "bad --ignore-submodules argument: %s"
msgstr "argument incorrecte --ignore-submodules: %s"
+#: submodule.c
#, c-format
msgid ""
"Submodule in commit %s at path: '%s' collides with a submodule named the "
@@ -21117,10 +27539,12 @@ msgstr ""
"El submòdul en la comissió %s al camí: «%s» col·lideix amb un submòdul amb "
"el mateix nom. Ometent-lo."
+#: submodule.c
#, c-format
msgid "submodule entry '%s' (%s) is a %s, not a commit"
msgstr "l'entrada del submòdul «%s» (%s) és a %s, no és una comissió"
+#: submodule.c
#, c-format
msgid ""
"Could not run 'git rev-list <commits> --not --remotes -n 1' command in "
@@ -21129,34 +27553,42 @@ msgstr ""
"No s'ha pogut executar l'ordre «git rev-list <commits> --not --remotes -n 1» "
"en el submòdul %s"
+#: submodule.c
#, c-format
msgid "process for submodule '%s' failed"
msgstr "ha fallat el procés per al submòdul «%s»"
+#: submodule.c
#, c-format
msgid "Pushing submodule '%s'\n"
msgstr "S'està pujant el submòdul «%s»\n"
+#: submodule.c
#, c-format
msgid "Unable to push submodule '%s'\n"
msgstr "No s'ha pogut pujar el submòdul «%s»\n"
+#: submodule.c
#, c-format
msgid "Fetching submodule %s%s\n"
msgstr "S'està obtenint el submòdul %s%s\n"
+#: submodule.c
#, c-format
msgid "Could not access submodule '%s'\n"
msgstr "No s'ha pogut accedir al submòdul «%s»\n"
+#: submodule.c
#, c-format
msgid "Could not access submodule '%s' at commit %s\n"
msgstr "No s'ha pogut accedir al submòdul «%s» en la comissió %s\n"
+#: submodule.c
#, c-format
msgid "Fetching submodule %s%s at commit %s\n"
msgstr "S'està obtenint el submòdul %s%s en la comissió %s\n"
+#: submodule.c
#, c-format
msgid ""
"Errors during submodule fetch:\n"
@@ -21165,51 +27597,74 @@ msgstr ""
"Errors durant l'obtenció de submòduls:\n"
"%s"
+#: submodule.c
#, c-format
msgid "'%s' not recognized as a git repository"
msgstr "«%s» no reconegut com un repositori git"
+#: submodule.c
#, c-format
msgid "Could not run 'git status --porcelain=2' in submodule %s"
msgstr "No s'ha pogut executar «git status --porcelain=2» en el submòdul %s"
+#: submodule.c
#, c-format
msgid "'git status --porcelain=2' failed in submodule %s"
msgstr "«git status --porcelain=2» ha fallat en el submòdul %s"
+#: submodule.c
#, c-format
msgid "could not start 'git status' in submodule '%s'"
msgstr "no s'ha pogut iniciar «git status» al submòdul «%s»"
+#: submodule.c
#, c-format
msgid "could not run 'git status' in submodule '%s'"
msgstr "no s'ha pogut executar «git status» al submòdul «%s»"
+#: submodule.c
#, c-format
msgid "Could not unset core.worktree setting in submodule '%s'"
msgstr ""
"No s'ha pogut desassignar el paràmetre «core.worktree» al submòdul «%s»"
+#: submodule.c
#, c-format
msgid "could not recurse into submodule '%s'"
msgstr ""
"s'ha produït un error en cercar recursivament al camí del submòdul «%s»"
+#: submodule.c
msgid "could not reset submodule index"
msgstr "no s'ha pogut restablir l'índex del submòdul"
+#: submodule.c
#, c-format
msgid "submodule '%s' has dirty index"
msgstr "el submòdul «%s» té l'índex brut"
+#: submodule.c
#, c-format
msgid "Submodule '%s' could not be updated."
msgstr "No s'ha pogut actualitzar el submòdul «%s»."
+#: submodule.c
#, c-format
msgid "submodule git dir '%s' is inside git dir '%.*s'"
msgstr "submodule git dir «%s» està dins git dir «%.*s»"
+#: submodule.c
+#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"s'esperava que «%.*s» en el camí del submòdul «%s» no fos un enllaç simbòlic"
+
+#: submodule.c
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "s'esperava que el camí del submòdul «%s» no fos un enllaç simbòlic"
+
+#: submodule.c
#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
@@ -21217,14 +27672,17 @@ msgstr ""
"no està admès relocate_gitdir per al submòdul «%s» amb més d'un arbre de "
"treball"
+#: submodule.c
#, c-format
msgid "could not lookup name for submodule '%s'"
msgstr "no s'ha trobat el nom pel submòdul «%s»"
+#: submodule.c
#, c-format
msgid "refusing to move '%s' into an existing git dir"
msgstr "s'ha refusat moure «%s» a un directori git existent"
+#: submodule.c
#, c-format
msgid ""
"Migrating git directory of '%s%s' from\n"
@@ -21235,156 +27693,186 @@ msgstr ""
"«%s» a\n"
"«%s»\n"
+#: submodule.c
msgid "could not start ls-files in .."
msgstr "no s'ha pogut iniciar ls-files a .."
+#: submodule.c
#, c-format
msgid "ls-tree returned unexpected return code %d"
msgstr "ls-tree ha retornat un codi de retorn %d no esperat"
+#: symlinks.c
#, c-format
msgid "failed to lstat '%s'"
msgstr "s'ha produït un error en fer lstat a «%s»"
+#: t/helper/test-bundle-uri.c
msgid "no remote configured to get bundle URIs from"
msgstr "no hi ha cap remot configurat per a obtenir els URI del paquet"
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "el remot «%s» no té cap URL configurat"
-
+#: t/helper/test-bundle-uri.c
msgid "could not get the bundle-uri list"
msgstr "no s'ha pogut obtenir la llista bundle-uri"
+#: t/helper/test-cache-tree.c
msgid "test-tool cache-tree <options> (control|prime|update)"
msgstr "test-tool cache-tree <opcions> (control|prime|update)"
+#: t/helper/test-cache-tree.c
msgid "clear the cache tree before each iteration"
msgstr "neteja l'arbre de la memòria cau abans de cada iteració"
+#: t/helper/test-cache-tree.c
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr ""
"nombre d'entrades a l'arbre de la memòria cau a invalidar (per defecte 0)"
-msgid "unhandled options"
-msgstr "opcions no gestionades"
-
-msgid "error preparing revisions"
-msgstr "s'ha produït un error en preparar les revisions"
-
+#: t/helper/test-reach.c
#, c-format
msgid "commit %s is not marked reachable"
msgstr "la comissió %s no està marcada com abastable"
+#: t/helper/test-reach.c
msgid "too many commits marked reachable"
msgstr "hi ha massa comissions marcades com abastables"
+#: t/helper/test-serve-v2.c
msgid "test-tool serve-v2 [<options>]"
msgstr "test-tool serve-v2 [<opcions>]"
+#: t/helper/test-serve-v2.c
msgid "exit immediately after advertising capabilities"
msgstr "surt immediatament després d'anunciar les funcionalitats"
+#: t/helper/test-simple-ipc.c
msgid "test-helper simple-ipc is-active [<name>] [<options>]"
msgstr "test-helper simple-ipc is-active [<nom>] [<opcions>]"
+#: t/helper/test-simple-ipc.c
msgid "test-helper simple-ipc run-daemon [<name>] [<threads>]"
msgstr "test-helper simple-ipc run-daemon [<nom>] [<fils>]"
+#: t/helper/test-simple-ipc.c
msgid "test-helper simple-ipc start-daemon [<name>] [<threads>] [<max-wait>]"
msgstr "test-helper simple-ipc start-daemon [<nom>] [<fils>] [<max-wait>]"
+#: t/helper/test-simple-ipc.c
msgid "test-helper simple-ipc stop-daemon [<name>] [<max-wait>]"
msgstr "test-helper simple-ipc stop-daemon [<nom>] [<max-wait>]"
+#: t/helper/test-simple-ipc.c
msgid "test-helper simple-ipc send [<name>] [<token>]"
msgstr "test-helper simple-ipc send [<nom>] [<testimoni>]"
+#: t/helper/test-simple-ipc.c
msgid "test-helper simple-ipc sendbytes [<name>] [<bytecount>] [<byte>]"
-msgstr "test-helper simple-ipc sendbytes [<nom>] [<bytecount>] [<byte>]"
+msgstr ""
+"test-helper simple-ipc sendbytes [<nom>] [<recompte-octets>] [<octet>]"
+#: t/helper/test-simple-ipc.c
msgid ""
"test-helper simple-ipc multiple [<name>] [<threads>] [<bytecount>] "
"[<batchsize>]"
msgstr ""
-"test-helper simple-ipc multiple [<nom>] [<fils>] [<bytecount>] "
-"[<batchsize>]"
+"test-helper simple-ipc multiple [<nom>] [<fils>] [<recompte-octets>] "
+"[<mida-lot>]"
+#: t/helper/test-simple-ipc.c
msgid "name or pathname of unix domain socket"
msgstr "nom o nom de camí del sòcol de domini unix"
+#: t/helper/test-simple-ipc.c
msgid "named-pipe name"
msgstr "nom del conducte amb nom"
+#: t/helper/test-simple-ipc.c
msgid "number of threads in server thread pool"
msgstr "nombre de fils en el conjunt de fils del servidor"
+#: t/helper/test-simple-ipc.c
msgid "seconds to wait for daemon to start or stop"
msgstr "segons a esperar que el dimoni comenci o s'aturi"
+#: t/helper/test-simple-ipc.c
msgid "number of bytes"
msgstr "nombre d'octets"
+#: t/helper/test-simple-ipc.c
msgid "number of requests per thread"
msgstr "nombre de peticions per fil"
+#: t/helper/test-simple-ipc.c
msgid "byte"
msgstr "octet"
+#: t/helper/test-simple-ipc.c
msgid "ballast character"
msgstr "caràcter de llast"
+#: t/helper/test-simple-ipc.c
msgid "token"
msgstr "testimoni"
+#: t/helper/test-simple-ipc.c
msgid "command token to send to the server"
msgstr "testimoni d'ordre a enviar al servidor"
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<opcions>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "sortir immediatament en fallar el primer test"
+
+# deixada sense traduir perquè pareix opció i no text
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr ""
+"executa només el conjunt de proves o la prova individual <suite[::test]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "suite"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "exclou conjunt de proves <conjunt>"
+
+#: trailer.c
#, c-format
msgid "running trailer command '%s' failed"
msgstr "l'execució de l'ordre «trailer» «%s» ha fallat"
+#: trailer.c
#, c-format
msgid "unknown value '%s' for key '%s'"
msgstr "valor desconegut «%s» per a la clau «%s»"
+#: trailer.c
#, c-format
msgid "empty trailer token in trailer '%.*s'"
msgstr "testimoni de «trailer» buit en el «trailer» «%.*s»"
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "no s'ha pogut llegir el fitxer d'entrada «%s»"
-
-#, c-format
-msgid "could not stat %s"
-msgstr "no s'ha pogut fer stat a %s"
-
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "el fitxer %s no és un fitxer regular"
-
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "el fitxer %s no és gravable per l'usuari"
-
-msgid "could not open temporary file"
-msgstr "no s'ha pogut obrir el fitxer temporal"
-
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "no s'ha pogut canviar el nom del fitxer temporal a %s"
-
+#: transport-helper.c
msgid "full write to remote helper failed"
msgstr "l'escriptura completa a l'ajudant remot ha fallat"
+#: transport-helper.c
#, c-format
msgid "unable to find remote helper for '%s'"
msgstr "no s'ha pogut trobar l'ajudant remot per a «%s»"
+#: transport-helper.c
msgid "can't dup helper output fd"
msgstr "no es pot duplicar la sortida de l'ajudant «fd»"
+#: transport-helper.c
#, c-format
msgid ""
"unknown mandatory capability %s; this remote helper probably needs newer "
@@ -21393,96 +27881,118 @@ msgstr ""
"funcionalitat obligatòria %s desconeguda; aquest ajudant remot probablement "
"necessita una versió més nova del Git"
+#: transport-helper.c
msgid "this remote helper should implement refspec capability"
msgstr "aquest ajudant remot ha d'implementar la funcionalitat de refspec"
+#: transport-helper.c
#, c-format
msgid "%s unexpectedly said: '%s'"
msgstr "%s ha dit inesperadament «%s»"
+#: transport-helper.c
#, c-format
msgid "%s also locked %s"
msgstr "%s també està bloquejat %s"
+#: transport-helper.c
msgid "couldn't run fast-import"
msgstr "no s'ha pogut executar «fast-import»"
+#: transport-helper.c
msgid "error while running fast-import"
msgstr "error en executar la importació ràpida"
+#: transport-helper.c
#, c-format
msgid "could not read ref %s"
msgstr "no s'ha pogut llegir la referència %s"
+#: transport-helper.c
#, c-format
msgid "unknown response to connect: %s"
msgstr "resposta desconeguda en connectar: %s"
+#: transport-helper.c
msgid "setting remote service path not supported by protocol"
msgstr "el protocol no permet establir el camí del servei remot"
+#: transport-helper.c
msgid "invalid remote service path"
msgstr "el camí del servei remot no és vàlid"
-msgid "operation not supported by protocol"
-msgstr "opció no admesa pel protocol"
-
+#: transport-helper.c
#, c-format
msgid "can't connect to subservice %s"
msgstr "no es pot connectar al subservei %s"
+#: transport-helper.c transport.c
msgid "--negotiate-only requires protocol v2"
msgstr "--negotiate-only requereix el protocol v2"
+#: transport-helper.c
msgid "'option' without a matching 'ok/error' directive"
msgstr "«option» sense una directiva «ok/error» coincident"
+#: transport-helper.c
#, c-format
msgid "expected ok/error, helper said '%s'"
msgstr "s'esperava error/OK, l'ajudant ha dit «%s»"
+#: transport-helper.c
#, c-format
msgid "helper reported unexpected status of %s"
msgstr "l'ajudant ha informat d'un estat inesperat de %s"
+#: transport-helper.c
#, c-format
msgid "helper %s does not support dry-run"
msgstr "l'ajudant %s no admet dry-run"
+#: transport-helper.c
#, c-format
msgid "helper %s does not support --signed"
msgstr "l'ajudant %s no admet --signed"
+#: transport-helper.c
#, c-format
msgid "helper %s does not support --signed=if-asked"
msgstr "l'ajudant %s no admet --signed=if-asked"
+#: transport-helper.c
#, c-format
msgid "helper %s does not support --atomic"
msgstr "l'ajudant %s no admet --atomic"
+#: transport-helper.c
#, c-format
msgid "helper %s does not support --%s"
msgstr "l'ajudant %s no admet --%s"
+#: transport-helper.c
#, c-format
msgid "helper %s does not support 'push-option'"
msgstr "l'ajudant %s no admet «push-option»"
+#: transport-helper.c
msgid "remote-helper doesn't support push; refspec needed"
msgstr ""
-"remot-helper no permet pujar; es necessiten especificacions de referència"
+"remote-helper no permet pujar; es necessiten especificacions de referència"
+#: transport-helper.c
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "l'ajudant %s no admet «force»"
+msgid "helper %s does not support '--force'"
+msgstr "l'ajudant %s no admet «--force»"
+#: transport-helper.c
msgid "couldn't run fast-export"
msgstr "no s'ha pogut executar l'exportació ràpida"
+#: transport-helper.c
msgid "error while running fast-export"
msgstr "error en executar l'exportació ràpida"
+#: transport-helper.c
#, c-format
msgid ""
"No refs in common and none specified; doing nothing.\n"
@@ -21491,84 +28001,101 @@ msgstr ""
"No hi ha referències en comú i no n'hi ha cap d'especificada.\n"
"No es farà res. Potser hauríeu d'especificar una branca.\n"
+#: transport-helper.c
#, c-format
msgid "unsupported object format '%s'"
msgstr "format d'objecte no suportat «%s»"
+#: transport-helper.c
#, c-format
msgid "malformed response in ref list: %s"
msgstr "resposta mal formada al llistat de referències: %s"
+#: transport-helper.c
#, c-format
msgid "read(%s) failed"
msgstr "ha fallat la lectura(%s)"
+#: transport-helper.c
#, c-format
msgid "write(%s) failed"
msgstr "ha fallat l'escriptura(%s)"
+#: transport-helper.c
#, c-format
msgid "%s thread failed"
msgstr "%s ha fallat el fil"
+#: transport-helper.c
#, c-format
msgid "%s thread failed to join: %s"
msgstr "el fil %s no s'ha pogut unir: %s"
+#: transport-helper.c
#, c-format
msgid "can't start thread for copying data: %s"
msgstr "no es pot iniciar el fil per a copiar les dades: %s"
+#: transport-helper.c
#, c-format
msgid "%s process failed to wait"
msgstr "el procés %s no ha pogut esperar"
+#: transport-helper.c
#, c-format
msgid "%s process failed"
msgstr "el procés %s ha fallat"
+#: transport-helper.c
msgid "can't start thread for copying data"
msgstr "no es pot iniciar el fil per a copiar dades"
+#: transport.c
#, c-format
msgid "Would set upstream of '%s' to '%s' of '%s'\n"
msgstr "Canviaria la font de «%s» a «%s» de «%s»\n"
+#: transport.c
#, c-format
msgid "could not read bundle '%s'"
msgstr "no s'ha pogut llegir el farcell «%s»"
+#: transport.c
#, c-format
msgid "transport: invalid depth option '%s'"
msgstr "transport: opció de profunditat no vàlida «%s»"
+#: transport.c
msgid "see protocol.version in 'git help config' for more details"
msgstr "vegeu «protocol.version» a «git help config» per a més detalls"
+#: transport.c
msgid "server options require protocol version 2 or later"
msgstr "les opcions del servidor requereixen el protocol versió 2 o posterior"
+#: transport.c
msgid "server does not support wait-for-done"
msgstr "el servidor no admet «wait-for-done»"
+#: transport.c
msgid "could not parse transport.color.* config"
msgstr "no s'ha pogut analitzar la configuració de transport.color.*"
+#: transport.c
msgid "support for protocol v2 not implemented yet"
msgstr ""
"encara no s'ha implementat la compatibilitat amb la versió v2 del protocol"
-#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "valor desconegut per al config «%s»': %s"
-
+#: transport.c
#, c-format
msgid "transport '%s' not allowed"
msgstr "no es permet el transport «%s»"
+#: transport.c
msgid "git-over-rsync is no longer supported"
msgstr "git-over-rsync ja no s'admet"
+#: transport.c
#, c-format
msgid ""
"The following submodule paths contain changes that can\n"
@@ -21577,6 +28104,7 @@ msgstr ""
"Els camins de submòdul següents contenen canvis que no\n"
"es poden trobar en cap remot:\n"
+#: transport.c
#, c-format
msgid ""
"\n"
@@ -21602,31 +28130,44 @@ msgstr ""
"\n"
"per a pujar-los a un remot.\n"
+#: transport.c
msgid "Aborting."
msgstr "S'està avortant."
+#: transport.c
msgid "failed to push all needed submodules"
msgstr "no s'han pogut pujar tots els submòduls necessaris"
+#: transport.c
msgid "bundle-uri operation not supported by protocol"
msgstr "L'operació bundle-uri no és compatible amb el protocol"
+#: transport.c
msgid "could not retrieve server-advertised bundle-uri list"
msgstr ""
"no s'ha pogut recuperar la llista de paquets d'URI anunciats pel servidor"
+#: transport.c
+msgid "operation not supported by protocol"
+msgstr "opció no admesa pel protocol"
+
+#: tree-walk.c
msgid "too-short tree object"
msgstr "objecte d'arbre massa curt"
+#: tree-walk.c
msgid "malformed mode in tree entry"
msgstr "mode mal format en entrada d'arbre"
+#: tree-walk.c
msgid "empty filename in tree entry"
msgstr "nom de fitxer buit en una entrada d'arbre"
+#: tree-walk.c
msgid "too-short tree file"
msgstr "fitxer d'arbre massa curt"
+#: unpack-trees.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by checkout:\n"
@@ -21635,6 +28176,7 @@ msgstr ""
"Els canvis locals als fitxers següents se sobreescriurien per a agafar:\n"
"%%sCometeu els vostres canvis o feu «stash» abans de canviar de branca."
+#: unpack-trees.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by checkout:\n"
@@ -21643,6 +28185,7 @@ msgstr ""
"Els canvis locals als fitxers següents se sobreescriurien per a agafar:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by merge:\n"
@@ -21651,6 +28194,7 @@ msgstr ""
"Els canvis locals als fitxers següents se sobreescriurien per a fusionar:\n"
"%%sCometeu els vostres canvis o feu «stash» abans de fusionar."
+#: unpack-trees.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by merge:\n"
@@ -21659,6 +28203,7 @@ msgstr ""
"Els canvis locals als fitxers següents se sobreescriurien per a fusionar:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by %s:\n"
@@ -21667,6 +28212,7 @@ msgstr ""
"Els vostres canvis locals als fitxers següents se sobreescriurien per %s:\n"
"%%sCometeu els vostres canvis o feu «stash» abans de %s."
+#: unpack-trees.c
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by %s:\n"
@@ -21675,6 +28221,7 @@ msgstr ""
"Els vostres canvis locals als fitxers següents se sobreescriurien per %s:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"Updating the following directories would lose untracked files in them:\n"
@@ -21683,6 +28230,7 @@ msgstr ""
"En actualitzar els directoris següents perdria fitxers no seguits en el:\n"
"%s"
+#: unpack-trees.c
#, c-format
msgid ""
"Refusing to remove the current working directory:\n"
@@ -21691,6 +28239,7 @@ msgstr ""
"S'ha rebutjat suprimir el directori de treball actual:\n"
"%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be removed by checkout:\n"
@@ -21700,6 +28249,7 @@ msgstr ""
"agafar:\n"
"%%sMoveu-los o elimineu-los abans de canviar de branca."
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be removed by checkout:\n"
@@ -21709,6 +28259,7 @@ msgstr ""
"agafar:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be removed by merge:\n"
@@ -21718,6 +28269,7 @@ msgstr ""
"fusionar:\n"
"%%sMoveu-los o elimineu-los abans de fusionar."
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be removed by merge:\n"
@@ -21727,6 +28279,7 @@ msgstr ""
"fusionar:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be removed by %s:\n"
@@ -21735,6 +28288,7 @@ msgstr ""
"Els següents fitxers no seguits en l'arbre de treball s'eliminarien per %s:\n"
"%%sMoveu-los o elimineu-los abans de %s."
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be removed by %s:\n"
@@ -21743,6 +28297,7 @@ msgstr ""
"Els següents fitxers no seguits en l'arbre de treball s'eliminarien per %s:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by "
@@ -21753,6 +28308,7 @@ msgstr ""
"a agafar:\n"
"%%sMoveu-los o elimineu-los abans de canviar de branca."
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by "
@@ -21763,6 +28319,7 @@ msgstr ""
"a agafar:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by merge:\n"
@@ -21772,6 +28329,7 @@ msgstr ""
"a fusionar:\n"
"%%sMoveu-los o elimineu-los abans de fusionar."
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by merge:\n"
@@ -21781,6 +28339,7 @@ msgstr ""
"a fusionar:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by %s:\n"
@@ -21790,6 +28349,7 @@ msgstr ""
"%s:\n"
"%%sMoveu-los o elimineu-los abans de %s."
+#: unpack-trees.c
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by %s:\n"
@@ -21799,10 +28359,12 @@ msgstr ""
"%s:\n"
"%%s"
+#: unpack-trees.c
#, c-format
msgid "Entry '%s' overlaps with '%s'. Cannot bind."
msgstr "L'entrada «%s» encavalca amb «%s». No es pot vincular."
+#: unpack-trees.c
#, c-format
msgid ""
"Cannot update submodule:\n"
@@ -21811,6 +28373,7 @@ msgstr ""
"No es pot actualitzar el submòdul:\n"
"%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following paths are not up to date and were left despite sparse "
@@ -21821,6 +28384,7 @@ msgstr ""
"patrons dispersos:\n"
"%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following paths are unmerged and were left despite sparse patterns:\n"
@@ -21830,6 +28394,7 @@ msgstr ""
"dispersos:\n"
"%s"
+#: unpack-trees.c
#, c-format
msgid ""
"The following paths were already present and thus not updated despite sparse "
@@ -21840,10 +28405,12 @@ msgstr ""
"malgrat els patrons dispersos.:\n"
"%s"
+#: unpack-trees.c
#, c-format
msgid "Aborting\n"
msgstr "S'està avortant\n"
+#: unpack-trees.c
#, c-format
msgid ""
"After fixing the above paths, you may want to run `git sparse-checkout "
@@ -21852,9 +28419,11 @@ msgstr ""
"Després de corregir els camins anteriors és possible que vulgueu executar "
"«git sparse-checkout reapply».\n"
+#: unpack-trees.c
msgid "Updating files"
msgstr "S'estan actualitzant els fitxers"
+#: unpack-trees.c
msgid ""
"the following paths have collided (e.g. case-sensitive paths\n"
"on a case-insensitive filesystem) and only one from the same\n"
@@ -21865,270 +28434,358 @@ msgstr ""
"minúscules). Només un camí del mateix grup de col·lisió es troba a l'arbre\n"
"de treball:\n"
+#: unpack-trees.c
msgid "Updating index flags"
msgstr "Actualitzant els indicadors d'índex"
+#: unpack-trees.c
#, c-format
msgid "worktree and untracked commit have duplicate entries: %s"
msgstr ""
"l'arbre de treball i la comissió no seguida tenen entrades duplicades: %s"
+#: upload-pack.c
msgid "expected flush after fetch arguments"
msgstr "s'esperava una neteja després dels arguments del «fetch»"
+#: urlmatch.c
msgid "invalid URL scheme name or missing '://' suffix"
msgstr "l'esquema d'URL no és vàlid o li manca el sufix «://»"
+#: urlmatch.c
#, c-format
msgid "invalid %XX escape sequence"
msgstr "seqüència d'escapament %XX no vàlida"
+#: urlmatch.c
msgid "missing host and scheme is not 'file:'"
msgstr "manca la màquina i l'esquema no és «file:»"
+#: urlmatch.c
msgid "a 'file:' URL may not have a port number"
msgstr "un URL «file:» no pot tenir número de port"
+#: urlmatch.c
msgid "invalid characters in host name"
msgstr "hi ha caràcters no vàlids en el nom de màquina"
+#: urlmatch.c
msgid "invalid port number"
msgstr "número de port no vàlid"
+#: urlmatch.c
msgid "invalid '..' path segment"
msgstr "segment de camí «..» no vàlid"
+#: usage.c
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "error: no s'ha pogut formatar el missatge: %s\n"
+
+#: usage.c
msgid "usage: "
msgstr "ús: "
+#: usage.c
msgid "fatal: "
msgstr "fatal: "
+#: usage.c
msgid "error: "
msgstr "error: "
+#: usage.c
msgid "warning: "
msgstr "avís: "
+#: walker.c
msgid "Fetching objects"
msgstr "S'estan obtenint objectes"
+#: worktree.c
#, c-format
msgid "'%s' at main working tree is not the repository directory"
msgstr "«%s» a l'arbre de treball principal no és al directori del repositori"
+#: worktree.c
#, c-format
msgid "'%s' file does not contain absolute path to the working tree location"
msgstr ""
"El fitxer «%s» no conté el camí absolut a la ubicació de l'arbre de treball"
+#: worktree.c
#, c-format
msgid "'%s' is not a .git file, error code %d"
msgstr "«%s» no és un fitxer .git, codi d'error %d"
+#: worktree.c
#, c-format
msgid "'%s' does not point back to '%s'"
msgstr "«%s» no assenyala de tornada a «%s»"
+#: worktree.c
msgid "not a directory"
msgstr "no és en un directori"
+#: worktree.c
msgid ".git is not a file"
msgstr ".git no és un fitxer"
+#: worktree.c
msgid ".git file broken"
msgstr "fitxer .git malmès"
+#: worktree.c
msgid ".git file incorrect"
msgstr "fitxer .git incorrecte"
+#: worktree.c
msgid "not a valid path"
msgstr "no és un camí vàlid"
+#: worktree.c
msgid "unable to locate repository; .git is not a file"
msgstr "no s'ha pogut trobar el repositori; .git no és un fitxer"
+#: worktree.c
msgid "unable to locate repository; .git file does not reference a repository"
msgstr ""
"no s'ha pogut trobar el repositori; el fitxer .git no fa referència a un "
"repositori"
+#: worktree.c
msgid "unable to locate repository; .git file broken"
msgstr "no s'ha pogut trobar el repositori; el fitxer .git està malmès"
+#: worktree.c
msgid "gitdir unreadable"
msgstr "gitdir illegible"
+#: worktree.c
msgid "gitdir incorrect"
msgstr "gitdir incorrecte"
+#: worktree.c
msgid "not a valid directory"
msgstr "no és en un directori vàlid"
+#: worktree.c
msgid "gitdir file does not exist"
msgstr "el fitxer gitdir no existeix"
+#: worktree.c
#, c-format
msgid "unable to read gitdir file (%s)"
msgstr "no s'ha pogut llegir el fitxer gitdir (%s)"
+#: worktree.c
#, c-format
msgid "short read (expected %<PRIuMAX> bytes, read %<PRIuMAX>)"
-msgstr "lectura curta (s'esperaven %<PRIuMAX> bytes, llegits %<PRIuMAX>)"
+msgstr "lectura curta (s'esperaven %<PRIuMAX> octets, s'han llegit %<PRIuMAX>)"
+#: worktree.c
msgid "invalid gitdir file"
msgstr "fitxer gitdir no vàlid"
+#: worktree.c
msgid "gitdir file points to non-existent location"
msgstr "el fitxer gitdir indica una ubicació no existent"
+#: worktree.c
#, c-format
msgid "unable to set %s in '%s'"
msgstr "no s'han pogut establir %s en «%s»"
+#: worktree.c
#, c-format
msgid "unable to unset %s in '%s'"
msgstr "no s'ha pogut desassignar %s en «%s»"
+#: worktree.c
msgid "failed to set extensions.worktreeConfig setting"
msgstr "no s'ha pogut establir el paràmetre extensions.worktreeConfig"
+#: wrapper.c
#, c-format
msgid "could not setenv '%s'"
msgstr "no s'ha pogut fer setenv «%s»"
+#: wrapper.c
#, c-format
msgid "unable to create '%s'"
msgstr "no s'ha pogut crear «%s»"
+#: wrapper.c
#, c-format
msgid "could not open '%s' for reading and writing"
msgstr "no s'ha pogut obrir «%s» per a lectura i escriptura"
+#: wrapper.c
#, c-format
msgid "unable to access '%s'"
msgstr "no s'ha pogut accedir a «%s»"
+#: wrapper.c
msgid "unable to get current working directory"
msgstr "no s'ha pogut obtenir el directori de treball actual"
+#: wrapper.c
+msgid "unable to get random bytes"
+msgstr "no s'han pogut obtenir octets aleatoris"
+
+#: wt-status.c
msgid "Unmerged paths:"
msgstr "Camins sense fusionar:"
+#: wt-status.c
msgid " (use \"git restore --staged <file>...\" to unstage)"
msgstr " (useu «git restore --staged <fitxer>...» per a fer «unstage»)"
+#: wt-status.c
#, c-format
msgid " (use \"git restore --source=%s --staged <file>...\" to unstage)"
msgstr ""
" (useu «git restore --source=%s --staged <fitxer>...» per a fer «unstage»)"
+#: wt-status.c
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr " (useu «git rm --cached <fitxer>...» per a fer «unstage»)"
+#: wt-status.c
msgid " (use \"git add <file>...\" to mark resolution)"
msgstr " (useu «git add <fitxer>...» per a senyalar resolució)"
+#: wt-status.c
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
" (useu «git add/rm <fitxer>...» segons sigui apropiat per a senyalar "
"resolució)"
+#: wt-status.c
msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr " (useu «git rm <fitxer>...» per a senyalar resolució)"
+#: wt-status.c
msgid "Changes to be committed:"
msgstr "Canvis a cometre:"
+#: wt-status.c
msgid "Changes not staged for commit:"
msgstr "Canvis no «staged» per a cometre:"
+#: wt-status.c
msgid " (use \"git add <file>...\" to update what will be committed)"
msgstr " (useu «git add <fitxer>...» per a actualitzar què es cometrà)"
+#: wt-status.c
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr " (useu «git add/rm <fitxer>...» per a actualitzar què es cometrà)"
+#: wt-status.c
msgid ""
" (use \"git restore <file>...\" to discard changes in working directory)"
msgstr ""
" (useu «git restore <fitxer>...» per a descartar canvis en el directori de "
"treball)"
+#: wt-status.c
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
" (cometeu o descarteu el contingut modificat o no seguit en els submòduls)"
+#: wt-status.c
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr " (useu «git %s <fitxer>...» per a incloure'ls en la comissió)"
+#: wt-status.c
msgid "both deleted:"
msgstr "suprimit per ambdós:"
+#: wt-status.c
msgid "added by us:"
msgstr "afegit per nosaltres:"
+#: wt-status.c
msgid "deleted by them:"
msgstr "suprimit per ells:"
+#: wt-status.c
msgid "added by them:"
msgstr "afegit per ells:"
+#: wt-status.c
msgid "deleted by us:"
msgstr "suprimit per nosaltres:"
+#: wt-status.c
msgid "both added:"
msgstr "afegit per ambdós:"
+#: wt-status.c
msgid "both modified:"
msgstr "modificat per ambdós:"
+#: wt-status.c
msgid "new file:"
msgstr "fitxer nou:"
+#: wt-status.c
msgid "copied:"
msgstr "copiat:"
+#: wt-status.c
msgid "deleted:"
msgstr "suprimit:"
+#: wt-status.c
msgid "modified:"
msgstr "modificat:"
+#: wt-status.c
msgid "renamed:"
msgstr "canviat de nom:"
+#: wt-status.c
msgid "typechange:"
msgstr "canviat de tipus:"
+#: wt-status.c
msgid "unknown:"
msgstr "desconegut:"
+#: wt-status.c
msgid "unmerged:"
msgstr "sense fusionar:"
+#: wt-status.c
msgid "new commits, "
msgstr "comissions noves, "
+#: wt-status.c
msgid "modified content, "
msgstr "contingut modificat, "
+#: wt-status.c
msgid "untracked content, "
msgstr "contingut no seguit, "
+#: wt-status.c
#, c-format
msgid "Your stash currently has %d entry"
msgid_plural "Your stash currently has %d entries"
msgstr[0] "L'«stash» té actualment %d entrada"
msgstr[1] "L'«stash» té actualment %d entrades"
+#: wt-status.c
msgid "Submodules changed but not updated:"
msgstr "Submòduls canviats però no actualitzats:"
+#: wt-status.c
msgid "Submodule changes to be committed:"
msgstr "Canvis de submòdul a cometre:"
+#: wt-status.c
msgid ""
"Do not modify or remove the line above.\n"
"Everything below it will be ignored."
@@ -22136,6 +28793,7 @@ msgstr ""
"No modifiqueu ni elimineu la línia de dalt.\n"
"Tot el que hi ha a sota s'ignorarà."
+#: wt-status.c
#, c-format
msgid ""
"\n"
@@ -22147,90 +28805,115 @@ msgstr ""
"darrere.\n"
"Podeu utilitzar «--no-ahead-behind» per a evitar-ho.\n"
+#: wt-status.c
msgid "You have unmerged paths."
msgstr "Teniu camins sense fusionar."
+#: wt-status.c
msgid " (fix conflicts and run \"git commit\")"
msgstr " (arregleu els conflictes i executeu «git commit»)"
+#: wt-status.c
msgid " (use \"git merge --abort\" to abort the merge)"
msgstr " (useu «git merge --abort» per a avortar la fusió)"
+#: wt-status.c
msgid "All conflicts fixed but you are still merging."
msgstr "Tots els conflictes estan arreglats però encara esteu fusionant."
+#: wt-status.c
msgid " (use \"git commit\" to conclude merge)"
msgstr " (useu «git commit» per a concloure la fusió)"
+#: wt-status.c
msgid "You are in the middle of an am session."
msgstr "Esteu enmig d'una sessió am."
+#: wt-status.c
msgid "The current patch is empty."
msgstr "El pedaç actual està buit."
+#: wt-status.c
msgid " (fix conflicts and then run \"git am --continue\")"
msgstr " (arregleu els conflictes i després executeu «git am --continue»)"
+#: wt-status.c
msgid " (use \"git am --skip\" to skip this patch)"
msgstr " (useu «git am --skip» per a ometre aquest pedaç)"
+#: wt-status.c
msgid ""
" (use \"git am --allow-empty\" to record this patch as an empty commit)"
msgstr ""
" (useu «git am --allow-empty» per a enregistrar aquest pedaç com una "
"comissió buida)"
+#: wt-status.c
msgid " (use \"git am --abort\" to restore the original branch)"
msgstr " (useu «git am --abort» per a restaurar la branca original)"
+#: wt-status.c
msgid "git-rebase-todo is missing."
msgstr "Manca git-rebase-todo."
+#: wt-status.c
msgid "No commands done."
msgstr "No s'ha fet cap ordre."
+#: wt-status.c
#, c-format
msgid "Last command done (%<PRIuMAX> command done):"
msgid_plural "Last commands done (%<PRIuMAX> commands done):"
msgstr[0] "Darrera ordre acabada (%<PRIuMAX> ordre acabada):"
msgstr[1] "Darreres ordres acabades (%<PRIuMAX> ordres acabades):"
+#: wt-status.c
#, c-format
msgid " (see more in file %s)"
msgstr " (vegeu més en el fitxer %s)"
+#: wt-status.c
msgid "No commands remaining."
msgstr "No manca cap ordre."
+#: wt-status.c
#, c-format
msgid "Next command to do (%<PRIuMAX> remaining command):"
msgid_plural "Next commands to do (%<PRIuMAX> remaining commands):"
msgstr[0] "Següent ordre a fer (%<PRIuMAX> ordre restant):"
msgstr[1] "Següents ordres a fer (%<PRIuMAX> ordres restants):"
+#: wt-status.c
msgid " (use \"git rebase --edit-todo\" to view and edit)"
msgstr " (useu «git rebase --edit-todo» per a veure i editar)"
+#: wt-status.c
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr "Actualment esteu fent «rebase» de la branca «%s» en «%s»."
+#: wt-status.c
msgid "You are currently rebasing."
msgstr "Actualment esteu fent «rebase»."
+#: wt-status.c
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr " (arregleu els conflictes i després executeu «git rebase --continue»)"
+#: wt-status.c
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr " (useu «git rebase --skip» per a ometre aquest pedaç)"
+#: wt-status.c
msgid " (use \"git rebase --abort\" to check out the original branch)"
msgstr " (useu «git rebase --abort» per a agafar la branca original)"
+#: wt-status.c
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr ""
" (tots els conflictes estan arreglats: executeu «git rebase --continue»)"
+#: wt-status.c
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
@@ -22238,128 +28921,164 @@ msgstr ""
"Actualment esteu dividint una comissió mentre es fa «rebase» de la branca "
"«%s» en «%s»."
+#: wt-status.c
msgid "You are currently splitting a commit during a rebase."
msgstr "Actualment esteu dividint una comissió durant un «rebase»."
+#: wt-status.c
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr ""
" (Una vegada que el vostre directori de treball sigui net, executeu «git "
"rebase --continue»)"
+#: wt-status.c
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
"Actualment esteu editant una comissió mentre es fa «rebase» de la branca "
"«%s» en «%s»."
+#: wt-status.c
msgid "You are currently editing a commit during a rebase."
msgstr "Actualment esteu editant una comissió durant un «rebase»."
+#: wt-status.c
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr " (useu «git commit --amend» per a esmenar la comissió actual)"
+#: wt-status.c
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
" (useu «git rebase --continue» una vegada que estigueu satisfet amb els "
"vostres canvis)"
+#: wt-status.c
msgid "Cherry-pick currently in progress."
msgstr "Hi ha «cherry pick» actualment en curs."
+#: wt-status.c
#, c-format
msgid "You are currently cherry-picking commit %s."
msgstr "Actualment esteu fent «cherry pick» a la comissió %s."
+#: wt-status.c
msgid " (fix conflicts and run \"git cherry-pick --continue\")"
msgstr " (arregleu els conflictes i executeu «git cherry-pick --continue»)"
+#: wt-status.c
msgid " (run \"git cherry-pick --continue\" to continue)"
msgstr " (executeu «git cherry-pick --continue» per a continuar)"
+#: wt-status.c
msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
msgstr ""
" (tots els conflictes estan arreglats: executeu «git cherry-pick --"
"continue»)"
+#: wt-status.c
msgid " (use \"git cherry-pick --skip\" to skip this patch)"
msgstr " (useu «git cherry-pick --skip» per a ometre aquest pedaç)"
+#: wt-status.c
msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
msgstr ""
" (useu «git cherry-pick --abort» per a cancel·lar l'operació de «cherry "
"pick»)"
+#: wt-status.c
msgid "Revert currently in progress."
msgstr "Una reversió està actualment en curs."
+#: wt-status.c
#, c-format
msgid "You are currently reverting commit %s."
msgstr "Actualment esteu revertint la comissió %s."
+#: wt-status.c
msgid " (fix conflicts and run \"git revert --continue\")"
msgstr " (arregleu els conflictes i executeu «git revert --continue»)"
+#: wt-status.c
msgid " (run \"git revert --continue\" to continue)"
msgstr " (executeu «git revert --continue» per a continuar)"
+#: wt-status.c
msgid " (all conflicts fixed: run \"git revert --continue\")"
msgstr ""
" (tots els conflictes estan arreglats: executeu «git revert --continue»)"
+#: wt-status.c
msgid " (use \"git revert --skip\" to skip this patch)"
msgstr " (useu «git revert --skip» per a ometre aquest pedaç)"
+#: wt-status.c
msgid " (use \"git revert --abort\" to cancel the revert operation)"
msgstr " (useu «git revert --abort» per a cancel·lar l'operació de reversió)"
+#: wt-status.c
#, c-format
msgid "You are currently bisecting, started from branch '%s'."
msgstr "Actualment esteu bisecant, heu començat des de la branca «%s»."
+#: wt-status.c
msgid "You are currently bisecting."
msgstr "Actualment esteu bisecant."
+#: wt-status.c
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr " (useu «git bisect reset» per a tornar a la branca original)"
+#: wt-status.c
msgid "You are in a sparse checkout."
msgstr "Esteu en un «sparse-checkout»."
+#: wt-status.c
#, c-format
msgid "You are in a sparse checkout with %d%% of tracked files present."
msgstr "Esteu en un «sparse-checkout» amb un %d%% de fitxers seguits presents."
+#: wt-status.c
msgid "On branch "
msgstr "En la branca "
+#: wt-status.c
msgid "interactive rebase in progress; onto "
msgstr "«rebase» interactiu en curs; sobre "
+#: wt-status.c
msgid "rebase in progress; onto "
msgstr "«rebase» en curs; sobre "
+#: wt-status.c
msgid "HEAD detached at "
msgstr "HEAD separat a "
+#: wt-status.c
msgid "HEAD detached from "
msgstr "HEAD separat des de "
+#: wt-status.c
msgid "Not currently on any branch."
msgstr "Actualment no s'és en cap branca."
+#: wt-status.c
msgid "Initial commit"
msgstr "Comissió inicial"
+#: wt-status.c
msgid "No commits yet"
msgstr "No s'ha fet cap comissió encara"
+#: wt-status.c
msgid "Untracked files"
msgstr "Fitxers no seguits"
+#: wt-status.c
msgid "Ignored files"
msgstr "Fitxers ignorats"
+#: wt-status.c
#, c-format
msgid ""
"It took %.2f seconds to enumerate untracked files,\n"
@@ -22369,32 +29088,40 @@ msgstr ""
"però els resultats es van emmagatzemar a la memòria cau, i les\n"
"execucions posteriors podrien ser més ràpides."
+#: wt-status.c
#, c-format
msgid "It took %.2f seconds to enumerate untracked files."
msgstr "S'han trigat %.2f segons a enumerar els fitxers sense seguiment."
+#: wt-status.c
msgid "See 'git help status' for information on how to improve this."
msgstr ""
"Vegeu «git help status» per a obtenir informació sobre com millorar-ho."
+#: wt-status.c
#, c-format
msgid "Untracked files not listed%s"
msgstr "Els fitxers no seguits no estan llistats%s"
+#: wt-status.c
msgid " (use -u option to show untracked files)"
msgstr " (useu l'opció -u per a mostrar els fitxers no seguits)"
+#: wt-status.c
msgid "No changes"
msgstr "Sense canvis"
+#: wt-status.c
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr "no hi ha canvis afegits a cometre (useu «git add» o «git commit -a»)\n"
+#: wt-status.c
#, c-format
msgid "no changes added to commit\n"
msgstr "no hi ha canvis afegits a cometre\n"
+#: wt-status.c
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
@@ -22403,56 +29130,75 @@ msgstr ""
"no hi ha res afegit a cometre però hi ha fitxers no seguits (useu «git add» "
"per a seguir-los)\n"
+#: wt-status.c
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr "no hi ha res afegit a cometre però hi ha fitxers no seguits\n"
+#: wt-status.c
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
"no hi ha res a cometre (creeu/copieu fitxers i useu «git add» per a seguir-"
"los)\n"
+#: wt-status.c
#, c-format
msgid "nothing to commit\n"
msgstr "no hi ha res a cometre\n"
+#: wt-status.c
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
"no hi ha res a cometre (useu -u per a mostrar els fitxers no seguits)\n"
+#: wt-status.c
#, c-format
msgid "nothing to commit, working tree clean\n"
msgstr "no hi ha res a cometre, l'arbre de treball està net\n"
+#: wt-status.c
msgid "No commits yet on "
msgstr "No s'ha fet cap comissió encara a "
+#: wt-status.c
msgid "HEAD (no branch)"
msgstr "HEAD (sense branca)"
+#: wt-status.c
msgid "different"
msgstr "diferent"
+#: wt-status.c
msgid "behind "
msgstr "darrere "
+#: wt-status.c
msgid "ahead "
msgstr "davant per "
#. TRANSLATORS: the action is e.g. "pull with rebase"
+#: wt-status.c
#, c-format
msgid "cannot %s: You have unstaged changes."
msgstr "no es pot %s: Teniu canvis «unstaged»."
+#: wt-status.c
msgid "additionally, your index contains uncommitted changes."
msgstr "addicionalment, el vostre índex conté canvis sense cometre."
+#: wt-status.c
#, c-format
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "no es pot %s: El vostre índex conté canvis sense cometre."
+#: xdiff-interface.c
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "estil desconegut «%s» donat per a «%s»"
+
+#: git-merge-octopus.sh git-merge-resolve.sh
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22460,92 +29206,120 @@ msgstr ""
"Error: Els vostres canvis locals als fitxers següents se sobreescriurien per "
"a fusionar"
+#: git-merge-octopus.sh
msgid "Automated merge did not work."
msgstr "La fusió automàtica no ha funcionat."
+#: git-merge-octopus.sh
msgid "Should not be doing an octopus."
msgstr "No s'ha de fer un «octopus»."
+#: git-merge-octopus.sh
#, sh-format
msgid "Unable to find common commit with $pretty_name"
msgstr "No s'ha pogut trobar cap comissió en comú amb $pretty_name"
+#: git-merge-octopus.sh
#, sh-format
msgid "Already up to date with $pretty_name"
msgstr "Ja està al dia amb $pretty_name"
+#: git-merge-octopus.sh
#, sh-format
msgid "Fast-forwarding to: $pretty_name"
msgstr "S'està avançant ràpidament a: $pretty_name"
+#: git-merge-octopus.sh
#, sh-format
msgid "Trying simple merge with $pretty_name"
msgstr "S'està intentant una fusió simple amb $pretty_name"
+#: git-merge-octopus.sh
msgid "Simple merge did not work, trying automatic merge."
msgstr ""
"La fusió simple no ha funcionat, s'està intentant una fusió automàtica."
+#: git-sh-setup.sh
#, sh-format
msgid "usage: $dashless $USAGE"
msgstr "ús: $dashless $USAGE"
+#: git-sh-setup.sh
#, sh-format
msgid "Cannot chdir to $cdup, the toplevel of the working tree"
msgstr ""
"No es pot canviar de directori a $cdup, el nivell superior de l'arbre de "
"treball"
+#: git-sh-setup.sh
#, sh-format
msgid "fatal: $program_name cannot be used without a working tree."
msgstr "fatal: no es pot usar $program_name sense un arbre de treball."
+#: git-sh-setup.sh
msgid "Cannot rewrite branches: You have unstaged changes."
msgstr "No es poden reescriure branques: Teniu canvis «unstaged»."
+#: git-sh-setup.sh
#, sh-format
msgid "Cannot $action: You have unstaged changes."
msgstr "No es pot $action: Teniu canvis «unstaged»."
+#: git-sh-setup.sh
#, sh-format
msgid "Cannot $action: Your index contains uncommitted changes."
msgstr "No es pot $action: El vostre índex conté canvis sense cometre."
+#: git-sh-setup.sh
msgid "Additionally, your index contains uncommitted changes."
msgstr "Addicionalment, el vostre índex conté canvis sense cometre."
+#: git-sh-setup.sh
msgid "You need to run this command from the toplevel of the working tree."
msgstr ""
"Heu d'executar aquesta ordre des del nivell superior de l'arbre de treball."
+#: git-sh-setup.sh
msgid "Unable to determine absolute path of git directory"
msgstr "No s'ha pogut determinar el camí absolut del directori de git"
+#: git-send-email.perl
msgid "local zone differs from GMT by a non-minute interval\n"
msgstr "la zona local difereix de GMT per un interval que no és de minuts\n"
+#: git-send-email.perl
msgid "local time offset greater than or equal to 24 hours\n"
msgstr "el desplaçament de la zona local és més gran o igual a 24 hores\n"
+#: git-send-email.perl
#, perl-format
msgid "fatal: command '%s' died with exit code %d"
msgstr "fatal: l'ordre «%s» ha mort amb el codi de sortida %d"
+#: git-send-email.perl
msgid "the editor exited uncleanly, aborting everything"
msgstr "l'editor no ha sortit correctament, avortant-ho tot"
+#: git-send-email.perl
#, perl-format
msgid ""
"'%s' contains an intermediate version of the email you were composing.\n"
msgstr "«%s» conté una versió intermèdia del correu que estàveu redactant.\n"
+#: git-send-email.perl
#, perl-format
msgid "'%s.final' contains the composed email.\n"
msgstr "«%s.final» conté el correu redactat.\n"
+#: git-send-email.perl
msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases és incompatible amb altres opcions\n"
+#: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases i --translate-aliases s'exclouen mútuament\n"
+
+#: git-send-email.perl
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -22556,9 +29330,11 @@ msgstr ""
"la «e». Establiu sendemail.forbidSendmailVariables a false per a desactivar\n"
"la comprovació.\n"
+#: git-send-email.perl
msgid "Cannot run git format-patch from outside a repository\n"
msgstr "No es pot executar git format-patch des de fora del repositori\n"
+#: git-send-email.perl
msgid ""
"`batch-size` and `relogin` must be specified together (via command-line or "
"configuration option)\n"
@@ -22566,30 +29342,37 @@ msgstr ""
"«batch-size» i «relogin» s'han d'especificar junts (a través de la línia "
"d'ordres o l'opció de configuració)\n"
+#: git-send-email.perl
#, perl-format
msgid "Unknown --suppress-cc field: '%s'\n"
msgstr "Camp --suppress-cc desconegut: «%s»\n"
+#: git-send-email.perl
#, perl-format
msgid "Unknown --confirm setting: '%s'\n"
msgstr "Paràmetre --confirm desconegut: «%s»\n"
+#: git-send-email.perl
#, perl-format
msgid "warning: sendmail alias with quotes is not supported: %s\n"
msgstr "avís: no s'admet l'àlies de sendmail amb cometes: %s\n"
+#: git-send-email.perl
#, perl-format
msgid "warning: `:include:` not supported: %s\n"
msgstr "avís: «:include:» no s'admet: %s\n"
+#: git-send-email.perl
#, perl-format
msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
msgstr "avís: les redireccions «/file» ni «|pipe» no s'admeten: %s\n"
+#: git-send-email.perl
#, perl-format
msgid "warning: sendmail line is not recognized: %s\n"
msgstr "avís: no es pot reconèixer la línia sendmail: %s\n"
+#: git-send-email.perl
#, perl-format
msgid ""
"File '%s' exists but it could also be the range of commits\n"
@@ -22604,10 +29387,12 @@ msgstr ""
" * Dient «./%s» si volíeu especificar un fitxer; o\n"
" * Proporcionant l'opció «--format-patch» si volíeu especificar un rang.\n"
+#: git-send-email.perl
#, perl-format
msgid "Failed to opendir %s: %s"
msgstr "S'ha produït un error en obrir el directori %s: %s"
+#: git-send-email.perl
msgid ""
"\n"
"No patch files specified!\n"
@@ -22617,14 +29402,17 @@ msgstr ""
"No s'han especificat fitxers de pedaç\n"
"\n"
+#: git-send-email.perl
#, perl-format
msgid "No subject line in %s?"
msgstr "Sense assumpte a %s?"
+#: git-send-email.perl
#, perl-format
msgid "Failed to open for writing %s: %s"
msgstr "S'ha produït un error en obrir per escriptura %s: %s"
+#: git-send-email.perl
msgid ""
"Lines beginning in \"GIT:\" will be removed.\n"
"Consider including an overall diffstat or table of contents\n"
@@ -22638,22 +29426,27 @@ msgstr ""
"\n"
"Esborreu el contingut del cos si no voleu enviar cap resum.\n"
-#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "S'ha produït un error en obrir %s: %s"
-
+#: git-send-email.perl
#, perl-format
msgid "Failed to open %s.final: %s"
msgstr "S'ha produït un error en obrir %s.final: %s"
+#: git-send-email.perl
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "S'ha produït un error en obrir %s: %s"
+
+#: git-send-email.perl
msgid "Summary email is empty, skipping it\n"
msgstr "El correu electrònic de resum està buit, s'omet\n"
#. TRANSLATORS: please keep [y/N] as is.
+#: git-send-email.perl
#, perl-format
msgid "Are you sure you want to use <%s> [y/N]? "
msgstr "Esteu segur que voleu usar <%s> [y/N]? "
+#: git-send-email.perl
msgid ""
"The following files are 8bit, but do not declare a Content-Transfer-"
"Encoding.\n"
@@ -22661,9 +29454,11 @@ msgstr ""
"Els fitxers següents són 8bit, però no declaren un Content-Transfer-"
"Encoding.\n"
+#: git-send-email.perl
msgid "Which 8bit encoding should I declare [UTF-8]? "
msgstr "Quina codificació de 8 bits hauria de declarar [UTF-8]? "
+#: git-send-email.perl
#, perl-format
msgid ""
"Refusing to send because the patch\n"
@@ -22676,19 +29471,23 @@ msgstr ""
"perquè la plantilla té l'assumpte «*** SUBJECT HERE ***». Passeu --force si "
"realment voleu enviar-ho.\n"
+#: git-send-email.perl
msgid "To whom should the emails be sent (if anyone)?"
msgstr ""
"A qui s'haurien d'enviar els correus electrònics (si s'han d'enviar a algú)?"
+#: git-send-email.perl
#, perl-format
msgid "fatal: alias '%s' expands to itself\n"
msgstr "fatal: l'àlies «%s» s'expandeix a si mateix\n"
+#: git-send-email.perl
msgid "Message-ID to be used as In-Reply-To for the first email (if any)? "
msgstr ""
"S'ha d'usar el Message-ID com a In-Reply-To pel primer correu (si n'hi ha "
"cap)? "
+#: git-send-email.perl
#, perl-format
msgid "error: unable to extract a valid address from: %s\n"
msgstr "error: no s'ha pogut extreure una adreça vàlida de: %s\n"
@@ -22696,13 +29495,16 @@ msgstr "error: no s'ha pogut extreure una adreça vàlida de: %s\n"
#. TRANSLATORS: Make sure to include [q] [d] [e] in your
#. translation. The program will only accept English input
#. at this point.
+#: git-send-email.perl
msgid "What to do with this address? ([q]uit|[d]rop|[e]dit): "
msgstr "Què cal fer amb aquesta adreça? ([q]surt|[d]escarta|[e]dita): "
+#: git-send-email.perl
#, perl-format
msgid "CA path \"%s\" does not exist"
msgstr "el camí CA «%s» no existeix"
+#: git-send-email.perl
msgid ""
" The Cc list above has been expanded by additional\n"
" addresses found in the patch commit message. By default\n"
@@ -22729,95 +29531,121 @@ msgstr ""
#. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
#. translation. The program will only accept English input
#. at this point.
+#: git-send-email.perl
msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
msgstr ""
"Voleu enviar aquest correu electrònic? ([y]sí|[n]o|[e]dita|[q]surt|[a]tot): "
+#: git-send-email.perl
msgid "Send this email reply required"
msgstr "Requereix resposta en enviar el correu"
+#: git-send-email.perl
msgid "The required SMTP server is not properly defined."
msgstr "El servidor SMTP requerit no està correctament definit."
+#: git-send-email.perl
#, perl-format
msgid "Server does not support STARTTLS! %s"
msgstr "El servidor no admet STARTTLS! %s"
+#: git-send-email.perl
#, perl-format
msgid "STARTTLS failed! %s"
msgstr "STARTTLS ha fallat! %s"
+#: git-send-email.perl
msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
msgstr ""
"No s'ha pogut inicialitzar SMTP correctament. Comproveu-ho la configuració i "
"useu --smtp-debug."
+#: git-send-email.perl
#, perl-format
msgid "Failed to send %s\n"
msgstr "S'ha produït un error en enviar %s\n"
+#: git-send-email.perl
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Simulació d'enviament %s\n"
+msgid "Dry-Sent %s"
+msgstr "Prova-Enviat %s"
+#: git-send-email.perl
#, perl-format
-msgid "Sent %s\n"
-msgstr "Enviat %s\n"
+msgid "Sent %s"
+msgstr "Enviat %s"
-msgid "Dry-OK. Log says:\n"
-msgstr "Simulació de correcte. El registre diu:\n"
+#: git-send-email.perl
+msgid "Dry-OK. Log says:"
+msgstr "Prova correcta. El registre diu:"
-msgid "OK. Log says:\n"
-msgstr "Correcte. El registre diu: \n"
+#: git-send-email.perl
+msgid "OK. Log says:"
+msgstr "Correcte. El registre diu:"
+#: git-send-email.perl
msgid "Result: "
msgstr "Resultat: "
-msgid "Result: OK\n"
-msgstr "Resultat: correcte\n"
+# OK = correcte?
+#: git-send-email.perl
+msgid "Result: OK"
+msgstr "Resultat: correcte"
+#: git-send-email.perl
#, perl-format
msgid "can't open file %s"
msgstr "no es pot obrir el fitxer %s"
+#: git-send-email.perl
#, perl-format
msgid "(mbox) Adding cc: %s from line '%s'\n"
msgstr "(mbox) S'està afegint cc: %s des de la línia «%s»\n"
+#: git-send-email.perl
#, perl-format
msgid "(mbox) Adding to: %s from line '%s'\n"
msgstr "(mbox) S'està afegint a: %s des de la línia «%s»\n"
+#: git-send-email.perl
#, perl-format
msgid "(non-mbox) Adding cc: %s from line '%s'\n"
msgstr "(no mbox) S'està afegint cc: %s des de la línia «%s»\n"
+#: git-send-email.perl
#, perl-format
msgid "(body) Adding cc: %s from line '%s'\n"
msgstr "(cos) S'està afegint cc: %s des de la línia «%s»\n"
+#: git-send-email.perl
#, perl-format
msgid "(%s) Could not execute '%s'"
msgstr "(%s) no s'ha pogut executar «%s»"
+#: git-send-email.perl
#, perl-format
msgid "(%s) Malformed output from '%s'"
msgstr "(%s) Sortida mal formada de «%s»"
+#: git-send-email.perl
#, perl-format
msgid "(%s) failed to close pipe to '%s'"
msgstr "(%s) s'ha produït un error en tancar el conducte «%s»"
+#: git-send-email.perl
#, perl-format
msgid "(%s) Adding %s: %s from: '%s'\n"
msgstr "(%s) S'està afegint %s: %s des de: «%s»\n"
+#: git-send-email.perl
msgid "cannot send message as 7bit"
msgstr "no es pot enviar el missatge en 7 bits"
+#: git-send-email.perl
msgid "invalid transfer encoding"
msgstr "codificació de transferència no vàlida"
+#: git-send-email.perl
#, perl-format
msgid ""
"fatal: %s: rejected by %s hook\n"
@@ -22828,10 +29656,12 @@ msgstr ""
"%s\n"
"avís: no s'ha enviat cap pedaç\n"
+#: git-send-email.perl
#, perl-format
msgid "unable to open %s: %s\n"
msgstr "no s'ha pogut obrir %s: %s\n"
+#: git-send-email.perl
#, perl-format
msgid ""
"fatal: %s:%d is longer than 998 characters\n"
@@ -22840,11 +29670,91 @@ msgstr ""
"fatal: %s:%d té més de 998 caràcters\n"
"avís: no s'ha enviat cap pedaç\n"
+#: git-send-email.perl
#, perl-format
msgid "Skipping %s with backup suffix '%s'.\n"
msgstr "S'està ometent %s amb el sufix de còpia de seguretat «%s».\n"
#. TRANSLATORS: please keep "[y|N]" as is.
+#: git-send-email.perl
#, perl-format
msgid "Do you really want to send %s? [y|N]: "
msgstr "Esteu segur que voleu enviar %s? [y|N]: "
+
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "la configuració del recorregut de revisions ha fallat\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "no s'ha pogut analitzar el contacte: %s"
+
+#, c-format
+#~ msgid "truncating .rej filename to %.*s.rej"
+#~ msgstr "s'està truncant el nom del fitxer .rej a %.*s.rej"
+
+#~ msgid ""
+#~ "the add.interactive.useBuiltin setting has been removed!\n"
+#~ "See its entry in 'git help config' for details."
+#~ msgstr ""
+#~ "s'ha eliminat la configuració add.interactive.useBuiltin\n"
+#~ "Per a més detalls, vegeu la seva entrada a «git help config»."
+
+#~ msgid ""
+#~ "Use -f if you really want to add them.\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addIgnoredFile false\""
+#~ msgstr ""
+#~ "Utilitzeu -f si realment voleu afegir-los.\n"
+#~ "Desactiveu aquest missatge executant\n"
+#~ "«git config advice.addIgnoredFile false»"
+
+#~ msgid ""
+#~ "Maybe you wanted to say 'git add .'?\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addEmptyPathspec false\""
+#~ msgstr ""
+#~ "Potser voleu dir «git add .»?\n"
+#~ "Desactiveu aquest missatge executant\n"
+#~ "«git config advice.addEmptyPathspec false»"
+
+#~ msgid "git archive: Remote with no URL"
+#~ msgstr "git archive: Remot sense URL"
+
+#~ msgid ""
+#~ "clean.requireForce defaults to true and neither -i, -n, nor -f given; "
+#~ "refusing to clean"
+#~ msgstr ""
+#~ "clean.requireForce és per defecte cert i ni -i, -n ni -f s'han indicat; "
+#~ "refusant netejar"
+
+#~ msgid "only one action at a time"
+#~ msgstr "només una acció cada cop"
+
+#~ msgid "use [RFC PATCH] instead of [PATCH]"
+#~ msgstr "useu [RFC PATCH] en comptes de [PATCH]"
+
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not start with '('"
+#~ msgstr "format incorrecte del ls-files: l'element «%s» no comença amb «(»"
+
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not end in ')'"
+#~ msgstr "format incorrecte del ls-files: l'element «%s» no acaba amb «)»"
+
+#, c-format
+#~ msgid "bad ls-files format: %%%.*s"
+#~ msgstr "format incorrecte de ls-files: %%%.*s"
+
+#, c-format
+#~ msgid "no URLs configured for remote '%s'"
+#~ msgstr "cap URL configurat per al remot «%s»"
+
+#~ msgid "keep redundant, empty commits"
+#~ msgstr "retén les comissions redundants i buides"
+
+#~ msgid "core.commentChar should only be one ASCII character"
+#~ msgstr "core.commentChar només hauria de ser un caràcter ASCII"
+
+#, c-format
+#~ msgid "remote '%s' has no configured URL"
+#~ msgstr "el remot «%s» no té cap URL configurat"
diff --git a/po/de.po b/po/de.po
index f7e49ce4a5..06055e7611 100644
--- 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-08-17 16:53+0200\n"
-"PO-Revision-Date: 2023-08-17 16:55+0200\n"
+"POT-Creation-Date: 2024-10-05 16:17+0200\n"
+"PO-Revision-Date: 2024-10-05 16:18+0200\n"
"Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
"Language-Team: German\n"
"Language: de\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
-"X-Generator: Poedit 3.3.2\n"
+"X-Generator: Poedit 3.4.4\n"
#, c-format
msgid "Huh (%s)?"
@@ -512,12 +512,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"Um '%c' Zeilen zu entfernen, machen Sie aus diesen ' ' Zeilen (Kontext).\n"
"Um '%c' Zeilen zu entfernen, löschen Sie diese.\n"
-"Zeilen, die mit %c beginnen, werden entfernt.\n"
+"Zeilen, die mit %s beginnen, werden entfernt.\n"
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
@@ -566,6 +566,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j - diesen Patch-Block unbestimmt lassen, nächsten unbestimmten Patch-Block "
@@ -575,11 +576,16 @@ msgstr ""
"Block anzeigen\n"
"K - diesen Patch-Block unbestimmt lassen, vorherigen Patch-Block anzeigen\n"
"g - Patch-Block zum Hinspringen auswählen\n"
-"/ - nach Patch-Block suchen, der gegebenem regulärem Ausdruck entspricht\n"
+"/ - nach Patch-Block suchen, der regulärem Ausdruck entspricht\n"
"s - aktuellen Patch-Block in kleinere Patch-Blöcke aufteilen\n"
"e - aktuellen Patch-Block manuell editieren\n"
+"p - aktuellen Patch-Block anzeigen, 'P' um Anzeigeprogramm zu benutzen\n"
"? - Hilfe anzeigen\n"
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "Es wird nur ein Buchstabe erwartet, '%s' erhalten"
+
msgid "No previous hunk"
msgstr "Kein vorheriger Patch-Block"
@@ -628,9 +634,19 @@ msgstr "In %d Patch-Block aufgeteilt."
msgid "Sorry, cannot edit this hunk"
msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten"
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Unbekannter Befehl '%s' (für Hilfe '?' verwenden)"
+
msgid "'git apply' failed"
msgstr "'git apply' schlug fehl"
+msgid "No changes."
+msgstr "Keine Änderungen."
+
+msgid "Only binary files changed."
+msgstr "Nur Binärdateien geändert."
+
#, c-format
msgid ""
"\n"
@@ -640,8 +656,8 @@ msgstr ""
"Deaktivieren Sie diese Nachricht mit \"git config advice.%s false\""
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sHinweis: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sHinweis:%s%.*s%s\n"
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr ""
@@ -1160,10 +1176,6 @@ msgstr[0] "Wende Patch %%s mit %d Zurückweisung an..."
msgstr[1] "Wende Patch %%s mit %d Zurückweisungen an..."
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "Verkürze Name von .rej Datei zu %.*s.rej"
-
-#, c-format
msgid "cannot open %s"
msgstr "kann '%s' nicht öffnen"
@@ -1268,6 +1280,15 @@ msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr ""
"versuche 3-Wege-Merge, weiche auf normalen Patch aus, wenn dies fehlschlägt"
+msgid "for conflicts, use our version"
+msgstr "bei Konflikten unsere Variante verwenden"
+
+msgid "for conflicts, use their version"
+msgstr "bei Konflikten ihre Variante verwenden"
+
+msgid "for conflicts, use a union version"
+msgstr "bei Konflikten eine gemeinsame Variante verwenden"
+
msgid "build a temporary index based on embedded index information"
msgstr ""
"einen temporären Index, basierend auf den integrierten Index-Informationen, "
@@ -1317,6 +1338,9 @@ msgstr "<Wurzelverzeichnis> vor alle Dateinamen stellen"
msgid "don't return error for empty patches"
msgstr "keinen Fehler für leere Patches zurückgeben"
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, und --union erfordern --3way"
+
#, c-format
msgid "cannot stream blob %s"
msgstr "kann Blob %s nicht streamen"
@@ -1390,6 +1414,10 @@ msgid "not a tree object: %s"
msgstr "Kein Tree-Objekt: %s"
#, c-format
+msgid "failed to unpack tree object %s"
+msgstr "Tree-Objekt %s konnte nicht entpackt werden"
+
+#, c-format
msgid "File not found: %s"
msgstr "Datei nicht gefunden: %s"
@@ -1474,6 +1502,10 @@ msgid "Unexpected option --output"
msgstr "Unerwartete Option --output"
#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "zusätzlicher Befehlszeilenparameter '%s'"
+
+#, c-format
msgid "Unknown archive format '%s'"
msgstr "Unbekanntes Archivformat '%s'"
@@ -1515,10 +1547,22 @@ 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 "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr ""
+"kann nicht --attr-source oder GIT_ATTR_SOURCE ohne Repository verwenden"
+
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "ungültiges --attr-source oder GIT_ATTR_SOURCE"
#, c-format
+msgid "unable to stat '%s'"
+msgstr "konnte '%s' nicht lesen"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "kann %s nicht lesen"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Ungültiger Inhalt bzgl. Anführungszeichen in Datei '%s': %s"
@@ -1588,6 +1632,10 @@ msgid "could not create file '%s'"
msgstr "konnte Datei '%s' nicht erstellen"
#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "konnte 'show' für Objekt '%s' nicht starten"
+
+#, c-format
msgid "could not read file '%s'"
msgstr "Konnte Datei '%s' nicht lesen"
@@ -1739,6 +1787,9 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "'%s' ist kein gültiger Branchname"
+msgid "See `man git check-ref-format`"
+msgstr "Siehe `man git check-ref-format`"
+
#, c-format
msgid "a branch named '%s' already exists"
msgstr "Branch '%s' existiert bereits"
@@ -1807,8 +1858,8 @@ msgid "submodule '%s': cannot create branch '%s'"
msgstr "Submodul '%s': kann Branch nicht erzeugen: '%s'"
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "'%s' ist bereits in '%s' ausgecheckt"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "'%s' wird bereits von Arbeitsverzeichnis in '%s' verwendet"
msgid "git add [<options>] [--] <pathspec>..."
msgstr "git add [<Optionen>] [--] <Pfadspezifikation>..."
@@ -1821,32 +1872,22 @@ msgid "Unstaged changes after refreshing the index:"
msgstr ""
"Nicht zum Commit vorgemerkte Änderungen nach Aktualisierung der Staging-Area:"
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"Die Einstellung add.interactive.useBuiltin wurde entfernt!\n"
-"Siehe den Eintrag in 'git help config' für Details."
-
-msgid "Could not read the index"
-msgstr "Konnte den Index nicht lesen"
-
-msgid "Could not write patch"
-msgstr "Konnte Patch nicht schreiben"
+msgid "could not read the index"
+msgstr "konnte den Index nicht lesen"
msgid "editing patch failed"
msgstr "Bearbeitung des Patches fehlgeschlagen"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Konnte Verzeichnis '%s' nicht lesen"
+msgid "could not stat '%s'"
+msgstr "Konnte '%s' nicht lesen."
-msgid "Empty patch. Aborted."
-msgstr "Leerer Patch. Abgebrochen."
+msgid "empty patch. aborted"
+msgstr "leerer Patch. Abgebrochen"
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Konnte '%s' nicht anwenden."
+msgid "could not apply '%s'"
+msgstr "konnte '%s' nicht anwenden"
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
@@ -1948,14 +1989,8 @@ msgstr ""
msgid "adding embedded git repository: %s"
msgstr "Füge eingebettetes Repository hinzu: %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 ""
-"Nutzen Sie die Option -f, wenn sie wirklich hinzugefügt werden sollen.\n"
-"Um diese Meldung abzuschalten, führen Sie folgenden Befehl aus:\n"
-"\"git config advice.addIgnoredFile false\""
+msgid "Use -f if you really want to add them."
+msgstr "Verwenden Sie -f, wenn Sie diese wirklich hinzufügen möchten."
msgid "adding files failed"
msgstr "Hinzufügen von Dateien fehlgeschlagen"
@@ -1973,18 +2008,15 @@ msgstr ""
msgid "Nothing specified, nothing added.\n"
msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Eventuell meinten Sie 'git add .'?\n"
-"Um diese Meldung abzuschalten, führen Sie folgenden Befehl aus:\n"
-"\"git config advice.addEmptyPathspec false\""
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Meinten Sie vielleicht 'git add .'?"
msgid "index file corrupt"
msgstr "Index-Datei beschädigt"
+msgid "unable to write new index file"
+msgstr "Konnte neue Index-Datei nicht schreiben."
+
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "ungültige Aktion '%s' für '%s'"
@@ -2054,21 +2086,22 @@ msgid "Failed to split patches."
msgstr "Fehler beim Aufteilen der Patches."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
msgstr ""
-"Wenn Sie das Problem aufgelöst haben, führen Sie \"%s --continue\" aus."
+"Wenn Sie dieses Problem behoben haben, führen Sie \"%s --continue\" aus.\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
msgstr ""
"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"%s --"
-"skip\" aus."
+"skip\" aus.\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
-"Um den leeren Patch als einen leeren Commit zu speichern, führen Sie \"%s --"
-"allow-empty\" aus."
+"Um den leeren Patch als leeren Commit aufzuzeichnen, führen Sie \"%s --allow-"
+"empty\" aus.\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
@@ -2199,9 +2232,6 @@ msgstr ""
"Sie können `git rm` auf Dateien ausführen, um \"von denen gelöscht\" für\n"
"diese zu akzeptieren."
-msgid "unable to write new index file"
-msgstr "Konnte neue Index-Datei nicht schreiben."
-
#, c-format
msgid "Could not parse object '%s'."
msgstr "Konnte Objekt '%s' nicht parsen."
@@ -2220,11 +2250,6 @@ msgstr ""
msgid "failed to read '%s'"
msgstr "Fehler beim Lesen von '%s'"
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr ""
-"die Optionen '%s=%s' und '%s=%s' können nicht gemeinsam verwendet werden"
-
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<Optionen>] [(<mbox> | <E-Mail-Verzeichnis>)...]"
@@ -2304,6 +2329,9 @@ msgstr "Patch-Operation abbrechen, aber HEAD an aktueller Stelle belassen"
msgid "show the patch being applied"
msgstr "den Patch, der gerade angewendet wird, anzeigen"
+msgid "try to apply current patch again"
+msgstr "den aktuellen Patch erneut versuchen anzuwenden"
+
msgid "record the empty patch as an empty commit"
msgstr "leerer Patch als leeren Commit gespeichert"
@@ -2359,9 +2387,6 @@ msgstr "git apply [<Optionen>] [<Patch>...]"
msgid "could not redirect output"
msgstr "konnte Ausgabe nicht umleiten"
-msgid "git archive: Remote with no URL"
-msgstr "git archive: Externes Archiv ohne URL"
-
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive: ACK/NAK erwartet, Flush-Paket bekommen"
@@ -2376,11 +2401,11 @@ msgid "git archive: expected a flush"
msgstr "git archive: erwartete eine Spülung (flush)"
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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}=<Begriff> --term-{old,good}=<Begriff>] [--"
-"no-checkout] [--first-parent] [<schlecht> [<gut>...]] [--] "
+"git bisect start [--term-(new|bad)=<Begriff> --term-(old|good)=<Begriff>] "
+"[--no-checkout] [--first-parent] [<schlecht> [<gut>...]] [--] "
"[<Pfadspezifikation>...]"
msgid "git bisect (good|bad) [<rev>...]"
@@ -2395,8 +2420,8 @@ msgstr "git bisect reset [<Commit>]"
msgid "git bisect replay <logfile>"
msgstr "git bisect replay <Logdatei>"
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <Programm>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <Programm> [<Argument>...]"
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2516,9 +2541,6 @@ msgstr ""
"Ungültiges Argument %s für 'git bisect terms'.\n"
"Unterstützte Optionen sind: --term-good|--term-old und --term-bad|--term-new."
-msgid "revision walk setup failed\n"
-msgstr "Einrichtung des Revisionsgangs fehlgeschlagen\n"
-
#, c-format
msgid "could not open '%s' for appending"
msgstr "konnte '%s' nicht zum Anhängen öffnen"
@@ -2818,44 +2840,46 @@ msgstr "git branch [<Optionen>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
-"entferne Branch '%s', der zusammengeführt wurde mit\n"
-" '%s', aber noch nicht mit HEAD zusammengeführt wurde."
+"Löschen des Branches '%s', der mit\n"
+" '%s', aber noch nicht in HEAD zusammengeführt wurde"
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
"entferne Branch '%s' nicht, der noch nicht zusammengeführt wurde mit\n"
-" '%s', obwohl er mit HEAD zusammengeführt wurde."
+" '%s', obwohl er mit HEAD zusammengeführt wurde"
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Konnte Commit-Objekt für '%s' nicht nachschlagen."
+msgid "couldn't look up commit object for '%s'"
+msgstr "konnte Commit-Objekt für '%s' nicht nachschlagen"
#, 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'."
+msgid "the branch '%s' is not fully merged"
+msgstr "der Branch '%s' ist nicht vollständig zusammengeführt"
+
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
msgstr ""
-"Der Branch '%s' ist nicht vollständig zusammengeführt.\n"
-"Wenn Sie sicher sind diesen Branch zu entfernen, führen Sie 'git branch -D "
-"%s' aus."
+"Wenn Sie sicher sind, dass Sie den Branch löschen wollen, führen Sie 'git "
+"branch -D %s' aus."
-msgid "Update of config-file failed"
+msgid "update of config-file failed"
msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen."
msgid "cannot use -a with -d"
msgstr "kann -a nicht mit -d benutzen"
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "Kann Branch '%s' nicht entfernen, ausgecheckt in '%s'."
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"kann Branch '%s' nicht löschen, der in Arbeitsverzeichnis '%s' verwendet wird"
#, c-format
-msgid "remote-tracking branch '%s' not found."
+msgid "remote-tracking branch '%s' not found"
msgstr "Remote-Tracking-Branch '%s' nicht gefunden"
#, c-format
@@ -2867,8 +2891,8 @@ msgstr ""
"Haben Sie --remote vergessen?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "Branch '%s' nicht gefunden."
+msgid "branch '%s' not found"
+msgstr "Branch '%s' nicht gefunden"
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -2889,66 +2913,66 @@ msgid "HEAD (%s) points outside of refs/heads/"
msgstr "HEAD (%s) wurde nicht unter \"refs/heads/\" gefunden!"
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "Branch %s wird auf %s umgesetzt"
+msgid "branch %s is being rebased at %s"
+msgstr "Rebase von Branch %s in %s im Gange"
#, c-format
-msgid "Branch %s is being bisected at %s"
-msgstr "Binäre Suche von Branch %s zu %s im Gange"
+msgid "branch %s is being bisected at %s"
+msgstr "Binäre Suche von Branch %s in %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'"
+msgid "invalid branch name: '%s'"
msgstr "Ungültiger Branchname: '%s'"
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Noch kein Commit in Branch '%s'."
+msgid "no commit on branch '%s' yet"
+msgstr "Noch kein Commit in Branch '%s'"
#, c-format
-msgid "No branch named '%s'."
-msgstr "Branch '%s' nicht vorhanden."
+msgid "no branch named '%s'"
+msgstr "kein Branch mit dem Namen '%s'"
-msgid "Branch rename failed"
+msgid "branch rename failed"
msgstr "Umbenennung des Branches fehlgeschlagen"
-msgid "Branch copy failed"
+msgid "branch copy failed"
msgstr "Kopie des Branches fehlgeschlagen"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Kopie eines falsch benannten Branches '%s' erstellt."
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "Kopie eines falsch benannten Branches '%s' erstellt"
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
+msgid "renamed a misnamed branch '%s' away"
msgstr "falsch benannten Branch '%s' umbenannt"
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "Branch umbenannt zu %s, aber HEAD ist nicht aktualisiert!"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "Branch wird in %s umbenannt, aber HEAD wird nicht aktualisiert"
-msgid "Branch is renamed, but update of config-file failed"
+msgid "branch is renamed, but update of config-file failed"
msgstr ""
-"Branch ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
-"fehlgeschlagen."
+"Branch wurde umbenannt, aber die Aktualisierung der Konfigurationsdatei\n"
+"ist fehlgeschlagen"
-msgid "Branch is copied, but update of config-file failed"
+msgid "branch is copied, but update of config-file failed"
msgstr ""
-"Branch wurde kopiert, aber die Aktualisierung der Konfigurationsdatei ist\n"
-"fehlgeschlagen."
+"Branch wurde kopiert, aber die Aktualisierung der Konfigurationsdatei\n"
+"ist fehlgeschlagen"
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Bitte ändern Sie die Beschreibung für den Branch\n"
" %s\n"
-"Zeilen, die mit '%c' beginnen, werden entfernt.\n"
+"Zeilen, die mit '%s' beginnen, werden entfernt.\n"
msgid "Generic options"
msgstr "Allgemeine Optionen"
@@ -3053,8 +3077,8 @@ msgstr "Rekursion in Submodulen durchführen"
msgid "format to use for the output"
msgstr "für die Ausgabe zu verwendendes Format"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Konnte HEAD nicht als gültige Referenz auflösen."
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "HEAD konnte nicht als gültige Referenz aufgelöst werden"
msgid "HEAD not found below refs/heads!"
msgstr "HEAD wurde nicht unter \"refs/heads\" gefunden!"
@@ -3072,18 +3096,18 @@ msgstr "--recurse-submodules kann nur genutzt werden, um Branches zu erstellen"
msgid "branch name required"
msgstr "Branchname erforderlich"
-msgid "Cannot give description to detached HEAD"
+msgid "cannot give description to detached HEAD"
msgstr "zu losgelöstem HEAD kann keine Beschreibung hinterlegt werden"
msgid "cannot edit description of more than one branch"
msgstr "Beschreibung von mehr als einem Branch kann nicht bearbeitet werden"
-msgid "cannot copy the current branch while not on any."
+msgid "cannot copy the current branch while not on any"
msgstr ""
"Kann den aktuellen Branch nicht kopieren, solange Sie sich auf keinem "
"befinden."
-msgid "cannot rename the current branch while not on any."
+msgid "cannot rename the current branch while not on any"
msgstr ""
"Kann aktuellen Branch nicht umbenennen, solange Sie sich auf keinem befinden."
@@ -3098,10 +3122,10 @@ msgstr "zu viele Argumente angegeben, um Upstream-Branch zu setzen"
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
-"Konnte keinen neuen Upstream-Branch von HEAD zu %s setzen, da dieser auf\n"
-"keinen Branch zeigt."
+"konnte den Upstream von HEAD nicht auf %s setzen, wenn er auf keinen Zweig "
+"verweist"
#, c-format
msgid "no such branch '%s'"
@@ -3116,17 +3140,17 @@ msgstr ""
"zu viele Argumente angegeben, um Konfiguration zu Upstream-Branch zu "
"entfernen"
-msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
msgstr ""
-"Konnte Konfiguration zu Upstream-Branch von HEAD nicht entfernen, da dieser\n"
-"auf keinen Branch zeigt."
+"konnte den Upstream von HEAD nicht aufheben, wenn er nicht auf einen Zweig "
+"verweist"
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "Branch '%s' hat keinen Upstream-Branch gesetzt"
+msgid "branch '%s' has no upstream information"
+msgstr "Branch '%s' hat keine Upstream-Informationen"
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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 ""
"Die Optionen -a und -r bei 'git branch' können nicht mit einem Branchnamen "
@@ -3135,7 +3159,7 @@ msgstr ""
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
"Die '--set-upstream' Option wird nicht länger unterstützt.\n"
"Bitte benutzen Sie stattdessen '--track' oder '--set-upstream-to'."
@@ -3157,10 +3181,12 @@ msgid "not run from a git repository - no hooks to show\n"
msgstr "nicht in einem Git-Repository ausgeführt - keine Hooks zum Anzeigen\n"
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <Pfad>] [(-s | --suffix) <Format>]\n"
+"git bugreport [(-o | --output-directory) <Pfad>]\n"
+" [(-s | --suffix) <Format> | --no-suffix]\n"
" [--diagnose[=<Modus>]]"
msgid ""
@@ -3215,6 +3241,10 @@ msgid "specify a strftime format suffix for the filename(s)"
msgstr "ein Suffix im strftime-Format für den/die Dateinamen angeben"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "unbekanntes Argument `%s'"
+
+#, c-format
msgid "could not create leading directories for '%s'"
msgstr "konnte vorangehende Verzeichnisse für '%s' nicht erstellen"
@@ -3276,6 +3306,9 @@ msgstr "Um ein Paket zu erstellen wird ein Repository benötigt."
msgid "do not show bundle details"
msgstr "Keine Bundle-Details anzeigen"
+msgid "need a repository to verify a bundle"
+msgstr "um ein Paket zu überprüfen wird ein Repository benötigt"
+
#, c-format
msgid "%s is okay\n"
msgstr "%s ist in Ordnung\n"
@@ -3321,6 +3354,14 @@ msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <Objekt>"
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<Commit>:<Pfad|Commit-Referenz> | --path=<Pfad|Commit-"
+"Referenz> <Commit>]"
+
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -3331,14 +3372,6 @@ msgstr ""
" [--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"
-" [<Commit>:<Pfad|Commit-Referenz> | --path=<Pfad|Commit-"
-"Referenz> <Commit>]"
-
msgid "Check object existence or emit object contents"
msgstr "Überprüfen von Objektexistenz oder Ausgeben von Objekt-Inhalten"
@@ -3513,9 +3546,14 @@ msgstr "git check-mailmap [<Optionen>] <Kontakt>..."
msgid "also read contacts from stdin"
msgstr "ebenfalls Kontakte von der Standard-Eingabe lesen"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "konnte Kontakt nicht parsen: %s"
+msgid "read additional mailmap entries from file"
+msgstr "zusätzliche mailmap-Einträge aus Datei lesen"
+
+msgid "blob"
+msgstr "Blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "zusätzliche mailmap-Einträge aus Blob lesen"
msgid "no contacts specified"
msgstr "keine Kontakte angegeben"
@@ -3641,9 +3679,19 @@ msgid "'%s' or '%s' cannot be used with %s"
msgstr "'%s' oder '%s' kann nicht mit %s verwendet werden"
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr ""
+"'%s', '%s' oder '%s' können beim Auschecken aus einem Verzeichnis nicht "
+"verwendet werden"
+
+#, c-format
msgid "path '%s' is unmerged"
msgstr "Pfad '%s' ist nicht zusammengeführt"
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "konnte \"Tree\"-Objekt (%s) nicht lesen"
+
msgid "you need to resolve your current index first"
msgstr "Sie müssen zuerst die Konflikte in Ihrem aktuellen Index auflösen."
@@ -3868,6 +3916,10 @@ msgid "'%s' cannot be used with switching branches"
msgstr "'%s' kann nicht beim Wechseln von Branches verwendet werden"
#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' benötigt die Pfade zum Auschecken"
+
+#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s' kann nicht mit '%s' verwendet werden"
@@ -3882,6 +3934,10 @@ msgstr "Kann Branch nicht zu Nicht-Commit '%s' wechseln"
msgid "missing branch or commit argument"
msgstr "Branch- oder Commit-Argument fehlt"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "unbekannter Konfliktstil '%s'"
+
msgid "perform a 3-way merge with the new branch"
msgstr "einen 3-Wege-Merge mit dem neuen Branch ausführen"
@@ -3900,8 +3956,8 @@ msgstr "Auschecken erzwingen (verwirft lokale Änderungen)"
msgid "new-branch"
msgstr "neuer Branch"
-msgid "new unparented branch"
-msgstr "neuer Branch ohne Eltern-Commit"
+msgid "new unborn branch"
+msgstr "neuer ungeborener Branch"
msgid "update ignored files (default)"
msgstr "ignorierte Dateien aktualisieren (Standard)"
@@ -4141,22 +4197,10 @@ msgstr "auch ignorierte Dateien löschen"
msgid "remove only ignored files"
msgstr "nur ignorierte Dateien löschen"
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce auf \"true\" gesetzt und weder -i, -n noch -f gegeben; "
-"\"clean\" verweigert"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"clean.requireForce standardmäßig auf \"true\" gesetzt und weder -i, -n noch -"
-"f gegeben; \"clean\" verweigert"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x und -X können nicht gemeinsam verwendet werden"
+"clean.requireForce ist 'true' und -f ist nicht angegeben: clean wird "
+"verweigert"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<Optionen>] [--] <Repository> [<Verzeichnis>]"
@@ -4170,8 +4214,8 @@ msgstr "kein Auschecken"
msgid "create a bare repository"
msgstr "ein Bare-Repository erstellen"
-msgid "create a mirror repository (implies bare)"
-msgstr "ein Spiegelarchiv erstellen (impliziert bare)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "ein Spiegel-Repository erstellen (impliziert --bare)"
msgid "to clone from a local repository"
msgstr "von einem lokalen Repository klonen"
@@ -4251,6 +4295,9 @@ msgstr ".git-Verzeichnis"
msgid "separate git dir from working tree"
msgstr "Git-Verzeichnis vom Arbeitsverzeichnis separieren"
+msgid "specify the reference format to use"
+msgstr "das zu verwendende Referenzformat angeben"
+
msgid "key=value"
msgstr "Schlüssel=Wert"
@@ -4313,6 +4360,14 @@ msgid "failed to unlink '%s'"
msgstr "Konnte '%s' nicht entfernen."
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "Hardlink bei '%s' kann nicht geprüft werden"
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "Hardlink unterscheidet sich von der Quelle bei '%s'"
+
+#, c-format
msgid "failed to create link '%s'"
msgstr "Konnte Verweis '%s' nicht erstellen"
@@ -4374,12 +4429,9 @@ msgstr "Zu viele Argumente."
msgid "You must specify a repository to clone."
msgstr "Sie müssen ein Repository zum Klonen angeben."
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr ""
-"--bundle-uri ist inkompatibel mit --depth, --shallow-since und --shallow-"
-"exclude"
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "unbekanntes Speicherformat für Referenzen '%s'"
#, c-format
msgid "repository '%s' does not exist"
@@ -4506,6 +4558,10 @@ msgstr "Abstand zum rechten Rand auffüllen"
msgid "padding space between columns"
msgstr "Abstand zwischen Spalten auffüllen"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s muss nicht-negativ sein"
+
msgid "--command must be the first argument"
msgstr "--command muss an erster Stelle stehen"
@@ -4521,7 +4577,7 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <Verzeichnis>] [--append]\n"
" [--split[=<Strategie>]] [--reachable | --stdin-packs "
@@ -4545,6 +4601,10 @@ msgid "Could not open commit-graph '%s'"
msgstr "Konnte Commit-Graph '%s' nicht öffnen."
#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "konnte die Commit-Graph-Kette '%s' nicht öffnen"
+
+#, c-format
msgid "unrecognized --split argument, %s"
msgstr "nicht erkanntes --split Argument, %s"
@@ -4655,7 +4715,7 @@ msgstr "git commit-tree: Fehler beim Lesen"
msgid ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -4665,7 +4725,7 @@ msgid ""
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<Modus>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <Commit> | --fixup [(amend|"
-"reword):]<Commit>)]\n"
+"reword):]<Commit>]\n"
" [-F <Datei> | -m <Nachricht>] [--reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--author=<Autor>]\n"
" [--date=<Datum>] [--cleanup=<Modus>] [--[no-]status]\n"
@@ -4747,9 +4807,6 @@ msgstr "Konnte temporären Index nicht aktualisieren."
msgid "Failed to update main cache tree"
msgstr "Konnte Haupt-Cache-Verzeichnis nicht aktualisieren"
-msgid "unable to write new_index file"
-msgstr "Konnte new_index Datei nicht schreiben"
-
msgid "cannot do a partial commit during a merge."
msgstr "Kann keinen Teil-Commit durchführen, während ein Merge im Gange ist."
@@ -4823,38 +4880,38 @@ msgstr "Konnte Commit-Vorlage nicht schreiben"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,\n"
-"die mit '%c' beginnen, werden ignoriert.\n"
+"die mit '%s' beginnen, werden ignoriert.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,\n"
-"die mit '%c' beginnen, werden ignoriert, und eine leere Beschreibung\n"
+"die mit '%s' beginnen, werden ignoriert, und eine leere Beschreibung\n"
"bricht den Commit ab.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen,\n"
-"die mit '%c' beginnen, werden beibehalten; wenn Sie möchten, können Sie\n"
+"die mit '%s' beginnen, werden beibehalten; wenn Sie möchten, können Sie\n"
"diese entfernen.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Bitte geben Sie eine Commit-Beschreibung für Ihre Änderungen ein. Zeilen, "
"die\n"
-"mit '%c' beginnen, werden beibehalten; wenn Sie möchten, können Sie diese "
+"mit '%s' beginnen, werden beibehalten; wenn Sie möchten, können Sie diese "
"entfernen.\n"
"Eine leere Beschreibung bricht den Commit ab.\n"
@@ -5159,23 +5216,68 @@ msgstr "Commit aufgrund leerer Commit-Beschreibung abgebrochen.\n"
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"Das Repository wurde aktualisiert, aber die \"new_index\"-Datei\n"
+"Das Repository wurde aktualisiert, aber die neue Index-Datei\n"
"konnte nicht geschrieben werden. Prüfen Sie, dass Ihre Festplatte nicht\n"
"voll und Ihr Kontingent nicht aufgebraucht ist und führen Sie\n"
-"anschließend \"git restore HEAD --staged :/\" zur Wiederherstellung aus."
+"anschließend \"git restore --staged :/\" zur Wiederherstellung aus."
-msgid "git config [<options>]"
-msgstr "git config [<Optionen>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<Datei-Option>] [<Anzeige-Option>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "nicht erkanntes --type Argument, %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<Datei-Option>] [<Anzeige-Option>] [--includes] [--all] [--"
+"regexp] [--value=<Wert>] [--fixed-value] [--default=<Standardwert>] "
+"<Name>"
-msgid "only one type at a time"
-msgstr "nur ein Typ erlaubt"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<Datei-Option>] [--type=<Typ>] [--all] [--value=<Wert>] [--"
+"fixed-value] <Name> <Wert>"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<Datei-Option>] [--all] [--value=<Wert>] [--fixed-value] "
+"<Name> <Wert>"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<Datei-Option>] <alter-Name> <neuer-Name>"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<Datei-Option>] <Name>"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<Datei-Option>]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr ""
+"git config [<Datei-Option>] --get-colorbool <Name> [<Standard-Ausgabe-ist-"
+"Terminal>]"
+
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<Datei-Option>] [<Anzeige-Option>] [--includes] [--all] [--"
+"regexp=<Regex>] [--value=<Wert>] [--fixed-value] [--default=<Standardwert>] "
+"<Name>"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<Datei-Option>] [--type=<Typ>] [--comment=<Nachricht>] [--"
+"all] [--value=<Wert>] [--fixed-value] <Name> <Wert>"
msgid "Config file location"
msgstr "Ort der Konfigurationsdatei"
@@ -5201,55 +5303,6 @@ msgstr "Blob-Id"
msgid "read config from given blob object"
msgstr "Konfiguration von angegebenem Blob-Objekt lesen"
-msgid "Action"
-msgstr "Aktion"
-
-msgid "get value: name [value-pattern]"
-msgstr "Wert zurückgeben: Name [Wert-Muster]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "alle Werte zurückgeben: Schlüssel [Wert-Muster]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "Werte für den regulären Ausdruck zurückgeben: Name-Regex [Wert-Muster]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "Wert spezifisch für eine URL zurückgeben: section[.var] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "alle passenden Variablen ersetzen: Name Wert [Wert-Muster] "
-
-msgid "add a new variable: name value"
-msgstr "neue Variable hinzufügen: Name Wert"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "eine Variable entfernen: Name [Wert-Muster]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "alle Übereinstimmungen entfernen: Name [Wert-Muster]"
-
-msgid "rename section: old-name new-name"
-msgstr "eine Sektion umbenennen: alter-Name neuer-Name"
-
-msgid "remove a section: name"
-msgstr "eine Sektion entfernen: Name"
-
-msgid "list all"
-msgstr "alles auflisten"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr ""
-"nutze String-Gleichheit beim Vergleich von Werten mit dem 'Wert-Muster'"
-
-msgid "open an editor"
-msgstr "einen Editor öffnen"
-
-msgid "find the color configured: slot [default]"
-msgstr "die konfigurierte Farbe finden: Slot [Standard]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "die Farbeinstellung finden: Slot [Standard-Ausgabe-ist-Terminal]"
-
msgid "Type"
msgstr "Typ"
@@ -5277,8 +5330,8 @@ msgstr "Wert ist ein Pfad (Datei oder Verzeichnisname)"
msgid "value is an expiry date"
msgstr "Wert ist ein Verfallsdatum"
-msgid "Other"
-msgstr "Sonstiges"
+msgid "Display options"
+msgstr "Anzeigeoptionen"
msgid "terminate values with NUL byte"
msgstr "schließt Werte mit NUL-Byte ab"
@@ -5286,9 +5339,6 @@ msgstr "schließt Werte mit NUL-Byte ab"
msgid "show variable names only"
msgstr "nur Variablennamen anzeigen"
-msgid "respect include directives on lookup"
-msgstr "beachtet \"include\"-Direktiven beim Nachschlagen"
-
msgid "show origin of config (file, standard input, blob, command line)"
msgstr ""
"Ursprung der Konfiguration anzeigen (Datei, Standard-Eingabe, Blob, "
@@ -5299,11 +5349,15 @@ msgstr ""
"Zeige Geltungsbereich der Konfiguration (Arbeitsverzeichnis, lokal, global, "
"systemweit, Befehl)"
-msgid "value"
-msgstr "Wert"
+msgid "show config keys in addition to their values"
+msgstr "Konfigurationsschlüssel zusätzlich zu dessen Werten anzeigen"
-msgid "with --get, use default value when missing entry"
-msgstr "mit --get, benutze den Standardwert, wenn der Eintrag fehlt"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "nicht erkanntes --type Argument, %s"
+
+msgid "only one type at a time"
+msgstr "nur ein Typ erlaubt"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5381,43 +5435,73 @@ msgstr ""
"lesen Sie die Sektion \"CONFIGURATION FILE\" in \"git help worktree\" für "
"Details"
-msgid "--get-color and variable type are incoherent"
-msgstr "Angabe von --get-color und Variablentyp sind ungültig."
+msgid "Other"
+msgstr "Sonstiges"
-msgid "only one action at a time"
-msgstr "Nur eine Aktion erlaubt."
+msgid "respect include directives on lookup"
+msgstr "beachtet \"include\"-Direktiven beim Nachschlagen"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only ist nur anwendbar auf --list oder --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "Konnte Konfigurationsdatei '%s' nicht lesen."
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr ""
-"--show-origin ist nur anwendbar auf --get, --get-all, --get-regexp und --list"
+msgid "error processing config file(s)"
+msgstr "Fehler beim Verarbeiten der Konfigurationsdatei(en)."
-msgid "--default is only applicable to --get"
-msgstr "--default ist nur anwendbar auf --get"
+msgid "Filter options"
+msgstr "Filter-Optionen"
+
+msgid "return all values for multi-valued config options"
+msgstr "alle Werte für mehrwertige Konfigurationsoptionen zurückgeben"
+
+msgid "interpret the name as a regular expression"
+msgstr "den Namen als regulären Ausdruck interpretieren"
+
+msgid "show config with values matching the pattern"
+msgstr "Anzeige von Konfiguration mit Werten, die dem Muster entsprechen"
+
+msgid "use string equality when comparing values to value pattern"
+msgstr "String-Gleichheit beim Vergleich von Werten mit Wertmustern verwenden"
+
+msgid "URL"
+msgstr "URL"
+
+msgid "show config matching the given URL"
+msgstr "Konfiguration für die angegebene URL anzeigen"
+
+msgid "value"
+msgstr "Wert"
+
+msgid "use default value when missing entry"
+msgstr "Standardwert verwenden, wenn Eintrag fehlt"
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value wird nur zusammen mit 'Wert-Muster' angewendet"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "Konnte Konfigurationsdatei '%s' nicht lesen."
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= kann nicht mit --all oder --url= verwendet werden"
-msgid "error processing config file(s)"
-msgstr "Fehler beim Verarbeiten der Konfigurationsdatei(en)."
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= kann nicht mit --all, --regexp oder --value verwendet werden"
-msgid "editing stdin is not supported"
-msgstr "Das Bearbeiten der Standard-Eingabe wird nicht unterstützt."
+msgid "Filter"
+msgstr "Filter"
-msgid "editing blobs is not supported"
-msgstr "Das Bearbeiten von Blobs wird nicht unterstützt."
+msgid "replace multi-valued config option with new value"
+msgstr "mehrwertige Konfigurationsoption durch einen neuen Wert ersetzen"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr ""
+"menschenlesbare Kommentarzeichenfolge (# wird bei Bedarf vorangestellt)"
+
+msgid "add a new line without altering any existing values"
+msgstr "eine neue Zeile hinzufügen, ohne bestehende Werte zu ändern"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value gilt nur mit --value=<pattern>"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append kann nicht mit --value=<pattern> verwendet werden"
#, c-format
msgid ""
@@ -5432,6 +5516,86 @@ msgstr ""
msgid "no such section: %s"
msgstr "Sektion nicht gefunden: %s"
+msgid "editing stdin is not supported"
+msgstr "Das Bearbeiten der Standard-Eingabe wird nicht unterstützt."
+
+msgid "editing blobs is not supported"
+msgstr "Das Bearbeiten von Blobs wird nicht unterstützt."
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
+
+msgid "Action"
+msgstr "Aktion"
+
+msgid "get value: name [<value-pattern>]"
+msgstr "Wert zurückgeben: Name [<Wert-Muster>]"
+
+msgid "get all values: key [<value-pattern>]"
+msgstr "alle Werte zurückgeben: Schlüssel [<Wert-Muster>]"
+
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "Werte für den regulären Ausdruck zurückgeben: Name-Regex <Wert-Muster>"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "Wert spezifisch für eine URL zurückgeben: section[.var] URL"
+
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "alle passenden Variablen ersetzen: Name Wert [<Wert-Muster>]"
+
+msgid "add a new variable: name value"
+msgstr "neue Variable hinzufügen: Name Wert"
+
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "eine Variable entfernen: Name [<Wert-Muster>]"
+
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "alle Treffer entfernen: Name [<Wert-Muster>]"
+
+msgid "rename section: old-name new-name"
+msgstr "eine Sektion umbenennen: alter-Name neuer-Name"
+
+msgid "remove a section: name"
+msgstr "eine Sektion entfernen: Name"
+
+msgid "list all"
+msgstr "alles auflisten"
+
+msgid "open an editor"
+msgstr "einen Editor öffnen"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "die konfigurierte Farbe finden: Slot [<Standard>]"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "die Farbeinstellung finden: Slot [Standard-Ausgabe-ist-Terminal]"
+
+msgid "with --get, use default value when missing entry"
+msgstr "mit --get, benutze den Standardwert, wenn der Eintrag fehlt"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "Angabe von --get-color und Variablentyp sind ungültig."
+
+msgid "no action specified"
+msgstr "keine Aktion angegeben"
+
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only ist nur anwendbar auf --list oder --get-regexp"
+
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin ist nur anwendbar auf --get, --get-all, --get-regexp und --list"
+
+msgid "--default is only applicable to --get"
+msgstr "--default ist nur anwendbar auf --get"
+
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr ""
+"--comment darf nur für die Operationen add/set/replace verwendet werden"
+
msgid "print sizes in human readable format"
msgstr "gibt Größenangaben in menschenlesbaren Format aus"
@@ -5927,8 +6091,8 @@ msgstr ""
"zu umgehen.\n"
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s hat nicht alle erforderlichen Objekte gesendet"
#, c-format
msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -5967,8 +6131,8 @@ msgid "option \"%s\" value \"%s\" is not valid for %s"
msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s"
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "Option \"%s\" wird ignoriert für %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "Option \"%s\" wird für %s ignoriert"
#, c-format
msgid "%s is not a valid object"
@@ -6270,6 +6434,9 @@ msgstr "nur Referenzen ausgeben, die diesen Commit nicht enthalten"
msgid "read reference patterns from stdin"
msgstr "Referenzmuster von Standard-Eingabe lesen"
+msgid "also include HEAD ref and pseudorefs"
+msgstr "auch die Referenz HEAD und Pseudoreferenzen einschließen"
+
msgid "unknown arguments supplied with --stdin"
msgstr "unbekannte Argumente mit --stdin geliefert"
@@ -6282,6 +6449,9 @@ msgstr "Konfiguration"
msgid "config key storing a list of repository paths"
msgstr "Konfigurationsschlüssel für eine Liste von Repository-Pfaden"
+msgid "keep going even if command fails in a repository"
+msgstr "weiterarbeiten, auch wenn der Befehl in einem Repository fehlschlägt"
+
msgid "missing --config=<config>"
msgstr "Option --config=<Konfiguration> fehlt"
@@ -6643,12 +6813,18 @@ msgstr "unreferenzierte Objekte entfernen"
msgid "pack unreferenced objects separately"
msgstr "unreferenzierte Objekte separat verpacken"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "mit --cruft, die Größe neuer Cruft-Pakete begrenzen"
+
msgid "be more thorough (increased runtime)"
msgstr "mehr Gründlichkeit (erhöht Laufzeit)"
msgid "enable auto-gc mode"
msgstr "\"auto-gc\" Modus aktivieren"
+msgid "perform garbage collection in the background"
+msgstr "Garbage Collection im Hintergrund ausführen"
+
msgid "force running gc even if there may be another gc running"
msgstr ""
"Ausführung von \"git gc\" erzwingen, selbst wenn ein anderes\n"
@@ -6752,6 +6928,9 @@ msgstr "Aufgabe '%s' kann nicht mehrfach ausgewählt werden"
msgid "run tasks based on the state of the repository"
msgstr "Aufgaben abhängig vom Zustand des Repositories ausführen"
+msgid "perform maintenance in the background"
+msgstr "Wartung im Hintergrund ausführen"
+
msgid "frequency"
msgstr "Häufigkeit"
@@ -6826,12 +7005,6 @@ msgstr ""
msgid "'crontab' died"
msgstr "'crontab' abgebrochen"
-msgid "failed to start systemctl"
-msgstr "Fehler beim Starten von systemctl"
-
-msgid "failed to run systemctl"
-msgstr "Fehler beim Ausführen von systemctl"
-
#, c-format
msgid "failed to delete '%s'"
msgstr "Fehler beim Löschen von '%s'"
@@ -6840,6 +7013,12 @@ msgstr "Fehler beim Löschen von '%s'"
msgid "failed to flush '%s'"
msgstr "Flush bei '%s' fehlgeschlagen."
+msgid "failed to start systemctl"
+msgstr "Fehler beim Starten von systemctl"
+
+msgid "failed to run systemctl"
+msgstr "Fehler beim Ausführen von systemctl"
+
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "nicht erkanntes --scheduler Argument '%s'"
@@ -6863,6 +7042,9 @@ msgstr "Scheduler"
msgid "scheduler to trigger git maintenance run"
msgstr "Scheduler, um \"git maintenance run\" auzuführen"
+msgid "failed to set up maintenance schedule"
+msgstr "Fehler beim Einrichten des Wartungsplans"
+
msgid "failed to add repo to global config"
msgstr "Repository konnte nicht zur globalen Konfiguration hinzugefügt werden"
@@ -6889,7 +7071,7 @@ msgid "no threads support, ignoring %s"
msgstr "keine Unterstützung von Threads, '%s' wird ignoriert"
#, c-format
-msgid "unable to read tree (%s)"
+msgid "unable to read tree %s"
msgstr "konnte \"Tree\"-Objekt (%s) nicht lesen"
#, c-format
@@ -6936,8 +7118,8 @@ msgstr "binäre Dateien mit \"textconv\"-Filtern verarbeiten"
msgid "search in subdirectories (default)"
msgstr "in Unterverzeichnissen suchen (Standard)"
-msgid "descend at most <depth> levels"
-msgstr "höchstens <Tiefe> Ebenen durchlaufen"
+msgid "descend at most <n> levels"
+msgstr "höchstens <n> Ebenen absteigen"
msgid "use extended POSIX regular expressions"
msgstr "erweiterte reguläre Ausdrücke aus POSIX verwenden"
@@ -7314,10 +7496,6 @@ msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !"
#, c-format
-msgid "unable to read %s"
-msgstr "kann %s nicht lesen"
-
-#, c-format
msgid "cannot read existing object info %s"
msgstr "Kann existierende Informationen zu Objekt %s nicht lesen."
@@ -7457,11 +7635,13 @@ msgstr "fsck Fehler beim Packen von Objekten"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
"git init [-q | --quiet] [--bare] [--template=<Vorlagenverzeichnis>]\n"
" [--separate-git-dir <Git-Verzeichnis>] [--object-format=<Format>]\n"
+" [--ref-format=<Format>]\n"
" [-b <Branchname> | --initial-branch=<Branchname>]\n"
" [--shared[=<Berechtigungen>]] [<Verzeichnis>]"
@@ -7505,19 +7685,49 @@ msgstr "--separate-git-dir nicht kompatibel mit Bare-Repository"
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <Token>[(=|:)<Wert>])...]\n"
+" [(--trailer (<Schlüssel>|<Schlüssel-Alias>)"
+"[(=|:)<Wert>])...]\n"
" [--parse] [<Datei>...]"
+#, c-format
+msgid "could not stat %s"
+msgstr "Konnte '%s' nicht lesen"
+
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "Datei '%s' ist keine reguläre Datei"
+
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "Datei %s ist vom Benutzer nicht beschreibbar."
+
+msgid "could not open temporary file"
+msgstr "konnte temporäre Datei '%s' nicht öffnen"
+
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "Konnte Eingabe-Datei '%s' nicht lesen"
+
+msgid "could not read from stdin"
+msgstr "konnte nicht von der Standard-Eingabe lesen"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "konnte temporäre Datei nicht zu %s umbenennen"
+
msgid "edit files in place"
msgstr "vorhandene Dateien direkt bearbeiten"
msgid "trim empty trailers"
msgstr "kürzt leere Anhänge"
+msgid "placement"
+msgstr "Platzierung"
+
msgid "where to place the new trailer"
msgstr "wo der neue Anhang platziert wird"
@@ -7530,17 +7740,17 @@ msgstr "Aktion, wenn Anhang fehlt"
msgid "output only the trailers"
msgstr "nur Anhänge ausgeben"
-msgid "do not apply config rules"
-msgstr "Regeln aus Konfiguration nicht anwenden"
+msgid "do not apply trailer.* configuration variables"
+msgstr "trailer.* Konfigurationsvariablen nicht anwenden"
-msgid "join whitespace-continued values"
-msgstr "durch Leerzeichen fortgesetzte Werte verbinden"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "mehrzeilige Trailer als einzeilige Werte umformatieren"
-msgid "set parsing options"
-msgstr "Optionen für das Parsen setzen"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "Alias für --only-trailers --only-input --unfold"
-msgid "do not treat --- specially"
-msgstr "--- nicht speziell behandeln"
+msgid "do not treat \"---\" as the end of input"
+msgstr "\"---\" nicht als Ende der Eingabe behandeln"
msgid "trailer(s) to add"
msgstr "Anhang/Anhänge hinzufügen"
@@ -7597,9 +7807,6 @@ msgstr "-L<Bereich>:<Datei> kann nicht mit Pfadspezifikation verwendet werden"
msgid "Final output: %d %s\n"
msgstr "letzte Ausgabe: %d %s\n"
-msgid "unable to create temporary object directory"
-msgstr "konnte temporäres Objektverzeichnis nicht erstellen"
-
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: ungültige Datei"
@@ -7630,6 +7837,10 @@ msgstr "Brauche genau einen Commit-Bereich."
msgid "not a range"
msgstr "Kein Commit-Bereich."
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "konnte Datei mit Branchbeschreibung '%s' nicht lesen"
+
msgid "cover letter needs email format"
msgstr "Anschreiben benötigt E-Mail-Format"
@@ -7719,8 +7930,11 @@ msgstr "die Serie als n-te Fassung kennzeichnen"
msgid "max length of output filename"
msgstr "maximale Länge des Dateinamens für die Ausgabe"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "[RFC PATCH] statt [PATCH] verwenden"
+msgid "rfc"
+msgstr "rfc"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "<rfc> (standardmäßig 'RFC') vor 'PATCH' hinzufügen"
msgid "cover-from-description-mode"
msgstr "Modus für Erstellung des Deckblattes aus der Beschreibung"
@@ -7729,6 +7943,9 @@ msgid "generate parts of a cover letter based on a branch's description"
msgstr ""
"Erzeuge Teile des Deckblattes basierend auf der Beschreibung des Branches"
+msgid "use branch description from file"
+msgstr "Branchbeschreibung aus Datei verwenden"
+
msgid "use [<prefix>] instead of [PATCH]"
msgstr "nutze [<Präfix>] statt [PATCH]"
@@ -7896,18 +8113,6 @@ msgstr ""
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"
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "ungültiges ls-files-Format: Element '%s' endet nicht auf ')'"
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "ungültiges ls-files-Format: %%%.*s"
-
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<Optionen>] [<Datei>...]"
@@ -8005,11 +8210,11 @@ msgstr ""
"verwendet werden"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<Programm>]\n"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<Programm>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<Schlüssel>]\n"
" [--symref] [<Repository> [<Muster>...]]"
@@ -8025,8 +8230,11 @@ msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite"
msgid "limit to tags"
msgstr "auf Tags einschränken"
-msgid "limit to heads"
-msgstr "auf Branches einschränken"
+msgid "limit to branches"
+msgstr "Beschränkung auf Branches"
+
+msgid "deprecated synonym for --branches"
+msgstr "veraltetes Synonym für --branches"
msgid "do not show peeled tags"
msgstr "keine Tags anzeigen, die andere Tags enthalten"
@@ -8045,18 +8253,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 "bad ls-tree format: element '%s' does not start with '('"
-msgstr "ungültiges ls-tree-Format: Element '%s' fängt nicht mit '(' an"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "ungültiges ls-tree-Format: Element '%s' endet nicht mit ')'"
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "ungültiges ls-tree-Format: %%%.*s"
-
msgid "only show trees"
msgstr "nur Verzeichnisse anzeigen"
@@ -8171,23 +8367,30 @@ msgstr ""
"git merge-file [<Optionen>] [-L <Name1> [-L <orig> [-L <Name2>]]] <Datei1> "
"<orig-Datei> <Datei2>"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"Option diff-algorithm akzeptiert: \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+
msgid "send results to standard output"
msgstr "Ergebnisse zur Standard-Ausgabe senden"
+msgid "use object IDs instead of filenames"
+msgstr "Objekt-IDs anstelle von Dateinamen verwenden"
+
msgid "use a diff3 based merge"
msgstr "einen diff3 basierten Merge verwenden"
msgid "use a zealous diff3 based merge"
msgstr "einen eifrigen diff3 basierten Merge verwenden"
-msgid "for conflicts, use our version"
-msgstr "bei Konflikten unsere Variante verwenden"
-
-msgid "for conflicts, use their version"
-msgstr "bei Konflikten ihre Variante verwenden"
+msgid "<algorithm>"
+msgstr "<Algorithmus>"
-msgid "for conflicts, use a union version"
-msgstr "bei Konflikten eine gemeinsame Variante verwenden"
+msgid "choose a diff algorithm"
+msgstr "einen Algorithmus für Änderungen wählen"
msgid "for conflicts, use this marker size"
msgstr "bei Konflikten diese Kennzeichnungslänge verwenden"
@@ -8199,6 +8402,13 @@ msgid "set labels for file1/orig-file/file2"
msgstr "Beschriftung für Datei1/orig-Datei/Datei2 setzen"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "Objekt '%s' existiert nicht"
+
+msgid "Could not write object file"
+msgstr "konnte Objektdatei nicht schreiben"
+
+#, c-format
msgid "unknown option %s"
msgstr "unbekannte Option: %s"
@@ -8223,6 +8433,10 @@ msgstr "Konnte Referenz '%s' nicht auflösen"
msgid "Merging %s with %s\n"
msgstr "Führe %s mit %s zusammen\n"
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "'%s' konnte nicht als Tree geparst werden"
+
msgid "not something we can merge"
msgstr "nichts was wir zusammenführen können"
@@ -8260,11 +8474,18 @@ msgstr "mehrere Merges durchführen, eine pro Eingabezeile"
msgid "specify a merge-base for the merge"
msgstr "Merge-Basis für den Merge angeben"
+msgid "option=value"
+msgstr "Option=Wert"
+
+msgid "option for selected merge strategy"
+msgstr "Option für ausgewählte Merge-Strategie"
+
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge ist mit allen anderen Optionen inkompatibel"
-msgid "--merge-base is incompatible with --stdin"
-msgstr "--merge-base ist inkompatibel mit --stdin"
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "unbekannte Strategie-Option: -X%s"
#, c-format
msgid "malformed input line: '%s'."
@@ -8335,12 +8556,6 @@ msgstr "Strategie"
msgid "merge strategy to use"
msgstr "zu verwendende Merge-Strategie"
-msgid "option=value"
-msgstr "Option=Wert"
-
-msgid "option for selected merge strategy"
-msgstr "Option für ausgewählte Merge-Strategie"
-
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
"Commit-Beschreibung zusammenführen (für einen Merge, der kein Vorspulen war)"
@@ -8402,10 +8617,6 @@ msgid "Not handling anything other than two heads merge."
msgstr "Es wird nur der Merge von zwei Branches behandelt."
#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "unbekannte Strategie-Option: -X%s"
-
-#, c-format
msgid "unable to write %s"
msgstr "konnte %s nicht schreiben"
@@ -8434,10 +8645,10 @@ msgstr "Eine leere Commit-Beschreibung bricht den Commit ab.\n"
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Zeilen, die mit '%c' beginnen, werden ignoriert,\n"
+"Zeilen, die mit '%s' beginnen, werden ignoriert,\n"
"und eine leere Beschreibung bricht den Commit ab.\n"
msgid "Empty commit message."
@@ -8602,9 +8813,6 @@ msgstr "konnte getaggtes Objekt '%s' nicht lesen"
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "Objekt '%s' als '%s' getaggt, aber ist ein '%s' Typ"
-msgid "could not read from stdin"
-msgstr "konnte nicht von der Standard-Eingabe lesen"
-
msgid "tag on stdin did not pass our strict fsck check"
msgstr ""
"Tag von der Standardeingabe für unsere strenge Überprüfung bei fsck ungültig"
@@ -8657,6 +8865,9 @@ msgstr ""
msgid "write multi-pack bitmap"
msgstr "schreibe Multi-Pack-Bitmap"
+msgid "write a new incremental MIDX"
+msgstr "ein neues inkrementelles MIDX schreiben"
+
msgid "write multi-pack index containing only given indexes"
msgstr "Multi-Pack-Index schreiben, der nur die gegebenen Indexe enthält"
@@ -8710,8 +8921,8 @@ msgstr "Ziel existiert bereits"
msgid "can not move directory into itself"
msgstr "kann Verzeichnis nicht in sich selbst verschieben"
-msgid "cannot move directory over file"
-msgstr "kann Verzeichnis nicht über Datei verschieben"
+msgid "destination already exists"
+msgstr "Ziel existiert bereits"
msgid "source directory is empty"
msgstr "Quellverzeichnis ist leer"
@@ -8871,10 +9082,6 @@ msgstr "git notes prune [<Optionen>]"
msgid "Write/edit the notes for the following object:"
msgstr "Schreiben/Bearbeiten der Notizen für das folgende Objekt:"
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "konnte 'show' für Objekt '%s' nicht starten"
-
msgid "could not read 'show' output"
msgstr "Konnte Ausgabe von 'show' nicht lesen."
@@ -9231,6 +9438,10 @@ msgid "inconsistency with delta count"
msgstr "Inkonsistenz mit der Anzahl von Deltas"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "ungültiger Wert für pack.allowPackReuse: '%s'"
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -9480,9 +9691,6 @@ msgid "--thin cannot be used to build an indexable pack"
msgstr ""
"--thin kann nicht benutzt werden, um ein indizierbares Paket zu erstellen."
-msgid "cannot use --filter without --stdout"
-msgstr "Kann --filter nicht ohne --stdout benutzen."
-
msgid "cannot use --filter with --stdin-packs"
msgstr "kann --filter nicht mit --stdin-packs benutzen"
@@ -9496,19 +9704,16 @@ msgstr "interne Commit-Liste kann nicht gemeinsam mit --cruft verwendet werden"
msgid "cannot use --stdin-packs with --cruft"
msgstr "kann --stdin-packs nicht mit --cruft benutzen"
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "kann --max-pack-size nicht mit --cruft benutzen"
-
msgid "Enumerating objects"
msgstr "Objekte aufzählen"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Gesamt %<PRIu32> (Delta %<PRIu32>), Wiederverwendet %<PRIu32> (Delta "
-"%<PRIu32>), Pack wiederverwendet %<PRIu32>"
+"%<PRIu32>), Paket wiederverwendet %<PRIu32> (von %<PRIuMAX>)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9528,10 +9733,11 @@ 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 "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <Muster>] [--exclude <Muster>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <Muster>] [--exclude "
+"<Muster>]"
msgid "pack everything"
msgstr "alles packen"
@@ -9539,6 +9745,9 @@ msgstr "alles packen"
msgid "prune loose refs (default)"
msgstr "lose Referenzen entfernen (Standard)"
+msgid "auto-pack refs as needed"
+msgstr "auto-pack-Referenzen nach Bedarf"
+
msgid "references to include"
msgstr "einzubeziehende Referenzen"
@@ -9775,7 +9984,7 @@ msgid "git push [<options>] [<repository> [<refspec>...]]"
msgstr "git push [<Optionen>] [<Repository> [<Refspec>...]]"
msgid "tag shorthand without <tag>"
-msgstr "Kurzschrift für Tag ohne <Tag>"
+msgstr "Kurzschrift für das Tag ohne <Tag>"
msgid "--delete only accepts plain target ref names"
msgstr "--delete akzeptiert nur reine Referenznamen als Ziel"
@@ -9893,9 +10102,9 @@ msgstr ""
"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."
+"Siehe auch den Abschnitt 'Note about fast-forwards' in 'git push --help' "
+"für\n"
+"weitere Informationen."
msgid ""
"Updates were rejected because a pushed branch tip is behind its remote\n"
@@ -9907,9 +10116,9 @@ msgstr ""
"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."
+"Siehe auch den Abschnitt 'Note about fast-forwards' in 'git push --help' "
+"für\n"
+"weitere Informationen."
msgid ""
"Updates were rejected because the remote contains work that you do not\n"
@@ -9926,9 +10135,9 @@ msgstr ""
"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."
+"Siehe auch den Abschnitt 'Note about fast-forwards' in 'git push --help' "
+"für\n"
+"weitere Informationen."
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
@@ -10230,21 +10439,6 @@ msgstr "Ignoriere ungültiges allow_rerere_autoupdate: '%s'"
msgid "could not remove '%s'"
msgstr "Konnte '%s' nicht löschen"
-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 ""
-"Lösen Sie alle Konflikte manuell auf, markieren Sie diese mit\n"
-"\"git add/rm <konfliktbehaftete_Dateien>\" und führen Sie dann\n"
-"\"git rebase --continue\" aus.\n"
-"Sie können auch stattdessen diesen Commit auslassen, indem\n"
-"Sie \"git rebase --skip\" ausführen.\n"
-"Um abzubrechen und zurück zum Zustand vor \"git rebase\" zu gelangen,\n"
-"führen Sie \"git rebase --abort\" aus."
-
#, c-format
msgid ""
"\n"
@@ -10277,13 +10471,16 @@ msgstr ""
"Optionen für \"am\" und Optionen für \"merge\" können nicht gemeinsam "
"verwendet werden"
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask ist veraltet; verwenden Sie stattdessen '--empty=stop'."
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
"nicht erkannter leerer Typ '%s'; gültige Werte sind \"drop\", \"keep\", und "
-"\"ask\"."
+"\"stop\"."
msgid ""
"--rebase-merges with an empty string argument is deprecated and will stop "
@@ -10471,8 +10668,8 @@ msgstr ""
"'preserve' gesetzt, was nicht länger unterstützt wird; nutzen Sie\n"
"stattdessen 'merges'"
-msgid "No rebase in progress?"
-msgstr "Kein Rebase im Gange?"
+msgid "no rebase in progress"
+msgstr "kein Rebase im Gange"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
@@ -10519,16 +10716,6 @@ msgstr ""
msgid "switch `C' expects a numerical value"
msgstr "Schalter `C' erwartet einen numerischen Wert."
-msgid "--strategy requires --merge or --interactive"
-msgstr "--strategy erfordert --merge oder --interactive"
-
-msgid ""
-"apply options are incompatible with rebase.autoSquash. Consider adding --no-"
-"autosquash"
-msgstr ""
-"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"
@@ -10681,6 +10868,9 @@ msgstr "Sie müssen ein Verzeichnis angeben"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<log-Optionen>] [<Referenz>]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10707,6 +10897,10 @@ msgstr "git reflog exists <Referenz>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "ungültiger Zeitstempel '%s' für '--%s'"
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s akzeptiert keine Argumente: '%s'"
+
msgid "do not actually prune any entries"
msgstr "Einträge nicht wirklich löschen"
@@ -10760,6 +10954,31 @@ msgstr "Kein Reflog zum Löschen angegeben."
msgid "invalid ref format: %s"
msgstr "Ungültiges Format für Referenzen: %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<Format> [--dry-run]"
+
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+msgid "specify the reference format to convert to"
+msgstr "das Referenzformat angeben, in das konvertiert werden soll"
+
+msgid "perform a non-destructive dry-run"
+msgstr "einen zerstörungsfreien Trockenlauf durchführen"
+
+msgid "missing --ref-format=<format>"
+msgstr "fehlendes --ref-format=<Format>"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "das Repository verwendet bereits das Format '%s'"
+
+msgid "enable strict checking"
+msgstr "strenge Kontrolle aktivieren"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' nimmt keine Argumente an"
+
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10836,8 +11055,8 @@ msgstr ""
"\t benutzen Sie stattdessen --mirror=fetch oder --mirror=push"
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "unbekanntes Argument für Option mirror: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "unbekanntes --mirror Argument: %s"
msgid "fetch the remote branches"
msgstr "die Remote-Branches anfordern"
@@ -11047,9 +11266,6 @@ msgstr "* Remote-Repository %s"
msgid " Fetch URL: %s"
msgstr " URL zum Abholen: %s"
-msgid "(no URL)"
-msgstr "(keine URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -11058,6 +11274,9 @@ msgstr "(keine URL)"
msgid " Push URL: %s"
msgstr " URL zum Versenden: %s"
+msgid "(no URL)"
+msgstr "(keine URL)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " Hauptbranch: %s"
@@ -11167,10 +11386,6 @@ msgstr "nur URLs für Push ausgeben"
msgid "return all URLs"
msgstr "alle URLs ausgeben"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "Keine URLs für Remote-Repository '%s' konfiguriert."
-
msgid "manipulate push URLs"
msgstr "URLs für \"push\" manipulieren"
@@ -11213,6 +11428,9 @@ msgstr ""
"Konnte 'pack-objects' für das Neupacken von Objekten aus partiell geklonten\n"
"Remote-Repositories nicht starten."
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "promisor-Objekte konnten nicht an pack-objects übergeben werden"
+
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"repack: Erwarte Zeilen mit vollständiger Hex-Objekt-ID nur von pack-objects."
@@ -11246,6 +11464,10 @@ msgstr "konnte temporäre Referenzen-Snapshot-Datei nicht schließen"
msgid "could not remove stale bitmap: %s"
msgstr "konnte veraltete Bitmap nicht entfernen: %s"
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "Pack-Präfix %s fängt nicht mit objdir %s an"
+
msgid "pack everything in a single pack"
msgstr "alles in eine einzige Pack-Datei packen"
@@ -11324,17 +11546,20 @@ msgstr "ein Multi-Pack-Index des resultierenden Pakets schreiben"
msgid "pack prefix to store a pack containing pruned objects"
msgstr "pack-Präfix zum Speichern eines Pakets mit gelöschten Objekten"
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "Paketpräfix, um ein Paket mit herausgefilterten Objekten zu speichern"
+
msgid "cannot delete packs in a precious-objects repo"
msgstr "kann Pack-Dateien in precious-objects Repository nicht löschen"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "Option '%s' kann nur zusammen mit '%s' verwendet werden"
+
msgid "Nothing new to pack."
msgstr "Nichts Neues zum Packen."
#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "Pack-Präfix %s fängt nicht mit objdir %s an"
-
-#, c-format
msgid "renaming pack to '%s' failed"
msgstr "Umbenennung des Pakets in '%s' fehlgeschlagen"
@@ -11535,6 +11760,77 @@ msgstr "--convert-graft-file erwartet keine Argumente"
msgid "only one pattern can be given with -l"
msgstr "Mit -l kann nur ein Muster angegeben werden"
+msgid "need some commits to replay"
+msgstr "zum erneuten Abspielen werden Commits benötigt"
+
+msgid "--onto and --advance are incompatible"
+msgstr "--onto und --advance sind inkompatibel"
+
+msgid "all positive revisions given must be references"
+msgstr "alle angegebenen positiven Commits müssen Referenzen sein"
+
+msgid "argument to --advance must be a reference"
+msgstr "Argument für --advance muss eine Referenz sein"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"kann Ziel nicht mit mehreren Quellen erweitern, da die Reihenfolge unklar "
+"wäre"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"kann nicht implizit bestimmen, ob es sich um eine --advance oder --onto "
+"Operation handelt"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"kann Ziel nicht mit mehreren Quell-Branches erweitern, da die Reihenfolge "
+"unklar wäre"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "kann nicht implizit die richtige Basis für --onto bestimmen"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(EXPERIMENTELL!) git replay ([--contained] --onto <neue-Basis> | --advance "
+"<Branch>) <Commitbereich>..."
+
+msgid "make replay advance given branch"
+msgstr "angegebenen Branch durch neues Abspielen erweitern"
+
+msgid "replay onto given commit"
+msgstr "auf angegebenen Commit neu abspielen"
+
+msgid "advance all branches contained in revision-range"
+msgstr "alle Branches erweitern, die in Commitbereich liegen"
+
+msgid "option --onto or --advance is mandatory"
+msgstr "Option --onto oder --advance erforderlich"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"einige Optionen für das Abgehen von Commits werden außer Kraft gesetzt, da "
+"das '%s' Bit in 'struct rev_info' erzwungen wird"
+
+msgid "error preparing revisions"
+msgstr "Fehler beim Vorbereiten der Commits"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "erneutes Abspielen bis zum Root-Commit wird noch nicht unterstützt!"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "erneutes Abspielen von Merge-Commits wird noch nicht unterstützt!"
+
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
msgstr ""
@@ -11742,22 +12038,23 @@ msgstr "--default benötigt ein Argument"
msgid "--prefix requires an argument"
msgstr "--prefix benötigt ein Argument"
+msgid "no object format specified"
+msgstr "kein Objektformat angegeben"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "nicht unterstütztes Objekt-Format: %s"
+
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "unbekannter Modus für --abbrev-ref: %s"
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden kann nicht zusammen mit --branches verwendet werden"
-
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden kann nicht zusammen mit --tags verwendet werden"
-
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden kann nicht zusammen mit --remotes verwendet werden"
-
msgid "this operation must be run in a work tree"
msgstr "Diese Operation muss in einem Arbeitsverzeichnis ausgeführt werden."
+msgid "Could not read the index"
+msgstr "Konnte den Index nicht lesen"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "unbekannter Modus für --show-object-format: %s"
@@ -11830,8 +12127,8 @@ msgstr "ursprüngliche, leere Commits erhalten"
msgid "allow commits with empty messages"
msgstr "Commits mit leerer Beschreibung erlauben"
-msgid "keep redundant, empty commits"
-msgstr "redundante, leere Commits behalten"
+msgid "deprecated: use --empty=keep instead"
+msgstr "veraltet: benutzen Sie stattdessen --empty=keep"
msgid "use the 'reference' format to refer to commits"
msgstr "das 'reference' Format nutzen, um auf Commits zu verweisen"
@@ -12107,22 +12404,43 @@ msgid "Unknown hash algorithm"
msgstr "Unbekannter Hash-Algorithmus"
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<Muster>...]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<Muster>...]"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<Referenz>...]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<Muster>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "nur Tags anzeigen (kann mit \"heads\" kombiniert werden)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <Referenz>"
-msgid "only show heads (can be combined with tags)"
-msgstr "nur Branches anzeigen (kann mit \"tags\" kombiniert werden)"
+msgid "reference does not exist"
+msgstr "Referenz nicht vorhanden"
+
+msgid "failed to look up reference"
+msgstr "Fehler beim Nachschlagen der Referenz"
+
+msgid "only show tags (can be combined with --branches)"
+msgstr "nur Tags anzeigen (kann mit --branches kombiniert werden)"
+
+msgid "only show branches (can be combined with --tags)"
+msgstr "nur Branches anzeigen (kann mit --tags kombiniert werden)"
+
+msgid "check for reference existence without resolving"
+msgstr "Prüfung auf Vorhandensein einer Referenz, ohne diese aufzulösen"
msgid "stricter reference checking, requires exact ref path"
msgstr "strengere Referenzprüfung, erfordert exakten Referenzpfad"
@@ -12178,6 +12496,10 @@ msgstr ""
"Fehler beim Erstellen eines Verzeichnisses für Datei eines partiellen "
"Checkouts"
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "kann %s nicht öffnen"
+
msgid "failed to initialize worktree config"
msgstr "Fehler beim Initialisieren der Arbeitsverzeichnis-Konfiguration"
@@ -12645,8 +12967,8 @@ msgid "couldn't hash object from '%s'"
msgstr "Hash eines Objektes von '%s' konnte nicht erzeugt werden"
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "unerwarteter Modus %o\n"
+msgid "unexpected mode %o"
+msgstr "unerwarteter Modus %o"
msgid "use the commit stored in the index instead of the submodule HEAD"
msgstr ""
@@ -12771,14 +13093,14 @@ msgstr ""
"verweigert."
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "Klonen von '%s' in Submodul-Pfad '%s' fehlgeschlagen."
-
-#, c-format
msgid "directory not empty: '%s'"
msgstr "Verzeichnis ist nicht leer: '%s'"
#, c-format
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "Klonen von '%s' in Submodul-Pfad '%s' fehlgeschlagen."
+
+#, c-format
msgid "could not get submodule directory for '%s'"
msgstr "Konnte Submodul-Verzeichnis '%s' nicht finden."
@@ -12973,6 +13295,9 @@ msgstr ""
"shallow] [--reference <Repository>] [--recursive] [--[no-]single-branch] "
"[--] [<Pfad>...]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Konnte HEAD nicht als gültige Referenz auflösen."
+
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<Optionen>] [<Pfad>...]"
@@ -13146,9 +13471,11 @@ msgstr "Grund für die Aktualisierung"
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <Key-ID>] [-f] [-m <Beschreibung> | -F <Datei>] [-e]\n"
+" [(--trailer <Token>[(=|:)<Wert>])...]\n"
" <Tagname> [<Commit> | <Objekt>]"
msgid "git tag -d <tagname>..."
@@ -13181,26 +13508,26 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
-"Geben Sie eine Beschreibung für Tag\n"
+"Geben Sie eine Beschreibung für das Tag:\n"
" %s\n"
-"ein. Zeilen, die mit '%c' beginnen, werden ignoriert.\n"
+"ein. Zeilen, die mit '%s' beginnen, werden ignoriert.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
-"Geben Sie eine Beschreibung für Tag\n"
+"Geben Sie eine Beschreibung für das Tag\n"
" %s\n"
-"ein. Zeilen, die mit '%c' beginnen, werden behalten; Sie dürfen diese\n"
-"selbst entfernen wenn Sie möchten.\n"
+"ein. Zeilen, die mit '%s' beginnen, werden behalten; Sie dürfen diese\n"
+"selbst entfernen, wenn Sie möchten.\n"
msgid "unable to sign the tag"
msgstr "konnte Tag nicht signieren"
@@ -13285,6 +13612,9 @@ msgstr "nur Tags ausgeben, die nicht gemerged wurden"
msgid "print only tags of the object"
msgstr "nur Tags von dem Objekt ausgeben"
+msgid "could not start 'git column'"
+msgstr "konnte 'git column' nicht starten"
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "die Option '%s' ist nur im Listenmodus erlaubt"
@@ -13456,6 +13786,9 @@ msgstr "(für Fremdprogramme) keine gespeicherten, nicht aufgelöste Konflikte"
msgid "write index in this format"
msgstr "Index-Datei in diesem Format schreiben"
+msgid "report on-disk index format version"
+msgstr "Bericht über die Version des Indexformats auf der Festplatte"
+
msgid "enable or disable split index"
msgstr "aufgeteilten Index aktivieren oder deaktivieren"
@@ -13482,6 +13815,14 @@ msgstr "Dateien als \"fsmonitor valid\" markieren"
msgid "clear fsmonitor valid bit"
msgstr "\"fsmonitor valid\"-Bit löschen"
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version: war %d, wurde auf %d gesetzt"
+
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -13537,12 +13878,11 @@ msgstr ""
msgid "fsmonitor disabled"
msgstr "Dateisystem-Monitor deaktiviert"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<Optionen>] -d <Referenzname> [<alter-Wert>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<Optionen>] -d <Referenzname> [<alte-oid>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr ""
-"git update-ref [<Optionen>] <Referenzname> <neuer-Wert> [<alter-Wert>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<Optionen>] <Referenzname> <neue-oid> [<alte-oid>]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<Optionen>] --stdin [-z]"
@@ -13643,33 +13983,29 @@ 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"
+"If you meant to create a worktree containing a new unborn 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"
+"Wenn Sie ein Arbeitsverzeichnis erstellen möchten, welches einen neuen\n"
+"ungeborenen Branch (Branch ohne Commits) für dieses Repository erzeugt,\n"
+"können Sie dies mit 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"
+"If you meant to create a worktree containing a new unborn 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"
+"Wenn Sie ein Arbeitsverzeichnis erstellen möchten, welches einen neuen\n"
+"ungeborenen Branch (Branch ohne Commits) für dieses Repository erzeugt,\n"
+"können Sie dies mit der Option --orphan tun:\n"
"\n"
" git worktree add --orphan %s\n"
@@ -13732,6 +14068,10 @@ msgid "initializing"
msgstr "initialisiere"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "konnte erstelltes Arbeitsverzeichnis '%s' nicht finden"
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "Bereite Arbeitsverzeichnis vor (neuer Branch '%s')"
@@ -13763,7 +14103,7 @@ msgstr ""
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"
+"present, stopping; use 'add -f' to override or fetch a remote first"
msgstr ""
"Es gibt keine lokalen oder entfernten Referenzen, obwohl mindestens ein "
"Remote-Repository\n"
@@ -13771,10 +14111,6 @@ msgstr ""
"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 "
@@ -13786,8 +14122,8 @@ 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 "create unborn branch"
+msgstr "ungeborenen Branch erzeugen"
msgid "populate the new working tree"
msgstr "das neue Arbeitsverzeichnis auschecken"
@@ -13812,11 +14148,8 @@ 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 "option '%s' and commit-ish cannot be used together"
+msgstr "Option '%s' und commit-ish können nicht gemeinsam verwendet werden"
msgid "added with --lock"
msgstr "mit --lock hinzugefügt"
@@ -14032,9 +14365,6 @@ msgstr "nicht erkannter Kopfbereich: %s%s (%d)"
msgid "Repository lacks these prerequisite commits:"
msgstr "Dem Repository fehlen folgende vorausgesetzte Commits:"
-msgid "need a repository to verify a bundle"
-msgstr "um ein Paket zu überprüfen wird ein Repository benötigt"
-
msgid ""
"some prerequisite commits exist in the object store, but are not connected "
"to the repository's history"
@@ -14100,6 +14430,10 @@ msgid "terminating chunk id appears earlier than expected"
msgstr "abschließende Chunk-ID erscheint eher als erwartet"
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "Chunk id %<PRIx32> nicht %d-byte-aligned"
+
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "unzulässige(r) Chunk-Offset(s) %<PRIx64> und %<PRIx64>"
@@ -14156,10 +14490,8 @@ msgstr ""
msgid "Move objects and refs by archive"
msgstr "Objekte und Referenzen über ein Archiv verteilen"
-msgid "Provide content or type and size information for repository objects"
-msgstr ""
-"Inhalt oder Informationen zu Typ und Größe für Repository-Objekte "
-"bereitstellen"
+msgid "Provide contents or details of repository objects"
+msgstr "Bereitstellung von Inhalten oder Details von Repository-Objekten"
msgid "Display gitattributes information"
msgstr "gitattributes Informationen darstellen"
@@ -14456,6 +14788,9 @@ msgstr "Empfangen was in das Repository übertragen wurde"
msgid "Manage reflog information"
msgstr "Reflog Informationen verwalten"
+msgid "Low-level access to refs"
+msgstr "Low-Level Zugang zu Referenzen"
+
msgid "Manage set of tracked repositories"
msgstr "Menge von hinterlegten Repositories verwalten"
@@ -14465,6 +14800,11 @@ msgstr "ungepackte Objekte in einem Repository packen"
msgid "Create, list, delete refs to replace objects"
msgstr "Referenzen für ersetzende Objekte erstellen, auflisten, löschen"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"EXPERIMENTELL: Commits auf neuer Basis abspielen, funktioniert auch mit Bare-"
+"Repositories"
+
msgid "Generates a summary of pending changes"
msgstr "eine Übersicht über ausstehende Änderungen generieren"
@@ -14591,8 +14931,8 @@ msgstr "die GPG-Signatur von Tags prüfen"
msgid "Display version information about Git"
msgstr "Versionsinformationen über Git anzeigen"
-msgid "Show logs with difference each commit introduces"
-msgstr "Logs mit dem Unterschied, den jeder Commit einführt, anzeigen"
+msgid "Show logs with differences each commit introduces"
+msgstr "Logs mit den Unterschieden anzeigen, den jeder Commit einführt"
msgid "Manage multiple working trees"
msgstr "mehrere Arbeitsverzeichnisse verwalten"
@@ -14709,6 +15049,32 @@ msgstr "Ein Werkzeug zur Verwaltung großer Git-Repositories"
msgid "commit-graph file is too small"
msgstr "Commit-Graph-Datei ist zu klein"
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "Commit-Graph OID fanout Chunk hat die falsche Größe"
+
+msgid "commit-graph fanout values out of order"
+msgstr "Commit-Graph fanout-Werte sind nicht in Ordnung"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "Commit-Graph OID Lookup Chunk hat die falsche Größe"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "Commit-Graph Commit Daten Chunk hat die falsche Größe"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "Commit-Graph Generations Chunk hat die falsche Größe"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "Commit-Graph changed-path Index Chunk ist zu klein"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"ignoriere zu kleinen Chunk für geänderte Pfade (%<PRIuMAX> < %<PRIuMAX>) in "
+"Commit-Graph-Datei"
+
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "Commit-Graph-Signatur %X stimmt nicht mit Signatur %X überein"
@@ -14725,9 +15091,30 @@ msgstr "Hash-Version des Commit-Graph %X stimmt nicht mit Version %X überein"
msgid "commit-graph file is too small to hold %u chunks"
msgstr "Commit-Graph-Datei ist zu klein, um %u Chunks zu enthalten"
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr "Commit-Graph benötigter OID fanout Chunk fehlt oder ist beschädigt"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "Commit-Graph benötigter OID lookup Chunk fehlt oder ist beschädigt"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr ""
+"Commit-Graph erforderlicher Commit-Daten Chunk fehlt oder ist beschädigt"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"deaktiviere Bloom-Filter für die Commit-Graph-Ebene '%s' aufgrund "
+"inkompatibler Einstellungen"
+
msgid "commit-graph has no base graphs chunk"
msgstr "Commit-Graph hat keinen Basis-Graph-Chunk"
+msgid "commit-graph base graphs chunk is too small"
+msgstr "Commit-Graph Basis-Graph-Chunk ist zu klein"
+
msgid "commit-graph chain does not match"
msgstr "Commit-Graph Verkettung stimmt nicht überein"
@@ -14735,6 +15122,9 @@ msgstr "Commit-Graph Verkettung stimmt nicht überein"
msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "Anzahl der Commits im Basisgraph zu hoch: %<PRIuMAX>"
+msgid "commit-graph chain file too small"
+msgstr "Commit-Graph Chain-Datei zu klein"
+
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr "Ungültige Commit-Graph Verkettung: Zeile '%s' ist kein Hash"
@@ -14752,6 +15142,12 @@ msgstr "konnte Commit %s nicht finden"
msgid "commit-graph requires overflow generation data but has none"
msgstr "Commit-Graph erfordert Überlaufgenerierungsdaten, aber hat keine"
+msgid "commit-graph overflow generation data is too small"
+msgstr "Commit-Graph Überlaufgenerierungsdaten sind zu klein"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "commit-graph extra-edges Zeiger außerhalb der Grenzen"
+
msgid "Loading known commits in commit graph"
msgstr "Lade bekannte Commits in Commit-Graph"
@@ -14840,6 +15236,14 @@ msgstr ""
"versuche einen Commit-Graph zu schreiben, aber 'core.commitGraph' ist "
"deaktiviert"
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"versuche, einen Commit-Graphen zu schreiben, aber 'commitGraph."
+"changedPathsVersion' (%d) wird nicht unterstützt"
+
msgid "too many commits to write graph"
msgstr "zu viele Commits zum Schreiben des Graphen"
@@ -14883,20 +15287,6 @@ msgid "commit-graph parent list for commit %s terminates early"
msgstr "Commit-Graph Vorgänger-Liste für Commit %s endet zu früh"
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr ""
-"Commit-Graph hat Generationsnummer null für Commit %s, aber sonst ungleich "
-"null"
-
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"Commit-Graph hat Generationsnummer ungleich null für Commit %s, aber sonst "
-"null"
-
-#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr "Commit-Graph Erstellung für Commit %s ist %<PRIuMAX> < %<PRIuMAX>"
@@ -14905,10 +15295,22 @@ 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>"
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"Commit-Graph hat sowohl Null- als auch Nicht-Null-Generationen (z. B. "
+"Commits '%s' und '%s')"
+
msgid "Verifying commits in commit graph"
msgstr "Commit in Commit-Graph überprüfen"
#, c-format
+msgid "could not parse commit %s"
+msgstr "Konnte Commit %s nicht parsen."
+
+#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s ist kein Commit!"
@@ -14933,6 +15335,11 @@ msgstr ""
"\"git config advice.graftFileDeprecated false\" ausführen."
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"Commit %s existiert im Commit-Graphen, aber nicht in der Objektdatenbank"
+
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr ""
"Commit %s hat eine nicht vertrauenswürdige GPG-Signatur, angeblich von %s."
@@ -15342,8 +15749,13 @@ 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 ASCII character"
-msgstr "core.commentChar sollte nur ein ASCII-Zeichen sein"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s kann keinen Zeilenumbruch enthalten"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s muss mindestens ein Zeichen enthalten"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15380,10 +15792,6 @@ msgstr "Referenz '%s' zeigt auf keinen Blob."
msgid "unable to resolve config blob '%s'"
msgstr "Konnte Blob '%s' für Konfiguration nicht auflösen."
-#, c-format
-msgid "failed to parse %s"
-msgstr "Fehler beim Parsen von %s."
-
msgid "unable to parse command-line config"
msgstr ""
"Konnte die über die Befehlszeile angegebene Konfiguration nicht parsen."
@@ -15425,6 +15833,10 @@ msgid "failed to write new configuration file %s"
msgstr "Konnte neue Konfigurationsdatei '%s' nicht schreiben."
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "kein mehrzeiliger Kommentar erlaubt: '%s'"
+
+#, c-format
msgid "could not lock config file %s"
msgstr "Konnte Konfigurationsdatei '%s' nicht sperren."
@@ -15863,9 +16275,6 @@ msgstr "Schreiben des Archivs fehlgeschlagen"
msgid "--merge-base does not work with ranges"
msgstr "--merge-base funktioniert nicht mit Bereichen"
-msgid "--merge-base only works with commits"
-msgstr "--merge-base funktioniert nur mit Commits"
-
msgid "unable to get HEAD"
msgstr "konnte HEAD nicht bekommen"
@@ -15927,6 +16336,10 @@ msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "Unbekannter Wert in Konfigurationsvariable 'diff.submodule': '%s'"
#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "Unbekannter Wert für Konfiguration '%s': %s"
+
+#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
@@ -16008,13 +16421,6 @@ msgstr "ungültiges --color-moved Argument: %s"
msgid "invalid mode '%s' in --color-moved-ws"
msgstr "ungültiger Modus '%s' in --color-moved-ws"
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"Option diff-algorithm akzeptiert: \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-
#, c-format
msgid "invalid argument to %s"
msgstr "ungültiges Argument für %s"
@@ -16058,8 +16464,8 @@ msgstr "maschinenlesbare Ausgabe von --stat"
msgid "output only the last line of --stat"
msgstr "nur die letzte Zeile von --stat ausgeben"
-msgid "<param1,param2>..."
-msgstr "<Parameter1,Parameter2>..."
+msgid "<param1>,<param2>..."
+msgstr "<Parameter1>,<Parameter2>..."
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
@@ -16070,8 +16476,8 @@ msgstr ""
msgid "synonym for --dirstat=cumulative"
msgstr "Synonym für --dirstat=cumulative"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "Synonym für --dirstat=files,Parameter1,Parameter2..."
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "Synonym für --dirstat=files,<Parameter1>,<Parameter2>..."
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
@@ -16254,12 +16660,6 @@ msgstr "Änderungen durch Nutzung des Algorithmus \"Patience Diff\" erzeugen"
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "Änderungen durch Nutzung des Algorithmus \"Histogram Diff\" erzeugen"
-msgid "<algorithm>"
-msgstr "<Algorithmus>"
-
-msgid "choose a diff algorithm"
-msgstr "einen Algorithmus für Änderungen wählen"
-
msgid "<text>"
msgstr "<Text>"
@@ -16733,17 +17133,21 @@ msgstr ""
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
msgstr ""
"git [-v | --version] [-h | --help] [-C <Pfad>] [-c <Name>=<Wert>]\n"
" [--exec-path[=<Pfad>]] [--html-path] [--man-path] [--info-path]\n"
-" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-" [--git-dir=<Pfad>] [--work-tree=<Pfad>] [--namespace=<Name>]\n"
-" [--config-env=<Name>=<Umgebungsvariable>] <Befehl> [<Argumente>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<Pfad>]\n"
+" [--work-tree=<Pfad>] [--namespace=<Name>] [--config-"
+"env=<Name>=<Umgebungsvariable>]\n"
+" <Befehl> [<Argumente>]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -17085,13 +17489,13 @@ msgstr ""
"Sie können diese Warnung mit `git config advice.ignoredHook false` "
"deaktivieren."
+msgid "not a git repository"
+msgstr "kein Git-Repository"
+
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "Argument für --packfile muss ein gültiger Hash sein ('%s' erhalten)"
-msgid "not a git repository"
-msgstr "kein Git-Repository"
-
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
msgstr "negativer Wert für http.postBuffer; benutze Standardwert %d"
@@ -17104,6 +17508,9 @@ msgstr ""
"Das Anheften des öffentlichen Schlüssels wird mit cURL < 7.39.0 nicht "
"unterstützt"
+msgid "Unknown value for http.proactiveauth"
+msgstr "Unbekannter Wert für http.proactiveauth"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE wird mit cURL < 7.44.0 nicht unterstützt."
@@ -17120,6 +17527,12 @@ msgstr ""
msgid "Could not set SSL backend to '%s': already set"
msgstr "Konnte SSL-Backend nicht zu '%s' setzen: bereits gesetzt"
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "Lesen von Cookies von http.cookiefile '-' verweigert"
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "http.savecookies wird bei leerem http.cookiefile ignoriert"
+
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -17262,6 +17675,17 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "Konnte '%s.lock' nicht erstellen: %s"
+msgid "unable to create temporary object directory"
+msgstr "konnte temporäres Objektverzeichnis nicht erstellen"
+
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "konnte den losen Objektindex %s nicht schreiben"
+
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "Fehler beim Schreiben des losen Objektindex %s"
+
#, c-format
msgid "unexpected line: '%s'"
msgstr "unerwartete Zeile: '%s'"
@@ -17273,6 +17697,10 @@ msgid "quoted CRLF detected"
msgstr "angeführtes CRLF entdeckt"
#, c-format
+msgid "unable to format message: %s"
+msgstr "Meldung kann nicht formatiert werden: %s"
+
+#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "Fehler beim Merge von Submodul %s (nicht ausgecheckt)."
@@ -17285,6 +17713,12 @@ msgid "Failed to merge submodule %s (commits not present)"
msgstr "Fehler beim Merge von Submodul %s (Commits nicht vorhanden)."
#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr ""
+"Fehler: Submodul %s konnte nicht zusammengeführt werden (Repository "
+"beschädigt)"
+
+#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr "Fehler beim Merge von Submodul %s (Commits folgen keiner Merge-Basis)"
@@ -17312,12 +17746,13 @@ msgstr ""
"sind vorhanden:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "Fehler bei Ausführung des internen Merges"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "Fehler: Der interne Merge für %s konnte nicht ausgeführt werden"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "Konnte %s nicht zur Datenbank hinzufügen"
+msgid "error: unable to add %s to database"
+msgstr "Fehler: kann %s nicht zur Datenbank hinzufügen"
#, c-format
msgid "Auto-merging %s"
@@ -17415,12 +17850,12 @@ msgstr ""
"KONFLIKT (umbenennen/löschen): %s zu %s in %s umbenannt, aber in %s gelöscht."
#, c-format
-msgid "cannot read object %s"
-msgstr "kann Objekt %s nicht lesen"
+msgid "error: cannot read object %s"
+msgstr "Fehler: kann Objekt %s nicht lesen"
#, c-format
-msgid "object %s is not a blob"
-msgstr "Objekt %s ist kein Blob"
+msgid "error: object %s is not a blob"
+msgstr "Fehler: Objekt %s ist kein Blob"
#, c-format
msgid ""
@@ -17473,7 +17908,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 ""
@@ -17563,6 +17998,11 @@ msgid "do not know what to do with %06o %s '%s'"
msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr ""
+"Submodul %s konnte nicht zusammengeführt werden (Repository beschädigt)"
+
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "Spule Submodul %s zu dem folgenden Commit vor:"
@@ -17603,6 +18043,13 @@ msgstr ""
msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "Fehler beim Merge von Submodul %s (mehrere Merges gefunden)"
+msgid "failed to execute internal merge"
+msgstr "Fehler bei Ausführung des internen Merges"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "konnte %s nicht zur Datenbank hinzufügen"
+
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
@@ -17710,6 +18157,14 @@ msgstr ""
"KONFLIKT (umbenennen/umbenennen): Benenne Verzeichnis um %s->%s in %s.\n"
"Benenne Verzeichnis um %s->%s in %s"
+#, c-format
+msgid "cannot read object %s"
+msgstr "kann Objekt %s nicht lesen"
+
+#, c-format
+msgid "object %s is not a blob"
+msgstr "Objekt %s ist kein Blob"
+
msgid "modify"
msgstr "ändern"
@@ -17771,50 +18226,6 @@ msgstr "Konnte Objekt '%s' nicht parsen."
msgid "failed to read the cache"
msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "Multi-Pack-Index OID fanout hat die falsche Größe"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "Multi-Pack-Index-Datei %s ist zu klein."
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr ""
-"Multi-Pack-Index-Signatur 0x%08x stimmt nicht mit Signatur 0x%08x überein."
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "Multi-Pack-Index-Version %d nicht erkannt."
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "Multi-Pack-Index Hash-Version %u stimmt nicht mit Version %u überein"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "Multi-Pack-Index fehlt erforderlicher Pack-Namen Chunk"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "Multi-Pack-Index fehlt erforderlicher OID fanout Chunk"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "Multi-Pack-Index fehlt erforderlicher OID lookup Chunk"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "Multi-Pack-Index fehlt erforderlicher Objekt offset Chunk"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "Falsche Reihenfolge bei Multi-Pack-Index Pack-Namen: '%s' vor '%s'"
-
-#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "Ungültige pack-int-id: %u (%u Pakete insgesamt)"
-
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr ""
-"Multi-Pack-Index speichert einen 64-Bit Offset, aber off_t ist zu klein"
-
#, c-format
msgid "failed to add packfile '%s'"
msgstr "Fehler beim Hinzufügen von Packdatei '%s'"
@@ -17838,10 +18249,6 @@ msgstr "Zeile konnte nicht geparst werden: %s"
msgid "malformed line: %s"
msgstr "fehlerhafte Zeile: %s"
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr ""
-"ignoriere existierenden Multi-Pack-Index; Prüfsumme stimmt nicht überein"
-
msgid "could not load pack"
msgstr "Paket konnte nicht geladen werden"
@@ -17849,6 +18256,21 @@ msgstr "Paket konnte nicht geladen werden"
msgid "could not open index for %s"
msgstr "konnte Index für %s nicht öffnen"
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "kann '%s' nicht mit '%s' verknüpfen"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "Fehler beim Löschen des Multi-Pack-Index bei %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "kann kein inkrementelles MIDX mit Bitmap schreiben"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"ignoriere existierenden Multi-Pack-Index; Prüfsumme stimmt nicht überein"
+
msgid "Adding packfiles to multi-pack-index"
msgstr "Packdateien zum Multi-Pack-Index hinzufügen"
@@ -17874,24 +18296,42 @@ msgstr "keine Packdateien zum Indizieren."
msgid "refusing to write multi-pack .bitmap without any objects"
msgstr "Schreiben der Multi-Pack-Bitmap ohne Objekte abgelehnt"
+msgid "unable to create temporary MIDX layer"
+msgstr "konnte keine temporäre MIDX-Ebene erstellen"
+
msgid "could not write multi-pack bitmap"
msgstr "Multi-Pack-Bitmap konnte nicht geschrieben werden"
+msgid "unable to open multi-pack-index chain file"
+msgstr "Multi-Pack-Indexketten-Datei kann nicht geöffnet werden"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "neue Multi-Pack-Index-Ebene konnte nicht umbenannt werden"
+
msgid "could not write multi-pack-index"
msgstr "Multi-Pack-Index konnte nicht geschrieben werden"
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "Fehler beim Löschen des Multi-Pack-Index bei %s"
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"kann Pakete aus einem inkrementellen Multi-Pack-Index nicht ablaufen lassen"
-msgid "multi-pack-index file exists, but failed to parse"
-msgstr "Multi-Pack-Index-Datei existiert, aber das Parsen schlug fehl"
+msgid "Counting referenced objects"
+msgstr "Referenzierte Objekte zählen"
-msgid "incorrect checksum"
-msgstr "Prüfsumme nicht korrekt"
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Suchen und Löschen von unreferenzierten Pack-Dateien"
-msgid "Looking for referenced packfiles"
-msgstr "Suche nach referenzierten Pack-Dateien"
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "kann einen inkrementellen Multi-Pack-Index nicht neu packen"
+
+msgid "could not start pack-objects"
+msgstr "Konnte 'pack-objects' nicht ausführen"
+
+msgid "could not finish pack-objects"
+msgstr "Konnte 'pack-objects' nicht beenden"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "Multi-Pack-Index OID fanout hat die falsche Größe"
#, c-format
msgid ""
@@ -17900,6 +18340,100 @@ msgstr ""
"Ungültige oid fanout Reihenfolge: fanout[%d] = %<PRIx32> > %<PRIx32> = "
"fanout[%d]"
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "multi-pack-index OID-Lookup-Chunk hat die falsche Größe"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "multi-pack-index Object-Offset-Chunk hat die falsche Größe"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "Multi-Pack-Index-Datei %s ist zu klein."
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr ""
+"Multi-Pack-Index-Signatur 0x%08x stimmt nicht mit Signatur 0x%08x überein."
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "Multi-Pack-Index-Version %d nicht erkannt."
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "Multi-Pack-Index Hash-Version %u stimmt nicht mit Version %u überein"
+
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr ""
+"multi-pack-index erforderlicher Pack-Name Chunk fehlt oder ist beschädigt"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"multi-pack-index erforderlicher OID-Fanout-Chunk fehlt oder ist beschädigt"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr ""
+"multi-pack-index erforderlicher OID Lookup Chunk fehlt oder ist beschädigt"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"multi-pack-index benötigte Objekt Offsets Chunk fehlt oder ist beschädigt"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "multi-pack-index Pack-Name Chunk ist zu klein"
+
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "Falsche Reihenfolge bei Multi-Pack-Index Pack-Namen: '%s' vor '%s'"
+
+msgid "multi-pack-index chain file too small"
+msgstr "Multi-Pack-Index-Kettendatei zu klein"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "Paketanzahl im Basis-MIDX zu hoch: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "Objektanzahl in Basis-MIDX zu hoch: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "ungültige Multi-Pack-Index-Kette: Zeile '%s' ist kein Hash"
+
+msgid "unable to find all multi-pack index files"
+msgstr "konnte nicht alle Multi-Pack-Indexdateien finden"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "ungültige MIDX-Objektposition, MIDX ist wahrscheinlich beschädigt"
+
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "Ungültige pack-int-id: %u (%u Pakete insgesamt)"
+
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX enthält keinen BTMP-Chunk"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "konnte Bitmap-Paket nicht laden %<PRIu32>"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr ""
+"Multi-Pack-Index speichert einen 64-Bit Offset, aber off_t ist zu klein"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr "multi-pack-index großer Offset außerhalb der Grenzen"
+
+msgid "multi-pack-index file exists, but failed to parse"
+msgstr "Multi-Pack-Index-Datei existiert, aber das Parsen schlug fehl"
+
+msgid "incorrect checksum"
+msgstr "Prüfsumme nicht korrekt"
+
+msgid "Looking for referenced packfiles"
+msgstr "Suche nach referenzierten Pack-Dateien"
+
msgid "the midx contains no oid"
msgstr "das midx enthält keine oid"
@@ -17928,18 +18462,6 @@ msgstr "Fehler beim Laden des Pack-Index für Packdatei %s"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "Falscher Objekt-Offset für oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-msgid "Counting referenced objects"
-msgstr "Referenzierte Objekte zählen"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "Suchen und Löschen von unreferenzierten Pack-Dateien"
-
-msgid "could not start pack-objects"
-msgstr "Konnte 'pack-objects' nicht ausführen"
-
-msgid "could not finish pack-objects"
-msgstr "Konnte 'pack-objects' nicht beenden"
-
#, c-format
msgid "unable to create lazy_dir thread: %s"
msgstr "Kann lazy_dir Thread nicht erzeugen: %s"
@@ -17991,6 +18513,25 @@ msgstr ""
msgid "Bad %s value: '%s'"
msgstr "Ungültiger %s Wert: '%s'"
+msgid "failed to decode tree entry"
+msgstr "Tree-Eintrag konnte nicht dekodiert werden"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "der Tree-Eintrag für %s konnte nicht zugeordnet werden"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "ungültiges %s in Commit"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "kann %s %s in Commit-Objekt nicht zuordnen"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Objekt konnte nicht von %s nach %s konvertiert werden"
+
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
msgstr ""
@@ -18098,6 +18639,18 @@ msgid "packed object %s (stored in %s) is corrupt"
msgstr "Gepacktes Objekt %s (gespeichert in %s) ist beschädigt."
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "fehlende Abbildung von %s auf %s"
+
+#, c-format
+msgid "unable to open %s"
+msgstr "kann %s nicht öffnen"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "die Dateien '%s' und '%s' unterscheiden sich im Inhalt"
+
+#, c-format
msgid "unable to write file %s"
msgstr "Konnte Datei %s nicht schreiben."
@@ -18153,6 +18706,10 @@ msgid "cannot read object for %s"
msgstr "Kann Objekt für %s nicht lesen."
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "kann Objekt %s nicht auf %s abbilden"
+
+#, c-format
msgid "object fails fsck: %s"
msgstr "fsck schlägt bei Objekt fehl: %s"
@@ -18180,10 +18737,6 @@ msgid "%s is not a valid '%s' object"
msgstr "%s ist kein gültiges '%s' Objekt"
#, c-format
-msgid "unable to open %s"
-msgstr "kann %s nicht öffnen"
-
-#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "Hash für %s stimmt nicht überein (%s erwartet)."
@@ -18214,7 +18767,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"
@@ -18223,7 +18776,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.
@@ -18239,7 +18792,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]"
@@ -18380,6 +18933,17 @@ msgstr "Konnte Objekt '%s' nicht parsen."
msgid "hash mismatch %s"
msgstr "Hash stimmt nicht mit %s überein."
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "doppelter Eintrag beim Schreiben des Bitmap-Index: %s"
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "versuchte, nicht gewählten Commit '%s' zu speichern"
+
+msgid "too many pseudo-merges"
+msgstr "zu viele Pseudo-Merges"
+
msgid "trying to write commit not in index"
msgstr "Versuch, einen Commit zu schreiben, der nicht im Index steht"
@@ -18404,6 +18968,17 @@ msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr ""
"beschädigte Bitmap-Indexdatei (zu kurz, um in die Lookup-Tabelle zu passen)"
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"beschädigte Bitmap-Indexdatei (zu kurz für den Pseudo-Merge-Tabellenkopf)"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr "beschädigte Bitmap-Indexdatei (zu kurz für die Pseudo-Merge-Tabelle)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "beschädigte Bitmap-Indexdatei, Pseudo-Merge-Tabelle zu kurz"
+
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "duplizierter Eintrag im Bitmap-Index: '%s'"
@@ -18435,6 +19010,9 @@ msgstr "Multi-Pack-Bitmap fehlt erforderlicher Reverse-Index"
msgid "could not open pack %s"
msgstr "konnte Paket '%s' nicht öffnen"
+msgid "could not determine MIDX preferred pack"
+msgstr "konnte das von MIDX bevorzugte Paket nicht ermitteln"
+
#, c-format
msgid "preferred pack (%s) is invalid"
msgstr "bevorzugtes Paket (%s) ist ungültig"
@@ -18458,6 +19036,17 @@ msgstr ""
"fehlerhafte ewah-Bitmap: abgeschnittener Header für Bitmap des Commits \"%s\""
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr ""
+"Paket kann nicht geladen werden: '%s', Deaktivierung der Paket-"
+"Wiederverwendung"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr ""
+"kann bevorzugtes Paket nicht berechnen, Wiederverwendung von Paketen wird "
+"deaktiviert"
+
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "Objekt '%s' nicht im Typ Bitmaps gefunden"
@@ -18487,6 +19076,10 @@ msgid "mismatch in bitmap results"
msgstr "Unstimmigkeiten bei Bitmap-Ergebnissen"
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "Pseudo-Merge-Index außerhalb des Bereichs (%<PRIu32> >= %<PRIuMAX>)"
+
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "konnte '%s' in Paket '%s' bei Offset %<PRIuMAX> nicht finden"
@@ -18545,6 +19138,12 @@ msgstr "ungültige Prüfsumme"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "ungültige rev-index Position bei %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "multi-pack-index Reverse-Index Chunk hat die falsche Größe"
+
+msgid "could not determine preferred pack"
+msgstr "konnte das bevorzugte Paket nicht bestimmen"
+
msgid "cannot both write and verify reverse index"
msgstr ""
"Reverse-Index kann nicht gleichzeitig geschrieben und verifiziert werden"
@@ -18597,14 +19196,6 @@ msgid "%s requires a value"
msgstr "%s erfordert einen Wert."
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s ist inkompatibel mit %s."
-
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s: inkompatibel mit etwas anderem"
-
-#, c-format
msgid "%s takes no value"
msgstr "%s erwartet keinen Wert"
@@ -18689,6 +19280,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-NUM"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "Gegenteil von --no-%s"
+
msgid "expiry-date"
msgstr "Verfallsdatum"
@@ -18720,6 +19315,14 @@ msgstr ""
"Mit der Option --pathspec-from-file sind Pfade durch NUL-Zeichen getrennt"
#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "falscher boolescher Wert von Umgebungsvariable '%s' für '%s'"
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "Fehler beim Parsen von %s."
+
+#, c-format
msgid "Could not make %s writable by group"
msgstr "Konnte Gruppenschreibrecht für %s nicht setzen."
@@ -18768,6 +19371,10 @@ msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s: 'literal' und 'glob' sind inkompatibel"
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "'%s' liegt außerhalb des Verzeichnisbaums"
+
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s: '%s' liegt außerhalb des Repositories von '%s'"
@@ -18842,6 +19449,10 @@ msgstr "Kann Thread für lstat nicht erzeugen: %s"
msgid "unable to parse --pretty format"
msgstr "Konnte --pretty Format nicht parsen."
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr ""
+"lazy fetching deaktiviert; einige Objekte sind möglicherweise nicht verfügbar"
+
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "Promisor-Remote: konnte Fetch-Subprozess nicht abspalten"
@@ -18867,6 +19478,67 @@ msgstr "object-info: erwartete Flush nach Argumenten"
msgid "Removing duplicate objects"
msgstr "Lösche doppelte Objekte"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "Pseudo-Merge-Regex konnte nicht geladen werden für %s: '%s'"
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s muss nicht-negativ sein, Standardwert wird verwendet"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s muss zwischen 0 und 1 liegen, Standardwert wird verwendet"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s muss positiv sein, verwende Standardwert"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "Pseudo-Merge-Gruppe '%s' fehlt erforderliches Muster"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"Pseudo-Merge-Gruppe '%s' hat einen instabilen vor einem stabilen "
+"Schwellenwert"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"Pseudo-Merge-Regex aus der Konfiguration hat zu viele Capture-Gruppen "
+"(maximum=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"erweiterter Pseudo-Merge liest außerhalb des Bereichs (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"erweiterter Pseudo-Merge-Eintrag ist zu kurz (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr "konnte keinen Pseudo-Merge für Commit %s bei Offset %<PRIuMAX> finden"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"erweiterte Pseudo-Merge-Suche außerhalb des Bereichs (%<PRIu32> >= %<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "Lesen außerhalb des zulässigen Bereichs: (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "konnte erweiterte Pseudo-Merge-Tabelle für Commit %s nicht lesen"
+
msgid "could not start `log`"
msgstr "Konnte `log` nicht starten."
@@ -18926,10 +19598,6 @@ msgid "unable to add '%s' to index"
msgstr "Konnte '%s' nicht dem Index hinzufügen."
#, c-format
-msgid "unable to stat '%s'"
-msgstr "konnte '%s' nicht lesen"
-
-#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "'%s' scheint eine Datei und ein Verzeichnis zu sein"
@@ -19037,10 +19705,6 @@ msgid "failed to convert to a sparse-index"
msgstr "Konvertierung zu einem Sparse-Index fehlgeschlagen"
#, c-format
-msgid "could not stat '%s'"
-msgstr "Konnte '%s' nicht lesen."
-
-#, c-format
msgid "unable to open git dir: %s"
msgstr "konnte Git-Verzeichnis nicht öffnen: %s"
@@ -19309,6 +19973,10 @@ msgid "expected format: %%(ahead-behind:<committish>)"
msgstr "erwartetes Format: %%(ahead-behind:<Commit>)"
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "erwartetes Format: %%(is-base:<committish>)"
+
+#, c-format
msgid "malformed field name: %.*s"
msgstr "Fehlerhafter Feldname: %.*s"
@@ -19483,11 +20151,18 @@ msgstr "Log für Referenz %s unerwartet bei %s beendet."
msgid "log for %s is empty"
msgstr "Log für %s ist leer."
+msgid "refusing to force and skip creation of reflog"
+msgstr "Erzwingen der Aktion verweigert; überspringe Erstellung des Reflogs"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "verweigere Aktualisierung einer Referenz mit fehlerhaftem Namen '%s'"
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "Aktualisierung von Pseudoreferenz '%s' verweigert"
+
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "update_ref für Referenz '%s' fehlgeschlagen: %s"
@@ -19512,10 +20187,6 @@ msgid "cannot process '%s' and '%s' at the same time"
msgstr "kann '%s' und '%s' nicht zur selben Zeit verarbeiten"
#, c-format
-msgid "could not remove reference %s"
-msgstr "konnte Referenz %s nicht löschen"
-
-#, c-format
msgid "could not delete reference %s: %s"
msgstr "konnte Referenz %s nicht entfernen: %s"
@@ -19524,6 +20195,104 @@ msgid "could not delete references: %s"
msgstr "konnte Referenzen nicht entfernen: %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr ""
+"Trockenlauf der Migration von Referenzen abgeschlossen. Das Ergebnis kann "
+"unter '%s' gefunden werden.\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "konnte das temporäre Migrationsverzeichnis '%s' nicht entfernen"
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "migrierte Referenzen befinden sich unter '%s'"
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"kann Referenz '%s' nicht sperren: erwartete symbolische Referenz mit Ziel "
+"'%s': ist aber eine reguläre Referenz"
+
+#, c-format
+msgid "cannot open directory %s"
+msgstr "Verzeichnis %s kann nicht geöffnet werden"
+
+msgid "Checking references consistency"
+msgstr "Überprüfung der Konsistenz der Referenzen"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "Referenzname ist gefährlich: %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "Versuch, Referenz '%s' mit nicht existierendem Objekt %s zu schreiben"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "Versuch, Nicht-Commit-Objekt %s in Branch '%s' zu schreiben"
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"mehrere Aktualisierungen für 'HEAD' (einschließlich einer über seinen "
+"Referenten '%s') sind nicht erlaubt"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr ""
+"kann Referenz '%s' nicht sperren: Referenz '%s' kann nicht aufgelöst werden"
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "kann Referenz '%s' nicht sperren: Fehler beim Lesen der Referenz"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"mehrere Aktualisierungen für '%s' (einschließlich einer über die symbolische "
+"Referenz '%s') sind nicht erlaubt"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "kann Referenz '%s' nicht sperren: Referenz existiert bereits"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr "kann Referenz '%s' nicht sperren: Referenz fehlt, aber bei %s erwartet"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "kann Referenz '%s' nicht sperren: ist bei %s, aber bei %s erwartet"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "reftable: Transaktion vorbereiten: %s"
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "reftable: Transaktionsfehler: %s"
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "kann Stapel nicht verkleinern: %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "Referenzname %s nicht gefunden"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr ""
+"Referenzname %s ist eine symbolische Referenz, Kopieren wird nicht "
+"unterstützt"
+
+#, c-format
msgid "invalid refspec '%s'"
msgstr "ungültige Refspec '%s'"
@@ -19532,6 +20301,10 @@ msgid "invalid quoting in push-option value: '%s'"
msgstr "Ungültiges Quoting beim \"push-option\"-Wert: '%s'"
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "unbekannter Wert für Objektformat: %s"
+
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs nicht gültig: Ist das ein Git-Repository?"
@@ -19709,16 +20482,13 @@ msgid ""
"\n"
"Neither worked, so we gave up. You must fully qualify the ref."
msgstr ""
-"Das angegebene Ziel ist kein vollständiger Referenzname (startet mit \"refs/"
-"\").\n"
-"Wir versuchten zu erraten, was Sie meinten, mit:\n"
+"Das angegebene Ziel ist kein vollständiger Referenzname (startet mit\n"
+"\"refs/\"). Wir versuchten zu erraten, was Sie meinten, mit:\n"
"\n"
"- Suche einer Referenz, die mit '%s' übereinstimmt, auf der Remote-Seite\n"
-"- Prüfung, ob die versendete <Quelle> ('%s') eine Referenz in \"refs/{heads,"
-"tags}\"\n"
-" ist, in dessen Falle wir einen entsprechenden refs/{heads,tags} Präfix "
-"auf\n"
-" der Remote-Seite hinzufügen würden.\n"
+"- Prüfung, ob die versendete <Quelle> ('%s') eine Referenz in\n"
+" \"refs/{heads,tags}/\" ist, in dessen Falle wir einen entsprechenden\n"
+" refs/{heads,tags}/ Präfix auf der Remote-Seite hinzufügen würden.\n"
"\n"
"Keines hat funktioniert, sodass wir aufgegeben haben. Sie müssen die\n"
"Referenz mit vollqualifizierten Namen angeben."
@@ -19988,8 +20758,19 @@ msgid "resolve-undo records `%s` which is missing"
msgstr "resolve-undo zeichnet `%s` auf, das fehlt"
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "konnte kein Commit für das Argument ancestry-path %s erhalten"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s existiert, ist aber eine symbolische Referenz"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge erfordert einen der Pseudoreferenzen MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD oder REBASE_HEAD"
+
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "konnte keinen Commit für das Argument --ancestry-path erhalten %s"
msgid "--unpacked=<packfile> no longer supported"
msgstr "--unpacked=<Pack-Datei> wird nicht länger unterstützt"
@@ -20084,8 +20865,18 @@ msgstr "vollständiges Arbeitsverzeichnis beim Klonen erstellen"
msgid "only download metadata for the branch that will be checked out"
msgstr "lade nur Metadaten des Branches herunter, der ausgecheckt wird"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<Optionen>] [--] <Repository> [<Verzeichnis>]"
+msgid "create repository within 'src' directory"
+msgstr "Repository im Verzeichnis 'src' erstellen"
+
+msgid "specify if tags should be fetched during clone"
+msgstr "Angabe, ob Tags während des Klonens abgerufen werden sollen"
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <Haupt-Branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <URL> [<Eintragung>]"
#, c-format
msgid "cannot deduce worktree name from '%s'"
@@ -20104,6 +20895,10 @@ msgid "could not configure remote in '%s'"
msgstr "konnte Remote-Repository in '%s' nicht konfigurieren"
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "konnte die Tags in '%s' nicht deaktivieren"
+
+#, c-format
msgid "could not configure '%s'"
msgstr "konnte '%s' nicht konfigurieren"
@@ -20136,12 +20931,28 @@ msgid "could not remove stale scalar.repo '%s'"
msgstr "konnte veraltetes scalar.repo '%s' nicht entfernen"
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "entferne veraltetes scalar.repo '%s'"
+msgid "removed stale scalar.repo '%s'"
+msgstr "veraltetes scalar.repo '%s' entfernt"
+
+#, c-format
+msgid "repository at '%s' has different owner"
+msgstr "Repository bei '%s' hat anderen Eigentümer"
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "Git-Repository entfernt in '%s'"
+msgid "repository at '%s' has a format issue"
+msgstr "Repository bei '%s' hat ein Formatproblem"
+
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "Kein Repository in '%s' gefunden"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"um dieses Repository von Scalar abzumelden, führen Sie aus\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
msgid ""
"scalar run <task> [<enlistment>]\n"
@@ -20254,6 +21065,21 @@ msgid "unknown action: %d"
msgstr "Unbekannte Aktion: %d"
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 ""
+"Lösen Sie alle Konflikte manuell auf, markieren Sie diese mit\n"
+"\"git add/rm <konfliktbehaftete_Dateien>\" und führen Sie dann\n"
+"\"git rebase --continue\" aus.\n"
+"Sie können auch stattdessen diesen Commit auslassen, indem\n"
+"Sie \"git rebase --skip\" ausführen.\n"
+"Um abzubrechen und zurück zum Zustand vor \"git rebase\" zu gelangen,\n"
+"führen Sie \"git rebase --abort\" aus."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -20481,10 +21307,6 @@ msgid "could not update %s"
msgstr "Konnte %s nicht aktualisieren."
#, c-format
-msgid "could not parse commit %s"
-msgstr "Konnte Commit %s nicht parsen."
-
-#, c-format
msgid "could not parse parent commit %s"
msgstr "Konnte Eltern-Commit %s nicht parsen."
@@ -20552,10 +21374,6 @@ msgid "%s: cannot parse parent commit %s"
msgstr "%s: kann Eltern-Commit %s nicht parsen"
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "Konnte '%s' nicht zu '%s' umbenennen."
-
-#, c-format
msgid "could not revert %s... %s"
msgstr "Konnte \"revert\" nicht auf %s... (%s) ausführen"
@@ -20590,12 +21408,52 @@ msgstr ""
"refs/heads/%s"
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "ungültiger Befehl '%.*s'"
+msgid "'%s' does not accept merge commits"
+msgstr "'%s' akzeptiert keine Merge-Commits"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"'pick' nimmt keinen Merge-Commit an. Wenn Sie den Merge wiederholen\n"
+"wollen, verwenden Sie 'merge -C' auf den Commit."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"'reword' erfordert keinen Merge-Commit. Wenn Sie\n"
+"den Merge wiederholen und die Commit-Nachricht\n"
+"neu formulieren wollen, verwenden Sie\n"
+"'merge -c' auf den Commit"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"'edit' nimmt keinen Merge-Commit an. Wenn Sie den Merge wiederholen\n"
+"wollen, verwenden Sie 'merge -C' auf den Commit und dann\n"
+"break', um die Kontrolle zurückzugewinnen, sodass Sie\n"
+"'git commit --amend && git rebase --continue' ausführen können."
+
+msgid "cannot squash merge commit into another commit"
+msgstr "kann einen Merge-Commit nicht mit einem anderen Commit zusammenfassen"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s akzeptiert keine Argumente: '%s'"
+msgid "invalid command '%.*s'"
+msgstr "ungültiger Befehl '%.*s'"
#, c-format
msgid "missing arguments for %s"
@@ -20711,9 +21569,8 @@ msgstr ""
msgid "cannot read HEAD"
msgstr "kann HEAD nicht lesen"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "konnte '%s' nicht nach '%s' kopieren"
+msgid "could not write commit message file"
+msgstr "konnte keine Commit-Beschreibungsdatei schreiben"
#, c-format
msgid ""
@@ -20884,6 +21741,9 @@ msgstr "Beim Anwenden des automatischen Stash traten Konflikte auf."
msgid "Autostash exists; creating a new stash entry."
msgstr "Automatischer Stash existiert; ein neuer Stash-Eintrag wird erstellt."
+msgid "autostash reference is a symref"
+msgstr "Referenz für autostash ist eine symbolische Referenz"
+
msgid "could not detach HEAD"
msgstr "konnte HEAD nicht loslösen"
@@ -20917,14 +21777,14 @@ msgstr ""
" git rebase --continue\n"
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "Rebase (%d/%d)%s"
-
-#, c-format
msgid "Stopped at %s... %.*s\n"
msgstr "Angehalten bei %s... %.*s\n"
#, c-format
+msgid "Rebasing (%d/%d)%s"
+msgstr "Rebase (%d/%d)%s"
+
+#, c-format
msgid "unknown command %d"
msgstr "Unbekannter Befehl %d"
@@ -21060,6 +21920,10 @@ msgstr ""
"Konnte Arbeitsverzeichnis mit ungültiger Konfiguration nicht einrichten."
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "'%s' bereits als '%s' angegeben"
+
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "Erwartete Git-Repository-Version <= %d, %d gefunden"
@@ -21116,6 +21980,22 @@ msgstr "Kann nicht zum aktuellen Arbeitsverzeichnis zurückwechseln."
msgid "failed to stat '%*s%s%s'"
msgstr "Konnte '%*s%s%s' nicht lesen."
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' nicht absolut"
+
+#, 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 ""
+"dubiose Besitzverhältnisse im Repository bei '%s' entdeckt\n"
+"%sUm eine Ausnahme für dieses Verzeichnis hinzuzufügen, rufen Sie auf:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
msgid "Unable to read current working directory"
msgstr "Konnte aktuelles Arbeitsverzeichnis nicht lesen."
@@ -21137,18 +22017,6 @@ msgstr ""
"Stoppe bei Dateisystemgrenze (GIT_DISCOVERY_ACROSS_FILESYSTEM nicht gesetzt)."
#, 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 ""
-"dubiose Besitzverhältnisse im Repository bei '%s' entdeckt\n"
-"%sUm eine Ausnahme für dieses Verzeichnis hinzuzufügen, rufen Sie auf:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-
-#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
msgstr ""
"kann Bare-Repository '%s' nicht verwenden (safe.bareRepository ist '%s')"
@@ -21193,7 +22061,7 @@ msgstr "ignoriere Vorlage %s"
#, c-format
msgid "templates not found in %s"
-msgstr "Keine Vorlagen in %s gefunden."
+msgstr "keine Vorlagen in %s gefunden"
#, c-format
msgid "not copying templates from '%s': %s"
@@ -21204,25 +22072,31 @@ msgid "invalid initial branch name: '%s'"
msgstr "ungültiger initialer Branchname: '%s'"
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "Neu-Initialisierung: --initial-branch=%s ignoriert"
+
+#, 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"
+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"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr ""
+"Versuch, das Repository mit einem anderen Referenzspeicherformat neu zu "
+"initialisieren"
+
#, 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"
@@ -21245,6 +22119,21 @@ msgstr "Index-Eintrag ist ein Verzeichnis, aber nicht partiell (%08x)"
msgid "cannot use split index with a sparse index"
msgstr "kann aufgeteilten Index nicht mit einem Sparse-Index benutzen"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "ungültiges %s-Format: Element '%s' beginnt nicht mit '('"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "ungültiges %s-Format: Element '%s' endet nicht auf ')'"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "ungültiges %s-Format: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
msgid "%u.%2.2u GiB"
@@ -21435,6 +22324,14 @@ msgstr ""
"Git-Verzeichnis des Submoduls '%s' ist im Git-Verzeichnis '%.*s' enthalten."
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr "erwartete, dass '%.*s' im Submodulpfad '%s' kein symbolischer Link ist"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "erwartete, dass der Submodulpfad '%s' kein symbolischer Link ist"
+
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
@@ -21473,10 +22370,6 @@ msgstr "'lstat' für '%s' fehlgeschlagen"
msgid "no remote configured to get bundle URIs from"
msgstr "kein Remote-Repository zum Erhalten von Bundle-URIs konfiguriert"
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "Remote-Repository '%s' hat keine konfigurierte URL"
-
msgid "could not get the bundle-uri list"
msgstr "konnte die Bundle-uri-Liste nicht erhalten"
@@ -21491,12 +22384,6 @@ msgstr ""
"Anzahl der Einträge im Cache-Verzeichnis, die ungültig gemacht werden sollen "
"(Standardwert 0)"
-msgid "unhandled options"
-msgstr "unbehandelte Optionen"
-
-msgid "error preparing revisions"
-msgstr "Fehler beim Vorbereiten der Commits"
-
#, c-format
msgid "commit %s is not marked reachable"
msgstr "Commit %s ist nicht als erreichbar gekennzeichnet."
@@ -21565,6 +22452,24 @@ msgstr "Token"
msgid "command token to send to the server"
msgstr "Befehlstoken, der an den Server gesendet werden soll"
+msgid "unit-test [<options>]"
+msgstr "unit-test [<Optionen>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "beim ersten fehlgeschlagenen Test sofort abbrechen"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "nur Testsuite oder einzelnen Test ausführen <suite[::test]>"
+
+msgid "suite"
+msgstr "Suite"
+
+msgid "exclude test suite <suite>"
+msgstr "Testsuite <Suite> ausschließen"
+
#, c-format
msgid "running trailer command '%s' failed"
msgstr "Ausführen des Anhang-Befehls '%s' fehlgeschlagen"
@@ -21577,29 +22482,6 @@ msgstr "unbekannter Wert '%s' für Schlüssel %s"
msgid "empty trailer token in trailer '%.*s'"
msgstr "leerer Anhang-Token in Anhang '%.*s'"
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "Konnte Eingabe-Datei '%s' nicht lesen"
-
-#, c-format
-msgid "could not stat %s"
-msgstr "Konnte '%s' nicht lesen"
-
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "Datei '%s' ist keine reguläre Datei"
-
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "Datei %s ist vom Benutzer nicht beschreibbar."
-
-msgid "could not open temporary file"
-msgstr "konnte temporäre Datei '%s' nicht öffnen"
-
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "konnte temporäre Datei nicht zu %s umbenennen"
-
msgid "full write to remote helper failed"
msgstr "Vollständiges Schreiben zu Remote-Helper fehlgeschlagen."
@@ -21652,9 +22534,6 @@ msgstr ""
msgid "invalid remote service path"
msgstr "ungültiger Remote-Service Pfad."
-msgid "operation not supported by protocol"
-msgstr "die Operation wird von dem Protokoll nicht unterstützt"
-
#, c-format
msgid "can't connect to subservice %s"
msgstr "kann keine Verbindung zu Subservice %s herstellen"
@@ -21701,8 +22580,8 @@ msgid "remote-helper doesn't support push; refspec needed"
msgstr "Remote-Helper unterstützt kein Push; Refspec benötigt"
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "Remote-Helper %s unterstützt kein 'force'."
+msgid "helper %s does not support '--force'"
+msgstr "Helper %s unterstützt '--force' nicht"
msgid "couldn't run fast-export"
msgstr "Konnte \"fast-export\" nicht ausführen."
@@ -21785,10 +22664,6 @@ msgid "support for protocol v2 not implemented yet"
msgstr "Unterstützung für Protokoll v2 noch nicht implementiert."
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "Unbekannter Wert für Konfiguration '%s': %s"
-
-#, c-format
msgid "transport '%s' not allowed"
msgstr "Übertragungsart '%s' nicht erlaubt."
@@ -21841,6 +22716,9 @@ msgstr "bundle-uri Operation wird vom Protokoll nicht unterstützt"
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "konnte die vom Server angekündigte bundle-uri-Liste nicht abrufen"
+msgid "operation not supported by protocol"
+msgstr "die Operation wird von dem Protokoll nicht unterstützt"
+
msgid "too-short tree object"
msgstr "zu kurzes Tree-Objekt"
@@ -22136,6 +23014,10 @@ msgstr "ungültige Portnummer"
msgid "invalid '..' path segment"
msgstr "ungültiges '..' Pfadsegment"
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "Fehler: Meldung kann nicht formatiert werden: %s\n"
+
msgid "usage: "
msgstr "Verwendung: "
@@ -22248,6 +23130,9 @@ msgstr "konnte nicht auf '%s' zugreifen"
msgid "unable to get current working directory"
msgstr "konnte aktuelles Arbeitsverzeichnis nicht bekommen"
+msgid "unable to get random bytes"
+msgstr "konnte keine Zufallsbytes abrufen"
+
msgid "Unmerged paths:"
msgstr "Nicht zusammengeführte Pfade:"
@@ -22726,6 +23611,10 @@ msgid "cannot %s: Your index contains uncommitted changes."
msgstr ""
"%s nicht möglich: Die Staging-Area enthält nicht committete Änderungen."
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "unbekannter Stil '%s' für '%s' angegeben"
+
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22830,6 +23719,10 @@ msgstr "'%s.final' enthält die verfasste E-Mail.\n"
msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases ist mit anderen Optionen inkompatibel\n"
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr ""
+"--dump-aliases und --translate-aliases schließen sich gegenseitig aus\n"
+
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -22930,13 +23823,13 @@ msgstr ""
"möchten.\n"
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "Fehler beim Öffnen von %s: %s"
-
-#, perl-format
msgid "Failed to open %s.final: %s"
msgstr "Fehler beim Öffnen von %s.final: %s"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "Fehler beim Öffnen von %s: %s"
+
msgid "Summary email is empty, skipping it\n"
msgstr "E-Mail mit Zusammenfassung ist leer, wird ausgelassen\n"
@@ -23054,24 +23947,24 @@ msgid "Failed to send %s\n"
msgstr "Fehler beim Senden %s\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Probeversand %s\n"
+msgid "Dry-Sent %s"
+msgstr "Probeversand %s"
#, perl-format
-msgid "Sent %s\n"
-msgstr "%s gesendet\n"
+msgid "Sent %s"
+msgstr "%s gesendet"
-msgid "Dry-OK. Log says:\n"
-msgstr "Probeversand OK. Log enthält:\n"
+msgid "Dry-OK. Log says:"
+msgstr "Probelauf OK. Das Protokoll enthält:"
-msgid "OK. Log says:\n"
-msgstr "OK. Log enthält:\n"
+msgid "OK. Log says:"
+msgstr "OK. Das Protokoll enthält:"
msgid "Result: "
msgstr "Ergebnis: "
-msgid "Result: OK\n"
-msgstr "Ergebnis: OK\n"
+msgid "Result: OK"
+msgstr "Ergebnis: OK"
#, perl-format
msgid "can't open file %s"
diff --git a/po/fr.po b/po/fr.po
index 68a4d45fd8..481e1bdc1d 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -21,6 +21,7 @@
# bypass | éviter d'utiliser
# to checkout | extraire
# cherry-pick | picorer
+# chunk | tronçon
# to commit | valider
# commit-ish | commit ou apparenté
# config file | fichier de configuration
@@ -29,6 +30,7 @@
# debugging | débogage
# to deflate | compresser
# email | courriel
+# enlistment | enrôlement
# entry | élément
# fanout | dispersion
# fast-forward | avance rapide
@@ -78,8 +80,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-08-16 11:48+0200\n"
-"PO-Revision-Date: 2023-08-16 11:49+0200\n"
+"POT-Creation-Date: 2024-10-02 16:57+0000\n"
+"PO-Revision-Date: 2024-10-04 23:03+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"
@@ -574,12 +576,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"Pour éliminer les lignes '%c', rendez-les ' ' (contexte).\n"
"Pour éliminer les lignes '%c', effacez-les.\n"
-"Les lignes commençant par %c seront éliminées.\n"
+"Les lignes commençant par %s seront éliminées.\n"
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
@@ -626,6 +628,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j - laisser cette section non décidée et aller à la suivante non-décidée\n"
@@ -636,8 +639,13 @@ msgstr ""
"/ - rechercher une section correspondant à une regex donnée\n"
"s - découper la section en sections plus petites\n"
"e - éditer manuellement la section actuelle\n"
+"p - afficher la section actuelle, 'P' pour utiliser un paginateur\n"
"? - afficher l'aide\n"
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "une seule lettre est attendue, mais '%s' a été reçu"
+
msgid "No previous hunk"
msgstr "Pas de section précédente"
@@ -686,9 +694,19 @@ msgstr "Découpée en %d sections."
msgid "Sorry, cannot edit this hunk"
msgstr "Désolé, impossible d'éditer cette section"
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "commande inconnue : '%s' (utilisez '?' pour de l'aide)"
+
msgid "'git apply' failed"
msgstr "'git apply' a échoué"
+msgid "No changes."
+msgstr "Aucune modification."
+
+msgid "Only binary files changed."
+msgstr "Seuls des fichiers binaires ont changé."
+
#, c-format
msgid ""
"\n"
@@ -698,8 +716,8 @@ msgstr ""
"Désactivez ce message avec \"git config advice.%s false\""
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sastuce: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sastuce :%s%.*s%s\n"
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr "Impossible de picorer car vous avez des fichiers non fusionnés."
@@ -1215,10 +1233,6 @@ msgstr[0] "Application du patch %%s avec %d rejet..."
msgstr[1] "Application du patch %%s avec %d rejets..."
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "troncature du nom de fichier .rej en %.*s.rej"
-
-#, c-format
msgid "cannot open %s"
msgstr "impossible d'ouvrir %s"
@@ -1316,6 +1330,15 @@ msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr ""
"tenter une fusion à 3 points, revenir à un rustinage normal en cas d'échec"
+msgid "for conflicts, use our version"
+msgstr "pour les conflits, utiliser notre version (our)"
+
+msgid "for conflicts, use their version"
+msgstr "pour les conflits, utiliser leur version (their)"
+
+msgid "for conflicts, use a union version"
+msgstr "pour les conflits, utiliser l'union des versions"
+
msgid "build a temporary index based on embedded index information"
msgstr ""
"construire un index temporaire fondé sur l'information de l'index embarqué"
@@ -1366,6 +1389,9 @@ msgstr "préfixer tous les noms de fichier avec <root>"
msgid "don't return error for empty patches"
msgstr "ne pas renvoyer d'erreur pour les rustines vides"
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs et --union requièrent --3way"
+
#, c-format
msgid "cannot stream blob %s"
msgstr "impossible de transmettre le blob %s en flux"
@@ -1439,6 +1465,9 @@ msgstr "nom d'objet invalide : %s"
msgid "not a tree object: %s"
msgstr "objet arbre invalide : %s"
+msgid "unable to checkout working tree"
+msgstr "impossible d'extraire la copie de travail"
+
#, c-format
msgid "File not found: %s"
msgstr "Fichier non trouvé : %s"
@@ -1524,6 +1553,10 @@ msgid "Unexpected option --output"
msgstr "Option --output inattendue"
#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "paramètre de commande supplémentaire '%s'"
+
+#, c-format
msgid "Unknown archive format '%s'"
msgstr "Format d'archive inconnu '%s'"
@@ -1565,10 +1598,21 @@ msgstr "fichier gitattributes trop gros ignoré '%s'"
msgid "ignoring overly large gitattributes blob '%s'"
msgstr "blob gitattributes trop gros ignoré '%s'"
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "impossible d'utiliser --attr-source ou GIT_ATTR_SOURCE sans dépôt"
+
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "mauvais --attr-source ou GIT_ATTR_SOURCE"
#, c-format
+msgid "unable to stat '%s'"
+msgstr "fstat de '%s' impossible"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "impossible de lire %s"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Contenu mal cité dans le fichier '%s' : %s"
@@ -1638,6 +1682,10 @@ msgid "could not create file '%s'"
msgstr "impossible de créer le fichier '%s'"
#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "impossible de démarrer 'show' pour l'objet '%s'"
+
+#, c-format
msgid "could not read file '%s'"
msgstr "impossible de lire le fichier '%s'"
@@ -1787,6 +1835,9 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "'%s' n'est pas un nom de branche valide"
+msgid "See `man git check-ref-format`"
+msgstr "Voir `man git check-ref-format`"
+
#, c-format
msgid "a branch named '%s' already exists"
msgstr "Une branche nommée '%s' existe déjà"
@@ -1855,8 +1906,8 @@ msgid "submodule '%s': cannot create branch '%s'"
msgstr "sous-module '%s' : impossible de créer la branche '%s'"
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "'%s' est déjà extrait dans '%s'"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "'%s' est déjà utilisé par l'arbre-de-travail dans '%s'"
msgid "git add [<options>] [--] <pathspec>..."
msgstr "git add [<options>] [--] <chemin>..."
@@ -1868,32 +1919,22 @@ msgstr "impossible de chmod %cx '%s'"
msgid "Unstaged changes after refreshing the index:"
msgstr "Modifications non indexées après rafraîchissement de l'index :"
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"le réglage add.interactive.useBuiltin a été supprimé !\n"
-"Référez-vous à cette entrée dans 'git help config' pour plus de détails."
-
-msgid "Could not read the index"
-msgstr "Impossible de lire l'index"
-
-msgid "Could not write patch"
-msgstr "Impossible d'écrire le patch"
+msgid "could not read the index"
+msgstr "impossible de lire l'index"
msgid "editing patch failed"
msgstr "échec de l'édition du patch"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Stat de '%s' impossible"
+msgid "could not stat '%s'"
+msgstr "impossible de stat '%s'"
-msgid "Empty patch. Aborted."
-msgstr "Patch vide. Abandon."
+msgid "empty patch. aborted"
+msgstr "rustine vide. abandon"
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Impossible d'appliquer '%s'"
+msgid "could not apply '%s'"
+msgstr "impossible d'appliquer '%s'"
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
@@ -1989,14 +2030,8 @@ msgstr ""
msgid "adding embedded git repository: %s"
msgstr "dépôt git embarqué ajouté : %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 ""
-"Utilisez -f si vous voulez vraiment les ajouter.\n"
-"Éliminez ce message en lançant\n"
-"\"git config advice.addIgnoredFile false\""
+msgid "Use -f if you really want to add them."
+msgstr "Utilisez -f si vous voulez vraiment les ajouter<."
msgid "adding files failed"
msgstr "échec de l'ajout de fichiers"
@@ -2015,18 +2050,15 @@ msgstr ""
msgid "Nothing specified, nothing added.\n"
msgstr "Rien de spécifié, rien n'a été ajouté.\n"
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Peut-être avez-vous voulu dire 'git add .' ?\n"
-"Éliminez ce message en lançant\n"
-"\"git config advice.addEmptyPathspec false\""
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Vous vouliez sûrement utiliser 'git add .' ?"
msgid "index file corrupt"
msgstr "fichier d'index corrompu"
+msgid "unable to write new index file"
+msgstr "impossible d'écrire le nouveau fichier d'index"
+
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "action invalide '%s' pour '%s'"
@@ -2096,18 +2128,19 @@ msgid "Failed to split patches."
msgstr "Échec de découpage des patchs."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Quand vous avez résolu ce problème, lancez \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "Quand vous avez résolu ce problème, lancez \"%s --continue\".\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "Si vous préférez plutôt sauter ce patch, lancez \"%s --skip\"."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr "Si vous préférez plutôt sauter cette rustine, lancez \"%s --skip\".\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
"Pour enregistrer la rustine vide comme un commit vide, lancez \"%s --allow-"
-"empty\"."
+"empty\".\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
@@ -2236,9 +2269,6 @@ msgstr ""
"Vous pouvez lancer 'git rm' sur un fichier \"supprimé par eux\" pour "
"accepter son état."
-msgid "unable to write new index file"
-msgstr "impossible d'écrire le nouveau fichier d'index"
-
#, c-format
msgid "Could not parse object '%s'."
msgstr "Impossible d'analyser l'objet '%s'."
@@ -2257,10 +2287,6 @@ msgstr ""
msgid "failed to read '%s'"
msgstr "échec de la lecture de '%s'"
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "les options '%s=%s' et '%s=%s' ne peuvent pas être utilisées ensemble"
-
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<options>] [(<mbox> | <Maildir>)...]"
@@ -2339,6 +2365,9 @@ msgstr "abandonne l'opération de patch mais garde HEAD où il est"
msgid "show the patch being applied"
msgstr "afficher le patch en cours d'application"
+msgid "try to apply current patch again"
+msgstr "essayer d'appliquer de nouveau la rustine"
+
msgid "record the empty patch as an empty commit"
msgstr "enregistrer la rustine vide comme un commit vide"
@@ -2397,9 +2426,6 @@ msgstr "git apply [<options>] [<patch>...]"
msgid "could not redirect output"
msgstr "impossible de rediriger la sortie"
-msgid "git archive: Remote with no URL"
-msgstr "git archive : Dépôt distant sans URL"
-
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive : ACK/NACK attendu, paquet de nettoyage reçu"
@@ -2414,7 +2440,7 @@ msgid "git archive: expected a flush"
msgstr "git archive : vidage attendu"
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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}=<terme> --term-{old,good}=<terme>] [--"
@@ -2433,8 +2459,8 @@ msgstr "git bisect reset [<commit>]"
msgid "git bisect replay <logfile>"
msgstr "git bisect replay <fichier-journal>"
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <cmd>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <cmd> [<arg>...]"
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2555,9 +2581,6 @@ msgstr ""
"Les options supportées sont : --term-good|--term-old et --term-bad|--term-"
"new."
-msgid "revision walk setup failed\n"
-msgstr "échec de la préparation du parcours des révisions\n"
-
#, c-format
msgid "could not open '%s' for appending"
msgstr "impossible d'ouvrir '%s' en ajout"
@@ -2861,44 +2884,46 @@ msgstr "git branch [<options>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
"suppression de la branche '%s' qui a été fusionnée dans\n"
-" '%s', mais pas dans HEAD."
+" '%s', mais pas encore dans HEAD"
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
-"branche '%s' non supprimée car elle n'a pas été fusionnée dans\n"
-" '%s', même si elle est fusionnée dans HEAD."
+"branche '%s' non supprimée car elle n'a pas encore été fusionnée dans\n"
+" '%s', même si elle est fusionnée dans HEAD"
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Impossible de rechercher l'objet commit pour '%s'"
+msgid "couldn't look up commit object for '%s'"
+msgstr "impossible de rechercher l'objet commit pour '%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 ""
-"La branche '%s' n'est pas totalement fusionnée.\n"
-"Si vous souhaitez réellement la supprimer, lancez 'git branch -D %s'."
+msgid "the branch '%s' is not fully merged"
+msgstr "la branche '%s' n'est pas complètement fusionnée"
-msgid "Update of config-file failed"
-msgstr "Échec de la mise à jour du fichier de configuration"
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "Si vous souhaitez réellement la supprimer, lancez 'git branch -D %s'"
+
+msgid "update of config-file failed"
+msgstr "échec de la mise à jour du fichier de configuration"
msgid "cannot use -a with -d"
msgstr "impossible d'utiliser -a avec -d"
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "Impossible de supprimer la branche '%s' extraite dans '%s'"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"impossible de supprimer la branche '%s' utilisée par l'arbre-de-travail dans "
+"'%s'"
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "branche de suivi '%s' non trouvée."
+msgid "remote-tracking branch '%s' not found"
+msgstr "branche de suivi '%s' non trouvée"
#, c-format
msgid ""
@@ -2909,8 +2934,8 @@ msgstr ""
"Avez-vous oublié --remote ?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "branche '%s' non trouvée."
+msgid "branch '%s' not found"
+msgstr "branche '%s' non trouvée"
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -2931,66 +2956,66 @@ msgid "HEAD (%s) points outside of refs/heads/"
msgstr "HEAD (%s) pointe hors de refs/heads/"
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "La branche %s est en cours de rebasage sur %s"
+msgid "branch %s is being rebased at %s"
+msgstr "la branche %s est en cours de rebasage sur %s"
#, c-format
-msgid "Branch %s is being bisected at %s"
-msgstr "La branche %s est en cours de bissection 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'"
+msgid "invalid branch name: '%s'"
+msgstr "nom de branche invalide : '%s'"
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Aucun commit sur la branche '%s'."
+msgid "no commit on branch '%s' yet"
+msgstr "aucun commit encore sur la branche '%s'"
#, c-format
-msgid "No branch named '%s'."
-msgstr "Aucune branche nommée '%s'."
+msgid "no branch named '%s'"
+msgstr "aucune branche nommée '%s'"
-msgid "Branch rename failed"
-msgstr "Échec de renommage de la branche"
+msgid "branch rename failed"
+msgstr "échec de renommage de la branche"
-msgid "Branch copy failed"
-msgstr "Échec de copie de la branche"
+msgid "branch copy failed"
+msgstr "échec de copie de la branche"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Création d'une copie d'une branche mal nommée '%s'"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "création d'une copie d'une branche mal nommée '%s'"
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Renommage d'une branche mal nommée '%s'"
+msgid "renamed a misnamed branch '%s' away"
+msgstr "renommage d'une branche mal nommée '%s'"
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "La branche a été renommée en %s, mais HEAD n'est pas mise à jour !"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "la branche a été renommée en %s, mais HEAD n'est pas mise à jour"
-msgid "Branch is renamed, but update of config-file failed"
+msgid "branch is renamed, but update of config-file failed"
msgstr ""
-"La branche est renommée, mais la mise à jour du fichier de configuration a "
+"la branche est renommée, mais la mise à jour du fichier de configuration a "
"échoué"
-msgid "Branch is copied, but update of config-file failed"
+msgid "branch is copied, but update of config-file failed"
msgstr ""
-"La branche est copiée, mais la mise à jour du fichier de configuration a "
+"la branche est copiée, mais la mise à jour du fichier de configuration a "
"échoué"
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Veuillez éditer la description de la branche\n"
" %s\n"
-"Les lignes commençant par '%c' seront ignorées.\n"
+"Les lignes commençant par '%s' seront ignorées.\n"
msgid "Generic options"
msgstr "Options génériques"
@@ -3094,8 +3119,8 @@ msgstr "parcourir récursivement les sous-modules"
msgid "format to use for the output"
msgstr "format à utiliser pour la sortie"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Échec de résolution de HEAD comme référence valide."
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "échec de résolution de HEAD comme référence valide"
msgid "HEAD not found below refs/heads!"
msgstr "HEAD non trouvée sous refs/heads !"
@@ -3113,17 +3138,17 @@ msgstr "--recurse-submodules ne peut être utilisé que pour créer des branches
msgid "branch name required"
msgstr "le nom de branche est requis"
-msgid "Cannot give description to detached HEAD"
-msgstr "Impossible de décrire une HEAD détachée"
+msgid "cannot give description to detached HEAD"
+msgstr "impossible de décrire une HEAD détachée"
msgid "cannot edit description of more than one branch"
msgstr "impossible d'éditer la description de plus d'une branche"
-msgid "cannot copy the current branch while not on any."
-msgstr "impossible de copier la branche actuelle, il n'y en a pas."
+msgid "cannot copy the current branch while not on any"
+msgstr "impossible de copier la branche actuelle, il n'y en a pas"
-msgid "cannot rename the current branch while not on any."
-msgstr "impossible de renommer la branche actuelle, il n'y en a pas."
+msgid "cannot rename the current branch while not on any"
+msgstr "impossible de renommer la branche actuelle, il n'y en a pas"
msgid "too many branches for a copy operation"
msgstr "trop de branches pour une opération de copie"
@@ -3136,10 +3161,10 @@ msgstr "trop d'arguments pour spécifier une branche amont"
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
"impossible de spécifier une branche amont de HEAD par %s qui ne pointe sur "
-"aucune branche."
+"aucune branche"
#, c-format
msgid "no such branch '%s'"
@@ -3152,29 +3177,29 @@ msgstr "la branche '%s' n'existe pas"
msgid "too many arguments to unset upstream"
msgstr "trop d'arguments pour désactiver un amont"
-msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
msgstr ""
"impossible de désactiver une branche amont de HEAD quand elle ne pointe sur "
-"aucune branche."
+"aucune branche"
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "La branche '%s' n'a aucune information de branche amont"
+msgid "branch '%s' has no upstream information"
+msgstr "la branche '%s' n'a aucune information de branche amont"
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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 ""
-"Les options -a et -r de 'git branch' n'ont pas de sens avec un nom de "
+"les options -a et -r de 'git branch' n'ont pas de sens avec un nom de "
"branche.\n"
"Vouliez-vous plutôt dire -a|-r --list <motif> ?"
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
"l'option '--set-upstream' est obsolète. Utilisez '--track' ou '--set-"
-"upstream-to' à la place."
+"upstream-to' à la place"
msgid "git version:\n"
msgstr "version git ::\n"
@@ -3193,11 +3218,12 @@ msgid "not run from a git repository - no hooks to show\n"
msgstr "lancé hors d'un dépôt git - aucun crochet à montrer\n"
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <chemin>] [(-s | --suffix) "
-"<format>]\n"
+"git bugreport [(-o | --output-directory) <chemin>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgid ""
@@ -3252,6 +3278,10 @@ msgid "specify a strftime format suffix for the filename(s)"
msgstr "spécifier une suffixe au format strftime pour le(s) nom(s) de fichier"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "argument inconnu '%s'"
+
+#, c-format
msgid "could not create leading directories for '%s'"
msgstr "impossible de créer les répertoires de premier niveau pour '%s'"
@@ -3313,6 +3343,9 @@ msgstr "La création d'un colis requiert un dépôt."
msgid "do not show bundle details"
msgstr "ne pas afficher les détails du colis"
+msgid "need a repository to verify a bundle"
+msgstr "la vérification d'un colis requiert un dépôt"
+
#, c-format
msgid "%s is okay\n"
msgstr "%s est correct\n"
@@ -3343,7 +3376,7 @@ msgstr "%s nécessite des arguments"
#, c-format
msgid "%s takes no arguments"
-msgstr "%s n'accepte aucune argument"
+msgstr "%s n'accepte aucun argument"
msgid "only one batch option may be specified"
msgstr "une seule option de traitement ne peut être spécifiée à la fois"
@@ -3358,6 +3391,13 @@ msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <objet>"
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<chemin|arbresque> | --path=<chemin|arbresque> <rev>]"
+
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -3368,13 +3408,6 @@ msgstr ""
" [--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"
-" [<rev>:<chemin|arbresque> | --path=<chemin|arbresque> <rev>]"
-
msgid "Check object existence or emit object contents"
msgstr "Vérifie l'existence d'un objet ou émettre le contenu de l'objet"
@@ -3548,9 +3581,14 @@ msgstr "git check-mailmap [<options>] <contact>..."
msgid "also read contacts from stdin"
msgstr "lire aussi les contacts depuis l'entrée standard"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "impossible d'analyser le contact : %s"
+msgid "read additional mailmap entries from file"
+msgstr "lire des entrées supplémentaires de mailmap depuis un fichier"
+
+msgid "blob"
+msgstr "blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "lire des entrées supplémentaires depuis un blob"
msgid "no contacts specified"
msgstr "aucun contact spécifié"
@@ -3676,9 +3714,19 @@ msgid "'%s' or '%s' cannot be used with %s"
msgstr "'%s' ou '%s' ne peut pas être utilisé avec %s"
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr ""
+"'%s', '%s' ou '%s' ne peuvent pas être utilisés lors de l'extraction d'un "
+"arbre"
+
+#, c-format
msgid "path '%s' is unmerged"
msgstr "le chemin '%s' n'est pas fusionné"
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "impossible de lire l'arbre (%s)"
+
msgid "you need to resolve your current index first"
msgstr "vous devez d'abord résoudre votre index courant"
@@ -3898,6 +3946,10 @@ msgid "'%s' cannot be used with switching branches"
msgstr "'%s' ne peut pas être utilisé avec un basculement de branches"
#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' requiert les chemins à extraire"
+
+#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s' ne peut pas être utilisé avec '%s'"
@@ -3912,6 +3964,10 @@ msgstr "Impossible de basculer de branche vers '%s' qui n'est pas un commit"
msgid "missing branch or commit argument"
msgstr "argument de branche ou de commit manquant"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "style de conflit inconnu '%s'"
+
msgid "perform a 3-way merge with the new branch"
msgstr "effectuer une fusion à 3 points avec la nouvelle branche"
@@ -3930,8 +3986,8 @@ msgstr "forcer l'extraction (laisser tomber les modifications locales)"
msgid "new-branch"
msgstr "nouvelle branche"
-msgid "new unparented branch"
-msgstr "nouvelle branche sans parent"
+msgid "new unborn branch"
+msgstr "nouvelle branche non née"
msgid "update ignored files (default)"
msgstr "mettre à jour les fichiers ignorés (par défaut)"
@@ -4171,22 +4227,9 @@ msgstr "supprimer les fichiers ignorés, aussi"
msgid "remove only ignored files"
msgstr "supprimer seulement les fichiers ignorés"
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce positionné à true et ni -i, -n ou -f fourni ; refus de "
-"nettoyer"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"clean.requireForce à true par défaut et ni -i, -n ou -f fourni ; refus de "
-"nettoyer"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x et -X ne peuvent pas être utilisés ensemble"
+"clean.requireForce positionné est true et -f non fourni ; refus de nettoyer"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<options>] [--] <dépôt> [<répertoire>]"
@@ -4200,8 +4243,8 @@ msgstr "ne pas créer d'extraction"
msgid "create a bare repository"
msgstr "créer un dépôt nu"
-msgid "create a mirror repository (implies bare)"
-msgstr "créer un dépôt miroir (implique dépôt nu)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "créer un dépôt miroir (implique --bare)"
msgid "to clone from a local repository"
msgstr "pour cloner depuis un dépôt local"
@@ -4278,6 +4321,9 @@ msgstr "gitdir"
msgid "separate git dir from working tree"
msgstr "séparer le répertoire git de la copie de travail"
+msgid "specify the reference format to use"
+msgstr "spécifier le format de réference à utiliser"
+
msgid "key=value"
msgstr "clé=valeur"
@@ -4339,6 +4385,14 @@ msgid "failed to unlink '%s'"
msgstr "échec pour délier '%s'"
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "le lien dur ne peut pas être vérifier à '%s'"
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "le lien dur est différent de la source à '%s'"
+
+#, c-format
msgid "failed to create link '%s'"
msgstr "échec de la création du lien '%s'"
@@ -4382,9 +4436,6 @@ msgstr ""
"la HEAD distante réfère à une référence non existante, impossible de "
"l'extraire"
-msgid "unable to checkout working tree"
-msgstr "impossible d'extraire la copie de travail"
-
msgid "unable to write parameters to config file"
msgstr "impossible d'écrire les paramètres dans le fichier de configuration"
@@ -4400,12 +4451,9 @@ msgstr "Trop d'arguments."
msgid "You must specify a repository to clone."
msgstr "Vous devez spécifier un dépôt à cloner."
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr ""
-"--bundle-uri est incompatible avec --depth, --shallow-since, et --shallow-"
-"exclude"
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "Format de stockage de réf inconnu '%s'"
#, c-format
msgid "repository '%s' does not exist"
@@ -4525,6 +4573,10 @@ msgstr "remplissage d'espace sur le côté droit"
msgid "padding space between columns"
msgstr "remplissage d'espace entre les colonnes"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s doit être non négatif"
+
msgid "--command must be the first argument"
msgstr "--command doit être le premier argument"
@@ -4539,14 +4591,14 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <rép>] [--append]\n"
" [--split[=<stratégie>]] [--reachable | --stdin-packs "
"| --stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <options de division>"
+" <options-de-division>"
msgid "dir"
msgstr "répertoire"
@@ -4563,6 +4615,10 @@ msgid "Could not open commit-graph '%s'"
msgstr "Impossible d'ouvrir le graphe de commit '%s'"
#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "impossible d'ouvrir le graphe de commit '%s'"
+
+#, c-format
msgid "unrecognized --split argument, %s"
msgstr "argument de --split non reconnu, %s"
@@ -4669,7 +4725,7 @@ msgstr "git commit-tree : échec de la lecture"
msgid ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -4680,7 +4736,7 @@ msgstr ""
"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"
+" [-F <fichier> | -m <msg>] [--reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--author=<auteur>]\n"
" [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
" [-i | -o] [--pathspec-from-file=<fichier> [--pathspec-file-nul]]\n"
@@ -4762,9 +4818,6 @@ msgstr "impossible de mettre à jour l'index temporaire"
msgid "Failed to update main cache tree"
msgstr "Impossible de mettre à jour l'arbre de cache principal"
-msgid "unable to write new_index file"
-msgstr "impossible d'écrire le fichier new_index"
-
msgid "cannot do a partial commit during a merge."
msgstr "impossible de faire une validation partielle pendant une fusion."
@@ -4837,38 +4890,38 @@ msgstr "impossible d'écrire le modèle de commit"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
-"commençant par '%c' seront ignorées.\n"
+"commençant par '%s' seront ignorées.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
-"commençant par '%c' seront ignorées, et un message vide abandonne la "
+"commençant par '%s' seront ignorées, et un message vide abandonne la "
"validation.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Veuillez saisir le message de validation pour vos modifications. Les lignes "
"commençant\n"
-"par '%c' seront conservées ; vous pouvez les supprimer vous-même si vous le "
+"par '%s' seront conservées ; vous pouvez les supprimer vous-même si vous le "
"souhaitez.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
-"commençant par '%c' seront conservées ; vous pouvez les supprimer vous-même\n"
+"commençant par '%s' seront conservées ; vous pouvez les supprimer vous-même\n"
"si vous le souhaitez. Un message vide abandonne la validation.\n"
msgid ""
@@ -5174,22 +5227,68 @@ msgstr ""
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"le dépôt a été mis à jour, mais impossible d'écrire le fichier\n"
-"new_index. Vérifiez que le disque n'est pas plein ou que le quota\n"
+"le dépôt a été mis à jour, mais impossible d'écrire le nouveau fichier\n"
+"d'index. Vérifiez que le disque n'est pas plein ou que le quota\n"
"n'a pas été dépassé, puis lancez \"git restore --staged :/\" pour réparer."
-msgid "git config [<options>]"
-msgstr "git config [<options>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr ""
+"git config list [<option-de-fichier>] [<option-d-affichage>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "argument --type non reconnu, %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<option-de-fichier>] [<option-d-affichage>] [--includes] [--"
+"all] [--regexp] [--value=<valeur>] [--fixed-value] [--default=<défaut>] "
+"<name>"
-msgid "only one type at a time"
-msgstr "qu'un seul type à la fois"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<option-de-fichier>] [--type=<type>] [--all] [--"
+"value=<valeur>] [--fixed-value] <nom> <valeur>"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<option-de-fichier>] [--all] [--value=<valeur>] [--fixed-"
+"value] <nom> <valeur>"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr ""
+"git config rename-section [<option-de-fichier>] <ancien-nom> <nouveau-nom>"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<option-de-fichier>] <nom>"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<option-de-fichier>]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr ""
+"git config [<option-de-fichier>] --get-colorbool <nom> [<stdout-est-tty>]"
+
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<option-de-fichier>] [<option-d-affichage>] [--includes] [--"
+"all] [--regexp=<regexp>] [--value=<valeur>] [--fixed-value] [--"
+"default=<défaut>] <name>"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<option-de-fichier>] [--type=<type>] [--comment=<message>] "
+"[--all] [--value=<valeur>] [--fixed-value] <nom> <valeur>"
msgid "Config file location"
msgstr "Emplacement du fichier de configuration"
@@ -5215,56 +5314,6 @@ msgstr "blob-id"
msgid "read config from given blob object"
msgstr "lire la configuration depuis l'objet blob fourni"
-msgid "Action"
-msgstr "Action"
-
-msgid "get value: name [value-pattern]"
-msgstr "obtenir la valeur : nom [motif-de-valeur]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "obtenir toutes les valeurs : clé [motif-de-valeur]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "obtenir les valeur pour la regexp : regex-de-nom [motif-de-valeur]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "obtenir la valeur spécifique pour l'URL : section[.var] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr ""
-"remplacer toutes les variables correspondant : nom valeur [motif-de-valeur]"
-
-msgid "add a new variable: name value"
-msgstr "ajouter une nouvelle variable : nom valeur"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "supprimer une variable : nom [motif-de-valeur]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "supprimer toutes les correspondances nom [motif-de-valeur]"
-
-msgid "rename section: old-name new-name"
-msgstr "renommer une section : ancien-nom nouveau-nom"
-
-msgid "remove a section: name"
-msgstr "supprimer une section : nom"
-
-msgid "list all"
-msgstr "afficher tout"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr ""
-"utiliser l'égalité de chaînes lors de la comparaison de 'motif-de-valeur'"
-
-msgid "open an editor"
-msgstr "ouvrir un éditeur"
-
-msgid "find the color configured: slot [default]"
-msgstr "trouver la couleur configurée : slot [par défaut]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "trouver le réglage de la couleur : slot [stdout-est-tty]"
-
msgid "Type"
msgstr "Type"
@@ -5292,8 +5341,8 @@ msgstr "la valeur est un chemin (vers un fichier ou un répertoire)"
msgid "value is an expiry date"
msgstr "la valeur est une date d'expiration"
-msgid "Other"
-msgstr "Autre"
+msgid "Display options"
+msgstr "Options d'affichage"
msgid "terminate values with NUL byte"
msgstr "terminer les valeurs avec un caractère NUL"
@@ -5301,9 +5350,6 @@ msgstr "terminer les valeurs avec un caractère NUL"
msgid "show variable names only"
msgstr "n'afficher que les noms de variable"
-msgid "respect include directives on lookup"
-msgstr "respecter les directives d'inclusion lors de la recherche"
-
msgid "show origin of config (file, standard input, blob, command line)"
msgstr ""
"afficher l'origine de la configuration (fichier, entrée standard, blob, "
@@ -5314,11 +5360,15 @@ msgstr ""
"afficher la portée de configuration (arbre de travail, local, global, "
"système, commande)"
-msgid "value"
-msgstr "valeur"
+msgid "show config keys in addition to their values"
+msgstr "afficher les clés de configuration en plus des valeurs"
-msgid "with --get, use default value when missing entry"
-msgstr "avec --get, utiliser le valeur par défaut quand l'entrée n'existe pas"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "argument --type non reconnu, %s"
+
+msgid "only one type at a time"
+msgstr "qu'un seul type à la fois"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5395,44 +5445,77 @@ msgstr ""
"la section \"CONFIGURATION FILE\" de \"git help worktree\" pour plus de "
"détails"
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color et le type de la variable sont incohérents"
+msgid "Other"
+msgstr "Autre"
-msgid "only one action at a time"
-msgstr "une seule action à la fois"
+msgid "respect include directives on lookup"
+msgstr "respecter les directives d'inclusion lors de la recherche"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only n'est applicable qu'avec --list ou --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "lecture du fichier de configuration '%s' impossible"
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
+msgid "error processing config file(s)"
+msgstr "erreur lors du traitement de fichier(s) de configuration"
+
+msgid "Filter options"
+msgstr "Options de filtre"
+
+msgid "return all values for multi-valued config options"
msgstr ""
-"--show-origin n'est applicable qu'avec --get, --get-all, --get-regexp ou --"
-"list"
+"renvoyer toutes les valeurs pour les options de configuration multi-valeurs"
-msgid "--default is only applicable to --get"
-msgstr "--default n'est applicable qu'avec --get"
+msgid "interpret the name as a regular expression"
+msgstr "interpréter le nom comme une expression régulière"
+
+msgid "show config with values matching the pattern"
+msgstr "afficher les configurations dont le nom correspond au motif"
+
+msgid "use string equality when comparing values to value pattern"
+msgstr ""
+"utiliser l'égalité de chaînes lors de la comparaison des valeurs au motif de "
+"valeur"
+
+msgid "URL"
+msgstr "URL"
+
+msgid "show config matching the given URL"
+msgstr "afficher les configs qui correspondent à l'URL donné"
+
+msgid "value"
+msgstr "valeur"
+
+msgid "use default value when missing entry"
+msgstr "utiliser le valeur par défaut quand l'entrée n'existe pas"
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value ne s'applique qu'à 'motif-de-valeur'"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "lecture du fichier de configuration '%s' impossible"
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= ne peut pas être utilisé avec --all ou --url="
-msgid "error processing config file(s)"
-msgstr "erreur lors du traitement de fichier(s) de configuration"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= ne peut pas être utilisé avec --all, --regexp ou --value"
-msgid "editing stdin is not supported"
-msgstr "l'édition de stdin n'est pas supportée"
+msgid "Filter"
+msgstr "Filtre"
-msgid "editing blobs is not supported"
-msgstr "l'édition de blobs n'est pas supportée"
+msgid "replace multi-valued config option with new value"
+msgstr "remplacer l'option de config multi-valeur par la nouvelle valeur"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "création impossible du fichier de configuration '%s'"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr ""
+"chaîne des commentaires lisibles par l'utilisateur (# sera ajouté en préfixe "
+"selon les besoins)"
+
+msgid "add a new line without altering any existing values"
+msgstr "ajouter une nouvelle ligne sans modifier les valeurs existantes"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value ne s'applique qu'avec --value=<motif>"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append ne s'applique pas avec --value=<motif>"
#, c-format
msgid ""
@@ -5446,6 +5529,87 @@ msgstr ""
msgid "no such section: %s"
msgstr "section inexistante : %s"
+msgid "editing stdin is not supported"
+msgstr "l'édition de stdin n'est pas supportée"
+
+msgid "editing blobs is not supported"
+msgstr "l'édition de blobs n'est pas supportée"
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "création impossible du fichier de configuration '%s'"
+
+msgid "Action"
+msgstr "Action"
+
+msgid "get value: name [<value-pattern>]"
+msgstr "obtenir la valeur : nom [<motif-de-valeur>]"
+
+msgid "get all values: key [<value-pattern>]"
+msgstr "obtenir toutes les valeurs : clé [<motif-de-valeur>]"
+
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "obtenir les valeur pour la regexp : name-regex [<motif-de-valeur>]"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "obtenir la valeur spécifique pour l'URL : section[.var] URL"
+
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr ""
+"remplacer toutes les variables correspondant : nom valeur [<motif-de-valeur>]"
+
+msgid "add a new variable: name value"
+msgstr "ajouter une nouvelle variable : nom valeur"
+
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "supprimer une variable : nom [<motif-de-valeur>]"
+
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "supprimer toutes les correspondances nom [<motif-de-valeur>]"
+
+msgid "rename section: old-name new-name"
+msgstr "renommer une section : ancien-nom nouveau-nom"
+
+msgid "remove a section: name"
+msgstr "supprimer une section : nom"
+
+msgid "list all"
+msgstr "afficher tout"
+
+msgid "open an editor"
+msgstr "ouvrir un éditeur"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "trouver la couleur configurée : slot [<valeur-par-défaut>]"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "trouver le réglage de la couleur : slot [<stdout-est-tty>]"
+
+msgid "with --get, use default value when missing entry"
+msgstr "avec --get, utiliser le valeur par défaut quand l'entrée n'existe pas"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color et le type de la variable sont incohérents"
+
+msgid "no action specified"
+msgstr "aucune action spécifiée"
+
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only n'est applicable qu'avec --list ou --get-regexp"
+
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin n'est applicable qu'avec --get, --get-all, --get-regexp ou --"
+"list"
+
+msgid "--default is only applicable to --get"
+msgstr "--default n'est applicable qu'avec --get"
+
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment n'est applicable qu'avec les opérations add/set/replace"
+
msgid "print sizes in human readable format"
msgstr "affiche les tailles dans un format humainement lisible"
@@ -5939,8 +6103,8 @@ msgstr ""
"'git config fetch.showForcedUpdates false' pour éviter cette vérification\n"
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s n'a pas envoyé tous les objets nécessaires\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s n'a pas envoyé tous les objets nécessaires"
#, c-format
msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -5979,8 +6143,8 @@ msgid "option \"%s\" value \"%s\" is not valid for %s"
msgstr "la valeur \"%2$s\" de l'option \"%1$s\" est invalide pour %3$s"
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "l'option \"%s\" est ignorée pour %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "l'option \"%s\" est ignorée pour %s"
#, c-format
msgid "%s is not a valid object"
@@ -6270,6 +6434,9 @@ 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 "also include HEAD ref and pseudorefs"
+msgstr "inclure aussi la référence HEAD et les pseudo-réfs"
+
msgid "unknown arguments supplied with --stdin"
msgstr "arguments inconnus fournis avec l'option --stdin"
@@ -6282,6 +6449,9 @@ msgstr "config"
msgid "config key storing a list of repository paths"
msgstr "clé de config qui stocke la liste des chemins de dépôts"
+msgid "keep going even if command fails in a repository"
+msgstr "continuer mêm si la commande échoue dans un dépôt"
+
msgid "missing --config=<config>"
msgstr "--config=<config> manquant"
@@ -6644,12 +6814,18 @@ msgstr "élaguer les objets non référencés"
msgid "pack unreferenced objects separately"
msgstr "empaqueter les objets non référencés séparément"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "avec --cruft, limiter la taille des nouveaux paquets déchets"
+
msgid "be more thorough (increased runtime)"
msgstr "être plus consciencieux (durée de traitement allongée)"
msgid "enable auto-gc mode"
msgstr "activer le mode auto-gc"
+msgid "perform garbage collection in the background"
+msgstr "réaliser le glanage de cellules en arrière plan"
+
msgid "force running gc even if there may be another gc running"
msgstr ""
"forcer le lancement du ramasse-miettes même si un autre ramasse-miettes "
@@ -6750,6 +6926,9 @@ msgstr "la tâche '%s' ne peut pas être sélectionnée plusieurs fois"
msgid "run tasks based on the state of the repository"
msgstr "lancer les tâches selon l'état du dépôt"
+msgid "perform maintenance in the background"
+msgstr "réaliser la maintenance en arrière-plan"
+
msgid "frequency"
msgstr "fréquence"
@@ -6823,12 +7002,6 @@ msgstr ""
msgid "'crontab' died"
msgstr "'crontab' est mort"
-msgid "failed to start systemctl"
-msgstr "échec du démarrage de systemctl"
-
-msgid "failed to run systemctl"
-msgstr "échec pour lancer systemctl"
-
#, c-format
msgid "failed to delete '%s'"
msgstr "échec de la suppression de '%s'"
@@ -6837,6 +7010,12 @@ msgstr "échec de la suppression de '%s'"
msgid "failed to flush '%s'"
msgstr "échec du flush de '%s'"
+msgid "failed to start systemctl"
+msgstr "échec du démarrage de systemctl"
+
+msgid "failed to run systemctl"
+msgstr "échec pour lancer systemctl"
+
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "argument '%s' de --scheduler non reconnu"
@@ -6862,6 +7041,9 @@ msgstr "planificateur"
msgid "scheduler to trigger git maintenance run"
msgstr "planificateur qui lancera les maintenances git"
+msgid "failed to set up maintenance schedule"
+msgstr "impossible de mettre en place la planification de maintenance"
+
msgid "failed to add repo to global config"
msgstr "échec de l'ajout du dépôt à la config globale"
@@ -6889,8 +7071,8 @@ msgid "no threads support, ignoring %s"
msgstr "pas de support des fils, ignore %s"
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "impossible de lire l'arbre (%s)"
+msgid "unable to read tree %s"
+msgstr "impossible de lire l'arbre %s"
#, c-format
msgid "unable to grep from object of type %s"
@@ -6936,8 +7118,8 @@ msgstr "traiter les fichiers binaires avec les filtres textconv"
msgid "search in subdirectories (default)"
msgstr "rechercher dans les sous-répertoires (défaut)"
-msgid "descend at most <depth> levels"
-msgstr "descendre au plus de <profondeur> dans l'arborescence"
+msgid "descend at most <n> levels"
+msgstr "descendre au plus de <n> niveaux"
msgid "use extended POSIX regular expressions"
msgstr "utiliser des expressions régulières étendues POSIX"
@@ -7311,10 +7493,6 @@ msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "COLLISION SHA1 TROUVÉE AVEC %s !"
#, c-format
-msgid "unable to read %s"
-msgstr "impossible de lire %s"
-
-#, c-format
msgid "cannot read existing object info %s"
msgstr "impossible de lire l'information existante de l'objet %s"
@@ -7455,12 +7633,14 @@ msgstr "erreur de fsck dans les objets paquets"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
-"git init [-q | --quiet] [--bare] [--template=<répertoire-modèle>]\n"
-" [--separate-git-dir <rép-git>] [--object-format=<format>]\\n\"\n"
-" [-b <nom-de-branche> | --initial-branch=<nom-de-branche>]\\n\"\n"
+"git init [-q | --quiet] [--bare] [--template=<répertoire-de-modèles>]\n"
+" [--separate-git-dir <rép-git>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
+" [-b <nom-de-branch> | --initial-branch=<nom-de-branche>]\n"
" [--shared[=<permissions>]] [<répertoire>]"
msgid "permissions"
@@ -7503,19 +7683,49 @@ msgstr "--separate-git-dir est incompatible avec un dépôt nu"
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <symbole>[(=|:)<valeur>])...]\n"
+" [(--trailer (<clé>|<alias-de-clé>)"
+"[(=|:)<valeur>])...]\n"
" [--parse] [<fichier>...]"
+#, c-format
+msgid "could not stat %s"
+msgstr "stat impossible de %s"
+
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "%s n'est pas un fichier régulier"
+
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "le fichier %s n'est pas inscriptible par l'utilisateur"
+
+msgid "could not open temporary file"
+msgstr "impossible de créer un fichier temporaire"
+
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "impossible de lire le fichier d'entrée '%s'"
+
+msgid "could not read from stdin"
+msgstr "impossible de lire depuis l'entrée standard"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "impossible de renommer un fichier temporaire en %s"
+
msgid "edit files in place"
msgstr "éditer les fichiers sur place"
msgid "trim empty trailers"
msgstr "éliminer les lignes de fin vides"
+msgid "placement"
+msgstr "placement"
+
msgid "where to place the new trailer"
msgstr "où placer les nouvelles lignes terminales"
@@ -7528,17 +7738,19 @@ msgstr "action si les lignes terminales manquent"
msgid "output only the trailers"
msgstr "éliminer les lignes terminales vides"
-msgid "do not apply config rules"
-msgstr "ne pas appliquer les règles de la configuration"
+msgid "do not apply trailer.* configuration variables"
+msgstr "ne pas appliquer les variables de configuration trailer.*"
-msgid "join whitespace-continued values"
-msgstr "joindre les valeurs continuées avec des caractères blancs"
+msgid "reformat multiline trailer values as single-line values"
+msgstr ""
+"reformatter les valeurs de ligne terminales multi-lignes en valeurs sur une "
+"seule ligne"
-msgid "set parsing options"
-msgstr "paramètres d'analyse"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "alias pour --only-trailers --only-input --unfold"
-msgid "do not treat --- specially"
-msgstr "ne pas traiter spécialement ---"
+msgid "do not treat \"---\" as the end of input"
+msgstr "ne pas traiter \"---\" comme la fin d'entrée"
msgid "trailer(s) to add"
msgstr "ligne(s) de fin à ajouter"
@@ -7596,9 +7808,6 @@ msgstr ""
msgid "Final output: %d %s\n"
msgstr "Sortie finale : %d %s\n"
-msgid "unable to create temporary object directory"
-msgstr "impossible de créer un répertoire d'objets temporaire"
-
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s : fichier incorrect"
@@ -7628,6 +7837,10 @@ msgstr "exactement une plage nécessaire"
msgid "not a range"
msgstr "ceci n'est pas une plage"
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "lecture du fichier de description de branche '%s' impossible"
+
msgid "cover letter needs email format"
msgstr "la lettre de motivation doit être au format courriel"
@@ -7723,8 +7936,11 @@ msgstr "marquer la série comme une Nième réédition"
msgid "max length of output filename"
msgstr "taille maximum du nom du fichier de sortie"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "utiliser [RFC PATCH] au lieu de [PATCH]"
+msgid "rfc"
+msgstr "rfc"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "ajouter <rfc> (par défaut 'RFC') avant 'PATCH'"
msgid "cover-from-description-mode"
msgstr "cover-from-description-mode"
@@ -7734,6 +7950,9 @@ msgstr ""
"générer des parties de la lettre d'introduction à partir de la description "
"de la branche"
+msgid "use branch description from file"
+msgstr "utiliser la description de branche dans le fichier"
+
msgid "use [<prefix>] instead of [PATCH]"
msgstr "utiliser [<préfixe>] au lieu de [PATCH]"
@@ -7903,18 +8122,6 @@ msgstr ""
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 '('"
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "mauvais format ls-files : l'élément '%s' ne se termine pas par ')'"
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "mauvais format ls-files : %%%.*s"
-
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<options>] [<fichier>...]"
@@ -8010,11 +8217,11 @@ msgstr ""
"deduplicate, --eol"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<exec>]\n"
+"git ls-remote [--brances] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<clé>]\n"
" [--symref] [<dépôt> [<motif>...]]"
@@ -8030,8 +8237,11 @@ msgstr "chemin vers git-upload-pack sur le serveur distant"
msgid "limit to tags"
msgstr "limiter aux étiquettes"
-msgid "limit to heads"
-msgstr "limiter aux heads"
+msgid "limit to branches"
+msgstr "limiter aux branches"
+
+msgid "deprecated synonym for --branches"
+msgstr "synonyme obsolète de --branches"
msgid "do not show peeled tags"
msgstr "ne pas afficher les étiquettes pelées"
@@ -8050,18 +8260,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 "bad ls-tree format: element '%s' does not start with '('"
-msgstr "mauvais format ls-tree : l'élément '%s' ne commence pas par '('"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "mauvais format ls-tree : l'élément '%s' ne se termine pas ')'"
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "mauvais format ls-tree : %%%.*s"
-
msgid "only show trees"
msgstr "afficher seulement les arbres"
@@ -8177,23 +8375,30 @@ msgstr ""
"git merge-file [<options>] [-L <nom1> [-L <orig> [-L <nom2>]]] <fichier1> "
"<fichier-orig> <fichier2>"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"l'option diff-algorithm accept \"myers\", \"minimal\", \"patience\" et "
+"\"histogram\""
+
msgid "send results to standard output"
msgstr "envoyer les résultats sur la sortie standard"
+msgid "use object IDs instead of filenames"
+msgstr "utiliser les IDs d'objet au lieu de noms de fichier"
+
msgid "use a diff3 based merge"
msgstr "utiliser une fusion basée sur diff3"
msgid "use a zealous diff3 based merge"
msgstr "utiliser une fusion basée sur un diff3 zélée"
-msgid "for conflicts, use our version"
-msgstr "pour les conflits, utiliser notre version (our)"
-
-msgid "for conflicts, use their version"
-msgstr "pour les conflits, utiliser leur version (their)"
+msgid "<algorithm>"
+msgstr "<algorithme>"
-msgid "for conflicts, use a union version"
-msgstr "pour les conflits, utiliser l'ensemble des versions"
+msgid "choose a diff algorithm"
+msgstr "choisir un algorithme de différence"
msgid "for conflicts, use this marker size"
msgstr "pour les conflits, utiliser cette taille de marqueur"
@@ -8205,6 +8410,13 @@ msgid "set labels for file1/orig-file/file2"
msgstr "définir les labels pour fichier1/fichier-orig/fichier2"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "l'objet '%s' n'existe pas"
+
+msgid "Could not write object file"
+msgstr "impossible d'écrire le fichier d'objet"
+
+#, c-format
msgid "unknown option %s"
msgstr "option inconnue %s"
@@ -8229,6 +8441,10 @@ msgstr "impossible de résoudre la référence '%s'"
msgid "Merging %s with %s\n"
msgstr "Fusion de %s avec %s\n"
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "impossible d'analyser '%s' comme un arbre"
+
msgid "not something we can merge"
msgstr "pas possible de fusionner ceci"
@@ -8265,11 +8481,18 @@ msgstr "réaliser des fusions multiples, une par ligne d'entrée"
msgid "specify a merge-base for the merge"
msgstr "spécifier une base de fusion pour la fusion"
+msgid "option=value"
+msgstr "option=valeur"
+
+msgid "option for selected merge strategy"
+msgstr "option pour la stratégie de fusion sélectionnée"
+
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge est incompatible avec d'autres options"
-msgid "--merge-base is incompatible with --stdin"
-msgstr "--merge-base est incompatible avec --stdin"
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "option de stratégie inconnue : -X%s"
#, c-format
msgid "malformed input line: '%s'."
@@ -8339,12 +8562,6 @@ msgstr "stratégie"
msgid "merge strategy to use"
msgstr "stratégie de fusion à utiliser"
-msgid "option=value"
-msgstr "option=valeur"
-
-msgid "option for selected merge strategy"
-msgstr "option pour la stratégie de fusion sélectionnée"
-
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
"message de validation de la fusion (pour une fusion sans avance rapide)"
@@ -8406,10 +8623,6 @@ msgid "Not handling anything other than two heads merge."
msgstr "Impossible de gérer autre chose que la fusion de deux têtes."
#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "option de stratégie inconnue : -X%s"
-
-#, c-format
msgid "unable to write %s"
msgstr "impossible d'écrire %s"
@@ -8439,10 +8652,10 @@ msgstr "Un message vide abandonne la validation.\n"
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Les lignes commençant par '%c' seront ignorées, et un message vide\n"
+"Les lignes commençant par '%s' seront ignorées, et un message vide\n"
"abandonne la validation.\n"
msgid "Empty commit message."
@@ -8604,9 +8817,6 @@ msgstr "impossible de lire l'objet étiqueté '%s'"
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "l'objet '%s' étiqueté comme '%s', mais est de type '%s'"
-msgid "could not read from stdin"
-msgstr "impossible de lire depuis l'entrée standard"
-
msgid "tag on stdin did not pass our strict fsck check"
msgstr "l'étiquette sur stdin n'a pas passé le test strict fsck"
@@ -8658,6 +8868,9 @@ msgstr "paquet à réutiliser lors du calcul de bitmap de multi-paquet"
msgid "write multi-pack bitmap"
msgstr "écriture du bitmap de multi-paquet"
+msgid "write a new incremental MIDX"
+msgstr "écrire un nouveau MIDX incrémental"
+
msgid "write multi-pack index containing only given indexes"
msgstr "écrire l'index multi-paquet ne contenant que les index fournis"
@@ -8710,8 +8923,8 @@ msgstr "la destination existe"
msgid "can not move directory into itself"
msgstr "impossible de déplacer un répertoire dans lui-même"
-msgid "cannot move directory over file"
-msgstr "impossible de déplacer un répertoire sur un fichier"
+msgid "destination already exists"
+msgstr "la destination existe déjà"
msgid "source directory is empty"
msgstr "le répertoire source est vide"
@@ -8873,10 +9086,6 @@ msgstr "git notes prune [<options>]"
msgid "Write/edit the notes for the following object:"
msgstr "Écrire/éditer les notes pour l'objet suivant :"
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "impossible de démarrer 'show' pour l'objet '%s'"
-
msgid "could not read 'show' output"
msgstr "impossible de lire la sortie de 'show'"
@@ -9228,6 +9437,10 @@ msgid "inconsistency with delta count"
msgstr "inconsistance dans le compte de delta"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "valeur invalide de pack.allowPackReuse : '%s'"
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -9471,9 +9684,6 @@ msgstr "la taille limite minimale d'un paquet est 1 MiB"
msgid "--thin cannot be used to build an indexable pack"
msgstr "--thin ne peut pas être utilisé pour construire un paquet indexable"
-msgid "cannot use --filter without --stdout"
-msgstr "impossible d'utiliser --filter sans --stdout"
-
msgid "cannot use --filter with --stdin-packs"
msgstr "impossible d'utiliser --filter avec --stdin-packs"
@@ -9487,19 +9697,16 @@ msgstr "impossible d'utiliser une liste interne de révisions avec --cruft"
msgid "cannot use --stdin-packs with --cruft"
msgstr "impossible d'utiliser --stdin-packs avec --cruft"
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "impossible d'utiliser --max-pack-size avec --cruft"
-
msgid "Enumerating objects"
msgstr "Énumération des objets"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Total %<PRIu32> (delta %<PRIu32>), réutilisés %<PRIu32> (delta %<PRIu32>), "
-"réutilisés du pack %<PRIu32>"
+"réutilisés du paquet %<PRIu32> (depuis %<PRIuMAX>)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9518,10 +9725,11 @@ 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 "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <motif>] [--exclude <motif>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <motif>] [--exclude "
+"<motif>]"
msgid "pack everything"
msgstr "empaqueter tout"
@@ -9529,6 +9737,9 @@ msgstr "empaqueter tout"
msgid "prune loose refs (default)"
msgstr "élaguer les références perdues (défaut)"
+msgid "auto-pack refs as needed"
+msgstr "auto-empaqueter les réfs au besoin"
+
msgid "references to include"
msgstr "références à inclure"
@@ -10208,19 +10419,6 @@ msgstr "allow_rerere_autoupdate invalide ignoré : '%s'"
msgid "could not remove '%s'"
msgstr "impossible de supprimer '%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 ""
-"Résolvez tous les conflits manuellement, marquez-les comme résolus avec\n"
-"\"git add/rm <fichier en conflit>\", puis lancez \"git rebase --continue\".\n"
-"Si vous préférez sauter ce commit, lancez \"git rebase --skip\". Pour "
-"arrêter\n"
-"et revenir à l'état antérieur à la commande, lancez \"git rebase --abort\"."
-
#, c-format
msgid ""
"\n"
@@ -10251,13 +10449,16 @@ msgid "apply options and merge options cannot be used together"
msgstr ""
"Les options d'apply et celles de merge ne peuvent pas être utilisées ensemble"
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask est obsolète ; utilisez '--empty=stop' à la place."
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
"type vide non connu '%s' ; les valeurs valides sont \"drop\" (abandonner), "
-"\"keep\" (garder) et \"ask\" (demander)."
+"\"keep\" (garder) et \"stop\" (arrêter)."
msgid ""
"--rebase-merges with an empty string argument is deprecated and will stop "
@@ -10439,8 +10640,8 @@ msgstr ""
"Note : votre configuration `pull.rebase` peut aussi être 'preserve',\n"
"qui n'est plus géré ; utilisez 'merges' à la place"
-msgid "No rebase in progress?"
-msgstr "Pas de rebasage en cours ?"
+msgid "no rebase in progress"
+msgstr "Pas de rebasage en cours"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
@@ -10488,16 +10689,6 @@ msgstr ""
msgid "switch `C' expects a numerical value"
msgstr "l'option `C' attend un valeur numérique"
-msgid "--strategy requires --merge or --interactive"
-msgstr "--strategy requiert --merge ou --interactive"
-
-msgid ""
-"apply options are incompatible with rebase.autoSquash. Consider adding --no-"
-"autosquash"
-msgstr ""
-"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"
@@ -10647,6 +10838,9 @@ msgstr "Vous devez spécifier un répertoire"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<options-de-journal>] [<réf>]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10672,6 +10866,10 @@ msgstr "git reflog exists <référence>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "horodatage invalide '%s' fourni à '--%s'"
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s n'accepte pas d'argument : '%s'"
+
msgid "do not actually prune any entries"
msgstr "ne pas réellement élaguer des entrées"
@@ -10725,6 +10923,31 @@ msgstr "pas de journal de références à supprimer spécifié"
msgid "invalid ref format: %s"
msgstr "format de référence invalide : %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+msgid "specify the reference format to convert to"
+msgstr "spécifier le format de réference vers lequel convertir"
+
+msgid "perform a non-destructive dry-run"
+msgstr "faire l'action en mode simulé non destructif"
+
+msgid "missing --ref-format=<format>"
+msgstr "--ref-format=<format> manquant"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "le dépôt utilise déjà le format '%s'"
+
+msgid "enable strict checking"
+msgstr "activer une vérification plus strict"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' n'accepte aucun argument"
+
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10802,8 +11025,8 @@ msgstr ""
"\t d'utiliser --mirror=fetch ou --mirror=push à la place"
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "argument miroir inconnu : %s"
+msgid "unknown --mirror argument: %s"
+msgstr "argument de --mirror inconnu : %s"
msgid "fetch the remote branches"
msgstr "rapatrier les branches distantes"
@@ -11013,9 +11236,6 @@ msgstr "* distant %s"
msgid " Fetch URL: %s"
msgstr " URL de rapatriement : %s"
-msgid "(no URL)"
-msgstr "(pas d'URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -11024,6 +11244,9 @@ msgstr "(pas d'URL)"
msgid " Push URL: %s"
msgstr " URL push : %s"
+msgid "(no URL)"
+msgstr "(pas d'URL)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " Branche HEAD : %s"
@@ -11133,10 +11356,6 @@ msgstr "interroger les URLs de poussée plutôt que les URLs de récupération"
msgid "return all URLs"
msgstr "retourner toutes les URLs"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "aucune URL configurée pour le dépôt distant '%s'"
-
msgid "manipulate push URLs"
msgstr "manipuler les URLs push"
@@ -11178,6 +11397,9 @@ msgid "could not start pack-objects to repack promisor objects"
msgstr ""
"ne pas démarrer pack-objects pour ré-empaqueter les objects de prometteur"
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "Échéc de la fourniture les objets du prometteur à pack-objects"
+
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"repack : attente de lignes d'Id d'objets en hexa complet seulement depuis "
@@ -11213,6 +11435,10 @@ msgstr "impossible de fermer le fichier temporaire d'instantané des réfs"
msgid "could not remove stale bitmap: %s"
msgstr "impossible de revenir la bitmap obsolète : %s"
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "le préfixe %s ne commence pas avec objdir %s"
+
msgid "pack everything in a single pack"
msgstr "empaqueter tout dans un seul paquet"
@@ -11290,17 +11516,20 @@ msgstr "écrire un index de multi-paquet des paquets résultants"
msgid "pack prefix to store a pack containing pruned objects"
msgstr "préfixe de paquet pour stocker un paquet contenant les objets élagués"
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "préfixe de paquet pour stocker un paquet contenant les objets filtrés"
+
msgid "cannot delete packs in a precious-objects repo"
msgstr "impossible de supprimer les paquets dans un dépôt d'objets précieux"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "l'option '%s' ne peut être utilisé qu'avec '%s'"
+
msgid "Nothing new to pack."
msgstr "Rien de neuf à empaqueter."
#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "le préfixe %s ne commence pas avec objdir %s"
-
-#, c-format
msgid "renaming pack to '%s' failed"
msgstr "le renommage du paquet en '%s' a échoué"
@@ -11500,6 +11729,77 @@ msgstr "--convert-graft-file ne supporte aucun argument"
msgid "only one pattern can be given with -l"
msgstr "-l n'accepte qu'un motifs"
+msgid "need some commits to replay"
+msgstr "commits requis pour pouvoir rejouer"
+
+msgid "--onto and --advance are incompatible"
+msgstr "--onto et --advance sont incompatibles"
+
+msgid "all positive revisions given must be references"
+msgstr "toutes les révisions positives fournies doivent être des références"
+
+msgid "argument to --advance must be a reference"
+msgstr "l'argument de --advance doit être une référence"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"impossible d'avancer la cible avec des sources multiples parce l'ordre ne "
+"serait pas total"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"impossible de déterminer implicitement s'il y a une opération --advance ou --"
+"onto"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"impossible d'avancer la cible sur des branches sources multiples parce que "
+"l'ordre ne serait pas total"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "impossible de déterminer implicitement une base correcte pour --onto"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <nouvelle-base> | --advance "
+"<branche>) <plage-de-révision>..."
+
+msgid "make replay advance given branch"
+msgstr "faire rejouer en avançant la branche indiquée"
+
+msgid "replay onto given commit"
+msgstr "rejouer par-dessus le commit indiqué"
+
+msgid "advance all branches contained in revision-range"
+msgstr "avancer toutes les branches contenues dans la plage-de-révisions"
+
+msgid "option --onto or --advance is mandatory"
+msgstr "une option --onto ou --advance est obligatoire"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"certaines options de parcours de révs seront surchargées car le bit '%s' "
+"dans 'struct rev_info' sera forcé"
+
+msgid "error preparing revisions"
+msgstr "erreur lors de la préparation des révisions"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "rejouer jusqu'au commit racine n'est pas encore géré !"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "rejouer des commits de fusion n'est pas encore géré !"
+
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
msgstr ""
@@ -11707,22 +12007,23 @@ msgstr "--default exige un argument"
msgid "--prefix requires an argument"
msgstr "--prefix exige un argument"
+msgid "no object format specified"
+msgstr "aucun format d'objet spécifié"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "format d'objet non géré : %s"
+
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "mode inconnu pour --abbrev-ref : %s"
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden ne peut être utilisé avec --branches"
-
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden ne peut pas être utilisé avec --tags"
-
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden ne peut pas être utilisé avec --remotes"
-
msgid "this operation must be run in a work tree"
msgstr "cette opération doit être effectuée dans un arbre de travail"
+msgid "Could not read the index"
+msgstr "Impossible de lire l'index"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "mode inconnu pour --show-object-format : %s"
@@ -11794,8 +12095,8 @@ msgstr "préserver les validations vides initialement"
msgid "allow commits with empty messages"
msgstr "autoriser les validations avec des messages vides"
-msgid "keep redundant, empty commits"
-msgstr "garder les validations redondantes, vides"
+msgid "deprecated: use --empty=keep instead"
+msgstr "obsolète : utilisez --empty=keep à la place"
msgid "use the 'reference' format to refer to commits"
msgstr "utiliser le format 'reference' pour se référer aux commits"
@@ -12072,22 +12373,43 @@ msgid "Unknown hash algorithm"
msgstr "Algorithme d'empreinte inconnu"
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<motif>...]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<motif>...]"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<motif>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "afficher seulement les étiquettes (peut être combiné avec heads)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <réf>"
+
+msgid "reference does not exist"
+msgstr "la référence n'existe pas"
+
+msgid "failed to look up reference"
+msgstr "échec de la recherche de la référence"
+
+msgid "only show tags (can be combined with --branches)"
+msgstr "afficher seulement les étiquettes (peut être combiné avec --branches)"
-msgid "only show heads (can be combined with tags)"
-msgstr "afficher seulement les têtes (peut être combiné avec tags)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "afficher seulement les branches (peut être combiné avec --tags)"
+
+msgid "check for reference existence without resolving"
+msgstr "vérifier l'existence de la référence sans la résoudre"
msgid "stricter reference checking, requires exact ref path"
msgstr ""
@@ -12143,6 +12465,10 @@ msgid "failed to create directory for sparse-checkout file"
msgstr ""
"échec de la création du répertoire pour le fichier d'extraction clairsemée"
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "impossible d'ouvrir %s avec fdopen"
+
msgid "failed to initialize worktree config"
msgstr "échec lors de l'initialisation de la configuration d'arbre de travail"
@@ -12612,8 +12938,8 @@ msgid "couldn't hash object from '%s'"
msgstr "impossible de calculer l'empreinte de l'objet depuis '%s'"
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "mode %o inattendu\n"
+msgid "unexpected mode %o"
+msgstr "mode %o inattendu"
msgid "use the commit stored in the index instead of the submodule HEAD"
msgstr ""
@@ -12736,14 +13062,14 @@ msgstr ""
"refus de créer/utiliser '%s' dans un répertoire git d'un autre sous-module"
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "le clonage de '%s' dans le chemin de sous-module '%s' a échoué"
-
-#, c-format
msgid "directory not empty: '%s'"
msgstr "le répertoire n'est pas vide : '%s'"
#, c-format
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "le clonage de '%s' dans le chemin de sous-module '%s' a échoué"
+
+#, c-format
msgid "could not get submodule directory for '%s'"
msgstr "impossible de créer le répertoire de sous-module pour '%s'"
@@ -12935,6 +13261,9 @@ msgstr ""
"[no-]recommend-shallow] [--reference <dépôt>] [--recursive] [--[no-]single-"
"branch] [--] [<chemin>...]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Échec de résolution de HEAD comme référence valide."
+
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<options>] [<chemin>...]"
@@ -13106,9 +13435,11 @@ msgstr "raison de la mise à jour"
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <id-clé>] [-f] [-m <msg> | -F <fichier>] [-e]\n"
+" [(--trailer <jeton>[(=|:)<valeur>)...]\n"
" <nom-d-étiquette> [<commit> | <objet>]"
msgid "git tag -d <tagname>..."
@@ -13141,25 +13472,25 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Écrivez un message pour l'étiquette :\n"
" %s\n"
-"Les lignes commençant par '%c' seront ignorées.\n"
+"Les lignes commençant par '%s' seront ignorées.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Écrivez un message pour l'étiquette :\n"
" %s\n"
-"Les lignes commençant par '%c' seront gardées ; vous pouvez les retirer vous-"
+"Les lignes commençant par '%s' seront gardées ; vous pouvez les retirer vous-"
"même si vous le souhaitez.\n"
msgid "unable to sign the tag"
@@ -13246,6 +13577,9 @@ msgstr "afficher seulement les étiquettes qui ne sont pas fusionnées"
msgid "print only tags of the object"
msgstr "afficher seulement les étiquettes de l'objet"
+msgid "could not start 'git column'"
+msgstr "impossible de démarrer 'git column'"
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "l'option '%s' est autorisée seulement en mode de liste"
@@ -13413,6 +13747,9 @@ msgstr "(pour porcelaines) oublier les conflits sauvés et non résolus"
msgid "write index in this format"
msgstr "écrire l'index dans ce format"
+msgid "report on-disk index format version"
+msgstr "afficher la version du format d'index sur disque"
+
msgid "enable or disable split index"
msgstr "activer ou désactiver l'index scindé"
@@ -13438,6 +13775,14 @@ msgstr "marquer les fichiers comme valides pour fsmonitor"
msgid "clear fsmonitor valid bit"
msgstr "effacer le bit de validité fsmonitor"
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version : précédemment %d, mis à %d"
+
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -13490,13 +13835,12 @@ msgstr ""
msgid "fsmonitor disabled"
msgstr "fsmonitor désactivé"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<options>] -d <nom-référence> [<ancienne-valeur>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<options>] -d <nom-référence> [<ancien-oid>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
msgstr ""
-"git update-ref [<options>] <nom-référence> <nouvelle-valeur> [<ancienne-"
-"valeur>]"
+"git update-ref [<options>] <nom-référence> <nouvel-oid> [<ancien-oid>]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<options>] --stdin [-z]"
@@ -13596,28 +13940,28 @@ msgstr "Aucune branche source possible, activation de '--orphan'"
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"non-née (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"
+"If you meant to create a worktree containing a new unborn 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"
+"non-née (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"
@@ -13680,6 +14024,10 @@ msgid "initializing"
msgstr "initialisation"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "impossible de trouver l'arbre-de-travail créé '%s'"
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "Préparation de l'arbre de travail (nouvelle branche '%s')"
@@ -13713,15 +14061,12 @@ msgstr ""
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"
+"present, stopping; use 'add -f' to override 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"
+"on arrête ; utilisez 'add -f' pour passe outre ou récupérer le distant en "
+"premier"
msgid "checkout <branch> even if already checked out in other worktree"
msgstr ""
@@ -13734,8 +14079,8 @@ 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 "create unborn branch"
+msgstr "créer une branche non née"
msgid "populate the new working tree"
msgstr "remplissage de la nouvelle copie de travail"
@@ -13757,11 +14102,9 @@ 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 "option '%s' and commit-ish cannot be used together"
+msgstr ""
+"l'option '%s' et des commit-esques ne peuvent pas être utilisés ensemble"
msgid "added with --lock"
msgstr "ajouté avec --lock"
@@ -13975,9 +14318,6 @@ msgstr "en-tête non reconnu : %s%s (%d)"
msgid "Repository lacks these prerequisite commits:"
msgstr "Le dépôt ne dispose pas des commits prérequis suivants :"
-msgid "need a repository to verify a bundle"
-msgstr "la vérification d'un colis requiert un dépôt"
-
msgid ""
"some prerequisite commits exist in the object store, but are not connected "
"to the repository's history"
@@ -14043,16 +14383,20 @@ msgid "terminating chunk id appears earlier than expected"
msgstr "l'identifiant de terminaison de tronçon apparaît plus tôt qu'attendu"
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "id de tronçon %<PRIx32> non alignés sur %d octets"
+
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
-msgstr "décalage(s) de section incorrect(s) %<PRIx64> et %<PRIx64>"
+msgstr "décalage(s) de tronçon incorrect(s) %<PRIx64> et %<PRIx64>"
#, c-format
msgid "duplicate chunk ID %<PRIx32> found"
-msgstr "ID de section dupliqué %<PRIx32>"
+msgstr "ID de tronçon dupliqué %<PRIx32>"
#, c-format
msgid "final chunk has non-zero id %<PRIx32>"
-msgstr "la section finale a un id non nul %<PRIx32>"
+msgstr "le tronçon final a un id non nul %<PRIx32>"
msgid "invalid hash version"
msgstr "version d'empreinte invalide"
@@ -14097,10 +14441,8 @@ msgstr ""
msgid "Move objects and refs by archive"
msgstr "Déplacer les objets et références par archive"
-msgid "Provide content or type and size information for repository objects"
-msgstr ""
-"Fournir le contenu ou l'information de type et taille pour les objets du "
-"dépôt"
+msgid "Provide contents or details of repository objects"
+msgstr "Fournir le contenu ou les détails des objets du dépôt"
msgid "Display gitattributes information"
msgstr "Afficher les informations gitattributes"
@@ -14391,6 +14733,9 @@ msgstr "Recevoir ce qui est poussé dans le dépôt"
msgid "Manage reflog information"
msgstr "Gérer l'information de reflog"
+msgid "Low-level access to refs"
+msgstr "accès de bas-niveau aux réfs"
+
msgid "Manage set of tracked repositories"
msgstr "Gérer un ensemble de dépôts suivis"
@@ -14400,6 +14745,11 @@ msgstr "Empaqueter les objets non-empaquetés d'un dépôt"
msgid "Create, list, delete refs to replace objects"
msgstr "Créer, lister, supprimer des référence pour remplacer des objets"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"EXPÉRIMENTAL ; rejoue des commits sur une nouvelle base, fonctionne aussi "
+"avec les dépôts nus"
+
msgid "Generates a summary of pending changes"
msgstr "Générer une résumé des modifications en attentes"
@@ -14524,7 +14874,7 @@ msgstr "Vérifier la signature GPG d'étiquettes"
msgid "Display version information about Git"
msgstr "Afficher l'information de version à propos de Git"
-msgid "Show logs with difference each commit introduces"
+msgid "Show logs with differences each commit introduces"
msgstr "Afficher les journaux avec la différence que chaque commit introduit"
msgid "Manage multiple working trees"
@@ -14561,7 +14911,7 @@ msgid "The bundle file format"
msgstr "le format du fichier de colis"
msgid "Chunk-based file formats"
-msgstr "format de fichier avec des sections"
+msgstr "format de fichier avec des tronçons"
msgid "Git commit-graph format"
msgstr "format de graphe de commit de Git"
@@ -14642,6 +14992,35 @@ msgstr "Un outil pour gérer les grands dépôts Git"
msgid "commit-graph file is too small"
msgstr "le graphe de commit est trop petit"
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr ""
+"le tronçon de distribution d'oid du graphe de commit n'a pas la bonne taille"
+
+msgid "commit-graph fanout values out of order"
+msgstr "les valeurs de distribution du graphe de commit sont désordonnées"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr ""
+"le tronçon de recherche de l'OID du graphe de commits n'a pas la bonne taille"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "le tronçon de données du graphe de commit n'a pas la bonne taille"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "le tronçon des générations du graphe de commit n'a pas la bonne taille"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr ""
+"le tronçon d'index des chemins modifiés du graphe de commit est trop petit"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"tronçon de chemin modifié dans le fichier de graphe de commits trop petit "
+"((%<PRIuMAX> < %<PRIuMAX>)) ignoré"
+
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr ""
@@ -14659,10 +15038,36 @@ msgstr ""
#, c-format
msgid "commit-graph file is too small to hold %u chunks"
-msgstr "le graphe de commit est trop petit pour contenir %u sections"
+msgstr "le graphe de commit est trop petit pour contenir %u tronçons"
+
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr ""
+"le tronçon de distribution des OID requis du graphe de commits est manquant "
+"ou corrompu"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr ""
+"le tronçon de recherche OID requis par le graphe de commits est manquant ou "
+"corrompu"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr ""
+"le tronçon d'étalement OID requis par le graphe de commits est manquant ou "
+"corrompu"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"désactivation des filtres de Bloom opur la couche de graphe de commits '%s' "
+"à cause de réglages incompatibles"
msgid "commit-graph has no base graphs chunk"
-msgstr "le graphe de commit n'a pas de section de graphes de base"
+msgstr "le graphe de commit n'a pas de tronçon de graphes de base"
+
+msgid "commit-graph base graphs chunk is too small"
+msgstr "le tronçon de graphes de base du graphe de commit est trop petit"
msgid "commit-graph chain does not match"
msgstr "la chaîne de graphe de commit ne correspond pas"
@@ -14671,6 +15076,9 @@ msgstr "la chaîne de graphe de commit ne correspond pas"
msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "nombre de commits dans le graphe de base trop haut : %<PRIuMAX>"
+msgid "commit-graph chain file too small"
+msgstr "la chaine du graphe de commit est trop petite"
+
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr ""
@@ -14693,6 +15101,14 @@ msgstr ""
"le graphe de commits requiert des données de génération de débordement mais "
"n'en contient pas"
+msgid "commit-graph overflow generation data is too small"
+msgstr ""
+"les données de génération de débordement du graphe de commits sont trop "
+"petites"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "pointeur hors-gamme d'arêtes supplémentaires du graphe de commits"
+
msgid "Loading known commits in commit graph"
msgstr "Lecture des commits connus dans un graphe de commit"
@@ -14781,6 +15197,14 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr ""
"essai d'écriture de graphe de commits, mais 'core.commitGraph' est désactivé"
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"essai d'écriture de graphe de commits, mais 'commitGraph."
+"changedPathsVersion' (%d) n'est pas pris en charge"
+
msgid "too many commits to write graph"
msgstr "trop de commits pour écrire un graphe"
@@ -14830,20 +15254,6 @@ msgstr ""
"la liste de parents du graphe de commit pour le commit %s se termine trop tôt"
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr ""
-"le graphe de commit a un numéro de génération nul pour le commit %s, mais "
-"non-nul ailleurs"
-
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"le graphe de commit a un numéro de génération non-nul pour le commit %s, "
-"mais nul ailleurs"
-
-#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr ""
"la génération du graphe de commit pour le commit %s est %<PRIuMAX> < "
@@ -14855,10 +15265,22 @@ msgstr ""
"la date de validation pour le commit %s dans le graphe de commit est "
"%<PRIuMAX> != %<PRIuMAX>"
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"le graphe de commit a des numéros de génération à la fois nuls et non-nuls "
+"(par ex. les commits %s et %s)"
+
msgid "Verifying commits in commit graph"
msgstr "Verification des commits dans le graphe de commits"
#, c-format
+msgid "could not parse commit %s"
+msgstr "impossible d'analyser le commit %s"
+
+#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s n'est pas un commit !"
@@ -14882,6 +15304,12 @@ msgstr ""
"\"git config advice.graftFileDeprecated false\""
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"le commit '%s' existe dans la graphe de commit mais pas dans la base de "
+"données d'objets"
+
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr "La validation %s a une signature GPG non fiable, prétendument par %s."
@@ -15291,8 +15719,13 @@ 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 ASCII character"
-msgstr "core.commentChar ne devrait être qu'un unique caractère ASCII"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s ne peut pas contenir de retour à la ligne"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s doit contenir au moins un caractère"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15328,10 +15761,6 @@ msgstr "la référence '%s' ne pointe pas sur un blob"
msgid "unable to resolve config blob '%s'"
msgstr "impossible de résoudre le blob de config '%s'"
-#, c-format
-msgid "failed to parse %s"
-msgstr "échec de l'analyse de %s"
-
msgid "unable to parse command-line config"
msgstr "lecture de la configuration de ligne de commande impossible"
@@ -15371,6 +15800,10 @@ msgid "failed to write new configuration file %s"
msgstr "impossible d'écrire le fichier de configuration %s"
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "aucun commentaire multi-ligne permis : '%s'"
+
+#, c-format
msgid "could not lock config file %s"
msgstr "impossible de verrouiller le fichier de configuration %s"
@@ -15814,9 +16247,6 @@ msgstr "impossible d'écrire l'archive"
msgid "--merge-base does not work with ranges"
msgstr "--merge-base ne fonctionne pas avec des plages"
-msgid "--merge-base only works with commits"
-msgstr "--merge-base ne fonctionne qu'avec des commits"
-
msgid "unable to get HEAD"
msgstr "impossible d'acquérir HEAD"
@@ -15880,6 +16310,10 @@ msgstr ""
"Valeur inconnue pour la variable de configuration 'diff.submodule' : '%s'"
#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "valeur inconnue pour la config '%s' : %s"
+
+#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
@@ -15961,13 +16395,6 @@ msgstr "mauvais argument --color-moved : %s"
msgid "invalid mode '%s' in --color-moved-ws"
msgstr "mode invalide '%s' dans --color-moved-ws"
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"l'option diff-algorithm accept \"myers\", \"minimal\", \"patience\" et "
-"\"histogram\""
-
#, c-format
msgid "invalid argument to %s"
msgstr "argument invalide pour %s"
@@ -16011,8 +16438,8 @@ msgstr "--stat pour traitement automatique"
msgid "output only the last line of --stat"
msgstr "afficher seulement la dernière ligne de --stat"
-msgid "<param1,param2>..."
-msgstr "<param1,param2>..."
+msgid "<param1>,<param2>..."
+msgstr "<param1>,<param2>..."
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
@@ -16023,8 +16450,8 @@ msgstr ""
msgid "synonym for --dirstat=cumulative"
msgstr "synonyme pour --dirstat=cumulative"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "synonyme pour --dirstat=files,param1,param2..."
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "synonyme pour --dirstat=files,<param1>,<param2>..."
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
@@ -16212,12 +16639,6 @@ msgid "generate diff using the \"histogram diff\" algorithm"
msgstr ""
"générer un diff en utilisant l'algorithme de différence \"histogramme\""
-msgid "<algorithm>"
-msgstr "<algorithme>"
-
-msgid "choose a diff algorithm"
-msgstr "choisir un algorithme de différence"
-
msgid "<text>"
msgstr "<texte>"
@@ -16697,19 +17118,23 @@ msgstr ""
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
msgstr ""
"git [-v | --version] [-h | --help] [-C <chemin>] [-c <nom>=<valeur>]\n"
" [--exec-path[=<chemin>]] [--html-path] [--man-path] [--info-"
"path]\n"
-" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-" [--git-dir=<chemin>] [--work-tree=<chemin>] [--namespace=<nom>]\n"
-" [--config-env=<nom>=<variable-d-environnement>] <commande> "
-"[<args>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-"
+"dir=<chemin>]\n"
+" [--work-tree=<chemin>] [--namespace=<nom>] [--config-"
+"env=<nom>=<var-d-env>] \n"
+" <commande> [<args>]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -17050,13 +17475,13 @@ msgstr ""
"Vous pouvez désactiver cet avertissement avec `git config advice.ignoredHook "
"false`."
+msgid "not a git repository"
+msgstr "pas un dépôt git"
+
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "l'argument de --packfile doit être une empreinte valide ('%s' reçu)"
-msgid "not a git repository"
-msgstr "pas un dépôt git"
-
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
msgstr ""
@@ -17068,6 +17493,9 @@ msgstr "La délégation de commande n'est pas supporté avec cuRL < 7.22.0"
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "L'épinglage de clé publique n'est pas supporté avec cuRL < 7.39.0"
+msgid "Unknown value for http.proactiveauth"
+msgstr "valeur inconnue pour http.proactiveauth"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE n'est pas supporté avec cuRL < 7.44.0"
@@ -17085,6 +17513,12 @@ msgstr ""
msgid "Could not set SSL backend to '%s': already set"
msgstr "Impossible de spécifier le dorsal SSL à '%s' : déjà spécifié"
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "refus de lire des cookies depuis http.cookiefile '-'"
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "http.savecookies ignoré pour http.cookiefile vide"
+
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -17228,6 +17662,17 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "Impossible de créer '%s.lock' : %s"
+msgid "unable to create temporary object directory"
+msgstr "impossible de créer un répertoire d'objets temporaire"
+
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "impossible d'écrire l'objet esseulé %s"
+
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "Échec de l'écriture de l'index d'objet esseulé %s"
+
#, c-format
msgid "unexpected line: '%s'"
msgstr "ligne inattendue : '%s'"
@@ -17239,6 +17684,10 @@ msgid "quoted CRLF detected"
msgstr "CRLF citées détectées"
#, c-format
+msgid "unable to format message: %s"
+msgstr "impossible de formater le message : %s"
+
+#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "Échec de la fusion du sous-module %s (non extrait)"
@@ -17251,6 +17700,10 @@ msgid "Failed to merge submodule %s (commits not present)"
msgstr "Échec de fusion du sous-module %s (commits non présents)"
#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "erreur : échec de la fusion du sous-module %s (dépôt corrompu)"
+
+#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr ""
"Échec de la fusion du sous-module %s (les commits ne descendent pas de la "
@@ -17280,12 +17733,13 @@ msgstr ""
"existent :\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "Échec à l'exécution de la fusion interne"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "erreur : échec à l'exécution de la fusion interne pour %s"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "Impossible d'ajouter %s à la base de données"
+msgid "error: unable to add %s to database"
+msgstr "erreur : impossible d'ajouter %s à la base de données"
#, c-format
msgid "Auto-merging %s"
@@ -17381,12 +17835,12 @@ msgstr ""
"supprimé dans %s."
#, c-format
-msgid "cannot read object %s"
-msgstr "impossible de lire l'objet %s"
+msgid "error: cannot read object %s"
+msgstr "erreur : impossible de lire l'objet %s"
#, c-format
-msgid "object %s is not a blob"
-msgstr "l'objet %s n'est pas un blob"
+msgid "error: object %s is not a blob"
+msgstr "erreur : l'objet %s n'est pas un blob"
#, c-format
msgid ""
@@ -17525,6 +17979,10 @@ msgid "do not know what to do with %06o %s '%s'"
msgstr "ne sait pas traiter %06o %s '%s'"
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "Échec de la fusion du sous-module %s (dépôt corrompu)"
+
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "Avance rapide du sous-module %s au commit suivant :"
@@ -17564,6 +18022,13 @@ msgstr ""
msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "Échec de fusion du sous-module %s (plusieurs fusions trouvées)"
+msgid "failed to execute internal merge"
+msgstr "échec à l'exécution de la fusion interne"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "impossible d'ajouter %s à la base de données"
+
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
@@ -17664,6 +18129,14 @@ msgstr ""
"CONFLIT (renommage/renommage) : renommage du répertoire %s->%s dans %s. "
"Renommage de répertoire %s->%s dans %s"
+#, c-format
+msgid "cannot read object %s"
+msgstr "impossible de lire l'objet %s"
+
+#, c-format
+msgid "object %s is not a blob"
+msgstr "l'objet %s n'est pas un blob"
+
msgid "modify"
msgstr "modification"
@@ -17724,54 +18197,6 @@ msgstr "Impossible d'analyser l'objet '%s'"
msgid "failed to read the cache"
msgstr "impossible de lire le cache"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "l'étalement de l'OID d'index multi-paquet n'a pas la bonne taille"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "le fichier d'index multi-paquet %s est trop petit"
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr ""
-"la signature de l'index multi-paquet 0x%08x ne correspond pas à la signature "
-"0x%08x"
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "la version d'index multi-paquet %d n'est pas reconnue"
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr ""
-"la version d'empreinte d'index multi-paquet %u ne correspond pas à la "
-"version %u"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "index multi-paquet manque de tronçon de nom de paquet"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "index multi-paquet manque de tronçon de d'étalement OID requis"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "index multi-paquet manque de tronçon de recherche OID requis"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "index multi-paquet manque de tronçon de décalage d'objet requis"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr ""
-"index multi-paquet les noms de paquets sont en désordre : '%s' avant '%s'"
-
-#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "mauvais pack-int-id : %u (%u paquets au total)"
-
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr ""
-"l'index multi-paquet stock un décalage en 64-bit, mais off_t est trop petit"
-
#, c-format
msgid "failed to add packfile '%s'"
msgstr "échec de l'ajout du fichier paquet '%s'"
@@ -17795,10 +18220,6 @@ msgstr "impossible d'analyser la ligne : %s"
msgid "malformed line: %s"
msgstr "ligne malformée : %s"
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr ""
-"index multi-paquet existant ignoré ; non-concordance de la somme de contrôle"
-
msgid "could not load pack"
msgstr "impossible de charger le paquet"
@@ -17806,6 +18227,21 @@ msgstr "impossible de charger le paquet"
msgid "could not open index for %s"
msgstr "impossible d'ouvrir l'index pour %s"
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "impossible de lier '%s' à '%s'"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "échec du nettoyage de l'index de multi-paquet à %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "impossible d'écrire un MIDX incrémental avec des bitmap"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"index multi-paquet existant ignoré ; non-concordance de la somme de contrôle"
+
msgid "Adding packfiles to multi-pack-index"
msgstr "Ajout de fichiers paquet à un index multi-paquet"
@@ -17831,24 +18267,42 @@ msgstr "aucun fichier paquet à l'index."
msgid "refusing to write multi-pack .bitmap without any objects"
msgstr "refus d'écrire le .bitmap multi-paquet sans aucun objet"
+msgid "unable to create temporary MIDX layer"
+msgstr "impossible de créer une couche MIDX temporaire"
+
msgid "could not write multi-pack bitmap"
msgstr "impossible d'écrire le bitmap multi-paquet"
+msgid "unable to open multi-pack-index chain file"
+msgstr "impossible d'ouvrir le fichier d'index multi-paquet"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "impossible d'écrire la nouvelle couche de l'index multi-paquet"
+
msgid "could not write multi-pack-index"
msgstr "échec de l'écriture de l'index de multi-paquet"
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "échec du nettoyage de l'index de multi-paquet à %s"
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"impossible d'expirer les paquets dpuis un index multi-paquet incrémental"
-msgid "multi-pack-index file exists, but failed to parse"
-msgstr "le fichier d'index multi-paquet existe mais n'a pu être analysé"
+msgid "Counting referenced objects"
+msgstr "Comptage des objets référencés"
-msgid "incorrect checksum"
-msgstr "somme de contrôle incorrecte"
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Recherche et effacement des fichiers paquets non-référencés"
-msgid "Looking for referenced packfiles"
-msgstr "Recherche de fichiers paquets référencés"
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "impossible de ré-empaqueter un index multi-paquet"
+
+msgid "could not start pack-objects"
+msgstr "impossible de démarrer le groupement d'objets"
+
+msgid "could not finish pack-objects"
+msgstr "impossible de finir le groupement d'objets"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "l'étalement de l'OID d'index multi-paquet n'a pas la bonne taille"
#, c-format
msgid ""
@@ -17857,6 +18311,111 @@ msgstr ""
"étalement oid en désordre : étalement[%d] = %<PRIx32> > %<PRIx32> = "
"étalement[%d]"
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr ""
+"le tronçon de recherche de l'OID d'index multi-paquet n'a pas la bonne taille"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr ""
+"le tronçon de décalage de l'OID d'index multi-paquet n'a pas la bonne taille"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "le fichier d'index multi-paquet %s est trop petit"
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr ""
+"la signature de l'index multi-paquet 0x%08x ne correspond pas à la signature "
+"0x%08x"
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "la version d'index multi-paquet %d n'est pas reconnue"
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr ""
+"la version d'empreinte d'index multi-paquet %u ne correspond pas à la "
+"version %u"
+
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr ""
+"le tronçon de nom de paquet requis par l'index multi-paquet est manquant ou "
+"corrompu"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"le tronçon d'étalement OID requis de l'index multi-paquet est manquant ou "
+"corrompu"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr ""
+"le tronçon de recherche OID requis de l'index multi-paquet est manquant ou "
+"corrompu"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"le tronçon de décalage d'objet requis de l'index multi-paquet est manquant "
+"ou corrompu"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "le tronçon de nom de paquet de l'index multi-paquet est trop petit"
+
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr ""
+"index multi-paquet les noms de paquets sont en désordre : '%s' avant '%s'"
+
+msgid "multi-pack-index chain file too small"
+msgstr "le fichier de chaîne d'index multi-paquet est trop petit"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "nombre de paquets dans la base MIDX trop haut : %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "nombre d'objets dans la base MIDX trop haut : %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr ""
+"chaîne d'index multi-paquet invalide : la ligne '%s' n'est pas une empreinte"
+
+msgid "unable to find all multi-pack index files"
+msgstr "impossible de trouver tous les fichiers d'index multi-paquet"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "position d'objet MIDX invalide. MIDX est vraisemblablement corrompu"
+
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "mauvais pack-int-id : %u (%u paquets au total)"
+
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "le MIDX ne contient pas de tronçon BTMP"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "impossible d'ouvrir le paquet bitmappé %<PRIu32>"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr ""
+"l'index multi-paquet stocke un décalage en 64-bit, mais off_t est trop petit"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr "le grand décalage de l'index-multi-paquet est hors limite"
+
+msgid "multi-pack-index file exists, but failed to parse"
+msgstr "le fichier d'index multi-paquet existe mais n'a pu être analysé"
+
+msgid "incorrect checksum"
+msgstr "somme de contrôle incorrecte"
+
+msgid "Looking for referenced packfiles"
+msgstr "Recherche de fichiers paquets référencés"
+
msgid "the midx contains no oid"
msgstr "le midx ne contient aucun oid"
@@ -17885,18 +18444,6 @@ msgstr "impossible de lire le fichier paquet %s"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "décalage d'objet incorrect pour oid[%d] = %s : %<PRIx64> != %<PRIx64>"
-msgid "Counting referenced objects"
-msgstr "Comptage des objets référencés"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "Recherche et effacement des fichiers paquets non-référencés"
-
-msgid "could not start pack-objects"
-msgstr "impossible de démarrer le groupement d'objets"
-
-msgid "could not finish pack-objects"
-msgstr "impossible de finir le groupement d'objets"
-
#, c-format
msgid "unable to create lazy_dir thread: %s"
msgstr "impossible de créer le fil lazy_dir : %s"
@@ -17942,6 +18489,25 @@ msgstr "Refus de réécrire des notes dans %s (hors de refs/notes/)"
msgid "Bad %s value: '%s'"
msgstr "Mauvaise valeur de %s : '%s'"
+msgid "failed to decode tree entry"
+msgstr "échec de décodage de l'entrée d'abre"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "échec de mise en correspondance de l'entrée d'arbre avec %s"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "%s mauvais dans le commit"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "impossible de faire correspondre %s %s dans l'objet de commit"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Échec de conversion de l'objet de %s vers %s"
+
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
msgstr ""
@@ -18046,6 +18612,18 @@ msgid "packed object %s (stored in %s) is corrupt"
msgstr "l'objet empaqueté %s (stocké dans %s) est corrompu"
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "correspondance manquante entre %s et %s"
+
+#, c-format
+msgid "unable to open %s"
+msgstr "impossible d'ouvrir %s"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "les fichiers '%s' et '%s' diffèrent par leur contenu"
+
+#, c-format
msgid "unable to write file %s"
msgstr "impossible d'écrire le fichier %s"
@@ -18100,6 +18678,10 @@ msgid "cannot read object for %s"
msgstr "impossible de lire l'objet pour %s"
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "impossible de faire correspondre l'objet %s avec %s"
+
+#, c-format
msgid "object fails fsck: %s"
msgstr "l'objet est en échec de fsck : %s"
@@ -18127,10 +18709,6 @@ msgid "%s is not a valid '%s' object"
msgstr "%s n'est pas un objet '%s' valide"
#, c-format
-msgid "unable to open %s"
-msgstr "impossible d'ouvrir %s"
-
-#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "incohérence de hachage pour %s (%s attendu)"
@@ -18326,6 +18904,17 @@ msgstr "impossible d'analyser l'objet : %s"
msgid "hash mismatch %s"
msgstr "incohérence de hachage %s"
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "entrée dupliquée dans l'index en bitmap : '%s'"
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "essai de stockage d'un commit non-sélectionné : '%s'"
+
+msgid "too many pseudo-merges"
+msgstr "trop de pseudo-fusions"
+
msgid "trying to write commit not in index"
msgstr "échec de l'écriture de l'objet commit absent de l'index"
@@ -18352,6 +18941,20 @@ msgstr ""
"fichier d'index en bitmap corrompu (trop court pour correspondre à une table "
"de recherche)"
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"fichier d'index en bitmap corrompu (trop court pour correspondre à un entête "
+"de table de pseudo-fusion)"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"fichier d'index en bitmap corrompu (trop court pour correspondre à une table "
+"de pseudo-fusion)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "fichier d'index en bitmap corrompu, table de pseudo-fusion trop courte"
+
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "entrée dupliquée dans l'index en bitmap : '%s'"
@@ -18383,6 +18986,9 @@ msgstr "l'index inverse requis manque dans l'index multi-paquet"
msgid "could not open pack %s"
msgstr "impossible d'ouvrir le paquet '%s'"
+msgid "could not determine MIDX preferred pack"
+msgstr "impossible de déterminer le paquet préféré de MIDX"
+
#, c-format
msgid "preferred pack (%s) is invalid"
msgstr "le paquet préféré (%s) est invalide"
@@ -18405,6 +19011,13 @@ msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
msgstr "bitmap ewah corrompue : entête tronqué pour la bitmap du commit '%s'"
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "impossible de charger le paquet : '%s', pack-reuse désactivé"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "impossible de calculer le paquet préféré, pack-reuse désactivé"
+
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "objet '%s' non trouvé dans les bitmaps de type"
@@ -18434,6 +19047,10 @@ msgid "mismatch in bitmap results"
msgstr "décalage dans le résultats de bitmap"
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "l'index de pseudo-fusion est hors-limite (%<PRIu32> ≥ %<PRIuMAX>)"
+
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "impossible de trouver '%s' dans le paquet '%s' à l'offset %<PRIuMAX>"
@@ -18492,6 +19109,13 @@ msgstr "somme de contrôle invalide"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "position de rev-index invalide à %<PRIu64> : %<PRIu32> != %<PRIu32>"
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr ""
+"le tronçon d'index inversé de l'index multi-paquet n'a pas la bonne taille"
+
+msgid "could not determine preferred pack"
+msgstr "impossible de déterminer le paquet préféré"
+
msgid "cannot both write and verify reverse index"
msgstr "impossible de lire et vérifier à la fois l'index inverse"
@@ -18544,14 +19168,6 @@ msgid "%s requires a value"
msgstr "%s a besoin d'une valeur"
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s est incompatible avec %s"
-
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s est incompatible avec toute autre option"
-
-#, c-format
msgid "%s takes no value"
msgstr "%s n'accepte aucune valeur"
@@ -18634,6 +19250,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-NUM"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "opposé de --no-%s"
+
msgid "expiry-date"
msgstr "date-d'expiration"
@@ -18665,6 +19285,14 @@ msgstr ""
"caractère NUL"
#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "valeur booléenne d'environnement invalide '%s' pour '%s'"
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "échec de l'analyse de %s"
+
+#, c-format
msgid "Could not make %s writable by group"
msgstr "Impossible de rendre %s inscriptible pour le groupe"
@@ -18715,6 +19343,10 @@ msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s : 'literal' et 'glob' sont incompatibles"
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "'%s' est hors de l'arbre de répertoire"
+
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s : '%s' est hors du dépôt à '%s'"
@@ -18791,6 +19423,11 @@ msgstr "impossible de créer le lstat en fil : %s"
msgid "unable to parse --pretty format"
msgstr "impossible d'analyser le format --pretty"
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr ""
+"récupération paresseuse désactivée ; certains objets pourraient ne pas être "
+"disponibles"
+
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr ""
"promisor-remote : impossible de créer un sous-processus de récupération"
@@ -18818,6 +19455,68 @@ msgstr "object-info : vidage attendu après les arguments"
msgid "Removing duplicate objects"
msgstr "Suppression des objets dupliqués"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "impossible de charger la regex de pseudo-fusion pour %s : '%s'"
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s doit être non négatif, utilisation de la valeur par défaut"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s doit valoir entre 0 et 1, utilisation de la valeur par défaut"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s doit être positif, utilisation de la valeur par défaut"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "le groupe de pseudo-fusion '%s' n'a pas de motif requis"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"le group de pseudo-fusion '%s' a un seuil instable avec un seuil stable"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"l'expression rationnelle de pseudo-fusion a trop de groupes de capture "
+"(max=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"la lecture de la pseudo-fusion étendue est hors-limite "
+"(%<PRIuMAX>=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"l'entrée de pseudo-fusion étendue est trop courte (%<PRIuMAX> ≥ %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr ""
+"impossible de trouver la pseudo-fusion pour le commit '%s' à l'offset "
+"%<PRIuMAX>"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr "recherche de pseudo-fusion étendue hors-limite (%<PRIu32> ≥ %<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "lecture hors-limite : (%<PRIuMAX> ≥ %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr ""
+"impossible de lire la table de pseudo-fusions étendues pour le commit %s"
+
msgid "could not start `log`"
msgstr "impossible de démarrer `log`"
@@ -18876,10 +19575,6 @@ msgid "unable to add '%s' to index"
msgstr "impossible d'ajouter '%s' à l'index"
#, c-format
-msgid "unable to stat '%s'"
-msgstr "fstat de '%s' impossible"
-
-#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "'%s' existe à la fois comme un fichier et un répertoire"
@@ -18987,10 +19682,6 @@ msgid "failed to convert to a sparse-index"
msgstr "échec de conversion d'un index clairsemé"
#, c-format
-msgid "could not stat '%s'"
-msgstr "impossible de stat '%s'"
-
-#, c-format
msgid "unable to open git dir: %s"
msgstr "impossible d'ouvrir le répertoire git : %s"
@@ -19261,6 +19952,10 @@ msgid "expected format: %%(ahead-behind:<committish>)"
msgstr "format attendu : %%(ahead-behind:<commit-esque>)"
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "format attendu : %%(is-base:<commit-esque>)"
+
+#, c-format
msgid "malformed field name: %.*s"
msgstr "nom de champ malformé %.*s"
@@ -19433,11 +20128,18 @@ msgstr "le journal pour la réf %s s'arrête de manière inattendue sur %s"
msgid "log for %s is empty"
msgstr "le journal pour la réf %s est vide"
+msgid "refusing to force and skip creation of reflog"
+msgstr "refus de forcer et sauter la création du reflog"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "refus de mettre à jour une réf avec un nom cassé '%s'"
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "refus de mettre à jour la pseudo-réf '%s'"
+
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "échec de update_ref pour la réf '%s' : %s"
@@ -19460,10 +20162,6 @@ msgid "cannot process '%s' and '%s' at the same time"
msgstr "impossible de traiter '%s' et '%s' en même temps"
#, c-format
-msgid "could not remove reference %s"
-msgstr "impossible de supprimer la référence %s"
-
-#, c-format
msgid "could not delete reference %s: %s"
msgstr "impossible de supprimer la référence %s : %s"
@@ -19472,6 +20170,106 @@ msgid "could not delete references: %s"
msgstr "impossible de supprimer les références : %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr ""
+"Migration simulée des réfs terminée, le résultat peut être trouvé à '%s'\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "impossible de supprimer le répetoire de migration temporaire '%s'"
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "les références migrées peuvent être trouvées dans '%s'"
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"impossible de vérrouiller '%s' : symref attendu avec la cible '%s', mais réf "
+"normale trouvée"
+
+#, c-format
+msgid "cannot open directory %s"
+msgstr "impossible d'ouvrir le répertoire %s"
+
+msgid "Checking references consistency"
+msgstr "Vérification de la cohérence des références"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "le nom de réference est dangereux : %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "essai d'écriture de la réf '%s' avec l'objet inexistant %s"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "essai d'écriture de l'objet non commit %s dans la branche '%s'"
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"mises à jour multiples pour la réf 'HEAD' (l'une d'elle étant via son "
+"référence '%s') non permises"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr ""
+"impossible de verrouiller la référence '%s' : impossible de résoudre la "
+"référence '%s'"
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr ""
+"impossible de verrouiller la référence '%s' : erreur de lecture de la "
+"référence"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"mises à jour multiples pour '%s' (dont un via la symref '%s') non permises"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "impossible de verrouiller la référence '%s' : la référence existe déjà"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr ""
+"impossible de verrouiller la réf '%s' : la référence manque mais %s était "
+"attendu"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "impossible de verrouiller '%s' : pointe sur %s mais %s était attendu"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "reftable : préparation de transaction : %s"
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "reftable : échec de transaction : %s"
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "impossible de compacter la pile : %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "nom de réf '%s' non trouvé"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr ""
+"le nom de réf %s est une réf symbolique, la copie n'est pas prise en charge"
+
+#, c-format
msgid "invalid refspec '%s'"
msgstr "spécificateur de réference invalide : '%s'"
@@ -19480,6 +20278,10 @@ msgid "invalid quoting in push-option value: '%s'"
msgstr "citation invalide dans la valeur push-option : '%s'"
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "valeur inconnue pour object-format : %s"
+
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs n'est pas valide : est-ce bien un dépôt git ?"
@@ -19658,7 +20460,7 @@ msgid ""
"Neither worked, so we gave up. You must fully qualify the ref."
msgstr ""
"La destination que vous avez fournie n'est pas un nom de référence complète\n"
-"(c'est-à-dire commençant par \"ref/\"). Essai d'approximation par :\n"
+"(c'est-à-dire commençant par \"refs/\"). Essai d'approximation par :\n"
"\n"
"- Recherche d'une référence qui correspond à '%s' sur le serveur distant.\n"
"- Vérification si la <source> en cours de poussée ('%s')\n"
@@ -19935,9 +20737,19 @@ msgid "resolve-undo records `%s` which is missing"
msgstr "resolve-undo enregistre `%s` qui manque"
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s existe mais c'est une référence symbolique"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
msgstr ""
-"impossible de récupérer le commit pour l'argument de chemin d'ascendance %s"
+"--merge nécessite une pseudo-réf MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD "
+"ou REBASE_HEAD"
+
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "impossible de récupérer le commit pour l'argument --ancestry-path %s"
msgid "--unpacked=<packfile> no longer supported"
msgstr "--unpacked=<fichier-paquet> n'est plus géré"
@@ -20032,8 +20844,20 @@ msgstr "lors d'un clonage, créer un répertoire de travail complet"
msgid "only download metadata for the branch that will be checked out"
msgstr "ne télécharger les méta-données que pour la branche qui sera extraite"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<options>] [--] <dépôt> [<répertoire>]"
+msgid "create repository within 'src' directory"
+msgstr "Créer un dépôt dans le repertoire 'src'"
+
+msgid "specify if tags should be fetched during clone"
+msgstr ""
+"spécifier si les étiquettes devraient être récupérées pendant le clonage"
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <branche-principale>] [--full-"
+"clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enrôlement>]"
#, c-format
msgid "cannot deduce worktree name from '%s'"
@@ -20052,6 +20876,10 @@ msgid "could not configure remote in '%s'"
msgstr "impossible de paramétrer le distant dans '%s'"
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "impossible de désactiver les étiquettes dans '%s'"
+
+#, c-format
msgid "could not configure '%s'"
msgstr "impossible de configurer '%s'"
@@ -20084,12 +20912,28 @@ msgid "could not remove stale scalar.repo '%s'"
msgstr "impossible de supprimé le scalar.repo obsolète '%s'"
#, c-format
-msgid "removing stale scalar.repo '%s'"
+msgid "removed stale scalar.repo '%s'"
msgstr "suppression du scalar.repo obsolète '%s'"
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "dépôt git parti dans '%s'"
+msgid "repository at '%s' has different owner"
+msgstr "le dépôt dans '%s' a un propriétaire différent"
+
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "le dépôt dans '%s' a un problème de format"
+
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "dépôt non trouvé dans '%s'"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"pour désinscrire ce dépôt de Scalar, lancez\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
msgid ""
"scalar run <task> [<enlistment>]\n"
@@ -20203,6 +21047,19 @@ msgid "unknown action: %d"
msgstr "action inconnue : %d"
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 ""
+"Résolvez tous les conflits manuellement, marquez-les comme résolus avec\n"
+"\"git add/rm <fichier en conflit>\", puis lancez \"git rebase --continue\".\n"
+"Si vous préférez sauter ce commit, lancez \"git rebase --skip\". Pour "
+"arrêter\n"
+"et revenir à l'état antérieur à la commande, lancez \"git rebase --abort\"."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -20426,10 +21283,6 @@ msgid "could not update %s"
msgstr "impossible de mettre à jour %s"
#, c-format
-msgid "could not parse commit %s"
-msgstr "impossible d'analyser le commit %s"
-
-#, c-format
msgid "could not parse parent commit %s"
msgstr "impossible d'analyser le commit parent %s"
@@ -20497,10 +21350,6 @@ msgid "%s: cannot parse parent commit %s"
msgstr "%s : impossible d'analyser le commit parent %s"
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "impossible de renommer '%s' en '%s'"
-
-#, c-format
msgid "could not revert %s... %s"
msgstr "impossible d'annuler %s... %s"
@@ -20535,12 +21384,51 @@ msgstr ""
"heads/%s"
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "commande '%.*s' invalide"
+msgid "'%s' does not accept merge commits"
+msgstr "'%s' n'accepte pas de commit de fusion"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"'pick' n'accepte pas de commit de fusion. Si vous voulez\n"
+"rejouer la fusion, utilisez 'merge -C' sur le commit."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"'reword' n'accepte pas de commit de fusion.\n"
+"Si vous vouliez rejouer la fusion et la reformuler,\n"
+"utilisez 'merge -c' sur le commit"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"'edit' n'accepte pas de commit de fusion. Si vous vouliez\n"
+"rejouer la fusion, utilisez 'merge -C' sur le commit, puis\n"
+"'break' pour vous redonner le contrôle pour pouvoir faire\n"
+"'git commit --amend && git rebase --continue'."
+
+msgid "cannot squash merge commit into another commit"
+msgstr "impossible d'écraser un commit de fusion avec un autre commit"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s n'accepte pas d'argument : '%s'"
+msgid "invalid command '%.*s'"
+msgstr "commande '%.*s' invalide"
#, c-format
msgid "missing arguments for %s"
@@ -20655,9 +21543,8 @@ msgstr ""
msgid "cannot read HEAD"
msgstr "impossible de lire HEAD"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "impossible de copier '%s' vers '%s'"
+msgid "could not write commit message file"
+msgstr "impossible d'écrire le fichier de message de validation"
#, c-format
msgid ""
@@ -20826,6 +21713,9 @@ msgid "Autostash exists; creating a new stash entry."
msgstr ""
"Un remisage automatique existe ; création d'une nouvelle entrée de remisage."
+msgid "autostash reference is a symref"
+msgstr "la référence d'auto-remisage est une symref"
+
msgid "could not detach HEAD"
msgstr "impossible de détacher HEAD"
@@ -20858,14 +21748,14 @@ msgstr ""
" git rebase --continue\n"
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "Rebasage (%d/%d)%s"
-
-#, c-format
msgid "Stopped at %s... %.*s\n"
msgstr "Arrêt à %s... %.*s\n"
#, c-format
+msgid "Rebasing (%d/%d)%s"
+msgstr "Rebasage (%d/%d)%s"
+
+#, c-format
msgid "unknown command %d"
msgstr "commande inconnue %d"
@@ -20998,6 +21888,10 @@ msgstr ""
"configuration invalide"
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "'%s' déjà spécifié comme '%s'"
+
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "Version attendue du dépôt git <= %d, %d trouvée"
@@ -21056,6 +21950,22 @@ msgstr "impossible de revenir au répertoire de travail courant"
msgid "failed to stat '%*s%s%s'"
msgstr "échec du stat de '%*s%s%s'"
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' n'est pas absolu"
+
+#, 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 ""
+"propriétaire douteux détecté dans le dépôt à '%s'\n"
+"%sPour ajouter une exception pour ce dépôt, lancez :\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
msgid "Unable to read current working directory"
msgstr "Impossible d'accéder au répertoire de travail courant"
@@ -21078,18 +21988,6 @@ msgstr ""
"n'est pas défini)."
#, 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 ""
-"propriétaire douteux détecté dans le dépôt à '%s'\n"
-"%sPour ajouter une exception pour ce dépôt, lancez :\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-
-#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
msgstr "impossible d'utiliser le dépôt nu '%s' (safe.bareRepository vaut '%s')"
@@ -21145,6 +22043,10 @@ msgid "invalid initial branch name: '%s'"
msgstr "nom de branche initiale invalide : '%s'"
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-initialisation : --initial-branch=%s ignoré"
+
+#, c-format
msgid "unable to handle file type %d"
msgstr "impossible de traiter le fichier de type %d"
@@ -21155,15 +22057,17 @@ 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"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr ""
+"essai de réinitialisation du dépôt avec un format de stockage de références "
+"différent"
+
#, 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"
@@ -21186,6 +22090,21 @@ msgstr "l'entrée d'index est un répertoire, mais pas clairsemé (%08x)"
msgid "cannot use split index with a sparse index"
msgstr "impossible d'utiliser l'index scindé avec un index clairsemé"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "mauvais format %s : l'élément '%s' ne commence pas par '('"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "mauvais format '%s' : l'élément '%s' ne se termine pas ')'"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "mauvais format %s : %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
msgid "%u.%2.2u GiB"
@@ -21378,6 +22297,16 @@ msgstr ""
"'%.*s'"
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"'%.*s' dans le chemin du sous-module '%s' ne devait pas être un lien "
+"symbolique"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "le chemin du sous-module '%s' ne devait pas être un lien symbolique"
+
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
@@ -21416,10 +22345,6 @@ msgstr "échec du lstat de '%s'"
msgid "no remote configured to get bundle URIs from"
msgstr "aucun distant configuré depuis lequel récupérer des URIs de colis"
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "le distant '%s' n'a pas d'URL configuré"
-
msgid "could not get the bundle-uri list"
msgstr "impossible d'avoir la liste de bundle-uris"
@@ -21432,12 +22357,6 @@ msgstr "effacer l'arbre de cache avant chaque itération"
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr "nombre d'entrées dans l'arbre de cache à invalider (par défaut, 0)"
-msgid "unhandled options"
-msgstr "options non gérées"
-
-msgid "error preparing revisions"
-msgstr "erreur lors de la préparation des révisions"
-
#, c-format
msgid "commit %s is not marked reachable"
msgstr "le commit %s n'est pas marqué joignable"
@@ -21510,6 +22429,25 @@ msgstr "jeton"
msgid "command token to send to the server"
msgstr "jeton de commande à envoyer au serveur"
+msgid "unit-test [<options>]"
+msgstr "unit-test [<options>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "sortir immédiatement sur le premier échec"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr ""
+"lancer seulement la suite de test ou le test individuel <suite[::test]>"
+
+msgid "suite"
+msgstr "suite"
+
+msgid "exclude test suite <suite>"
+msgstr "exclure la suite de tests <suite>"
+
#, c-format
msgid "running trailer command '%s' failed"
msgstr "échec de la commande trailer '%s'"
@@ -21522,29 +22460,6 @@ msgstr "valeur inconnue '%s' pour la clé '%s'"
msgid "empty trailer token in trailer '%.*s'"
msgstr "symbole vide dans la ligne de fin '%.*s'"
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "impossible de lire le fichier d'entrée '%s'"
-
-#, c-format
-msgid "could not stat %s"
-msgstr "stat impossible de %s"
-
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "%s n'est pas un fichier régulier"
-
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "le fichier %s n'est pas inscriptible par l'utilisateur"
-
-msgid "could not open temporary file"
-msgstr "impossible de créer un fichier temporaire"
-
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "impossible de renommer un fichier temporaire en %s"
-
msgid "full write to remote helper failed"
msgstr "échec de l'écriture totale sur l'assistant distant"
@@ -21597,9 +22512,6 @@ msgstr ""
msgid "invalid remote service path"
msgstr "chemin de service distant invalide"
-msgid "operation not supported by protocol"
-msgstr "option non supportée par le protocole"
-
#, c-format
msgid "can't connect to subservice %s"
msgstr "impossible de se connecter au sous-service %s"
@@ -21648,8 +22560,8 @@ msgstr ""
"nécessaire"
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "l'assistant %s ne gère pas 'force'"
+msgid "helper %s does not support '--force'"
+msgstr "l'assistant %s ne gère pas '--force'"
msgid "couldn't run fast-export"
msgstr "impossible de lancer fast-export"
@@ -21732,10 +22644,6 @@ msgid "support for protocol v2 not implemented yet"
msgstr "le support du protocole v2 n'est pas encore implanté"
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "valeur inconnue pour la config '%s' : %s"
-
-#, c-format
msgid "transport '%s' not allowed"
msgstr "transport '%s' non permis"
@@ -21789,6 +22697,9 @@ msgid "could not retrieve server-advertised bundle-uri list"
msgstr ""
"impossible de récupérer la liste de bundle-uris annoncée par le serveur"
+msgid "operation not supported by protocol"
+msgstr "option non supportée par le protocole"
+
msgid "too-short tree object"
msgstr "objet arbre trop court"
@@ -22073,6 +22984,10 @@ msgstr "numéro de port invalide"
msgid "invalid '..' path segment"
msgstr "segment de chemin '..' invalide"
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "erreur : impossible de formater le message : %s\n"
+
msgid "usage: "
msgstr "usage : "
@@ -22189,6 +23104,9 @@ msgstr "impossible d'accéder à '%s'"
msgid "unable to get current working directory"
msgstr "impossible d'accéder au répertoire de travail courant"
+msgid "unable to get random bytes"
+msgstr "impossible d'acquérir des octets aléatoires"
+
msgid "Unmerged paths:"
msgstr "Chemins non fusionnés :"
@@ -22635,6 +23553,10 @@ msgstr "de plus, votre index contient des modifications non validées."
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "%s impossible : votre index contient des modifications non validées."
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "style inconnu '%s' pour '%s'"
+
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22732,6 +23654,9 @@ msgstr "'%s.final' contient le courriel composé.\n"
msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases est incompatible avec d'autres options\n"
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases et --translate-aliases sont mutuellement exclusifs.\n"
+
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -22828,13 +23753,13 @@ msgstr ""
"Effacez le corps si vous ne souhaitez pas envoyer un résumé.\n"
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "Échec à l'ouverture de %s : %s"
-
-#, perl-format
msgid "Failed to open %s.final: %s"
msgstr "Échec à l'ouverture de %s.final : %s"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "Échec à l'ouverture de %s : %s"
+
msgid "Summary email is empty, skipping it\n"
msgstr "Le courriel de résumé étant vide, il a été ignoré\n"
@@ -22944,24 +23869,24 @@ msgid "Failed to send %s\n"
msgstr "Échec de l'envoi de %s\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Envoi simulé de %s\n"
+msgid "Dry-Sent %s"
+msgstr "Envoi simulé de %s"
#, perl-format
-msgid "Sent %s\n"
-msgstr "%s envoyé\n"
+msgid "Sent %s"
+msgstr "%s envoyé"
-msgid "Dry-OK. Log says:\n"
-msgstr "Simulation OK. Le journal indique :\n"
+msgid "Dry-OK. Log says:"
+msgstr "Simulation OK. Le journal indique :"
-msgid "OK. Log says:\n"
-msgstr "OK. Le journal indique :\n"
+msgid "OK. Log says:"
+msgstr "OK. Le journal indique :"
msgid "Result: "
msgstr "Résultat : "
-msgid "Result: OK\n"
-msgstr "Résultat : OK\n"
+msgid "Result: OK"
+msgstr "Résultat : OK"
#, perl-format
msgid "can't open file %s"
@@ -23036,6 +23961,194 @@ msgstr "%s sauté avec un suffix de sauvegarde '%s'.\n"
msgid "Do you really want to send %s? [y|N]: "
msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : "
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "échec de la préparation du parcours des révisions\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "impossible d'analyser le contact : %s"
+
+#, c-format
+#~ msgid "truncating .rej filename to %.*s.rej"
+#~ msgstr "troncature du nom de fichier .rej en %.*s.rej"
+
+#~ msgid ""
+#~ "the add.interactive.useBuiltin setting has been removed!\n"
+#~ "See its entry in 'git help config' for details."
+#~ msgstr ""
+#~ "le réglage add.interactive.useBuiltin a été supprimé !\n"
+#~ "Référez-vous à cette entrée dans 'git help config' pour plus de détails."
+
+#~ msgid "git archive: Remote with no URL"
+#~ msgstr "git archive : Dépôt distant sans URL"
+
+#~ msgid "only one action at a time"
+#~ msgstr "une seule action à la fois"
+
+#~ msgid "use [RFC PATCH] instead of [PATCH]"
+#~ msgstr "utiliser [RFC PATCH] au lieu de [PATCH]"
+
+#, c-format
+#~ msgid "no URLs configured for remote '%s'"
+#~ msgstr "aucune URL configurée pour le dépôt distant '%s'"
+
+#, c-format
+#~ msgid "remote '%s' has no configured URL"
+#~ msgstr "le distant '%s' n'a pas d'URL configuré"
+
+#~ msgid ""
+#~ "Use -f if you really want to add them.\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addIgnoredFile false\""
+#~ msgstr ""
+#~ "Utilisez -f si vous voulez vraiment les ajouter.\n"
+#~ "Éliminez ce message en lançant\n"
+#~ "\"git config advice.addIgnoredFile false\""
+
+#~ msgid ""
+#~ "Maybe you wanted to say 'git add .'?\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addEmptyPathspec false\""
+#~ msgstr ""
+#~ "Peut-être avez-vous voulu dire 'git add .' ?\n"
+#~ "Éliminez ce message en lançant\n"
+#~ "\"git config advice.addEmptyPathspec false\""
+
+#~ msgid ""
+#~ "clean.requireForce defaults to true and neither -i, -n, nor -f given; "
+#~ "refusing to clean"
+#~ msgstr ""
+#~ "clean.requireForce à true par défaut et ni -i, -n ou -f fourni ; refus de "
+#~ "nettoyer"
+
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not start with '('"
+#~ msgstr "mauvais format ls-files : l'élément '%s' ne commence pas par '('"
+
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not end in ')'"
+#~ msgstr "mauvais format ls-files : l'élément '%s' ne se termine pas par ')'"
+
+#, c-format
+#~ msgid "bad ls-files format: %%%.*s"
+#~ msgstr "mauvais format ls-files : %%%.*s"
+
+#~ msgid "keep redundant, empty commits"
+#~ msgstr "garder les validations redondantes, vides"
+
+#~ msgid "core.commentChar should only be one ASCII character"
+#~ msgstr "core.commentChar ne devrait être qu'un unique caractère ASCII"
+
+#~ msgid ""
+#~ "--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+#~ "exclude"
+#~ msgstr ""
+#~ "--bundle-uri est incompatible avec --depth, --shallow-since, et --shallow-"
+#~ "exclude"
+
+#~ msgid "--merge-base is incompatible with --stdin"
+#~ msgstr "--merge-base est incompatible avec --stdin"
+
+#~ msgid ""
+#~ "apply options are incompatible with rebase.autoSquash. Consider adding --"
+#~ "no-autosquash"
+#~ msgstr ""
+#~ "les options d'application sont incompatibles avec rebase.autoSquash. "
+#~ "Considérez l'ajout de --no-autosquash"
+
+#~ msgid "--exclude-hidden cannot be used together with --branches"
+#~ msgstr "--exclude-hidden ne peut être utilisé avec --branches"
+
+#~ msgid "--exclude-hidden cannot be used together with --tags"
+#~ msgstr "--exclude-hidden ne peut pas être utilisé avec --tags"
+
+#~ msgid "--exclude-hidden cannot be used together with --remotes"
+#~ msgstr "--exclude-hidden ne peut pas être utilisé avec --remotes"
+
+#, c-format
+#~ msgid "only one of '%s', '%s' or '%s' can be given"
+#~ msgstr "les options '%s', '%s' et '%s' sont mutuellement exclusives"
+
+#, c-format
+#~ msgid "'%s' and '%s' cannot be used together"
+#~ msgstr "'%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>"
+
+#, c-format
+#~ msgid "%s is incompatible with %s"
+#~ msgstr "%s est incompatible avec %s"
+
+#~ msgid "unhandled options"
+#~ msgstr "options non gérées"
+
+#, c-format
+#~ msgid "options '%s=%s' and '%s=%s' cannot be used together"
+#~ msgstr ""
+#~ "les options '%s=%s' et '%s=%s' ne peuvent pas être utilisées ensemble"
+
+#, c-format
+#~ msgid "%s : incompatible with something else"
+#~ msgstr "%s est incompatible avec toute autre option"
+
+#~ msgid "Could not write patch"
+#~ msgstr "Impossible d'écrire le patch"
+
+#, c-format
+#~ msgid "Could not stat '%s'"
+#~ msgstr "Stat de '%s' impossible"
+
+#, c-format
+#~ msgid "Cannot delete branch '%s' checked out at '%s'"
+#~ msgstr "Impossible de supprimer la branche '%s' extraite dans '%s'"
+
+#~ msgid "unable to write new_index file"
+#~ msgstr "impossible d'écrire le fichier new_index"
+
+#~ msgid "do not apply config rules"
+#~ msgstr "ne pas appliquer les règles de la configuration"
+
+#~ msgid "join whitespace-continued values"
+#~ msgstr "joindre les valeurs continuées avec des caractères blancs"
+
+#~ msgid "set parsing options"
+#~ msgstr "paramètres d'analyse"
+
+#~ msgid "cannot move directory over file"
+#~ msgstr "impossible de déplacer un répertoire sur un fichier"
+
+#~ msgid "cannot use --filter without --stdout"
+#~ msgstr "impossible d'utiliser --filter sans --stdout"
+
+#~ msgid "cannot use --max-pack-size with --cruft"
+#~ msgstr "impossible d'utiliser --max-pack-size avec --cruft"
+
+#~ msgid "--strategy requires --merge or --interactive"
+#~ msgstr "--strategy requiert --merge ou --interactive"
+
+#, c-format
+#~ msgid ""
+#~ "commit-graph has generation number zero for commit %s, but non-zero "
+#~ "elsewhere"
+#~ msgstr ""
+#~ "le graphe de commit a un numéro de génération nul pour le commit %s, mais "
+#~ "non-nul ailleurs"
+
+#~ msgid "--merge-base only works with commits"
+#~ msgstr "--merge-base ne fonctionne qu'avec des commits"
+
+#~ msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+#~ msgstr "scalar clone [<options>] [--] <dépôt> [<répertoire>]"
+
+#, c-format
+#~ msgid "could not rename '%s' to '%s'"
+#~ msgstr "impossible de renommer '%s' en '%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."
diff --git a/po/id.po b/po/id.po
index e20e18e893..fc34140776 100644
--- 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-08-06 17:06+0700\n"
-"PO-Revision-Date: 2023-08-06 17:06+0700\n"
+"POT-Creation-Date: 2024-10-04 08:33+0700\n"
+"PO-Revision-Date: 2024-10-04 08:52+0700\n"
"Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n"
"Language-Team: Indonesian\n"
"Language: id\n"
@@ -104,12 +104,12 @@ msgstr[1] "%d jalur ditambahkan\n"
msgid "ignoring unmerged: %s"
msgstr "mengabaikan tak tergabung: %s"
-#: add-interactive.c add-patch.c
+#: add-interactive.c
#, c-format
msgid "Only binary files changed.\n"
msgstr "Hanya berkas biner yang berubah.\n"
-#: add-interactive.c add-patch.c
+#: add-interactive.c
#, c-format
msgid "No changes.\n"
msgstr "Tidak ada perubahan.\n"
@@ -591,12 +591,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"Untuk menghapus baris '%c', buatlah menjadi baris ' ' (konteks).\n"
"Untuk menghapus baris '%c', hapuslahnya.\n"
-"Baris yang diawali dengan %c akan dihapus.\n"
+"Baris yang diawali dengan %s akan dihapus.\n"
#: add-patch.c
msgid ""
@@ -651,17 +651,26 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
-"j - biarkan bingkah ini ragu, lihat bingkah ragu berikutnya\n"
-"J - biarkan bingkah ini ragu, lihat bingkah berikutnya\n"
-"k - biarkan bingkah ini ragu, lihat bingkah ragu sebelumnya\n"
-"K - biarkan bingkah ini ragu, lihat bingkah sebelumnya\n"
+"j - biarkan bingkah ini tak diputuskan, lihat bingkah berikutnya yang belum "
+"diputuskan\n"
+"J - biarkan bingkah ini tak diputuskan, lihat bingkah berikutnya\n"
+"k - biarkan bingkah ini tak diputuskan, lihat bingkah sebelumnya yang belum "
+"diputuskan\n"
+"K - biarkan bingkah ini tak diputuskan, lihat bingkah sebelumnya\n"
"g - pilih satu bingkah untuk dikunjungi\n"
"/ - cari satu bingkah yang cocok dengan regex yang diberikan\n"
"s - belah bingkah saat ini ke dalam bingkah yang lebih kecil\n"
"e - sunting bingkah saat ini secara manual\n"
-"? - cetak bantuan\n"
+"p - lihat bingkah saat ini, 'P' untuk menggunakan pager\n"
+"? - lihat bantuan\n"
+
+#: add-patch.c
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "Hanya satu huruf yang diharapkan, dapat '%s'"
#: add-patch.c
msgid "No previous hunk"
@@ -726,9 +735,22 @@ msgid "Sorry, cannot edit this hunk"
msgstr "Maaf, tidak dapat menyunting bingkah ini"
#: add-patch.c
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Perintah tidak dikenal '%s' (gunakan '?' untuk bantuan)"
+
+#: add-patch.c
msgid "'git apply' failed"
msgstr "'git apply' gagal"
+#: add-patch.c
+msgid "No changes."
+msgstr "Tidak ada perubahan."
+
+#: add-patch.c
+msgid "Only binary files changed."
+msgstr "Hanya berkas biner yang berubah."
+
#: advice.c
#, c-format
msgid ""
@@ -740,8 +762,8 @@ msgstr ""
#: advice.c
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%shint: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%spetunjuk:%s%.*s%s\n"
#: advice.c
msgid "Cherry-picking is not possible because you have unmerged files."
@@ -764,9 +786,8 @@ msgid "Reverting is not possible because you have unmerged files."
msgstr "Pembalikkan tidak mungkin sebab Anda punya berkas tak tergabung."
#: advice.c
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "Tidak mungkin untuk %s sebab Anda punya berkas tak tergabung."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "Pendasaran ulang tidak mungkin sebab Anda punya berkas tak tergabung."
#: advice.c
msgid ""
@@ -910,7 +931,7 @@ msgid "unclosed quote"
msgstr "tanda kutip tak ditutup"
#: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c
-#: builtin/receive-pack.c builtin/tag.c
+#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c
msgid "too many arguments"
msgstr "terlalu banyak argumen"
@@ -924,14 +945,16 @@ msgstr "opsi spasi putih tidak dikenal '%s'"
msgid "unrecognized whitespace ignore option '%s'"
msgstr "opsi abai spasi putih tidak dikenal '%s'"
-#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout.c
-#: builtin/clone.c builtin/commit.c builtin/describe.c builtin/diff-tree.c
-#: builtin/difftool.c builtin/fast-export.c builtin/fetch.c builtin/help.c
-#: builtin/index-pack.c builtin/init-db.c builtin/log.c builtin/ls-files.c
-#: builtin/merge-base.c builtin/merge.c builtin/pack-objects.c builtin/push.c
-#: builtin/rebase.c builtin/repack.c builtin/reset.c builtin/rev-list.c
-#: builtin/show-branch.c builtin/stash.c builtin/submodule--helper.c
-#: builtin/tag.c builtin/worktree.c parse-options.c range-diff.c revision.c
+#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c
+#: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c
+#: builtin/describe.c builtin/diff-tree.c builtin/difftool.c
+#: builtin/fast-export.c builtin/fetch.c builtin/help.c builtin/index-pack.c
+#: builtin/init-db.c builtin/log.c builtin/ls-files.c builtin/merge-base.c
+#: builtin/merge-tree.c builtin/merge.c builtin/pack-objects.c builtin/rebase.c
+#: builtin/repack.c builtin/replay.c builtin/reset.c builtin/rev-list.c
+#: builtin/rev-parse.c builtin/show-branch.c builtin/stash.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/worktree.c parse-options.c
+#: range-diff.c revision.c
#, c-format
msgid "options '%s' and '%s' cannot be used together"
msgstr "Opsi '%s' dan '%s' tidak dapat digunakan bersamaan"
@@ -1358,11 +1381,6 @@ msgstr[1] "Menerapkan tambalan %%s dengan %d penolakan..."
#: apply.c
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "memotong nama berkas .rej ke %.*s.rej"
-
-#: apply.c
-#, c-format
msgid "cannot open %s"
msgstr "tidak dapat membuka %s"
@@ -1421,7 +1439,7 @@ msgid_plural "%d lines applied after fixing whitespace errors."
msgstr[0] "%d baris diterapkan setelah memperbaiki kesalahan spasi putih."
msgstr[1] "%d baris diterapkan setelah memperbaiki kesalahan spasi putih."
-#: apply.c builtin/add.c builtin/mv.c builtin/rm.c
+#: apply.c builtin/mv.c builtin/rm.c
msgid "Unable to write new index file"
msgstr "Tidak dapat menulis berkas indeks baru"
@@ -1486,6 +1504,18 @@ msgstr "juga terapkan tambalan (gunakan dengan --stat/--summary/--check)"
msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr "coba penggabungan tiga arah, mundur ke penambalan normal jika gagal"
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "untuk konflik, gunakan versi kami"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "untuk konflik, gunakan versi mereka"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "untuk konflik, gunakan versi bersatu"
+
#: apply.c
msgid "build a temporary index based on embedded index information"
msgstr "bangun sebuah indeks sementara berdasarkan informasi indeks tertanam"
@@ -1547,6 +1577,10 @@ msgstr "tambahkan <akar> di depan semua nama berkas"
msgid "don't return error for empty patches"
msgstr "jangan kembalikan kesalahan untuk tambalan kosong"
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, dan --union memerlukan --3way"
+
#: archive-tar.c archive-zip.c
#, c-format
msgid "cannot stream blob %s"
@@ -1636,6 +1670,10 @@ msgstr "bukan nama objek valid: %s"
msgid "not a tree object: %s"
msgstr "bukan objek pohon: %s"
+#: archive.c builtin/clone.c
+msgid "unable to checkout working tree"
+msgstr "tidak dapat men-checkout pohon kerja"
+
#: archive.c
#, c-format
msgid "File not found: %s"
@@ -1752,6 +1790,11 @@ msgstr "opsi `%s' butuh '%s'"
msgid "Unexpected option --output"
msgstr "Opsi --output tak diharapkan"
+#: archive.c t/unit-tests/unit-test.c
+#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "parameter konfigurasi tambahan: '%s'"
+
#: archive.c
#, c-format
msgid "Unknown archive format '%s'"
@@ -1805,9 +1848,25 @@ msgid "ignoring overly large gitattributes blob '%s'"
msgstr "mengabaikan blob gitattributes '%s' yang terlalu besar"
#: attr.c
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr ""
+"tidak dapat menggunakan --attr-source atau GIT_ATTR_SOURCE tanpa repositori"
+
+#: attr.c
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "--attr-source atau GIT_ATTR_SOURCE jelek"
+#: attr.c read-cache.c
+#, c-format
+msgid "unable to stat '%s'"
+msgstr "tidak dapat men-stat '%s'"
+
+#: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
+#, c-format
+msgid "unable to read %s"
+msgstr "tidak dapat membaca %s"
+
#: bisect.c
#, c-format
msgid "Badly quoted content in file '%s': %s"
@@ -1887,6 +1946,11 @@ msgstr "sebuah revisi %s diperlukan"
msgid "could not create file '%s'"
msgstr "tidak dapat membuat berkas '%s'"
+#: bisect.c builtin/notes.c
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "tidak dapat memulai 'show' untuk objek '%s'"
+
#: bisect.c builtin/merge.c
#, c-format
msgid "could not read file '%s'"
@@ -1936,9 +2000,9 @@ 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 remote.c
-#: sequencer.c submodule.c
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
+#: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
+#: remote.c sequencer.c submodule.c
msgid "revision walk setup failed"
msgstr "persiapan jalan revisi gagal"
@@ -2063,6 +2127,10 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "'%s' bukan nama cabang valid"
+#: branch.c builtin/branch.c
+msgid "See `man git check-ref-format`"
+msgstr "Lihat `man git check-ref-format`"
+
#: branch.c
#, c-format
msgid "a branch named '%s' already exists"
@@ -2143,8 +2211,8 @@ msgstr "submodul '%s': tidak dapat membuat cabang '%s'"
#: branch.c
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "'%s' sudah di-checkout pada '%s'"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "'%s' sudah digunakan oleh pohon kerja di '%s'"
#: builtin/add.c
msgid "git add [<options>] [--] <pathspec>..."
@@ -2160,38 +2228,26 @@ msgid "Unstaged changes after refreshing the index:"
msgstr "Perubahan tak tergelar setelah menyegarkan indeks:"
#: builtin/add.c
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"setelan add.interactive.useBuiltin sudah dihapus!\n"
-"Selengkapnya lihat entrinya di 'git help config'."
-
-#: builtin/add.c builtin/rev-parse.c
-msgid "Could not read the index"
-msgstr "Tidak dapat membaca indeks"
-
-#: builtin/add.c
-msgid "Could not write patch"
-msgstr "Tidak dapat menulis tambalan"
+msgid "could not read the index"
+msgstr "tidak dapat membaca indeks"
#: builtin/add.c
msgid "editing patch failed"
msgstr "Gagal menyunting tambalan"
-#: builtin/add.c
+#: builtin/add.c read-cache.c
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Tidak dapat men-stat '%s'"
+msgid "could not stat '%s'"
+msgstr "tidak dapat men-stat '%s'"
#: builtin/add.c
-msgid "Empty patch. Aborted."
-msgstr "Tambalan kosong. Dibatalkan."
+msgid "empty patch. aborted"
+msgstr "tambalan kosong, dibatalkan"
#: builtin/add.c
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Tidak dapat terapkan '%s'"
+msgid "could not apply '%s'"
+msgstr "tidak dapat menerapkan '%s'"
#: builtin/add.c
msgid "The following paths are ignored by one of your .gitignore files:\n"
@@ -2205,7 +2261,7 @@ msgstr "latihan"
#: builtin/add.c builtin/check-ignore.c builtin/commit.c
#: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
-#: builtin/read-tree.c
+#: builtin/read-tree.c builtin/refs.c
msgid "be verbose"
msgstr "jadi berkata-kata"
@@ -2306,14 +2362,8 @@ msgid "adding embedded git repository: %s"
msgstr "menambahkan repositori git tertanam: %s"
#: builtin/add.c
-msgid ""
-"Use -f if you really want to add them.\n"
-"Turn this message off by running\n"
-"\"git config advice.addIgnoredFile false\""
-msgstr ""
-"Gunakan -f jika Anda benar-benar ingin menambahkannya.\n"
-"Matikan pesan ini dengan menjalankan\n"
-"\"git config advice.addIgnoredFile false\""
+msgid "Use -f if you really want to add them."
+msgstr "Gunakan -f jika Anda benar-benar ingin menambahkannya."
#: builtin/add.c
msgid "adding files failed"
@@ -2336,14 +2386,8 @@ msgid "Nothing specified, nothing added.\n"
msgstr "Tidak ada yang disebutkan, tidak ada yang ditambahkan.\n"
#: builtin/add.c
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Mungkin Anda ingin bilang 'git add .'?\n"
-"Matikan pesan ini dengan menjalankan\n"
-"\"git config advice.addEmptyPathspec false\""
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Mungkin Anda ingin bilang 'git add .'?"
#: builtin/add.c builtin/check-ignore.c builtin/checkout.c builtin/clean.c
#: builtin/commit.c builtin/diff-tree.c builtin/grep.c builtin/mv.c
@@ -2352,14 +2396,19 @@ msgstr ""
msgid "index file corrupt"
msgstr "berkas indeks rusak"
+#: builtin/add.c builtin/am.c builtin/checkout.c builtin/clone.c
+#: builtin/commit.c builtin/stash.c merge.c rerere.c
+msgid "unable to write new index file"
+msgstr "gagal menulis berkas indeks baru"
+
#: builtin/am.c builtin/mailinfo.c mailinfo.c
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "tindakan jelek '%s' untuk '%s'"
#: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c
-#: builtin/pull.c diff-merges.c gpg-interface.c ls-refs.c parallel-checkout.c
-#: sequencer.c setup.c
+#: builtin/pull.c builtin/revert.c config.c diff-merges.c gpg-interface.c
+#: ls-refs.c parallel-checkout.c sequencer.c setup.c
#, c-format
msgid "invalid value for '%s': '%s'"
msgstr "nilai tidak valid untuk '%s': '%s'"
@@ -2443,29 +2492,30 @@ msgstr "Gagal memecah tambalan."
#: builtin/am.c
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Saat Anda sudah menyelesaikan masalah ini, jalankan \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr ""
+"Saat Anda sudah menyelesaikan masalah ini, jalankan \"%s --continue\".\n"
#: builtin/am.c
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
msgstr ""
-"Jika Anda lebih suka melewati tambalan ini, jalankan \"%s --skip\" sebagai "
-"gantinya."
+"Jika Anda lebih suka melewati tambalan ini, jalankan \"%s --skip\" saja.\n"
#: builtin/am.c
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
"Untuk merekam tambalan kosong sebagai komit kosong, jalankan \"%s --allow-"
-"empty\"."
+"empty\".\n"
#: builtin/am.c
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
msgstr ""
"Untuk mengembalikan cabang yang asli dan berhenti menambal, jalankan \"%s --"
-"abort\""
+"abort\"."
#: builtin/am.c
msgid "Patch sent with format=flowed; space at the end of lines might be lost."
@@ -2522,8 +2572,7 @@ msgstr "git write-tree gagal menulis sebuah pohon"
msgid "applying to an empty history"
msgstr "menerapkan ke sebuah riwayat kosong"
-#: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
-#: t/helper/test-fast-rebase.c
+#: builtin/am.c builtin/commit.c builtin/merge.c builtin/replay.c sequencer.c
msgid "failed to write commit object"
msgstr "gagal menulis objek komit"
@@ -2615,11 +2664,6 @@ msgstr ""
"Anda mungkin jalankan `git rm` pada berkas untuk menerima \"penghapusan oleh "
"mereka\" untuk itu."
-#: builtin/am.c builtin/checkout.c builtin/clone.c builtin/stash.c merge.c
-#: rerere.c
-msgid "unable to write new index file"
-msgstr "gagal menulis berkas indeks baru"
-
#: builtin/am.c builtin/reset.c
#, c-format
msgid "Could not parse object '%s'."
@@ -2637,17 +2681,12 @@ msgstr ""
"Sepertinya Anda telah memindahkan HEAD sejak kegagalan 'am' terakhir.\n"
"Tidak memutar ulang ke ORIG_HEAD"
-#: builtin/am.c builtin/bisect.c worktree.c
+#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c
#, c-format
msgid "failed to read '%s'"
msgstr "gagal membaca '%s'"
#: builtin/am.c
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "Opsi '%s=%s' dan '%s=%s' tidak dapat digunakan bersamaan"
-
-#: builtin/am.c
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<opsi>] [(<mbox> | <Maildir>)...]"
@@ -2719,8 +2758,9 @@ msgid "n"
msgstr "n"
#: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
-#: builtin/diagnose.c builtin/for-each-ref.c builtin/ls-files.c
-#: builtin/ls-tree.c builtin/replace.c builtin/tag.c builtin/verify-tag.c
+#: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
+#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
msgid "format"
msgstr "format"
@@ -2757,6 +2797,10 @@ msgid "show the patch being applied"
msgstr "perlihatkan tambalan yang diterapkan"
#: builtin/am.c
+msgid "try to apply current patch again"
+msgstr "coba terapkan lagi tambalan saat ini"
+
+#: builtin/am.c
msgid "record the empty patch as an empty commit"
msgstr "rekam tambalan kosong sebagai komit kosong"
@@ -2829,10 +2873,6 @@ msgid "could not redirect output"
msgstr "tidak dapat mengalihkan keluaran"
#: builtin/archive.c
-msgid "git archive: Remote with no URL"
-msgstr "git archive: Remote tanpa URL"
-
-#: builtin/archive.c
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive: ACK/NAK diharapkan, dapat paket bilasan"
@@ -2851,10 +2891,10 @@ msgstr "git archive: sebuah bilasan diharapkan"
#: builtin/bisect.c
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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}=<istilah> --term-{old, good}=<istilah>] "
+"git bisect start [--term-(new,bad)=<istilah> --term-(old, good)=<istilah>] "
"[--no-checkout] [--first-parent] [<jelek> [<bagus>...]] [--] [<jalur>...]"
#: builtin/bisect.c
@@ -2874,8 +2914,8 @@ msgid "git bisect replay <logfile>"
msgstr "git bisect replay <berkas log>"
#: builtin/bisect.c
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <perintah>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <perintah> [<argumen>...]"
#: builtin/bisect.c
#, c-format
@@ -3019,10 +3059,6 @@ msgstr ""
"Opsi yang didukung adalah: --term-good|--term-old dan --term-bad|--term-new."
#: builtin/bisect.c
-msgid "revision walk setup failed\n"
-msgstr "setup jalan revisi gagal\n"
-
-#: builtin/bisect.c
#, c-format
msgid "could not open '%s' for appending"
msgstr "tidak dapat membuka '%s' untuk menambahkan"
@@ -3394,37 +3430,38 @@ msgstr "git branch [<opsi>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
"menghapus cabang '%s' yang sudah digabungkan ke\n"
-" '%s', tapi belum digabungkan ke HEAD."
+" '%s', tapi belum digabungkan ke HEAD"
#: builtin/branch.c
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
"tidak menghapus cabang '%s' yang belum digabungkan ke\n"
-" '%s', walaupun tergabung ke HEAD."
+" '%s', walaupun tergabung ke HEAD"
#: builtin/branch.c
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Tidak dapat mencari objek komit untuk '%s'"
+msgid "couldn't look up commit object for '%s'"
+msgstr "tidak dapat mencari objek komit untuk '%s'"
#: builtin/branch.c
#, 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 ""
-"Cabang '%s' belum sepenuhnya tergabung.\n"
-"Kalau Anda yakin ingin menghapusnya, jalankan 'git branch -D %s'."
+msgid "the branch '%s' is not fully merged"
+msgstr "cabang '%s' belum sepenuhnya digabungkan"
#: builtin/branch.c
-msgid "Update of config-file failed"
-msgstr "Pembaruan berkas konfigurasi gagal"
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "Jika anda yakin untuk menghapusnya, lakukan 'git branch -D %s'"
+
+#: builtin/branch.c
+msgid "update of config-file failed"
+msgstr "pembaruan berkas konfigurasi gagal"
#: builtin/branch.c
msgid "cannot use -a with -d"
@@ -3432,13 +3469,14 @@ msgstr "tidak dapat gunakan -a dengan -d"
#: builtin/branch.c
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "Tidak dapat menghapus cabang '%s' yang ter-checkout pada '%s'"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"tidak dapat menghapus cabang '%s' yang digunakan oleh pohon kerja di '%s'"
#: builtin/branch.c
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "cabang pelacak remote '%s' tidak ditemukan."
+msgid "remote-tracking branch '%s' not found"
+msgstr "cabang pelacak remote '%s' tidak ditemukan"
#: builtin/branch.c
#, c-format
@@ -3451,8 +3489,8 @@ msgstr ""
#: builtin/branch.c
#, c-format
-msgid "branch '%s' not found."
-msgstr "cabang '%s' tidak ditemukan."
+msgid "branch '%s' not found"
+msgstr "cabang '%s' tidak ditemukan"
#: builtin/branch.c
#, c-format
@@ -3479,13 +3517,13 @@ msgstr "HEAD (%s) merujuk diluar refs/heads/"
#: builtin/branch.c
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "Cabang %s sedang didasarkan ulang pada %s"
+msgid "branch %s is being rebased at %s"
+msgstr "cabang %s sedang didasarkan ulang pada %s"
#: builtin/branch.c
#, c-format
-msgid "Branch %s is being bisected at %s"
-msgstr "Cabang %s sedang dibagi dua pada %s"
+msgid "branch %s is being bisected at %s"
+msgstr "cabang %s sedang dibagi dua pada %s"
#: builtin/branch.c
#, c-format
@@ -3494,60 +3532,60 @@ msgstr "HEAD dari pohon kerja %s tidak diperbarui"
#: builtin/branch.c
#, c-format
-msgid "Invalid branch name: '%s'"
-msgstr "Nama cabang tidak valid: '%s'"
+msgid "invalid branch name: '%s'"
+msgstr "nama cabang tidak valid: '%s'"
#: builtin/branch.c
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Belum ada komit pada cabang '%s'."
+msgid "no commit on branch '%s' yet"
+msgstr "belum ada komit pada cabang '%s'."
#: builtin/branch.c
#, c-format
-msgid "No branch named '%s'."
-msgstr "Tidak ada cabang bernama '%s'."
+msgid "no branch named '%s'"
+msgstr "tidak ada cabang bernama '%s'"
#: builtin/branch.c
-msgid "Branch rename failed"
-msgstr "Penggantian nama cabang gagal"
+msgid "branch rename failed"
+msgstr "penggantian nama cabang gagal"
#: builtin/branch.c
-msgid "Branch copy failed"
-msgstr "Penyalinan cabang gagal"
+msgid "branch copy failed"
+msgstr "penyalinan cabang gagal"
#: builtin/branch.c
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Salinan cabang salah nama '%s' dibuat"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "salinan cabang salah nama '%s' dibuat"
#: builtin/branch.c
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Cabang salah nama '%s' berganti nama"
+msgid "renamed a misnamed branch '%s' away"
+msgstr "cabang salah nama '%s' berganti nama"
#: builtin/branch.c
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "Cabang berganti nama ke %s, tapi HEAD tidak diperbarui!"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "cabang berganti nama ke %s, tapi HEAD tidak diperbarui"
#: builtin/branch.c
-msgid "Branch is renamed, but update of config-file failed"
-msgstr "Cabang berganti nama, tapi pembaruan berkas konfigurasi gagal"
+msgid "branch is renamed, but update of config-file failed"
+msgstr "cabang berganti nama, tapi pembaruan berkas konfigurasi gagal"
#: builtin/branch.c
-msgid "Branch is copied, but update of config-file failed"
-msgstr "Cabang disalin, tapi pembaruan berkas konfigurasi gagal"
+msgid "branch is copied, but update of config-file failed"
+msgstr "cabang disalin, tapi pembaruan berkas konfigurasi gagal"
#: builtin/branch.c
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Mohon sunting deskripsi untuk cabang\n"
" %s\n"
-"Baris yang diawali dengan '%c' akan dicopot.\n"
+"Baris yang diawali dengan '%s' akan dicopot.\n"
#: builtin/branch.c
msgid "Generic options"
@@ -3686,9 +3724,9 @@ msgstr "rekursi melalui submodul"
msgid "format to use for the output"
msgstr "format yang digunakan untuk keluaran"
-#: builtin/branch.c builtin/submodule--helper.c submodule.c
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Gagal menguraikan HEAD sebagai referensi valid."
+#: builtin/branch.c
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "gagal menguraikan HEAD sebagai referensi valid."
#: builtin/branch.c builtin/clone.c
msgid "HEAD not found below refs/heads!"
@@ -3711,20 +3749,20 @@ msgid "branch name required"
msgstr "nama cabang diperlukan"
#: builtin/branch.c
-msgid "Cannot give description to detached HEAD"
-msgstr "Tidak dapat memberikan deskripsi ke HEAD terpisah"
+msgid "cannot give description to detached HEAD"
+msgstr "tidak dapat memberikan deskripsi ke HEAD terpisah"
#: builtin/branch.c
msgid "cannot edit description of more than one branch"
msgstr "tidak dapat menyunting deskripsi lebih dari satu cabang"
#: builtin/branch.c
-msgid "cannot copy the current branch while not on any."
-msgstr "tidak dapat menyalin cabang saat ini ketika tidak ada."
+msgid "cannot copy the current branch while not on any"
+msgstr "tidak dapat menyalin cabang saat ini ketika tidak ada"
#: builtin/branch.c
-msgid "cannot rename the current branch while not on any."
-msgstr "tidak dapat mengganti nama cabang saat ini ketika tidak ada."
+msgid "cannot rename the current branch while not on any"
+msgstr "tidak dapat mengganti nama cabang saat ini ketika tidak ada"
#: builtin/branch.c
msgid "too many branches for a copy operation"
@@ -3741,10 +3779,9 @@ msgstr "terlalu banyak argumen untuk menyetel hulu baru"
#: builtin/branch.c
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
-"tidak dapat menyetel hulu HEAD ke %s ketika itu tak menunjuk pada cabang "
-"apapun."
+"tidak dapat menyetel hulu HEAD ke %s ketika tak menunjuk pada cabang apapun"
#: builtin/branch.c
#, c-format
@@ -3761,31 +3798,30 @@ msgid "too many arguments to unset upstream"
msgstr "terlalu banyak argumen untuk batal-setel hulu"
#: builtin/branch.c
-msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
msgstr ""
-"tidak dapat membatal-setel hulu HEAD ketika itu tak menunjuk pada cabang "
-"apapun."
+"tidak dapat membatal-setel hulu HEAD ketika tak menunjuk pada cabang apapun"
#: builtin/branch.c
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "Cabang '%s' tidak ada informasi hulu"
+msgid "branch '%s' has no upstream information"
+msgstr "cabang '%s' tidak ada informasi hulu"
#: builtin/branch.c
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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 ""
-"Opsi -a dan -r tidak mengambil nama cabang.\n"
-"Mungkin maksud Anda gunakan: -a|-r --list <pola>?"
+"opsi -a dan -r tidak mengambil nama cabang.\n"
+"Mungkin maksud Anda menggunakan: -a|-r --list <pola>?"
#: builtin/branch.c
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
"opsi '--set-upstream' tidak lagi didukung. Mohon gunakan '--track' atau '--"
-"set-upstream-to' sebagai gantinya."
+"set-upstream-to' sebagai gantinya"
#: builtin/bugreport.c
msgid "git version:\n"
@@ -3812,11 +3848,12 @@ msgstr ""
#: builtin/bugreport.c
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <berkas>] [(-s |-- suffix) "
-"<format>]\n"
+"git bugreport [(-o | --output-directory) <jalur>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
#: builtin/bugreport.c
@@ -3871,6 +3908,11 @@ msgstr "sebutkan tujuan untuk berkas(-berkas) laporan bug"
msgid "specify a strftime format suffix for the filename(s)"
msgstr "sebutkan akhiran format strftime untuk nama(-nama) berkas"
+#: builtin/bugreport.c
+#, c-format
+msgid "unknown argument `%s'"
+msgstr "argumen tidak dikenal `%s'"
+
#: builtin/bugreport.c builtin/diagnose.c
#, c-format
msgid "could not create leading directories for '%s'"
@@ -3951,6 +3993,10 @@ msgstr "Perlu sebuah repositori untuk membuat bundel."
msgid "do not show bundle details"
msgstr "jangan perlihatkan detail bundel"
+#: builtin/bundle.c bundle.c
+msgid "need a repository to verify a bundle"
+msgstr "perlu sebuah repositori untuk verifikasi bundel"
+
#: builtin/bundle.c
#, c-format
msgid "%s is okay\n"
@@ -4010,6 +4056,15 @@ msgstr "git cat-file (-t | -s) [--allow-unknown-type] <objek>"
#: builtin/cat-file.c
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<revisi>:<jalur|mirip-pohon> | --path=<jalur|mirip-pohon>] "
+"<revisi>"
+
+#: builtin/cat-file.c
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -4021,15 +4076,6 @@ msgstr ""
" [--textconv | --filters] [-z]"
#: builtin/cat-file.c
-msgid ""
-"git cat-file (--textconv | --filters)\n"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
-msgstr ""
-"git cat-file (--textconv | --filters)\n"
-" [<revisi>:<jalur|mirip-pohon> | --path=<jalur|mirip-pohon>] "
-"<revisi>"
-
-#: builtin/cat-file.c
msgid "Check object existence or emit object contents"
msgstr "Periksa keberadaan objek atau keluarkan isi objek"
@@ -4254,9 +4300,16 @@ msgid "also read contacts from stdin"
msgstr "juga baca kontak dari masukan standar"
#: builtin/check-mailmap.c
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "tidak dapat menguraikan kontak: %s"
+msgid "read additional mailmap entries from file"
+msgstr "baca entri mailmap tambahan dari berkas"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "blob"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "baca entri mailmap tambahan dari blob"
#: builtin/check-mailmap.c
msgid "no contacts specified"
@@ -4417,9 +4470,20 @@ msgstr "'%s' atau '%s' tidak dapat digunakan untuk %s"
#: builtin/checkout.c
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "'%s', '%s', atau '%s' tidak dapat digunakan ketika men-checkout pohon"
+
+#: builtin/checkout.c
+#, c-format
msgid "path '%s' is unmerged"
msgstr "jalur '%s' tak tergabung"
+#: builtin/checkout.c builtin/grep.c builtin/merge-tree.c builtin/reset.c
+#: merge-ort.c reset.c sequencer.c tree-walk.c
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "tidak dapat membaca pohon (%s)"
+
#: builtin/checkout.c
msgid "you need to resolve your current index first"
msgstr "Anda perlu selesaikan dulu indeks Anda saat ini"
@@ -4443,7 +4507,7 @@ msgstr "Tidak dapat melakukan reflog untuk '%s': %s\n"
msgid "HEAD is now at"
msgstr "HEAD sekarang berada di"
-#: builtin/checkout.c builtin/clone.c t/helper/test-fast-rebase.c
+#: builtin/checkout.c builtin/clone.c
msgid "unable to update HEAD"
msgstr "tidak dapat memperbarui HEAD"
@@ -4672,6 +4736,11 @@ msgstr "'%s' tidak dapat digunakan dengan mengganti cabang"
#: builtin/checkout.c
#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' butuh jalur untuk di-checkout"
+
+#: builtin/checkout.c
+#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s' tidak dapat digunakan dengan '%s'"
@@ -4690,6 +4759,11 @@ msgid "missing branch or commit argument"
msgstr "kehilangan argumen cabang atau komit"
#: builtin/checkout.c
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "gaya konflik '%s' tidak dikenal"
+
+#: builtin/checkout.c
msgid "perform a 3-way merge with the new branch"
msgstr "lakukan penggabungan 3 arah dengan cabang baru"
@@ -4714,8 +4788,8 @@ msgid "new-branch"
msgstr "cabang baru"
#: builtin/checkout.c
-msgid "new unparented branch"
-msgstr "cabang baru tanpa induk"
+msgid "new unborn branch"
+msgstr "cabang yatim baru"
#: builtin/checkout.c builtin/merge.c
msgid "update ignored files (default)"
@@ -4783,7 +4857,7 @@ msgstr ""
msgid "you must specify path(s) to restore"
msgstr "Anda harus sebutkan jalur untuk dipulihkan"
-#: builtin/checkout.c builtin/clone.c builtin/remote.c
+#: builtin/checkout.c builtin/clone.c builtin/remote.c builtin/replay.c
#: builtin/submodule--helper.c builtin/worktree.c
msgid "branch"
msgstr "cabang"
@@ -4993,9 +5067,9 @@ msgstr "pembersihan interaktif"
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/pack-refs.c builtin/show-ref.c
-#: ref-filter.h
+#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c
+#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c
+#: builtin/show-ref.c ref-filter.h
msgid "pattern"
msgstr "pola"
@@ -5012,24 +5086,8 @@ msgid "remove only ignored files"
msgstr "hanya hapus berkas terabaikan"
#: builtin/clean.c
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce disetel ke true dan baik -i, -n, atau -f tidak diberikan; "
-"menolak membersihkan"
-
-#: builtin/clean.c
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce asal ke true dan baik -i, -n, atau -f tidak diberikan; "
-"menolak membersihkan"
-
-#: builtin/clean.c
-msgid "-x and -X cannot be used together"
-msgstr "-x dan -X tidak dapat digunakan bersamaan"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
+msgstr "clean.requireForce 'true' dan -f tidak diberikan: menolak membersihkan"
#: builtin/clone.c
msgid "git clone [<options>] [--] <repo> [<dir>]"
@@ -5048,8 +5106,8 @@ msgid "create a bare repository"
msgstr "buat repositori bare"
#: builtin/clone.c
-msgid "create a mirror repository (implies bare)"
-msgstr "buat repositori cermin (implikasikan bare)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "buat repositori cermin (mengimplikasikan --bare)"
#: builtin/clone.c
msgid "to clone from a local repository"
@@ -5109,7 +5167,7 @@ msgstr "checkout <cabang> daripada HEAD remote"
msgid "path to git-upload-pack on the remote"
msgstr "jalur ke git-upload-pack pada remote"
-#: builtin/clone.c builtin/fetch.c builtin/grep.c builtin/pull.c
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
msgid "depth"
msgstr "kedalaman"
@@ -5122,6 +5180,7 @@ msgid "create a shallow clone since a specific time"
msgstr "buat klon dangkal sejak waktu yang disebutkan"
#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c
+#: builtin/replay.c
msgid "revision"
msgstr "revisi"
@@ -5149,6 +5208,10 @@ msgstr "direktori git"
msgid "separate git dir from working tree"
msgstr "pisahkan direktori git dari pohon kerja"
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
+msgid "specify the reference format to use"
+msgstr "sebutkan format referensi untuk digunakan"
+
#: builtin/clone.c
msgid "key=value"
msgstr "kunci=nilai"
@@ -5225,6 +5288,16 @@ msgstr "gagal menghapus tautan '%s'"
#: builtin/clone.c
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "tautan keras tidak dapat diperiksa pada '%s'"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "tautan keras berbeda dari sumber pada '%s'"
+
+#: builtin/clone.c
+#, c-format
msgid "failed to create link '%s'"
msgstr "gagal membuat tautan '%s'"
@@ -5233,7 +5306,7 @@ msgstr "gagal membuat tautan '%s'"
msgid "failed to copy file to '%s'"
msgstr "gagal menyalin berkas ke '%s'"
-#: builtin/clone.c
+#: builtin/clone.c refs/files-backend.c
#, c-format
msgid "failed to iterate over '%s'"
msgstr "gagal iterasi pada '%s'"
@@ -5276,10 +5349,6 @@ msgid "remote HEAD refers to nonexistent ref, unable to checkout"
msgstr "HEAD remote merujuk pada ref yang tidak ada, tidak dapat men-checkout"
#: builtin/clone.c
-msgid "unable to checkout working tree"
-msgstr "tidak dapat men-checkout pohon kerja"
-
-#: builtin/clone.c
msgid "unable to write parameters to config file"
msgstr "tidak dapat menulis parameter ke berkas konfigurasi"
@@ -5299,13 +5368,11 @@ msgstr "Terlalu banyak argumen."
msgid "You must specify a repository to clone."
msgstr "Anda harus sebutkan repositori untuk diklon."
-#: builtin/clone.c
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr ""
-"--bundle-uri tidak kompatibel dengan --depth, --shallow-since, dan --shallow-"
-"exclude"
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "format penyimpanan referensi tidak dikenal '%s'"
#: builtin/clone.c
#, c-format
@@ -5454,6 +5521,11 @@ msgid "padding space between columns"
msgstr "bantalan spasi di antara kolom"
#: builtin/column.c
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s harus non-negatif"
+
+#: builtin/column.c
msgid "--command must be the first argument"
msgstr "--command harus menjadi argumen pertama"
@@ -5471,13 +5543,13 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <direktori>] [--append]\n"
" [--split[=<strategi>]] [--reachable | --stdin-packs | "
"--stdin-commits]\n"
-" [--changed-paths] [--[no-]max-new-filters <n>] [--[-"
-"no-]progress]\n"
+" [--changed-paths] [--[no-]max-new-filters <n>] [--"
+"[no-]progress]\n"
" <opsi pemisahan>"
#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
@@ -5499,6 +5571,11 @@ msgstr "Tidak dapat membuka grafik komit '%s'"
#: builtin/commit-graph.c
#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "tidak dapat membuka grafik komit '%s'"
+
+#: builtin/commit-graph.c
+#, c-format
msgid "unrecognized --split argument, %s"
msgstr "argumen --split tidak dikenal, %s"
@@ -5637,7 +5714,7 @@ msgstr "git commit-tree: gagal membaca"
msgid ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -5647,7 +5724,7 @@ msgid ""
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <komit> | --fixup [(amend|"
-"reword):]<komit>)]\n"
+"reword):]<komit>]\n"
" [-F <berkas> | -m <pesan>] [--reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--"
"author=<pengarang>]\n"
@@ -5743,10 +5820,6 @@ msgid "Failed to update main cache tree"
msgstr "gagal memperbarui tembolok pohon utama"
#: builtin/commit.c
-msgid "unable to write new_index file"
-msgstr "tidak dapat menulis berkas new_index"
-
-#: builtin/commit.c
msgid "cannot do a partial commit during a merge."
msgstr "tidak dapat melakukan komit sebagian selama penggabungan."
@@ -5793,7 +5866,7 @@ msgstr ""
"tidak dapat memilih karakter komentar yang tidak terpakai\n"
"dalam pesan komit saat ini"
-#: builtin/commit.c builtin/merge-tree.c
+#: builtin/commit.c
#, c-format
msgid "could not lookup commit '%s'"
msgstr "tidak dapat mencari komit '%s'"
@@ -5838,38 +5911,38 @@ msgstr "tidak dapat menulis templat komit"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Mohon masukkan pesan komit untuk perubahan Anda. Baris yang diawali\n"
-"dengan '%c' akan diabaikan.\n"
+"dengan '%s' akan diabaikan.\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Mohon masukkan pesan komit untuk perubahan Anda. Baris yang diawali\n"
-"dengan '%c' akan diabaikan, dan pesan kosong batalkan komit.\n"
+"dengan '%s' akan diabaikan, dan pesan kosong batalkan komit.\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Mohon masukkan pesan komit untuk perubahan Anda. Baris yang diawali\n"
-"dengan '%c' akan tetap; Anda dapat menghapusnya jika Anda mau.\n"
+"dengan '%s' akan tetap; Anda dapat menghapusnya jika Anda mau.\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Mohon masukkan pesan komit untuk perubahan Anda. Baris yang diawali\n"
-"dengan '%c' akan tetap; Anda dapat menghapusnya jika Anda mau.\n"
+"dengan '%s' akan tetap; Anda dapat menghapusnya jika Anda mau.\n"
"Pesan kosong batalkan komit.\n"
#: builtin/commit.c
@@ -5919,7 +5992,7 @@ msgstr "%sPengkomit: %.*s <%.*s>"
msgid "Cannot read index"
msgstr "Tidak dapat membaca indeks"
-#: builtin/commit.c
+#: builtin/commit.c builtin/tag.c
msgid "unable to pass trailers to --trailers"
msgstr "tidak dapat melewatkan trailer ke --trailers"
@@ -6101,7 +6174,7 @@ msgstr "tangal"
msgid "override date for commit"
msgstr "timpa tanggal komit"
-#: builtin/commit.c builtin/merge-tree.c parse-options.h ref-filter.h
+#: builtin/commit.c parse-options.h ref-filter.h
msgid "commit"
msgstr "komit"
@@ -6135,11 +6208,11 @@ msgstr "gunakan pesan terformat autosquash untuk lumat komit tersebut"
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr "komit sekarang dikarang olehku (gunakan dengan -C/-c/--amend)"
-#: builtin/commit.c builtin/interpret-trailers.c
+#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c
msgid "trailer"
msgstr "trailer"
-#: builtin/commit.c
+#: builtin/commit.c builtin/tag.c
msgid "add custom trailer(s)"
msgstr "tambahkan trailer kustom"
@@ -6244,25 +6317,74 @@ msgstr "Batalkan komit karena badan pesan komit kosong.\n"
#: builtin/commit.c
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
"repositori sudah diperbarui, tetapi tidak dapat menulis\n"
-"berkas new_index. Periksa bahwa disk tidak penuh dan kuota\n"
+"berkas indeks baru. Periksa bahwa disk tidak penuh dan kuota\n"
"tidak terlampaui, lalu \"git restore --staged :/\" untuk pulihkan."
#: builtin/config.c
-msgid "git config [<options>]"
-msgstr "git config [<opsi>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<opsi berkas>] [<opsi tampilan>] [--includes]"
#: builtin/config.c
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "argumen --type tidak dikenal %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<opsi berkas>] [<opsi tampilan>] [--includes] [--all] [--"
+"regexp] [--value=<nilai>] [--fixed-value] [--default=<default>] <nama>"
#: builtin/config.c
-msgid "only one type at a time"
-msgstr "hanya satu tipe pada suatu saat"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<opsi berkas>] [--type=<tipe>] [--all] [--value=<nilai>] [--"
+"fixed-value] <nama> <nilai>"
+
+#: builtin/config.c
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<opsi berkas] [--all] [--value=<nilai>] [--fixed-value] "
+"<nama> <nilai>"
+
+#: builtin/config.c
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<opsi berkas>] <nama lama> <nama baru>"
+
+#: builtin/config.c
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<opsi berkas>] <nama>"
+
+#: builtin/config.c
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<opsi berkas>]"
+
+#: builtin/config.c
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<opsi berkas>] --get-colorbool <nama> [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<opsi berkas>] [<opsi tampilan] [--includes] [--all] [--"
+"regexp=<regexp> [--value=<nilai>] [--fixed-value] [--default=<default>] "
+"<nama>"
+
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<opsi berkas>] [--type=<tipe>] [--comment=<pesan>] [--all] "
+"[--value=<nilai>] [--fixed-value] <nama> <nilai>"
#: builtin/config.c
msgid "Config file location"
@@ -6297,70 +6419,6 @@ msgid "read config from given blob object"
msgstr "baca konfigurasi dari objek blob yang diberikan"
#: builtin/config.c
-msgid "Action"
-msgstr "Tindakan"
-
-#: builtin/config.c
-msgid "get value: name [value-pattern]"
-msgstr "dapatkan nilai: name [pola nilai]"
-
-#: builtin/config.c
-msgid "get all values: key [value-pattern]"
-msgstr "dapatkan semua nilai: key [pola nilai]"
-
-#: builtin/config.c
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "dapatkan nilai dari regexp: name-regex [pola nilai]"
-
-#: builtin/config.c
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "dapatkan nilai spesifik untuk URL: section[.var] URL"
-
-#: builtin/config.c
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "ganti semua variabel yang cocok: name value [pola nilai]"
-
-#: builtin/config.c
-msgid "add a new variable: name value"
-msgstr "tambahkan variabel baru: name value"
-
-#: builtin/config.c
-msgid "remove a variable: name [value-pattern]"
-msgstr "hapus variabel: name [pola nilai]"
-
-#: builtin/config.c
-msgid "remove all matches: name [value-pattern]"
-msgstr "hapus semua cocokan: name [pola nilai]"
-
-#: builtin/config.c
-msgid "rename section: old-name new-name"
-msgstr "ganti nama bagian: old-name new-name"
-
-#: builtin/config.c
-msgid "remove a section: name"
-msgstr "hapus bagian: name"
-
-#: builtin/config.c
-msgid "list all"
-msgstr "daftar semua"
-
-#: builtin/config.c
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr "gunakan kesamaan untai ketika membandingkan nilai ke 'pola nilai'"
-
-#: builtin/config.c
-msgid "open an editor"
-msgstr "buka penyunting"
-
-#: builtin/config.c
-msgid "find the color configured: slot [default]"
-msgstr "temukan warna terkonfigurasi: slot [asali]"
-
-#: builtin/config.c
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "temukan setelan warna: slot [stdout-is-tty]"
-
-#: builtin/config.c
msgid "Type"
msgstr "Tipe"
@@ -6397,8 +6455,8 @@ msgid "value is an expiry date"
msgstr "nilai adalah tanggal kadaluarsa"
#: builtin/config.c
-msgid "Other"
-msgstr "Lainnya"
+msgid "Display options"
+msgstr "Tampilkan opsi"
#: builtin/config.c
msgid "terminate values with NUL byte"
@@ -6409,10 +6467,6 @@ msgid "show variable names only"
msgstr "perlihatkan hanya nama variabel"
#: builtin/config.c
-msgid "respect include directives on lookup"
-msgstr "segani arahan masukkan pada pencarian"
-
-#: builtin/config.c
msgid "show origin of config (file, standard input, blob, command line)"
msgstr ""
"perlihatkan asal konfigurasi (berkas, masukan standar, blob, baris perintah)"
@@ -6424,12 +6478,17 @@ msgstr ""
"perintah)"
#: builtin/config.c
-msgid "value"
-msgstr "nilai"
+msgid "show config keys in addition to their values"
+msgstr "perlihatkan kunci opsi beserta nilainya"
#: builtin/config.c
-msgid "with --get, use default value when missing entry"
-msgstr "dengan --get, gunakan nilai asali ketika kehilangan entri"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "argumen --type tidak dikenal %s"
+
+#: builtin/config.c
+msgid "only one type at a time"
+msgstr "hanya satu tipe pada suatu saat"
#: builtin/config.c
#, c-format
@@ -6523,54 +6582,94 @@ msgstr ""
"\"CONFIGURATION FILE\" di \"git help worktree\" untuk selengkapnya"
#: builtin/config.c
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color dan tipe variabel raban"
+msgid "Other"
+msgstr "Lainnya"
#: builtin/config.c
-msgid "only one action at a time"
-msgstr "hanya satu tindakan pada suatu saat"
+msgid "respect include directives on lookup"
+msgstr "segani arahan masukkan pada pencarian"
#: builtin/config.c
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only hanya dapat diterapkan pada --list atau --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "tidak dapat membaca berkas konfigurasi '%s'"
#: builtin/config.c
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr ""
-"--show-origin hanya dapat diterapkan pada --get, --get-all, --get-regexp, "
-"dan --list"
+msgid "error processing config file(s)"
+msgstr "kesalahan memproses berkas konfigurasi"
#: builtin/config.c
-msgid "--default is only applicable to --get"
-msgstr "--default hanya dapat diterapkan pada --get"
+msgid "Filter options"
+msgstr "Opsi penyaringan"
+
+#: builtin/config.c
+msgid "return all values for multi-valued config options"
+msgstr "dapatkan semua nilai untuk opsi konfigurasi multi-nilai"
+
+#: builtin/config.c
+msgid "interpret the name as a regular expression"
+msgstr "tafsirkan nama sebagai ekspresi reguler"
+
+#: builtin/config.c
+msgid "show config with values matching the pattern"
+msgstr "perlihatkan konfigurasi dengan nilai yang cocok dengan pola"
+
+#: builtin/config.c
+msgid "use string equality when comparing values to value pattern"
+msgstr "gunakan kesamaan untai ketika membandingkan nilai dan pola nilai"
+
+#: builtin/config.c
+msgid "URL"
+msgstr "URL"
+
+#: builtin/config.c
+msgid "show config matching the given URL"
+msgstr "perlihatkan konfigurasi yang cocok dengan URL yang diberikan"
+
+#: builtin/config.c
+msgid "value"
+msgstr "nilai"
+
+#: builtin/config.c
+msgid "use default value when missing entry"
+msgstr "gunakan nilai asali ketika entri hilang"
#: builtin/config.c
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value hanya diterapkan dengan 'pola nilai'"
#: builtin/config.c
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "tidak dapat membaca berkas konfigurasi '%s'"
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= tidak dapat digunakan dengan --all atau --url="
#: builtin/config.c
-msgid "error processing config file(s)"
-msgstr "kesalahan memproses berkas konfigurasi"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= tidak dapat digunakan dengan --all, --regexp atau --value"
#: builtin/config.c
-msgid "editing stdin is not supported"
-msgstr "menyunting stdin tidak didukung"
+msgid "Filter"
+msgstr "Penyaring"
#: builtin/config.c
-msgid "editing blobs is not supported"
-msgstr "menyunting blob tidak didukung"
+msgid "replace multi-valued config option with new value"
+msgstr "ganti opsi konfigurasi multi-nilai dengan nilai baru"
#: builtin/config.c
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "tidak dapat membuat berkas konfigurasi %s"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr ""
+"untai komentar yang dapat dibaca manusia (# akan ditambahkan bila diperlukan"
+
+#: builtin/config.c
+msgid "add a new line without altering any existing values"
+msgstr "tambahkan baris baru tanpa mengubah nilai yang ada"
+
+#: builtin/config.c
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value hanya diterapkan dengan --value=<pola>"
+
+#: builtin/config.c
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append tidak dapat digunakan dengan --value=<pola>"
#: builtin/config.c
#, c-format
@@ -6586,6 +6685,113 @@ msgstr ""
msgid "no such section: %s"
msgstr "tidak ada bagian seperti: %s"
+#: builtin/config.c
+msgid "editing stdin is not supported"
+msgstr "menyunting stdin tidak didukung"
+
+#: builtin/config.c
+msgid "editing blobs is not supported"
+msgstr "menyunting blob tidak didukung"
+
+#: builtin/config.c
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "tidak dapat membuat berkas konfigurasi %s"
+
+#: builtin/config.c
+msgid "Action"
+msgstr "Tindakan"
+
+#: builtin/config.c
+msgid "get value: name [<value-pattern>]"
+msgstr "dapatkan nilai: name [<pola nilai>]"
+
+#: builtin/config.c
+msgid "get all values: key [<value-pattern>]"
+msgstr "dapatkan semua nilai: key [<pola nilai>]"
+
+#: builtin/config.c
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "dapatkan nilai dari ekspresi reguler: name-regex [<pola nilai>]"
+
+#: builtin/config.c
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "dapatkan nilai spesifik untuk URL: section[.var] URL"
+
+#: builtin/config.c
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "ganti semua variabel yang cocok: name value [<pola nilai>]"
+
+#: builtin/config.c
+msgid "add a new variable: name value"
+msgstr "tambahkan variabel baru: name value"
+
+#: builtin/config.c
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "hapus variabel: name [<pola nilai>]"
+
+#: builtin/config.c
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "hapus semua cocokan: name [<pola nilai>]"
+
+#: builtin/config.c
+msgid "rename section: old-name new-name"
+msgstr "ganti nama bagian: old-name new-name"
+
+#: builtin/config.c
+msgid "remove a section: name"
+msgstr "hapus bagian: name"
+
+#: builtin/config.c
+msgid "list all"
+msgstr "daftar semua"
+
+#: builtin/config.c
+msgid "open an editor"
+msgstr "buka penyunting"
+
+#: builtin/config.c
+msgid "find the color configured: slot [<default>]"
+msgstr "temukan warna terkonfigurasi: slot [<asali>]"
+
+#: builtin/config.c
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "temukan setelan warna: slot [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid "with --get, use default value when missing entry"
+msgstr "dengan --get, gunakan nilai asali ketika kehilangan entri"
+
+#: builtin/config.c
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color dan tipe variabel raban"
+
+#: builtin/config.c
+msgid "no action specified"
+msgstr "tidak ada tindakan yang dipilih"
+
+#: builtin/config.c
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only hanya dapat diterapkan pada --list atau --get-regexp"
+
+#: builtin/config.c
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin hanya dapat diterapkan pada --get, --get-all, --get-regexp, "
+"dan --list"
+
+#: builtin/config.c
+msgid "--default is only applicable to --get"
+msgstr "--default hanya dapat diterapkan pada --get"
+
+#: builtin/config.c
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr ""
+"--comment hanya dapat diterapkan pada operasi penambahan/penyetelan/"
+"penggantian"
+
#: builtin/count-objects.c
msgid "print sizes in human readable format"
msgstr "cetak ukuran dalam format yang bisa dibaca manusia"
@@ -7201,8 +7407,8 @@ msgstr ""
#: builtin/fetch.c
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s tidak mengirim semua objek yang diperlukan\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s tidak mengirim semua objek yang diperlukan"
#: builtin/fetch.c
#, c-format
@@ -7248,8 +7454,8 @@ msgstr "opsi \"%s\" nilai \"%s\" tidak valid untuk %s"
#: builtin/fetch.c
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "opsi \"%s\" diabaikan untuk %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "opsi \"%s\" diabaikan untuk %s"
#: builtin/fetch.c object-file.c
#, c-format
@@ -7614,6 +7820,10 @@ msgid "read reference patterns from stdin"
msgstr "baca pola referensi dari masukan standar"
#: builtin/for-each-ref.c
+msgid "also include HEAD ref and pseudorefs"
+msgstr "juga termasuk referensi HEAD dan referensi semu"
+
+#: builtin/for-each-ref.c
msgid "unknown arguments supplied with --stdin"
msgstr "argumen tidak dikenal diberikan dengan --stdin"
@@ -7630,6 +7840,10 @@ msgid "config key storing a list of repository paths"
msgstr "kunci konfigurasi yang menampung daftar jalur repositori"
#: builtin/for-each-repo.c
+msgid "keep going even if command fails in a repository"
+msgstr "tetap lanjut meski perintah gagal pada repositori"
+
+#: builtin/for-each-repo.c
msgid "missing --config=<config>"
msgstr "kehilangan --config=<config>"
@@ -8085,6 +8299,10 @@ msgstr "pangkas objek tak tereferensi"
msgid "pack unreferenced objects separately"
msgstr "pak objek tak terujuk secara terpisah"
+#: builtin/gc.c builtin/repack.c
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "batasi ukuran pak sisa dengan --cruft"
+
#: builtin/gc.c
msgid "be more thorough (increased runtime)"
msgstr "jadi lebih cermat (waktu yang dijalankan bertambah)"
@@ -8094,6 +8312,10 @@ msgid "enable auto-gc mode"
msgstr "aktifkan mode gc otomatis"
#: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "lakukan pengumpulan sampah di latar belakang"
+
+#: builtin/gc.c
msgid "force running gc even if there may be another gc running"
msgstr "paksa jalankan gc bahkan jika mungkin ada gc lain yang berjalan"
@@ -8214,6 +8436,10 @@ msgid "run tasks based on the state of the repository"
msgstr "jalankan tugas berdasarkan keadaan repositori"
#: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "lakukan pemeliharaan di latar belakang"
+
+#: builtin/gc.c
msgid "frequency"
msgstr "frekuensi"
@@ -8306,14 +8532,6 @@ msgstr ""
msgid "'crontab' died"
msgstr "'crontab' mati"
-#: builtin/gc.c
-msgid "failed to start systemctl"
-msgstr "gagal memulai systemctl"
-
-#: builtin/gc.c
-msgid "failed to run systemctl"
-msgstr "gagal menjalankan systemctl"
-
#: builtin/gc.c builtin/worktree.c
#, c-format
msgid "failed to delete '%s'"
@@ -8325,6 +8543,14 @@ msgid "failed to flush '%s'"
msgstr "gagal membilas '%s'"
#: builtin/gc.c
+msgid "failed to start systemctl"
+msgstr "gagal memulai systemctl"
+
+#: builtin/gc.c
+msgid "failed to run systemctl"
+msgstr "gagal menjalankan systemctl"
+
+#: builtin/gc.c
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "argumen --scheduler tidak dikenal '%s'"
@@ -8355,6 +8581,10 @@ msgid "scheduler to trigger git maintenance run"
msgstr "penjadwal untuk memicu git maintenance run"
#: builtin/gc.c
+msgid "failed to set up maintenance schedule"
+msgstr "gagal mempersiapkan jadwal pemeliharaan"
+
+#: builtin/gc.c
msgid "failed to add repo to global config"
msgstr "gagal menambahkan repositori ke konfigurasi global"
@@ -8388,8 +8618,8 @@ msgstr "tidak ada dukungan utas, abaikan %s"
#: builtin/grep.c
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "tidak dapat membaca pohon (%s)"
+msgid "unable to read tree %s"
+msgstr "tidak dapat membaca pohon %s"
#: builtin/grep.c
#, c-format
@@ -8450,7 +8680,7 @@ msgid "search in subdirectories (default)"
msgstr "cari dalam subdirektori (asali)"
#: builtin/grep.c
-msgid "descend at most <depth> levels"
+msgid "descend at most <n> levels"
msgstr "turun paling banyak <kedalaman> tingkat"
#: builtin/grep.c
@@ -8920,11 +9150,6 @@ msgstr "inkonsistensi inflate serius"
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "TUMBUKAN SHA1 DITEMUKAN DENGAN %s !"
-#: builtin/index-pack.c builtin/pack-objects.c
-#, c-format
-msgid "unable to read %s"
-msgstr "tidak dapat membaca %s"
-
#: builtin/index-pack.c
#, c-format
msgid "cannot read existing object info %s"
@@ -9102,11 +9327,13 @@ msgstr "kesalahan fsck dalam objek paket"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
"git init [-q | --quiet] [--bare] [--template=<direktori templat>]\n"
" [--separate-git-dir <direktori git>] [--object-format=<format>]\n"
+"\t [--ref-format=<format>]\n"
" [-b <nama cabang> | --initial-branch=<nama cabang>]\n"
" [--shared[=<perizinan>]] [<direktori>]"
@@ -9162,13 +9389,47 @@ msgstr "--separate-git-dir tidak kompatibel dengan repositori bare"
#: builtin/interpret-trailers.c
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<nilai>])...]\n"
+" [(--trailer (<kunci>|<alias kunci>)"
+"[(=|:)<nilai>])...]\n"
" [--parse] [<berkas>...]"
+#: builtin/interpret-trailers.c wrapper.c
+#, c-format
+msgid "could not stat %s"
+msgstr "tidak dapat membaca %s"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "berkas %s bukan sebuah berkas reguler"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "berkas %s tidak dapat ditulis oleh pengguna"
+
+#: builtin/interpret-trailers.c
+msgid "could not open temporary file"
+msgstr "tidak dapat membuka berkas sementara"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "tidak dapat membaca berkas masukan '%s'"
+
+#: builtin/interpret-trailers.c builtin/mktag.c imap-send.c
+msgid "could not read from stdin"
+msgstr "tidak dapat membaca dari masukan standar"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "tidak dapat menamai ulang berkas sementara ke %s"
+
#: builtin/interpret-trailers.c
msgid "edit files in place"
msgstr "sunting berkas di tempat"
@@ -9178,6 +9439,10 @@ msgid "trim empty trailers"
msgstr "pangkas trailer kosong"
#: builtin/interpret-trailers.c
+msgid "placement"
+msgstr "penempatan"
+
+#: builtin/interpret-trailers.c
msgid "where to place the new trailer"
msgstr "dimana trailer baru ditempatkan"
@@ -9194,20 +9459,20 @@ msgid "output only the trailers"
msgstr "keluarkan hanya trailer"
#: builtin/interpret-trailers.c
-msgid "do not apply config rules"
-msgstr "jangan terapkan aturan konfigurasi"
+msgid "do not apply trailer.* configuration variables"
+msgstr "jangan terapkan variabel konfigurasi trailer.*"
#: builtin/interpret-trailers.c
-msgid "join whitespace-continued values"
-msgstr "gabungkan nilai yang dilanjutkan oleh spasi"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "format ulang nilai trailer multibaris sebagai nilai satu baris."
#: builtin/interpret-trailers.c
-msgid "set parsing options"
-msgstr "setel opsi penguraian"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "alias untuk --only-trailers --only-input --unfold"
#: builtin/interpret-trailers.c
-msgid "do not treat --- specially"
-msgstr "jangan memperlakukan khusus ---"
+msgid "do not treat \"---\" as the end of input"
+msgstr "jangan perlakukan \"---\" sebagai ujung masukan"
#: builtin/interpret-trailers.c
msgid "trailer(s) to add"
@@ -9266,7 +9531,7 @@ msgstr ""
"lacak evolusi rentang baris <awal>,<akhir> atau fungsi :<nama fungsi> dalam "
"<berkas>"
-#: builtin/log.c builtin/shortlog.c bundle.c
+#: builtin/log.c builtin/replay.c builtin/shortlog.c bundle.c
#, c-format
msgid "unrecognized argument: %s"
msgstr "argumen tidak dikenal: %s"
@@ -9281,10 +9546,6 @@ msgid "Final output: %d %s\n"
msgstr "Keluaran terakhir: %d %s\n"
#: builtin/log.c
-msgid "unable to create temporary object directory"
-msgstr "tidak dapat membuat direktori objek sementara"
-
-#: builtin/log.c
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: berkas jelek"
@@ -9322,6 +9583,11 @@ msgid "not a range"
msgstr "bukan sebuah rentang"
#: builtin/log.c
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "tidak dapat membaca berkas deskripsi cabang '%s'"
+
+#: builtin/log.c
msgid "cover letter needs email format"
msgstr "sampul surat butuh format email"
@@ -9438,8 +9704,12 @@ msgid "max length of output filename"
msgstr "panjang nama berkas keluaran maksimum"
#: builtin/log.c
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "gunakan [RFC PATCH] daripada [PATCH]"
+msgid "rfc"
+msgstr "rfc"
+
+#: builtin/log.c
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "tambahkan <rfc> (asali 'RFC') sebelum 'PATCH'"
#: builtin/log.c
msgid "cover-from-description-mode"
@@ -9450,6 +9720,10 @@ msgid "generate parts of a cover letter based on a branch's description"
msgstr "buat bagian dari sampul surat berdasarkan deskripsi cabang"
#: builtin/log.c
+msgid "use branch description from file"
+msgstr "gunakan deskripsi cabang dari berkas"
+
+#: builtin/log.c
msgid "use [<prefix>] instead of [PATCH]"
msgstr "gunakan [<prefix>] daripada [PATCH]"
@@ -9664,21 +9938,6 @@ 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 '('"
-msgstr "format ls-files jelek: elemen '%s' tidak dimulai dengan '('"
-
-#: builtin/ls-files.c
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "format ls-files jelek: elemen '%s' tidak diakhiri dengan ')'"
-
-#: builtin/ls-files.c
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "format ls-files jelek: %%%.*s"
-
-#: builtin/ls-files.c
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<opsi>] [<berkas>...]"
@@ -9771,7 +10030,7 @@ msgid "if any <file> is not in the index, treat this as an error"
msgstr ""
"jika <berkas> apapun tidak berada di indeks, perlakukan sebagai kesalahan"
-#: builtin/ls-files.c
+#: builtin/ls-files.c builtin/merge-tree.c
msgid "tree-ish"
msgstr "mirip-pohon"
@@ -9801,11 +10060,11 @@ msgstr ""
#: builtin/ls-remote.c
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<exec>]\n"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<kunci>]\n"
" [--symref] [<repositori> [<pola>...]]"
@@ -9826,8 +10085,12 @@ msgid "limit to tags"
msgstr "batasi ke tag"
#: builtin/ls-remote.c
-msgid "limit to heads"
-msgstr "batasi ke kepala"
+msgid "limit to branches"
+msgstr "batasi ke cabang"
+
+#: builtin/ls-remote.c builtin/show-ref.c
+msgid "deprecated synonym for --branches"
+msgstr "sinonim usang untuk --branches"
#: builtin/ls-remote.c
msgid "do not show peeled tags"
@@ -9851,21 +10114,6 @@ msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
msgstr "git ls-tree [<opsi>] <mirip-pohon> [<jalur>...]"
#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "format ls-tree jelek: elemen '%s' tidak dimulai dengan '('"
-
-#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "format ls-tree jelek: elemen '%s' tidak diakhiri dengan ')'"
-
-#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "format ls-tree jelek: %%%.*s"
-
-#: builtin/ls-tree.c
msgid "only show trees"
msgstr "hanya perlihatkan pohon"
@@ -10013,11 +10261,23 @@ msgstr ""
"git merge-file [<opsi>] [-L <nama 1> [-L <asli> [-L <nama 2>]]] <berkas 1> "
"<berkas asli> <berkas 2>"
+#: builtin/merge-file.c diff.c
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"opsi diff-algorithm terima \"myers\", \"minimal\", \"patience\" dan "
+"\"histogram\""
+
#: builtin/merge-file.c
msgid "send results to standard output"
msgstr "kirim hasil ke keluaran standar"
#: builtin/merge-file.c
+msgid "use object IDs instead of filenames"
+msgstr "gunakan ID objek daripada nama berkas"
+
+#: builtin/merge-file.c
msgid "use a diff3 based merge"
msgstr "gunakan penggabungan berdasarkan diff3"
@@ -10025,17 +10285,13 @@ msgstr "gunakan penggabungan berdasarkan diff3"
msgid "use a zealous diff3 based merge"
msgstr "gunakan penggabungan berdasarkan diff3 yang bersemangat"
-#: builtin/merge-file.c
-msgid "for conflicts, use our version"
-msgstr "untuk konflik, gunakan versi kami"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use their version"
-msgstr "untuk konflik, gunakan versi mereka"
+#: builtin/merge-file.c diff.c
+msgid "<algorithm>"
+msgstr "<algoritma>"
-#: builtin/merge-file.c
-msgid "for conflicts, use a union version"
-msgstr "untuk konflik, gunakan versi bersatu"
+#: builtin/merge-file.c diff.c
+msgid "choose a diff algorithm"
+msgstr "pilih algoritma diff"
#: builtin/merge-file.c
msgid "for conflicts, use this marker size"
@@ -10049,6 +10305,15 @@ msgstr "jangan peringatkan tentang konflik"
msgid "set labels for file1/orig-file/file2"
msgstr "setel label untuk file1/orig-file/file2"
+#: builtin/merge-file.c
+#, c-format
+msgid "object '%s' does not exist"
+msgstr "objek '%s' tidak ada"
+
+#: builtin/merge-file.c
+msgid "Could not write object file"
+msgstr "Tidak dapat menulis berkas objek"
+
#: builtin/merge-recursive.c
#, c-format
msgid "unknown option %s"
@@ -10080,6 +10345,11 @@ msgstr "tidak dapat menguraikan referensi '%s'"
msgid "Merging %s with %s\n"
msgstr "Menggabungkan %s dengan %s\n"
+#: builtin/merge-tree.c
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "tidak dapat mengurai '%s' sebagai pohon"
+
#: builtin/merge-tree.c builtin/merge.c
msgid "not something we can merge"
msgstr "bukan sesuatu yang kami bisa gabungkan"
@@ -10128,13 +10398,22 @@ msgstr "lakukan banyak penggabungan, satu per baris masukan"
msgid "specify a merge-base for the merge"
msgstr "harus menyebutkan sebuah dasar penggabungan untuk penggabungan"
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option=value"
+msgstr "opsi=nilai"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option for selected merge strategy"
+msgstr "opsi untuk strategi penggabungan yang dipilih"
+
#: builtin/merge-tree.c
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge tidak kompatibel dengan semua opsi lainnya"
-#: builtin/merge-tree.c
-msgid "--merge-base is incompatible with --stdin"
-msgstr "--merge-base tidak kompatibel dengan --stdin"
+#: builtin/merge-tree.c builtin/merge.c
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "opsi strategi tidak dikenal: -X%s"
#: builtin/merge-tree.c builtin/notes.c
#, c-format
@@ -10224,14 +10503,6 @@ msgstr "strategi"
msgid "merge strategy to use"
msgstr "strategi penggabungan yang digunakan"
-#: builtin/merge.c builtin/pull.c
-msgid "option=value"
-msgstr "opsi=nilai"
-
-#: builtin/merge.c builtin/pull.c
-msgid "option for selected merge strategy"
-msgstr "opsi untuk strategi penggabungan yang dipilih"
-
#: builtin/merge.c
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "pesan komit penggabungan (untuk penggabungan bukan maju cepat)"
@@ -10301,7 +10572,7 @@ msgstr "'%s' tidak menunjuk pada sebuah komit"
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Untai branch.%s.mergeoptions jelek: %s"
-#: builtin/merge.c builtin/stash.c merge-recursive.c
+#: builtin/merge.c merge-recursive.c
msgid "Unable to write index."
msgstr "Tidak dapat menulis indeks."
@@ -10309,12 +10580,7 @@ msgstr "Tidak dapat menulis indeks."
msgid "Not handling anything other than two heads merge."
msgstr "Tak tangani apapun selain penggabungan dua kepala."
-#: builtin/merge.c
-#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "opsi strategi tidak dikenal: -X%s"
-
-#: builtin/merge.c t/helper/test-fast-rebase.c
+#: builtin/merge.c builtin/sparse-checkout.c
#, c-format
msgid "unable to write %s"
msgstr "tidak dapat menulis %s"
@@ -10348,10 +10614,10 @@ msgstr "Pesan kosong membatalkan komit.\n"
#: builtin/merge.c
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Baris yang diawali dengan '%c' akan diabaikan, dan pesan kosong batalkan\n"
+"Baris yang diawali dengan '%s' akan diabaikan, dan pesan kosong batalkan\n"
"komit.\n"
#: builtin/merge.c
@@ -10549,10 +10815,6 @@ msgstr "tidak dapat membaca objek tertag '%s'"
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "objek '%s' ditag sebagai '%s', tetapi bertipe '%s'"
-#: builtin/mktag.c imap-send.c trailer.c
-msgid "could not read from stdin"
-msgstr "tidak dapat membaca dari masukan standar"
-
#: builtin/mktag.c
msgid "tag on stdin did not pass our strict fsck check"
msgstr "tag pada masukan standar tidak lolos pemeriksaan fsck ketat kami"
@@ -10618,6 +10880,10 @@ msgid "write multi-pack bitmap"
msgstr "tulis bitmap multipak"
#: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "tulis MIDX tambahan baru"
+
+#: builtin/multi-pack-index.c
msgid "write multi-pack index containing only given indexes"
msgstr "tulis indeks multipak yang hanya berisi indeks yang diberikan"
@@ -10682,8 +10948,8 @@ msgid "can not move directory into itself"
msgstr "tidak dapat memindahkan direktori ke dirinya sendiri"
#: builtin/mv.c
-msgid "cannot move directory over file"
-msgstr "tidak dapat memindahkan direktori ke berkas"
+msgid "destination already exists"
+msgstr "tujuan sudah ada"
#: builtin/mv.c
msgid "source directory is empty"
@@ -10890,11 +11156,6 @@ msgid "Write/edit the notes for the following object:"
msgstr "Tulis/sunting catatan untuk objek berikut:"
#: builtin/notes.c
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "tidak dapat memulai 'show' untuk objek '%s'"
-
-#: builtin/notes.c
msgid "could not read 'show' output"
msgstr "tidak dapat membaca keluaran 'show'"
@@ -11329,6 +11590,11 @@ msgstr "ketidakkonsistenan dengan hitungan delta"
#: builtin/pack-objects.c
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "nilai pack.allowPackReuse tidak valid: '%s'"
+
+#: builtin/pack-objects.c
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -11635,10 +11901,6 @@ msgstr ""
"--thin tidak dapat digunakan untuk membangun sebuah pak yang dapat diindeks"
#: builtin/pack-objects.c
-msgid "cannot use --filter without --stdout"
-msgstr "tidak dapat menggunakan --filter tanpa --stdout"
-
-#: builtin/pack-objects.c
msgid "cannot use --filter with --stdin-packs"
msgstr "tidak dapat menggunakan --filter dengan --stdin-packs"
@@ -11655,10 +11917,6 @@ msgid "cannot use --stdin-packs with --cruft"
msgstr "tidak dapat menggunakan --stdin-packs dengan --cruft"
#: builtin/pack-objects.c
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "tidak dapat menggunakan --max-pack-size dengan --cruft"
-
-#: builtin/pack-objects.c
msgid "Enumerating objects"
msgstr "Menghitung objek"
@@ -11666,10 +11924,10 @@ msgstr "Menghitung objek"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Total %<PRIu32> (delta %<PRIu32>), digunakan ulang %<PRIu32> (delta "
-"%<PRIu32>), pak yang digunakan ulang %<PRIu32>"
+"%<PRIu32>), pak yang digunakan ulang %<PRIu32> (dari %<PRIuMAX>)"
#: builtin/pack-redundant.c
msgid ""
@@ -11691,10 +11949,11 @@ msgstr "menolak menjalankan tanpa --i-still-use-this"
#: builtin/pack-refs.c
msgid ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <pola>] [--exclude <pola>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pola>][--exclude "
+"<pola>]"
#: builtin/pack-refs.c
msgid "pack everything"
@@ -11705,6 +11964,10 @@ msgid "prune loose refs (default)"
msgstr "pangkas referensi longgar (asali)"
#: builtin/pack-refs.c
+msgid "auto-pack refs as needed"
+msgstr "otomatis pak referensi jika dibutuhkan"
+
+#: builtin/pack-refs.c
msgid "references to include"
msgstr "referensi untuk ditambahkan"
@@ -12502,21 +12765,6 @@ msgid "could not remove '%s'"
msgstr "tidak dapat menghapus '%s'"
#: builtin/rebase.c
-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 ""
-"Selesaikan semua konflik secara manual, tandai sebagai terselesaikan\n"
-"dengan \"git add/rm <berkas terkonflik>\", lalu jalankan\n"
-"\"git rebase --continue\".\n"
-"Anda juga bisa melewatkan komit ini: jalankan \"git rebase --skip\".\n"
-"Untuk membatalkan dan kembali ke kondisi sebelum \"git rebase\",jalankan "
-"\"git rebase --abort\"."
-
-#: builtin/rebase.c
#, c-format
msgid ""
"\n"
@@ -12550,13 +12798,17 @@ msgid "apply options and merge options cannot be used together"
msgstr "opsi apply dan opsi merge tidak dapat digunakan bersamaan"
#: builtin/rebase.c
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask usang; gunakan '--empty=stop' sebagai gantinya."
+
+#: builtin/rebase.c
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
"tipe kosong tak dikenali '%s'; nilai yang valid adalah \"drop\", \"keep\", "
-"dan \"ask\"."
+"dan \"stop\"."
#: builtin/rebase.c
msgid ""
@@ -12698,7 +12950,7 @@ msgstr "biarkan pengguna menyunting daftar komit untuk didasarkan ulang"
msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
msgstr "(USANG) yaitu: coba buat ulang penggabungan daripada abaikannya"
-#: builtin/rebase.c
+#: builtin/rebase.c builtin/revert.c
msgid "how to handle commits that become empty"
msgstr "bagaimana cara menangani komit yang menjadi kosong"
@@ -12780,15 +13032,15 @@ msgstr ""
"yang tidak lagi didukung; gunakan 'merges' sebagai gantinya"
#: builtin/rebase.c
-msgid "No rebase in progress?"
-msgstr "Tidak ada pendasaran ulang yang sedang berjalan?"
+msgid "no rebase in progress"
+msgstr "tidak ada pendasaran ulang yang sedang berjalan"
#: builtin/rebase.c
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
"Aksi --edit-todo hanya dapat digunakan selama pendasaran ulang interaktif."
-#: builtin/rebase.c t/helper/test-fast-rebase.c
+#: builtin/rebase.c
msgid "Cannot read HEAD"
msgstr "Tidak dapat membaca HEAD"
@@ -12835,18 +13087,6 @@ msgid "switch `C' expects a numerical value"
msgstr "tombol `C' harap nilai numerik"
#: 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-"
-"autosquash"
-msgstr ""
-"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"
@@ -13022,6 +13262,10 @@ msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git remote [show] [<opsi log>] [<referensi>]"
#: builtin/reflog.c
+msgid "git reflog list"
+msgstr "git reflog list"
+
+#: builtin/reflog.c
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -13050,6 +13294,11 @@ msgstr "git reflog exists <referensi>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "stempel waktu tidak valid '%s' diberikan ke '--%s'"
+#: builtin/reflog.c sequencer.c
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s tidak menerima argumen: '%s'"
+
#: builtin/reflog.c
msgid "do not actually prune any entries"
msgstr "jangan benar-benar pangkas entri apapun"
@@ -13114,6 +13363,39 @@ msgstr "tidak ada log referensi yang disebutkan untuk dihapus"
msgid "invalid ref format: %s"
msgstr "format referensi tidak valid: %s"
+#: builtin/refs.c
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+
+#: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [---verbose]"
+
+#: builtin/refs.c
+msgid "specify the reference format to convert to"
+msgstr "sebutkan format referensi untuk dikonversi"
+
+#: builtin/refs.c
+msgid "perform a non-destructive dry-run"
+msgstr "lakukan uji coba non desktruktif"
+
+#: builtin/refs.c
+msgid "missing --ref-format=<format>"
+msgstr "--ref-format=<format> hilang"
+
+#: builtin/refs.c
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "repositori telah menggunakan format '%s'"
+
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "aktifkan pemeriksaan lebih ketat"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' tidak mengambil argumen"
+
#: builtin/remote.c
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
@@ -13212,8 +13494,8 @@ msgstr ""
#: builtin/remote.c
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "argumen mirror tidak dikenal: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "argumen --mirror tidak dikenal: %s"
#: builtin/remote.c
msgid "fetch the remote branches"
@@ -13344,10 +13626,10 @@ msgid_plural ""
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:"
msgstr[0] ""
-"Catatan: Sebuah cabang diluar hierarki refs/remotes tidak dihapus;\n"
+"Catatan: Sebuah cabang diluar hierarki refs/remotes/ tidak dihapus;\n"
"untuk menghapusnya, gunakan:"
msgstr[1] ""
-"Catatan: Beberapa cabang diluar hierarki refs/remotes tidak dihapus;\n"
+"Catatan: Beberapa cabang diluar hierarki refs/remotes/ tidak dihapus;\n"
"untuk menghapusnya, gunakan:"
#: builtin/remote.c
@@ -13467,10 +13749,6 @@ msgstr "* remote %s"
msgid " Fetch URL: %s"
msgstr " URL pengambilan: %s"
-#: builtin/remote.c
-msgid "(no URL)"
-msgstr "(tidak ada URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -13481,6 +13759,10 @@ msgid " Push URL: %s"
msgstr " URL pendorongan: %s"
#: builtin/remote.c
+msgid "(no URL)"
+msgstr "(tidak ada URL)"
+
+#: builtin/remote.c
#, c-format
msgid " HEAD branch: %s"
msgstr " Cabang HEAD: %s"
@@ -13615,11 +13897,6 @@ msgid "return all URLs"
msgstr "kembalikan semua URL"
#: builtin/remote.c
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "tidak ada URL yang dikonfigurasi untuk remote '%s'"
-
-#: builtin/remote.c
msgid "manipulate push URLs"
msgstr "manipulasi URL pendorongan"
@@ -13670,6 +13947,10 @@ msgid "could not start pack-objects to repack promisor objects"
msgstr "tidak dapat memulai pack-objects untuk mengepak ulang objek pejanji"
#: builtin/repack.c
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "gagal mengumpan objek penjanji ke pack-objects"
+
+#: builtin/repack.c
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr "repack: Mengharapkan baris ID objek hex penuh hanya dari pack-objects."
@@ -13708,6 +13989,11 @@ msgid "could not remove stale bitmap: %s"
msgstr "tidak dapt memindahkan bitmap basi: %s"
#: builtin/repack.c
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "nama berkas paket %s tidak diawali dengan %s"
+
+#: builtin/repack.c
msgid "pack everything in a single pack"
msgstr "pak semuanya dalam satu pak"
@@ -13810,17 +14096,21 @@ msgid "pack prefix to store a pack containing pruned objects"
msgstr "awalan pak untuk menyimpan pak berisi objek terpangkas"
#: builtin/repack.c
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "awalan pak untuk menyimpan pak berisi objek tersaring"
+
+#: builtin/repack.c
msgid "cannot delete packs in a precious-objects repo"
msgstr "tidak dapat menghapus pak dalam repositori objek berharga"
#: builtin/repack.c
-msgid "Nothing new to pack."
-msgstr "Tidak ada yang baru untuk dipak."
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "opsi '%s' tidak dapat digunakan bersamaan dengan '%s'"
#: builtin/repack.c
-#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "nama berkas paket %s tidak diawali dengan %s"
+msgid "Nothing new to pack."
+msgstr "Tidak ada yang baru untuk dipak."
#: builtin/repack.c
#, c-format
@@ -14075,6 +14365,94 @@ msgstr "--convert-graft-file tidak mengambil argumen"
msgid "only one pattern can be given with -l"
msgstr "hanya satu pola yang dapat diberikan dengan -l"
+#: builtin/replay.c
+msgid "need some commits to replay"
+msgstr "butuh beberapa komit untuk dimainkan ulang"
+
+#: builtin/replay.c
+msgid "--onto and --advance are incompatible"
+msgstr "--onto dan --advance tidak kompatibel"
+
+#: builtin/replay.c
+msgid "all positive revisions given must be references"
+msgstr "semua revisi positif yang diberikan haruslah referensi"
+
+#: builtin/replay.c
+msgid "argument to --advance must be a reference"
+msgstr "argumen pada --advance harus sebuah referensi"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"tidak dapat memajukan target dengan banyak sumber karena pengurutannya akan "
+"menjadi tidak jelas"
+
+#: builtin/replay.c
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"tidak dapat menentukan secara tidak langsung apakah ini operasi --advance "
+"atau --onto"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"tidak dapat memajukan target dengan banyak cabang sumber karena "
+"pengurutannya akan menjadi tidak jelas"
+
+#: builtin/replay.c
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "tidak dapat menentukan secara tidak langsung dasar untuk --onto"
+
+#: builtin/replay.c
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(EKSPERIMENTAL!) git replay ([--contained] --onto <dasar baru> | --advance "
+"<cabang>) <rentang revisi>..."
+
+#: builtin/replay.c
+msgid "make replay advance given branch"
+msgstr "buat pemainan ulang memajukan caban yang diberikan"
+
+#: builtin/replay.c
+msgid "replay onto given commit"
+msgstr "mainkan ulang pada komit yang diberikan"
+
+#: builtin/replay.c
+msgid "advance all branches contained in revision-range"
+msgstr "majukan semua cabang yang berada pada rentang komit"
+
+#: builtin/replay.c
+msgid "option --onto or --advance is mandatory"
+msgstr "opsi --onto atau --advance diwajibkan"
+
+#: builtin/replay.c
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"beberapa opsi jalan revisi akan ditimpa oleh karena bit '%s' di 'struct "
+"rev_info' akan dipaksakan"
+
+#: builtin/replay.c
+msgid "error preparing revisions"
+msgstr "kesalahan menyiapkan revisi"
+
+#: builtin/replay.c
+msgid "replaying down to root commit is not supported yet!"
+msgstr "memainkan ulang ke komit akar belum didukung!"
+
+#: builtin/replay.c
+msgid "replaying merge commits is not supported yet!"
+msgstr "memainkan ulang komit penggabungan belum didukung!"
+
#: builtin/rerere.c
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
@@ -14333,27 +14711,28 @@ msgid "--prefix requires an argument"
msgstr "--prefix butuh sebuah argumen"
#: builtin/rev-parse.c
+msgid "no object format specified"
+msgstr "tidak ada format objek yang disebutkan"
+
+#: builtin/rev-parse.c
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "format objek tidak didukung: '%s'"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "mode untuk --abbrev-ref tidak dikenal: %s"
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden tidak dapat digunakan bersamaan dengan --branches"
-
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden tidak dapat digunakan bersamaan dengan --tags"
-
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden tidak dapat digunakan dengan --remotes"
-
#: builtin/rev-parse.c setup.c
msgid "this operation must be run in a work tree"
msgstr "operasi ini harus dijalankan di dalam pohon kerja"
#: builtin/rev-parse.c
+msgid "Could not read the index"
+msgstr "Tidak dapat membaca indeks"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "mode untuk --show-object-format tidak dikenal: %s"
@@ -14445,8 +14824,8 @@ msgid "allow commits with empty messages"
msgstr "perbolehkan komit dengan pesan kosong"
#: builtin/revert.c
-msgid "keep redundant, empty commits"
-msgstr "simpan komit kosong mubazir"
+msgid "deprecated: use --empty=keep instead"
+msgstr "usang: gunakan --empty=keep sebagai gantinya"
#: builtin/revert.c
msgid "use the 'reference' format to refer to commits"
@@ -14785,11 +15164,21 @@ msgstr "algoritma hash tidak dikenal"
#: builtin/show-ref.c
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pola>...]"
+
+#: builtin/show-ref.c
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
" [--heads] [--] [<pola>...]"
@@ -14798,12 +15187,28 @@ msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<pola>]"
#: builtin/show-ref.c
-msgid "only show tags (can be combined with heads)"
-msgstr "hanya perlihatkan tag (bisa dikombinasikan dengan kepala)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <referensi>"
+
+#: builtin/show-ref.c
+msgid "reference does not exist"
+msgstr "referensi tidak ada"
+
+#: builtin/show-ref.c
+msgid "failed to look up reference"
+msgstr "gagal mencari referensi"
#: builtin/show-ref.c
-msgid "only show heads (can be combined with tags)"
-msgstr "hanya perlihatkan kepala (bisa dikombinasikan dengan tag)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "hanya perlihatkan tag (bisa dikombinasikan dengan --branches)"
+
+#: builtin/show-ref.c
+msgid "only show branches (can be combined with --tags)"
+msgstr "hanya perlihatkan cabang (bisa dikombinasikan dengan --tags)"
+
+#: builtin/show-ref.c
+msgid "check for reference existence without resolving"
+msgstr "periksa adanya referensi tanpa penguraian"
#: builtin/show-ref.c
msgid "stricter reference checking, requires exact ref path"
@@ -14866,6 +15271,11 @@ msgid "failed to create directory for sparse-checkout file"
msgstr "gagal membuat direktori untuk berkas sparse-checkout"
#: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "tidak dapat membuka (fdopen) %s"
+
+#: builtin/sparse-checkout.c
msgid "failed to initialize worktree config"
msgstr "gagal menginisialisasi konfigurasi pohon kerja"
@@ -14881,7 +15291,7 @@ msgstr "inisialisasi checkout tipis dalam mode kerucut"
msgid "toggle the use of a sparse index"
msgstr "gunakan indeks tipis"
-#: builtin/sparse-checkout.c commit-graph.c midx.c sequencer.c
+#: builtin/sparse-checkout.c commit-graph.c midx-write.c sequencer.c
#, c-format
msgid "unable to create leading directories of %s"
msgstr "tidak dapat membuat direktori utama dari %s"
@@ -15435,8 +15845,8 @@ msgstr "tidak dapat hash objek dari '%s'"
#: builtin/submodule--helper.c
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "mode tidak diharapkan %o\n"
+msgid "unexpected mode %o"
+msgstr "mode tidak diharapkan %o"
#: builtin/submodule--helper.c
msgid "use the commit stored in the index instead of the submodule HEAD"
@@ -15574,7 +15984,7 @@ msgstr "Nilai '%s' untuk submodule.alternateErrorStrategy tidak dikenal"
msgid "Value '%s' for submodule.alternateLocation is not recognized"
msgstr "Nilai '%s' untuk submodule.alternateLocation tidak dikenal"
-#: builtin/submodule--helper.c
+#: builtin/submodule--helper.c submodule.c
#, c-format
msgid "refusing to create/use '%s' in another submodule's git dir"
msgstr ""
@@ -15582,13 +15992,13 @@ msgstr ""
#: builtin/submodule--helper.c
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "gagal mengkloning '%s' ke dalam jalur submodul '%s'"
+msgid "directory not empty: '%s'"
+msgstr "direktori tidak kosong: '%s'"
#: builtin/submodule--helper.c
#, c-format
-msgid "directory not empty: '%s'"
-msgstr "direktori tidak kosong: '%s'"
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "gagal mengkloning '%s' ke dalam jalur submodul '%s'"
#: builtin/submodule--helper.c
#, c-format
@@ -15827,6 +16237,10 @@ msgstr ""
"shallow] [--reference <repositori>] [--recursive] [--[no-]single-branch] "
"[--] [<jalur>...]"
+#: builtin/submodule--helper.c submodule.c
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Gagal menguraikan HEAD sebagai referensi valid."
+
#: builtin/submodule--helper.c
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<opsi>] [<jalur>...]"
@@ -16035,9 +16449,11 @@ msgstr "alasan pembaruan"
#: builtin/tag.c
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <id kunci>] [-f] [-m <pesan> | -F <berkas>] [-e]\n"
+" [(--trailer <token>[(=|:)<nilai>])...]\n"
" <nama tag> [<komit> | <objek>]"
#: builtin/tag.c
@@ -16076,12 +16492,12 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Tulis pesan untuk tag:\n"
" %s\n"
-"Baris yang diawali dengan '%c' akan diabaikan.\n"
+"Baris yang diawali dengan '%s' akan diabaikan.\n"
#: builtin/tag.c
#, c-format
@@ -16089,13 +16505,13 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be kept; you may remove them yourself if you "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Tulis pesan untuk tag:\n"
" %s\n"
-"Baris yang diawali dengan '%c' akan disimpan; Anda dapat menghapusnya bila "
+"Baris yang diawali dengan '%s' akan disimpan; Anda dapat menghapusnya bila "
"Anda mau.\n"
#: builtin/tag.c
@@ -16206,6 +16622,10 @@ msgid "print only tags of the object"
msgstr "hanya cetak tag dari objek"
#: builtin/tag.c
+msgid "could not start 'git column'"
+msgstr "tidak dapat memulai 'git column'"
+
+#: builtin/tag.c
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "opsi '%s' hanya diperbolehkan dalam mode daftar"
@@ -16409,6 +16829,10 @@ msgid "write index in this format"
msgstr "tulis indeks dalam format ini"
#: builtin/update-index.c
+msgid "report on-disk index format version"
+msgstr "laporkan versi format indeks pada-disk"
+
+#: builtin/update-index.c
msgid "enable or disable split index"
msgstr "aktifkan atau nonaktifkan indeks terpisah"
@@ -16441,6 +16865,16 @@ msgid "clear fsmonitor valid bit"
msgstr "bersihkan bita fsmonitor valid"
#: builtin/update-index.c
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#: builtin/update-index.c
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version: sebelumnya %d, disetel ke %d"
+
+#: builtin/update-index.c
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -16503,13 +16937,12 @@ msgid "fsmonitor disabled"
msgstr "fsmonitor dinonaktifkan"
#: builtin/update-ref.c
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<opsi>] -d <nama referensi> [<nilai lama>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<opsi>] -d <nama referensi> [<oid lama>]"
#: builtin/update-ref.c
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr ""
-"git update-ref [<opsi>] <nama referensi> <nilai baru> [<nilai lama>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<options>] <nama referensi> <oid baru> [<oid lama>]"
#: builtin/update-ref.c
msgid "git update-ref [<options>] --stdin [-z]"
@@ -16634,7 +17067,7 @@ 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"
+"If you meant to create a worktree containing a new unborn branch\n"
"(branch with no commits) for this repository, you can do so\n"
"using the --orphan flag:\n"
"\n"
@@ -16648,7 +17081,7 @@ msgstr ""
#: builtin/worktree.c
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn branch\n"
"(branch with no commits) for this repository, you can do so\n"
"using the --orphan flag:\n"
"\n"
@@ -16728,6 +17161,11 @@ msgstr "menginisialisasi"
#: builtin/worktree.c
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "tidak dapat menemukan pohon kerja yang dibuat '%s'"
+
+#: builtin/worktree.c
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "Menyiapkan pohon kerja (cabang baru '%s')"
@@ -16766,17 +17204,11 @@ msgstr ""
#: 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"
+"present, stopping; use 'add -f' to override 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"
+"ada, berhenti; gunakan 'add -f' untuk menimpa atau mengambil remote\n"
+"terlebih dahulu"
#: builtin/worktree.c
msgid "checkout <branch> even if already checked out in other worktree"
@@ -16792,7 +17224,7 @@ msgid "create or reset a branch"
msgstr "buat atau setel ulang sebuah cabang"
#: builtin/worktree.c
-msgid "create unborn/orphaned branch"
+msgid "create unborn branch"
msgstr "buat cabang belum lahir/yatim"
#: builtin/worktree.c
@@ -16822,12 +17254,8 @@ 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>"
+msgid "option '%s' and commit-ish cannot be used together"
+msgstr "opsi '%s' dan mirip-komit tidak dapat digunakan bersamaan"
#: builtin/worktree.c
msgid "added with --lock"
@@ -17085,10 +17513,6 @@ msgid "Repository lacks these prerequisite commits:"
msgstr "Repositori kekurangan komit prasyarat berikut:"
#: bundle.c
-msgid "need a repository to verify a bundle"
-msgstr "perlu sebuah repositori untuk verifikasi bundel"
-
-#: bundle.c
msgid ""
"some prerequisite commits exist in the object store, but are not connected "
"to the repository's history"
@@ -17170,6 +17594,11 @@ msgstr "id bingkah pengakhiran muncul lebih awal dari yang diharapkan"
#: chunk-format.c
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "id bingkah %<PRIx32> tidak terata %d-bita"
+
+#: chunk-format.c
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "offset bingkah %<PRIx64> dan %<PRIx64> tidak tepat"
@@ -17239,9 +17668,8 @@ msgid "Move objects and refs by archive"
msgstr "Pindahkan objek dan referensi oleh arsip"
#: command-list.h
-msgid "Provide content or type and size information for repository objects"
-msgstr ""
-"Sediakan isi atau informasi tipe dan ukuran berkas untuk objek repositori"
+msgid "Provide contents or details of repository objects"
+msgstr "Sediakan isi atau detail objek repositori"
#: command-list.h
msgid "Display gitattributes information"
@@ -17614,6 +18042,10 @@ msgid "Manage reflog information"
msgstr "Kelola informasi log referensi"
#: command-list.h
+msgid "Low-level access to refs"
+msgstr "Akses tingat bawah ke referensi"
+
+#: command-list.h
msgid "Manage set of tracked repositories"
msgstr "Kelola set repositori terlacak"
@@ -17626,6 +18058,12 @@ msgid "Create, list, delete refs to replace objects"
msgstr "Buat, daftar, hapus referensi untuk mengganti objek"
#: command-list.h
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"EKSPERIMENTAL: Mainkan ulang komit pada dasar baru, dan juga bekerja pada "
+"repositori bare"
+
+#: command-list.h
msgid "Generates a summary of pending changes"
msgstr "Buat ringkasan perubahan tertunda"
@@ -17787,8 +18225,8 @@ msgid "Display version information about Git"
msgstr "Perlihatkan info versi Git"
#: command-list.h
-msgid "Show logs with difference each commit introduces"
-msgstr "Perlihatkan log dengan perbedaan yang dimasukkan setiap komit"
+msgid "Show logs with differences each commit introduces"
+msgstr "Perlihatkan log dengan perbedaan yang diperkenalkan pada setiap komit"
#: command-list.h
msgid "Manage multiple working trees"
@@ -17943,6 +18381,39 @@ msgid "commit-graph file is too small"
msgstr "berkas grafik komit terlalu kecil"
#: commit-graph.c
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "bingkah oid grafik komit kipas keluar salah ukuran"
+
+#: commit-graph.c
+msgid "commit-graph fanout values out of order"
+msgstr "nilai kipas keluar grafik komit tidak berurutan"
+
+#: commit-graph.c
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "bingkah OID pencarian grafik komit salah ukuran"
+
+#: commit-graph.c
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "bingkah data grafik komit salah ukuran"
+
+#: commit-graph.c
+msgid "commit-graph generations chunk is wrong size"
+msgstr "bingkah generasi grafik komit salah ukuran"
+
+#: commit-graph.c
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "bingkah indeks grafik komit jalur berubah terlalu kecil"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"mengabaikan bingkah jalur berubah yang terlalu kecil (%<PRIuMAX> < "
+"%<PRIuMAX>) di dalam berkas grafik komit"
+
+#: commit-graph.c
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "tanda tangan grafik komit %X tidak cocok dengan tanda tangan %X"
@@ -17963,10 +18434,36 @@ msgid "commit-graph file is too small to hold %u chunks"
msgstr "berkas grafik komit terlalu kecil untuk menyimpan %u bingkah"
#: commit-graph.c
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr ""
+"bingkah grafik komit OID kipas keluar yang diperlukan hilang atau rusak"
+
+#: commit-graph.c
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "bingkah grafik komit OID pencarian yang diperlukan hilang atau rusak"
+
+#: commit-graph.c
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr "bingkah grafik komit data komit yang diperlukan hilang atau rusak"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"menonaktifkan penyaring Bloom untuk lapisan grafik komit '%s' karena setelan "
+"yang tidak cocok"
+
+#: commit-graph.c
msgid "commit-graph has no base graphs chunk"
msgstr "grafik komit tidak punya bingkah grafik dasar"
#: commit-graph.c
+msgid "commit-graph base graphs chunk is too small"
+msgstr "bingkah grafik komit dasar terlalu kecil"
+
+#: commit-graph.c
msgid "commit-graph chain does not match"
msgstr "rantai grafik komit tidak cocok"
@@ -17976,6 +18473,10 @@ msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "jumlah komit pada grafik dasar terlalu tinggi: %<PRIuMAX>"
#: commit-graph.c
+msgid "commit-graph chain file too small"
+msgstr "berkas rantai grafik komit terlalu kecil"
+
+#: commit-graph.c
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr "rantai grafik komit tidak cocok: baris '%s' bukan sebuah hash"
@@ -17998,6 +18499,14 @@ msgid "commit-graph requires overflow generation data but has none"
msgstr "grafik komit memerlukan pembuatan data meluap tapi tidak punya"
#: commit-graph.c
+msgid "commit-graph overflow generation data is too small"
+msgstr "data generasi luapan grafik komit terlalu kecil"
+
+#: commit-graph.c
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "penunjuk tepi tambahan grafik komit di luar batas"
+
+#: commit-graph.c
msgid "Loading known commits in commit graph"
msgstr "Memuat komit yang dikenal di grafik komit"
@@ -18058,7 +18567,7 @@ msgstr "gagal menulis jumlah id grafik dasar yang benar"
msgid "unable to create temporary graph layer"
msgstr "tidak dapat membuat lapisan grafik dasar"
-#: commit-graph.c
+#: commit-graph.c midx-write.c
#, c-format
msgid "unable to adjust shared permissions for '%s'"
msgstr "tidak dapat menyesuaikan perizinan berbagi untuk '%s'"
@@ -18105,6 +18614,15 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr "mencoba menulis grafik komit, tapi 'core.commitGraph' dimatikan"
#: commit-graph.c
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"mencoba menulis grafik komit, tapi 'commitGraph.changedPathsVersion (%d) "
+"tidak didukung"
+
+#: commit-graph.c
msgid "too many commits to write graph"
msgstr "terlalu banyak komit untuk menulis grafik"
@@ -18154,22 +18672,6 @@ msgstr "daftar induk grafik komit untuk komit %s berakhir lebih awal"
#: commit-graph.c
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr ""
-"grafik komit punya angka pembuatan nol untuk komit %s, tapi bukan nol di "
-"tempat lain"
-
-#: commit-graph.c
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"grafik komit punya angka pembuatan bukan nol untuk komit %s, tapi nol di "
-"tempat lain"
-
-#: commit-graph.c
-#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr "pembuatan grafik komit untuk komit %s yaitu %<PRIuMAX> < %<PRIuMAX>"
@@ -18181,9 +18683,23 @@ msgstr ""
"%<PRIuMAX>"
#: commit-graph.c
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"grafik komit punya baik generasi nol dan bukan nol (seperti komit '%s' dan "
+"'%s')"
+
+#: commit-graph.c
msgid "Verifying commits in commit graph"
msgstr "Memverifikasi komit di dalam grafik komit"
+#: commit-reach.c sequencer.c
+#, c-format
+msgid "could not parse commit %s"
+msgstr "tidak dapat menguraikan komit %s"
+
#: commit.c
#, c-format
msgid "%s %s is not a commit!"
@@ -18211,6 +18727,12 @@ msgstr ""
#: commit.c
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"komit %s ada pada grafik komit tapi tidak ada di dalam basis data objek"
+
+#: commit.c
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr "Komit %s punya tandatangan GPG tak dipercaya, dituduh sebagai %s."
@@ -18711,8 +19233,14 @@ msgid "bad zlib compression level %d"
msgstr "level kompresi zlib jelek %d"
#: config.c
-msgid "core.commentChar should only be one ASCII character"
-msgstr "core.commentChar seharusnya hanya satu karakter ASCII"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s tidak dapat berisi baris baru"
+
+#: config.c
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s harus ada sedikitnya satu karakter"
#: config.c
#, c-format
@@ -18758,11 +19286,6 @@ msgid "unable to resolve config blob '%s'"
msgstr "tidak dapat menguraikan blob konfigurasi '%s'"
#: config.c
-#, c-format
-msgid "failed to parse %s"
-msgstr "gagal menguraikan %s"
-
-#: config.c
msgid "unable to parse command-line config"
msgstr "gagal menguraikan konfigurasi baris perintah"
@@ -18807,6 +19330,11 @@ msgstr "gagal menulis berkas konfigurasi baru %s"
#: config.c
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "komentar multi baris tidak diperbolehkan: '%s'"
+
+#: config.c
+#, c-format
msgid "could not lock config file %s"
msgstr "tidak dapat mengunci berkas konfigurasi %s"
@@ -19342,10 +19870,6 @@ msgid "--merge-base does not work with ranges"
msgstr "--merge-base tidak bekerja dengan rentang"
#: diff-lib.c
-msgid "--merge-base only works with commits"
-msgstr "--merge-base hanya bekerja dengan komit"
-
-#: diff-lib.c
msgid "unable to get HEAD"
msgstr "tidak dapat mendapatkan HEAD"
@@ -19418,6 +19942,11 @@ msgstr ""
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "Nilai tidak dikenal untuk variabel konfigurasi 'diff.submodule': '%s'"
+#: diff.c merge-recursive.c transport.c
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "nilai tidak dikenal untuk konfigurasi '%s': %s"
+
#: diff.c
#, c-format
msgid ""
@@ -19515,14 +20044,6 @@ msgid "invalid mode '%s' in --color-moved-ws"
msgstr "mode tidak valid '%s' dalam --color-moved-ws"
#: diff.c
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"opsi diff-algorithm terima \"myers\", \"minimal\", \"patience\" dan "
-"\"histogram\""
-
-#: diff.c
#, c-format
msgid "invalid argument to %s"
msgstr "argumen tidak valid ke %s"
@@ -19579,8 +20100,8 @@ msgid "output only the last line of --stat"
msgstr "keluarkan hanya baris terakhir --stat"
#: diff.c
-msgid "<param1,param2>..."
-msgstr "<parameter 1,parameter 2>..."
+msgid "<param1>,<param2>..."
+msgstr "<parameter 1>,<parameter 2>..."
#: diff.c
msgid ""
@@ -19593,8 +20114,8 @@ msgid "synonym for --dirstat=cumulative"
msgstr "sinonim untuk --dirstat=cumulative"
#: diff.c
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "sinonim untuk --dirstat=files,param1,param2..."
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "sinonim untuk --dirstat=files,<parameter 1>,<parameter 2>..."
#: diff.c
msgid "warn if changes introduce conflict markers or whitespace errors"
@@ -19827,14 +20348,6 @@ msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "buat diff menggunakan algoritma \"diff histogram\""
#: diff.c
-msgid "<algorithm>"
-msgstr "<algoritma>"
-
-#: diff.c
-msgid "choose a diff algorithm"
-msgstr "pilih algoritma diff"
-
-#: diff.c
msgid "<text>"
msgstr "<teks>"
@@ -20419,15 +20932,17 @@ msgstr ""
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
msgstr ""
"git [-v| --version] [-h | --help] [-C <jalur>] [-c <nama>=<nilai>]\n"
" [--exec-path[=<jalur>]] [--html-path] [--man-path] [--info-path]\n"
-" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects]\n"
+" [--no-lazy-fetch] [--no-optional-locks] [--no-advice] [--bare]\n"
" [--git-dir=<jalur>] [--work-tree=<jalur>] [--namespace=<nama>]\n"
" [--config-env=<nama>=<variabel lingkungan>]\n"
" <perintah> [<argumen>]"
@@ -20843,14 +21358,14 @@ msgstr ""
"ignoredHook false`."
#: http-fetch.c
+msgid "not a git repository"
+msgstr "bukan sebuah repositori git"
+
+#: http-fetch.c
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "argumen ke --packfile harus sebuah hash valid (dapat '%s')"
-#: http-fetch.c
-msgid "not a git repository"
-msgstr "bukan sebuah repositori git"
-
#: http.c
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
@@ -20865,6 +21380,10 @@ msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "Penyematan kunci publik tidak didukung oleh cURL < 7.39.0"
#: http.c
+msgid "Unknown value for http.proactiveauth"
+msgstr "nilai tidak dikenal untuk http.proactiveauth"
+
+#: http.c
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE tidak didukung dengan cURL < 7.44.0"
@@ -20886,6 +21405,14 @@ msgid "Could not set SSL backend to '%s': already set"
msgstr "Tidak dapat menyetel tulang punggung SSL ke '%s': sudah disetel"
#: http.c
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "menolak membaca kuki dari http.cookiefile '-'"
+
+#: http.c
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "mengabaikan http.savecookies karena http.cookiefile kosong"
+
+#: http.c
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -21050,6 +21577,20 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "Tidak dapat membuat '%s.lock': %s"
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "tidak dapat membuat direktori objek sementara"
+
+#: loose.c
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "tidak dapat menulis indeks objek longgar %s"
+
+#: loose.c
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "gagal menulis indeks objek longgar %s"
+
#: ls-refs.c
#, c-format
msgid "unexpected line: '%s'"
@@ -21063,6 +21604,11 @@ msgstr "bilasan diharapkan setelah argumen ls-refs"
msgid "quoted CRLF detected"
msgstr "CRLF terkutip terdeteksi"
+#: mem-pool.c strbuf.c wrapper.c
+#, c-format
+msgid "unable to format message: %s"
+msgstr "tidak dapat memformat pesan: %s"
+
#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (not checked out)"
@@ -21078,6 +21624,11 @@ msgstr "Gagal menggabungkan submodul %s (tidak ada dasar penggabungan)"
msgid "Failed to merge submodule %s (commits not present)"
msgstr "Gagal menggabungkan submodul %s (komit tidak ada)"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "kesalahan: gagal menggabungkan submodul %s (repositori rusak)"
+
#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
@@ -21112,14 +21663,15 @@ msgstr ""
"mungkin:\n"
"%s"
-#: merge-ort.c merge-recursive.c
-msgid "Failed to execute internal merge"
-msgstr "Gagal menjalankan penggabungan internal"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "kesalahan: gagal menjalankan penggabungan internal untuk %s"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "Unable to add %s to database"
-msgstr "Tidak dapat menambahkan %s ke basis data"
+msgid "error: unable to add %s to database"
+msgstr "kesalahan: tidak dapat menambahkan %s ke basis data"
#: merge-ort.c merge-recursive.c
#, c-format
@@ -21226,15 +21778,15 @@ msgstr ""
"KONFLIK (penamaan ulang/penghapusan): %s dinamai ulang ke %s di %s, tetapi "
"dihapus di %s."
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "cannot read object %s"
-msgstr "tidak dapat membaca objek %s"
+msgid "error: cannot read object %s"
+msgstr "kesalahan: tidak dapat membaca objek %s"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "object %s is not a blob"
-msgstr "objek %s bukanlah sebuah blob"
+msgid "error: object %s is not a blob"
+msgstr "kesalahan: objek %s bukanlah suatu blob"
#: merge-ort.c
#, c-format
@@ -21395,6 +21947,11 @@ msgstr "tidak tahu apa yang dilakukan dengan %06o %s '%s'"
#: merge-recursive.c
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "Gagal menggabungkan submodul %s (repositori rusak)"
+
+#: merge-recursive.c
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "Memaju-cepat submodul %s ke komit berikut:"
@@ -21441,6 +21998,15 @@ msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "Gagal menggabungkan submodul %s (banyak penggabungan ditemukan)"
#: merge-recursive.c
+msgid "failed to execute internal merge"
+msgstr "gagal menjalankan penggabungan internal"
+
+#: merge-recursive.c
+#, c-format
+msgid "unable to add %s to database"
+msgstr "tidak dapat menambahkan %s ke basis data"
+
+#: merge-recursive.c
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
@@ -21563,6 +22129,16 @@ msgstr ""
"%s. Penamaan ulang %s->%s di %s"
#: merge-recursive.c
+#, c-format
+msgid "cannot read object %s"
+msgstr "tidak dapat membaca objek %s"
+
+#: merge-recursive.c
+#, c-format
+msgid "object %s is not a blob"
+msgstr "objek %s bukanlah sebuah blob"
+
+#: merge-recursive.c
msgid "modify"
msgstr "ubah"
@@ -21638,147 +22214,254 @@ msgstr "Tidak dapat menguraikan objek '%s'"
msgid "failed to read the cache"
msgstr "gagal membaca tembolok"
-#: midx.c
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "OID kipas-keluar indeks multipak salah ukuran"
+#: midx-write.c
+#, c-format
+msgid "failed to add packfile '%s'"
+msgstr "gagal menambah berkas pak '%s'"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "berkas indeks multipak %s terlalu kecil"
+msgid "failed to open pack-index '%s'"
+msgstr "gagal membuka indeks pak '%s'"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr ""
-"tanda tangan indeks multipak 0x%08x tidak cocok dengan tanda tangan 0x%08x"
+msgid "failed to locate object %d in packfile"
+msgstr "gagal melokasi objek %d di dalam berkas pak"
-#: midx.c
+#: midx-write.c
+msgid "cannot store reverse index file"
+msgstr "tidak dapat menyimpan berkas indeks balik"
+
+#: midx-write.c
#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "versi indeks multipak %d tidak dikenal"
+msgid "could not parse line: %s"
+msgstr "tidak dapat menguraikan baris: %s"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "versi hash indeks multipak %u tidak cocok dengan versi %u"
+msgid "malformed line: %s"
+msgstr "baris jelek '%s'."
-#: midx.c
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "indeks multipak kehilangan bingkah pack-name yang diperlukan"
+#: midx-write.c
+msgid "could not load pack"
+msgstr "tidak dapat memuat pak"
-#: midx.c
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "indeks multipak kehilangan bingkah OID kipas keluar yang diperlukan"
+#: midx-write.c
+#, c-format
+msgid "could not open index for %s"
+msgstr "tidak dapat membuka indeks untuk %s"
-#: midx.c
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "indeks multipak kehilangan bingkah pencarian OID yang diperlukan"
+#: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "tidak dapat mentautkan '%s' ke '%s'"
-#: midx.c
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "indeks multipak kehilangan bingkah offset objek yang diperlukan"
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "gagal membersihkan indeks multipak pada %s"
-#: midx.c
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "tidak dapat menulis MIDX tambahan dengan bitmap"
+
+#: midx-write.c
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr "abaikan indeks multipak yang sudah ada; checksum tidak cocok"
+
+#: midx-write.c
+msgid "Adding packfiles to multi-pack-index"
+msgstr "Menambahkan berkas pak ke indeks multipak"
+
+#: midx-write.c
#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "nama pak indeks multipak tidak berurutan: '%s' sebelum '%s'"
+msgid "unknown preferred pack: '%s'"
+msgstr "pak yang disukai tidak dikenal: '%s'"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "pack-int-id jelek: %u (total pak %u)"
+msgid "cannot select preferred pack %s with no objects"
+msgstr "tidak dapat memilih pak yang disukai %s tanpa objek"
+
+#: midx-write.c
+#, c-format
+msgid "did not see pack-file %s to drop"
+msgstr "tidak melihat berkas pak %s untuk dijeblokkan"
+
+#: midx-write.c
+#, c-format
+msgid "preferred pack '%s' is expired"
+msgstr "pak yang disukai '%s' kadaluarsa"
+
+#: midx-write.c
+msgid "no pack files to index."
+msgstr "tidak ada berkas pak untuk diindeks."
+
+#: midx-write.c
+msgid "refusing to write multi-pack .bitmap without any objects"
+msgstr "menolak menulis .bitmap multipak tanpa objek apapun"
+
+#: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "tidak dapat membuat lapisan MIDX sementara"
+
+#: midx-write.c
+msgid "could not write multi-pack bitmap"
+msgstr "tidak dapat menulis bitmap multipak"
+
+#: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "tidak dapat membuka berkas rantai indeks multipak"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "tidak dapat menamai ulang lapisan indeks multipak baru"
+
+#: midx-write.c
+msgid "could not write multi-pack-index"
+msgstr "gagal menulis indeks multipak"
+
+#: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "tidak dapat mengkadaluarsakan pak dari indeks multipak tambahan"
+
+#: midx-write.c
+msgid "Counting referenced objects"
+msgstr "Menghitung objek tereferensi"
+
+#: midx-write.c
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Mencari dan menghapus berkas pak tak tereferensi"
+
+#: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "tidak dapat mempak ulang indeks multipak tambahan"
+
+#: midx-write.c
+msgid "could not start pack-objects"
+msgstr "tidak dapat memulai pack-objects"
+
+#: midx-write.c
+msgid "could not finish pack-objects"
+msgstr "tidak dapat menyelesaikan pack-objects"
#: midx.c
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr "indeks multipak simpan offset 64-bit, tapi off_t terlalu kecil"
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "OID kipas-keluar indeks multipak salah ukuran"
#: midx.c
#, c-format
-msgid "failed to add packfile '%s'"
-msgstr "gagal menambah berkas pak '%s'"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr ""
+"kipas-keluar oid tidak berurutan: fanout[%d] =%<PRIx32> > %<PRIx32> = "
+"fanout[%d]"
#: midx.c
-#, c-format
-msgid "failed to open pack-index '%s'"
-msgstr "gagal membuka indeks pak '%s'"
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "bingkah pencarian OID kipas-keluar indeks multipak salah ukuran"
+
+#: midx.c
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "bingkah offset OID kipas-keluar indeks multipak salah ukuran"
#: midx.c
#, c-format
-msgid "failed to locate object %d in packfile"
-msgstr "gagal melokasi objek %d di dalam berkas pak"
+msgid "multi-pack-index file %s is too small"
+msgstr "berkas indeks multipak %s terlalu kecil"
#: midx.c
-msgid "cannot store reverse index file"
-msgstr "tidak dapat menyimpan berkas indeks balik"
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr ""
+"tanda tangan indeks multipak 0x%08x tidak cocok dengan tanda tangan 0x%08x"
#: midx.c
#, c-format
-msgid "could not parse line: %s"
-msgstr "tidak dapat menguraikan baris: %s"
+msgid "multi-pack-index version %d not recognized"
+msgstr "versi indeks multipak %d tidak dikenal"
#: midx.c
#, c-format
-msgid "malformed line: %s"
-msgstr "baris jelek '%s'."
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "versi hash indeks multipak %u tidak cocok dengan versi %u"
#: midx.c
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "abaikan indeks multipak yang sudah ada; checksum tidak cocok"
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr "bingkah nama pak indeks multipak yang diperlukan hilang atau rusak"
#: midx.c
-msgid "could not load pack"
-msgstr "tidak dapat memuat pak"
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"bingkah OID kipas-keluar indeks multipak yang diperlukan hilang atau rusak"
#: midx.c
-#, c-format
-msgid "could not open index for %s"
-msgstr "tidak dapat membuka indeks untuk %s"
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr ""
+"bingkah pencarian OID indeks multipak yang diperlukan hilang atau rusak"
#: midx.c
-msgid "Adding packfiles to multi-pack-index"
-msgstr "Menambahkan berkas pak ke indeks multipak"
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr "bingkah offset objek indeks multipak yang diperlukan hilang atau rusak"
+
+#: midx.c
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "bingkah nama pak indeks multipak terlalu kecil"
#: midx.c
#, c-format
-msgid "unknown preferred pack: '%s'"
-msgstr "pak yang disukai tidak dikenal: '%s'"
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "nama pak indeks multipak tidak berurutan: '%s' sebelum '%s'"
+
+#: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "berkas rantai indeks multipak terlalu kecil"
#: midx.c
#, c-format
-msgid "cannot select preferred pack %s with no objects"
-msgstr "tidak dapat memilih pak yang disukai %s tanpa objek"
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "jumlah pak pada MIDX dasarterlalu tinggi: %<PRIuMAX>"
#: midx.c
#, c-format
-msgid "did not see pack-file %s to drop"
-msgstr "tidak melihat berkas pak %s untuk dijeblokkan"
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "jumlah object pada MIDX dasar terlalu tinggi: %<PRIuMAX>"
#: midx.c
#, c-format
-msgid "preferred pack '%s' is expired"
-msgstr "pak yang disukai '%s' kadaluarsa"
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "rantai indeks multipak tidak valid: baris '%s' bukan suatu hash"
#: midx.c
-msgid "no pack files to index."
-msgstr "tidak ada berkas pak untuk diindeks."
+msgid "unable to find all multi-pack index files"
+msgstr "tidak dapat menemukan semua berkas indeks multipak"
#: midx.c
-msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "menolak menulis .bitmap multipak tanpa objek apapun"
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "posisi objek MIDX tidak valid, MIDX mungkin rusak"
#: midx.c
-msgid "could not write multi-pack bitmap"
-msgstr "tidak dapat menulis bitmap multipak"
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "pack-int-id jelek: %u (total pak %u)"
#: midx.c
-msgid "could not write multi-pack-index"
-msgstr "gagal menulis indeks multipak"
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX tidak berisi bingkah BTMP"
#: midx.c
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "gagal membersihkan indeks multipak pada %s"
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "tidak dapat membuka pak terbitmap %<PRIu32>"
+
+#: midx.c
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr "indeks multipak simpan offset 64-bit, tapi off_t terlalu kecil"
+
+#: midx.c
+msgid "multi-pack-index large offset out of bounds"
+msgstr "offset indeks multipak besar di luar jangkauan"
#: midx.c
msgid "multi-pack-index file exists, but failed to parse"
@@ -21793,14 +22476,6 @@ msgid "Looking for referenced packfiles"
msgstr "Mencari berkas pak yang direferensikan"
#: midx.c
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr ""
-"kipas-keluar oid tidak berurutan: fanout[%d] =%<PRIx32> > %<PRIx32> = "
-"fanout[%d]"
-
-#: midx.c
msgid "the midx contains no oid"
msgstr "midx tidak berisi oid"
@@ -21836,22 +22511,6 @@ msgstr "gagal memuat indeks pak untuk berkas pak %s"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "offset objek salah untuk oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-#: midx.c
-msgid "Counting referenced objects"
-msgstr "Menghitung objek tereferensi"
-
-#: midx.c
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "Mencari dan menghapus berkas pak tak tereferensi"
-
-#: midx.c
-msgid "could not start pack-objects"
-msgstr "tidak dapat memulai pack-objects"
-
-#: midx.c
-msgid "could not finish pack-objects"
-msgstr "tidak dapat menyelesaikan pack-objects"
-
#: name-hash.c
#, c-format
msgid "unable to create lazy_dir thread: %s"
@@ -21907,6 +22566,30 @@ msgstr "Menolak menulis ulang catatan di %s (di luar refs/notes/)"
msgid "Bad %s value: '%s'"
msgstr "Nilai %s jelek: '%s'"
+#: object-file-convert.c
+msgid "failed to decode tree entry"
+msgstr "gagal mendekode entri pohon"
+
+#: object-file-convert.c
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "gagal memetakan entri pohon untuk %s"
+
+#: object-file-convert.c
+#, c-format
+msgid "bad %s in commit"
+msgstr "%s di dalam komit"
+
+#: object-file-convert.c
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "tidak dapat memetakan %s %s pada objek komit"
+
+#: object-file-convert.c
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Gagal mengkonversi objek dari %s ke %s"
+
#: object-file.c
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
@@ -22036,6 +22719,21 @@ msgstr "objek terpak %s (disimpan di %s) rusak"
#: object-file.c
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "pemetaan %s ke %s hilang"
+
+#: object-file.c
+#, c-format
+msgid "unable to open %s"
+msgstr "tidak dapat membuka %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "berkas '%s' dan '%s' berbeda konteks"
+
+#: object-file.c
+#, c-format
msgid "unable to write file %s"
msgstr "tidak dapat menulis berkas %s"
@@ -22105,6 +22803,11 @@ msgstr "tidak dapat membaca objek untuk %s"
#: object-file.c
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "tidak dapat memetakan objek %s ke %s"
+
+#: object-file.c
+#, c-format
msgid "object fails fsck: %s"
msgstr "fsck objek gagal: %s"
@@ -22139,11 +22842,6 @@ msgstr "%s bukan sebuah objek '%s' valid"
#: object-file.c
#, c-format
-msgid "unable to open %s"
-msgstr "tidak dapat membuka %s"
-
-#: object-file.c
-#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "hash tidak cocok untuk %s (diharapkan %s)"
@@ -22368,6 +23066,20 @@ msgid "hash mismatch %s"
msgstr "hash tidak cocok %s"
#: pack-bitmap-write.c
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "entri duplikat ketika menulis indeks bitmap: %s"
+
+#: pack-bitmap-write.c
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "mencoba menyimpan komit yang tidak dipilih: '%s'"
+
+#: pack-bitmap-write.c
+msgid "too many pseudo-merges"
+msgstr "terlalu banyak penggabungan semu"
+
+#: pack-bitmap-write.c
msgid "trying to write commit not in index"
msgstr "mencoba menulis komit yang bukan di indeks"
@@ -22398,6 +23110,23 @@ msgstr ""
"berkas indeks bitmap rusak (terlalu pendek untuk masuk tabel pencarian)"
#: pack-bitmap.c
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"berkas indeks bitmap rusak (terlalu pendek untuk masuk kepala tabel "
+"penggabungan semu)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"berkas indeks bitmap rusak (terlalu pendek untuk masuk tabel penggabungan "
+"semu)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "berkas indeks bitmap rusak (tabel penggabungan semu terlalu pendek)"
+
+#: pack-bitmap.c
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "entri duplikat di indeks bitmap: '%s'"
@@ -22437,6 +23166,10 @@ msgstr "bitmap multipak kehilangan indeks balik yang diperlukan"
msgid "could not open pack %s"
msgstr "tidak dapat membuka '%s'"
+#: pack-bitmap.c t/helper/test-read-midx.c
+msgid "could not determine MIDX preferred pack"
+msgstr "tidak dapat menentukan pak MIDX terpilih"
+
#: pack-bitmap.c
#, c-format
msgid "preferred pack (%s) is invalid"
@@ -22462,6 +23195,16 @@ msgstr "bitmap ewah rusak: kepala terpotong untuk bitmap komit \"%s\""
#: pack-bitmap.c
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "tidak dapat memuat pak: '%s', mematikan penggunaan ulang pak"
+
+#: pack-bitmap.c
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr ""
+"tidak dapat menghitung pak yang disukai, mematikan penggunaan ulang pak"
+
+#: pack-bitmap.c
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "objek '%s' tidak ditemukan di bitmap tipe"
@@ -22499,6 +23242,11 @@ msgstr "ketidaksesuaian di dalam hasil bitmap"
#: pack-bitmap.c
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "indeks penggabungan semu di luar jangkauan (%<PRIu32> >= %<PRIuMAX>)"
+
+#: pack-bitmap.c
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "tidak dapat menemukan %s di dalam pak '%s' pada offset %<PRIuMAX>"
@@ -22571,6 +23319,14 @@ msgstr "checksum tidak valid"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "posisi indeks balik tidak valid pada %<PRIu64>: %<PRIu32> != %<PRIu32>"
+#: pack-revindex.c
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "bingkah indeks balik multipak salah ukuran"
+
+#: pack-revindex.c
+msgid "could not determine preferred pack"
+msgstr "tidak dapat menentukan pak terpilih"
+
#: pack-write.c
msgid "cannot both write and verify reverse index"
msgstr "tidak dapat kedua-duanya menulis dan memverifikasi indeks balik"
@@ -22636,16 +23392,6 @@ msgstr "%s butuh sebuah nilai"
#: parse-options.c
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s tidak kompatibel dengan %s"
-
-#: parse-options.c
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s : tidak kompatibel dengan sesuatu yang lain"
-
-#: parse-options.c
-#, c-format
msgid "%s takes no value"
msgstr "%s tidak mengambil nilai apapun"
@@ -22745,6 +23491,11 @@ msgstr " %s"
msgid "-NUM"
msgstr "-NUM"
+#: parse-options.c
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "lawan dari --no-%s"
+
#: parse-options.h
msgid "expiry-date"
msgstr "tanggal kadaluarsa"
@@ -22783,6 +23534,16 @@ msgid ""
msgstr ""
"dengan --pathspec-from-file, elemen spek jalur dipisahkan dengan karakter NUL"
+#: parse.c
+#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "nilai lingkungan boolean '%s' jelek untuk '%s'"
+
+#: parse.c
+#, c-format
+msgid "failed to parse %s"
+msgstr "gagal menguraikan %s"
+
#: path.c
#, c-format
msgid "Could not make %s writable by group"
@@ -22845,6 +23606,11 @@ msgstr "%s: 'literal' dan 'glob' tidak kompatibel"
#: pathspec.c
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "'%s' di luar pohon direktori"
+
+#: pathspec.c
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s: '%s' di luar repositori pada '%s'"
@@ -22938,6 +23704,10 @@ msgid "unable to parse --pretty format"
msgstr "tidak dapat menguraikan format --pretty"
#: promisor-remote.c
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "pengambilan malas dimatikan; beberapa objek mungkin tidak tersedia"
+
+#: promisor-remote.c
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote: tidak dapat menggarpu subproses pengambilan"
@@ -22968,6 +23738,83 @@ msgstr "object-info: bilasan diharapkan setelah argumen"
msgid "Removing duplicate objects"
msgstr "Menghapus objek duplikat"
+#: pseudo-merge.c
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "gagal memuat regex penggabungan semu untuk %s: '%s'"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s harus non-negatif, menggunakan yang asali"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s harus di antara 0 atau 1, menggunakan yang asali"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s harus positif, menggunakan yang asali"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "grup penggabungan semu '%s' kehilangan pola yang diperlukan"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"grup penggabungan semu '%s' punya ambang batas tidak stabil sebelum yang "
+"stabil"
+
+#: pseudo-merge.c
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"regex penggabungan semu dari konfigurasi punya terlalu banyak grup tangkap "
+"(max=%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"pembacaan penggabungan semu yang diperluas di luar batas (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"entri penggabungan semu yang diperluas terlalu pendek (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr ""
+"tidak dapat menemukan penggabungan semu untuk %s pada offset %<PRIuMAX>"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"pencarian penggabungan semu yang diperluas di luar batas (%<PRIu32> >= "
+"%<PRIu32>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "pembacaan di luar batas: (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "tidak dapat membaca tabel penggabungan semu untuk komit %s"
+
#: range-diff.c
msgid "could not start `log`"
msgstr "tidak dapat memulai `log`"
@@ -23042,11 +23889,6 @@ msgstr "tidak dapat menambahkan '%s' ke indeks"
#: read-cache.c
#, c-format
-msgid "unable to stat '%s'"
-msgstr "tidak dapat men-stat '%s'"
-
-#: read-cache.c
-#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "'%s' muncul baik sebagai sebuah berkas dan sebagai sebuah direktori"
@@ -23180,11 +24022,6 @@ msgstr "gagal mengubah ke indeks jarang"
#: read-cache.c
#, c-format
-msgid "could not stat '%s'"
-msgstr "tidak dapat men-stat '%s'"
-
-#: read-cache.c
-#, c-format
msgid "unable to open git dir: %s"
msgstr "tidak dapat membuka direktori git: %s"
@@ -23491,6 +24328,11 @@ msgstr "format yang diharapkan: %%(ahead-behind:<mirip komit>)"
#: ref-filter.c
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "format yang diharapkan: %%(is-base:<mirip komit>)"
+
+#: ref-filter.c
+#, c-format
msgid "malformed field name: %.*s"
msgstr "nama bidang rusak: %.*s"
@@ -23704,12 +24546,21 @@ msgid "log for %s is empty"
msgstr "log untuk %s kosong"
#: refs.c
+msgid "refusing to force and skip creation of reflog"
+msgstr "menolak memaksa dan melewatkan pembuatan reflog"
+
+#: refs.c
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "menolak memperbarui referensi dengan nama jelek '%s'"
#: refs.c
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "menolak memperbarui referensi semu '%s'"
+
+#: refs.c
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "update_ref gagal untuk referensi '%s': %s"
@@ -23736,21 +24587,131 @@ msgstr "'%s' ada; tidak dapat membuat '%s'"
msgid "cannot process '%s' and '%s' at the same time"
msgstr "tidak dapat memproses '%s' dan '%s' pada waktu yang bersamaan"
-#: refs/files-backend.c
-#, c-format
-msgid "could not remove reference %s"
-msgstr "tidak dapat menghapus referensi %s"
-
-#: refs/files-backend.c refs/packed-backend.c
+#: refs.c
#, c-format
msgid "could not delete reference %s: %s"
msgstr "tidak dapat menghapus referensi %s: %s"
-#: refs/files-backend.c refs/packed-backend.c
+#: refs.c
#, c-format
msgid "could not delete references: %s"
msgstr "tidak dapat menghapus referensi: %s"
+#: refs.c
+#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "Selesai uji coba migrasi referensi, hasilnya bisa dilihat di '%s'\n"
+
+#: refs.c
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "tidak dapat menamai ulang direktori migrasi sementara '%s'"
+
+#: refs.c
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "referensi termigrasi dapat ditemukan pada '%s'"
+
+#: refs/files-backend.c refs/reftable-backend.c
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"tidak dapat mengunci referensi '%s': diharapkan referensi simbolik dengan "
+"target '%s': tetapi bukan referensi reguler"
+
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "tidak dapat membuka direktori %s"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "Memeriksa konsistensi referensi"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "nama referensi berbahaya: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "mencoba menulis referensi '%s' dengan objek %s yang tak ada"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "mencoba menulis objek non-komit %s pada cabang '%s'"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"beberapa pembaruan 'HEAD' (termasuk yang lewat perujuknya '%s' tidak "
+"diperbolehkan"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr "tidak dapat mengunci '%s': tidak dapat menguraikan referensi '%s'"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "tidak dapat mengunci referensi '%s': kesalahan membaca referensi"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"beberapa pembaruan '%s' (termasuk yang lewat referensi simboliknya "
+"'%s')tidak diperbolehkan"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "tidak dapat mengunci referensi '%s': referensi sudah ada"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr ""
+"tidak dapat mengunci referensi '%s' referensi %s hilang tapi diharapkan"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "tidak dapat mengunci referensi '%s': pada %s tetapi diharapkan %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "reftable: menyiapkan transaksi: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "reftable: transaksi gagal: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "tidak dapat memampatkan tumpukan: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s not found"
+msgstr "nama referensi %s tidak ditemukan"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "nama referensi %s simbolik, menyalinnya tidak didukung"
+
#: refspec.c
#, c-format
msgid "invalid refspec '%s'"
@@ -23763,6 +24724,11 @@ msgstr "kuotasi tidak valid dalam nilai push-option: '%s'"
#: remote-curl.c
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "nilai object-format tidak dikenal: %s"
+
+#: remote-curl.c
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs tidak valid: apakah ini sebuah repositori git?"
@@ -23981,9 +24947,9 @@ msgid ""
msgstr ""
"Tujuan yang Anda berikan bukan nama referensi penuh (seperti \n"
"dimulai dengan \"refs/\"). Kami mencoba menebak maksud Anda dengan:\n"
-"- Cari referensi yang cocok dengan '%s' pada sisi remote.\n"
-"- Perika apakah <src> yang sedang didorong ('%s') adalah \n"
-" referensi pada \"refs/{heads,tags}\". Bila demikian kami \n"
+"- mencari referensi yang cocok dengan '%s' pada sisi remote.\n"
+"- memeriksa apakah <src> yang sedang didorong ('%s') adalah \n"
+" referensi pada \"refs/{heads,tags}/\". Bila demikian kami \n"
" menambahkan awalan refs/{heads,tags}/ yang bersesuaian pada sisi \n"
" remote.\n"
"\n"
@@ -24310,8 +25276,21 @@ msgstr "resolve-undo merekam `%s` yang dimana hilang"
#: revision.c
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "tidak dapat mendapatkan komit untuk argumen jalur leluhur '%s'"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s ada dan tapi referensi simbolik"
+
+#: revision.c
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge butuh salah satu dari referensi semu MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD atau REBASE_HEAD"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "tidak dapat mendapatkan komit untuk argumen --ancestry-path %s"
#: revision.c
msgid "--unpacked=<packfile> no longer supported"
@@ -24434,8 +25413,20 @@ msgid "only download metadata for the branch that will be checked out"
msgstr "hanya unduh metadata untuk cabang yang akan dicheckout"
#: scalar.c
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<options>] [--] <repositori> [<direktori>]"
+msgid "create repository within 'src' directory"
+msgstr "salin repositori di dalam direktori 'src'"
+
+#: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "rincikan jikan tag hendak diambil selama kloning"
+
+#: scalar.c
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <cabang utama>] [--full-clone]\n"
+"\t[--[-no-]src] [--[no-]tags] <url> [<pendaftaran>]"
#: scalar.c
#, c-format
@@ -24459,6 +25450,11 @@ msgstr "tidak dapat menyetel remote di '%s'"
#: scalar.c
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "tidak dapat menonaktifkan tag di '%s'"
+
+#: scalar.c
+#, c-format
msgid "could not configure '%s'"
msgstr "tidak dapat menyetel '%s'"
@@ -24501,13 +25497,32 @@ msgstr "tidak dapat menghapus scalar.repo basi '%s'"
#: scalar.c
#, c-format
-msgid "removing stale scalar.repo '%s'"
+msgid "removed stale scalar.repo '%s'"
msgstr "menghapus scalar.repo basi '%s'"
#: scalar.c
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "repositori git pergi di '%s'"
+msgid "repository at '%s' has different owner"
+msgstr "repositori pada '%s' berpemilik lain"
+
+#: scalar.c
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "repositori pada '%s' ada masalah format"
+
+#: scalar.c
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "repositori tidak ditemukan di '%s'"
+
+#: scalar.c
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"untuk mencabut repositori ini dari Scalar, jalankan\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
#: scalar.c
msgid ""
@@ -24648,6 +25663,21 @@ msgstr "aksi tidak dikenal: %d"
#: sequencer.c
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 ""
+"Selesaikan semua konflik secara manual, tandai sebagai terselesaikan\n"
+"dengan \"git add/rm <berkas terkonflik>\", lalu jalankan\n"
+"\"git rebase --continue\".\n"
+"Anda juga bisa melewatkan komit ini: jalankan \"git rebase --skip\".\n"
+"Untuk membatalkan dan kembali ke kondisi sebelum \"git rebase\",jalankan "
+"\"git rebase --abort\"."
+
+#: sequencer.c
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -24896,18 +25926,13 @@ msgstr "identitas pengarang tidak valid '%s'"
msgid "corrupt author: missing date information"
msgstr "pengarang rusak: informasi tanggal hilang"
-#: sequencer.c t/helper/test-fast-rebase.c
+#: sequencer.c
#, c-format
msgid "could not update %s"
msgstr "tidak dapat memperbarui %s"
#: sequencer.c
#, c-format
-msgid "could not parse commit %s"
-msgstr "tidak dapat menguraikan komit %s"
-
-#: sequencer.c
-#, c-format
msgid "could not parse parent commit %s"
msgstr "tidak dapat menguraikan komit induk %s"
@@ -24993,11 +26018,6 @@ msgstr "%s: tidak dapat menguraikan komit induk %s"
#: sequencer.c
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "tidak dapat menamai ulang '%s' ke '%s'"
-
-#: sequencer.c
-#, c-format
msgid "could not revert %s... %s"
msgstr "tidak dapat membalikkan %s... %s"
@@ -25040,13 +26060,57 @@ msgstr ""
#: sequencer.c
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "perintah tidak valid '%.*s'"
+msgid "'%s' does not accept merge commits"
+msgstr "'%s' tidak menerima komit penggabungan"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"'pick' tidak mengambil komit penggabungan. Apabila Anda\n"
+"ingin memainkan ulang penggabungan, gunakan 'merge -C'\n"
+"pada komit."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"'reword' tidak mengambil komit penggabungan. Apabila Anda\n"
+"ingin memainkan ulang penggabungan dan menulis ulang pesan\n"
+"komit, gunakan 'merge -c' pada komit"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+#: sequencer.c
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"'edit' tidak mengambil komit penggabungan. Apabila Anda\n"
+"ingin memainkan ulang komit, gunakan 'merge -C' pada komit,\n"
+"lalu 'break' untuk memberikan Anda kembali kendali agar\n"
+"Anda dapat menjalankan 'git commit --amend && git rebase --continue'."
+
+#: sequencer.c
+msgid "cannot squash merge commit into another commit"
+msgstr "tidak dapat melumatkan komit penggabungan ke dalam komit lainnya"
#: sequencer.c
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s tidak menerima argumen: '%s'"
+msgid "invalid command '%.*s'"
+msgstr "perintah tidak valid '%.*s'"
#: sequencer.c
#, c-format
@@ -25195,9 +26259,8 @@ msgid "cannot read HEAD"
msgstr "tidak dapat membaca HEAD"
#: sequencer.c
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "tidak dapat menyalin '%s' ke '%s'"
+msgid "could not write commit message file"
+msgstr "tidak dapat menulis berkas pesan komit"
#: sequencer.c
#, c-format
@@ -25396,6 +26459,10 @@ msgid "Autostash exists; creating a new stash entry."
msgstr "Stase otomatis sudah ada; membuat entri stase baru."
#: sequencer.c
+msgid "autostash reference is a symref"
+msgstr "referensi autostase itu referensi simbolik"
+
+#: sequencer.c
msgid "could not detach HEAD"
msgstr "tidak dapat melepas HEAD"
@@ -25432,13 +26499,13 @@ msgstr ""
#: sequencer.c
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "Mendasarkan ulang (%d/%d)%s"
+msgid "Stopped at %s... %.*s\n"
+msgstr "Berhenti pada %s... %.*s\n"
#: sequencer.c
#, c-format
-msgid "Stopped at %s... %.*s\n"
-msgstr "Berhenti pada %s... %.*s\n"
+msgid "Rebasing (%d/%d)%s"
+msgstr "Mendasarkan ulang (%d/%d)%s"
#: sequencer.c
#, c-format
@@ -25601,6 +26668,11 @@ msgstr "tidak dapat memasang pohon kerja menggunakan konfigurasi tidak valid"
#: setup.c
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "'%s' sudah diberikan yaitu '%s'"
+
+#: setup.c
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "Versi repositori git diharapkan <= %d, dapat %d"
@@ -25671,6 +26743,24 @@ msgid "failed to stat '%*s%s%s'"
msgstr "gagal men-stat '%*s%s%s'"
#: setup.c
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' bukan mutlak"
+
+#: 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 ""
+"perizinan meragukan terdeteksi di dalam repositori pada '%s'\n"
+"%sUntuk menambahkan pengecualian untuk direktori ini, panggil:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
+#: setup.c
msgid "Unable to read current working directory"
msgstr "tidak dapat membaca direktori kerja saat ini"
@@ -25696,19 +26786,6 @@ msgstr ""
#: 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 ""
-"perizinan meragukan terdeteksi di dalam repositori pada '%s'\n"
-"%sUntuk menambahkan pengecualian untuk direktori ini, panggil:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-
-#: setup.c
-#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
msgstr ""
"tidak dapat menggunakan repositori bare '%s' (safe.bareRepository yaitu '%s')"
@@ -25777,6 +26854,11 @@ msgstr "nama cabang asal salah: '%s'"
#: setup.c
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: --initial-branch=%s diabaikan"
+
+#: setup.c
+#, c-format
msgid "unable to handle file type %d"
msgstr "tidak dapat menangani tipe berkas %d"
@@ -25790,14 +26872,16 @@ 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"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr ""
+"mencoba menginisialisasi ulang repositori dengan format penyimpanan "
+"referensi yang berbeda"
#: setup.c
#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: --initial-branch=%s diabaikan"
+msgid "%s already exists"
+msgstr "%s sudah ada"
#: setup.c
#, c-format
@@ -25828,6 +26912,24 @@ msgstr "entri indeks adalah direktori, tapi bukan tipis (%08x)"
msgid "cannot use split index with a sparse index"
msgstr "tidak dapat menggunakan indeks terpisah dengan indeks tipis"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "format %s jelek: elemen '%s' tidak dimulai dengan '('"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "format %s jelek: elemen '%s' tidak diakhiri dengan ')'"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "format %s jelek: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#: strbuf.c
#, c-format
@@ -26057,6 +27159,17 @@ msgstr "direktori submodul git '%s' di dalam direktori git '%.*s'"
#: submodule.c
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"'%.*s' diharapkan di jalur submodul '%s' yang tidak menjadi tautan simbolik"
+
+#: submodule.c
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "jalur submodul '%s' diharapkan yang tidak menjadi tautan simbolik"
+
+#: submodule.c
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
@@ -26103,11 +27216,6 @@ msgid "no remote configured to get bundle URIs from"
msgstr "tidak ada remote yang dikonfigurasi untuk mendapatkan URI bundel"
#: t/helper/test-bundle-uri.c
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "remote '%s' tidak punya URL terkonfigurasi"
-
-#: t/helper/test-bundle-uri.c
msgid "could not get the bundle-uri list"
msgstr "tidak dapat mendapatkan daftar bundle-uri"
@@ -26123,14 +27231,6 @@ msgstr "bersihkan pohon tembolok sebelum setiap iterasi"
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr "jumlah entri di dalam pohon tembolok untuk dinirvalidasi (asali 0)"
-#: t/helper/test-fast-rebase.c
-msgid "unhandled options"
-msgstr "opsi tak tertangani"
-
-#: t/helper/test-fast-rebase.c
-msgid "error preparing revisions"
-msgstr "kesalahan menyiapkan revisi"
-
#: t/helper/test-reach.c
#, c-format
msgid "commit %s is not marked reachable"
@@ -26222,6 +27322,30 @@ msgstr "token"
msgid "command token to send to the server"
msgstr "token perintah untuk dikirim ke peladen"
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<opsi>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "langsung keluar pada saat kegagalan tes pertama"
+
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "hanya jalankan rangkaian tes atau tes individu <suite[::test]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "rangkaian"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "kecualikan rangkaian tes <rangkaian>"
+
#: trailer.c
#, c-format
msgid "running trailer command '%s' failed"
@@ -26237,35 +27361,6 @@ msgstr "nilai tidak dikenal '%s' untuk kunci '%s'"
msgid "empty trailer token in trailer '%.*s'"
msgstr "token trailer kosong dalam trailer '%.*s'"
-#: trailer.c
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "tidak dapat membaca berkas masukan '%s'"
-
-#: trailer.c wrapper.c
-#, c-format
-msgid "could not stat %s"
-msgstr "tidak dapat membaca %s"
-
-#: trailer.c
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "berkas %s bukan sebuah berkas reguler"
-
-#: trailer.c
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "berkas %s tidak dapat ditulis oleh pengguna"
-
-#: trailer.c
-msgid "could not open temporary file"
-msgstr "tidak dapat membuka berkas sementara"
-
-#: trailer.c
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "tidak dapat menamai ulang berkas sementara ke %s"
-
#: transport-helper.c
msgid "full write to remote helper failed"
msgstr "gagal menulis penuh ke pembantu remote"
@@ -26328,10 +27423,6 @@ msgstr "menyetel jalur layanan remote tidak didukung oleh protokol"
msgid "invalid remote service path"
msgstr "jalur layanan remote tidak valid"
-#: transport-helper.c transport.c
-msgid "operation not supported by protocol"
-msgstr "operasi tidak didukung oleh protokol"
-
#: transport-helper.c
#, c-format
msgid "can't connect to subservice %s"
@@ -26391,8 +27482,8 @@ msgstr "pembantu tidak mendukung pendorongan; spek referensi diperlukan"
#: transport-helper.c
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "pembantu %s tidak mendukung 'force'"
+msgid "helper %s does not support '--force'"
+msgstr "pembantu %s tidak mendukung '--force'"
#: transport-helper.c
msgid "couldn't run fast-export"
@@ -26497,11 +27588,6 @@ msgstr "dukungan untuk protokol v2 belum diterapkan"
#: transport.c
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "nilai tidak dikenal untuk konfigurasi '%s': %s"
-
-#: transport.c
-#, c-format
msgid "transport '%s' not allowed"
msgstr "transportasi '%s' tidak diperbolehkan"
@@ -26560,6 +27646,10 @@ msgstr "operasi bundle-uri tidak didukung oleh protokol"
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "tidak dapat menerima daftar bundle-uri teriklankan server"
+#: transport.c
+msgid "operation not supported by protocol"
+msgstr "operasi tidak didukung oleh protokol"
+
#: tree-walk.c
msgid "too-short tree object"
msgstr "objek pohon terlalu pendek"
@@ -26876,6 +27966,11 @@ msgid "invalid '..' path segment"
msgstr "segmen jalur '..' tidak valid"
#: usage.c
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "kesalahan: tidak dapat memformat pesan: %s\n"
+
+#: usage.c
msgid "usage: "
msgstr "penggunaan: "
@@ -27020,6 +28115,10 @@ msgstr "tidak dapat mengakses '%s'"
msgid "unable to get current working directory"
msgstr "tidak dapat mendapatkan direktori kerja saat ini"
+#: wrapper.c
+msgid "unable to get random bytes"
+msgstr "tidak dapat mendapatkan bita acak"
+
#: wt-status.c
msgid "Unmerged paths:"
msgstr "Jalur yang tak tergabung:"
@@ -27577,6 +28676,11 @@ msgstr "juga indeks Anda berisi perubahan yang belum dikomit."
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "tidak dapat %s: indeks Anda berisi perubahan yang belum dikomit."
+#: xdiff-interface.c
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "nilai gaya tidak dikenal '%s' diberikan untuk '%s'"
+
#: git-merge-octopus.sh git-merge-resolve.sh
msgid ""
"Error: Your local changes to the following files would be overwritten by "
@@ -27691,6 +28795,10 @@ msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases tidak kompatibel dengan opsi yang lain\n"
#: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases dan --translate-aliases saling eksklusif\n"
+
+#: git-send-email.perl
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -27799,13 +28907,13 @@ msgstr ""
#: git-send-email.perl
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "Gagal membuka %s: %s"
+msgid "Failed to open %s.final: %s"
+msgstr "Gagal membuka %s.final: %s"
#: git-send-email.perl
#, perl-format
-msgid "Failed to open %s.final: %s"
-msgstr "Gagal membuka %s.final: %s"
+msgid "Failed to open %s: %s"
+msgstr "Gagal membuka %s: %s"
#: git-send-email.perl
msgid "Summary email is empty, skipping it\n"
@@ -27934,29 +29042,29 @@ msgstr "Gagal mengirim %s\n"
#: git-send-email.perl
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Terkirim-kering %s\n"
+msgid "Dry-Sent %s"
+msgstr "Uji-coba-Terkirim %s"
#: git-send-email.perl
#, perl-format
-msgid "Sent %s\n"
-msgstr "Terkirim %s\n"
+msgid "Sent %s"
+msgstr "Terkirim %s"
#: git-send-email.perl
-msgid "Dry-OK. Log says:\n"
-msgstr "OK-kering. Log berkata:\n"
+msgid "Dry-OK. Log says:"
+msgstr "Uji-coba-OK. Log berkata:"
#: git-send-email.perl
-msgid "OK. Log says:\n"
-msgstr "OK. Log berkata:\n"
+msgid "OK. Log says:"
+msgstr "OK. Log berkata:"
#: git-send-email.perl
msgid "Result: "
msgstr "Hasil: "
#: git-send-email.perl
-msgid "Result: OK\n"
-msgstr "Hasil: OK\n"
+msgid "Result: OK"
+msgstr "Hasil: OK"
#: git-send-email.perl
#, perl-format
@@ -28046,22 +29154,3 @@ 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)"
diff --git a/po/sv.po b/po/sv.po
index a14d0d6f38..973dd940ac 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -1,14 +1,14 @@
# Swedish translations for Git.
-# Copyright (C) 2010-2023 Peter Krefting <peter@softwolves.pp.se>
+# Copyright (C) 2010-2024 Peter Krefting <peter@softwolves.pp.se>
# This file is distributed under the same license as the Git package.
-# Peter Krefting <peter@softwolves.pp.se>, 2010-2023.
+# Peter Krefting <peter@softwolves.pp.se>, 2010-2024.
#
msgid ""
msgstr ""
-"Project-Id-Version: git 2.42.0\n"
+"Project-Id-Version: git 2.47.0\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-08-16 07:40+0100\n"
-"PO-Revision-Date: 2023-08-16 07:42+0100\n"
+"POT-Creation-Date: 2024-09-19 02:06+0000\n"
+"PO-Revision-Date: 2024-09-28 15:45+0100\n"
"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
"Language-Team: Svenska <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Gtranslator 3.38.0\n"
+"X-Generator: Gtranslator 42.0\n"
#, c-format
msgid "Huh (%s)?"
@@ -39,7 +39,7 @@ msgstr "Uppdatera"
#, c-format
msgid "could not stage '%s'"
-msgstr "kunde inte köa \"%s\""
+msgstr "kunde inte köa â€%sâ€"
msgid "could not write index"
msgstr "kunde inte skriva indexet"
@@ -56,7 +56,7 @@ msgstr "observera: %s spåras inte längre.\n"
#, c-format
msgid "make_cache_entry failed for path '%s'"
-msgstr "make_cache_entry misslyckades för sökvägen \"%s\""
+msgstr "make_cache_entry misslyckades för sökvägen â€%sâ€"
msgid "Revert"
msgstr "Återställ"
@@ -228,7 +228,7 @@ msgid ""
"stashing."
msgstr ""
"Om patchen kan appliceras rent kommer det redigerade stycket att läggas till "
-"i \"stash\" omedelbart."
+"i â€stash†omedelbart."
msgid ""
"y - stash this hunk\n"
@@ -237,11 +237,11 @@ msgid ""
"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 - \"stash\":a stycket\n"
-"n - \"stash\":a inte stycket\n"
-"q - avsluta; \"stash\":a inte stycket eller något av de följande\n"
-"a - \"stash\":a stycket och alla följande i filen\n"
-"d - \"stash\":a inte stycket eller något av de följande i filen\n"
+"y - â€stashâ€:a stycket\n"
+"n - â€stashâ€:a inte stycket\n"
+"q - avsluta; â€stashâ€:a inte stycket eller nÃ¥got av de följande\n"
+"a - â€stashâ€:a stycket och alla följande i filen\n"
+"d - â€stashâ€:a inte stycket eller nÃ¥got av de följande i filen\n"
#, c-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
@@ -440,7 +440,7 @@ msgstr ""
#, c-format
msgid "could not parse hunk header '%.*s'"
-msgstr "kunde inte tolka styckehuvudet \"%.*s\""
+msgstr "kunde inte tolka styckehuvudet â€%.*sâ€"
msgid "could not parse diff"
msgstr "kunde inte tolka diff"
@@ -450,7 +450,7 @@ msgstr "kunde inte tolka färgad diff"
#, c-format
msgid "failed to run '%s'"
-msgstr "misslyckades att köra \"%s\""
+msgstr "misslyckades att köra â€%sâ€"
msgid "mismatched output from interactive.diffFilter"
msgstr "omaka utdata från interactive.diffFilter"
@@ -490,12 +490,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
-"Ta bort \"%c\" rader genom att göra dem \" \"-rader (sammanhang).\n"
-"Ta bort \"%c\" rader genom att radera dem.\n"
-"Rader som börjar med %c kommer att tas bort.\n"
+"Ta bort â€%c†rader genom att göra dem †â€-rader (sammanhang).\n"
+"Ta bort â€%c†rader genom att radera dem.\n"
+"Rader som börjar med %s kommer att tas bort.\n"
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
@@ -510,7 +510,7 @@ msgid "could not parse hunk header"
msgstr "kunde inte tolka styckehuvud"
msgid "'git apply --cached' failed"
-msgstr "\"git apply --cached\" misslyckades"
+msgstr "â€git apply --cached†misslyckades"
#. TRANSLATORS: do not translate [y/n]
#. The program will only accept that input at this point.
@@ -521,8 +521,8 @@ msgstr "\"git apply --cached\" misslyckades"
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
-"Ditt redigerade stycke kan inte appliceras. Redigera igen (\"nej\" kastar!) "
-"[y/n]? "
+"Ditt redigerade stycke kan inte appliceras. Redigera igen (â€nej†kastar!) [y/"
+"n]? "
msgid "The selected hunks do not apply to the index!"
msgstr "Markerade stycken kan inte appliceras på indexet!"
@@ -542,6 +542,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j - lämna stycket obestämt, se nästa obestämda stycke\n"
@@ -552,8 +553,13 @@ msgstr ""
"/ - sök efter stycke som motsvarar angivet reguljärt uttryck\n"
"s - dela aktuellt stycke i mindre styckens\n"
"e - redigera aktuellt stycke manuellt\n"
+"p - visa aktuellt stycke, â€P†för att använda bläddrare\n"
"? - visa hjälp\n"
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "Förväntade endast en bokstav, fick â€%sâ€"
+
msgid "No previous hunk"
msgstr "Inget föregående stycke"
@@ -571,7 +577,7 @@ msgstr "gå till vilket stycke? "
#, c-format
msgid "Invalid number: '%s'"
-msgstr "Ogiltigt siffervärde: \"%s\""
+msgstr "Ogiltigt siffervärde: â€%sâ€"
#, c-format
msgid "Sorry, only %d hunk available."
@@ -602,8 +608,18 @@ msgstr "Dela i %d stycken."
msgid "Sorry, cannot edit this hunk"
msgstr "Beklagar, kan inte redigera stycket"
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Okänt kommando â€%s†(använd â€?†för hjälp)"
+
msgid "'git apply' failed"
-msgstr "\"git apply\" misslyckades"
+msgstr "â€git apply†misslyckades"
+
+msgid "No changes."
+msgstr "Inga ändringar."
+
+msgid "Only binary files changed."
+msgstr "Endast binära filer ändrade."
#, c-format
msgid ""
@@ -611,15 +627,15 @@ msgid ""
"Disable this message with \"git config advice.%s false\""
msgstr ""
"\n"
-"Slå av meddelandet med \"git config advice.%s false\""
+"SlÃ¥ av meddelandet med â€git config advice.%s falseâ€"
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%stips: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%stips:%s%.*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."
@@ -632,7 +648,7 @@ msgstr ""
msgid "Pulling is not possible because you have unmerged files."
msgstr ""
-"Du kan inte utföra en \"pull\" eftersom du har filer som inte slagits samman."
+"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 återställa eftersom du har filer som inte slagits samman."
@@ -644,11 +660,11 @@ 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 ""
-"Rätta dem i din arbetskatalog och använd sedan \"git add/rm <fil>\"\n"
+"Rätta dem i din arbetskatalog och använd sedan â€git add/rm <fil>â€\n"
"som lämpligt för att ange lösning och checka in."
msgid "Exiting because of an unresolved conflict."
-msgstr "Avslutar på grund av olöst konflikgt."
+msgstr "Avslutar på grund av olöst konflikt."
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)."
@@ -686,7 +702,7 @@ msgid ""
"updated in the index:\n"
msgstr ""
"Följande sökvägar och/eller sökvägsangivelser motsvarar sökvägar\n"
-"utanför din \"sparse-checkout\"-definition, så de kommer inte\n"
+"utanför din â€sparse-checkoutâ€-definition, sÃ¥ de kommer inte\n"
"uppdateras i indexet:\n"
msgid ""
@@ -719,9 +735,9 @@ msgid ""
"false\n"
"\n"
msgstr ""
-"Observera: checkar ut \"%s\".\n"
+"Observera: checkar ut â€%sâ€.\n"
"\n"
-"Du har nu ett \"frånkopplat HEAD\". Du kan se dig omkring, experimentera\n"
+"Du har nu ett â€frÃ¥nkopplat HEADâ€. Du kan se dig omkring, experimentera\n"
"med ändringar och checka in dem, och du kan kasta incheckningar du gör\n"
"i det här läget utan att det påverkar grenar genom att växla tillbaka\n"
"till en gren.\n"
@@ -747,7 +763,7 @@ msgid ""
"modifications.\n"
msgstr ""
"Följande sökvägar har flyttats ut från din\n"
-"\"sparse-checkout\"-definition, men är inte glesa på grund av\n"
+"â€sparse-checkoutâ€-definition, men är inte glesa pÃ¥ grund av\n"
"lokala ändringar.\n"
msgid ""
@@ -756,8 +772,8 @@ msgid ""
"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
msgstr ""
"För att korrigera glesheten för dessa sökvägar, gör följande:\n"
-"* Använd \"git add --sparse <sökväg>\" för att uppdatera indexet\n"
-"* Använd \"git sparse-checkout reapply\" för att tillämpa gleshetsreglerna"
+"* Använd â€git add --sparse <sökväg>†för att uppdatera indexet\n"
+"* Använd â€git sparse-checkout reapply†för att tillämpa gleshetsreglerna"
msgid "cmdline ends with \\"
msgstr "kommandorad avslutas med \\"
@@ -770,19 +786,19 @@ msgstr "för många argument"
#, c-format
msgid "unrecognized whitespace option '%s'"
-msgstr "okänt alternativ för whitespace: \"%s\""
+msgstr "okänt alternativ för whitespace: â€%sâ€"
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
-msgstr "okänt alternativ för ignore-whitespace: \"%s\""
+msgstr "okänt alternativ för ignore-whitespace: â€%sâ€"
#, c-format
msgid "options '%s' and '%s' cannot be used together"
-msgstr "flaggorna \"%s\" och \"%s\" kan inte användas samtidigt"
+msgstr "flaggorna â€%s†och â€%s†kan inte användas samtidigt"
#, c-format
msgid "'%s' outside a repository"
-msgstr "\"%s\" utanför arkiv"
+msgstr "â€%s†utanför arkiv"
msgid "failed to read patch"
msgstr "misslyckades läsa patchen"
@@ -889,15 +905,15 @@ msgstr "patch med bara skräp på rad %d"
#, c-format
msgid "unable to read symlink %s"
-msgstr "kunde inte läsa symboliska länken %s"
+msgstr "kan inte läsa symboliska länken %s"
#, c-format
msgid "unable to open or read %s"
-msgstr "kunde inte öppna eller läsa %s"
+msgstr "kan inte öppna eller läsa %s"
#, c-format
msgid "invalid start of line: '%c'"
-msgstr "felaktig inledning på rad: \"%c\""
+msgstr "felaktig inledning pÃ¥ rad: â€%câ€"
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
@@ -919,41 +935,38 @@ msgstr ""
#, c-format
msgid "missing binary patch data for '%s'"
-msgstr "saknar binära patchdata för \"%s\""
+msgstr "saknar binära patchdata för â€%sâ€"
#, c-format
msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'"
msgstr ""
-"kan inte applicera en binärpatch baklänges utan den omvända patchen för \"%s"
-"\""
+"kan inte applicera en binärpatch baklänges utan den omvända patchen för â€%sâ€"
#, c-format
msgid "cannot apply binary patch to '%s' without full index line"
-msgstr ""
-"kan inte applicera binärpatch på \"%s\" utan den fullständiga indexraden"
+msgstr "kan inte applicera binärpatch pÃ¥ â€%s†utan den fullständiga indexraden"
#, c-format
msgid ""
"the patch applies to '%s' (%s), which does not match the current contents."
msgstr ""
-"patchen appliceras på \"%s\" (%s), som inte motsvarar det nuvarande "
-"innehållet."
+"patchen appliceras pÃ¥ â€%s†(%s), som inte motsvarar det nuvarande innehÃ¥llet."
#, c-format
msgid "the patch applies to an empty '%s' but it is not empty"
-msgstr "patchen appliceras på en tom \"%s\", men den är inte tom"
+msgstr "patchen appliceras pÃ¥ en tom â€%sâ€, men den är inte tom"
#, c-format
msgid "the necessary postimage %s for '%s' cannot be read"
-msgstr "nödvändig efterbild %s för \"%s\" kan inte läsas"
+msgstr "nödvändig efterbild %s för â€%s†kan inte läsas"
#, c-format
msgid "binary patch does not apply to '%s'"
-msgstr "binärpatchen kan inte tillämpas på \"%s\""
+msgstr "binärpatchen kan inte tillämpas pÃ¥ â€%sâ€"
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
-msgstr "binärpatchen på \"%s\" ger felaktigt resultat (förväntade %s, fick %s)"
+msgstr "binärpatchen pÃ¥ â€%s†ger felaktigt resultat (förväntade %s, fick %s)"
#, c-format
msgid "patch failed: %s:%ld"
@@ -969,7 +982,7 @@ msgstr "misslyckades läsa %s"
#, c-format
msgid "reading from '%s' beyond a symbolic link"
-msgstr "läser från \"%s\" som är på andra sidan av en symbolisk länk"
+msgstr "läser frÃ¥n â€%s†som är pÃ¥ andra sidan av en symbolisk länk"
#, c-format
msgid "path %s has been renamed/deleted"
@@ -992,7 +1005,7 @@ msgstr "Utför trevägssammanslagning...\n"
#, c-format
msgid "cannot read the current contents of '%s'"
-msgstr "kunde inte läsa aktuellt innehåll i \"%s\""
+msgstr "kunde inte läsa aktuellt innehÃ¥ll i â€%sâ€"
#, c-format
msgid "Failed to perform three-way merge...\n"
@@ -1000,11 +1013,11 @@ msgstr "Misslyckades utföra trevägssammanslagning...\n"
#, c-format
msgid "Applied patch to '%s' with conflicts.\n"
-msgstr "Applicerade patchen på \"%s\" med konflikter.\n"
+msgstr "Applicerade patchen pÃ¥ â€%s†med konflikter.\n"
#, c-format
msgid "Applied patch to '%s' cleanly.\n"
-msgstr "Tillämpade patchen på \"%s\" rent.\n"
+msgstr "Tillämpade patchen pÃ¥ â€%s†rent.\n"
#, c-format
msgid "Falling back to direct application...\n"
@@ -1023,7 +1036,7 @@ msgstr "%s har typen %o, förväntade %o"
#, c-format
msgid "invalid path '%s'"
-msgstr "ogiltig sökväg \"%s\""
+msgstr "ogiltig sökväg â€%sâ€"
#, c-format
msgid "%s: already exists in index"
@@ -1043,7 +1056,7 @@ msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o) för %s"
#, c-format
msgid "affected file '%s' is beyond a symbolic link"
-msgstr "den berörda filen \"%s\" är på andra sidan av en symbolisk länk"
+msgstr "den berörda filen â€%s†är pÃ¥ andra sidan av en symbolisk länk"
#, c-format
msgid "%s: patch does not apply"
@@ -1083,7 +1096,7 @@ msgstr "trasig patch för undermodulen %s"
#, c-format
msgid "unable to stat newly created file '%s'"
-msgstr "kan inte ta status på nyligen skapade filen \"%s\""
+msgstr "kan inte ta status pÃ¥ nyligen skapade filen â€%sâ€"
#, c-format
msgid "unable to create backing store for newly created file %s"
@@ -1095,15 +1108,15 @@ msgstr "kan inte lägga till cachepost för %s"
#, c-format
msgid "failed to write to '%s'"
-msgstr "misslyckades skriva till \"%s\""
+msgstr "misslyckades skriva till â€%sâ€"
#, c-format
msgid "closing file '%s'"
-msgstr "stänger filen \"%s\""
+msgstr "stänger filen â€%sâ€"
#, c-format
msgid "unable to write file '%s' mode %o"
-msgstr "kan inte skriva filen \"%s\" läge %o"
+msgstr "kan inte skriva filen â€%s†läge %o"
#, c-format
msgid "Applied patch %s cleanly."
@@ -1119,16 +1132,12 @@ msgstr[0] "Tillämpade patchen %%s med %d refuserad..."
msgstr[1] "Tillämpade patchen %%s med %d refuserade..."
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "trunkerar .rej-filnamnet till %.*s.rej"
-
-#, c-format
msgid "cannot open %s"
msgstr "kan inte öppna %s"
#, c-format
msgid "cannot unlink '%s'"
-msgstr "kan inte ta bort länken \"%s\""
+msgstr "kan inte ta bort länken â€%sâ€"
#, c-format
msgid "Hunk #%d applied cleanly."
@@ -1140,17 +1149,17 @@ msgstr "Refuserar stycke %d."
#, c-format
msgid "Skipped patch '%s'."
-msgstr "Ignorerar patch \"%s\"."
+msgstr "Ignorerar patch â€%sâ€."
msgid "No valid patches in input (allow with \"--allow-empty\")"
-msgstr "Inga giltiga patchar i indata (tillåt med \"--allow-empty\")"
+msgstr "Inga giltiga patchar i indata (tillÃ¥t med â€--allow-emptyâ€)"
msgid "unable to read index file"
msgstr "kan inte läsa indexfilen"
#, c-format
msgid "can't open patch '%s': %s"
-msgstr "kan inte öppna patchen \"%s\": %s"
+msgstr "kan inte öppna patchen â€%sâ€: %s"
#, c-format
msgid "squelched %d whitespace error"
@@ -1171,7 +1180,7 @@ msgstr[0] "%d rad applicerade efter att ha rättat fel i blanksteg."
msgstr[1] "%d rader applicerade efter att ha rättat fel i blanksteg."
msgid "Unable to write new index file"
-msgstr "Kunde inte skriva ny indexfil"
+msgstr "Kan inte skriva ny indexfil"
msgid "don't apply changes matching the given path"
msgstr "tillämpa inte ändringar som motsvarar given sökväg"
@@ -1204,7 +1213,7 @@ msgid "make sure the patch is applicable to the current index"
msgstr "se till att patchen kan tillämpas på aktuellt index"
msgid "mark new files with `git add --intent-to-add`"
-msgstr "markera nya filer med \"git add --intent-to-add\""
+msgstr "markera nya filer med â€git add --intent-to-addâ€"
msgid "apply a patch without touching the working tree"
msgstr "tillämpa en patch utan att röra arbetskatalogen"
@@ -1220,6 +1229,15 @@ msgstr ""
"försök en trevägssammanslagning, fall tillbaka på normal patch om det "
"misslyckas"
+msgid "for conflicts, use our version"
+msgstr "för konflikter, använd vår version"
+
+msgid "for conflicts, use their version"
+msgstr "för konflikter, använd deras version"
+
+msgid "for conflicts, use a union version"
+msgstr "för konflikter, använd en förenad version"
+
msgid "build a temporary index based on embedded index information"
msgstr "bygg ett temporärt index baserat på inbyggd indexinformation"
@@ -1265,6 +1283,9 @@ msgstr "lägg till <rot> i alla filnamn"
msgid "don't return error for empty patches"
msgstr "ge inte någon felkod för tomma patchar"
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, och --union kräver --3way"
+
#, c-format
msgid "cannot stream blob %s"
msgstr "kan inte strömma blob:en %s"
@@ -1279,14 +1300,14 @@ msgstr "fel i deflate (%d)"
#, c-format
msgid "unable to start '%s' filter"
-msgstr "kunde inte starta filtret \"%s\""
+msgstr "kane inte starta filtret â€%sâ€"
msgid "unable to redirect descriptor"
msgstr "kan inte omdirigera handtag"
#, c-format
msgid "'%s' filter reported error"
-msgstr "filtret \"%s\" rapporterade fel"
+msgstr "filtret â€%s†rapporterade fel"
#, c-format
msgid "path is not valid UTF-8: %s"
@@ -1314,15 +1335,15 @@ msgstr "git archive --remote <arkiv> [--exec <kmd>] --list"
#, c-format
msgid "cannot read '%s'"
-msgstr "kunde inte läsa \"%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"
+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"
+msgstr "sökvägsangivelsen â€%s†motsvarade inte nÃ¥gra filer"
#, c-format
msgid "no such ref: %.*s"
@@ -1346,15 +1367,15 @@ msgstr "Inte en vanlig fil: %s"
#, c-format
msgid "unclosed quote: '%s'"
-msgstr "citat ej stängt: \"%s\""
+msgstr "citat ej stängt: â€%sâ€"
#, c-format
msgid "missing colon: '%s'"
-msgstr "kolon saknas: \"%s\""
+msgstr "kolon saknas: â€%sâ€"
#, c-format
msgid "empty file name: '%s'"
-msgstr "tomt filnamn: \"%s\""
+msgstr "tomt filnamn: â€%sâ€"
msgid "fmt"
msgstr "fmt"
@@ -1415,25 +1436,29 @@ msgstr "Oväntad flagga --remote"
#, c-format
msgid "the option '%s' requires '%s'"
-msgstr "flaggan \"%s\" kräver \"%s\""
+msgstr "flaggan â€%s†kräver â€%sâ€"
msgid "Unexpected option --output"
msgstr "Oväntad flagga --output"
#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "falsk konfigureringsparameter: â€%sâ€"
+
+#, c-format
msgid "Unknown archive format '%s'"
-msgstr "Okänt arkivformat \"%s\""
+msgstr "Okänt arkivformat â€%sâ€"
#, c-format
msgid "Argument not supported for format '%s': -%d"
-msgstr "Argumentet stöd inte för formatet \"%s\": -%d"
+msgstr "Argumentet stöd inte för formatet â€%sâ€: -%d"
#, c-format
msgid "%.*s is not a valid attribute name"
msgstr "%-*s är inte ett giltigt namn på attribut"
msgid "unable to add additional attribute"
-msgstr "Kunde inte lägga till ytterligare attribut"
+msgstr "kan inte lägga till ytterligare attribut"
#, c-format
msgid "ignoring overly long attributes line %d"
@@ -1452,26 +1477,37 @@ msgstr ""
#, c-format
msgid "cannot fstat gitattributes file '%s'"
-msgstr "kan inte utföra fstat på gitattributes-filen \"%s\""
+msgstr "kan inte utföra fstat pÃ¥ gitattributes-filen â€%sâ€"
#, c-format
msgid "ignoring overly large gitattributes file '%s'"
-msgstr "ignorerar allt för stor gitattributes-fil \"%s\""
+msgstr "ignorerar allt för stor gitattributes-fil â€%sâ€"
#, c-format
msgid "ignoring overly large gitattributes blob '%s'"
-msgstr "ignorerar allt för stor gitattributes-objekt \"%s\""
+msgstr "ignorerar allt för stor gitattributes-objekt â€%sâ€"
+
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "kan inte använda --attr-source eller GIT_ATTR_SOURCE utan arkiv"
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "felaktig --attr-source eller GIT_ATTR_SOURCE"
#, c-format
+msgid "unable to stat '%s'"
+msgstr "kan inte ta status pÃ¥ â€%sâ€"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "kan inte läsa %s"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
-msgstr "Felaktigt citerat innehåll i filen \"%s\": %s"
+msgstr "Felaktigt citerat innehÃ¥ll i filen â€%sâ€: %s"
#, c-format
msgid "We cannot bisect more!\n"
-msgstr "Det finns inte mer att göra \"bisect\" på!\n"
+msgstr "Det finns inte mer att göra â€bisect†pÃ¥!\n"
#, c-format
msgid "Not a valid commit name %s"
@@ -1499,7 +1535,7 @@ msgid ""
"This means the first '%s' commit is between %s and [%s].\n"
msgstr ""
"Sammanslagningsbasen %s är %s.\n"
-"Det betyder att den första \"%s\" incheckningen är mellan %s och [%s].\n"
+"Det betyder att den första â€%s†incheckningen är mellan %s och [%s].\n"
#, c-format
msgid ""
@@ -1532,11 +1568,15 @@ msgstr "en %s-revision behövs"
#, c-format
msgid "could not create file '%s'"
-msgstr "kunde inte skapa filen \"%s\""
+msgstr "kunde inte skapa filen â€%sâ€"
+
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "kan inte starta â€show†för objektet â€%sâ€"
#, c-format
msgid "could not read file '%s'"
-msgstr "kunde inte läsa filen \"%s\""
+msgstr "kunde inte läsa filen â€%sâ€"
msgid "reading bisect refs failed"
msgstr "misslyckades läsa bisect-referenser"
@@ -1606,15 +1646,15 @@ msgstr "ställer inte in grenen %s som sin egen uppströmsgren"
#, c-format
msgid "branch '%s' set up to track '%s' by rebasing."
-msgstr "grenen \"%s\" inställd på att spåra \"%s\" genom ombasering."
+msgstr "grenen â€%s†inställd pÃ¥ att spÃ¥ra â€%s†genom ombasering."
#, c-format
msgid "branch '%s' set up to track '%s'."
-msgstr "grenen \"%s\" inställd på att spåra \"%s\"."
+msgstr "grenen â€%s†inställd pÃ¥ att spÃ¥ra â€%sâ€."
#, c-format
msgid "branch '%s' set up to track:"
-msgstr "grenen \"%s\" inställd på att spåra:"
+msgstr "grenen â€%s†inställd pÃ¥ att spÃ¥ra:"
msgid "unable to write upstream branch configuration"
msgstr "kan inte skriva inställningar för uppströmsgren"
@@ -1630,17 +1670,17 @@ msgstr ""
#, c-format
msgid "asked to inherit tracking from '%s', but no remote is set"
-msgstr "bad om att ärva spårning från \"%s\", men ingen fjärr är vald"
+msgstr "bad om att ärva spÃ¥rning frÃ¥n â€%sâ€, men ingen fjärr är vald"
#, c-format
msgid "asked to inherit tracking from '%s', but no merge configuration is set"
msgstr ""
-"bad om att ärva spårning från \"%s\", men ingen sammanslagningsinställning "
-"är vald"
+"bad om att ärva spÃ¥rning frÃ¥n â€%sâ€, men ingen sammanslagningsinställning är "
+"vald"
#, c-format
msgid "not tracking: ambiguous information for ref '%s'"
-msgstr "spårar inte: tvetydig information för referensen \"%s\""
+msgstr "spÃ¥rar inte: tvetydig information för referensen â€%sâ€"
#. #-#-#-#-# branch.c.po #-#-#-#-#
#. TRANSLATORS: This is a line listing a remote with duplicate
@@ -1672,7 +1712,7 @@ msgid ""
"tracking namespaces."
msgstr ""
"Flera fjärrars hämtnings-referensspecifikationer motsvarar fjärr-\n"
-"spårningsreferensen \"%s\":\n"
+"spÃ¥rningsreferensen â€%sâ€:\n"
"%s\n"
"Detta är vanligtvis ett fel i konfigurationen.\n"
"\n"
@@ -1682,26 +1722,29 @@ msgstr ""
#, c-format
msgid "'%s' is not a valid branch name"
-msgstr "\"%s\" är inte ett giltigt grennamn"
+msgstr "â€%s†är inte ett giltigt grennamn"
+
+msgid "See `man git check-ref-format`"
+msgstr "Se â€man git check-ref-formatâ€"
#, c-format
msgid "a branch named '%s' already exists"
-msgstr "det finns redan en gren som heter \"%s\""
+msgstr "det finns redan en gren som heter â€%sâ€"
#, c-format
msgid "cannot force update the branch '%s' used by worktree at '%s'"
msgstr ""
-"kan inte tvinga uppdatering av grenen \"%s\" som används av arbetskatalogen "
-"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"
msgstr ""
-"kan inte ställa in spårningsinformation; startpunkten \"%s\" är inte en gren"
+"kan inte ställa in spÃ¥rningsinformation; startpunkten â€%s†är inte en gren"
#, c-format
msgid "the requested upstream branch '%s' does not exist"
-msgstr "den efterfrågade uppströmsgrenen \"%s\" finns inte"
+msgstr "den efterfrÃ¥gade uppströmsgrenen â€%s†finns inte"
msgid ""
"\n"
@@ -1715,81 +1758,71 @@ msgid ""
msgstr ""
"\n"
"Om du har tänkt basera ditt arbete på en uppströmsgren\n"
-"som redan finns på fjärren kan du behöva köra \"git fetch\"\n"
+"som redan finns pÃ¥ fjärren kan du behöva köra â€git fetchâ€\n"
"för att hämta den.\n"
"\n"
"Om du har tänkt sända in en ny lokal gren som ska\n"
-"spåra dess fjärrmotsvarighet kan du använda \"git push -u\"\n"
+"spÃ¥ra dess fjärrmotsvarighet kan du använda â€git push -uâ€\n"
"för att ställa in uppströmskonfigurationen när du sänder in."
#, c-format
msgid "not a valid object name: '%s'"
-msgstr "objektnamnet är inte giltigt: \"%s\""
+msgstr "objektnamnet är inte giltigt: â€%sâ€"
#, c-format
msgid "ambiguous object name: '%s'"
-msgstr "objektnamnet är tvetydigt: \"%s\""
+msgstr "objektnamnet är tvetydigt: â€%sâ€"
#, c-format
msgid "not a valid branch point: '%s'"
-msgstr "avgreningspunkten är inte giltig: \"%s\""
+msgstr "avgreningspunkten är inte giltig: â€%sâ€"
#, c-format
msgid "submodule '%s': unable to find submodule"
-msgstr "undermodulen \"%s\": kan inte hitta undermodulen"
+msgstr "undermodulen â€%sâ€: kan inte hitta undermodulen"
#, c-format
msgid ""
"You may try updating the submodules using 'git checkout --no-recurse-"
"submodules %s && git submodule update --init'"
msgstr ""
-"Du kan försöka uppdatera undermodulerna med \"git checkout --no-recurse-"
-"submodules %s && git submodule update --init\""
+"Du kan försöka uppdatera undermodulerna med â€git checkout --no-recurse-"
+"submodules %s && git submodule update --initâ€"
#, c-format
msgid "submodule '%s': cannot create branch '%s'"
-msgstr "undermodulen \"%s\": kan inte skapa grenen \"%s\""
+msgstr "undermodulen â€%sâ€: kan inte skapa grenen â€%sâ€"
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "\"%s\" är redan utcheckad på \"%s\""
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "â€%s†används redan av arbetskatalogen â€%sâ€"
msgid "git add [<options>] [--] <pathspec>..."
msgstr "git add [<flaggor>] [--] <sökväg>..."
#, c-format
msgid "cannot chmod %cx '%s'"
-msgstr "kan inte utföra chmod %cx \"%s\""
+msgstr "kan inte utföra chmod %cx â€%sâ€"
msgid "Unstaged changes after refreshing the index:"
msgstr "Oköade ändringar efter att ha uppdaterat indexet:"
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"inställningen add.interactive.useBuiltin har tagits bort!\n"
-"Se dess post i \"git help config\" för detaljer."
-
-msgid "Could not read the index"
-msgstr "Kunde inte läsa indexet"
-
-msgid "Could not write patch"
-msgstr "Kunde inte skriva patch"
+msgid "could not read the index"
+msgstr "kunde inte läsa indexet"
msgid "editing patch failed"
msgstr "redigering av patch misslyckades"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Kunde inte ta status på \"%s\""
+msgid "could not stat '%s'"
+msgstr "kunde inte ta status pÃ¥ â€%sâ€"
-msgid "Empty patch. Aborted."
-msgstr "Tom patch. Avbryter."
+msgid "empty patch. aborted"
+msgstr "tom patch. avbryter"
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Kunde inte tillämpa \"%s\""
+msgid "could not apply '%s'"
+msgstr "kunde inte tillämpa â€%sâ€"
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\n"
@@ -1837,7 +1870,7 @@ msgid "check if - even missing - files are ignored in dry run"
msgstr "se om - även saknade - filer ignoreras i testkörning"
msgid "allow updating entries outside of the sparse-checkout cone"
-msgstr "tillåt uppdatera poster utanför området angivet i \"sparse-checkout\""
+msgstr "tillÃ¥t uppdatera poster utanför omrÃ¥det angivet i â€sparse-checkoutâ€"
msgid "override the executable bit of the listed files"
msgstr "överstyr exekveringsbiten för angivna filer"
@@ -1873,59 +1906,50 @@ msgstr ""
"\n"
"\tgit rm --cached %s\n"
"\n"
-"Se \"git help submodule\" för ytterligare information."
+"Se â€git help submodule†för ytterligare information."
#, c-format
msgid "adding embedded git repository: %s"
msgstr "lägger till inbäddat git-arkiv: %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 ""
-"Använd -f om du verkligen vill lägga till dem.\n"
-"Slå av detta meddelande med\n"
-"\"git config advice.addIgnoredFile false\""
+msgid "Use -f if you really want to add them."
+msgstr "Använd -f om du verkligen vill lägga till dem."
msgid "adding files failed"
msgstr "misslyckades lägga till filer"
#, c-format
msgid "--chmod param '%s' must be either -x or +x"
-msgstr "\"--chmod\"-parametern \"%s\" måste antingen vara -x eller +x"
+msgstr "â€--chmodâ€-parametern â€%s†mÃ¥ste antingen vara -x eller +x"
#, c-format
msgid "'%s' and pathspec arguments cannot be used together"
-msgstr "\"%s\" kan inte användas tillsammans med sökvägsangivelser"
+msgstr "â€%s†kan inte användas tillsammans med sökvägsangivelser"
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "Inget angivet, inget tillagt.\n"
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Tänkte du kanske säga \"git add .\"?\n"
-"Slå av detta meddelande genom att köra\n"
-"\"git config advice.addEmptyPathspec false\""
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Tänkte du kanske säga â€git add .â€?"
msgid "index file corrupt"
msgstr "indexfilen trasig"
+msgid "unable to write new index file"
+msgstr "kan inte skriva ny indexfil"
+
#, c-format
msgid "bad action '%s' for '%s'"
-msgstr "felaktig funktion \"%s\" för \"%s\""
+msgstr "felaktig funktion â€%s†för â€%sâ€"
#, c-format
msgid "invalid value for '%s': '%s'"
-msgstr "felaktigt värde för \"%s\": \"%s\""
+msgstr "felaktigt värde för â€%sâ€: â€%sâ€"
#, c-format
msgid "could not read '%s'"
-msgstr "kunde inte läsa \"%s\""
+msgstr "kunde inte läsa â€%sâ€"
msgid "could not parse author script"
msgstr "kunde inte tolka författarskript"
@@ -1936,30 +1960,30 @@ msgstr "kunde inte tolka %s"
#, c-format
msgid "'%s' was deleted by the applypatch-msg hook"
-msgstr "\"%s\" togs bort av kroken applypatch-msg"
+msgstr "â€%s†togs bort av kroken applypatch-msg"
#, c-format
msgid "Malformed input line: '%s'."
-msgstr "Felaktig indatarad: \"%s\"."
+msgstr "Felaktig indatarad: â€%sâ€."
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
-msgstr "Misslyckades kopiera anteckningar från \"%s\" till \"%s\""
+msgstr "Misslyckades kopiera anteckningar frÃ¥n â€%s†till â€%sâ€"
msgid "fseek failed"
-msgstr "\"fseek\" misslyckades"
+msgstr "â€fseek†misslyckades"
#, c-format
msgid "could not open '%s' for reading"
-msgstr "kunde inte öppna \"%s\" för läsning"
+msgstr "kunde inte öppna â€%s†för läsning"
#, c-format
msgid "could not open '%s' for writing"
-msgstr "kunde inte öppna \"%s\" för skrivning"
+msgstr "kunde inte öppna â€%s†för skrivning"
#, c-format
msgid "could not parse patch '%s'"
-msgstr "kunde inte tolka patchen \"%s\""
+msgstr "kunde inte tolka patchen â€%sâ€"
msgid "Only one StGIT patch series can be applied at once"
msgstr "Endast en StGIT-patchserie kan tillämpas åt gången"
@@ -1968,7 +1992,7 @@ msgid "invalid timestamp"
msgstr "ogiltig tidsstämpel"
msgid "invalid Date line"
-msgstr "ogiltig \"Date\"-rad"
+msgstr "ogiltig â€Dateâ€-rad"
msgid "invalid timezone offset"
msgstr "ogiltig tidszons-offset"
@@ -1978,29 +2002,30 @@ msgstr "Misslyckades detektera patchformat."
#, c-format
msgid "failed to create directory '%s'"
-msgstr "misslyckades skapa katalogen \"%s\""
+msgstr "misslyckades skapa katalogen â€%sâ€"
msgid "Failed to split patches."
msgstr "Misslyckades dela patchar."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "När du har löst problemet, kör \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "När du har löst problemet, kör â€%s --continueâ€.\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "Om du hellre vill hoppa över patchen, kör \"%s --skip\" i stället."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr "Om du hellre vill hoppa över patchen, kör â€%s --skip†i stället.\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
-"För att registrera den tomma patchen som en tom incheckning, kör \"%s --"
-"allow-empty\"."
+"För att registrera den tomma patchen som en tom incheckning, kör â€%s --allow-"
+"emptyâ€.\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
msgstr ""
-"För att återgå till ursprunglig gren och sluta patcha, kör \"%s --abort\"."
+"För att Ã¥tergÃ¥ till ursprunglig gren och sluta patcha, kör â€%s --abortâ€."
msgid "Patch sent with format=flowed; space at the end of lines might be lost."
msgstr ""
@@ -2008,7 +2033,7 @@ msgstr ""
#, c-format
msgid "missing author line in commit %s"
-msgstr "saknad \"author\"-rad i incheckningen %s"
+msgstr "saknad â€authorâ€-rad i incheckningen %s"
#, c-format
msgid "invalid ident line: %.*s"
@@ -2016,7 +2041,7 @@ msgstr "ogiltig ident-rad: %.*s"
#, c-format
msgid "unable to parse commit %s"
-msgstr "kunde inte tolka incheckningen %s"
+msgstr "kan inte tolka incheckningen %s"
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr ""
@@ -2047,7 +2072,7 @@ msgid "applying to an empty history"
msgstr "tillämpar på en tom historik"
msgid "failed to write commit object"
-msgstr "kunde inte skriva incheckningsobjekt"
+msgstr "misslyckades skriva incheckningsobjekt"
#, c-format
msgid "cannot resume: %s does not exist."
@@ -2095,8 +2120,7 @@ msgstr "Patch misslyckades på %s %.*s"
msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
msgstr ""
-"Använd \"git am --show-current-patch=diff\" för att se patchen som "
-"misslyckades"
+"Använd â€git am --show-current-patch=diff†för att se patchen som misslyckades"
msgid "No changes - recorded it as an empty commit."
msgstr "Inga ändringar - sparat som en tom incheckning."
@@ -2106,7 +2130,7 @@ msgid ""
"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 ""
-"Inga ändringar - glömde du att använda \"git add\"?\n"
+"Inga ändringar - glömde du att använda â€git addâ€?\n"
"Om det inte är något kvar att köa kan det hända att något annat redan\n"
"introducerat samma ändringar; kanske du bör hoppa över patchen."
@@ -2117,16 +2141,13 @@ msgid ""
"You might run `git rm` on a file to accept \"deleted by them\" for it."
msgstr ""
"Du har fortfarande ej sammanslagna sökvägar i indexet.\n"
-"Du bör köra \"git add\" på filer med lösta konflikter för att ange dem som "
+"Du bör köra â€git add†pÃ¥ filer med lösta konflikter för att ange dem som "
"lösta.\n"
-"Du kan köra \"git rm\" för att godta \"borttagen av dem\" för den."
-
-msgid "unable to write new index file"
-msgstr "kunde inte skriva ny indexfil"
+"Du kan köra â€git rm†för att godta â€borttagen av dem†för den."
#, c-format
msgid "Could not parse object '%s'."
-msgstr "Kan inte tolka objektet \"%s\"."
+msgstr "Kan inte tolka objektet â€%sâ€."
msgid "failed to clean index"
msgstr "misslyckades städa upp indexet"
@@ -2135,16 +2156,12 @@ msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
msgstr ""
-"Du verkar ha flyttat HEAD sedan \"am\" sist misslyckades.\n"
+"Du verkar ha flyttat HEAD sedan â€am†sist misslyckades.\n"
"Återställer inte till ORIG_HEAD"
#, c-format
msgid "failed to read '%s'"
-msgstr "misslyckades läsa \"%s\""
-
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "flaggorna \"%s=%s\" och \"%s=%s\" kan inte användas samtidigt"
+msgstr "misslyckades läsa â€%sâ€"
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<flaggor>] [(<mbox> | <Maildir>)...]"
@@ -2168,7 +2185,7 @@ msgid "be quiet"
msgstr "var tyst"
msgid "add a Signed-off-by trailer to the commit message"
-msgstr "lägg till \"Signed-off-by\"-släprad i incheckningsmeddelandet"
+msgstr "lägg till â€Signed-off-byâ€-släprad i incheckningsmeddelandet"
msgid "recode into utf8 (default)"
msgstr "koda om till utf8 (standard)"
@@ -2224,6 +2241,9 @@ msgstr "avbryt patchningen men behåll HEAD där det är"
msgid "show the patch being applied"
msgstr "visa patchen som tillämpas"
+msgid "try to apply current patch again"
+msgstr "försök applicera aktuell patch på nytt"
+
msgid "record the empty patch as an empty commit"
msgstr "lagra den tomma patchen som en tom incheckning"
@@ -2265,7 +2285,7 @@ msgid ""
"Use \"git am --abort\" to remove it."
msgstr ""
"Kvarbliven katalog %s hittades.\n"
-"Använd \"git am --abort\" för att ta bort den."
+"Använd â€git am --abort†för att ta bort den."
msgid "Resolve operation not in progress, we are not resuming."
msgstr "Lösningsoperation pågår inte, vi återupptar inte."
@@ -2279,9 +2299,6 @@ msgstr "git apply [<flaggor>] [<patch>...]"
msgid "could not redirect output"
msgstr "kunde inte omdirigera utdata"
-msgid "git archive: Remote with no URL"
-msgstr "git archive: Fjärr utan URL"
-
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive: förväntade ACK/NAK, fick flush-paket"
@@ -2296,10 +2313,10 @@ msgid "git archive: expected a flush"
msgstr "git archive: förväntade en tömning (flush)"
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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> --term-{old,good}=<term>] [--no-"
+"git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>] [--no-"
"checkout] [--first-parent] [<dålig> [<bra>...]] [--] [<sökvägar>...]"
msgid "git bisect (good|bad) [<rev>...]"
@@ -2314,32 +2331,32 @@ msgstr "git bisect reset [<incheckning>]"
msgid "git bisect replay <logfile>"
msgstr "git bisect replay <loggfil>"
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <kommando>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <kommando> [<argument>]..."
#, c-format
msgid "cannot open file '%s' in mode '%s'"
-msgstr "kan inte kopiera filen \"%s\" i läget \"%s\""
+msgstr "kan inte kopiera filen â€%s†i läget â€%sâ€"
#, c-format
msgid "could not write to file '%s'"
-msgstr "kunde inte skriva till filen \"%s\""
+msgstr "kunde inte skriva till filen â€%sâ€"
#, c-format
msgid "cannot open file '%s' for reading"
-msgstr "kan inte öppna filen \"%s\" för läsning"
+msgstr "kan inte öppna filen â€%s†för läsning"
#, c-format
msgid "'%s' is not a valid term"
-msgstr "\"%s\" är inte en giltig term"
+msgstr "â€%s†är inte en giltig term"
#, c-format
msgid "can't use the builtin command '%s' as a term"
-msgstr "kan inte använda det inbyggda kommandot \"%s\" som term"
+msgstr "kan inte använda det inbyggda kommandot â€%s†som term"
#, c-format
msgid "can't change the meaning of the term '%s'"
-msgstr "kan inte ändra betydelsen av termen \"%s\""
+msgstr "kan inte ändra betydelsen av termen â€%sâ€"
msgid "please use two different terms"
msgstr "termerna måste vara olika"
@@ -2350,14 +2367,14 @@ msgstr "Vi utför ingen bisect för tillfället.\n"
#, c-format
msgid "'%s' is not a valid commit"
-msgstr "\"%s\" är inte en giltig incheckning"
+msgstr "â€%s†är inte en giltig incheckning"
#, c-format
msgid ""
"could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
msgstr ""
-"Kunde inte checka ut original-HEAD \"%s\". Försök \"git bisect reset "
-"<incheckning>\"."
+"kan inte checka ut original-HEAD â€%sâ€. Försök â€git bisect reset "
+"<incheckning>â€."
#, c-format
msgid "Bad bisect_write argument: %s"
@@ -2365,15 +2382,15 @@ msgstr "Felaktigt argument till bisect_write: %s"
#, c-format
msgid "couldn't get the oid of the rev '%s'"
-msgstr "kan inte läsa oid för referensen \"%s\""
+msgstr "kan inte läsa oid för referensen â€%sâ€"
#, c-format
msgid "couldn't open the file '%s'"
-msgstr "kunde inte öppna filen \"%s\""
+msgstr "kunde inte öppna filen â€%sâ€"
#, c-format
msgid "Invalid command: you're currently in a %s/%s bisect"
-msgstr "Ogiltigt kommando: du utför just nu en \"bisect\" med %s/%s."
+msgstr "Ogiltigt kommando: du utför just nu en â€bisect†med %s/%s."
#, c-format
msgid ""
@@ -2381,7 +2398,7 @@ msgid ""
"You can use \"git bisect %s\" and \"git bisect %s\" for that."
msgstr ""
"Du måste ange åtminstone en %s och en %s version.\n"
-"(Du kan använda \"git bisect %s\" och \"git bisect %s\" för detta.)"
+"(Du kan använda â€git bisect %s†och â€git bisect %s†för detta.)"
#, c-format
msgid ""
@@ -2389,9 +2406,9 @@ msgid ""
"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 ""
-"Du måste starta med \"git bisect start\".\n"
+"Du mÃ¥ste starta med â€git bisect startâ€.\n"
"Du måste sedan ange åtminstone en %s och en %s version.\n"
-"(Du kan använda \"git bisect %s\" och \"git bisect %s\" för detta.)"
+"(Du kan använda â€git bisect %s†och â€git bisect %s†för detta.)"
#, c-format
msgid "bisecting only with a %s commit"
@@ -2432,18 +2449,15 @@ msgid ""
"invalid argument %s for 'git bisect terms'.\n"
"Supported options are: --term-good|--term-old and --term-bad|--term-new."
msgstr ""
-"ogiltigt argument %s för \"git bisect terms\".\n"
+"ogiltigt argument %s för â€git bisect termsâ€.\n"
"Flaggor som stöds är: --term-good|--term-old och --term-bad|--term-new."
-msgid "revision walk setup failed\n"
-msgstr "misslyckades starta revisionstraversering\n"
-
#, c-format
msgid "could not open '%s' for appending"
-msgstr "kunde inte öppna \"%s\" för tillägg"
+msgstr "kunde inte öppna â€%s†för tillägg"
msgid "'' is not a valid term"
-msgstr "\"\" är inte en giltig term"
+msgstr "â€â€ är inte en giltig term"
#, c-format
msgid "unrecognized option: '%s'"
@@ -2451,25 +2465,24 @@ msgstr "okänd flagga: %s"
#, c-format
msgid "'%s' does not appear to be a valid revision"
-msgstr "\"%s\" verkar inte vara en giltig revision"
+msgstr "â€%s†verkar inte vara en giltig revision"
msgid "bad HEAD - I need a HEAD"
msgstr "felaktigt HEAD - Jag behöver ett HEAD"
#, c-format
msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
-msgstr ""
-"misslyckades checka ut \"%s\". Försök \"git bisect reset <giltig_gren>\"."
+msgstr "misslyckades checka ut â€%sâ€. Försök â€git bisect reset <giltig_gren>â€."
msgid "bad HEAD - strange symbolic ref"
msgstr "felaktigt HEAD - konstig symbolisk referens"
#, c-format
msgid "invalid ref: '%s'"
-msgstr "ogiltig referens: \"%s\""
+msgstr "ogiltig referens: â€%sâ€"
msgid "You need to start by \"git bisect start\"\n"
-msgstr "Du måste starta med \"git bisect start\"\n"
+msgstr "Du mÃ¥ste starta med â€git bisect startâ€\n"
#. TRANSLATORS: Make sure to include [Y] and [n] in your
#. translation. The program will only accept English input
@@ -2479,11 +2492,11 @@ msgid "Do you want me to do it for you [Y/n]? "
msgstr "Vill du att jag ska göra det åt dig [Y=ja/N=nej]? "
msgid "Please call `--bisect-state` with at least one argument"
-msgstr "Anropa \"--bisect-state\" med minst ett argument."
+msgstr "Anropa â€--bisect-state†med minst ett argument."
#, c-format
msgid "'git bisect %s' can take only one argument."
-msgstr "\"git bisect %s\" kan bara ta ett argument."
+msgstr "â€git bisect %s†kan bara ta ett argument."
#, c-format
msgid "Bad rev input: %s"
@@ -2498,11 +2511,11 @@ msgstr "Vi utför ingen bisect för tillfället."
#, c-format
msgid "'%s'?? what are you talking about?"
-msgstr "\"%s\"?? vad menar du?"
+msgstr "â€%sâ€?? vad menar du?"
#, c-format
msgid "cannot read file '%s' for replaying"
-msgstr "kan inte läsa filen \"%s\" för återuppspelning"
+msgstr "kan inte läsa filen â€%s†för Ã¥teruppspelning"
#, c-format
msgid "running %s\n"
@@ -2521,18 +2534,17 @@ msgstr "falsk slutkod %d för bra revision"
#, c-format
msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
-msgstr ""
-"\"bisect\"-körningen misslyckades: felkod %d från %s är < 0 eller >= 128"
+msgstr "â€bisectâ€-körningen misslyckades: felkod %d frÃ¥n %s är < 0 eller >= 128"
#, c-format
msgid "cannot open file '%s' for writing"
-msgstr "kan inte öppna \"%s\" för skrivning"
+msgstr "kan inte öppna â€%s†för skrivning"
msgid "bisect run cannot continue any more"
-msgstr "\"bisect\"-körningen kan inte fortsätta längre"
+msgstr "â€bisectâ€-körningen kan inte fortsätta längre"
msgid "bisect run success"
-msgstr "\"bisect\"-körningen lyckades"
+msgstr "â€bisectâ€-körningen lyckades"
msgid "bisect found first bad commit"
msgstr "bisect hittade första trasiga incheckning"
@@ -2540,34 +2552,33 @@ msgstr "bisect hittade första trasiga incheckning"
#, c-format
msgid "bisect run failed: 'git bisect %s' exited with error code %d"
msgstr ""
-"\"bisect\"-körningen misslyckades: \"git bisect %s\" avslutades med felkoden "
-"%d"
+"â€bisectâ€-körningen misslyckades: â€git bisect %s†avslutades med felkoden %d"
#, c-format
msgid "'%s' requires either no argument or a commit"
-msgstr "\"%s\" kräver antingen inget argument eller en incheckning"
+msgstr "â€%s†kräver antingen inget argument eller en incheckning"
#, c-format
msgid "'%s' requires 0 or 1 argument"
-msgstr "\"%s\" kräver noll eller ett argument"
+msgstr "â€%s†kräver noll eller ett argument"
#, c-format
msgid "'%s' requires 0 arguments"
-msgstr "\"%s\" kräver noll argument"
+msgstr "â€%s†kräver noll argument"
msgid "no logfile given"
msgstr "ingen loggfil angiven"
#, c-format
msgid "'%s' failed: no command provided."
-msgstr "\"%s\" misslyckades: inget kommando gavs."
+msgstr "â€%s†misslyckades: inget kommando gavs."
msgid "need a command"
msgstr "behöver ett kommando"
#, c-format
msgid "unknown command: '%s'"
-msgstr "okänt kommando: \"%s\""
+msgstr "okänt kommando: â€%sâ€"
msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
msgstr "git blame [<flaggor>] [<rev-flaggor>] [<rev>] [--] <fil>"
@@ -2596,7 +2607,7 @@ msgid "do not show object names of boundary commits (Default: off)"
msgstr "visa inte objektnamn för gränsincheckningar (Standard: av)"
msgid "do not treat root commits as boundaries (Default: off)"
-msgstr "vehandla inte rotincheckningar som gränser (Standard: av)"
+msgstr "behandla inte rotincheckningar som gränser (Standard: av)"
msgid "show work cost statistics"
msgstr "visa statistik över arbetskostnad"
@@ -2730,56 +2741,56 @@ msgstr "git branch [<flaggor>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
-"tar bort grenen \"%s\" som har slagits ihop med\n"
-" \"%s\", men ännu inte slagits ihop med HEAD."
+"tar bort grenen â€%s†som har slagits ihop med\n"
+" â€%sâ€, men ännu inte slagits ihop med HEAD"
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
-"tar inte bort grenen \"%s\" som inte har slagits ihop med\n"
-" \"%s\", trots att den har slagits ihop med HEAD."
+"tar inte bort grenen â€%s†som inte har slagits ihop med\n"
+" â€%sâ€, trots att den har slagits ihop med HEAD"
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\""
+msgid "couldn't look up commit object for '%s'"
+msgstr "kunde inte slÃ¥ upp incheckningsobjekt för â€%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 ""
-"Grenen \"%s\" har inte slagits samman i sin helhet.\n"
-"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"."
+msgid "the branch '%s' is not fully merged"
+msgstr "grenen â€%s†har inte slagits samman i sin helhet"
-msgid "Update of config-file failed"
-msgstr "Misslyckades uppdatera konfigurationsfil"
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "Om du är säker pÃ¥ att du vill ta bort den, kör â€git branch -D %sâ€"
+
+msgid "update of config-file failed"
+msgstr "misslyckades uppdatera konfigurationsfil"
msgid "cannot use -a with -d"
msgstr "kan inte ange -a med -d"
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "Kan inte ta bort grenen \"%s\" som är utcheckad på \"%s\""
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr "kan inte ta bort grenen â€%s†som används av arbetskatalogen pÃ¥ â€%sâ€"
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "fjärrspårande grenen \"%s\" hittades inte."
+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"
+"grenen â€%s†hittades inte.\n"
"Glömde du --remote?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "grenen \"%s\" hittades inte."
+msgid "branch '%s' not found"
+msgstr "grenen â€%s†hittades inte"
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -2800,62 +2811,62 @@ msgid "HEAD (%s) points outside of refs/heads/"
msgstr "HEAD (%s) pekar utenför refs/heads/"
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "Grenen %s ombaseras på %s"
+msgid "branch %s is being rebased at %s"
+msgstr "grenen %s ombaseras på %s"
#, c-format
-msgid "Branch %s is being bisected at %s"
-msgstr "Grenen %s är i en \"bisect\" 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\""
+msgid "invalid branch name: '%s'"
+msgstr "gelaktigt namn pÃ¥ gren: â€%sâ€"
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Inga incheckningar på grenen \"%s\" ännu."
+msgid "no commit on branch '%s' yet"
+msgstr "inga incheckningar pÃ¥ grenen â€%s†ännu"
#, c-format
-msgid "No branch named '%s'."
-msgstr "Ingen gren vid namnet \"%s\"."
+msgid "no branch named '%s'"
+msgstr "ingen gren vid namnet â€%sâ€"
-msgid "Branch rename failed"
-msgstr "Misslyckades byta namn på gren"
+msgid "branch rename failed"
+msgstr "misslyckades byta namn på gren"
-msgid "Branch copy failed"
-msgstr "Misslyckades kopiera gren"
+msgid "branch copy failed"
+msgstr "misslyckades kopiera gren"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Skapade kopia av felaktigt namngiven gren \"%s\""
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "skapade kopia av felaktigt namngiven gren â€%sâ€"
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\""
+msgid "renamed a misnamed branch '%s' away"
+msgstr "bytte bort namn pÃ¥ en felaktigt namngiven gren â€%sâ€"
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "Grenen namnbytt till %s, men HEAD har inte uppdaterats!"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "grenen namnbytt till %s, men HEAD har inte uppdaterats"
-msgid "Branch is renamed, but update of config-file failed"
-msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
+msgid "branch is renamed, but update of config-file failed"
+msgstr "grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
-msgid "Branch is copied, but update of config-file failed"
-msgstr "Grenen kopierades, men misslyckades uppdatera konfigurationsfilen"
+msgid "branch is copied, but update of config-file failed"
+msgstr "grenen kopierades, men misslyckades uppdatera konfigurationsfilen"
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Redigera beskrivningen för grenen\n"
" %s\n"
-"Rader som inleds med \"%c\" ignoreras.\n"
+"Rader som inleds med â€%s†ignoreras.\n"
msgid "Generic options"
msgstr "Allmänna flaggor"
@@ -2959,8 +2970,8 @@ msgstr "rekursera ner i undermoduler"
msgid "format to use for the output"
msgstr "format att använda för utdata"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Misslyckades slå upp HEAD som giltig referens."
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "misslyckades slå upp HEAD som giltig referens"
msgid "HEAD not found below refs/heads!"
msgstr "HEAD hittades inte under refs/heads!"
@@ -2978,18 +2989,17 @@ msgstr "--recurse-submodules kan endast användas för att skapa grenar"
msgid "branch name required"
msgstr "grennamn krävs"
-msgid "Cannot give description to detached HEAD"
-msgstr "Kan inte beskriva frånkopplad HEAD"
+msgid "cannot give description to detached HEAD"
+msgstr "kan inte beskriva frånkopplad HEAD"
msgid "cannot edit description of more than one branch"
msgstr "kan inte redigera beskrivning för mer än en gren"
-msgid "cannot copy the current branch while not on any."
-msgstr "kunde inte kopiera aktuell gren när du inte befinner dig på någon."
+msgid "cannot copy the current branch while not on any"
+msgstr "kunde inte kopiera aktuell gren när du inte befinner dig på någon"
-msgid "cannot rename the current branch while not on any."
-msgstr ""
-"kunde inte byta namn på aktuell gren när du inte befinner dig på någon."
+msgid "cannot rename the current branch while not on any"
+msgstr "kunde inte byta namn på aktuell gren när du inte befinner dig på någon"
msgid "too many branches for a copy operation"
msgstr "för många grenar för kopiering"
@@ -3002,49 +3012,48 @@ msgstr "för många flaggor för att byta uppström"
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
-"kunde inte sätta uppström för HEAD till %s när det inte pekar mot någon gren."
+"kunde inte sätta uppström för HEAD till %s när det inte pekar mot någon gren"
#, c-format
msgid "no such branch '%s'"
-msgstr "okänd gren \"%s\""
+msgstr "okänd gren â€%sâ€"
#, c-format
msgid "branch '%s' does not exist"
-msgstr "grenen \"%s\" finns inte"
+msgstr "grenen â€%s†finns inte"
msgid "too many arguments to unset upstream"
msgstr "för många flaggor för att ta bort uppström"
-msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr ""
-"kunde inte ta bort uppström för HEAD när det inte pekar mot någon gren."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
+msgstr "kunde inte ta bort uppström för HEAD när det inte pekar mot någon gren"
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "Grenen \"%s\" har ingen uppströmsinformation"
+msgid "branch '%s' has no upstream information"
+msgstr "grenen â€%s†har ingen uppströmsinformation"
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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 ""
-"Flaggorna -a och -r på \"git branch\" tar inte ett namn på gren.\n"
+"flaggorna -a och -r pÃ¥ â€git branch†tar inte ett namn pÃ¥ gren.\n"
"Menade du att använda: -a|-r --list <mönster>?"
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
-"Flaggan --set-upstream rekommenderas ej och kommer tas bort. Använd --track "
-"eller --set-upstream-to istället."
+"flaggan â€--set-upstream†rekommenderas ej och kommer tas bort. Använd â€--"
+"track†eller â€--set-upstream-to†istället"
msgid "git version:\n"
msgstr "git version:\n"
#, c-format
msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() misslyckades med felet \"%s\" (%d)\n"
+msgstr "uname() misslyckades med felet â€%s†(%d)\n"
msgid "compiler info: "
msgstr "kompilatorinfo:"
@@ -3056,11 +3065,13 @@ msgid "not run from a git repository - no hooks to show\n"
msgstr "körs inte från ett git-arkiv - inga krokar att visa\n"
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <fil>] [(-s | --suffix) <format>]\n"
-" [--diagnose[=<läge>]"
+"git bugreport [(-o | --output-directory) <sökväg>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
+" [--diagnose[=<läge>]]"
msgid ""
"Thank you for filling out a Git bug report!\n"
@@ -3103,8 +3114,7 @@ msgstr "läge"
msgid ""
"create an additional zip archive of detailed diagnostics (default 'stats')"
msgstr ""
-"skapa ett ytterligare zip-arkiv med detaljerad diagnostik (förval är \"stats"
-"\")"
+"skapa ett ytterligare zip-arkiv med detaljerad diagnostik (förval är â€statsâ€)"
msgid "specify a destination for the bugreport file(s)"
msgstr "ange mål för buggrapporteringsfilen/-rna"
@@ -3113,12 +3123,16 @@ msgid "specify a strftime format suffix for the filename(s)"
msgstr "ange filändelse i strftime-format"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "okänt argument â€%sâ€"
+
+#, c-format
msgid "could not create leading directories for '%s'"
-msgstr "kunde inte skapa inledande kataloger för \"%s\""
+msgstr "kunde inte skapa inledande kataloger för â€%sâ€"
#, c-format
msgid "unable to create diagnostics archive %s"
-msgstr "kunde inte skapa diagnostikarkiven %s"
+msgstr "kan inte skapa diagnostikarkiven %s"
msgid "System Info"
msgstr "Systeminfo"
@@ -3128,11 +3142,11 @@ msgstr "Aktiverade krokar"
#, c-format
msgid "unable to write to %s"
-msgstr "kunde inte skriva till %s"
+msgstr "kan inte skriva till %s"
#, c-format
msgid "Created new report at '%s'.\n"
-msgstr "Skapade ny rapport på \"%s\"\n"
+msgstr "Skapade ny rapport pÃ¥ â€%sâ€\n"
msgid ""
"git bundle create [-q | --quiet | --progress]\n"
@@ -3174,6 +3188,9 @@ msgstr "Behöver ett arkiv för att skapa en bunt."
msgid "do not show bundle details"
msgstr "visa inte buntdetaljer"
+msgid "need a repository to verify a bundle"
+msgstr "behöver ett arkiv för att bekräfta en bunt."
+
#, c-format
msgid "%s is okay\n"
msgstr "%s är okej\n"
@@ -3186,17 +3203,17 @@ msgstr "Packar upp objektbunt"
#, c-format
msgid "cannot read object %s '%s'"
-msgstr "kan inte läsa objektet %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"
#, c-format
msgid "whitespace before command: '%s'"
-msgstr "blanksteg före kommando: \"%s\""
+msgstr "blanksteg före kommando: â€%sâ€"
#, c-format
msgid "%s requires arguments"
@@ -3219,6 +3236,14 @@ msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <objekt>"
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<revision>:<sökväg|träd-igt> | --path=<sökväg|träd-igt> "
+"<revision>]"
+
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -3229,14 +3254,6 @@ msgstr ""
" [--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"
-" [<revision>:<sökväg|träd-igt> | --path=<sökväg|träd-igt> "
-"<revision>]"
-
msgid "Check object existence or emit object contents"
msgstr "Kontrollera om objektet finns eller mata ut objektets innehåll"
@@ -3250,7 +3267,7 @@ msgid "Emit [broken] object attributes"
msgstr "Skriv ut [trasiga] objektattribut"
msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
-msgstr "visa objekttyp (en av: \"blob\", \"tree\", \"commit\", \"tag\", ...)"
+msgstr "visa objekttyp (en av: â€blobâ€, â€treeâ€, â€commitâ€, â€tagâ€, ...)"
msgid "show object size"
msgstr "visa objektstorlek"
@@ -3322,22 +3339,22 @@ msgstr "sökväg|träd-igt"
#, c-format
msgid "'%s' requires a batch mode"
-msgstr "\"%s\" behöver ett buntläge"
+msgstr "â€%s†behöver ett buntläge"
#, c-format
msgid "'-%c' is incompatible with batch mode"
-msgstr "\"-%c\" är inkompatibel med buntläge"
+msgstr "â€-%c†är inkompatibel med buntläge"
msgid "batch modes take no arguments"
msgstr "buntlägen inte några argument"
#, c-format
msgid "<rev> required with '%s'"
-msgstr "<rev> krävs med \"%s\""
+msgstr "<rev> krävs med â€%sâ€"
#, c-format
msgid "<object> required with '-%c'"
-msgstr "<objekt> krävs med \"-%c\""
+msgstr "<objekt> krävs med â€-%câ€"
#, c-format
msgid "only two arguments allowed in <type> <object> mode, not %d"
@@ -3406,9 +3423,14 @@ msgstr "git check-mailmap [<flaggor>] <kontakt>..."
msgid "also read contacts from stdin"
msgstr "läs även kontakter från standard in"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "kunde inte tolka kontakt: %s"
+msgid "read additional mailmap entries from file"
+msgstr "läs ytterligare mailmap-poster från fil"
+
+msgid "blob"
+msgstr "blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "läs ytterligare mailmap-poster från blob"
msgid "no contacts specified"
msgstr "inga kontakter angavs"
@@ -3426,7 +3448,7 @@ msgid "git checkout-index [<options>] [--] [<file>...]"
msgstr "git checkout-index [<flaggor>] [--] [<fil>...]"
msgid "stage should be between 1 and 3 or all"
-msgstr "etapp måste vara mellan 1 och 3 eller \"all\""
+msgstr "etapp mÃ¥ste vara mellan 1 och 3 eller â€allâ€"
msgid "check out all files in the index"
msgstr "checka ut alla filer i indexet"
@@ -3469,27 +3491,27 @@ msgstr "git restore [<flaggor>] [--source=<gren>] <fil>..."
#, c-format
msgid "path '%s' does not have our version"
-msgstr "sökvägen \"%s\" har inte vår version"
+msgstr "sökvägen â€%s†har inte vÃ¥r version"
#, c-format
msgid "path '%s' does not have their version"
-msgstr "sökvägen \"%s\" har inte deras version"
+msgstr "sökvägen â€%s†har inte deras version"
#, c-format
msgid "path '%s' does not have all necessary versions"
-msgstr "sökvägen \"%s\" innehåller inte alla nödvändiga versioner"
+msgstr "sökvägen â€%s†innehÃ¥ller inte alla nödvändiga versioner"
#, c-format
msgid "path '%s' does not have necessary versions"
-msgstr "sökvägen \"%s\" innehåller inte nödvändiga versioner"
+msgstr "sökvägen â€%s†innehÃ¥ller inte nödvändiga versioner"
#, c-format
msgid "path '%s': cannot merge"
-msgstr "sökväg \"%s\": kan inte slå ihop"
+msgstr "sökväg â€%sâ€: kan inte slÃ¥ ihop"
#, c-format
msgid "Unable to add merge result for '%s'"
-msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\""
+msgstr "Kan inte lägga till sammanslagningsresultat för â€%sâ€"
#, c-format
msgid "Recreated %d merge conflict"
@@ -3511,27 +3533,35 @@ msgstr[1] "Uppdaterade %d sökvägar från indexet"
#, c-format
msgid "'%s' cannot be used with updating paths"
-msgstr "\"%s\" kan inte användas vid uppdatering av sökvägar"
+msgstr "â€%s†kan inte användas vid uppdatering av sökvägar"
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
-msgstr "Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt."
+msgstr "Kan inte uppdatera sökvägar och växla till grenen â€%s†samtidigt."
#, c-format
msgid "neither '%s' or '%s' is specified"
-msgstr "varken \"%s\" eller \"%s\" har angivits"
+msgstr "varken â€%s†eller â€%s†har angivits"
#, c-format
msgid "'%s' must be used when '%s' is not specified"
-msgstr "\"%s\" måste användas när \"%s\" inte anges"
+msgstr "â€%s†mÃ¥ste användas när â€%s†inte anges"
#, c-format
msgid "'%s' or '%s' cannot be used with %s"
-msgstr "\"%s\" eller \"%s\" kan inte användas med %s"
+msgstr "â€%s†eller â€%s†kan inte användas med %s"
+
+#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "â€%sâ€, â€%s†eller â€%s†kan inte användas när en katalog checkas ut"
#, c-format
msgid "path '%s' is unmerged"
-msgstr "sökvägen \"%s\" har inte slagits ihop"
+msgstr "sökvägen â€%s†har inte slagits ihop"
+
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "kan inte läsa träd (%s)"
msgid "you need to resolve your current index first"
msgstr "du måste lösa ditt befintliga index först"
@@ -3546,7 +3576,7 @@ msgstr ""
#, c-format
msgid "Can not do reflog for '%s': %s\n"
-msgstr "Kan inte skapa referenslogg för \"%s\": %s\n"
+msgstr "Kan inte skapa referenslogg för â€%sâ€: %s\n"
msgid "HEAD is now at"
msgstr "HEAD är nu på"
@@ -3556,23 +3586,23 @@ msgstr "kan inte uppdatera HEAD"
#, c-format
msgid "Reset branch '%s'\n"
-msgstr "Återställ gren \"%s\"\n"
+msgstr "Ã…terställ gren â€%sâ€\n"
#, c-format
msgid "Already on '%s'\n"
-msgstr "Redan på \"%s\"\n"
+msgstr "Redan pÃ¥ â€%sâ€\n"
#, c-format
msgid "Switched to and reset branch '%s'\n"
-msgstr "Växlade till och nollställde grenen \"%s\"\n"
+msgstr "Växlade till och nollställde grenen â€%sâ€\n"
#, c-format
msgid "Switched to a new branch '%s'\n"
-msgstr "Växlade till en ny gren \"%s\"\n"
+msgstr "Växlade till en ny gren â€%sâ€\n"
#, c-format
msgid "Switched to branch '%s'\n"
-msgstr "Växlade till grenen \"%s\"\n"
+msgstr "Växlade till grenen â€%sâ€\n"
#, c-format
msgid " ... and %d more.\n"
@@ -3640,7 +3670,7 @@ msgid ""
"'%s' could be both a local file and a tracking branch.\n"
"Please use -- (and optionally --no-guess) to disambiguate"
msgstr ""
-"\"%s\" kan vara både en lokal fil och en spårande gren.\n"
+"â€%s†kan vara bÃ¥de en lokal fil och en spÃ¥rande gren.\n"
"Använd -- (och möjligen --no-guess) för att göra otvetydig"
msgid ""
@@ -3653,18 +3683,18 @@ msgid ""
"one remote, e.g. the 'origin' remote, consider setting\n"
"checkout.defaultRemote=origin in your config."
msgstr ""
-"Om du menade checka ut en spårad fjärrgren på t.ex \"origin\", kan du\n"
+"Om du menade checka ut en spÃ¥rad fjärrgren pÃ¥ t.ex â€originâ€, kan du\n"
"göra det genom att ange hela namnet med flaggan --track:\n"
"\n"
" git checkout --track origin/<namn>\n"
"\n"
"Om du alltid vill att utcheckningar med tvetydiga <namn> ska\n"
-"föredra en fjärr, t.ex fjärren \"origin\" kan du ställa in\n"
+"föredra en fjärr, t.ex fjärren â€origin†kan du ställa in\n"
"checkout.defaultRemote=origin i din konfiguration."
#, c-format
msgid "'%s' matched multiple (%d) remote tracking branches"
-msgstr "\"%s\" motsvarar flera (%d) spårade fjärrgrenar"
+msgstr "â€%s†motsvarar flera (%d) spÃ¥rade fjärrgrenar"
msgid "only one reference expected"
msgstr "endast en referens förväntades"
@@ -3683,19 +3713,19 @@ msgstr "referensen är inte ett träd: %s"
#, c-format
msgid "a branch is expected, got tag '%s'"
-msgstr "förväntade gren, fick taggen \"%s\""
+msgstr "förväntade gren, fick taggen â€%sâ€"
#, c-format
msgid "a branch is expected, got remote branch '%s'"
-msgstr "förväntade gren, fick fjärrgrenen \"%s\""
+msgstr "förväntade gren, fick fjärrgrenen â€%sâ€"
#, c-format
msgid "a branch is expected, got '%s'"
-msgstr "förväntade gren, fick \"%s\""
+msgstr "förväntade gren, fick â€%sâ€"
#, c-format
msgid "a branch is expected, got commit '%s'"
-msgstr "förväntade gren, fick incheckningen \"%s\""
+msgstr "förväntade gren, fick incheckningen â€%sâ€"
msgid ""
"If you want to detach HEAD at the commit, try again with the --detach option."
@@ -3708,61 +3738,69 @@ msgid ""
"Consider \"git merge --quit\" or \"git worktree add\"."
msgstr ""
"kan inte växla gren vid sammanslagning\n"
-"Överväg \"git merge --quit\" eller \"git worktree add\"."
+"Överväg â€git merge --quit†eller â€git worktree addâ€."
msgid ""
"cannot switch branch in the middle of an am session\n"
"Consider \"git am --quit\" or \"git worktree add\"."
msgstr ""
-"kan inte växla gren mitt i en \"am\"-körning\n"
-"Överväg \"git am --quit\" eller \"git worktree add\"."
+"kan inte växla gren mitt i en â€amâ€-körning\n"
+"Överväg â€git am --quit†eller â€git worktree addâ€."
msgid ""
"cannot switch branch while rebasing\n"
"Consider \"git rebase --quit\" or \"git worktree add\"."
msgstr ""
"kan inte växla gren vid ombasering\n"
-"Överväg \"git rebase --quit\" eller \"git worktree add\"."
+"Överväg â€git rebase --quit†eller â€git worktree addâ€."
msgid ""
"cannot switch branch while cherry-picking\n"
"Consider \"git cherry-pick --quit\" or \"git worktree add\"."
msgstr ""
-"kan inte växla gren i en \"cherry-pick\"\n"
-"Överväg \"git cherry-pick --quit\" eller \"git worktree add\"."
+"kan inte växla gren i en â€cherry-pickâ€\n"
+"Överväg â€git cherry-pick --quit†eller â€git worktree addâ€."
msgid ""
"cannot switch branch while reverting\n"
"Consider \"git revert --quit\" or \"git worktree add\"."
msgstr ""
-"kan inte växla gren i en \"revert\"\n"
-"Överväg \"git revert --quit\" eller \"git worktree add\"."
+"kan inte växla gren i en â€revertâ€\n"
+"Överväg â€git revert --quit†eller â€git worktree addâ€."
msgid "you are switching branch while bisecting"
-msgstr "då växlar grenar medan du gör en \"bisect\""
+msgstr "dÃ¥ växlar grenar medan du gör en â€bisectâ€"
msgid "paths cannot be used with switching branches"
msgstr "sökvägar kan inte användas vid byte av gren"
#, c-format
msgid "'%s' cannot be used with switching branches"
-msgstr "\"%s\" kan inte användas vid byte av gren"
+msgstr "â€%s†kan inte användas vid byte av gren"
+
+#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "â€%s†behöver sökvägar att checka ut"
#, c-format
msgid "'%s' cannot be used with '%s'"
-msgstr "\"%s\" kan inte användas med \"%s\""
+msgstr "â€%s†kan inte användas med â€%sâ€"
#, c-format
msgid "'%s' cannot take <start-point>"
-msgstr "\"%s\" kan inte ta <startpunkt>"
+msgstr "â€%s†kan inte ta <startpunkt>"
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
-msgstr "Kan inte växla gren till icke-incheckningen \"%s\""
+msgstr "Kan inte växla gren till icke-incheckningen â€%sâ€"
msgid "missing branch or commit argument"
msgstr "saknar gren- eller incheckingsargument"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "okänd konflikttyp â€%sâ€"
+
msgid "perform a 3-way merge with the new branch"
msgstr "utför en 3-vägssammanslagning för den nya grenen"
@@ -3781,8 +3819,8 @@ msgstr "tvinga utcheckning (kasta bort lokala ändringar)"
msgid "new-branch"
msgstr "ny-gren"
-msgid "new unparented branch"
-msgstr "ny gren utan förälder"
+msgid "new unborn branch"
+msgstr "ny ofödd gren"
msgid "update ignored files (default)"
msgstr "uppdatera ignorerade filer (standard)"
@@ -3802,7 +3840,7 @@ msgstr "begränsa inte sökvägar till endast glesa poster"
#, c-format
msgid "options '-%c', '-%c', and '%s' cannot be used together"
-msgstr "flaggorna \"%-c\", \"-%c\" och \"%s\" kan inte användas samtidigt"
+msgstr "flaggorna â€%-câ€, â€-%c†och â€%s†kan inte användas samtidigt"
msgid "--track needs a branch name"
msgstr "--track behöver ett namn på en gren"
@@ -3820,12 +3858,11 @@ msgstr "felaktig sökvägsangivelse"
#, c-format
msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
-msgstr ""
-"\"%s\" är inte en incheckning och grenen \"%s\" kan inte skapas från den"
+msgstr "â€%s†är inte en incheckning och grenen â€%s†kan inte skapas frÃ¥n den"
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
-msgstr "git checkout: --detach tar inte en sökväg som argument \"%s\""
+msgstr "git checkout: --detach tar inte en sökväg som argument â€%sâ€"
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
@@ -3850,7 +3887,7 @@ msgid "create reflog for new branch"
msgstr "skapa reflogg för ny gren"
msgid "second guess 'git checkout <no-such-branch>' (default)"
-msgstr "förutspå \"git checkout <gren-saknas>\" (förval)"
+msgstr "förutspÃ¥ â€git checkout <gren-saknas>†(förval)"
msgid "use overlay mode (default)"
msgstr "använd överläggsläge (standard)"
@@ -3862,7 +3899,7 @@ msgid "create/reset and switch to a branch"
msgstr "skapa/nollställ och växla till en gren"
msgid "second guess 'git switch <no-such-branch>'"
-msgstr "förutspå \"git checkout <gren-saknas>\""
+msgstr "förutspÃ¥ â€git checkout <gren-saknas>â€"
msgid "throw away local modifications"
msgstr "kasta bort lokala ändringar"
@@ -3910,7 +3947,7 @@ msgstr "misslyckades ta bort %s"
#, c-format
msgid "could not lstat %s\n"
-msgstr "kunde inte ta status (\"lstat\") på %s\n"
+msgstr "kunde inte ta status (â€lstatâ€) pÃ¥ %s\n"
msgid "Refusing to remove current working directory\n"
msgstr "Vägrar ta bort aktuell arbetskatalog\n"
@@ -3982,7 +4019,7 @@ msgstr ""
"clean - börja städa\n"
"filter by pattern - uteslut poster från borttagning\n"
"select by numbers - markera poster som ska tas bort med siffror\n"
-"ask each - bekräfta varje borttagning (som \"rm -i\")\n"
+"ask each - bekräfta varje borttagning (som â€rm -iâ€)\n"
"quit - sluta städa\n"
"help - denna skärm\n"
"? - hjälp för kommandoval"
@@ -4019,22 +4056,8 @@ msgstr "ta även bort ignorerade filer"
msgid "remove only ignored files"
msgstr "ta endast bort ignorerade filer"
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce satt till true, men varken -i, -n eller -f angavs; vägrar "
-"städa"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce har standardvärdet true och varken -i, -n eller -f "
-"angavs; vägrar städa"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x och -X kan inte användas samtidigt"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
+msgstr "clean.requireForce är true och -f angavs inte: vägrar städa"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<flaggor>] [--] <arkiv> [<kat>]"
@@ -4046,10 +4069,10 @@ msgid "don't create a checkout"
msgstr "skapa inte någon utcheckning"
msgid "create a bare repository"
-msgstr "skapa ett naket (\"bare\") arkiv"
+msgstr "skapa ett naket (â€bareâ€) arkiv"
-msgid "create a mirror repository (implies bare)"
-msgstr "skapa ett spegelarkiv (implicerar \"bare\")"
+msgid "create a mirror repository (implies --bare)"
+msgstr "skapa ett spegelarkiv (implicerar --bare)"
msgid "to clone from a local repository"
msgstr "för att klona från ett lokalt arkiv"
@@ -4085,7 +4108,7 @@ msgid "name"
msgstr "namn"
msgid "use <name> instead of 'origin' to track upstream"
-msgstr "använd <namn> istället för \"origin\" för att spåra uppströms"
+msgstr "använd <namn> istället för â€origin†för att spÃ¥ra uppströms"
msgid "checkout <branch> instead of the remote's HEAD"
msgstr "checka ut <gren> istället för fjärrens HEAD"
@@ -4123,6 +4146,9 @@ msgstr "gitkat"
msgid "separate git dir from working tree"
msgstr "separera gitkatalogen från arbetskatalogen"
+msgid "specify the reference format to use"
+msgstr "använd referensformatet som ska användas"
+
msgid "key=value"
msgstr "nyckel=värde"
@@ -4152,11 +4178,11 @@ msgstr "en URI för att hämta buntar innan de hämtas från ursprungsfjärr"
#, c-format
msgid "info: Could not add alternate for '%s': %s\n"
-msgstr "info: Kan inte skapa suppleant för \"%s\": %s\n"
+msgstr "info: Kan inte skapa suppleant för â€%sâ€: %s\n"
#, c-format
msgid "failed to stat '%s'"
-msgstr "misslyckades ta status på \"%s\""
+msgstr "misslyckades ta status pÃ¥ â€%sâ€"
#, c-format
msgid "%s exists and is not a directory"
@@ -4164,31 +4190,39 @@ 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"
+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\""
+msgstr "misslyckades starta iterator över â€%sâ€"
#, c-format
msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "symbolisk länk \"%s\" finns redan, vägrar klona med --local"
+msgstr "symbolisk länk â€%s†finns redan, vägrar klona med --local"
#, c-format
msgid "failed to unlink '%s'"
-msgstr "misslyckades ta bort länken \"%s\""
+msgstr "misslyckades ta bort länken â€%sâ€"
+
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "hÃ¥rd länk kan inte kontrolleras vid â€%sâ€"
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "hÃ¥rd länk skiljer sig frÃ¥n källan vid â€%sâ€"
#, c-format
msgid "failed to create link '%s'"
-msgstr "misslyckades skapa länken \"%s\""
+msgstr "misslyckades skapa länken â€%sâ€"
#, c-format
msgid "failed to copy file to '%s'"
-msgstr "misslyckades kopiera filen till \"%s\""
+msgstr "misslyckades kopiera filen till â€%sâ€"
#, c-format
msgid "failed to iterate over '%s'"
-msgstr "misslyckades iterera över \"%s\""
+msgstr "misslyckades iterera över â€%sâ€"
#, c-format
msgid "done.\n"
@@ -4200,8 +4234,8 @@ msgid ""
"and retry with 'git restore --source=HEAD :/'\n"
msgstr ""
"Klonen lyckades, men utcheckningen misslyckades.\n"
-"Du kan inspektera det som checkades ut med \"git status\"\n"
-"och försöka med \"git restore --source=HEAD :/\"\n"
+"Du kan inspektera det som checkades ut med â€git statusâ€\n"
+"och försöka med â€git restore --source=HEAD :/â€\n"
#, c-format
msgid "Could not find remote branch %s to clone."
@@ -4221,16 +4255,16 @@ msgid "remote HEAD refers to nonexistent ref, unable to checkout"
msgstr "HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut"
msgid "unable to checkout working tree"
-msgstr "kunde inte checka ut arbetskatalogen"
+msgstr "kan inte checka ut arbetskatalogen"
msgid "unable to write parameters to config file"
-msgstr "kunde inte skriva parametrar till konfigurationsfilen"
+msgstr "kan inte skriva parametrar till konfigurationsfilen"
msgid "cannot repack to clean up"
msgstr "kan inte packa om för att städa upp"
msgid "cannot unlink temporary alternates file"
-msgstr "kunde inte ta bort temporär \"alternates\"-fil"
+msgstr "kunde inte ta bort temporär â€alternatesâ€-fil"
msgid "Too many arguments."
msgstr "För många argument."
@@ -4238,16 +4272,13 @@ msgstr "För många argument."
msgid "You must specify a repository to clone."
msgstr "Du måste ange ett arkiv att klona."
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr ""
-"--bundle-uri är inkompatibelt med --depth, --shallow-since och --shallow-"
-"exclude"
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "okänt format för lagring av referenser â€%sâ€"
#, c-format
msgid "repository '%s' does not exist"
-msgstr "arkivet \"%s\" finns inte"
+msgstr "arkivet â€%s†finns inte"
#, c-format
msgid "depth %s is not a positive number"
@@ -4255,31 +4286,31 @@ msgstr "djupet %s är inte ett positivt tal"
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
-msgstr "destinationssökvägen \"%s\" finns redan och är inte en tom katalog."
+msgstr "destinationssökvägen â€%s†finns redan och är inte en tom katalog."
#, c-format
msgid "repository path '%s' already exists and is not an empty directory."
-msgstr "arkivsökvägen \"%s\" finns redan och är inte en tom katalog."
+msgstr "arkivsökvägen â€%s†finns redan och är inte en tom katalog."
#, c-format
msgid "working tree '%s' already exists."
-msgstr "arbetsträdet \"%s\" finns redan."
+msgstr "arbetsträdet â€%s†finns redan."
#, c-format
msgid "could not create leading directories of '%s'"
-msgstr "kunde inte skapa inledande kataloger för \"%s\""
+msgstr "kunde inte skapa inledande kataloger för â€%sâ€"
#, c-format
msgid "could not create work tree dir '%s'"
-msgstr "kunde inte skapa arbetskatalogen \"%s\""
+msgstr "kunde inte skapa arbetskatalogen â€%sâ€"
#, c-format
msgid "Cloning into bare repository '%s'...\n"
-msgstr "Klonar till ett naket arkiv \"%s\"...\n"
+msgstr "Klonar till ett naket arkiv â€%sâ€...\n"
#, c-format
msgid "Cloning into '%s'...\n"
-msgstr "Klonar till \"%s\"...\n"
+msgstr "Klonar till â€%sâ€...\n"
msgid ""
"clone --recursive is not compatible with both --reference and --reference-if-"
@@ -4289,7 +4320,7 @@ msgstr ""
#, c-format
msgid "'%s' is not a valid remote name"
-msgstr "\"%s\" är inte ett giltigt namn på fjärrarkiv"
+msgstr "â€%s†är inte ett giltigt namn pÃ¥ fjärrarkiv"
msgid "--depth is ignored in local clones; use file:// instead."
msgstr "--depth ignoreras i lokala kloningar; använd file:// istället."
@@ -4321,7 +4352,7 @@ msgstr "misslyckades initiera arkivet, hoppar över bunt-URI"
#, c-format
msgid "failed to fetch objects from bundle URI '%s'"
-msgstr "misslyckades hämta objekt från bunt-URI \"%s\""
+msgstr "misslyckades hämta objekt frÃ¥n bunt-URI â€%sâ€"
msgid "failed to fetch advertised bundles"
msgstr "misslyckades hämta annonserade buntar"
@@ -4357,6 +4388,10 @@ msgstr "spaltfyllnad i högerkanten"
msgid "padding space between columns"
msgstr "spaltfyllnad mellan spalter"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s måste vara icke-negativt"
+
msgid "--command must be the first argument"
msgstr "--command måste vara första argument"
@@ -4371,7 +4406,7 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <kat>] [--append]\n"
" [--split[=<strategi>]] [--reachable | --stdin-packs | "
@@ -4391,7 +4426,11 @@ msgstr "om inchecknignsgrafen är delad, kontrollera bara spetsfilen"
#, c-format
msgid "Could not open commit-graph '%s'"
-msgstr "Kunde inte öppna incheckningsgrafen \"%s\""
+msgstr "Kunde inte öppna incheckningsgrafen â€%sâ€"
+
+#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "kunde inte öppna incheckningsgrafen â€%sâ€"
#, c-format
msgid "unrecognized --split argument, %s"
@@ -4407,7 +4446,7 @@ msgstr "ogiltigt objekt: %s"
#, c-format
msgid "option `%s' expects a numerical value"
-msgstr "flaggan \"%s\" antar ett numeriskt värde"
+msgstr "flaggan â€%s†antar ett numeriskt värde"
msgid "start walk at all refs"
msgstr "starta traversering vid alla referenser"
@@ -4467,11 +4506,11 @@ msgstr "objektnamnet är inte giltigt: %s"
#, c-format
msgid "git commit-tree: failed to read '%s'"
-msgstr "git commit-tree: misslyckades läsa \"%s\""
+msgstr "git commit-tree: misslyckades läsa â€%sâ€"
#, c-format
msgid "git commit-tree: failed to close '%s'"
-msgstr "git commit-tree: misslyckades stänga \"%s\""
+msgstr "git commit-tree: misslyckades stänga â€%sâ€"
msgid "parent"
msgstr "förälder"
@@ -4500,7 +4539,7 @@ msgstr "git commit-tree: misslyckades läsa"
msgid ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -4510,7 +4549,7 @@ msgid ""
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<läge>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <incheckning> | --fixup [(amend|"
-"reword):]<incheckning>)]\n"
+"reword):]<incheckning>]\n"
" [-F <fil> | -m <medd>] [--reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--"
"author=<författare>]\n"
@@ -4529,7 +4568,7 @@ msgid ""
msgstr ""
"Du bad om att utöka den senaste incheckningen, men om du gör det\n"
"blir den tom. Du kan köra kommandot på nytt med --allow-empty, eller\n"
-"så kan du ta bort incheckningen helt med \"git reset HEAD^\".\n"
+"sÃ¥ kan du ta bort incheckningen helt med â€git reset HEAD^â€.\n"
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
@@ -4538,17 +4577,17 @@ msgid ""
" git commit --allow-empty\n"
"\n"
msgstr ""
-"Den tidigare \"cherry-pick\":en är nu tom, kanske på grund av en löst\n"
+"Den tidigare â€cherry-pickâ€:en är nu tom, kanske pÃ¥ grund av en löst\n"
"konflikt. Om du vill checka in den ändå använder du:\n"
"\n"
" git commit --allow-empty\n"
"\n"
msgid "Otherwise, please use 'git rebase --skip'\n"
-msgstr "Använd annars \"git rebase --skip\"\n"
+msgstr "Använd annars â€git rebase --skipâ€\n"
msgid "Otherwise, please use 'git cherry-pick --skip'\n"
-msgstr "Använd annars \"git cherry-pick --skip\"\n"
+msgstr "Använd annars â€git cherry-pick --skipâ€\n"
msgid ""
"and then use:\n"
@@ -4565,7 +4604,7 @@ msgstr ""
"\n"
" git cherry-pick --continue\n"
"\n"
-"för att fortsätta \"cherry-pick\" med resterande incheckningar.\n"
+"för att fortsätta â€cherry-pick†med resterande incheckningar.\n"
"Om du vill hoppa över den här incheckningen, använd:\n"
"\n"
" git cherry-pick --skip\n"
@@ -4581,7 +4620,7 @@ msgid "No paths with --include/--only does not make sense."
msgstr "Du måste ange sökvägar tillsammans med --include/--only."
msgid "unable to create temporary index"
-msgstr "kunde inte skapa temporär indexfil"
+msgstr "kan inte skapa temporär indexfil"
msgid "interactive add failed"
msgstr "interaktiv tilläggning misslyckades"
@@ -4592,9 +4631,6 @@ msgstr "kan inte uppdatera temporärt index"
msgid "Failed to update main cache tree"
msgstr "Misslyckades uppdatera huvud-cacheträdet"
-msgid "unable to write new_index file"
-msgstr "kunde inte skriva filen new_index"
-
msgid "cannot do a partial commit during a merge."
msgstr "kan inte utföra en delvis incheckning under en sammanslagning."
@@ -4608,18 +4644,18 @@ msgid "cannot read the index"
msgstr "kan inte läsa indexet"
msgid "unable to write temporary index file"
-msgstr "kunde inte skriva temporär indexfil"
+msgstr "kan inte skriva temporär indexfil"
#, c-format
msgid "commit '%s' lacks author header"
-msgstr "incheckningen \"%s\" saknar författarhuvud"
+msgstr "incheckningen â€%s†saknar författarhuvud"
#, c-format
msgid "commit '%s' has malformed author line"
-msgstr "incheckningen \"%s\" har felformaterat författarhuvud"
+msgstr "incheckningen â€%s†har felformaterat författarhuvud"
msgid "malformed --author parameter"
-msgstr "felformad \"--author\"-flagga"
+msgstr "felformad â€--authorâ€-flagga"
#, c-format
msgid "invalid date format: %s"
@@ -4629,12 +4665,12 @@ msgid ""
"unable to select a comment character that is not used\n"
"in the current commit message"
msgstr ""
-"kunde inte välja ett kommentarstecken som inte använts\n"
+"kan inte välja ett kommentarstecken som inte använts\n"
"i det befintliga incheckningsmeddelandet"
#, c-format
msgid "could not lookup commit '%s'"
-msgstr "kunde inte slå upp incheckningen \"%s\""
+msgstr "kunde inte slÃ¥ upp incheckningen â€%sâ€"
#, c-format
msgid "(reading log message from standard input)\n"
@@ -4645,11 +4681,11 @@ msgstr "kunde inte läsa logg från standard in"
#, c-format
msgid "could not read log file '%s'"
-msgstr "kunde inte läsa loggfilen \"%s\""
+msgstr "kunde inte läsa loggfilen â€%sâ€"
#, c-format
msgid "options '%s' and '%s:%s' cannot be used together"
-msgstr "flaggorna \"%s\" och \"%s:%s\" kan inte användas samtidigt"
+msgstr "flaggorna â€%s†och â€%s:%s†kan inte användas samtidigt"
msgid "could not read SQUASH_MSG"
msgstr "kunde inte läsa SQUASH_MSG"
@@ -4659,7 +4695,7 @@ msgstr "kunde inte läsa MERGE_MSG"
#, c-format
msgid "could not open '%s'"
-msgstr "kunde inte öppna \"%s\""
+msgstr "kunde inte öppna â€%sâ€"
msgid "could not write commit template"
msgstr "kunde inte skriva incheckningsmall"
@@ -4667,36 +4703,35 @@ msgstr "kunde inte skriva incheckningsmall"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
-"med \"%c\" kommer ignoreras.\n"
+"med â€%s†kommer ignoreras.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
-"med \"%c\" kommer ignoreras, och ett tomt meddelande avbryter "
-"incheckningen.\n"
+"med â€%s†kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
-"med \"%c\" kommer behållas; du kan själv ta bort dem om du vill.\n"
+"med â€%s†kommer behÃ¥llas; du kan själv ta bort dem om du vill.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
-"med \"%c\" kommer behållas; du kan själv ta bort dem om du vill.\n"
+"med â€%s†kommer behÃ¥llas; du kan själv ta bort dem om du vill.\n"
"Ett tomt meddelande avbryter incheckningen.\n"
msgid ""
@@ -4757,11 +4792,11 @@ msgstr ""
#, c-format
msgid "Invalid ignored mode '%s'"
-msgstr "Ogiltigt ignorerat läge \"%s\""
+msgstr "Ogiltigt ignorerat läge â€%sâ€"
#, c-format
msgid "Invalid untracked files mode '%s'"
-msgstr "Ogiltigt läge för ospårade filer: \"%s\""
+msgstr "Ogiltigt läge för ospÃ¥rade filer: â€%sâ€"
msgid "You are in the middle of a merge -- cannot reword."
msgstr "Du är i mitten av en sammanslagning -- kan inte omformulera."
@@ -4772,11 +4807,11 @@ msgstr "Du är i mitten av en cherry-pick -- kan inte omformulera."
#, c-format
msgid "reword option of '%s' and path '%s' cannot be used together"
msgstr ""
-"reword-flaggan till \"%s\" och sökvägen \"%s\" kan inte användas tillsammans"
+"reword-flaggan till â€%s†och sökvägen â€%s†kan inte användas tillsammans"
#, c-format
msgid "reword option of '%s' and '%s' cannot be used together"
-msgstr "reword-flaggan till \"%s\" och \"%s\" kan inte användas tillsammans"
+msgstr "reword-flaggan till â€%s†och â€%s†kan inte användas tillsammans"
msgid "You have nothing to amend."
msgstr "Du har inget att utöka."
@@ -4799,7 +4834,7 @@ msgstr "okänd flagga: --fixup=%s:%s"
#, c-format
msgid "paths '%s ...' with -a does not make sense"
-msgstr "sökvägarna \"%s ...\" med -a ger ingen mening"
+msgstr "sökvägarna â€%s ...†med -a ger ingen mening"
msgid "show status concisely"
msgstr "visa koncis status"
@@ -4992,23 +5027,65 @@ msgstr "Avbryter på grund av tom incheckningsmeddelandekropp.\n"
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"arkivet har uppdaterats, men kunde inte skriva filen\n"
-"new_index. Kontrollera att disken inte är full och\n"
+"arkivet har uppdaterats, men kunde inte skriva ny\n"
+"indexfil. Kontrollera att disken inte är full och\n"
"att kvoten inte har överskridits, och kör sedan\n"
-"\"git restore --staged :/\" för att återställa."
+"â€git restore --staged :/†för att Ã¥terställa."
-msgid "git config [<options>]"
-msgstr "git config [<flaggor>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<filflagga>] [<visningsflagga>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "okänt argument för --type, %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<filflagga>] [<visningsflagga>] [--includes] [--all] [--"
+"regexp] [--value=<värde>] [--fixed-value] [--default=<förval>] <namn>"
-msgid "only one type at a time"
-msgstr "endast en typ åt gången"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<filflagga>] [--type=<typ>] [--all] [--value=<värde>] [--"
+"fixed-value] <namn> <värde>"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<filflagga>] [--all] [--value=<värde>] [--fixed-value] "
+"<namn> <värde>"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<filflagga>] <gammalt-namn> <nytt-namn>"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<filflagga>] <namn>"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<filflagga>]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<filflagga>] --get-colorbool <namn> [<stdout-är-tty>]"
+
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<filflagga>] [<visningsflagga>] [--includes] [--all] [--"
+"regexp=<reguttr>] [--value=<värde>] [--fixed-value] [--default=<förval>] "
+"<namn>"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<filflagga>] [--type=<typ>] [--comment=<meddelande>] [--all] "
+"[--value=<värde>] [--fixed-value] <namn> <värde>"
msgid "Config file location"
msgstr "Konfigurationsfilens plats"
@@ -5034,54 +5111,6 @@ msgstr "blob-id"
msgid "read config from given blob object"
msgstr "läs konfiguration från givet blob-objekt"
-msgid "Action"
-msgstr "Åtgärd"
-
-msgid "get value: name [value-pattern]"
-msgstr "hämta värde: namn [värde-mönster]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "hämta alla värden: nyckel [värde-mönster]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "hämta värden för reguttr: namn-reguttr [värde-mönster]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "hämta värde specifikt URL:en: sektion[.var] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "ersätt alla motsvarande variabler: namn värde [värde-mönster]"
-
-msgid "add a new variable: name value"
-msgstr "lägg till en ny variabel: namn värde"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "ta bort en variabel: namn [värde-mönster]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "ta bort alla träffar: namn [värde-mönster]"
-
-msgid "rename section: old-name new-name"
-msgstr "byt namn på sektion: gammalt-namn nytt-namn"
-
-msgid "remove a section: name"
-msgstr "ta bort en sektion: namn"
-
-msgid "list all"
-msgstr "visa alla"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr "använd stränglikhet vid när värden jämförs med \"värde-mönster\""
-
-msgid "open an editor"
-msgstr "öppna textredigeringsprogram"
-
-msgid "find the color configured: slot [default]"
-msgstr "hitta den inställda färgen: slot [default]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "hitta färginställningen: slot [stdout-is-tty]"
-
msgid "Type"
msgstr "Typ"
@@ -5092,7 +5121,7 @@ msgid "value is given this type"
msgstr "värdet har givits denna typ"
msgid "value is \"true\" or \"false\""
-msgstr "värdet är \"true\" eller \"false\""
+msgstr "värdet är â€true†eller â€falseâ€"
msgid "value is decimal number"
msgstr "värdet är ett decimalt tal"
@@ -5109,8 +5138,8 @@ msgstr "värdet är en sökväg (fil- eller katalognamn)"
msgid "value is an expiry date"
msgstr "värdet är ett utgångsdatum"
-msgid "Other"
-msgstr "Andra"
+msgid "Display options"
+msgstr "Visningsflaggor"
msgid "terminate values with NUL byte"
msgstr "terminera värden med NUL-byte"
@@ -5118,9 +5147,6 @@ msgstr "terminera värden med NUL-byte"
msgid "show variable names only"
msgstr "visa endast variabelnamn"
-msgid "respect include directives on lookup"
-msgstr "respektera inkluderingsdirektiv vid uppslag"
-
msgid "show origin of config (file, standard input, blob, command line)"
msgstr "visa konfigurationskälla (fil, standard in, blob, kommandorad)"
@@ -5129,11 +5155,15 @@ msgstr ""
"visa omfång för konfiguration (arbetskatalog, lokalt, globalt, system, "
"kommando)"
-msgid "value"
-msgstr "värde"
+msgid "show config keys in addition to their values"
+msgstr "visa konfigurationsnycklar tillsammans med deras värden"
-msgid "with --get, use default value when missing entry"
-msgstr "med --get, använd standardvärde vid saknad post"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "okänt argument för --type, %s"
+
+msgid "only one type at a time"
+msgstr "endast en typ åt gången"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5157,7 +5187,7 @@ msgstr "misslyckades formatera standardkonfigurationsvärde: %s"
#, c-format
msgid "cannot parse color '%s'"
-msgstr "kan inte tolka färgen \"%s\""
+msgstr "kan inte tolka färgen â€%sâ€"
msgid "unable to parse default color value"
msgstr "kan inte tolka standardfärgvärde"
@@ -5207,45 +5237,74 @@ msgid ""
msgstr ""
"--worktree kan inte användas med flera arbetskataloger om inte\n"
"konfigurationsutöknignen worktreeConfig har aktiverats. Läsa stycket\n"
-"\"KONFIGURATIONSFIL\" i \"git help worktree\" för detaljer"
+"â€KONFIGURATIONSFIL†i â€git help worktree†för detaljer"
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color och variabeltyp stämmer inte överens"
+msgid "Other"
+msgstr "Andra"
-msgid "only one action at a time"
-msgstr "endast en åtgärd åt gången"
+msgid "respect include directives on lookup"
+msgstr "respektera inkluderingsdirektiv vid uppslag"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only gäller bara för --list eller --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "kan inte läsa konfigurationsfilen â€%sâ€"
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr ""
-"--show-origin gäller bara för --get, --get-all, --get-regexp och --list"
+msgid "error processing config file(s)"
+msgstr "fel vid hantering av konfigurationsfil(er)"
-msgid "--default is only applicable to --get"
-msgstr "--default gäller bara för --get"
+msgid "Filter options"
+msgstr "Filterflaggor"
+
+msgid "return all values for multi-valued config options"
+msgstr "returnera alla värden för konfigurationsflaggor med flera värden"
+
+msgid "interpret the name as a regular expression"
+msgstr "tolka namnet som reguljärt uttryck"
+
+msgid "show config with values matching the pattern"
+msgstr "via konfiguration med värden som motsvarar mönster"
+
+msgid "use string equality when comparing values to value pattern"
+msgstr "använd stränglikhet vid när värden jämförs med värde-mönster"
+
+msgid "URL"
+msgstr "URL"
+
+msgid "show config matching the given URL"
+msgstr "visa konfiguration som motsvarar given URL"
+
+msgid "value"
+msgstr "värde"
+
+msgid "use default value when missing entry"
+msgstr "använd standardvärde vid saknad post"
msgid "--fixed-value only applies with 'value-pattern'"
-msgstr "--fixed-value gäller endast med \"värde-mönster\""
+msgstr "--fixed-value gäller endast med â€värde-mönsterâ€"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "kan inte konfigurationsfil \"%s\""
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= kan inte användas med --all eller --url="
-msgid "error processing config file(s)"
-msgstr "fel vid hantering av konfigurationsfil(er)"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= kan inte användas med --all, --regexp eller --value"
-msgid "editing stdin is not supported"
-msgstr "redigering av standard in stöds ej"
+msgid "Filter"
+msgstr "Filter"
-msgid "editing blobs is not supported"
-msgstr "redigering av blobbar stöds ej"
+msgid "replace multi-valued config option with new value"
+msgstr "ersätt konfigurationsflagga med flera värden med nytt värde"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "kan inte skapa konfigurationsfilen \"%s\""
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr "människoläsbar kommentarssträng (# läggs in först efter behov)"
+
+msgid "add a new line without altering any existing values"
+msgstr "lägg till ny rad utan att ändra befintliga värden"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value gäller endast med --value=<mönster>"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append kan inte användas med --value=<mönster>"
#, c-format
msgid ""
@@ -5259,6 +5318,85 @@ msgstr ""
msgid "no such section: %s"
msgstr "ingen sådan sektion: %s"
+msgid "editing stdin is not supported"
+msgstr "redigering av standard in stöds ej"
+
+msgid "editing blobs is not supported"
+msgstr "redigering av blobbar stöds ej"
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "kan inte skapa konfigurationsfilen â€%sâ€"
+
+msgid "Action"
+msgstr "Åtgärd"
+
+msgid "get value: name [<value-pattern>]"
+msgstr "hämta värde: namn <värde-mönster>"
+
+msgid "get all values: key [<value-pattern>]"
+msgstr "hämta alla värden: nyckel <värde-mönster>"
+
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "hämta värden för reguttr: namn-reguttr <värde-mönster>"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "hämta värde specifikt URL:en: sektion[.var] URL"
+
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "ersätt alla motsvarande variabler: namn värde <värde-mönster>"
+
+msgid "add a new variable: name value"
+msgstr "lägg till en ny variabel: namn värde"
+
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "ta bort en variabel: namn <värde-mönster>"
+
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "ta bort alla träffar: namn <värde-mönster>"
+
+msgid "rename section: old-name new-name"
+msgstr "byt namn på sektion: gammalt-namn nytt-namn"
+
+msgid "remove a section: name"
+msgstr "ta bort en sektion: namn"
+
+msgid "list all"
+msgstr "visa alla"
+
+msgid "open an editor"
+msgstr "öppna textredigeringsprogram"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "hitta den inställda färgen: lucka <förval>"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "hitta färginställningen: lucka <stdout-är-tty>"
+
+msgid "with --get, use default value when missing entry"
+msgstr "med --get, använd standardvärde vid saknad post"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color och variabeltyp stämmer inte överens"
+
+msgid "no action specified"
+msgstr "ingen handling angavs"
+
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only gäller bara för --list eller --get-regexp"
+
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin gäller bara för --get, --get-all, --get-regexp och --list"
+
+msgid "--default is only applicable to --get"
+msgstr "--default gäller bara för --get"
+
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment gäller bara för â€getâ€/â€setâ€/â€replaceâ€-operationerna"
+
msgid "print sizes in human readable format"
msgstr "skriv storlekar i människoläsbart format"
@@ -5278,15 +5416,14 @@ msgid "print debugging messages to stderr"
msgstr "skriv felsökningsmeddelanden på standard fel"
msgid "credential-cache--daemon unavailable; no unix socket support"
-msgstr ""
-"\"credential-cache--daemon\" ej tillgänglig; stöd för unix-uttag saknas"
+msgstr "â€credential-cache--daemon†ej tillgänglig; stöd för unix-uttag saknas"
msgid "credential-cache unavailable; no unix socket support"
-msgstr "\"credential-cache\" ej tillgänglig; stöd för unix-uttag saknas"
+msgstr "â€credential-cache†ej tillgänglig; stöd för unix-uttag saknas"
#, c-format
msgid "unable to get credential storage lock in %d ms"
-msgstr "kunde inte erhålla låset för lagring av inlogginsuppgifter på %d ms"
+msgstr "kan inte erhålla låset för lagring av inlogginsuppgifter på %d ms"
msgid ""
"git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
@@ -5317,11 +5454,11 @@ msgstr "den annoterade taggen %s inte tillgänglig"
#, c-format
msgid "tag '%s' is externally known as '%s'"
-msgstr "taggen \"%s\" är utanför känd som \"%s\""
+msgstr "taggen â€%s†är utanför känd som â€%sâ€"
#, c-format
msgid "no tag exactly matches '%s'"
-msgstr "ingen tagg motsvarar \"%s\" exakt"
+msgstr "ingen tagg motsvarar â€%s†exakt"
#, c-format
msgid "No exact match on refs or tags, searching to describe\n"
@@ -5337,7 +5474,7 @@ msgid ""
"No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."
msgstr ""
-"Inga annoterade taggar kan beskriva \"%s\".\n"
+"Inga annoterade taggar kan beskriva â€%sâ€.\n"
"Det finns dock oannoterade taggar: testa --tags."
#, c-format
@@ -5345,7 +5482,7 @@ msgid ""
"No tags can describe '%s'.\n"
"Try --always, or create some tags."
msgstr ""
-"Inga taggar kan beskriva \"%s\".\n"
+"Inga taggar kan beskriva â€%sâ€.\n"
"Testa --always, eller skapa några taggar."
#, c-format
@@ -5409,17 +5546,17 @@ msgid "mark"
msgstr "märke"
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
-msgstr "lägg till <märke> på lortigt arbetsträd (standard: \"-dirty\")"
+msgstr "lägg till <märke> pÃ¥ lortigt arbetsträd (standard: â€-dirtyâ€)"
msgid "append <mark> on broken working tree (default: \"-broken\")"
-msgstr "lägg till <märke> på trasigt arbetsträd (standard: \"-broken\")"
+msgstr "lägg till <märke> pÃ¥ trasigt arbetsträd (standard: â€-brokenâ€)"
msgid "No names found, cannot describe anything."
msgstr "Inga namn hittades, kan inte beskriva något."
#, c-format
msgid "option '%s' and commit-ishes cannot be used together"
-msgstr "flaggorna \"%s\" och incheckning-igter kan inte användas samtidigt"
+msgstr "flaggorna â€%s†och incheckning-igter kan inte användas samtidigt"
msgid ""
"git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
@@ -5443,7 +5580,7 @@ msgstr "--merge-base fungerar endast med två incheckningar"
#, c-format
msgid "'%s': not a regular file or symlink"
-msgstr "\"%s\": inte en normal fil eller symbolisk länk"
+msgstr "â€%sâ€: inte en normal fil eller symbolisk länk"
msgid "no merge given, only parents."
msgstr "ingen sammanslagning angiven, endast föräldrar."
@@ -5461,15 +5598,15 @@ msgstr "Inte ett git-arkiv"
#, c-format
msgid "invalid object '%s' given."
-msgstr "objektet \"%s\" som angavs är felaktigt."
+msgstr "objektet â€%s†som angavs är felaktigt."
#, c-format
msgid "more than two blobs given: '%s'"
-msgstr "mer än två blobbar angavs: \"%s\""
+msgstr "mer än tvÃ¥ blobbar angavs: â€%sâ€"
#, c-format
msgid "unhandled object '%s' given."
-msgstr "ej hanterat objekt \"%s\" angavs."
+msgstr "ej hanterat objekt â€%s†angavs."
#, c-format
msgid "%s...%s: multiple merge bases, using %s"
@@ -5495,23 +5632,23 @@ msgid ""
"combined diff formats ('-c' and '--cc') are not supported in\n"
"directory diff mode ('-d' and '--dir-diff')."
msgstr ""
-"kombinerade diff-format (\"-c\" och \"--cc\") stöds inte i\n"
-"katalogdiffläge (\"-d\" och \"--dir-diff\")."
+"kombinerade diff-format (â€-c†och â€--ccâ€) stöds inte i\n"
+"katalogdiffläge (â€-d†och â€--dir-diffâ€)."
#, c-format
msgid "both files modified: '%s' and '%s'."
-msgstr "bägge filerna ändrade: \"%s\" och \"%s\"."
+msgstr "bägge filerna ändrade: â€%s†och â€%sâ€."
msgid "working tree file has been left."
msgstr "filen i arbetskatalogen lämnades kvar."
#, c-format
msgid "could not copy '%s' to '%s'"
-msgstr "kunde inte kopiera in \"%s\" till \"%s\""
+msgstr "kunde inte kopiera in â€%s†till â€%sâ€"
#, c-format
msgid "temporary files exist in '%s'."
-msgstr "temporära filer finns i \"%s\"."
+msgstr "temporära filer finns i â€%sâ€."
msgid "you may want to cleanup or recover these."
msgstr "du kanske vill städa eller rädda dem."
@@ -5521,7 +5658,7 @@ msgid "failed: %d"
msgstr "misslyckades: %d"
msgid "use `diff.guitool` instead of `diff.tool`"
-msgstr "använd \"diff.guitool\" istället för \"diff.tool\""
+msgstr "använd â€diff.guitool†istället för â€diff.toolâ€"
msgid "perform a full-directory diff"
msgstr "utför diff för hela katalogen"
@@ -5539,20 +5676,20 @@ msgid "use the specified diff tool"
msgstr "använd angivet diff-verktyg"
msgid "print a list of diff tools that may be used with `--tool`"
-msgstr "visa en lista över diff-verktyg som kan användas med \"--tool\""
+msgstr "visa en lista över diff-verktyg som kan användas med â€--toolâ€"
msgid ""
"make 'git-difftool' exit when an invoked diff tool returns a non-zero exit "
"code"
msgstr ""
-"låt \"git-difftool\" avsluta när ett anropat diff-verktyg ger returvärde "
-"skilt från noll"
+"lÃ¥t â€git-difftool†avsluta när ett anropat diff-verktyg ger returvärde skilt "
+"från noll"
msgid "specify a custom command for viewing diffs"
msgstr "ange eget kommando för att visa diffar"
msgid "passed to `diff`"
-msgstr "sändes till \"diff\""
+msgstr "sändes till â€diffâ€"
msgid "difftool requires worktree or --no-index"
msgstr "difftool kräver en arbetskatalog eller --no-index"
@@ -5631,26 +5768,26 @@ msgstr "märk taggar med märke-id"
#, c-format
msgid "Missing from marks for submodule '%s'"
-msgstr "Saknar från-märken för undermodulen \"%s\""
+msgstr "Saknar frÃ¥n-märken för undermodulen â€%sâ€"
#, c-format
msgid "Missing to marks for submodule '%s'"
-msgstr "Saknar till-märken för undermodulen \"%s\""
+msgstr "Saknar till-märken för undermodulen â€%sâ€"
#, c-format
msgid "Expected 'mark' command, got %s"
-msgstr "Förväntade \"mark\"-kommando, fick %s"
+msgstr "Förväntade â€markâ€-kommando, fick %s"
#, c-format
msgid "Expected 'to' command, got %s"
-msgstr "Förväntade \"to\"-kommando, fick %s"
+msgstr "Förväntade â€toâ€-kommando, fick %s"
msgid "Expected format name:filename for submodule rewrite option"
msgstr "Förvändae formatet namn:filnamn för undermodul-omskrivningsflaggan"
#, c-format
msgid "feature '%s' forbidden in input without --allow-unsafe-features"
-msgstr "funktionen \"%s\" förbjuden i indata utan --allow-unsafe-features"
+msgstr "funktionen â€%s†förbjuden i indata utan --allow-unsafe-features"
#, c-format
msgid "Lockfile created but not reported: %s"
@@ -5695,7 +5832,7 @@ msgid "[tag update]"
msgstr "[uppdaterad tagg]"
msgid "unable to update local ref"
-msgstr "kunde inte uppdatera lokal ref"
+msgstr "kan inte uppdatera lokal ref"
msgid "would clobber existing tag"
msgstr "skulle skriva över befintlig tagg"
@@ -5717,7 +5854,7 @@ msgstr "ej snabbspolad"
#, c-format
msgid "cannot open '%s'"
-msgstr "kan inte öppna \"%s\""
+msgstr "kan inte öppna â€%sâ€"
msgid ""
"fetch normally indicates which branches had a forced update,\n"
@@ -5726,8 +5863,8 @@ msgid ""
msgstr ""
"fetch visar normalt vilka grenar som tvångsuppdaterats, men testet har "
"slagits\n"
-"av; för att slå på igen, använd flaggan \"--show-forced-updates\" eller kör\n"
-"\"git config fetch.showForcedUpdates true\""
+"av; för att slÃ¥ pÃ¥ igen, använd flaggan â€--show-forced-updates†eller kör\n"
+"â€git config fetch.showForcedUpdates trueâ€"
#, c-format
msgid ""
@@ -5737,13 +5874,12 @@ msgid ""
"to avoid this check\n"
msgstr ""
"det tog %.2f sekunder att se efter tvångsuppdateringar; Du kan använda\n"
-"\"--no-show-forced-updates\" eller köra \"git config fetch."
-"showForcedUpdates\n"
-"false\" för att undvika testet\n"
+"â€--no-show-forced-updates†eller köra â€git config fetch.showForcedUpdates\n"
+"false†för att undvika testet\n"
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s sände inte alla nödvändiga objekt\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s sände inte alla nödvändiga objekt"
#, c-format
msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -5755,7 +5891,7 @@ msgid ""
" 'git remote prune %s' to remove any old, conflicting branches"
msgstr ""
"vissa lokala referenser kunde inte uppdateras; testa att köra\n"
-" \"git remote prune %s\" för att ta bort gamla grenar som står i konflikt"
+" â€git remote prune %s†för att ta bort gamla grenar som stÃ¥r i konflikt"
#, c-format
msgid " (%s will become dangling)"
@@ -5773,15 +5909,15 @@ msgstr "(ingen)"
#, c-format
msgid "refusing to fetch into branch '%s' checked out at '%s'"
-msgstr "vägrar hämta till grenen \"%s\" som är utcheckad på \"%s\""
+msgstr "vägrar hämta till grenen â€%s†som är utcheckad pÃ¥ â€%sâ€"
#, c-format
msgid "option \"%s\" value \"%s\" is not valid for %s"
-msgstr "flaggan \"%s\" med värdet \"%s\" är inte giltigt för %s"
+msgstr "flaggan â€%s†med värdet â€%s†är inte giltigt för %s"
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "flaggan \"%s\" ignoreras för %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "flaggan â€%s†ignoreras för %s"
#, c-format
msgid "%s is not a valid object"
@@ -5799,8 +5935,8 @@ msgid ""
"could not set upstream of HEAD to '%s' from '%s' when it does not point to "
"any branch."
msgstr ""
-"kunde inte sätta uppström för HEAD till \"%s\" från \"%s\" när det inte "
-"pekar mot någon gren."
+"kunde inte sätta uppström för HEAD till â€%s†frÃ¥n â€%s†när det inte pekar "
+"mot någon gren."
msgid "not setting upstream for a remote remote-tracking branch"
msgstr "ställer inte in uppströmsgren för en fjärrspårande gren på fjärren"
@@ -5828,7 +5964,7 @@ msgstr "kunde inte hämta %s"
#, c-format
msgid "could not fetch '%s' (exit code: %d)\n"
-msgstr "kunde inte hämta \"%s\" (felkod: %d)\n"
+msgstr "kunde inte hämta â€%s†(felkod: %d)\n"
msgid ""
"no remote repository specified; please specify either a URL or a\n"
@@ -5926,7 +6062,7 @@ msgid "refmap"
msgstr "referenskarta"
msgid "specify fetch refmap"
-msgstr "ange referenskarta för \"fetch\""
+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"
@@ -5935,7 +6071,7 @@ 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"
+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"
@@ -5957,7 +6093,7 @@ msgstr "--unshallow kan inte användas på ett komplett arkiv"
#, c-format
msgid "failed to fetch bundles from '%s'"
-msgstr "misslyckades hämta buntar från \"%s\""
+msgstr "misslyckades hämta buntar frÃ¥n â€%sâ€"
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all tar inte namnet på ett arkiv som argument"
@@ -6064,6 +6200,9 @@ 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 "also include HEAD ref and pseudorefs"
+msgstr "ta också med HEAD- och pseudo-referenser"
+
msgid "unknown arguments supplied with --stdin"
msgstr "okända argument angavs tillsammans med --stdin"
@@ -6076,6 +6215,9 @@ msgstr "konfig"
msgid "config key storing a list of repository paths"
msgstr "konfigurationsnyckel som innehåller en lista över arkivsökvägar"
+msgid "keep going even if command fails in a repository"
+msgstr "fortsätt även om kommandot misslyckas i ett arkiv"
+
msgid "missing --config=<config>"
msgstr "saknar --config=<konfig>"
@@ -6133,11 +6275,11 @@ msgstr "kunde inte skapa lost-found"
#, c-format
msgid "could not write '%s'"
-msgstr "kunde inte skriva \"%s\""
+msgstr "kunde inte skriva â€%sâ€"
#, c-format
msgid "could not finish '%s'"
-msgstr "kunde inte avsluta \"%s\""
+msgstr "kunde inte avsluta â€%sâ€"
#, c-format
msgid "Checking %s"
@@ -6174,7 +6316,7 @@ msgstr "%s: ogiltig reflog-post %s"
#, c-format
msgid "Checking reflog %s->%s"
-msgstr "Kontrollerar reflog %s->%s"
+msgstr "Kontrollerar reflog %s→%s"
#, c-format
msgid "%s: invalid sha1 pointer %s"
@@ -6197,7 +6339,7 @@ msgstr "%s: objektet trasigt eller saknas: %s"
#, c-format
msgid "%s: object is of unknown type '%s': %s"
-msgstr "%s: objektet har okänd typ \"%s\": %s"
+msgstr "%s: objektet har okänd typ â€%sâ€: %s"
#, c-format
msgid "%s: object could not be parsed: %s"
@@ -6250,11 +6392,11 @@ 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\""
+msgstr "kan 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\""
+msgstr "ogiltigt rev-index för paketet â€%sâ€"
msgid ""
"git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -6314,7 +6456,7 @@ msgstr "%s: objekt saknas"
#, c-format
msgid "invalid parameter: expected sha1, got '%s'"
-msgstr "ogiltig parameter: förväntade sha1, fick \"%s\""
+msgstr "ogiltig parameter: förväntade sha1, fick â€%sâ€"
msgid "git fsmonitor--daemon start [<options>]"
msgstr "git fsmonitor--daemon start [<flaggor>]"
@@ -6324,23 +6466,23 @@ msgstr "git fsmonitor--daemon run [<flaggor>]"
#, c-format
msgid "value of '%s' out of range: %d"
-msgstr "värdet för \"%s\" utanför intervallet: %d"
+msgstr "värdet för â€%s†utanför intervallet: %d"
#, c-format
msgid "value of '%s' not bool or int: %d"
-msgstr "värdet för \"%s\" är inte bool eller int: %d"
+msgstr "värdet för â€%s†är inte bool eller int: %d"
#, c-format
msgid "fsmonitor-daemon is watching '%s'\n"
-msgstr "fsmonitor-daemon bevakar \"%s\"\n"
+msgstr "fsmonitor-daemon bevakar â€%sâ€\n"
#, c-format
msgid "fsmonitor-daemon is not watching '%s'\n"
-msgstr "fsmonitor-daemon bevakar inte \"%s\"\n"
+msgstr "fsmonitor-daemon bevakar inte â€%sâ€\n"
#, c-format
msgid "could not create fsmonitor cookie '%s'"
-msgstr "kunde inte skapa fsmonitor-kaka \"%s\""
+msgstr "kunde inte skapa fsmonitor-kaka â€%sâ€"
#, c-format
msgid "fsmonitor: cookie_result '%d' != SEEN"
@@ -6348,7 +6490,7 @@ msgstr "fsmonitor: cookie_result '%d' != SEEN"
#, c-format
msgid "could not start IPC thread pool on '%s'"
-msgstr "kunde inte starta IPC-trådpol på \"%s\""
+msgstr "kunde inte starta IPC-trÃ¥dpol pÃ¥ â€%sâ€"
msgid "could not start fsmonitor listener thread"
msgstr "kunde inte starta fsmonitor-lyssnartråd"
@@ -6364,19 +6506,19 @@ msgstr "kunde inte initiera hälsotråd"
#, c-format
msgid "could not cd home '%s'"
-msgstr "kunde inte byta katalog hem \"%s\""
+msgstr "kunde inte byta katalog hem â€%sâ€"
#, c-format
msgid "fsmonitor--daemon is already running '%s'"
-msgstr "fsmonitor--daemon körs redan på \"%s\""
+msgstr "fsmonitor--daemon körs redan pÃ¥ â€%sâ€"
#, c-format
msgid "running fsmonitor-daemon in '%s'\n"
-msgstr "kör fsmonitor-daemon i \"%s\"\n"
+msgstr "kör fsmonitor-daemon i â€%sâ€\n"
#, c-format
msgid "starting fsmonitor-daemon in '%s'\n"
-msgstr "startar fsmonitor-daemon i \"%s\"\n"
+msgstr "startar fsmonitor-daemon i â€%sâ€\n"
msgid "daemon failed to start"
msgstr "serverprocessen kunde inte startas"
@@ -6398,11 +6540,11 @@ msgstr "max sekunder att vänta på att serverprocessen startar"
#, c-format
msgid "invalid 'ipc-threads' value (%d)"
-msgstr "ogiltigt värde för \"ipc-threads\" (%d)"
+msgstr "ogiltigt värde för â€ipc-threads†(%d)"
#, c-format
msgid "Unhandled subcommand '%s'"
-msgstr "Ej hanterat underkommando \"%s\""
+msgstr "Ej hanterat underkommando â€%sâ€"
msgid "fsmonitor--daemon not supported on this platform"
msgstr "fsmonitor--daemon stöds inte på denna plattform"
@@ -6416,11 +6558,11 @@ msgstr "Misslyckades ta status (fstat) på %s: %s"
#, c-format
msgid "failed to parse '%s' value '%s'"
-msgstr "misslyckades tolka \"%s\" värde \"%s\""
+msgstr "misslyckades tolka â€%s†värde â€%sâ€"
#, c-format
msgid "cannot stat '%s'"
-msgstr "kan inte ta status på \"%s\""
+msgstr "kan inte ta status pÃ¥ â€%sâ€"
#, c-format
msgid ""
@@ -6442,12 +6584,18 @@ msgstr "rensa ej refererade objekt"
msgid "pack unreferenced objects separately"
msgstr "packa ej refererade objekt separat"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "med --cruft, begränsa storleken på nya onödiga paket"
+
msgid "be more thorough (increased runtime)"
msgstr "var mer grundlig (ökar körtiden)"
msgid "enable auto-gc mode"
msgstr "aktivera auto-gc-läge"
+msgid "perform garbage collection in the background"
+msgstr "utför skräpsamling i bakgrunden"
+
msgid "force running gc even if there may be another gc running"
msgstr "tvinga gc-körning även om en annan gc kanske körs"
@@ -6456,11 +6604,11 @@ msgstr "packa om alla paket förutom det största paketet"
#, c-format
msgid "failed to parse gc.logExpiry value %s"
-msgstr "kunde inte tolka värdet %s för gc.logExpiry"
+msgstr "misslyckades tolka värdet %s för gc.logExpiry"
#, c-format
msgid "failed to parse prune expiry value %s"
-msgstr "kunde inte tolka värdet %s för prune expiry"
+msgstr "misslyckades tolka värdet %s för prune expiry"
#, c-format
msgid "Auto packing the repository in background for optimum performance.\n"
@@ -6472,20 +6620,19 @@ msgstr "Packar arkivet automatiskt för optimal prestanda.\n"
#, c-format
msgid "See \"git help gc\" for manual housekeeping.\n"
-msgstr "Se \"git help gc\" för manuell hushållning.\n"
+msgstr "Se â€git help gc†för manuell hushÃ¥llning.\n"
#, c-format
msgid ""
"gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
msgstr ""
-"gc körs redan på maskinen \"%s\" pid %<PRIuMAX> (använd --force om så inte "
-"är fallet)"
+"gc körs redan pÃ¥ maskinen â€%s†pid %<PRIuMAX> (använd --force om sÃ¥ inte är "
+"fallet)"
msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
-"Det finns för många onåbara lösa objekt; kör \"git prune\" för att ta bort "
-"dem."
+"Det finns för mÃ¥nga onÃ¥bara lösa objekt; kör â€git prune†för att ta bort dem."
msgid ""
"git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"
@@ -6500,51 +6647,54 @@ msgid "unrecognized --schedule argument '%s'"
msgstr "okänt argument för --schedule, %s"
msgid "failed to write commit-graph"
-msgstr "kunde inte skriva incheckningsgraf"
+msgstr "misslyckades skriva incheckningsgraf"
msgid "failed to prefetch remotes"
-msgstr "kunde inte förhämta fjärrar"
+msgstr "misslyckades förhämta fjärrar"
msgid "failed to start 'git pack-objects' process"
-msgstr "kunde inte starta \"git pack-objects\"-process"
+msgstr "misslyckades starta â€git pack-objectsâ€-process"
msgid "failed to finish 'git pack-objects' process"
-msgstr "kunde inte avsluta \"git pack-objects\"-process"
+msgstr "misslyckades att avsluta â€git pack-objectsâ€-process"
msgid "failed to write multi-pack-index"
-msgstr "kunde inte skriva multi-pack-index"
+msgstr "misslyckades skriva multi-pack-index"
msgid "'git multi-pack-index expire' failed"
-msgstr "\"git multi-pack-index expire\" misslyckades"
+msgstr "â€git multi-pack-index expire†misslyckades"
msgid "'git multi-pack-index repack' failed"
-msgstr "\"git multi-pack-index repack\" misslyckades"
+msgstr "â€git multi-pack-index repack†misslyckades"
msgid ""
"skipping incremental-repack task because core.multiPackIndex is disabled"
msgstr ""
-"hoppar över \"incremental-repack\"-uppgift eftersom core.multiPackIndex är "
+"hoppar över â€incremental-repackâ€-uppgift eftersom core.multiPackIndex är "
"inaktiverat"
#, c-format
msgid "lock file '%s' exists, skipping maintenance"
-msgstr "låsfilen \"%s\" finns, hoppar över underhåll"
+msgstr "lÃ¥sfilen â€%s†finns, hoppar över underhÃ¥ll"
#, c-format
msgid "task '%s' failed"
-msgstr "uppgiften \"%s\" misslyckades"
+msgstr "uppgiften â€%s†misslyckades"
#, c-format
msgid "'%s' is not a valid task"
-msgstr "\"%s\" är inte en giltig uppgift"
+msgstr "â€%s†är inte en giltig uppgift"
#, c-format
msgid "task '%s' cannot be selected multiple times"
-msgstr "uppgiften \"%s\" kan inte väljas flera gånger"
+msgstr "uppgiften â€%s†kan inte väljas flera gÃ¥nger"
msgid "run tasks based on the state of the repository"
msgstr "kör uppgifter baserad på arkivets tillstånd"
+msgid "perform maintenance in the background"
+msgstr "utför underhåll i bakgrunden"
+
msgid "frequency"
msgstr "frekvens"
@@ -6565,29 +6715,29 @@ msgstr "använd som mest en av --auto och --schedule=<frekvens>"
#, c-format
msgid "unable to add '%s' value of '%s'"
-msgstr "kan inte lägga till \"%s\"-värdet för \"%s\""
+msgstr "kan inte lägga till â€%sâ€-värdet för â€%sâ€"
msgid "return success even if repository was not registered"
msgstr "returnera framgång även om arkivet inte var registrerat"
#, c-format
msgid "unable to unset '%s' value of '%s'"
-msgstr "kan inte ta bort \"%s\"-värdet för \"%s\""
+msgstr "kan inte ta bort â€%sâ€-värdet för â€%sâ€"
#, c-format
msgid "repository '%s' is not registered"
-msgstr "arkivet \"%s\" har inte registrerats"
+msgstr "arkivet â€%s†har inte registrerats"
#, c-format
msgid "failed to expand path '%s'"
-msgstr "misslyckades expandera sökvägen \"%s\""
+msgstr "misslyckades expandera sökvägen â€%sâ€"
msgid "failed to start launchctl"
msgstr "misslyckades starta launchctl"
#, c-format
msgid "failed to create directories for '%s'"
-msgstr "misslyckades skapa kataloger för \"%s\""
+msgstr "misslyckades skapa kataloger för â€%sâ€"
#, c-format
msgid "failed to bootstrap service %s"
@@ -6600,8 +6750,7 @@ msgid "failed to start schtasks"
msgstr "misslyckades starta schtasks"
msgid "failed to run 'crontab -l'; your system might not support 'cron'"
-msgstr ""
-"misslyckades köra \"crontab -l\"; ditt system kanske inte stöder \"cron\""
+msgstr "misslyckades köra â€crontab -lâ€; ditt system kanske inte stöder â€cronâ€"
msgid "failed to create crontab temporary file"
msgstr "misslyckades skapa temporär crontab-fil"
@@ -6610,28 +6759,28 @@ msgid "failed to open temporary file"
msgstr "misslyckades öppna temporär fil"
msgid "failed to run 'crontab'; your system might not support 'cron'"
-msgstr "misslyckades köra \"crontab\"; ditt system kanske inte stöder \"cron\""
+msgstr "misslyckades köra â€crontabâ€; ditt system kanske inte stöder â€cronâ€"
msgid "'crontab' died"
-msgstr "\"crontab\" dog"
-
-msgid "failed to start systemctl"
-msgstr "misslyckades starta systemctl"
-
-msgid "failed to run systemctl"
-msgstr "misslyckades att köra systemctl"
+msgstr "â€crontab†dog"
#, c-format
msgid "failed to delete '%s'"
-msgstr "misslyckades ta bort \"%s\""
+msgstr "misslyckades ta bort â€%sâ€"
#, c-format
msgid "failed to flush '%s'"
-msgstr "misslyckades spola \"%s\""
+msgstr "misslyckades spola â€%sâ€"
+
+msgid "failed to start systemctl"
+msgstr "misslyckades starta systemctl"
+
+msgid "failed to run systemctl"
+msgstr "misslyckades att köra systemctl"
#, c-format
msgid "unrecognized --scheduler argument '%s'"
-msgstr "okänt argument för --scheduler, \"%s\""
+msgstr "okänt argument för --scheduler, â€%sâ€"
msgid "neither systemd timers nor crontab are available"
msgstr "varken systemd-timer eller crontab är tillgänglig"
@@ -6650,7 +6799,10 @@ msgid "scheduler"
msgstr "schemaläggare"
msgid "scheduler to trigger git maintenance run"
-msgstr "schemaläggare som utlöser \"git maintenance\"-körning"
+msgstr "schemaläggare som utlöser â€git maintenanceâ€-körning"
+
+msgid "failed to set up maintenance schedule"
+msgstr "misslyckades uppdatera underhållsschema"
msgid "failed to add repo to global config"
msgstr "misslyckades lägga till arkiv till global konfiguration"
@@ -6679,16 +6831,16 @@ msgid "no threads support, ignoring %s"
msgstr "trådstöd saknas, ignorerar %s"
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "kunde inte läsa träd (%s)"
+msgid "unable to read tree %s"
+msgstr "kan inte läsa trädet %s"
#, c-format
msgid "unable to grep from object of type %s"
-msgstr "kunde inte \"grep\" från objekt av typen %s"
+msgstr "kan inte â€grep†frÃ¥n objekt av typen %s"
#, c-format
msgid "switch `%c' expects a numerical value"
-msgstr "flaggan \"%c\" antar ett numeriskt värde"
+msgstr "flaggan â€%c†antar ett numeriskt värde"
msgid "search in index instead of in the work tree"
msgstr "sök i indexet istället för i arbetskatalogen"
@@ -6700,7 +6852,7 @@ msgid "search in both tracked and untracked files"
msgstr "sök i både spårade och ospårade filer"
msgid "ignore files specified via '.gitignore'"
-msgstr "ignorera filer angivna i \".gitignore\""
+msgstr "ignorera filer angivna i â€.gitignoreâ€"
msgid "recursively search in each submodule"
msgstr "sök varje undermodul rekursivt"
@@ -6726,8 +6878,8 @@ msgstr "hantera binärfiler med textconv-filter"
msgid "search in subdirectories (default)"
msgstr "sök i underkataloger (standard)"
-msgid "descend at most <depth> levels"
-msgstr "gå som mest ned <djup> nivåer"
+msgid "descend at most <n> levels"
+msgstr "gå som mest ned <n> nivåer"
msgid "use extended POSIX regular expressions"
msgstr "använd utökade POSIX-reguljära uttryck"
@@ -6934,41 +7086,41 @@ msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<kommando>|<doc>]"
#, c-format
msgid "unrecognized help format '%s'"
-msgstr "okänt hjälpformat: \"%s\""
+msgstr "okänt hjälpformat: â€%sâ€"
msgid "Failed to start emacsclient."
msgstr "Misslyckades starta emacsclient."
msgid "Failed to parse emacsclient version."
-msgstr "Kunde inte tolka emacsclient-version."
+msgstr "Misslyckades tolka emacsclient-version."
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
-msgstr "emacsclient version \"%d\" för gammal (< 22)."
+msgstr "emacsclient version â€%d†för gammal (< 22)."
#, c-format
msgid "failed to exec '%s'"
-msgstr "exec misslyckades för \"%s\""
+msgstr "â€exec†misslyckades för â€%sâ€"
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
"Please consider using 'man.<tool>.cmd' instead."
msgstr ""
-"\"%s\": sökväg för man-visare som ej stöds.\n"
-"Använd \"man.<verktyg>.cmd\" istället."
+"â€%sâ€: sökväg för man-visare som ej stöds.\n"
+"Använd â€man.<verktyg>.cmd†istället."
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
"Please consider using 'man.<tool>.path' instead."
msgstr ""
-"\"%s\": kommando för man-visare som stöds.\n"
-"Använd \"man.<verktyg>.path\" istället."
+"â€%sâ€: kommando för man-visare som stöds.\n"
+"Använd â€man.<verktyg>.path†istället."
#, c-format
msgid "'%s': unknown man viewer."
-msgstr "\"%s\": okänd man-visare."
+msgstr "â€%sâ€: okänd man-visare."
msgid "no man viewer handled the request"
msgstr "ingen man-visare hanterade förfrågan"
@@ -6978,7 +7130,7 @@ msgstr "ingen info-visare hanterade förfrågan"
#, c-format
msgid "'%s' is aliased to '%s'"
-msgstr "\"%s\" är ett alias för \"%s\""
+msgstr "â€%s†är ett alias för â€%sâ€"
#, c-format
msgid "bad alias.%s string: %s"
@@ -6986,20 +7138,19 @@ msgstr "felaktig alias.%s-sträng: %s"
#, c-format
msgid "the '%s' option doesn't take any non-option arguments"
-msgstr "flaggan \"%s\" tar inte några argument som inte är flaggor"
+msgstr "flaggan â€%s†tar inte nÃ¥gra argument som inte är flaggor"
msgid ""
"the '--no-[external-commands|aliases]' options can only be used with '--all'"
msgstr ""
-"flaggorna '--no-[external-commands|aliases]' kan endast användas med \"--all"
-"\""
+"flaggorna '--no-[external-commands|aliases]' kan endast användas med â€--allâ€"
#, c-format
msgid "usage: %s%s"
msgstr "användning: %s%s"
msgid "'git help config' for more information"
-msgstr "\"git help config\" för mer information"
+msgstr "â€git help config†för mer information"
msgid ""
"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
@@ -7074,7 +7225,7 @@ msgid "unknown object type %d"
msgstr "okänd objekttyp %d"
msgid "cannot pread pack file"
-msgstr "kan inte utföra \"pread\" på paketfil"
+msgstr "kan inte utföra â€pread†pÃ¥ paketfil"
#, c-format
msgid "premature end of pack file, %<PRIuMAX> byte missing"
@@ -7090,10 +7241,6 @@ msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "SHA1-KOLLISION UPPTÄCKT VID %s !"
#, c-format
-msgid "unable to read %s"
-msgstr "kunde inte läsa %s"
-
-#, c-format
msgid "cannot read existing object info %s"
msgstr "kan inte läsa information om befintligt objekt %s"
@@ -7125,7 +7272,7 @@ msgid "pack is corrupted (SHA1 mismatch)"
msgstr "paketet är trasigt (SHA1 stämmer inte)"
msgid "cannot fstat packfile"
-msgstr "kan inte utföra \"fstat\" på paketfil"
+msgstr "kan inte utföra â€fstat†pÃ¥ paketfil"
msgid "pack has junk at the end"
msgstr "paket har skräp i slutet"
@@ -7138,7 +7285,7 @@ msgstr "Analyserar delta"
#, c-format
msgid "unable to create thread: %s"
-msgstr "kunde inte skapa tråd: %s"
+msgstr "kan inte skapa tråd: %s"
msgid "confusion beyond insanity"
msgstr "förvirrad bortom vanvett"
@@ -7161,7 +7308,7 @@ msgstr[1] "paketet har %d oanalyserade delta"
#, c-format
msgid "unable to deflate appended object (%d)"
-msgstr "kunde inte utföra \"deflate\" på tillagt objekt (%d)"
+msgstr "kan inte utföra â€deflate†pÃ¥ tillagt objekt (%d)"
#, c-format
msgid "local object %s is corrupt"
@@ -7169,19 +7316,19 @@ msgstr "lokalt objekt %s är trasigt"
#, c-format
msgid "packfile name '%s' does not end with '.%s'"
-msgstr "paketfilnamnet \"%s\" slutar inte med \".%s\""
+msgstr "paketfilnamnet â€%s†slutar inte med â€.%sâ€"
#, c-format
msgid "cannot write %s file '%s'"
-msgstr "kan inte ta skriva %s-fil \"%s\""
+msgstr "kan inte ta skriva %s-fil â€%sâ€"
#, c-format
msgid "cannot close written %s file '%s'"
-msgstr "kan inte stänga skriven %s-fil \"%s\""
+msgstr "kan inte stänga skriven %s-fil â€%sâ€"
#, c-format
msgid "unable to rename temporary '*.%s' file to '%s'"
-msgstr "kunde inte byta namn på temporär \"*.%s\"-fil till \"%s\""
+msgstr "kan inte byta namn pÃ¥ temporär â€*.%sâ€-fil till â€%sâ€"
msgid "error while closing pack file"
msgstr "fel vid stängning av paketfil"
@@ -7192,11 +7339,11 @@ msgstr "felaktig pack.indexVersion=%<PRIu32>"
#, c-format
msgid "Cannot open existing pack file '%s'"
-msgstr "Kan inte öppna befintlig paketfil \"%s\""
+msgstr "Kan inte öppna befintlig paketfil â€%sâ€"
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
-msgstr "Kan inte öppna befintlig paket-idx-fil för \"%s\""
+msgstr "Kan inte öppna befintlig paket-idx-fil för â€%sâ€"
#, c-format
msgid "non delta: %d object"
@@ -7219,7 +7366,7 @@ msgstr "felaktig %s"
#, c-format
msgid "unknown hash algorithm '%s'"
-msgstr "okänd hashningsalgoritm \"%s\""
+msgstr "okänd hashningsalgoritm â€%sâ€"
msgid "--stdin requires a git repository"
msgstr "--stdin kräver ett git-arkiv"
@@ -7233,11 +7380,13 @@ 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"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
"git init [-q | --quiet] [--bare] [--template=<mallkatalog>]\n"
" [--separate-git-dir <git-kat>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <grennamn> | --initial-branch=<grennamn>]\n"
" [--shared[=<behörigheter>]] [<katalog>]"
@@ -7274,26 +7423,56 @@ msgstr ""
#, c-format
msgid "Cannot access work tree '%s'"
-msgstr "Kan inte komma åt arbetskatalogen \"%s\""
+msgstr "Kan inte komma Ã¥t arbetskatalogen â€%sâ€"
msgid "--separate-git-dir incompatible with bare repository"
msgstr "--separate-git-dir är inkompatibelt med naket arkiv"
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <symbol>[(=|:)<värde>])...]\n"
+" [(--trailer (<nyckel>|<nyckel-alias>)"
+"[(=|:)<värde>])...]\n"
" [--parse] [<fil>...]"
+#, c-format
+msgid "could not stat %s"
+msgstr "kunde inte ta status på %s"
+
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "filen %s är inte en normal fil"
+
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "filen %s är inte skrivbar av användaren"
+
+msgid "could not open temporary file"
+msgstr "kunde inte öppna temporär fil"
+
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "kunde inte läsa indatafilen â€%sâ€"
+
+msgid "could not read from stdin"
+msgstr "kunde inte läsa från standard in"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "kunde inte byta namn på temporär fil till %s"
+
msgid "edit files in place"
msgstr "redigera filer på plats"
msgid "trim empty trailers"
msgstr "ta bort tomma släprader"
+msgid "placement"
+msgstr "placering"
+
msgid "where to place the new trailer"
msgstr "var nya släprader ska placeras"
@@ -7306,17 +7485,17 @@ msgstr "att göra om släprader saknas"
msgid "output only the trailers"
msgstr "visa endast släprader"
-msgid "do not apply config rules"
-msgstr "använd inte regler från konfigurationen"
+msgid "do not apply trailer.* configuration variables"
+msgstr "tillämpa inte konfigurationsvariablerna trailer.*"
-msgid "join whitespace-continued values"
-msgstr "slå ihop värden avdelade med blanksteg"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "omformatera flerradiga släpradsvärden som enradsvärden"
-msgid "set parsing options"
-msgstr "välj tolkningsalternativ"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "alias för --only-trailers --only-input --unfold"
-msgid "do not treat --- specially"
-msgstr "tolka inte --- speciellt"
+msgid "do not treat \"---\" as the end of input"
+msgstr "tolka inte â€---†som slut pÃ¥ indata"
msgid "trailer(s) to add"
msgstr "släprad(er) att lägga till"
@@ -7373,9 +7552,6 @@ msgstr "-L<intervall>:<fil> kan inte användas med sökvägsspecifikation"
msgid "Final output: %d %s\n"
msgstr "Slututdata: %d %s\n"
-msgid "unable to create temporary object directory"
-msgstr "kunde inte skapa temporär objektkatalog"
-
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: felaktig fil"
@@ -7405,6 +7581,10 @@ msgstr "behöver precis ett intervall"
msgid "not a range"
msgstr "inte ett intervall"
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "kan inte läsa grenbeskrivningsfilen â€%sâ€"
+
msgid "cover letter needs email format"
msgstr "omslagsbrevet behöver e-postformat"
@@ -7427,7 +7607,7 @@ msgstr "okänd incheckning %s"
#, c-format
msgid "failed to resolve '%s' as a valid ref"
-msgstr "misslyckades slå upp \"%s\" som en giltig referens"
+msgstr "misslyckades slÃ¥ upp â€%s†som en giltig referens"
msgid "could not find exact merge base"
msgstr "kunde inte hitta exakt sammanslagningsbas"
@@ -7437,12 +7617,12 @@ msgid ""
"please use git branch --set-upstream-to to track a remote branch.\n"
"Or you could specify base commit by --base=<base-commit-id> manually"
msgstr ""
-"kunde inte hämta uppström, om du vill lagra basincheckningen automatiskt,\n"
+"misslyckades hämta uppström, om du vill lagra basincheckningen automatiskt,\n"
"använd git branch --set-upstream-to för att spåra en fjärrgren.\n"
"Eller så kan du ange basincheckning med --base=<bas-inchecknings-id> manuellt"
msgid "failed to find exact merge base"
-msgstr "kunde inte hitta exakt sammanslagningsbas"
+msgstr "misslyckades hitta exakt sammanslagningsbas"
msgid "base commit should be the ancestor of revision list"
msgstr "basincheckningen bör vara förfader till revisionslistan"
@@ -7458,7 +7638,7 @@ msgstr "misslyckades räkna ut intervalldiff-ursprung för aktuell serie"
#, c-format
msgid "using '%s' as range-diff origin of current series"
-msgstr "använd \"%s\" som intervalldiff-ursprung för aktuell serie"
+msgstr "använd â€%s†som intervalldiff-ursprung för aktuell serie"
msgid "use [PATCH n/m] even with a single patch"
msgstr "använd [PATCH n/m] även för en ensam patch"
@@ -7479,7 +7659,7 @@ msgid "sfx"
msgstr "sfx"
msgid "use <sfx> instead of '.patch'"
-msgstr "använd <sfx> istället för \".patch\""
+msgstr "använd <sfx> istället för â€.patchâ€"
msgid "start numbering patches at <n> instead of 1"
msgstr "börja numrera patchar på <n> istället för 1"
@@ -7493,8 +7673,11 @@ msgstr "markera serien som N:te försök"
msgid "max length of output filename"
msgstr "maximal längd för utdatafilnamn"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "använd [RFC PATCH] istället för [PATCH]"
+msgid "rfc"
+msgstr "rfc"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "lägg till <rfc> (förval â€RFCâ€) före â€PATCHâ€"
msgid "cover-from-description-mode"
msgstr "cover-from-description-läge"
@@ -7502,6 +7685,9 @@ msgstr "cover-from-description-läge"
msgid "generate parts of a cover letter based on a branch's description"
msgstr "skapa delar av omslagsbrevet baserat på grenbeskrivelsen"
+msgid "use branch description from file"
+msgstr "använd grenbeskrivningar från fil"
+
msgid "use [<prefix>] instead of [PATCH]"
msgstr "använd [<prefix>] istället för [PATCH]"
@@ -7536,10 +7722,10 @@ msgid "email"
msgstr "epost"
msgid "add To: header"
-msgstr "lägg till mottagarhuvud (\"To:\")"
+msgstr "lägg till mottagarhuvud (â€To:â€)"
msgid "add Cc: header"
-msgstr "lägg till kopiehuvud (\"Cc:\")"
+msgstr "lägg till kopiehuvud (â€Cc:â€)"
msgid "ident"
msgstr "ident"
@@ -7616,7 +7802,7 @@ msgstr "kan inte använda --remerge-diff"
#, c-format
msgid "could not create directory '%s'"
-msgstr "kunde inte skapa katalogen \"%s\""
+msgstr "kunde inte skapa katalogen â€%sâ€"
msgid "--interdiff requires --cover-letter or single patch"
msgstr "--interdiff kräver --cover-letter eller ensam patch"
@@ -7640,7 +7826,7 @@ msgstr "Intervall-diff mot v%d:"
#, c-format
msgid "unable to read signature file '%s'"
-msgstr "kunde inte läsa signaturfil \"%s\""
+msgstr "kan inte läsa signaturfil â€%sâ€"
msgid "Generating patches"
msgstr "Skapar patchar"
@@ -7658,19 +7844,7 @@ 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 \"(\""
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "felaktigt ls-files-format: elementet \"%s\" slutar inte med \")\""
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "felaktigt ls-files-format: %%%.*s"
+msgstr "kunde inte hämta objektinfo om â€%sâ€"
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<flaggor>] [<fil>...]"
@@ -7682,10 +7856,10 @@ msgid "identify the file status with tags"
msgstr "identifiera filstatus med taggar"
msgid "use lowercase letters for 'assume unchanged' files"
-msgstr "använd små bokstäver för \"anta oförändrade\"-filer"
+msgstr "använd smÃ¥ bokstäver för â€anta oförändradeâ€-filer"
msgid "use lowercase letters for 'fsmonitor clean' files"
-msgstr "använd små bokstäver för \"fsmonitor clean\"-filer"
+msgstr "använd smÃ¥ bokstäver för â€fsmonitor cleanâ€-filer"
msgid "show cached files in the output (default)"
msgstr "visa cachade filer i utdata (standard)"
@@ -7709,7 +7883,7 @@ msgid "show files on the filesystem that need to be removed"
msgstr "visa filer i filsystemet som behöver tas bort"
msgid "show 'other' directories' names only"
-msgstr "visa endast namn för \"andra\" kataloger"
+msgstr "visa endast namn för â€andra†kataloger"
msgid "show line endings of files"
msgstr "visa radslut i filer"
@@ -7721,7 +7895,7 @@ msgid "show unmerged files in the output"
msgstr "visa ej sammanslagna filer i utdata"
msgid "show resolve-undo information"
-msgstr "visa \"resolve-undo\"-information"
+msgstr "visa â€resolve-undoâ€-information"
msgid "skip files matching pattern"
msgstr "hoppa över filer som motsvarar mönster"
@@ -7764,11 +7938,11 @@ msgstr ""
"deduplicate, --eol"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<exec>]\n"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<nyckel>]\n"
" [--symref] [<arkiv> [<mönster>...]]"
@@ -7784,8 +7958,11 @@ msgstr "sökväg till git-upload-pack på fjärren"
msgid "limit to tags"
msgstr "begränsa till taggar"
-msgid "limit to heads"
-msgstr "begränsa till huvuden"
+msgid "limit to branches"
+msgstr "begränsa till grenar"
+
+msgid "deprecated synonym for --branches"
+msgstr "föråldrad synonym till --branches"
msgid "do not show peeled tags"
msgstr "visa inte avskalade taggar"
@@ -7802,18 +7979,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 "bad ls-tree format: element '%s' does not start with '('"
-msgstr "felaktigt ls-tree-format: elementet \"%s\" börjar inte med \"(\""
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "felaktigt ls-tree-format: elementet \"%s\" slutar inte med \")\""
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "felaktigt ls-tree-format: %%%.*s"
-
msgid "only show trees"
msgstr "visa endast träd"
@@ -7852,7 +8017,7 @@ msgid "keep subject"
msgstr "behåll ärenderad"
msgid "keep non patch brackets in subject"
-msgstr "behåll hakparanterser som inte är \"patch\" i ärenderaden"
+msgstr "behÃ¥ll hakparanterser som inte är â€patch†i ärenderaden"
msgid "copy Message-ID to the end of commit message"
msgstr "kopiera Message-ID till slutet av incheckningsmeddelandet"
@@ -7886,7 +8051,7 @@ msgstr "läser patchar från standard in/tty..."
#, c-format
msgid "empty mbox: '%s'"
-msgstr "tom mbox: \"%s\""
+msgstr "tom mbox: â€%sâ€"
msgid "git merge-base [-a | --all] <commit> <commit>..."
msgstr "git merge-base [-a | --all] <incheckning> <incheckning>..."
@@ -7925,23 +8090,29 @@ msgstr ""
"git merge-file [<alternativ>] [-L <namn1> [-L <orig> [-L <namn2>]]] <fil1> "
"<origfil> <fil2>"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"flaggan diff-algorithm godtar â€myersâ€, â€minimalâ€, â€patience†och â€histogramâ€"
+
msgid "send results to standard output"
msgstr "sänd resultat till standard ut"
+msgid "use object IDs instead of filenames"
+msgstr "använd objekt-ID istället för filnamn"
+
msgid "use a diff3 based merge"
msgstr "använd diff3-baserad sammanslagning"
msgid "use a zealous diff3 based merge"
msgstr "använd nitisk diff3-baserad sammanslagning"
-msgid "for conflicts, use our version"
-msgstr "för konflikter, använd vår version"
-
-msgid "for conflicts, use their version"
-msgstr "för konflikter, använd deras version"
+msgid "<algorithm>"
+msgstr "<algoritm>"
-msgid "for conflicts, use a union version"
-msgstr "för konflikter, använd en förenad version"
+msgid "choose a diff algorithm"
+msgstr "välj en diff-algoritm"
msgid "for conflicts, use this marker size"
msgstr "för konflikter, använd denna markörstorlek"
@@ -7953,12 +8124,19 @@ msgid "set labels for file1/orig-file/file2"
msgstr "sätt etiketter för fil1/origfil/fil2"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "objektet â€%s†finns inte"
+
+msgid "Could not write object file"
+msgstr "Kunde inte skriva objektfilen"
+
+#, c-format
msgid "unknown option %s"
msgstr "okänd flagga %s"
#, c-format
msgid "could not parse object '%s'"
-msgstr "kunde inte tolka objektet \"%s\""
+msgstr "kunde inte tolka objektet â€%sâ€"
#, c-format
msgid "cannot handle more than %d base. Ignoring %s."
@@ -7971,12 +8149,16 @@ msgstr "hanterar inte något annat än en sammanslagning av två huvuden."
#, c-format
msgid "could not resolve ref '%s'"
-msgstr "kunde inte bestämma referensen \"%s\""
+msgstr "kunde inte bestämma referensen â€%sâ€"
#, c-format
msgid "Merging %s with %s\n"
msgstr "Slår ihop %s med %s\n"
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "kunde inte tolka som träd â€%sâ€"
+
msgid "not something we can merge"
msgstr "inte något vi kan slå ihop"
@@ -8013,15 +8195,22 @@ msgstr "utför flera sammanslagningar, en per indatarad"
msgid "specify a merge-base for the merge"
msgstr "ange en sammanslagningsbas för sammanslagningen"
+msgid "option=value"
+msgstr "alternativ=värde"
+
+msgid "option for selected merge strategy"
+msgstr "alternativ för vald sammanslagningsstrategi"
+
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge är inkompatibelt med andra flaggor"
-msgid "--merge-base is incompatible with --stdin"
-msgstr "--merge-base är inkompatibel med --stdin"
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "okänd strategiflagga: -X%s"
#, c-format
msgid "malformed input line: '%s'."
-msgstr "felaktig indatarad: \"%s\"."
+msgstr "felaktig indatarad: â€%sâ€."
#, c-format
msgid "merging cannot continue; got unclean result of %d"
@@ -8031,15 +8220,15 @@ msgid "git merge [<options>] [<commit>...]"
msgstr "git merge [<flaggor>] [<incheckning>...]"
msgid "switch `m' requires a value"
-msgstr "flaggan \"m\" behöver ett värde"
+msgstr "flaggan â€m†behöver ett värde"
#, c-format
msgid "option `%s' requires a value"
-msgstr "flaggan \"%s\" behöver ett värde"
+msgstr "flaggan â€%s†behöver ett värde"
#, c-format
msgid "Could not find merge strategy '%s'.\n"
-msgstr "Kunde inte hitta sammanslagningsstrategin \"%s\".\n"
+msgstr "Kunde inte hitta sammanslagningsstrategin â€%sâ€.\n"
#, c-format
msgid "Available strategies are:"
@@ -8086,12 +8275,6 @@ msgstr "strategi"
msgid "merge strategy to use"
msgstr "sammanslagningsstrategi att använda"
-msgid "option=value"
-msgstr "alternativ=värde"
-
-msgid "option for selected merge strategy"
-msgstr "alternativ för vald sammanslagningsstrategi"
-
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "incheckningsmeddelande för (icke snabbspolande) sammanslagning"
@@ -8139,35 +8322,30 @@ msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n"
#, c-format
msgid "'%s' does not point to a commit"
-msgstr "\"%s\" verkar inte peka på en incheckning"
+msgstr "â€%s†verkar inte peka pÃ¥ en incheckning"
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Felaktig branch.%s.mergeoptions-sträng: %s"
msgid "Unable to write index."
-msgstr "Kunde inte skriva indexet."
+msgstr "Kan inte skriva indexet."
msgid "Not handling anything other than two heads merge."
msgstr "Hanterar inte något annat än en sammanslagning av två huvuden."
#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "okänd strategiflagga: -X%s"
-
-#, c-format
msgid "unable to write %s"
-msgstr "kunde inte skriva %s"
+msgstr "kan inte skriva %s"
#, c-format
msgid "Could not read from '%s'"
-msgstr "Kunde inte läsa från \"%s\""
+msgstr "Kunde inte läsa frÃ¥n â€%sâ€"
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
-"Checkar inte in sammanslagningen; använd \"git commit\" för att slutföra "
-"den.\n"
+"Checkar inte in sammanslagningen; använd â€git commit†för att slutföra den.\n"
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -8184,10 +8362,10 @@ msgstr "Ett tomt meddelande avbryter incheckningen.\n"
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Rader som inleds med \"%c\" kommer ignoreras, och ett tomt meddelande\n"
+"Rader som inleds med â€%s†kommer ignoreras, och ett tomt meddelande\n"
"avbryter incheckningen.\n"
msgid "Empty commit message."
@@ -8217,11 +8395,11 @@ msgstr "Ingen fjärrspårande gren för %s från %s"
#, c-format
msgid "Bad value '%s' in environment '%s'"
-msgstr "Felaktigt värde \"%s\" i miljövariabeln \"%s\""
+msgstr "Felaktigt värde â€%s†i miljövariabeln â€%sâ€"
#, c-format
msgid "could not close '%s'"
-msgstr "kunde inte stänga \"%s\""
+msgstr "kunde inte stänga â€%sâ€"
#, c-format
msgid "not something we can merge in %s: %s"
@@ -8253,11 +8431,11 @@ msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."
msgstr ""
-"Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns).\n"
+"Du har inte avslutat din â€cherry-pick†(CHERRY_PICK_HEAD finns).\n"
"Checka in dina ändringar innan du slår ihop."
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
-msgstr "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns)."
+msgstr "Du har inte avslutat din â€cherry-pick†(CHERRY_PICK_HEAD finns)."
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt."
@@ -8323,7 +8501,7 @@ msgstr ""
#, c-format
msgid "When finished, apply stashed changes with `git stash pop`\n"
-msgstr "När färdig, applicerade sparade ändringar med \"git stash pop\"\n"
+msgstr "När färdig, applicerade sparade ändringar med â€git stash popâ€\n"
#, c-format
msgid "warning: tag input does not pass fsck: %s"
@@ -8339,14 +8517,11 @@ msgstr "%d (FSCK_IGNORE?) skulle aldrig utlösa detta återanrop"
#, c-format
msgid "could not read tagged object '%s'"
-msgstr "kunde inte läsa det taggade objektet \"%s\""
+msgstr "kunde inte läsa det taggade objektet â€%sâ€"
#, c-format
msgid "object '%s' tagged as '%s', but is a '%s' type"
-msgstr "objektet \"%s\" taggat som \"%s\", men är av typen \"%s\""
-
-msgid "could not read from stdin"
-msgstr "kunde inte läsa från standard in"
+msgstr "objektet â€%s†taggat som â€%sâ€, men är av typen â€%sâ€"
msgid "tag on stdin did not pass our strict fsck check"
msgstr "tagg på stdin godkänns inte av vår strikta fsck-kontroll"
@@ -8355,7 +8530,7 @@ msgid "tag on stdin did not refer to a valid object"
msgstr "taggen på stdin pekar inte på ett giltigt objekt"
msgid "unable to write tag file"
-msgstr "kunde inte skriva tagg-filen"
+msgstr "kan inte skriva tagg-filen"
msgid "input is NUL terminated"
msgstr "indata är NUL-terminerad"
@@ -8397,6 +8572,9 @@ msgstr "paket att återanvända vid beräkning av multipaketsbitkarta"
msgid "write multi-pack bitmap"
msgstr "skriv flerpaketsbitkarta"
+msgid "write a new incremental MIDX"
+msgstr "skriv en ny inkrementell MIDX"
+
msgid "write multi-pack index containing only given indexes"
msgstr "skriv flerpaketsindex som endast innehåller angivna index"
@@ -8419,7 +8597,7 @@ msgstr "Katalogen %s är i indexet och inte en undermodul?"
msgid "Please stage your changes to .gitmodules or stash them to proceed"
msgstr ""
-"Köa dina ändringar i .gitmodules eller använd \"stash\" för att fortsätta"
+"Köa dina ändringar i .gitmodules eller använd â€stash†för att fortsätta"
#, c-format
msgid "%.*s is in index"
@@ -8433,11 +8611,11 @@ msgstr "hoppa över fel vid flytt/namnändring"
#, c-format
msgid "destination '%s' is not a directory"
-msgstr "destinationen \"%s\" är ingen katalog"
+msgstr "destinationen â€%s†är ingen katalog"
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
-msgstr "Kontrollerar namnbyte av \"%s\" till \"%s\"\n"
+msgstr "Kontrollerar namnbyte av â€%s†till â€%sâ€\n"
msgid "bad source"
msgstr "felaktig källa"
@@ -8448,8 +8626,8 @@ msgstr "destinationen finns"
msgid "can not move directory into itself"
msgstr "kan inte flytta katalog till sig själv"
-msgid "cannot move directory over file"
-msgstr "kan inte flytta katalog över fil"
+msgid "destination already exists"
+msgstr "destinationen finns redan"
msgid "source directory is empty"
msgstr "källkatalogen är tom"
@@ -8462,7 +8640,7 @@ msgstr "i konflikt"
#, c-format
msgid "overwriting '%s'"
-msgstr "skriver över \"%s\""
+msgstr "skriver över â€%sâ€"
msgid "Cannot overwrite"
msgstr "Kan inte skriva över"
@@ -8486,7 +8664,7 @@ msgstr "Byter namn på %s till %s\n"
#, c-format
msgid "renaming '%s' failed"
-msgstr "misslyckades byta namn på \"%s\""
+msgstr "misslyckades byta namn pÃ¥ â€%sâ€"
msgid "git name-rev [<options>] <commit>..."
msgstr "git name-rev [<flaggor>] <incheckning>..."
@@ -8519,7 +8697,7 @@ msgid "annotate text from stdin"
msgstr "annotera text från standard in"
msgid "allow to print `undefined` names (default)"
-msgstr "tillåt att skriva \"odefinierade\" namn (standard)"
+msgstr "tillÃ¥t att skriva â€odefinierade†namn (standard)"
msgid "dereference tags in the input (internal use)"
msgstr "avreferera taggar i indata (används internt)"
@@ -8609,22 +8787,18 @@ msgstr "git notes prune [<flaggor>]"
msgid "Write/edit the notes for the following object:"
msgstr "Skriv/redigera anteckningar för följande objekt:"
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "kunde inte starta \"show\" för objektet \"%s\""
-
msgid "could not read 'show' output"
-msgstr "kunde inte läsa utdata från \"show\""
+msgstr "kan inte läsa utdata frÃ¥n â€showâ€"
#, c-format
msgid "failed to finish 'show' for object '%s'"
-msgstr "kunde inte avsluta \"show\" för objektet \"%s\""
+msgstr "misslyckades att avsluta â€show†för objektet â€%sâ€"
msgid "please supply the note contents using either -m or -F option"
msgstr "ange innehåll för anteckningen med antingen -m eller -F"
msgid "unable to write note object"
-msgstr "kunde inte skriva anteckningsobjekt"
+msgstr "kan inte skriva anteckningsobjekt"
#, c-format
msgid "the note contents have been left in %s"
@@ -8632,30 +8806,30 @@ msgstr "anteckningens innehåll har lämnats kvar i %s"
#, c-format
msgid "could not open or read '%s'"
-msgstr "kunde inte öppna eller läsa \"%s\""
+msgstr "kunde inte öppna eller läsa â€%sâ€"
#, c-format
msgid "failed to resolve '%s' as a valid ref."
-msgstr "kunde inte slå upp \"%s\" som en giltig referens."
+msgstr "misslyckades slÃ¥ upp â€%s†som en giltig referens."
#, c-format
msgid "failed to read object '%s'."
-msgstr "kunde inte läsa objektet \"%s\"."
+msgstr "misslyckades läsa objektet â€%sâ€."
#, c-format
msgid "cannot read note data from non-blob object '%s'."
-msgstr "kan inte läsa anteckningsdata från icke-blob-objektet \"%s\"."
+msgstr "kan inte läsa anteckningsdata frÃ¥n icke-blob-objektet â€%sâ€."
#, c-format
msgid "failed to copy notes from '%s' to '%s'"
-msgstr "misslyckades kopiera anteckningar från \"%s\" till \"%s\""
+msgstr "misslyckades kopiera anteckningar frÃ¥n â€%s†till â€%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 "vägrar utföra \"%s\" på anteckningar i %s (utanför refs/notes/)"
+msgstr "vägrar utföra â€%s†pÃ¥ anteckningar i %s (utanför refs/notes/)"
#, c-format
msgid "no note found for object %s."
@@ -8694,7 +8868,7 @@ msgid ""
"existing notes"
msgstr ""
"Kan inte lägga till anteckningar. Hittade befintliga anteckningar för "
-"objektet %s. Använd \"-f\" för att skriva över befintliga anteckningar"
+"objektet %s. Använd â€-f†för att skriva över befintliga anteckningar"
#, c-format
msgid "Overwriting existing notes for object %s\n"
@@ -8719,7 +8893,7 @@ msgid ""
"existing notes"
msgstr ""
"Kan inte kopiera anteckningar. Hittade befintliga anteckningar för objektet "
-"%s. Använd \"-f\" för att skriva över befintliga anteckningar"
+"%s. Använd â€-f†för att skriva över befintliga anteckningar"
#, c-format
msgid "missing notes on source object %s. Cannot copy."
@@ -8730,8 +8904,8 @@ 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 ""
-"Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot \"edit\".\n"
-"Använd \"git notes add -f -m/-F/-c/-C\" istället.\n"
+"Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot â€editâ€.\n"
+"Använd â€git notes add -f -m/-F/-c/-C†istället.\n"
msgid "failed to delete ref NOTES_MERGE_PARTIAL"
msgstr "misslyckades ta bort referensen NOTES_MERGE_PARTIAL"
@@ -8740,7 +8914,7 @@ msgid "failed to delete ref NOTES_MERGE_REF"
msgstr "misslyckades ta bort referensen NOTES_MERGE_REF"
msgid "failed to remove 'git notes merge' worktree"
-msgstr "misslyckades ta bort arbetskatalogen för \"git notes merge\""
+msgstr "misslyckades ta bort arbetskatalogen för â€git notes mergeâ€"
msgid "failed to read ref NOTES_MERGE_PARTIAL"
msgstr "misslyckades läsa references NOTES_MERGE_PARTIAL"
@@ -8813,12 +8987,12 @@ msgid ""
"abort'.\n"
msgstr ""
"Automatisk sammanslagning av anteckningar misslyckades. Rätta konflikter i "
-"%s och checka in resultatet med \"git notes merge --commit\", eller avbryt "
-"sammanslagningen med \"git notes merge --abort\".\n"
+"%s och checka in resultatet med â€git notes merge --commitâ€, eller avbryt "
+"sammanslagningen med â€git notes merge --abortâ€.\n"
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
-msgstr "Kunde inte slå upp \"%s\" som en giltig referens."
+msgstr "Misslyckades slÃ¥ upp â€%s†som en giltig referens."
#, c-format
msgid "Object %s has no note\n"
@@ -8844,7 +9018,7 @@ msgstr "använd anteckningar från <anteckningsref>"
#, c-format
msgid "unknown subcommand: `%s'"
-msgstr "okänt underkommando: \"%s\""
+msgstr "okänt underkommando: â€%sâ€"
msgid "git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"
msgstr "git pack-objects --stdout [<flaggor>] [< <reflista> | < <objektlista>]"
@@ -8895,7 +9069,7 @@ msgstr "misslyckades ta status på %s"
#, c-format
msgid "failed utime() on %s"
-msgstr "\"utime()\" misslyckades på %s"
+msgstr "â€utime()†misslyckades pÃ¥ %s"
msgid "failed to write bitmap index"
msgstr "misslyckade skriva bitkarteindex"
@@ -8924,7 +9098,7 @@ msgstr "kan inte hämta storlek på %s"
#, c-format
msgid "unable to parse object header of %s"
-msgstr "kunde inte tolka objekthuvud för %s"
+msgstr "kan inte tolka objekthuvud för %s"
#, c-format
msgid "object %s cannot be read"
@@ -8947,7 +9121,7 @@ msgstr "kan inte packa objekt nåbara från taggen %s"
#, c-format
msgid "unable to get type of object %s"
-msgstr "kunde inte hämta typ för objektet %s"
+msgstr "kan inte hämta typ för objektet %s"
msgid "Compressing objects"
msgstr "Komprimerar objekt"
@@ -8956,6 +9130,10 @@ msgid "inconsistency with delta count"
msgstr "deltaräknaren är inkonsekvent"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "felaktigt värde för pack.allowPackReuse: â€%sâ€"
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -8975,7 +9153,7 @@ msgstr "kunde inte hämta typ för objektet %s i paketet %s"
#, c-format
msgid "could not find pack '%s'"
-msgstr "kunde inte hitta paketet \"%s\""
+msgstr "kunde inte hitta paketet â€%sâ€"
#, c-format
msgid "packfile %s cannot be accessed"
@@ -9021,11 +9199,11 @@ msgstr "kan inte tvinga lösa objekt"
#, c-format
msgid "not a rev '%s'"
-msgstr "inte en referens \"%s\""
+msgstr "inte en referens â€%sâ€"
#, c-format
msgid "bad revision '%s'"
-msgstr "felaktig revision \"%s\""
+msgstr "felaktig revision â€%sâ€"
msgid "unable to add recent objects"
msgstr "kan inte lägga till nya objekt"
@@ -9036,7 +9214,7 @@ msgstr "indexversionen %s stöds ej"
#, c-format
msgid "bad index version '%s'"
-msgstr "felaktig indexversion \"%s\""
+msgstr "felaktig indexversion â€%sâ€"
msgid "show progress meter during object writing phase"
msgstr "visa förloppsindikator under objektskrivningsfasen"
@@ -9141,7 +9319,7 @@ msgid "pack compression level"
msgstr "komprimeringsgrad för paket"
msgid "do not hide commits by grafts"
-msgstr "göm inte incheckningar med ympningar (\"grafts\")"
+msgstr "göm inte incheckningar med ympningar (â€graftsâ€)"
msgid "use a bitmap index if available to speed up counting objects"
msgstr "använd bitkartindex om tillgängligt för att räkna objekt snabbare"
@@ -9190,9 +9368,6 @@ msgstr "minsta packstorlek är 1 MiB"
msgid "--thin cannot be used to build an indexable pack"
msgstr "--thin kan inte användas för att bygga ett indexerbart paket"
-msgid "cannot use --filter without --stdout"
-msgstr "kan inte använda --filter utan --stdout"
-
msgid "cannot use --filter with --stdin-packs"
msgstr "kan inte använda --filter med --stdin-packs"
@@ -9205,19 +9380,16 @@ msgstr "kan inte använda intern revisionslista med --cruft"
msgid "cannot use --stdin-packs with --cruft"
msgstr "kan inte använda --stdin-packs med --cruft"
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "kan inte använda --max-pack-size med --cruft"
-
msgid "Enumerating objects"
msgstr "Räknar upp objekt"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Totalt %<PRIu32> (delta %<PRIu32>), återanvände %<PRIu32> (delta %<PRIu32>), "
-"paket-återanvända %<PRIu32>"
+"paket-återanvända %<PRIu32> (från %<PRIuMAX>)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9226,9 +9398,9 @@ msgid ""
"and let us know you still use it by sending an e-mail\n"
"to <git@vger.kernel.org>. Thanks.\n"
msgstr ""
-"\"git pack-redundant\" har nominerats för borttagning.\n"
+"â€git pack-redundant†har nominerats för borttagning.\n"
"Om du fortfarande använder kommandot, lägg till flaggan\n"
-"\"--i-still-use-this\" på kommandoraden och berätta för\n"
+"â€--i-still-use-this†pÃ¥ kommandoraden och berätta för\n"
"oss att du fortfarande använder det på e-post till\n"
"<git@vger.kernel.org>. Tack.\n"
@@ -9236,10 +9408,10 @@ 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 "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <mönster>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <mönster>] [--exclude "
"<mönster>]"
msgid "pack everything"
@@ -9248,6 +9420,9 @@ msgstr "packa allt"
msgid "prune loose refs (default)"
msgstr "ta bort lösa referenser (standard)"
+msgid "auto-pack refs as needed"
+msgstr "packa referenser automatiskt om nödvändigt"
+
msgid "references to include"
msgstr "referenser att ta med"
@@ -9279,7 +9454,7 @@ msgid "limit traversal to objects outside promisor packfiles"
msgstr "begränsa vandring av objekt utanför kontraktspackfiler."
msgid "cannot prune in a precious-objects repo"
-msgstr "kan inte rensa i ett \"precious-objekt\"-arkiv"
+msgstr "kan inte rensa i ett â€precious-objektâ€-arkiv"
msgid "git pull [<options>] [<repository> [<refspec>...]]"
msgstr "git pull [<flaggor>] [<arkiv> [<refspec>...]]"
@@ -9343,7 +9518,7 @@ msgid ""
"a branch. Because this is not the default configured remote\n"
"for your current branch, you must specify a branch on the command line."
msgstr ""
-"Du bad om att hämta från fjärren \"%s\", men angav inte någon\n"
+"Du bad om att hämta frÃ¥n fjärren â€%sâ€, men angav inte nÃ¥gon\n"
"gren. Eftersom det inte är den fjärr som är konfigurerad som\n"
"standard för aktuell gren måste du ange en gren på kommandoraden."
@@ -9377,12 +9552,12 @@ msgid ""
"Your configuration specifies to merge with the ref '%s'\n"
"from the remote, but no such ref was fetched."
msgstr ""
-"Dina inställningar anger sammanslagning med referensen \"%s\"\n"
+"Dina inställningar anger sammanslagning med referensen â€%sâ€\n"
"från fjärren, men någon sådan referens togs inte emot."
#, c-format
msgid "unable to access commit %s"
-msgstr "kunde inte komma åt incheckningen %s"
+msgstr "kan inte komma åt incheckningen %s"
msgid "ignoring --verify-signatures for rebase"
msgstr "ignorera --verify-signatures för ombasering"
@@ -9404,13 +9579,13 @@ msgid ""
msgstr ""
"Du har avvikande grenar och måste ange hur de skall förlikas.\n"
"Du kan göra detta genom att köra ett av följande kommando innan du\n"
-"gör \"pull\" nästa gång: \n"
+"gör â€pull†nästa gÃ¥ng: \n"
"\n"
" git config pull.rebase false # sammanslagning\n"
" git config pull.rebase true # ombasering\n"
" git config pull.ff only # endast snabbspolning\n"
"\n"
-"Du kan ersätta \"git config\" med \"git config --global\" för att välja en\n"
+"Du kan ersätta â€git config†med â€git config --global†för att välja en\n"
"förvald inställning för alla arkiv. Du kan också ange --rebase, --no-rebase\n"
"eller --ff-only på kommandoraden för att överstyra det konfigurerade\n"
"förvalet vid körning.\n"
@@ -9422,7 +9597,7 @@ msgid "pull with rebase"
msgstr "pull med ombasering"
msgid "Please commit or stash them."
-msgstr "Checka in eller använd \"stash\" på dem."
+msgstr "Checka in eller använd â€stash†pÃ¥ dem."
#, c-format
msgid ""
@@ -9479,8 +9654,8 @@ msgid ""
"To choose either option permanently, see push.default in 'git help config'.\n"
msgstr ""
"\n"
-"För att välja ett av alternativen permanent, se push.default i \"git help "
-"config\".\n"
+"För att välja ett av alternativen permanent, se push.default i â€git help "
+"configâ€.\n"
msgid ""
"\n"
@@ -9490,9 +9665,9 @@ msgid ""
msgstr ""
"\n"
"För att undvika att en uppströmsgren automatiskt konfigureras när dess namn\n"
-"inte motsvarar den lokala grenen, se värdet \"simple\" i branch."
+"inte motsvarar den lokala grenen, se värdet â€simple†i branch."
"autoSetupMerge\n"
-"i \"git help config\".\n"
+"i â€git help configâ€.\n"
#, c-format
msgid ""
@@ -9539,7 +9714,7 @@ msgid ""
msgstr ""
"\n"
"För att detta ska ske automatiskt för grenar som saknar en spårande\n"
-"uppströmsgren, se \"push.autoSetupRemote\" i \"git help config\".\n"
+"uppströmsgren, se â€push.autoSetupRemote†i â€git help configâ€.\n"
#, c-format
msgid ""
@@ -9563,7 +9738,7 @@ msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
"Du angav inga referensspecifikationer att sända, och push.default är "
-"\"nothing\"."
+"â€nothingâ€."
#, c-format
msgid ""
@@ -9571,8 +9746,8 @@ msgid ""
"your current branch '%s', without telling me what to push\n"
"to update which remote branch."
msgstr ""
-"Du sänder till fjärren \"%s\", som inte är uppströms för den\n"
-"aktuella grenen \"%s\", utan att tala om för mig vad som\n"
+"Du sänder till fjärren â€%sâ€, som inte är uppströms för den\n"
+"aktuella grenen â€%sâ€, utan att tala om för mig vad som\n"
"ska sändas för att uppdatera fjärrgrenen."
msgid ""
@@ -9583,8 +9758,8 @@ msgid ""
msgstr ""
"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.\t\n"
-"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
+"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"
@@ -9593,10 +9768,9 @@ msgid ""
"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. Om du vill integrera fjärrändringarna, använd \"git pull"
-"\"\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."
+"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 not\n"
@@ -9607,9 +9781,9 @@ msgid ""
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. Om du vill integrera fjärrändringarna, använd \"git pull\"\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."
+"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."
msgstr "Uppdateringarna avvisades eftersom taggen redan finns på fjärren."
@@ -9622,7 +9796,7 @@ msgstr ""
"Du kan inte uppdatera en fjärr-referens som pekar på ett objekt som\n"
"inte är en incheckning, eller uppdatera en fjärr-referens så att den\n"
"pekar på något som inte är en incheckning, utan att använda flaggan\n"
-"\"--force\".\n"
+"â€--forceâ€.\n"
msgid ""
"Updates were rejected because the tip of the remote-tracking branch has\n"
@@ -9632,8 +9806,8 @@ msgid ""
msgstr ""
"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."
+"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"
@@ -9641,7 +9815,7 @@ msgstr "Sänder till %s\n"
#, c-format
msgid "failed to push some refs to '%s'"
-msgstr "misslyckades sända vissa referenser till \"%s\""
+msgstr "misslyckades sända vissa referenser till â€%sâ€"
msgid ""
"recursing into submodule with push.recurseSubmodules=only; using on-demand "
@@ -9652,7 +9826,7 @@ msgstr ""
#, c-format
msgid "invalid value for '%s'"
-msgstr "ogiltigt värde för \"%s\""
+msgstr "ogiltigt värde för â€%sâ€"
msgid "repository"
msgstr "arkiv"
@@ -9714,7 +9888,7 @@ msgstr "--delete kan inte användas utan referenser"
#, c-format
msgid "bad repository '%s'"
-msgstr "felaktigt arkiv \"%s\""
+msgstr "felaktigt arkiv â€%sâ€"
msgid ""
"No configured push destination.\n"
@@ -9762,7 +9936,7 @@ msgid "notes"
msgstr "anteckningar"
msgid "passed to 'git log'"
-msgstr "sänds till \"git log\""
+msgstr "sänds till â€git logâ€"
msgid "only emit output related to the first range"
msgstr "visa endast utdata för det första intervallet"
@@ -9772,15 +9946,15 @@ msgstr "visa endast utdata för det andra intervallet"
#, c-format
msgid "not a revision: '%s'"
-msgstr "inte en revision: \"%s\""
+msgstr "inte en revision: â€%sâ€"
#, c-format
msgid "not a commit range: '%s'"
-msgstr "inte ett incheckningsintervall: \"%s\""
+msgstr "inte ett incheckningsintervall: â€%sâ€"
#, c-format
msgid "not a symmetric range: '%s'"
-msgstr "inte ett symmetriskt intervall: \"%s\""
+msgstr "inte ett symmetriskt intervall: â€%sâ€"
msgid "need two commit ranges"
msgstr "behöver två incheckningsintervall"
@@ -9864,7 +10038,7 @@ msgstr ""
#, c-format
msgid "could not read '%s'."
-msgstr "kunde inte läsa \"%s\"."
+msgstr "kunde inte läsa â€%sâ€."
#, c-format
msgid "could not create temporary %s"
@@ -9874,43 +10048,30 @@ msgid "could not mark as interactive"
msgstr "kunde inte markera som interaktiv"
msgid "could not generate todo list"
-msgstr "Kunde inte skapa attgöra-lista"
+msgstr "kunde inte skapa attgöra-lista"
msgid "a base commit must be provided with --upstream or --onto"
msgstr "en basincheckning måste anges med --upstream eller --onto"
#, c-format
msgid "%s requires the merge backend"
-msgstr "%s kräver \"merge\"-bakändan"
+msgstr "%s kräver â€mergeâ€-bakändan"
#, c-format
msgid "invalid onto: '%s'"
-msgstr "ogiltig \"onto\": \"%s\""
+msgstr "ogiltig â€ontoâ€: â€%sâ€"
#, c-format
msgid "invalid orig-head: '%s'"
-msgstr "ogiltig \"orig-head\": \"%s\""
+msgstr "ogiltig â€orig-headâ€: â€%sâ€"
#, c-format
msgid "ignoring invalid allow_rerere_autoupdate: '%s'"
-msgstr "ignorera ogiltigt allow_rerere_autoupdate: \"%s\""
+msgstr "ignorera ogiltigt allow_rerere_autoupdate: â€%sâ€"
#, c-format
msgid "could not remove '%s'"
-msgstr "kunde inte ta bort \"%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 ""
-"Lös alla konflikter manuellt, märk dem som lösta med\n"
-"\"git add/rm <filer_i_konflikt>\", kör sedan \"git rebase --continue\".\n"
-"Du kan hoppa över incheckningen istället: kör \"git rebase --skip\".\n"
-"För att avbryta och återgå till där du var före ombaseringen, kör \"git "
-"rebase --abort\"."
+msgstr "kunde inte ta bort â€%sâ€"
#, c-format
msgid ""
@@ -9942,12 +10103,14 @@ msgid "apply options and merge options cannot be used together"
msgstr ""
"appliceringsflaggor och sammanslagningsflaggor kan inte användas tillsammans"
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask rekommenderas inte; använd â€--empty=stop†istället."
+
#, c-format
msgid ""
-"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask"
-"\"."
-msgstr ""
-"okänd tom-typ \"%s\"; giltiga värden är \"drop\", \"keep\" och \"ask\"."
+"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
+"\"stop\"."
+msgstr "okänd tom-typ â€%sâ€; giltiga värden är â€dropâ€, â€keep†och â€stopâ€."
msgid ""
"--rebase-merges with an empty string argument is deprecated and will stop "
@@ -10011,7 +10174,7 @@ msgid "do not show diffstat of what changed upstream"
msgstr "visa inte en diffstat för vad som ändrats uppströms"
msgid "add a Signed-off-by trailer to each commit"
-msgstr "lägg \"Signed-off-by:\"-släprad till varje incheckning"
+msgstr "lägg â€Signed-off-by:â€-släprad till varje incheckning"
msgid "make committer date match author date"
msgstr "sätt incheckningsdatum till författardatum"
@@ -10023,7 +10186,7 @@ msgid "synonym of --reset-author-date"
msgstr "synonym för --reset-author-date"
msgid "passed to 'git apply'"
-msgstr "sänds till \"git apply\""
+msgstr "sänds till â€git applyâ€"
msgid "ignore changes in whitespace"
msgstr "ignorera ändringar i blanksteg"
@@ -10085,7 +10248,7 @@ msgid "try to rebase merges instead of skipping them"
msgstr "försök ombasera sammanslagningar istället för att ignorera dem"
msgid "use 'merge-base --fork-point' to refine upstream"
-msgstr "använd \"merge-base --fork-point\" för att förfina uppström"
+msgstr "använd â€merge-base --fork-point†för att förfina uppström"
msgid "use the given merge strategy"
msgstr "använd angiven sammanslagningsstrategi"
@@ -10100,21 +10263,21 @@ msgid "rebase all reachable commits up to the root(s)"
msgstr "ombasera alla nåbara incheckningar upp till roten/rötterna"
msgid "automatically re-schedule any `exec` that fails"
-msgstr "kör automatiskt alla \"exec\" som misslyckas på nytt"
+msgstr "kör automatiskt alla â€exec†som misslyckas pÃ¥ nytt"
msgid "apply all changes, even those already present upstream"
msgstr "applicera alla ändringar, även de som redan finns uppströms"
msgid "It looks like 'git am' is in progress. Cannot rebase."
-msgstr "Det verkar som en \"git am\" körs. Kan inte ombasera."
+msgstr "Det verkar som en â€git am†körs. Kan inte ombasera."
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) stöds ej längre.\n"
-"Använd \"git rebase --abort\" för att avsluta aktuell ombasering.\n"
+"â€rebase --preserve-merges†(-p) stöds ej längre.\n"
+"Använd â€git rebase --abort†för att avsluta aktuell ombasering.\n"
"Eller nedgradera till v2.33 eller tidigare för att slutföra ombaseringen."
msgid ""
@@ -10123,11 +10286,11 @@ msgid ""
"which is no longer supported; use 'merges' instead"
msgstr ""
"--preserve-merges ersattes av --rebase-merges\n"
-"Observera: Din inställning för \"pull.rebase\" kan också vara satt till\n"
-"\"preserve\", som inte längre stöds; använd \"merges\" istället"
+"Observera: Din inställning för â€pull.rebase†kan ocksÃ¥ vara satt till\n"
+"â€preserveâ€, som inte längre stöds; använd â€merges†istället"
-msgid "No rebase in progress?"
-msgstr "Ingen ombasering pågår?"
+msgid "no rebase in progress"
+msgstr "ingen ombasering pågår"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr "Åtgärden --edit-todo kan endast användas under interaktiv ombasering."
@@ -10170,30 +10333,20 @@ msgstr ""
"något av värde där.\n"
msgid "switch `C' expects a numerical value"
-msgstr "flaggan \"C\" förväntar ett numeriskt värde"
-
-msgid "--strategy requires --merge or --interactive"
-msgstr "--strategy kräver --merge eller --interactive"
-
-msgid ""
-"apply options are incompatible with rebase.autoSquash. Consider adding --no-"
-"autosquash"
-msgstr ""
-"argument för \"apply\" är inkompatibla med rebase.autoSquash. Överväg att "
-"lägga till --no-autosquash"
+msgstr "flaggan â€C†förväntar ett numeriskt värde"
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 "
+"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"
msgstr ""
-"argument för \"apply\" är inkompatibla med rebase.updateRefs. Överväg att "
+"argument för â€apply†är inkompatibla med rebase.updateRefs. Överväg att "
"lägga till --no-update-refs"
#, c-format
@@ -10205,14 +10358,14 @@ msgstr "--reschedule-failed-exec kräver --exec eller --interactive"
#, c-format
msgid "invalid upstream '%s'"
-msgstr "felaktig uppström \"%s\""
+msgstr "felaktig uppström â€%sâ€"
msgid "Could not create new root commit"
msgstr "kunde inte skapa ny rotincheckning"
#, c-format
msgid "no such branch/commit '%s'"
-msgstr "ingen sådan gren/incheckning: \"%s\""
+msgstr "ingen sÃ¥dan gren/incheckning: â€%sâ€"
#, c-format
msgid "No such ref: %s"
@@ -10223,15 +10376,15 @@ msgstr "Kunde inte bestämma en incheckning för HEAD"
#, c-format
msgid "'%s': need exactly one merge base with branch"
-msgstr "\"%s\": behöver precis en sammanslagningsbas med gren"
+msgstr "â€%sâ€: behöver precis en sammanslagningsbas med gren"
#, c-format
msgid "'%s': need exactly one merge base"
-msgstr "\"%s\": behöver precis en sammanslagningsbas"
+msgstr "â€%sâ€: behöver precis en sammanslagningsbas"
#, c-format
msgid "Does not point to a valid commit '%s'"
-msgstr "Pekar inte på en giltig incheckning: \"%s\""
+msgstr "Pekar inte pÃ¥ en giltig incheckning: â€%sâ€"
msgid "HEAD is up to date."
msgstr "HEAD är à jour."
@@ -10290,17 +10443,17 @@ msgid ""
msgstr ""
"Normalt tillåts inte uppdatering av aktuell gren i ett icke-naket\n"
"arkiv, då index och arbetskatalog inte kommer stämma med det du\n"
-"sände och \"git reset --hard\" krävs för att få arbetskatalogen och\n"
+"sände och â€git reset --hard†krävs för att fÃ¥ arbetskatalogen och\n"
"HEAD att stämma överens.\n"
"\n"
-"Du kan ställa in variabeln \"receive.denyCurrentBranch\" till\n"
-"\"ignore\" eller \"warn\" i fjärrarkivet för att tillåta sändning till\n"
+"Du kan ställa in variabeln â€receive.denyCurrentBranch†till\n"
+"â€ignore†eller â€warn†i fjärrarkivet för att tillÃ¥ta sändning till\n"
"dess aktuella gren; detta rekommenderas dock inte såvida du inte\n"
"sett till att dess arbetskatalog uppdateras till det tu sände in\n"
"på annat sätt.\n"
"\n"
"För att undvika detta meddelande och fortfarande behålla det\n"
-"normala beteendet, sätt \"receive.denyCurrentBranch\" till \"refuse\"."
+"normala beteendet, sätt â€receive.denyCurrentBranch†till â€refuseâ€."
msgid ""
"By default, deleting the current branch is denied, because the next\n"
@@ -10313,14 +10466,14 @@ msgid ""
"To squelch this message, you can set it to 'refuse'."
msgstr ""
"Normalt tillåts inte radering av aktuell gren, eftersom nästa\n"
-"\"git clone\" inte kommer innebära att några filer checkas ut,\n"
+"â€git clone†inte kommer innebära att nÃ¥gra filer checkas ut,\n"
"vilket är förvirrande.\n"
"\n"
-"Du kan ställa in variabeln \"receive.denyDeleteCurrent\" till\n"
-"\"warn\" eller \"ignore\" i fjärrarkivet för att tillåta borttagning\n"
+"Du kan ställa in variabeln â€receive.denyDeleteCurrent†till\n"
+"â€warn†eller â€ignore†i fjärrarkivet för att tillÃ¥ta borttagning\n"
"av aktuell gren, med eller utan varningsmeddelande.\n"
"\n"
-"För att undvika detta meddelande kan du sätta det till \"refuse\"."
+"För att undvika detta meddelande kan du sätta det till â€refuseâ€."
msgid "quiet"
msgstr "tyst"
@@ -10331,6 +10484,9 @@ msgstr "du måste ange en katalog"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<log-flaggor>] [<ref>]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10354,7 +10510,11 @@ msgstr "git reflog exists <referens>"
#, c-format
msgid "invalid timestamp '%s' given to '--%s'"
-msgstr "ogiltig tidsstämpel \"%s\" given i \"--%s\""
+msgstr "ogiltig tidsstämpel â€%s†given i â€--%sâ€"
+
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s tar inte argument: â€%sâ€"
msgid "do not actually prune any entries"
msgstr "rensa faktiskt inte några poster"
@@ -10405,6 +10565,31 @@ msgstr "ingen referenslogg att ta bort angavs"
msgid "invalid ref format: %s"
msgstr "felaktigt referensformat: %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+msgid "specify the reference format to convert to"
+msgstr "ange referensformatet att konvertera till"
+
+msgid "perform a non-destructive dry-run"
+msgstr "utför ett icke-destruktiv testkörning"
+
+msgid "missing --ref-format=<format>"
+msgstr "saknad --ref-format=<format>"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "arkivet använder redan â€%sâ€-format"
+
+msgid "enable strict checking"
+msgstr "aktivera strikt kontroll"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "â€git refs verify†tar inget argument"
+
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10481,8 +10666,8 @@ msgstr ""
"\t --mirror=fetch eller --mirror=push istället"
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "okänt argument till mirror: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "okänt argument till --mirror: %s"
msgid "fetch the remote branches"
msgstr "hämta fjärrgrenarna"
@@ -10515,7 +10700,7 @@ msgstr "fjärrarkivet %s finns redan."
#, c-format
msgid "Could not setup master '%s'"
-msgstr "Kunde inte skapa master \"%s\""
+msgstr "Kunde inte skapa master â€%sâ€"
#, c-format
msgid "more than one %s"
@@ -10523,7 +10708,7 @@ msgstr "mer än en %s"
#, c-format
msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
-msgstr "ohanterad branch.%s.rebase=%s; antar \"true\""
+msgstr "ohanterad branch.%s.rebase=%s; antar â€trueâ€"
#, c-format
msgid "Could not get fetch map for refspec %s"
@@ -10537,11 +10722,11 @@ msgstr "(ta bort)"
#, c-format
msgid "could not set '%s'"
-msgstr "kunde inte ställa in \"%s\""
+msgstr "kunde inte ställa in â€%sâ€"
#, c-format
msgid "could not unset '%s'"
-msgstr "kunde inte ta bort inställning för \"%s\""
+msgstr "kunde inte ta bort inställning för â€%sâ€"
#, c-format
msgid ""
@@ -10551,15 +10736,15 @@ msgid ""
msgstr ""
"Konfigurationen för %s för remote.pushDefault i:\n"
"\t%s:%d\n"
-"anger nu den icke-existerande fjärren \"%s\""
+"anger nu den icke-existerande fjärren â€%sâ€"
#, c-format
msgid "No such remote: '%s'"
-msgstr "Ingen sådan fjärr: \"%s\""
+msgstr "Ingen sÃ¥dan fjärr: â€%sâ€"
#, c-format
msgid "Could not rename config section '%s' to '%s'"
-msgstr "Kunde inte byta namn på konfigurationssektionen \"%s\" till \"%s\""
+msgstr "Kunde inte byta namn pÃ¥ konfigurationssektionen â€%s†till â€%sâ€"
#, c-format
msgid ""
@@ -10576,11 +10761,11 @@ msgstr "Byter namn på fjärreferenser"
#, c-format
msgid "deleting '%s' failed"
-msgstr "misslyckades ta bort \"%s\""
+msgstr "misslyckades ta bort â€%sâ€"
#, c-format
msgid "creating '%s' failed"
-msgstr "misslyckades skapa \"%s\""
+msgstr "misslyckades skapa â€%sâ€"
msgid ""
"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
@@ -10597,7 +10782,7 @@ msgstr[1] ""
#, c-format
msgid "Could not remove config section '%s'"
-msgstr "Kunde inte ta bort konfigurationssektionen \"%s\""
+msgstr "Kunde inte ta bort konfigurationssektionen â€%sâ€"
#, c-format
msgid " new (next fetch will store in remotes/%s)"
@@ -10610,7 +10795,7 @@ msgid " skipped"
msgstr " överhoppad"
msgid " stale (use 'git remote prune' to remove)"
-msgstr " förlegad (använd \"git remote prune\" för att ta bort)"
+msgstr " förlegad (använd â€git remote prune†för att ta bort)"
msgid " ???"
msgstr " ???"
@@ -10685,9 +10870,6 @@ msgstr "* fjärr %s"
msgid " Fetch URL: %s"
msgstr " Hämt-URL: %s"
-msgid "(no URL)"
-msgstr "(ingen URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -10696,6 +10878,9 @@ msgstr "(ingen URL)"
msgid " Push URL: %s"
msgstr " Sänd-URL: %s"
+msgid "(no URL)"
+msgstr "(ingen URL)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " HEAD-gren: %s"
@@ -10722,17 +10907,17 @@ msgstr " (status inte förfrågad)"
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
-msgstr[0] " Lokal gren konfigurerad för \"git pull\":"
-msgstr[1] " Lokala grenar konfigurerade för \"git pull\":"
+msgstr[0] " Lokal gren konfigurerad för â€git pullâ€:"
+msgstr[1] " Lokala grenar konfigurerade för â€git pullâ€:"
msgid " Local refs will be mirrored by 'git push'"
-msgstr " Lokala referenser speglas av \"git push\""
+msgstr " Lokala referenser speglas av â€git pushâ€"
#, c-format
msgid " Local ref configured for 'git push'%s:"
msgid_plural " Local refs configured for 'git push'%s:"
-msgstr[0] " Lokal referens konfigurerad för \"git push\"%s:"
-msgstr[1] " Lokala referenser konfigurerade för \"git push\"%s:"
+msgstr[0] " Lokal referens konfigurerad för â€git pushâ€%s:"
+msgstr[1] " Lokala referenser konfigurerade för â€git pushâ€%s:"
msgid "set refs/remotes/<name>/HEAD according to remote"
msgstr "sätt refs/remotes/<namn>/HEAD enligt fjärren"
@@ -10787,7 +10972,7 @@ msgstr "rensa fjärrar efter hämtning"
#, c-format
msgid "No such remote '%s'"
-msgstr "Ingen sådan fjärr \"%s\""
+msgstr "Ingen sÃ¥dan fjärr â€%sâ€"
msgid "add branch"
msgstr "lägg till gren"
@@ -10801,10 +10986,6 @@ msgstr "fråga sänd-URL:er istället för hämta-URL:er"
msgid "return all URLs"
msgstr "returnera alla URL:er"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "ingen URL:er angivna för fjärren \"%s\""
-
msgid "manipulate push URLs"
msgstr "manipulera URL:ar för sändning"
@@ -10845,6 +11026,9 @@ msgstr ""
msgid "could not start pack-objects to repack promisor objects"
msgstr "kunde inte starta pack-objects för att packa om kontraktsobjekt"
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "misslyckades sända kontraktsobjekt till pack-objects"
+
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"repack: Förväntar kompletta hex-objekt-id-rader endast från pack-objects."
@@ -10875,6 +11059,10 @@ msgstr "kunde inte stänga temporär fil för refs-ögonblicksbild"
msgid "could not remove stale bitmap: %s"
msgstr "kunde inte ta bort gammal bitkarta: %s"
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "paketprefixet %s börjar inte med objkat %s"
+
msgid "pack everything in a single pack"
msgstr "packa allt i ett enda paket"
@@ -10950,27 +11138,30 @@ msgstr "skriv ett flerpaketsindex för de skapade paketen"
msgid "pack prefix to store a pack containing pruned objects"
msgstr "paketprefix att lagra ett paket som innehåller bortrensade objekt"
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "paketprefix att lagra ett paket som innehåller utfiltrerade objekt"
+
msgid "cannot delete packs in a precious-objects repo"
-msgstr "kan inte ta bort paket i ett \"precious-objects\"-arkiv"
+msgstr "kan inte ta bort paket i ett â€precious-objectsâ€-arkiv"
+
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "flaggan â€%s†kan inte användas med â€%sâ€"
msgid "Nothing new to pack."
msgstr "Inget nytt att packa."
#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "paketprefixet %s börjar inte med objkat %s"
-
-#, c-format
msgid "renaming pack to '%s' failed"
-msgstr "misslyckades byta namn på paket till \"%s\""
+msgstr "misslyckades byta namn pÃ¥ paket till â€%sâ€"
#, c-format
msgid "pack-objects did not write a '%s' file for pack %s-%s"
-msgstr "pack-objects skrev inte en \"%s\"-fil för paketet %s-%s"
+msgstr "pack-objects skrev inte en â€%sâ€-fil för paketet %s-%s"
#, c-format
msgid "could not unlink: %s"
-msgstr "kunde inte ta bort: \"%s\""
+msgstr "kunde inte ta bort: â€%sâ€"
msgid "git replace [-f] <object> <replacement>"
msgstr "git replace [-f] <objekt> <ersättning>"
@@ -10992,24 +11183,24 @@ msgid ""
"invalid replace format '%s'\n"
"valid formats are 'short', 'medium' and 'long'"
msgstr ""
-"ogiltigt ersättningsformat \"%s\"\n"
-"giltiga format är \"short\", \"medium\" och \"long\""
+"ogiltigt ersättningsformat â€%sâ€\n"
+"giltiga format är â€shortâ€, â€medium†och â€longâ€"
#, c-format
msgid "replace ref '%s' not found"
-msgstr "ersättningsreferensen \"%s\" hittades inte"
+msgstr "ersättningsreferensen â€%s†hittades inte"
#, c-format
msgid "Deleted replace ref '%s'"
-msgstr "Tog bort ersättningsreferensen \"%s\""
+msgstr "Tog bort ersättningsreferensen â€%sâ€"
#, c-format
msgid "'%s' is not a valid ref name"
-msgstr "\"%s\" är inte ett giltigt referensnamn"
+msgstr "â€%s†är inte ett giltigt referensnamn"
#, c-format
msgid "replace ref '%s' already exists"
-msgstr "ersättningsreferensen \"%s\" finns redan"
+msgstr "ersättningsreferensen â€%s†finns redan"
#, c-format
msgid ""
@@ -11018,8 +11209,8 @@ msgid ""
"while '%s' points to a replacement object of type '%s'."
msgstr ""
"Objekt måste vara av samma typ.\n"
-"\"%s\" pekar på ett ersatt objekt med typen \"%s\"\n"
-"medan \"%s\" pekar på ett ersättningsobjekt av typen \"%s\"."
+"â€%s†pekar pÃ¥ ett ersatt objekt med typen â€%sâ€\n"
+"medan â€%s†pekar pÃ¥ ett ersättningsobjekt av typen â€%sâ€."
#, c-format
msgid "unable to open %s for writing"
@@ -11046,7 +11237,7 @@ msgstr "mktree returnerade inte ett objektnamn"
#, c-format
msgid "unable to fstat %s"
-msgstr "kan inte utföra \"fstat\" på %s"
+msgstr "kan inte utföra â€fstat†pÃ¥ %s"
msgid "unable to write object to database"
msgstr "kan inte skriva objektet till databasen"
@@ -11060,7 +11251,7 @@ msgstr "misslyckades redigera objektfilen"
#, c-format
msgid "new object is the same as the old one: '%s'"
-msgstr "nytt objekt är samma som det gamla: \"%s\""
+msgstr "nytt objekt är samma som det gamla: â€%sâ€"
#, c-format
msgid "could not parse %s as a commit"
@@ -11068,38 +11259,38 @@ msgstr "kunde inte tolka %s som incheckning"
#, c-format
msgid "bad mergetag in commit '%s'"
-msgstr "felaktig sammanslagningstagg i incheckningen \"%s\""
+msgstr "felaktig sammanslagningstagg i incheckningen â€%sâ€"
#, c-format
msgid "malformed mergetag in commit '%s'"
-msgstr "felformad sammanslagningstagg i incheckningen \"%s\""
+msgstr "felformad sammanslagningstagg i incheckningen â€%sâ€"
#, c-format
msgid ""
"original commit '%s' contains mergetag '%s' that is discarded; use --edit "
"instead of --graft"
msgstr ""
-"den ursprungliga incheckningen \"%s\" innehåller sammanslagningstaggen \"%s"
-"\" som har förkastats; använd --edit istället för --graft"
+"den ursprungliga incheckningen â€%s†innehÃ¥ller sammanslagningstaggen â€%s†"
+"som har förkastats; använd --edit istället för --graft"
#, c-format
msgid "the original commit '%s' has a gpg signature"
-msgstr "den ursprungliga incheckningen \"%s\" har en gpg-signatur"
+msgstr "den ursprungliga incheckningen â€%s†har en gpg-signatur"
msgid "the signature will be removed in the replacement commit!"
msgstr "signaturen kommer att tas bort i ersättningsincheckningen!"
#, c-format
msgid "could not write replacement commit for: '%s'"
-msgstr "kunde inte skriva ersättningsincheckning för: \"%s\""
+msgstr "kunde inte skriva ersättningsincheckning för: â€%sâ€"
#, c-format
msgid "graft for '%s' unnecessary"
-msgstr "ympning för \"%s\" behövs inte"
+msgstr "ympning för â€%s†behövs inte"
#, c-format
msgid "new commit is the same as the old one: '%s'"
-msgstr "ny incheckning är samma som den gamla: \"%s\""
+msgstr "ny incheckning är samma som den gamla: â€%sâ€"
#, c-format
msgid ""
@@ -11160,6 +11351,76 @@ msgstr "--convert-graft-file tar inga argument"
msgid "only one pattern can be given with -l"
msgstr "endast ett mönster kan anges med -l"
+msgid "need some commits to replay"
+msgstr "behöver några incheckningar för omspelning"
+
+msgid "--onto and --advance are incompatible"
+msgstr "--onto och --advance kan inte kombineras"
+
+msgid "all positive revisions given must be references"
+msgstr "alla positiva revisioner som anges måste vara referenser"
+
+msgid "argument to --advance must be a reference"
+msgstr "argumentet till --advance måste vara en referens"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"kan inte flytta målet framåt när det finns flera källor eftersom ordningen "
+"inte kan fastställas"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"kan inte avgöra om den underförstådda processen är --advance eller --onto"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"kan inte flytta målet framåt när det finns flera källgrenar eftersom "
+"ordningen inte kan fastställas"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "kan inte avgöra den underförstådda basen för --onto"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(EXPERIMENTELLT!) git replay ([--contained] --onto <nybas> | --advance "
+"<gren>) <revisions-intervall>..."
+
+msgid "make replay advance given branch"
+msgstr "låt omspelningen flytta den givna grenen framåt"
+
+msgid "replay onto given commit"
+msgstr "spela om ovanpå en given incheckning"
+
+msgid "advance all branches contained in revision-range"
+msgstr "flytta alla grenar som finns i revisionsintervallet framåt"
+
+msgid "option --onto or --advance is mandatory"
+msgstr "flaggan --onto eller --advance måste anges"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"nÃ¥gra flaggor för revisionstraversering kommer överstyras eftersom â€%sâ€-"
+"biten i â€struct rev_info†kommer att tvingas"
+
+msgid "error preparing revisions"
+msgstr "fel när revisioner skulle förberedas"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "kan ännu inte spela om hela vägen ned till rotincheckningen!"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "kan ännu inte spela om sammanslagningsincheckningar!"
+
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
msgstr ""
@@ -11169,11 +11430,11 @@ msgid "register clean resolutions in index"
msgstr "registrera rena lösningar i indexet"
msgid "'git rerere forget' without paths is deprecated"
-msgstr "\"git rerere forget\" utan sökvägar är föråldrat"
+msgstr "â€git rerere forget†utan sökvägar är förÃ¥ldrat"
#, c-format
msgid "unable to generate diff for '%s'"
-msgstr "misslyckades skapa diff för \"%s\""
+msgstr "kan inte skapa diff för â€%sâ€"
msgid ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
@@ -11210,11 +11471,11 @@ msgid "You do not have a valid HEAD."
msgstr "Du har inte en giltig HEAD."
msgid "Failed to find tree of HEAD."
-msgstr "Kunde inte hitta trädet för HEAD."
+msgstr "Misslyckades hitta trädet för HEAD."
#, c-format
msgid "Failed to find tree of %s."
-msgstr "Kunde inte hitta trädet för %s."
+msgstr "Misslyckades hitta trädet för %s."
#, c-format
msgid "HEAD is now at %s"
@@ -11247,15 +11508,15 @@ msgstr "registrera endast att borttagna sökvägar kommer läggas till senare"
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
-msgstr "Kunde inte slå upp \"%s\" som en giltig revision."
+msgstr "Misslyckades slÃ¥ upp â€%s†som en giltig revision."
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
-msgstr "Kunde inte slå upp \"%s\" som ett giltigt träd."
+msgstr "Misslyckades slÃ¥ upp â€%s†som ett giltigt träd."
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
-"--mixed rekommenderas inte med sökvägar; använd \"git reset -- <sökvägar>\"."
+"--mixed rekommenderas inte med sökvägar; använd â€git reset -- <sökvägar>â€."
#, c-format
msgid "Cannot do %s reset with paths."
@@ -11274,11 +11535,11 @@ msgid ""
"'--no-refresh' to avoid this."
msgstr ""
"Det tog %.2f sekunder att uppdatera indexet efter återställning.\n"
-"Du kan använda \"--no-refresh\" för undvika detta."
+"Du kan använda â€--no-refresh†för undvika detta."
#, c-format
msgid "Could not reset index file to revision '%s'."
-msgstr "Kunde inte återställa indexfilen till versionen \"%s\"."
+msgstr "Kunde inte Ã¥terställa indexfilen till versionen â€%sâ€."
msgid "Could not write new index file."
msgstr "Kunde inte skriva ny indexfil."
@@ -11289,21 +11550,20 @@ msgstr "kan inte hämta diskanvändning för %s"
#, c-format
msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
-msgstr ""
-"felaktigt värde för \"%s\": \"%s\", det enda tillåtna formatet är \"%s\""
+msgstr "felaktigt värde för â€%sâ€: â€%sâ€, det enda tillÃ¥tna formatet är â€%sâ€"
msgid "rev-list does not support display of notes"
msgstr "rev-list stöder inte visning av anteckningar"
#, c-format
msgid "marked counting and '%s' cannot be used together"
-msgstr "markerad räkning och \"%s\" kan inte användas samtidigt."
+msgstr "markerad räkning och â€%s†kan inte användas samtidigt."
msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
msgstr "git rev-parse --parseopt [<options>] -- [<argument>...]"
msgid "keep the `--` passed as an arg"
-msgstr "behåll \"--\" sänt som argument"
+msgstr "behÃ¥ll â€--†sänt som argument"
msgid "stop parsing after the first non-option argument"
msgstr "sluta tolka efter första argument som inte är flagga"
@@ -11315,7 +11575,7 @@ msgid "premature end of input"
msgstr "för tidigt slut på indata"
msgid "no usage string given before the `--' separator"
-msgstr "ingen användningssträng angavs före \"--\"-avdelaren"
+msgstr "ingen användningssträng angavs före â€--â€-avdelaren"
msgid "missing opt-spec before option flags"
msgstr "saknar flagg-spec före alternativflaggor"
@@ -11334,7 +11594,7 @@ msgstr ""
" eller: git rev-parse --sq-quote [<argument>...]\n"
" eller: git rev-parse [<flaggor>] [<argument>...]\n"
"\n"
-"Kör \"git rev-parse --parseopt -h\" för mer information om den första "
+"Kör â€git rev-parse --parseopt -h†för mer information om den första "
"varianten."
msgid "--resolve-git-dir requires an argument"
@@ -11342,7 +11602,7 @@ msgstr "--resolve-git-dir kräver ett argument"
#, c-format
msgid "not a gitdir '%s'"
-msgstr "inte en gitkatalog \"%s\""
+msgstr "inte en gitkatalog â€%sâ€"
msgid "--git-path requires an argument"
msgstr "--git-path kräver ett argument"
@@ -11363,22 +11623,23 @@ msgstr "--default kräver ett argument"
msgid "--prefix requires an argument"
msgstr "--prefix kräver ett argument"
+msgid "no object format specified"
+msgstr "inget objektformat angavs"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "objektformatet stöds ej: %s"
+
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "okänt läge för --abbrev-ref: %s"
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden kan endast användas tillsammans med --branches"
-
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden kan kan inte användas tillsammans med --tags"
-
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden kan kan inte användas tillsammans med --remotes"
-
msgid "this operation must be run in a work tree"
msgstr "funktionen måste köras i en arbetskatalog"
+msgid "Could not read the index"
+msgstr "Kunde inte läsa indexet"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "okänt läge för --show-object-format: %s"
@@ -11405,7 +11666,7 @@ msgstr "git cherry-pick (--continue | --skip | --abort | --quit)"
#, c-format
msgid "option `%s' expects a number greater than zero"
-msgstr "flaggan \"%s\" antar ett numeriskt värde större än noll"
+msgstr "flaggan â€%s†antar ett numeriskt värde större än noll"
#, c-format
msgid "%s: %s cannot be used with %s"
@@ -11450,17 +11711,17 @@ msgstr "behåll incheckningar som börjar som tomma"
msgid "allow commits with empty messages"
msgstr "tillåt incheckningar med tomt meddelande"
-msgid "keep redundant, empty commits"
-msgstr "behåll redundanta, tomma incheckningar"
+msgid "deprecated: use --empty=keep instead"
+msgstr "avråds: använd --empty=keep istället"
msgid "use the 'reference' format to refer to commits"
-msgstr "använd \"referens\"-format för att referera till incheckningar"
+msgstr "använd â€referensâ€-format för att referera till incheckningar"
msgid "revert failed"
-msgstr "\"revert\" misslyckades"
+msgstr "â€revert†misslyckades"
msgid "cherry-pick failed"
-msgstr "\"cherry-pick\" misslyckades"
+msgstr "â€cherry-pick†misslyckades"
msgid ""
"git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
@@ -11526,11 +11787,11 @@ msgstr "Ingen sökvägsangivelse gavs. Vilka filer ska jag ta bort?"
msgid "please stage your changes to .gitmodules or stash them to proceed"
msgstr ""
-"löa dina ändringar i .gitmodules eller använd \"stash\" för att fortsätta"
+"löa dina ändringar i .gitmodules eller använd â€stash†för att fortsätta"
#, c-format
msgid "not removing '%s' recursively without -r"
-msgstr "tar inte bort \"%s\" rekursivt utan -r"
+msgstr "tar inte bort â€%s†rekursivt utan -r"
#, c-format
msgid "git rm: unable to remove %s"
@@ -11571,7 +11832,7 @@ msgid "git log --pretty=short | git shortlog [<options>]"
msgstr "git log --pretty=short | git shortlog [<flaggor>]"
msgid "using multiple --group options with stdin is not supported"
-msgstr "mer än en \"--group\"-flagga stöds inte med standard in"
+msgstr "mer än en â€--groupâ€-flagga stöds inte med standard in"
#, c-format
msgid "using %s with stdin is not supported"
@@ -11641,7 +11902,7 @@ msgid "show remote-tracking branches"
msgstr "visa fjärrspårande grenar"
msgid "color '*!+-' corresponding to the branch"
-msgstr "färga \"*!+-\" enligt grenen"
+msgstr "färga â€*!+-†enligt grenen"
msgid "show <n> more commits after the common ancestor"
msgstr "visa <n> ytterligare incheckningar efter gemensam anfader"
@@ -11706,7 +11967,7 @@ msgstr[1] "kan inte hantera mer än %d revisioner."
#, c-format
msgid "'%s' is not a valid ref."
-msgstr "\"%s\" är inte en giltig referens."
+msgstr "â€%s†är inte en giltig referens."
#, c-format
msgid "cannot find commit %s (%s)"
@@ -11719,22 +11980,43 @@ msgid "Unknown hash algorithm"
msgstr "okänd hashningsalgoritm"
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<mönster>...]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<mönster>...]"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<mönster>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "visa endast taggar (kan kombineras med huvuden)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <ref>"
+
+msgid "reference does not exist"
+msgstr "referensen existerar inte"
+
+msgid "failed to look up reference"
+msgstr "misslyckades slå upp referensen"
+
+msgid "only show tags (can be combined with --branches)"
+msgstr "visa endast taggar (kan kombineras med --branches)"
+
+msgid "only show branches (can be combined with --tags)"
+msgstr "visa endast grenar (kan kombineras med --tags)"
-msgid "only show heads (can be combined with tags)"
-msgstr "visa endast huvuden (kan kombineras med taggar)"
+msgid "check for reference existence without resolving"
+msgstr "kontrollerar att referensen existerar utan att slå upp dem"
msgid "stricter reference checking, requires exact ref path"
msgstr "striktare referenskontroll, kräver exakt referenssökväg"
@@ -11773,15 +12055,19 @@ msgid ""
"directory '%s' contains untracked files, but is not in the sparse-checkout "
"cone"
msgstr ""
-"katalogen \"%s\" innehåller ospårade filer, men är inte i området som ages i "
-"\"sparse-checkout\""
+"katalogen â€%s†innehÃ¥ller ospÃ¥rade filer, men är inte i omrÃ¥det som ages i "
+"â€sparse-checkoutâ€"
#, c-format
msgid "failed to remove directory '%s'"
-msgstr "misslyckades ta bort katalogen \"%s\""
+msgstr "misslyckades ta bort katalogen â€%sâ€"
msgid "failed to create directory for sparse-checkout file"
-msgstr "misslyckades skapa katalog för \"sparse-checkout\"-filen"
+msgstr "misslyckades skapa katalog för â€sparse-checkoutâ€-filen"
+
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "kan inte utföra fdopen %s"
msgid "failed to initialize worktree config"
msgstr "misslyckades initiera arbetskataloginställning"
@@ -11797,22 +12083,22 @@ msgstr "slå på/av använding av glest index"
#, c-format
msgid "unable to create leading directories of %s"
-msgstr "kunde inte skapa inledande kataloger för %s"
+msgstr "kan inte skapa inledande kataloger för %s"
#, c-format
msgid "failed to open '%s'"
-msgstr "misslyckades öppna \"%s\""
+msgstr "misslyckades öppna â€%sâ€"
#, c-format
msgid "could not normalize path %s"
-msgstr "kunde inte normalisera sökvägen \"%s\""
+msgstr "kunde inte normalisera sökvägen â€%sâ€"
#, c-format
msgid "unable to unquote C-style string '%s'"
-msgstr "kan inte ta bort citering av C-sträng \"%s\""
+msgstr "kan inte ta bort citering av C-sträng â€%sâ€"
msgid "unable to load existing sparse-checkout patterns"
-msgstr "kunde inte läsa in existerande mönster för gles utcheckning"
+msgstr "kan inte läsa in existerande mönster för gles utcheckning"
msgid "existing sparse-checkout patterns do not use cone mode"
msgstr "befintliga filter för gles utcheckning använder inte konläge"
@@ -11827,8 +12113,8 @@ msgid ""
"specify directories rather than patterns. If your directory starts with a "
"'!', pass --skip-checks"
msgstr ""
-"ange kataloger istället för mönster. Om din katalog börjar med ett \"!\", "
-"sänd med --skip-checks"
+"ange kataloger istället för mönster. Om din katalog börjar med ett â€!â€, sänd "
+"med --skip-checks"
msgid ""
"specify directories rather than patterns. If your directory really has any "
@@ -11842,7 +12128,7 @@ msgid ""
"'%s' is not a directory; to treat it as a directory anyway, rerun with --"
"skip-checks"
msgstr ""
-"\"%s\" är inte en katalog: för att ändå behandla det som en katalog, kör på "
+"â€%s†är inte en katalog: för att ändÃ¥ behandla det som en katalog, kör pÃ¥ "
"nytt med --skip-checks"
#, c-format
@@ -11850,7 +12136,7 @@ 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änd med ett inledande snedstreck före sökvägar som \"%s\" om du vill ha en "
+"sänd med ett inledande snedstreck före sökvägar som â€%s†om du vill ha en "
"enstaka file (se NON-CONE PROBLEMS i manualen git-sparse-checkout)."
msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
@@ -11899,13 +12185,13 @@ 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>]"
+msgstr "git stash list [<â€logâ€-flaggor>]"
msgid ""
"git stash show [-u | --include-untracked | --only-untracked] [<diff-"
"options>] [<stash>]"
msgstr ""
-"git stash show [-u | --include-untracked | --only-untracked] [<\"diff\"-"
+"git stash show [-u | --include-untracked | --only-untracked] [<â€diffâ€-"
"flaggor>] [<stash>]"
msgid "git stash drop [-q | --quiet] [<stash>]"
@@ -11953,21 +12239,21 @@ msgstr "git stash create [<meddelande>]"
#, c-format
msgid "'%s' is not a stash-like commit"
-msgstr "\"%s\" är inte en \"stash\"-liknande incheckning"
+msgstr "â€%s†är inte en â€stashâ€-liknande incheckning"
#, c-format
msgid "Too many revisions specified:%s"
msgstr "För många revisioner angivna:%s"
msgid "No stash entries found."
-msgstr "Inga \"stash\"-poster hittades."
+msgstr "Inga â€stashâ€-poster hittades."
#, c-format
msgid "%s is not a valid reference"
msgstr "%s är inte en giltigt referens"
msgid "git stash clear with arguments is unimplemented"
-msgstr "\"git stash clear\" med argument har inte implementerats"
+msgstr "â€git stash clear†med argument har inte implementerats"
#, c-format
msgid ""
@@ -11976,11 +12262,11 @@ msgid ""
" to make room.\n"
msgstr ""
"VARNING: En ospårad fil är i vägen för en spårad fil! Byter namn\n"
-" %s -> %s\n"
+" %s → %s\n"
" för att lämna plats.\n"
msgid "cannot apply a stash in the middle of a merge"
-msgstr "kan inte tillämpa en \"stash\" mitt i en sammanslagning"
+msgstr "kan inte tillämpa en â€stash†mitt i en sammanslagning"
#, c-format
msgid "could not generate diff %s^!."
@@ -11997,7 +12283,7 @@ msgid "Merging %s with %s"
msgstr "Slår ihop %s med %s"
msgid "Index was not unstashed."
-msgstr "Indexet har inte tagits upp ur \"stash\":en"
+msgstr "Indexet har inte tagits upp ur â€stashâ€:en"
msgid "could not restore untracked files from stash"
msgstr "kunde inte återställa ospårade filer från stash-post"
@@ -12011,11 +12297,11 @@ msgstr "Kastade %s (%s)"
#, c-format
msgid "%s: Could not drop stash entry"
-msgstr "%s: Kunde inte kasta \"stash\"-post"
+msgstr "%s: Kunde inte kasta â€stashâ€-post"
#, c-format
msgid "'%s' is not a stash reference"
-msgstr "\"%s\" är inte en \"stash\"-referens"
+msgstr "â€%s†är inte en â€stashâ€-referens"
msgid "The stash entry is kept in case you need it again."
msgstr "Stash-posten behålls ifall du behöver den igen."
@@ -12030,20 +12316,20 @@ msgid "failed to unpack trees"
msgstr "misslyckades packa upp träd"
msgid "include untracked files in the stash"
-msgstr "ta med ospårade filer i \"stash\""
+msgstr "ta med ospÃ¥rade filer i â€stashâ€"
msgid "only show untracked files in the stash"
-msgstr "visa bara ospårade filer i \"stash\""
+msgstr "visa bara ospÃ¥rade filer i â€stashâ€"
#, c-format
msgid "Cannot update %s with %s"
msgstr "Kan inte uppdatera %s med %s"
msgid "stash message"
-msgstr "\"stash\"-meddelande"
+msgstr "â€stashâ€-meddelande"
msgid "\"git stash store\" requires one <commit> argument"
-msgstr "\"git stash store\" kräver ett <incheckning>-argument"
+msgstr "â€git stash store†kräver ett <incheckning>-argument"
msgid "No staged changes"
msgstr "Inga köade ändringar"
@@ -12077,13 +12363,13 @@ msgstr ""
"Kan inte använda --staged och --include-untracked eller --all samtidigt"
msgid "Did you forget to 'git add'?"
-msgstr "Glömde du använda \"git add\"?"
+msgstr "Glömde du använda â€git addâ€?"
msgid "No local changes to save"
msgstr "Inga lokala ändringar att spara"
msgid "Cannot initialize stash"
-msgstr "Kan inte initiera \"stash\""
+msgstr "Kan inte initiera â€stashâ€"
msgid "Cannot save the current status"
msgstr "Kan inte spara aktuell status"
@@ -12102,13 +12388,13 @@ msgid "stash staged changes only"
msgstr "stash:a endast köade ändringar"
msgid "stash in patch mode"
-msgstr "\"stash\" i \"patch\"-läge"
+msgstr "â€stash†i â€patchâ€-läge"
msgid "quiet mode"
msgstr "tyst läge"
msgid "include untracked files in stash"
-msgstr "ta med ospårade filer i \"stash\""
+msgstr "ta med ospÃ¥rade filer i â€stashâ€"
msgid "include ignore files"
msgstr "ta med ignorerade filer"
@@ -12125,23 +12411,23 @@ msgstr "Förväntade fullt referensnamn, fick %s"
#, c-format
msgid "could not get a repository handle for submodule '%s'"
-msgstr "kunde inte få tag i arkivhandtag för undermodulen \"%s\""
+msgstr "kunde inte fÃ¥ tag i arkivhandtag för undermodulen â€%sâ€"
#, c-format
msgid ""
"could not look up configuration '%s'. Assuming this repository is its own "
"authoritative upstream."
msgstr ""
-"kunde inte slå upp konfigurationen \"%s\". Antar att arkivet är sin eget "
+"kunde inte slÃ¥ upp konfigurationen â€%sâ€. Antar att arkivet är sin eget "
"officiella uppström."
#, c-format
msgid "No url found for submodule path '%s' in .gitmodules"
-msgstr "Hittade ingen url för undermodulsökvägen \"%s\" i .gitmodules"
+msgstr "Hittade ingen url för undermodulsökvägen â€%s†i .gitmodules"
#, c-format
msgid "Entering '%s'\n"
-msgstr "GÃ¥r in i \"%s\"\n"
+msgstr "GÃ¥r in i â€%sâ€\n"
#, c-format
msgid ""
@@ -12172,19 +12458,19 @@ msgstr "git submodule foreach [--quiet] [--recursive] [--] <kommando>"
#, c-format
msgid "Failed to register url for submodule path '%s'"
-msgstr "Misslyckades registrera url för undermodulsökväg \"%s\""
+msgstr "Misslyckades registrera url för undermodulsökväg â€%sâ€"
#, c-format
msgid "Submodule '%s' (%s) registered for path '%s'\n"
-msgstr "Undermodulen \"%s\" (%s) registrerad för sökvägen \"%s\"\n"
+msgstr "Undermodulen â€%s†(%s) registrerad för sökvägen â€%sâ€\n"
#, c-format
msgid "warning: command update mode suggested for submodule '%s'\n"
-msgstr "varning: kommandouppdateringsläge föreslogs för undermodulen \"%s\"\n"
+msgstr "varning: kommandouppdateringsläge föreslogs för undermodulen â€%sâ€\n"
#, c-format
msgid "Failed to register update mode for submodule path '%s'"
-msgstr "Misslyckades registrera uppdateringsläge för undermodulsökväg \"%s\""
+msgstr "Misslyckades registrera uppdateringsläge för undermodulsökväg â€%sâ€"
msgid "suppress output for initializing a submodule"
msgstr "dölj utdata från initiering av undermodul"
@@ -12194,15 +12480,15 @@ msgstr "git submodule init [<flaggor>] [<sökväg>]"
#, c-format
msgid "no submodule mapping found in .gitmodules for path '%s'"
-msgstr "hittade ingen undermodulmappning i .gitmodules för sökvägen \"%s\""
+msgstr "hittade ingen undermodulmappning i .gitmodules för sökvägen â€%sâ€"
#, c-format
msgid "could not resolve HEAD ref inside the submodule '%s'"
-msgstr "kunde inte bestämma HEAD:s incheckning i undermodulen \"%s\""
+msgstr "kunde inte bestämma HEAD:s incheckning i undermodulen â€%sâ€"
#, c-format
msgid "failed to recurse into submodule '%s'"
-msgstr "misslyckades rekursera in i undermodulen \"%s\""
+msgstr "misslyckades rekursera in i undermodulen â€%sâ€"
msgid "suppress submodule status output"
msgstr "hindra statusutskrift för undermodul"
@@ -12219,11 +12505,11 @@ msgstr "git submodule status [--quitet] [--cached] [--recursive] [<sökväg>...]
#, c-format
msgid "* %s %s(blob)->%s(submodule)"
-msgstr "* %s %s(blob)->%s(submodule)"
+msgstr "* %s %s(blob)→%s(submodule)"
#, c-format
msgid "* %s %s(submodule)->%s(blob)"
-msgstr "* %s %s(submodule)->%s(blob)"
+msgstr "* %s %s(submodule)→%s(blob)"
#, c-format
msgid "%s"
@@ -12231,11 +12517,11 @@ msgstr "%s"
#, c-format
msgid "couldn't hash object from '%s'"
-msgstr "kunde inte hasha objekt från \"%s\""
+msgstr "kunde inte hasha objekt frÃ¥n â€%sâ€"
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "okänt läge %o\n"
+msgid "unexpected mode %o"
+msgstr "okänt läge %o"
msgid "use the commit stored in the index instead of the submodule HEAD"
msgstr "använd incechkning lagrad i indexet istället för undermodulens HEAD"
@@ -12245,7 +12531,7 @@ msgstr "jämför incheckningen i indexet med den i undermodulens HEAD"
msgid "skip submodules with 'ignore_config' value set to 'all'"
msgstr ""
-"hoppa över undermoduler där värdet för \"ignore_config\" är satt till \"all\""
+"hoppa över undermoduler där värdet för â€ignore_config†är satt till â€allâ€"
msgid "limit the summary size"
msgstr "begränsa översiktsstorleken"
@@ -12258,15 +12544,15 @@ msgstr "kunde inte hämta en version för HEAD"
#, c-format
msgid "Synchronizing submodule url for '%s'\n"
-msgstr "Synkroniserar undermodul-url för \"%s\"\n"
+msgstr "Synkroniserar undermodul-url för â€%sâ€\n"
#, c-format
msgid "failed to register url for submodule path '%s'"
-msgstr "misslyckades registrera url för undermodulsökväg \"%s\""
+msgstr "misslyckades registrera url för undermodulsökväg â€%sâ€"
#, c-format
msgid "failed to update remote for submodule '%s'"
-msgstr "misslyckades uppdatera fjärr för undermodulsökväg \"%s\""
+msgstr "misslyckades uppdatera fjärr för undermodulsökväg â€%sâ€"
msgid "suppress output of synchronizing submodule url"
msgstr "dölj utdata från synkronisering av undermodul-url"
@@ -12279,7 +12565,7 @@ msgid ""
"Submodule work tree '%s' contains a .git directory. This will be replaced "
"with a .git file by using absorbgitdirs."
msgstr ""
-"Undermodulsarbetskatalogen \"%s\" innehåller en .git-katalog. Denna kommer "
+"Undermodulsarbetskatalogen â€%s†innehÃ¥ller en .git-katalog. Denna kommer "
"ersättas med en .git-fil med absorbgitdirs."
#, c-format
@@ -12287,16 +12573,15 @@ msgid ""
"Submodule work tree '%s' contains local modifications; use '-f' to discard "
"them"
msgstr ""
-"Undermodulens arbetskatalog \"%s\" har lokala ändringar; \"-f\" kastar bort "
-"dem"
+"Undermodulens arbetskatalog â€%s†har lokala ändringar; â€-f†kastar bort dem"
#, c-format
msgid "Cleared directory '%s'\n"
-msgstr "Rensade katalogen \"%s\"\n"
+msgstr "Rensade katalogen â€%sâ€\n"
#, c-format
msgid "Could not remove submodule work tree '%s'\n"
-msgstr "Kunde inte ta bort undermodulens arbetskatalog \"%s\"\n"
+msgstr "Kunde inte ta bort undermodulens arbetskatalog â€%sâ€\n"
#, c-format
msgid "could not create empty submodule directory %s"
@@ -12304,7 +12589,7 @@ msgstr "kunde inte skapa tom undermodulskatalog %s"
#, c-format
msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
-msgstr "Undermodulen \"%s\" (%s) registrerad för sökvägen \"%s\"\n"
+msgstr "Undermodulen â€%s†(%s) registrerad för sökvägen â€%sâ€\n"
msgid "remove submodule working trees even if they contain local changes"
msgstr ""
@@ -12319,7 +12604,7 @@ msgstr ""
"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<sökväg>...]]"
msgid "Use '--all' if you really want to deinitialize all submodules"
-msgstr "Använd \"--all\" om du verkligen vill avinitiera alla undermoduler"
+msgstr "Använd â€--all†om du verkligen vill avinitiera alla undermoduler"
msgid ""
"An alternate computed from a superproject's alternate is invalid.\n"
@@ -12329,40 +12614,40 @@ msgid ""
msgstr ""
"En suppleant beräknad från huvudprojektets suppleant är ogiltig.\n"
"För att i så fall låta Git klona utan ett suppleant, sätt\n"
-"submodule.alternateErrorStrategy till \"info\" eller, likvärdigt, klona\n"
-"med \"--reference-if-able\" istället för \"--reference\"."
+"submodule.alternateErrorStrategy till â€info†eller, likvärdigt, klona\n"
+"med â€--reference-if-able†istället för â€--referenceâ€."
#, c-format
msgid "could not get a repository handle for gitdir '%s'"
-msgstr "kunde inte få tag i arkivhandtag för gitkatalogen \"%s\""
+msgstr "kunde inte fÃ¥ tag i arkivhandtag för gitkatalogen â€%sâ€"
#, c-format
msgid "submodule '%s' cannot add alternate: %s"
-msgstr "undermodulen \"%s\" kan inte lägga till suppleant: %s"
+msgstr "undermodulen â€%s†kan inte lägga till suppleant: %s"
#, c-format
msgid "Value '%s' for submodule.alternateErrorStrategy is not recognized"
-msgstr "Värdet \"%s\" i submodule.alternateErrorStrategy förstås inte"
+msgstr "Värdet â€%s†i submodule.alternateErrorStrategy förstÃ¥s inte"
#, c-format
msgid "Value '%s' for submodule.alternateLocation is not recognized"
-msgstr "Värdet \"%s\" i submodule.alternateLocation förstås inte"
+msgstr "Värdet â€%s†i submodule.alternateLocation förstÃ¥s inte"
#, c-format
msgid "refusing to create/use '%s' in another submodule's git dir"
-msgstr "vägrar skapa/använda \"%s\" i en annan undermoduls gitkatalog"
+msgstr "vägrar skapa/använda â€%s†i en annan undermoduls gitkatalog"
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "misslyckades klona \"%s\" till undermodulsökvägen \"%s\""
+msgid "directory not empty: '%s'"
+msgstr "katalogen inte tom: â€%sâ€"
#, c-format
-msgid "directory not empty: '%s'"
-msgstr "katalogen inte tom: \"%s\""
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "misslyckades klona â€%s†till undermodulsökvägen â€%sâ€"
#, c-format
msgid "could not get submodule directory for '%s'"
-msgstr "kunde inte få tag i undermodulkatalog för \"%s\""
+msgstr "kunde inte fÃ¥ tag i undermodulkatalog för â€%sâ€"
msgid "alternative anchor for relative paths"
msgstr "alternativa ankare för relativa sökvägar"
@@ -12396,15 +12681,14 @@ msgstr ""
#, c-format
msgid "Invalid update mode '%s' configured for submodule path '%s'"
-msgstr ""
-"Ogiltigt uppdateringsläge \"%s\" konfigurerat för undermodulsökväg \"%s\""
+msgstr "Ogiltigt uppdateringsläge â€%s†konfigurerat för undermodulsökväg â€%sâ€"
#, c-format
msgid "Submodule path '%s' not initialized"
-msgstr "Undermodulsökvägen \"%s\" har inte initierats"
+msgstr "Undermodulsökvägen â€%s†har inte initierats"
msgid "Maybe you want to use 'update --init'?"
-msgstr "Kanske menade du att använda \"update --init\"?"
+msgstr "Kanske menade du att använda â€update --initâ€?"
#, c-format
msgid "Skipping unmerged submodule %s"
@@ -12412,67 +12696,67 @@ msgstr "Hoppar över ej sammanslagen undermodul %s"
#, c-format
msgid "Skipping submodule '%s'"
-msgstr "Hoppar över undermodulen \"%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"
+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"
+msgstr "Misslyckades klona â€%sâ€. Nytt försök planlagt"
#, c-format
msgid "Failed to clone '%s' a second time, aborting"
-msgstr "Misslyckades klona \"%s\" för andra gången, avbryter"
+msgstr "Misslyckades klona â€%s†för andra gÃ¥ngen, avbryter"
#, c-format
msgid "Unable to checkout '%s' in submodule path '%s'"
-msgstr "Kan inte checka ut \"%s\" i undermodulsökvägen \"%s\""
+msgstr "Kan inte checka ut â€%s†i undermodulsökvägen â€%sâ€"
#, c-format
msgid "Unable to rebase '%s' in submodule path '%s'"
-msgstr "Kan inte ombasera \"%s\" i undermodulsökvägen \"%s\""
+msgstr "Kan inte ombasera â€%s†i undermodulsökvägen â€%sâ€"
#, c-format
msgid "Unable to merge '%s' in submodule path '%s'"
-msgstr "Kan inte slå ihop \"%s\" i undermodulsökvägen \"%s\""
+msgstr "Kan inte slÃ¥ ihop â€%s†i undermodulsökvägen â€%sâ€"
#, c-format
msgid "Execution of '%s %s' failed in submodule path '%s'"
-msgstr "Misslyckades köra \"%s %s\" i undermodulsökvägen \"%s\""
+msgstr "Misslyckades köra â€%s %s†i undermodulsökvägen â€%sâ€"
#, c-format
msgid "Submodule path '%s': checked out '%s'\n"
-msgstr "Undermodulsökvägen \"%s\": checkade ut \"%s\"\n"
+msgstr "Undermodulsökvägen â€%sâ€: checkade ut â€%sâ€\n"
#, c-format
msgid "Submodule path '%s': rebased into '%s'\n"
-msgstr "Undermodulsökvägen \"%s\": ombaserade in i \"%s\"\n"
+msgstr "Undermodulsökvägen â€%sâ€: ombaserade in i â€%sâ€\n"
#, c-format
msgid "Submodule path '%s': merged in '%s'\n"
-msgstr "Undermodulsökvägen \"%s\": sammanslagen i \"%s\"\n"
+msgstr "Undermodulsökvägen â€%sâ€: sammanslagen i â€%sâ€\n"
#, c-format
msgid "Submodule path '%s': '%s %s'\n"
-msgstr "Undermodulsökvägen \"%s\": \"%s %s\"\n"
+msgstr "Undermodulsökvägen â€%sâ€: â€%s %sâ€\n"
#, c-format
msgid "Unable to fetch in submodule path '%s'; trying to directly fetch %s:"
-msgstr "Kan inte hämta i undermodulsökväg \"%s\"; försökte hämta %s direkt:"
+msgstr "Kan inte hämta i undermodulsökväg â€%sâ€; försökte hämta %s direkt:"
#, c-format
msgid ""
"Fetched in submodule path '%s', but it did not contain %s. Direct fetching "
"of that commit failed."
msgstr ""
-"Hämtade i undermodulssökvägen \"%s\", men den innehöll inte %s. Direkt "
+"Hämtade i undermodulssökvägen â€%sâ€, men den innehöll inte %s. Direkt "
"hämtning av incheckningen misslyckades."
#, c-format
msgid "could not initialize submodule at path '%s'"
-msgstr "kunde inte initiera undermodul i sökvägen \"%s\""
+msgstr "kunde inte initiera undermodul i sökvägen â€%sâ€"
#, c-format
msgid ""
@@ -12484,19 +12768,19 @@ msgstr ""
#, c-format
msgid "Unable to find current revision in submodule path '%s'"
-msgstr "Kan inte hitta aktuell revision i undermodulsökvägen \"%s\""
+msgstr "Kan inte hitta aktuell revision i undermodulsökvägen â€%sâ€"
#, c-format
msgid "Unable to fetch in submodule path '%s'"
-msgstr "Kan inte hämta i undermodulsökväg \"%s\""
+msgstr "Kan inte hämta i undermodulsökväg â€%sâ€"
#, c-format
msgid "Unable to find %s revision in submodule path '%s'"
-msgstr "Kan inte hitta %s revision i undermodulsökvägen \"%s\""
+msgstr "Kan inte hitta %s revision i undermodulsökvägen â€%sâ€"
#, c-format
msgid "Failed to recurse into submodule path '%s'"
-msgstr "Misslyckades rekursera in i undermodulsökväg \"%s\""
+msgstr "Misslyckades rekursera in i undermodulsökväg â€%sâ€"
msgid "force checkout updates"
msgstr "tvinga utcheckningsuppdateringar"
@@ -12514,13 +12798,13 @@ msgid "don't fetch new objects from the remote site"
msgstr "hämta inte nya objekt från fjärrplatsen"
msgid "use the 'checkout' update strategy (default)"
-msgstr "använd uppdateringsstrategin \"checkout\" (utcheckning; förval)"
+msgstr "använd uppdateringsstrategin â€checkout†(utcheckning; förval)"
msgid "use the 'merge' update strategy"
-msgstr "använd uppdateringsstrategin \"merge\" (sammanslagning)"
+msgstr "använd uppdateringsstrategin â€merge†(sammanslagning)"
msgid "use the 'rebase' update strategy"
-msgstr "använd uppdateringsstrategin \"rebase\" (ombasering)"
+msgstr "använd uppdateringsstrategin â€rebase†(ombasering)"
msgid "create a shallow clone truncated to the specified number of revisions"
msgstr "skapa en grund klon trunkerad till angivet antal revisioner"
@@ -12548,6 +12832,9 @@ msgstr ""
"[no-]recommend-shallow] [--reference <arkiv>] [--recursive] [--[no-]single-"
"branch] [--] [<sökväg>...]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Misslyckades slå upp HEAD som giltig referens."
+
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<flaggor>] [<sökväg>...]"
@@ -12590,19 +12877,19 @@ msgstr ""
#, c-format
msgid "creating branch '%s'"
-msgstr "skapar grenen \"%s\""
+msgstr "skapar grenen â€%sâ€"
#, c-format
msgid "Adding existing repo at '%s' to the index\n"
-msgstr "Lägger till befintligt arkiv i \"%s\" i indexet\n"
+msgstr "Lägger till befintligt arkiv i â€%s†i indexet\n"
#, c-format
msgid "'%s' already exists and is not a valid git repo"
-msgstr "\"%s\" finns redan och är inte ett giltigt git-arkiv"
+msgstr "â€%s†finns redan och är inte ett giltigt git-arkiv"
#, c-format
msgid "A git directory for '%s' is found locally with remote(s):\n"
-msgstr "En git-katalog för \"%s\" hittades lokalt med fjärr(ar):\n"
+msgstr "En git-katalog för â€%s†hittades lokalt med fjärr(ar):\n"
#, c-format
msgid ""
@@ -12616,41 +12903,41 @@ msgstr ""
"Om du vill återanvända den lokala git-katalogen istället för att klona på "
"nytt från\n"
" %s\n"
-"kan du använda flaggan \"--force\". Om den lokala git-katalogen inte är "
+"kan du använda flaggan â€--forceâ€. Om den lokala git-katalogen inte är "
"korrekt\n"
"arkiv eller om du är osäker på vad det här betyder, välj ett annat namn med\n"
-"flaggan \"--name\"."
+"flaggan â€--nameâ€."
#, c-format
msgid "Reactivating local git directory for submodule '%s'\n"
-msgstr "Aktiverar lokal git-katalog för undermodulen \"%s\" på nytt.\n"
+msgstr "Aktiverar lokal git-katalog för undermodulen â€%s†pÃ¥ nytt.\n"
#, c-format
msgid "unable to checkout submodule '%s'"
-msgstr "Kan inte checka ut undermodulen \"%s\""
+msgstr "Kan inte checka ut undermodulen â€%sâ€"
msgid "please make sure that the .gitmodules file is in the working tree"
msgstr "se till att .gitmodules finns i arbetskatalogen"
#, c-format
msgid "Failed to add submodule '%s'"
-msgstr "Misslyckades lägga till undermodulen \"%s\""
+msgstr "Misslyckades lägga till undermodulen â€%sâ€"
#, c-format
msgid "Failed to register submodule '%s'"
-msgstr "Misslyckades registrera undermodulen \"%s\""
+msgstr "Misslyckades registrera undermodulen â€%sâ€"
#, c-format
msgid "'%s' already exists in the index"
-msgstr "\"%s\" finns redan i indexet"
+msgstr "â€%s†finns redan i indexet"
#, c-format
msgid "'%s' already exists in the index and is not a submodule"
-msgstr "\"%s\" finns redan i indexet och är inte en undermodul"
+msgstr "â€%s†finns redan i indexet och är inte en undermodul"
#, c-format
msgid "'%s' does not have a commit checked out"
-msgstr "\"%s\" har inte någon utcheckad incheckning"
+msgstr "â€%s†har inte nÃ¥gon utcheckad incheckning"
msgid "branch of repository to add as submodule"
msgstr "gren från arkivet att lägga till som undermodul"
@@ -12676,11 +12963,11 @@ msgstr "Relativ sökväg kan endast användas från arbetskatalogens toppnivå"
#, c-format
msgid "repo URL: '%s' must be absolute or begin with ./|../"
-msgstr "arkiv-URL: \"%s\" måste vara absolut eller börja med ./|../"
+msgstr "arkiv-URL: â€%s†mÃ¥ste vara absolut eller börja med ./|../"
#, c-format
msgid "'%s' is not a valid submodule name"
-msgstr "\"%s\" är inte ett giltigt namn på undermodul"
+msgstr "â€%s†är inte ett giltigt namn pÃ¥ undermodul"
msgid "git submodule--helper <command>"
msgstr "git submodule--helper <kommando>"
@@ -12715,9 +13002,11 @@ msgstr "skäl till uppdateringen"
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <nyckel-id>] [-f] [-m <medd> | -F <fil>] [-e]\n"
+" [(--trailer <symbol>[(=|:)<värde>])...]\n"
" <taggnamn> [<incheckning> | <objekt>]"
msgid "git tag -d <tagname>..."
@@ -12740,40 +13029,40 @@ msgstr "git tag -v [--format=<format>] <taggnamn>..."
#, c-format
msgid "tag '%s' not found."
-msgstr "taggen \"%s\" hittades inte."
+msgstr "taggen â€%s†hittades inte."
#, c-format
msgid "Deleted tag '%s' (was %s)\n"
-msgstr "Tog bort tagg \"%s\" (var %s)\n"
+msgstr "Tog bort tagg â€%s†(var %s)\n"
#, c-format
msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Skriv ett meddelande för taggen:\n"
" %s\n"
-"Rader som inleds med \"%c\" ignoreras.\n"
+"Rader som inleds med â€%s†ignoreras.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Skriv ett meddelande för taggen:\n"
" %s\n"
-"Rader som inleds med \"%c\" kommer behållas; du kan själv ta bort dem om\n"
+"Rader som inleds med â€%s†kommer behÃ¥llas; du kan själv ta bort dem om\n"
"du vill.\n"
msgid "unable to sign the tag"
-msgstr "kunde inte signera taggen"
+msgstr "kan inte signera taggen"
#, c-format
msgid ""
@@ -12854,17 +13143,20 @@ msgstr "visa endast taggar som ej slagits samman"
msgid "print only tags of the object"
msgstr "visa endast taggar för objektet"
+msgid "could not start 'git column'"
+msgstr "kunde inte starta â€git columnâ€"
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
-msgstr "flaggan \"%s\" är endast tillåten i listläge"
+msgstr "flaggan â€%s†är endast tillÃ¥ten i listläge"
#, c-format
msgid "'%s' is not a valid tag name."
-msgstr "\"%s\" är inte ett giltigt taggnamn."
+msgstr "â€%s†är inte ett giltigt taggnamn."
#, c-format
msgid "tag '%s' already exists"
-msgstr "taggen \"%s\" finns redan"
+msgstr "taggen â€%s†finns redan"
#, c-format
msgid "Invalid cleanup mode %s"
@@ -12872,7 +13164,7 @@ msgstr "Felaktigt städningsläge %s"
#, c-format
msgid "Updated tag '%s' (was %s)\n"
-msgstr "Uppdaterad tagg \"%s\" (var %s)\n"
+msgstr "Uppdaterad tagg â€%s†(var %s)\n"
msgid "pack exceeds maximum allowed size"
msgstr "paket är större än tillåten maximal storlek"
@@ -12904,7 +13196,7 @@ msgstr "misslyckades ta bort katalogen %s"
#, c-format
msgid "Testing mtime in '%s' "
-msgstr "Testar mtime i \"%s\" "
+msgstr "Testar mtime i â€%s†"
msgid "directory stat info does not change after adding a new file"
msgstr "stat-informationen för en katalog ändras inte när nya filer läggs till"
@@ -12964,19 +13256,19 @@ msgid "add the specified entry to the index"
msgstr "lägg till angiven post i indexet"
msgid "mark files as \"not changing\""
-msgstr "markera filer som \"ändras inte\""
+msgstr "markera filer som â€Ã¤ndras inteâ€"
msgid "clear assumed-unchanged bit"
-msgstr "rensa \"assume-unchanged\"-biten"
+msgstr "rensa â€assume-unchangedâ€-biten"
msgid "mark files as \"index-only\""
-msgstr "markera filer som \"endast index\""
+msgstr "markera filer som â€endast indexâ€"
msgid "clear skip-worktree bit"
-msgstr "töm \"skip-worktree\"-biten"
+msgstr "töm â€skip-worktreeâ€-biten"
msgid "do not touch index-only entries"
-msgstr "rör inte \"endast index\"-poster"
+msgstr "rör inte â€endast indexâ€-poster"
msgid "add to index only; do not add content to object database"
msgstr "lägg endast till indexet; lägg inte till innehållet i objektdatabasen"
@@ -13011,6 +13303,9 @@ msgstr "(för porslin) glöm sparade olösta konflikter"
msgid "write index in this format"
msgstr "skriv index i detta format"
+msgid "report on-disk index format version"
+msgstr "rapportera formatversion för indexfilen på disk"
+
msgid "enable or disable split index"
msgstr "aktivera eller inaktivera delat index"
@@ -13030,10 +13325,18 @@ msgid "enable or disable file system monitor"
msgstr "aktivera eller inaktivera filsystemsövervakning"
msgid "mark files as fsmonitor valid"
-msgstr "markera filer som \"fsmonitor valid\""
+msgstr "markera filer som â€fsmonitor validâ€"
msgid "clear fsmonitor valid bit"
-msgstr "töm \"fsmonitor valid\"-bit"
+msgstr "töm â€fsmonitor validâ€-bit"
+
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version: vad %d, sattes till %d"
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
@@ -13068,7 +13371,7 @@ msgstr ""
#, c-format
msgid "Untracked cache enabled for '%s'"
-msgstr "Ospårad cache är aktiverad för \"%s\""
+msgstr "OspÃ¥rad cache är aktiverad för â€%sâ€"
msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
msgstr "core.fsmonitor inte satt; sätt om du verkligen vill aktivera fsmonitor"
@@ -13084,11 +13387,11 @@ msgstr ""
msgid "fsmonitor disabled"
msgstr "fsmonitor inaktiverat"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<flaggor>] -d <refnamn> [<gammaltvärde>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<flaggor>] -d <refnamn> [<gammalt-oid>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr "git update-ref [<flaggor>] <refnamn> <gammaltvärde> [<nyttvärde>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<flaggor>] <refnamn> <gammalt-oid> [<nytt-oid>]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<flaggor>] --stdin [-z]"
@@ -13182,17 +13485,17 @@ 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\""
+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"
+"If you meant to create a worktree containing a new unborn 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"
+"Om meningen var att skapa en arbetskatalog från en ny ofödd\n"
"gren (gren utan incheckningar) för det här arkivet kan du göra\n"
"det med flaggan --orphan:\n"
"\n"
@@ -13200,13 +13503,13 @@ msgstr ""
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"Om meningen var att skapa en arbetskatalog från en ny ofödd\n"
"gren (gren utan incheckningar) för det här arkivet kan du göra\n"
"det med flaggan --orphan:\n"
"\n"
@@ -13224,63 +13527,65 @@ msgstr "låt tid gå ut för arbetskataloger äldre än <tid>"
#, c-format
msgid "'%s' already exists"
-msgstr "\"%s\" finns redan"
+msgstr "â€%s†finns redan"
#, c-format
msgid "unusable worktree destination '%s'"
-msgstr "oanvändbar mål för arbetskatalog \"%s\""
+msgstr "oanvändbar mÃ¥l för arbetskatalog â€%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\" är en saknad men låst arbetskatalog;\n"
-"använd \"%s -f -f\" för att överstyra, eller \"unlock\" och \"prune\" eller "
-"\"remove\" för att rensa"
+"â€%s†är en saknad men lÃ¥st arbetskatalog;\n"
+"använd â€%s -f -f†för att överstyra, eller â€unlock†och â€prune†eller "
+"â€remove†för att rensa"
#, 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\" är en saknad men redan registrerad arbetskatalog;\n"
-"använd \"%s -f\" för att överstyra, eller \"prune\" eller \"remove\" för att "
-"rensa"
+"â€%s†är en saknad men redan registrerad arbetskatalog;\n"
+"använd â€%s -f†för att överstyra, eller â€prune†eller â€remove†för att rensa"
#, c-format
msgid "failed to copy '%s' to '%s'; sparse-checkout may not work correctly"
msgstr ""
-"misslyckades kopiera \"%s\" till \"%s\"; sparse-checkout kanske inte kommer "
-"att fungera korrekt"
+"misslyckades kopiera â€%s†till â€%sâ€; sparse-checkout kanske inte kommer att "
+"fungera korrekt"
#, c-format
msgid "failed to copy worktree config from '%s' to '%s'"
-msgstr ""
-"misslyckades kopiera arbetskatalogkonfiguration från \"%s\" till \"%s\""
+msgstr "misslyckades kopiera arbetskatalogkonfiguration frÃ¥n â€%s†till â€%sâ€"
#, c-format
msgid "failed to unset '%s' in '%s'"
-msgstr "misslyckades slå av \"%s\" i \"%s\""
+msgstr "misslyckades slÃ¥ av â€%s†i â€%sâ€"
#, c-format
msgid "could not create directory of '%s'"
-msgstr "kunde inte skapa katalogen \"%s\""
+msgstr "kunde inte skapa katalogen â€%sâ€"
msgid "initializing"
msgstr "initierar"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "kunde inte hitta den skapade arbetskatalogen â€%sâ€"
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
-msgstr "Förbereder arbetskatalog (ny gren \"%s\")"
+msgstr "Förbereder arbetskatalog (ny gren â€%sâ€)"
#, c-format
msgid "Preparing worktree (resetting branch '%s'; was at %s)"
-msgstr "Förbereder arbetskatalog (återställer gren \"%s\"; var på %s)"
+msgstr "Förbereder arbetskatalog (Ã¥terställer gren â€%sâ€; var pÃ¥ %s)"
#, c-format
msgid "Preparing worktree (checking out '%s')"
-msgstr "Förbereder arbetskatalog (checkar ut \"%s\")"
+msgstr "Förbereder arbetskatalog (checkar ut â€%sâ€)"
#, c-format
msgid "unreachable: invalid reference: %s"
@@ -13297,20 +13602,16 @@ msgid ""
"HEAD contents: '%s'"
msgstr ""
"HEAD pekar på en ogiltig (eller övergiven) referens.\n"
-"HEAD-sökväg: \"%s\"\n"
-"HEAD-innehåll: \"%s\""
+"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"
+"present, stopping; use 'add -f' to override 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"
+"finns, avslutar; använd â€add -f†för att överstyra eller hämta frÃ¥n en fjärr "
+"först"
msgid "checkout <branch> even if already checked out in other worktree"
msgstr ""
@@ -13322,8 +13623,8 @@ 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 "create unborn branch"
+msgstr "skapa en ofödd gren"
msgid "populate the new working tree"
msgstr "befolka den nya arbetskatalogen"
@@ -13342,14 +13643,11 @@ msgstr "försök träffa namn på ny gren mot en fjärrspårande gren"
#, c-format
msgid "options '%s', '%s', and '%s' cannot be used together"
-msgstr "flaggorna \"%s\", \"%s\" och \"%s\" kan inte användas samtidigt"
+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 "option '%s' and commit-ish cannot be used together"
+msgstr "flaggorna â€%s†och incheckning-igt kan inte användas samtidigt"
msgid "added with --lock"
msgstr "lagt till med --lock"
@@ -13361,30 +13659,29 @@ msgid "show extended annotations and reasons, if available"
msgstr "visa utökade annoteringar och grunder, om tillgängliga"
msgid "add 'prunable' annotation to worktrees older than <time>"
-msgstr ""
-"lägg till \"prunable\"-annoteringar till arbetskataloger äldre än <tid>"
+msgstr "lägg till â€prunableâ€-annoteringar till arbetskataloger äldre än <tid>"
msgid "terminate records with a NUL character"
msgstr "avsluta poster med NUL-tecken"
#, c-format
msgid "'%s' is not a working tree"
-msgstr "\"%s\" är inte en arbetskatalog"
+msgstr "â€%s†är inte en arbetskatalog"
msgid "The main working tree cannot be locked or unlocked"
msgstr "Huvudarbetskatalogen kan inte låsas eller låsas upp"
#, c-format
msgid "'%s' is already locked, reason: %s"
-msgstr "\"%s\" är redan låst, orsak: %s"
+msgstr "â€%s†är redan lÃ¥st, orsak: %s"
#, c-format
msgid "'%s' is already locked"
-msgstr "\"%s\" är redan låst"
+msgstr "â€%s†är redan lÃ¥st"
#, c-format
msgid "'%s' is not locked"
-msgstr "\"%s\" är inte låst"
+msgstr "â€%s†är inte lÃ¥st"
msgid "working trees containing submodules cannot be moved or removed"
msgstr "arbetskataloger med undermoduler kan inte flyttas eller tas bort"
@@ -13394,11 +13691,11 @@ msgstr "tvinga flyttning även om arbetskatalogen är smutsig eller låst"
#, c-format
msgid "'%s' is a main working tree"
-msgstr "\"%s\" är inte en huvudarbetskatalog"
+msgstr "â€%s†är inte en huvudarbetskatalog"
#, c-format
msgid "could not figure out destination name from '%s'"
-msgstr "kunde inte lista ut målnamn från \"%s\""
+msgstr "kunde inte lista ut mÃ¥lnamn frÃ¥n â€%sâ€"
#, c-format
msgid ""
@@ -13406,14 +13703,14 @@ msgid ""
"use 'move -f -f' to override or unlock first"
msgstr ""
"kan inte flytta en låst arbetskatalog, orsak till lås: %s\n"
-"använd \"move -f -f\" för att överstyra, eller lås upp först"
+"använd â€move -f -f†för att överstyra, eller lÃ¥s upp först"
msgid ""
"cannot move a locked working tree;\n"
"use 'move -f -f' to override or unlock first"
msgstr ""
"kan inte flytta en låst arbetskatalog;\n"
-"använd \"move -f -f\" för att överstyra, eller lås upp först"
+"använd â€move -f -f†för att överstyra, eller lÃ¥s upp först"
#, c-format
msgid "validation failed, cannot move working tree: %s"
@@ -13421,21 +13718,21 @@ msgstr "kontroll misslyckades, kan inte flytta arbetskatalog: %s"
#, c-format
msgid "failed to move '%s' to '%s'"
-msgstr "misslyckades flytta \"%s\" till \"%s\""
+msgstr "misslyckades flytta â€%s†till â€%sâ€"
#, c-format
msgid "failed to run 'git status' on '%s'"
-msgstr "misslyckades köra \"git status\" på \"%s\""
+msgstr "misslyckades köra â€git status†pÃ¥ â€%sâ€"
#, c-format
msgid "'%s' contains modified or untracked files, use --force to delete it"
msgstr ""
-"\"%s\" innehåller ändrade eller ospårade filer, använd --force för att ta "
-"bort det"
+"â€%s†innehÃ¥ller ändrade eller ospÃ¥rade filer, använd --force för att ta bort "
+"det"
#, c-format
msgid "failed to run 'git status' on '%s', code %d"
-msgstr "misslyckades köra \"git status\" på \"%s\", kod %d"
+msgstr "misslyckades köra â€git status†pÃ¥ â€%sâ€, kod %d"
msgid "force removal even if worktree is dirty or locked"
msgstr "tvinga ta bort även om arbetskatalogen är smutsig eller låst"
@@ -13446,14 +13743,14 @@ msgid ""
"use 'remove -f -f' to override or unlock first"
msgstr ""
"kan inte ta bort en låst arbetskatalog, orsak till låset: %s\n"
-"använd \"remove -f -f\" för att överstyra, eller lås upp först"
+"använd â€remove -f -f†för att överstyra, eller lÃ¥s upp först"
msgid ""
"cannot remove a locked working tree;\n"
"use 'remove -f -f' to override or unlock first"
msgstr ""
"kan inte ta bort en låst arbetskatalog;\n"
-"använd \"remove -f -f\" för att överstyra, eller lås upp först"
+"använd â€remove -f -f†för att överstyra, eller lÃ¥s upp först"
#, c-format
msgid "validation failed, cannot remove working tree: %s"
@@ -13484,11 +13781,11 @@ msgstr "core.fsyncMethod = batch stöds inte på denna plattform"
#, c-format
msgid "could not parse bundle list key %s with value '%s'"
-msgstr "kunde inte tolka listnyckeln %s med värdet \"%s\""
+msgstr "kunde inte tolka listnyckeln %s med värdet â€%sâ€"
#, c-format
msgid "bundle list at '%s' has no mode"
-msgstr "buntlistan på \"%s\" har inget läge"
+msgstr "buntlistan pÃ¥ â€%s†har inget läge"
msgid "failed to create temporary file"
msgstr "misslyckades skapa temporär fil"
@@ -13498,14 +13795,14 @@ msgstr "otillräckliga kapabiliteter"
#, c-format
msgid "file downloaded from '%s' is not a bundle"
-msgstr "filen hämtad från \"%s\" är inte en bunt"
+msgstr "filen hämtad frÃ¥n â€%s†är inte en bunt"
msgid "failed to store maximum creation token"
msgstr "misslyckades lagra maximal skaparsymbol"
#, c-format
msgid "unrecognized bundle mode from URI '%s'"
-msgstr "okänt buntlägre från URI:en \"%s\""
+msgstr "okänt buntlägre frÃ¥n URI:en â€%sâ€"
#, c-format
msgid "exceeded bundle URI recursion limit (%d)"
@@ -13513,35 +13810,35 @@ msgstr "överskred buntens URI-rekursionsgräns (%d)"
#, c-format
msgid "failed to download bundle from URI '%s'"
-msgstr "kunde inte hämta bunt från URI:en \"%s\""
+msgstr "misslyckades hämta bunt frÃ¥n URI:en â€%sâ€"
#, c-format
msgid "file at URI '%s' is not a bundle or bundle list"
-msgstr "filen på URI:en \"%s\" är inte en bunt eller buntlista"
+msgstr "filen pÃ¥ URI:en â€%s†är inte en bunt eller buntlista"
#, c-format
msgid "bundle-uri: unexpected argument: '%s'"
-msgstr "bundle-uri: okänt argument: \"%s\""
+msgstr "bundle-uri: okänt argument: â€%sâ€"
msgid "bundle-uri: expected flush after arguments"
-msgstr "bundle-uri: förväntade \"flush\" efter argument"
+msgstr "bundle-uri: förväntade â€flush†efter argument"
msgid "bundle-uri: got an empty line"
msgstr "bunt-uri: fick en tom rad"
msgid "bundle-uri: line is not of the form 'key=value'"
-msgstr "bunt-uri: raden är inte på formen \"nyckel=värde\""
+msgstr "bunt-uri: raden är inte pÃ¥ formen â€nyckel=värdeâ€"
msgid "bundle-uri: line has empty key or value"
msgstr "bunt-uri: raden har tom nyckel eller värde"
#, c-format
msgid "unrecognized bundle hash algorithm: %s"
-msgstr "okänd hashningsalgoritm för bunt: \"%s\""
+msgstr "okänd hashningsalgoritm för bunt: â€%sâ€"
#, c-format
msgid "unknown capability '%s'"
-msgstr "okänd kapabilitet \"%s\""
+msgstr "okänd kapabilitet â€%sâ€"
#, c-format
msgid "'%s' does not look like a v2 or v3 bundle file"
@@ -13554,9 +13851,6 @@ msgstr "okänt huvud: %s%s (%d)"
msgid "Repository lacks these prerequisite commits:"
msgstr "Arkivet saknar dessa nödvändiga incheckningar:"
-msgid "need a repository to verify a bundle"
-msgstr "behöver ett arkiv för att bekräfta en bunt."
-
msgid ""
"some prerequisite commits exist in the object store, but are not connected "
"to the repository's history"
@@ -13598,7 +13892,7 @@ msgstr "pack-objects misslyckades"
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
-msgstr "referensen \"%s\" exkluderas av argumenten till rev-list"
+msgstr "referensen â€%s†exkluderas av argumenten till rev-list"
#, c-format
msgid "unsupported bundle version %d"
@@ -13613,7 +13907,7 @@ msgstr "Vägrar skapa en tom bunt."
#, c-format
msgid "cannot create '%s'"
-msgstr "kan inte skapa \"%s\""
+msgstr "kan inte skapa â€%sâ€"
msgid "index-pack died"
msgstr "index-pack dog"
@@ -13622,6 +13916,10 @@ msgid "terminating chunk id appears earlier than expected"
msgstr "avslutande stycke-id förekommer tidigare än förväntat"
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "stycke-id %<PRIx32> är inte %d-byte-justerad"
+
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "felaktigt stycke-offset %<PRIx64> och %<PRIx64>"
@@ -13673,9 +13971,8 @@ msgstr "Samla information från användaren för att sända en felrapport"
msgid "Move objects and refs by archive"
msgstr "Flytta objekt och referenser efter arkiv"
-msgid "Provide content or type and size information for repository objects"
-msgstr ""
-"Visa innehåller eller typ- och storleksinformation för objekt i arkivet"
+msgid "Provide contents or details of repository objects"
+msgstr "Visa innehåll eller detaljer för objekt i arkivet"
msgid "Display gitattributes information"
msgstr "Visa information från gitattributes"
@@ -13951,6 +14248,9 @@ msgstr "Ta emot det som sänds till arkivet"
msgid "Manage reflog information"
msgstr "Hantera referenslogg-information"
+msgid "Low-level access to refs"
+msgstr "Lågnivååtkomst till referenser"
+
msgid "Manage set of tracked repositories"
msgstr "Hantera uppsättningen spårade arkiv"
@@ -13960,6 +14260,11 @@ msgstr "Packa opackade objekt i ett arkiv"
msgid "Create, list, delete refs to replace objects"
msgstr "Skapa, visa, ta bort referenser för att ersätta objekt"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"EXPERIMENTELLT: Spela om incheckningar ovanpå en ny bas, fungerar även med "
+"nakna arkiv"
+
msgid "Generates a summary of pending changes"
msgstr "Skapar en sammanfattning av väntande ändringar"
@@ -14000,7 +14305,7 @@ msgid "Restricted login shell for Git-only SSH access"
msgstr "Begränsat inloggningsskal för SSH-åtkomst till bara Git"
msgid "Summarize 'git log' output"
-msgstr "Summera \"git log\"-utdata"
+msgstr "Summera â€git logâ€-utdata"
msgid "Show various types of objects"
msgstr "Visa olika sorters objekt"
@@ -14080,8 +14385,8 @@ msgstr "Kontrollera GPG-signaturer i taggar"
msgid "Display version information about Git"
msgstr "Visa versionsinformation om Git"
-msgid "Show logs with difference each commit introduces"
-msgstr "Visa loggar med differenser varje incheckning introducerar"
+msgid "Show logs with differences each commit introduces"
+msgstr "Visa loggar med ändringarna varje incheckning introducerar"
msgid "Manage multiple working trees"
msgstr "Hantera ytterligare arbetskataloger"
@@ -14197,6 +14502,32 @@ msgstr "Verktyg för att hantera stora Git-arkiv"
msgid "commit-graph file is too small"
msgstr "incheckningsgraffilen %s är för liten"
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "incheckningsgrafens oid-utbredningsstycke har fel storlek"
+
+msgid "commit-graph fanout values out of order"
+msgstr "incheckningsgrafens utbredningsvärden är i fel ordning"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "incheckningsgrafens OID-uppslagningsstycket har fel storlek"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "incheckningsgrafens incheckningsdatastycke har fel storlek"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "incheckningsgrafens generationsstycke har fel storlek"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "incheckningsgrafens ändrade-sökvägar-indexstycke är förö litet"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"ignorerar för litet ändrade-sökvägar-stycke (%<PRIuMAX> < %<PRIuMAX>) i "
+"incheckningsgraffilen"
+
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "incheckningsgrafens signatur %X stämmer inte med signaturen %X"
@@ -14213,9 +14544,32 @@ msgstr "incheckningsgrafens hashversion %X stämmer inte med versionen %X"
msgid "commit-graph file is too small to hold %u chunks"
msgstr "incheckningsgraffilen är för liten för att innehålla %u stycken"
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr ""
+"incheckningsgrafens nödvändiga OID-utbredningsstycke saknas eller är trasigt"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr ""
+"incheckningsgrafens nödvändiga OID-uppslagningsstycke saknas eller är trasigt"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr ""
+"incheckningsgrafens nödvändiga incheckningsdatastycke saknas eller är trasigt"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"inaktivera Bloom-filter för incheckningsgraflager â€%s†pÃ¥ grund av "
+"inkompatibla inställningar"
+
msgid "commit-graph has no base graphs chunk"
msgstr "incheckningsgrafen har inga bas-graf-stycken"
+msgid "commit-graph base graphs chunk is too small"
+msgstr "incheckningsgrafens bas-graf-stycken är för små"
+
msgid "commit-graph chain does not match"
msgstr "incheckningsgrafens kedja stämmer inte"
@@ -14223,9 +14577,12 @@ msgstr "incheckningsgrafens kedja stämmer inte"
msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "antalet incheckningar i basgrafen för högt: %<PRIuMAX>"
+msgid "commit-graph chain file too small"
+msgstr "incheckningsgrafens kedjefil är för liten"
+
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
-msgstr "ogiltig incheckingsgrafkedja: rad \"%s\" är inte ett hash-värde"
+msgstr "ogiltig incheckingsgrafkedja: rad â€%s†är inte ett hash-värde"
msgid "unable to find all commit-graph files"
msgstr "kan inte hitta alla incheckingsgraffiler"
@@ -14240,6 +14597,12 @@ msgstr "kunde inte hitta incheckningen %s"
msgid "commit-graph requires overflow generation data but has none"
msgstr "incheckningsgraf kräver spillgenerationsdata, men har ingen"
+msgid "commit-graph overflow generation data is too small"
+msgstr "incheckningsgrafens spillgenerationsdata är för liten"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "incheckningsgrafens extra-kant-pekare är utanför intervallet"
+
msgid "Loading known commits in commit graph"
msgstr "Läser in kända incheckningar i incheckningsgraf"
@@ -14282,14 +14645,14 @@ msgid "Finding extra edges in commit graph"
msgstr "Söker ytterligare kanter i incheckingsgraf"
msgid "failed to write correct number of base graph ids"
-msgstr "kunde inte skriva korrekt antal bas-graf-id:n"
+msgstr "misslyckades skriva korrekt antal bas-graf-id:n"
msgid "unable to create temporary graph layer"
msgstr "kan inte skapa temporärt graflager"
#, c-format
msgid "unable to adjust shared permissions for '%s'"
-msgstr "kan inte justera delade behörigheter för \"%s\""
+msgstr "kan inte justera delade behörigheter för â€%sâ€"
#, c-format
msgid "Writing out commit graph in %d pass"
@@ -14298,13 +14661,13 @@ msgstr[0] "Skriver ut incheckningsgraf i %d pass"
msgstr[1] "Skriver ut incheckningsgraf i %d pass"
msgid "unable to open commit-graph chain file"
-msgstr "Kunde inte öppna incheckningsgrafkedjefilen"
+msgstr "kan inte öppna incheckningsgrafkedjefilen"
msgid "failed to rename base commit-graph file"
-msgstr "kunde inte byta namn på bas-incheckingsgraffilen"
+msgstr "misslyckades byta namn på bas-incheckingsgraffilen"
msgid "failed to rename temporary commit-graph file"
-msgstr "kunde inte byta namn på temporär incheckningsgraffil"
+msgstr "misslyckades byta namn på temporär incheckningsgraffil"
#, c-format
msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
@@ -14322,7 +14685,15 @@ msgstr "Slår ihop incheckningsgraf"
msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr ""
-"försöker skriva en incheckningsgraf, men \"core.commitGraph\" är inaktiverad"
+"försöker skriva en incheckningsgraf, men â€core.commitGraph†är inaktiverad"
+
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph."
+"changedPathsVersion' (%d) is not supported"
+msgstr ""
+"försöker skriva en incheckningsgraf, men â€commitGraph."
+"changedPathsVersion†(%d) stöds inte"
msgid "too many commits to write graph"
msgstr "för många incheckningar för att skriva graf"
@@ -14343,12 +14714,12 @@ msgstr ""
#, c-format
msgid "failed to parse commit %s from commit-graph"
-msgstr "kunde inte tolka incheckning %s från incheckningsgraf"
+msgstr "misslyckades tolka incheckningen %s från incheckningsgraf"
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
msgstr ""
-"misslyckades tolka incheckning %s från objektdatabasen för incheckningsgraf"
+"misslyckades tolka incheckningen %s från objektdatabasen för incheckningsgraf"
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
@@ -14368,20 +14739,6 @@ msgstr ""
"incheckningsgrafens föräldralista för incheckningen %s avslutas för tidigt"
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr ""
-"incheckningsgrafen har generationsnummer noll för incheckningen %s, men icke-"
-"noll på annan plats"
-
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"incheckningsgrafen har generationsnummer skilt från noll för incheckningen "
-"%s, men noll på annan plats"
-
-#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr ""
"incheckningsgrafens generation för incheckningen %s är %<PRIuMAX> < "
@@ -14393,10 +14750,22 @@ msgstr ""
"incheckningsdatumet för incheckningen %s i incheckningsgrafen är %<PRIuMAX> !"
"= %<PRIuMAX>"
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"incheckningsgrafen har generationsnummer som både är noll och icke-noll "
+"(dvs, incheckningarna â€%s†och â€%sâ€)"
+
msgid "Verifying commits in commit graph"
msgstr "Bekräftar incheckningar i incheckningsgrafen"
#, c-format
+msgid "could not parse commit %s"
+msgstr "kunde inte tolka incheckningen %s"
+
+#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s är inte en incheckning!"
@@ -14413,11 +14782,16 @@ msgstr ""
"Stöd för <GIT_DIR>/info/grafts avråds från och\n"
"kommer tas bort i en framtida version av Git.\n"
"\n"
-"Använd \"git replace --convert-graft-file\"\n"
+"Använd â€git replace --convert-graft-fileâ€\n"
"för att omvandla grafts till ersättningsreferenser.\n"
"\n"
"Slå av detta meddelande genom att skriva\n"
-"\"git config advice.graftFileDeprecated false\""
+"â€git config advice.graftFileDeprecated falseâ€"
+
+#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"incheckningen %s finns i incheckningsgrafen, men inte i objektdatabasen"
#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
@@ -14454,31 +14828,31 @@ msgstr "ingen libc-information tillgänglig\n"
#, c-format
msgid "could not determine free disk size for '%s'"
-msgstr "kunde inte ta reda på ledigt diskutrymme för \"%s\""
+msgstr "kunde inte ta reda pÃ¥ ledigt diskutrymme för â€%sâ€"
#, c-format
msgid "could not get info for '%s'"
-msgstr "kunde inte hämta info för \"%s\""
+msgstr "kunde inte hämta info för â€%sâ€"
#, c-format
msgid "[GLE %ld] health thread could not open '%ls'"
-msgstr "[GLE %ld] hälsotråden kunde inte öppna \"%ls\""
+msgstr "[GLE %ld] hälsotrÃ¥den kunde inte öppna â€%lsâ€"
#, c-format
msgid "[GLE %ld] health thread getting BHFI for '%ls'"
-msgstr "[GLE %ld] hälsotråden hämtar BHFI för \"%ls\""
+msgstr "[GLE %ld] hälsotrÃ¥den hämtar BHFI för â€%lsâ€"
#, c-format
msgid "could not convert to wide characters: '%s'"
-msgstr "kunde inte konvertera till breda tecken: \"%s\""
+msgstr "kunde inte konvertera till breda tecken: â€%sâ€"
#, c-format
msgid "BHFI changed '%ls'"
-msgstr "BHFI ändrade \"%ls\""
+msgstr "BHFI ändrade â€%lsâ€"
#, c-format
msgid "unhandled case in 'has_worktree_moved': %d"
-msgstr "ohanterat fall i \"has_worktree_moved\": %d"
+msgstr "ohanterat fall i â€has_worktree_movedâ€: %d"
#, c-format
msgid "health thread wait failed [GLE %ld]"
@@ -14496,23 +14870,23 @@ msgstr "Misslyckades starta FSEventStream:en"
#, c-format
msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
-msgstr "[GLE %ld] kunde inte konvertera sökväg till UTF-8: \"%.*ls\""
+msgstr "[GLE %ld] kunde inte konvertera sökväg till UTF-8: â€%.*lsâ€"
#, c-format
msgid "[GLE %ld] could not watch '%s'"
-msgstr "[GLE %ld] kunde inte övervaka \"%s\""
+msgstr "[GLE %ld] kunde inte övervaka â€%sâ€"
#, c-format
msgid "[GLE %ld] could not get longname of '%s'"
-msgstr "[GLE %ld] kunde inte hämta långt namn för \"%s\""
+msgstr "[GLE %ld] kunde inte hämta lÃ¥ngt namn för â€%sâ€"
#, c-format
msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
-msgstr "ReadDirectoryChangedW misslyckades på \"%s\" [GLE %ld]"
+msgstr "ReadDirectoryChangedW misslyckades pÃ¥ â€%s†[GLE %ld]"
#, c-format
msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
-msgstr "GetOverlappedResult misslyckades på \"%s\" [GLE %ld]"
+msgstr "GetOverlappedResult misslyckades pÃ¥ â€%s†[GLE %ld]"
#, c-format
msgid "could not read directory changes [GLE %ld]"
@@ -14536,11 +14910,11 @@ msgstr "closedir('%s') misslyckades"
#, c-format
msgid "[GLE %ld] unable to open for read '%ls'"
-msgstr "[GLE %ld] kunde inte öppna \"%ls\" för läsning"
+msgstr "[GLE %ld] kan inte öppna â€%ls†för läsning"
#, c-format
msgid "[GLE %ld] unable to get protocol information for '%ls'"
-msgstr "[GLE %ld] kunde inte hämta protokollinformation för \"%ls\""
+msgstr "[GLE %ld] kan inte hämta protokollinformation för â€%lsâ€"
#, c-format
msgid "failed to copy SID (%ld)"
@@ -14548,7 +14922,7 @@ msgstr "misslyckades kopiera SID (%ld)"
#, c-format
msgid "failed to get owner for '%s' (%ld)"
-msgstr "misslyckades hämta ägaren för \"%s\" (%ld)"
+msgstr "misslyckades hämta ägaren för â€%s†(%ld)"
msgid "memory exhausted"
msgstr "minnet slut"
@@ -14615,15 +14989,15 @@ msgstr "kunde inte läsa IPC-svar"
#, c-format
msgid "could not start accept_thread '%s'"
-msgstr "kunde inte ta status \"accept_thread\" \"%s\""
+msgstr "kunde inte ta status â€accept_thread†â€%sâ€"
#, c-format
msgid "could not start worker[0] for '%s'"
-msgstr "kunde inte starta \"worker[0]\" för \"%s\""
+msgstr "kunde inte starta â€worker[0]†för â€%sâ€"
#, c-format
msgid "ConnectNamedPipe failed for '%s' (%lu)"
-msgstr "ConnectNamedPipe misslyckades för \"%s\" (%lu)"
+msgstr "ConnectNamedPipe misslyckades för â€%s†(%lu)"
#, c-format
msgid "could not create fd from pipe for '%s'"
@@ -14631,14 +15005,14 @@ msgstr "kunde inte skapa filhandtag från rör för %s"
#, c-format
msgid "could not start thread[0] for '%s'"
-msgstr "kunde inte starta thread[0] för \"%s\""
+msgstr "kunde inte starta thread[0] för â€%sâ€"
#, c-format
msgid "wait for hEvent failed for '%s'"
-msgstr "misslyckades vänta på hEvent för \"%s\""
+msgstr "misslyckades vänta pÃ¥ hEvent för â€%sâ€"
msgid "cannot resume in the background, please use 'fg' to resume"
-msgstr "kan inte fortsätta i bakgrunden, använd \"fg\" för att återuppta"
+msgstr "kan inte fortsätta i bakgrunden, använd â€fg†för att Ã¥teruppta"
msgid "cannot restore terminal settings"
msgstr "kan inte återställa terminalinställningar"
@@ -14659,7 +15033,7 @@ msgstr ""
#, c-format
msgid "could not expand include path '%s'"
-msgstr "kunde inte expandera inkluderingssökväg \"%s\""
+msgstr "kunde inte expandera inkluderingssökväg â€%sâ€"
msgid "relative config includes must come from files"
msgstr "relativa konfigureringsinkluderingar måste komma från filer"
@@ -14680,11 +15054,11 @@ msgstr "felaktigt konfigurationsformat: %s"
#, c-format
msgid "missing environment variable name for configuration '%.*s'"
-msgstr "miljövariabelnamn saknas för konfigurationen \"%.*s\""
+msgstr "miljövariabelnamn saknas för konfigurationen â€%.*sâ€"
#, c-format
msgid "missing environment variable '%s' for configuration '%.*s'"
-msgstr "miljövariabeln \"%s\" saknas för konfigurationen \"%.*s\""
+msgstr "miljövariabeln â€%s†saknas för konfigurationen â€%.*sâ€"
#, c-format
msgid "key does not contain a section: %s"
@@ -14761,38 +15135,35 @@ msgstr "ogiltig enhet"
#, c-format
msgid "bad numeric config value '%s' for '%s': %s"
-msgstr "felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\": %s"
+msgstr "felaktigt numeriskt konfigurationsvärde â€%s†för â€%sâ€: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
-msgstr ""
-"felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\" i blob:en %s: %s"
+msgstr "felaktigt numeriskt konfigurationsvärde â€%s†för â€%s†i blob:en %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in file %s: %s"
-msgstr ""
-"felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\" i filen %s: %s"
+msgstr "felaktigt numeriskt konfigurationsvärde â€%s†för â€%s†i filen %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in standard input: %s"
msgstr ""
-"felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\" i standard in: %s"
+"felaktigt numeriskt konfigurationsvärde â€%s†för â€%s†i standard in: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
msgstr ""
-"felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\" i undermodul-blob:"
-"en %s: %s"
+"felaktigt numeriskt konfigurationsvärde â€%s†för â€%s†i undermodul-blob:en "
+"%s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
msgstr ""
-"felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\" i kommandoraden "
-"%s: %s"
+"felaktigt numeriskt konfigurationsvärde â€%s†för â€%s†i kommandoraden %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in %s: %s"
-msgstr "felaktigt numeriskt konfigurationsvärde \"%s\" för \"%s\" i %s: %s"
+msgstr "felaktigt numeriskt konfigurationsvärde â€%s†för â€%s†i %s: %s"
#, c-format
msgid "invalid value for variable %s"
@@ -14800,19 +15171,19 @@ msgstr "ogiltigt värde för variabeln %s"
#, c-format
msgid "ignoring unknown core.fsync component '%s'"
-msgstr "ignorerar okänd core.fsync-komponent \"%s\""
+msgstr "ignorerar okänd core.fsync-komponent â€%sâ€"
#, c-format
msgid "bad boolean config value '%s' for '%s'"
-msgstr "felaktigt booleskt konfigurationsvärde \"%s\" för \"%s\""
+msgstr "felaktigt booleskt konfigurationsvärde â€%s†för â€%sâ€"
#, c-format
msgid "failed to expand user dir in: '%s'"
-msgstr "misslyckades expandera användarkatalog i: \"%s\""
+msgstr "misslyckades expandera användarkatalog i: â€%sâ€"
#, c-format
msgid "'%s' for '%s' is not a valid timestamp"
-msgstr "\"%s\" för \"%s\" är inte en giltig tidsstämpel"
+msgstr "â€%s†för â€%s†är inte en giltig tidsstämpel"
#, c-format
msgid "abbrev length out of range: %d"
@@ -14822,12 +15193,17 @@ 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 ASCII character"
-msgstr "core.commentChar kan bara vara ett ASCII-tecken"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s kan inte innehålla nyradstecken"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s måste innehålla minst ett tecken"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
-msgstr "ignorerar okänt core.fsyncMethod-värde \"%s\""
+msgstr "ignorerar okänt core.fsyncMethod-värde â€%sâ€"
msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
msgstr "core.fsyncObjectFiles avråds från; använd core.fsync istället"
@@ -14849,19 +15225,15 @@ msgstr "måste vara en av nothing, matching, simple, upstream eller current"
#, c-format
msgid "unable to load config blob object '%s'"
-msgstr "kunde inte läsa konfigurerings-blobobjektet \"%s\""
+msgstr "kan inte läsa konfigurerings-blobobjektet â€%sâ€"
#, c-format
msgid "reference '%s' does not point to a blob"
-msgstr "referensen \"%s\" pekar inte på en blob"
+msgstr "referensen â€%s†pekar inte pÃ¥ en blob"
#, c-format
msgid "unable to resolve config blob '%s'"
-msgstr "kan inte slå upp konfigurerings-bloben \"%s\""
-
-#, c-format
-msgid "failed to parse %s"
-msgstr "kunde inte tolka %s"
+msgstr "kan inte slÃ¥ upp konfigurerings-bloben â€%sâ€"
msgid "unable to parse command-line config"
msgstr "kan inte tolka kommandoradskonfiguration"
@@ -14871,24 +15243,24 @@ msgstr "okänt fel uppstod vid läsning av konfigurationsfilerna"
#, c-format
msgid "Invalid %s: '%s'"
-msgstr "Felaktigt %s: \"%s\""
+msgstr "Felaktigt %s: â€%sâ€"
#, c-format
msgid "splitIndex.maxPercentChange value '%d' should be between 0 and 100"
msgstr ""
-"värdet \"%d\" för splitIndex.maxPercentChange borde vara mellan 0 och 100"
+"värdet â€%d†för splitIndex.maxPercentChange borde vara mellan 0 och 100"
#, c-format
msgid "unable to parse '%s' from command-line config"
-msgstr "kunde inte tolka värdet \"%s\" från kommandoradskonfiguration"
+msgstr "kan inte tolka värdet â€%s†frÃ¥n kommandoradskonfiguration"
#, c-format
msgid "bad config variable '%s' in file '%s' at line %d"
-msgstr "felaktig konfigurationsvariabel \"%s\" i filen \"%s\" på rad %d"
+msgstr "felaktig konfigurationsvariabel â€%s†i filen â€%s†pÃ¥ rad %d"
#, c-format
msgid "invalid section name '%s'"
-msgstr "felaktigt sektionsnamn \"%s\""
+msgstr "felaktigt sektionsnamn â€%sâ€"
#, c-format
msgid "%s has multiple values"
@@ -14896,7 +15268,11 @@ msgstr "%s har flera värden"
#, c-format
msgid "failed to write new configuration file %s"
-msgstr "kan inte skriva nya konfigurationsfilen \"%s\""
+msgstr "misslyckades skriva nya konfigurationsfilen â€%sâ€"
+
+#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "inga flerradiga kommentarer tillÃ¥tna: â€%sâ€"
#, c-format
msgid "could not lock config file %s"
@@ -14908,7 +15284,7 @@ msgstr "öppnar %s"
#, c-format
msgid "invalid config file %s"
-msgstr "ogiltig konfigurationsfil: \"%s\""
+msgstr "ogiltig konfigurationsfil: â€%sâ€"
#, c-format
msgid "fstat on %s failed"
@@ -14916,7 +15292,7 @@ msgstr "fstat misslyckades på %s"
#, c-format
msgid "unable to mmap '%s'%s"
-msgstr "kunde inte utföra mmap på \"%s\"%s"
+msgstr "kan inte utföra mmap pÃ¥ â€%sâ€%s"
#, c-format
msgid "chmod on %s failed"
@@ -14928,7 +15304,7 @@ msgstr "kunde inte skriva konfigurationsfilen %s"
#, c-format
msgid "could not set '%s' to '%s'"
-msgstr "kunde inte ställa in \"%s\" till \"%s\""
+msgstr "kunde inte ställa in â€%s†till â€%sâ€"
#, c-format
msgid "invalid section name: %s"
@@ -14936,11 +15312,11 @@ 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>"
+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\""
+msgstr "värde saknas för â€%sâ€"
msgid "the remote end hung up upon initial contact"
msgstr "fjärren lade på vid inledande kontakt"
@@ -14958,25 +15334,25 @@ msgstr ""
#, c-format
msgid "server doesn't support '%s'"
-msgstr "Servern stöder inte \"%s\""
+msgstr "Servern stöder inte â€%sâ€"
#, c-format
msgid "server doesn't support feature '%s'"
-msgstr "servern stöder inte funktionen \"%s\""
+msgstr "servern stöder inte funktionen â€%sâ€"
msgid "expected flush after capabilities"
-msgstr "förväntade \"flush\" efter förmågor"
+msgstr "förväntade â€flush†efter förmÃ¥gor"
#, c-format
msgid "ignoring capabilities after first line '%s'"
-msgstr "ignorerar förmågor efter första raden \"%s\""
+msgstr "ignorerar förmÃ¥gor efter första raden â€%sâ€"
msgid "protocol error: unexpected capabilities^{}"
msgstr "protokollfel: förväntade inte capabilities^{}"
#, c-format
msgid "protocol error: expected shallow sha-1, got '%s'"
-msgstr "protokollfel: förväntade \"shallow sha-1\" fick \"%s\""
+msgstr "protokollfel: förväntade â€shallow sha-1†fick â€%sâ€"
msgid "repository on the other end cannot be shallow"
msgstr "arkivet på andra sidan kan inte vara grunt"
@@ -14986,18 +15362,18 @@ msgstr "ogiltigt paket"
#, c-format
msgid "protocol error: unexpected '%s'"
-msgstr "protokollfel: förväntade inte \"%s\""
+msgstr "protokollfel: förväntade inte â€%sâ€"
#, c-format
msgid "unknown object format '%s' specified by server"
-msgstr "okänt objektformat \"%s\" angavs av servern"
+msgstr "okänt objektformat â€%s†angavs av servern"
#, c-format
msgid "error on bundle-uri response line %d: %s"
msgstr "fel på bundle-uri-svar rad %d: %s"
msgid "expected flush after bundle-uri listing"
-msgstr "förväntade \"flush\" efter bundle-uri-listan"
+msgstr "förväntade â€flush†efter bundle-uri-listan"
msgid "expected response end packet after ref listing"
msgstr "förväntade svarsavslutningspaket efter ref-listan"
@@ -15007,14 +15383,14 @@ msgid "invalid ls-refs response: %s"
msgstr "ogiltigt svar på ls-refs: %s"
msgid "expected flush after ref listing"
-msgstr "förväntade \"flush\" efter ref-listan"
+msgstr "förväntade â€flush†efter ref-listan"
#, c-format
msgid "protocol '%s' is not supported"
-msgstr "protokollet \"%s\" stöds inte"
+msgstr "protokollet â€%s†stöds inte"
msgid "unable to set SO_KEEPALIVE on socket"
-msgstr "kunde inte sätta SO_KEEPALIVE på uttaget"
+msgstr "kan inte sätta SO_KEEPALIVE på uttaget"
#, c-format
msgid "Looking up %s ... "
@@ -15038,7 +15414,7 @@ msgid ""
"unable to connect to %s:\n"
"%s"
msgstr ""
-"kunde inte ansluta till %s:\n"
+"kan inte ansluta till %s:\n"
"%s"
#. TRANSLATORS: this is the end of "Connecting to %s (port %s) ... "
@@ -15047,7 +15423,7 @@ msgstr "klart."
#, c-format
msgid "unable to look up %s (%s)"
-msgstr "kunde inte slå upp %s (%s)"
+msgstr "kan inte slå upp %s (%s)"
#, c-format
msgid "unknown port %s"
@@ -15055,46 +15431,46 @@ msgstr "okänd port %s"
#, c-format
msgid "strange hostname '%s' blocked"
-msgstr "konstigt värdnamn \"%s\" blockerat"
+msgstr "konstigt värdnamn â€%s†blockerat"
#, c-format
msgid "strange port '%s' blocked"
-msgstr "konstig port \"%s\" blockerad"
+msgstr "konstig port â€%s†blockerad"
#, c-format
msgid "cannot start proxy %s"
msgstr "kan inte starta mellanserver (proxy) %s"
msgid "no path specified; see 'git help pull' for valid url syntax"
-msgstr "ingen sökväg angavs; se \"git help pull\" för giltig URL-syntax"
+msgstr "ingen sökväg angavs; se â€git help pull†för giltig URL-syntax"
msgid "newline is forbidden in git:// hosts and repo paths"
msgstr "radbrytningar är förbjudna i git://-värdnamn och arkivsökvägar"
msgid "ssh variant 'simple' does not support -4"
-msgstr "ssh-varianten \"simple\" stöder inte -4"
+msgstr "ssh-varianten â€simple†stöder inte -4"
msgid "ssh variant 'simple' does not support -6"
-msgstr "ssh-varianten \"simple\" stöder inte -6"
+msgstr "ssh-varianten â€simple†stöder inte -6"
msgid "ssh variant 'simple' does not support setting port"
-msgstr "ssh-varianten \"simple\" stöder inte val av port"
+msgstr "ssh-varianten â€simple†stöder inte val av port"
#, c-format
msgid "strange pathname '%s' blocked"
-msgstr "konstigt sökvägsnamn \"%s\" blockerat"
+msgstr "konstigt sökvägsnamn â€%s†blockerat"
msgid "unable to fork"
-msgstr "kunde inte grena (fork)"
+msgstr "kan inte grena (fork)"
msgid "Could not run 'git rev-list'"
-msgstr "Kunde inte köra \"git rev-list\""
+msgstr "Kunde inte köra â€git rev-listâ€"
msgid "failed write to rev-list"
-msgstr "kunde inte skriva till rev-list"
+msgstr "misslyckades skriva till rev-list"
msgid "failed to close rev-list's stdin"
-msgstr "kunde inte stänga rev-list:s standard in"
+msgstr "misslyckades stänga rev-list:s standard in"
#, c-format
msgid "illegal crlf_action %d"
@@ -15109,7 +15485,7 @@ msgid ""
"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
"touches it"
msgstr ""
-"CRLF i arbetskopian av \"%s\" kommer ersättas med LF nästa gång Git rör den"
+"CRLF i arbetskopian av â€%s†kommer ersättas med LF nästa gÃ¥ng Git rör den"
#, c-format
msgid "LF would be replaced by CRLF in %s"
@@ -15120,60 +15496,59 @@ msgid ""
"in the working copy of '%s', LF will be replaced by CRLF the next time Git "
"touches it"
msgstr ""
-"LF i arbetskopian av \"%s\" kommer ersättas med CRLF nästa gång Git rör den"
+"LF i arbetskopian av â€%s†kommer ersättas med CRLF nästa gÃ¥ng Git rör den"
#, c-format
msgid "BOM is prohibited in '%s' if encoded as %s"
-msgstr "BOM är förbjudet i \"%s\" om kodat som %s"
+msgstr "BOM är förbjudet i â€%s†om kodat som %s"
#, c-format
msgid ""
"The file '%s' contains a byte order mark (BOM). Please use UTF-%.*s as "
"working-tree-encoding."
msgstr ""
-"Filen \"%s\" innehåller byte order mark (BOM). Använd UTF-%.*s som "
+"Filen â€%s†innehÃ¥ller byte order mark (BOM). Använd UTF-%.*s som "
"teckenkodning i arbetskatalogen."
#, c-format
msgid "BOM is required in '%s' if encoded as %s"
-msgstr "BOM krävs om \"%s\" kodas som %s"
+msgstr "BOM krävs om â€%s†kodas som %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 ""
-"Filen \"%s\" saknar byte order mark (BOM). Använd UTF-%sBE eller UTF-%sLE "
+"Filen â€%s†saknar byte order mark (BOM). Använd UTF-%sBE eller UTF-%sLE "
"(beroende på byteordning) som teckenkodning i arbetskatalogen."
#, c-format
msgid "failed to encode '%s' from %s to %s"
-msgstr "misslyckades omkoda \"%s\" från %s till %s"
+msgstr "misslyckades omkoda â€%s†frÃ¥n %s till %s"
#, c-format
msgid "encoding '%s' from %s to %s and back is not the same"
-msgstr ""
-"omkodning av \"%s\" från %s till %s och tillbaka ger inte samma resultat"
+msgstr "omkodning av â€%s†frÃ¥n %s till %s och tillbaka ger inte samma resultat"
#, c-format
msgid "cannot fork to run external filter '%s'"
-msgstr "kan inte grena (fork) för att köra externt filter \"%s\""
+msgstr "kan inte grena (fork) av för att köra externt filter â€%sâ€"
#, c-format
msgid "cannot feed the input to external filter '%s'"
-msgstr "kunde inte skicka indata till externt filter \"%s\""
+msgstr "kunde inte skicka indata till externt filter â€%sâ€"
#, c-format
msgid "external filter '%s' failed %d"
-msgstr "externt filter \"%s\" misslyckades %d"
+msgstr "externt filter â€%s†misslyckades %d"
#, c-format
msgid "read from external filter '%s' failed"
-msgstr "läsning från externt filter \"%s\" misslyckades"
+msgstr "läsning frÃ¥n externt filter â€%s†misslyckades"
#, c-format
msgid "external filter '%s' failed"
-msgstr "externt filter \"%s\" misslyckades"
+msgstr "externt filter â€%s†misslyckades"
msgid "unexpected filter type"
msgstr "oväntad filtertyp"
@@ -15186,19 +15561,19 @@ msgid ""
"external filter '%s' is not available anymore although not all paths have "
"been filtered"
msgstr ""
-"externt filter \"%s\" är inte längre tillgängligt trots att alla sökvägar "
-"inte har filtrerats"
+"externt filter â€%s†är inte längre tillgängligt trots att alla sökvägar inte "
+"har filtrerats"
msgid "true/false are no valid working-tree-encodings"
msgstr "true/false är inte giltig teckenkodning för arbetskatalogen"
#, c-format
msgid "%s: clean filter '%s' failed"
-msgstr "%s: \"clean\"-filtret \"%s\" misslyckades"
+msgstr "%s: â€cleanâ€-filtret â€%s†misslyckades"
#, c-format
msgid "%s: smudge filter %s failed"
-msgstr "%s: \"smudge\"-filtret \"%s\" misslyckades"
+msgstr "%s: â€smudgeâ€-filtret â€%s†misslyckades"
#, c-format
msgid "skipping credential lookup for key: credential.%s"
@@ -15289,7 +15664,7 @@ msgstr "felaktigt trädobjektet %s"
#, c-format
msgid "failed to load island regex for '%s': %s"
-msgstr "kunde inte hämta ö-regex för \"%s\": %s"
+msgstr "misslyckades hämta ö-regex för â€%sâ€: %s"
#, c-format
msgid "island regex from config has too many capture groups (max=%d)"
@@ -15301,26 +15676,26 @@ msgstr "Markerade %d öar, klar.\n"
#, c-format
msgid "invalid --%s value '%s'"
-msgstr "ogiltigt värde för --%s: \"%s\""
+msgstr "ogiltigt värde för --%s: â€%sâ€"
#, c-format
msgid "could not archive missing directory '%s'"
-msgstr "kunde inte arkivera saknad katalog \"%s\""
+msgstr "kunde inte arkivera saknad katalog â€%sâ€"
#, c-format
msgid "could not open directory '%s'"
-msgstr "kunde inte öppna katalogen \"%s\""
+msgstr "kunde inte öppna katalogen â€%sâ€"
#, c-format
msgid "skipping '%s', which is neither file nor directory"
-msgstr "hoppar över \"%s\", som varken är en fil eller en katalog"
+msgstr "hoppar över â€%sâ€, som varken är en fil eller en katalog"
msgid "could not duplicate stdout"
msgstr "kunde inte duplicera standard ut"
#, c-format
msgid "could not add directory '%s' to archiver"
-msgstr "kunde inte lägga till katalogen \"%s\" till arkiveraren"
+msgstr "kunde inte lägga till katalogen â€%s†till arkiveraren"
msgid "failed to write archive"
msgstr "misslyckades skriva arkiv"
@@ -15328,9 +15703,6 @@ msgstr "misslyckades skriva arkiv"
msgid "--merge-base does not work with ranges"
msgstr "--merge-base fungerar inte med intervall"
-msgid "--merge-base only works with commits"
-msgstr "--merge-base fungerar bara med incheckningar"
-
msgid "unable to get HEAD"
msgstr "kan inte hämta HEAD"
@@ -15358,27 +15730,26 @@ msgstr ""
#, c-format
msgid " Failed to parse dirstat cut-off percentage '%s'\n"
-msgstr " Misslyckades tolka dirstat-avskärningsprocentandel \"%s\"\n"
+msgstr " Misslyckades tolka dirstat-avskärningsprocentandel â€%sâ€\n"
#, c-format
msgid " Unknown dirstat parameter '%s'\n"
-msgstr " Okänd dirstat-parameter \"%s\"\n"
+msgstr " Okänd dirstat-parameter â€%sâ€\n"
msgid ""
"color moved setting must be one of 'no', 'default', 'blocks', 'zebra', "
"'dimmed-zebra', 'plain'"
msgstr ""
-"färginställningen för flyttade block måste vara en av \"no\", \"default\", "
-"\"blocks\", \"zebra\", \"dimmed-zebra\", \"plain\""
+"färginställningen för flyttade block mÃ¥ste vara en av â€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 ""
-"okänt läge \"%s\" för color-moved-ws, möjliga värden är \"ignore-space-change"
-"\", \"ignore-space-at-eol\", \"ignore-all-space\", \"allow-indentation-change"
-"\""
+"okänt läge â€%s†för color-moved-ws, möjliga värden är â€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 "
@@ -15389,14 +15760,18 @@ msgstr ""
#, c-format
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
-msgstr "Okänt värde för konfigurationsvariabeln \"diff.submodule\": \"%s\""
+msgstr "Okänt värde för konfigurationsvariabeln â€diff.submoduleâ€: â€%sâ€"
+
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "okänt värde för inställningen â€%sâ€: %s"
#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
msgstr ""
-"Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n"
+"Hittade fel i konfigurationsvariabeln â€diff.dirstatâ€:\n"
"%s"
#, c-format
@@ -15412,21 +15787,19 @@ 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 ""
-"flaggorna \"%s\", \"%s\", \"%s\" och \"%s\" kan inte användas samtidigt"
+msgstr "flaggorna â€%sâ€, â€%sâ€, â€%s†och â€%s†kan inte användas samtidigt"
#, c-format
msgid "options '%s' and '%s' cannot be used together, use '%s' with '%s'"
msgstr ""
-"flaggorna \"%s\" och \"%s\" kan inte användas samtidigt, använd \"%s\" med "
-"\"%s\""
+"flaggorna â€%s†och â€%s†kan inte användas samtidigt, använd â€%s†med â€%sâ€"
#, c-format
msgid ""
"options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
msgstr ""
-"flaggorna \"%s\" och \"%s\" kan inte användas samtidigt, använd \"%s\" med "
-"\"%s\" och \"%s\""
+"flaggorna â€%s†och â€%s†kan inte användas samtidigt, använd â€%s†med â€%s†"
+"och â€%sâ€"
#, c-format
msgid "invalid --stat value: %s"
@@ -15446,7 +15819,7 @@ msgstr ""
#, c-format
msgid "unknown change class '%c' in --diff-filter=%s"
-msgstr "okänd ändringsklass \"%c\" i --diff-filter=%s"
+msgstr "okänd ändringsklass â€%c†i --diff-filter=%s"
#, c-format
msgid "unknown value after ws-error-highlight=%.*s"
@@ -15454,7 +15827,7 @@ msgstr "okänt värde efter ws-error-highlight=%.*s"
#, c-format
msgid "unable to resolve '%s'"
-msgstr "kunde inte slå upp \"%s\""
+msgstr "kan inte slÃ¥ upp â€%sâ€"
#, c-format
msgid "%s expects <n>/<m> form"
@@ -15462,7 +15835,7 @@ msgstr "%s förväntar formen <n>/<m>"
#, c-format
msgid "%s expects a character, got '%s'"
-msgstr "%s förväntar ett tecken, fick \"%s\""
+msgstr "%s förväntar ett tecken, fick â€%sâ€"
#, c-format
msgid "bad --color-moved argument: %s"
@@ -15470,14 +15843,7 @@ msgstr "felaktigt argument till --color-moved: %s"
#, c-format
msgid "invalid mode '%s' in --color-moved-ws"
-msgstr "ogiltigt läge %s\" i --color-moved-ws"
-
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"flaggan diff-algorithm godtar\"myers\", \"minimal\", \"patience\" och "
-"\"histogram\""
+msgstr "ogiltigt läge %s†i --color-moved-ws"
#, c-format
msgid "invalid argument to %s"
@@ -15485,11 +15851,11 @@ msgstr "ogiltigt argument för %s"
#, c-format
msgid "invalid regex given to -I: '%s'"
-msgstr "ogiltigt reguljärt uttryck angavs för -I: \"%s\""
+msgstr "ogiltigt reguljärt uttryck angavs för -I: â€%sâ€"
#, c-format
msgid "failed to parse --submodule option parameter: '%s'"
-msgstr "misslyckades tolka argument till flaggan --submodule: \"%s\""
+msgstr "misslyckades tolka argument till flaggan --submodule: â€%sâ€"
#, c-format
msgid "bad --word-diff argument: %s"
@@ -15511,10 +15877,10 @@ msgid "generate the diff in raw format"
msgstr "generera diff i råformat"
msgid "synonym for '-p --raw'"
-msgstr "synonym till \"-p --raw\""
+msgstr "synonym till â€-p --rawâ€"
msgid "synonym for '-p --stat'"
-msgstr "synonym till \"-p --stat\""
+msgstr "synonym till â€-p --statâ€"
msgid "machine friendly --stat"
msgstr "maskinläsbar --stat"
@@ -15522,8 +15888,8 @@ msgstr "maskinläsbar --stat"
msgid "output only the last line of --stat"
msgstr "skriv bara ut den sista raden för --stat"
-msgid "<param1,param2>..."
-msgstr "<param1,param2>..."
+msgid "<param1>,<param2>..."
+msgstr "<param1>,<param2>..."
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
@@ -15533,8 +15899,8 @@ msgstr ""
msgid "synonym for --dirstat=cumulative"
msgstr "synonym för --dirstat=cumulative"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "synonym för --dirstat=filer,param1,param2..."
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "synonym för --dirstat=filer,<param1>,<param2>..."
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr "varna om ändringar introducerar konfliktmarkörer eller blankstegsfel"
@@ -15580,7 +15946,7 @@ msgstr "skapa en binärdiff som kan appliceras"
msgid "show full pre- and post-image object names on the \"index\" lines"
msgstr ""
-"visa fullständiga objektnamn i \"index\"-rader för läget både före och efter"
+"visa fullständiga objektnamn i â€indexâ€-rader för läget bÃ¥de före och efter"
msgid "show colored diff"
msgstr "visa färgad diff"
@@ -15592,8 +15958,8 @@ msgid ""
"highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
"diff"
msgstr ""
-"ljusmarkera blankstegsfel i \"context\" (sammanhang), \"old\" (gamla) eller "
-"\"new\" (nya) rader i diffen"
+"ljusmarkera blankstegsfel i â€context†(sammanhang), â€old†(gamla) eller "
+"â€new†(nya) rader i diffen"
msgid ""
"do not munge pathnames and use NULs as output field terminators in --raw or "
@@ -15606,10 +15972,10 @@ msgid "<prefix>"
msgstr "<prefix>"
msgid "show the given source prefix instead of \"a/\""
-msgstr "visa givet källprefix istället för \"a/\""
+msgstr "visa givet källprefix istället för â€a/â€"
msgid "show the given destination prefix instead of \"b/\""
-msgstr "visa givet målprefix istället för \"b/\""
+msgstr "visa givet mÃ¥lprefix istället för â€b/â€"
msgid "prepend an additional prefix to every line of output"
msgstr "lägg till ytterligare prefix på alla rader i utdata"
@@ -15627,13 +15993,13 @@ msgid "<char>"
msgstr "<tecken>"
msgid "specify the character to indicate a new line instead of '+'"
-msgstr "ange tecken för att ange ny rad istället för \"+\""
+msgstr "ange tecken för att ange ny rad istället för â€+â€"
msgid "specify the character to indicate an old line instead of '-'"
-msgstr "ange tecken för att ange gammal rad istället för \"-\""
+msgstr "ange tecken för att ange gammal rad istället för â€-â€"
msgid "specify the character to indicate a context instead of ' '"
-msgstr "ange tecken för att ange sammanhang istället för \" \""
+msgstr "ange tecken för att ange sammanhang istället för †â€"
msgid "Diff rename options"
msgstr "Diff-namnbytesflaggor"
@@ -15703,22 +16069,16 @@ msgid "heuristic to shift diff hunk boundaries for easy reading"
msgstr "heuristik för att flytta diff-gränser för lättare läsning"
msgid "generate diff using the \"patience diff\" algorithm"
-msgstr "skapa diffar med algoritmen \"patience diff\""
+msgstr "skapa diffar med algoritmen â€patience diffâ€"
msgid "generate diff using the \"histogram diff\" algorithm"
-msgstr "skapa diffar med algoritmen \"histogram diff\""
-
-msgid "<algorithm>"
-msgstr "<algoritm>"
-
-msgid "choose a diff algorithm"
-msgstr "välj en diff-algoritm"
+msgstr "skapa diffar med algoritmen â€histogram diffâ€"
msgid "<text>"
msgstr "<text>"
msgid "generate diff using the \"anchored diff\" algorithm"
-msgstr "skapa diffar med algoritmen \"anchored diff\""
+msgstr "skapa diffar med algoritmen â€anchored diffâ€"
msgid "<mode>"
msgstr "<läge>"
@@ -15777,10 +16137,10 @@ msgid "specify how differences in submodules are shown"
msgstr "ange hur ändringar i undermoduler visas"
msgid "hide 'git add -N' entries from the index"
-msgstr "dölj \"git add -N\"-poster från indexet"
+msgstr "dölj â€git add -Nâ€-poster frÃ¥n indexet"
msgid "treat 'git add -N' entries as real in the index"
-msgstr "tolka \"git add -N\"-poster som äkta i indexet"
+msgstr "tolka â€git add -Nâ€-poster som äkta i indexet"
msgid "<string>"
msgstr "<sträng>"
@@ -15850,18 +16210,18 @@ msgstr ""
#, c-format
msgid "failed to read orderfile '%s'"
-msgstr "kunde inte läsa orderfilen \"%s\""
+msgstr "misslyckades läsa orderfilen â€%sâ€"
msgid "Performing inexact rename detection"
msgstr "Utför onöjaktig namnbytesdetektering"
#, c-format
msgid "No such path '%s' in the diff"
-msgstr "Sökvägen \"%s\" finns inte i diffen"
+msgstr "Sökvägen â€%s†finns inte i diffen"
#, c-format
msgid "pathspec '%s' did not match any file(s) known to git"
-msgstr "sökvägsangivelsen \"%s\" motsvarade inte några av git kända filer"
+msgstr "sökvägsangivelsen â€%s†motsvarade inte nÃ¥gra av git kända filer"
#, c-format
msgid "unrecognized pattern: '%s'"
@@ -15874,7 +16234,7 @@ msgstr "okänt negativt mönster: %s"
#, c-format
msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
msgstr ""
-"din \"sparse-checkout\"-fil kan ha problem: mönstret \"%s\" förekommer flera "
+"din â€sparse-checkoutâ€-fil kan ha problem: mönstret â€%s†förekommer flera "
"gånger"
msgid "disabling cone pattern matching"
@@ -15907,7 +16267,7 @@ msgstr "kunde inte skapa kataloger för %s"
#, c-format
msgid "could not migrate git directory from '%s' to '%s'"
-msgstr "kunde inte migrera git-katalog från \"%s\" till \"%s\""
+msgstr "kunde inte migrera git-katalog frÃ¥n â€%s†till â€%sâ€"
#, c-format
msgid "hint: Waiting for your editor to close the file...%c"
@@ -15915,22 +16275,22 @@ 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\""
+msgstr "kunde inte skriva till â€%sâ€"
#, c-format
msgid "could not edit '%s'"
-msgstr "kunde inte redigera \"%s\""
+msgstr "kunde inte redigera â€%sâ€"
msgid "Filtering content"
msgstr "Filtrerar innehåll"
#, c-format
msgid "could not stat file '%s'"
-msgstr "kunde inte ta status på filen \"%s\""
+msgstr "kunde inte ta status pÃ¥ filen â€%sâ€"
#, c-format
msgid "bad git namespace path \"%s\""
-msgstr "felaktig git-namnrymdssökväg \"%s\""
+msgstr "felaktig git-namnrymdssökväg â€%sâ€"
#, c-format
msgid "too many args to run %s"
@@ -15947,21 +16307,21 @@ msgstr "git fetch-pack: förväntade ACK/NAK, fick flush-paket"
#, c-format
msgid "git fetch-pack: expected ACK/NAK, got '%s'"
-msgstr "git fetch-pack: förväntade ACK/NAK, fick \"%s\""
+msgstr "git fetch-pack: förväntade ACK/NAK, fick â€%sâ€"
msgid "unable to write to remote"
-msgstr "kunde inte skriva till fjärren"
+msgstr "kan inte skriva till fjärren"
msgid "Server supports filter"
msgstr "Servern stöder filter"
#, c-format
msgid "invalid shallow line: %s"
-msgstr "ogiltig \"shallow\"-rad: %s"
+msgstr "ogiltig â€shallowâ€-rad: %s"
#, c-format
msgid "invalid unshallow line: %s"
-msgstr "ogiltig \"unshallow\"-rad: %s"
+msgstr "ogiltig â€unshallowâ€-rad: %s"
#, c-format
msgid "object not found: %s"
@@ -15973,7 +16333,7 @@ msgstr "fel i objekt: %s"
#, c-format
msgid "no shallow found: %s"
-msgstr "ingen \"shallow\" hittades: %s"
+msgstr "ingen â€shallow†hittades: %s"
#, c-format
msgid "expected shallow/unshallow, got %s"
@@ -16006,14 +16366,14 @@ msgid "already have %s (%s)"
msgstr "har redan %s (%s)"
msgid "fetch-pack: unable to fork off sideband demultiplexer"
-msgstr "fetch-patch: kunde inte grena av sidbandsmultiplexare"
+msgstr "fetch-patch: kan inte grena (fork) av sidbandsmultiplexare"
msgid "protocol error: bad pack header"
msgstr "protokollfel: felaktigt packhuvud"
#, c-format
msgid "fetch-pack: unable to fork off %s"
-msgstr "fetch-patch: kunde inte grena av %s"
+msgstr "fetch-patch: kan inte grena (fork) av %s"
msgid "fetch-pack: invalid index-pack output"
msgstr "fetch-patch: ogiltig utdata från index-pack"
@@ -16060,25 +16420,25 @@ msgstr "omaka algoritmer: klient %s; server %s"
#, c-format
msgid "the server does not support algorithm '%s'"
-msgstr "servern stöder inte algoritmen \"%s\""
+msgstr "servern stöder inte algoritmen â€%sâ€"
msgid "Server does not support shallow requests"
msgstr "Servern stöder inte grunda förfrågningar"
msgid "unable to write request to remote"
-msgstr "kunde inte skriva anrop till fjärren"
+msgstr "kan inte skriva anrop till fjärren"
#, c-format
msgid "expected '%s', received '%s'"
-msgstr "förväntade \"%s\", tog emot \"%s\""
+msgstr "förväntade â€%sâ€, tog emot â€%sâ€"
#, c-format
msgid "expected '%s'"
-msgstr "förväntade \"%s\""
+msgstr "förväntade â€%sâ€"
#, c-format
msgid "unexpected acknowledgment line: '%s'"
-msgstr "oväntad bekräftelserad: \"%s\""
+msgstr "oväntad bekräftelserad: â€%sâ€"
#, c-format
msgid "error processing acks: %d"
@@ -16089,19 +16449,18 @@ msgstr "fel vid hantering av bekräftelser: %d"
#.
#, c-format
msgid "expected packfile to be sent after '%s'"
-msgstr "väntade att paketfil skulle sändas efter \"%s\""
+msgstr "väntade att paketfil skulle sändas efter â€%sâ€"
#. TRANSLATORS: The parameter will be 'ready', a protocol
#. keyword.
#.
#, c-format
msgid "expected no other sections to be sent after no '%s'"
-msgstr ""
-"väntade inte att några ytterligare sektioner skulle sändas efter \"%s\""
+msgstr "väntade inte att nÃ¥gra ytterligare sektioner skulle sändas efter â€%sâ€"
#, c-format
msgid "error processing shallow info: %d"
-msgstr "fel vid hantering av grund (\"shallow\") info: %d"
+msgstr "fel vid hantering av grund (â€shallowâ€) info: %d"
#, c-format
msgid "expected wanted-ref, got '%s'"
@@ -16109,7 +16468,7 @@ msgstr "förväntade wanted-ref, fick %s"
#, c-format
msgid "unexpected wanted-ref: '%s'"
-msgstr "oväntad wanted-ref: \"%s\""
+msgstr "oväntad wanted-ref: â€%sâ€"
#, c-format
msgid "error processing wanted refs: %d"
@@ -16122,7 +16481,7 @@ msgid "no matching remote head"
msgstr "inget motsvarande fjärrhuvud"
msgid "unexpected 'ready' from remote"
-msgstr "oväntat \"ready\" från fjärr"
+msgstr "oväntat â€ready†frÃ¥n fjärr"
#, c-format
msgid "no such remote ref %s"
@@ -16134,58 +16493,63 @@ msgstr "Servern tillåter inte förfrågan om ej tillkännagivet objekt %s"
#, c-format
msgid "fsmonitor_ipc__send_query: invalid path '%s'"
-msgstr "fsmonitor_ipc__send_query: ogilitg sökväg \"%s\""
+msgstr "fsmonitor_ipc__send_query: ogilitg sökväg â€%sâ€"
#, c-format
msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
-msgstr "fsmonitor_ipc__send_query: ospecificerat fel på \"%s\""
+msgstr "fsmonitor_ipc__send_query: ospecificerat fel pÃ¥ â€%sâ€"
msgid "fsmonitor--daemon is not running"
msgstr "fsmonitor--daemon kör inte"
#, c-format
msgid "could not send '%s' command to fsmonitor--daemon"
-msgstr "kunde inte sända kommandot \"%s\" till fsmonitor--daemon"
+msgstr "kunde inte sända kommandot â€%s†till fsmonitor--daemon"
#, c-format
msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr "naket arkiv \"%s\" är inkompatibelt med fsmonitor"
+msgstr "naket arkiv â€%s†är inkompatibelt med fsmonitor"
#, c-format
msgid "repository '%s' is incompatible with fsmonitor due to errors"
-msgstr "arkivet \"%s\" är inkompatibelt med fsmonitor på grund av fel"
+msgstr "arkivet â€%s†är inkompatibelt med fsmonitor pÃ¥ grund av fel"
#, c-format
msgid "remote repository '%s' is incompatible with fsmonitor"
-msgstr "fjärrarkivet \"%s\" är inkompatibelt med fsmonitor"
+msgstr "fjärrarkivet â€%s†är inkompatibelt med fsmonitor"
#, c-format
msgid "virtual repository '%s' is incompatible with fsmonitor"
-msgstr "det virtuella arkivet \"%s\" är inkompatibelt med fsmonitor"
+msgstr "det virtuella arkivet â€%s†är inkompatibelt med fsmonitor"
#, c-format
msgid ""
"socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
"sockets support"
msgstr ""
-"uttagskatalogen \"%s\" är inkompatibelt med fsmonitor på grund av avsaknad "
-"av Unix-uttag"
+"uttagskatalogen â€%s†är inkompatibelt med fsmonitor pÃ¥ grund av avsaknad av "
+"Unix-uttag"
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
msgstr ""
"git [-v | --version] [-h |--help] [-C <sökväg>] [-c <namn>=<värde>]\n"
" [--exec-path[=<sökväg>]] [--html-path] [--man-path] [--info-"
"path]\n"
-" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-" [--git-dir=<sökväg>] [--work-tree=<sökväg>] [--namespace=<namn>]\n"
-" [--config-env=<namn>=<miljövar>] <kommando> [<flaggor>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-"
+"dir=<sökväg>]\n"
+" [--work-tree=<sökväg>] [--namespace=<namn>] [--config-"
+"env=<namn>=<miljövar>]\n"
+" <kommando> [<flaggor>]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16193,18 +16557,18 @@ msgid ""
"to read about a specific subcommand or concept.\n"
"See 'git help git' for an overview of the system."
msgstr ""
-"\"git help -a\" och \"git help -g\" visar tillgängliga underkommandon och\n"
-"några konceptvägledningar. Se \"git help <kommando>\" eller \"git help\n"
-"<koncept>\" för att läsa mer om specifika underkommandon och koncept.\n"
-"See \"git help git\" för en översikt över systemet."
+"â€git help -a†och â€git help -g†visar tillgängliga underkommandon och\n"
+"nÃ¥gra konceptvägledningar. Se â€git help <kommando>†eller â€git help\n"
+"<koncept>†för att läsa mer om specifika underkommandon och koncept.\n"
+"See â€git help git†för en översikt över systemet."
#, c-format
msgid "unsupported command listing type '%s'"
-msgstr "okänd kommandolisttyp \"%s\""
+msgstr "okänd kommandolisttyp â€%sâ€"
#, c-format
msgid "no directory given for '%s' option\n"
-msgstr "ingen katalog angavs för flaggan \"%s\"\n"
+msgstr "ingen katalog angavs för flaggan â€%sâ€\n"
#, c-format
msgid "no namespace given for --namespace\n"
@@ -16228,15 +16592,15 @@ msgstr "okänd flagga: %s\n"
#, c-format
msgid "while expanding alias '%s': '%s'"
-msgstr "vid expandering av aliaset \"%s\": \"%s\""
+msgstr "vid expandering av aliaset â€%sâ€: â€%sâ€"
#, c-format
msgid ""
"alias '%s' changes environment variables.\n"
"You can use '!git' in the alias to do this"
msgstr ""
-"aliaset \"%s\" ändrar miljövariabler.\n"
-"Du kan använda \"!git\" i aliaset för att göra det"
+"aliaset â€%s†ändrar miljövariabler.\n"
+"Du kan använda â€!git†i aliaset för att göra det"
#, c-format
msgid "empty alias for %s"
@@ -16257,7 +16621,7 @@ msgstr "stäng misslyckades på standard ut"
#, c-format
msgid "alias loop detected: expansion of '%s' does not terminate:%s"
-msgstr "alias-slinga detekterades: expansionen av \"%s\" avslutas aldrig:%s"
+msgstr "alias-slinga detekterades: expansionen av â€%s†avslutas aldrig:%s"
#, c-format
msgid "cannot handle %s as a builtin"
@@ -16274,18 +16638,18 @@ msgstr ""
#, c-format
msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
msgstr ""
-"expandering av alias \"%s\" misslyckades; \"%s\" är inte ett git-kommando\n"
+"expandering av alias â€%s†misslyckades; â€%s†är inte ett git-kommando\n"
#, c-format
msgid "failed to run command '%s': %s\n"
-msgstr "misslyckades köra kommandot \"%s\": %s\n"
+msgstr "misslyckades köra kommandot â€%sâ€: %s\n"
msgid "could not create temporary file"
msgstr "kunde inte skapa temporära fil"
#, c-format
msgid "failed writing detached signature to '%s'"
-msgstr "misslyckades skriva fristående signatur till \"%s\""
+msgstr "misslyckades skriva fristÃ¥ende signatur till â€%sâ€"
msgid ""
"gpg.ssh.allowedSignersFile needs to be configured and exist for ssh "
@@ -16298,7 +16662,7 @@ 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\" behövs för att bekräfta ssh-"
+"â€ssh-keygen -Y find-principals/verify†behövs för att bekräfta ssh-"
"signaturer (tillgängligt i openssh version 8.2p1+)"
#, c-format
@@ -16307,11 +16671,11 @@ msgstr "återkallningsfilen för ssh-signering inställd men saknas: %s"
#, c-format
msgid "bad/incompatible signature '%s'"
-msgstr "felaktig/inkompatibel signatur \"%s\""
+msgstr "felaktig/inkompatibel signatur â€%sâ€"
#, c-format
msgid "failed to get the ssh fingerprint for key '%s'"
-msgstr "misslyckades hämta ssh-fingeravtrycket för nyckeln \"%s\""
+msgstr "misslyckades hämta ssh-fingeravtrycket för nyckeln â€%sâ€"
msgid ""
"either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"
@@ -16339,26 +16703,26 @@ msgstr "user.signingKey måste anges för ssh-signering"
#, c-format
msgid "failed writing ssh signing key to '%s'"
-msgstr "misslyckades skriva ssh-signeringsnyckel till \"%s\""
+msgstr "misslyckades skriva ssh-signeringsnyckel till â€%sâ€"
#, c-format
msgid "failed writing ssh signing key buffer to '%s'"
-msgstr "misslyckades skriva ssh-signeringsnyckelbuffert till \"%s\""
+msgstr "misslyckades skriva ssh-signeringsnyckelbuffert till â€%sâ€"
msgid ""
"ssh-keygen -Y sign is needed for ssh signing (available in openssh version "
"8.2p1+)"
msgstr ""
-"\"ssh-keygen -Y sign\" behövs för ssh-signering (tillgängligt i openssh "
+"â€ssh-keygen -Y sign†behövs för ssh-signering (tillgängligt i openssh "
"version 8.2p1+)"
#, c-format
msgid "failed reading ssh signing data buffer from '%s'"
-msgstr "misslyckades läsa ssh-signeringsdatabuffert från \"%s\""
+msgstr "misslyckades läsa ssh-signeringsdatabuffert frÃ¥n â€%sâ€"
#, c-format
msgid "ignored invalid color '%.*s' in log.graphColors"
-msgstr "ignorerade felaktig färg \"%.*s\" i log.graphColors"
+msgstr "ignorerade felaktig färg â€%.*s†i log.graphColors"
msgid ""
"given pattern contains NULL byte (via -f <file>). This is only supported "
@@ -16369,11 +16733,11 @@ msgstr ""
#, c-format
msgid "'%s': unable to read %s"
-msgstr "\"%s\" kunde inte läsa %s"
+msgstr "â€%sâ€: kan inte läsa %s"
#, c-format
msgid "'%s': short read"
-msgstr "\"%s\": kort läsning"
+msgstr "â€%sâ€: kort läsning"
msgid "start a working area (see also: git help tutorial)"
msgstr "starta arbetskatalog (se också: git help tutorial)"
@@ -16422,7 +16786,7 @@ msgstr "Filformat, protokoll och andra gränssnitt tänkta för utvecklare"
#, c-format
msgid "available git commands in '%s'"
-msgstr "git-kommandon tillgängliga i \"%s\""
+msgstr "git-kommandon tillgängliga i â€%sâ€"
msgid "git commands available from elsewhere on your $PATH"
msgstr "git-kommandon från andra platser i din $PATH"
@@ -16446,39 +16810,39 @@ msgid "Command aliases"
msgstr "Kommadoalias"
msgid "See 'git help <command>' to read about a specific subcommand"
-msgstr "Se \"git help <kommando>\" för att läsa om ett specifikt underkommando"
+msgstr "Se â€git help <kommando>†för att läsa om ett specifikt underkommando"
#, 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\" verkar vara ett git-kommando, men vi kan inte\n"
+"â€%s†verkar vara ett git-kommando, men vi kan inte\n"
"köra det. Kanske git-%s är trasigt?"
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: \"%s\" är inte ett git-kommando. Se \"git --help\"."
+msgstr "git: â€%s†är inte ett git-kommando. Se â€git --helpâ€."
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Oj då. Ditt system rapporterar inga Git-kommandon alls."
#, c-format
msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr "VARNING: Du anropade ett Git-kommando vid namn \"%s\", som inte finns."
+msgstr "VARNING: Du anropade ett Git-kommando vid namn â€%sâ€, som inte finns."
#, c-format
msgid "Continuing under the assumption that you meant '%s'."
-msgstr "Fortsätter under förutsättningen att du menade \"%s\"."
+msgstr "Fortsätter under förutsättningen att du menade â€%sâ€."
#, c-format
msgid "Run '%s' instead [y/N]? "
-msgstr "Köra \"%s\" istället (j/N)?"
+msgstr "Köra â€%s†istället (j/N)?"
#, c-format
msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
msgstr ""
-"Fortsätter om %0.1f sekunder, under förutsättningen att du menade \"%s\"."
+"Fortsätter om %0.1f sekunder, under förutsättningen att du menade â€%sâ€."
msgid ""
"\n"
@@ -16518,17 +16882,17 @@ 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 ""
-"Kroken \"%s\" ignorerades eftersom den inte är markerad som körbar.\n"
-"Du kan inaktivera varningen med \"git config advice.ignoredHook false\"."
+"Kroken â€%s†ignorerades eftersom den inte är markerad som körbar.\n"
+"Du kan inaktivera varningen med â€git config advice.ignoredHook falseâ€."
+
+msgid "not a git repository"
+msgstr "inte ett git-arkiv"
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr ""
"argumentet till --packfile måste vara ett giltigt hashvärde (fick '%s')"
-msgid "not a git repository"
-msgstr "inte ett git-arkiv"
-
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
msgstr "http.postBuffer har negativt värde; använder förvalet %d"
@@ -16539,20 +16903,29 @@ msgstr "Delegerad styrning stöds inte av cURL < 7.22.0"
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "Fastnålning av öppen nyckel stöds inte av cURL < 7.39.0"
+msgid "Unknown value for http.proactiveauth"
+msgstr "Okänt värde för http.proactiveauth"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE stöds inte av cURL < 7.44.0"
#, c-format
msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
-msgstr "SSL-bakändan \"%s\" stöds inte. Dessa SSL-bakändor stöds:"
+msgstr "SSL-bakändan â€%s†stöds inte. Dessa SSL-bakändor stöds:"
#, c-format
msgid "Could not set SSL backend to '%s': cURL was built without SSL backends"
-msgstr "Kan inte sätta SSL-bakända till \"%s\": cURL byggdes utan SSL-bakändor"
+msgstr "Kan inte sätta SSL-bakända till â€%sâ€: cURL byggdes utan SSL-bakändor"
#, c-format
msgid "Could not set SSL backend to '%s': already set"
-msgstr "Kunde inte sätta SSL-bakända till \"%s\": redan valt"
+msgstr "Kunde inte sätta SSL-bakända till â€%sâ€: redan valt"
+
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "vägrar läsa kakor frÃ¥n filen â€-†angiven i http.cookiefile"
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "ignorerar http.savecookies för tom http.cookiefile"
#, c-format
msgid ""
@@ -16600,14 +16973,14 @@ msgstr "ingen e-post angavs och autodetektering är inaktiverad"
#, c-format
msgid "unable to auto-detect email address (got '%s')"
-msgstr "kunde inte autodetektera e-postadress (fick \"%s\")"
+msgstr "kan inte autodetektera e-postadress (fick â€%sâ€)"
msgid "no name was given and auto-detection is disabled"
msgstr "inget namn angavs och autodetektering är inaktiverad"
#, c-format
msgid "unable to auto-detect name (got '%s')"
-msgstr "kunde inte autodetektera namn (fick \"%s\")"
+msgstr "kan inte autodetektera namn (fick â€%sâ€)"
#, c-format
msgid "empty ident name (for <%s>) not allowed"
@@ -16618,22 +16991,22 @@ msgid "name consists only of disallowed characters: %s"
msgstr "namnet består enbart av ej tillåtna tecken: %s"
msgid "expected 'tree:<depth>'"
-msgstr "förväntade \"tree:<djup>\""
+msgstr "förväntade â€tree:<djup>â€"
msgid "sparse:path filters support has been dropped"
msgstr "sparse:sökväg-filter stöds inte längre"
#, c-format
msgid "'%s' for 'object:type=<type>' is not a valid object type"
-msgstr "\"%s\" för \"object:type=<typ>\" är inte en giltig objekttyp"
+msgstr "â€%s†för â€object:type=<typ>†är inte en giltig objekttyp"
#, c-format
msgid "invalid filter-spec '%s'"
-msgstr "felaktig filterspecifikation: \"%s\""
+msgstr "felaktig filterspecifikation: â€%sâ€"
#, c-format
msgid "must escape char in sub-filter-spec: '%c'"
-msgstr "måste använda specialsekvens i delfilter-spec: \"%c\""
+msgstr "mÃ¥ste använda specialsekvens i delfilter-spec: â€%câ€"
msgid "expected something after combine:"
msgstr "förväntade någonting efter combine:"
@@ -16642,7 +17015,7 @@ msgid "multiple filter-specs cannot be combined"
msgstr "flera filterspecifikationer kan inte kombineras"
msgid "unable to upgrade repository format to support partial clone"
-msgstr "kunde inte uppgradera arkivformat till att stöda delvis klon"
+msgstr "kan inte uppgradera arkivformat till att stöda delvis klon"
msgid "args"
msgstr "argument"
@@ -16652,23 +17025,23 @@ msgstr "objektfiltrering"
#, c-format
msgid "unable to access sparse blob in '%s'"
-msgstr "kunde inte nå gles blob på \"%s\""
+msgstr "kan inte nÃ¥ gles blob pÃ¥ â€%sâ€"
#, c-format
msgid "unable to parse sparse filter data in %s"
-msgstr "kunde inte tolka gles filterdata i %s"
+msgstr "kan inte tolka gles filterdata i %s"
#, c-format
msgid "entry '%s' in tree %s has tree mode, but is not a tree"
-msgstr "posten \"%s\" i trädet %s har träd-läge, men är inte ett träd"
+msgstr "posten â€%s†i trädet %s har träd-läge, men är inte ett träd"
#, c-format
msgid "entry '%s' in tree %s has blob mode, but is not a blob"
-msgstr "posten \"%s\" i trädet %s har blob-läge, men är inte en blob"
+msgstr "posten â€%s†i trädet %s har blob-läge, men är inte en blob"
#, c-format
msgid "unable to load root tree for commit %s"
-msgstr "kunde inte läsa in rot-trädet för incheckningen %s"
+msgstr "kan inte läsa in rot-trädet för incheckningen %s"
#, c-format
msgid ""
@@ -16680,10 +17053,10 @@ msgid ""
"may have crashed in this repository earlier:\n"
"remove the file manually to continue."
msgstr ""
-"Kunde inte skapa \"%s.lock\": %s.\n"
+"Kunde inte skapa â€%s.lockâ€: %s.\n"
"\n"
"Det verkar som en annan git-process kör i det här arkivet, t.ex.\n"
-"ett textredigeringsprogram startat av \"git commit\". Se till att\n"
+"ett textredigeringsprogram startat av â€git commitâ€. Se till att\n"
"alla processer avslutats och försök sedan igen. Om det fortfarande\n"
"misslyckas kanske en git-process har kraschat i det här arkivet\n"
"tidigare:\n"
@@ -16691,19 +17064,34 @@ msgstr ""
#, c-format
msgid "Unable to create '%s.lock': %s"
-msgstr "Kunde inte skapa \"%s.lock\": %s"
+msgstr "Kunde inte skapa â€%s.lockâ€: %s"
+
+msgid "unable to create temporary object directory"
+msgstr "kan inte skapa temporär objektkatalog"
+
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "kunde inte skriva löst objektindex %s"
+
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "misslyckades skriva löst objektindex %s"
#, c-format
msgid "unexpected line: '%s'"
-msgstr "oväntad rad: \"%s\""
+msgstr "oväntad rad: â€%sâ€"
msgid "expected flush after ls-refs arguments"
-msgstr "förväntade \"flush\" efter ls-refs-argument"
+msgstr "förväntade â€flush†efter ls-refs-argument"
msgid "quoted CRLF detected"
msgstr "citerad CRLF upptäcktes"
#, c-format
+msgid "unable to format message: %s"
+msgstr "kan inte formatera meddelandet: %s"
+
+#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "Misslyckades slå ihop undermodulen %s (ej utcheckad)"
@@ -16716,6 +17104,10 @@ msgid "Failed to merge submodule %s (commits not present)"
msgstr "Misslyckades slå ihop undermodulen %s (incheckningar saknas)"
#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "fel: misslyckades slå ihop undermodulen %s (arkivet är trasigt)"
+
+#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr ""
"Misslyckades slå ihop undermodulen %s (incheckningar följer inte "
@@ -16743,12 +17135,13 @@ msgstr ""
"finns:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "Misslyckades exekvera intern sammanslagning"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "fel: misslyckades exekvera intern sammanslagning för %s"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "Kunde inte lägga till %s till databasen"
+msgid "error: unable to add %s to database"
+msgstr "fel: kan inte lägga till %s till databasen"
#, c-format
msgid "Auto-merging %s"
@@ -16785,7 +17178,7 @@ msgid ""
"WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
"renamed."
msgstr ""
-"VARNING: Undviker att applicera namnändring %s -> %s på %s, då %s själv har "
+"VARNING: Undviker att applicera namnändring %s → %s på %s, då %s själv har "
"bytt namn."
#, c-format
@@ -16831,7 +17224,7 @@ msgid ""
"conflicts AND collides with another path; this may result in nested conflict "
"markers."
msgstr ""
-"KONFLIKT (namnbyte involverad i krock): namnbyte av %s -> %s har "
+"KONFLIKT (namnbyte involverad i krock): namnbyte av %s → %s har "
"innehållskonflikter OCH krockar med en annan sökväg; detta kan leda till "
"nästlade konfliktmarkörer."
@@ -16841,12 +17234,12 @@ msgstr ""
"KONFLIKT (namnbyte/radera): %s namnbytt till %s i %s, men borttagen i %s."
#, c-format
-msgid "cannot read object %s"
-msgstr "kan inte läsa objektet %s"
+msgid "error: cannot read object %s"
+msgstr "fel: kan inte läsa objektet %s"
#, c-format
-msgid "object %s is not a blob"
-msgstr "objektet %s är inte en blob"
+msgid "error: object %s is not a blob"
+msgstr "fel: objektet %s är inte en blob"
#, c-format
msgid ""
@@ -16946,17 +17339,17 @@ msgstr "(felaktig incheckning)\n"
#, c-format
msgid "add_cacheinfo failed for path '%s'; merge aborting."
msgstr ""
-"add_cacheinfo misslyckades för sökvägen \"%s\"; avslutar sammanslagningen."
+"add_cacheinfo misslyckades för sökvägen â€%sâ€; avslutar sammanslagningen."
#, c-format
msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
msgstr ""
-"add_cacheinfo misslyckades uppdatera för sökvägen \"%s\"; avslutar "
+"add_cacheinfo misslyckades uppdatera för sökvägen â€%sâ€; avslutar "
"sammanslagningen."
#, c-format
msgid "failed to create path '%s'%s"
-msgstr "misslyckades skapa sökvägen \"%s\"%s"
+msgstr "misslyckades skapa sökvägen â€%sâ€%s"
#, c-format
msgid "Removing %s to make room for subdirectory\n"
@@ -16967,23 +17360,27 @@ msgstr ": kanske en K/F-konflikt?"
#, c-format
msgid "refusing to lose untracked file at '%s'"
-msgstr "vägrar förlora ospårad fil vid \"%s\""
+msgstr "vägrar förlora ospÃ¥rad fil vid â€%sâ€"
#, c-format
msgid "blob expected for %s '%s'"
-msgstr "blob förväntades för %s \"%s\""
+msgstr "blob förväntades för %s â€%sâ€"
#, c-format
msgid "failed to open '%s': %s"
-msgstr "misslyckades öppna \"%s\": %s"
+msgstr "misslyckades öppna â€%sâ€: %s"
#, c-format
msgid "failed to symlink '%s': %s"
-msgstr "misslyckades skapa symboliska länken \"%s\": %s"
+msgstr "misslyckades skapa symboliska länken â€%sâ€: %s"
#, c-format
msgid "do not know what to do with %06o %s '%s'"
-msgstr "vet inte hur %06o %s \"%s\" ska hanteras"
+msgstr "vet inte hur %06o %s â€%s†ska hanteras"
+
+#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "Misslyckades slå ihop undermodulen %s (arkivet är trasigt)"
#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
@@ -17027,6 +17424,13 @@ msgid "Failed to merge submodule %s (multiple merges found)"
msgstr ""
"Misslyckades slå ihop undermodulen %s (flera sammanslagningar hittades)"
+msgid "failed to execute internal merge"
+msgstr "misslyckades exekvera intern sammanslagning"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "kan inte lägga till %s till databasen"
+
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr "Fel: Vägrar förlora ospårad fil vid %s; skriver till %s istället."
@@ -17071,7 +17475,7 @@ msgstr "namnbytt"
#, c-format
msgid "Refusing to lose dirty file at %s"
-msgstr "Vägrar förlora lortig fil vid \"%s\""
+msgstr "Vägrar förlora lortig fil vid â€%sâ€"
#, c-format
msgid "Refusing to lose untracked file at %s, even though it's in the way."
@@ -17079,7 +17483,7 @@ msgstr "Vägrar förlora ospårad fil vid %s, trots att den är i vägen."
#, c-format
msgid "CONFLICT (rename/add): Rename %s->%s in %s. Added %s in %s"
-msgstr "KONFLIKT (namnbyte/tillägg): Namnbyte %s->%s i %s. Lade till %s i %s"
+msgstr "KONFLIKT (namnbyte/tillägg): Namnbyte %s→%s i %s. Lade till %s i %s"
#, c-format
msgid "%s is a directory in %s adding as %s instead"
@@ -17091,19 +17495,18 @@ msgstr "Vägrar förlora ospårad fil vid %s; lägger till som %s istället"
#, c-format
msgid ""
-"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
-"\"->\"%s\" in \"%s\"%s"
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename "
+"\"%s\"->\"%s\" in \"%s\"%s"
msgstr ""
-"KONFLIKT (namnbyte/namnbyte): Namnbyte \"%s\"->\"%s\" på grenen \"%s\" "
-"namnbyte \"%s\"->\"%s\" i \"%s\"%s"
+"KONFLIKT (namnbyte/namnbyte): Namnbyte â€%sâ€â†’â€%s†pÃ¥ grenen â€%s†namnbyte "
+"â€%sâ€â†’â€%s†i â€%sâ€%s"
msgid " (left unresolved)"
msgstr " (lämnad olöst)"
#, c-format
msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
-msgstr ""
-"KONFLIKT (namnbyte/namnbyte): Namnbyte %s->%s i %s. Namnbyte %s->%s i %s"
+msgstr "KONFLIKT (namnbyte/namnbyte): Namnbyte %s→%s i %s. Namnbyte %s→%s i %s"
#, c-format
msgid ""
@@ -17120,8 +17523,16 @@ msgid ""
"CONFLICT (rename/rename): Rename directory %s->%s in %s. Rename directory %s-"
">%s in %s"
msgstr ""
-"KONFLIKT (namnbyte/namnbyte): Namnbytt katalog %s->%s i %s. Namnbytt katalog "
-"%s->%s i %s"
+"KONFLIKT (namnbyte/namnbyte): Namnbytt katalog %s→%s i %s. Namnbytt katalog "
+"%s→%s i %s"
+
+#, c-format
+msgid "cannot read object %s"
+msgstr "kan inte läsa objektet %s"
+
+#, c-format
+msgid "object %s is not a blob"
+msgstr "objektet %s är inte en blob"
msgid "modify"
msgstr "ändra"
@@ -17178,60 +17589,18 @@ msgstr "sammanslagningen returnerade ingen incheckning"
#, c-format
msgid "Could not parse object '%s'"
-msgstr "Kunde inte tolka objektet \"%s\""
+msgstr "Kunde inte tolka objektet â€%sâ€"
msgid "failed to read the cache"
msgstr "misslyckades läsa cachen"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "multi-pack-indexets OID-utbredning har fel storlek"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "multi-pack-indexfilen %s är för liten"
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr "multi-pack-indexsignaturen 0x%08x stämmer inte med signaturen 0x%08x"
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "multi-pack-indexversionen %d stöds inte"
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "multi-pack-index-hashversionen %u stämmer inte med versionen %u"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "multi-pack-index saknar krävd paketnamn-stycke"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "multi-pack-index saknar krävt OID-utbredningsstycke"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "multi-pack-index saknar krävt OID-uppslagnignsstycke"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "multi-pack-index saknar krävt objekt-offsetstycke"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "multi-pack-index-paketnamn i fel ordning: \"%s\" före \"%s\""
-
-#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "bad pack-int-id: %u (%u paket totalt)"
-
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr "multi-pack-index skriver 64-bitars offset, men off_t är för liten"
-
#, c-format
msgid "failed to add packfile '%s'"
-msgstr "misslyckades läsa paketfilen \"%s\""
+msgstr "misslyckades läsa paketfilen â€%sâ€"
#, c-format
msgid "failed to open pack-index '%s'"
-msgstr "misslyckades öppna paketindexet \"%s\""
+msgstr "misslyckades öppna paketindexet â€%sâ€"
#, c-format
msgid "failed to locate object %d in packfile"
@@ -17248,9 +17617,6 @@ msgstr "kunde inte tolka rad: %s"
msgid "malformed line: %s"
msgstr "felaktig rad: %s"
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "ignorerar befintlig multi-pack-index; felaktig kontrollsumma"
-
msgid "could not load pack"
msgstr "kunde inte läsa paket{"
@@ -17258,6 +17624,20 @@ msgstr "kunde inte läsa paket{"
msgid "could not open index for %s"
msgstr "kunde inte öppna indexet för %s"
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "kan inte länka â€%s†till â€%sâ€"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "misslyckades städa multi-pack-index på %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "kan inte skriva inkrementell MIDX med bitkarta"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr "ignorerar befintlig multi-pack-index; felaktig kontrollsumma"
+
msgid "Adding packfiles to multi-pack-index"
msgstr "Lägger till paketfiler till multi-pack-index"
@@ -17275,7 +17655,7 @@ msgstr "såg inte paketfilen %s som skulle kastas"
#, c-format
msgid "preferred pack '%s' is expired"
-msgstr "föredraget paket \"%s\" har löpt ut"
+msgstr "föredraget paket â€%s†har löpt ut"
msgid "no pack files to index."
msgstr "inga paketfiler att indexera."
@@ -17283,15 +17663,131 @@ msgstr "inga paketfiler att indexera."
msgid "refusing to write multi-pack .bitmap without any objects"
msgstr "kunde inte skriva fler-paketsbitkarta utan några objekt"
+msgid "unable to create temporary MIDX layer"
+msgstr "kan inte skapa temporärt MIDX-lager"
+
msgid "could not write multi-pack bitmap"
msgstr "kunde inte skriva fler-paketsbitkarta"
+msgid "unable to open multi-pack-index chain file"
+msgstr "kan inte öppna kedjefil för multi-pack-index"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "kan inte byta namn på nytt multi-pack-index-lager"
+
msgid "could not write multi-pack-index"
msgstr "kunde inte skriva flerpakets-index"
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "kan inte låta tid gå ut för paket från inkrementellt multi-pack-index"
+
+msgid "Counting referenced objects"
+msgstr "Räknar refererade objekt"
+
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Ser efter och tar bort orefererade packfiler"
+
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "kunde packa om ett inkrementellt multi-pack-index"
+
+msgid "could not start pack-objects"
+msgstr "kunde inte starta pack-objects"
+
+msgid "could not finish pack-objects"
+msgstr "kunde inte avsluta pack-objects"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "OID-utbredning för multi-pack-index har fel storlek"
+
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "misslyckades städa multi-pack-index på %s"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr ""
+"oid-utbredning i fel ordning: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "OID-uppslagningsstycket för multi-pack-index har fel storlek"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "objekt-offset-stycket för multi-pack-index har fel storlek"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "multi-pack-indexfilen %s är för liten"
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "multi-pack-indexsignaturen 0x%08x stämmer inte med signaturen 0x%08x"
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "multi-pack-indexversionen %d stöds inte"
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "multi-pack-index-hashversionen %u stämmer inte med versionen %u"
+
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr ""
+"nödvändigt paketnamn-stycke för multi-pack-index saknas eller är trasigt"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"nödvändigt OID-utbredningsstycke för multi-pack-index saknas eller är trasigt"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr ""
+"nödvändigt OID-uppslagningsstycke för multi-pack-index saknas eller är "
+"trasigt"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"nödvändigt objekt-offsetstycke för multi-pack-index saknas eller är trasigt"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "paketnamnstycke för multi-pack-index är för kort"
+
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "paketnamn för multi-pack-index i fel ordning: â€%s†före â€%sâ€"
+
+msgid "multi-pack-index chain file too small"
+msgstr "kedjefilen för multi-pack-index är för liten"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "antalet paket i bas-MIDX för högt: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "antalet object i bas-MIDX för högt: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "ogiltig kedja för multi-pack-index: raden â€%s†är inte ett hash-värde"
+
+msgid "unable to find all multi-pack index files"
+msgstr "kan inte hitta alla indexfiler för multi-pack"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "ogiltig MIDX-objektposition, MIDX är troligtvis trasig"
+
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "bad pack-int-id: %u (%u paket totalt)"
+
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX innehåller inte BTMP-stycket"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "kunde inte läsa det bitmappade paketet %<PRIu32>"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr "multi-pack-index innehåller 64-bitars offset, men off_t är för liten"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr "stort offset för mult-pack-index utanför gränsen"
msgid "multi-pack-index file exists, but failed to parse"
msgstr "multi-pack-indexfilen finns, men kunde inte tolkas"
@@ -17302,12 +17798,6 @@ msgstr "felaktig kontrollsumma"
msgid "Looking for referenced packfiles"
msgstr "Ser efter refererade packfiler"
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr ""
-"oid-utbredning i fel ordning: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-
msgid "the midx contains no oid"
msgstr "midx saknar oid"
@@ -17336,29 +17826,17 @@ msgstr "misslyckades läsa paketindex för paketfil %s"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "felaktigt objekt-offset för oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-msgid "Counting referenced objects"
-msgstr "Räknar refererade objekt"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "Ser efter och tar bort orefererade packfiler"
-
-msgid "could not start pack-objects"
-msgstr "kunde inte starta pack-objects"
-
-msgid "could not finish pack-objects"
-msgstr "kunde inte avsluta pack-objects"
-
#, c-format
msgid "unable to create lazy_dir thread: %s"
-msgstr "misslyckades skapa lazy_dir-tråd: %s"
+msgstr "kan inte skapa lazy_dir-tråd: %s"
#, c-format
msgid "unable to create lazy_name thread: %s"
-msgstr "misslyckades skapa lazy_name-tråd: %s"
+msgstr "kan inte skapa lazy_name-tråd: %s"
#, c-format
msgid "unable to join lazy_name thread: %s"
-msgstr "misslyckades utföra join på lazy_name-tråd: %s"
+msgstr "kan inte utföra join på lazy_name-tråd: %s"
#, c-format
msgid ""
@@ -17367,9 +17845,9 @@ msgid ""
"commit/abort the previous merge before you start a new notes merge."
msgstr ""
"Du har inte avslutat föregående antecknings-sammanslagning (%s finns).\n"
-"Använd \"git notes merge --commit\" eller \"git notes merge --abort\" för "
-"att checka in eller avbryta föregående sammanslagning innan du påbörjar en "
-"ny antecknings-sammanslagning."
+"Använd â€git notes merge --commit†eller â€git notes merge --abort†för att "
+"checka in eller avbryta föregående sammanslagning innan du påbörjar en ny "
+"antecknings-sammanslagning."
#, c-format
msgid "You have not concluded your notes merge (%s exists)."
@@ -17392,7 +17870,26 @@ msgstr "Vägrar skriva över anteckningar i %s (utanför refs/notes/)"
#.
#, c-format
msgid "Bad %s value: '%s'"
-msgstr "Felaktigt värde på %s: \"%s\""
+msgstr "Felaktigt värde pÃ¥ %s: â€%sâ€"
+
+msgid "failed to decode tree entry"
+msgstr "misslyckades avkoda trädposten"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "misslyckades koppla trädpost för %s"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "felaktig %s i incheckning"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "kan inte koppla %s %s i incheckningsobjekt"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Misslyckades konvertera objekt från %s till %s"
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
@@ -17400,40 +17897,40 @@ msgstr "objektkatalogen %s finns inte; se .git/objects/info/alternates"
#, c-format
msgid "unable to normalize alternate object path: %s"
-msgstr "kunde inte normalisera supplerande objektsökväg: %s"
+msgstr "kan inte normalisera supplerande objektsökväg: %s"
#, c-format
msgid "%s: ignoring alternate object stores, nesting too deep"
msgstr "%s: ignorerar supplerande objektlager, för djup nästling"
msgid "unable to fdopen alternates lockfile"
-msgstr "kan inte utföra \"fdopen\" på suppleantlåsfil"
+msgstr "kan inte utföra â€fdopen†pÃ¥ suppleantlÃ¥sfil"
msgid "unable to read alternates file"
-msgstr "kan inte läsa \"alternates\"-filen"
+msgstr "kan inte läsa â€alternatesâ€-filen"
msgid "unable to move new alternates file into place"
-msgstr "kan inte flytta ny \"alternates\"-fil på plats"
+msgstr "kan inte flytta ny â€alternatesâ€-fil pÃ¥ plats"
#, c-format
msgid "path '%s' does not exist"
-msgstr "sökvägen \"%s\" finns inte"
+msgstr "sökvägen â€%s†finns inte"
#, c-format
msgid "reference repository '%s' as a linked checkout is not supported yet."
-msgstr "referensarkivet \"%s\" som en länkad utcheckning stöds inte ännu."
+msgstr "referensarkivet â€%s†som en länkad utcheckning stöds inte ännu."
#, c-format
msgid "reference repository '%s' is not a local repository."
-msgstr "referensarkivet \"%s\" är inte ett lokalt arkiv."
+msgstr "referensarkivet â€%s†är inte ett lokalt arkiv."
#, c-format
msgid "reference repository '%s' is shallow"
-msgstr "referensarkivet \"%s\" är grunt"
+msgstr "referensarkivet â€%s†är grunt"
#, c-format
msgid "reference repository '%s' is grafted"
-msgstr "referensarkivet \"%s\" är ympat"
+msgstr "referensarkivet â€%s†är ympat"
#, c-format
msgid "could not find object directory matching %s"
@@ -17445,7 +17942,7 @@ msgstr "felaktig rad vid tolkning av supplerande referenser: %s"
#, c-format
msgid "attempting to mmap %<PRIuMAX> over limit %<PRIuMAX>"
-msgstr "försök att utföra \"mmap\" på %<PRIuMAX> över gränsen %<PRIuMAX>"
+msgstr "försök att utföra â€mmap†pÃ¥ %<PRIuMAX> över gränsen %<PRIuMAX>"
#, c-format
msgid "mmap failed%s"
@@ -17457,11 +17954,11 @@ msgstr "objektfilen %s är tom"
#, c-format
msgid "corrupt loose object '%s'"
-msgstr "trasigt löst objekt \"%s\""
+msgstr "trasigt löst objekt â€%sâ€"
#, c-format
msgid "garbage at end of loose object '%s'"
-msgstr "skräp i slutet av löst objekt \"%s\""
+msgstr "skräp i slutet av löst objekt â€%sâ€"
#, c-format
msgid "unable to open loose object %s"
@@ -17495,12 +17992,16 @@ msgid "packed object %s (stored in %s) is corrupt"
msgstr "packat objekt %s (lagrat i %s) är trasigt"
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "saknar koppling av %s till %s"
+
+#, c-format
msgid "unable to write file %s"
-msgstr "kunde inte skriva filen %s"
+msgstr "kan inte skriva filen %s"
#, c-format
msgid "unable to set permission to '%s'"
-msgstr "kan inte sätta behörigheten till \"%s\""
+msgstr "kan inte sätta behörigheten till â€%sâ€"
msgid "error when closing loose object file"
msgstr "fel vid stängning av fil för löst objekt"
@@ -17514,15 +18015,15 @@ msgid "unable to create temporary file"
msgstr "kan inte skapa temporär fil"
msgid "unable to write loose object file"
-msgstr "kunde inte skriva fil för löst objekt"
+msgstr "kan inte skriva fil för löst objekt"
#, c-format
msgid "unable to deflate new object %s (%d)"
-msgstr "kan inte utföra \"deflate\" på nytt objekt %s (%d)"
+msgstr "kan inte utföra â€deflate†pÃ¥ nytt objekt %s (%d)"
#, c-format
msgid "deflateEnd on object %s failed (%d)"
-msgstr "\"deflateend\" på objektet %s misslyckades (%d)"
+msgstr "â€deflateEnd†pÃ¥ objektet %s misslyckades (%d)"
#, c-format
msgid "confused by unstable object source data for %s"
@@ -17534,21 +18035,25 @@ msgstr "skriv strömobjektet %ld != %<PRIuMAX>"
#, c-format
msgid "unable to stream deflate new object (%d)"
-msgstr "kan inte utföra \"deflate\" på nytt strömobjekt (%d)"
+msgstr "kan inte utföra â€deflate†pÃ¥ nytt strömobjekt (%d)"
#, c-format
msgid "deflateEnd on stream object failed (%d)"
-msgstr "\"deflateend\" på strömobjektet misslyckades (%d)"
+msgstr "â€deflatEend†pÃ¥ strömobjektet misslyckades (%d)"
#, c-format
msgid "unable to create directory %s"
-msgstr "kunde inte skapa katalogen %s"
+msgstr "kan inte skapa katalogen %s"
#, c-format
msgid "cannot read object for %s"
msgstr "kan inte läsa objekt för %s"
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "kan inte koppla objektet %s till %s"
+
+#, c-format
msgid "object fails fsck: %s"
msgstr "objekt klarar inte fsck: %s"
@@ -17573,7 +18078,7 @@ msgstr "%s: filtypen stöds ej"
#, c-format
msgid "%s is not a valid '%s' object"
-msgstr "%s är inte ett giltigt \"%s\"-objekt"
+msgstr "%s är inte ett giltigt â€%sâ€-objekt"
#, c-format
msgid "unable to open %s"
@@ -17585,7 +18090,7 @@ msgstr "hash stämmer inte för %s (förväntade %s)"
#, c-format
msgid "unable to mmap %s"
-msgstr "kan inte utföra \"mmap\" för %s"
+msgstr "kan inte utföra â€mmap†för %s"
#, c-format
msgid "unable to unpack header of %s"
@@ -17688,72 +18193,72 @@ msgstr ""
"\n"
" git switch -c $br $(git rev-parse ...)\n"
"\n"
-"där \"$br\" på något sätt blivit tomt och en 40-hex-referens skapats.\n"
+"där â€$br†pÃ¥ nÃ¥got sätt blivit tomt och en 40-hex-referens skapats.\n"
"Undersök referenserna och ta kanske bort dem. Stäng av meddelandet\n"
-"genom att köra \"git config advice.objectNameWarning false\""
+"genom att köra â€git config advice.objectNameWarning falseâ€"
#, c-format
msgid "log for '%.*s' only goes back to %s"
-msgstr "loggen för \"%.*s\" räcker bara tillbaka till %s"
+msgstr "loggen för â€%.*s†räcker bara tillbaka till %s"
#, c-format
msgid "log for '%.*s' only has %d entries"
-msgstr "loggen för \"%.*s\" har bara %d poster"
+msgstr "loggen för â€%.*s†har bara %d poster"
#, c-format
msgid "path '%s' exists on disk, but not in '%.*s'"
-msgstr "Sökvägen \"%s\" finns på disken, men inte i \"%.*s\""
+msgstr "Sökvägen â€%s†finns pÃ¥ disken, men inte i â€%.*sâ€"
#, c-format
msgid ""
"path '%s' exists, but not '%s'\n"
"hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"
msgstr ""
-"sökvägen \"%s\" finns, men inte i \"%s\"\n"
-"tips: Menade du \"%.*s:%s\", även känd som \"%.*s:./%s\"?"
+"sökvägen â€%s†finns, men inte i â€%sâ€\n"
+"tips: Menade du â€%.*s:%sâ€, även känd som â€%.*s:./%sâ€?"
#, c-format
msgid "path '%s' does not exist in '%.*s'"
-msgstr "sökvägen \"%s\" finns inte i \"%.*s\""
+msgstr "sökvägen â€%s†finns inte i â€%.*sâ€"
#, c-format
msgid ""
"path '%s' is in the index, but not at stage %d\n"
"hint: Did you mean ':%d:%s'?"
msgstr ""
-"sökvägen \"%s\" finns i indexet men inte i etapp %d\n"
-"tips: Menade du \":%d:%s\"?"
+"sökvägen â€%s†finns i indexet men inte i etapp %d\n"
+"tips: Menade du â€:%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ökvägen \"%s\" finns i indexet, men inte i \"%s\"\n"
-"tips: Menade du \":%d:%s\", även känd som \":%d:./%s\"?"
+"sökvägen â€%s†finns i indexet, men inte i â€%sâ€\n"
+"tips: Menade du â€:%d:%sâ€, även känd som â€:%d:./%sâ€?"
#, c-format
msgid "path '%s' exists on disk, but not in the index"
-msgstr "sökvägen \"%s\" finns på disk, men inte i indexet"
+msgstr "sökvägen â€%s†finns pÃ¥ disk, men inte i indexet"
#, c-format
msgid "path '%s' does not exist (neither on disk nor in the index)"
-msgstr "sökvägen \"%s\" finns inte (varken i disken eller i indexet)"
+msgstr "sökvägen â€%s†finns inte (varken i disken eller i indexet)"
msgid "relative path syntax can't be used outside working tree"
msgstr "relativ sökväg kan inte användas utanför arbetskatalogen"
#, c-format
msgid "<object>:<path> required, only <object> '%s' given"
-msgstr "<objekt>:<sökväg> krävs, endast <objekt> \"%s\" har angivits"
+msgstr "<objekt>:<sökväg> krävs, endast <objekt> â€%s†har angivits"
#, c-format
msgid "invalid object name '%.*s'."
-msgstr "felaktigt objektnamn \"%.*s\"."
+msgstr "felaktigt objektnamn â€%.*sâ€."
#, c-format
msgid "invalid object type \"%s\""
-msgstr "ogiltig objekttyp \"%s\""
+msgstr "ogiltig objekttyp â€%sâ€"
#, c-format
msgid "object %s is a %s, not a %s"
@@ -17765,12 +18270,23 @@ msgstr "objektet %s har okänd typ-id %d"
#, c-format
msgid "unable to parse object: %s"
-msgstr "kunde inte tolka objektet: %s"
+msgstr "kan inte tolka objektet: %s"
#, c-format
msgid "hash mismatch %s"
msgstr "hashvärde stämmer inte överens %s"
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "duplicerad post när bitkarteindex skulle skrivas: %s"
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "försökta lagra icke-vald incheckning: â€%sâ€"
+
+msgid "too many pseudo-merges"
+msgstr "för många pseudo-sammanslagningar"
+
msgid "trying to write commit not in index"
msgstr "försöker skriva incheckning som inte finns i indexet"
@@ -17785,7 +18301,7 @@ msgstr "trasigt bitkarteindex (felaktigt huvud)"
#, c-format
msgid "unsupported version '%d' for bitmap index file"
-msgstr "versionen \"%d\" i bitkarteindexfilen stöds inte"
+msgstr "versionen â€%d†i bitkarteindexfilen stöds inte"
msgid "corrupted bitmap index file (too short to fit hash cache)"
msgstr "trasigt bitkarteindex (för kort för att få plats för hash-cache)"
@@ -17793,9 +18309,23 @@ msgstr "trasigt bitkarteindex (för kort för att få plats för hash-cache)"
msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr "trasigt bitkarteindex (för kort för att få plats för uppslagstabell)"
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"trasig bitkarteindexfil (för kort för att få plats för pseudo-"
+"sammanslagningsatbellhuvudet)"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"trasig bitkarteindexfil (för kort för att få plats för pseudo-"
+"sammanslagningstabell)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "trasig bitkarteindexfil, pseudosammanslagningstabellen är för kort"
+
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
-msgstr "duplicerad post i bitkarteindex: \"%s\""
+msgstr "duplicerad post i bitkarteindex: â€%sâ€"
#, c-format
msgid "corrupt ewah bitmap: truncated header for entry %d"
@@ -17812,7 +18342,7 @@ msgid "invalid XOR offset in bitmap pack index"
msgstr "ogiltigt XOR-offset i bitkarte-packindex"
msgid "cannot fstat bitmap file"
-msgstr "kan inte utföra \"fstat\" på bitkartefil"
+msgstr "kan inte utföra â€fstat†pÃ¥ bitkartefil"
msgid "checksum doesn't match in MIDX and bitmap"
msgstr "checksumman stämmer inte i MIDX och bitkarta"
@@ -17824,6 +18354,9 @@ msgstr "flerpaketsbitkarta saknar nödvändigt omvänt index"
msgid "could not open pack %s"
msgstr "kunde inte öppna paketfilen %s"
+msgid "could not determine MIDX preferred pack"
+msgstr "kunde inte bestämma det föredragna MIDX-paketet"
+
#, c-format
msgid "preferred pack (%s) is invalid"
msgstr "föredragen paketfil (%s) är ogiltig"
@@ -17841,20 +18374,26 @@ msgstr ""
#, c-format
msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
-msgstr ""
-"trasig ewah-bitkarta: avhugget huvud för bitkarta för incheckning \"%s\""
+msgstr "trasig ewah-bitkarta: avhugget huvud för bitkarta för incheckning â€%sâ€"
+
+#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "kan inte läsa paketet: â€%sâ€, inaktiverar Ã¥teranvändning av paket"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "kan inte beräkna föredraget paket, inaktiverar återanvändning av paket"
#, c-format
msgid "object '%s' not found in type bitmaps"
-msgstr "objektet \"%s\" hittades inte i typbitkartor"
+msgstr "objektet â€%s†hittades inte i typbitkartor"
#, c-format
msgid "object '%s' does not have a unique type"
-msgstr "objektet \"%s\" har inte en unik typ"
+msgstr "objektet â€%s†har inte en unik typ"
#, c-format
msgid "object '%s': real type '%s', expected: '%s'"
-msgstr "objektet \"%s\": riktig typ \"%s\", förväntade \"%s\""
+msgstr "objektet â€%sâ€: riktig typ â€%sâ€, förväntade â€%sâ€"
#, c-format
msgid "object not in bitmap: '%s'"
@@ -17868,22 +18407,26 @@ msgstr "du måste ange exakt en incheckning att testa"
#, c-format
msgid "commit '%s' doesn't have an indexed bitmap"
-msgstr "incheckningen \"%s\" har inte en indexerad bitkarta"
+msgstr "incheckningen â€%s†har inte en indexerad bitkarta"
msgid "mismatch in bitmap results"
msgstr "bitkarteresultat stämmer inte överens"
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "pseudosammanslaningsindex utenför intervallet (%<PRIu32> ≥ %<PRIuMAX>)"
+
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
-msgstr "kunde inte hitta \"%s\" i paketet \"%s\" på offset %<PRIuMAX>"
+msgstr "kunde inte hitta â€%s†i paketet â€%s†pÃ¥ offset %<PRIuMAX>"
#, c-format
msgid "unable to get disk usage of '%s'"
-msgstr "kan inte hämta diskanvändning för \"%s\""
+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"
+msgstr "bitkartefilen â€%s†har ogiltig kontrollsumma"
#, c-format
msgid "mtimes file %s is too small"
@@ -17932,6 +18475,12 @@ msgstr "ogiltig kontrollsumma"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "ogiltig rev-indexposition vid %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "baklängesindex-stycke för multi-pack-index har fel storlek"
+
+msgid "could not determine preferred pack"
+msgstr "kunde inte bestämma föredraget paket"
+
msgid "cannot both write and verify reverse index"
msgstr "kan inte både skriva och bekräfta reverse-index"
@@ -17941,11 +18490,11 @@ msgstr "kunde inte ta status: %s"
#, c-format
msgid "failed to make %s readable"
-msgstr "kunde inte göra %s läsbar"
+msgstr "misslyckades göra %s läsbar"
#, c-format
msgid "could not write '%s' promisor file"
-msgstr "kunde inte skriva kontraktsfilen \"%s\""
+msgstr "kunde inte skriva kontraktsfilen â€%sâ€"
msgid "offset before end of packfile (broken .idx?)"
msgstr "offset före slutet av packfilen (trasig .idx?)"
@@ -17964,34 +18513,25 @@ msgstr "offset borton slutet av packindex för %s (trunkerat index?)"
#, c-format
msgid "malformed expiration date '%s'"
-msgstr "trasigt utlöpsdatum: \"%s\""
+msgstr "trasigt utlöpsdatum: â€%sâ€"
#, c-format
msgid "option `%s' expects \"always\", \"auto\", or \"never\""
-msgstr ""
-"flaggan \"%s\" antar \"always\" (alltid), \"auto\" eller \"never\" (aldrig)"
+msgstr "flaggan â€%s†antar â€always†(alltid), â€auto†eller â€never†(aldrig)"
#, c-format
msgid "malformed object name '%s'"
-msgstr "felformat objektnamn \"%s\""
+msgstr "felformat objektnamn â€%sâ€"
#, c-format
msgid "option `%s' expects \"%s\" or \"%s\""
-msgstr "flaggan \"%s\" kräver \"%s\" eller \"%s\""
+msgstr "flaggan â€%s†kräver â€%s†eller â€%sâ€"
#, c-format
msgid "%s requires a value"
msgstr "%s behöver ett värde"
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s är inkompatibel med %s"
-
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s: inkompatibelt med något annat"
-
-#, c-format
msgid "%s takes no value"
msgstr "%s tar inget värde"
@@ -18009,7 +18549,7 @@ msgstr "tvetydig flagga: %s (kan vara --%s%s eller --%s%s)"
#, c-format
msgid "did you mean `--%s` (with two dashes)?"
-msgstr "menade du \"--%s\" (med två bindestreck)?"
+msgstr "menade du â€--%s†(med tvÃ¥ bindestreck)?"
#, c-format
msgid "alias of --%s"
@@ -18020,15 +18560,15 @@ msgstr "behöver ett underkommando"
#, c-format
msgid "unknown option `%s'"
-msgstr "okänd flagga \"%s\""
+msgstr "okänd flagga â€%sâ€"
#, c-format
msgid "unknown switch `%c'"
-msgstr "okänd flagga \"%c\""
+msgstr "okänd flagga â€%câ€"
#, c-format
msgid "unknown non-ascii option in string: `%s'"
-msgstr "okänd icke-ascii-flagga i strängen: \"%s\""
+msgstr "okänd icke-ascii-flagga i strängen: â€%sâ€"
msgid "..."
msgstr "..."
@@ -18074,6 +18614,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-TAL"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "motsatsen mot --no-%s"
+
msgid "expiry-date"
msgstr "giltig-till"
@@ -18103,14 +18647,22 @@ msgid ""
msgstr "med --pathspec-from-file, sökvägsangivelser avdelas med NUL-tecken"
#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "felaktigt booleskt miljövariabelvärde â€%s†för â€%sâ€"
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "misslyckades tolka %s"
+
+#, c-format
msgid "Could not make %s writable by group"
msgstr "Kunde inte göra %s skrivbar för gruppen"
msgid "Escape character '\\' not allowed as last character in attr value"
-msgstr "Specialtecknet \"\\\" tillåts inte som sista tecken i attributvärde"
+msgstr "Specialtecknet â€\\†tillÃ¥ts inte som sista tecken i attributvärde"
msgid "Only one 'attr:' specification is allowed."
-msgstr "Endast en \"attr:\"-angivelse tillåten."
+msgstr "Endast en â€attr:â€-angivelse tillÃ¥ten."
msgid "attr spec must not be empty"
msgstr "attr-angivelse kan inte vara tom"
@@ -18120,42 +18672,45 @@ msgid "invalid attribute name %s"
msgstr "ogiltigt attributnamn %s"
msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
-msgstr ""
-"de globala sökvägsinställningarna \"glob\" och \"noglob\" är inkompatibla"
+msgstr "de globala sökvägsinställningarna â€glob†och â€noglob†är inkompatibla"
msgid ""
"global 'literal' pathspec setting is incompatible with all other global "
"pathspec settings"
msgstr ""
-"den globala sökvägsinställningen \"literal\" är inkompatibel med alla andra "
+"den globala sökvägsinställningen â€literal†är inkompatibel med alla andra "
"globala sökvägsinställningar"
msgid "invalid parameter for pathspec magic 'prefix'"
-msgstr "ogiltig parameter för sökvägsuttrycket för \"prefix\""
+msgstr "ogiltig parameter för sökvägsuttrycket för â€prefixâ€"
#, c-format
msgid "Invalid pathspec magic '%.*s' in '%s'"
-msgstr "Felaktigt sökvägsuttryck \"%.*s\" i \"%s\""
+msgstr "Felaktigt sökvägsuttryck â€%.*s†i â€%sâ€"
#, c-format
msgid "Missing ')' at the end of pathspec magic in '%s'"
-msgstr "\")\" saknas i slutet av sökvägsuttrycket för \"%s\""
+msgstr "â€)†saknas i slutet av sökvägsuttrycket för â€%sâ€"
#, c-format
msgid "Unimplemented pathspec magic '%c' in '%s'"
-msgstr "Ej implementerat sökvägsuttryckmagi \"%c\" i \"%s\""
+msgstr "Ej implementerat sökvägsuttryckmagi â€%c†i â€%sâ€"
#, c-format
msgid "%s: 'literal' and 'glob' are incompatible"
-msgstr "%s: \"literal\" och \"glob\" är inkompatibla"
+msgstr "%s: â€literal†och â€glob†är inkompatibla"
+
+#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "â€%s†är utanför katalogträdet"
#, c-format
msgid "%s: '%s' is outside repository at '%s'"
-msgstr "%s: \"%s\" är utanför arkivet på \"%s\""
+msgstr "%s: â€%s†är utanför arkivet pÃ¥ â€%sâ€"
#, c-format
msgid "'%s' (mnemonic: '%c')"
-msgstr "\"%s\" (minnesstöd: \"%c\")"
+msgstr "â€%s†(minnesstöd: â€%câ€)"
#, c-format
msgid "%s: pathspec magic not supported by this command: %s"
@@ -18163,7 +18718,7 @@ msgstr "%s: sökvägsuttrycket hanteras inte av det här kommandot: %s"
#, c-format
msgid "pathspec '%s' is beyond a symbolic link"
-msgstr "sökvägsangivelsen \"%s\" är på andra sidan av en symbolisk länk"
+msgstr "sökvägsangivelsen â€%s†är pÃ¥ andra sidan av en symbolisk länk"
#, c-format
msgid "line is badly quoted: %s"
@@ -18176,10 +18731,10 @@ msgid "unable to write delim packet"
msgstr "kan inte skriva delim-paket"
msgid "unable to write response end packet"
-msgstr "kunde inte skriva svarsavslutningspaket"
+msgstr "kan inte skriva svarsavslutningspaket"
msgid "flush packet write failed"
-msgstr "fel vid skrivning av \"flush\"-paket"
+msgstr "fel vid skrivning av â€flushâ€-paket"
msgid "protocol error: impossibly long line"
msgstr "protokollfel: omöjligt lång rad"
@@ -18217,16 +18772,20 @@ msgstr "Uppdaterar indexet"
#, c-format
msgid "unable to create threaded lstat: %s"
-msgstr "kunde inte skapa trådad lstat: %s"
+msgstr "kan inte skapa trådad lstat: %s"
msgid "unable to parse --pretty format"
-msgstr "kunde inte tolka format för --pretty"
+msgstr "kan inte tolka format för --pretty"
+
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr ""
+"fördröjd hämtning inaktiverad; några objekt kanske inte är tillgängliga"
msgid "promisor-remote: unable to fork off fetch subprocess"
-msgstr "promisor-remote: kunde inte starta (fork) underprocessen för fetch"
+msgstr "promisor-remote: kan inte grena (fork) av underprocessen för fetch"
msgid "promisor-remote: could not write to fetch subprocess"
-msgstr "promisor-remote: kunde skriva till underprocessen för fetch"
+msgstr "promisor-remote: kan skriva till underprocessen för fetch"
msgid "promisor-remote: could not close stdin to fetch subprocess"
msgstr ""
@@ -18234,57 +18793,121 @@ msgstr ""
#, c-format
msgid "promisor remote name cannot begin with '/': %s"
-msgstr "kontraktsfjärr kan inte börja med \"/\": %s"
+msgstr "kontraktsfjärr kan inte börja med â€/â€: %s"
#, c-format
msgid "could not fetch %s from promisor remote"
msgstr "kunde inte hämta %s från kontraktsfjärr"
msgid "object-info: expected flush after arguments"
-msgstr "object-info: förväntade \"flush\" efter argument"
+msgstr "object-info: förväntade â€flush†efter argument"
msgid "Removing duplicate objects"
msgstr "Tar bort duplicerade objekt"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr ""
+"misslyckades läsa reguljärt uttryck för pseudosammanslagning för â€%sâ€: %s"
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s måste vara icke-negativt, använder förval"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s måste vara mellan 0 och 1, använder förval"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s måste vara positivt, använder förval"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "pseudosammanslagningsgruppen â€%s†saknar nödvändigt mönster"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"pseudosammanslagningsgruppen â€%s†har instabila tröskelvärden innan de "
+"stabila"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"reguljärt uttryck för pseudosammanslagning har för många fångstgrupper "
+"(max=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"läsning utanför intervallet för utökad pseudosammanslagning (%<PRIuMAX> ≥ "
+"%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"posten för utökad pseudosammanslagning är för kort (%<PRIuMAX> ≥ %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr ""
+"kunde inte hitta pseudosammanslagning för incheckningen %s på offset "
+"%<PRIuMAX>"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"uppslagning utanför intervallet för utökad pseudosammanslagning (%<PRIu32> ≥ "
+"%<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "läsning utanför intervallet: (%<PRIuMAX> ≥ %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "kunde inte läsa utökad pseudosammanslagningstabell för incheckning %s"
+
msgid "could not start `log`"
-msgstr "kunde inte starta \"log\""
+msgstr "kunde inte starta â€logâ€"
msgid "could not read `log` output"
-msgstr "kunde inte läsa utdata från \"log\""
+msgstr "kunde inte läsa utdata frÃ¥n â€logâ€"
#, c-format
msgid "could not parse commit '%s'"
-msgstr "kunde inte tolka incheckningen \"%s\""
+msgstr "kunde inte tolka incheckningen â€%sâ€"
#, c-format
msgid ""
"could not parse first line of `log` output: did not start with 'commit ': "
"'%s'"
msgstr ""
-"kunde inte tolka första raden i \"log\"-updata: börjar inte med \"commit \": "
-"\"%s\""
+"kunde inte tolka första raden i â€logâ€-updata: börjar inte med â€commit â€: â€%sâ€"
#, c-format
msgid "could not parse git header '%.*s'"
-msgstr "kunde inte tolka git-huvudet \"%.*s\""
+msgstr "kunde inte tolka git-huvudet â€%.*sâ€"
msgid "failed to generate diff"
msgstr "misslyckades skapa diff"
#, c-format
msgid "could not parse log for '%s'"
-msgstr "kunde inte tolka loggen för \"%s\""
+msgstr "kunde inte tolka loggen för â€%sâ€"
#, c-format
msgid "invalid extra cruft tip: '%s'"
-msgstr "ogiltig extra överbliven ände: \"%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)"
+msgstr "lägger inte till filalias â€%s†(â€%s†finns redan i indexet)"
msgid "cannot create an empty blob in the object database"
msgstr "kan inte skapa tom blob i objektdatabasen"
@@ -18296,19 +18919,15 @@ msgstr ""
#, c-format
msgid "unable to index file '%s'"
-msgstr "kan inte indexera filen \"%s\""
+msgstr "kan inte indexera filen â€%sâ€"
#, c-format
msgid "unable to add '%s' to index"
-msgstr "kan inte lägga till \"%s\" till indexet"
-
-#, c-format
-msgid "unable to stat '%s'"
-msgstr "kan inte ta status på \"%s\""
+msgstr "kan inte lägga till â€%s†till indexet"
#, c-format
msgid "'%s' appears as both a file and as a directory"
-msgstr "\"%s\" finns både som en fil och en katalog"
+msgstr "â€%s†finns bÃ¥de som en fil och en katalog"
msgid "Refresh index"
msgstr "Uppdatera indexet"
@@ -18354,26 +18973,26 @@ msgstr "okänt format 0x%08x på indexpost"
#, c-format
msgid "malformed name field in the index, near path '%s'"
-msgstr "felformat namnfält i indexet, nära sökvägen \"%s\""
+msgstr "felformat namnfält i indexet, nära sökvägen â€%sâ€"
msgid "unordered stage entries in index"
msgstr "osorterade köposter i index"
#, c-format
msgid "multiple stage entries for merged file '%s'"
-msgstr "flera köposter för den sammanslagna filen \"%s\""
+msgstr "flera köposter för den sammanslagna filen â€%sâ€"
#, c-format
msgid "unordered stage entries for '%s'"
-msgstr "osorterade köposter för \"%s\""
+msgstr "osorterade köposter för â€%sâ€"
#, c-format
msgid "unable to create load_cache_entries thread: %s"
-msgstr "kunde inte skapa tråd för load_cache_entries: %s"
+msgstr "kan inte skapa tråd för load_cache_entries: %s"
#, c-format
msgid "unable to join load_cache_entries thread: %s"
-msgstr "kunde inte ansluta till tråden för load_cache_entries: %s"
+msgstr "kan inte ansluta till tråden för load_cache_entries: %s"
#, c-format
msgid "%s: index file open failed"
@@ -18393,15 +19012,15 @@ msgstr "%s: kan inte koppla indexfilen%s"
#, c-format
msgid "unable to create load_index_extensions thread: %s"
-msgstr "kunde inte skapa load_index_extensions-tråden: %s"
+msgstr "kan inte skapa load_index_extensions-tråden: %s"
#, c-format
msgid "unable to join load_index_extensions thread: %s"
-msgstr "kunde inte utföra join på load_index_extensions-tråden: %s"
+msgstr "kan inte utföra join på load_index_extensions-tråden: %s"
#, c-format
msgid "could not freshen shared index '%s'"
-msgstr "kunde inte uppdatera delat index \"%s\""
+msgstr "kunde inte uppdatera delat index â€%sâ€"
#, c-format
msgid "broken index, expect %s in %s, got %s"
@@ -18414,20 +19033,16 @@ msgid "failed to convert to a sparse-index"
msgstr "misslyckades omvandla till glest index"
#, c-format
-msgid "could not stat '%s'"
-msgstr "kunde inte ta status på \"%s\""
-
-#, c-format
msgid "unable to open git dir: %s"
-msgstr "kunde inte öppna git-katalog: %s"
+msgstr "kan inte öppna git-katalog: %s"
#, c-format
msgid "unable to unlink: %s"
-msgstr "misslyckades ta bort länken: %s"
+msgstr "kan inte ta bort länken: %s"
#, c-format
msgid "cannot fix permission bits on '%s'"
-msgstr "kan inte rätta behörighetsbitar på \"%s\""
+msgstr "kan inte rätta behörighetsbitar pÃ¥ â€%sâ€"
#, c-format
msgid "%s: cannot drop to stage #0"
@@ -18439,16 +19054,16 @@ msgstr "diff-status %c förväntades inte"
#, c-format
msgid "remove '%s'\n"
-msgstr "ta bort \"%s\"\n"
+msgstr "ta bort â€%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 ""
-"Du kan rätta detta med \"git rebase --edit-todo\" följt av \"git rebase --"
-"continue\".\n"
-"Avbryt ombaseringen med \"git rebase --abort\".\n"
+"Du kan rätta detta med â€git rebase --edit-todo†följt av â€git rebase --"
+"continueâ€.\n"
+"Avbryt ombaseringen med â€git rebase --abortâ€.\n"
#, c-format
msgid ""
@@ -18490,18 +19105,17 @@ msgstr ""
"e, edit <incheckning> = använd incheckning, men stanna för tillägg\n"
"s, squash <incheckning> = använd incheckning, men infoga i föregående "
"incheckning\n"
-"f, fixup [-C | -c] <incheckning> = som \"squash\" men behåll bara "
+"f, fixup [-C | -c] <incheckning> = som â€squash†men behÃ¥ll bara "
"loggmeddelandet\n"
" från föregående incheckning, såvida inte -C används, då "
"används\n"
" istället bara den här incheckningens meddelande; -c är "
"samma\n"
" som -C, men öppnar redigeringsprogrammet\n"
-"f, fixup <incheckning> = som \"squash\", men förkasta "
-"incheckningsmeddelandet\n"
+"f, fixup <incheckning> = som â€squashâ€, men förkasta incheckningsmeddelandet\n"
"x, exec <kommando> = kör kommando (resten av raden) i skalet\n"
-"b, break = stoppa här (fortsätt ombaseringen senare med \"git rebase --"
-"continue\")\n"
+"b, break = stoppa här (fortsätt ombaseringen senare med â€git rebase --"
+"continueâ€)\n"
"d, drop <incheckning> = ta bort incheckning\n"
"l, label <etikett> = ge aktuellt HEAD ett namn\n"
"t, reset <etikett> = återställ HEAD till en etikett\n"
@@ -18526,7 +19140,7 @@ msgid ""
"Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
msgstr ""
"\n"
-"Ta inte bort rader. Använd \"drop\" för att specifikt förkasta en "
+"Ta inte bort rader. Använd â€drop†för att specifikt förkasta en "
"incheckning.\n"
msgid ""
@@ -18544,7 +19158,7 @@ msgid ""
"\n"
msgstr ""
"\n"
-"Du redigerar \"todo\"-filen för en pågående interaktiv ombasering.\n"
+"Du redigerar â€todoâ€-filen för en pÃ¥gÃ¥ende interaktiv ombasering.\n"
"För att forsätta ombasera efter redigeringen, kör:\n"
" git rebase --continue\n"
"\n"
@@ -18560,7 +19174,7 @@ msgstr ""
#, c-format
msgid "could not write '%s'."
-msgstr "kunde inte skriva \"%s\"."
+msgstr "kunde inte skriva â€%sâ€."
#, c-format
msgid ""
@@ -18579,19 +19193,16 @@ msgid ""
"The possible behaviours are: ignore, warn, error.\n"
"\n"
msgstr ""
-"För att undvika det här meddelandet kan du använda \"drop\" för att "
-"explicit\n"
+"För att undvika det här meddelandet kan du använda â€drop†för att explicit\n"
"kasta en incheckning.\n"
"\n"
-"Använd \"git config rebase.missingCommitsCheck\" för att ändra "
-"varningsnivån.\n"
-"Möjliga bettenden är: \"ignore\" (ignorera), \"warn\" (varna), \"error"
-"\" (fel).\n"
+"Använd â€git config rebase.missingCommitsCheck†för att ändra varningsnivÃ¥n.\n"
+"Möjliga bettenden är: â€ignore†(ignorera), â€warn†(varna), â€error†(fel).\n"
"\n"
#, c-format
msgid "%s: 'preserve' superseded by 'merges'"
-msgstr "%s: \"preserve\" har ersatts av \"merges\""
+msgstr "%s: â€preserve†har ersatts av â€mergesâ€"
msgid "gone"
msgstr "försvunnen"
@@ -18662,7 +19273,7 @@ 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)"
+msgstr "positivt värde förväntat â€%s†i %%(%s)"
#, c-format
msgid "expected format: %%(align:<width>,<position>)"
@@ -18689,6 +19300,10 @@ msgid "expected format: %%(ahead-behind:<committish>)"
msgstr "förväntat format: %%(ahead-behind:<incheckning-igt>)"
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "förväntat format: %%(is-base:<incheckning-igt>)"
+
+#, c-format
msgid "malformed field name: %.*s"
msgstr "felformat fältnamn: %.*s"
@@ -18699,8 +19314,7 @@ msgstr "okänt fältnamn: %.*s"
#, c-format
msgid ""
"not a git repository, but the field '%.*s' requires access to object data"
-msgstr ""
-"inte ett git-arkiv, men fältet \"%.*s\" kräver tillgång till objektdata"
+msgstr "inte ett git-arkiv, men fältet â€%.*s†kräver tillgÃ¥ng till objektdata"
#, c-format
msgid "format: %%(%s) atom used without a %%(%s) atom"
@@ -18735,7 +19349,7 @@ 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\""
+msgstr "misslyckades att köra â€describeâ€"
#, c-format
msgid "(no branch, rebasing %s)"
@@ -18747,7 +19361,7 @@ msgstr "(ingen gren, ombaserar frånkopplat HEAD %s)"
#, c-format
msgid "(no branch, bisect started on %s)"
-msgstr "(ingen gren, \"bisect\" startad på %s)"
+msgstr "(ingen gren, â€bisect†startad pÃ¥ %s)"
#, c-format
msgid "(HEAD detached at %s)"
@@ -18770,7 +19384,7 @@ msgstr "parse_object_buffer misslyckades på %s för %s"
#, c-format
msgid "malformed object at '%s'"
-msgstr "felformat objekt vid \"%s\""
+msgstr "felformat objekt vid â€%sâ€"
#, c-format
msgid "ignoring ref with broken name %s"
@@ -18790,7 +19404,7 @@ msgstr "felformat objektnamn %s"
#, c-format
msgid "option `%s' must point to a commit"
-msgstr "flaggan \"%s\" måste peka på en incheckning"
+msgstr "flaggan â€%s†mÃ¥ste peka pÃ¥ en incheckning"
msgid "key"
msgstr "nyckel"
@@ -18807,11 +19421,11 @@ msgstr "inte en referenslogg: %s"
#, c-format
msgid "no reflog for '%s'"
-msgstr "ingen referenslogg för \"%s\""
+msgstr "ingen referenslogg för â€%sâ€"
#, c-format
msgid "%s does not point to a valid object!"
-msgstr "\"%s\" pekar inte på ett giltigt objekt!"
+msgstr "â€%s†pekar inte pÃ¥ ett giltigt objekt!"
#, c-format
msgid ""
@@ -18826,20 +19440,20 @@ msgid ""
"\n"
"\tgit branch -m <name>\n"
msgstr ""
-"Använder \"%s\" som namn för den inledande grenen. Detta förvalda grennamn\n"
+"Använder â€%s†som namn för den inledande grenen. Detta förvalda grennamn\n"
"kan ändras i framtiden. För att välja vilket namn som ska användas på\n"
"den inledande grenen i alla nya arkiv, och dölja denna varning, kör du:\n"
"\n"
"\tgit config --global init.defaultBranch <namn>\n"
"\n"
-"Namn som ofta används istället för \"master\" är \"main\", \"trunk\" och\n"
-"\"development\". Den nyskapade grenen kan ges nytt namn med kommandot:\n"
+"Namn som ofta används istället för â€master†är â€mainâ€, â€trunk†och\n"
+"â€developmentâ€. Den nyskapade grenen kan ges nytt namn med kommandot:\n"
"\n"
"\tgit branch -m <namn>\n"
#, c-format
msgid "could not retrieve `%s`"
-msgstr "kunde inte hämta \"%s\""
+msgstr "kunde inte hämta â€%sâ€"
#, c-format
msgid "invalid branch name: %s = %s"
@@ -18861,17 +19475,24 @@ msgstr "loggen för referensen %s slutade oväntat på %s"
msgid "log for %s is empty"
msgstr "loggen för %s är tom"
+msgid "refusing to force and skip creation of reflog"
+msgstr "vägrar att tvinga och hoppa över skapande av reflogg"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
-msgstr "vägrar uppdatera referens med trasigt namn \"%s\""
+msgstr "vägrar uppdatera referens med trasigt namn â€%sâ€"
+
+#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "vägrar uppdatera pseudoreferensen â€%sâ€"
#, c-format
msgid "update_ref failed for ref '%s': %s"
-msgstr "update_ref misslyckades för referensen \"%s\": %s"
+msgstr "update_ref misslyckades för referensen â€%sâ€: %s"
#, c-format
msgid "multiple updates for ref '%s' not allowed"
-msgstr "flera uppdateringar för referensen \"%s\" tillåts inte"
+msgstr "flera uppdateringar för referensen â€%s†tillÃ¥ts inte"
msgid "ref updates forbidden inside quarantine environment"
msgstr "referensuppdateringar förbjudna i karantänmiljö"
@@ -18881,15 +19502,11 @@ msgstr "referensuppdateringar avbrutna av krok"
#, c-format
msgid "'%s' exists; cannot create '%s'"
-msgstr "\"%s\" finns; kan inte skapa \"%s\""
+msgstr "â€%s†finns; kan inte skapa â€%sâ€"
#, c-format
msgid "cannot process '%s' and '%s' at the same time"
-msgstr "kan inte hantera \"%s\" och \"%s\" samtidigt"
-
-#, c-format
-msgid "could not remove reference %s"
-msgstr "kunde inte ta bort referensen %s"
+msgstr "kan inte hantera â€%s†och â€%s†samtidigt"
#, c-format
msgid "could not delete reference %s: %s"
@@ -18900,12 +19517,108 @@ msgid "could not delete references: %s"
msgstr "kunde inte ta bort referenser: %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "Avslutade testkörning av referensmigrering, resultatet hittas i â€%sâ€\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "kunde ta bort temporär migreringskatalog â€%sâ€"
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "migrerade referenser hittas vid â€%sâ€"
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"kan inte läsa referensen â€%sâ€: förväntade symbolisk referens med mÃ¥let â€%sâ€: "
+"men är en vanlig referens"
+
+#, c-format
+msgid "cannot open directory %s"
+msgstr "kunde inte öppna katalogen %s"
+
+msgid "Checking references consistency"
+msgstr "Kontrollerar konsistens för referenser"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "refnamnet är farligt: %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "försöker skriva referensen â€%s†med icke-existerande objektet %s"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "försöker skriva objektet %s som inte är incheckning till grenen â€%sâ€"
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"flera uppdateringar för â€HEAD†(inklusive en via dess referent â€%sâ€) tillÃ¥ts "
+"inte"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr "kan inte lÃ¥sa referensen â€%sâ€: kan inte slÃ¥ upp referensen â€%sâ€"
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "kan inte lÃ¥sa referensen â€%sâ€: fel vid läsning av referensen"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"flera uppdateringar för â€%s†(inklusive en via symrefen â€%sâ€) tillÃ¥ts inte"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "kan inte lÃ¥sa referensen â€%sâ€: referensen finns redan"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr "kan inte lÃ¥sa referensen â€%sâ€: referensen saknas men förväntade %s"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "kan inte lÃ¥sa referensen â€%sâ€: är vid %s men förväntade %s"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "referenstabell: förbereder transaktion: %s"
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "referenstabell: transaktionen misslyckades: %s"
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "kan inte kompaktera stack: %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "referensnamnet %s hittades inte"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "referensnamnet %s är en symbolisk referens, kopiering stöds inte"
+
+#, c-format
msgid "invalid refspec '%s'"
-msgstr "felaktig referensspecifikation: \"%s\""
+msgstr "felaktig referensspecifikation: â€%sâ€"
#, c-format
msgid "invalid quoting in push-option value: '%s'"
-msgstr "felaktig citering på värde för push-option: \"%s\""
+msgstr "felaktig citering pÃ¥ värde för push-option: â€%sâ€"
+
+#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "okänt värde för object-format: %s"
#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
@@ -18916,23 +19629,23 @@ msgstr "ogiltigt svar från servern; förväntade tjänst, fick flush-paket"
#, c-format
msgid "invalid server response; got '%s'"
-msgstr "ogiltigt svar från servern; fick \"%s\""
+msgstr "ogiltigt svar frÃ¥n servern; fick â€%sâ€"
#, c-format
msgid "repository '%s' not found"
-msgstr "arkivet \"%s\" hittades inte"
+msgstr "arkivet â€%s†hittades inte"
#, c-format
msgid "Authentication failed for '%s'"
-msgstr "Autentisering misslyckades \"%s\""
+msgstr "Autentisering misslyckades â€%sâ€"
#, c-format
msgid "unable to access '%s' with http.pinnedPubkey configuration: %s"
-msgstr "kan inte nå \"%s\" med http.pinnedPubkey inställt till: %s"
+msgstr "kan inte nÃ¥ â€%s†med http.pinnedPubkey inställt till: %s"
#, c-format
msgid "unable to access '%s': %s"
-msgstr "kan inte komma åt \"%s\": %s"
+msgstr "kan inte komma Ã¥t â€%sâ€: %s"
#, c-format
msgid "redirecting to %s"
@@ -18945,7 +19658,7 @@ msgid "remote server sent unexpected response end packet"
msgstr "fjärrservern sände oväntat svarsavslutningspaketet"
msgid "unable to rewind rpc post data - try increasing http.postBuffer"
-msgstr "kunde inte spola tillbaka rpc-postdata - försök öka http.postBuffer"
+msgstr "kan inte spola tillbaka rpc-postdata - försök öka http.postBuffer"
#, c-format
msgid "remote-curl: bad line length character: %.4s"
@@ -18988,18 +19701,18 @@ msgstr "kan inte hämta med sha1 över smart http"
#, c-format
msgid "protocol error: expected sha/ref, got '%s'"
-msgstr "protokollfel: förväntade sha/ref, fick \"%s\""
+msgstr "protokollfel: förväntade sha/ref, fick â€%sâ€"
#, c-format
msgid "http transport does not support %s"
msgstr "http-transporten stöder inte %s"
msgid "protocol error: expected '<url> <path>', missing space"
-msgstr "protokollfel: förväntade \"<url> <sökväg>\", saknar blanksteg"
+msgstr "protokollfel: förväntade â€<url> <sökväg>â€, saknar blanksteg"
#, c-format
msgid "failed to download file at URL '%s'"
-msgstr "misslyckades hämta filen på URL \"%s\""
+msgstr "misslyckades hämta filen pÃ¥ URL â€%sâ€"
msgid "git-http-push failed"
msgstr "git-http-push misslyckades"
@@ -19015,11 +19728,11 @@ msgstr "remote-curl: försökte ta emot utan lokalt arkiv"
#, c-format
msgid "remote-curl: unknown command '%s' from git"
-msgstr "remote-curl: okänt kommando \"%s\" från git"
+msgstr "remote-curl: okänt kommando â€%s†frÃ¥n git"
#, c-format
msgid "config remote shorthand cannot begin with '/': %s"
-msgstr "konfigurerad kortform för fjärr kan inte börja med \"/\": %s"
+msgstr "konfigurerad kortform för fjärr kan inte börja med â€/â€: %s"
msgid "more than one receivepack given, using the first"
msgstr "mer än en receivepack angavs, använder den första"
@@ -19029,11 +19742,11 @@ msgstr "mer än en uploadpack angavs, använder den första"
#, c-format
msgid "unrecognized value transfer.credentialsInUrl: '%s'"
-msgstr "okänt värde transfer.credentialsInUrl: \"%s\""
+msgstr "okänt värde transfer.credentialsInUrl: â€%sâ€"
#, c-format
msgid "URL '%s' uses plaintext credentials"
-msgstr "URL \"%s\" använder inloggningsuppgifter i klartext"
+msgstr "URL â€%s†använder inloggningsuppgifter i klartext"
#, c-format
msgid "Cannot fetch both %s and %s to %s"
@@ -19049,11 +19762,11 @@ msgstr "%s spårar både %s och %s"
#, c-format
msgid "key '%s' of pattern had no '*'"
-msgstr "nyckeln \"%s\" i mönstret innehåller ingen \"*\""
+msgstr "nyckeln â€%s†i mönstret innehÃ¥ller ingen â€*â€"
#, c-format
msgid "value '%s' of pattern has no '*'"
-msgstr "värdet \"%s\" i mönstret innehåller ingen \"*\""
+msgstr "värdet â€%s†i mönstret innehÃ¥ller ingen â€*â€"
#, c-format
msgid "src refspec %s does not match any"
@@ -19080,12 +19793,12 @@ msgid ""
"Neither worked, so we gave up. You must fully qualify the ref."
msgstr ""
"Målet du angav är inte ett komplett referensamn (dvs.,\n"
-"startar med \"refs/\"). Vi försökte gissa vad du menade genom att:\n"
+"startar med â€refs/â€). Vi försökte gissa vad du menade genom att:\n"
"\n"
-"- Se efter en referens som motsvarar \"%s\" på fjärrsidan.\n"
-"- Se om <källan> som sänds (\"%s\")\n"
-" är en referens i \"refs/{heads,tags}/\". Om så lägger vi till\n"
-" motsvarande refs/{heads,tags}/-prefix på fjärrsidan.\n"
+"- Se efter en referens som motsvarar â€%s†pÃ¥ fjärrsidan.\n"
+"- Se om <källan> som sänds (â€%sâ€)\n"
+" är en referens i â€refs/{heads,tags}/â€. Om sÃ¥ lägger vi till\n"
+" motsvarande â€refs/{heads,tags}/â€-prefix pÃ¥ fjärrsidan.\n"
"\n"
"Inget av dem fungerade, så vi gav upp. Ange fullständig referens."
@@ -19097,7 +19810,7 @@ msgid ""
msgstr ""
"<Källa>-delen av ref.spec-en är ett incheckningsobjekt.\n"
"Var det meningen att skapa en ny gren genom att sända\n"
-"till \"%s:refs/heads/%s\"?"
+"till â€%s:refs/heads/%sâ€?"
#, c-format
msgid ""
@@ -19107,7 +19820,7 @@ msgid ""
msgstr ""
"<Källa>-delen av ref.spec-en är ett taggobjekt.\n"
"Var det meningen att skapa en ny tagg genom att sända\n"
-"till \"%s:refs/tags/%s\"?"
+"till â€%s:refs/tags/%sâ€?"
#, c-format
msgid ""
@@ -19117,7 +19830,7 @@ msgid ""
msgstr ""
"<Källa>-delen av ref.spec-en är ett trädobjekt.\n"
"Var det meningen att tagga ett nytt träd genom att sända\n"
-"till \"%s:refs/tags/%s\"?"
+"till â€%s:refs/tags/%sâ€?"
#, c-format
msgid ""
@@ -19127,7 +19840,7 @@ msgid ""
msgstr ""
"<Källa>-delen av ref.spec-en är ett blobobjekt.\n"
"Var det meningen att tagga en ny blob genom att sända\n"
-"till \"%s:refs/tags/%s\"?"
+"till â€%s:refs/tags/%sâ€?"
#, c-format
msgid "%s cannot be resolved to branch"
@@ -19135,96 +19848,96 @@ msgstr "%s kan inte slås upp till en gren"
#, c-format
msgid "unable to delete '%s': remote ref does not exist"
-msgstr "kan inte ta bort \"%s\": fjärreferensen finns inte"
+msgstr "kan inte ta bort â€%sâ€: fjärreferensen finns inte"
#, c-format
msgid "dst refspec %s matches more than one"
-msgstr "fjärr-referensspecifikationen \"%s\" motsvarar mer än en"
+msgstr "fjärr-referensspecifikationen â€%s†motsvarar mer än en"
#, c-format
msgid "dst ref %s receives from more than one src"
-msgstr "fjärr-referensen \"%s\" hämtar från mer än en källa"
+msgstr "fjärr-referensen â€%s†hämtar frÃ¥n mer än en källa"
msgid "HEAD does not point to a branch"
msgstr "HEAD pekar inte på en gren"
#, c-format
msgid "no such branch: '%s'"
-msgstr "okänd gren: \"%s\""
+msgstr "okänd gren: â€%sâ€"
#, c-format
msgid "no upstream configured for branch '%s'"
-msgstr "ingen standarduppström angiven för grenen \"%s\""
+msgstr "ingen standarduppström angiven för grenen â€%sâ€"
#, c-format
msgid "upstream branch '%s' not stored as a remote-tracking branch"
-msgstr "uppströmsgrenen \"%s\" är inte lagrad som en fjärrspårande gren"
+msgstr "uppströmsgrenen â€%s†är inte lagrad som en fjärrspÃ¥rande gren"
#, c-format
msgid "push destination '%s' on remote '%s' has no local tracking branch"
-msgstr "push-målet \"%s\" på fjärren \"%s\" har ingen lokalt spårande gren"
+msgstr "push-mÃ¥let â€%s†pÃ¥ fjärren â€%s†har ingen lokalt spÃ¥rande gren"
#, c-format
msgid "branch '%s' has no remote for pushing"
-msgstr "grenen \"%s\" har ingen fjärr för \"push\""
+msgstr "grenen â€%s†har ingen fjärr för â€pushâ€"
#, c-format
msgid "push refspecs for '%s' do not include '%s'"
-msgstr "\"push\"-referensspecifikation för \"%s\" innehåller inte \"%s\""
+msgstr "â€pushâ€-referensspecifikation för â€%s†innehÃ¥ller inte â€%sâ€"
msgid "push has no destination (push.default is 'nothing')"
-msgstr "\"push\" har inget mål (push.default är \"ingenting\")"
+msgstr "â€push†har inget mÃ¥l (push.default är â€ingentingâ€)"
msgid "cannot resolve 'simple' push to a single destination"
-msgstr "\"enkel push\" motsvarar flera olika mål"
+msgstr "â€enkel push†motsvarar flera olika mÃ¥l"
#, c-format
msgid "couldn't find remote ref %s"
-msgstr "Kunde inte hitta fjärr-referensen %s"
+msgstr "kunde inte hitta fjärr-referensen %s"
#, c-format
msgid "* Ignoring funny ref '%s' locally"
-msgstr "* Ignorerar märklig referens \"%s\" lokalt"
+msgstr "* Ignorerar märklig referens â€%s†lokalt"
#, c-format
msgid "Your branch is based on '%s', but the upstream is gone.\n"
-msgstr "Din gren är baserad på \"%s\", men den har försvunnit uppströms.\n"
+msgstr "Din gren är baserad pÃ¥ â€%sâ€, men den har försvunnit uppströms.\n"
msgid " (use \"git branch --unset-upstream\" to fixup)\n"
-msgstr " (använd \"git branch --unset-upstream\" för att rätta)\n"
+msgstr " (använd â€git branch --unset-upstream†för att rätta)\n"
#, c-format
msgid "Your branch is up to date with '%s'.\n"
-msgstr "Din gren är à jour med \"%s\".\n"
+msgstr "Din gren är à jour med â€%sâ€.\n"
#, c-format
msgid "Your branch and '%s' refer to different commits.\n"
-msgstr "Din gren och \"%s\" pekar på olika incheckningar.\n"
+msgstr "Din gren och â€%s†pekar pÃ¥ olika incheckningar.\n"
#, c-format
msgid " (use \"%s\" for details)\n"
-msgstr " (använd \"%s\" för detaljer)\n"
+msgstr " (använd â€%s†för detaljer)\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] "Din gren ligger före \"%s\" med %d incheckning.\n"
-msgstr[1] "Din gren ligger före \"%s\" med %d incheckningar.\n"
+msgstr[0] "Din gren ligger före â€%s†med %d incheckning.\n"
+msgstr[1] "Din gren ligger före â€%s†med %d incheckningar.\n"
msgid " (use \"git push\" to publish your local commits)\n"
-msgstr " (använd \"git push\" för att publicera dina lokala incheckningar)\n"
+msgstr " (använd â€git push†för att publicera dina lokala incheckningar)\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] ""
-"Din gren ligger efter \"%s\" med %d incheckning, och kan snabbspolas.\n"
+"Din gren ligger efter â€%s†med %d incheckning, och kan snabbspolas.\n"
msgstr[1] ""
-"Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n"
+"Din gren ligger efter â€%s†med %d incheckningar, och kan snabbspolas.\n"
msgid " (use \"git pull\" to update your local branch)\n"
-msgstr " (använd \"git pull\" för att uppdatera din lokala gren)\n"
+msgstr " (använd â€git pull†för att uppdatera din lokala gren)\n"
#, c-format
msgid ""
@@ -19234,24 +19947,23 @@ msgid_plural ""
"Your branch and '%s' have diverged,\n"
"and have %d and %d different commits each, respectively.\n"
msgstr[0] ""
-"Din gren och \"%s\" har divergerat,\n"
+"Din gren och â€%s†har divergerat,\n"
"och har %d respektive %d olika incheckning.\n"
msgstr[1] ""
-"Din gren och \"%s\" har divergerat,\n"
+"Din gren och â€%s†har divergerat,\n"
"och har %d respektive %d olika incheckningar.\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"
+msgstr " (använd â€git pull†om du vill integrera fjärrgrenen med din egen)\n"
#, c-format
msgid "cannot parse expected object name '%s'"
-msgstr "kan inte tolka förväntat objektnamn \"%s\""
+msgstr "kan inte tolka förväntat objektnamn â€%sâ€"
#, c-format
msgid "cannot strip one component off url '%s'"
-msgstr "kan inte ta bort en komponent från url:en \"%s\""
+msgstr "kan inte ta bort en komponent frÃ¥n url:en â€%sâ€"
#, c-format
msgid "bad replace ref name: %s"
@@ -19269,59 +19981,59 @@ msgid "corrupt MERGE_RR"
msgstr "trasig MERGE_RR"
msgid "unable to write rerere record"
-msgstr "kunde inte skriva rerere-post"
+msgstr "kan inte skriva rerere-post"
#, c-format
msgid "there were errors while writing '%s' (%s)"
-msgstr "fel vid skrivning av \"%s\" (%s)"
+msgstr "fel vid skrivning av â€%s†(%s)"
#, c-format
msgid "could not parse conflict hunks in '%s'"
-msgstr "kunde inte tolka konflikt-stycket i \"%s\""
+msgstr "kunde inte tolka konflikt-stycket i â€%sâ€"
#, c-format
msgid "failed utime() on '%s'"
-msgstr "\"utime()\" misslyckades på \"%s\""
+msgstr "â€utime()†misslyckades pÃ¥ â€%sâ€"
#, c-format
msgid "writing '%s' failed"
-msgstr "misslyckades skriva \"%s\""
+msgstr "misslyckades skriva â€%sâ€"
#, c-format
msgid "Staged '%s' using previous resolution."
-msgstr "Köade \"%s\" med sparad lösning."
+msgstr "Köade â€%s†med sparad lösning."
#, c-format
msgid "Recorded resolution for '%s'."
-msgstr "Sparade lösning för \"%s\"."
+msgstr "Sparade lösning för â€%sâ€."
#, c-format
msgid "Resolved '%s' using previous resolution."
-msgstr "Löste \"%s\" med tidigare lösning."
+msgstr "Löste â€%s†med tidigare lösning."
#, c-format
msgid "cannot unlink stray '%s'"
-msgstr "kan inte ta bort lös länk \"%s\""
+msgstr "kan inte ta bort lös länk â€%sâ€"
#, c-format
msgid "Recorded preimage for '%s'"
-msgstr "Sparade förhandsbild för \"%s\""
+msgstr "Sparade förhandsbild för â€%sâ€"
#, c-format
msgid "failed to update conflicted state in '%s'"
-msgstr "misslyckades uppdatera tillstånd för sammanslagningsproblem i \"%s\""
+msgstr "misslyckades uppdatera tillstÃ¥nd för sammanslagningsproblem i â€%sâ€"
#, c-format
msgid "no remembered resolution for '%s'"
-msgstr "inget sparat sammanslagningsresultat för \"%s\""
+msgstr "inget sparat sammanslagningsresultat för â€%sâ€"
#, c-format
msgid "Updated preimage for '%s'"
-msgstr "Uppdaterade förhandsbild för \"%s\""
+msgstr "Uppdaterade förhandsbild för â€%sâ€"
#, c-format
msgid "Forgot resolution for '%s'\n"
-msgstr "Glömde lösning för \"%s\"\n"
+msgstr "Glömde lösning för â€%sâ€\n"
msgid "unable to open rr-cache directory"
msgstr "kan inte uppdatera katalogen rr-cache"
@@ -19334,7 +20046,7 @@ msgstr "kunde inte bestämma HEAD-revision"
#, c-format
msgid "failed to find tree of %s"
-msgstr "kunde inte hitta trädet för %s."
+msgstr "misslyckades hitta trädet för %s."
#, c-format
msgid "unsupported section for hidden refs: %s"
@@ -19345,25 +20057,36 @@ msgstr "--exclude-hidden= angavs mer än en gång"
#, c-format
msgid "resolve-undo records `%s` which is missing"
-msgstr "resolve-undo registrerar \"%s\" som saknas"
+msgstr "resolve-undo registrerar â€%s†som saknas"
+
+#, c-format
+msgid "%s exists but is a symbolic ref"
+msgstr "%s finns men är en symbolisk referens"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge kräver en av pseudoreferenserna MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD eller REBASE_HEAD"
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "kunde inte hämta incheckning för \"ancestry-path\"-argumentet %s"
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "kunde inte hämta incheckning för â€--ancestry-pathâ€-argumentet %s"
msgid "--unpacked=<packfile> no longer supported"
msgstr "--unpacked=<paketfil> stöds inte längre"
#, c-format
msgid "invalid option '%s' in --stdin mode"
-msgstr "ogiltig flagga \"%s\" i --stdin-läge"
+msgstr "ogiltig flagga â€%s†i â€--stdinâ€-läge"
msgid "your current branch appears to be broken"
msgstr "din nuvarande gren verkar vara trasig"
#, c-format
msgid "your current branch '%s' does not have any commits yet"
-msgstr "din nuvarande gren \"%s\" innehåller ännu inte några incheckningar"
+msgstr "din nuvarande gren â€%s†innehÃ¥ller ännu inte nÃ¥gra incheckningar"
msgid "object filtering requires --objects"
msgstr "objektfiltrering kräver --objects"
@@ -19377,11 +20100,11 @@ msgstr "kan inte skapa asynkron tråd: %s"
#, c-format
msgid "'%s' does not exist"
-msgstr "\"%s\" finns inte"
+msgstr "â€%s†finns inte"
#, c-format
msgid "could not switch to '%s'"
-msgstr "kunde inte växla till \"%s\""
+msgstr "kunde inte växla till â€%sâ€"
msgid "need a working directory"
msgstr "behöver en arbetskatalog"
@@ -19416,7 +20139,7 @@ msgstr "kunde inte ta bort enrollering"
#, c-format
msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "HEAD hos fjärren är inte en gren: \"%.*s\""
+msgstr "HEAD hos fjärren är inte en gren: â€%.*sâ€"
msgid "failed to get default branch name from remote; using local default"
msgstr ""
@@ -19443,28 +20166,42 @@ msgstr "skapa komplett arbetskatalog vid kloning"
msgid "only download metadata for the branch that will be checked out"
msgstr "hämta endast metadata för grenen som skall checkas ut"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<flaggor>] [--] <arkiv> [<kat>]"
+msgid "create repository within 'src' directory"
+msgstr "skapa arkiv inuti katalogen â€srcâ€"
+
+msgid "specify if tags should be fetched during clone"
+msgstr "ange om taggar ska hämtas vid kloning"
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <huvudgren>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enrollering>]"
#, c-format
msgid "cannot deduce worktree name from '%s'"
-msgstr "Kan inte härleda arbetsträdsnamn från \"%s\""
+msgstr "Kan inte härleda arbetsträdsnamn frÃ¥n â€%sâ€"
#, c-format
msgid "directory '%s' exists already"
-msgstr "katalogen \"%s\" finns redan"
+msgstr "katalogen â€%s†finns redan"
#, c-format
msgid "failed to get default branch for '%s'"
-msgstr "misslyckades hämta standardgren för \"%s\""
+msgstr "misslyckades hämta standardgren för â€%sâ€"
#, c-format
msgid "could not configure remote in '%s'"
-msgstr "kunde inte ställa in fjärr i \"%s\""
+msgstr "kunde inte ställa in fjärr i â€%sâ€"
+
+#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "kunde inte inaktivera taggar i â€%sâ€"
#, c-format
msgid "could not configure '%s'"
-msgstr "kunde inte ställa in \"%s\""
+msgstr "kunde inte ställa in â€%sâ€"
msgid "partial clone failed; attempting full clone"
msgstr "delvis klon misslyckades; försöker med fullständig klon"
@@ -19476,7 +20213,7 @@ msgid "scalar diagnose [<enlistment>]"
msgstr "scalar diagnose [<enrollering>]"
msgid "`scalar list` does not take arguments"
-msgstr "\"scalar list\" tar inte argument"
+msgstr "â€scalar list†tar inte argument"
msgid "scalar register [<enlistment>]"
msgstr "scalar register [<enrollering>]"
@@ -19492,15 +20229,31 @@ msgstr "--all eller <enrollering>, men inte bägge"
#, c-format
msgid "could not remove stale scalar.repo '%s'"
-msgstr "kunde inte ta bort gammal scalar.repo \"%s\""
+msgstr "kunde inte ta bort gammal scalar.repo â€%sâ€"
+
+#, c-format
+msgid "removed stale scalar.repo '%s'"
+msgstr "tog bort gammal scalar.repo â€%sâ€"
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "tar bort gammal scalar.repo \"%s\""
+msgid "repository at '%s' has different owner"
+msgstr "arkivet â€%s†har en annan ägare"
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git-arkiv försvunnet i \"%s\""
+msgid "repository at '%s' has a format issue"
+msgstr "arkivet â€%s†har ett formatproblem"
+
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "arkivet hittades inte i â€%sâ€"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"för att avregistrera arkivet från Scalar, kör\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
msgid ""
"scalar run <task> [<enlistment>]\n"
@@ -19511,7 +20264,7 @@ msgstr ""
#, c-format
msgid "no such task: '%s'"
-msgstr "okänd uppgift: \"%s\""
+msgstr "okänd uppgift: â€%sâ€"
msgid "scalar unregister [<enlistment>]"
msgstr "scalar unregister [<enrollering>]"
@@ -19536,7 +20289,7 @@ msgstr "-C kräver en <katalog>"
#, c-format
msgid "could not change to '%s'"
-msgstr "kunde inte byta till \"%s\""
+msgstr "kunde inte byta till â€%sâ€"
msgid "-c requires a <key>=<value> argument"
msgstr "-c kräver ett argument på formen <nyckel>=<värde>"
@@ -19555,7 +20308,7 @@ msgstr "oväntat flush-paket vid läsning av fjärruppackningsstatus"
#, c-format
msgid "unable to parse remote unpack status: %s"
-msgstr "kunde inte tolka fjärruppackningsstatus: %s"
+msgstr "kan inte tolka fjärruppackningsstatus: %s"
#, c-format
msgid "remote unpack failed: %s"
@@ -19565,7 +20318,7 @@ msgid "failed to sign the push certificate"
msgstr "misslyckades underteckna push-certifikatet"
msgid "send-pack: unable to fork off fetch subprocess"
-msgstr "send-pack: kunde inte starta (fork) underprocessen för fetch"
+msgstr "send-pack: kan inte grena (fork) av underprocessen för fetch"
msgid "push negotiation failed; proceeding anyway with push"
msgstr "sänd-förhandling misslyckades; fortsätter ändå med sändningen"
@@ -19591,11 +20344,11 @@ msgstr "mottagarsidan stöder inte push-flaggor"
#, c-format
msgid "invalid commit message cleanup mode '%s'"
-msgstr "felaktigt incheckningsmeddelandestädningsläge \"%s\""
+msgstr "felaktigt incheckningsmeddelandestädningsläge â€%sâ€"
#, c-format
msgid "could not delete '%s'"
-msgstr "kunde inte ta bort \"%s\""
+msgstr "kunde inte ta bort â€%sâ€"
msgid "revert"
msgstr "revert"
@@ -19611,11 +20364,24 @@ msgid "unknown action: %d"
msgstr "okänd funktion: %d"
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 ""
+"Lös alla konflikter manuellt, märk dem som lösta med\n"
+"â€git add/rm <filer_i_konflikt>â€, kör sedan â€git rebase --continueâ€.\n"
+"Du kan hoppa över incheckningen istället: kör â€git rebase --skipâ€.\n"
+"För att avbryta och Ã¥tergÃ¥ till där du var före ombaseringen, kör â€git "
+"rebase --abortâ€."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
"efter att ha löst konflikterna, markera de rättade sökvägarna\n"
-"med \"git add <sökvägar>\" eller \"git rm <sökvägar>\""
+"med â€git add <sökvägar>†eller â€git rm <sökvägar>â€"
msgid ""
"After resolving the conflicts, mark them with\n"
@@ -19626,11 +20392,11 @@ msgid ""
"run \"git cherry-pick --abort\"."
msgstr ""
"Efter att ha löst konflikterna, märk dem med\n"
-"\"git add/rm <sökvägsangivelse>\" och kör sedan\n"
-"\"git cherry-pick --continue\".\n"
-"Du kan hoppa över incheckningen istället med \"git cherry-pick --skip\"\n"
-"För att avbryta och återgå till där du var före \"git cherry-pick\",\n"
-"kör \"git cherry-pick --abort\"."
+"â€git add/rm <sökvägsangivelse>†och kör sedan\n"
+"â€git cherry-pick --continueâ€.\n"
+"Du kan hoppa över incheckningen istället med â€git cherry-pick --skipâ€\n"
+"För att avbryta och Ã¥tergÃ¥ till där du var före â€git cherry-pickâ€,\n"
+"kör â€git cherry-pick --abortâ€."
msgid ""
"After resolving the conflicts, mark them with\n"
@@ -19641,30 +20407,30 @@ msgid ""
"run \"git revert --abort\"."
msgstr ""
"Efter att ha löst konflikterna, märk dem med\n"
-"\"git add/rm <sökvägsangivelse>\" och kör sedan\n"
-"\"git revert --continue\".\n"
-"Du kan hoppa över incheckningen istället med \"git revert --skip\"\n"
-"För att avbryta och återgå till där du var före \"git revert\",\n"
-"kör \"git revert --abort\"."
+"â€git add/rm <sökvägsangivelse>†och kör sedan\n"
+"â€git revert --continueâ€.\n"
+"Du kan hoppa över incheckningen istället med â€git revert --skipâ€\n"
+"För att avbryta och Ã¥tergÃ¥ till där du var före â€git revertâ€,\n"
+"kör â€git revert --abortâ€."
#, c-format
msgid "could not lock '%s'"
-msgstr "kunde inte låsa \"%s\""
+msgstr "kunde inte lÃ¥sa â€%sâ€"
#, c-format
msgid "could not write eol to '%s'"
-msgstr "kunde inte skriva radslut till \"%s\""
+msgstr "kunde inte skriva radslut till â€%sâ€"
#, c-format
msgid "failed to finalize '%s'"
-msgstr "misslyckades färdigställa \"%s\""
+msgstr "misslyckades färdigställa â€%sâ€"
#, c-format
msgid "your local changes would be overwritten by %s."
msgstr "dina lokala ändringar skulle skrivas över av %s."
msgid "commit your changes or stash them to proceed."
-msgstr "checka in dina ändringar eller använd \"stash\" för att fortsätta."
+msgstr "checka in dina ändringar eller använd â€stash†för att fortsätta."
#. TRANSLATORS: %s will be "revert", "cherry-pick" or
#. "rebase".
@@ -19681,33 +20447,33 @@ msgstr "kunde inte bestämma HEAD:s incheckning"
#, c-format
msgid "no key present in '%.*s'"
-msgstr "ingen nyckel i \"%.*s\""
+msgstr "ingen nyckel i â€%.*sâ€"
#, c-format
msgid "unable to dequote value of '%s'"
-msgstr "kan inte ta bort citering av värdet \"%s\""
+msgstr "kan inte ta bort citering av värdet â€%sâ€"
msgid "'GIT_AUTHOR_NAME' already given"
-msgstr "\"GIT_AUTHOR_NAME\" har redan angivits"
+msgstr "â€GIT_AUTHOR_NAME†har redan angivits"
msgid "'GIT_AUTHOR_EMAIL' already given"
-msgstr "\"GIT_AUTHOR_EMAIL\" har redan angivits"
+msgstr "â€GIT_AUTHOR_EMAIL†har redan angivits"
msgid "'GIT_AUTHOR_DATE' already given"
-msgstr "\"GIT_AUTHOR_DATE\" har redan angivits"
+msgstr "â€GIT_AUTHOR_DATE†har redan angivits"
#, c-format
msgid "unknown variable '%s'"
-msgstr "okänd variabel \"%s\""
+msgstr "okänd variabel â€%sâ€"
msgid "missing 'GIT_AUTHOR_NAME'"
-msgstr "\"GIT_AUTHOR_NAME\" saknas"
+msgstr "â€GIT_AUTHOR_NAME†saknas"
msgid "missing 'GIT_AUTHOR_EMAIL'"
-msgstr "\"GIT_AUTHOR_EMAIL\" saknas"
+msgstr "â€GIT_AUTHOR_EMAIL†saknas"
msgid "missing 'GIT_AUTHOR_DATE'"
-msgstr "\"GIT_AUTHOR_DATE\" saknas"
+msgstr "â€GIT_AUTHOR_DATE†saknas"
#, c-format
msgid ""
@@ -19738,7 +20504,7 @@ msgstr ""
" git rebase --continue\n"
msgid "'prepare-commit-msg' hook failed"
-msgstr "kroken \"prepare-commit-msg\" misslyckades"
+msgstr "kroken â€prepare-commit-msg†misslyckades"
msgid ""
"Your name and email address were configured automatically based\n"
@@ -19797,7 +20563,7 @@ msgid "could not parse newly created commit"
msgstr "kunde inte tolka en precis skapad incheckning"
msgid "unable to resolve HEAD after creating commit"
-msgstr "kunde inte bestämma HEAD efter att ha skapat incheckning"
+msgstr "kan inte bestämma HEAD efter att ha skapat incheckning"
msgid "detached HEAD"
msgstr "frånkopplad HEAD"
@@ -19813,15 +20579,15 @@ msgid "HEAD %s is not a commit!"
msgstr "HEAD %s är inte en incheckning!"
msgid "unable to parse commit author"
-msgstr "kunde inte tolka incheckningens författare"
+msgstr "kan inte tolka incheckningens författare"
#, c-format
msgid "unable to read commit message from '%s'"
-msgstr "kunde inte läsa incheckningsmeddelande från \"%s\""
+msgstr "kan inte läsa incheckningsmeddelande frÃ¥n â€%sâ€"
#, c-format
msgid "invalid author identity '%s'"
-msgstr "ogiltig författar-identitet \"%s\""
+msgstr "ogiltig författar-identitet â€%sâ€"
msgid "corrupt author: missing date information"
msgstr "trasig författare: saknar datuminformation"
@@ -19831,10 +20597,6 @@ msgid "could not update %s"
msgstr "kunde inte uppdatera %s"
#, c-format
-msgid "could not parse commit %s"
-msgstr "kunde inte tolka incheckningen %s"
-
-#, c-format
msgid "could not parse parent commit %s"
msgstr "kunde inte tolka föräldraincheckningen %s"
@@ -19862,7 +20624,7 @@ msgstr "Det här är en kombination av %d incheckningar."
#, c-format
msgid "cannot write '%s'"
-msgstr "kan inte skriva \"%s\""
+msgstr "kan inte skriva â€%sâ€"
msgid "need a HEAD to fixup"
msgstr "behöver en HEAD-incheckning att rätta"
@@ -19881,7 +20643,7 @@ msgid "your index file is unmerged."
msgstr "din indexfil har inte slagits ihop."
msgid "cannot fixup root commit"
-msgstr "kan inte göra \"fixup\" på rotincheckning"
+msgstr "kan inte göra â€fixup†pÃ¥ rotincheckning"
#, c-format
msgid "commit %s is a merge but no -m option was given."
@@ -19902,10 +20664,6 @@ msgid "%s: cannot parse parent commit %s"
msgstr "%s: kan inte tolka föräldraincheckningen %s"
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "kunde inte byta namn på \"%s\" till \"%s\""
-
-#, c-format
msgid "could not revert %s... %s"
msgstr "kunde inte ångra %s... %s"
@@ -19927,23 +20685,66 @@ msgstr "git %s: misslyckades uppdatera indexet"
#, c-format
msgid "'%s' is not a valid label"
-msgstr "\"%s\" är inte en giltig etikett"
+msgstr "â€%s†är inte en giltig etikett"
#, c-format
msgid "'%s' is not a valid refname"
-msgstr "\"%s\" är inte ett giltigt referensnamn"
+msgstr "â€%s†är inte ett giltigt referensnamn"
#, c-format
msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
msgstr "update-ref kräver ett fullständigt referensnamn, t.ex refs/heads/%s"
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "ogiltigt kommando \"%.*s\""
+msgid "'%s' does not accept merge commits"
+msgstr "â€%s†godtar inte sammanslagningsincheckningar"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"â€pick†tar inte en sammanslagningsincheckning. Om du\n"
+"ville spela upp sammanslagningen på nytt använder du\n"
+"â€merge -C†pÃ¥ incheckningen."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"â€reword†tar inte en sammanslagningsincheckning. Om du\n"
+"ville spela upp sammanslagningen på nytt och ändra texten\n"
+"i incheckningsmeddelandet använder du â€merge -C†pÃ¥\n"
+"incheckningen"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"â€edit†tar inte en sammanslagningsincheckning. Om du\n"
+"ville spela upp sammanslagningen på nytt använder du\n"
+"â€merge -C†pÃ¥ incheckningen och sedan â€break†för att\n"
+"lämna kontrollen tillbaka till dig så att du kan\n"
+"använda â€git commit --amend && git rebase --continueâ€."
+
+msgid "cannot squash merge commit into another commit"
+msgstr ""
+"kan inte slå ihop en sammanslagningsincheckning med en annan incheckning"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s tar inte argument: \"%s\""
+msgid "invalid command '%.*s'"
+msgstr "ogiltigt kommando â€%.*sâ€"
#, c-format
msgid "missing arguments for %s"
@@ -19951,7 +20752,7 @@ msgstr "argument saknas för %s"
#, c-format
msgid "could not parse '%s'"
-msgstr "kunde inte tolka \"%s\""
+msgstr "kunde inte tolka â€%sâ€"
#, c-format
msgid "invalid line %d: %.*s"
@@ -19959,60 +20760,60 @@ msgstr "ogiltig rad %d: %.*s"
#, c-format
msgid "cannot '%s' without a previous commit"
-msgstr "kan inte utföra \"%s\" utan en föregående incheckning"
+msgstr "kan inte utföra â€%s†utan en föregÃ¥ende incheckning"
msgid "cancelling a cherry picking in progress"
-msgstr "avbryter pågående \"cherry-pick\""
+msgstr "avbryter pÃ¥gÃ¥ende â€cherry-pickâ€"
msgid "cancelling a revert in progress"
-msgstr "avbryter pågående \"revert\""
+msgstr "avbryter pÃ¥gÃ¥ende â€revertâ€"
msgid "please fix this using 'git rebase --edit-todo'."
-msgstr "rätta det med \"git rebase --edit-todo\"."
+msgstr "rätta det med â€git rebase --edit-todoâ€."
#, c-format
msgid "unusable instruction sheet: '%s'"
-msgstr "oanvändbart manus: \"%s\""
+msgstr "oanvändbart manus: â€%sâ€"
msgid "no commits parsed."
msgstr "inga incheckningar lästes."
msgid "cannot cherry-pick during a revert."
-msgstr "kan inte utföra \"cherry-pick\" under en \"revert\"."
+msgstr "kan inte utföra â€cherry-pick†under en â€revertâ€."
msgid "cannot revert during a cherry-pick."
-msgstr "kan inte utföra \"revert\" under en \"cherry-pick\"."
+msgstr "kan inte utföra â€revert†under en â€cherry-pickâ€."
msgid "unusable squash-onto"
msgstr "oanvändbar squash-onto"
#, c-format
msgid "malformed options sheet: '%s'"
-msgstr "trasigt manus: \"%s\""
+msgstr "trasigt manus: â€%sâ€"
msgid "empty commit set passed"
msgstr "den angivna uppsättningen incheckningar är tom"
msgid "revert is already in progress"
-msgstr "en \"revert\" pågår redan"
+msgstr "en â€revert†pÃ¥gÃ¥r redan"
#, c-format
msgid "try \"git revert (--continue | %s--abort | --quit)\""
-msgstr "testa \"git revert (--continue | %s--abort | --quit)\""
+msgstr "testa â€git revert (--continue | %s--abort | --quit)â€"
msgid "cherry-pick is already in progress"
-msgstr "en \"cherry-pick\" pågår redan"
+msgstr "en â€cherry-pick†pÃ¥gÃ¥r redan"
#, c-format
msgid "try \"git cherry-pick (--continue | %s--abort | --quit)\""
-msgstr "testa \"git cherry-pick (--continue | %s--abort | --quit)\""
+msgstr "testa â€git cherry-pick (--continue | %s--abort | --quit)â€"
#, c-format
msgid "could not create sequencer directory '%s'"
-msgstr "kunde inte skapa \"sequencer\"-katalogen \"%s\""
+msgstr "kunde inte skapa â€sequencerâ€-katalogen â€%sâ€"
msgid "no cherry-pick or revert in progress"
-msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
+msgstr "ingen â€cherry-pick†eller â€revert†pÃ¥gÃ¥r"
msgid "cannot resolve HEAD"
msgstr "kan inte bestämma HEAD"
@@ -20022,14 +20823,14 @@ msgstr "kan inte avbryta från en gren som ännu inte är född"
#, c-format
msgid "cannot read '%s': %s"
-msgstr "kan inte läsa \"%s\": %s"
+msgstr "kan inte läsa â€%sâ€: %s"
msgid "unexpected end of file"
msgstr "oväntat filslut"
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
-msgstr "sparad HEAD-fil från före \"cherry-pick\", \"%s\", är trasig"
+msgstr "sparad HEAD-fil frÃ¥n före â€cherry-pickâ€, â€%sâ€, är trasig"
msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
msgstr ""
@@ -20037,13 +20838,13 @@ msgstr ""
"Spolar inte tillbaka, kontrollera HEAD!"
msgid "no revert in progress"
-msgstr "ingen \"revers\" pågår"
+msgstr "ingen â€revert†pÃ¥gÃ¥r"
msgid "no cherry-pick in progress"
-msgstr "ingen \"cherry-pick\" pågår"
+msgstr "ingen â€cherry-pick†pÃ¥gÃ¥r"
msgid "failed to skip the commit"
-msgstr "kunde inte hoppa över incheckningen"
+msgstr "misslyckades hoppa över incheckningen"
msgid "there is nothing to skip"
msgstr "ingenting att hoppa över"
@@ -20054,14 +20855,13 @@ msgid ""
"try \"git %s --continue\""
msgstr ""
"har du redan checkat in?\n"
-"testa \"git %s --continue\""
+"testa â€git %s --continueâ€"
msgid "cannot read HEAD"
msgstr "kan inte läsa HEAD"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "kan inte kopiera in \"%s\" till \"%s\""
+msgid "could not write commit message file"
+msgstr "kunde inte skriva fil för incheckningsmeddelande"
#, c-format
msgid ""
@@ -20121,18 +20921,18 @@ msgid ""
msgstr ""
"körningen lyckades: %s\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"
+"Checka in eller utför â€stash†pÃ¥ ändringarna och kör sedan\n"
"\n"
"\tgit rebase --continue\n"
"\n"
#, c-format
msgid "illegal label name: '%.*s'"
-msgstr "ogiltigt etikettnamn: \"%.*s\""
+msgstr "ogiltigt etikettnamn: â€%.*sâ€"
#, c-format
msgid "could not resolve '%s'"
-msgstr "kunde inte upplösa \"%s\""
+msgstr "kunde inte upplösa â€%sâ€"
msgid "writing fake root commit"
msgstr "skriver fejkad rotincheckning"
@@ -20145,22 +20945,22 @@ msgstr "kan inte slå ihop utan en aktuell incheckning"
#, c-format
msgid "unable to parse '%.*s'"
-msgstr "kan inte tolka \"%.*s\""
+msgstr "kan inte tolka â€%.*sâ€"
#, c-format
msgid "nothing to merge: '%.*s'"
-msgstr "inget att slå samman: \"%.*s\""
+msgstr "inget att slÃ¥ samman: â€%.*sâ€"
msgid "octopus merge cannot be executed on top of a [new root]"
-msgstr "\"octopus\"-sammanslagning kan inte köras ovanpå en [ny rot]"
+msgstr "â€octopusâ€-sammanslagning kan inte köras ovanpÃ¥ en [ny rot]"
#, c-format
msgid "could not get commit message of '%s'"
-msgstr "kunde inte läsa incheckningsmeddelande för \"%s\""
+msgstr "kunde inte läsa incheckningsmeddelande för â€%sâ€"
#, c-format
msgid "could not even attempt to merge '%.*s'"
-msgstr "kunde inte ens försöka slå ihop \"%.*s\""
+msgstr "kunde inte ens försöka slÃ¥ ihop â€%.*sâ€"
msgid "merge: Unable to write new index file"
msgstr "sammanslagning: Kunde inte skriva ny indexfil"
@@ -20168,7 +20968,7 @@ msgstr "sammanslagning: Kunde inte skriva ny indexfil"
#, c-format
msgid ""
"another 'rebase' process appears to be running; '%s.lock' already exists"
-msgstr "en annan \"rebase\"-process verkar vara aktiv; \"%s.lock\" finns redan"
+msgstr "en annan â€rebaseâ€-process verkar vara aktiv; â€%s.lock†finns redan"
#, c-format
msgid ""
@@ -20187,22 +20987,22 @@ msgstr ""
"%s"
msgid "Cannot autostash"
-msgstr "Kan inte utföra \"autostash\""
+msgstr "Kan inte utföra â€autostashâ€"
#, c-format
msgid "Unexpected stash response: '%s'"
-msgstr "Oväntat svar från stash: \"%s\""
+msgstr "Oväntat svar frÃ¥n stash: â€%sâ€"
#, c-format
msgid "Could not create directory for '%s'"
-msgstr "Kunde inte skapa katalog för \"%s\""
+msgstr "Kunde inte skapa katalog för â€%sâ€"
#, c-format
msgid "Created autostash: %s\n"
msgstr "Skapade autostash: %s\n"
msgid "could not reset --hard"
-msgstr "kunde inte utföra \"reset --hard\""
+msgstr "kunde inte utföra â€reset --hardâ€"
#, c-format
msgid "Applied autostash.\n"
@@ -20220,7 +21020,7 @@ msgid ""
msgstr ""
"%s\n"
"Dina ändringar är säkra i stashen.\n"
-"Du kan när som helst använda \"git stash pop\" eller \"git stash drop\".\n"
+"Du kan när som helst använda â€git stash pop†eller â€git stash dropâ€.\n"
msgid "Applying autostash resulted in conflicts."
msgstr "Tillämpning av autostash gav konflikter."
@@ -20228,6 +21028,9 @@ msgstr "Tillämpning av autostash gav konflikter."
msgid "Autostash exists; creating a new stash entry."
msgstr "Autostash finns; skapar ny stash-post."
+msgid "autostash reference is a symref"
+msgstr "autostash-referensen är en symbolisk referens"
+
msgid "could not detach HEAD"
msgstr "kunde inte koppla från HEAD"
@@ -20260,14 +21063,14 @@ msgstr ""
" git rebase --continue\n"
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "Ombaserar (%d/%d)%s"
-
-#, c-format
msgid "Stopped at %s... %.*s\n"
msgstr "Stoppade på %s... %.*s\n"
#, c-format
+msgid "Rebasing (%d/%d)%s"
+msgstr "Ombaserar (%d/%d)%s"
+
+#, c-format
msgid "unknown command %d"
msgstr "okänt kommando %d"
@@ -20275,7 +21078,7 @@ msgid "could not read orig-head"
msgstr "kunde inte läsa orig-head"
msgid "could not read 'onto'"
-msgstr "kunde inte läsa \"onto\""
+msgstr "kunde inte läsa â€ontoâ€"
#, c-format
msgid "could not update HEAD to %s"
@@ -20293,11 +21096,11 @@ msgstr "kan inte lägga till incheckning som inte finns"
#, c-format
msgid "invalid file: '%s'"
-msgstr "ogiltig fil: \"%s\""
+msgstr "ogiltig fil: â€%sâ€"
#, c-format
msgid "invalid contents: '%s'"
-msgstr "ogiltigt innehåll: \"%s\""
+msgstr "ogiltigt innehÃ¥ll: â€%sâ€"
msgid ""
"\n"
@@ -20306,11 +21109,11 @@ msgid ""
msgstr ""
"\n"
"Du har ändringar i arbetskatalogen som inte checkats in. Checka in dem\n"
-"först och kör sedan \"git rebase --continue\" igen."
+"först och kör sedan â€git rebase --continue†igen."
#, c-format
msgid "could not write file: '%s'"
-msgstr "kunde inte skriva fil: \"%s\""
+msgstr "kunde inte skriva fil: â€%sâ€"
msgid "could not remove CHERRY_PICK_HEAD"
msgstr "kunde inte ta bort CHERRY_PICK_HEAD"
@@ -20320,7 +21123,7 @@ msgstr "kunde inte checka in köade ändringar."
#, c-format
msgid "%s: can't cherry-pick a %s"
-msgstr "%s: kan inte göra \"cherry-pick\" på typen \"%s\""
+msgstr "%s: kan inte göra â€cherry-pick†pÃ¥ typen â€%sâ€"
#, c-format
msgid "%s: bad revision"
@@ -20346,18 +21149,18 @@ msgid "nothing to do"
msgstr "inget att göra"
msgid "could not skip unnecessary pick commands"
-msgstr "kunde inte hoppa över onödiga \"pick\"-kommandon"
+msgstr "kunde inte hoppa över onödiga â€pickâ€-kommandon"
msgid "the script was already rearranged."
msgstr "skriptet har redan omordnats."
#, c-format
msgid "update-refs file at '%s' is invalid"
-msgstr "update-refs-filen vid \"%s\" är ogiltig"
+msgstr "update-refs-filen vid â€%s†är ogiltig"
#, c-format
msgid "'%s' is outside repository at '%s'"
-msgstr "\"%s\" är utanför arkivet på \"%s\""
+msgstr "â€%s†är utanför arkivet pÃ¥ â€%sâ€"
#, c-format
msgid ""
@@ -20365,7 +21168,7 @@ msgid ""
"Use 'git <command> -- <path>...' to specify paths that do not exist locally."
msgstr ""
"%s: sökvägen finns inte i arbetskatalogen.\n"
-"Använd \"git <kommando> -- <sökväg>..\" för att ange sökvägar som inte finns "
+"Använd â€git <kommando> -- <sökväg>..†för att ange sökvägar som inte finns "
"lokalt."
#, c-format
@@ -20374,14 +21177,14 @@ msgid ""
"Use '--' to separate paths from revisions, like this:\n"
"'git <command> [<revision>...] -- [<file>...]'"
msgstr ""
-"tvetydigt argument \"%s\": okänd revision eller sökväg inte i "
+"tvetydigt argument â€%sâ€: okänd revision eller sökväg inte i "
"arbetskatalogen.\n"
-"Använd \"--\" för att skilja sökvägar från revisioner, så här:\n"
-"\"git <kommando> [<revision>...] -- [<fil>...]\""
+"Använd â€--†för att skilja sökvägar frÃ¥n revisioner, sÃ¥ här:\n"
+"â€git <kommando> [<revision>...] -- [<fil>...]â€"
#, c-format
msgid "option '%s' must come before non-option arguments"
-msgstr "flaggan \"%s\" måste anges före argument som inte är flaggor"
+msgstr "flaggan â€%s†mÃ¥ste anges före argument som inte är flaggor"
#, c-format
msgid ""
@@ -20389,14 +21192,18 @@ msgid ""
"Use '--' to separate paths from revisions, like this:\n"
"'git <command> [<revision>...] -- [<file>...]'"
msgstr ""
-"tvetydigt argument \"%s\": både revision och filnamn\n"
-"Använd \"--\" för att skilja sökvägar från revisioner, så här:\n"
-"\"git <kommando> [<revision>...] -- [<fil>...]\""
+"tvetydigt argument â€%sâ€: bÃ¥de revision och filnamn\n"
+"Använd â€--†för att skilja sökvägar frÃ¥n revisioner, sÃ¥ här:\n"
+"â€git <kommando> [<revision>...] -- [<fil>...]â€"
msgid "unable to set up work tree using invalid config"
msgstr "kan inte skapa arbetskatalog med felaktig konfiguration"
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "â€%s†har redan angivits som â€%sâ€"
+
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "Förväntade git-arkivversion <= %d, hittade %d"
@@ -20412,11 +21219,11 @@ msgstr[1] "arkivversionen är 0, men utökningar som bara finns i v1 upptäcktes
#, c-format
msgid "error opening '%s'"
-msgstr "fel vid öppning av \"%s\""
+msgstr "fel vid öppning av â€%sâ€"
#, c-format
msgid "too large to be a .git file: '%s'"
-msgstr "för stor för att vara en .git-fil: \"%s\""
+msgstr "för stor för att vara en .git-fil: â€%sâ€"
#, c-format
msgid "error reading %s"
@@ -20436,29 +21243,45 @@ msgstr "inte ett git-arkiv: %s"
#, c-format
msgid "'$%s' too big"
-msgstr "\"$%s\" för stor"
+msgstr "â€$%s†för stor"
#, c-format
msgid "not a git repository: '%s'"
-msgstr "inte ett git-arkiv: \"%s\""
+msgstr "inte ett git-arkiv: â€%sâ€"
#, c-format
msgid "cannot chdir to '%s'"
-msgstr "kan inte byta katalog (chdir) till \"%s\""
+msgstr "kan inte byta katalog (chdir) till â€%sâ€"
msgid "cannot come back to cwd"
msgstr "kan inte gå tillbaka till arbetskatalogen (cwd)"
#, c-format
msgid "failed to stat '%*s%s%s'"
-msgstr "misslyckades ta status på \"%*ss%s%s\""
+msgstr "misslyckades ta status pÃ¥ â€%*ss%s%sâ€"
+
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory â€%s†är inte absolut"
+
+#, 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 ""
+"upptäckte tveksamt ägarskap i arkivet i â€%sâ€\n"
+"%sFör att lägga till ett undantag för denna katalog, kör:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
msgid "Unable to read current working directory"
msgstr "Kan inte läsa aktuell arbetskatalog"
#, c-format
msgid "cannot change to '%s'"
-msgstr "kan inte byta till \"%s\""
+msgstr "kan inte byta till â€%sâ€"
#, c-format
msgid "not a git repository (or any of the parent directories): %s"
@@ -20474,20 +21297,8 @@ msgstr ""
"Stoppar vid filsystemsgräns (GIT_DISCOVERY_ACROSS_FILESYSTEM är inte satt)."
#, 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 ""
-"upptäckte tveksamt ägarskap i arkivet i \"%s\"\n"
-"%sFör att lägga till ett undantag för denna katalog, kör:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-
-#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
-msgstr "kan inte använda naket arkiv \"%s\" (safe.bareRepository är \"%s\")"
+msgstr "kan inte använda naket arkiv â€%s†(safe.bareRepository är â€%sâ€)"
#, c-format
msgid ""
@@ -20498,30 +21309,30 @@ msgstr ""
"Ägaren av filerna måste alltid ha läs- och skrivbehörighet."
msgid "fork failed"
-msgstr "\"fork\" misslyckades"
+msgstr "â€fork†misslyckades"
msgid "setsid failed"
-msgstr "\"setsid\" misslyckades"
+msgstr "â€setsid†misslyckades"
#, c-format
msgid "cannot stat template '%s'"
-msgstr "kan inte ta status på mallen \"%s\""
+msgstr "kan inte ta status pÃ¥ mallen â€%sâ€"
#, c-format
msgid "cannot opendir '%s'"
-msgstr "kan inte öppna katalogen (opendir) \"%s\""
+msgstr "kan inte öppna katalogen (opendir) â€%sâ€"
#, c-format
msgid "cannot readlink '%s'"
-msgstr "kan inte läsa länk (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\""
+msgstr "kan inte skapa symbolisk länk â€%s†â€%sâ€"
#, c-format
msgid "cannot copy '%s' to '%s'"
-msgstr "kan inte kopiera \"%s\" till \"%s\""
+msgstr "kan inte kopiera â€%s†till â€%sâ€"
#, c-format
msgid "ignoring template %s"
@@ -20533,11 +21344,15 @@ msgstr "mallarna hittades inte i %s"
#, c-format
msgid "not copying templates from '%s': %s"
-msgstr "kopierade inte mallar från \"%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\""
+msgstr "ogiltigt namn pÃ¥ första gren: â€%sâ€"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: ignorerade --initial-branch=%s"
#, c-format
msgid "unable to handle file type %d"
@@ -20550,15 +21365,15 @@ 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"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr "försöker initiera arkivet på nytt med annat referenslagringsformat"
+
#, 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"
@@ -20581,6 +21396,21 @@ msgstr "indexposten är en katalog, men inte gles (%08x)"
msgid "cannot use split index with a sparse index"
msgstr "kan inte dela indexet med ett glest index"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "felaktigt %s-format: elementet â€%s†börjar inte med â€(â€"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "felaktigt %s-format: elementet â€%s†slutar inte med â€)â€"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "felaktigt %s-format: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
msgid "%u.%2.2u GiB"
@@ -20634,15 +21464,15 @@ msgstr "negativa värden är inte tillåtna för submodule.fetchJobs"
#, c-format
msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
-msgstr "ignorerar \"%s\" som kan tolkas som en kommandoradsflagga: %s"
+msgstr "ignorerar â€%s†som kan tolkas som en kommandoradsflagga: %s"
#, c-format
msgid "Could not update .gitmodules entry %s"
-msgstr "Kunde inte uppdatera .gitmodules-posten %s"
+msgstr "Kunde inte uppdatera â€.gitmodulesâ€-posten %s"
msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
msgstr ""
-"Kan inte ändra .gitmodules-fil som inte slagits ihop, lös "
+"Kan inte ändra â€.gitmodulesâ€-fil som inte slagits ihop, lös "
"sammanslagningskonflikter först"
#, c-format
@@ -20651,18 +21481,18 @@ msgstr "Hittade inte någon sektion i .gitmodules där sökväg=%s"
#, c-format
msgid "Could not remove .gitmodules entry for %s"
-msgstr "Kunde inte ta bort .gitmodules-posten för %s"
+msgstr "Kunde inte ta bort â€.gitmodulesâ€-posten för %s"
msgid "staging updated .gitmodules failed"
msgstr "misslyckades köa uppdaterad .gitmodules"
#, c-format
msgid "in unpopulated submodule '%s'"
-msgstr "i ej utcheckad undermodul \"%s\""
+msgstr "i ej utcheckad undermodul â€%sâ€"
#, c-format
msgid "Pathspec '%s' is in submodule '%.*s'"
-msgstr "Sökvägsangivelsen \"%s\" är i undermodulen \"%.*s\""
+msgstr "Sökvägsangivelsen â€%s†är i undermodulen â€%.*sâ€"
#, c-format
msgid "bad --ignore-submodules argument: %s"
@@ -20673,32 +21503,32 @@ msgid ""
"Submodule in commit %s at path: '%s' collides with a submodule named the "
"same. Skipping it."
msgstr ""
-"Undermodulen i incheckning %s på sökvägen: \"%s\" krockar med en undermodul "
+"Undermodulen i incheckning %s pÃ¥ sökvägen: â€%s†krockar med en undermodul "
"med samma namn. Hoppar över den."
#, c-format
msgid "submodule entry '%s' (%s) is a %s, not a commit"
-msgstr "undermodulposten \"%s\" (%s) är en %s, inte en incheckning"
+msgstr "undermodulposten â€%s†(%s) är en %s, inte en incheckning"
#, c-format
msgid ""
"Could not run 'git rev-list <commits> --not --remotes -n 1' command in "
"submodule %s"
msgstr ""
-"kunde inte köra \"git rev-list <incheckningar> --not --remotes -n 1\" i "
-"undermodulen \"%s\""
+"kunde inte köra â€git rev-list <incheckningar> --not --remotes -n 1†i "
+"undermodulen â€%sâ€"
#, c-format
msgid "process for submodule '%s' failed"
-msgstr "process för undermodulen \"%s\" misslyckades"
+msgstr "process för undermodulen â€%s†misslyckades"
#, c-format
msgid "Pushing submodule '%s'\n"
-msgstr "Sänder undermodulen \"%s\"\n"
+msgstr "Sänder undermodulen â€%sâ€\n"
#, c-format
msgid "Unable to push submodule '%s'\n"
-msgstr "Kunde inte sända undermodulen \"%s\"\n"
+msgstr "Kunde inte sända undermodulen â€%sâ€\n"
#, c-format
msgid "Fetching submodule %s%s\n"
@@ -20706,15 +21536,15 @@ msgstr "Hämtar undermodulen %s%s\n"
#, c-format
msgid "Could not access submodule '%s'\n"
-msgstr "Kunde inte komma åt undermodulen \"%s\"\n"
+msgstr "Kunde inte komma Ã¥t undermodulen â€%sâ€\n"
#, c-format
msgid "Could not access submodule '%s' at commit %s\n"
-msgstr "Kunde inte komma åt undermodulen \"%s\" vid incheckningen %s\n"
+msgstr "Kunde inte komma Ã¥t undermodulen â€%s†vid incheckningen %s\n"
#, c-format
msgid "Fetching submodule %s%s at commit %s\n"
-msgstr "Hämtar undermodulen %s%s vvid incheckningen %s\n"
+msgstr "Hämtar undermodulen %s%s vid incheckningen %s\n"
#, c-format
msgid ""
@@ -20726,61 +21556,71 @@ msgstr ""
#, c-format
msgid "'%s' not recognized as a git repository"
-msgstr "\"%s\" känns inte igen som ett git-arkiv"
+msgstr "â€%s†känns inte igen som ett git-arkiv"
#, c-format
msgid "Could not run 'git status --porcelain=2' in submodule %s"
-msgstr "Kunde inte köra \"git status --porcelain=2\" i undermodulen \"%s\""
+msgstr "Kunde inte köra â€git status --porcelain=2†i undermodulen â€%sâ€"
#, c-format
msgid "'git status --porcelain=2' failed in submodule %s"
-msgstr "\"git status --porcelain=2\" misslyckades i undermodulen \"%s\""
+msgstr "â€git status --porcelain=2†misslyckades i undermodulen â€%sâ€"
#, c-format
msgid "could not start 'git status' in submodule '%s'"
-msgstr "kunde inte starta \"git status\" i undermodulen \"%s\""
+msgstr "kunde inte starta â€git status†i undermodulen â€%sâ€"
#, c-format
msgid "could not run 'git status' in submodule '%s'"
-msgstr "kunde inte köra \"git status\" i undermodulen \"%s\""
+msgstr "kunde inte köra â€git status†i undermodulen â€%sâ€"
#, c-format
msgid "Could not unset core.worktree setting in submodule '%s'"
-msgstr "Kunde inte ta bort inställningen core.worktree i undermodulen \"%s\""
+msgstr "Kunde inte ta bort inställningen core.worktree i undermodulen â€%sâ€"
#, c-format
msgid "could not recurse into submodule '%s'"
-msgstr "kunde inte rekursera in i undermodulen \"%s\""
+msgstr "kunde inte rekursera in i undermodulen â€%sâ€"
msgid "could not reset submodule index"
msgstr "kunde inte återställa indexet i undermodul"
#, c-format
msgid "submodule '%s' has dirty index"
-msgstr "undermodulen \"%s\" har ett smutsigt index"
+msgstr "undermodulen â€%s†har ett smutsigt index"
#, c-format
msgid "Submodule '%s' could not be updated."
-msgstr "Undermoduler \"%s\" kunde inte uppdateras."
+msgstr "Undermoduler â€%s†kunde inte uppdateras."
#, c-format
msgid "submodule git dir '%s' is inside git dir '%.*s'"
-msgstr "undermodul-gitkatalogen \"%s\" är inuti gitkatalogen \"%.*s\""
+msgstr "undermodul-gitkatalogen â€%s†är inuti gitkatalogen â€%.*sâ€"
+
+#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"förväntade att â€%.*s†i undermodulsökvägen â€%s†inte ska vara en symbolisk "
+"länk"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "förväntade att undermodulsökvägen â€%s†inte ska vara en symbolisk länk"
#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
-"relocate_gitdir för undermodulen \"%s\", som har mer än en arbetskatalog, "
+"relocate_gitdir för undermodulen â€%sâ€, som har mer än en arbetskatalog, "
"stöds ej"
#, c-format
msgid "could not lookup name for submodule '%s'"
-msgstr "kunde inte slå upp namnet för undermodulen \"%s\""
+msgstr "kunde inte slÃ¥ upp namnet för undermodulen â€%sâ€"
#, c-format
msgid "refusing to move '%s' into an existing git dir"
-msgstr "vägrar flytta \"%s\" till en befintlig gitkatalog"
+msgstr "vägrar flytta â€%s†till en befintlig gitkatalog"
#, c-format
msgid ""
@@ -20788,9 +21628,9 @@ msgid ""
"'%s' to\n"
"'%s'\n"
msgstr ""
-"Migrerar git-katalogen för \"%s%s\" från\n"
-"\"%s\" till\n"
-"\"%s\"\n"
+"Migrerar git-katalogen för â€%s%s†frÃ¥n\n"
+"â€%s†till\n"
+"â€%sâ€\n"
msgid "could not start ls-files in .."
msgstr "kunde inte starta ls-files i .."
@@ -20801,15 +21641,11 @@ msgstr "ls-tree returnerade en oväntad returkod %d"
#, c-format
msgid "failed to lstat '%s'"
-msgstr "misslyckades ta status (lstat) på \"%s\""
+msgstr "misslyckades ta status (lstat) pÃ¥ â€%sâ€"
msgid "no remote configured to get bundle URIs from"
msgstr "ingen fjärr att hämta bunt-URI:er från inställd"
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "fjärren \"%s\" har ingen URL konfigurerad"
-
msgid "could not get the bundle-uri list"
msgstr "kunde inte hämta bundle-uri-listan"
@@ -20822,12 +21658,6 @@ msgstr "töm cacheträdet före varje iteration"
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr "antal poster i cacheträdet att ogiltigförklara (förval är 0)"
-msgid "unhandled options"
-msgstr "flaggor som inte hanterats"
-
-msgid "error preparing revisions"
-msgstr "fel när revisioner skulle förberedas"
-
#, c-format
msgid "commit %s is not marked reachable"
msgstr "incheckning %s är inte märkt nåbar"
@@ -20897,47 +21727,42 @@ msgstr "igenkänningstecken"
msgid "command token to send to the server"
msgstr "igenkänningstecken för kommando att sända till servern"
-#, c-format
-msgid "running trailer command '%s' failed"
-msgstr "misslyckades utföra släpradskommandot \"%s\""
+msgid "unit-test [<options>]"
+msgstr "unit-test [<flaggor>]"
-#, c-format
-msgid "unknown value '%s' for key '%s'"
-msgstr "okänt värde \"%s\" för nyckeln \"%s\""
+msgid "immediately exit upon the first failed test"
+msgstr "avsluta omedelbart vid det första misslyckade testet"
-#, c-format
-msgid "empty trailer token in trailer '%.*s'"
-msgstr "tom släpradssymbol i släpraden \"%.*s\""
+msgid "suite[::test]"
+msgstr "svit[::test]"
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "kunde inte läsa indatafilen \"%s\""
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "kör endast testsviten eller individuella testet <svit[::test]>"
-#, c-format
-msgid "could not stat %s"
-msgstr "kunde inte ta status på %s"
+msgid "suite"
+msgstr "svit"
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "filen %s är inte en normal fil"
+msgid "exclude test suite <suite>"
+msgstr "uteslut testsviten <svit>"
#, c-format
-msgid "file %s is not writable by user"
-msgstr "filen %s är inte skrivbar av användaren"
+msgid "running trailer command '%s' failed"
+msgstr "misslyckades utföra släpradskommandot â€%sâ€"
-msgid "could not open temporary file"
-msgstr "kunde inte öppna temporär fil"
+#, c-format
+msgid "unknown value '%s' for key '%s'"
+msgstr "okänt värde â€%s†för nyckeln â€%sâ€"
#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "kunde inte byta namn på temporär fil till %s"
+msgid "empty trailer token in trailer '%.*s'"
+msgstr "tom släpradssymbol i släpraden â€%.*sâ€"
msgid "full write to remote helper failed"
msgstr "komplett skrivning till fjärrhjälpare misslyckades"
#, c-format
msgid "unable to find remote helper for '%s'"
-msgstr "kan inte hitta fjärrhjälpare för \"%s\""
+msgstr "kan inte hitta fjärrhjälpare för â€%sâ€"
msgid "can't dup helper output fd"
msgstr "kunde inte duplicera utdata-filhandtag"
@@ -20957,7 +21782,7 @@ msgstr ""
#, c-format
msgid "%s unexpectedly said: '%s'"
-msgstr "%s sade oväntat: \"%s\""
+msgstr "%s sade oväntat: â€%sâ€"
#, c-format
msgid "%s also locked %s"
@@ -20983,9 +21808,6 @@ msgstr "protkollet stöder inte att sätta sökväg till fjärrtjänst"
msgid "invalid remote service path"
msgstr "felaktig sökväg till fjärrtjänst"
-msgid "operation not supported by protocol"
-msgstr "funktionen stöds inte av protokollet"
-
#, c-format
msgid "can't connect to subservice %s"
msgstr "kan inte ansluta till undertjänsten %s"
@@ -20994,11 +21816,11 @@ msgid "--negotiate-only requires protocol v2"
msgstr "--negotiate-only kräver protokoll v2"
msgid "'option' without a matching 'ok/error' directive"
-msgstr "\"option\" utan mostsvarande \"ok/error\"-direktiv"
+msgstr "â€option†utan mostsvarande â€ok/errorâ€-direktiv"
#, c-format
msgid "expected ok/error, helper said '%s'"
-msgstr "förväntade ok/error, hjälpprogrammet svarade \"%s\""
+msgstr "förväntade ok/error, hjälpprogrammet svarade â€%sâ€"
#, c-format
msgid "helper reported unexpected status of %s"
@@ -21026,14 +21848,14 @@ msgstr "hjälparen %s stöder inte --%s"
#, c-format
msgid "helper %s does not support 'push-option'"
-msgstr "hjälparen %s stöder inte \"push-option\""
+msgstr "hjälparen %s stöder inte â€push-optionâ€"
msgid "remote-helper doesn't support push; refspec needed"
msgstr "fjärrhjälparen stöder inte push; referensspecifikation krävs"
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "hjälparen %s stöder inte \"force\""
+msgid "helper %s does not support '--force'"
+msgstr "hjälparen %s stöder inte â€--forceâ€"
msgid "couldn't run fast-export"
msgstr "kunde inte köra fast-export"
@@ -21051,7 +21873,7 @@ msgstr ""
#, c-format
msgid "unsupported object format '%s'"
-msgstr "objektformatet \"%s\" stöds ej"
+msgstr "objektformatet â€%s†stöds ej"
#, c-format
msgid "malformed response in ref list: %s"
@@ -21090,18 +21912,18 @@ msgstr "kan inte skapa tråd för kopiering av data"
#, c-format
msgid "Would set upstream of '%s' to '%s' of '%s'\n"
-msgstr "Skulle sätta uppströms för \"%s\" till \"%s\" från \"%s\"\n"
+msgstr "Skulle sätta uppströms för â€%s†till â€%s†frÃ¥n â€%sâ€\n"
#, c-format
msgid "could not read bundle '%s'"
-msgstr "kunde inte läsa bunten \"%s\""
+msgstr "kunde inte läsa bunten â€%sâ€"
#, c-format
msgid "transport: invalid depth option '%s'"
-msgstr "transport: ogiltig flagga för depth: \"%s\""
+msgstr "transport: ogiltig flagga för depth: â€%sâ€"
msgid "see protocol.version in 'git help config' for more details"
-msgstr "se protocol.version i \"git help config\" för mer information"
+msgstr "se protocol.version i â€git help config†för mer information"
msgid "server options require protocol version 2 or later"
msgstr "serverflaggor kräver protokollversion 2 eller senare"
@@ -21116,12 +21938,8 @@ msgid "support for protocol v2 not implemented yet"
msgstr "stöd för protokoll v2 ännu ej implementerat"
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "okänt värde för inställningen \"%s\": %s"
-
-#, c-format
msgid "transport '%s' not allowed"
-msgstr "transporten \"%s\" tillåts inte"
+msgstr "transporten â€%s†tillÃ¥ts inte"
msgid "git-over-rsync is no longer supported"
msgstr "git-over-rsync stöds inte längre"
@@ -21164,7 +21982,7 @@ msgid "Aborting."
msgstr "Avbryter."
msgid "failed to push all needed submodules"
-msgstr "kunde inte sända alla nödvändiga undermoduler"
+msgstr "misslyckades sända alla nödvändiga undermoduler"
msgid "bundle-uri operation not supported by protocol"
msgstr "bundle-uri-funktionen stöds inte av protokollet"
@@ -21172,6 +21990,9 @@ msgstr "bundle-uri-funktionen stöds inte av protokollet"
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "kunde inte hämta bundle-uri-listan som servern annonserade"
+msgid "operation not supported by protocol"
+msgstr "funktionen stöds inte av protokollet"
+
msgid "too-short tree object"
msgstr "trädobjekt för kort"
@@ -21190,7 +22011,7 @@ msgid ""
"%%sPlease commit your changes or stash them before you switch branches."
msgstr ""
"Dina lokala ändringar av följande filer skulle skrivas över av utcheckning:\n"
-"%%sChecka in dina ändringar eller använd \"stash\" innan du byter gren."
+"%%sChecka in dina ändringar eller använd â€stash†innan du byter gren."
#, c-format
msgid ""
@@ -21207,7 +22028,7 @@ msgid ""
msgstr ""
"Dina lokala ändringar av följande filer skulle skrivas över av "
"sammanslagning:\n"
-"%%sChecka in dina ändringar eller använd \"stash\" innan du byter gren."
+"%%sChecka in dina ändringar eller använd â€stash†innan du byter gren."
#, c-format
msgid ""
@@ -21223,15 +22044,15 @@ 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 ""
-"Dina lokala ändringar av följande filer skulle skrivas över av \"%s\":\n"
-"%%sChecka in dina ändringar eller använd \"stash\" innan du \"%s\"."
+"Dina lokala ändringar av följande filer skulle skrivas över av â€%sâ€:\n"
+"%%sChecka in dina ändringar eller använd â€stash†innan du â€%sâ€."
#, c-format
msgid ""
"Your local changes to the following files would be overwritten by %s:\n"
"%%s"
msgstr ""
-"Dina lokala ändringar av följande filer skulle skrivas över av \"%s\":\n"
+"Dina lokala ändringar av följande filer skulle skrivas över av â€%sâ€:\n"
"%%s"
#, c-format
@@ -21290,15 +22111,15 @@ msgid ""
"The following untracked working tree files would be removed by %s:\n"
"%%sPlease move or remove them before you %s."
msgstr ""
-"Följande ospårade filer i arbetskatalogen skulle tas bort av \"%s\":\n"
-"%%sFlytta eller ta bort dem innan du \"%s\"."
+"Följande ospÃ¥rade filer i arbetskatalogen skulle tas bort av â€%sâ€:\n"
+"%%sFlytta eller ta bort dem innan du â€%sâ€."
#, c-format
msgid ""
"The following untracked working tree files would be removed by %s:\n"
"%%s"
msgstr ""
-"Följande ospårade filer i arbetskatalogen skulle tas bort av \"%s\":\n"
+"Följande ospÃ¥rade filer i arbetskatalogen skulle tas bort av â€%sâ€:\n"
"%%s"
#, c-format
@@ -21344,20 +22165,20 @@ msgid ""
"The following untracked working tree files would be overwritten by %s:\n"
"%%sPlease move or remove them before you %s."
msgstr ""
-"Följande ospårade filer i arbetskatalogen skulle skrivas över av \"%s\":\n"
-"%%sFlytta eller ta bort dem innan du \"%s\"."
+"Följande ospÃ¥rade filer i arbetskatalogen skulle skrivas över av â€%sâ€:\n"
+"%%sFlytta eller ta bort dem innan du â€%sâ€."
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by %s:\n"
"%%s"
msgstr ""
-"Följande ospårade filer i arbetskatalogen skulle skrivas över av \"%s\":\n"
+"Följande ospÃ¥rade filer i arbetskatalogen skulle skrivas över av â€%sâ€:\n"
"%%s"
#, c-format
msgid "Entry '%s' overlaps with '%s'. Cannot bind."
-msgstr "Posten \"%s\" överlappar \"%s\". Kan inte binda."
+msgstr "Posten â€%s†överlappar â€%sâ€. Kan inte binda."
#, c-format
msgid ""
@@ -21404,7 +22225,7 @@ msgid ""
"After fixing the above paths, you may want to run `git sparse-checkout "
"reapply`.\n"
msgstr ""
-"Du bör köra \"git sparse-checkout reapply\" efter att ha fixat sökvägarna "
+"Du bör köra â€git sparse-checkout reapply†efter att ha fixat sökvägarna "
"ovan.\n"
msgid "Updating files"
@@ -21427,20 +22248,20 @@ msgid "worktree and untracked commit have duplicate entries: %s"
msgstr "arbetskatalog och ospårad incheckning har dublettposter: %s"
msgid "expected flush after fetch arguments"
-msgstr "förväntade \"flush\" efter \"fetch\"-argument"
+msgstr "förväntade â€flush†efter â€fetchâ€-argument"
msgid "invalid URL scheme name or missing '://' suffix"
-msgstr "ogiltig URL-schemanamn eller saknat \"://\"-suffix"
+msgstr "ogiltig URL-schemanamn eller saknat â€://â€-suffix"
#, c-format
msgid "invalid %XX escape sequence"
msgstr "ogiltig %XX-teckensekvens"
msgid "missing host and scheme is not 'file:'"
-msgstr "värd saknas och schemat är inte \"file:\""
+msgstr "värd saknas och schemat är inte â€file:â€"
msgid "a 'file:' URL may not have a port number"
-msgstr "en \"file:\"-URL kan inte innehålla portnummer"
+msgstr "en â€file:â€-URL kan inte innehÃ¥lla portnummer"
msgid "invalid characters in host name"
msgstr "ogiltiga tecken i värdnamnet"
@@ -21449,7 +22270,11 @@ msgid "invalid port number"
msgstr "felaktigt portnummer"
msgid "invalid '..' path segment"
-msgstr "felaktigt \"..\"-sökvägssegment"
+msgstr "felaktigt â€..â€-sökvägssegment"
+
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "fel: kan inte formatera meddelande: %s\n"
msgid "usage: "
msgstr "användning: "
@@ -21468,19 +22293,19 @@ msgstr "Hämtar objekt"
#, c-format
msgid "'%s' at main working tree is not the repository directory"
-msgstr "\"%s\" i huvudarbetskatalogen är inte arkivkatalogen"
+msgstr "â€%s†i huvudarbetskatalogen är inte arkivkatalogen"
#, c-format
msgid "'%s' file does not contain absolute path to the working tree location"
-msgstr "filen \"%s\" innehåller inte absolut sökväg till arbetskatalogen"
+msgstr "filen â€%s†innehÃ¥ller inte absolut sökväg till arbetskatalogen"
#, c-format
msgid "'%s' is not a .git file, error code %d"
-msgstr "\"%s\" är inte en .git-fil, felkod %d"
+msgstr "â€%s†är inte en .git-fil, felkod %d"
#, c-format
msgid "'%s' does not point back to '%s'"
-msgstr "\"%s\" pekar inte tillbaka till \"%s\""
+msgstr "â€%s†pekar inte tillbaka till â€%sâ€"
msgid "not a directory"
msgstr "inte en katalog"
@@ -21498,13 +22323,13 @@ msgid "not a valid path"
msgstr "inte en giltig sökväg"
msgid "unable to locate repository; .git is not a file"
-msgstr "hittar inte arkivet; .git är inte en fil"
+msgstr "kan inte hitta arkivet; .git är inte en fil"
msgid "unable to locate repository; .git file does not reference a repository"
-msgstr "hittar inte arkivet; .git-filen hänvisar inte till ett arkiv"
+msgstr "kan inte hitta arkivet; â€.gitâ€-filen hänvisar inte till ett arkiv"
msgid "unable to locate repository; .git file broken"
-msgstr "hittar inte arkivet; .git-filen är trasig"
+msgstr "kan inte hitta arkivet; â€.gitâ€-filen är trasig"
msgid "gitdir unreadable"
msgstr "gitdir är oläsbar"
@@ -21516,75 +22341,78 @@ msgid "not a valid directory"
msgstr "inte i en giltig katalog"
msgid "gitdir file does not exist"
-msgstr "gitdir-filen existerar inte"
+msgstr "â€gitdirâ€-filen existerar inte"
#, c-format
msgid "unable to read gitdir file (%s)"
-msgstr "kunde inte läsa gitdir-filen (%s)"
+msgstr "kan inte läsa â€gitdirâ€-filen (%s)"
#, c-format
msgid "short read (expected %<PRIuMAX> bytes, read %<PRIuMAX>)"
msgstr "kort läsning (förväntade %<PRIuMAX> byte, läste %<PRIuMAX>)"
msgid "invalid gitdir file"
-msgstr "ogiltig gitdir-fil"
+msgstr "ogiltig â€gitdirâ€-fil"
msgid "gitdir file points to non-existent location"
-msgstr "gitdir-filen pekar på en ickeexisterande plats"
+msgstr "â€gitdirâ€-filen pekar pÃ¥ en ickeexisterande plats"
#, c-format
msgid "unable to set %s in '%s'"
-msgstr "kan inte sätta %s i \"%s\""
+msgstr "kan inte sätta %s i â€%sâ€"
#, c-format
msgid "unable to unset %s in '%s'"
-msgstr "kan inte slå av %s i \"%s\""
+msgstr "kan inte slÃ¥ av %s i â€%sâ€"
msgid "failed to set extensions.worktreeConfig setting"
msgstr "misslyckades ändra inställningen extensions.worktreeConfig"
#, c-format
msgid "could not setenv '%s'"
-msgstr "kunde inte lagra miljövariabeln \"%s\""
+msgstr "kunde inte lagra miljövariabeln â€%sâ€"
#, c-format
msgid "unable to create '%s'"
-msgstr "kunde inte skapa \"%s\""
+msgstr "kan inte skapa â€%sâ€"
#, c-format
msgid "could not open '%s' for reading and writing"
-msgstr "kunde inte öppna \"%s\" för läsning och skrivning"
+msgstr "kunde inte öppna â€%s†för läsning och skrivning"
#, c-format
msgid "unable to access '%s'"
-msgstr "kan inte komma åt \"%s\""
+msgstr "kan inte komma Ã¥t â€%sâ€"
msgid "unable to get current working directory"
msgstr "kan inte hämta aktuell arbetskatalog"
+msgid "unable to get random bytes"
+msgstr "kan inte hämta slumpdata"
+
msgid "Unmerged paths:"
msgstr "Ej sammanslagna sökvägar:"
msgid " (use \"git restore --staged <file>...\" to unstage)"
-msgstr " (använd \"git restore --staged <fil>...\" för att ta bort från kö)"
+msgstr " (använd â€git restore --staged <fil>...†för att ta bort frÃ¥n kö)"
#, c-format
msgid " (use \"git restore --source=%s --staged <file>...\" to unstage)"
msgstr ""
-" (använd \"git restore --source=%s --staged <fil>...\" för att ta bort från "
+" (använd â€git restore --source=%s --staged <fil>...†för att ta bort frÃ¥n "
"kö)"
msgid " (use \"git rm --cached <file>...\" to unstage)"
-msgstr " (använd \"git rm --cached <fil>...\" för att ta bort från kö)"
+msgstr " (använd â€git rm --cached <fil>...†för att ta bort frÃ¥n kö)"
msgid " (use \"git add <file>...\" to mark resolution)"
-msgstr " (använd \"git add <fil>...\" för att ange lösning)"
+msgstr " (använd â€git add <fil>...†för att ange lösning)"
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
-msgstr " (använd \"git add/rm <fil>...\" som lämpligt för att ange lösning)"
+msgstr " (använd â€git add/rm <fil>...†som lämpligt för att ange lösning)"
msgid " (use \"git rm <file>...\" to mark resolution)"
-msgstr " (använd \"git rm <fil>...\" för att ange lösning)"
+msgstr " (använd â€git rm <fil>...†för att ange lösning)"
msgid "Changes to be committed:"
msgstr "Ändringar att checka in:"
@@ -21593,17 +22421,16 @@ msgid "Changes not staged for commit:"
msgstr "Ändringar ej i incheckningskön:"
msgid " (use \"git add <file>...\" to update what will be committed)"
-msgstr ""
-" (använd \"git add <fil>...\" för att uppdatera vad som ska checkas in)"
+msgstr " (använd â€git add <fil>...†för att uppdatera vad som ska checkas in)"
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
-" (använd \"git add/rm <fil>...\" för att uppdatera vad som ska checkas in)"
+" (använd â€git add/rm <fil>...†för att uppdatera vad som ska checkas in)"
msgid ""
" (use \"git restore <file>...\" to discard changes in working directory)"
msgstr ""
-" (använd \"git restore <fil>...\" för att förkasta ändringar i "
+" (använd â€git restore <fil>...†för att förkasta ändringar i "
"arbetskatalogen)"
msgid " (commit or discard the untracked or modified content in submodules)"
@@ -21612,7 +22439,7 @@ msgstr ""
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
-msgstr " (använd \"git %s <fil>...\" för att ta med i det som ska checkas in)"
+msgstr " (använd â€git %s <fil>...†för att ta med i det som ska checkas in)"
msgid "both deleted:"
msgstr "borttaget av bägge:"
@@ -21695,43 +22522,43 @@ msgid ""
msgstr ""
"\n"
"Det tog %.2f sekunder att räkna före/bakom-värden.\n"
-"Du kan använda \"--no-ahead-behind\" för undvika detta.\n"
+"Du kan använda â€--no-ahead-behind†för undvika detta.\n"
msgid "You have unmerged paths."
msgstr "Du har ej sammanslagna sökvägar."
msgid " (fix conflicts and run \"git commit\")"
-msgstr " (rätta konflikter och kör \"git commit\")"
+msgstr " (rätta konflikter och kör â€git commitâ€)"
msgid " (use \"git merge --abort\" to abort the merge)"
-msgstr " (använd \"git merge --abort\" för att avbryta sammanslagningen)"
+msgstr " (använd â€git merge --abort†för att avbryta sammanslagningen)"
msgid "All conflicts fixed but you are still merging."
msgstr "Alla konflikter har rättats men du är fortfarande i en sammanslagning."
msgid " (use \"git commit\" to conclude merge)"
-msgstr " (använd \"git commit\" för att slutföra sammanslagningen)"
+msgstr " (använd â€git commit†för att slutföra sammanslagningen)"
msgid "You are in the middle of an am session."
-msgstr "Du är i mitten av en körning av \"git am\"."
+msgstr "Du är i mitten av en körning av â€git amâ€."
msgid "The current patch is empty."
msgstr "Aktuell patch är tom."
msgid " (fix conflicts and then run \"git am --continue\")"
-msgstr " (rätta konflikter och kör sedan \"git am --continue\")"
+msgstr " (rätta konflikter och kör sedan â€git am --continueâ€)"
msgid " (use \"git am --skip\" to skip this patch)"
-msgstr " (använd \"git am --skip\" för att hoppa över patchen)"
+msgstr " (använd â€git am --skip†för att hoppa över patchen)"
msgid ""
" (use \"git am --allow-empty\" to record this patch as an empty commit)"
msgstr ""
-" (använd \"git am --allow-empty\" för att registrera patchen som en tom "
+" (använd â€git am --allow-empty†för att registrera patchen som en tom "
"incheckning)"
msgid " (use \"git am --abort\" to restore the original branch)"
-msgstr " (använd \"git am --abort\" för att återställa ursprungsgrenen)"
+msgstr " (använd â€git am --abort†för att Ã¥terställa ursprungsgrenen)"
msgid "git-rebase-todo is missing."
msgstr "git-rebase-todo saknas."
@@ -21759,79 +22586,79 @@ msgstr[0] "Nästa kommando att utföra (%<PRIuMAX> kommando återstår):"
msgstr[1] "Följande kommandon att utföra (%<PRIuMAX> kommandon återstår):"
msgid " (use \"git rebase --edit-todo\" to view and edit)"
-msgstr " (använd \"git rebase --edit-todo\" för att visa och redigera)"
+msgstr " (använd â€git rebase --edit-todo†för att visa och redigera)"
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
-msgstr "Du håller på att ombasera grenen \"%s\" ovanpå \"%s\"."
+msgstr "Du hÃ¥ller pÃ¥ att ombasera grenen â€%s†ovanpÃ¥ â€%sâ€."
msgid "You are currently rebasing."
msgstr "Du håller på med en ombasering."
msgid " (fix conflicts and then run \"git rebase --continue\")"
-msgstr " (rätta konflikter och kör sedan \"git rebase --continue\")"
+msgstr " (rätta konflikter och kör sedan â€git rebase --continueâ€)"
msgid " (use \"git rebase --skip\" to skip this patch)"
-msgstr " (använd \"git rebase --skip\" för att hoppa över patchen)"
+msgstr " (använd â€git rebase --skip†för att hoppa över patchen)"
msgid " (use \"git rebase --abort\" to check out the original branch)"
-msgstr " (använd \"git rebase --abort\" för att checka ut ursprungsgrenen)"
+msgstr " (använd â€git rebase --abort†för att checka ut ursprungsgrenen)"
msgid " (all conflicts fixed: run \"git rebase --continue\")"
-msgstr " (alla konflikter rättade: kör \"git rebase --continue\")"
+msgstr " (alla konflikter rättade: kör â€git rebase --continueâ€)"
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
msgstr ""
-"Du håller på att dela upp en incheckning medan du ombaserar grenen \"%s\" "
-"ovanpå \"%s\"."
+"Du hÃ¥ller pÃ¥ att dela upp en incheckning medan du ombaserar grenen â€%s†"
+"ovanpÃ¥ â€%sâ€."
msgid "You are currently splitting a commit during a rebase."
msgstr "Du håller på att dela upp en incheckning i en ombasering."
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
-msgstr " (Så fort din arbetskatalog är ren, kör \"git rebase --continue\")"
+msgstr " (SÃ¥ fort din arbetskatalog är ren, kör â€git rebase --continueâ€)"
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
-"Du håller på att redigera en incheckning medan du ombaserar grenen \"%s\" "
-"ovanpå \"%s\"."
+"Du hÃ¥ller pÃ¥ att redigera en incheckning medan du ombaserar grenen â€%s†"
+"ovanpÃ¥ â€%sâ€."
msgid "You are currently editing a commit during a rebase."
msgstr "Du håller på att redigera en incheckning under en ombasering."
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr ""
-" (använd \"git commit --amend\" för att lägga till på aktuell incheckning)"
+" (använd â€git commit --amend†för att lägga till pÃ¥ aktuell incheckning)"
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
-msgstr " (använd \"git rebase --continue\" när du är nöjd med dina ändringar)"
+msgstr " (använd â€git rebase --continue†när du är nöjd med dina ändringar)"
msgid "Cherry-pick currently in progress."
msgstr "Cherry-pick pågår."
#, c-format
msgid "You are currently cherry-picking commit %s."
-msgstr "Du håller på med en \"cherry-pick\" av incheckningen %s."
+msgstr "Du hÃ¥ller pÃ¥ med en â€cherry-pick†av incheckningen %s."
msgid " (fix conflicts and run \"git cherry-pick --continue\")"
-msgstr " (rätta konflikter och kör sedan \"git cherry-pick --continue\")"
+msgstr " (rätta konflikter och kör sedan â€git cherry-pick --continueâ€)"
msgid " (run \"git cherry-pick --continue\" to continue)"
-msgstr " (kör \"git cherry-pick --continue\" för att fortsätta)"
+msgstr " (kör â€git cherry-pick --continue†för att fortsätta)"
msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
-msgstr " (alla konflikter rättade: kör \"git cherry-pick --continue\")"
+msgstr " (alla konflikter rättade: kör â€git cherry-pick --continueâ€)"
msgid " (use \"git cherry-pick --skip\" to skip this patch)"
-msgstr " (använd \"git cherry-pick --skip\" för att hoppa över patchen)"
+msgstr " (använd â€git cherry-pick --skip†för att hoppa över patchen)"
msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
msgstr ""
-" (använd \"git cherry-pick --abort\" för att avbryta \"cherry-pick\"-"
+" (använd â€git cherry-pick --abort†för att avbryta â€cherry-pickâ€-"
"operationen)"
msgid "Revert currently in progress."
@@ -21842,30 +22669,30 @@ msgid "You are currently reverting commit %s."
msgstr "Du håller på med att ångra incheckningen %s."
msgid " (fix conflicts and run \"git revert --continue\")"
-msgstr " (rätta konflikter och kör sedan \"git revert --continue\")"
+msgstr " (rätta konflikter och kör sedan â€git revert --continueâ€)"
msgid " (run \"git revert --continue\" to continue)"
-msgstr " (kör \"git revert --continue\" för att fortsätta)"
+msgstr " (kör â€git revert --continue†för att fortsätta)"
msgid " (all conflicts fixed: run \"git revert --continue\")"
-msgstr " (alla konflikter rättade: kör \"git revert --continue\")"
+msgstr " (alla konflikter rättade: kör â€git revert --continueâ€)"
msgid " (use \"git revert --skip\" to skip this patch)"
-msgstr " (använd \"git revert --skip\" för att hoppa över patchen)"
+msgstr " (använd â€git revert --skip†för att hoppa över patchen)"
msgid " (use \"git revert --abort\" to cancel the revert operation)"
-msgstr " (använd \"git revert --abort\" för att avbryta ångrandet)"
+msgstr " (använd â€git revert --abort†för att avbryta Ã¥ngrandet)"
#, c-format
msgid "You are currently bisecting, started from branch '%s'."
-msgstr "Du håller på med en \"bisect\", startad från grenen \"%s\"."
+msgstr "Du hÃ¥ller pÃ¥ med en â€bisectâ€, startad frÃ¥n grenen â€%sâ€."
msgid "You are currently bisecting."
-msgstr "Du håller på med en \"bisect\"."
+msgstr "Du hÃ¥ller pÃ¥ med en â€bisectâ€."
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr ""
-" (använd \"git bisect reset\" för att komma tillbaka till ursprungsgrenen)"
+" (använd â€git bisect reset†för att komma tillbaka till ursprungsgrenen)"
msgid "You are in a sparse checkout."
msgstr "Du är i en gles utcheckning."
@@ -21917,7 +22744,7 @@ msgid "It took %.2f seconds to enumerate untracked files."
msgstr "Det tog %.2f sekunder att räkna upp ospårade filer."
msgid "See 'git help status' for information on how to improve this."
-msgstr "Se \"git help status\" för information om hur du kan förbättra detta."
+msgstr "Se â€git help status†för information om hur du kan förbättra detta."
# %s är nästa sträng eller tom.
#, c-format
@@ -21933,8 +22760,7 @@ msgstr "Inga ändringar"
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
-"inga ändringar att checka in (använd \"git add\" och/eller \"git commit -a"
-"\")\n"
+"inga ändringar att checka in (använd â€git add†och/eller â€git commit -aâ€)\n"
#, c-format
msgid "no changes added to commit\n"
@@ -21945,8 +22771,7 @@ msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
"track)\n"
msgstr ""
-"inget köat för incheckning, men ospårade filer finns (spåra med \"git add"
-"\")\n"
+"inget köat för incheckning, men ospÃ¥rade filer finns (spÃ¥ra med â€git addâ€)\n"
#, c-format
msgid "nothing added to commit but untracked files present\n"
@@ -21954,7 +22779,7 @@ msgstr "inget köat för incheckning, men ospårade filer finns\n"
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
-msgstr "inget att checka in (skapa/kopiera filer och spåra med \"git add\")\n"
+msgstr "inget att checka in (skapa/kopiera filer och spÃ¥ra med â€git addâ€)\n"
#, c-format
msgid "nothing to commit\n"
@@ -21995,6 +22820,10 @@ msgstr "dessutom innehåller dit index ändringar som inte har checkats in."
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "kan inte %s: Ditt index innehåller ändringar som inte checkats in."
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "okänd stil â€%s†angavs för â€%sâ€"
+
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22033,7 +22862,7 @@ msgstr "använd: $dashless $USAGE"
#, sh-format
msgid "Cannot chdir to $cdup, the toplevel of the working tree"
-msgstr "Kunde inte byta katalog till $cdup, toppnivån på arbetskatalogen"
+msgstr "Kan inte byta katalog till $cdup, toppnivån på arbetskatalogen"
#, sh-format
msgid "fatal: $program_name cannot be used without a working tree."
@@ -22068,7 +22897,7 @@ msgstr "lokal tidszonförskjutning större än eller lika med 24 timmar\n"
#, perl-format
msgid "fatal: command '%s' died with exit code %d"
-msgstr "ödesdigert: kommandot \"%s\" dog med slutkoden %d"
+msgstr "ödesdigert: kommandot â€%s†dog med slutkoden %d"
msgid "the editor exited uncleanly, aborting everything"
msgstr "textredigeringsprogrammet avslutades med fel, avbryter allting"
@@ -22076,24 +22905,26 @@ msgstr "textredigeringsprogrammet avslutades med fel, avbryter allting"
#, perl-format
msgid ""
"'%s' contains an intermediate version of the email you were composing.\n"
-msgstr ""
-"\"%s\" innehåller en mellanliggande version av e-postbrevet du skrev.\n"
+msgstr "â€%s†innehÃ¥ller en mellanliggande version av e-postbrevet du skrev.\n"
#, perl-format
msgid "'%s.final' contains the composed email.\n"
-msgstr "\"%s.final\" innehåller det skrivna brevet.\n"
+msgstr "â€%s.final†innehÃ¥ller det skrivna brevet.\n"
msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases är inkompatibelt med andra flaggor\n"
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases och --translate-aliases är ömsesidigt utelsutande\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 ""
-"ödesdigert: hittade konfigurationsflaggor för \"sendmail\"\n"
-"git-send-email konfigureras med \"sendemail.*\"-flaggor - lägg märke till \"e"
-"\".\n"
+"ödesdigert: hittade konfigurationsflaggor för â€sendmailâ€\n"
+"git-send-email konfigureras med â€sendemail.*â€-flaggor - lägg märke till "
+"â€eâ€.\n"
"Sätt sendemail.forbidSendmailVariables till false för att inaktivera denna "
"kontroll.\n"
@@ -22104,16 +22935,16 @@ msgid ""
"`batch-size` and `relogin` must be specified together (via command-line or "
"configuration option)\n"
msgstr ""
-"\"batch-size\" och \"relogin\" måste anges tillsammans (via kommandorad "
-"eller konfigurationsflagga)\n"
+"â€batch-size†och â€relogin†mÃ¥ste anges tillsammans (via kommandorad eller "
+"konfigurationsflagga)\n"
#, perl-format
msgid "Unknown --suppress-cc field: '%s'\n"
-msgstr "Okänt fält i --suppress-cc: \"%s\"\n"
+msgstr "Okänt fält i --suppress-cc: â€%sâ€\n"
#, perl-format
msgid "Unknown --confirm setting: '%s'\n"
-msgstr "Okänd inställning i --confirm: \"%s\"\n"
+msgstr "Okänd inställning i --confirm: â€%sâ€\n"
#, perl-format
msgid "warning: sendmail alias with quotes is not supported: %s\n"
@@ -22121,11 +22952,11 @@ msgstr "varning: sendmail-alias med citationstecken stöds inte. %s\n"
#, perl-format
msgid "warning: `:include:` not supported: %s\n"
-msgstr "varning: \":include:\" stöds inte: %s\n"
+msgstr "varning: â€:include:†stöds inte: %s\n"
#, perl-format
msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
-msgstr "varning: omdirigering til \"/fil\" eller \"|rör\" stöds inte: %s\n"
+msgstr "varning: omdirigering til â€/fil†eller â€|rör†stöds inte: %s\n"
#, perl-format
msgid "warning: sendmail line is not recognized: %s\n"
@@ -22139,10 +22970,10 @@ msgid ""
" * Saying \"./%s\" if you mean a file; or\n"
" * Giving --format-patch option if you mean a range.\n"
msgstr ""
-"Filen \"%s\" finns men kan också vara ett incheckningsintervall\n"
+"Filen â€%s†finns men kan ocksÃ¥ vara ett incheckningsintervall\n"
"att skapa patchar för. Gör otvetydigt genom att...\n"
"\n"
-" * Säga \"./%s\" om du menar en fil; eller\n"
+" * Säga â€./%s†om du menar en fil; eller\n"
" * Ange flaggan --format-patch om du menar ett intervall.\n"
#, perl-format
@@ -22164,7 +22995,7 @@ msgstr "Ingen ärenderad i %s?"
#, perl-format
msgid "Failed to open for writing %s: %s"
-msgstr "Kunde inte öppna för skrivning %s: %s"
+msgstr "Misslyckades öppna för skrivning %s: %s"
msgid ""
"Lines beginning in \"GIT:\" will be removed.\n"
@@ -22173,20 +23004,20 @@ msgid ""
"\n"
"Clear the body content if you don't wish to send a summary.\n"
msgstr ""
-"Rader som börjar med \"GIT:\" kommer tas bort.\n"
+"Rader som börjar med â€GIT:†kommer tas bort.\n"
"Överväg att ta med en övergripande diffstatus eller\n"
"innehållsförteckning för patchen du skriver.\n"
"\n"
"Rensa brevkroppen om du inte vill sända någon sammanfattning.\n"
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "Misslyckades öppna %s: %s"
-
-#, perl-format
msgid "Failed to open %s.final: %s"
msgstr "Misslyckades öppna %s.final: %s"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "Misslyckades öppna %s: %s"
+
msgid "Summary email is empty, skipping it\n"
msgstr "Sammanfattande brev tomt, hoppar över\n"
@@ -22213,15 +23044,15 @@ msgid ""
msgstr ""
"Vägrar sända eftersom patchen\n"
"\t%s\n"
-"har mallärendet \"*** SUBJECT HERE ***\". Använd --force om du verkligen "
-"vill sända.\n"
+"har mallärendet â€*** SUBJECT HERE ***â€. Använd --force om du verkligen vill "
+"sända.\n"
msgid "To whom should the emails be sent (if anyone)?"
msgstr "Till vem ska breven sändas (om någon)?"
#, perl-format
msgid "fatal: alias '%s' expands to itself\n"
-msgstr "ödesdigert: aliaset \"%s\" expanderar till sig själv\n"
+msgstr "ödesdigert: aliaset â€%s†expanderar till sig själv\n"
msgid "Message-ID to be used as In-Reply-To for the first email (if any)? "
msgstr ""
@@ -22229,7 +23060,7 @@ msgstr ""
#, perl-format
msgid "error: unable to extract a valid address from: %s\n"
-msgstr "fel: kunde inte få fram en giltig adress från: %s\n"
+msgstr "fel: kan inte få fram en giltig adress från: %s\n"
#. TRANSLATORS: Make sure to include [q] [d] [e] in your
#. translation. The program will only accept English input
@@ -22239,7 +23070,7 @@ msgstr "Vad vill du göra med adressen? (q=avsluta, d=kasta, e=redigera): "
#, perl-format
msgid "CA path \"%s\" does not exist"
-msgstr "CA-sökvägen \"%s\" finns inte"
+msgstr "CA-sökvägen â€%s†finns inte"
msgid ""
" The Cc list above has been expanded by additional\n"
@@ -22259,9 +23090,9 @@ msgstr ""
" Beteendet styrs av konfigurationsinställningen\n"
" sendemail.confirm\n"
"\n"
-" För ytterligare information, kör \"git send-email --help\".\n"
+" För ytterligare information, kör â€git send-email --helpâ€.\n"
" För att behålla nuvarande beteende, men dölja detta\n"
-" meddelande, kör \"git config --global sendemail.confirm auto\".\n"
+" meddelande, kör â€git config --global sendemail.confirm autoâ€.\n"
"\n"
#. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
@@ -22271,7 +23102,7 @@ msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
msgstr "Sända brevet? (y=ja, n=nej, e=redigera, q=avsluta, a=alla): "
msgid "Send this email reply required"
-msgstr "Svar krävs på frågan \"Sända brevet?\""
+msgstr "Svar krävs pÃ¥ frÃ¥gan â€Sända brevet?â€"
msgid "The required SMTP server is not properly defined."
msgstr "Nödvändig SMTP-server har inte angivits korrekt."
@@ -22294,24 +23125,24 @@ msgid "Failed to send %s\n"
msgstr "Misslyckades sända %s\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Test-Sände %s\n"
+msgid "Dry-Sent %s"
+msgstr "Test-Sände %s"
#, perl-format
-msgid "Sent %s\n"
-msgstr "Sände %s\n"
+msgid "Sent %s"
+msgstr "Sände %s"
-msgid "Dry-OK. Log says:\n"
-msgstr "Test-OK. Loggen säger:\n"
+msgid "Dry-OK. Log says:"
+msgstr "Test-OK. Loggen säger:"
-msgid "OK. Log says:\n"
-msgstr "OK. Loggen säger:\n"
+msgid "OK. Log says:"
+msgstr "OK. Loggen säger:"
msgid "Result: "
msgstr "Resultat: "
-msgid "Result: OK\n"
-msgstr "Resultat: OK\n"
+msgid "Result: OK"
+msgstr "Resultat: OK"
#, perl-format
msgid "can't open file %s"
@@ -22319,35 +23150,35 @@ msgstr "kan inte öppna filen %s"
#, perl-format
msgid "(mbox) Adding cc: %s from line '%s'\n"
-msgstr "(mbox) Lägger till cc: %s från raden \"%s\"\n"
+msgstr "(mbox) Lägger till cc: %s frÃ¥n raden â€%sâ€\n"
#, perl-format
msgid "(mbox) Adding to: %s from line '%s'\n"
-msgstr "(mbox) Lägger till to: %s från raden \"%s\"\n"
+msgstr "(mbox) Lägger till to: %s frÃ¥n raden â€%sâ€\n"
#, perl-format
msgid "(non-mbox) Adding cc: %s from line '%s'\n"
-msgstr "(icke-mbox) Lägger till cc: %s från raden \"%s\"\n"
+msgstr "(icke-mbox) Lägger till cc: %s frÃ¥n raden â€%sâ€\n"
#, perl-format
msgid "(body) Adding cc: %s from line '%s'\n"
-msgstr "(kropp) Lägger till cc: %s från raden \"%s\"\n"
+msgstr "(kropp) Lägger till cc: %s frÃ¥n raden â€%sâ€\n"
#, perl-format
msgid "(%s) Could not execute '%s'"
-msgstr "(%s) Kunde inte köra \"%s\""
+msgstr "(%s) Kunde inte köra â€%sâ€"
#, perl-format
msgid "(%s) Malformed output from '%s'"
-msgstr "(%s) Felformaterad utdata från \"%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\""
+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"
+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"
@@ -22367,7 +23198,7 @@ msgstr ""
#, perl-format
msgid "unable to open %s: %s\n"
-msgstr "kunde inte öppna %s: %s\n"
+msgstr "kan inte öppna %s: %s\n"
#, perl-format
msgid ""
@@ -22380,10 +23211,16 @@ msgstr ""
#, perl-format
msgid "Skipping %s with backup suffix '%s'.\n"
msgstr ""
-"Hoppar över %s med filnamnstillägget \"%s\" som används för "
-"säkerhetskopior.\n"
+"Hoppar över %s med filnamnstillägget â€%s†som används för säkerhetskopior.\n"
#. TRANSLATORS: please keep "[y|N]" as is.
#, perl-format
msgid "Do you really want to send %s? [y|N]: "
msgstr "Vill du verkligen sända %s? [y=ja, n=nej]: "
+
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "misslyckades starta revisionstraversering\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "kan inte tolka kontakt: %s"
diff --git a/po/tr.po b/po/tr.po
index bc3acbcc84..7aede5cd5f 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -1,8 +1,8 @@
# Turkish translations for Git
# Git Türkçe çevirileri
-# Copyright (C) 2020-2023 Emir SARI <emir_sari@icloud.com>
+# Copyright (C) 2020-2024 Emir SARI <emir_sari@icloud.com>
# This file is distributed under the same license as the Git package.
-# Emir SARI <emir_sari@icloud.com>, 2020-2023
+# Emir SARI <emir_sari@icloud.com>, 2020-2024
#
# ######################################################### #
# Git Türkçe kavramlar dizini / Git Turkish Glossary #
@@ -20,13 +20,14 @@
# clone | klon(lamak) #
# commit (ad) | iÅŸleme #
# commit (eyl.) | iÅŸlemek #
-# commitish | iÅŸlememsi #
+# commit-ish | iÅŸlememsi #
# conflict | çakışma #
# cruft | süprüntü #
# dangling object | sallanan nesne #
# detached HEAD | ayrık HEAD #
# dirty | kirli #
# evil merge | uÄŸursuz birleÅŸtirme #
+# fanout | çıkış sayısı #
# fast-forward | ileri sarım/sarmak #
# fetch | getirme(k) #
# fixup | düzeltmek #
@@ -48,10 +49,10 @@
# pathspec | yol belirteci #
# pattern | dizgi #
# porcelain | okunabilir #
-# prune | budamak #
-# pseudoref | yalancıktan başvuru #
-# pull | çekme(k) #
-# push | itme(k) #
+# prune | buda(mak) #
+# pseudoref | yalancı başvuru #
+# pull | çek(mek) #
+# push | it(mek) #
# rebase | yeniden temellendirme(k) #
# record | kayıt yaz(mak) #
# ref | baÅŸvuru #
@@ -85,6 +86,7 @@
# trailer | artbilgi #
# tree | ağaç #
# treeish | ağacımsı #
+# unborn | henüz doğmamış (dal) #
# unstage | hazırlıktan çıkar(mak) #
# upstream | üstkaynak #
# worktree/working tree | çalışma ağacı #
@@ -94,8 +96,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-08-16 14:34+0300\n"
-"PO-Revision-Date: 2023-08-16 15:00+0300\n"
+"POT-Creation-Date: 2024-10-03 06:52+0300\n"
+"PO-Revision-Date: 2024-10-03 07: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"
@@ -578,12 +580,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"'%c' satır kaldırmak için onları ' ' satır yapın (bağlam).\n"
"'%c' satır kaldırmak için onları silin.\n"
-"%c kaldırılacak.\n"
+"%s ile başlayan satırlar kaldırılacak.\n"
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
@@ -630,6 +632,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j - bu parça için sonra karar ver, bir sonraki karar verilmemiş parçayı gör\n"
@@ -639,9 +642,14 @@ msgstr ""
"g - gidilecek bir parça seç\n"
"/ - verilen düzenli ifade ile eşleşen bir parça ara\n"
"s - geçerli parçayı daha ufak parçalara böl\n"
-"e - geçerli parçayı el ile düzenle\n"
+"e - geçerli parçayı elle düzenle\n"
+"p - geçerli parçalı yazdır, sayfalayıcı için 'P' kullan\n"
"? - yardımı yazdır\n"
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "Yalnızca bir harf bekleniyordu, '%s' alındı"
+
msgid "No previous hunk"
msgstr "Öncesinde parça yok"
@@ -690,9 +698,19 @@ msgstr "%d parçaya bölündü."
msgid "Sorry, cannot edit this hunk"
msgstr "Üzgünüm, bu parça düzenlenemiyor"
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Bilinmeyen komut '%s' (yardım için '?')"
+
msgid "'git apply' failed"
msgstr "'git apply' başarısız oldu"
+msgid "No changes."
+msgstr "DeÄŸiÅŸiklik yok."
+
+msgid "Only binary files changed."
+msgstr "Yalnızca ikili dosyalar değiştirildi."
+
#, c-format
msgid ""
"\n"
@@ -702,8 +720,8 @@ msgstr ""
"Bu iletiyi \"git config advice.%s false\" ile devre dışı bırakın"
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sipucu: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sipucu: %s%.*s%s\n"
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr "Seç-al yapılamaz; birleştirmesi tamamlanmamış dosyalarınız var."
@@ -1201,10 +1219,6 @@ msgstr[0] "%%s yaması %d geri çevirme ile uygulanıyor..."
msgstr[1] "%%s yaması %d geri çevirme ile uygulanıyor..."
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr ".rej dosya adı %.*s.rej olarak kısaltılıyor"
-
-#, c-format
msgid "cannot open %s"
msgstr "%s açılamıyor"
@@ -1300,6 +1314,15 @@ msgstr "ek olarak yamayı da uygula (--stat/--summary/--check ile kullan)"
msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr "3 yönlü birleştirme dene, başarısız olursa normal yamaya geri çekil"
+msgid "for conflicts, use our version"
+msgstr "çakışmalarda bizim sürümü kullan"
+
+msgid "for conflicts, use their version"
+msgstr "çakışmalarda onların sürümünü kullan"
+
+msgid "for conflicts, use a union version"
+msgstr "çakışmalarda birlik olmuş bir sürüm kullan"
+
msgid "build a temporary index based on embedded index information"
msgstr "gömülü indeks bilgisini temel alan geçici bir indeks oluştur"
@@ -1345,6 +1368,9 @@ msgstr "tüm dosya adlarının başına <kök> ekle"
msgid "don't return error for empty patches"
msgstr "boş yamalar için hata döndürme"
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs ve --union; --3way gerektiriyor"
+
#, c-format
msgid "cannot stream blob %s"
msgstr "%s ikili nesnesi akıtılamıyor"
@@ -1415,6 +1441,9 @@ msgstr "geçerli bir nesne adı değil: %s"
msgid "not a tree object: %s"
msgstr "bir ağaç nesnesi değil: %s"
+msgid "unable to checkout working tree"
+msgstr "çalışma ağacı çıkış yapılamıyor"
+
#, c-format
msgid "File not found: %s"
msgstr "Dosya bulunamadı: %s"
@@ -1500,6 +1529,10 @@ msgid "Unexpected option --output"
msgstr "Beklenmedik seçenek --output"
#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "fazladan komut satırı parametresi '%s'"
+
+#, c-format
msgid "Unknown archive format '%s'"
msgstr "Bilinmeyen arşiv biçimi '%s'"
@@ -1541,10 +1574,21 @@ 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 "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "depo olmadan --attr-source veya GIT_ATTR_SOURCE kullanılamaz"
+
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "hatalı --attr-source veya GIT_ATTR_SOURCE"
#, c-format
+msgid "unable to stat '%s'"
+msgstr "'%s' dosyasının bilgileri alınamıyor"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "%s okunamıyor"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "'%s' dosyasında hatalı tırnağa alınmış içerik: %s"
@@ -1613,6 +1657,10 @@ msgid "could not create file '%s'"
msgstr "'%s' dosyası oluşturulamadı"
#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "'%s' nesnesi için 'show' başlatılamıyor"
+
+#, c-format
msgid "could not read file '%s'"
msgstr "'%s' dosyası okunamadı"
@@ -1764,6 +1812,9 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "'%s' geçerli bir dal adı değil"
+msgid "See `man git check-ref-format`"
+msgstr "'man git check-ref-format' kılavuz sayfasına bakın"
+
#, c-format
msgid "a branch named '%s' already exists"
msgstr "'%s' adında bir dal halihazırda var"
@@ -1830,8 +1881,8 @@ msgid "submodule '%s': cannot create branch '%s'"
msgstr "'%s' altmodülü: '%s' dalı oluşturulamıyor"
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "'%s' çıkışı '%s' konumunda halihazırda yapılmış"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "'%s', '%s' konumunda halihazırda çalışma ağacı tarafından kullanılıyor"
msgid "git add [<options>] [--] <pathspec>..."
msgstr "git add [<seçenekler>] [--] <yol-blrtç>..."
@@ -1843,31 +1894,21 @@ msgstr "%cx '%s' chmod yapılamıyor"
msgid "Unstaged changes after refreshing the index:"
msgstr "İndeksi yeniledikten sonra hazırlanmamış değişiklikler:"
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"add.interactive.useBuiltin ayarı kaldırıldı!\n"
-"Ayrıntılar için onun 'git help config' içindeki girdisine bakın."
-
-msgid "Could not read the index"
-msgstr "İndeks okunamadı"
-
-msgid "Could not write patch"
-msgstr "Yama yazılamadı"
+msgid "could not read the index"
+msgstr "indeks okunamadı"
msgid "editing patch failed"
msgstr "yamayı düzenleme başarısız"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "'%s' dosya bilgileri alınamadı"
+msgid "could not stat '%s'"
+msgstr "'%s' bilgileri alınamadı"
-msgid "Empty patch. Aborted."
-msgstr "Boş yama. İptal edildi."
+msgid "empty patch. aborted"
+msgstr "boÅŸ yama. iptal edildi."
#, c-format
-msgid "Could not apply '%s'"
+msgid "could not apply '%s'"
msgstr "'%s' uygulanamadı"
msgid "The following paths are ignored by one of your .gitignore files:\n"
@@ -1962,14 +2003,8 @@ msgstr ""
msgid "adding embedded git repository: %s"
msgstr "gömülü git deposu ekleniyor: %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 ""
-"Gerçekten eklemek istiyorsanız -f kullanın.\n"
-"Bu iletiyi 'git config advice.addIgnoredFile false'\n"
-"yaparak kapatabilirsiniz"
+msgid "Use -f if you really want to add them."
+msgstr "Onları eklemeyi gerçekten istiyorsanız -f kullanın."
msgid "adding files failed"
msgstr "dosya ekleme başarısız"
@@ -1986,18 +2021,15 @@ msgstr "'%s' ve yol belirteci argümanları birlikte kullanılamaz"
msgid "Nothing specified, nothing added.\n"
msgstr "Hiçbir şey belirtilmedi, hiçbir şey eklenmedi.\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 .' mı demek istediniz?\n"
-"Bu iletiyi 'git config advice.addEmptyPathspec false'\n"
-"yaparak kapatabilirsiniz"
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "'git add .' mi demek istediniz?"
msgid "index file corrupt"
msgstr "indeks dosyası hasarlı"
+msgid "unable to write new index file"
+msgstr "yeni indeks dosyası yazılamıyor"
+
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "hatalı eylem '%s', '%s' için"
@@ -2067,24 +2099,25 @@ msgid "Failed to split patches."
msgstr "Yamalar parçalanıp bölünemedi."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Bu sorunu çözdüğünüzde \"%s --continue\" çalıştırın."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "Bu sorunu çözdüğünüzde \"%s --continue\" çalıştırın.\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "Eğer bu yamayı atlamayı yeğliyorsanız \"%s --skip\" çalıştırın."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr "Eğer bu yamayı atlamayı yeğliyorsanız \"%s --skip\" çalıştırın.\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
"Boş yamayı boş işleme kaydı olarak yazmak için \"%s --allow-empty\" "
-"çalıştırın."
+"çalıştırın.\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
msgstr ""
"İlk dalı eski durumuna getirip yamalamayı durdurmak için \"%s --abort\" "
-"çalıştır."
+"çalıştırın."
msgid "Patch sent with format=flowed; space at the end of lines might be lost."
msgstr ""
@@ -2206,9 +2239,6 @@ msgstr ""
"Bir dosyanın \"onlar sildi\" olduğunu kabul etmek için dosya ile 'git rm' "
"yapabilirsiniz."
-msgid "unable to write new index file"
-msgstr "yeni indeks dosyası yazılamıyor"
-
#, c-format
msgid "Could not parse object '%s'."
msgstr "'%s' nesnesi ayrıştırılamadı."
@@ -2227,10 +2257,6 @@ msgstr ""
msgid "failed to read '%s'"
msgstr "'%s' okunamadı"
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "'%s=%s' ve '%s=%s' seçenekleri birlikte kullanılamaz"
-
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<seçenekler>] [(<mbox> | <posta-dizin>)...]"
@@ -2309,6 +2335,9 @@ msgstr "yamalama işlemini iptal et; ancak HEAD'i olduğu yerde bırak"
msgid "show the patch being applied"
msgstr "uygulanmakta olan yamayı göster"
+msgid "try to apply current patch again"
+msgstr "yeniden geçerli yamayı uygulamaya çalış"
+
msgid "record the empty patch as an empty commit"
msgstr "boş yamayı bir boş işleme olarak kayıt yaz"
@@ -2365,9 +2394,6 @@ msgstr "git apply [<seçenekler>] [<yama>...]"
msgid "could not redirect output"
msgstr "çıktı yeniden yönlendirilemedi"
-msgid "git archive: Remote with no URL"
-msgstr "git archive: URL'si olmayan uzak konum"
-
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive: ACK/NAK bekleniyordu, floş paketi alındı"
@@ -2382,11 +2408,11 @@ msgid "git archive: expected a flush"
msgstr "git archive: FloÅŸ bekleniyordu"
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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}=<terim> --term-{old,good}=<terim>] [--"
-"no-checkout] [--first-parent] [<kötü> [<iyi>...]] [--] [<yol-blrtç>...]"
+"git bisect start [--term-(new|bad)=<uçbirim> --term-(old|good)=<uçbirim>] "
+"[--no-checkout] [--first-parent] [<kötü> [<iyi>...]] [--] [<yol-blrtç>...]"
msgid "git bisect (good|bad) [<rev>...]"
msgstr "git bisect (good|bad) [<rev>...]"
@@ -2400,8 +2426,8 @@ msgstr "git bisect reset [<iÅŸleme>]"
msgid "git bisect replay <logfile>"
msgstr "git bisect replay <günlük-dosyası>"
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <komut>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <komut> [<argüman>...]"
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2520,9 +2546,6 @@ msgstr ""
"'git bisect terms' için geçersiz argüman %s.\n"
"Desteklenen seçenekler: --term-good|--term-old ve --term-bad|--term-new."
-msgid "revision walk setup failed\n"
-msgstr "revizyonda gezinme ayarlaması başarısız oldu\n"
-
#, c-format
msgid "could not open '%s' for appending"
msgstr "'%s' iliştirme için açılamadı"
@@ -2812,7 +2835,7 @@ msgstr "git branch [<seçenekler>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
"'%s' dalı siliniyor: Bu dal '%s'\n"
" dalına birleştirilmiş; ancak HEAD'e henüz birleştirilmemiş."
@@ -2820,36 +2843,37 @@ msgstr ""
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
"'%s' dalı silinmiyor: Bu dal HEAD'e birleştirilmiş olmasına rağmen\n"
" '%s' dalına birleştirilmemiş."
#, c-format
-msgid "Couldn't look up commit object for '%s'"
+msgid "couldn't look up commit object for '%s'"
msgstr "'%s' için işleme nesnesi aranamadı"
#, 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' dalı tümüyle birleştirilmemiş.\n"
-"Eğer silmek istediğinizden eminseniz 'git branch -D %s' çalıştırın."
+msgid "the branch '%s' is not fully merged"
+msgstr "'%s' dalı tümüyle birleştirilmedi"
+
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "Onu silmek istediğinizden eminseniz 'git branch -D %s' çalıştırın."
-msgid "Update of config-file failed"
-msgstr "config-file güncellemesi başarısız"
+msgid "update of config-file failed"
+msgstr "config-file güncellenemedi"
msgid "cannot use -a with -d"
msgstr "-a, -d ile kullanılamıyor"
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "'%s' dalı silinemiyor, şurada çıkış yapılmış: '%s'"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"'%s' konumundaki çalışma ağacı tarafından kullanılan '%s' dalı silinemiyor"
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "Uzak izleme dalı '%s' bulunamadı."
+msgid "remote-tracking branch '%s' not found"
+msgstr "uzak izleme dalı '%s' bulunamadı"
#, c-format
msgid ""
@@ -2860,8 +2884,8 @@ msgstr ""
"--remote yazmayı mı unuttunuz?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "'%s' dalı bulunamadı."
+msgid "branch '%s' not found"
+msgstr "'%s' dalı bulunamadı"
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -2882,11 +2906,11 @@ msgid "HEAD (%s) points outside of refs/heads/"
msgstr "HEAD (%s), refs/heads/ dışına işaret ediyor"
#, c-format
-msgid "Branch %s is being rebased at %s"
+msgid "branch %s is being rebased at %s"
msgstr "%s dalı %s konumunda yeniden temellendiriliyor"
#, c-format
-msgid "Branch %s is being bisected at %s"
+msgid "branch %s is being bisected at %s"
msgstr "%s dalı %s konumunda ikili aranıyor"
#, c-format
@@ -2894,50 +2918,50 @@ 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'"
+msgid "invalid branch name: '%s'"
+msgstr "geçersiz dal adı: '%s'"
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "'%s' dalında henüz bir işleme yok."
+msgid "no commit on branch '%s' yet"
+msgstr "'%s' dalında henüz bir işleme yok"
#, c-format
-msgid "No branch named '%s'."
-msgstr "'%s' adında bir dal yok."
+msgid "no branch named '%s'"
+msgstr "'%s' adında bir dal yok"
-msgid "Branch rename failed"
-msgstr "Dal yeniden adlandırması başarısız"
+msgid "branch rename failed"
+msgstr "dal yeniden adlandırılamadı"
-msgid "Branch copy failed"
-msgstr "Dal kopyalaması başarısız"
+msgid "branch copy failed"
+msgstr "dal kopyalanamadı"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Yanlış adlandırılan '%s' dalının bir kopyası oluşturuldu"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "yanlış adlandırılan '%s' dalının bir kopyası oluşturuldu"
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Yanlış adlandırılan '%s' dalı yeniden adlandırıldı"
+msgid "renamed a misnamed branch '%s' away"
+msgstr "yanlış adlandırılan '%s' dalı yeniden adlandırıldı"
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "Dal %s olarak yeniden adlandırıldı; ancak HEAD güncellenmedi!"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "dal %s olarak yeniden adlandırıldı; ancak HEAD güncellenmedi!"
-msgid "Branch is renamed, but update of config-file failed"
-msgstr "Dal yeniden adlandırıldı; ancak config-file güncellemesi başarısız"
+msgid "branch is renamed, but update of config-file failed"
+msgstr "dal yeniden adlandırıldı; ancak config-file güncellenemedi"
-msgid "Branch is copied, but update of config-file failed"
-msgstr "Dal kopyalandı; ancak config-file güncellemesi başarısız"
+msgid "branch is copied, but update of config-file failed"
+msgstr "dal kopyalandı; ancak config-file güncellenemedi"
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
-"Lütfen dal açıklamasını düzenleyin:\n"
+"Lütfen dal açıklamasını düzenleyin\n"
"\t%s\n"
-"'%c' ile başlayan satırlar çıkarılacaktır.\n"
+"'%s' ile başlayan satırlar soyulacaktır.\n"
msgid "Generic options"
msgstr "Genel seçenekler"
@@ -3041,8 +3065,8 @@ msgstr "altmodüller içinden özyinele"
msgid "format to use for the output"
msgstr "çıktı için kullanılacak biçim"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "HEAD geçerli bir başvuru olarak çözülemedi."
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "HEAD geçerli bir başvuru olarak çözülemedi"
msgid "HEAD not found below refs/heads!"
msgstr "HEAD, refs/heads altında bulunamadı!"
@@ -3060,17 +3084,17 @@ msgstr "--recurse-submodules, yalnızca dal oluşturmada kullanılabilir"
msgid "branch name required"
msgstr "dal adı gerekli"
-msgid "Cannot give description to detached HEAD"
-msgstr "Ayrılmış HEAD'e açıklama verilemiyor"
+msgid "cannot give description to detached HEAD"
+msgstr "ayrık HEAD'e açıklama verilemiyor"
msgid "cannot edit description of more than one branch"
msgstr "birden çok dalın açıklaması düzenlenemiyor"
-msgid "cannot copy the current branch while not on any."
-msgstr "Bir dalın üzerinde değilken geçerli dal kopyalanamaz."
+msgid "cannot copy the current branch while not on any"
+msgstr "bir dalın üzerinde değilken geçerli dal kopyalanamaz"
-msgid "cannot rename the current branch while not on any."
-msgstr "Bir dalın üzerinde değilken geçerli dal yeniden adlandırılamaz."
+msgid "cannot rename the current branch while not on any"
+msgstr "bir dalın üzerinde değilken geçerli dal yeniden adlandırılamaz"
msgid "too many branches for a copy operation"
msgstr "bir kopyalama işlemi için pek fazla dal"
@@ -3083,10 +3107,10 @@ msgstr "yeni üstkaynak ayarlamak için pek fazla argüman"
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
"HEAD'in üst kaynağı %s olarak ayarlanamadı; çünkü herhangi bir dala işaret "
-"etmiyor."
+"etmiyor"
#, c-format
msgid "no such branch '%s'"
@@ -3099,16 +3123,16 @@ msgstr "'%s' diye bir dal yok"
msgid "too many arguments to unset upstream"
msgstr "üst kaynağı kaldırmak için pek fazla argüman"
-msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
msgstr ""
-"HEAD'in üst kaynağı kaldırılamadı; çünkü herhangi bir dala işaret etmiyor."
+"HEAD'in üst kaynağı kaldırılamadı; çünkü herhangi bir dala işaret etmiyor"
#, c-format
-msgid "Branch '%s' has no upstream information"
+msgid "branch '%s' has no upstream information"
msgstr "'%s' dalının üstkaynak bilgisi yok"
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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'in -a ve -r seçenekleri bir dal adı almaz.\n"
@@ -3116,10 +3140,10 @@ msgstr ""
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
"--set-upstream seçeneği artık desteklenmiyor. Lütfen --track veya --set-"
-"upstream-to kullanın."
+"upstream-to kullanın"
msgid "git version:\n"
msgstr "git sürümü:\n"
@@ -3138,10 +3162,12 @@ msgid "not run from a git repository - no hooks to show\n"
msgstr "bir git deposundan çalıştırılmadı - gösterilecek kanca yok\n"
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <yol>] [(-s | --suffix) <biçim>]\n"
+"git bugreport [(-o | --output-directory) <yol>]\n"
+" [(-s | --suffix) <biçim> | --no-suffix]\n"
" [--diagnose[=<kip>]]"
msgid ""
@@ -3192,6 +3218,10 @@ msgid "specify a strftime format suffix for the filename(s)"
msgstr "dosya adları için bir strftime biçim soneki belirtin"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "bilinmeyen argüman '%s'"
+
+#, c-format
msgid "could not create leading directories for '%s'"
msgstr "'%s' için öncü dizinler oluşturulamadı"
@@ -3253,6 +3283,9 @@ msgstr "Bir demet oluşturmak için bir depo gerekli."
msgid "do not show bundle details"
msgstr "demet ayrıntılarını gösterme"
+msgid "need a repository to verify a bundle"
+msgstr "bir demeti doğrulamak için bir depo gerekiyor"
+
#, c-format
msgid "%s is okay\n"
msgstr "%s tamam\n"
@@ -3298,6 +3331,13 @@ msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <nesne>"
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<başvuru>:<yol|ağacımsı> | --path=<yol|ağacımsı> <revizyon>]"
+
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -3308,13 +3348,6 @@ msgstr ""
" [--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"
-" [<başvuru>:<yol|ağacımsı> | --path=<yol|ağacımsı> <revizyon>]"
-
msgid "Check object existence or emit object contents"
msgstr "Nesne varlığını denetle veya nesne içeriğini yay"
@@ -3487,9 +3520,14 @@ msgstr "git check-mailmap [<seçenekler>] <kişi>..."
msgid "also read contacts from stdin"
msgstr "stdin'den kiÅŸileri de oku"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "kişi ayrıştırılamadı: %s"
+msgid "read additional mailmap entries from file"
+msgstr "dosyadan ek mailmap girdilerini oku"
+
+msgid "blob"
+msgstr "ikili nesne"
+
+msgid "read additional mailmap entries from blob"
+msgstr "ikili nesneden ek mailmap girdilerini oku"
msgid "no contacts specified"
msgstr "kiÅŸi belirtilmedi"
@@ -3611,9 +3649,17 @@ msgid "'%s' or '%s' cannot be used with %s"
msgstr "'%s' veya '%s', %s ile birlikte kullanılamaz"
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "'%s', '%s' veya '%s' bir ağaçtan çıkış yaparken kullanılamaz"
+
+#, c-format
msgid "path '%s' is unmerged"
msgstr "'%s' yolu birleÅŸtirilmemiÅŸ"
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "ağaç okunamıyor (%s)"
+
msgid "you need to resolve your current index first"
msgstr "önce geçerli indeksinizi çözmelisiniz"
@@ -3829,6 +3875,10 @@ msgid "'%s' cannot be used with switching branches"
msgstr "dal değiştirilirken '%s' kullanılamaz"
#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "çıkış yapmak için '%s' yollara gereksinim duyuyor"
+
+#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s', '%s' ile birlikte kullanılamaz"
@@ -3843,6 +3893,10 @@ msgstr "Dal, işleme olmayan '%s' ögesine değiştirilemez"
msgid "missing branch or commit argument"
msgstr "dal veya işleme argümanı eksik"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "bilinmeyen çakışma stili '%s'"
+
msgid "perform a 3-way merge with the new branch"
msgstr "yeni dal ile bir 3 yönlü birleştirme gerçekleştir"
@@ -3861,8 +3915,8 @@ msgstr "zorla çıkış yap (yerel değişiklikleri çöpe at)"
msgid "new-branch"
msgstr "yeni dal"
-msgid "new unparented branch"
-msgstr "yeni üst ögesi olmayan dal"
+msgid "new unborn branch"
+msgstr "yeni henüz doğmamış dal"
msgid "update ignored files (default)"
msgstr "yok sayılan dosyaları güncelle (öntanımlı)"
@@ -4099,22 +4153,10 @@ msgstr "yok sayılan dosyalar da kaldırıldı"
msgid "remove only ignored files"
msgstr "yalnızca yok sayılan dosyaları kaldır"
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"clean.requireForce 'true' olarak ayarlanmış ve ne -i ne -n ne de -f "
-"verilmiÅŸ; temizleme reddediliyor"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce öntanımlı olarak 'true' ve ne -i ne -n ne de -f verilmiş; "
-"temizleme reddediliyor"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x ve -X birlikte kullanılamaz"
+"clean.requireForce 'true' olarak ayarlı ve -f verilmedi; temizlik "
+"reddediliyor"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<seçenekler>] [--] <depo> [<dizin>]"
@@ -4128,8 +4170,8 @@ msgstr "çıkış yapma!"
msgid "create a bare repository"
msgstr "çıplak bir depo oluştur"
-msgid "create a mirror repository (implies bare)"
-msgstr "bir yansı depo oluştur (çıplak ima eder)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "bir yansı depo oluştur (--bare ima eder)"
msgid "to clone from a local repository"
msgstr "bir yerel depodan klonla"
@@ -4203,6 +4245,9 @@ msgstr "git dizini"
msgid "separate git dir from working tree"
msgstr "git dizinini çalışma ağacından ayır"
+msgid "specify the reference format to use"
+msgstr "kullanılacak başvuru biçimini belirt"
+
msgid "key=value"
msgstr "anahtar=deÄŸer"
@@ -4246,7 +4291,7 @@ 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"
+msgstr "'%s' bir sembolik baÄŸ; --local ile klonlama reddediliyor"
#, c-format
msgid "failed to start iterator over '%s'"
@@ -4254,13 +4299,21 @@ msgstr "yineleyici '%s' üzerinden çalıştırılamadı"
#, c-format
msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "'%s' sembolik bağlantısı var, --local ile klonlama reddediliyor"
+msgstr "'%s' sembolik bağı var, --local ile klonlama reddediliyor"
#, c-format
msgid "failed to unlink '%s'"
msgstr "'%s' bağlantısı kesilemedi"
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "sabit bağlantı, '%s' konumunda denetlenemiyor"
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "sabit bağlantı, '%s' konumundaki kaynaktan farklı"
+
+#, c-format
msgid "failed to create link '%s'"
msgstr "'%s' bağı oluşturulamadı"
@@ -4302,9 +4355,6 @@ msgstr "sparse-checkout ilklendirilemedi"
msgid "remote HEAD refers to nonexistent ref, unable to checkout"
msgstr "uzak konum HEAD'i, var olmayan başvuruya başvuruyor; çıkış yapılamıyor"
-msgid "unable to checkout working tree"
-msgstr "çalışma ağacı çıkış yapılamıyor"
-
msgid "unable to write parameters to config file"
msgstr "parametreler yapılandırma dosyasına yazılamıyor"
@@ -4320,11 +4370,9 @@ msgstr "Çok fazla argüman."
msgid "You must specify a repository to clone."
msgstr "Klonlamak için bir depo belirtmelisiniz."
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr ""
-"--bundle-uri; --depth, --shallow-since ve --shallow-exclude ile uyumsuz"
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "bilinmeyen başvuru depolama biçimi '%s'"
#, c-format
msgid "repository '%s' does not exist"
@@ -4438,6 +4486,10 @@ msgstr "saÄŸ kenardaki dolgu boÅŸluÄŸu"
msgid "padding space between columns"
msgstr "sütunlar arasındaki dolgu boşluğu"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s negatif dışı bir değer olmalı"
+
msgid "--command must be the first argument"
msgstr "--command ilk argüman olmalı"
@@ -4452,11 +4504,11 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <dizin>] [--append]\n"
-" [--split[=<<strateji>]] [--reachable | --stdin-packs "
-"| --stdin-commits]\n"
+" [--split[=<strateji>]] [--reachable | --stdin-packs | "
+"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
" <bölme-seçenekleri>"
@@ -4475,6 +4527,10 @@ msgid "Could not open commit-graph '%s'"
msgstr "commit-graph '%s' açılamadı"
#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "commit-graph zinciri '%s' açılamadı"
+
+#, c-format
msgid "unrecognized --split argument, %s"
msgstr "tanımlanamayan --split argümanı, %s"
@@ -4584,7 +4640,7 @@ msgstr "git commit-tree: okunamadı"
msgid ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -4593,14 +4649,14 @@ msgid ""
" [--] [<pathspec>...]"
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<kip>] [--amend]\n"
-" [--dry-run] [(-c | -C | --squash) <iÅŸleme> | --fixup [(amend|"
-"reword):]<iÅŸleme>)]\n"
-" [-F <dosya> | -m <ileti>] [--reset-author] [--allow-empty]\n"
+" [--dry-run] [(-c | -C | --squash) <iÅŸleme> | --fixup\n"
+" [(amend|reword):]<iÅŸleme>] [-F <dosya> | -m <ileti>] [--"
+"reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
" [--date=<tarih>] [--cleanup=<kip>] [--[no-]status]\n"
" [-i | -o] [--pathspec-from-file=<dosya> [--pathspec-file-nul]]\n"
" [(--trailer <jeton>[(=|:)<deÄŸer>])...] [-S[<anahtar-kimliÄŸi>]]\n"
-" [--] [<yol-blrtç>...]"
+" [--] [<yol-belirteci>...]"
msgid "git status [<options>] [--] [<pathspec>...]"
msgstr "git status [<seçenekler>] [--] [<yol-blrtç>...]"
@@ -4675,9 +4731,6 @@ msgstr "geçici indeks güncellenemiyor"
msgid "Failed to update main cache tree"
msgstr "Ana önbellek ağacı güncellenemedi"
-msgid "unable to write new_index file"
-msgstr "new_index dosyası yazılamıyor"
-
msgid "cannot do a partial commit during a merge."
msgstr "Bir birleştirme sırasında kısmi işleme yapılamaz."
@@ -4750,34 +4803,34 @@ msgstr "işleme şablonu yazılamadı"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
-"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%c' ile başlayan\n"
+"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%s' ile başlayan\n"
"satırlar yok sayılacaktır.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%c' ile başlayan\n"
+"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%s' ile başlayan\n"
"satırlar yok sayılacaktır. Boş bir ileti işlemeyi iptal eder.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
-"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%c' ile başlayan\n"
+"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%s' ile başlayan\n"
"satırlar tutulacaktır; isterseniz onları kaldırabilirsiniz.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
-"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%c' ile başlayan\n"
+"Lütfen değişiklikleriniz için bir işleme iletisi girin. '%s' ile başlayan\n"
"satırlar tutulacaktır; isterseniz onları kaldırabilirsiniz.\n"
"BoÅŸ bir ileti iÅŸlemeyi iptal eder.\n"
@@ -5083,22 +5136,65 @@ msgstr "İşleme iletisi gövdesinin boş bırakılmasından ötürü iptal edil
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"Depo güncellendi; ancak new_index dosyası yazılamıyor.\n"
+"Depo güncellendi; ancak yeni indeks dosyası yazılamıyor.\n"
"Diskin dolu olup olmadığını ve kotanızı aşıp aşmadığınızı denetleyin,\n"
"sonra kurtarmak için \"git restore --staged :/\" kullanın."
-msgid "git config [<options>]"
-msgstr "git config [<seçenekler>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr ""
+"git config list [<dosya-seçeneği>] [<görüntüleme-seçeneği>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "tanımlanamayan --type argümanı, %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<dosya-sçnği>] [<görüntü-sçnği>] [--includes] [--all] [--"
+"regexp] [--value=<değer>] [--fixed-value] [--default=<öntanımlı>] <ad>"
-msgid "only one type at a time"
-msgstr "bir kerede yalnızca bir tür"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<dosya-seçeneği>] [--type=<tür>] [--all] [--value=<değer>] "
+"[--fixed-value] <ad> <deÄŸer>"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<dosya-seçeneği>] [--all] [--value=<değer>] [--fixed-"
+"value] <ad> <deÄŸer>"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<dosya-seçeneği>] <eski-ad> <yeni-ad>"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<dosya-seçeneği>] <ad>"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<dosya-seçeneği>]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<dosya-seçeneği>] --get-colorbool <ad> [<stdout-tty>]"
+
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<dosya-seçeneği>] [<görüntüleme-seçeneği>] [--includes] [--"
+"all] [--regexp=<düzenli-ifade>] [--value=<değer>] [--fixed-value] [--"
+"default=<öntanımlı>] <ad>"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<dosya-seçeneği>] [--type=<tür>] [--comment=<ileti>] [--all] "
+"[--value=<deÄŸer>] [--fixed-value] <ad> <deÄŸer>"
msgid "Config file location"
msgstr "Yapılandırma dosyası konumu"
@@ -5124,54 +5220,6 @@ msgstr "ikili nesne numarası"
msgid "read config from given blob object"
msgstr "verilen ikili nesneden yapılandırmayı oku"
-msgid "Action"
-msgstr "Eylem"
-
-msgid "get value: name [value-pattern]"
-msgstr "deÄŸer al: ad [deÄŸer-dizgisi]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "tüm değerleri al: anahtar [değer-dizgisi]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "düzenli ifade için değerleri al: düzenli ifade adı [değer-dizgisi]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "URL için özel olan değeri al: bölüm[.var] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "tüm eşleşen değişkenleri değiştir: ad değer [değer-dizgisi]"
-
-msgid "add a new variable: name value"
-msgstr "yeni bir deÄŸiÅŸken ekle: ad deÄŸer"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "bir değişken kaldır: ad [değer-dizgisi]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "tüm eşleşmeleri kaldır: ad [değer-dizgisi]"
-
-msgid "rename section: old-name new-name"
-msgstr "bölümü yeniden adlandır: eski-ad yeni-ad"
-
-msgid "remove a section: name"
-msgstr "bir bölümü kaldır: ad"
-
-msgid "list all"
-msgstr "tümünü listele"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr "değerleri 'değer-dizgisi' ile karşılaştırırken dizi eşitliği kullan"
-
-msgid "open an editor"
-msgstr "bir düzenleyici aç"
-
-msgid "find the color configured: slot [default]"
-msgstr "yapılandırılan rengi bul: yuva [öntanımlı]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "renk ayarını bul: yuva [stdout tty]"
-
msgid "Type"
msgstr "Tür"
@@ -5199,8 +5247,8 @@ msgstr "değer bir yol (dosya veya dizin adı)"
msgid "value is an expiry date"
msgstr "değer bir son kullanım tarihi"
-msgid "Other"
-msgstr "DiÄŸer"
+msgid "Display options"
+msgstr "Seçenekleri görüntüle"
msgid "terminate values with NUL byte"
msgstr "değerleri NUL baytı ile sonlandır"
@@ -5208,9 +5256,6 @@ msgstr "değerleri NUL baytı ile sonlandır"
msgid "show variable names only"
msgstr "yalnızca değişken adlarını göster"
-msgid "respect include directives on lookup"
-msgstr "arama sırasında içerme yönergelerine uy"
-
msgid "show origin of config (file, standard input, blob, command line)"
msgstr ""
"yapılandırmanın kökenini göster (dosya, stdin, ikili nesne, komut satırı)"
@@ -5220,11 +5265,15 @@ msgstr ""
"yapılandırmanın kapsamını göster (çalışma ağacı, yerel, global, sistem, "
"komut)"
-msgid "value"
-msgstr "deÄŸer"
+msgid "show config keys in addition to their values"
+msgstr "değerlerine ek olarak yapılandırma anahtarlarını da göster"
-msgid "with --get, use default value when missing entry"
-msgstr "--get ile girdi verilmemişse öntanımlı değeri kullan"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "tanımlanamayan --type argümanı, %s"
+
+msgid "only one type at a time"
+msgstr "bir kerede yalnızca bir tür"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5300,44 +5349,72 @@ msgstr ""
"sürece birden çok çalışma ağacı ile birlikte kullanılamaz. Ayrıntılar için\n"
"lütfen \"git help worktree\" içindeki \"CONFIGURATION FILE\" bölümünü okuyun"
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color ve değişken türü tutarsız"
+msgid "Other"
+msgstr "DiÄŸer"
-msgid "only one action at a time"
-msgstr "bir kerede yalnızca bir eylem"
+msgid "respect include directives on lookup"
+msgstr "arama sırasında içerme yönergelerine uy"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only yalnızca şunlara uygulanabilir: --list, --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "'%s' yapılandırma dosyası okunamıyor"
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr ""
-"--show-origin yalnızca şunlara uygulanabilir: --get, --get-all, --get-regexp "
-"ve --list"
+msgid "error processing config file(s)"
+msgstr "yapılandırma dosyaları işlenirken hata"
-msgid "--default is only applicable to --get"
-msgstr "--default yalnızca şuna uygulanabilir: --get"
+msgid "Filter options"
+msgstr "Süzme seçenekleri"
+
+msgid "return all values for multi-valued config options"
+msgstr "birden çok değerli yapılandırma seçeneklerinin tüm değerlerini döndür"
+
+msgid "interpret the name as a regular expression"
+msgstr "adı düzenli ifade olarak yorumla"
+
+msgid "show config with values matching the pattern"
+msgstr "dizgiyle eşleşen değerleri olan yapılandırmayı göster"
+
+msgid "use string equality when comparing values to value pattern"
+msgstr "değerleri değer dizgisiyle karşılaştırırken dizi eşitliğini kullan"
+
+msgid "URL"
+msgstr "URL"
+
+msgid "show config matching the given URL"
+msgstr "verilen URL ile eşleşen yapılandırmayı göster"
+
+msgid "value"
+msgstr "deÄŸer"
+
+msgid "use default value when missing entry"
+msgstr "girdi eksikse öntanımlı değeri kullan"
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value yalnızca 'değer-dizgisi' ile uygulanır"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "'%s' yapılandırma dosyası okunamıyor"
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default=, --all veya --url= ile kullanılamaz"
-msgid "error processing config file(s)"
-msgstr "yapılandırma dosyaları işlenirken hata"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url=; --all, --regexp veya --value ile kullanılamaz"
-msgid "editing stdin is not supported"
-msgstr "stdin'i düzenleme desteklenmiyor"
+msgid "Filter"
+msgstr "Süzgeç"
-msgid "editing blobs is not supported"
-msgstr "ikili nesneleri düzenleme desteklenmiyor"
+msgid "replace multi-valued config option with new value"
+msgstr "birden çok değerli yapılandırma seçeneğini yeni değerle değiştir"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "%s yapılandırma dosyası oluşturulamıyor"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr "kişi tarafından okunabilir yorum satırı (gerekirse önüne # koyulur)"
+
+msgid "add a new line without altering any existing values"
+msgstr "var olan herhangi değeri değiştirmeden yeni satır ekle"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value, yalnızca --value=<dizgi> ile geçerlidir"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append, --value=<dizgi> ile kullanılamaz"
#, c-format
msgid ""
@@ -5352,6 +5429,86 @@ msgstr ""
msgid "no such section: %s"
msgstr "böyle bir bölüm yok: %s"
+msgid "editing stdin is not supported"
+msgstr "stdin'i düzenleme desteklenmiyor"
+
+msgid "editing blobs is not supported"
+msgstr "ikili nesneleri düzenleme desteklenmiyor"
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "%s yapılandırma dosyası oluşturulamıyor"
+
+msgid "Action"
+msgstr "Eylem"
+
+msgid "get value: name [<value-pattern>]"
+msgstr "deÄŸer al: ad [<deÄŸer-dizgisi>]"
+
+msgid "get all values: key [<value-pattern>]"
+msgstr "tüm değerleri al: anahtar [<değer-dizgisi>]"
+
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "düzenli ifade için değerleri al: düzenli ifade adı [<değer-dizgisi>]"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "URL için özel olan değeri al: bölüm[.var] URL"
+
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "tüm eşleşen değişkenleri değiştir: ad değer [<değer-dizgisi>]"
+
+msgid "add a new variable: name value"
+msgstr "yeni bir deÄŸiÅŸken ekle: ad deÄŸer"
+
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "bir değişken kaldır: ad [<değer-dizgisi>]"
+
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "tüm eşleşmeleri kaldır: ad [<değer-dizgisi>]"
+
+msgid "rename section: old-name new-name"
+msgstr "bölümü yeniden adlandır: eski-ad yeni-ad"
+
+msgid "remove a section: name"
+msgstr "bir bölümü kaldır: ad"
+
+msgid "list all"
+msgstr "tümünü listele"
+
+msgid "open an editor"
+msgstr "bir düzenleyici aç"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "yapılandırılan rengi bul: yuva [<öntanımlı>]"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "renk ayarını bul: yuva [<stdout-tty>]"
+
+msgid "with --get, use default value when missing entry"
+msgstr "--get ile girdi verilmemişse öntanımlı değeri kullan"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color ve değişken türü tutarsız"
+
+msgid "no action specified"
+msgstr "belirtilen eylem yok"
+
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only yalnızca şunlara uygulanabilir: --list, --get-regexp"
+
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin yalnızca şunlara uygulanabilir: --get, --get-all, --get-regexp "
+"ve --list"
+
+msgid "--default is only applicable to --get"
+msgstr "--default yalnızca --get için uygulanabilir"
+
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment yalnızca ekle/ayarla/değiştir işlemlerine uygulanabilir"
+
msgid "print sizes in human readable format"
msgstr "yazdırma boyutları kişi tarafından okunabilir biçimde"
@@ -5834,8 +5991,8 @@ msgstr ""
"bu denetlemeden kaçınabilirsiniz.\n"
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s tüm gerekli nesneleri göndermedi\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s tüm gerekli nesneleri göndermedi"
#, c-format
msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -5872,8 +6029,8 @@ msgid "option \"%s\" value \"%s\" is not valid for %s"
msgstr "\"%s\" seçeneği \"%s\" değeri %s için geçerli değil"
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "\"%s\" seçeneği %s için yok sayılıyor\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "\"%s\" seçeneği %s için yok sayılıyor"
#, c-format
msgid "%s is not a valid object"
@@ -6159,6 +6316,9 @@ 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 "also include HEAD ref and pseudorefs"
+msgstr "ayrıca HEAD ve yalancı başvuruları içer"
+
msgid "unknown arguments supplied with --stdin"
msgstr "--stdin ile bilinmeyen argümanlar verilmiş"
@@ -6171,6 +6331,9 @@ msgstr "yapılandırma"
msgid "config key storing a list of repository paths"
msgstr "bir depo yolları listesi tutan yapılandırma anahtarı"
+msgid "keep going even if command fails in a repository"
+msgstr "komut depoda başarısız olsa bile gitmeyi sürdür"
+
msgid "missing --config=<config>"
msgstr "--config=<yapılandırma> eksik"
@@ -6531,12 +6694,18 @@ msgstr "baÅŸvurulmayan nesneleri buda"
msgid "pack unreferenced objects separately"
msgstr "başvurulmamış nesneleri ayrı olarak paketle"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "--cruft ile yeni süprüntü paketlerinin boyutunu sınırla"
+
msgid "be more thorough (increased runtime)"
msgstr "biraz daha titiz ol (artırılmış işleyiş süresi)"
msgid "enable auto-gc mode"
msgstr "auto-gc kipini etkinleÅŸtir"
+msgid "perform garbage collection in the background"
+msgstr "çöp toplamayı arka planda gerçekleştir"
+
msgid "force running gc even if there may be another gc running"
msgstr "başka bir gc çalışıyor olsa bile zorla gc çalıştır"
@@ -6632,6 +6801,9 @@ msgstr "'%s' görevi birden çok kez seçilemez"
msgid "run tasks based on the state of the repository"
msgstr "görevleri deponun durumuna göre çalıştır"
+msgid "perform maintenance in the background"
+msgstr "bakımı arka planda gerçekleştir"
+
msgid "frequency"
msgstr "sıklık"
@@ -6701,12 +6873,6 @@ msgstr "'crontab' çalıştırılamadı; sisteminiz 'cron' desteklemiyor olabili
msgid "'crontab' died"
msgstr "'crontab' beklenmedik bir biçimde sonlandı"
-msgid "failed to start systemctl"
-msgstr "systemctl başlatılamadı"
-
-msgid "failed to run systemctl"
-msgstr "systemctl çalıştırılamadı"
-
#, c-format
msgid "failed to delete '%s'"
msgstr "'%s' silinemedi"
@@ -6715,6 +6881,12 @@ msgstr "'%s' silinemedi"
msgid "failed to flush '%s'"
msgstr "'%s' floş yapılamadı"
+msgid "failed to start systemctl"
+msgstr "systemctl başlatılamadı"
+
+msgid "failed to run systemctl"
+msgstr "systemctl çalıştırılamadı"
+
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "tanımlanamayan --scheduler argümanı, '%s'"
@@ -6738,6 +6910,9 @@ msgstr "görev planlayıcı"
msgid "scheduler to trigger git maintenance run"
msgstr "git bakımını tetikleyecek görev planlayıcı"
+msgid "failed to set up maintenance schedule"
+msgstr "bakım programı ayarlanamadı"
+
msgid "failed to add repo to global config"
msgstr "depo, global yapılandırmaya eklenemedi"
@@ -6765,8 +6940,8 @@ msgid "no threads support, ignoring %s"
msgstr "iş parçacığı desteği yok, %s yok sayılıyor"
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "ağaç okunamıyor (%s)"
+msgid "unable to read tree %s"
+msgstr "%s ağacı okunamıyor"
#, c-format
msgid "unable to grep from object of type %s"
@@ -6812,8 +6987,8 @@ msgstr "ikili dosyaları textconv süzgeçleri ile işle"
msgid "search in subdirectories (default)"
msgstr "altdizinlerde ara (öntanımlı)"
-msgid "descend at most <depth> levels"
-msgstr "en çok <derinlik> düzey in"
+msgid "descend at most <n> levels"
+msgstr "en çok <n> düzey aşağı in"
msgid "use extended POSIX regular expressions"
msgstr "genişletilmiş POSIX düzenli ifadelerini kullan"
@@ -7181,10 +7356,6 @@ msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "%s İLE SHA1 ÇARPIŞMASI BULUNDU!"
#, c-format
-msgid "unable to read %s"
-msgstr "%s okunamıyor"
-
-#, c-format
msgid "cannot read existing object info %s"
msgstr "var olan nesne bilgisi %s okunamıyor"
@@ -7324,13 +7495,15 @@ msgstr "paket nesnelerinde fsck hatası"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
"git init [-q | --quiet] [--bare] [--template=<ÅŸablon-dizini>]\n"
" [--separate-git-dir <git-dizini>] [--object-format=<biçim>]\n"
+" [--ref-format=<biçim>]\n"
" [-b <dal-adı> | --initial-branch=<dal-adı>]\n"
-" [--shared[=<izinler>]] [<dizin>]"
+" [--shared[=<izin>]] [<dizin>]"
msgid "permissions"
msgstr "izinler"
@@ -7372,19 +7545,48 @@ msgstr "--separate-git-dir, çıplak depo ile uyumsuz"
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <jeton>[(=|:)<deÄŸer>])...]\n"
+" [(--trailer (<anahtar>|<arma>)[(=|:)<deÄŸer>])...]\n"
" [--parse] [<dosya>...]"
+#, c-format
+msgid "could not stat %s"
+msgstr "%s dosya bilgileri alınamadı"
+
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "%s dosyası sıradan bir dosya değil"
+
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "%s dosyası kullanıcı tarafından yazılabilir değil"
+
+msgid "could not open temporary file"
+msgstr "geçici dosya açılamadı"
+
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "'%s' girdi dosyası okunamadı"
+
+msgid "could not read from stdin"
+msgstr "stdin'den okunamadı"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "geçici dosya adı %s olarak değiştirilemedi"
+
msgid "edit files in place"
msgstr "dosyaları yerinde düzenle"
msgid "trim empty trailers"
msgstr "boş artbilgileri kırp"
+msgid "placement"
+msgstr "yerleÅŸtirme"
+
msgid "where to place the new trailer"
msgstr "yeni artbilgiler nereye yerleÅŸtirilecek"
@@ -7397,17 +7599,17 @@ msgstr "artbilgi eksikse yapılacak eylem"
msgid "output only the trailers"
msgstr "yalnızca artbilgileri çıktı ver"
-msgid "do not apply config rules"
-msgstr "yapılandırma kurallarını uygulama"
+msgid "do not apply trailer.* configuration variables"
+msgstr "trailer.* yapılandırma değişkenlerini uygulama"
-msgid "join whitespace-continued values"
-msgstr "boşluk ile sürdürülen değerleri uç uca ekle"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "çok satırlı artbilgileri tek satırlı değerler olarak biçimlendir"
-msgid "set parsing options"
-msgstr "ayrıştırma seçeneklerini ayarla"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "--only-trailers --only-input --unfold için arma"
-msgid "do not treat --- specially"
-msgstr "ayırma çizgilerine (---) özel davranma"
+msgid "do not treat \"---\" as the end of input"
+msgstr "\"---\" dizgisine satır sonu olarak davranma"
msgid "trailer(s) to add"
msgstr "eklenecek artbilgi(ler)"
@@ -7464,9 +7666,6 @@ msgstr "-L<erim>:<dosya>, yol belirteci ile kullanılamıyor"
msgid "Final output: %d %s\n"
msgstr "Son çıktı: %d %s\n"
-msgid "unable to create temporary object directory"
-msgstr "geçici nesne dizini oluşturulamıyor"
-
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: hatalı dosya"
@@ -7496,6 +7695,10 @@ msgstr "bir tam erim gerekiyor"
msgid "not a range"
msgstr "bir erim deÄŸil"
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "'%s' dal açıklama dosyası okunamıyor"
+
msgid "cover letter needs email format"
msgstr "ön yazı için e-posta biçimi gerekli"
@@ -7585,8 +7788,11 @@ msgstr "diziyi n. deneme olarak imle"
msgid "max length of output filename"
msgstr "çıktı dosya adının olabilecek en çok uzunluğu"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "[PATCH] yerine [RFC PATCH] kullan"
+msgid "rfc"
+msgstr "rfc"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "'PATCH' öncesi <rfc> ekle (öntanımlı 'RFC')"
msgid "cover-from-description-mode"
msgstr "açıklama kipinden kapak sayfası kipi"
@@ -7594,6 +7800,9 @@ msgstr "açıklama kipinden kapak sayfası kipi"
msgid "generate parts of a cover letter based on a branch's description"
msgstr "ön yazının bazı kısımlarını dalın açıklamasından oluştur"
+msgid "use branch description from file"
+msgstr "dal açıklamasını dosyadan oku"
+
msgid "use [<prefix>] instead of [PATCH]"
msgstr "[PATCH] yerine [<önek>] kullan"
@@ -7754,18 +7963,6 @@ msgstr "İzlenen bir uzak dal bulunamadı, lütfen el ile <üstkaynak> belirtin.
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"
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "hatalı ls-files biçimi: '%s' ögesi, ')' ile sonlanmıyor"
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "hatalı ls-files biçimi: %%%.*s"
-
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<seçenekler>] [<dosya>...]"
@@ -7858,11 +8055,12 @@ msgstr ""
"kullanılamaz"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<yürütülebilir>]\n"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-"
+"pack=<yürütülebilir>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<anahtar>]\n"
" [--symref] [<depo> [<dizgiler>...]]"
@@ -7878,8 +8076,11 @@ msgstr "uzak konum makinesindeki git-upload-pack yolu"
msgid "limit to tags"
msgstr "etiketlere kısıtla"
-msgid "limit to heads"
-msgstr "uç işlemelere kısıtla"
+msgid "limit to branches"
+msgstr "dallara kısıtla"
+
+msgid "deprecated synonym for --branches"
+msgstr "--branches için artık kullanılmayan eşanlamlı"
msgid "do not show peeled tags"
msgstr "soyulmuş etiketleri gösterme"
@@ -7896,18 +8097,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 "bad ls-tree format: element '%s' does not start with '('"
-msgstr "hatalı ls-tree biçimi: '%s' ögesi '(' ile başlamıyor"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "hatalı ls-tree biçimi: '%s' ögesi ')' ile sonlanmıyor"
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "hatalı ls-tree biçimi: %%%.*s"
-
msgid "only show trees"
msgstr "yalnızca ağaçları göster"
@@ -8019,23 +8208,30 @@ msgstr ""
"git merge-file [<seçenekler>] [-L <ad1> [-L <orij> [-L <ad2>]]] <dosya1> "
"<orij-dosya> <dosya2>"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"diff-algorithm seçeneği şunları kabul eder: \"myers\", \"minimal\", "
+"\"patience\" ve \"histogram\""
+
msgid "send results to standard output"
msgstr "sonuçları standart çıktıya gönder"
+msgid "use object IDs instead of filenames"
+msgstr "dosya adları yerine nesne kimlikleri kullan"
+
msgid "use a diff3 based merge"
msgstr "diff3 tabanlı birleştirme kullan"
msgid "use a zealous diff3 based merge"
msgstr "gayretli bir diff3 tabanlı birleştirme kullan"
-msgid "for conflicts, use our version"
-msgstr "çakışmalarda bizim sürümü kullan"
-
-msgid "for conflicts, use their version"
-msgstr "çakışmalarda onların sürümünü kullan"
+msgid "<algorithm>"
+msgstr "<algoritma>"
-msgid "for conflicts, use a union version"
-msgstr "çakışmalarda birlik olmuş bir sürüm kullan"
+msgid "choose a diff algorithm"
+msgstr "bir diff algoritması seç"
msgid "for conflicts, use this marker size"
msgstr "çakışmalarda bu imleyici boyutunu kullan"
@@ -8047,6 +8243,13 @@ msgid "set labels for file1/orig-file/file2"
msgstr "file1/orig-file/file2 için etiketler yapıştır"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "'%s' diye bir nesne yok"
+
+msgid "Could not write object file"
+msgstr "nesne dosyası yazılamadı"
+
+#, c-format
msgid "unknown option %s"
msgstr "bilinmeyen seçenek %s"
@@ -8071,6 +8274,10 @@ msgstr "'%s' başvurusu çözülemedi"
msgid "Merging %s with %s\n"
msgstr "%s, %s ile birleÅŸtiriliyor\n"
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "'%s' ağacı olarak ayrıştırılamadı"
+
msgid "not something we can merge"
msgstr "birleÅŸtirebileceÄŸimiz bir ÅŸey deÄŸil"
@@ -8107,11 +8314,18 @@ msgstr "girdi satırı başına bir adet çoklu birleştirmeler gerçekleştir"
msgid "specify a merge-base for the merge"
msgstr "birleştirme için bir birleştirme temeli belirtilmeli"
+msgid "option=value"
+msgstr "seçenek=değer"
+
+msgid "option for selected merge strategy"
+msgstr "seçili birleştirme stratejisi için seçenekler"
+
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge, tüm diğer seçeneklerle uyumsuz"
-msgid "--merge-base is incompatible with --stdin"
-msgstr "--merge-base, --stdin ile uyumsuz"
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "bilinmeyen strateji seçeneği: -X%s"
#, c-format
msgid "malformed input line: '%s'."
@@ -8180,12 +8394,6 @@ msgstr "strateji"
msgid "merge strategy to use"
msgstr "kullanılacak birleştirme stratejisi"
-msgid "option=value"
-msgstr "seçenek=değer"
-
-msgid "option for selected merge strategy"
-msgstr "seçili birleştirme stratejisi için seçenekler"
-
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
"birleştirme işlemesi iletisi (ileri sarım olmayan bir birleştirme için)"
@@ -8247,10 +8455,6 @@ msgid "Not handling anything other than two heads merge."
msgstr "İki uç işlemenin birleştirilmesi dışında bir şey yapılmıyor."
#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "bilinmeyen strateji seçeneği: -X%s"
-
-#, c-format
msgid "unable to write %s"
msgstr "%s yazılamıyor"
@@ -8276,10 +8480,10 @@ msgstr "BoÅŸ bir ileti iÅŸlemeyi iptal eder.\n"
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"'%c' ile başlayan satırlar yok sayılacaktır. Boş bir ileti işlemeyi\n"
+"'%s' ile başlayan satırlar yok sayılacaktır. Boş bir ileti işlemeyi\n"
"iptal eder.\n"
msgid "Empty commit message."
@@ -8436,9 +8640,6 @@ msgstr "etiketlenmiş nesne '%s' okunamadı"
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "'%s' nesnesi '%s' olarak etiketlenmiş; ancak bir '%s' türü"
-msgid "could not read from stdin"
-msgstr "stdin'den okunamadı"
-
msgid "tag on stdin did not pass our strict fsck check"
msgstr "stdin üzerindeki etiket bizim sıkı fsck denetimimizi geçemedi"
@@ -8488,6 +8689,9 @@ msgstr "bir çoklu paket biteşlemi hesaplanırken yeniden kullanılacak paket"
msgid "write multi-pack bitmap"
msgstr "çoklu paket biteşlemi yaz"
+msgid "write a new incremental MIDX"
+msgstr "yeni bir artımlı MIDX yaz"
+
msgid "write multi-pack index containing only given indexes"
msgstr "yalnızca verilen indeksleri içeren çoklu paket indekslerini yaz"
@@ -8540,8 +8744,8 @@ msgstr "hedef konum var"
msgid "can not move directory into itself"
msgstr "dizin kendi içine taşınamıyor"
-msgid "cannot move directory over file"
-msgstr "dizin dosya üzerinden taşınamıyor"
+msgid "destination already exists"
+msgstr "hedef halihazırda var"
msgid "source directory is empty"
msgstr "kaynak dizin boÅŸ"
@@ -8699,10 +8903,6 @@ msgstr "git notes prune [<seçenekler>]"
msgid "Write/edit the notes for the following object:"
msgstr "Aşağıdaki nesneler için not yaz/düzenle:"
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "'%s' nesnesi için 'show' başlatılamıyor"
-
msgid "could not read 'show' output"
msgstr "'show' çıktısı okunamadı"
@@ -9048,6 +9248,10 @@ msgid "inconsistency with delta count"
msgstr "delta sayımında tutarsızlık"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "geçersiz pack.allowPackReuse değeri: '%s'"
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -9284,9 +9488,6 @@ msgstr "olabilecek en küçük paket boyutu limiti 1 MiB'dır"
msgid "--thin cannot be used to build an indexable pack"
msgstr "--thin bir indekslenebilir paket yapımında kullanılamaz"
-msgid "cannot use --filter without --stdout"
-msgstr "--filter, --stdout olmadan kullanılamaz"
-
msgid "cannot use --filter with --stdin-packs"
msgstr "--filter, --stdin-packs ile birlikte kullanılamıyor"
@@ -9299,19 +9500,16 @@ msgstr "iç revizyon listeleri, --cruft ile birlikte kullanılamıyor"
msgid "cannot use --stdin-packs with --cruft"
msgstr "--stdin-packs, --cruft ile birlikte kullanılamıyor"
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "--max-pack-size, --cruft ile birlikte kullanılamıyor"
-
msgid "Enumerating objects"
msgstr "Nesneler ortaya dökülüyor"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Toplam %<PRIu32> (delta %<PRIu32>), yeniden kullanılan %<PRIu32> (delta "
-"%<PRIu32>), yeniden kullanılan paket %<PRIu32>"
+"%<PRIu32>), yeniden kullanılan paket %<PRIu32> (%<PRIuMAX> konumundan)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9331,11 +9529,11 @@ 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 "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune]git pack-refs [--all] [--no-prune] [--"
-"include <dizgi>] [--exclude <dizgi>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <dizgi>] [--exclude "
+"<dizgi>]"
msgid "pack everything"
msgstr "her ÅŸeyi paketle"
@@ -9343,6 +9541,9 @@ msgstr "her ÅŸeyi paketle"
msgid "prune loose refs (default)"
msgstr "gevşek başvuruları buda (öntanımlı)"
+msgid "auto-pack refs as needed"
+msgstr "gerekirse başvuruları paketle"
+
msgid "references to include"
msgstr "içerilecek başvurular"
@@ -9995,19 +10196,6 @@ msgstr "geçersiz allow_rerere_autoupdate yok sayılıyor: '%s'"
msgid "could not remove '%s'"
msgstr "'%s' kaldırılamadı"
-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 ""
-"Tüm çakışmaları el ile çözün, onları \"git add/rm <çakışan-dosyalar>\"\n"
-"ile tamam olarak imleyin, ardından \"git rebase --continue\"\n"
-"çalıştırın. Bunun yerine bu işlemeyi atlayabilirsiniz: \"git rebase\n"
-"--skip\" yapın. İptal edip \"git rebase\" öncesine geri dönmek için\n"
-"\"git rebase --abort\" çalıştırın."
-
#, c-format
msgid ""
"\n"
@@ -10037,12 +10225,15 @@ msgstr "şuraya geçilemedi: %s"
msgid "apply options and merge options cannot be used together"
msgstr "uygulama seçenekleri ve birleştirme seçenekleri birlikte kullanılamaz"
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask artık kullanılmıyor; yerine '--empty=stop' kullanın."
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
-"Tanımlanamayan boş tür '%s'; geçerli türler: \"drop\", \"keep\" ve \"ask\"."
+"Tanımlanamayan boş tür '%s'; geçerli türler: \"drop\", \"keep\" ve \"stop\"."
msgid ""
"--rebase-merges with an empty string argument is deprecated and will stop "
@@ -10226,8 +10417,8 @@ msgstr ""
"Not: `pull.rebase` yapılandırmanız, artık desteklenmeyen'\n"
"'preserve' olarak ayarlı olabilir; yerine 'merges' kullanın"
-msgid "No rebase in progress?"
-msgstr "Sürmekte olan bir yeniden temellendirme yok"
+msgid "no rebase in progress"
+msgstr "sürmekte olan yeniden temellendirme yok"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
@@ -10274,16 +10465,6 @@ msgstr ""
msgid "switch `C' expects a numerical value"
msgstr "'C' anahtarı sayısal bir değer bekliyor"
-msgid "--strategy requires --merge or --interactive"
-msgstr "--strategy, --merge veya --interactive gerektiriyor"
-
-msgid ""
-"apply options are incompatible with rebase.autoSquash. Consider adding --no-"
-"autosquash"
-msgstr ""
-"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"
@@ -10433,6 +10614,9 @@ msgstr "bir dizin belirtmelisiniz"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<günlük-seçenekleri>] [<başvuru>]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10458,6 +10642,10 @@ msgstr "git reflog exists <baÅŸvuru>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "geçersiz zaman damgası '%s', '--%s' argümanına verildi"
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s argüman kabul etmiyor: '%s'"
+
msgid "do not actually prune any entries"
msgstr "özünde, hiçbir girdiyi budama"
@@ -10509,6 +10697,31 @@ msgstr "silmek için bir başvuru günlüğü belirtilmedi"
msgid "invalid ref format: %s"
msgstr "geçersiz başvuru biçimi: %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<biçim> [--dry-run]"
+
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+msgid "specify the reference format to convert to"
+msgstr "dönüştürülecek başvuru biçimini belirt"
+
+msgid "perform a non-destructive dry-run"
+msgstr "yıkıcı olmayan bir deneme gerçekleştir"
+
+msgid "missing --ref-format=<format>"
+msgstr "--ref-format=<biçim> eksik"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "depo halihazırda '%s' biçimini kullanıyor"
+
+msgid "enable strict checking"
+msgstr "kesin denetlemeyi etkinleÅŸtir"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' bir argüman almıyor"
+
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10585,8 +10798,8 @@ msgstr ""
"\t yerine --mirror=fetch veya --mirror=push kullanın"
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "bilinmeyen yansı argümanı: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "bilinmeyen --mirror argümanı: %s"
msgid "fetch the remote branches"
msgstr "uzak konum dallarını getir"
@@ -10696,10 +10909,10 @@ msgid_plural ""
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:"
msgstr[0] ""
-"Not: refs/remotes hiyerarşisi dışındaki bir dal kaldırılmadı;\n"
+"Not: refs/remotes/ hiyerarşisi dışındaki bir dal kaldırılmadı;\n"
"onu silmek için şunu kullanın:"
msgstr[1] ""
-"Not: refs/remotes hiyerarşisi dışındaki bazı dallar kaldırılmadı;\n"
+"Not: refs/remotes/ hiyerarşisi dışındaki bazı dallar kaldırılmadı;\n"
"onları silmek için şunu kullanın:"
#, c-format
@@ -10794,9 +11007,6 @@ msgstr "* uzak konum %s"
msgid " Fetch URL: %s"
msgstr " URL'yi getir: %s"
-msgid "(no URL)"
-msgstr "(URL yok)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -10805,6 +11015,9 @@ msgstr "(URL yok)"
msgid " Push URL: %s"
msgstr " URL'yi it: %s"
+msgid "(no URL)"
+msgstr "(URL yok)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " HEAD dalı: %s"
@@ -10911,10 +11124,6 @@ msgstr "itme URL'lerinden çok getirme URL'lerini sorgula"
msgid "return all URLs"
msgstr "tüm URL'leri döndür"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "'%s' uzak konumu için URL yapılandırılmamış"
-
msgid "manipulate push URLs"
msgstr "itme URL'lerini deÄŸiÅŸtir"
@@ -10955,6 +11164,9 @@ msgstr ""
msgid "could not start pack-objects to repack promisor objects"
msgstr "vaatçi nesneleri yeniden paketleme için pack-objects başlatılamadı"
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "vaatçi nesneleri pack-objects'e beslenemedi"
+
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"repack: Onaltılı tam nesne no satırları yalnızca pack-objects'ten bekleniyor."
@@ -10985,6 +11197,10 @@ msgstr "başvurular anlık görüntü geçici dosyası kapatılamadı"
msgid "could not remove stale bitmap: %s"
msgstr "eskimiş biteşlem kaldırılamadı: %s"
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "paket öneki %s, nesne dizini %s ile başlamıyor"
+
msgid "pack everything in a single pack"
msgstr "her şeyi tek bir pakete sığdır"
@@ -10998,7 +11214,7 @@ msgid "approxidate"
msgstr "yaklaşık tarih"
msgid "with --cruft, expire objects older than this"
-msgstr "--cruft ile, bundan daha eski nesneleri yürürlükten kaldır"
+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"
@@ -11060,17 +11276,20 @@ msgstr "ortaya çıkan paketlerin bir çoklu paket indeksini yaz"
msgid "pack prefix to store a pack containing pruned objects"
msgstr "budanan nesneler içeren paketi depolamak için paket öneki"
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "süzülen nesneler içeren paketi depolamak için paket öneki"
+
msgid "cannot delete packs in a precious-objects repo"
msgstr "bir precious-objects deposundaki paketler silinemiyor"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "'%s' seçeneği, yalnızca '%s' ile birlikte kullanılabilir"
+
msgid "Nothing new to pack."
msgstr "Paketlenecek yeni bir ÅŸey yok."
#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "paket öneki %s, nesne dizini %s ile başlamıyor"
-
-#, c-format
msgid "renaming pack to '%s' failed"
msgstr "paketi '%s' olarak yeniden adlandırma başarısız"
@@ -11270,6 +11489,76 @@ msgstr "--convert-graft-file argüman almaz"
msgid "only one pattern can be given with -l"
msgstr "-l ile yalnızca bir dizgi verilebilir"
+msgid "need some commits to replay"
+msgstr "yeniden oynatmak için birkaç işleme gerekli"
+
+msgid "--onto and --advance are incompatible"
+msgstr "--onto ve --advance birbiriyle uyumsuz"
+
+msgid "all positive revisions given must be references"
+msgstr "verilen tüm pozitif revizyonlar, başvuru olmalı"
+
+msgid "argument to --advance must be a reference"
+msgstr "--advance'a olan argüman bir başvuru olmalı"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"birden çok kaynaklı hedef ilerletilemiyor; çünkü sıralama hatalı tanımlanmış "
+"olurdu"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr ""
+"bunun --advance veya --onto işlemi olup olmadığı örtük olarak algılanamıyor"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"birden çok kaynak dallı hedef ilerletilemiyor; çünkü sıralama hatalı "
+"tanımlanmış olurdu"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "--onto için olan doğru temel örtük olarak algılanamıyor"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(DENEYSEL!) git replay ([--contained] --onto <yeni-temel> | --advance <dal>) "
+"<revizyon-erimi>..."
+
+msgid "make replay advance given branch"
+msgstr "verilen dalı önceden yeniden oynat"
+
+msgid "replay onto given commit"
+msgstr "verilen iÅŸlemeye yeniden oynat"
+
+msgid "advance all branches contained in revision-range"
+msgstr "revizyon eriminde içerilen tüm dalları ilerlet"
+
+msgid "option --onto or --advance is mandatory"
+msgstr "--onto veya --advance seçeneğinin kullanımı zorunlu"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"'struct rev_info' içindeki '%s' biti zorlanacağından kimi revizyon yürütme "
+"seçenekleri geçersiz kılınacak"
+
+msgid "error preparing revisions"
+msgstr "revizyonlar hazırlanırken hata"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "kök işlemeye kadar yeniden oynatma henüz desteklenmiyor!"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "birleştirme işlemelerini yeniden oynatma henüz desteklenmiyor!"
+
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
msgstr ""
@@ -11474,22 +11763,23 @@ msgstr "--default bir argüman gerektiriyor"
msgid "--prefix requires an argument"
msgstr "--prefix bir argüman gerektiriyor"
+msgid "no object format specified"
+msgstr "belirtilen nesne biçimi yok"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "desteklenmeyen nesne biçimi: %s"
+
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "--abbrev-ref için bilinmeyen kip: %s"
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden, --branches ile birlikte kullanılamıyor"
-
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden, --tags ile birlikte kullanılamıyor"
-
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden, --remotes ile birlikte kullanılamıyor"
-
msgid "this operation must be run in a work tree"
msgstr "bu işlem bir çalışma ağacı içinde çalıştırılmalı"
+msgid "Could not read the index"
+msgstr "İndeks okunamadı"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "--show-object-format için bilinmeyen kip: %s"
@@ -11561,8 +11851,8 @@ msgstr "başlangıçta boş olan işlemeleri koru"
msgid "allow commits with empty messages"
msgstr "boÅŸ iletili iÅŸlemelere izin ver"
-msgid "keep redundant, empty commits"
-msgstr "gereksiz, boÅŸ iÅŸlemeleri tut"
+msgid "deprecated: use --empty=keep instead"
+msgstr "kullanılmıyor: Yerine --empty=keep kullanın"
msgid "use the 'reference' format to refer to commits"
msgstr "işlemelere başvurmak için 'reference' biçimini kullan"
@@ -11833,22 +12123,43 @@ msgid "Unknown hash algorithm"
msgstr "bilinmeyen sağlama algoritması '%s'"
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<dizgi>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<dizgi>...]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
+msgstr ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<baÅŸvuru>...]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<dizgi>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "yalnızca etiketleri göster (dal uçlarıyla birlikte kullanılabilir)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <baÅŸvuru>"
+
+msgid "reference does not exist"
+msgstr "baÅŸvuru yok"
+
+msgid "failed to look up reference"
+msgstr "başvuru bakılamadı"
+
+msgid "only show tags (can be combined with --branches)"
+msgstr "yalnızca etiketleri göster (--branches ile birlikte kullanılabilir)"
-msgid "only show heads (can be combined with tags)"
-msgstr "yalnızca dal uçlarını göster (etiketlerle birlikte kullanılabilir)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "yalnızca dalları göster (--tags ile birlikte kullanılabilir)"
+
+msgid "check for reference existence without resolving"
+msgstr "çözmeden başvuru varlığını denetle"
msgid "stricter reference checking, requires exact ref path"
msgstr "daha sıkı başvuru denetlemesi; kesin başvuru yolu gerektirir"
@@ -11897,6 +12208,10 @@ msgstr "'%s' dizini kaldırılamadı"
msgid "failed to create directory for sparse-checkout file"
msgstr "aralıklı çıkış dosyası için dizin oluşturulamadı"
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "%s fdopen yapılamıyor"
+
msgid "failed to initialize worktree config"
msgstr "çalışma ağacı yapılandırması ilklendirilemedi"
@@ -12345,8 +12660,8 @@ msgid "couldn't hash object from '%s'"
msgstr "'%s' üzerinden nesne sağlaması yapılamadı"
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "beklenmedik kip %o\n"
+msgid "unexpected mode %o"
+msgstr "beklenmedik kip %o"
msgid "use the commit stored in the index instead of the submodule HEAD"
msgstr "altmodül HEAD'i içindeki işleme ile indekstekini karşılaştırmak için"
@@ -12465,14 +12780,14 @@ msgstr ""
"başka bir altmodülün git dizininde '%s' oluşturma/kullanma reddediliyor"
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "'%s' ögesinin '%s' altmodül yoluna klonlanması başarısız"
-
-#, c-format
msgid "directory not empty: '%s'"
msgstr "dizin boÅŸ deÄŸil: '%s'"
#, c-format
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "'%s' ögesinin '%s' altmodül yoluna klonlanması başarısız"
+
+#, c-format
msgid "could not get submodule directory for '%s'"
msgstr "'%s' için altmodül dizini alınamadı"
@@ -12661,6 +12976,9 @@ msgstr ""
"shallow] [--reference <depo>] [--recursive] [--[no-]single-branch] [--] "
"[<yol>...]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "HEAD geçerli bir başvuru olarak çözülemedi."
+
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<seçenekler>] [<yol>...]"
@@ -12826,10 +13144,12 @@ msgstr "güncelleme nedeni"
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <anahtar-kimliÄŸi>] [-f] [-m <ileti> | -F <dosya>] [-"
"e]\n"
+" [(--trailer <jeton>[(=|:)<deÄŸer>])...]\n"
" <etiket-adı> [<işleme> | <nesne>]"
msgid "git tag -d <tagname>..."
@@ -12862,25 +13182,25 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Etiket için bir ileti yazın:\n"
" %s\n"
-"'%c' ile başlayan satırlar yok sayılacaktır.\n"
+"'%s' ile başlayan satırlar yok sayılacaktır.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Etiket için bir ileti yazın:\n"
" %s\n"
-"'%c' ile başlayan satırlar tutulacaktır; isterseniz onları "
+"'%s' ile başlayan satırlar tutulacaktır; isterseniz onları "
"kaldırabilirsiniz.\n"
msgid "unable to sign the tag"
@@ -12965,6 +13285,9 @@ msgstr "yalnızca birleştirilmeyen etiketleri yazdır"
msgid "print only tags of the object"
msgstr "yalnızca nesnenin etiketlerini yazdır"
+msgid "could not start 'git column'"
+msgstr "'git column' başlatılamadı"
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "'%s' seçeneğine yalnızca liste kipinde izin verilir"
@@ -13119,6 +13442,9 @@ msgstr "(okunabilir veri için) kaydedilmiş çözülmeyen çakışmaları unut"
msgid "write index in this format"
msgstr "indeksi bu biçimle yaz"
+msgid "report on-disk index format version"
+msgstr "diskteki indeks biçimi sürümünü raporla"
+
msgid "enable or disable split index"
msgstr "bölünmüş indeksi etkinleştir veya devre dışı bırak"
@@ -13143,6 +13469,14 @@ msgstr "dosyaları dosya sistemi monitöründe geçerli olarak imle"
msgid "clear fsmonitor valid bit"
msgstr "dosya sistemi monitöründe geçerli kısmını temizle"
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version: %d idi, %d olarak ayarlandı"
+
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -13161,8 +13495,8 @@ msgid ""
"core.untrackedCache is set to true; remove or change it, if you really want "
"to disable the untracked cache"
msgstr ""
-"core.untrackedCache 'true' olarak ayarlanmış; izlenmeyen önbelleği gerçekten "
-"devre dışı bırakmayı istiyorsanız bunu kaldırın veya değiştirin"
+"core.untrackedCache 'true' olarak ayarlanmış; izlenmeyen önbelleği devre "
+"dışı bırakmayı gerçekten istiyorsanız bunu kaldırın veya değiştirin"
msgid "Untracked cache disabled"
msgstr "İzlenmeyen önbellek devre dışı bırakıldı"
@@ -13172,7 +13506,7 @@ msgid ""
"to enable the untracked cache"
msgstr ""
"core.untrackedCache 'false' olarak ayarlanmış; izlenmeyen önbelleği "
-"gerçekten etkinleştirmek istiyorsanız bunu kaldırın veya değiştirin"
+"etkinleştirmeyi gerçekten istiyorsanız bunu kaldırın veya değiştirin"
#, c-format
msgid "Untracked cache enabled for '%s'"
@@ -13180,8 +13514,8 @@ msgstr "İzlenmeyen önbellek '%s' için etkinleştirildi"
msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
msgstr ""
-"core.fsmonitor ayarlanmamış; dosya sistemin monitörünü gerçekten "
-"etkinleştirmek istiyorsanız onu ayarlayın"
+"core.fsmonitor ayarlanmamış; dosya sistemin monitörünü etkinleştirmeyi "
+"gerçekten istiyorsanız onu ayarlayın"
msgid "fsmonitor enabled"
msgstr "dosya sistemi monitörü etkin"
@@ -13189,18 +13523,18 @@ msgstr "dosya sistemi monitörü etkin"
msgid ""
"core.fsmonitor is set; remove it if you really want to disable fsmonitor"
msgstr ""
-"core.fsmonitor ayarlanmış; dosya sistemi monitörünü gerçekten devre dışı "
-"bırakmak istiyorsanız onu kaldırın"
+"core.fsmonitor ayarlanmış; dosya sistemi monitörünü devre dışı bırakmayı "
+"gerçekten istiyorsanız onu kaldırın"
msgid "fsmonitor disabled"
msgstr "dosya sistemi monitörü devre dışı"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<seçenekler>] -d <bşvr-adı> [<eski-değer>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<seçenekler>] -d <bşvr-adı> [<eski-nesne-kimliği>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
msgstr ""
-"git update-ref [<seçenekler>] <bşvr-adı> <yeni-değer> [<eski-değer>]"
+"git update-ref [<seçenekler>] <bşvr-adı> <yeni-n-kiml> [<eski-n-kiml>]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<seçenekler>] --stdin [-z]"
@@ -13297,29 +13631,29 @@ 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"
+"If you meant to create a worktree containing a new unborn 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"
+"Bu depo için henüz doğmamış bir dal (işleme içermeyen dal) içeren\n"
+"bir çalışma ağacı oluşturmak istediyseniz bunu --orphan bayrağını\n"
+"kullanarak 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"
+"If you meant to create a worktree containing a new unborn 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"
+"Bu depo için henüz doğmamış bir dal (işleme içermeyen dal) içeren\n"
+"bir çalışma ağacı oluşturmak istediyseniz bunu --orphan bayrağını\n"
+"kullanarak yapabilirsiniz:\n"
"\n"
" git worktree add --orphan %s\n"
@@ -13378,6 +13712,10 @@ msgid "initializing"
msgstr "ilklendiriliyor"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "oluşturulan '%s' çalışma ağacı bulunamadı"
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "Çalışma ağacı hazırlanıyor (yeni dal '%s')"
@@ -13409,15 +13747,10 @@ msgstr ""
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"
+"present, stopping; use 'add -f' to override 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"
+"Bir uzak konum olmasına rağmen hiçbir yerel/uzak başvuru yok, durduruluyor;\n"
+"geçersiz kılmak veya önce bir uzak konum getirmek için 'add -f' kullanın"
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"
@@ -13428,8 +13761,8 @@ 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 "create unborn branch"
+msgstr "henüz doğmamış dal oluştur"
msgid "populate the new working tree"
msgstr "yeni çalışma ağacını doldur"
@@ -13451,11 +13784,8 @@ 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 "option '%s' and commit-ish cannot be used together"
+msgstr "'%s' seçeneği ve işlememsiler birlikte kullanılamaz"
msgid "added with --lock"
msgstr "--lock ile eklendi"
@@ -13659,9 +13989,6 @@ msgstr "tanımlanamayan üstbilgi: %s%s (%d)"
msgid "Repository lacks these prerequisite commits:"
msgstr "Depo aşağıdaki önkoşul işlemelere iye değil:"
-msgid "need a repository to verify a bundle"
-msgstr "bir demeti doğrulamak için bir depo gerekiyor"
-
msgid ""
"some prerequisite commits exist in the object store, but are not connected "
"to the repository's history"
@@ -13727,6 +14054,10 @@ msgid "terminating chunk id appears earlier than expected"
msgstr "iri parça numarası sonlandırması beklenenden önce ortaya çıkıyor"
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "iri parça kimliği %<PRIx32>, %d bayt hizalı değil"
+
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "düzgün olmayan iri parça ofseti %<PRIx64> ve %<PRIx64>"
@@ -13778,8 +14109,8 @@ msgstr "Hata raporu bildirimi için veri topla"
msgid "Move objects and refs by archive"
msgstr "Nesneleri ve başvuruları arşive göre taşı"
-msgid "Provide content or type and size information for repository objects"
-msgstr "Depo nesneleri için içerik veya tür/boyut bilgisi sağla"
+msgid "Provide contents or details of repository objects"
+msgstr "Depo nesnelerinin içeriğini veya ayrıntılarını sağla"
msgid "Display gitattributes information"
msgstr "gitattributes bilgisini görüntüle"
@@ -14054,6 +14385,9 @@ msgstr "Depoya ne itildiyse al"
msgid "Manage reflog information"
msgstr "Başvuru günlüğü bilgisini yönet"
+msgid "Low-level access to refs"
+msgstr "Başvurulara alt düzeyden erişim"
+
msgid "Manage set of tracked repositories"
msgstr "İzlenen depolar setini yönet"
@@ -14063,6 +14397,10 @@ msgstr "Bir depodaki paketlenmemiÅŸ nesneleri paketle"
msgid "Create, list, delete refs to replace objects"
msgstr "Nesne değiştirmek için başvurular oluştur, sil, listele"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"DENEYSEL: İşlemeleri yeni temelde yeniden oynat, çıplak depolarla da çalışır"
+
msgid "Generates a summary of pending changes"
msgstr "Bekleyen değişikliklerin bir özetini çıkart"
@@ -14184,8 +14522,8 @@ msgstr "Etiketlerin GPG imzasını doğrula"
msgid "Display version information about Git"
msgstr "Git sürüm bilgisini görüntüle"
-msgid "Show logs with difference each commit introduces"
-msgstr "Günlükleri her işlemenin sunduğu değişikliklerle göster"
+msgid "Show logs with differences each commit introduces"
+msgstr "Günlükleri her işlemenin değişiklikleriyle göster"
msgid "Manage multiple working trees"
msgstr "Birden çok çalışma ağacını yönet"
@@ -14301,6 +14639,32 @@ msgstr "Büyük Git depolarını yönetmek için bir araç"
msgid "commit-graph file is too small"
msgstr "commit-graph dosyası pek küçük"
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "commit-graph OID çıkış sayısı iri parçası boyutu yanlış"
+
+msgid "commit-graph fanout values out of order"
+msgstr "commit-graph çıkış sayısı değerleri sırasız: fanout[%d] = %u != %u"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "commit-graph OID arama iri parçası boyutu yanlış"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "commit-graph işleme verisi iri parçası boyutu yanlış"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "commit-graph kuşaklar iri parçası boyutu yanlış"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "commit-graph changed-path indeksi iri parçası boyutu pek küçük"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"commit-graph dosyasındaki pek küçük changed-path iri parçası (%<PRIuMAX> < "
+"%<PRIuMAX>) yok sayılıyor"
+
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "commit-graph imzası %X, %X ile eşleşmiyor"
@@ -14317,9 +14681,31 @@ msgstr "commit-graph sağlama sürümü %X, %X ile eşleşmiyor"
msgid "commit-graph file is too small to hold %u chunks"
msgstr "commit-graph dosyası %u iri parça tutmak için pek küçük"
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr ""
+"commit-graph'ten gerekli OID çıkış sayısı iri parçası eksik veya hasarlı"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "commit-graph'ten gerekli OID arama iri parçası eksik veya hasarlı"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr ""
+"commit-graph'ten gerekli OID çıkış sayısı iri parçası eksik veya hasarlı"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"uyumsuz ayarlardan dolayı '%s' commit-graph katmanı için olan Bloom "
+"süzgeçleri devre dışı bırakılıyor"
+
msgid "commit-graph has no base graphs chunk"
msgstr "commit-graph temel grafiği iri parçasına iye değil"
+msgid "commit-graph base graphs chunk is too small"
+msgstr "commit-graph temel grafiği iri parçası pek küçük"
+
msgid "commit-graph chain does not match"
msgstr "commit-graph zinciri eÅŸleÅŸmiyor"
@@ -14327,6 +14713,9 @@ msgstr "commit-graph zinciri eÅŸleÅŸmiyor"
msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "temel grafikteki işleme sayısı pek yüksek: %<PRIuMAX>"
+msgid "commit-graph chain file too small"
+msgstr "commit-graph zincir dosyası pek küçük"
+
#, 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"
@@ -14344,6 +14733,12 @@ msgstr "%s işlemesi bulunamadı"
msgid "commit-graph requires overflow generation data but has none"
msgstr "commit-graph, taşım oluşturma verisi gerektiriyor; ancak hiç yok"
+msgid "commit-graph overflow generation data is too small"
+msgstr "commit-graph, taşım üretim verisi pek küçük"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "commit-graph extra-edges işaretçisi sınırlar dışında"
+
msgid "Loading known commits in commit graph"
msgstr "İşleme grafiğindeki bilinen işlemeler yükleniyor"
@@ -14429,6 +14824,14 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr ""
"bir commit-graph yazılmaya çalışılıyor; ancak 'core.commitGraph' devre dışı"
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"bir commit-graph yazılmaya çalışılıyor; ancak 'commitGraph."
+"changedPathsVersion' (%d) desteklenmiyor"
+
msgid "too many commits to write graph"
msgstr "grafik yazımı için pek fazla işleme"
@@ -14471,20 +14874,6 @@ msgid "commit-graph parent list for commit %s terminates early"
msgstr "%s işlemesi için olan commit-graph üst öge listesi erkenden sonlanıyor"
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr ""
-"%s işlemesi için commit-graph kuşak sayısı sıfır; ancak başka yerlerde "
-"sıfırdan farklı"
-
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr ""
-"%s işlemesi için commit-graph kuşak sayısı sıfırdan farklı; ancak başka "
-"yerlerde sıfır"
-
-#, c-format
msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr "%s işlemesi için commit-graph kuşağı %<PRIuMAX> < %<PRIuMAX>"
@@ -14493,10 +14882,22 @@ 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>"
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"commit-graph'te hem sıfır hem de sıfır olmayan üretimler var (örneğin, "
+"'%s've '%s' iÅŸlemeleri)"
+
msgid "Verifying commits in commit graph"
msgstr "İşleme grafiğindeki işlemeler doğrulanıyor"
#, c-format
+msgid "could not parse commit %s"
+msgstr "%s işlemesi ayrıştırılamadı"
+
+#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s bir iÅŸleme deÄŸil!"
@@ -14520,6 +14921,10 @@ msgstr ""
"kullanarak bu iletiyi kapatabilirsiniz"
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr "%s işlemesi işleme grafiğinde var; ancak nesne veritabanında yok"
+
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr ""
"%s işlemesinin güvenilmeyen bir GPG imzası var, iddiaya göre %s tarafından."
@@ -14923,8 +15328,13 @@ 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 ASCII character"
-msgstr "core.commentChar yalnızca bir ASCII karakter olmalı"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s yenisatır içeremez"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s, en az bir karaktere iye olmalı"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -14960,10 +15370,6 @@ msgstr "'%s' baÅŸvurusu ikili bir nesneye iÅŸaret etmiyor"
msgid "unable to resolve config blob '%s'"
msgstr "'%s' yapılandırma ikili nesnesi çözülemiyor"
-#, c-format
-msgid "failed to parse %s"
-msgstr "%s ayrıştırılamadı"
-
msgid "unable to parse command-line config"
msgstr "komut satırı yapılandırması ayrıştırılamıyor"
@@ -14999,6 +15405,10 @@ msgid "failed to write new configuration file %s"
msgstr "yeni yapılandırma dosyası %s yazılamadı"
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "çok satırlı işlemeye izin verilmiyor: '%s'"
+
+#, c-format
msgid "could not lock config file %s"
msgstr "%s yapılandırma dosyası kilitlenemedi"
@@ -15431,9 +15841,6 @@ msgstr "arşiv yazılamadı"
msgid "--merge-base does not work with ranges"
msgstr "--merge-base erimlerle çalışmaz"
-msgid "--merge-base only works with commits"
-msgstr "--merge-base yalnızca işlemelerle çalışır"
-
msgid "unable to get HEAD"
msgstr "HEAD alınamıyor"
@@ -15494,6 +15901,10 @@ msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "'diff.submodule' yapılandırma değişkeni için bilinmeyen değer: '%s'"
#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "'%s' yapılandırması için bilinmeyen değer: %s"
+
+#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
@@ -15573,13 +15984,6 @@ msgstr "hatalı --color-moved argümanı: %s"
msgid "invalid mode '%s' in --color-moved-ws"
msgstr "--color-moved-ws içinde geçersiz kip '%s'"
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"diff-algorithm seçeneği şunları kabul eder: \"myers\", \"minimal\", "
-"\"patience\" ve \"histogram\""
-
#, c-format
msgid "invalid argument to %s"
msgstr "%s için geçersiz argüman"
@@ -15623,8 +16027,8 @@ msgstr "makinede okunabilen --stat"
msgid "output only the last line of --stat"
msgstr "--stat'ın yalnızca son satırını çıktı ver"
-msgid "<param1,param2>..."
-msgstr "<param1,param2>..."
+msgid "<param1>,<param2>..."
+msgstr "<param1>,<param2>..."
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
@@ -15634,8 +16038,8 @@ msgstr ""
msgid "synonym for --dirstat=cumulative"
msgstr "--dirstat=cumulative eşanlamlısı"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "--dirstat=files,param1,param2... eşanlamlısı"
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "--dirstat=files,<param1>,<param2>... eşanlamlısı"
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
@@ -15810,12 +16214,6 @@ msgstr "diff'i \"patience diff\" algoritmasını kullanarak oluştur"
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "diff'i \"histogram diff\" algoritmasını kullanarak oluştur"
-msgid "<algorithm>"
-msgstr "<algoritma>"
-
-msgid "choose a diff algorithm"
-msgstr "bir diff algoritması seç"
-
msgid "<text>"
msgstr "<metin>"
@@ -16277,17 +16675,21 @@ msgstr ""
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
msgstr ""
"git [-v | --version] [-h | --help] [-C <yol>] [-c <ad>=<deÄŸer>]\n"
" [--exec-path[=<yol>]] [--html-path] [--man-path] [--info-path]\n"
-" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-" [--git-dir=<yol>] [--work-tree=<yol>] [--namespace=<ad>]\n"
-" [--config-env=<ad>=<çevre-değişkeni>] <komut> [<argümanlar>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<ad>] [--config-env=<ad>=<çevre-"
+"deÄŸiÅŸkeni>]\n"
+" <komut> [<argümanlar>]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16627,13 +17029,13 @@ msgstr ""
"'%s' kancası yok sayıldı; çünkü bir yürütülebilir olarak ayarlanmamış.\n"
"Bu uyarıyı 'git config advice.ignoredHook false' ile kapatabilirsiniz."
+msgid "not a git repository"
+msgstr "bir git deposu deÄŸil"
+
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "--packfile için argüman geçerli bir sağlama olmalıdır ('%s' alındı)"
-msgid "not a git repository"
-msgstr "bir git deposu deÄŸil"
-
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
msgstr "http.postBuffer için negatif değer; %d olarak varsayılıyor"
@@ -16644,6 +17046,9 @@ msgstr "Delegasyon denetimi cURL < 7.22.0 tarafından desteklenmiyor"
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "Ortak anahtar iğnelemesi cURL < 7.39.0 tarafından desteklenmiyor"
+msgid "Unknown value for http.proactiveauth"
+msgstr "http.proactiveauth için bilinmeyen değer"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE cURL < 7.44.0 tarafından desteklenmiyor"
@@ -16660,6 +17065,12 @@ msgstr ""
msgid "Could not set SSL backend to '%s': already set"
msgstr "SSL arka ucu '%s' olarak ayarlanamadı: Halihazırda ayarlanmış"
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "http.cookiefile '-' konumundan çerezleri okuma reddediliyor"
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "boş http.cookiefile için http.savecookies yok sayılıyor"
+
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -16801,6 +17212,17 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "'%s.lock' oluşturulamıyor: %s"
+msgid "unable to create temporary object directory"
+msgstr "geçici nesne dizini oluşturulamıyor"
+
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "gevşek nesne indeksi %s yazılamadı"
+
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "gevşek nesne indeksi %s yazılamadı"
+
#, c-format
msgid "unexpected line: '%s'"
msgstr "beklenmedik satır: '%s'"
@@ -16812,6 +17234,10 @@ msgid "quoted CRLF detected"
msgstr "alıntılanmış CRLF algılandı"
#, c-format
+msgid "unable to format message: %s"
+msgstr "ileti biçimlendirilemiyor: %s"
+
+#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "%s altmodülü birleştirilemedi (çıkış yapılmadı)"
@@ -16824,6 +17250,10 @@ msgid "Failed to merge submodule %s (commits not present)"
msgstr "%s altmodülü birleştirilemedi (işlemeler yok)"
#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "hata: %s altmodülü birleştirilemedi (depo hasarlı)"
+
+#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr "%s altmodülü birleştirilemedi (işlemeler merge-base'i takip etmiyor)"
@@ -16849,12 +17279,13 @@ msgstr ""
"%s altmodülü birleştirilemedi; ancak birden çok olası birleştirmeler var:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "İç birleştirme yürütülemedi"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "hata: %s için iç birleştirme yürütülemedi"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "%s veritabanına eklenemedi"
+msgid "error: unable to add %s to database"
+msgstr "hata: %s veritabanına eklenemiyor"
#, c-format
msgid "Auto-merging %s"
@@ -16951,12 +17382,12 @@ msgstr ""
"ancak %s içinde silindi."
#, c-format
-msgid "cannot read object %s"
-msgstr "%s nesnesi okunamıyor"
+msgid "error: cannot read object %s"
+msgstr "hata: %s nesnesi okunamıyor"
#, c-format
-msgid "object %s is not a blob"
-msgstr "%s nesnesi ikili bir nesne deÄŸil"
+msgid "error: object %s is not a blob"
+msgstr "hata: %s nesnesi ikili bir nesne deÄŸil"
#, c-format
msgid ""
@@ -17095,6 +17526,10 @@ msgid "do not know what to do with %06o %s '%s'"
msgstr "şununla ne yapılacağı bilinmiyor: %06o %s '%s'"
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "%s altmodülü birleştirilemedi (depo hasarlı)"
+
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "%s altmodülü şu işlemeye ileri sarılıyor:"
@@ -17133,6 +17568,13 @@ msgstr ""
msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "%s altmodülü birleştirilemedi (birden çok birleştirme bulundu)"
+msgid "failed to execute internal merge"
+msgstr "iç birleştirme yürütülemedi"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "%s veritabanına eklenemiyor"
+
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
@@ -17237,6 +17679,14 @@ msgstr ""
"ÇAKIŞMA (y. adlandır/y. adlandır): Dizini %s->%s olarak adlandır (%s "
"içinde). Dizini %s->%s olarak adlandır (%s içinde)"
+#, c-format
+msgid "cannot read object %s"
+msgstr "%s nesnesi okunamıyor"
+
+#, c-format
+msgid "object %s is not a blob"
+msgstr "%s nesnesi ikili bir nesne deÄŸil"
+
msgid "modify"
msgstr "deÄŸiÅŸtir"
@@ -17297,48 +17747,6 @@ msgstr "'%s' nesnesi ayrıştırılamadı"
msgid "failed to read the cache"
msgstr "önbellek okunamadı"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "multi-pack-index OID ikiye bölümünün boyutu hatalı"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "multi-pack-index dosyası %s pek küçük"
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr "multi-pack-index imzası 0x%08x, 0x%08x imzası ile eşleşmiyor"
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "multi-pack-index sürümü %d tanımlanamıyor"
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "multi-pack-index sağlama sürümü %u, %u sürümü ile eşleşmiyor"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "multi-pack-index'ten gerekli pack-name iri parçası eksik"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "multi-pack-index'ten gerekli OID fanout iri parçası eksik"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "multi-pack-index'ten gerekli OID arama iri parçası eksik"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "multi-pack-index'ten gerekli nesne ofsetleri iri parçası eksik"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "multi-pack-index paket adlarının sırasız: '%s' şundan önce: '%s'"
-
-#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "hatalı pack-int-id: %u (%u toplam paket)"
-
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr "multi-pack-index bir 64 bit ofset depoluyor; ancak off_t pek küçük"
-
#, c-format
msgid "failed to add packfile '%s'"
msgstr "paket dosyası '%s' eklenemedi"
@@ -17362,9 +17770,6 @@ msgstr "satır ayrıştırılamadı: %s"
msgid "malformed line: %s"
msgstr "hatalı oluşturulmuş satır: %s"
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "var olan multi-pack-index yok sayılıyor; sağlama toplamı uyumsuzluğu"
-
msgid "could not load pack"
msgstr "paket yüklenemedi"
@@ -17372,6 +17777,20 @@ msgstr "paket yüklenemedi"
msgid "could not open index for %s"
msgstr "%s için indeks açılamadı"
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "'%s', '%s' ile bağlantılanamıyor"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "multi-pack-index %s konumunda temizlenemedi"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "biteşlem ile artımlı MIDX yazılamıyor"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr "var olan multi-pack-index yok sayılıyor; sağlama toplamı uyumsuzluğu"
+
msgid "Adding packfiles to multi-pack-index"
msgstr "Paket dosyaları multi-pack-index'e ekleniyor"
@@ -17397,15 +17816,128 @@ msgstr "indekslenecek paket dosyası yok."
msgid "refusing to write multi-pack .bitmap without any objects"
msgstr "bir nesne olmadan multi-pack .bitmap yazımı reddediliyor"
+msgid "unable to create temporary MIDX layer"
+msgstr "geçici MIDX katmanı oluşturulamıyor"
+
msgid "could not write multi-pack bitmap"
msgstr "çoklu paket biteşlem yazılamadı"
+msgid "unable to open multi-pack-index chain file"
+msgstr "multi-pack-index zincir dosyası açılamıyor"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "yeni multi-pack-index katmanı yeniden adlandırılamıyor"
+
msgid "could not write multi-pack-index"
msgstr "multi-pack-index yazılamadı"
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"artımlı bir multi-pack-index ögesinden paketlerin süresi doldurulamıyor"
+
+msgid "Counting referenced objects"
+msgstr "Başvurulmuş nesneler sayılıyor"
+
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Başvurulmamış paket dosyaları bulunuyor ve siliniyor"
+
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "artımlı bir multi-pack-index yeniden paketlenemiyor"
+
+msgid "could not start pack-objects"
+msgstr "pack-objects başlatılamadı"
+
+msgid "could not finish pack-objects"
+msgstr "pack-objects bitirilemedi"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "multi-pack-index OID çıkış sayısı boyutu yanlış"
+
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "multi-pack-index %s konumunda temizlenemedi"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr ""
+"oid çıkış sayısı sırasız: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "multi-pack-index OID arama iri parçası yanlış boyutlu"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "multi-pack-index OID nesne ofseti iri parçası yanlış boyutlu"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "multi-pack-index dosyası %s pek küçük"
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "multi-pack-index imzası 0x%08x, 0x%08x imzası ile eşleşmiyor"
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "multi-pack-index sürümü %d tanımlanamıyor"
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "multi-pack-index sağlama sürümü %u, %u sürümü ile eşleşmiyor"
+
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr "multi-pack-index'ten gerekli pack-name iri parçası eksik veya hasarlı"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr "multi-pack-index'ten gerekli OID fanout iri parçası eksik veya hasarlı"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr "multi-pack-index'ten gerekli OID arama iri parçası eksik veya hasarlı"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"multi-pack-index'ten gerekli nesne ofsetleri iri parçası eksik veya hasarlı"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "multi-pack-index pack-name iri parçası pek kısa"
+
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "multi-pack-index paket adlarının sırasız: '%s' şundan önce: '%s'"
+
+msgid "multi-pack-index chain file too small"
+msgstr "multi-pack-index zincir dosyası pek küçük"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "temel MIDX içindeki paket sayısı pek yüksek: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "temel MIDX içindeki nesne sayısı pek yüksek: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "geçersiz multi-pack-index zinciri: '%s' bir sağlama değil"
+
+msgid "unable to find all multi-pack index files"
+msgstr "tüm multi-pack-index dosyaları bulunamıyor"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "geçersiz MIDX nesnesi konumu, MIDX büyük olasılıkla hasarlı"
+
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "hatalı pack-int-id: %u (%u toplam paket)"
+
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX, BTMP iri parçasını içermiyor"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "biteşlemli %<PRIu32> paketi yüklenemedi"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr "multi-pack-index bir 64 bit ofset depoluyor; ancak off_t pek küçük"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr "multi-pack-index geniş ofseti sınırlar dışında"
msgid "multi-pack-index file exists, but failed to parse"
msgstr "multi-pack-index dosyası var; ancak ayrıştırılamadı"
@@ -17416,11 +17948,6 @@ msgstr "yanlış sağlama toplamı"
msgid "Looking for referenced packfiles"
msgstr "Başvurulmuş paket dosyaları aranıyor"
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr "oid fanout sırasız: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-
msgid "the midx contains no oid"
msgstr "midx bir oid içermiyor"
@@ -17449,18 +17976,6 @@ msgstr "paket dosyası %s için pack-index yüklenemedi"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "şunun için yanlış nesne ofseti: oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-msgid "Counting referenced objects"
-msgstr "Başvurulmuş nesneler sayılıyor"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "Başvurulmamış paket dosyaları bulunuyor ve siliniyor"
-
-msgid "could not start pack-objects"
-msgstr "pack-objects başlatılamadı"
-
-msgid "could not finish pack-objects"
-msgstr "pack-objects bitirilemedi"
-
#, c-format
msgid "unable to create lazy_dir thread: %s"
msgstr "lazy_dir iş parçacığı oluşturulamıyor: %s"
@@ -17507,6 +18022,25 @@ msgstr "%s içindeki notları yeniden yazma reddediliyor (refs/notes/ dışında
msgid "Bad %s value: '%s'"
msgstr "Hatalı %s değeri: '%s'"
+msgid "failed to decode tree entry"
+msgstr "ağaç girdisinin kodu çözülemedi"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "%s için olan ağaç girdisi eşlemlenemedi"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "işlemede hatalı %s"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "iÅŸleme nesnesinde %s %s eÅŸlemlenemiyor"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Nesne, %s -> %s olarak dönüştürülemedi"
+
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
msgstr "nesne dizini %s yok; şurayı denetleyin: .git/objects/info/alternates"
@@ -17609,6 +18143,18 @@ msgid "packed object %s (stored in %s) is corrupt"
msgstr "paketlenmiş nesne %s (%s içinde depolanıyor) hasarlı"
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "%s ögesinin %s ögesine eksik eşlemlemesi"
+
+#, c-format
+msgid "unable to open %s"
+msgstr "%s açılamıyor"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "'%s' ve '%s' dosyalarının içeriği farklı"
+
+#, c-format
msgid "unable to write file %s"
msgstr "%s dosyası yazılamıyor"
@@ -17662,6 +18208,10 @@ msgid "cannot read object for %s"
msgstr "%s için nesne okunamıyor"
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "%s nesnesi %s ögesine eşlemlenemiyor"
+
+#, c-format
msgid "object fails fsck: %s"
msgstr "nesne fsck'yi başarısız ediyor: %s"
@@ -17689,10 +18239,6 @@ msgid "%s is not a valid '%s' object"
msgstr "%s geçerli bir '%s' nesnesi değil"
#, c-format
-msgid "unable to open %s"
-msgstr "%s açılamıyor"
-
-#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "%s için sağlama uyuşmazlığı (%s bekleniyordu)"
@@ -17885,6 +18431,17 @@ msgstr "nesne ayrıştırılamıyor: %s"
msgid "hash mismatch %s"
msgstr "sağlama uyuşmazlığı %s"
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "biteşlem indeksi yazılırken yinelenen girdi: %s"
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "seçili olmayan işleme yazılmaya çalışıldı: '%s'"
+
+msgid "too many pseudo-merges"
+msgstr "pek çok yalancı birleştirme"
+
msgid "trying to write commit not in index"
msgstr "indekste olmayan işleme yazılmaya çalışılıyor"
@@ -17909,6 +18466,20 @@ msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr ""
"hasarlı biteşlem indeks dosyası (arama tablosuna sığmak için pek küçük)"
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"hasarlı biteşlem indeks dosyası (yalancı birleştirme tablo üstbilgisine "
+"sığmak için pek kısa)"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"hasarlı biteşlem indeks dosyası (yalancı birleştirme tablosuna sığmak için "
+"pek kısa)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "hasarlı biteşlem indeks dosyası, yalancı birleştirme tablosu pek kısa"
+
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "biteÅŸlem indeksinde yinelenen girdi: '%s'"
@@ -17940,9 +18511,12 @@ msgstr "çoklu paket biteşlemi gereken ters indeksi içermiyor"
msgid "could not open pack %s"
msgstr "%s paketi açılamadı"
+msgid "could not determine MIDX preferred pack"
+msgstr "MIDX yeğlenen paketi algılanamadı"
+
#, c-format
msgid "preferred pack (%s) is invalid"
-msgstr "tercih edilen (%s) paket geçersiz"
+msgstr "yeğlenen paket (%s) geçersiz"
msgid "corrupt bitmap lookup table: triplet position out of index"
msgstr "hasarlı biteşlem arama tablosu: üçlü konum indeks dışında"
@@ -17960,6 +18534,13 @@ msgstr ""
"hasarlı ewah biteşlemi: \"%s\" işlemesinin biteşleminde kısaltılmış üstbilgi"
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "paket yüklenemiyor: '%s', pack-reuse devre dışı bırakılıyor"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "yeğlenen paket hesaplanamıyor, pack-reuse devre dışı bırakılıyor"
+
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "'%s' nesnesi, tür biteşlemlerinde bulunamadı"
@@ -17989,6 +18570,10 @@ msgid "mismatch in bitmap results"
msgstr "biteşlem sonuçlarında uyuşmazlık"
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "yalancı birleştirme indeksi erim dışında (%<PRIu32> >= %<PRIuMAX>)"
+
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "öge bulunamadı: '%s'; '%s' paketinde, %<PRIuMAX> ofsetinde"
@@ -18047,6 +18632,12 @@ msgstr "geçersiz sağlama toplamı"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "%<PRIu64> konumunda geçersiz rev-index konumu: %<PRIu32> != %<PRIu32>"
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "multi-pack-index reverse-index iri parçası yanlış boyutlu"
+
+msgid "could not determine preferred pack"
+msgstr "yeğlenen paket algılanamadı"
+
msgid "cannot both write and verify reverse index"
msgstr "ters indeks dosyası hem yazılıp hem doğrulanamıyor"
@@ -18098,14 +18689,6 @@ msgid "%s requires a value"
msgstr "%s bir deÄŸer gerektiriyor"
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s, %s ile uyumsuz"
-
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s: baÅŸka bir ÅŸeyle uyumsuz"
-
-#, c-format
msgid "%s takes no value"
msgstr "%s bir değer almıyor"
@@ -18188,6 +18771,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-SAYI"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "--no-%s karşıtı"
+
msgid "expiry-date"
msgstr "son kullanım tarihi"
@@ -18215,7 +18802,15 @@ msgstr "yol belirtecini dosyadan oku"
msgid ""
"with --pathspec-from-file, pathspec elements are separated with NUL character"
msgstr ""
-"--pathspec-from-file ile, yol belirteci ögeleri NUL karakteri ile ayrılır"
+"--pathspec-from-file ile yol belirteci ögeleri NUL karakteri ile ayrılır"
+
+#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "hatalı Boole çevre değeri '%s', '%s' için"
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "%s ayrıştırılamadı"
#, c-format
msgid "Could not make %s writable by group"
@@ -18264,6 +18859,10 @@ msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s: 'literal' ve 'glob' birbiriyle uyumsuz"
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "'%s', dizin ağacının dışında"
+
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s: '%s', '%s' konumunda depo dışında"
@@ -18336,6 +18935,9 @@ msgstr "iş parçacıklarına ayrılmış 'lstat' oluşturulamıyor: %s"
msgid "unable to parse --pretty format"
msgstr "--pretty biçimi ayrıştırılamıyor"
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "gerekince getirme devre dışı; bazı nesneler kullanılamayabilir"
+
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote: getirme alt süreci çatallanamıyor"
@@ -18359,6 +18961,67 @@ msgstr "object-info: argümanlardan sonra floş bekleniyordu"
msgid "Removing duplicate objects"
msgstr "Yinelenmiş nesneler kaldırılıyor"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "%s için yalancı birleştirme düzenli ifadesi yüklenemedi: '%s'"
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s negatif dışı bir değer olmalı, öntanımlı değer kullanılıyor"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s, 0 ve 1 arasında olmalıdır, öntanımlı kullanılıyor"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s pozitif olmalıdır, öntanımlı kullanılıyor"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "yalancı birleştirme grubu '%s' içinde gerekli dizgi yok"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"yalancı birleştirme gribi '%s' içinde kararlıdan önce kararsız eşik var"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"yapılandırmadaki yalancı birleştirme düzenli ifadesinde pek çok yakalama "
+"grubu var (max=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"genişletilmiş yalancı birleştirme sınırlar dışında okundu (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"genişletilmiş yalancı birleştirme girdisi pek kısa (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr "%s işlemesi için yalancı birleştirme bulunamadı, %<PRIuMAX> ofsetinde"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"genişletilmiş yalancı birleştirme araması sınırlar dışında (%<PRIu32> >= "
+"%<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "sınırlar dışında okundu: (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "%s işlemesi için genişletilmiş yalancı birleştirme tablosu okunamadı"
+
msgid "could not start `log`"
msgstr "'log' başlatılamadı"
@@ -18415,10 +19078,6 @@ msgid "unable to add '%s' to index"
msgstr "'%s' indekse eklenemiyor"
#, c-format
-msgid "unable to stat '%s'"
-msgstr "'%s' dosyasının bilgileri alınamıyor"
-
-#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "'%s' hem bir dosya hem de bir dizin olarak görünüyor"
@@ -18526,10 +19185,6 @@ msgid "failed to convert to a sparse-index"
msgstr "bir sparse-index'e dönüştürülemedi"
#, c-format
-msgid "could not stat '%s'"
-msgstr "'%s' bilgileri alınamadı"
-
-#, c-format
msgid "unable to open git dir: %s"
msgstr "git dizini açılamıyor: %s"
@@ -18793,6 +19448,10 @@ msgid "expected format: %%(ahead-behind:<committish>)"
msgstr "beklenen biçim: %%(ahead-behind:<işlememsi>)"
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "beklenen biçim: %%(is-base:<işlememsi>)"
+
+#, c-format
msgid "malformed field name: %.*s"
msgstr "hatalı oluşturulmuş alan adı: %.*s"
@@ -18967,11 +19626,18 @@ msgstr ""
msgid "log for %s is empty"
msgstr "%s için olan günlük boş"
+msgid "refusing to force and skip creation of reflog"
+msgstr "başvuru günlüğünün oluşturulma/atlanma zorlanması reddediliyor"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "hatalı ada iye '%s' başvurusunu güncelleme reddediliyor"
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "'%s' yalancı başvurusunun güncellenmesi reddediliyor"
+
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "'%s' başvurusu için update_ref başarısız oldu: %s"
@@ -18994,10 +19660,6 @@ msgid "cannot process '%s' and '%s' at the same time"
msgstr "'%s' ve '%s' aynı anda işlenemiyor"
#, c-format
-msgid "could not remove reference %s"
-msgstr "%s başvurusu kaldırılamadı"
-
-#, c-format
msgid "could not delete reference %s: %s"
msgstr "%s baÅŸvurusu silinemedi: %s"
@@ -19006,6 +19668,99 @@ msgid "could not delete references: %s"
msgstr "baÅŸvurular silinemedi: %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "Başvuruların göç denemesi bitti, sonuç '%s' konumunda bulunabilir\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "geçici göç dizini '%s' kaldırılamadı"
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "göç ettirilen başvurular '%s' konumunda bulunabilir"
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"'%s' baÅŸvurusu kilitlenemiyor: '%s' hedefiyle bir sembolik baÅŸvuru "
+"bekleniyordu; ancak bu normal bir baÅŸvuru"
+
+#, c-format
+msgid "cannot open directory %s"
+msgstr "%s dizini açılamıyor"
+
+msgid "Checking references consistency"
+msgstr "Başvuruların tutarlılığı denetleniyor"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "başvuru adı tehlikeli: %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "'%s' başvurusu, var olmayan %s nesnesiyle yazılmaya çalışılıyor"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "işleme olmayan %s nesnesi '%s' dalına yazılmaya çalışılıyor"
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"'HEAD' için birden çok güncellemeye (ona başvuran '%s' ile olan bir tanesini "
+"de içeren) izin verilmiyor"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr "'%s' başvurusu kilitlenemiyor: '%s' başvurusu çözülemiyor"
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "'%s' baÅŸvurusu kilitlenemiyor: BaÅŸvuruyu okurken hata"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"'%s' için birden çok güncellemeye ('%s' sembolik bağı ile olan bir tanesini "
+"de içeren) izin verilmiyor"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "'%s' başvurusu kilitlenemiyor: Başvuru halihazırda var"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr "'%s' baÅŸvurusu kilitlenemiyor: BaÅŸvuru eksik; ancak %s bekleniyordu"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "'%s' başvurusu kilitlenemiyor: %s üzerinde; ancak %s bekleniyordu"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "reftable: İşlem hazırlığı: %s"
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "reftable: İşlem başarısız: %s"
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "yığın kompaktlaştırılamıyor: %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "başvuru adı %s bulunamadı"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "başvuru adı %s bir sembolik bağ, onu kopyalamak desteklenmiyor"
+
+#, c-format
msgid "invalid refspec '%s'"
msgstr "geçersiz başvuru belirteci '%s'"
@@ -19014,6 +19769,10 @@ msgid "invalid quoting in push-option value: '%s'"
msgstr "push-option değerinde geçersiz tırnak içine alım: '%s'"
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "object-format için bilinmeyen değer: %s"
+
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs geçerli değil: bu bir git deposu mu?"
@@ -19456,8 +20215,19 @@ msgid "resolve-undo records `%s` which is missing"
msgstr "resolve-undo, kayıp olan '%s' ögesini kaydetmiş"
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "soy yolu argümanı %s için işleme alınamadı"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s var; ancak bir sembolik baÄŸ"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge; MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD veya REBASE_HEAD yalancı "
+"başvurularından birini gerektiriyor"
+
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "--ancestry-path argümanı %s için olan işleme alınamadı"
msgid "--unpacked=<packfile> no longer supported"
msgstr "--unpacked=<paketdosyası> artık desteklenmiyor"
@@ -19551,8 +20321,18 @@ msgstr "klonlama sırasında tam çalışma dizini oluştur"
msgid "only download metadata for the branch that will be checked out"
msgstr "yalnızca çıkış yapılacak dalın üstverisini indir"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<seçenekler>] [--] <depo> [<dizin>]"
+msgid "create repository within 'src' directory"
+msgstr "'src' dizininde depo oluÅŸtur"
+
+msgid "specify if tags should be fetched during clone"
+msgstr "etiketlerin klonlama sırasında getirilip getirilmeyeceğini belirt"
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <ana-dal>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<listeleme>]"
#, c-format
msgid "cannot deduce worktree name from '%s'"
@@ -19571,6 +20351,10 @@ msgid "could not configure remote in '%s'"
msgstr "'%s' içindeki uzak konum yapılandırılamadı"
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "'%s' içindeki etiketler devre dışı bırakılamıyor"
+
+#, c-format
msgid "could not configure '%s'"
msgstr "'%s' yapılandırılamadı"
@@ -19603,12 +20387,28 @@ msgid "could not remove stale scalar.repo '%s'"
msgstr "eskimiş scalar.repo '%s' kaldırılamadı"
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "eskimiş scalar.repo '%s' kaldırılıyor"
+msgid "removed stale scalar.repo '%s'"
+msgstr "eskimiş scalar.repo '%s' kaldırıldı"
+
+#, c-format
+msgid "repository at '%s' has different owner"
+msgstr "'%s' konumundaki deponun sahibi başkası"
+
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "'%s' konumundaki depoda bir biçim sorunu var"
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git deposu '%s' içinde gitti"
+msgid "repository not found in '%s'"
+msgstr "'%s' konumunda depo bulunamadı"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"bu deponun kaydını Scalar'dan kaldırmak için şu komutu çalıştırın:\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
msgid ""
"scalar run <task> [<enlistment>]\n"
@@ -19719,6 +20519,19 @@ msgid "unknown action: %d"
msgstr "bilinmeyen eylem: %d"
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 ""
+"Tüm çakışmaları el ile çözün, onları \"git add/rm <çakışan-dosyalar>\"\n"
+"ile tamam olarak imleyin, ardından \"git rebase --continue\"\n"
+"çalıştırın. Bunun yerine bu işlemeyi atlayabilirsiniz: \"git rebase\n"
+"--skip\" yapın. İptal edip \"git rebase\" öncesine geri dönmek için\n"
+"\"git rebase --abort\" çalıştırın."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -19938,10 +20751,6 @@ msgid "could not update %s"
msgstr "%s güncellenemedi"
#, c-format
-msgid "could not parse commit %s"
-msgstr "%s işlemesi ayrıştırılamadı"
-
-#, c-format
msgid "could not parse parent commit %s"
msgstr "üst işleme %s ayrıştırılamadı"
@@ -20009,10 +20818,6 @@ msgid "%s: cannot parse parent commit %s"
msgstr "%s: üst işleme %s ayrıştırılamıyor"
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "'%s', '%s' olarak yeniden adlandırılamadı"
-
-#, c-format
msgid "could not revert %s... %s"
msgstr "%s geri alınamadı... %s"
@@ -20046,12 +20851,52 @@ msgstr ""
"update-ref, tümüyle kalifiye bir başvuru adı gerektiriyor; örn. refs/heads/%s"
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "geçersiz komut %.*s"
+msgid "'%s' does not accept merge commits"
+msgstr "'%s' birleÅŸtirme iÅŸlemelerini kabul etmiyor"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"'pick', bir birleÅŸtirme iÅŸlemesi almaz. BirleÅŸtirmeyi\n"
+"yeniden oynatmak istediyseniz işlemede 'merge -C' kullanın."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"'reword', bir birleÅŸtirme iÅŸlemesi almaz. BirleÅŸtirmeyi\n"
+"yeniden oynatmak ve işleme iletisini düzenlemek istediyseniz\n"
+"işlemede 'merge -c' kullanın."
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"'edit', bir birleÅŸtirme iÅŸlemesi almaz. BirleÅŸtirmeyi\n"
+"yeniden oynatmak istediyseniz işlemede 'merge -C' kullanın,sonrasında "
+"denetimin size geri verilmesi için 'break'\n"
+"yapın; böylece 'git commit --amend && git rebase --continue'\n"
+"yapabilirsiniz."
+
+msgid "cannot squash merge commit into another commit"
+msgstr "birleştirme işlemesi başka bir işlemeye tıkıştırılamaz"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s argüman kabul etmiyor: '%s'"
+msgid "invalid command '%.*s'"
+msgstr "geçersiz komut %.*s"
#, c-format
msgid "missing arguments for %s"
@@ -20165,9 +21010,8 @@ msgstr ""
msgid "cannot read HEAD"
msgstr "HEAD okunamıyor"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "'%s', '%s' konumuna kopyalanamıyor"
+msgid "could not write commit message file"
+msgstr "işleme iletisi dosyası yazılamadı"
#, c-format
msgid ""
@@ -20334,6 +21178,9 @@ msgstr "Kendiliğinden zulalama çakışmalara neden oldu."
msgid "Autostash exists; creating a new stash entry."
msgstr "KendiliÄŸinden zulalama mevcut; yeni bir zula girdisi oluÅŸturuluyor."
+msgid "autostash reference is a symref"
+msgstr "kendiliÄŸinden zulalama baÅŸvurusu bir sembol baÅŸvurusu"
+
msgid "could not detach HEAD"
msgstr "HEAD ayrılamadı"
@@ -20366,14 +21213,14 @@ msgstr ""
"\tgit rebase --continue\n"
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "Yeniden temellendiriliyor: (%d/%d)%s"
-
-#, c-format
msgid "Stopped at %s... %.*s\n"
msgstr "%s konumunda durdu... %.*s\n"
#, c-format
+msgid "Rebasing (%d/%d)%s"
+msgstr "Yeniden temellendiriliyor: (%d/%d)%s"
+
+#, c-format
msgid "unknown command %d"
msgstr "bilinmeyen komut %d"
@@ -20502,6 +21349,10 @@ msgid "unable to set up work tree using invalid config"
msgstr "geçersiz yapılandırma kullanılarak çalışma ağacı kurulamıyor"
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "'%s', halihazırda '%s' olarak belirtilmiş"
+
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "Beklenen git repo sürümü <= %d, %d bulundu"
@@ -20558,6 +21409,22 @@ msgstr "cwd'ye geri dönülemiyor"
msgid "failed to stat '%*s%s%s'"
msgstr "'%*s%s%s' bilgileri alınamadı"
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' mutlak deÄŸil"
+
+#, 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' konumundaki depoda belirsiz iyelik algılandı\n"
+"%sBu dizin için istisna eklemek için şunu çağırın:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
msgid "Unable to read current working directory"
msgstr "Şu anki çalışma dizini okunamıyor"
@@ -20579,18 +21446,6 @@ msgstr ""
"ayarlanmamış)."
#, 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' konumundaki depoda belirsiz iyelik algılandı\n"
-"%sBu dizin için istisna eklemek için şunu çağırın:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-
-#, c-format
msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
msgstr "çıplak depo '%s', kullanılamaz (safe.bareRepository '%s')"
@@ -20645,6 +21500,10 @@ msgid "invalid initial branch name: '%s'"
msgstr "geçersiz başlangıç dalı adı: '%s'"
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: --initial-branch=%s yok sayıldı"
+
+#, c-format
msgid "unable to handle file type %d"
msgstr "%d dosya türü ele alınamıyor"
@@ -20655,15 +21514,16 @@ 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"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr ""
+"depo başka bir başvuru depolama biçimiyle yeniden ilklendirilmeye çalışılıyor"
+
#, 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"
@@ -20686,6 +21546,21 @@ msgstr "indeks girdisi bir dizin; ancak aralıklı değil (%08x)"
msgid "cannot use split index with a sparse index"
msgstr "bir aralıklı indeksle bölünmüş indeks kullanılamıyor"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "hatalı %s biçimi: '%s' ögesi '(' ile başlamıyor"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "hatalı %s biçimi: '%s' ögesi ')' ile sonlanmıyor"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "hatalı %s biçimi: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
msgid "%u.%2.2u GiB"
@@ -20874,6 +21749,15 @@ msgid "submodule git dir '%s' is inside git dir '%.*s'"
msgstr "altmodül git dizini '%s', '%.*s' git dizini içinde"
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"'%.*s' ögesinin bir sembolik bağ olması beklenmiyordu, '%s' altmodül yolunda"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "'%s' altmodül yolunun bir sembolik bağ olması beklenmiyordu"
+
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
@@ -20911,10 +21795,6 @@ msgstr "'%s', lstat yapılamadı"
msgid "no remote configured to get bundle URIs from"
msgstr "demet URI'lerini almak için bir uzak konum yapılandırılmamış"
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "'%s' uzak konumunun yapılandırılmış bir URL'si yok"
-
msgid "could not get the bundle-uri list"
msgstr "bundle-uri listesi alınamadı"
@@ -20927,12 +21807,6 @@ msgstr "her bir yinelemeden önce önbellek ağacını temizle"
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr "önbellek ağacındaki geçersizleştirilecek girdi sayısı (öntanımlı 0)"
-msgid "unhandled options"
-msgstr "beklenmeyen seçenekler"
-
-msgid "error preparing revisions"
-msgstr "revizyonlar hazırlanırken hata"
-
#, c-format
msgid "commit %s is not marked reachable"
msgstr "%s işlemesi ulaşılabilir olarak imlenmedi"
@@ -21002,6 +21876,24 @@ msgstr "jeton"
msgid "command token to send to the server"
msgstr "sunucuya gönderilecek komut jetonu"
+msgid "unit-test [<options>]"
+msgstr "unit-test [<seçenekler>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "ilk başarısız sınamada anında çık"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "yalnızca sınama paketini veya bireysel <süit[::sınama]> çalıştır"
+
+msgid "suite"
+msgstr "suite"
+
+msgid "exclude test suite <suite>"
+msgstr "<süit> sınama süitini dışla"
+
#, c-format
msgid "running trailer command '%s' failed"
msgstr "'%s' artbilgi komutunu çalıştırma başarısız oldu"
@@ -21014,29 +21906,6 @@ msgstr "bilinmeyen değer '%s' ('%s' anahtarı için)"
msgid "empty trailer token in trailer '%.*s'"
msgstr "'%.*s' artbilgisi içinde boş artbilgi jetonu"
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "'%s' girdi dosyası okunamadı"
-
-#, c-format
-msgid "could not stat %s"
-msgstr "%s dosya bilgileri alınamadı"
-
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "%s dosyası sıradan bir dosya değil"
-
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "%s dosyası kullanıcı tarafından yazılabilir değil"
-
-msgid "could not open temporary file"
-msgstr "geçici dosya açılamadı"
-
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "geçici dosya adı %s olarak değiştirilemedi"
-
msgid "full write to remote helper failed"
msgstr "uzak konum yardımcısına tam yazım başarısız"
@@ -21086,9 +21955,6 @@ msgstr "uzak servis yolu ayarlama protokol tarafından desteklenmiyor"
msgid "invalid remote service path"
msgstr "geçersiz uzak konum servis yolu"
-msgid "operation not supported by protocol"
-msgstr "işlem protokol tarafından desteklenmiyor"
-
#, c-format
msgid "can't connect to subservice %s"
msgstr "%s altservisine bağlanılamıyor"
@@ -21135,8 +22001,8 @@ msgid "remote-helper doesn't support push; refspec needed"
msgstr "remote-helper itme desteklemiyor; baÅŸvuru belirteci gerekli"
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "%s yardımcısı 'force' desteklemiyor"
+msgid "helper %s does not support '--force'"
+msgstr "%s yardımcısı '--force' desteklemiyor"
msgid "couldn't run fast-export"
msgstr "fast-export çalıştırılamadı"
@@ -21219,10 +22085,6 @@ msgid "support for protocol v2 not implemented yet"
msgstr "protokol v2 desteği henüz yerine getirilmedi"
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "'%s' yapılandırması için bilinmeyen değer: %s"
-
-#, c-format
msgid "transport '%s' not allowed"
msgstr "'%s' taşıyıcısına izin verilmiyor"
@@ -21275,6 +22137,9 @@ msgstr "bundle-uri işlemi protokol tarafından desteklenmiyor"
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "sunucu tarafından tanıtılan bundle-uri listesi alınamadı"
+msgid "operation not supported by protocol"
+msgstr "işlem protokol tarafından desteklenmiyor"
+
msgid "too-short tree object"
msgstr "ağaç nesnesi çok kısa"
@@ -21550,6 +22415,10 @@ msgstr "geçersiz kapı numarası"
msgid "invalid '..' path segment"
msgstr "geçersiz '..' yol kesimi"
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "hata: ileti biçimlendirilemiyor: %s\n"
+
msgid "usage: "
msgstr "kullanım: "
@@ -21661,6 +22530,9 @@ msgstr "'%s' eriÅŸilemiyor"
msgid "unable to get current working directory"
msgstr "geçerli çalışma dizini alınamıyor"
+msgid "unable to get random bytes"
+msgstr "rastgele baytlar alınamıyor"
+
msgid "Unmerged paths:"
msgstr "BirleÅŸtirilmemiÅŸ yollar:"
@@ -22095,6 +22967,10 @@ msgstr "Ek olarak, indeksiniz işlenmemiş değişiklikler içeriyor."
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "%s yapılamıyor: İndeksiniz işlenmemiş değişiklikler içeriyor."
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "'%s' bilinmeyen biçemi şunun için verildi: '%s'"
+
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22184,6 +23060,9 @@ msgstr "'%s.final' yazılan e-postayı içeriyor.\n"
msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases diğer seçeneklerle uyumsuz\n"
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases ve --translate-aliases birlikte kullanılamaz\n"
+
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -22277,13 +23156,13 @@ msgstr ""
"Bir özet göndermek istemiyorsanız gövde kısmını temizleyin.\n"
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "%s açılamadı: %s"
-
-#, perl-format
msgid "Failed to open %s.final: %s"
msgstr "%s.final açılamadı: %s"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "%s açılamadı: %s"
+
msgid "Summary email is empty, skipping it\n"
msgstr "Özet e-postası boş, atlanıyor\n"
@@ -22392,24 +23271,24 @@ msgid "Failed to send %s\n"
msgstr "%s gönderilemedi\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "%s gönderilir gibi yapıldı\n"
+msgid "Dry-Sent %s"
+msgstr "%s gönderilir gibi yapıldı"
#, perl-format
-msgid "Sent %s\n"
-msgstr "%s gönderildi\n"
+msgid "Sent %s"
+msgstr "%s gönderildi"
-msgid "Dry-OK. Log says:\n"
-msgstr "Sınama tamam. Günlük çıktısı:\n"
+msgid "Dry-OK. Log says:"
+msgstr "Sınama tamam. Günlük çıktısı:"
-msgid "OK. Log says:\n"
-msgstr "Tamam. Günlük çıktısı:\n"
+msgid "OK. Log says:"
+msgstr "Tamam. Günlük çıktısı:"
msgid "Result: "
msgstr "Sonuç: "
-msgid "Result: OK\n"
-msgstr "Sonuç: Tamam\n"
+msgid "Result: OK"
+msgstr "Sonuç: Tamam"
#, perl-format
msgid "can't open file %s"
@@ -22482,4 +23361,4 @@ msgstr "%s, yedek sonek '%s' ile atlanıyor.\n"
#. TRANSLATORS: please keep "[y|N]" as is.
#, perl-format
msgid "Do you really want to send %s? [y|N]: "
-msgstr "%s ögesini gerçekten göndermek istiyor musunuz? [y|N]: "
+msgstr "%s ögesini göndermeyi gerçekten istiyor musunuz? [y|N]: "
diff --git a/po/uk.po b/po/uk.po
index 5a11cc6614..297f7b0687 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -6,10 +6,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: Git v2.42.0\n"
+"Project-Id-Version: Git v2.46\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"
+"POT-Creation-Date: 2023-04-11 09:55-0700\n"
+"PO-Revision-Date: 2024-07-24 08:45-0700\n"
"Last-Translator: Arkadii Yakovets <ark@cho.red>\n"
"Language-Team: Ukrainian <https://github.com/arkid15r/git-uk-l10n/>\n"
"Language: uk\n"
@@ -18,7 +18,7 @@ msgstr ""
"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"
+"X-Generator: Poedit 3.4.2\n"
#, c-format
msgid "Huh (%s)?"
@@ -496,12 +496,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"Щоб видалити Ñ€Ñдки \"%c\", зробіть Ñ—Ñ… Ñ€Ñдками \" \" (контекÑÑ‚).\n"
"Щоб видалити Ñ€Ñдки \"%c\", вилучіть Ñ—Ñ….\n"
-"Буде видалено Ñ€Ñдки, що починаютьÑÑ Ð· %c.\n"
+"РÑдки, що починаютьÑÑ Ð· %s, будуть видалені.\n"
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
@@ -525,7 +525,6 @@ msgstr "\"git apply --cached\" завершивÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾"
#. (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 ""
@@ -550,6 +549,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk\n"
"? - print help\n"
msgstr ""
"j - залишити цей шматок невизначеним, перейти до наÑтупного невизначеного "
@@ -562,8 +562,13 @@ msgstr ""
"/ - шукати шматок, що відповідає заданому регвиру\n"
"s - розбити поточний шматок на менші шматки\n"
"e - редагувати поточний шматок вручну\n"
+"p - показати поточний шматок\n"
"? - показати довідку\n"
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "ОчікувавÑÑ Ð»Ð¸ÑˆÐµ один Ñимвол, отримано \"%s\""
+
msgid "No previous hunk"
msgstr "Ðемає попереднього шматка"
@@ -613,9 +618,19 @@ msgstr "Розщепити на %d шматків."
msgid "Sorry, cannot edit this hunk"
msgstr "Вибачайте, не можу редагувати цей шматок"
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Ðевідома команда: \"%s\" (викориÑтовуйте \"?\" Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¸)"
+
msgid "'git apply' failed"
msgstr "\"git apply\" завершивÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾"
+msgid "No changes."
+msgstr "Ðічого не змінено."
+
+msgid "Only binary files changed."
+msgstr "Змінено лише бінарні файли."
+
#, c-format
msgid ""
"\n"
@@ -625,8 +640,8 @@ msgstr ""
"Вимкнути це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¼Ð¾Ð¶Ð½Ð° за допомогою \"git config advice.%s false\""
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sпідказка: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sпідказка:%s%.*s%s\n"
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr "ВиÑÐ¼Ð¸ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ðµ, оÑкільки у Ð²Ð°Ñ Ñ” не злиті файли."
@@ -1139,10 +1154,6 @@ 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"
@@ -1445,6 +1456,10 @@ msgid "Unexpected option --output"
msgstr "Ðеочікувана Ð¾Ð¿Ñ†Ñ–Ñ --output"
#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "зайвий параметр командного Ñ€Ñдка: \"%s\""
+
+#, c-format
msgid "Unknown archive format '%s'"
msgstr "Ðевідомий формат архіву \"%s\""
@@ -1486,10 +1501,21 @@ msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ñ‚Ð¾ великого файлу gitattribu
msgid "ignoring overly large gitattributes blob '%s'"
msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ñ‚Ð¾ великих gitattributes blob \"%s\""
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "неможливо викориÑтати --attr-source або GIT_ATTR_SOURCE без Ñховища"
+
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "невірний --attr-source або GIT_ATTR_SOURCE"
#, c-format
+msgid "unable to stat '%s'"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ stat Ð´Ð»Ñ \"%s\""
+
+#, c-format
+msgid "unable to read %s"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ %s"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Ðевірно процитований вміÑÑ‚ у файлі \"%s\": %s"
@@ -1559,6 +1585,10 @@ msgid "could not create file '%s'"
msgstr "не вдалоÑÑ Ñтворити файл \"%s\""
#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити \"show\" Ð´Ð»Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ð° \"%s\""
+
+#, c-format
msgid "could not read file '%s'"
msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл \"%s\""
@@ -1587,7 +1617,6 @@ 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"
@@ -1668,16 +1697,17 @@ msgstr ""
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
#. around.
#.
-
#, c-format
msgid " %s\n"
msgstr " %s\n"
@@ -1685,7 +1715,6 @@ 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"
@@ -1712,6 +1741,9 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "\"%s\" не Ñ” допуÑтимою назвою гілки"
+msgid "See `man git check-ref-format`"
+msgstr "ДивітьÑÑ \"man git check-ref-format\""
+
#, c-format
msgid "a branch named '%s' already exists"
msgstr "гілка з ім’Ñм \"%s\" вже Ñ–Ñнує"
@@ -1781,8 +1813,8 @@ msgid "submodule '%s': cannot create branch '%s'"
msgstr "підмодуль \"%s\": неможливо Ñтворити гілку \"%s\""
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "\"%s\" вже Ñ–Ñнує в \"%s\""
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "\"%s\" вже викориÑтовуєтьÑÑ Ñ€Ð¾Ð±Ð¾Ñ‡Ð¸Ð¼ деревом в \"%s\""
msgid "git add [<options>] [--] <pathspec>..."
msgstr "git add [<опції>] [--] <визначник шлÑху>..."
@@ -1794,32 +1826,22 @@ 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 "could not read the index"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ індекÑ"
msgid "editing patch failed"
msgstr "не вдалоÑÑ Ð²Ñ–Ð´Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ñ‚Ð¸ латку"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ stat \"%s\""
+msgid "could not stat '%s'"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ stat \"%s\""
-msgid "Empty patch. Aborted."
-msgstr "ÐŸÐ¾Ñ€Ð¾Ð¶Ð½Ñ Ð»Ð°Ñ‚ÐºÐ°. Перервано."
+msgid "empty patch. aborted"
+msgstr "Ð¿Ð¾Ñ€Ð¾Ð¶Ð½Ñ Ð»Ð°Ñ‚ÐºÐ°. перервано"
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Ðе вдалоÑÑ Ð·Ð°ÑтоÑувати \"%s\""
+msgid "could not apply '%s'"
+msgstr "не вдалоÑÑ Ð·Ð°ÑтоÑувати \"%s\""
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr "ÐаÑтупні шлÑхи ігноруютьÑÑ Ð¾Ð´Ð½Ð¸Ð¼ з ваших .gitignore файлів:\n"
@@ -1911,14 +1933,8 @@ msgstr ""
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 "Use -f if you really want to add them."
+msgstr "СкориÑтайтеÑÑŒ -f, Ñкщо ви дійÑно хочете Ñ—Ñ… додати."
msgid "adding files failed"
msgstr "Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð² завершилоÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾"
@@ -1935,18 +1951,15 @@ msgstr "\"%s\" та аргументи визначника шлÑху не мо
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 "Maybe you wanted to say 'git add .'?"
+msgstr "Можливо, ви хотіли вказати \"git add .\"?"
msgid "index file corrupt"
msgstr "індекÑний файл пошкоджено"
+msgid "unable to write new index file"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати новий файл індекÑу"
+
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "невірна Ð´Ñ–Ñ \"%s\" Ð´Ð»Ñ \"%s\""
@@ -2016,18 +2029,20 @@ msgid "Failed to split patches."
msgstr "Ðе вдалоÑÑ Ñ€Ð¾Ð·Ñ‰ÐµÐ¿Ð¸Ñ‚Ð¸ латки."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Коли ви вирішите цю проблему, виконайте \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "Коли ви вирішите цю проблему, виконайте \"%s --continue\".\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
msgstr ""
-"Якщо ви бажаєте пропуÑтити цю латку, виконайте \"%s --skip\" заміÑть цього."
+"Якщо ви бажаєте пропуÑтити цю латку, виконайте \"%s --skip\" заміÑть цього.\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
-"Щоб запиÑати порожню латку Ñк порожній коміт, виконайте \"%s --allow-empty\"."
+"Щоб запиÑати порожню латку Ñк порожній коміт, виконайте \"%s --allow-"
+"empty\".\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
@@ -2094,7 +2109,6 @@ msgstr "Тіло коміту:"
#. 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 ""
@@ -2158,9 +2172,6 @@ msgstr ""
"щоб позначити Ñ—Ñ… Ñк такі.\n"
"Ви можете виконати \"git rm\" Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ñƒ, щоб прийнÑти \"видалено ними\"."
-msgid "unable to write new index file"
-msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати новий файл індекÑу"
-
#, c-format
msgid "Could not parse object '%s'."
msgstr "Ðе вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ об'єкт '%s'."
@@ -2179,10 +2190,6 @@ msgstr ""
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 [<опції>] [(<Ñкринька> [<поштова директоріÑ>)...]"
@@ -2261,6 +2268,9 @@ msgstr "перервати латаннÑ, але залишити HEAD на Ñ‚Ð
msgid "show the patch being applied"
msgstr "показати латку, що заÑтоÑовуєтьÑÑ"
+msgid "try to apply current patch again"
+msgstr "Ñпробувати заÑтоÑувати поточну латку ще раз"
+
msgid "record the empty patch as an empty commit"
msgstr "запиÑати порожню латку Ñк порожній коміт"
@@ -2317,9 +2327,6 @@ 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-пакет"
@@ -2334,10 +2341,10 @@ msgid "git archive: expected a flush"
msgstr "git archive: очікувалоÑÑŒ flush"
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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}=<термін>] "
+"git bisect start [--term-(new,bad)=<термін> --term-(old,good)=<термін>] "
"[--no-checkout] [--first-parent] [<поганий> [<добрий>...]] [--] "
"[<визначник шлÑху>...]"
@@ -2353,8 +2360,8 @@ msgstr "git bisect reset [<коміт>]"
msgid "git bisect replay <logfile>"
msgstr "git bisect replay <лог файл>"
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <команда>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <команда> [<аргумент>...]"
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2442,7 +2449,6 @@ msgstr "біÑÐµÐºÑ†Ñ–Ñ Ð»Ð¸ÑˆÐµ з %s комітом"
#. translation. The program will only accept English input
#. at this point.
#.
-
msgid "Are you sure [Y/n]? "
msgstr "Ви впевнені [Y/n]? "
@@ -2519,7 +2525,6 @@ msgstr "Вам потрібно почати з \"git bisect start\"\n"
#. 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]? "
@@ -2737,7 +2742,6 @@ msgstr ""
#. your language may need more or fewer display
#. columns.
#.
-
msgid "4 years, 11 months ago"
msgstr "4 роки, 11 міÑÑців тому"
@@ -2782,44 +2786,47 @@ 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."
+" '%s', but not yet merged to HEAD"
msgstr ""
"Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð³Ñ–Ð»ÐºÐ¸ \"%s\", Ñка була злита з\n"
-" \"%s\", але ще не злита з HEAD."
+" \"%s\", але ще не злита з HEAD"
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
"ÑƒÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð³Ñ–Ð»ÐºÐ¸ \"%s\", Ñка ще не була злита з\n"
-" \"%s\", незважаючи на те, що вже злита з HEAD."
+" \"%s\", незважаючи на те, що вже була злита з HEAD"
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ об’єкт коміту Ð´Ð»Ñ \"%s\""
+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'."
+msgid "the branch '%s' is not fully merged"
+msgstr "гілка \"%s\" злита не повніÑтю"
+
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
msgstr ""
-"Гілка \"%s\" злита не повніÑтю.\n"
-"Якщо ви впевнені, що хочете її видалити, виконайте \"git branch -D %s\"."
+"Якщо ви впевнені, що хочете її видалити, виконайте \"git branch -D %s\""
-msgid "Update of config-file failed"
-msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ конфігураційний файл"
+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\""
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr ""
+"неможливо видалити гілку \"%s\", Ñка викориÑтовуєтьÑÑ Ñ€Ð¾Ð±Ð¾Ñ‡Ð¸Ð¼ деревом у "
+"\"%s\""
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "віддалено відÑтежувана гілка \"%s\" не знайдена."
+msgid "remote-tracking branch '%s' not found"
+msgstr "віддалено відÑтежувана гілка \"%s\" не знайдена"
#, c-format
msgid ""
@@ -2830,8 +2837,8 @@ msgstr ""
"Ви забули --remote?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "гілка \"%s\" не знайдена."
+msgid "branch '%s' not found"
+msgstr "гілка \"%s\" не знайдена"
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -2852,62 +2859,62 @@ 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"
+msgid "branch %s is being rebased at %s"
+msgstr "гілка %s перебазуєтьÑÑ Ð½Ð° %s"
#, c-format
-msgid "Branch %s is being bisected at %s"
-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\""
+msgid "invalid branch name: '%s'"
+msgstr "неприпуÑтима назва гілки: \"%s\""
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Поки що немає комітів в гілці \"%s\"."
+msgid "no commit on branch '%s' yet"
+msgstr "поки що немає комітів у гілці \"%s\""
#, c-format
-msgid "No branch named '%s'."
-msgstr "Ðемає гілки з ім’Ñм \"%s\"."
+msgid "no branch named '%s'"
+msgstr "немає гілки з назвою \"%s\""
-msgid "Branch rename failed"
-msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ гілку"
+msgid "branch rename failed"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ гілку"
-msgid "Branch copy failed"
-msgstr "Ðе вдалоÑÑ Ñтворити копію гілки"
+msgid "branch copy failed"
+msgstr "не вдалоÑÑ Ñкопіювати гілку"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Створено копію невірно названої гілки \"%s\""
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "Ñтворено копію невірно названої гілки \"%s\""
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Перейменовано невірно названу гілку \"%s\""
+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 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 renamed, but update of config-file failed"
+msgstr "гілку перейменовано, але не вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ конфігураційний файл"
-msgid "Branch is copied, 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"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"Будь лаÑка, відредагуйте Ð¾Ð¿Ð¸Ñ Ð³Ñ–Ð»ÐºÐ¸\n"
" %s\n"
-"РÑдки, що починаютьÑÑ Ð· \"%c\", будуть вилучені.\n"
+"РÑдки, що починаютьÑÑ Ð· \"%s\", будуть вилучені.\n"
msgid "Generic options"
msgstr "Загальні опції"
@@ -3012,8 +3019,8 @@ msgstr "рекурÑивно через підмодулі"
msgid "format to use for the output"
msgstr "формат, що викориÑтовувати Ð´Ð»Ñ Ð²Ð¸Ð²Ð¾Ð´Ñƒ"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ñ‚Ð¸ HEAD Ñк дійÑне поÑиланнÑ."
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ñ‚Ð¸ HEAD Ñк дійÑне поÑиланнÑ"
msgid "HEAD not found below refs/heads!"
msgstr "HEAD не знайдено під refs/heads!"
@@ -3031,17 +3038,17 @@ msgstr "--recurse-submodules можна викориÑтовувати лише
msgid "branch name required"
msgstr "назва гілки Ñ” обовʼÑзковою"
-msgid "Cannot give description to detached HEAD"
-msgstr "Ðеможливо вÑтановити Ð¾Ð¿Ð¸Ñ Ð²Ñ–Ð´Ð¾ÐºÑ€ÐµÐ¼Ð»ÐµÐ½Ð¾Ð¼Ñƒ HEAD"
+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 copy the current branch while not on any"
+msgstr "неможливо Ñкопіювати поточну гілку, не перебуваючи на жодній з них"
-msgid "cannot rename 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 "забагато гілок Ð´Ð»Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ— копіюваннÑ"
@@ -3054,10 +3061,10 @@ msgstr "забагато аргументів Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"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'"
@@ -3070,28 +3077,28 @@ 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."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
msgstr ""
-"неможливво Ñкинути Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð´Ð¶ÐµÑ€ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ Ñховища Ð´Ð»Ñ HEAD, Ñкий не "
-"вказує на жодну гілку."
+"не вдалоÑÑ Ñкинути Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð´Ð¶ÐµÑ€ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ Ñховища Ð´Ð»Ñ HEAD, Ñкий не "
+"вказує на жодну гілку"
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "Гілка \"%s\" не має інформації щодо першоджерельного Ñховища"
+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"
+"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 Ð´Ð»Ñ \"git branch\" не приймають назву гілки.\n"
"Ви хотіли викориÑтати -a|-r --list <шаблон>?"
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
"Ð¾Ð¿Ñ†Ñ–Ñ \"--set-upstream\" більше не підтримуєтьÑÑ. Будь лаÑка, викориÑтовуйте "
-"\"--track\" або \"--set-upstream-to\"."
+"\"--track\" або \"--set-upstream-to\" заміÑть неї"
msgid "git version:\n"
msgstr "верÑÑ–Ñ git:\n"
@@ -3110,10 +3117,12 @@ 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"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <шлÑÑ…>] [(-s | --suffix) <формат>]\n"
+"git bugreport [(-o | --output-directory) <шлÑÑ…>]\n"
+" [(-s | --suffix) <формат> | --no-suffix]\n"
" [--diagnose[=<режим>]]"
msgid ""
@@ -3167,6 +3176,10 @@ msgid "specify a strftime format suffix for the filename(s)"
msgstr "вказати ÑÑƒÑ„Ñ–ÐºÑ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ñƒ strftime Ð´Ð»Ñ Ð½Ð°Ð·Ð²Ð¸ файла(-ів)"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "невідомий аргумент \"%s\""
+
+#, c-format
msgid "could not create leading directories for '%s'"
msgstr "не вдалоÑÑ Ñтворити провідні каталоги Ð´Ð»Ñ \"%s\""
@@ -3228,6 +3241,9 @@ msgstr "Ð”Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÐ° потрібне Ñховище
msgid "do not show bundle details"
msgstr "не показувати деталі пакунка"
+msgid "need a repository to verify a bundle"
+msgstr "потрібне Ñховище Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ пакунка"
+
#, c-format
msgid "%s is okay\n"
msgstr "%s у порÑдку\n"
@@ -3273,6 +3289,14 @@ msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <об’єкт>"
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 ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -3283,14 +3307,6 @@ msgstr ""
" [--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 "Перевірити Ñ–ÑÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ð° або видати вміÑÑ‚ об’єкта"
@@ -3589,9 +3605,18 @@ msgid "'%s' or '%s' cannot be used with %s"
msgstr "\"%s\" або \"%s\" не можна викориÑтовувати з %s"
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr ""
+"\"%s\", \"%s\" або \"%s\" не можна викориÑтовувати при переключенні Ñтану"
+
+#, c-format
msgid "path '%s' is unmerged"
msgstr "шлÑÑ… '%s' не злитий"
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ дерево (%s)"
+
msgid "you need to resolve your current index first"
msgstr "Ñпочатку потрібно розібратиÑÑŒ з вашим поточним індекÑом"
@@ -3834,6 +3859,10 @@ msgstr "Ðеможливо переключити гілку на не коміÑ
msgid "missing branch or commit argument"
msgstr "відÑÑƒÑ‚Ð½Ñ Ð³Ñ–Ð»ÐºÐ° або коміт"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "невідомий Ñтиль конфлікту \"%s\""
+
msgid "perform a 3-way merge with the new branch"
msgstr "здійÑнити 3-Ñтороннє Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· новою гілкою"
@@ -3852,8 +3881,8 @@ msgstr "переключити примуÑово (викинути локаль
msgid "new-branch"
msgstr "нова-гілка"
-msgid "new unparented branch"
-msgstr "нова гілка без джерела"
+msgid "new unborn branch"
+msgstr "нова ненароджена гілка"
msgid "update ignored files (default)"
msgstr "оновити ігноровані файли (за замовчуваннÑм)"
@@ -4036,7 +4065,6 @@ 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]? "
@@ -4091,22 +4119,9 @@ 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"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"clean.requireForce вÑтановлено у true за замовчуваннÑм Ñ– не задано ні -i, ні "
-"-n, ні -f; відмовлено в прибиранні"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x та -X не можна викориÑтовувати разом"
+"clean.requireForce вÑтановлено у true Ñ– -f не задано: відмовлено в прибиранні"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<опції>] [--] <Ñховище> [<директоріÑ>]"
@@ -4120,8 +4135,8 @@ msgstr "не переходити на гілку"
msgid "create a bare repository"
msgstr "Ñтворити порожнє Ñховище"
-msgid "create a mirror repository (implies bare)"
-msgstr "Ñтворити дзеркальне Ñховище (включає опцію bare)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "Ñтворити дзеркальне Ñховище (включає опцію --bare)"
msgid "to clone from a local repository"
msgstr "клонувати з локального Ñховища"
@@ -4198,6 +4213,9 @@ msgstr "git директоріÑ"
msgid "separate git dir from working tree"
msgstr "відокремити git-директорію від робочого дерева"
+msgid "specify the reference format to use"
+msgstr "вкажіть формат поÑиланнÑ, Ñкий потрібно викориÑтовувати"
+
msgid "key=value"
msgstr "ключ=значеннÑ"
@@ -4257,6 +4275,14 @@ msgid "failed to unlink '%s'"
msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ \"%s\""
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "неможливо перевірити жорÑтке поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\""
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "жорÑтке поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ñ€Ñ–Ð·Ð½ÑєтьÑÑ Ð²Ñ–Ð´ джерела в \"%s\""
+
+#, c-format
msgid "failed to create link '%s'"
msgstr "не вдалоÑÑ Ñтворити поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\""
@@ -4316,11 +4342,9 @@ 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 "unknown ref storage format '%s'"
+msgstr "невідомий формат Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ð¾Ñилань \"%s\""
#, c-format
msgid "repository '%s' does not exist"
@@ -4440,6 +4464,10 @@ msgstr "відÑтуп по правому краю"
msgid "padding space between columns"
msgstr "відÑтуп між Ñтовпчиками"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s має бути невідʼємним значеннÑм"
+
msgid "--command must be the first argument"
msgstr "--command має бути першим аргументом"
@@ -4455,7 +4483,7 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <директоріÑ>] [--append] [--object-dir "
"<директоріÑ>] [--append] [--object-dir <директоріÑ>] [--append\n"
@@ -4463,7 +4491,7 @@ msgstr ""
"| --stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <чиÑло>] [--"
"[no-]progress]\n"
-" <опції розділеннÑ>"
+" <опції-розділеннÑ>"
msgid "dir"
msgstr "директоріÑ"
@@ -4479,6 +4507,10 @@ msgid "Could not open commit-graph '%s'"
msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ коміт-граф \"%s\""
#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ ланцюжок коміт-графа \"%s\""
+
+#, c-format
msgid "unrecognized --split argument, %s"
msgstr "нерозпізнаний --split аргумент, %s"
@@ -4677,9 +4709,6 @@ 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 "неможливо зробити чаÑтковий коміт під Ñ‡Ð°Ñ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ."
@@ -4752,35 +4781,35 @@ msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати шаблон комітів"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Будь лаÑка, введіть Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ коміту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… змін. РÑдки, що починаютьÑÑ Ð·\n"
-" \"%c\" будуть проігноровані.\n"
+" \"%s\" будуть проігноровані.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Будь лаÑка, введіть Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ коміту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… змін. РÑдки, що починаютьÑÑ Ð·\n"
-" \"%c\" будуть проігноровані, а порожній Ð´Ð¾Ð¿Ð¸Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ðµ коміт.\n"
+" \"%s\" будуть проігноровані, а порожній Ð´Ð¾Ð¿Ð¸Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ðµ коміт.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Будь лаÑка, введіть Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ коміту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… змін. РÑдки, що починаютьÑÑ Ð·\n"
-" \"%c\" будуть збережені; ви можете вилучити Ñ—Ñ… ÑамоÑтійно, Ñкщо захочете.\n"
+" \"%s\" будуть збережені; ви можете вилучити Ñ—Ñ… ÑамоÑтійно, Ñкщо захочете.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Будь лаÑка, введіть Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ коміту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… змін. РÑдки, що починаютьÑÑ Ð·\n"
-" \"%c\" будуть збережені; ви можете вилучити Ñ—Ñ… ÑамоÑтійно, Ñкщо захочете.\n"
+" \"%s\" будуть збережені; ви можете вилучити Ñ—Ñ… ÑамоÑтійно, Ñкщо захочете.\n"
"Порожній Ð´Ð¾Ð¿Ð¸Ñ Ð¿ÐµÑ€ÐµÑ€Ð¸Ð²Ð°Ñ” коміт.\n"
msgid ""
@@ -4982,7 +5011,6 @@ msgstr "повторно викориÑтати Ð´Ð¾Ð¿Ð¸Ñ Ð·Ñ– вказаног
#. TRANSLATORS: Leave "[(amend|reword):]" as-is,
#. and only translate <commit>.
#.
-
msgid "[(amend|reword):]commit"
msgstr "[(amend|reword):]коміт"
@@ -5081,22 +5109,57 @@ msgstr "ÐŸÐµÑ€ÐµÑ€Ð¸Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ через порожнє тіло Ð
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
"Ñховище було оновлено, але не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати\n"
-"файл new_index. ПереконайтеÑÑ, що диÑк не переповнений Ñ– квота\n"
+"новий файл індекÑу. ПереконайтеÑÑ, що диÑк не переповнений Ñ– квота\n"
"не перевищена, а потім виконайте \"git restore --staged :/\" Ð´Ð»Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ."
-msgid "git config [<options>]"
-msgstr "git config [<опції>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<опціÑ-файлу>] [<опціÑ-відображеннÑ>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "нерозпізнаний аргумент --type, %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<опціÑ-файлу>] [<опціÑ-відображеннÑ>] [--includes] [--all] "
+"[--regexp=<регвир>] [--value=<значеннÑ>] [--fixed-value] [--"
+"default=<Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ -за-умовчаннÑм>] <назва>"
-msgid "only one type at a time"
-msgstr "лише один тип за раз"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<опціÑ-файлу>] [--type=<тип>] [--all] [--value=<значеннÑ>] "
+"[--fixed-value] <назва> <значеннÑ>"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<опціÑ-файлу>] [--all] [--value=<значеннÑ>] [--fixed-"
+"value] <назва> <значеннÑ>"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<опціÑ-файлу>] <Ñтара-назва> <нова-назва>"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<опціÑ-файлу>] <назва>"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<опціÑ-файлу>]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<опціÑ-файлу>] --get-colorbool <назва> [<stdout-is-tty>]"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<опціÑ-файлу>] [--type=<тип>] [--comment=<допиÑ>] [--all][--"
+"value=<значеннÑ>] [--fixed-value] <назва> <значеннÑ>"
msgid "Config file location"
msgstr "Ð Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ конфігурації"
@@ -5122,55 +5185,6 @@ 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 "Тип"
@@ -5198,8 +5212,8 @@ msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÑˆÐ»ÑÑ… (файл або назва директорі
msgid "value is an expiry date"
msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ - дата Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії"
-msgid "Other"
-msgstr "Інше"
+msgid "Display options"
+msgstr "Опції відображеннÑ"
msgid "terminate values with NUL byte"
msgstr "завершити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±Ð°Ð¹Ñ‚Ð¾Ð¼ NUL"
@@ -5207,9 +5221,6 @@ 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, командний "
@@ -5220,12 +5231,15 @@ msgstr ""
"показати межі дії конфігурації (робоче дерево, локально, глобально, ÑиÑтема, "
"команда)"
-msgid "value"
-msgstr "значеннÑ"
+msgid "show config keys in addition to their values"
+msgstr "показувати ключі конфігурації на додачу до їхніх значень"
-msgid "with --get, use default value when missing entry"
-msgstr ""
-"з --get викориÑтовувати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм, Ñкщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ñутній"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "нерозпізнаний аргумент --type, %s"
+
+msgid "only one type at a time"
+msgstr "лише один тип за раз"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5303,43 +5317,75 @@ msgstr ""
"ФÐЙЛ\"\n"
"у \"git help worktree\" Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації"
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color Ñ– тип змінної не узгоджуютьÑÑ"
+msgid "Other"
+msgstr "Інше"
-msgid "only one action at a time"
-msgstr "лише одна Ð´Ñ–Ñ Ð·Ð° раз"
+msgid "respect include directives on lookup"
+msgstr "дотримуватиÑÑŒ директив Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸ пошуку"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --list або --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл конфігурації \"%s\""
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
+msgid "error processing config file(s)"
+msgstr "помилка при обробці файлу(ів) конфігурації"
+
+msgid "Filter options"
+msgstr "Опції фільтрації"
+
+msgid "return all values for multi-valued config options"
+msgstr "повернути вÑÑ– Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð±Ð°Ð³Ð°Ñ‚Ð¾Ð·Ð½Ð°Ñ‡Ð½Ð¸Ñ… параметрів конфігурації"
+
+msgid "interpret the name as a regular expression"
+msgstr "інтерпретувати назву Ñк регулÑрний вираз"
+
+msgid "show config with values matching the pattern"
+msgstr "показати конфіг зі значеннÑми, що відповідають шаблону"
+
+msgid "use string equality when comparing values to value pattern"
msgstr ""
-"--show-origin заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --get, --get-all, --get-regexp та --list"
+"викориÑтовувати Ñ€Ñдкову еквівалентніÑть при порівнÑнні з шаблоном значень"
-msgid "--default is only applicable to --get"
-msgstr "--default заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --get"
+msgid "URL"
+msgstr "URL"
+
+msgid "show config matching the given URL"
+msgstr "показати конфіг, що відповідає вказаній URL-адреÑÑ–"
+
+msgid "value"
+msgstr "значеннÑ"
+
+msgid "use default value when missing entry"
+msgstr "викориÑтовувати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм, Ñкщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ñутній"
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ з \"шаблоном-значеннÑ\""
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл конфігурації \"%s\""
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= не можна викориÑтовувати з --all або --url="
-msgid "error processing config file(s)"
-msgstr "помилка при обробці файлу(ів) конфігурації"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= не можна викориÑтовувати з --all, --regexp або --value"
-msgid "editing stdin is not supported"
-msgstr "Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ stdin не підтримуєтьÑÑ"
+msgid "Filter"
+msgstr "ФільтраціÑ"
-msgid "editing blobs is not supported"
-msgstr "Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ blobs не підтримуєтьÑÑ"
+msgid "replace multi-valued config option with new value"
+msgstr "замінити багатозначний параметр конфігурації новим значеннÑм"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "неможливо Ñтворити конфігураційний файл %s"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr ""
+"зрозумілий Ð´Ð»Ñ Ð»ÑŽÐ´Ð¸Ð½Ð¸ Ñ€Ñдок ÐºÐ¾Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ñ (# буде додано попереду при "
+"необхідноÑті)"
+
+msgid "add a new line without altering any existing values"
+msgstr "додати новий Ñ€Ñдок, не змінюючи жодного з Ñ–Ñнуючих значень"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ з --value=<шаблон>"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append не можна викориÑтовувати з --value=<шаблон>"
#, c-format
msgid ""
@@ -5353,6 +5399,87 @@ msgstr ""
msgid "no such section: %s"
msgstr "немає такого розділу: %s"
+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"
+
+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-адреÑи: розділ[.змінна] 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 "open an editor"
+msgstr "відкрити редактор"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "знайти налаштований колір: Ñлот [<за замовчуваннÑм>]"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "знайти Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñƒ: Ñлот [<stdout-is-tty>]"
+
+msgid "with --get, use default value when missing entry"
+msgstr ""
+"з --get викориÑтовувати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм, Ñкщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ñутній"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color Ñ– тип змінної не узгоджуютьÑÑ"
+
+msgid "no action specified"
+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 "--comment is only applicable to add/set/replace operations"
+msgstr "--comment заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до add/set/replace операцій"
+
msgid "print sizes in human readable format"
msgstr "показувати розмір у зручному Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ñ–"
@@ -6171,6 +6298,9 @@ msgstr "виводити тільки ті поÑиланнÑ, що не міÑÑ
msgid "read reference patterns from stdin"
msgstr "читати шаблони поÑилань з stdin"
+msgid "also include HEAD ref and pseudorefs"
+msgstr "також включити HEAD та пÑевдопоÑиланнÑ"
+
msgid "unknown arguments supplied with --stdin"
msgstr "невідомі аргументи надані через --stdin"
@@ -6183,6 +6313,10 @@ msgstr "конфіг"
msgid "config key storing a list of repository paths"
msgstr "ключ конфігурації, в Ñкому зберігаєтьÑÑ ÑпиÑок шлÑхів до Ñховищ"
+msgid "keep going even if command fails in a repository"
+msgstr ""
+"продовжувати роботу, навіть Ñкщо команда завершилаÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ в репозиторії"
+
msgid "missing --config=<config>"
msgstr "відÑутній --config=<конфіг>"
@@ -6194,13 +6328,11 @@ 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"
@@ -6545,6 +6677,9 @@ msgstr "видалити об’єкти, на Ñкі немає поÑиланÑ
msgid "pack unreferenced objects separately"
msgstr "пакувати об’єкти, на Ñкі немає поÑилань, окремо"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "з --cruft, обмежити розмір нових марних пакунків"
+
msgid "be more thorough (increased runtime)"
msgstr "працювати ретельніше (збільшує Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ)"
@@ -6723,12 +6858,6 @@ msgstr ""
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\""
@@ -6737,6 +6866,12 @@ msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ \"%s\""
msgid "failed to flush '%s'"
msgstr "не вдалоÑÑ Ð¾Ñ‡Ð¸Ñтити \"%s\""
+msgid "failed to start systemctl"
+msgstr "не вдалоÑÑ Ñтартувати systemctl"
+
+msgid "failed to run systemctl"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити systemctl"
+
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "нерозпізнаний --scheduler аргумент \"%s\""
@@ -6760,6 +6895,9 @@ msgstr "планувальник"
msgid "scheduler to trigger git maintenance run"
msgstr "планувальник Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку обÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ git"
+msgid "failed to set up maintenance schedule"
+msgstr "не вдалоÑÑ Ð²Ñтановити розклад обÑлуговуваннÑ"
+
msgid "failed to add repo to global config"
msgstr "не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ Ñховище до глобальної конфігурації"
@@ -6777,18 +6915,18 @@ msgstr "grep: не вдалоÑÑ Ñтворити потік: %s"
msgid "invalid number of threads specified (%d) for %s"
msgstr "невірно вказана кількіÑть потоків (%d) Ð´Ð»Ñ %s"
+#. #-#-#-#-# grep.c.po #-#-#-#-#
#. 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)"
+msgid "unable to read tree %s"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ дерево %s"
#, c-format
msgid "unable to grep from object of type %s"
@@ -6834,8 +6972,8 @@ msgstr "оброблÑти бінарні файли за допомогою tex
msgid "search in subdirectories (default)"
msgstr "шукати в піддиректоріÑÑ… (за замовчуваннÑм)"
-msgid "descend at most <depth> levels"
-msgstr "ÑпуÑкатиÑÑ Ð½Ðµ більше ніж на <глибина> рівнів"
+msgid "descend at most <n> levels"
+msgstr "ÑпуÑкатиÑÑ Ð½Ðµ більше ніж на <н> рівнів"
msgid "use extended POSIX regular expressions"
msgstr "викориÑтовувати розширені POSIX регулÑрні вирази"
@@ -7203,10 +7341,6 @@ 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"
@@ -7350,11 +7484,13 @@ msgstr "помилка fsck в об’єктах пакунка"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-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"
+" [--ref-format=<формат>]\n"
" [-b <назва-гілки> | --initial-branch=<назва-гілки>]\n"
" [--shared[=<дозволи>]] [<директоріÑ>]"
@@ -7398,19 +7534,49 @@ msgstr "--separate-git-dir неÑуміÑна з порожнім Ñховище
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <токен>[(=|:)<значеннÑ>])...]\n"
+" [(--trailer <ключ>|"
+"<аліаÑКлюча>[(=|:)<значеннÑ>])...]\n"
" [--parse] [<файл>...]"
+#, c-format
+msgid "could not stat %s"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ stat Ð´Ð»Ñ %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 read input file '%s'"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ вхідний файл \"%s\""
+
+msgid "could not read from stdin"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ з stdin"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ тимчаÑовий файл на %s"
+
msgid "edit files in place"
msgstr "редагувати файли на міÑцÑÑ…"
msgid "trim empty trailers"
msgstr "обрізати порожні причепи"
+msgid "placement"
+msgstr "розміщеннÑ"
+
msgid "where to place the new trailer"
msgstr "де розміÑтити новий причіп"
@@ -7423,17 +7589,17 @@ msgstr "що робити, Ñкщо причіп відÑутній"
msgid "output only the trailers"
msgstr "виводити лише причепи"
-msgid "do not apply config rules"
-msgstr "не заÑтоÑовувати правила конфігурації"
+msgid "do not apply trailer.* configuration variables"
+msgstr "не заÑтоÑовувати конфігураційні змінні trailer.*"
-msgid "join whitespace-continued values"
-msgstr "об’єднати значеннÑ, що продовжуютьÑÑ Ñ‡ÐµÑ€ÐµÐ· пробіл"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "переформатувати багаторÑдкові Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ñ‡ÐµÐ¿Ñ–Ð² в однорÑдкові"
-msgid "set parsing options"
-msgstr "вÑтановити параметри розбору"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "Ð°Ð»Ñ–Ð°Ñ Ð´Ð»Ñ --only-trailers --only-input --unfold"
-msgid "do not treat --- specially"
-msgstr "не оброблÑти --- оÑобливим чином"
+msgid "do not treat \"---\" as the end of input"
+msgstr "не оброблÑти \"---\" Ñк кінець вводу"
msgid "trailer(s) to add"
msgstr "причіп(и) Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ"
@@ -7522,6 +7688,10 @@ msgstr "потрібен лишень один діапазон"
msgid "not a range"
msgstr "не діапазон"
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл опиÑу гілки \"%s\""
+
msgid "cover letter needs email format"
msgstr "Ñупровідний лиÑÑ‚ має бути у форматі електронної пошти"
@@ -7613,8 +7783,11 @@ msgstr "позначити Ñ€Ñд Ñк N-не перекиданнÑ"
msgid "max length of output filename"
msgstr "макÑимальна довжина назви вихідного файлу"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "викориÑтати [RFC PATCH] заміÑть [PATCH]"
+msgid "rfc"
+msgstr "rfc"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "додати <rfc> (за замовчуваннÑм \"RFC\") перед \"PATCH\""
msgid "cover-from-description-mode"
msgstr "cover-from-description-mode"
@@ -7622,6 +7795,9 @@ msgstr "cover-from-description-mode"
msgid "generate parts of a cover letter based on a branch's description"
msgstr "ÑклаÑти чаÑтини Ñупровідного лиÑта на оÑнові опиÑу гілки"
+msgid "use branch description from file"
+msgstr "викориÑтовувати Ð¾Ð¿Ð¸Ñ Ð³Ñ–Ð»ÐºÐ¸ з файлу"
+
msgid "use [<prefix>] instead of [PATCH]"
msgstr "викориÑтати [<префікÑ>] заміÑть [PATCH]"
@@ -7788,18 +7964,6 @@ msgstr ""
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 [<опції>] [<файл>...]"
@@ -7893,11 +8057,12 @@ msgstr ""
"deduplicate, --eol"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<виконавчий-"
+"файл>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<ключ>]\n"
" [--symref] [<Ñховище> [<шаблони>...]]"
@@ -7913,8 +8078,11 @@ msgstr "шлÑÑ… до git-upload-pack на віддаленому Ñервері
msgid "limit to tags"
msgstr "обмежити до тегів"
-msgid "limit to heads"
-msgstr "обмежити до голів"
+msgid "limit to branches"
+msgstr "обмежити до гілок"
+
+msgid "deprecated synonym for --branches"
+msgstr "заÑтарілий Ñинонім до --branches"
msgid "do not show peeled tags"
msgstr "не показувати очищені теги"
@@ -7931,18 +8099,6 @@ 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 "показувати тільки дерева"
@@ -7976,7 +8132,6 @@ 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"
@@ -8057,9 +8212,19 @@ msgstr ""
"git merge-file [<опції>] [-L <назва1> [-L <оріг> [-L <назва2>]]] <файл1> "
"<оріг-файл> <файл2>"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"Ð¾Ð¿Ñ†Ñ–Ñ diff-algorithm приймає Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ \"myers\", \"minimal\", \"patience\" "
+"та \"histogram\""
+
msgid "send results to standard output"
msgstr "надÑилати результати до Ñтандартного виводу"
+msgid "use object IDs instead of filenames"
+msgstr "викориÑтовувати ідентифікатори обʼєктів заміÑть назв файлів"
+
msgid "use a diff3 based merge"
msgstr "викориÑтовувати Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ð° оÑнові diff3"
@@ -8075,6 +8240,12 @@ msgstr "у разі конфліктів викориÑтовувати їхню
msgid "for conflicts, use a union version"
msgstr "у разі конфліктів викориÑтовувати об’єднану верÑÑ–ÑŽ"
+msgid "<algorithm>"
+msgstr "<алгоритм>"
+
+msgid "choose a diff algorithm"
+msgstr "вибрати алгоритм різниці"
+
msgid "for conflicts, use this marker size"
msgstr "у разі конфліктів викориÑтовувати цей розмір маркера"
@@ -8085,6 +8256,13 @@ msgid "set labels for file1/orig-file/file2"
msgstr "вÑтановити мітки Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»1/оріг-файл/файл2"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "об’єкт \"%s\" не Ñ–Ñнує"
+
+msgid "Could not write object file"
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл обʼєкта"
+
+#, c-format
msgid "unknown option %s"
msgstr "невідома Ð¾Ð¿Ñ†Ñ–Ñ %s"
@@ -8110,6 +8288,11 @@ msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð²Ê¼Ñзати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\""
msgid "Merging %s with %s\n"
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ %s з %s\n"
+# c-format
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ дерево з \"%s\""
+
msgid "not something we can merge"
msgstr "не те, що ми в змозі об’єднати"
@@ -8146,11 +8329,18 @@ msgstr "виконати кілька злиттів, по одному на кÐ
msgid "specify a merge-base for the merge"
msgstr "вказати базу Ð´Ð»Ñ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ"
+msgid "option=value"
+msgstr "опціÑ=значеннÑ"
+
+msgid "option for selected merge strategy"
+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 "unknown strategy option: -X%s"
+msgstr "невідомий варіант Ñтратегії: -X%s"
#, c-format
msgid "malformed input line: '%s'."
@@ -8219,12 +8409,6 @@ 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 "Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ коміту Ð·Ð»Ð¸Ñ‚Ñ‚Ñ (Ð´Ð»Ñ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð±ÐµÐ· Ð¿ÐµÑ€ÐµÐ¼Ð¾Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¿ÐµÑ€ÐµÐ´)"
@@ -8285,10 +8469,6 @@ 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"
@@ -8315,10 +8495,10 @@ msgstr "Порожній Ð´Ð¾Ð¿Ð¸Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ðµ Ð¿Ñ€Ð¾Ñ†ÐµÑ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ.\n"
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"РÑдки, що починаютьÑÑ Ð· \"%c\", будуть проігноровані, а порожній Ð´Ð¾Ð¿Ð¸Ñ "
+"РÑдки, що починаютьÑÑ Ð· \"%s\", будуть проігноровані, а порожній Ð´Ð¾Ð¿Ð¸Ñ "
"перерве\n"
"Ð¿Ñ€Ð¾Ñ†ÐµÑ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ.\n"
@@ -8479,9 +8659,6 @@ msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ тегований об’єкт
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"
@@ -8584,8 +8761,8 @@ msgstr "Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ–Ñнує"
msgid "can not move directory into itself"
msgstr "неможливо переміÑтити директорію в Ñаму Ñебе"
-msgid "cannot move directory over file"
-msgstr "неможливо переміÑтити директорію поверх файлу"
+msgid "destination already exists"
+msgstr "Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ð¶Ðµ Ñ–Ñнує"
msgid "source directory is empty"
msgstr "Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ñ–Ñ Ð´Ð¶ÐµÑ€ÐµÐ»Ð° порожнÑ"
@@ -8745,10 +8922,6 @@ 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\""
@@ -8789,7 +8962,6 @@ msgstr "не вдалоÑÑ Ñкопіювати нотатки з \"%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/)"
@@ -9096,6 +9268,10 @@ msgid "inconsistency with delta count"
msgstr "неÑÐ¿Ñ–Ð²Ð¿Ð°Ð´Ñ–Ð½Ð½Ñ Ð· підрахунком дельти"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "неприпуÑтиме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ pack.allowPackReuse: \"%s\""
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -9333,9 +9509,6 @@ 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"
@@ -9348,19 +9521,16 @@ msgstr "неможливо викориÑтовувати внутрішній Ñ
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>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"Ð’Ñього %<PRIu32> (дельта %<PRIu32>), повторно викориÑтано %<PRIu32> (дельта "
-"%<PRIu32>), повторно викориÑтано пакунків %<PRIu32>"
+"%<PRIu32>), повторно викориÑтано пакунків %<PRIu32> (з %<PRIuMAX>)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9380,10 +9550,11 @@ msgid "refusing to run without --i-still-use-this"
msgstr "відмовлено в запуÑку без --i-still-use-this"
msgid ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <шаблон>] [--exclude <шаблон>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <шаблон>] [--exclude "
+"<шаблон>]"
msgid "pack everything"
msgstr "запакувати вÑе"
@@ -9391,6 +9562,9 @@ msgstr "запакувати вÑе"
msgid "prune loose refs (default)"
msgstr "видалити вивільнені поÑÐ¸Ð»Ð°Ð½Ð½Ñ (за замовчуваннÑм)"
+msgid "auto-pack refs as needed"
+msgstr "Ð°Ð²Ñ‚Ð¾Ð¿Ð°ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ñилань за потреби"
+
msgid "references to include"
msgstr "поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ"
@@ -10062,21 +10236,6 @@ msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¿Ñ€Ð¸Ð¿ÑƒÑтимого allow_rerere_autoupd
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"
@@ -10106,13 +10265,16 @@ msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡Ð¸Ñ‚Ð¸ÑÑŒ на %s"
msgid "apply options and merge options cannot be used together"
msgstr "apply опції не можна викориÑтовувати разом з merge опціÑми"
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask заÑтаріло; викориÑтовуйте \"--empty=stop\" заміÑть цього."
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
msgstr ""
"нерозпізнаний порожній тип \"%s\"; припуÑтимими значеннÑми Ñ” \"drop\", "
-"\"keep\" та \"ask\"."
+"\"keep\" та \"stop\"."
msgid ""
"--rebase-merges with an empty string argument is deprecated and will stop "
@@ -10300,8 +10462,8 @@ msgstr ""
"Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ \"preserve\",\n"
"Ñкий більше не підтримуєтьÑÑ; натоміÑть викориÑтовуйте \"merges\""
-msgid "No rebase in progress?"
-msgstr "ÐŸÐµÑ€ÐµÐ±Ð°Ð·ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ відбуваєтьÑÑ?"
+msgid "no rebase in progress"
+msgstr "Ð¿ÐµÑ€ÐµÐ±Ð°Ð·ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ відбуваєтьÑÑ"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
@@ -10349,16 +10511,6 @@ msgstr ""
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"
@@ -10509,6 +10661,9 @@ msgstr "необхідно вказати директорію"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<лог-опції>] [<поÑиланнÑ>]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10534,6 +10689,10 @@ msgstr "git reflog exists <поÑиланнÑ>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "неприпуÑтима позначка чаÑу \"%s\" передана до \"--%s\""
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s не приймає аргументів: \"%s\""
+
msgid "do not actually prune any entries"
msgstr "наÑправді не видалÑти жодного запиÑу"
@@ -10584,6 +10743,22 @@ msgstr "не вказано журнал поÑилань Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð
msgid "invalid ref format: %s"
msgstr "неприпуÑтимий формат поÑиланнÑ: %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<формат> [--dry-run]"
+
+msgid "specify the reference format to convert to"
+msgstr "вкажіть формат поÑиланнÑ, в Ñкий потрібно конвертувати"
+
+msgid "perform a non-destructive dry-run"
+msgstr "виконати неруйнівний пробний запуÑк"
+
+msgid "missing --ref-format=<format>"
+msgstr "відÑутній --ref-format=<формат>"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "Ñховище вже викориÑтовує формат \"%s\""
+
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10662,8 +10837,8 @@ msgstr ""
"\t ÑкориÑтайтеÑÑŒ --mirror=fetch або --mirror=push"
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "невідомий аргумент дзеркала: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "невідомий --mirror аргумент: %s"
msgid "fetch the remote branches"
msgstr "отримати віддалені гілки"
@@ -10872,18 +11047,17 @@ msgstr "* віддалене %s"
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"
+msgid "(no URL)"
+msgstr "(без URL-адреÑи)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " HEAD гілка: %s"
@@ -10996,10 +11170,6 @@ msgstr "запитувати 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-адреÑами надÑиланнÑ"
@@ -11040,6 +11210,9 @@ msgstr ""
msgid "could not start pack-objects to repack promisor objects"
msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ð¾Ñ‡Ð°Ñ‚Ð¸ pack-objects Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¿Ð°ÐºÑƒÐ²Ð°Ð½Ð½Ñ promisor обʼєктів"
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‚Ð¸ promisor обʼєкти обʼєктам пакунків"
+
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
"перепакуваннÑ: очікуютьÑÑ Ð¿Ð¾Ð²Ð½Ñ– Ñ€Ñдки hex ідентифікаторів обʼєктів тільки "
@@ -11071,6 +11244,10 @@ msgstr "не вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸ тимчаÑовий файл зніÐ
msgid "could not remove stale bitmap: %s"
msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ заÑтарілий bitmap: %s"
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ð¿Ð°ÐºÑƒÐ½ÐºÑƒ %s не починаєтьÑÑ Ð· objdir %s"
+
msgid "pack everything in a single pack"
msgstr "запакувати вÑе в один пакунок"
@@ -11145,19 +11322,22 @@ 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 "Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ð¿Ð°ÐºÑƒÐ½ÐºÐ° Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÐ° з обрізаними обʼєктами"
+msgstr "Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÐ° з обрізаними обʼєктами"
+
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÐ° з відфільтрованими обʼєктами"
msgid "cannot delete packs in a precious-objects repo"
msgstr "неможливо видалити пакунки в precious-objects Ñховищі"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "Ð¾Ð¿Ñ†Ñ–Ñ \"%s\" може бути викориÑтана тільки разом з \"%s\""
+
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\" завершилоÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾"
@@ -11357,6 +11537,75 @@ msgstr "--convert-graft-file не потребує аргументів"
msgid "only one pattern can be given with -l"
msgstr "тільки один шаблон може бути заданий з -l"
+msgid "need some commits to replay"
+msgstr "потрібні деÑкі коміти Ð´Ð»Ñ Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ"
+
+msgid "--onto and --advance are incompatible"
+msgstr "--onto та --advance неÑуміÑні"
+
+msgid "all positive revisions given must be references"
+msgstr "вÑÑ– надані позитивні ревізії мають бути поÑиланнÑми"
+
+msgid "argument to --advance must be a reference"
+msgstr "аргумент до --advance має бути поÑиланнÑм"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr ""
+"неможливо проÑунути поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· декількома джерелами, тому що впорÑÐ´ÐºÑƒÐ²Ð°Ð½Ð½Ñ "
+"буде нечітко визначеним"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr "неможливо неÑвно визначити, чи це Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ --advance або --onto"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr ""
+"неможливо проÑунути поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· декількома джерельними гілками, тому що "
+"впорÑÐ´ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ´Ðµ нечітко визначеним"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "неможливо неÑвно визначити вірну базу Ð´Ð»Ñ --onto"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(ЕКСПЕРИМЕÐТÐЛЬÐО!) git replay ([--contained] --onto <нова-база> | --advance "
+"<гілка>) <діапазон-ревізій>..."
+
+msgid "make replay advance given branch"
+msgstr "зробити Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð· проÑуваннÑм даної гілки"
+
+msgid "replay onto given commit"
+msgstr "відтворити на заданий коміт"
+
+msgid "advance all branches contained in revision-range"
+msgstr "проÑунути вÑÑ– гілки, що міÑÑ‚ÑтьÑÑ Ð² діапазоні ревізій"
+
+msgid "option --onto or --advance is mandatory"
+msgstr "Ð¾Ð¿Ñ†Ñ–Ñ --onto або --advance Ñ” обовʼÑзковою"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"деÑкі опції Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾ ревізіÑм будуть перевизначені, оÑкільки біт "
+"\"%s\" у \"struct rev_info\" буде примуÑово викориÑтано"
+
+msgid "error preparing revisions"
+msgstr "помилка при підготовці ревізій"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð´Ð¾ кореневого коміту поки що не підтримуєтьÑÑ!"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð² Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ð¾ÐºÐ¸ що не підтримуєтьÑÑ!"
+
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
msgstr ""
@@ -11565,22 +11814,23 @@ msgstr "--default потребує аргументу"
msgid "--prefix requires an argument"
msgstr "--prefix потребує аргументу"
+msgid "no object format specified"
+msgstr "не зазначено формат обʼєкту"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "непідтримуваний формат обʼєкту: %s"
+
#, 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 "цю операцію треба виконувати в робочому дереві"
+msgid "Could not read the index"
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ індекÑ"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "невідомий режим Ð´Ð»Ñ --show-object-format: %s"
@@ -11652,8 +11902,8 @@ msgstr "зберігати первинно порожні коміти"
msgid "allow commits with empty messages"
msgstr "дозволити коміти з порожніми допиÑами"
-msgid "keep redundant, empty commits"
-msgstr "зберігати зайві порожні коміти"
+msgid "deprecated: use --empty=keep instead"
+msgstr "заÑтаріле: викориÑтовуйте --empty=keep заміÑть цього"
msgid "use the 'reference' format to refer to commits"
msgstr "викориÑтовувати \"reference\" формат Ð´Ð»Ñ Ð¿Ð¾Ñилань на коміти"
@@ -11932,23 +12182,43 @@ 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>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<н>]] [--abbrev[=<н>]] [--branches] [--tags]\n"
+" [--] [<шаблон>...]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-d | --"
-"dereference]\n"
-" [-s | --hash[=<н>]] [--abbrev[=<н>]] [--tags]\n"
-" [--heads] [--] [<шаблон>...]"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<н>]] [--abbrev[=<н>]]\n"
+" [--] [<поÑиланнÑ>...]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<шаблон>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "показати тільки теги (можна комбінувати з верхівками)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <поÑиланнÑ>"
+
+msgid "reference does not exist"
+msgstr "поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ðµ Ñ–Ñнує"
+
+msgid "failed to look up reference"
+msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ поÑиланнÑ"
+
+msgid "only show tags (can be combined with branches)"
+msgstr "показати тільки теги (можна комбінувати з гілками)"
+
+msgid "only show branches (can be combined with tags)"
+msgstr "показати тільки гілки (можна комбінувати з тегами)"
-msgid "only show heads (can be combined with tags)"
-msgstr "показати тільки верхівки (можна комбінувати з тегами)"
+msgid "check for reference existence without resolving"
+msgstr "перевірÑти наÑвніÑть поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð±ÐµÐ· розвʼÑзаннÑ"
msgid "stricter reference checking, requires exact ref path"
msgstr "більш Ñувора перевірка поÑилань, потребує точного шлÑху до поÑиланнÑ"
@@ -12580,14 +12850,14 @@ 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 "clone of '%s' into submodule path '%s' failed"
+msgstr "не вдалоÑÑ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ñ‚Ð¸ \"%s\" у шлÑÑ… Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\""
+
+#, c-format
msgid "could not get submodule directory for '%s'"
msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ директорію Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð´Ð»Ñ \"%s\""
@@ -12778,6 +13048,9 @@ msgstr ""
"[no-]recommend-shallow] [--reference <Ñховище>] [--recursive] [--[no-]single-"
"branch] [--] [<шлÑÑ…>...]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð²Ê¼Ñзати HEAD в дійÑне поÑиланнÑ."
+
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<опції>] [<шлÑÑ…>...]"
@@ -12949,14 +13222,16 @@ msgstr "причина оновленнÑ"
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <ідентифікатор-ключа>] [-f] [-m <допиÑ> | -F <файл>] [-"
"e]\n"
+" [(--trailer <токен>[(=|:)<значеннÑ>])...]\n"
" <назва-тегу> [<коміт> | <об’єкт>]"
msgid "git tag -d <tagname>..."
-msgstr "git tag -d <назва-тега>..."
+msgstr "git tag -d <назва-тегу>..."
msgid ""
"git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
@@ -12985,25 +13260,25 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Ðапишіть Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ тегу:\n"
" %s\n"
-"РÑдки, що починаютьÑÑ Ð· \"%c\", будуть проігноровані.\n"
+"РÑдки, що починаютьÑÑ Ð· \"%s\", будуть проігноровані.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Ðапишіть Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ тегу:\n"
" %s\n"
-"РÑдки, що починаютьÑÑ Ð· \"%c\", будуть збережені; ви можете вилучити Ñ—Ñ… "
+"РÑдки, що починаютьÑÑ Ð· \"%s\", будуть збережені; ви можете вилучити Ñ—Ñ… "
"ÑамоÑтійно, Ñкщо захочете.\n"
msgid "unable to sign the tag"
@@ -13089,6 +13364,9 @@ msgstr "вивеÑти тільки не злиті теги"
msgid "print only tags of the object"
msgstr "вивеÑти тільки теги обʼєкта"
+msgid "could not start 'git column'"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ \"git column\""
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "Ð¾Ð¿Ñ†Ñ–Ñ \"%s\" дозволена лише в режимі виводу"
@@ -13248,8 +13526,11 @@ msgstr "(Ð´Ð»Ñ Ð²Ð¸Ñокорівневих команд) забути збер
msgid "write index in this format"
msgstr "запиÑати Ñ–Ð½Ð´ÐµÐºÑ Ñƒ цьому форматі"
+msgid "report on-disk index format version"
+msgstr "звітувати про верÑÑ–ÑŽ формату індекÑу на диÑку"
+
msgid "enable or disable split index"
-msgstr "увімкнути або вимкнути розщеплений індекÑ"
+msgstr "увімкнути або вимкнути розділений індекÑ"
msgid "enable/disable untracked cache"
msgstr "увімкнути/вимкнути невідÑтежуваний кеш"
@@ -13272,19 +13553,27 @@ msgstr "позначити файли придатними Ð´Ð»Ñ fsmonitor"
msgid "clear fsmonitor valid bit"
msgstr "очиÑтити біт придатноÑті Ð´Ð»Ñ fsmonitor"
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "верÑÑ–Ñ Ñ–Ð½Ð´ÐµÐºÑу: була %d, Ñтала %d"
+
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 "
@@ -13324,12 +13613,12 @@ msgstr ""
msgid "fsmonitor disabled"
msgstr "fsmonitor вимкнено"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<опції>] -d <назва поÑиланнÑ> [<Ñтаре значеннÑ>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<опції>] -d <назва-поÑиланнÑ> [<Ñтарий-oid>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
msgstr ""
-"git update-ref [<опції>] <назва-поÑиланнÑ> <нове-значеннÑ> [<Ñтаре-значеннÑ>]"
+"git update-ref [<опції>] <назва-поÑиланнÑ> <новий-oid> [<Ñтарий-oid>]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<опції>] --stdin [-z]"
@@ -13427,13 +13716,13 @@ msgstr "Ðемає можливої джерельної гілки, що озн
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
"(гілку без комітів) Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñховища, ви можете зробити це\n"
"за допомогою Ð¿Ñ€Ð°Ð¿Ð¾Ñ€Ñ†Ñ --orphan:\n"
"\n"
@@ -13441,13 +13730,13 @@ msgstr ""
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
"(гілку без комітів) Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñховища, ви можете зробити це\n"
"за допомогою Ð¿Ñ€Ð°Ð¿Ð¾Ñ€Ñ†Ñ --orphan:\n"
"\n"
@@ -13511,6 +13800,10 @@ msgid "initializing"
msgstr "ініціалізаціÑ"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ Ñтворене робоче дерево \"%s\""
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "Підготовка робочого дерева (нова гілка \"%s\")"
@@ -13542,16 +13835,12 @@ msgstr ""
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"
+"present, stopping; use 'add -f' to override or fetch a remote first"
msgstr ""
"Ðе Ñ–Ñнує локальних або віддалених поÑилань, незважаючи на наÑвніÑть "
"принаймні одного віддаленого\n"
-"призначеннÑ, зупинка; ÑкориÑтайтеÑÑŒ \"add -f\", щоб перевизначити або "
-"Ñпочатку отримати віддалене поÑиланнÑ"
-
-#, c-format
-msgid "'%s' and '%s' cannot be used together"
-msgstr "\"%s\" Ñ– \"%s\" не можна викориÑтовувати разом"
+"призначеннÑ, зупинка; ÑкориÑтайтеÑÑŒ \"add -f\", щоб перевизначити, або "
+"Ñпочатку виконайте Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð· віддаленного Ñховища"
msgid "checkout <branch> even if already checked out in other worktree"
msgstr ""
@@ -13563,8 +13852,8 @@ msgstr "Ñтворити нову гілку"
msgid "create or reset a branch"
msgstr "Ñтворити або Ñкинути гілку"
-msgid "create unborn/orphaned branch"
-msgstr "Ñтворити ненароджену/ÑирітÑьку гілку"
+msgid "create unborn branch"
+msgstr "Ñтворити ненароджену гілку"
msgid "populate the new working tree"
msgstr "заповнити нове робоче дерево"
@@ -13587,11 +13876,8 @@ 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 "option '%s' and commit-ish cannot be used together"
+msgstr "опцію \"%s\" не можна викориÑтовувати разом з комітоподібними"
msgid "added with --lock"
msgstr "додано з --lock"
@@ -13800,9 +14086,6 @@ 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"
@@ -13870,6 +14153,10 @@ msgid "terminating chunk id appears earlier than expected"
msgstr "ідентифікатор Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ„Ñ€Ð°Ð³Ð¼ÐµÐ½Ñ‚Ð° зʼÑвивÑÑ Ñ€Ð°Ð½Ñ–ÑˆÐµ, ніж очікувалоÑÑŒ"
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "шматок id %<PRIx32> не Ñ” %d-byte впорÑдкованим"
+
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "невірне Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ ÑˆÐ¼Ð°Ñ‚ÐºÐ°(ів) %<PRIx64> та %<PRIx64>"
@@ -13921,8 +14208,8 @@ msgstr "Зібрати інформацію, щоб кориÑтувач міг
msgid "Move objects and refs by archive"
msgstr "ПеренеÑти архів обʼєктів та поÑилань"
-msgid "Provide content or type and size information for repository objects"
-msgstr "Показати вміÑÑ‚ або інформацію про тип Ñ– розмір обʼєктів Ñховища"
+msgid "Provide contents or details of repository objects"
+msgstr "Ðадавати вміÑÑ‚ або деталі обʼєктів Ñховища"
msgid "Display gitattributes information"
msgstr "Відобразити інформацію про gitattributes"
@@ -14201,6 +14488,9 @@ msgstr "Отримати те, що надÑилаєтьÑÑ Ð´Ð¾ Ñховища
msgid "Manage reflog information"
msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ”ÑŽ журналу поÑилань"
+msgid "Low-level access to refs"
+msgstr "Ðизькорівневий доÑтуп до поÑилань"
+
msgid "Manage set of tracked repositories"
msgstr "Керувати набором відÑтежуваних Ñховищ"
@@ -14210,6 +14500,11 @@ msgstr "Запакувати розпаковані обʼєкти у Ñхови
msgid "Create, list, delete refs to replace objects"
msgstr "Створити, показати, видалити поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² заміни"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"ЕКСПЕРИМЕÐТÐЛЬÐО: Ð’Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð² на новій базі також працює з порожніми "
+"Ñховищами"
+
msgid "Generates a summary of pending changes"
msgstr "Створює підÑумок змін Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð»Ñду"
@@ -14283,7 +14578,7 @@ msgid "Initialize, update or inspect submodules"
msgstr "Ініціалізувати, оновити або перевірити підмодулі"
msgid "Bidirectional operation between a Subversion repository and Git"
-msgstr "Двонаправлена Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð¼Ñ–Ð¶ Subversion Ñховищем та Git"
+msgstr "ДвонапрÑмлена Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð¼Ñ–Ð¶ Subversion Ñховищем та Git"
msgid "Switch branches"
msgstr "Переключити гілки"
@@ -14331,8 +14626,8 @@ msgstr "Перевірити GPG-Ð¿Ñ–Ð´Ð¿Ð¸Ñ Ñ‚ÐµÐ³Ñ–Ð²"
msgid "Display version information about Git"
msgstr "Показати інформацію про верÑÑ–ÑŽ Git"
-msgid "Show logs with difference each commit introduces"
-msgstr "Показати журнал з різницею, Ñку вноÑить кожен коміт"
+msgid "Show logs with differences each commit introduces"
+msgstr "Показати журнал з різницÑми, Ñкі вноÑить кожен коміт"
msgid "Manage multiple working trees"
msgstr "Керувати кількома робочими деревами"
@@ -14448,6 +14743,32 @@ msgstr "ІнÑтрумент Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÐµÐ»Ð¸ÐºÐ¸Ð¼Ð¸ Ñхов
msgid "commit-graph file is too small"
msgstr "файл коміт-графа занадто малий"
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "шматок oid fanout коміт-графа має невірний розмір"
+
+msgid "commit-graph fanout values out of order"
+msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ fanout коміт-графа впорÑдковані невірно"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "шматок OID lookup коміт-графа має невірний розмір"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "шматок commit data коміт-графа має невірний розмір"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "шматок generations коміт-графа має невірний розмір"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "шматок changed-path index коміт-графа має невірний розмір"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ малого шматка changed-path (%<PRIuMAX> < %<PRIuMAX>) "
+"файла коміт-графа"
+
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "Ð¿Ñ–Ð´Ð¿Ð¸Ñ ÐºÐ¾Ð¼Ñ–Ñ‚-графа %X не збігаєтьÑÑ Ð· підпиÑом %X"
@@ -14464,9 +14785,29 @@ msgstr "хеш верÑÑ–Ñ ÐºÐ¾Ð¼Ñ–Ñ‚-графа %X не збігаєтьÑÑ Ð
msgid "commit-graph file is too small to hold %u chunks"
msgstr "файл коміт-графа занадто малий, щоб вміÑтити %u шматків"
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr "необхідний шматок OID fanout коміт-графа відÑутній або пошкоджений"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "необхідний шматок OID lookup коміт-графа відÑутній або пошкоджений"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr "необхідний шматок commit data коміт-графа відÑутній або пошкоджений"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€Ñ–Ð² Блума Ð´Ð»Ñ ÑˆÐ°Ñ€Ñƒ коміт-графа \"%s\" через неÑуміÑніÑть "
+"параметрів"
+
msgid "commit-graph has no base graphs chunk"
msgstr "коміт-граф не має шматка базових графів"
+msgid "commit-graph base graphs chunk is too small"
+msgstr "шматок base graphs коміт-графа занадто малий"
+
msgid "commit-graph chain does not match"
msgstr "ланцюжок коміт-графа не Ñпівпадає"
@@ -14474,6 +14815,9 @@ msgstr "ланцюжок коміт-графа не Ñпівпадає"
msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "кількіÑть комітів у базовому графі занадто велика: %<PRIuMAX>"
+msgid "commit-graph chain file too small"
+msgstr "файл ланцюжка коміт-графа занадто малий"
+
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr "неприпуÑтимий ланцюжок коміт-графа: Ñ€Ñдок \"%s\" не Ñ” хешем"
@@ -14489,7 +14833,13 @@ msgid "could not find commit %s"
msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ коміт %s"
msgid "commit-graph requires overflow generation data but has none"
-msgstr "коміт-граф потребує даних генерації переповненнÑ, але Ñ—Ñ… немаєданих"
+msgstr "коміт-граф потребує даних генерації переповненнÑ, але не має Ñ—Ñ…"
+
+msgid "commit-graph overflow generation data is too small"
+msgstr "занадто мало даних генерації Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚-графа"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "extra-edges pointer коміт-графа виходить за межі"
msgid "Loading known commits in commit graph"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¾Ð¼Ð¸Ñ… комітів у коміт-графі"
@@ -14576,6 +14926,14 @@ msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ ÐºÐ¾Ð¼Ñ–Ñ‚-графа"
msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr "Ñпроба запиÑати коміт-граф, але \"core.commitGraph\" відключено"
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"Ñпроба запиÑати коміт-граф, але \"commitGraph.changedPathsVersion\" (%d) не "
+"підтримуєтьÑÑ"
+
msgid "too many commits to write graph"
msgstr "занадто багато комітів, щоб запиÑати граф"
@@ -14615,18 +14973,6 @@ 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>"
@@ -14634,10 +14980,22 @@ msgstr "Ð³ÐµÐ½ÐµÑ€Ð°Ñ†Ñ–Ñ ÐºÐ¾Ð¼Ñ–Ñ‚-графа Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ %s Ñ” %<PRI
msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
msgstr "дата коміту Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ %s у коміт-графі Ñ” %<PRIuMAX> != %<PRIuMAX>"
+#, c-format
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr ""
+"коміт-граф має Ñк нульові, так Ñ– ненульові генерації (наприклад, коміти "
+"\"%s\" Ñ– \"%s\")"
+
msgid "Verifying commits in commit graph"
msgstr "Перевірка комітів у коміт-графі"
#, c-format
+msgid "could not parse commit %s"
+msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ коміт %s"
+
+#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s не є комітом!"
@@ -14661,6 +15019,10 @@ msgstr ""
"\"git config advice.graftFileDeprecated false\""
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr "коміт %s Ñ–Ñнує в коміт-графі, але не в базі даних обʼєктів"
+
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr "Коміт %s має недоÑтовірний GPG-підпиÑ, нібито від %s."
@@ -15064,8 +15426,13 @@ msgstr "довжина ÑÐºÐ¾Ñ€Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð¾Ð·Ð° діапазоном: %d"
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 "%s cannot contain newline"
+msgstr "%s не може міÑтити Ñимволи нового Ñ€Ñдка"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s повинен мати принаймні один Ñимвол"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -15101,10 +15468,6 @@ msgstr "поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\" не вказує на blob"
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 "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ конфігурацію командного Ñ€Ñдка"
@@ -15141,6 +15504,10 @@ msgid "failed to write new configuration file %s"
msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати новий конфігураційний файл %s"
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "багаторÑдкові коментарі не дозволÑютьÑÑ: \"%s\""
+
+#, c-format
msgid "could not lock config file %s"
msgstr "не вдалоÑÑ Ð·Ð°Ñ„Ñ–ÐºÑувати файл конфігурації %s"
@@ -15268,7 +15635,6 @@ 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"
@@ -15286,7 +15652,6 @@ msgstr ""
"%s"
#. TRANSLATORS: this is the end of "Connecting to %s (port %s) ... "
-
msgid "done."
msgstr "готово."
@@ -15327,7 +15692,7 @@ msgstr "ssh Ð¾Ð¿Ñ†Ñ–Ñ \"simple\" не підтримує вÑтановленн
#, c-format
msgid "strange pathname '%s' blocked"
-msgstr "дивне Ñ–Ð¼Ê¼Ñ ÑˆÐ»Ñху \"%s\" заблоковано"
+msgstr "дивна назва шлÑху \"%s\" заблокована"
msgid "unable to fork"
msgstr "неможливо розгалужити"
@@ -15522,7 +15887,6 @@ msgstr[1] "%<PRIuMAX> роки"
msgstr[2] "%<PRIuMAX> років"
#. TRANSLATORS: "%s" is "<n> years"
-
#, c-format
msgid "%s, %<PRIuMAX> month ago"
msgid_plural "%s, %<PRIuMAX> months ago"
@@ -15585,9 +15949,6 @@ 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"
@@ -15649,6 +16010,10 @@ msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "Ðевідоме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ð¹Ð½Ð¾Ñ— змінної \"diff.submodule\": \"%s\""
#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "невідоме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ— \"%s\": %s"
+
+#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
@@ -15728,13 +16093,6 @@ msgstr "невірний --color-moved аргумент: %s"
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"
@@ -15778,8 +16136,8 @@ msgstr "машинний вивід --stat"
msgid "output only the last line of --stat"
msgstr "вивеÑти лише оÑтанній Ñ€Ñдок --stat"
-msgid "<param1,param2>..."
-msgstr "<параметр1,параметр2>..."
+msgid "<param1>,<param2>..."
+msgstr "<параметр1>,<параметр2>..."
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
@@ -15788,8 +16146,8 @@ msgstr "вивеÑти розподіл відноÑної кількоÑті з
msgid "synonym for --dirstat=cumulative"
msgstr "Ñинонім Ð´Ð»Ñ --dirstat=cumulative"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "Ñинонім Ð´Ð»Ñ --dirstat=files,параметр1,параметр2..."
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "Ñинонім Ð´Ð»Ñ --dirstat=files,<параметр1>,<параметр2>..."
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
@@ -15965,12 +16323,6 @@ msgstr "згенерувати різницю за алгоритмом \"patien
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "згенерувати різницю за алгоритмом \"histogram diff\""
-msgid "<algorithm>"
-msgstr "<алгоритм>"
-
-msgid "choose a diff algorithm"
-msgstr "вибрати алгоритм різниці"
-
msgid "<text>"
msgstr "<текÑÑ‚>"
@@ -16351,7 +16703,6 @@ msgstr "помилка при обробці підтверджень: %d"
#. TRANSLATORS: The parameter will be 'ready', a protocol
#. keyword.
#.
-
#, c-format
msgid "expected packfile to be sent after '%s'"
msgstr "очікувалоÑÑŒ надÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð° пакунка піÑÐ»Ñ \"%s\""
@@ -16359,7 +16710,6 @@ msgstr "очікувалоÑÑŒ надÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð° пакунка п
#. TRANSLATORS: The parameter will be 'ready', a protocol
#. keyword.
#.
-
#, c-format
msgid "expected no other sections to be sent after no '%s'"
msgstr "не очікувалоÑÑŒ надÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¶Ð¾Ð´Ð½Ð¾Ñ— Ñекції Ð´Ð»Ñ ÑтатуÑу не \"%s\""
@@ -16439,17 +16789,21 @@ msgstr ""
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <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=<назва>=<змінна-оточеннÑ>] <команда> [<аргументи>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<шлÑÑ…>]\n"
+" [--work-tree=<шлÑÑ…>] [--namespace=<назва>] [--config-"
+"env=<шлÑÑ…>=<змінна-оточеннÑ>]\n"
+" <команда> [<аргументи>]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16792,13 +17146,13 @@ msgstr ""
"Ви можете вимкнути це Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð·Ð° допомогою \"git config advice."
"ignoredHook false\"."
+msgid "not a git repository"
+msgstr "не Ñ” git Ñховищем"
+
#, 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 ""
@@ -16810,6 +17164,9 @@ msgstr "Контроль Ð´ÐµÐ»ÐµÐ³ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "Ð—Ð°ÐºÑ€Ñ–Ð¿Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸Ñ… ключів не підтримуєтьÑÑ Ð· cURL < 7.39.0"
+msgid "Unknown value for http.proactiveauth"
+msgstr "Ðевідоме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ http.proactiveauth"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE не підтримуєтьÑÑ Ð· cURL < 7.44.0"
@@ -16827,6 +17184,12 @@ msgstr ""
msgid "Could not set SSL backend to '%s': already set"
msgstr "Ðе вдалоÑÑ Ð²Ñтановити SSL обробник в \"%s\": вже вÑтановлено"
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "відмова від Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ cookies з http.cookiefile \"-\""
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ http.savecookies Ð´Ð»Ñ Ð¿Ð¾Ñ€Ð¾Ð¶Ð½ÑŒÐ¾Ð³Ð¾ http.cookiefile"
+
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -16968,6 +17331,14 @@ msgid "Unable to create '%s.lock': %s"
msgstr "Ðе вдалоÑÑ Ñтворити \"%s.lock\": %s"
#, c-format
+msgid "could not write loose object index %s"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати Ñ–Ð½Ð´ÐµÐºÑ Ð²Ñ–Ð»ÑŒÐ½Ð¾Ð³Ð¾ обʼєкта %s"
+
+#, c-format
+msgid "failed to write loose object index %s\n"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати Ñ–Ð½Ð´ÐµÐºÑ Ð²Ñ–Ð»ÑŒÐ½Ð¾Ð³Ð¾ обʼєкта %s\n"
+
+#, c-format
msgid "unexpected line: '%s'"
msgstr "неочікуваний Ñ€Ñдок: \"%s\""
@@ -16978,6 +17349,10 @@ msgid "quoted CRLF detected"
msgstr "виÑвлено цитований CRLF"
#, c-format
+msgid "unable to format message: %s"
+msgstr "не вдалоÑÑ Ð²Ñ–Ð´Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ допиÑ: %s"
+
+#, c-format
msgid "Failed to merge submodule %s (not checked out)"
msgstr "Ðе вдалоÑÑ Ð¾Ð±Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ підмодуль %s (не активне)"
@@ -16990,6 +17365,10 @@ msgid "Failed to merge submodule %s (commits not present)"
msgstr "Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s (відÑутні коміти)"
#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "помилка: не вдалоÑÑ Ð¾Ð±Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ підмодуль %s (Ñховище пошкоджено)"
+
+#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr "Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s (коміти не відповідають базі)"
@@ -17014,12 +17393,13 @@ msgstr ""
"Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s, але Ñ–Ñнує кілька можливих варіантів злиттÑ:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ внутрішнє злиттÑ"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "помилка: не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ внутрішнє Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ %s"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %s до бази даних"
+msgid "error: unable to add %s to database"
+msgstr "помилка: не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %s до бази даних"
#, c-format
msgid "Auto-merging %s"
@@ -17116,12 +17496,12 @@ msgstr ""
"в %s."
#, c-format
-msgid "cannot read object %s"
-msgstr "неможливо прочитати обʼєкт %s"
+msgid "error: cannot read object %s"
+msgstr "помилка: неможливо прочитати обʼєкт %s"
#, c-format
-msgid "object %s is not a blob"
-msgstr "обʼєкт %s не є blob"
+msgid "error: object %s is not a blob"
+msgstr "помилка: обʼєкт %s не є blob"
#, c-format
msgid ""
@@ -17172,9 +17552,8 @@ 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 ""
" - go to submodule (%s), and either merge commit %s\n"
@@ -17210,7 +17589,6 @@ 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 "Ð·Ð±Ð¸Ñ€Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— про Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ вдалоÑÑ Ð´Ð»Ñ Ð´ÐµÑ€ÐµÐ² %s, %s, %s"
@@ -17260,6 +17638,10 @@ msgid "do not know what to do with %06o %s '%s'"
msgstr "не знаю, що робити з %06o %s \"%s\""
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "Ðе вдалоÑÑ Ð¾Ð±Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ підмодуль %s (Ñховище пошкоджено)"
+
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "ÐŸÐµÑ€ÐµÐ¼Ð¾Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ %s вперед до наÑтупного коміту:"
@@ -17298,6 +17680,13 @@ msgstr ""
msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s (знайдено більше одного злиттÑ)"
+msgid "failed to execute internal merge"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ внутрішнє злиттÑ"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %s до бази даних"
+
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
@@ -17400,6 +17789,14 @@ msgstr ""
"КОÐФЛІКТ (перейменовано/перейменовано): перейменовано директорію %s->%s в "
"%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"
+
msgid "modify"
msgstr "змінити"
@@ -17460,51 +17857,6 @@ 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\""
@@ -17515,7 +17867,7 @@ msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ pack-index \"%s\""
#, c-format
msgid "failed to locate object %d in packfile"
-msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ обʼєкт %d у файлі пакунка"
+msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ обʼєкт %d у packfile"
msgid "cannot store reverse index file"
msgstr "неможливо зберегти файл зворотнього індекÑу"
@@ -17528,17 +17880,17 @@ msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ Ñ€Ñдок: %s"
msgid "malformed line: %s"
msgstr "невірно Ñформований Ñ€Ñдок: %s"
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr ""
-"Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ñнуючого multi-pack-index; невідповідніÑть контрольних Ñум"
-
msgid "could not load pack"
-msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ пакет"
+msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ пакунок"
#, c-format
msgid "could not open index for %s"
msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ Ñ–Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ %s"
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ñнуючого multi-pack-index; невідповідніÑть контрольних Ñум"
+
msgid "Adding packfiles to multi-pack-index"
msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÑ–Ð² до multi-pack-index"
@@ -17552,11 +17904,11 @@ msgstr "неможливо вибрати бажаний пакунок %s за
#, c-format
msgid "did not see pack-file %s to drop"
-msgstr "не побачив файл пакунка %s, Ñкий потрібно Ñкинути"
+msgstr "не знайдено файл пакунка %s Ð´Ð»Ñ ÑкиданнÑ"
#, c-format
msgid "preferred pack '%s' is expired"
-msgstr "у бажаного пакета \"%s\" закінчивÑÑ Ñ‚ÐµÑ€Ð¼Ñ–Ð½ дії"
+msgstr "у бажаного пакунка \"%s\" закінчивÑÑ Ñ‚ÐµÑ€Ð¼Ñ–Ð½ дії"
msgid "no pack files to index."
msgstr "немає файлів пакунків Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑації."
@@ -17570,6 +17922,92 @@ msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати мультіпакунковий bi
msgid "could not write multi-pack-index"
msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати multi-pack-index"
+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"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "multi-pack-index OID розÑÑ–ÑŽÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” невірний розмір"
+
+#, c-format
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr ""
+"невірна поÑлідовніÑть oid fanout: fanout[%d] = %<PRIx32> > %<PRIx32> = "
+"fanout[%d]"
+
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "multi-pack-index OID lookup шматок має невірний розмір"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "multi-pack-index object offset шматок має невірний розмір"
+
+#, 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 required pack-name chunk missing or corrupted"
+msgstr "необхідний шматок pack-name multi-pack-index відÑутній або пошкоджений"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr ""
+"необхідний шматок OID fanout multi-pack-index відÑутній або пошкоджений"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr ""
+"необхідний шматок OID lookup multi-pack-index відÑутній або пошкоджений"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"необхідний шматок object offsets multi-pack-index відÑутній або пошкоджений"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "шматок pack-name 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 "MIDX does not contain the BTMP chunk"
+msgstr "MIDX не міÑтить шматок BTMP"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ бітмаповий пакунок %<PRIu32>"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr ""
+"multi-pack-index зберігає 64-бітне зміщеннÑ, але Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ off_t занадто мале"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr "large offset multi-pack-index виходить за межі"
+
#, c-format
msgid "failed to clear multi-pack-index at %s"
msgstr "не вдалоÑÑ Ð¾Ñ‡Ð¸Ñтити multi-pack-index при %s"
@@ -17583,13 +18021,6 @@ 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"
@@ -17618,18 +18049,6 @@ msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ Ñ–Ð½Ð´ÐµÐºÑ Ñ„Ð°Ð¹Ð»Ð° паÐ
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"
@@ -17672,11 +18091,29 @@ msgstr "Відмовлено в перезапиÑÑ– нотаток у %s (за
#. the environment variable, the second %s is
#. its value.
#.
-
#, c-format
msgid "Bad %s value: '%s'"
msgstr "Ðевірне %s значеннÑ: \"%s\""
+msgid "failed to decode tree entry"
+msgstr "не вдалоÑÑ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ñ‚Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð´ÐµÑ€ÐµÐ²Ð°"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "не вдалоÑÑ Ð·Ñ–Ñтавити Ð·Ð°Ð¿Ð¸Ñ Ñƒ дереві Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "невірній %s у коміті"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "не вдалоÑÑ Ð·Ñ–Ñтавити %s %s в обʼєкті коміту"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ обʼєкт з \"%s\" на \"%s\""
+
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
msgstr "Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ñ–Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ð° %s не Ñ–Ñнує; перевірте .git/objects/info/alternates"
@@ -17780,6 +18217,10 @@ msgid "packed object %s (stored in %s) is corrupt"
msgstr "упакований обʼєкт %s (що зберігаєтьÑÑ Ñƒ %s) пошкоджено"
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "відÑутнє зіÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð½Ñ %s до %s"
+
+#, c-format
msgid "unable to write file %s"
msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл %s"
@@ -17833,6 +18274,10 @@ msgid "cannot read object for %s"
msgstr "неможливо прочитати обʼєкт Ð´Ð»Ñ %s"
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "неможливо зіÑтавити обʼєкт %s з %s"
+
+#, c-format
msgid "object fails fsck: %s"
msgstr "об’єкт не пройшов перевірку fsck: %s"
@@ -17887,7 +18332,6 @@ msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ð°ÐºÑƒÐ²Ð°Ñ‚Ð¸ вміÑÑ‚ %s"
#. 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 [невірний обʼект]"
@@ -17895,9 +18339,8 @@ 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"
#.
-
#, c-format
msgid "%s commit %s - %s"
msgstr "%s коміт %s - %s"
@@ -17905,7 +18348,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.
@@ -17913,7 +18356,6 @@ msgstr "%s коміт %s - %s"
#. The third argument is the "tag" string
#. from object.c.
#.
-
#, c-format
msgid "%s tag %s - %s"
msgstr "%s тег %s - %s"
@@ -17922,9 +18364,8 @@ 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]"
#.
-
#, c-format
msgid "%s [bad tag, could not parse it]"
msgstr "%s [невірний тег, не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸]"
@@ -17932,7 +18373,6 @@ msgstr "%s [невірний тег, не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸]"
#. TRANSLATORS: This is a line of ambiguous <type>
#. object output. E.g. "deadbeef tree".
#.
-
#, c-format
msgid "%s tree"
msgstr "%s дерево"
@@ -17940,7 +18380,6 @@ msgstr "%s дерево"
#. TRANSLATORS: This is a line of ambiguous <type>
#. object output. E.g. "deadbeef blob".
#.
-
#, c-format
msgid "%s blob"
msgstr "%s blob"
@@ -17953,7 +18392,6 @@ msgstr "короткий ідентифікатор обʼєкта %s неодн
#. objects composed in show_ambiguous_object(). See
#. its "TRANSLATORS" comments for details.
#.
-
#, c-format
msgid ""
"The candidates are:\n"
@@ -18066,6 +18504,17 @@ msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ обʼєкт: %s"
msgid "hash mismatch %s"
msgstr "невідповідніÑть хешу %s"
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "дубльований елемент під Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñу bitmap індекÑу: \"%s\""
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "Ñпроба зберегти невибраний коміт: \"%s\""
+
+msgid "too many pseudo-merges"
+msgstr "занадто багато пÑевдозлиттÑ"
+
msgid "trying to write commit not in index"
msgstr "Ñпроба запиÑати коміт, Ñкого немає в індекÑÑ–"
@@ -18088,8 +18537,21 @@ msgstr ""
msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr ""
+"пошкоджений файл bitmap індекÑу (занадто малий, щоб вміÑтити таблицю пошуку)"
+
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"пошкоджений файл bitmap індекÑу (занадто малий, щоб вміÑтити заголовок "
+"таблиці пÑевдозлиттÑ"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
"пошкоджений файл bitmap індекÑу (занадто короткий, щоб вміÑтити таблицю "
-"пошуку)"
+"пÑевдозлиттÑ)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "пошкоджений файл bitmap індекÑу, Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿ÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ мала"
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
@@ -18122,6 +18584,9 @@ msgstr "у мультіпакунковому bitmap відÑутній необ
msgid "could not open pack %s"
msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ пакунок %s"
+msgid "could not determine MIDX preferred pack"
+msgstr "не вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ бажаний пакунок MIDX"
+
#, c-format
msgid "preferred pack (%s) is invalid"
msgstr "бажаний пакунок (%s) Ñ” неприпуÑтимим"
@@ -18143,6 +18608,17 @@ msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
msgstr "пошкоджений ewah bitmap: урізаний заголовок Ð´Ð»Ñ bitmap коміту \"%s\""
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr ""
+"не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ пакунок: \"%s\", Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ викориÑÑ‚Ð°Ð½Ð½Ñ "
+"пакунків"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr ""
+"не вдалоÑÑ Ð¾Ð±Ñ‡Ð¸Ñлити бажаний пакунок, Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ викориÑÑ‚Ð°Ð½Ð½Ñ "
+"пакунків"
+
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "обʼєкт \"%s\" не знайдено в типах bitmap"
@@ -18172,6 +18648,10 @@ msgid "mismatch in bitmap results"
msgstr "розбіжніÑть в bitmap результатах"
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "Ñ–Ð½Ð´ÐµÐºÑ Ð¿ÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ð¾Ð·Ð° діапазоном (%<PRIu32> >= %<PRIuMAX>)"
+
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ \"%s\" у пакунку \"%s\" зі зміщеннÑм %<PRIuMAX>"
@@ -18233,6 +18713,12 @@ msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr ""
"невірна Ð¿Ð¾Ð·Ð¸Ñ†Ñ–Ñ Ð·Ð²Ð¾Ñ€Ð¾Ñ€Ñ‚Ð½Ð¾Ð³Ð¾ індекÑу у %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "multi-pack-index reverse-index шматок має невірний розмір"
+
+msgid "could not determine preferred pack"
+msgstr "не вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ бажаний пакунок"
+
msgid "cannot both write and verify reverse index"
msgstr "неможливо одночаÑно запиÑувати та звірÑти зворотний індекÑ"
@@ -18284,14 +18770,6 @@ 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 не приймає значеннÑ"
@@ -18340,7 +18818,6 @@ msgstr "викориÑтаннÑ: %s"
#. TRANSLATORS: the colon here should align with the
#. one in "usage: %s" translation.
#.
-
#, c-format
msgid " or: %s"
msgstr " або: %s"
@@ -18364,7 +18841,6 @@ msgstr " або: %s"
#. translated) N_() usage string, which contained embedded
#. newlines before we split it up.
#.
-
#, c-format
msgid "%*s%s"
msgstr "%*s%s"
@@ -18376,6 +18852,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-NUM"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "протилежне --no-%s"
+
msgid "expiry-date"
msgstr "Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñтроку дії"
@@ -18407,6 +18887,14 @@ msgstr ""
"Ñимволом NUL"
#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "невірне булеве Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¾Ñ‚Ð¾Ñ‡ÐµÐ½Ð½Ñ \"%s\" Ð´Ð»Ñ \"%s\""
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ %s"
+
+#, c-format
msgid "Could not make %s writable by group"
msgstr "Ðе вдалоÑÑ Ð·Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ %s доÑтупним Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу групою"
@@ -18457,6 +18945,10 @@ msgid "%s: 'literal' and 'glob' are incompatible"
msgstr "%s: \"literal\" та \"glob\" неÑуміÑні"
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "\"%s\" знаходитьÑÑ Ð¿Ð¾Ð·Ð° деревом директорій"
+
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s: \"%s\" знаходитьÑÑ Ð·Ð° межами Ñховища за адреÑою \"%s\""
@@ -18531,6 +19023,9 @@ msgstr "не вдалоÑÑ Ñтворити потоковий lstat: %s"
msgid "unable to parse --pretty format"
msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ --pretty формат"
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "лінива вибірка вимкнена; деÑкі обʼєкти можуть бути недоÑтупні"
+
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote: не вдалоÑÑ Ñ€Ð¾Ð·Ð³Ð°Ð»ÑƒÐ¶Ð¸Ñ‚Ð¸ Ð¿Ñ–Ð´Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ"
@@ -18554,6 +19049,65 @@ msgstr "object-info: очікувавÑÑ flush піÑÐ»Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ñ–Ð²"
msgid "Removing duplicate objects"
msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð´ÑƒÐ±Ð»Ñ–ÐºÐ°Ñ‚Ñ–Ð² обʼєктів"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ регвир пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ %s: \"%s\""
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr ""
+"%s має бути невідʼємним значеннÑм, викориÑтано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr ""
+"%s має бути в діапазоні від 0 до 1, викориÑтано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s має бути додатнім, викориÑтано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "у групі пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ \"%s\" відÑутній потрібний шаблон"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr "група пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ \"%s\" має неÑтабільний поріг перед Ñтабільним"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"регвир пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· конфігурації має забагато груп Ð·Ð°Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ "
+"(max=%<PRIuMAX>"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð·Ð° межами (%<PRIuMAX> >= %<PRIuMAX>) при розширеному пÑевдозлитті"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"Ð·Ð°Ð¿Ð¸Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ð¾Ð³Ð¾ пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ малий (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ пÑÐµÐ²Ð¾Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð° %s зі зміщеннÑм %<PRIuMAX>"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr "розширене пÑевдозлиттÑ, пошук за межами (%<PRIu32> >= %<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð·Ð° межами: (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ таблицю розширеного пÑевдо-Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ %s"
+
msgid "could not start `log`"
msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ð¾Ñ‡Ð°Ñ‚Ð¸ \"log\""
@@ -18611,10 +19165,6 @@ 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\" відображаєтьÑÑ Ñк файл Ñ– Ñк каталог"
@@ -18716,16 +19266,12 @@ msgid "broken index, expect %s in %s, got %s"
msgstr "пошкоджений індекÑ, очікувавÑÑ %s у %s, отримано %s"
msgid "cannot write split index for a sparse index"
-msgstr "неможливо запиÑати розщеплений Ñ–Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ñ–Ð´Ð¶ÐµÐ½Ð¾Ð³Ð¾ індекÑу"
+msgstr "неможливо запиÑати розділений Ñ–Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ñ–Ð´Ð¶ÐµÐ½Ð¾Ð³Ð¾ індекÑу"
msgid "failed to convert to a sparse-index"
msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ в sparse-index"
#, c-format
-msgid "could not stat '%s'"
-msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ stat '%s'"
-
-#, c-format
msgid "unable to open git dir: %s"
msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ git-директорію: %s"
@@ -18964,7 +19510,7 @@ msgstr "очікувалоÑÑŒ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ %s="
#, c-format
msgid "positive value expected '%s' in %%(%s)"
-msgstr "очікувалоÑÑŒ додатне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ \"%s\" у %%(%s)"
+msgstr "очікувалоÑÑŒ додатне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ \"%s\" в %%(%s)"
#, c-format
msgid "expected format: %%(align:<width>,<position>)"
@@ -19165,11 +19711,18 @@ msgstr "лог Ð´Ð»Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ %s неÑподівано завершÐ
msgid "log for %s is empty"
msgstr "лог Ð´Ð»Ñ %s порожній"
+msgid "refusing to force and skip creation of reflog"
+msgstr "відмовлено в примуÑовому пропуÑку ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€ÐµÑ„Ð»Ð¾Ð³Ñƒ"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "відмовлено в оновленні поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· невірною назвою \"%s\""
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "відмовлено в оновленні пÑевдопоÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\""
+
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "update_ref завершивÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ Ð´Ð»Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": %s"
@@ -19192,10 +19745,6 @@ 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"
@@ -19204,6 +19753,98 @@ msgid "could not delete references: %s"
msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ поÑиланнÑ: %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "Закінчено пробну міграцію поÑилань, результат можна знайти в \"%s\"\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ тимчаÑову директорію міграції \"%s\""
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "перенеÑені поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ð½Ð° знайти в \"%s\""
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"неможливо заблокувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": очікувалоÑÑŒ Ñимвольне поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· "
+"призначеннÑм \"%s\", але це звичайне поÑиланнÑ"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "refname є небезпечним: %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "Ñпроба запиÑати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\" з неіÑнуючим обʼєктом %s"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "Ñпроба запиÑати не коміт обʼєкт %s у гілку \"%s\""
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"багаторазові Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ \"HEAD\" (включаючи через поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· \"%s\") не "
+"дозволені"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr ""
+"неможливо зафікÑуваті поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": не вдалоÑÑŒ розвʼÑзати поÑÐ¸Ð»Ð°Ð½Ð½Ñ "
+"\"%s\""
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr ""
+"неможливо зафікÑувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": помилка при зчитуванні поÑиланнÑ"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"багаторазові Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ \"%s\" (включаючи Ñимвольні поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· \"%s\") "
+"не дозволені"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "неможливо зафікÑувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð²Ð¶Ðµ Ñ–Ñнує"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr ""
+"неможливо зафікÑувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ñутнє, але очікуване %s"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr ""
+"неможливо зафікÑувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": Ñтановить %s, але очікуєтьÑÑ %s"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿Ð¾Ñилань: підготовка транзакції: \"%s\""
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿Ð¾Ñилань: помилка транзакції: \"%s\""
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "не вдалоÑÑ ÑтиÑнути Ñтек: %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "назва поÑÐ¸Ð»Ð°Ð½Ð½Ñ %s не знайдена"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr ""
+"назва поÑÐ¸Ð»Ð°Ð½Ð½Ñ %s Ñ” Ñимвольним поÑиланнÑм, ÐºÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ñкого не підтримуєтьÑÑ"
+
+#, c-format
msgid "invalid refspec '%s'"
msgstr "неприпуÑтимий визначник поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\""
@@ -19212,6 +19853,10 @@ msgid "invalid quoting in push-option value: '%s'"
msgstr "неприпуÑтимі лапки у значенні push-опції: \"%s\""
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "невідоме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ object-format: %s"
+
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs не дійÑні: це git Ñховище?"
@@ -19376,7 +20021,6 @@ msgstr "визначник поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð¶ÐµÑ€ÐµÐ»Ð° %s збігаєть
#. <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"
@@ -19674,15 +20318,26 @@ 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 "%s exists but is a symbolic ref"
+msgstr "%s Ñ–Ñнує але Ñ” Ñимвольним поÑиланнÑм"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge вимагає одне з пÑевдопоÑилань MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD або REBASE_HEAD"
+
+#, 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"
+msgstr "неприпуÑтима Ð¾Ð¿Ñ†Ñ–Ñ \"%s\" у --stdin режимі"
msgid "your current branch appears to be broken"
msgstr "ваша поточна гілка виглÑдає пошкодженою"
@@ -19771,8 +20426,15 @@ msgid "only download metadata for the branch that will be checked out"
msgstr ""
"завантажити метадані тільки Ð´Ð»Ñ Ð³Ñ–Ð»ÐºÐ¸, на Ñку буде здійÑнюватиÑÑ Ð¿ÐµÑ€ÐµÑ…Ñ–Ð´"
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "ÑкалÑрний клон [<опції>] [--] <Ñховище> [<директоріÑ>]"
+msgid "create repository within 'src' directory"
+msgstr "Ñтворити Ñховище в директорії \"src\""
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <головна-гілка>] [--full-clone]\n"
+"\t[--[no-]src] <URL-адреÑа> [<коренева-директоріÑ>]"
#, c-format
msgid "cannot deduce worktree name from '%s'"
@@ -19823,12 +20485,28 @@ msgid "could not remove stale scalar.repo '%s'"
msgstr "неможливо видалити заÑтаріле scalar.repo \"%s\""
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілого scalar.repo \"%s\""
+msgid "removed stale scalar.repo '%s'"
+msgstr "видалено заÑтаріле scalar.repo \"%s\""
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git Ñховище зникло у \"%s\""
+msgid "repository at '%s' has different owner"
+msgstr "у Ñховища \"%s\" інший влаÑник"
+
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "невірній формат Ñховища \"%s\""
+
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "Ñховище \"%s\" не знайдено"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"щоб ÑкаÑувати реєÑтрацію цього репозиторію в Scalar, виконайте\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
msgid ""
"scalar run <task> [<enlistment>]\n"
@@ -19940,6 +20618,21 @@ msgid "unknown action: %d"
msgstr "невідома діÑ: %d"
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\"."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -20000,7 +20693,6 @@ msgstr "зробіть коміт або додайте ваші зміни до
#. TRANSLATORS: %s will be "revert", "cherry-pick" or
#. "rebase".
#.
-
#, c-format
msgid "%s: Unable to write new index file"
msgstr "%s: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати новий індекÑний файл"
@@ -20057,7 +20749,7 @@ msgid ""
" git rebase --continue\n"
msgstr ""
"ви маєте індекÑовані зміни у вашому робочому дереві\n"
-"Якщо ці зміни мають бути ÑтиÑнуті у попередній коміт, запуÑтіть:\n"
+"Якщо ці зміни мають бути зчавлені у попередній коміт, запуÑтіть:\n"
"\n"
" git commit --amend %s\n"
"\n"
@@ -20168,10 +20860,6 @@ 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"
@@ -20234,16 +20922,11 @@ msgstr "неможливо отримати Ð´Ð¾Ð¿Ð¸Ñ Ð´Ð¾ коміту длÑ
#. 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"
@@ -20277,12 +20960,51 @@ 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\""
+msgid "'%s' does not accept merge commits"
+msgstr "\"%s\" не приймає коміти злиттÑ"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"\"pick\" не приймає коміти злиттÑ. Якщо ви хочете\n"
+"відтворити злиттÑ, викориÑтовуйте \"merge -C\" Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð°."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"\"reword\" не приймає коміти злиттÑ. Якщо ви хочете\n"
+"відтворити Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° змінити текÑÑ‚ допиÑу, викориÑтовуйте\n"
+"\"merge -c\" Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð°."
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"\"edit\" не приймає коміти злиттÑ. Якщо ви хочете\n"
+"відтворити злиттÑ, викориÑтовуйте \"merge -C\" Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð°, а потім\n"
+"\"break\" Ð´Ð»Ñ Ð¿Ð¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ, щоб ви могли\n"
+"виконати \"git commit --amend && git rebase --continue\"."
+
+msgid "cannot squash merge commit into another commit"
+msgstr "неможливо зчавити коміт Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² інший коміт"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s не приймає аргументи: \"%s\""
+msgid "invalid command '%.*s'"
+msgstr "неприпуÑтима команда \"%.*s\""
#, c-format
msgid "missing arguments for %s"
@@ -20398,9 +21120,8 @@ msgstr ""
msgid "cannot read HEAD"
msgstr "неможливо прочитати HEAD"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "не вдалоÑÑ Ñкопіювати \"%s\" в \"%s\""
+msgid "could not write commit message file"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл допиÑу до коміта"
#, c-format
msgid ""
@@ -20566,6 +21287,9 @@ msgstr "ЗаÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ñхову призвело до кон
msgid "Autostash exists; creating a new stash entry."
msgstr "ÐвтоÑхов Ñ–Ñнує; ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ запиÑу Ñхову."
+msgid "autostash reference is a symref"
+msgstr "поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ñхову Ñ” Ñимвольним поÑиланнÑм"
+
msgid "could not detach HEAD"
msgstr "не вдалоÑÑ Ð²Ñ–Ð´Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ HEAD"
@@ -20599,14 +21323,14 @@ msgstr ""
" 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 "Rebasing (%d/%d)%s"
+msgstr "ÐŸÐµÑ€ÐµÐ±Ð°Ð·ÑƒÐ²Ð°Ð½Ð½Ñ (%d/%d)%s"
+
+#, c-format
msgid "unknown command %d"
msgstr "невідома команда %d"
@@ -20739,6 +21463,10 @@ msgstr ""
"конфігурацію"
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "\"%s\" вже зазначено Ñк \"%s\""
+
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "ОчікувалоÑÑŒ git Ñховищe верÑÑ–Ñ— <= %d, знайдено %d"
@@ -20797,6 +21525,18 @@ msgstr "неможливо повернутиÑÑ Ð´Ð¾ поточної робо
msgid "failed to stat '%*s%s%s'"
msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати \"%*s%s%s\""
+#, 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 "Unable to read current working directory"
msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ поточну робочу директорію"
@@ -20819,18 +21559,6 @@ msgstr ""
"вÑтановлено)."
#, 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 "
@@ -20887,6 +21615,10 @@ msgid "invalid initial branch name: '%s'"
msgstr "неприпуÑтиме початкове Ñ–Ð¼â€™Ñ Ð³Ñ–Ð»ÐºÐ¸: \"%s\""
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: ігноровано --initial-branch=%s"
+
+#, c-format
msgid "unable to handle file type %d"
msgstr "не вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ тип файлу %d"
@@ -20897,15 +21629,15 @@ msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити %s на %s"
msgid "attempt to reinitialize repository with different hash"
msgstr "Ñпроба переініціалізувати репозиторій з іншим хеш-алгоритмом"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+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"
@@ -20923,35 +21655,57 @@ msgstr "Ініціалізовано порожнє Git Ñховище в %s%s\n
#, c-format
msgid "index entry is a directory, but not sparse (%08x)"
-msgstr "індекÑний Ð·Ð°Ð¿Ð¸Ñ Ñ” директорією, але не Ñ” розрідженим (%08x)"
+msgstr "Ð·Ð°Ð¿Ð¸Ñ Ñ–Ð½Ð´ÐµÐºÑу Ñ” директорією, але не розрідженою (%08x)"
msgid "cannot use split index with a sparse index"
-msgstr "не можна викориÑтовувати розщеплений Ñ–Ð½Ð´ÐµÐºÑ Ð· розрідженим індекÑом"
+msgstr "неможливо викориÑтовувати розділений Ñ–Ð½Ð´ÐµÐºÑ Ð· розрідженим індекÑом"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "невірний формат %s: елемент \"%s\" не починаєтьÑÑ Ð· \"(\""
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "невірний формат %s: елемент \"%s\" не закінчуєтьÑÑ Ð½Ð° \")\""
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "невірний формат %s: %%%.*s"
+
+#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
msgid "%u.%2.2u GiB"
msgstr "%u.%2.2u ГіБ"
+#. TRANSLATORS: IEC 80000-13:2008 gibibyte/second
#, c-format
msgid "%u.%2.2u GiB/s"
msgstr "%u.%2.2u ГіБ/Ñ"
+#. TRANSLATORS: IEC 80000-13:2008 mebibyte
#, c-format
msgid "%u.%2.2u MiB"
msgstr "%u.%2.2u МіБ"
+#. TRANSLATORS: IEC 80000-13:2008 mebibyte/second
#, c-format
msgid "%u.%2.2u MiB/s"
msgstr "%u.%2.2u МіБ/Ñ"
+#. TRANSLATORS: IEC 80000-13:2008 kibibyte
#, c-format
msgid "%u.%2.2u KiB"
msgstr "%u.%2.2u КіБ"
+#. TRANSLATORS: IEC 80000-13:2008 kibibyte/second
#, c-format
msgid "%u.%2.2u KiB/s"
msgstr "%u.%2.2u КіБ/Ñ"
+#. TRANSLATORS: IEC 80000-13:2008 byte
#, c-format
msgid "%u byte"
msgid_plural "%u bytes"
@@ -20959,6 +21713,7 @@ msgstr[0] "%u байт"
msgstr[1] "%u байти"
msgstr[2] "%u байтів"
+#. TRANSLATORS: IEC 80000-13:2008 byte/second
#, c-format
msgid "%u byte/s"
msgid_plural "%u bytes/s"
@@ -21108,7 +21863,17 @@ msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ підмодуль \"%s\"."
#, c-format
msgid "submodule git dir '%s' is inside git dir '%.*s'"
-msgstr "підмодуль git dir \"%s\" знаходитьÑÑ Ð²Ñередині git директорії \"%.*s\""
+msgstr "підмодуль git dir \"%s\" знаходитьÑÑ Ð²Ñередині git директорії \"%*s\""
+
+#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"очікувалоÑÑŒ, що \"%.*s\" у шлÑху Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\" не буде Ñимвольним "
+"поÑиланнÑм"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "очікувалоÑÑŒ, що шлÑÑ… Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\" не буде Ñимвольним поÑиланнÑм"
#, c-format
msgid ""
@@ -21151,10 +21916,6 @@ 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"
@@ -21168,12 +21929,6 @@ 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 не позначений Ñк доÑÑжний"
@@ -21258,29 +22013,6 @@ msgstr "невідоме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ \"%s\" Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð° \"%s\""
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 "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ повний Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ віддаленого помічника"
@@ -21330,9 +22062,6 @@ 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"
@@ -21379,8 +22108,8 @@ 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 "helper %s does not support '--force'"
+msgstr "помічник %s не підтримує \"--force\""
msgid "couldn't run fast-export"
msgstr "не вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити fast-export"
@@ -21465,10 +22194,6 @@ 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\" не дозволений"
@@ -21520,6 +22245,9 @@ msgstr "bundle-uri Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ підтримуєтьÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¾Ðº
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ÑпиÑок Ð°Ð´Ñ€ÐµÑ Ð¿Ð°ÐºÐµÑ‚Ñ–Ð², оголошений Ñервером"
+msgid "operation not supported by protocol"
+msgstr "Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ підтримуєтьÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð¾Ð¼"
+
msgid "too-short tree object"
msgstr "занадто короткий обʼєкт дерева"
@@ -21804,6 +22532,10 @@ msgstr "неприпуÑтимий номер порту"
msgid "invalid '..' path segment"
msgstr "неприпуÑтимий \"..\" Ñегмент шлÑху"
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "помилка: не вдалоÑÑ Ð²Ñ–Ð´Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ допиÑ: %s\n"
+
msgid "usage: "
msgstr "викориÑтаннÑ: "
@@ -21917,8 +22649,11 @@ msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ доÑтуп до \"%s\""
msgid "unable to get current working directory"
msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ поточну робочу директорію"
+msgid "unable to get random bytes"
+msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ випадкові байти"
+
msgid "Unmerged paths:"
-msgstr "не злиті шлÑхи:"
+msgstr "Ðе злиті шлÑхи:"
msgid " (use \"git restore --staged <file>...\" to unstage)"
msgstr ""
@@ -22059,7 +22794,7 @@ msgstr ""
"Ви можете викориÑтати параметр '--no-ahead-behind', щоб уникнути цього.\n"
msgid "You have unmerged paths."
-msgstr "У Ð²Ð°Ñ Ñ” не злиті шлÑхи."
+msgstr "У Ð²Ð°Ñ Ñ” незлиті шлÑхи."
msgid " (fix conflicts and run \"git commit\")"
msgstr " (виправте конфлікти та виконайте \"git commit\")"
@@ -22359,7 +23094,6 @@ msgid "ahead "
msgstr "попереду "
#. TRANSLATORS: the action is e.g. "pull with rebase"
-
#, c-format
msgid "cannot %s: You have unstaged changes."
msgstr "неможливо %s: У Ð²Ð°Ñ Ñ” неіндекÑовані зміни."
@@ -22371,6 +23105,10 @@ msgstr "крім того, ваш Ñ–Ð½Ð´ÐµÐºÑ Ð¼Ñ–Ñтить незакоміч
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "неможливо виконати %s: Ваш Ñ–Ð½Ð´ÐµÐºÑ Ð¼Ñ–Ñтить незакомічені зміни."
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "невідомий Ñтиль \"%s\" наданий Ð´Ð»Ñ \"%s\""
+
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
@@ -22555,18 +23293,17 @@ msgstr ""
"ОчиÑтіть вміÑÑ‚ тіла, Ñкщо ви не бажаєте надÑилати підÑумок.\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"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ %s: %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]? "
@@ -22611,7 +23348,6 @@ msgstr "помилка: не вдалоÑÑ Ð²Ð¸Ñ‚Ñгти дійÑну адре
#. 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): "
@@ -22646,7 +23382,6 @@ msgstr ""
#. 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): "
@@ -22674,24 +23409,24 @@ msgid "Failed to send %s\n"
msgstr "Ðе вдалоÑÑ Ð½Ð°Ð´Ñ–Ñлати %s\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Пробно відправлено %s\n"
+msgid "Dry-Sent %s"
+msgstr "Пробно відправлено %s"
#, perl-format
-msgid "Sent %s\n"
-msgstr "Відправлено %s\n"
+msgid "Sent %s"
+msgstr "Відправлено %s"
-msgid "Dry-OK. Log says:\n"
-msgstr "Пробно OK. Журнал каже:\n"
+msgid "Dry-OK. Log says:"
+msgstr "Пробно OK. Журнал каже:"
-msgid "OK. Log says:\n"
-msgstr "ОК. Журнал каже:\n"
+msgid "OK. Log says:"
+msgstr "ОК. Журнал каже:"
msgid "Result: "
msgstr "Результат: "
-msgid "Result: OK\n"
-msgstr "Результат: OK\n"
+msgid "Result: OK"
+msgstr "Результат: OK"
#, perl-format
msgid "can't open file %s"
@@ -22762,7 +23497,6 @@ 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]: "
diff --git a/po/vi.po b/po/vi.po
index d673745ac5..00008b50f5 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -2,32 +2,86 @@
# Bản dịch tiếng Việt dành cho GIT-CORE.
# This file is distributed under the same license as the git-core package.
# https://raw.githubusercontent.com/git-l10n/git-po/pot/main/po/git.pot
+# ---
+# Copyright (C) 2012-2022, Translation Project, Vietnamese Team <http://translationproject.org/team/vi.html>
+# Copyright (C) 2024, Vũ Tiến Hưng <newcomerminecraft@gmail.com>
# Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com>, 2012.
# Äoàn Trần Công Danh <congdanhqx@gmail.com>, 2020.
# Trần Ngá»c Quân <vnwildman@gmail.com>, 2012-2022.
+# Vũ Tiến Hưng <newcomerminecraft@gmail.com>, 2024.
+# ---
+# BẢNG THUẬT NGỮ / TERMINOLOGY
+# Updated: 2024-07-26, git 2.46
#
-msgid ""
-msgstr ""
-"Project-Id-Version: git v2.37.0\n"
+# Ghi chú:
+# - Bảng thuật ngữ này chưa hoàn thiện.
+# - Tuỳ vào ngữ cảnh, bản dịch có thể thay đổi cho phù hợp.
+#
+# CÃCH VIẾT TẮT
+# n. = danh từ
+# v. = động từ
+# a. = tính từ
+#
+# +------------------------------------------------------------------+
+# | Thuật ngữ / Term | Bản dịch / Translation |
+# +------------------------------------------------------------------+
+# | file | tập tin |
+# | folder | thư mục |
+# | path | đưá»ng dẫn |
+# | error | lá»—i |
+# | fatal / fatal error | lá»—i nghiêm trá»ng |
+# | warning | cảnh báo |
+# | (v.) commit | chuyển giao |
+# | (n.) commit | lần chuyển giao |
+# | (n.) branch | nhánh |
+# | (v.) branch | tạo nhánh |
+# | (n.) log | nhật ký |
+# | (v.) log | ghi lại |
+# | (n.) ref/refs | tham chiếu |
+# | hunk | khúc |
+# | index | chỉ mục |
+# | (n.) stage | vùng chỠ|
+# | (v.) stage <...> | đưa <...> vào vùng chỠ|
+# | (v.) unstage <...> | bá» <...> ra khá»i vùng chá» |
+# | revert | hoàn nguyên |
+# | add | thêm |
+# | restore | phục hồi |
+# | (n./v.) change | thay đổi |
+# | (v.) update | cập nhật |
+# | (v.) track | theo dõi |
+# | (v.) untrack | bỠtheo dõi |
+# | (a.) tracked | được theo dõi |
+# | (a.) untracked | không được theo dõi |
+# | (v.) parse | hiểu cú pháp |
+# | (n.) output | đầu ra, kết quả |
+# | (v.) output | in ra, xuất ra |
+# | (v.) merge | hoà trộn |
+# | (v.) rebase | cải tổ |
+# | (v.) squash | squash |
+# | (v.) amend | tu bổ |
+# | | |
+# | ... TODO ... | |
+# +------------------------------------------------------------------+
+msgid ""
+msgstr ""
+"Project-Id-Version: git 2.47\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-21 20:20+0000\n"
-"PO-Revision-Date: 2022-06-25 08:37+0700\n"
-"Last-Translator: Trần Ngá»c Quân <vnwildman@gmail.com>\n"
-"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 16:48+0700\n"
+"Last-Translator: Vũ Tiến Hưng <newcomerminecraft@gmail.com>\n"
+"Language-Team: Vietnamese <https://github.com/Nekosha/git-po>\n"
"Language: vi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0\n"
-"X-Language-Team-Website: <http://translationproject.org/team/vi.html>\n"
-"X-Generator: Gtranslator 42.0\n"
#, c-format
msgid "Huh (%s)?"
msgstr "Hả (%s)?"
msgid "could not read index"
-msgstr "không thể Ä‘á»c bảng mục lục"
+msgstr "không thể Ä‘á»c chỉ mục"
msgid "binary"
msgstr "nhị phân"
@@ -43,31 +97,31 @@ msgstr "Cập nhật"
#, c-format
msgid "could not stage '%s'"
-msgstr "không thể đưa “%s†lên bệ phóng"
+msgstr "không thể đưa '%s' vào vùng chá»"
msgid "could not write index"
-msgstr "không thể ghi bảng mục lục"
+msgstr "không thể ghi chỉ mục"
-#, c-format, perl-format
+#, c-format
msgid "updated %d path\n"
msgid_plural "updated %d paths\n"
msgstr[0] "đã cập nhật %d đưá»ng dẫn\n"
-#, c-format, perl-format
+#, c-format
msgid "note: %s is untracked now.\n"
-msgstr "chú ý: %s giỠđã bỠtheo dõi.\n"
+msgstr "chú ý: đã bỠtheo dõi %s.\n"
#, c-format
msgid "make_cache_entry failed for path '%s'"
-msgstr "make_cache_entry gặp lá»—i đối vá»›i đưá»ng dẫn “%sâ€"
+msgstr "make_cache_entry gặp lá»—i đối vá»›i đưá»ng dẫn '%s'"
msgid "Revert"
msgstr "Hoàn nguyên"
msgid "Could not parse HEAD^{tree}"
-msgstr "Không thể phân tích cú pháp HEAD^{tree}"
+msgstr "Không hiểu cú pháp HEAD^{tree}"
-#, c-format, perl-format
+#, c-format
msgid "reverted %d path\n"
msgid_plural "reverted %d paths\n"
msgstr[0] "đã hoàn nguyên %d đưá»ng dẫn\n"
@@ -77,33 +131,33 @@ msgid "No untracked files.\n"
msgstr "Không có tập tin nào chưa được theo dõi.\n"
msgid "Add untracked"
-msgstr "Thêm các cái chưa được theo dõi"
+msgstr "Thêm các tập tin chưa được theo dõi"
-#, c-format, perl-format
+#, c-format
msgid "added %d path\n"
msgid_plural "added %d paths\n"
msgstr[0] "đã thêm %d đưá»ng dẫn\n"
#, c-format
msgid "ignoring unmerged: %s"
-msgstr "bỠqua những thứ chưa hòa trộn: %s"
+msgstr "bỠqua những tập tin chưa hòa trộn: %s"
#, c-format
msgid "Only binary files changed.\n"
-msgstr "Chỉ có các tập tin nhị phân là thay đổi.\n"
+msgstr "Chỉ có các tập tin nhị phân thay đổi.\n"
#, c-format
msgid "No changes.\n"
msgstr "Không có thay đổi nào.\n"
msgid "Patch update"
-msgstr "Cập nhật miếng vá"
+msgstr "Cập nhật bản vá"
msgid "Review diff"
-msgstr "Xem xét lại diff"
+msgstr "Xem xét lại thay đổi"
msgid "show paths with changes"
-msgstr "hiển thị đưá»ng dẫn vá»›i các thay đổi"
+msgstr "hiển thị các đưá»ng dẫn có thay đổi"
msgid "add working tree state to the staged set of changes"
msgstr ""
@@ -112,19 +166,19 @@ msgstr ""
msgid "revert staged set of changes back to the HEAD version"
msgstr ""
-"hoàn nguyên lại tập hợp các thay đổi đã được đưa lên bệ phóng trở lại phiên "
+"hoàn nguyên lại tập hợp các thay đổi đã được đưa vào vùng chỠtrở lại phiên "
"bản HEAD"
msgid "pick hunks and update selectively"
-msgstr "chá»n các “khúc†và cập nhật có tuyển chá»n"
+msgstr "chá»n các khúc và cập nhật có lá»±a chá»n"
msgid "view diff between HEAD and index"
-msgstr "xem khác biệt giữa HEAD và mục lục"
+msgstr "xem khác biệt giữa HEAD và chỉ mục"
msgid "add contents of untracked files to the staged set of changes"
msgstr ""
"thêm nội dung của các tập tin chưa được theo dõi vào tập hợp các thay đổi đã "
-"được đưa lên bệ phóng"
+"được đưa vào vùng chá»"
msgid "Prompt help:"
msgstr "Trợ giúp vỠnhắc:"
@@ -139,7 +193,7 @@ msgid "select multiple ranges"
msgstr "chá»n nhiá»u vùng"
msgid "select item based on unique prefix"
-msgstr "chá»n mục dá»±a trên tiá»n tố duy nhất"
+msgstr "chá»n mục dá»±a trên tiá»n tố độc nhất"
msgid "unselect specified items"
msgstr "bá» chá»n các mục đã cho"
@@ -151,7 +205,7 @@ msgid "(empty) finish selecting"
msgstr "(để trống) hoàn tất chá»n lá»±a"
msgid "select a numbered item"
-msgstr "tùy chá»n mục bằng số"
+msgstr "lá»±a chá»n mục bằng số"
msgid "(empty) select nothing"
msgstr "(để trống) không chá»n gì"
@@ -163,43 +217,43 @@ msgid "What now"
msgstr "GiỠthì sao"
msgid "staged"
-msgstr "đã đưa lên bệ phóng"
+msgstr "đã đưa vào vùng chá»"
msgid "unstaged"
-msgstr "chưa đưa lên bệ phóng"
+msgstr "chưa đưa vào vùng chá»"
msgid "path"
msgstr "đưá»ng-dẫn"
msgid "could not refresh index"
-msgstr "không thể Ä‘á»c lại bảng mục lục"
+msgstr "không thể Ä‘á»c lại chỉ mục"
#, c-format
msgid "Bye.\n"
msgstr "Tạm biệt.\n"
-#, c-format, perl-format
+#, c-format
msgid "Stage mode change [y,n,q,a,d%s,?]? "
-msgstr "Thay đổi chế độ bệ phóng [y,n,q,a,d%s,?]? "
+msgstr "ÄÆ°a vào vùng chá» thay đổi chế độ [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage deletion [y,n,q,a,d%s,?]? "
-msgstr "Xóa khá»i bệ phóng [y,n,q,a,d%s,?]? "
+msgstr "ÄÆ°a vào vùng chá» thao tác xoá [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage addition [y,n,q,a,d%s,?]? "
-msgstr "Thêm vào bệ phóng [y,n,q,a,d%s,?]? "
+msgstr "ÄÆ°a vào vùng chá» thao tác thêm [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage this hunk [y,n,q,a,d%s,?]? "
-msgstr "ÄÆ°a lên bệ phóng khúc này [y,n,q,a,d%s,?]? "
+msgstr "ÄÆ°a vào vùng chá» khúc này [y,n,q,a,d%s,?]? "
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"staging."
msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức được đánh dấu "
-"để chuyển lên bệ phóng."
+"Nếu bản vá được áp dụng hoàn toàn, khúc đã sửa sẽ ngay lập tức được đánh dấu "
+"để chuyển vào vùng chá»."
msgid ""
"y - stage this hunk\n"
@@ -208,26 +262,25 @@ msgid ""
"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 - đưa lên bệ phóng khúc này\n"
-"n - đừng đưa lên bệ phóng khúc này\n"
-"q - thoát; đừng đưa lên bệ phóng khúc này cũng như bất kỳ cái nào còn lại\n"
-"a - đưa lên bệ phóng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng đưa lên bệ phóng khúc này cũng như bất kỳ cái nào còn lại trong tập "
-"tin\n"
+"y - đưa vào vùng chỠkhúc này\n"
+"n - đừng đưa vào vùng chỠkhúc này\n"
+"q - thoát; đừng đưa vào vùng chỠkhúc này hay bất kỳ cái nào còn lại\n"
+"a - đưa vào vùng chỠkhúc này và tất cả các khúc sau này trong tập tin\n"
+"d - đừng đưa vào vùng chỠkhúc này hay bất kỳ cái nào còn lại trong tập tin\n"
-#, c-format, perl-format
+#, c-format
msgid "Stash mode change [y,n,q,a,d%s,?]? "
-msgstr "Thay đổi chế độ tạm cất đi [y,n,q,a,d%s,?]? "
+msgstr "Tạm cất thay đổi chế độ [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash deletion [y,n,q,a,d%s,?]? "
-msgstr "Xóa tạm cất [y,n,q,a,d%s,?]? "
+msgstr "Tạm cất thao tác xoá [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash addition [y,n,q,a,d%s,?]? "
-msgstr "Thêm vào tạm cất [y,n,q,a,d%s,?]? "
+msgstr "Tạm cất thao tác thêm [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash this hunk [y,n,q,a,d%s,?]? "
msgstr "Tạm cất khúc này [y,n,q,a,d%s,?]? "
@@ -235,7 +288,7 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"stashing."
msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức được đánh dấu "
+"Nếu bản vá được áp dụng hoàn toàn, khúc đã sửa sẽ ngay lập tức được đánh dấu "
"để tạm cất."
msgid ""
@@ -247,32 +300,32 @@ msgid ""
msgstr ""
"y - tạm cất khúc này\n"
"n - đừng tạm cất khúc này\n"
-"q - thoát; đừng tạm cất khúc này cũng như bất kỳ cái nào còn lại\n"
+"q - thoát; đừng tạm cất khúc này hay bất kỳ cái nào còn lại\n"
"a - tạm cất khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng tạm cất khúc này cũng như bất kỳ cái nào còn lại trong tập tin\n"
+"d - đừng tạm cất khúc này hay bất kỳ cái nào còn lại trong tập tin\n"
-#, c-format, perl-format
+#, c-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
-msgstr "Thay đổi chế độ bá» ra khá»i bệ phóng [y,n,q,a,d%s,?]? "
+msgstr "Bá» ra khá»i vùng chá» thay đổi chế độ [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage deletion [y,n,q,a,d%s,?]? "
-msgstr "Xóa bá» việc bá» ra khá»i bệ phóng [y,n,q,a,d%s,?]? "
+msgstr "Bá» ra khá»i vùng chá» thao tác xoá [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage addition [y,n,q,a,d%s,?]? "
-msgstr "Thêm vào việc bá» ra khá»i bệ phóng [y,n,q,a,d%s,?]? "
+msgstr "Bá» ra khá»i vùng chá» thao tác thêm [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
-msgstr "Bá» ra khá»i bệ phóng khúc này [y,n,q,a,d%s,?]? "
+msgstr "Bá» ra khá»i vùng chá» khúc này [y,n,q,a,d%s,?]? "
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"unstaging."
msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức được đánh dấu "
-"để bá» ra khá»i bệ phóng."
+"Nếu bản vá được áp dụng hoàn toàn, khúc đã sửa sẽ ngay lập tức được đánh dấu "
+"để bá» ra khá»i vùng chá»."
msgid ""
"y - unstage this hunk\n"
@@ -281,35 +334,34 @@ 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 - đưa ra khá»i bệ phóng khúc này\n"
-"n - đừng đưa ra khá»i bệ phóng khúc này\n"
-"q - thoát; đừng đưa ra khá»i bệ phóng khúc này cÅ©ng như bất kỳ cái nào còn "
-"lại\n"
-"a - đưa ra khá»i bệ phóng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng đưa ra khá»i bệ phóng khúc này cÅ©ng như bất kỳ cái nào còn lại trong "
-"tập tin\n"
+"y - đưa ra khá»i vùng chá» khúc này\n"
+"n - đừng đưa ra khá»i vùng chá» khúc này\n"
+"q - thoát; đừng đưa ra khá»i vùng chá» khúc này hay bất kỳ cái nào còn lại\n"
+"a - đưa ra khá»i vùng chá» khúc này và tất cả các khúc sau này trong tập tin\n"
+"d - đừng đưa ra khá»i vùng chá» khúc này hay bất kỳ cái nào còn lại trong tập "
+"tin\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng thay đổi chế độ cho mục lục [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thay đổi chế độ vào chỉ mục [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng việc xóa vào mục lục [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thao tác xóa vào chỉ mục [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to index [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng các thêm vào mục lục [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thao tác thêm vào chỉ mục [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 "Ão dụng khúc này vào mục lục [y,n,q,a,d%s,?]? "
+msgstr "Ão dụng khúc này vào chỉ mục [y,n,q,a,d%s,?]? "
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"applying."
msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức được đánh dấu "
+"Nếu bản vá được áp dụng hoàn toàn, khúc đã sửa sẽ ngay lập tức được đánh dấu "
"để áp dụng."
msgid ""
@@ -319,25 +371,25 @@ 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 - áp dụng khúc này vào mục lục\n"
-"n - đừng áp dụng khúc này vào mục lục\n"
-"q - thoát; đừng áp dụng khúc này cũng như bất kỳ cái nào còn lại\n"
+"y - áp dụng khúc này vào chỉ mục\n"
+"n - đừng áp dụng khúc này vào chỉ mục\n"
+"q - thoát; đừng áp dụng khúc này hay bất kỳ cái nào còn lại\n"
"a - áp dụng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng áp dụng khúc này cũng như bất kỳ cái nào sau này trong tập tin\n"
+"d - đừng áp dụng khúc này hay bất kỳ cái nào sau này trong tập tin\n"
-#, c-format, perl-format
+#, c-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
-msgstr "Loại bỠcác thay đổi chế độ từ cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» thay đổi chế độ khá»i cây làm việc [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
-msgstr "Loại bá» việc xóa khá»i cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» thao tác xóa khá»i cây làm việc [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
-msgstr "Thêm các loại bá» khá»i cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» thao tác thêm khá»i cây làm việc [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 "Loại bá» khúc này khá»i cây làm việc [y,n,q,a,d%s,?]? "
@@ -345,7 +397,7 @@ msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"discarding."
msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức được đánh dấu "
+"Nếu bản vá được áp dụng hoàn toàn, khúc đã sửa sẽ ngay lập tức được đánh dấu "
"để loại bá»."
msgid ""
@@ -357,25 +409,25 @@ msgid ""
msgstr ""
"y - loại bá» khúc này khá»i cây làm việc\n"
"n - đừng loại bá» khúc khá»i cây làm việc\n"
-"q - thoát; đừng loại bỠkhúc này cũng như bất kỳ cái nào còn lại\n"
+"q - thoát; đừng loại bỠkhúc này hay bất kỳ cái nào còn lại\n"
"a - loại bỠkhúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng loại bỠkhúc này cũng như bất kỳ cái nào sau này trong tập tin\n"
+"d - đừng loại bỠkhúc này hay bất kỳ cái nào sau này trong tập tin\n"
-#, c-format, perl-format
+#, c-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Loại bỠthay đổi chế độ từ mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» thay đổi chế độ khá»i chỉ mục và cây làm việc [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 "Loại bá» việc xóa khá»i mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» thao tác xóa khá»i chỉ mục và cây làm việc [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 "Thêm các loại bỠtừ mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» thao tác thêm khá»i chỉ mục và cây làm việc [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 "Loại bá» khúc này khá»i mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Loại bá» khúc này khá»i chỉ mục và cây làm việc [y,n,q,a,d%s,?]? "
msgid ""
"y - discard this hunk from index and worktree\n"
@@ -384,27 +436,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 - loại bá» khúc này khá»i mục lục và cây làm việc\n"
-"n - đừng loại bá» khúc khá»i mục lục và cây làm việc\n"
-"q - thoát; đừng loại bỠkhúc này cũng như bất kỳ cái nào còn lại\n"
+"y - loại bá» khúc này khá»i chỉ mục và cây làm việc\n"
+"n - đừng loại bá» khúc khá»i chỉ mục và cây làm việc\n"
+"q - thoát; đừng loại bỠkhúc này hay bất kỳ cái nào còn lại\n"
"a - loại bỠkhúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng loại bỠkhúc này cũng như bất kỳ cái nào sau này trong tập tin\n"
+"d - đừng loại bỠkhúc này hay bất kỳ cái nào sau này trong tập tin\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng thay đổi chế độ cho mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thay đổi chế độ cho chỉ mục và cây làm việc [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 "Ãp dụng việc xóa vào mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thao tác xóa vào chỉ mục và cây làm việc [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 "Ãp dụng thêm vào mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thao tác thêm vào chỉ mục và cây làm việc [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 "Ãp dụng khúc này vào mục lục và cây làm việc [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng khúc này vào chỉ mục và cây làm việc [y,n,q,a,d%s,?]? "
msgid ""
"y - apply this hunk to index and worktree\n"
@@ -413,11 +465,27 @@ 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 - áp dụng khúc này vào mục lục và cây làm việc\n"
-"n - đừng áp dụng khúc vào mục lục và cây làm việc\n"
-"q - thoát; đừng áp dụng khúc này cũng như bất kỳ cái nào còn lại\n"
+"y - áp dụng khúc này vào chỉ mục và cây làm việc\n"
+"n - đừng áp dụng khúc vào chỉ mục và cây làm việc\n"
+"q - thoát; đừng áp dụng khúc này hay bất kỳ cái nào còn lại\n"
"a - áp dụng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng áp dụng khúc này cũng như bất kỳ cái nào sau này trong tập tin\n"
+"d - đừng áp dụng khúc này hay bất kỳ cái nào sau này trong tập tin\n"
+
+#, c-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thay đổi chế độ cho cây làm việc [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thao tác xóa cho cây làm việc [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng thao tác thêm cho cây làm việc [y,n,q,a,d%s,?]? "
+
+#, c-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Ãp dụng khúc này vào cây làm việc [y,n,q,a,d%s,?]? "
msgid ""
"y - apply this hunk to worktree\n"
@@ -428,36 +496,32 @@ msgid ""
msgstr ""
"y - áp dụng khúc này vào cây làm việc\n"
"n - đừng áp dụng khúc vào cây làm việc\n"
-"q - thoát; đừng áp dụng khúc này cũng như bất kỳ cái nào còn lại\n"
+"q - thoát; đừng áp dụng khúc này hay bất kỳ cái nào còn lại\n"
"a - áp dụng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng áp dụng khúc này cũng như bất kỳ cái nào sau này trong tập tin\n"
+"d - đừng áp dụng khúc này hay bất kỳ cái nào sau này trong tập tin\n"
#, c-format
msgid "could not parse hunk header '%.*s'"
-msgstr "không thể phân tích cú pháp phần đầu cá»§a khúc “%.*sâ€"
-
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "không thể phân tích cú pháp phần đầu khúc đã tô màu “%.*sâ€"
+msgstr "không thể Ä‘á»c phần đầu cá»§a khúc '%.*s'"
msgid "could not parse diff"
-msgstr "không thể phân tích cú pháp khác biệt"
+msgstr "không thể Ä‘á»c diff"
msgid "could not parse colored diff"
-msgstr "không thể phân tích khác biệt được tô màu"
+msgstr "không thể Ä‘á»c diff có màu"
#, c-format
msgid "failed to run '%s'"
-msgstr "gặp lá»—i khi chạy “%sâ€"
+msgstr "gặp lỗi khi chạy '%s'"
msgid "mismatched output from interactive.diffFilter"
-msgstr "đầu ra không khớp từ interactive.diffFilter"
+msgstr "đầu ra không khớp nhau từ interactive.diffFilter"
msgid ""
"Your filter must maintain a one-to-one correspondence\n"
"between its input and output lines."
msgstr ""
-"Bá»™ lá»c cá»§a bạn phải duy trì má»™t quan hệ má»™t-đến-má»™t\n"
+"Bá»™ lá»c cá»§a bạn phải duy trì quan hệ má»™t-má»™t\n"
"giữa các dòng đầu vào và đầu ra của nó."
#, c-format
@@ -465,7 +529,7 @@ msgid ""
"expected context line #%d in\n"
"%.*s"
msgstr ""
-"cần dòng ngữ cảnh #%d trong\n"
+"cần dòng ngữ cảnh số %d trong\n"
"%.*s"
#, c-format
@@ -481,51 +545,42 @@ msgstr ""
"%.*s"
msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
-msgstr "Chế độ sửa khúc bằng tay -- xem ở đáy để có hướng dẫn sử dụng nhanh.\n"
+msgstr ""
+"Chế độ sửa khúc bằng tay -- xem ở dưới để có hướng dẫn sử dụng nhanh.\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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
-"Äể gỡ bá» dòng “%câ€, sá»­a chúng thành những dòng “ †(ngữ cảnh).\n"
-"Äể gõ bá» dòng “%câ€, xóa chúng Ä‘i.\n"
-"Những dòng bắt đầu bằng %c sẽ bị loại bá».\n"
+"Äể gỡ bá» dòng '%c', sá»­a chúng thành những dòng ' ' (ngữ cảnh).\n"
+"Äể gõ bá» dòng '%c', xóa chúng Ä‘i.\n"
+"Những dòng bắt đầu bằng %s sẽ bị loại bá».\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"
"aborted and the hunk is left unchanged.\n"
msgstr ""
-"Nếu miếng vá không được áp dụng sạch sẽ, bạn sẽ có một cơ hội\n"
-"để sá»­a lần nữa. Nếu má»i dòng cá»§a khúc bị xóa bá», thế thì những\n"
-"sá»­a dổi sẽ bị loại bá», và khúc vẫn giữ nguyên.\n"
+"Nếu bản vá không được áp dụng hoàn toàn, bạn sẽ có cơ hội\n"
+"để sá»­a lại. Nếu má»i dòng cá»§a khúc bị xóa bá», thì những\n"
+"sá»­a đổi sẽ bị loại bá», và khúc vẫn giữ nguyên.\n"
msgid "could not parse hunk header"
-msgstr "không thể phân tích cú pháp phần đầu khúc"
+msgstr "không hiểu cú pháp phần đầu khúc"
msgid "'git apply --cached' failed"
-msgstr "“git apply --cached†gặp lỗi"
+msgstr "'git apply --cached' gặp lỗi"
-#. #-#-#-#-# 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 ""
@@ -533,7 +588,7 @@ msgstr ""
"bá»!) [y/n]? "
msgid "The selected hunks do not apply to the index!"
-msgstr "Các khúc đã chá»n không được áp dụng vào bảng mục lục!"
+msgstr "Các khúc đã chá»n không được áp dụng vào chỉ mục!"
msgid "Apply them to the worktree anyway? "
msgstr "Vẫn áp dụng chúng cho cây làm việc? "
@@ -550,6 +605,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j - để lại khúc này là chưa quyết định, xem khúc chưa quyết định kế tiếp\n"
@@ -557,11 +613,16 @@ msgstr ""
"k - để lại khúc này là chưa quyết định, xem khúc chưa quyết định kế trước\n"
"K - để lại khúc này là chưa quyết định, xem khúc kế trước\n"
"g - chá»n má»™t khúc muốn tá»›i\n"
-"/ - tìm một khúc khớp với biểu thức chính quy đưa ra\n"
+"/ - tìm một khúc khớp với biểu thức chính quy\n"
"s - chia khúc hiện tại thành các khúc nhỠhơn\n"
"e - sửa bằng tay khúc hiện hành\n"
+"p - in ra khúc hiện hành, 'P' để chạy trình phân trang\n"
"? - hiển thị trợ giúp\n"
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "Cần một ký tự, nhưng lại có '%s'"
+
msgid "No previous hunk"
msgstr "Không có khúc kế trước"
@@ -569,48 +630,58 @@ msgid "No next hunk"
msgstr "Không có khúc kế tiếp"
msgid "No other hunks to goto"
-msgstr "Không còn khúc nào để mà nhảy đến"
+msgstr "Không còn khúc nào để nhảy đến"
msgid "go to which hunk (<ret> to see more)? "
-msgstr "nhảy đến khúc nào (<ret> để xem thêm)? "
+msgstr "nhảy đến khúc nào (<Enter> để xem thêm)? "
msgid "go to which hunk? "
msgstr "nhảy đến khúc nào? "
#, c-format
msgid "Invalid number: '%s'"
-msgstr "Số không hợp lệ: “%sâ€"
+msgstr "Số không hợp lệ: '%s'"
#, c-format
msgid "Sorry, only %d hunk available."
msgid_plural "Sorry, only %d hunks available."
-msgstr[0] "Rất tiếc, chỉ có sẵn %d khúc."
+msgstr[0] "Chỉ có %d khúc."
msgid "No other hunks to search"
-msgstr "Không còn khúc nào để mà tìm kiếm"
+msgstr "Không còn khúc nào để tìm kiếm"
msgid "search for regex? "
-msgstr "tìm kiếm cho biểu thức chính quy? "
+msgstr "tìm kiếm cho biểu thức chính quy (regex)? "
#, c-format
msgid "Malformed search regexp %s: %s"
-msgstr "Äịnh dạng tìm kiếm cá»§a biểu thức chính quy không đúng %s: %s"
+msgstr "Äịnh dạng tìm kiếm cá»§a biểu thức chính quy (regex) bất thưá»ng %s: %s"
msgid "No hunk matches the given pattern"
msgstr "Không thấy khúc nào khớp mẫu đã cho"
msgid "Sorry, cannot split this hunk"
-msgstr "Rất tiếc, không thể chia nhỠkhúc này"
+msgstr "Không thể chia nhỠkhúc này"
#, c-format
msgid "Split into %d hunks."
-msgstr "Chi nhỠthành %d khúc."
+msgstr "Chia nhỠthành %d khúc."
msgid "Sorry, cannot edit this hunk"
-msgstr "Rất tiếc, không thể sửa khúc này"
+msgstr "Không thể sửa khúc này"
+
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "không hiểu câu lệnh: '%s' ('?' để hiển thị trợ giúp)"
msgid "'git apply' failed"
-msgstr "“git apply†gặp lỗi"
+msgstr "'git apply' gặp lỗi"
+
+msgid "No changes."
+msgstr "Không có thay đổi nào."
+
+msgid "Only binary files changed."
+msgstr "Chỉ có các tập tin nhị phân thay đổi."
#, c-format
msgid ""
@@ -621,47 +692,41 @@ msgstr ""
"Tắt lá»i nhắn này bằng \"git config advice.%s false\""
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sgợi ý: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sgợi ý:%s%.*s%s\n"
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr ""
-"Cherry-picking là không thể thực hiện bởi vì bạn có những tập tin chưa được "
-"hòa trộn."
+"Không thể thực hiện cherry-pick vì bạn có những tập tin chưa được hòa trộn."
msgid "Committing is not possible because you have unmerged files."
msgstr ""
-"Không thể thực hiện chuyển giao được bởi vì bạn có những tập tin chưa được "
-"hòa trộn."
+"Không thể thực hiện chuyển giao vì bạn có những tập tin chưa được hòa trộn."
msgid "Merging is not possible because you have unmerged files."
msgstr ""
-"Không thể thực hiện hòa trộn bởi vì bạn có những tập tin chưa được hòa trộn."
+"Không thể thực hiện hòa trộn vì bạn có những tập tin chưa được hòa trộn."
msgid "Pulling is not possible because you have unmerged files."
-msgstr ""
-"Không thể thực hiện kéo vỠbởi vì bạn có những tập tin chưa được hòa trộn."
+msgstr "Không thể thực hiện kéo vỠvì bạn có những tập tin chưa được hòa trộn."
msgid "Reverting is not possible because you have unmerged files."
msgstr ""
-"Không thể thực hiện hoàn nguyên bởi vì bạn có những tập tin chưa được hòa "
-"trá»™n."
+"Không thể thực hiện hoàn nguyên vì bạn có những tập tin chưa được hòa trộn."
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
+msgid "Rebasing is not possible because you have unmerged files."
msgstr ""
-"Việc này không thể thực hiện với %s bởi vì bạn có những tập tin chưa được "
-"hòa trộn."
+"Không thể thực hiện hoàn nguyên vì bạn có những tập tin chưa được hòa trộn."
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 ""
-"Sá»­a chúng trong cây làm việc, và sau đó dùng lệnh “git add/rm <tập-tin>â€\n"
-"dành riêng cho việc đánh dấu cần giải quyết và tạo lần chuyển giao."
+"Sửa chúng trong cây làm việc, và sau đó dùng lệnh 'git add/rm <tập-tin>'\n"
+"để chá»n cách giải quyết và tiến hành chuyển giao."
msgid "Exiting because of an unresolved conflict."
-msgstr "Thoát ra bởi vì xung đột không thể giải quyết."
+msgstr "Thoát vì không thể giải quyết xung đột."
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Bạn chưa kết thúc việc hòa trộn (MERGE_HEAD vẫn tồn tại)."
@@ -670,10 +735,27 @@ msgid "Please, commit your changes before merging."
msgstr "Vui lòng chuyển giao các thay đổi trước khi hòa trộn."
msgid "Exiting because of unfinished merge."
-msgstr "Thoát ra bởi vì việc hòa trộn không hoàn tất."
+msgstr "Thoát vì việc hòa trộn còn dang dở."
+
+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 ""
+"Không thể chuyển-tiếp-nhanh các nhánh phân kỳ, bạn cần dùng:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"hoặc:\n"
+"\n"
+"\tgit rebase\n"
msgid "Not possible to fast-forward, aborting."
-msgstr "Thực hiện lệnh chuyển-tiếp-nhanh là không thể được, đang bỠqua."
+msgstr "Không thể chuyển-tiếp-nhanh, đang huỷ lệnh."
#, c-format
msgid ""
@@ -683,7 +765,7 @@ msgid ""
msgstr ""
"Các đưá»ng dẫn và/hoặc đặc tả đưá»ng dẫn sau đây khá»›p vá»›i các đưá»ng dẫn tồn "
"tại\n"
-"bên ngoài định nghĩa “sparse-checkout†của bạn, vì vậy sẽ không\n"
+"bên ngoài định nghĩa 'sparse-checkout' của bạn, vì vậy sẽ không\n"
"cập nhật trong chỉ mục:\n"
msgid ""
@@ -693,7 +775,7 @@ msgid ""
msgstr ""
"Nếu bạn có ý định cập nhật các mục như vậy, hãy thử một trong các mục sau:\n"
"* Sá»­ dụng tùy chá»n --sparse.\n"
-"* Vô hiệu hóa hoặc sửa đổi các quy tắc thưa thớt."
+"* Vô hiệu hóa hoặc sửa đổi sparse rules (luật thưa)."
#, c-format
msgid ""
@@ -716,14 +798,14 @@ msgid ""
"false\n"
"\n"
msgstr ""
-"Chú ý: Ä‘ang chuyển sang “%sâ€.\n"
+"Chú ý: đang chuyển sang '%s'.\n"
"\n"
-"Bạn Ä‘ang ở tình trạng “detached HEADâ€. Bạn có thể xem qua, tạo các thay\n"
-"đổi thử nghiệm và chuyển giao chúng, bạn có thể loại bỠbất kỳ lần chuyển\n"
-"giao nào trong tình trạng này mà không cần đụng chạm đến bất kỳ nhánh nào\n"
+"Bạn đang ở tình trạng 'detached HEAD'. Bạn có thể xem qua, tạo và\n"
+"chuyển giao các thay đổi thử nghiệm, và bạn có thể loại bỠcác lần chuyển\n"
+"giao trong trạng thái này mà không ảnh hưởng đến bất kỳ nhánh nào\n"
"bằng cách chuyển trở lại một nhánh.\n"
"\n"
-"Nếu bạn muốn tạo một nhánh mới để giữ lại các lần chuyển giao bạn tạo,\n"
+"Nếu bạn muốn tạo một nhánh mới để giữ lại các lần chuyển giao đã tạo,\n"
"bạn có thể làm thế (ngay bây giá» hay sau này) bằng cách dùng tùy chá»n\n"
"dòng lệnh -c. Ví dụ:\n"
"\n"
@@ -736,19 +818,41 @@ msgstr ""
"Tắt hướng dẫn này bằng cách đặt biến advice.detachedHead thành 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 ""
+"Các đưá»ng dẫn sau đã được di chuyển ra ngoài định nghÄ©a\n"
+"sparse-checkout nhưng không còn thuộc loại sparse (thưa) vì có\n"
+"thay đổi nội bộ.\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 ""
+"Äể sá»­a lại đúng loại sprase (thưa) cá»§a các tập này, hãy thá»±c hiện:\n"
+"* Chạy \"git add --sparse <đưá»ng-dẫn>\" để cập nhật chỉ mục\n"
+"* Chạy \"git sparse-checkout reapply\" để áp dụng luật thưa"
+
msgid "cmdline ends with \\"
-msgstr "cmdline kết thúc với \\"
+msgstr "cuối dòng lệnh có \\"
msgid "unclosed quote"
msgstr "chưa có dấu nháy đóng"
+msgid "too many arguments"
+msgstr "có quá nhiá»u đối số"
+
#, c-format
msgid "unrecognized whitespace option '%s'"
-msgstr "không nhận ra tùy chá»n vá» khoảng trắng “%sâ€"
+msgstr "không nhận ra tùy chá»n vá» khoảng trắng '%s'"
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
-msgstr "không nhận ra tùy chá»n bá» qua khoảng trắng “%sâ€"
+msgstr "không nhận ra tùy chá»n bá» qua khoảng trắng '%s'"
#, c-format
msgid "options '%s' and '%s' cannot be used together"
@@ -756,13 +860,17 @@ msgstr "tùy chá»n '%s' và '%s' không thể dùng cùng nhau"
#, c-format
msgid "'%s' outside a repository"
-msgstr "'%s' ở ngoài một kho chứa"
+msgstr "'%s' ở ngoài kho chứa"
+
+msgid "failed to read patch"
+msgstr "gặp lá»—i khi Ä‘á»c bản vá"
+
+msgid "patch too large"
+msgstr "bản vá quá lớn"
#, c-format
msgid "Cannot prepare timestamp regexp %s"
-msgstr ""
-"Không thể chuẩn bị biểu thức chính qui dấu vết thá»i gian (timestamp regexp) "
-"%s"
+msgstr "Không thể chuẩn bị biểu thức chính quy dấu thá»i gian%s"
#, c-format
msgid "regexec returned %d for input: %s"
@@ -770,12 +878,11 @@ msgstr "thi hành biểu thức chính quy trả vỠ%d cho đầu vào: %s"
#, c-format
msgid "unable to find filename in patch at line %d"
-msgstr "không thể tìm thấy tên tập tin trong miếng vá tại dòng %d"
+msgstr "không thể tìm thấy tên tập tin trong bản vá tại dòng %d"
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
-msgstr ""
-"git apply: git-diff sai - cần /dev/null, nhưng lại nhận được %s trên dòng %d"
+msgstr "git apply: git-diff sai - cần /dev/null, nhưng lại có %s trên dòng %d"
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
@@ -787,7 +894,7 @@ msgstr "git apply: git-diff sai - tên tập tin cũ không nhất quán trên d
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
-msgstr "git apply: git-diff sai - cần “/dev/null†trên dòng %d"
+msgstr "git apply: git-diff sai - cần '/dev/null' trên dòng %d"
#, c-format
msgid "invalid mode on line %d: %s"
@@ -795,7 +902,7 @@ msgstr "chế độ không hợp lệ trên dòng %d: %s"
#, c-format
msgid "inconsistent header lines %d and %d"
-msgstr "phần đầu mâu thuẫn dòng %d và %d"
+msgstr "phần đầu không nhất quán tại dòng %d và %d"
#, c-format
msgid ""
@@ -805,8 +912,8 @@ msgid_plural ""
"git diff header lacks filename information when removing %d leading pathname "
"components (line %d)"
msgstr[0] ""
-"phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bỠđi %d trong "
-"thành phần dẫn đầu tên cá»§a đưá»ng dẫn (dòng %d)"
+"phần đầu diff cho git thiếu thông tin tên tập tin khi xoá đi %d mục dẫn đầu "
+"trong tên cá»§a đưá»ng dẫn (dòng %d)"
#, c-format
msgid "git diff header lacks filename information (line %d)"
@@ -814,11 +921,11 @@ msgstr "phần đầu diff cho git thiếu thông tin tên tập tin (dòng %d)"
#, c-format
msgid "recount: unexpected line: %.*s"
-msgstr "chi tiết: dòng không cần: %.*s"
+msgstr "recount: dòng bất thưá»ng %.*s"
#, c-format
msgid "patch fragment without header at line %d: %.*s"
-msgstr "miếng vá phân mảnh mà không có phần đầu tại dòng %d: %.*s"
+msgstr "bản vá không có phần đầu tại dòng %d: %.*s"
msgid "new file depends on old contents"
msgstr "tập tin mới phụ thuộc vào nội dung cũ"
@@ -828,7 +935,7 @@ msgstr "tập tin đã xóa vẫn còn nội dung"
#, c-format
msgid "corrupt patch at line %d"
-msgstr "miếng vá há»ng tại dòng %d"
+msgstr "bản vá há»ng tại dòng %d"
#, c-format
msgid "new file %s depends on old contents"
@@ -844,15 +951,15 @@ msgstr "** cảnh báo: tập tin %s trở nên trống rá»—ng nhưng không bá»
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
-msgstr "miếng vá định dạng nhị phân sai há»ng tại dòng %d: %.*s"
+msgstr "bản vá nhị phân há»ng tại dòng %d: %.*s"
#, c-format
msgid "unrecognized binary patch at line %d"
-msgstr "miếng vá định dạng nhị phân không được nhận ra tại dòng %d"
+msgstr "bản vá nhị phân không thể nhận diện tại dòng %d"
#, c-format
msgid "patch with only garbage at line %d"
-msgstr "vá chỉ với “rác†tại dòng %d"
+msgstr "bản vá chứa 'rác' tại dòng %d"
#, c-format
msgid "unable to read symlink %s"
@@ -864,64 +971,59 @@ msgstr "không thể mở hay Ä‘á»c %s"
#, c-format
msgid "invalid start of line: '%c'"
-msgstr "sai khởi đầu dòng: “%câ€"
+msgstr "sai khởi đầu dòng: '%c'"
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
-msgstr[0] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)."
+msgstr[0] "Khối thứ %d thành công tại %d (offset %d dòng)."
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
-msgstr "Ngữ cảnh bị giảm xuống còn (%ld/%ld) để áp dụng mảnh dữ liệu tại %d"
+msgstr "Ngữ cảnh bị giảm xuống còn (%ld/%ld) để áp dụng bản vá tại %d"
#, c-format
msgid ""
"while searching for:\n"
"%.*s"
msgstr ""
-"trong khi đang tìm kiếm cho:\n"
+"trong khi đang tìm kiếm:\n"
"%.*s"
#, c-format
msgid "missing binary patch data for '%s'"
-msgstr "thiếu dữ liệu cá»§a miếng vá định dạng nhị phân cho “%sâ€"
+msgstr "thiếu dữ liệu của bản vá nhị phân cho '%s'"
#, c-format
msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'"
-msgstr ""
-"không thể reverse-apply một miếng vá nhị phân mà không đảo ngược khúc thành "
-"“%sâ€"
+msgstr "không thể đảo ngược bản vá nhị phân mà không có khúc ngược cho '%s'"
#, c-format
msgid "cannot apply binary patch to '%s' without full index line"
msgstr ""
-"không thể áp dụng miếng vá nhị phân thành “%s†mà không có dòng chỉ mục đầy "
-"đủ"
+"không thể áp dụng bản vá nhị phân cho '%s' mà không có dòng chỉ mục đầy đủ"
#, c-format
msgid ""
"the patch applies to '%s' (%s), which does not match the current contents."
-msgstr ""
-"miếng vá áp dụng cho “%s†(%s), cái mà không khớp với các nội dung hiện tại."
+msgstr "bản vá áp dụng cho '%s' (%s), nhưng không khớp với nội dung hiện tại."
#, c-format
msgid "the patch applies to an empty '%s' but it is not empty"
-msgstr "miếng vá áp dụng cho một “%s†trống rỗng nhưng nó lại không trống"
+msgstr "bản vá áp dụng cho '%s' trống rỗng nhưng nó lại không trống"
#, c-format
msgid "the necessary postimage %s for '%s' cannot be read"
-msgstr "không thể Ä‘á»c postimage %s cần thiết cho “%sâ€"
+msgstr "không thể Ä‘á»c hậu ảnh %s cần thiết cho '%s'"
#, c-format
msgid "binary patch does not apply to '%s'"
-msgstr "miếng vá định dạng nhị phân không được áp dụng cho “%sâ€"
+msgstr "bản vá nhị phân không được áp dụng cho '%s'"
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
-"vá nhị phân cho “%s†tạo ra kết quả không chính xác (mong chỠ%s, lại nhận "
-"%s)"
+"bản vá nhị phân cho '%s' cho ra kết quả không chính xác (cần %s, lại nhận %s)"
#, c-format
msgid "patch failed: %s:%ld"
@@ -929,7 +1031,7 @@ msgstr "gặp lỗi khi vá: %s:%ld"
#, c-format
msgid "cannot checkout %s"
-msgstr "không thể lấy ra %s"
+msgstr "không thể checkout %s"
#, c-format
msgid "failed to read %s"
@@ -937,7 +1039,7 @@ msgstr "gặp lá»—i khi Ä‘á»c %s"
#, c-format
msgid "reading from '%s' beyond a symbolic link"
-msgstr "Ä‘á»c từ “%s†vượt ra ngoài liên kết má»m"
+msgstr "Ä‘á»c từ '%s' đứng sau liên kết má»m"
#, c-format
msgid "path %s has been renamed/deleted"
@@ -945,41 +1047,42 @@ msgstr "đưá»ng dẫn %s đã bị xóa hoặc đổi tên"
#, c-format
msgid "%s: does not exist in index"
-msgstr "%s: không tồn tại trong bảng mục lục"
+msgstr "%s: không tồn tại trong chỉ mục"
#, c-format
msgid "%s: does not match index"
-msgstr "%s: không khớp trong mục lục"
+msgstr "%s: không khớp với chỉ mục"
msgid "repository lacks the necessary blob to perform 3-way merge."
-msgstr "kho thiếu đối tượng blob cần thiết để thá»±c hiện hòa trá»™n “3-wayâ€."
+msgstr ""
+"kho thiếu đối tượng blob cần thiết để thực hiện hòa trộn kiểu three-way."
#, c-format
msgid "Performing three-way merge...\n"
-msgstr "Äang thá»±c hiện hòa trá»™n “3-đưá»ngâ€â€¦\n"
+msgstr "Äang thá»±c hiện hòa trá»™n three-way...\n"
#, c-format
msgid "cannot read the current contents of '%s'"
-msgstr "không thể Ä‘á»c ná»™i dung hiện hành cá»§a “%sâ€"
+msgstr "không thể Ä‘á»c ná»™i dung hiện hành cá»§a '%s'"
#, c-format
msgid "Failed to perform three-way merge...\n"
-msgstr "Gặp lá»—i khi thá»±c hiện hòa trá»™n kiểu “three-wayâ€â€¦\n"
+msgstr "Gặp lỗi khi thực hiện hòa trộn kiểu three-way...\n"
#, c-format
msgid "Applied patch to '%s' with conflicts.\n"
-msgstr "Äã áp dụng miếng vá %s vá»›i các xung đột.\n"
+msgstr "Ãp dụng bản vá '%s' còn các xung đột.\n"
#, c-format
msgid "Applied patch to '%s' cleanly.\n"
-msgstr "Äã áp dụng miếng vá %s má»™t cách sạch sẽ.\n"
+msgstr "Ãp dụng bản vá %s má»™t cách hoàn toàn.\n"
#, c-format
msgid "Falling back to direct application...\n"
-msgstr "Äang trở lại ứng dụng chi phối…\n"
+msgstr "Äang trở vá» cách áp dụng trá»±c tiếp..\n"
msgid "removal patch leaves file contents"
-msgstr "loại bỠmiếng vá để lại nội dung tập tin"
+msgstr "bản vá để lại tập tin còn nội dung"
#, c-format
msgid "%s: wrong type"
@@ -991,15 +1094,15 @@ msgstr "%s có kiểu %o, cần %o"
#, c-format
msgid "invalid path '%s'"
-msgstr "đưá»ng dẫn không hợp lệ “%sâ€"
+msgstr "đưá»ng dẫn không hợp lệ '%s'"
#, c-format
msgid "%s: already exists in index"
-msgstr "%s: đã có từ trước trong bảng mục lục"
+msgstr "%s: đã sẵn có trong chỉ mục"
#, c-format
msgid "%s: already exists in working directory"
-msgstr "%s: đã sẵn có trong thư mục đang làm việc"
+msgstr "%s: đã sẵn có trong thư mục làm việc"
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
@@ -1011,15 +1114,15 @@ msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o)
#, c-format
msgid "affected file '%s' is beyond a symbolic link"
-msgstr "tập tin chịu tác động “%s†vượt ra ngoài liên kết má»m"
+msgstr "tập tin chịu tác động '%s' đứng sau liên kết má»m"
#, c-format
msgid "%s: patch does not apply"
-msgstr "%s: miếng vá không được áp dụng"
+msgstr "%s: bản vá không được áp dụng"
#, c-format
msgid "Checking patch %s..."
-msgstr "Äang kiểm tra miếng vá %s…"
+msgstr "Äang kiểm tra bản vá %s..."
#, c-format
msgid "sha1 information is lacking or useless for submodule %s"
@@ -1027,35 +1130,35 @@ msgstr "thông tin sha1 thiếu hoặc không dùng được cho mô-đun %s"
#, c-format
msgid "mode change for %s, which is not in current HEAD"
-msgstr "thay đổi chế độ cho %s, cái mà không phải là HEAD hiện tại"
+msgstr "thay đổi chế độ cho %s, nhưng nó không nằm trong HEAD hiện tại"
#, c-format
msgid "sha1 information is lacking or useless (%s)."
-msgstr "thông tin sha1 còn thiếu hay không dùng được(%s)."
+msgstr "thông tin sha1 còn thiếu hay không dùng được (%s)."
#, c-format
msgid "could not add %s to temporary index"
-msgstr "không thể thêm %s vào chỉ mục tạm thá»i"
+msgstr "không thể thêm %s vào chỉ mục tạm"
#, c-format
msgid "could not write temporary index to %s"
-msgstr "không thể ghi mục lục tạm vào %s"
+msgstr "không thể ghi chỉ mục tạm vào %s"
#, c-format
msgid "unable to remove %s from index"
-msgstr "không thể gỡ bỠ%s từ mục lục"
+msgstr "không thể gỡ bỠ%s từ chỉ mục"
#, c-format
msgid "corrupt patch for submodule %s"
-msgstr "miếng vá sai há»ng cho mô-Ä‘un-con %s"
+msgstr "bản vá há»ng cho mô-Ä‘un-con %s"
#, c-format
msgid "unable to stat newly created file '%s'"
-msgstr "không thể lấy thống kê vỠtập tin %s mới hơn đã được tạo"
+msgstr "không thể stat tập tin '%s' mới tạo"
#, c-format
msgid "unable to create backing store for newly created file %s"
-msgstr "không thể tạo “kho lưu đằng sau†cho tập tin được tạo mới hơn %s"
+msgstr "không thể tạo 'backing store' cho tập tin mới tạo %s"
#, c-format
msgid "unable to add cache entry for %s"
@@ -1063,19 +1166,19 @@ msgstr "không thể thêm mục nhớ đệm cho %s"
#, c-format
msgid "failed to write to '%s'"
-msgstr "gặp lá»—i khi ghi vào “%sâ€"
+msgstr "gặp lỗi khi ghi vào '%s'"
#, c-format
msgid "closing file '%s'"
-msgstr "Ä‘ang đóng tập tin “%sâ€"
+msgstr "đang đóng tập tin '%s'"
#, c-format
msgid "unable to write file '%s' mode %o"
-msgstr "không thể ghi vào tập tin “%s†chế độ %o"
+msgstr "không thể ghi vào tập tin '%s' chế độ %o"
#, c-format
msgid "Applied patch %s cleanly."
-msgstr "Äã áp dụng miếng vá %s má»™t cách sạch sẽ."
+msgstr "Äã áp dụng bản vá %s má»™t cách hoàn toàn."
msgid "internal error"
msgstr "lá»—i ná»™i bá»™"
@@ -1083,43 +1186,43 @@ msgstr "lá»—i ná»™i bá»™"
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
-msgstr[0] "Äang áp dụng miếng vá %%s vá»›i %d lần từ chối…"
+msgstr[0] "Äang áp dụng bản vá %%s vá»›i %d lần từ chối..."
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "đang cắt ngắn tên tập tin .rej thành %.*s.rej"
+msgid "cannot open %s"
+msgstr "không thể mở '%s'"
#, c-format
-msgid "cannot open %s"
-msgstr "không mở được “%sâ€"
+msgid "cannot unlink '%s'"
+msgstr "không thể unlink '%s'"
#, c-format
msgid "Hunk #%d applied cleanly."
-msgstr "Khối nhá»› #%d được áp dụng gá»n gàng."
+msgstr "Khúc #%d được áp dụng hoàn toàn."
#, c-format
msgid "Rejected hunk #%d."
-msgstr "Äoạn dữ liệu #%d bị từ chối."
+msgstr "Khúc #%d bị từ chối."
#, c-format
msgid "Skipped patch '%s'."
-msgstr "Bá» qua đưá»ng dẫn “%sâ€."
+msgstr "Bá» qua đưá»ng dẫn '%s'."
msgid "No valid patches in input (allow with \"--allow-empty\")"
msgstr ""
-"Không có miếng vá hợp lệ nào trong đầu vào (cho phép với \"--allow-empty\")"
+"Không có bản vá hợp lệ nào trong đầu vào (cho phép với \"--allow-empty\")"
msgid "unable to read index file"
-msgstr "không thể Ä‘á»c tập tin lưu bảng mục lục"
+msgstr "không thể Ä‘á»c tập tin chỉ mục"
#, c-format
msgid "can't open patch '%s': %s"
-msgstr "không thể mở miếng vá “%sâ€: %s"
+msgstr "không thể mở bản vá '%s': %s"
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
-msgstr[0] "đã chấm dứt %d lỗi khoảng trắng"
+msgstr[0] "đã xử lý %d lỗi khoảng trắng"
#, c-format
msgid "%d line adds whitespace errors."
@@ -1132,7 +1235,7 @@ msgid_plural "%d lines applied after fixing whitespace errors."
msgstr[0] "%d dòng được áp dụng sau khi sửa các lỗi khoảng trắng."
msgid "Unable to write new index file"
-msgstr "Không thể ghi tập tin lưu bảng mục lục mới"
+msgstr "Không thể ghi tập tin chỉ mục mới"
msgid "don't apply changes matching the given path"
msgstr "không áp dụng các thay đổi khá»›p vá»›i đưá»ng dẫn đã cho"
@@ -1144,52 +1247,55 @@ msgid "num"
msgstr "số"
msgid "remove <num> leading slashes from traditional diff paths"
-msgstr "gỡ bá» <số> dấu gạch chéo dẫn đầu từ đưá»ng dẫn diff cổ Ä‘iển"
+msgstr "gỡ bá» <số> dấu gạch chéo dẫn đầu từ đưá»ng dẫn diff"
msgid "ignore additions made by the patch"
-msgstr "lỠđi phần bổ xung được tạo ra bởi miếng vá"
+msgstr "bỠqua các bổ sung trong bản vá"
msgid "instead of applying the patch, output diffstat for the input"
-msgstr ""
-"thay vì áp dụng một miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra"
+msgstr "thay vì áp dụng bản vá, xuất kết quả diffstat cho đầu vào"
msgid "show number of added and deleted lines in decimal notation"
-msgstr ""
-"hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân"
+msgstr "hiển thị số lượng các dòng được thêm vào và xóa đi theo hệ thập phân"
msgid "instead of applying the patch, output a summary for the input"
-msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả cho đầu vào"
+msgstr "thay vì áp dụng bản vá, xuất tóm tắt kết quả cho đầu vào"
msgid "instead of applying the patch, see if the patch is applicable"
-msgstr "thay vì áp dụng miếng vá, hãy xem xem miếng vá có thích hợp không"
+msgstr "thay vì áp dụng bản vá, xem xem bản vá có thích hợp không"
msgid "make sure the patch is applicable to the current index"
-msgstr "hãy chắc chắn là miếng vá thích hợp với bảng mục lục hiện hành"
+msgstr "kiểm tra chắc chắn là bản vá thích hợp với chỉ mục hiện hành"
msgid "mark new files with `git add --intent-to-add`"
-msgstr "đánh dấu các tập tin má»›i vá»›i “git add --intent-to-addâ€"
+msgstr "đánh dấu các tập tin mới với 'git add --intent-to-add'"
msgid "apply a patch without touching the working tree"
-msgstr "áp dụng một miếng vá mà không động chạm đến cây làm việc"
+msgstr "áp dụng bản vá mà không động chạm đến cây làm việc"
msgid "accept a patch that touches outside the working area"
-msgstr "chấp nhận một miếng vá mà không động chạm đến cây làm việc"
+msgstr "chấp nhận bản vá có động chạm đến ngoài cây làm việc"
msgid "also apply the patch (use with --stat/--summary/--check)"
-msgstr ""
-"đồng thá»i áp dụng miếng vá (dùng vá»›i tùy chá»n --stat/--summary/--check)"
+msgstr "đồng thá»i áp dụng bản vá (dùng vá»›i tùy chá»n --stat/--summary/--check)"
msgid "attempt three-way merge, fall back on normal patch if that fails"
-msgstr ""
-"thá»­ hòa trá»™n kiểu three-way, quay lại dán bình thưá»ng nếu không thể thá»±c "
-"hiện được"
+msgstr "thá»­ hòa trá»™n kiểu three-way, quay lại kiểu bình thưá»ng nếu thất bại"
+
+msgid "for conflicts, use our version"
+msgstr "nếu xung đột, sử dụng phiên bản của ta"
+
+msgid "for conflicts, use their version"
+msgstr "nếu xung đột, sá»­ dụng phiên bản cá»§a há»"
+
+msgid "for conflicts, use a union version"
+msgstr "nếu xung đột, sử dụng phiên bản kết hợp"
msgid "build a temporary index based on embedded index information"
-msgstr ""
-"xây dá»±ng bảng mục lục tạm thá»i trên cÆ¡ sở thông tin bảng mục lục được nhúng"
+msgstr "xây dá»±ng chỉ mục tạm thá»i dá»±a trên thông tin chỉ mục được nhúng"
msgid "paths are separated with NUL character"
-msgstr "các đưá»ng dẫn bị ngăn cách bởi ký tá»± NULL"
+msgstr "các đưá»ng dẫn được ngăn cách bởi ký tá»± NULL"
msgid "ensure at least <n> lines of context match"
msgstr "đảm bảo rằng có ít nhất <n> dòng ngữ cảnh khớp"
@@ -1198,22 +1304,22 @@ msgid "action"
msgstr "hành động"
msgid "detect new or modified lines that have whitespace errors"
-msgstr "tìm thấy một dòng mới hoặc bị sửa đổi mà nó có lỗi do khoảng trắng"
+msgstr "tìm thấy dòng mới hoặc dòng bị sửa đổi có lỗi khoảng trắng"
msgid "ignore changes in whitespace when finding context"
-msgstr "lỠđi sự thay đổi do khoảng trắng gây ra khi tìm ngữ cảnh"
+msgstr "bỠqua sự thay đổi do khoảng trắng gây ra khi tìm ngữ cảnh"
msgid "apply the patch in reverse"
-msgstr "áp dụng miếng vá theo chiá»u ngược"
+msgstr "áp dụng bản vá theo chiá»u ngược"
msgid "don't expect at least one line of context"
msgstr "đừng hy vá»ng có ít nhất má»™t dòng ngữ cảnh"
msgid "leave the rejected hunks in corresponding *.rej files"
-msgstr "để lại khối dữ liệu bị từ chối trong các tập tin *.rej tương ứng"
+msgstr "để lại khối bị từ chối trong các tập tin *.rej tương ứng"
msgid "allow overlapping hunks"
-msgstr "cho phép chồng khối nhớ"
+msgstr "cho phép chồng khối"
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr ""
@@ -1226,65 +1332,72 @@ msgid "root"
msgstr "gốc"
msgid "prepend <root> to all filenames"
-msgstr "treo thêm <root> vào tất cả các tên tập tin"
+msgstr "thêm <gốc> vào trước tất cả các tên tập tin"
msgid "don't return error for empty patches"
-msgstr "đừng trả vỠlỗi khi các miếng vá trống rỗng"
+msgstr "đừng trả vỠlỗi khi các bản vá trống rỗng"
+
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, và --union cần tuỳ chá»n --3way"
#, c-format
msgid "cannot stream blob %s"
-msgstr "không thể stream blob “%sâ€"
+msgstr "không thể stream blob '%s'"
#, c-format
msgid "unsupported file mode: 0%o (SHA1: %s)"
msgstr "chế độ tập tin không được hỗ trợ: 0%o (SHA1: %s)"
#, c-format
+msgid "deflate error (%d)"
+msgstr "lỗi giải nén (%d)"
+
+#, c-format
msgid "unable to start '%s' filter"
-msgstr "không thể bắt đầu bá»™ lá»c “%sâ€"
+msgstr "không thể khởi chạy bá»™ lá»c '%s'"
msgid "unable to redirect descriptor"
-msgstr "không thể chuyển hướng mô tả"
+msgstr "không thể chuyển hướng vào/ra"
#, c-format
msgid "'%s' filter reported error"
-msgstr "bá»™ lá»c “%s†đã báo cáo lá»—i"
+msgstr "bá»™ lá»c '%s' đã báo lá»—i"
#, c-format
msgid "path is not valid UTF-8: %s"
-msgstr "đưá»ng dẫn không hợp lệ UTF-8: %s"
+msgstr "đưá»ng dẫn không hợp lệ theo UTF-8: %s"
#, c-format
msgid "path too long (%d chars, SHA1: %s): %s"
msgstr "đưá»ng dẫn quá dài (%d ký tá»±, SHA1: %s): %s"
#, c-format
-msgid "deflate error (%d)"
-msgstr "lỗi giải nén (%d)"
-
-#, c-format
msgid "timestamp too large for this system: %<PRIuMAX>"
-msgstr "dấu vết thá»i gian là quá lá»›n cho hệ thống này: %<PRIuMAX>"
+msgstr "dấu thá»i gian là quá lá»›n cho hệ thống này: %<PRIuMAX>"
msgid "git archive [<options>] <tree-ish> [<path>...]"
-msgstr "git archive [<các tùy chá»n>] <tree-ish> [</đưá»ng/dẫn>…]"
+msgstr "git archive [<các tùy chá»n>] <tree-ish> [</đưá»ng/dẫn>...]"
msgid ""
"git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
msgstr ""
"git archive --remote <kho> [--exec <lệnh>] [<các tùy chá»n>] <tree-ish> [</"
-"đưá»ng/dẫn>…]"
+"đưá»ng/dẫn>...]"
msgid "git archive --remote <repo> [--exec <cmd>] --list"
msgstr "git archive --remote <kho> [--exec <lệnh>] --list"
#, c-format
msgid "cannot read '%s'"
-msgstr "không thể Ä‘á»c “%sâ€"
+msgstr "không thể Ä‘á»c '%s'"
+
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr "đặc tả đưá»ng dẫn '%s' nằm ngoài thư mục hiện hành"
#, c-format
msgid "pathspec '%s' did not match any files"
-msgstr "đặc tả đưá»ng dẫn “%s†không khá»›p vá»›i bất kỳ tập tin nào"
+msgstr "đặc tả đưá»ng dẫn '%s' không khá»›p vá»›i bất kỳ tập tin nào"
#, c-format
msgid "no such ref: %.*s"
@@ -1292,14 +1405,15 @@ msgstr "không có tham chiếu nào như thế: %.*s"
#, c-format
msgid "not a valid object name: %s"
-msgstr "không phải là tên đối tượng hợp lệ: “%sâ€"
+msgstr "không phải là tên đối tượng hợp lệ: %s"
#, c-format
msgid "not a tree object: %s"
-msgstr "không phải là đối tượng cây: “%sâ€"
+msgstr "không phải là đối tượng cây: %s"
-msgid "current working directory is untracked"
-msgstr "thư mục làm việc hiện hành chưa được theo dõi"
+#, c-format
+msgid "failed to unpack tree object %s"
+msgstr "gặp lỗi khi giải nén đối tượng cây %s"
#, c-format
msgid "File not found: %s"
@@ -1307,7 +1421,7 @@ msgstr "Không tìm thấy tập tin: %s"
#, c-format
msgid "Not a regular file: %s"
-msgstr "Không phải má»™t tập tin thưá»ng: %s"
+msgstr "Không phải tập tin thưá»ng: %s"
#, c-format
msgid "unclosed quote: '%s'"
@@ -1315,26 +1429,26 @@ msgstr "chưa có dấu nháy đóng: '%s'"
#, c-format
msgid "missing colon: '%s'"
-msgstr "thiếu dấu hai chấm: “%sâ€"
+msgstr "thiếu dấu hai chấm: '%s'"
#, c-format
msgid "empty file name: '%s'"
-msgstr "tên tập tin trống rá»—ng: “%sâ€"
+msgstr "tên tập tin trống: '%s'"
msgid "fmt"
-msgstr "định_dạng"
+msgstr "định-dạng"
msgid "archive format"
msgstr "định dạng lưu trữ"
msgid "prefix"
-msgstr "tiá»n_tố"
+msgstr "tiá»n tố"
msgid "prepend prefix to each pathname in the archive"
msgstr "nối thêm tiá»n tố vào từng đưá»ng dẫn tập tin trong kho lưu"
msgid "file"
-msgstr "tập_tin"
+msgstr "tập tin"
msgid "add untracked file to archive"
msgstr "thêm các tập tin không được theo dõi vào kho lưu"
@@ -1349,7 +1463,13 @@ msgid "read .gitattributes in working directory"
msgstr "Ä‘á»c .gitattributes trong thư mục làm việc"
msgid "report archived files on stderr"
-msgstr "liệt kê các tập tin được lưu trữ vào stderr (đầu ra lỗi tiêu chuẩn)"
+msgstr "liệt kê các tập tin được lưu trữ ra stderr"
+
+msgid "time"
+msgstr "thá»i-gian"
+
+msgid "set modification time of archive entries"
+msgstr "đặt thá»i Ä‘iểm sá»­a đổi cá»§a các mục nén"
msgid "set compression level"
msgstr "đặt mức nén"
@@ -1370,27 +1490,38 @@ msgid "path to the remote git-upload-archive command"
msgstr "đưá»ng dẫn đến lệnh git-upload-archive trên máy chá»§"
msgid "Unexpected option --remote"
-msgstr "Gặp tùy chá»n không cần --remote"
+msgstr "Gặp tùy chá»n bất thưá»ng --remote"
#, c-format
msgid "the option '%s' requires '%s'"
-msgstr "tùy chá»n “%s†yêu cầu “%sâ€"
+msgstr "tùy chá»n '%s' yêu cầu '%s'"
msgid "Unexpected option --output"
-msgstr "Gặp tùy chá»n không cần --output"
+msgstr "Gặp tùy chá»n bất thưá»ng --output"
+
+#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "thừa tham số dòng lệnh '%s'"
#, c-format
msgid "Unknown archive format '%s'"
-msgstr "Không hiểu định dạng “%sâ€"
+msgstr "Không hiểu định dạng lưu trữ '%s'"
#, c-format
msgid "Argument not supported for format '%s': -%d"
-msgstr "Tham số không được há»— trợ cho định dạng “%sâ€: -%d"
+msgstr "Tham số không được hỗ trợ cho định dạng '%s': -%d"
#, c-format
msgid "%.*s is not a valid attribute name"
msgstr "%.*s không phải tên thuộc tính hợp lệ"
+msgid "unable to add additional attribute"
+msgstr "Không thể thêm thuộc tính"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "bỠqua dòng thuộc tính thứ %d quá dài"
+
#, c-format
msgid "%s not allowed: %s:%d"
msgstr "%s không được phép: %s:%d"
@@ -1399,16 +1530,42 @@ msgid ""
"Negative patterns are ignored in git attributes\n"
"Use '\\!' for literal leading exclamation."
msgstr ""
-"Các mẫu dạng phủ định bị cấm dùng cho các thuộc tính của git\n"
-"Dùng “\\!†cho các chuỗi văn bản có dấu chấm than dẫn đầu."
+"Các mẫu dạng phủ định bị cấm dùng cho git attribute\n"
+"Dùng '\\!' cho tên có dấu chấm than dẫn đầu."
+
+#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "không thể fstat tập tin gitattributes '%s'"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "bỠqua tập tin gitattributes quá lớn '%s'"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "bỠqua blob gitattributes quá lớn '%s'"
+
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "không thể dùng --attr-source hoặc GIT_ATTR_SOURCE mà không có kho chứa"
+
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "--attr-source hoặc GIT_ATTR_SOURCE sai"
+
+#, c-format
+msgid "unable to stat '%s'"
+msgstr "không thể stat '%s'"
+
+#, c-format
+msgid "unable to read %s"
+msgstr "không thể Ä‘á»c %s"
#, c-format
msgid "Badly quoted content in file '%s': %s"
-msgstr "Ná»™i dung được trích dẫn sai trong tập tin “%sâ€: %s"
+msgstr "Nội dung được trích dẫn sai trong tập tin '%s': %s"
#, c-format
msgid "We cannot bisect more!\n"
-msgstr "Chúng tôi không bisect thêm nữa!\n"
+msgstr "Không bisect thêm nữa!\n"
#, c-format
msgid "Not a valid commit name %s"
@@ -1419,16 +1576,16 @@ msgid ""
"The merge base %s is bad.\n"
"This means the bug has been fixed between %s and [%s].\n"
msgstr ""
-"Hòa trộn trên %s là sai.\n"
-"Äiá»u đó có nghÄ©a là lá»—i đã được sá»­a chữa giữa %s và [%s].\n"
+"Gốc hòa trộn trên %s là sai.\n"
+"Có nghĩa là lỗi đã được sửa chữa giữa %s và [%s].\n"
#, c-format
msgid ""
"The merge base %s is new.\n"
"The property has changed between %s and [%s].\n"
msgstr ""
-"Hòa trộn trên %s là mới.\n"
-"Gần như chắc chắn là có thay đổi giữa %s và [%s].\n"
+"Gốc hòa trộn trên %s là mới.\n"
+"Äã có thay đổi thuá»™c tính giữa %s và [%s].\n"
#, c-format
msgid ""
@@ -1436,7 +1593,7 @@ msgid ""
"This means the first '%s' commit is between %s and [%s].\n"
msgstr ""
"Hòa trộn trên %s là %s.\n"
-"Äiá»u đó có nghÄ©a là lần chuyển giao “%s†đầu tiên là giữa %s và [%s].\n"
+"Có nghĩa là lần chuyển giao '%s' đầu tiên là giữa %s và [%s].\n"
#, c-format
msgid ""
@@ -1445,7 +1602,7 @@ msgid ""
"Maybe you mistook %s and %s revs?\n"
msgstr ""
"Một số điểm xét duyệt %s không phải tổ tiên của điểm xét duyệt %s.\n"
-"git bisect không thể làm việc đúng đắn trong trưá»ng hợp này.\n"
+"git bisect không thể làm việc đúng trong trưá»ng hợp này.\n"
"Liệu có phải bạn nhầm lẫn các điểm %s và %s không?\n"
#, c-format
@@ -1454,14 +1611,13 @@ msgid ""
"So we cannot be sure the first %s commit is between %s and %s.\n"
"We continue anyway."
msgstr ""
-"hòa trộn trên cơ sở giữa %s và [%s] phải bị bỠqua.\n"
-"Do vậy chúng tôi không thể chắc lần chuyển giao đầu tiên %s là giữa %s và "
-"%s.\n"
-"Chúng tôi vẫn cứ tiếp tục."
+"gốc hòa trộn giữa %s và [%s] phải bị bỠqua.\n"
+"Do vậy không thể chắc chắn lần chuyển giao %s đầu tiên là giữa %s và %s.\n"
+"Vẫn tiếp tục."
#, c-format
msgid "Bisecting: a merge base must be tested\n"
-msgstr "Bisecting: ná»n hòa trá»™n cần phải được kiểm tra\n"
+msgstr "Äang bisect: gốc hòa trá»™n cần phải được kiểm tra\n"
#, c-format
msgid "a %s revision is needed"
@@ -1469,11 +1625,15 @@ msgstr "cần một điểm xét duyệt %s"
#, c-format
msgid "could not create file '%s'"
-msgstr "không thể tạo tập tin “%sâ€"
+msgstr "không thể tạo tập tin '%s'"
+
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "không thể khởi chạy 'show' cho đối tượng '%s'"
#, c-format
msgid "could not read file '%s'"
-msgstr "không thể Ä‘á»c tập tin “%sâ€"
+msgstr "không thể Ä‘á»c tập tin '%s'"
msgid "reading bisect refs failed"
msgstr "việc Ä‘á»c tham chiếu bisect gặp lá»—i"
@@ -1487,13 +1647,13 @@ msgid ""
"No testable commit found.\n"
"Maybe you started with bad path arguments?\n"
msgstr ""
-"Không tìm thấy lần chuyển giao kiểm tra được nào.\n"
+"Không tìm thấy lần chuyển giao nào kiểm tra được.\n"
"Có lẽ bạn bắt đầu vá»›i các tham số đưá»ng dẫn sai?\n"
#, c-format
msgid "(roughly %d step)"
msgid_plural "(roughly %d steps)"
-msgstr[0] "(ước chừng %d bước)"
+msgstr[0] "(cần khoảng chừng %d bước)"
#. TRANSLATORS: the last %s will be replaced with "(roughly %d
#. steps)" translation.
@@ -1501,13 +1661,10 @@ msgstr[0] "(ước chừng %d bước)"
#, 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] "Bisecting: còn %d điểm xét duyệt để kiểm sau %s này\n"
+msgstr[0] "Bisecting: còn %d điểm xét duyệt để kiểm tra %s\n"
msgid "--contents and --reverse do not blend well."
-msgstr "tùy chá»n --contents và --reverse không được trá»™n vào nhau."
-
-msgid "cannot use --contents with final commit object name"
-msgstr "không thể dùng --contents với tên đối tượng chuyển giao cuối cùng"
+msgstr "tùy chá»n --contents và --reverse không nên Ä‘i vá»›i nhau."
msgid "--reverse and --first-parent together require specified latest commit"
msgstr ""
@@ -1519,16 +1676,16 @@ msgstr "cài đặt việc di chuyển qua các điểm xét duyệt gặp lỗi
msgid ""
"--reverse --first-parent together require range along first-parent chain"
msgstr ""
-"cùng sử dụng --reverse --first-parent yêu cầu vùng cùng với chuỗi cha-mẹ-đầu-"
-"tiên"
+"cùng sử dụng --reverse và --first-parent yêu cầu vùng cùng với chuỗi cha-mẹ-"
+"đầu-tiên"
#, c-format
msgid "no such path %s in %s"
-msgstr "không có đưá»ng dẫn %s trong “%sâ€"
+msgstr "không có đưá»ng dẫn %s trong '%s'"
#, c-format
msgid "cannot read blob %s for path %s"
-msgstr "không thể Ä‘á»c blob %s cho đưá»ng dẫn “%sâ€"
+msgstr "không thể Ä‘á»c blob %s cho đưá»ng dẫn '%s'"
msgid ""
"cannot inherit upstream tracking configuration of multiple refs when "
@@ -1539,19 +1696,19 @@ msgstr ""
#, c-format
msgid "not setting branch '%s' as its own upstream"
-msgstr "không cài đặt nhánh '%s' như là thượng nguồn của nó"
+msgstr "không đặt nhánh '%s' là thượng nguồn của chính nó"
#, c-format
msgid "branch '%s' set up to track '%s' by rebasing."
-msgstr "nhánh “%s†cài đặt để theo dõi “%s†bằng cách rebase."
+msgstr "nhánh '%s' cài đặt để theo dõi '%s' bằng cách rebase."
#, c-format
msgid "branch '%s' set up to track '%s'."
-msgstr "nhánh “%s†cài đặt để theo dõi “%sâ€."
+msgstr "nhánh '%s' cài đặt để theo dõi '%s'."
#, c-format
msgid "branch '%s' set up to track:"
-msgstr "nhánh “%s†cài đặt để theo dõi:"
+msgstr "nhánh '%s' cài đặt để theo dõi:"
msgid "unable to write upstream branch configuration"
msgstr "không thể ghi cấu hình nhánh thượng nguồn"
@@ -1562,19 +1719,17 @@ msgid ""
"the remote tracking information by invoking:"
msgstr ""
"\n"
-"Sau khi sửa nguyên nhân gây lỗi bạn có lẻ cần thử sửa\n"
+"Sau khi sửa nguyên nhân gây lỗi bạn có thể thử sửa\n"
"thông tin theo dõi máy chá»§ bằng cách gá»i lệnh:"
#, c-format
msgid "asked to inherit tracking from '%s', but no remote is set"
-msgstr ""
-"đã há»i để kế thừa theo dõi từ '%s', nhưng không có máy chá»§ nào được đặt"
+msgstr "đã yêu cầu kế thừa theo dõi từ '%s', nhưng chưa cấu hình máy chủ nào"
#, c-format
msgid "asked to inherit tracking from '%s', but no merge configuration is set"
msgstr ""
-"đã há»i để kế thừa theo dõi từ '%s', nhưng không có cấu hình hòa trá»™n nào "
-"được đặt"
+"đã yêu cầu kế thừa theo dõi từ '%s', nhưng không có cấu hình hòa trộn nào"
#, c-format
msgid "not tracking: ambiguous information for ref '%s'"
@@ -1609,8 +1764,8 @@ msgid ""
"different remotes' fetch refspecs map into different\n"
"tracking namespaces."
msgstr ""
-"Có nhiá»u máy chá»§ những cái lấy ánh xạ refspecs tham chiếu theo\n"
-"dõi máy chủ '%s':\n"
+"Có nhiá»u máy chá»§ có fetch refspec ánh xạ tá»›i refspecs tham chiếu\n"
+"theo dõi máy chủ '%s':\n"
"%s\n"
"Äây thưá»ng là lá»—i cấu hình.\n"
"\n"
@@ -1620,25 +1775,29 @@ msgstr ""
#, c-format
msgid "'%s' is not a valid branch name"
-msgstr "“%s†không phải là một tên nhánh hợp lệ"
+msgstr "'%s' không phải là một tên nhánh hợp lệ"
+
+msgid "See `man git check-ref-format`"
+msgstr "Äá»c `man git check-ref-format`"
#, c-format
msgid "a branch named '%s' already exists"
-msgstr "đã có nhánh mang tên “%sâ€"
+msgstr "đã có nhánh mang tên '%s'"
#, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "không thể ép buá»™c cập nhật nhánh “%s†đã được lấy ra tại “%sâ€"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr ""
+"không thể ép buộc cập nhật nhánh '%s' đang được sử dụng tại cây làm việc '%s'"
#, c-format
msgid "cannot set up tracking information; starting point '%s' is not a branch"
msgstr ""
-"không thể cài đặt thông tin theo dõi; điểm bắt đầu “%s†không phải là một "
+"không thể cài đặt thông tin theo dõi; điểm bắt đầu '%s' không phải là một "
"nhánh"
#, c-format
msgid "the requested upstream branch '%s' does not exist"
-msgstr "nhánh thượng nguồn đã yêu cầu “%s†không tồn tại"
+msgstr "nhánh thượng nguồn đã yêu cầu '%s' không tồn tại"
msgid ""
"\n"
@@ -1651,95 +1810,76 @@ msgid ""
"\"git push -u\" to set the upstream config as you push."
msgstr ""
"\n"
-"Nếu bạn có ý định “cải tổ†công việc của bạn trên nhánh thượng nguồn\n"
-"(upstream) cái mà đã sẵn có trên máy chủ, bạn cần chạy\n"
+"Nếu bạn có ý định bắt đầu công việc của bạn trên nhánh thượng nguồn\n"
+"(upstream) đã sẵn có trên máy chủ, bạn cần chạy\n"
"lệnh \"git fetch\" để lấy nó vá».\n"
"\n"
-"Nếu bạn có ý định đẩy lên lên một nhánh nội bộ mới cái mà\n"
-"sẽ theo dõi bản đối chiếu máy chủ của nó, bạn cần dùng lệnh\n"
-"\"git push -u\" để đặt cấu hình thượng nguồn bạn muốn push."
+"Nếu bạn có ý định đẩy một nhánh nội bộ mới mà\n"
+"sẽ theo dõi nhánh trên máy chủ, bạn cần dùng lệnh\n"
+"\"git push -u\" để đặt cấu hình thượng nguồn khi push."
#, c-format
msgid "not a valid object name: '%s'"
-msgstr "không phải là tên đối tượng hợp lệ: “%sâ€"
+msgstr "không phải là tên đối tượng hợp lệ: '%s'"
#, c-format
msgid "ambiguous object name: '%s'"
-msgstr "tên đối tượng chưa rõ ràng: “%sâ€."
+msgstr "tên đối tượng chưa rõ ràng: '%s'."
#, c-format
msgid "not a valid branch point: '%s'"
-msgstr "không phải là má»™t Ä‘iểm nhánh hợp lệ: “%sâ€"
+msgstr "không phải là một điểm nhánh hợp lệ: '%s'"
#, c-format
msgid "submodule '%s': unable to find submodule"
-msgstr "mô-Ä‘un-con “%sâ€: không thể tìm thấy mô-Ä‘un-con"
+msgstr "mô-đun-con '%s': không thể tìm thấy mô-đun-con"
#, 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 ""
-"Bạn có thể thử cập nhật các mô-đun-con bằng cách sử dụng 'git checkout %s && "
-"git submodule update --init'"
+"Bạn có thể thử cập nhật các mô-đun-con bằng cách sử dụng 'git checkout --no-"
+"recurse-submodules %s && git submodule update --init'"
#, c-format
msgid "submodule '%s': cannot create branch '%s'"
-msgstr "mô-Ä‘un-con “%sâ€: không thể tạo nhánh “%sâ€"
+msgstr "mô-đun-con '%s': không thể tạo nhánh '%s'"
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "“%s†đã được lấy ra tại “%s†rồi"
-
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "HEAD của cây làm việc %s chưa được cập nhật"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "'%s' đang được sử dụng tại cây làm việc '%s'"
msgid "git add [<options>] [--] <pathspec>..."
-msgstr "git add [<các tùy chá»n>] [--] <pathspec>…"
+msgstr "git add [<các tùy chá»n>] [--] <pathspec>..."
#, c-format
msgid "cannot chmod %cx '%s'"
-msgstr "không thể chmod %cx “%sâ€"
-
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "trạng thái lệnh diff không như mong đợi %c"
-
-msgid "updating files failed"
-msgstr "cập nhật tập tin gặp lỗi"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "gỡ bỠ“%sâ€\n"
+msgstr "không thể chmod %cx '%s'"
msgid "Unstaged changes after refreshing the index:"
-msgstr ""
-"ÄÆ°a ra khá»i bệ phóng các thay đổi sau khi làm tươi má»›i lại bảng mục lục:"
+msgstr "ÄÆ°a ra khá»i vùng chá» các thay đổi sau khi làm má»›i lại chỉ mục:"
-msgid "Could not read the index"
-msgstr "Không thể Ä‘á»c bảng mục lục"
-
-msgid "Could not write patch"
-msgstr "Không thể ghi ra miếng vá"
+msgid "could not read the index"
+msgstr "Không thể Ä‘á»c chỉ mục"
msgid "editing patch failed"
-msgstr "gặp lỗi khi sửa miếng vá"
+msgstr "gặp lỗi khi sửa bản vá"
#, c-format
-msgid "Could not stat '%s'"
-msgstr "Không thể lấy thông tin thống kê vỠ“%sâ€"
+msgid "could not stat '%s'"
+msgstr "không thể stat '%s'"
-msgid "Empty patch. Aborted."
-msgstr "Miếng vá trống rỗng. Nên bỠqua."
+msgid "empty patch. aborted"
+msgstr "bản vá trống rá»—ng. huá»· bá»"
#, c-format
-msgid "Could not apply '%s'"
-msgstr "Không thể áp dụng miếng vá “%sâ€"
+msgid "could not apply '%s'"
+msgstr "không thể áp dụng bản vá '%s'"
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
-"Các đưá»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các tập tin .gitignore "
+"Các đưá»ng dẫn theo sau đây sẽ bị bá» qua bởi má»™t trong các tập tin .gitignore "
"của bạn:\n"
msgid "dry run"
@@ -1752,7 +1892,7 @@ msgid "interactive picking"
msgstr "sửa bằng cách tương tác"
msgid "select hunks interactively"
-msgstr "chá»n “hunks†theo kiểu tương tác"
+msgstr "chá»n 'hunks' theo kiểu tương tác"
msgid "edit current diff and apply"
msgstr "sửa diff hiện nay và áp dụng nó"
@@ -1764,22 +1904,19 @@ msgid "update tracked files"
msgstr "cập nhật các tập tin được theo dõi"
msgid "renormalize EOL of tracked files (implies -u)"
-msgstr "thưá»ng hóa lại EOL cá»§a các tập tin được theo dõi (ý là -u)"
+msgstr "thưá»ng hóa lại EOL cá»§a các tập tin được theo dõi (ngụ ý -u)"
msgid "record only the fact that the path will be added later"
msgstr "chỉ ghi lại sá»± việc mà đưá»ng dẫn sẽ được thêm vào sau"
msgid "add changes from all tracked and untracked files"
-msgstr ""
-"thêm các thay đổi từ tất cả các tập tin có cũng như không được theo dõi dấu "
-"vết"
+msgstr "thêm các thay đổi từ tất cả các tập tin dù được theo dõi hay không"
msgid "ignore paths removed in the working tree (same as --no-all)"
-msgstr ""
-"lá» Ä‘i các đưá»ng dẫn bị gỡ bá» trong cây thư mục làm việc (giống vá»›i --no-all)"
+msgstr "bá» qua các đưá»ng dẫn bị xoá bá» trong cây làm việc (giống vá»›i --no-all)"
msgid "don't add, only refresh the index"
-msgstr "không thêm, chỉ làm tươi mới bảng mục lục"
+msgstr "không thêm, chỉ làm mới chỉ mục"
msgid "just skip files which cannot be added because of errors"
msgstr "chie bỠqua những tập tin mà nó không thể được thêm vào bởi vì gặp lỗi"
@@ -1789,10 +1926,11 @@ msgstr ""
"kiểm tra xem - thậm chí thiếu - tập tin bị bỠqua trong quá trình chạy thử"
msgid "allow updating entries outside of the sparse-checkout cone"
-msgstr "cho phép cập nhật các mục ở ngoài “sparse-checkout coneâ€"
+msgstr ""
+"cho phép cập nhật các mục ở ngoài 'sparse-checkout cone' (nón checkout thưa)"
msgid "override the executable bit of the listed files"
-msgstr "ghi đè lên bít thi hành của các tập tin được liệt kê"
+msgstr "ghi đè lên executable bit (bít thực thi) của các tập tin được liệt kê"
msgid "warn when adding an embedded repository"
msgstr "cảnh báo khi thêm một kho nhúng"
@@ -1820,8 +1958,8 @@ msgstr ""
"\n"
"\tgit submodule add <url> %s\n"
"\n"
-"Nếu bạn đã thêm miếng vá này chỉ là sai sót, bạn có thể xóa bá»\n"
-"nó khá»i mục lục bằng:\n"
+"Nếu bạn đã thêm bản vá này chỉ là sai sót, bạn có thể xóa bá»\n"
+"nó khá»i chỉ mục bằng:\n"
"\n"
"\tgit rm --cached %s\n"
"\n"
@@ -1831,21 +1969,15 @@ msgstr ""
msgid "adding embedded git repository: %s"
msgstr "thêm cần một kho git nhúng: %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 ""
-"Sử dụng -f nếu bạn thực sự muốn thêm chúng.\n"
-"Tắt thông báo này bằng cách chạy lệnh\n"
-"\"git config advice.addIgnoredFile false\""
+msgid "Use -f if you really want to add them."
+msgstr "Dùng -f nếu bạn thực sự muốn thêm chúng"
msgid "adding files failed"
msgstr "thêm tập tin gặp lỗi"
#, c-format
msgid "--chmod param '%s' must be either -x or +x"
-msgstr "--chmod tham số “%s†phải hoặc là -x hay +x"
+msgstr "--chmod tham số '%s' phải hoặc là -x hay +x"
#, c-format
msgid "'%s' and pathspec arguments cannot be used together"
@@ -1855,21 +1987,18 @@ msgstr "'%s' và các tham số đặc tả đưá»ng dẫn không thể dùng c
msgid "Nothing specified, nothing added.\n"
msgstr "Không có gì được chỉ ra, không có gì được thêm vào.\n"
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Có lẽ bạn muốn chạy “git add .�\n"
-"Tắt thông báo này bằng cách chạy lệnh\n"
-"\"git config advice.addEmptyPathspec false\""
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Có lẽ là bạn muốn dùng 'git add .'?"
msgid "index file corrupt"
-msgstr "tập tin ghi bảng mục lục bị há»ng"
+msgstr "tập tin ghi chỉ mục bị há»ng"
+
+msgid "unable to write new index file"
+msgstr "không thể ghi tập tin chỉ mục mới"
#, c-format
msgid "bad action '%s' for '%s'"
-msgstr "thao tác sai “%s†cho “%sâ€"
+msgstr "thao tác sai '%s' cho '%s'"
#, c-format
msgid "invalid value for '%s': '%s'"
@@ -1877,44 +2006,44 @@ msgstr "giá trị không hợp lệ cho '%s': '%s'"
#, c-format
msgid "could not read '%s'"
-msgstr "không thể Ä‘á»c “%sâ€"
+msgstr "không thể Ä‘á»c '%s'"
msgid "could not parse author script"
-msgstr "không thể phân tích cú pháp văn lệnh tác giả"
+msgstr "không hiểu cú pháp author script"
#, c-format
msgid "could not parse %s"
-msgstr "không thể phân tích cú pháp %s"
+msgstr "không hiểu cú pháp %s"
#, c-format
msgid "'%s' was deleted by the applypatch-msg hook"
-msgstr "“%s†bị xóa bởi móc applypatch-msg"
+msgstr "'%s' bị xóa bởi móc applypatch-msg"
#, c-format
msgid "Malformed input line: '%s'."
-msgstr "Dòng đầu vào dị hình: “%sâ€."
+msgstr "Dòng đầu vào sai quy cách: '%s'."
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
-msgstr "Gặp lá»—i khi sao chép ghi chú (note) từ “%s†tá»›i “%sâ€"
+msgstr "Gặp lỗi khi sao chép ghi chú (note) từ '%s' tới '%s'"
msgid "fseek failed"
msgstr "fseek gặp lỗi"
#, c-format
msgid "could not open '%s' for reading"
-msgstr "không thể mở “%s†để Ä‘á»c"
+msgstr "không thể mở '%s' để Ä‘á»c"
#, c-format
msgid "could not open '%s' for writing"
-msgstr "không thể mở “%s†để ghi"
+msgstr "không thể mở '%s' để ghi"
#, c-format
msgid "could not parse patch '%s'"
-msgstr "không thể phân tích cú pháp “%sâ€"
+msgstr "không hiểu cú pháp '%s'"
msgid "Only one StGIT patch series can be applied at once"
-msgstr "Chỉ có một sê-ri miếng vá StGIT được áp dụng một lúc"
+msgstr "Chỉ có một sê-ri bản vá StGIT được áp dụng một lúc"
msgid "invalid timestamp"
msgstr "dấu thá»i gian không hợp lệ"
@@ -1926,29 +2055,30 @@ msgid "invalid timezone offset"
msgstr "độ lệch múi giỠkhông hợp lệ"
msgid "Patch format detection failed."
-msgstr "Dò tìm định dạng miếng vá gặp lỗi."
+msgstr "Dò tìm định dạng bản vá gặp lỗi."
#, c-format
msgid "failed to create directory '%s'"
msgstr "tạo thư mục \"%s\" gặp lỗi"
msgid "Failed to split patches."
-msgstr "Gặp lỗi khi chia nhỠcác miếng vá."
+msgstr "Gặp lỗi khi chia nhỠcác bản vá."
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Khi bạn đã giải quyết xong trục trặc này, hãy chạy \"%s --continue\"."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr ""
+"Sau khi bạn đã giải quyết xong vấn Ä‘á», hãy chạy lệnh\"%s --continue\".\n"
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr ""
-"Nếu bạn muốn bỠqua miếng vá này, hãy chạy lệnh \"%s --skip\" để thay thế."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr "Nếu bạn muốn bỠqua bản vá này, hãy chạy lệnh \"%s --skip\".\n"
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
msgstr ""
-"Äể ghi má»™t miếng vá trống rá»—ng như má»™t lần chuyển giao rông, \"%s --allow-"
-"empty\"."
+"Äể ghi lại lần chuyển giao rá»—ng ứng vá»›i má»™t bản vá rá»—ng, hãy chạy \"%s --"
+"allow-empty\".\n"
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
@@ -1956,7 +2086,7 @@ msgstr "Äể phục hồi lại nhánh gốc và dừng vá, hãy chạy \"%s -
msgid "Patch sent with format=flowed; space at the end of lines might be lost."
msgstr ""
-"Miếng vá được gửi với format=flowed; khoảng trống ở cuối của các dòng có thể "
+"bản vá được gửi với format=flowed; khoảng trống ở cuối của các dòng có thể "
"bị mất."
#, c-format
@@ -1969,24 +2099,24 @@ msgstr "dòng định danh không hợp lệ: %.*s"
#, c-format
msgid "unable to parse commit %s"
-msgstr "không thể phân tích lần chuyển giao “%sâ€"
+msgstr "không thể Ä‘á»c lần chuyển giao '%s'"
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
-msgstr "Kho thiếu đối tượng blob cần thiết để thá»±c hiện “3-way mergeâ€."
+msgstr "Kho thiếu đối tượng blob cần thiết để thực hiện '3-way merge'."
msgid "Using index info to reconstruct a base tree..."
msgstr ""
-"Sử dụng thông tin trong bảng mục lục để cấu trúc lại một cây (tree) cơ sở…"
+"Sử dụng thông tin trong chỉ mục để cấu trúc lại một cây (tree) cơ sở..."
msgid ""
"Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."
msgstr ""
-"Bạn đã sửa miếng vá của mình bằng cách thủ công à?\n"
-"Nó không thể áp dụng các blob đã được ghi lại trong bảng mục lục của nó."
+"Bạn đã sửa bản vá của mình bằng cách thủ công à?\n"
+"Nó không thể áp dụng các blob đã được ghi lại trong chỉ mục của nó."
msgid "Falling back to patching base and 3-way merge..."
-msgstr "Äang dùng phương án dá»± phòng: vá bản cÆ¡ sở và “hòa trá»™n 3-đưá»ngâ€â€¦"
+msgstr "Äang dùng phương án dá»± phòng: vá bản cÆ¡ sở và 'hòa trá»™n 3-đưá»ng'..."
msgid "Failed to merge in the changes."
msgstr "Gặp lỗi khi trộn vào các thay đổi."
@@ -2014,15 +2144,16 @@ msgstr "Thân của lần chuyển giao là:"
#, c-format
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "
msgstr ""
-"Ãp dụng? đồng ý [y]/khô[n]g/chỉnh sá»­a [e]/hiển thị miếng [v]á/chấp nhận tất "
-"cả [a]: "
+"Ãp dụng? đồng ý [y]/không [n]/chỉnh sá»­a [e]/hiển thị bản vá [v]/chấp nhận "
+"tất cả [a]: "
msgid "unable to write index file"
-msgstr "không thể ghi tập tin lưu mục lục"
+msgstr "không thể ghi tập tin chỉ mục"
#, c-format
msgid "Dirty index: cannot apply patches (dirty: %s)"
-msgstr "Bảng mục lục bẩn: không thể áp dụng các miếng vá (bẩn: %s)"
+msgstr ""
+"chỉ mục không sạch sẽ: không thể áp dụng các bản vá (còn không sạch: %s)"
#, c-format
msgid "Skipping: %.*s"
@@ -2033,21 +2164,21 @@ msgid "Creating an empty commit: %.*s"
msgstr "Äang tạo má»™t lần chuyển giao trống rá»—ng: %.*s"
msgid "Patch is empty."
-msgstr "Miếng vá trống rỗng."
+msgstr "bản vá trống rỗng."
#, c-format
msgid "Applying: %.*s"
msgstr "Ãp dụng: %.*s"
msgid "No changes -- Patch already applied."
-msgstr "Không thay đổi gì cả -- Miếng vá đã được áp dụng rồi."
+msgstr "Không thay đổi gì cả -- bản vá đã được áp dụng rồi."
#, c-format
msgid "Patch failed at %s %.*s"
msgstr "Gặp lỗi khi vá tại %s %.*s"
msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
-msgstr "Dùng “git am --show-current-patch=diff†để xem miếng vá bị lỗi"
+msgstr "Dùng 'git am --show-current-patch=diff' để xem bản vá bị lỗi"
msgid "No changes - recorded it as an empty commit."
msgstr "Không có thay đổi nào - được ghi thành một lần chuyển giao rỗng."
@@ -2057,10 +2188,9 @@ msgid ""
"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 ""
-"Không có thay đổi nào - bạn đã quên sử dụng lệnh “git add†à?\n"
-"Nếu ở đây không có gì còn lại stage, tình cỠlà có một số thứ khác\n"
-"đã sẵn được đưa vào với cùng nội dung thay đổi; bạn có lẽ muốn bỠqua miếng "
-"vá này."
+"Không có thay đổi nào - bạn đã quên sử dụng lệnh 'git add' à?\n"
+"Nếu ở đây không còn gì để đưa vào vùng chá», có lẽ má»™t số ngưá»i khác\n"
+"đã thêm các thay đổi trong này rồi; bạn có lẽ muốn bỠqua bản vá này."
msgid ""
"You still have unmerged paths in your index.\n"
@@ -2069,38 +2199,31 @@ msgid ""
"You might run `git rm` on a file to accept \"deleted by them\" for it."
msgstr ""
"Bạn vẫn có những đưá»ng dẫn chưa hòa trá»™n trong chỉ mục cá»§a bạn.\n"
-"Bạn nên “git add†từng tập tin với các xung đột đã được giải quyết để đánh "
-"dấu chúng là thế.\n"
-"Bạn có lẽ muốn chạy “git rm“ trên má»™t tập tin để chấp nhận \"được xóa bởi há»"
-"\" cho nó."
-
-msgid "unable to write new index file"
-msgstr "không thể ghi tập tin lưu bảng mục lục mới"
+"Bạn nên 'git add' những tập tin đã giải quyết xung đột để đánh dấu chúng là "
+"đã xong.\n"
+"Bạn có lẽ muốn chạy 'git rm' trên một tập tin để chấp nhận \"được xóa bởi "
+"há»\" cho nó."
#, c-format
msgid "Could not parse object '%s'."
-msgstr "Không thể phân tích đối tượng “%sâ€."
+msgstr "Không thể Ä‘á»c đối tượng '%s'."
msgid "failed to clean index"
-msgstr "gặp lá»—i khi dá»n bảng mục lục"
+msgstr "gặp lá»—i khi dá»n chỉ mục"
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
msgstr ""
-"Bạn có lẽ đã có HEAD đã bị di chuyển đi kể từ lần “am†thất bại cuối cùng.\n"
+"Bạn có lẽ đã có HEAD đã bị di chuyển đi kể từ lần 'am' thất bại cuối cùng.\n"
"Không thể chuyển tới ORIG_HEAD"
#, c-format
msgid "failed to read '%s'"
-msgstr "gặp lá»—i khi Ä‘á»c “%sâ€"
-
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "tùy chá»n '%s=%s' và '%s=%s' không thể dùng cùng nhau"
+msgstr "gặp lá»—i khi Ä‘á»c '%s'"
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
-msgstr "git am [<các tùy chá»n>] [(<mbox>|<Maildir>)…]"
+msgstr "git am [<các tùy chá»n>] [(<mbox>|<Maildir>)...]"
msgid "git am [<options>] (--continue | --skip | --abort)"
msgstr "git am [<các tùy chá»n>] (--continue | --skip | --abort)"
@@ -2108,11 +2231,14 @@ msgstr "git am [<các tùy chá»n>] (--continue | --skip | --abort)"
msgid "run interactively"
msgstr "chạy kiểu tương tác"
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "bỠqua hook pre-applypatch và applypatch-msg"
+
msgid "historical option -- no-op"
-msgstr "tùy chá»n lịch sá»­ -- không-toán-tá»­"
+msgstr "tùy chá»n cÅ© -- không làm gì cả"
msgid "allow fall back on 3way merging if needed"
-msgstr "cho phép quay trở lại để hòa trộn kiểu “3way†nếu cần"
+msgstr "cho phép quay trở lại để hòa trộn kiểu 3way nếu cần"
msgid "be quiet"
msgstr "im lặng"
@@ -2135,10 +2261,6 @@ msgstr "chuyển cỠ-m cho git-mailinfo"
msgid "pass --keep-cr flag to git-mailsplit for mbox format"
msgstr "chuyển cỠ--keep-cr cho git-mailsplit với định dạng mbox"
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"đừng chuyển cỠ--keep-cr cho git-mailsplit không phụ thuộc vào am.keepcr"
-
msgid "strip everything before a scissors line"
msgstr "cắt má»i thứ trước dòng scissors"
@@ -2155,34 +2277,37 @@ msgid "format"
msgstr "định dạng"
msgid "format the patch(es) are in"
-msgstr "định dạng (các) miếng vá theo"
+msgstr "định dạng (các) bản vá theo"
msgid "override error message when patch failure occurs"
msgstr "đè lên các lá»i nhắn lá»—i khi xảy ra lá»—i vá nghiêm trá»ng"
msgid "continue applying patches after resolving a conflict"
-msgstr "tiếp tục áp dụng các miếng vá sau khi giải quyết xung đột"
+msgstr "tiếp tục áp dụng các bản vá sau khi giải quyết xung đột"
msgid "synonyms for --continue"
msgstr "đồng nghĩa với --continue"
msgid "skip the current patch"
-msgstr "bỠqua miếng vá hiện hành"
+msgstr "bỠqua bản vá hiện hành"
msgid "restore the original branch and abort the patching operation"
-msgstr "phục hồi lại nhánh gốc và loại bỠthao tác vá"
+msgstr "phục hồi lại nhánh gốc và huỷ thao tác vá"
msgid "abort the patching operation but keep HEAD where it is"
-msgstr "bỠqua thao tác vá nhưng vẫn giữ HEAD nơi nó chỉ đến"
+msgstr "huỷ thao tác vá nhưng vẫn giữ HEAD nơi nó chỉ đến"
msgid "show the patch being applied"
-msgstr "hiển thị miếng vá đã được áp dụng rồi"
+msgstr "hiển thị bản vá đã được áp dụng rồi"
+
+msgid "try to apply current patch again"
+msgstr "thử áp dụng bản vá hiện hành thêm lần nữa"
msgid "record the empty patch as an empty commit"
-msgstr "ghi lại miếng vá trống rỗng như là một lần chuyển giao trống"
+msgstr "ghi lại bản vá trống rỗng như là một lần chuyển giao trống"
msgid "lie about committer date"
-msgstr "nói dối vỠngày chuyển giao"
+msgstr "làm giả ngày chuyển giao"
msgid "use current timestamp for author date"
msgstr "dùng dấu thá»i gian hiện tại cho ngày tác giả"
@@ -2194,7 +2319,7 @@ msgid "GPG-sign commits"
msgstr "Các lần chuyển giao ký-GPG"
msgid "how to handle empty patches"
-msgstr "xử lý các miếng vá trống rỗng như thế nào"
+msgstr "xử lý các bản vá trống rỗng như thế nào"
msgid "(internal use for git-rebase)"
msgstr "(dùng nội bộ cho git-rebase)"
@@ -2204,10 +2329,10 @@ msgid ""
"it will be removed. Please do not use it anymore."
msgstr ""
"Tùy chá»n -b/--binary đã không dùng từ lâu rồi, và\n"
-"nó sẽ được bỠđi. Xin đừng sử dụng nó thêm nữa."
+"nó sẽ được bỠđi. Xin đừng sử dụng nó nữa."
msgid "failed to read the index"
-msgstr "gặp lá»—i Ä‘á»c bảng mục lục"
+msgstr "gặp lá»—i Ä‘á»c chỉ mục"
#, c-format
msgid "previous rebase directory %s still exists but mbox given."
@@ -2222,19 +2347,16 @@ msgstr ""
"Dùng \"git am --abort\" để loại bỠnó đi."
msgid "Resolve operation not in progress, we are not resuming."
-msgstr "Thao tác phân giải không được tiến hành, chúng ta không phục hồi lại."
+msgstr "Thao tác phân giải không được tiến hành, sẽ không phục hồi lại."
msgid "interactive mode requires patches on the command line"
-msgstr "chế độ tương tác yêu cầu có các miếng vá trên dòng lệnh"
+msgstr "chế độ tương tác yêu cầu có các bản vá trên dòng lệnh"
msgid "git apply [<options>] [<patch>...]"
-msgstr "git apply [<các tùy chá»n>] [<miếng-vá>…]"
+msgstr "git apply [<các tùy chá»n>] [<miếng-vá>...]"
msgid "could not redirect output"
-msgstr "không thể chuyển hướng kết xuất"
-
-msgid "git archive: Remote with no URL"
-msgstr "git archive: Máy chủ không có địa chỉ URL"
+msgstr "không thể chuyển hướng đầu ra"
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive: cần ACK/NAK, nhưng lại nhận được gói flush"
@@ -2247,58 +2369,53 @@ msgid "git archive: protocol error"
msgstr "git archive: lỗi giao thức"
msgid "git archive: expected a flush"
-msgstr "git archive: cần một flush (đẩy dữ liệu lên đĩa)"
-
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<lần_chuyển_giao>]"
+msgstr "git archive: cần flush dữ liệu"
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>…]] [--] [</các/"
-"đưá»ng/dẫn>…]"
+"git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>] [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--] [<đưá»ng/dẫn>...]"
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<lần_chuyển_giao>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<rev>...]"
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<lần_chuyển_giao>…]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<rev>|<vùng>)...]"
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <tên_tập_tin>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<lần_chuyển_giao>]"
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<rev>|<vùng>)…]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <tên_tập tin>"
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <lệnh>…"
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <lệnh> [<đối_số>]..."
#, c-format
msgid "cannot open file '%s' in mode '%s'"
-msgstr "không thể mở tập tin “%s†ở chế độ “%sâ€"
+msgstr "không thể mở tập tin '%s' ở chế độ '%s'"
#, c-format
msgid "could not write to file '%s'"
-msgstr "không thể ghi vào tập tin “%sâ€"
+msgstr "không thể ghi vào tập tin '%s'"
#, c-format
msgid "cannot open file '%s' for reading"
-msgstr "không thể mở tập tin “%s†để Ä‘á»c"
+msgstr "không thể mở tập tin '%s' để Ä‘á»c"
#, c-format
msgid "'%s' is not a valid term"
-msgstr "“%s†không phải má»™t thá»i hạn hợp lệ"
+msgstr "'%s' không phải má»™t thá»i hạn hợp lệ"
#, c-format
msgid "can't use the builtin command '%s' as a term"
-msgstr "không thể dùng lệnh tích hợp “%s†như là má»™t thá»i kỳ"
+msgstr "không thể dùng lệnh tích hợp '%s' như là má»™t thá»i kỳ"
#, c-format
msgid "can't change the meaning of the term '%s'"
-msgstr "không thể thay đổi nghÄ©a cá»§a thá»i kỳ “%sâ€"
+msgstr "không thể thay đổi nghÄ©a cá»§a thá»i kỳ '%s'"
msgid "please use two different terms"
msgstr "vui lòng dùng hai thá»i kỳ khác nhau"
@@ -2309,14 +2426,14 @@ msgstr "Chúng tôi đang không bisect.\n"
#, c-format
msgid "'%s' is not a valid commit"
-msgstr "“%s†không phải một lần chuyển giao hợp lệ"
+msgstr "'%s' không phải một lần chuyển giao hợp lệ"
#, c-format
msgid ""
"could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
msgstr ""
-"không thể lấy ra HEAD nguyên thá»§y cá»§a “%sâ€. Hãy thá»­ “git bisect reset <lần-"
-"chuyển-giao>â€."
+"không thể checkout HEAD nguyên thủy của '%s'. Hãy thử 'git bisect reset <lần-"
+"chuyển-giao>'."
#, c-format
msgid "Bad bisect_write argument: %s"
@@ -2324,11 +2441,11 @@ msgstr "Äối số bisect_write sai: %s"
#, c-format
msgid "couldn't get the oid of the rev '%s'"
-msgstr "không thể lấy oid cá»§a Ä‘iểm xét duyệt “%sâ€"
+msgstr "không thể lấy oid của điểm xét duyệt '%s'"
#, c-format
msgid "couldn't open the file '%s'"
-msgstr "không thể mở tập tin “%sâ€"
+msgstr "không thể mở tập tin '%s'"
#, c-format
msgid "Invalid command: you're currently in a %s/%s bisect"
@@ -2393,43 +2510,37 @@ msgid ""
"invalid argument %s for 'git bisect terms'.\n"
"Supported options are: --term-good|--term-old and --term-bad|--term-new."
msgstr ""
-"tham số không hợp lệ %s cho “git bisect termsâ€.\n"
+"tham số không hợp lệ %s cho 'git bisect terms'.\n"
"Các tùy chá»n há»— trợ là: --term-good|--term-old và --term-bad|--term-new."
-msgid "revision walk setup failed\n"
-msgstr "gặp lỗi cài đặt việc di chuyển qua các điểm xét duyệt\n"
-
#, c-format
msgid "could not open '%s' for appending"
-msgstr "không thể mở “%s†để nối thêm"
+msgstr "không thể mở '%s' để nối thêm"
msgid "'' is not a valid term"
-msgstr "†không phải má»™t thá»i hạn hợp lệ"
+msgstr "'' không phải term hợp lệ"
#, c-format
msgid "unrecognized option: '%s'"
-msgstr "tùy chá»n không được thừa nhận: “%sâ€"
+msgstr "không nhận ra tuỳ chá»n: '%s'"
#, c-format
msgid "'%s' does not appear to be a valid revision"
-msgstr "“%s†không có vẻ như là một điểm xét duyệt hợp lệ"
+msgstr "'%s' không có vẻ như là một điểm xét duyệt hợp lệ"
msgid "bad HEAD - I need a HEAD"
msgstr "sai HEAD - Tôi cần một HEAD"
#, c-format
msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
-msgstr "lấy ra “%s†ra gặp lỗi. Hãy thử \"git bisect reset <nhánh_hợp_lệ>\"."
-
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "sẽ không di chuyển nửa bước trên cây được cg-seek"
+msgstr "checkout '%s' ra gặp lỗi. Hãy thử \"git bisect reset <nhánh_hợp_lệ>\"."
msgid "bad HEAD - strange symbolic ref"
msgstr "sai HEAD - tham chiếu má»m kỳ lạ"
#, c-format
msgid "invalid ref: '%s'"
-msgstr "refspec không hợp lệ: “%sâ€"
+msgstr "refspec không hợp lệ: '%s'"
msgid "You need to start by \"git bisect start\"\n"
msgstr "Bạn cần khởi đầu bằng \"git bisect start\"\n"
@@ -2442,11 +2553,11 @@ msgid "Do you want me to do it for you [Y/n]? "
msgstr "Bạn có muốn tôi thá»±c hiện Ä‘iá»u này cho bạn không [Y/n]? "
msgid "Please call `--bisect-state` with at least one argument"
-msgstr "Hãy gá»i “--bisect-state†vá»›i ít nhất má»™t đối số"
+msgstr "Hãy gá»i '--bisect-state' vá»›i ít nhất má»™t đối số"
#, c-format
msgid "'git bisect %s' can take only one argument."
-msgstr "“git bisect %s†có thể lấy chỉ một đối số."
+msgstr "'git bisect %s' có thể lấy chỉ một đối số."
#, c-format
msgid "Bad rev input: %s"
@@ -2461,11 +2572,11 @@ msgstr "Chúng tôi không bisect."
#, c-format
msgid "'%s'?? what are you talking about?"
-msgstr "“%s�? bạn đang nói gì thế?"
+msgstr "'%s'?? bạn đang nói gì thế?"
#, c-format
msgid "cannot read file '%s' for replaying"
-msgstr "không thể Ä‘á»c tập tin “%s†để thao diá»…n lại"
+msgstr "không thể Ä‘á»c tập tin '%s' để thao diá»…n lại"
#, c-format
msgid "running %s\n"
@@ -2475,97 +2586,68 @@ msgid "bisect run failed: no command provided."
msgstr "bisect chạy gặp lỗi: không đưa ra lệnh."
#, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "không thể xác nhận “%s†trên điểm xét duyệt tốt"
+msgid "unable to verify %s on good revision"
+msgstr "không thể xác nhận '%s' trên điểm xét duyệt tốt"
#, c-format
msgid "bogus exit code %d for good revision"
-msgstr "mã thoát giả %d cho điểm xét duyệt tốt"
+msgstr "mã trả vá» %d bất thưá»ng cho Ä‘iểm xét duyệt tốt"
#, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
-msgstr "chạy bisect gặp lỗi: mã trả vỠ%d từ lệnh “%s†là < 0 hoặc >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "bisect gặp lỗi: mã trả vỠ%d từ lệnh '%s' < 0 hoặc >= 128"
#, c-format
msgid "cannot open file '%s' for writing"
-msgstr "không thể mở “%s†để ghi"
+msgstr "không thể mở '%s' để ghi"
msgid "bisect run cannot continue any more"
-msgstr "bisect không thể tiếp tục thêm được nữa"
+msgstr "không thể tiếp tục bisect thêm được nữa"
-#, c-format
msgid "bisect run success"
-msgstr "bisect chạy thành công"
+msgstr "bisect thành công"
-#, c-format
msgid "bisect found first bad commit"
msgstr "bisect tìm thấy lần chuyển giao sai đầu tiên"
#, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"chạy bisect gặp lỗi: “git bisect--helper --bisect-state %s†đã thoát ra với "
-"mã lỗi %d"
-
-msgid "reset the bisection state"
-msgstr "đặt lại trạng di chuyển nửa bước"
-
-msgid "check whether bad or good terms exist"
-msgstr "kiểm tra xem các thá»i Ä‘iểm xấu/tốt có tồn tại không"
-
-msgid "print out the bisect terms"
-msgstr "in ra các thá»i Ä‘iểm di chuyển ná»­a bước"
-
-msgid "start the bisect session"
-msgstr "bắt đầu phiên di chuyển nửa bước"
-
-msgid "find the next bisection commit"
-msgstr "tìm lần chuyển giao không di chuyển phân đôi"
-
-msgid "mark the state of ref (or refs)"
-msgstr "đánh dấu trạng thái ref (hoặc refs)"
-
-msgid "list the bisection steps so far"
-msgstr "liệt kê các bước bisection đi quá xa"
-
-msgid "replay the bisection process from the given file"
-msgstr "phát lại quá trình bisection từ tệp đã cho"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "bisect gặp lỗi: 'git bisect %s' đã thoát với mã lỗi %d"
-msgid "skip some commits for checkout"
-msgstr "bỠqua một số lần chuyển giao để lấy ra"
-
-msgid "visualize the bisection"
-msgstr "trực quan việc di chuyển nửa bước"
-
-msgid "use <cmd>... to automatically bisect"
-msgstr "dùng <cmd>… để bisect một cách tự động"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "'%s' không nhận đối số hay lần chuyển giao"
-msgid "no log for BISECT_WRITE"
-msgstr "không có nhật ký cho BISECT_WRITE"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "%s cần 0 hoặc 1 tham số"
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr ""
-"--bisect-reset requires không nhận đối số cũng không nhận lần chuyển giao"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "%s không cần tham số"
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms cần 0 hoặc 1 tham số"
+msgid "no logfile given"
+msgstr "chưa chỉ ra tập tin ghi nhật ký"
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next cần 0 tham số"
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "'%s' gặp lỗi: không chỉ ra lệnh."
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log cần 0 tham số"
+msgid "need a command"
+msgstr "cần chỉ ra lệnh"
-msgid "no logfile given"
-msgstr "chưa chỉ ra tập tin ghi nhật ký"
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "không hiểu câu lệnh: '%s'"
msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
msgstr "git blame [<các tùy chá»n>] [<rev-opts>] [<rev>] [--] <tập-tin>"
+msgid "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
+msgstr "git annotate [<các tùy chá»n>] [<rev-opts>] [<rev>] [--] <tập-tin>"
+
msgid "<rev-opts> are documented in git-rev-list(1)"
-msgstr "<rev-opts> được mô tả trong tài liệu git-rev-list(1)"
+msgstr "<rev-opts> được mô tả trong git-rev-list(1)"
#, c-format
msgid "expecting a color: %s"
@@ -2576,10 +2658,10 @@ msgstr "phải kết thúc bằng một màu"
#, c-format
msgid "cannot find revision %s to ignore"
-msgstr "không thể tìm thấy điểm xét duyệt %s để mà bỠqua"
+msgstr "không thể tìm thấy điểm xét duyệt %s để bỠqua"
msgid "show blame entries as we find them, incrementally"
-msgstr "hiển thị các mục “blame†như là chúng ta thấy chúng, tăng dần"
+msgstr "hiển thị các mục 'blame' theo thá»i gian, tăng dần"
msgid "do not show object names of boundary commits (Default: off)"
msgstr ""
@@ -2593,10 +2675,10 @@ msgid "show work cost statistics"
msgstr "hiển thị thống kê công sức làm việc"
msgid "force progress reporting"
-msgstr "ép buộc báo cáo tiến triển công việc"
+msgstr "ép buộc báo cáo tiến độ công việc"
msgid "show output score for blame entries"
-msgstr "hiển thị kết xuất Ä‘iểm số cho các mục tin “blameâ€"
+msgstr "hiển thị điểm số đầu ra cho các mục tin 'blame'"
msgid "show original filename (Default: auto)"
msgstr "hiển thị tên tập tin gốc (Mặc định: auto)"
@@ -2608,7 +2690,7 @@ msgid "show in a format designed for machine consumption"
msgstr "hiển thị ở định dạng đã thiết kế cho dùng bằng máy"
msgid "show porcelain format with per-line commit information"
-msgstr "hiển thị định dạng “porcelain†với thông tin chuyển giao mỗi dòng"
+msgstr "hiển thị định dạng 'porcelain' với thông tin chuyển giao mỗi dòng"
msgid "use the same output mode as git-annotate (Default: off)"
msgstr "dùng cùng chế độ xuất ra với git-annotate (Mặc định: off)"
@@ -2638,17 +2720,17 @@ msgid "ignore revisions from <file>"
msgstr "bỠqua các điểm xét duyệt từ <tập tin>"
msgid "color redundant metadata from previous line differently"
-msgstr "siêu dữ liệu dư thừa màu từ dòng trước khác hẳn"
+msgstr "tô màu khác cho siêu dữ liệu dư thừa từ dòng trước"
msgid "color lines by age"
-msgstr "các dòng màu theo tuổi"
+msgstr "tô màu các dòng theo tuổi"
msgid "spend extra cycles to find better match"
-msgstr "tiêu thụ thêm năng tài nguyên máy móc để tìm kiếm tốt hơn nữa"
+msgstr "tiêu thụ thêm tài nguyên để tìm kiếm tốt hơn nữa"
msgid "use revisions from <file> instead of calling git-rev-list"
msgstr ""
-"sá»­ dụng các Ä‘iểm xét duyệt (revision) từ <tập tin> thay vì gá»i “git-rev-listâ€"
+"sá»­ dụng các Ä‘iểm xét duyệt (revision) từ <tập tin> thay vì gá»i git-rev-list"
msgid "use <file>'s contents as the final image"
msgstr "sử dụng nội dung của <tập tin> như là ảnh cuối cùng"
@@ -2681,7 +2763,7 @@ msgstr ""
#. columns.
#.
msgid "4 years, 11 months ago"
-msgstr "4 năm, 11 tháng trước"
+msgstr "11 tháng, 28 ngày trước"
#, c-format
msgid "file %s has only %lu line"
@@ -2705,7 +2787,7 @@ msgid "git branch [<options>] [-l] [<pattern>...]"
msgstr "git branch [<các tùy chá»n>] [-l] [<mẫu>...]"
msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..."
-msgstr "git branch [<các tùy chá»n>] [-r] (-d | -D) <tên-nhánh> …"
+msgstr "git branch [<các tùy chá»n>] [-r] (-d | -D) <tên-nhánh> ..."
msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
msgstr "git branch [<các tùy chá»n>] (-m | -M) [<nhánh-cÅ©>] <nhánh-má»›i>"
@@ -2722,51 +2804,56 @@ msgstr "git branch [<các tùy chá»n>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
-"đang xóa nhánh “%s†mà nó lại đã được hòa trộn vào\n"
-" “%sâ€, nhưng vẫn chưa được hòa trá»™n vào HEAD."
+"đang xóa nhánh '%s' đã được hòa trộn vào\n"
+" '%s', nhưng vẫn chưa được hòa trộn vào HEAD."
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
-"không xóa nhánh “%s†cái mà chưa được hòa trộn vào\n"
-" “%sâ€, cho dù là nó đã được hòa trá»™n vào HEAD."
+"không xóa nhánh '%s' chưa được hòa trộn vào\n"
+" '%s', dù đã được hòa trộn vào HEAD."
#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Không thể tìm kiếm đối tượng chuyển giao cho “%sâ€"
+msgid "couldn't look up commit object for '%s'"
+msgstr "Không thể tìm kiếm đối tượng chuyển giao cho '%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 ""
-"Nhánh “%s†không được trộn một cách đầy đủ.\n"
-"Nếu bạn thá»±c sá»± muốn xóa nó, thì chạy lệnh “git branch -D %sâ€."
+msgid "the branch '%s' is not fully merged"
+msgstr "nhánh '%s' chưa được hoà trộn."
-msgid "Update of config-file failed"
-msgstr "Cập nhật tập tin cấu hình gặp lỗi"
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "Nếu bạn thực sự muốn xóa nó, hãy chạy lệnh 'git branch -D %s'."
+
+msgid "update of config-file failed"
+msgstr "cập nhật tập tin cấu hình gặp lỗi"
msgid "cannot use -a with -d"
msgstr "không thể dùng tùy chá»n -a vá»›i -d"
-msgid "Couldn't look up commit object for HEAD"
-msgstr "Không thể tìm kiếm đối tượng chuyển giao cho HEAD"
+#, c-format
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr "chông thể xóa nhánh '%s' đang được sử dụng tại cây làm việc '%s'"
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "Không thể xóa nhánh “%s†đã được lấy ra tại “%sâ€"
+msgid "remote-tracking branch '%s' not found"
+msgstr "không tìm thấy nhánh theo dõi máy chủ '%s'."
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "không tìm thấy nhánh theo dõi máy chá»§ “%sâ€."
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+"không tìm thấy nhánh '%s'.\n"
+"Bạn có quên dùng --remote không?"
#, c-format
-msgid "branch '%s' not found."
-msgstr "không tìm thấy nhánh “%sâ€."
+msgid "branch '%s' not found"
+msgstr "không tìm thấy nhánh '%s'."
#, c-format
msgid "Deleted remote-tracking branch %s (was %s).\n"
@@ -2774,10 +2861,10 @@ msgstr "Äã xóa nhánh theo dõi máy chá»§ \"%s\" (từng là %s).\n"
#, c-format
msgid "Deleted branch %s (was %s).\n"
-msgstr "Nhánh “%s†đã bị xóa (từng là %s)\n"
+msgstr "Nhánh '%s' đã bị xóa (từng là %s)\n"
msgid "unable to parse format string"
-msgstr "không thể phân tích chuỗi định dạng"
+msgstr "không thể Ä‘á»c chuá»—i định dạng"
msgid "could not resolve HEAD"
msgstr "không thể phân giải HEAD"
@@ -2787,56 +2874,62 @@ msgid "HEAD (%s) points outside of refs/heads/"
msgstr "HEAD (%s) chỉ bên ngoài của refs/heads/"
#, c-format
-msgid "Branch %s is being rebased at %s"
-msgstr "Nhánh %s đang được cải tổ lại tại %s"
+msgid "branch %s is being rebased at %s"
+msgstr "Nhánh %s đang được cải tổ tại %s"
#, c-format
-msgid "Branch %s is being bisected at %s"
-msgstr "Nhánh %s đang được di chuyển phân đôi (bisect) tại %s"
+msgid "branch %s is being bisected at %s"
+msgstr "Nhánh %s đang được bisect tại %s"
-msgid "cannot copy the current branch while not on any."
-msgstr "không thể sao chép nhánh hiện hành trong khi nó chẳng ở đâu cả."
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "HEAD của cây làm việc %s chưa được cập nhật"
+
+#, c-format
+msgid "invalid branch name: '%s'"
+msgstr "tên nhánh không hợp lệ: '%s'"
-msgid "cannot rename the current branch while not on any."
-msgstr "không thể đổi tên nhánh hiện hành trong khi nó chẳng ở đâu cả."
+#, c-format
+msgid "no commit on branch '%s' yet"
+msgstr "vẫn chưa chuyển giao trên nhánh '%s'."
#, c-format
-msgid "Invalid branch name: '%s'"
-msgstr "Tên nhánh không hợp lệ: “%sâ€"
+msgid "no branch named '%s'"
+msgstr "không có nhánh nào có tên '%s'."
-msgid "Branch rename failed"
-msgstr "Gặp lỗi khi đổi tên nhánh"
+msgid "branch rename failed"
+msgstr "gặp lỗi khi đổi tên nhánh"
-msgid "Branch copy failed"
-msgstr "Gặp lỗi khi sao chép nhánh"
+msgid "branch copy failed"
+msgstr "gặp lỗi khi sao chép nhánh"
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "Äã tạo má»™t bản sao cá»§a nhánh khuyết danh “%sâ€"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "đã tạo một bản sao của nhánh khuyết danh '%s'"
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "Äã đổi tên nhánh khuyết danh “%s†đi"
+msgid "renamed a misnamed branch '%s' away"
+msgstr "đã đổi tên nhánh khuyết danh '%s'"
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "Nhánh bị đổi tên thành %s, nhưng HEAD lại không được cập nhật!"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "đã đổi tên nhánh thành %s, nhưng HEAD không được cập nhật"
-msgid "Branch is renamed, but update of config-file failed"
-msgstr "Nhánh bị đổi tên, nhưng cập nhật tập tin cấu hình gặp lỗi"
+msgid "branch is renamed, but update of config-file failed"
+msgstr "đã đổi tên nhánh, nhưng cập nhật tập tin cấu hình gặp lỗi"
-msgid "Branch is copied, but update of config-file failed"
-msgstr "Nhánh đã được sao chép, nhưng cập nhật tập tin cấu hình gặp lỗi"
+msgid "branch is copied, but update of config-file failed"
+msgstr "đã sao chép nhánh, nhưng cập nhật tập tin cấu hình gặp lỗi"
#, c-format
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
-"Viết các ghi chú cho nhánh:\n"
+"Viết các ghi chú cho nhánh\n"
" %s\n"
-"Những dòng được bắt đầu bằng “%c†sẽ được cắt bá».\n"
+"Những dòng được bắt đầu bằng '%s' sẽ được cắt bá».\n"
msgid "Generic options"
msgstr "Tùy chá»n chung"
@@ -2863,10 +2956,10 @@ msgid "unset the upstream info"
msgstr "bỠđặt thông tin thượng nguồn"
msgid "use colored output"
-msgstr "tô màu kết xuất"
+msgstr "tô màu đầu ra"
msgid "act on remote-tracking branches"
-msgstr "thao tác trên nhánh “remote-trackingâ€"
+msgstr "thao tác trên nhánh 'remote-tracking'"
msgid "print only branches that contain the commit"
msgstr "chỉ hiển thị những nhánh mà nó chứa lần chuyển giao"
@@ -2878,7 +2971,7 @@ msgid "Specific git-branch actions:"
msgstr "Hành động git-branch:"
msgid "list both remote-tracking and local branches"
-msgstr "liệt kê cả nhánh “remote-tracking†và nội bộ"
+msgstr "liệt kê cả nhánh 'remote-tracking' và nội bộ"
msgid "delete fully merged branch"
msgstr "xóa một toàn bộ nhánh đã hòa trộn"
@@ -2892,6 +2985,9 @@ msgstr "di chuyển hay đổi tên một nhánh và reflog của nó"
msgid "move/rename a branch, even if target exists"
msgstr "di chuyển hoặc đổi tên một nhánh ngay cả khi đích đã có sẵn"
+msgid "do not output a newline after empty formatted refs"
+msgstr "không in ra ký tự xuống dòng sau tham chiếu rỗng"
+
msgid "copy a branch and its reflog"
msgstr "sao chép một nhánh và reflog của nó"
@@ -2937,8 +3033,8 @@ msgstr "đệ quy xuyên qua mô-đun con"
msgid "format to use for the output"
msgstr "định dạng sẽ dùng cho đầu ra"
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Gặp lỗi khi phân giải HEAD như là một tham chiếu hợp lệ."
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "gặp lỗi khi phân giải HEAD thành một tham chiếu hợp lệ."
msgid "HEAD not found below refs/heads!"
msgstr "Không tìm thấy HEAD ở dưới refs/heads!"
@@ -2956,22 +3052,20 @@ msgstr "--recurse-submodules chỉ có thể được sử dụng để tạo ra
msgid "branch name required"
msgstr "cần chỉ ra tên nhánh"
-msgid "Cannot give description to detached HEAD"
-msgstr "Không thể đưa ra mô tả HEAD đã tách rá»i"
+msgid "cannot give description to detached HEAD"
+msgstr "không thể đưa ra mô tả cho HEAD đã tách rá»i"
msgid "cannot edit description of more than one branch"
msgstr "không thể sá»­a mô tả cho nhiá»u hÆ¡n má»™t nhánh"
-#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Vẫn chưa chuyển giao trên nhánh “%sâ€."
+msgid "cannot copy the current branch while not on any"
+msgstr "không thể sao chép nhánh hiện hành khi đang không ở trên nhánh nào."
-#, c-format
-msgid "No branch named '%s'."
-msgstr "Không có nhánh nào có tên “%sâ€."
+msgid "cannot rename the current branch while not on any"
+msgstr "không thể đổi tên nhánh hiện hành khi đang không ở trên nhánh nào."
msgid "too many branches for a copy operation"
-msgstr "quá nhiá»u nhánh dành cho thao tác sao chép"
+msgstr "quá nhiá»u nhánh cho thao tác sao chép"
msgid "too many arguments for a rename operation"
msgstr "quá nhiá»u tham số cho thao tác đổi tên"
@@ -2981,50 +3075,48 @@ msgstr "quá nhiá»u tham số để đặt thượng nguồn má»›i"
#, c-format
msgid ""
-"could not set upstream of HEAD to %s when it does not point to any branch."
+"could not set upstream of HEAD to %s when it does not point to any branch"
msgstr ""
-"không thể đặt thượng nguồn của HEAD thành %s khi mà nó chẳng chỉ đến nhánh "
-"nào cả."
+"không thể đặt thượng nguồn của HEAD thành %s khi nó không chỉ đến nhánh nào."
#, c-format
msgid "no such branch '%s'"
-msgstr "không có nhánh nào như thế “%sâ€"
+msgstr "không có nhánh nào tên '%s'"
#, c-format
msgid "branch '%s' does not exist"
-msgstr "chưa có nhánh “%sâ€"
+msgstr "chưa có nhánh '%s'"
msgid "too many arguments to unset upstream"
msgstr "quá nhiá»u tham số để bỠđặt thượng nguồn"
-msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr "không thể bỠđặt thượng nguồn của HEAD không chỉ đến một nhánh nào cả."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
+msgstr "không thể bỠđặt thượng nguồn của HEAD khi nó không chỉ đến nhánh nào."
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "Nhánh “%s†không có thông tin thượng nguồn"
+msgid "branch '%s' has no upstream information"
+msgstr "nhánh '%s' không có thông tin thượng nguồn"
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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 ""
-"Hai tùy chá»n -a và -r áp dụng cho lệnh “git branch†không nhận má»™t tên "
-"nhánh.\n"
-"Có phải ý bạn là dùng: -a|-r --list <mẫu>?"
+"Hai tùy chá»n -a, và -r, cho lệnh 'git branch' không nhận má»™t tên nhánh.\n"
+"Có phải ý bạn là: -a|-r --list <mẫu>?"
msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
-"'--set-upstream-to' instead."
+"'--set-upstream-to' instead"
msgstr ""
-"tùy chá»n --set-upstream đã không còn được há»— trợ nữa. Vui lòng dùng “--"
-"track†hoặc “--set-upstream-to†để thay thế."
+"tùy chá»n --set-upstream đã không còn được há»— trợ nữa. Vui lòng dùng '--"
+"track' hoặc '--set-upstream-to'"
msgid "git version:\n"
msgstr "phiên bản git:\n"
#, c-format
msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() gặp lỗi “%s†(%d)\n"
+msgstr "uname() gặp lỗi '%s' (%d)\n"
msgid "compiler info: "
msgstr "thông tin trình biên dịch: "
@@ -3033,11 +3125,16 @@ msgid "libc info: "
msgstr "thông tin libc: "
msgid "not run from a git repository - no hooks to show\n"
-msgstr "không chạy từ một kho git - nên chẳng có móc nào để mà hiển thị cả\n"
+msgstr "không chạy từ một kho git - nên chẳng có móc nào để hiển thị cả\n"
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
+" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [-o|--output-directory <tập_tin>] [-s|--suffix <định_dạng>]"
+"git bugreport [(-o | --output-directory) <đưá»ng dẫn>]\n"
+" [(-s | --suffix) <định dạng> | --no-suffix]\n"
+" [--diagnose[=<chế độ>]]"
msgid ""
"Thank you for filling out a Git bug report!\n"
@@ -3059,29 +3156,45 @@ msgstr ""
"Cảm ơn bạn đã tạo một báo cáo lỗi Git!\n"
"Vui lòng trả lá»i các câu há»i sau để giúp chúng tôi hiểu vấn đỠcá»§a bạn.\n"
"\n"
-"Bạn đã làm gì trước khi lỗi xảy ra? (Các bước để tái tạo sự cố của bạn)\n"
+"Bạn đã làm gì trước khi lỗi xảy ra? (Các bước để tái hiện sự cố của bạn)\n"
"\n"
"Äiá»u bạn mong muốn xảy ra? (Hành vi dá»± kiến)\n"
"\n"
-"Äiá»u gì đã xảy ra thay thế? (Hành vi thá»±c tế)\n"
+"Äiá»u gì đã xảy ra? (Hành vi thá»±c tế)\n"
"\n"
"Có gì khác biệt giữa những gì bạn mong đợi và những gì thực sự xảy ra?\n"
"\n"
-"Bất kỳ thứ gì khác bạn muốn thêm:\n"
+"Những thứ khác bạn muốn thêm:\n"
"\n"
-"Vui lòng xen xét phần còn lại của báo cáo lỗi bên dưới.\n"
+"Vui lòng xem xét phần còn lại của báo cáo lỗi bên dưới.\n"
"Bạn có thể xóa bất kỳ dòng nào bạn không muốn chia sẻ.\n"
-msgid "specify a destination for the bugreport file"
-msgstr "chỉ định thư mục định để tạo tập tin báo cáo lỗi"
+msgid "mode"
+msgstr "chế độ"
-msgid "specify a strftime format suffix for the filename"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"tạo thêm tập tin nén zip của bản báo cáo chi tiết hơn (mặc định 'stats')"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "chỉ định thư mục đích để tạo tập tin báo cáo lỗi"
+
+msgid "specify a strftime format suffix for the filename(s)"
msgstr ""
"chỉ định chuá»—i định dạng thá»i gian strftime dùng làm hậu tố cho tên tập tin"
#, c-format
+msgid "unknown argument `%s'"
+msgstr "không hiểu đối số: '%s'"
+
+#, c-format
msgid "could not create leading directories for '%s'"
-msgstr "không thể tạo các thư mục dẫn đầu cho “%sâ€"
+msgstr "không thể tạo các thư mục cha cho '%s'"
+
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "không thể tạo bản báo cáo %s"
msgid "System Info"
msgstr "Thông tin hệ thống"
@@ -3095,34 +3208,41 @@ msgstr "không thể ghi vào %s"
#, c-format
msgid "Created new report at '%s'.\n"
-msgstr "Äã tạo báo cáo má»›i tại “%sâ€\n"
+msgstr "Äã tạo báo cáo má»›i tại '%s'\n"
-msgid "git bundle create [<options>] <file> <git-rev-list args>"
-msgstr "git bundle create [<các tùy chá»n>] <tập_tin> <git-rev-list args>"
+msgid ""
+"git bundle create [-q | --quiet | --progress]\n"
+" [--version=<version>] <file> <git-rev-list-args>"
+msgstr ""
+"git bundle create [-q | --quiet | --progress]\n"
+" [--version=<phiên_bản>] <tập tin> <đối-số-git-rev-list>"
-msgid "git bundle verify [<options>] <file>"
-msgstr "git bundle verify [<các tùy chá»n>] <tập-tin>"
+msgid "git bundle verify [-q | --quiet] <file>"
+msgstr "git bundle verify [-q | --quiet] <tập-tin>"
msgid "git bundle list-heads <file> [<refname>...]"
-msgstr "git bundle list-heads <tập tin> [<tên tham chiếu>…]"
+msgstr "git bundle list-heads <tập tin> [<tên tham chiếu>...]"
+
+msgid "git bundle unbundle [--progress] <file> [<refname>...]"
+msgstr "git bundle unbundle [--progress] <tập tin> [<tên tham chiếu>...]"
-msgid "git bundle unbundle <file> [<refname>...]"
-msgstr "git bundle unbundle <tập tin> [<tên tham chiếu>…]"
+msgid "need a <file> argument"
+msgstr "cần tham số <tập_tin>"
msgid "do not show progress meter"
-msgstr "không hiển thị bộ đo tiến trình"
+msgstr "không hiển thị thanh đo tiến độ"
msgid "show progress meter"
-msgstr "hiển thị bộ đo tiến trình"
+msgstr "hiển thị thanh đo tiến độ"
-msgid "show progress meter during object writing phase"
-msgstr "hiển thị bộ đo tiến triển trong suốt pha ghi đối tượng"
+msgid "historical; same as --progress"
+msgstr "tuỳ chá»n cÅ©; giống như --progress"
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "tương tự --all-progress khi bộ đo tiến trình được xuất hiện"
+msgid "historical; does nothing"
+msgstr "tuỳ chá»n cÅ©; không làm gì cả"
msgid "specify bundle format version"
-msgstr "chỉ điịnh định dạng cho bundle"
+msgstr "chỉ định phiên bản định dạng bundle"
msgid "Need a repository to create a bundle."
msgstr "Cần một kho chứa để có thể tạo một bundle."
@@ -3130,9 +3250,12 @@ msgstr "Cần một kho chứa để có thể tạo một bundle."
msgid "do not show bundle details"
msgstr "không hiển thị chi tiết bundle (bó)"
+msgid "need a repository to verify a bundle"
+msgstr "cần một kho chứa để thẩm tra một bundle"
+
#, c-format
msgid "%s is okay\n"
-msgstr "“%s†tốt\n"
+msgstr "%s tốt\n"
msgid "Need a repository to unbundle."
msgstr "Cần một kho chứa để có thể giải nén một bundle."
@@ -3141,12 +3264,8 @@ msgid "Unbundling objects"
msgstr "Tháo rá»i các đối tượng"
#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Không hiểu câu lệnh con: %s"
-
-#, c-format
msgid "cannot read object %s '%s'"
-msgstr "không thể Ä‘á»c đối tượng %s “%sâ€"
+msgstr "không thể Ä‘á»c đối tượng %s '%s'"
msgid "flush is only for --buffer mode"
msgstr "flush chỉ dành cho chế độ --buffer"
@@ -3166,10 +3285,6 @@ msgstr "%s cần các tham số"
msgid "%s takes no arguments"
msgstr "%s không nhận tham số"
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "không hiểu câu lệnh: '%s'"
-
msgid "only one batch option may be specified"
msgstr "chỉ má»™t tùy chá»n batch được chỉ ra"
@@ -3183,22 +3298,22 @@ msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
msgstr "git cat-file (-t | -s) [--allow-unknown-type] <đối_tượng>"
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
-" [--textconv | --filters]"
+" [--textconv | --filters] [-Z]"
msgstr ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
-" [--textconv | --filters]"
-
-msgid ""
-"git cat-file (--textconv | --filters)\n"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
-msgstr ""
-"git cat-file (--textconv | --filters)\n"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+" [--textconv | --filters] [-Z]"
msgid "Check object existence or emit object contents"
msgstr "Kiểm tra đối tượng có sẵn hay không hoặc phát nội dung của đối tượng"
@@ -3223,10 +3338,11 @@ msgstr "hiển thị kích thước đối tượng"
msgid "allow -s and -t to work with broken/corrupt objects"
msgstr "cho phép -s và -t để làm việc vá»›i các đối tượng sai/há»ng"
+msgid "use mail map file"
+msgstr "sử dụng tập tin ánh xạ thư"
+
msgid "Batch objects requested on stdin (or --batch-all-objects)"
-msgstr ""
-"Äã yêu cầu các đối tượng batch trên đầu vào tiêu chuẩn stdin (hoặc --batch-"
-"all-objects)"
+msgstr "Äã yêu cầu các đối tượng batch trên stdin (hoặc --batch-all-objects)"
msgid "show full <object> or <rev> contents"
msgstr "hiển thị đầy đủ nội dung <object> hay <rev>"
@@ -3234,19 +3350,23 @@ msgstr "hiển thị đầy đủ nội dung <object> hay <rev>"
msgid "like --batch, but don't emit <contents>"
msgstr "giống --batch, nhưng không phát ra <contents>"
+msgid "stdin is NUL-terminated"
+msgstr "stdin được kết thúc bởi NUL"
+
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin và stdout được kết thúc bởi NUL"
+
msgid "read commands from stdin"
-msgstr "Ä‘á»c các lệnh từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c các lệnh từ stdin"
msgid "with --batch[-check]: ignores stdin, batches all known objects"
-msgstr ""
-"vá»›i --batch[-check]: bá» qua đầu vào tiêu chuẩn stdin, batch má»i đối tượng đã "
-"biết"
+msgstr "vá»›i --batch[-check]: bá» qua stdin, batch má»i đối tượng đã biết"
msgid "Change or optimize batch output"
msgstr "Thay đổi hay tối ưu hóa đầu ra batch"
msgid "buffer --batch output"
-msgstr "đệm kết xuất --batch"
+msgstr "buffer đầu ra --batch"
msgid "follow in-tree symlinks"
msgstr "theo liên kết má»m trong-cây"
@@ -3283,11 +3403,11 @@ msgstr "path|tree-ish"
#, c-format
msgid "'%s' requires a batch mode"
-msgstr "“%s†cần một chế độ batch"
+msgstr "'%s' cần một chế độ batch"
#, c-format
msgid "'-%c' is incompatible with batch mode"
-msgstr "'-%c' là xung khắc với chế độ batch"
+msgstr "'-%c' không tương thích với chế độ batch"
msgid "batch modes take no arguments"
msgstr "chế độ batch không nhận các đối số"
@@ -3300,30 +3420,39 @@ msgstr "cần <rev> với '%s'"
msgid "<object> required with '-%c'"
msgstr "cần <object> với '-%c'"
-msgid "too many arguments"
-msgstr "có quá nhiá»u đối số"
-
#, c-format
msgid "only two arguments allowed in <type> <object> mode, not %d"
msgstr "chỉ hai đối số được phép trong chế độ <type> <object>, không phải %d"
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <attr>…] [--] tên-đưá»ng-dẫn…"
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <tên-"
+"đưá»ng-dẫn>..."
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <attr>…]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
msgid "report all attributes set on file"
-msgstr "báo cáo tất cả các thuộc tính đặt trên tập tin"
+msgstr "liệt kê tất cả các thuộc tính đặt trên tập tin"
msgid "use .gitattributes only from the index"
-msgstr "chỉ dùng .gitattributes từ bảng mục lục"
+msgstr "chỉ dùng .gitattributes từ chỉ mục"
msgid "read file names from stdin"
-msgstr "Ä‘á»c tên tập tin từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c tên tập tin từ stdin"
msgid "terminate input and output records by a NUL character"
-msgstr "chấm dứt các bản ghi vào và ra bằng ký tự NULL"
+msgstr "kết thúc các bản ghi vào và ra bằng ký tự NULL"
+
+msgid "<tree-ish>"
+msgstr "<tree-ish>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "kiểm tra thuộc tính từ tree-ish nào"
msgid "suppress progress reporting"
msgstr "chặn các báo cáo tiến trình hoạt động"
@@ -3332,7 +3461,7 @@ msgid "show non-matching input paths"
msgstr "hiển thị những đưá»ng dẫn đầu vào không khá»›p vá»›i mẫu"
msgid "ignore index when checking"
-msgstr "bỠqua mục lục khi kiểm tra"
+msgstr "bỠqua chỉ mục khi kiểm tra"
msgid "cannot specify pathnames with --stdin"
msgstr "không thể chỉ định các tên đưá»ng dẫn vá»›i --stdin"
@@ -3353,14 +3482,19 @@ msgid "--non-matching is only valid with --verbose"
msgstr "tùy-chá»n --non-matching chỉ hợp lệ khi dùng vá»›i --verbose"
msgid "git check-mailmap [<options>] <contact>..."
-msgstr "git check-mailmap [<các tùy chá»n>] <danh-bạ>…"
+msgstr "git check-mailmap [<các tùy chá»n>] <danh-bạ>..."
msgid "also read contacts from stdin"
-msgstr "đồng thá»i Ä‘á»c các danh bạ từ đầu vào tiêu chuẩn"
+msgstr "đồng thá»i Ä‘á»c các danh bạ từ stdin"
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "không thể phân tích danh bạ: “%sâ€"
+msgid "read additional mailmap entries from file"
+msgstr "Ä‘á»c thêm mục mailmap từ tập-tin"
+
+msgid "blob"
+msgstr "blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "Ä‘á»c thêm mục mailmap từ blob"
msgid "no contacts specified"
msgstr "chưa chỉ ra danh bạ"
@@ -3375,13 +3509,13 @@ msgid "when creating files, prepend <string>"
msgstr "khi tạo các tập tin, nối thêm <chuỗi>"
msgid "git checkout-index [<options>] [--] [<file>...]"
-msgstr "git checkout-index [<các tùy chá»n>] [--] [<tập-tin>…]"
+msgstr "git checkout-index [<các tùy chá»n>] [--] [<tập-tin>...]"
msgid "stage should be between 1 and 3 or all"
msgstr "stage nên giữa 1 và 3 hay all"
msgid "check out all files in the index"
-msgstr "lấy ra toàn bộ các tập tin trong bảng mục lục"
+msgstr "checkout toàn bộ các tập tin trong chỉ mục"
msgid "do not skip files with skip-worktree set"
msgstr "đừng bỠqua các tập tin với skip-worktree được đặt"
@@ -3390,59 +3524,58 @@ msgid "force overwrite of existing files"
msgstr "ép buộc ghi đè lên tập tin đã sẵn có từ trước"
msgid "no warning for existing files and files not in index"
-msgstr ""
-"không cảnh báo cho những tập tin tồn tại và không có trong bảng mục lục"
+msgstr "không cảnh báo cho những tập tin tồn tại và không có trong chỉ mục"
msgid "don't checkout new files"
msgstr "không checkout các tập tin mới"
msgid "update stat information in the index file"
-msgstr "cập nhật thông tin thống kê trong tập tin lưu bảng mục lục mới"
+msgstr "cập nhật thông tin thống kê trong tập tin chỉ mục mới"
msgid "read list of paths from the standard input"
-msgstr "Ä‘á»c danh sách đưá»ng dẫn từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c danh sách đưá»ng dẫn từ stdin"
msgid "write the content to temporary files"
msgstr "ghi nội dung vào tập tin tạm"
msgid "copy out the files from named stage"
-msgstr "sao chép ra các tập tin từ bệ phóng có tên"
+msgstr "sao chép ra các tập tin từ vùng chỠcó tên"
msgid "git checkout [<options>] <branch>"
msgstr "git checkout [<các tùy chá»n>] <nhánh>"
msgid "git checkout [<options>] [<branch>] -- <file>..."
-msgstr "git checkout [<các tùy chá»n>] [<nhánh>] -- <tập-tin>…"
+msgstr "git checkout [<các tùy chá»n>] [<nhánh>] -- <tập-tin>..."
msgid "git switch [<options>] [<branch>]"
msgstr "git switch [<các tùy chá»n>] [<nhánh>]"
msgid "git restore [<options>] [--source=<branch>] <file>..."
-msgstr "git restore [<các tùy chá»n>] [--source=<nhánh>] <tập tin>…"
+msgstr "git restore [<các tùy chá»n>] [--source=<nhánh>] <tập tin>..."
#, c-format
msgid "path '%s' does not have our version"
-msgstr "đưá»ng dẫn “%s†không có các phiên bản cá»§a chúng ta"
+msgstr "đưá»ng dẫn '%s' không có các phiên bản cá»§a ta"
#, c-format
msgid "path '%s' does not have their version"
-msgstr "đưá»ng dẫn “%s†không có các phiên bản cá»§a chúng"
+msgstr "đưá»ng dẫn '%s' không có các phiên bản cá»§a há»"
#, c-format
msgid "path '%s' does not have all necessary versions"
-msgstr "đưá»ng dẫn “%s†không có tất cả các phiên bản cần thiết"
+msgstr "đưá»ng dẫn '%s' không có tất cả các phiên bản cần thiết"
#, c-format
msgid "path '%s' does not have necessary versions"
-msgstr "đưá»ng dẫn “%s†không có các phiên bản cần thiết"
+msgstr "đưá»ng dẫn '%s' không có các phiên bản cần thiết"
#, c-format
msgid "path '%s': cannot merge"
-msgstr "đưá»ng dẫn “%sâ€: không thể hòa trá»™n"
+msgstr "đưá»ng dẫn '%s': không thể hòa trá»™n"
#, c-format
msgid "Unable to add merge result for '%s'"
-msgstr "Không thể thêm kết quả hòa trá»™n cho “%sâ€"
+msgstr "Không thể thêm kết quả hòa trộn cho '%s'"
#, c-format
msgid "Recreated %d merge conflict"
@@ -3457,48 +3590,56 @@ msgstr[0] "Äã cập nhật đưá»ng dẫn %d từ %s"
#, c-format
msgid "Updated %d path from the index"
msgid_plural "Updated %d paths from the index"
-msgstr[0] "Äã cập nhật đưá»ng dẫn %d từ mục lục"
+msgstr[0] "Äã cập nhật đưá»ng dẫn %d từ chỉ mục"
#, c-format
msgid "'%s' cannot be used with updating paths"
-msgstr "không được dùng “%s†vá»›i các đưá»ng dẫn cập nhật"
+msgstr "không được dùng '%s' vá»›i các đưá»ng dẫn cập nhật"
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
msgstr ""
-"Không thể cập nhật các đưá»ng dẫn và chuyển đến nhánh “%s†cùng má»™t lúc."
+"Không thể cập nhật các đưá»ng dẫn và chuyển đến nhánh '%s' cùng má»™t lúc."
#, c-format
msgid "neither '%s' or '%s' is specified"
-msgstr "không chỉ định “%s†cÅ©ng không “%sâ€"
+msgstr "không chỉ định '%s' cũng không '%s'"
#, c-format
msgid "'%s' must be used when '%s' is not specified"
-msgstr "phải có “%s†khi không chỉ định “%sâ€"
+msgstr "phải có '%s' khi không chỉ định '%s'"
#, c-format
msgid "'%s' or '%s' cannot be used with %s"
-msgstr "“%s†hay “%s†không thể được sử dụng với %s"
+msgstr "'%s' hay '%s' không thể được sử dụng với %s"
+
+#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "'%s', '%s', hay '%s' không thể được sử dụng khi checkout cây làm việc"
#, c-format
msgid "path '%s' is unmerged"
-msgstr "đưá»ng dẫn “%s†không được hòa trá»™n"
+msgstr "đưá»ng dẫn '%s' không được hòa trá»™n"
+
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "không thể Ä‘á»c cây (%s)"
msgid "you need to resolve your current index first"
-msgstr "bạn cần phải giải quyết bảng mục lục hiện tại của bạn trước đã"
+msgstr "bạn cần phải giải quyết chỉ mục hiện tại của bạn trước đã"
#, c-format
msgid ""
"cannot continue with staged changes in the following files:\n"
"%s"
msgstr ""
-"không thể tiếp tục với các thay đổi đã được đưa lên bệ phóng trong các dòng "
+"không thể tiếp tục với các thay đổi đã được đưa vào vùng chỠtrong các dòng "
"sau:\n"
"%s"
#, c-format
msgid "Can not do reflog for '%s': %s\n"
-msgstr "Không thể thá»±c hiện reflog cho “%sâ€: %s\n"
+msgstr "Không thể thực hiện reflog cho '%s': %s\n"
msgid "HEAD is now at"
msgstr "HEAD hiện giỠtại"
@@ -3508,27 +3649,27 @@ msgstr "không thể cập nhật HEAD"
#, c-format
msgid "Reset branch '%s'\n"
-msgstr "Äặt lại nhánh “%sâ€\n"
+msgstr "Äặt lại nhánh '%s'\n"
#, c-format
msgid "Already on '%s'\n"
-msgstr "Äã sẵn sàng trên “%sâ€\n"
+msgstr "Äã sẵn ở trên '%s'\n"
#, c-format
msgid "Switched to and reset branch '%s'\n"
-msgstr "Äã chuyển tá»›i và đặt lại nhánh “%sâ€\n"
+msgstr "Äã chuyển tá»›i và đặt lại nhánh '%s'\n"
#, c-format
msgid "Switched to a new branch '%s'\n"
-msgstr "Äã chuyển đến nhánh má»›i “%sâ€\n"
+msgstr "Äã chuyển đến nhánh má»›i '%s'\n"
#, c-format
msgid "Switched to branch '%s'\n"
-msgstr "Äã chuyển đến nhánh “%sâ€\n"
+msgstr "Äã chuyển đến nhánh '%s'\n"
#, c-format
msgid " ... and %d more.\n"
-msgstr " … và nhiá»u hÆ¡n %d.\n"
+msgstr " ... và nhiá»u hÆ¡n %d.\n"
#, c-format
msgid ""
@@ -3582,7 +3723,7 @@ msgid ""
"'%s' could be both a local file and a tracking branch.\n"
"Please use -- (and optionally --no-guess) to disambiguate"
msgstr ""
-"“%s†không thể là cả tập tin nội bộ và một nhánh theo dõi.\n"
+"'%s' không thể là cả tập tin nội bộ và một nhánh theo dõi.\n"
"Vui long dùng -- (và tùy chá»n thêm --no-guess) để tránh lẫn lá»™n"
msgid ""
@@ -3595,18 +3736,18 @@ msgid ""
"one remote, e.g. the 'origin' remote, consider setting\n"
"checkout.defaultRemote=origin in your config."
msgstr ""
-"Nếu ý bạn là lấy ra nhánh máy chá»§ được theo dõi, ví dụ “originâ€,\n"
+"Nếu ý bạn là checkout nhánh máy chủ được theo dõi, ví dụ 'origin',\n"
"bạn có thể làm như vậy bằng cách chỉ định đầy đủ tên vá»›i tùy chá»n --track:\n"
"\n"
" git checkout --track origin/<tên>\n"
"\n"
-"Nếu bạn muốn luôn lấy ra từ một <tên> một máy chủ ưa thích\n"
-"chưa rõ ràng, ví dụ máy chá»§ “originâ€, cân nhắc cài đặt\n"
+"Nếu bạn muốn luôn checkout từ một <tên> một máy chủ ưa thích\n"
+"chưa rõ ràng, ví dụ máy chủ 'origin', cân nhắc cài đặt\n"
"checkout.defaultRemote=origin trong cấu hình của bạn."
#, c-format
msgid "'%s' matched multiple (%d) remote tracking branches"
-msgstr "“%s†khá»›p vá»›i nhiá»u (%d) nhánh máy chá»§ được theo dõi"
+msgstr "'%s' khá»›p vá»›i nhiá»u (%d) nhánh máy chá»§ được theo dõi"
msgid "only one reference expected"
msgstr "chỉ cần một tham chiếu"
@@ -3625,19 +3766,19 @@ msgstr "tham chiếu không phải là một cây:%s"
#, c-format
msgid "a branch is expected, got tag '%s'"
-msgstr "cần má»™t nhánh, nhưng lại nhận được thẻ “%sâ€"
+msgstr "cần một nhánh, nhưng lại có thẻ '%s'"
#, c-format
msgid "a branch is expected, got remote branch '%s'"
-msgstr "cần má»™t nhánh, nhưng lại nhận được nhánh máy phục vụ “%sâ€"
+msgstr "cần một nhánh, nhưng lại có nhánh máy chủ '%s'"
#, c-format
msgid "a branch is expected, got '%s'"
-msgstr "cần má»™t nhánh, nhưng lại nhận được “%sâ€"
+msgstr "cần một nhánh, nhưng lại có '%s'"
#, c-format
msgid "a branch is expected, got commit '%s'"
-msgstr "cần má»™t nhánh, nhưng lại nhận được “%sâ€"
+msgstr "cần một nhánh, nhưng lại có '%s'"
msgid ""
"If you want to detach HEAD at the commit, try again with the --detach option."
@@ -3650,35 +3791,35 @@ msgid ""
"Consider \"git merge --quit\" or \"git worktree add\"."
msgstr ""
"không thể chuyển nhánh trong khi đang hòa trộn\n"
-"Cân nhắc dung \"git merge --quit\" hoặc \"git worktree add\"."
+"Thử dung \"git merge --quit\" hoặc \"git worktree add\"."
msgid ""
"cannot switch branch in the middle of an am session\n"
"Consider \"git am --quit\" or \"git worktree add\"."
msgstr ""
"không thể chuyển nhanh ở giữa một phiên am\n"
-"Cân nhắc dùng \"git am --quit\" hoặc \"git worktree add\"."
+"Thử dùng \"git am --quit\" hoặc \"git worktree add\"."
msgid ""
"cannot switch branch while rebasing\n"
"Consider \"git rebase --quit\" or \"git worktree add\"."
msgstr ""
"không thể chuyển nhánh trong khi cải tổ\n"
-"Cân nhắc dùng \"git rebase --quit\" hay \"git worktree add\"."
+"Thử dùng \"git rebase --quit\" hay \"git worktree add\"."
msgid ""
"cannot switch branch while cherry-picking\n"
"Consider \"git cherry-pick --quit\" or \"git worktree add\"."
msgstr ""
-"không thể chuyển nhánh trong khi cherry-picking\n"
-"Cân nhắc dùng \"git cherry-pick --quit\" hay \"git worktree add\"."
+"không thể chuyển nhánh trong khi cherry-pick\n"
+"Hãy dùng \"git cherry-pick --quit\" hay \"git worktree add\"."
msgid ""
"cannot switch branch while reverting\n"
"Consider \"git revert --quit\" or \"git worktree add\"."
msgstr ""
"không thể chuyển nhánh trong khi hoàn nguyên\n"
-"Cân nhắc dùng \"git revert --quit\" hoặc \"git worktree add\"."
+"Thử dùng \"git revert --quit\" hoặc \"git worktree add\"."
msgid "you are switching branch while bisecting"
msgstr ""
@@ -3690,23 +3831,31 @@ msgstr "các đưá»ng dẫn không thể dùng cùng vá»›i các nhánh chuyển
#, c-format
msgid "'%s' cannot be used with switching branches"
-msgstr "“%s†không thể được sử dụng với các nhánh chuyển"
+msgstr "'%s' không thể được sử dụng khi chuyển nhánh"
+
+#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' cần đưá»ng dẫn để checkout"
#, c-format
msgid "'%s' cannot be used with '%s'"
-msgstr "“%s†không thể được dùng vá»›i “%sâ€"
+msgstr "'%s' không thể được dùng với '%s'"
#, c-format
msgid "'%s' cannot take <start-point>"
-msgstr "“%s†không thể nhận <điểm-đầu>"
+msgstr "'%s' không thể nhận <điểm-đầu>"
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
-msgstr "Không thể chuyển nhánh đến má»™t thứ không phải là lần chuyển giao “%sâ€"
+msgstr "Không thể chuyển nhánh đến một thứ không phải là lần chuyển giao '%s'"
msgid "missing branch or commit argument"
msgstr "thiếu tham số là nhánh hoặc lần chuyển giao"
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "không hiểu kiểu hiển thị xung đột '%s'"
+
msgid "perform a 3-way merge with the new branch"
msgstr "thực hiện hòa trộn kiểu 3-way với nhánh mới"
@@ -3720,13 +3869,13 @@ msgid "detach HEAD at named commit"
msgstr "rá»i bá» HEAD tại lần chuyển giao theo tên"
msgid "force checkout (throw away local modifications)"
-msgstr "ép buộc lấy ra (bỠđi những thay đổi nội bộ)"
+msgstr "ép buộc checkout (bỠđi những thay đổi nội bộ)"
msgid "new-branch"
msgstr "nhánh-mới"
-msgid "new unparented branch"
-msgstr "nhánh không cha mới"
+msgid "new unborn branch"
+msgstr "nhánh chưa sinh mới"
msgid "update ignored files (default)"
msgstr "cập nhật các tập tin bị bỠqua (mặc định)"
@@ -3735,15 +3884,13 @@ msgid "do not check if another worktree is holding the given ref"
msgstr "không kiểm tra nếu cây làm việc khác đang giữ tham chiếu đã cho"
msgid "checkout our version for unmerged files"
-msgstr ""
-"lấy ra (checkout) phiên bản của chúng ta cho các tập tin chưa được hòa trộn"
+msgstr "checkout phiên bản của ta cho các tập tin chưa được hòa trộn"
msgid "checkout their version for unmerged files"
-msgstr ""
-"lấy ra (checkout) phiên bản của chúng hỠcho các tập tin chưa được hòa trộn"
+msgstr "checkout phiên bản của hỠcho các tập tin chưa được hòa trộn"
msgid "do not limit pathspecs to sparse entries only"
-msgstr "không giá»›i hạn đặc tả đưá»ng dẫn thành chỉ các mục rải rác"
+msgstr "không giá»›i hạn đặc tả đưá»ng dẫn chỉ trong các mục sparse (thưa)"
#, c-format
msgid "options '-%c', '-%c', and '%s' cannot be used together"
@@ -3758,7 +3905,7 @@ msgstr "thiếu tên nhánh; hãy thử -%c"
#, c-format
msgid "could not resolve %s"
-msgstr "không thể phân giải “%sâ€"
+msgstr "không thể phân giải '%s'"
msgid "invalid path specification"
msgstr "đưá»ng dẫn đã cho không hợp lệ"
@@ -3766,19 +3913,19 @@ msgstr "đưá»ng dẫn đã cho không hợp lệ"
#, c-format
msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
msgstr ""
-"“%s†không phải là một lần chuyển giao và một nhánh'%s†không thể được tạo "
+"'%s' không phải là một lần chuyển giao và một nhánh'%s' không thể được tạo "
"từ đó"
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
-msgstr "git checkout: --detach không nhận má»™t đối số đưá»ng dẫn “%sâ€"
+msgstr "git checkout: --detach không nhận má»™t đối số đưá»ng dẫn '%s'"
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
msgstr ""
"git checkout: --ours/--theirs, --force và --merge là xung khắc với nhau khi\n"
-"checkout bảng mục lục (index)."
+"checkout chỉ mục (index)."
msgid "you must specify path(s) to restore"
msgstr "bạn phải chỉ định các thư mục muốn hồi phục"
@@ -3796,7 +3943,7 @@ msgid "create reflog for new branch"
msgstr "tạo reflog cho nhánh mới"
msgid "second guess 'git checkout <no-such-branch>' (default)"
-msgstr "gợi ý thứ hai “git checkout <không-nhánh-nào-như-vậy>†(mặc định)"
+msgstr "gợi ý thứ hai 'git checkout <không-nhánh-nào-như-vậy>' (mặc định)"
msgid "use overlay mode (default)"
msgstr "dùng chế độ che phủ (mặc định)"
@@ -3814,10 +3961,10 @@ msgid "throw away local modifications"
msgstr "vứt bỠcác sửa đổi địa phương"
msgid "which tree-ish to checkout from"
-msgstr "lấy ra từ tree-ish nào"
+msgstr "checkout từ tree-ish nào"
msgid "restore the index"
-msgstr "phục hồi bảng mục lục"
+msgstr "phục hồi chỉ mục"
msgid "restore the working tree (default)"
msgstr "phục hồi cây làm việc (mặc định)"
@@ -3829,18 +3976,18 @@ msgid "use overlay mode"
msgstr "dùng chế độ che phủ"
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 <mẫu>] [-x | -X] [--] </các/đưá»ng/"
-"dẫn>…"
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <mẫu>] [-x | -X] [--][<đưá»ng/dẫn>...]"
#, c-format
msgid "Removing %s\n"
-msgstr "Äang gỡ bá» %s\n"
+msgstr "Äang xoá %s\n"
#, c-format
msgid "Would remove %s\n"
-msgstr "Có thể gỡ bỠ%s\n"
+msgstr "Sẽ xoá %s\n"
#, c-format
msgid "Skipping repository %s\n"
@@ -3852,17 +3999,17 @@ msgstr "Nên bỠqua kho chứa %s\n"
#, c-format
msgid "failed to remove %s"
-msgstr "gặp lỗi khi gỡ bỠ%s"
+msgstr "gặp lỗi khi xoá %s"
#, c-format
msgid "could not lstat %s\n"
-msgstr "không thể lấy thông tin thống kê đầy đủ của %s\n"
+msgstr "không thể lstat %s\n"
msgid "Refusing to remove current working directory\n"
-msgstr "Từ chối gỡ bỠthư mục làm việc hiện tại\n"
+msgstr "Từ chối xoá thư mục làm việc hiện tại\n"
msgid "Would refuse to remove current working directory\n"
-msgstr "Nên từ chối gỡ bỠthư mục làm việc hiện tại\n"
+msgstr "Sẽ từ chối xoá bỠthư mục làm việc hiện tại\n"
#, c-format
msgid ""
@@ -3892,17 +4039,17 @@ msgstr ""
"3-5 - chá»n má»™t vùng\n"
"2-3,6-9 - chá»n nhiá»u vùng\n"
"foo - chá»n mục dá»±a trên tiá»n tố duy nhất\n"
-"-… - không chá»n các mục đã chỉ ra\n"
+"-... - không chá»n các mục đã chỉ ra\n"
"* - chá»n tất\n"
" - (để trống) kết thúc việc chá»n\n"
-#, c-format, perl-format
+#, c-format
msgid "Huh (%s)?\n"
msgstr "Hả (%s)?\n"
#, c-format
msgid "Input ignore patterns>> "
-msgstr "Mẫu để lá»c các tập tin đầu vào cần lá» Ä‘i>> "
+msgstr "Mẫu để lá»c các tập tin đầu vào cần bá» qua>> "
#, c-format
msgid "WARNING: Cannot find items matched by: %s"
@@ -3914,7 +4061,7 @@ msgstr "Chá»n mục muốn xóa"
#. TRANSLATORS: Make sure to keep [y/N] as is
#, c-format
msgid "Remove %s [y/N]? "
-msgstr "Xóa bỠ“%s†[y/N]? "
+msgstr "Xóa bỠ'%s' [y/N]? "
msgid ""
"clean - start cleaning\n"
@@ -3935,7 +4082,7 @@ msgstr ""
msgid "Would remove the following item:"
msgid_plural "Would remove the following items:"
-msgstr[0] "Có muốn gỡ bỠ(các) mục sau đây không:"
+msgstr[0] "Có muốn xoá (các) mục sau đây không:"
msgid "No more files to clean, exiting."
msgstr "Không còn tập-tin nào để dá»n dẹp, Ä‘ang thoát ra."
@@ -3950,13 +4097,13 @@ msgid "interactive cleaning"
msgstr "dá»n bằng kiểu tương tác"
msgid "remove whole directories"
-msgstr "gỡ bỠtoàn bộ thư mục"
+msgstr "xoá toàn bộ thư mục"
msgid "pattern"
msgstr "mẫu"
msgid "add <pattern> to ignore rules"
-msgstr "thêm <mẫu> vào trong qui tắc bỠqua"
+msgstr "thêm <mẫu> vào trong quy tắc bỠqua"
msgid "remove ignored files, too"
msgstr "đồng thá»i gỡ bá» cả các tập tin bị bá» qua"
@@ -3964,22 +4111,10 @@ msgstr "đồng thá»i gỡ bá» cả các tập tin bị bá» qua"
msgid "remove only ignored files"
msgstr "chỉ gỡ bỠnhững tập tin bị bỠqua"
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce được đặt thành true và không đưa ra tùy chá»n -i, -n mà "
-"cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)"
-
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
msgstr ""
-"clean.requireForce mặc định được đặt là true và không đưa ra tùy chá»n -i, -n "
-"mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)"
-
-msgid "-x and -X cannot be used together"
-msgstr "-x và -X không thể dùng cùng nhau"
+"clean.requireForce được đặt thành true và không có tuỳ chá»n -f; từ chối dá»n "
+"dẹp"
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [<các tùy chá»n>] [--] <kho> [<t.mục>]"
@@ -3991,10 +4126,10 @@ msgid "don't create a checkout"
msgstr "không tạo một checkout"
msgid "create a bare repository"
-msgstr "tạo kho thuần"
+msgstr "tạo kho bare"
-msgid "create a mirror repository (implies bare)"
-msgstr "tạo kho bản sao (ý là kho thuần)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "tạo kho bản sao (ngụ ý --bare)"
msgid "to clone from a local repository"
msgstr "để nhân bản từ kho nội bộ"
@@ -4030,10 +4165,10 @@ msgid "name"
msgstr "tên"
msgid "use <name> instead of 'origin' to track upstream"
-msgstr "dùng <tên> thay cho “origin†để theo dõi thượng nguồn"
+msgstr "dùng <tên> thay cho 'origin' để theo dõi thượng nguồn"
msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "lấy ra <nhánh> thay cho HEAD của máy chủ"
+msgstr "checkout <nhánh> thay cho HEAD của máy chủ"
msgid "path to git-upload-pack on the remote"
msgstr "đưá»ng dẫn đến git-upload-pack trên máy chá»§"
@@ -4044,9 +4179,6 @@ msgstr "độ-sâu"
msgid "create a shallow clone of that depth"
msgstr "tạo bản sao không đầy đủ cho mức sâu đã cho"
-msgid "time"
-msgstr "thá»i-gian"
-
msgid "create a shallow clone since a specific time"
msgstr "tạo bản sao không đầy đủ từ thá»i Ä‘iểm đã cho"
@@ -4073,6 +4205,9 @@ msgstr "gitdir"
msgid "separate git dir from working tree"
msgstr "không dùng chung thư mục dành riêng cho git và thư mục làm việc"
+msgid "specify the reference format to use"
+msgstr "dùng định dạng tham chiếu nào cho các lần chuyển giao"
+
msgid "key=value"
msgstr "khóa=giá_trị"
@@ -4085,52 +4220,68 @@ msgstr "đặc-tả-máy-phục-vụ"
msgid "option to transmit"
msgstr "tùy chá»n để chuyển giao"
-msgid "use IPv4 addresses only"
-msgstr "chỉ dùng địa chỉ IPv4"
-
-msgid "use IPv6 addresses only"
-msgstr "chỉ dùng địa chỉ IPv6"
-
msgid "apply partial clone filters to submodules"
msgstr "áp dụng các bá»™ lá»c nhân bản má»™t phần cho mô-Ä‘un-con"
msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "má»i mô-Ä‘un-con nhân bản sẽ dung nhánh theo dõi máy chá»§ cá»§a chúng"
+msgstr "má»i mô-Ä‘un-con được nhân bản sẽ dùng nhánh theo dõi máy chá»§ cá»§a chúng"
msgid "initialize sparse-checkout file to include only files at root"
msgstr "khởi tạo tập tin sparse-checkout để bao gồm chỉ các tập tin ở gốc"
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "URI để tải xuống bundle trước khi lấy vỠtừ máy chủ origin"
+
#, c-format
msgid "info: Could not add alternate for '%s': %s\n"
-msgstr "thông tin: không thể thêm thay thế cho “%sâ€: %s\n"
+msgstr "thông tin: không thể thêm thay thế cho '%s': %s\n"
#, c-format
msgid "failed to stat '%s'"
-msgstr "gặp lá»—i khi lấy thống kê vỠ“%sâ€"
+msgstr "gặp lỗi khi stat '%s'"
#, c-format
msgid "%s exists and is not a directory"
msgstr "%s có tồn tại nhưng lại không phải là một thư mục"
#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "'%s' là liên kết má»m, từ chối sao chép vá»›i --local"
+
+#, c-format
msgid "failed to start iterator over '%s'"
-msgstr "gặp lá»—i khi bắt đầu lặp qua “%sâ€"
+msgstr "gặp lỗi khi bắt đầu lặp qua '%s'"
+
+#, c-format
+msgid "symlink '%s' exists, refusing to clone with --local"
+msgstr "liên kết má»m '%s' đã tồn tại, từ chối sao chép vá»›i --local"
#, c-format
msgid "failed to unlink '%s'"
-msgstr "gặp lá»—i khi bá» liên kết (unlink) “%sâ€"
+msgstr "gặp lỗi khi unlink '%s'"
+
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "không thể kiểm tra liên kết cứng '%s'"
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "liên kết cứng '%s' khác với nguồn"
#, c-format
msgid "failed to create link '%s'"
-msgstr "gặp lá»—i khi tạo được liên kết má»m %s"
+msgstr "gặp lá»—i khi tạo liên kết má»m %s"
#, c-format
msgid "failed to copy file to '%s'"
-msgstr "gặp lá»—i khi sao chép tập tin và “%sâ€"
+msgstr "gặp lỗi khi sao chép tập tin tới '%s'"
#, c-format
msgid "failed to iterate over '%s'"
-msgstr "gặp lá»—i khi lặp qua “%sâ€"
+msgstr "gặp lỗi khi lặp qua '%s'"
#, c-format
msgid "done.\n"
@@ -4142,8 +4293,8 @@ msgid ""
"and retry with 'git restore --source=HEAD :/'\n"
msgstr ""
"Việc nhân bản thành công, nhưng checkout gặp lỗi.\n"
-"Bạn kiểm tra kỹ xem cái gì được lấy ra bằng lệnh “git statusâ€\n"
-"và thá»­ lấy ra vá»›i lệnh “git restore --source=HEAD :/â€\n"
+"Kiểm tra xem cái gì đã được checkout bằng lệnh 'git status'\n"
+"và thử lại với lệnh 'git restore --source=HEAD :/'\n"
#, c-format
msgid "Could not find remote branch %s to clone."
@@ -4159,11 +4310,11 @@ msgstr "không thể cập nhật %s"
msgid "failed to initialize sparse-checkout"
msgstr "gặp lỗi khi khởi tạo sparse-checkout"
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr "refers HEAD máy chủ chỉ đến ref không tồn tại, không thể lấy ra.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "HEAD ở máy chủ chỉ đến ref không tồn tại, không thể checkout"
msgid "unable to checkout working tree"
-msgstr "không thể lấy ra (checkout) cây làm việc"
+msgstr "không thể checkout cây làm việc"
msgid "unable to write parameters to config file"
msgstr "không thể ghi các tham số vào tập tin cấu hình"
@@ -4175,18 +4326,18 @@ msgid "cannot unlink temporary alternates file"
msgstr "không thể bá» liên kết tập tin thay thế tạm thá»i"
msgid "Too many arguments."
-msgstr "Có quá nhiá»u đối số."
+msgstr "Quá nhiá»u đối số."
msgid "You must specify a repository to clone."
-msgstr "Bạn phải chỉ định một kho để mà nhân bản (clone)."
+msgstr "Bạn phải chỉ định một kho để nhân bản."
#, c-format
-msgid "options '%s' and '%s %s' cannot be used together"
-msgstr "tùy chá»n '%s', và '%s %s' không thể dùng cùng nhau"
+msgid "unknown ref storage format '%s'"
+msgstr "Không hiểu định dạng lưu tham chiếu '%s'"
#, c-format
msgid "repository '%s' does not exist"
-msgstr "kho chứa “%s†chưa tồn tại"
+msgstr "kho chứa '%s' chưa tồn tại"
#, c-format
msgid "depth %s is not a positive number"
@@ -4194,32 +4345,32 @@ msgstr "độ sâu %s không phải là một số nguyên dương"
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
-msgstr "đưá»ng dẫn đích “%s†đã có từ trước và không phải là má»™t thư mục rá»—ng."
+msgstr "đưá»ng dẫn đích '%s' đã có từ trước và không phải là má»™t thư mục rá»—ng."
#, c-format
msgid "repository path '%s' already exists and is not an empty directory."
msgstr ""
-"đưá»ng dẫn kho chứa “%s†đã có từ trước và không phải là má»™t thư mục rá»—ng."
+"đưá»ng dẫn kho chứa '%s' đã có từ trước và không phải là má»™t thư mục rá»—ng."
#, c-format
msgid "working tree '%s' already exists."
-msgstr "cây làm việc “%s†đã sẵn tồn tại rồi."
+msgstr "cây làm việc '%s' đã sẵn tồn tại rồi."
#, c-format
msgid "could not create leading directories of '%s'"
-msgstr "không thể tạo các thư mục dẫn đầu cá»§a “%sâ€"
+msgstr "không thể tạo các thư mục dẫn đầu của '%s'"
#, c-format
msgid "could not create work tree dir '%s'"
-msgstr "không thể tạo cây thư mục làm việc dir “%sâ€"
+msgstr "không thể tạo cây làm việc dir '%s'"
#, c-format
msgid "Cloning into bare repository '%s'...\n"
-msgstr "Äang nhân bản thành kho chứa bare “%sâ€â€¦\n"
+msgstr "Äang nhân bản thành kho chứa bare '%s'...\n"
#, c-format
msgid "Cloning into '%s'...\n"
-msgstr "Äang nhân bản thành “%sâ€â€¦\n"
+msgstr "Äang nhân bản thành '%s'...\n"
msgid ""
"clone --recursive is not compatible with both --reference and --reference-if-"
@@ -4230,24 +4381,25 @@ msgstr ""
#, c-format
msgid "'%s' is not a valid remote name"
-msgstr "“%s†không phải tên máy chủ hợp lệ"
+msgstr "'%s' không phải tên máy chủ hợp lệ"
msgid "--depth is ignored in local clones; use file:// instead."
-msgstr "--depth bị lỠđi khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
+msgstr ""
+"--depth bị bỠqua khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
msgid "--shallow-since is ignored in local clones; use file:// instead."
msgstr ""
-"--shallow-since bị lỠđi khi nhân bản nội bộ; hãy sử dụng file:// để thay "
+"--shallow-since bị bỠqua khi nhân bản nội bộ; hãy sử dụng file:// để thay "
"thế."
msgid "--shallow-exclude is ignored in local clones; use file:// instead."
msgstr ""
-"--shallow-exclude bị lỠđi khi nhân bản nội bộ; hãy sử dụng file:// để thay "
+"--shallow-exclude bị bỠqua khi nhân bản nội bộ; hãy sử dụng file:// để thay "
"thế."
msgid "--filter is ignored in local clones; use file:// instead."
msgstr ""
-"--filter bị lỠđi khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
+"--filter bị bỠqua khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
msgid "source repository is shallow, reject to clone."
msgstr "kho nguồn là nông, nên bỠtừ chối nhân bản."
@@ -4256,13 +4408,23 @@ msgid "source repository is shallow, ignoring --local"
msgstr "kho nguồn là nông, nên bỠqua --local"
msgid "--local is ignored"
-msgstr "--local bị lỠđi"
+msgstr "--local bị bỠqua"
msgid "cannot clone from filtered bundle"
msgstr "không thể nhân bản từ bundle được lá»c ra"
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "khởi tạo kho chứa thất bại, đang bỠqua URI bundle"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "lấy vỠđối tượng từ URI bundle '%s' thất bại"
+
+msgid "failed to fetch advertised bundles"
+msgstr "lấy vỠbundle thất bại"
+
msgid "remote transport reported error"
-msgstr "vận chuyển máy mạng đã báo cáo lỗi"
+msgstr "trình vận chuyển đã báo lỗi"
#, c-format
msgid "Remote branch %s not found in upstream %s"
@@ -4292,38 +4454,50 @@ msgstr "chèn thêm khoảng trắng vào bên phải"
msgid "padding space between columns"
msgstr "chèn thêm khoảng trắng giữa các cột"
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s phải không âm"
+
msgid "--command must be the first argument"
msgstr "--command phải là đối số đầu tiên"
msgid ""
-"git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"
+"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
msgstr ""
"git commit-graph verify [--object-dir </thư/mục/đối/tượng>] [--shallow] [--"
"[no-]progress]"
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 ""
-"git commit-graph write [--object-dir </thư/mục/đối/tượng>] [--append][--"
-"split[=<chiến lược>]] [--reachable|--stdin-packs|--stdin-commits][--changed-"
-"paths] [--[no-]max-new-filters <n>] [--[no-]progress] <các tùy chá»n chia "
-"tách>"
+"git commit-graph write [--object-dir </thư/mục/đối/tượng>] [--append]\n"
+" [--split[=<chiến lược>]] [--reachable | --stdin-packs "
+"| --stdin-commits]\n"
+" [--changed-paths] [--[no-]max-new-filters <n>] [--"
+"[no-]progress]\n"
+" <các tùy chá»n chia tách>"
msgid "dir"
-msgstr "tmục"
+msgstr "thư mục"
msgid "the object directory to store the graph"
msgstr "thư mục đối tượng để lưu đồ thị"
msgid "if the commit-graph is split, only verify the tip file"
-msgstr ""
-"nếu đồ-thị-các-lần-chuyển-giao bị chia cắt, thì chỉ thẩm tra tập tin đỉnh"
+msgstr "nếu đồ-thị-chuyển-giao bị chia cắt, thì chỉ thẩm tra tập tin đỉnh"
#, c-format
msgid "Could not open commit-graph '%s'"
-msgstr "Không thể mở đồ thị chuyển giao “%sâ€"
+msgstr "Không thể mở đồ thị chuyển giao '%s'"
+
+#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "Không thể mở dãy đồ thị chuyển giao '%s'"
#, c-format
msgid "unrecognized --split argument, %s"
@@ -4331,7 +4505,7 @@ msgstr "đối số --split không được thừa nhận, %s"
#, c-format
msgid "unexpected non-hex object ID: %s"
-msgstr "nhận được ID đối tượng không phải dạng hex không cần: %s"
+msgstr "nhận được ID đối tượng không phải dạng hex bất thưá»ng %s"
#, c-format
msgid "invalid object: %s"
@@ -4339,24 +4513,19 @@ msgstr "đối tượng không hợp lệ: %s"
#, c-format
msgid "option `%s' expects a numerical value"
-msgstr "tùy chá»n “%s†cần má»™t giá trị bằng số"
+msgstr "tùy chá»n '%s' cần má»™t giá trị bằng số"
msgid "start walk at all refs"
msgstr "bắt đầu di chuyển tại má»i tham chiếu"
msgid "scan pack-indexes listed by stdin for commits"
-msgstr ""
-"quét dó các mục lục gói được liệt kê bởi đầu vào tiêu chuẩn cho các lần "
-"chuyển giao"
+msgstr "quét dó các chỉ mục gói được liệt kê bởi stdin cho các lần chuyển giao"
msgid "start walk at commits listed by stdin"
-msgstr ""
-"bắt đầu di chuyển tại các lần chuyển giao được liệt kê bởi đầu vào tiêu chuẩn"
+msgstr "bắt đầu di chuyển tại các lần chuyển giao được liệt kê bởi stdin"
msgid "include all commits already in the commit-graph file"
-msgstr ""
-"bao gồm má»i lần chuyển giao đã sẵn có trongưá»i tập tin đồ-thị-các-lần-chuyển-"
-"giao"
+msgstr "bao gồm má»i lần chuyển giao đã sẵn có trong tập tin đồ-thị-chuyển-giao"
msgid "enable computation for changed paths"
msgstr "cho phép tính toán các đưá»ng dẫn đã bị thay đổi"
@@ -4366,11 +4535,11 @@ msgstr "cho phép ghi má»™t tập tin đồ há»a các lần chuyển giao lá»›n
msgid "maximum number of commits in a non-base split commit-graph"
msgstr ""
-"số lượng tối đa của các lần chuyển giao trong một đồ-thị-các-lần-chuyển-giao "
-"chia cắt không-cơ-sở"
+"số lượng tối đa của các lần chuyển giao trong một đồ-thị-chuyển-giao chia "
+"cắt không-cơ-sở"
msgid "maximum ratio between two levels of a split commit-graph"
-msgstr "tỷ lệ tối đa giữa hai mức của một đồ-thị-các-lần-chuyển-giao chia cắt"
+msgstr "tỉ lệ tối đa giữa hai mức của một đồ-thị-chuyển-giao chia cắt"
msgid "only expire files older than a given date-time"
msgstr "chỉ làm hết hạn các tập tin khi nó cÅ© hÆ¡n khoảng <thá»i gian> đưa ra"
@@ -4385,16 +4554,15 @@ msgstr ""
msgid "Collecting commits from input"
msgstr "Sưu tập các lần chuyển giao từ đầu vào"
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "không hiểu câu lệnh con: %s"
+msgid "git commit-tree <tree> [(-p <parent>)...]"
+msgstr "git commit-tree <cây> [(-p <cha>)...]"
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 ""
-"git commit-tree [(-p <cha>)…] [-S[<keyid>]] [(-m <ghi chú>)…] [(-F <tập tin>)"
-"…] <cây>"
+"git commit-tree [(-p <cha>)...] [-S[<keyid>]] [(-m <ghi chú>)...]\n"
+" [(-F <tập tin>)...] <cây>"
#, c-format
msgid "duplicate parent %s ignored"
@@ -4402,15 +4570,15 @@ msgstr "cha mẹ bị trùng lặp %s đã bị bỠqua"
#, c-format
msgid "not a valid object name %s"
-msgstr "không phải là tên đối tượng hợp lệ “%sâ€"
+msgstr "không phải là tên đối tượng hợp lệ '%s'"
#, c-format
msgid "git commit-tree: failed to read '%s'"
-msgstr "git commit-tree: gặp lá»—i khi Ä‘á»c “%sâ€"
+msgstr "git commit-tree: gặp lá»—i khi Ä‘á»c '%s'"
#, c-format
msgid "git commit-tree: failed to close '%s'"
-msgstr "git commit-tree: gặp lá»—i khi đóng “%sâ€"
+msgstr "git commit-tree: gặp lỗi khi đóng '%s'"
msgid "parent"
msgstr "cha-mẹ"
@@ -4436,22 +4604,38 @@ msgstr "phải đưa ra chính xác một cây"
msgid "git commit-tree: failed to read"
msgstr "git commit-tree: gặp lá»—i khi Ä‘á»c"
-msgid "git commit [<options>] [--] <pathspec>..."
-msgstr "git commit [<các tùy chá»n>] [--] <pathspec>…"
+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<chế-độ>] [--amend]\n"
+" [--dry-run] [(-c | -C | --squash) <lần chuyển giao> | --fixup "
+"[(amend|reword):]<lần chuyển giao>)]\n"
+" [-F <tập tin> | -m <ghi chú>] [--reset-author] [--allow-empty]\n"
+" [--allow-empty-message] [--no-verify] [-e] [--author=<tác giả>]\n"
+" [--date=<ngày tháng>] [--cleanup=<chế-độ>] [--[no-]status]\n"
+" [-i | -o] [--pathspec-from-file=<tập-tin> [--pathspec-file-nul]]\n"
+" [(--trailer <thẻ>[(=|:)<giá-trị>])...] [-S[<keyid>]]\n"
+" [--] [<pathspec>...]"
-msgid "git status [<options>] [--] <pathspec>..."
-msgstr "git status [<các tùy chá»n>] [--] <pathspec>…"
+msgid "git status [<options>] [--] [<pathspec>...]"
+msgstr "git status [<các tùy chá»n>] [--] <pathspec>..."
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 ""
-"Bạn đã yêu cầu amend (“tu bổâ€) phần lá»›n các lần chuyển giao gần đây, nhưng "
-"làm như thế\n"
-"có thể làm cho nó trở nên trống rỗng. Bạn có thể lặp lại lệnh của mình bằng "
-"--allow-empty,\n"
-"hoặc là bạn gỡ bỠcác lần chuyển giao một cách hoàn toàn bằng lệnh:\n"
+"Bạn đã yêu cầu amend ('tu bổ') lần chuyển giao gần nhất, nhưng làm vậy\n"
+"sẽ làm cho nó trở nên rỗng. Bạn có thể lặp lại lệnh với --allow-empty,\n"
+"hoặc là bạn gỡ bỠlần chuyển giao một cách hoàn toàn bằng lệnh:\n"
"\"git reset HEAD^\".\n"
msgid ""
@@ -4461,18 +4645,17 @@ msgid ""
" git commit --allow-empty\n"
"\n"
msgstr ""
-"Lần cherry-pick trước hiện nay trống rỗng, có lẽ là bởi vì sự phân giải xung "
-"đột.\n"
+"Lần cherry-pick trước hiện nay trống rỗng, có lẽ là do giải quyết xung đột.\n"
"Nếu bạn vẫn muốn chuyển giao nó cho dù thế nào đi nữa, hãy dùng:\n"
"\n"
" git commit --allow-empty\n"
"\n"
msgid "Otherwise, please use 'git rebase --skip'\n"
-msgstr "Nếu không được thì dùng lệnh \"git rebase --skip\"\n"
+msgstr "Nếu không thì dùng lệnh \"git rebase --skip\"\n"
msgid "Otherwise, please use 'git cherry-pick --skip'\n"
-msgstr "Nếu không được thì dùng lệnh \"git cherry-pick --skip\"\n"
+msgstr "Nếu không thì dùng lệnh \"git cherry-pick --skip\"\n"
msgid ""
"and then use:\n"
@@ -4489,33 +4672,33 @@ msgstr ""
"\n"
" git cherry-pick --continue\n"
"\n"
-"để lại tiếp tục cherry-picking các lần chuyển giao còn lại.\n"
+"để lại tiếp tục cherry-pick các lần chuyển giao còn lại.\n"
"Nếu bạn muốn bỠqua lần chuyển giao này thì dùng:\n"
"\n"
" git cherry-pick --skip\n"
"\n"
+msgid "updating files failed"
+msgstr "cập nhật tập tin gặp lỗi"
+
msgid "failed to unpack HEAD tree object"
-msgstr "gặp lỗi khi tháo dỡ HEAD đối tượng cây"
+msgstr "gặp lỗi khi giải nén đối tượng cây HEAD"
msgid "No paths with --include/--only does not make sense."
msgstr "Không đưá»ng dẫn vá»›i các tùy chá»n --include/--only không hợp lý."
msgid "unable to create temporary index"
-msgstr "không thể tạo bảng mục lục tạm thá»i"
+msgstr "không thể tạo chỉ mục tạm thá»i"
msgid "interactive add failed"
msgstr "gặp lỗi khi thêm bằng cách tương"
msgid "unable to update temporary index"
-msgstr "không thể cập nhật bảng mục lục tạm thá»i"
+msgstr "không thể cập nhật chỉ mục tạm thá»i"
msgid "Failed to update main cache tree"
msgstr "Gặp lỗi khi cập nhật cây bộ nhớ đệm"
-msgid "unable to write new_index file"
-msgstr "không thể ghi tập tin lưu bảng mục lục mới (new_index)"
-
msgid "cannot do a partial commit during a merge."
msgstr ""
"không thể thực hiện việc chuyển giao cục bộ trong khi đang được hòa trộn."
@@ -4529,21 +4712,21 @@ msgstr ""
"không thể thực hiện việc chuyển giao cục bộ trong khi đang thực hiện cải tổ."
msgid "cannot read the index"
-msgstr "không Ä‘á»c được bảng mục lục"
+msgstr "không Ä‘á»c được chỉ mục"
msgid "unable to write temporary index file"
-msgstr "không thể ghi tập tin lưu bảng mục lục tạm thá»i"
+msgstr "không thể ghi tập tin chỉ mục tạm thá»i"
#, c-format
msgid "commit '%s' lacks author header"
-msgstr "lần chuyển giao “%s†thiếu phần tác giả ở đầu"
+msgstr "lần chuyển giao '%s' thiếu phần tác giả ở đầu"
#, c-format
msgid "commit '%s' has malformed author line"
-msgstr "lần chuyển giao “%s†có phần tác giả ở đầu dị dạng"
+msgstr "lần chuyển giao '%s' có phần tác giả ở đầu dị dạng"
msgid "malformed --author parameter"
-msgstr "đối số cho --author bị dị hình"
+msgstr "đối số cho --author bị sai quy cách"
#, c-format
msgid "invalid date format: %s"
@@ -4557,19 +4740,19 @@ msgstr ""
"trong phần ghi chú hiện tại"
#, c-format
-msgid "could not lookup commit %s"
-msgstr "không thể tìm kiếm commit (lần chuyển giao) %s"
+msgid "could not lookup commit '%s'"
+msgstr "không thể tìm kiếm lần chuyển giao '%s'"
#, c-format
msgid "(reading log message from standard input)\n"
-msgstr "(Ä‘ang Ä‘á»c thông Ä‘iệp nhật ký từ đầu vào tiêu chuẩn)\n"
+msgstr "(Ä‘ang Ä‘á»c thông Ä‘iệp nhật ký từ stdin)\n"
msgid "could not read log from standard input"
-msgstr "không thể Ä‘á»c nhật ký từ đầu vào tiêu chuẩn"
+msgstr "không thể Ä‘á»c nhật ký từ stdin"
#, c-format
msgid "could not read log file '%s'"
-msgstr "không Ä‘á»c được tệp nhật ký “%sâ€"
+msgstr "không Ä‘á»c được tập nhật ký '%s'"
#, c-format
msgid "options '%s' and '%s:%s' cannot be used together"
@@ -4583,7 +4766,7 @@ msgstr "không thể Ä‘á»c MERGE_MSG"
#, c-format
msgid "could not open '%s'"
-msgstr "không thể mở “%sâ€"
+msgstr "không thể mở '%s'"
msgid "could not write commit template"
msgstr "không thể ghi mẫu chuyển giao"
@@ -4591,39 +4774,39 @@ msgstr "không thể ghi mẫu chuyển giao"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những\n"
-"dòng được bắt đầu bằng “%c†sẽ được bỠqua.\n"
+"dòng được bắt đầu bằng '%s' sẽ được bỠqua.\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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng "
"được\n"
-"bắt đầu bằng “%c†sẽ được bỠqua, nếu phần chú thích rỗng sẽ hủy bỠlần "
+"bắt đầu bằng '%s' sẽ được bỠqua, nếu phần chú thích rỗng sẽ hủy bỠlần "
"chuyển giao.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng "
"được\n"
-"bắt đầu bằng “%c†sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn thế.\n"
+"bắt đầu bằng '%s' sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn thế.\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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng "
"được\n"
-"bắt đầu bằng “%c†sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn thế.\n"
+"bắt đầu bằng '%s' sẽ được bỠqua; bạn có thể xóa chúng đi nếu muốn thế.\n"
"Phần chú thích này nếu trống rỗng sẽ hủy bỠlần chuyển giao.\n"
msgid ""
@@ -4665,10 +4848,10 @@ msgid "%sCommitter: %.*s <%.*s>"
msgstr "%sNgưá»i chuyển giao: %.*s <%.*s>"
msgid "Cannot read index"
-msgstr "Không Ä‘á»c được bảng mục lục"
+msgstr "Không Ä‘á»c được chỉ mục"
msgid "unable to pass trailers to --trailers"
-msgstr "không thể chuyển phần Ä‘uôi cho “--trailersâ€"
+msgstr "không thể chuyển phần đuôi cho '--trailers'"
msgid "Error building trees"
msgstr "Gặp lỗi khi xây dựng cây"
@@ -4680,25 +4863,25 @@ msgstr "Xin hãy cung cấp lá»i chú giải hoặc là dùng tùy chá»n -m ho
#, c-format
msgid "--author '%s' is not 'Name <email>' and matches no existing author"
msgstr ""
-"--author “%s†không phải là “HỠvà tên <thư điện tửl>†và không khớp bất kỳ "
-"tác giả nào sẵn có"
+"--author '%s' không phải là 'Há»-và-tên <email>' và không khá»›p bất kỳ tác giả "
+"nào sẵn có"
#, c-format
msgid "Invalid ignored mode '%s'"
-msgstr "Chế độ bá» qua không hợp lệ “%sâ€"
+msgstr "Chế độ bỠqua không hợp lệ '%s'"
#, c-format
msgid "Invalid untracked files mode '%s'"
-msgstr "Chế độ cho các tập tin chưa được theo dõi không hợp lệ “%sâ€"
+msgstr "Chế độ cho các tập tin chưa được theo dõi không hợp lệ '%s'"
msgid "You are in the middle of a merge -- cannot reword."
msgstr ""
-"Bạn Ä‘ang ở giữa cá»§a quá trình hòa trá»™n -- không thể thá»±c hiện việc “rewordâ€."
+"Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện việc 'reword'."
msgid "You are in the middle of a cherry-pick -- cannot reword."
msgstr ""
"Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện việc "
-"“rewordâ€."
+"'reword'."
#, c-format
msgid "reword option of '%s' and path '%s' cannot be used together"
@@ -4710,20 +4893,20 @@ msgid "reword option of '%s' and '%s' cannot be used together"
msgstr "không thể tổ hợp tùy chá»n \"reword\" cá»§a '%s' vá»›i '%s' cùng nhau"
msgid "You have nothing to amend."
-msgstr "Không có gì để mà “tu bổ†cả."
+msgstr "Không có gì để 'tu bổ' cả."
msgid "You are in the middle of a merge -- cannot amend."
msgstr ""
-"Bạn Ä‘ang ở giữa cá»§a quá trình hòa trá»™n -- không thể thá»±c hiện việc “tu bổâ€."
+"Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện việc 'tu bổ'."
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr ""
-"Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện việc “tu "
-"bổâ€."
+"Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện việc 'tu "
+"bổ'."
msgid "You are in the middle of a rebase -- cannot amend."
msgstr ""
-"Bạn Ä‘ang ở giữa cá»§a quá trình cải tổ -- nên không thể thá»±c hiện việc “tu bổâ€."
+"Bạn đang ở giữa của quá trình cải tổ -- nên không thể thực hiện việc 'tu bổ'."
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr ""
@@ -4735,7 +4918,7 @@ msgstr "không hiểu tùy chá»n: --fixup=%s:%s"
#, c-format
msgid "paths '%s ...' with -a does not make sense"
-msgstr "các đưá»ng dẫn “%s …†vá»›i tùy chá»n -a không hợp lý"
+msgstr "các đưá»ng dẫn '%s ...' vá»›i tùy chá»n -a không hợp lý"
msgid "show status concisely"
msgstr "hiển thị trạng thái ở dạng súc tích"
@@ -4747,22 +4930,19 @@ msgid "show stash information"
msgstr "hiển thị thông tin vỠtạm cất"
msgid "compute full ahead/behind values"
-msgstr "tính đầy đủ giá trị trước/sau"
+msgstr "tính đầy đủ giá trị dẫn trước/sau"
msgid "version"
msgstr "phiên bản"
msgid "machine-readable output"
-msgstr "kết xuất dạng máy-có-thể-Ä‘á»c"
+msgstr "xuất ra dạng máy-có-thể-Ä‘á»c"
msgid "show status in long format (default)"
msgstr "hiển thị trạng thái ở định dạng dài (mặc định)"
msgid "terminate entries with NUL"
-msgstr "chấm dứt các mục bằng NUL"
-
-msgid "mode"
-msgstr "chế độ"
+msgstr "kết thúc các mục bằng NUL"
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
@@ -4790,20 +4970,19 @@ msgid "list untracked files in columns"
msgstr "hiển thị danh sách các tập-tin chưa được theo dõi trong các cột"
msgid "do not detect renames"
-msgstr "không dò tìm các tên thay đổi"
+msgstr "không dò tìm các lần đổi tên"
msgid "detect renames, optionally set similarity index"
-msgstr "dò các tên thay đổi, tùy ý đặt mục lục tương tự"
+msgstr "tìm và phát hiện các lần đổi tên, có thể đánh chỉ số tương tự"
msgid "Unsupported combination of ignored and untracked-files arguments"
-msgstr ""
-"Không hỗ trỡ tổ hợp các tham số các tập tin bị bỠqua và không được theo dõi"
+msgstr "Không hỗ trợ cùng lúc tham số tập tin bị bỠqua và không được theo dõi"
msgid "suppress summary after successful commit"
msgstr "không hiển thị tổng kết sau khi chuyển giao thành công"
msgid "show diff in commit message template"
-msgstr "hiển thị sự khác biệt trong mẫu tin nhắn chuyển giao"
+msgstr "hiển thị diff trong mẫu tin nhắn chuyển giao"
msgid "Commit message options"
msgstr "Các tùy chá»n ghi chú commit"
@@ -4846,15 +5025,14 @@ msgstr ""
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
-"dùng lá»i nhắn có định dạng tá»± động nén để nén lại các lần chuyển giao đã chỉ "
-"ra"
+"dùng lá»i nhắn có định dạng autosquash để squash các lần chuyển giao đã chỉ ra"
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr ""
"lần chuyển giao nhận tôi là tác giả (được dùng vá»›i tùy chá»n -C/-c/--amend)"
msgid "trailer"
-msgstr "bộ dò vết"
+msgstr "trailer"
msgid "add custom trailer(s)"
msgstr "thêm Ä‘uôi tá»± chá»n"
@@ -4878,7 +5056,7 @@ msgid "commit all changed files"
msgstr "chuyển giao tất cả các tập tin có thay đổi"
msgid "add specified files to index for commit"
-msgstr "thêm các tập tin đã chỉ ra vào bảng mục lục để chuyển giao"
+msgstr "thêm các tập tin đã chỉ ra vào chỉ mục để chuyển giao"
msgid "interactively add files"
msgstr "thêm các tập-tin bằng tương tác"
@@ -4896,7 +5074,7 @@ msgid "show what would be committed"
msgstr "hiển thị xem cái gì có thể được chuyển giao"
msgid "amend previous commit"
-msgstr "“tu bổ†(amend) lần commit trước"
+msgstr "'tu bổ' (amend) lần commit trước"
msgid "bypass post-rewrite hook"
msgstr "vòng qua móc (hook) post-rewrite"
@@ -4908,7 +5086,7 @@ msgid "ok to record a change with an empty message"
msgstr "ok để ghi các thay đổi vá»›i lá»i nhắn trống rá»—ng"
msgid "could not parse HEAD commit"
-msgstr "không thể phân tích commit (lần chuyển giao) HEAD"
+msgstr "không thể Ä‘á»c commit (lần chuyển giao) HEAD"
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
@@ -4923,38 +5101,81 @@ msgstr "không thể Ä‘á»c phần chú thích (message) cá»§a lần chuyển gi
#, c-format
msgid "Aborting commit due to empty commit message.\n"
-msgstr "Bãi bỠviệc chuyển giao bởi vì phần chú thích của nó trống rỗng.\n"
+msgstr "Huỷ bỠlệnh chuyển giao bởi vì phần chú thích của nó trống rỗng.\n"
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr ""
-"Äang bá» qua việc chuyển giao; bạn đã không biên soạn phần chú thích "
-"(message).\n"
+"Huỷ bỠlệnh chuyển giao; bạn đã không biên soạn phần chú thích (message).\n"
#, c-format
msgid "Aborting commit due to empty commit message body.\n"
msgstr ""
-"Bãi bỠviệc chuyển giao bởi vì phần thân chú thích của nó trống rỗng.\n"
+"Huỷ bỠlệnh chuyển giao bởi vì phần thân chú thích của nó trống rỗng.\n"
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
"kho chứa đã được cập nhật, nhưng không thể ghi vào\n"
-"tập tin new_index (bảng mục lục mới). Hãy kiểm tra xem đĩa\n"
-"có bị đầy quá hay quota (hạn nghạch đĩa cứng) bị vượt quá,\n"
+"tập tin chỉ mục mới. Hãy kiểm tra xem đĩa\n"
+"có bị đầy quá hay hạn nghạch đĩa (quota) bị vượt quá hay không,\n"
"và sau đó \"git restore --staged :/\" để khắc phục."
-msgid "git config [<options>]"
-msgstr "git config [<các tùy chá»n>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<tuỳ-chá»n>] [<tuỳ-chá»n-hiển-thị>] [--includes]"
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "đối số không được thừa nhận --type, %s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<tuỳ-chá»n>] [<tuỳ-chá»n-hiển-thị>] [--includes] [--all] [--"
+"regexp] [--value=<giá-trị>] [--fixed-value] [--default=<giá-trị-mặc-định>] "
+"<tên>"
-msgid "only one type at a time"
-msgstr "chỉ một kiểu một lần"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<tuỳ-chá»n>] [--type=<kiểu>] [--all] [--value=<giá-trị>] [--"
+"fixed-value] <khoá> <giá-trị>"
+
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<tuỳ-chá»n>] [--all] [--value=<giá-trị>] [--fixed-value] "
+"<khoá> <giá-trị>"
+
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<tuỳ-chá»n>] <tên-cÅ©> <tên-má»›i>"
+
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<tuỳ-chá»n>] <tên>"
+
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<tùy-chá»n>]"
+
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr ""
+"git config [<tuỳ-chá»n>] --get-colorbool <tên> [<stdout-là-tty-hay-không>]"
+
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<tuỳ-chá»n>] [<tuỳ-chá»n-hiển-thị>] [--includes] [--all] [--"
+"regexp=<biểu-thức-chính-quy>] [--value=<giá-trị>] [--fixed-value] [--"
+"default=<giá-trị-mặc-định>] <khoá>"
+
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<tuỳ-chá»n>] [--type=<kiểu>] [--comment=<chú-thích>] [--all] "
+"[--value=<giá-trị>] [--fixed-value] <khoá> <giá-trị>"
msgid "Config file location"
msgstr "Vị trí tập tin cấu hình"
@@ -4980,54 +5201,6 @@ msgstr "blob-id"
msgid "read config from given blob object"
msgstr "Ä‘á»c cấu hình từ đối tượng blob đã cho"
-msgid "Action"
-msgstr "Hành động"
-
-msgid "get value: name [value-pattern]"
-msgstr "lấy giá trị: tên [value-pattern]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "lấy tất cả giá trị: khóa [value-pattern]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "lấy giá trị cho regexp: name-regex [value-pattern]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "lấy đặc tả giá trị cho URL: phần[.biến] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "thay thế tất cả các biến khớp mẫu: tên giá-trị [value-pattern]"
-
-msgid "add a new variable: name value"
-msgstr "thêm biến mới: tên giá-trị"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "gỡ bỠbiến: tên [value-pattern]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "gỡ bá» má»i cái khá»›p: tên [value-pattern]"
-
-msgid "rename section: old-name new-name"
-msgstr "đổi tên phần: tên-cũ tên-mới"
-
-msgid "remove a section: name"
-msgstr "gỡ bỠphần: tên"
-
-msgid "list all"
-msgstr "liệt kê tất"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr "sá»­ dụng so sánh bằng chuá»—i khi so sánh các giá trị vá»›i “value-patternâ€"
-
-msgid "open an editor"
-msgstr "mở một trình biên soạn"
-
-msgid "find the color configured: slot [default]"
-msgstr "tìm cấu hình màu sắc: slot [mặc định]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "tìm các cài đặt vỠmàu sắc: slot [stdout-là-tty]"
-
msgid "Type"
msgstr "Kiểu"
@@ -5055,33 +5228,32 @@ msgstr "giá trị là đưá»ng dẫn (tên tập tin hay thư mục)"
msgid "value is an expiry date"
msgstr "giá trị là một ngày hết hạn"
-msgid "Other"
-msgstr "Khác"
+msgid "Display options"
+msgstr "Tuỳ chá»n hiển thị"
msgid "terminate values with NUL byte"
-msgstr "chấm dứt giá trị với byte NUL"
+msgstr "kết thúc giá trị với byte NUL"
msgid "show variable names only"
msgstr "chỉ hiển thị các tên biến"
-msgid "respect include directives on lookup"
-msgstr "tôn trá»ng kể cà các hướng trong tìm kiếm"
-
msgid "show origin of config (file, standard input, blob, command line)"
-msgstr ""
-"hiển thị nguyên gốc của cấu hình (tập tin, đầu vào tiêu chuẩn, blob, dòng "
-"lệnh)"
+msgstr "hiển thị nguồn gốc của cấu hình (tập tin, stdin, blob, dòng lệnh)"
msgid "show scope of config (worktree, local, global, system, command)"
msgstr ""
"hiển thị phạm vi của cấu hình (cây làm việc, cục bộ, toàn cầu, hệ thống, "
"lệnh)"
-msgid "value"
-msgstr "giá trị"
+msgid "show config keys in addition to their values"
+msgstr "hiển thị khoá cùng vói giá trị"
-msgid "with --get, use default value when missing entry"
-msgstr "với --get, dùng giá trị mặc định khi thiếu mục tin"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "đối số không được thừa nhận --type, %s"
+
+msgid "only one type at a time"
+msgstr "chỉ một kiểu một lần"
#, c-format
msgid "wrong number of arguments, should be %d"
@@ -5105,16 +5277,16 @@ msgstr "gặp lỗi khi định dạng giá trị cấu hình mặc định: %s"
#, c-format
msgid "cannot parse color '%s'"
-msgstr "không thể phân tích màu “%sâ€"
+msgstr "không thể Ä‘á»c màu '%s'"
msgid "unable to parse default color value"
-msgstr "không thể phân tích giá trị màu mặc định"
+msgstr "không thể Ä‘á»c giá trị màu mặc định"
msgid "not in a git directory"
msgstr "không trong thư mục git"
msgid "writing to stdin is not supported"
-msgstr "việc ghi ra đầu ra tiêu chuẩn là không được hỗ trợ"
+msgstr "việc ghi ra stdin là không được hỗ trợ"
msgid "writing config blobs is not supported"
msgstr "không hỗ trợ ghi cấu hình các blob"
@@ -5157,44 +5329,72 @@ msgstr ""
"worktreeConfig được bật. Vui lòng Ä‘á»c phần \"CONFIGURATION FILE\"\n"
"trong \"git help worktree\" để biết thêm chi tiết"
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color và kiểu biến là không mạch lạc"
+msgid "Other"
+msgstr "Khác"
-msgid "only one action at a time"
-msgstr "chỉ một thao tác mỗi lần"
+msgid "respect include directives on lookup"
+msgstr "tôn trá»ng kể cà các hướng trong tìm kiếm"
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only chỉ được áp dụng cho --list hoặc --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "không thể Ä‘á»c tập tin cấu hình '%s'"
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr ""
-"--show-origin chỉ được áp dụng cho --get, --get-all, --get-regexp, hoặc --"
-"list"
+msgid "error processing config file(s)"
+msgstr "gặp lỗi khi xử lý các tập tin cấu hình"
-msgid "--default is only applicable to --get"
-msgstr "--default chỉ được áp dụng cho --get"
+msgid "Filter options"
+msgstr "Tùy chá»n lá»c"
+
+msgid "return all values for multi-valued config options"
+msgstr "trả vá» tất cả giá trị cho tuỳ chá»n cấu hình Ä‘a trị"
+
+msgid "interpret the name as a regular expression"
+msgstr "coi khoá là biểu thức chính quy"
+
+msgid "show config with values matching the pattern"
+msgstr "hiển thị giá trị cấu hình khớp với mẫu"
+
+msgid "use string equality when comparing values to value pattern"
+msgstr "sử dụng so sánh xâu khi so sánh các giá trị với mẫu"
+
+msgid "URL"
+msgstr "URL"
+
+msgid "show config matching the given URL"
+msgstr "hiển thị giá trị cấu hình khớp với URL"
+
+msgid "value"
+msgstr "giá trị"
+
+msgid "use default value when missing entry"
+msgstr "dùng giá trị mặc định khi không tồn tại"
msgid "--fixed-value only applies with 'value-pattern'"
-msgstr "--fixed-value chỉ áp dụng vá»›i “value-patternâ€"
+msgstr "--fixed-value chỉ áp dụng với 'value-pattern'"
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "không thể Ä‘á»c tập tin cấu hình “%sâ€"
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= không thể được dùng với --all hay --url"
-msgid "error processing config file(s)"
-msgstr "gặp lỗi khi xử lý các tập tin cấu hình"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= không thể được dùng với --all, --regexp hay --value"
-msgid "editing stdin is not supported"
-msgstr "sửa chữa đầu ra tiêu chuẩn là không được hỗ trợ"
+msgid "Filter"
+msgstr "Bá»™ lá»c"
-msgid "editing blobs is not supported"
-msgstr "việc sửa chữa các blob là không được hỗ trợ"
+msgid "replace multi-valued config option with new value"
+msgstr "thay thế tuỳ chá»n cấu hình Ä‘a trị thành giá trị"
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "không thể tạo tập tin cấu hình “%sâ€"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr "ghi chú cho ngưá»i Ä‘á»c được (tá»± động thêm # vào trước nếu cần)"
+
+msgid "add a new line without altering any existing values"
+msgstr "thêm dòng mới giữ nguyên các giá trị cũ"
+
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value chỉ áp dụng với --value=<mẫu>"
+
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append không thể được dùng với --value=<mẫu>"
#, c-format
msgid ""
@@ -5208,6 +5408,86 @@ msgstr ""
msgid "no such section: %s"
msgstr "không có đoạn: %s"
+msgid "editing stdin is not supported"
+msgstr "sửa chữa stdin là không được hỗ trợ"
+
+msgid "editing blobs is not supported"
+msgstr "việc sửa chữa các blob là không được hỗ trợ"
+
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "không thể tạo tập tin cấu hình '%s'"
+
+msgid "Action"
+msgstr "Hành động"
+
+msgid "get value: name [<value-pattern>]"
+msgstr "lấy giá trị: khoá [<mẫu-giá-trị>]"
+
+msgid "get all values: key [<value-pattern>]"
+msgstr "lấy tất cả giá trị: khóa [<mẫu-giá-trị>]"
+
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "lấy giá trị cho biểu thức chính quy: regex [<mẫu-giá-trị>]"
+
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "lấy giá trị riêng cho URL: phần[.biến] URL"
+
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "thay thế tất cả các biến khớp mẫu: tên giá-trị [<mẫu-giá-trị>]"
+
+msgid "add a new variable: name value"
+msgstr "thêm biến mới: tên giá-trị"
+
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "gỡ bỠbiến: tên [<mẫu-giá-trị>]"
+
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "gỡ bá» má»i biến khá»›p: tên [<mẫu-giá-trị>]"
+
+msgid "rename section: old-name new-name"
+msgstr "đổi tên phần: tên-cũ tên-mới"
+
+msgid "remove a section: name"
+msgstr "gỡ bỠphần: tên"
+
+msgid "list all"
+msgstr "liệt kê tất"
+
+msgid "open an editor"
+msgstr "mở một trình biên soạn"
+
+msgid "find the color configured: slot [<default>]"
+msgstr "tìm cấu hình màu sắc: slot [<mặc định>]"
+
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "tìm các cài đặt vỠmàu sắc: slot [<stdout-là-tty-hay-không>]"
+
+msgid "with --get, use default value when missing entry"
+msgstr "với --get, dùng giá trị mặc định khi thiếu mục tin"
+
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color và kiểu biến là không mạch lạc"
+
+msgid "no action specified"
+msgstr "chưa chỉ ra hành động"
+
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only chỉ được áp dụng cho --list hoặc --get-regexp"
+
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin chỉ được áp dụng cho --get, --get-all, --get-regexp, hoặc --"
+"list"
+
+msgid "--default is only applicable to --get"
+msgstr "--default chỉ được áp dụng cho --get"
+
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment chỉ được áp dụng cho thao tác add/set/replace"
+
msgid "print sizes in human readable format"
msgstr "hiển thị kích cỡ theo định dạng dành cho ngưá»i Ä‘á»c"
@@ -5219,12 +5499,12 @@ msgid ""
"\tchmod 0700 %s"
msgstr ""
"Quyá»n hạn trên thư mục gói mạng cá»§a bạn không chính xác; ngưá»i dùng\n"
-"khác có lẽ có thể Ä‘á»c được chứng thư được lưu đệm cá»§a bạn. Cân nhắc chạy:\n"
+"khác có lẽ có thể Ä‘á»c được chứng thư được lưu đệm cá»§a bạn. Thá»­ chạy:\n"
"\n"
"\tchmod 0700 %s"
msgid "print debugging messages to stderr"
-msgstr "in thông tin gỡ lỗi ra đầu ra lỗi tiêu chuẩn"
+msgstr "in thông tin gỡ lỗi ra stderr"
msgid "credential-cache--daemon unavailable; no unix socket support"
msgstr "credential-cache--daemon không sẵn có; không hỗ trợ unix socket"
@@ -5236,17 +5516,24 @@ msgstr "credential-cache không sẵn có; không hỗ trợ unix socket"
msgid "unable to get credential storage lock in %d ms"
msgstr "không thể lấy khóa lưu trữ ủy nhiệm %d ms"
-msgid "git describe [<options>] [<commit-ish>...]"
-msgstr "git describe [<các tùy chá»n>] <commit-ish>*"
+msgid ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
+msgstr ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
+
+msgid ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
+msgstr ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
-msgid "git describe [<options>] --dirty"
-msgstr "git describe [<các tùy chá»n>] --dirty"
+msgid "git describe <blob>"
+msgstr "git describe <blob>"
msgid "head"
-msgstr "phía trước"
+msgstr "head"
msgid "lightweight"
-msgstr "hạng nhẹ"
+msgstr "nhẹ"
msgid "annotated"
msgstr "có diễn giải"
@@ -5257,11 +5544,11 @@ msgstr "thẻ đã được ghi chú %s không sẵn để dùng"
#, c-format
msgid "tag '%s' is externally known as '%s'"
-msgstr "ở bên ngoài, thẻ “%s†đã được biết đến là “%sâ€"
+msgstr "ở bên ngoài, thẻ '%s' đã được biết đến là '%s'"
#, c-format
msgid "no tag exactly matches '%s'"
-msgstr "không có thẻ nào khá»›p chính xác vá»›i “%sâ€"
+msgstr "không có thẻ nào khớp chính xác với '%s'"
#, c-format
msgid "No exact match on refs or tags, searching to describe\n"
@@ -5276,7 +5563,7 @@ msgid ""
"No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."
msgstr ""
-"Không có thẻ được chú giải nào được mô tả là “%sâ€.\n"
+"Không có thẻ được chú giải nào được mô tả là '%s'.\n"
"Tuy nhiên, ở đây có những thẻ không được chú giải: hãy thử --tags."
#, c-format
@@ -5284,7 +5571,7 @@ msgid ""
"No tags can describe '%s'.\n"
"Try --always, or create some tags."
msgstr ""
-"Không có thẻ có thể mô tả “%sâ€.\n"
+"Không có thẻ có thể mô tả '%s'.\n"
"Hãy thử --always, hoặc tạo một số thẻ."
#, c-format
@@ -5315,13 +5602,13 @@ msgid "find the tag that comes after the commit"
msgstr "tìm các thẻ mà nó đến trước lần chuyển giao"
msgid "debug search strategy on stderr"
-msgstr "chiến lược tìm kiếm gỡ lỗi trên đầu ra lỗi chuẩn stderr"
+msgstr "gỡ lỗi chiến lược tìm kiếm ra stderr"
msgid "use any ref"
msgstr "dùng ref bất kỳ"
msgid "use any tag, even unannotated"
-msgstr "dùng thẻ bất kỳ, cả khi “unannotatedâ€"
+msgstr "dùng thẻ bất kỳ, cả khi 'unannotated'"
msgid "always use long format"
msgstr "luôn dùng định dạng dài"
@@ -5333,39 +5620,60 @@ msgid "only output exact matches"
msgstr "chỉ xuất những gì khớp chính xác"
msgid "consider <n> most recent tags (default: 10)"
-msgstr "coi như <n> thẻ gần đây nhất (mặc định: 10)"
+msgstr "chá»n trong <n> thẻ gần đây nhất (mặc định: 10)"
msgid "only consider tags matching <pattern>"
-msgstr "chỉ cân nhắc đến những thẻ khớp với <mẫu>"
+msgstr "chỉ chá»n những thẻ khá»›p vá»›i <mẫu>"
msgid "do not consider tags matching <pattern>"
-msgstr "không coi rằng các thẻ khớp với <mẫu>"
+msgstr "không chá»n những thẻ khá»›p vá»›i <mẫu>"
msgid "show abbreviated commit object as fallback"
-msgstr "hiển thị đối tượng chuyển giao vắn tắt như là fallback"
+msgstr "hiển thị vắn tắt đối tượng chuyển giao để thay thế"
msgid "mark"
msgstr "dấu"
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
-msgstr "thêm <dấu> trên cây thư mục làm việc bẩn (mặc định \"-dirty\")"
+msgstr "thêm <dấu> trên cây làm việc không sạch (mặc định \"-dirty\")"
msgid "append <mark> on broken working tree (default: \"-broken\")"
-msgstr "thêm <dấu> trên cây thư mục làm việc bị há»ng (mặc định \"-broken\")"
+msgstr "thêm <dấu> trên cây làm việc bị há»ng (mặc định \"-broken\")"
msgid "No names found, cannot describe anything."
-msgstr "Không tìm thấy các tên, không thể mô tả gì cả."
+msgstr "Không tìm thấy tên, không thể mô tả gì cả."
#, c-format
msgid "option '%s' and commit-ishes cannot be used together"
msgstr "tùy chá»n '%s' và commit-ishes không thể dùng cùng nhau"
+msgid ""
+"git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+" [--mode=<mode>]"
+msgstr ""
+"git diagnose [(-o | --output-directory) <tập tin>] [(-s | --suffix) <định "
+"dạng>]\n"
+" [--mode=<chế độ>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "chỉ định thư mục đích để tạo bản báo cáo"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr ""
+"chỉ định chuá»—i định dạng thá»i gian strftime dùng làm hậu tố cho tên tập tin"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "chỉ định nội dung bản báo cáo"
+
msgid "--merge-base only works with two commits"
msgstr "--merge-base chỉ hoạt động với hai lần chuyển giao"
#, c-format
msgid "'%s': not a regular file or symlink"
-msgstr "“%sâ€: không phải tập tin bình thưá»ng hay liên kết má»m"
+msgstr "'%s': không phải tập tin bình thưá»ng hay liên kết má»m"
+
+msgid "no merge given, only parents."
+msgstr "không có lần hoà trộn, chỉ có các lần chuyển giao cha"
#, c-format
msgid "invalid option: %s"
@@ -5373,31 +5681,31 @@ msgstr "tùy chá»n không hợp lệ: %s"
#, c-format
msgid "%s...%s: no merge base"
-msgstr "%s…%s: không có cơ sở hòa trộn"
+msgstr "%s...%s: không có gốc hòa trộn"
msgid "Not a git repository"
msgstr "Không phải là kho git"
#, c-format
msgid "invalid object '%s' given."
-msgstr "đối tượng đã cho “%s†không hợp lệ."
+msgstr "đối tượng đã cho '%s' không hợp lệ."
#, c-format
msgid "more than two blobs given: '%s'"
-msgstr "đã cho nhiá»u hÆ¡n hai đối tượng blob: “%sâ€"
+msgstr "đã cho nhiá»u hÆ¡n hai đối tượng blob: '%s'"
#, c-format
msgid "unhandled object '%s' given."
-msgstr "đã cho đối tượng không thể nắm giữ “%sâ€."
+msgstr "đã cho đối tượng không thể xử lý '%s'."
#, c-format
msgid "%s...%s: multiple merge bases, using %s"
-msgstr "%s…%s: có nhiá»u cÆ¡ sở để hòa trá»™n, nên dùng %s"
+msgstr "%s...%s: có nhiá»u gốc hòa trá»™n, sẽ dùng %s"
msgid "git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"
msgstr ""
"git difftool [<các tùy chá»n>] [<lần_chuyển_giao> [<lần_chuyển_giao>]] [--] </"
-"đưá»ng/dẫn>…]"
+"đưá»ng/dẫn>...]"
#, c-format
msgid "could not read symlink %s"
@@ -5415,23 +5723,23 @@ msgid ""
"combined diff formats ('-c' and '--cc') are not supported in\n"
"directory diff mode ('-d' and '--dir-diff')."
msgstr ""
-"các định dạng diff tổ hợp(“-c†và “--ccâ€) chưa được há»— trợ trong\n"
-"chế độ diff thư mục(“-d†và “--dir-diffâ€)."
+"các định dạng diff tổ hợp('-c' và '--cc') chưa được hỗ trợ trong\n"
+"chế độ diff thư mục('-d' và '--dir-diff')."
#, c-format
msgid "both files modified: '%s' and '%s'."
-msgstr "cả hai tập tin đã bị sá»­a: “%s†và “%sâ€."
+msgstr "cả hai tập tin đã bị sửa: '%s' và '%s'."
msgid "working tree file has been left."
msgstr "cây làm việc ở bên trái."
#, c-format
msgid "could not copy '%s' to '%s'"
-msgstr "không thể chép “%s†sang “%sâ€"
+msgstr "không thể chép '%s' sang '%s'"
#, c-format
msgid "temporary files exist in '%s'."
-msgstr "các tập tin tạm đã sẵn có trong “%sâ€."
+msgstr "các tập tin tạm đã sẵn có trong '%s'."
msgid "you may want to cleanup or recover these."
msgstr "bạn có lẽ muốn dá»n dẹp hay phục hồi ở đây."
@@ -5441,7 +5749,7 @@ msgid "failed: %d"
msgstr "gặp lỗi: %d"
msgid "use `diff.guitool` instead of `diff.tool`"
-msgstr "dùng “diff.guitool“ thay vì dùng “diff.tool“"
+msgstr "dùng 'diff.guitool' thay vì dùng 'diff.tool'"
msgid "perform a full-directory diff"
msgstr "thực hiện một diff toàn thư mục"
@@ -5459,18 +5767,18 @@ msgid "use the specified diff tool"
msgstr "dùng công cụ diff đã cho"
msgid "print a list of diff tools that may be used with `--tool`"
-msgstr "in ra danh sách các công cụ dif cái mà có thẻ dùng với “--tool“"
+msgstr "in ra danh sách các công cụ dif cái mà có thẻ dùng với '--tool'"
msgid ""
"make 'git-difftool' exit when an invoked diff tool returns a non-zero exit "
"code"
-msgstr "làm cho “git-difftool†thoát khi gá»i công cụ diff trả vá» mã khác không"
+msgstr "làm cho 'git-difftool' thoát khi gá»i công cụ diff trả vá» mã khác không"
msgid "specify a custom command for viewing diffs"
msgstr "chỉ định một lệnh tùy ý để xem diff"
msgid "passed to `diff`"
-msgstr "chuyển cho “diffâ€"
+msgstr "chuyển cho 'diff'"
msgid "difftool requires worktree or --no-index"
msgstr "difftool cần cây làm việc hoặc --no-index"
@@ -5481,28 +5789,6 @@ msgstr "chưa đưa ra <công_cụ> cho --tool=<công_cụ>"
msgid "no <cmd> given for --extcmd=<cmd>"
msgstr "chưa đưa ra <lệnh> cho --extcmd=<lệnh>"
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <các tùy chá»n> <env-var>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "mặc định cho git_env_*(…) để quay vá»"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "im lặng chỉ khi dung giá trị git_env_*() làm mã thoát"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"tùy chá»n “--default†cần má»™t giá trị logic vá»›i “--type=bool“, không phải “%s“"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not `"
-"%s`"
-msgstr ""
-"tùy chá»n “--default†cần má»™t giá trị số nguyên dài không dấu vá»›i “--"
-"type=ulong“, không phải “%s“"
-
msgid "git fast-export [<rev-list-opts>]"
msgstr "git fast-export [<rev-list-opts>]"
@@ -5541,10 +5827,10 @@ msgid "output full tree for each commit"
msgstr "xuất ra toàn bộ cây cho mỗi lần chuyển giao"
msgid "use the done feature to terminate the stream"
-msgstr "sử dụng tính năng done để chấm dứt luồng dữ liệu"
+msgstr "sử dụng tính năng done để kết thúc luồng dữ liệu"
msgid "skip output of blob data"
-msgstr "bỠqua kết xuất của dữ liệu blob"
+msgstr "bỠqua đầu ra của dữ liệu blob"
msgid "refspec"
msgstr "refspec"
@@ -5553,7 +5839,7 @@ msgid "apply refspec to exported refs"
msgstr "áp dụng refspec cho refs đã xuất"
msgid "anonymize output"
-msgstr "kết xuất anonymize"
+msgstr "ẩn danh đầu ra"
msgid "from:to"
msgstr "từ:đến"
@@ -5574,40 +5860,40 @@ msgstr "gắn thẻ với các mã ID đánh dấu"
#, c-format
msgid "Missing from marks for submodule '%s'"
-msgstr "Thiếu các đánh dấu cho mô-Ä‘un-con “%sâ€"
+msgstr "Thiếu các đánh dấu cho mô-đun-con '%s'"
#, c-format
msgid "Missing to marks for submodule '%s'"
-msgstr "Thiếu đánh dấu cho mô-Ä‘un-con “%sâ€"
+msgstr "Thiếu đánh dấu cho mô-đun-con '%s'"
#, c-format
msgid "Expected 'mark' command, got %s"
-msgstr "Cần lệnh “markâ€, nhưng lại nhận được %s"
+msgstr "Cần lệnh 'mark', nhưng lại có %s"
#, c-format
msgid "Expected 'to' command, got %s"
-msgstr "Cần lệnh “toâ€, nhưng lại nhận được %s"
+msgstr "Cần lệnh 'to', nhưng lại có %s"
msgid "Expected format name:filename for submodule rewrite option"
-msgstr "Cần định dạng tên:tên_tập_tin cho tùy chá»n ghi lại mô-Ä‘un-con"
+msgstr "Cần định dạng tên:tên_tập tin cho tùy chá»n ghi lại mô-Ä‘un-con"
#, c-format
msgid "feature '%s' forbidden in input without --allow-unsafe-features"
msgstr ""
-"tính năng “%s†bị cấm chỉ trong đầu vào mà không có --allow-unsafe-features"
+"tính năng '%s' bị cấm chỉ trong đầu vào mà không có --allow-unsafe-features"
#, c-format
msgid "Lockfile created but not reported: %s"
msgstr "Tập tin khóa đã được tạo nhưng chưa được báo cáo: %s"
msgid "git fetch [<options>] [<repository> [<refspec>...]]"
-msgstr "git fetch [<các tùy chá»n>] [<kho-chứa> [<refspec>…]]"
+msgstr "git fetch [<các tùy chá»n>] [<kho-chứa> [<refspec>...]]"
msgid "git fetch [<options>] <group>"
msgstr "git fetch [<các tùy chá»n>] [<nhóm>"
msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
-msgstr "git fetch --multiple [<các tùy chá»n>] [(<kho> | <nhóm>)…]"
+msgstr "git fetch --multiple [<các tùy chá»n>] [(<kho> | <nhóm>)...]"
msgid "git fetch --all [<options>]"
msgstr "git fetch --all [<các tùy chá»n>]"
@@ -5615,118 +5901,14 @@ msgstr "git fetch --all [<các tùy chá»n>]"
msgid "fetch.parallel cannot be negative"
msgstr "fetch.parallel không thể âm"
-msgid "fetch from all remotes"
-msgstr "lấy vỠtừ tất cả các máy chủ"
-
-msgid "set upstream for git pull/fetch"
-msgstr "đặt thượng nguồn cho git pull/fetch"
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "nối thêm vào .git/FETCH_HEAD thay vì ghi đè lên nó"
-
-msgid "use atomic transaction to update references"
-msgstr "sử dụng giao dịch hạt nhân bên phía máy chủ"
-
-msgid "path to upload pack on remote end"
-msgstr "đưá»ng dẫn đến gói tải lên trên máy chá»§ cuối"
-
-msgid "force overwrite of local reference"
-msgstr "ép buộc ghi đè lên tham chiếu nội bộ"
-
-msgid "fetch from multiple remotes"
-msgstr "lấy từ nhiá»u máy chá»§ cùng lúc"
-
-msgid "fetch all tags and associated objects"
-msgstr "lấy tất cả các thẻ cùng với các đối tượng liên quan đến nó"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "không lấy tất cả các thẻ (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "số lượng mô-Ä‘un-con được lấy đồng thá»i"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-"sá»­a đặc tả đưá»ng dẫn cho các tham chiếu má»i chá»— có trong refs/prefetch/"
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr ""
-"cắt cụt (prune) các nhánh “remote-tracking†không còn tồn tại trên máy chủ "
-"nữa"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr "cắt xém các thẻ nội bộ không còn ở máy chủ và xóa các thẻ đã thay đổi"
-
-msgid "on-demand"
-msgstr "khi-cần"
-
-msgid "control recursive fetching of submodules"
-msgstr "Ä‘iá»u khiển việc lấy vỠđệ quy trong các mô-Ä‘un-con"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr "ghi các tham chiếu lấy vỠvào tập tin FETCH_HEAD"
-
-msgid "keep downloaded pack"
-msgstr "giữ lại gói đã tải vá»"
-
-msgid "allow updating of HEAD ref"
-msgstr "cho phép cập nhật th.chiếu HEAD"
-
-msgid "deepen history of shallow clone"
-msgstr "làm sâu hơn lịch sử của bản sao"
-
-msgid "deepen history of shallow repository based on time"
-msgstr "làm sâu hÆ¡n lịch sá»­ cá»§a kho bản sao shallow dá»±a trên thá»i gian"
-
-msgid "convert to a complete repository"
-msgstr "chuyển đổi hoàn toàn sang kho git"
-
-msgid "re-fetch without negotiating common commits"
-msgstr "re-fetch mà không dàn xếp các lần chuyển giao chung"
-
-msgid "prepend this to submodule path output"
-msgstr "soạn sẵn cái này cho kết xuất đưá»ng dẫn mô-Ä‘un-con"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"mặc định cho việc lấy đệ quy các mô-đun-con (có mức ưu tiên thấp hơn các tập "
-"tin cấu hình config)"
-
-msgid "accept refs that update .git/shallow"
-msgstr "chấp nhận tham chiếu cập nhật .git/shallow"
-
-msgid "refmap"
-msgstr "refmap"
-
-msgid "specify fetch refmap"
-msgstr "chỉ ra refmap cần lấy vá»"
-
-msgid "report that we have only objects reachable from this object"
-msgstr ""
-"báo cáo rằng chúng ta chỉ có các đối tượng tiếp cận được từ đối tượng này"
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-"không lấy vỠmột packfile; thay vào đó, hãy in tổ tiên của đỉnh đàm phán"
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr "chạy “maintenance --auto†sau khi lấy vá»"
-
-msgid "check for forced-updates on all updated branches"
-msgstr "kiểm cho các-cập-nhật-bắt-buá»™c trên má»i nhánh đã cập nhật"
-
-msgid "write the commit-graph after fetching"
-msgstr "ghi ra đồ thị các lần chuyển giao sau khi lấy vá»"
-
-msgid "accept refspecs from stdin"
-msgstr "chấp nhận tham chiếu từ đầu vào tiêu chuẩn"
-
msgid "couldn't find remote ref HEAD"
msgstr "không thể tìm thấy HEAD tham chiếu máy chủ"
#, c-format
+msgid "From %.*s\n"
+msgstr "Từ %.*s\n"
+
+#, c-format
msgid "object %s not found"
msgstr "không tìm thấy đối tượng %s"
@@ -5736,11 +5918,8 @@ msgstr "[đã cập nhật]"
msgid "[rejected]"
msgstr "[Bị từ chối]"
-msgid "can't fetch in current branch"
-msgstr "không thể fetch (lấy) vỠnhánh hiện hành"
-
-msgid "checked out in another worktree"
-msgstr "lấy ra trong cây làm việc khác"
+msgid "can't fetch into checked-out branch"
+msgstr "không thể fetch vỠnhánh đã checkout"
msgid "[tag update]"
msgstr "[cập nhật thẻ]"
@@ -5768,7 +5947,7 @@ msgstr "không-phải-chuyển-tiếp-nhanh"
#, c-format
msgid "cannot open '%s'"
-msgstr "không mở được “%sâ€"
+msgstr "không mở được '%s'"
msgid ""
"fetch normally indicates which branches had a forced update,\n"
@@ -5777,7 +5956,7 @@ msgid ""
msgstr ""
"việc lấy vá» thưá»ng chỉ ra các nhánh buá»™c phải cập nhật,\n"
"nhưng lá»±a chá»n bị tắt; để kích hoạt lại, sá»­ dụng cá»\n"
-"“--show-forced-updates†hoặc chạy “git config fetch.showForcedUpdates trueâ€."
+"'--show-forced-updates' hoặc chạy 'git config fetch.showForcedUpdates true'."
#, c-format
msgid ""
@@ -5787,29 +5966,25 @@ msgid ""
"to avoid this check\n"
msgstr ""
"việc này cần %.2f giây để kiểm tra các cập nhật ép buộc; bạn có thể dùng\n"
-"“--no-show-forced-updates†hoặc chạy “git config fetch.showForcedUpdates "
-"falseâ€\n"
+"'--no-show-forced-updates' hoặc chạy 'git config fetch.showForcedUpdates "
+"false'\n"
"để tránh kiểm tra này\n"
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s đã không gửi tất cả các đối tượng cần thiết\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s đã không gửi tất cả các đối tượng cần thiết"
#, c-format
msgid "rejected %s because shallow roots are not allowed to be updated"
msgstr "từ chối %s bởi vì các gốc nông thì không được phép cập nhật"
#, c-format
-msgid "From %.*s\n"
-msgstr "Từ %.*s\n"
-
-#, c-format
msgid ""
"some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting branches"
msgstr ""
"một số tham chiếu nội bộ không thể được cập nhật; hãy thử chạy\n"
-" “git remote prune %s†để bỠđi những nhánh cũ, hay bị xung đột"
+" 'git remote prune %s' để bỠđi những nhánh cũ, hay bị xung đột"
#, c-format
msgid " (%s will become dangling)"
@@ -5827,15 +6002,15 @@ msgstr "(không)"
#, c-format
msgid "refusing to fetch into branch '%s' checked out at '%s'"
-msgstr "từ chối lấy vá» vào nhánh “%s†đã được lấy ra tại “%sâ€"
+msgstr "từ chối lấy vỠvào nhánh '%s' đã được checkout tại '%s'"
#, c-format
msgid "option \"%s\" value \"%s\" is not valid for %s"
msgstr "tùy chá»n \"%s\" có giá trị \"%s\" là không hợp lệ cho %s"
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "tùy chá»n \"%s\" bị bá» qua vá»›i %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "tùy chá»n \"%s\" bị bá» qua vá»›i %s"
#, c-format
msgid "%s is not a valid object"
@@ -5843,7 +6018,7 @@ msgstr "%s không phải là một đối tượng hợp lệ"
#, c-format
msgid "the object %s does not exist"
-msgstr "đối tượng “%s†không tồn tại"
+msgstr "đối tượng '%s' không tồn tại"
msgid "multiple branches detected, incompatible with --set-upstream"
msgstr "phát hiện nhiá»u nhánh, không tương thích vá»›i --set-upstream"
@@ -5874,15 +6049,15 @@ msgstr ""
#, c-format
msgid "Fetching %s\n"
-msgstr "Äang lấy “%s†vá»\n"
+msgstr "Äang lấy '%s' vá»\n"
#, c-format
msgid "could not fetch %s"
-msgstr "không thể lấy “%s†vá»"
+msgstr "không thể lấy '%s' vá»"
#, c-format
msgid "could not fetch '%s' (exit code: %d)\n"
-msgstr "không thể lấy “%s†(mã thoát: %d)\n"
+msgstr "không thể lấy '%s' (mã thoát: %d)\n"
msgid ""
"no remote repository specified; please specify either a URL or a\n"
@@ -5894,6 +6069,113 @@ msgstr ""
msgid "you need to specify a tag name"
msgstr "bạn cần chỉ định một tên thẻ"
+msgid "fetch from all remotes"
+msgstr "lấy vỠtừ tất cả các máy chủ"
+
+msgid "set upstream for git pull/fetch"
+msgstr "đặt thượng nguồn cho git pull/fetch"
+
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "nối thêm vào .git/FETCH_HEAD thay vì ghi đè lên nó"
+
+msgid "use atomic transaction to update references"
+msgstr "sử dụng giao dịch hạt nhân bên phía máy chủ"
+
+msgid "path to upload pack on remote end"
+msgstr "đưá»ng dẫn đến gói tải lên trên máy chá»§ cuối"
+
+msgid "force overwrite of local reference"
+msgstr "ép buộc ghi đè lên tham chiếu nội bộ"
+
+msgid "fetch from multiple remotes"
+msgstr "lấy từ nhiá»u máy chá»§ cùng lúc"
+
+msgid "fetch all tags and associated objects"
+msgstr "lấy tất cả các thẻ cùng với các đối tượng liên quan đến nó"
+
+msgid "do not fetch all tags (--no-tags)"
+msgstr "không lấy tất cả các thẻ (--no-tags)"
+
+msgid "number of submodules fetched in parallel"
+msgstr "số lượng mô-Ä‘un-con được lấy đồng thá»i"
+
+msgid "modify the refspec to place all refs within refs/prefetch/"
+msgstr ""
+"sá»­a đặc tả đưá»ng dẫn cho các tham chiếu má»i chá»— có trong refs/prefetch/"
+
+msgid "prune remote-tracking branches no longer on remote"
+msgstr ""
+"cắt (prune) các nhánh 'remote-tracking' không còn tồn tại trên máy chủ nữa"
+
+msgid "prune local tags no longer on remote and clobber changed tags"
+msgstr ""
+"xoá (prune) các thẻ nội bộ không còn ở máy chủ và xóa các thẻ đã thay đổi"
+
+msgid "on-demand"
+msgstr "khi-cần"
+
+msgid "control recursive fetching of submodules"
+msgstr "Ä‘iá»u khiển việc lấy vỠđệ quy trong các mô-Ä‘un-con"
+
+msgid "write fetched references to the FETCH_HEAD file"
+msgstr "ghi các tham chiếu lấy vỠvào tập tin FETCH_HEAD"
+
+msgid "keep downloaded pack"
+msgstr "giữ lại gói đã tải vá»"
+
+msgid "allow updating of HEAD ref"
+msgstr "cho phép cập nhật th.chiếu HEAD"
+
+msgid "deepen history of shallow clone"
+msgstr "làm sâu hơn lịch sử của bản sao"
+
+msgid "deepen history of shallow repository based on time"
+msgstr "làm sâu hÆ¡n lịch sá»­ cá»§a kho bản sao shallow dá»±a trên thá»i gian"
+
+msgid "convert to a complete repository"
+msgstr "chuyển đổi hoàn toàn sang kho git"
+
+msgid "re-fetch without negotiating common commits"
+msgstr "re-fetch mà không dàn xếp các lần chuyển giao chung"
+
+msgid "prepend this to submodule path output"
+msgstr "soạn sẵn cái này cho đầu ra đưá»ng dẫn mô-Ä‘un-con"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"mặc định cho việc lấy đệ quy các mô-đun-con (có mức ưu tiên thấp hơn các tập "
+"tin cấu hình config)"
+
+msgid "accept refs that update .git/shallow"
+msgstr "chấp nhận tham chiếu cập nhật .git/shallow"
+
+msgid "refmap"
+msgstr "refmap"
+
+msgid "specify fetch refmap"
+msgstr "chỉ ra refmap cần lấy vá»"
+
+msgid "report that we have only objects reachable from this object"
+msgstr "báo rằng ta chỉ có các đối tượng tiếp cận được từ đối tượng này"
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+"không lấy vỠmột packfile; thay vào đó, hãy in tổ tiên của đỉnh đàm phán"
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr "chạy 'maintenance --auto' sau khi lấy vá»"
+
+msgid "check for forced-updates on all updated branches"
+msgstr "kiểm cho các-cập-nhật-bắt-buá»™c trên má»i nhánh đã cập nhật"
+
+msgid "write the commit-graph after fetching"
+msgstr "ghi ra đồ thị các lần chuyển giao sau khi lấy vá»"
+
+msgid "accept refspecs from stdin"
+msgstr "chấp nhận tham chiếu từ stdin"
+
msgid "--negotiate-only needs one or more --negotiation-tip=*"
msgstr "--negotiate-only cần má»™t hay nhiá»u --negotiation-tip=* hÆ¡n"
@@ -5903,6 +6185,10 @@ msgstr "mức sâu là số âm trong --deepen là không được hỗ trợ"
msgid "--unshallow on a complete repository does not make sense"
msgstr "--unshallow trên kho hoàn chỉnh là không hợp lý"
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "gặp lỗi khi lấy vỠbundle từ '%s'"
+
msgid "fetch --all does not take a repository argument"
msgstr "lệnh lấy vỠ\"fetch --all\" không lấy đối số kho chứa"
@@ -5942,16 +6228,16 @@ msgstr ""
"tin>]"
msgid "populate log with at most <n> entries from shortlog"
-msgstr "gắn nhật ký vá»›i ít nhất <n> mục từ lệnh “shortlogâ€"
+msgstr "gắn nhật ký với ít nhất <n> mục từ lệnh 'shortlog'"
msgid "alias for --log (deprecated)"
-msgstr "bí danh cho --log (không được dùng)"
+msgstr "đồng nghĩa với --log (đã không còn)"
msgid "text"
msgstr "văn bản"
msgid "use <text> as start of message"
-msgstr "dùng <văn bản thưá»ng> để bắt đầu ghi chú"
+msgstr "dùng <văn bản> để bắt đầu ghi chú"
msgid "use <name> instead of the real target branch"
msgstr "dùng <tên> thay cho nhánh đích thật"
@@ -5976,16 +6262,16 @@ msgstr ""
"chuyển-giao>]]"
msgid "quote placeholders suitably for shells"
-msgstr "trích dẫn để phù hợp cho hệ vỠ(shell)"
+msgstr "trích dẫn dạng phù hợp cho shell"
msgid "quote placeholders suitably for perl"
-msgstr "trích dẫn để phù hợp cho perl"
+msgstr "trích dẫn dạng phù hợp cho perl"
msgid "quote placeholders suitably for python"
-msgstr "trích dẫn để phù hợp cho python"
+msgstr "trích dẫn dạng phù hợp cho python"
msgid "quote placeholders suitably for Tcl"
-msgstr "trích dẫn để phù hợp cho Tcl"
+msgstr "trích dẫn dạng phù hợp cho Tcl"
msgid "show only <n> matched refs"
msgstr "hiển thị chỉ <n> tham chiếu khớp"
@@ -6008,8 +6294,17 @@ msgstr "chỉ hiển thị những tham chiếu mà nó chứa lần chuyển gi
msgid "print only refs which don't contain the commit"
msgstr "chỉ hiển thị những tham chiếu mà nó không chứa lần chuyển giao"
-msgid "git for-each-repo --config=<config> <command-args>"
-msgstr "git for-each-repo --config=<config> <command-args>"
+msgid "read reference patterns from stdin"
+msgstr "Ä‘á»c các mẫu tham chiếu từ stdin"
+
+msgid "also include HEAD ref and pseudorefs"
+msgstr "bao gồm tham chiếu HEAD và giả tham chiếu"
+
+msgid "unknown arguments supplied with --stdin"
+msgstr "đối số không rõ được chỉ định cùng với --stdin"
+
+msgid "git for-each-repo --config=<config> [--] <arguments>"
+msgstr "git for-each-repo --config=<tùy chá»n> [--] <đối số>"
msgid "config"
msgstr "config"
@@ -6017,9 +6312,16 @@ msgstr "config"
msgid "config key storing a list of repository paths"
msgstr "khóa cấu hình lưu trữ danh sách đưá»ng dẫn kho lưu trữ"
+msgid "keep going even if command fails in a repository"
+msgstr "tiếp tục dù có lệnh thất bại trong kho chứa"
+
msgid "missing --config=<config>"
msgstr "thiếu --config=<config>"
+#, c-format
+msgid "got bad config --config=%s"
+msgstr "cấu hình sai --config=%s"
+
msgid "unknown"
msgstr "không hiểu"
@@ -6035,7 +6337,7 @@ msgstr "có cảnh báo trong %s %s: %s"
#, c-format
msgid "broken link from %7s %s"
-msgstr "liên kết gãy từ %7s %s"
+msgstr "liên kết há»ng từ %7s %s"
msgid "wrong object type in link"
msgstr "kiểu đối tượng sai trong liên kết"
@@ -6045,7 +6347,7 @@ msgid ""
"broken link from %7s %s\n"
" to %7s %s"
msgstr ""
-"liên kết gãy từ %7s %s \n"
+"liên kết há»ng từ %7s %s \n"
" tá»›i %7s %s"
msgid "Checking connectivity"
@@ -6068,11 +6370,11 @@ msgstr "không thể tạo lost-found"
#, c-format
msgid "could not write '%s'"
-msgstr "không thể ghi “%sâ€"
+msgstr "không thể ghi '%s'"
#, c-format
msgid "could not finish '%s'"
-msgstr "không thể hoàn thành “%sâ€"
+msgstr "không thể hoàn thành '%s'"
#, c-format
msgid "Checking %s"
@@ -6087,7 +6389,7 @@ msgid "Checking %s %s"
msgstr "Äang kiểm tra %s %s"
msgid "broken links"
-msgstr "các liên kết bị gẫy"
+msgstr "liên kết há»ng"
#, c-format
msgid "root %s"
@@ -6107,7 +6409,7 @@ msgstr "%s: mục reflog không hợp lệ %s"
#, c-format
msgid "Checking reflog %s->%s"
-msgstr "Äang kiểm tra việc đổi tên cá»§a “%s†thành “%sâ€"
+msgstr "Äang kiểm tra việc đổi tên cá»§a '%s' thành '%s'"
#, c-format
msgid "%s: invalid sha1 pointer %s"
@@ -6130,11 +6432,11 @@ msgstr "%s: thiếu đối tượng hoặc há»ng: %s"
#, c-format
msgid "%s: object is of unknown type '%s': %s"
-msgstr "%s: đối tượng có kiểu chưa biết “%sâ€: %s"
+msgstr "%s: đối tượng có kiểu chưa biết '%s': %s"
#, c-format
msgid "%s: object could not be parsed: %s"
-msgstr "%s: không thể phân tích cú đối tượng: %s"
+msgstr "%s: không thể Ä‘á»c cú đối tượng: %s"
#, c-format
msgid "bad sha1 file: %s"
@@ -6166,36 +6468,57 @@ msgstr "%s: HEAD đã tách rá»i không chỉ vào đâu cả"
msgid "notice: %s points to an unborn branch (%s)"
msgstr "chú ý: %s chỉ đến một nhánh chưa sinh (%s)"
-msgid "Checking cache tree"
-msgstr "Äang kiểm tra cây nhá»› tạm"
+#, c-format
+msgid "Checking cache tree of %s"
+msgstr "Äang kiểm tra cây nhá»› tạm cá»§a %s"
#, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
-msgstr "%s: con trỠsha1 không hợp lệ trong cache-tree"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
+msgstr "%s: con trỠsha1 không hợp lệ trong cây nhớ tạm của %s"
msgid "non-tree in cache-tree"
msgstr "non-tree trong cache-tree"
-msgid "git fsck [<options>] [<object>...]"
-msgstr "git fsck [<các tùy chá»n>] [<đối-tượng>…]"
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr "%s: con trỠsha1 không hợp lệ trong resolve-undo của %s"
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr "không thể tải pack-index cho gói '%s'"
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr "giá trị rev-index cho gói '%s' không hợp lệ"
+
+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] [<đối tượng>...]"
msgid "show unreachable objects"
-msgstr "hiển thị các đối tượng không thể Ä‘á»c được"
+msgstr "hiển thị các đối tượng không thể tới được"
msgid "show dangling objects"
msgstr "hiển thị các đối tượng không được quản lý"
msgid "report tags"
-msgstr "báo cáo các thẻ"
+msgstr "liệt kê các thẻ"
msgid "report root nodes"
-msgstr "báo cáo node gốc"
+msgstr "liệt kê node gốc"
msgid "make index objects head nodes"
-msgstr "tạo “index objects head nodesâ€"
+msgstr "tạo 'index objects head nodes'"
msgid "make reflogs head nodes (default)"
-msgstr "tạo “reflogs head nodes†(mặc định)"
+msgstr "tạo 'reflogs head nodes' (mặc định)"
msgid "also consider packs and alternate objects"
msgstr "cũng cân nhắc đến các đối tượng gói và thay thế"
@@ -6224,7 +6547,7 @@ msgstr "%s: thiếu đối tượng"
#, c-format
msgid "invalid parameter: expected sha1, got '%s'"
-msgstr "tham số không hợp lệ: cần sha1, nhưng lại nhận được “%sâ€"
+msgstr "tham số không hợp lệ: cần sha1, nhưng lại có '%s'"
msgid "git fsmonitor--daemon start [<options>]"
msgstr "git fsmonitor--daemon start [<các tùy chá»n>]"
@@ -6232,15 +6555,9 @@ msgstr "git fsmonitor--daemon start [<các tùy chá»n>]"
msgid "git fsmonitor--daemon run [<options>]"
msgstr "git fsmonitor--daemon run [<các tùy chá»n>]"
-msgid "git fsmonitor--daemon stop"
-msgstr "git fsmonitor--daemon stop"
-
-msgid "git fsmonitor--daemon status"
-msgstr "git fsmonitor--daemon status"
-
#, c-format
msgid "value of '%s' out of range: %d"
-msgstr "siá trị '%s' ngoài phạm vi cho phép: %d"
+msgstr "giá trị '%s' ngoài phạm vi cho phép: %d"
#, c-format
msgid "value of '%s' not bool or int: %d"
@@ -6256,7 +6573,7 @@ msgstr "fsmonitor-daemon hiện không theo dõi '%s'\n"
#, c-format
msgid "could not create fsmonitor cookie '%s'"
-msgstr "không thể tạo fsmonitor cookie “%sâ€"
+msgstr "không thể tạo fsmonitor cookie '%s'"
#, c-format
msgid "fsmonitor: cookie_result '%d' != SEEN"
@@ -6264,24 +6581,23 @@ msgstr "fsmonitor: cookie_result '%d' != SEEN"
#, c-format
msgid "could not start IPC thread pool on '%s'"
-msgstr "không thể khởi chạy bể tiến trình IPC trêm “%sâ€"
+msgstr "không thể khởi chạy pool tiến trình IPC trên '%s'"
msgid "could not start fsmonitor listener thread"
-msgstr "không thể lấy thông tin thống kê vỠtuyến trình lắng nghe fsmonitor"
+msgstr "không thể khởi chạy fsmonitor listener thread"
msgid "could not start fsmonitor health thread"
-msgstr ""
-"không thể lấy thông tin thống kê vá» tuyến trình theo dõi sức khá»e fsmonitor"
+msgstr "không thể khởi chạy fsmonitor health thread"
msgid "could not initialize listener thread"
-msgstr "không thể khởi tạo tuyến trình lắng nghe"
+msgstr "không thể khởi tạo listener thread"
msgid "could not initialize health thread"
-msgstr "không thể khởi tạo tuyến trình sức "
+msgstr "không thể khởi tạo health thread"
#, c-format
msgid "could not cd home '%s'"
-msgstr "không thể chuyển đến thư mục cá nhân “%sâ€"
+msgstr "không thể cd home '%s'"
#, c-format
msgid "fsmonitor--daemon is already running '%s'"
@@ -6293,7 +6609,7 @@ msgstr "chạy fsmonitor-daemon trong '%s'\n"
#, c-format
msgid "starting fsmonitor-daemon in '%s'\n"
-msgstr "Ä‘ang khởi chạy fsmonitor-daemon trong “%sâ€\n"
+msgstr "đang khởi chạy fsmonitor-daemon trong '%s'\n"
msgid "daemon failed to start"
msgstr "gặp lỗi khi khởi chạy dịch vụ chạy ngầm"
@@ -6329,15 +6645,15 @@ msgstr "git gc [<các tùy chá»n>]"
#, c-format
msgid "Failed to fstat %s: %s"
-msgstr "Gặp lỗi khi lấy thông tin thống kê vỠtập tin %s: %s"
+msgstr "Gặp lỗi khi fstat %s: %s"
#, c-format
msgid "failed to parse '%s' value '%s'"
-msgstr "gặp lá»—i khi phân tích “%s†giá trị “%sâ€"
+msgstr "gặp lá»—i khi Ä‘á»c '%s' giá trị '%s'"
#, c-format
msgid "cannot stat '%s'"
-msgstr "không thể lấy thông tin thống kê vỠ“%sâ€"
+msgstr "không thể stat '%s'"
#, c-format
msgid ""
@@ -6359,11 +6675,17 @@ msgstr "xóa bỠcác đối tượng không được tham chiếu"
msgid "pack unreferenced objects separately"
msgstr "đóng gói riêng các đối tượng không được tham chiếu"
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "vá»›i tuỳ chá»n --cruft, giá»›i hạn kích thước pack cruft má»›i"
+
msgid "be more thorough (increased runtime)"
msgstr "cẩn thận hÆ¡n nữa (tăng thá»i gian chạy)"
msgid "enable auto-gc mode"
-msgstr "bật chế độ auto-gc"
+msgstr "bật chế độ auto-gc (tá»± động dá»n rác)"
+
+msgid "perform garbage collection in the background"
+msgstr "tiến hành gc (dá»n rác) trong ná»n"
msgid "force running gc even if there may be another gc running"
msgstr "buộc gc chạy ngay cả khi có tiến trình gc khác đang chạy"
@@ -6373,11 +6695,11 @@ msgstr "đóng gói lại tất cả các gói khác ngoại trừ gói lớn nh
#, c-format
msgid "failed to parse gc.logExpiry value %s"
-msgstr "gặp lỗi khi phân tích giá trị gc.logExpiry %s"
+msgstr "gặp lá»—i khi Ä‘á»c giá trị gc.logExpiry %s"
#, c-format
msgid "failed to parse prune expiry value %s"
-msgstr "gặp lỗi khi phân tích giá trị prune %s"
+msgstr "gặp lá»—i khi Ä‘á»c giá trị prune %s"
#, c-format
msgid "Auto packing the repository in background for optimum performance.\n"
@@ -6397,13 +6719,13 @@ msgstr "Xem \"git help gc\" để có hướng dẫn cụ thể vá» cách dá»n
msgid ""
"gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
msgstr ""
-"gc đang được thực hiện trên máy “%s†pid %<PRIuMAX> (dùng --force nếu không "
+"gc đang được thực hiện trên máy '%s' pid %<PRIuMAX> (dùng --force nếu không "
"phải thế)"
msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
-"Có quá nhiá»u đối tượng tá»± do không được dùng đến; hãy chạy lệnh “git prune†"
+"Có quá nhiá»u đối tượng tá»± do không được dùng đến; hãy chạy lệnh 'git prune' "
"để xóa bỠchúng đi."
msgid ""
@@ -6425,19 +6747,19 @@ msgid "failed to prefetch remotes"
msgstr "gặp lỗi khi tải trước các máy chủ"
msgid "failed to start 'git pack-objects' process"
-msgstr "gặp lá»—i khi lấy thông tin thống kê vá» tiến trình “git pack-objectsâ€"
+msgstr "gặp lỗi khi khởi chạy tiến trình 'git pack-objects'"
msgid "failed to finish 'git pack-objects' process"
-msgstr "gặp lá»—i khi hoàn tất tiến trình “git pack-objectsâ€"
+msgstr "gặp lỗi khi hoàn tất tiến trình 'git pack-objects'"
msgid "failed to write multi-pack-index"
msgstr "gặp lỗi khi ghi multi-pack-index"
msgid "'git multi-pack-index expire' failed"
-msgstr "gặp lá»—i khi chạy “git multi-pack-index expireâ€"
+msgstr "gặp lỗi khi chạy 'git multi-pack-index expire'"
msgid "'git multi-pack-index repack' failed"
-msgstr "gặp lá»—i khi chạy “git multi-pack-index repackâ€"
+msgstr "gặp lỗi khi chạy 'git multi-pack-index repack'"
msgid ""
"skipping incremental-repack task because core.multiPackIndex is disabled"
@@ -6445,23 +6767,26 @@ msgstr "bỠqua tác vụ incremental-repack vì core.multiPackIndex bị vô h
#, c-format
msgid "lock file '%s' exists, skipping maintenance"
-msgstr "đã có khóa cá»§a tập tin “%sâ€, bá» qua bảo trì"
+msgstr "đã có khóa của tập tin '%s', bỠqua bảo trì"
#, c-format
msgid "task '%s' failed"
-msgstr "gặp lá»—i khi thá»±c hiện nhiệm vụ “%sâ€"
+msgstr "gặp lỗi khi thực hiện nhiệm vụ '%s'"
#, c-format
msgid "'%s' is not a valid task"
-msgstr "“%s†không phải một nhiệm vụ hợp lệ"
+msgstr "'%s' không phải một nhiệm vụ hợp lệ"
#, c-format
msgid "task '%s' cannot be selected multiple times"
-msgstr "nhiệm vụ “%s†không được chá»n nhiá»u lần"
+msgstr "nhiệm vụ '%s' không được chá»n nhiá»u lần"
msgid "run tasks based on the state of the repository"
msgstr "chạy nhiệm vụ dựa trên trạng thái của kho chứa"
+msgid "perform maintenance in the background"
+msgstr "tiến hành bảo trì trong ná»n"
+
msgid "frequency"
msgstr "tần số"
@@ -6469,7 +6794,7 @@ msgid "run tasks based on frequency"
msgstr "chạy nhiệm vụ dựa trên tần suất"
msgid "do not report progress or other information over stderr"
-msgstr "đừng báo cáo diễn tiến hay các thông tin khác ra đầu lỗi tiêu chuẩn"
+msgstr "đừng báo cáo tiến độ hay các thông tin khác ra stderr"
msgid "task"
msgstr "tác vụ"
@@ -6480,12 +6805,24 @@ msgstr "chạy một nhiệm vụ cụ thể"
msgid "use at most one of --auto and --schedule=<frequency>"
msgstr "dùng nhiá»u nhất là má»™t trong --auto và --schedule=<frequency>"
-msgid "failed to run 'git config'"
-msgstr "gặp lá»—i khi chạy “git configâ€"
+#, c-format
+msgid "unable to add '%s' value of '%s'"
+msgstr "không thể thêm giá trị '%s' của '%s'"
+
+msgid "return success even if repository was not registered"
+msgstr "trả vỠthành công kể cả khi kho chứa chưa được ghi nhận"
+
+#, c-format
+msgid "unable to unset '%s' value of '%s'"
+msgstr "không thể bỠđặt giá trị '%s' của '%s'"
+
+#, c-format
+msgid "repository '%s' is not registered"
+msgstr "kho chứa '%s' chưa tồn tại"
#, c-format
msgid "failed to expand path '%s'"
-msgstr "gặp lá»—i khi khai triển đưá»ng dẫn “%sâ€"
+msgstr "gặp lá»—i khi khai triển đưá»ng dẫn '%s'"
msgid "failed to start launchctl"
msgstr "gặp lỗi khi khởi chạy launchctl"
@@ -6502,38 +6839,41 @@ msgid "failed to create temp xml file"
msgstr "gặp lá»—i khi tạo tập tin xml tạm thá»i"
msgid "failed to start schtasks"
-msgstr "gặp lỗi khi lấy thông tin thống kê vỠschtasks"
+msgstr "gặp lỗi khi khởi chạy schtasks"
msgid "failed to run 'crontab -l'; your system might not support 'cron'"
msgstr ""
-"gặp lá»—i khi chạy “crontab -lâ€; hệ thống cá»§a bạn có thể không há»— trợ “cronâ€"
-
-msgid "failed to run 'crontab'; your system might not support 'cron'"
-msgstr "gặp lá»—i khi chạy “crontabâ€; hiển thị cá»§a bạn có lẽ không há»— trợ “cronâ€"
+"gặp lỗi khi chạy 'crontab -l'; hệ thống của bạn có thể không hỗ trợ 'cron'"
-msgid "failed to open stdin of 'crontab'"
-msgstr "gặp lá»—i khi mở đầu vào tiêu chuẩn cá»§a “crontabâ€"
+msgid "failed to create crontab temporary file"
+msgstr "không thể tạo tập tin tạm thá»i crontab"
-msgid "'crontab' died"
-msgstr "“crontab†đã chết"
+msgid "failed to open temporary file"
+msgstr "không thể mở tập tin tạm thá»i"
-msgid "failed to start systemctl"
-msgstr "gặp lỗi khi khởi chạy systemctl"
+msgid "failed to run 'crontab'; your system might not support 'cron'"
+msgstr "gặp lỗi khi chạy 'crontab'; hệ thống của bạn có lẽ không hỗ trợ 'cron'"
-msgid "failed to run systemctl"
-msgstr "gặp lỗi khi chạy systemctl"
+msgid "'crontab' died"
+msgstr "'crontab' đã chết"
#, c-format
msgid "failed to delete '%s'"
-msgstr "gặp lá»—i khi xóa “%sâ€"
+msgstr "gặp lỗi khi xóa '%s'"
#, c-format
msgid "failed to flush '%s'"
-msgstr "gặp lỗi khi đẩy dữ liệu “%s†lên đĩa"
+msgstr "gặp lỗi khi đẩy dữ liệu '%s' lên đĩa"
+
+msgid "failed to start systemctl"
+msgstr "gặp lỗi khi khởi chạy systemctl"
+
+msgid "failed to run systemctl"
+msgstr "gặp lỗi khi chạy systemctl"
#, c-format
msgid "unrecognized --scheduler argument '%s'"
-msgstr "đối số --scheduler không được thừa nhận “%sâ€"
+msgstr "đối số --scheduler không được thừa nhận '%s'"
msgid "neither systemd timers nor crontab are available"
msgstr "hoặc là bộ lập lịch systemd hoặc là crontab không sẵn có"
@@ -6554,18 +6894,17 @@ msgstr "bộ lên lịch"
msgid "scheduler to trigger git maintenance run"
msgstr "bộ lên lịch để kích hoạt chạy chương trình bảo trì git"
+msgid "failed to set up maintenance schedule"
+msgstr "gặp lỗi khi lên lịch bảo trì"
+
msgid "failed to add repo to global config"
msgstr "gặp lỗi khi thêm cấu hình toàn cục"
msgid "git maintenance <subcommand> [<options>]"
msgstr "git maintenance run <lệnh_con> [<các tùy chá»n>]"
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "lện con không hợp lệ: %s"
-
msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
-msgstr "git grep [<các tùy chá»n>] [-e] <mẫu> [<rev>…] [[--] </đưá»ng/dẫn>…]"
+msgstr "git grep [<các tùy chá»n>] [-e] <mẫu> [<rev>...] [[--] </đưá»ng/dẫn>...]"
#, c-format
msgid "grep: failed to create thread: %s"
@@ -6585,8 +6924,8 @@ msgid "no threads support, ignoring %s"
msgstr "không hỗ trợ đa tuyến, bỠqua %s"
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "không thể Ä‘á»c cây (%s)"
+msgid "unable to read tree %s"
+msgstr "không thể Ä‘á»c cây %s"
#, c-format
msgid "unable to grep from object of type %s"
@@ -6594,10 +6933,10 @@ msgstr "không thể thá»±c hiện lệnh grep (lá»c tìm) từ đối tượng
#, c-format
msgid "switch `%c' expects a numerical value"
-msgstr "chuyển đến “%c†cần một giá trị bằng số"
+msgstr "chuyển đến '%c' cần một giá trị bằng số"
msgid "search in index instead of in the work tree"
-msgstr "tìm trong bảng mục lục thay vì trong cây làm việc"
+msgstr "tìm trong chỉ mục thay vì trong cây làm việc"
msgid "find in contents not managed by git"
msgstr "tìm trong nội dung không được quản lý bởi git"
@@ -6606,7 +6945,7 @@ msgid "search in both tracked and untracked files"
msgstr "tìm kiếm các tập tin được và chưa được theo dõi dấu vết"
msgid "ignore files specified via '.gitignore'"
-msgstr "các tập tin bị bá» qua được chỉ định thông qua “.gitignoreâ€"
+msgstr "các tập tin bị bỠqua được chỉ định thông qua '.gitignore'"
msgid "recursively search in each submodule"
msgstr "tìm kiếm đệ quy trong từng mô-đun-con"
@@ -6627,16 +6966,16 @@ msgid "don't match patterns in binary files"
msgstr "không khớp mẫu trong các tập tin nhị phân"
msgid "process binary files with textconv filters"
-msgstr "xá»­ lý tập tin nhị phân vá»›i các bá»™ lá»c “textconvâ€"
+msgstr "xá»­ lý tập tin nhị phân vá»›i các bá»™ lá»c 'textconv'"
msgid "search in subdirectories (default)"
msgstr "tìm kiếm trong thư mục con (mặc định)"
-msgid "descend at most <depth> levels"
-msgstr "hạ xuống ít nhất là mức <sâu>"
+msgid "descend at most <n> levels"
+msgstr "hạ xuống tối đa <n> mức"
msgid "use extended POSIX regular expressions"
-msgstr "dùng biểu thức chính qui POSIX có mở rộng"
+msgstr "dùng biểu thức chính quy POSIX có mở rộng"
msgid "use basic POSIX regular expressions (default)"
msgstr "sử dụng biểu thức chính quy kiểu POSIX (mặc định)"
@@ -6684,7 +7023,7 @@ msgid "highlight matches"
msgstr "tô sáng phần khớp mẫu"
msgid "print empty line between matches from different files"
-msgstr "hiển thị dòng trống giữa các lần khớp từ các tập tin khác biệt"
+msgstr "hiển thị dòng trống giữa các lần khớp từ các tập tin khác nhau"
msgid "show filename only once above matches from same file"
msgstr ""
@@ -6721,20 +7060,23 @@ msgid "combine patterns specified with -e"
msgstr "tổ hợp mẫu được chỉ ra vá»›i tùy chá»n -e"
msgid "indicate hit with exit status without output"
-msgstr "đưa ra gợi ý với trạng thái thoát mà không có kết xuất"
+msgstr "chỉ ra có khớp mẫu hay không với trạng thái thoát thay vì đầu ra"
msgid "show only matches from files that match all patterns"
msgstr "chỉ hiển thị những cái khớp từ tập tin mà nó khớp toàn bộ các mẫu"
msgid "pager"
-msgstr "dàn trang"
+msgstr "trình phân trang"
msgid "show matching files in the pager"
-msgstr "hiển thị các tập tin khớp trong trang giấy"
+msgstr "hiển thị các tập tin khớp trong trình phân trang"
msgid "allow calling of grep(1) (ignored by this build)"
msgstr "cho phép gá»i grep(1) (bị bá» qua bởi lần dịch này)"
+msgid "maximum number of results per file"
+msgstr "số lượng kết quả tối đa trên mỗi tập tin"
+
msgid "no pattern given"
msgstr "chưa chỉ ra mẫu"
@@ -6768,11 +7110,14 @@ msgid "both --cached and trees are given"
msgstr "cả hai --cached và các cây phải được chỉ ra"
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 ""
-"git hash-object [-t <kiểu>] [-w] [--path=<tập-tin> | --no-filters] [--stdin] "
-"[--] <tập-tin>…"
+"git hash-object [-t <kiểu>] [-w] [--path=<tập-tin> | --no-filters]\n"
+" [--stdin [--literally]] [--] <tập-tin>..."
+
+msgid "git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"
+msgstr "git hash-object [-t <kiểu>] [-w] --stdin-paths [--no-filters] "
msgid "object type"
msgstr "kiểu đối tượng"
@@ -6781,14 +7126,14 @@ msgid "write the object into the object database"
msgstr "ghi đối tượng vào dữ liệu đối tượng"
msgid "read the object from stdin"
-msgstr "Ä‘á»c đối tượng từ đầu vào tiêu chuẩn stdin"
+msgstr "Ä‘á»c đối tượng từ stdin"
msgid "store file as is without filters"
msgstr "lưu các tập tin mà nó không có các bá»™ lá»c"
msgid ""
"just hash any random garbage to create corrupt objects for debugging Git"
-msgstr "chỉ cần băm rác ngẫu nhiên để tạo má»™t đối tượng há»ng để mà gỡ lá»—i Git"
+msgstr "chỉ cần băm rác ngẫu nhiên để tạo má»™t đối tượng há»ng để gỡ lá»—i Git"
msgid "process file as it were from this path"
msgstr "xử lý tập tin như là nó đang ở thư mục này"
@@ -6820,49 +7165,55 @@ msgstr "hiển thị mô tả lệnh"
msgid "print list of useful guides"
msgstr "hiển thị danh sách các hướng dẫn hữu dụng"
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr "hiển thị các giao diện cho ngưá»i dùng"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr "hiển thị các giao diện cho lập trình viên"
+
msgid "print all configuration variable names"
msgstr "in ra tất cả các tên biến cấu hình"
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<lệnh>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<lệnh>|<tài liệu>]"
#, c-format
msgid "unrecognized help format '%s'"
-msgstr "không nhận ra định dạng trợ giúp “%sâ€"
+msgstr "không nhận ra định dạng trợ giúp '%s'"
msgid "Failed to start emacsclient."
msgstr "Gặp lỗi khi khởi chạy emacsclient."
msgid "Failed to parse emacsclient version."
-msgstr "Gặp lỗi khi phân tích phiên bản emacsclient."
+msgstr "Gặp lá»—i khi Ä‘á»c phiên bản emacsclient."
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
-msgstr "phiên bản của emacsclient “%d†quá cũ (< 22)."
+msgstr "phiên bản của emacsclient '%d' quá cũ (< 22)."
#, c-format
msgid "failed to exec '%s'"
-msgstr "gặp lá»—i khi thá»±c thi “%sâ€"
+msgstr "gặp lỗi khi thực thi '%s'"
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
"Please consider using 'man.<tool>.cmd' instead."
msgstr ""
-"“%sâ€: đưá»ng dẫn không há»— trợ bá»™ trình chiếu man.\n"
-"Hãy cân nhắc đến việc sử dụng “man.<tool>.cmd†để thay thế."
+"'%s': đưá»ng dẫn không há»— trợ bá»™ trình chiếu man.\n"
+"Hãy cân nhắc đến việc sử dụng 'man.<tool>.cmd' để thay thế."
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
"Please consider using 'man.<tool>.path' instead."
msgstr ""
-"“%sâ€: cmd (lệnh) há»— trợ bá»™ trình chiếu man.\n"
-"Hãy cân nhắc đến việc sử dụng “man.<tool>.path†để thay thế."
+"'%s': cmd (lệnh) hỗ trợ bộ trình chiếu man.\n"
+"Hãy cân nhắc đến việc sử dụng 'man.<tool>.path' để thay thế."
#, c-format
msgid "'%s': unknown man viewer."
-msgstr "“%sâ€: không rõ chương trình xem man."
+msgstr "'%s': không rõ chương trình xem man."
msgid "no man viewer handled the request"
msgstr "không có trình xem trợ giúp dạng manpage tiếp hợp với yêu cầu"
@@ -6872,7 +7223,7 @@ msgstr "không có trình xem trợ giúp dạng info tiếp hợp vá»›i yêu cá
#, c-format
msgid "'%s' is aliased to '%s'"
-msgstr "“%s†được đặt bí danh thành “%sâ€"
+msgstr "'%s' được đặt bí danh thành '%s'"
#, c-format
msgid "bad alias.%s string: %s"
@@ -6893,13 +7244,20 @@ msgid "usage: %s%s"
msgstr "cách dùng: %s%s"
msgid "'git help config' for more information"
-msgstr "Chạy lệnh “git help config†để có thêm thông tin"
+msgstr "Chạy lệnh 'git help config' để có thêm thông tin"
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <tên-móc> [-- <các tham số cho móc>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=</đưá»ng/dẫn/>] <tên-móc> [-- "
+"<các tham số cho móc>]"
msgid "silently ignore missing requested <hook-name>"
-msgstr "bỠqua âm thầm các <hook-name> đã yêu cầu còn thiếu"
+msgstr "âm thầm bỠqua các <hook-name> đã yêu cầu còn thiếu"
+
+msgid "file to read into hooks' stdin"
+msgstr "tập tin để đưa vào stdin của hook"
#, c-format
msgid "object type mismatch at %s"
@@ -6911,7 +7269,7 @@ msgstr "không thể lấy vỠđối tượng cần %s"
#, c-format
msgid "object %s: expected type %s, found %s"
-msgstr "đối tượng %s: cần kiểu %s nhưng lại nhận được %s"
+msgstr "đối tượng %s: cần kiểu %s nhưng lại có %s"
#, c-format
msgid "cannot fill %d byte"
@@ -6947,13 +7305,13 @@ msgstr "gói có đối tượng sai tại khoảng bù %<PRIuMAX>: %s"
#, c-format
msgid "inflate returned %d"
-msgstr "xả nén trả vỠ%d"
+msgstr "giải nén trả vỠ%d"
msgid "offset value overflow for delta base object"
msgstr "tràn giá trị khoảng bù cho đối tượng delta cơ sở"
msgid "delta base offset is out of bound"
-msgstr "khoảng bù cơ sở cho delta nằm ngoài phạm vi"
+msgstr "khoảng bù cơ sở cho delta nằm ngoài biên"
#, c-format
msgid "unknown object type %d"
@@ -6968,17 +7326,13 @@ msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
msgstr[0] "tập tin gói bị kết thúc sớm, thiếu %<PRIuMAX> byte"
msgid "serious inflate inconsistency"
-msgstr "sá»± mâu thuẫn xả nén nghiêm trá»ng"
+msgstr "sá»± mâu thuẫn giải nén nghiêm trá»ng"
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "Sá»° VA CHẠM SHA1 ÄÃ XẢY RA VỚI %s!"
#, c-format
-msgid "unable to read %s"
-msgstr "không thể Ä‘á»c %s"
-
-#, c-format
msgid "cannot read existing object info %s"
msgstr "không thể Ä‘á»c thông tin đối tượng sẵn có %s"
@@ -7004,13 +7358,13 @@ msgid "Receiving objects"
msgstr "Äang nhận vá» các đối tượng"
msgid "Indexing objects"
-msgstr "Các đối tượng bảng mục lục"
+msgstr "Các đối tượng chỉ mục"
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "gói bị sai há»ng (SHA1 không khá»›p)"
msgid "cannot fstat packfile"
-msgstr "không thể lấy thông tin thống kê packfile"
+msgstr "không thể fstat packfile"
msgid "pack has junk at the end"
msgstr "pack có phần thừa ở cuối"
@@ -7035,7 +7389,7 @@ msgstr[0] "đầy đủ với %d đối tượng nội bộ"
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
-msgstr "Gặp tổng kiểm tra tail không cần cho %s (đĩa há»ng?)"
+msgstr "Gặp tổng kiểm tra tail bất thưá»ng cho %s (đĩa há»ng?)"
#, c-format
msgid "pack has %d unresolved delta"
@@ -7044,7 +7398,7 @@ msgstr[0] "gói có %d delta chưa được giải quyết"
#, c-format
msgid "unable to deflate appended object (%d)"
-msgstr "không thể xả nén đối tượng nối thêm (%d)"
+msgstr "không thể giải nén đối tượng nối thêm (%d)"
#, c-format
msgid "local object %s is corrupt"
@@ -7052,19 +7406,19 @@ msgstr "đối tượng ná»™i bá»™ %s bị há»ng"
#, c-format
msgid "packfile name '%s' does not end with '.%s'"
-msgstr "tên tập tin tập tin gói “%s†không được kết thúc “.%sâ€"
+msgstr "tên tập tin tập tin gói '%s' không được kết thúc '.%s'"
#, c-format
msgid "cannot write %s file '%s'"
-msgstr "không thể ghi %s tập tin “%sâ€"
+msgstr "không thể ghi %s tập tin '%s'"
#, c-format
msgid "cannot close written %s file '%s'"
-msgstr "không thể đóng tập tin được ghi %s “%sâ€"
+msgstr "không thể đóng tập tin được ghi %s '%s'"
#, c-format
msgid "unable to rename temporary '*.%s' file to '%s'"
-msgstr "không thể đổi tên tập tin tạm thá»i “*.%s†thành “%sâ€"
+msgstr "không thể đổi tên tập tin tạm thá»i '*.%s' thành '%s'"
msgid "error while closing pack file"
msgstr "gặp lỗi trong khi đóng tập tin gói"
@@ -7075,11 +7429,11 @@ msgstr "sai pack.indexVersion=%<PRIu32>"
#, c-format
msgid "Cannot open existing pack file '%s'"
-msgstr "Không thể mở tập tin gói đã sẵn có “%sâ€"
+msgstr "Không thể mở tập tin gói đã sẵn có '%s'"
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
-msgstr "Không thể mở tập tin idx cá»§a gói cho “%sâ€"
+msgstr "Không thể mở tập tin idx của gói cho '%s'"
#, c-format
msgid "non delta: %d object"
@@ -7089,10 +7443,10 @@ msgstr[0] "không delta: %d đối tượng"
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
-msgstr[0] "chiá»u dài xích = %d: %lu đối tượng"
+msgstr[0] "chiá»u dài chuá»—i = %d: %lu đối tượng"
msgid "Cannot come back to cwd"
-msgstr "Không thể quay lại cwd"
+msgstr "Không thể quay lại thư mục hiện hành"
#, c-format
msgid "bad %s"
@@ -7100,7 +7454,7 @@ msgstr "%s sai"
#, c-format
msgid "unknown hash algorithm '%s'"
-msgstr "không hiểu thuật toán băm dữ liệu “%sâ€"
+msgstr "không hiểu thuật toán băm dữ liệu '%s'"
msgid "--stdin requires a git repository"
msgstr "--stdin cần một kho git"
@@ -7111,83 +7465,18 @@ msgstr "dùng tùy chá»n --verify mà không đưa ra tên packfile"
msgid "fsck error in pack objects"
msgstr "lỗi fsck trong các đối tượng gói"
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "không thể lấy thông tin thống kê vá» mẫu “%sâ€"
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "không thể opendir() “%sâ€"
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "không thể readlink “%sâ€"
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "không thể tạo liên kết má»m (symlink) “%s†“%sâ€"
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "không thể sao chép “%s†sang “%sâ€"
-
-#, c-format
-msgid "ignoring template %s"
-msgstr "Ä‘ang lá» Ä‘i mẫu “%sâ€"
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "các mẫu không được tìm thấy trong %s"
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "không sao chép các mẫu từ “%sâ€: %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "tên nhánh khởi tạo không hợp lệ: “%sâ€"
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "không thể xử lý (handle) tập tin kiểu %d"
-
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "không di chuyển được %s vào %s"
-
-msgid "attempt to reinitialize repository with different hash"
-msgstr "cố để khởi tạo lại một kho với kiểu băm dữ liệu khác"
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s đã có từ trước rồi"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: --initial-branch=%s bị bỠqua"
-
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "Äã khởi tạo lại kho Git chia sẻ sẵn có trong %s%s\n"
-
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "Äã khởi tạo lại kho Git sẵn có trong %s%s\n"
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "Äã khởi tạo lại kho Git chia sẻ trống rá»—ng sẵn có trong %s%s\n"
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "Äã khởi tạo lại kho Git trống rá»—ng sẵn có trong %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"
+" [--ref-format=<format>]\n"
+" [-b <branch-name> | --initial-branch=<branch-name>]\n"
+" [--shared[=<permissions>]] [<directory>]"
msgstr ""
-"git init [-q | --quiet] [--bare] [--template=<thư-mục-tạm>] [--shared[=<các-"
-"quyá»n>]] [thư-mục]"
+"git init [-q | --quiet] [--bare] [--template=<thư mục mẫu>]\n"
+" [--separate-git-dir <thư mục git>] [--object-format=<định dạng>]\n"
+" [--ref-format=<định dạng>]\n"
+" [-b <tên nhánh> | --initial-branch=<tên nhánh>]\n"
+" [--shared[=<quyá»n hạn>]] [<thư mục>]"
msgid "permissions"
msgstr "các quyá»n"
@@ -7222,23 +7511,54 @@ msgstr ""
#, c-format
msgid "Cannot access work tree '%s'"
-msgstr "Không thể truy cập cây (tree) làm việc “%sâ€"
+msgstr "Không thể truy cập cây làm việc '%s'"
msgid "--separate-git-dir incompatible with bare repository"
-msgstr "--separate-git-dir xung khắc với kho thuần"
+msgstr "--separate-git-dir không tương thích với kho bare"
msgid ""
-"git interpret-trailers [--in-place] [--trim-empty] [(--trailer "
-"<token>[(=|:)<value>])...] [<file>...]"
+"git interpret-trailers [--in-place] [--trim-empty]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
+" [--parse] [<file>...]"
msgstr ""
-"git interpret-trailers [--in-place] [--trim-empty] [(--trailer "
-"<thẻ>[(=|:)<giá-trị>])…] [<tập-tin>…]"
+"git interpret-trailers [--in-place] [--trim-empty]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<giá-trị>])...]\n"
+" [--parse] [<tập-tin>...]"
+
+#, c-format
+msgid "could not stat %s"
+msgstr "không thể stat %s"
+
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "\"%s\" không phải là tập tin bình thưá»ng"
+
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "tập tin %s ngưá»i dùng không thể ghi được"
+
+msgid "could not open temporary file"
+msgstr "không thể tạo tập tin tạm thá»i"
+
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "không Ä‘á»c được tập tin đầu vào '%s'"
+
+msgid "could not read from stdin"
+msgstr "không thể Ä‘á»c từ stdin"
+
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "không thể đổi tên tập tin tạm thá»i thành %s"
msgid "edit files in place"
msgstr "sửa các tập tin tại chỗ"
msgid "trim empty trailers"
-msgstr "bộ dò vết cắt bỠphần trống rỗng"
+msgstr "cắt bỠphần trailer trống ở đuôi"
+
+msgid "placement"
+msgstr "vị trí"
msgid "where to place the new trailer"
msgstr "đặt phần đuôi mới ở đâu"
@@ -7252,20 +7572,20 @@ msgstr "thao tác khi thiếu phần đuôi"
msgid "output only the trailers"
msgstr "chỉ xuất phần đuôi"
-msgid "do not apply config rules"
-msgstr "đừng áp dụng các quy tắc cấu hình"
+msgid "do not apply trailer.* configuration variables"
+msgstr "không áp dụng các biến cấu hình trailer.*"
-msgid "join whitespace-continued values"
-msgstr "nối các giá trị khoảng-trắng-liên-tiếp"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "định dạng lại giá trị đuôi thành giá trị trên một dòng"
-msgid "set parsing options"
-msgstr "đặt các tùy chá»n phân tích cú pháp"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "viết tắt cho --only-trailers --only-input --unfold"
-msgid "do not treat --- specially"
-msgstr "không coi --- là đặc biệt"
+msgid "do not treat \"---\" as the end of input"
+msgstr "không coi \"---\" là kết thúc đầu vào"
msgid "trailer(s) to add"
-msgstr "bộ dò vết cần thêm"
+msgstr "phần đuôi cần thêm"
msgid "--trailer with --only-input does not make sense"
msgstr "--trailer cùng với --only-input không hợp lý"
@@ -7274,23 +7594,23 @@ msgid "no input file given for in-place editing"
msgstr "không đưa ra tập tin đầu vào để sửa tại-chỗ"
msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
-msgstr "git log [<các tùy chá»n>] [<vùng-xem-xét>] [[--] </đưá»ng/dẫn>…]"
+msgstr "git log [<các tùy chá»n>] [<vùng-xem-xét>] [[--] </đưá»ng/dẫn>...]"
msgid "git show [<options>] <object>..."
-msgstr "git show [<các tùy chá»n>] <đối-tượng>…"
+msgstr "git show [<các tùy chá»n>] <đối-tượng>..."
#, c-format
msgid "invalid --decorate option: %s"
msgstr "tùy chá»n --decorate không hợp lệ: %s"
msgid "suppress diff output"
-msgstr "chặn má»i kết xuất từ diff"
+msgstr "chặn má»i đầu ra từ diff"
msgid "show source"
msgstr "hiển thị mã nguồn"
-msgid "use mail map file"
-msgstr "sử dụng tập tin ánh xạ thư"
+msgid "clear all previously-defined decoration filters"
+msgstr "xoá các bá»™ lá»c decorate đã định nghÄ©a từ trước"
msgid "only decorate refs that match <pattern>"
msgstr "chỉ tô sáng các tham chiếu khớp với <mẫu>"
@@ -7299,28 +7619,25 @@ msgid "do not decorate refs that match <pattern>"
msgstr "không tô sáng các tham chiếu khớp với <mẫu>"
msgid "decorate options"
-msgstr "các tùy chá»n trang trí"
+msgstr "các tùy chá»n decorate"
msgid ""
"trace the evolution of line range <start>,<end> or function :<funcname> in "
"<file>"
msgstr ""
-"theo dõi sự tiến hóa của phạm vi <start><end> dòng, hoặc chức năng:"
-"<funcname> trong <file>"
+"theo vết sự tiến hóa của phạm vi dòng <start>,<end>, hoặc hàm :<tên hàm> "
+"trong <tập tin>"
#, c-format
msgid "unrecognized argument: %s"
msgstr "đối số không được thừa nhận: %s"
msgid "-L<range>:<file> cannot be used with pathspec"
-msgstr "-L<vùng>:<tập_tin> không thể được sá»­ dụng vá»›i đặc tả đưá»ng dẫn"
+msgstr "-L<vùng>:<tập tin> không thể được sá»­ dụng vá»›i đặc tả đưá»ng dẫn"
#, c-format
msgid "Final output: %d %s\n"
-msgstr "Kết xuất cuối cùng: %d %s\n"
-
-msgid "unable to create temporary object directory"
-msgstr "không thể tạo thư mục đối tượng tạm thá»i"
+msgstr "Äầu ra cuối cùng: %d %s\n"
#, c-format
msgid "git show %s: bad file"
@@ -7343,7 +7660,7 @@ msgstr "format.headers không có giá trị cụ thể"
#, c-format
msgid "cannot open patch file %s"
-msgstr "không thể mở tập tin miếng vá: %s"
+msgstr "không thể mở tập tin bản vá: %s"
msgid "need exactly one range"
msgstr "cần chính xác một vùng"
@@ -7351,8 +7668,12 @@ msgstr "cần chính xác một vùng"
msgid "not a range"
msgstr "không phải là một vùng"
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "không thể Ä‘á»c tập tin cấu hình nhánh '%s'"
+
msgid "cover letter needs email format"
-msgstr "“cover letter†cần cho định dạng thư"
+msgstr "cover letter cần định dạng thư"
msgid "failed to create cover-letter file"
msgstr "gặp lỗi khi tạo các tập tin cover-letter"
@@ -7365,7 +7686,7 @@ msgid "git format-patch [<options>] [<since> | <revision-range>]"
msgstr "git format-patch [<các tùy chá»n>] [<kể-từ> | <vùng-xem-xét>]"
msgid "two output directories?"
-msgstr "hai thư mục kết xuất?"
+msgstr "hai thư mục đầu ra?"
#, c-format
msgid "unknown commit %s"
@@ -7373,10 +7694,10 @@ msgstr "không hiểu lần chuyển giao %s"
#, c-format
msgid "failed to resolve '%s' as a valid ref"
-msgstr "gặp lỗi khi phân giải “%s†như là một tham chiếu hợp lệ"
+msgstr "gặp lỗi khi phân giải '%s' thành một tham chiếu hợp lệ"
msgid "could not find exact merge base"
-msgstr "không tìm thấy ná»n hòa trá»™n chính xác"
+msgstr "không tìm thấy gốc hòa trộn chính xác"
msgid ""
"failed to get upstream, if you want to record base commit automatically,\n"
@@ -7389,7 +7710,7 @@ msgstr ""
"\"--base=<base-commit-id>\" một cách thủ công"
msgid "failed to find exact merge base"
-msgstr "gặp lá»—i khi tìm ná»n hòa trá»™n chính xác"
+msgstr "gặp lỗi khi tìm gốc hòa trộn chính xác"
msgid "base commit should be the ancestor of revision list"
msgstr "lần chuyển giao ná»n không là tổ tiên cá»§a danh sách Ä‘iểm xét duyệt"
@@ -7398,7 +7719,7 @@ msgid "base commit shouldn't be in revision list"
msgstr "lần chuyển giao ná»n không được trong danh sách Ä‘iểm xét duyệt"
msgid "cannot get patch id"
-msgstr "không thể lấy mã miếng vá"
+msgstr "không thể lấy mã bản vá"
msgid "failed to infer range-diff origin of current series"
msgstr ""
@@ -7406,70 +7727,76 @@ msgstr ""
#, c-format
msgid "using '%s' as range-diff origin of current series"
-msgstr "dùng “%s†như là gốc range-diff của sê-ri hiện tại"
+msgstr "dùng '%s' làm gốc range-diff của sê-ri hiện tại"
msgid "use [PATCH n/m] even with a single patch"
-msgstr "dùng [PATCH n/m] ngay cả với miếng vá đơn"
+msgstr "dùng [PATCH n/m] ngay cả với bản vá đơn"
msgid "use [PATCH] even with multiple patches"
-msgstr "dùng [VÃ] ngay cả vá»›i các miếng vá phức tạp"
+msgstr "dùng [PATCH] ngay cả vá»›i các bản vá nhiá»u phần"
msgid "print patches to standard out"
-msgstr "hiển thị miếng vá ra đầu ra chuẩn"
+msgstr "hiển thị bản vá ra stdout"
msgid "generate a cover letter"
msgstr "tạo bì thư"
msgid "use simple number sequence for output file names"
-msgstr "sử dụng chỗi dãy số dạng đơn giản cho tên tập-tin xuất ra"
+msgstr "sử dụng chuỗi dãy số dạng đơn giản cho tên tập-tin xuất ra"
msgid "sfx"
-msgstr "sfx"
+msgstr "hậu-tố"
msgid "use <sfx> instead of '.patch'"
-msgstr "sá»­ dụng <sfx> thay cho “.patchâ€"
+msgstr "sử dụng <hậu-tố> thay cho '.patch'"
msgid "start numbering patches at <n> instead of 1"
-msgstr "bắt đầu đánh số miếng vá từ <n> thay vì 1"
+msgstr "bắt đầu đánh số bản vá từ <n> thay vì 1"
msgid "reroll-count"
-msgstr "đếm reroll"
+msgstr "số-lần-chạy-lại"
msgid "mark the series as Nth re-roll"
-msgstr "đánh dấu chuỗi nối tiếp dạng thứ-N re-roll"
+msgstr "đánh dấu chuỗi là lần chạy lại thứ N"
msgid "max length of output filename"
msgstr "chiá»u dài tên tập tin đầu ra tối Ä‘a"
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "dùng [Và RFC] thay cho [VÃ]"
+msgid "rfc"
+msgstr "rfc"
+
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "thêm <rfc> (mặc định 'RFC') trước '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 "tạo ra các phần của một lá thư bao gồm dựa trên mô tả của nhánh"
+msgstr "tạo ra phần bìa thư dựa trên mô tả của nhánh"
+
+msgid "use branch description from file"
+msgstr "dùng mô tả nhánh từ tập tin"
msgid "use [<prefix>] instead of [PATCH]"
-msgstr "dùng [<tiá»n-tố>] thay cho [VÃ]"
+msgstr "dùng [<tiá»n-tố>] thay cho [PATCH]"
msgid "store resulting files in <dir>"
-msgstr "lưu các tập tin kết quả trong <t.mục>"
+msgstr "lưu các tập tin kết quả trong <thư mục>"
msgid "don't strip/add [PATCH]"
-msgstr "không strip/add [VÃ]"
+msgstr "không loại bá»/thêm [PATCH]"
msgid "don't output binary diffs"
-msgstr "không kết xuất diff (những khác biệt) nhị phân"
+msgstr "không xuất diff nhị phân"
msgid "output all-zero hash in From header"
msgstr "xuất má»i mã băm all-zero trong phần đầu From"
msgid "don't include a patch matching a commit upstream"
-msgstr "không bao gồm miếng vá khớp với một lần chuyển giao thượng nguồn"
+msgstr "không bao gồm bản vá khớp với một lần chuyển giao thượng nguồn"
msgid "show patch format instead of default (patch + stat)"
-msgstr "hiển thị định dạng miếng vá thay vì mặc định (miếng vá + thống kê)"
+msgstr "hiển thị định dạng bản vá thay vì mặc định (bản vá + thống kê)"
msgid "Messaging"
msgstr "Lá»i nhắn"
@@ -7490,11 +7817,10 @@ msgid "add Cc: header"
msgstr "thêm Cc: đầu đỠthư"
msgid "ident"
-msgstr "thụt lá»"
+msgstr "ident"
msgid "set From address to <ident> (or committer ident if absent)"
-msgstr ""
-"đặt “Äịa chỉ gá»­i†thành <thụ lá»> (hoặc thụt lá» ngưá»i commit nếu bá» quên)"
+msgstr "đặt 'Äịa chỉ gá»­i' thành <ident> (hoặc ngưá»i commit nếu bá» quên)"
msgid "message-id"
msgstr "message-id"
@@ -7506,13 +7832,13 @@ msgid "boundary"
msgstr "ranh giá»›i"
msgid "attach the patch"
-msgstr "đính kèm miếng vá"
+msgstr "đính kèm bản vá"
msgid "inline the patch"
-msgstr "dùng miếng vá làm nội dung"
+msgstr "dùng bản vá làm nội dung"
msgid "enable message threading, styles: shallow, deep"
-msgstr "cho phép luồng lá»i nhắn, kiểu: “shallowâ€, “deepâ€"
+msgstr "cho phép luồng lá»i nhắn, kiểu: 'shallow', 'deep'"
msgid "signature"
msgstr "chữ ký"
@@ -7524,28 +7850,31 @@ msgid "base-commit"
msgstr "lần_chuyển_giao_ná»n"
msgid "add prerequisite tree info to the patch series"
-msgstr "add trước hết đòi há»i thông tin cây tá»›i sê-ri miếng vá"
+msgstr "add trước hết đòi há»i thông tin cây tá»›i sê-ri bản vá"
msgid "add a signature from a file"
msgstr "thêm chữ ký từ một tập tin"
msgid "don't print the patch filenames"
-msgstr "không hiển thị các tên tập tin của miếng vá"
+msgstr "không hiển thị các tên tập tin của bản vá"
msgid "show progress while generating patches"
-msgstr "hiển thị bộ đo tiến triển trong khi tạo các miếng vá"
+msgstr "hiển thị bộ đo tiến triển trong khi tạo các bản vá"
msgid "show changes against <rev> in cover letter or single patch"
msgstr ""
-"hiển thị các thay đổi dá»±a trên <rev> trong các chữ bao bá»c hoặc miếng vá đơn"
+"hiển thị các thay đổi dá»±a trên <rev> trong các chữ bao bá»c hoặc bản vá đơn"
msgid "show changes against <refspec> in cover letter or single patch"
msgstr ""
-"hiển thị các thay đổi dá»±a trên <refspec> trong các chữ bao bá»c hoặc miếng vá "
+"hiển thị các thay đổi dá»±a trên <refspec> trong các chữ bao bá»c hoặc bản vá "
"đơn"
msgid "percentage by which creation is weighted"
-msgstr "tỷ lệ phần trăm theo cái tạo là weighted"
+msgstr "tỉ lệ phần trăm theo cái tạo là weighted"
+
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "hiện mục From: trong phần thân kể cả khi giống với phần tiêu đỠe-mail"
#, c-format
msgid "invalid ident line: %s"
@@ -7565,7 +7894,7 @@ msgstr "--remerge-diff không hợp lý"
#, c-format
msgid "could not create directory '%s'"
-msgstr "không thể tạo thư mục “%sâ€"
+msgstr "không thể tạo thư mục '%s'"
msgid "--interdiff requires --cover-letter or single patch"
msgstr "--interdiff cần --cover-letter hoặc vá đơn"
@@ -7578,7 +7907,7 @@ msgid "Interdiff against v%d:"
msgstr "Interdiff dựa trên v%d:"
msgid "--range-diff requires --cover-letter or single patch"
-msgstr "--range-diff yêu cầu --cover-letter hoặc miếng vá đơn"
+msgstr "--range-diff yêu cầu --cover-letter hoặc bản vá đơn"
msgid "Range-diff:"
msgstr "Range-diff:"
@@ -7589,13 +7918,13 @@ msgstr "Range-diff dựa trên v%d:"
#, c-format
msgid "unable to read signature file '%s'"
-msgstr "không thể Ä‘á»c tập tin chữ ký “%sâ€"
+msgstr "không thể Ä‘á»c tập tin chữ ký '%s'"
msgid "Generating patches"
-msgstr "Äang tạo các miếng vá"
+msgstr "Äang tạo các bản vá"
msgid "failed to create output files"
-msgstr "gặp lỗi khi tạo các tập tin kết xuất"
+msgstr "gặp lỗi khi tạo các tập tin đầu ra"
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr "git cherry [-v] [<thượng-nguồn> [<đầu> [<giới-hạn>]]]"
@@ -7607,8 +7936,12 @@ msgstr ""
"Không tìm thấy nhánh mạng được theo dõi, hãy chỉ định <thượng-nguồn> một "
"cách thủ công.\n"
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "không thể lấy thông tin đối tượng vỠ'%s'"
+
msgid "git ls-files [<options>] [<file>...]"
-msgstr "git ls-files [<các tùy chá»n>] [<tập-tin>…]"
+msgstr "git ls-files [<các tùy chá»n>] [<tập-tin>...]"
msgid "separate paths with the NUL character"
msgstr "các đưá»ng dẫn được ngăn cách bởi ký tá»± NULL"
@@ -7618,35 +7951,35 @@ msgstr "nhận dạng các trạng thái tập tin với thẻ"
msgid "use lowercase letters for 'assume unchanged' files"
msgstr ""
-"dùng chữ cái viết thưá»ng cho các tập tin “assume unchanged†(giả định không "
+"dùng chữ cái viết thưá»ng cho các tập tin 'assume unchanged' (giả định không "
"thay đổi)"
msgid "use lowercase letters for 'fsmonitor clean' files"
-msgstr "dùng chữ cái viết thưá»ng cho các tập tin “fsmonitor cleanâ€"
+msgstr "dùng chữ cái viết thưá»ng cho các tập tin 'fsmonitor clean'"
msgid "show cached files in the output (default)"
msgstr "hiển thị các tập tin được nhớ tạm vào đầu ra (mặc định)"
msgid "show deleted files in the output"
-msgstr "hiển thị các tập tin đã xóa trong kết xuất"
+msgstr "hiển thị các tập tin đã xóa trong đầu ra"
msgid "show modified files in the output"
-msgstr "hiển thị các tập tin đã bị sửa đổi ra kết xuất"
+msgstr "hiển thị các tập tin đã bị sửa đổi ra đầu ra"
msgid "show other files in the output"
-msgstr "hiển thị các tập tin khác trong kết xuất"
+msgstr "hiển thị các tập tin khác trong đầu ra"
msgid "show ignored files in the output"
-msgstr "hiển thị các tập tin bị bỠqua trong kết xuất"
+msgstr "hiển thị các tập tin bị bỠqua trong đầu ra"
msgid "show staged contents' object name in the output"
-msgstr "hiển thị tên đối tượng của nội dung được đặt lên bệ phóng ra kết xuất"
+msgstr "hiển thị tên đối tượng của nội dung được đặt vào vùng chỠra đầu ra"
msgid "show files on the filesystem that need to be removed"
msgstr "hiển thị các tập tin trên hệ thống tập tin mà nó cần được gỡ bá»"
msgid "show 'other' directories' names only"
-msgstr "chỉ hiển thị tên cá»§a các thư mục “khácâ€"
+msgstr "chỉ hiển thị tên của các thư mục 'khác'"
msgid "show line endings of files"
msgstr "hiển thị kết thúc dòng của các tập tin"
@@ -7655,13 +7988,13 @@ msgid "don't show empty directories"
msgstr "không hiển thị thư mục rỗng"
msgid "show unmerged files in the output"
-msgstr "hiển thị các tập tin chưa hòa trộn trong kết xuất"
+msgstr "hiển thị các tập tin chưa hòa trộn trong đầu ra"
msgid "show resolve-undo information"
msgstr "hiển thị thông tin resolve-undo"
msgid "skip files matching pattern"
-msgstr "bỠqua những tập tin khớp với một mẫu"
+msgstr "bỠqua những tập tin khớp với mẫu"
msgid "read exclude patterns from <file>"
msgstr "Ä‘á»c mẫu cần loại trừ từ <tập-tin>"
@@ -7673,10 +8006,10 @@ msgid "add the standard git exclusions"
msgstr "thêm loại trừ tiêu chuẩn kiểu git"
msgid "make the output relative to the project top directory"
-msgstr "làm cho kết xuất liên quan đến thư mục ở mức cao nhất (gốc) của dự án"
+msgstr "cho kết quả là đưá»ng dẫn tương đối từ thư mục gốc cá»§a dá»± án"
msgid "if any <file> is not in the index, treat this as an error"
-msgstr "nếu <tập tin> bất kỳ không ở trong bảng mục lục, xử lý nó như một lỗi"
+msgstr "nếu có bất kỳ <tập tin> không ở trong chỉ mục, coi nó như một lỗi"
msgid "tree-ish"
msgstr "tree-ish"
@@ -7692,16 +8025,23 @@ msgid "suppress duplicate entries"
msgstr "chặn các mục tin trùng lặp"
msgid "show sparse directories in the presence of a sparse index"
-msgstr "hiển thị thư mục \"sparse\" trong sự có mặt của mục lục \"sparse\""
+msgstr "hiển thị thư mục thưa trong sự có mặt của chỉ mục thưa"
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
-" [-q | --quiet] [--exit-code] [--get-url]\n"
-" [--symref] [<repository> [<refs>...]]"
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
msgstr ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
-" [-q | --quiet] [--exit-code] [--get-url]\n"
-" [--symref] [<kho> [<các tham chiếu>…]]"
+"--format không thể được dùng với -s, -o, -k, -t, --resolve-undo,--"
+"deduplicate, --eol"
+
+msgid ""
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
+" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
+" [--symref] [<repository> [<patterns>...]]"
+msgstr ""
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
+" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
+" [--symref] [<kho> [<mẫu>...]]"
msgid "do not print remote URL"
msgstr "không hiển thị URL máy chủ"
@@ -7715,8 +8055,11 @@ msgstr "đưá»ng dẫn cá»§a git-upload-pack trên máy chá»§"
msgid "limit to tags"
msgstr "giới hạn tới các thẻ"
-msgid "limit to heads"
-msgstr "giới hạn cho các đầu"
+msgid "limit to branches"
+msgstr "giới hạn tới các nhánh"
+
+msgid "deprecated synonym for --branches"
+msgstr "trước đây là đồng nghĩa với --branches"
msgid "do not show peeled tags"
msgstr "không hiển thị thẻ bị peel (gá»t bá»)"
@@ -7731,23 +8074,7 @@ msgid "show underlying ref in addition to the object pointed by it"
msgstr "hiển thị tham chiếu nằm dưới để thêm vào đối tượng được chỉ bởi nó"
msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
-msgstr "git ls-tree [<các tùy chá»n>] <tree-ish> [</đưá»ng/dẫn>…]"
-
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "không thể lấy thông tin đối tượng vỠ“%sâ€"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "định dạng ls-tree sai: phần tá»­ “%s†không bắt đầu bằng “(â€"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "định dạng ls-tree sai: phần tá»­ “%s†không bắt kết thúc bằng “)â€"
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "định dạng ls-tree sai: %%%.*s"
+msgstr "git ls-tree [<các tùy chá»n>] <tree-ish> [</đưá»ng/dẫn>...]"
msgid "only show trees"
msgstr "chỉ hiển thị các tree"
@@ -7759,7 +8086,7 @@ msgid "show trees when recursing"
msgstr "hiển thị cây khi đệ quy"
msgid "terminate entries with NUL byte"
-msgstr "chấm dứt mục tin với byte NUL"
+msgstr "kết thúc mục tin với byte NUL"
msgid "include object size"
msgstr "gồm cả kích thước đối tượng"
@@ -7818,38 +8145,38 @@ msgid "use headers in message's body"
msgstr "sử dụng phần đầu trong nội dung thư"
msgid "reading patches from stdin/tty..."
-msgstr "Ä‘á»c các miếng vá từ đầu vào tiêu chuẩn stdin/tty..."
+msgstr "Ä‘á»c các bản vá từ stdin/tty..."
#, c-format
msgid "empty mbox: '%s'"
-msgstr "mbox trống rá»—ng: “%sâ€"
+msgstr "mbox trống rỗng: '%s'"
msgid "git merge-base [-a | --all] <commit> <commit>..."
-msgstr "git merge-base [-a | --all] <lần_chuyển_giao> <lần_chuyển_giao>…"
+msgstr "git merge-base [-a | --all] <lần_chuyển_giao> <lần_chuyển_giao>..."
msgid "git merge-base [-a | --all] --octopus <commit>..."
-msgstr "git merge-base [-a | --all] --octopus <lần_chuyển_giao>…"
-
-msgid "git merge-base --independent <commit>..."
-msgstr "git merge-base --independent <lần_chuyển_giao>…"
+msgstr "git merge-base [-a | --all] --octopus <lần_chuyển_giao>..."
msgid "git merge-base --is-ancestor <commit> <commit>"
msgstr "git merge-base --is-ancestor <commit> <lần_chuyển_giao>"
+msgid "git merge-base --independent <commit>..."
+msgstr "git merge-base --independent <lần_chuyển_giao>..."
+
msgid "git merge-base --fork-point <ref> [<commit>]"
msgstr "git merge-base --fork-point <tham-chiếu> [<lần_chuyển_giao>]"
msgid "output all common ancestors"
-msgstr "xuất ra tất cả các ông bà, tổ tiên chung"
+msgstr "xuất ra tất cả các ông bà tổ tiên chung"
msgid "find ancestors for a single n-way merge"
msgstr "tìm tổ tiên của hòa trộn n-way đơn"
msgid "list revs not reachable from others"
-msgstr "liệt kê các “rev†mà nó không thể Ä‘á»c được từ cái khác"
+msgstr "liệt kê các 'rev' không thể tới được từ cái còn lại"
msgid "is the first one ancestor of the other?"
-msgstr "là cha mẹ đầu tiên của cái khác?"
+msgstr "có phải cái trước là tổ tiên của cái sau?"
msgid "find where <commit> forked from reflog of <ref>"
msgstr "tìm xem <commit> được rẽ nhánh ở đâu từ reflog của <th.chiếu>"
@@ -7861,8 +8188,18 @@ msgstr ""
"git merge-file [<các tùy chá»n>] [-L <tên1> [-L <gốc> [-L <tên2>]]] <tập-"
"tin1> <tập-tin-gốc> <tập-tin2>"
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"tùy chá»n diff-algorithm chấp nhận \"myers\", \"minimal\", \"patience\" và "
+"\"histogram\""
+
msgid "send results to standard output"
-msgstr "gửi kết quả vào đầu ra tiêu chuẩn"
+msgstr "gửi kết quả ra stdout"
+
+msgid "use object IDs instead of filenames"
+msgstr "dùng ID đối tượng thay vì tên tập tin"
msgid "use a diff3 based merge"
msgstr "dùng kiểu hòa dựa trên diff3"
@@ -7870,17 +8207,14 @@ msgstr "dùng kiểu hòa dựa trên diff3"
msgid "use a zealous diff3 based merge"
msgstr "dùng kiểu hòa trộn dựa trên 'zealous diff3'"
-msgid "for conflicts, use our version"
-msgstr "để tránh xung đột, sử dụng phiên bản của chúng ta"
-
-msgid "for conflicts, use their version"
-msgstr "để tránh xung đột, sá»­ dụng phiên bản cá»§a há»"
+msgid "<algorithm>"
+msgstr "<thuật toán>"
-msgid "for conflicts, use a union version"
-msgstr "để tránh xung đột, sử dụng phiên bản kết hợp"
+msgid "choose a diff algorithm"
+msgstr "chá»n thuật toán diff"
msgid "for conflicts, use this marker size"
-msgstr "để tránh xung đột, hãy sử dụng kích thước bộ tạo này"
+msgstr "nếu xung đột, hãy sử dụng kích thước bộ tạo này"
msgid "do not warn about conflicts"
msgstr "không cảnh báo vỠcác xung đột xảy ra"
@@ -7889,12 +8223,19 @@ msgid "set labels for file1/orig-file/file2"
msgstr "đặt nhãn cho tập-tin-1/tập-tin-gốc/tập-tin-2"
#, c-format
+msgid "object '%s' does not exist"
+msgstr "đối tượng '%s' không tồn tại"
+
+msgid "Could not write object file"
+msgstr "Không thể ghi vào tập tin"
+
+#, c-format
msgid "unknown option %s"
msgstr "không hiểu tùy chá»n %s"
#, c-format
msgid "could not parse object '%s'"
-msgstr "không thể phân tích đối tượng “%sâ€"
+msgstr "không thể Ä‘á»c đối tượng '%s'"
#, c-format
msgid "cannot handle more than %d base. Ignoring %s."
@@ -7912,33 +8253,94 @@ msgstr "không thể phân giải tham chiếu %s"
msgid "Merging %s with %s\n"
msgstr "Äang hòa trá»™n %s vá»›i %s\n"
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "không hiểu cú pháp cây '%s'"
+
+msgid "not something we can merge"
+msgstr "không phải là thứ gì đó mà chúng tôi có thể hòa trộn"
+
+msgid "refusing to merge unrelated histories"
+msgstr "từ chối hòa trộn lịch sử không liên quan"
+
+msgid "failure to merge"
+msgstr "gặp lỗi khi hoà trộn"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<tuỳ chá»n>] <nhánh 1> <nhánh 2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <cây gốc> <nhánh 1> <nhánh 2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "hoà trộn đúng chuẩn thay vì đơn giản"
+
+msgid "do a trivial merge only"
+msgstr "chỉ hoà trộn đơn giản"
+
+msgid "also show informational/conflict messages"
+msgstr "hiển thị thông báo chú thích/xung đột"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "liệt kê tên tập tin không kèm chế độ/oid/stage"
+
+msgid "allow merging unrelated histories"
+msgstr "cho phép hòa trộn lịch sử không liên quan"
+
+msgid "perform multiple merges, one per line of input"
+msgstr "thá»±c hiện hoà trá»™n nhiá»u lần, vá»›i từng dòng đầu vào"
+
+msgid "specify a merge-base for the merge"
+msgstr "chỉ định gốc hoà trộn để hòa trộn"
+
+msgid "option=value"
+msgstr "tùy_chá»n=giá_trị"
+
+msgid "option for selected merge strategy"
+msgstr "tùy chá»n cho chiến lược hòa trá»™n đã chá»n"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge không tương thích vá»›i các tùy chá»n khác"
+
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "không hiểu chiến lược: -X%s"
+
+#, c-format
+msgid "malformed input line: '%s'."
+msgstr "dòng đầu vào sai quy cách: '%s'."
+
+#, c-format
+msgid "merging cannot continue; got unclean result of %d"
+msgstr "không thể tiếp tục hoà trộn; kết quả không hoàn toàn %d"
+
msgid "git merge [<options>] [<commit>...]"
-msgstr "git merge [<các tùy chá»n>] [<commit>…]"
+msgstr "git merge [<các tùy chá»n>] [<commit>...]"
msgid "switch `m' requires a value"
-msgstr "switch “m†yêu cầu một giá trị"
+msgstr "tuỳ chá»n 'm' yêu cầu má»™t giá trị"
#, c-format
msgid "option `%s' requires a value"
-msgstr "tùy chá»n “%s†yêu cầu má»™t giá trị"
+msgstr "tùy chá»n '%s' yêu cầu má»™t giá trị"
#, c-format
msgid "Could not find merge strategy '%s'.\n"
-msgstr "Không tìm thấy chiến lược hòa trá»™n “%sâ€.\n"
+msgstr "Không tìm thấy chiến lược hòa trộn '%s'.\n"
#, c-format
msgid "Available strategies are:"
-msgstr "Các chiến lược sẵn sàng là:"
+msgstr "Các chiến lược khả dụng là:"
#, c-format
msgid "Available custom strategies are:"
-msgstr "Các chiến lược tùy chỉnh sẵn sàng là:"
+msgstr "Các chiến lược tùy chỉnh khả dụng là:"
msgid "do not show a diffstat at the end of the merge"
-msgstr "không hiển thị thống kê khác biệt tại cuối của lần hòa trộn"
+msgstr "không hiển thị diffstat (thống kê khác biệt) phía dưới hòa trộn"
msgid "show a diffstat at the end of the merge"
-msgstr "hiển thị thống kê khác biệt tại cuối của hòa trộn"
+msgstr "hiển thị diffstat (thống kê khác biệt) phía dưới hòa trộn"
msgid "(synonym to --stat)"
msgstr "(đồng nghĩa với --stat)"
@@ -7947,7 +8349,7 @@ msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr "thêm (ít nhất <n>) mục từ shortlog cho ghi chú chuyển giao hòa trộn"
msgid "create a single commit instead of doing a merge"
-msgstr "tạo một lần chuyển giao đưon thay vì thực hiện việc hòa trộn"
+msgstr "tạo một lần chuyển giao đơn thay vì thực hiện việc hòa trộn"
msgid "perform a commit if the merge succeeds (default)"
msgstr "thực hiện chuyển giao nếu hòa trộn thành công (mặc định)"
@@ -7959,7 +8361,7 @@ msgid "allow fast-forward (default)"
msgstr "cho phép chuyển-tiếp-nhanh (mặc định)"
msgid "abort if fast-forward is not possible"
-msgstr "bỠqua nếu chuyển-tiếp-nhanh không thể được"
+msgstr "huỷ lệnh nếu không thể chuyển-tiếp-nhanh"
msgid "verify that the named commit has a valid GPG signature"
msgstr "thẩm tra xem lần chuyển giao có tên đó có chữ ký GPG hợp lệ hay không"
@@ -7970,12 +8372,6 @@ msgstr "chiến lược"
msgid "merge strategy to use"
msgstr "chiến lược hòa trộn sẽ dùng"
-msgid "option=value"
-msgstr "tùy_chá»n=giá_trị"
-
-msgid "option for selected merge strategy"
-msgstr "tùy chá»n cho chiến lược hòa trá»™n đã chá»n"
-
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
"hòa trộn ghi chú của lần chuyển giao (dành cho hòa trộn không-chuyển-tiếp-"
@@ -7985,17 +8381,14 @@ msgid "use <name> instead of the real target"
msgstr "dùng <tên> thay cho đích thật"
msgid "abort the current in-progress merge"
-msgstr "bãi bỠquá trình hòa trộn hiện tại đang thực hiện"
+msgstr "huỷ bỠquá trình hòa trộn hiện đang thực hiện"
msgid "--abort but leave index and working tree alone"
-msgstr "--abort nhưng để lại bảng mục lục và cây làm việc"
+msgstr "--abort nhưng để lại chỉ mục và cây làm việc"
msgid "continue the current in-progress merge"
msgstr "tiếp tục quá trình hòa trộn hiện tại đang thực hiện"
-msgid "allow merging unrelated histories"
-msgstr "cho phép hòa trộn lịch sử không liên quan"
-
msgid "bypass pre-merge-commit and commit-msg hooks"
msgstr "vòng qua móc (hook) pre-merge-commit và commit-msg"
@@ -8028,34 +8421,30 @@ msgstr "Không có lá»i chú thích hòa trá»™n -- nên không cập nhật HEA
#, c-format
msgid "'%s' does not point to a commit"
-msgstr "“%s†không chỉ đến một lần chuyển giao nào cả"
+msgstr "'%s' không chỉ đến một lần chuyển giao nào cả"
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Chuá»—i branch.%s.mergeoptions sai: %s"
msgid "Unable to write index."
-msgstr "Không thể ghi bảng mục lục."
+msgstr "Không thể ghi chỉ mục."
msgid "Not handling anything other than two heads merge."
msgstr "Không cầm nắm gì ngoài hai head hòa trộn."
#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "không hiểu chiến lược: -X%s"
-
-#, c-format
msgid "unable to write %s"
msgstr "không thể ghi %s"
#, c-format
msgid "Could not read from '%s'"
-msgstr "Không thể Ä‘á»c từ “%sâ€"
+msgstr "Không thể Ä‘á»c từ '%s'"
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
-"Vẫn chưa hòa trộn các lần chuyển giao; sử dụng lệnh “git commit†để hoàn tất "
+"Vẫn chưa hòa trộn các lần chuyển giao; sử dụng lệnh 'git commit' để hoàn tất "
"việc hòa trộn.\n"
msgid ""
@@ -8074,10 +8463,10 @@ msgstr "Nếu phần chú thích rỗng sẽ hủy bỠlần chuyển giao.\n"
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
-"Những dòng được bắt đầu bằng “%c†sẽ được bỠqua, và nếu phần chú\n"
+"Những dòng được bắt đầu bằng '%s' sẽ được bỠqua, và nếu phần chú\n"
"thích rỗng sẽ hủy bỠlần chuyển giao.\n"
msgid "Empty commit message."
@@ -8108,19 +8497,16 @@ msgstr "Không nhánh mạng theo dõi cho %s từ %s"
#, c-format
msgid "Bad value '%s' in environment '%s'"
-msgstr "Giá trị sai “%s†trong biến môi trưá»ng “%sâ€"
+msgstr "Giá trị sai '%s' trong biến môi trưá»ng '%s'"
#, c-format
msgid "could not close '%s'"
-msgstr "không thể đóng “%sâ€"
+msgstr "không thể đóng '%s'"
#, c-format
msgid "not something we can merge in %s: %s"
msgstr "không phải là một thứ gì đó mà chúng tôi có thể hòa trộn trong %s: %s"
-msgid "not something we can merge"
-msgstr "không phải là thứ gì đó mà chúng tôi có thể hòa trộn"
-
msgid "--abort expects no arguments"
msgstr "--abort không nhận các đối số"
@@ -8172,16 +8558,22 @@ msgid "Can merge only exactly one commit into empty head"
msgstr ""
"Không thể hòa trộn một cách đúng đắn một lần chuyển giao vào một head rỗng"
-msgid "refusing to merge unrelated histories"
-msgstr "từ chối hòa trộn lịch sử không liên quan"
-
#, c-format
msgid "Updating %s..%s\n"
msgstr "Äang cập nhật %s..%s\n"
#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+" %s"
+msgstr ""
+"Các thay đổi nội bộ của bạn với các tập tin sau đây sẽ bị ghi đè bởi lệnh "
+"hòa trộn:\n"
+" %s"
+
+#, c-format
msgid "Trying really trivial in-index merge...\n"
-msgstr "Äang thá»­ hòa trá»™n kiểu “trivial in-indexâ€â€¦\n"
+msgstr "Äang thá»­ hòa trá»™n kiểu 'trivial in-index'...\n"
#, c-format
msgid "Nope.\n"
@@ -8189,15 +8581,15 @@ msgstr "Không.\n"
#, c-format
msgid "Rewinding the tree to pristine...\n"
-msgstr "Äang tua lại cây thành thá»i xa xưa…\n"
+msgstr "Äang tua lại cây thành thá»i xa xưa...\n"
#, c-format
msgid "Trying merge strategy %s...\n"
-msgstr "Äang thá»­ chiến lược hòa trá»™n %s…\n"
+msgstr "Äang thá»­ chiến lược hòa trá»™n %s...\n"
#, c-format
msgid "No merge strategy handled the merge.\n"
-msgstr "Không có chiến lược hòa trộn nào được nắm giữ (handle) sự hòa trộn.\n"
+msgstr "Không có chiến lược hòa trộn nào có thể xử lý việc hòa trộn.\n"
#, c-format
msgid "Merge with strategy %s failed.\n"
@@ -8209,9 +8601,12 @@ msgstr "Sử dụng chiến lược %s để chuẩn bị giải quyết bằng
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr "Hòa trộn tự động đã xong; dừng trước khi chuyển giao như đã yêu cầu\n"
+
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
msgstr ""
-"Hòa trộn tự động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu "
-"cầu\n"
+"Sau khi hoàn thành, áp dụng các thay đổi trong stash với `git stash pop` \n"
#, c-format
msgid "warning: tag input does not pass fsck: %s"
@@ -8219,11 +8614,11 @@ msgstr "cảnh báo: đầu vào thẻ không qua kiểm tra fsck: %s"
#, c-format
msgid "error: tag input does not pass fsck: %s"
-msgstr "lỗi: đầu vào thẻ không vượt qua fsck: %s"
+msgstr "lỗi: đầu vào thẻ không qua kiểm tra fsck: %s"
#, c-format
msgid "%d (FSCK_IGNORE?) should never trigger this callback"
-msgstr "%d (FSCK_IGNORE?) không bao giá» nên kích hoạt cuá»™c gá»i ngược này"
+msgstr "%d (FSCK_IGNORE?) không bao giỠnên kích hoạt callback này"
#, c-format
msgid "could not read tagged object '%s'"
@@ -8231,24 +8626,20 @@ msgstr "không thể Ä‘á»c đối tượng được đánh thẻ %s"
#, c-format
msgid "object '%s' tagged as '%s', but is a '%s' type"
-msgstr "đối tượng %s được đánh thẻ là %s, không phải là kiểu %s"
-
-msgid "could not read from stdin"
-msgstr "không thể Ä‘á»c từ đầu vào tiêu chuẩn"
+msgstr "đối tượng '%s' được đánh thẻ là '%s', nhưng là kiểu '%s'"
msgid "tag on stdin did not pass our strict fsck check"
msgstr ""
"thẻ trên stdin đã không vượt qua kiểm tra fsck nghiêm ngặt của chúng tôi"
msgid "tag on stdin did not refer to a valid object"
-msgstr ""
-"thẻ trên đầu vào tiêu chuẩn không chỉ đến một lần chuyển giao hợp lệ nào cả"
+msgstr "thẻ trên stdin không chỉ đến một đối tượng hợp lệ"
msgid "unable to write tag file"
-msgstr "không thể ghi vào tập tin lưu thẻ"
+msgstr "không thể ghi vào tập tin thẻ"
msgid "input is NUL terminated"
-msgstr "đầu vào được chấm dứt bởi NUL"
+msgstr "đầu vào được kết thúc bởi NUL"
msgid "allow missing objects"
msgstr "cho phép thiếu đối tượng"
@@ -8287,8 +8678,11 @@ msgstr "gói được sử dụng khi tính toán một \"multi-pack bitmap\""
msgid "write multi-pack bitmap"
msgstr "ghi multi-pack bitmap"
+msgid "write a new incremental MIDX"
+msgstr "ghi incremental MIDX má»›i"
+
msgid "write multi-pack index containing only given indexes"
-msgstr "ghi mục lục multi-pack chỉ chứa các mục lục đã cho"
+msgstr "ghi chỉ mục multi-pack chỉ chứa các chỉ mục đã cho"
msgid "refs snapshot for selecting bitmap commits"
msgstr "ảnh chụp nhanh refs để chá»n các lần chuyển giao ánh xạ"
@@ -8301,11 +8695,11 @@ msgstr ""
"vào một bó cái mà lớn hơn kích thước này"
msgid "git mv [<options>] <source>... <destination>"
-msgstr "git mv [<các tùy chá»n>] <nguồn>… <đích>"
+msgstr "git mv [<các tùy chá»n>] <nguồn>... <đích>"
#, c-format
msgid "Directory %s is in index and no submodule?"
-msgstr "Thư mục “%s†có ở trong chỉ mục mà không có mô-đun con?"
+msgstr "Thư mục '%s' có ở trong chỉ mục mà không có mô-đun con?"
msgid "Please stage your changes to .gitmodules or stash them to proceed"
msgstr ""
@@ -8313,7 +8707,7 @@ msgstr ""
#, c-format
msgid "%.*s is in index"
-msgstr "%.*s trong bảng mục lục"
+msgstr "%.*s trong chỉ mục"
msgid "force move/rename even if target exists"
msgstr "ép buộc di chuyển hay đổi tên thậm chí cả khi đích đã tồn tại"
@@ -8323,20 +8717,23 @@ msgstr "bỠqua các lỗi liên quan đến di chuyển, đổi tên"
#, c-format
msgid "destination '%s' is not a directory"
-msgstr "có đích “%s†nhưng đây không phải là một thư mục"
+msgstr "có đích '%s' nhưng đây không phải là một thư mục"
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
-msgstr "Äang kiểm tra việc đổi tên cá»§a “%s†thành “%sâ€\n"
+msgstr "Äang kiểm tra việc đổi tên cá»§a '%s' thành '%s'\n"
msgid "bad source"
msgstr "nguồn sai"
+msgid "destination exists"
+msgstr "đích đã tồn tại sẵn rồi"
+
msgid "can not move directory into itself"
msgstr "không thể di chuyển một thư mục vào trong chính nó được"
-msgid "cannot move directory over file"
-msgstr "không di chuyển được thư mục thông qua tập tin"
+msgid "destination already exists"
+msgstr "đích đã tồn tại sẵn rồi"
msgid "source directory is empty"
msgstr "thư mục nguồn là trống rỗng"
@@ -8347,12 +8744,9 @@ msgstr "không nằm dưới sự quản lý mã nguồn"
msgid "conflicted"
msgstr "bị xung đột"
-msgid "destination exists"
-msgstr "đích đã tồn tại sẵn rồi"
-
#, c-format
msgid "overwriting '%s'"
-msgstr "Ä‘ang ghi đè lên “%sâ€"
+msgstr "đang ghi đè lên '%s'"
msgid "Cannot overwrite"
msgstr "Không thể ghi đè"
@@ -8363,6 +8757,9 @@ msgstr "nhiá»u nguồn cho cùng má»™t đích"
msgid "destination directory does not exist"
msgstr "thư mục đích không tồn tại"
+msgid "destination exists in the index"
+msgstr "đích đã tồn tại sẵn trong chỉ mục"
+
#, c-format
msgid "%s, source=%s, destination=%s"
msgstr "%s, nguồn=%s, đích=%s"
@@ -8373,10 +8770,10 @@ msgstr "Äổi tên %s thành %s\n"
#, c-format
msgid "renaming '%s' failed"
-msgstr "gặp lá»—i khi đổi tên “%sâ€"
+msgstr "gặp lỗi khi đổi tên '%s'"
msgid "git name-rev [<options>] <commit>..."
-msgstr "git name-rev [<các tùy chá»n>] <commit>…"
+msgstr "git name-rev [<các tùy chá»n>] <commit>..."
msgid "git name-rev [<options>] --all"
msgstr "git name-rev [<các tùy chá»n>] --all"
@@ -8404,33 +8801,37 @@ msgid "deprecated: use --annotate-stdin instead"
msgstr "đã lạc hậu: hãy dùng --annotate-stdin để thay thế"
msgid "annotate text from stdin"
-msgstr "chú giải chữ từ đầu vào tiêu chuẩn stdin"
+msgstr "chú giải chữ từ stdin"
msgid "allow to print `undefined` names (default)"
-msgstr "cho phép in các tên “chưa định nghĩa†(mặc định)"
+msgstr "cho phép in các tên `chưa định nghĩa` (mặc định)"
msgid "dereference tags in the input (internal use)"
-msgstr "bãi bỠtham chiếu các thẻ trong đầu vào (dùng nội bộ)"
+msgstr "giải tham chiếu các thẻ trong đầu vào (dùng nội bộ)"
msgid "git notes [--ref <notes-ref>] [list [<object>]]"
msgstr "git notes [--ref <notes-ref>] [list [<đối-tượng>]]"
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 <notes-ref>] add [-f] [--allow-empty] [-m <lá»i-nhắn> | -F "
-"<tập-tin> | (-c | -C) <đối-tượng>] [<đối-tượng>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <lá»i-nhắn> | -F <tập-"
+"tin> | (-c | -C) <đối-tượng>] [<đối-tượng>]"
msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
msgstr "git notes [--ref <notes-ref>] copy [-f] <từ-đối-tượng> <đến-đối-tượng>"
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 <notes-ref>] append [--allow-empty] [-m <lá»i-nhắn> | -F "
-"<tập-tin> | (-c | -C) <đối-tượng>] [<đối-tượng>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <lá»i-nhắn> | -F <tập-"
+"tin> | (-c | -C) <đối-tượng>] [<đối-tượng>]"
msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
msgstr "git notes [--ref <notes-ref>] edit [--allow-empty] [<đối-tượng>]"
@@ -8444,7 +8845,7 @@ msgstr ""
"git notes [--ref <notes-ref>] merge [-v | -q] [-s <chiến-lược> ] <notes-ref>"
msgid "git notes [--ref <notes-ref>] remove [<object>...]"
-msgstr "git notes [--ref <notes-ref>] remove [<đối-tượng>…]"
+msgstr "git notes [--ref <notes-ref>] remove [<đối-tượng>...]"
msgid "git notes [--ref <notes-ref>] prune [-n] [-v]"
msgstr "git notes [--ref <notes-ref>] prune [-n] [-v]"
@@ -8462,7 +8863,7 @@ msgid "git notes copy [<options>] <from-object> <to-object>"
msgstr "git notes copy [<các tùy chá»n>] <từ-đối-tượng> <đến-đối-tượng>"
msgid "git notes copy --stdin [<from-object> <to-object>]..."
-msgstr "git notes copy --stdin [<từ-đối-tượng> <đến-đối-tượng>]…"
+msgstr "git notes copy --stdin [<từ-đối-tượng> <đến-đối-tượng>]..."
msgid "git notes append [<options>] [<object>]"
msgstr "git notes append [<các tùy chá»n>] [<đối-tượng>]"
@@ -8491,16 +8892,12 @@ msgstr "git notes prune [<các tùy chá»n>]"
msgid "Write/edit the notes for the following object:"
msgstr "Ghi hay sửa ghi chú cho đối tượng sau đây:"
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "không thể khởi chạy “show†cho đối tượng “%sâ€"
-
msgid "could not read 'show' output"
-msgstr "không thể Ä‘á»c kết xuất “showâ€"
+msgstr "không thể Ä‘á»c đầu ra 'show'"
#, c-format
msgid "failed to finish 'show' for object '%s'"
-msgstr "gặp lá»—i khi hoàn thành “show†cho đối tượng “%sâ€"
+msgstr "gặp lỗi khi hoàn thành 'show' cho đối tượng '%s'"
msgid "please supply the note contents using either -m or -F option"
msgstr ""
@@ -8515,27 +8912,23 @@ msgstr "nội dung ghi chú còn lại %s"
#, c-format
msgid "could not open or read '%s'"
-msgstr "không thể mở hay Ä‘á»c “%sâ€"
+msgstr "không thể mở hay Ä‘á»c '%s'"
#, c-format
msgid "failed to resolve '%s' as a valid ref."
-msgstr "gặp lỗi khi phân giải “%s†như là một tham chiếu hợp lệ."
+msgstr "gặp lỗi khi phân giải '%s' thành một tham chiếu hợp lệ."
#, c-format
msgid "failed to read object '%s'."
-msgstr "gặp lá»—i khi Ä‘á»c đối tượng “%sâ€."
+msgstr "gặp lá»—i khi Ä‘á»c đối tượng '%s'."
#, c-format
msgid "cannot read note data from non-blob object '%s'."
-msgstr "không thể Ä‘á»c dữ liệu ghi chú từ đối tượng không-blob “%sâ€."
-
-#, c-format
-msgid "malformed input line: '%s'."
-msgstr "dòng đầu vào dị hình: “%sâ€."
+msgstr "không thể Ä‘á»c dữ liệu ghi chú từ đối tượng không-blob '%s'."
#, c-format
msgid "failed to copy notes from '%s' to '%s'"
-msgstr "gặp lá»—i khi sao chép ghi chú (note) từ “%s†sang “%sâ€"
+msgstr "gặp lỗi khi sao chép ghi chú (note) từ '%s' sang '%s'"
#. TRANSLATORS: the first %s will be replaced by a git
#. notes command: 'add', 'merge', 'remove', etc.
@@ -8566,13 +8959,22 @@ msgstr "cho lưu trữ ghi chú trống rỗng"
msgid "replace existing notes"
msgstr "thay thế ghi chú trước"
+msgid "<paragraph-break>"
+msgstr "<dấu ngắt đoạn>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "chèn <dấu ngắt đoạn> giữa các đoạn văn"
+
+msgid "remove unnecessary whitespace"
+msgstr "Xóa bỠcác khoảng trắng không cần thiết"
+
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr ""
"Không thể thêm các ghi chú. Äã tìm thấy các ghi chú đã có sẵn cho đối tượng "
-"%s. Sá»­ dụng tùy chá»n “-f†để ghi đè lên các ghi chú cÅ©"
+"%s. Sá»­ dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©"
#, c-format
msgid "Overwriting existing notes for object %s\n"
@@ -8583,10 +8985,10 @@ msgid "Removing note for object %s\n"
msgstr "Äang gỡ bá» ghi chú (note) cho đối tượng %s\n"
msgid "read objects from stdin"
-msgstr "Ä‘á»c các đối tượng từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c các đối tượng từ stdin"
msgid "load rewriting config for <command> (implies --stdin)"
-msgstr "tải cấu hình chép lại cho <lệnh> (ngầm định là --stdin)"
+msgstr "tải cấu hình chép lại cho <lệnh> (ngụ ý --stdin)"
msgid "too few arguments"
msgstr "quá ít đối số"
@@ -8597,7 +8999,7 @@ msgid ""
"existing notes"
msgstr ""
"Không thể sao chép các ghi chú. Äã tìm thấy các ghi chú đã có sẵn cho đối "
-"tượng %s. Sá»­ dụng tùy chá»n “-f†để ghi đè lên các ghi chú cÅ©"
+"tượng %s. Sá»­ dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©"
#, c-format
msgid "missing notes on source object %s. Cannot copy."
@@ -8608,8 +9010,8 @@ 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 ""
-"Các tùy chá»n -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con “editâ€.\n"
-"Xin hãy sá»­ dụng lệnh sau để thay thế: “git notes add -f -m/-F/-c/-Câ€.\n"
+"Các tùy chá»n -m/-F/-c/-C đã không còn dùng cho lệnh con 'edit'.\n"
+"Xin hãy sử dụng lệnh sau để thay thế: 'git notes add -f -m/-F/-c/-C'.\n"
msgid "failed to delete ref NOTES_MERGE_PARTIAL"
msgstr "gặp lỗi khi xóa tham chiếu NOTES_MERGE_PARTIAL"
@@ -8618,7 +9020,7 @@ msgid "failed to delete ref NOTES_MERGE_REF"
msgstr "gặp lỗi khi xóa tham chiếu NOTES_MERGE_REF"
msgid "failed to remove 'git notes merge' worktree"
-msgstr "gặp lá»—i khi gỡ bá» cây làm việc “git notes mergeâ€"
+msgstr "gặp lỗi khi gỡ bỠcây làm việc 'git notes merge'"
msgid "failed to read ref NOTES_MERGE_PARTIAL"
msgstr "gặp lá»—i khi Ä‘á»c tham chiếu NOTES_MERGE_PARTIAL"
@@ -8627,7 +9029,7 @@ msgid "could not find commit from NOTES_MERGE_PARTIAL."
msgstr "không thể tìm thấy lần chuyển giao từ NOTES_MERGE_PARTIAL."
msgid "could not parse commit from NOTES_MERGE_PARTIAL."
-msgstr "không thể phân tích cú pháp lần chuyển giao từ NOTES_MERGE_PARTIAL."
+msgstr "không hiểu cú pháp lần chuyển giao từ NOTES_MERGE_PARTIAL."
msgid "failed to resolve NOTES_MERGE_REF"
msgstr "gặp lỗi khi phân giải NOTES_MERGE_REF"
@@ -8649,7 +9051,7 @@ msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
msgstr ""
-"phân giải các xung đột “notes†sử dụng chiến lược đã đưa ra (manual/ours/"
+"phân giải các xung đột 'notes' sử dụng chiến lược đã đưa ra (manual/ours/"
"theirs/union/cat_sort_uniq)"
msgid "Committing unmerged notes"
@@ -8691,49 +9093,48 @@ msgid ""
"abort'.\n"
msgstr ""
"Gặp lỗi khi hòa trộn các ghi chú tự động. Sửa các xung đột này trong %s và "
-"chuyển giao kết quả bằng “git notes merge --commitâ€, hoặc bãi bá» việc hòa "
-"trá»™n bằng “git notes merge --abortâ€.\n"
+"chuyển giao kết quả bằng 'git notes merge --commit', hoặc huỷ bỠviệc hòa "
+"trộn bằng 'git notes merge --abort'.\n"
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
-msgstr "Gặp lỗi khi phân giải “%s†như là một tham chiếu hợp lệ."
+msgstr "Gặp lỗi khi phân giải '%s' thành một tham chiếu hợp lệ."
#, c-format
msgid "Object %s has no note\n"
msgstr "Äối tượng %s không có ghi chú (note)\n"
msgid "attempt to remove non-existent note is not an error"
-msgstr "cố gắng gỡ bỠmột note chưa từng tồn tại không phải là một lỗi"
+msgstr "việc gỡ bỠmột note không tồn tại không phải là lỗi"
msgid "read object names from the standard input"
-msgstr "Ä‘á»c tên đối tượng từ thiết bị nhập chuẩn"
+msgstr "Ä‘á»c tên đối tượng từ stdin"
msgid "do not remove, show only"
msgstr "không gỡ bá», chỉ hiển thị"
msgid "report pruned notes"
-msgstr "báo cáo các đối tượng đã prune"
+msgstr "liệt kê các đối tượng đã prune"
msgid "notes-ref"
msgstr "notes-ref"
msgid "use notes from <notes-ref>"
-msgstr "dùng “notes†từ <notes-ref>"
+msgstr "dùng 'notes' từ <notes-ref>"
#, c-format
-msgid "unknown subcommand: %s"
-msgstr "không hiểu câu lệnh con: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "không hiểu câu lệnh con: `%s'"
-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 [các tùy chá»n…] [< <danh-sách-tham-chiếu> | < "
+"git pack-objects --stdout [<các tùy chá»n>] [< <danh-sách-tham-chiếu> | < "
"<danh-sách-đối-tượng>]"
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ác tùy chá»n…] <base-name> [< <danh-sách-ref> | < <danh-"
+"git pack-objects [<các tùy chá»n>] <base-name> [< <danh-sách-ref> | < <danh-"
"sách-đối-tượng>]"
#, c-format
@@ -8772,14 +9173,14 @@ msgstr "Äang ghi lại các đối tượng"
#, c-format
msgid "failed to stat %s"
-msgstr "gặp lỗi khi lấy thông tin thống kê vỠ%s"
+msgstr "gặp lỗi khi stat %s"
#, c-format
msgid "failed utime() on %s"
-msgstr "gặp lá»—i utime() trên “%sâ€"
+msgstr "gặp lỗi utime() trên '%s'"
msgid "failed to write bitmap index"
-msgstr "gặp lỗi khi ghi mục lục ánh xạ"
+msgstr "gặp lỗi khi ghi chỉ mục ánh xạ"
#, c-format
msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
@@ -8805,7 +9206,7 @@ msgstr "không thể lấy kích cỡ của %s"
#, c-format
msgid "unable to parse object header of %s"
-msgstr "không thể phân tích phần đầu đối tượng cá»§a “%sâ€"
+msgstr "không thể Ä‘á»c phần đầu đối tượng cá»§a '%s'"
#, c-format
msgid "object %s cannot be read"
@@ -8826,11 +9227,11 @@ msgstr "Nén delta dùng tới %d tuyến trình"
#, c-format
msgid "unable to pack objects reachable from tag %s"
-msgstr "không thể đóng gói các đối tượng tiếp cận được từ thẻ “%sâ€"
+msgstr "không thể đóng gói các đối tượng tiếp cận được từ thẻ '%s'"
#, c-format
msgid "unable to get type of object %s"
-msgstr "không thể lấy kiểu cá»§a đối tượng “%sâ€"
+msgstr "không thể lấy kiểu của đối tượng '%s'"
msgid "Compressing objects"
msgstr "Äang nén các đối tượng"
@@ -8839,27 +9240,31 @@ msgid "inconsistency with delta count"
msgstr "mâu thuẫn với số lượng delta"
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "giá trị pack.allowPackReuse không hợp lệ: '%s'"
+
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
msgstr ""
-"giá trị của uploadpack.blobpackfileuri phải có dạng “<object-hash> <pack-"
-"hash> <uri>†(nhận “%sâ€)"
+"giá trị của uploadpack.blobpackfileuri phải có dạng '<object-hash> <pack-"
+"hash> <uri>' (nhận '%s')"
#, c-format
msgid ""
"object already configured in another uploadpack.blobpackfileuri (got '%s')"
msgstr ""
"đối tượng đã được cấu hình trong một uploadpack.blobpackfileuri khác (đã "
-"nhận “%sâ€)"
+"nhận '%s')"
#, c-format
msgid "could not get type of object %s in pack %s"
-msgstr "không thể lấy kiểu cá»§a đối tượng “%s†trong gói “%sâ€"
+msgstr "không thể lấy kiểu của đối tượng '%s' trong gói '%s'"
#, c-format
msgid "could not find pack '%s'"
-msgstr "không thể tìm thấy gói “%sâ€"
+msgstr "không thể tìm thấy gói '%s'"
#, c-format
msgid "packfile %s cannot be accessed"
@@ -8879,7 +9284,7 @@ msgid ""
"expected edge object ID, got garbage:\n"
" %s"
msgstr ""
-"cần ID đối tượng cạnh, nhận được rác:\n"
+"cần ID đối tượng cạnh, có rác:\n"
" %s"
#, c-format
@@ -8887,14 +9292,14 @@ msgid ""
"expected object ID, got garbage:\n"
" %s"
msgstr ""
-"cần ID đối tượng, nhận được rác:\n"
+"cần ID đối tượng, có rác:\n"
" %s"
msgid "could not load cruft pack .mtimes"
msgstr "không thể tải cruft pack .mtimes"
msgid "cannot open pack index"
-msgstr "không thể mở mục lục của gói"
+msgstr "không thể mở chỉ mục của gói"
#, c-format
msgid "loose object at %s could not be examined"
@@ -8905,31 +9310,37 @@ msgstr "không thể buộc mất đối tượng"
#, c-format
msgid "not a rev '%s'"
-msgstr "không phải má»™t rev “%sâ€"
+msgstr "không phải một rev '%s'"
#, c-format
msgid "bad revision '%s'"
-msgstr "Ä‘iểm xem xét sai “%sâ€"
+msgstr "điểm xem xét sai '%s'"
msgid "unable to add recent objects"
msgstr "không thể thêm các đối tượng mới dùng"
#, c-format
msgid "unsupported index version %s"
-msgstr "phiên bản mục lục không được hỗ trợ %s"
+msgstr "phiên bản chỉ mục không được hỗ trợ %s"
#, c-format
msgid "bad index version '%s'"
-msgstr "phiên bản mục lục sai “%sâ€"
+msgstr "phiên bản chỉ mục sai '%s'"
+
+msgid "show progress meter during object writing phase"
+msgstr "hiển thị bộ đo tiến triển trong suốt pha ghi đối tượng"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "tương tự --all-progress khi bộ đo tiến trình được xuất hiện"
msgid "<version>[,<offset>]"
msgstr "<phiên bản>[,offset]"
msgid "write the pack index file in the specified idx format version"
-msgstr "ghi tập tin bảng mục lục gói (pack) ở phiên bản định dạng idx đã cho"
+msgstr "ghi tập tin chỉ mục gói (pack) ở phiên bản định dạng idx đã cho"
msgid "maximum size of each output pack file"
-msgstr "kcíh thước tối đa cho tập tin gói được tạo"
+msgstr "kích thước tối đa cho tập tin gói được tạo"
msgid "ignore borrowed objects from alternate object store"
msgstr "bỠqua các đối tượng vay mượn từ kho đối tượng thay thế"
@@ -8944,7 +9355,7 @@ msgid "limit pack window by memory in addition to object limit"
msgstr "giới hạn cửa sổ đóng gói theo bộ nhớ cộng thêm với giới hạn đối tượng"
msgid "maximum length of delta chain allowed in the resulting pack"
-msgstr "độ dài tối đa của chuỗi móc xích “delta†được phép trong gói kết quả"
+msgstr "độ dài tối đa của chuỗi móc xích 'delta' được phép trong gói kết quả"
msgid "reuse existing deltas"
msgstr "dùng lại các delta sẵn có"
@@ -8959,10 +9370,10 @@ msgid "use threads when searching for best delta matches"
msgstr "sử dụng các tuyến trình khi tìm kiếm cho các mẫu khớp delta tốt nhất"
msgid "do not create an empty pack output"
-msgstr "không thể tạo kết xuất gói trống rỗng"
+msgstr "không thể tạo đầu ra gói trống rỗng"
msgid "read revision arguments from standard input"
-msgstr "Ä‘á»c tham số “revision†từ thiết bị nhập chuẩn"
+msgstr "Ä‘á»c tham số 'revision' từ stdin"
msgid "limit the objects to those that are not yet packed"
msgstr "giới hạn các đối tượng thành những cái mà chúng vẫn chưa được đóng gói"
@@ -8974,13 +9385,13 @@ msgid "include objects referred by reflog entries"
msgstr "bao gồm các đối tượng được tham chiếu bởi các mục reflog"
msgid "include objects referred to by the index"
-msgstr "bao gồm các đối tượng được tham chiếu bởi mục lục"
+msgstr "bao gồm các đối tượng được tham chiếu bởi chỉ mục"
msgid "read packs from stdin"
-msgstr "Ä‘á»c các gói từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c các gói từ stdin"
msgid "output pack to stdout"
-msgstr "xuất gói ra đầu ra tiêu chuẩn"
+msgstr "xuất gói ra stdout"
msgid "include tag objects that refer to objects to be packed"
msgstr "bao gồm các đối tượng tham chiếu đến các đối tượng được đóng gói"
@@ -8993,16 +9404,16 @@ msgstr "pack mất các đối tượng không thể Ä‘á»c được"
msgid "unpack unreachable objects newer than <time>"
msgstr ""
-"xả nén (gỡ khá»i gói) các đối tượng không thể Ä‘á»c được má»›i hÆ¡n <thá»i-gian>"
+"giải nén (gỡ khá»i gói) các đối tượng không thể Ä‘á»c được má»›i hÆ¡n <thá»i-gian>"
msgid "create a cruft pack"
msgstr "tạo gói cruft"
msgid "expire cruft objects older than <time>"
-msgstr "các đối tượng cruft hết hạn cÅ© hÆ¡n khoảng <thá»i gian>"
+msgstr "các đối tượng cruft hết hạn cÅ© hÆ¡n <mốc thá»i gian>"
msgid "use the sparse reachability algorithm"
-msgstr "sá»­ dụng thuật toán “sparse reachabilityâ€"
+msgstr "sử dụng thuật toán 'sparse reachability'"
msgid "create thin packs"
msgstr "tạo gói nhẹ"
@@ -9020,25 +9431,25 @@ msgid "pack compression level"
msgstr "mức nén gói"
msgid "do not hide commits by grafts"
-msgstr "không ẩn các lần chuyển giao bởi “graftsâ€"
+msgstr "không ẩn các lần chuyển giao bởi 'grafts'"
msgid "use a bitmap index if available to speed up counting objects"
-msgstr "dùng mục lục ánh xạ nếu có thể được để nâng cao tốc độ đếm đối tượng"
+msgstr "dùng chỉ mục ánh xạ nếu có thể được để nâng cao tốc độ đếm đối tượng"
msgid "write a bitmap index together with the pack index"
-msgstr "ghi một mục lục ánh xạ cùng với mục lục gói"
+msgstr "ghi một chỉ mục ánh xạ cùng với chỉ mục gói"
msgid "write a bitmap index if possible"
-msgstr "ghi mục lục ánh xạ nếu được"
+msgstr "ghi chỉ mục ánh xạ nếu được"
msgid "handling for missing objects"
msgstr "xử lý cho thiếu đối tượng"
msgid "do not pack objects in promisor packfiles"
-msgstr "không thể đóng gói các đối tượng trong các tập tin gói hứa hẹn"
+msgstr "không thể đóng gói các đối tượng trong các tập tin gói promisor"
msgid "respect islands during delta compression"
-msgstr "tôn trá»ng island trong suốt quá trình nén “deltaâ€"
+msgstr "tôn trá»ng island trong suốt quá trình nén 'delta'"
msgid "protocol"
msgstr "giao thức"
@@ -9048,7 +9459,7 @@ msgstr "loại trừ bất kỳ cấu hình uploadpack.blobpackfileuri với gia
#, c-format
msgid "delta chain depth %d is too deep, forcing %d"
-msgstr "mức sau xích delta %d là quá sâu, buộc dùng %d"
+msgstr "mức delta chain %d là quá sâu, buộc dùng %d"
#, c-format
msgid "pack.deltaCacheLimit is too high, forcing %d"
@@ -9066,36 +9477,30 @@ msgid "minimum pack size limit is 1 MiB"
msgstr "giới hạn kích thước tối thiểu của gói là 1 MiB"
msgid "--thin cannot be used to build an indexable pack"
-msgstr "--thin không thể được dùng để xây dựng gói đánh mục lục được"
-
-msgid "cannot use --filter without --stdout"
-msgstr "không thể dùng tùy chá»n --filter mà không có --stdout"
+msgstr "không thể dùng --thin để xây dựng gói đánh chỉ mục được"
msgid "cannot use --filter with --stdin-packs"
msgstr "không thể dùng tùy chá»n --filter vá»›i --stdin-packs"
msgid "cannot use internal rev list with --stdin-packs"
-msgstr "không thể dùng danh sách rev bên trong với --stdin-packs"
+msgstr "không thể dùng danh sách rev nội bộ với --stdin-packs"
msgid "cannot use internal rev list with --cruft"
-msgstr "không thể dùng danh sách rev bên trong với --cruft"
+msgstr "không thể dùng danh sách rev nội bộ với --cruft"
msgid "cannot use --stdin-packs with --cruft"
-msgstr "không thể dùng tùy chá»n --stdin-packs vá»›i --cruft"
-
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "không thể dùng tùy chá»n --max-pack-size vá»›i --cruft"
+msgstr "không thể dùng tùy chá»n --stdin-packs vá»›i --cruft"
msgid "Enumerating objects"
-msgstr "Äánh số các đối tượng"
+msgstr "Duyệt các đối tượng"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
-"Tổng %<PRIu32> (delta %<PRIu32>), dùng lại %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"Tổng %<PRIu32> (delta %<PRIu32>), dùng lại %<PRIu32> (delta %<PRIu32>), dùng "
+"lại pack %<PRIu32> (trong số %<PRIuMAX>)"
msgid ""
"'git pack-redundant' is nominated for removal.\n"
@@ -9104,14 +9509,21 @@ msgid ""
"and let us know you still use it by sending an e-mail\n"
"to <git@vger.kernel.org>. Thanks.\n"
msgstr ""
-"“git pack-redundant†được đỠcá»­ để loại bá».\n"
-"Nếu bạn vẫn sử dụng lệnh này, vui lòng bổ sung\n"
-"thêm má»™t tùy chá»n, “--i-still-use-thisâ€, trên dòng lệnh\n"
+"'git pack-redundant' đã được đỠcá»­ để loại bá».\n"
+"Nếu bạn vẫn còn sử dụng lệnh này, vui lòng bổ sung\n"
+"thêm má»™t tùy chá»n, '--i-still-use-this', trên dòng lệnh\n"
"và cho chúng tôi biết bạn vẫn sử dụng nó bằng cách gửi e-mail\n"
-"đến <git@vger.kernel.org>. Cảm ơn.\n"
+"đến <git@vger.kernel.org>. Xin cảm ơn.\n"
-msgid "git pack-refs [<options>]"
-msgstr "git pack-refs [<các tùy chá»n>]"
+msgid "refusing to run without --i-still-use-this"
+msgstr "từ chối chạy lệnh này mà không có --i-still-use-this"
+
+msgid ""
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
+"<pattern>]"
msgid "pack everything"
msgstr "đóng gói má»i thứ"
@@ -9119,23 +9531,45 @@ msgstr "đóng gói má»i thứ"
msgid "prune loose refs (default)"
msgstr "prune (cắt cụt) những tham chiếu bị mất (mặc định)"
+msgid "auto-pack refs as needed"
+msgstr "tự động pack tham chiếu nếu cần"
+
+msgid "references to include"
+msgstr "bao gồm các tham chiếu"
+
+msgid "references to exclude"
+msgstr "loại trừ các tham chiếu"
+
+msgid "git patch-id [--stable | --unstable | --verbatim]"
+msgstr "git patch-id [--stable | --unstable | --verbatim]"
+
+msgid "use the unstable patch-id algorithm"
+msgstr "sử dụng thuật toán patch-id unstable"
+
+msgid "use the stable patch-id algorithm"
+msgstr "sử dụng thuật toán patch-id stable"
+
+msgid "don't strip whitespace from the patch"
+msgstr "không lược bỠkhoảng trắng thừa từ bản vá"
+
msgid "git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"
-msgstr "git prune [-n] [-v] [--progress] [--expire <thá»i-gian>] [--] [<head>…]"
+msgstr ""
+"git prune [-n] [-v] [--progress] [--expire <thá»i-gian>] [--] [<head>...]"
msgid "report pruned objects"
-msgstr "báo cáo các đối tượng đã prune"
+msgstr "liệt kê các đối tượng đã prune"
msgid "expire objects older than <time>"
msgstr "các đối tượng hết hạn cÅ© hÆ¡n khoảng <thá»i gian>"
msgid "limit traversal to objects outside promisor packfiles"
-msgstr "giới hạn giao đến các đối tượng nằm ngoài các tập tin gói hứa hẹn"
+msgstr "giới hạn giao đến các đối tượng nằm ngoài các tập tin gói promisor"
msgid "cannot prune in a precious-objects repo"
msgstr "không thể tỉa bớt trong một kho đối_tượng_vĩ_đại"
msgid "git pull [<options>] [<repository> [<refspec>...]]"
-msgstr "git pull [<các tùy chá»n>] [<kho-chứa> [<refspec>…]]"
+msgstr "git pull [<các tùy chá»n>] [<kho-chứa> [<refspec>...]]"
msgid "control for recursive fetching of submodules"
msgstr "Ä‘iá»u khiển việc lấy vỠđệ quy cá»§a các mô-Ä‘un-con"
@@ -9164,6 +9598,12 @@ msgstr "ép buộc ghi đè lên nhánh nội bộ"
msgid "number of submodules pulled in parallel"
msgstr "số lượng mô-Ä‘un-con được đẩy lên đồng thá»i"
+msgid "use IPv4 addresses only"
+msgstr "chỉ dùng địa chỉ IPv4"
+
+msgid "use IPv6 addresses only"
+msgstr "chỉ dùng địa chỉ IPv6"
+
msgid ""
"There is no candidate for rebasing against among the refs that you just "
"fetched."
@@ -9181,9 +9621,9 @@ msgid ""
"Generally this means that you provided a wildcard refspec which had no\n"
"matches on the remote end."
msgstr ""
-"Äại thể Ä‘iá»u này có nghÄ©a là bạn đã cung cấp đặc tả đưá»ng dẫn dạng dùng ký "
+"Äại khái Ä‘iá»u này có nghÄ©a là bạn đã cung cấp đặc tả đưá»ng dẫn dạng dùng ký "
"tá»±\n"
-"đại diện mà nó lại không khớp trên điểm cuối máy phục vụ."
+"đại diện mà nó lại không khớp trên điểm cuối máy chủ."
#, c-format
msgid ""
@@ -9191,16 +9631,16 @@ msgid ""
"a branch. Because this is not the default configured remote\n"
"for your current branch, you must specify a branch on the command line."
msgstr ""
-"Bạn yêu cầu pull từ máy dịch vụ “%sâ€, nhưng lại chưa chỉ định\n"
-"nhánh nào. Bởi vì đây không phải là máy dịch vụ được cấu hình\n"
-"theo mặc định cho nhánh hiện tại của bạn, bạn phải chỉ định\n"
+"Bạn yêu cầu pull từ máy dịch vụ '%s', nhưng lại chưa chỉ định\n"
+"nhánh nào. Bởi vì đây không phải là máy chủ được cấu hình\n"
+"mặc định cho nhánh hiện tại của bạn, bạn phải chỉ định\n"
"một nhánh trên dòng lệnh."
msgid "You are not currently on a branch."
-msgstr "Hiện tại bạn chẳng ở nhánh nào cả."
+msgstr "Hiện tại bạn đang không ở trên nhánh nào."
msgid "Please specify which branch you want to rebase against."
-msgstr "Vui lòng chỉ định nhánh nào bạn muốn cải tổ lại."
+msgstr "Vui lòng chỉ định nhánh bạn muốn cải tổ lại."
msgid "Please specify which branch you want to merge with."
msgstr "Vui lòng chỉ định nhánh nào bạn muốn hòa trộn vào."
@@ -9220,22 +9660,23 @@ msgstr "Ở đây không có thông tin theo dõi cho nhánh hiện hành."
msgid ""
"If you wish to set tracking information for this branch you can do so with:"
msgstr ""
-"Nếu bạn muốn theo dõi thông tin cho nhánh này bạn có thể thực hiện bằng lệnh:"
+"Nếu bạn muốn thiết lập thông tin theo dõi cho nhánh này bạn có thể thực hiện "
+"bằng lệnh:"
#, c-format
msgid ""
"Your configuration specifies to merge with the ref '%s'\n"
"from the remote, but no such ref was fetched."
msgstr ""
-"Các đặc tả cấu hình cá»§a bạn để hòa trá»™n vá»›i tham chiếu “%sâ€\n"
-"từ máy dịch vụ, nhưng không có nhánh nào như thế được lấy vá»."
+"Cấu hình của bạn nói cần hòa trộn với tham chiếu '%s'\n"
+"từ máy dịch vụ, nhưng không có tham chiếu nào như thế được lấy vá»."
#, c-format
msgid "unable to access commit %s"
-msgstr "không thể truy cập lần chuyển giao “%sâ€"
+msgstr "không thể truy cập lần chuyển giao '%s'"
msgid "ignoring --verify-signatures for rebase"
-msgstr "bá» qua --verify-signatures khi rebase"
+msgstr "bỠqua --verify-signatures khi cải tổ"
msgid ""
"You have divergent branches and need to specify how to reconcile them.\n"
@@ -9252,31 +9693,30 @@ msgid ""
"or --ff-only on the command line to override the configured default per\n"
"invocation.\n"
msgstr ""
-"Bạn có các nhánh phân kỳ và cần chỉ định cách hòa hợp chúng.\n"
-"Bạn có thể làm như vậy bằng cách chạy một trong những lệnh sau đây\n"
-"thỉnh thoảng trước khi thực hiện lệnh pull tiếp theo của bạn:\n"
+"Bạn có các nhánh phân kỳ và cần chỉ định cách hợp nhất chúng.\n"
+"Bạn có thể làm vậy bằng cách chạy một trong những lệnh sau đây\n"
+"trước khi thực hiện lệnh pull tiếp theo của bạn:\n"
"\n"
-" git config pull.rebase false # merge\n"
-" git config pull.rebase true # rebase\n"
-" git config pull.ff only # chỉ fast-forward\n"
+" git config pull.rebase false # hợp nhất\n"
+" git config pull.rebase true # cải tổ\n"
+" git config pull.ff only # chỉ chuyển tiếp nhanh\n"
"\n"
"Bạn có thể thay thế \"git config\" với \"git config --global\" để thiết lập "
"mặc định\n"
-"ưu tiên cho tất cả các kho. Bạn cũng có thể chuyển qua --rebase, --no-"
-"rebase,\n"
-"hoặc --ff-only trên dòng lệnh để ghi đè các mặc định đã cấu hình cho mỗi\n"
+"ưu tiên cho tất cả các kho. Bạn cũng có thể chỉ định --rebase, --no-rebase,\n"
+"hoặc --ff-only trên dòng lệnh để ghi đè cấu hình mặc định cho từng\n"
"lần gá»i.\n"
msgid "Updating an unborn branch with changes added to the index."
msgstr ""
-"Äang cập nhật má»™t nhánh chưa được sinh ra vá»›i các thay đổi được thêm vào "
-"bảng mục lục."
+"Äang cập nhật má»™t nhánh chưa được sinh ra từ các thay đổi được thêm vào mục "
+"lục."
msgid "pull with rebase"
msgstr "pull vá»›i rebase"
-msgid "please commit or stash them."
-msgstr "xin hãy chuyển giao hoặc tạm cất (stash) chúng."
+msgid "Please commit or stash them."
+msgstr "Xin hãy chuyển giao hoặc tạm cất chúng."
#, c-format
msgid ""
@@ -9286,7 +9726,7 @@ msgid ""
msgstr ""
"fetch đã cập nhật head nhánh hiện tại.\n"
"đang chuyển-tiếp-nhanh cây làm việc của bạn từ\n"
-"lần chuyển giaot %s."
+"lần chuyển giao %s."
#, c-format
msgid ""
@@ -9299,30 +9739,29 @@ msgid ""
msgstr ""
"Không thể chuyển tiếp nhanh cây làm việc của bạn.\n"
"Sau khi chắc chắn rằng mình đã ghi lại má»i thứ\n"
-"quý báu từ kết xuất của lệnh\n"
+"quan trá»ng từ đầu ra cá»§a lệnh\n"
"$ git diff %s\n"
"chạy\n"
"$ git reset --hard\n"
-"để khôi phục lại."
+"để khôi phục."
msgid "Cannot merge multiple branches into empty head."
-msgstr "Không thể hòa trá»™n nhiá»u nhánh vào trong má»™t head trống rá»—ng."
+msgstr "Không thể hòa trá»™n nhiá»u nhánh vào má»™t head trống rá»—ng."
msgid "Cannot rebase onto multiple branches."
-msgstr "Không thể thá»±c hiện lệnh rebase (cải tổ) trên nhiá»u nhánh."
+msgstr "Không thể thá»±c hiện lệnh cải tổ trên nhiá»u nhánh."
msgid "Cannot fast-forward to multiple branches."
msgstr "Không thể thá»±c hiện chuyển tiếp nhanh trên nhiá»u nhánh."
msgid "Need to specify how to reconcile divergent branches."
-msgstr "Caanfchir định làm thế nào để giải quyết các nhánh phân kỳ."
+msgstr "Cần chỉ định làm thế nào để giải quyết các nhánh phân kỳ."
msgid "cannot rebase with locally recorded submodule modifications"
-msgstr ""
-"không thể cải tổ với các thay đổi mô-đun-con được ghi lại một cách cục bộ"
+msgstr "không thể cải tổ với các thay đổi submodule cục bộ"
msgid "git push [<options>] [<repository> [<refspec>...]]"
-msgstr "git push [<các tùy chá»n>] [<kho-chứa> [<refspec>…]]"
+msgstr "git push [<các tùy chá»n>] [<kho-chứa> [<refspec>...]]"
msgid "tag shorthand without <tag>"
msgstr "dùng tốc ký thẻ không có <thẻ>"
@@ -9335,14 +9774,13 @@ msgid ""
"To choose either option permanently, see push.default in 'git help config'.\n"
msgstr ""
"\n"
-"Äể chá»n má»—i tùy chá»n má»™t cách cố định, xem push.default trong “git help "
-"configâ€.\n"
+"Äể chá»n má»—i tùy chá»n má»™t cách cố định, xem push.default trong 'git help "
+"config'.\n"
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 ""
"\n"
@@ -9407,8 +9845,7 @@ msgid ""
"%s"
msgstr ""
"Nhánh hiện tại %s không có nhánh thượng nguồn nào.\n"
-"Äể push (đẩy lên) nhánh hiện tại và đặt máy chá»§ này làm thượng nguồn "
-"(upstream), sử dụng\n"
+"Äể đẩy lên nhánh hiện tại và đặt máy chá»§ này làm thượng nguồn, sá»­ dụng\n"
"\n"
" git push --set-upstream %s %s\n"
"%s"
@@ -9420,8 +9857,8 @@ msgstr "Nhánh hiện tại %s có nhiá»u nhánh thượng nguồn, từ chối
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
-"Bạn đã không chỉ ra một refspecs nào để đẩy lên, và push.default là \"không "
-"là gì cả\"."
+"Bạn đã không chỉ ra một refspecs nào để đẩy lên, và push.default "
+"là\"nothing\"."
#, c-format
msgid ""
@@ -9429,48 +9866,46 @@ msgid ""
"your current branch '%s', without telling me what to push\n"
"to update which remote branch."
msgstr ""
-"Bạn Ä‘ang push (đẩy lên) máy chá»§ “%sâ€, mà nó không phải là thượng nguồn "
-"(upstream) cá»§a\n"
-"nhánh hiện tại “%s†của bạn, mà không báo cho tôi biết là cái gì được push\n"
-"để cập nhật nhánh máy chủ nào."
+"Bạn đang đẩy lên máy chủ '%s', không phải là thượng nguồn của\n"
+"nhánh hiện tại '%s' của bạn, mà không báo cho tôi biết là cần đẩy lên\n"
+"nhánh nào để cập nhật nhánh nào."
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 ""
-"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh hiện tại của bạn nằm đằng\n"
-"sau bộ phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ\n"
-"(v.d. \"git pull …\") trước khi đẩy lên lần nữa.\n"
-"Xem “Note about fast-forwards†trong “git push --help†để có thông tin chi "
+"Việc cập nhật bị từ chối bởi vì đỉnh của nhánh hiện tại của bạn đứng sau\n"
+"nhánh tương ứng của máy chủ. Nếu bạn cần hòa trộn với các thay đổi từ\n"
+"máy chủ, hãy chạy 'git pull' trước khi đẩy lên.\n"
+"Xem 'Note about fast-forwards' trong 'git push --help' để biết thông tin chi "
"tiết."
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 ""
-"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh đã đẩy lên nằm đằng sau "
-"bá»™\n"
-"phận tương ứng của máy chủ. Checkou nhánh này và hòa trộn với các thay đổi\n"
-"từ máy chá»§ (v.d. “git pull …â€) trước khi lại push lần nữa.\n"
-"Xem “Note about fast-forwards†trong “git push --help†để có thông tin chi "
+"Việc cập nhật bị từ chối bởi vì đỉnh của nhánh đã đẩy lên đứng sau\n"
+"nhánh tương ứng của máy chủ. Nếu bạn cần hòa trộn với các thay đổi từ\n"
+"máy chủ, hãy chạy 'git pull' trước khi đẩy lên.\n"
+"Xem 'Note about fast-forwards' trong 'git push --help' để biết thông tin chi "
"tiết."
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 ""
-"Việc cập nhật bị từ chối bởi vì máy chủ có chứa công việc mà bạn không\n"
-"có ở máy ná»™i bá»™ cá»§a mình. Lá»—i này thưá»ng có nguyên nhân bởi kho khác đẩy\n"
-"dữ liệu lên cùng một tham chiếu. Bạn có lẽ muốn hòa trộn với các thay đổi\n"
-"từ máy chá»§ (v.d. “git pull…â€) trước khi lại push lần nữa.\n"
-"Xem “Note about fast-forwards†trong “git push --help†để có thông tin chi "
+"Việc cập nhật bị từ chối bởi vì máy chủ có chứa thay đổi mà bạn không\n"
+"có ở nhánh cá»§a mình. Lá»—i này thưá»ng xảy ra khi kho khác đẩy dữ liệu\n"
+"lên cùng một tham chiếu. Nếu bạn cần hòa trộn với các thay đổi từ\n"
+"máy chủ, hãy chạy 'git pull' trước khi đẩy lên.\n"
+"Xem 'Note about fast-forwards' trong 'git push --help' để biết thông tin chi "
"tiết."
msgid "Updates were rejected because the tag already exists in the remote."
@@ -9481,22 +9916,22 @@ msgid ""
"or update a remote ref to make it point at a non-commit object,\n"
"without using the '--force' option.\n"
msgstr ""
-"Không thể cập nhật một tham chiếu trên máy chủ mà nó chỉ đến đối tượng "
-"không\n"
-"phải là lần chuyển giao, hoặc cập nhật một tham chiếu máy chủ để nó chỉ đến "
-"đối tượng\n"
-"không phải chuyển giao, mà không sá»­ dụng tùy chá»n “--forceâ€.\n"
+"Không thể cập nhật tham chiếu trên máy chủ đang chỉ đến đối tượng không\n"
+"phải là lần chuyển giao, hoặc cập nhật tham chiếu trên máy chủ để nó\n"
+"chỉ đến đối tượng không phải lần chuyển giao, mà không sử dụng\n"
+"tùy chá»n '--force'.\n"
msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-"Việc cập nhật bị từ chối bởi vì đầu mút của nhánh theo dõi máy chủ\n"
-"đã được cập nhật kể từ sau lần lấy ra cuối cùng. Bạn có lẽ muốn\n"
-"tích hợp các thay đổi này một cách cục bộ (v.d. \"git pull …\")\n"
-"trước khi ép buộc một cập nhật.\n"
+"Việc cập nhật bị từ chối bởi vì đỉnh của nhánh theo dõi máy chủ đã được\n"
+"cập nhật sau lần checkout trước. Nếu bạn cần hòa trộn với các thay đổi từ\n"
+"máy chủ, hãy chạy 'git pull' trước khi đẩy lên.\n"
+"Xem 'Note about fast-forwards' trong 'git push --help' để biết thông tin chi "
+"tiết."
#, c-format
msgid "Pushing to %s\n"
@@ -9504,7 +9939,13 @@ msgstr "Äang đẩy lên %s\n"
#, c-format
msgid "failed to push some refs to '%s'"
-msgstr "gặp lá»—i khi đẩy tá»›i má»™t số tham chiếu đến “%sâ€"
+msgstr "gặp lỗi khi đẩy tới một số tham chiếu đến '%s'"
+
+msgid ""
+"recursing into submodule with push.recurseSubmodules=only; using on-demand "
+"instead"
+msgstr ""
+"đệ quy vào mô-đun con với push.recurseSubmodules=only; thay bằng on-demand"
#, c-format
msgid "invalid value for '%s'"
@@ -9513,17 +9954,17 @@ msgstr "giá trị cho '%s' không hợp lệ"
msgid "repository"
msgstr "kho"
-msgid "push all refs"
-msgstr "đẩy tất cả các tham chiếu"
+msgid "push all branches"
+msgstr "đẩy tất cả các nhánh"
msgid "mirror all refs"
-msgstr "mirror tất cả các tham chiếu"
+msgstr "sao tất cả các tham chiếu"
msgid "delete refs"
msgstr "xóa các tham chiếu"
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "đẩy các thẻ (không dùng cùng với --all hay --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr "đẩy các thẻ (không dùng cùng với --all hay --branches hay --mirror)"
msgid "force updates"
msgstr "ép buộc cập nhật"
@@ -9538,7 +9979,7 @@ msgid "require remote updates to be integrated locally"
msgstr "yêu cầu máy chủ cập nhật để thích hợp với máy cục bộ"
msgid "control recursive pushing of submodules"
-msgstr "Ä‘iá»u khiển việc đẩy lên (push) đệ qui cá»§a mô-Ä‘un-con"
+msgstr "Ä‘iá»u khiển việc đẩy lên (push) đệ quy cá»§a mô-Ä‘un-con"
msgid "use thin pack"
msgstr "tạo gói nhẹ"
@@ -9569,7 +10010,7 @@ msgstr "--delete không hợp lý nếu không có bất kỳ tham chiếu nào"
#, c-format
msgid "bad repository '%s'"
-msgstr "repository (kho) sai “%sâ€"
+msgstr "repository (kho) sai '%s'"
msgid ""
"No configured push destination.\n"
@@ -9605,7 +10046,7 @@ msgstr ""
"git range-diff [<các tùy chá»n>] <old-base>..<old-tip> <new-base>..<new-tip>"
msgid "git range-diff [<options>] <old-tip>...<new-tip>"
-msgstr "git range-diff [<các tùy chá»n>] <old-tip>…<new-tip>"
+msgstr "git range-diff [<các tùy chá»n>] <old-tip>...<new-tip>"
msgid "git range-diff [<options>] <base> <old-tip> <new-tip>"
msgstr "git range-diff [<các tùy chá»n>] <base> <old-tip> <new-tip>"
@@ -9617,38 +10058,45 @@ msgid "notes"
msgstr "ghi chú"
msgid "passed to 'git log'"
-msgstr "chuyển cho “git logâ€"
+msgstr "chuyển cho 'git log'"
msgid "only emit output related to the first range"
-msgstr "chỉ phát ra kết xuất liên quan đến vùng đầu tiên"
+msgstr "chỉ phát ra kết quả liên quan đến vùng đầu tiên"
msgid "only emit output related to the second range"
-msgstr "chỉ phát ra kết xuất liên quan đến vùng thứ hai"
+msgstr "chỉ phát ra kết quả liên quan đến vùng thứ hai"
+
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "không phải một revision '%s'"
#, c-format
msgid "not a commit range: '%s'"
-msgstr "không phải là vùng chuyển giao: “%sâ€"
+msgstr "không phải là vùng chuyển giao: '%s'"
-msgid "single arg format must be symmetric range"
-msgstr "định dạng đối số đơn phải là một vùng đối xứng"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "không phải là vùng tương xứng: '%s'"
msgid "need two commit ranges"
-msgstr "cần hai vùng lần chuyển giao"
+msgstr "cần hai vùng chuyển giao"
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>]])"
-msgstr ""
"git read-tree [(-m [--trivial] [--aggressive] | --reset | --"
-"prefix=<tiá»n_tố>) [-u | -i]] [--no-sparse-checkout] [--index-"
-"output=<tập_tin>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
+"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=<tiá»n "
+"tố>)\n"
+" [-u | -i]] [--index-output=<tập tin>] [--no-sparse-checkout]\n"
+" (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
msgid "write resulting index to <file>"
-msgstr "ghi mục lục kết quả vào <tập-tin>"
+msgstr "ghi chỉ mục kết quả vào <tập-tin>"
msgid "only empty the index"
-msgstr "chỉ với bảng mục lục trống rỗng"
+msgstr "chỉ với chỉ mục trống rỗng"
msgid "Merging"
msgstr "Hòa trộn"
@@ -9658,10 +10106,10 @@ msgstr "thá»±c hiện má»™t hòa trá»™n thêm vào việc Ä‘á»c"
msgid "3-way merge if no file level merging required"
msgstr ""
-"hòa trộn kiểu “3-way†nếu không có tập tin mức hòa trộn nào được yêu cầu"
+"hòa trộn kiểu '3-way' nếu không có tập tin mức hòa trộn nào được yêu cầu"
msgid "3-way merge in presence of adds and removes"
-msgstr "hòa trá»™n 3-way trong sá»± hiện diện cá»§a “adds†và “removesâ€"
+msgstr "hòa trộn 3-way trong sự hiện diện của 'adds' và 'removes'"
msgid "same as -m, but discard unmerged entries"
msgstr "giống với -m, nhưng bỠqua các mục chưa được hòa trộn"
@@ -9670,7 +10118,7 @@ msgid "<subdirectory>/"
msgstr "<thư-mục-con>/"
msgid "read the tree into the index under <subdirectory>/"
-msgstr "Ä‘á»c cây vào trong bảng mục lục dưới <thư_mục_con>/"
+msgstr "Ä‘á»c cây vào trong chỉ mục dưới <thư_mục_con>/"
msgid "update working tree with merge result"
msgstr "cập nhật cây làm việc với kết quả hòa trộn"
@@ -9679,25 +10127,25 @@ msgid "gitignore"
msgstr "gitignore"
msgid "allow explicitly ignored files to be overwritten"
-msgstr "cho phép các tập tin rõ ràng bị lỠđi được ghi đè"
+msgstr "cho phép các tập tin rõ ràng bị bỠqua được ghi đè"
msgid "don't check the working tree after merging"
msgstr "không kiểm tra cây làm việc sau hòa trộn"
msgid "don't update the index or the work tree"
-msgstr "không cập nhật bảng mục lục hay cây làm việc"
+msgstr "không cập nhật chỉ mục hay cây làm việc"
msgid "skip applying sparse checkout filter"
-msgstr "bá» qua áp dụng bá»™ lá»c lấy ra (checkout) thưa thá»›t"
+msgstr "bá» qua áp dụng bá»™ lá»c sparse checkout (checkout thưa)"
msgid "debug unpack-trees"
-msgstr "gỡ lá»—i “unpack-treesâ€"
+msgstr "gỡ lỗi 'unpack-trees'"
msgid "suppress feedback messages"
msgstr "không xuất các thông tin phản hồi"
msgid "You need to resolve your current index first"
-msgstr "Bạn cần phải giải quyết bảng mục lục hiện tại của bạn trước đã"
+msgstr "Bạn cần phải giải quyết chỉ mục hiện tại của bạn trước đã"
msgid ""
"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase> | --keep-base] "
@@ -9714,7 +10162,7 @@ msgstr ""
#, c-format
msgid "could not read '%s'."
-msgstr "không thể Ä‘á»c “%sâ€."
+msgstr "không thể Ä‘á»c '%s'."
#, c-format
msgid "could not create temporary %s"
@@ -9734,34 +10182,20 @@ msgid "%s requires the merge backend"
msgstr "%s cần một ứng dụng hòa trộn chạy phía sau"
#, c-format
-msgid "could not get 'onto': '%s'"
-msgstr "không thể đặt lấy “ontoâ€: “%sâ€"
+msgid "invalid onto: '%s'"
+msgstr "onto không hợp lệ: '%s'"
#, c-format
msgid "invalid orig-head: '%s'"
-msgstr "orig-head không hợp lệ: “%sâ€"
+msgstr "orig-head không hợp lệ: '%s'"
#, c-format
msgid "ignoring invalid allow_rerere_autoupdate: '%s'"
-msgstr "Ä‘ang bá» qua allow_rerere_autoupdate không hợp lệ: “%sâ€"
+msgstr "đang bỠqua allow_rerere_autoupdate không hợp lệ: '%s'"
#, c-format
msgid "could not remove '%s'"
-msgstr "không thể gỡ bỠ“%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 ""
-"Giải quyết vấn đỠnày thủ công, hãy đanh dấu chúng đã được giải quyết bằng\n"
-"hãy chạy lệnh \"git add/rm <các_tập_tin_xung_đột>\", sau đó chạy \"git "
-"rebase --continue\".\n"
-"Bạn có thể bỠqua miếng vá, chạy \"git rebase --skip\".\n"
-"Äể bãi bá» và quay trở lại trạng thái trước \"git rebase\", chạy \"git rebase "
-"--abort\"."
+msgstr "không thể gỡ bỠ'%s'"
#, c-format
msgid ""
@@ -9774,24 +10208,44 @@ msgid ""
"As a result, git cannot rebase them."
msgstr ""
"\n"
-"git chạm trán một lỗi trong khi đang chuẩn bị các miếng vá để diễn lại\n"
+"git gặp phải một lỗi trong khi đang chuẩn bị các bản vá để diễn lại\n"
"những điểm xét duyệt này:\n"
"\n"
" %s\n"
"\n"
-"Kết quả là git không thể cải tổ lại chúng."
+"Kết quả là, git không thể cải tổ lại chúng."
+
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr "Không hiểu chế độ cải tổ: %s"
#, c-format
msgid "could not switch to %s"
msgstr "không thể chuyển đến %s"
+msgid "apply options and merge options cannot be used together"
+msgstr ""
+"không thể tổ hợp các tùy chá»n áp dụng vá»›i các tùy chá»n hòa trá»™n vá»›i nhau"
+
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "không còn dùng --empty=ask nữa; hãy thay thế bằng '--empty=stop'."
+
#, c-format
msgid ""
-"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask"
-"\"."
+"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
+"\"stop\"."
+msgstr ""
+"kiểu rỗng không được nhận dạng '%s'; giá trị hợp lệ là \"drop\", \"keep\", "
+"và \"stop\"."
+
+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 ""
-"kiểu rá»—ng không được nhận dạng “%sâ€; giá trị hợp lệ là \"drop\", \"keep\", "
-"và \"ask\"."
+"--rebase-merges vá»›i tham số xâu rá»—ng được coi là lá»—i thá»i và sẽ không còn "
+"hoạt động trong Git tương lai. Thay vào đó dùng --rebase-merges không có "
+"tham số, cho kết quả như nhau."
#, c-format
msgid ""
@@ -9803,10 +10257,10 @@ msgid ""
"\n"
msgstr ""
"%s\n"
-"Vui lòng chỉ định nhánh nào bạn muốn cải tổ dựa vào.\n"
+"Vui lòng chỉ định nhánh nào bạn muốn cải tổ lên.\n"
"Xem git-rebase(1) để biết thêm chi tiết.\n"
"\n"
-" git rebase “<nhánh>â€\n"
+" git rebase '<nhánh>'\n"
"\n"
#, c-format
@@ -9816,7 +10270,7 @@ msgid ""
" git branch --set-upstream-to=%s/<branch> %s\n"
"\n"
msgstr ""
-"Nếu bạn muốn theo dõi thông tin cho nhánh này bạn có thể thực hiện bằng "
+"Nếu bạn muốn đặt thông tin theo dõi cho nhánh này bạn có thể thực hiện bằng "
"lệnh:\n"
"\n"
" git branch --set-upstream-to=%s/<nhánh> %s\n"
@@ -9832,17 +10286,16 @@ msgid "rebase onto given branch instead of upstream"
msgstr "cải tổ vào nhánh đã cho thay cho thượng nguồn"
msgid "use the merge-base of upstream and branch as the current base"
-msgstr ""
-"sử dụng các cơ sở hòa trộn của thượng nguồn và nhánh như là cơ sở hiện tại"
+msgstr "sử dụng gốc hòa trộn của thượng nguồn và nhánh làm gốc hiện tại"
msgid "allow pre-rebase hook to run"
msgstr "cho phép móc (hook) pre-rebase được chạy"
msgid "be quiet. implies --no-stat"
-msgstr "hãy im lặng. ý là --no-stat"
+msgstr "im lặng. ngụ ý --no-stat"
msgid "display a diffstat of what changed upstream"
-msgstr "hiển thị một diffstat của những thay đổi thượng nguồn"
+msgstr "hiển thị diffstat của những thay đổi thượng nguồn"
msgid "do not show diffstat of what changed upstream"
msgstr "đừng hiển thị diffstat của những thay đổi thượng nguồn"
@@ -9860,10 +10313,10 @@ msgid "synonym of --reset-author-date"
msgstr "đồng nghĩa với --reset-author-date"
msgid "passed to 'git apply'"
-msgstr "chuyển cho “git applyâ€"
+msgstr "chuyển cho 'git apply'"
msgid "ignore changes in whitespace"
-msgstr "lỠđi sự thay đổi do khoảng trắng gây ra"
+msgstr "bỠqua sự thay đổi do khoảng trắng gây ra"
msgid "cherry-pick all commits, even if unchanged"
msgstr ""
@@ -9873,19 +10326,19 @@ msgid "continue"
msgstr "tiếp tục"
msgid "skip current patch and continue"
-msgstr "bỠqua miếng vá hiện hành và tiếp tục"
+msgstr "bỠqua bản vá hiện hành và tiếp tục"
msgid "abort and check out the original branch"
-msgstr "bãi bỠvà lấy ra nhánh nguyên thủy"
+msgstr "huỷ bỠvà checkout nhánh gốc"
msgid "abort but keep HEAD where it is"
-msgstr "bãi bỠnhưng vẫn vẫn giữ HEAD chỉ đến nó"
+msgstr "huỷ bỠnhưng vẫn vẫn giữ nguyên HEAD"
msgid "edit the todo list during an interactive rebase"
-msgstr "sửa danh sách cần làm trong quá trình “rebase†(cải tổ) tương tác"
+msgstr "sửa danh sách cần làm trong quá trình 'rebase' (cải tổ) tương tác"
msgid "show the patch file being applied or merged"
-msgstr "hiển thị miếng vá đã được áp dụng hay hòa trộn"
+msgstr "hiển thị bản vá đã được áp dụng hay hòa trộn"
msgid "use apply strategies to rebase"
msgstr "dùng chiến lược áp dụng để cải tổ"
@@ -9908,6 +10361,9 @@ msgstr "bỠqua các lần chuyển giao mà nó bắt đầu trống rỗng"
msgid "move commits that begin with squash!/fixup! under -i"
msgstr "di chuyển các lần chuyển giao mà bắt đầu bằng squash!/fixup! dưới -i"
+msgid "update branches that point to commits that are being rebased"
+msgstr "cập nhật các nhánh trỠđến commit đang được cải tổ"
+
msgid "add exec lines after each commit of the editable list"
msgstr "thêm các dòng thực thi sau từng lần chuyển giao của danh sách sửa được"
@@ -9918,7 +10374,7 @@ msgid "try to rebase merges instead of skipping them"
msgstr "cố thử cải tổ các hòa trộn thay vì bỠqua chúng"
msgid "use 'merge-base --fork-point' to refine upstream"
-msgstr "dùng “merge-base --fork-point†để định nghĩa lại thượng nguồn"
+msgstr "dùng 'merge-base --fork-point' để định nghĩa lại thượng nguồn"
msgid "use the given merge strategy"
msgstr "dùng chiến lược hòa trộn đã cho"
@@ -9933,7 +10389,7 @@ msgid "rebase all reachable commits up to the root(s)"
msgstr "cải tổ tất các các lần chuyển giao cho đến root"
msgid "automatically re-schedule any `exec` that fails"
-msgstr "lập lịch lại một cách tự động bất kỳ “exec“ bị lỗi"
+msgstr "lập lịch lại một cách tự động bất kỳ 'exec' bị lỗi"
msgid "apply all changes, even those already present upstream"
msgstr ""
@@ -9941,7 +10397,7 @@ msgstr ""
msgid "It looks like 'git am' is in progress. Cannot rebase."
msgstr ""
-"Hình như Ä‘ang trong quá trình thá»±c hiện lệnh “git amâ€. Không thể rebase."
+"Hình như đang trong quá trình thực hiện lệnh 'git am'. Không thể rebase."
msgid ""
"`rebase --preserve-merges` (-p) is no longer supported.\n"
@@ -9949,7 +10405,7 @@ msgid ""
"Or downgrade to v2.33, or earlier, to complete the rebase."
msgstr ""
"`rebase --preserve-merges` (-p) không còn được hỗ trợ nữa.\n"
-"Dùng `git rebase --abort` để chấm dứt việc cải tổ hiện tại.\n"
+"Dùng `git rebase --abort` để kết thúc việc cải tổ hiện tại.\n"
"Hoặc là hạ phiên bản phần má»m xuống v2.33,\n"
"hoặc trước nữa, để hoàn thành việc cải tổ."
@@ -9963,12 +10419,12 @@ msgstr ""
"'preserve',\n"
"cái mà giỠkhông còn được hỗ trợ nữa; dùng 'merges' để thay thế"
-msgid "No rebase in progress?"
-msgstr "Không có tiến trình rebase nào phải không?"
+msgid "no rebase in progress"
+msgstr "không có cải tổ đang được thực hiện"
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
-"Hành động “--edit-todo†chỉ có thể dùng trong quá trình “rebase†(sửa lịch "
+"Hành động '--edit-todo' chỉ có thể dùng trong quá trình 'rebase' (sửa lịch "
"sử) tương tác."
msgid "Cannot read HEAD"
@@ -10000,67 +10456,67 @@ msgid ""
"valuable there.\n"
msgstr ""
"Hình như là ở đây sẵn có một thư mục %s, và\n"
-"Tôi tá»± há»i có phải bạn Ä‘ang ở giữa má»™t lệnh rebase khác. Nếu đúng là\n"
+"có lẽ bạn đang ở giữa một lệnh rebase khác. Nếu đúng là\n"
"như vậy, xin hãy thử\n"
"\t%s\n"
"Nếu không phải thế, hãy thử\n"
"\t%s\n"
-"và chạy TÔI lần nữa. TÔI dừng lại trong trưá»ng hợp bạn vẫn\n"
-"có một số thứ quý giá ở đây.\n"
+"và chạy TÔI lần nữa. TÔI sẽ dừng lại vì có khả năng bạn vẫn\n"
+"còn má»™t số thứ quan trá»ng ở đây.\n"
msgid "switch `C' expects a numerical value"
-msgstr "tùy chá»n “%c†cần má»™t giá trị bằng số"
+msgstr "tùy chá»n '%c' cần má»™t giá trị bằng số"
-#, c-format
-msgid "Unknown mode: %s"
-msgstr "Không hiểu chế độ: %s"
-
-msgid "--strategy requires --merge or --interactive"
-msgstr "--strategy cần --merge hay --interactive"
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges. Consider adding --"
+"no-rebase-merges"
+msgstr ""
+"tuỳ chá»n apply không tương thích vá»›i rebase.rebaseMerges. Cân nhắc dùng --no-"
+"rebase-merges"
-msgid "apply options and merge options cannot be used together"
+msgid ""
+"apply options are incompatible with rebase.updateRefs. Consider adding --no-"
+"update-refs"
msgstr ""
-"không thể tổ hợp các tùy chá»n áp dụng vá»›i các tùy chá»n hòa trá»™n vá»›i nhau"
+"tuỳ chá»n apply không tương thích vá»›i rebase.updateRefs. Cân nhắc dùng --no-"
+"update-refs"
#, c-format
msgid "Unknown rebase backend: %s"
-msgstr "Không hiểu ứng dụng chạy phía sau lệnh cải tổ: %s"
+msgstr "Không hiểu backend cải tổ: %s"
msgid "--reschedule-failed-exec requires --exec or --interactive"
msgstr "--reschedule-failed-exec cần --exec hay --interactive"
#, c-format
msgid "invalid upstream '%s'"
-msgstr "thượng nguồn không hợp lệ “%sâ€"
+msgstr "thượng nguồn không hợp lệ '%s'"
msgid "Could not create new root commit"
msgstr "Không thể tạo lần chuyển giao gốc mới"
#, c-format
msgid "no such branch/commit '%s'"
-msgstr "không có nhánh/lần chuyển giao “%s†như thế"
+msgstr "không có nhánh/lần chuyển giao '%s' như thế"
#, c-format
msgid "No such ref: %s"
msgstr "Không có tham chiếu nào như thế: %s"
-msgid "Could not resolve HEAD to a revision"
-msgstr "Không thể phân giải lần chuyển giao HEAD đến một điểm xét duyệt"
+msgid "Could not resolve HEAD to a commit"
+msgstr "không thể phân giải HEAD thành tên lần chuyển giao"
#, c-format
msgid "'%s': need exactly one merge base with branch"
-msgstr "“%sâ€: cần chính xác má»™t cÆ¡ sở hòa trá»™n vá»›i nhánh"
+msgstr "'%s': cần chính xác một gốc hòa trộn với nhánh"
#, c-format
msgid "'%s': need exactly one merge base"
-msgstr "“%sâ€: cần chính xác má»™t cÆ¡ sở hòa trá»™n"
+msgstr "'%s': cần chính xác một gốc hòa trộn"
#, c-format
msgid "Does not point to a valid commit '%s'"
-msgstr "Không chỉ đến má»™t lần chuyển giao không hợp lệ “%sâ€"
-
-msgid "Please commit or stash them."
-msgstr "Xin hãy chuyển giao hoặc tạm cất (stash) chúng."
+msgstr "Không chỉ đến một lần chuyển giao không hợp lệ '%s'"
msgid "HEAD is up to date."
msgstr "HEAD đã cập nhật."
@@ -10090,7 +10546,7 @@ msgstr "Thay đổi từ %s thành %s:\n"
#, c-format
msgid "First, rewinding head to replay your work on top of it...\n"
msgstr ""
-"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó…\n"
+"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó...\n"
msgid "Could not detach HEAD"
msgstr "Không thể tách rá»i HEAD"
@@ -10117,19 +10573,19 @@ msgid ""
"To squelch this message and still keep the default behaviour, set\n"
"'receive.denyCurrentBranch' configuration variable to 'refuse'."
msgstr ""
-"Theo mặc định, việc cập nhật nhánh hiện tại trong một kho không-thuần\n"
+"Theo mặc định, việc cập nhật nhánh hiện tại trong một kho không bare\n"
"bị từ chối, bởi vì nó sẽ làm cho chỉ mục và cây làm việc mâu thuẫn với\n"
-"cái mà bạn đẩy lên, và sẽ yêu cầu lệnh “git reset --hard†để mà làm\n"
+"cái mà bạn đẩy lên, và sẽ yêu cầu lệnh 'git reset --hard' để làm\n"
"cho cây làm việc khớp với HEAD.\n"
"\n"
-"Bạn có thể đặt biến cấu hình “receive.denyCurrentBranch†thành\n"
-"“ignore†hay “warn†trong kho máy chủ để cho phép đẩy lên nhánh\n"
+"Bạn có thể đặt biến cấu hình 'receive.denyCurrentBranch' thành\n"
+"'ignore' hay 'warn' trong kho máy chủ để cho phép đẩy lên nhánh\n"
"hiện tại của nó; tuy nhiên, không nên làm như thế trừ phi bạn\n"
"sắp đặt để cập nhật cây làm việc của nó tương ứng với cái mà bạn đẩy\n"
"lên theo cách nào đó.\n"
"\n"
-"Äể chấm dứt lá»i nhắn này và vẫn giữ cách ứng xá»­ mặc định, hãy đặt\n"
-"biến cấu hình “receive.denyCurrentBranch†thành “refuseâ€."
+"Äể tắt lá»i nhắn này và vẫn giữ hành vi mặc định, hãy đặt\n"
+"biến cấu hình 'receive.denyCurrentBranch' thành 'refuse'."
msgid ""
"By default, deleting the current branch is denied, because the next\n"
@@ -10142,14 +10598,14 @@ msgid ""
"To squelch this message, you can set it to 'refuse'."
msgstr ""
"Theo mặc định, việc cập xóa nhánh hiện tại bị từ chối, bởi vì\n"
-"lệnh “git clone†tiếp theo sẽ không có tác dụng trong việc lấy\n"
+"lệnh 'git clone' tiếp theo sẽ không có tác dụng trong việc lấy\n"
"ra bất kỳ tập tin nào, dẫn đến hỗn loạn\n"
"\n"
-"Bạn có thể đặt biến cấu hình “receive.denyDeleteCurrent†thành\n"
-"“warn†hay “ignore†trong kho máy chủ để cho phép đẩy xóa nhánh\n"
+"Bạn có thể đặt biến cấu hình 'receive.denyDeleteCurrent' thành\n"
+"'warn' hay 'ignore' trong kho máy chủ để cho phép đẩy xóa nhánh\n"
"hiện tại của nó có hoặc không cảnh báo.\n"
"\n"
-"Äể chấm dứt lá»i nhắn này, bạn hãy đặt nó thành “refuseâ€."
+"Äể tắt lá»i nhắn này, bạn hãy đặt nó thành 'refuse'."
msgid "quiet"
msgstr "im lặng"
@@ -10160,6 +10616,9 @@ msgstr "bạn phải chỉ định thư mục"
msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<các tùy chá»n>] [<tham chiếu>]"
+msgid "git reflog list"
+msgstr "git reflog list"
+
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10185,6 +10644,10 @@ msgstr "git reflog exists <tham_chiếu>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "dấu vết thá»i gian không hợp lệ '%s' đưa cho '--%s'"
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s không nhận các đối số: '%s'"
+
msgid "do not actually prune any entries"
msgstr "thực tế không cắt ngắn bất kỳ mục tin nào"
@@ -10222,7 +10685,7 @@ msgstr "giới hạn xử lý với reflogs chỉ từ thư mục làm việc hi
#, c-format
msgid "Marking reachable objects..."
-msgstr "Äánh dấu các đối tượng tiếp cận được…"
+msgstr "Äánh dấu các đối tượng tiếp cận được..."
#, c-format
msgid "%s points nowhere!"
@@ -10235,6 +10698,31 @@ msgstr "chưa chỉ ra reflog để xóa"
msgid "invalid ref format: %s"
msgstr "định dạng tham chiếu không hợp lệ: %s"
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<định dạng> [--dry-run]"
+
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+msgid "specify the reference format to convert to"
+msgstr "chỉ định định dạng tham chiếu để chuyển đổi sang"
+
+msgid "perform a non-destructive dry-run"
+msgstr "chạy thử mà không thay đổi gì"
+
+msgid "missing --ref-format=<format>"
+msgstr "thiếu --ref-format=<định dạng>"
+
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "kho đã dùng định dạng '%s'"
+
+msgid "enable strict checking"
+msgstr "cho phép kiểm tra nghiêm ngặt"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' không nhận tham số"
+
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
"mirror=<fetch|push>] <name> <url>"
@@ -10260,10 +10748,10 @@ msgstr "git remote prune [-n | --dry-run] <tên>"
msgid ""
"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
msgstr ""
-"git remote [-v | --verbose] update [-p | --prune] [(<nhóm> | <máy-chủ>)…]"
+"git remote [-v | --verbose] update [-p | --prune] [(<nhóm> | <máy-chủ>)...]"
msgid "git remote set-branches [--add] <name> <branch>..."
-msgstr "git remote set-branches [--add] <tên> <nhánh>…"
+msgstr "git remote set-branches [--add] <tên> <nhánh>..."
msgid "git remote get-url [--push] [--all] <name>"
msgstr "git remote set-url [--push] [--all] <tên>"
@@ -10281,10 +10769,10 @@ msgid "git remote add [<options>] <name> <url>"
msgstr "git remote add [<các tùy chá»n>] <tên> <url>"
msgid "git remote set-branches <name> <branch>..."
-msgstr "git remote set-branches <tên> <nhánh>…"
+msgstr "git remote set-branches <tên> <nhánh>..."
msgid "git remote set-branches --add <name> <branch>..."
-msgstr "git remote set-branches --add <tên> <nhánh>…"
+msgstr "git remote set-branches --add <tên> <nhánh>..."
msgid "git remote show [<options>] <name>"
msgstr "git remote show [<các tùy chá»n>] <tên>"
@@ -10293,7 +10781,7 @@ msgid "git remote prune [<options>] <name>"
msgstr "git remote prune [<các tùy chá»n>] <tên>"
msgid "git remote update [<options>] [<group> | <remote>]..."
-msgstr "git remote update [<các tùy chá»n>] [<nhóm> | <máy-chá»§>]…"
+msgstr "git remote update [<các tùy chá»n>] [<nhóm> | <máy-chá»§>]..."
#, c-format
msgid "Updating %s"
@@ -10301,27 +10789,28 @@ msgstr "Äang cập nhật %s"
#, c-format
msgid "Could not fetch %s"
-msgstr "Không thể lấy“%s†vá»"
+msgstr "Không thể lấy'%s' vá»"
msgid ""
"--mirror is dangerous and deprecated; please\n"
"\t use --mirror=fetch or --mirror=push instead"
msgstr ""
-"--mirror nguy hiểm và không dùng nữa; xin hãy\n"
+"--mirror nguy hiểm và không được dùng nữa; xin hãy\n"
"\t sá»­ dụng tùy chá»n --mirror=fetch hoặc --mirror=push để thay thế"
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "không hiểu tham số máy bản sao (mirror): %s"
+msgid "unknown --mirror argument: %s"
+msgstr "không hiểu tham số --mirror: %s"
msgid "fetch the remote branches"
msgstr "lấy vỠcác nhánh từ máy chủ"
-msgid "import all tags and associated objects when fetching"
-msgstr "nhập vào tất cả các đối tượng thẻ và thành phần liên quan khi lấy vá»"
-
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "hoặc không lấy vỠbất kỳ thẻ nào (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"nhập vào tất cả các thẻ và đối tượng liên quan khi lấy vá»\n"
+"hoặc không nhận vỠmột thẻ nào cả (--no-tags)"
msgid "branch(es) to track"
msgstr "các nhánh để theo dõi"
@@ -10336,7 +10825,7 @@ msgid "specifying a master branch makes no sense with --mirror"
msgstr "Ä‘ang chỉ định má»™t nhánh master không hợp lý vá»›i tùy chá»n --mirror"
msgid "specifying branches to track makes sense only with fetch mirrors"
-msgstr "chỉ định những nhánh để theo dõi chỉ hợp lý vá»›i các “fetch mirrorâ€"
+msgstr "chỉ định những nhánh để theo dõi chỉ hợp lý với các 'fetch mirror'"
#, c-format
msgid "remote %s already exists."
@@ -10344,7 +10833,7 @@ msgstr "máy chủ %s đã tồn tại rồi."
#, c-format
msgid "Could not setup master '%s'"
-msgstr "Không thể cài đặt nhánh master “%sâ€"
+msgstr "Không thể cài đặt nhánh master '%s'"
#, c-format
msgid "more than one %s"
@@ -10352,7 +10841,7 @@ msgstr "nhiá»u hÆ¡n má»™t %s"
#, c-format
msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
-msgstr "nhánh chưa được quản lý.%s.rebase=%s; giả định là “trueâ€"
+msgstr "nhánh chưa được quản lý.%s.rebase=%s; giả định là 'true'"
#, c-format
msgid "Could not get fetch map for refspec %s"
@@ -10366,11 +10855,11 @@ msgstr "(xóa)"
#, c-format
msgid "could not set '%s'"
-msgstr "không thể đặt “%sâ€"
+msgstr "không thể đặt '%s'"
#, c-format
msgid "could not unset '%s'"
-msgstr "không thể thôi đặt “%sâ€"
+msgstr "không thể thôi đặt '%s'"
#, c-format
msgid ""
@@ -10380,15 +10869,15 @@ msgid ""
msgstr ""
"Cấu hình %s remote.pushDefault trong:\n"
"\t%s:%d\n"
-"bây giá» tên trên máy chá»§ không tồn tại “%sâ€"
+"bây giỠtên trên máy chủ không tồn tại '%s'"
#, c-format
msgid "No such remote: '%s'"
-msgstr "Không có máy chá»§ nào như vậy: “%sâ€"
+msgstr "Không có máy chủ nào như vậy: '%s'"
#, c-format
msgid "Could not rename config section '%s' to '%s'"
-msgstr "Không thể đổi tên phần cá»§a cấu hình từ “%s†thành “%sâ€"
+msgstr "Không thể đổi tên phần của cấu hình từ '%s' thành '%s'"
#, c-format
msgid ""
@@ -10396,20 +10885,20 @@ msgid ""
"\t%s\n"
"\tPlease update the configuration manually if necessary."
msgstr ""
-"Không cập nhật “non-default fetch respecâ€\n"
+"Không cập nhật tham chiếu fetch không mặc định\n"
"\t%s\n"
-"\tXin hãy cập nhật phần cấu hình một cách thủ công nếu thấy cần thiết."
+"\tXin hãy cập nhật phần cấu hình một cách thủ công nếu cần."
msgid "Renaming remote references"
msgstr "Äổi tên các tham chiếu máy chá»§"
#, c-format
msgid "deleting '%s' failed"
-msgstr "gặp lá»—i khi xóa “%sâ€"
+msgstr "gặp lỗi khi xóa '%s'"
#, c-format
msgid "creating '%s' failed"
-msgstr "gặp lá»—i khi tạo “%sâ€"
+msgstr "gặp lỗi khi tạo '%s'"
msgid ""
"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
@@ -10424,7 +10913,7 @@ msgstr[0] ""
#, c-format
msgid "Could not remove config section '%s'"
-msgstr "Không thể gỡ bá» phần cấu hình “%sâ€"
+msgstr "Không thể gỡ bỠphần cấu hình '%s'"
#, c-format
msgid " new (next fetch will store in remotes/%s)"
@@ -10433,8 +10922,11 @@ msgstr " mới (lần lấy vỠtiếp theo sẽ lưu trong remotes/%s)"
msgid " tracked"
msgstr " được theo dõi"
+msgid " skipped"
+msgstr " được bỠqua"
+
msgid " stale (use 'git remote prune' to remove)"
-msgstr " cÅ© rích (dùng “git remote prune†để gỡ bá»)"
+msgstr " đã cÅ© (dùng 'git remote prune' để xoá bá»)"
msgid " ???"
msgstr " ???"
@@ -10510,9 +11002,6 @@ msgstr "* máy chủ %s"
msgid " Fetch URL: %s"
msgstr " URL để lấy vá»: %s"
-msgid "(no URL)"
-msgstr "(không có URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -10521,6 +11010,9 @@ msgstr "(không có URL)"
msgid " Push URL: %s"
msgstr " URL để đẩy lên: %s"
+msgid "(no URL)"
+msgstr "(không có URL)"
+
#, c-format
msgid " HEAD branch: %s"
msgstr " Nhánh HEAD: %s"
@@ -10546,15 +11038,15 @@ msgstr " (trạng thái không được yêu cầu)"
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
-msgstr[0] " Những nhánh ná»™i bá»™ đã được cấu hình cho lệnh “git pullâ€:"
+msgstr[0] " Những nhánh nội bộ đã được cấu hình cho lệnh 'git pull':"
msgid " Local refs will be mirrored by 'git push'"
-msgstr " refs ná»™i bá»™ sẽ được phản chiếu bởi lệnh “git pushâ€"
+msgstr " refs nội bộ sẽ được phản chiếu bởi lệnh 'git push'"
#, c-format
msgid " Local ref configured for 'git push'%s:"
msgid_plural " Local refs configured for 'git push'%s:"
-msgstr[0] " Những tham chiếu ná»™i bá»™ được cấu hình cho lệnh “git pushâ€%s:"
+msgstr[0] " Những tham chiếu nội bộ được cấu hình cho lệnh 'git push'%s:"
msgid "set refs/remotes/<name>/HEAD according to remote"
msgstr "đặt refs/remotes/<tên>/HEAD cho phù hợp với máy chủ"
@@ -10609,7 +11101,7 @@ msgstr "cắt máy chá»§ sau khi lấy vá»"
#, c-format
msgid "No such remote '%s'"
-msgstr "Không có máy chá»§ nào có tên “%sâ€"
+msgstr "Không có máy chủ nào có tên '%s'"
msgid "add branch"
msgstr "thêm nhánh"
@@ -10623,12 +11115,8 @@ msgstr "truy vấn đẩy URL thay vì lấy"
msgid "return all URLs"
msgstr "trả vá» má»i URL"
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "không có URL nào được cấu hình cho nhánh “%sâ€"
-
msgid "manipulate push URLs"
-msgstr "đẩy các “URL†bằng tay"
+msgstr "đẩy các 'URL' bằng tay"
msgid "add URL"
msgstr "thêm URL"
@@ -10665,35 +11153,45 @@ msgstr ""
msgid "could not start pack-objects to repack promisor objects"
msgstr ""
-"không thể lấy thông tin thống kê pack-objects để mà đóng gói lại các đối "
-"tượng hứa hẹn"
+"không thể lấy thông tin thống kê pack-objects để đóng gói lại các đối tượng "
+"promisor"
+
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "gặp lỗi khi đưa promisor object cho pack-objects"
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr ""
-"repack: Äang chỉ cần các dòng ID đối tượng dạng thập lục phân đầy dá»§ từ pack-"
-"objects."
+"repack: Äang chỉ cần các dòng ID đối tượng dạng hexa đầy đủ từ pack-objects."
msgid "could not finish pack-objects to repack promisor objects"
-msgstr "không thể hoàn tất pack-objects để đóng gói các đối tượng hứa hẹn"
+msgstr "không thể hoàn tất pack-objects để đóng gói các đối tượng promisor"
#, c-format
msgid "cannot open index for %s"
-msgstr "không thể mở mục lục cho “%sâ€"
+msgstr "không thể mở chỉ mục cho %s"
#, c-format
msgid "pack %s too large to consider in geometric progression"
-msgstr "gói %s là quá lá»›n để được xem là trong tiến trình hình há»c"
+msgstr "gói %s quá lớn để xem xét cấp số nhân"
#, c-format
msgid "pack %s too large to roll up"
-msgstr "gói %s là quá lớn để được cuộn lại"
+msgstr "gói %s quá lớn để cuộn lại"
#, c-format
msgid "could not open tempfile %s for writing"
msgstr "không thể mở tập tin tạm %s để ghi"
msgid "could not close refs snapshot tempfile"
-msgstr "không thể đóng tập tin tạm thá»i chụp nhanh các tham chiếu"
+msgstr "không thể đóng tập tin snapshot các tham chiếu"
+
+#, c-format
+msgid "could not remove stale bitmap: %s"
+msgstr "không thể xoá bỠbitmap đã cũ: %s"
+
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "tiá»n tố gói '%s' không được bắt đầu vá»›i objdir '.%s'"
msgid "pack everything in a single pack"
msgstr "đóng gói má»i thứ trong má»™t gói đơn"
@@ -10708,8 +11206,8 @@ msgstr ""
msgid "approxidate"
msgstr "ngày ước tính"
-msgid "with -C, expire objects older than this"
-msgstr "với -C, các đối tượng hết hạn cũ hơn khoảng này"
+msgid "with --cruft, expire objects older than this"
+msgstr "với --cruft, đánh dấu hết hạn các đối tượng cũ hơn khoảng này"
msgid "remove redundant packs, and run git-prune-packed"
msgstr "xóa bỠcác gói dư thừa, và chạy git-prune-packed"
@@ -10727,7 +11225,7 @@ msgid "pass --local to git-pack-objects"
msgstr "chuyển --local cho git-pack-objects"
msgid "write bitmap index"
-msgstr "ghi mục lục ánh xạ"
+msgstr "ghi chỉ mục ánh xạ"
msgid "pass --delta-islands to git-pack-objects"
msgstr "chuyển --delta-islands cho git-pack-objects"
@@ -10739,7 +11237,7 @@ msgid "with -a, repack unreachable objects"
msgstr "vá»›i -a, đóng gói lại các đối tượng không thể Ä‘á»c được"
msgid "size of the window used for delta compression"
-msgstr "kích thước cá»­a sổ được dùng cho nén “deltaâ€"
+msgstr "kích thước cửa sổ được dùng cho nén 'delta'"
msgid "bytes"
msgstr "byte"
@@ -10748,7 +11246,7 @@ msgid "same as the above, but limit memory size instead of entries count"
msgstr "giống như trên, nhưng giới hạn kích thước bộ nhớ hay vì số lượng"
msgid "limits the maximum delta depth"
-msgstr "giá»›i hạn độ sâu tối Ä‘a cá»§a “deltaâ€"
+msgstr "giới hạn độ sâu tối đa của 'delta'"
msgid "limits the maximum number of threads"
msgstr "giới hạn số lượng tối đa tuyến trình"
@@ -10766,25 +11264,35 @@ msgid "find a geometric progression with factor <N>"
msgstr "tìm má»™t tiến trình hình há»c vá»›i hệ số <N>"
msgid "write a multi-pack index of the resulting packs"
-msgstr "ghi mục lục “multi-pack†của các gói kết quả"
+msgstr "ghi chỉ mục 'multi-pack' của các gói kết quả"
+
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "tiá»n tố cá»§a gói để lưu gói gồm những đối tượng đã loại bá»"
+
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "tiá»n tố cá»§a gói để lưu gói gồm những đối tượng đã lá»c bá»"
msgid "cannot delete packs in a precious-objects repo"
-msgstr "không thể xóa các gói trong một kho đối_tượng_vĩ_đại"
+msgstr "không thể xóa các gói trong một kho đối tượng cần thiết"
+
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "tuỳ chá»n '%s' chỉ có thể được dùng vá»›i '%s'"
msgid "Nothing new to pack."
-msgstr "Không có gì mới để mà đóng gói."
+msgstr "Không có gì mới để đóng gói."
#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "tiá»n tố gói “%s†không được bắt đầu vá»›i objdir “.%sâ€"
+msgid "renaming pack to '%s' failed"
+msgstr "gặp lỗi khi đổi tên gói thành '%s'"
#, c-format
-msgid "missing required file: %s"
-msgstr "thiếu tập tin cần thiết: %s"
+msgid "pack-objects did not write a '%s' file for pack %s-%s"
+msgstr "pack-objects không ghi tập tin '%s' cho gói %s-%s"
#, c-format
msgid "could not unlink: %s"
-msgstr "không thể bỠliên kết: %s"
+msgstr "không thể unlink: %s"
msgid "git replace [-f] <object> <replacement>"
msgstr "git replace [-f] <đối-tượng> <thay-thế>"
@@ -10793,37 +11301,37 @@ msgid "git replace [-f] --edit <object>"
msgstr "git replace [-f] --edit <đối tượng>"
msgid "git replace [-f] --graft <commit> [<parent>...]"
-msgstr "git replace [-f] --graft <lần_chuyển_giao> [<cha_mẹ>…]"
+msgstr "git replace [-f] --graft <lần_chuyển_giao> [<cha_mẹ>...]"
msgid "git replace -d <object>..."
-msgstr "git replace -d <đối tượng>…"
+msgstr "git replace -d <đối tượng>..."
msgid "git replace [--format=<format>] [-l [<pattern>]]"
-msgstr "git replace [--format=<định_dạng>] [-l [<mẫu>]]"
+msgstr "git replace [--format=<định dạng>] [-l [<mẫu>]]"
#, c-format
msgid ""
"invalid replace format '%s'\n"
"valid formats are 'short', 'medium' and 'long'"
msgstr ""
-"định dạng thay thế không hợp lệ “%sâ€\n"
-"định dạng hợp lệ là “shortâ€, “medium†và “longâ€"
+"định dạng thay thế không hợp lệ '%s'\n"
+"định dạng hợp lệ là 'short', 'medium' và 'long'"
#, c-format
msgid "replace ref '%s' not found"
-msgstr "không tìm thấy tham chiếu thay thế “%sâ€"
+msgstr "không tìm thấy tham chiếu thay thế '%s'"
#, c-format
msgid "Deleted replace ref '%s'"
-msgstr "Äã xóa tham chiếu thay thế “%sâ€"
+msgstr "Äã xóa tham chiếu thay thế '%s'"
#, c-format
msgid "'%s' is not a valid ref name"
-msgstr "“%s†không phải tên tham chiếu hợp lệ"
+msgstr "'%s' không phải tên tham chiếu hợp lệ"
#, c-format
msgid "replace ref '%s' already exists"
-msgstr "tham chiếu thay thế “%s†đã tồn tại rồi"
+msgstr "tham chiếu thay thế '%s' đã tồn tại rồi"
#, c-format
msgid ""
@@ -10832,19 +11340,19 @@ msgid ""
"while '%s' points to a replacement object of type '%s'."
msgstr ""
"Các đối tượng phải cùng kiểu.\n"
-"“%s†chỉ đến đối tượng thay thế cá»§a kiểu “%sâ€\n"
-"trong khi “%s†chỉ đến đối tượng tham chiếu cá»§a kiểu “%sâ€."
+"'%s' chỉ đến đối tượng thay thế của kiểu '%s'\n"
+"trong khi '%s' chỉ đến đối tượng tham chiếu của kiểu '%s'."
#, c-format
msgid "unable to open %s for writing"
-msgstr "không thể mở “%s†để ghi"
+msgstr "không thể mở '%s' để ghi"
msgid "cat-file reported failure"
-msgstr "cat-file đã báo cáo gặp lá»—i nghiêm trá»ng"
+msgstr "cat-file đã báo nghiêm trá»ng"
#, c-format
msgid "unable to open %s for reading"
-msgstr "không thể mở “%s†để Ä‘á»c"
+msgstr "không thể mở '%s' để Ä‘á»c"
msgid "unable to spawn mktree"
msgstr "không thể sinh tiến trình con mktree"
@@ -10853,7 +11361,7 @@ msgid "unable to read from mktree"
msgstr "không thể Ä‘á»c từ mktree"
msgid "mktree reported failure"
-msgstr "mktree đã báo cáo gặp lá»—i nghiêm trá»ng"
+msgstr "mktree đã báo lá»—i nghiêm trá»ng"
msgid "mktree did not return an object name"
msgstr "mktree đã không trả vỠmột tên đối tượng"
@@ -10874,46 +11382,46 @@ msgstr "việc sửa tập tin đối tượng gặp lỗi"
#, c-format
msgid "new object is the same as the old one: '%s'"
-msgstr "đối tượng má»›i là giống vá»›i cái cÅ©: “%sâ€"
+msgstr "đối tượng mới là giống với cái cũ: '%s'"
#, c-format
msgid "could not parse %s as a commit"
-msgstr "không thể phân tích %s như là một lần chuyển giao"
+msgstr "không thể Ä‘á»c %s như là má»™t lần chuyển giao"
#, c-format
msgid "bad mergetag in commit '%s'"
-msgstr "thẻ hòa trá»™n sai trong lần chuyển giao “%sâ€"
+msgstr "thẻ hòa trộn sai trong lần chuyển giao '%s'"
#, c-format
msgid "malformed mergetag in commit '%s'"
-msgstr "thẻ hòa trá»™n không đúng dạng ở lần chuyển giao “%sâ€"
+msgstr "thẻ hòa trá»™n bất thưá»ng dạng ở lần chuyển giao '%s'"
#, c-format
msgid ""
"original commit '%s' contains mergetag '%s' that is discarded; use --edit "
"instead of --graft"
msgstr ""
-"lần chuyển giao gốc “%s†có chứa thẻ hòa trá»™n “%s†cái mà bị loại bá»; dùng "
-"tùy chá»n --edit thay cho --graft"
+"lần chuyển giao gốc '%s' có chứa thẻ hòa trá»™n '%s' đã bị loại bá»; dùng tùy "
+"chá»n --edit thay cho --graft"
#, c-format
msgid "the original commit '%s' has a gpg signature"
-msgstr "lần chuyển giao gốc “%s†có chữ ký GPG"
+msgstr "lần chuyển giao gốc '%s' có chữ ký GPG"
msgid "the signature will be removed in the replacement commit!"
msgstr "chữ ký sẽ được bỠđi trong lần chuyển giao thay thế!"
#, c-format
msgid "could not write replacement commit for: '%s'"
-msgstr "không thể ghi lần chuyển giao thay thế cho: “%sâ€"
+msgstr "không thể ghi lần chuyển giao thay thế cho: '%s'"
#, c-format
msgid "graft for '%s' unnecessary"
-msgstr "graft cho “%s†không cần thiết"
+msgstr "graft cho '%s' không cần thiết"
#, c-format
msgid "new commit is the same as the old one: '%s'"
-msgstr "lần chuyển giao má»›i là giống vá»›i cái cÅ©: “%sâ€"
+msgstr "lần chuyển giao mới là giống với cái cũ: '%s'"
#, c-format
msgid ""
@@ -10972,21 +11480,87 @@ msgid "--convert-graft-file takes no argument"
msgstr "--convert-graft-file không nhận đối số"
msgid "only one pattern can be given with -l"
-msgstr "chỉ má»™t mẫu được chỉ ra vá»›i tùy chá»n -l"
+msgstr "chỉ được chỉ định má»™t mẫu cùng vá»›i tùy chá»n -l"
+
+msgid "need some commits to replay"
+msgstr "cần các chuyển giao để phát lại"
+
+msgid "--onto and --advance are incompatible"
+msgstr "--onto và --advance xung khắc"
+
+msgid "all positive revisions given must be references"
+msgstr "má»i Ä‘iểm xét duyệt cá»™ng thêm phải là tên tham chiếu"
-msgid "git rerere [clear | forget <path>... | status | remaining | diff | gc]"
+msgid "argument to --advance must be a reference"
+msgstr "tham số cho --advance phải là tham chiếu"
+
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr "không thể đẩy nhánh vá»›i nhiá»u nguồn vì thứ tá»± không xác định"
+
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr "không thể tự xác định là thực hiện --advance hay --onto"
+
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr "không thể đẩy nhánh vá»›i nhiá»u nhánh nguồn vì thứ tá»± không xác định"
+
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "không thể tự xác định gốc thực hiện --onto"
+
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(TRONG QUà TRÌNH THỬ NGHIỆM!) git replay ([--contained] --onto <gốc mới> | "
+"--advance <nhánh>) <khoảng-xét-duyệt>..."
+
+msgid "make replay advance given branch"
+msgstr "đẩy nhánh này trong khi phát lại"
+
+msgid "replay onto given commit"
+msgstr "phát lại vào commit này"
+
+msgid "advance all branches contained in revision-range"
+msgstr "đẩy tất cả các nhánh có trong khoảng-xét-duyệt "
+
+msgid "option --onto or --advance is mandatory"
+msgstr "tuỳ chá»n --onto hoặc --advance là bắt buá»™c"
+
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
msgstr ""
-"git rerere [clear | forget <đưá»ng dẫn>… | status | remaining | diff | gc]"
+"má»™t số tuỳ chá»n duyệt qua Ä‘iểm xét duyệt sẽ bị bá» qua do bit '%s' trong "
+"'struct rev_info' bị ép bật/tắt"
+
+msgid "error preparing revisions"
+msgstr "gặp lỗi khi chuẩn bị các điểm xét duyệt"
+
+msgid "replaying down to root commit is not supported yet!"
+msgstr "chưa hỗ trợ phát lại đến lần chuyển giao gốc!"
+
+msgid "replaying merge commits is not supported yet!"
+msgstr "chưa hỗ trợ phát lại các lần hoà trộn!"
+
+msgid ""
+"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
+msgstr ""
+"git rerere [clear | forget <đưá»ng dẫn>... | diff | status | remaining | gc]"
msgid "register clean resolutions in index"
-msgstr "sổ ghi dá»n sạch các phân giải trong bản mục lục"
+msgstr "ghi lại các lần giải quyết ổn thoả xung đột trong chỉ mục"
msgid "'git rerere forget' without paths is deprecated"
-msgstr "“git rerere forget†mà không có các đưá»ng dẫn là đã lạc hậu"
+msgstr "không còn dùng 'git rerere forget' mà không có các đưá»ng dẫn"
#, c-format
msgid "unable to generate diff for '%s'"
-msgstr "không thể tạo khác biệt cho “%sâ€"
+msgstr "không thể tạo diff cho '%s'"
msgid ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
@@ -10994,7 +11568,7 @@ msgstr ""
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
msgid "git reset [-q] [<tree-ish>] [--] <pathspec>..."
-msgstr "git reset [-q] [<tree-ish>] [--] <đặc/tả/đưá»ng/dẫn>…"
+msgstr "git reset [-q] [<tree-ish>] [--] <đặc/tả/đưá»ng/dẫn>..."
msgid ""
"git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
@@ -11002,7 +11576,7 @@ msgstr ""
"git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
msgid "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
-msgstr "git reset --patch [<tree-ish>] [--] [<đặc/tả/đưá»ng/dẫn>…]"
+msgstr "git reset --patch [<tree-ish>] [--] [<đặc/tả/đưá»ng/dẫn>...]"
msgid "mixed"
msgstr "pha trá»™n"
@@ -11041,16 +11615,16 @@ msgid "be quiet, only report errors"
msgstr "làm việc ở chế độ im lặng, chỉ hiển thị khi có lỗi"
msgid "skip refreshing the index after reset"
-msgstr "bỠqua làm tươi mục lục sau khi đặt lại"
+msgstr "bỠqua làm mới chỉ mục sau khi reset"
msgid "reset HEAD and index"
-msgstr "đặt lại (reset) HEAD và bảng mục lục"
+msgstr "đặt lại HEAD và chỉ mục"
msgid "reset only HEAD"
-msgstr "chỉ đặt lại (reset) HEAD"
+msgstr "chỉ đặt lại HEAD"
msgid "reset HEAD, index and working tree"
-msgstr "đặt lại HEAD, bảng mục lục và cây làm việc"
+msgstr "đặt lại HEAD, chỉ mục và cây làm việc"
msgid "reset HEAD but keep local changes"
msgstr "đặt lại HEAD nhưng giữ lại các thay đổi nội bộ"
@@ -11060,16 +11634,16 @@ msgstr "chỉ ghi lại những đưá»ng dẫn thá»±c sá»± sẽ được thêm
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
-msgstr "Gặp lỗi khi phân giải “%s†như là điểm xét duyệt hợp lệ."
+msgstr "Gặp lỗi khi phân giải '%s' thành điểm xét duyệt hợp lệ."
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
-msgstr "Gặp lỗi khi phân giải “%s†như là một cây (tree) hợp lệ."
+msgstr "Gặp lỗi khi phân giải '%s' như là một cây (tree) hợp lệ."
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
-"--mixed vá»›i các đưá»ng dẫn không còn dùng nữa; hãy thay thế bằng lệnh “git "
-"reset -- </các/đưá»ng/dẫn>â€."
+"không còn dùng --mixed vá»›i các đưá»ng dẫn nữa; hãy thay thế bằng lệnh 'git "
+"reset -- </các/đưá»ng/dẫn>'."
#, c-format
msgid "Cannot do %s reset with paths."
@@ -11077,31 +11651,35 @@ msgstr "Không thể thá»±c hiện lệnh %s reset vá»›i các đưá»ng dẫn."
#, c-format
msgid "%s reset is not allowed in a bare repository"
-msgstr "%s reset không được phép trên kho thuần"
+msgstr "%s reset không được phép trên kho chứa bare"
msgid "Unstaged changes after reset:"
-msgstr "Những thay đổi được đưa ra khá»i bệ phóng sau khi reset:"
+msgstr "Những thay đổi được đưa ra khá»i vùng chá» sau khi reset:"
#, c-format
msgid ""
"It took %.2f seconds to refresh the index after reset. You can use\n"
"'--no-refresh' to avoid this."
msgstr ""
-"Việc này cần %.2f giây để làm tươi mới mục lục sau khi đặt lại. Bạn có thể "
+"Việc này cần %.2f giây để làm tươi mới chỉ mục sau khi đặt lại. Bạn có thể "
"sử dụng\n"
-"“--no-refresh†tránh Ä‘iá»u này."
+"'--no-refresh' tránh Ä‘iá»u này."
#, c-format
msgid "Could not reset index file to revision '%s'."
-msgstr "Không thể đặt lại (reset) bảng mục lục thành Ä‘iểm xét duyệt “%sâ€."
+msgstr "Không thể đặt lại (reset) chỉ mục thành điểm xét duyệt '%s'."
msgid "Could not write new index file."
-msgstr "Không thể ghi tập tin lưu bảng mục lục mới."
+msgstr "Không thể ghi tập tin chỉ mục mới."
#, c-format
msgid "unable to get disk usage of %s"
msgstr "không thể dung lượng đĩa đã dùng của %s"
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "giá trị không hợp lệ cho '%s': '%s', chỉ cho phép định dạng là '%s'"
+
msgid "rev-list does not support display of notes"
msgstr "rev-list không hỗ trợ hiển thị các ghi chú"
@@ -11110,22 +11688,25 @@ msgid "marked counting and '%s' cannot be used together"
msgstr "đánh dấu để đếm và '%s' không thể dùng cùng nhau"
msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
-msgstr "git rev-parse --parseopt [<các tùy chá»n>] -- [<các tham số>…]"
+msgstr "git rev-parse --parseopt [<các tùy chá»n>] -- [<các tham số>...]"
msgid "keep the `--` passed as an arg"
-msgstr "giữ lại “--†chuyển sang làm tham số"
+msgstr "giữ lại '--' chuyển sang làm tham số"
msgid "stop parsing after the first non-option argument"
-msgstr "dừng phân tích sau đối số đầu tiên không có tùy chá»n"
+msgstr "dừng Ä‘á»c sau đối số đầu tiên không có tùy chá»n"
msgid "output in stuck long form"
-msgstr "kết xuất trong định dạng gậy dài"
+msgstr "kết quả có định dạng dài"
msgid "premature end of input"
-msgstr "đầu vào chấm dứt bất thưá»ng"
+msgstr "đầu vào kết thúc bất thưá»ng"
msgid "no usage string given before the `--' separator"
-msgstr "không có chuá»—i cách dùng nào được đưa ra trước dấu phân cách “--â€"
+msgstr "không có chuỗi cách dùng nào được đưa ra trước dấu phân cách '--'"
+
+msgid "missing opt-spec before option flags"
+msgstr "thiếu opt-spec trước các tuỳ chá»n"
msgid "Needed a single revision"
msgstr "Cần một điểm xét duyệt đơn"
@@ -11137,9 +11718,9 @@ msgid ""
"\n"
"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
msgstr ""
-"git rev-parse --parseopt [<các tùy chá»n>] -- [<các đối số>…]\n"
-" hoặc: git rev-parse --sq-quote [<đ.số>…]\n"
-" hoặc: git rev-parse [<các tùy chá»n>] [<Ä‘.số>…]\n"
+"git rev-parse --parseopt [<các tùy chá»n>] -- [<các đối số>...]\n"
+" hoặc: git rev-parse --sq-quote [<đ.số>...]\n"
+" hoặc: git rev-parse [<các tùy chá»n>] [<Ä‘.số>...]\n"
"\n"
"Chạy lệnh \"git rev-parse --parseopt -h\" để có thêm thông tin vỠcách dùng."
@@ -11148,7 +11729,7 @@ msgstr "--resolve-git-dir cần một tham số"
#, c-format
msgid "not a gitdir '%s'"
-msgstr "không phải má»™t thư mục git “%sâ€"
+msgstr "không phải một thư mục git '%s'"
msgid "--git-path requires an argument"
msgstr "--git-path cần một tham số"
@@ -11169,6 +11750,13 @@ msgstr "--default cần một tham số"
msgid "--prefix requires an argument"
msgstr "--prefix cần một tham số"
+msgid "no object format specified"
+msgstr "không chỉ ra định dạng đối tượng"
+
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "không hỗ trợ định dạng đối tượng: %s"
+
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "không hiểu chế độ cho --abbrev-ref: %s"
@@ -11176,25 +11764,36 @@ msgstr "không hiểu chế độ cho --abbrev-ref: %s"
msgid "this operation must be run in a work tree"
msgstr "thao tác này phải được thực hiện trong thư mục làm việc"
+msgid "Could not read the index"
+msgstr "Không thể Ä‘á»c chỉ mục"
+
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "không hiểu chế độ cho --show-object-format: %s"
-msgid "git revert [<options>] <commit-ish>..."
-msgstr "git revert [<các tùy chá»n>] <commit-ish>…"
+msgid ""
+"git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
+"<commit>..."
+msgstr ""
+"git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
+"<commit>..."
-msgid "git revert <subcommand>"
-msgstr "git revert <lệnh-con>"
+msgid "git revert (--continue | --skip | --abort | --quit)"
+msgstr "git revert (--continue | --skip | --abort | --quit)"
-msgid "git cherry-pick [<options>] <commit-ish>..."
-msgstr "git cherry-pick [<các tùy chá»n>] <commit-ish>…"
+msgid ""
+"git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
+" [-S[<keyid>]] <commit>..."
+msgstr ""
+"git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
+" [-S[<keyid>]] <commit>..."
-msgid "git cherry-pick <subcommand>"
-msgstr "git cherry-pick <lệnh-con>"
+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 "tùy chá»n “%s†cần má»™t giá trị bằng số lá»›n hÆ¡n không"
+msgstr "tùy chá»n '%s' cần má»™t giá trị bằng số lá»›n hÆ¡n không"
#, c-format
msgid "%s: %s cannot be used with %s"
@@ -11239,8 +11838,8 @@ msgstr "cấm khởi tạo lần chuyển giao trống rỗng"
msgid "allow commits with empty messages"
msgstr "chấp nhận chuyển giao mà không ghi chú gì"
-msgid "keep redundant, empty commits"
-msgstr "giữ lại các lần chuyển giao dư thừa, rỗng"
+msgid "deprecated: use --empty=keep instead"
+msgstr "đã lạc hậu: hãy dùng --empty=keep"
msgid "use the 'reference' format to refer to commits"
msgstr "dùng định dạng 'tham chiếu' để quy cho các lần chuyển giao"
@@ -11251,8 +11850,14 @@ msgstr "hoàn nguyên gặp lỗi"
msgid "cherry-pick failed"
msgstr "cherry-pick gặp lỗi"
-msgid "git rm [<options>] [--] <file>..."
-msgstr "git rm [<các tùy chá»n>] [--] <tập-tin>…"
+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]\n"
+" [--quiet] [--pathspec-from-file=<tập tin> [--pathspec-file-nul]]\n"
+" [--] [<đặc/tả/đưá»ng/dẫn>...]]"
msgid ""
"the following file has staged content different from both the\n"
@@ -11261,7 +11866,7 @@ msgid_plural ""
"the following files have staged content different from both the\n"
"file and the HEAD:"
msgstr[0] ""
-"các tập tin sau đây có khác biệt nội dung đã đưa lên bệ phóng\n"
+"các tập tin sau đây có khác biệt ná»™i dung đã đưa vào vùng chá»\n"
"từ cả tập tin và cả HEAD:"
msgid ""
@@ -11273,7 +11878,7 @@ msgstr ""
msgid "the following file has changes staged in the index:"
msgid_plural "the following files have changes staged in the index:"
-msgstr[0] "các tập tin sau đây có thay đổi trạng thái trong bảng mục lục:"
+msgstr[0] "các tập tin sau đây có thay đổi trạng thái trong chỉ mục:"
msgid ""
"\n"
@@ -11290,13 +11895,13 @@ msgid "do not list removed files"
msgstr "không liệt kê các tập tin đã gỡ bá»"
msgid "only remove from the index"
-msgstr "chỉ gỡ bỠtừ mục lục"
+msgstr "chỉ gỡ bỠtừ chỉ mục"
msgid "override the up-to-date check"
msgstr "ghi đè lên kiểm tra cập nhật"
msgid "allow recursive removal"
-msgstr "cho phép gỡ bỠđệ qui"
+msgstr "cho phép gỡ bỠđệ quy"
msgid "exit with a zero status even if nothing matched"
msgstr "thoát ra với trạng thái khác không thậm chí nếu không có gì khớp"
@@ -11310,7 +11915,7 @@ msgstr ""
#, c-format
msgid "not removing '%s' recursively without -r"
-msgstr "không thể gỡ bỠ“%s†má»™t cách đệ qui mà không có tùy chá»n -r"
+msgstr "không thể gỡ bá» '%s' má»™t cách đệ quy mà không có tùy chá»n -r"
#, c-format
msgid "git rm: unable to remove %s"
@@ -11320,37 +11925,43 @@ 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-receive-pack>]\n"
" [--verbose] [--thin] [--atomic]\n"
-" [<host>:]<thư mục> (--all | <tham chiếu>…)"
+" [--[no-]signed | --signed=(true|false|if-asked)]\n"
+" [<host>:]<thư mục> (--all | <tham chiếu>...)"
msgid "remote name"
msgstr "tên máy dịch vụ"
+msgid "push all refs"
+msgstr "đẩy tất cả các tham chiếu"
+
msgid "use stateless RPC protocol"
msgstr "dùng giao thức RPC không ổn định"
msgid "read refs from stdin"
-msgstr "Ä‘á»c tham chiếu từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c tham chiếu từ stdin"
msgid "print status from remote helper"
msgstr "in các trạng thái từ phần hướng dẫn trên máy dịch vụ"
msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
-msgstr "git shortlog [<các tùy chá»n>] [<vùng-xét-duyệt>] [[--] [<đưá»ng/dẫn>…]]"
+msgstr ""
+"git shortlog [<các tùy chá»n>] [<vùng-xét-duyệt>] [[--] [<đưá»ng/dẫn>...]]"
msgid "git log --pretty=short | git shortlog [<options>]"
msgstr "git log --pretty=short | git shortlog [<các tùy chá»n>]"
msgid "using multiple --group options with stdin is not supported"
-msgstr ""
-"việc dùng nhiá»u tùy chá»n --group vá»›i đầu ra tiêu chuẩn là không được há»— trợ"
+msgstr "việc dùng nhiá»u tùy chá»n --group vá»›i stdin là không được há»— trợ"
-msgid "using --group=trailer with stdin is not supported"
-msgstr "việc dùng --group=trailer với đầu ra tiêu chuẩn là không được hỗ trợ"
+#, c-format
+msgid "using %s with stdin is not supported"
+msgstr "không hỗ trợ dùng %s cùng stdin"
#, c-format
msgid "unknown group type: %s"
@@ -11360,7 +11971,7 @@ msgid "group by committer rather than author"
msgstr "nhóm theo ngưá»i chuyển giao thay vì tác giả"
msgid "sort output according to the number of commits per author"
-msgstr "sắp xếp kết xuất tuân theo số lượng chuyển giao trên mỗi tác giả"
+msgstr "sắp xếp kết quả theo số lượng chuyển giao trên mỗi tác giả"
msgid "suppress commit descriptions, only provides commit count"
msgstr "chặn má»i mô tả lần chuyển giao, chỉ đưa ra số lượng lần chuyển giao"
@@ -11387,15 +11998,17 @@ 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 ""
"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>)...]"
msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
-msgstr "git show-branch (-g | --reflog)[=<n>[,<ná»n>]] [--list] [<ref>]"
+msgstr "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
#, c-format
msgid "ignoring %s; cannot handle more than %d ref"
@@ -11413,7 +12026,7 @@ msgid "show remote-tracking branches"
msgstr "hiển thị các nhánh remote-tracking"
msgid "color '*!+-' corresponding to the branch"
-msgstr "màu “*!+-†tương ứng với nhánh"
+msgstr "màu '*!+-' tương ứng với nhánh"
msgid "show <n> more commits after the common ancestor"
msgstr "hiển thị thêm <n> lần chuyển giao sau cha mẹ chung"
@@ -11431,7 +12044,7 @@ msgid "name commits with their object names"
msgstr "đặt tên các lần chuyển giao bằng các tên của đối tượng của chúng"
msgid "show possible merge bases"
-msgstr "hiển thị má»i cÆ¡ sở có thể dùng để hòa trá»™n"
+msgstr "hiển thị má»i gốc hòa trá»™n khả dụng"
msgid "show refs unreachable from any other ref"
msgstr "hiển thị các tham chiếu không thể được Ä‘á»c bởi bất kỳ tham chiếu khác"
@@ -11443,7 +12056,7 @@ msgid "show only commits not on the first branch"
msgstr "chỉ hiển thị các lần chuyển giao không nằm trên nhánh đầu tiên"
msgid "show merges reachable from only one tip"
-msgstr "hiển thị các lần hòa trá»™n có thể Ä‘á»c được chỉ từ má»™t đầu mút"
+msgstr "hiển thị các lần hòa trá»™n có thể Ä‘á»c được chỉ từ má»™t đỉnh"
msgid "topologically sort, maintaining date order where possible"
msgstr "sắp xếp hình thái há»c, bảo trì thứ tá»± ngày nếu có thể"
@@ -11452,7 +12065,7 @@ msgid "<n>[,<base>]"
msgstr "<n>[,<cơ_sở>]"
msgid "show <n> most recent ref-log entries starting at base"
-msgstr "hiển thị <n> các mục “ref-log†gần nhất kể từ ná»n (base)"
+msgstr "hiển thị <n> các mục 'ref-log' gần nhất kể từ ná»n (base)"
msgid "no branches given, and HEAD is not valid"
msgstr "chưa đưa ra nhánh, và HEAD không hợp lệ"
@@ -11476,7 +12089,7 @@ msgstr[0] "không thể xá»­ lý nhiá»u hÆ¡n %d Ä‘iểm xét duyệt."
#, c-format
msgid "'%s' is not a valid ref."
-msgstr "“%s†không phải tham chiếu hợp lệ."
+msgstr "'%s' không phải tham chiếu hợp lệ."
#, c-format
msgid "cannot find commit %s (%s)"
@@ -11489,61 +12102,83 @@ msgid "Unknown hash algorithm"
msgstr "Không hiểu thuật toán băm dữ liệu"
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --"
-"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --"
-"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<mẫu>…]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<mẫu>...]"
+
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
+msgstr ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<mẫu>...]"
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<mẫu>]"
-msgid "only show tags (can be combined with heads)"
-msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng với đầu)"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <tham_chiếu>"
+
+msgid "reference does not exist"
+msgstr "tham chiếu không tồn tại"
+
+msgid "failed to look up reference"
+msgstr "gặp lỗi khi tìm tham chiếu"
+
+msgid "only show tags (can be combined with --branches)"
+msgstr "chỉ hiển thị thẻ (có thể kết hợp với --branches)"
-msgid "only show heads (can be combined with tags)"
-msgstr "chỉ hiển thị đầu (có thể tổ hợp cùng với thẻ)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "chỉ hiển thị đầu (có thể kết hợp với --tags)"
+
+msgid "check for reference existence without resolving"
+msgstr "kiểm tra tồn tại tham chiếu nhưng không phân giải"
msgid "stricter reference checking, requires exact ref path"
-msgstr ""
-"việc kiểm tra tham chiếu chính xác, đòi há»i chính xác đưá»ng dẫn tham chiếu"
+msgstr "kiểm tra tham chiếu chính xác, đòi há»i chính xác đưá»ng dẫn tham chiếu"
msgid "show the HEAD reference, even if it would be filtered out"
msgstr "hiển thị tham chiếu HEAD, ngay cả khi nó đã được lá»c ra"
msgid "dereference tags into object IDs"
-msgstr "bãi bỠtham chiếu các thẻ thành ra các ID đối tượng"
+msgstr "giải tham chiếu các thẻ thành các ID đối tượng"
msgid "only show SHA1 hash using <n> digits"
msgstr "chỉ hiển thị mã băm SHA1 sử dụng <n> chữ số"
msgid "do not print results to stdout (useful with --verify)"
-msgstr ""
-"không hiển thị kết quả ra đầu ra chuẩn (stdout) (chỉ hữu dụng với --verify)"
+msgstr "không hiển thị kết quả ra stdout (hữu dụng khi dùng cùng --verify)"
msgid "show refs from stdin that aren't in local repository"
-msgstr ""
-"hiển thị các tham chiếu từ đầu vào tiêu chuẩn (stdin) cái mà không ở kho nội "
-"bá»™"
+msgstr "hiển thị các tham chiếu từ stdin mà không ở kho nội bộ"
-msgid "git sparse-checkout (init|list|set|add|reapply|disable) <options>"
-msgstr "git sparse-checkout (init|list|set|add|reapply|disable) <các-tùy-chá»n>"
+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) [<các-tùy-chá»n>]"
msgid "this worktree is not sparse"
-msgstr "cây làm việc này không phải là sparse"
+msgstr "cây làm việc này không thưa"
msgid "this worktree is not sparse (sparse-checkout file may not exist)"
msgstr ""
-"không thể phân tích cú pháp cây làm việc này (tập tin sparse-checkout có lẽ "
-"không tồn tại)"
+"cây làm việc này không thưa (tập tin sparse-checkout có lẽ không tồn tại)"
#, c-format
msgid ""
"directory '%s' contains untracked files, but is not in the sparse-checkout "
"cone"
msgstr ""
-"thư mục “%s†có chứa các tập tin chưa được theo dõi, nhưng lại không trong "
-"“sparse-checkout coneâ€"
+"thư mục '%s' có chứa các tập tin chưa được theo dõi, nhưng không nằm trong "
+"'sparse-checkout cone' (vùng checkout thưa)"
#, c-format
msgid "failed to remove directory '%s'"
@@ -11552,39 +12187,43 @@ msgstr "gặp lỗi khi gỡ bỠthư mục \"%s\""
msgid "failed to create directory for sparse-checkout file"
msgstr "gặp lỗi khi tạo thư mục cho tập tin sparse-checkout"
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "không thể fdopen %s"
+
msgid "failed to initialize worktree config"
msgstr "gặp lỗi khi khởi tạo cấu hình cây làm việc"
msgid "failed to modify sparse-index config"
-msgstr "gặp lỗi khi sửa cấu hình \"sparse-index\""
+msgstr "gặp lỗi khi sửa cấu hình sparse-index"
msgid "initialize the sparse-checkout in cone mode"
msgstr "khởi tạo sparse-checkout trong chế độ nón"
msgid "toggle the use of a sparse index"
-msgstr "bật tắt việc sử dụng một \"sparse index\""
+msgstr "bật tắt việc sử dụng sparse index"
#, c-format
msgid "unable to create leading directories of %s"
-msgstr "không thể tạo các thư mục dẫn đầu cá»§a “%sâ€"
+msgstr "không thể tạo các thư mục dẫn đầu của '%s'"
#, c-format
msgid "failed to open '%s'"
-msgstr "gặp lá»—i khi mở “%sâ€"
+msgstr "gặp lỗi khi mở '%s'"
#, c-format
msgid "could not normalize path %s"
-msgstr "không thể thưá»ng hóa đưá»ng dẫn “%sâ€"
+msgstr "không thể thưá»ng hóa đưá»ng dẫn '%s'"
#, c-format
msgid "unable to unquote C-style string '%s'"
-msgstr "không thể bá» trích dẫn chuá»—i kiểu C “%sâ€"
+msgstr "không thể bỠtrích dẫn chuỗi kiểu C '%s'"
msgid "unable to load existing sparse-checkout patterns"
msgstr "không thể tải các mẫu sparse-checkout"
msgid "existing sparse-checkout patterns do not use cone mode"
-msgstr "đặt các mẫu sparse-checkout sẵn có không sử dụng chế độ cone"
+msgstr "các mẫu sparse-checkout sẵn có không sử dụng chế độ cone"
msgid "please run from the toplevel directory in non-cone mode"
msgstr "vui lòng chạy từ thư mục mức cao nhất trong chế độ non-cone"
@@ -11619,8 +12258,8 @@ 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 ""
-"chuyển má»™t dấu xổ chéo dẫn đầu đưá»ng dẫn như là '%s' nếu bạn muốn má»™t tập "
-"tin đơn (xem NON-CONE PROBLEMS trong hướng dẫn sử dụng git-sparse-checkout)."
+"dùng dấu gạch chéo dẫn đầu trước đưá»ng dẫn như '%s' nếu bạn muốn má»™t tập tin "
+"đơn lẻ (xem NON-CONE PROBLEMS trong hướng dẫn sử dụng git-sparse-checkout)."
msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
msgstr "git sparse-checkout add [--skip-checks] (--stdin | <các mẫu>)"
@@ -11628,11 +12267,11 @@ msgstr "git sparse-checkout add [--skip-checks] (--stdin | <các mẫu>)"
msgid ""
"skip some sanity checks on the given paths that might give false positives"
msgstr ""
-"bá» qua má»™t số kiểm tra đúng mục trên đưá»ng dẫn đã cho cái mà có thể đưa ra "
-"xác thực sai"
+"bá» qua má»™t số tiá»n kiểm tra có thể không cho kết quả đúng trên các đưá»ng dẫn "
+"đã cho"
msgid "read patterns from standard in"
-msgstr "Ä‘á»c các mẫu từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c các mẫu từ stdin"
msgid "no sparse-checkout to add to"
msgstr "không có sparse-checkout để thêm vào"
@@ -11645,76 +12284,82 @@ msgstr ""
"(--stdin | <các mẫu>)"
msgid "must be in a sparse-checkout to reapply sparsity patterns"
-msgstr "phải trong một sparse-checkout để áp dụng lại các mẫu sparse"
+msgstr "phải trong sparse-checkout để áp dụng lại các mẫu sparse"
msgid "error while refreshing working directory"
msgstr "gặp lá»—i khi Ä‘á»c lại thư mục làm việc"
-msgid "git stash list [<options>]"
-msgstr "git stash list [<các tùy chá»n>]"
+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 <tập tin>]"
-msgid "git stash show [<options>] [<stash>]"
-msgstr "git stash show [<các tùy chá»n>] <stash>"
+msgid "terminate input and output files by a NUL character"
+msgstr "kết thúc các bản ghi vào và ra bằng ký tự NULL"
-msgid "git stash drop [-q|--quiet] [<stash>]"
-msgstr "git stash drop [-q|--quiet] [<stash>]"
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr "khi dùng với --rules-file, dùng mẫu ở chế độ cone"
-msgid "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
-msgstr "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
+msgid "use patterns in <file> instead of the current ones."
+msgstr "dùng mẫu từ <tập tin> thay vì các mẫu hiện tại"
-msgid "git stash branch <branchname> [<stash>]"
-msgstr "git stash branch <tên-nhánh> [<stash>]"
+msgid "git stash list [<log-options>]"
+msgstr "git stash list [<các tùy chá»n>]"
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 ""
-"git stash [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
-"quiet]\n"
-" [-u|--include-untracked] [-a|--all] [-m|--message <ghi chú>]\n"
-" [--pathspec-from-file=<tập_tin> [--pathspec-file-nul]]\n"
-" [--] [<đặc/tả/đưá»ng/dẫn>…]]"
+"git stash show [-u | --include-untracked | --only-untracked] [<diff-"
+"options>] [<stash>]"
-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] [<ghi chú>]"
+msgid "git stash drop [-q | --quiet] [<stash>]"
+msgstr "git stash drop [-q | --quiet] [<stash>]"
-msgid "git stash pop [--index] [-q|--quiet] [<stash>]"
-msgstr "git stash pop [--index] [-q|--quiet] [<stash>]"
+msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
+msgstr "git stash pop [--index] [-q | --quiet] [<stash>]"
-msgid "git stash apply [--index] [-q|--quiet] [<stash>]"
-msgstr "git stash apply [--index] [-q|--quiet] [<stash>]"
+msgid "git stash apply [--index] [-q | --quiet] [<stash>]"
+msgstr "git stash apply [--index] [-q | --quiet] [<stash>]"
-msgid "git stash store [-m|--message <message>] [-q|--quiet] <commit>"
-msgstr "git stash store [-m|--message <ghi chú>] [-q|--quiet] <commit>"
+msgid "git stash branch <branchname> [<stash>]"
+msgstr "git stash branch <tên-nhánh> [<stash>]"
+
+msgid "git stash store [(-m | --message) <message>] [-q | --quiet] <commit>"
+msgstr "git stash store [(-m | --message) <ghi chú>] [-q | --quiet] <commit>"
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 <lá»i nhắn>]\n"
-" [--] [<đặc/tả/đưá»ng/dẫn>…]]"
+"git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
+"| --quiet]\n"
+" [-u | --include-untracked] [-a | --all] [(-m | --message) <ghi "
+"chú>]\n"
+" [--pathspec-from-file=<tập tin> [--pathspec-file-nul]]\n"
+" [--] [<đặc/tả/đưá»ng/dẫ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 ""
-"git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-" [-u|--include-untracked] [-a|--all] [<ghi chú>]"
+"git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | "
+"--quiet]\n"
+" [-u | --include-untracked] [-a | --all] [<ghi chú>]"
+
+msgid "git stash create [<message>]"
+msgstr "git stash create [<ghi chú>]"
#, c-format
msgid "'%s' is not a stash-like commit"
-msgstr "“%s†không phải là lần chuyển giao kiểu-stash (cất đi)"
+msgstr "'%s' không phải là lần chuyển giao kiểu-stash"
#, c-format
msgid "Too many revisions specified:%s"
@@ -11725,10 +12370,10 @@ msgstr "Không tìm thấy các mục tạm cất (stash) nào."
#, c-format
msgid "%s is not a valid reference"
-msgstr "“%s†không phải một tham chiếu hợp lệ"
+msgstr "'%s' không phải một tham chiếu hợp lệ"
msgid "git stash clear with arguments is unimplemented"
-msgstr "git stash clear với các tham số là chưa được thực hiện"
+msgstr "git stash clear với các tham số là chưa được hỗ trợ"
#, c-format
msgid ""
@@ -11736,7 +12381,8 @@ msgid ""
" %s -> %s\n"
" to make room.\n"
msgstr ""
-"CẢNH BÃO: Tệp chưa được theo dõi theo cách cá»§a tệp được theo dõi! Äổi tên\n"
+"CẢNH BÃO: tập tin chưa được theo dõi chắn đưá»ng tập tin được theo dõi! Äổi "
+"tên\n"
" %s -> %s\n"
" để nhưá»ng chá»—.\n"
@@ -11748,7 +12394,7 @@ msgid "could not generate diff %s^!."
msgstr "không thể tạo diff %s^!."
msgid "conflicts in index. Try without --index."
-msgstr "xung đột trong bảng mục lục. Hãy thá»­ mà không dùng tùy chá»n --index."
+msgstr "xung đột trong chỉ mục. Hãy thá»­ mà không dùng tùy chá»n --index."
msgid "could not save index tree"
msgstr "không thể ghi lại cây chỉ mục"
@@ -11758,13 +12404,13 @@ msgid "Merging %s with %s"
msgstr "Äang hòa trá»™n %s vá»›i %s"
msgid "Index was not unstashed."
-msgstr "Bảng mục lục đã không được bỠstash."
+msgstr "chỉ mục đã không được bỠstash."
msgid "could not restore untracked files from stash"
msgstr "không thể phục hồi các tập tin chưa theo dõi từ mục cất đi (stash)"
msgid "attempt to recreate the index"
-msgstr "gặp lá»—i Ä‘á»c bảng mục lục"
+msgstr "gặp lá»—i Ä‘á»c chỉ mục"
#, c-format
msgid "Dropped %s (%s)"
@@ -11776,7 +12422,7 @@ msgstr "%s: Không thể xóa bỠmục stash"
#, c-format
msgid "'%s' is not a stash reference"
-msgstr "â€%s†không phải tham chiếu đến stash"
+msgstr "'%s' không phải tham chiếu đến stash"
msgid "The stash entry is kept in case you need it again."
msgstr "Các mục tạm cất (stash) được giữ trong trưá»ng hợp bạn lại cần nó."
@@ -11785,10 +12431,10 @@ msgid "No branch name specified"
msgstr "Chưa chỉ ra tên của nhánh"
msgid "failed to parse tree"
-msgstr "gặp lỗi khi phân tích cây"
+msgstr "gặp lá»—i khi Ä‘á»c cây"
msgid "failed to unpack trees"
-msgstr "gặp lỗi khi tháo dỡ cây"
+msgstr "gặp lỗi khi giải nén cây"
msgid "include untracked files in the stash"
msgstr "bao gồm các tập tin không được theo dõi trong stash"
@@ -11807,7 +12453,7 @@ msgid "\"git stash store\" requires one <commit> argument"
msgstr "\"git stash store\" cần một đối số <lần chuyển giao>"
msgid "No staged changes"
-msgstr "Không có thay đổi đã được đưa lên bệ phóng"
+msgstr "Không có thay đổi đã được đưa vào vùng chá»"
msgid "No changes selected"
msgstr "Chưa có thay đổi nào được chá»n"
@@ -11816,7 +12462,7 @@ msgid "You do not have the initial commit yet"
msgstr "Bạn chưa còn có lần chuyển giao khởi tạo"
msgid "Cannot save the current index state"
-msgstr "Không thể ghi lại trạng thái bảng mục lục hiện hành"
+msgstr "Không thể ghi lại trạng thái chỉ mục hiện hành"
msgid "Cannot save the untracked files"
msgstr "Không thể ghi lại các tập tin chưa theo dõi"
@@ -11825,7 +12471,7 @@ msgid "Cannot save the current worktree state"
msgstr "Không thể ghi lại trạng thái cây-làm-việc hiện hành"
msgid "Cannot save the current staged state"
-msgstr "Không thể ghi lại trạng thái bệ phóng hiện hành"
+msgstr "Không thể ghi lại trạng thái vùng chỠhiện hành"
msgid "Cannot record working tree state"
msgstr "Không thể ghi lại trạng thái cây làm việc hiện hành"
@@ -11837,7 +12483,7 @@ msgid "Can't use --staged and --include-untracked or --all at the same time"
msgstr "Không thể dùng --staged và --include-untracked hay --all cùng một lúc"
msgid "Did you forget to 'git add'?"
-msgstr "Có lẽ bạn đã quên “git add †phải không?"
+msgstr "Có lẽ bạn đã quên 'git add'?"
msgid "No local changes to save"
msgstr "Không có thay đổi nội bộ nào được ghi lại"
@@ -11850,19 +12496,19 @@ msgstr "Không thể ghi lại trạng thái hiện hành"
#, c-format
msgid "Saved working directory and index state %s"
-msgstr "Äã ghi lại thư mục làm việc và trạng thái mục lục %s"
+msgstr "Äã ghi lại thư mục làm việc và trạng thái chỉ mục %s"
msgid "Cannot remove worktree changes"
msgstr "Không thể gỡ bỠcác thay đổi cây-làm-việc"
msgid "keep index"
-msgstr "giữ nguyên bảng mục lục"
+msgstr "giữ nguyên chỉ mục"
msgid "stash staged changes only"
-msgstr "chỉ tạm cất đi các thay đổi đã đưa lên bệ phóng"
+msgstr "chỉ tạm cất Ä‘i các thay đổi đã đưa vào vùng chá»"
msgid "stash in patch mode"
-msgstr "cất đi ở chế độ miếng vá"
+msgstr "cất đi ở chế độ vá"
msgid "quiet mode"
msgstr "chế độ im lặng"
@@ -11881,29 +12527,27 @@ msgstr "treo trước ký tự ghi chú và ký tự khoảng trắng cho từng
#, c-format
msgid "Expecting a full ref name, got %s"
-msgstr "Cần tên tham chiếu dạng đầy đủ, nhưng lại nhận được %s"
+msgstr "Cần tên tham chiếu dạng đầy đủ, nhưng lại có %s"
+
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "không thể lấy thẻ quản kho cho mô-đun-con '%s'"
#, c-format
msgid ""
"could not look up configuration '%s'. Assuming this repository is its own "
"authoritative upstream."
msgstr ""
-"không thể tìm thấy cấu hình “%sâ€. Coi rằng đây là kho thượng nguồn có quyá»n "
+"không thể tìm thấy cấu hình '%s'. Coi rằng đây là kho thượng nguồn có quyá»n "
"sở hữu chính nó."
-msgid "alternative anchor for relative paths"
-msgstr "Ä‘iểm neo thay thế cho các đưá»ng dẫn tương đối"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=</đưá»ng/dẫn>] [</đưá»ng/dẫn>…]"
-
#, c-format
msgid "No url found for submodule path '%s' in .gitmodules"
-msgstr "Không tìm thấy url cho đưá»ng dẫn mô-Ä‘un-con “%s†trong .gitmodules"
+msgstr "Không tìm thấy url cho đưá»ng dẫn mô-Ä‘un-con '%s' trong .gitmodules"
#, c-format
msgid "Entering '%s'\n"
-msgstr "Äang vào “%sâ€\n"
+msgstr "Äang vào '%s'\n"
#, c-format
msgid ""
@@ -11924,66 +12568,63 @@ msgstr ""
"."
msgid "suppress output of entering each submodule command"
-msgstr "chặn kết xuất của từng lệnh mô-đun-con"
+msgstr "chặn đầu ra của từng lệnh mô-đun-con"
msgid "recurse into nested submodules"
msgstr "đệ quy vào trong mô-đun-con lồng nhau"
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <lệnh>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <lệnh>"
#, c-format
msgid "Failed to register url for submodule path '%s'"
-msgstr "Gặp lá»—i khi đăng ký url cho đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Gặp lá»—i khi đăng ký url cho đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Submodule '%s' (%s) registered for path '%s'\n"
-msgstr "Mô-Ä‘un-con “%s†(%s) được đăng ký cho đưá»ng dẫn “%sâ€\n"
+msgstr "Mô-Ä‘un-con '%s' (%s) được đăng ký cho đưá»ng dẫn '%s'\n"
#, c-format
msgid "warning: command update mode suggested for submodule '%s'\n"
-msgstr "cảnh báo: chế độ lệnh cập nhật được gợi ý cho mô-Ä‘un-con “%sâ€\n"
+msgstr "cảnh báo: chế độ lệnh cập nhật được gợi ý cho mô-đun-con '%s'\n"
#, c-format
msgid "Failed to register update mode for submodule path '%s'"
-msgstr "Gặp lá»—i khi đăng ký chế độ cập nhật cho đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Gặp lá»—i khi đăng ký chế độ cập nhật cho đưá»ng dẫn mô-Ä‘un-con '%s'"
msgid "suppress output for initializing a submodule"
-msgstr "chặn kết xuất của khởi tạo một mô-đun-con"
+msgstr "chặn đầu ra của khởi tạo một mô-đun-con"
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<các tùy chá»n>] [</đưá»ng/dẫn>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<các tùy chá»n>] [</đưá»ng/dẫn>]"
#, c-format
msgid "no submodule mapping found in .gitmodules for path '%s'"
msgstr ""
"không tìm thấy ánh xạ (mapping) mô-Ä‘un-con trong .gitmodules cho đưá»ng dẫn "
-"“%sâ€"
+"'%s'"
#, c-format
msgid "could not resolve HEAD ref inside the submodule '%s'"
-msgstr "không thể phân giải tham chiếu HEAD bên trong mô-Ä‘un-con “%sâ€"
+msgstr "không thể phân giải tham chiếu HEAD bên trong mô-đun-con '%s'"
#, c-format
msgid "failed to recurse into submodule '%s'"
-msgstr "gặp lá»—i khi đệ quy vào trong mô-Ä‘un-con “%sâ€"
+msgstr "gặp lỗi khi đệ quy vào trong mô-đun-con '%s'"
msgid "suppress submodule status output"
-msgstr "chặn kết xuất vỠtình trạng mô-đun-con"
+msgstr "chặn đầu ra vỠtình trạng mô-đun-con"
msgid ""
"use commit stored in the index instead of the one stored in the submodule "
"HEAD"
msgstr ""
-"dùng lần chuyển giao lưu trong mục lục thay cho cái được lưu trong HEAD mô-"
+"dùng lần chuyển giao lưu trong chỉ mục thay cho cái được lưu trong HEAD mô-"
"đun-con"
msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
msgstr ""
-"git submodule status [--quiet] [--cached] [--recursive] [</đưá»ng/dẫn>…]"
-
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name </đưá»ng/dẫn>"
+"git submodule status [--quiet] [--cached] [--recursive] [</đưá»ng/dẫn>...]"
#, c-format
msgid "* %s %s(blob)->%s(submodule)"
@@ -12001,61 +12642,57 @@ msgstr "%s"
#, c-format
msgid "couldn't hash object from '%s'"
-msgstr "không thể băm đối tượng từ “%sâ€"
+msgstr "không thể băm đối tượng từ '%s'"
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "gặp chế độ không như mong chỠ%o\n"
+msgid "unexpected mode %o"
+msgstr "gặp chế độ không rõ %o"
msgid "use the commit stored in the index instead of the submodule HEAD"
-msgstr "hùng lần chuyển giao đã lưu trong mục lục thay cho HEAD mô-đun-con"
+msgstr "hùng lần chuyển giao đã lưu trong chỉ mục thay cho HEAD mô-đun-con"
msgid "compare the commit in the index with that in the submodule HEAD"
-msgstr "để so sánh lần trong mục lục với cái trong HEAD mô-đun-con"
+msgstr "để so sánh lần trong chỉ mục với cái trong HEAD mô-đun-con"
msgid "skip submodules with 'ignore_config' value set to 'all'"
msgstr ""
-"bá» qua các mô-Ä‘un-con vá»›i giá trị cá»§a “ignore_config†được đặt thành “allâ€"
+"bỠqua các mô-đun-con với giá trị của 'ignore_config' được đặt thành 'all'"
msgid "limit the summary size"
msgstr "giới hạn kích cỡ tổng hợp"
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
msgstr ""
-"git submodule--helper summary [<các tùy chá»n>] [<lần_chuyển_giao>] [--] [</"
-"đưá»ng/dẫn>]"
+"git submodule summary [<các tùy chá»n>] [<lần_chuyển_giao>] [--] [</đưá»ng/"
+"dẫn>]"
msgid "could not fetch a revision for HEAD"
msgstr "không thể lấy vỠmột điểm xem xét cho HEAD"
#, c-format
msgid "Synchronizing submodule url for '%s'\n"
-msgstr "Url mô-Ä‘un-con đồng bá»™ hóa cho “%sâ€\n"
+msgstr "Url mô-đun-con đồng bộ hóa cho '%s'\n"
#, c-format
msgid "failed to register url for submodule path '%s'"
-msgstr "gặp lá»—i khi đăng ký url cho đưá»ng dẫn mô-Ä‘un-con “%sâ€"
-
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "gặp lá»—i khi lấy máy chá»§ mặc định cho mô-Ä‘un-con “%sâ€"
+msgstr "gặp lá»—i khi đăng ký url cho đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "failed to update remote for submodule '%s'"
-msgstr "gặp lá»—i khi cập nhật cho mô-Ä‘un-con “%sâ€"
+msgstr "gặp lỗi khi cập nhật cho mô-đun-con '%s'"
msgid "suppress output of synchronizing submodule url"
-msgstr "chặn kết xuất của url mô-đun-con đồng bộ"
+msgstr "chặn đầu ra của url mô-đun-con đồng bộ"
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [</đưá»ng/dẫn>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [</đưá»ng/dẫn>]"
#, c-format
msgid ""
"Submodule work tree '%s' contains a .git directory. This will be replaced "
"with a .git file by using absorbgitdirs."
msgstr ""
-"Cây làm việc mô-đun-con “%s†có chứa thư mục .git. Việc này sẽ được thay thế "
+"Cây làm việc mô-đun-con '%s' có chứa thư mục .git. Việc này sẽ được thay thế "
"với một tập tin .git bằng các sử dụng absorbgitdirs."
#, c-format
@@ -12063,24 +12700,24 @@ msgid ""
"Submodule work tree '%s' contains local modifications; use '-f' to discard "
"them"
msgstr ""
-"Cây làm việc mô-đun-con “%s†chứa các thay đổi nội bộ; hãy dùng “-f†để loại "
+"Cây làm việc mô-đun-con '%s' chứa các thay đổi nội bộ; hãy dùng '-f' để loại "
"bỠchúng đi"
#, c-format
msgid "Cleared directory '%s'\n"
-msgstr "Äã xóa thư mục “%sâ€\n"
+msgstr "Äã xóa thư mục '%s'\n"
#, c-format
msgid "Could not remove submodule work tree '%s'\n"
-msgstr "Không thể gỡ bá» cây làm việc mô-Ä‘un-con “%sâ€\n"
+msgstr "Không thể gỡ bỠcây làm việc mô-đun-con '%s'\n"
#, c-format
msgid "could not create empty submodule directory %s"
-msgstr "không thể tạo thư mục mô-Ä‘un-con rá»—ng “%sâ€"
+msgstr "không thể tạo thư mục mô-đun-con rỗng '%s'"
#, c-format
msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
-msgstr "Mô-Ä‘un-con “%s†(%s) được đăng ký cho đưá»ng dẫn “%sâ€\n"
+msgstr "Mô-Ä‘un-con '%s' (%s) được đăng ký cho đưá»ng dẫn '%s'\n"
msgid "remove submodule working trees even if they contain local changes"
msgstr "gỡ bỠcây làm việc của mô-đun-con ngay cả khi nó có thay đổi nội bộ"
@@ -12091,10 +12728,11 @@ msgstr "bỠđăng ký tất cả các trong mô-đun-con"
msgid ""
"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"
msgstr ""
-"git submodule deinit [--quiet] [-f | --force] [--all | [--] [</đưá»ng/dẫn>…]]"
+"git submodule deinit [--quiet] [-f | --force] [--all | [--] [</đưá»ng/"
+"dẫn>...]]"
msgid "Use '--all' if you really want to deinitialize all submodules"
-msgstr "Dùng “--all†nếu bạn thá»±c sá»± muốn há»§y khởi tạo má»i mô-Ä‘un-con"
+msgstr "Dùng '--all' nếu bạn thá»±c sá»± muốn há»§y khởi tạo má»i mô-Ä‘un-con"
msgid ""
"An alternate computed from a superproject's alternate is invalid.\n"
@@ -12102,41 +12740,48 @@ msgid ""
"submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
"'--reference-if-able' instead of '--reference'."
msgstr ""
-"Một cái thay thế được tính toán từ một thay thế của siêu dự án là không hợp "
+"Một cái thay thế được tính toán từ một thay thế của project cha là không hợp "
"lệ.\n"
"Äể cho Git thá»±c hiện nhân bản mà không có cái thay thế như trong trưá»ng hợp "
"này, đặt\n"
-"submodule.alternateErrorStrategy thành “info†hoặc, tương đương, nhân bản "
+"submodule.alternateErrorStrategy thành 'info' hoặc, tương đương, nhân bản "
"bằng\n"
-"“--reference-if-able†thay vì dùng “--referenceâ€."
+"'--reference-if-able' thay vì dùng '--reference'."
+
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "không thể lấy thẻ quản kho cho gitdir '%s'"
#, c-format
msgid "submodule '%s' cannot add alternate: %s"
-msgstr "mô-đun-con “%s†không thể thêm thay thế: %s"
+msgstr "mô-đun-con '%s' không thể thêm thay thế: %s"
#, c-format
msgid "Value '%s' for submodule.alternateErrorStrategy is not recognized"
-msgstr "Giá trị “%s†cho submodule.alternateErrorStrategy không được thừa nhận"
+msgstr "Giá trị '%s' cho submodule.alternateErrorStrategy không được thừa nhận"
#, c-format
msgid "Value '%s' for submodule.alternateLocation is not recognized"
-msgstr "Giá trị “%s†cho submodule.alternateLocation không được thừa nhận"
+msgstr "Giá trị '%s' cho submodule.alternateLocation không được thừa nhận"
#, c-format
msgid "refusing to create/use '%s' in another submodule's git dir"
-msgstr "từ chối tạo/dùng “%s†trong một thư mục git của mô đun con"
+msgstr "từ chối tạo/dùng '%s' trong một thư mục git của mô đun con"
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "việc sao “%s†vào đưá»ng dẫn mô-Ä‘un-con “%s†gặp lá»—i"
+msgid "directory not empty: '%s'"
+msgstr "thư mục không trống: '%s'"
#, c-format
-msgid "directory not empty: '%s'"
-msgstr "thư mục không trống: “%sâ€"
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "việc sao '%s' vào đưá»ng dẫn mô-Ä‘un-con '%s' gặp lá»—i"
#, c-format
msgid "could not get submodule directory for '%s'"
-msgstr "không thể lấy thư mục mô-Ä‘un-con cho “%sâ€"
+msgstr "không thể lấy thư mục mô-đun-con cho '%s'"
+
+msgid "alternative anchor for relative paths"
+msgstr "Ä‘iểm neo thay thế cho các đưá»ng dẫn tương đối"
msgid "where the new submodule will be cloned to"
msgstr "nhân bản mô-đun-con mới vào chỗ nào"
@@ -12166,20 +12811,16 @@ msgstr ""
"spec>] --url <url> --path </đưá»ng/dẫn>"
#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Chế độ cập nhật “%s†không hợp lệ cho đưá»ng dẫn mô-Ä‘un-con “%sâ€"
-
-#, c-format
msgid "Invalid update mode '%s' configured for submodule path '%s'"
msgstr ""
-"Chế độ cập nhật “%s†không hợp lệ được cấu hình cho đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+"Chế độ cập nhật '%s' không hợp lệ được cấu hình cho đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Submodule path '%s' not initialized"
-msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “%s†chưa được khởi tạo"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '%s' chưa được khởi tạo"
msgid "Maybe you want to use 'update --init'?"
-msgstr "Có lẽ bạn là bạn muốn dùng \"update --init\" phải không?"
+msgstr "Có lẽ bạn muốn dùng 'update --init'?"
#, c-format
msgid "Skipping unmerged submodule %s"
@@ -12187,93 +12828,97 @@ msgstr "BỠqua các mô-đun-con chưa được hòa trộn %s"
#, c-format
msgid "Skipping submodule '%s'"
-msgstr "Bá» qua mô-Ä‘un-con “%sâ€"
+msgstr "BỠqua mô-đun-con '%s'"
+
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "không thể nhân bản mô-đun-con '%s' nếu không có URL"
#, c-format
msgid "Failed to clone '%s'. Retry scheduled"
-msgstr "Gặp lá»—i khi nhân bản “%sâ€. Thá»­ lại lịch trình"
+msgstr "Gặp lá»—i khi nhân bản '%s'. Äã lên lịch thá»­ lại"
#, c-format
msgid "Failed to clone '%s' a second time, aborting"
-msgstr "Gặp lá»—i khi nhân bản “%s†lần thứ hai nên bãi bá»"
+msgstr "Gặp lá»—i khi nhân bản '%s' lần thứ hai, huá»· bá»"
#, c-format
msgid "Unable to checkout '%s' in submodule path '%s'"
-msgstr "Không thể lấy ra “%s†trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Không thể checkout '%s' trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Unable to rebase '%s' in submodule path '%s'"
-msgstr "Không thể cải tổ “%s†trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Không thể cải tổ '%s' trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Unable to merge '%s' in submodule path '%s'"
-msgstr "Không thể hòa trá»™n (merge) “%s†trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Không thể hòa trá»™n (merge) '%s' trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Execution of '%s %s' failed in submodule path '%s'"
msgstr ""
-"Thá»±c hiện không thành công lệnh “%s %s†trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+"Thá»±c hiện không thành công lệnh '%s %s' trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Submodule path '%s': checked out '%s'\n"
-msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “%sâ€: đã checkout “%sâ€\n"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '%s': đã checkout '%s'\n"
#, c-format
msgid "Submodule path '%s': rebased into '%s'\n"
-msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “%sâ€: được rebase vào trong “%sâ€\n"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '%s': được rebase vào trong '%s'\n"
#, c-format
msgid "Submodule path '%s': merged in '%s'\n"
-msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “%sâ€: được hòa trá»™n vào “%sâ€\n"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '%s': được hòa trá»™n vào '%s'\n"
#, c-format
msgid "Submodule path '%s': '%s %s'\n"
-msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “%sâ€: “%s %sâ€\n"
+msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '%s': '%s %s'\n"
#, c-format
msgid "Unable to fetch in submodule path '%s'; trying to directly fetch %s:"
msgstr ""
-"Không thể lấy vá» trong đưá»ng dẫn mô-Ä‘un-con “%sâ€; thá»­ lấy vá» trá»±c tiếp %s:"
+"Không thể lấy vá» trong đưá»ng dẫn mô-Ä‘un-con '%s'; thá»­ lấy vá» trá»±c tiếp %s:"
#, c-format
msgid ""
"Fetched in submodule path '%s', but it did not contain %s. Direct fetching "
"of that commit failed."
msgstr ""
-"Äã lấy vá» từ đưá»ng dẫn mô-Ä‘un con “%sâ€, nhưng nó không chứa %s. Lấy vá» trá»±c "
+"Äã lấy vá» từ đưá»ng dẫn mô-Ä‘un con '%s', nhưng nó không chứa %s. Lấy vá» trá»±c "
"tiếp lần chuyển giao gặp lỗi đó."
#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "Không thể khởi tạo mô-Ä‘un-con tại đưá»ng dẫn '%s'"
+
+#, c-format
msgid ""
"Submodule (%s) branch configured to inherit branch from superproject, but "
"the superproject is not on any branch"
msgstr ""
-"Nhánh mô-đun-con (%s) được cấu hình kế thừa nhánh từ siêu dự án, nhưng siêu "
-"dự án lại không trên bất kỳ nhánh nào"
-
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "không thể lấy thẻ quản kho cho mô-Ä‘un-con “%sâ€"
+"Nhánh mô-đun-con (%s) được cấu hình kế thừa nhánh từ project cha, nhưng "
+"project cha lại không trên bất kỳ nhánh nào"
#, c-format
msgid "Unable to find current revision in submodule path '%s'"
msgstr ""
-"Không tìm thấy Ä‘iểm xét duyệt hiện hành trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+"Không tìm thấy Ä‘iểm xét duyệt hiện hành trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Unable to fetch in submodule path '%s'"
-msgstr "Không thể lấy vá» trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Không thể lấy vá» trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Unable to find %s revision in submodule path '%s'"
-msgstr "Không tìm thấy Ä‘iểm xét duyệt %s trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Không tìm thấy Ä‘iểm xét duyệt %s trong đưá»ng dẫn mô-Ä‘un-con '%s'"
#, c-format
msgid "Failed to recurse into submodule path '%s'"
-msgstr "Gặp lá»—i khi đệ quy vào trong đưá»ng dẫn mô-Ä‘un-con “%sâ€"
+msgstr "Gặp lá»—i khi đệ quy vào trong đưá»ng dẫn mô-Ä‘un-con '%s'"
msgid "force checkout updates"
-msgstr "ép buộc lấy ra các cập nhật"
+msgstr "ép buộc checkout các cập nhật"
msgid "initialize uninitialized submodules before update"
msgstr "khởi tạo mô-đun-con chưa khởi tạo trước khi cập nhật"
@@ -12287,14 +12932,14 @@ msgstr "đi theo mô-đun con một cách đệ quy"
msgid "don't fetch new objects from the remote site"
msgstr "đừng lấy các đối tượng mới từ địa chỉ trên mạng"
-msgid "path into the working tree"
-msgstr "đưá»ng dẫn đến cây làm việc"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "dùng chiến lược hòa trộn 'checkout' (mặc định)"
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "đưá»ng dẫn đến cây làm việc, chéo biên giá»›i mô-Ä‘un-con lồng nhau"
+msgid "use the 'merge' update strategy"
+msgstr "dùng chiến lược hòa trộn 'merge'"
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout hoặc không làm gì cả"
+msgid "use the 'rebase' update strategy"
+msgstr "dùng chiến lược hòa trộn 'rebase'"
msgid "create a shallow clone truncated to the specified number of revisions"
msgstr ""
@@ -12309,6 +12954,9 @@ msgstr "nhân bản lần đầu có nên theo khuyến nghị là nông hay khÃ
msgid "don't print cloning progress"
msgstr "đừng in tiến trình nhân bản"
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "không cho phép nhân bản vào thư mục trống, ngụ ý --init"
+
msgid ""
"git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
"[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12320,35 +12968,17 @@ msgstr ""
"shallow] [--reference <kho>] [--recursive] [--[no-]single-branch] [--] [</"
"đưá»ng/dẫn/>...]"
-msgid "bad value for update parameter"
-msgstr "giá trị cho tham số cập nhật bị sai"
-
-msgid "recurse into submodules"
-msgstr "đệ quy vào trong mô-đun-con"
-
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<các tùy chá»n>] [</đưá»ng/dẫn>…]"
-
-msgid "check if it is safe to write to the .gitmodules file"
-msgstr "chá»n nếu nó là an toàn để ghi vào tập tin .gitmodules"
-
-msgid "unset the config in the .gitmodules file"
-msgstr "bỠđặt cấu hình trong tập tin .gitmodules"
-
-msgid "git submodule--helper config <name> [<value>]"
-msgstr "git submodule--helper config <tên> [<giá trị>]"
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "Gặp lỗi khi phân giải HEAD như là một tham chiếu hợp lệ."
-msgid "git submodule--helper config --unset <name>"
-msgstr "git submodule--helper config --unset <tên>"
-
-msgid "please make sure that the .gitmodules file is in the working tree"
-msgstr "hãy đảm bảo rằng tập tin .gitmodules có trong cây làm việc"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<các tùy chá»n>] [</đưá»ng/dẫn>...]"
msgid "suppress output for setting url of a submodule"
-msgstr "chặn kết xuất cho cài đặt url của một mô-đun-con"
+msgstr "chặn đầu ra cho việc đặt url của một mô-đun-con"
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] </đưá»ng/dẫn> <url_má»›i>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] </đưá»ng/dẫn> <url_má»›i>"
msgid "set the default tracking branch to master"
msgstr "đặt nhánh theo dõi mặc định thành master"
@@ -12356,15 +12986,12 @@ msgstr "đặt nhánh theo dõi mặc định thành master"
msgid "set the default tracking branch"
msgstr "đặt nhánh theo dõi mặc định"
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet](-d|--default)</đưá»ng/dẫn>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet](-d|--default)</đưá»ng/dẫn>"
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <nhánh> </đưá»ng/"
-"dẫn>"
+"git submodule set-branch [-q|--quiet] (-b|--branch) <nhánh> </đưá»ng/dẫn>"
msgid "--branch or --default required"
msgstr "cần --branch hoặc --default"
@@ -12387,19 +13014,19 @@ msgstr ""
#, c-format
msgid "creating branch '%s'"
-msgstr "Ä‘ang tạo nhánh “%sâ€"
+msgstr "đang tạo nhánh '%s'"
#, c-format
msgid "Adding existing repo at '%s' to the index\n"
-msgstr "Äang thêm repo có sẵn tại “%s†vào bảng mục lục\n"
+msgstr "Äang thêm repo có sẵn tại '%s' vào chỉ mục\n"
#, c-format
msgid "'%s' already exists and is not a valid git repo"
-msgstr "“%s†đã tồn tại từ trước và không phải là một kho git hợp lệ"
+msgstr "'%s' đã tồn tại từ trước và không phải là một kho git hợp lệ"
#, c-format
msgid "A git directory for '%s' is found locally with remote(s):\n"
-msgstr "Thư mục git cho “%s†được tìm thấy một cách cục bộ với các máy chủ:\n"
+msgstr "Thư mục git cho '%s' được tìm thấy một cách cục bộ với các máy chủ:\n"
#, c-format
msgid ""
@@ -12413,39 +13040,41 @@ msgstr ""
"Nếu bạn muốn sử dụng lại thư mục git nội bộ này thay vì nhân bản lại lần nữa "
"từ\n"
" %s\n"
-"dùng tùy chá»n “--forceâ€. Nếu thư mục git ná»™i bá»™ không phải là má»™t kho đúng "
+"dùng tùy chá»n '--force'. Nếu thư mục git ná»™i bá»™ không phải là má»™t kho đúng "
"hoặc\n"
-"là bạn không chắc chắn Ä‘iá»u đó nghÄ©a là gì thì chá»n tên khác vá»›i tùy chá»n “--"
-"nameâ€."
+"là bạn không chắc chắn Ä‘iá»u đó nghÄ©a là gì thì chá»n tên khác vá»›i tùy chá»n '--"
+"name'."
#, c-format
msgid "Reactivating local git directory for submodule '%s'\n"
-msgstr "Phục hồi sá»± hoạt động cá»§a thư mục git ná»™i bá»™ cho mô-Ä‘un-con “%sâ€.\n"
+msgstr "Phục hồi sự hoạt động của thư mục git nội bộ cho mô-đun-con '%s'.\n"
#, c-format
msgid "unable to checkout submodule '%s'"
-msgstr "không thể lấy ra mô-Ä‘un-con “%sâ€"
+msgstr "không thể checkout mô-đun-con '%s'"
+
+msgid "please make sure that the .gitmodules file is in the working tree"
+msgstr "hãy đảm bảo rằng tập tin .gitmodules có trong cây làm việc"
#, c-format
msgid "Failed to add submodule '%s'"
-msgstr "Gặp lá»—i khi thêm mô-Ä‘un-con “%sâ€"
+msgstr "Gặp lỗi khi thêm mô-đun-con '%s'"
#, c-format
msgid "Failed to register submodule '%s'"
-msgstr "Gặp lá»—i khi đăng ký mô-Ä‘un-con “%sâ€"
+msgstr "Gặp lỗi khi đăng ký mô-đun-con '%s'"
#, c-format
msgid "'%s' already exists in the index"
-msgstr "â€%s†thá»±c sá»± đã tồn tại ở bảng mục lục rồi"
+msgstr "'%s' thực sự đã tồn tại ở chỉ mục rồi"
#, c-format
msgid "'%s' already exists in the index and is not a submodule"
-msgstr ""
-"â€%s†thá»±c sá»± đã tồn tại ở bảng mục lục rồi và không phải là má»™t mô-Ä‘un-con"
+msgstr "'%s' thực sự đã tồn tại ở chỉ mục rồi và không phải là một mô-đun-con"
#, c-format
msgid "'%s' does not have a commit checked out"
-msgstr "“%s†không có một lần chuyển giao nào được lấy ra"
+msgstr "'%s' không có một lần chuyển giao nào được checkout"
msgid "branch of repository to add as submodule"
msgstr "nhánh của kho để thêm như là mô-đun-con"
@@ -12462,8 +13091,8 @@ msgid ""
msgstr ""
"đặt tên cá»§a mô-Ä‘un-con bằng chuá»—i đã cho thay vì mặc định là đưá»ng dẫn cá»§a nó"
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<các tùy chá»n>] [--] <kho> [</đưá»ng/dẫn>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<các tùy chá»n>] [--] <kho> [</đưá»ng/dẫn>]"
msgid "Relative path can only be used from the toplevel of the working tree"
msgstr ""
@@ -12472,34 +13101,35 @@ msgstr ""
#, c-format
msgid "repo URL: '%s' must be absolute or begin with ./|../"
-msgstr "repo URL: “%s†phải là đưá»ng dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
+msgstr "repo URL: '%s' phải là đưá»ng dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
#, c-format
msgid "'%s' is not a valid submodule name"
-msgstr "“%s†không phải là một tên mô-đun-con hợp lệ"
+msgstr "'%s' không phải là một tên mô-đun-con hợp lệ"
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s không hỗ trợ --super-prefix"
+msgid "git submodule--helper <command>"
+msgstr "git submodule--helper <lệnh>"
-#, c-format
-msgid "'%s' is not a valid submodule--helper subcommand"
-msgstr "“%s†không phải là lệnh con submodule--helper hợp lệ"
+msgid "git symbolic-ref [-m <reason>] <name> <ref>"
+msgstr "git symbolic-ref [-m <lý do>] <tên> <tham chiếu>"
-msgid "git symbolic-ref [<options>] <name> [<ref>]"
-msgstr "git symbolic-ref [<các tùy chá»n>] <tên> [<t.chiếu>]"
+msgid "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
+msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <tên>"
-msgid "git symbolic-ref -d [-q] <name>"
-msgstr "git symbolic-ref -d [-q] <tên>"
+msgid "git symbolic-ref --delete [-q] <name>"
+msgstr "git symbolic-ref --delete [-q] <tên>"
msgid "suppress error message for non-symbolic (detached) refs"
-msgstr "chặn các thông tin lá»—i cho các tham chiếu “không-má»m†(bị tách ra)"
+msgstr "chặn các thông tin lá»—i cho các tham chiếu 'không-má»m' (bị tách ra)"
msgid "delete symbolic ref"
msgstr "xóa tham chiếu má»m"
msgid "shorten ref output"
-msgstr "làm ngắn kết xuất ref (tham chiếu)"
+msgstr "làm ngắn kết quả ref (tham chiếu)"
+
+msgid "recursively dereference (default)"
+msgstr "chế độ giải tham chiếu đệ quy (mặc định)"
msgid "reason"
msgstr "lý do"
@@ -12508,61 +13138,65 @@ msgid "reason of the update"
msgstr "lý do cập nhật"
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"
+" [(--trailer <token>[(=|:)<value>])...]\n"
+" <tagname> [<commit> | <object>]"
msgstr ""
-"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <tập-tin>]\n"
-" <tên-thẻ> [<head>]"
+"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <tập-tin>] [-e]\n"
+" [(--trailer <token>[(=|:)<giá-trị>])...]\n"
+" <tên-thẻ> [<lần chuyển giao> | <đối tượng> ]"
msgid "git tag -d <tagname>..."
-msgstr "git tag -d <tên-thẻ>…"
+msgstr "git tag -d <tên-thẻ>..."
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 ""
-"git tag -l [-n[<số>]] [--contains <lần_chuyển_giao>] [--no-contains "
-"<lần_chuyển_giao>] [--points-at <đối-tượng>]\n"
-" [--format=<định_dạng>] [--merged <lần_chuyển_giao>] [--no-merged "
-"[<lần_chuyển_giao>]] [<mẫu>…]"
+"git tag [-n[<số>]] -l [--contains <lần_chuyển_giao>] [--no-contains "
+"<lần_chuyển_giao>]\n"
+" [--points-at <đối-tượng>] [--column[=<options>] | --no-column]\n"
+" [--create-reflog] [--sort=<key>] [--format=<định dạng>]\n"
+" [--merged <lần_chuyển_giao>] [--no-merged <lần_chuyển_giao>] "
+"[<mẫu>...]"
msgid "git tag -v [--format=<format>] <tagname>..."
-msgstr "git tag -v [--format=<định_dạng>] <tên-thẻ>…"
+msgstr "git tag -v [--format=<định dạng>] <tên-thẻ>..."
#, c-format
msgid "tag '%s' not found."
-msgstr "không tìm thấy tìm thấy thẻ “%sâ€."
+msgstr "không tìm thấy thẻ '%s'."
#, c-format
msgid "Deleted tag '%s' (was %s)\n"
-msgstr "Thẻ đã bị xóa “%s†(từng là %s)\n"
+msgstr "Thẻ đã bị xóa '%s' (từng là %s)\n"
#, c-format
msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"Viết các ghi chú cho thẻ:\n"
" %s\n"
-"Những dòng được bắt đầu bằng “%c†sẽ được bỠqua.\n"
+"Những dòng được bắt đầu bằng '%s' sẽ được bỠqua.\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 "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"Viết các ghi chú cho thẻ:\n"
" %s\n"
-"Những dòng được bắt đầu bằng “%c†sẽ được giữ lại; bạn có thể xóa chúng đi "
+"Những dòng được bắt đầu bằng '%s' sẽ được giữ lại; bạn có thể xóa chúng đi "
"nếu muốn.\n"
msgid "unable to sign the tag"
@@ -12647,17 +13281,20 @@ msgstr "chỉ hiển thị những thẻ mà nó không được hòa trộn"
msgid "print only tags of the object"
msgstr "chỉ hiển thị các thẻ của đối tượng"
+msgid "could not start 'git column'"
+msgstr "không thể chạy 'git column'"
+
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "tùy chá»n '%s' chỉ cho phép dùng trong chế độ liệt kê"
#, c-format
msgid "'%s' is not a valid tag name."
-msgstr "“%s†không phải thẻ hợp lệ."
+msgstr "'%s' không phải thẻ hợp lệ."
#, c-format
msgid "tag '%s' already exists"
-msgstr "thẻ “%s†đã tồn tại rồi"
+msgstr "thẻ '%s' đã tồn tại rồi"
#, c-format
msgid "Invalid cleanup mode %s"
@@ -12665,11 +13302,21 @@ msgstr "Chế độ dá»n dẹp không hợp lệ %s"
#, c-format
msgid "Updated tag '%s' (was %s)\n"
-msgstr "Äã cập nhật thẻ “%s†(trước là %s)\n"
+msgstr "Äã cập nhật thẻ '%s' (trước là %s)\n"
msgid "pack exceeds maximum allowed size"
msgstr "gói đã vượt quá cỡ tối đa được phép"
+msgid "failed to write object in stream"
+msgstr "gặp lá»—i khi Ä‘á»c đối tượng trong stream"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "inflate trả vỠ(%d)"
+
+msgid "invalid blob object from stream"
+msgstr "đối tượng blob không hợp lệ trong stream"
+
msgid "Unpacking objects"
msgstr "Äang giải nén các đối tượng"
@@ -12687,7 +13334,7 @@ msgstr "gặp lỗi khi xóa thư mục %s"
#, c-format
msgid "Testing mtime in '%s' "
-msgstr "Äang kiểm thá»­ mtime trong “%s†"
+msgstr "Äang kiểm thá»­ mtime trong '%s' "
msgid "directory stat info does not change after adding a new file"
msgstr "thông tin thống kê thư mục không thay đổi sau khi thêm tập tin mới"
@@ -12713,38 +13360,37 @@ msgid " OK"
msgstr " Äồng ý"
msgid "git update-index [<options>] [--] [<file>...]"
-msgstr "git update-index [<các tùy chá»n>] [--] [<tập-tin>…]"
+msgstr "git update-index [<các tùy chá»n>] [--] [<tập-tin>...]"
msgid "continue refresh even when index needs update"
-msgstr "tiếp tục làm mới ngay cả khi bảng mục lục cần được cập nhật"
+msgstr "tiếp tục làm mới ngay cả khi chỉ mục cần được cập nhật"
msgid "refresh: ignore submodules"
-msgstr "refresh: lỠđi mô-đun-con"
+msgstr "refresh: bỠqua mô-đun-con"
msgid "do not ignore new files"
msgstr "không bỠqua các tập tin mới tạo"
msgid "let files replace directories and vice-versa"
-msgstr "để các tập tin thay thế các thư mục và “vice-versaâ€"
+msgstr "để các tập tin thay thế các thư mục và 'vice-versa'"
msgid "notice files missing from worktree"
msgstr "thông báo các tập-tin thiếu trong thư-mục làm việc"
msgid "refresh even if index contains unmerged entries"
-msgstr ""
-"làm tươi mới thậm chí khi bảng mục lục chứa các mục tin chưa được hòa trộn"
+msgstr "làm tươi mới thậm chí khi chỉ mục chứa các mục tin chưa được hòa trộn"
msgid "refresh stat information"
msgstr "lấy lại thông tin thống kê"
msgid "like --refresh, but ignore assume-unchanged setting"
-msgstr "giống --refresh, nhưng bá» qua các cài đặt “assume-unchangedâ€"
+msgstr "giống --refresh, nhưng bỠqua các cài đặt 'assume-unchanged'"
msgid "<mode>,<object>,<path>"
msgstr "<chế_độ>,<đối_tượng>,<đưá»ng_dẫn>"
msgid "add the specified entry to the index"
-msgstr "thêm các tập tin đã chỉ ra vào bảng mục lục"
+msgstr "thêm các tập tin đã chỉ ra vào chỉ mục"
msgid "mark files as \"not changing\""
msgstr "đánh dấu các tập tin là \"không thay đổi\""
@@ -12753,7 +13399,7 @@ msgid "clear assumed-unchanged bit"
msgstr "xóa bít assumed-unchanged (giả định là không thay đổi)"
msgid "mark files as \"index-only\""
-msgstr "đánh dấu các tập tin là “chỉ-Ä‘á»câ€"
+msgstr "đánh dấu các tập tin là 'chỉ-Ä‘á»c'"
msgid "clear skip-worktree bit"
msgstr "xóa bít skip-worktree"
@@ -12762,8 +13408,7 @@ msgid "do not touch index-only entries"
msgstr "đừng động vào các mục index-only"
msgid "add to index only; do not add content to object database"
-msgstr ""
-"chỉ thêm vào bảng mục lục; không thêm nội dung vào cơ sở dữ liệu đối tượng"
+msgstr "chỉ thêm vào chỉ mục; không thêm nội dung vào cơ sở dữ liệu đối tượng"
msgid "remove named paths even if present in worktree"
msgstr ""
@@ -12771,13 +13416,13 @@ msgstr ""
"làm việc"
msgid "with --stdin: input lines are terminated by null bytes"
-msgstr "vá»›i tùy chá»n --stdin: các dòng đầu vào được chấm dứt bởi ký tá»± null"
+msgstr "vá»›i tùy chá»n --stdin: các dòng đầu vào được kết thúc bởi ký tá»± null"
msgid "read list of paths to be updated from standard input"
-msgstr "Ä‘á»c danh sách đưá»ng dẫn cần cập nhật từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c danh sách đưá»ng dẫn cần cập nhật từ stdin"
msgid "add entries from standard input to the index"
-msgstr "không thể Ä‘á»c các mục từ đầu vào tiêu chuẩn vào bảng mục lục"
+msgstr "không thể Ä‘á»c các mục từ stdin vào chỉ mục"
msgid "repopulate stages #2 and #3 for the listed paths"
msgstr "phục hồi các trạng thái #2 và #3 cho các đưá»ng dẫn được liệt kê"
@@ -12789,16 +13434,19 @@ msgid "ignore files missing from worktree"
msgstr "bỠqua các tập-tin thiếu trong thư-mục làm việc"
msgid "report actions to standard output"
-msgstr "báo cáo các thao tác ra thiết bị xuất chuẩn"
+msgstr "ghi các thao tác ra stdout"
msgid "(for porcelains) forget saved unresolved conflicts"
-msgstr "(cho “porcelainsâ€) quên các xung đột chưa được giải quyết đã ghi"
+msgstr "(cho 'porcelains') quên các xung đột chưa được giải quyết đã ghi"
msgid "write index in this format"
-msgstr "ghi mục lục ở định dạng này"
+msgstr "ghi chỉ mục ở định dạng này"
+
+msgid "report on-disk index format version"
+msgstr "cho biết phiên bản định dạng chỉ mục trên đĩa"
msgid "enable or disable split index"
-msgstr "bật/tắt chia cắt bảng mục lục"
+msgstr "bật/tắt chia cắt chỉ mục"
msgid "enable/disable untracked cache"
msgstr "bật/tắt bộ đệm không theo vết"
@@ -12810,7 +13458,7 @@ msgid "enable untracked cache without testing the filesystem"
msgstr "bật bộ đệm không theo vết mà không kiểm tra hệ thống tập tin"
msgid "write out the index even if is not flagged as changed"
-msgstr "ghi ra mục lục ngay cả khi không được đánh cỠlà có thay đổi"
+msgstr "ghi ra chỉ mục ngay cả khi không được đánh cỠlà có thay đổi"
msgid "enable or disable file system monitor"
msgstr "bật/tắt theo dõi hệ thống tập tin"
@@ -12821,19 +13469,27 @@ msgstr "đánh dấu các tập tin là hợp lệ fsmonitor"
msgid "clear fsmonitor valid bit"
msgstr "xóa bít hợp lệ fsmonitor"
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version: đang là %d, đặt vỠ%d"
+
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
msgstr ""
"core.splitIndex được đặt là sai; xóa bỠhay thay đổi nó, nếu bạn thực sự "
-"muốn bật chia tách mục lục"
+"muốn bật chia tách chỉ mục"
msgid ""
"core.splitIndex is set to true; remove or change it, if you really want to "
"disable split index"
msgstr ""
"core.splitIndex được đặt là đúng; xóa bỠhay thay đổi nó, nếu bạn thực sự "
-"muốn tắt chia tách mục lục"
+"muốn tắt chia tách chỉ mục"
msgid ""
"core.untrackedCache is set to true; remove or change it, if you really want "
@@ -12854,7 +13510,7 @@ msgstr ""
#, c-format
msgid "Untracked cache enabled for '%s'"
-msgstr "Nhá»› đệm không theo vết được bật cho “%sâ€"
+msgstr "Nhớ đệm không theo vết được bật cho '%s'"
msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
msgstr ""
@@ -12873,11 +13529,11 @@ msgstr ""
msgid "fsmonitor disabled"
msgstr "fsmonitor bị tắt"
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<các tùy chá»n>] -d <refname> [<biến-cÅ©>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<các tùy chá»n>] -d <refname> [<oid-cÅ©>]"
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr "git update-ref [<các tùy chá»n>] <refname> <biến-má»›i> [<biến-cÅ©>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<các tùy chá»n>] <refname> <oid-má»›i> [<oid-cÅ©>]"
msgid "git update-ref [<options>] --stdin [-z]"
msgstr "git update-ref [<các tùy chá»n>] --stdin [-z]"
@@ -12889,19 +13545,23 @@ msgid "update <refname> not the one it points to"
msgstr "cập nhật <tên-tham-chiếu> không phải cái nó chỉ tới"
msgid "stdin has NUL-terminated arguments"
-msgstr "đầu vào tiêu chuẩn có các đối số được chấm dứt bởi NUL"
+msgstr "stdin có các đối số được kết thúc bởi NUL"
msgid "read updates from stdin"
-msgstr "Ä‘á»c cập nhật từ đầu vào tiêu chuẩn"
+msgstr "Ä‘á»c cập nhật từ stdin"
msgid "update the info files from scratch"
msgstr "cập nhật các tập tin thông tin từ điểm xuất phát"
-msgid "git upload-pack [<options>] <dir>"
-msgstr "git upload-pack [<các tùy chá»n>] </đưá»ng/dẫn>"
+msgid ""
+"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
+" [--advertise-refs] <directory>"
+msgstr ""
+"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
+" [--advertise-refs] <thư mục>"
msgid "quit after a single request/response exchange"
-msgstr "thoát sau khi má»™t trao đổi yêu cầu hay trả lá»i đơn"
+msgstr "thoát sau má»™t trao đổi yêu cầu/trả lá»i"
msgid "serve up the info/refs for git-http-backend"
msgstr "phục vụ info/refs (thông tin/tham chiếu) cho git-http-backend"
@@ -12912,17 +13572,17 @@ msgstr "đừng thử <thư_mục>/.git/ nếu <thư_mục> không phải là th
msgid "interrupt transfer after <n> seconds of inactivity"
msgstr "ngắt truyá»n thông sau <n> giây không hoạt động"
-msgid "git verify-commit [-v | --verbose] <commit>..."
-msgstr "git verify-commit [-v | --verbose] <lần_chuyển_giao>…"
+msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
+msgstr "git verify-commit [-v | --verbose] [--raw] <lần_chuyển_giao>..."
msgid "print commit contents"
msgstr "hiển thị nội dung của lần chuyển giao"
msgid "print raw gpg status output"
-msgstr "in kết xuất trạng thái gpg dạng thô"
+msgstr "in đầu ra trạng thái gpg dạng thô"
-msgid "git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."
-msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] <gói>…"
+msgid "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
+msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <gói>.idx..."
msgid "verbose"
msgstr "chi tiết"
@@ -12930,69 +13590,106 @@ msgstr "chi tiết"
msgid "show statistics only"
msgstr "chỉ hiển thị thống kê"
-msgid "git verify-tag [-v | --verbose] [--format=<format>] <tag>..."
-msgstr "git verify-tag [-v | --verbose] [--format=<định_dạng>] <thẻ>…"
+msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
+msgstr ""
+"git verify-tag [-v | --verbose] [--format=<định dạng>] [--raw] <thẻ>..."
msgid "print tag contents"
msgstr "hiển thị nội dung của thẻ"
-msgid "git worktree add [<options>] <path> [<commit-ish>]"
-msgstr "git worktree add [<các tùy chá»n>] </đưá»ng/dẫn> [<commit-ish>]"
+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 <lý do>]]\n"
+" [--orphan] [(-b | -B) <nhánh-má»›i>] <đưá»ng/dẫn> [<commit-"
+"ish>]"
-msgid "git worktree list [<options>]"
-msgstr "git worktree list [<các tùy chá»n>]"
+msgid "git worktree list [-v | --porcelain [-z]]"
+msgstr "git worktree list [-v | --porcelain [-z]]"
-msgid "git worktree lock [<options>] <path>"
-msgstr "git worktree lock [<các tùy chá»n>] </đưá»ng/dẫn>"
+msgid "git worktree lock [--reason <string>] <worktree>"
+msgstr "git worktree lock [--reason <lý do>] <cây làm việc>"
msgid "git worktree move <worktree> <new-path>"
-msgstr "git worktree move <worktree> </đưá»ng/dẫn/má»›i>"
+msgstr "git worktree move <cây làm việc> </đưá»ng/dẫn/má»›i>"
-msgid "git worktree prune [<options>]"
-msgstr "git worktree prune [<các tùy chá»n>]"
+msgid "git worktree prune [-n] [-v] [--expire <expire>]"
+msgstr "git worktree prune [-n] [-v] [--expire <khi nào hết hạn>]"
-msgid "git worktree remove [<options>] <worktree>"
-msgstr "git worktree remove [<các tùy chá»n>] <worktree>"
+msgid "git worktree remove [-f] <worktree>"
+msgstr "git worktree remove [-f] <cây làm việc>"
msgid "git worktree repair [<path>...]"
msgstr "git worktree repair [</đưá»ng/dẫn/>...]"
-msgid "git worktree unlock <path>"
-msgstr "git worktree unlock </đưá»ng/dẫn>"
+msgid "git worktree unlock <worktree>"
+msgstr "git worktree unlock <cây làm việc>"
+
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Không có nhánh gốc, đoán là --orphan"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new unborn 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ếu bạn muốn tạo cây làm việc với nhánh chưa sinh\n"
+"(nhánh chưa có lần chuyển giao) cho kho chứa này, bạn có thể dùng\n"
+"tuỳ chá»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 unborn 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ếu bạn muốn tạo cây làm việc với nhánh chưa sinh\n"
+"(nhánh chưa có lần chuyển giao) cho kho chứa này, bạn có thể dùng\n"
+"tuỳ chá»n --orphan:\n"
+"\n"
+" git worktree add --orphan %s\n"
#, c-format
msgid "Removing %s/%s: %s"
msgstr "Äang xóa %s/%s: %s"
msgid "report pruned working trees"
-msgstr "báo cáo các cây làm việc đã prune"
+msgstr "liệt kê các cây làm việc đã prune"
msgid "expire working trees older than <time>"
msgstr "các cây làm việc hết hạn cÅ© hÆ¡n khoảng <thá»i gian>"
#, c-format
msgid "'%s' already exists"
-msgstr "“%s†đã có từ trước rồi"
+msgstr "'%s' đã có từ trước rồi"
#, c-format
msgid "unusable worktree destination '%s'"
-msgstr "đích cây làm việc không sá»­ dụng được “%sâ€"
+msgstr "đích cây làm việc không sử dụng được '%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†bị mất nhưng cây làm việc bị khóa;\n"
-"dùng “%s -f -f†để ghi đè, hoặc “unlock†và “prune†hay “remove†để xóa"
+"'%s' bị mất nhưng cây làm việc bị khóa;\n"
+"dùng '%s -f -f' để ghi đè, hoặc 'unlock' và 'prune' hay 'remove' để xóa"
#, 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†bị mất nhưng cây làm việc đã được đăng ký;\n"
-"dùng “%s -f†để ghi đè, hoặc “prune†hay “remove†để xóa"
+"'%s' bị mất nhưng cây làm việc đã được đăng ký;\n"
+"dùng '%s -f' để ghi đè, hoặc 'prune' hay 'remove' để xóa"
#, c-format
msgid "failed to copy '%s' to '%s'; sparse-checkout may not work correctly"
@@ -13000,37 +13697,62 @@ msgstr "gặp lỗi khi sao chép '%s' sang '%s'; không thể làm việc đún
#, c-format
msgid "failed to copy worktree config from '%s' to '%s'"
-msgstr "gặp lá»—i khi sao chép cấu hình cây làm việc từ “%s†sang “%sâ€"
+msgstr "gặp lỗi khi sao chép cấu hình cây làm việc từ '%s' sang '%s'"
#, c-format
msgid "failed to unset '%s' in '%s'"
-msgstr "gặp lá»—i bỠđặt “%s†trong “%sâ€"
+msgstr "gặp lỗi bỠđặt '%s' trong '%s'"
#, c-format
msgid "could not create directory of '%s'"
-msgstr "không thể tạo thư mục cá»§a “%sâ€"
+msgstr "không thể tạo thư mục của '%s'"
msgid "initializing"
msgstr "khởi tạo"
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "không tìm thấy cây làm việc '%s'"
+
+#, c-format
msgid "Preparing worktree (new branch '%s')"
-msgstr "Äang chuẩn bị cây làm việc (nhánh má»›i “%sâ€)"
+msgstr "Äang chuẩn bị cây làm việc (nhánh má»›i '%s')"
#, c-format
msgid "Preparing worktree (resetting branch '%s'; was at %s)"
-msgstr "Äang chuẩn bị cây làm việc (Ä‘ang cài đặt nhánh “%sâ€, trước đây tại %s)"
+msgstr "Äang chuẩn bị cây làm việc (Ä‘ang tái đặt nhánh '%s'; trước đây tại %s)"
#, c-format
msgid "Preparing worktree (checking out '%s')"
-msgstr "Äang chuẩn bị cây làm việc (Ä‘ang lấy ra “%sâ€)"
+msgstr "Äang chuẩn bị cây làm việc (Ä‘ang checkout '%s')"
+
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "không tham chiếu được: tham chiếu không hợp lệ: %s"
#, c-format
msgid "Preparing worktree (detached HEAD %s)"
-msgstr "Äang chuẩn bị cây làm việc (HEAD đã tách rá»i “%sâ€)"
+msgstr "Äang chuẩn bị cây làm việc (HEAD đã tách rá»i '%s')"
+
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD trỠđến tham chiếu sai (hoặc mồ côi).\n"
+"ÄÆ°á»ng dẫn HEAD: '%s'\n"
+"Ná»™i dung HEAD: '%s'"
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to override or fetch a remote first"
+msgstr ""
+"Không tồn tại tham chiếu cục bộ hay trên máy chủ mặc dù có cấu hình\n"
+"máy chủ, dừng lại; hãy dùng 'add -f' để ép buộc hoặc thực hiện kéo vỠtrước"
msgid "checkout <branch> even if already checked out in other worktree"
-msgstr "lấy ra <nhánh> ngay cả khi nó đã được lấy ra ở cây làm việc khác"
+msgstr "checkout <nhánh> ngay cả khi nó đã được checkout ở cây làm việc khác"
msgid "create a new branch"
msgstr "tạo nhánh mới"
@@ -13038,11 +13760,14 @@ msgstr "tạo nhánh mới"
msgid "create or reset a branch"
msgstr "tạo hay đặt lại một nhánh"
+msgid "create unborn branch"
+msgstr "tạo nhánh chưa sinh"
+
msgid "populate the new working tree"
msgstr "di chuyển cây làm việc mới"
msgid "keep the new working tree locked"
-msgstr "giữ cây làm việc mới bị khóa"
+msgstr "tiếp tục khoá cây làm việc mới"
msgid "reason for locking"
msgstr "lý do khóa"
@@ -13057,6 +13782,10 @@ msgstr "có khá»›p tên tên nhánh má»›i vá»›i má»™t nhánh theo dõi máy chá»
msgid "options '%s', '%s', and '%s' cannot be used together"
msgstr "tùy chá»n '%s', '%s' và '%s' không thể dùng cùng nhau"
+#, c-format
+msgid "option '%s' and commit-ish cannot be used together"
+msgstr "tùy chá»n '%s' và commit-ish không thể dùng cùng nhau"
+
msgid "added with --lock"
msgstr "được thêm với --lock"
@@ -13068,30 +13797,30 @@ msgstr "hiển thị chú thích và lý do mở rộng, nếu có"
msgid "add 'prunable' annotation to worktrees older than <time>"
msgstr ""
-"thêm chú thích kiểu “prunable†cho các cây làm việc hết hạn cũ hơn khoảng "
+"thêm chú thích kiểu 'prunable' cho các cây làm việc hết hạn cũ hơn khoảng "
"<thá»i gian>"
msgid "terminate records with a NUL character"
-msgstr "chấm dứt các bản ghi bằng ký tự NULL"
+msgstr "kết thúc các bản ghi bằng ký tự NULL"
#, c-format
msgid "'%s' is not a working tree"
msgstr "%s không phải là cây làm việc"
msgid "The main working tree cannot be locked or unlocked"
-msgstr "Cây thư mục làm việc chính không thể khóa hay bỠkhóa được"
+msgstr "Cây làm việc chính không thể khóa hay bỠkhóa được"
#, c-format
msgid "'%s' is already locked, reason: %s"
-msgstr "“%s†đã được khóa rồi, lý do: %s"
+msgstr "'%s' đã được khóa rồi, lý do: %s"
#, c-format
msgid "'%s' is already locked"
-msgstr "“%s†đã được khóa rồi"
+msgstr "'%s' đã được khóa rồi"
#, c-format
msgid "'%s' is not locked"
-msgstr "“%s†chưa bị khóa"
+msgstr "'%s' chưa bị khóa"
msgid "working trees containing submodules cannot be moved or removed"
msgstr "cây làm việc có chứa mô-Ä‘un-con không thể di chuyển hay xóa bá»"
@@ -13101,11 +13830,11 @@ msgstr "ép buộc ngay cả khi cây làm việc đang bẩn hay bị khóa"
#, c-format
msgid "'%s' is a main working tree"
-msgstr "“%s†là cây làm việc chính"
+msgstr "'%s' là cây làm việc chính"
#, c-format
msgid "could not figure out destination name from '%s'"
-msgstr "không thể phác há»a ra tên đích đến “%sâ€"
+msgstr "không thể phác há»a ra tên đích đến '%s'"
#, c-format
msgid ""
@@ -13113,14 +13842,14 @@ msgid ""
"use 'move -f -f' to override or unlock first"
msgstr ""
"không thể di chuyển một cây-làm-việc bị khóa, khóa vì: %s\n"
-"dùng “move -f -f†để ghi đè hoặc mở khóa trước đã"
+"dùng 'move -f -f' để ghi đè hoặc mở khóa trước đã"
msgid ""
"cannot move a locked working tree;\n"
"use 'move -f -f' to override or unlock first"
msgstr ""
"không thể di chuyển một cây-làm-việc bị khóa;\n"
-"dùng “move -f -f†để ghi đè hoặc mở khóa trước đã"
+"dùng 'move -f -f' để ghi đè hoặc mở khóa trước đã"
#, c-format
msgid "validation failed, cannot move working tree: %s"
@@ -13128,21 +13857,21 @@ msgstr "thẩm tra gặp lỗi, không thể di chuyển một cây-làm-việc:
#, c-format
msgid "failed to move '%s' to '%s'"
-msgstr "gặp lá»—i khi chuyển “%s†sang “%sâ€"
+msgstr "gặp lỗi khi chuyển '%s' sang '%s'"
#, c-format
msgid "failed to run 'git status' on '%s'"
-msgstr "gặp lá»—i khi chạy “git status†vào “%sâ€"
+msgstr "gặp lỗi khi chạy 'git status' vào '%s'"
#, c-format
msgid "'%s' contains modified or untracked files, use --force to delete it"
msgstr ""
-"“%s†có chứa các tập tin đã bị sửa chữa hoặc chưa được theo dõi, hãy dùng --"
+"'%s' có chứa các tập tin đã bị sửa chữa hoặc chưa được theo dõi, hãy dùng --"
"force để xóa nó"
#, c-format
msgid "failed to run 'git status' on '%s', code %d"
-msgstr "gặp lá»—i khi chạy “git status†trong “%sâ€, mã %d"
+msgstr "gặp lỗi khi chạy 'git status' trong '%s', mã %d"
msgid "force removal even if worktree is dirty or locked"
msgstr "ép buộc di chuyển thậm chí cả khi cây làm việc đang bẩn hay bị khóa"
@@ -13153,14 +13882,14 @@ msgid ""
"use 'remove -f -f' to override or unlock first"
msgstr ""
"không thể xóa bỠmột cây-làm-việc bị khóa, khóa vì: %s\n"
-"dùng “remove -f -f†để ghi đè hoặc mở khóa trước đã"
+"dùng 'remove -f -f' để ghi đè hoặc mở khóa trước đã"
msgid ""
"cannot remove a locked working tree;\n"
"use 'remove -f -f' to override or unlock first"
msgstr ""
"không thể xóa bỠmột cây-làm-việc bị khóa;\n"
-"dùng “remove -f -f†để ghi đè hoặc mở khóa trước đã"
+"dùng 'remove -f -f' để ghi đè hoặc mở khóa trước đã"
#, c-format
msgid "validation failed, cannot remove working tree: %s"
@@ -13186,17 +13915,73 @@ msgstr "ghi đối tượng cây (tree) cho <tiá»n tố> thư mục con"
msgid "only useful for debugging"
msgstr "chỉ hữu ích khi cần gỡ lỗi"
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch không được há»— trợ trên ná»n tảng này"
+
+#, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "không thể Ä‘á»c danh sách bundle khoá %s giá trị '%s'"
+
+#, c-format
+msgid "bundle list at '%s' has no mode"
+msgstr "bundle list at '%s' has no mode"
+
+msgid "failed to create temporary file"
+msgstr "không thể tạo tập tin tạm thá»i"
+
+msgid "insufficient capabilities"
+msgstr "không đủ quyá»n hạn"
+
+#, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "tập tin lấy vỠtừ '%s' không phải là bundle"
+
+msgid "failed to store maximum creation token"
+msgstr "gặp lỗi khi lưu token tạo tối đa"
+
+#, c-format
+msgid "unrecognized bundle mode from URI '%s'"
+msgstr "không nhận ra định dạng bundle từ URI '%s'"
+
+#, c-format
+msgid "exceeded bundle URI recursion limit (%d)"
+msgstr "vượt quá giới hạn đệ quy URI (%d)"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "gặp lỗi khi tải bundle từ URI '%s'"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle or bundle list"
+msgstr "tập tin ở URI '%s' không phải bundle hay danh sách bundle"
+
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: không nhận ra đối số: '%s'"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: cần flush dữ liệu sau các tham số"
+
+msgid "bundle-uri: got an empty line"
+msgstr "bundle-uri: nhận được dòng trống"
+
+msgid "bundle-uri: line is not of the form 'key=value'"
+msgstr "bundle-uri: dòng không có dạng 'key=value'"
+
+msgid "bundle-uri: line has empty key or value"
+msgstr "bundle-uri: dòng có key trống hoặc value trống"
+
#, c-format
msgid "unrecognized bundle hash algorithm: %s"
-msgstr "không hiểu thuật toán băm dữ liệu bundle: %s"
+msgstr "không hiểu thuật toán băm bundle: %s"
#, c-format
msgid "unknown capability '%s'"
-msgstr "không hiểu dung lượng “%sâ€"
+msgstr "không hiểu dung lượng '%s'"
#, c-format
msgid "'%s' does not look like a v2 or v3 bundle file"
-msgstr "“%s†không giống như tập tin v2 hay v3 bundle (định dạng dump của git)"
+msgstr "'%s' không giống như tập tin bundle v2 hay v3 (định dạng dump của git)"
#, c-format
msgid "unrecognized header: %s%s (%d)"
@@ -13205,8 +13990,12 @@ msgstr "phần đầu không được thừa nhận: %s%s (%d)"
msgid "Repository lacks these prerequisite commits:"
msgstr "Kho chứa thiếu những lần chuyển giao tiên quyết này:"
-msgid "need a repository to verify a bundle"
-msgstr "cần một kho chứa để thẩm tra một bundle"
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"một số lần chuyển giao tiên quyết tồn tại trong object store, nhưng không "
+"nằm trong lịch sử của kho chứa"
#, c-format
msgid "The bundle contains this ref:"
@@ -13221,18 +14010,26 @@ msgid "The bundle requires this ref:"
msgid_plural "The bundle requires these %<PRIuMAX> refs:"
msgstr[0] "Lệnh bundle yêu cầu %<PRIuMAX> tham chiếu này:"
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "Lệnh bundle dùng thuật toán băm sau: %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Lệnh bundle dùng bá»™ lá»c sau: %s"
+
msgid "unable to dup bundle descriptor"
-msgstr "không thể nhân đôi bộ mô tả bundle"
+msgstr "không thể dup bundle descriptor"
msgid "Could not spawn pack-objects"
-msgstr "Không thể sản sinh đối tượng gói"
+msgstr "Không thể spawn pack-objects"
msgid "pack-objects died"
-msgstr "đối tượng gói đã chết"
+msgstr "pack-objects đã chết"
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
-msgstr "th.chiếu “%s†bị loại trừ bởi các tùy chá»n rev-list"
+msgstr "th.chiếu '%s' bị loại trừ bởi các tùy chá»n rev-list"
#, c-format
msgid "unsupported bundle version %d"
@@ -13247,25 +14044,29 @@ msgstr "Từ chối tạo một bó dữ liệu trống rỗng."
#, c-format
msgid "cannot create '%s'"
-msgstr "không thể tạo “%sâ€"
+msgstr "không thể tạo '%s'"
msgid "index-pack died"
-msgstr "mục lục gói đã chết"
+msgstr "index-pack đã chết"
msgid "terminating chunk id appears earlier than expected"
-msgstr "mã mảnh kết thúc sá»›m hÆ¡n bình thưá»ng"
+msgstr "id chunk kết thúc sá»›m hÆ¡n bình thưá»ng"
+
+#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "id chunk %<PRIx32> không thẳng %d-byte"
#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
-msgstr "bù mảnh không đúng cách %<PRIx64> và %<PRIx64>"
+msgstr "chunk offset bất thưá»ng %<PRIx64> và %<PRIx64>"
#, c-format
msgid "duplicate chunk ID %<PRIx32> found"
-msgstr "tìm thấy ID của mảnh bị trùng lặp %<PRIx32>"
+msgstr "tìm thấy ID của chunk bị trùng lặp %<PRIx32>"
#, c-format
msgid "final chunk has non-zero id %<PRIx32>"
-msgstr "mảnh cuối cùng có id không bằng không %<PRIx32>"
+msgstr "chunk cuối cùng có id không bằng không %<PRIx32>"
msgid "invalid hash version"
msgstr "phiên bản băm không hợp lệ"
@@ -13275,7 +14076,7 @@ msgid "invalid color value: %.*s"
msgstr "giá trị màu không hợp lệ: %.*s"
msgid "Add file contents to the index"
-msgstr "Thêm nội dung tập tin vào bảng mục lục"
+msgstr "Thêm nội dung tập tin vào chỉ mục"
msgid "Apply a series of patches from a mailbox"
msgstr "Ãp dụng má»™t chuá»—i các miếng và từ má»™t mailbox"
@@ -13284,8 +14085,7 @@ msgid "Annotate file lines with commit information"
msgstr "Các dòng diễn giải tập tin với thông tin chuyển giao"
msgid "Apply a patch to files and/or to the index"
-msgstr ""
-"Ãp dụng má»™t miếng vá cho các tập tin đã chỉ ra và/hoặc vào bảng mục lục"
+msgstr "Ãp dụng má»™t bản vá cho các tập tin đã chỉ ra và/hoặc vào chỉ mục"
msgid "Import a GNU Arch repository into Git"
msgstr "Nhập một kho GNU Arch vào một kho Git"
@@ -13310,8 +14110,8 @@ msgstr "Sưu tập thông tin ngưá»i dùng để báo cáo lá»—i"
msgid "Move objects and refs by archive"
msgstr "Di chuyển các đối tượng và tham chiếu theo kho lưu"
-msgid "Provide content or type and size information for repository objects"
-msgstr "Cung cấp nội dung hoặc thông tin vỠkiểu và cỡ cho các đối tượng kho"
+msgid "Provide contents or details of repository objects"
+msgstr "Cung cấp nội dung hoặc thông tin vỠcác đối tượng kho"
msgid "Display gitattributes information"
msgstr "Hiển thị thông tin gitattributes"
@@ -13326,13 +14126,13 @@ msgid "Ensures that a reference name is well formed"
msgstr "Äảm bảo rằng má»™t tên tham chiếu ở dạng thức tốt"
msgid "Switch branches or restore working tree files"
-msgstr "Chuyển các nhánh hoặc phục hồi lại các tập tin cây làm việc"
+msgstr "Chuyển các nhánh hoặc phục hồi lại các tập tin trong cây làm việc"
msgid "Copy files from the index to the working tree"
-msgstr "Sao chép các tập tin từ mục lục ra cây làm việc"
+msgstr "Sao chép các tập tin từ chỉ mục ra cây làm việc"
msgid "Find commits yet to be applied to upstream"
-msgstr "Tìm những lần chuyển giao còn chưa được áp dụng lên thượng nguồn"
+msgstr "Tìm những lần chuyển giao chưa được đẩy lên thượng nguồn"
msgid "Apply the changes introduced by some existing commits"
msgstr "Ãp dụng các thay đổi được đưa ra bởi má»™t số lần chuyển giao sẵn có"
@@ -13369,13 +14169,13 @@ msgid "Retrieve and store user credentials"
msgstr "Nhận và lưu chứng nhận cá»§a ngưá»i dùng"
msgid "Helper to temporarily store passwords in memory"
-msgstr "Bá»™ há»— trợ để lưu mật khẩu tạm thá»i trong bá»™ nhá»›"
+msgstr "helper để lưu mật khẩu tạm thá»i trong bá»™ nhá»›"
msgid "Helper to store credentials on disk"
-msgstr "Bộ hỗ trợ để lưu chứng nhận vào đĩa"
+msgstr "helper để lưu chứng nhận vào đĩa"
msgid "Export a single commit to a CVS checkout"
-msgstr "Xuất một lần chuyển giao thành một lần lấy ra CVS"
+msgstr "Xuất một lần chuyển giao thành một lần checkout CVS"
msgid "Salvage your data out of another SCM people love to hate"
msgstr "Xem xét giá trị dữ liệu cá»§a bạn khá»i ngưá»i khác yêu SCM để ghét"
@@ -13384,23 +14184,26 @@ msgid "A CVS server emulator for Git"
msgstr "Má»™t bá»™ mô phá»ng máy dịch vụ CVS cho Git"
msgid "A really simple server for Git repositories"
-msgstr "Một máy phục vụ thực sự đơn giản dành cho kho Git"
+msgstr "Một máy chủ thực sự đơn giản dành cho kho Git"
msgid "Give an object a human readable name based on an available ref"
msgstr ""
"ÄÆ°a ra má»™t đối tượng dá»±a trên má»™t tên ở dạng con ngưá»i Ä‘á»c được trên má»™t "
"tham chiếu sẵn có"
+msgid "Generate a zip archive of diagnostic information"
+msgstr "tạo tập tin nén zip của bản báo cáo"
+
msgid "Show changes between commits, commit and working tree, etc"
msgstr ""
"Hiển thị các thay đổi giữa những lần chuyển giao, giữa một lần chuyển giao "
"và cây làm việc, v.v.."
msgid "Compares files in the working tree and the index"
-msgstr "So sánh các tập tin trong cây làm việc và bảng mục lục"
+msgstr "So sánh các tập tin trong cây làm việc và chỉ mục"
msgid "Compare a tree to the working tree or index"
-msgstr "So sánh các cây trong cây làm việc hoặc bảng mục lục"
+msgstr "So sánh các cây trong cây làm việc hoặc chỉ mục"
msgid "Compares the content and mode of blobs found via two tree objects"
msgstr ""
@@ -13434,7 +14237,7 @@ msgid "Run a Git command on a list of repositories"
msgstr "Chạy lệnh Git trên danh sách các kho chứa"
msgid "Prepare patches for e-mail submission"
-msgstr "Chuẩn bị các miếng vá để gửi qua thư điện tử"
+msgstr "Chuẩn bị các bản vá để gửi qua thư điện tử"
msgid "Verifies the connectivity and validity of the objects in the database"
msgstr ""
@@ -13449,13 +14252,13 @@ msgstr ""
"Rút trích mã số lần chuyển giao từ một kho nén đã được tạo bởi git-archive"
msgid "Print lines matching a pattern"
-msgstr "In ra những dòng khớp với một mẫu"
+msgstr "In ra những dòng khớp với mẫu"
msgid "A portable graphical interface to Git"
msgstr "Má»™t giao diện đồ há»a khả chuyển cho Git"
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "Tính toán ID đối tượng và tùy chá»n là tạo má»™t blob từ má»™t tập tin"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "Tính toán ID đối tượng và tùy tạo một object từ một tập tin"
msgid "Display help information about Git"
msgstr "Hiển thị thông tin trợ giúp vỠGit"
@@ -13464,7 +14267,7 @@ msgid "Run git hooks"
msgstr "Chạy các móc git"
msgid "Server side implementation of Git over HTTP"
-msgstr "Thi hành phía máy chủ của Git qua HTTP"
+msgstr "Hỗ trợ phía máy chủ của Git qua HTTP"
msgid "Download from a remote Git repository via HTTP"
msgstr "Tải vỠtừ một kho chứa Git trên mạng thông qua HTTP"
@@ -13473,11 +14276,10 @@ msgid "Push objects over HTTP/DAV to another repository"
msgstr "Äẩy các đối tượng lên thông qua HTTP/DAV đến kho chứa khác"
msgid "Send a collection of patches from stdin to an IMAP folder"
-msgstr ""
-"Gửi một bộ sưu tập các miếng vá từ đầu vào tiêu chuẩn đến một thư mục IMAP"
+msgstr "Gửi một bộ sưu tập các bản vá từ stdin đến một thư mục IMAP"
msgid "Build pack index file for an existing packed archive"
-msgstr "Xây dựng tập tin mục lục gói cho một kho nén đã đóng gói sẵn có"
+msgstr "Xây dựng tập tin chỉ mục gói cho một kho nén đã đóng gói sẵn có"
msgid "Create an empty Git repository or reinitialize an existing one"
msgstr "Tạo một kho git mới hay khởi tạo lại một kho đã tồn tại từ trước"
@@ -13486,13 +14288,13 @@ msgid "Instantly browse your working repository in gitweb"
msgstr "Duyệt ngay kho làm việc của bạn trong gitweb"
msgid "Add or parse structured information in commit messages"
-msgstr "Thêm hay phân tích thông tin cấu trúc trong ghi chú lần chuyển giao"
+msgstr "Thêm hay Ä‘á»c thông tin cấu trúc trong ghi chú lần chuyển giao"
msgid "Show commit logs"
msgstr "Hiển thị nhật ký các lần chuyển giao"
msgid "Show information about files in the index and the working tree"
-msgstr "Hiển thị thông tin vỠcác tập tin trong bảng mục lục và cây làm việc"
+msgstr "Hiển thị thông tin vỠcác tập tin trong chỉ mục và cây làm việc"
msgid "List references in a remote repository"
msgstr "Liệt kê các tham chiếu trong một kho chứa trên mạng"
@@ -13516,7 +14318,7 @@ msgid "Find as good common ancestors as possible for a merge"
msgstr "Tìm các tổ tiên chung tốt có thể được cho hòa trộn"
msgid "Run a three-way file merge"
-msgstr "Chạy má»™t hòa trá»™n tập tin “3-đưá»ngâ€"
+msgstr "Chạy má»™t hòa trá»™n tập tin '3-đưá»ng'"
msgid "Run a merge for files needing merging"
msgstr "Chạy một hòa trộn cho các tập tin cần hòa trộn"
@@ -13524,13 +14326,12 @@ msgstr "Chạy một hòa trộn cho các tập tin cần hòa trộn"
msgid "The standard helper program to use with git-merge-index"
msgstr "Một chương trình hỗ trợ tiêu chuẩn dùng với git-merge-index"
-msgid "Show three-way merge without touching index"
-msgstr "Hiển thị hòa trá»™n ba-đưá»ng mà không đụng chạm đến mục lục"
+msgid "Perform merge without touching index or working tree"
+msgstr "Ãp dụng má»™t bản vá mà không động chạm đến cây làm việc"
msgid "Run merge conflict resolution tools to resolve merge conflicts"
msgstr ""
-"Chạy công cụ phân giải xung đột hòa trộn để mà giải quyết các xung đột hòa "
-"trá»™n"
+"Chạy công cụ phân giải xung đột hòa trộn để giải quyết các xung đột hòa trộn"
msgid "Creates a tag object with extra validation"
msgstr "Tạo một đối tượng thẻ với kiểm tra mở rộng"
@@ -13563,7 +14364,7 @@ msgid "Pack heads and tags for efficient repository access"
msgstr "Äóng gói các phần đầu và thẻ để truy cập kho hiệu quả hÆ¡n"
msgid "Compute unique ID for a patch"
-msgstr "Tính toán ID duy nhất cho một miếng vá"
+msgstr "Tính toán ID duy nhất cho một bản vá"
msgid "Prune all unreachable objects from the object database"
msgstr ""
@@ -13579,16 +14380,16 @@ msgid "Update remote refs along with associated objects"
msgstr "Cập nhật th.chiếu máy chủ cùng với các đối tượng liên quan đến nó"
msgid "Applies a quilt patchset onto the current branch"
-msgstr "Ấp dụng một bộ miếng vá quilt vào trong nhánh hiện hành"
+msgstr "Ấp dụng một bộ bản vá quilt vào trong nhánh hiện hành"
msgid "Compare two commit ranges (e.g. two versions of a branch)"
msgstr "So sánh hai vùng chuyển giao (vd: hai phiên bản của một nhánh)"
msgid "Reads tree information into the index"
-msgstr "Äá»c thông tin cây vào trong mục lục"
+msgstr "Äá»c thông tin cây vào trong chỉ mục"
msgid "Reapply commits on top of another base tip"
-msgstr "Thu hoạch các lần chuyển giao trên đỉnh của đầu mút cơ sở khác"
+msgstr "Thu hoạch các lần chuyển giao trên đỉnh của đỉnh cơ sở khác"
msgid "Receive what is pushed into the repository"
msgstr "Nhận cái mà được đẩy vào trong kho"
@@ -13596,6 +14397,9 @@ msgstr "Nhận cái mà được đẩy vào trong kho"
msgid "Manage reflog information"
msgstr "Quản lý thông tin reflog"
+msgid "Low-level access to refs"
+msgstr "Truy cập tới tham chiếu ở mức thấp"
+
msgid "Manage set of tracked repositories"
msgstr "Quản lý tập hợp các kho chứa đã được theo dõi"
@@ -13605,6 +14409,11 @@ msgstr "Äóng gói các đối tượng chưa đóng gói ở má»™t kho chứa"
msgid "Create, list, delete refs to replace objects"
msgstr "Tạo, liệt kê, xóa các tham chiếu để thay thế các đối tượng"
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr ""
+"ÄANG TRONG QUà TRÃŒNH THỬ NGHIỆM: Phát lại lần chuyển giao vào gốc má»›i, dùng "
+"được trong kho chứa bare"
+
msgid "Generates a summary of pending changes"
msgstr "Tạo ra một tóm tắt các thay đổi còn treo"
@@ -13627,25 +14436,25 @@ msgid "Revert some existing commits"
msgstr "Hoàn lại một số lần chuyển giao sẵn có"
msgid "Remove files from the working tree and from the index"
-msgstr "Gỡ bỠcác tập tin từ cây làm việc và từ bảng mục lục"
+msgstr "Gỡ bỠcác tập tin từ cây làm việc và từ chỉ mục"
msgid "Send a collection of patches as emails"
-msgstr "Gửi một tập hợp của các miếng vá ở dạng thư điện tử"
+msgstr "Gửi một tập hợp của các bản vá ở dạng thư điện tử"
msgid "Push objects over Git protocol to another repository"
msgstr "Äẩy các đối tượng lên thông qua giao thức Git đến kho chứa khác"
msgid "Git's i18n setup code for shell scripts"
-msgstr "Mã cài đặt quốc tế hóa cá»§a Git cho văn lệnh hệ vá»"
+msgstr "Mã cài đặt quốc tế hóa của Git cho shell script"
msgid "Common Git shell script setup code"
-msgstr "Mã cài đặt văn lệnh hệ vỠGit chung"
+msgstr "Mã cài đặt shell script Git chung"
msgid "Restricted login shell for Git-only SSH access"
-msgstr "Hệ vỠđăng nhập có hạn chế cho truy cập SSH chỉ-Git"
+msgstr "Shell đăng nhập có hạn chế cho truy cập SSH chỉ-Git"
msgid "Summarize 'git log' output"
-msgstr "Kết xuất “git log†dạng tóm tắt"
+msgstr "Tóm tắt kết quả 'git log'"
msgid "Show various types of objects"
msgstr "Hiển thị các kiểu khác nhau của các đối tượng"
@@ -13665,7 +14474,7 @@ msgstr ""
"dõi"
msgid "Add file contents to the staging area"
-msgstr "Thêm nội dung tập tin vào vùng bệ phóng"
+msgstr "Thêm ná»™i dung tập tin vào vùng vùng chá»"
msgid "Stash the changes in a dirty working directory away"
msgstr "Tạm cất đi các thay đổi trong một thư mục làm việc bẩn"
@@ -13683,7 +14492,7 @@ msgid "Bidirectional operation between a Subversion repository and Git"
msgstr "Thao tác hai hướng giữ hai kho Subversion và Git"
msgid "Switch branches"
-msgstr "Các nhánh chuyển"
+msgstr "Chuyển sang nhánh khác"
msgid "Read, modify and delete symbolic refs"
msgstr "Äá»c, sá»­a và xóa tham chiếu má»m"
@@ -13698,7 +14507,7 @@ msgid "Unpack objects from a packed archive"
msgstr "Gỡ các đối tượng khá»i má»™t kho lưu đã đóng gói"
msgid "Register file contents in the working tree to the index"
-msgstr "Äăng ký ná»™i dung tập tin từ cây làm việc đến bảng mục lục"
+msgstr "Äăng ký ná»™i dung tập tin từ cây làm việc đến chỉ mục"
msgid "Update the object name stored in a ref safely"
msgstr "Cập nhật tên đối tượng được lưu trong một tham chiếu một cách an toàn"
@@ -13724,20 +14533,23 @@ msgstr "Kiểm tra lại các tập tin kho (lưu trữ, nén) Git đã được
msgid "Check the GPG signature of tags"
msgstr "Kiểm tra chữ ký GPG của các thẻ"
-msgid "Show logs with difference each commit introduces"
-msgstr "Hiển thị các nhật ký với từng lần chuyển giao khác nhau đưa ra"
+msgid "Display version information about Git"
+msgstr "Hiển thị thông tin vỠphiên bản Git"
+
+msgid "Show logs with differences each commit introduces"
+msgstr "Hiển thị nhật ký với thay đổi của từng lần chuyển giao"
msgid "Manage multiple working trees"
msgstr "Quản lý nhiá»u cây làm việc"
msgid "Create a tree object from the current index"
-msgstr "Tạo một đối tượng cây từ đầu vào tiêu chuẩn stdin hiện tại"
+msgstr "Tạo một đối tượng cây từ chỉ mục hiện tại"
msgid "Defining attributes per path"
msgstr "Äịnh nghÄ©a các thuá»™c tính cho má»—i đưá»ng dẫn"
msgid "Git command-line interface and conventions"
-msgstr "Giao diện dòng lệnh Git và quy ước"
+msgstr "Giao diện dòng lệnh Git và các quy ước"
msgid "A Git core tutorial for developers"
msgstr "Hướng dẫn Git cơ bản cho nhà phát triển"
@@ -13749,25 +14561,43 @@ msgid "Git for CVS users"
msgstr "Git dành cho những ngưá»i dùng CVS"
msgid "Tweaking diff output"
-msgstr "Chỉnh kết xuất diff"
+msgstr "Tinh chỉnh đầu ra diff"
msgid "A useful minimum set of commands for Everyday Git"
-msgstr "Một tập hợp lệnh hữu dụng tối thiểu để dùng Git hàng ngày"
+msgstr "Tập hợp lệnh hữu dụng tối thiểu để dùng Git hàng ngày"
msgid "Frequently asked questions about using Git"
msgstr "Các câu há»i thưá»ng gặp vá» cách sá»­ dụng Git"
+msgid "The bundle file format"
+msgstr "Äịnh dạng tập tin bundle"
+
+msgid "Chunk-based file formats"
+msgstr "Äịnh dạng tập tin dạng khúc"
+
+msgid "Git commit-graph format"
+msgstr "Äịnh dạng đồ-thị-chuyển-giao"
+
+msgid "Git index format"
+msgstr "Äịnh dạng chỉ mục"
+
+msgid "Git pack format"
+msgstr "Äịnh dạng pack"
+
+msgid "Git cryptographic signature formats"
+msgstr "Äịnh dạng chữ ký bảo mật Git"
+
msgid "A Git Glossary"
msgstr "Thuật ngữ chuyên môn Git"
msgid "Hooks used by Git"
-msgstr "Các móc được sử dụng bởi Git"
+msgstr "Các hook được sử dụng bởi Git"
msgid "Specifies intentionally untracked files to ignore"
msgstr "Chỉ định các tập tin không cần theo dõi"
msgid "The Git repository browser"
-msgstr "Bộ duyện kho Git"
+msgstr "Bộ duyệt kho Git"
msgid "Map author/committer names and/or E-Mail addresses"
msgstr "Ãnh xạ tên tác giả/ngưá»i chuyển giao và/hoặc địa chỉ E-Mail"
@@ -13778,8 +14608,23 @@ msgstr "Äịnh nghÄ©a thuá»™c tính mô-Ä‘un-con"
msgid "Git namespaces"
msgstr "Không gian tên Git"
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Capabilities của giao thức v0 và v1"
+
+msgid "Things common to various protocols"
+msgstr "Những thứ chung cho các giao thức"
+
+msgid "Git HTTP-based protocols"
+msgstr "Những giao thức Git dựa trên HTTP"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Gói được truyá»n thá»±c tế (over-the-wire) như thế nào"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Git Wire Protocol, Version 2"
+
msgid "Helper programs to interact with remote repositories"
-msgstr "Các chương trình hỗ trợ để tương tác với các kho chứa trên máy chủ"
+msgstr "Các chương trình helper để tương tác với các kho chứa trên máy chủ"
msgid "Git Repository Layout"
msgstr "Bố cục kho Git"
@@ -13802,44 +14647,98 @@ msgstr "Giao diện Git trên ná»n web (ứng dụng web chạy trên kho Git)"
msgid "An overview of recommended workflows with Git"
msgstr "Tổng quan vỠluồng công việc khuyến nghị nên dùng với Git"
+msgid "A tool for managing large Git repositories"
+msgstr "Công cụ quản lý các kho Git lớn"
+
msgid "commit-graph file is too small"
-msgstr "tập tin đồ-thị-các-lần-chuyển-giao quá nhá»"
+msgstr "tập tin đồ-thị-chuyển-giao quá nhá»"
+
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "đồ-thị-chuyển-giao có kích cỡ oid fanout chunk không đúng"
+
+msgid "commit-graph fanout values out of order"
+msgstr "đồ-thị-chuyển-giao có giá trị fanout không đúng"
+
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "đồ-thị-chuyển-giao có kích cỡ OID lookup chunk không đúng"
+
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "đồ-thị-chuyển-giao có kích cỡ commit data chunk không đúng"
+
+msgid "commit-graph generations chunk is wrong size"
+msgstr "đồ-thị-chuyển-giao có kích cỡ generations chunk không đúng"
+
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "đồ-thị-chuyển-giao có changed-path index chunk quá nhá»"
+
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr ""
+"bá» qua chunk thay-đổi-đưá»ng-dẫn quá nhá» (%<PRIuMAX> < %<PRIuMAX>) trong tập "
+"tin đồ-thị-chuyển-giao"
#, c-format
msgid "commit-graph signature %X does not match signature %X"
-msgstr "chữ ký đồ-thị-các-lần-chuyển-giao %X không khớp chữ ký %X"
+msgstr "chữ ký đồ-thị-chuyển-giao %X không khớp chữ ký %X"
#, c-format
msgid "commit-graph version %X does not match version %X"
-msgstr "phiên bản đồ-thị-các-lần-chuyển-giao %X không khớp phiên bản %X"
+msgstr "phiên bản đồ-thị-chuyển-giao %X không khớp phiên bản %X"
#, c-format
msgid "commit-graph hash version %X does not match version %X"
-msgstr "phiên bản đồ-thị-các-lần-chuyển-giao %X không khớp phiên bản %X"
+msgstr "phiên bản đồ-thị-chuyển-giao %X không khớp phiên bản %X"
#, c-format
msgid "commit-graph file is too small to hold %u chunks"
-msgstr "tập tin đồ-thị-các-lần-chuyển-giao quá nhỠđể giữ %u mảnh dữ liệu"
+msgstr "tập tin đồ-thị-chuyển-giao quá nhỠđể giữ %u chunk"
+
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr "đồ-thị-chuyển-giao thiếu chunk OID fanout cần thiết hoặc bị há»ng"
+
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "đồ-thị-chuyển-giao thiếu chunk OID lookup cần thiết hoặc bị há»ng"
+
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr "đồ-thị-chuyển-giao thiếu chunk commit data cần thiết hoặc bị há»ng"
+
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"vô hiệu hoá bá»™ lá»c Bloom cho đồ thị chuyển giao '%s' do tuỳ chá»n không tương "
+"thích"
msgid "commit-graph has no base graphs chunk"
-msgstr "đồ-thị-các-lần-chuyển-giao có không có mảnh các đồ há»a cÆ¡ sở"
+msgstr "đồ thị chuyển giao không có chunk đồ thị cơ sở"
+
+msgid "commit-graph base graphs chunk is too small"
+msgstr "đồ thị chuyển giao có chunk đồ thị cÆ¡ sở quá nhá»"
msgid "commit-graph chain does not match"
-msgstr "móc xích đồ-thị-các-lần-chuyển-giao không khớp"
+msgstr "chuỗi đồ-thị-chuyển-giao không khớp"
+
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "số lần chuyển giao trong đồ thị cơ sở quá lớn: %<PRIuMAX>"
+
+msgid "commit-graph chain file too small"
+msgstr "tập tin chuá»—i đồ-thị-chuyển-giao quá nhá»"
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr ""
-"móc xích đồ-thị-các-lần-chuyển-giao không hợp lệ: dòng “%s†không phải là "
-"một mã băm"
+"chuỗi đồ-thị-chuyển-giao không hợp lệ: dòng '%s' không phải là một mã băm"
msgid "unable to find all commit-graph files"
-msgstr "không thể tìm thấy tất cả các tập tin đồ-thị-các-lần-chuyển-giao"
+msgstr "không thể tìm thấy tất cả các tập tin đồ-thị-chuyển-giao"
msgid "invalid commit position. commit-graph is likely corrupt"
msgstr ""
-"vị trí lần chuyển giao không hợp lệ. đồ-thị-các-lần-chuyển-giao có vẻ như đã "
-"bị há»ng"
+"vị trí lần chuyển giao không hợp lệ. đồ-thị-chuyển-giao có vẻ như đã bị há»ng"
#, c-format
msgid "could not find commit %s"
@@ -13848,6 +14747,12 @@ msgstr "không thể tìm thấy lần chuyển giao %s"
msgid "commit-graph requires overflow generation data but has none"
msgstr "commit-graph yêu cầu dữ liệu tạo tràn nhưng không có"
+msgid "commit-graph overflow generation data is too small"
+msgstr "commit-graph yêu cầu dữ liệu tạo tràn nhưng quá nhá»"
+
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "con trỠextra-edge của đồ thị chuyển giao nằm ngoài biên"
+
msgid "Loading known commits in commit graph"
msgstr "Äang tải các lần chuyển giao chưa biết trong đồ thị lần chuyển giao"
@@ -13883,7 +14788,7 @@ msgstr "gặp lỗi thêm gói %s"
#, c-format
msgid "error opening index for %s"
-msgstr "gặp lá»—i khi mở mục lục cho “%sâ€"
+msgstr "gặp lỗi khi mở chỉ mục cho '%s'"
msgid "Finding commits for commit graph among packed objects"
msgstr ""
@@ -13901,7 +14806,7 @@ msgstr "không thể tạo lá»›p sÆ¡ đồ tạm thá»i"
#, c-format
msgid "unable to adjust shared permissions for '%s'"
-msgstr "không thể chỉnh sá»­a quyá»n chia sẻ thành “%sâ€"
+msgstr "không thể chỉnh sá»­a quyá»n chia sẻ thành '%s'"
#, c-format
msgid "Writing out commit graph in %d pass"
@@ -13909,102 +14814,109 @@ msgid_plural "Writing out commit graph in %d passes"
msgstr[0] "Äang ghi ra đồ thị các lần chuyển giao trong lần %d"
msgid "unable to open commit-graph chain file"
-msgstr "không thể mở tập tin mắt xích đồ thị chuyển giao"
+msgstr "không thể mở tập tin chain đồ thị chuyển giao"
msgid "failed to rename base commit-graph file"
-msgstr "gặp lỗi khi đổi tên tập tin đồ-thị-các-lần-chuyển-giao"
+msgstr "gặp lỗi khi đổi tên tập tin đồ-thị-chuyển-giao"
msgid "failed to rename temporary commit-graph file"
-msgstr "gặp lá»—i khi đổi tên tập tin đồ-thị-các-lần-chuyển-giao tạm thá»i"
+msgstr "gặp lá»—i khi đổi tên tập tin đồ-thị-chuyển-giao tạm thá»i"
+
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "không thể kết hợp đồ thị với %<PRIuMAX>, %<PRIuMAX> lần chuyển giao"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "không thể kết hợp đồ thị %s, quá nhiá»u lần chuyển giao: %<PRIuMAX>"
msgid "Scanning merged commits"
msgstr "Äang quét các lần chuyển giao đã hòa trá»™n"
msgid "Merging commit-graph"
-msgstr "Äang hòa trá»™n đồ-thị-các-lần-chuyển-giao"
+msgstr "Äang hòa trá»™n đồ-thị-chuyển-giao"
msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr ""
-"cố gắng để ghi một đồ thị các lần chuyển giao, nhưng “core.commitGraph†bị "
-"vô hiệu hóa"
+"đang thử ghi đồ thị chuyển giao, nhưng 'core.commitGraph' bị vô hiệu hóa"
+
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr ""
+"đang thử ghi đồ thị chuyển giao, nhưng 'commitGraph.changedPathsVersion' "
+"(%d) không được hỗ trợ"
msgid "too many commits to write graph"
msgstr "có quá nhiá»u lần chuyển giao để ghi đồ thị"
msgid "the commit-graph file has incorrect checksum and is likely corrupt"
msgstr ""
-"tập tin đồ-thị-các-lần-chuyển-giao có tổng kiểm không đúng và có vẻ như là "
-"đã há»ng"
+"tập tin đồ-thị-chuyển-giao có tổng kiểm không đúng và có vẻ như là đã há»ng"
#, c-format
msgid "commit-graph has incorrect OID order: %s then %s"
-msgstr "đồ-thị-các-lần-chuyển-giao có thứ tự OID không đúng: %s sau %s"
+msgstr "đồ-thị-chuyển-giao có thứ tự OID không đúng: %s sau %s"
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
-msgstr ""
-"đồ-thị-các-lần-chuyển-giao có giá trị fanout không đúng: fanout[%d] = %u != "
-"%u"
+msgstr "đồ-thị-chuyển-giao có giá trị fanout không đúng: fanout[%d] = %u != %u"
#, c-format
msgid "failed to parse commit %s from commit-graph"
-msgstr "gặp lỗi khi phân tích lần chuyển giao từ %s đồ-thị-các-lần-chuyển-giao"
-
-msgid "Verifying commits in commit graph"
-msgstr "Äang thẩm tra các lần chuyển giao trong đồ thị lần chuyển giao"
+msgstr "gặp lá»—i khi Ä‘á»c lần chuyển giao từ %s đồ-thị-chuyển-giao"
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
msgstr ""
-"gặp lỗi khi phân tích lần chuyển giao %s từ cơ sở dữ liệu đối tượng cho đồ "
-"thị lần chuyển giao"
+"gặp lá»—i khi Ä‘á»c lần chuyển giao %s từ cÆ¡ sở dữ liệu đối tượng cho đồ thị lần "
+"chuyển giao"
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
msgstr ""
-"OID cây gốc cho lần chuyển giao %s trong đồ-thị-các-lần-chuyển-giao là %s != "
-"%s"
+"OID cây gốc cho lần chuyển giao %s trong đồ-thị-chuyển-giao là %s != %s"
#, c-format
msgid "commit-graph parent list for commit %s is too long"
-msgstr ""
-"danh sách cha mẹ đồ-thị-các-lần-chuyển-giao cho lần chuyển giao %s là quá dài"
+msgstr "danh sách cha mẹ đồ-thị-chuyển-giao cho lần chuyển giao %s là quá dài"
#, c-format
msgid "commit-graph parent for %s is %s != %s"
-msgstr "cha mẹ đồ-thị-các-lần-chuyển-giao cho %s là %s != %s"
+msgstr "cha mẹ đồ-thị-chuyển-giao cho %s là %s != %s"
#, c-format
msgid "commit-graph parent list for commit %s terminates early"
msgstr ""
-"danh sách cha mẹ đồ-thị-các-lần-chuyển-giao cho lần chuyển giao %s bị chấm "
-"dứt quá sớm"
+"danh sách cha mẹ đồ-thị-chuyển-giao cho lần chuyển giao %s bị chấm dứt quá "
+"sá»›m"
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
+msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
msgstr ""
-"đồ-thị-các-lần-chuyển-giao có con số không lần tạo cho lần chuyển giao %s, "
-"nhưng không phải số không ở chỗ khác"
+"tạo đồ-thị-chuyển-giao cho lần chuyển giao %s là %<PRIuMAX> < %<PRIuMAX>"
#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
+msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
msgstr ""
-"đồ-thị-các-lần-chuyển-giao có con số không phải không lần tạo cho lần chuyển "
-"giao %s, nhưng số không ở chỗ khác"
+"ngày chuyển giao cho lần chuyển giao %s trong đồ-thị-chuyển-giao là "
+"%<PRIuMAX> != %<PRIuMAX>"
#, c-format
-msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
msgstr ""
-"tạo đồ-thị-các-lần-chuyển-giao cho lần chuyển giao %s là %<PRIuMAX> < "
-"%<PRIuMAX>"
+"đồ-thị-chuyển-giao có số thế hệ không và khác không (v.d. lần chuyển giao "
+"'%s' và '%s')"
+
+msgid "Verifying commits in commit graph"
+msgstr "Äang thẩm tra các lần chuyển giao trong đồ thị lần chuyển giao"
#, c-format
-msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
-msgstr ""
-"ngày chuyển giao cho lần chuyển giao %s trong đồ-thị-các-lần-chuyển-giao là "
-"%<PRIuMAX> != %<PRIuMAX>"
+msgid "could not parse commit %s"
+msgstr "không thể Ä‘á»c lần chuyển giao %s"
#, c-format
msgid "%s %s is not a commit!"
@@ -14020,7 +14932,7 @@ msgid ""
"Turn this message off by running\n"
"\"git config advice.graftFileDeprecated false\""
msgstr ""
-"Việc hỗ trợ cho <GIT_DIR>/info/grafts đã lạc hậu\n"
+"Hỗ trợ cho <GIT_DIR>/info/grafts đã không còn\n"
"và sẽ bị xóa bỠở phiên bản Git tương lai.\n"
"\n"
"Vui lòng dùng \"git replace --convert-graft-file\"\n"
@@ -14030,6 +14942,12 @@ msgstr ""
"\"git config advice.graftFileDeprecated false\""
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr ""
+"commit %s tồn tại trong đồ-thị-chuyển-giao nhưng không có trong cơ sở dữ "
+"liệu đối tượng"
+
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr ""
"Lần chuyển giao %s có một chữ ký GPG không đáng tin, được cho là bởi %s."
@@ -14062,6 +14980,14 @@ msgid "no libc information available\n"
msgstr "không có thông tin vỠlibc\n"
#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "không thể dò tìm chỗ trống trên đĩa cho '%s'"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "không thể lấy thông tin cho '%s'"
+
+#, c-format
msgid "[GLE %ld] health thread could not open '%ls'"
msgstr "[GLE %ld] không thể mở tuyến trình sức khá»e '%ls'"
@@ -14085,6 +15011,10 @@ msgstr "có trưá»ng hợp không được xá»­ lý trong 'has_worktree_moved'
msgid "health thread wait failed [GLE %ld]"
msgstr "gặp lá»—i khi chá» tiến trình sức khá»e [GLE %ld]"
+#, c-format
+msgid "Invalid path: %s"
+msgstr "đưá»ng dẫn không hợp lệ: %s"
+
msgid "Unable to create FSEventStream."
msgstr "Không thể tạo FSEventStream."
@@ -14116,6 +15046,30 @@ msgid "could not read directory changes [GLE %ld]"
msgstr "không thể Ä‘á»c các thay đổi thư mục [GLE %ld]"
#, c-format
+msgid "opendir('%s') failed"
+msgstr "opendir('%s') gặp lỗi"
+
+#, c-format
+msgid "lstat('%s') failed"
+msgstr "lstat('%s') gặp lỗi"
+
+#, c-format
+msgid "strbuf_readlink('%s') failed"
+msgstr "strbuf_readlink('%s') gặp lỗi"
+
+#, c-format
+msgid "closedir('%s') failed"
+msgstr "closedir('%s') gặp lỗi"
+
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] không thể mở hay Ä‘á»c '%ls'"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] không thể lấy thông tin giao thức cho '%ls'"
+
+#, c-format
msgid "failed to copy SID (%ld)"
msgstr "gặp lỗi khi sao chép SID (%ld)"
@@ -14154,7 +15108,7 @@ msgid "Unmatched ( or \\("
msgstr "Chưa khớp ( hay \\("
msgid "Unmatched \\{"
-msgstr "Chưa khá»›p cặp “\\{â€"
+msgstr "Chưa khớp cặp '\\{'"
msgid "Invalid content of \\{\\}"
msgstr "Nội dung của \\{\\} không hợp lệ"
@@ -14188,11 +15142,11 @@ msgstr "không thể Ä‘á»c đáp ứng IPC"
#, c-format
msgid "could not start accept_thread '%s'"
-msgstr "không thể khởi chạy accept_thread “%sâ€"
+msgstr "không thể khởi chạy accept_thread '%s'"
#, c-format
msgid "could not start worker[0] for '%s'"
-msgstr "không thể khởi chạy bá»™ làm việc worker[0] cho “%sâ€"
+msgstr "không thể khởi chạy bộ làm việc worker[0] cho '%s'"
#, c-format
msgid "ConnectNamedPipe failed for '%s' (%lu)"
@@ -14204,11 +15158,11 @@ msgstr "không thể tạo mô tả tập tin từ đưá»ng ống cho '%s'"
#, c-format
msgid "could not start thread[0] for '%s'"
-msgstr "không thể khởi chạy tiến trình[0] cho “%sâ€"
+msgstr "không thể khởi chạy tiến trình[0] cho '%s'"
#, c-format
msgid "wait for hEvent failed for '%s'"
-msgstr "chá» cho hEvent gặp lá»—i vá»›i “%sâ€"
+msgstr "chỠcho hEvent gặp lỗi với '%s'"
msgid "cannot resume in the background, please use 'fg' to resume"
msgstr ""
@@ -14234,7 +15188,7 @@ msgstr ""
#, c-format
msgid "could not expand include path '%s'"
-msgstr "không thể khai triển đưá»ng dẫn “%sâ€"
+msgstr "không thể khai triển đưá»ng dẫn '%s'"
msgid "relative config includes must come from files"
msgstr "các bao gồm cấu hình liên quan phải đến từ các tập tin"
@@ -14246,7 +15200,7 @@ msgid ""
"remote URLs cannot be configured in file directly or indirectly included by "
"includeIf.hasconfig:remote.*.url"
msgstr ""
-"các URL máy chủ không thể được cấu hình trong tệp trực tiếp hoặc gián tiếp "
+"các URL máy chủ không thể được cấu hình trong tập trực tiếp hoặc gián tiếp "
"được bao gồm bởi includeIf.hasconfig:remote.*.url"
#, c-format
@@ -14255,11 +15209,11 @@ msgstr "định dạng cấu hình không hợp lệ: %s"
#, c-format
msgid "missing environment variable name for configuration '%.*s'"
-msgstr "thiếu tên biến môi trưá»ng cho cấu hình “%.*sâ€"
+msgstr "thiếu tên biến môi trưá»ng cho cấu hình '%.*s'"
#, c-format
msgid "missing environment variable '%s' for configuration '%.*s'"
-msgstr "thiếu biến môi trưá»ng “%s†cho cấu hình “%.*sâ€"
+msgstr "thiếu biến môi trưá»ng '%s' cho cấu hình '%.*s'"
#, c-format
msgid "key does not contain a section: %s"
@@ -14271,7 +15225,7 @@ msgstr "khóa không chứa bất kỳ một tên biến nào: %s"
#, c-format
msgid "invalid key: %s"
-msgstr "khóa không đúng: %s"
+msgstr "khóa không hợp lệ: %s"
#, c-format
msgid "invalid key (newline): %s"
@@ -14298,11 +15252,11 @@ msgstr "quá nhiá»u mục tin trong %s"
#, c-format
msgid "missing config key %s"
-msgstr "thiếu khóa cấu hình “%sâ€"
+msgstr "thiếu khóa cấu hình '%s'"
#, c-format
msgid "missing config value %s"
-msgstr "thiếu giá trị cấu hình “%sâ€"
+msgstr "thiếu giá trị cấu hình '%s'"
#, c-format
msgid "bad config line %d in blob %s"
@@ -14314,7 +15268,7 @@ msgstr "cấu hình sai tại dòng %d trong tập tin %s"
#, c-format
msgid "bad config line %d in standard input"
-msgstr "cấu hình sai tại dòng %d trong đầu vào tiêu chuẩn"
+msgstr "cấu hình sai tại dòng %d từ stdin"
#, c-format
msgid "bad config line %d in submodule-blob %s"
@@ -14336,33 +15290,32 @@ msgstr "đơn vị không hợp lệ"
#, c-format
msgid "bad numeric config value '%s' for '%s': %s"
-msgstr "sai giá trị bằng số cá»§a cấu hình “%s†cho “%sâ€: %s"
+msgstr "sai giá trị bằng số của cấu hình '%s' cho '%s': %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
-msgstr "sai giá trị bằng số của cấu hình “%s†cho “%s†trong blob %s: %s"
+msgstr "sai giá trị bằng số của cấu hình '%s' cho '%s' trong blob %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in file %s: %s"
-msgstr "sai giá trị bằng số của cấu hình “%s†cho “%s†trong tập tin %s: %s"
+msgstr "sai giá trị bằng số của cấu hình '%s' cho '%s' trong tập tin %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in standard input: %s"
-msgstr ""
-"sai giá trị bằng số của cấu hình “%s†cho “%s†trong đầu vào tiêu chuẩn: %s"
+msgstr "sai giá trị bằng số của cấu hình '%s' cho '%s' trong stdin: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
msgstr ""
-"sai giá trị bằng số của cấu hình “%s†cho “%s†trong submodule-blob %s: %s"
+"sai giá trị bằng số của cấu hình '%s' cho '%s' trong submodule-blob %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
-msgstr "sai giá trị bằng số của cấu hình “%s†cho “%s†trong dòng lệnh %s: %s"
+msgstr "sai giá trị bằng số của cấu hình '%s' cho '%s' trong dòng lệnh %s: %s"
#, c-format
msgid "bad numeric config value '%s' for '%s' in %s: %s"
-msgstr "sai giá trị bằng số của cấu hình “%s†cho “%s†trong %s: %s"
+msgstr "sai giá trị bằng số của cấu hình '%s' cho '%s' trong %s: %s"
#, c-format
msgid "invalid value for variable %s"
@@ -14374,15 +15327,15 @@ msgstr "bỠqua thành phần core.fsync chưa biết '%s'"
#, c-format
msgid "bad boolean config value '%s' for '%s'"
-msgstr "sai giá trị kiểu lô-gíc cá»§a cấu hình “%s†cho “%sâ€"
+msgstr "sai giá trị kiểu boolean của cấu hình '%s' cho '%s'"
#, c-format
msgid "failed to expand user dir in: '%s'"
-msgstr "gặp lá»—i mở rá»™ng thư mục ngưá»i dùng trong: “%sâ€"
+msgstr "gặp lá»—i mở rá»™ng thư mục ngưá»i dùng trong: '%s'"
#, c-format
msgid "'%s' for '%s' is not a valid timestamp"
-msgstr "“%s†dành cho “%s†không phải là dấu vết thá»i gian hợp lệ"
+msgstr "'%s' dành cho '%s' không phải là dấu vết thá»i gian hợp lệ"
#, c-format
msgid "abbrev length out of range: %d"
@@ -14392,8 +15345,13 @@ msgstr "chiá»u dài abbrev nằm ngoài phạm vi: %d"
msgid "bad zlib compression level %d"
msgstr "mức nén zlib %d là sai"
-msgid "core.commentChar should only be one character"
-msgstr "core.commentChar chỉ được có một ký tự"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s không thể chứa ký tự xuống dòng"
+
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s phải có ít nhất một ký tự"
#, c-format
msgid "ignoring unknown core.fsyncMethod value '%s'"
@@ -14419,45 +15377,41 @@ msgstr "phải là một trong số nothing, matching, simple, upstream hay curr
#, c-format
msgid "unable to load config blob object '%s'"
-msgstr "không thể tải đối tượng blob cấu hình “%sâ€"
+msgstr "không thể tải đối tượng blob cấu hình '%s'"
#, c-format
msgid "reference '%s' does not point to a blob"
-msgstr "tham chiếu “%s†không chỉ đến một blob nào cả"
+msgstr "tham chiếu '%s' không chỉ đến một blob nào cả"
#, c-format
msgid "unable to resolve config blob '%s'"
-msgstr "không thể phân giải Ä‘iểm xét duyệt “%sâ€"
-
-#, c-format
-msgid "failed to parse %s"
-msgstr "gặp lỗi khi phân tích cú pháp %s"
+msgstr "không thể phân giải điểm xét duyệt '%s'"
msgid "unable to parse command-line config"
-msgstr "không thể phân tích cấu hình dòng lệnh"
+msgstr "không thể Ä‘á»c cấu hình dòng lệnh"
msgid "unknown error occurred while reading the configuration files"
msgstr "đã có lá»—i chưa biết xảy ra trong khi Ä‘á»c các tập tin cấu hình"
#, c-format
msgid "Invalid %s: '%s'"
-msgstr "%s không hợp lệ: “%sâ€"
+msgstr "%s không hợp lệ: '%s'"
#, c-format
msgid "splitIndex.maxPercentChange value '%d' should be between 0 and 100"
-msgstr "giá trị splitIndex.maxPercentChange “%d†phải nằm giữa 0 và 100"
+msgstr "giá trị splitIndex.maxPercentChange '%d' phải nằm giữa 0 và 100"
#, c-format
msgid "unable to parse '%s' from command-line config"
-msgstr "không thể phân tích “%s†từ cấu hình dòng lệnh"
+msgstr "không thể Ä‘á»c '%s' từ cấu hình dòng lệnh"
#, c-format
msgid "bad config variable '%s' in file '%s' at line %d"
-msgstr "sai biến cấu hình “%s†trong tập tin “%s†tại dòng %d"
+msgstr "sai biến cấu hình '%s' trong tập tin '%s' tại dòng %d"
#, c-format
msgid "invalid section name '%s'"
-msgstr "tên cá»§a phần không hợp lệ “%sâ€"
+msgstr "tên của phần không hợp lệ '%s'"
#, c-format
msgid "%s has multiple values"
@@ -14465,7 +15419,11 @@ msgstr "%s có đa giá trị"
#, c-format
msgid "failed to write new configuration file %s"
-msgstr "gặp lá»—i khi ghi tập tin cấu hình “%sâ€"
+msgstr "gặp lỗi khi ghi tập tin cấu hình '%s'"
+
+#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "không cho phép ghi chú nhiá»u dòng: '%s'"
#, c-format
msgid "could not lock config file %s"
@@ -14473,11 +15431,11 @@ msgstr "không thể khóa tập tin cấu hình %s"
#, c-format
msgid "opening %s"
-msgstr "Ä‘ang mở “%sâ€"
+msgstr "đang mở '%s'"
#, c-format
msgid "invalid config file %s"
-msgstr "tập tin cấu hình “%s†không hợp lệ"
+msgstr "tập tin cấu hình '%s' không hợp lệ"
#, c-format
msgid "fstat on %s failed"
@@ -14485,7 +15443,7 @@ msgstr "fstat trên %s gặp lỗi"
#, c-format
msgid "unable to mmap '%s'%s"
-msgstr "không thể mmap “%sâ€%s"
+msgstr "không thể mmap '%s'%s"
#, c-format
msgid "chmod on %s failed"
@@ -14493,19 +15451,23 @@ msgstr "chmod trên %s gặp lỗi"
#, c-format
msgid "could not write config file %s"
-msgstr "không thể ghi tập tin cấu hình “%sâ€"
+msgstr "không thể ghi tập tin cấu hình '%s'"
#, c-format
msgid "could not set '%s' to '%s'"
-msgstr "không thể đặt “%s†thành “%sâ€"
+msgstr "không thể đặt '%s' thành '%s'"
#, c-format
msgid "invalid section name: %s"
msgstr "tên của phần không hợp lệ: %s"
#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr "từ chối làm việc với dòng quá dài '%s' trên dòng %<PRIuMAX>"
+
+#, c-format
msgid "missing value for '%s'"
-msgstr "thiếu giá trị cho cho “%sâ€"
+msgstr "thiếu giá trị cho cho '%s'"
msgid "the remote end hung up upon initial contact"
msgstr "máy chủ bị treo trên lần tiếp xúc đầu tiên"
@@ -14523,25 +15485,25 @@ msgstr ""
#, c-format
msgid "server doesn't support '%s'"
-msgstr "máy chá»§ không há»— trợ “%sâ€"
+msgstr "máy chủ không hỗ trợ '%s'"
#, c-format
msgid "server doesn't support feature '%s'"
-msgstr "máy chá»§ không há»— trợ tính năng “%sâ€"
+msgstr "máy chủ không hỗ trợ tính năng '%s'"
msgid "expected flush after capabilities"
msgstr "cần đẩy dữ liệu lên đĩa sau các capabilities"
#, c-format
msgid "ignoring capabilities after first line '%s'"
-msgstr "bá» qua capabilities sau dòng đầu tiên “%sâ€"
+msgstr "bỠqua capabilities sau dòng đầu tiên '%s'"
msgid "protocol error: unexpected capabilities^{}"
-msgstr "lỗi giao thức: không cần capabilities^{}"
+msgstr "lá»—i giao thức: capabilities^{} bất thưá»ng"
#, c-format
msgid "protocol error: expected shallow sha-1, got '%s'"
-msgstr "lá»—i giao thức: cần sha-1 shallow, nhưng lại nhận được “%sâ€"
+msgstr "lỗi giao thức: cần sha-1 shallow, nhưng lại có '%s'"
msgid "repository on the other end cannot be shallow"
msgstr "kho đã ở điểm cuối khoác nên không thể được shallow"
@@ -14551,11 +15513,21 @@ msgstr "gói không hợp lệ"
#, c-format
msgid "protocol error: unexpected '%s'"
-msgstr "lá»—i giao thức: không cần “%sâ€"
+msgstr "lá»—i giao thức: '%s' bất thưá»ng"
#, c-format
msgid "unknown object format '%s' specified by server"
-msgstr "không hiểu định dạng đối tượng “%s†được chỉ định bởi máy phục vụ"
+msgstr "không hiểu định dạng đối tượng '%s' được chỉ định bởi máy chủ"
+
+#, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "lỗi trên dòng phản hồi bundle-uri thứ %d: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "cần đẩy dữ liệu lên đĩa sau khi liệt kê bundle-uri"
+
+msgid "expected response end packet after ref listing"
+msgstr "cần nhận được trả lá»i là kết thúc gói sau khi liệt kê tham chiếu"
#, c-format
msgid "invalid ls-refs response: %s"
@@ -14564,19 +15536,16 @@ msgstr "trả vỠcủa ls-refs không hợp lệ: %s"
msgid "expected flush after ref listing"
msgstr "cần đẩy dữ liệu lên đĩa sau khi liệt kê tham chiếu"
-msgid "expected response end packet after ref listing"
-msgstr "cần nhận được trả lá»i là kết thúc gói sau khi liệt kê tham chiếu"
-
#, c-format
msgid "protocol '%s' is not supported"
-msgstr "giao thức “%s†chưa được hỗ trợ"
+msgstr "giao thức '%s' chưa được hỗ trợ"
msgid "unable to set SO_KEEPALIVE on socket"
msgstr "không thể đặt SO_KEEPALIVE trên ổ cắm"
#, c-format
msgid "Looking up %s ... "
-msgstr "Äang tìm kiếm %s … "
+msgstr "Äang tìm kiếm %s ... "
#, c-format
msgid "unable to look up %s (port %s) (%s)"
@@ -14589,7 +15558,7 @@ msgid ""
"Connecting to %s (port %s) ... "
msgstr ""
"xong.\n"
-"Äang kết nối đến %s (cổng %s) … "
+"Äang kết nối đến %s (cổng %s) ... "
#, c-format
msgid ""
@@ -14613,221 +15582,46 @@ msgstr "không hiểu cổng %s"
#, c-format
msgid "strange hostname '%s' blocked"
-msgstr "đã khóa tên máy lạ “%sâ€"
+msgstr "đã khóa tên máy lạ '%s'"
#, c-format
msgid "strange port '%s' blocked"
-msgstr "đã khóa cổng lạ “%sâ€"
+msgstr "đã khóa cổng lạ '%s'"
#, c-format
msgid "cannot start proxy %s"
-msgstr "không thể khởi chạy á»§y nhiệm “%sâ€"
+msgstr "không thể khởi chạy ủy nhiệm '%s'"
msgid "no path specified; see 'git help pull' for valid url syntax"
-msgstr "chưa chỉ định đưá»ng dẫn; xem'git help pull†để biết cú pháp url hợp lệ"
+msgstr "chưa chỉ định đưá»ng dẫn; xem'git help pull' để biết cú pháp url hợp lệ"
msgid "newline is forbidden in git:// hosts and repo paths"
-msgstr "newline bị cấm trong các git:// máy chá»§ và đưá»ng dẫn repo"
+msgstr "ký tá»± xuống dòng bị cấm trong các git:// máy chá»§ và đưá»ng dẫn repo"
msgid "ssh variant 'simple' does not support -4"
-msgstr "ssh biến thể “simple†không hỗ trợ -4"
+msgstr "ssh biến thể 'simple' không hỗ trợ -4"
msgid "ssh variant 'simple' does not support -6"
-msgstr "ssh biến thể “simple†không hỗ trợ -6"
+msgstr "ssh biến thể 'simple' không hỗ trợ -6"
msgid "ssh variant 'simple' does not support setting port"
-msgstr "ssh biến thể “simple†không hỗ trợ đặt cổng"
+msgstr "ssh biến thể 'simple' không hỗ trợ đặt cổng"
#, c-format
msgid "strange pathname '%s' blocked"
-msgstr "đã khóa tên đưá»ng dẫn lạ “%sâ€"
+msgstr "đã khóa tên đưá»ng dẫn lạ '%s'"
msgid "unable to fork"
msgstr "không thể rẽ nhánh tiến trình con"
msgid "Could not run 'git rev-list'"
-msgstr "Không thể chạy “git rev-listâ€"
+msgstr "Không thể chạy 'git rev-list'"
msgid "failed write to rev-list"
msgstr "gặp lỗi khi ghi vào rev-list"
msgid "failed to close rev-list's stdin"
-msgstr "gặp lỗi khi đóng đầu vào chuẩn stdin của rev-list"
-
-#, c-format
-msgid "'%s' does not exist"
-msgstr "\"%s\" không tồn tại"
-
-msgid "need a working directory"
-msgstr "cần một thư mục làm việc"
-
-msgid "could not find enlistment root"
-msgstr "không tìm thấy gốc enlistment"
-
-#, c-format
-msgid "could not switch to '%s'"
-msgstr "không thể chuyển đến '%s'"
-
-#, c-format
-msgid "could not configure %s=%s"
-msgstr "không thể đóng cấu hình %s=%s"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "không thể cấu hình log.excludeDecoration"
-
-msgid "Scalar enlistments require a worktree"
-msgstr "'Scalar enlistments' cần một cây làm việc"
-
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "không thể mở thư mục “%sâ€"
-
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr ""
-"Ä‘ang bá» qua “%sâ€, cái không phải là má»™t tập tin, cÅ©ng không phải thư mục"
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "không thể dò tìm chá»— trống trên đĩa cho “%sâ€"
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "không thể lấy thông tin cho “%sâ€"
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "HEAD của máy chủ không phải một nhánh: '%.*s'"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr "gặp lỗi khi lấy tên nhánh mặc định từ máy chủ; sử dụng mặc định nội bộ"
-
-msgid "failed to get default branch name"
-msgstr "gặp lỗi khi lấy tên nhánh mặc định"
-
-msgid "failed to unregister repository"
-msgstr "gặp lỗi khi hủy đăng ký kho chứa"
-
-msgid "failed to delete enlistment directory"
-msgstr "gặp lỗi khi xóa thư mục dành được"
-
-msgid "branch to checkout after clone"
-msgstr "nhánh để lấy ra sau khi nhân bản"
-
-msgid "when cloning, create full working directory"
-msgstr "khi nhân bản, tạo đầy đủ thư mục làm việc"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "chỉ siêu dữ liệu tải vỠcho nhánh mà sẽ được lấy ra"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<các tùy chá»n>] [--] <kho> [<t.mục>]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "không thể suy diễn tên cây làm việc từ '%s'"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "thư mục '%s' đã sẵn có"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "gặp lỗi khi lấy nhánh mặc định cho '%s'"
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "không thể cấu hình máy chủ trong '%s'"
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "không thể cấu hình '%s'"
-
-msgid "partial clone failed; attempting full clone"
-msgstr "nhân bản từng phần gặp lỗi; đang cố thử nhân bản đầy đủ"
-
-msgid "could not configure for full clone"
-msgstr "không thể cấu hình cho nhân bản đầy đủ"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<enlistment>]"
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "không thể tạo thư mục cho “%sâ€"
-
-msgid "could not duplicate stdout"
-msgstr "không thể nhân đôi đầu vào tiêu chuẩn"
-
-msgid "failed to write archive"
-msgstr "gặp lỗi khi khi kho nén"
-
-msgid "`scalar list` does not take arguments"
-msgstr "`scalar list` không nhận các tham số"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<enlistment>]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "cấu hình má»i enlistments đã đăng ký"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <enlistment>]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "--all hoặc <enlistment>, không thể là cả hai"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "kho git ra đi trong '%s'"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <task> [<enlistment>]\n"
-"Nhiệm vụ:\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "không có nhiệm vụ nào như thế: “%sâ€"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<enlistment>]"
-
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <enlistment>"
-
-msgid "refusing to delete current working directory"
-msgstr "từ chối gỡ bỠthư mục làm việc hiện tại"
-
-msgid "include Git version"
-msgstr "bao gồm phiên bản Git"
-
-msgid "include Git's build options"
-msgstr "bao gồm các tùy chá»n biên dịch cá»§a Git"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "-C cần một <thư_mục>"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "không thể chuyển sang “%sâ€"
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c cần một tham số <key>=<value>"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C </thư/mục/>] [-c <khóa>=<giá trị>] <lệnh> [<các tùy chá»n>]\n"
-"\n"
-"Các lệnh:\n"
+msgstr "gặp lỗi khi đóng stdin của rev-list"
#, c-format
msgid "illegal crlf_action %d"
@@ -14859,55 +15653,55 @@ msgstr ""
#, c-format
msgid "BOM is prohibited in '%s' if encoded as %s"
-msgstr "BOM bị cấm trong “%s†nếu được mã hóa là %s"
+msgstr "BOM bị cấm trong '%s' nếu được mã hóa là %s"
#, c-format
msgid ""
"The file '%s' contains a byte order mark (BOM). Please use UTF-%.*s as "
"working-tree-encoding."
msgstr ""
-"Tập tin “%s†có chứa ký hiệu thứ tự byte (BOM). Vui lòng dùng UTF-%.*s như "
+"Tập tin '%s' có chứa ký hiệu thứ tự byte (BOM). Vui lòng dùng UTF-%.*s như "
"là bảng mã cây làm việc."
#, c-format
msgid "BOM is required in '%s' if encoded as %s"
-msgstr "BOM là bắt buộc trong “%s†nếu được mã hóa là %s"
+msgstr "BOM là bắt buộc trong '%s' nếu được mã hóa là %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 ""
-"Tập tin “%s†còn thiếu ký hiệu thứ tự byte (BOM). Vui lòng dùng UTF-%sBE hay "
+"Tập tin '%s' còn thiếu ký hiệu thứ tự byte (BOM). Vui lòng dùng UTF-%sBE hay "
"UTF-%sLE (còn phục thuộc vào thứ tự byte) như là bảng mã cây làm việc."
#, c-format
msgid "failed to encode '%s' from %s to %s"
-msgstr "gặp lá»—i khi mã hóa “%s†từ “%s†sang “%sâ€"
+msgstr "gặp lỗi khi mã hóa '%s' từ '%s' sang '%s'"
#, c-format
msgid "encoding '%s' from %s to %s and back is not the same"
-msgstr "mã hóa “%s†từ %s thành %s và ngược trở lại không phải là cùng"
+msgstr "mã hóa '%s' từ %s thành %s và ngược trở lại không phải là cùng"
#, c-format
msgid "cannot fork to run external filter '%s'"
-msgstr "không thể rẽ nhánh tiến trình để chạy bá»™ lá»c bên ngoài “%sâ€"
+msgstr "không thể rẽ nhánh tiến trình để chạy bá»™ lá»c bên ngoài '%s'"
#, c-format
msgid "cannot feed the input to external filter '%s'"
-msgstr "không thể cấp đầu vào cho bá»™ lá»c bên ngoài “%sâ€"
+msgstr "không thể cấp đầu vào cho bá»™ lá»c bên ngoài '%s'"
#, c-format
msgid "external filter '%s' failed %d"
-msgstr "chạy bá»™ lá»c bên ngoài “%s†gặp lá»—i %d"
+msgstr "chạy bá»™ lá»c bên ngoài '%s' gặp lá»—i %d"
#, c-format
msgid "read from external filter '%s' failed"
-msgstr "Ä‘á»c từ bá»™ lá»c bên ngoài “%s†gặp lá»—i"
+msgstr "Ä‘á»c từ bá»™ lá»c bên ngoài '%s' gặp lá»—i"
#, c-format
msgid "external filter '%s' failed"
-msgstr "gặp lá»—i khi chạy bá»™ lá»c bên ngoài “%sâ€"
+msgstr "gặp lá»—i khi chạy bá»™ lá»c bên ngoài '%s'"
msgid "unexpected filter type"
msgstr "gặp kiểu bá»™ lá»c thừa"
@@ -14920,23 +15714,23 @@ msgid ""
"external filter '%s' is not available anymore although not all paths have "
"been filtered"
msgstr ""
-"bá»™ lá»c bên ngoài “%s†không sẵn sàng nữa mặc dù không phải tất cả các đưá»ng "
-"dẫn đã được lá»c"
+"bá»™ lá»c ngoài '%s' không còn nữa mặc dù không phải tất cả các đưá»ng dẫn đã "
+"được lá»c"
msgid "true/false are no valid working-tree-encodings"
-msgstr "true/false là không phải bảng-mã-cây-làm-việc hợp lệ"
+msgstr "true/false không phải là bảng mã cây làm việc hợp lệ"
#, c-format
msgid "%s: clean filter '%s' failed"
-msgstr "%s: gặp lá»—i khi xóa bá»™ lá»c “%sâ€"
+msgstr "%s: bá»™ lá»c clean '%s' gặp lá»—i"
#, c-format
msgid "%s: smudge filter %s failed"
-msgstr "%s: smudge bá»™ lá»c %s gặp lá»—i"
+msgstr "%s: bá»™ lá»c smudge %s gặp lá»—i"
#, c-format
msgid "skipping credential lookup for key: credential.%s"
-msgstr "bỠqua tìm kiếm giấy chứng chực cho khóa: credential.%s"
+msgstr "bỠqua tìm kiếm giấy chứng thực cho khóa: credential.%s"
msgid "refusing to work with credential missing host field"
msgstr "từ chối làm việc vá»›i giấy chứng thá»±c thiếu trưá»ng máy chá»§"
@@ -14954,10 +15748,10 @@ msgstr "url không có lược đồ: %s"
#, c-format
msgid "credential url cannot be parsed: %s"
-msgstr "không thể phân tích cú pháp giấy chứng thực url: %s"
+msgstr "không hiểu cú pháp giấy chứng thực url: %s"
msgid "in the future"
-msgstr "ở thá»i tương lai"
+msgstr "ở tương lai"
#, c-format
msgid "%<PRIuMAX> second ago"
@@ -15010,35 +15804,64 @@ msgstr "Äang lan truyá»n các đánh dấu island"
#, c-format
msgid "bad tree object %s"
-msgstr "đối tượng cây sai “%sâ€"
+msgstr "đối tượng cây sai '%s'"
#, c-format
msgid "failed to load island regex for '%s': %s"
-msgstr "gặp lá»—i khi tải biểu thức chính quy island cho “%sâ€: %s"
+msgstr "gặp lỗi khi tải biểu thức chính quy island cho '%s': %s"
#, c-format
msgid "island regex from config has too many capture groups (max=%d)"
msgstr ""
-"biểu thức chính quy island từ cấu hình có quá nhiá»u nhóm chụp (tối Ä‘a=%d)"
+"biểu thức chính quy island từ cấu hình có quá nhiá»u nhóm chá»n (tối Ä‘a=%d)"
#, c-format
msgid "Marked %d islands, done.\n"
msgstr "Äã đánh dấu %d island, xong.\n"
-msgid "--merge-base does not work with ranges"
-msgstr "--merge-base không hoạt động với phạm vi"
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "giá trị --%s không hợp lệ: '%s'"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "không thể nén thư mục '%s' không còn tồn tại"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "không thể mở thư mục '%s'"
-msgid "--merge-base only works with commits"
-msgstr "--merge-base chỉ hoạt động với các lần chuyển giao"
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "đang bỠqua '%s', không phải là một tập tin hay thư mục"
+
+msgid "could not duplicate stdout"
+msgstr "không thể nhân bản stdout"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "không thể thêm thư mục '%s' vào kho nén"
+
+msgid "failed to write archive"
+msgstr "gặp lỗi khi ghi kho nén"
+
+msgid "--merge-base does not work with ranges"
+msgstr "--merge-base không thể dùng với chỉ vùng"
msgid "unable to get HEAD"
msgstr "không thể lấy HEAD"
msgid "no merge base found"
-msgstr "không tìm thấy cơ sở để hòa trộn"
+msgstr "không tìm thấy gốc hòa trộn"
msgid "multiple merge bases found"
-msgstr "có nhiá»u cÆ¡ sở để hòa trá»™n"
+msgstr "có nhiá»u hÆ¡n má»™t gốc hòa trá»™n"
+
+msgid "cannot compare stdin to a directory"
+msgstr "không thể so sánh stdin và thư mục"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "không thể so sánh pipe có tên và thư mục"
msgid "git diff --no-index [<options>] <path> <path>"
msgstr "git diff --no-index [<các tùy chá»n>] </đưá»ng/dẫn> </đưá»ng/dẫn>"
@@ -15048,54 +15871,65 @@ msgid ""
"tree"
msgstr ""
"Không phải là má»™t thư mục git. Dùng --no-index để so sánh hai đưá»ng dẫn bên "
-"ngoài một cây làm việc"
+"ngoài cây làm việc"
#, c-format
msgid " Failed to parse dirstat cut-off percentage '%s'\n"
-msgstr " Gặp lá»—i khi phân tích dirstat cắt bá» phần trăm “%sâ€\n"
+msgstr " Gặp lá»—i khi Ä‘á»c phần trăm cắt bá» dirstat '%s'\n"
#, c-format
msgid " Unknown dirstat parameter '%s'\n"
-msgstr " Không hiểu đối số dirstat “%sâ€\n"
+msgstr " Không hiểu đối số dirstat '%s'\n"
msgid ""
"color moved setting must be one of 'no', 'default', 'blocks', 'zebra', "
"'dimmed-zebra', 'plain'"
msgstr ""
-"cài đặt màu đã di chuyển phải là má»™t trong “noâ€, “defaultâ€, “blocksâ€, "
-"“zebraâ€, “dimmed-zebraâ€, “plainâ€"
+"cài đặt color moved phải là một trong '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 ""
-"không hiểu chế độ color-moved-ws “%sâ€, các giá trị có thể là “ignore-space-"
-"changeâ€, “ignore-space-at-eolâ€, “ignore-all-spaceâ€, “allow-indentation-"
-"changeâ€"
+"không hiểu chế độ color-moved-ws '%s', các giá trị có thể là '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 không thể tổ hợp cùng với các chế "
+"color-moved-ws: allow-indentation-change không thể kết hợp cùng với các chế "
"độ khoảng trắng khác"
#, c-format
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
-msgstr "Không hiểu giá trị cho biến cấu hình “diff.submoduleâ€: “%sâ€"
+msgstr "Không hiểu giá trị cho biến cấu hình 'diff.submodule': '%s'"
+
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "không hiểu giá trị cho cho cấu hình '%s': %s"
#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
msgstr ""
-"Tìm thấy các lá»—i trong biến cấu hình “diff.dirstatâ€:\n"
+"Tìm thấy các lỗi trong biến cấu hình 'diff.dirstat':\n"
"%s"
#, c-format
msgid "external diff died, stopping at %s"
-msgstr "phần má»m diff ở bên ngoài đã chết, dừng tại %s"
+msgstr "phần má»m diff ở bên ngoài đã thoát, dừng tại %s"
+
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow cần đúng má»™t đặc tả đưá»ng dẫn"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "đặc tả đưá»ng dẫn đặc biệt chưa được há»— trợ bởi --follow: %s"
#, c-format
msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
@@ -15111,28 +15945,25 @@ msgid ""
msgstr ""
"tùy chá»n '%s' và '%s' không thể dùng cùng nhau, dùng '%s' vá»›i '%s' và '%s'"
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow cần chính xác má»™t đặc tả đưá»ng dẫn"
-
#, c-format
msgid "invalid --stat value: %s"
-msgstr "giá trị --stat không hợp lệ: “%sâ€"
+msgstr "giá trị --stat không hợp lệ: '%s'"
#, c-format
msgid "%s expects a numerical value"
-msgstr "tùy chá»n “%s†cần má»™t giá trị bằng số"
+msgstr "tùy chá»n '%s' cần má»™t giá trị số"
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
"%s"
msgstr ""
-"Gặp lá»—i khi phân tích đối số tùy chá»n --dirstat/-X:\n"
+"Gặp lá»—i khi Ä‘á»c đối số tùy chá»n --dirstat/-X:\n"
"%s"
#, c-format
msgid "unknown change class '%c' in --diff-filter=%s"
-msgstr "không hiểu lớp thay đổi “%c†trong --diff-filter=%s"
+msgstr "không hiểu change class '%c' trong --diff-filter=%s"
#, c-format
msgid "unknown value after ws-error-highlight=%.*s"
@@ -15140,7 +15971,7 @@ msgstr "không hiểu giá trị sau ws-error-highlight=%.*s"
#, c-format
msgid "unable to resolve '%s'"
-msgstr "không thể phân giải “%sâ€"
+msgstr "không thể phân giải '%s'"
#, c-format
msgid "%s expects <n>/<m> form"
@@ -15148,7 +15979,7 @@ msgstr "%s cần dạng <n>/<m>"
#, c-format
msgid "%s expects a character, got '%s'"
-msgstr "%s cần má»™t ký tá»±, nhưng lại nhận được “%sâ€"
+msgstr "%s cần một ký tự, nhưng lại có '%s'"
#, c-format
msgid "bad --color-moved argument: %s"
@@ -15156,14 +15987,7 @@ msgstr "đối số --color-moved sai: %s"
#, c-format
msgid "invalid mode '%s' in --color-moved-ws"
-msgstr "chế độ “%s†không hợp lệ trong --color-moved-ws"
-
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"tùy chá»n diff-algorithm chấp nhận \"myers\", \"minimal\", \"patience\" và "
-"\"histogram\""
+msgstr "chế độ '%s' không hợp lệ trong --color-moved-ws"
#, c-format
msgid "invalid argument to %s"
@@ -15171,21 +15995,21 @@ msgstr "tham số cho %s không hợp lệ"
#, c-format
msgid "invalid regex given to -I: '%s'"
-msgstr "đưa cho -I biểu thức chính quy không hợp lệ: “%sâ€"
+msgstr "đưa cho -I biểu thức chính quy không hợp lệ: '%s'"
#, c-format
msgid "failed to parse --submodule option parameter: '%s'"
-msgstr "gặp lá»—i khi phân tích đối số tùy chá»n --submodule: “%sâ€"
+msgstr "gặp lá»—i khi Ä‘á»c đối số tùy chá»n --submodule: '%s'"
#, c-format
msgid "bad --word-diff argument: %s"
msgstr "đối số --word-diff sai: %s"
msgid "Diff output format options"
-msgstr "Các tùy chá»n định dạng khi xuất các khác biệt"
+msgstr "Các tùy chá»n định dạng kết quả khác biệt"
msgid "generate patch"
-msgstr "tạo miếng vá"
+msgstr "tạo bản vá"
msgid "<n>"
msgstr "<n>"
@@ -15197,29 +16021,29 @@ msgid "generate the diff in raw format"
msgstr "tạo khác biệt ở định dạng thô"
msgid "synonym for '-p --raw'"
-msgstr "đồng nghÄ©a vá»›i “-p --rawâ€"
+msgstr "đồng nghĩa với '-p --raw'"
msgid "synonym for '-p --stat'"
-msgstr "đồng nghÄ©a vá»›i “-p --statâ€"
+msgstr "đồng nghĩa với '-p --stat'"
msgid "machine friendly --stat"
msgstr "--stat thuận tiện cho máy Ä‘á»c"
msgid "output only the last line of --stat"
-msgstr "chỉ xuất những dòng cuối của --stat"
+msgstr "chỉ in ra những dòng cuối của --stat"
-msgid "<param1,param2>..."
-msgstr "<tham_số_1,tham_số_2>…"
+msgid "<param1>,<param2>..."
+msgstr "<tham_số_1>,<tham_số_2>..."
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
-msgstr "đầu ra phân phối của số lượng thay đổi tương đối cho mỗi thư mục con"
+msgstr "in ra phân phối số lượng thay đổi tương đối cho mỗi thư mục con"
msgid "synonym for --dirstat=cumulative"
msgstr "đồng nghĩa với --dirstat=cumulative"
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "đồng nghĩa với --dirstat=files,param1,param2…"
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "đồng nghĩa với --dirstat=files,<tham_số_1>,<tham_số_2>..."
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
@@ -15262,12 +16086,12 @@ msgid "generate compact summary in diffstat"
msgstr "tạo tổng hợp xúc tích trong diffstat"
msgid "output a binary diff that can be applied"
-msgstr "xuất ra một khác biệt dạng nhị phân cái mà có thể được áp dụng"
+msgstr "in ra một khác biệt dạng nhị phân có thể được áp dụng"
msgid "show full pre- and post-image object names on the \"index\" lines"
msgstr ""
-"hiển thị đầy đủ các tên đối tượng pre- và post-image trên các dòng \"mục lục"
-"\""
+"hiển thị đầy đủ các tên đối tượng pre- và post-image trên các dòng \"mục "
+"lục\""
msgid "show colored diff"
msgstr "hiển thị thay đổi được tô màu"
@@ -15279,7 +16103,7 @@ msgid ""
"highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
"diff"
msgstr ""
-"tô sáng các lá»—i vá» khoảng trắng trong các dòng “contextâ€, “old†và “new†"
+"tô sáng các lỗi vỠkhoảng trắng trong các dòng 'context', 'old' và 'new' "
"trong khác biệt"
msgid ""
@@ -15290,7 +16114,7 @@ msgstr ""
"trong --raw hay --numstat"
msgid "<prefix>"
-msgstr "<tiá»n_tố>"
+msgstr "<tiá»n tố>"
msgid "show the given source prefix instead of \"a/\""
msgstr "hiển thị tiá»n tố nguồn đã cho thay cho \"a/\""
@@ -15299,11 +16123,14 @@ msgid "show the given destination prefix instead of \"b/\""
msgstr "hiển thị tiá»n tố đích đã cho thay cho \"b/\""
msgid "prepend an additional prefix to every line of output"
-msgstr "treo vào trước má»™t tiá»n tố bổ sung cho má»—i dòng kết xuất"
+msgstr "thêm vào trước má»™t tiá»n tố bổ sung cho má»—i dòng đầu ra"
msgid "do not show any source or destination prefix"
msgstr "đừng hiển thị bất kỳ tiá»n tố nguồn hay đích"
+msgid "use default prefixes a/ and b/"
+msgstr "dùng tiá»n tố mặc định a/ và b/"
+
msgid "show context between diff hunks up to the specified number of lines"
msgstr ""
"hiển thị ngữ cảnh giữa các khúc khác biệt khi đạt đến số lượng dòng đã chỉ "
@@ -15313,13 +16140,13 @@ msgid "<char>"
msgstr "<ký_tự>"
msgid "specify the character to indicate a new line instead of '+'"
-msgstr "chỉ định má»™t ký tá»± để biểu thị má»™t dòng được thêm má»›i thay cho “+â€"
+msgstr "chỉ định một ký tự để biểu thị một dòng được thêm mới thay cho '+'"
msgid "specify the character to indicate an old line instead of '-'"
-msgstr "chỉ định má»™t ký tá»± để biểu thị má»™t dòng đã cÅ© thay cho “-â€"
+msgstr "chỉ định một ký tự để biểu thị một dòng đã cũ thay cho '-'"
msgid "specify the character to indicate a context instead of ' '"
-msgstr "chỉ định má»™t ký tá»± để biểu thị má»™t ngữ cảnh thay cho “â€"
+msgstr "chỉ định một ký tự để biểu thị một ngữ cảnh thay cho ''"
msgid "Diff rename options"
msgstr "Tùy chá»n khác biệt đổi tên"
@@ -15365,13 +16192,13 @@ msgid "produce the smallest possible diff"
msgstr "sản sinh khác biệt ít nhất có thể"
msgid "ignore whitespace when comparing lines"
-msgstr "lỠđi sự thay đổi do khoảng trắng gây ra khi so sánh các dòng"
+msgstr "bỠqua sự thay đổi do khoảng trắng gây ra khi so sánh các dòng"
msgid "ignore changes in amount of whitespace"
-msgstr "lỠđi sự thay đổi do số lượng khoảng trắng gây ra"
+msgstr "bỠqua sự thay đổi do số lượng khoảng trắng gây ra"
msgid "ignore changes in whitespace at EOL"
-msgstr "lỠđi sự thay đổi do khoảng trắng gây ra khi ở cuối dòng EOL"
+msgstr "bỠqua sự thay đổi do khoảng trắng gây ra khi ở cuối dòng EOL"
msgid "ignore carrier-return at the end of line"
msgstr "bỠqua ký tự vỠđầu dòng tại cuối dòng"
@@ -15394,12 +16221,6 @@ msgstr "tạo khác biệt sử dung thuật toán \"patience diff\""
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "tạo khác biệt sử dung thuật toán \"histogram diff\""
-msgid "<algorithm>"
-msgstr "<thuật toán>"
-
-msgid "choose a diff algorithm"
-msgstr "chá»n má»™t thuật toán khác biệt"
-
msgid "<text>"
msgstr "<văn bản>"
@@ -15443,10 +16264,10 @@ msgid "exit with 1 if there were differences, 0 otherwise"
msgstr "thoát với mã 1 nếu không có khác biệt gì, 0 nếu ngược lại"
msgid "disable all output of the program"
-msgstr "tắt má»i kết xuất cá»§a chương trình"
+msgstr "tắt má»i đầu ra cá»§a chương trình"
msgid "allow an external diff helper to be executed"
-msgstr "cho phép mộ bộ hỗ trợ xuất khác biệt ở bên ngoài được phép thực thi"
+msgstr "cho phép mộ helper xuất khác biệt ở bên ngoài được phép thực thi"
msgid "run external text conversion filters when comparing binary files"
msgstr ""
@@ -15466,10 +16287,10 @@ msgid "specify how differences in submodules are shown"
msgstr "chi định khác biệt bao nhiêu trong các mô đun con được hiển thị"
msgid "hide 'git add -N' entries from the index"
-msgstr "ẩn các mục “git add -N†từ bảng mục lục"
+msgstr "ẩn các mục 'git add -N' từ chỉ mục"
msgid "treat 'git add -N' entries as real in the index"
-msgstr "coi các mục “git add -N†như là có thật trong bảng mục lục"
+msgstr "coi các mục 'git add -N' như là có thật trong chỉ mục"
msgid "<string>"
msgstr "<chuá»—i>"
@@ -15492,19 +16313,19 @@ msgid "show all changes in the changeset with -S or -G"
msgstr "hiển thị tất cả các thay đổi trong một bộ các thay đổi với -S hay -G"
msgid "treat <string> in -S as extended POSIX regular expression"
-msgstr "coi <chuỗi> trong -S như là biểu thức chính qui POSIX có mở rộng"
+msgstr "coi <chuỗi> trong -S là biểu thức chính quy POSIX mở rộng"
msgid "control the order in which files appear in the output"
-msgstr "Ä‘iá»u khiển thứ tá»± xuát hiện các tập tin trong kết xuất"
+msgstr "Ä‘iá»u khiển thứ tá»± xuất hiện các tập tin trong kết quả"
msgid "<path>"
msgstr "<đưá»ng-dẫn>"
msgid "show the change in the specified path first"
-msgstr "hiển thị các thay đổi trong đưá»ng dẫn đã cho đầu tiên"
+msgstr "hiển thị các thay đổi trong đưá»ng dẫn đã cho ở đầu"
msgid "skip the output to the specified path"
-msgstr "bá» qua đầu ra đến đưá»ng dẫn đã cho"
+msgstr "bá» qua kết quả vá»›i đưá»ng dẫn đã cho"
msgid "<object-id>"
msgstr "<mã-số-đối-tượng>"
@@ -15512,42 +16333,38 @@ msgstr "<mã-số-đối-tượng>"
msgid ""
"look for differences that change the number of occurrences of the specified "
"object"
-msgstr ""
-"tìm các khác biệt cái mà thay đổi số lượng xảy ra của các phát sinh của đối "
-"tượng được chỉ ra"
+msgstr "tìm các diff có thay đổi số lượng xuất hiện của đối tượng"
msgid "[(A|C|D|M|R|T|U|X|B)...[*]]"
-msgstr "[(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 "chá»n các tập tin theo kiểu khác biệt"
msgid "<file>"
-msgstr "<tập_tin>"
+msgstr "<tập tin>"
msgid "output to a specific file"
-msgstr "xuất ra một tập tin cụ thể"
+msgstr "xuất ra tập tin này"
msgid "exhaustive rename detection was skipped due to too many files."
-msgstr "nhận thấy đổi tên toàn diện đã bị bá» qua bởi có quá nhiá»u tập tin."
+msgstr "bá» tìm tất cả các lần đổi tên vì có quá nhiá»u tập tin."
msgid "only found copies from modified paths due to too many files."
msgstr ""
-"chỉ tìm thấy các bản sao từ đưá»ng dẫn đã sá»­a đổi bởi vì có quá nhiá»u tập tin."
+"chỉ tìm các lần sao chép từ đưá»ng dẫn đã sá»­a đổi vì có quá nhiá»u tập tin."
#, c-format
msgid ""
"you may want to set your %s variable to at least %d and retry the command."
-msgstr ""
-"bạn có lẽ muốn đặt biến %s của bạn thành ít nhất là %d và thử lại lệnh lần "
-"nữa."
+msgstr "bạn có lẽ muốn đặt biến %s của bạn thành ít nhất là %d và thử lại."
#, c-format
msgid "failed to read orderfile '%s'"
-msgstr "gặp lá»—i khi Ä‘á»c tập-tin-thứ-tá»± “%sâ€"
+msgstr "gặp lá»—i khi Ä‘á»c orderfile '%s'"
msgid "Performing inexact rename detection"
-msgstr "Äang thá»±c hiện dò tìm đổi tên không chính xác"
+msgstr "Äang thá»±c hiện inexact rename detection (tìm sÆ¡ bá»™ các lần đổi tên)"
#, c-format
msgid "No such path '%s' in the diff"
@@ -15555,43 +16372,43 @@ msgstr "Không có đưá»ng dẫn %s trong diff"
#, c-format
msgid "pathspec '%s' did not match any file(s) known to git"
-msgstr "đặc tả đưá»ng dẫn “%s†không khá»›p vá»›i bất kỳ tập tin nào mà git biết"
+msgstr "đặc tả đưá»ng dẫn '%s' không khá»›p vá»›i bất kỳ tập tin nào mà git biết"
#, c-format
msgid "unrecognized pattern: '%s'"
-msgstr "mẫu không được thừa nhận: “%sâ€"
+msgstr "không hiểu mẫu: '%s'"
#, c-format
msgid "unrecognized negative pattern: '%s'"
-msgstr "mẫu âm không được thừa nhận: “%sâ€"
+msgstr "không hiểu mẫu loại trừ: '%s'"
#, c-format
msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
-msgstr "tập tin sparse-checkout của bạn có lẽ gặp lỗi: mẫu “%s†đã bị lặp lại"
+msgstr "tập tin sparse-checkout của bạn có lẽ gặp lỗi: mẫu '%s' đã bị lặp lại"
msgid "disabling cone pattern matching"
-msgstr "vô hiệu khớp mẫu nón"
+msgstr "vô hiệu cone pattern matching (khớp mẫu nón)"
#, c-format
msgid "cannot use %s as an exclude file"
-msgstr "không thể dùng %s như là một tập tin loại trừ"
+msgstr "không thể dùng %s như là tập tin loại trừ"
msgid "failed to get kernel name and information"
-msgstr "gặp lỗi khi lấy tên và thông tin của nhân"
+msgstr "gặp lỗi khi lấy tên và thông tin của kernel"
msgid "untracked cache is disabled on this system or location"
-msgstr "bộ nhớ tạm không theo vết bị tắt trên hệ thống hay vị trí này"
+msgstr "bộ nhớ tạm không theo vết bị vô hiệu trên hệ thống hay vị trí này"
msgid ""
"No directory name could be guessed.\n"
"Please specify a directory on the command line"
msgstr ""
"Không đoán được thư mục tên là gì.\n"
-"Vui lòng chỉ định tên một thư mục trên dòng lệnh"
+"Vui lòng chỉ định tên thư mục trên dòng lệnh"
#, c-format
msgid "index file corrupt in repo %s"
-msgstr "tập tin ghi bảng mục lục bị há»ng trong kho %s"
+msgstr "tập tin ghi chỉ mục bị há»ng trong kho %s"
#, c-format
msgid "could not create directories for %s"
@@ -15599,18 +16416,26 @@ msgstr "không thể tạo thư mục cho %s"
#, c-format
msgid "could not migrate git directory from '%s' to '%s'"
-msgstr "không thể di dá»i thư mục git từ “%s†sang “%sâ€"
+msgstr "không thể di dá»i thư mục git từ '%s' sang '%s'"
#, c-format
msgid "hint: Waiting for your editor to close the file...%c"
-msgstr "gợi ý: ChỠtrình biên soạn của bạn đóng tập tin…%c"
+msgstr "gợi ý: ChỠtrình biên soạn của bạn đóng tập tin...%c"
+
+#, c-format
+msgid "could not write to '%s'"
+msgstr "không thể ghi vào '%s'"
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr "không thể sửa '%s'"
msgid "Filtering content"
msgstr "Ná»™i dung lá»c"
#, c-format
msgid "could not stat file '%s'"
-msgstr "không thể lấy thống kê tập tin “%sâ€"
+msgstr "không thể lấy thống kê tập tin '%s'"
#, c-format
msgid "bad git namespace path \"%s\""
@@ -15624,17 +16449,20 @@ msgid "git fetch-pack: expected shallow list"
msgstr "git fetch-pack: cần danh sách shallow"
msgid "git fetch-pack: expected a flush packet after shallow list"
-msgstr "git fetch-pack: cần một gói đẩy sau danh sách shallow"
+msgstr "git fetch-pack: cần một gói flush sau danh sách shallow"
msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
msgstr "git fetch-pack: cần ACK/NAK, nhưng lại nhận được một gói flush"
#, c-format
msgid "git fetch-pack: expected ACK/NAK, got '%s'"
-msgstr "git fetch-pack: cần ACK/NAK, nhưng lại nhận được “%sâ€"
+msgstr "git fetch-pack: cần ACK/NAK, nhưng lại nhận được '%s'"
msgid "unable to write to remote"
-msgstr "không thể ghi lên máy phục vụ"
+msgstr "không thể ghi lên máy chủ"
+
+msgid "Server supports filter"
+msgstr "Máy chá»§ há»— trợ bá»™ lá»c"
#, c-format
msgid "invalid shallow line: %s"
@@ -15658,7 +16486,7 @@ msgstr "không tìm shallow nào: %s"
#, c-format
msgid "expected shallow/unshallow, got %s"
-msgstr "cần shallow/unshallow, nhưng lại nhận được %s"
+msgstr "cần shallow/unshallow, nhưng lại có %s"
#, c-format
msgid "got %s %d %s"
@@ -15697,7 +16525,7 @@ msgid "fetch-pack: unable to fork off %s"
msgstr "fetch-pack: không thể rẽ nhánh %s"
msgid "fetch-pack: invalid index-pack output"
-msgstr "fetch-pack: kết xuất index-pack không hợp lệ"
+msgstr "fetch-pack: đầu ra index-pack không hợp lệ"
#, c-format
msgid "%s failed"
@@ -15741,28 +16569,25 @@ msgstr "các thuật toán không khớp nhau: máy khách %s; máy chủ %s"
#, c-format
msgid "the server does not support algorithm '%s'"
-msgstr "máy chá»§ không há»— trợ thuật toán “%sâ€"
+msgstr "máy chủ không hỗ trợ thuật toán '%s'"
msgid "Server does not support shallow requests"
msgstr "Máy chủ không hỗ trợ yêu cầu shallow"
-msgid "Server supports filter"
-msgstr "Máy chá»§ há»— trợ bá»™ lá»c"
-
msgid "unable to write request to remote"
-msgstr "không thể ghi các yêu cầu lên máy phục vụ"
+msgstr "không thể ghi các yêu cầu lên máy chủ"
#, c-format
msgid "expected '%s', received '%s'"
-msgstr "cần “%sâ€, nhưng lại nhận “%sâ€"
+msgstr "cần '%s', nhưng lại nhận '%s'"
#, c-format
msgid "expected '%s'"
-msgstr "cần “%sâ€"
+msgstr "cần '%s'"
#, c-format
msgid "unexpected acknowledgment line: '%s'"
-msgstr "gặp dòng không được thừa nhận: “%sâ€"
+msgstr "gặp dòng không được thừa nhận: '%s'"
#, c-format
msgid "error processing acks: %d"
@@ -15773,14 +16598,14 @@ msgstr "gặp lá»—i khi xá»­ lý tín hiệu trả lá»i: %d"
#.
#, c-format
msgid "expected packfile to be sent after '%s'"
-msgstr "cần tập tin gói để gá»­i sau “%sâ€"
+msgstr "cần tập tin gói để gửi sau '%s'"
#. TRANSLATORS: The parameter will be 'ready', a protocol
#. keyword.
#.
#, c-format
msgid "expected no other sections to be sent after no '%s'"
-msgstr "không cần thêm phần nào để gá»­i sau không “%sâ€"
+msgstr "không có phần nào để gửi khi không có '%s'"
#, c-format
msgid "error processing shallow info: %d"
@@ -15788,11 +16613,11 @@ msgstr "lỗi xử lý thông tin shallow: %d"
#, c-format
msgid "expected wanted-ref, got '%s'"
-msgstr "cần wanted-ref, nhưng lại nhận được “%sâ€"
+msgstr "cần wanted-ref, nhưng lại nhận được '%s'"
#, c-format
msgid "unexpected wanted-ref: '%s'"
-msgstr "wanted-ref không được mong đợi: “%sâ€"
+msgstr "wanted-ref không được mong đợi: '%s'"
#, c-format
msgid "error processing wanted refs: %d"
@@ -15805,7 +16630,7 @@ msgid "no matching remote head"
msgstr "không khớp phần đầu máy chủ"
msgid "unexpected 'ready' from remote"
-msgstr "gặp “ready†đột xuất từ máy chủ"
+msgstr "gặp 'ready' đột xuất từ máy chủ"
#, c-format
msgid "no such remote ref %s"
@@ -15813,8 +16638,7 @@ msgstr "không có máy chủ tham chiếu nào như %s"
#, c-format
msgid "Server does not allow request for unadvertised object %s"
-msgstr ""
-"Máy phục vụ không cho phép yêu cầu cho đối tượng không được báo trước %s"
+msgstr "máy chủ không cho phép yêu cầu cho đối tượng không được báo trước %s"
#, c-format
msgid "fsmonitor_ipc__send_query: invalid path '%s'"
@@ -15833,7 +16657,7 @@ msgstr "không thể gửi lệnh '%s' đến fsmonitor--daemon"
#, c-format
msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr "kho thuần '%s' là không tương thích với fsmonitor"
+msgstr "kho bare '%s' là không tương thích với fsmonitor"
#, c-format
msgid "repository '%s' is incompatible with fsmonitor due to errors"
@@ -15849,26 +16673,31 @@ msgstr "kho ảo '%s' là không tương thích với fsmonitor"
#, c-format
msgid ""
-"repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"
-msgstr "kho '%s' là không tương thích với fsmonitor bởi vì thiếu Unix sockets"
+"socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
+"sockets support"
+msgstr ""
+"thư mục socket '%s' không tương thích với fsmonitor bởi vì thiếu hỗ trợ Unix "
+"socket"
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"
-" [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
" <command> [<args>]"
msgstr ""
-"git [--version] [-h | --help] [-C </đưá»ng/dẫn/>] [-c <tên>=<giá trị>]\n"
+"git [-v | --version] [-h | --help] [-C </đưá»ng/dẫn/>] [-c <tên>=<giá trị>]\n"
" [--exec-path[=</đưá»ng/dẫn/>]] [--html-path] [--man-path] [--info-"
"path]\n"
-" [-p | --paginate | -P --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-" [--git-dir=</đưá»ng/dẫn/>] [--work-tree=</đưá»ng/dẫn/>] [--"
-"namespace=<tên>]\n"
-" [--super-prefix=</đưá»ng/dẫn/>] [--config-env=<tên>=<envvar>]\n"
+" [-p | --paginate | -P --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=</đưá»ng/"
+"dẫn/>]\n"
+" [--work-tree=</đưá»ng/dẫn/>] [--namespace=<tên>] [--config-"
+"env=<tên>=<envvar>]\n"
" <lệnh> [<các tham số>]"
msgid ""
@@ -15877,14 +16706,14 @@ msgid ""
"to read about a specific subcommand or concept.\n"
"See 'git help git' for an overview of the system."
msgstr ""
-"“git help -a†và “git help -g†liệt kê các câu lệnh con sẵn có và một số\n"
-"hướng dẫn vá» khái niệm. Xem “git help <lệnh>†hay “git help <khái-niệm>â€\n"
+"'git help -a' và 'git help -g' liệt kê các câu lệnh con sẵn có và một số\n"
+"hướng dẫn vỠkhái niệm. Xem 'git help <lệnh>' hay 'git help <khái-niệm>'\n"
"để xem các đặc tả cho lệnh hay khái niệm cụ thể.\n"
-"Xem “git help git†để biết tổng quan của hệ thống."
+"Xem 'git help git' để biết tổng quan của hệ thống."
#, c-format
msgid "unsupported command listing type '%s'"
-msgstr "không há»— trợ liệt kê lệnh kiểu “%sâ€"
+msgstr "không hỗ trợ liệt kê lệnh kiểu '%s'"
#, c-format
msgid "no directory given for '%s' option\n"
@@ -15895,10 +16724,6 @@ msgid "no namespace given for --namespace\n"
msgstr "chưa đưa ra không gian làm việc cho --namespace\n"
#, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "chưa đưa ra tiá»n tố cho --super-prefix\n"
-
-#, c-format
msgid "-c expects a configuration string\n"
msgstr "-c cần một chuỗi cấu hình\n"
@@ -15907,20 +16732,24 @@ msgid "no config key given for --config-env\n"
msgstr "không đưa ra khóa cấu hình cho --config-env\n"
#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "không đưa ra nguồn thuộc tính cho --attr-source\n"
+
+#, c-format
msgid "unknown option: %s\n"
msgstr "không hiểu tùy chá»n: %s\n"
#, c-format
msgid "while expanding alias '%s': '%s'"
-msgstr "trong khi triển khai bí danh “%sâ€: “%sâ€"
+msgstr "trong khi triển khai bí danh '%s': '%s'"
#, c-format
msgid ""
"alias '%s' changes environment variables.\n"
"You can use '!git' in the alias to do this"
msgstr ""
-"bí danh “%s†thay đổi biến môi trưá»ng.\n"
-"Bạn có thể sử dụng “!git†trong đặt bí danh để làm việc này"
+"bí danh '%s' thay đổi biến môi trưá»ng.\n"
+"Bạn có thể sử dụng '!git' trong đặt bí danh để làm việc này"
#, c-format
msgid "empty alias for %s"
@@ -15931,22 +16760,22 @@ msgid "recursive alias: %s"
msgstr "đệ quy các bí danh: %s"
msgid "write failure on standard output"
-msgstr "lỗi ghi nghiêm trong trên đầu ra tiêu chuẩn"
+msgstr "lá»—i khi ghi ra stdout"
msgid "unknown write failure on standard output"
-msgstr "lá»—i nghiêm trá»ng chưa biết khi ghi ra đầu ra tiêu chuẩn"
+msgstr "lỗi không rõ khi ghi ra stdout"
msgid "close failed on standard output"
-msgstr "gặp lỗi khi đóng đầu ra tiêu chuẩn"
+msgstr "lỗi khi đóng stdout"
#, c-format
msgid "alias loop detected: expansion of '%s' does not terminate:%s"
msgstr ""
-"dò tìm thấy các bí danh quẩn tròn: biểu thức của “%s†không có điểm kết:%s"
+"dò tìm thấy các bí danh quẩn tròn: biểu thức của '%s' không có điểm kết:%s"
#, c-format
msgid "cannot handle %s as a builtin"
-msgstr "không thể xử lý %s như là một phần bổ sung"
+msgstr "không thể xử lý %s như là builtin"
#, c-format
msgid ""
@@ -15958,18 +16787,18 @@ msgstr ""
#, c-format
msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
-msgstr "gặp lá»—i khi khai triển bí danh “%sâ€; “%s†không phải là lệnh git\n"
+msgstr "gặp lỗi khi khai triển bí danh '%s'; '%s' không phải là lệnh git\n"
#, c-format
msgid "failed to run command '%s': %s\n"
-msgstr "gặp lá»—i khi chạy lệnh “%sâ€: %s\n"
+msgstr "gặp lỗi khi chạy lệnh '%s': %s\n"
msgid "could not create temporary file"
msgstr "không thể tạo tập tin tạm thá»i"
#, c-format
msgid "failed writing detached signature to '%s'"
-msgstr "gặp lá»—i khi ghi chữ ký đính kèm vào “%sâ€"
+msgstr "gặp lỗi khi ghi chữ ký đính kèm vào '%s'"
msgid ""
"gpg.ssh.allowedSignersFile needs to be configured and exist for ssh "
@@ -15991,11 +16820,11 @@ msgstr "tập tin thu hồi chữ ký ssh đã được cấu hình nhưng khôn
#, c-format
msgid "bad/incompatible signature '%s'"
-msgstr "chữ sai / không tương thích “%sâ€"
+msgstr "chữ sai / không tương thích '%s'"
#, c-format
msgid "failed to get the ssh fingerprint for key '%s'"
-msgstr "gặp lá»—i khi lấy dấu vân tay ssh cho khóa “%sâ€"
+msgstr "gặp lỗi khi lấy dấu vân tay ssh cho khóa '%s'"
msgid ""
"either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"
@@ -16011,19 +16840,24 @@ msgstr ""
msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
msgstr "gpg.ssh.defaultKeyCommand gặp lỗi: %s %s"
-msgid "gpg failed to sign the data"
-msgstr "gpg gặp lỗi khi ký dữ liệu"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg gặp lỗi khi ký dữ liệu:\n"
+"%s"
msgid "user.signingKey needs to be set for ssh signing"
msgstr "user.signingKey cần được đặt cho ký ssh"
#, c-format
msgid "failed writing ssh signing key to '%s'"
-msgstr "gặp lá»—i khi ghi chìa khóa ký ssh vào “%sâ€"
+msgstr "gặp lỗi khi ghi chìa khóa ký ssh vào '%s'"
#, c-format
msgid "failed writing ssh signing key buffer to '%s'"
-msgstr "gặp lá»—i khi ghi bá»™ đệm chìa khóa ký ssh vào “%sâ€"
+msgstr "gặp lỗi khi ghi bộ đệm chìa khóa ký ssh vào '%s'"
msgid ""
"ssh-keygen -Y sign is needed for ssh signing (available in openssh version "
@@ -16034,11 +16868,11 @@ msgstr ""
#, c-format
msgid "failed reading ssh signing data buffer from '%s'"
-msgstr "gặp lá»—i khi Ä‘á»c bá»™ đệm dữ liệu chữ ký ssh từ “%sâ€"
+msgstr "gặp lá»—i khi Ä‘á»c bá»™ đệm dữ liệu chữ ký ssh từ '%s'"
#, c-format
msgid "ignored invalid color '%.*s' in log.graphColors"
-msgstr "bỠqua màu không hợp lệ “%.*s†trong log.graphColors"
+msgstr "bỠqua màu không hợp lệ '%.*s' trong log.graphColors"
msgid ""
"given pattern contains NULL byte (via -f <file>). This is only supported "
@@ -16049,11 +16883,11 @@ msgstr ""
#, c-format
msgid "'%s': unable to read %s"
-msgstr "“%sâ€: không thể Ä‘á»c %s"
+msgstr "'%s': không thể Ä‘á»c %s"
#, c-format
msgid "'%s': short read"
-msgstr "“%sâ€: Ä‘á»c ngắn"
+msgstr "'%s': Ä‘á»c ngắn"
msgid "start a working area (see also: git help tutorial)"
msgstr "bắt đầu một vùng làm việc (xem thêm: git help tutorial)"
@@ -16094,9 +16928,15 @@ msgstr "Lệnh/Äồng bá»™ kho ở mức thấp"
msgid "Low-level Commands / Internal Helpers"
msgstr "Lệnh/Hỗ trợ nội tại ở mức thấp"
+msgid "User-facing repository, command and file interfaces"
+msgstr "Các giao diện kho, lệnh và tập tin hướng ngưá»i dùng"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Các giao diện tập tin, giao thức và khác cho lập trình viên"
+
#, c-format
msgid "available git commands in '%s'"
-msgstr "các lệnh git sẵn có trong thư mục “%sâ€:"
+msgstr "các lệnh git sẵn có trong thư mục '%s':"
msgid "git commands available from elsewhere on your $PATH"
msgstr "các lệnh git sẵn có từ một nơi khác trong $PATH của bạn"
@@ -16107,6 +16947,12 @@ msgstr "Có các lệnh Git chung được sử dụng trong các tình huống
msgid "The Git concept guides are:"
msgstr "Các chỉ dẫn khái niệm vỠGit là:"
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Các giao diện kho, lệnh và tập tin hướng ngưá»i dùng"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Các giao diện tập tin, giao thức và khác cho lập trình viên"
+
msgid "External commands"
msgstr "Các lệnh bên ngoài"
@@ -16114,38 +16960,38 @@ msgid "Command aliases"
msgstr "Các bí danh lệnh"
msgid "See 'git help <command>' to read about a specific subcommand"
-msgstr "Xem “git help <lệnh>†để Ä‘á»c các đặc tả cá»§a lệnh con"
+msgstr "Xem 'git help <lệnh>' để Ä‘á»c các đặc tả cá»§a lệnh con"
#, 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†trông như là một lệnh git, nhưng chúng tôi không\n"
+"'%s' trông như là một lệnh git, nhưng chúng tôi không\n"
"thể thá»±c thi nó. Có lẽ là lệnh git-%s đã bị há»ng?"
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: “%s†không phải là má»™t lệnh cá»§a git. Xem “git --helpâ€."
+msgstr "git: '%s' không phải là một lệnh của git. Xem 'git --help'."
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "á»i chà. Hệ thống cá»§a bạn báo rằng chẳng có lệnh Git nào cả."
#, c-format
msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr "CẢNH BÃO: Bạn đã gá»i lệnh Git có tên “%sâ€, mà nó lại không có sẵn."
+msgstr "CẢNH BÃO: Bạn đã gá»i lệnh Git có tên '%s', mà nó lại không có sẵn."
#, c-format
msgid "Continuing under the assumption that you meant '%s'."
-msgstr "Tiếp tục và coi rằng ý bạn là “%sâ€."
+msgstr "Tiếp tục và coi rằng ý bạn là '%s'."
#, c-format
msgid "Run '%s' instead [y/N]? "
-msgstr "Chạy “%s†để thay thế? (y/N)? "
+msgstr "Chạy '%s' để thay thế? (y/N)? "
#, c-format
msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
-msgstr "Tiếp tục trong %0.1f giây,và coi rằng ý bạn là “%sâ€."
+msgstr "Tiếp tục trong %0.1f giây,và coi rằng ý bạn là '%s'."
msgid ""
"\n"
@@ -16157,8 +17003,8 @@ msgstr[0] ""
"\n"
"Những lệnh giống nhất là"
-msgid "git version [<options>]"
-msgstr "git version [<các tùy chá»n>]"
+msgid "git version [--build-options]"
+msgstr "git version [--build-options]"
#, c-format
msgid "%s: %s - %s"
@@ -16179,19 +17025,15 @@ 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 ""
-"Móc “%s†bị bỠqua bởi vì nó không thể đặt là thực thi được.\n"
-"Bạn có thể tắt cảnh báo này bằng “git config advice.ignoredHook false“."
+"Móc '%s' bị bỠqua bởi vì nó không có cỠthực thi được.\n"
+"Bạn có thể tắt cảnh báo này bằng 'git config advice.ignoredHook false'."
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "Không thể khởi chạy móc “%sâ€\n"
+msgid "not a git repository"
+msgstr "không phải là kho git"
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
-msgstr "tham số cho --packfile phải là má»™t giá trị băm hợp lệ (nhận được “%sâ€)"
-
-msgid "not a git repository"
-msgstr "không phải là kho git"
+msgstr "tham số cho --packfile phải là một giá trị băm hợp lệ (có '%s')"
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
@@ -16203,24 +17045,33 @@ msgstr "Äiá»u khiển giao quyá»n không được há»— trợ vá»›i cURL < 7.2
msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "Chốt khóa công không được hỗ trợ với cURL < 7.39.0"
+msgid "Unknown value for http.proactiveauth"
+msgstr "không hiểu giá trị cho http.proactiveauth"
+
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "CURLSSLOPT_NO_REVOKE không được hỗ trợ với cURL < 7.44.0"
#, c-format
msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
msgstr ""
-"Không há»— trợ ứng dụng SSL chạy phía sau “%sâ€. Há»— trợ ứng dụng SSL chạy phía "
+"Không hỗ trợ ứng dụng SSL chạy phía sau '%s'. Hỗ trợ ứng dụng SSL chạy phía "
"sau:"
#, c-format
msgid "Could not set SSL backend to '%s': cURL was built without SSL backends"
msgstr ""
-"Không thể đặt ứng dụng chạy SSL phía sau “%sâ€: cURL được biên dịch không có "
+"Không thể đặt ứng dụng chạy SSL phía sau '%s': cURL được biên dịch không có "
"sự hỗ trợ ứng dụng chạy phía sau SSL"
#, c-format
msgid "Could not set SSL backend to '%s': already set"
-msgstr "Không thể đặt ứng dụng chạy sau SSL cho “%sâ€: đã đặt rồi"
+msgstr "Không thể đặt ứng dụng chạy sau SSL cho '%s': đã đặt rồi"
+
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "từ chối Ä‘á»c cookie từ http.cookiefile '-'"
+
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "bá» qua tuỳ chá»n http.savecookies vì http.cookiefile để trống"
#, c-format
msgid ""
@@ -16268,14 +17119,14 @@ msgstr "không đưa ra địa chỉ thư điện tử và auto-detection bị t
#, c-format
msgid "unable to auto-detect email address (got '%s')"
-msgstr "không thể tá»± dò tìm địa chỉ thư Ä‘iện tá»­ (nhận “%sâ€)"
+msgstr "không thể tự dò tìm địa chỉ thư điện tử (nhận '%s')"
msgid "no name was given and auto-detection is disabled"
msgstr "chưa chỉ ra tên và tự-động-dò-tìm bị tắt"
#, c-format
msgid "unable to auto-detect name (got '%s')"
-msgstr "không thể dò-tìm-tá»± động tên (đã nhận “%sâ€)"
+msgstr "không thể dò-tìm-tự động tên (đã nhận '%s')"
#, c-format
msgid "empty ident name (for <%s>) not allowed"
@@ -16286,22 +17137,22 @@ msgid "name consists only of disallowed characters: %s"
msgstr "tên chỉ được phép bao gồm các ký tự sau: %s"
msgid "expected 'tree:<depth>'"
-msgstr "cần “tree:<depth>â€"
+msgstr "cần 'tree:<depth>'"
msgid "sparse:path filters support has been dropped"
-msgstr "việc há»— trợ bá»™ lá»c sparse:đưá»ng/dẫn đã bị bá»"
+msgstr "há»— trợ bá»™ lá»c sparse:đưá»ng/dẫn đã không còn"
#, c-format
msgid "'%s' for 'object:type=<type>' is not a valid object type"
-msgstr "“%s†dành cho “object:type=<type>†không phải là kiểu đối tượng hợp lệ"
+msgstr "'%s' dành cho 'object:type=<type>' không phải là kiểu đối tượng hợp lệ"
#, c-format
msgid "invalid filter-spec '%s'"
-msgstr "đặc tả bá»™ lá»c không hợp lệ “%sâ€"
+msgstr "đặc tả bá»™ lá»c không hợp lệ '%s'"
#, c-format
msgid "must escape char in sub-filter-spec: '%c'"
-msgstr "phải thoát char trong sub-filter-spec: “%câ€"
+msgstr "phải thoát char trong sub-filter-spec: '%c'"
msgid "expected something after combine:"
msgstr "mong đợi một cái gì đó sau khi kết hợp:"
@@ -16320,23 +17171,23 @@ msgstr "lá»c đối tượng"
#, c-format
msgid "unable to access sparse blob in '%s'"
-msgstr "không thể truy cập các blob rải rác trong “%sâ€"
+msgstr "không thể truy cập các blob rải rác trong '%s'"
#, c-format
msgid "unable to parse sparse filter data in %s"
-msgstr "không thể phân tích dữ liệu bá»™ lá»c rải rác trong %s"
+msgstr "không thể Ä‘á»c dữ liệu bá»™ lá»c rải rác trong %s"
#, c-format
msgid "entry '%s' in tree %s has tree mode, but is not a tree"
-msgstr "mục “%s†trong cây %s có nút cây, nhưng không phải là một cây"
+msgstr "mục '%s' trong cây %s có nút cây, nhưng không phải là một cây"
#, c-format
msgid "entry '%s' in tree %s has blob mode, but is not a blob"
-msgstr "mục “%s†trong cây %s có nút blob, nhưng không phải là một blob"
+msgstr "mục '%s' trong cây %s có nút blob, nhưng không phải là một blob"
#, c-format
msgid "unable to load root tree for commit %s"
-msgstr "không thể tải cây gốc cho lần chuyển giao “%sâ€"
+msgstr "không thể tải cây gốc cho lần chuyển giao '%s'"
#, c-format
msgid ""
@@ -16348,21 +17199,32 @@ msgid ""
"may have crashed in this repository earlier:\n"
"remove the file manually to continue."
msgstr ""
-"Không thể tạo “%s.lockâ€: %s.\n"
+"Không thể tạo '%s.lock': %s.\n"
"\n"
"Tiến trình git khác có lẽ đang chạy ở kho này, ví dụ\n"
-"má»™t trình soạn thảo được mở bởi “git commitâ€. Vui lòng chắc chắn\n"
-"rằng má»i tiến trình đã chấm dứt và sau đó thá»­ lại. Nếu vẫn lá»—i,\n"
-"một tiến trình git có lẽ đã đổ vỡ khi thực hiện ở kho này trước đó:\n"
+"một trình soạn thảo được mở bởi 'git commit'. Vui lòng chắc chắn\n"
+"rằng má»i tiến trình đã kết thúc và sau đó thá»­ lại. Nếu vẫn lá»—i,\n"
+"một tiến trình git có lẽ đã crash khi thực hiện ở kho này trước đó:\n"
"gõ bỠtập tin một cách thủ công để tiếp tục."
#, c-format
msgid "Unable to create '%s.lock': %s"
-msgstr "Không thể tạo “%s.lockâ€: %s"
+msgstr "Không thể tạo '%s.lock': %s"
+
+msgid "unable to create temporary object directory"
+msgstr "không thể tạo thư mục đối tượng tạm thá»i"
+
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "không thể ghi tập tin đối tượng loose %s"
+
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "ghi chỉ mục đối tượng loose %s thất bại"
#, c-format
msgid "unexpected line: '%s'"
-msgstr "dòng không cần: “%sâ€"
+msgstr "dòng bất thưá»ng: '%s'"
msgid "expected flush after ls-refs arguments"
msgstr "cần đẩy dữ liệu lên đĩa sau tham số ls-refs (liệt kê tham chiếu)"
@@ -16371,74 +17233,59 @@ msgid "quoted CRLF detected"
msgstr "phát hiện CRLF được trích dẫn"
#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-" %s"
-msgstr ""
-"Các thay đổi nội bộ của bạn với các tập tin sau đây sẽ bị ghi đè bởi lệnh "
-"hòa trộn:\n"
-" %s"
+msgid "unable to format message: %s"
+msgstr "không thể định dạng thông điệp: %s"
#, c-format
msgid "Failed to merge submodule %s (not checked out)"
-msgstr "Gặp lỗi khi hòa trộn mô-đun-con “%s†(không lấy ra được)"
+msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s (không checkout được)"
+
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s (không có gốc hoà trộn)"
#, c-format
msgid "Failed to merge submodule %s (commits not present)"
-msgstr "Gặp lỗi khi hòa trộn mô-đun-con “%s†(lần chuyển giao không hiện diện)"
+msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s (lần chuyển giao không hiện diện)"
+
+#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "lá»—i: gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s (kho chứa há»ng)"
#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
msgstr ""
-"Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con “%s†(lần chuyển giao không theo sau ná»n-hòa-"
+"Gặp lỗi khi hòa trộn mô-đun-con %s (lần chuyển giao không theo sau gốc-hòa-"
"trá»™n)"
#, c-format
msgid "Note: Fast-forwarding submodule %s to %s"
-msgstr "Chú ý: Chuyển-tiếp-nhanh mô-Ä‘un-con “%s†sang “%sâ€"
+msgstr "Chú ý: Chuyển-tiếp-nhanh mô-đun-con %s sang %s"
#, c-format
msgid "Failed to merge submodule %s"
-msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con “%sâ€"
+msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s"
#, c-format
msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con “%sâ€, nhưng có cách giải quyết:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-" git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"Nếu đây là đúng đơn giản thêm nó vào mục lục ví dụ\n"
-"bằng cách dùng:\n"
-"\n"
-" git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"cái mà sẽ chấp nhận gợi ý này.\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
+msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s, nhưng có cách giải quyết: %s"
#, c-format
msgid ""
"Failed to merge submodule %s, but multiple possible merges exist:\n"
"%s"
msgstr ""
-"Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con “%sâ€, nhưng có nhiá»u cách giải quyết:\n"
+"Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s, nhưng có nhiá»u cách giải quyết:\n"
"%s"
-msgid "Failed to execute internal merge"
-msgstr "Gặp lỗi khi thực hiện trộn nội bộ"
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "lỗi: Gặp lỗi khi thực hiện trộn nội bộ %s"
#, c-format
-msgid "Unable to add %s to database"
-msgstr "Không thể thêm %s vào cơ sở dữ liệu"
+msgid "error: unable to add %s to database"
+msgstr "lỗi: không thể thêm %s vào cơ sở dữ liệu"
#, c-format
msgid "Auto-merging %s"
@@ -16449,16 +17296,16 @@ 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 ""
-"XUNG ÄỘT: (ngầm đổi tên thư mục): Tập tin/thư mục đã sẵn có tại %s theo cách "
-"cá»§a các đổi tên thư mục ngầm đặt (các) đưá»ng dẫn sau ở đây: %s."
+"XUNG ÄỘT: (ngầm đổi tên thư mục): Tập tin/thư mục đã sẵn có tại %s do việc "
+"đổi tên thư mục sẽ đặt các đưá»ng dẫn sau ở đó: %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 ""
-"XUNG ÄỘT: (ngầm đổi tên thư mục): Không thể ánh xạ má»™t đưá»ng dẫn thành %s; "
-"các đổi tên thư mục ngầm cố đặt các đưá»ng dẫn ở đây: %s"
+"XUNG ÄỘT: (ngầm đổi tên thư mục): Không thể ánh xạ hÆ¡n má»™t đưá»ng dẫn thành "
+"%s; việc đổi tên thư mục sẽ đặt các đưá»ng dẫn sau ở đó: %s"
#, c-format
msgid ""
@@ -16466,17 +17313,17 @@ msgid ""
"renamed to multiple other directories, with no destination getting a "
"majority of the files."
msgstr ""
-"XUNG ÄỘT: (thư mục đổi tên chia tách): Không rõ ràng nÆ¡i để đổi tên %s "
-"thành; nó đã bị đổi tên thành nhiá»u thư mục khác, vá»›i không đích đến nhận "
-"má»™t phần nhiá»u cá»§a các tập tin."
+"XUNG ÄỘT: (phân hoá đổi tên thư mục): Không rõ đổi tên %s vỠđâu; nó đã bị "
+"đổi tên thành nhiá»u thư mục khác, mà không bên nào nhận phần lá»›n các tập tin "
+"gốc."
#, c-format
msgid ""
"WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
"renamed."
msgstr ""
-"CẢNH BÃO: tránh áp dụng %s -> %s đổi thên thành %s, bởi vì bản thân %s cÅ©ng "
-"bị đổi tên."
+"CẢNH BÃO: Tránh áp dụng đổi tên %s -> %s cho %s, bởi vì bản thân %s đã bị "
+"đổi tên."
#, c-format
msgid ""
@@ -16484,7 +17331,7 @@ msgid ""
"moving it to %s."
msgstr ""
"ÄÆ°á»ng dẫn đã được cập nhật: %s được thêm vào trong %s bên trong má»™t thư mục "
-"đã được đổi tên trong %s; di chuyển nó đến %s."
+"đã được đổi tên trong %s; sẽ di chuyển nó đến %s."
#, c-format
msgid ""
@@ -16492,14 +17339,14 @@ msgid ""
"%s; moving it to %s."
msgstr ""
"ÄÆ°á»ng dẫn đã được cập nhật: %s được đổi tên thành %s trong %s, bên trong má»™t "
-"thư mục đã được đổi tên trong %s; di chuyển nó đến %s."
+"thư mục đã được đổi tên trong %s; sẽ di chuyển nó đến %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 ""
-"XUNG ÄỘT (vị trí tệp): %s được thêm vào trong %s trong má»™t thư mục đã được "
+"XUNG ÄỘT (vị trí tập): %s được thêm vào trong %s trong má»™t thư mục đã được "
"đổi tên thành %s, đoán là nó nên được di chuyển đến %s."
#, c-format
@@ -16507,7 +17354,7 @@ 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 ""
-"XUNG ÄỘT (vị trí tệp): %s được đổi tên thành %s trong %s, bên trong má»™t thư "
+"XUNG ÄỘT (vị trí tập): %s được đổi tên thành %s trong %s, bên trong má»™t thư "
"mục đã được đổi tên thành %s, đoán là nó nên được di chuyển đến %s."
#, c-format
@@ -16531,20 +17378,20 @@ msgstr ""
"XUNG ÄỘT (đổi-tên/xóa): Äổi tên %s->%s trong %s, nhưng lại bị xóa trong %s."
#, c-format
-msgid "cannot read object %s"
-msgstr "không thể Ä‘á»c đối tượng %s"
+msgid "error: cannot read object %s"
+msgstr "lá»—i: không thể Ä‘á»c đối tượng %s"
#, c-format
-msgid "object %s is not a blob"
-msgstr "đối tượng %s không phải là một blob"
+msgid "error: object %s is not a blob"
+msgstr "lỗi: đối tượng %s không phải là một blob"
#, c-format
msgid ""
"CONFLICT (file/directory): directory in the way of %s from %s; moving it to "
"%s instead."
msgstr ""
-"XUNG ÄỘT (tập tin/thư mục): thư mục theo cách cá»§a %s từ %s; thay vào đó, di "
-"chuyển nó đến %s."
+"XUNG ÄỘT (tập tin/thư mục): thư mục khác nằm trên %s từ %s; thay vào đó sẽ "
+"di chuyển nó đến %s."
#, c-format
msgid ""
@@ -16552,15 +17399,15 @@ msgid ""
"of them so each can be recorded somewhere."
msgstr ""
"XUNG ÄỘT (các kiểu riêng biệt): %s có các kiểu khác nhau ở má»—i bên; đã đổi "
-"tên cả hai trong số chúng để mỗi cái có thể được ghi lại ở đâu đó."
+"tên cả hai để có thể ghi lại cả hai."
#, c-format
msgid ""
"CONFLICT (distinct types): %s had different types on each side; renamed one "
"of them so each can be recorded somewhere."
msgstr ""
-"XUNG ÄỘT (các kiểu riêng biệt): %s có các loại khác nhau ở má»—i bên; đã đổi "
-"tên một trong số chúng để mỗi cái có thể được ghi lại ở đâu đó."
+"XUNG ÄỘT (các kiểu riêng biệt): %s có các kiểu khác nhau ở má»—i bên; đã đổi "
+"tên một trong số chúng để có thể ghi lại cả hai."
msgid "content"
msgstr "ná»™i dung"
@@ -16583,13 +17430,43 @@ msgstr ""
"XUNG ÄỘT (sá»­a/xóa): %s bị xóa trong %s và sá»­a trong %s. Phiên bản %s cá»§a %s "
"còn lại trong cây (tree)."
+#. 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 ""
-"Lưu ý: %s không được cập nhật và theo cách lấy ra phiên bản xung đột; bản "
-"sao cũ được đổi tên thành %s"
+" - đi tới mô-đun con (%s), và hoà trộn lần chuyển giao %s\n"
+" hoặc cập nhật tới một lần chuyển giao đã có hoà trộn các thay đổi\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 ""
+"Hoà trá»™n đệ quy vá»›i mô-Ä‘un con hiện chỉ há»— trợ các trưá»ng hợp đơn giản.\n"
+"Vui lòng hoà trộn các mô-đun con có xung đột bằng tay.\n"
+"Bạn có thể thực hiện theo các bước sau:\n"
+"%s - trở vỠproject cha và chạy lệnh:\n"
+"\n"
+" git add %s\n"
+"\n"
+" để ghi lại hoà trộn hoặc cập nhật\n"
+" - giải quyết các xung đột trong project cha\n"
+" - chuyển giao kết quả trong project cha\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.
@@ -16603,74 +17480,101 @@ msgstr "(commit sai)\n"
#, c-format
msgid "add_cacheinfo failed for path '%s'; merge aborting."
-msgstr "add_cacheinfo gặp lá»—i đối vá»›i đưá»ng dẫn “%sâ€; việc hòa trá»™n bị bãi bá»."
+msgstr "add_cacheinfo gặp lá»—i đối vá»›i đưá»ng dẫn '%s'; huá»· bá» việc hòa trá»™n."
#, c-format
msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
msgstr ""
-"add_cacheinfo gặp lá»—i khi làm má»›i đối vá»›i đưá»ng dẫn “%sâ€; việc hòa trá»™n bị "
-"bãi bá»."
+"add_cacheinfo gặp lá»—i khi làm má»›i đối vá»›i đưá»ng dẫn '%s'; huá»· bá» việc hòa "
+"trá»™n."
#, c-format
msgid "failed to create path '%s'%s"
-msgstr "gặp lá»—i khi tạo đưá»ng dẫn “%sâ€%s"
+msgstr "gặp lá»—i khi tạo đưá»ng dẫn '%s'%s"
#, c-format
msgid "Removing %s to make room for subdirectory\n"
msgstr "Gỡ bỠ%s để tạo chỗ (room) cho thư mục con\n"
msgid ": perhaps a D/F conflict?"
-msgstr ": có lẽ là một xung đột D/F?"
+msgstr ": có lẽ là xung đột D/F (tập tin/thư mục)?"
#, c-format
msgid "refusing to lose untracked file at '%s'"
-msgstr "từ chối đóng tập tin không được theo dõi tại “%sâ€"
+msgstr "từ chối đóng tập tin không được theo dõi tại '%s'"
#, c-format
msgid "blob expected for %s '%s'"
-msgstr "mong đợi đối tượng blob cho %s “%sâ€"
+msgstr "mong đợi đối tượng blob cho %s '%s'"
#, c-format
msgid "failed to open '%s': %s"
-msgstr "gặp lá»—i khi mở “%sâ€: %s"
+msgstr "gặp lỗi khi mở '%s': %s"
#, c-format
msgid "failed to symlink '%s': %s"
-msgstr "gặp lá»—i khi tạo liên kết má»m (symlink) “%sâ€: %s"
+msgstr "gặp lá»—i khi tạo liên kết má»m (symlink) '%s': %s"
#, c-format
msgid "do not know what to do with %06o %s '%s'"
-msgstr "không hiểu phải làm gì vá»›i %06o %s “%sâ€"
+msgstr "không hiểu phải làm gì với %06o %s '%s'"
+
+#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s (kho chứa há»ng)"
#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
-msgstr "Chuyển-tiếp-nhanh mô-đun-con “%s†đến lần chuyển giao sau đây:"
+msgstr "Chuyển-tiếp-nhanh mô-đun-con '%s' đến lần chuyển giao sau đây:"
#, c-format
msgid "Fast-forwarding submodule %s"
-msgstr "Chuyển-tiếp-nhanh mô-Ä‘un-con “%sâ€"
+msgstr "Chuyển-tiếp-nhanh mô-đun-con '%s'"
#, c-format
msgid "Failed to merge submodule %s (merge following commits not found)"
msgstr ""
-"Gặp lỗi khi hòa trộn mô-đun-con “%s†(không tìm thấy các lần chuyển giao "
+"Gặp lỗi khi hòa trộn mô-đun-con '%s' (không tìm thấy các lần chuyển giao "
"theo sau hòa trộn)"
#, c-format
msgid "Failed to merge submodule %s (not fast-forward)"
-msgstr "Gặp lỗi khi hòa trộn mô-đun-con “%s†(không chuyển tiếp nhanh được)"
+msgstr "Gặp lỗi khi hòa trộn mô-đun-con '%s' (không chuyển tiếp nhanh được)"
msgid "Found a possible merge resolution for the submodule:\n"
-msgstr "Tìm thấy một giải pháp hòa trộn có thể cho mô-đun-con:\n"
+msgstr "Tìm thấy một giải pháp hòa trộn khả thi cho mô-đun-con:\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ếu đây là đúng đơn giản thêm nó vào chỉ mục ví dụ\n"
+"bằng cách dùng:\n"
+"\n"
+" git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"cái mà sẽ chấp nhận gợi ý này.\n"
#, c-format
msgid "Failed to merge submodule %s (multiple merges found)"
-msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con “%s†(thấy nhiá»u hòa trá»™n Ä‘a trùng)"
+msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con '%s' (thấy nhiá»u hòa trá»™n Ä‘a trùng)"
+
+msgid "failed to execute internal merge"
+msgstr "Gặp lỗi khi thực hiện trộn nội bộ"
+
+#, c-format
+msgid "unable to add %s to database"
+msgstr "Không thể thêm %s vào cơ sở dữ liệu"
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr ""
-"Lá»—i: từ chối đóng tập tin không được theo dõi tại “%sâ€; thay vào đó ghi vào "
+"Lỗi: từ chối đóng tập tin không được theo dõi tại '%s'; thay vào đó ghi vào "
"%s."
#, c-format
@@ -16713,12 +17617,12 @@ msgstr "đã đổi tên"
#, c-format
msgid "Refusing to lose dirty file at %s"
-msgstr "Từ chối đóng tập tin không được theo dõi tại “%sâ€"
+msgstr "Từ chối đóng tập tin không được theo dõi tại '%s'"
#, c-format
msgid "Refusing to lose untracked file at %s, even though it's in the way."
msgstr ""
-"Từ chối đóng tập tin không được theo dõi tại “%sâ€, ngay cả khi nó ở trên "
+"Từ chối đóng tập tin không được theo dõi tại '%s', ngay cả khi nó ở trên "
"đưá»ng."
#, c-format
@@ -16733,13 +17637,13 @@ msgstr "%s là một thư mục trong %s thay vào đó thêm vào như là %s"
#, c-format
msgid "Refusing to lose untracked file at %s; adding as %s instead"
msgstr ""
-"Từ chối đóng tập tin không được theo dõi tại “%sâ€; thay vào đó Ä‘ang thêm "
+"Từ chối đóng tập tin không được theo dõi tại '%s'; thay vào đó đang thêm "
"thành %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 ""
"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên \"%s\"->\"%s\" trong nhánh \"%s\" đổi "
"tên \"%s\"->\"%s\" trong \"%s\"%s"
@@ -16758,9 +17662,9 @@ msgid ""
"directory %s was renamed to multiple other directories, with no destination "
"getting a majority of the files."
msgstr ""
-"XUNG ÄỘT: (thư mục đổi tên chia tách): Không rõ ràng để đặt địa Ä‘iểm %s bởi "
-"vì thư mục %s đã bị đổi tên thành nhiá»u thư mục khác, vá»›i không đích đến "
-"nhận má»™t phần nhiá»u cá»§a các tập tin."
+"XUNG ÄỘT: (phân hoá đổi tên thư mục): Không rõ đặt %s ở đâu bởi vì thư mục "
+"%s đã bị đổi tên thành nhiá»u thư mục khác, mà không bên nào nhận phần lá»›n "
+"các tập tin gốc."
#, c-format
msgid ""
@@ -16770,6 +17674,14 @@ msgstr ""
"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên thư mục %s->%s trong %s. Äổi tên thư mục "
"%s->%s trong %s"
+#, c-format
+msgid "cannot read object %s"
+msgstr "không thể Ä‘á»c đối tượng %s"
+
+#, c-format
+msgid "object %s is not a blob"
+msgstr "đối tượng %s không phải là một blob"
+
msgid "modify"
msgstr "sửa đổi"
@@ -16825,92 +17737,61 @@ msgstr "hòa trộn không trả vỠlần chuyển giao nào"
#, c-format
msgid "Could not parse object '%s'"
-msgstr "Không thể phân tích đối tượng “%sâ€"
+msgstr "Không thể Ä‘á»c đối tượng '%s'"
msgid "failed to read the cache"
msgstr "gặp lá»—i khi Ä‘á»c bá»™ nhá»› đệm"
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "fanout OID nhiá»u gói chỉ mục có kích thước sai"
-
-#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "tập tin đồ thị multi-pack-index %s quá nhá»"
-
-#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr "chữ ký multi-pack-index 0x%08x không khớp chữ ký 0x%08x"
-
-#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "không nhận ra phiên bản %d của multi-pack-index"
-
-#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "phiên bản băm multi-pack-index %u không khớp phiên bản %u"
-
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "multi-pack-index thiếu mảnh pack-name cần thiết"
-
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "multi-pack-index thiếu mảnh OID fanout cần thiết"
-
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "multi-pack-index thiếu mảnh OID lookup cần thiết"
-
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "multi-pack-index thiếu mảnh các khoảng bù đối tượng cần thiết"
-
-#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "các tên gói multi-pack-index không đúng thứ tá»±: “%s†trước “%sâ€"
-
-#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "pack-int-id sai: %u (%u các gói tổng)"
-
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr "multi-pack-index lưu trữ má»™t khoảng bù 64-bít, nhưng off_t là quá nhá»"
-
#, c-format
msgid "failed to add packfile '%s'"
-msgstr "gặp lá»—i khi thêm tập tin gói “%sâ€"
+msgstr "gặp lỗi khi thêm packfile '%s'"
#, c-format
msgid "failed to open pack-index '%s'"
-msgstr "gặp lá»—i khi mở pack-index “%sâ€"
+msgstr "gặp lỗi khi mở pack-index '%s'"
#, c-format
msgid "failed to locate object %d in packfile"
-msgstr "gặp lỗi khi phân bổ đối tượng “%d†trong tập tin gói"
+msgstr "gặp lỗi khi phân bổ đối tượng '%d' trong tập tin gói"
msgid "cannot store reverse index file"
-msgstr "không thể lưu trữ tập tin ghi mục lục đảo ngược"
+msgstr "không thể lưu trữ tập tin ghi chỉ mục đảo ngược"
#, c-format
msgid "could not parse line: %s"
-msgstr "không thể phân tích cú pháp dòng: %s"
+msgstr "không hiểu cú pháp dòng: %s"
#, c-format
msgid "malformed line: %s"
-msgstr "dòng dị hình: %s"
-
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "bỠqua multi-pack-index sẵn có; tổng kiểm không khớp"
+msgstr "dòng sai quy cách: %s"
msgid "could not load pack"
msgstr "không thể tải gói"
#, c-format
msgid "could not open index for %s"
-msgstr "không thể mở mục lục cho %s"
+msgstr "không thể mở chỉ mục cho %s"
+
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "không thể liên kết '%s' vào '%s'"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "gặp lỗi khi xóa multi-pack-index tại %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "không thể ghi incremental MIDX với bitmap"
+
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr "bỠqua multi-pack-index sẵn có; tổng kiểm không khớp"
msgid "Adding packfiles to multi-pack-index"
msgstr "Äang thêm tập tin gói từ multi-pack-index"
#, c-format
msgid "unknown preferred pack: '%s'"
-msgstr "không hiểu \"preferred pack\": %s"
+msgstr "không hiểu preferred pack: %s"
#, c-format
msgid "cannot select preferred pack %s with no objects"
@@ -16918,30 +17799,141 @@ msgstr "không thể chá»n gói ưa dùng %s vá»›i không đối tượng nào"
#, c-format
msgid "did not see pack-file %s to drop"
-msgstr "đã không thấy tập tin gói %s để mà xóa"
+msgstr "đã không thấy tập tin gói %s để xóa"
#, c-format
msgid "preferred pack '%s' is expired"
-msgstr "\"preferred pack\" “%s†đã hết hạn"
+msgstr "preferred pack '%s' đã hết hạn"
msgid "no pack files to index."
-msgstr "không có tập tin gói để đánh mục lục."
+msgstr "không có tập tin gói để đánh chỉ mục."
msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "từ chối ghi “multi-pack bitmap†mà không có bất kỳ đối tượng nào"
+msgstr "từ chối ghi multi-pack bitmap mà không có bất kỳ đối tượng nào"
+
+msgid "unable to create temporary MIDX layer"
+msgstr "không thể tạo lá»›p MIDX tạm thá»i"
msgid "could not write multi-pack bitmap"
-msgstr "không thể ghi “multi-pack bitmapâ€"
+msgstr "không thể ghi multi-pack bitmap"
+
+msgid "unable to open multi-pack-index chain file"
+msgstr "không thể mở tập tin chain multi-pack-index"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "gặp lỗi khi đổi tên lớp multi-pack-index"
msgid "could not write multi-pack-index"
-msgstr "không thể ghi “multi-pack-indexâ€"
+msgstr "không thể ghi multi-pack-index"
+
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "không thể hết hạn gói từ incremental multi-pack-index"
+
+msgid "Counting referenced objects"
+msgstr "Äang đếm các đối tượng được tham chiếu"
+
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "Äang tìm và xóa các gói không được tham chiếu"
+
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "không thể repack incremental multi-pack-index"
+
+msgid "could not start pack-objects"
+msgstr "không thể khởi chạy pack-objects"
+
+msgid "could not finish pack-objects"
+msgstr "không thể hoàn thiện pack-objects"
+
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "fanout OID multi-pack-index có kích thước sai"
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "gặp lỗi khi xóa multi-pack-index tại %s"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr "fanout cũ sai thứ tự: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "OID lookup chunk multi-pack-index có kích thước sai"
+
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "object offset chunk multi-pack-index có kích thước sai"
+
+#, c-format
+msgid "multi-pack-index file %s is too small"
+msgstr "tập tin đồ thị multi-pack-index %s quá nhá»"
+
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "chữ ký multi-pack-index 0x%08x không khớp chữ ký 0x%08x"
+
+#, c-format
+msgid "multi-pack-index version %d not recognized"
+msgstr "không nhận ra phiên bản %d của multi-pack-index"
+
+#, c-format
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "phiên bản băm multi-pack-index %u không khớp phiên bản %u"
+
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr "multi-pack-index thiếu chunk pack-name cần thiết hoặc bị há»ng"
+
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr "multi-pack-index thiếu chunk OID fanout cần thiết hoặc bị há»ng"
+
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr "multi-pack-index thiếu chunk OID lookup cần thiết hoặc bị há»ng"
+
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr ""
+"multi-pack-index thiếu chunk các khoảng bù đối tượng cần thiết hoặc bị há»ng"
+
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "tập tin đồ thị multi-pack-index %s quá nhá»"
+
+#, c-format
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "các tên gói multi-pack-index không đúng thứ tự: '%s' trước '%s'"
+
+msgid "multi-pack-index chain file too small"
+msgstr "tập tin chain multi-pack-index quá nhá»"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "số pack trong base MIDX quá lớn: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "số đối tượng trong base MIDX quá lớn: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "multi-pack-index chain không hợp lệ: dòng '%s' không phải là mã băm"
+
+msgid "unable to find all multi-pack index files"
+msgstr "không thể tìm thấy tất cả các tập tin multi-pack index"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "vị trí đối tượng MIDX không hợp lệ. MIDX có vẻ như đã bị há»ng"
+
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "pack-int-id sai: %u (%u các gói tổng)"
+
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX không chứa chunk BTMP"
+
+#, c-format
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "không thể Ä‘á»c gói bitmap %<PRIu32>"
+
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr "multi-pack-index lưu trữ má»™t offset 64-bít, nhưng off_t là quá nhá»"
+
+msgid "multi-pack-index large offset out of bounds"
+msgstr "multi-pack-index large offset nằm ngoài biên"
msgid "multi-pack-index file exists, but failed to parse"
-msgstr "đã có tập tin multi-pack-index, nhưng gặp lỗi khi phân tích cú pháp"
+msgstr "đã có tập tin multi-pack-index, nhưng gặp lá»—i khi Ä‘á»c cú pháp"
msgid "incorrect checksum"
msgstr "tổng kiểm không đúng"
@@ -16949,11 +17941,6 @@ msgstr "tổng kiểm không đúng"
msgid "Looking for referenced packfiles"
msgstr "Äang khóa cho các gói bị tham chiếu"
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr "fanout cũ sai thứ tự: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-
msgid "the midx contains no oid"
msgstr "midx chẳng chứa oid nào"
@@ -16983,18 +17970,6 @@ msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr ""
"khoảng bù đối tượng không đúng cho oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-msgid "Counting referenced objects"
-msgstr "Äang đếm các đối tượng được tham chiếu"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "Äang tìm và xóa các gói không được tham chiếu"
-
-msgid "could not start pack-objects"
-msgstr "không thể lấy thông tin thống kê vỠcác đối tượng gói"
-
-msgid "could not finish pack-objects"
-msgstr "không thể hoàn thiện các đối tượng gói"
-
#, c-format
msgid "unable to create lazy_dir thread: %s"
msgstr "không thể tạo tuyến lazy_dir: %s"
@@ -17013,10 +17988,9 @@ msgid ""
"Please, use 'git notes merge --commit' or 'git notes merge --abort' to "
"commit/abort the previous merge before you start a new notes merge."
msgstr ""
-"Bạn đã chưa hoàn tất hòa trộn ghi chú trước đây (%s vẫn còn).\n"
-"Vui lòng dùng “git notes merge --commit†hay “git notes merge --abort†để "
-"chuyển giao hay bãi bỠlần hòa trộn trước đây và bắt đầu một hòa trộn ghi "
-"chú mới."
+"Bạn chưa hoàn tất lần hòa trộn ghi chú trước (%s vẫn còn).\n"
+"Vui lòng dùng 'git notes merge --commit' hay 'git notes merge --abort' để "
+"chuyển giao hay huỷ bỠlần hòa trộn trước và bắt đầu hòa trộn ghi chú mới."
#, c-format
msgid "You have not concluded your notes merge (%s exists)."
@@ -17029,7 +18003,7 @@ msgstr ""
#, c-format
msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "Giá trị notes.rewriteMode sai: “%sâ€"
+msgstr "Giá trị notes.rewriteMode sai: '%s'"
#, c-format
msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
@@ -17041,7 +18015,26 @@ msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoài refs/notes/)"
#.
#, c-format
msgid "Bad %s value: '%s'"
-msgstr "Giá trị %s sai: “%sâ€"
+msgstr "Giá trị %s sai: '%s'"
+
+msgid "failed to decode tree entry"
+msgstr "giải mã mục cây thất bại"
+
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "ánh xạ mục cây cho %s thất bại"
+
+#, c-format
+msgid "bad %s in commit"
+msgstr "ký tự không đúng %s trong lần chuyển giao"
+
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "không thể ánh xạ %s %s trong đối tượng chuyển giao"
+
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "Chuyển đổi đối tượng từ %s sang %s thất bại"
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
@@ -17050,16 +18043,12 @@ msgstr ""
#, c-format
msgid "unable to normalize alternate object path: %s"
-msgstr "không thể thưá»ng hóa đưá»ng dẫn đối tượng thay thế: “%sâ€"
+msgstr "không thể thưá»ng hóa đưá»ng dẫn đối tượng thay thế: '%s'"
#, c-format
msgid "%s: ignoring alternate object stores, nesting too deep"
msgstr "%s: đang bỠqua kho đối tượng thay thế, lồng nhau quá sâu"
-#, c-format
-msgid "unable to normalize object directory: %s"
-msgstr "không thể chuẩn hóa thư mục đối tượng: “%sâ€"
-
msgid "unable to fdopen alternates lockfile"
msgstr "không thể fdopen tập tin khóa thay thế"
@@ -17071,31 +18060,31 @@ msgstr "không thể di chuyển tập tin thay thế vào chỗ"
#, c-format
msgid "path '%s' does not exist"
-msgstr "đưá»ng dẫn “%s†không tồn tại"
+msgstr "đưá»ng dẫn '%s' không tồn tại"
#, c-format
msgid "reference repository '%s' as a linked checkout is not supported yet."
-msgstr "kho tham chiếu “%s†như là lấy ra liên kết vẫn chưa được hỗ trợ."
+msgstr "kho tham chiếu '%s' như là checkout liên kết vẫn chưa được hỗ trợ."
#, c-format
msgid "reference repository '%s' is not a local repository."
-msgstr "kho tham chiếu “%s†không phải là một kho nội bộ."
+msgstr "kho tham chiếu '%s' không phải là một kho nội bộ."
#, c-format
msgid "reference repository '%s' is shallow"
-msgstr "kho tham chiếu “%s†là nông"
+msgstr "kho tham chiếu '%s' là nông"
#, c-format
msgid "reference repository '%s' is grafted"
-msgstr "kho tham chiếu “%s†bị cấy ghép"
+msgstr "kho tham chiếu '%s' bị cấy ghép"
#, c-format
msgid "could not find object directory matching %s"
-msgstr "không thể tìm thấy thư mục đối tượng khá»›p vá»›i “%sâ€"
+msgstr "không thể tìm thấy thư mục đối tượng khớp với '%s'"
#, c-format
msgid "invalid line while parsing alternate refs: %s"
-msgstr "dòng không hợp lệ trong khi phân tích các tham chiếu thay thế: %s"
+msgstr "dòng không hợp lệ trong khi Ä‘á»c các tham chiếu thay thế: %s"
#, c-format
msgid "attempting to mmap %<PRIuMAX> over limit %<PRIuMAX>"
@@ -17111,15 +18100,19 @@ msgstr "tập tin đối tượng %s trống rỗng"
#, c-format
msgid "corrupt loose object '%s'"
-msgstr "đối tượng mất há»ng “%sâ€"
+msgstr "đối tượng mất há»ng '%s'"
#, c-format
msgid "garbage at end of loose object '%s'"
-msgstr "gặp rác tại cuối cá»§a đối tượng bị mất “%sâ€"
+msgstr "gặp rác tại cuối của đối tượng bị mất '%s'"
+
+#, c-format
+msgid "unable to open loose object %s"
+msgstr "không thể mở đối tượng mất %s"
#, c-format
msgid "unable to parse %s header"
-msgstr "không thể phân tích phần đầu cá»§a “%sâ€"
+msgstr "không thể Ä‘á»c phần đầu cá»§a '%s'"
msgid "invalid object type"
msgstr "kiểu đối tượng không hợp lệ"
@@ -17133,31 +18126,36 @@ msgid "header for %s too long, exceeds %d bytes"
msgstr "phần đầu cho %s quá dài, vượt quá %d byte"
#, c-format
-msgid "failed to read object %s"
-msgstr "gặp lá»—i khi Ä‘á»c đối tượng “%sâ€"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "đối tượng mất %s (được lưu trong %s) bị há»ng"
#, c-format
msgid "replacement %s not found for %s"
msgstr "c%s thay thế không được tìm thấy cho %s"
#, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "đối tượng mất %s (được lưu trong %s) bị há»ng"
-
-#, c-format
msgid "packed object %s (stored in %s) is corrupt"
msgstr "đối tượng đã đóng gói %s (được lưu trong %s) bị há»ng"
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "thiếu ánh xạ %s sang %s"
+
+#, c-format
+msgid "unable to open %s"
+msgstr "không thể mở %s"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "tập tin '%s' và '%s' có nội dung khác nhau"
+
+#, c-format
msgid "unable to write file %s"
msgstr "không thể ghi tập tin %s"
#, c-format
msgid "unable to set permission to '%s'"
-msgstr "không thể đặt quyá»n thành “%sâ€"
-
-msgid "file write error"
-msgstr "lỗi ghi tập tin"
+msgstr "không thể đặt quyá»n thành '%s'"
msgid "error when closing loose object file"
msgstr "gặp lỗi trong khi đóng tập tin đối tượng"
@@ -17175,7 +18173,7 @@ msgstr "không thể ghi tập tin đối tượng đã mất"
#, c-format
msgid "unable to deflate new object %s (%d)"
-msgstr "không thể xả nén đối tượng mới %s (%d)"
+msgstr "không thể giải nén đối tượng mới %s (%d)"
#, c-format
msgid "deflateEnd on object %s failed (%d)"
@@ -17186,22 +18184,43 @@ msgid "confused by unstable object source data for %s"
msgstr "chưa rõ ràng baowir dữ liệu nguồn đối tượng không ổn định cho %s"
#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "đối tượng ghi dòng %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "không thể stream deflate đối tượng mới (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "deflateEnd trên đối tượng stream gặp lỗi (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "tạo thư mục %s gặp lỗi"
+
+#, c-format
msgid "cannot read object for %s"
msgstr "không thể Ä‘á»c đối tượng cho %s"
-msgid "corrupt commit"
-msgstr "lần chuyển giao sai há»ng"
+#, c-format
+msgid "cannot map object %s to %s"
+msgstr "không thể ánh xạ đối tượng %s sang %s"
-msgid "corrupt tag"
-msgstr "thẻ sai há»ng"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "đối tượng không qua fsck (kiểm tra toàn vẹn): %s"
+
+msgid "refusing to create malformed object"
+msgstr "Từ chối tạo đối tượng lỗi"
#, c-format
msgid "read error while indexing %s"
-msgstr "gặp lá»—i Ä‘á»c khi đánh mục lục %s"
+msgstr "gặp lá»—i Ä‘á»c khi đánh chỉ mục %s"
#, c-format
msgid "short read while indexing %s"
-msgstr "không Ä‘á»c ngắn khi đánh mục lục %s"
+msgstr "không Ä‘á»c ngắn khi đánh chỉ mục %s"
#, c-format
msgid "%s: failed to insert into database"
@@ -17213,11 +18232,7 @@ msgstr "%s: kiểu tập tin không được hỗ trợ"
#, c-format
msgid "%s is not a valid '%s' object"
-msgstr "%s không phải là một đối tượng “%s†hợp lệ"
-
-#, c-format
-msgid "unable to open %s"
-msgstr "không thể mở %s"
+msgstr "%s không phải là một đối tượng '%s' hợp lệ"
#, c-format
msgid "hash mismatch for %s (expected %s)"
@@ -17229,15 +18244,15 @@ msgstr "không thể mmap %s"
#, c-format
msgid "unable to unpack header of %s"
-msgstr "không thể giải gói phần đầu cá»§a “%sâ€"
+msgstr "không thể giải gói phần đầu của '%s'"
#, c-format
msgid "unable to parse header of %s"
-msgstr "không thể phân tích phần đầu cá»§a “%sâ€"
+msgstr "không thể Ä‘á»c phần đầu cá»§a '%s'"
#, c-format
msgid "unable to unpack contents of %s"
-msgstr "không thể giải gói ná»™i dung cá»§a “%sâ€"
+msgstr "không thể giải gói nội dung của '%s'"
#. TRANSLATORS: This is a line of ambiguous object
#. output shown when we cannot look up or parse the
@@ -17279,7 +18294,7 @@ msgstr "%s thẻ %s - %s"
#.
#, c-format
msgid "%s [bad tag, could not parse it]"
-msgstr "%s [thẻ sai, không thể phân tích cú pháp nó]"
+msgstr "%s [thẻ sai, không hiểu cú pháp nó]"
#. TRANSLATORS: This is a line of ambiguous <type>
#. object output. E.g. "deadbeef tree".
@@ -17322,65 +18337,64 @@ msgid ""
"examine these refs and maybe delete them. Turn this message off by\n"
"running \"git config advice.objectNameWarning false\""
msgstr ""
-"Git thưá»ng không bao giá» tạo tham chiếu mà nó kết thúc vá»›i 40 ký tá»± hex\n"
-"bởi vì nó sẽ bị bỠqua khi bạn chỉ định 40-hex. Những tham chiếu này\n"
-"có lẽ được tạo ra bởi một sai sót nào đó. Ví dụ,\n"
+"Git thưá»ng không bao giá» tạo tham chiếu kết thúc vá»›i 40 ký tá»± hex\n"
+"bởi vì nó sẽ bị bỠqua khi bạn chỉ định 40 ký tự hex. Những tham chiếu\n"
+"này có lẽ đã được tạo nhầm. Ví dụ,\n"
"\n"
-" git switch -c $br $(git rev-parse …)\n"
+" git switch -c $br $(git rev-parse ...)\n"
"\n"
-"với \"$br\" không hiểu lý do vì sao trống rỗng và một tham chiếu 40-hex được "
-"tạo ra.\n"
-"Xin hãy kiểm tra những tham chiếu này và có thể xóa chúng Ä‘i. Tắt lá»i nhắn "
-"này\n"
-"bằng cách chạy lệnh \"git config advice.objectNameWarning false\""
+"với \"$br\" không hiểu lý do vì sao rỗng và tạo ra tham chiếu 40-hex.\n"
+" Xin hãy kiểm tra những tham chiếu này và xóa chúng đi nếu cần. Tắt\n"
+"lá»i nhắn này bằng cách chạy lệnh \"git config advice.objectNameWarning "
+"false\""
#, c-format
msgid "log for '%.*s' only goes back to %s"
-msgstr "nhật ký cho “%.*s†chỉ trở lại đến %s"
+msgstr "nhật ký cho '%.*s' chỉ kéo dài đến %s"
#, c-format
msgid "log for '%.*s' only has %d entries"
-msgstr "nhật ký cho “%.*s†chỉ có %d mục"
+msgstr "nhật ký cho '%.*s' chỉ có %d mục"
#, c-format
msgid "path '%s' exists on disk, but not in '%.*s'"
-msgstr "đưá»ng dẫn “%s†có ở trên đĩa, nhưng không trong “%.*sâ€"
+msgstr "đưá»ng dẫn '%s' có ở trên đĩa, nhưng không trong '%.*s'"
#, c-format
msgid ""
"path '%s' exists, but not '%s'\n"
"hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"
msgstr ""
-"đưá»ng dẫn “%s†tồn tại, nhưng không phải “%sâ€\n"
-"gợi ý: Có phải ý bạn là “%.*s:%s†aka “%.*s:./%s�"
+"đưá»ng dẫn '%s' tồn tại, nhưng không phải '%s'\n"
+"gợi ý: Có phải ý bạn là '%.*s:%s' aka '%.*s:./%s'?"
#, c-format
msgid "path '%s' does not exist in '%.*s'"
-msgstr "đưá»ng dẫn “%s†không tồn tại trong “%.*sâ€"
+msgstr "đưá»ng dẫn '%s' không tồn tại trong '%.*s'"
#, c-format
msgid ""
"path '%s' is in the index, but not at stage %d\n"
"hint: Did you mean ':%d:%s'?"
msgstr ""
-"đưá»ng dẫn “%s†nằm trong chỉ mục, nhưng không phải ở giai Ä‘oạn %d\n"
-"gợi ý: Có phải ý bạn là “:%d:%s�"
+"đưá»ng dẫn '%s' nằm trong chỉ mục, nhưng không phải ở giai Ä‘oạn %d\n"
+"gợi ý: Có phải ý bạn là ':%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 ""
-"đưá»ng dẫn “%s†nằm trong chỉ mục, nhưng không phải “%sâ€\n"
-"gợi ý: Có phải ý bạn là “:% d:%s “ aka “:%d:./%s�"
+"đưá»ng dẫn '%s' nằm trong chỉ mục, nhưng không phải '%s'\n"
+"gợi ý: Có phải ý bạn là ':% d:%s ' aka ':%d:./%s'?"
#, c-format
msgid "path '%s' exists on disk, but not in the index"
-msgstr "đưá»ng dẫn “%s†tồn tại trên đĩa, nhưng không có trong chỉ mục"
+msgstr "đưá»ng dẫn '%s' tồn tại trên đĩa, nhưng không có trong chỉ mục"
#, c-format
msgid "path '%s' does not exist (neither on disk nor in the index)"
-msgstr "đưá»ng dẫn “%s†không tồn tại (không trên đĩa cÅ©ng không trong mục lục)"
+msgstr "đưá»ng dẫn '%s' không tồn tại (không trên đĩa cÅ©ng không trong chỉ mục)"
msgid "relative path syntax can't be used outside working tree"
msgstr "cú pháp đưá»ng dẫn tương đối không thể thể dùng ngoài cây làm việc"
@@ -17391,7 +18405,7 @@ msgstr "<object>:<path> cần cả hai, nhưng chỉ <object> '%s' được đư
#, c-format
msgid "invalid object name '%.*s'."
-msgstr "“%.*s†không phải là tên đối tượng hợp lệ."
+msgstr "'%.*s' không phải là tên đối tượng hợp lệ."
#, c-format
msgid "invalid object type \"%s\""
@@ -17407,26 +18421,160 @@ msgstr "đối tượng %s có mã kiểu %d chưa biết"
#, c-format
msgid "unable to parse object: %s"
-msgstr "không thể phân tích đối tượng: “%sâ€"
+msgstr "không thể Ä‘á»c đối tượng: '%s'"
#, c-format
msgid "hash mismatch %s"
msgstr "mã băm không khớp %s"
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "đối tượng trùng lặp khi ghi chỉ mục bitmap: %s"
+
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "đã cố ghi lần chuyển giao không được chá»n: '%s'"
+
+msgid "too many pseudo-merges"
+msgstr "có quá nhiá»u lần pseudo-merge"
+
+msgid "trying to write commit not in index"
+msgstr "đã thử ghi lần chuyển giao nằm ngoài chỉ mục"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "không thể Ä‘á»c chỉ mục bitmap (bị há»ng?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "chỉ mục bitmap bị há»ng (quá nhá»)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "tập tin chỉ mục bitmap bị há»ng (sai phần đầu)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "không hỗ trợ tập tin chỉ mục bitmap phiên bản '%d'"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr "tập tin chỉ mục bitmap bị há»ng (quá ngắn để chứa bá»™ đệm mã băm)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr "tập tin chỉ mục bitmap bị há»ng (quá ngắn để chứa bảng tìm kiếm)"
+
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"tập tin chỉ mục bitmap bị há»ng (quá ngắn để chứa đỠmục bảng pseudo-merge)"
+
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr "tập tin chỉ mục bitmap bị há»ng (quá ngắn để chứa bảng pseudo-merge)"
+
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "tập tin chỉ mục bitmap bị há»ng, bảng pseudo-merge quá ngắn"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "đối tượng trùng lặp trong bitmap: '%s'"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "ewah bitmap bị há»ng: phần đầu bị cắt ngắn cho mục thứ %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "ewah bitmap bị há»ng: mục chuyển giao thứ %u nằm ngoài phạm vi"
+
+msgid "corrupted bitmap pack index"
+msgstr "chỉ mục gói bitmap bị há»ng"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "XOR offset không hợp lệ trong chỉ mục gói bitmap"
+
+msgid "cannot fstat bitmap file"
+msgstr "không thể fstat file bitmap"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "tổng kiểm ra trong MIDX và bitmap không khớp"
+
msgid "multi-pack bitmap is missing required reverse index"
-msgstr "ánh xạ multi-pack thiếu mục lục để dành cần thiết"
+msgstr "bitmap multi-pack thiếu chỉ mục để dành cần thiết"
#, c-format
msgid "could not open pack %s"
-msgstr "không thể mở gói “%sâ€"
+msgstr "không thể mở gói '%s'"
+
+msgid "could not determine MIDX preferred pack"
+msgstr "không thể xác định gói MIDX ưa dùng"
#, c-format
msgid "preferred pack (%s) is invalid"
-msgstr "\"preferred pack\" (%s) không hợp lệ"
+msgstr "preferred pack (%s) không hợp lệ"
+
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "bảng tìm kiếm bitmap bị há»ng: vị trí bá»™ ba nằm ngoài chỉ mục"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr "bảng tìm kiếm bitmap bị há»ng: chuá»—i xor vượt quá số lượng mục"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr "bảng tìm kiếm bitmap bị há»ng: mục chuyển giao thứ %u nằm ngoài phạm vi"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr ""
+"ewah bitmap bị há»ng: bitmap lần chuyển giao \"%s\" có phần đầu bị cắt ngắn"
+
+#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "không thể Ä‘á»c gói: '%s', vô hiệu sá»­ dụng lại gói"
+
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "không thể tính giá trị gói ưa dùng, vô hiệu sử dụng lại gói"
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "không tìm thấy đối tượng '%s' trong type bitmap"
+
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "đối tượng '%s' không có kiểu độc nhất"
#, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "không thể tìm thấy %s trong gói “%s†tại vị trí %<PRIuMAX>"
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "đối tượng '%s': kiểu '%s', cần: '%s'"
+
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "không tìm thấy đối tượng trong bitmap: %s"
+
+msgid "failed to load bitmap indexes"
+msgstr "Ä‘á»c chỉ mục bitmap thất bại"
+
+msgid "you must specify exactly one commit to test"
+msgstr "bạn phải chỉ định các lần chuyển giao muốn kiểm tra"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "lần chuyển giao '%s' không có chỉ mục bitmap"
+
+msgid "mismatch in bitmap results"
+msgstr "kết quả bitmap không khớp"
+
+#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "chỉ mục pseudo-merge vượt ngoài phạm vi (%<PRIu32> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "không thể tìm thấy '%s' trong gói '%s' tại vị trí %<PRIuMAX>"
+
+#, c-format
+msgid "unable to get disk usage of '%s'"
+msgstr "không thể lấy dung lượng đĩa đã dùng của %s"
+
+#, c-format
+msgid "bitmap file '%s' has invalid checksum"
+msgstr "file bitmap '%s' có checksum không hợp lệ"
#, c-format
msgid "mtimes file %s is too small"
@@ -17438,7 +18586,7 @@ msgstr "tập tin mtimes %s có chữ ký chưa biết"
#, c-format
msgid "mtimes file %s has unsupported version %<PRIu32>"
-msgstr "tệp mtimes %s có phiên bản không được hỗ trợ %<PRIu32>"
+msgstr "tập mtimes %s có phiên bản không được hỗ trợ %<PRIu32>"
#, c-format
msgid "mtimes file %s has unsupported hash id %<PRIu32>"
@@ -17462,18 +18610,31 @@ msgstr "tập tin reverse-index %s có chữ ký chưa biết"
#, c-format
msgid "reverse-index file %s has unsupported version %<PRIu32>"
-msgstr "tệp chỉ mục ngược %s có phiên bản không được hỗ trợ %<PRIu32>"
+msgstr "tập chỉ mục ngược %s có phiên bản không được hỗ trợ %<PRIu32>"
#, c-format
msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
-msgstr "tệp chỉ mục ngược %s có id mã băm không được hỗ trợ %<PRIu32>"
+msgstr "tập chỉ mục ngược %s có id mã băm không được hỗ trợ %<PRIu32>"
+
+msgid "invalid checksum"
+msgstr "checksum không hợp lệ"
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "vị trí mục xét duyệt không hợp lệ %<PRIu64>: %<PRIu32> != %<PRIu32>"
+
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "chunk chỉ mục ngược của chỉ mục đa gói có kích thước sai"
+
+msgid "could not determine preferred pack"
+msgstr "không thể xác định gói ưa dùng"
msgid "cannot both write and verify reverse index"
-msgstr "không thể cùng lúc Ä‘á»c và xác minh được bảng mục lục đảo ngược"
+msgstr "không thể cùng lúc gh và xác minh chỉ mục ngược"
#, c-format
msgid "could not stat: %s"
-msgstr "không thể lấy thông tin thống kê: %s"
+msgstr "không thể stat: %s"
#, c-format
msgid "failed to make %s readable"
@@ -17481,7 +18642,7 @@ msgstr "gặp lá»—i làm cho %s Ä‘á»c được"
#, c-format
msgid "could not write '%s' promisor file"
-msgstr "không thể ghi tập tin promisor “%sâ€"
+msgstr "không thể ghi tập tin promisor '%s'"
msgid "offset before end of packfile (broken .idx?)"
msgstr "vị trí tương đối trước Ä‘iểm kết thúc cá»§a tập tin gói (.idx há»ng à?)"
@@ -17492,44 +18653,36 @@ msgstr "tập tin gói %s không thể được ánh xạ %s"
#, c-format
msgid "offset before start of pack index for %s (corrupt index?)"
-msgstr "vị trí tương đối nằm trước chỉ mục gói cho %s (mục lục bị há»ng à?)"
+msgstr "vị trí tương đối nằm trước chỉ mục gói cho %s (chỉ mục bị há»ng à?)"
#, c-format
msgid "offset beyond end of pack index for %s (truncated index?)"
msgstr ""
-"vị trí tương đối vượt quá cuối của chỉ mục gói cho %s (mục lục bị cắt cụt à?)"
+"vị trí tương đối vượt quá cuối của chỉ mục gói cho %s (chỉ mục bị cắt cụt à?)"
#, c-format
msgid "malformed expiration date '%s'"
-msgstr "ngày tháng hết hạn dị hình “%sâ€"
+msgstr "ngày tháng hết hạn sai quy cách '%s'"
#, c-format
msgid "option `%s' expects \"always\", \"auto\", or \"never\""
-msgstr "tùy chá»n “%s†cần \"always\", \"auto\", hoặc \"never\""
+msgstr "tùy chá»n '%s' cần \"always\", \"auto\", hoặc \"never\""
#, c-format
msgid "malformed object name '%s'"
-msgstr "tên đối tượng dị hình “%sâ€"
+msgstr "tên đối tượng sai quy cách '%s'"
#, c-format
msgid "option `%s' expects \"%s\" or \"%s\""
-msgstr "tùy chá»n “%s†cần \"%s\" hoặc \"%s\""
+msgstr "tùy chá»n '%s' cần \"%s\" hoặc \"%s\""
#, c-format
msgid "%s requires a value"
-msgstr "“%s†yêu cầu một giá trị"
-
-#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s là xung khắc với %s"
-
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s : xung khắc với các cái khác"
+msgstr "'%s' yêu cầu một giá trị"
#, c-format
msgid "%s takes no value"
-msgstr "%s k nhận giá trị"
+msgstr "%s không nhận giá trị"
#, c-format
msgid "%s isn't available"
@@ -17545,26 +18698,29 @@ msgstr "tùy chá»n chưa rõ rang: %s (nên là --%s%s hay --%s%s)"
#, c-format
msgid "did you mean `--%s` (with two dashes)?"
-msgstr "có phải ý bạn là “--%s“ (với hai dấu gạch ngang)?"
+msgstr "có phải ý bạn là '--%s' (với hai dấu gạch ngang)?"
#, c-format
msgid "alias of --%s"
msgstr "bí danh của --%s"
+msgid "need a subcommand"
+msgstr "cần câu lệnh con"
+
#, c-format
msgid "unknown option `%s'"
-msgstr "không hiểu tùy chá»n “%sâ€"
+msgstr "không hiểu tùy chá»n '%s'"
#, c-format
msgid "unknown switch `%c'"
-msgstr "không hiểu tùy chá»n “%câ€"
+msgstr "không hiểu tùy chá»n '%c'"
#, c-format
msgid "unknown non-ascii option in string: `%s'"
-msgstr "không hiểu tùy chá»n non-ascii trong chuá»—i: “%sâ€"
+msgstr "không hiểu tùy chá»n non-ascii trong chuá»—i: '%s'"
msgid "..."
-msgstr "…"
+msgstr "..."
#, c-format
msgid "usage: %s"
@@ -17607,6 +18763,10 @@ msgstr " %s"
msgid "-NUM"
msgstr "-Sá»"
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "ngược lại với --no-%s"
+
msgid "expiry-date"
msgstr "ngày hết hạn"
@@ -17622,8 +18782,11 @@ msgstr "im lặng hơn nữa"
msgid "use <n> digits to display object names"
msgstr "sử dụng <n> chữ số để hiển thị tên đối tượng"
+msgid "prefixed path to initial superproject"
+msgstr "đưá»ng dẫn tiá»n tố đến project cha ban đầu"
+
msgid "how to strip spaces and #comments from message"
-msgstr "làm thế nào để cắt bỠkhoảng trắng và #ghichú từ mẩu tin nhắn"
+msgstr "làm thế nào để cắt bỠkhoảng trắng và #ghi-chú từ tin nhắn"
msgid "read pathspec from file"
msgstr "Ä‘á»c đặc tả đưá»ng dẫn từ tập tin"
@@ -17635,15 +18798,23 @@ msgstr ""
"tá»± NULL"
#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "sai giá trị kiểu boolean của cấu hình '%s' cho '%s'"
+
+#, c-format
+msgid "failed to parse %s"
+msgstr "gặp lá»—i khi Ä‘á»c cú pháp %s"
+
+#, c-format
msgid "Could not make %s writable by group"
msgstr "Không thể làm %s được ghi bởi nhóm"
msgid "Escape character '\\' not allowed as last character in attr value"
msgstr ""
-"Ký tự thoát chuỗi “\\†không được phép là ký tự cuối trong giá trị thuộc tính"
+"Ký tự thoát chuỗi '\\' không được phép là ký tự cuối trong giá trị thuộc tính"
msgid "Only one 'attr:' specification is allowed."
-msgstr "Chỉ có một đặc tả “attr:†là được phép."
+msgstr "Chỉ có một đặc tả 'attr:' là được phép."
msgid "attr spec must not be empty"
msgstr "đặc tả attr phải không được để trống"
@@ -17653,42 +18824,45 @@ msgid "invalid attribute name %s"
msgstr "tên thuộc tính không hợp lệ %s"
msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
-msgstr ""
-"các cài đặt đặc tả đưá»ng dẫn “glob†và “noglob†toàn cục là xung khắc nhau"
+msgstr "các cài đặt đặc tả đưá»ng dẫn 'glob' và 'noglob' toàn cục là xung khắc"
msgid ""
"global 'literal' pathspec setting is incompatible with all other global "
"pathspec settings"
msgstr ""
-"cài đặt đặc tả đưá»ng dẫn “literal†toàn cục là xung khắc vá»›i các cài đặt đặc "
-"tả đưá»ng dẫn toàn cục khác"
+"cài đặt đặc tả đưá»ng dẫn 'literal' toàn cục không tương thích vá»›i các cài "
+"đặt đặc tả đưá»ng dẫn toàn cục khác"
msgid "invalid parameter for pathspec magic 'prefix'"
-msgstr "tham số không hợp lệ cho “tiá»n tố†màu nhiệm đặc tả đưá»ng đẫn"
+msgstr "tham số không hợp lệ cho đặc tả đưá»ng đẫn đặc biệt 'prefix'"
#, c-format
msgid "Invalid pathspec magic '%.*s' in '%s'"
-msgstr "Số màu nhiệm đặc tả đưá»ng dẫn không hợp lệ “%.*s†trong “%sâ€"
+msgstr "Äặc tả đưá»ng dẫn không hợp lệ '%.*s' trong '%s'"
#, c-format
msgid "Missing ')' at the end of pathspec magic in '%s'"
-msgstr "Thiếu “)†tại cuối cá»§a số màu nhiệm đặc tả đưá»ng dẫn trong “%sâ€"
+msgstr "Thiếu ')' tại cuối cá»§a đặc tả đưá»ng dẫn trong '%s'"
#, c-format
msgid "Unimplemented pathspec magic '%c' in '%s'"
-msgstr "Chưa viết mã cho số màu nhiệm đặc tả đưá»ng dẫn “%c†trong “%sâ€"
+msgstr "Chưa há»— trợ đặc tả đưá»ng dẫn '%c' trong '%s'"
#, c-format
msgid "%s: 'literal' and 'glob' are incompatible"
-msgstr "%s: “literal†và “glob†xung khắc nhau"
+msgstr "%s: 'literal' và 'glob' xung khắc"
+
+#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "'%s' nằm ngoài cây thư mục"
#, c-format
msgid "%s: '%s' is outside repository at '%s'"
-msgstr "%s: “%s†ngoài má»™t kho chứa tại “%sâ€"
+msgstr "%s: '%s' nằm ngoài một kho chứa tại '%s'"
#, c-format
msgid "'%s' (mnemonic: '%c')"
-msgstr "“%s†(mnemonic: “%câ€)"
+msgstr "'%s' (mnemonic: '%c')"
#, c-format
msgid "%s: pathspec magic not supported by this command: %s"
@@ -17696,7 +18870,7 @@ msgstr "%s: số mầu nhiệm đặc tả đưá»ng dẫn chưa được há»— t
#, c-format
msgid "pathspec '%s' is beyond a symbolic link"
-msgstr "đặc tả đưá»ng dẫn “%s†vượt ra ngoài liên kết má»m"
+msgstr "đặc tả đưá»ng dẫn '%s' vượt ra ngoài liên kết má»m"
#, c-format
msgid "line is badly quoted: %s"
@@ -17746,14 +18920,17 @@ msgid "remote error: %s"
msgstr "lỗi máy chủ: %s"
msgid "Refreshing index"
-msgstr "Làm mới bảng mục lục"
+msgstr "Làm mới chỉ mục"
#, c-format
msgid "unable to create threaded lstat: %s"
-msgstr "không thể tạo tuyến trình lstat: %s"
+msgstr "không thể tạo tiến trình lstat: %s"
msgid "unable to parse --pretty format"
-msgstr "không thể phân tích định dạng --pretty"
+msgstr "không thể Ä‘á»c định dạng --pretty"
+
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "vô hiệu lazy fetching; một số đối tượng sẽ không có sẵn"
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote: không thể rẽ nhánh tuyến trình con fetch"
@@ -17762,12 +18939,15 @@ msgid "promisor-remote: could not write to fetch subprocess"
msgstr "promisor-remote: không thể ghi tiến trình con fetch"
msgid "promisor-remote: could not close stdin to fetch subprocess"
-msgstr ""
-"promisor-remote: không thể đóng đầu vào tiêu chuẩn tiến trình con fetch"
+msgstr "promisor-remote: không thể đóng stdin tiến trình con fetch"
#, c-format
msgid "promisor remote name cannot begin with '/': %s"
-msgstr "tên máy chá»§ hứa hẹn không thể bắt đầu bằng “/â€: %s"
+msgstr "tên máy chủ promisor không thể bắt đầu bằng '/': %s"
+
+#, c-format
+msgid "could not fetch %s from promisor remote"
+msgstr "không thể tải %s từ máy chủ promisor"
msgid "object-info: expected flush after arguments"
msgstr "object-info: cần đẩy dữ liệu lên đĩa sau các tham số"
@@ -17775,39 +18955,101 @@ msgstr "object-info: cần đẩy dữ liệu lên đĩa sau các tham số"
msgid "Removing duplicate objects"
msgstr "Äang gỡ các đối tượng trùng lặp"
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "gặp lá»—i khi Ä‘á»c biểu thức chính quy pseudo-merge cho %s: '%s'"
+
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s phải không âm, dùng mặc định thay thế"
+
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s nên giữa 0 và 1, dùng mặc định thay thế"
+
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s phải dương, dùng mặc định thay thế"
+
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "nhóm pseudo-merge '%s' thiếu mẫu bắt buộc"
+
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr "nhóm pseudo-merge '%s' có unstable threshold trước stable"
+
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"biểu thức chính quy pseudo-merge từ cấu hình có quá nhiá»u nhóm chá»n (tối "
+"đa=%<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "extended pseudo-merge Ä‘á»c ngoài biên (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "mục extended pseudo-merge quá ngắn (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr ""
+"không thể tìm pseudo-merge cho lần chuyển giao %s tại vị trí %<PRIuMAX>"
+
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr "extended pseudo-merge lookup vượt ngoài biên (%<PRIu32> >= %<PRIu32>)"
+
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "Ä‘á»c ngoài biên (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "không thể Ä‘á»c bảng extended pseudo-merge cho lần chuyển giao %s"
+
msgid "could not start `log`"
-msgstr "không thể lấy thông tin thống kê vỠ“log“"
+msgstr "không thể khởi chạy `log`"
msgid "could not read `log` output"
-msgstr "không thể Ä‘á»c kết xuất “logâ€"
+msgstr "không thể Ä‘á»c đầu ra `log`"
#, c-format
msgid "could not parse commit '%s'"
-msgstr "không thể phân tích lần chuyển giao “%sâ€"
+msgstr "không thể Ä‘á»c lần chuyển giao '%s'"
#, c-format
msgid ""
"could not parse first line of `log` output: did not start with 'commit ': "
"'%s'"
msgstr ""
-"không thể phân tích cú pháp dòng đầu tiên cá»§a đầu ra “logâ€: không bắt đầu "
-"bằng “commit â€: “%sâ€"
+"không hiểu cú pháp dòng đầu tiên của đầu ra 'log': không bắt đầu bằng "
+"'commit ': '%s'"
#, c-format
msgid "could not parse git header '%.*s'"
-msgstr "không thể phân tích cú pháp phần đầu git “%.*sâ€"
+msgstr "không hiểu cú pháp phần đầu git '%.*s'"
msgid "failed to generate diff"
msgstr "gặp lỗi khi tạo khác biệt"
#, c-format
msgid "could not parse log for '%s'"
-msgstr "không thể phân tích nhật ký cho “%sâ€"
+msgstr "không thể Ä‘á»c nhật ký cho '%s'"
+
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "extra cruft tip không hợp lệ: '%s'"
+
+msgid "unable to enumerate additional recent objects"
+msgstr "không thể đếm các đối tượng mới thêm"
#, c-format
msgid "will not add file alias '%s' ('%s' already exists in index)"
-msgstr ""
-"sẽ không thêm các bí danh “%s†(“%s†đã có từ trước trong bảng mục lục)"
+msgstr "sẽ không thêm các bí danh '%s' ('%s' đã có từ trước trong chỉ mục)"
msgid "cannot create an empty blob in the object database"
msgstr "không thể tạo một blob rỗng trong cơ sở dữ liệu đối tượng"
@@ -17819,22 +19061,18 @@ msgstr ""
#, c-format
msgid "unable to index file '%s'"
-msgstr "không thể đánh mục lục tập tin “%sâ€"
+msgstr "không thể đánh chỉ mục tập tin '%s'"
#, c-format
msgid "unable to add '%s' to index"
-msgstr "không thể thêm %s vào bảng mục lục"
-
-#, c-format
-msgid "unable to stat '%s'"
-msgstr "không thể lấy thống kê “%sâ€"
+msgstr "không thể thêm %s vào chỉ mục"
#, c-format
msgid "'%s' appears as both a file and as a directory"
-msgstr "%s có vẻ không phải là tập tin và cũng chẳng phải là một thư mục"
+msgstr "%s có vẻ vừa là tập tin và cũng vừa là thư mục"
msgid "Refresh index"
-msgstr "Làm tươi mới bảng mục lục"
+msgstr "Làm mới chỉ mục"
#, c-format
msgid ""
@@ -17858,37 +19096,37 @@ msgstr "chữ ký sai 0x%08x"
#, c-format
msgid "bad index version %d"
-msgstr "phiên bản mục lục sai %d"
+msgstr "phiên bản chỉ mục sai %d"
msgid "bad index file sha1 signature"
-msgstr "chữ ký dạng sha1 cho tập tin mục lục không đúng"
+msgstr "chữ ký dạng sha1 cho tập tin chỉ mục không đúng"
#, c-format
msgid "index uses %.4s extension, which we do not understand"
-msgstr "mục lục dùng phần mở rộng %.4s, cái mà chúng tôi không hiểu được"
+msgstr "chỉ mục dùng phần mở rộng %.4s, cái mà chúng tôi không hiểu được"
#, c-format
msgid "ignoring %.4s extension"
-msgstr "đang lỠđi phần mở rộng %.4s"
+msgstr "đang bỠqua phần mở rộng %.4s"
#, c-format
msgid "unknown index entry format 0x%08x"
-msgstr "không hiểu định dạng mục lục 0x%08x"
+msgstr "không hiểu định dạng chỉ mục 0x%08x"
#, c-format
msgid "malformed name field in the index, near path '%s'"
-msgstr "trưá»ng tên sai sạng trong mục lục, gần đưá»ng dẫn “%sâ€"
+msgstr "trưá»ng tên sai sạng trong chỉ mục, gần đưá»ng dẫn '%s'"
msgid "unordered stage entries in index"
-msgstr "các mục tin stage không đúng thứ tự trong mục lục"
+msgstr "các mục tin stage không đúng thứ tự trong chỉ mục"
#, c-format
msgid "multiple stage entries for merged file '%s'"
-msgstr "nhiá»u mục stage cho tập tin hòa trá»™n “%sâ€"
+msgstr "nhiá»u mục stage cho tập tin hòa trá»™n '%s'"
#, c-format
msgid "unordered stage entries for '%s'"
-msgstr "các mục tin stage không đúng thứ tá»± cho “%sâ€"
+msgstr "các mục tin stage không đúng thứ tự cho '%s'"
#, c-format
msgid "unable to create load_cache_entries thread: %s"
@@ -17900,19 +19138,19 @@ msgstr "không thể gia nhập tuyến load_cache_entries: %s"
#, c-format
msgid "%s: index file open failed"
-msgstr "%s: mở tập tin mục lục gặp lỗi"
+msgstr "%s: mở tập tin chỉ mục gặp lỗi"
#, c-format
msgid "%s: cannot stat the open index"
-msgstr "%s: không thể lấy thống kê bảng mục lục đã mở"
+msgstr "%s: không thể stat chỉ mục đã mở"
#, c-format
msgid "%s: index file smaller than expected"
-msgstr "%s: tập tin mục lục nhỠhơn mong đợi"
+msgstr "%s: tập tin chỉ mục nhỠhơn mong đợi"
#, c-format
msgid "%s: unable to map index file%s"
-msgstr "%s: không thể ánh xạ tập tin mục lục%s"
+msgstr "%s: không thể ánh xạ tập tin chỉ mục%s"
#, c-format
msgid "unable to create load_index_extensions thread: %s"
@@ -17924,21 +19162,17 @@ msgstr "không thể gia nhập tuyến load_index_extensions: %s"
#, c-format
msgid "could not freshen shared index '%s'"
-msgstr "không thể làm tươi má»›i mục lục đã chia sẻ “%sâ€"
+msgstr "không thể làm tươi mới chỉ mục đã chia sẻ '%s'"
#, c-format
msgid "broken index, expect %s in %s, got %s"
-msgstr "mục lục bị há»ng, cần %s trong %s, nhưng lại nhận được %s"
+msgstr "chỉ mục bị há»ng, cần %s trong %s, nhưng lại có %s"
msgid "cannot write split index for a sparse index"
-msgstr "không thể ghi mục lục chia tách cho \"sparse index\""
+msgstr "không thể ghi chỉ mục chia tách cho sparse index"
msgid "failed to convert to a sparse-index"
-msgstr "gặp lỗi khi chuyển đổi sang \"sparse-index\""
-
-#, c-format
-msgid "could not stat '%s'"
-msgstr "không thể lấy thông tin thống kê vỠ“%sâ€"
+msgstr "gặp lỗi khi chuyển đổi sang sparse-index"
#, c-format
msgid "unable to open git dir: %s"
@@ -17946,24 +19180,32 @@ msgstr "không thể mở thư mục git: %s"
#, c-format
msgid "unable to unlink: %s"
-msgstr "không thể bá» liên kết (unlink): “%sâ€"
+msgstr "không thể bỠliên kết (unlink): '%s'"
#, c-format
msgid "cannot fix permission bits on '%s'"
-msgstr "không thể sá»­a các bít phân quyá»n trên “%sâ€"
+msgstr "không thể sá»­a các bít phân quyá»n trên '%s'"
#, c-format
msgid "%s: cannot drop to stage #0"
msgstr "%s: không thể xóa bỠstage #0"
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "trạng thái lệnh diff không như mong đợi %c"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "gỡ bỠ'%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 ""
-"Bạn có thể sửa nó bằng “git rebase --edit-todo†và sau đó chạy “git rebase --"
-"continueâ€.\n"
-"Hoặc là bạn có thể bãi bá» việc cải tổ bằng “git rebase --abortâ€.\n"
+"Bạn có thể sửa nó bằng 'git rebase --edit-todo' và sau đó chạy 'git rebase --"
+"continue'.\n"
+"Hoặc là bạn có thể huỷ bỠviệc cải tổ bằng 'git rebase --abort'.\n"
#, c-format
msgid ""
@@ -17988,9 +19230,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 ""
@@ -17998,7 +19243,7 @@ msgstr ""
"Các lệnh:\n"
"p, pick <commit> = dùng lần chuyển giao\n"
"r, reword <commit> = dùng lần chuyển giao, nhưng sửa lại phần chú thích\n"
-"e, edit <commit> = dùng lần chuyển giao, nhưng dừng lại để tu bổ (amend)\n"
+"e, edit <commit> = dùng lần chuyển giao, nhưng dừng lại để tu bổ\n"
"s, squash <commit> = dùng lần chuyển giao, nhưng trộn vào lần chuyển giao kế "
"trước\n"
"f, fixup [-C | -c] <commit> = giống như \"squash\", nhưng chỉ giữ lại phần "
@@ -18008,34 +19253,36 @@ msgstr ""
" chỉ giữ ghi chú của lần chuyển giao này; -c giống như -C "
"nhưng\n"
" mở trình biên soạn\n"
-"x, exec <commit> = chạy lệnh (phần còn lại cá»§a dòng) dùng hệ vá»\n"
-"b, break = dừng tại đây (tiếp tục cải tổ sau này bằng “git rebase --"
-"continueâ€)\n"
+"x, exec <commit> = chạy lệnh (phần còn lại của dòng) dùng shell\n"
+"b, break = dừng tại đây (tiếp tục cải tổ sau này bằng 'git rebase --"
+"continue')\n"
"d, drop <commit> = xóa bỠlần chuyển giao\n"
-"l, label <label> = đánh nhãn HEAD hiện tại bằng một tên\n"
-"t, reset <label> = đặt lại HEAD thành một nhãn\n"
+"l, label <label> = đánh tên nhãn HEAD hiện tại\n"
+"t, reset <label> = đặt lại HEAD vỠmột nhãn\n"
"m, merge [-C <commit> | -c <commit>] <nhãn> [# <một_dòng>]\n"
". tạo một lần chuyển giao hòa trộn sử dụng chú thích của lần chuyển\n"
". giao hòa trộn gốc (hoặc một_dòng, nếu không chỉ định lần chuyển giao "
"hòa\n"
". trộn gốc). Dùng -c <commit> để reword chú thích của lần chuyển "
"giao.\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"
-"Những dòng này có thể được thay đổi thứ tự; chúng chạy từ trên đỉnh xuống "
-"dưới đáy.\n"
+"Những dòng này có thể được thay đổi thứ tự; chúng được thực thi từ trên "
+"xuống dưới.\n"
#, c-format
msgid "Rebase %s onto %s (%d command)"
msgid_plural "Rebase %s onto %s (%d commands)"
-msgstr[0] "Cải tổ %s vào %s (%d lệnh )"
+msgstr[0] "Cải tổ %s vào %s (%d lệnh)"
msgid ""
"\n"
"Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
msgstr ""
"\n"
-"Äừng xóa bất kỳ dòng nào. Dùng “drop†má»™t cách rõ ràng để xóa bá» má»™t lần "
-"chuyển giao.\n"
+"Äừng xóa bất kỳ dòng nào. Dùng 'drop' để xóa bá» má»™t lần chuyển giao.\n"
msgid ""
"\n"
@@ -18063,12 +19310,12 @@ msgid ""
"\n"
msgstr ""
"\n"
-"Tuy nhiên, nếu bạn xóa bá» má»i thứ, việc cải tổ sẽ bị bãi bá».\n"
+"Tuy nhiên, nếu bạn xóa bá» má»i thứ, việc cải tổ sẽ bị huá»· bá».\n"
"\n"
#, c-format
msgid "could not write '%s'."
-msgstr "không thể ghi “%sâ€."
+msgstr "không thể ghi '%s'."
#, c-format
msgid ""
@@ -18090,29 +19337,37 @@ msgstr ""
"Äể tránh thông báo này, dùng \"drop\" má»™t cách rõ ràng để xóa bá» má»™t lần "
"chuyển giao.\n"
"\n"
-"Dùng “git config rebase.missingCommitsCheck†để thay đổi mức độ của cảnh "
+"Dùng 'git config rebase.missingCommitsCheck' để thay đổi mức độ của cảnh "
"báo.\n"
"Cánh ứng xử có thể là: ignore, warn, error.\n"
"\n"
#, c-format
msgid "%s: 'preserve' superseded by 'merges'"
-msgstr "%s: “preserve†bị cấm bởi “mergesâ€"
+msgstr "%s: 'preserve' bị thay bởi 'merges'"
msgid "gone"
-msgstr "đã ra đi"
+msgstr "đã xoá"
#, c-format
msgid "ahead %d"
-msgstr "phía trước %d"
+msgstr "đứng trước %d"
#, c-format
msgid "behind %d"
-msgstr "đằng sau %d"
+msgstr "đứng sau %d"
#, c-format
msgid "ahead %d, behind %d"
-msgstr "trước %d, sau %d"
+msgstr "đứng trước %d, đứng sau %d"
+
+#, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) không nhận các đối số"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "đối số không được thừa nhận %%(%.*s): %s"
#, c-format
msgid "expected format: %%(color:<color>)"
@@ -18131,40 +19386,36 @@ msgid "Integer value expected refname:rstrip=%s"
msgstr "Giá trị nguyên cần tên tham chiếu:rstrip=%s"
#, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "đối số không được thừa nhận %%(%s): %s"
+msgid "expected %%(trailers:key=<value>)"
+msgstr "cần %%(trailers:key=<giá trị>)"
#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) không nhận các đối số"
+msgid "unknown %%(trailers) argument: %s"
+msgstr "không hiểu tham số %%(trailers): %s"
#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) không nhận các đối số"
+msgid "positive value expected contents:lines=%s"
+msgstr "cần nội dung mang giá trị dương:lines=%s"
#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) không nhận các đối số"
+msgid "argument expected for %s"
+msgstr "cần đối số cho %s"
#, c-format
-msgid "expected %%(trailers:key=<value>)"
-msgstr "cần %%(trailers:key=<giá trị>)"
+msgid "positive value expected %s=%s"
+msgstr "cần giá trị dương %s=%s"
#, c-format
-msgid "unknown %%(trailers) argument: %s"
-msgstr "không hiểu tham số %%(trailers): %s"
+msgid "cannot fully parse %s=%s"
+msgstr "không hiểu %s=%s"
#, c-format
-msgid "positive value expected contents:lines=%s"
-msgstr "cần nội dung mang giá trị dương:lines=%s"
+msgid "value expected %s="
+msgstr "cần %s="
#, c-format
msgid "positive value expected '%s' in %%(%s)"
-msgstr "cần giá trị dương “%s†trong %%(%s)"
-
-#, c-format
-msgid "unrecognized email option: %s"
-msgstr "không nhận ra tùy chá»n thư Ä‘iện tá»­: “%sâ€"
+msgstr "cần giá trị dương '%s' trong %%(%s)"
#, c-format
msgid "expected format: %%(align:<width>,<position>)"
@@ -18179,16 +19430,24 @@ msgid "unrecognized width:%s"
msgstr "chiá»u rá»™ng không được thừa nhận:%s"
#, c-format
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "đối số không được thừa nhận %%(%s): %s"
+
+#, c-format
msgid "positive width expected with the %%(align) atom"
-msgstr "cần giá trị độ rộng dương với nguyên tử %%(align)"
+msgstr "cần giá trị độ rộng dương với atom %%(align)"
#, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) không nhận các đối số"
+msgid "expected format: %%(ahead-behind:<committish>)"
+msgstr "cần định dạng: %%(ahead-behind:<committish>)"
+
+#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "cần định dạng: %%(is-base:<committish>)"
#, c-format
msgid "malformed field name: %.*s"
-msgstr "tên trưá»ng dị hình: %.*s"
+msgstr "tên trưá»ng sai quy cách: %.*s"
#, c-format
msgid "unknown field name: %.*s"
@@ -18198,32 +19457,32 @@ msgstr "không hiểu tên trưá»ng: %.*s"
msgid ""
"not a git repository, but the field '%.*s' requires access to object data"
msgstr ""
-"không phải là má»™t kho git, nhưng trưá»ng “%.*s†yêu cầu truy cập vào dữ liệu "
+"không phải là má»™t kho git, nhưng trưá»ng '%.*s' yêu cầu truy cập vào dữ liệu "
"đối tượng"
#, c-format
msgid "format: %%(%s) atom used without a %%(%s) atom"
-msgstr "định dạng: nguyên tử %%(%s) được dùng mà không có nguyên tử %%(%s)"
+msgstr "định dạng: atom %%(%s) được dùng mà không có atom %%(%s)"
#, c-format
msgid "format: %%(then) atom used more than once"
-msgstr "định dạng: nguyên tá»­ %%(then) được dùng nhiá»u hÆ¡n má»™t lần"
+msgstr "định dạng: atom %%(then) được dùng nhiá»u hÆ¡n má»™t lần"
#, c-format
msgid "format: %%(then) atom used after %%(else)"
-msgstr "định dạng: nguyên tử %%(then) được dùng sau %%(else)"
+msgstr "định dạng: atom %%(then) được dùng sau %%(else)"
#, c-format
msgid "format: %%(else) atom used more than once"
-msgstr "định dạng: nguyên tá»­ %%(else) được dùng nhiá»u hÆ¡n má»™t lần"
+msgstr "định dạng: atom %%(else) được dùng nhiá»u hÆ¡n má»™t lần"
#, c-format
msgid "format: %%(end) atom used without corresponding atom"
-msgstr "định dạng: nguyên tử %%(end) được dùng mà không có nguyên tử tương ứng"
+msgstr "định dạng: atom %%(end) được dùng mà không có atom tương ứng"
#, c-format
msgid "malformed format string %s"
-msgstr "chuỗi định dạng dị hình %s"
+msgstr "chuỗi định dạng sai quy cách %s"
#, c-format
msgid "this command reject atom %%(%.*s)"
@@ -18233,6 +19492,9 @@ msgstr "lệnh này từ chối atom %%(%.*s)"
msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
msgstr "--format=%.*s không thể được dùng với --python, --shell, --tcl"
+msgid "failed to run 'describe'"
+msgstr "gặp lỗi khi chạy 'describe'"
+
#, c-format
msgid "(no branch, rebasing %s)"
msgstr "(không nhánh, đang cải tổ %s)"
@@ -18266,27 +19528,27 @@ msgstr "parse_object_buffer gặp lỗi trên %s cho %s"
#, c-format
msgid "malformed object at '%s'"
-msgstr "đối tượng dị hình tại “%sâ€"
+msgstr "đối tượng sai quy cách tại '%s'"
#, c-format
msgid "ignoring ref with broken name %s"
-msgstr "Ä‘ang lá» Ä‘i tham chiếu vá»›i tên há»ng %s"
+msgstr "Ä‘ang bá» qua tham chiếu vá»›i tên há»ng %s"
#, c-format
msgid "ignoring broken ref %s"
-msgstr "Ä‘ang lá» Ä‘i tham chiếu há»ng %s"
+msgstr "Ä‘ang bá» qua tham chiếu há»ng %s"
#, c-format
msgid "format: %%(end) atom missing"
-msgstr "định dạng: thiếu nguyên tử %%(end)"
+msgstr "định dạng: thiếu atom %%(end)"
#, c-format
msgid "malformed object name %s"
-msgstr "tên đối tượng dị hình %s"
+msgstr "tên đối tượng sai quy cách %s"
#, c-format
msgid "option `%s' must point to a commit"
-msgstr "tùy chá»n “%s†phải chỉ đến má»™t lần chuyển giao"
+msgstr "tùy chá»n '%s' phải chỉ đến má»™t lần chuyển giao"
msgid "key"
msgstr "khóa"
@@ -18294,17 +19556,20 @@ msgstr "khóa"
msgid "field name to sort on"
msgstr "tên trưá»ng cần sắp xếp"
+msgid "exclude refs which match pattern"
+msgstr "không bao gồm các tham chiếu khớp với mẫu"
+
#, c-format
msgid "not a reflog: %s"
msgstr "không phải một reflog: %s"
#, c-format
msgid "no reflog for '%s'"
-msgstr "không reflog cho “%sâ€"
+msgstr "không reflog cho '%s'"
#, c-format
msgid "%s does not point to a valid object!"
-msgstr "“%s†không chỉ đến một lần chuyển giao hợp lệ nào cả!"
+msgstr "'%s' không chỉ đến một lần chuyển giao hợp lệ nào cả!"
#, c-format
msgid ""
@@ -18319,20 +19584,20 @@ msgid ""
"\n"
"\tgit branch -m <name>\n"
msgstr ""
-"Sử dụng “%s†làm tên cho nhánh ban đầu. Tên nhánh mặc định này\n"
+"Sử dụng '%s' làm tên cho nhánh ban đầu. Tên nhánh mặc định này\n"
"có thể thay đổi. Äể cấu hình tên nhánh khởi đầu sá»­ dụng trong tất cả\n"
"kho lưu trữ má»›i cá»§a bạn, cái mà sẽ ngăn chặn cảnh báo này, gá»i lệnh:\n"
"\n"
"\tgit config --global init.defaultBranch <tên>\n"
"\n"
-"Tên thưá»ng được chá»n thay cho “master†là “mainâ€, “trunk†và\n"
-"“developmentâ€. Nhánh vừa tạo có thể được đổi tên thông qua lệnh:\n"
+"Tên thưá»ng được chá»n thay cho 'master' là 'main', 'trunk' và\n"
+"'development'. Nhánh vừa tạo có thể được đổi tên thông qua lệnh:\n"
"\n"
"\tgit branch -m <tên>\n"
#, c-format
msgid "could not retrieve `%s`"
-msgstr "không thể lấy vỠ“%sâ€"
+msgstr "không thể lấy vỠ'%s'"
#, c-format
msgid "invalid branch name: %s = %s"
@@ -18340,7 +19605,7 @@ msgstr "tên nhánh không hợp lệ: %s = %s"
#, c-format
msgid "ignoring dangling symref %s"
-msgstr "Ä‘ang lá» Ä‘i tham chiếu má»m thừa %s"
+msgstr "Ä‘ang bá» qua tham chiếu má»m thừa %s"
#, c-format
msgid "log for ref %s has gap after %s"
@@ -18354,35 +19619,38 @@ msgstr "nhật ký cho tham chiếu %s kết thúc bất ngỠtrên %s"
msgid "log for %s is empty"
msgstr "nhật ký cho %s trống rỗng"
+msgid "refusing to force and skip creation of reflog"
+msgstr "từ chối bỠqua việc tạo log tham chiếu"
+
#, c-format
msgid "refusing to update ref with bad name '%s'"
-msgstr "từ chối cập nhật tham chiếu vá»›i tên sai “%sâ€"
+msgstr "từ chối cập nhật tham chiếu với tên sai '%s'"
+
+#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "từ chối cập nhật tham chiếu ảo '%s'"
#, c-format
msgid "update_ref failed for ref '%s': %s"
-msgstr "update_ref bị lá»—i cho ref “%sâ€: %s"
+msgstr "update_ref bị lỗi cho ref '%s': %s"
#, c-format
msgid "multiple updates for ref '%s' not allowed"
-msgstr "không cho phép Ä‘a cập nhật cho tham chiếu “%sâ€"
+msgstr "không cho phép đa cập nhật cho tham chiếu '%s'"
msgid "ref updates forbidden inside quarantine environment"
msgstr "cập nhật tham chiếu bị cấm trong môi trưá»ng kiểm tra"
msgid "ref updates aborted by hook"
-msgstr "các cập nhật tham chiếu bị bãi bỠbởi móc"
+msgstr "các cập nhật tham chiếu bị huỷ bỠbởi móc"
#, c-format
msgid "'%s' exists; cannot create '%s'"
-msgstr "“%s†sẵn có; không thể tạo “%sâ€"
+msgstr "'%s' sẵn có; không thể tạo '%s'"
#, c-format
msgid "cannot process '%s' and '%s' at the same time"
-msgstr "không thể xử lý “%s†và “%s†cùng một lúc"
-
-#, c-format
-msgid "could not remove reference %s"
-msgstr "không thể gỡ bỠtham chiếu: %s"
+msgstr "không thể xử lý '%s' và '%s' cùng một lúc"
#, c-format
msgid "could not delete reference %s: %s"
@@ -18393,12 +19661,109 @@ msgid "could not delete references: %s"
msgstr "không thể xóa bỠtham chiếu: %s"
#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "Äã hoàn thành thá»­ chạy di cư tham chiếu, kết quả tại '%s'\n"
+
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "không thể xoá thư mục tạm thá»i '%s'"
+
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "ydam chiếu đã di cư tại '%s'"
+
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"không thể lock tham chiếu '%s': cần tham chiếu má»m tá»›i '%s': nhưng lại là "
+"tham chiếu thưá»ng"
+
+#, c-format
+msgid "cannot open directory %s"
+msgstr "không thể mở thư mục %s"
+
+msgid "Checking references consistency"
+msgstr "Äang kiểm tra tính nhất quán các tham chiếu"
+
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "tên tham chiếu không an toàn: %s"
+
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "thử ghi tham chiếu '%s' tới đối tượng %s không tồn tại"
+
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "thử ghi đối tượng không phải chuyển giao %s tới nhánh '%s'"
+
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"không cho phép đa cập nhật cho tham chiếu HEAD (bao gồm cả thông qua tham "
+"chiếu '%s')"
+
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr "không thể khoá tham chiếu '%s': không thể phân giải tham chiếu '%s'"
+
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "không thể khoá tham chiếu '%s': lá»—i khi Ä‘á»c tham chiếu"
+
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"không cho phép đa cập nhật cho tham chiếu '%s' (bao gồm cả thông qua tham "
+"chiếu biểu trưng '%s')"
+
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "không thể lock tham chiếu '%s': tham chiếu đã tồn tại"
+
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr "không thể lock tham chiếu '%s': không tồn tại tham chiếu nhưng cần %s"
+
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "không thể lock tham chiếu '%s': đang ở %s nhưng cần %s"
+
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "reftable: chuẩn bị chuyển giao: %s"
+
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "reftable: chuyển giao thất bại: %s"
+
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "không thể nén stack: %s"
+
+#, c-format
+msgid "refname %s not found"
+msgstr "không tìm thấy tên tham chiếu %s"
+
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "tên tham chiếu %s là tham chiếu biểu trưng, không hỗ trợ sao chép"
+
+#, c-format
msgid "invalid refspec '%s'"
-msgstr "refspec không hợp lệ “%sâ€"
+msgstr "refspec không hợp lệ '%s'"
#, c-format
msgid "invalid quoting in push-option value: '%s'"
-msgstr "sai trích dẫn trong giá trị push-option :“%sâ€"
+msgstr "sai trích dẫn trong giá trị push-option :'%s'"
+
+#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "không hiểu giá trị cho object-format: %s"
#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
@@ -18406,38 +19771,37 @@ msgstr "%sinfo/refs không hợp lệ: đây có phải là một kho git?"
msgid "invalid server response; expected service, got flush packet"
msgstr ""
-"đáp ứng từ máy phục vụ không hợp lệ; cần dịch vụ, nhưng lại nhận được gói "
-"flush"
+"phản hồi từ máy chủ không hợp lệ; cần dịch vụ, nhưng lại nhận được gói flush"
#, c-format
msgid "invalid server response; got '%s'"
-msgstr "trả vỠcủa máy phục vụ không hợp lệ; nhận được %s"
+msgstr "phản hồi từ máy chủ không hợp lệ; nhận được %s"
#, c-format
msgid "repository '%s' not found"
-msgstr "không tìm thấy kho “%sâ€"
+msgstr "không tìm thấy kho '%s'"
#, c-format
msgid "Authentication failed for '%s'"
-msgstr "Xác thá»±c gặp lá»—i cho “%sâ€"
+msgstr "Xác thực gặp lỗi cho '%s'"
#, c-format
msgid "unable to access '%s' with http.pinnedPubkey configuration: %s"
-msgstr "không thể truy cập “%s†với cấu hình http.pinnedPubkey: %s"
+msgstr "không thể truy cập '%s' với cấu hình http.pinnedPubkey: %s"
#, c-format
msgid "unable to access '%s': %s"
-msgstr "không thể truy cập “%sâ€: %s"
+msgstr "không thể truy cập '%s': %s"
#, c-format
msgid "redirecting to %s"
msgstr "chuyển hướng đến %s"
msgid "shouldn't have EOF when not gentle on EOF"
-msgstr "không nên có EOF khi không gentle trên EOF"
+msgstr "không nên có EOF khi không thể xử lý EOF"
msgid "remote server sent unexpected response end packet"
-msgstr "máy phục vụ gửi gói kết thúc không cần"
+msgstr "máy chá»§ gá»­i gói kết thúc bất thưá»ng"
msgid "unable to rewind rpc post data - try increasing http.postBuffer"
msgstr "không thể tua lại dữ liệu post rpc - thử tăng http.postBuffer"
@@ -18454,15 +19818,15 @@ msgid "RPC failed; %s"
msgstr "RPC gặp lỗi; %s"
msgid "cannot handle pushes this big"
-msgstr "không thể xử lý đẩy cái lớn này"
+msgstr "không thể xử lý đẩy lớn cỡ này"
#, c-format
msgid "cannot deflate request; zlib deflate error %d"
-msgstr "không thể giải nén yêu cầu; có lỗi khi giải nén của zlib %d"
+msgstr "không thể giải nén yêu cầu; lỗi zlib deflate %d"
#, c-format
msgid "cannot deflate request; zlib end error %d"
-msgstr "không thể giải nén yêu cầu; có lỗi ở cuối %d"
+msgstr "không thể giải nén yêu cầu; lỗi zlib end %d"
#, c-format
msgid "%d bytes of length header were received"
@@ -18483,12 +19847,19 @@ msgstr "không thể lấy vỠbằng sha1 thông qua smart http"
#, c-format
msgid "protocol error: expected sha/ref, got '%s'"
-msgstr "lá»—i giao thức: cần sha/ref, nhưng lại nhận được “%sâ€"
+msgstr "lỗi giao thức: cần sha/ref, nhưng lại nhận được '%s'"
#, c-format
msgid "http transport does not support %s"
msgstr "vận chuyển http không hỗ trợ %s"
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "lỗi giao thức: cần '<url> <path>', thiếu dấu cách"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "gặp lỗi khi tải tập tin tại URL '%s'"
+
msgid "git-http-push failed"
msgstr "git-http-push gặp lỗi"
@@ -18503,11 +19874,11 @@ msgstr "remote-curl: đã cố gắng fetch mà không có kho nội bộ"
#, c-format
msgid "remote-curl: unknown command '%s' from git"
-msgstr "remote-curl: không hiểu lệnh “%s†từ git"
+msgstr "remote-curl: không hiểu lệnh '%s' từ git"
#, c-format
msgid "config remote shorthand cannot begin with '/': %s"
-msgstr "cấu hình viết tắt máy chá»§ không thể bắt đầu bằng “/â€: %s"
+msgstr "cấu hình viết tắt máy chủ không thể bắt đầu bằng '/': %s"
msgid "more than one receivepack given, using the first"
msgstr "đã đưa ra nhiá»u hÆ¡n má»™t gói nhận vá», Ä‘ang sá»­ dụng cái đầu tiên"
@@ -18537,19 +19908,19 @@ msgstr "%s theo dõi cả %s và %s"
#, c-format
msgid "key '%s' of pattern had no '*'"
-msgstr "khóa “%s†cá»§a mẫu k có “*â€"
+msgstr "khóa '%s' của mẫu k có '*'"
#, c-format
msgid "value '%s' of pattern has no '*'"
-msgstr "giá trị “%s†cá»§a mẫu k có “*â€"
+msgstr "giá trị '%s' của mẫu k có '*'"
#, c-format
msgid "src refspec %s does not match any"
-msgstr "refspec %s nguồn không khớp bất kỳ cái gì"
+msgstr "refspec (đặc tả tham chiếu) nguồn %s không khớp bất kỳ cái gì"
#, c-format
msgid "src refspec %s matches more than one"
-msgstr "refspec %s nguồn khá»›p nhiá»u hÆ¡n má»™t"
+msgstr "refspec (đặc tả tham chiếu) nguồn %s khá»›p nhiá»u hÆ¡n má»™t"
#. TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
#. <remote> <src>:<dst>" push, and "being pushed ('%s')" is
@@ -18567,17 +19938,16 @@ msgid ""
"\n"
"Neither worked, so we gave up. You must fully qualify the ref."
msgstr ""
-"Äích bạn đã cung cấp không phải tên tham chiếu đầy đủ (tức là\n"
-"bắt đầu bằng \"refs/\"). Chúng tôi đã cố suy luận rằng ý của bạn là:\n"
+"Äích bạn đã cung cấp không phải tên tham chiếu đầy đủ\n"
+"(bắt đầu bằng \"refs/\"). Chúng tôi đã thử đoán ý của bạn theo hai cách:\n"
"\n"
-"- Tìm kiếm một tham chiếu mà nó khớp “%s†bên phía máy chủ.\n"
-"- Kiểm tra xem <src> được đẩy lên (“%sâ€)\n"
-" là một tham chiếu trong \"refs/{heads,tags}/\". Nếu thế chúng tôi thêm một "
-"tiá»n tố\n"
-" refs/{heads,tags}/ tương ứng bên phía máy chủ.\n"
+"- Tìm kiếm một tham chiếu khớp '%s' bên phía máy chủ.\n"
+"- Kiểm tra xem <nguồn> được đẩy lên ('%s')\n"
+" có là một tham chiếu trong \"refs/{heads,tags}/\", và nếu vậy thêm\n"
+" tiá»n tố refs/{heads,tags}/ tương ứng bên phía máy chá»§.\n"
"\n"
-"Nếu cả hai là không thể, thì chúng tôi cũng chịu thua. Bạn phải dùng tham "
-"chiếu dạng đầy đủ."
+"Vì cả hai Ä‘á»u không thể, chúng tôi chịu. Bạn phải dùng tham chiếu dạng đầy "
+"đủ."
#, c-format
msgid ""
@@ -18585,9 +19955,9 @@ msgid ""
"Did you mean to create a new branch by pushing to\n"
"'%s:refs/heads/%s'?"
msgstr ""
-"Phần <src> cá»§a đặc tả đưá»ng dẫn là má»™t đối tượng lần chuyển giao.\n"
+"Phần <src> của đặc tả tham chiếu là một đối tượng lần chuyển giao.\n"
"Có phải ý bạn là một tạo một nhánh mới bằng cách đẩy lên\n"
-"“%s:refs/heads/%s�"
+"'%s:refs/heads/%s'?"
#, c-format
msgid ""
@@ -18595,9 +19965,9 @@ msgid ""
"Did you mean to create a new tag by pushing to\n"
"'%s:refs/tags/%s'?"
msgstr ""
-"Phần <src> cá»§a đặc tả đưá»ng dẫn là má»™t đối tượng thẻ.\n"
+"Phần <nguồn> của đặc tả tham chiếu là một đối tượng thẻ.\n"
"Có phải ý bạn là một tạo một thẻ mới bằng cách đẩy lên\n"
-"“%s:refs/tags/%s�"
+"'%s:refs/tags/%s'?"
#, c-format
msgid ""
@@ -18605,9 +19975,9 @@ msgid ""
"Did you mean to tag a new tree by pushing to\n"
"'%s:refs/tags/%s'?"
msgstr ""
-"Phần <src> cá»§a đặc tả đưá»ng dẫn là má»™t đối tượng cây.\n"
+"Phần <nguồn> của đặc tả tham chiếu là một đối tượng cây.\n"
"Có phải ý bạn là một tạo một cây mới bằng cách đẩy lên\n"
-"“%s:refs/tags/%s�"
+"'%s:refs/tags/%s'?"
#, c-format
msgid ""
@@ -18615,17 +19985,17 @@ msgid ""
"Did you mean to tag a new blob by pushing to\n"
"'%s:refs/tags/%s'?"
msgstr ""
-"Phần <src> cá»§a đặc tả đưá»ng dẫn là má»™t đối tượng blob.\n"
+"Phần <nguồn> của đặc tả tham chiếu là một đối tượng blob.\n"
"Có phải ý bạn là một tạo một blob mới bằng cách đẩy lên\n"
-"“%s:refs/tags/%s�"
+"'%s:refs/tags/%s'?"
#, c-format
msgid "%s cannot be resolved to branch"
-msgstr "“%s†không thể được phân giải thành nhánh"
+msgstr "'%s' không thể được phân giải thành nhánh"
#, c-format
msgid "unable to delete '%s': remote ref does not exist"
-msgstr "không thể xóa “%sâ€: tham chiếu trên máy chá»§ không tồn tại"
+msgstr "không thể xóa '%s': tham chiếu trên máy chủ không tồn tại"
#, c-format
msgid "dst refspec %s matches more than one"
@@ -18640,34 +20010,34 @@ msgstr "HEAD không chỉ đến một nhánh nào cả"
#, c-format
msgid "no such branch: '%s'"
-msgstr "không có nhánh nào như thế: “%sâ€"
+msgstr "không có nhánh nào như thế: '%s'"
#, c-format
msgid "no upstream configured for branch '%s'"
-msgstr "không có thượng nguồn được cấu hình cho nhánh “%sâ€"
+msgstr "không có thượng nguồn được cấu hình cho nhánh '%s'"
#, c-format
msgid "upstream branch '%s' not stored as a remote-tracking branch"
msgstr ""
-"nhánh thượng nguồn “%s†không được lưu lại như là một nhánh theo dõi máy chủ"
+"nhánh thượng nguồn '%s' không được lưu lại như là một nhánh theo dõi máy chủ"
#, c-format
msgid "push destination '%s' on remote '%s' has no local tracking branch"
-msgstr "đẩy lên đích “%s†trên máy chủ “%s†không có nhánh theo dõi nội bộ"
+msgstr "đẩy lên đích '%s' trên máy chủ '%s' không có nhánh theo dõi nội bộ"
#, c-format
msgid "branch '%s' has no remote for pushing"
-msgstr "nhánh “%s†không có máy chủ để đẩy lên"
+msgstr "nhánh '%s' không có máy chủ để đẩy lên"
#, c-format
msgid "push refspecs for '%s' do not include '%s'"
-msgstr "đẩy refspecs cho “%s†không bao gồm “%sâ€"
+msgstr "đẩy refspecs cho '%s' không bao gồm '%s'"
msgid "push has no destination (push.default is 'nothing')"
-msgstr "đẩy lên mà không có đích (push.default là “nothingâ€)"
+msgstr "đẩy lên mà không có đích (push.default là 'nothing')"
msgid "cannot resolve 'simple' push to a single destination"
-msgstr "không thể phân giải đẩy “đơn giản†đến một đích đơn"
+msgstr "không thể phân giải đẩy 'đơn giản' đến một đích đơn"
#, c-format
msgid "couldn't find remote ref %s"
@@ -18675,23 +20045,23 @@ msgstr "không thể tìm thấy tham chiếu máy chủ %s"
#, c-format
msgid "* Ignoring funny ref '%s' locally"
-msgstr "* Äang bá» qua tham chiếu thú vị ná»™i bá»™ “%sâ€"
+msgstr "* Äang bá» qua tham chiếu ná»™i bá»™ '%s'"
#, c-format
msgid "Your branch is based on '%s', but the upstream is gone.\n"
msgstr ""
-"Nhánh cá»§a bạn dá»±a trên cÆ¡ sở là “%sâ€, nhưng trên thượng nguồn không còn.\n"
+"Nhánh của bạn dựa trên cơ sở là '%s', nhưng trên thượng nguồn không còn.\n"
msgid " (use \"git branch --unset-upstream\" to fixup)\n"
msgstr " (dùng \" git branch --unset-upstream\" để sửa)\n"
#, c-format
msgid "Your branch is up to date with '%s'.\n"
-msgstr "Nhánh cá»§a bạn đã cập nhật vá»›i “%sâ€.\n"
+msgstr "Nhánh của bạn đã cập nhật với '%s'.\n"
#, c-format
msgid "Your branch and '%s' refer to different commits.\n"
-msgstr "Nhánh của bạn và “%s†tham chiếu đến các lần chuyển giao khác nhau.\n"
+msgstr "Nhánh của bạn và '%s' tham chiếu đến các lần chuyển giao khác nhau.\n"
#, c-format
msgid " (use \"%s\" for details)\n"
@@ -18700,7 +20070,7 @@ msgstr " (dùng \"%s\" để biết thêm chi tiết)\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] "Nhánh của bạn đứng trước “%s†%d lần chuyển giao.\n"
+msgstr[0] "Nhánh của bạn đứng trước '%s' %d lần chuyển giao.\n"
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (dùng \"git push\" để xuất bản các lần chuyển giao nội bộ của bạn)\n"
@@ -18710,8 +20080,8 @@ 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] ""
-"Nhánh của bạn đứng đằng sau “%s†%d lần chuyển giao, và có thể được chuyển-"
-"tiếp-nhanh.\n"
+"Nhánh của bạn đứng sau '%s' %d lần chuyển giao, và có thể được chuyển-tiếp-"
+"nhanh.\n"
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (dùng \"git pull\" để cập nhật nhánh nội bộ của bạn)\n"
@@ -18724,22 +20094,21 @@ msgid_plural ""
"Your branch and '%s' have diverged,\n"
"and have %d and %d different commits each, respectively.\n"
msgstr[0] ""
-"Nhánh của bạn và “%s†bị phân kỳ,\n"
-"và có %d và %d lần chuyển giao khác nhau cho từng cái,\n"
-"tương ứng với mỗi lần.\n"
+"Nhánh của bạn và '%s' bị phân kỳ,\n"
+"và tương ứng có %d và %d lần chuyển giao khác nhau cho từng nhánh.\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 ""
-" (dùng \"git pull\" để hòa trộn nhánh trên máy chủ vào trong nhánh của "
-"bạn)\n"
+" (dùng \"git pull\" để hòa trộn nhánh trên máy chủ vào nhánh của bạn)\n"
#, c-format
msgid "cannot parse expected object name '%s'"
-msgstr "không thể phân tích tên đối tượng mong muốn “%sâ€"
+msgstr "không thể Ä‘á»c tên đối tượng mong muốn '%s'"
#, c-format
msgid "cannot strip one component off url '%s'"
-msgstr "không thể cắt bá» má»™t thành phần ra khá»i “%s†url"
+msgstr "không thể cắt bá» má»™t thành phần ra khá»i '%s' url"
#, c-format
msgid "bad replace ref name: %s"
@@ -18761,65 +20130,61 @@ msgstr "không thể ghi bản ghi rerere"
#, c-format
msgid "there were errors while writing '%s' (%s)"
-msgstr "gặp lá»—i Ä‘á»c khi Ä‘ang ghi “%s†(%s)"
+msgstr "gặp lá»—i Ä‘á»c khi Ä‘ang ghi '%s' (%s)"
#, c-format
msgid "could not parse conflict hunks in '%s'"
-msgstr "không thể phân tích các mảnh xung đột trong “%sâ€"
+msgstr "không thể Ä‘á»c các khúc xung đột trong '%s'"
#, c-format
msgid "failed utime() on '%s'"
-msgstr "gặp lá»—i utime() trên “%sâ€"
+msgstr "gặp lỗi utime() trên '%s'"
#, c-format
msgid "writing '%s' failed"
-msgstr "gặp lá»—i khi Ä‘ang ghi “%sâ€"
+msgstr "gặp lỗi khi đang ghi '%s'"
#, c-format
msgid "Staged '%s' using previous resolution."
-msgstr "Äã tạm cất “%s†sá»­ dụng cách phân giải kế trước."
+msgstr "Äã tạm cất '%s' sá»­ dụng cách phân giải kế trước."
#, c-format
msgid "Recorded resolution for '%s'."
-msgstr "Cách giải quyết đã ghi lại cho “%sâ€."
+msgstr "Cách giải quyết đã ghi lại cho '%s'."
#, c-format
msgid "Resolved '%s' using previous resolution."
-msgstr "Äã phân giải giải “%s†sá»­ dụng cách giải quyết kế trước."
+msgstr "Äã phân giải giải '%s' sá»­ dụng cách giải quyết kế trước."
#, c-format
msgid "cannot unlink stray '%s'"
-msgstr "không thể unlink stray “%sâ€"
+msgstr "không thể unlink stray '%s'"
#, c-format
msgid "Recorded preimage for '%s'"
-msgstr "Preimage đã được ghi lại cho “%sâ€"
+msgstr "Preimage đã được ghi lại cho '%s'"
#, c-format
msgid "failed to update conflicted state in '%s'"
-msgstr "gặp lá»—i khi chạy cập nhật trạng thái bị xung đột trong “%sâ€"
+msgstr "gặp lỗi khi chạy cập nhật trạng thái bị xung đột trong '%s'"
#, c-format
msgid "no remembered resolution for '%s'"
-msgstr "đừng nhó các giải quyết cho “%sâ€"
-
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "không thể unlink “%sâ€"
+msgstr "đừng nhó các giải quyết cho '%s'"
#, c-format
msgid "Updated preimage for '%s'"
-msgstr "Äã cập nhật preimage cho “%sâ€"
+msgstr "Äã cập nhật preimage cho '%s'"
#, c-format
msgid "Forgot resolution for '%s'\n"
-msgstr "Quên phân giải cho “%sâ€\n"
+msgstr "Quên phân giải cho '%s'\n"
msgid "unable to open rr-cache directory"
msgstr "không thể mở thư mục rr-cache"
msgid "update the index with reused conflict resolution if possible"
-msgstr "cập nhật bảng mục lục với phân giải xung đột dùng lại nếu được"
+msgstr "cập nhật chỉ mục với phân giải xung đột dùng lại nếu được"
msgid "could not determine HEAD revision"
msgstr "không thể dò tìm điểm xét duyệt HEAD"
@@ -18828,15 +20193,45 @@ msgstr "không thể dò tìm điểm xét duyệt HEAD"
msgid "failed to find tree of %s"
msgstr "gặp lỗi khi tìm cây của %s"
+#, c-format
+msgid "unsupported section for hidden refs: %s"
+msgstr "không hỗ trợ mục cho tham chiếu ẩn: %s"
+
+msgid "--exclude-hidden= passed more than once"
+msgstr "--exclude-hidden= được dùng hơn một lần"
+
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo ghi nhận '%s' bị thiếu"
+
+#, c-format
+msgid "%s exists but is a symbolic ref"
+msgstr "%s có tồn tại nhưng là tham chiếu biểu trưng"
+
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge yêu cầu tham chiếu ảo MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD hoặc "
+"REBASE_HEAD"
+
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "không tìm thấy lần chuyển giao ứng với đối số --ancestry-path %s"
+
msgid "--unpacked=<packfile> no longer supported"
msgstr "--unpacked=<packfile> không còn được hỗ trợ nữa"
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "tùy chá»n không hợp lệ '%s' trong chế độ --stdin"
+
msgid "your current branch appears to be broken"
msgstr "nhánh hiện tại cá»§a bạn có vẻ như bị há»ng"
#, c-format
msgid "your current branch '%s' does not have any commits yet"
-msgstr "nhánh hiện tại của bạn “%s†không có một lần chuyển giao nào cả"
+msgstr "nhánh hiện tại của bạn '%s' không có một lần chuyển giao nào cả"
msgid "object filtering requires --objects"
msgstr "lá»c đối tượng yêu cầu --objects"
@@ -18848,13 +20243,217 @@ msgstr "-L vẫn chưa hỗ trợ định dạng khác biệt nào ngoài -p và
msgid "cannot create async thread: %s"
msgstr "không thể tạo tuyến trình async: %s"
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' không tồn tại"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "không thể chuyển đến '%s'"
+
+msgid "need a working directory"
+msgstr "cần một thư mục làm việc"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "'Scalar enlistments' cần một cây làm việc"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "không thể đóng cấu hình %s=%s"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "không thể cấu hình log.excludeDecoration"
+
+msgid "could not add enlistment"
+msgstr "không thể thêm enlistment"
+
+msgid "could not set recommended config"
+msgstr "không thể đặt cấu hình đỠnghị"
+
+msgid "could not turn on maintenance"
+msgstr "không thể bật chế độ bảo trì"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "không thể khởi chạy tiến trình ná»n FSMonitor"
+
+msgid "could not turn off maintenance"
+msgstr "không thể tắt chế độ bảo trì"
+
+msgid "could not remove enlistment"
+msgstr "không thể bỠenlistment"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "HEAD của máy chủ không phải một nhánh: '%.*s'"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr "gặp lỗi khi lấy tên nhánh mặc định từ máy chủ; sử dụng mặc định nội bộ"
+
+msgid "failed to get default branch name"
+msgstr "gặp lỗi khi lấy tên nhánh mặc định"
+
+msgid "failed to unregister repository"
+msgstr "gặp lỗi khi hủy đăng ký kho chứa"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "Gặp lá»—i khi dừng tiến trình ná»n FSMonitor"
+
+msgid "failed to delete enlistment directory"
+msgstr "gặp lỗi khi xóa thư mục enlistment"
+
+msgid "branch to checkout after clone"
+msgstr "nhánh để checkout sau khi nhân bản"
+
+msgid "when cloning, create full working directory"
+msgstr "khi nhân bản, tạo đầy đủ thư mục làm việc"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "chỉ siêu dữ liệu tải vỠcho nhánh mà sẽ được checkout"
+
+msgid "create repository within 'src' directory"
+msgstr "tạo kho chứa trong thư mục 'src'"
+
+msgid "specify if tags should be fetched during clone"
+msgstr "có nên lấy vỠthẻ khi nhân bản"
+
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <nhánh-chính>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "không thể suy diễn tên cây làm việc từ '%s'"
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "thư mục '%s' đã sẵn có"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "gặp lỗi khi lấy nhánh mặc định cho '%s'"
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "không thể cấu hình máy chủ trong '%s'"
+
+#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "không thể vô hiệu thẻ trong '%s'"
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "không thể cấu hình '%s'"
+
+msgid "partial clone failed; attempting full clone"
+msgstr "nhân bản từng phần gặp lỗi; đang cố thử nhân bản đầy đủ"
+
+msgid "could not configure for full clone"
+msgstr "không thể cấu hình cho nhân bản đầy đủ"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<enlistment>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` không nhận các tham số"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<enlistment>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "cấu hình má»i enlistments đã đăng ký"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <enlistment>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all hoặc <enlistment>, không thể là cả hai"
+
+#, c-format
+msgid "could not remove stale scalar.repo '%s'"
+msgstr "không thể xoá scalar.repo đã cũ '%s'"
+
+#, c-format
+msgid "removed stale scalar.repo '%s'"
+msgstr "đã xoá scalar.repo đã cũ '%s'"
+
+#, c-format
+msgid "repository at '%s' has different owner"
+msgstr "kho '%s' thuá»™c quyá»n sở hữu cá»§a ngưá»i khác"
+
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "kho '%s' có vấn đỠđịnh dạng"
+
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "không tìm thấy kho trong '%s'"
+
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"để bỠđăng ký kho này khá»i Scalar, chạy lệnh\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <task> [<enlistment>]\n"
+"Nhiệm vụ:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "không có nhiệm vụ nào như thế: '%s'"
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<enlistment>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <enlistment>"
+
+msgid "refusing to delete current working directory"
+msgstr "từ chối gỡ bỠthư mục làm việc hiện tại"
+
+msgid "include Git version"
+msgstr "bao gồm phiên bản Git"
+
+msgid "include Git's build options"
+msgstr "bao gồm các tùy chá»n biên dịch cá»§a Git"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C cần một <thư_mục>"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "không thể chuyển sang '%s'"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c cần một tham số <key>=<value>"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C </thư/mục/>] [-c <khóa>=<giá trị>] <lệnh> [<các tùy chá»n>]\n"
+"\n"
+"Các lệnh:\n"
+
msgid "unexpected flush packet while reading remote unpack status"
msgstr ""
-"gặp gói flush không cần trong khi Ä‘á»c tình trạng giải nén gói trên máy chá»§"
+"gặp gói flush bất thưá»ng trong khi Ä‘á»c tình trạng giải nén gói trên máy chá»§"
#, c-format
msgid "unable to parse remote unpack status: %s"
-msgstr "không thể phân tích tình trạng unpack máy chủ: %s"
+msgstr "không thể Ä‘á»c tình trạng unpack máy chá»§: %s"
#, c-format
msgid "remote unpack failed: %s"
@@ -18890,11 +20489,11 @@ msgstr "kết thúc nhận không há»— trợ các tùy chá»n cá»§a lệnh push"
#, c-format
msgid "invalid commit message cleanup mode '%s'"
-msgstr "chế độ dá»n dẹp ghi chú các lần chuyển giao không hợp lệ “%sâ€"
+msgstr "chế độ dá»n dẹp ghi chú các lần chuyển giao không hợp lệ '%s'"
#, c-format
msgid "could not delete '%s'"
-msgstr "không thể xóa bỠ“%sâ€"
+msgstr "không thể xóa bỠ'%s'"
msgid "revert"
msgstr "hoàn nguyên"
@@ -18910,11 +20509,25 @@ msgid "unknown action: %d"
msgstr "không nhận ra thao tác: %d"
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 ""
+"Hãy giải quyết vấn đỠnày bằng tay, đánh dấu chúng đã được giải quyết bằng\n"
+"lệnh \"git add/rm <các_tập tin_xung_đột>\", sau đó chạy \"git rebase --"
+"continue\".\n"
+"Bạn có thể bỠqua bản vá, chạy \"git rebase --skip\".\n"
+"Äể huá»· bá» và quay trở lại trạng thái trước \"git rebase\", chạy \"git rebase "
+"--abort\"."
+
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
"sau khi giải quyết các xung đột, đánh dấu đưá»ng dẫn đã sá»­a\n"
-"vá»›i lệnh “git add </các/đưá»ng/dẫn>†hoặc “git rm </các/đưá»ng/dẫn>â€"
+"vá»›i lệnh 'git add </các/đưá»ng/dẫn>' hoặc 'git rm </các/đưá»ng/dẫn>'"
msgid ""
"After resolving the conflicts, mark them with\n"
@@ -18928,7 +20541,7 @@ msgstr ""
"\"git add/rm <pathspec>\", sai đó chạy\n"
"\"git cherry-pick --continue\".\n"
"Bạn có thể bỠqua lần chuyển giao này với \"git cherry-pick --skip\".\n"
-"Äể bãi bá» và quay trở lại trạng thái trước khi \"git cherry-pick\",\n"
+"Äể huá»· bá» và quay trở lại trạng thái trước khi \"git cherry-pick\",\n"
"chạy \"git cherry-pick --abort\"."
msgid ""
@@ -18943,24 +20556,20 @@ msgstr ""
"\"git add/rm <đặc_tả_đưá»ng_dẫn_xung_đột>\", sau đó chạy\n"
"\"git revert --continue\".\n"
"Bạn có thể bỠqua lần chuyển giao này với \"git rebase --skip\".\n"
-"Äể bãi bá» và quay trở lại trạng thái trước \"git revert\",\n"
+"Äể huá»· bá» và quay trở lại trạng thái trước \"git revert\",\n"
"chạy \"git revert --abort\"."
#, c-format
msgid "could not lock '%s'"
-msgstr "không thể khóa “%sâ€"
-
-#, c-format
-msgid "could not write to '%s'"
-msgstr "không thể ghi vào “%sâ€"
+msgstr "không thể khóa '%s'"
#, c-format
msgid "could not write eol to '%s'"
-msgstr "không thể ghi eol vào “%sâ€"
+msgstr "không thể ghi eol vào '%s'"
#, c-format
msgid "failed to finalize '%s'"
-msgstr "gặp lá»—i khi hoàn thành “%sâ€"
+msgstr "gặp lỗi khi hoàn thành '%s'"
#, c-format
msgid "your local changes would be overwritten by %s."
@@ -18969,16 +20578,12 @@ msgstr "các thay đổi ná»™i bá»™ cá»§a bạn có thể bị ghi đè bởi lá
msgid "commit your changes or stash them to proceed."
msgstr "chuyển giao các thay đổi của bạn hay tạm cất (stash) chúng để xử lý."
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: chuyển-tiếp-nhanh"
-
#. TRANSLATORS: %s will be "revert", "cherry-pick" or
#. "rebase".
#.
#, c-format
msgid "%s: Unable to write new index file"
-msgstr "%s: Không thể ghi tập tin lưu bảng mục lục mới"
+msgstr "%s: Không thể ghi tập tin chỉ mục mới"
msgid "unable to update cache tree"
msgstr "không thể cập nhật cây bộ nhớ đệm"
@@ -18988,33 +20593,33 @@ msgstr "không thể phân giải lần chuyển giao HEAD"
#, c-format
msgid "no key present in '%.*s'"
-msgstr "không có khóa hiện diện trong “%.*sâ€"
+msgstr "không có khóa hiện diện trong '%.*s'"
#, c-format
msgid "unable to dequote value of '%s'"
-msgstr "không thể giải trích dẫn giá trị cá»§a “%sâ€"
+msgstr "không thể giải trích dẫn giá trị của '%s'"
msgid "'GIT_AUTHOR_NAME' already given"
-msgstr "“GIT_AUTHOR_NAME†đã sẵn đưa ra rồi"
+msgstr "'GIT_AUTHOR_NAME' đã sẵn đưa ra rồi"
msgid "'GIT_AUTHOR_EMAIL' already given"
-msgstr "“GIT_AUTHOR_EMAIL†đã sẵn đưa ra rồi"
+msgstr "'GIT_AUTHOR_EMAIL' đã sẵn đưa ra rồi"
msgid "'GIT_AUTHOR_DATE' already given"
-msgstr "“GIT_AUTHOR_DATE†đã sẵn đưa ra rồi"
+msgstr "'GIT_AUTHOR_DATE' đã sẵn đưa ra rồi"
#, c-format
msgid "unknown variable '%s'"
-msgstr "không hiểu biến “%sâ€"
+msgstr "không hiểu biến '%s'"
msgid "missing 'GIT_AUTHOR_NAME'"
-msgstr "thiếu “GIT_AUTHOR_NAMEâ€"
+msgstr "thiếu 'GIT_AUTHOR_NAME'"
msgid "missing 'GIT_AUTHOR_EMAIL'"
-msgstr "thiếu “GIT_AUTHOR_EMAILâ€"
+msgstr "thiếu 'GIT_AUTHOR_EMAIL'"
msgid "missing 'GIT_AUTHOR_DATE'"
-msgstr "thiếu “GIT_AUTHOR_DATEâ€"
+msgstr "thiếu 'GIT_AUTHOR_DATE'"
#, c-format
msgid ""
@@ -19031,7 +20636,7 @@ msgid ""
"\n"
" git rebase --continue\n"
msgstr ""
-"bạn có các thay đổi so với trong bệ phóng trong thư mục làm việc của bạn.\n"
+"bạn có các thay đổi so với trong vùng chỠtrong thư mục làm việc của bạn.\n"
"Nếu các thay đổi này là muốn squash vào lần chuyển giao kế trước, chạy:\n"
"\n"
" git commit --amend %s\n"
@@ -19045,7 +20650,7 @@ msgstr ""
" git rebase --continue\n"
msgid "'prepare-commit-msg' hook failed"
-msgstr "móc “prepare-commit-msg†bị lỗi"
+msgstr "móc 'prepare-commit-msg' bị lỗi"
msgid ""
"Your name and email address were configured automatically based\n"
@@ -19108,8 +20713,7 @@ msgid "couldn't look up newly created commit"
msgstr "không thể tìm thấy lần chuyển giao mới hơn đã được tạo"
msgid "could not parse newly created commit"
-msgstr ""
-"không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
+msgstr "không hiểu cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
msgid "unable to resolve HEAD after creating commit"
msgstr "không thể phân giải HEAD sau khi tạo lần chuyển giao"
@@ -19121,37 +20725,33 @@ msgid " (root-commit)"
msgstr " (root-commit)"
msgid "could not parse HEAD"
-msgstr "không thể phân tích HEAD"
+msgstr "không thể Ä‘á»c HEAD"
#, c-format
msgid "HEAD %s is not a commit!"
msgstr "HEAD %s không phải là một lần chuyển giao!"
msgid "unable to parse commit author"
-msgstr "không thể phân tích tác giả của lần chuyển giao"
+msgstr "không thể Ä‘á»c tác giả cá»§a lần chuyển giao"
#, c-format
msgid "unable to read commit message from '%s'"
-msgstr "không thể Ä‘á»c phần chú thích (message) từ “%sâ€"
+msgstr "không thể Ä‘á»c phần chú thích từ '%s'"
#, c-format
msgid "invalid author identity '%s'"
-msgstr "định danh tác giả không hợp lệ “%sâ€"
+msgstr "danh tính tác giả không hợp lệ '%s'"
msgid "corrupt author: missing date information"
-msgstr "tác giả sai há»ng: thiếu thông tin ngày tháng"
+msgstr "há»ng tên tác giả: thiếu thông tin ngày tháng"
#, c-format
msgid "could not update %s"
msgstr "không thể cập nhật %s"
#, c-format
-msgid "could not parse commit %s"
-msgstr "không thể phân tích lần chuyển giao %s"
-
-#, c-format
msgid "could not parse parent commit %s"
-msgstr "không thể phân tích lần chuyển giao cha mẹ “%sâ€"
+msgstr "không thể Ä‘á»c lần chuyển giao mẹ '%s'"
#, c-format
msgid "unknown command: %d"
@@ -19162,14 +20762,14 @@ msgstr "Äây là chú thích cho lần chuyển giao thứ nhất:"
#, c-format
msgid "This is the commit message #%d:"
-msgstr "Äây là chú thích cho lần chuyển giao thứ #%d:"
+msgstr "Äây là chú thích cho lần chuyển giao thứ %d:"
msgid "The 1st commit message will be skipped:"
msgstr "Chú thích cho lần chuyển giao thứ nhất sẽ bị bỠqua:"
#, c-format
msgid "The commit message #%d will be skipped:"
-msgstr "Chú thích cho lần chuyển giao thứ #%d sẽ bị bỠqua:"
+msgstr "Chú thích cho lần chuyển giao thứ %d sẽ bị bỠqua:"
#, c-format
msgid "This is a combination of %d commits."
@@ -19177,7 +20777,7 @@ msgstr "Äây là tổ hợp cá»§a %d lần chuyển giao."
#, c-format
msgid "cannot write '%s'"
-msgstr "không thể ghi “%sâ€"
+msgstr "không thể ghi '%s'"
msgid "need a HEAD to fixup"
msgstr "cần một HEAD để sửa"
@@ -19186,21 +20786,22 @@ msgid "could not read HEAD"
msgstr "không thể Ä‘á»c HEAD"
msgid "could not read HEAD's commit message"
-msgstr "không thể Ä‘á»c phần chú thích (message) cá»§a HEAD"
+msgstr "không thể Ä‘á»c phần chú thích cá»§a HEAD"
#, c-format
msgid "could not read commit message of %s"
-msgstr "không thể Ä‘á»c phần chú thích (message) cá»§a %s"
+msgstr "không thể Ä‘á»c phần chú thích cá»§a %s"
msgid "your index file is unmerged."
-msgstr "tập tin lưu mục lục của bạn không được hòa trộn."
+msgstr "tập tin chỉ mục của bạn không được hòa trộn."
msgid "cannot fixup root commit"
msgstr "không thể sửa chữa lần chuyển giao gốc"
#, c-format
msgid "commit %s is a merge but no -m option was given."
-msgstr "lần chuyển giao %s là má»™t lần hòa trá»™n nhưng không đưa ra tùy chá»n -m."
+msgstr ""
+"lần chuyển giao %s là má»™t lần hòa trá»™n nhưng lệnh không có tùy chá»n -m."
#, c-format
msgid "commit %s does not have parent %d"
@@ -19214,35 +20815,84 @@ msgstr "không thể lấy ghi chú lần chuyển giao cho %s"
#. "revert" or "pick", the second %s a SHA1.
#, c-format
msgid "%s: cannot parse parent commit %s"
-msgstr "%s: không thể phân tích lần chuyển giao mẹ của %s"
-
-#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "không thể đổi tên “%s†thành “%sâ€"
+msgstr "%s: không thể Ä‘á»c lần chuyển giao mẹ cá»§a %s"
#, c-format
msgid "could not revert %s... %s"
-msgstr "không thể hoàn nguyên %s… %s"
+msgstr "không thể hoàn nguyên %s... %s"
#, c-format
msgid "could not apply %s... %s"
-msgstr "không thể áp dụng miếng vá %s… %s"
+msgstr "không thể áp dụng bản vá %s... %s"
#, c-format
msgid "dropping %s %s -- patch contents already upstream\n"
-msgstr "xóa %s %s -- vá nội dung thượng nguồn đã có\n"
+msgstr "xóa %s %s -- thượng nguồn đã có bản vá\n"
#, c-format
msgid "git %s: failed to read the index"
-msgstr "git %s: gặp lá»—i Ä‘á»c bảng mục lục"
+msgstr "git %s: gặp lá»—i khi Ä‘á»c chỉ mục"
#, c-format
msgid "git %s: failed to refresh the index"
-msgstr "git %s: gặp lỗi khi làm tươi mới bảng mục lục"
+msgstr "git %s: gặp lỗi khi làm mới chỉ mục"
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s không nhận các đối số: “%sâ€"
+msgid "'%s' is not a valid label"
+msgstr "'%s' không phải một nhãn hợp lệ"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "'%s' không phải tên tham chiếu hợp lệ"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr "update-ref yêu cầu tên tham chiếu đầy đủ v.d. refs/heads/%s"
+
+#, c-format
+msgid "'%s' does not accept merge commits"
+msgstr "'%s' không nhận đối số lần chuyển giao hoà trộn"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"'pick' không cho phép dùng lần chuyển giao hoà trộn. Nếu như cần phát lại\n"
+"lần hoà trộn, hày dùng 'merge -C'."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"'reword' không cho phép dùng lần chuyển giao hoà trộn. Nếu như cần phát lại\n"
+"lần hoà trộn và sửa nội dung, hãy dùng 'merge -c'."
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"'pick' không cho phép dùng lần chuyển giao hoà trộn. Nếu như cần phát lại\n"
+"lần hoà trộn, hày dùng 'merge -C', sau đó 'break' để dùng lệnh\n"
+"'git commit --amend && git rebase --continue'."
+
+msgid "cannot squash merge commit into another commit"
+msgstr "không thể squash lần chuyển giao hoà trộn vào lần chuyển giao khác"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "lệnh không hợp lệ '%.*s'"
#, c-format
msgid "missing arguments for %s"
@@ -19250,7 +20900,7 @@ msgstr "thiếu đối số cho %s"
#, c-format
msgid "could not parse '%s'"
-msgstr "không thể phân tích cú pháp “%sâ€"
+msgstr "không thể Ä‘á»c '%s'"
#, c-format
msgid "invalid line %d: %.*s"
@@ -19258,7 +20908,7 @@ msgstr "dòng không hợp lệ %d: %.*s"
#, c-format
msgid "cannot '%s' without a previous commit"
-msgstr "không thể “%s†thể mà không có lần chuyển giao kế trước"
+msgstr "không thể '%s' thể mà không có lần chuyển giao kế trước"
msgid "cancelling a cherry picking in progress"
msgstr "đang hủy bỠthao tác cherry pick đang thực hiện"
@@ -19267,30 +20917,30 @@ msgid "cancelling a revert in progress"
msgstr "đang hủy bỠcác thao tác hoàn nguyên đang thực hiện"
msgid "please fix this using 'git rebase --edit-todo'."
-msgstr "vui lòng sá»­a lá»—i này bằng cách dùng “git rebase --edit-todoâ€."
+msgstr "vui lòng sửa lỗi này bằng cách dùng 'git rebase --edit-todo'."
#, c-format
msgid "unusable instruction sheet: '%s'"
-msgstr "bảng chỉ thị không thể dùng được: %s"
+msgstr "bảng chỉ thị không dùng được: %s"
msgid "no commits parsed."
-msgstr "không có lần chuyển giao nào được phân tích."
+msgstr "không Ä‘á»c được lần chuyển giao nào."
msgid "cannot cherry-pick during a revert."
-msgstr "không thể cherry-pick trong khi hoàn nguyên."
+msgstr "không thể cherry-pick trong khi đang hoàn nguyên."
msgid "cannot revert during a cherry-pick."
-msgstr "không thể thực hiện việc hoàn nguyên trong khi đang cherry-pick."
+msgstr "không thể hoàn nguyên trong khi đang cherry-pick."
msgid "unusable squash-onto"
-msgstr "squash-onto không dùng được"
+msgstr "không dùng được squash-onto"
#, c-format
msgid "malformed options sheet: '%s'"
-msgstr "bảng tùy chá»n dị hình: “%sâ€"
+msgstr "bảng tùy chá»n sai quy cách: '%s'"
msgid "empty commit set passed"
-msgstr "lần chuyển giao trống rỗng đặt là hợp quy cách"
+msgstr "được chỉ định một lần chuyển giao trống rỗng"
msgid "revert is already in progress"
msgstr "có thao tác hoàn nguyên đang được thực hiện"
@@ -19300,7 +20950,7 @@ msgid "try \"git revert (--continue | %s--abort | --quit)\""
msgstr "hãy thử \"git revert (--continue | %s--abort | --quit)\""
msgid "cherry-pick is already in progress"
-msgstr "có thao tác “cherry-pick†đang được thực hiện"
+msgstr "có thao tác cherry-pick đang được thực hiện"
#, c-format
msgid "try \"git cherry-pick (--continue | %s--abort | --quit)\""
@@ -19308,62 +20958,56 @@ msgstr "hãy thử \"git cherry-pick (--continue | %s--abort | --quit)\""
#, c-format
msgid "could not create sequencer directory '%s'"
-msgstr "không thể tạo thư mục xếp dãy “%sâ€"
-
-msgid "could not lock HEAD"
-msgstr "không thể khóa HEAD"
+msgstr "không thể tạo thư mục sequencer '%s'"
msgid "no cherry-pick or revert in progress"
-msgstr "không cherry-pick hay hoàn nguyên trong tiến trình"
+msgstr "không có cherry-pick hay hoàn nguyên đang được thực hiện"
msgid "cannot resolve HEAD"
msgstr "không thể phân giải HEAD"
msgid "cannot abort from a branch yet to be born"
-msgstr "không thể hủy bỠtừ một nhánh mà nó còn chưa được tạo ra"
+msgstr "không thể hủy bỠtừ một nhánh chưa được tạo ra"
#, c-format
msgid "cannot read '%s': %s"
-msgstr "không thể Ä‘á»c “%sâ€: %s"
+msgstr "không thể Ä‘á»c '%s': %s"
msgid "unexpected end of file"
msgstr "gặp kết thúc tập tin đột xuất"
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
-msgstr "tập tin HEAD “pre-cherry-pick†đã lưu “%s†bị há»ng"
+msgstr "tập tin HEAD trước cherry-pick '%s' bị há»ng"
msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
-msgstr ""
-"Bạn có lẽ đã có HEAD đã bị di chuyển đi, Không thể tua, kiểm tra HEAD của "
-"bạn!"
+msgstr "Bạn có lẽ đã di chuyển HEAD, Không thể quay lại, hãy kiểm tra HEAD!"
msgid "no revert in progress"
-msgstr "không có tiến trình hoàn nguyên nào"
+msgstr "không có hoàn nguyên nào đang được thực hiện"
msgid "no cherry-pick in progress"
msgstr "không có cherry-pick đang được thực hiện"
msgid "failed to skip the commit"
-msgstr "gặp lỗi khi bỠqua đối tượng chuyển giao"
+msgstr "gặp lỗi khi bỠqua lần chuyển giao"
msgid "there is nothing to skip"
-msgstr "ở đây không có gì để mà bỠqua cả"
+msgstr "ở đây không có gì để bỠqua"
#, c-format
msgid ""
"have you committed already?\n"
"try \"git %s --continue\""
msgstr ""
-"bạn đã sẵn sàng chuyển giao chưa?\n"
-"thá»­ \"git %s --continue\""
+"hình như bạn đã bắt đầu chuyển giao rồi?\n"
+"thử chạy \"git %s --continue\""
msgid "cannot read HEAD"
msgstr "không thể Ä‘á»c HEAD"
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "không thể chép “%s†sang “%sâ€"
+msgid "could not write commit message file"
+msgstr "không thể ghi tập tin chú thích lần chuyển giao"
#, c-format
msgid ""
@@ -19375,21 +21019,21 @@ msgid ""
"\n"
" git rebase --continue\n"
msgstr ""
-"Bạn có thể tu bổ lần chuyển giao ngay bây giỠbằng:\n"
+"Bạn có thể tu bổ lần chuyển giao bằng:\n"
"\n"
" git commit --amend %s\n"
"\n"
-"Một khi đã hài lòng với những thay đổi của mình, thì chạy:\n"
+"Sau khi hài lòng với những thay đổi của mình, hãy chạy:\n"
"\n"
" git rebase --continue\n"
#, c-format
msgid "Could not apply %s... %.*s"
-msgstr "Không thể áp dụng %s… %.*s"
+msgstr "Không thể áp dụng %s... %.*s"
#, c-format
msgid "Could not merge %.*s"
-msgstr "Không hòa trộn %.*s"
+msgstr "Không thể hòa trộn %.*s"
#, c-format
msgid "Executing: %s\n"
@@ -19404,33 +21048,37 @@ msgid ""
"\n"
msgstr ""
"thực thi gặp lỗi: %s\n"
-"%sBạn có thể sửa các trục trặc, và sau đó chạy lệnh\n"
+"%sBạn có thể sửa lại, và sau đó chạy lệnh\n"
"\n"
" git rebase --continue\n"
"\n"
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "và tạo các thay đổi bảng mục lục và/hay cây làm việc\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr "và thay đổi chỉ mục hay cây làm việc\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 ""
"thực thi thành công: %s\n"
-"nhưng còn các thay đổi trong mục lục và/hoặc cây làm việc\n"
-"Chuyển giao hay tạm cất các thay đổi này đi, rồi chạy\n"
+"nhưng còn các thay đổi trong chỉ mục hay cây làm việc.\n"
+"Hãy chuyển giao hay tạm cất các thay đổi này, rồi chạy\n"
"\n"
" git rebase --continue\n"
"\n"
#, c-format
msgid "illegal label name: '%.*s'"
-msgstr "tên nhãn dị hình: “%.*sâ€"
+msgstr "tên nhãn không hợp lệ: '%.*s'"
+
+#, c-format
+msgid "could not resolve '%s'"
+msgstr "không thể phân giải '%s'"
msgid "writing fake root commit"
msgstr "ghi lần chuyển giao gốc giả"
@@ -19438,45 +21086,63 @@ msgstr "ghi lần chuyển giao gốc giả"
msgid "writing squash-onto"
msgstr "đang ghi squash-onto"
-#, c-format
-msgid "could not resolve '%s'"
-msgstr "không thể phân giải “%sâ€"
-
msgid "cannot merge without a current revision"
-msgstr "không thể hòa trộn mà không có một điểm xét duyệt hiện tại"
+msgstr "không thể hòa trộn mà không có điểm hiệu chỉnh hiện tại"
#, c-format
msgid "unable to parse '%.*s'"
-msgstr "không thể phân tích “%.*sâ€"
+msgstr "không thể Ä‘á»c '%.*s'"
#, c-format
msgid "nothing to merge: '%.*s'"
-msgstr "chẳng có gì để hòa trá»™n: “%.*sâ€"
+msgstr "chẳng có gì để hòa trộn: '%.*s'"
msgid "octopus merge cannot be executed on top of a [new root]"
-msgstr "hòa trộn octopus không thể được thực thi trên đỉnh của một [new root]"
+msgstr ""
+"hòa trộn kiểu bạch tuộc không thể được thực thi trên đỉnh của [new root]"
#, c-format
msgid "could not get commit message of '%s'"
-msgstr "không thể lấy chú thích cá»§a lần chuyển giao cá»§a “%sâ€"
+msgstr "không thể lấy chú thích của lần chuyển giao của '%s'"
#, c-format
msgid "could not even attempt to merge '%.*s'"
-msgstr "không thể ngay cả khi thá»­ hòa trá»™n “%.*sâ€"
+msgstr "hoàn toàn không thể hòa trộn '%.*s'"
msgid "merge: Unable to write new index file"
-msgstr "merge: Không thể ghi tập tin lưu bảng mục lục mới"
+msgstr "merge: Không thể ghi tập tin chỉ mục mới"
+
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "Một lần cải tổ khác đang diễn ra; %s.lock đã tồn tại"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Äã cập nhật các tham chiếu sau thành %s:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Không thể cập nhật các tham chiếu sau thành %s:\n"
+"%s"
msgid "Cannot autostash"
msgstr "Không thể autostash"
#, c-format
msgid "Unexpected stash response: '%s'"
-msgstr "Gặp đáp ứng stash không cần: “%sâ€"
+msgstr "Gặp phản hồi stash bất thưá»ng '%s'"
#, c-format
msgid "Could not create directory for '%s'"
-msgstr "Không thể tạo thư mục cho “%sâ€"
+msgstr "Không thể tạo thư mục cho '%s'"
#, c-format
msgid "Created autostash: %s\n"
@@ -19491,7 +21157,7 @@ msgstr "Äã áp dụng autostash.\n"
#, c-format
msgid "cannot store %s"
-msgstr "không thá»­ lưu “%sâ€"
+msgstr "không thể lưu '%s'"
#, c-format
msgid ""
@@ -19500,16 +21166,19 @@ msgid ""
"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
msgstr ""
"%s\n"
-"Các thay đổi của bạn an toàn trong stash (tạm cất đi).\n"
+"Các thay đổi của bạn an toàn trong tạm cất.\n"
"Bạn có thể chạy lệnh \"git stash pop\" hay \"git stash drop\" bất kỳ lúc "
"nào.\n"
msgid "Applying autostash resulted in conflicts."
-msgstr "Ãp dụng autostash có hiệu quả trong các xung đột."
+msgstr "Ãp dụng autostash đã gây nên xung đột."
msgid "Autostash exists; creating a new stash entry."
msgstr "Autostash đã sẵn có; nên tạo một mục stash mới."
+msgid "autostash reference is a symref"
+msgstr "tham chiếu autostash là symref"
+
msgid "could not detach HEAD"
msgstr "không thể tách rá»i HEAD"
@@ -19535,19 +21204,19 @@ msgstr ""
"Không thể thực thi lệnh todo\n"
"\n"
" %.*s\n"
-"Nó đã được lên lịch lại: Äể sá»­a lệnh trước khi tiếp tục, vui lòng\n"
+"Lệnh đã được lên lịch lại. Äể sá»­a lệnh trước khi tiếp tục, vui lòng\n"
"sửa danh sách todo trước:\n"
"\n"
" git rebase --edit-todo\n"
" git rebase --continue\n"
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "Äang cải tổ (%d/%d)%s"
+msgid "Stopped at %s... %.*s\n"
+msgstr "Dừng lại ở %s... %.*s\n"
#, c-format
-msgid "Stopped at %s... %.*s\n"
-msgstr "Dừng lại ở %s… %.*s\n"
+msgid "Rebasing (%d/%d)%s"
+msgstr "Äang cải tổ (%d/%d)%s"
#, c-format
msgid "unknown command %d"
@@ -19557,7 +21226,7 @@ msgid "could not read orig-head"
msgstr "không thể Ä‘á»c orig-head"
msgid "could not read 'onto'"
-msgstr "không thể Ä‘á»c “ontoâ€."
+msgstr "không thể Ä‘á»c 'onto'."
#, c-format
msgid "could not update HEAD to %s"
@@ -19568,18 +21237,18 @@ msgid "Successfully rebased and updated %s.\n"
msgstr "Cài tổ và cập nhật %s một cách thành công.\n"
msgid "cannot rebase: You have unstaged changes."
-msgstr "không thể cải tổ: Bạn có các thay đổi chưa được đưa lên bệ phóng."
+msgstr "không thể cải tổ: Bạn có các thay đổi chưa được đưa vào vùng chá»."
msgid "cannot amend non-existing commit"
-msgstr "không thể tu bỠmột lần chuyển giao không tồn tại"
+msgstr "không thể tu sửa lần chuyển giao không tồn tại"
#, c-format
msgid "invalid file: '%s'"
-msgstr "tập tin không hợp lệ: “%sâ€"
+msgstr "tập tin không hợp lệ: '%s'"
#, c-format
msgid "invalid contents: '%s'"
-msgstr "ná»™i dung không hợp lệ: “%sâ€"
+msgstr "nội dung không hợp lệ: '%s'"
msgid ""
"\n"
@@ -19588,28 +21257,28 @@ msgid ""
msgstr ""
"\n"
"Bạn có các thay đổi chưa chuyển giao trong thư mục làm việc. Vui lòng\n"
-"chuyển giao chúng trước và sau đó chạy lệnh “git rebase --continue†lần nữa."
+"chuyển giao chúng trước rồi sau đó chạy lệnh 'git rebase --continue'."
#, c-format
msgid "could not write file: '%s'"
-msgstr "không thể ghi tập tin: “%sâ€"
+msgstr "không thể ghi tập tin: '%s'"
msgid "could not remove CHERRY_PICK_HEAD"
msgstr "không thể xóa bỠCHERRY_PICK_HEAD"
msgid "could not commit staged changes."
-msgstr "không thể chuyển giao các thay đổi đã đưa lên bệ phóng."
+msgstr "không thể chuyển giao các thay đổi đã đưa vào vùng chá»."
#, c-format
msgid "%s: can't cherry-pick a %s"
-msgstr "%s: không thể cherry-pick một %s"
+msgstr "%s: không thể cherry-pick %s"
#, c-format
msgid "%s: bad revision"
-msgstr "%s: điểm xét duyệt sai"
+msgstr "%s: điểm hiệu chỉnh không hợp lệ"
msgid "can't revert as initial commit"
-msgstr "không thể hoàn nguyên một lần chuyển giao khởi tạo"
+msgstr "không thể hoàn nguyên lần chuyển giao khởi tạo"
#, c-format
msgid "skipped previously applied commit %s"
@@ -19629,14 +21298,18 @@ msgid "nothing to do"
msgstr "không có gì để làm"
msgid "could not skip unnecessary pick commands"
-msgstr "không thể bỠqua các lệnh cậy (pick) không cần thiết"
+msgstr "không thể bỠqua các lệnh pick không cần thiết"
msgid "the script was already rearranged."
-msgstr "văn lệnh đã sẵn được sắp đặt rồi."
+msgstr "script đã được sắp đặt rồi."
+
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "tập tin update-refs '%s' không hợp lệ"
#, c-format
msgid "'%s' is outside repository at '%s'"
-msgstr "“%s†ngoài má»™t kho chứa tại “%sâ€"
+msgstr "'%s' nằm ngoài kho chứa tại '%s'"
#, c-format
msgid ""
@@ -19644,8 +21317,8 @@ msgid ""
"Use 'git <command> -- <path>...' to specify paths that do not exist locally."
msgstr ""
"%s: không có đưá»ng dẫn nào như thế ở trong cây làm việc.\n"
-"Dùng “git <lệnh> -- <đưá»ng/dẫn>…†để chỉ định đưá»ng dẫn mà nó không tồn tại "
-"một cách nội bộ."
+"Dùng 'git <lệnh> -- <đưá»ng/dẫn>...' để chỉ định đưá»ng dẫn không tồn tại ná»™i "
+"bá»™."
#, c-format
msgid ""
@@ -19653,14 +21326,14 @@ msgid ""
"Use '--' to separate paths from revisions, like this:\n"
"'git <command> [<revision>...] -- [<file>...]'"
msgstr ""
-"tham số chưa rõ ràng “%sâ€: chưa biết Ä‘iểm xem xét hay đưá»ng dẫn không trong "
-"cây làm việc.\n"
-"Dùng “--†để ngăn cách các đưá»ng dẫn khá»i Ä‘iểm xem xét, như thế này:\n"
-"“git <lệnh> [<Ä‘iểm xem xét>…] -- [<tập tin>…]â€"
+"tham số chưa rõ ràng '%s': chưa biết Ä‘iểm xét duyệt hay đưá»ng dẫn không "
+"trong cây làm việc.\n"
+"Dùng '--' để ngăn cách các đưá»ng dẫn khá»i Ä‘iểm xét duyệt, như thế này:\n"
+"'git <lệnh> [<điểm xét duyệt>...] -- [<tập tin>...]'"
#, c-format
msgid "option '%s' must come before non-option arguments"
-msgstr "tùy chá»n “%s†phải trước các đối số đầu tiên không có tùy chá»n"
+msgstr "tùy chá»n '%s' phải trước các đối số đầu tiên không có tùy chá»n"
#, c-format
msgid ""
@@ -19668,16 +21341,20 @@ msgid ""
"Use '--' to separate paths from revisions, like this:\n"
"'git <command> [<revision>...] -- [<file>...]'"
msgstr ""
-"tham số chưa rõ ràng “%sâ€: cả Ä‘iểm xem xét và tên tập tin.\n"
-"Dùng “--†để ngăn cách các đưá»ng dẫn khá»i Ä‘iểm xem xét, như thế này:\n"
-"“git <lệnh> [<Ä‘iểm xem xét>…] -- [<tập tin>…]â€"
+"tham số chưa rõ ràng '%s': cả điểm xem xét và tên tập tin.\n"
+"Dùng '--' để ngăn cách các đưá»ng dẫn khá»i Ä‘iểm xem xét, như thế này:\n"
+"'git <lệnh> [<điểm xem xét>...] -- [<tập tin>...]'"
msgid "unable to set up work tree using invalid config"
-msgstr "không thể cài đặt thư mục làm việc sử dụng cấu hình không hợp lệ"
+msgstr "không thể thiết lập thư mục làm việc với cấu hình không hợp lệ"
+
+#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "'%s' đã được chỉ định là '%s' rồi"
#, c-format
msgid "Expected git repo version <= %d, found %d"
-msgstr "Cần phiên bản kho git <= %d, nhưng lại nhận được %d"
+msgstr "Cần phiên bản kho git <= %d, nhưng lại là %d"
msgid "unknown repository extension found:"
msgid_plural "unknown repository extensions found:"
@@ -19685,15 +21362,16 @@ msgstr[0] "tìm thấy phần mở rộng kho chưa biết:"
msgid "repo version is 0, but v1-only extension found:"
msgid_plural "repo version is 0, but v1-only extensions found:"
-msgstr[0] "phiên bản kho là 0, nhưng lại tìm thấy phần mở rộng chỉ v1:"
+msgstr[0] ""
+"phiên bản kho là 0, nhưng lại tìm thấy phần mở rộng chỉ dành cho v1:"
#, c-format
msgid "error opening '%s'"
-msgstr "gặp lá»—i khi mở “%sâ€"
+msgstr "gặp lỗi khi mở '%s'"
#, c-format
msgid "too large to be a .git file: '%s'"
-msgstr "tập tin .git là quá lá»›n: “%sâ€"
+msgstr "tập tin .git quá lớn: '%s'"
#, c-format
msgid "error reading %s"
@@ -19701,11 +21379,11 @@ msgstr "gặp lá»—i khi Ä‘á»c %s"
#, c-format
msgid "invalid gitfile format: %s"
-msgstr "định dạng tập tin git không hợp lệ: %s"
+msgstr "định dạng gitfile không hợp lệ: %s"
#, c-format
msgid "no path in gitfile: %s"
-msgstr "không có đưá»ng dẫn trong tập tin git: %s"
+msgstr "không có đưá»ng dẫn trong gitfile: %s"
#, c-format
msgid "not a git repository: %s"
@@ -19713,54 +21391,63 @@ msgstr "không phải là kho git: %s"
#, c-format
msgid "'$%s' too big"
-msgstr "“$%s†quá lớn"
+msgstr "'$%s' quá lớn"
#, c-format
msgid "not a git repository: '%s'"
-msgstr "không phải là kho git: “%sâ€"
+msgstr "không phải là kho git: '%s'"
#, c-format
msgid "cannot chdir to '%s'"
-msgstr "không thể chdir (chuyển đổi thư mục) sang “%sâ€"
+msgstr "không thể chdir (chuyển thư mục) sang '%s'"
msgid "cannot come back to cwd"
-msgstr "không thể quay lại cwd"
+msgstr "không thể quay lại thư mục làm việc hiện hành"
#, c-format
msgid "failed to stat '%*s%s%s'"
-msgstr "gặp lá»—i khi lấy thống kê vỠ“%*s%s%sâ€"
+msgstr "gặp lỗi khi stat'%*s%s%s'"
+
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' không phải đưá»ng dẫn tuyệt đối"
+
+#, 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 ""
+"kho lưu trữ '%s' thuá»™c sở hữu cá»§a ngưá»i khác\n"
+"%sÄể thêm ngoại lệ cho thư mục này, hãy gá»i:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
msgid "Unable to read current working directory"
msgstr "Không thể Ä‘á»c thư mục làm việc hiện hành"
#, c-format
msgid "cannot change to '%s'"
-msgstr "không thể chuyển sang “%sâ€"
+msgstr "không thể chuyển sang '%s'"
#, c-format
msgid "not a git repository (or any of the parent directories): %s"
-msgstr "không phải là kho git (hoặc bất kỳ thư mục cha mẹ nào): %s"
+msgstr "không phải là kho git (các thư mục cha cũng không phải): %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 ""
-"không phải là kho git (hay bất kỳ cha mẹ nào đến tận điểm gắn kết %s)\n"
+"không phải là kho git (các thư mục cha dưới điểm gắn kết %s cũng không "
+"phải)\n"
"Dừng tại biên của hệ thống tập tin (GIT_DISCOVERY_ACROSS_FILESYSTEM chưa "
-"đặt)."
+"được đặt)."
#, c-format
-msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
-msgstr ""
-"kho lưu trữ không an toàn ('%s' thuá»™c sở hữu cá»§a ngưá»i khác)\n"
-"Äể thêm ngoại lệ cho thư mục này, hãy gá»i:\n"
-"\n"
-"\tgit config --global --add safe.directory %s"
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "không thể dùng kho chứa bare '%s' (safe.bareRepository là '%s')"
#, c-format
msgid ""
@@ -19771,17 +21458,107 @@ msgstr ""
"ngưá»i sở hữu tập tin phải luôn có quyá»n Ä‘á»c và ghi."
msgid "fork failed"
-msgstr "gặp lỗi khi rẽ nhánh tiến trình"
+msgstr "gặp lỗi khi fork"
msgid "setsid failed"
msgstr "setsid gặp lỗi"
#, c-format
+msgid "cannot stat template '%s'"
+msgstr "không thể lấy thông tin vỠmẫu '%s'"
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "không thể mở thư mục '%s'"
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "không thể Ä‘á»c ná»™i dung liên kết '%s'"
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "không thể tạo liên kết má»m '%s' '%s'"
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "không thể sao chép '%s' sang '%s'"
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "đang bỠqua mẫu '%s'"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "các mẫu không được tìm thấy trong %s"
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "không sao chép các mẫu từ '%s': %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "tên nhánh khởi tạo không hợp lệ: '%s'"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: --initial-branch=%s bị bỠqua"
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "không thể xử lý (handle) tập tin kiểu %d"
+
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "không di chuyển được %s vào %s"
+
+msgid "attempt to reinitialize repository with different hash"
+msgstr "cố để khởi tạo lại một kho với kiểu băm dữ liệu khác"
+
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr "cố khởi tạo lại một kho với kiểu lưu tham chiếu dữ liệu khác"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s đã có từ trước rồi"
+
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "Äã khởi tạo lại kho Git chia sẻ sẵn có trong %s%s\n"
+
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "Äã khởi tạo lại kho Git sẵn có trong %s%s\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "Äã khởi tạo lại kho Git chia sẻ trống rá»—ng sẵn có trong %s%s\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "Äã khởi tạo lại kho Git trống rá»—ng sẵn có trong %s%s\n"
+
+#, c-format
msgid "index entry is a directory, but not sparse (%08x)"
-msgstr "mục tin mục lục là một thư mục, nhưng không \"sparse\" (%08x)"
+msgstr "mục tin chỉ mục là một thư mục, nhưng không \"sparse\" (%08x)"
msgid "cannot use split index with a sparse index"
-msgstr "không thể sử dụng bảng mục lục chia tách với một \"sparse index\""
+msgstr "không thể sử dụng chỉ mục chia tách với một \"sparse index\""
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "định dạng %s sai: phần tử '%s' không bắt đầu bằng '('"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "định dạng %s sai: phần tử '%s' không bắt kết thúc bằng ')'"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "định dạng %s sai: %%%.*s"
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#, c-format
@@ -19826,21 +21603,15 @@ msgid_plural "%u bytes/s"
msgstr[0] "%u byte/giây"
#, c-format
-msgid "could not edit '%s'"
-msgstr "không thể sá»­a “%sâ€"
-
-#, c-format
msgid "ignoring suspicious submodule name: %s"
-msgstr "Ä‘ang lá» Ä‘i tên mô-Ä‘un-con mập má»: %s"
+msgstr "Ä‘ang bá» qua tên mô-Ä‘un-con mập má»: %s"
msgid "negative values not allowed for submodule.fetchJobs"
msgstr "không cho phép giá trị âm ở submodule.fetchJobs"
#, c-format
msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
-msgstr ""
-"Ä‘ang bá» qua “%s†cái mà có thể được phiên dịch như là má»™t tùy chá»n dòng "
-"lệnh: %s"
+msgstr "Ä‘ang bá» qua '%s' nhưng có thể được hiểu là tùy chá»n trên dòng lệnh: %s"
#, c-format
msgid "Could not update .gitmodules entry %s"
@@ -19864,11 +21635,11 @@ msgstr "gặp lỗi khi tổ chức .gitmodules đã cập nhật"
#, c-format
msgid "in unpopulated submodule '%s'"
-msgstr "trong mô-Ä‘un-con không có gì “%sâ€"
+msgstr "trong mô-đun-con không có gì '%s'"
#, c-format
msgid "Pathspec '%s' is in submodule '%.*s'"
-msgstr "Äặc tả đưá»ng dẫn “%s†thì ở trong mô-Ä‘un-con “%.*sâ€"
+msgstr "Äặc tả đưá»ng dẫn '%s' ở trong mô-Ä‘un-con '%.*s'"
#, c-format
msgid "bad --ignore-submodules argument: %s"
@@ -19879,33 +21650,33 @@ msgid ""
"Submodule in commit %s at path: '%s' collides with a submodule named the "
"same. Skipping it."
msgstr ""
-"Mô-Ä‘un-con trong lần chuyển giao %s tại đưá»ng dẫn: “%s†va chạm vá»›i mô-Ä‘un-"
-"con cùng tên. Nên bỠqua nó."
+"Mô-Ä‘un-con trong lần chuyển giao %s tại đưá»ng dẫn: '%s' va chạm vá»›i mô-Ä‘un-"
+"con cùng tên. Nên sẽ bỠqua."
#, c-format
msgid "submodule entry '%s' (%s) is a %s, not a commit"
msgstr ""
-"mục tin mô-đun-con “%s†(%s) là một %s, không phải là một lần chuyển giao"
+"mục tin mô-đun-con '%s' (%s) là một %s, không phải là một lần chuyển giao"
#, c-format
msgid ""
"Could not run 'git rev-list <commits> --not --remotes -n 1' command in "
"submodule %s"
msgstr ""
-"Không thể chạy lệnh “git rev-list <các lần chuyển giao> --not --remotes -n "
-"1†trong mô-Ä‘un-con “%sâ€"
+"Không thể chạy lệnh 'git rev-list <các lần chuyển giao> --not --remotes -n "
+"1' trong mô-đun-con '%s'"
#, c-format
msgid "process for submodule '%s' failed"
-msgstr "xử lý cho mô-đun-con “%s†gặp lỗi"
+msgstr "xử lý cho mô-đun-con '%s' gặp lỗi"
#, c-format
msgid "Pushing submodule '%s'\n"
-msgstr "Äẩy lên mô-Ä‘un-con “%sâ€\n"
+msgstr "Äẩy lên mô-Ä‘un-con '%s'\n"
#, c-format
msgid "Unable to push submodule '%s'\n"
-msgstr "Không thể đẩy lên mô-Ä‘un-con “%sâ€\n"
+msgstr "Không thể đẩy lên mô-đun-con '%s'\n"
#, c-format
msgid "Fetching submodule %s%s\n"
@@ -19913,11 +21684,11 @@ msgstr "Äang lấy vá» mô-Ä‘un-con %s%s\n"
#, c-format
msgid "Could not access submodule '%s'\n"
-msgstr "Không thể truy cập mô-Ä‘un-con “%sâ€\n"
+msgstr "Không thể truy cập mô-đun-con '%s'\n"
#, c-format
msgid "Could not access submodule '%s' at commit %s\n"
-msgstr "Không thể truy cập mô-đun-con “%s†ở lần chuyển giao %s\n"
+msgstr "Không thể truy cập mô-đun-con '%s' ở lần chuyển giao %s\n"
#, c-format
msgid "Fetching submodule %s%s at commit %s\n"
@@ -19929,65 +21700,74 @@ msgid ""
"%s"
msgstr ""
"Có lỗi khi lấy vỠmô-đun-con:\n"
-" “%sâ€"
+" '%s'"
#, c-format
msgid "'%s' not recognized as a git repository"
-msgstr "không nhận ra “%s†là một kho git"
+msgstr "không nhận ra '%s' là một kho git"
#, c-format
msgid "Could not run 'git status --porcelain=2' in submodule %s"
-msgstr "Không thể chạy “git status --porcelain=2†trong mô-Ä‘un-con “%sâ€"
+msgstr "Không thể chạy 'git status --porcelain=2' trong mô-đun-con '%s'"
#, c-format
msgid "'git status --porcelain=2' failed in submodule %s"
-msgstr "“git status --porcelain=2†gặp lá»—i trong mô-Ä‘un-con “%sâ€"
+msgstr "'git status --porcelain=2' gặp lỗi trong mô-đun-con '%s'"
#, c-format
msgid "could not start 'git status' in submodule '%s'"
-msgstr "không thể lấy thống kê “git status†trong mô-Ä‘un-con “%sâ€"
+msgstr "không thể khởi chạy 'git status' trong mô-đun-con '%s'"
#, c-format
msgid "could not run 'git status' in submodule '%s'"
-msgstr "không thể chạy “git status†trong mô-Ä‘un-con “%sâ€"
+msgstr "không thể chạy 'git status' trong mô-đun-con '%s'"
#, c-format
msgid "Could not unset core.worktree setting in submodule '%s'"
-msgstr "Không thể đặt core.worktree trong mô-Ä‘un-con “%sâ€"
+msgstr "Không thể đặt core.worktree trong mô-đun-con '%s'"
#, c-format
msgid "could not recurse into submodule '%s'"
-msgstr "không thể đệ quy vào trong mô-Ä‘un-con “%sâ€"
+msgstr "không thể đệ quy vào trong mô-đun-con '%s'"
msgid "could not reset submodule index"
-msgstr "không thể đặt lại mục lục của mô-đun-con"
+msgstr "không thể đặt lại chỉ mục của mô-đun-con"
#, c-format
msgid "submodule '%s' has dirty index"
-msgstr "mô-đun-con “%s†có mục lục còn bẩn"
+msgstr "mô-đun-con '%s' có chỉ mục không sạch"
#, c-format
msgid "Submodule '%s' could not be updated."
-msgstr "Mô-đun-con “%s†không thể được cập nhật."
+msgstr "Mô-đun-con '%s' không thể được cập nhật."
#, c-format
msgid "submodule git dir '%s' is inside git dir '%.*s'"
-msgstr "thư mục git mô Ä‘un con “%s†là bên trong git DIR “%.*sâ€"
+msgstr "thư mục git mô đun con '%s' là bên trong git DIR '%.*s'"
+
+#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"cần '%.*s' trong đưá»ng dẫn tá»›i mô-Ä‘un-con '%s' không phải là liên kết má»m"
+
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "cần đưá»ng dẫn tá»›i mô-Ä‘un-con '%s' không phải là liên kết má»m"
#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr ""
-"relocate_gitdir cho mô-Ä‘un-con “%s†vá»›i nhiá»u hÆ¡n má»™t cây làm việc là chưa "
+"relocate_gitdir cho mô-Ä‘un-con '%s' vá»›i nhiá»u hÆ¡n má»™t cây làm việc là chưa "
"được hỗ trợ"
#, c-format
msgid "could not lookup name for submodule '%s'"
-msgstr "không thể tìm kiếm tên cho mô-Ä‘un-con “%sâ€"
+msgstr "không thể tìm kiếm tên cho mô-đun-con '%s'"
#, c-format
msgid "refusing to move '%s' into an existing git dir"
-msgstr "từ chối di chuyển “%s†vào trong một thư mục git sẵn có"
+msgstr "từ chối di chuyển '%s' vào trong một thư mục git sẵn có"
#, c-format
msgid ""
@@ -19995,12 +21775,12 @@ msgid ""
"'%s' to\n"
"'%s'\n"
msgstr ""
-"Di cư thư mục git của “%s%s†từ\n"
-"“%s†sang\n"
-"“%sâ€\n"
+"Di cư thư mục git của '%s%s' từ\n"
+"'%s' sang\n"
+"'%s'\n"
msgid "could not start ls-files in .."
-msgstr "không thể lấy thông tin thống kê vỠls-files trong .."
+msgstr "không thể khởi chạy ls-files trong .."
#, c-format
msgid "ls-tree returned unexpected return code %d"
@@ -20008,13 +21788,22 @@ msgstr "ls-tree trả vỠmã không như mong đợi %d"
#, c-format
msgid "failed to lstat '%s'"
-msgstr "gặp lá»—i khi lstat “%sâ€"
+msgstr "gặp lỗi khi lstat '%s'"
-msgid "unhandled options"
-msgstr "các tùy chá»n được không xá»­ lý"
+msgid "no remote configured to get bundle URIs from"
+msgstr "không có máy chủ để lấy URI bundle"
-msgid "error preparing revisions"
-msgstr "gặp lỗi khi chuẩn bị các điểm xét duyệt"
+msgid "could not get the bundle-uri list"
+msgstr "không thể lấy vỠdanh sách bundle-uri"
+
+msgid "test-tool cache-tree <options> (control|prime|update)"
+msgstr "test-tool cache-tree <các tuỳ chá»n> (control|prime|update)"
+
+msgid "clear the cache tree before each iteration"
+msgstr "dá»n cây nhá»› tạm trước má»—i chu kỳ"
+
+msgid "number of entries in the cache tree to invalidate (default 0)"
+msgstr "số mục cần huỷ trong câu nhớ tạm (mặc định 0)"
#, c-format
msgid "commit %s is not marked reachable"
@@ -20027,7 +21816,7 @@ msgid "test-tool serve-v2 [<options>]"
msgstr "test-tool serve-v2 [<các tùy chá»n>]"
msgid "exit immediately after advertising capabilities"
-msgstr "thoát ngay sau khi khởi tạo quảng cáo capabilities"
+msgstr "thoát ngay sau khi quảng bá capabilities"
msgid "test-helper simple-ipc is-active [<name>] [<options>]"
msgstr "test-helper simple-ipc is-active [<tên>] [<các tùy chá»n>]"
@@ -20062,7 +21851,7 @@ msgid "named-pipe name"
msgstr "tên named-pipe"
msgid "number of threads in server thread pool"
-msgstr "số lượng tiến trình trong kho tiến trình máy phục vụ"
+msgstr "số lượng tiến trình trong kho tiến trình máy chủ"
msgid "seconds to wait for daemon to start or stop"
msgstr "số giây mà dịch vụ chạy ná»n chá» khi khởi động hoặc dừng"
@@ -20083,67 +21872,62 @@ msgid "token"
msgstr "thẻ bài"
msgid "command token to send to the server"
-msgstr "thẻ bài lệnh để gửi lên cho máy phục vụ"
+msgstr "thẻ bài lệnh để gửi lên cho máy chủ"
-#, c-format
-msgid "running trailer command '%s' failed"
-msgstr "chạy lệnh kéo theo “%s†gặp lỗi"
+msgid "unit-test [<options>]"
+msgstr "unit-test [<các tùy chá»n>]"
-#, c-format
-msgid "unknown value '%s' for key '%s'"
-msgstr "không hiểu giá trị “%s†cho khóa “%sâ€"
+msgid "immediately exit upon the first failed test"
+msgstr "thoát ngay khi gặp test thất bại"
-#, c-format
-msgid "empty trailer token in trailer '%.*s'"
-msgstr "thẻ thừa trống rá»—ng trong phần thừa “%.*sâ€"
+msgid "suite[::test]"
+msgstr "suite[::test]"
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "không Ä‘á»c được tập tin đầu vào “%sâ€"
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "chạy riêng test suite hoặc test <suite[::test]>"
-#, c-format
-msgid "could not stat %s"
-msgstr "không thể lấy thông tin thống kê vỠ%s"
+msgid "suite"
+msgstr "suite"
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "\"%s\" không phải là tập tin bình thưá»ng"
+msgid "exclude test suite <suite>"
+msgstr "loại trừ test suite <suite>"
#, c-format
-msgid "file %s is not writable by user"
-msgstr "tập tin %s ngưá»i dùng không thể ghi được"
+msgid "running trailer command '%s' failed"
+msgstr "chạy lệnh trailer '%s' gặp lỗi"
-msgid "could not open temporary file"
-msgstr "không thể tạo tập tin tạm thá»i"
+#, c-format
+msgid "unknown value '%s' for key '%s'"
+msgstr "không hiểu giá trị '%s' cho khóa '%s'"
#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "không thể đổi tên tập tin tạm thá»i thành %s"
+msgid "empty trailer token in trailer '%.*s'"
+msgstr "thẻ trailer trống rỗng trong phần trailer '%.*s'"
msgid "full write to remote helper failed"
-msgstr "ghi đầy đủ lên bộ hỗ trợ máy chủ gặp lỗi"
+msgstr "ghi đầy đủ lên helper máy chủ gặp lỗi"
#, c-format
msgid "unable to find remote helper for '%s'"
-msgstr "không thể tìm thấy bá»™ há»— trợ máy chá»§ cho “%sâ€"
+msgstr "không thể tìm thấy helper máy chủ cho '%s'"
msgid "can't dup helper output fd"
-msgstr "không thể nhân đôi fd dầu ra bộ hỗ trợ"
+msgstr "không thể nhân đôi fd dầu ra helper"
#, c-format
msgid ""
"unknown mandatory capability %s; this remote helper probably needs newer "
"version of Git"
msgstr ""
-"không hiểu capability bắt buộc %s; bộ hỗ trợ máy chủ này gần như chắc chắn "
-"là cần phiên bản Git mới hơn"
+"không hiểu capability bắt buộc %s; helper máy chủ này gần như chắc chắn là "
+"cần phiên bản Git mới hơn"
msgid "this remote helper should implement refspec capability"
-msgstr "bộ hỗ trợ máy chủ này cần phải thực thi capability đặc tả tham chiếu"
+msgstr "remote helper này cần hỗ trợ capability đặc tả tham chiếu"
#, c-format
msgid "%s unexpectedly said: '%s'"
-msgstr "%s said bất ngá»: “%sâ€"
+msgstr "%s bất ngá» trả lá»i: '%s'"
#, c-format
msgid "%s also locked %s"
@@ -20169,9 +21953,6 @@ msgstr "giao thức này không há»— trợ cài đặt đưá»ng dẫn dịch vá
msgid "invalid remote service path"
msgstr "đưá»ng dẫn dịch vụ máy chá»§ không hợp lệ"
-msgid "operation not supported by protocol"
-msgstr "thao tác không được gia thức hỗ trợ"
-
#, c-format
msgid "can't connect to subservice %s"
msgstr "không thể kết nối đến dịch vụ phụ %s"
@@ -20180,15 +21961,15 @@ msgid "--negotiate-only requires protocol v2"
msgstr "--negotiate-only cần giao thức v2"
msgid "'option' without a matching 'ok/error' directive"
-msgstr "“option†không có chỉ thị “ok/error†tương ứng"
+msgstr "'option' không có chỉ thị 'ok/error' tương ứng"
#, c-format
msgid "expected ok/error, helper said '%s'"
-msgstr "cần ok/error, nhưng bá»™ há»— trợ lại nói “%sâ€"
+msgstr "cần ok/error, nhưng helper lại nói '%s'"
#, c-format
msgid "helper reported unexpected status of %s"
-msgstr "bộ hỗ trợ báo cáo rằng không cần tình trạng của %s"
+msgstr "helper báo cáo tình trạng bất thưá»ng cá»§a %s"
#, c-format
msgid "helper %s does not support dry-run"
@@ -20212,14 +21993,14 @@ msgstr "helper %s không hỗ trợ --%s"
#, c-format
msgid "helper %s does not support 'push-option'"
-msgstr "helper %s không há»— trợ “push-optionâ€"
+msgstr "helper %s không hỗ trợ 'push-option'"
msgid "remote-helper doesn't support push; refspec needed"
msgstr "remote-helper không hỗ trợ push; cần đặc tả tham chiếu"
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "helper %s không há»— trợ “forceâ€"
+msgid "helper %s does not support '--force'"
+msgstr "helper %s không hỗ trợ '--force'"
msgid "couldn't run fast-export"
msgstr "không thể chạy fast-export"
@@ -20238,7 +22019,7 @@ msgstr ""
#, c-format
msgid "unsupported object format '%s'"
-msgstr "không há»— trợ định dạng đối tượng “%sâ€"
+msgstr "không hỗ trợ định dạng đối tượng '%s'"
#, c-format
msgid "malformed response in ref list: %s"
@@ -20277,18 +22058,18 @@ msgstr "không thể khởi chạy tuyến trình cho việc chép dữ liệu"
#, c-format
msgid "Would set upstream of '%s' to '%s' of '%s'\n"
-msgstr "Không thể đặt thượng nguồn cá»§a “%s†thành “%s†cá»§a “%sâ€\n"
+msgstr "Không thể đặt thượng nguồn của '%s' thành '%s' của '%s'\n"
#, c-format
msgid "could not read bundle '%s'"
-msgstr "không thể Ä‘á»c bó “%sâ€"
+msgstr "không thể Ä‘á»c bó '%s'"
#, c-format
msgid "transport: invalid depth option '%s'"
-msgstr "vận chuyển: tùy chá»n độ sâu “%s†không hợp lệ"
+msgstr "vận chuyển: tùy chá»n độ sâu '%s' không hợp lệ"
msgid "see protocol.version in 'git help config' for more details"
-msgstr "xem protocol.version trong “git help config†để có thêm thông tin"
+msgstr "xem protocol.version trong 'git help config' để có thêm thông tin"
msgid "server options require protocol version 2 or later"
msgstr "các tùy chá»n máy chá»§ yêu cầu giao thức phiên bản 2 hoặc má»›i hÆ¡n"
@@ -20297,18 +22078,14 @@ msgid "server does not support wait-for-done"
msgstr "máy chủ không hỗ trợ wait-for-done"
msgid "could not parse transport.color.* config"
-msgstr "không thể phân tích cú pháp cấu hình transport.color.*"
+msgstr "không hiểu cú pháp cấu hình transport.color.*"
msgid "support for protocol v2 not implemented yet"
-msgstr "việc hỗ trợ giao thức v2 chưa được thực hiện"
-
-#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "không hiểu giá trị cho cho cấu hình “%sâ€: %s"
+msgstr "chưa hỗ trợ giao thức v2"
#, c-format
msgid "transport '%s' not allowed"
-msgstr "không cho phép phương thức vận chuyển “%sâ€"
+msgstr "không cho phép phương thức vận chuyển '%s'"
msgid "git-over-rsync is no longer supported"
msgstr "git-over-rsync không còn được hỗ trợ nữa"
@@ -20319,7 +22096,7 @@ msgid ""
"not be found on any remote:\n"
msgstr ""
"Các đưá»ng dẫn mô-Ä‘un-con sau đây có chứa các thay đổi cái mà\n"
-"có thể được tìm thấy trên má»i máy phục vụ:\n"
+"có thể được tìm thấy trên má»i máy chá»§:\n"
#, c-format
msgid ""
@@ -20344,20 +22121,29 @@ msgstr ""
"\n"
"\tgit push\n"
"\n"
-"để đẩy chúng lên máy phục vụ.\n"
+"để đẩy chúng lên máy chủ.\n"
"\n"
msgid "Aborting."
-msgstr "Bãi bá»."
+msgstr "huá»· bá»."
msgid "failed to push all needed submodules"
msgstr "gặp lỗi khi đẩy dữ liệu của tất cả các mô-đun-con cần thiết"
+msgid "bundle-uri operation not supported by protocol"
+msgstr "thao tác bundle-uri không được giao thức hỗ trợ"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "không thể lấy vỠdanh sách bundle-uri do phía máy chủ quảng bá"
+
+msgid "operation not supported by protocol"
+msgstr "thao tác không được giao thức hỗ trợ"
+
msgid "too-short tree object"
msgstr "đối tượng cây quá ngắn"
msgid "malformed mode in tree entry"
-msgstr "chế độ dị hình trong đỠmục cây"
+msgstr "chế độ sai quy cách trong đỠmục cây"
msgid "empty filename in tree entry"
msgstr "tên tập tin trống rỗng trong mục tin cây"
@@ -20452,7 +22238,7 @@ msgid ""
"The following untracked working tree files would be removed by checkout:\n"
"%%s"
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị gỡ bỠbởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị xoá bỠbởi lệnh "
"checkout:\n"
"%%s"
@@ -20461,17 +22247,17 @@ msgid ""
"The following untracked working tree files would be removed by merge:\n"
"%%sPlease move or remove them before you merge."
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị gỡ bỠbởi lệnh hòa "
-"trá»™n:\n"
-"%%sVui lòng di chuyển hay gỡ bỠchúng trước khi bạn hòa trộn."
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị xoá bỠbởi lệnh "
+"hòa trộn:\n"
+"%%sVui lòng di chuyển hay xoá bỠchúng trước khi bạn hòa trộn."
#, c-format
msgid ""
"The following untracked working tree files would be removed by merge:\n"
"%%s"
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị gỡ bỠbởi lệnh hòa "
-"trá»™n:\n"
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị xoá bỠbởi lệnh "
+"hòa trộn:\n"
"%%s"
#, c-format
@@ -20479,15 +22265,15 @@ msgid ""
"The following untracked working tree files would be removed by %s:\n"
"%%sPlease move or remove them before you %s."
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị gỡ bỠbởi %s:\n"
-"%%sVui lòng di chuyển hay gỡ bỠchúng trước khi bạn %s."
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị xoá bỠbởi %s:\n"
+"%%sVui lòng di chuyển hay xoá bỠchúng trước khi bạn %s."
#, c-format
msgid ""
"The following untracked working tree files would be removed by %s:\n"
"%%s"
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị gỡ bỠbởi %s:\n"
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị xoá bỠbởi %s:\n"
"%%s"
#, c-format
@@ -20496,9 +22282,9 @@ msgid ""
"checkout:\n"
"%%sPlease move or remove them before you switch branches."
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị ghi đè bởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị ghi đè bởi lệnh "
"checkout:\n"
-"%%sVui lòng di chuyển hay gỡ bỠchúng trước khi bạn chuyển nhánh."
+"%%sVui lòng di chuyển hay xoá bỠchúng trước khi bạn chuyển nhánh."
#, c-format
msgid ""
@@ -20506,7 +22292,7 @@ msgid ""
"checkout:\n"
"%%s"
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị ghi đè bởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị ghi đè bởi lệnh "
"checkout:\n"
"%%s"
@@ -20515,16 +22301,16 @@ msgid ""
"The following untracked working tree files would be overwritten by merge:\n"
"%%sPlease move or remove them before you merge."
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị ghi đè bởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị ghi đè bởi lệnh "
"hòa trộn:\n"
-"%%sVui lòng di chuyển hay gỡ bỠchúng trước khi bạn hòa trộn."
+"%%sVui lòng di chuyển hay xoá bỠchúng trước khi bạn hòa trộn."
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by merge:\n"
"%%s"
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị ghi đè bởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị ghi đè bởi lệnh "
"hòa trộn:\n"
"%%s"
@@ -20533,22 +22319,22 @@ msgid ""
"The following untracked working tree files would be overwritten by %s:\n"
"%%sPlease move or remove them before you %s."
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị ghi đè bởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị ghi đè bởi lệnh "
"%s:\n"
-"%%sVui lòng di chuyển hay gỡ bỠchúng trước khi bạn %s."
+"%%sVui lòng di chuyển hay xoá chúng trước khi bạn %s."
#, c-format
msgid ""
"The following untracked working tree files would be overwritten by %s:\n"
"%%s"
msgstr ""
-"Các tập tin cây làm việc chưa được theo dõi sau đây sẽ bị ghi đè bởi lệnh "
+"Các tập tin trong cây làm việc chưa được theo dõi sau sẽ bị ghi đè bởi lệnh "
"%s:\n"
"%%s"
#, c-format
msgid "Entry '%s' overlaps with '%s'. Cannot bind."
-msgstr "Mục “%s†đè lên “%sâ€. Không thể buá»™c."
+msgstr "Mục '%s' đè lên '%s'. Không thể bind."
#, c-format
msgid ""
@@ -20564,7 +22350,7 @@ msgid ""
"patterns:\n"
"%s"
msgstr ""
-"Các đưá»ng dẫn sau đây không được cập nhật và vẫn được để lại bất chấp các "
+"Các đưá»ng dẫn sau đây chưa được cập nhật và vẫn được để lại mặc dù khá»›p các "
"mẫu sparse:\n"
"%s"
@@ -20583,21 +22369,21 @@ msgid ""
"patterns:\n"
"%s"
msgstr ""
-"Các đưá»ng dẫn sau đây đã sẵn hiện diện và như vậy không được cập nhật bất "
-"cấp các mẫu sparse:\n"
+"Các đưá»ng dẫn sau đây đã tồn tại và như vậy không được cập nhật mặc dù khá»›p "
+"các mẫu sparse:\n"
"%s"
#, c-format
msgid "Aborting\n"
-msgstr "Bãi bá»\n"
+msgstr "Huá»· bá»\n"
#, c-format
msgid ""
"After fixing the above paths, you may want to run `git sparse-checkout "
"reapply`.\n"
msgstr ""
-"Sau khi sá»­a các đưá»ng dẫn phía trên, bạn có thể chạy “git sparse-checkout "
-"reapply“.\n"
+"Sau khi sá»­a các đưá»ng dẫn phía trên, bạn có thể chạy 'git sparse-checkout "
+"reapply'.\n"
msgid "Updating files"
msgstr "Äang cập nhật các tập tin"
@@ -20607,12 +22393,12 @@ msgid ""
"on a case-insensitive filesystem) and only one from the same\n"
"colliding group is in the working tree:\n"
msgstr ""
-"các đưá»ng dẫn sau đây có xung đột(vd: các đưá»ng dẫn phân biệt\n"
-"HOA/thưá»ng trên má»™t hệ thống tập tin không phân biệt HOA/thưá»ng)\n"
-"và chỉ một từ cùng một nhóm xung đột là trong cây làm việc hiện tại:\n"
+"các đưá»ng dẫn sau đây có xung đột (vd: các đưá»ng dẫn phân biệt HOA/thưá»ng\n"
+"trên hệ thống tập tin không phân biệt HOA/thưá»ng) và chỉ má»™t đưá»ng dẫn\n"
+"trong nhóm xung đột nằm trong cây làm việc hiện tại:\n"
msgid "Updating index flags"
-msgstr "Äang cập nhật các cá» mục lục"
+msgstr "Äang cập nhật các cá» chỉ mục"
#, c-format
msgid "worktree and untracked commit have duplicate entries: %s"
@@ -20623,17 +22409,17 @@ msgid "expected flush after fetch arguments"
msgstr "cần đẩy dữ liệu lên đĩa sau các tham số của lệnh fetch"
msgid "invalid URL scheme name or missing '://' suffix"
-msgstr "tên lược đồ URL không hợp lệ, hoặc thiếu hậu tố “://â€"
+msgstr "tên lược đồ URL không hợp lệ, hoặc thiếu hậu tố '://'"
#, c-format
msgid "invalid %XX escape sequence"
msgstr "thoát chuỗi %XX không hợp lệ"
msgid "missing host and scheme is not 'file:'"
-msgstr "thiếu máy chá»§ và lược đồ thì không phải là giao thức “file:â€"
+msgstr "thiếu máy chủ và lược đồ không phải là 'file:'"
msgid "a 'file:' URL may not have a port number"
-msgstr "một URL kiểu “file:†không được chứa cổng"
+msgstr "URL kiểu 'file:' không được chứa cổng"
msgid "invalid characters in host name"
msgstr "có các ký tự không hợp lệ trong tên máy"
@@ -20642,27 +22428,43 @@ msgid "invalid port number"
msgstr "tên cổng không hợp lệ"
msgid "invalid '..' path segment"
-msgstr "Ä‘oạn đưá»ng dẫn “..†không hợp lệ"
+msgstr "Ä‘oạn đưá»ng dẫn '..' không hợp lệ"
+
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "lỗi: không thể định dạng thông điệp: %s\n"
+
+msgid "usage: "
+msgstr "cách dùng: "
+
+msgid "fatal: "
+msgstr "lá»—i nghiêm trá»ng: "
+
+msgid "error: "
+msgstr "lá»—i: "
+
+msgid "warning: "
+msgstr "cảnh báo: "
msgid "Fetching objects"
msgstr "Äang lấy vá» các đối tượng"
#, c-format
msgid "'%s' at main working tree is not the repository directory"
-msgstr "“%s†tại cây làm việc chình không phải là thư mục kho"
+msgstr "'%s' tại cây làm việc chính không phải là thư mục kho"
#, c-format
msgid "'%s' file does not contain absolute path to the working tree location"
msgstr ""
-"tập tin “%s†không chứa đưá»ng dẫn tuyệt đối đến vị trí cây làm việc hiện"
+"tập tin '%s' không chứa đưá»ng dẫn tuyệt đối đến vị trí cây làm việc hiện"
#, c-format
msgid "'%s' is not a .git file, error code %d"
-msgstr "“%s†không phải là tập tin .git, mã lỗi %d"
+msgstr "'%s' không phải là tập tin .git, mã lỗi %d"
#, c-format
msgid "'%s' does not point back to '%s'"
-msgstr "“%s†không chỉ ngược đến “%sâ€"
+msgstr "'%s' không chỉ ngược đến '%s'"
msgid "not a directory"
msgstr "không phải thư mục"
@@ -20671,7 +22473,7 @@ msgid ".git is not a file"
msgstr ".git không phải là một tập tin"
msgid ".git file broken"
-msgstr "tệp .git bị há»ng"
+msgstr "tập tin .git bị há»ng"
msgid ".git file incorrect"
msgstr "tập tin .git không chính xác"
@@ -20680,13 +22482,13 @@ msgid "not a valid path"
msgstr "không phải là má»™t đưá»ng dẫn hợp lệ"
msgid "unable to locate repository; .git is not a file"
-msgstr "không thể phân bổ kho chứa; .git không phải là một tập tin"
+msgstr "không thể định vị kho chứa; .git không phải là một tập tin"
msgid "unable to locate repository; .git file does not reference a repository"
-msgstr "không thể phân bổ kho chứa; tập tin .git tham chiếu đến một kho"
+msgstr "không thể định vị kho chứa; tập tin .git không chỉ đến một kho"
msgid "unable to locate repository; .git file broken"
-msgstr "không thể phân bổ kho chứa; tập tin .git bị há»ng"
+msgstr "không thể định vị kho chứa; tập tin .git bị há»ng"
msgid "gitdir unreadable"
msgstr "gitdir không thể Ä‘á»c được"
@@ -20716,7 +22518,7 @@ msgstr "tập tin gitdir chỉ đến vị trí không tồn tại"
#, c-format
msgid "unable to set %s in '%s'"
-msgstr "không thể đặt %s trong “%sâ€"
+msgstr "không thể đặt %s trong '%s'"
#, c-format
msgid "unable to unset %s in '%s'"
@@ -20727,95 +22529,97 @@ msgstr "gặp lỗi khi đặt cài đặt extensions.worktreeConfig"
#, c-format
msgid "could not setenv '%s'"
-msgstr "không thể setenv “%sâ€"
+msgstr "không thể setenv '%s'"
#, c-format
msgid "unable to create '%s'"
-msgstr "không thể tạo “%sâ€"
+msgstr "không thể tạo '%s'"
#, c-format
msgid "could not open '%s' for reading and writing"
-msgstr "không thể mở “%s†để Ä‘á»c và ghi"
+msgstr "không thể mở '%s' để Ä‘á»c và ghi"
#, c-format
msgid "unable to access '%s'"
-msgstr "không thể truy cập “%sâ€"
+msgstr "không thể truy cập '%s'"
msgid "unable to get current working directory"
msgstr "không thể lấy thư mục làm việc hiện hành"
+msgid "unable to get random bytes"
+msgstr "không thể lấy byte ngẫu nhiên"
+
msgid "Unmerged paths:"
msgstr "Những đưá»ng dẫn chưa được hòa trá»™n:"
msgid " (use \"git restore --staged <file>...\" to unstage)"
-msgstr " (dùng \"git restore --staged <tập-tin>…\" để bá» ra khá»i bệ phóng)"
+msgstr " (dùng \"git restore --staged <tập-tin>...\" để bá» ra khá»i vùng chá»)"
#, c-format
msgid " (use \"git restore --source=%s --staged <file>...\" to unstage)"
msgstr ""
-" (dùng \"git restore --source=%s --staged <tập-tin>…\" để bá» ra khá»i bệ "
+" (dùng \"git restore --source=%s --staged <tập-tin>...\" để bá» ra khá»i bệ "
"phóng)"
msgid " (use \"git rm --cached <file>...\" to unstage)"
-msgstr " (dùng \"git rm --cached <tập-tin>…\" để bá» ra khá»i bệ phóng)"
+msgstr " (dùng \"git rm --cached <tập-tin>...\" để bá» ra khá»i vùng chá»)"
msgid " (use \"git add <file>...\" to mark resolution)"
-msgstr " (dùng \"git add <tập-tin>…\" để đánh dấu là cần giải quyết)"
+msgstr " (dùng \"git add <tập-tin>...\" để đánh dấu là muốn thêm)"
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
-msgstr ""
-" (dùng \"git add/rm <tập-tin>…\" như là một cách thích hợp để đánh dấu là "
-"cần được giải quyết)"
+msgstr " (dùng \"git add/rm <tập-tin>...\" để đánh dấu là muốn thêm/xoá)"
msgid " (use \"git rm <file>...\" to mark resolution)"
-msgstr " (dùng \"git rm <tập-tin>…\" để đánh dấu là cần giải quyết)"
+msgstr " (dùng \"git rm <tập-tin>...\" để đánh dấu là muốn xoá)"
msgid "Changes to be committed:"
msgstr "Những thay đổi sẽ được chuyển giao:"
msgid "Changes not staged for commit:"
-msgstr "Các thay đổi chưa được đặt lên bệ phóng để chuyển giao:"
+msgstr "Các thay đổi chưa được đặt vào vùng chỠđể chuyển giao:"
msgid " (use \"git add <file>...\" to update what will be committed)"
-msgstr " (dùng \"git add <tập-tin>…\" để cập nhật những gì sẽ chuyển giao)"
+msgstr ""
+" (dùng \"git add <tập-tin>...\" để cập nhật những gì sẽ được chuyển giao)"
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
msgstr ""
-" (dùng \"git add/rm <tập-tin>…\" để cập nhật những gì sẽ được chuyển giao)"
+" (dùng \"git add/rm <tập-tin>...\" để cập nhật những gì sẽ được chuyển giao)"
msgid ""
" (use \"git restore <file>...\" to discard changes in working directory)"
msgstr ""
-" (dùng \"git restore <tập-tin>…\" để loại bỠcác thay đổi trong thư mục làm "
-"việc)"
+" (dùng \"git restore <tập-tin>...\" để loại bỠcác thay đổi trong thư mục "
+"làm việc)"
msgid " (commit or discard the untracked or modified content in submodules)"
msgstr ""
" (chuyển giao hoặc là loại bỠcác nội dung chưa được theo dõi hay đã sửa "
-"chữa trong mô-đun-con)"
+"trong mô-đun-con)"
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
msgstr ""
-" (dùng \"git %s <tập-tin>…\" để thêm vào những gì cần được chuyển giao)"
+" (dùng \"git %s <tập-tin>...\" để thêm vào những gì cần được chuyển giao)"
msgid "both deleted:"
-msgstr "bị xóa bởi cả hai:"
+msgstr "bị cả hai xóa đi:"
msgid "added by us:"
-msgstr "được thêm vào bởi chúng ta:"
+msgstr "được ta thêm vào:"
msgid "deleted by them:"
-msgstr "bị xóa Ä‘i bởi há»:"
+msgstr "bị hỠxóa đi:"
msgid "added by them:"
-msgstr "được thêm vào bởi há»:"
+msgstr "được hỠthêm vào:"
msgid "deleted by us:"
-msgstr "bị xóa bởi chúng ta:"
+msgstr "bị ta xóa đi:"
msgid "both added:"
-msgstr "được thêm vào bởi cả hai:"
+msgstr "được cả hai thêm vào:"
msgid "both modified:"
msgstr "bị sửa bởi cả hai:"
@@ -20836,10 +22640,10 @@ msgid "renamed:"
msgstr "đã đổi tên:"
msgid "typechange:"
-msgstr "đổi-kiểu:"
+msgstr "đổi kiểu:"
msgid "unknown:"
-msgstr "không hiểu:"
+msgstr "không rõ:"
msgid "unmerged:"
msgstr "chưa hòa trộn:"
@@ -20856,20 +22660,20 @@ msgstr "nội dung chưa được theo dõi, "
#, c-format
msgid "Your stash currently has %d entry"
msgid_plural "Your stash currently has %d entries"
-msgstr[0] "Bạn hiện nay ở trong phần cất đi đang có %d mục"
+msgstr[0] "Hiện trong phần cất đi đang có %d mục"
msgid "Submodules changed but not updated:"
msgstr "Những mô-đun-con đã bị thay đổi nhưng chưa được cập nhật:"
msgid "Submodule changes to be committed:"
-msgstr "Những mô-đun-con thay đổi đã được chuyển giao:"
+msgstr "Những thay đổi mô-đun-con sẽ được chuyển giao:"
msgid ""
"Do not modify or remove the line above.\n"
"Everything below it will be ignored."
msgstr ""
"Không sá»­a hay xóa bỠđưá»ng ở trên.\n"
-"Má»i thứ phía dưới sẽ được xóa bá»."
+"Má»i thứ phía dưới sẽ được bá» qua."
#, c-format
msgid ""
@@ -20878,8 +22682,8 @@ msgid ""
"You can use '--no-ahead-behind' to avoid this.\n"
msgstr ""
"\n"
-"Nó cần %.2f giây để tính toán giá trị của trước/sau của nhánh.\n"
-"Bạn có thể dùng “--no-ahead-behind†tránh phải Ä‘iá»u này.\n"
+"Cần tới %.2f giây để tính toán giá trị đứng trước/sau của nhánh.\n"
+"Bạn có thể dùng '--no-ahead-behind' để bỠqua.\n"
msgid "You have unmerged paths."
msgstr "Bạn có những đưá»ng dẫn chưa được hòa trá»™n."
@@ -20888,7 +22692,7 @@ msgid " (fix conflicts and run \"git commit\")"
msgstr " (sửa các xung đột rồi chạy \"git commit\")"
msgid " (use \"git merge --abort\" to abort the merge)"
-msgstr " (dùng \"git merge --abort\" để bãi bỠviệc hòa trộn)"
+msgstr " (dùng \"git merge --abort\" để huỷ bỠviệc hòa trộn)"
msgid "All conflicts fixed but you are still merging."
msgstr "Tất cả các xung đột đã được giải quyết nhưng bạn vẫn đang hòa trộn."
@@ -20897,112 +22701,107 @@ msgid " (use \"git commit\" to conclude merge)"
msgstr " (dùng \"git commit\" để hoàn tất việc hòa trộn)"
msgid "You are in the middle of an am session."
-msgstr "Bạn Ä‘ang ở giữa cá»§a má»™t phiên “amâ€."
+msgstr "Bạn đang trong một phiên 'am' (áp dụng bản vá từ hòm thư)."
msgid "The current patch is empty."
-msgstr "Miếng vá hiện tại bị trống rỗng."
+msgstr "bản vá hiện tại bị trống."
msgid " (fix conflicts and then run \"git am --continue\")"
msgstr " (sửa các xung đột và sau đó chạy lệnh \"git am --continue\")"
msgid " (use \"git am --skip\" to skip this patch)"
-msgstr " (dùng \"git am --skip\" để bỠqua miếng vá này)"
+msgstr " (dùng \"git am --skip\" để bỠqua bản vá này)"
msgid ""
" (use \"git am --allow-empty\" to record this patch as an empty commit)"
msgstr ""
-" (dùng \"git am --allow-empty\" ghi miếng vá này như một lần chuyển giao "
+" (dùng \"git am --allow-empty\" để ghi bản vá này thành một lần chuyển giao "
"rá»—ng)"
msgid " (use \"git am --abort\" to restore the original branch)"
-msgstr " (dùng \"git am --abort\" để phục hồi lại nhánh nguyên thủy)"
+msgstr " (dùng \"git am --abort\" để phục hồi lại nhánh gốc)"
msgid "git-rebase-todo is missing."
msgstr "thiếu git-rebase-todo."
msgid "No commands done."
-msgstr "Không thực hiện lệnh nào."
+msgstr "Chưa thực hiện lệnh nào."
#, c-format
msgid "Last command done (%<PRIuMAX> command done):"
msgid_plural "Last commands done (%<PRIuMAX> commands done):"
-msgstr[0] "Lệnh thực hiện cuối (%<PRIuMAX> lệnh được thực thi):"
+msgstr[0] "Lệnh thực hiện cuối (đã thực thi %<PRIuMAX> lệnh):"
#, c-format
msgid " (see more in file %s)"
msgstr " (xem thêm trong %s)"
msgid "No commands remaining."
-msgstr "Không có lệnh nào còn lại."
+msgstr "Không còn lệnh nào."
#, c-format
msgid "Next command to do (%<PRIuMAX> remaining command):"
msgid_plural "Next commands to do (%<PRIuMAX> remaining commands):"
-msgstr[0] "Lệnh cần làm kế tiếp (%<PRIuMAX> lệnh còn lại):"
+msgstr[0] "Lệnh cần làm kế tiếp (còn %<PRIuMAX> lệnh):"
msgid " (use \"git rebase --edit-todo\" to view and edit)"
msgstr " (dùng lệnh \"git rebase --edit-todo\" để xem và sửa)"
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
-msgstr "Bạn hiện nay Ä‘ang thá»±c hiện việc “rebase†nhánh “%s†trên “%sâ€."
+msgstr "Bạn hiện đang thực hiện rebase (cải tổ) nhánh '%s' lên '%s'."
msgid "You are currently rebasing."
-msgstr "Bạn hiện nay đang thực hiện việc “rebase†(cải tổ)."
+msgstr "Bạn hiện đang thực hiện rebase (cải tổ)."
msgid " (fix conflicts and then run \"git rebase --continue\")"
-msgstr ""
-" (sửa các xung đột và sau đó chạy lệnh “cải tổ†\"git rebase --continue\")"
+msgstr " (sửa các xung đột và sau đó chạy lệnh \"git rebase --continue\")"
msgid " (use \"git rebase --skip\" to skip this patch)"
-msgstr " (dùng lệnh “cải tổ†\"git rebase --skip\" để bỠqua lần vá này)"
+msgstr " (dùng lệnh \"git rebase --skip\" để bỠqua bản vá này)"
msgid " (use \"git rebase --abort\" to check out the original branch)"
-msgstr ""
-" (dùng lệnh “cải tổ†\"git rebase --abort\" để check-out nhánh nguyên thủy)"
+msgstr " (dùng lệnh \"git rebase --abort\" để check-out nhánh gốc)"
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr ""
-" (khi tất cả các xung đột đã sửa xong: chạy lệnh “cải tổ†\"git rebase --"
-"continue\")"
+" (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git rebase --continue\")"
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
msgstr ""
-"Bạn hiện nay đang thực hiện việc chia tách một lần chuyển giao trong khi "
-"Ä‘ang “rebase†nhánh “%s†trên “%sâ€."
+"Bạn hiện đang chia nhỠmột lần chuyển giao trong khi đang rebase nhánh '%s' "
+"lên '%s'."
msgid "You are currently splitting a commit during a rebase."
msgstr ""
-"Bạn hiện tại đang cắt đôi một lần chuyển giao trong khi đang thực hiện việc "
-"rebase."
+"Bạn hiện đang chia nhỠmột lần chuyển giao trong khi đang thực hiện rebase."
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr ""
-" (Má»™t khi thư mục làm việc cá»§a bạn đã gá»n gàng, chạy lệnh “cải tổ†\"git "
-"rebase --continue\")"
+" (Sau khi thư mục làm việc đã ổn, chạy lệnh \"git rebase --continue\")"
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
-"Bạn hiện nay đang thực hiện việc sửa chữa một lần chuyển giao trong khi đang "
-"rebase nhánh “%s†trên “%sâ€."
+"Bạn hiện đang thực hiện sửa chữa một lần chuyển giao trong khi đang rebase "
+"nhánh '%s' lên '%s'."
msgid "You are currently editing a commit during a rebase."
-msgstr "Bạn hiện đang sửa một lần chuyển giao trong khi bạn thực hiện rebase."
+msgstr "Bạn hiện đang sửa một lần chuyển giao trong khi đang thực hiện rebase."
msgid " (use \"git commit --amend\" to amend the current commit)"
-msgstr " (dùng \"git commit --amend\" để “tu bổ†lần chuyển giao hiện tại)"
+msgstr " (dùng \"git commit --amend\" để tu bổ lần chuyển giao hiện tại)"
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
-" (chạy lệnh “cải tổ†\"git rebase --continue\" một khi bạn cảm thấy hài "
-"lòng vỠnhững thay đổi của mình)"
+" (chạy lệnh \"git rebase --continue\" khi bạn cảm thấy hài lòng vỠnhững "
+"thay đổi của mình)"
msgid "Cherry-pick currently in progress."
-msgstr "Cherry-pick hiện tại đang được thực hiện."
+msgstr "Cherry-pick hiện đang được thực hiện."
#, c-format
msgid "You are currently cherry-picking commit %s."
@@ -21021,17 +22820,17 @@ msgstr ""
"continue\")"
msgid " (use \"git cherry-pick --skip\" to skip this patch)"
-msgstr " (dùng \"git cherry-pick --skip\" để bỠqua miếng vá này)"
+msgstr " (dùng \"git cherry-pick --skip\" để bỠqua bản vá này)"
msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
msgstr " (dùng \"git cherry-pick --abort\" để hủy bỠthao tác cherry-pick)"
msgid "Revert currently in progress."
-msgstr "Hoàn nguyên hiện tại đang thực hiện."
+msgstr "Hoàn nguyên hiện đang được thực hiện."
#, c-format
msgid "You are currently reverting commit %s."
-msgstr "Bạn hiện nay Ä‘ang thá»±c hiện thao tác hoàn nguyên lần chuyển giao “%sâ€."
+msgstr "Bạn hiện nay đang thực hiện thao tác hoàn nguyên lần chuyển giao '%s'."
msgid " (fix conflicts and run \"git revert --continue\")"
msgstr " (sửa các xung đột và sau đó chạy lệnh \"git revert --continue\")"
@@ -21053,7 +22852,7 @@ msgstr " (dùng \"git revert --abort\" để hủy bỠthao tác hoàn nguyên
msgid "You are currently bisecting, started from branch '%s'."
msgstr ""
"Bạn hiện nay đang thực hiện thao tác di chuyển nửa bước (bisect), bắt đầu từ "
-"nhánh “%sâ€."
+"nhánh '%s'."
msgid "You are currently bisecting."
msgstr "Bạn hiện tại đang thực hiện việc bisect (di chuyển nửa bước)."
@@ -21062,19 +22861,18 @@ msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr " (dùng \"git bisect reset\" để quay trở lại nhánh nguyên thủy)"
msgid "You are in a sparse checkout."
-msgstr "Bạn đang trong lần lấy ra sparse."
+msgstr "Bạn đang ở trong lần checkout thưa."
#, c-format
msgid "You are in a sparse checkout with %d%% of tracked files present."
msgstr ""
-"Bạn đang ở trong lần lấy ra sparser %d%% của các tập tin được theo dõi hiện "
-"tại."
+"Bạn đang ở trong lần checkout thưa với %d%% tập tin hiện được theo dõi."
msgid "On branch "
msgstr "Trên nhánh "
msgid "interactive rebase in progress; onto "
-msgstr "rebase ở chế độ tương tác đang được thực hiện; lên trên "
+msgstr "rebase có tương tác đang được thực hiện; lên trên "
msgid "rebase in progress; onto "
msgstr "rebase đang được thực hiện: lên trên "
@@ -21098,33 +22896,37 @@ msgid "Untracked files"
msgstr "Những tập tin chưa được theo dõi"
msgid "Ignored files"
-msgstr "Những tập tin bị lỠđi"
+msgstr "Những tập tin bị bỠqua"
#, 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ần %.2f giây để liệt kê tất cả các tập tin chưa được theo dõi. “status -"
-"unoâ€\n"
-"có lẽ làm nó nhanh hơn, nhưng bạn phải cẩn thận đừng quên mình phải\n"
-"tá»± thêm các tập tin má»›i (xem “git help statusâ€.."
+"Cần %.2f để duyệt các tập tin không được theo dõi,\n"
+"nhưng đã ghi nhớ kết quả, và các lần chạy sau sẽ nhanh hơn."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "Cần %.2f để duyệt các tập tin không được theo dõi."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr "Xem 'git help status' để biết cách cải thiện việc này."
#, c-format
msgid "Untracked files not listed%s"
-msgstr "Những tập tin chưa được theo dõi không được liệt kê ra %s"
+msgstr "Không liệt kê những tập tin chưa được theo dõi%s"
msgid " (use -u option to show untracked files)"
-msgstr " (dùng tùy chá»n -u để hiển thị các tập tin chưa được theo dõi)"
+msgstr " (dùng tùy chá»n -u để hiển thị những tập tin chưa được theo dõi)"
msgid "No changes"
-msgstr "Không có thay đổi nào"
+msgstr "Không có thay đổi"
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
-"không có thay đổi nào được thêm vào để chuyển giao (dùng \"git add\" và/hoặc "
+"không có thay đổi nào được thêm vào để chuyển giao (dùng \"git add\" hoặc "
"\"git commit -a\")\n"
#, c-format
@@ -21136,14 +22938,14 @@ msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
"track)\n"
msgstr ""
-"không có gì được thêm vào lần chuyển giao nhưng có những tập tin chưa được "
-"theo dõi hiện diện (dùng \"git add\" để đưa vào theo dõi)\n"
+"không có gì được thêm vào để chuyển giao nhưng hiện có những tập tin chưa "
+"được theo dõi (dùng \"git add\" để đưa vào theo dõi)\n"
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr ""
-"không có gì được thêm vào lần chuyển giao nhưng có những tập tin chưa được "
-"theo dõi hiện diện\n"
+"không có gì được thêm vào lần chuyển giao nhưng có những tập tin hiện chưa "
+"được theo dõi\n"
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
@@ -21158,53 +22960,57 @@ msgstr "không có gì để chuyển giao\n"
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
-"không có gì để chuyển giao (dùng -u xem các tập tin chưa được theo dõi)\n"
+"không có gì để chuyển giao (dùng -u để xem những tập tin chưa được theo "
+"dõi)\n"
#, c-format
msgid "nothing to commit, working tree clean\n"
msgstr "không có gì để chuyển giao, thư mục làm việc sạch sẽ\n"
msgid "No commits yet on "
-msgstr "Vẫn không thực hiện lệnh chuyển giao nào "
+msgstr "Chưa thực hiện lệnh chuyển giao nào trên"
msgid "HEAD (no branch)"
msgstr "HEAD (không nhánh)"
msgid "different"
-msgstr "khác"
+msgstr "khác nhau"
msgid "behind "
-msgstr "đằng sau "
+msgstr "đứng sau "
msgid "ahead "
-msgstr "phía trước "
+msgstr "đứng trước "
#. TRANSLATORS: the action is e.g. "pull with rebase"
#, c-format
msgid "cannot %s: You have unstaged changes."
-msgstr "không thể %s: Bạn có các thay đổi chưa được đưa lên bệ phóng."
+msgstr "không thể %s: Bạn có các thay đổi chưa được đưa vào vùng chá»."
msgid "additionally, your index contains uncommitted changes."
-msgstr ""
-"thêm vào đó, bảng mục lục của bạn có chứa các thay đổi chưa được chuyển giao."
+msgstr "ngoài ra, chỉ mục của bạn có chứa các thay đổi chưa được chuyển giao."
#, c-format
msgid "cannot %s: Your index contains uncommitted changes."
msgstr ""
-"không thể %s: Mục lục của bạn có chứa các thay đổi chưa được chuyển giao."
+"không thể %s: chỉ mục của bạn có chứa các thay đổi chưa được chuyển giao."
+
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "không hiểu style '%s' cho '%s'"
msgid ""
"Error: Your local changes to the following files would be overwritten by "
"merge"
msgstr ""
-"Lỗi: Các thay đổi nội bộ của bạn với các tập tin sau đây sẽ bị ghi đè bởi "
-"lệnh hòa trộn"
+"Lỗi: Các thay đổi nội bộ của bạn với các tập tin sau đây sẽ bị ghi đè khi "
+"hòa trộn"
msgid "Automated merge did not work."
-msgstr "Hòa trộn một cách tự động không làm việc."
+msgstr "Hòa trộn tự động không thành công."
msgid "Should not be doing an octopus."
-msgstr "Không thể thực hiện một octopus."
+msgstr "Không thể thực hiện hoà trộn kiểu bạch tuộc."
#, sh-format
msgid "Unable to find common commit with $pretty_name"
@@ -21223,7 +23029,7 @@ msgid "Trying simple merge with $pretty_name"
msgstr "Äang thá»­ hòa trá»™n đơn giản vá»›i $pretty_name"
msgid "Simple merge did not work, trying automatic merge."
-msgstr "Hòa trộn đơn giản không làm việc, thử hòa trộn tự động."
+msgstr "Hòa trộn đơn giản không thành công, thử hòa trộn tự động."
#, sh-format
msgid "usage: $dashless $USAGE"
@@ -21231,32 +23037,29 @@ msgstr "cách dùng: $dashless $USAGE"
#, sh-format
msgid "Cannot chdir to $cdup, the toplevel of the working tree"
-msgstr ""
-"Không thể chuyển thư mục (chdir) sang $cdup, thư mục ở mức cao nhất của cây "
-"làm việc"
+msgstr "Không thể chuyển thư mục sang $cdup, ở mức cao nhất của cây làm việc"
#, sh-format
msgid "fatal: $program_name cannot be used without a working tree."
msgstr ""
-"lá»—i nghiêm trá»ng: $program_name không thể được dùng ngoaoif thư mục làm việc."
+"lá»—i nghiêm trá»ng: $program_name không thể được dùng ngoài thư mục làm việc."
msgid "Cannot rewrite branches: You have unstaged changes."
msgstr ""
-"Không thể ghi lại các nhánh: Bạn có các thay đổi chưa được đưa lên bệ phóng."
+"Không thể ghi lại các nhánh: Bạn có các thay đổi chưa được đưa vào vùng chá»."
#, sh-format
msgid "Cannot $action: You have unstaged changes."
-msgstr "Không thể $action: Bạn có các thay đổi chưa được đưa lên bệ phóng."
+msgstr "Không thể $action: Bạn có các thay đổi chưa được đưa vào vùng chá»."
#, sh-format
msgid "Cannot $action: Your index contains uncommitted changes."
msgstr ""
-"Không thể $action: Mục lục của bạn có chứa các thay đổi chưa được chuyển "
+"Không thể $action: chỉ mục của bạn có chứa các thay đổi chưa được chuyển "
"giao."
msgid "Additionally, your index contains uncommitted changes."
-msgstr ""
-"Thêm vào đó, bảng mục lục của bạn có chứa các thay đổi chưa được chuyển giao."
+msgstr "Ngoài ra, chỉ mục của bạn có chứa các thay đổi chưa được chuyển giao."
msgid "You need to run this command from the toplevel of the working tree."
msgstr "Bạn cần chạy lệnh này từ thư mục ở mức cao nhất của cây làm việc."
@@ -21264,360 +23067,76 @@ msgstr "Bạn cần chạy lệnh này từ thư mục ở mức cao nhất củ
msgid "Unable to determine absolute path of git directory"
msgstr "Không thể dò tìm đưá»ng dẫn tuyệt đối cá»§a thư mục 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 đưá»ng dẫn đã touch (chạm)\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức\n"
-"được đánh dấu để chuyển lên bệ phóng."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức\n"
-"được đánh dấu để tạm cất."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức\n"
-"được đánh dấu để bỠchuyển lên bệ phóng."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức\n"
-"được đánh dấu để áp dụng."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Nếu miếng vá được áp dụng sạch sẽ, khúc đã sửa sẽ ngay lập tức\n"
-"được đánh dấu để loại bá»."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "gặp lỗi khi tập tin sửa khúc để ghi: %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"
-"Äể gỡ bá» các dòng “%sâ€, làm chúng thành những dòng “ “ (ná»™i dung).\n"
-"Äể xóa bá» dòng “%sâ€, xóa chúng Ä‘i.\n"
-"Những dòng bắt đầu bằng %s sẽ bị loại bá».\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "gặp lá»—i khi mở tập tin khúc để Ä‘á»c: %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 - đưa lên bệ phóng khúc này\n"
-"n - đừng đưa lên bệ phóng khúc này\n"
-"q - thoát; đừng đưa lên bệ phóng khúc này cũng như bất kỳ cái nào còn lại\n"
-"a - đưa lên bệ phóng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng đưa lên bệ phóng khúc này cũng như bất kỳ cái nào còn lại trong tập "
-"tin"
-
-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 - tạm cất khúc này\n"
-"n - đừng tạm cất khúc này\n"
-"q - thoát; đừng tạm cất khúc này cũng như bất kỳ cái nào còn lại\n"
-"a - tạm cất khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng tạm cất khúc này cũng như bất kỳ cái nào còn lại trong tập tin"
-
-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 - đưa ra khá»i bệ phóng khúc này\n"
-"n - đừng đưa ra khá»i bệ phóng khúc này\n"
-"q - thoát; đừng đưa ra khá»i bệ phóng khúc này cÅ©ng như bất kỳ cái nào còn "
-"lại\n"
-"a - đưa ra khá»i bệ phóng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng đưa ra khá»i bệ phóng khúc này cÅ©ng như bất kỳ cái nào còn lại trong "
-"tập tin"
-
-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 - áp dụng khúc này vào mục lục\n"
-"n - đừng áp dụng khúc này vào mục lục\n"
-"q - thoát; đừng áp dụng khúc này cũng như bất kỳ cái nào còn lại\n"
-"a - áp dụng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng áp dụng khúc này cũng như bất kỳ cái nào sau này trong tập tin"
-
-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 - loại bá» khúc này khá»i cây làm việc\n"
-"n - đừng loại bá» khúc khá»i cây làm việc\n"
-"q - thoát; đừng loại bỠkhúc này cũng như bất kỳ cái nào còn lại\n"
-"a - loại bỠkhúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng loại bỠkhúc này cũng như bất kỳ cái nào sau này trong tập tin"
-
-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 - loại bá» khúc này khá»i mục lục và cây làm việc\n"
-"n - đừng loại bá» khúc khá»i mục lục và cây làm việc\n"
-"q - thoát; đừng loại bỠkhúc này cũng như bất kỳ cái nào còn lại\n"
-"a - loại bỠkhúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng loại bỠkhúc này cũng như bất kỳ cái nào sau này trong tập tin"
-
-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 - áp dụng khúc này vào mục lục và cây làm việc\n"
-"n - đừng áp dụng khúc vào mục lục và cây làm việc\n"
-"q - thoát; đừng áp dụng khúc này cũng như bất kỳ cái nào còn lại\n"
-"a - áp dụng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng áp dụng khúc này cũng như bất kỳ cái nào sau này trong tập tin"
-
-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 - áp dụng khúc này vào cây làm việc\n"
-"n - đừng áp dụng khúc vào cây làm việc\n"
-"q - thoát; đừng áp dụng khúc này cũng như bất kỳ cái nào còn lại\n"
-"a - áp dụng khúc này và tất cả các khúc sau này trong tập tin\n"
-"d - đừng áp dụng khúc này cũng như bất kỳ cái nào sau này trong tập tin"
-
-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 - chá»n má»™t khúc muốn tá»›i\n"
-"/ - tìm một khúc khớp với biểu thức chính quy đưa ra\n"
-"j - để lại khúc này là chưa quyết định, xem khúc chưa quyết định kế\n"
-"J - để lại khúc này là chưa quyết định, xem khúc kế\n"
-"k - để lại khúc này là chưa quyết định, xem khúc chưa quyết định kế trước\n"
-"K - để lại khúc này là chưa quyết định, xem khúc kế trước\n"
-"s - chia khúc hiện tại thành các khúc nhỠhơn\n"
-"e - sửa bằng tay khúc hiện hành\n"
-"? - in trợ giúp\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Các khúc đã chá»n không được áp dụng vào bảng mục lục!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "bỠqua những thứ chưa hòa trộn: %s\n"
-
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng thay đổi chế độ cho cây làm việc [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng việc xóa cho cây làm việc [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng việc thêm cho cây làm việc [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "Ãp dụng khúc này vào cây làm việc [y,n,q,a,d%s,?]? "
-
-msgid "No other hunks to goto\n"
-msgstr "Không còn khúc nào để mà nhảy đến\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Số không hợp lệ: “%sâ€\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Rất tiếc, chỉ có sẵn %d khúc.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Không còn khúc nào để mà tìm kiếm\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Äịnh dạng tìm kiếm cá»§a biểu thức chính quy không đúng %s: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Không thấy khúc nào khớp mẫu đã cho\n"
-
-msgid "No previous hunk\n"
-msgstr "Không có khúc kế trước\n"
-
-msgid "No next hunk\n"
-msgstr "Không có khúc kế tiếp\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Rất tiếc, không thể chia nhỠkhúc này\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Chi nhỠthành %d khúc.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Rất tiếc, không thể sửa khúc này\n"
-
-#. 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 - hiển thị các đưá»ng dẫn vá»›i các thay đổi\n"
-"update - đặt trạng thái cây làm việc thành tập hợp các thay đổi đã "
-"đặt lên bệ phóng\n"
-"revert - hoàn nguyên tập hợp các thay đổi đã đặt lên bệ phóng trở lại "
-"phiên bản HEAD\n"
-"patch - cậy các khúc và cập nhật có lá»±a chá»n\n"
-"diff\t - xem khác biệt giữa HEAD và mục lục\n"
-"add untracked - thêm nội dung các các tập tin chưa theo dõi và tập hợp các "
-"thay đổi đã đặt lên bệ phóng\n"
-
-msgid "missing --"
-msgstr "thiếu --"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "không hiểu chế độ --patch: %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "đối số không hợp lệ %s, cần --"
-
msgid "local zone differs from GMT by a non-minute interval\n"
-msgstr "múi giá» ná»™i bá»™ khác biệt vá»›i GMT bởi khoảng thá»i gian không-phút\n"
+msgstr "múi giá» ná»™i bá»™ lệch vá»›i GMT má»™t khoảng thá»i gian không-tròn-phút\n"
msgid "local time offset greater than or equal to 24 hours\n"
-msgstr "khoảng bù thá»i gian ná»™i bá»™ lá»›n hÆ¡n hoặc bằng 24 giá»\n"
+msgstr "độ lệch thá»i gian ná»™i bá»™ lá»›n hÆ¡n hoặc bằng 24 giá»\n"
#, perl-format
msgid "fatal: command '%s' died with exit code %d"
-msgstr "lá»—i nghiêm trá»ng: lệnh “%s†chết vá»›i mã thoát %d"
+msgstr "lá»—i nghiêm trá»ng: lệnh '%s' đã thoát vá»›i mã %d"
msgid "the editor exited uncleanly, aborting everything"
-msgstr "trình soạn thảo thoát không sạch sẽ, bãi bá» má»i thứ"
+msgstr "trình soạn thảo thoát không thành công, huỷ bỠcác thay đổi"
#, perl-format
msgid ""
"'%s' contains an intermediate version of the email you were composing.\n"
-msgstr "“%s†có chưa một phiên bản trung gian của thư bạn đã soạn.\n"
+msgstr "'%s' có chứa một phiên bản trung gian của email bạn đã soạn.\n"
#, perl-format
msgid "'%s.final' contains the composed email.\n"
-msgstr "“%s.final†chứa thư điện tử đã soạn thảo.\n"
+msgstr "'%s.final' chứa emal đã soạn thảo.\n"
msgid "--dump-aliases incompatible with other options\n"
-msgstr "--dump-aliases xung khắc vá»›i các tùy chá»n khác\n"
+msgstr "--dump-aliases không tương thích vá»›i các tùy chá»n khác\n"
+
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases và --translate-aliases không tương thích với nhau\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 ""
-"lá»—i nghiêm trá»ng: tìm thấy các tùy chá»n cấu hình cho “sendmailâ€\n"
-"git-send-email được cấu hình vá»›i các tùy chá»n sendemail.* - chú ý “eâ€.\n"
+"lá»—i nghiêm trá»ng: tìm thấy các tùy chá»n cấu hình có tên 'sendmail'\n"
+"git-send-email được cấu hình vá»›i các tùy chá»n sendemail.* - chú ý chữ 'e'.\n"
"Äặt sendemail.forbidSendmailVariables thành false để tắt kiểm tra này.\n"
msgid "Cannot run git format-patch from outside a repository\n"
-msgstr "Không thể chạy git format-patch ở ngoài một kho chứa\n"
+msgstr "Không thể chạy git format-patch ở ngoài kho chứa\n"
msgid ""
"`batch-size` and `relogin` must be specified together (via command-line or "
"configuration option)\n"
msgstr ""
-"“batch-size†và “relogin†phải được chỉ định cùng với nhau (thông qua dòng "
-"lệnh hoặc tùy chá»n cấu hình)\n"
+"'batch-size' và 'relogin' phải được chỉ định cùng nhau (thông qua dòng lệnh "
+"hoặc tùy chá»n cấu hình)\n"
#, perl-format
msgid "Unknown --suppress-cc field: '%s'\n"
-msgstr "Không hiểu trưá»ng --suppress-cc: “%sâ€\n"
+msgstr "Không hiểu trưá»ng --suppress-cc: '%s'\n"
#, perl-format
msgid "Unknown --confirm setting: '%s'\n"
-msgstr "Không hiểu cài đặt --confirm: “%sâ€\n"
+msgstr "Không hiểu cài đặt --confirm: '%s'\n"
#, perl-format
msgid "warning: sendmail alias with quotes is not supported: %s\n"
-msgstr "cảnh báo: bí danh sendmail với dấu trích dẫn không được hỗ trợ: %s\n"
+msgstr "cảnh báo: không hỗ trợ bí danh sendmail với dấu trích dẫn: %s\n"
#, perl-format
msgid "warning: `:include:` not supported: %s\n"
-msgstr "cảnh báo: “:include:“ không được hỗ trợ: %s\n"
+msgstr "cảnh báo: không hỗ trợ ':include:': %s\n"
#, perl-format
msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
-msgstr "cảnh báo: chuyển hướng “/file“ hay “|pipe“ không được hỗ trợ: %s\n"
+msgstr "cảnh báo: không hỗ trợ chuyển hướng '/file' hay '|pipe': %s\n"
#, perl-format
msgid "warning: sendmail line is not recognized: %s\n"
-msgstr "cảnh báo: dòng sendmail không nhận ra được: %s\n"
+msgstr "cảnh báo: không hiểu dòng cấu hình sendmail: %s\n"
#, perl-format
msgid ""
@@ -21627,15 +23146,15 @@ msgid ""
" * Saying \"./%s\" if you mean a file; or\n"
" * Giving --format-patch option if you mean a range.\n"
msgstr ""
-"Tập tin “%s†đã có sẵn nhưng nó có lẽ cũng là chuẩn bị của\n"
-"các miếng vá tạo lần chuyển giao. Vui lòng làm rõ ý bằng…\n"
+"Tập tin '%s' có tồn tại nhưng cũng có thể hiểu là cần tạo bản vá cho\n"
+"một khoảng các lần chuyển giao. Vui lòng làm rõ ý của bạn bằng...\n"
"\n"
-" * Nói \"./%s\" nếu ý bạn là một tập tin; hoặc\n"
-" * ÄÆ°a ra tùy chá»n --format-patch nếu ý bạn là chuẩn bị.\n"
+" * Ghi \"./%s\" nếu ý bạn là tập tin; hoặc\n"
+" * ÄÆ°a ra tùy chá»n --format-patch nếu ý bạn là tạo bản vá.\n"
#, perl-format
msgid "Failed to opendir %s: %s"
-msgstr "Gặp lá»—i khi mở thư mục “%sâ€: %s"
+msgstr "Gặp lỗi khi opendir %s: %s"
msgid ""
"\n"
@@ -21643,7 +23162,7 @@ msgid ""
"\n"
msgstr ""
"\n"
-"Chưa chỉ định các tập tin miếng vá!\n"
+"Chưa chỉ định các tập tin bản vá!\n"
"\n"
#, perl-format
@@ -21652,7 +23171,7 @@ msgstr "Không có dòng chủ đỠtrong %s?"
#, perl-format
msgid "Failed to open for writing %s: %s"
-msgstr "Gặp lỗi khi mở “%s†để ghi: %s"
+msgstr "Gặp lỗi khi mở %s để ghi: %s"
msgid ""
"Lines beginning in \"GIT:\" will be removed.\n"
@@ -21662,21 +23181,21 @@ msgid ""
"Clear the body content if you don't wish to send a summary.\n"
msgstr ""
"Các dòng bắt đầu bằng \"GIT:\" sẽ bị xóa bá».\n"
-"Cân nhắc bao gồm một thống kê diff toàn thể hay bảng nội dung\n"
-"cho miếng vá mà bạn đang viết.\n"
+"Hãy cân nhắc bao gồm một bản diffstat hay chỉ mục\n"
+"cho bản vá bạn đang viết.\n"
"\n"
"Xóa nội dung phần thân nếu bạn không muốn gửi tóm tắt.\n"
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "Gặp lá»—i khi mở “%sâ€: %s"
-
-#, perl-format
msgid "Failed to open %s.final: %s"
msgstr "Gặp lỗi khi mở %s.final: %s"
+#, perl-format
+msgid "Failed to open %s: %s"
+msgstr "Gặp lỗi khi mở %s: %s"
+
msgid "Summary email is empty, skipping it\n"
-msgstr "Thư tổng thể là trống rỗng, nên bỠqua nó\n"
+msgstr "Thư tóm tắt trống, nên sẽ bỠqua\n"
#. TRANSLATORS: please keep [y/N] as is.
#, perl-format
@@ -21687,11 +23206,10 @@ msgid ""
"The following files are 8bit, but do not declare a Content-Transfer-"
"Encoding.\n"
msgstr ""
-"Các trưá»ng sau đây là 8bit, nhưng không khai báo má»™t Content-Transfer-"
-"Encoding.\n"
+"Các trưá»ng sau đây là 8bit, nhưng không khai báo Content-Transfer-Encoding.\n"
msgid "Which 8bit encoding should I declare [UTF-8]? "
-msgstr "Bảng mã 8bit nào tôi nên khai báo [UTF-8]? "
+msgstr "Nên khai báo bảng mã 8bit nào [UTF-8]? "
#, perl-format
msgid ""
@@ -21700,24 +23218,24 @@ msgid ""
"has the template subject '*** SUBJECT HERE ***'. Pass --force if you really "
"want to send.\n"
msgstr ""
-"Từ chối gửi bởi vì miếng vá\n"
+"Từ chối gửi vì bản vá\n"
"\t%s\n"
-"có chá»§ đỠở dạng mẫu “*** SUBJECT HERE ***â€. Dùng --force nếu bạn thá»±c sá»± "
+"có chủ đỠở dạng mẫu '*** SUBJECT HERE ***'. Dùng --force nếu bạn thực sự "
"muốn gửi.\n"
msgid "To whom should the emails be sent (if anyone)?"
-msgstr "Tá»›i ngưá»i mà thư được gá»­i (nếu có)?"
+msgstr "Gửi email đến ai (nếu có)?"
#, perl-format
msgid "fatal: alias '%s' expands to itself\n"
-msgstr "nghiêm trá»ng: bí danh “%s†được khai triển thành chính nó\n"
+msgstr "lá»—i nghiêm trá»ng: khai triển bí danh '%s' lại thành chính nó\n"
msgid "Message-ID to be used as In-Reply-To for the first email (if any)? "
-msgstr "Message-ID được dùng như là In-Reply-To cho thư đầu tiên (nếu có)? "
+msgstr "Dùng Message-ID như In-Reply-To cho email đầu tiên (nếu có)? "
#, perl-format
msgid "error: unable to extract a valid address from: %s\n"
-msgstr "lỗi: không thể rút trích một địa chỉ hợp lệ từ: %s\n"
+msgstr "lỗi: không thể trích xuất địa chỉ hợp lệ từ: %s\n"
#. TRANSLATORS: Make sure to include [q] [d] [e] in your
#. translation. The program will only accept English input
@@ -21727,7 +23245,7 @@ msgstr "Làm gì với địa chỉ này? (thoát[q]|xóa[d]|sửa[e]): "
#, perl-format
msgid "CA path \"%s\" does not exist"
-msgstr "ÄÆ°á»ng dẫn CA “%s†không tồn tại"
+msgstr "CA path '%s' không tồn tại"
msgid ""
" The Cc list above has been expanded by additional\n"
@@ -21741,28 +23259,28 @@ msgid ""
" run 'git config --global sendemail.confirm auto'.\n"
"\n"
msgstr ""
-" Danh sách Cc ở trên được diễn giải bằng các địa chỉ phụ\n"
-" thêm tìm thấy trong lá»i ghi chú lần chuyển giao cá»§a miếng vá.\n"
-" Theo mặc định send-email sẽ nhắc trước khi gửi bất cứ khi\n"
-" nào Ä‘iá»u này xảy ra. Cách hành xá»­ này được Ä‘iá»u khiển bởi cài\n"
+" Danh sách Cc ở trên đã được thêm các địa chỉ có trong\n"
+" nội dung lần chuyển giao của bản vá. Theo mặc định\n"
+" send-email sẽ nhắc bạn trước khi gá»­i má»—i khi Ä‘iá»u này \n"
+" xảy ra. Bạn có thể Ä‘iá»u chỉnh hành vi này qua cài\n"
" đặt cấu hình sendemail.confirm.\n"
"\n"
-" Äể biết thêm chi tiết, hãy chạy lệnh “git send-email --helpâ€.\n"
-" Äể giữ lại cách hành xá»­ hiện nay, làm hết lá»i nhắn này,\n"
-" chạy “git config --global sendemail.confirm autoâ€.\n"
+" Äể biết thêm chi tiết, hãy chạy lệnh 'git send-email --help'.\n"
+" Äể tiếp tục sá»­ dụng hành vi này, nhưng bá» hiển thị lá»i nhắc,\n"
+" chạy 'git config --global sendemail.confirm auto'.\n"
"\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 "Gửi thư này chứ? ([y]có|[n]không|[e]sửa|[q]thoát|[a]tất): "
+msgstr "Gửi email này chứ? ([y]có|[n]không|[e]sửa|[q]thoát|[a]tất cả): "
msgid "Send this email reply required"
-msgstr "Gá»­i thư này trả lá»i yêu cầu"
+msgstr "Hãy trả lá»i yêu cầu gá»­i email"
msgid "The required SMTP server is not properly defined."
-msgstr "Máy phục vụ SMTP chưa được định nghĩa một cách thích hợp."
+msgstr "Máy chủ SMTP chưa được định nghĩa đúng cách."
#, perl-format
msgid "Server does not support STARTTLS! %s"
@@ -21774,67 +23292,70 @@ msgstr "STARTTLS gặp lỗi! %s"
msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
msgstr ""
-"Không thể khởi tạo SMTP một cách đúng đắn. Kiểm tra cấu hình và dùng --smtp-"
-"debug."
+"Không thể khởi tạo SMTP đúng cách. Kiểm tra cấu hình và dùng --smtp-debug."
#, perl-format
msgid "Failed to send %s\n"
msgstr "Gặp lỗi khi gửi %s\n"
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Thá»­ gá»­i %s\n"
+msgid "Dry-Sent %s"
+msgstr "Thá»­ gá»­i %s"
#, perl-format
-msgid "Sent %s\n"
-msgstr "Gá»­i %s\n"
+msgid "Sent %s"
+msgstr "Gá»­i %s"
-msgid "Dry-OK. Log says:\n"
-msgstr "Dry-OK. Nhật ký nói rằng:\n"
+msgid "Dry-OK. Log says:"
+msgstr "Thử gửi OK. Nhật ký ghi lại:"
-msgid "OK. Log says:\n"
-msgstr "OK. Nhật ký nói rằng:\n"
+msgid "OK. Log says:"
+msgstr "OK. Nhật ký ghi lại:"
msgid "Result: "
msgstr "Kết quả: "
-msgid "Result: OK\n"
-msgstr "Kết quả: Tốt\n"
+msgid "Result: OK"
+msgstr "Kết quả: OK"
#, perl-format
msgid "can't open file %s"
-msgstr "không thể mở tập tin “%sâ€"
+msgstr "không thể mở tập tin '%s'"
#, perl-format
msgid "(mbox) Adding cc: %s from line '%s'\n"
-msgstr "(mbox) Thêm cc: %s từ dòng “%sâ€\n"
+msgstr "(mbox) Thêm cc: %s từ dòng '%s'\n"
#, perl-format
msgid "(mbox) Adding to: %s from line '%s'\n"
-msgstr "(mbox) Äang thêm to: %s từ dòng “%sâ€\n"
+msgstr "(mbox) Thêm to: %s từ dòng '%s'\n"
#, perl-format
msgid "(non-mbox) Adding cc: %s from line '%s'\n"
-msgstr "(non-mbox) Thêm cc: %s từ dòng “%sâ€\n"
+msgstr "(non-mbox) Thêm cc: %s từ dòng '%s'\n"
#, perl-format
msgid "(body) Adding cc: %s from line '%s'\n"
-msgstr "(body) Thêm cc: %s từ dòng “%sâ€\n"
+msgstr "(body) Thêm cc: %s từ dòng '%s'\n"
#, perl-format
msgid "(%s) Could not execute '%s'"
-msgstr "(%s) Không thể thá»±c thi “%sâ€"
+msgstr "(%s) Không thể thực thi '%s'"
#, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Äang thêm %s: %s từ: “%sâ€\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr "(%s) Dòng đầu ra sai quy cách từ '%s'"
#, perl-format
msgid "(%s) failed to close pipe to '%s'"
-msgstr "(%s) gặp lá»—i khi đóng đưá»ng ống đến “%sâ€"
+msgstr "(%s) gặp lỗi khi đóng pipe đến '%s'"
+
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) Thêm %s: %s từ: '%s'\n"
msgid "cannot send message as 7bit"
-msgstr "không thể lấy gửi thư dạng 7 bít"
+msgstr "không thể gửi thư dạng 7bit"
msgid "invalid transfer encoding"
msgstr "bảng mã truyá»n không hợp lệ"
@@ -21845,9 +23366,9 @@ msgid ""
"%s\n"
"warning: no patches were sent\n"
msgstr ""
-"nghiêm trá»ng: %s: bị từ chối bởi móc %s\n"
+"nghiêm trá»ng: %s: bị từ chối bởi hook %s\n"
"%s\n"
-"cảnh báo: không có miếng vá nào được gửi đi\n"
+"cảnh báo: không gửi đi bản vá nào\n"
#, perl-format
msgid "unable to open %s: %s\n"
@@ -21858,307 +23379,14 @@ msgid ""
"fatal: %s:%d is longer than 998 characters\n"
"warning: no patches were sent\n"
msgstr ""
-"nghiêm trá»ng: %s: %d là dài hÆ¡n 998 ký tá»±\n"
-"cảnh báo: không có miếng vá nào được gửi đi\n"
+"nghiêm trá»ng: %s: %d dài hÆ¡n 998 ký tá»±\n"
+"cảnh báo: không có bản vá nào được gửi đi\n"
#, perl-format
msgid "Skipping %s with backup suffix '%s'.\n"
-msgstr "Bá» qua %s vá»›i hậu tố sao lưu dá»± phòng “%sâ€.\n"
+msgstr "BỠqua %s với hậu tố sao lưu '%s'.\n"
#. TRANSLATORS: please keep "[y|N]" as is.
#, perl-format
msgid "Do you really want to send %s? [y|N]: "
msgstr "Bạn có thực sự muốn gửi %s? [y|N](có/KHÔNG): "
-
-#~ msgid "--preserve-merges was replaced by --rebase-merges"
-#~ msgstr "--preserve-merges đã bị thay thế bằng --rebase-merges"
-
-#, c-format
-#~ msgid ""
-#~ "CRLF will be replaced by LF in %s.\n"
-#~ "The file will have its original line endings in your working directory"
-#~ msgstr ""
-#~ "CRLF sẽ bị thay thế bằng LF trong %s.\n"
-#~ "Tập tin sẽ có kiểu xuống dòng như bản gốc trong thư mục làm việc của bạn"
-
-#, c-format
-#~ msgid ""
-#~ "LF will be replaced by CRLF in %s.\n"
-#~ "The file will have its original line endings in your working directory"
-#~ msgstr ""
-#~ "LF sẽ bị thay thế bằng CRLF trong %s.\n"
-#~ "Tập tin sẽ có kiểu xuống dòng như bản gốc trong thư mục làm việc của bạn"
-
-#, c-format
-#~ msgid "error reading section header '%s'"
-#~ msgstr "gặp lá»—i khi Ä‘á»c phần đầu cá»§a Ä‘oạn %s"
-
-#~ msgid "load_reverse_index: could not open pack"
-#~ msgstr "load_reverse_index: không thể mở gói"
-
-#, perl-format
-#~ msgid "fatal: %s: rejected by %s hook\n"
-#~ msgstr "lá»—i nghiêm trá»ng: %s: bị từ chối bởi móc %s\n"
-
-#~ msgid "git archive --list"
-#~ msgstr "git archive --list"
-
-#, c-format
-#~ msgid "unknown value for --diff-merges: %s"
-#~ msgstr "không hiểu giá trị cho --diff-merges: %s"
-
-#, c-format
-#~ msgid "invalid value '%s' for lsrefs.unborn"
-#~ msgstr "giá trị “%s†không hợp lệ cho lsrefs.unborn"
-
-#~ msgid "backend for `git stash -p`"
-#~ msgstr "ứng dụng chạy phía sau cho “git stash -pâ€"
-
-#, c-format
-#~ msgid "Invalid value for --empty: %s"
-#~ msgstr "Giá trị cho --empty không hợp lệ: %s"
-
-#, c-format
-#~ msgid "Invalid value for --patch-format: %s"
-#~ msgstr "Giá trị không hợp lệ cho --patch-format: %s"
-
-#, c-format
-#~ msgid "Invalid value for --show-current-patch: %s"
-#~ msgstr "Giá trị không hợp lệ cho --show-current-patch: %s"
-
-#~ msgid ""
-#~ "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad "
-#~ "| --term-new]"
-#~ msgstr ""
-#~ "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad "
-#~ "| --term-new]"
-
-#~ msgid "git bisect--helper --bisect-next"
-#~ msgstr "git bisect--helper --bisect-next"
-
-#~ msgid "git bisect--helper --bisect-visualize"
-#~ msgstr "git bisect--helper --bisect-visualize"
-
-#, c-format
-#~ msgid "invalid color '%s' in color.blame.repeatedLines"
-#~ msgstr "màu không hợp lệ “%s†trong color.blame.repeatedLines"
-
-#~ msgid "invalid value for blame.coloring"
-#~ msgstr "màu không hợp lệ cho blame.coloring"
-
-#~ msgid ""
-#~ "git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e "
-#~ "| -p | <type> | --textconv | --filters) [--path=<path>] <object>"
-#~ msgstr ""
-#~ "git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e "
-#~ "| -p | <kiểu> | --textconv) | --filters) [--path=<đưá»ng/dẫn>] <đối_tượng>"
-
-#~ msgid "show object type"
-#~ msgstr "hiển thị kiểu đối tượng"
-
-#~ msgid "exit with zero when there's no error"
-#~ msgstr "thoát với 0 khi không có lỗi"
-
-#~ msgid "show info and content of objects fed from the standard input"
-#~ msgstr ""
-#~ "hiển thị thông tin và nội dung của các đối tượng lấy từ đầu vào tiêu chuẩn"
-
-#~ msgid "show info about objects fed from the standard input"
-#~ msgstr "hiển thị các thông tin vỠđối tượng fed từ đầu vào tiêu chuẩn"
-
-#~ msgid "follow in-tree symlinks (used with --batch or --batch-check)"
-#~ msgstr ""
-#~ "theo liên kết má»m trong-cây (được dùng vá»›i --batch hay --batch-check)"
-
-#~ msgid "show all objects with --batch or --batch-check"
-#~ msgstr "hiển thị má»i đối tượng vá»›i --batch hay --batch-check"
-
-#~ msgid "do not order --batch-all-objects output"
-#~ msgstr "đừng sắp xếp đầu ra --batch-all-objects"
-
-#~ msgid "set up tracking mode (see git-pull(1))"
-#~ msgstr "cài đặt chế độ theo dõi (xem git-pull(1))"
-
-#~ msgid "Using both --reset-author and --author does not make sense"
-#~ msgstr "Sá»­ dụng cả hai tùy chá»n --reset-author và --author không hợp lý"
-
-#~ msgid "Options --squash and --fixup cannot be used together"
-#~ msgstr "Các tùy chá»n --squash và --fixup không thể sá»­ dụng cùng vá»›i nhau"
-
-#~ msgid "Only one of -c/-C/-F/--fixup can be used."
-#~ msgstr "Chỉ được dùng má»™t trong số tùy chá»n trong số -c/-C/-F/--fixup."
-
-#~ msgid "Option -m cannot be combined with -c/-C/-F."
-#~ msgstr "Tùy chá»n -m không thể được tổ hợp cùng vá»›i -c/-C/-F."
-
-#~ msgid ""
-#~ "Only one of --include/--only/--all/--interactive/--patch can be used."
-#~ msgstr ""
-#~ "Chỉ má»™t trong các tùy chá»n --include/--only/--all/--interactive/--patch "
-#~ "được sử dụng."
-
-#~ msgid "git count-objects [-v] [-H | --human-readable]"
-#~ msgstr "git count-objects [-v] [-H | --human-readable]"
-
-#, c-format
-#~ msgid "configuration fetch.output contains invalid value %s"
-#~ msgstr "phần cấu hình fetch.output có chứa giá-trị không hợp lệ %s"
-
-#~ msgid "--cached or --untracked cannot be used with --no-index"
-#~ msgstr "--cached hay --untracked không được sử dụng với --no-index"
-
-#~ msgid "--untracked cannot be used with --cached"
-#~ msgstr "--untracked không thể được sá»­ dụng vá»›i tùy chá»n --cached"
-
-#~ msgid "git hash-object --stdin-paths"
-#~ msgstr "git hash-object --stdin-paths"
-
-#~ msgid "git help [-g|--guides]"
-#~ msgstr "git help [-g|--guides]"
-
-#~ msgid "git help [-c|--config]"
-#~ msgstr "git help [-c|--config]"
-
-#~ msgid "git mktag"
-#~ msgstr "git mktag"
-
-#~ msgid "git mktree [-z] [--missing] [--batch]"
-#~ msgstr "git mktree [-z] [--missing] [--batch]"
-
-#~ msgid "read from stdin"
-#~ msgstr "Ä‘á»c từ đầu vào tiêu chuẩn"
-
-#~ msgid "git notes merge --commit [-v | -q]"
-#~ msgstr "git notes merge --commit [-v | -q]"
-
-#~ msgid "git notes merge --abort [-v | -q]"
-#~ msgstr "git notes merge --abort [-v | -q]"
-
-#~ msgid "git notes get-ref"
-#~ msgstr "git notes get-ref"
-
-#~ msgid "invalid value for --missing"
-#~ msgstr "giá trị cho --missing không hợp lệ"
-
-#~ msgid "git prune-packed [-n | --dry-run] [-q | --quiet]"
-#~ msgstr "git prune-packed [-n | --dry-run] [-q | --quiet]"
-
-#, c-format
-#~ msgid "Invalid value for %s: %s"
-#~ msgstr "Giá trị không hợp lệ %s: %s"
-
-#, c-format
-#~ msgid "Invalid value for pull.ff: %s"
-#~ msgstr "Giá trị không hợp lệ cho pull.ff: %s"
-
-#~ msgid "git rebase --continue | --abort | --skip | --edit-todo"
-#~ msgstr "git rebase --continue | --abort | --skip | --edit-todo"
-
-#, c-format
-#~ msgid "'%s' is not a valid timestamp"
-#~ msgstr "“%s†không phải là dấu thá»i gian hợp lệ"
-
-#~ msgid "git reflog [ show | expire | delete | exists ]"
-#~ msgstr "git reflog [ show | expire | delete | exists ]"
-
-#~ msgid "git remote [-v | --verbose]"
-#~ msgstr "git remote [-v | --verbose]"
-
-#~ msgid "git replace [-f] --convert-graft-file"
-#~ msgstr "git replace [-f] --convert-graft-file"
-
-#, c-format
-#~ msgid ""
-#~ "\n"
-#~ "It took %.2f seconds to enumerate unstaged changes after reset. You can\n"
-#~ "use '--quiet' to avoid this. Set the config setting reset.quiet to true\n"
-#~ "to make this the default.\n"
-#~ msgstr ""
-#~ "\n"
-#~ "Cần %.2f giây để kiểm đếm các thay đổi chưa đưa lên bệ phóng sau khi đặt "
-#~ "lại.\n"
-#~ "Bạn có thể sá»­ dụng “--quiet†để tránh việc này. Äặt reset.quiet thành "
-#~ "true trong\n"
-#~ "cài đặt config nếu bạn muốn thực hiện nó như là mặc định.\n"
-
-#~ msgid "git sparse-checkout list"
-#~ msgstr "git sparse-checkout list"
-
-#~ msgid "unable to upgrade repository format to enable worktreeConfig"
-#~ msgstr ""
-#~ "không thể nâng cấp định dạng kho lưu trữ để kích hoạt worktreeConfig"
-
-#~ msgid "git sparse-checkout init [--cone] [--[no-]sparse-index]"
-#~ msgstr "git sparse-checkout init [--cone] [--[no-]sparse-index]"
-
-#~ msgid "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]"
-#~ msgstr "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]"
-
-#~ msgid "git sparse-checkout disable"
-#~ msgstr "git sparse-checkout disable"
-
-#~ msgid ""
-#~ "the stash.useBuiltin support has been removed!\n"
-#~ "See its entry in 'git help config' for details."
-#~ msgstr ""
-#~ "việc hỗ trợ stash.useBuiltin đã bị xóa!\n"
-#~ "Xem mục tin của nó trong “git help config†để biết chi tiết."
-
-#~ msgid "git stripspace [-s | --strip-comments]"
-#~ msgstr "git stripspace [-s | --strip-comments]"
-
-#~ msgid "git stripspace [-c | --comment-lines]"
-#~ msgstr "git stripspace [-c | --comment-lines]"
-
-#~ msgid "submodule--helper print-default-remote takes no arguments"
-#~ msgstr "submodule--helper print-default-remote takes không nhận tham số"
-
-#~ msgid "git submodule--helper update-clone [--prefix=<path>] [<path>...]"
-#~ msgstr ""
-#~ "git submodule--helper update-clone [--prefix=</đưá»ng/dẫn>] [</đưá»ng/dẫn>…]"
-
-#~ msgid "suppress output for update by rebase or merge"
-#~ msgstr "chặn kết xuất cho cập nhật bởi cải tổ hoặc hòa trộn"
-
-#~ msgid "overrides update mode in case the repository is a fresh clone"
-#~ msgstr "ghi đè chế độ cập nhật trong trưá»ng hợp kho lưu trữ là bản sao má»›i"
-
-#~ msgid "depth for shallow fetch"
-#~ msgstr "chiá»u sâu lịch sá»­ muốn lấy vá»"
-
-#~ msgid "sha1"
-#~ msgstr "sha1"
-
-#~ msgid "SHA1 expected by superproject"
-#~ msgstr "SHA1 là cần thiết cho superproject"
-
-#~ msgid "subsha1"
-#~ msgstr "subsha1"
-
-#~ msgid "SHA1 of submodule's HEAD"
-#~ msgstr "SHA1 của HEAD của mô-đun-con"
-
-#~ msgid "git submodule--helper run-update-procedure [<options>] <path>"
-#~ msgstr ""
-#~ "git submodule--helper run-update-procedure [<các tùy chá»n>] </đưá»ng/dẫn>"
-
-#~ msgid "git submodule--helper config --check-writeable"
-#~ msgstr "git submodule--helper config --check-writeable"
-
-#~ msgid "git update-server-info [--force]"
-#~ msgstr "git update-server-info [--force]"
-
-#~ msgid "Initialize and modify the sparse-checkout"
-#~ msgstr "Khởi tạo và sửa đổi sparse-checkout"
-
-#, sh-format
-#~ msgid ""
-#~ "Unable to find current ${remote_name}/${branch} revision in submodule "
-#~ "path '$sm_path'"
-#~ msgstr ""
-#~ "Không thể tìm thấy điểm xét duyệt hiện hành ${remote_name}/${branch} "
-#~ "trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€"
-
-#, sh-format
-#~ msgid "Failed to recurse into submodule path '$displaypath'"
-#~ msgstr "Gặp lá»—i khi đệ quy vào trong đưá»ng dẫn mô-Ä‘un-con “$displaypathâ€"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index b70ae3866b..55d2aee627 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -46,6 +46,7 @@
# commit | æäº¤
# commit message | æäº¤è¯´æ˜Ž
# commit object | æäº¤å¯¹è±¡
+# commit-graph | æäº¤å›¾
# commit-ish (also committish) | æäº¤å·
# cone | é”¥å½¢ï¼ˆç¨€ç–æ£€å‡ºæ¨¡åž‹ï¼‰ï¼›é”¥ï¼ˆç¨€ç–检出)
# conflict | 冲çª
@@ -99,8 +100,10 @@
# plumbing | 管件(Git 底层核心命令的别称)
# porcelain | 瓷件(Git 上层å°è£…命令的别称)
# precious-objects repo | çå“仓库
+# preferred pack | 首选包(多包索引中引入的首选包概念)
# promisor | 承诺者
# prune | 清除
+# pseudorefs | 伪引用
# pull | 拉,拉å–
# push | 推,推é€
# reachable | å¯è¾¾
@@ -151,8 +154,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-08-18 10:21+0800\n"
-"PO-Revision-Date: 2023-08-18 19:29+0800\n"
+"POT-Creation-Date: 2024-10-05 03:31+0800\n"
+"PO-Revision-Date: 2024-10-05 03:32+0800\n"
"Last-Translator: Teng Long <dyroneteng@gmail.com>\n"
"Language-Team: GitHub <https://github.com/dyrone/git/>\n"
"Language: zh_CN\n"
@@ -249,12 +252,12 @@ msgstr[1] "增加了 %d 个路径\n"
msgid "ignoring unmerged: %s"
msgstr "忽略未åˆå…¥çš„:%s"
-#: add-interactive.c add-patch.c
+#: add-interactive.c
#, c-format
msgid "Only binary files changed.\n"
msgstr "åªæœ‰äºŒè¿›åˆ¶æ–‡ä»¶è¢«ä¿®æ”¹ã€‚\n"
-#: add-interactive.c add-patch.c
+#: add-interactive.c
#, c-format
msgid "No changes.\n"
msgstr "没有修改。\n"
@@ -724,12 +727,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
"è¦åˆ é™¤ '%c' 开始的行,使其æˆä¸º ' ' 开始的行(上下文)。\n"
"è¦åˆ é™¤ '%c' 开始的行,删除它们。\n"
-"以 %c 开始的行将被删除。\n"
+"以 %s 开始的行将被删除。\n"
#: add-patch.c
msgid ""
@@ -781,6 +784,7 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
"j - ç»´æŒè¯¥å—未决状æ€ï¼ŒæŸ¥çœ‹ä¸‹ä¸€ä¸ªæœªå†³å—\n"
@@ -791,9 +795,15 @@ msgstr ""
"/ - 查找和给定正则表达å¼åŒ¹é…çš„å—\n"
"s - 拆分当å‰å—为更å°çš„å—\n"
"e - 手动编辑当å‰å—\n"
+"p - 显示当å‰å—, 'P' 使用分页器\n"
"? - 显示帮助\n"
#: add-patch.c
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "é¢„æœŸåªæœ‰ä¸€ä¸ªå­—æ¯ï¼Œå¾—到 '%s'"
+
+#: add-patch.c
msgid "No previous hunk"
msgstr "没有å‰ä¸€ä¸ªå—"
@@ -856,9 +866,22 @@ msgid "Sorry, cannot edit this hunk"
msgstr "对ä¸èµ·ï¼Œä¸èƒ½ç¼–辑这个å—"
#: add-patch.c
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "未知命令 '%s'(使用 '?' 寻求帮助)"
+
+#: add-patch.c
msgid "'git apply' failed"
msgstr "'git apply' 失败"
+#: add-patch.c
+msgid "No changes."
+msgstr "没有修改。"
+
+#: add-patch.c
+msgid "Only binary files changed."
+msgstr "åªæœ‰äºŒè¿›åˆ¶æ–‡ä»¶è¢«ä¿®æ”¹ã€‚"
+
#: advice.c
#, c-format
msgid ""
@@ -870,8 +893,8 @@ msgstr ""
#: advice.c
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sæç¤ºï¼š%.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sæç¤ºï¼š%s%.*s%s\n"
#: advice.c
msgid "Cherry-picking is not possible because you have unmerged files."
@@ -1031,7 +1054,7 @@ msgid "unclosed quote"
msgstr "未关闭的引å·"
#: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c
-#: builtin/receive-pack.c builtin/tag.c
+#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c
msgid "too many arguments"
msgstr "å¤ªå¤šå‚æ•°"
@@ -1045,14 +1068,16 @@ msgstr "未能识别的空白字符选项 '%s'"
msgid "unrecognized whitespace ignore option '%s'"
msgstr "未能识别的空白字符忽略选项 '%s'"
-#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout.c
-#: builtin/clone.c builtin/commit.c builtin/describe.c builtin/diff-tree.c
-#: builtin/difftool.c builtin/fast-export.c builtin/fetch.c builtin/help.c
-#: builtin/index-pack.c builtin/init-db.c builtin/log.c builtin/ls-files.c
-#: builtin/merge-base.c builtin/merge.c builtin/pack-objects.c builtin/push.c
-#: builtin/rebase.c builtin/repack.c builtin/reset.c builtin/rev-list.c
-#: builtin/show-branch.c builtin/stash.c builtin/submodule--helper.c
-#: builtin/tag.c builtin/worktree.c parse-options.c range-diff.c revision.c
+#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c
+#: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c
+#: builtin/describe.c builtin/diff-tree.c builtin/difftool.c
+#: builtin/fast-export.c builtin/fetch.c builtin/help.c builtin/index-pack.c
+#: builtin/init-db.c builtin/log.c builtin/ls-files.c builtin/merge-base.c
+#: builtin/merge-tree.c builtin/merge.c builtin/pack-objects.c builtin/rebase.c
+#: builtin/repack.c builtin/replay.c builtin/reset.c builtin/rev-list.c
+#: builtin/rev-parse.c builtin/show-branch.c builtin/stash.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/worktree.c parse-options.c
+#: range-diff.c revision.c
#, c-format
msgid "options '%s' and '%s' cannot be used together"
msgstr "选项 '%s' å’Œ '%s' ä¸èƒ½åŒæ—¶ä½¿ç”¨"
@@ -1467,11 +1492,6 @@ msgstr[1] "应用 %%s 个补ä¸ï¼Œå…¶ä¸­ %d 个被拒ç»..."
#: apply.c
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "截短 .rej 文件å为 %.*s.rej"
-
-#: apply.c
-#, c-format
msgid "cannot open %s"
msgstr "ä¸èƒ½æ‰“å¼€ %s"
@@ -1529,7 +1549,7 @@ msgid_plural "%d lines applied after fixing whitespace errors."
msgstr[0] "ä¿®å¤ç©ºç™½é”™è¯¯åŽï¼Œåº”用了 %d 行。"
msgstr[1] "ä¿®å¤ç©ºç™½é”™è¯¯åŽï¼Œåº”用了 %d 行。"
-#: apply.c builtin/add.c builtin/mv.c builtin/rm.c
+#: apply.c builtin/mv.c builtin/rm.c
msgid "Unable to write new index file"
msgstr "无法写入新索引文件"
@@ -1593,6 +1613,18 @@ msgstr "还应用此补ä¸ï¼ˆä¸Ž --stat/--summary/--check é€‰é¡¹åŒæ—¶ä½¿ç”¨ï¼‰"
msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr "å°è¯•三路åˆå¹¶ï¼Œå¦‚果失败则回è½è‡³æ­£å¸¸è¡¥ä¸æ¨¡å¼"
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "如果冲çªï¼Œä½¿ç”¨æˆ‘们的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "如果冲çªï¼Œä½¿ç”¨ä»–们的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "如果冲çªï¼Œä½¿ç”¨è”åˆç‰ˆæœ¬"
+
#: apply.c
msgid "build a temporary index based on embedded index information"
msgstr "创建一个临时索引基于嵌入的索引信æ¯"
@@ -1654,6 +1686,10 @@ msgstr "为所有文件å剿·»åŠ  <根目录>"
msgid "don't return error for empty patches"
msgstr "对空的补ä¸ä¸è¿”回错误"
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--oursã€--theirs å’Œ --union éœ€è¦ --3way"
+
#: archive-tar.c archive-zip.c
#, c-format
msgid "cannot stream blob %s"
@@ -1742,6 +1778,10 @@ msgstr "䏿˜¯ä¸€ä¸ªæœ‰æ•ˆçš„对象å:%s"
msgid "not a tree object: %s"
msgstr "䏿˜¯ä¸€ä¸ªæ ‘对象:%s"
+#: archive.c builtin/clone.c
+msgid "unable to checkout working tree"
+msgstr "ä¸èƒ½æ£€å‡ºå·¥ä½œåŒº"
+
#: archive.c
#, c-format
msgid "File not found: %s"
@@ -1858,6 +1898,11 @@ msgstr "选项 '%s' éœ€è¦ '%s'"
msgid "Unexpected option --output"
msgstr "æœªçŸ¥å‚æ•° --output"
+#: archive.c t/unit-tests/unit-test.c
+#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "é¢å¤–çš„å‘½ä»¤è¡Œå‚æ•°ï¼š'%s'"
+
#: archive.c
#, c-format
msgid "Unknown archive format '%s'"
@@ -1911,9 +1956,24 @@ msgid "ignoring overly large gitattributes blob '%s'"
msgstr "忽略过大的 gitattributes æ•°æ®å¯¹è±¡ '%s'"
#: attr.c
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "无法在没有存储库的情况下使用 --attr-source 或 GIT_ATTR_SOURCE"
+
+#: attr.c
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "错误的 --attr-source 或 GIT_ATTR_SOURCE"
+#: attr.c read-cache.c
+#, c-format
+msgid "unable to stat '%s'"
+msgstr "无法对 %s 执行 stat"
+
+#: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
+#, c-format
+msgid "unable to read %s"
+msgstr "ä¸èƒ½è¯» %s"
+
#: bisect.c
#, c-format
msgid "Badly quoted content in file '%s': %s"
@@ -1993,6 +2053,11 @@ msgstr "需è¦ä¸€ä¸ª %s 版本"
msgid "could not create file '%s'"
msgstr "ä¸èƒ½åˆ›å»ºæ–‡ä»¶ '%s'"
+#: bisect.c builtin/notes.c
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "ä¸èƒ½ä¸ºå¯¹è±¡ '%s' 开始 'show'"
+
#: bisect.c builtin/merge.c
#, c-format
msgid "could not read file '%s'"
@@ -2041,9 +2106,9 @@ msgstr "--contents å’Œ --reverse ä¸èƒ½æ··ç”¨ã€‚"
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 remote.c
-#: sequencer.c submodule.c
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
+#: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
+#: remote.c sequencer.c submodule.c
msgid "revision walk setup failed"
msgstr "版本é历åˆå§‹åŒ–失败"
@@ -2160,6 +2225,10 @@ msgstr ""
msgid "'%s' is not a valid branch name"
msgstr "'%s' 䏿˜¯ä¸€ä¸ªæœ‰æ•ˆçš„分支åç§°"
+#: branch.c builtin/branch.c
+msgid "See `man git check-ref-format`"
+msgstr "查阅 `man git check-ref-format`"
+
#: branch.c
#, c-format
msgid "a branch named '%s' already exists"
@@ -2234,8 +2303,8 @@ msgstr "å­æ¨¡ç»„ '%s':ä¸èƒ½åˆ›å»ºåˆ†æ”¯ '%s'"
#: branch.c
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "'%s' å·²ç»æ£€å‡ºåˆ° '%s'"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "'%s' å·²ç»è¢«å·¥ä½œåŒº '%s' 使用"
#: builtin/add.c
msgid "git add [<options>] [--] <pathspec>..."
@@ -2251,37 +2320,25 @@ 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"
+msgid "could not read the index"
msgstr "ä¸èƒ½è¯»å–索引"
#: builtin/add.c
-msgid "Could not write patch"
-msgstr "ä¸èƒ½ç”Ÿæˆè¡¥ä¸"
-
-#: builtin/add.c
msgid "editing patch failed"
msgstr "编辑补ä¸å¤±è´¥"
-#: builtin/add.c
+#: builtin/add.c read-cache.c
#, c-format
-msgid "Could not stat '%s'"
+msgid "could not stat '%s'"
msgstr "ä¸èƒ½å¯¹ '%s' 调用 stat"
#: builtin/add.c
-msgid "Empty patch. Aborted."
-msgstr "空补ä¸ã€‚异常终止。"
+msgid "empty patch. aborted"
+msgstr "空补ä¸ã€‚异常终止"
#: builtin/add.c
#, c-format
-msgid "Could not apply '%s'"
+msgid "could not apply '%s'"
msgstr "ä¸èƒ½åº”用 '%s'"
#: builtin/add.c
@@ -2296,7 +2353,7 @@ msgstr "演习"
#: builtin/add.c builtin/check-ignore.c builtin/commit.c
#: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
-#: builtin/read-tree.c
+#: builtin/read-tree.c builtin/refs.c
msgid "be verbose"
msgstr "冗长输出"
@@ -2394,14 +2451,8 @@ msgid "adding embedded git repository: %s"
msgstr "æ­£åœ¨æ·»åŠ åµŒå…¥å¼ git 仓库:%s"
#: builtin/add.c
-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 "Use -f if you really want to add them."
+msgstr "如果您确实想添加它们,请使用 -f 选项。"
#: builtin/add.c
msgid "adding files failed"
@@ -2424,14 +2475,8 @@ msgid "Nothing specified, nothing added.\n"
msgstr "没有指定文件,也没有文件被添加。\n"
#: builtin/add.c
-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 "Maybe you wanted to say 'git add .'?"
+msgstr "ä¹Ÿè®¸æ‚¨æƒ³è¦æ‰§è¡Œ 'git add .'?"
#: builtin/add.c builtin/check-ignore.c builtin/checkout.c builtin/clean.c
#: builtin/commit.c builtin/diff-tree.c builtin/grep.c builtin/mv.c
@@ -2440,14 +2485,19 @@ msgstr ""
msgid "index file corrupt"
msgstr "索引文件æŸå"
+#: builtin/add.c builtin/am.c builtin/checkout.c builtin/clone.c
+#: builtin/commit.c builtin/stash.c merge.c rerere.c
+msgid "unable to write new index file"
+msgstr "无法写新的索引文件"
+
#: builtin/am.c builtin/mailinfo.c mailinfo.c
#, c-format
msgid "bad action '%s' for '%s'"
msgstr "'%2$s' 的错误动作 '%1$s'"
#: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c
-#: builtin/pull.c diff-merges.c gpg-interface.c ls-refs.c parallel-checkout.c
-#: sequencer.c setup.c
+#: builtin/pull.c builtin/revert.c config.c diff-merges.c gpg-interface.c
+#: ls-refs.c parallel-checkout.c sequencer.c setup.c
#, c-format
msgid "invalid value for '%s': '%s'"
msgstr "'%s' 的值无效:'%s'"
@@ -2531,18 +2581,19 @@ msgstr "无法拆分补ä¸ã€‚"
#: builtin/am.c
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "当您解决这一问题,执行 \"%s --continue\"。"
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "当您解决这一问题之åŽï¼Œæ‰§è¡Œ \"%s --continue\"。\n"
#: builtin/am.c
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "如果您想è¦è·³è¿‡è¿™ä¸€è¡¥ä¸ï¼Œåˆ™æ‰§è¡Œ \"%s --skip\"。"
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr "如果您想è¦è·³è¿‡è¿™ä¸€è¡¥ä¸ï¼Œåˆ™æ‰§è¡Œ \"%s --skip\"。\n"
#: builtin/am.c
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
-msgstr "è‹¥è¦æŠŠç©ºè¡¥ä¸è®°å½•为空æäº¤ï¼Œæ‰§è¡Œ \"%s --allow-empty\"。"
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
+msgstr "è‹¥è¦æŠŠç©ºè¡¥ä¸è®°å½•为空æäº¤ï¼Œæ‰§è¡Œ \"%s --allow-empty\"。\n"
#: builtin/am.c
#, c-format
@@ -2600,8 +2651,7 @@ msgstr "git write-tree 无法写入树对象"
msgid "applying to an empty history"
msgstr "正应用到一个空历å²ä¸Š"
-#: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
-#: t/helper/test-fast-rebase.c
+#: builtin/am.c builtin/commit.c builtin/merge.c builtin/replay.c sequencer.c
msgid "failed to write commit object"
msgstr "无法写æäº¤å¯¹è±¡"
@@ -2689,11 +2739,6 @@ msgstr ""
"您应该对已ç»å†²çªè§£å†³çš„æ¯ä¸€ä¸ªæ–‡ä»¶æ‰§è¡Œ 'git add' æ¥æ ‡è®°å·²ç»å®Œæˆã€‚ \n"
"您å¯ä»¥å¯¹ \"由他们删除\" 的文件执行 `git rm` 命令。"
-#: builtin/am.c builtin/checkout.c builtin/clone.c builtin/stash.c merge.c
-#: rerere.c
-msgid "unable to write new index file"
-msgstr "无法写新的索引文件"
-
#: builtin/am.c builtin/reset.c
#, c-format
msgid "Could not parse object '%s'."
@@ -2709,17 +2754,12 @@ msgid ""
"Not rewinding to ORIG_HEAD"
msgstr "您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_HEAD"
-#: builtin/am.c builtin/bisect.c worktree.c
+#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c
#, c-format
msgid "failed to read '%s'"
msgstr "æ— æ³•è¯»å– '%s'"
#: builtin/am.c
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "选项 '%s=%s' å’Œ '%s=%s' ä¸èƒ½åŒæ—¶ä½¿ç”¨"
-
-#: builtin/am.c
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
msgstr "git am [<选项>] [(<mbox> | <Maildir>)...]"
@@ -2791,8 +2831,9 @@ msgid "n"
msgstr "n"
#: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
-#: builtin/diagnose.c builtin/for-each-ref.c builtin/ls-files.c
-#: builtin/ls-tree.c builtin/replace.c builtin/tag.c builtin/verify-tag.c
+#: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
+#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
msgid "format"
msgstr "æ ¼å¼"
@@ -2829,6 +2870,10 @@ msgid "show the patch being applied"
msgstr "显示正在应用的补ä¸"
#: builtin/am.c
+msgid "try to apply current patch again"
+msgstr "å°è¯•冿¬¡åº”用当å‰è¡¥ä¸"
+
+#: builtin/am.c
msgid "record the empty patch as an empty commit"
msgstr "把空补ä¸è®°å½•为空æäº¤"
@@ -2900,10 +2945,6 @@ msgid "could not redirect output"
msgstr "ä¸èƒ½é‡å®šå‘输出"
#: builtin/archive.c
-msgid "git archive: Remote with no URL"
-msgstr "git archive:未æä¾›è¿œç¨‹ URL"
-
-#: builtin/archive.c
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archive:期望是 ACK/NAK,å´å¾—到 flush 包"
@@ -2922,10 +2963,10 @@ msgstr "git archive:应有一个 flush 包"
#: builtin/bisect.c
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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-"
+"git bisect start [--term-{new|bad}=<术语> --term-{old|good}=<术语>] [--no-"
"checkout] [--first-parent] [<å> [<好>...]] [--] [<路径规格>...]"
#: builtin/bisect.c
@@ -2945,8 +2986,8 @@ msgid "git bisect replay <logfile>"
msgstr "git bisect replay <日志文件>"
#: builtin/bisect.c
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <命令>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <命令> [<傿•°>...]"
#: builtin/bisect.c
#, c-format
@@ -3087,10 +3128,6 @@ msgstr ""
"支æŒçš„选项有:--term-good|--term-old å’Œ --term-bad|--term-new。"
#: builtin/bisect.c
-msgid "revision walk setup failed\n"
-msgstr "版本é历设置失败\n"
-
-#: builtin/bisect.c
#, c-format
msgid "could not open '%s' for appending"
msgstr "无法打开 '%s' 进行追加"
@@ -3461,37 +3498,38 @@ 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."
+" '%s', but not yet merged to HEAD"
msgstr ""
"å°†è¦åˆ é™¤çš„分支 '%s' å·²ç»è¢«åˆå¹¶åˆ°\n"
-" '%s',但未åˆå¹¶åˆ° HEAD。"
+" '%s',但未åˆå¹¶åˆ° HEAD"
# è¯‘è€…ï¼šä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让字符串å˜é•¿
#: builtin/branch.c
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
msgstr ""
-"并未删除分支 '%s', 虽然它已ç»åˆå¹¶åˆ° HEAD,\n"
-" 然而å´å°šæœªè¢«åˆå¹¶åˆ°åˆ†æ”¯ '%s' 。"
+"并未删除分支 '%s',虽然它已ç»åˆå¹¶åˆ° HEAD,\n"
+" 然而å´å°šæœªè¢«åˆå¹¶åˆ°åˆ†æ”¯ '%s'"
#: builtin/branch.c
#, c-format
-msgid "Couldn't look up commit object for '%s'"
+msgid "couldn't look up commit object for '%s'"
msgstr "无法查询 '%s' 指å‘çš„æäº¤å¯¹è±¡"
#: builtin/branch.c
#, 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 "the branch '%s' is not fully merged"
+msgstr "分支 '%s' 没有完全åˆå¹¶"
+
+#: builtin/branch.c
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "如果您确认è¦åˆ é™¤å®ƒï¼Œæ‰§è¡Œ 'git branch -D %s'"
#: builtin/branch.c
-msgid "Update of config-file failed"
+msgid "update of config-file failed"
msgstr "æ›´æ–°é…置文件失败"
#: builtin/branch.c
@@ -3500,13 +3538,13 @@ msgstr "ä¸èƒ½å°† -a å’Œ -d åŒæ—¶ä½¿ç”¨"
#: builtin/branch.c
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "无法删除检出于 '%2$s' 的分支 '%1$s'。"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr "无法强制更新被工作区 '%2$s' 所使用的分支 '%1$s'"
#: builtin/branch.c
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "未能找到远程跟踪分支 '%s'。"
+msgid "remote-tracking branch '%s' not found"
+msgstr "未能找到远程跟踪分支 '%s'"
#: builtin/branch.c
#, c-format
@@ -3519,8 +3557,8 @@ msgstr ""
#: builtin/branch.c
#, c-format
-msgid "branch '%s' not found."
-msgstr "分支 '%s' 未å‘现。"
+msgid "branch '%s' not found"
+msgstr "分支 '%s' 未å‘现"
#: builtin/branch.c
#, c-format
@@ -3547,12 +3585,12 @@ msgstr "HEAD (%s) æŒ‡å‘ refs/heads/ 之外"
#: builtin/branch.c
#, c-format
-msgid "Branch %s is being rebased at %s"
+msgid "branch %s is being rebased at %s"
msgstr "分支 %s 正被å˜åŸºåˆ° %s"
#: builtin/branch.c
#, c-format
-msgid "Branch %s is being bisected at %s"
+msgid "branch %s is being bisected at %s"
msgstr "分支 %s 正被二分查找于 %s"
#: builtin/branch.c
@@ -3562,48 +3600,48 @@ msgstr "工作区 %s çš„ HEAD æŒ‡å‘æ²¡æœ‰è¢«æ›´æ–°"
#: builtin/branch.c
#, c-format
-msgid "Invalid branch name: '%s'"
+msgid "invalid branch name: '%s'"
msgstr "无效的分支å:'%s'"
#: builtin/branch.c
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "分支 '%s' å°šæ— æäº¤ã€‚"
+msgid "no commit on branch '%s' yet"
+msgstr "分支 '%s' å°šæ— æäº¤"
#: builtin/branch.c
#, c-format
-msgid "No branch named '%s'."
-msgstr "没有分支 '%s'。"
+msgid "no branch named '%s'"
+msgstr "没有分支 '%s'"
#: builtin/branch.c
-msgid "Branch rename failed"
+msgid "branch rename failed"
msgstr "分支é‡å‘½å失败"
#: builtin/branch.c
-msgid "Branch copy failed"
+msgid "branch copy failed"
msgstr "分支拷è´å¤±è´¥"
#: builtin/branch.c
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
+msgid "created a copy of a misnamed branch '%s'"
msgstr "已为错误命å的分支 '%s' 创建了一个副本"
#: builtin/branch.c
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
+msgid "renamed a misnamed branch '%s' away"
msgstr "已将错误命å的分支 '%s' é‡å‘½å"
#: builtin/branch.c
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "分支é‡å‘½å为 %s,但 HEAD 没有更新ï¼"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "分支é‡å‘½å为 %s,但 HEAD 没有更新"
#: builtin/branch.c
-msgid "Branch is renamed, but update of config-file failed"
+msgid "branch is renamed, but update of config-file failed"
msgstr "分支被é‡å‘½å,但更新é…置文件失败"
#: builtin/branch.c
-msgid "Branch is copied, but update of config-file failed"
+msgid "branch is copied, but update of config-file failed"
msgstr "分支已拷è´ï¼Œä½†æ›´æ–°é…置文件失败"
#: builtin/branch.c
@@ -3611,11 +3649,11 @@ msgstr "分支已拷è´ï¼Œä½†æ›´æ–°é…置文件失败"
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"请编辑分支的æè¿°\n"
" %s\n"
-"以 '%c' 开头的行将被过滤。\n"
+"以 '%s' 开头的行将被过滤。\n"
#: builtin/branch.c
msgid "Generic options"
@@ -3754,9 +3792,9 @@ msgstr "åœ¨å­æ¨¡ç»„中递归"
msgid "format to use for the output"
msgstr "输出格å¼"
-#: builtin/branch.c builtin/submodule--helper.c submodule.c
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "无法将 HEAD è§£æžä¸ºæœ‰æ•ˆå¼•用。"
+#: builtin/branch.c
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "无法将 HEAD è§£æžä¸ºæœ‰æ•ˆå¼•用"
#: builtin/branch.c builtin/clone.c
msgid "HEAD not found below refs/heads!"
@@ -3778,7 +3816,7 @@ msgid "branch name required"
msgstr "å¿…é¡»æä¾›åˆ†æ”¯å"
#: builtin/branch.c
-msgid "Cannot give description to detached HEAD"
+msgid "cannot give description to detached HEAD"
msgstr "ä¸èƒ½å‘分离头指针æä¾›æè¿°"
#: builtin/branch.c
@@ -3786,12 +3824,12 @@ msgid "cannot edit description of more than one branch"
msgstr "ä¸èƒ½ä¸ºä¸€ä¸ªä»¥ä¸Šçš„分支编辑æè¿°"
#: builtin/branch.c
-msgid "cannot copy the current branch while not on any."
-msgstr "ä¸å¤„于任何分支上,无法拷è´å½“å‰åˆ†æ”¯ã€‚"
+msgid "cannot copy the current branch while not on any"
+msgstr "ä¸å¤„于任何分支上,无法拷è´å½“å‰åˆ†æ”¯"
#: builtin/branch.c
-msgid "cannot rename the current branch while not on any."
-msgstr "ä¸å¤„于任何分支上,无法é‡å‘½å当å‰åˆ†æ”¯ã€‚"
+msgid "cannot rename the current branch while not on any"
+msgstr "ä¸å¤„于任何分支上,无法é‡å‘½å当å‰åˆ†æ”¯"
#: builtin/branch.c
msgid "too many branches for a copy operation"
@@ -3808,8 +3846,8 @@ 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 没有指å‘任何分支。"
+"could not set upstream of HEAD to %s when it does not point to any branch"
+msgstr "无法设置 HEAD 的上游为 %s,因为 HEAD 没有指å‘任何分支"
#: builtin/branch.c
#, c-format
@@ -3826,17 +3864,17 @@ msgid "too many arguments to unset upstream"
msgstr "ä¸ºå–æ¶ˆä¸Šæ¸¸è®¾ç½®æ“作æä¾›äº†å¤ªå¤šçš„傿•°"
#: builtin/branch.c
-msgid "could not unset upstream of HEAD when it does not point to any branch."
+msgid "could not unset upstream of HEAD when it does not point to any branch"
msgstr "æ— æ³•å–æ¶ˆ HEAD 的上游设置因为它没有指å‘一个分支"
#: builtin/branch.c
#, c-format
-msgid "Branch '%s' has no upstream information"
+msgid "branch '%s' has no upstream information"
msgstr "分支 '%s' 没有上游信æ¯"
#: builtin/branch.c
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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"
@@ -3845,9 +3883,8 @@ msgstr ""
#: 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-to' instead"
+msgstr "ä¸å†æ”¯æŒé€‰é¡¹ '--set-upstream'。请使用 '--track' 或 '--set-upstream-to'"
#: builtin/bugreport.c
msgid "git version:\n"
@@ -3872,10 +3909,12 @@ msgstr "䏿˜¯åœ¨ git 仓库中执行 - æ²¡æœ‰å¯æ˜¾ç¤ºçš„é’©å­\n"
#: builtin/bugreport.c
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [-o|--output-directory <文件>] [(-s|--suffix) <æ ¼å¼>]\n"
+"git bugreport [-o | --output-directory <文件>]\n"
+" [(-s | --suffix) <æ ¼å¼> | --no-suffix]\n"
" [--diagnose[=<模å¼>]"
#: builtin/bugreport.c
@@ -3930,6 +3969,11 @@ msgstr "指定错误报告文件的目标ä½ç½®"
msgid "specify a strftime format suffix for the filename(s)"
msgstr "指定文件的 strftime æ ¼å¼åŽç¼€"
+#: builtin/bugreport.c
+#, c-format
+msgid "unknown argument `%s'"
+msgstr "æœªçŸ¥å‚æ•° `%s'"
+
#: builtin/bugreport.c builtin/diagnose.c
#, c-format
msgid "could not create leading directories for '%s'"
@@ -4010,6 +4054,10 @@ msgstr "需è¦ä¸€ä¸ªä»“库æ¥åˆ›å»ºå½’档包。"
msgid "do not show bundle details"
msgstr "䏿˜¾ç¤ºå½’档包的细节"
+#: builtin/bundle.c bundle.c
+msgid "need a repository to verify a bundle"
+msgstr "需è¦ä¸€ä¸ªä»“åº“æ¥æ ¡éªŒä¸€ä¸ªå½’档包"
+
#: builtin/bundle.c
#, c-format
msgid "%s is okay\n"
@@ -4069,6 +4117,14 @@ msgstr "git cat-file (-t | -s) [--allow-unknown-type] <对象>"
#: builtin/cat-file.c
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<版本>:<路径|树对象> | --path=<路径|树对象> <版本>]"
+
+#: builtin/cat-file.c
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -4080,14 +4136,6 @@ msgstr ""
" [--textconv | --filters] [-Z]"
#: builtin/cat-file.c
-msgid ""
-"git cat-file (--textconv | --filters)\n"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
-msgstr ""
-"git cat-file (--textconv | --filters)\n"
-" [<版本>:<路径|树对象> | --path=<路径|树对象> <版本>]"
-
-#: builtin/cat-file.c
msgid "Check object existence or emit object contents"
msgstr "检查对象存在或输出对象内容"
@@ -4305,9 +4353,16 @@ msgid "also read contacts from stdin"
msgstr "还从标准输入读å–è”系地å€"
#: builtin/check-mailmap.c
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "ä¸èƒ½è§£æžè”系地å€ï¼š%s"
+msgid "read additional mailmap entries from file"
+msgstr "从文件中读å–附加邮件映射æ¡ç›®"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "æ•°æ®å¯¹è±¡"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "从数æ®å¯¹è±¡ä¸­è¯»å–附加邮件映射æ¡ç›®"
#: builtin/check-mailmap.c
msgid "no contacts specified"
@@ -4464,9 +4519,20 @@ msgstr "'%s' 或 '%s' ä¸èƒ½å’Œ %s 一起使用"
#: builtin/checkout.c
#, c-format
+msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "'%s'ã€'%s' 或 '%s' ä¸èƒ½åœ¨æ£€å‡ºä¸€ä¸ªæ ‘时使用"
+
+#: builtin/checkout.c
+#, c-format
msgid "path '%s' is unmerged"
msgstr "路径 '%s' 未åˆå¹¶"
+#: builtin/checkout.c builtin/grep.c builtin/merge-tree.c builtin/reset.c
+#: merge-ort.c reset.c sequencer.c tree-walk.c
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "æ— æ³•è¯»å–æ ‘(%s)"
+
#: builtin/checkout.c
msgid "you need to resolve your current index first"
msgstr "您需è¦å…ˆè§£å†³å½“å‰ç´¢å¼•的冲çª"
@@ -4489,7 +4555,7 @@ msgstr "ä¸èƒ½å¯¹ '%s' 执行 reflog æ“作:%s\n"
msgid "HEAD is now at"
msgstr "HEAD ç›®å‰ä½äºŽ"
-#: builtin/checkout.c builtin/clone.c t/helper/test-fast-rebase.c
+#: builtin/checkout.c builtin/clone.c
msgid "unable to update HEAD"
msgstr "ä¸èƒ½æ›´æ–° HEAD"
@@ -4716,6 +4782,11 @@ msgstr "'%s' ä¸èƒ½å’Œåˆ‡æ¢åˆ†æ”¯åŒæ—¶ä½¿ç”¨"
#: builtin/checkout.c
#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' 需è¦è·¯å¾„进行检出"
+
+#: builtin/checkout.c
+#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "'%s' ä¸èƒ½å’Œ '%s' åŒæ—¶ä½¿ç”¨"
@@ -4734,6 +4805,11 @@ msgid "missing branch or commit argument"
msgstr "缺少分支或æäº¤å‚æ•°"
#: builtin/checkout.c
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "未知的冲çªé£Žæ ¼ '%s'"
+
+#: builtin/checkout.c
msgid "perform a 3-way merge with the new branch"
msgstr "和新的分支执行三方åˆå¹¶"
@@ -4758,8 +4834,8 @@ msgid "new-branch"
msgstr "新分支"
#: builtin/checkout.c
-msgid "new unparented branch"
-msgstr "新的没有父æäº¤çš„分支"
+msgid "new unborn branch"
+msgstr "新的未诞生的分支"
#: builtin/checkout.c builtin/merge.c
msgid "update ignored files (default)"
@@ -4825,7 +4901,7 @@ msgstr ""
msgid "you must specify path(s) to restore"
msgstr "æ‚¨å¿…é¡»æŒ‡å®šè¦æ¢å¤çš„路径"
-#: builtin/checkout.c builtin/clone.c builtin/remote.c
+#: builtin/checkout.c builtin/clone.c builtin/remote.c builtin/replay.c
#: builtin/submodule--helper.c builtin/worktree.c
msgid "branch"
msgstr "分支"
@@ -5034,9 +5110,9 @@ msgstr "äº¤äº’å¼æ¸…除"
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/pack-refs.c builtin/show-ref.c
-#: ref-filter.h
+#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c
+#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c
+#: builtin/show-ref.c ref-filter.h
msgid "pattern"
msgstr "模å¼"
@@ -5053,22 +5129,8 @@ msgid "remove only ignored files"
msgstr "åªåˆ é™¤å¿½ç•¥çš„æ–‡ä»¶"
#: builtin/clean.c
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce 设置为 true 且未æä¾› -iã€-n 或 -f é€‰é¡¹ï¼Œæ‹’ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
-
-#: builtin/clean.c
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce 默认为 true 且未æä¾› -iã€-n 或 -f é€‰é¡¹ï¼Œæ‹’ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
-
-#: builtin/clean.c
-msgid "-x and -X cannot be used together"
-msgstr "-x å’Œ -X ä¸èƒ½åŒæ—¶ä½¿ç”¨"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
+msgstr "clean.requireForce 设置为 true 且未æä¾› -f é€‰é¡¹ï¼šæ‹’ç»æ‰§è¡Œæ¸…ç†åŠ¨ä½œ"
#: builtin/clone.c
msgid "git clone [<options>] [--] <repo> [<dir>]"
@@ -5087,8 +5149,8 @@ msgid "create a bare repository"
msgstr "创建一个纯仓库"
#: builtin/clone.c
-msgid "create a mirror repository (implies bare)"
-msgstr "创建一个镜åƒä»“库(也是纯仓库)"
+msgid "create a mirror repository (implies --bare)"
+msgstr "创建一个镜åƒä»“库(éšå« --bare)"
#: builtin/clone.c
msgid "to clone from a local repository"
@@ -5148,7 +5210,7 @@ msgstr "检出 <分支> è€Œä¸æ˜¯è¿œç¨‹ HEAD"
msgid "path to git-upload-pack on the remote"
msgstr "远程 git-upload-pack 路径"
-#: builtin/clone.c builtin/fetch.c builtin/grep.c builtin/pull.c
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
msgid "depth"
msgstr "深度"
@@ -5161,6 +5223,7 @@ msgid "create a shallow clone since a specific time"
msgstr "从一个特定时间创建一个浅克隆"
#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c
+#: builtin/replay.c
msgid "revision"
msgstr "版本"
@@ -5188,6 +5251,10 @@ msgstr "git目录"
msgid "separate git dir from working tree"
msgstr "git目录和工作区分离"
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
+msgid "specify the reference format to use"
+msgstr "指定è¦ä½¿ç”¨çš„引用格å¼"
+
#: builtin/clone.c
msgid "key=value"
msgstr "key=value"
@@ -5263,6 +5330,16 @@ msgstr "无法删除 '%s'"
#: builtin/clone.c
#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "无法检查 '%s' 处的硬链接"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "硬链接与 '%s' 处的æºä¸åŒ"
+
+#: builtin/clone.c
+#, c-format
msgid "failed to create link '%s'"
msgstr "无法创建链接 '%s'"
@@ -5271,7 +5348,7 @@ msgstr "无法创建链接 '%s'"
msgid "failed to copy file to '%s'"
msgstr "æ— æ³•æ‹·è´æ–‡ä»¶è‡³ '%s'"
-#: builtin/clone.c
+#: builtin/clone.c refs/files-backend.c
#, c-format
msgid "failed to iterate over '%s'"
msgstr "无法在 '%s' 上迭代"
@@ -5314,10 +5391,6 @@ msgid "remote HEAD refers to nonexistent ref, unable to checkout"
msgstr "远程 HEAD 指å‘一个ä¸å­˜åœ¨çš„引用,无法检出"
#: builtin/clone.c
-msgid "unable to checkout working tree"
-msgstr "ä¸èƒ½æ£€å‡ºå·¥ä½œåŒº"
-
-#: builtin/clone.c
msgid "unable to write parameters to config file"
msgstr "æ— æ³•å°†å‚æ•°å†™å…¥é…置文件"
@@ -5337,11 +5410,11 @@ msgstr "å¤ªå¤šå‚æ•°ã€‚"
msgid "You must specify a repository to clone."
msgstr "您必须指定一个仓库æ¥å…‹éš†ã€‚"
-#: builtin/clone.c
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr "--bundle-uri 与 --depthã€--shallow-since å’Œ --shallow-exclude ä¸å…¼å®¹"
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "æœªçŸ¥çš„å¼•ç”¨å­˜å‚¨æ ¼å¼ '%s'"
#: builtin/clone.c
#, c-format
@@ -5486,6 +5559,11 @@ msgid "padding space between columns"
msgstr "两列之间的填充空间"
#: builtin/column.c
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s 必须为éžè´Ÿæ•´æ•°"
+
+#: builtin/column.c
msgid "--command must be the first argument"
msgstr "--command å¿…é¡»æ˜¯ç¬¬ä¸€ä¸ªå‚æ•°"
@@ -5502,7 +5580,7 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"git commit-graph write [--object-dir <目录>] [--append]\n"
" [--split[=<ç­–ç•¥>]] [--reachable | --stdin-packs | --"
@@ -5521,12 +5599,17 @@ msgstr "ä¿å­˜å›¾å½¢çš„对象目录"
#: builtin/commit-graph.c
msgid "if the commit-graph is split, only verify the tip file"
-msgstr "如果æäº¤å›¾å½¢è¢«æ‹†åˆ†ï¼ŒåªéªŒè¯å¤´ä¸€ä¸ªæ–‡ä»¶"
+msgstr "如果æäº¤å›¾è¢«æ‹†åˆ†ï¼ŒåªéªŒè¯å¤´ä¸€ä¸ªæ–‡ä»¶"
#: builtin/commit-graph.c
#, c-format
msgid "Could not open commit-graph '%s'"
-msgstr "无法打开æäº¤å›¾å½¢ '%s'"
+msgstr "无法打开æäº¤å›¾ '%s'"
+
+#: builtin/commit-graph.c
+#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "无法打开æäº¤å›¾é“¾ '%s'"
#: builtin/commit-graph.c
#, c-format
@@ -5570,15 +5653,15 @@ msgstr "å¯ç”¨å˜æ›´è·¯å¾„的计算"
#: builtin/commit-graph.c
msgid "allow writing an incremental commit-graph file"
-msgstr "å…è®¸å†™ä¸€ä¸ªå¢žé‡æäº¤å›¾å½¢æ–‡ä»¶"
+msgstr "å…è®¸å†™ä¸€ä¸ªå¢žé‡æäº¤å›¾æ–‡ä»¶"
#: builtin/commit-graph.c
msgid "maximum number of commits in a non-base split commit-graph"
-msgstr "在éžåŸºæœ¬æ‹†åˆ†æäº¤å›¾å½¢ä¸­çš„æœ€å¤§æäº¤æ•°"
+msgstr "在éžåŸºæœ¬æ‹†åˆ†æäº¤å›¾ä¸­çš„æœ€å¤§æäº¤æ•°"
#: builtin/commit-graph.c
msgid "maximum ratio between two levels of a split commit-graph"
-msgstr "一个拆分æäº¤å›¾å½¢çš„两个级别之间的最大比率"
+msgstr "一个拆分æäº¤å›¾çš„两个级别之间的最大比率"
#: builtin/commit-graph.c
msgid "only expire files older than a given date-time"
@@ -5666,7 +5749,7 @@ 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"
+"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"
@@ -5676,7 +5759,7 @@ msgid ""
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<模å¼>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <æäº¤> | --fixup [(amend|"
-"reword):]<æäº¤>)]\n"
+"reword):]<æäº¤>]\n"
" [-F <文件> | -m <消æ¯>] [--reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--author=<作者>]\n"
" [--date=<日期>] [--cleanup=<模å¼>] [--[no-]status]\n"
@@ -5769,10 +5852,6 @@ msgid "Failed to update main cache tree"
msgstr "ä¸èƒ½æ›´æ–°æ ‘的主缓存"
#: builtin/commit.c
-msgid "unable to write new_index file"
-msgstr "无法写 new_index 文件"
-
-#: builtin/commit.c
msgid "cannot do a partial commit during a merge."
msgstr "在åˆå¹¶è¿‡ç¨‹ä¸­ä¸èƒ½åšéƒ¨åˆ†æäº¤ã€‚"
@@ -5817,7 +5896,7 @@ msgid ""
"in the current commit message"
msgstr "æ— æ³•é€‰æ‹©ä¸€ä¸ªæœªè¢«å½“å‰æäº¤è¯´æ˜Žä½¿ç”¨çš„æ³¨é‡Šå­—ç¬¦"
-#: builtin/commit.c builtin/merge-tree.c
+#: builtin/commit.c
#, c-format
msgid "could not lookup commit '%s'"
msgstr "ä¸èƒ½æŸ¥è¯¢æäº¤ '%s'"
@@ -5862,35 +5941,35 @@ msgstr "ä¸èƒ½å†™æäº¤æ¨¡ç‰ˆ"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
-msgstr "è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%c' 开始的行将被忽略。\n"
+"with '%s' will be ignored.\n"
+msgstr "è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%s' 开始的行将被忽略。\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-"è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%c' 开始的行将被忽略,而一个空的æäº¤\n"
+"è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%s' 开始的行将被忽略,而一个空的æäº¤\n"
"说明将会终止æäº¤ã€‚\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
-"è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%c' 开始的行将被ä¿ç•™ï¼Œå¦‚果您愿æ„\n"
+"è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%s' 开始的行将被ä¿ç•™ï¼Œå¦‚果您愿æ„\n"
"也å¯ä»¥åˆ é™¤å®ƒä»¬ã€‚\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
-"è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%c' 开始的行将被ä¿ç•™ï¼Œå¦‚果您愿æ„\n"
+"è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '%s' 开始的行将被ä¿ç•™ï¼Œå¦‚果您愿æ„\n"
"也å¯ä»¥åˆ é™¤å®ƒä»¬ã€‚一个空的æäº¤è¯´æ˜Žå°†ä¼šç»ˆæ­¢æäº¤ã€‚\n"
#: builtin/commit.c
@@ -5941,7 +6020,7 @@ msgstr "%sæäº¤è€…:%.*s <%.*s>"
msgid "Cannot read index"
msgstr "无法读å–索引"
-#: builtin/commit.c
+#: builtin/commit.c builtin/tag.c
msgid "unable to pass trailers to --trailers"
msgstr "无法将尾注传递给 --trailers"
@@ -6119,7 +6198,7 @@ msgstr "日期"
msgid "override date for commit"
msgstr "æäº¤æ—¶è¦†ç›–日期"
-#: builtin/commit.c builtin/merge-tree.c parse-options.h ref-filter.h
+#: builtin/commit.c parse-options.h ref-filter.h
msgid "commit"
msgstr "æäº¤"
@@ -6151,11 +6230,11 @@ msgstr "使用自动挤压格å¼çš„æäº¤è¯´æ˜Žç”¨ä»¥æŒ¤åŽ‹è‡³æŒ‡å®šçš„æäº¤"
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr "现在将该æäº¤çš„作者改为我(和 -C/-c/--amend 傿•°å…±ç”¨ï¼‰"
-#: builtin/commit.c builtin/interpret-trailers.c
+#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c
msgid "trailer"
msgstr "尾注"
-#: builtin/commit.c
+#: builtin/commit.c builtin/tag.c
msgid "add custom trailer(s)"
msgstr "添加自定义尾注"
@@ -6260,24 +6339,72 @@ msgstr "å› æäº¤è¯´æ˜Žçš„æ­£æ–‡ä¸ºç©ºè€Œç»ˆæ­¢æäº¤ã€‚\n"
#: builtin/commit.c
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"仓库已更新,但无法写 new_index 文件。检查是å¦ç£ç›˜å·²æ»¡æˆ–\n"
+"仓库已更新,但无法写入索引文件。检查是å¦ç£ç›˜å·²æ»¡æˆ–\n"
"ç£ç›˜é…é¢å·²è€—å°½ï¼Œç„¶åŽæ‰§è¡Œ \"git restore --staged :/\" æ¢å¤ã€‚"
#: builtin/config.c
-msgid "git config [<options>]"
-msgstr "git config [<选项>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<文件选项>] [<显示选项>] [--includes]"
#: builtin/config.c
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "未能识别的 --type 傿•°ï¼Œ%s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<文件选项>] [<显示选项>] [--includes] [--all] [--regexp] [--"
+"value=<值>] [--fixed-value] [--default=<默认值>] <åç§°>"
#: builtin/config.c
-msgid "only one type at a time"
-msgstr "一次åªèƒ½ä¸€ä¸ªç±»åž‹"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<文件选项>] [--type=<类型>] [--all] [--value=<值>] [--fixed-"
+"value] <åç§°> <值>"
+
+#: builtin/config.c
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<文件选项>] [--all] [--value=<值>] [--fixed-value] <åç§°> <"
+"值>"
+
+#: builtin/config.c
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<文件选项>] <æ—§åç§°> <æ–°åç§°>"
+
+#: builtin/config.c
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<文件选项>] <åç§°>"
+
+#: builtin/config.c
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<文件选项>]"
+
+#: builtin/config.c
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<文件选项>] --get-colorbool <åç§°> [<标准输出为tty>]"
+
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<文件选项>] [<显示选项>] [--includes] [--all] [--regexp=<正则"
+"表达å¼>] [--value=<值>] [--fixed-value] [--default=<默认值>] <åç§°>"
+
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<文件选项>] [--type=<类型>] [--comment=<消æ¯>] [--all] [--"
+"value=<值>] [--fixed-value] <åç§°> <值>"
#: builtin/config.c
msgid "Config file location"
@@ -6312,70 +6439,6 @@ msgid "read config from given blob object"
msgstr "从给定的数æ®å¯¹è±¡è¯»å–é…ç½®"
#: builtin/config.c
-msgid "Action"
-msgstr "æ“作"
-
-#: builtin/config.c
-msgid "get value: name [value-pattern]"
-msgstr "获å–值:åç§° [值模å¼]"
-
-#: builtin/config.c
-msgid "get all values: key [value-pattern]"
-msgstr "获得所有的值:键 [值模å¼]"
-
-#: builtin/config.c
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "æ ¹æ®æ­£åˆ™è¡¨è¾¾å¼èŽ·å¾—å€¼ï¼šå称正则 [值模å¼]"
-
-#: builtin/config.c
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "获得 URL å–值:section[.var] URL"
-
-#: builtin/config.c
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "æ›¿æ¢æ‰€æœ‰åŒ¹é…çš„å˜é‡ï¼šåç§° 值 [值模å¼]"
-
-#: builtin/config.c
-msgid "add a new variable: name value"
-msgstr "添加一个新的å˜é‡ï¼šåç§° 值"
-
-#: builtin/config.c
-msgid "remove a variable: name [value-pattern]"
-msgstr "删除一个å˜é‡ï¼šåç§° [值模å¼]"
-
-#: builtin/config.c
-msgid "remove all matches: name [value-pattern]"
-msgstr "删除所有匹é…项:åç§° [值模å¼]"
-
-#: builtin/config.c
-msgid "rename section: old-name new-name"
-msgstr "é‡å‘½åå°èŠ‚ï¼šold-name new-name"
-
-#: builtin/config.c
-msgid "remove a section: name"
-msgstr "删除一个å°èŠ‚ï¼šname"
-
-#: builtin/config.c
-msgid "list all"
-msgstr "列出所有"
-
-#: builtin/config.c
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr "在比较值与 '值模å¼' æ—¶ï¼Œä½¿ç”¨å­—ç¬¦ä¸²å­—é¢æ¯”较"
-
-#: builtin/config.c
-msgid "open an editor"
-msgstr "打开一个编辑器"
-
-#: builtin/config.c
-msgid "find the color configured: slot [default]"
-msgstr "获得é…置的颜色:é…ç½® [默认]"
-
-#: builtin/config.c
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "获得颜色设置:é…ç½® [stdout-is-tty]"
-
-#: builtin/config.c
msgid "Type"
msgstr "类型"
@@ -6412,8 +6475,8 @@ msgid "value is an expiry date"
msgstr "值是一个到期日期"
#: builtin/config.c
-msgid "Other"
-msgstr "其它"
+msgid "Display options"
+msgstr "显示选项"
#: builtin/config.c
msgid "terminate values with NUL byte"
@@ -6424,10 +6487,6 @@ msgid "show variable names only"
msgstr "åªæ˜¾ç¤ºå˜é‡å"
#: builtin/config.c
-msgid "respect include directives on lookup"
-msgstr "查询时å‚ç…§ include 指令递归查找"
-
-#: builtin/config.c
msgid "show origin of config (file, standard input, blob, command line)"
msgstr "显示é…ç½®çš„æ¥æºï¼ˆæ–‡ä»¶ã€æ ‡å‡†è¾“å…¥ã€æ•°æ®å¯¹è±¡ï¼Œæˆ–命令行)"
@@ -6436,12 +6495,17 @@ msgid "show scope of config (worktree, local, global, system, command)"
msgstr "显示é…ç½®çš„ä½œç”¨åŸŸï¼ˆå·¥ä½œåŒºã€æœ¬åœ°ã€å…¨å±€ã€ç³»ç»Ÿã€å‘½ä»¤ï¼‰"
#: builtin/config.c
-msgid "value"
-msgstr "å–值"
+msgid "show config keys in addition to their values"
+msgstr "显示é…置键åŠå…¶å€¼"
#: builtin/config.c
-msgid "with --get, use default value when missing entry"
-msgstr "使用 --get 傿•°ï¼Œå½“缺少设置时使用默认值"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "未能识别的 --type 傿•°ï¼Œ%s"
+
+#: builtin/config.c
+msgid "only one type at a time"
+msgstr "一次åªèƒ½ä¸€ä¸ªç±»åž‹"
#: builtin/config.c
#, c-format
@@ -6534,52 +6598,93 @@ msgstr ""
"详情请阅读“git help worktreeâ€çš„“CONFIGURATION FILEâ€å°èŠ‚"
#: builtin/config.c
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color å’Œå˜é‡ç±»åž‹ä¸å…¼å®¹"
+msgid "Other"
+msgstr "其它"
#: builtin/config.c
-msgid "only one action at a time"
-msgstr "一次åªèƒ½æœ‰ä¸€ä¸ªåŠ¨ä½œ"
+msgid "respect include directives on lookup"
+msgstr "查询时å‚ç…§ include 指令递归查找"
#: builtin/config.c
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only 仅适用于 --list 或 --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "无法读å–é…置文件 '%s'"
#: builtin/config.c
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr "--show-origin 仅适用于 --getã€--get-allã€--get-regexp å’Œ --list"
+msgid "error processing config file(s)"
+msgstr "处ç†é…置文件出错"
#: builtin/config.c
-msgid "--default is only applicable to --get"
-msgstr "--default 仅适用于 --get"
+msgid "Filter options"
+msgstr "过滤选项"
+
+#: builtin/config.c
+msgid "return all values for multi-valued config options"
+msgstr "返回多值é…置选项的所有值"
+
+#: builtin/config.c
+msgid "interpret the name as a regular expression"
+msgstr "å°†å称解释为正则表达å¼"
+
+#: builtin/config.c
+msgid "show config with values matching the pattern"
+msgstr "显示值与模å¼åŒ¹é…çš„é…ç½®"
+
+#: builtin/config.c
+msgid "use string equality when comparing values to value pattern"
+msgstr "在将值与值模å¼è¿›è¡Œæ¯”较时使用字符串相等性"
+
+#: builtin/config.c
+msgid "URL"
+msgstr "URL"
+
+#: builtin/config.c
+msgid "show config matching the given URL"
+msgstr "显示与给定 URL 匹é…çš„é…ç½®"
+
+#: builtin/config.c
+msgid "value"
+msgstr "值"
+
+#: builtin/config.c
+msgid "use default value when missing entry"
+msgstr "缺少æ¡ç›®æ—¶ä½¿ç”¨é»˜è®¤å€¼"
#: builtin/config.c
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value 仅适用于有 '值模å¼'"
#: builtin/config.c
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "无法读å–é…置文件 '%s'"
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= ä¸èƒ½ä¸Ž --all 或 --url= 一起使用"
#: builtin/config.c
-msgid "error processing config file(s)"
-msgstr "处ç†é…置文件出错"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= ä¸èƒ½ä¸Ž --allã€--regexp 或 --value 一起使用"
#: builtin/config.c
-msgid "editing stdin is not supported"
-msgstr "䏿”¯æŒç¼–辑标准输入"
+msgid "Filter"
+msgstr "过滤器"
#: builtin/config.c
-msgid "editing blobs is not supported"
-msgstr "䏿”¯æŒç¼–辑数æ®å¯¹è±¡"
+msgid "replace multi-valued config option with new value"
+msgstr "将多值é…置选项替æ¢ä¸ºæ–°å€¼"
#: builtin/config.c
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "ä¸èƒ½åˆ›å»ºé…置文件 %s"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr "人类å¯è¯»çš„æ³¨é‡Šå­—符串(# 将根æ®éœ€è¦æ·»åŠ åˆ°å‰é¢ï¼‰"
+
+#: builtin/config.c
+msgid "add a new line without altering any existing values"
+msgstr "æ·»åŠ æ–°è¡Œè€Œä¸æ›´æ”¹ä»»ä½•现有值"
+
+#: builtin/config.c
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value åªèƒ½ä¸Ž --value=<模å¼> é…åˆä½¿ç”¨"
+
+#: builtin/config.c
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append ä¸èƒ½ä¸Ž --value=<模å¼> 一起使用"
#: builtin/config.c
#, c-format
@@ -6595,6 +6700,109 @@ msgstr ""
msgid "no such section: %s"
msgstr "æ— æ­¤å°èŠ‚ï¼š%s"
+#: builtin/config.c
+msgid "editing stdin is not supported"
+msgstr "䏿”¯æŒç¼–辑标准输入"
+
+#: builtin/config.c
+msgid "editing blobs is not supported"
+msgstr "䏿”¯æŒç¼–辑数æ®å¯¹è±¡"
+
+#: builtin/config.c
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "ä¸èƒ½åˆ›å»ºé…置文件 %s"
+
+#: builtin/config.c
+msgid "Action"
+msgstr "æ“作"
+
+#: builtin/config.c
+msgid "get value: name [<value-pattern>]"
+msgstr "获å–值:name [<值模å¼>]"
+
+#: builtin/config.c
+msgid "get all values: key [<value-pattern>]"
+msgstr "èŽ·å–æ‰€æœ‰å€¼ï¼škey [<值模å¼>]"
+
+#: builtin/config.c
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "èŽ·å–æ­£åˆ™è¡¨è¾¾å¼çš„值:name-regex [<值模å¼>]"
+
+#: builtin/config.c
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "获得 URL å–值:section[.var] URL"
+
+#: builtin/config.c
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "æ›¿æ¢æ‰€æœ‰åŒ¹é…çš„å˜é‡ï¼šname value [<值模å¼>]"
+
+#: builtin/config.c
+msgid "add a new variable: name value"
+msgstr "添加一个新的å˜é‡ï¼šåç§° 值"
+
+#: builtin/config.c
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "删除一个å˜é‡ï¼šåç§° [<值模å¼>]"
+
+#: builtin/config.c
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "删除所有匹é…项:åç§° [<值模å¼>]"
+
+#: builtin/config.c
+msgid "rename section: old-name new-name"
+msgstr "é‡å‘½åå°èŠ‚ï¼šold-name new-name"
+
+#: builtin/config.c
+msgid "remove a section: name"
+msgstr "删除一个å°èŠ‚ï¼šname"
+
+#: builtin/config.c
+msgid "list all"
+msgstr "列出所有"
+
+#: builtin/config.c
+msgid "open an editor"
+msgstr "打开编辑器"
+
+#: builtin/config.c
+msgid "find the color configured: slot [<default>]"
+msgstr "找到é…置的颜色:slot [<默认>]"
+
+#: builtin/config.c
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "找到颜色设置:slot [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid "with --get, use default value when missing entry"
+msgstr "使用 --get 傿•°ï¼Œå½“缺少设置时使用默认值"
+
+#: builtin/config.c
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color å’Œå˜é‡ç±»åž‹ä¸å…¼å®¹"
+
+#: builtin/config.c
+msgid "no action specified"
+msgstr "未指定任何æ“作"
+
+#: builtin/config.c
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only 仅适用于 --list 或 --get-regexp"
+
+#: builtin/config.c
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr "--show-origin 仅适用于 --getã€--get-allã€--get-regexp å’Œ --list"
+
+#: builtin/config.c
+msgid "--default is only applicable to --get"
+msgstr "--default 仅适用于 --get"
+
+#: builtin/config.c
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment 仅适用于 add/set/replace æ“作"
+
#: builtin/count-objects.c
msgid "print sizes in human readable format"
msgstr "以用户å¯è¯»çš„æ ¼å¼æ˜¾ç¤ºå¤§å°"
@@ -6821,7 +7029,7 @@ msgstr "--merge-base 仅适用于两个æäº¤"
#: builtin/diff.c
#, c-format
msgid "'%s': not a regular file or symlink"
-msgstr "'%s'ï¼šä¸æ˜¯ä¸€ä¸ªæ­£è§„文件或符å·é“¾æŽ¥"
+msgstr "'%s'ï¼šä¸æ˜¯ä¸€ä¸ªæ™®é€šæ–‡ä»¶æˆ–符å·é“¾æŽ¥"
#: builtin/diff.c
msgid "no merge given, only parents."
@@ -7198,8 +7406,8 @@ msgstr ""
#: builtin/fetch.c
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s 未å‘逿‰€æœ‰å¿…需的对象\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s 未å‘逿‰€æœ‰å¿…需的对象"
#: builtin/fetch.c
#, c-format
@@ -7247,8 +7455,8 @@ msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的"
#: builtin/fetch.c
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "选项 \"%s\" 为 %s 所忽略\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "选项 \"%s\" 为 %s 所忽略"
#: builtin/fetch.c object-file.c
#, c-format
@@ -7601,6 +7809,10 @@ msgid "read reference patterns from stdin"
msgstr "从标准输入读å–引用的模å¼"
#: builtin/for-each-ref.c
+msgid "also include HEAD ref and pseudorefs"
+msgstr "还包括 HEAD 引用和伪引用"
+
+#: builtin/for-each-ref.c
msgid "unknown arguments supplied with --stdin"
msgstr "为 --stdin æä¾›äº†æœªçŸ¥çš„命令傿•°"
@@ -7617,6 +7829,10 @@ msgid "config key storing a list of repository paths"
msgstr "存储ç€ä»“库路径列表的é…置项键å"
#: builtin/for-each-repo.c
+msgid "keep going even if command fails in a repository"
+msgstr "å³ä½¿å­˜å‚¨åº“中的命令失败,ä»ç»§ç»­æ‰§è¡Œ"
+
+#: builtin/for-each-repo.c
msgid "missing --config=<config>"
msgstr "缺少 --config=<é…ç½®>"
@@ -8070,6 +8286,10 @@ msgstr "清除未引用的对象"
msgid "pack unreferenced objects separately"
msgstr "分开打包未引用的对象"
+#: builtin/gc.c builtin/repack.c
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "使用 --cruft,é™åˆ¶æ–° cruft 包的总大å°"
+
#: builtin/gc.c
msgid "be more thorough (increased runtime)"
msgstr "更彻底(增加è¿è¡Œæ—¶é—´ï¼‰"
@@ -8079,6 +8299,10 @@ msgid "enable auto-gc mode"
msgstr "å¯ç”¨è‡ªåŠ¨åžƒåœ¾å›žæ”¶æ¨¡å¼"
#: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "在åŽå°è¿›è¡Œåžƒåœ¾å›žæ”¶"
+
+#: builtin/gc.c
msgid "force running gc even if there may be another gc running"
msgstr "强制执行 gc å³ä½¿å¦å¤–一个 gc 正在执行"
@@ -8196,6 +8420,10 @@ msgid "run tasks based on the state of the repository"
msgstr "åŸºäºŽä»“åº“çŠ¶æ€æ¥è¿è¡Œä»»åŠ¡"
#: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "在åŽå°æ‰§è¡Œè¿ç»´"
+
+#: builtin/gc.c
msgid "frequency"
msgstr "频率"
@@ -8285,14 +8513,6 @@ msgstr "无法è¿è¡Œ 'crontab',您的系统å¯èƒ½ä¸æ”¯æŒ 'cron'"
msgid "'crontab' died"
msgstr "'crontab' 终止"
-#: builtin/gc.c
-msgid "failed to start systemctl"
-msgstr "无法å¯åЍ systemctl"
-
-#: builtin/gc.c
-msgid "failed to run systemctl"
-msgstr "无法è¿è¡Œ systemctl"
-
#: builtin/gc.c builtin/worktree.c
#, c-format
msgid "failed to delete '%s'"
@@ -8304,6 +8524,14 @@ msgid "failed to flush '%s'"
msgstr "无法刷新 '%s'"
#: builtin/gc.c
+msgid "failed to start systemctl"
+msgstr "无法å¯åЍ systemctl"
+
+#: builtin/gc.c
+msgid "failed to run systemctl"
+msgstr "无法è¿è¡Œ systemctl"
+
+#: builtin/gc.c
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "无法识别的 --scheduler 傿•° '%s'"
@@ -8334,6 +8562,10 @@ msgid "scheduler to trigger git maintenance run"
msgstr "è§¦å‘ git maintenance 执行的调度器"
#: builtin/gc.c
+msgid "failed to set up maintenance schedule"
+msgstr "无法设置维护计划"
+
+#: builtin/gc.c
msgid "failed to add repo to global config"
msgstr "无法将仓库添加到全局é…ç½®"
@@ -8367,8 +8599,8 @@ msgstr "没有线程支æŒï¼Œå¿½ç•¥ %s"
#: builtin/grep.c
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "æ— æ³•è¯»å–æ ‘(%s)"
+msgid "unable to read tree %s"
+msgstr "æ— æ³•è¯»å–æ ‘ %s"
#: builtin/grep.c
#, c-format
@@ -8429,8 +8661,8 @@ msgid "search in subdirectories (default)"
msgstr "在å­ç›®å½•中寻找(默认)"
#: builtin/grep.c
-msgid "descend at most <depth> levels"
-msgstr "最多以指定的深度å‘下寻找"
+msgid "descend at most <n> levels"
+msgstr "最多å‘下寻找 <n> 层"
#: builtin/grep.c
msgid "use extended POSIX regular expressions"
@@ -8893,11 +9125,6 @@ msgstr "解压缩严é‡çš„ä¸ä¸€è‡´"
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "å‘现 %s 出现 SHA1 冲çªï¼"
-#: builtin/index-pack.c builtin/pack-objects.c
-#, c-format
-msgid "unable to read %s"
-msgstr "ä¸èƒ½è¯» %s"
-
#: builtin/index-pack.c
#, c-format
msgid "cannot read existing object info %s"
@@ -9075,11 +9302,13 @@ msgstr "在打包对象中 fsck 检查出错"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-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"
+" [--ref-format=<æ ¼å¼>]\n"
" [-b <分支å> | --initial-branch=<分支å>]\n"
" [--shared[=<æƒé™>]] [<目录>]"
@@ -9132,13 +9361,46 @@ msgstr "--separate-git-dir ä¸èƒ½ç”¨äºŽçº¯ä»“库"
#: builtin/interpret-trailers.c
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <键>[(=|:)<值>])...]\n"
+" [(--trailer (<é”®|键别å>)[(=|:)<值>])...]\n"
" [--parse] [<文件>...]"
+#: builtin/interpret-trailers.c wrapper.c
+#, c-format
+msgid "could not stat %s"
+msgstr "ä¸èƒ½å¯¹ %s 调用 stat"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "文件 %s 䏿˜¯ä¸€ä¸ªæ™®é€šæ–‡ä»¶"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "文件 %s 用户ä¸å¯å†™"
+
+#: builtin/interpret-trailers.c
+msgid "could not open temporary file"
+msgstr "ä¸èƒ½æ‰“开临时文件"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "ä¸èƒ½è¯»å–输入文件 '%s'"
+
+#: builtin/interpret-trailers.c builtin/mktag.c imap-send.c
+msgid "could not read from stdin"
+msgstr "ä¸èƒ½è‡ªæ ‡å‡†è¾“入读å–"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "ä¸èƒ½é‡å‘½å临时文件为 %s"
+
#: builtin/interpret-trailers.c
msgid "edit files in place"
msgstr "在原ä½ç¼–辑文件"
@@ -9148,6 +9410,10 @@ msgid "trim empty trailers"
msgstr "删除空的尾注"
#: builtin/interpret-trailers.c
+msgid "placement"
+msgstr "安置"
+
+#: builtin/interpret-trailers.c
msgid "where to place the new trailer"
msgstr "在哪里放置新的尾注"
@@ -9164,20 +9430,20 @@ msgid "output only the trailers"
msgstr "åªè¾“出尾注"
#: builtin/interpret-trailers.c
-msgid "do not apply config rules"
-msgstr "ä¸è¦åº”用é…置规则"
+msgid "do not apply trailer.* configuration variables"
+msgstr "ä¸åº”用 trailer.* é…ç½®å˜é‡"
#: builtin/interpret-trailers.c
-msgid "join whitespace-continued values"
-msgstr "连接空白折行的值"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "å°†å¤šè¡Œå°¾æ³¨å€¼é‡æ–°æ ¼å¼åŒ–为å•行值"
#: builtin/interpret-trailers.c
-msgid "set parsing options"
-msgstr "设置解æžé€‰é¡¹"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "--only-trailers --only-input --unfold 的别å"
#: builtin/interpret-trailers.c
-msgid "do not treat --- specially"
-msgstr "ä¸è¦å¯¹ --- 特殊处ç†"
+msgid "do not treat \"---\" as the end of input"
+msgstr "ä¸è¦å°† \"---\" 视为输入的结æŸ"
#: builtin/interpret-trailers.c
msgid "trailer(s) to add"
@@ -9234,7 +9500,7 @@ msgid ""
"<file>"
msgstr "跟踪 <文件> 中 <开始>,<结æŸ> 范围内的行或函数 :<函数å> 的演å˜"
-#: builtin/log.c builtin/shortlog.c bundle.c
+#: builtin/log.c builtin/replay.c builtin/shortlog.c bundle.c
#, c-format
msgid "unrecognized argument: %s"
msgstr "æœªèƒ½è¯†åˆ«çš„å‚æ•°ï¼š%s"
@@ -9249,10 +9515,6 @@ msgid "Final output: %d %s\n"
msgstr "最终输出:%d %s\n"
#: builtin/log.c
-msgid "unable to create temporary object directory"
-msgstr "无法创建临时对象目录"
-
-#: builtin/log.c
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: æŸå的文件"
@@ -9290,6 +9552,11 @@ msgid "not a range"
msgstr "䏿˜¯ä¸€ä¸ªèŒƒå›´"
#: builtin/log.c
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "无法读å–分支æè¿°æ–‡ä»¶ '%s'"
+
+#: builtin/log.c
msgid "cover letter needs email format"
msgstr "附函需è¦é‚®ä»¶åœ°å€æ ¼å¼"
@@ -9404,8 +9671,12 @@ msgid "max length of output filename"
msgstr "输出文件å的最大长度"
#: builtin/log.c
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "使用 [RFC PATCH] 代替 [PATCH]"
+msgid "rfc"
+msgstr "RFC"
+
+#: builtin/log.c
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "在 'PATCH' 之剿·»åŠ  <RFC> (默认为 'RFC')"
#: builtin/log.c
msgid "cover-from-description-mode"
@@ -9416,6 +9687,10 @@ msgid "generate parts of a cover letter based on a branch's description"
msgstr "基于一个分支æè¿°ç”Ÿæˆéƒ¨åˆ†é™„函"
#: builtin/log.c
+msgid "use branch description from file"
+msgstr "使用æ¥è‡ªæ–‡ä»¶çš„分支æè¿°"
+
+#: builtin/log.c
msgid "use [<prefix>] instead of [PATCH]"
msgstr "使用 [<å‰ç¼€>] 代替 [PATCH]"
@@ -9624,21 +9899,6 @@ 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 '('"
-msgstr "åçš„ ls-files æ ¼å¼ï¼šå…ƒç´  '%s' 没有以 '(' 开头"
-
-#: builtin/ls-files.c
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "åçš„ ls-files æ ¼å¼ï¼šå…ƒç´  '%s' 没有以 ')' 结尾"
-
-#: builtin/ls-files.c
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "åçš„ ls-files æ ¼å¼: %%%.*s"
-
-#: builtin/ls-files.c
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<选项>] [<文件>...]"
@@ -9730,7 +9990,7 @@ msgstr "显示相对于顶级目录的文件å"
msgid "if any <file> is not in the index, treat this as an error"
msgstr "如果任何 <文件> 都ä¸åœ¨ç´¢å¼•区,视为错误"
-#: builtin/ls-files.c
+#: builtin/ls-files.c builtin/merge-tree.c
msgid "tree-ish"
msgstr "树对象"
@@ -9760,11 +10020,11 @@ msgstr ""
#: builtin/ls-remote.c
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<坿‰§è¡Œæ–‡ä»¶>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<é”®>]\n"
" [--symref] [<仓库> [<模å¼>...]]"
@@ -9785,9 +10045,13 @@ msgid "limit to tags"
msgstr "ä»…é™äºŽæ ‡ç­¾"
#: builtin/ls-remote.c
-msgid "limit to heads"
+msgid "limit to branches"
msgstr "ä»…é™äºŽåˆ†æ”¯"
+#: builtin/ls-remote.c builtin/show-ref.c
+msgid "deprecated synonym for --branches"
+msgstr "已弃用的 --branches åŒä¹‰è¯"
+
#: builtin/ls-remote.c
msgid "do not show peeled tags"
msgstr "䏿˜¾ç¤ºå·²è§£æžçš„æ ‡ç­¾"
@@ -9809,21 +10073,6 @@ msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
msgstr "git ls-tree [<选项>] <树对象> [<路径>...]"
#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "åçš„ ls-tree æ ¼å¼ï¼šå…ƒç´  '%s' 没有以 '(' 开头"
-
-#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "åçš„ ls-tree æ ¼å¼ï¼šå…ƒç´  '%s' 没有以 ')' 结尾"
-
-#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "åçš„ ls-tree æ ¼å¼: %%%.*s"
-
-#: builtin/ls-tree.c
msgid "only show trees"
msgstr "åªæ˜¾ç¤ºæ ‘"
@@ -9969,11 +10218,23 @@ msgstr ""
"git merge-file [<选项>] [-L <åå­—1> [-L <åˆå§‹åå­—> [-L <åå­—2>]]] <文件1> <åˆ"
"始文件> <文件2>"
+#: builtin/merge-file.c diff.c
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"选项 diff-algorithm 接å—傿•° \"myers\"ã€\"minimal\"ã€\"patience\" å’Œ "
+"\"histogram\""
+
#: builtin/merge-file.c
msgid "send results to standard output"
msgstr "将结果å‘é€åˆ°æ ‡å‡†è¾“出"
#: builtin/merge-file.c
+msgid "use object IDs instead of filenames"
+msgstr "使用对象 ID æ›¿æ¢æ–‡ä»¶å"
+
+#: builtin/merge-file.c
msgid "use a diff3 based merge"
msgstr "使用基于 diff3 çš„åˆå¹¶"
@@ -9981,17 +10242,13 @@ msgstr "使用基于 diff3 çš„åˆå¹¶"
msgid "use a zealous diff3 based merge"
msgstr "使用基于狂热 diff3(zealous diff3)的åˆå¹¶"
-#: builtin/merge-file.c
-msgid "for conflicts, use our version"
-msgstr "如果冲çªï¼Œä½¿ç”¨æˆ‘们的版本"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use their version"
-msgstr "如果冲çªï¼Œä½¿ç”¨ä»–们的版本"
+#: builtin/merge-file.c diff.c
+msgid "<algorithm>"
+msgstr "<算法>"
-#: builtin/merge-file.c
-msgid "for conflicts, use a union version"
-msgstr "如果冲çªï¼Œä½¿ç”¨è”åˆç‰ˆæœ¬"
+#: builtin/merge-file.c diff.c
+msgid "choose a diff algorithm"
+msgstr "选择一个差异算法"
#: builtin/merge-file.c
msgid "for conflicts, use this marker size"
@@ -10005,6 +10262,15 @@ msgstr "ä¸è¦è­¦å‘Šå†²çª"
msgid "set labels for file1/orig-file/file2"
msgstr "为 文件1/åˆå§‹æ–‡ä»¶/文件2 设置标签"
+#: builtin/merge-file.c
+#, c-format
+msgid "object '%s' does not exist"
+msgstr "对象 '%s' ä¸å­˜åœ¨"
+
+#: builtin/merge-file.c
+msgid "Could not write object file"
+msgstr "ä¸èƒ½å†™å…¥å¯¹è±¡æ–‡ä»¶"
+
#: builtin/merge-recursive.c
#, c-format
msgid "unknown option %s"
@@ -10036,6 +10302,11 @@ msgstr "无法解æžå¼•用 '%s'"
msgid "Merging %s with %s\n"
msgstr "åˆå¹¶ %s å’Œ %s\n"
+#: builtin/merge-tree.c
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "无法解æžä¸ºæ ‘对象 '%s'"
+
#: builtin/merge-tree.c builtin/merge.c
msgid "not something we can merge"
msgstr "䏿˜¯å¯ä»¥åˆå¹¶çš„东西"
@@ -10084,13 +10355,22 @@ msgstr "实施多个åˆå¹¶ï¼Œæ¯è¾“入行一个"
msgid "specify a merge-base for the merge"
msgstr "指定用于åˆå¹¶çš„åˆå¹¶åŸºçº¿"
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option=value"
+msgstr "option=value"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option for selected merge strategy"
+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/merge.c
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "未知的策略选项:-X%s"
#: builtin/merge-tree.c builtin/notes.c
#, c-format
@@ -10179,14 +10459,6 @@ msgstr "ç­–ç•¥"
msgid "merge strategy to use"
msgstr "è¦ä½¿ç”¨çš„åˆå¹¶ç­–ç•¥"
-#: builtin/merge.c builtin/pull.c
-msgid "option=value"
-msgstr "option=value"
-
-#: builtin/merge.c builtin/pull.c
-msgid "option for selected merge strategy"
-msgstr "所选的åˆå¹¶ç­–略的选项"
-
#: builtin/merge.c
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "åˆå¹¶çš„æäº¤è¯´æ˜Žï¼ˆé’ˆå¯¹éžå¿«è¿›å¼åˆå¹¶ï¼‰"
@@ -10257,7 +10529,7 @@ msgstr "'%s' 没有指å‘一个æäº¤"
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "åçš„ branch.%s.mergeoptions 字符串:%s"
-#: builtin/merge.c builtin/stash.c merge-recursive.c
+#: builtin/merge.c merge-recursive.c
msgid "Unable to write index."
msgstr "ä¸èƒ½å†™å…¥ç´¢å¼•。"
@@ -10265,12 +10537,7 @@ msgstr "ä¸èƒ½å†™å…¥ç´¢å¼•。"
msgid "Not handling anything other than two heads merge."
msgstr "未处ç†ä¸¤ä¸ªå¤´åˆå¹¶ä¹‹å¤–的任何æ“作。"
-#: builtin/merge.c
-#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "未知的策略选项:-X%s"
-
-#: builtin/merge.c t/helper/test-fast-rebase.c
+#: builtin/merge.c builtin/sparse-checkout.c
#, c-format
msgid "unable to write %s"
msgstr "ä¸èƒ½å†™ %s"
@@ -10302,9 +10569,9 @@ msgstr "空的æäº¤è¯´æ˜Žä¼šç»ˆæ­¢æäº¤ã€‚\n"
#: builtin/merge.c
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
-msgstr "以 '%c' 开始的行将被忽略,而空的æäº¤è¯´æ˜Žå°†ç»ˆæ­¢æäº¤ã€‚\n"
+msgstr "以 '%s' 开始的行将被忽略,而空的æäº¤è¯´æ˜Žå°†ç»ˆæ­¢æäº¤ã€‚\n"
#: builtin/merge.c
msgid "Empty commit message."
@@ -10497,10 +10764,6 @@ msgstr "ä¸èƒ½è¯»å–被标记的对象 '%s'"
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "对象 '%s' 被标记为 '%s',然而是一个 '%s' 类型"
-#: builtin/mktag.c imap-send.c trailer.c
-msgid "could not read from stdin"
-msgstr "ä¸èƒ½è‡ªæ ‡å‡†è¾“入读å–"
-
#: builtin/mktag.c
msgid "tag on stdin did not pass our strict fsck check"
msgstr "标准输入上的标签未通过我们严格的 fsck 检查"
@@ -10566,6 +10829,10 @@ msgid "write multi-pack bitmap"
msgstr "写入多包ä½å›¾"
#: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "å†™å…¥ä¸€ä¸ªæ–°çš„å¢žé‡ MIDX"
+
+#: builtin/multi-pack-index.c
msgid "write multi-pack index containing only given indexes"
msgstr "写入åªåŒ…括给定索引的多包索引"
@@ -10628,8 +10895,8 @@ msgid "can not move directory into itself"
msgstr "ä¸èƒ½å°†ç›®å½•移动到自身"
#: builtin/mv.c
-msgid "cannot move directory over file"
-msgstr "ä¸èƒ½å°†ç›®å½•移动到文件"
+msgid "destination already exists"
+msgstr "目标已存在"
#: builtin/mv.c
msgid "source directory is empty"
@@ -10833,11 +11100,6 @@ msgid "Write/edit the notes for the following object:"
msgstr "为下é¢çš„对象写/编辑说明:"
#: builtin/notes.c
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "ä¸èƒ½ä¸ºå¯¹è±¡ '%s' 开始 'show'"
-
-#: builtin/notes.c
msgid "could not read 'show' output"
msgstr "ä¸èƒ½è¯»å– 'show' 的输出"
@@ -11258,6 +11520,11 @@ msgstr "ä¸ä¸€è‡´çš„差异计数"
#: builtin/pack-objects.c
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "无效的 pack.allowPackReuse 值:'%s'"
+
+#: builtin/pack-objects.c
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -11557,10 +11824,6 @@ msgid "--thin cannot be used to build an indexable pack"
msgstr "--thin ä¸èƒ½ç”¨äºŽåˆ›å»ºä¸€ä¸ªå¯ç´¢å¼•包"
#: builtin/pack-objects.c
-msgid "cannot use --filter without --stdout"
-msgstr "ä¸èƒ½åœ¨æ²¡æœ‰ --stdout 的情况下使用 --filter"
-
-#: builtin/pack-objects.c
msgid "cannot use --filter with --stdin-packs"
msgstr "ä¸èƒ½åŒæ—¶ä½¿ç”¨ --filter å’Œ --stdin-packs"
@@ -11577,10 +11840,6 @@ msgid "cannot use --stdin-packs with --cruft"
msgstr "ä¸èƒ½å°† --stdin-packs å’Œ --cruft åŒæ—¶ä½¿ç”¨"
#: builtin/pack-objects.c
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "ä¸èƒ½å°† --max-pack-size å’Œ --cruft åŒæ—¶ä½¿ç”¨"
-
-#: builtin/pack-objects.c
msgid "Enumerating objects"
msgstr "枚举对象中"
@@ -11588,10 +11847,10 @@ msgstr "枚举对象中"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"总共 %<PRIu32>(差异 %<PRIu32>),å¤ç”¨ %<PRIu32>(差异 %<PRIu32>),包å¤ç”¨ "
-"%<PRIu32>"
+"%<PRIu32>(æ¥è‡ª %<PRIuMAX> 个包)"
#: builtin/pack-redundant.c
msgid ""
@@ -11612,10 +11871,11 @@ msgstr "æ‹’ç»åœ¨æœªæŒ‡å®š --i-still-use-this 选项时è¿è¡Œ"
#: builtin/pack-refs.c
msgid ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <模å¼>] [--exclude <模å¼>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <模å¼>] [--exclude <模"
+"å¼>]"
#: builtin/pack-refs.c
msgid "pack everything"
@@ -11626,6 +11886,10 @@ msgid "prune loose refs (default)"
msgstr "æ¸…é™¤æ¾æ•£çš„引用(默认)"
#: builtin/pack-refs.c
+msgid "auto-pack refs as needed"
+msgstr "按需对引用自动打包"
+
+#: builtin/pack-refs.c
msgid "references to include"
msgstr "需包å«çš„引用"
@@ -12386,19 +12650,6 @@ msgid "could not remove '%s'"
msgstr "无法删除 '%s'"
#: builtin/rebase.c
-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 ""
-"手工解决所有冲çªï¼Œæ‰§è¡Œ \"git add/rm <冲çªçš„æ–‡ä»¶>\" 标记\n"
-"冲çªå·²è§£å†³ï¼Œç„¶åŽæ‰§è¡Œ \"git rebase --continue\"。您也å¯ä»¥æ‰§è¡Œ\n"
-"\"git rebase --skip\" 命令跳过这个æäº¤ã€‚如果想è¦ç»ˆæ­¢æ‰§è¡Œå¹¶å›žåˆ°\n"
-"\"git rebase\" 执行之å‰çš„状æ€ï¼Œæ‰§è¡Œ \"git rebase --abort\"。"
-
-#: builtin/rebase.c
#, c-format
msgid ""
"\n"
@@ -12431,11 +12682,15 @@ msgid "apply options and merge options cannot be used together"
msgstr "应用选项和åˆå¹¶é€‰é¡¹ä¸èƒ½åŒæ—¶ä½¿ç”¨"
#: builtin/rebase.c
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask 已弃用;请使用 '--empty=stop'。"
+
+#: builtin/rebase.c
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
-msgstr "无法识别的空类型 '%s';有效值有 \"drop\"ã€\"keep\" å’Œ \"ask\"。"
+"\"stop\"."
+msgstr "无法识别的空类型 '%s';有效值有 \"drop\"ã€\"keep\" å’Œ \"stop\"。"
#: builtin/rebase.c
msgid ""
@@ -12577,7 +12832,7 @@ msgstr "让用户编辑è¦å˜åŸºçš„æäº¤åˆ—表"
msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
msgstr "(已删除)曾是:å°è¯•é‡å»ºåˆå¹¶æäº¤è€Œéžå¿½ç•¥å®ƒä»¬"
-#: builtin/rebase.c
+#: builtin/rebase.c builtin/revert.c
msgid "how to handle commits that become empty"
msgstr "å¦‚ä½•å¤„ç†æˆä¸ºç©ºæäº¤çš„æäº¤"
@@ -12658,14 +12913,14 @@ msgstr ""
"å–而代之请使用 'merges'"
#: builtin/rebase.c
-msgid "No rebase in progress?"
-msgstr "没有正在进行的å˜åŸºï¼Ÿ"
+msgid "no rebase in progress"
+msgstr "没有正在进行的å˜åŸº"
#: builtin/rebase.c
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr "动作 --edit-todo åªèƒ½ç”¨åœ¨äº¤äº’å¼å˜åŸºè¿‡ç¨‹ä¸­ã€‚"
-#: builtin/rebase.c t/helper/test-fast-rebase.c
+#: builtin/rebase.c
msgid "Cannot read HEAD"
msgstr "ä¸èƒ½è¯»å– HEAD"
@@ -12710,16 +12965,6 @@ msgid "switch `C' expects a numerical value"
msgstr "开关 `C' 期望一个数字值"
#: 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-"
-"autosquash"
-msgstr "应用的选项与 rebase.autoSquash ä¸å…¼å®¹ã€‚考虑加上 --no-autosquash"
-
-#: builtin/rebase.c
msgid ""
"apply options are incompatible with rebase.rebaseMerges. Consider adding --"
"no-rebase-merges"
@@ -12886,6 +13131,10 @@ msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<log 选项>] [<引用>]"
#: builtin/reflog.c
+msgid "git reflog list"
+msgstr "git reflog list"
+
+#: builtin/reflog.c
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -12914,6 +13163,11 @@ msgstr "git reflog exists <引用>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "给 '--%2$s' 的时间戳 '%1$s' 无效"
+#: builtin/reflog.c sequencer.c
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s 䏿ޥå—傿•°ï¼š'%s'"
+
#: builtin/reflog.c
msgid "do not actually prune any entries"
msgstr "ä¸è¦å®žé™…清除任何æ¡ç›®"
@@ -12976,6 +13230,39 @@ msgstr "未指定è¦åˆ é™¤çš„引用日志"
msgid "invalid ref format: %s"
msgstr "无效的引用格å¼ï¼š%s"
+#: builtin/refs.c
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<æ ¼å¼> [--dry-run]"
+
+#: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+#: builtin/refs.c
+msgid "specify the reference format to convert to"
+msgstr "指定è¦è½¬æ¢çš„引用格å¼"
+
+#: builtin/refs.c
+msgid "perform a non-destructive dry-run"
+msgstr "进行éžç ´å性的试è¿è¡Œï¼ˆdry-run)"
+
+#: builtin/refs.c
+msgid "missing --ref-format=<format>"
+msgstr "缺少 --ref-format=<æ ¼å¼>"
+
+#: builtin/refs.c
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "仓库已使用 '%s' æ ¼å¼"
+
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "å¯ç”¨ä¸¥æ ¼çš„æ£€æŸ¥"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' 䏿ޥå—任何傿•°"
+
#: builtin/remote.c
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
@@ -13073,8 +13360,8 @@ msgstr ""
#: builtin/remote.c
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "未知的镜åƒå‚数:%s"
+msgid "unknown --mirror argument: %s"
+msgstr "未知的 --mirror 傿•°ï¼š%s"
#: builtin/remote.c
msgid "fetch the remote branches"
@@ -13202,8 +13489,8 @@ msgid ""
msgid_plural ""
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:"
-msgstr[0] "注æ„:ref/remotes 层级之外的一个分支未被移除。è¦åˆ é™¤å®ƒï¼Œä½¿ç”¨ï¼š"
-msgstr[1] "注æ„:ref/remotes 层级之外的一些分支未被移除。è¦åˆ é™¤å®ƒä»¬ï¼Œä½¿ç”¨ï¼š"
+msgstr[0] "注æ„:refs/remotes/ 层级之外的一个分支未被移除。è¦åˆ é™¤å®ƒï¼Œä½¿ç”¨ï¼š"
+msgstr[1] "注æ„:refs/remotes/ 层级之外的一些分支未被移除。è¦åˆ é™¤å®ƒä»¬ï¼Œä½¿ç”¨ï¼š"
#: builtin/remote.c
#, c-format
@@ -13320,10 +13607,6 @@ msgstr "* 远程 %s"
msgid " Fetch URL: %s"
msgstr " 获å–地å€ï¼š%s"
-#: builtin/remote.c
-msgid "(no URL)"
-msgstr "(æ—  URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -13334,6 +13617,10 @@ msgid " Push URL: %s"
msgstr " 推é€åœ°å€ï¼š%s"
#: builtin/remote.c
+msgid "(no URL)"
+msgstr "(æ—  URL)"
+
+#: builtin/remote.c
#, c-format
msgid " HEAD branch: %s"
msgstr " HEAD 分支:%s"
@@ -13470,11 +13757,6 @@ msgid "return all URLs"
msgstr "返回所有 URL 地å€"
#: builtin/remote.c
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "没有给远程仓库 '%s' 设定 URL"
-
-#: builtin/remote.c
msgid "manipulate push URLs"
msgstr "æ“ä½œæŽ¨é€ URLS"
@@ -13525,6 +13807,10 @@ msgid "could not start pack-objects to repack promisor objects"
msgstr "无法开始 pack-objects æ¥é‡æ–°æ‰“包 promisor 对象"
#: builtin/repack.c
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "无法将承诺者对象æä¾›ç»™ pack-objects"
+
+#: builtin/repack.c
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr "repack:期望æ¥è‡ª pack-objects 的完整å六进制对象 ID。"
@@ -13562,6 +13848,11 @@ msgid "could not remove stale bitmap: %s"
msgstr "无法删除过期的ä½å›¾ï¼š %s"
#: builtin/repack.c
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "包å‰ç¼€ %s 没有以对象目录 %s 开始"
+
+#: builtin/repack.c
msgid "pack everything in a single pack"
msgstr "所有内容打包到一个包文件中"
@@ -13662,17 +13953,21 @@ msgid "pack prefix to store a pack containing pruned objects"
msgstr "储存被清除的对象的包的å‰ç¼€"
#: builtin/repack.c
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "储存被过滤的对象的包的å‰ç¼€"
+
+#: builtin/repack.c
msgid "cannot delete packs in a precious-objects repo"
msgstr "ä¸èƒ½åˆ é™¤çå“仓库中的打包文件"
#: builtin/repack.c
-msgid "Nothing new to pack."
-msgstr "æ²¡æœ‰æ–°çš„è¦æ‰“包。"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "选项 '%s' åªèƒ½å’Œ '%s' æ­é…使用"
#: builtin/repack.c
-#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "包å‰ç¼€ %s 没有以对象目录 .%s 开始"
+msgid "Nothing new to pack."
+msgstr "æ²¡æœ‰æ–°çš„è¦æ‰“包。"
#: builtin/repack.c
#, c-format
@@ -13925,6 +14220,87 @@ msgstr "--convert-graft-file ä¸å¸¦å‚æ•°"
msgid "only one pattern can be given with -l"
msgstr "åªèƒ½ä¸º -l æä¾›ä¸€ä¸ªæ¨¡å¼"
+#: builtin/replay.c
+msgid "need some commits to replay"
+msgstr "需è¦ä¸€äº›æäº¤æ¥é‡æ”¾"
+
+#: builtin/replay.c
+msgid "--onto and --advance are incompatible"
+msgstr "--onto å’Œ --advance ä¸å…¼å®¹"
+
+#: builtin/replay.c
+msgid "all positive revisions given must be references"
+msgstr "æä¾›çš„æ‰€æœ‰æ­£å‘版本必须为引用"
+
+#: builtin/replay.c
+msgid "argument to --advance must be a reference"
+msgstr "--advance çš„å‚æ•°å¿…须是引用"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr "ä¸èƒ½ä½¿ç”¨å¤šä¸ªæºæŽ¨è¿›ç›®æ ‡ï¼Œå› ä¸ºæ— æ³•明确如何排åº"
+
+#: builtin/replay.c
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr "ä¸èƒ½éšå¼åœ°ç¡®å®šè¿™æ˜¯ --advance 还是 --onto çš„æ“作"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr "ä¸èƒ½ä½¿ç”¨å¤šä¸ªæºåˆ†æ”¯æŽ¨è¿›ç›®æ ‡ï¼Œå› ä¸ºæ— æ³•明确如何排åº"
+
+#: builtin/replay.c
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "ä¸èƒ½éšå¼åœ°ç¡®å®š --onto 正确的基线"
+
+#: builtin/replay.c
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(试验中ï¼ï¼‰git replay ([--contained] --onto <新基线> | --advance <分支>) <版"
+"本范围>..."
+
+#: builtin/replay.c
+msgid "make replay advance given branch"
+msgstr "釿”¾æ—¶æ¼”进给定的分支"
+
+#: builtin/replay.c
+msgid "replay onto given commit"
+msgstr "釿”¾åˆ°ç»™å®šæäº¤"
+
+#: builtin/replay.c
+msgid "advance all branches contained in revision-range"
+msgstr "演进版本范围中包å«çš„æ‰€æœ‰åˆ†æ”¯"
+
+#: builtin/replay.c
+msgid "option --onto or --advance is mandatory"
+msgstr "选项 --onto 或 --advance 必须指定其一"
+
+#: builtin/replay.c
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr ""
+"一些版本é历选项将被覆盖,如 'struct rev_info' 中的 '%s' ä½å°†è¢«å¼ºåˆ¶è®¾å®š"
+
+#: builtin/replay.c
+msgid "error preparing revisions"
+msgstr "准备版本时错误"
+
+#: builtin/replay.c
+msgid "replaying down to root commit is not supported yet!"
+msgstr "ç›®å‰è¿˜ä¸æ”¯æŒé‡æ”¾åˆ°æ ¹æäº¤ï¼"
+
+#: builtin/replay.c
+msgid "replaying merge commits is not supported yet!"
+msgstr "ç›®å‰è¿˜ä¸æ”¯æŒé‡æ”¾åˆ°åˆå¹¶æäº¤ï¼"
+
#: builtin/rerere.c
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
@@ -14180,27 +14556,28 @@ msgid "--prefix requires an argument"
msgstr "--prefix 需è¦ä¸€ä¸ªå‚æ•°"
#: builtin/rev-parse.c
+msgid "no object format specified"
+msgstr "未指定对象格å¼"
+
+#: builtin/rev-parse.c
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "䏿”¯æŒçš„对象格å¼ï¼š'%s'"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "未知的 --abbrev-ref 模å¼ï¼š%s"
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden ä¸èƒ½ä¸Ž --branches 一起使用"
-
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden ä¸èƒ½ä¸Ž --tags 一起使用"
-
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden ä¸èƒ½ä¸Ž --remotes 一起使用"
-
#: builtin/rev-parse.c setup.c
msgid "this operation must be run in a work tree"
msgstr "该æ“作必须在一个工作区中è¿è¡Œ"
#: builtin/rev-parse.c
+msgid "Could not read the index"
+msgstr "ä¸èƒ½è¯»å–索引"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "未知的 --show-object-format 模å¼ï¼š%s"
@@ -14291,8 +14668,8 @@ msgid "allow commits with empty messages"
msgstr "å…许æäº¤è¯´æ˜Žä¸ºç©º"
#: builtin/revert.c
-msgid "keep redundant, empty commits"
-msgstr "ä¿æŒå¤šä½™çš„ã€ç©ºçš„æäº¤"
+msgid "deprecated: use --empty=keep instead"
+msgstr "已弃用:å–而代之使用 --empty=keep"
#: builtin/revert.c
msgid "use the 'reference' format to refer to commits"
@@ -14625,25 +15002,51 @@ msgstr "未知的哈希算法"
#: builtin/show-ref.c
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<模å¼>...]"
+
+#: builtin/show-ref.c
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<模å¼>...]"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<引用>...]"
#: builtin/show-ref.c
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<模å¼>]"
#: builtin/show-ref.c
-msgid "only show tags (can be combined with heads)"
-msgstr "åªæ˜¾ç¤ºæ ‡ç­¾ï¼ˆå¯ä»¥å’Œå¤´å…±ç”¨ï¼‰"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <引用>"
+
+#: builtin/show-ref.c
+msgid "reference does not exist"
+msgstr "引用ä¸å­˜åœ¨"
+
+#: builtin/show-ref.c
+msgid "failed to look up reference"
+msgstr "无法找到引用"
+
+#: builtin/show-ref.c
+msgid "only show tags (can be combined with --branches)"
+msgstr "仅显示标签(å¯ä¸Ž --branches 组åˆä½¿ç”¨ï¼‰"
#: builtin/show-ref.c
-msgid "only show heads (can be combined with tags)"
-msgstr "åªæ˜¾ç¤ºå¤´ï¼ˆå¯ä»¥å’Œæ ‡ç­¾å…±ç”¨ï¼‰"
+msgid "only show branches (can be combined with --tags)"
+msgstr "仅显示分支(å¯ä¸Ž --tags 组åˆä½¿ç”¨ï¼‰"
+
+#: builtin/show-ref.c
+msgid "check for reference existence without resolving"
+msgstr "检查引用是å¦å­˜åœ¨ä½†ä¸è§£æž"
#: builtin/show-ref.c
msgid "stricter reference checking, requires exact ref path"
@@ -14702,6 +15105,11 @@ msgid "failed to create directory for sparse-checkout file"
msgstr "æ— æ³•ä¸ºç¨€ç–æ£€å‡ºæ–‡ä»¶åˆ›å»ºç›®å½•"
#: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "ä¸èƒ½ fdopen %s"
+
+#: builtin/sparse-checkout.c
msgid "failed to initialize worktree config"
msgstr "无法åˆå§‹åŒ–工作树é…ç½®"
@@ -14717,7 +15125,7 @@ msgstr "åˆå§‹åŒ–ç¨€ç–æ£€å‡ºä¸ºé”¥å½¢æ¨¡å¼"
msgid "toggle the use of a sparse index"
msgstr "切æ¢ç¨€ç–索引的使用"
-#: builtin/sparse-checkout.c commit-graph.c midx.c sequencer.c
+#: builtin/sparse-checkout.c commit-graph.c midx-write.c sequencer.c
#, c-format
msgid "unable to create leading directories of %s"
msgstr "ä¸èƒ½ä¸º %s 创建先导目录"
@@ -15250,8 +15658,8 @@ msgstr "ä¸èƒ½ä»Ž '%s' 创建哈希对象"
#: builtin/submodule--helper.c
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "æ„å¤–çš„æ¨¡å¼ %o\n"
+msgid "unexpected mode %o"
+msgstr "æ„å¤–çš„æ¨¡å¼ %o"
#: builtin/submodule--helper.c
msgid "use the commit stored in the index instead of the submodule HEAD"
@@ -15386,20 +15794,20 @@ msgstr "ä¸èƒ½è¯†åˆ« submodule.alternateErrorStrategy çš„å–值 '%s'"
msgid "Value '%s' for submodule.alternateLocation is not recognized"
msgstr "ä¸èƒ½è¯†åˆ« submodule.alternateLocation çš„å–值 '%s'"
-#: builtin/submodule--helper.c
+#: builtin/submodule--helper.c submodule.c
#, c-format
msgid "refusing to create/use '%s' in another submodule's git dir"
msgstr "æ‹’ç»åœ¨å¦ä¸€ä¸ªå­æ¨¡ç»„çš„ git 目录中创建/使用 '%s'"
#: builtin/submodule--helper.c
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "无法克隆 '%s' åˆ°å­æ¨¡ç»„路径 '%s'"
+msgid "directory not empty: '%s'"
+msgstr "目录éžç©ºï¼š'%s'"
#: builtin/submodule--helper.c
#, c-format
-msgid "directory not empty: '%s'"
-msgstr "目录éžç©ºï¼š'%s'"
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "无法克隆 '%s' åˆ°å­æ¨¡ç»„路径 '%s'"
#: builtin/submodule--helper.c
#, c-format
@@ -15631,6 +16039,10 @@ msgstr ""
"shallow] [--reference <仓库>] [--recursive] [--[no-]single-branch] [--] [<路"
"径>...]"
+#: builtin/submodule--helper.c submodule.c
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "无法将 HEAD è§£æžä¸ºæœ‰æ•ˆå¼•用。"
+
#: builtin/submodule--helper.c
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<选项>] [<路径>...]"
@@ -15836,9 +16248,11 @@ msgstr "更新的原因"
#: builtin/tag.c
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
-"git tag [-a | -s | -u <ç§é’¥ ID>] [-f] [-m <消æ¯> | -F <文件>] [-e]\n"
+"git tag [-a | -s | -u <ç§é’¥ id>] [-f] [-m <消æ¯> | -F <文件>] [-e]\n"
+" [(--trailer <令牌>[(=|:)<值>])...]\n"
" <标签å> [<æäº¤> | <对象>]"
#: builtin/tag.c
@@ -15877,12 +16291,12 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
"输入一个标签说明:\n"
" %s\n"
-"以 '%c' 开头的行将被忽略。\n"
+"以 '%s' 开头的行将被忽略。\n"
#: builtin/tag.c
#, c-format
@@ -15890,13 +16304,13 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be kept; you may remove them yourself if you "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
"输入一个标签说明:\n"
" %s\n"
-"以 '%c' 开头的行将被ä¿ç•™ï¼Œå¦‚果您愿æ„也å¯ä»¥åˆ é™¤å®ƒä»¬ã€‚\n"
+"以 '%s' 开头的行将被ä¿ç•™ï¼Œå¦‚果您愿æ„也å¯ä»¥åˆ é™¤å®ƒä»¬ã€‚\n"
#: builtin/tag.c
msgid "unable to sign the tag"
@@ -16005,6 +16419,10 @@ msgid "print only tags of the object"
msgstr "åªæ‰“å°æŒ‡å‘该对象的标签"
#: builtin/tag.c
+msgid "could not start 'git column'"
+msgstr "无法å¯åЍ 'git column'"
+
+#: builtin/tag.c
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "'%s' 选项åªå…许用在列表显示模å¼"
@@ -16207,6 +16625,10 @@ msgid "write index in this format"
msgstr "ä»¥è¿™ç§æ ¼å¼å†™å…¥ç´¢å¼•区"
#: builtin/update-index.c
+msgid "report on-disk index format version"
+msgstr "报告ç£ç›˜ç´¢å¼•æ ¼å¼çš„版本"
+
+#: builtin/update-index.c
msgid "enable or disable split index"
msgstr "å¯ç”¨æˆ–ç¦ç”¨ç´¢å¼•拆分"
@@ -16239,6 +16661,16 @@ msgid "clear fsmonitor valid bit"
msgstr "清除 fsmonitor 有效ä½"
#: builtin/update-index.c
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#: builtin/update-index.c
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "索引版本:从 %d 设置为 %d"
+
+#: builtin/update-index.c
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -16295,12 +16727,12 @@ msgid "fsmonitor disabled"
msgstr "fsmonitor 被ç¦ç”¨"
#: builtin/update-ref.c
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<选项>] -d <引用å> [<旧值>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<选项>] -d <引用å> [<旧对象>]"
#: builtin/update-ref.c
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr "git update-ref [<选项>] <引用å> <新值> [<旧值>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<选项>] <引用å> <新对象> [<旧对象>]"
#: builtin/update-ref.c
msgid "git update-ref [<options>] --stdin [-z]"
@@ -16425,30 +16857,30 @@ msgstr "没有å¯ç”¨çš„æºåˆ†æ”¯ï¼Œå°†åŸºäºŽ '--orphan' 选项进行推断"
#: builtin/worktree.c
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"分支(没有æäº¤çš„分支)的工作区,你å¯ä»¥ä½¿ç”¨\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"
+"If you meant to create a worktree containing a new unborn 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"
+"分支(没有æäº¤çš„分支)的工作区,你å¯ä»¥ä½¿ç”¨\n"
+"选项 --orphan æ¥æ‰§è¡Œæ­¤æ“作:\n"
"\n"
" git worktree add --orphan %s\n"
@@ -16519,6 +16951,11 @@ msgstr "åˆå§‹åŒ–"
#: builtin/worktree.c
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "无法找到已创建的工作树 '%s'"
+
+#: builtin/worktree.c
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "准备工作区(新分支 '%s')"
@@ -16556,15 +16993,10 @@ msgstr ""
#: 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"
+"present, stopping; use 'add -f' to override 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' ä¸èƒ½åŒæ—¶ä½¿ç”¨"
+"尽管已é…置远程仓库,但ä¸å­˜åœ¨ä»»ä½•本地的或远程的引用,æ“作终止。\n"
+"请先使用 'add -f' æ¥è¦†ç›–或拉å–一个远程仓库"
#: builtin/worktree.c
msgid "checkout <branch> even if already checked out in other worktree"
@@ -16579,8 +17011,8 @@ msgid "create or reset a branch"
msgstr "创建或é‡ç½®ä¸€ä¸ªåˆ†æ”¯"
#: builtin/worktree.c
-msgid "create unborn/orphaned branch"
-msgstr "创建一个尚未诞生的/孤立的分支"
+msgid "create unborn branch"
+msgstr "创建一个尚未诞生的分支"
#: builtin/worktree.c
msgid "populate the new working tree"
@@ -16609,12 +17041,8 @@ 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 "<æäº¤å·>"
+msgid "option '%s' and commit-ish cannot be used together"
+msgstr "选项 '%s' å’Œæäº¤å·ä¸èƒ½åŒæ—¶ä½¿ç”¨"
#: builtin/worktree.c
msgid "added with --lock"
@@ -16869,10 +17297,6 @@ msgid "Repository lacks these prerequisite commits:"
msgstr "仓库中缺少这些必备的æäº¤ï¼š"
#: bundle.c
-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"
@@ -16952,6 +17376,11 @@ msgstr "ç»ˆæ­¢å— ID 比预期更早出现"
#: chunk-format.c
#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "å— id %<PRIx32> 未 %d 字节对é½"
+
+#: chunk-format.c
+#, c-format
msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
msgstr "䏿­£ç¡®çš„å—åç§» %<PRIx64> å’Œ %<PRIx64>"
@@ -17019,8 +17448,8 @@ msgid "Move objects and refs by archive"
msgstr "通过归档移动对象和引用"
#: command-list.h
-msgid "Provide content or type and size information for repository objects"
-msgstr "æä¾›ä»“库对象的内容ã€ç±»åž‹æˆ–大å°"
+msgid "Provide contents or details of repository objects"
+msgstr "æä¾›ä»“库对象的内容或详情"
#: command-list.h
msgid "Display gitattributes information"
@@ -17388,6 +17817,10 @@ msgid "Manage reflog information"
msgstr "ç®¡ç† reflog ä¿¡æ¯"
#: command-list.h
+msgid "Low-level access to refs"
+msgstr "对引用的低级访问"
+
+#: command-list.h
msgid "Manage set of tracked repositories"
msgstr "管ç†å·²è·Ÿè¸ªä»“库"
@@ -17400,6 +17833,10 @@ msgid "Create, list, delete refs to replace objects"
msgstr "创建ã€åˆ—出ã€åˆ é™¤å¯¹è±¡æ›¿æ¢å¼•用"
#: command-list.h
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr "è¯•éªŒä¸­ï¼šåŸºäºŽä¸€ä¸ªæ–°åŸºçº¿é‡æ”¾æäº¤ï¼ŒåŒæ ·é€‚用于纯仓库"
+
+#: command-list.h
msgid "Generates a summary of pending changes"
msgstr "生æˆå¾…定更改的摘è¦"
@@ -17561,7 +17998,7 @@ msgid "Display version information about Git"
msgstr "显示关于 Git 的版本信æ¯"
#: command-list.h
-msgid "Show logs with difference each commit introduces"
+msgid "Show logs with differences each commit introduces"
msgstr "显示æ¯ä¸€ä¸ªæäº¤å¼•入的差异日志"
#: command-list.h
@@ -17714,35 +18151,89 @@ msgstr "一个管ç†å¤§åž‹ Git 仓库的工具"
#: commit-graph.c
msgid "commit-graph file is too small"
-msgstr "æäº¤å›¾å½¢æ–‡ä»¶å¤ªå°"
+msgstr "æäº¤å›¾æ–‡ä»¶å¤ªå°"
+
+#: commit-graph.c
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "æäº¤å›¾ä¸­å¯¹è±¡ ID 的扇出å—大å°é”™è¯¯"
+
+#: commit-graph.c
+msgid "commit-graph fanout values out of order"
+msgstr "æäº¤å›¾çš„æ‰‡å‡ºå€¼å¤±åº"
+
+#: commit-graph.c
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "æäº¤å›¾çš„对象 ID 查询å—大å°é”™è¯¯"
+
+#: commit-graph.c
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "æäº¤å›¾çš„æäº¤æ•°æ®å—大å°é”™è¯¯"
+
+#: commit-graph.c
+msgid "commit-graph generations chunk is wrong size"
+msgstr "æäº¤å›¾çš„世代å—大å°é”™è¯¯"
+
+#: commit-graph.c
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "æäº¤å›¾çš„å˜æ›´è·¯å¾„的索引å—太å°"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr "忽略æäº¤å›¾æ–‡ä»¶ä¸­è¿‡å°çš„æ›´æ”¹è·¯å¾„å—(%<PRIuMAX> < %<PRIuMAX>)"
#: commit-graph.c
#, c-format
msgid "commit-graph signature %X does not match signature %X"
-msgstr "æäº¤å›¾å½¢ç­¾å %X 和签å %X ä¸åŒ¹é…"
+msgstr "æäº¤å›¾ç­¾å %X 和签å %X ä¸åŒ¹é…"
#: commit-graph.c
#, c-format
msgid "commit-graph version %X does not match version %X"
-msgstr "æäº¤å›¾å½¢ç‰ˆæœ¬ %X 和版本 %X ä¸åŒ¹é…"
+msgstr "æäº¤å›¾ç‰ˆæœ¬ %X 和版本 %X ä¸åŒ¹é…"
#: commit-graph.c
#, c-format
msgid "commit-graph hash version %X does not match version %X"
-msgstr "æäº¤å›¾å½¢å“ˆå¸Œç‰ˆæœ¬ %X 和版本 %X ä¸åŒ¹é…"
+msgstr "æäº¤å›¾å“ˆå¸Œç‰ˆæœ¬ %X 和版本 %X ä¸åŒ¹é…"
#: commit-graph.c
#, c-format
msgid "commit-graph file is too small to hold %u chunks"
-msgstr "æäº¤å›¾å½¢æ–‡ä»¶å¤ªå°ï¼Œå®¹ä¸ä¸‹ %u 个å—"
+msgstr "æäº¤å›¾æ–‡ä»¶å¤ªå°ï¼Œå®¹ä¸ä¸‹ %u 个å—"
+
+#: commit-graph.c
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr "æäº¤å›¾æ‰€éœ€çš„对象 ID 扇出å—缺失或æŸå"
+
+#: commit-graph.c
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "æäº¤å›¾æ‰€éœ€çš„对象 ID 查询å—缺失或æŸå"
+
+#: commit-graph.c
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr "æäº¤å›¾æ‰€éœ€çš„æäº¤æ•°æ®å—缺失或æŸå"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr "由于ä¸å…¼å®¹çš„设置,正在ç¦ç”¨æäº¤å›¾å±‚ '%s' 的布隆过滤器"
#: commit-graph.c
msgid "commit-graph has no base graphs chunk"
-msgstr "æäº¤å›¾å½¢æ²¡æœ‰åŸºç¡€å›¾å½¢å—"
+msgstr "æäº¤å›¾æ²¡æœ‰åŸºç¡€å›¾å½¢å—"
+
+#: commit-graph.c
+msgid "commit-graph base graphs chunk is too small"
+msgstr "æäº¤å›¾çš„基础图形å—过å°"
#: commit-graph.c
msgid "commit-graph chain does not match"
-msgstr "æäº¤å›¾å½¢é“¾ä¸åŒ¹é…"
+msgstr "æäº¤å›¾é“¾ä¸åŒ¹é…"
#: commit-graph.c
#, c-format
@@ -17750,17 +18241,21 @@ msgid "commit count in base graph too high: %<PRIuMAX>"
msgstr "基础图形中的æäº¤æ•°é‡è¿‡é«˜ï¼š%<PRIuMAX>"
#: commit-graph.c
+msgid "commit-graph chain file too small"
+msgstr "æäº¤å›¾é“¾æ–‡ä»¶å¤ªå°"
+
+#: commit-graph.c
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
-msgstr "无效的æäº¤å›¾å½¢é“¾ï¼šè¡Œ '%s' 䏿˜¯ä¸€ä¸ªå“ˆå¸Œå€¼"
+msgstr "无效的æäº¤å›¾é“¾ï¼šè¡Œ '%s' 䏿˜¯ä¸€ä¸ªå“ˆå¸Œå€¼"
#: commit-graph.c
msgid "unable to find all commit-graph files"
-msgstr "无法找到所有æäº¤å›¾å½¢æ–‡ä»¶"
+msgstr "无法找到所有æäº¤å›¾æ–‡ä»¶"
#: commit-graph.c
msgid "invalid commit position. commit-graph is likely corrupt"
-msgstr "无效的æäº¤ä½ç½®ã€‚æäº¤å›¾å½¢å¯èƒ½å·²æŸå"
+msgstr "无效的æäº¤ä½ç½®ã€‚æäº¤å›¾å¯èƒ½å·²æŸå"
#: commit-graph.c
#, c-format
@@ -17772,6 +18267,14 @@ msgid "commit-graph requires overflow generation data but has none"
msgstr "æäº¤å›¾éœ€è¦æº¢å‡ºä¸–代数æ®ï¼Œä½†æ˜¯æ²¡æœ‰"
#: commit-graph.c
+msgid "commit-graph overflow generation data is too small"
+msgstr "æäº¤å›¾æº¢å‡ºä¸–代数æ®è¿‡å°"
+
+#: commit-graph.c
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "æäº¤å›¾é¢å¤–边的指针越界"
+
+#: commit-graph.c
msgid "Loading known commits in commit graph"
msgstr "正在加载æäº¤å›¾ä¸­çš„已知æäº¤"
@@ -17832,7 +18335,7 @@ msgstr "无法写入正确数é‡çš„基础图形 ID"
msgid "unable to create temporary graph layer"
msgstr "无法创建临时图层"
-#: commit-graph.c
+#: commit-graph.c midx-write.c
#, c-format
msgid "unable to adjust shared permissions for '%s'"
msgstr "无法为 '%s' 调整共享æƒé™"
@@ -17846,26 +18349,26 @@ msgstr[1] "正在用 %d 步写出æäº¤å›¾"
#: commit-graph.c
msgid "unable to open commit-graph chain file"
-msgstr "无法打开æäº¤å›¾å½¢é“¾æ–‡ä»¶"
+msgstr "无法打开æäº¤å›¾é“¾æ–‡ä»¶"
#: commit-graph.c
msgid "failed to rename base commit-graph file"
-msgstr "无法é‡å‘½å基础æäº¤å›¾å½¢æ–‡ä»¶"
+msgstr "无法é‡å‘½å基础æäº¤å›¾æ–‡ä»¶"
#: commit-graph.c
msgid "failed to rename temporary commit-graph file"
-msgstr "无法é‡å‘½å临时æäº¤å›¾å½¢æ–‡ä»¶"
+msgstr "无法é‡å‘½å临时æäº¤å›¾æ–‡ä»¶"
#: commit-graph.c
#, c-format
msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
msgstr ""
-"无法åˆå¹¶æäº¤å›¾å½¢ï¼Œæ€»å…±å·²ç´¯åŠ æäº¤æ•°ï¼š%<PRIuMAX>,当å‰å¾…累加æäº¤æ•°ï¼š%<PRIuMAX>"
+"无法åˆå¹¶æäº¤å›¾ï¼Œæ€»å…±å·²ç´¯åŠ æäº¤æ•°ï¼š%<PRIuMAX>,当å‰å¾…累加æäº¤æ•°ï¼š%<PRIuMAX>"
#: commit-graph.c
#, c-format
msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
-msgstr "无法åˆå¹¶æäº¤å›¾å½¢ %s, æäº¤è¿‡å¤šï¼š%<PRIuMAX>"
+msgstr "无法åˆå¹¶æäº¤å›¾ %s, æäº¤è¿‡å¤šï¼š%<PRIuMAX>"
#: commit-graph.c
msgid "Scanning merged commits"
@@ -17873,13 +18376,20 @@ msgstr "正在扫æåˆå¹¶æäº¤"
#: commit-graph.c
msgid "Merging commit-graph"
-msgstr "正在åˆå¹¶æäº¤å›¾å½¢"
+msgstr "正在åˆå¹¶æäº¤å›¾"
#: commit-graph.c
msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
msgstr "æ­£å°è¯•写æäº¤å›¾ï¼Œä½†æ˜¯ 'core.commitGraph' 被ç¦ç”¨"
#: commit-graph.c
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
+msgstr "å°è¯•写入æäº¤å›¾ï¼Œä½†ä¸æ”¯æŒ 'commitGraph.changedPathsVersion' (%d)"
+
+#: commit-graph.c
msgid "too many commits to write graph"
msgstr "æäº¤å¤ªå¤šä¸èƒ½ç”»å›¾"
@@ -17890,69 +18400,69 @@ msgstr "æäº¤å›¾æ–‡ä»¶çš„æ ¡éªŒç é”™è¯¯ï¼Œå¯èƒ½å·²ç»æŸå"
#: commit-graph.c
#, c-format
msgid "commit-graph has incorrect OID order: %s then %s"
-msgstr "æäº¤å›¾å½¢çš„对象 ID 顺åºä¸æ­£ç¡®ï¼š%s ç„¶åŽ %s"
+msgstr "æäº¤å›¾çš„对象 ID 顺åºä¸æ­£ç¡®ï¼š%s ç„¶åŽ %s"
#: commit-graph.c
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
-msgstr "æäº¤å›¾å½¢æœ‰ä¸æ­£ç¡®çš„æ‰‡å‡ºå€¼ï¼šfanout[%d] = %u != %u"
+msgstr "æäº¤å›¾æœ‰ä¸æ­£ç¡®çš„æ‰‡å‡ºå€¼ï¼šfanout[%d] = %u != %u"
#: commit-graph.c
#, c-format
msgid "failed to parse commit %s from commit-graph"
-msgstr "无法从æäº¤å›¾å½¢ä¸­è§£æžæäº¤ %s"
+msgstr "无法从æäº¤å›¾ä¸­è§£æžæäº¤ %s"
#: commit-graph.c
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
-msgstr "无法从æäº¤å›¾å½¢çš„å¯¹è±¡åº“ä¸­è§£æžæäº¤ %s"
+msgstr "无法从æäº¤å›¾çš„å¯¹è±¡åº“ä¸­è§£æžæäº¤ %s"
#: commit-graph.c
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
-msgstr "æäº¤å›¾å½¢ä¸­çš„æäº¤ %s 的根树对象 ID 是 %s != %s"
+msgstr "æäº¤å›¾ä¸­çš„æäº¤ %s 的根树对象 ID 是 %s != %s"
#: commit-graph.c
#, c-format
msgid "commit-graph parent list for commit %s is too long"
-msgstr "æäº¤ %s çš„æäº¤å›¾å½¢çˆ¶æäº¤åˆ—表太长了"
+msgstr "æäº¤ %s çš„æäº¤å›¾çˆ¶æäº¤åˆ—表太长了"
#: commit-graph.c
#, c-format
msgid "commit-graph parent for %s is %s != %s"
-msgstr "%s çš„æäº¤å›¾å½¢çˆ¶æäº¤æ˜¯ %s != %s"
+msgstr "%s çš„æäº¤å›¾çˆ¶æäº¤æ˜¯ %s != %s"
#: commit-graph.c
#, c-format
msgid "commit-graph parent list for commit %s terminates early"
-msgstr "æäº¤ %s çš„æäº¤å›¾å½¢çˆ¶æäº¤åˆ—表过早终止"
+msgstr "æäº¤ %s çš„æäº¤å›¾çˆ¶æäº¤åˆ—表过早终止"
#: commit-graph.c
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr "æäº¤å›¾å½¢ä¸­æäº¤ %s çš„ä¸–ä»£å·æ˜¯é›¶ï¼Œä½†å…¶å®ƒåœ°æ–¹éžé›¶"
-
-#: commit-graph.c
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr "æäº¤å›¾å½¢ä¸­æäº¤ %s 的世代å·éžé›¶ï¼Œä½†å…¶å®ƒåœ°æ–¹æ˜¯é›¶"
+msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
+msgstr "æäº¤å›¾ä¸­çš„æäº¤ %s çš„ä¸–ä»£å·æ˜¯ %<PRIuMAX> < %<PRIuMAX>"
#: commit-graph.c
#, c-format
-msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
-msgstr "æäº¤å›¾å½¢ä¸­çš„æäº¤ %s çš„ä¸–ä»£å·æ˜¯ %<PRIuMAX> < %<PRIuMAX>"
+msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
+msgstr "æäº¤å›¾ä¸­æäº¤ %s çš„æäº¤æ—¥æœŸæ˜¯ %<PRIuMAX> != %<PRIuMAX>"
#: commit-graph.c
#, c-format
-msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
-msgstr "æäº¤å›¾å½¢ä¸­æäº¤ %s çš„æäº¤æ—¥æœŸæ˜¯ %<PRIuMAX> != %<PRIuMAX>"
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr "æäº¤å›¾å…·æœ‰é›¶å’Œéžé›¶çš„世代(例如:æäº¤ '%s' å’Œ '%s')"
#: commit-graph.c
msgid "Verifying commits in commit graph"
msgstr "正在校验æäº¤å›¾ä¸­çš„æäº¤"
+#: commit-reach.c sequencer.c
+#, c-format
+msgid "could not parse commit %s"
+msgstr "ä¸èƒ½è§£æžæäº¤ %s"
+
#: commit.c
#, c-format
msgid "%s %s is not a commit!"
@@ -17980,6 +18490,11 @@ msgstr ""
#: commit.c
#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr "æäº¤ %s 存在于æäº¤å›¾ä¸­ï¼Œä½†ä¸å­˜åœ¨äºŽå¯¹è±¡æ•°æ®åº“中"
+
+#: commit.c
+#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr "æäº¤ %s 有一个éžå¯ä¿¡çš„声称æ¥è‡ª %s çš„ GPG ç­¾å。"
@@ -18475,8 +18990,14 @@ msgid "bad zlib compression level %d"
msgstr "错误的 zlib 压缩级别 %d"
#: config.c
-msgid "core.commentChar should only be one ASCII character"
-msgstr "core.commentChar 应该是一个 ASCII ç¼–ç çš„字符"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s ä¸èƒ½åŒ…嫿¢è¡Œç¬¦"
+
+#: config.c
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s 必须至少有一个字符"
#: config.c
#, c-format
@@ -18522,11 +19043,6 @@ msgid "unable to resolve config blob '%s'"
msgstr "ä¸èƒ½è§£æžé…置对象 '%s'"
#: config.c
-#, c-format
-msgid "failed to parse %s"
-msgstr "æ— æ³•è§£æž %s"
-
-#: config.c
msgid "unable to parse command-line config"
msgstr "无法解æžå‘½ä»¤è¡Œä¸­çš„é…ç½®"
@@ -18571,6 +19087,11 @@ msgstr "无法写入新的é…置文件 %s"
#: config.c
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "ä¸å…许多行注释:'%s'"
+
+#: config.c
+#, c-format
msgid "could not lock config file %s"
msgstr "ä¸èƒ½é”定é…置文件 %s"
@@ -19094,10 +19615,6 @@ msgid "--merge-base does not work with ranges"
msgstr "--merge-base ä¸é€‚用于范围"
#: diff-lib.c
-msgid "--merge-base only works with commits"
-msgstr "--merge-base 仅适用于æäº¤"
-
-#: diff-lib.c
msgid "unable to get HEAD"
msgstr "ä¸èƒ½è§£æž HEAD"
@@ -19167,6 +19684,11 @@ msgstr "color-moved-ws:allow-indentation-change ä¸èƒ½ä¸Žå…¶å®ƒç©ºç™½å­—符模
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "é…ç½®å˜é‡ 'diff.submodule' 未知的å–值:'%s'"
+#: diff.c merge-recursive.c transport.c
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "é…ç½® '%s' 未知的å–值:%s"
+
#: diff.c
#, c-format
msgid ""
@@ -19261,13 +19783,6 @@ msgid "invalid mode '%s' in --color-moved-ws"
msgstr "--color-moved-ws ä¸­çš„æ— æ•ˆæ¨¡å¼ '%s' "
#: diff.c
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"diff-algorithm 选项有 \"myers\"ã€\"minimal\"ã€\"patience\" å’Œ \"histogram\""
-
-#: diff.c
#, c-format
msgid "invalid argument to %s"
msgstr "%s çš„å‚æ•°æ— æ•ˆ"
@@ -19324,8 +19839,8 @@ msgid "output only the last line of --stat"
msgstr "åªè¾“出 --stat 的最åŽä¸€è¡Œ"
#: diff.c
-msgid "<param1,param2>..."
-msgstr "<傿•°1,傿•°2>..."
+msgid "<param1>,<param2>..."
+msgstr "<傿•°1>,<傿•°2>..."
#: diff.c
msgid ""
@@ -19337,8 +19852,8 @@ msgid "synonym for --dirstat=cumulative"
msgstr "å’Œ --dirstat=cumulative åŒä¹‰"
#: diff.c
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "是 --dirstat=files,param1,param2... çš„åŒä¹‰è¯"
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "是 --dirstat=files,<傿•°1>,<傿•°2>... çš„åŒä¹‰è¯"
#: diff.c
msgid "warn if changes introduce conflict markers or whitespace errors"
@@ -19561,14 +20076,6 @@ msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "使用 \"histogram diff\" 算法生æˆå·®å¼‚"
#: diff.c
-msgid "<algorithm>"
-msgstr "<算法>"
-
-#: diff.c
-msgid "choose a diff algorithm"
-msgstr "选择一个差异算法"
-
-#: diff.c
msgid "<text>"
msgstr "<文本>"
@@ -20142,16 +20649,19 @@ msgstr "因为缺少 Unix 套接字支æŒï¼Œå¥—接字目录 '%s' 与 fsmonitor ä
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <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"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [\"--"
+"no-lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<路径>]\n"
+" [--work-tree=<路径>] [--namespace=<åç§°>]\n"
" [--config-env=<åç§°>=<环境å˜é‡>] <命令> [<傿•°>]"
#: git.c
@@ -20558,14 +21068,14 @@ msgstr ""
"é…ç½® `git config advice.ignoredHook false` æ¥å…³é—­è¿™æ¡è­¦å‘Šã€‚"
#: http-fetch.c
+msgid "not a git repository"
+msgstr "䏿˜¯ git 仓库"
+
+#: http-fetch.c
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "--packfile çš„å‚æ•°å¿…须是有效的哈希值(得到 '%s')"
-#: http-fetch.c
-msgid "not a git repository"
-msgstr "䏿˜¯ git 仓库"
-
#: http.c
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
@@ -20580,6 +21090,10 @@ msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "䏿”¯æŒå…¬é’¥æ–‡ä»¶é”定,因为 cURL < 7.39.0"
#: http.c
+msgid "Unknown value for http.proactiveauth"
+msgstr "http.proactiveauth 为未知å–值"
+
+#: http.c
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "䏿”¯æŒ CURLSSLOPT_NO_REVOKE,因为 cURL < 7.44.0"
@@ -20599,6 +21113,14 @@ msgid "Could not set SSL backend to '%s': already set"
msgstr "无法将 SSL åŽç«¯è®¾ç½®ä¸º '%s':已ç»è®¾ç½®"
#: http.c
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "æ‹’ç»ä»Ž http.cookiefile '-' è¯»å– cookies"
+
+#: http.c
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "因为 http.cookiefile 为空,忽略 http.savecookies"
+
+#: http.c
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -20641,6 +21163,7 @@ msgstr ""
"\n"
"æ¥è®¾ç½®æ‚¨è´¦å·çš„缺çœèº«ä»½æ ‡è¯†ã€‚\n"
"如果仅在本仓库设置身份标识,则çœç•¥ --global 傿•°ã€‚\n"
+"\n"
#: ident.c
msgid "no email was given and auto-detection is disabled"
@@ -20761,6 +21284,20 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "ä¸èƒ½åˆ›å»º '%s.lock':%s"
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "无法创建临时对象目录"
+
+#: loose.c
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "ä¸èƒ½å†™å…¥æ¾æ•£å¯¹è±¡ç´¢å¼• %s"
+
+#: loose.c
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "æ— æ³•å†™å…¥æ¾æ•£å¯¹è±¡ç´¢å¼• %s"
+
#: ls-refs.c
#, c-format
msgid "unexpected line: '%s'"
@@ -20774,6 +21311,11 @@ msgstr "在 ls-refs 傿•°åŽåº”该有一个 flush 包"
msgid "quoted CRLF detected"
msgstr "检测到被引用的 CRLF"
+#: mem-pool.c strbuf.c wrapper.c
+#, c-format
+msgid "unable to format message: %s"
+msgstr "无法格å¼åŒ–消æ¯ï¼š%s"
+
#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (not checked out)"
@@ -20789,6 +21331,11 @@ msgstr "无法åˆå¹¶å­æ¨¡ç»„ %s (没有åˆå¹¶åŸºçº¿ï¼‰"
msgid "Failed to merge submodule %s (commits not present)"
msgstr "无法åˆå¹¶å­æ¨¡ç»„ %s(æäº¤ä¸å­˜åœ¨ï¼‰"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "错误:无法åˆå¹¶å­æ¨¡ç»„ %s(仓库æŸå)"
+
#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
@@ -20819,14 +21366,15 @@ msgstr ""
"无法åˆå¹¶å­æ¨¡ç»„ %s,但是存在多个å¯èƒ½çš„åˆå¹¶ï¼š\n"
"%s"
-#: merge-ort.c merge-recursive.c
-msgid "Failed to execute internal merge"
-msgstr "无法执行内部åˆå¹¶"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "错误:无法为 %s 执行内部åˆå¹¶"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "Unable to add %s to database"
-msgstr "ä¸èƒ½æ·»åŠ  %s 至对象库"
+msgid "error: unable to add %s to database"
+msgstr "错误:ä¸èƒ½æ·»åŠ  %s 至对象库"
#: merge-ort.c merge-recursive.c
#, c-format
@@ -20924,15 +21472,15 @@ msgstr ""
msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s."
msgstr "冲çªï¼ˆé‡å‘½å/删除):%1$s 在 %3$s 中é‡å‘½å为 %2$s,但在 %4$s 中删除。"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "cannot read object %s"
-msgstr "ä¸èƒ½è¯»å–对象 %s"
+msgid "error: cannot read object %s"
+msgstr "错误:ä¸èƒ½è¯»å–对象 %s"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "object %s is not a blob"
-msgstr "对象 %s 䏿˜¯ä¸€ä¸ªæ•°æ®å¯¹è±¡"
+msgid "error: object %s is not a blob"
+msgstr "错误:对象 %s 䏿˜¯ä¸€ä¸ªæ•°æ®å¯¹è±¡"
#: merge-ort.c
#, c-format
@@ -21088,6 +21636,11 @@ msgstr "ä¸çŸ¥é“å¦‚ä½•å¤„ç† %06o %s '%s'"
#: merge-recursive.c
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "无法åˆå¹¶å­æ¨¡ç»„ %s(仓库æŸå)"
+
+#: merge-recursive.c
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "å­æ¨¡ç»„ %s 快进到如下æäº¤ï¼š"
@@ -21132,6 +21685,15 @@ msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "无法åˆå¹¶å­æ¨¡ç»„ %s (å‘现多个åˆå¹¶ï¼‰"
#: merge-recursive.c
+msgid "failed to execute internal merge"
+msgstr "无法执行内部åˆå¹¶"
+
+#: merge-recursive.c
+#, c-format
+msgid "unable to add %s to database"
+msgstr "ä¸èƒ½æ·»åŠ  %s 至对象库"
+
+#: merge-recursive.c
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr "错误:拒ç»ä¸¢å¤±æœªè·Ÿè¸ªæ–‡ä»¶ '%s',而是写入 %s。"
@@ -21245,6 +21807,16 @@ msgstr ""
"%4$s->%5$s"
#: merge-recursive.c
+#, c-format
+msgid "cannot read object %s"
+msgstr "ä¸èƒ½è¯»å–对象 %s"
+
+#: merge-recursive.c
+#, c-format
+msgid "object %s is not a blob"
+msgstr "对象 %s 䏿˜¯ä¸€ä¸ªæ•°æ®å¯¹è±¡"
+
+#: merge-recursive.c
msgid "modify"
msgstr "修改"
@@ -21319,146 +21891,249 @@ msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'"
msgid "failed to read the cache"
msgstr "无法读å–缓存"
-#: midx.c
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "多包索引的对象ID扇出表大å°é”™è¯¯"
+#: midx-write.c
+#, c-format
+msgid "failed to add packfile '%s'"
+msgstr "无法添加包文件 '%s'"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "多包索引文件 %s 太å°"
+msgid "failed to open pack-index '%s'"
+msgstr "无法打开包索引 '%s'"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr "多包索引签å 0x%08x 和签å 0x%08x ä¸åŒ¹é…"
+msgid "failed to locate object %d in packfile"
+msgstr "无法在包文件中定ä½å¯¹è±¡ %d"
-#: midx.c
+#: midx-write.c
+msgid "cannot store reverse index file"
+msgstr "无法存储åå‘索引文件"
+
+#: midx-write.c
#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "multi-pack-index 版本 %d ä¸èƒ½è¢«è¯†åˆ«"
+msgid "could not parse line: %s"
+msgstr "ä¸èƒ½è§£æžè¡Œï¼š%s"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "多包索引哈希版本 %u 和版本 %u ä¸åŒ¹é…"
+msgid "malformed line: %s"
+msgstr "æ ¼å¼é”™è¯¯çš„行:%s"
-#: midx.c
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "多包索引缺少必需的包åå—"
+#: midx-write.c
+msgid "could not load pack"
+msgstr "ä¸èƒ½è½½å…¥åŒ…"
-#: midx.c
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "多包索引缺少必需的对象 ID 扇出å—"
+#: midx-write.c
+#, c-format
+msgid "could not open index for %s"
+msgstr "ä¸èƒ½æ‰“å¼€ %s 的索引"
-#: midx.c
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "多包索引缺少必需的对象 ID 查询å—"
+#: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "无法将 '%s' 链接至 '%s'"
-#: midx.c
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "多包索引缺少必需的对象åç§»å—"
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "无法清ç†ä½äºŽ %s 的多包索引"
-#: midx.c
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "无法使用ä½å›¾å†™å…¥å¢žé‡ MIDX"
+
+#: midx-write.c
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr "忽略已存在的多包索引,校验ç ä¸åŒ¹é…"
+
+#: midx-write.c
+msgid "Adding packfiles to multi-pack-index"
+msgstr "添加包文件到多包索引"
+
+#: midx-write.c
#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "å¤šåŒ…ç´¢å¼•åŒ…åæ— åºï¼š'%s' 在 '%s' 之å‰"
+msgid "unknown preferred pack: '%s'"
+msgstr "未知的首选包:'%s'"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "错的 pack-int-id:%u(共有 %u 个包)"
+msgid "cannot select preferred pack %s with no objects"
+msgstr "ä¸èƒ½é€‰æ‹©æ²¡æœ‰å¯¹è±¡çš„首选包 %s"
+
+#: midx-write.c
+#, c-format
+msgid "did not see pack-file %s to drop"
+msgstr "没有看到è¦ä¸¢å¼ƒçš„包文件 %s"
+
+#: midx-write.c
+#, c-format
+msgid "preferred pack '%s' is expired"
+msgstr "首选包 '%s' 已过期"
+
+#: midx-write.c
+msgid "no pack files to index."
+msgstr "没有è¦ç´¢å¼•的包文件。"
+
+#: midx-write.c
+msgid "refusing to write multi-pack .bitmap without any objects"
+msgstr "æ‹’ç»å†™å…¥æ²¡æœ‰ä»»ä½•对象的多包ä½å›¾"
+
+#: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "无法创建临时 MIDX 层"
+
+#: midx-write.c
+msgid "could not write multi-pack bitmap"
+msgstr "无法写入多包ä½å›¾"
+
+#: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "无法打开多包索引链文件"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "无法é‡å‘½å新的多包索引层"
+
+#: midx-write.c
+msgid "could not write multi-pack-index"
+msgstr "无法写入多包索引"
+
+#: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "增é‡å¤šåŒ…索引中的包ä¸èƒ½è¿‡æœŸ"
+
+#: midx-write.c
+msgid "Counting referenced objects"
+msgstr "正在对引用对象计数"
+
+#: midx-write.c
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "正在查找和删除未引用的包文件"
+
+#: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "æ— æ³•é‡æ–°æ‰“包增é‡å¤šåŒ…索引"
+
+#: midx-write.c
+msgid "could not start pack-objects"
+msgstr "ä¸èƒ½å¼€å§‹ pack-objects"
+
+#: midx-write.c
+msgid "could not finish pack-objects"
+msgstr "ä¸èƒ½ç»“æŸ pack-objects"
#: midx.c
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr "多包索引存储一个64ä½å移,但是 off_t 太å°"
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "多包索引的对象 ID 扇出表大å°é”™è¯¯"
#: midx.c
#, c-format
-msgid "failed to add packfile '%s'"
-msgstr "无法添加包文件 '%s'"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr "对象 ID 扇出失åºï¼šfanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
#: midx.c
-#, c-format
-msgid "failed to open pack-index '%s'"
-msgstr "无法打开包索引 '%s'"
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "多包索引的对象 ID 查询å—大å°é”™è¯¯"
+
+#: midx.c
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "多包索引的对象 ID åç§»å—大å°é”™è¯¯"
#: midx.c
#, c-format
-msgid "failed to locate object %d in packfile"
-msgstr "无法在包文件中定ä½å¯¹è±¡ %d"
+msgid "multi-pack-index file %s is too small"
+msgstr "多包索引文件 %s 太å°"
#: midx.c
-msgid "cannot store reverse index file"
-msgstr "无法存储åå‘索引文件"
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "多包索引签å 0x%08x 和签å 0x%08x ä¸åŒ¹é…"
#: midx.c
#, c-format
-msgid "could not parse line: %s"
-msgstr "ä¸èƒ½è§£æžè¡Œï¼š%s"
+msgid "multi-pack-index version %d not recognized"
+msgstr "multi-pack-index 版本 %d ä¸èƒ½è¢«è¯†åˆ«"
#: midx.c
#, c-format
-msgid "malformed line: %s"
-msgstr "æ ¼å¼é”™è¯¯çš„行:%s"
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "多包索引哈希版本 %u 和版本 %u ä¸åŒ¹é…"
#: midx.c
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "忽略已存在的多包索引,校验ç ä¸åŒ¹é…"
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr "多包索引必需的包åå—缺失或æŸå"
#: midx.c
-msgid "could not load pack"
-msgstr "ä¸èƒ½è½½å…¥åŒ…"
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr "多包索引必需的对象 ID 扇出å—缺失或æŸå"
#: midx.c
-#, c-format
-msgid "could not open index for %s"
-msgstr "ä¸èƒ½æ‰“å¼€ %s 的索引"
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr "多包索引必需的对象 ID 查询å—缺失或æŸå"
#: midx.c
-msgid "Adding packfiles to multi-pack-index"
-msgstr "添加包文件到多包索引"
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr "多包索引必需的对象åç§»å—缺少或æŸå"
+
+#: midx.c
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "多包索引包åå—过短"
#: midx.c
#, c-format
-msgid "unknown preferred pack: '%s'"
-msgstr "未知的首选包:'%s'"
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "å¤šåŒ…ç´¢å¼•åŒ…åæ— åºï¼š'%s' 在 '%s' 之å‰"
+
+#: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "多包索引链文件太å°"
#: midx.c
#, c-format
-msgid "cannot select preferred pack %s with no objects"
-msgstr "ä¸èƒ½é€‰æ‹©æ²¡æœ‰å¯¹è±¡çš„首选包 %s"
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "基线的 MIDX 中包的数é‡è¿‡é«˜ï¼š%<PRIuMAX>"
#: midx.c
#, c-format
-msgid "did not see pack-file %s to drop"
-msgstr "没有看到è¦ä¸¢å¼ƒçš„包文件 %s"
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "基线的 MIDX 中对象的数é‡è¿‡é«˜ï¼š%<PRIuMAX>"
#: midx.c
#, c-format
-msgid "preferred pack '%s' is expired"
-msgstr "首选包 '%s' 已过期"
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "无效的多包索引链:第 '%s' è¡Œä¸æ˜¯å“ˆå¸Œå€¼"
#: midx.c
-msgid "no pack files to index."
-msgstr "没有è¦ç´¢å¼•的包文件。"
+msgid "unable to find all multi-pack index files"
+msgstr "无法找到所有的多包索引文件"
#: midx.c
-msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "æ‹’ç»å†™å…¥æ²¡æœ‰ä»»ä½•对象的多包ä½å›¾ .bitmap"
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "无效的 MIDX 对象ä½ç½®ï¼ŒMIDX å¯èƒ½å·²æŸå"
#: midx.c
-msgid "could not write multi-pack bitmap"
-msgstr "无法写入多包ä½å›¾"
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "错的 pack-int-id:%u(共有 %u 个包)"
#: midx.c
-msgid "could not write multi-pack-index"
-msgstr "无法写入多包索引"
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "å¤šåŒ…ç´¢å¼•ä¸­æœªåŒ…å« BTMP å—"
#: midx.c
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "无法清ç†ä½äºŽ %s 的多包索引"
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "ä¸èƒ½æ‰“开已被ä½å›¾ç´¢å¼•的包 %<PRIu32>"
+
+#: midx.c
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr "多包索引存储一个64ä½å移,但是 off_t 太å°"
+
+#: midx.c
+msgid "multi-pack-index large offset out of bounds"
+msgstr "多包索引大å移区越界"
#: midx.c
msgid "multi-pack-index file exists, but failed to parse"
@@ -21473,12 +22148,6 @@ msgid "Looking for referenced packfiles"
msgstr "正在查找引用的包文件"
#: midx.c
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr "对象 ID 扇出无åºï¼šfanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-
-#: midx.c
msgid "the midx contains no oid"
msgstr "midx ä¸åŒ…å« oid"
@@ -21514,22 +22183,6 @@ msgstr "无法为包文件 %s 加载包索引"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "oid[%d] = %s 错误的对象å移:%<PRIx64> != %<PRIx64>"
-#: midx.c
-msgid "Counting referenced objects"
-msgstr "正在对引用对象计数"
-
-#: midx.c
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "正在查找和删除未引用的包文件"
-
-#: midx.c
-msgid "could not start pack-objects"
-msgstr "ä¸èƒ½å¼€å§‹ pack-objects"
-
-#: midx.c
-msgid "could not finish pack-objects"
-msgstr "ä¸èƒ½ç»“æŸ pack-objects"
-
#: name-hash.c
#, c-format
msgid "unable to create lazy_dir thread: %s"
@@ -21584,6 +22237,30 @@ msgstr "æ‹’ç»å‘ %s(在 refs/notes/ 之外)写入注解"
msgid "Bad %s value: '%s'"
msgstr "åçš„ %s 值:'%s'"
+#: object-file-convert.c
+msgid "failed to decode tree entry"
+msgstr "æ— æ³•è§£ç æ ‘对象"
+
+#: object-file-convert.c
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "无法为 %s 映射树对象"
+
+#: object-file-convert.c
+#, c-format
+msgid "bad %s in commit"
+msgstr "æäº¤ä¸­æœ‰é”™è¯¯çš„ %s"
+
+#: object-file-convert.c
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "无法将 %s %s 映射到æäº¤å¯¹è±¡ä¸­"
+
+#: object-file-convert.c
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "无法将对象从 %s 转æ¢ä¸º %s"
+
#: object-file.c
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
@@ -21712,6 +22389,21 @@ msgstr "打包对象 %s(ä¿å­˜åœ¨ %s)已æŸå"
#: object-file.c
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "缺少 %s 到 %s 的映射"
+
+#: object-file.c
+#, c-format
+msgid "unable to open %s"
+msgstr "ä¸èƒ½æ‰“å¼€ %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "文件 '%s' å’Œ '%s' 的内容ä¸åŒ"
+
+#: object-file.c
+#, c-format
msgid "unable to write file %s"
msgstr "无法写文件 %s"
@@ -21779,6 +22471,11 @@ msgstr "ä¸èƒ½è¯»å–对象 %s"
#: object-file.c
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "无法将对象 %s 映射到 %s"
+
+#: object-file.c
+#, c-format
msgid "object fails fsck: %s"
msgstr "对象 fsck 失败:%s"
@@ -21813,11 +22510,6 @@ msgstr "%s 䏿˜¯ä¸€ä¸ªæœ‰æ•ˆçš„ '%s' 对象"
#: object-file.c
#, c-format
-msgid "unable to open %s"
-msgstr "ä¸èƒ½æ‰“å¼€ %s"
-
-#: object-file.c
-#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "%s 的哈希值ä¸åŒ¹é…(预期 %s)"
@@ -22039,6 +22731,20 @@ msgid "hash mismatch %s"
msgstr "哈希值与 %s ä¸åŒ¹é…"
#: pack-bitmap-write.c
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "写入ä½å›¾ç´¢å¼•时存在é‡å¤æ¡ç›®ï¼š'%s'"
+
+#: pack-bitmap-write.c
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "å°è¯•存储未选定的æäº¤ï¼š'%s'"
+
+#: pack-bitmap-write.c
+msgid "too many pseudo-merges"
+msgstr "太多伪åˆå¹¶"
+
+#: pack-bitmap-write.c
msgid "trying to write commit not in index"
msgstr "å°è¯•写入未在索引中的æäº¤"
@@ -22068,6 +22774,19 @@ msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr "æŸåçš„ä½å›¾ç´¢å¼•(太å°ï¼Œå®¹ä¸ä¸‹æŸ¥è¯¢è¡¨ï¼‰"
#: pack-bitmap.c
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr "æŸåçš„ä½å›¾ç´¢å¼•文件(太短而无法容纳伪åˆå¹¶è¡¨å¤´ï¼‰"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr "æŸåçš„ä½å›¾ç´¢å¼•(太短而无法容纳伪åˆå¹¶è¡¨ï¼‰"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "æŸåçš„ä½å›¾ç´¢å¼•,伪åˆå¹¶è¡¨è¿‡çŸ­"
+
+#: pack-bitmap.c
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "ä½å›¾ç´¢å¼•中的é‡å¤æ¡ç›®ï¼š'%s'"
@@ -22107,6 +22826,10 @@ msgstr "多包ä½å›¾ç¼ºå°‘必需的åå‘索引"
msgid "could not open pack %s"
msgstr "ä¸èƒ½æ‰“开包 %s"
+#: pack-bitmap.c t/helper/test-read-midx.c
+msgid "could not determine MIDX preferred pack"
+msgstr "ä¸èƒ½ç¡®å®šå¤šåŒ…索引的首选包"
+
#: pack-bitmap.c
#, c-format
msgid "preferred pack (%s) is invalid"
@@ -22132,6 +22855,15 @@ msgstr "æŸåçš„ EWAH ä½å›¾ï¼šæäº¤ \"%s\" ä½å›¾çš„æ–‡ä»¶å¤´è¢«æˆªæ–­"
#: pack-bitmap.c
#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "无法打开包:'%s',ç¦ç”¨åŒ…é‡ç”¨"
+
+#: pack-bitmap.c
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "无法计算首选包,ç¦ç”¨åŒ…é‡ç”¨"
+
+#: pack-bitmap.c
+#, c-format
msgid "object '%s' not found in type bitmaps"
msgstr "对象 %s 为在类型ä½å›¾ä¸­æ‰¾åˆ°"
@@ -22169,6 +22901,11 @@ msgstr "ä½å›¾ç»“æžœä¸ä¸€è‡´"
#: pack-bitmap.c
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "伪åˆå¹¶ç´¢å¼•超出范围 (%<PRIu32> >= %<PRIuMAX>)"
+
+#: pack-bitmap.c
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "无法在包 '%2$s' åç§» %3$<PRIuMAX> 中找到 '%1$s'"
@@ -22241,6 +22978,14 @@ msgstr "æ— æ•ˆçš„æ ¡éªŒç  %s"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "ä½äºŽ %<PRIu64> 的无效的åå‘索引:%<PRIu32> != %<PRIu32>"
+#: pack-revindex.c
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "多包索引的åå‘索引å—大å°é”™è¯¯"
+
+#: pack-revindex.c
+msgid "could not determine preferred pack"
+msgstr "无法确定首选包"
+
#: pack-write.c
msgid "cannot both write and verify reverse index"
msgstr "æ— æ³•åŒæ—¶å†™å…¥å’Œæ ¡éªŒåå‘索引"
@@ -22306,16 +23051,6 @@ msgstr "%s 需è¦ä¸€ä¸ªå€¼"
#: parse-options.c
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s 与 %s ä¸å…¼å®¹"
-
-#: parse-options.c
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s:和其它的ä¸å…¼å®¹"
-
-#: parse-options.c
-#, c-format
msgid "%s takes no value"
msgstr "%s ä¸å–值"
@@ -22414,6 +23149,11 @@ msgstr " %s"
msgid "-NUM"
msgstr "-æ•°å­—"
+#: parse-options.c
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "与 --no-%s 相å"
+
#: parse-options.h
msgid "expiry-date"
msgstr "到期时间"
@@ -22451,6 +23191,16 @@ msgid ""
"with --pathspec-from-file, pathspec elements are separated with NUL character"
msgstr "使用 --pathspec-from-file,路径表达å¼ç”¨ç©ºå­—符分隔"
+#: parse.c
+#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "对于 '%2$s' 的错误的布尔环境å–值 '%1$s'"
+
+#: parse.c
+#, c-format
+msgid "failed to parse %s"
+msgstr "æ— æ³•è§£æž %s"
+
#: path.c
#, c-format
msgid "Could not make %s writable by group"
@@ -22509,6 +23259,11 @@ msgstr "%s:'literal' å’Œ 'glob' ä¸å…¼å®¹"
#: pathspec.c
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "'%s' ä½äºŽç›®å½•树之外"
+
+#: pathspec.c
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s:'%s' 在ä½äºŽ '%s' 的仓库之外"
@@ -22602,6 +23357,10 @@ msgid "unable to parse --pretty format"
msgstr "ä¸èƒ½è§£æž --pretty æ ¼å¼"
#: promisor-remote.c
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "ç¦ç”¨å»¶è¿ŸèŽ·å–,æŸäº›å¯¹è±¡å¯èƒ½ä¸å¯ç”¨"
+
+#: promisor-remote.c
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote:无法派生 fetch å­è¿›ç¨‹"
@@ -22631,6 +23390,72 @@ msgstr "object-infoï¼šåœ¨å‚æ•°ä¹‹åŽåº”有一个 flush"
msgid "Removing duplicate objects"
msgstr "正在删除é‡å¤å¯¹è±¡"
+#: pseudo-merge.c
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "未能加载 %s 的伪åˆå¹¶æ­£åˆ™è¡¨è¾¾å¼ï¼š'%s'"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s 必须为éžè´Ÿæ•´æ•°ï¼Œä½¿ç”¨é»˜è®¤å€¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s 必须介于 0 到 1 之间,使用默认值"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s 必须为正数,使用默认值"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "伪åˆå¹¶ç»„ '%s' 缺少所需的模å¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr "伪åˆå¹¶ç»„ '%s' åœ¨ç¨³å®šé˜ˆå€¼ä¹‹å‰æœ‰ä¸ç¨³å®šé˜ˆå€¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr "æ¥è‡ª config 的伪åˆå¹¶æ­£åˆ™è¡¨è¾¾å¼æœ‰å¤ªå¤šçš„æ•èŽ·ç»„ï¼ˆæœ€å¤š %<PRIuMAX> 个)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "扩展伪åˆå¹¶è¯»å–越界 (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "扩展伪åˆå¹¶æ¡ç›®å¤ªçŸ­ï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr "无法在æäº¤ %1$s çš„åç§» %2$<PRIuMAX> 中找到伪åˆå¹¶"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr "扩展伪åˆå¹¶æŸ¥æ‰¾è¶Šç•Œ (%<PRIu32> >= %<PRIu32>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "越界读å–:(%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "æ— æ³•è¯»å–æäº¤ %s 的扩展伪åˆå¹¶è¡¨"
+
#: range-diff.c
msgid "could not start `log`"
msgstr "ä¸èƒ½å¯åЍ `log`"
@@ -22700,11 +23525,6 @@ msgstr "无法在索引中添加 '%s'"
#: read-cache.c
#, c-format
-msgid "unable to stat '%s'"
-msgstr "无法对 %s 执行 stat"
-
-#: read-cache.c
-#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "'%s' çœ‹èµ·æ¥æ—¢æ˜¯æ–‡ä»¶åˆæ˜¯ç›®å½•"
@@ -22838,11 +23658,6 @@ msgstr "无法转æ¢ä¸ºç¨€ç–索引"
#: read-cache.c
#, c-format
-msgid "could not stat '%s'"
-msgstr "ä¸èƒ½å¯¹ '%s' 调用 stat"
-
-#: read-cache.c
-#, c-format
msgid "unable to open git dir: %s"
msgstr "ä¸èƒ½æ‰“å¼€ git 目录:%s"
@@ -23141,6 +23956,11 @@ msgstr "期望的格å¼ï¼š%%(ahead-behind:<æäº¤å·>)"
#: ref-filter.c
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "期望的格å¼ï¼š%%(is-base:<æäº¤å·>)"
+
+#: ref-filter.c
+#, c-format
msgid "malformed field name: %.*s"
msgstr "æ ¼å¼é”™è¯¯çš„字段å:%.*s"
@@ -23350,12 +24170,21 @@ msgid "log for %s is empty"
msgstr "%s 的日志为空"
#: refs.c
+msgid "refusing to force and skip creation of reflog"
+msgstr "æ‹’ç»æ—¢å¼ºåˆ¶åˆè·³è¿‡åˆ›å»ºå¼•用日志"
+
+#: refs.c
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "æ‹’ç»æ›´æ–°æœ‰é”™è¯¯åç§° '%s' 的引用"
#: refs.c
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "æ‹’ç»æ›´æ–°ä¼ªå¼•用 '%s'"
+
+#: refs.c
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "对引用 '%s' 执行 update_ref 失败:%s"
@@ -23382,21 +24211,124 @@ msgstr "'%s' 已存在,无法创建 '%s'"
msgid "cannot process '%s' and '%s' at the same time"
msgstr "æ— æ³•åŒæ—¶å¤„ç† '%s' å’Œ '%s'"
-#: refs/files-backend.c
-#, c-format
-msgid "could not remove reference %s"
-msgstr "无法删除引用 %s"
-
-#: refs/files-backend.c refs/packed-backend.c
+#: refs.c
#, c-format
msgid "could not delete reference %s: %s"
msgstr "无法删除引用 %s:%s"
-#: refs/files-backend.c refs/packed-backend.c
+#: refs.c
#, c-format
msgid "could not delete references: %s"
msgstr "无法删除引用:%s"
+#: refs.c
+#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "å·²å®Œæˆ refs 的试è¿è¡Œè¿ç§»ï¼Œç»“æžœå¯åœ¨ '%s' 处找到\n"
+
+#: refs.c
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "无法删除临时è¿ç§»ç›®å½• '%s'"
+
+#: refs.c
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "è¿ç§»çš„引用å¯ä»¥åœ¨ '%s' 处找到"
+
+#: refs/files-backend.c refs/reftable-backend.c
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr "无法é”定引用 '%s':预期目标为 '%s' 的符å·å¼•用:但是是普通引用"
+
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "无法打开目录 %s"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "正在检查引用一致性"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "å±é™©çš„引用å称:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "试图用ä¸å­˜åœ¨çš„对象 %2$s 写入引用 '%1$s'"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "å°è¯•å°†éžæäº¤å¯¹è±¡ %s 写入分支 '%s'"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr "ä¸å…许对 'HEAD' 进行多次更新(包括通过其引用 '%s' 进行的更新)"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr "无法é”定引用 '%s':无法解æžå¼•用 '%s'"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "无法é”定引用 '%s':读å–引用时出错"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr "ä¸å…许对 '%s' 进行多次更新(包括通过符å·å¼•用 '%s' 更新)"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "无法é”定引用 '%s':引用已存在"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr "无法é”定 '%s' 引用:引用丢失,但预期为 %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "无法é”定 '%s' 引用:ä½äºŽ %s,但预期为 %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "reftable: 事务准备:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "reftable: 事务失败:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "无法压缩栈:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s not found"
+msgstr "引用åç§° %s 未找到"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "引用å %s 是一个符å·å¼•ç”¨ï¼Œä¸æ”¯æŒå¤åˆ¶"
+
#: refspec.c
#, c-format
msgid "invalid refspec '%s'"
@@ -23409,6 +24341,11 @@ msgstr "在 push-option å–值中无效的引å·ï¼š'%s'"
#: remote-curl.c
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "对象格å¼çš„æœªçŸ¥å–值:%s"
+
+#: remote-curl.c
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs 无效:这是 git 仓库么?"
@@ -23944,8 +24881,21 @@ msgstr "resolve-undo 记录 `%s`,现缺失"
#: revision.c
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "无法获得 ancestry-path 傿•° %s çš„æäº¤"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s 存在但是一个符å·å¼•用"
+
+#: revision.c
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge é€‰é¡¹éœ€è¦æŒ‡å®š MERGE_HEADã€CHERRY_PICK_HEADã€REVERT_HEAD 或 "
+"REBASE_HEAD 中的一个伪引用"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "无法获得 --ancestry-path 傿•° %s çš„æäº¤"
#: revision.c
msgid "--unpacked=<packfile> no longer supported"
@@ -24067,8 +25017,20 @@ msgid "only download metadata for the branch that will be checked out"
msgstr "åªä¸‹è½½è¦æ£€å‡ºçš„分支的元信æ¯"
#: scalar.c
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<选项>] [--] <仓库> [<目录>]"
+msgid "create repository within 'src' directory"
+msgstr "在 'src' 目录中创建仓库"
+
+#: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "å¦‚è‹¥åº”åœ¨å…‹éš†æœŸé—´èŽ·å–æ ‡ç­¾åˆ™æŒ‡å®š"
+
+#: scalar.c
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<登记>]"
#: scalar.c
#, c-format
@@ -24092,6 +25054,11 @@ msgstr "无法在 '%s' 中é…置远程"
#: scalar.c
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "无法ç¦ç”¨ '%s' 中的标签"
+
+#: scalar.c
+#, c-format
msgid "could not configure '%s'"
msgstr "无法é…ç½® '%s'"
@@ -24134,13 +25101,32 @@ msgstr "无法删除过期的 scalar.repo '%s'"
#: scalar.c
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "正在删除过期的 scalar.repo '%s'"
+msgid "removed stale scalar.repo '%s'"
+msgstr "已删除过期的 scalar.repo '%s'"
+
+#: scalar.c
+#, c-format
+msgid "repository at '%s' has different owner"
+msgstr "ä½äºŽ '%s' 处的仓库有ä¸åŒçš„æ‰€æœ‰è€…"
+
+#: scalar.c
+#, c-format
+msgid "repository at '%s' has a format issue"
+msgstr "ä½äºŽ '%s' 处的仓库存在格å¼é—®é¢˜"
#: scalar.c
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "在 '%s' 的 git 仓库已消失"
+msgid "repository not found in '%s'"
+msgstr "在 '%s' 中找ä¸åˆ°ä»“库"
+
+#: scalar.c
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"若希望从 Scalar 注销该仓库,执行\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
#: scalar.c
msgid ""
@@ -24279,6 +25265,19 @@ msgstr "未知动作:%d"
#: sequencer.c
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 ""
+"手工解决所有冲çªï¼Œæ‰§è¡Œ \"git add/rm <冲çªçš„æ–‡ä»¶>\" 标记\n"
+"冲çªå·²è§£å†³ï¼Œç„¶åŽæ‰§è¡Œ \"git rebase --continue\"。您也å¯ä»¥æ‰§è¡Œ\n"
+"\"git rebase --skip\" 命令跳过这个æäº¤ã€‚如果想è¦ç»ˆæ­¢æ‰§è¡Œå¹¶å›žåˆ°\n"
+"\"git rebase\" 执行之å‰çš„状æ€ï¼Œæ‰§è¡Œ \"git rebase --abort\"。"
+
+#: sequencer.c
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -24520,18 +25519,13 @@ msgstr "无效的作者身份 '%s'"
msgid "corrupt author: missing date information"
msgstr "æŸå的作者:缺失日期信æ¯"
-#: sequencer.c t/helper/test-fast-rebase.c
+#: sequencer.c
#, c-format
msgid "could not update %s"
msgstr "ä¸èƒ½æ›´æ–° %s"
#: sequencer.c
#, c-format
-msgid "could not parse commit %s"
-msgstr "ä¸èƒ½è§£æžæäº¤ %s"
-
-#: sequencer.c
-#, c-format
msgid "could not parse parent commit %s"
msgstr "ä¸èƒ½è§£æžçˆ¶æäº¤ %s"
@@ -24617,11 +25611,6 @@ msgstr "%s:ä¸èƒ½è§£æžçˆ¶æäº¤ %s"
#: sequencer.c
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "ä¸èƒ½å°† '%s' é‡å‘½å为 '%s'"
-
-#: sequencer.c
-#, c-format
msgid "could not revert %s... %s"
msgstr "ä¸èƒ½è¿˜åŽŸ %s... %s"
@@ -24662,13 +25651,55 @@ msgstr "update-ref 需è¦ä¸€ä¸ªå®Œæ•´çš„引用å,例如:refs/heads/%s"
#: sequencer.c
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "无效命令 '%.*s'"
+msgid "'%s' does not accept merge commits"
+msgstr "'%s' 䏿ޥå—åˆå¹¶æäº¤"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"'pick' 䏿ޥå—åˆå¹¶æäº¤ã€‚如果您想è¦é‡æ”¾åˆå¹¶ï¼Œ\n"
+"请在æäº¤ä¸Šä½¿ç”¨ 'merge -C'。"
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"'reword' 䏿ޥå—åˆå¹¶æäº¤ã€‚å¦‚æžœæ‚¨æƒ³é‡æ”¾åˆå¹¶å¹¶é‡å†™æäº¤æ¶ˆæ¯ï¼Œ\n"
+"请在æäº¤ä¸Šä½¿ç”¨ 'merge -c'"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+#: sequencer.c
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"'editâ€' 䏿ޥå—åˆå¹¶æäº¤ã€‚如果您想è¦é‡æ”¾åˆå¹¶ï¼Œ\n"
+"请在æäº¤ä¸Šä½¿ç”¨ 'merge -C',然åŽä½¿ç”¨ 'break'\n"
+"将控制æƒäº¤è¿˜ç»™æ‚¨ï¼Œä»¥ä¾¿æ‚¨å¯ä»¥æ‰§è¡Œ\n"
+"'git commit --amend && git rebase --continue'。"
+
+#: sequencer.c
+msgid "cannot squash merge commit into another commit"
+msgstr "无法将åˆå¹¶æäº¤åŽ‹ç¼©åˆ°å¦ä¸€ä¸ªæäº¤ä¸­"
#: sequencer.c
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s 䏿ޥå—傿•°ï¼š'%s'"
+msgid "invalid command '%.*s'"
+msgstr "无效命令 '%.*s'"
#: sequencer.c
#, c-format
@@ -24815,9 +25846,8 @@ msgid "cannot read HEAD"
msgstr "ä¸èƒ½è¯»å– HEAD"
#: sequencer.c
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "æ— æ³•æ‹·è´ '%s' 至 '%s'"
+msgid "could not write commit message file"
+msgstr "无法写入æäº¤è¯´æ˜Žæ–‡ä»¶"
#: sequencer.c
#, c-format
@@ -25016,6 +26046,10 @@ msgid "Autostash exists; creating a new stash entry."
msgstr "自动贮è—å·²ç»å­˜åœ¨ï¼›æ­£åœ¨åˆ›å»ºä¸€ä¸ªæ–°çš„è´®è—æ¡ç›®ã€‚"
#: sequencer.c
+msgid "autostash reference is a symref"
+msgstr "自动贮è—的引用是一个符å·å¼•用"
+
+#: sequencer.c
msgid "could not detach HEAD"
msgstr "ä¸èƒ½åˆ†ç¦»å¤´æŒ‡é’ˆ"
@@ -25051,13 +26085,13 @@ msgstr ""
#: sequencer.c
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "正在å˜åŸºï¼ˆ%d/%d)%s"
+msgid "Stopped at %s... %.*s\n"
+msgstr "åœæ­¢åœ¨ %s... %.*s\n"
#: sequencer.c
#, c-format
-msgid "Stopped at %s... %.*s\n"
-msgstr "åœæ­¢åœ¨ %s... %.*s\n"
+msgid "Rebasing (%d/%d)%s"
+msgstr "正在å˜åŸºï¼ˆ%d/%d)%s"
#: sequencer.c
#, c-format
@@ -25217,6 +26251,11 @@ msgstr "无法使用无效é…ç½®æ¥åˆ›å»ºå·¥ä½œåŒº"
#: setup.c
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "'%s' 已指定为 '%s'"
+
+#: setup.c
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "期望 git 仓库版本 <= %d,å´å¾—到 %d"
@@ -25287,6 +26326,24 @@ msgid "failed to stat '%*s%s%s'"
msgstr "æ— æ³•èŽ·å– '%*s%s%s' 状æ€ï¼ˆstat)"
#: setup.c
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%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"
+
+#: setup.c
msgid "Unable to read current working directory"
msgstr "ä¸èƒ½è¯»å–当å‰å·¥ä½œç›®å½•"
@@ -25311,19 +26368,6 @@ msgstr ""
#: 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')"
@@ -25391,6 +26435,11 @@ msgstr "无效的åˆå§‹åˆ†æ”¯å:'%s'"
#: setup.c
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init:已忽略 --initial-branch=%s"
+
+#: setup.c
+#, c-format
msgid "unable to handle file type %d"
msgstr "ä¸èƒ½å¤„ç† %d 类型的文件"
@@ -25404,14 +26453,14 @@ msgid "attempt to reinitialize repository with different hash"
msgstr "å°è¯•用ä¸åŒçš„å“ˆå¸Œç®—æ³•é‡æ–°åˆå§‹åŒ–仓库"
#: setup.c
-#, c-format
-msgid "%s already exists"
-msgstr "%s å·²ç»å­˜åœ¨"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr "å°è¯•使用ä¸åŒçš„引用存储格å¼é‡æ–°åˆå§‹åŒ–仓库"
#: setup.c
#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init:已忽略 --initial-branch=%s"
+msgid "%s already exists"
+msgstr "%s å·²ç»å­˜åœ¨"
#: setup.c
#, c-format
@@ -25442,6 +26491,24 @@ msgstr "索引æ¡ç›®æ˜¯ä¸€ä¸ªç›®å½•ï¼Œä½†ä¸æ˜¯ç¨€ç–çš„ (%08x)"
msgid "cannot use split index with a sparse index"
msgstr "拆分索引无法与稀ç–索引一起使用"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "åçš„ %s æ ¼å¼ï¼šå…ƒç´  '%s' 没有以 '(' 开头"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "åçš„ %s æ ¼å¼ï¼šå…ƒç´  '%s' 没有以 ')' 结尾"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "åçš„ %s æ ¼å¼: %%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#: strbuf.c
#, c-format
@@ -25665,6 +26732,16 @@ msgstr "å­æ¨¡ç»„ git 目录 '%s' ä½äºŽ git 目录 '%.*s' 中"
#: submodule.c
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr "æœŸæœ›å­æ¨¡ç»„的父目录 '%.*s' 䏿˜¯ä¸€ä¸ªç¬¦å·é“¾æŽ¥ï¼Œå­æ¨¡ç»„路径为 '%s'"
+
+#: submodule.c
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "é¢„æœŸå­æ¨¡ç»„路径 '%s' 䏿˜¯ç¬¦å·é“¾æŽ¥"
+
+#: submodule.c
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr "䏿”¯æŒå¯¹æœ‰å¤šä¸ªå·¥ä½œåŒºçš„å­æ¨¡ç»„ '%s' 执行 relocate_gitdir"
@@ -25709,11 +26786,6 @@ msgid "no remote configured to get bundle URIs from"
msgstr "没有远程被设置为å¯ä»¥èŽ·å–归档包 URI"
#: 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 列表"
@@ -25729,14 +26801,6 @@ msgstr "åœ¨æ¯æ¬¡è¿­ä»£å‰æ¸…除缓存树"
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr "缓存树中无效化的æ¡ç›®æ•°é‡ï¼ˆé»˜è®¤ 0)"
-#: t/helper/test-fast-rebase.c
-msgid "unhandled options"
-msgstr "未处ç†çš„选项"
-
-#: t/helper/test-fast-rebase.c
-msgid "error preparing revisions"
-msgstr "准备版本时错误"
-
#: t/helper/test-reach.c
#, c-format
msgid "commit %s is not marked reachable"
@@ -25826,6 +26890,30 @@ msgstr "令牌"
msgid "command token to send to the server"
msgstr "å‘é€åˆ°æœåŠ¡å™¨çš„å‘½ä»¤ä»¤ç‰Œ"
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<选项>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "第一次测试失败åŽç«‹å³é€€å‡º"
+
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::测试用例]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "åªè¿è¡Œæµ‹è¯•套件或å•独的测试 <测试套件[::测试用例]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "测试套件"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "排除测试套件 <测试套件>"
+
#: trailer.c
#, c-format
msgid "running trailer command '%s' failed"
@@ -25841,35 +26929,6 @@ msgstr "é”® '%2$s' 的未知å–值 '%1$s'"
msgid "empty trailer token in trailer '%.*s'"
msgstr "尾注 '%.*s' 的键为空"
-#: trailer.c
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "ä¸èƒ½è¯»å–输入文件 '%s'"
-
-#: trailer.c wrapper.c
-#, c-format
-msgid "could not stat %s"
-msgstr "ä¸èƒ½å¯¹ %s 调用 stat"
-
-#: trailer.c
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "文件 %s 䏿˜¯ä¸€ä¸ªæ­£è§„文件"
-
-#: trailer.c
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "文件 %s 用户ä¸å¯å†™"
-
-#: trailer.c
-msgid "could not open temporary file"
-msgstr "ä¸èƒ½æ‰“开临时文件"
-
-#: trailer.c
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "ä¸èƒ½é‡å‘½å临时文件为 %s"
-
#: transport-helper.c
msgid "full write to remote helper failed"
msgstr "完整写入远程助手失败"
@@ -25930,10 +26989,6 @@ msgstr "åè®®ä¸æ”¯æŒè®¾ç½®è¿œç¨‹æœåŠ¡è·¯å¾„"
msgid "invalid remote service path"
msgstr "无效的远程æœåŠ¡è·¯å¾„"
-#: transport-helper.c transport.c
-msgid "operation not supported by protocol"
-msgstr "åè®®ä¸æ”¯æŒè¯¥æ“作"
-
#: transport-helper.c
#, c-format
msgid "can't connect to subservice %s"
@@ -25993,8 +27048,8 @@ msgstr "remote-heper 䏿”¯æŒæŽ¨é€ï¼Œéœ€è¦å¼•用规格"
#: transport-helper.c
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "助手 %s 䏿”¯æŒ 'force'"
+msgid "helper %s does not support '--force'"
+msgstr "助手 %s 䏿”¯æŒ '--force'"
#: transport-helper.c
msgid "couldn't run fast-export"
@@ -26099,11 +27154,6 @@ msgstr "åè®® v2 的支æŒå°šæœªå®žçް"
#: transport.c
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "é…ç½® '%s' çš„å–值未知:%s"
-
-#: transport.c
-#, c-format
msgid "transport '%s' not allowed"
msgstr "传输 '%s' ä¸å…许"
@@ -26161,6 +27211,10 @@ msgstr "åè®®ä¸æ”¯æŒ bundle-uri æ“作"
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "æ— æ³•èŽ·å–æœåŠ¡å™¨å…¬å¸ƒçš„ bundle-uri 列表"
+#: transport.c
+msgid "operation not supported by protocol"
+msgstr "åè®®ä¸æ”¯æŒè¯¥æ“作"
+
#: tree-walk.c
msgid "too-short tree object"
msgstr "太短的树对象"
@@ -26470,6 +27524,11 @@ msgid "invalid '..' path segment"
msgstr "无效的 '..' 路径片段"
#: usage.c
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "错误:无法格å¼åŒ–消æ¯ï¼š%s\n"
+
+#: usage.c
msgid "usage: "
msgstr "用法:"
@@ -26613,6 +27672,10 @@ msgstr "ä¸èƒ½è®¿é—® '%s'"
msgid "unable to get current working directory"
msgstr "ä¸èƒ½èŽ·å–当å‰å·¥ä½œç›®å½•"
+#: wrapper.c
+msgid "unable to get random bytes"
+msgstr "无法获å–éšæœºå­—节"
+
#: wt-status.c
msgid "Unmerged paths:"
msgstr "未åˆå¹¶çš„路径:"
@@ -27185,6 +28248,11 @@ msgstr "å¦å¤–ï¼Œæ‚¨çš„ç´¢å¼•ä¸­åŒ…å«æœªæäº¤çš„å˜æ›´ã€‚"
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "ä¸èƒ½%sï¼šæ‚¨çš„ç´¢å¼•ä¸­åŒ…å«æœªæäº¤çš„å˜æ›´ã€‚"
+#: xdiff-interface.c
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "'%2$s' 的未知风格å–值 '%1$s'"
+
#: git-merge-octopus.sh git-merge-resolve.sh
msgid ""
"Error: Your local changes to the following files would be overwritten by "
@@ -27297,6 +28365,10 @@ msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases 和其它选项ä¸å…¼å®¹\n"
#: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases 和 --translate-aliases 是互斥的\n"
+
+#: git-send-email.perl
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -27401,13 +28473,13 @@ msgstr ""
#: git-send-email.perl
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "无法打开 %s: %s"
+msgid "Failed to open %s.final: %s"
+msgstr "无法打开 %s.final: %s"
#: git-send-email.perl
#, perl-format
-msgid "Failed to open %s.final: %s"
-msgstr "无法打开 %s.final: %s"
+msgid "Failed to open %s: %s"
+msgstr "无法打开 %s: %s"
#: git-send-email.perl
msgid "Summary email is empty, skipping it\n"
@@ -27529,29 +28601,29 @@ msgstr "无法å‘é€ %s\n"
#: git-send-email.perl
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "演习å‘é€ %s\n"
+msgid "Dry-Sent %s"
+msgstr "演习å‘é€ %s"
#: git-send-email.perl
#, perl-format
-msgid "Sent %s\n"
-msgstr "æ­£å‘é€ %s\n"
+msgid "Sent %s"
+msgstr "å·²å‘é€ %s"
#: git-send-email.perl
-msgid "Dry-OK. Log says:\n"
-msgstr "演习æˆåŠŸã€‚æ—¥å¿—è¯´ï¼š\n"
+msgid "Dry-OK. Log says:"
+msgstr "演习æˆåŠŸã€‚æ—¥å¿—è¯´ï¼š"
#: git-send-email.perl
-msgid "OK. Log says:\n"
-msgstr "OK。日志说:\n"
+msgid "OK. Log says:"
+msgstr "æˆåŠŸã€‚æ—¥å¿—è¯´ï¼š"
#: git-send-email.perl
msgid "Result: "
msgstr "结果:"
#: git-send-email.perl
-msgid "Result: OK\n"
-msgstr "结果:OK\n"
+msgid "Result: OK"
+msgstr "结果:æˆåŠŸ"
#: git-send-email.perl
#, perl-format
diff --git a/po/zh_TW.po b/po/zh_TW.po
index 6ae75e7e19..5e6818f453 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -1,7 +1,7 @@
# Chinese (traditional) translations for Git package
# Git 套è£è»Ÿé«”çš„ç¹é«”中文翻譯。
# Copyright (C) 2012-2021 Jiang Xin <worldhello.net AT gmail.com>
-# Copyright (C) 2019-2022 Yi-Jyun Pan <pan93412@gmail.com>
+# Copyright (C) 2019-2023 Yi-Jyun Pan <pan93412@gmail.com>
# This file is distributed under the same license as the Git package.
#
# The glossary can be found on https://github.com/l10n-tw/git-glossary
@@ -19,15 +19,19 @@
# - Yichao Yu <yyc1992 AT gmail.com>
# - Zhuang Ya <zhuangya AT me.com>
#
-# Yi-Jyun Pan <pan93412@gmail.com>, 2021, 2022, 2023.
+# Yi-Jyun Pan <pan93412@gmail.com>, 2021, 2022, 2023, 2024.
# Kaiyang Wu <self@origincode.me>, 2022.
-# lumynou5 <lumynou5.tw@gmail.com>, 2023.
+# Lumynous <lumynou5.tw@gmail.com>, 2023, 2024.
+# Kisaragi Hiu <mail@kisaragi-hiu.com>, 2024.
+# Ngoo Ka-iu <willy04wu69@gmail.com>, 2024.
+# Nightfeather Chen <slat@nightfeather.me>, 2024.
+# hms5232 <hms5232@hhming.moe>, 2024.
msgid ""
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-08-20 21:51+0800\n"
-"PO-Revision-Date: 2023-08-20 21:58+0800\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 15:45+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"
@@ -36,7 +40,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.3.2\n"
+"X-Generator: Poedit 3.5\n"
"X-ZhConverter: ç¹åŒ–姬 dict-f4bc617e-r910 @ 2019/11/16 20:23:12 | https://"
"zhconvert.org\n"
@@ -68,7 +72,7 @@ msgstr "æ›´æ–°"
#: add-interactive.c
#, c-format
msgid "could not stage '%s'"
-msgstr "無法暫存 “%sâ€"
+msgstr "無法暫存「%sã€"
#: add-interactive.c builtin/stash.c reset.c sequencer.c
msgid "could not write index"
@@ -88,7 +92,7 @@ msgstr "註:ç¾å·²ä¸å†è¿½è¹¤ %s。\n"
#: add-interactive.c apply.c builtin/checkout.c builtin/reset.c
#, c-format
msgid "make_cache_entry failed for path '%s'"
-msgstr "å° â€œ%s†路徑執行 make_cache_entry 失敗"
+msgstr "å°ã€Œ%sã€è·¯å¾‘執行 make_cache_entry 失敗"
#: add-interactive.c
msgid "Revert"
@@ -124,12 +128,12 @@ msgstr[0] "已加入 %d 個路徑\n"
msgid "ignoring unmerged: %s"
msgstr "忽略未åˆä½µé …目:%s"
-#: add-interactive.c add-patch.c
+#: add-interactive.c
#, c-format
msgid "Only binary files changed.\n"
msgstr "åªæœ‰äºŒé€²ä½æª”案更動了。\n"
-#: add-interactive.c add-patch.c
+#: add-interactive.c
#, c-format
msgid "No changes.\n"
msgstr "沒有更動。\n"
@@ -542,7 +546,7 @@ msgstr ""
#: add-patch.c
#, c-format
msgid "could not parse hunk header '%.*s'"
-msgstr "無法解æžå€å¡Šæ¨™é ­ “%.*sâ€"
+msgstr "無法解æžå€å¡Šæ¨™é ­ã€Œ%.*sã€"
#: add-patch.c
msgid "could not parse diff"
@@ -555,7 +559,7 @@ msgstr "無法解æžä¸Šè‰²éŽçš„差異"
#: add-patch.c
#, c-format
msgid "failed to run '%s'"
-msgstr "無法執行 “%sâ€"
+msgstr "無法執行「%sã€"
#: add-patch.c
msgid "mismatched output from interactive.diffFilter"
@@ -601,12 +605,12 @@ 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"
+"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
-"è¦åˆªé™¤ “%c†開頭的列,請將列首(上下文)改æˆç©ºç™½ã€‚\n"
-"è¦åˆªé™¤ “%c†開頭的列,請直接刪除。\n"
-"開頭是 %c 的列將會被移除。\n"
+"è¦åˆªé™¤ã€Œ%cã€é–‹é ­çš„列,請將列首(上下文)改æˆç©ºç™½ã€‚\n"
+"è¦åˆªé™¤ã€Œ%cã€é–‹é ­çš„列,請直接刪除。\n"
+"開頭是 %s 的列將會被移除。\n"
#: add-patch.c
msgid ""
@@ -624,7 +628,7 @@ msgstr "無法解æžå€å¡Šæ¨™é ­"
#: add-patch.c
msgid "'git apply --cached' failed"
-msgstr "“git apply --cached†失敗"
+msgstr "「git apply --cachedã€å¤±æ•—"
#. TRANSLATORS: do not translate [y/n]
#. The program will only accept that input at this point.
@@ -635,7 +639,7 @@ msgstr "“git apply --cached†失敗"
#: add-patch.c
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
-msgstr "未套用您編輯的å€å¡Šã€‚是å¦é‡æ–°ç·¨è¼¯ï¼ˆè¼¸å…¥ “noâ€ æ¨æ£„ï¼ï¼‰ [y/n]? "
+msgstr "未套用您編輯的å€å¡Šã€‚是å¦é‡æ–°ç·¨è¼¯ï¼ˆè¼¸å…¥ã€Œnoã€æ¨æ£„ï¼ï¼‰ [y/n]? "
#: add-patch.c
msgid "The selected hunks do not apply to the index!"
@@ -659,19 +663,26 @@ msgid ""
"/ - 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"
+"p - print the current hunk, 'P' to use the pager\n"
"? - print help\n"
msgstr ""
-"j - ç¶­æŒæ­¤å€å¡Šæœªæ±ºç‹€æ…‹ï¼Œæª¢è¦–下一個未決定å€å¡Š\n"
-"J - ç¶­æŒæ­¤å€å¡Šæœªæ±ºç‹€æ…‹ï¼Œæª¢è¦–下一個å€å¡Š\n"
-"k - ç¶­æŒæ­¤å€å¡Šæœªæ±ºç‹€æ…‹ï¼Œæª¢è¦–上一個未決定å€å¡Š\n"
-"K - ç¶­æŒæ­¤å€å¡Šæœªæ±ºç‹€æ…‹ï¼Œæª¢è¦–上一個å€å¡Š\n"
+"j - ç¶­æŒæ­¤å€å¡Šæœªæ±ºå®šç‹€æ…‹ï¼Œæª¢è¦–下一個未決定å€å¡Š\n"
+"J - ç¶­æŒæ­¤å€å¡Šæœªæ±ºå®šç‹€æ…‹ï¼Œæª¢è¦–下一個å€å¡Š\n"
+"k - ç¶­æŒæ­¤å€å¡Šæœªæ±ºå®šç‹€æ…‹ï¼Œæª¢è¦–上一個未決定å€å¡Š\n"
+"K - ç¶­æŒæ­¤å€å¡Šæœªæ±ºå®šç‹€æ…‹ï¼Œæª¢è¦–上一個å€å¡Š\n"
"g - 鏿“‡è¦è·³è½‰è‡³çš„å€å¡Š\n"
"/ - å°‹æ‰¾ç¬¦åˆæä¾›ä¹‹å¸¸è¦è¡¨ç¤ºå¼çš„å€å¡Š\n"
"s - 分割目å‰å€å¡Šç‚ºæ›´å°çš„å€å¡Š\n"
"e - 手動編輯目å‰å€å¡Š\n"
+"p - 輸出目å‰å€å¡Šï¼Œã€ŒPã€åˆ†é é¡¯ç¤º\n"
"? - 顯示說明\n"
#: add-patch.c
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "é æœŸæ”¶åˆ°ä¸€å€‹å­—æ¯ï¼Œå»æ”¶åˆ°ã€Œ%sã€"
+
+#: add-patch.c
msgid "No previous hunk"
msgstr "沒有上一個å€å¡Š"
@@ -694,7 +705,7 @@ msgstr "跳轉到哪個å€å¡Š? "
#: add-patch.c
#, c-format
msgid "Invalid number: '%s'"
-msgstr "無效數字:“%sâ€"
+msgstr "無效數字:「%sã€"
#: add-patch.c
#, c-format
@@ -733,8 +744,21 @@ msgid "Sorry, cannot edit this hunk"
msgstr "å°ä¸èµ·ï¼Œç„¡æ³•編輯這個å€å¡Š"
#: add-patch.c
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "未知命令「%sã€ï¼ˆä½¿ç”¨ã€Œ?ã€ç²å–幫助)"
+
+#: add-patch.c
msgid "'git apply' failed"
-msgstr "“git apply†失敗"
+msgstr "「git applyã€å¤±æ•—"
+
+#: add-patch.c
+msgid "No changes."
+msgstr "沒有更動。"
+
+#: add-patch.c
+msgid "Only binary files changed."
+msgstr "åªæœ‰äºŒé€²ä½æª”案更動了。"
#: advice.c
#, c-format
@@ -743,12 +767,12 @@ msgid ""
"Disable this message with \"git config advice.%s false\""
msgstr ""
"\n"
-"請使用 “git config advice.%s false†åœç”¨æ­¤è¨Šæ¯"
+"請使用「git config advice.%s falseã€åœç”¨æ­¤è¨Šæ¯"
#: advice.c
#, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sæç¤ºï¼š%.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sæç¤ºï¼š%s%.*s%s\n"
#: advice.c
msgid "Cherry-picking is not possible because you have unmerged files."
@@ -779,7 +803,7 @@ 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 <file>â€\n"
+"請在工作å€ä¿®æ­£æª”案,然後視情æ³ä½¿ç”¨ã€Œgit add/rm <file>ã€\n"
"命令標記解決方案並æäº¤ã€‚"
#: advice.c
@@ -863,7 +887,7 @@ msgid ""
"false\n"
"\n"
msgstr ""
-"註:切æ›è‡³ “%sâ€ã€‚\n"
+"註:切æ›è‡³ã€Œ%sã€ã€‚\n"
"\n"
"您正處於「分離 HEADã€ç‹€æ…‹ã€‚您å¯ä»¥æª¢è¦–ã€é€²è¡Œå¯¦é©—性修改並æäº¤ï¼Œ\n"
"而且您å¯ä»¥åœ¨åˆ‡å›žåˆ†æ”¯æ™‚ï¼Œæ¨æ£„在此狀態下所åšçš„æäº¤\n"
@@ -898,8 +922,8 @@ msgid ""
"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
msgstr ""
"è‹¥è¦æ›´æ­£é€™äº›è·¯å¾‘的稀ç–狀態,請:\n"
-"* 使用 “git add --sparse <路徑†更新索引\n"
-"* 使用 “git sparse-checkout reapply†套用稀ç–è¦å‰‡"
+"* 使用「git add --sparse <路徑>ã€æ›´æ–°ç´¢å¼•\n"
+"* 使用「git sparse-checkout reapplyã€å¥—用稀ç–è¦å‰‡"
#: alias.c
msgid "cmdline ends with \\"
@@ -910,36 +934,38 @@ msgid "unclosed quote"
msgstr "未閉åˆçš„引號"
#: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c
-#: builtin/receive-pack.c builtin/tag.c
+#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c
msgid "too many arguments"
msgstr "引數éŽå¤š"
#: apply.c
#, c-format
msgid "unrecognized whitespace option '%s'"
-msgstr "空白字元é¸é … “%s†無法識別"
+msgstr "空白字元é¸é …「%sã€ç„¡æ³•識別"
#: apply.c
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
-msgstr "空白字元忽略é¸é … “%s†無法識別"
-
-#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout.c
-#: builtin/clone.c builtin/commit.c builtin/describe.c builtin/diff-tree.c
-#: builtin/difftool.c builtin/fast-export.c builtin/fetch.c builtin/help.c
-#: builtin/index-pack.c builtin/init-db.c builtin/log.c builtin/ls-files.c
-#: builtin/merge-base.c builtin/merge.c builtin/pack-objects.c builtin/push.c
-#: builtin/rebase.c builtin/repack.c builtin/reset.c builtin/rev-list.c
-#: builtin/show-branch.c builtin/stash.c builtin/submodule--helper.c
-#: builtin/tag.c builtin/worktree.c parse-options.c range-diff.c revision.c
+msgstr "空白字元忽略é¸é …「%sã€ç„¡æ³•識別"
+
+#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c
+#: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c
+#: builtin/describe.c builtin/diff-tree.c builtin/difftool.c
+#: builtin/fast-export.c builtin/fetch.c builtin/help.c builtin/index-pack.c
+#: builtin/init-db.c builtin/log.c builtin/ls-files.c builtin/merge-base.c
+#: builtin/merge-tree.c builtin/merge.c builtin/pack-objects.c builtin/rebase.c
+#: builtin/repack.c builtin/replay.c builtin/reset.c builtin/rev-list.c
+#: builtin/rev-parse.c builtin/show-branch.c builtin/stash.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/worktree.c parse-options.c
+#: range-diff.c revision.c
#, c-format
msgid "options '%s' and '%s' cannot be used together"
-msgstr "ç„¡æ³•åŒæ™‚使用 “%s†和 “%s†é¸é …"
+msgstr "ç„¡æ³•åŒæ™‚使用「%sã€å’Œã€Œ%sã€é¸é …"
#: apply.c
#, c-format
msgid "'%s' outside a repository"
-msgstr "“%s†在版本庫之外"
+msgstr "「%sã€åœ¨ç‰ˆæœ¬åº«ä¹‹å¤–"
#: apply.c
msgid "failed to read patch"
@@ -1075,7 +1101,7 @@ msgstr "ç„¡æ³•é–‹å•Ÿæˆ–è®€å– %s"
#: apply.c
#, c-format
msgid "invalid start of line: '%c'"
-msgstr "無效的列首字元:“%câ€"
+msgstr "無效的列首字元:「%cã€"
#: apply.c
#, c-format
@@ -1100,43 +1126,43 @@ msgstr ""
#: apply.c
#, c-format
msgid "missing binary patch data for '%s'"
-msgstr "缺少 “%s†的二進ä½ä¿®è£œæª”資料"
+msgstr "缺少「%sã€çš„二進ä½ä¿®è£œæª”資料"
#: apply.c
#, c-format
msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'"
-msgstr "無法åå‘套用一個缺少至 “%s†的åå‘資料å€å¡Šçš„二進ä½ä¿®è£œæª”"
+msgstr "無法åå‘套用一個缺少至「%sã€çš„åå‘資料å€å¡Šçš„二進ä½ä¿®è£œæª”"
#: apply.c
#, c-format
msgid "cannot apply binary patch to '%s' without full index line"
-msgstr "無法在 “%s†上套用沒有完整索引列的二進ä½ä¿®è£œæª”"
+msgstr "無法在「%sã€ä¸Šå¥—用沒有完整索引列的二進ä½ä¿®è£œæª”"
#: apply.c
#, c-format
msgid ""
"the patch applies to '%s' (%s), which does not match the current contents."
-msgstr "修補檔è¦å¥—用到 “%sâ€ï¼ˆ%s),但與目å‰å…§å®¹ä¸ç¬¦ã€‚"
+msgstr "修補檔è¦å¥—用到「%sã€ï¼ˆ%s),但與目å‰å…§å®¹ä¸ç¬¦ã€‚"
#: apply.c
#, c-format
msgid "the patch applies to an empty '%s' but it is not empty"
-msgstr "修補檔è¦å¥—用至空檔案 “%sâ€ï¼Œä½†å…¶éžç©ºæª”案"
+msgstr "修補檔è¦å¥—用至空檔案「%sã€ï¼Œä½†å…¶éžç©ºæª”案"
#: apply.c
#, c-format
msgid "the necessary postimage %s for '%s' cannot be read"
-msgstr "ç„¡æ³•è®€å– â€œ%2$s†必須的目標檔案 %1$s"
+msgstr "無法讀å–「%2$sã€å¿…須的目標檔案 %1$s"
#: apply.c
#, c-format
msgid "binary patch does not apply to '%s'"
-msgstr "二進ä½ä¿®è£œæª”未套用到 “%sâ€"
+msgstr "二進ä½ä¿®è£œæª”未套用到「%sã€"
#: apply.c
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
-msgstr "修補 “%s†的二進ä½ä¿®è£œæª”ï¼Œç”¢ç”Ÿäº†ä¸æ­£ç¢ºçš„çµæžœï¼ˆé æœŸ %s,å»ç‚º %s)"
+msgstr "修補「%sã€çš„二進ä½ä¿®è£œæª”ï¼Œç”¢ç”Ÿäº†ä¸æ­£ç¢ºçš„çµæžœï¼ˆé æœŸ %s,å»ç‚º %s)"
#: apply.c
#, c-format
@@ -1156,7 +1182,7 @@ msgstr "ç„¡æ³•è®€å– %s"
#: apply.c
#, c-format
msgid "reading from '%s' beyond a symbolic link"
-msgstr "讀å–符號連çµèƒŒå¾Œçš„ “%sâ€"
+msgstr "讀å–符號連çµèƒŒå¾Œçš„「%sã€"
#: apply.c
#, c-format
@@ -1185,7 +1211,7 @@ msgstr "正在進行三方åˆä½µâ€¦â€¦\n"
#: apply.c
#, c-format
msgid "cannot read the current contents of '%s'"
-msgstr "ç„¡æ³•è®€å– â€œ%s†目å‰çš„內容"
+msgstr "無法讀å–「%sã€ç›®å‰çš„內容"
#: apply.c
#, c-format
@@ -1195,12 +1221,12 @@ msgstr "無法進行三方åˆä½µâ€¦â€¦\n"
#: apply.c
#, c-format
msgid "Applied patch to '%s' with conflicts.\n"
-msgstr "å·²å¥—ç”¨å° â€œ%s†的修補檔,但有è¡çªã€‚\n"
+msgstr "已套用å°ã€Œ%sã€çš„修補檔,但有è¡çªã€‚\n"
#: apply.c
#, c-format
msgid "Applied patch to '%s' cleanly.\n"
-msgstr "å·²å®Œå…¨å¥—ç”¨å° â€œ%s†的修補檔。\n"
+msgstr "已完全套用å°ã€Œ%sã€çš„修補檔。\n"
#: apply.c
#, c-format
@@ -1224,7 +1250,7 @@ msgstr "%s 的類型是 %oï¼Œé æœŸæ˜¯ %o"
#: apply.c read-cache.c
#, c-format
msgid "invalid path '%s'"
-msgstr "路徑 “%s†無效"
+msgstr "路徑「%sã€ç„¡æ•ˆ"
#: apply.c
#, c-format
@@ -1239,17 +1265,17 @@ msgstr "%s:已存在於工作å€ä¸­"
#: apply.c
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
-msgstr "%2$s çš„æ–°æ¨¡å¼ (%1$o) å’ŒèˆŠæ¨¡å¼ (%3$o) ä¸ç¬¦"
+msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和舊模å¼ï¼ˆ%3$o)ä¸ç¬¦"
#: apply.c
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
-msgstr "%2$s çš„æ–°æ¨¡å¼ (%1$o) å’Œ %4$s çš„èˆŠæ¨¡å¼ (%3$o) ä¸ç¬¦"
+msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和 %4$s 的舊模å¼ï¼ˆ%3$o)ä¸ç¬¦"
#: apply.c
#, c-format
msgid "affected file '%s' is beyond a symbolic link"
-msgstr "å—影響的檔案 “%s†在符號連çµå¾Œ"
+msgstr "å—影響的檔案「%sã€åœ¨ç¬¦è™Ÿé€£çµå¾Œ"
#: apply.c
#, c-format
@@ -1299,7 +1325,7 @@ msgstr "修補 %s å­æ¨¡çµ„的修補檔æå£ž"
#: apply.c
#, c-format
msgid "unable to stat newly created file '%s'"
-msgstr "無法å°å‰›å»ºç«‹çš„æª”案 “%s†執行 stat"
+msgstr "無法å°å‰›å»ºç«‹çš„æª”案「%sã€åŸ·è¡Œ stat"
#: apply.c
#, c-format
@@ -1314,17 +1340,17 @@ msgstr "無法為 %s 加入快å–é …ç›®"
#: apply.c builtin/bisect.c builtin/gc.c
#, c-format
msgid "failed to write to '%s'"
-msgstr "無法寫入 “%sâ€"
+msgstr "無法寫入「%sã€"
#: apply.c
#, c-format
msgid "closing file '%s'"
-msgstr "關閉檔案 “%sâ€"
+msgstr "關閉檔案「%sã€"
#: apply.c
#, c-format
msgid "unable to write file '%s' mode %o"
-msgstr "ç„¡æ³•ä»¥æ¨¡å¼ %2$o 寫入 “%1$s†檔案"
+msgstr "ç„¡æ³•ä»¥æ¨¡å¼ %2$o 寫入「%1$sã€æª”案"
#: apply.c
#, c-format
@@ -1343,18 +1369,13 @@ msgstr[0] "套用 %%s 個修補檔,其中 %d 個被拒絕……"
#: apply.c
#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "正在將 .rej 檔案å稱截短為 %.*s.rej"
-
-#: apply.c
-#, c-format
msgid "cannot open %s"
msgstr "無法開啟 %s"
#: apply.c rerere.c
#, c-format
msgid "cannot unlink '%s'"
-msgstr "無法刪除 “%sâ€"
+msgstr "無法刪除「%sã€"
#: apply.c
#, c-format
@@ -1369,11 +1390,11 @@ msgstr "拒絕第 #%d 個å€å¡Šã€‚"
#: apply.c
#, c-format
msgid "Skipped patch '%s'."
-msgstr "ç•¥éŽä¿®è£œæª” “%sâ€ã€‚"
+msgstr "ç•¥éŽä¿®è£œæª”「%sã€ã€‚"
#: apply.c
msgid "No valid patches in input (allow with \"--allow-empty\")"
-msgstr "輸入沒有有效的修補檔內容(傳入 “--allow-empty†å…許此行為)"
+msgstr "輸入沒有有效的修補檔內容(傳入「--allow-emptyã€å…許此行為)"
#: apply.c t/helper/test-cache-tree.c
msgid "unable to read index file"
@@ -1382,7 +1403,7 @@ msgstr "無法讀å–索引檔案"
#: apply.c
#, c-format
msgid "can't open patch '%s': %s"
-msgstr "無法開啟修補檔 “%sâ€ï¼š%s"
+msgstr "無法開啟修補檔「%sã€ï¼š%s"
#: apply.c
#, c-format
@@ -1402,7 +1423,7 @@ msgid "%d line applied after fixing whitespace errors."
msgid_plural "%d lines applied after fixing whitespace errors."
msgstr[0] "修正空白誤用後,套用了 %d 列。"
-#: apply.c builtin/add.c builtin/mv.c builtin/rm.c
+#: apply.c builtin/mv.c builtin/rm.c
msgid "Unable to write new index file"
msgstr "無法寫入新索引檔案"
@@ -1466,6 +1487,18 @@ msgstr "亦套用修補檔(與 --stat/--summary/--check é¸é …åŒæ™‚使用)"
msgid "attempt three-way merge, fall back on normal patch if that fails"
msgstr "嘗試三方åˆä½µï¼Œè‹¥å¤±æ•—則回到正常修補模å¼"
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "如果è¡çªï¼Œä½¿ç”¨æˆ‘們的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "如果è¡çªï¼Œä½¿ç”¨ä»–們的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "如果è¡çªï¼Œä½¿ç”¨è¯åˆç‰ˆæœ¬"
+
#: apply.c
msgid "build a temporary index based on embedded index information"
msgstr "組建以嵌入索引資訊為基礎的暫存索引"
@@ -1527,6 +1560,10 @@ msgstr "在所有檔案å稱å‰åŠ ä¸Š <root>"
msgid "don't return error for empty patches"
msgstr "é‡åˆ°ç©ºç™½ä¿®è£œæª”時,ä¸å›žå‚³éŒ¯èª¤"
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--oursã€--theirs å’Œ --union éœ€è¦ --3way"
+
#: archive-tar.c archive-zip.c
#, c-format
msgid "cannot stream blob %s"
@@ -1545,7 +1582,7 @@ msgstr "壓縮錯誤 (%d)"
#: archive-tar.c
#, c-format
msgid "unable to start '%s' filter"
-msgstr "無法啟動 “%sâ€ éŽæ¿¾å™¨"
+msgstr "無法啟動「%sã€éŽæ¿¾å™¨"
#: archive-tar.c
msgid "unable to redirect descriptor"
@@ -1554,7 +1591,7 @@ msgstr "ç„¡æ³•é‡æ–°å°Žå‘æè¿°å…ƒ"
#: archive-tar.c
#, c-format
msgid "'%s' filter reported error"
-msgstr "“%sâ€ éŽæ¿¾å™¨å›žå ±éŒ¯èª¤"
+msgstr "「%sã€éŽæ¿¾å™¨å›žå ±éŒ¯èª¤"
#: archive-zip.c
#, c-format
@@ -1588,17 +1625,17 @@ msgstr "git archive --remote <repo> [--exec <cmd>] --list"
#: archive.c builtin/gc.c builtin/notes.c builtin/tag.c
#, c-format
msgid "cannot read '%s'"
-msgstr "ç„¡æ³•è®€å– â€œ%sâ€"
+msgstr "無法讀å–「%sã€"
#: archive.c
#, c-format
msgid "pathspec '%s' matches files outside the current directory"
-msgstr "符åˆè·¯å¾‘è¦æ ¼ “%s†的檔案在目å‰ç›®éŒ„之外"
+msgstr "符åˆè·¯å¾‘è¦æ ¼ã€Œ%sã€çš„æª”案在目å‰ç›®éŒ„之外"
#: archive.c builtin/add.c builtin/rm.c
#, c-format
msgid "pathspec '%s' did not match any files"
-msgstr "è·¯å¾‘è¦æ ¼ “%s†未符åˆä»»ä½•檔案"
+msgstr "è·¯å¾‘è¦æ ¼ã€Œ%sã€æœªç¬¦åˆä»»ä½•檔案"
#: archive.c
#, c-format
@@ -1617,6 +1654,11 @@ msgstr "éžæ¨¹ç‹€ç‰©ä»¶ï¼š%s"
#: archive.c
#, c-format
+msgid "failed to unpack tree object %s"
+msgstr "解包 %s 樹狀物件失敗"
+
+#: archive.c
+#, c-format
msgid "File not found: %s"
msgstr "找ä¸åˆ°æª”案:%s"
@@ -1628,17 +1670,17 @@ msgstr "䏿˜¯ä¸€èˆ¬æª”案:%s"
#: archive.c
#, c-format
msgid "unclosed quote: '%s'"
-msgstr "未閉åˆçš„引號:“%sâ€"
+msgstr "未閉åˆçš„引號:「%sã€"
#: archive.c
#, c-format
msgid "missing colon: '%s'"
-msgstr "缺少冒號:“%sâ€"
+msgstr "缺少冒號:「%sã€"
#: archive.c
#, c-format
msgid "empty file name: '%s'"
-msgstr "檔案å稱空白:“%sâ€"
+msgstr "檔案å稱空白:「%sã€"
#: archive.c
msgid "fmt"
@@ -1725,21 +1767,26 @@ msgstr "éžé æœŸé¸é … --remote"
#: revision.c
#, c-format
msgid "the option '%s' requires '%s'"
-msgstr "“%s†é¸é …éœ€è¦ â€œ%sâ€"
+msgstr "「%sã€é¸é …需è¦ã€Œ%sã€"
#: archive.c
msgid "Unexpected option --output"
msgstr "éžé æœŸé¸é … --output"
+#: archive.c t/unit-tests/unit-test.c
+#, c-format
+msgid "extra command line parameter '%s'"
+msgstr "å¤šå‡ºå‘½ä»¤åˆ—åƒæ•¸ã€Œ%sã€"
+
#: archive.c
#, c-format
msgid "Unknown archive format '%s'"
-msgstr "å°å­˜æ ¼å¼ “%s†未知"
+msgstr "å°å­˜æ ¼å¼ã€Œ%sã€æœªçŸ¥"
#: archive.c
#, c-format
msgid "Argument not supported for format '%s': -%d"
-msgstr "å¼•æ•¸ä¸æ”¯æ´ “%s†格å¼ï¼š-%d"
+msgstr "å¼•æ•¸ä¸æ”¯æ´ã€Œ%sã€æ ¼å¼ï¼š-%d"
#: attr.c
#, c-format
@@ -1766,31 +1813,46 @@ msgid ""
"Use '\\!' for literal leading exclamation."
msgstr ""
"git attributes 會忽略å呿¨¡å¼\n"
-"當字串確定è¦ä»¥é©šå˜†è™Ÿé–‹å§‹æ™‚,請使用 “\\!â€ã€‚"
+"當字串確定è¦ä»¥é©šå˜†è™Ÿé–‹å§‹æ™‚,請使用「\\!ã€ã€‚"
#: attr.c
#, c-format
msgid "cannot fstat gitattributes file '%s'"
-msgstr "無法 fstat gitattributes 檔案 “%sâ€"
+msgstr "無法 fstat gitattributes 檔案「%sã€"
#: attr.c
#, c-format
msgid "ignoring overly large gitattributes file '%s'"
-msgstr "忽略éŽå¤§çš„ gitattributes 檔案 “%sâ€"
+msgstr "忽略éŽå¤§çš„ gitattributes 檔案「%sã€"
#: attr.c
#, c-format
msgid "ignoring overly large gitattributes blob '%s'"
-msgstr "忽略éŽå¤§çš„ gitattributes 資料物件 “%sâ€"
+msgstr "忽略éŽå¤§çš„ gitattributes 資料物件「%sã€"
+
+#: attr.c
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "沒有版本庫無法使用 --attr-source 或 GIT_ATTR_SOURCE"
#: attr.c
msgid "bad --attr-source or GIT_ATTR_SOURCE"
msgstr "無效的 --attr-source 或 GIT_ATTR_SOURCE"
+#: attr.c read-cache.c
+#, c-format
+msgid "unable to stat '%s'"
+msgstr "無法統計「%sã€"
+
+#: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
+#, c-format
+msgid "unable to read %s"
+msgstr "ç„¡æ³•è®€å– %s"
+
#: bisect.c
#, c-format
msgid "Badly quoted content in file '%s': %s"
-msgstr "檔案 “%s†包å«ç„¡æ•ˆçš„引用內容:%s"
+msgstr "檔案「%sã€åŒ…å«ç„¡æ•ˆçš„引用內容:%s"
#: bisect.c
#, c-format
@@ -1827,7 +1889,7 @@ msgid ""
"This means the first '%s' commit is between %s and [%s].\n"
msgstr ""
"åˆä½µåŸºç¤Ž %s 是 %s。\n"
-"這æ„味著第一個 “%s†æäº¤ä½æ–¼ %s å’Œ [%s] 之間。\n"
+"這æ„味著第一個「%sã€æäº¤ä½æ–¼ %s å’Œ [%s] 之間。\n"
#: bisect.c
#, c-format
@@ -1864,12 +1926,17 @@ msgstr "需è¦ä¸€å€‹ %s 修訂版"
#: bisect.c
#, c-format
msgid "could not create file '%s'"
-msgstr "無法建立 “%s†檔案"
+msgstr "無法建立「%sã€æª”案"
+
+#: bisect.c builtin/notes.c
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "無法為物件「%sã€é–‹å§‹ã€Œshowã€"
#: bisect.c builtin/merge.c
#, c-format
msgid "could not read file '%s'"
-msgstr "ç„¡æ³•è®€å– â€œ%s†檔案"
+msgstr "無法讀å–「%sã€æª”案"
#: bisect.c
msgid "reading bisect refs failed"
@@ -1912,9 +1979,9 @@ msgstr "--contents å’Œ --reverse ä¸èƒ½æ··ç”¨ã€‚"
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 remote.c
-#: sequencer.c submodule.c
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
+#: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
+#: remote.c sequencer.c submodule.c
msgid "revision walk setup failed"
msgstr "ä¿®è¨‚ç‰ˆéæ­·è¨­å®šå¤±æ•—"
@@ -1942,22 +2009,22 @@ msgstr "請求é‡å®šåŸºåº•時,無法繼承多個引用的上游追蹤設定"
#: branch.c
#, c-format
msgid "not setting branch '%s' as its own upstream"
-msgstr "未將 “%s†分支設為其自己的上游"
+msgstr "未將「%sã€åˆ†æ”¯è¨­ç‚ºå…¶è‡ªå·±çš„上游"
#: branch.c
#, c-format
msgid "branch '%s' set up to track '%s' by rebasing."
-msgstr "已藉由é‡è¨‚基底,將 “%s†分支設定為追蹤 “%sâ€ã€‚"
+msgstr "已藉由é‡è¨‚基底,將「%sã€åˆ†æ”¯è¨­å®šç‚ºè¿½è¹¤ã€Œ%sã€ã€‚"
#: branch.c
#, c-format
msgid "branch '%s' set up to track '%s'."
-msgstr "已將 “%s†分支設定為追蹤 “%sâ€ã€‚"
+msgstr "已將「%sã€åˆ†æ”¯è¨­å®šç‚ºè¿½è¹¤ã€Œ%sã€ã€‚"
#: branch.c
#, c-format
msgid "branch '%s' set up to track:"
-msgstr "“%s†分支已設定追蹤:"
+msgstr "「%sã€åˆ†æ”¯å·²è¨­å®šè¿½è¹¤ï¼š"
#: branch.c
msgid "unable to write upstream branch configuration"
@@ -1976,17 +2043,17 @@ msgstr ""
#: branch.c
#, c-format
msgid "asked to inherit tracking from '%s', but no remote is set"
-msgstr "請求繼承 “%s†的追蹤設定,但未設定é ç«¯"
+msgstr "請求繼承「%sã€çš„追蹤設定,但未設定é ç«¯"
#: branch.c
#, c-format
msgid "asked to inherit tracking from '%s', but no merge configuration is set"
-msgstr "請求繼承 “%s†的追蹤設定,但未設定åˆä½µè¨­å®š"
+msgstr "請求繼承「%sã€çš„追蹤設定,但未設定åˆä½µè¨­å®š"
#: branch.c
#, c-format
msgid "not tracking: ambiguous information for ref '%s'"
-msgstr "未追蹤:“%s†引用有歧義"
+msgstr "未追蹤:「%sã€å¼•用有歧義"
# 譯者:為ä¿è­‰åœ¨è¼¸å‡ºä¸­å°é½Šï¼Œæ³¨æ„調整å¥ä¸­ç©ºæ ¼ï¼
#. TRANSLATORS: This is a line listing a remote with duplicate
@@ -2019,7 +2086,7 @@ msgid ""
"tracking namespaces."
msgstr ""
"有多個é ç«¯çš„æŠ“å–å¼•ç”¨è¦æ ¼ï¼Œæ˜ å°„到\n"
-"é ç«¯è¿½è¹¤å¼•用 “%sâ€ çš„è¦æ ¼ï¼š\n"
+"é ç«¯è¿½è¹¤å¼•用「%sã€çš„è¦æ ¼ï¼š\n"
"%s\n"
"這通常是設定錯誤。\n"
"\n"
@@ -2029,27 +2096,31 @@ msgstr ""
#: branch.c
#, c-format
msgid "'%s' is not a valid branch name"
-msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„分支å稱"
+msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„分支å稱"
+
+#: branch.c builtin/branch.c
+msgid "See `man git check-ref-format`"
+msgstr "è«‹åƒé–±ã€Œman git check-ref-formatã€"
#: branch.c
#, c-format
msgid "a branch named '%s' already exists"
-msgstr "已有åŒå “%s†分支"
+msgstr "已有åŒå「%sã€åˆ†æ”¯"
#: branch.c
#, c-format
msgid "cannot force update the branch '%s' used by worktree at '%s'"
-msgstr "ç„¡æ³•å¼·åˆ¶æ›´æ–°è¢«ä½æ–¼ “%2$s†的工作å€ä½¿ç”¨çš„ “%1$s†分支"
+msgstr "ç„¡æ³•å¼·åˆ¶æ›´æ–°è¢«ä½æ–¼ã€Œ%2$sã€çš„工作å€ä½¿ç”¨çš„分支「%1$sã€"
#: branch.c
#, c-format
msgid "cannot set up tracking information; starting point '%s' is not a branch"
-msgstr "無法設定追蹤資訊:起始點 “%sâ€ ä¸æ˜¯åˆ†æ”¯"
+msgstr "無法設定追蹤資訊:起始點「%sã€ä¸æ˜¯åˆ†æ”¯"
#: branch.c
#, c-format
msgid "the requested upstream branch '%s' does not exist"
-msgstr "請求的上游分支 “%s†ä¸å­˜åœ¨"
+msgstr "請求的上游分支「%sã€ä¸å­˜åœ¨"
#: branch.c
msgid ""
@@ -2073,22 +2144,22 @@ msgstr ""
#: branch.c builtin/replace.c
#, c-format
msgid "not a valid object name: '%s'"
-msgstr "物件å稱無效:“%sâ€"
+msgstr "物件å稱無效:「%sã€"
#: branch.c
#, c-format
msgid "ambiguous object name: '%s'"
-msgstr "物件å稱有歧義:“%sâ€"
+msgstr "物件å稱有歧義:「%sã€"
#: branch.c
#, c-format
msgid "not a valid branch point: '%s'"
-msgstr "分支點無效:“%sâ€"
+msgstr "分支點無效:「%sã€"
#: branch.c
#, c-format
msgid "submodule '%s': unable to find submodule"
-msgstr "“%sâ€ å­æ¨¡çµ„:找ä¸åˆ°å­æ¨¡çµ„"
+msgstr "「%sã€å­æ¨¡çµ„:找ä¸åˆ°å­æ¨¡çµ„"
#: branch.c
#, c-format
@@ -2096,18 +2167,18 @@ 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â€ å‘½ä»¤å˜—è©¦æ›´æ–°å­æ¨¡çµ„"
+"您å¯ä»¥ä½¿ç”¨ã€Œgit checkout --no-recurse-submodules %s && git submodule update "
+"--initã€å‘½ä»¤å˜—è©¦æ›´æ–°å­æ¨¡çµ„"
#: branch.c
#, c-format
msgid "submodule '%s': cannot create branch '%s'"
-msgstr "“%sâ€ å­æ¨¡çµ„:無法建立 “%s†分支"
+msgstr "「%sã€å­æ¨¡çµ„:無法建立「%sã€åˆ†æ”¯"
#: branch.c
#, c-format
-msgid "'%s' is already checked out at '%s'"
-msgstr "“%s†已在 “%s†點簽出"
+msgid "'%s' is already used by worktree at '%s'"
+msgstr "「%sã€å·²è¢«ä½æ–¼ã€Œ%sã€çš„工作å€ä½¿ç”¨"
#: builtin/add.c
msgid "git add [<options>] [--] <pathspec>..."
@@ -2123,38 +2194,26 @@ 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"
+msgid "could not read the index"
msgstr "無法讀å–索引"
#: builtin/add.c
-msgid "Could not write patch"
-msgstr "無法寫入修補檔"
-
-#: builtin/add.c
msgid "editing patch failed"
msgstr "編輯修補檔失敗"
-#: builtin/add.c
+#: builtin/add.c read-cache.c
#, c-format
-msgid "Could not stat '%s'"
-msgstr "ä¸èƒ½å° “%s†執行 stat"
+msgid "could not stat '%s'"
+msgstr "無法統計「%sã€"
#: builtin/add.c
-msgid "Empty patch. Aborted."
-msgstr "修補檔空白。中止。"
+msgid "empty patch. aborted"
+msgstr "修補檔空白。中止"
#: builtin/add.c
#, c-format
-msgid "Could not apply '%s'"
-msgstr "無法套用 “%sâ€"
+msgid "could not apply '%s'"
+msgstr "無法套用「%sã€"
#: builtin/add.c
msgid "The following paths are ignored by one of your .gitignore files:\n"
@@ -2168,7 +2227,7 @@ msgstr "測試執行"
#: builtin/add.c builtin/check-ignore.c builtin/commit.c
#: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
-#: builtin/read-tree.c
+#: builtin/read-tree.c builtin/refs.c
msgid "be verbose"
msgstr "詳細輸出"
@@ -2261,7 +2320,7 @@ msgstr ""
"\n"
"\tgit rm --cached %s\n"
"\n"
-"åƒè¦‹ “git help submodule†深入了解。"
+"åƒè¦‹ã€Œgit help submoduleã€æ·±å…¥äº†è§£ã€‚"
#: builtin/add.c
#, c-format
@@ -2269,14 +2328,8 @@ msgid "adding embedded git repository: %s"
msgstr "æ­£åœ¨åŠ å…¥åµŒå…¥å¼ git 版本庫:%s"
#: builtin/add.c
-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 "Use -f if you really want to add them."
+msgstr "如果您確定想è¦åŠ å…¥å®ƒå€‘ï¼Œè«‹ä½¿ç”¨ -f。"
#: builtin/add.c
msgid "adding files failed"
@@ -2285,13 +2338,13 @@ msgstr "加入檔案失敗"
#: builtin/add.c
#, c-format
msgid "--chmod param '%s' must be either -x or +x"
-msgstr "--chmod çš„åƒæ•¸ “%s†必須是 -x 或 +x"
+msgstr "--chmod çš„åƒæ•¸ã€Œ%sã€å¿…須是 -x 或 +x"
#: builtin/add.c builtin/checkout.c builtin/commit.c builtin/reset.c
#: builtin/rm.c builtin/stash.c
#, c-format
msgid "'%s' and pathspec arguments cannot be used together"
-msgstr "“%sâ€ å’Œè·¯å¾‘è¦æ ¼å¼•數ä¸å¾—åŒæ™‚使用"
+msgstr "「%sã€å’Œè·¯å¾‘è¦æ ¼å¼•數ä¸å¾—åŒæ™‚使用"
#: builtin/add.c
#, c-format
@@ -2299,14 +2352,8 @@ msgid "Nothing specified, nothing added.\n"
msgstr "沒有指定,亦未加入檔案。\n"
#: builtin/add.c
-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 "Maybe you wanted to say 'git add .'?"
+msgstr "也許您想è¦åŸ·è¡Œçš„æ˜¯ã€Œgit add .ã€ï¼Ÿ"
#: builtin/add.c builtin/check-ignore.c builtin/checkout.c builtin/clean.c
#: builtin/commit.c builtin/diff-tree.c builtin/grep.c builtin/mv.c
@@ -2315,22 +2362,27 @@ msgstr ""
msgid "index file corrupt"
msgstr "索引檔案æå£ž"
+#: builtin/add.c builtin/am.c builtin/checkout.c builtin/clone.c
+#: builtin/commit.c builtin/stash.c merge.c rerere.c
+msgid "unable to write new index file"
+msgstr "無法寫入新的索引檔案"
+
#: builtin/am.c builtin/mailinfo.c mailinfo.c
#, c-format
msgid "bad action '%s' for '%s'"
-msgstr "“%sâ€ å‹•ä½œå° â€œ%s†無效"
+msgstr "「%sã€å‹•作å°ã€Œ%sã€ç„¡æ•ˆ"
#: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c
-#: builtin/pull.c diff-merges.c gpg-interface.c ls-refs.c parallel-checkout.c
-#: sequencer.c setup.c
+#: builtin/pull.c builtin/revert.c config.c diff-merges.c gpg-interface.c
+#: ls-refs.c parallel-checkout.c sequencer.c setup.c
#, c-format
msgid "invalid value for '%s': '%s'"
-msgstr "“%s†的值無效:“%sâ€"
+msgstr "「%sã€çš„值無效:「%sã€"
#: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
#, c-format
msgid "could not read '%s'"
-msgstr "ç„¡æ³•è®€å– â€œ%sâ€"
+msgstr "無法讀å–「%sã€"
#: builtin/am.c
msgid "could not parse author script"
@@ -2344,17 +2396,17 @@ msgstr "ç„¡æ³•è§£æž %s"
#: builtin/am.c
#, c-format
msgid "'%s' was deleted by the applypatch-msg hook"
-msgstr "“%s†被 applypatch-msg 掛鉤刪除"
+msgstr "「%sã€è¢« applypatch-msg 掛鉤刪除"
#: builtin/am.c
#, c-format
msgid "Malformed input line: '%s'."
-msgstr "æ ¼å¼éŒ¯èª¤çš„輸入列:“%sâ€ã€‚"
+msgstr "æ ¼å¼éŒ¯èª¤çš„輸入列:「%sã€ã€‚"
#: builtin/am.c
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
-msgstr "從 “%s†拷è²è¨»è§£åˆ° “%s†失敗"
+msgstr "從「%sã€æ‹·è²è¨»è§£åˆ°ã€Œ%sã€å¤±æ•—"
#: builtin/am.c
msgid "fseek failed"
@@ -2363,17 +2415,17 @@ msgstr "fseek 失敗"
#: builtin/am.c builtin/rebase.c sequencer.c wrapper.c
#, c-format
msgid "could not open '%s' for reading"
-msgstr "無法開啟 “%s†進行讀å–"
+msgstr "無法開啟「%sã€é€²è¡Œè®€å–"
#: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c
#, c-format
msgid "could not open '%s' for writing"
-msgstr "無法開啟 “%s†進行寫入"
+msgstr "無法開啟「%sã€é€²è¡Œå¯«å…¥"
#: builtin/am.c
#, c-format
msgid "could not parse patch '%s'"
-msgstr "無法解æžä¿®è£œæª” “%sâ€"
+msgstr "無法解æžä¿®è£œæª”「%sã€"
#: builtin/am.c
msgid "Only one StGIT patch series can be applied at once"
@@ -2398,7 +2450,7 @@ msgstr "修補檔格å¼åµæ¸¬å¤±æ•—。"
#: builtin/am.c builtin/clone.c
#, c-format
msgid "failed to create directory '%s'"
-msgstr "無法建立目錄 “%sâ€"
+msgstr "無法建立目錄「%sã€"
#: builtin/am.c
msgid "Failed to split patches."
@@ -2406,23 +2458,24 @@ msgstr "無法切割修補檔。"
#: builtin/am.c
#, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "解決此å•題後,請執行 “%s --continueâ€ã€‚"
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "解決此å•題後,請執行「%s --continueã€ã€‚\n"
#: builtin/am.c
#, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "è‹¥è¦ç•¥éŽæ­¤ä¿®è£œï¼Œè«‹æ”¹åŸ·è¡Œ “%s --skipâ€ã€‚"
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr "è‹¥è¦ç•¥éŽæ­¤ä¿®è£œï¼Œè«‹æ”¹åŸ·è¡Œã€Œ%s --skipã€ã€‚\n"
#: builtin/am.c
#, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
-msgstr "è‹¥è¦å°‡ç©ºç™½ä¿®è£œæª”錄入為空白æäº¤ï¼Œè«‹åŸ·è¡Œ “%s --allow-emptyâ€ã€‚"
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
+msgstr "è‹¥è¦å°‡ç©ºç™½ä¿®è£œæª”錄入為空白æäº¤ï¼Œè«‹åŸ·è¡Œã€Œ%s --allow-emptyã€ã€‚\n"
#: builtin/am.c
#, c-format
msgid "To restore the original branch and stop patching, run \"%s --abort\"."
-msgstr "è‹¥è¦é‚„åŽŸè‡³åŽŸå§‹åˆ†æ”¯ï¼Œä¸¦åœæ­¢ä¿®è£œå‹•作,請執行 “%s --abortâ€ã€‚"
+msgstr "è‹¥è¦é‚„åŽŸè‡³åŽŸå§‹åˆ†æ”¯ï¼Œä¸¦åœæ­¢ä¿®è£œå‹•作,請執行「%s --abortã€ã€‚"
#: builtin/am.c
msgid "Patch sent with format=flowed; space at the end of lines might be lost."
@@ -2475,8 +2528,7 @@ msgstr "git write-tree 無法寫入樹狀物件"
msgid "applying to an empty history"
msgstr "正在套用至空白歷å²è¨˜éŒ„上"
-#: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
-#: t/helper/test-fast-rebase.c
+#: builtin/am.c builtin/commit.c builtin/merge.c builtin/replay.c sequencer.c
msgid "failed to write commit object"
msgstr "無法寫入æäº¤ç‰©ä»¶"
@@ -2538,7 +2590,7 @@ msgstr "在 %s %.*s 處修補失敗"
#: builtin/am.c
msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
-msgstr "使用 “git am --show-current-patch=diff†命令檢視失敗的修補檔"
+msgstr "使用「git am --show-current-patch=diffã€å‘½ä»¤æª¢è¦–失敗的修補檔"
#: builtin/am.c
msgid "No changes - recorded it as an empty commit."
@@ -2550,7 +2602,7 @@ msgid ""
"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"
+"沒有變更:是å¦å¿˜è¨˜åŸ·è¡Œã€Œgit addã€ï¼Ÿ\n"
"å¦‚æžœæ²’æœ‰å…¶ä»–è¦æ–°å¢žåˆ°æš«å­˜å€çš„,則很å¯èƒ½æ˜¯å…¶å®ƒæäº¤\n"
"已經引入了相åŒçš„變更。您也許想è¦ç•¥éŽé€™å€‹ä¿®è£œæª”。"
@@ -2565,15 +2617,10 @@ msgstr ""
"您應該å°å·²ç¶“解決è¡çªçš„æ¯ä¸€å€‹æª”æ¡ˆåŸ·è¡Œ `git add`,標記為已經完æˆã€‚\n"
"ä½ å¯ä»¥å°ã€Œç”±ä»–們刪除ã€çš„æª”案,執行 `git rm` 指令。"
-#: builtin/am.c builtin/checkout.c builtin/clone.c builtin/stash.c merge.c
-#: rerere.c
-msgid "unable to write new index file"
-msgstr "無法寫入新的索引檔案"
-
#: builtin/am.c builtin/reset.c
#, c-format
msgid "Could not parse object '%s'."
-msgstr "ç„¡æ³•è§£æž â€œ%s†物件。"
+msgstr "無法解æžã€Œ%sã€ç‰©ä»¶ã€‚"
#: builtin/am.c
msgid "failed to clean index"
@@ -2584,18 +2631,13 @@ msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
msgstr ""
-"您似乎在上一次 “am†失敗後移動了 HEAD。\n"
+"您似乎在上一次「amã€å¤±æ•—後移動了 HEAD。\n"
"未倒轉回 ORIG_HEAD"
-#: builtin/am.c builtin/bisect.c worktree.c
+#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c
#, c-format
msgid "failed to read '%s'"
-msgstr "ç„¡æ³•è®€å– â€œ%sâ€"
-
-#: builtin/am.c
-#, c-format
-msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "“%s=%s†和 “%s=%s†é¸é …ä¸å¾—åŒæ™‚使用"
+msgstr "無法讀å–「%sã€"
#: builtin/am.c
msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
@@ -2669,8 +2711,9 @@ msgid "n"
msgstr "n"
#: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
-#: builtin/diagnose.c builtin/for-each-ref.c builtin/ls-files.c
-#: builtin/ls-tree.c builtin/replace.c builtin/tag.c builtin/verify-tag.c
+#: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
+#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
msgid "format"
msgstr "format"
@@ -2707,6 +2750,10 @@ msgid "show the patch being applied"
msgstr "顯示正在套用的修補檔"
#: builtin/am.c
+msgid "try to apply current patch again"
+msgstr "冿¬¡å˜—試套用目å‰ä¿®è£œæª”"
+
+#: builtin/am.c
msgid "record the empty patch as an empty commit"
msgstr "將空白修補檔錄入為空白æäº¤"
@@ -2759,7 +2806,7 @@ msgid ""
"Use \"git am --abort\" to remove it."
msgstr ""
"發ç¾å¤±æ•£çš„ %s 目錄。\n"
-"使用 “git am --abort†移除。"
+"使用「git am --abortã€ç§»é™¤ã€‚"
#: builtin/am.c
msgid "Resolve operation not in progress, we are not resuming."
@@ -2778,10 +2825,6 @@ msgid "could not redirect output"
msgstr "ç„¡æ³•é‡æ–°å°Žå‘輸出"
#: builtin/archive.c
-msgid "git archive: Remote with no URL"
-msgstr "git archive: 未æä¾›é ç«¯ URL"
-
-#: builtin/archive.c
msgid "git archive: expected ACK/NAK, got a flush packet"
msgstr "git archiveï¼šé æœŸæ˜¯ ACK/NAKï¼Œå»æ”¶åˆ° flush å°åŒ…"
@@ -2800,10 +2843,10 @@ msgstr "git archiveï¼šé æœŸæ”¶åˆ° flush å°åŒ…"
#: builtin/bisect.c
msgid ""
-"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"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> --term-{old,good}=<term>] [--no-"
+"git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>] [--no-"
"checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]"
#: builtin/bisect.c
@@ -2823,38 +2866,38 @@ msgid "git bisect replay <logfile>"
msgstr "git bisect replay <logfile>"
#: builtin/bisect.c
-msgid "git bisect run <cmd>..."
-msgstr "git bisect run <cmd>..."
+msgid "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <cmd> [<arg>...]"
#: builtin/bisect.c
#, c-format
msgid "cannot open file '%s' in mode '%s'"
-msgstr "無法以 “%2$s†模å¼é–‹å•Ÿ “%1$s†檔案"
+msgstr "無法以「%2$sã€æ¨¡å¼é–‹å•Ÿã€Œ%1$sã€æª”案"
#: builtin/bisect.c
#, c-format
msgid "could not write to file '%s'"
-msgstr "無法寫入 “%s†檔案"
+msgstr "無法寫入「%sã€æª”案"
#: builtin/bisect.c
#, c-format
msgid "cannot open file '%s' for reading"
-msgstr "無法開啟 “%s†檔案進行讀å–"
+msgstr "無法開啟「%sã€æª”案進行讀å–"
#: builtin/bisect.c
#, c-format
msgid "'%s' is not a valid term"
-msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆè¡“語"
+msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆè¡“語"
#: builtin/bisect.c
#, c-format
msgid "can't use the builtin command '%s' as a term"
-msgstr "ä¸èƒ½å°‡å…§å»ºå‘½ä»¤ “%s†當作術語使用"
+msgstr "ä¸èƒ½å°‡å…§å»ºå‘½ä»¤ã€Œ%sã€ç•¶ä½œè¡“語使用"
#: builtin/bisect.c
#, c-format
msgid "can't change the meaning of the term '%s'"
-msgstr "ä¸èƒ½è®Šæ›´è¡“語 “%s†的å«ç¾©"
+msgstr "ä¸èƒ½è®Šæ›´è¡“語「%sã€çš„å«ç¾©"
#: builtin/bisect.c
msgid "please use two different terms"
@@ -2868,13 +2911,13 @@ msgstr "我們沒有在二分æœå°‹ã€‚\n"
#: builtin/bisect.c
#, c-format
msgid "'%s' is not a valid commit"
-msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„æäº¤"
+msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„æäº¤"
#: 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>â€ã€‚"
+msgstr "ä¸èƒ½ç°½å‡ºåŽŸå§‹ HEAD「%sã€ã€‚請嘗試「git bisect reset <commit>ã€ã€‚"
#: builtin/bisect.c
#, c-format
@@ -2884,12 +2927,12 @@ msgstr "bisect_write 引數無效:%s"
#: builtin/bisect.c
#, c-format
msgid "couldn't get the oid of the rev '%s'"
-msgstr "無法å–得修訂版 “%s†的物件 ID"
+msgstr "無法å–得修訂版「%sã€çš„物件 ID"
#: builtin/bisect.c
#, c-format
msgid "couldn't open the file '%s'"
-msgstr "無法開啟檔案 “%sâ€"
+msgstr "無法開啟檔案「%sã€"
#: builtin/bisect.c
#, c-format
@@ -2903,7 +2946,7 @@ msgid ""
"You can use \"git bisect %s\" and \"git bisect %s\" for that."
msgstr ""
"需指定至少一個 %s 和一個 %s 修訂版。\n"
-"為此您å¯ä»¥ç”¨ “git bisect %s†和 “git bisect %sâ€ã€‚"
+"為此您å¯ä»¥ç”¨ã€Œgit bisect %sã€å’Œã€Œgit bisect %sã€ã€‚"
#: builtin/bisect.c
#, c-format
@@ -2912,9 +2955,9 @@ msgid ""
"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"
+"è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œã€Œgit bisect startã€ã€‚\n"
"接著æä¾›è‡³å°‘一個 %s 和一個 %s 修訂版。\n"
-"為此您å¯ä»¥ç”¨ “git bisect %s†和 “git bisect %sâ€ã€‚"
+"為此您å¯ä»¥ç”¨ã€Œgit bisect %sã€å’Œã€Œgit bisect %sã€ã€‚"
#: builtin/bisect.c
#, c-format
@@ -2963,31 +3006,27 @@ msgid ""
"invalid argument %s for 'git bisect terms'.\n"
"Supported options are: --term-good|--term-old and --term-bad|--term-new."
msgstr ""
-"傳入 “git bisect terms†的 %s 引數無效。\n"
+"傳入「git bisect termsã€çš„ %s 引數無效。\n"
"支æ´çš„é¸é …有:--term-good|--term-old å’Œ --term-bad|--term-new。"
#: builtin/bisect.c
-msgid "revision walk setup failed\n"
-msgstr "ä¿®è¨‚ç‰ˆéæ­·è¨­å®šå¤±æ•—\n"
-
-#: builtin/bisect.c
#, c-format
msgid "could not open '%s' for appending"
-msgstr "無法開啟 “%s†進行附加"
+msgstr "無法開啟「%sã€é€²è¡Œé™„加"
#: builtin/bisect.c
msgid "'' is not a valid term"
-msgstr "“ â€ ä¸æ˜¯æœ‰æ•ˆè¡“語"
+msgstr "「 ã€ä¸æ˜¯æœ‰æ•ˆè¡“語"
#: builtin/bisect.c
#, c-format
msgid "unrecognized option: '%s'"
-msgstr "無法識別é¸é …:“%sâ€"
+msgstr "無法識別é¸é …:「%sã€"
#: builtin/bisect.c
#, c-format
msgid "'%s' does not appear to be a valid revision"
-msgstr "“%sâ€ ä¼¼ä¹Žä¸æ˜¯æœ‰æ•ˆä¿®è¨‚版"
+msgstr "「%sã€ä¼¼ä¹Žä¸æ˜¯æœ‰æ•ˆä¿®è¨‚版"
#: builtin/bisect.c
msgid "bad HEAD - I need a HEAD"
@@ -2996,7 +3035,7 @@ msgstr "HEAD 無效 — 需è¦ä¸€å€‹ HEAD"
#: builtin/bisect.c
#, c-format
msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
-msgstr "簽出 “%s†失敗。請嘗試 “git bisect start <valid-branch>â€ã€‚"
+msgstr "簽出「%sã€å¤±æ•—。請嘗試「git bisect start <valid-branch>ã€ã€‚"
#: builtin/bisect.c
msgid "bad HEAD - strange symbolic ref"
@@ -3005,11 +3044,11 @@ msgstr "HEAD 無效 — 異常符號引用"
#: builtin/bisect.c
#, c-format
msgid "invalid ref: '%s'"
-msgstr "引用無效:“%sâ€"
+msgstr "引用無效:「%sã€"
#: builtin/bisect.c
msgid "You need to start by \"git bisect start\"\n"
-msgstr "è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œ “git bisect startâ€\n"
+msgstr "è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œã€Œgit bisect startã€\n"
# 譯者:請維æŒå¥å°¾ç©ºæ ¼
#. TRANSLATORS: Make sure to include [Y] and [n] in your
@@ -3027,7 +3066,7 @@ msgstr "è¦å‘¼å« `--bisect-state`,請傳入一個以上的引數"
#: builtin/bisect.c
#, c-format
msgid "'git bisect %s' can take only one argument."
-msgstr "“git bisect %s†åªå–一個引數。"
+msgstr "「git bisect %sã€åªå–一個引數。"
#: builtin/bisect.c
#, c-format
@@ -3080,7 +3119,7 @@ msgstr "二分æœå°‹åŸ·è¡Œå¤±æ•—:%2$s å›žå‚³çš„çµæŸä»£ç¢¼ %1$d å°æ–¼ 0 或å
#: builtin/bisect.c
#, c-format
msgid "cannot open file '%s' for writing"
-msgstr "無法開啟 “%s†檔案進行寫入"
+msgstr "無法開啟「%sã€æª”案進行寫入"
#: builtin/bisect.c
msgid "bisect run cannot continue any more"
@@ -3097,22 +3136,22 @@ msgstr "二分æœå°‹ç™¼ç¾åˆ°ç¬¬ä¸€å€‹æœ‰å•題的æäº¤"
#: builtin/bisect.c
#, c-format
msgid "bisect run failed: 'git bisect %s' exited with error code %d"
-msgstr "二分æœå°‹åŸ·è¡Œå¤±æ•—:“git bisect %s†以錯誤碼 %d 離開"
+msgstr "二分æœå°‹åŸ·è¡Œå¤±æ•—:「git bisect %sã€ä»¥éŒ¯èª¤ç¢¼ %d 離開"
#: builtin/bisect.c
#, c-format
msgid "'%s' requires either no argument or a commit"
-msgstr "“%s†ä¸éœ€è¦å¼•數,或者得傳入一個æäº¤"
+msgstr "「%sã€ä¸éœ€è¦å¼•數,或者得傳入一個æäº¤"
#: builtin/bisect.c
#, c-format
msgid "'%s' requires 0 or 1 argument"
-msgstr "“%sâ€ éœ€è¦ 0 或 1 個引數"
+msgstr "「%sã€éœ€è¦ 0 或 1 個引數"
#: builtin/bisect.c
#, c-format
msgid "'%s' requires 0 arguments"
-msgstr "“%s†ä¸éœ€å¼•數"
+msgstr "「%sã€ä¸éœ€å¼•數"
#: builtin/bisect.c
msgid "no logfile given"
@@ -3121,7 +3160,7 @@ msgstr "未æä¾›æ—¥èªŒæª”案"
#: builtin/bisect.c
#, c-format
msgid "'%s' failed: no command provided."
-msgstr "“%s†失敗:沒有æä¾›å‘½ä»¤ã€‚"
+msgstr "「%sã€å¤±æ•—:沒有æä¾›å‘½ä»¤ã€‚"
#: builtin/bisect.c
msgid "need a command"
@@ -3130,7 +3169,7 @@ msgstr "éœ€è¦æä¾›å‘½ä»¤"
#: builtin/bisect.c builtin/cat-file.c
#, c-format
msgid "unknown command: '%s'"
-msgstr "未知命令:“%sâ€"
+msgstr "未知命令:「%sã€"
#: builtin/blame.c
msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
@@ -3343,37 +3382,38 @@ msgstr "git branch [<options>] [-r | -a] [--format]"
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
-" '%s', but not yet merged to HEAD."
+" '%s', but not yet merged to HEAD"
msgstr ""
-"å°‡è¦åˆªé™¤çš„ “%s†分支已經被åˆä½µåˆ°\n"
-" “%sâ€ï¼Œä½†å°šæœªåˆä½µåˆ° HEAD。"
+"å°‡è¦åˆªé™¤çš„分支「%sã€å·²ç¶“被åˆä½µåˆ°\n"
+" 「%sã€ï¼Œä½†å°šæœªåˆä½µåˆ° HEAD"
# è­¯è€…ï¼šä¿æŒåŽŸæ›è¡Œæ ¼å¼ï¼Œåœ¨è¼¸å‡ºæ™‚ %s 的替代內容會讓字串變長
#: builtin/branch.c
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
-" '%s', even though it is merged to HEAD."
+" '%s', even though it is merged to HEAD"
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†指å‘çš„æäº¤ç‰©ä»¶"
+msgid "couldn't look up commit object for '%s'"
+msgstr "無法查詢「%sã€æŒ‡å‘çš„æäº¤ç‰©ä»¶"
#: builtin/branch.c
#, 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 "the branch '%s' is not fully merged"
+msgstr "分支「%sã€æ²’有完全åˆä½µ"
#: builtin/branch.c
-msgid "Update of config-file failed"
+#, c-format
+msgid "If you are sure you want to delete it, run 'git branch -D %s'"
+msgstr "如果確定è¦åˆªé™¤å®ƒï¼Œè«‹åŸ·è¡Œã€Œgit branch -D %sã€"
+
+#: builtin/branch.c
+msgid "update of config-file failed"
msgstr "更新組態檔案失敗"
#: builtin/branch.c
@@ -3382,13 +3422,13 @@ msgstr "ä¸èƒ½å°‡ -a å’Œ -d åŒæ™‚使用"
#: builtin/branch.c
#, c-format
-msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "無法刪除在 “%2$s†簽出的 “%1$s†分支"
+msgid "cannot delete branch '%s' used by worktree at '%s'"
+msgstr "ç„¡æ³•åˆªé™¤è¢«ä½æ–¼ã€Œ%2$sã€çš„工作å€ä½¿ç”¨çš„分支「%1$sã€"
#: builtin/branch.c
#, c-format
-msgid "remote-tracking branch '%s' not found."
-msgstr "找ä¸åˆ° “%s†é ç«¯è¿½è¹¤åˆ†æ”¯ã€‚"
+msgid "remote-tracking branch '%s' not found"
+msgstr "找ä¸åˆ°é ç«¯è¿½è¹¤åˆ†æ”¯ã€Œ%sã€"
#: builtin/branch.c
#, c-format
@@ -3396,13 +3436,13 @@ msgid ""
"branch '%s' not found.\n"
"Did you forget --remote?"
msgstr ""
-"找ä¸åˆ° “%s†分支。\n"
-"您å¯èƒ½è¦åŠ ä¸Š --remote?"
+"找ä¸åˆ°åˆ†æ”¯ã€Œ%sã€ã€‚\n"
+"您å¯èƒ½æƒ³åŠ ä¸Š --remote?"
#: builtin/branch.c
#, c-format
-msgid "branch '%s' not found."
-msgstr "找ä¸åˆ° “%s†分支。"
+msgid "branch '%s' not found"
+msgstr "找ä¸åˆ°åˆ†æ”¯ã€Œ%sã€"
#: builtin/branch.c
#, c-format
@@ -3420,72 +3460,72 @@ 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"
+msgid "branch %s is being rebased at %s"
+msgstr "分支 %s 正在é‡å®šåŸºåº•至 %s"
#: builtin/branch.c
#, c-format
-msgid "Branch %s is being bisected at %s"
-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 æŒ‡é‡æœªè¢«æ›´æ–°"
+msgstr "%s 工作å€çš„ HEAD 指標未被更新"
#: builtin/branch.c
#, c-format
-msgid "Invalid branch name: '%s'"
-msgstr "分支å稱無效:“%sâ€"
+msgid "invalid branch name: '%s'"
+msgstr "分支å稱無效:「%sã€"
#: builtin/branch.c
#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "分支 “%s†尚無æäº¤ã€‚"
+msgid "no commit on branch '%s' yet"
+msgstr "分支「%sã€å°šç„¡æäº¤"
#: builtin/branch.c
#, c-format
-msgid "No branch named '%s'."
-msgstr "沒有å為 “%s†的分支。"
+msgid "no branch named '%s'"
+msgstr "沒有å為「%sã€çš„分支"
#: builtin/branch.c
-msgid "Branch rename failed"
+msgid "branch rename failed"
msgstr "åˆ†æ”¯é‡æ–°å‘½å失敗"
#: builtin/branch.c
-msgid "Branch copy failed"
+msgid "branch copy failed"
msgstr "分支拷è²å¤±æ•—"
#: builtin/branch.c
#, c-format
-msgid "Created a copy of a misnamed branch '%s'"
-msgstr "已為誤命åçš„ “%s†分支建立拷è²"
+msgid "created a copy of a misnamed branch '%s'"
+msgstr "已為誤命å的分支「%sã€å»ºç«‹æ‹·è²"
#: builtin/branch.c
#, c-format
-msgid "Renamed a misnamed branch '%s' away"
-msgstr "已更改誤命åçš„ “%s†分支的å稱"
+msgid "renamed a misnamed branch '%s' away"
+msgstr "已更改誤命å的分支「%sã€çš„å稱"
#: builtin/branch.c
#, c-format
-msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "åˆ†æ”¯å·²é‡æ–°å‘½å為 %s,但 HEAD 指é‡å°šæœªæ›´æ–°ï¼"
+msgid "branch renamed to %s, but HEAD is not updated"
+msgstr "åˆ†æ”¯å·²é‡æ–°å‘½å為 %s,但 HEAD 指標尚未更新"
#: builtin/branch.c
-msgid "Branch is renamed, but update of config-file failed"
+msgid "branch is renamed, but update of config-file failed"
msgstr "åˆ†æ”¯å·²é‡æ–°å‘½å,但無法更新組態檔案"
#: builtin/branch.c
-msgid "Branch is copied, but update of config-file failed"
+msgid "branch is copied, but update of config-file failed"
msgstr "分支已拷è²ï¼Œä½†ç„¡æ³•更新組態檔案"
#: builtin/branch.c
@@ -3493,11 +3533,11 @@ msgstr "分支已拷è²ï¼Œä½†ç„¡æ³•更新組態檔案"
msgid ""
"Please edit the description for the branch\n"
" %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
msgstr ""
"請編輯下述分支的æè¿°\n"
" %s\n"
-"開頭是 “%c†的列將被刪除。\n"
+"開頭是「%sã€çš„列將被刪除。\n"
#: builtin/branch.c
msgid "Generic options"
@@ -3573,7 +3613,7 @@ msgstr "å³ä½¿ç›®æ¨™å·²å­˜åœ¨ï¼Œä»ç§»å‹•æˆ–é‡æ–°å‘½å分支"
#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
msgid "do not output a newline after empty formatted refs"
-msgstr "在格å¼åŒ–å¼•ç”¨çµæžœç‚ºç©ºä¹‹å¾Œï¼Œä¸è¦è¼¸å‡ºæ›åˆ—符號"
+msgstr "在格å¼åŒ–çµæžœç‚ºç©ºçš„引用之後,ä¸è¦è¼¸å‡ºæ›åˆ—符號"
#: builtin/branch.c
msgid "copy a branch and its reflog"
@@ -3636,13 +3676,13 @@ msgstr "åœ¨å­æ¨¡çµ„中éžè¿´"
msgid "format to use for the output"
msgstr "輸出格å¼"
-#: builtin/branch.c builtin/submodule--helper.c submodule.c
-msgid "Failed to resolve HEAD as a valid ref."
-msgstr "無法將 HEAD è§£æžç‚ºæœ‰æ•ˆå¼•用。"
+#: builtin/branch.c
+msgid "failed to resolve HEAD as a valid ref"
+msgstr "無法將 HEAD è§£æžç‚ºæœ‰æ•ˆå¼•用"
#: builtin/branch.c builtin/clone.c
msgid "HEAD not found below refs/heads!"
-msgstr "HEAD 指é‡ä¸åœ¨ /refs/heads 中ï¼"
+msgstr "HEAD 指標ä¸åœ¨ /refs/heads 中ï¼"
#: builtin/branch.c
msgid ""
@@ -3660,20 +3700,20 @@ msgid "branch name required"
msgstr "å¿…é ˆæä¾›åˆ†æ”¯å稱"
#: builtin/branch.c
-msgid "Cannot give description to detached HEAD"
-msgstr "無法å‘分離 HEAD æŒ‡é‡æä¾›æè¿°"
+msgid "cannot give description to detached HEAD"
+msgstr "無法å‘分離 HEAD 指標æä¾›æè¿°"
#: builtin/branch.c
msgid "cannot edit description of more than one branch"
msgstr "無法編輯超éŽä¸€å€‹åˆ†æ”¯çš„æè¿°"
#: builtin/branch.c
-msgid "cannot copy the current branch while not on any."
-msgstr "ä¸åœ¨ä»»ä½•分支上,無法拷è²ç›®å‰åˆ†æ”¯ã€‚"
+msgid "cannot copy the current branch while not on any"
+msgstr "ä¸åœ¨ä»»ä½•分支上,無法拷è²ç›®å‰åˆ†æ”¯"
#: builtin/branch.c
-msgid "cannot rename the current branch while not on any."
-msgstr "ä¸åœ¨ä»»ä½•åˆ†æ”¯ä¸Šï¼Œç„¡æ³•é‡æ–°å‘½åç›®å‰åˆ†æ”¯ã€‚"
+msgid "cannot rename the current branch while not on any"
+msgstr "ä¸åœ¨ä»»ä½•åˆ†æ”¯ä¸Šï¼Œç„¡æ³•é‡æ–°å‘½åç›®å‰åˆ†æ”¯"
#: builtin/branch.c
msgid "too many branches for a copy operation"
@@ -3690,46 +3730,46 @@ 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:其未指å‘任何分支。"
+"could not set upstream of HEAD to %s when it does not point to any branch"
+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 "è¦å–消設定上游的引數太多"
#: builtin/branch.c
-msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr "ç„¡æ³•å–æ¶ˆè¨­å®š HEAD 的上游:其未指å‘任何分支。"
+msgid "could not unset upstream of HEAD when it does not point to any branch"
+msgstr "ç„¡æ³•å–æ¶ˆè¨­å®š HEAD 的上游:其未指å‘任何分支"
#: builtin/branch.c
#, c-format
-msgid "Branch '%s' has no upstream information"
-msgstr "分支 “%s†沒有上游資訊"
+msgid "branch '%s' has no upstream information"
+msgstr "分支「%sã€æ²’有上游資訊"
#: builtin/branch.c
msgid ""
-"The -a, and -r, options to 'git branch' do not take a branch name.\n"
+"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"
+"「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."
+"'--set-upstream-to' instead"
msgstr ""
-"ä¸å†æ”¯æ´é¸é … “--set-upstreamâ€ã€‚請改用 “--track†或 “--set-upstream-toâ€ã€‚"
+"ä¸å†æ”¯æ´é¸é …「--set-upstreamã€ã€‚請改用「--trackã€æˆ–「--set-upstream-toã€"
#: builtin/bugreport.c
msgid "git version:\n"
@@ -3738,7 +3778,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: "
@@ -3754,10 +3794,12 @@ msgstr "䏿˜¯åœ¨ git 版本庫執行 — 沒有å¯é¡¯ç¤ºçš„æŽ›é‰¤\n"
#: builtin/bugreport.c
msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
msgstr ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+" [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"
#: builtin/bugreport.c
@@ -3802,7 +3844,7 @@ msgstr "mode"
#: builtin/bugreport.c
msgid ""
"create an additional zip archive of detailed diagnostics (default 'stats')"
-msgstr "å¦å¤–建立有詳細診斷資訊的 ZIP å°å­˜æª”(é è¨­å€¼ “statsâ€ï¼‰"
+msgstr "å¦å¤–建立有詳細診斷資訊的 ZIP å°å­˜æª”(é è¨­å€¼ã€Œstatsã€ï¼‰"
#: builtin/bugreport.c
msgid "specify a destination for the bugreport file(s)"
@@ -3812,10 +3854,15 @@ msgstr "指定臭蟲報告檔案的目的地"
msgid "specify a strftime format suffix for the filename(s)"
msgstr "指定用於檔åçš„ strftime æ ¼å¼å¾Œç¶´"
+#: builtin/bugreport.c
+#, c-format
+msgid "unknown argument `%s'"
+msgstr "未知引數「%sã€"
+
#: 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
@@ -3838,7 +3885,7 @@ msgstr "無法寫入 %s"
#: builtin/bugreport.c
#, c-format
msgid "Created new report at '%s'.\n"
-msgstr "已在 “%s†建立新報告。\n"
+msgstr "已在「%sã€å»ºç«‹æ–°å ±å‘Šã€‚\n"
#: builtin/bundle.c
msgid ""
@@ -3892,6 +3939,10 @@ msgstr "需è¦ç‰ˆæœ¬åº«ä¾†å»ºç«‹å¥—件包。"
msgid "do not show bundle details"
msgstr "ä¸é¡¯ç¤ºå¥—件包的詳細資訊"
+#: builtin/bundle.c bundle.c
+msgid "need a repository to verify a bundle"
+msgstr "需è¦ç‰ˆæœ¬åº«é©—證套件包"
+
#: builtin/bundle.c
#, c-format
msgid "%s is okay\n"
@@ -3908,7 +3959,7 @@ 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"
@@ -3921,7 +3972,7 @@ msgstr "輸入中沒有命令"
#: builtin/cat-file.c
#, c-format
msgid "whitespace before command: '%s'"
-msgstr "命令剿œ‰ç©ºæ ¼ï¼šâ€œ%sâ€"
+msgstr "命令剿œ‰ç©ºæ ¼ï¼šã€Œ%sã€"
#: builtin/cat-file.c
#, c-format
@@ -3951,6 +4002,14 @@ msgstr "git cat-file (-t | -s) [--allow-unknown-type] <object>"
#: builtin/cat-file.c
msgid ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+msgstr ""
+"git cat-file (--textconv | --filters)\n"
+" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
+
+#: builtin/cat-file.c
+msgid ""
"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
"objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
@@ -3962,14 +4021,6 @@ msgstr ""
" [--textconv | --filters] [-Z]"
#: builtin/cat-file.c
-msgid ""
-"git cat-file (--textconv | --filters)\n"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
-msgstr ""
-"git cat-file (--textconv | --filters)\n"
-" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
-
-#: builtin/cat-file.c
msgid "Check object existence or emit object contents"
msgstr "檢查物件的存在狀態,或輸出物件內容"
@@ -3987,7 +4038,8 @@ msgstr "輸出 [æå£žçš„] ([broken]) 物件屬性"
#: builtin/cat-file.c
msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
-msgstr "顯示物件類型(å¯ä»¥æ˜¯ “blobâ€ã€â€œtreeâ€ã€â€œcommitâ€ã€â€œtag†等其中一個)"
+msgstr ""
+"顯示物件類型(å¯ä»¥æ˜¯ã€Œblobã€ã€ã€Œtreeã€ã€ã€Œcommitã€ã€ã€Œtagã€ç­‰å…¶ä¸­ä¸€å€‹ï¼‰"
#: builtin/cat-file.c
msgid "show object size"
@@ -4065,12 +4117,12 @@ msgstr "blob|tree"
#: builtin/cat-file.c
msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
-msgstr "請在 (--textconv | --filters) 使用 <path>ï¼Œè€Œéž â€œbatchâ€"
+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"
@@ -4079,12 +4131,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"
@@ -4093,12 +4145,12 @@ msgstr "æ‰¹æ¬¡è™•ç†æ¨¡å¼ä¸å–引數"
#: builtin/cat-file.c
#, c-format
msgid "<rev> required with '%s'"
-msgstr "“%sâ€ éœ€è¦ <rev>"
+msgstr "「%sã€éœ€è¦ <rev>"
#: builtin/cat-file.c
#, c-format
msgid "<object> required with '-%c'"
-msgstr "“-%câ€ éœ€è¦ <object>"
+msgstr "「-%cã€éœ€è¦ <object>"
#: builtin/cat-file.c
#, c-format
@@ -4188,9 +4240,16 @@ msgid "also read contacts from stdin"
msgstr "亦從 stdin 讀å–è¯çµ¡åœ°å€"
#: builtin/check-mailmap.c
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "無法解æžè¯çµ¡åœ°å€ï¼š%s"
+msgid "read additional mailmap entries from file"
+msgstr "從檔案讀å–å…¶ä»– mailmap é …ç›®"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "資料物件"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "從 blob 讀å–å…¶ä»– mailmap é …ç›®"
#: builtin/check-mailmap.c
msgid "no contacts specified"
@@ -4272,32 +4331,32 @@ 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
@@ -4320,32 +4379,43 @@ msgstr[0] "å·²å¾žç´¢å¼•å€æ›´æ–° %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 "'%s', '%s', or '%s' cannot be used when checking out of a tree"
+msgstr "「%sã€ã€ã€Œ%sã€æˆ–「%sã€ç„¡æ³•在簽出樹狀物件時使用"
#: builtin/checkout.c
#, c-format
msgid "path '%s' is unmerged"
-msgstr "路徑 “%s†未åˆä½µ"
+msgstr "路徑「%sã€æœªåˆä½µ"
+
+#: builtin/checkout.c builtin/grep.c builtin/merge-tree.c builtin/reset.c
+#: merge-ort.c reset.c sequencer.c tree-walk.c
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "ç„¡æ³•è®€å–æ¨¹ï¼ˆ%s)"
#: builtin/checkout.c
msgid "you need to resolve your current index first"
@@ -4363,40 +4433,40 @@ msgstr ""
#: 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"
msgstr "HEAD ç›®å‰ä½æ–¼"
-#: builtin/checkout.c builtin/clone.c t/helper/test-fast-rebase.c
+#: builtin/checkout.c builtin/clone.c
msgid "unable to update 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 "已切æ›ä¸¦é‡è¨­åˆ†æ”¯ “%sâ€\n"
+msgstr "已切æ›ä¸¦é‡è¨­åˆ†æ”¯ã€Œ%sã€\n"
#: builtin/checkout.c
#, c-format
msgid "Switched to a new branch '%s'\n"
-msgstr "已切æ›è‡³æ–°åˆ†æ”¯ “%sâ€\n"
+msgstr "已切æ›è‡³æ–°åˆ†æ”¯ã€Œ%sã€\n"
#: builtin/checkout.c
#, c-format
msgid "Switched to branch '%s'\n"
-msgstr "已切æ›è‡³åˆ†æ”¯ “%sâ€\n"
+msgstr "已切æ›è‡³åˆ†æ”¯ã€Œ%sã€\n"
# 譯者:請維æŒå‰å°Žç©ºæ ¼
#: builtin/checkout.c
@@ -4449,7 +4519,7 @@ 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"
@@ -4461,7 +4531,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
@@ -4475,19 +4545,19 @@ msgid ""
"one remote, e.g. the 'origin' remote, consider setting\n"
"checkout.defaultRemote=origin in your config."
msgstr ""
-"如果您想è¦ç°½å‡ºé ç«¯è¿½è¹¤åˆ†æ”¯ï¼Œä¾‹å¦‚ “originâ€ï¼Œ\n"
+"如果您想è¦ç°½å‡ºé ç«¯è¿½è¹¤åˆ†æ”¯ï¼Œä¾‹å¦‚「originã€ï¼Œ\n"
"您å¯ä»¥ä½¿ç”¨ --track é¸é …寫出全å:\n"
"\n"
" git checkout --track origin/<name>\n"
"\n"
"如果您平時比較想è¦ä½¿ç”¨æ¨¡ç³Šçš„簡短分支å稱 <name>,\n"
-"而ä¸å¤ªæƒ³å¯«å¦‚ “origin†的é ç«¯ç‰ˆæœ¬åº«å稱,\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"
@@ -4511,27 +4581,27 @@ 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 "若您想è¦åœ¨æ­¤æäº¤åˆ†é›¢ HEAD 指é‡ï¼Œè«‹å‚³å…¥ --detach é¸é …é‡è©¦ã€‚"
+msgstr "若您想è¦åœ¨æ­¤æäº¤åˆ†é›¢ HEAD 指標,請傳入 --detach é¸é …é‡è©¦ã€‚"
#: builtin/checkout.c
msgid ""
@@ -4539,7 +4609,7 @@ msgid ""
"Consider \"git merge --quit\" or \"git worktree add\"."
msgstr ""
"無法在åˆä½µæ™‚切æ›åˆ†æ”¯\n"
-"請試試 “git merge --quit†或 “git worktree addâ€ã€‚"
+"請試試「git merge --quitã€æˆ–「git worktree addã€ã€‚"
#: builtin/checkout.c
msgid ""
@@ -4547,7 +4617,7 @@ msgid ""
"Consider \"git am --quit\" or \"git worktree add\"."
msgstr ""
"無法在 am 工作階段期間時切æ›åˆ†æ”¯\n"
-"請試試 “git am --quit†或 “git worktree addâ€ã€‚"
+"請試試「git am --quitã€æˆ–「git worktree addã€ã€‚"
#: builtin/checkout.c
msgid ""
@@ -4555,7 +4625,7 @@ msgid ""
"Consider \"git rebase --quit\" or \"git worktree add\"."
msgstr ""
"無法在é‡å®šåŸºåº•時切æ›åˆ†æ”¯\n"
-"請試試 “git rebase --quit†或 “git worktree addâ€ã€‚"
+"請試試「git rebase --quitã€æˆ–「git worktree addã€ã€‚"
#: builtin/checkout.c
msgid ""
@@ -4563,7 +4633,7 @@ msgid ""
"Consider \"git cherry-pick --quit\" or \"git worktree add\"."
msgstr ""
"無法在æ€é¸æ™‚切æ›åˆ†æ”¯\n"
-"請試試 “git cherry-pick --quit†或 “git worktree addâ€ã€‚"
+"請試試「git cherry-pick --quitã€æˆ–「git worktree addã€ã€‚"
#: builtin/checkout.c
msgid ""
@@ -4571,7 +4641,7 @@ msgid ""
"Consider \"git revert --quit\" or \"git worktree add\"."
msgstr ""
"無法在還原時切æ›åˆ†æ”¯\n"
-"請試試 “git revert --quit†或 “git worktree addâ€ã€‚"
+"請試試「git revert --quitã€æˆ–「git worktree addã€ã€‚"
#: builtin/checkout.c
msgid "you are switching branch while bisecting"
@@ -4584,28 +4654,38 @@ 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' needs the paths to check out"
+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†ä¸å– <start-point>"
+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 "缺少分支或æäº¤å¼•數"
#: builtin/checkout.c
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "未知的è¡çªè¼¸å‡ºé¢¨æ ¼ã€Œ%sã€"
+
+#: builtin/checkout.c
msgid "perform a 3-way merge with the new branch"
msgstr "和新分支進行三方åˆä½µ"
@@ -4619,7 +4699,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)"
@@ -4630,8 +4710,8 @@ msgid "new-branch"
msgstr "new-branch"
#: builtin/checkout.c
-msgid "new unparented branch"
-msgstr "新的,沒有父æäº¤çš„分支"
+msgid "new unborn branch"
+msgstr "新的未誕生分支"
#: builtin/checkout.c builtin/merge.c
msgid "update ignored files (default)"
@@ -4656,7 +4736,7 @@ 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"
@@ -4679,12 +4759,12 @@ 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 ""
@@ -4698,7 +4778,7 @@ msgstr ""
msgid "you must specify path(s) to restore"
msgstr "您必須指定è¦é‚„原的路徑"
-#: builtin/checkout.c builtin/clone.c builtin/remote.c
+#: builtin/checkout.c builtin/clone.c builtin/remote.c builtin/replay.c
#: builtin/submodule--helper.c builtin/worktree.c
msgid "branch"
msgstr "branch"
@@ -4717,7 +4797,7 @@ 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)"
@@ -4733,7 +4813,7 @@ 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"
@@ -4877,7 +4957,7 @@ 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"
"? - 顯示如何在æç¤ºä¸‹é¸æ“‡çš„å”助"
@@ -4907,9 +4987,9 @@ msgstr "äº’å‹•å¼æ¸…除"
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/pack-refs.c builtin/show-ref.c
-#: ref-filter.h
+#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c
+#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c
+#: builtin/show-ref.c ref-filter.h
msgid "pattern"
msgstr "pattern"
@@ -4926,22 +5006,8 @@ msgid "remove only ignored files"
msgstr "åªç§»é™¤å¿½ç•¥çš„æª”案"
#: builtin/clean.c
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
-msgstr ""
-"clean.requireForce 設定為 true 且未æä¾› -iã€-n 或 -f é¸é …,拒絕執行清ç†å‹•作"
-
-#: builtin/clean.c
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce é è¨­ç‚º true 且未æä¾› -iã€-n 或 -f é¸é …,拒絕執行清ç†å‹•作"
-
-#: builtin/clean.c
-msgid "-x and -X cannot be used together"
-msgstr "-x å’Œ -X ä¸èƒ½åŒæ™‚使用"
+msgid "clean.requireForce is true and -f not given: refusing to clean"
+msgstr "clean.requireForce 是 true 且未給定 -f é¸é …:拒絕清ç†"
#: builtin/clone.c
msgid "git clone [<options>] [--] <repo> [<dir>]"
@@ -4960,8 +5026,8 @@ msgid "create a bare repository"
msgstr "建立裸版本庫"
#: builtin/clone.c
-msgid "create a mirror repository (implies bare)"
-msgstr "建立é¡åƒç‰ˆæœ¬åº«ï¼ˆäº¦å³è£¸ç‰ˆæœ¬åº«ï¼‰"
+msgid "create a mirror repository (implies --bare)"
+msgstr "建立é¡åƒç‰ˆæœ¬åº«ï¼ˆéš±å« --bare)"
#: builtin/clone.c
msgid "to clone from a local repository"
@@ -5011,7 +5077,7 @@ msgstr "name"
#: builtin/clone.c
msgid "use <name> instead of 'origin' to track upstream"
-msgstr "使用 <name> è€Œä¸æ˜¯ “origin†追蹤上游"
+msgstr "使用 <name> è€Œä¸æ˜¯ã€Œoriginã€è¿½è¹¤ä¸Šæ¸¸"
#: builtin/clone.c
msgid "checkout <branch> instead of the remote's HEAD"
@@ -5021,7 +5087,7 @@ msgstr "簽出 <branch> è€Œä¸æ˜¯é ç«¯ HEAD"
msgid "path to git-upload-pack on the remote"
msgstr "é ç«¯ git-upload-pack 路徑"
-#: builtin/clone.c builtin/fetch.c builtin/grep.c builtin/pull.c
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
msgid "depth"
msgstr "depth"
@@ -5034,6 +5100,7 @@ msgid "create a shallow clone since a specific time"
msgstr "建立從指定時間到ç¾åœ¨çš„æ·ºå±¤è¤‡è£½"
#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c
+#: builtin/replay.c
msgid "revision"
msgstr "revision"
@@ -5061,6 +5128,10 @@ msgstr "gitdir"
msgid "separate git dir from working tree"
msgstr "git 目錄和工作å€åˆ†é›¢"
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
+msgid "specify the reference format to use"
+msgstr "指定è¦ä½¿ç”¨çš„引用格å¼"
+
#: builtin/clone.c
msgid "key=value"
msgstr "key=value"
@@ -5117,7 +5188,7 @@ msgstr "%s å­˜åœ¨ä¸”ä¸æ˜¯ä¸€å€‹ç›®éŒ„"
#: builtin/clone.c
#, c-format
msgid "'%s' is a symlink, refusing to clone with --local"
-msgstr "“%s†是個符號連çµï¼Œæ•…ä¸èƒ½ä½¿ç”¨ --local 複製"
+msgstr "「%sã€æ˜¯å€‹ç¬¦è™Ÿé€£çµï¼Œæ•…ä¸èƒ½ä½¿ç”¨ --local 複製"
#: builtin/clone.c
#, c-format
@@ -5132,7 +5203,17 @@ 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
+msgid "hardlink cannot be checked at '%s'"
+msgstr "ç„¡æ³•æª¢æŸ¥ä½æ–¼ã€Œ%sã€çš„硬連çµ"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "硬連çµèˆ‡ä½æ–¼ '%s' 的來æºä¸åŒ"
#: builtin/clone.c
#, c-format
@@ -5144,7 +5225,7 @@ msgstr "å»ºç«‹é€£çµ '%s' 失敗"
msgid "failed to copy file to '%s'"
msgstr "複製檔案至 '%s' 失敗"
-#: builtin/clone.c
+#: builtin/clone.c refs/files-backend.c
#, c-format
msgid "failed to iterate over '%s'"
msgstr "無法在 '%s' 上疊代"
@@ -5210,11 +5291,11 @@ msgstr "å¤ªå¤šåƒæ•¸ã€‚"
msgid "You must specify a repository to clone."
msgstr "您必須指定è¦è¤‡è£½çš„版本庫。"
-#: builtin/clone.c
-msgid ""
-"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
-"exclude"
-msgstr "--bundle-uri 與 --depthã€--shallow-since å’Œ --shallow-exclude ä¸ç›¸å®¹"
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
+#, c-format
+msgid "unknown ref storage format '%s'"
+msgstr "未知的引用儲存格å¼ã€Œ%sã€"
#: builtin/clone.c
#, c-format
@@ -5311,7 +5392,7 @@ msgstr "無法åˆå§‹åŒ–版本庫,略éŽå¥—件包 URI"
#: builtin/clone.c
#, c-format
msgid "failed to fetch objects from bundle URI '%s'"
-msgstr "無法從套件包 URL “%s†抓å–物件"
+msgstr "無法從套件包 URL「%sã€æŠ“å–物件"
#: builtin/clone.c
msgid "failed to fetch advertised bundles"
@@ -5359,6 +5440,11 @@ msgid "padding space between columns"
msgstr "兩直行之間的填充空間"
#: builtin/column.c
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s ä¸å¾—為負數"
+
+#: builtin/column.c
msgid "--command must be the first argument"
msgstr "--command å¿…é ˆæ˜¯ç¬¬ä¸€å€‹åƒæ•¸"
@@ -5366,7 +5452,7 @@ msgstr "--command å¿…é ˆæ˜¯ç¬¬ä¸€å€‹åƒæ•¸"
msgid ""
"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
msgstr ""
-"git commit-graph verify [--object-dir <目錄>] [--shallow] [--[no-]progress]"
+"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
#: builtin/commit-graph.c
msgid ""
@@ -5375,14 +5461,14 @@ msgid ""
"--stdin-commits]\n"
" [--changed-paths] [--[no-]max-new-filters <n>] [--"
"[no-]progress]\n"
-" <split options>"
+" <split-options>"
msgstr ""
"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>"
+" <split-options>"
#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
msgid "dir"
@@ -5390,16 +5476,21 @@ msgstr "目錄"
#: builtin/commit-graph.c
msgid "the object directory to store the graph"
-msgstr "儲存圖形的物件目錄"
+msgstr "儲存圖的物件目錄"
#: builtin/commit-graph.c
msgid "if the commit-graph is split, only verify the tip file"
-msgstr "如果æäº¤åœ–形被分割,åªé©—證頭一個檔案"
+msgstr "如果æäº¤åœ–被分割,åªé©—證頭一個檔案"
#: builtin/commit-graph.c
#, c-format
msgid "Could not open commit-graph '%s'"
-msgstr "無法開啟æäº¤åœ–å½¢ '%s'"
+msgstr "無法開啟æäº¤åœ–「%sã€"
+
+#: builtin/commit-graph.c
+#, c-format
+msgid "could not open commit-graph chain '%s'"
+msgstr "無法開啟æäº¤åœ–éˆã€Œ%sã€"
#: builtin/commit-graph.c
#, c-format
@@ -5435,7 +5526,7 @@ msgstr "從標準輸入中的æäº¤é–‹å§‹æŽƒæ"
#: builtin/commit-graph.c
msgid "include all commits already in the commit-graph file"
-msgstr "åŒ…å« commit-graph 檔案中已有所有æäº¤"
+msgstr "åŒ…å«æäº¤åœ–æª”æ¡ˆä¸­æ‰€æœ‰å·²æœ‰çš„æäº¤"
#: builtin/commit-graph.c
msgid "enable computation for changed paths"
@@ -5443,15 +5534,15 @@ msgstr "啟用已變更路徑的計算"
#: builtin/commit-graph.c
msgid "allow writing an incremental commit-graph file"
-msgstr "å…è¨±å¯«ä¸€å€‹å¢žé‡æäº¤åœ–å½¢æª”æ¡ˆ"
+msgstr "å…è¨±å¯«ä¸€å€‹å¢žé‡æäº¤åœ–æª”æ¡ˆ"
#: builtin/commit-graph.c
msgid "maximum number of commits in a non-base split commit-graph"
-msgstr "在éžåŸºæœ¬åˆ†å‰²æäº¤åœ–形中的最大æäº¤æ•¸"
+msgstr "在éžåŸºç¤Žåˆ†å‰²æäº¤åœ–中的最大æäº¤æ•¸"
#: builtin/commit-graph.c
msgid "maximum ratio between two levels of a split commit-graph"
-msgstr "一個分割æäº¤åœ–形的兩個級別之間的最大比率"
+msgstr "一個分割æäº¤åœ–的兩個級別之間的最大比率"
#: builtin/commit-graph.c
msgid "only expire files older than a given date-time"
@@ -5539,7 +5630,7 @@ 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"
+"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"
@@ -5549,7 +5640,7 @@ msgid ""
msgstr ""
"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"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"
@@ -5642,10 +5733,6 @@ msgid "Failed to update main cache tree"
msgstr "ä¸èƒ½æ›´æ–°æ¨¹çš„主快å–"
#: builtin/commit.c
-msgid "unable to write new_index file"
-msgstr "無法寫 new_index 檔案"
-
-#: builtin/commit.c
msgid "cannot do a partial commit during a merge."
msgstr "在åˆä½µéŽç¨‹ä¸­ä¸èƒ½åšéƒ¨åˆ†æäº¤ã€‚"
@@ -5690,10 +5777,10 @@ msgid ""
"in the current commit message"
msgstr "ç„¡æ³•é¸æ“‡ä¸€å€‹æœªè¢«ç›®å‰æäº¤èªªæ˜Žä½¿ç”¨çš„備註字元"
-#: builtin/commit.c builtin/merge-tree.c
+#: builtin/commit.c
#, c-format
msgid "could not lookup commit '%s'"
-msgstr "無法查詢æäº¤ “%sâ€"
+msgstr "無法查詢æäº¤ã€Œ%sã€"
#: builtin/commit.c builtin/shortlog.c
#, c-format
@@ -5725,7 +5812,7 @@ msgstr "ä¸èƒ½è®€å– MERGE_MSG"
#: builtin/commit.c bundle.c rerere.c sequencer.c
#, c-format
msgid "could not open '%s'"
-msgstr "ä¸èƒ½é–‹å•Ÿ '%s'"
+msgstr "無法開啟「%sã€"
#: builtin/commit.c
msgid "could not write commit template"
@@ -5735,38 +5822,38 @@ msgstr "ä¸èƒ½å¯«æäº¤ç¯„本"
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
msgstr ""
"請輸入æè¿°æ‚¨è®Šæ›´çš„æäº¤è¨Šæ¯ã€‚\n"
-"開頭是「%cã€çš„行皆會忽略。\n"
+"開頭是「%sã€çš„列皆會忽略。\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
msgstr ""
-"請輸入æè¿°æ‚¨è®Šæ›´çš„æäº¤è¨Šæ¯ã€‚開頭是「%cã€\n"
-"的行皆會忽略。æäº¤è¨Šæ¯ç©ºç™½å‰‡å–消本次æäº¤ä½œæ¥­ã€‚\n"
+"請輸入æè¿°æ‚¨è®Šæ›´çš„æäº¤è¨Šæ¯ã€‚開頭是「%sã€çš„列\n"
+"皆會忽略。æäº¤è¨Šæ¯ç©ºç™½å‰‡å–消本次æäº¤ä½œæ¥­ã€‚\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
msgstr ""
-"請輸入æè¿°æ‚¨è®Šæ›´çš„æäº¤è¨Šæ¯ã€‚會ä¿ç•™é–‹é ­æ˜¯ã€Œ%cã€\n"
-"的行,但也å¯ä»¥è‡ªå·±ç§»é™¤æŽ‰é€™äº›è¡Œã€‚\n"
+"請輸入æè¿°æ‚¨è®Šæ›´çš„æäº¤è¨Šæ¯ã€‚會ä¿ç•™é–‹é ­æ˜¯ã€Œ%sã€\n"
+"的列,但也å¯ä»¥è‡ªå·±ç§»é™¤æŽ‰é€™äº›åˆ—。\n"
#: builtin/commit.c
#, 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"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
msgstr ""
"請輸入æè¿°æ‚¨è®Šæ›´çš„æäº¤è¨Šæ¯ã€‚會ä¿ç•™é–‹é ­æ˜¯\n"
-"「%cã€çš„行,但也å¯ä»¥è‡ªå·±ç§»é™¤æŽ‰é€™äº›è¡Œã€‚\n"
+"「%sã€çš„列,但也å¯ä»¥è‡ªå·±ç§»é™¤æŽ‰é€™äº›åˆ—。\n"
"æäº¤è¨Šæ¯ç©ºç™½å‰‡å–消本次æäº¤ä½œæ¥­ã€‚\n"
#: builtin/commit.c
@@ -5819,7 +5906,7 @@ msgstr "%sæäº¤è€…:%.*s <%.*s>"
msgid "Cannot read index"
msgstr "無法讀å–索引"
-#: builtin/commit.c
+#: builtin/commit.c builtin/tag.c
msgid "unable to pass trailers to --trailers"
msgstr "無法將尾部署å傳éžè‡³ --trailers"
@@ -5998,7 +6085,7 @@ msgstr "日期"
msgid "override date for commit"
msgstr "æäº¤æ™‚覆蓋日期"
-#: builtin/commit.c builtin/merge-tree.c parse-options.h ref-filter.h
+#: builtin/commit.c parse-options.h ref-filter.h
msgid "commit"
msgstr "æäº¤"
@@ -6030,11 +6117,11 @@ msgstr "使用 autosquash æ ¼å¼çš„æäº¤èªªæ˜Žç”¨ä»¥å£“縮至指定的æäº¤"
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr "ç¾åœ¨å°‡è©²æäº¤çš„作者改為我(和 -C/-c/--amend åƒæ•¸å…±ç”¨ï¼‰"
-#: builtin/commit.c builtin/interpret-trailers.c
+#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c
msgid "trailer"
msgstr "尾部署å"
-#: builtin/commit.c
+#: builtin/commit.c builtin/tag.c
msgid "add custom trailer(s)"
msgstr "加入自訂尾部署å"
@@ -6139,24 +6226,72 @@ msgstr "æäº¤èªªæ˜Žå…§æ–‡ç©ºç™½ï¼Œä¸­æ­¢æäº¤ä½œæ¥­ã€‚\n"
#: builtin/commit.c
msgid ""
"repository has been updated, but unable to write\n"
-"new_index file. Check that disk is not full and quota is\n"
+"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."
msgstr ""
-"版本庫已更新,但無法寫 new_index 檔案。檢查是å¦ç£ç¢Ÿå·²æ»¿æˆ–\n"
-"ç£ç¢Ÿé…é¡å·²è€—盡,然後執行 \"git restore --staged :/\" 復原。"
+"版本庫已更新,但無法寫入新的索引檔案。請檢查ç£ç¢Ÿæ˜¯å¦\n"
+"已滿或ç£ç¢Ÿé…é¡å·²è€—盡,然後執行「git restore --staged :/ã€å¾©åŽŸã€‚"
#: builtin/config.c
-msgid "git config [<options>]"
-msgstr "git config [<é¸é …>]"
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<檔案é¸é …>] [<顯示é¸é …>] [--includes]"
#: builtin/config.c
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "無法識別的 --type åƒæ•¸ï¼Œ%s"
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<檔案é¸é …>] [<顯示é¸é …>] [--includes] [--all] [--regexp] [--"
+"value=<值>] [--fixed-value] [--default=<é è¨­å€¼>] <å稱>"
#: builtin/config.c
-msgid "only one type at a time"
-msgstr "一次åªèƒ½ä¸€å€‹é¡žåž‹"
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<檔案é¸é …>] [--type=<類型>] [--all] [--value=<值>] [--fixed-"
+"value] <å稱> <值>"
+
+#: builtin/config.c
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<檔案é¸é …>] [--all] [--value=<值>] [--fixed-value] <å稱> <"
+"值>"
+
+#: builtin/config.c
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<檔案é¸é …>] <舊å稱> <æ–°å稱>"
+
+#: builtin/config.c
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<檔案é¸é …>] <å稱>"
+
+#: builtin/config.c
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<檔案é¸é …>]"
+
+#: builtin/config.c
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<檔案é¸é …>] [<顯示é¸é …>] [--includes] [--all] [--regexp=<常è¦"
+"表示å¼>] [--value=<值>] [--fixed-value] [--default=<é è¨­å€¼>] <å稱>"
+
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<檔案é¸é …>] [--type=<類型>] [--comment=<備註>] [--all] [--"
+"value=<值>] [--fixed-value] <å稱> <值>"
#: builtin/config.c
msgid "Config file location"
@@ -6191,70 +6326,6 @@ msgid "read config from given blob object"
msgstr "從æä¾›çš„資料物件讀å–設定"
#: builtin/config.c
-msgid "Action"
-msgstr "動作"
-
-#: builtin/config.c
-msgid "get value: name [value-pattern]"
-msgstr "å–得值:name [value-pattern]"
-
-#: builtin/config.c
-msgid "get all values: key [value-pattern]"
-msgstr "å–得所有值:key [value-pattern]"
-
-#: builtin/config.c
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "根據常è¦è¡¨ç¤ºå¼å–得值:name-regex [value-pattern]"
-
-#: builtin/config.c
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "ç²å¾— URL å–值:section[.var] URL"
-
-#: builtin/config.c
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr "å–代所有符åˆçš„變數:name value [value-pattern]"
-
-#: builtin/config.c
-msgid "add a new variable: name value"
-msgstr "新增一個新的變數:name value"
-
-#: builtin/config.c
-msgid "remove a variable: name [value-pattern]"
-msgstr "移除一個變數:name [value-pattern]"
-
-#: builtin/config.c
-msgid "remove all matches: name [value-pattern]"
-msgstr "移除所有符åˆé …目:name [value-pattern]"
-
-#: builtin/config.c
-msgid "rename section: old-name new-name"
-msgstr "釿–°å‘½åå°ç¯€ï¼šold-name new-name"
-
-#: builtin/config.c
-msgid "remove a section: name"
-msgstr "刪除一個å°ç¯€ï¼šname"
-
-#: builtin/config.c
-msgid "list all"
-msgstr "全部列出"
-
-#: builtin/config.c
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr "比較「value-patternã€çš„值時,使用字串相等比較"
-
-#: builtin/config.c
-msgid "open an editor"
-msgstr "開啟一個編輯器"
-
-#: builtin/config.c
-msgid "find the color configured: slot [default]"
-msgstr "ç²å¾—設定的é¡è‰²ï¼šè¨­å®š [é è¨­å€¼]"
-
-#: builtin/config.c
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "ç²å¾—é¡è‰²è¨­å®šï¼šè¨­å®š [stdout-is-tty]"
-
-#: builtin/config.c
msgid "Type"
msgstr "類型"
@@ -6291,8 +6362,8 @@ msgid "value is an expiry date"
msgstr "值是一個到期日期"
#: builtin/config.c
-msgid "Other"
-msgstr "其它"
+msgid "Display options"
+msgstr "顯示é¸é …"
#: builtin/config.c
msgid "terminate values with NUL byte"
@@ -6303,10 +6374,6 @@ msgid "show variable names only"
msgstr "åªé¡¯ç¤ºè®Šæ•¸å"
#: builtin/config.c
-msgid "respect include directives on lookup"
-msgstr "查詢時引用 include 指令éžè¿´å°‹æ‰¾"
-
-#: builtin/config.c
msgid "show origin of config (file, standard input, blob, command line)"
msgstr "顯示設定的來æºï¼ˆæª”æ¡ˆã€æ¨™æº–輸入ã€è³‡æ–™ç‰©ä»¶ï¼Œæˆ–命令列)"
@@ -6317,12 +6384,17 @@ msgstr ""
"令 command)"
#: builtin/config.c
-msgid "value"
-msgstr "å–值"
+msgid "show config keys in addition to their values"
+msgstr "除了顯示組態值,é¡å¤–顯示其éµå"
#: builtin/config.c
-msgid "with --get, use default value when missing entry"
-msgstr "使用 --get ä½†æœªæŒ‡å®šåƒæ•¸æ™‚所使用的é è¨­å€¼"
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "無法識別的 --type åƒæ•¸ï¼Œ%s"
+
+#: builtin/config.c
+msgid "only one type at a time"
+msgstr "一次åªèƒ½ä¸€å€‹é¡žåž‹"
#: builtin/config.c
#, c-format
@@ -6415,52 +6487,93 @@ msgstr ""
"詳情請閱讀「git help worktreeã€çš„「CONFIGURATION FILEã€å°ç¯€"
#: builtin/config.c
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color 和變數類型ä¸ç›¸å®¹"
+msgid "Other"
+msgstr "其它"
#: builtin/config.c
-msgid "only one action at a time"
-msgstr "一次åªèƒ½æœ‰ä¸€å€‹å‹•作"
+msgid "respect include directives on lookup"
+msgstr "查詢時引用 include 指令éžè¿´å°‹æ‰¾"
#: builtin/config.c
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only 僅é©ç”¨æ–¼ --list 或 --get-regexp"
+#, c-format
+msgid "unable to read config file '%s'"
+msgstr "無法讀å–設定檔案 '%s'"
#: builtin/config.c
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr "--show-origin 僅é©ç”¨æ–¼ --getã€--get-allã€--get-regexp å’Œ --list"
+msgid "error processing config file(s)"
+msgstr "處ç†è¨­å®šæª”案發生錯誤"
#: builtin/config.c
-msgid "--default is only applicable to --get"
-msgstr "--default 僅é©ç”¨æ–¼ --get"
+msgid "Filter options"
+msgstr "éŽæ¿¾é¸é …"
+
+#: builtin/config.c
+msgid "return all values for multi-valued config options"
+msgstr "回傳有多項值之組態é¸é …的所有值"
+
+#: builtin/config.c
+msgid "interpret the name as a regular expression"
+msgstr "å°‡å稱當作常è¦è¡¨ç¤ºå¼è§£è®€"
+
+#: builtin/config.c
+msgid "show config with values matching the pattern"
+msgstr "é¡¯ç¤ºå€¼ç¬¦åˆæ¨¡å¼çš„組態"
+
+#: builtin/config.c
+msgid "use string equality when comparing values to value pattern"
+msgstr "使用字串相等比較值和模å¼"
+
+#: builtin/config.c
+msgid "URL"
+msgstr "URL"
+
+#: builtin/config.c
+msgid "show config matching the given URL"
+msgstr "é¡¯ç¤ºç¬¦åˆæä¾› URL 的組態"
+
+#: builtin/config.c
+msgid "value"
+msgstr "å–值"
+
+#: builtin/config.c
+msgid "use default value when missing entry"
+msgstr "æœªæŒ‡å®šåƒæ•¸æ™‚所使用的é è¨­å€¼"
#: builtin/config.c
msgid "--fixed-value only applies with 'value-pattern'"
msgstr "--fixed-value 僅套用至 'value-pattern'"
#: builtin/config.c
-#, c-format
-msgid "unable to read config file '%s'"
-msgstr "無法讀å–設定檔案 '%s'"
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= 無法和 --all 或 --url= 一起使用"
#: builtin/config.c
-msgid "error processing config file(s)"
-msgstr "處ç†è¨­å®šæª”案發生錯誤"
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= 無法和 --allã€--regexpã€--value 一起使用"
#: builtin/config.c
-msgid "editing stdin is not supported"
-msgstr "䏿”¯æ´ç·¨è¼¯æ¨™æº–輸入"
+msgid "Filter"
+msgstr "éŽæ¿¾å™¨"
#: builtin/config.c
-msgid "editing blobs is not supported"
-msgstr "䏿”¯æ´ç·¨è¼¯è³‡æ–™ç‰©ä»¶"
+msgid "replace multi-valued config option with new value"
+msgstr "以新值å–代有多項值的組態é¸é …"
#: builtin/config.c
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "ä¸èƒ½å»ºç«‹è¨­å®šæª”案 %s"
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr "人類å¯è®€çš„備註字串(將按需æ’å…¥ # è‡³å‰æ–¹ï¼‰"
+
+#: builtin/config.c
+msgid "add a new line without altering any existing values"
+msgstr "åœ¨ä¸æ›´å‹•ä»»ä½•ç¾æœ‰å€¼çš„æƒ…æ³ä¸‹æ–°å¢žä¸€è¡Œ"
+
+#: builtin/config.c
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value 僅套用至 --value=<模å¼>"
+
+#: builtin/config.c
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "--append 無法和 --value=<模å¼> 一起使用"
#: builtin/config.c
#, c-format
@@ -6476,6 +6589,109 @@ msgstr ""
msgid "no such section: %s"
msgstr "ç„¡æ­¤å°ç¯€ï¼š%s"
+#: builtin/config.c
+msgid "editing stdin is not supported"
+msgstr "䏿”¯æ´ç·¨è¼¯æ¨™æº–輸入"
+
+#: builtin/config.c
+msgid "editing blobs is not supported"
+msgstr "䏿”¯æ´ç·¨è¼¯è³‡æ–™ç‰©ä»¶"
+
+#: builtin/config.c
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "ä¸èƒ½å»ºç«‹è¨­å®šæª”案 %s"
+
+#: builtin/config.c
+msgid "Action"
+msgstr "動作"
+
+#: builtin/config.c
+msgid "get value: name [<value-pattern>]"
+msgstr "å–得值:name [<value-pattern>]"
+
+#: builtin/config.c
+msgid "get all values: key [<value-pattern>]"
+msgstr "å–得所有值:key [<value-pattern>]"
+
+#: builtin/config.c
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr "根據常è¦è¡¨ç¤ºå¼å–得值:name-regex [<value-pattern>]"
+
+#: builtin/config.c
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "ç²å¾— URL å–值:section[.var] URL"
+
+#: builtin/config.c
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr "å–代所有符åˆçš„變數:name value [<value-pattern>]"
+
+#: builtin/config.c
+msgid "add a new variable: name value"
+msgstr "新增一個新的變數:name value"
+
+#: builtin/config.c
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "移除一個變數:name [<value-pattern>]"
+
+#: builtin/config.c
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "移除所有符åˆé …目:name [<value-pattern>]"
+
+#: builtin/config.c
+msgid "rename section: old-name new-name"
+msgstr "釿–°å‘½åå°ç¯€ï¼šold-name new-name"
+
+#: builtin/config.c
+msgid "remove a section: name"
+msgstr "刪除一個å°ç¯€ï¼šname"
+
+#: builtin/config.c
+msgid "list all"
+msgstr "全部列出"
+
+#: builtin/config.c
+msgid "open an editor"
+msgstr "開啟一個編輯器"
+
+#: builtin/config.c
+msgid "find the color configured: slot [<default>]"
+msgstr "ç²å¾—設定的é¡è‰²ï¼šè¨­å®š [<é è¨­å€¼>]"
+
+#: builtin/config.c
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "ç²å¾—é¡è‰²è¨­å®šï¼šè¨­å®š [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid "with --get, use default value when missing entry"
+msgstr "使用 --get ä½†æœªæŒ‡å®šåƒæ•¸æ™‚所使用的é è¨­å€¼"
+
+#: builtin/config.c
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color 和變數類型ä¸ç›¸å®¹"
+
+#: builtin/config.c
+msgid "no action specified"
+msgstr "未指定動作"
+
+#: builtin/config.c
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only 僅é©ç”¨æ–¼ --list 或 --get-regexp"
+
+#: builtin/config.c
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr "--show-origin 僅é©ç”¨æ–¼ --getã€--get-allã€--get-regexp å’Œ --list"
+
+#: builtin/config.c
+msgid "--default is only applicable to --get"
+msgstr "--default 僅é©ç”¨æ–¼ --get"
+
+#: builtin/config.c
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment åªèƒ½ç”¨æ–¼åŠ å…¥ã€è¨­å®šå’Œå–代動作"
+
#: builtin/count-objects.c
msgid "print sizes in human readable format"
msgstr "以使用者å¯è®€çš„æ ¼å¼é¡¯ç¤ºå¤§å°"
@@ -6660,11 +6876,11 @@ msgstr "標記"
#: builtin/describe.c
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
-msgstr "å°æ–¼é«’工作å€ï¼Œè¿½åŠ  <標記>(é è¨­å€¼ï¼šâ€-dirty\")"
+msgstr "å°æ–¼é«’工作å€ï¼Œè¿½åŠ  <標記>(é è¨­å€¼ï¼šã€-dirty\")"
#: builtin/describe.c
msgid "append <mark> on broken working tree (default: \"-broken\")"
-msgstr "å°æ–¼æå£žçš„工作å€ï¼Œè¿½åŠ  <標記>(é è¨­å€¼ï¼šâ€-broken\")"
+msgstr "å°æ–¼æå£žçš„工作å€ï¼Œè¿½åŠ  <標記>(é è¨­å€¼ï¼šã€-broken\")"
#: builtin/describe.c
msgid "No names found, cannot describe anything."
@@ -7005,7 +7221,7 @@ msgstr "來自 %.*s\n"
#: builtin/fetch.c
#, c-format
msgid "object %s not found"
-msgstr "物件 %s 未發ç¾"
+msgstr "找ä¸åˆ°ç‰©ä»¶ %s"
#: builtin/fetch.c
msgid "[up to date]"
@@ -7079,8 +7295,8 @@ msgstr ""
#: builtin/fetch.c
#, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s æœªå‚³é€æ‰€æœ‰å¿…需的物件\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s æœªå‚³é€æ‰€æœ‰å¿…需的物件"
#: builtin/fetch.c
#, c-format
@@ -7128,8 +7344,8 @@ msgstr "é¸é …「%sã€çš„值「%sã€å° %s 無效"
#: builtin/fetch.c
#, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "é¸é …「%sã€è¢« %s 忽略\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "é¸é …「%sã€è¢« %s 忽略"
#: builtin/fetch.c object-file.c
#, c-format
@@ -7329,7 +7545,7 @@ msgstr "在所有更新分支上檢查強制更新"
#: builtin/fetch.c
msgid "write the commit-graph after fetching"
-msgstr "抓å–後寫入分支圖"
+msgstr "抓å–後寫入æäº¤åœ–"
#: builtin/fetch.c
msgid "accept refspecs from stdin"
@@ -7485,6 +7701,10 @@ msgid "read reference patterns from stdin"
msgstr "從 stdin 讀å–引用模å¼"
#: builtin/for-each-ref.c
+msgid "also include HEAD ref and pseudorefs"
+msgstr "åŒ…å« HEAD 引用和å½å¼•用"
+
+#: builtin/for-each-ref.c
msgid "unknown arguments supplied with --stdin"
msgstr "為 --stdin æä¾›çš„引數未知"
@@ -7501,6 +7721,10 @@ msgid "config key storing a list of repository paths"
msgstr "儲存版本庫路徑清單的設定éµ"
#: builtin/for-each-repo.c
+msgid "keep going even if command fails in a repository"
+msgstr "命令在版本庫中失敗時ä»ç¹¼çºŒåŸ·è¡Œ"
+
+#: builtin/for-each-repo.c
msgid "missing --config=<config>"
msgstr "缺少 --config=<設定>"
@@ -7715,12 +7939,12 @@ msgstr "%s:%s 的 resolve-undo 中的 sha1 指標無效"
#: builtin/fsck.c
#, c-format
msgid "unable to load rev-index for pack '%s'"
-msgstr "ç„¡æ³•è®€å– â€œ%s†å°è£çš„修訂版索引 (rev-index)"
+msgstr "無法讀å–「%sã€å°è£çš„修訂版索引 (rev-index)"
#: builtin/fsck.c
#, c-format
msgid "invalid rev-index for pack '%s'"
-msgstr "“%s†å°è£çš„修訂版索引 (rev-index) 無效"
+msgstr "「%sã€å°è£çš„修訂版索引 (rev-index) 無效"
#: builtin/fsck.c
msgid ""
@@ -7954,6 +8178,10 @@ msgstr "清除未引用的物件"
msgid "pack unreferenced objects separately"
msgstr "ç¨ç«‹å°è£ç„¡å¼•用物件"
+#: builtin/gc.c builtin/repack.c
+msgid "with --cruft, limit the size of new cruft packs"
+msgstr "æ­é… --cruft,é™åˆ¶æ–°å»¢æ£„å°è£çš„大å°"
+
#: builtin/gc.c
msgid "be more thorough (increased runtime)"
msgstr "更徹底(增加執行時間)"
@@ -7963,6 +8191,10 @@ msgid "enable auto-gc mode"
msgstr "啟用自動垃圾回收模å¼"
#: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "在背景執行垃圾回收"
+
+#: builtin/gc.c
msgid "force running gc even if there may be another gc running"
msgstr "強制執行 gc å³ä½¿å¦å¤–一個 gc 正在執行"
@@ -8023,7 +8255,7 @@ msgstr "無法識別的 --schedule 引數 '%s'"
#: builtin/gc.c
msgid "failed to write commit-graph"
-msgstr "無法寫入æäº¤åœ–å½¢"
+msgstr "無法寫入æäº¤åœ–"
#: builtin/gc.c
msgid "failed to prefetch remotes"
@@ -8079,6 +8311,10 @@ msgid "run tasks based on the state of the repository"
msgstr "基於版本庫狀態執行作業"
#: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "在背景執行維護"
+
+#: builtin/gc.c
msgid "frequency"
msgstr "frequency"
@@ -8150,7 +8386,7 @@ msgstr "無法啟動 schtasks"
#: builtin/gc.c
msgid "failed to run 'crontab -l'; your system might not support 'cron'"
-msgstr "無法執行 “crontab -lâ€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ “cronâ€"
+msgstr "無法執行「crontab -lã€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ã€Œcronã€"
#: builtin/gc.c
msgid "failed to create crontab temporary file"
@@ -8162,19 +8398,11 @@ msgstr "無法開啟暫存檔"
#: builtin/gc.c
msgid "failed to run 'crontab'; your system might not support 'cron'"
-msgstr "無法執行 “crontabâ€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ “cronâ€"
+msgstr "無法執行「crontabã€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ã€Œcronã€"
#: builtin/gc.c
msgid "'crontab' died"
-msgstr "“crontabâ€ çµæŸé‹ä½œ"
-
-#: builtin/gc.c
-msgid "failed to start systemctl"
-msgstr "無法啟動 systemctl"
-
-#: builtin/gc.c
-msgid "failed to run systemctl"
-msgstr "無法執行 systemctl"
+msgstr "「crontabã€çµæŸé‹ä½œ"
#: builtin/gc.c builtin/worktree.c
#, c-format
@@ -8187,6 +8415,14 @@ msgid "failed to flush '%s'"
msgstr "排清 '%s' 失敗"
#: builtin/gc.c
+msgid "failed to start systemctl"
+msgstr "無法啟動 systemctl"
+
+#: builtin/gc.c
+msgid "failed to run systemctl"
+msgstr "無法執行 systemctl"
+
+#: builtin/gc.c
#, c-format
msgid "unrecognized --scheduler argument '%s'"
msgstr "無法識別的 --scheduler 引數 '%s'"
@@ -8217,6 +8453,10 @@ msgid "scheduler to trigger git maintenance run"
msgstr "è¦è§¸ç™¼ git maintenance run 的排程器"
#: builtin/gc.c
+msgid "failed to set up maintenance schedule"
+msgstr "無法設定維護排程"
+
+#: builtin/gc.c
msgid "failed to add repo to global config"
msgstr "無法將版本庫加至全域設定"
@@ -8249,8 +8489,8 @@ msgstr "沒有執行緒支æ´ï¼Œå¿½ç•¥ %s"
#: builtin/grep.c
#, c-format
-msgid "unable to read tree (%s)"
-msgstr "ç„¡æ³•è®€å–æ¨¹ï¼ˆ%s)"
+msgid "unable to read tree %s"
+msgstr "ç„¡æ³•è®€å– %s 樹狀物件"
#: builtin/grep.c
#, c-format
@@ -8312,8 +8552,8 @@ msgid "search in subdirectories (default)"
msgstr "在å­ç›®éŒ„中尋找(é è¨­å€¼ï¼‰"
#: builtin/grep.c
-msgid "descend at most <depth> levels"
-msgstr "最多以指定的深度å‘下尋找"
+msgid "descend at most <n> levels"
+msgstr "最多å‘下尋找 <n> 層"
#: builtin/grep.c
msgid "use extended POSIX regular expressions"
@@ -8774,11 +9014,6 @@ msgstr "解壓縮嚴é‡çš„ä¸ä¸€è‡´"
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr "ç™¼ç¾ %s å‡ºç¾ SHA1 è¡çªï¼"
-#: builtin/index-pack.c builtin/pack-objects.c
-#, c-format
-msgid "unable to read %s"
-msgstr "ä¸èƒ½è®€ %s"
-
#: builtin/index-pack.c
#, c-format
msgid "cannot read existing object info %s"
@@ -8952,11 +9187,13 @@ msgstr "在打包物件中 fsck 檢查發生錯誤"
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
msgstr ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+" [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"
@@ -9009,13 +9246,46 @@ msgstr "--separate-git-dir 與純版本庫ä¸ç›¸å®¹"
#: builtin/interpret-trailers.c
msgid ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
msgstr ""
"git interpret-trailers [--in-place] [--trim-empty]\n"
-" [(--trailer <token>[(=|:)<value>])...]\n"
+" [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"
+#: builtin/interpret-trailers.c wrapper.c
+#, c-format
+msgid "could not stat %s"
+msgstr "ä¸èƒ½å° %s å‘¼å« stat"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "檔案 %s 䏿˜¯ä¸€å€‹æ­£è¦æª”案"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "檔案 %s 使用者ä¸å¯å¯«"
+
+#: builtin/interpret-trailers.c
+msgid "could not open temporary file"
+msgstr "ä¸èƒ½é–‹å•Ÿæš«å­˜æª”"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "ä¸èƒ½è®€å–輸入檔案 '%s'"
+
+#: builtin/interpret-trailers.c builtin/mktag.c imap-send.c
+msgid "could not read from stdin"
+msgstr "ä¸èƒ½è‡ªæ¨™æº–輸入讀å–"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "ä¸èƒ½é‡æ–°å‘½å暫存檔為 %s"
+
#: builtin/interpret-trailers.c
msgid "edit files in place"
msgstr "在原ä½ç·¨è¼¯æª”案"
@@ -9025,6 +9295,10 @@ msgid "trim empty trailers"
msgstr "刪除空的尾部署å"
#: builtin/interpret-trailers.c
+msgid "placement"
+msgstr "placement"
+
+#: builtin/interpret-trailers.c
msgid "where to place the new trailer"
msgstr "在哪裡放置新的尾部署å"
@@ -9041,20 +9315,20 @@ msgid "output only the trailers"
msgstr "åªè¼¸å‡ºå°¾éƒ¨ç½²å"
#: builtin/interpret-trailers.c
-msgid "do not apply config rules"
-msgstr "ä¸è¦å¥—用組態設定è¦å‰‡"
+msgid "do not apply trailer.* configuration variables"
+msgstr "ä¸å¥—用 trailer.* 組態變數"
#: builtin/interpret-trailers.c
-msgid "join whitespace-continued values"
-msgstr "連線空白折行的值"
+msgid "reformat multiline trailer values as single-line values"
+msgstr "將多列尾注值 (trailer values) 釿–°æ ¼å¼åŒ–為單列值"
#: builtin/interpret-trailers.c
-msgid "set parsing options"
-msgstr "設定解æžé¸é …"
+msgid "alias for --only-trailers --only-input --unfold"
+msgstr "--only-trailers --only-input --unfold 的別å"
#: builtin/interpret-trailers.c
-msgid "do not treat --- specially"
-msgstr "ä¸è¦å° --- 特殊處ç†"
+msgid "do not treat \"---\" as the end of input"
+msgstr "ä¸è¦æŠŠã€Œ---ã€ç•¶ä½œè¼¸å…¥çµå°¾"
#: builtin/interpret-trailers.c
msgid "trailer(s) to add"
@@ -9111,10 +9385,10 @@ msgid ""
"<file>"
msgstr "追蹤 <é–‹å§‹>,<çµæŸ> 範åœä¸­æ©«åˆ—或 <檔案> 中> :<函數å稱> 的變化å²"
-#: builtin/log.c builtin/shortlog.c bundle.c
+#: builtin/log.c builtin/replay.c builtin/shortlog.c bundle.c
#, c-format
msgid "unrecognized argument: %s"
-msgstr "ç„¡æ³•è­˜åˆ¥çš„åƒæ•¸ï¼š%s"
+msgstr "無法識別的引數:%s"
#: builtin/log.c
msgid "-L<range>:<file> cannot be used with pathspec"
@@ -9126,10 +9400,6 @@ msgid "Final output: %d %s\n"
msgstr "最終輸出:%d %s\n"
#: builtin/log.c
-msgid "unable to create temporary object directory"
-msgstr "無法建立暫存物件目錄"
-
-#: builtin/log.c
#, c-format
msgid "git show %s: bad file"
msgstr "git show %s: æå£žçš„æª”案"
@@ -9167,6 +9437,11 @@ msgid "not a range"
msgstr "䏿˜¯ä¸€å€‹ç¯„åœ"
#: builtin/log.c
+#, c-format
+msgid "unable to read branch description file '%s'"
+msgstr "無法讀å–分支æè¿°æª”「%sã€"
+
+#: builtin/log.c
msgid "cover letter needs email format"
msgstr "附函需è¦ä¿¡ä»¶ä½å€æ ¼å¼"
@@ -9281,8 +9556,12 @@ msgid "max length of output filename"
msgstr "輸出檔å的最大長度"
#: builtin/log.c
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "使用 [RFC PATCH] 代替 [PATCH]"
+msgid "rfc"
+msgstr "rfc"
+
+#: builtin/log.c
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "在「PATCHã€å‰å† ä¸Š <rfc>(é è¨­ç‚ºã€ŒRFCã€ï¼‰"
#: builtin/log.c
msgid "cover-from-description-mode"
@@ -9293,6 +9572,10 @@ msgid "generate parts of a cover letter based on a branch's description"
msgstr "基於分支æè¿°ç”¢ç”Ÿéƒ¨åˆ†é™„函"
#: builtin/log.c
+msgid "use branch description from file"
+msgstr "從檔案讀å–分支æè¿°ä¸¦ä½¿ç”¨"
+
+#: builtin/log.c
msgid "use [<prefix>] instead of [PATCH]"
msgstr "使用 [<å‰ç¶´>] 代替 [PATCH]"
@@ -9501,21 +9784,6 @@ 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 '('"
-msgstr "ls-files æ ¼å¼éŒ¯èª¤ï¼šâ€œ%s†元素ä¸ä»¥ “(†開頭"
-
-#: builtin/ls-files.c
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "ls-files æ ¼å¼éŒ¯èª¤ï¼šâ€œ%s†元素ä¸ä»¥ “)†çµå°¾"
-
-#: builtin/ls-files.c
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "ls-files æ ¼å¼éŒ¯èª¤ï¼š%%%.*s"
-
-#: builtin/ls-files.c
msgid "git ls-files [<options>] [<file>...]"
msgstr "git ls-files [<é¸é …>] [<檔案>...]"
@@ -9607,7 +9875,7 @@ msgstr "é¡¯ç¤ºç›¸å°æ–¼é ‚級目錄的檔案å"
msgid "if any <file> is not in the index, treat this as an error"
msgstr "如果任何 <檔案> 都ä¸åœ¨ç´¢å¼•å€ï¼Œè¦–為錯誤"
-#: builtin/ls-files.c
+#: builtin/ls-files.c builtin/merge-tree.c
msgid "tree-ish"
msgstr "樹或æäº¤"
@@ -9636,11 +9904,11 @@ msgstr ""
#: builtin/ls-remote.c
msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--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=<exec>]\n"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
" [--symref] [<repository> [<patterns>...]]"
@@ -9661,9 +9929,13 @@ msgid "limit to tags"
msgstr "åƒ…é™æ–¼æ¨™ç±¤"
#: builtin/ls-remote.c
-msgid "limit to heads"
+msgid "limit to branches"
msgstr "åƒ…é™æ–¼åˆ†æ”¯"
+#: builtin/ls-remote.c builtin/show-ref.c
+msgid "deprecated synonym for --branches"
+msgstr "--branches 已棄用的åŒç¾©è©ž"
+
#: builtin/ls-remote.c
msgid "do not show peeled tags"
msgstr "ä¸é¡¯ç¤ºå·²è§£æžçš„æ¨™ç±¤"
@@ -9685,21 +9957,6 @@ msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
msgstr "git ls-tree [<é¸é …>] <樹或æäº¤> [<路徑>...]"
#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "無效的 ls-tree æ ¼å¼ï¼šã€Œ%sã€å…ƒç´ çš„開頭䏿˜¯ã€Œ(ã€"
-
-#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "無效的 ls-tree æ ¼å¼ï¼šã€Œ%sã€å…ƒç´ çš„çµå°¾ä¸æ˜¯ã€Œ)ã€"
-
-#: builtin/ls-tree.c
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "無效的 ls-tree æ ¼å¼ï¼š%%%.*s"
-
-#: builtin/ls-tree.c
msgid "only show trees"
msgstr "åªé¡¯ç¤ºæ¨¹"
@@ -9845,11 +10102,22 @@ msgstr ""
"git merge-file [<é¸é …>] [-L <檔案1> [-L <åˆå§‹> [-L <åå­—2>]]] <檔案1> <åˆå§‹æ–‡"
"件> <檔案2>"
+#: builtin/merge-file.c diff.c
+msgid ""
+"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
+"\"histogram\""
+msgstr ""
+"diff-algorithm é¸é …有 \"myers\"ã€\"minimal\"ã€\"patience\" å’Œ \"histogram\""
+
#: builtin/merge-file.c
msgid "send results to standard output"
msgstr "å°‡çµæžœå‚³é€åˆ°æ¨™æº–輸出"
#: builtin/merge-file.c
+msgid "use object IDs instead of filenames"
+msgstr "使用物件 ID å–代檔å"
+
+#: builtin/merge-file.c
msgid "use a diff3 based merge"
msgstr "使用基於 diff3 çš„åˆä½µ"
@@ -9857,17 +10125,13 @@ msgstr "使用基於 diff3 çš„åˆä½µ"
msgid "use a zealous diff3 based merge"
msgstr "使用基於 zealous diff3 çš„åˆä½µ"
-#: builtin/merge-file.c
-msgid "for conflicts, use our version"
-msgstr "如果è¡çªï¼Œä½¿ç”¨æˆ‘們的版本"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use their version"
-msgstr "如果è¡çªï¼Œä½¿ç”¨ä»–們的版本"
+#: builtin/merge-file.c diff.c
+msgid "<algorithm>"
+msgstr "<演算法>"
-#: builtin/merge-file.c
-msgid "for conflicts, use a union version"
-msgstr "如果è¡çªï¼Œä½¿ç”¨è¯åˆç‰ˆæœ¬"
+#: builtin/merge-file.c diff.c
+msgid "choose a diff algorithm"
+msgstr "鏿“‡ä¸€å€‹å·®ç•°æ¼”算法"
#: builtin/merge-file.c
msgid "for conflicts, use this marker size"
@@ -9881,6 +10145,15 @@ msgstr "ä¸è¦è­¦å‘Šè¡çª"
msgid "set labels for file1/orig-file/file2"
msgstr "為 檔案1/åˆå§‹æª”案/檔案2 設定標籤"
+#: builtin/merge-file.c
+#, c-format
+msgid "object '%s' does not exist"
+msgstr "物件「%sã€ä¸å­˜åœ¨"
+
+#: builtin/merge-file.c
+msgid "Could not write object file"
+msgstr "無法寫入物件檔案"
+
#: builtin/merge-recursive.c
#, c-format
msgid "unknown option %s"
@@ -9911,6 +10184,11 @@ msgstr "無法解æžå¼•用 '%s'"
msgid "Merging %s with %s\n"
msgstr "åˆä½µ %s å’Œ %s\n"
+#: builtin/merge-tree.c
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "無法解æžç‚ºæ¨¹ç‹€ç‰©ä»¶ã€Œ%sã€"
+
#: builtin/merge-tree.c builtin/merge.c
msgid "not something we can merge"
msgstr "ä¸èƒ½åˆä½µ"
@@ -9959,13 +10237,22 @@ msgstr "執行多次åˆä½µï¼Œä¸€æ¬¡åŸ·è¡Œè¼¸å…¥ä¸€åˆ—"
msgid "specify a merge-base for the merge"
msgstr "指定用來åˆä½µçš„åˆä½µåŸºåº•"
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option=value"
+msgstr "option=value"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "option for selected merge strategy"
+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/merge.c
+#, c-format
+msgid "unknown strategy option: -X%s"
+msgstr "未知的策略é¸é …:-X%s"
#: builtin/merge-tree.c builtin/notes.c
#, c-format
@@ -10054,14 +10341,6 @@ msgstr "ç­–ç•¥"
msgid "merge strategy to use"
msgstr "è¦ä½¿ç”¨çš„åˆä½µç­–ç•¥"
-#: builtin/merge.c builtin/pull.c
-msgid "option=value"
-msgstr "option=value"
-
-#: builtin/merge.c builtin/pull.c
-msgid "option for selected merge strategy"
-msgstr "所é¸çš„åˆä½µç­–略的é¸é …"
-
#: builtin/merge.c
msgid "merge commit message (for a non-fast-forward merge)"
msgstr "åˆä½µçš„æäº¤èªªæ˜Žï¼ˆé‡å°éžå¿«è½‰å¼åˆä½µï¼‰"
@@ -10133,7 +10412,7 @@ msgstr "'%s' 沒有指å‘一個æäº¤"
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "壞的 branch.%s.mergeoptions 字串:%s"
-#: builtin/merge.c builtin/stash.c merge-recursive.c
+#: builtin/merge.c merge-recursive.c
msgid "Unable to write index."
msgstr "ä¸èƒ½å¯«å…¥ç´¢å¼•。"
@@ -10141,12 +10420,7 @@ msgstr "ä¸èƒ½å¯«å…¥ç´¢å¼•。"
msgid "Not handling anything other than two heads merge."
msgstr "未處ç†å…©å€‹é ­åˆä½µä¹‹å¤–的任何動作。"
-#: builtin/merge.c
-#, c-format
-msgid "unknown strategy option: -X%s"
-msgstr "未知的策略é¸é …:-X%s"
-
-#: builtin/merge.c t/helper/test-fast-rebase.c
+#: builtin/merge.c builtin/sparse-checkout.c
#, c-format
msgid "unable to write %s"
msgstr "ä¸èƒ½å¯« %s"
@@ -10178,9 +10452,9 @@ msgstr "空的æäº¤èªªæ˜Žæœƒçµ‚æ­¢æäº¤ã€‚\n"
#: builtin/merge.c
#, c-format
msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n"
-msgstr "以 '%c' 開始的行將被忽略,而空的æäº¤èªªæ˜Žå°‡çµ‚æ­¢æäº¤ã€‚\n"
+msgstr "以「%sã€é–‹å§‹çš„列將被忽略,æäº¤èªªæ˜Žç•™ç©ºå‰‡æœƒçµ‚æ­¢æäº¤ã€‚\n"
#: builtin/merge.c
msgid "Empty commit message."
@@ -10373,10 +10647,6 @@ msgstr "ç„¡æ³•è®€å–æœ‰æ¨™ç±¤çš„物件「%sã€"
msgid "object '%s' tagged as '%s', but is a '%s' type"
msgstr "「%sã€å·²æ¨™ç‚ºã€Œ%sã€ï¼Œä½†å»æ˜¯ã€Œ%sã€é¡žåž‹"
-#: builtin/mktag.c imap-send.c trailer.c
-msgid "could not read from stdin"
-msgstr "ä¸èƒ½è‡ªæ¨™æº–輸入讀å–"
-
#: builtin/mktag.c
msgid "tag on stdin did not pass our strict fsck check"
msgstr "stdin ä¸Šçš„æ¨™ç±¤æœªé€šéŽæˆ‘們的嚴格 fsck 檢查"
@@ -10442,6 +10712,10 @@ msgid "write multi-pack bitmap"
msgstr "寫入多包ä½åœ–"
#: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "å¯«å…¥æ–°çš„å¢žé‡ MIDX"
+
+#: builtin/multi-pack-index.c
msgid "write multi-pack index containing only given indexes"
msgstr "寫入åªåŒ…嫿Œ‡å®šç´¢å¼•的多包索引"
@@ -10504,8 +10778,8 @@ msgid "can not move directory into itself"
msgstr "ä¸èƒ½å°‡ç›®éŒ„移動到自身"
#: builtin/mv.c
-msgid "cannot move directory over file"
-msgstr "ä¸èƒ½å°‡ç›®éŒ„移動到檔案"
+msgid "destination already exists"
+msgstr "目的地已存在"
#: builtin/mv.c
msgid "source directory is empty"
@@ -10589,7 +10863,7 @@ msgstr "列出å¯ä»¥å¾žæ‰€æœ‰å¼•用存å–çš„æäº¤"
#: builtin/name-rev.c
msgid "deprecated: use --annotate-stdin instead"
-msgstr "已廢棄:請改用 --annotate-stdin"
+msgstr "已棄用:請改用 --annotate-stdin"
#: builtin/name-rev.c
msgid "annotate text from stdin"
@@ -10709,11 +10983,6 @@ msgid "Write/edit the notes for the following object:"
msgstr "為下é¢çš„物件寫/編輯說明:"
#: builtin/notes.c
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "ä¸èƒ½ç‚ºç‰©ä»¶ '%s' é–‹å§‹ 'show'"
-
-#: builtin/notes.c
msgid "could not read 'show' output"
msgstr "ä¸èƒ½è®€å– 'show' 的輸出"
@@ -10856,8 +11125,8 @@ 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 ""
-"å­æŒ‡ä»¤ 'edit' çš„é¸é … -m/-F/-c/-C 已棄用。\n"
-"è«‹æ›ç”¨ 'git notes add -f -m/-F/-c/-C'。\n"
+"å­æŒ‡ä»¤ã€Œeditã€çš„é¸é … -m/-F/-c/-C 已棄用。\n"
+"è«‹æ›ç”¨ã€Œgit notes add -f -m/-F/-c/-Cã€ã€‚\n"
#: builtin/notes.c
msgid "failed to delete ref NOTES_MERGE_PARTIAL"
@@ -11134,6 +11403,11 @@ msgstr "ä¸ä¸€è‡´çš„差異計數"
#: builtin/pack-objects.c
#, c-format
+msgid "invalid pack.allowPackReuse value: '%s'"
+msgstr "無效的 pack.allowPackReuse 值:「%sã€"
+
+#: builtin/pack-objects.c
+#, c-format
msgid ""
"value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
"hash> <uri>' (got '%s')"
@@ -11433,10 +11707,6 @@ msgid "--thin cannot be used to build an indexable pack"
msgstr "--thin ä¸èƒ½ç”¨æ–¼å»ºç«‹ä¸€å€‹å¯ç´¢å¼•包"
#: builtin/pack-objects.c
-msgid "cannot use --filter without --stdout"
-msgstr "ä¸èƒ½åœ¨æ²’有 --stdout 的情æ³ä¸‹ä½¿ç”¨ --filter"
-
-#: builtin/pack-objects.c
msgid "cannot use --filter with --stdin-packs"
msgstr "無法將 --filter åŠ --stdin-packs çµåˆä½¿ç”¨"
@@ -11453,10 +11723,6 @@ msgid "cannot use --stdin-packs with --cruft"
msgstr "無法將 --stdin-packs 與 --cruft 組åˆä½¿ç”¨"
#: builtin/pack-objects.c
-msgid "cannot use --max-pack-size with --cruft"
-msgstr "無法將 --max-pack-size 與 --cruft 組åˆä½¿ç”¨"
-
-#: builtin/pack-objects.c
msgid "Enumerating objects"
msgstr "枚舉物件"
@@ -11464,10 +11730,10 @@ msgstr "枚舉物件"
#, c-format
msgid ""
"Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
-"reused %<PRIu32>"
+"reused %<PRIu32> (from %<PRIuMAX>)"
msgstr ""
"總共 %<PRIu32> (差異 %<PRIu32>),復用 %<PRIu32> (差異 %<PRIu32>),é‡ç”¨åŒ… "
-"%<PRIu32>"
+"%<PRIu32> (總共 %<PRIuMAX>)"
#: builtin/pack-redundant.c
msgid ""
@@ -11489,10 +11755,10 @@ msgstr "傳入 --i-still-use-this 剿‹’絕執行"
#: builtin/pack-refs.c
msgid ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
"<pattern>]"
#: builtin/pack-refs.c
@@ -11504,6 +11770,10 @@ msgid "prune loose refs (default)"
msgstr "剪除鬆散引用(é è¨­å€¼ï¼‰"
#: builtin/pack-refs.c
+msgid "auto-pack refs as needed"
+msgstr "按需自動å°è£å¼•用"
+
+#: builtin/pack-refs.c
msgid "references to include"
msgstr "è¦åŒ…å«çš„引用"
@@ -11779,7 +12049,7 @@ msgid ""
"To choose either option permanently, see push.default in 'git help config'.\n"
msgstr ""
"\n"
-"è‹¥è¦æ°¸ä¹…鏿“‡æŸå€‹é¸é …,請åƒé–± “git help config†中的 push.default。\n"
+"è‹¥è¦æ°¸ä¹…鏿“‡æŸå€‹é¸é …,請åƒé–±ã€Œgit help configã€ä¸­çš„ push.default。\n"
#: builtin/push.c
msgid ""
@@ -11790,8 +12060,8 @@ msgid ""
msgstr ""
"\n"
"è‹¥è¦é¿å…在å稱與本機分支ä¸åŒæ™‚自動設定上游分支,\n"
-"è«‹åƒé–± “git help config†中 branch.autoSetupMerge çš„\n"
-"“simple†é¸é …。\n"
+"è«‹åƒé–±ã€Œgit help configã€ä¸­ branch.autoSetupMerge çš„\n"
+"「simpleã€é¸é …。\n"
#: builtin/push.c
#, c-format
@@ -11838,8 +12108,8 @@ msgid ""
"upstream, see 'push.autoSetupRemote' in 'git help config'.\n"
msgstr ""
"\n"
-"è‹¥è¦ä½¿æ²’有追蹤上游的分支自動é…置,請åƒé–± “git help config†中的\n"
-"“push.autoSetupRemoteâ€ã€‚\n"
+"è‹¥è¦ä½¿æ²’有追蹤上游的分支自動é…置,請åƒé–±ã€Œgit help configã€ä¸­çš„\n"
+"「push.autoSetupRemoteã€ã€‚\n"
#: builtin/push.c
#, c-format
@@ -11884,8 +12154,8 @@ msgid ""
"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 ""
@@ -11895,8 +12165,8 @@ msgid ""
"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 ""
@@ -11908,7 +12178,7 @@ msgid ""
msgstr ""
"更新被拒絕,因為é ç«¯åŒ…嫿‚¨æœ¬æ©Ÿæ²’有的æäº¤ã€‚這通常是因為\n"
"å¦ä¸€å€‹ç‰ˆæœ¬åº«æœ‰æŽ¨é€æ›´å‹•到åŒå€‹å¼•ç”¨ã€‚å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•,\n"
-"è«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ “git pullâ€ã€‚詳見 “git push --help†中的\n"
+"è«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ã€Œgit pullã€ã€‚詳見「git push --helpã€ä¸­çš„\n"
"〈Note about fast-forwards〉å°ç¯€ã€‚"
#: builtin/push.c
@@ -11932,8 +12202,8 @@ msgid ""
"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
#, c-format
@@ -12267,19 +12537,6 @@ msgid "could not remove '%s'"
msgstr "無法刪除 '%s'"
#: builtin/rebase.c
-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 ""
-"手動解決所有è¡çªï¼ŒåŸ·è¡Œ \"git add/rm <è¡çªçš„æª”案>\" 標記\n"
-"è¡çªå·²è§£æ±ºï¼Œç„¶å¾ŒåŸ·è¡Œ \"git rebase --continue\"。您也å¯ä»¥åŸ·è¡Œ\n"
-"\"git rebase --skip\" 指令略éŽé€™å€‹æäº¤ã€‚如果想è¦çµ‚止執行並回到\n"
-"\"git rebase\" 執行之å‰çš„狀態,執行 \"git rebase --abort\"。"
-
-#: builtin/rebase.c
#, c-format
msgid ""
"\n"
@@ -12312,11 +12569,15 @@ msgid "apply options and merge options cannot be used together"
msgstr "套用é¸é …與åˆä½µé¸é …ä¸å¾—åŒæ™‚使用"
#: builtin/rebase.c
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask 已棄用。請改用「--empty=stopã€ã€‚"
+
+#: builtin/rebase.c
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
-msgstr "無法識別的 '%s' 空類型;有效的數值有 \"drop\"ã€\"keep\" è·Ÿ \"ask\"。"
+"\"stop\"."
+msgstr "無法識別空類型「%sã€ï¼›æœ‰æ•ˆçš„æ•¸å€¼æœ‰ã€Œdropã€ã€ã€Œkeepã€è·Ÿã€Œstopã€ã€‚"
#: builtin/rebase.c
msgid ""
@@ -12458,7 +12719,7 @@ msgstr "讓使用者編輯è¦é‡å®šåŸºåº•çš„æäº¤åˆ—表"
msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
msgstr "ï¼ˆå·²ç§»é™¤ï¼‰æ›¾ç‚ºï¼šå˜—è©¦é‡æ–°å»ºç«‹ï¼Œè€Œéžå¿½ç•¥åˆä½µ"
-#: builtin/rebase.c
+#: builtin/rebase.c builtin/revert.c
msgid "how to handle commits that become empty"
msgstr "處ç†ç©ºç™½æäº¤çš„æ–¹å¼"
@@ -12535,18 +12796,18 @@ msgid ""
"which is no longer supported; use 'merges' instead"
msgstr ""
"--preserve-merges 已被 --rebase-merges å–代\n"
-"註:您的 `pull.rebase` 設定å¯èƒ½ä¹Ÿè¢«è¨­å®šç‚ºä¸å—支æ´çš„ “preserveâ€ï¼›\n"
-"請改用 “mergesâ€"
+"註:您的 `pull.rebase` 設定å¯èƒ½ä¹Ÿè¢«è¨­å®šç‚ºä¸å—支æ´çš„「preserveã€ï¼›\n"
+"請改用「mergesã€"
#: builtin/rebase.c
-msgid "No rebase in progress?"
-msgstr "沒有正在進行的é‡å®šåŸºåº•?"
+msgid "no rebase in progress"
+msgstr "沒有進行中的é‡å®šåŸºåº•æµç¨‹"
#: builtin/rebase.c
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr "動作 --edit-todo åªèƒ½ç”¨åœ¨äº’å‹•å¼é‡å®šåŸºåº•éŽç¨‹ä¸­ã€‚"
-#: builtin/rebase.c t/helper/test-fast-rebase.c
+#: builtin/rebase.c
msgid "Cannot read HEAD"
msgstr "ä¸èƒ½è®€å– HEAD"
@@ -12591,16 +12852,6 @@ msgid "switch `C' expects a numerical value"
msgstr "開關 `C' 期望一個數字值"
#: 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-"
-"autosquash"
-msgstr "apply é¸é …與 rebase.autoSquash ä¸ç›¸å®¹ã€‚請考慮加上 --no-autosquash"
-
-#: builtin/rebase.c
msgid ""
"apply options are incompatible with rebase.rebaseMerges. Consider adding --"
"no-rebase-merges"
@@ -12767,6 +13018,10 @@ msgid "git reflog [show] [<log-options>] [<ref>]"
msgstr "git reflog [show] [<log-options>] [<ref>]"
#: builtin/reflog.c
+msgid "git reflog list"
+msgstr "git reflog list"
+
+#: builtin/reflog.c
msgid ""
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
" [--rewrite] [--updateref] [--stale-fix]\n"
@@ -12795,6 +13050,11 @@ msgstr "git reflog exists <引用>"
msgid "invalid timestamp '%s' given to '--%s'"
msgstr "傳入「--%sã€çš„æ™‚間戳「%sã€ç„¡æ•ˆ"
+#: builtin/reflog.c sequencer.c
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s 䏿ޥå—åƒæ•¸ï¼š'%s'"
+
#: builtin/reflog.c
msgid "do not actually prune any entries"
msgstr "ä¸å¯¦éš›å‰ªé™¤ä»»ä½•é …ç›®"
@@ -12857,6 +13117,39 @@ msgstr "未指定è¦åˆªé™¤çš„引用日誌"
msgid "invalid ref format: %s"
msgstr "無效的引用格å¼ï¼š%s"
+#: builtin/refs.c
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<æ ¼å¼> [--dry-run]"
+
+#: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+#: builtin/refs.c
+msgid "specify the reference format to convert to"
+msgstr "指定è¦è½‰æ›æˆçš„引用格å¼"
+
+#: builtin/refs.c
+msgid "perform a non-destructive dry-run"
+msgstr "進行éžç ´å£žæ€§çš„試執行"
+
+#: builtin/refs.c
+msgid "missing --ref-format=<format>"
+msgstr "缺少 --ref-format=<æ ¼å¼>"
+
+#: builtin/refs.c
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "版本庫已經使用 '%s' æ ¼å¼"
+
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "啟用嚴格檢查"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "「git refs verifyã€ä¸æŽ¥å—引數"
+
#: builtin/remote.c
msgid ""
"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
@@ -12949,13 +13242,13 @@ msgid ""
"--mirror is dangerous and deprecated; please\n"
"\t use --mirror=fetch or --mirror=push instead"
msgstr ""
-"--mirror é¸é …å±éšªä¸”éŽæ™‚,請使用 --mirror=fetch\n"
+"--mirror é¸é …å±éšªä¸”已棄用,請使用 --mirror=fetch\n"
"\t 或 --mirror=push"
#: builtin/remote.c
#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "未知的é¡åƒåƒæ•¸ï¼š%s"
+msgid "unknown --mirror argument: %s"
+msgstr "未知的 --mirror 引數:%s"
#: builtin/remote.c
msgid "fetch the remote branches"
@@ -13085,7 +13378,7 @@ msgid ""
msgid_plural ""
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:"
-msgstr[0] "注æ„:ref/remotes 層級之外的一個分支未被移除。è¦åˆªé™¤å®ƒï¼Œä½¿ç”¨ï¼š"
+msgstr[0] "注æ„:refs/remotes/ 層級之外的一個分支未被移除。è¦åˆªé™¤å®ƒï¼Œä½¿ç”¨ï¼š"
#: builtin/remote.c
#, c-format
@@ -13202,10 +13495,6 @@ msgstr "* é ç«¯ %s"
msgid " Fetch URL: %s"
msgstr " å–å¾—ä½å€ï¼š%s"
-#: builtin/remote.c
-msgid "(no URL)"
-msgstr "(ç„¡ URL)"
-
#. TRANSLATORS: the colon ':' should align
#. with the one in " Fetch URL: %s"
#. translation.
@@ -13216,6 +13505,10 @@ msgid " Push URL: %s"
msgstr " 推é€ä½å€ï¼š%s"
#: builtin/remote.c
+msgid "(no URL)"
+msgstr "(ç„¡ URL)"
+
+#: builtin/remote.c
#, c-format
msgid " HEAD branch: %s"
msgstr " HEAD 分支:%s"
@@ -13350,11 +13643,6 @@ msgid "return all URLs"
msgstr "返回所有 URL ä½å€"
#: builtin/remote.c
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "沒有給é ç«¯ç‰ˆæœ¬åº« '%s' 設定 URL"
-
-#: builtin/remote.c
msgid "manipulate push URLs"
msgstr "å‹•ä½œæŽ¨é€ URLS"
@@ -13405,6 +13693,10 @@ msgid "could not start pack-objects to repack promisor objects"
msgstr "無法開始 pack-objects 來釿–°æ‰“包 promisor 物件"
#: builtin/repack.c
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "無法將承諾者物件喂給 pack-objects"
+
+#: builtin/repack.c
msgid "repack: Expecting full hex object ID lines only from pack-objects."
msgstr "repack:期望來自 pack-objects 的完整å六進ä½ç‰©ä»¶ ID。"
@@ -13442,6 +13734,11 @@ msgid "could not remove stale bitmap: %s"
msgstr "ç„¡æ³•ç§»é™¤éŽæ™‚ä½åœ–:%s"
#: builtin/repack.c
+#, c-format
+msgid "pack prefix %s does not begin with objdir %s"
+msgstr "å°åŒ…å‰ç¶´ %s ä¸ä»¥ objdir %s é–‹é ­"
+
+#: builtin/repack.c
msgid "pack everything in a single pack"
msgstr "所有內容打包到一個包檔案中"
@@ -13542,17 +13839,21 @@ msgid "pack prefix to store a pack containing pruned objects"
msgstr "å°è£å‰ç¶´ï¼Œå„²å­˜ç‚ºåŒ…å«éŽæ™‚物件的套件包"
#: builtin/repack.c
+msgid "pack prefix to store a pack containing filtered out objects"
+msgstr "å°‡å‰ç¶´é€²è¡ŒåŒ…è£ï¼Œå„²å­˜ç‚ºåŒ…å«å·²éŽæ¿¾ç‰©ä»¶çš„å°è£"
+
+#: builtin/repack.c
msgid "cannot delete packs in a precious-objects repo"
msgstr "ä¸èƒ½åˆªé™¤çå“版本庫中的å°åŒ…"
#: builtin/repack.c
-msgid "Nothing new to pack."
-msgstr "æ²’æœ‰æ–°çš„è¦æ‰“包。"
+#, c-format
+msgid "option '%s' can only be used along with '%s'"
+msgstr "「%sã€é¸é …åªèƒ½èˆ‡ã€Œ%sã€ä¸€èµ·ä½¿ç”¨"
#: builtin/repack.c
-#, c-format
-msgid "pack prefix %s does not begin with objdir %s"
-msgstr "å°åŒ…å‰ç¶´ %s ä¸ä»¥ objdir %s é–‹é ­"
+msgid "Nothing new to pack."
+msgstr "æ²’æœ‰æ–°çš„è¦æ‰“包。"
#: builtin/repack.c
#, c-format
@@ -13562,7 +13863,7 @@ msgstr "ç„¡æ³•å°‡åŒ…é‡æ–°å‘½å為「%sã€"
#: builtin/repack.c
#, c-format
msgid "pack-objects did not write a '%s' file for pack %s-%s"
-msgstr "pack-objects 沒有為 %2$s-%3$s 套件包寫入 “%1$s†檔案"
+msgstr "pack-objects 沒有為 %2$s-%3$s 套件包寫入「%1$sã€æª”案"
#: builtin/repack.c sequencer.c
#, c-format
@@ -13805,6 +14106,86 @@ msgstr "--convert-graft-file ä¸å¸¶åƒæ•¸"
msgid "only one pattern can be given with -l"
msgstr "åªèƒ½ç‚º -l æä¾›ä¸€å€‹æ¨¡å¼"
+#: builtin/replay.c
+msgid "need some commits to replay"
+msgstr "需è¦ä¸€äº›æäº¤æ‰èƒ½é‡æ”¾"
+
+#: builtin/replay.c
+msgid "--onto and --advance are incompatible"
+msgstr "--onto å’Œ --advance ä¸ç›¸å®¹"
+
+#: builtin/replay.c
+msgid "all positive revisions given must be references"
+msgstr "æä¾›çš„æ‰€æœ‰æ­£å‘修訂集必須為引用"
+
+#: builtin/replay.c
+msgid "argument to --advance must be a reference"
+msgstr "傳入 --advance 的引數必須為引用"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple sources because ordering would be ill-"
+"defined"
+msgstr "ç„¡æ³•ç”¨å¤šå€‹ä¾†æºæ¼”進目的地,以å…無法確定排åº"
+
+#: builtin/replay.c
+msgid ""
+"cannot implicitly determine whether this is an --advance or --onto operation"
+msgstr "無法å‡è¨­é€™æ˜¯ --advance 還是 --onto 動作"
+
+#: builtin/replay.c
+msgid ""
+"cannot advance target with multiple source branches because ordering would "
+"be ill-defined"
+msgstr "無法由多個來æºåˆ†æ”¯æ¼”進目的地,以å…無法確定排åº"
+
+#: builtin/replay.c
+msgid "cannot implicitly determine correct base for --onto"
+msgstr "無法å‡è¨­ --onto 的正確基底"
+
+#: builtin/replay.c
+msgid ""
+"(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+msgstr ""
+"(實驗性功能ï¼ï¼‰git replay ([--contained] --onto <newbase> | --advance "
+"<branch>) <revision-range>..."
+
+#: builtin/replay.c
+msgid "make replay advance given branch"
+msgstr "åœ¨æŒ‡å®šåˆ†æ”¯ä¸Šé€²è¡Œé‡æ”¾æ¼”進"
+
+#: builtin/replay.c
+msgid "replay onto given commit"
+msgstr "釿”¾åˆ°æŒ‡å®šæäº¤"
+
+#: builtin/replay.c
+msgid "advance all branches contained in revision-range"
+msgstr "演進所有包å«åœ¨ revision-range 中的分支"
+
+#: builtin/replay.c
+msgid "option --onto or --advance is mandatory"
+msgstr "必須傳入 --onto 或 --advance é¸é …"
+
+#: builtin/replay.c
+#, c-format
+msgid ""
+"some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
+"will be forced"
+msgstr "å°‡è¦†å¯«éƒ¨åˆ†ä¿®è¨‚ç‰ˆéæ­·é¸é …,強制使用「struct rev_infoã€çš„「%sã€ä½å…ƒ"
+
+#: builtin/replay.c
+msgid "error preparing revisions"
+msgstr "無法準備修訂集"
+
+#: builtin/replay.c
+msgid "replaying down to root commit is not supported yet!"
+msgstr "å°šä¸æ”¯æ´é‡æ”¾åˆ°æ ¹æäº¤ï¼"
+
+#: builtin/replay.c
+msgid "replaying merge commits is not supported yet!"
+msgstr "å°šä¸æ”¯æ´é‡æ”¾åˆä½µæäº¤ï¼"
+
#: builtin/rerere.c
msgid ""
"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
@@ -13817,7 +14198,7 @@ msgstr "在索引中註冊乾淨的解決方案"
#: builtin/rerere.c
msgid "'git rerere forget' without paths is deprecated"
-msgstr "沒有路徑的 'git rerere forget' å·²ç¶“éŽæ™‚"
+msgstr "沒有路徑的「git rerere forgetã€å·²ç¶“棄用"
#: builtin/rerere.c
#, c-format
@@ -13927,7 +14308,7 @@ msgstr "無法將 '%s' è§£æžç‚ºä¸€å€‹æœ‰æ•ˆçš„æ¨¹ç‹€ç‰©ä»¶ã€‚"
#: builtin/reset.c
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
-msgstr "--mixed 帶路徑已棄用,而是用 'git reset -- <路徑>'。"
+msgstr "--mixed 帶路徑已棄用,請改用「git reset -- <路徑>ã€ã€‚"
# 譯者:漢字之間無空格,故刪除%så‰å¾Œç©ºæ ¼
#: builtin/reset.c
@@ -14063,27 +14444,28 @@ msgid "--prefix requires an argument"
msgstr "--prefix éœ€è¦ 1 個引數"
#: builtin/rev-parse.c
+msgid "no object format specified"
+msgstr "未指定物件格å¼"
+
+#: builtin/rev-parse.c
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "䏿”¯æ´çš„物件格å¼ï¼š%s"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --abbrev-ref: %s"
msgstr "--abbrev-ref çš„æ¨¡å¼æœªçŸ¥ï¼š%s"
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden 無法與 --branches åŒæ™‚使用"
-
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --tags"
-msgstr "--exclude-hidden 無法與 --tags åŒæ™‚使用"
-
-#: builtin/rev-parse.c revision.c
-msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr "--exclude-hidden 無法與 --remotes åŒæ™‚使用"
-
#: builtin/rev-parse.c setup.c
msgid "this operation must be run in a work tree"
msgstr "該動作必須在一個工作å€ä¸­åŸ·è¡Œ"
#: builtin/rev-parse.c
+msgid "Could not read the index"
+msgstr "無法讀å–索引"
+
+#: builtin/rev-parse.c
#, c-format
msgid "unknown mode for --show-object-format: %s"
msgstr "--show-object-format çš„æ¨¡å¼æœªçŸ¥ï¼š%s"
@@ -14175,12 +14557,12 @@ msgid "allow commits with empty messages"
msgstr "å…許æäº¤èªªæ˜Žç‚ºç©º"
#: builtin/revert.c
-msgid "keep redundant, empty commits"
-msgstr "ä¿æŒå¤šé¤˜çš„ã€ç©ºçš„æäº¤"
+msgid "deprecated: use --empty=keep instead"
+msgstr "已棄用:請改用 --empty=keep"
#: builtin/revert.c
msgid "use the 'reference' format to refer to commits"
-msgstr "請使用 “reference†格å¼åƒè€ƒæäº¤"
+msgstr "請使用「referenceã€æ ¼å¼åƒè€ƒæäº¤"
#: builtin/revert.c
msgid "revert failed"
@@ -14503,25 +14885,51 @@ msgstr "未知的雜湊算法"
#: builtin/show-ref.c
msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+msgstr ""
+"git show-ref [--head] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+" [--] [<pattern>...]"
+
+#: builtin/show-ref.c
+msgid ""
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
-" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-" [--heads] [--] [<pattern>...]"
+"git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+" [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+" [--] [<ref>...]"
#: builtin/show-ref.c
msgid "git show-ref --exclude-existing[=<pattern>]"
msgstr "git show-ref --exclude-existing[=<模å¼>]"
#: builtin/show-ref.c
-msgid "only show tags (can be combined with heads)"
-msgstr "åªé¡¯ç¤ºæ¨™ç±¤ï¼ˆå¯ä»¥å’Œé ­å…±ç”¨ï¼‰"
+msgid "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <ref>"
+
+#: builtin/show-ref.c
+msgid "reference does not exist"
+msgstr "引用ä¸å­˜åœ¨"
+
+#: builtin/show-ref.c
+msgid "failed to look up reference"
+msgstr "無法查詢引用"
+
+#: builtin/show-ref.c
+msgid "only show tags (can be combined with --branches)"
+msgstr "åªé¡¯ç¤ºæ¨™ç±¤ï¼ˆå¯ä»¥å’Œ --branches 共用)"
+
+#: builtin/show-ref.c
+msgid "only show branches (can be combined with --tags)"
+msgstr "åªé¡¯ç¤ºåˆ†æ”¯ï¼ˆå¯ä»¥å’Œ --tags 共用)"
#: builtin/show-ref.c
-msgid "only show heads (can be combined with tags)"
-msgstr "åªé¡¯ç¤ºé ­ï¼ˆå¯ä»¥å’Œæ¨™ç±¤å…±ç”¨ï¼‰"
+msgid "check for reference existence without resolving"
+msgstr "檢查引用是å¦å­˜åœ¨ä½†ä¸è§£æž"
#: builtin/show-ref.c
msgid "stricter reference checking, requires exact ref path"
@@ -14580,6 +14988,11 @@ msgid "failed to create directory for sparse-checkout file"
msgstr "無法建立稀ç–簽出檔案的目錄"
#: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "無法 fdopen %s"
+
+#: builtin/sparse-checkout.c
msgid "failed to initialize worktree config"
msgstr "無法åˆå§‹åŒ–工作å€çµ„æ…‹"
@@ -14595,7 +15008,7 @@ msgstr "以 cone 模å¼åˆå§‹åŒ–稀ç–簽出"
msgid "toggle the use of a sparse index"
msgstr "åˆ‡æ›æ˜¯å¦ä½¿ç”¨ç¨€ç–索引"
-#: builtin/sparse-checkout.c commit-graph.c midx.c sequencer.c
+#: builtin/sparse-checkout.c commit-graph.c midx-write.c sequencer.c
#, c-format
msgid "unable to create leading directories of %s"
msgstr "ä¸èƒ½ç‚º %s 建立先導目錄"
@@ -15131,8 +15544,8 @@ msgstr "無法雜湊來自 '%s' 的物件"
#: builtin/submodule--helper.c
#, c-format
-msgid "unexpected mode %o\n"
-msgstr "éžé æœŸçš„æ¨¡å¼ %o\n"
+msgid "unexpected mode %o"
+msgstr "éžé æœŸçš„æ¨¡å¼ %o"
#: builtin/submodule--helper.c
msgid "use the commit stored in the index instead of the submodule HEAD"
@@ -15249,7 +15662,7 @@ msgstr ""
#: builtin/submodule--helper.c
#, c-format
msgid "could not get a repository handle for gitdir '%s'"
-msgstr "無法å–å¾— gitdir “%s†的版本庫控點"
+msgstr "無法å–å¾— gitdir「%sã€çš„版本庫控點"
#: builtin/submodule--helper.c
#, c-format
@@ -15266,20 +15679,20 @@ msgstr "ä¸èƒ½è­˜åˆ¥ submodule.alternateErrorStrategy çš„å–值 '%s'"
msgid "Value '%s' for submodule.alternateLocation is not recognized"
msgstr "ä¸èƒ½è­˜åˆ¥ submodule.alternateLocation çš„å–值 '%s'"
-#: builtin/submodule--helper.c
+#: builtin/submodule--helper.c submodule.c
#, c-format
msgid "refusing to create/use '%s' in another submodule's git dir"
msgstr "æ‹’çµ•åœ¨å…¶ä»–å­æ¨¡çµ„çš„ git 路徑建立ï¼ä½¿ç”¨ã€Œ%sã€"
#: builtin/submodule--helper.c
#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "無法複製 '%s' åˆ°å­æ¨¡çµ„路徑 '%s'"
+msgid "directory not empty: '%s'"
+msgstr "ç›®éŒ„ä¸æ˜¯ç©ºçš„:「%sã€"
#: builtin/submodule--helper.c
#, c-format
-msgid "directory not empty: '%s'"
-msgstr "ç›®éŒ„ä¸æ˜¯ç©ºçš„:「%sã€"
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "無法複製 '%s' åˆ°å­æ¨¡çµ„路徑 '%s'"
#: builtin/submodule--helper.c
#, c-format
@@ -15351,7 +15764,7 @@ msgstr "ç•¥éŽå­æ¨¡çµ„ '%s'"
#: builtin/submodule--helper.c
#, c-format
msgid "cannot clone submodule '%s' without a URL"
-msgstr "無法在沒有網å€çš„æƒ…æ³ä¸‹è¤‡è£½ “%sâ€ å­æ¨¡çµ„"
+msgstr "無法在沒有網å€çš„æƒ…æ³ä¸‹è¤‡è£½ã€Œ%sã€å­æ¨¡çµ„"
#: builtin/submodule--helper.c
#, c-format
@@ -15469,15 +15882,15 @@ msgstr "ä¸å¾žé ç«¯ç«™å°å–得新物件"
#: builtin/submodule--helper.c
msgid "use the 'checkout' update strategy (default)"
-msgstr "使用 “checkout†更新策略(é è¨­å€¼ï¼‰"
+msgstr "使用「checkoutã€æ›´æ–°ç­–略(é è¨­å€¼ï¼‰"
#: builtin/submodule--helper.c
msgid "use the 'merge' update strategy"
-msgstr "使用 “merge†更新策略"
+msgstr "使用「mergeã€æ›´æ–°ç­–ç•¥"
#: builtin/submodule--helper.c
msgid "use the 'rebase' update strategy"
-msgstr "使用 “rebase†更新策略"
+msgstr "使用「rebaseã€æ›´æ–°ç­–ç•¥"
#: builtin/submodule--helper.c
msgid "create a shallow clone truncated to the specified number of revisions"
@@ -15511,6 +15924,10 @@ msgstr ""
"shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
"[--] [<path>...]"
+#: builtin/submodule--helper.c submodule.c
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "無法將 HEAD è§£æžç‚ºæœ‰æ•ˆå¼•用。"
+
#: builtin/submodule--helper.c
msgid "git submodule absorbgitdirs [<options>] [<path>...]"
msgstr "git submodule absorbgitdirs [<options>] [<path>...]"
@@ -15716,9 +16133,11 @@ msgstr "更新的原因"
#: builtin/tag.c
msgid ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
msgstr ""
"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+" [(--trailer <token>[(=|:)<value>])...]\n"
" <tagname> [<commit> | <object>]"
#: builtin/tag.c
@@ -15757,12 +16176,12 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
msgstr ""
"\n"
-"輸入一個標籤說明:\n"
+"為標籤輸入說明訊æ¯ï¼š\n"
" %s\n"
-"以 '%c' 開頭的行將被忽略。\n"
+"以「%sã€é–‹é ­çš„列將被忽略。\n"
#: builtin/tag.c
#, c-format
@@ -15770,13 +16189,13 @@ msgid ""
"\n"
"Write a message for tag:\n"
" %s\n"
-"Lines starting with '%c' will be kept; you may remove them yourself if you "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
"\n"
-"輸入一個標籤說明:\n"
+"為標籤輸入說明訊æ¯ï¼š\n"
" %s\n"
-"以 '%c' 開頭的行將被ä¿ç•™ï¼Œå¦‚果您願æ„也å¯ä»¥åˆªé™¤å®ƒå€‘。\n"
+"以「%sã€é–‹é ­çš„列將被ä¿ç•™ï¼›éœ€è¦çš„話您å¯ä»¥è‡ªå·±åˆªé™¤ã€‚\n"
#: builtin/tag.c
msgid "unable to sign the tag"
@@ -15885,6 +16304,10 @@ msgid "print only tags of the object"
msgstr "åªåˆ—å°æŒ‡å‘該物件的標籤"
#: builtin/tag.c
+msgid "could not start 'git column'"
+msgstr "無法啟動「git columnã€"
+
+#: builtin/tag.c
#, c-format
msgid "the '%s' option is only allowed in list mode"
msgstr "「%sã€é¸é …åªèƒ½åœ¨åˆ—表顯示模å¼ä½¿ç”¨"
@@ -16087,6 +16510,10 @@ msgid "write index in this format"
msgstr "以這種格å¼å¯«å…¥ç´¢å¼•å€"
#: builtin/update-index.c
+msgid "report on-disk index format version"
+msgstr "回報ç£ç¢Ÿä¸Šç´¢å¼•æ ¼å¼çš„版本"
+
+#: builtin/update-index.c
msgid "enable or disable split index"
msgstr "啟用或åœç”¨ç´¢å¼•分割"
@@ -16119,6 +16546,16 @@ msgid "clear fsmonitor valid bit"
msgstr "清除 fsmonitor 有效ä½"
#: builtin/update-index.c
+#, c-format
+msgid "%d\n"
+msgstr "%d\n"
+
+#: builtin/update-index.c
+#, c-format
+msgid "index-version: was %d, set to %d"
+msgstr "index-version:曾是 %d,已設為 %d"
+
+#: builtin/update-index.c
msgid ""
"core.splitIndex is set to false; remove or change it, if you really want to "
"enable split index"
@@ -16173,12 +16610,12 @@ msgid "fsmonitor disabled"
msgstr "fsmonitor 被åœç”¨"
#: builtin/update-ref.c
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<é¸é …>] -d <引用å> [<舊值>]"
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<options>] -d <refname> [<old-oid>]"
#: builtin/update-ref.c
-msgid "git update-ref [<options>] <refname> <new-val> [<old-val>]"
-msgstr "git update-ref [<é¸é …>] <引用å> <新值> [<舊值>]"
+msgid "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<options>] <refname> <new-oid> [<old-oid>]"
#: builtin/update-ref.c
msgid "git update-ref [<options>] --stdin [-z]"
@@ -16298,19 +16735,19 @@ msgstr "git worktree unlock <worktree>"
#: builtin/worktree.c
msgid "No possible source branch, inferring '--orphan'"
-msgstr "沒有å¯èƒ½çš„來æºåˆ†æ”¯ï¼ŒæŽ¨æ¸¬ç‚º “--orphanâ€"
+msgstr "沒有å¯èƒ½çš„來æºåˆ†æ”¯ï¼ŒæŽ¨æ¸¬ç‚ºã€Œ--orphanã€"
#: builtin/worktree.c
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"æœªèª•ç”Ÿåˆ†æ”¯ï¼ˆå³æ²’有æäº¤çš„分支),å¯ä»¥ä½¿ç”¨ --orphan é”到\n"
"這個效果:\n"
"\n"
" git worktree add --orphan -b %s %s\n"
@@ -16318,14 +16755,14 @@ msgstr ""
#: builtin/worktree.c
#, c-format
msgid ""
-"If you meant to create a worktree containing a new orphan branch\n"
+"If you meant to create a worktree containing a new unborn 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"
+"æœªèª•ç”Ÿåˆ†æ”¯ï¼ˆå³æ²’有æäº¤çš„分支),å¯ä»¥ä½¿ç”¨ --orphan é”到\n"
"這個效果:\n"
"\n"
" git worktree add --orphan %s\n"
@@ -16397,6 +16834,11 @@ msgstr "正在åˆå§‹åŒ–"
#: builtin/worktree.c
#, c-format
+msgid "could not find created worktree '%s'"
+msgstr "找ä¸åˆ°å»ºç«‹çš„工作å€ã€Œ%sã€"
+
+#: builtin/worktree.c
+#, c-format
msgid "Preparing worktree (new branch '%s')"
msgstr "準備工作å€ï¼ˆæ–°åˆ†æ”¯ '%s')"
@@ -16428,21 +16870,16 @@ msgid ""
"HEAD contents: '%s'"
msgstr ""
"HEAD 指å‘無效(或孤立)引用。\n"
-"HEAD 路徑:“%sâ€\n"
-"HEAD 內容:“%sâ€"
+"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"
+"present, stopping; use 'add -f' to override 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â€"
+"æ•…åœæ­¢ã€‚使用「add -fã€å…ˆè¦†è“‹æˆ–抓å–é ç«¯"
#: builtin/worktree.c
msgid "checkout <branch> even if already checked out in other worktree"
@@ -16457,8 +16894,8 @@ msgid "create or reset a branch"
msgstr "建立或é‡è¨­ä¸€å€‹åˆ†æ”¯"
#: builtin/worktree.c
-msgid "create unborn/orphaned branch"
-msgstr "建立尚無內容(孤立)的分支"
+msgid "create unborn branch"
+msgstr "建立未誕生分支"
#: builtin/worktree.c
msgid "populate the new working tree"
@@ -16487,12 +16924,8 @@ 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 "<æäº¤æŒ‡ç¤ºå…ƒ>"
+msgid "option '%s' and commit-ish cannot be used together"
+msgstr "「%sã€é¸é …å’Œæäº¤ç·¨è™Ÿä¸å¾—åŒæ™‚使用"
#: builtin/worktree.c
msgid "added with --lock"
@@ -16657,12 +17090,12 @@ msgstr "core.fsyncMethod = batch 䏿”¯æ´æœ¬å¹³å°"
#: bundle-uri.c
#, c-format
msgid "could not parse bundle list key %s with value '%s'"
-msgstr "無法解æžå¥—ä»¶åŒ…æ¸…å–®éµ %s 的值 “%sâ€"
+msgstr "無法解æžå¥—ä»¶åŒ…æ¸…å–®éµ %s 的值「%sã€"
#: bundle-uri.c
#, c-format
msgid "bundle list at '%s' has no mode"
-msgstr "使–¼ “%s†的套件包清單沒有模å¼"
+msgstr "使–¼ã€Œ%sã€çš„套件包清單沒有模å¼"
#: bundle-uri.c
msgid "failed to create temporary file"
@@ -16675,7 +17108,7 @@ msgstr "功能ä¸è¶³"
#: bundle-uri.c
#, c-format
msgid "file downloaded from '%s' is not a bundle"
-msgstr "從 “%sâ€ ä¸‹è¼‰çš„æª”æ¡ˆä¸æ˜¯å¥—件包"
+msgstr "從「%sã€ä¸‹è¼‰çš„æª”æ¡ˆä¸æ˜¯å¥—件包"
#: bundle-uri.c
msgid "failed to store maximum creation token"
@@ -16684,7 +17117,7 @@ msgstr "無法儲存最大的建立權æ–"
#: bundle-uri.c
#, c-format
msgid "unrecognized bundle mode from URI '%s'"
-msgstr "無法識別從 URI “%s†å–回的套件包模å¼"
+msgstr "無法識別從 URI「%sã€å–回的套件包模å¼"
#: bundle-uri.c
#, c-format
@@ -16694,17 +17127,17 @@ msgstr "超出套件包 URI éžè¿´é™åˆ¶ (%d)"
#: bundle-uri.c
#, c-format
msgid "failed to download bundle from URI '%s'"
-msgstr "無法從 “%s†URI 下載套件包"
+msgstr "無法從「%sã€URI 下載套件包"
#: bundle-uri.c
#, c-format
msgid "file at URI '%s' is not a bundle or bundle list"
-msgstr "使–¼ URI “%sâ€ çš„æª”æ¡ˆä¸æ˜¯å¥—件包或套件包清單"
+msgstr "使–¼ URI「%sã€çš„æª”æ¡ˆä¸æ˜¯å¥—件包或套件包清單"
#: bundle-uri.c
#, c-format
msgid "bundle-uri: unexpected argument: '%s'"
-msgstr "bundle-uri: éžé æœŸçš„引數:“%sâ€"
+msgstr "bundle-uri: éžé æœŸçš„引數:「%sã€"
#: bundle-uri.c
msgid "bundle-uri: expected flush after arguments"
@@ -16716,7 +17149,7 @@ msgstr "bundle-uri: 收到空白列"
#: bundle-uri.c
msgid "bundle-uri: line is not of the form 'key=value'"
-msgstr "bundle-uri: 列的格å¼ä¸æ˜¯ “key=valueâ€"
+msgstr "bundle-uri: 列的格å¼ä¸æ˜¯ã€Œkey=valueã€"
#: bundle-uri.c
msgid "bundle-uri: line has empty key or value"
@@ -16730,27 +17163,23 @@ msgstr "無法識別的套件包雜湊演算法:%s"
#: bundle.c
#, c-format
msgid "unknown capability '%s'"
-msgstr "未知功能 '%s'"
+msgstr "未知功能「%sã€"
#: bundle.c
#, c-format
msgid "'%s' does not look like a v2 or v3 bundle file"
-msgstr "“%s†ä¸åƒæ˜¯ä¸€å€‹ v2 或 v3 版本的套件包檔案"
+msgstr "「%sã€ä¸åƒæ˜¯ä¸€å€‹ v2 或 v3 版本的套件包檔案"
#: bundle.c
#, c-format
msgid "unrecognized header: %s%s (%d)"
-msgstr "無法識別的包頭:%s%s (%d)"
+msgstr "無法識別的標頭:%s%s (%d)"
#: bundle.c
msgid "Repository lacks these prerequisite commits:"
msgstr "版本庫中缺少這些必備的æäº¤ï¼š"
#: bundle.c
-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"
@@ -16788,7 +17217,7 @@ msgstr "無法複製套件包æè¿°å…ƒ"
#: bundle.c
msgid "Could not spawn pack-objects"
-msgstr "ä¸èƒ½ç”Ÿæˆ pack-objects 進程"
+msgstr "無法 spawn pack-objects 處ç†ç¨‹åº"
#: bundle.c
msgid "pack-objects died"
@@ -16797,7 +17226,7 @@ msgstr "pack-objects 終止"
#: bundle.c
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
-msgstr "引用 '%s' 被 rev-list é¸é …排除"
+msgstr "引用「%sã€è¢« rev-list é¸é …排除"
#: bundle.c
#, c-format
@@ -16816,7 +17245,7 @@ msgstr "ä¸èƒ½å»ºç«‹ç©ºå¥—件包。"
#: bundle.c
#, c-format
msgid "cannot create '%s'"
-msgstr "ä¸èƒ½å»ºç«‹ '%s'"
+msgstr "無法建立「%sã€"
#: bundle.c
msgid "index-pack died"
@@ -16824,7 +17253,12 @@ msgstr "index-pack 終止"
#: chunk-format.c
msgid "terminating chunk id appears earlier than expected"
-msgstr "終止å€å¡Š id 出ç¾çš„æ™‚é–“æ—©æ–¼é æœŸ"
+msgstr "終止å€å¡Š ID æ¯”é æœŸé‚„早出ç¾"
+
+#: chunk-format.c
+#, c-format
+msgid "chunk id %<PRIx32> not %d-byte aligned"
+msgstr "å€å¡Š ID %<PRIx32> 沒有以 %d ä½å…ƒçµ„為單ä½å°é½Š"
#: chunk-format.c
#, c-format
@@ -16895,8 +17329,8 @@ msgid "Move objects and refs by archive"
msgstr "é€éŽæ­¸æª”移動物件和引用"
#: command-list.h
-msgid "Provide content or type and size information for repository objects"
-msgstr "æä¾›ç‰ˆæœ¬åº«ç‰©ä»¶çš„內容ã€é¡žåž‹æˆ–大å°"
+msgid "Provide contents or details of repository objects"
+msgstr "æä¾›ç‰ˆæœ¬åº«ç‰©ä»¶çš„內容或詳細資訊"
#: command-list.h
msgid "Display gitattributes information"
@@ -17264,6 +17698,10 @@ msgid "Manage reflog information"
msgstr "ç®¡ç† reflog 訊æ¯"
#: command-list.h
+msgid "Low-level access to refs"
+msgstr "å°å¼•用的低階存å–"
+
+#: command-list.h
msgid "Manage set of tracked repositories"
msgstr "管ç†å·²è¿½è¹¤ç‰ˆæœ¬åº«"
@@ -17276,6 +17714,10 @@ msgid "Create, list, delete refs to replace objects"
msgstr "建立ã€åˆ—出ã€åˆªé™¤ç‰©ä»¶å–代引用"
#: command-list.h
+msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
+msgstr "å¯¦é©—æ€§åŠŸèƒ½ï¼šåœ¨æ–°çš„åŸºåº•é‡æ”¾æäº¤ï¼Œäº¦æ”¯æ´è£¸ç‰ˆæœ¬åº«"
+
+#: command-list.h
msgid "Generates a summary of pending changes"
msgstr "生æˆå¾…定更改的摘è¦"
@@ -17354,7 +17796,7 @@ msgstr "將工作å€é™ç¸®è‡³åªåŒ…å«è¿½è¹¤æª”案的å­é›†"
#: command-list.h
msgid "Add file contents to the staging area"
-msgstr "將檔案內容新增到索引"
+msgstr "將檔案內容新增到暫存å€"
#: command-list.h
msgid "Stash the changes in a dirty working directory away"
@@ -17437,7 +17879,7 @@ msgid "Display version information about Git"
msgstr "顯示 Git 的版本資訊"
#: command-list.h
-msgid "Show logs with difference each commit introduces"
+msgid "Show logs with differences each commit introduces"
msgstr "顯示æ¯ä¸€å€‹æäº¤å¼•入的差異日誌"
#: command-list.h
@@ -17502,7 +17944,7 @@ msgstr "Git å°åŒ…æ ¼å¼"
#: command-list.h
msgid "Git cryptographic signature formats"
-msgstr "Git 密碼編譯簽章格å¼"
+msgstr "Git 數ä½ç°½ç« æ ¼å¼"
#: command-list.h
msgid "A Git Glossary"
@@ -17590,53 +18032,111 @@ msgstr "用來管ç†å¤§åž‹ Git 版本庫的工具"
#: commit-graph.c
msgid "commit-graph file is too small"
-msgstr "æäº¤åœ–形檔案太å°"
+msgstr "æäº¤åœ–檔案太å°"
+
+#: commit-graph.c
+msgid "commit-graph oid fanout chunk is wrong size"
+msgstr "æäº¤åœ– OID 扇出å€å¡Šå¤§å°æœ‰èª¤"
+
+#: commit-graph.c
+msgid "commit-graph fanout values out of order"
+msgstr "æäº¤åœ–扇出的數值失åº"
+
+#: commit-graph.c
+msgid "commit-graph OID lookup chunk is the wrong size"
+msgstr "æäº¤åœ– OID 查詢å€å¡Šçš„大尿œ‰èª¤"
+
+#: commit-graph.c
+msgid "commit-graph commit data chunk is wrong size"
+msgstr "æäº¤åœ–çš„æäº¤è³‡æ–™å€å¡Šå¤§å°æœ‰èª¤"
+
+#: commit-graph.c
+msgid "commit-graph generations chunk is wrong size"
+msgstr "æäº¤åœ–的世代å€å¡Šå¤§å°æœ‰èª¤"
+
+#: commit-graph.c
+msgid "commit-graph changed-path index chunk is too small"
+msgstr "æäº¤åœ–的更動路徑索引å€å¡ŠéŽå°"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
+"graph file"
+msgstr "忽略æäº¤åœ–檔案中éŽå°çš„æ›´å‹•路徑å€å¡Šï¼ˆ%<PRIuMAX> < %<PRIuMAX>)"
#: commit-graph.c
#, c-format
msgid "commit-graph signature %X does not match signature %X"
-msgstr "æäº¤åœ–形簽å %X 和簽å %X ä¸ç¬¦åˆ"
+msgstr "æäº¤åœ–簽章 %X 和簽章 %X ä¸ç¬¦"
#: commit-graph.c
#, c-format
msgid "commit-graph version %X does not match version %X"
-msgstr "æäº¤åœ–形版本 %X 和版本 %X ä¸ç¬¦åˆ"
+msgstr "æäº¤åœ–版本 %X 和版本 %X ä¸ç¬¦"
#: commit-graph.c
#, c-format
msgid "commit-graph hash version %X does not match version %X"
-msgstr "æäº¤åœ–形雜湊版本 %X 和版本 %X ä¸ç¬¦åˆ"
+msgstr "æäº¤åœ–雜湊版本 %X 和版本 %X ä¸ç¬¦"
#: commit-graph.c
#, c-format
msgid "commit-graph file is too small to hold %u chunks"
-msgstr "commit-graph 檔案ä¸å¤ æ”¾ç½® %u 個å€å¡Š"
+msgstr "æäº¤åœ–檔案ä¸å¤ æ”¾ç½® %u 個å€å¡Š"
+
+#: commit-graph.c
+msgid "commit-graph required OID fanout chunk missing or corrupted"
+msgstr "æäº¤åœ–需è¦çš„ OID 扇出å€å¡Šéºå¤±æˆ–æå£ž"
+
+#: commit-graph.c
+msgid "commit-graph required OID lookup chunk missing or corrupted"
+msgstr "æäº¤åœ–需è¦çš„ OID 查詢å€å¡Šéºå¤±æˆ–æå£ž"
+
+#: commit-graph.c
+msgid "commit-graph required commit data chunk missing or corrupted"
+msgstr "æäº¤åœ–需è¦çš„æäº¤è³‡æ–™å€å¡Šéºå¤±æˆ–æå£ž"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr "由於ä¸ç›¸å®¹çš„設定,åœç”¨æäº¤åœ–層 '%s' çš„å¸ƒéš†éŽæ¿¾å™¨"
#: commit-graph.c
msgid "commit-graph has no base graphs chunk"
-msgstr "æäº¤åœ–形沒有基礎圖形å€å¡Š"
+msgstr "æäº¤åœ–沒有基礎圖å€å¡Š"
+
+#: commit-graph.c
+msgid "commit-graph base graphs chunk is too small"
+msgstr "æäº¤åœ–的基礎圖å€å¡ŠéŽå°"
#: commit-graph.c
msgid "commit-graph chain does not match"
-msgstr "æäº¤åœ–å½¢éˆä¸ç¬¦åˆ"
+msgstr "æäº¤åœ–éˆä¸ç¬¦"
#: commit-graph.c
#, c-format
msgid "commit count in base graph too high: %<PRIuMAX>"
-msgstr "基礎圖 (base graph) 中的æäº¤æ•¸éŽå¤šï¼š%<PRIuMAX>"
+msgstr "基礎圖中的æäº¤æ•¸éŽå¤šï¼š%<PRIuMAX>"
+
+#: commit-graph.c
+msgid "commit-graph chain file too small"
+msgstr "æäº¤åœ–éˆæª”案éŽå°"
#: commit-graph.c
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
-msgstr "無效的æäº¤åœ–å½¢éˆï¼šè¡Œ '%s' 䏿˜¯ä¸€å€‹é›œæ¹Šå€¼"
+msgstr "無效的æäº¤åœ–éˆï¼šã€Œ%sã€åˆ—䏿˜¯é›œæ¹Šå€¼"
#: commit-graph.c
msgid "unable to find all commit-graph files"
-msgstr "無法找到所有æäº¤åœ–形檔案"
+msgstr "無法找到所有æäº¤åœ–檔案"
#: commit-graph.c
msgid "invalid commit position. commit-graph is likely corrupt"
-msgstr "無效的æäº¤ä½ç½®ã€‚æäº¤åœ–å½¢å¯èƒ½å·²æå£ž"
+msgstr "無效的æäº¤ä½ç½®ã€‚æäº¤åœ–å¯èƒ½å·²æå£ž"
#: commit-graph.c
#, c-format
@@ -17645,7 +18145,15 @@ msgstr "無法找到æäº¤ %s"
#: commit-graph.c
msgid "commit-graph requires overflow generation data but has none"
-msgstr "æäº¤åœ–éœ€è¦æ¯”ç›®å‰æ›´å¤šçš„世代資料,但沒有相關資料"
+msgstr "缺少æäº¤åœ–需è¦çš„æº¢ä½ä¸–代資料"
+
+#: commit-graph.c
+msgid "commit-graph overflow generation data is too small"
+msgstr "æäº¤åœ–的溢ä½ä¸–代資料éŽå°"
+
+#: commit-graph.c
+msgid "commit-graph extra-edges pointer out of bounds"
+msgstr "æäº¤åœ–é¡å¤–的邊指標超出範åœ"
#: commit-graph.c
msgid "Loading known commits in commit graph"
@@ -17653,7 +18161,7 @@ msgstr "正在載入æäº¤åœ–中的已知æäº¤"
#: commit-graph.c
msgid "Expanding reachable commits in commit graph"
-msgstr "正在展開æäº¤åœ–中的å¯ä»¥å–å¾—çš„æäº¤"
+msgstr "正在展開æäº¤åœ–中的å¯è§¸åŠæäº¤"
#: commit-graph.c
msgid "Clearing commit marks in commit graph"
@@ -17661,11 +18169,11 @@ msgstr "正在清除æäº¤åœ–中的æäº¤æ¨™è¨˜"
#: commit-graph.c
msgid "Computing commit graph topological levels"
-msgstr "正在計算æäº¤åœ–拓樸級別"
+msgstr "正在計算æäº¤åœ–的拓樸層級"
#: commit-graph.c
msgid "Computing commit graph generation numbers"
-msgstr "正在計算æäº¤åœ–世代數字"
+msgstr "正在計算æäº¤åœ–的世代數"
#: commit-graph.c
msgid "Computing commit changed paths Bloom filters"
@@ -17693,7 +18201,7 @@ msgstr "為 %s 開啟索引發生錯誤"
#: commit-graph.c
msgid "Finding commits for commit graph among packed objects"
-msgstr "正在打包物件中尋找æäº¤åœ–çš„æäº¤"
+msgstr "正在從打包物件中尋找æäº¤åœ–çš„æäº¤"
#: commit-graph.c
msgid "Finding extra edges in commit graph"
@@ -17701,13 +18209,13 @@ msgstr "正在尋找æäº¤åœ–中é¡å¤–的邊"
#: commit-graph.c
msgid "failed to write correct number of base graph ids"
-msgstr "無法寫入正確數é‡çš„基礎圖形 ID"
+msgstr "無法寫入正確數é‡çš„基礎圖 ID"
#: commit-graph.c
msgid "unable to create temporary graph layer"
-msgstr "無法建立暫時的圖形層"
+msgstr "無法建立暫時性圖層"
-#: commit-graph.c
+#: commit-graph.c midx-write.c
#, c-format
msgid "unable to adjust shared permissions for '%s'"
msgstr "無法調整「%sã€çš„共用權é™"
@@ -17720,25 +18228,25 @@ msgstr[0] "正在用 %d 步寫出æäº¤åœ–"
#: commit-graph.c
msgid "unable to open commit-graph chain file"
-msgstr "無法開啟æäº¤åœ–å½¢éˆæª”案"
+msgstr "無法開啟æäº¤åœ–éˆæª”案"
#: commit-graph.c
msgid "failed to rename base commit-graph file"
-msgstr "ç„¡æ³•é‡æ–°å‘½å基礎æäº¤åœ–形檔案"
+msgstr "ç„¡æ³•é‡æ–°å‘½å基礎æäº¤åœ–檔案"
#: commit-graph.c
msgid "failed to rename temporary commit-graph file"
-msgstr "ç„¡æ³•é‡æ–°å‘½å暫時æäº¤åœ–形檔案"
+msgstr "ç„¡æ³•é‡æ–°å‘½å暫時性æäº¤åœ–檔案"
#: commit-graph.c
#, c-format
msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
-msgstr "無法將圖與 %<PRIuMAX>, %<PRIuMAX> 個æäº¤é€²è¡Œåˆä½µ"
+msgstr "無法åˆä½µåœ–,兩者分別有 %<PRIuMAX>ã€%<PRIuMAX> 個æäº¤"
#: commit-graph.c
#, c-format
msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
-msgstr "無法åˆä½µ %s 圖,太多æäº¤ï¼š%<PRIuMAX>"
+msgstr "無法åˆä½µåœ– %s,太多æäº¤ï¼š%<PRIuMAX>"
#: commit-graph.c
msgid "Scanning merged commits"
@@ -17746,15 +18254,22 @@ msgstr "正在掃æåˆä½µæäº¤"
#: commit-graph.c
msgid "Merging commit-graph"
-msgstr "正在åˆä½µæäº¤åœ–å½¢"
+msgstr "正在åˆä½µæäº¤åœ–"
#: commit-graph.c
msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
-msgstr "嘗試寫入æäº¤åœ–形,但 “core.commitGraph†已被åœç”¨"
+msgstr "嘗試寫入æäº¤åœ–,但「core.commitGraphã€å·²åœç”¨"
+
+#: commit-graph.c
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph."
+"changedPathsVersion' (%d) is not supported"
+msgstr "嘗試寫入æäº¤åœ–ï¼Œä½†ä¸æ”¯æ´ã€ŒcommitGraph.changedPathsVersionã€ï¼ˆ%d)"
#: commit-graph.c
msgid "too many commits to write graph"
-msgstr "æäº¤å¤ªå¤šä¸èƒ½ç•«åœ–"
+msgstr "æäº¤éŽå¤šç„¡æ³•畫圖"
#: commit-graph.c
msgid "the commit-graph file has incorrect checksum and is likely corrupt"
@@ -17763,69 +18278,69 @@ msgstr "æäº¤åœ–檔案的總和檢查碼錯誤,å¯èƒ½å·²ç¶“æå£ž"
#: commit-graph.c
#, c-format
msgid "commit-graph has incorrect OID order: %s then %s"
-msgstr "æäº¤åœ–形的物件 ID é †åºä¸æ­£ç¢ºï¼š%s 然後 %s"
+msgstr "æäº¤åœ–的物件 ID é †åºä¸æ­£ç¢ºï¼š%s 然後 %s"
#: commit-graph.c
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
-msgstr "æäº¤åœ–å½¢æœ‰ä¸æ­£ç¢ºçš„æ‰‡å‡ºå€¼ï¼šfanout[%d] = %u != %u"
+msgstr "æäº¤åœ–æœ‰ä¸æ­£ç¢ºçš„æ‰‡å‡ºå€¼ï¼šfanout[%d] = %u != %u"
#: commit-graph.c
#, c-format
msgid "failed to parse commit %s from commit-graph"
-msgstr "無法從æäº¤åœ–å½¢ä¸­è§£æžæäº¤ %s"
+msgstr "無法從æäº¤åœ–ä¸­è§£æžæäº¤ %s"
#: commit-graph.c
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
-msgstr "無法從æäº¤åœ–å½¢çš„ç‰©ä»¶åº«ä¸­è§£æžæäº¤ %s"
+msgstr "無法從æäº¤åœ–çš„ç‰©ä»¶è³‡æ–™åº«ä¸­è§£æžæäº¤ %s"
#: commit-graph.c
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
-msgstr "æäº¤åœ–形中的æäº¤ %s 的根樹狀物件 ID 是 %s != %s"
+msgstr "æäº¤åœ–中的æäº¤ %s 的根樹狀物件 ID 是 %s != %s"
#: commit-graph.c
#, c-format
msgid "commit-graph parent list for commit %s is too long"
-msgstr "æäº¤ %s çš„æäº¤åœ–形父æäº¤åˆ—表太長了"
+msgstr "æäº¤ %s çš„æäº¤åœ–上級清單éŽé•·"
#: commit-graph.c
#, c-format
msgid "commit-graph parent for %s is %s != %s"
-msgstr "%s çš„æäº¤åœ–形父æäº¤æ˜¯ %s != %s"
+msgstr "%s çš„æäº¤åœ–上級是 %s != %s"
#: commit-graph.c
#, c-format
msgid "commit-graph parent list for commit %s terminates early"
-msgstr "æäº¤ %s çš„æäº¤åœ–形父æäº¤åˆ—è¡¨éŽæ—©çµ‚æ­¢"
+msgstr "æäº¤ %s çš„æäº¤åœ–ä¸Šç´šæ¸…å–®éŽæ—©çµ‚æ­¢"
#: commit-graph.c
#, c-format
-msgid ""
-"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
-msgstr "æäº¤åœ–形中æäº¤ %s 的世代號是零,但其它地方éžé›¶"
-
-#: commit-graph.c
-#, c-format
-msgid ""
-"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
-msgstr "æäº¤åœ–形中æäº¤ %s 的世代號éžé›¶ï¼Œä½†å…¶å®ƒåœ°æ–¹æ˜¯é›¶"
+msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
+msgstr "æäº¤ %s 使–¼ %<PRIuMAX> < %<PRIuMAX> æäº¤åœ–世代"
#: commit-graph.c
#, c-format
-msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
-msgstr "æäº¤ %s çš„æäº¤åœ–形處於 %<PRIuMAX> < %<PRIuMAX> 世代"
+msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
+msgstr "æäº¤åœ–中的æäº¤ %s æäº¤æ—¥æœŸæ˜¯ %<PRIuMAX> != %<PRIuMAX>"
#: commit-graph.c
#, c-format
-msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
-msgstr "æäº¤åœ–形中æäº¤ %s çš„æäº¤æ—¥æœŸæ˜¯ %<PRIuMAX> != %<PRIuMAX>"
+msgid ""
+"commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
+"'%s')"
+msgstr "æäº¤åœ–ä¸­åŒ…å« 0 å’Œéž 0 兩個世代數(例如æäº¤ã€Œ%sã€å’Œã€Œ%sã€ï¼‰"
#: commit-graph.c
msgid "Verifying commits in commit graph"
msgstr "正在驗證æäº¤åœ–中的æäº¤"
+#: commit-reach.c sequencer.c
+#, c-format
+msgid "could not parse commit %s"
+msgstr "ä¸èƒ½è§£æžæäº¤ %s"
+
#: commit.c
#, c-format
msgid "%s %s is not a commit!"
@@ -17842,14 +18357,19 @@ msgid ""
"Turn this message off by running\n"
"\"git config advice.graftFileDeprecated false\""
msgstr ""
-"å° <GIT_DIR>/info/grafts 的支æ´å·²è¢«æ£„用,並將在\n"
-"未來的Git版本中被移除。\n"
+"å° <GIT_DIR>/info/grafts 的支æ´å·²æ£„用,並將在\n"
+"未來的 Git 版本中被移除。\n"
"\n"
-"請使用 \"git replace --convert-graft-file\" 將\n"
+"請使用「git replace --convert-graft-fileã€å°‡\n"
"grafts 轉æ›ç‚ºå–代引用。\n"
"\n"
-"設定 \"git config advice.graftFileDeprecated false\"\n"
-"å¯é—œé–‰æœ¬æ¶ˆæ¯"
+"設定「git config advice.graftFileDeprecated falseã€\n"
+"å¯ä»¥å°‡æœ¬è¨Šæ¯é—œé–‰"
+
+#: commit.c
+#, c-format
+msgid "commit %s exists in commit-graph but not in the object database"
+msgstr "%s æäº¤åœ¨æäº¤åœ–中,但ä¸åœ¨ç‰©ä»¶è³‡æ–™åº«ä¸­"
#: commit.c
#, c-format
@@ -17892,37 +18412,37 @@ msgstr "沒有å¯ç”¨çš„ libc 資訊\n"
#: compat/disk.h
#, c-format
msgid "could not determine free disk size for '%s'"
-msgstr "無法判斷 “%s†的剩餘ç£ç¢Ÿå¤§å°"
+msgstr "無法判斷「%sã€çš„剩餘ç£ç¢Ÿå¤§å°"
#: compat/disk.h
#, c-format
msgid "could not get info for '%s'"
-msgstr "無法å–å¾— “%s†的資訊"
+msgstr "無法å–得「%sã€çš„資訊"
#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "[GLE %ld] health thread could not open '%ls'"
-msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’無法開啟 “%lsâ€"
+msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’無法開啟「%lsã€"
#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "[GLE %ld] health thread getting BHFI for '%ls'"
-msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’å–å¾— “%ls†的 BHFI"
+msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’å–得「%lsã€çš„ BHFI"
#: compat/fsmonitor/fsm-health-win32.c compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "could not convert to wide characters: '%s'"
-msgstr "無法轉æ›è‡³è¼ƒå¯¬å­—元:“%sâ€"
+msgstr "無法轉æ›è‡³è¼ƒå¯¬å­—元:「%sã€"
#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "BHFI changed '%ls'"
-msgstr "BHFI 更改了 “%lsâ€"
+msgstr "BHFI 更改了「%lsã€"
#: compat/fsmonitor/fsm-health-win32.c
#, c-format
msgid "unhandled case in 'has_worktree_moved': %d"
-msgstr "“has_worktree_moved†中有未處置的情æ³ï¼š%d"
+msgstr "「has_worktree_movedã€ä¸­æœ‰æœªè™•置的情æ³ï¼š%d"
#: compat/fsmonitor/fsm-health-win32.c
#, c-format
@@ -17950,22 +18470,22 @@ msgstr "[GLE %ld] 無法將路徑轉æ›ç‚º UTF-8:「%.*lsã€"
#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "[GLE %ld] could not watch '%s'"
-msgstr "[GLE %ld] ç„¡æ³•ç›£è½ â€œ%sâ€"
+msgstr "[GLE %ld] 無法監è½ã€Œ%sã€"
#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "[GLE %ld] could not get longname of '%s'"
-msgstr "[GLE %ld] 無法å–å¾— “%s†的 longname"
+msgstr "[GLE %ld] 無法å–得「%sã€çš„ longname"
#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
-msgstr "在 “%sâ€ ä¸Šå‘¼å« ReadDirectoryChangedW 失敗 [GLE %ld]"
+msgstr "在「%sã€ä¸Šå‘¼å« ReadDirectoryChangedW 失敗 [GLE %ld]"
#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
-msgstr "在 “%sâ€ ä¸Šå‘¼å« GetOverlappedResult 失敗 [GLE %ld]"
+msgstr "在「%sã€ä¸Šå‘¼å« GetOverlappedResult 失敗 [GLE %ld]"
#: compat/fsmonitor/fsm-listen-win32.c
#, c-format
@@ -18010,7 +18530,7 @@ msgstr "無法複製 SID (%ld)"
#: compat/mingw.c
#, c-format
msgid "failed to get owner for '%s' (%ld)"
-msgstr "無法å–å¾— “%s†的所有者 (%ld)"
+msgstr "無法å–得「%sã€çš„æ‰€æœ‰è€… (%ld)"
#: compat/obstack.c
msgid "memory exhausted"
@@ -18099,7 +18619,7 @@ msgstr "ç„¡æ³•è®€å– IPC 回應"
#: compat/simple-ipc/ipc-unix-socket.c
#, c-format
msgid "could not start accept_thread '%s'"
-msgstr "無法啟動 accept_thread “%sâ€"
+msgstr "無法啟動 accept_thread「%sã€"
#: compat/simple-ipc/ipc-unix-socket.c
#, c-format
@@ -18109,26 +18629,26 @@ msgstr "無法啟動「%sã€çš„ worker[0]"
#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "ConnectNamedPipe failed for '%s' (%lu)"
-msgstr "å° â€œ%s†進行 ConnectNamedPipe 失敗 (%lu)"
+msgstr "å°ã€Œ%sã€é€²è¡Œ ConnectNamedPipe 失敗 (%lu)"
#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "could not create fd from pipe for '%s'"
-msgstr "無法為 “%s†從管é“建立 fd"
+msgstr "無法為「%sã€å¾žç®¡é“建立 fd"
#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "could not start thread[0] for '%s'"
-msgstr "無法為 “%s†啟動 thread[0]"
+msgstr "無法為「%sã€å•Ÿå‹• thread[0]"
#: compat/simple-ipc/ipc-win32.c
#, c-format
msgid "wait for hEvent failed for '%s'"
-msgstr "等待 “%s†的 hEvent 失敗"
+msgstr "等待「%sã€çš„ hEvent 失敗"
#: compat/terminal.c
msgid "cannot resume in the background, please use 'fg' to resume"
-msgstr "無法在背景繼續;請使用 “fg†繼續"
+msgstr "無法在背景繼續;請使用「fgã€ç¹¼çºŒ"
#: compat/terminal.c
msgid "cannot restore terminal settings"
@@ -18320,7 +18840,7 @@ msgstr "%s 變數的值無效"
#: config.c
#, c-format
msgid "ignoring unknown core.fsync component '%s'"
-msgstr "忽略未知的 core.fsync 組件「%sã€"
+msgstr "忽略未知的 core.fsync 元件「%sã€"
#: config.c
#, c-format
@@ -18348,8 +18868,14 @@ msgid "bad zlib compression level %d"
msgstr "錯誤的 zlib 壓縮級別 %d"
#: config.c
-msgid "core.commentChar should only be one ASCII character"
-msgstr "core.commentChar 應該是一個 ASCII 字元"
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s ä¸èƒ½åŒ…嫿›è¡Œç¬¦è™Ÿ"
+
+#: config.c
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s 得有至少 1 個字元"
#: config.c
#, c-format
@@ -18358,7 +18884,7 @@ msgstr "忽略未知的 core.fsyncMethod 值「%sã€"
#: config.c
msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
-msgstr "core.fsyncObjectFiles 已被å–代。請改用 core.fsync"
+msgstr "core.fsyncObjectFiles 已棄用。請改用 core.fsync"
#: config.c
#, c-format
@@ -18395,11 +18921,6 @@ msgid "unable to resolve config blob '%s'"
msgstr "ä¸èƒ½è§£æžè¨­å®šç‰©ä»¶ '%s'"
#: config.c
-#, c-format
-msgid "failed to parse %s"
-msgstr "è§£æž %s 失敗"
-
-#: config.c
msgid "unable to parse command-line config"
msgstr "無法解æžå‘½ä»¤åˆ—中的設定"
@@ -18444,6 +18965,11 @@ msgstr "寫入新的設定檔案 %s 失敗"
#: config.c
#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "ä¸å…許多列備註:「%sã€"
+
+#: config.c
+#, c-format
msgid "could not lock config file %s"
msgstr "ä¸èƒ½éŽ–å®šè¨­å®šæª”æ¡ˆ %s"
@@ -18490,7 +19016,7 @@ msgstr "無效的å°ç¯€å稱:%s"
#: config.c
#, c-format
msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
-msgstr "因為第 %2$<PRIuMAX> 列中 “%1$s†的文字列太長,故拒絕é‹ä½œ"
+msgstr "因為第 %2$<PRIuMAX> 列中「%1$sã€çš„æ–‡å­—列太長,故拒絕é‹ä½œ"
#: config.c
#, c-format
@@ -18704,7 +19230,7 @@ msgstr "%s 中的 CRLF 將被 LF å–代"
msgid ""
"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
"touches it"
-msgstr "在 “%s†的工作複本中,下次 Git 接觸到時會用 LF å–代 CRLF"
+msgstr "在「%sã€çš„工作複本中,下次 Git 接觸到時會用 LF å–代 CRLF"
#: convert.c
#, c-format
@@ -18716,7 +19242,7 @@ msgstr "檔案 %s 中的 LF 將被 CRLF å–代"
msgid ""
"in the working copy of '%s', LF will be replaced by CRLF the next time Git "
"touches it"
-msgstr "在 “%s†的工作複本中,下次 Git 接觸到時會用 CRLF å–代 LF"
+msgstr "在「%sã€çš„工作複本中,下次 Git 接觸到時會用 CRLF å–代 LF"
#: convert.c
#, c-format
@@ -18937,7 +19463,7 @@ msgstr "ä¸èƒ½é–‹å•Ÿç›®éŒ„ '%s'"
#: diagnose.c
#, c-format
msgid "skipping '%s', which is neither file nor directory"
-msgstr "ç•¥éŽ â€œ%sâ€ï¼Œå…¶éžæª”案或目錄"
+msgstr "ç•¥éŽã€Œ%sã€ï¼Œå…¶éžæª”案或目錄"
#: diagnose.c
msgid "could not duplicate stdout"
@@ -18957,10 +19483,6 @@ msgid "--merge-base does not work with ranges"
msgstr "--merge-base 跟範åœç„¡æ³•æ­é…é‹ä½œ"
#: diff-lib.c
-msgid "--merge-base only works with commits"
-msgstr "--merge-base åªèƒ½è·Ÿæäº¤æ­é…æ‰èƒ½é‹ä½œ"
-
-#: diff-lib.c
msgid "unable to get HEAD"
msgstr "ä¸èƒ½å–å¾— HEAD"
@@ -19030,6 +19552,11 @@ msgstr "color-moved-ws:allow-indentation-change ä¸èƒ½èˆ‡å…¶å®ƒç©ºç™½å­—元模
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr "設定變數 'diff.submodule' 未知的å–值:'%s'"
+#: diff.c merge-recursive.c transport.c
+#, c-format
+msgid "unknown value for config '%s': %s"
+msgstr "設定 '%s' çš„å–值未知:%s"
+
#: diff.c
#, c-format
msgid ""
@@ -19124,13 +19651,6 @@ msgid "invalid mode '%s' in --color-moved-ws"
msgstr "--color-moved-ws ä¸­çš„ç„¡æ•ˆæ¨¡å¼ '%s'"
#: diff.c
-msgid ""
-"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
-"\"histogram\""
-msgstr ""
-"diff-algorithm é¸é …有 \"myers\"ã€\"minimal\"ã€\"patience\" å’Œ \"histogram\""
-
-#: diff.c
#, c-format
msgid "invalid argument to %s"
msgstr "%s çš„åƒæ•¸ç„¡æ•ˆ"
@@ -19187,8 +19707,8 @@ msgid "output only the last line of --stat"
msgstr "åªè¼¸å‡º --stat 的最後一行"
#: diff.c
-msgid "<param1,param2>..."
-msgstr "<åƒæ•¸1,åƒæ•¸2>..."
+msgid "<param1>,<param2>..."
+msgstr "<param1>,<param2>..."
#: diff.c
msgid ""
@@ -19200,8 +19720,8 @@ msgid "synonym for --dirstat=cumulative"
msgstr "å’Œ --dirstat=cumulative åŒç¾©"
#: diff.c
-msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "是 --dirstat=files,param1,param2... çš„åŒç¾©è©ž"
+msgid "synonym for --dirstat=files,<param1>,<param2>..."
+msgstr "是 --dirstat=files,<param1>,<param2>... çš„åŒç¾©è©ž"
#: diff.c
msgid "warn if changes introduce conflict markers or whitespace errors"
@@ -19241,7 +19761,7 @@ msgstr "使用æä¾›çš„æª”案å長度生æˆå·®ç•°çµ±è¨ˆ"
#: diff.c
msgid "generate diffstat with a given graph width"
-msgstr "使用æä¾›çš„圖形長度生æˆå·®ç•°çµ±è¨ˆ"
+msgstr "產出é™åˆ¶ç‚ºæä¾›çš„寬度的差異統計圖形"
#: diff.c
msgid "<count>"
@@ -19424,14 +19944,6 @@ msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "使用 \"histogram diff\" 演算法生æˆå·®ç•°"
#: diff.c
-msgid "<algorithm>"
-msgstr "<演算法>"
-
-#: diff.c
-msgid "choose a diff algorithm"
-msgstr "鏿“‡ä¸€å€‹å·®ç•°æ¼”算法"
-
-#: diff.c
msgid "<text>"
msgstr "<文字>"
@@ -19885,7 +20397,7 @@ msgstr "é æœŸ '%s',得到 '%s'"
#: fetch-pack.c
#, c-format
msgid "expected '%s'"
-msgstr "é æœŸ “%sâ€"
+msgstr "é æœŸã€Œ%sã€"
#: fetch-pack.c
#, c-format
@@ -19977,45 +20489,49 @@ msgstr "無法將「%sã€å‘½ä»¤å‚³é€åˆ° fsmonitor--daemon"
#: fsmonitor-settings.c
#, c-format
msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr "純版本庫 “%s†與 fsmonitor ä¸ç›¸å®¹"
+msgstr "純版本庫「%sã€èˆ‡ fsmonitor ä¸ç›¸å®¹"
#: fsmonitor-settings.c
#, c-format
msgid "repository '%s' is incompatible with fsmonitor due to errors"
-msgstr "版本庫 “%s†因錯誤而與 fsmonitor ä¸ç›¸å®¹"
+msgstr "版本庫「%sã€å› éŒ¯èª¤è€Œèˆ‡ fsmonitor ä¸ç›¸å®¹"
#: fsmonitor-settings.c
#, c-format
msgid "remote repository '%s' is incompatible with fsmonitor"
-msgstr "é ç«¯ç‰ˆæœ¬åº« “%s†與 fsmonitor ä¸ç›¸å®¹"
+msgstr "é ç«¯ç‰ˆæœ¬åº«ã€Œ%sã€èˆ‡ fsmonitor ä¸ç›¸å®¹"
#: fsmonitor-settings.c
#, c-format
msgid "virtual repository '%s' is incompatible with fsmonitor"
-msgstr "虛擬版本庫 “%s†與 fsmonitor ä¸ç›¸å®¹"
+msgstr "虛擬版本庫「%sã€èˆ‡ fsmonitor ä¸ç›¸å®¹"
#: fsmonitor-settings.c
#, c-format
msgid ""
"socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
"sockets support"
-msgstr "通訊端 “%s†因缺少 Unix 通訊端支æ´ï¼Œè€Œèˆ‡ fsmonitor ä¸ç›¸å®¹"
+msgstr "通訊端「%sã€å› ç¼ºå°‘ Unix 通訊端支æ´ï¼Œè€Œèˆ‡ fsmonitor ä¸ç›¸å®¹"
#: git.c
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>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <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"
-" [--config-env=<name>=<envvar>] <command> [<args>]"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+" [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+" <command> [<args>]"
#: git.c
msgid ""
@@ -20219,7 +20735,7 @@ msgstr "無法從「%sã€è®€å– SSH ç°½å資料緩è¡å€"
#: graph.c
#, c-format
msgid "ignored invalid color '%.*s' in log.graphColors"
-msgstr "已忽略 log.graphColors 中無效的 “%.*s†色彩"
+msgstr "已忽略 log.graphColors 中無效的「%.*sã€è‰²å½©"
#: grep.c
msgid ""
@@ -20415,14 +20931,14 @@ msgstr ""
"設定 `git config advice.ignoredHook false` 來關閉這æ¢è­¦å‘Šã€‚"
#: http-fetch.c
+msgid "not a git repository"
+msgstr "䏿˜¯ä¸€å€‹ git 版本庫"
+
+#: http-fetch.c
#, c-format
msgid "argument to --packfile must be a valid hash (got '%s')"
msgstr "傳入 --packfile çš„åƒæ•¸å¿…須是有效的雜湊 (收到 '%s')"
-#: http-fetch.c
-msgid "not a git repository"
-msgstr "䏿˜¯ä¸€å€‹ git 版本庫"
-
#: http.c
#, c-format
msgid "negative value for http.postBuffer; defaulting to %d"
@@ -20437,6 +20953,10 @@ msgid "Public key pinning not supported with cURL < 7.39.0"
msgstr "䏿”¯æ´å…¬é‘°æª”案鎖定,因為 cURL < 7.39.0"
#: http.c
+msgid "Unknown value for http.proactiveauth"
+msgstr "http.proactiveauth 的值未知"
+
+#: http.c
msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
msgstr "䏿”¯æ´ CURLSSLOPT_NO_REVOKE,因為 cURL < 7.44.0"
@@ -20456,6 +20976,14 @@ msgid "Could not set SSL backend to '%s': already set"
msgstr "無法將 SSL 後端設定為 '%s':已經設定"
#: http.c
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "ä¸å…許從 http.cookiefile 的設定值「-ã€è™•è®€å– cookie"
+
+#: http.c
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "http.cookiefile 空白,忽略 http.savecookies"
+
+#: http.c
#, c-format
msgid ""
"unable to update url base from redirection:\n"
@@ -20539,7 +21067,7 @@ msgstr "sparse:path éŽæ¿¾å™¨æ”¯æ´å·²è¢«åˆªé™¤"
#: list-objects-filter-options.c
#, c-format
msgid "'%s' for 'object:type=<type>' is not a valid object type"
-msgstr "“object:type=<type>†的 “%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„物件格å¼"
+msgstr "「object:type=<type>ã€çš„「%sã€ä¸æ˜¯æœ‰æ•ˆçš„物件格å¼"
#: list-objects-filter-options.c
#, c-format
@@ -20620,6 +21148,20 @@ msgstr ""
msgid "Unable to create '%s.lock': %s"
msgstr "ä¸èƒ½å»ºç«‹ '%s.lock':%s"
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "無法建立暫存物件目錄"
+
+#: loose.c
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "無法寫入鬆散物件索引 %s"
+
+#: loose.c
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "寫入鬆散物件索引 %s 失敗"
+
#: ls-refs.c
#, c-format
msgid "unexpected line: '%s'"
@@ -20633,6 +21175,11 @@ msgstr "在 ls-refs 引數之後應該有一個 flush 包"
msgid "quoted CRLF detected"
msgstr "嵿¸¬åˆ°ç”±å¯åˆ—å°å­—å…ƒ (quoted) 所組æˆçš„ CRLF"
+#: mem-pool.c strbuf.c wrapper.c
+#, c-format
+msgid "unable to format message: %s"
+msgstr "無法格å¼åŒ–訊æ¯ï¼š%s"
+
#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (not checked out)"
@@ -20648,6 +21195,11 @@ msgstr "無法åˆä½µ %s å­æ¨¡çµ„(沒有åˆä½µåŸºåº•)"
msgid "Failed to merge submodule %s (commits not present)"
msgstr "無法åˆä½µå­æ¨¡çµ„ %s(æäº¤ä¸å­˜åœ¨ï¼‰"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "錯誤:無法åˆä½µå­æ¨¡çµ„ %s (版本庫æå£žï¼‰"
+
#: merge-ort.c merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (commits don't follow merge-base)"
@@ -20678,14 +21230,15 @@ msgstr ""
"無法åˆä½µ %s å­æ¨¡çµ„,但有找到幾個å¯è¡Œçš„åˆä½µæ–¹æ¡ˆï¼š\n"
"%s"
-#: merge-ort.c merge-recursive.c
-msgid "Failed to execute internal merge"
-msgstr "無法執行內部åˆä½µ"
+#: merge-ort.c
+#, c-format
+msgid "error: failed to execute internal merge for %s"
+msgstr "éŒ¯èª¤ï¼šç„¡æ³•å° %s 執行內部åˆä½µ"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "Unable to add %s to database"
-msgstr "ä¸èƒ½æ–°å¢ž %s 至物件庫"
+msgid "error: unable to add %s to database"
+msgstr "錯誤:無法將 %s 加進資料庫"
#: merge-ort.c merge-recursive.c
#, c-format
@@ -20785,15 +21338,15 @@ msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s."
msgstr ""
"è¡çªï¼ˆé‡æ–°å‘½å/刪除):%1$s 已釿–°å‘½å為 %3$s 中的 %2$s å»åœ¨ %4$s 中被刪除。"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "cannot read object %s"
-msgstr "ä¸èƒ½è®€å–物件 %s"
+msgid "error: cannot read object %s"
+msgstr "錯誤:無法讀å–物件 %s"
-#: merge-ort.c merge-recursive.c
+#: merge-ort.c
#, c-format
-msgid "object %s is not a blob"
-msgstr "物件 %s 䏿˜¯ä¸€å€‹è³‡æ–™ç‰©ä»¶"
+msgid "error: object %s is not a blob"
+msgstr "錯誤:物件 %s 䏿˜¯ä¸€å€‹è³‡æ–™ç‰©ä»¶"
#: merge-ort.c
#, c-format
@@ -20850,7 +21403,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
@@ -20949,6 +21502,11 @@ msgstr "ä¸çŸ¥é“å¦‚ä½•è™•ç† %06o %s '%s'"
#: merge-recursive.c
#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "無法åˆä½µå­æ¨¡çµ„ %s (版本庫æå£žï¼‰"
+
+#: merge-recursive.c
+#, c-format
msgid "Fast-forwarding submodule %s to the following commit:"
msgstr "å­æ¨¡çµ„ %s 快轉到如下æäº¤ï¼š"
@@ -20960,7 +21518,7 @@ msgstr "å¿«è½‰å­æ¨¡çµ„ %s"
#: merge-recursive.c
#, c-format
msgid "Failed to merge submodule %s (merge following commits not found)"
-msgstr "無法åˆä½µå­æ¨¡çµ„ %s (沒發ç¾åˆä½µè·Ÿéš¨çš„æäº¤ï¼‰"
+msgstr "無法åˆä½µå­æ¨¡çµ„ %s (找ä¸åˆ°åˆä½µè·Ÿéš¨çš„æäº¤ï¼‰"
#: merge-recursive.c
#, c-format
@@ -20993,6 +21551,15 @@ msgid "Failed to merge submodule %s (multiple merges found)"
msgstr "無法åˆä½µå­æ¨¡çµ„ %s (發ç¾å¤šå€‹åˆä½µï¼‰"
#: merge-recursive.c
+msgid "failed to execute internal merge"
+msgstr "無法執行內部åˆä½µ"
+
+#: merge-recursive.c
+#, c-format
+msgid "unable to add %s to database"
+msgstr "無法將 %s 加進資料庫"
+
+#: merge-recursive.c
#, c-format
msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
msgstr "錯誤:拒絕éºå¤±æœªè¿½è¹¤æª”案 '%s',而是寫入 %s。"
@@ -21107,6 +21674,16 @@ msgstr ""
"命å目錄 %4$s->%5$s"
#: merge-recursive.c
+#, c-format
+msgid "cannot read object %s"
+msgstr "ä¸èƒ½è®€å–物件 %s"
+
+#: merge-recursive.c
+#, c-format
+msgid "object %s is not a blob"
+msgstr "物件 %s 䏿˜¯ä¸€å€‹è³‡æ–™ç‰©ä»¶"
+
+#: merge-recursive.c
msgid "modify"
msgstr "修改"
@@ -21180,146 +21757,249 @@ msgstr "ä¸èƒ½è§£æžç‰©ä»¶ '%s'"
msgid "failed to read the cache"
msgstr "讀å–å¿«å–失敗"
-#: midx.c
-msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr "多包索引的物件 ID fanout 大å°éŒ¯èª¤"
+#: midx-write.c
+#, c-format
+msgid "failed to add packfile '%s'"
+msgstr "新增 packfile '%s' 失敗"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index file %s is too small"
-msgstr "多包索引檔案 %s 太å°"
+msgid "failed to open pack-index '%s'"
+msgstr "開啟包索引 '%s' 失敗"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr "多包索引簽å 0x%08x 和簽å 0x%08x ä¸ç¬¦åˆ"
+msgid "failed to locate object %d in packfile"
+msgstr "在 packfile 中定ä½ç‰©ä»¶ %d 失敗"
-#: midx.c
+#: midx-write.c
+msgid "cannot store reverse index file"
+msgstr "無法儲存倒排索引檔案"
+
+#: midx-write.c
#, c-format
-msgid "multi-pack-index version %d not recognized"
-msgstr "multi-pack-index 版本 %d ä¸èƒ½è¢«è­˜åˆ¥"
+msgid "could not parse line: %s"
+msgstr "ç„¡æ³•è§£æžæ©«åˆ—:%s"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "multi-pack-index 雜湊版本 %u 與版本 %u ä¸ç¬¦åˆ"
+msgid "malformed line: %s"
+msgstr "橫列格å¼éŒ¯èª¤ï¼š%s"
-#: midx.c
-msgid "multi-pack-index missing required pack-name chunk"
-msgstr "多包索引缺少必需的包åå€å¡Š"
+#: midx-write.c
+msgid "could not load pack"
+msgstr "無法載入包"
-#: midx.c
-msgid "multi-pack-index missing required OID fanout chunk"
-msgstr "多包索引缺少必需的物件 ID fanout å€å¡Š"
+#: midx-write.c
+#, c-format
+msgid "could not open index for %s"
+msgstr "無法開啟 %s 的索引"
-#: midx.c
-msgid "multi-pack-index missing required OID lookup chunk"
-msgstr "多包索引缺少必需的物件 ID 查詢å€å¡Š"
+#: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "無法將「%sã€link 至「%sã€"
-#: midx.c
-msgid "multi-pack-index missing required object offsets chunk"
-msgstr "多包索引缺少必需的物件ä½ç§»å€å¡Š"
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "清ç†ä½æ–¼ %s 的多包索引失敗"
-#: midx.c
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "無法寫入有ä½åœ–çš„å¢žé‡ MIDX"
+
+#: midx-write.c
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr "å¿½ç•¥ç¾æœ‰çš„多包索引:總和檢查碼ä¸ç¬¦"
+
+#: midx-write.c
+msgid "Adding packfiles to multi-pack-index"
+msgstr "正在新增 packfile 至多包索引"
+
+#: midx-write.c
#, c-format
-msgid "multi-pack-index pack names out of order: '%s' before '%s'"
-msgstr "多包索引包åç„¡åºï¼š'%s' 在 '%s' 之å‰"
+msgid "unknown preferred pack: '%s'"
+msgstr "未知å好包:「%sã€"
-#: midx.c
+#: midx-write.c
#, c-format
-msgid "bad pack-int-id: %u (%u total packs)"
-msgstr "錯的 pack-int-id:%u(共有 %u 個包)"
+msgid "cannot select preferred pack %s with no objects"
+msgstr "無法é¸å–å好,沒有物件的 %s 包"
+
+#: midx-write.c
+#, c-format
+msgid "did not see pack-file %s to drop"
+msgstr "æ²’æœ‰çœ‹åˆ°è¦æ¨æ£„çš„ packfile %s"
+
+#: midx-write.c
+#, c-format
+msgid "preferred pack '%s' is expired"
+msgstr "å好包「%sã€å·²ç¶“éŽæœŸ"
+
+#: midx-write.c
+msgid "no pack files to index."
+msgstr "沒有è¦ç´¢å¼•çš„ pack 檔案。"
+
+#: midx-write.c
+msgid "refusing to write multi-pack .bitmap without any objects"
+msgstr "拒絕寫入無任何物件的多包 .bitmap"
+
+#: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "無法建立暫時的 MIDX 層"
+
+#: midx-write.c
+msgid "could not write multi-pack bitmap"
+msgstr "無法寫入多包ä½åœ–"
+
+#: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "無法開啟多å°è£ç´¢å¼•éˆæª”案"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "無法更改新多å°è£ç´¢å¼•層的å稱"
+
+#: midx-write.c
+msgid "could not write multi-pack-index"
+msgstr "無法寫入多包索引"
+
+#: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "無法將一個增é‡å¤šå°è£ç´¢å¼•çš„å¥—ä»¶è¨­ç‚ºéŽæœŸ"
+
+#: midx-write.c
+msgid "Counting referenced objects"
+msgstr "正在計算引用物件"
+
+#: midx-write.c
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "正在尋找並刪除沒有引用的 packfile"
+
+#: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "ç„¡æ³•é‡æ–°å°è£å¢žé‡çš„多å°è£ç´¢å¼•"
+
+#: midx-write.c
+msgid "could not start pack-objects"
+msgstr "ä¸èƒ½é–‹å§‹ pack-objects"
+
+#: midx-write.c
+msgid "could not finish pack-objects"
+msgstr "ä¸èƒ½çµæŸ pack-objects"
#: midx.c
-msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
-msgstr "多包索引儲存一個64ä½ä½ç§»ï¼Œä½†æ˜¯ off_t 太å°"
+msgid "multi-pack-index OID fanout is of the wrong size"
+msgstr "多包索引的物件 ID fanout 大å°éŒ¯èª¤"
#: midx.c
#, c-format
-msgid "failed to add packfile '%s'"
-msgstr "新增 packfile '%s' 失敗"
+msgid ""
+"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
+msgstr "物件 ID 扇出無åºï¼šfanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
#: midx.c
-#, c-format
-msgid "failed to open pack-index '%s'"
-msgstr "開啟包索引 '%s' 失敗"
+msgid "multi-pack-index OID lookup chunk is the wrong size"
+msgstr "多包索引 OID 查詢å€å¡Šçš„大尿œ‰èª¤"
+
+#: midx.c
+msgid "multi-pack-index object offset chunk is the wrong size"
+msgstr "多包索引的物件åç§»å€å¡Šå¤§å°æœ‰èª¤"
#: midx.c
#, c-format
-msgid "failed to locate object %d in packfile"
-msgstr "在 packfile 中定ä½ç‰©ä»¶ %d 失敗"
+msgid "multi-pack-index file %s is too small"
+msgstr "多包索引檔案 %s 太å°"
#: midx.c
-msgid "cannot store reverse index file"
-msgstr "無法儲存倒排索引檔案"
+#, c-format
+msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
+msgstr "多包索引簽å 0x%08x 和簽å 0x%08x ä¸ç¬¦åˆ"
#: midx.c
#, c-format
-msgid "could not parse line: %s"
-msgstr "ç„¡æ³•è§£æžæ©«åˆ—:%s"
+msgid "multi-pack-index version %d not recognized"
+msgstr "multi-pack-index 版本 %d ä¸èƒ½è¢«è­˜åˆ¥"
#: midx.c
#, c-format
-msgid "malformed line: %s"
-msgstr "橫列格å¼éŒ¯èª¤ï¼š%s"
+msgid "multi-pack-index hash version %u does not match version %u"
+msgstr "multi-pack-index 雜湊版本 %u 與版本 %u ä¸ç¬¦åˆ"
#: midx.c
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "å¿½ç•¥ç¾æœ‰çš„多包索引:總和檢查碼ä¸ç¬¦"
+msgid "multi-pack-index required pack-name chunk missing or corrupted"
+msgstr "多包索引所需的å°è£å稱å€å¡Šä¸å­˜åœ¨æˆ–æå£ž"
#: midx.c
-msgid "could not load pack"
-msgstr "無法載入包"
+msgid "multi-pack-index required OID fanout chunk missing or corrupted"
+msgstr "多包索引所需的 OID fanout å€å¡Šä¸å­˜åœ¨æˆ–æå£ž"
#: midx.c
-#, c-format
-msgid "could not open index for %s"
-msgstr "無法開啟 %s 的索引"
+msgid "multi-pack-index required OID lookup chunk missing or corrupted"
+msgstr "多包索引所需的 OID 查詢å€å¡Šä¸å­˜åœ¨æˆ–æå£ž"
#: midx.c
-msgid "Adding packfiles to multi-pack-index"
-msgstr "正在新增 packfile 至多包索引"
+msgid "multi-pack-index required object offsets chunk missing or corrupted"
+msgstr "多包索引所需的物件åç§»å€å¡Šä¸å­˜åœ¨æˆ–æå£ž"
+
+#: midx.c
+msgid "multi-pack-index pack-name chunk is too short"
+msgstr "多包索引的å°è£å稱å€å¡ŠéŽçŸ­"
#: midx.c
#, c-format
-msgid "unknown preferred pack: '%s'"
-msgstr "未知å好包:「%sã€"
+msgid "multi-pack-index pack names out of order: '%s' before '%s'"
+msgstr "多包索引包åç„¡åºï¼š'%s' 在 '%s' 之å‰"
+
+#: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "多å°è£ç´¢å¼•éˆæª”案éŽå°"
#: midx.c
#, c-format
-msgid "cannot select preferred pack %s with no objects"
-msgstr "無法é¸å–å好,沒有物件的 %s 包"
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "基礎 MIDX çš„å°è£è¨ˆæ•¸å¤ªé«˜ï¼š%<PRIuMAX>"
#: midx.c
#, c-format
-msgid "did not see pack-file %s to drop"
-msgstr "æ²’æœ‰çœ‹åˆ°è¦æ¨æ£„çš„ packfile %s"
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "基礎 MIDX 的物件計數太高:%<PRIuMAX>"
#: midx.c
#, c-format
-msgid "preferred pack '%s' is expired"
-msgstr "å好包「%sã€å·²ç¶“éŽæœŸ"
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "無法的多å°è£ç´¢å¼•éˆï¼šã€Œ%sã€åˆ—䏿˜¯é›œæ¹Šå€¼"
#: midx.c
-msgid "no pack files to index."
-msgstr "沒有è¦ç´¢å¼•çš„ pack 檔案。"
+msgid "unable to find all multi-pack index files"
+msgstr "找ä¸åˆ°æ‰€æœ‰çš„多å°è£ç´¢å¼•檔案"
#: midx.c
-msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "拒絕寫入無任何物件的多包 .bitmap"
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "無效的 MIDX 物件ä½ç½®ï¼ŒMIDX 大概有å•題"
#: midx.c
-msgid "could not write multi-pack bitmap"
-msgstr "無法寫入多包ä½åœ–"
+#, c-format
+msgid "bad pack-int-id: %u (%u total packs)"
+msgstr "錯的 pack-int-id:%u(共有 %u 個包)"
#: midx.c
-msgid "could not write multi-pack-index"
-msgstr "無法寫入多包索引"
+msgid "MIDX does not contain the BTMP chunk"
+msgstr "MIDX æœªåŒ…å« BTMP å€å¡Š"
#: midx.c
#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "清ç†ä½æ–¼ %s 的多包索引失敗"
+msgid "could not load bitmapped pack %<PRIu32>"
+msgstr "無法載入ä½åœ–化 (bitmapped) çš„å°è£ %<PRIu32>"
+
+#: midx.c
+msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
+msgstr "多包索引儲存一個64ä½ä½ç§»ï¼Œä½†æ˜¯ off_t 太å°"
+
+#: midx.c
+msgid "multi-pack-index large offset out of bounds"
+msgstr "多包索引的最大å移超出邊界"
#: midx.c
msgid "multi-pack-index file exists, but failed to parse"
@@ -21334,12 +22014,6 @@ msgid "Looking for referenced packfiles"
msgstr "正在尋找引用的 packfile"
#: midx.c
-#, c-format
-msgid ""
-"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-msgstr "物件 ID 扇出無åºï¼šfanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
-
-#: midx.c
msgid "the midx contains no oid"
msgstr "midx 沒有 oid"
@@ -21375,22 +22049,6 @@ msgstr "為 packfile %s 載入包索引失敗"
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "oid[%d] = %s 錯誤的物件ä½ç§»ï¼š%<PRIx64> != %<PRIx64>"
-#: midx.c
-msgid "Counting referenced objects"
-msgstr "正在計算引用物件"
-
-#: midx.c
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "正在尋找並刪除沒有引用的 packfile"
-
-#: midx.c
-msgid "could not start pack-objects"
-msgstr "ä¸èƒ½é–‹å§‹ pack-objects"
-
-#: midx.c
-msgid "could not finish pack-objects"
-msgstr "ä¸èƒ½çµæŸ pack-objects"
-
#: name-hash.c
#, c-format
msgid "unable to create lazy_dir thread: %s"
@@ -21445,6 +22103,30 @@ msgstr "æ‹’çµ•å‘ %s(在 refs/notes/ 之外)寫入註解"
msgid "Bad %s value: '%s'"
msgstr "壞的 %s 值:'%s'"
+#: object-file-convert.c
+msgid "failed to decode tree entry"
+msgstr "無法解碼樹狀物件項目"
+
+#: object-file-convert.c
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "無法為 %s 映射樹狀物件項目"
+
+#: object-file-convert.c
+#, c-format
+msgid "bad %s in commit"
+msgstr "æäº¤ä¸­æœ‰ç„¡æ•ˆçš„ %s"
+
+#: object-file-convert.c
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "無法在æäº¤ç‰©ä»¶ä¸­æ˜ å°„ %s %s"
+
+#: object-file-convert.c
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "無法將物件從 %s 轉æ›ç‚º %s"
+
#: object-file.c
#, c-format
msgid "object directory %s does not exist; check .git/objects/info/alternates"
@@ -21573,6 +22255,21 @@ msgstr "打包物件 %s(儲存在 %s)已æå£ž"
#: object-file.c
#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "缺少 %s 到 %s 的映射"
+
+#: object-file.c
+#, c-format
+msgid "unable to open %s"
+msgstr "ä¸èƒ½é–‹å•Ÿ %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "「%sã€å’Œã€Œ%sã€æª”案內容ä¸åŒ"
+
+#: object-file.c
+#, c-format
msgid "unable to write file %s"
msgstr "無法寫檔案 %s"
@@ -21640,6 +22337,11 @@ msgstr "ä¸èƒ½è®€å–物件 %s"
#: object-file.c
#, c-format
+msgid "cannot map object %s to %s"
+msgstr "無法將物件 %s 映射到 %s"
+
+#: object-file.c
+#, c-format
msgid "object fails fsck: %s"
msgstr "物件 fsck 失敗:%s"
@@ -21674,11 +22376,6 @@ msgstr "%s 䏿˜¯ä¸€å€‹æœ‰æ•ˆçš„ '%s' 物件"
#: object-file.c
#, c-format
-msgid "unable to open %s"
-msgstr "ä¸èƒ½é–‹å•Ÿ %s"
-
-#: object-file.c
-#, c-format
msgid "hash mismatch for %s (expected %s)"
msgstr "%s 的雜湊值ä¸ç¬¦åˆï¼ˆé æœŸ %s)"
@@ -21714,7 +22411,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
@@ -21724,7 +22421,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.
@@ -21741,7 +22438,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
@@ -21901,6 +22598,20 @@ msgid "hash mismatch %s"
msgstr "雜湊值與 %s ä¸ç¬¦åˆ"
#: pack-bitmap-write.c
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "寫入ä½åœ–索引中時發ç¾é‡è¤‡é …目:%s"
+
+#: pack-bitmap-write.c
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "嘗試儲存未é¸å–çš„æäº¤ï¼šã€Œ%sã€"
+
+#: pack-bitmap-write.c
+msgid "too many pseudo-merges"
+msgstr "å½åˆä½µéŽå¤š"
+
+#: pack-bitmap-write.c
msgid "trying to write commit not in index"
msgstr "嘗試寫入ä¸åœ¨ç´¢å¼•çš„æäº¤"
@@ -21919,7 +22630,7 @@ msgstr "ä½åœ–索引檔案æå£žï¼ˆæ¨™é ­éŒ¯èª¤ï¼‰"
#: pack-bitmap.c
#, c-format
msgid "unsupported version '%d' for bitmap index file"
-msgstr "ä½åœ–索引檔案的版本 “%dâ€ ä¸æ”¯æ´"
+msgstr "ä½åœ–索引檔案的版本「%dã€ä¸æ”¯æ´"
#: pack-bitmap.c
msgid "corrupted bitmap index file (too short to fit hash cache)"
@@ -21930,6 +22641,19 @@ msgid "corrupted bitmap index file (too short to fit lookup table)"
msgstr "ä½åœ–索引檔案æå£žï¼ˆä¸å¤ é•·ï¼Œç„¡æ³•置入查詢表)"
#: pack-bitmap.c
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr "ä½åœ–索引檔案æå£žï¼ˆä¸å¤ é•·ï¼Œç„¡æ³•置入å½åˆä½µè¡¨æ¨™é ­ï¼‰"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr "ä½åœ–索引檔案æå£žï¼ˆä¸å¤ é•·ï¼Œç„¡æ³•置入å½åˆä½µè¡¨ï¼‰"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr "ä½åœ–索引檔案æå£žï¼Œå½åˆä½µè¡¨å¤ªçŸ­"
+
+#: pack-bitmap.c
#, c-format
msgid "duplicate entry in bitmap index: '%s'"
msgstr "ä½åœ–索引中有é‡è¤‡é …目:「%sã€"
@@ -21969,6 +22693,10 @@ msgstr "多包ä½åœ–缺少需è¦çš„åå‘索引"
msgid "could not open pack %s"
msgstr "無法開啟å°åŒ… %s"
+#: pack-bitmap.c t/helper/test-read-midx.c
+msgid "could not determine MIDX preferred pack"
+msgstr "無法確定 MIDX å好的å°è£"
+
#: pack-bitmap.c
#, c-format
msgid "preferred pack (%s) is invalid"
@@ -21990,7 +22718,16 @@ msgstr "ä½åœ–查詢表æå£žï¼šæäº¤ç´¢å¼• %u 超出範åœ"
#: pack-bitmap.c
#, c-format
msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
-msgstr "ewah ä½åœ–æå£žï¼šæäº¤ “%s†之ä½åœ–çš„æ¨™é ­é­æˆªæ–·"
+msgstr "ewah ä½åœ–æå£žï¼šæäº¤ã€Œ%sã€ä¹‹ä½åœ–çš„æ¨™é ­é­æˆªæ–·"
+
+#: pack-bitmap.c
+#, c-format
+msgid "unable to load pack: '%s', disabling pack-reuse"
+msgstr "無法載入「%sã€å°è£ï¼Œåœç”¨ pack-reuse"
+
+#: pack-bitmap.c
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "無法計算å好å°è£ï¼Œåœç”¨ pack-reuse"
#: pack-bitmap.c
#, c-format
@@ -22031,6 +22768,11 @@ msgstr "ä½åœ–çµæžœä¸­æœ‰ä¸ç¬¦é …ç›®"
#: pack-bitmap.c
#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "å½åˆä½µç´¢å¼•超出範åœï¼ˆ%<PRIu32> >= %<PRIuMAX>)"
+
+#: pack-bitmap.c
+#, c-format
msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
msgstr "在「%2$sã€å°åŒ…,ä½ç§» %3$<PRIuMAX> 的地方找ä¸åˆ°ã€Œ%1$sã€"
@@ -22042,7 +22784,7 @@ msgstr "無法å–得「%sã€çš„ç£ç¢Ÿç”¨é‡"
#: pack-bitmap.c
#, c-format
msgid "bitmap file '%s' has invalid checksum"
-msgstr "“%s†ä½åœ–檔案的總和檢查碼無效"
+msgstr "「%sã€ä½åœ–檔案的總和檢查碼無效"
#: pack-mtimes.c
#, c-format
@@ -22103,6 +22845,14 @@ msgstr "無效的總和檢查碼"
msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
msgstr "%<PRIu64> ä½ç½®çš„修訂版索引 (rev-index) 無效:%<PRIu32> != %<PRIu32>"
+#: pack-revindex.c
+msgid "multi-pack-index reverse-index chunk is the wrong size"
+msgstr "多包索引的åå‘索引å€å¡Šå¤§å°æœ‰èª¤"
+
+#: pack-revindex.c
+msgid "could not determine preferred pack"
+msgstr "無法確定å好å°è£"
+
#: pack-write.c
msgid "cannot both write and verify reverse index"
msgstr "ç„¡æ³•åŒæ™‚寫入和驗證倒排索引"
@@ -22168,16 +22918,6 @@ msgstr "%s 需è¦ä¸€å€‹å€¼"
#: parse-options.c
#, c-format
-msgid "%s is incompatible with %s"
-msgstr "%s 與 %s ä¸ç›¸å®¹"
-
-#: parse-options.c
-#, c-format
-msgid "%s : incompatible with something else"
-msgstr "%s:和其它的ä¸ç›¸å®¹"
-
-#: parse-options.c
-#, c-format
msgid "%s takes no value"
msgstr "%s ä¸å–值"
@@ -22276,6 +23016,11 @@ msgstr " %s"
msgid "-NUM"
msgstr "-數字"
+#: parse-options.c
+#, c-format
+msgid "opposite of --no-%s"
+msgstr "--no-%s 的相å行為"
+
#: parse-options.h
msgid "expiry-date"
msgstr "到期時間"
@@ -22313,6 +23058,16 @@ msgid ""
"with --pathspec-from-file, pathspec elements are separated with NUL character"
msgstr "如使用 --pathspec-from-file,則 <è·¯å¾‘è¦æ ¼> 元件會使用 NUL 字元分隔"
+#: parse.c
+#, c-format
+msgid "bad boolean environment value '%s' for '%s'"
+msgstr "「%2$sã€çš„「%1$sã€å¸ƒæž—環境值無效"
+
+#: parse.c
+#, c-format
+msgid "failed to parse %s"
+msgstr "è§£æž %s 失敗"
+
#: path.c
#, c-format
msgid "Could not make %s writable by group"
@@ -22352,7 +23107,7 @@ msgstr "è·¯å¾‘è¦æ ¼åŒ…å«ç„¡æ•ˆçš„神奇å‰ç¶´"
#: pathspec.c
#, c-format
msgid "Invalid pathspec magic '%.*s' in '%s'"
-msgstr "åœ¨è·¯å¾‘è¦æ ¼ '%3$s' 中無效的神奇å‰ç¶´ '%2$.*1$s'"
+msgstr "有無效的神奇å‰ç¶´ã€Œ%.*sã€å‡ºç¾åœ¨è·¯å¾‘è¦æ ¼ã€Œ%sã€ä¸­"
#: pathspec.c
#, c-format
@@ -22371,6 +23126,11 @@ msgstr "%s:'literal' å’Œ 'glob' ä¸ç›¸å®¹"
#: pathspec.c
#, c-format
+msgid "'%s' is outside the directory tree"
+msgstr "「%sã€åœ¨ç›®éŒ„樹之外"
+
+#: pathspec.c
+#, c-format
msgid "%s: '%s' is outside repository at '%s'"
msgstr "%s:'%s' åœ¨ä½æ–¼ '%s' 的版本庫之外"
@@ -22464,6 +23224,10 @@ msgid "unable to parse --pretty format"
msgstr "ä¸èƒ½è§£æž --pretty æ ¼å¼"
#: promisor-remote.c
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr "延後抓å–已被åœç”¨ï¼›æŸäº›ç‰©ä»¶å¯èƒ½ç„¡æ³•使用"
+
+#: promisor-remote.c
msgid "promisor-remote: unable to fork off fetch subprocess"
msgstr "promisor-remote: 無法 fork fetch å­è™•ç†ç¨‹åº"
@@ -22493,6 +23257,72 @@ msgstr "object-infoï¼šå¼•æ•¸å¾Œé æœŸè¦æœ‰ flush"
msgid "Removing duplicate objects"
msgstr "正在刪除é‡è¤‡ç‰©ä»¶"
+#: pseudo-merge.c
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr "未能載入 %s çš„å½åˆä½µå¸¸è¦è¡¨ç¤ºå¼ï¼š%s"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s 須為éžè² æ•¸ï¼Œå°‡æŽ¡ç”¨é è¨­å€¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s 須介於 0 到 1 之間,將採用é è¨­å€¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s 須為正數,將採用é è¨­å€¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "å½åˆä½µç¾¤çµ„「%sã€ç¼ºå°‘必須的模å¼"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr "å½åˆä½µç¾¤çµ„「%sã€çš„éžç©©å®šé–¾å€¼ä½æ–¼ç©©å®šè€…之å‰"
+
+#: pseudo-merge.c
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr "來自組態的å½åˆä½µå¸¸è¦è¡¨ç¤ºå¼åŒ…å«å¤ªå¤šçš„æ“·å–群組(最多 %<PRIuMAX> 個)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "延伸å½åˆä½µè®€å–超出範åœï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "延伸å½åˆä½µé …ç›®éŽçŸ­ï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr "無法在åç§» %2$<PRIuMAX> 處找到æäº¤ %1$s çš„å½åˆä½µ"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr "延伸å½åˆä½µæŸ¥è©¢è¶…出範åœï¼ˆ%<PRIu32> >= %<PRIu32>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "讀å–超出範åœï¼šï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr "ç„¡æ³•è®€å–æäº¤ %s 的延伸å½åˆä½µè¡¨"
+
#: range-diff.c
msgid "could not start `log`"
msgstr "ä¸èƒ½å•Ÿå‹• `log`"
@@ -22530,7 +23360,7 @@ msgstr "ä¸èƒ½è§£æž '%s' 的日誌"
#: reachable.c
#, c-format
msgid "invalid extra cruft tip: '%s'"
-msgstr "無效的é¡å¤–廢棄æäº¤ä¿®è¨‚版:“%sâ€"
+msgstr "無效的é¡å¤–廢棄æäº¤ä¿®è¨‚版:「%sã€"
#: reachable.c
msgid "unable to enumerate additional recent objects"
@@ -22562,11 +23392,6 @@ msgstr "無法在索引中新增 '%s'"
#: read-cache.c
#, c-format
-msgid "unable to stat '%s'"
-msgstr "ç„¡æ³•å° %s 執行 stat"
-
-#: read-cache.c
-#, c-format
msgid "'%s' appears as both a file and as a directory"
msgstr "'%s' çœ‹èµ·ä¾†æ—¢æ˜¯æª”æ¡ˆåˆæ˜¯ç›®éŒ„"
@@ -22701,11 +23526,6 @@ msgstr "ç„¡æ³•è½‰æ›æˆç¨€ç–索引"
#: read-cache.c
#, c-format
-msgid "could not stat '%s'"
-msgstr "ä¸èƒ½å° '%s' å‘¼å« stat"
-
-#: read-cache.c
-#, c-format
msgid "unable to open git dir: %s"
msgstr "ä¸èƒ½é–‹å•Ÿ git 目錄:%s"
@@ -22732,7 +23552,7 @@ msgstr "éžé æœŸçš„ diff 狀態 %c"
#: read-cache.c
#, c-format
msgid "remove '%s'\n"
-msgstr "移除 “%sâ€\n"
+msgstr "移除「%sã€\n"
#: rebase-interactive.c
msgid ""
@@ -22782,11 +23602,11 @@ msgstr ""
"r, reword <æäº¤> = 使用æäº¤ï¼Œä½†ç·¨è¼¯æäº¤èªªæ˜Ž\n"
"e, edit <æäº¤> = 使用æäº¤ï¼Œä½†ä¸ç›´æŽ¥ä¿®è£œ (amend) \n"
"s, squash <æäº¤> = 使用æäº¤ï¼Œä½†èžåˆè‡³ä¸Šå€‹æäº¤\n"
-"f, fixup [-C | -c] <æäº¤> = è·Ÿ “squash†相似,但除éžå‚³å…¥ -C,\n"
+"f, fixup [-C | -c] <æäº¤> = 跟「squashã€ç›¸ä¼¼ï¼Œä½†é™¤éžå‚³å…¥ -C,\n"
" å¦å‰‡åªä¿ç•™ä¸Šä¸€å€‹æäº¤çš„æ—¥èªŒè¨Šæ¯ã€‚傳入 -C 表示åªä¿ç•™é€™å€‹\n"
" æäº¤çš„訊æ¯ï¼›å‚³å…¥ -c 與 -C 功能相åŒï¼Œä½†æœƒé–‹å•Ÿç·¨è¼¯å™¨\n"
"x, exec <命令> = 使用 shell 執行命令(這一列的剩餘部分)\n"
-"b, break = åœ¨æ­¤åœæ­¢ï¼ˆä½¿ç”¨ “git rebase --continue†繼續é‡å®šåŸºåº•)\n"
+"b, break = åœ¨æ­¤åœæ­¢ï¼ˆä½¿ç”¨ã€Œgit rebase --continueã€ç¹¼çºŒé‡å®šåŸºåº•)\n"
"d, drop <æäº¤> = 移除æäº¤\n"
"l, label <標籤> = ç‚ºç›®å‰ HEAD 打上指定å字標籤\n"
"t, reset <標籤> = é‡è¨­ HEAD 到指定標籤\n"
@@ -23002,6 +23822,11 @@ msgstr "é æœŸæ ¼å¼ï¼š%%(ahead-behind:<committish>)"
#: ref-filter.c
#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "é æœŸæ ¼å¼ï¼š%%(is-base:<committish>)"
+
+#: ref-filter.c
+#, c-format
msgid "malformed field name: %.*s"
msgstr "æ ¼å¼éŒ¯èª¤çš„æ¬„ä½å:%.*s"
@@ -23058,7 +23883,7 @@ msgstr "--format=%.*s ä¸èƒ½å’Œ --pythonã€--shellã€--tcl 一起使用"
#: ref-filter.c
msgid "failed to run 'describe'"
-msgstr "無法執行 “describeâ€"
+msgstr "無法執行「describeã€"
#: ref-filter.c
#, c-format
@@ -23176,8 +24001,8 @@ msgstr ""
"\n"
"\tgit config --global init.defaultBranch <name>\n"
"\n"
-"除了 “master†外,常用的分支å稱有 “mainâ€, “trunk†以åŠ\n"
-"“developmentâ€ã€‚剛建立的分支å¯ä»¥ç”¨é€™å€‹å‘½ä»¤é‡æ–°å‘½å:\n"
+"除了「masterã€å¤–,常用的分支å稱有「mainã€,「trunkã€ä»¥åŠ\n"
+"「developmentã€ã€‚剛建立的分支å¯ä»¥ç”¨é€™å€‹å‘½ä»¤é‡æ–°å‘½å:\n"
"\n"
"\tgit branch -m <name>\n"
@@ -23212,12 +24037,21 @@ msgid "log for %s is empty"
msgstr "%s 的日誌為空"
#: refs.c
+msgid "refusing to force and skip creation of reflog"
+msgstr "拒絕強制並略éŽå»ºç«‹å¼•用日誌"
+
+#: refs.c
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "拒絕更新有錯誤å稱 '%s' 的引用"
#: refs.c
#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "拒絕更新å½å¼•用「%sã€"
+
+#: refs.c
+#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "å°å¼•用 '%s' 執行 update_ref 失敗:%s"
@@ -23244,21 +24078,124 @@ msgstr "'%s' 已存在,無法建立 '%s'"
msgid "cannot process '%s' and '%s' at the same time"
msgstr "ç„¡æ³•åŒæ™‚è™•ç† '%s' å’Œ '%s'"
-#: refs/files-backend.c
-#, c-format
-msgid "could not remove reference %s"
-msgstr "無法刪除引用 %s"
-
-#: refs/files-backend.c refs/packed-backend.c
+#: refs.c
#, c-format
msgid "could not delete reference %s: %s"
msgstr "無法刪除引用 %s:%s"
-#: refs/files-backend.c refs/packed-backend.c
+#: refs.c
#, c-format
msgid "could not delete references: %s"
msgstr "無法刪除引用:%s"
+#: refs.c
+#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr "完æˆå¼•用移轉的測試執行,å¯ä»¥åœ¨ã€Œ%sã€æ‰¾åˆ°çµæžœ\n"
+
+#: refs.c
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "無法移除暫時性é·ç§»ç›®éŒ„「%sã€"
+
+#: refs.c
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "å¯ä»¥åœ¨ã€Œ%sã€æ‰¾åˆ°å·²é·ç§»çš„引用"
+
+#: refs/files-backend.c refs/reftable-backend.c
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr "無法鎖定引用「%sã€ï¼šé æœŸæ˜¯æŒ‡å‘「%sã€çš„符號引用,但這個是一般引用"
+
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "無法開啟 %s 目錄"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "正在檢查引用一致性"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "此引用å稱是å±éšªçš„:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr "嘗試以ä¸å­˜åœ¨çš„物件 %s 寫入引用「%sã€"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr "å˜—è©¦å°‡éžæäº¤ç‰©ä»¶ %s 寫入分支「%sã€"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr "ä¸å…許å°ã€ŒHEADã€é€²è¡Œå¤šæ¬¡æ›´æ–°ï¼ˆåŒ…å«é€éŽå…¶ã€Œ%sã€å¼•用進行的更新)"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr "無法鎖定引用「%sã€ï¼šç„¡æ³•è§£æžå¼•用「%sã€"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "無法鎖定引用「%sã€ï¼šç„¡æ³•讀å–引用"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr "ä¸å…許å°ã€Œ%sã€é€²è¡Œå¤šæ¬¡æ›´æ–°ï¼ˆåŒ…å«é€éŽã€Œ%sã€ç¬¦è™Ÿå¼•用進行的更新)"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "無法鎖定引用「%sã€ï¼šå¼•用已經存在"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr "無法鎖定引用「%sã€ï¼šç¼ºå°‘å¼•ç”¨ä½†é æœŸçš„æ˜¯ %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "無法鎖定引用「%sã€ï¼šä½æ–¼ %s 但頿œŸçš„æ˜¯ %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "引用表:準備事務:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "引用表:事務失敗:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "無法壓縮堆疊:%s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s not found"
+msgstr "找ä¸åˆ°å¼•用å稱 %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr "引用å稱 %s æ˜¯ç¬¦è™Ÿå¼•ç”¨ï¼Œä¸æ”¯æ´è¤‡è£½"
+
#: refspec.c
#, c-format
msgid "invalid refspec '%s'"
@@ -23271,6 +24208,11 @@ msgstr "在 push-option å–值中無效的引號:'%s'"
#: remote-curl.c
#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "未知的 object-format 值:%s"
+
+#: remote-curl.c
+#, c-format
msgid "%sinfo/refs not valid: is this a git repository?"
msgstr "%sinfo/refs 無效:這是一個 git 版本庫嗎?"
@@ -23387,7 +24329,7 @@ msgstr "å”å®šéŒ¯èª¤ï¼šé æœŸæ˜¯ã€Œ<URL> <路徑>ã€ï¼Œä½†ç¼ºå°‘空白"
#: remote-curl.c
#, c-format
msgid "failed to download file at URL '%s'"
-msgstr "ç„¡æ³•ä¸‹è¼‰ä½æ–¼ URL “%s†的檔案"
+msgstr "ç„¡æ³•ä¸‹è¼‰ä½æ–¼ URL「%sã€çš„æª”案"
#: remote-curl.c
msgid "git-http-push failed"
@@ -23426,12 +24368,12 @@ msgstr "æä¾›äº†ä¸€å€‹ä»¥ä¸Šçš„ uploadpack,使用第一個"
#: remote.c
#, c-format
msgid "unrecognized value transfer.credentialsInUrl: '%s'"
-msgstr "數值 transfer.credentialsInUrl 無法識別:“%sâ€"
+msgstr "數值 transfer.credentialsInUrl 無法識別:「%sã€"
#: remote.c
#, c-format
msgid "URL '%s' uses plaintext credentials"
-msgstr "URL “%s†使用明文憑證"
+msgstr "URL「%sã€ä½¿ç”¨æ˜Žæ–‡æ†‘è­‰"
#: remote.c
#, c-format
@@ -23672,7 +24614,7 @@ msgstr[0] ""
#: remote.c
msgid ""
" (use \"git pull\" if you want to integrate the remote branch with yours)\n"
-msgstr " (使用 “git pull†來將é ç«¯åˆ†æ”¯æ•´åˆé€²æ‚¨çš„分支)\n"
+msgstr " (使用「git pullã€ä¾†å°‡é ç«¯åˆ†æ”¯æ•´åˆé€²æ‚¨çš„分支)\n"
#: remote.c
#, c-format
@@ -23745,7 +24687,7 @@ msgstr "使用之å‰çš„解決方案解決 '%s'。"
#: rerere.c
#, c-format
msgid "cannot unlink stray '%s'"
-msgstr "無法刪除失散檔案 “%sâ€"
+msgstr "無法刪除失散檔案「%sã€"
#: rerere.c
#, c-format
@@ -23805,8 +24747,21 @@ msgstr "resolve-undo ä¸å­˜åœ¨çš„「%sã€è¨˜éŒ„"
#: revision.c
#, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "無法å–å¾— ancestry-path 引數 %s çš„æäº¤"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s 存在但屬於符號連çµ"
+
+#: revision.c
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge 需è¦å…¶ä¸­ä¸€ç¨®å½å¼•用 MERGE_HEADã€CHERRY_PICK_HEADã€REVERT_HEAD 或 "
+"REBASE_HEAD"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr "無法å–å¾— --ancestry-path 引數 %s çš„æäº¤"
#: revision.c
msgid "--unpacked=<packfile> no longer supported"
@@ -23815,7 +24770,7 @@ msgstr "--unpacked=<packfile> å·²ä¸å—支æ´"
#: revision.c
#, c-format
msgid "invalid option '%s' in --stdin mode"
-msgstr "在 --stdin 模å¼ä¸‹ï¼Œâ€œ%s†é¸é …無效"
+msgstr "在 --stdin 模å¼ä¸‹ï¼Œã€Œ%sã€é¸é …無效"
#: revision.c
msgid "your current branch appears to be broken"
@@ -23928,8 +24883,20 @@ msgid "only download metadata for the branch that will be checked out"
msgstr "åªä¸‹è¼‰æœƒç°½å‡ºçš„分支中介資料"
#: scalar.c
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<options>] [--] <repo> [<dir>]"
+msgid "create repository within 'src' directory"
+msgstr "在「srcã€ç›®éŒ„建立版本庫"
+
+#: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "指定是å¦è¦åœ¨è¤‡è£½éšŽæ®µæŠ“å–æ¨™ç±¤"
+
+#: scalar.c
+msgid ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
+msgstr ""
+"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
#: scalar.c
#, c-format
@@ -23953,6 +24920,11 @@ msgstr "無法設定「%sã€ä¸­çš„é ç«¯"
#: scalar.c
#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "無法åœç”¨ã€Œ%sã€çš„æ¨™ç±¤"
+
+#: scalar.c
+#, c-format
msgid "could not configure '%s'"
msgstr "無法設定「%sã€"
@@ -23991,17 +24963,36 @@ msgstr "--all 或 <enlistment> 但ä¸èƒ½å‚³å…¥å…©è€…"
#: scalar.c
#, c-format
msgid "could not remove stale scalar.repo '%s'"
-msgstr "ç„¡æ³•ç§»é™¤éŽæ™‚çš„ scalar.repo “%sâ€"
+msgstr "ç„¡æ³•ç§»é™¤éŽæ™‚çš„ scalar.repo「%sã€"
+
+#: scalar.c
+#, c-format
+msgid "removed stale scalar.repo '%s'"
+msgstr "å·²ç§»é™¤éŽæ™‚çš„ scalar.repo「%sã€"
#: scalar.c
#, c-format
-msgid "removing stale scalar.repo '%s'"
-msgstr "æ­£åœ¨ç§»é™¤éŽæ™‚çš„ scalar.repo “%sâ€"
+msgid "repository at '%s' has different owner"
+msgstr "使–¼ã€Œ%sã€çš„版本庫有ä¸åŒçš„æ“æœ‰è€…"
#: scalar.c
#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git 版本庫在「%sã€éºå¤±"
+msgid "repository at '%s' has a format issue"
+msgstr "使–¼ã€Œ%sã€çš„版本庫有格å¼å•題"
+
+#: scalar.c
+#, c-format
+msgid "repository not found in '%s'"
+msgstr "版本庫ä¸åœ¨ã€Œ%sã€"
+
+#: scalar.c
+#, c-format
+msgid ""
+"to unregister this repository from Scalar, run\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
+msgstr ""
+"如果è¦å¾ž Scalar 解除這個版本庫的註冊,請執行\n"
+"\tgit config --global --unset --fixed-value scalar.repo \"%s\""
#: scalar.c
msgid ""
@@ -24140,6 +25131,19 @@ msgstr "未知動作:%d"
#: sequencer.c
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 ""
+"手動解決所有è¡çªï¼ŒåŸ·è¡Œ \"git add/rm <è¡çªçš„æª”案>\" 標記\n"
+"è¡çªå·²è§£æ±ºï¼Œç„¶å¾ŒåŸ·è¡Œ \"git rebase --continue\"。您也å¯ä»¥åŸ·è¡Œ\n"
+"\"git rebase --skip\" 指令略éŽé€™å€‹æäº¤ã€‚如果想è¦çµ‚止執行並回到\n"
+"\"git rebase\" 執行之å‰çš„狀態,執行 \"git rebase --abort\"。"
+
+#: sequencer.c
+msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
@@ -24385,18 +25389,13 @@ msgstr "無效的作者身分 '%s'"
msgid "corrupt author: missing date information"
msgstr "作者資訊æå£žï¼šç¼ºå°‘日期資訊"
-#: sequencer.c t/helper/test-fast-rebase.c
+#: sequencer.c
#, c-format
msgid "could not update %s"
msgstr "ä¸èƒ½æ›´æ–° %s"
#: sequencer.c
#, c-format
-msgid "could not parse commit %s"
-msgstr "ä¸èƒ½è§£æžæäº¤ %s"
-
-#: sequencer.c
-#, c-format
msgid "could not parse parent commit %s"
msgstr "ä¸èƒ½è§£æžçˆ¶æäº¤ %s"
@@ -24482,11 +25481,6 @@ msgstr "%s:ä¸èƒ½è§£æžçˆ¶æäº¤ %s"
#: sequencer.c
#, c-format
-msgid "could not rename '%s' to '%s'"
-msgstr "ä¸èƒ½å°‡ '%s' 釿–°å‘½å為 '%s'"
-
-#: sequencer.c
-#, c-format
msgid "could not revert %s... %s"
msgstr "ä¸èƒ½é‚„原 %s... %s"
@@ -24513,12 +25507,12 @@ msgstr "git %sï¼šç„¡æ³•é‡æ–°æ•´ç†ç´¢å¼•"
#: sequencer.c
#, c-format
msgid "'%s' is not a valid label"
-msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„æ¨™ç±¤"
+msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„æ¨™ç±¤"
#: sequencer.c
#, c-format
msgid "'%s' is not a valid refname"
-msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„引用å稱"
+msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„引用å稱"
#: sequencer.c
#, c-format
@@ -24527,13 +25521,56 @@ msgstr "update-ref 需è¦å®Œå…¨é™å®šçš„引用å稱,比如:refs/heads/%s"
#: sequencer.c
#, c-format
-msgid "invalid command '%.*s'"
-msgstr "無效的命令 “%.*sâ€"
+msgid "'%s' does not accept merge commits"
+msgstr "「%sã€ä¸æŽ¥å—åˆä½µæäº¤"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"ä¸èƒ½ä½¿ç”¨ã€Œpickã€é¸æ“‡ä¸€å€‹åˆä½µæäº¤ã€‚\n"
+"如果你想è¦é‡æ”¾é€™å€‹åˆä½µï¼Œè«‹å°é€™å€‹æäº¤ä½¿ç”¨ã€Œmerge -Cã€ã€‚"
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"「rewordã€ä¸¦ç„¡æ³•使用åˆä½µæäº¤ä½œç‚ºåƒæ•¸ã€‚\n"
+"如果你希望åˆä½µä¸¦æ”¹å¯«æäº¤è¨Šæ¯ï¼Œ\n"
+"è«‹å°é€™å€‹æäº¤ä½¿ç”¨ã€Œmerge -cã€"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+#: sequencer.c
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"「editã€ä¸¦ç„¡æ³•使用åˆä½µæäº¤ä½œç‚ºåƒæ•¸ã€‚\n"
+"å¦‚æžœä½ å¸Œæœ›é‡æ”¾é€™å€‹åˆä½µï¼Œè«‹å°é€™å€‹æäº¤ä½¿ç”¨ã€Œmerge -Cã€ï¼Œ\n"
+"並使用「breakã€å–回控制權,\n"
+"這樣æ‰èƒ½åŸ·è¡Œã€Œgit commit --amend && git rebase --continueã€ã€‚"
+
+#: sequencer.c
+msgid "cannot squash merge commit into another commit"
+msgstr "無法將一個åˆä½µæäº¤å£“æ‰é€²å…¶ä»–æäº¤"
#: sequencer.c
#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s 䏿ޥå—åƒæ•¸ï¼š'%s'"
+msgid "invalid command '%.*s'"
+msgstr "無效的命令「%.*sã€"
#: sequencer.c
#, c-format
@@ -24680,9 +25717,8 @@ msgid "cannot read HEAD"
msgstr "ä¸èƒ½è®€å– HEAD"
#: sequencer.c
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "無法複製 '%s' 至 '%s'"
+msgid "could not write commit message file"
+msgstr "無法寫入æäº¤è¨Šæ¯æª”案"
#: sequencer.c
#, c-format
@@ -24809,7 +25845,7 @@ msgstr "åˆä½µï¼šç„¡æ³•寫入新索引檔案"
#, c-format
msgid ""
"another 'rebase' process appears to be running; '%s.lock' already exists"
-msgstr "似乎有å¦ä¸€å€‹ “rebaseâ€ ç¨‹åºæ­£åœ¨é€²è¡Œï¼›â€œ%s.lock†已經存在"
+msgstr "似乎有å¦ä¸€å€‹ã€Œrebaseã€ç¨‹åºæ­£åœ¨é€²è¡Œï¼›ã€Œ%s.lockã€å·²ç¶“存在"
#: sequencer.c
#, c-format
@@ -24882,6 +25918,10 @@ msgid "Autostash exists; creating a new stash entry."
msgstr "已有自動貯存;建立新貯存項目。"
#: sequencer.c
+msgid "autostash reference is a symref"
+msgstr "autostash 引用是符號引用"
+
+#: sequencer.c
msgid "could not detach HEAD"
msgstr "ä¸èƒ½åˆ†é›¢é–‹é ­æŒ‡æ¨™"
@@ -24917,13 +25957,13 @@ msgstr ""
#: sequencer.c
#, c-format
-msgid "Rebasing (%d/%d)%s"
-msgstr "正在é‡å®šåŸºåº• (%d/%d)%s"
+msgid "Stopped at %s... %.*s\n"
+msgstr "åœæ­¢åœ¨ %s... %.*s\n"
#: sequencer.c
#, c-format
-msgid "Stopped at %s... %.*s\n"
-msgstr "åœæ­¢åœ¨ %s... %.*s\n"
+msgid "Rebasing (%d/%d)%s"
+msgstr "正在é‡å®šåŸºåº• (%d/%d)%s"
#: sequencer.c
#, c-format
@@ -25083,6 +26123,11 @@ msgstr "無法使用無效設定來建立工作å€"
#: setup.c
#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "「%sã€å·²ç¶“指定為「%sã€"
+
+#: setup.c
+#, c-format
msgid "Expected git repo version <= %d, found %d"
msgstr "期望 git 版本庫版本 <= %d,å»å¾—到 %d"
@@ -25151,6 +26196,24 @@ msgid "failed to stat '%*s%s%s'"
msgstr "å–å¾— '%*s%s%s' 狀態(stat)失敗"
#: setup.c
+#, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory「%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"
+
+#: setup.c
msgid "Unable to read current working directory"
msgstr "ä¸èƒ½è®€å–ç›®å‰å·¥ä½œç›®éŒ„"
@@ -25175,21 +26238,8 @@ msgstr ""
#: 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â€ï¼‰"
+msgstr "無法使用「%sã€ç´”版本庫(safe.bareRepository 是「%sã€ï¼‰"
#: setup.c
#, c-format
@@ -25255,6 +26305,11 @@ msgstr "無效的åˆå§‹åˆ†æ”¯å稱:'%s'"
#: setup.c
#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: 忽略 --initial-branch=%s"
+
+#: setup.c
+#, c-format
msgid "unable to handle file type %d"
msgstr "ä¸èƒ½è™•ç† %d 類型的檔案"
@@ -25268,14 +26323,14 @@ msgid "attempt to reinitialize repository with different hash"
msgstr "嘗試以ä¸åŒçš„é›œæ¹Šå€¼é‡æ–°åˆå§‹åŒ–版本庫"
#: setup.c
-#, c-format
-msgid "%s already exists"
-msgstr "%s 已經存在"
+msgid ""
+"attempt to reinitialize repository with different reference storage format"
+msgstr "嘗試以ä¸åŒçš„引用儲存格å¼é‡æ–°åˆå§‹åŒ–版本庫"
#: setup.c
#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: 忽略 --initial-branch=%s"
+msgid "%s already exists"
+msgstr "%s 已經存在"
#: setup.c
#, c-format
@@ -25306,6 +26361,24 @@ msgstr "ç´¢å¼•é …ç›®æ˜¯è³‡æ–™å¤¾ï¼Œä½†ä¸æ˜¯ç¨€ç–資料夾(%08x)"
msgid "cannot use split index with a sparse index"
msgstr "無法在稀ç–索引使用索引分割"
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "無效的 %s æ ¼å¼ï¼šã€Œ%sã€å…ƒç´ çš„開頭䏿˜¯ã€Œ(ã€"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "無效的 %s æ ¼å¼ï¼šã€Œ%sã€å…ƒç´ çš„çµå°¾ä¸æ˜¯ã€Œ)ã€"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "無效的 %s æ ¼å¼ï¼š%%%.*s"
+
#. TRANSLATORS: IEC 80000-13:2008 gibibyte
#: strbuf.c
#, c-format
@@ -25527,6 +26600,16 @@ msgstr "「%sã€å­æ¨¡çµ„ git 目錄在「%.*sã€git 路徑中"
#: submodule.c
#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr "é æœŸã€Œ%.*sã€ï¼ˆä½æ–¼å­æ¨¡çµ„路徑「%sã€ï¼‰ä¸æ˜¯è±¡å¾µå¼é€£çµ"
+
+#: submodule.c
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "é æœŸå­æ¨¡çµ„路徑「%sã€ä¸æ˜¯è±¡å¾µå¼é€£çµ"
+
+#: submodule.c
+#, c-format
msgid ""
"relocate_gitdir for submodule '%s' with more than one worktree not supported"
msgstr "䏿”¯æ´å°æœ‰å¤šå€‹å·¥ä½œå€çš„å­æ¨¡çµ„ '%s' 執行 relocate_gitdir"
@@ -25564,18 +26647,13 @@ msgstr "ls-tree 返回未知返回值 %d"
#: symlinks.c
#, c-format
msgid "failed to lstat '%s'"
-msgstr "無法 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 清單"
@@ -25591,14 +26669,6 @@ msgstr "æ¯æ¬¡è¿­ä»£å‰æ¸…é™¤å¿«å–æ¨¹ç‹€ç‰©ä»¶"
msgid "number of entries in the cache tree to invalidate (default 0)"
msgstr "åœ¨å¿«å–æ¨¹ç‹€ç‰©ä»¶ä¸­ï¼Œè¦ä½¿å¤±æ•ˆçš„項目數é‡ï¼ˆé è¨­å€¼ç‚º 0)"
-#: t/helper/test-fast-rebase.c
-msgid "unhandled options"
-msgstr "未處ç†é¸é …"
-
-#: t/helper/test-fast-rebase.c
-msgid "error preparing revisions"
-msgstr "準備修訂版本時發生錯誤"
-
#: t/helper/test-reach.c
#, c-format
msgid "commit %s is not marked reachable"
@@ -25688,6 +26758,30 @@ msgstr "代符"
msgid "command token to send to the server"
msgstr "è¦å‚³é€è‡³ä¼ºæœå™¨çš„命令代符"
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<options>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "一旦有測試失敗就立刻退出"
+
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "åªåŸ·è¡Œæ¸¬è©¦å¥—件或單ç¨çš„æ¸¬è©¦ <suite[::test]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "suite"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "排除測試套件 <suite>"
+
#: trailer.c
#, c-format
msgid "running trailer command '%s' failed"
@@ -25703,35 +26797,6 @@ msgstr "éµ '%2$s' 的未知å–值 '%1$s'"
msgid "empty trailer token in trailer '%.*s'"
msgstr "ç°½å '%.*s' çš„éµç‚ºç©º"
-#: trailer.c
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "ä¸èƒ½è®€å–輸入檔案 '%s'"
-
-#: trailer.c wrapper.c
-#, c-format
-msgid "could not stat %s"
-msgstr "ä¸èƒ½å° %s å‘¼å« stat"
-
-#: trailer.c
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "檔案 %s 䏿˜¯ä¸€å€‹æ­£è¦æª”案"
-
-#: trailer.c
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "檔案 %s 使用者ä¸å¯å¯«"
-
-#: trailer.c
-msgid "could not open temporary file"
-msgstr "ä¸èƒ½é–‹å•Ÿæš«å­˜æª”"
-
-#: trailer.c
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "ä¸èƒ½é‡æ–°å‘½å暫存檔為 %s"
-
#: transport-helper.c
msgid "full write to remote helper failed"
msgstr "完整寫入é ç«¯å”助工具失敗"
@@ -25792,10 +26857,6 @@ msgstr "å”å®šä¸æ”¯æ´è¨­å®šé ç«¯æœå‹™è·¯å¾‘"
msgid "invalid remote service path"
msgstr "無效的é ç«¯æœå‹™è·¯å¾‘"
-#: transport-helper.c transport.c
-msgid "operation not supported by protocol"
-msgstr "å”å®šä¸æ”¯æ´è©²å‹•作"
-
#: transport-helper.c
#, c-format
msgid "can't connect to subservice %s"
@@ -25855,8 +26916,8 @@ msgstr "remote-heper 䏿”¯æ´ push,需è¦å¼•ç”¨è¦æ ¼"
#: transport-helper.c
#, c-format
-msgid "helper %s does not support 'force'"
-msgstr "å”助工具 %s 䏿”¯æ´ 'force'"
+msgid "helper %s does not support '--force'"
+msgstr "å”助工具 %s 䏿”¯æ´ã€Œ--forceã€"
#: transport-helper.c
msgid "couldn't run fast-export"
@@ -25961,11 +27022,6 @@ msgstr "å”定 v2 的支æ´å°šæœªå¯¦ç¾"
#: transport.c
#, c-format
-msgid "unknown value for config '%s': %s"
-msgstr "設定 '%s' çš„å–值未知:%s"
-
-#: transport.c
-#, c-format
msgid "transport '%s' not allowed"
msgstr "傳輸 '%s' ä¸å…許"
@@ -26023,6 +27079,10 @@ msgstr "通訊å”å®šä¸æ”¯æ´ bundle-uri 動作"
msgid "could not retrieve server-advertised bundle-uri list"
msgstr "無法å–得伺æœå™¨å…¬ä½ˆçš„ bundle-uri 清單"
+#: transport.c
+msgid "operation not supported by protocol"
+msgstr "å”å®šä¸æ”¯æ´è©²å‹•作"
+
#: tree-walk.c
msgid "too-short tree object"
msgstr "太短的樹狀物件"
@@ -26332,6 +27392,11 @@ msgid "invalid '..' path segment"
msgstr "無效的 '..' 路徑å€å¡Š"
#: usage.c
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "錯誤:無法格å¼åŒ–訊æ¯ï¼š%s\n"
+
+#: usage.c
msgid "usage: "
msgstr "用法: "
@@ -26475,6 +27540,10 @@ msgstr "ä¸èƒ½å­˜å– '%s'"
msgid "unable to get current working directory"
msgstr "ä¸èƒ½å–å¾—ç›®å‰å·¥ä½œç›®éŒ„"
+#: wrapper.c
+msgid "unable to get random bytes"
+msgstr "無法å–得隨機ä½å…ƒçµ„"
+
#: wt-status.c
msgid "Unmerged paths:"
msgstr "未åˆä½µçš„路徑:"
@@ -26950,7 +28019,7 @@ msgstr "列舉未追蹤檔案花費 %.2f 秒。"
#: wt-status.c
msgid "See 'git help status' for information on how to improve this."
-msgstr "è«‹åƒé–± “git help status†深入了解如何改善。"
+msgstr "è«‹åƒé–±ã€Œgit help statusã€æ·±å…¥äº†è§£å¦‚何改善。"
#: wt-status.c
#, c-format
@@ -27047,6 +28116,11 @@ msgstr "å¦å¤–ï¼Œæ‚¨çš„ç´¢å¼•ä¸­åŒ…å«æœªæäº¤çš„變更。"
msgid "cannot %s: Your index contains uncommitted changes."
msgstr "ä¸èƒ½%sï¼šæ‚¨çš„ç´¢å¼•ä¸­åŒ…å«æœªæäº¤çš„變更。"
+#: xdiff-interface.c
+#, c-format
+msgid "unknown style '%s' given for '%s'"
+msgstr "給予「%2$sã€çš„「%1$sã€æ¨£å¼æœªçŸ¥"
+
#: git-merge-octopus.sh git-merge-resolve.sh
msgid ""
"Error: Your local changes to the following files would be overwritten by "
@@ -27159,6 +28233,10 @@ msgid "--dump-aliases incompatible with other options\n"
msgstr "--dump-aliases 和其它é¸é …ä¸ç›¸å®¹\n"
#: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases 和 --translate-aliases 互斥\n"
+
+#: git-send-email.perl
msgid ""
"fatal: found configuration options for 'sendmail'\n"
"git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -27263,13 +28341,13 @@ msgstr ""
#: git-send-email.perl
#, perl-format
-msgid "Failed to open %s: %s"
-msgstr "無法開啟 %s: %s"
+msgid "Failed to open %s.final: %s"
+msgstr "無法開啟 %s.final: %s"
#: git-send-email.perl
#, perl-format
-msgid "Failed to open %s.final: %s"
-msgstr "無法開啟 %s.final: %s"
+msgid "Failed to open %s: %s"
+msgstr "無法開啟 %s: %s"
#: git-send-email.perl
msgid "Summary email is empty, skipping it\n"
@@ -27391,29 +28469,29 @@ msgstr "ç„¡æ³•å‚³é€ %s\n"
#: git-send-email.perl
#, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "æ¸¬è©¦åŸ·è¡Œå‚³é€ %s\n"
+msgid "Dry-Sent %s"
+msgstr "è©¦åŸ·è¡Œå‚³é€ %s"
#: git-send-email.perl
#, perl-format
-msgid "Sent %s\n"
-msgstr "æ­£å‚³é€ %s\n"
+msgid "Sent %s"
+msgstr "æ­£å‚³é€ %s"
#: git-send-email.perl
-msgid "Dry-OK. Log says:\n"
-msgstr "測試執行æˆåŠŸã€‚æ—¥èªŒèªªï¼š\n"
+msgid "Dry-OK. Log says:"
+msgstr "試執行æˆåŠŸã€‚æ—¥èªŒèªªï¼š"
#: git-send-email.perl
-msgid "OK. Log says:\n"
-msgstr "OK。日誌說:\n"
+msgid "OK. Log says:"
+msgstr "OK。日誌說:"
#: git-send-email.perl
msgid "Result: "
msgstr "çµæžœï¼š "
#: git-send-email.perl
-msgid "Result: OK\n"
-msgstr "çµæžœï¼šOK\n"
+msgid "Result: OK"
+msgstr "çµæžœï¼šOK"
#: git-send-email.perl
#, perl-format
@@ -27448,7 +28526,7 @@ msgstr "(%s) ä¸èƒ½åŸ·è¡Œ '%s'"
#: git-send-email.perl
#, perl-format
msgid "(%s) Malformed output from '%s'"
-msgstr "(%s) 從 “%s†讀到格å¼éŒ¯èª¤çš„輸出"
+msgstr "(%s) 從「%sã€è®€åˆ°æ ¼å¼éŒ¯èª¤çš„輸出"
#: git-send-email.perl
#, perl-format
@@ -27504,516 +28582,125 @@ 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_*() 的值作為離開碼"
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "ä¿®è¨‚ç‰ˆéæ­·è¨­å®šå¤±æ•—\n"
#, c-format
-#~ msgid ""
-#~ "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-#~ msgstr "é¸é …「--defaultã€é æœŸæ”¶åˆ°ã€Œ--type=boolã€çš„布林值,而éžã€Œ%sã€"
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "無法解æžè¯çµ¡åœ°å€ï¼š%s"
-#, c-format
#~ msgid ""
-#~ "option `--default' expects an unsigned long value with `--type=ulong`, "
-#~ "not `%s`"
+#~ "the add.interactive.useBuiltin setting has been removed!\n"
+#~ "See its entry in 'git help config' for details."
#~ msgstr ""
-#~ "é¸é …「--defaultã€é æœŸæ”¶åˆ°ã€Œ--type=ulongã€çš„無號 long 數值,而éžã€Œ%sã€"
-
-#~ msgid "please commit or stash them."
-#~ msgstr "è«‹æäº¤æˆ–貯存它們。"
+#~ "add.interactive.useBuiltin 設定已被移除ï¼\n"
+#~ "深入了解請åƒé–± “git help configâ€ ä¸­çš„å°æ‡‰æ¢ç›®ã€‚"
-#, 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 "git archive: Remote with no URL"
+#~ msgstr "git archive: 未æä¾›é ç«¯ URL"
-#~ msgid "corrupt tag"
-#~ msgstr "æå£žçš„æ¨™ç±¤"
+#~ msgid "only one action at a time"
+#~ msgstr "一次åªèƒ½æœ‰ä¸€å€‹å‹•作"
-#, c-format
-#~ msgid "%%(objecttype) does not take arguments"
-#~ msgstr "%%(objecttype) ä¸å¸¶åƒæ•¸"
-
-#, c-format
-#~ msgid "%%(deltabase) does not take arguments"
-#~ msgstr "%%(deltabase) ä¸å¸¶åƒæ•¸"
+#~ msgid "use [RFC PATCH] instead of [PATCH]"
+#~ msgstr "使用 [RFC PATCH] 代替 [PATCH]"
#, c-format
-#~ msgid "%%(body) does not take arguments"
-#~ msgstr "%%(body) ä¸å¸¶åƒæ•¸"
+#~ msgid "no URLs configured for remote '%s'"
+#~ msgstr "沒有給é ç«¯ç‰ˆæœ¬åº« '%s' 設定 URL"
#, c-format
-#~ msgid "unrecognized email option: %s"
-#~ msgstr "無法識別的 email é¸é …:%s"
-
-#~ msgid "could not lock HEAD"
-#~ msgstr "ä¸èƒ½éŽ–å®š HEAD"
+#~ msgid "remote '%s' has no configured URL"
+#~ msgstr "“%s†é ç«¯æœªè¨­å®š URL"
#, 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 "truncating .rej filename to %.*s.rej"
+#~ msgstr "正在將 .rej 檔案å稱截短為 %.*s.rej"
#~ 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"
+#~ "Use -f if you really want to add them.\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addIgnoredFile false\""
#~ msgstr ""
-#~ "y - 暫存此å€å¡Š\n"
-#~ "n - ä¸è¦æš«å­˜æ­¤å€å¡Š\n"
-#~ "q - é›¢é–‹ã€‚ä¸æš«å­˜æ­¤å€å¡ŠåŠå¾Œé¢çš„全部å€å¡Š\n"
-#~ "a - 暫存此å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š\n"
-#~ "d - 䏿š«å­˜æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#~ "若您真的想加入,請傳入 -f。\n"
+#~ "如è¦é—œé–‰æ­¤è¨Šæ¯ï¼Œè«‹åŸ·è¡Œ\n"
+#~ "“git config advice.addIgnoredFile falseâ€"
#~ 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"
+#~ "Maybe you wanted to say 'git add .'?\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addEmptyPathspec false\""
#~ msgstr ""
-#~ "y - 貯存此å€å¡Š\n"
-#~ "n - ä¸è¦è²¯å­˜æ­¤å€å¡Š\n"
-#~ "q - 離開。ä¸è²¯å­˜æ­¤å€å¡ŠåŠå¾Œé¢çš„全部å€å¡Š\n"
-#~ "a - 貯存此å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š\n"
-#~ "d - ä¸è²¯å­˜æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#~ "å¯èƒ½æ‚¨æƒ³åš “git add .â€ï¼Ÿ\n"
+#~ "如è¦é—œé–‰æ­¤è¨Šæ¯ï¼Œè«‹åŸ·è¡Œ\n"
+#~ "“git config advice.addEmptyPathspec falseâ€"
#~ 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"
+#~ "clean.requireForce defaults to true and neither -i, -n, nor -f given; "
+#~ "refusing to clean"
#~ msgstr ""
-#~ "y - 䏿š«å­˜æ­¤å€å¡Š\n"
-#~ "n - ä¸è¦ä¸æš«å­˜æ­¤å€å¡Š\n"
-#~ "q - 離開。ä¸è¦ä¸æš«å­˜æ­¤å€å¡ŠåŠå¾Œé¢çš„全部å€å¡Š\n"
-#~ "a - 䏿š«å­˜æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š\n"
-#~ "d - ä¸è¦ä¸æš«å­˜æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#~ "clean.requireForce é è¨­ç‚º true 且未æä¾› -iã€-n 或 -f é¸é …,拒絕執行清ç†å‹•"
+#~ "作"
-#~ 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 - ä¸è¦å¥—用此å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not start with '('"
+#~ msgstr "ls-files æ ¼å¼éŒ¯èª¤ï¼šâ€œ%s†元素ä¸ä»¥ “(†開頭"
-#~ 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 - ä¸è¦æ¨æ£„æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not end in ')'"
+#~ msgstr "ls-files æ ¼å¼éŒ¯èª¤ï¼šâ€œ%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"
-#~ msgstr ""
-#~ "y - 在索引和工作å€ä¸­æ¨æ£„æ­¤å€å¡Š\n"
-#~ "n - ä¸è¦åœ¨ç´¢å¼•和工作å€ä¸­æ¨æ£„æ­¤å€å¡Š\n"
-#~ "q - 離開。ä¸è¦æ¨æ£„æ­¤å€å¡ŠåŠå¾Œé¢çš„全部å€å¡Š\n"
-#~ "a - æ¨æ£„æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š\n"
-#~ "d - ä¸è¦æ¨æ£„æ­¤å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#, c-format
+#~ msgid "bad ls-files format: %%%.*s"
+#~ msgstr "ls-files æ ¼å¼éŒ¯èª¤ï¼š%%%.*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"
-#~ msgstr ""
-#~ "y - 在索引和工作å€ä¸­å¥—用此å€å¡Š\n"
-#~ "n - ä¸è¦åœ¨ç´¢å¼•和工作å€ä¸­å¥—用此å€å¡Š\n"
-#~ "q - 離開。ä¸è¦å¥—用此å€å¡ŠåŠå¾Œé¢çš„全部å€å¡Š\n"
-#~ "a - 套用此å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š\n"
-#~ "d - ä¸è¦å¥—用此å€å¡Šå’Œæœ¬æª”案中後é¢çš„全部å€å¡Š"
+#~ msgid "keep redundant, empty commits"
+#~ msgstr "ä¿æŒå¤šé¤˜çš„ã€ç©ºçš„æäº¤"
-#~ 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 "core.commentChar should only be one ASCII character"
+#~ msgstr "core.commentChar 應該是一個 ASCII 字元"
#~ 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"
+#~ "--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+#~ "exclude"
#~ 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"
+#~ "--bundle-uri 與 --depthã€--shallow-since å’Œ --shallow-exclude ä¸ç›¸å®¹"
-#~ 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 "--merge-base is incompatible with --stdin"
+#~ msgstr "--merge-base 與 --stdin ä¸ç›¸å®¹"
#~ 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"
+#~ "apply options are incompatible with rebase.autoSquash. Consider adding --"
+#~ "no-autosquash"
+#~ msgstr "apply é¸é …與 rebase.autoSquash ä¸ç›¸å®¹ã€‚請考慮加上 --no-autosquash"
-#~ msgid "missing --"
-#~ msgstr "缺少 --"
+#~ msgid "--exclude-hidden cannot be used together with --branches"
+#~ msgstr "--exclude-hidden 無法與 --branches åŒæ™‚使用"
-#, perl-format
-#~ msgid "unknown --patch mode: %s"
-#~ msgstr "未知的 --patch 模å¼ï¼š%s"
+#~ msgid "--exclude-hidden cannot be used together with --tags"
+#~ msgstr "--exclude-hidden 無法與 --tags åŒæ™‚使用"
-#, perl-format
-#~ msgid "invalid argument %s, expecting --"
-#~ msgstr "ç„¡æ•ˆçš„åƒæ•¸ %s,期望是 --"
+#~ msgid "--exclude-hidden cannot be used together with --remotes"
+#~ msgstr "--exclude-hidden 無法與 --remotes åŒæ™‚使用"
#, c-format
-#~ msgid "unable to normalize object directory: %s"
-#~ msgstr "無法è¦ç¯„化物件目錄: %s"
-
-#~ 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"
-#~ msgstr "啟動二分æœå°‹éŽç¨‹"
-
-#~ msgid "find the next bisection commit"
-#~ msgstr "尋找下一個二分æœå°‹æäº¤"
-
-#~ msgid "mark the state of ref (or refs)"
-#~ msgstr "標記 ref (或 refs) 的狀態"
-
-#~ 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"
-#~ msgstr "使用 <cmd>... 自動進行二分æœå°‹"
-
-#~ msgid "no log for BISECT_WRITE"
-#~ msgstr "BISECT_WRITE 無日誌"
-
-#~ msgid "Couldn't look up commit object for HEAD"
-#~ msgstr "無法查詢 HEAD 指å‘çš„æäº¤ç‰©ä»¶"
-
-#~ msgid "git bundle create [<options>] <file> <git-rev-list args>"
-#~ msgstr "git bundle create [<é¸é …>] <檔案> <git-rev-list åƒæ•¸>"
+#~ msgid "only one of '%s', '%s' or '%s' can be given"
+#~ msgstr "åªèƒ½å‚³å…¥ “%sâ€ã€â€œ%s†或 “%sâ€"
#, c-format
-#~ msgid "options '%s' and '%s %s' cannot be used together"
-#~ msgstr "「%sã€å’Œã€Œ%s %sã€é¸é …ä¸å¾—åŒæ™‚使用"
-
-#~ msgid "git commit [<options>] [--] <pathspec>..."
-#~ msgstr "git commit [<é¸é …>] [--] <è·¯å¾‘è¦æ ¼>..."
-
-#~ msgid "git fsck [<options>] [<object>...]"
-#~ msgstr "git fsck [<é¸é …>] [<物件>...]"
-
-#~ msgid "git fsmonitor--daemon stop"
-#~ msgstr "git fsmonitor--daemon stop"
-
-#~ msgid "git fsmonitor--daemon status"
-#~ msgstr "git fsmonitor--daemon status"
-
-#~ msgid "failed to run 'git config'"
-#~ msgstr "無法執行 ‘git config’"
-
-#, c-format
-#~ msgid "could not get 'onto': '%s'"
-#~ msgstr "無法å–å¾— 'onto':'%s'"
-
-#~ msgid "Could not resolve HEAD to a revision"
-#~ msgstr "無法將 HEAD è§£æžç‚ºä¸€å€‹ç‰ˆæœ¬"
+#~ msgid "'%s' and '%s' cannot be used together"
+#~ msgstr "ç„¡æ³•åŒæ™‚使用 “%s†和 “%sâ€"
#, c-format
-#~ msgid "missing required file: %s"
-#~ msgstr "ç¼ºå°‘å¿…è¦æª”案:%s"
-
-#~ msgid "git revert [<options>] <commit-ish>..."
-#~ msgstr "git revert [<é¸é …>] <æäº¤è™Ÿ>..."
-
-#~ msgid "git revert <subcommand>"
-#~ msgstr "git revert <å­æŒ‡ä»¤>"
-
-#~ msgid "git cherry-pick [<options>] <commit-ish>..."
-#~ msgstr "git cherry-pick [<é¸é …>] <æäº¤è™Ÿ>..."
-
-#~ msgid "git cherry-pick <subcommand>"
-#~ msgstr "git cherry-pick <å­æŒ‡ä»¤>"
-
-#~ msgid "git rm [<options>] [--] <file>..."
-#~ msgstr "git rm [<é¸é …>] [--] <檔案>..."
-
-#~ msgid "using --group=trailer with stdin is not supported"
-#~ msgstr "䏿”¯æ´åœ¨æ¨™æº–輸入使用 --group=trailer"
-
-#~ msgid "git stash show [<options>] [<stash>]"
-#~ msgstr "git stash show [<é¸é …>] [<stash>]"
-
-#~ msgid "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
-#~ msgstr "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
+#~ msgid "options '%s', and '%s' cannot be used together"
+#~ msgstr "ç„¡æ³•åŒæ™‚使用 “%s†和 “%s†é¸é …"
-#~ msgid ""
-#~ "git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\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>]"
-#~ msgstr ""
-#~ "git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ " [-u|--include-untracked] [-a|--all] [<消æ¯>]"
-
-#~ msgid "path into the working tree"
-#~ msgstr "到工作å€çš„路徑"
-
-#~ msgid "recurse into submodules"
-#~ msgstr "åœ¨å­æ¨¡çµ„中éžè¿´"
-
-#~ msgid "check if it is safe to write to the .gitmodules file"
-#~ msgstr "檢查寫入 .gitmodules 檔案是å¦å®‰å…¨"
-
-#~ msgid "unset the config in the .gitmodules file"
-#~ msgstr "å–æ¶ˆ .gitmodules 檔案中的設定"
-
-#~ msgid "git submodule--helper config --unset <name>"
-#~ msgstr "git submodule--helper config --unset <å稱>"
+#~ msgid "<commit-ish>"
+#~ msgstr "<æäº¤æŒ‡ç¤ºå…ƒ>"
#, c-format
-#~ msgid "'%s' is not a valid submodule--helper subcommand"
-#~ msgstr "'%s' 䏿˜¯ä¸€å€‹æœ‰æ•ˆçš„ submodule--helper å­æŒ‡ä»¤"
-
-#~ msgid "git upload-pack [<options>] <dir>"
-#~ msgstr "git upload-pack [<é¸é …>] <目錄>"
-
-#~ msgid "git worktree add [<options>] <path> [<commit-ish>]"
-#~ msgstr "git worktree add [<é¸é …>] <路徑> [<æäº¤>]"
+#~ msgid "%s is incompatible with %s"
+#~ msgstr "%s 與 %s ä¸ç›¸å®¹"
-#~ msgid "git worktree lock [<options>] <path>"
-#~ msgstr "git worktree lock [<é¸é …>] <路徑>"
+#~ msgid "unhandled options"
+#~ msgstr "未處ç†é¸é …"
diff --git a/preload-index.c b/preload-index.c
index e44530c80c..7926eb09a6 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -1,13 +1,16 @@
/*
* Copyright (C) 2008 Linus Torvalds
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "pathspec.h"
#include "dir.h"
#include "environment.h"
#include "fsmonitor.h"
#include "gettext.h"
-#include "config.h"
+#include "parse.h"
#include "preload-index.h"
#include "progress.h"
#include "read-cache.h"
diff --git a/pretty.c b/pretty.c
index 718530bbab..098378720a 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
@@ -61,8 +63,8 @@ static int git_pretty_formats_config(const char *var, const char *value,
void *cb UNUSED)
{
struct cmt_fmt_map *commit_format = NULL;
- const char *name;
- const char *fmt;
+ const char *name, *stripped;
+ char *fmt;
int i;
if (!skip_prefix(var, "pretty.", &name))
@@ -88,18 +90,28 @@ static int git_pretty_formats_config(const char *var, const char *value,
commit_formats_len++;
}
+ free((char *)commit_format->name);
commit_format->name = xstrdup(name);
commit_format->format = CMIT_FMT_USERFORMAT;
if (git_config_string(&fmt, var, value))
return -1;
- if (skip_prefix(fmt, "format:", &fmt))
+ free((char *)commit_format->user_format);
+ if (skip_prefix(fmt, "format:", &stripped)) {
commit_format->is_tformat = 0;
- else if (skip_prefix(fmt, "tformat:", &fmt) || strchr(fmt, '%'))
+ commit_format->user_format = xstrdup(stripped);
+ free(fmt);
+ } else if (skip_prefix(fmt, "tformat:", &stripped)) {
commit_format->is_tformat = 1;
- else
+ commit_format->user_format = xstrdup(stripped);
+ free(fmt);
+ } else if (strchr(fmt, '%')) {
+ commit_format->is_tformat = 1;
+ commit_format->user_format = fmt;
+ } else {
commit_format->is_alias = 1;
- commit_format->user_format = fmt;
+ commit_format->user_format = fmt;
+ }
return 0;
}
@@ -147,7 +159,7 @@ static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
for (i = 0; i < commit_formats_len; i++) {
size_t match_len;
- if (!starts_with(commit_formats[i].name, sought))
+ if (!istarts_with(commit_formats[i].name, sought))
continue;
match_len = strlen(commit_formats[i].name);
@@ -428,7 +440,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
}
const char *show_ident_date(const struct ident_split *ident,
- const struct date_mode *mode)
+ struct date_mode mode)
{
timestamp_t date = 0;
long tz = 0;
@@ -592,7 +604,7 @@ void pp_user_info(struct pretty_print_context *pp,
switch (pp->fmt) {
case CMIT_FMT_MEDIUM:
strbuf_addf(sb, "Date: %s\n",
- show_ident_date(&ident, &pp->date_mode));
+ show_ident_date(&ident, pp->date_mode));
break;
case CMIT_FMT_EMAIL:
case CMIT_FMT_MBOXRD:
@@ -601,7 +613,7 @@ void pp_user_info(struct pretty_print_context *pp,
break;
case CMIT_FMT_FULLER:
strbuf_addf(sb, "%sDate: %s\n", what,
- show_ident_date(&ident, &pp->date_mode));
+ show_ident_date(&ident, pp->date_mode));
break;
default:
/* notin' */
@@ -775,7 +787,7 @@ static int mailmap_name(const char **email, size_t *email_len,
static size_t format_person_part(struct strbuf *sb, char part,
const char *msg, int len,
- const struct date_mode *dmode)
+ struct date_mode dmode)
{
/* currently all placeholders have same length */
const int placeholder_len = 2;
@@ -1034,7 +1046,7 @@ static void rewrap_message_tail(struct strbuf *sb,
static int format_reflog_person(struct strbuf *sb,
char part,
struct reflog_walk_info *log,
- const struct date_mode *dmode)
+ struct date_mode dmode)
{
const char *ident;
@@ -1252,8 +1264,8 @@ 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)
+static struct strbuf *expand_string_arg(struct strbuf *sb,
+ const char *argval, size_t arglen)
{
char *fmt = xstrndup(argval, arglen);
const char *format = fmt;
@@ -1301,9 +1313,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)) {
- opts->separator = expand_separator(sepbuf, argval, arglen);
+ opts->separator = expand_string_arg(sepbuf, argval, arglen);
} else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
- opts->key_value_separator = expand_separator(kvsepbuf, argval, arglen);
+ opts->key_value_separator = expand_string_arg(kvsepbuf, argval, arglen);
} else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) &&
!match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) &&
!match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) &&
@@ -1321,7 +1333,7 @@ int format_set_trailers_options(struct process_trailer_options *opts,
static size_t parse_describe_args(const char *start, struct strvec *args)
{
struct {
- char *name;
+ const char *name;
enum {
DESCRIBE_ARG_BOOL,
DESCRIBE_ARG_INTEGER,
@@ -1384,6 +1396,44 @@ static size_t parse_describe_args(const char *start, struct strvec *args)
return arg - start;
}
+
+static int parse_decoration_option(const char **arg,
+ const char *name,
+ char **opt)
+{
+ const char *argval;
+ size_t arglen;
+
+ if (match_placeholder_arg_value(*arg, name, arg, &argval, &arglen)) {
+ struct strbuf sb = STRBUF_INIT;
+
+ expand_string_arg(&sb, argval, arglen);
+ *opt = strbuf_detach(&sb, NULL);
+ return 1;
+ }
+ return 0;
+}
+
+static void parse_decoration_options(const char **arg,
+ struct decoration_options *opts)
+{
+ while (parse_decoration_option(arg, "prefix", &opts->prefix) ||
+ parse_decoration_option(arg, "suffix", &opts->suffix) ||
+ parse_decoration_option(arg, "separator", &opts->separator) ||
+ parse_decoration_option(arg, "pointer", &opts->pointer) ||
+ parse_decoration_option(arg, "tag", &opts->tag))
+ ;
+}
+
+static void free_decoration_options(const struct decoration_options *opts)
+{
+ free(opts->prefix);
+ free(opts->suffix);
+ free(opts->separator);
+ free(opts->pointer);
+ free(opts->tag);
+}
+
static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
const char *placeholder,
void *context)
@@ -1537,11 +1587,18 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
strbuf_addstr(sb, get_revision_mark(NULL, commit));
return 1;
case 'd':
- format_decorations(sb, commit, c->auto_color);
+ format_decorations(sb, commit, c->auto_color, NULL);
return 1;
case 'D':
- format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
- return 1;
+ {
+ const struct decoration_options opts = {
+ .prefix = (char *) "",
+ .suffix = (char *) "",
+ };
+
+ format_decorations(sb, commit, c->auto_color, &opts);
+ return 1;
+ }
case 'S': /* tag/branch like --source */
if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
return 0;
@@ -1557,7 +1614,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
if (c->pretty_ctx->reflog_info)
get_reflog_selector(sb,
c->pretty_ctx->reflog_info,
- &c->pretty_ctx->date_mode,
+ c->pretty_ctx->date_mode,
c->pretty_ctx->date_mode_explicit,
(placeholder[1] == 'd'));
return 2;
@@ -1572,7 +1629,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
return format_reflog_person(sb,
placeholder[1],
c->pretty_ctx->reflog_info,
- &c->pretty_ctx->date_mode);
+ c->pretty_ctx->date_mode);
}
return 0; /* unknown %g placeholder */
case 'N':
@@ -1638,6 +1695,23 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
return 2;
}
+ if (skip_prefix(placeholder, "(decorate", &arg)) {
+ struct decoration_options opts = { NULL };
+ size_t ret = 0;
+
+ if (*arg == ':') {
+ arg++;
+ parse_decoration_options(&arg, &opts);
+ }
+ if (*arg == ')') {
+ format_decorations(sb, commit, c->auto_color, &opts);
+ ret = arg - placeholder + 1;
+ }
+
+ free_decoration_options(&opts);
+ return ret;
+ }
+
/* For the rest we have to parse the commit header. */
if (!c->commit_header_parsed) {
msg = c->message =
@@ -1650,11 +1724,11 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
case 'a': /* author ... */
return format_person_part(sb, placeholder[1],
msg + c->author.off, c->author.len,
- &c->pretty_ctx->date_mode);
+ c->pretty_ctx->date_mode);
case 'c': /* committer ... */
return format_person_part(sb, placeholder[1],
msg + c->committer.off, c->committer.len,
- &c->pretty_ctx->date_mode);
+ c->pretty_ctx->date_mode);
case 'e': /* encoding */
if (c->commit_encoding)
strbuf_addstr(sb, c->commit_encoding);
@@ -1697,11 +1771,12 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
goto trailer_out;
}
if (*arg == ')') {
- format_trailers_from_commit(sb, msg + c->subject_off, &opts);
+ format_trailers_from_commit(&opts, msg + c->subject_off, sb);
ret = arg - placeholder + 1;
}
trailer_out:
string_list_clear(&filter_list, 0);
+ strbuf_release(&kvsepbuf);
strbuf_release(&sepbuf);
return ret;
}
@@ -1899,6 +1974,10 @@ void userformat_find_requirements(const char *fmt, struct userformat_want *w)
case 'D':
w->decorate = 1;
break;
+ case '(':
+ if (starts_with(fmt + 1, "decorate"))
+ w->decorate = 1;
+ break;
}
}
}
@@ -1953,6 +2032,7 @@ void repo_format_commit_message(struct repository *r,
free(context.commit_encoding);
repo_unuse_commit_buffer(r, commit, context.message);
+ signature_check_clear(&context.signature_check);
}
static void pp_header(struct pretty_print_context *pp,
@@ -2011,11 +2091,11 @@ static void pp_header(struct pretty_print_context *pp,
}
}
-void pp_title_line(struct pretty_print_context *pp,
- const char **msg_p,
- struct strbuf *sb,
- const char *encoding,
- int need_8bit_cte)
+void pp_email_subject(struct pretty_print_context *pp,
+ const char **msg_p,
+ struct strbuf *sb,
+ const char *encoding,
+ int need_8bit_cte)
{
static const int max_length = 78; /* per rfc2047 */
struct strbuf title;
@@ -2025,19 +2105,14 @@ void pp_title_line(struct pretty_print_context *pp,
pp->preserve_subject ? "\n" : " ");
strbuf_grow(sb, title.len + 1024);
- if (pp->print_email_subject) {
- if (pp->rev)
- fmt_output_email_subject(sb, pp->rev);
- if (pp->encode_email_headers &&
- needs_rfc2047_encoding(title.buf, title.len))
- add_rfc2047(sb, title.buf, title.len,
- encoding, RFC2047_SUBJECT);
- else
- strbuf_add_wrapped_bytes(sb, title.buf, title.len,
+ fmt_output_email_subject(sb, pp->rev);
+ if (pp->encode_email_headers &&
+ needs_rfc2047_encoding(title.buf, title.len))
+ add_rfc2047(sb, title.buf, title.len,
+ encoding, RFC2047_SUBJECT);
+ else
+ strbuf_add_wrapped_bytes(sb, title.buf, title.len,
-last_line_length(sb), 1, max_length);
- } else {
- strbuf_addbuf(sb, &title);
- }
strbuf_addch(sb, '\n');
if (need_8bit_cte == 0) {
@@ -2060,9 +2135,8 @@ void pp_title_line(struct pretty_print_context *pp,
if (pp->after_subject) {
strbuf_addstr(sb, pp->after_subject);
}
- if (cmit_fmt_is_mail(pp->fmt)) {
- strbuf_addch(sb, '\n');
- }
+
+ strbuf_addch(sb, '\n');
if (pp->in_body_headers.nr) {
int i;
@@ -2132,7 +2206,7 @@ static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,
}
/*
- * pp_handle_indent() prints out the intendation, and
+ * pp_handle_indent() prints out the indentation, and
* the whole line (without the final newline), after
* de-tabifying.
*/
@@ -2254,7 +2328,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
}
pp_header(pp, encoding, commit, &msg, sb);
- if (pp->fmt != CMIT_FMT_ONELINE && !pp->print_email_subject) {
+ if (pp->fmt != CMIT_FMT_ONELINE && !cmit_fmt_is_mail(pp->fmt)) {
strbuf_addch(sb, '\n');
}
@@ -2262,8 +2336,11 @@ void pretty_print_commit(struct pretty_print_context *pp,
msg = skip_blank_lines(msg);
/* These formats treat the title line specially. */
- if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
- pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
+ if (pp->fmt == CMIT_FMT_ONELINE) {
+ msg = format_subject(sb, msg, " ");
+ strbuf_addch(sb, '\n');
+ } else if (cmit_fmt_is_mail(pp->fmt))
+ pp_email_subject(pp, &msg, sb, encoding, need_8bit_cte);
beginning_of_body = sb->len;
if (pp->fmt != CMIT_FMT_ONELINE)
diff --git a/pretty.h b/pretty.h
index 421209e9ec..df267afe4a 100644
--- a/pretty.h
+++ b/pretty.h
@@ -35,11 +35,10 @@ struct pretty_print_context {
*/
enum cmit_fmt fmt;
int abbrev;
- const char *after_subject;
+ char *after_subject;
int preserve_subject;
struct date_mode date_mode;
unsigned date_mode_explicit:1;
- int print_email_subject;
int expand_tabs_in_log;
int need_8bit_cte;
char *notes_message;
@@ -96,13 +95,13 @@ void pp_user_info(struct pretty_print_context *pp, const char *what,
const char *encoding);
/*
- * Format title line of commit message taken from "msg_p" and
+ * Format subject line of commit message taken from "msg_p" and
* put it into "sb".
* First line of "msg_p" is also affected.
*/
-void pp_title_line(struct pretty_print_context *pp, const char **msg_p,
- struct strbuf *sb, const char *encoding,
- int need_8bit_cte);
+void pp_email_subject(struct pretty_print_context *pp, const char **msg_p,
+ struct strbuf *sb, const char *encoding,
+ int need_8bit_cte);
/*
* Get current state of commit message from "msg_p" and continue formatting
@@ -168,7 +167,7 @@ int format_set_trailers_options(struct process_trailer_options *opts,
* a well-known sentinel date if they appear bogus.
*/
const char *show_ident_date(const struct ident_split *id,
- const struct date_mode *mode);
+ struct date_mode mode);
#endif /* PRETTY_H */
diff --git a/progress.c b/progress.c
index f695798aca..0d44c18edc 100644
--- a/progress.c
+++ b/progress.c
@@ -9,6 +9,8 @@
*/
#define GIT_TEST_PROGRESS_ONLY
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "pager.h"
#include "progress.h"
@@ -17,7 +19,7 @@
#include "trace.h"
#include "trace2.h"
#include "utf8.h"
-#include "config.h"
+#include "parse.h"
#define TP_IDX_MAX 8
diff --git a/promisor-remote.c b/promisor-remote.c
index 7faf33b4d7..9345ae3db2 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hex.h"
@@ -8,6 +10,7 @@
#include "transport.h"
#include "strvec.h"
#include "packfile.h"
+#include "environment.h"
struct promisor_remote_config {
struct promisor_remote *promisors;
@@ -22,9 +25,9 @@ static int fetch_objects(struct repository *repo,
struct child_process child = CHILD_PROCESS_INIT;
int i;
FILE *child_in;
+ int quiet;
- /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
- if (git_env_bool("GIT_NO_LAZY_FETCH", 0)) {
+ if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0)) {
static int warning_shown;
if (!warning_shown) {
warning_shown = 1;
@@ -41,6 +44,8 @@ static int fetch_objects(struct repository *repo,
"fetch", remote_name, "--no-tags",
"--no-write-fetch-head", "--recurse-submodules=no",
"--filter=blob:none", "--stdin", NULL);
+ if (!git_config_get_bool("promisor.quiet", &quiet) && quiet)
+ strvec_push(&child.args, "--quiet");
if (start_command(&child))
die(_("promisor-remote: unable to fork off fetch subprocess"));
child_in = xfdopen(child.in, "w");
@@ -149,6 +154,7 @@ static int promisor_remote_config(const char *var, const char *value,
if (!r)
return 0;
+ FREE_AND_NULL(r->partial_clone_filter);
return git_config_string(&r->partial_clone_filter, var, value);
}
@@ -184,6 +190,7 @@ void promisor_remote_clear(struct promisor_remote_config *config)
{
while (config->promisors) {
struct promisor_remote *r = config->promisors;
+ free(r->partial_clone_filter);
config->promisors = config->promisors->next;
free(r);
}
diff --git a/promisor-remote.h b/promisor-remote.h
index 2cb9eda9ea..88cb599c39 100644
--- a/promisor-remote.h
+++ b/promisor-remote.h
@@ -13,7 +13,7 @@ struct object_id;
*/
struct promisor_remote {
struct promisor_remote *next;
- const char *partial_clone_filter;
+ char *partial_clone_filter;
const char name[FLEX_ARRAY];
};
diff --git a/prompt.c b/prompt.c
index 3baa33f63d..f21c5bf1c7 100644
--- a/prompt.c
+++ b/prompt.c
@@ -1,5 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "config.h"
+#include "parse.h"
#include "environment.h"
#include "run-command.h"
#include "strbuf.h"
diff --git a/protocol-caps.c b/protocol-caps.c
index 808a68c974..855f279c2f 100644
--- a/protocol-caps.c
+++ b/protocol-caps.c
@@ -3,11 +3,11 @@
#include "gettext.h"
#include "hex.h"
#include "pkt-line.h"
-#include "strvec.h"
-#include "hash-ll.h"
+#include "hash.h"
#include "hex.h"
#include "object.h"
#include "object-store-ll.h"
+#include "repository.h"
#include "string-list.h"
#include "strbuf.h"
@@ -53,7 +53,7 @@ static void send_info(struct repository *r, struct packet_writer *writer,
struct object_id oid;
unsigned long object_size;
- if (get_oid_hex(oid_str, &oid) < 0) {
+ if (get_oid_hex_algop(oid_str, &oid, r->hash_algo) < 0) {
packet_writer_error(
writer,
"object-info: protocol error, expected to get oid, not '%s'",
diff --git a/protocol.c b/protocol.c
index 079ba75acf..bae7226ff4 100644
--- a/protocol.c
+++ b/protocol.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
diff --git a/protocol.h b/protocol.h
index de66bf80f8..1e574bbd80 100644
--- a/protocol.h
+++ b/protocol.h
@@ -18,7 +18,7 @@
* with Linus Torvalds <torvalds@osdl.org> as the point of
* contact. September 2005.
*
- * See http://www.iana.org/assignments/port-numbers
+ * See https://www.iana.org/assignments/port-numbers
*/
#define DEFAULT_GIT_PORT 9418
diff --git a/prune-packed.c b/prune-packed.c
index e54daf740a..2bb99c29df 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -1,10 +1,12 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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"
+#include "repository.h"
static struct progress *progress;
@@ -37,7 +39,7 @@ void prune_packed_objects(int opts)
if (opts & PRUNE_PACKED_VERBOSE)
progress = start_delayed_progress(_("Removing duplicate objects"), 256);
- for_each_loose_file_in_objdir(get_object_directory(),
+ for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
prune_object, NULL, prune_subdir, &opts);
/* Ensure we show 100% before finishing progress */
diff --git a/pseudo-merge.c b/pseudo-merge.c
new file mode 100644
index 0000000000..bb59965ed2
--- /dev/null
+++ b/pseudo-merge.c
@@ -0,0 +1,784 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "pseudo-merge.h"
+#include "date.h"
+#include "oid-array.h"
+#include "strbuf.h"
+#include "config.h"
+#include "string-list.h"
+#include "refs.h"
+#include "pack-bitmap.h"
+#include "commit.h"
+#include "alloc.h"
+#include "progress.h"
+#include "hex.h"
+
+#define DEFAULT_PSEUDO_MERGE_DECAY 1.0
+#define DEFAULT_PSEUDO_MERGE_MAX_MERGES 64
+#define DEFAULT_PSEUDO_MERGE_SAMPLE_RATE 1
+#define DEFAULT_PSEUDO_MERGE_THRESHOLD approxidate("1.week.ago")
+#define DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD approxidate("1.month.ago")
+#define DEFAULT_PSEUDO_MERGE_STABLE_SIZE 512
+
+static double gitexp(double base, int exp)
+{
+ double result = 1;
+ while (1) {
+ if (exp % 2)
+ result *= base;
+ exp >>= 1;
+ if (!exp)
+ break;
+ base *= base;
+ }
+ return result;
+}
+
+static uint32_t pseudo_merge_group_size(const struct pseudo_merge_group *group,
+ const struct pseudo_merge_matches *matches,
+ uint32_t i)
+{
+ double C = 0.0f;
+ uint32_t n;
+
+ /*
+ * The size of pseudo-merge groups decays according to a power series,
+ * which looks like:
+ *
+ * f(n) = C * n^-k
+ *
+ * , where 'n' is the n-th pseudo-merge group, 'f(n)' is its size, 'k'
+ * is the decay rate, and 'C' is a scaling value.
+ *
+ * The value of C depends on the number of groups, decay rate, and total
+ * number of commits. It is computed such that if there are M and N
+ * total groups and commits, respectively, that:
+ *
+ * N = f(0) + f(1) + ... f(M-1)
+ *
+ * Rearranging to isolate C, we get:
+ *
+ * N = \sum_{n=1}^M C / n^k
+ *
+ * N / C = \sum_{n=1}^M n^-k
+ *
+ * C = N / \sum_{n=1}^M n^-k
+ *
+ * For example, if we have a decay rate of 'k' being equal to 1.5, 'N'
+ * total commits equal to 10,000, and 'M' being equal to 6 groups, then
+ * the (rounded) group sizes are:
+ *
+ * { 5469, 1934, 1053, 684, 489, 372 }
+ *
+ * increasing the number of total groups, say to 10, scales the group
+ * sizes appropriately:
+ *
+ * { 5012, 1772, 964, 626, 448, 341, 271, 221, 186, 158 }
+ */
+ for (n = 0; n < group->max_merges; n++)
+ C += 1.0 / gitexp(n + 1, group->decay);
+ C = matches->unstable_nr / C;
+
+ return (uint32_t)((C / gitexp(i + 1, group->decay)) + 0.5);
+}
+
+static void pseudo_merge_group_init(struct pseudo_merge_group *group)
+{
+ memset(group, 0, sizeof(struct pseudo_merge_group));
+
+ strmap_init_with_options(&group->matches, NULL, 1);
+
+ group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
+ group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES;
+ group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
+ group->threshold = DEFAULT_PSEUDO_MERGE_THRESHOLD;
+ group->stable_threshold = DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD;
+ group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE;
+}
+
+void pseudo_merge_group_release(struct pseudo_merge_group *group)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+
+ regfree(group->pattern);
+ free(group->pattern);
+
+ strmap_for_each_entry(&group->matches, &iter, e) {
+ struct pseudo_merge_matches *matches = e->value;
+ free(matches->stable);
+ free(matches->unstable);
+ free(matches);
+ }
+ strmap_clear(&group->matches, 0);
+
+ free(group->merges);
+}
+
+static int pseudo_merge_config(const char *var, const char *value,
+ const struct config_context *ctx,
+ void *cb_data)
+{
+ struct string_list *list = cb_data;
+ struct string_list_item *item;
+ struct pseudo_merge_group *group;
+ struct strbuf buf = STRBUF_INIT;
+ const char *sub, *key;
+ size_t sub_len;
+ int ret = 0;
+
+ if (parse_config_key(var, "bitmappseudomerge", &sub, &sub_len, &key))
+ goto done;
+
+ if (!sub_len)
+ goto done;
+
+ strbuf_add(&buf, sub, sub_len);
+
+ item = string_list_lookup(list, buf.buf);
+ if (!item) {
+ item = string_list_insert(list, buf.buf);
+
+ item->util = xmalloc(sizeof(struct pseudo_merge_group));
+ pseudo_merge_group_init(item->util);
+ }
+
+ group = item->util;
+
+ if (!strcmp(key, "pattern")) {
+ struct strbuf re = STRBUF_INIT;
+
+ free(group->pattern);
+ if (*value != '^')
+ strbuf_addch(&re, '^');
+ strbuf_addstr(&re, value);
+
+ group->pattern = xcalloc(1, sizeof(regex_t));
+ if (regcomp(group->pattern, re.buf, REG_EXTENDED))
+ die(_("failed to load pseudo-merge regex for %s: '%s'"),
+ sub, re.buf);
+
+ strbuf_release(&re);
+ } else if (!strcmp(key, "decay")) {
+ group->decay = git_config_double(var, value, ctx->kvi);
+ if (group->decay < 0) {
+ warning(_("%s must be non-negative, using default"), var);
+ group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
+ }
+ } else if (!strcmp(key, "samplerate")) {
+ group->sample_rate = git_config_double(var, value, ctx->kvi);
+ if (!(0 <= group->sample_rate && group->sample_rate <= 1)) {
+ warning(_("%s must be between 0 and 1, using default"), var);
+ group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
+ }
+ } else if (!strcmp(key, "threshold")) {
+ if (git_config_expiry_date(&group->threshold, var, value)) {
+ ret = -1;
+ goto done;
+ }
+ } else if (!strcmp(key, "maxmerges")) {
+ group->max_merges = git_config_int(var, value, ctx->kvi);
+ if (group->max_merges < 0) {
+ warning(_("%s must be non-negative, using default"), var);
+ group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES;
+ }
+ } else if (!strcmp(key, "stablethreshold")) {
+ if (git_config_expiry_date(&group->stable_threshold, var, value)) {
+ ret = -1;
+ goto done;
+ }
+ } else if (!strcmp(key, "stablesize")) {
+ group->stable_size = git_config_int(var, value, ctx->kvi);
+ if (group->stable_size <= 0) {
+ warning(_("%s must be positive, using default"), var);
+ group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE;
+ }
+ }
+
+done:
+ strbuf_release(&buf);
+
+ return ret;
+}
+
+void load_pseudo_merges_from_config(struct repository *r,
+ struct string_list *list)
+{
+ struct string_list_item *item;
+
+ repo_config(r, pseudo_merge_config, list);
+
+ for_each_string_list_item(item, list) {
+ struct pseudo_merge_group *group = item->util;
+ if (!group->pattern)
+ die(_("pseudo-merge group '%s' missing required pattern"),
+ item->string);
+ if (group->threshold < group->stable_threshold)
+ die(_("pseudo-merge group '%s' has unstable threshold "
+ "before stable one"), item->string);
+ }
+}
+
+static int find_pseudo_merge_group_for_ref(const char *refname,
+ const char *referent UNUSED,
+ const struct object_id *oid,
+ int flags UNUSED,
+ void *_data)
+{
+ struct bitmap_writer *writer = _data;
+ struct object_id peeled;
+ struct commit *c;
+ uint32_t i;
+ int has_bitmap;
+
+ if (!peel_iterated_oid(the_repository, oid, &peeled))
+ oid = &peeled;
+
+ c = lookup_commit(the_repository, oid);
+ if (!c)
+ return 0;
+ if (!packlist_find(writer->to_pack, oid))
+ return 0;
+
+ has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, oid);
+
+ for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
+ struct pseudo_merge_group *group;
+ struct pseudo_merge_matches *matches;
+ struct strbuf group_name = STRBUF_INIT;
+ regmatch_t captures[16];
+ size_t j;
+
+ group = writer->pseudo_merge_groups.items[i].util;
+ if (regexec(group->pattern, refname, ARRAY_SIZE(captures),
+ captures, 0))
+ continue;
+
+ if (captures[ARRAY_SIZE(captures) - 1].rm_so != -1)
+ warning(_("pseudo-merge regex from config has too many capture "
+ "groups (max=%"PRIuMAX")"),
+ (uintmax_t)ARRAY_SIZE(captures) - 2);
+
+ for (j = !!group->pattern->re_nsub; j < ARRAY_SIZE(captures); j++) {
+ regmatch_t *match = &captures[j];
+ if (match->rm_so == -1)
+ continue;
+
+ if (group_name.len)
+ strbuf_addch(&group_name, '-');
+
+ strbuf_add(&group_name, refname + match->rm_so,
+ match->rm_eo - match->rm_so);
+ }
+
+ matches = strmap_get(&group->matches, group_name.buf);
+ if (!matches) {
+ matches = xcalloc(1, sizeof(*matches));
+ strmap_put(&group->matches, group_name.buf,
+ matches);
+ }
+
+ if (c->date <= group->stable_threshold) {
+ ALLOC_GROW(matches->stable, matches->stable_nr + 1,
+ matches->stable_alloc);
+ matches->stable[matches->stable_nr++] = c;
+ } else if (c->date <= group->threshold && !has_bitmap) {
+ ALLOC_GROW(matches->unstable, matches->unstable_nr + 1,
+ matches->unstable_alloc);
+ matches->unstable[matches->unstable_nr++] = c;
+ }
+
+ strbuf_release(&group_name);
+ }
+
+ return 0;
+}
+
+static struct commit *push_pseudo_merge(struct pseudo_merge_group *group)
+{
+ struct commit *merge;
+
+ ALLOC_GROW(group->merges, group->merges_nr + 1, group->merges_alloc);
+
+ merge = alloc_commit_node(the_repository);
+ merge->object.parsed = 1;
+ merge->object.flags |= BITMAP_PSEUDO_MERGE;
+
+ group->merges[group->merges_nr++] = merge;
+
+ return merge;
+}
+
+static struct pseudo_merge_commit_idx *pseudo_merge_idx(kh_oid_map_t *pseudo_merge_commits,
+ const struct object_id *oid)
+
+{
+ struct pseudo_merge_commit_idx *pmc;
+ int hash_ret;
+ khiter_t hash_pos = kh_put_oid_map(pseudo_merge_commits, *oid,
+ &hash_ret);
+
+ if (hash_ret) {
+ CALLOC_ARRAY(pmc, 1);
+ kh_value(pseudo_merge_commits, hash_pos) = pmc;
+ } else {
+ pmc = kh_value(pseudo_merge_commits, hash_pos);
+ }
+
+ return pmc;
+}
+
+#define MIN_PSEUDO_MERGE_SIZE 8
+
+static void select_pseudo_merges_1(struct bitmap_writer *writer,
+ struct pseudo_merge_group *group,
+ struct pseudo_merge_matches *matches)
+{
+ uint32_t i, j;
+ uint32_t stable_merges_nr;
+
+ if (!matches->stable_nr && !matches->unstable_nr)
+ return; /* all tips in this group already have bitmaps */
+
+ stable_merges_nr = matches->stable_nr / group->stable_size;
+ if (matches->stable_nr % group->stable_size)
+ stable_merges_nr++;
+
+ /* make stable_merges_nr pseudo merges for stable commits */
+ for (i = 0, j = 0; i < stable_merges_nr; i++) {
+ struct commit *merge;
+ struct commit_list **p;
+
+ merge = push_pseudo_merge(group);
+ p = &merge->parents;
+
+ /*
+ * For each pseudo-merge created above, add parents to the
+ * allocated commit node from the stable set of commits
+ * (un-bitmapped, newer than the stable threshold).
+ */
+ do {
+ struct commit *c;
+ struct pseudo_merge_commit_idx *pmc;
+
+ if (j >= matches->stable_nr)
+ break;
+
+ c = matches->stable[j++];
+ /*
+ * Here and below, make sure that we keep our mapping of
+ * commits -> pseudo-merge(s) which include the key'd
+ * commit up-to-date.
+ */
+ pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
+ &c->object.oid);
+
+ ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
+
+ pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
+ p = commit_list_append(c, p);
+ } while (j % group->stable_size);
+
+ if (merge->parents) {
+ bitmap_writer_push_commit(writer, merge, 1);
+ writer->pseudo_merges_nr++;
+ }
+ }
+
+ /* make up to group->max_merges pseudo merges for unstable commits */
+ for (i = 0, j = 0; i < group->max_merges; i++) {
+ struct commit *merge;
+ struct commit_list **p;
+ uint32_t size, end;
+
+ merge = push_pseudo_merge(group);
+ p = &merge->parents;
+
+ size = pseudo_merge_group_size(group, matches, i);
+ end = size < MIN_PSEUDO_MERGE_SIZE ? matches->unstable_nr : j + size;
+
+ /*
+ * For each pseudo-merge commit created above, add parents to
+ * the allocated commit node from the unstable set of commits
+ * (newer than the stable threshold).
+ *
+ * Account for the sample rate, since not every candidate from
+ * the set of stable commits will be included as a pseudo-merge
+ * parent.
+ */
+ for (; j < end && j < matches->unstable_nr; j++) {
+ struct commit *c = matches->unstable[j];
+ struct pseudo_merge_commit_idx *pmc;
+
+ if (j % (uint32_t)(1.0 / group->sample_rate))
+ continue;
+
+ pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
+ &c->object.oid);
+
+ ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
+
+ pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
+ p = commit_list_append(c, p);
+ }
+
+ if (merge->parents) {
+ bitmap_writer_push_commit(writer, merge, 1);
+ writer->pseudo_merges_nr++; }
+ if (end >= matches->unstable_nr)
+ break;
+ }
+}
+
+static int commit_date_cmp(const void *va, const void *vb)
+{
+ timestamp_t a = (*(const struct commit **)va)->date;
+ timestamp_t b = (*(const struct commit **)vb)->date;
+
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ return 0;
+}
+
+static void sort_pseudo_merge_matches(struct pseudo_merge_matches *matches)
+{
+ QSORT(matches->stable, matches->stable_nr, commit_date_cmp);
+ QSORT(matches->unstable, matches->unstable_nr, commit_date_cmp);
+}
+
+void select_pseudo_merges(struct bitmap_writer *writer)
+{
+ struct progress *progress = NULL;
+ uint32_t i;
+
+ if (!writer->pseudo_merge_groups.nr)
+ return;
+
+ if (writer->show_progress)
+ progress = start_progress("Selecting pseudo-merge commits",
+ writer->pseudo_merge_groups.nr);
+
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ find_pseudo_merge_group_for_ref, writer);
+
+ for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
+ struct pseudo_merge_group *group;
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+
+ group = writer->pseudo_merge_groups.items[i].util;
+ strmap_for_each_entry(&group->matches, &iter, e) {
+ struct pseudo_merge_matches *matches = e->value;
+
+ sort_pseudo_merge_matches(matches);
+
+ select_pseudo_merges_1(writer, group, matches);
+ }
+
+ display_progress(progress, i + 1);
+ }
+
+ stop_progress(&progress);
+}
+
+void free_pseudo_merge_map(struct pseudo_merge_map *pm)
+{
+ uint32_t i;
+ for (i = 0; i < pm->nr; i++) {
+ ewah_pool_free(pm->v[i].commits);
+ ewah_pool_free(pm->v[i].bitmap);
+ }
+ free(pm->v);
+}
+
+struct pseudo_merge_commit_ext {
+ uint32_t nr;
+ const unsigned char *ptr;
+};
+
+static int pseudo_merge_ext_at(const struct pseudo_merge_map *pm,
+ struct pseudo_merge_commit_ext *ext, size_t at)
+{
+ if (at >= pm->map_size)
+ return error(_("extended pseudo-merge read out-of-bounds "
+ "(%"PRIuMAX" >= %"PRIuMAX")"),
+ (uintmax_t)at, (uintmax_t)pm->map_size);
+ if (at + 4 >= pm->map_size)
+ return error(_("extended pseudo-merge entry is too short "
+ "(%"PRIuMAX" >= %"PRIuMAX")"),
+ (uintmax_t)(at + 4), (uintmax_t)pm->map_size);
+
+ ext->nr = get_be32(pm->map + at);
+ ext->ptr = pm->map + at + sizeof(uint32_t);
+
+ return 0;
+}
+
+struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm,
+ struct pseudo_merge *merge)
+{
+ if (!merge->loaded_commits)
+ BUG("cannot use unloaded pseudo-merge bitmap");
+
+ if (!merge->loaded_bitmap) {
+ size_t at = merge->bitmap_at;
+
+ merge->bitmap = read_bitmap(pm->map, pm->map_size, &at);
+ merge->loaded_bitmap = 1;
+ }
+
+ return merge->bitmap;
+}
+
+struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm,
+ struct pseudo_merge *merge)
+{
+ if (!merge->loaded_commits) {
+ size_t pos = merge->at;
+
+ merge->commits = read_bitmap(pm->map, pm->map_size, &pos);
+ merge->bitmap_at = pos;
+ merge->loaded_commits = 1;
+ }
+ return merge;
+}
+
+static struct pseudo_merge *pseudo_merge_at(const struct pseudo_merge_map *pm,
+ struct object_id *oid,
+ size_t want)
+{
+ size_t lo = 0;
+ size_t hi = pm->nr;
+
+ while (lo < hi) {
+ size_t mi = lo + (hi - lo) / 2;
+ size_t got = pm->v[mi].at;
+
+ if (got == want)
+ return use_pseudo_merge(pm, &pm->v[mi]);
+ else if (got < want)
+ hi = mi;
+ else
+ lo = mi + 1;
+ }
+
+ warning(_("could not find pseudo-merge for commit %s at offset %"PRIuMAX),
+ oid_to_hex(oid), (uintmax_t)want);
+
+ return NULL;
+}
+
+struct pseudo_merge_commit {
+ uint32_t commit_pos;
+ uint64_t pseudo_merge_ofs;
+};
+
+#define PSEUDO_MERGE_COMMIT_RAWSZ (sizeof(uint32_t)+sizeof(uint64_t))
+
+static void read_pseudo_merge_commit_at(struct pseudo_merge_commit *merge,
+ const unsigned char *at)
+{
+ merge->commit_pos = get_be32(at);
+ merge->pseudo_merge_ofs = get_be64(at + sizeof(uint32_t));
+}
+
+static int nth_pseudo_merge_ext(const struct pseudo_merge_map *pm,
+ struct pseudo_merge_commit_ext *ext,
+ struct pseudo_merge_commit *merge,
+ uint32_t n)
+{
+ size_t ofs;
+
+ if (n >= ext->nr)
+ return error(_("extended pseudo-merge lookup out-of-bounds "
+ "(%"PRIu32" >= %"PRIu32")"), n, ext->nr);
+
+ ofs = get_be64(ext->ptr + st_mult(n, sizeof(uint64_t)));
+ if (ofs >= pm->map_size)
+ return error(_("out-of-bounds read: (%"PRIuMAX" >= %"PRIuMAX")"),
+ (uintmax_t)ofs, (uintmax_t)pm->map_size);
+
+ read_pseudo_merge_commit_at(merge, pm->map + ofs);
+
+ return 0;
+}
+
+static unsigned apply_pseudo_merge(const struct pseudo_merge_map *pm,
+ struct pseudo_merge *merge,
+ struct bitmap *result,
+ struct bitmap *roots)
+{
+ if (merge->satisfied)
+ return 0;
+
+ if (!ewah_bitmap_is_subset(merge->commits, roots ? roots : result))
+ return 0;
+
+ bitmap_or_ewah(result, pseudo_merge_bitmap(pm, merge));
+ if (roots)
+ bitmap_or_ewah(roots, pseudo_merge_bitmap(pm, merge));
+ merge->satisfied = 1;
+
+ return 1;
+}
+
+static int pseudo_merge_commit_cmp(const void *va, const void *vb)
+{
+ struct pseudo_merge_commit merge;
+ uint32_t key = *(uint32_t*)va;
+
+ read_pseudo_merge_commit_at(&merge, vb);
+
+ if (key < merge.commit_pos)
+ return -1;
+ if (key > merge.commit_pos)
+ return 1;
+ return 0;
+}
+
+static struct pseudo_merge_commit *find_pseudo_merge(const struct pseudo_merge_map *pm,
+ uint32_t pos)
+{
+ if (!pm->commits_nr)
+ return NULL;
+
+ return bsearch(&pos, pm->commits, pm->commits_nr,
+ PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp);
+}
+
+int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
+ struct bitmap *result,
+ struct commit *commit, uint32_t commit_pos)
+{
+ struct pseudo_merge *merge;
+ struct pseudo_merge_commit *merge_commit;
+ int ret = 0;
+
+ merge_commit = find_pseudo_merge(pm, commit_pos);
+ if (!merge_commit)
+ return 0;
+
+ if (merge_commit->pseudo_merge_ofs & ((uint64_t)1<<63)) {
+ struct pseudo_merge_commit_ext ext = { 0 };
+ off_t ofs = merge_commit->pseudo_merge_ofs & ~((uint64_t)1<<63);
+ uint32_t i;
+
+ if (pseudo_merge_ext_at(pm, &ext, ofs) < -1) {
+ warning(_("could not read extended pseudo-merge table "
+ "for commit %s"),
+ oid_to_hex(&commit->object.oid));
+ return ret;
+ }
+
+ for (i = 0; i < ext.nr; i++) {
+ if (nth_pseudo_merge_ext(pm, &ext, merge_commit, i) < 0)
+ return ret;
+
+ merge = pseudo_merge_at(pm, &commit->object.oid,
+ merge_commit->pseudo_merge_ofs);
+
+ if (!merge)
+ return ret;
+
+ if (apply_pseudo_merge(pm, merge, result, NULL))
+ ret++;
+ }
+ } else {
+ merge = pseudo_merge_at(pm, &commit->object.oid,
+ merge_commit->pseudo_merge_ofs);
+
+ if (!merge)
+ return ret;
+
+ if (apply_pseudo_merge(pm, merge, result, NULL))
+ ret++;
+ }
+
+ if (ret)
+ cascade_pseudo_merges(pm, result, NULL);
+
+ return ret;
+}
+
+int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
+ struct bitmap *result,
+ struct bitmap *roots)
+{
+ unsigned any_satisfied;
+ int ret = 0;
+
+ do {
+ struct pseudo_merge *merge;
+ uint32_t i;
+
+ any_satisfied = 0;
+
+ for (i = 0; i < pm->nr; i++) {
+ merge = use_pseudo_merge(pm, &pm->v[i]);
+ if (apply_pseudo_merge(pm, merge, result, roots)) {
+ any_satisfied |= 1;
+ ret++;
+ }
+ }
+ } while (any_satisfied);
+
+ return ret;
+}
+
+struct pseudo_merge *pseudo_merge_for_parents(const struct pseudo_merge_map *pm,
+ struct bitmap *parents)
+{
+ struct pseudo_merge *match = NULL;
+ size_t i;
+
+ if (!pm->nr)
+ return NULL;
+
+ /*
+ * NOTE: this loop is quadratic in the worst-case (where no
+ * matching pseudo-merge bitmaps are found), but in practice
+ * this is OK for a few reasons:
+ *
+ * - Rejecting pseudo-merge bitmaps that do not match the
+ * given commit is done quickly (i.e. `bitmap_equals_ewah()`
+ * returns early when we know the two bitmaps aren't equal.
+ *
+ * - Already matched pseudo-merge bitmaps (which we track with
+ * the `->satisfied` bit here) are skipped as potential
+ * candidates.
+ *
+ * - The number of pseudo-merges should be small (in the
+ * hundreds for most repositories).
+ *
+ * If in the future this semi-quadratic behavior does become a
+ * problem, another approach would be to keep track of which
+ * pseudo-merges are still "viable" after enumerating the
+ * pseudo-merge commit's parents:
+ *
+ * - A pseudo-merge bitmap becomes non-viable when the bit(s)
+ * corresponding to one or more parent(s) of the given
+ * commit are not set in a candidate pseudo-merge's commits
+ * bitmap.
+ *
+ * - After processing all bits, enumerate the remaining set of
+ * viable pseudo-merge bitmaps, and check that their
+ * popcount() matches the number of parents in the given
+ * commit.
+ */
+ for (i = 0; i < pm->nr; i++) {
+ struct pseudo_merge *candidate = use_pseudo_merge(pm, &pm->v[i]);
+ if (!candidate || candidate->satisfied)
+ continue;
+ if (!bitmap_equals_ewah(parents, candidate->commits))
+ continue;
+
+ match = candidate;
+ match->satisfied = 1;
+ break;
+ }
+
+ return match;
+}
diff --git a/pseudo-merge.h b/pseudo-merge.h
new file mode 100644
index 0000000000..29df8a32ec
--- /dev/null
+++ b/pseudo-merge.h
@@ -0,0 +1,218 @@
+#ifndef PSEUDO_MERGE_H
+#define PSEUDO_MERGE_H
+
+#include "git-compat-util.h"
+#include "strmap.h"
+#include "khash.h"
+#include "ewah/ewok.h"
+
+struct commit;
+struct string_list;
+struct bitmap_index;
+struct bitmap_writer;
+struct repository;
+
+/*
+ * A pseudo-merge group tracks the set of non-bitmapped reference tips
+ * that match the given pattern.
+ *
+ * Within those matches, they are further segmented by separating
+ * consecutive capture groups with '-' dash character capture groups
+ * with '-' dash characters.
+ *
+ * Those groups are then ordered by committer date and partitioned
+ * into individual pseudo-merge(s) according to the decay, max_merges,
+ * sample_rate, and threshold parameters.
+ */
+struct pseudo_merge_group {
+ regex_t *pattern;
+
+ /* capture group(s) -> struct pseudo_merge_matches */
+ struct strmap matches;
+
+ /*
+ * The individual pseudo-merge(s) that are generated from the
+ * above array of matches, partitioned according to the below
+ * parameters.
+ */
+ struct commit **merges;
+ size_t merges_nr;
+ size_t merges_alloc;
+
+ /*
+ * Pseudo-merge grouping parameters. See git-config(1) for
+ * more information.
+ */
+ double decay;
+ int max_merges;
+ double sample_rate;
+ int stable_size;
+ timestamp_t threshold;
+ timestamp_t stable_threshold;
+};
+
+void pseudo_merge_group_release(struct pseudo_merge_group *group);
+
+struct pseudo_merge_matches {
+ struct commit **stable;
+ struct commit **unstable;
+ size_t stable_nr, stable_alloc;
+ size_t unstable_nr, unstable_alloc;
+};
+
+/*
+ * Read the repository's configuration:
+ *
+ * - bitmapPseudoMerge.<name>.pattern
+ * - bitmapPseudoMerge.<name>.decay
+ * - bitmapPseudoMerge.<name>.sampleRate
+ * - bitmapPseudoMerge.<name>.threshold
+ * - bitmapPseudoMerge.<name>.maxMerges
+ * - bitmapPseudoMerge.<name>.stableThreshold
+ * - bitmapPseudoMerge.<name>.stableSize
+ *
+ * and populates the given `list` with pseudo-merge groups. String
+ * entry keys are the pseudo-merge group names, and the values are
+ * pointers to the pseudo_merge_group structure itself.
+ */
+void load_pseudo_merges_from_config(struct repository *r, struct string_list *list);
+
+/*
+ * A pseudo-merge commit index (pseudo_merge_commit_idx) maps a
+ * particular (non-pseudo-merge) commit to the list of pseudo-merge(s)
+ * it appears in.
+ */
+struct pseudo_merge_commit_idx {
+ uint32_t *pseudo_merge;
+ size_t nr, alloc;
+};
+
+/*
+ * Selects pseudo-merges from a list of commits, populating the given
+ * string_list of pseudo-merge groups.
+ *
+ * Populates the pseudo_merge_commits map with a commit_idx
+ * corresponding to each commit in the list. Counts the total number
+ * of pseudo-merges generated.
+ *
+ * Optionally shows a progress meter.
+ */
+void select_pseudo_merges(struct bitmap_writer *writer);
+
+/*
+ * Represents a serialized view of a file containing pseudo-merge(s)
+ * (see Documentation/technical/bitmap-format.txt for a specification
+ * of the format).
+ */
+struct pseudo_merge_map {
+ /*
+ * An array of pseudo-merge(s), lazily loaded from the .bitmap
+ * file.
+ */
+ struct pseudo_merge *v;
+ size_t nr;
+ size_t commits_nr;
+
+ /*
+ * Pointers into a memory-mapped view of the .bitmap file:
+ *
+ * - map: the beginning of the .bitmap file
+ * - commits: the beginning of the pseudo-merge commit index
+ * - map_size: the size of the .bitmap file
+ */
+ const unsigned char *map;
+ const unsigned char *commits;
+
+ size_t map_size;
+};
+
+/*
+ * An individual pseudo-merge, storing a pair of lazily-loaded
+ * bitmaps:
+ *
+ * - commits: the set of commit(s) that are part of the pseudo-merge
+ * - bitmap: the set of object(s) reachable from the above set of
+ * commits.
+ *
+ * The `at` and `bitmap_at` fields are used to store the locations of
+ * each of the above bitmaps in the .bitmap file.
+ */
+struct pseudo_merge {
+ struct ewah_bitmap *commits;
+ struct ewah_bitmap *bitmap;
+
+ off_t at;
+ off_t bitmap_at;
+
+ /*
+ * `satisfied` indicates whether the given pseudo-merge has been
+ * used.
+ *
+ * `loaded_commits` and `loaded_bitmap` indicate whether the
+ * respective bitmaps have been loaded and read from the
+ * .bitmap file.
+ */
+ unsigned satisfied : 1,
+ loaded_commits : 1,
+ loaded_bitmap : 1;
+};
+
+/*
+ * Frees the given pseudo-merge map, releasing any memory held by (a)
+ * parsed EWAH bitmaps, or (b) the array of pseudo-merges itself. Does
+ * not free the memory-mapped view of the .bitmap file.
+ */
+void free_pseudo_merge_map(struct pseudo_merge_map *pm);
+
+/*
+ * Loads the bitmap corresponding to the given pseudo-merge from the
+ * map, if it has not already been loaded.
+ */
+struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm,
+ struct pseudo_merge *merge);
+
+/*
+ * Loads the pseudo-merge and its commits bitmap from the given
+ * pseudo-merge map, if it has not already been loaded.
+ */
+struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm,
+ struct pseudo_merge *merge);
+
+/*
+ * Applies pseudo-merge(s) containing the given commit to the bitmap
+ * "result".
+ *
+ * If any pseudo-merge(s) were satisfied, returns the number
+ * satisfied, otherwise returns 0. If any were satisfied, the
+ * remaining unsatisfied pseudo-merges are cascaded (see below).
+ */
+int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
+ struct bitmap *result,
+ struct commit *commit, uint32_t commit_pos);
+
+/*
+ * Applies pseudo-merge(s) which are satisfied according to the
+ * current bitmap in result (or roots, see below). If any
+ * pseudo-merges were satisfied, repeat the process over unsatisfied
+ * pseudo-merge commits until no more pseudo-merges are satisfied.
+ *
+ * Result is the bitmap to which the pseudo-merge(s) are applied.
+ * Roots (if given) is a bitmap of the traversal tip(s) for either
+ * side of a reachability traversal.
+ *
+ * Roots may given instead of a populated results bitmap at the
+ * beginning of a traversal on either side where the reachability
+ * closure over tips is not yet known.
+ */
+int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
+ struct bitmap *result,
+ struct bitmap *roots);
+
+/*
+ * Returns a pseudo-merge which contains the exact set of commits
+ * listed in the "parents" bitamp, or NULL if none could be found.
+ */
+struct pseudo_merge *pseudo_merge_for_parents(const struct pseudo_merge_map *pm,
+ struct bitmap *parents);
+
+#endif
diff --git a/range-diff.c b/range-diff.c
index ca5493984a..10885ba301 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@@ -60,7 +62,7 @@ static int read_patches(const char *range, struct string_list *list,
"--output-indicator-context=#",
"--no-abbrev-commit",
"--pretty=medium",
- "--notes",
+ "--show-notes-by-default",
NULL);
strvec_push(&cp.args, range);
if (other_arg)
@@ -448,8 +450,10 @@ static void output_pair_header(struct diff_options *diffopt,
}
static struct userdiff_driver section_headers = {
- .funcname = { "^ ## (.*) ##$\n"
- "^.?@@ (.*)$", REG_EXTENDED }
+ .funcname = {
+ .pattern = "^ ## (.*) ##$\n^.?@@ (.*)$",
+ .cflags = REG_EXTENDED,
+ },
};
static struct diff_filespec *get_filespec(const char *name, const char *p)
@@ -476,7 +480,7 @@ static void patch_diff(const char *a, const char *b,
diff_flush(diffopt);
}
-static struct strbuf *output_prefix_cb(struct diff_options *opt UNUSED, void *data)
+static const char *output_prefix_cb(struct diff_options *opt UNUSED, void *data)
{
return data;
}
@@ -504,7 +508,7 @@ static void output(struct string_list *a, struct string_list *b,
opts.flags.suppress_hunk_header_line_count = 1;
opts.output_prefix = output_prefix_cb;
strbuf_addstr(&indent, " ");
- opts.output_prefix_data = &indent;
+ opts.output_prefix_data = indent.buf;
diff_setup_done(&opts);
/*
diff --git a/range-diff.h b/range-diff.h
index 04ffe217be..2f69f6a434 100644
--- a/range-diff.h
+++ b/range-diff.h
@@ -6,6 +6,12 @@
#define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60
+/*
+ * A much higher value than the default, when we KNOW we are comparing
+ * the same series (e.g., used when format-patch calls range-diff).
+ */
+#define CREATION_FACTOR_FOR_THE_SAME_SERIES 999
+
struct range_diff_options {
int creation_factor;
unsigned dual_color:1;
diff --git a/reachable.c b/reachable.c
index 0ce8f83e56..3e9b3dd0a4 100644
--- a/reachable.c
+++ b/reachable.c
@@ -1,8 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
-#include "tag.h"
#include "commit.h"
#include "blob.h"
#include "diff.h"
@@ -18,6 +19,7 @@
#include "pack-mtimes.h"
#include "config.h"
#include "run-command.h"
+#include "sequencer.h"
struct connectivity_progress {
struct progress *progress;
@@ -31,7 +33,53 @@ static void update_progress(struct connectivity_progress *cp)
display_progress(cp->progress, cp->count);
}
-static int add_one_ref(const char *path, const struct object_id *oid,
+static void add_one_file(const char *path, struct rev_info *revs)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct object_id oid;
+ struct object *object;
+
+ if (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {
+ strbuf_release(&buf);
+ return;
+ }
+ strbuf_trim(&buf);
+ if (!get_oid_hex(buf.buf, &oid)) {
+ object = parse_object_or_die(&oid, buf.buf);
+ add_pending_object(revs, object, "");
+ }
+ strbuf_release(&buf);
+}
+
+/* Mark objects recorded in rebase state files as reachable. */
+static void add_rebase_files(struct rev_info *revs)
+{
+ struct strbuf buf = STRBUF_INIT;
+ size_t len;
+ const char *path[] = {
+ "rebase-apply/autostash",
+ "rebase-apply/orig-head",
+ "rebase-merge/autostash",
+ "rebase-merge/orig-head",
+ };
+ struct worktree **worktrees = get_worktrees();
+
+ for (struct worktree **wt = worktrees; *wt; wt++) {
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, get_worktree_git_dir(*wt));
+ strbuf_complete(&buf, '/');
+ len = buf.len;
+ for (size_t i = 0; i < ARRAY_SIZE(path); i++) {
+ strbuf_setlen(&buf, len);
+ strbuf_addstr(&buf, path[i]);
+ add_one_file(buf.buf, revs);
+ }
+ }
+ strbuf_release(&buf);
+ free_worktrees(worktrees);
+}
+
+static int add_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
struct rev_info *revs = (struct rev_info *)cb_data;
@@ -317,12 +365,16 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
add_index_objects_to_pending(revs, 0);
/* Add all external refs */
- for_each_ref(add_one_ref, revs);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_one_ref,
+ revs);
/* detached HEAD is not included in the list above */
- head_ref(add_one_ref, revs);
+ refs_head_ref(get_main_ref_store(the_repository), add_one_ref, revs);
other_head_refs(add_one_ref, revs);
+ /* rebase autostash and orig-head */
+ add_rebase_files(revs);
+
/* Add all reflog info */
if (mark_reflog)
add_reflogs_to_pending(revs, 0);
diff --git a/read-cache-ll.h b/read-cache-ll.h
index 9a1a7edc5a..71b49d9af4 100644
--- a/read-cache-ll.h
+++ b/read-cache-ll.h
@@ -1,7 +1,7 @@
#ifndef READ_CACHE_LL_H
#define READ_CACHE_LL_H
-#include "hash-ll.h"
+#include "hash.h"
#include "hashmap.h"
#include "statinfo.h"
@@ -151,7 +151,7 @@ enum sparse_index_mode {
/*
* The index has already been collapsed to sparse directories
- * whereever possible.
+ * wherever possible.
*/
INDEX_COLLAPSED,
@@ -196,7 +196,7 @@ struct index_state {
*
* 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
+ * which does the same thing, but will 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.
*/
@@ -436,6 +436,14 @@ int match_stat_data_racy(const struct index_state *istate,
void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st);
+/*
+ * Fill members of st by members of sd enough to convince match_stat()
+ * to consider that they match. It should be usable as a replacement
+ * for lstat() for a tracked path that is known to be up-to-date via
+ * some out-of-line means (like fsmonitor).
+ */
+int fake_lstat(const 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 */
@@ -472,8 +480,8 @@ 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);
+ const struct pathspec *pathspec, char *ps_matched,
+ int include_sparse, int flags);
void overlay_tree_on_index(struct index_state *istate,
const char *tree_name, const char *prefix);
diff --git a/read-cache.c b/read-cache.c
index bdd983e1d3..01d0b3ad22 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -3,6 +3,9 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "bulk-checkin.h"
#include "config.h"
@@ -20,7 +23,6 @@
#include "oid-array.h"
#include "tree.h"
#include "commit.h"
-#include "blob.h"
#include "environment.h"
#include "gettext.h"
#include "mem-pool.h"
@@ -29,9 +31,9 @@
#include "path.h"
#include "preload-index.h"
#include "read-cache.h"
+#include "repository.h"
#include "resolve-undo.h"
#include "revision.h"
-#include "run-command.h"
#include "strbuf.h"
#include "trace2.h"
#include "varint.h"
@@ -197,6 +199,33 @@ void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, st
}
}
+static unsigned int st_mode_from_ce(const struct cache_entry *ce)
+{
+ extern int trust_executable_bit, has_symlinks;
+
+ switch (ce->ce_mode & S_IFMT) {
+ case S_IFLNK:
+ return has_symlinks ? S_IFLNK : (S_IFREG | 0644);
+ case S_IFREG:
+ return (ce->ce_mode & (trust_executable_bit ? 0755 : 0644)) | S_IFREG;
+ case S_IFGITLINK:
+ return S_IFDIR | 0755;
+ case S_IFDIR:
+ return ce->ce_mode;
+ default:
+ BUG("unsupported ce_mode: %o", ce->ce_mode);
+ }
+}
+
+int fake_lstat(const struct cache_entry *ce, struct stat *st)
+{
+ fake_lstat_data(&ce->ce_stat_data, st);
+ st->st_mode = st_mode_from_ce(ce);
+
+ /* always succeed as lstat() replacement */
+ return 0;
+}
+
static int ce_compare_data(struct index_state *istate,
const struct cache_entry *ce,
struct stat *st)
@@ -246,7 +275,8 @@ static int ce_compare_gitlink(const struct cache_entry *ce)
*
* If so, we consider it always to match.
*/
- if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, ce->name,
+ "HEAD", &oid) < 0)
return 0;
return !oideq(&oid, &ce->oid);
}
@@ -311,7 +341,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
/* Racily smudged entry? */
if (!ce->ce_stat_data.sd_size) {
- if (!is_empty_blob_sha1(ce->oid.hash))
+ if (!is_empty_blob_oid(&ce->oid, the_repository->hash_algo))
changed |= DATA_CHANGED;
}
@@ -686,7 +716,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
namelen = strlen(path);
if (S_ISDIR(st_mode)) {
- if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+ if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
return error(_("'%s' does not have a commit checked out"), path);
while (namelen && path[namelen-1] == '/')
namelen--;
@@ -1702,14 +1732,14 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
end = (unsigned char *)hdr + size;
start = end - the_hash_algo->rawsz;
- oidread(&oid, start);
+ oidread(&oid, start, the_repository->hash_algo);
if (oideq(&oid, null_oid()))
return 0;
the_hash_algo->init_fn(&c);
the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
the_hash_algo->final_fn(hash, &c);
- if (!hasheq(hash, start))
+ if (!hasheq(hash, start, the_repository->hash_algo))
return error(_("bad index file sha1 signature"));
return 0;
}
@@ -1850,7 +1880,8 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
ce->ce_flags = flags & ~CE_NAMEMASK;
ce->ce_namelen = len;
ce->index = 0;
- oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data));
+ oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data),
+ the_repository->hash_algo);
if (expand_name_field) {
if (copy_len)
@@ -1915,7 +1946,7 @@ static void tweak_untracked_cache(struct index_state *istate)
static void tweak_split_index(struct index_state *istate)
{
- switch (git_config_get_split_index()) {
+ switch (repo_config_get_split_index(the_repository)) {
case -1: /* unset: do nothing */
break;
case 0: /* false */
@@ -2157,6 +2188,7 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con
if (err)
die(_("unable to join load_cache_entries thread: %s"), strerror(err));
mem_pool_combine(istate->ce_mem_pool, p->ce_mem_pool);
+ free(p->ce_mem_pool);
consumed += p->consumed;
}
@@ -2223,7 +2255,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
if (verify_hdr(hdr, mmap_size) < 0)
goto unmap;
- oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
+ oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz,
+ the_repository->hash_algo);
istate->version = ntohl(hdr->hdr_version);
istate->cache_nr = ntohl(hdr->hdr_entries);
istate->cache_alloc = alloc_nr(istate->cache_nr);
@@ -2236,7 +2269,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
src_offset = sizeof(*hdr);
- if (git_config_get_index_threads(&nr_threads))
+ if (repo_config_get_index_threads(the_repository, &nr_threads))
nr_threads = 1;
/* TODO: does creating more threads than cores help? */
@@ -2615,7 +2648,7 @@ static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
ondisk->uid = htonl(ce->ce_stat_data.sd_uid);
ondisk->gid = htonl(ce->ce_stat_data.sd_gid);
ondisk->size = htonl(ce->ce_stat_data.sd_size);
- hashcpy(ondisk->data, ce->oid.hash);
+ hashcpy(ondisk->data, ce->oid.hash, the_repository->hash_algo);
flags = ce->ce_flags & ~CE_NAMEMASK;
flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
@@ -2704,7 +2737,7 @@ static int verify_index_from(const struct index_state *istate, const char *path)
if (n != the_hash_algo->rawsz)
goto out;
- if (!hasheq(istate->oid.hash, hash))
+ if (!hasheq(istate->oid.hash, hash, the_repository->hash_algo))
goto out;
close(fd);
@@ -2756,7 +2789,7 @@ static int record_eoie(void)
* used for threading is written by default if the user
* explicitly requested threaded index reads.
*/
- return !git_config_get_index_threads(&val) && val != 1;
+ return !repo_config_get_index_threads(the_repository, &val) && val != 1;
}
static int record_ieot(void)
@@ -2771,7 +2804,7 @@ static int record_ieot(void)
* written by default if the user explicitly requested
* threaded index reads.
*/
- return !git_config_get_index_threads(&val) && val != 1;
+ return !repo_config_get_index_threads(the_repository, &val) && val != 1;
}
enum write_extensions {
@@ -2809,8 +2842,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
int csum_fsync_flag;
int ieot_entries = 1;
struct index_entry_offset_table *ieot = NULL;
- int nr, nr_threads;
struct repository *r = istate->repo;
+ struct strbuf sb = STRBUF_INIT;
+ int nr, nr_threads, ret;
f = hashfd(tempfile->fd, tempfile->filename.buf);
@@ -2844,7 +2878,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
hashwrite(f, &hdr, sizeof(hdr));
- if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
+ if (!HAVE_THREADS || repo_config_get_index_threads(the_repository, &nr_threads))
nr_threads = 1;
if (nr_threads != 1 && record_ieot()) {
@@ -2931,8 +2965,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
strbuf_release(&previous_name_buf);
if (err) {
- free(ieot);
- return err;
+ ret = err;
+ goto out;
}
offset = hashfile_total(f);
@@ -2954,20 +2988,20 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
* index.
*/
if (ieot) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_ieot_extension(&sb, ieot);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- free(ieot);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
istate->split_index) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
if (istate->sparse_index)
die(_("cannot write split index for a sparse index"));
@@ -2976,59 +3010,66 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
write_index_ext_header(f, eoie_c, CACHE_EXT_LINK,
sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
!drop_cache_tree && istate->cache_tree) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
cache_tree_write(&sb, istate->cache_tree);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
istate->resolve_undo) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
resolve_undo_write(&sb, istate->resolve_undo);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO,
sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
istate->untracked) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_untracked_extension(&sb, istate->untracked);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_UNTRACKED,
sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
istate->fsmonitor_last_update) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_fsmonitor_extension(&sb, istate);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
if (istate->sparse_index) {
- if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0)
- return -1;
+ if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0) {
+ ret = -1;
+ goto out;
+ }
}
/*
@@ -3038,14 +3079,15 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
* when loading the shared index.
*/
if (eoie_c) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_eoie_extension(&sb, eoie_c, offset);
err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- if (err)
- return -1;
+ if (err) {
+ ret = -1;
+ goto out;
+ }
}
csum_fsync_flag = 0;
@@ -3054,13 +3096,16 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
finalize_hashfile(f, istate->oid.hash, FSYNC_COMPONENT_INDEX,
CSUM_HASH_IN_STREAM | csum_fsync_flag);
+ f = NULL;
if (close_tempfile_gently(tempfile)) {
- error(_("could not close '%s'"), get_tempfile_path(tempfile));
- return -1;
+ ret = error(_("could not close '%s'"), get_tempfile_path(tempfile));
+ goto out;
+ }
+ if (stat(get_tempfile_path(tempfile), &st)) {
+ ret = -1;
+ goto out;
}
- if (stat(get_tempfile_path(tempfile), &st))
- return -1;
istate->timestamp.sec = (unsigned int)st.st_mtime;
istate->timestamp.nsec = ST_MTIME_NSEC(st);
trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
@@ -3074,7 +3119,15 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
trace2_data_intmax("index", the_repository, "write/cache_nr",
istate->cache_nr);
- return 0;
+ ret = 0;
+
+out:
+ if (f)
+ free_hashfile(f);
+ strbuf_release(&sb);
+ free(eoie_c);
+ free(ieot);
+ return ret;
}
void set_alternate_index_output(const char *name)
@@ -3125,9 +3178,9 @@ static int do_write_locked_index(struct index_state *istate,
else
ret = close_lock_file_gently(lock);
- run_hooks_l("post-index-change",
- istate->updated_workdir ? "1" : "0",
- istate->updated_skipworktree ? "1" : "0", NULL);
+ run_hooks_l(the_repository, "post-index-change",
+ istate->updated_workdir ? "1" : "0",
+ istate->updated_skipworktree ? "1" : "0", NULL);
istate->updated_workdir = 0;
istate->updated_skipworktree = 0;
@@ -3145,18 +3198,24 @@ static int write_split_index(struct index_state *istate,
return ret;
}
-static const char *shared_index_expire = "2.weeks.ago";
-
static unsigned long get_shared_index_expire_date(void)
{
static unsigned long shared_index_expire_date;
static int shared_index_expire_date_prepared;
if (!shared_index_expire_date_prepared) {
- git_config_get_expiry("splitindex.sharedindexexpire",
- &shared_index_expire);
+ const char *shared_index_expire = "2.weeks.ago";
+ char *value = NULL;
+
+ repo_config_get_expiry(the_repository, "splitindex.sharedindexexpire",
+ &value);
+ if (value)
+ shared_index_expire = value;
+
shared_index_expire_date = approxidate(shared_index_expire);
shared_index_expire_date_prepared = 1;
+
+ free(value);
}
return shared_index_expire_date;
@@ -3182,10 +3241,11 @@ static int should_delete_shared_index(const char *shared_index_path)
static int clean_shared_index_files(const char *current_hex)
{
struct dirent *de;
- DIR *dir = opendir(get_git_dir());
+ DIR *dir = opendir(repo_get_git_dir(the_repository));
if (!dir)
- return error_errno(_("unable to open git dir: %s"), get_git_dir());
+ return error_errno(_("unable to open git dir: %s"),
+ repo_get_git_dir(the_repository));
while ((de = readdir(dir)) != NULL) {
const char *sha1_hex;
@@ -3244,7 +3304,7 @@ static const int default_max_percent_split_change = 20;
static int too_many_not_shared_entries(struct index_state *istate)
{
int i, not_shared = 0;
- int max_split = git_config_get_max_percent_split_change();
+ int max_split = repo_config_get_max_percent_split_change(the_repository);
switch (max_split) {
case -1:
@@ -3275,8 +3335,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
int new_shared_index, ret, test_split_index_env;
struct split_index *si = istate->split_index;
- if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
- cache_tree_verify(the_repository, istate);
+ if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0) &&
+ cache_tree_verify(the_repository, istate) < 0)
+ return -1;
if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
if (flags & COMMIT_LOCK)
@@ -3577,7 +3638,7 @@ static size_t read_eoie_extension(const char *mmap, size_t mmap_size)
src_offset += extsize;
}
the_hash_algo->final_fn(hash, &c);
- if (!hasheq(hash, (const unsigned char *)index))
+ if (!hasheq(hash, (const unsigned char *)index, the_repository->hash_algo))
return 0;
/* Validate that the extension offsets returned us back to the eoie extension. */
@@ -3899,8 +3960,8 @@ static void update_callback(struct diff_queue_struct *q,
}
int add_files_to_cache(struct repository *repo, const char *prefix,
- const struct pathspec *pathspec, int include_sparse,
- int flags)
+ const struct pathspec *pathspec, char *ps_matched,
+ int include_sparse, int flags)
{
struct update_callback_data data;
struct rev_info rev;
@@ -3912,8 +3973,10 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
repo_init_revisions(repo, &rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
- if (pathspec)
+ if (pathspec) {
copy_pathspec(&rev.prune_data, pathspec);
+ rev.ps_matched = ps_matched;
+ }
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
diff --git a/rebase-interactive.c b/rebase-interactive.c
index d9718409b3..cbeb864147 100644
--- a/rebase-interactive.c
+++ b/rebase-interactive.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit.h"
#include "editor.h"
@@ -71,14 +73,14 @@ void append_todo_help(int command_count,
if (!edit_todo) {
strbuf_addch(buf, '\n');
- strbuf_commented_addf(buf, comment_line_char,
+ strbuf_commented_addf(buf, comment_line_str,
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), comment_line_char);
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_str);
if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)
msg = _("\nDo not remove any line. Use 'drop' "
@@ -87,7 +89,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), comment_line_char);
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_str);
if (edit_todo)
msg = _("\nYou are editing the todo file "
@@ -98,12 +100,13 @@ 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), comment_line_char);
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_str);
}
-int edit_todo_list(struct repository *r, struct todo_list *todo_list,
- struct todo_list *new_todo, const char *shortrevisions,
- const char *shortonto, unsigned flags)
+int edit_todo_list(struct repository *r, struct replay_opts *opts,
+ struct todo_list *todo_list, struct todo_list *new_todo,
+ const char *shortrevisions, const char *shortonto,
+ unsigned flags)
{
const char *todo_file = rebase_path_todo(),
*todo_backup = rebase_path_todo_backup();
@@ -114,7 +117,9 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
* it. If there is an error, we do not return, because the user
* might want to fix it in the first place. */
if (!initial)
- incorrect = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list) |
+ incorrect = todo_list_parse_insn_buffer(r, opts,
+ todo_list->buf.buf,
+ todo_list) |
file_exists(rebase_path_dropped());
if (todo_list_write_to_file(r, todo_list, todo_file, shortrevisions, shortonto,
@@ -130,17 +135,17 @@ 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, comment_line_char);
+ strbuf_stripspace(&new_todo->buf, comment_line_str);
if (initial && new_todo->buf.len == 0)
return -3;
- if (todo_list_parse_insn_buffer(r, new_todo->buf.buf, new_todo)) {
+ if (todo_list_parse_insn_buffer(r, opts, new_todo->buf.buf, new_todo)) {
fprintf(stderr, _(edit_todo_list_advice));
return -4;
}
if (incorrect) {
- if (todo_list_check_against_backup(r, new_todo)) {
+ if (todo_list_check_against_backup(r, opts, new_todo)) {
write_file(rebase_path_dropped(), "%s", "");
return -4;
}
@@ -228,13 +233,15 @@ leave_check:
return res;
}
-int todo_list_check_against_backup(struct repository *r, struct todo_list *todo_list)
+int todo_list_check_against_backup(struct repository *r,
+ struct replay_opts *opts,
+ struct todo_list *todo_list)
{
struct todo_list backup = TODO_LIST_INIT;
int res = 0;
if (strbuf_read_file(&backup.buf, rebase_path_todo_backup(), 0) > 0) {
- todo_list_parse_insn_buffer(r, backup.buf.buf, &backup);
+ todo_list_parse_insn_buffer(r, opts, backup.buf.buf, &backup);
res = todo_list_check(&backup, todo_list);
}
diff --git a/rebase-interactive.h b/rebase-interactive.h
index 7239c60f79..8e5b181b33 100644
--- a/rebase-interactive.h
+++ b/rebase-interactive.h
@@ -3,17 +3,20 @@
struct strbuf;
struct repository;
+struct replay_opts;
struct todo_list;
void append_todo_help(int command_count,
const char *shortrevisions, const char *shortonto,
struct strbuf *buf);
-int edit_todo_list(struct repository *r, struct todo_list *todo_list,
- struct todo_list *new_todo, const char *shortrevisions,
- const char *shortonto, unsigned flags);
+int edit_todo_list(struct repository *r, struct replay_opts *opts,
+ struct todo_list *todo_list, struct todo_list *new_todo,
+ const char *shortrevisions, const char *shortonto,
+ unsigned flags);
int todo_list_check(struct todo_list *old_todo, struct todo_list *new_todo);
int todo_list_check_against_backup(struct repository *r,
+ struct replay_opts *opts,
struct todo_list *todo_list);
#endif
diff --git a/rebase.c b/rebase.c
index 17a570f1ff..9d1ae95978 100644
--- a/rebase.c
+++ b/rebase.c
@@ -1,6 +1,6 @@
#include "git-compat-util.h"
#include "rebase.h"
-#include "config.h"
+#include "parse.h"
#include "gettext.h"
/*
@@ -11,7 +11,7 @@
* The callers that care if (any) rebase is requested should say
* if (REBASE_TRUE <= rebase_parse_value(string))
*
- * The callers that want to differenciate an unrecognised value and
+ * The callers that want to differentiate an unrecognised value and
* false can do so by treating _INVALID and _FALSE differently.
*/
enum rebase_type rebase_parse_value(const char *value)
diff --git a/ref-filter.c b/ref-filter.c
index 9dbc4f71bd..84c6036107 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
@@ -11,8 +13,11 @@
#include "object-name.h"
#include "object-store-ll.h"
#include "oid-array.h"
+#include "repo-settings.h"
#include "repository.h"
#include "commit.h"
+#include "mailmap.h"
+#include "ident.h"
#include "remote.h"
#include "color.h"
#include "tag.h"
@@ -20,16 +25,13 @@
#include "ref-filter.h"
#include "revision.h"
#include "utf8.h"
-#include "version.h"
#include "versioncmp.h"
#include "trailer.h"
#include "wt-status.h"
#include "commit-slab.h"
-#include "commit-graph.h"
#include "commit-reach.h"
#include "worktree.h"
#include "hashmap.h"
-#include "strvec.h"
static struct ref_msg {
const char *gone;
@@ -74,11 +76,11 @@ struct refname_atom {
int lstrip, rstrip;
};
-static struct ref_trailer_buf {
+struct ref_trailer_buf {
struct string_list filter_list;
struct strbuf sepbuf;
struct strbuf kvsepbuf;
-} ref_trailer_buf = {STRING_LIST_INIT_NODUP, STRBUF_INIT, STRBUF_INIT};
+};
static struct expand_data {
struct object_id oid;
@@ -168,6 +170,7 @@ enum atom_type {
ATOM_ELSE,
ATOM_REST,
ATOM_AHEADBEHIND,
+ ATOM_ISBASE,
};
/*
@@ -199,6 +202,7 @@ static struct used_atom {
enum { C_BARE, C_BODY, C_BODY_DEP, C_LENGTH, C_LINES,
C_SIG, C_SUB, C_SUB_SANITIZE, C_TRAILERS } option;
struct process_trailer_options trailer_opts;
+ struct ref_trailer_buf *trailer_buf;
unsigned int nlines;
} contents;
struct {
@@ -215,14 +219,22 @@ static struct used_atom {
struct {
enum { O_SIZE, O_SIZE_DISK } option;
} objectsize;
- struct email_option {
- enum { EO_RAW, EO_TRIM, EO_LOCALPART } option;
+ struct {
+ enum { N_RAW, N_MAILMAP } option;
+ } name_option;
+ struct {
+ enum {
+ EO_RAW = 0,
+ EO_TRIM = 1<<0,
+ EO_LOCALPART = 1<<1,
+ EO_MAILMAP = 1<<2,
+ } option;
} email_option;
struct {
enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
} signature;
- const char **describe_args;
+ struct strvec describe_args;
struct refname_atom refname;
char *head;
} u;
@@ -549,27 +561,43 @@ static int signature_atom_parser(struct ref_format *format UNUSED,
return 0;
}
-static int trailers_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int trailers_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
atom->u.contents.trailer_opts.no_divider = 1;
if (arg) {
- const char *argbuf = xstrfmt("%s)", arg);
+ char *argbuf = xstrfmt("%s)", arg);
+ const char *arg = argbuf;
char *invalid_arg = NULL;
+ struct ref_trailer_buf *tb;
+
+ /*
+ * Do not inline these directly into the used_atom struct!
+ * When we parse them in format_set_trailers_options(),
+ * we will make pointer references directly to them,
+ * which will not survive a realloc() of the used_atom list.
+ * They must be allocated in a separate, stable struct.
+ */
+ atom->u.contents.trailer_buf = tb = xmalloc(sizeof(*tb));
+ string_list_init_dup(&tb->filter_list);
+ strbuf_init(&tb->sepbuf, 0);
+ strbuf_init(&tb->kvsepbuf, 0);
if (format_set_trailers_options(&atom->u.contents.trailer_opts,
- &ref_trailer_buf.filter_list,
- &ref_trailer_buf.sepbuf,
- &ref_trailer_buf.kvsepbuf,
- &argbuf, &invalid_arg)) {
+ &tb->filter_list,
+ &tb->sepbuf, &tb->kvsepbuf,
+ &arg, &invalid_arg)) {
if (!invalid_arg)
strbuf_addf(err, _("expected %%(trailers:key=<value>)"));
else
strbuf_addf(err, _("unknown %%(trailers) argument: %s"), invalid_arg);
- free((char *)invalid_arg);
+ free(invalid_arg);
+ free(argbuf);
return -1;
}
+ free(argbuf);
}
atom->u.contents.option = C_TRAILERS;
return 0;
@@ -666,7 +694,7 @@ 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;
+ strvec_init(&atom->u.describe_args);
for (;;) {
int found = 0;
@@ -675,13 +703,12 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
if (!arg || !*arg)
break;
- found = describe_atom_option_parser(&args, &arg, err);
+ found = describe_atom_option_parser(&atom->u.describe_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;
}
@@ -719,21 +746,54 @@ static int oid_atom_parser(struct ref_format *format UNUSED,
return 0;
}
-static int person_email_atom_parser(struct ref_format *format UNUSED,
- struct used_atom *atom,
- const char *arg, struct strbuf *err)
+static int person_name_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
+ const char *arg, struct strbuf *err)
{
if (!arg)
- atom->u.email_option.option = EO_RAW;
- else if (!strcmp(arg, "trim"))
- atom->u.email_option.option = EO_TRIM;
- else if (!strcmp(arg, "localpart"))
- atom->u.email_option.option = EO_LOCALPART;
+ atom->u.name_option.option = N_RAW;
+ else if (!strcmp(arg, "mailmap"))
+ atom->u.name_option.option = N_MAILMAP;
else
return err_bad_arg(err, atom->name, arg);
return 0;
}
+static int email_atom_option_parser(const char **arg)
+{
+ if (!*arg)
+ return EO_RAW;
+ if (skip_prefix(*arg, "trim", arg))
+ return EO_TRIM;
+ if (skip_prefix(*arg, "localpart", arg))
+ return EO_LOCALPART;
+ if (skip_prefix(*arg, "mailmap", arg))
+ return EO_MAILMAP;
+ return -1;
+}
+
+static int person_email_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+ for (;;) {
+ int opt = email_atom_option_parser(&arg);
+ const char *bad_arg = arg;
+
+ if (opt < 0)
+ return err_bad_arg(err, atom->name, bad_arg);
+ atom->u.email_option.option |= opt;
+
+ if (!arg || !*arg)
+ break;
+ if (*arg == ',')
+ arg++;
+ else
+ return err_bad_arg(err, atom->name, bad_arg);
+ }
+ return 0;
+}
+
static int refname_atom_parser(struct ref_format *format UNUSED,
struct used_atom *atom,
const char *arg, struct strbuf *err)
@@ -821,7 +881,7 @@ static int if_atom_parser(struct ref_format *format UNUSED,
return 0;
}
-static int rest_atom_parser(struct ref_format *format,
+static int rest_atom_parser(struct ref_format *format UNUSED,
struct used_atom *atom UNUSED,
const char *arg, struct strbuf *err)
{
@@ -830,7 +890,8 @@ static int rest_atom_parser(struct ref_format *format,
return 0;
}
-static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int ahead_behind_atom_parser(struct ref_format *format,
+ struct used_atom *atom UNUSED,
const char *arg, struct strbuf *err)
{
struct string_list_item *item;
@@ -846,13 +907,32 @@ static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom
return 0;
}
+static int is_base_atom_parser(struct ref_format *format,
+ struct used_atom *atom UNUSED,
+ const char *arg, struct strbuf *err)
+{
+ struct string_list_item *item;
+
+ if (!arg)
+ return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));
+
+ item = string_list_append(&format->is_base_tips, 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)
return err_no_arg(err, "HEAD");
- atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
+ atom->u.head = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", RESOLVE_REF_READING, NULL,
+ NULL);
return 0;
}
@@ -875,15 +955,15 @@ static struct {
[ATOM_TYPE] = { "type", SOURCE_OBJ },
[ATOM_TAG] = { "tag", SOURCE_OBJ },
[ATOM_AUTHOR] = { "author", SOURCE_OBJ },
- [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ },
+ [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ, FIELD_STR, person_name_atom_parser },
[ATOM_AUTHOREMAIL] = { "authoremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
[ATOM_AUTHORDATE] = { "authordate", SOURCE_OBJ, FIELD_TIME },
[ATOM_COMMITTER] = { "committer", SOURCE_OBJ },
- [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ },
+ [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ, FIELD_STR, person_name_atom_parser },
[ATOM_COMMITTEREMAIL] = { "committeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
[ATOM_COMMITTERDATE] = { "committerdate", SOURCE_OBJ, FIELD_TIME },
[ATOM_TAGGER] = { "tagger", SOURCE_OBJ },
- [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ },
+ [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ, FIELD_STR, person_name_atom_parser },
[ATOM_TAGGEREMAIL] = { "taggeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
[ATOM_TAGGERDATE] = { "taggerdate", SOURCE_OBJ, FIELD_TIME },
[ATOM_CREATOR] = { "creator", SOURCE_OBJ },
@@ -909,6 +989,7 @@ static struct {
[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 },
+ [ATOM_ISBASE] = { "is-base", SOURCE_OTHER, FIELD_STR, is_base_atom_parser },
/*
* Please update $__git_ref_fieldlist in git-completion.bash
* when you add new atoms
@@ -921,6 +1002,7 @@ struct ref_formatting_stack {
struct ref_formatting_stack *prev;
struct strbuf output;
void (*at_end)(struct ref_formatting_stack **stack);
+ void (*at_end_data_free)(void *data);
void *at_end_data;
};
@@ -1089,6 +1171,8 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
if (prev)
strbuf_addbuf(&prev->output, &current->output);
strbuf_release(&current->output);
+ if (current->at_end_data_free)
+ current->at_end_data_free(current->at_end_data);
free(current);
*stack = prev;
}
@@ -1148,15 +1232,13 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
}
*stack = cur;
- free(if_then_else);
}
static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
struct strbuf *err UNUSED)
{
struct ref_formatting_stack *new_stack;
- struct if_then_else *if_then_else = xcalloc(1,
- sizeof(struct if_then_else));
+ struct if_then_else *if_then_else = xcalloc(1, sizeof(*if_then_else));
if_then_else->str = atomv->atom->u.if_then_else.str;
if_then_else->cmp_status = atomv->atom->u.if_then_else.cmp_status;
@@ -1165,6 +1247,7 @@ static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+ new_stack->at_end_data_free = free;
return 0;
}
@@ -1484,32 +1567,49 @@ static const char *copy_name(const char *buf)
return xstrdup("");
}
+static const char *find_end_of_email(const char *email, int opt)
+{
+ const char *eoemail;
+
+ if (opt & EO_LOCALPART) {
+ eoemail = strchr(email, '@');
+ if (eoemail)
+ return eoemail;
+ return strchr(email, '>');
+ }
+
+ if (opt & EO_TRIM)
+ return strchr(email, '>');
+
+ /*
+ * The option here is either the raw email option or the raw
+ * mailmap option (that is EO_RAW or EO_MAILMAP). In such cases,
+ * we directly grab the whole email including the closing
+ * angle brackets.
+ *
+ * If EO_MAILMAP was set with any other option (that is either
+ * EO_TRIM or EO_LOCALPART), we already grab the end of email
+ * above.
+ */
+ eoemail = strchr(email, '>');
+ if (eoemail)
+ eoemail++;
+ return eoemail;
+}
+
static const char *copy_email(const char *buf, struct used_atom *atom)
{
const char *email = strchr(buf, '<');
const char *eoemail;
+ int opt = atom->u.email_option.option;
+
if (!email)
return xstrdup("");
- switch (atom->u.email_option.option) {
- case EO_RAW:
- eoemail = strchr(email, '>');
- if (eoemail)
- eoemail++;
- break;
- case EO_TRIM:
- email++;
- eoemail = strchr(email, '>');
- break;
- case EO_LOCALPART:
+
+ if (opt & (EO_LOCALPART | EO_TRIM))
email++;
- eoemail = strchr(email, '@');
- if (!eoemail)
- eoemail = strchr(email, '>');
- break;
- default:
- BUG("unknown email option");
- }
+ eoemail = find_end_of_email(email, opt);
if (!eoemail)
return xstrdup("");
return xmemdupz(email, eoemail - email);
@@ -1551,6 +1651,12 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
if (formatp) {
formatp++;
parse_date_format(formatp, &date_mode);
+
+ /*
+ * If this is a sort field and a format was specified, we'll
+ * want to compare formatted date by string value.
+ */
+ v->atom->type = FIELD_STR;
}
if (!eoemail)
@@ -1558,10 +1664,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
timestamp = parse_timestamp(eoemail + 2, &zone, 10);
if (timestamp == TIME_MAX)
goto bad;
+ errno = 0;
tz = strtol(zone, NULL, 10);
if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
goto bad;
- v->s = xstrdup(show_date(timestamp, tz, &date_mode));
+ v->s = xstrdup(show_date(timestamp, tz, date_mode));
v->value = timestamp;
date_mode_release(&date_mode);
return;
@@ -1570,16 +1677,23 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
v->value = 0;
}
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
+
/* See grab_values */
static void grab_person(const char *who, struct atom_value *val, int deref, void *buf)
{
int i;
int wholen = strlen(who);
const char *wholine = NULL;
+ const char *headers[] = { "author ", "committer ",
+ "tagger ", NULL };
for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i].name;
+ struct used_atom *atom = &used_atom[i];
+ const char *name = atom->name;
struct atom_value *v = &val[i];
+ struct strbuf mailmap_buf = STRBUF_INIT;
+
if (!!deref != (*name == '*'))
continue;
if (deref)
@@ -1587,22 +1701,36 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
if (strncmp(who, name, wholen))
continue;
if (name[wholen] != 0 &&
- strcmp(name + wholen, "name") &&
+ !starts_with(name + wholen, "name") &&
!starts_with(name + wholen, "email") &&
!starts_with(name + wholen, "date"))
continue;
- if (!wholine)
+
+ if ((starts_with(name + wholen, "name") &&
+ (atom->u.name_option.option == N_MAILMAP)) ||
+ (starts_with(name + wholen, "email") &&
+ (atom->u.email_option.option & EO_MAILMAP))) {
+ if (!mailmap.items)
+ read_mailmap(&mailmap);
+ strbuf_addstr(&mailmap_buf, buf);
+ apply_mailmap_to_header(&mailmap_buf, headers, &mailmap);
+ wholine = find_wholine(who, wholen, mailmap_buf.buf);
+ } else {
wholine = find_wholine(who, wholen, buf);
+ }
+
if (!wholine)
return; /* no point looking for it */
if (name[wholen] == 0)
v->s = copy_line(wholine);
- else if (!strcmp(name + wholen, "name"))
+ else if (starts_with(name + wholen, "name"))
v->s = copy_name(wholine);
else if (starts_with(name + wholen, "email"))
v->s = copy_email(wholine, &used_atom[i]);
else if (starts_with(name + wholen, "date"))
grab_date(wholine, v, name);
+
+ strbuf_release(&mailmap_buf);
}
/*
@@ -1723,16 +1851,10 @@ static void find_subpos(const char *buf,
size_t *nonsiglen,
const char **sig, size_t *siglen)
{
- struct strbuf payload = STRBUF_INIT;
- struct strbuf signature = STRBUF_INIT;
const char *eol;
const char *end = buf + strlen(buf);
const char *sigstart;
- /* parse signature first; we might not even have a subject line */
- parse_signature(buf, end - buf, &payload, &signature);
- strbuf_release(&payload);
-
/* skip past header until we hit empty line */
while (*buf && *buf != '\n') {
eol = strchrnul(buf, '\n');
@@ -1743,8 +1865,10 @@ static void find_subpos(const char *buf,
/* skip any empty lines */
while (*buf == '\n')
buf++;
- *sig = strbuf_detach(&signature, siglen);
+ /* parse signature first; we might not even have a subject line */
sigstart = buf + parse_signed_buffer(buf, strlen(buf));
+ *sig = sigstart;
+ *siglen = end - *sig;
/* subject is first non-empty line */
*sub = buf;
@@ -1819,7 +1943,7 @@ static void grab_describe_values(struct atom_value *val, int deref,
cmd.git_cmd = 1;
strvec_push(&cmd.args, "describe");
- strvec_pushv(&cmd.args, atom->u.describe_args);
+ strvec_pushv(&cmd.args, atom->u.describe_args.v);
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'"));
@@ -1902,16 +2026,23 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
v->s = strbuf_detach(&s, NULL);
} else if (atom->u.contents.option == C_TRAILERS) {
struct strbuf s = STRBUF_INIT;
+ const char *msg;
+ char *to_free = NULL;
+
+ if (siglen)
+ msg = to_free = xmemdupz(subpos, sigpos - subpos);
+ else
+ msg = subpos;
/* Format the trailer info according to the trailer_opts given */
- format_trailers_from_commit(&s, subpos, &atom->u.contents.trailer_opts);
+ format_trailers_from_commit(&atom->u.contents.trailer_opts, msg, &s);
+ free(to_free);
v->s = strbuf_detach(&s, NULL);
} else if (atom->u.contents.option == C_BARE)
v->s = xstrdup(subpos);
}
- free((void *)sigpos);
}
/*
@@ -2048,7 +2179,9 @@ static const char *rstrip_ref_components(const char *refname, int len)
static const char *show_ref(struct refname_atom *atom, const char *refname)
{
if (atom->option == R_SHORT)
- return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ return refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ refname,
+ repo_settings_get_warn_ambiguous_refs(the_repository));
else if (atom->option == R_LSTRIP)
return lstrip_ref_components(refname, atom->lstrip);
else if (atom->option == R_RSTRIP)
@@ -2107,7 +2240,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
const char *merge;
merge = remote_ref_for_branch(branch, atom->u.remote_ref.push);
- *s = xstrdup(merge ? merge : "");
+ *s = merge ? merge : xstrdup("");
} else
BUG("unhandled RR_* enum");
}
@@ -2128,7 +2261,7 @@ char *get_head_description(void)
state.detached_from);
} else if (state.bisect_in_progress)
strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
- state.branch);
+ state.bisecting_from);
else if (state.detached_from) {
if (state.detached_at)
strbuf_addf(&desc, _("(HEAD detached at %s)"),
@@ -2247,12 +2380,21 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
int i;
struct object_info empty = OBJECT_INFO_INIT;
int ahead_behind_atoms = 0;
+ int is_base_atoms = 0;
CALLOC_ARRAY(ref->value, used_atom_cnt);
+ /**
+ * NEEDSWORK: The following code might be unnecessary if all codepaths
+ * that call populate_value() populates the symref member of ref_array_item
+ * like in apply_ref_filter(). Currently pretty_print_ref() is the only codepath
+ * that calls populate_value() without first populating symref.
+ */
if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
- ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
- NULL, NULL);
+ ref->symref = refs_resolve_refdup(get_main_ref_store(the_repository),
+ ref->refname,
+ RESOLVE_REF_READING,
+ NULL, NULL);
if (!ref->symref)
ref->symref = xstrdup("");
}
@@ -2388,6 +2530,15 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
v->s = xstrdup("");
}
continue;
+ } else if (atom_type == ATOM_ISBASE) {
+ if (ref->is_base && ref->is_base[is_base_atoms]) {
+ v->s = xstrfmt("(%s)", ref->is_base[is_base_atoms]);
+ free(ref->is_base[is_base_atoms]);
+ } else {
+ v->s = xstrdup("");
+ }
+ is_base_atoms++;
+ continue;
} else
continue;
@@ -2424,17 +2575,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
return 0;
/*
- * If it is a tag object, see if we use a value that derefs
- * the object, and if we do grab the object it refers to.
+ * If it is a tag object, see if we use the peeled value. If we do,
+ * grab the peeled OID.
*/
- oi_deref.oid = *get_tagged_oid((struct tag *)obj);
+ if (need_tagged && peel_iterated_oid(the_repository, &obj->oid, &oi_deref.oid))
+ die("bad tag");
- /*
- * NEEDSWORK: This derefs tag only once, which
- * is good to deal with chains of trust, but
- * is not consistent with what deref_tag() does
- * which peels the onion to the core.
- */
return get_object(ref, 1, &obj, &oi_deref, err);
}
@@ -2546,13 +2692,20 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
each_ref_fn cb,
void *cb_data)
{
+ if (filter->kind & FILTER_REFS_ROOT_REFS) {
+ /* In this case, we want to print all refs including root refs. */
+ return refs_for_each_include_root_refs(get_main_ref_store(the_repository),
+ cb, cb_data);
+ }
+
if (!filter->match_as_path) {
/*
* in this case, the patterns are applied after
* prefixes like "refs/heads/" etc. are stripped off,
* so 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),
+ "", NULL, cb, cb_data);
}
if (filter->ignore_case) {
@@ -2561,7 +2714,8 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
* so just return everything and let the caller
* sort it out.
*/
- return for_each_fullref_in("", cb, cb_data);
+ return refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "", NULL, cb, cb_data);
}
if (!filter->name_patterns[0]) {
@@ -2632,15 +2786,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,
return ref;
}
+static void ref_array_append(struct ref_array *array, struct ref_array_item *ref)
+{
+ ALLOC_GROW(array->items, array->nr + 1, array->alloc);
+ array->items[array->nr++] = ref;
+}
+
struct ref_array_item *ref_array_push(struct ref_array *array,
const char *refname,
const struct object_id *oid)
{
struct ref_array_item *ref = new_ref_array_item(refname, oid);
-
- ALLOC_GROW(array->items, array->nr + 1, array->alloc);
- array->items[array->nr++] = ref;
-
+ ref_array_append(array, ref);
return ref;
}
@@ -2665,6 +2822,11 @@ static int ref_kind_from_refname(const char *refname)
return ref_kind[i].kind;
}
+ if (is_pseudo_ref(refname))
+ return FILTER_REFS_PSEUDOREFS;
+ if (is_root_ref(refname))
+ return FILTER_REFS_ROOT_REFS;
+
return FILTER_REFS_OTHERS;
}
@@ -2677,48 +2839,45 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)
return ref_kind_from_refname(refname);
}
-struct ref_filter_cbdata {
- struct ref_array *array;
- struct ref_filter *filter;
- struct contains_cache contains_cache;
- struct contains_cache no_contains_cache;
-};
-
-/*
- * A call-back given to for_each_ref(). Filter refs and keep them for
- * later object processing.
- */
-static int ref_filter_handler(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static struct ref_array_item *apply_ref_filter(const char *refname, const char *referent, const struct object_id *oid,
+ int flag, struct ref_filter *filter)
{
- struct ref_filter_cbdata *ref_cbdata = cb_data;
- struct ref_filter *filter = ref_cbdata->filter;
struct ref_array_item *ref;
struct commit *commit = NULL;
unsigned int kind;
if (flag & REF_BAD_NAME) {
warning(_("ignoring ref with broken name %s"), refname);
- return 0;
+ return NULL;
}
if (flag & REF_ISBROKEN) {
warning(_("ignoring broken ref %s"), refname);
- return 0;
+ return NULL;
}
/* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
kind = filter_ref_kind(filter, refname);
- if (!(kind & filter->kind))
- return 0;
+
+ /*
+ * Generally HEAD refs are printed with special description denoting a rebase,
+ * detached state and so forth. This is useful when only printing the HEAD ref
+ * But when it is being printed along with other root refs, it makes sense to
+ * keep the formatting consistent. So we mask the type to act like a root ref.
+ */
+ if (filter->kind & FILTER_REFS_ROOT_REFS && kind == FILTER_REFS_DETACHED_HEAD)
+ kind = FILTER_REFS_ROOT_REFS;
+ else if (!(kind & filter->kind))
+ return NULL;
if (!filter_pattern_match(filter, refname))
- return 0;
+ return NULL;
if (filter_exclude_match(filter, refname))
- return 0;
+ return NULL;
if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname))
- return 0;
+ return NULL;
/*
* A merge filter is applied on refs pointing to commits. Hence
@@ -2729,15 +2888,15 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
filter->with_commit || filter->no_commit || filter->verbose) {
commit = lookup_commit_reference_gently(the_repository, oid, 1);
if (!commit)
- return 0;
+ return NULL;
/* We perform the filtering for the '--contains' option... */
if (filter->with_commit &&
- !commit_contains(filter, commit, filter->with_commit, &ref_cbdata->contains_cache))
- return 0;
+ !commit_contains(filter, commit, filter->with_commit, &filter->internal.contains_cache))
+ return NULL;
/* ...or for the `--no-contains' option */
if (filter->no_commit &&
- commit_contains(filter, commit, filter->no_commit, &ref_cbdata->no_contains_cache))
- return 0;
+ commit_contains(filter, commit, filter->no_commit, &filter->internal.no_contains_cache))
+ return NULL;
}
/*
@@ -2745,10 +2904,32 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
* to do its job and the resulting list may yet to be pruned
* by maxcount logic.
*/
- ref = ref_array_push(ref_cbdata->array, refname, oid);
+ ref = new_ref_array_item(refname, oid);
ref->commit = commit;
ref->flag = flag;
ref->kind = kind;
+ ref->symref = xstrdup_or_null(referent);
+
+ return ref;
+}
+
+struct ref_filter_cbdata {
+ struct ref_array *array;
+ struct ref_filter *filter;
+};
+
+/*
+ * A call-back given to for_each_ref(). Filter refs and keep them for
+ * later object processing.
+ */
+static int filter_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
+{
+ struct ref_filter_cbdata *ref_cbdata = cb_data;
+ struct ref_array_item *ref;
+
+ ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
+ if (ref)
+ ref_array_append(ref_cbdata->array, ref);
return 0;
}
@@ -2764,9 +2945,53 @@ static void free_array_item(struct ref_array_item *item)
free(item->value);
}
free(item->counts);
+ free(item->is_base);
free(item);
}
+struct ref_filter_and_format_cbdata {
+ struct ref_filter *filter;
+ struct ref_format *format;
+
+ struct ref_filter_and_format_internal {
+ int count;
+ } internal;
+};
+
+static int filter_and_format_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
+{
+ struct ref_filter_and_format_cbdata *ref_cbdata = cb_data;
+ struct ref_array_item *ref;
+ struct strbuf output = STRBUF_INIT, err = STRBUF_INIT;
+
+ ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
+ if (!ref)
+ return 0;
+
+ if (format_ref_array_item(ref, ref_cbdata->format, &output, &err))
+ die("%s", err.buf);
+
+ if (output.len || !ref_cbdata->format->array_opts.omit_empty) {
+ fwrite(output.buf, 1, output.len, stdout);
+ putchar('\n');
+ }
+
+ strbuf_release(&output);
+ strbuf_release(&err);
+ free_array_item(ref);
+
+ /*
+ * Increment the running count of refs that match the filter. If
+ * max_count is set and we've reached the max, stop the ref
+ * iteration by returning a nonzero value.
+ */
+ if (ref_cbdata->format->array_opts.max_count &&
+ ++ref_cbdata->internal.count >= ref_cbdata->format->array_opts.max_count)
+ return 1;
+
+ return 0;
+}
+
/* Free all memory allocated for ref_array */
void ref_array_clear(struct ref_array *array)
{
@@ -2781,6 +3006,19 @@ void ref_array_clear(struct ref_array *array)
struct used_atom *atom = &used_atom[i];
if (atom->atom_type == ATOM_HEAD)
free(atom->u.head);
+ else if (atom->atom_type == ATOM_DESCRIBE)
+ strvec_clear(&atom->u.describe_args);
+ else if (atom->atom_type == ATOM_TRAILERS ||
+ (atom->atom_type == ATOM_CONTENTS &&
+ atom->u.contents.option == C_TRAILERS)) {
+ struct ref_trailer_buf *tb = atom->u.contents.trailer_buf;
+ if (tb) {
+ string_list_clear(&tb->filter_list, 0);
+ strbuf_release(&tb->sepbuf);
+ strbuf_release(&tb->kvsepbuf);
+ free(tb);
+ }
+ }
free((char *)atom->name);
}
FREE_AND_NULL(used_atom);
@@ -2885,28 +3123,57 @@ void filter_ahead_behind(struct repository *r,
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
- * as per the given ref_filter structure and finally store the
- * filtered refs in the ref_array structure.
- */
-int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
+void filter_is_base(struct repository *r,
+ struct ref_format *format,
+ struct ref_array *array)
{
- struct ref_filter_cbdata ref_cbdata;
- int save_commit_buffer_orig;
- int ret = 0;
+ struct commit **bases;
+ size_t bases_nr = 0;
+ struct ref_array_item **back_index;
- ref_cbdata.array = array;
- ref_cbdata.filter = filter;
+ if (!format->is_base_tips.nr || !array->nr)
+ return;
- filter->kind = type & FILTER_REFS_KIND_MASK;
+ CALLOC_ARRAY(back_index, array->nr);
+ CALLOC_ARRAY(bases, array->nr);
- save_commit_buffer_orig = save_commit_buffer;
- save_commit_buffer = 0;
+ for (size_t i = 0; i < array->nr; i++) {
+ const char *name = array->items[i]->refname;
+ struct commit *c = lookup_commit_reference_by_name_gently(name, 1);
+
+ CALLOC_ARRAY(array->items[i]->is_base, format->is_base_tips.nr);
+
+ if (!c)
+ continue;
- init_contains_cache(&ref_cbdata.contains_cache);
- init_contains_cache(&ref_cbdata.no_contains_cache);
+ back_index[bases_nr] = array->items[i];
+ bases[bases_nr] = c;
+ bases_nr++;
+ }
+
+ for (size_t i = 0; i < format->is_base_tips.nr; i++) {
+ struct commit *tip = format->is_base_tips.items[i].util;
+ int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
+
+ if (base_index < 0)
+ continue;
+
+ /* Store the string for use in output later. */
+ back_index[base_index]->is_base[i] = xstrdup(format->is_base_tips.items[i].string);
+ }
+
+ free(back_index);
+ free(bases);
+}
+
+static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref_fn fn, void *cb_data)
+{
+ int ret = 0;
+
+ filter->kind = type & FILTER_REFS_KIND_MASK;
+
+ init_contains_cache(&filter->internal.contains_cache);
+ init_contains_cache(&filter->internal.no_contains_cache);
/* Simple per-ref filtering */
if (!filter->kind)
@@ -2919,19 +3186,55 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
* of filter_ref_kind().
*/
if (filter->kind == FILTER_REFS_BRANCHES)
- ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata);
+ ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/heads/", NULL,
+ fn, cb_data);
else if (filter->kind == FILTER_REFS_REMOTES)
- ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata);
+ ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/remotes/", NULL,
+ fn, cb_data);
else if (filter->kind == FILTER_REFS_TAGS)
- ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata);
- else if (filter->kind & FILTER_REFS_ALL)
- ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata);
- if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
- head_ref(ref_filter_handler, &ref_cbdata);
+ ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/tags/", NULL, fn,
+ cb_data);
+ else if (filter->kind & FILTER_REFS_REGULAR)
+ ret = for_each_fullref_in_pattern(filter, fn, cb_data);
+
+ /*
+ * When printing all ref types, HEAD is already included,
+ * so we don't want to print HEAD again.
+ */
+ if (!ret && !(filter->kind & FILTER_REFS_ROOT_REFS) &&
+ (filter->kind & FILTER_REFS_DETACHED_HEAD))
+ refs_head_ref(get_main_ref_store(the_repository), fn,
+ cb_data);
}
- clear_contains_cache(&ref_cbdata.contains_cache);
- clear_contains_cache(&ref_cbdata.no_contains_cache);
+ clear_contains_cache(&filter->internal.contains_cache);
+ clear_contains_cache(&filter->internal.no_contains_cache);
+
+ return ret;
+}
+
+/*
+ * 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
+ * as per the given ref_filter structure and finally store the
+ * filtered refs in the ref_array structure.
+ */
+int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
+{
+ struct ref_filter_cbdata ref_cbdata;
+ int save_commit_buffer_orig;
+ int ret = 0;
+
+ ref_cbdata.array = array;
+ ref_cbdata.filter = filter;
+
+ save_commit_buffer_orig = save_commit_buffer;
+ save_commit_buffer = 0;
+
+ ret = do_filter_refs(filter, type, filter_one, &ref_cbdata);
/* Filters that need revision walking */
reach_filter(array, &filter->reachable_from, INCLUDE_REACHED);
@@ -2941,6 +3244,72 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
return ret;
}
+struct ref_sorting {
+ struct ref_sorting *next;
+ int atom; /* index into used_atom array (internal) */
+ enum ref_sorting_order sort_flags;
+};
+
+static inline int can_do_iterative_format(struct ref_filter *filter,
+ struct ref_sorting *sorting,
+ struct ref_format *format)
+{
+ /*
+ * Reference backends sort patterns lexicographically by refname, so if
+ * the sorting options ask for exactly that we are able to do iterative
+ * formatting.
+ *
+ * Note that we do not have to worry about multiple name patterns,
+ * either. Those get sorted and deduplicated eventually in
+ * `refs_for_each_fullref_in_prefixes()`, so we return names in the
+ * correct ordering here, too.
+ */
+ if (sorting && (sorting->next ||
+ sorting->sort_flags ||
+ used_atom[sorting->atom].atom_type != ATOM_REFNAME))
+ return 0;
+
+ /*
+ * Filtering & formatting results within a single ref iteration
+ * callback is not compatible with options that require
+ * post-processing a filtered ref_array. These include:
+ * - filtering on reachability
+ * - including ahead-behind information in the formatted output
+ */
+ return !(filter->reachable_from ||
+ filter->unreachable_from ||
+ format->bases.nr ||
+ format->is_base_tips.nr);
+}
+
+void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
+ struct ref_sorting *sorting,
+ struct ref_format *format)
+{
+ if (can_do_iterative_format(filter, sorting, format)) {
+ int save_commit_buffer_orig;
+ struct ref_filter_and_format_cbdata ref_cbdata = {
+ .filter = filter,
+ .format = format,
+ };
+
+ save_commit_buffer_orig = save_commit_buffer;
+ save_commit_buffer = 0;
+
+ do_filter_refs(filter, type, filter_and_format_one, &ref_cbdata);
+
+ save_commit_buffer = save_commit_buffer_orig;
+ } else {
+ struct ref_array array = { 0 };
+ filter_refs(&array, filter, type);
+ filter_ahead_behind(the_repository, format, &array);
+ filter_is_base(the_repository, format, &array);
+ ref_array_sort(sorting, &array);
+ print_formatted_ref_array(&array, format);
+ ref_array_clear(&array);
+ }
+}
+
static int compare_detached_head(struct ref_array_item *a, struct ref_array_item *b)
{
if (!(a->kind ^ b->kind))
@@ -2966,12 +3335,6 @@ static int memcasecmp(const void *vs1, const void *vs2, size_t n)
return 0;
}
-struct ref_sorting {
- struct ref_sorting *next;
- int atom; /* index into used_atom array (internal) */
- enum ref_sorting_order sort_flags;
-};
-
static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
{
struct atom_value *va, *vb;
@@ -3058,7 +3421,8 @@ void ref_sorting_set_sort_flags_all(struct ref_sorting *sorting,
void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
{
- QSORT_S(array->items, array->nr, compare_refs, sorting);
+ if (sorting)
+ QSORT_S(array->items, array->nr, compare_refs, sorting);
}
static void append_literal(const char *cp, const char *ep, struct ref_formatting_state *state)
@@ -3129,6 +3493,29 @@ int format_ref_array_item(struct ref_array_item *info,
return 0;
}
+void print_formatted_ref_array(struct ref_array *array, struct ref_format *format)
+{
+ int total;
+ struct strbuf output = STRBUF_INIT, err = STRBUF_INIT;
+
+ total = format->array_opts.max_count;
+ if (!total || array->nr < total)
+ total = array->nr;
+ for (int i = 0; i < total; i++) {
+ strbuf_reset(&err);
+ strbuf_reset(&output);
+ if (format_ref_array_item(array->items[i], format, &output, &err))
+ die("%s", err.buf);
+ if (output.len || !format->array_opts.omit_empty) {
+ fwrite(output.buf, 1, output.len, stdout);
+ putchar('\n');
+ }
+ }
+
+ strbuf_release(&err);
+ strbuf_release(&output);
+}
+
void pretty_print_ref(const char *name, const struct object_id *oid,
struct ref_format *format)
{
@@ -3164,18 +3551,6 @@ static int parse_sorting_atom(const char *atom)
return res;
}
-/* If no sorting option is given, use refname to sort as default */
-static struct ref_sorting *ref_default_sorting(void)
-{
- static const char cstr_name[] = "refname";
-
- struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));
-
- sorting->next = NULL;
- sorting->atom = parse_sorting_atom(cstr_name);
- return sorting;
-}
-
static void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
{
struct ref_sorting *s;
@@ -3199,9 +3574,7 @@ struct ref_sorting *ref_sorting_options(struct string_list *options)
struct string_list_item *item;
struct ref_sorting *sorting = NULL, **tail = &sorting;
- if (!options->nr) {
- sorting = ref_default_sorting();
- } else {
+ if (options->nr) {
for_each_string_list_item(item, options)
parse_ref_sorting(tail, item->string);
}
@@ -3264,3 +3637,16 @@ void ref_filter_clear(struct ref_filter *filter)
free_commit_list(filter->unreachable_from);
ref_filter_init(filter);
}
+
+void ref_format_init(struct ref_format *format)
+{
+ struct ref_format blank = REF_FORMAT_INIT;
+ memcpy(format, &blank, sizeof(blank));
+}
+
+void ref_format_clear(struct ref_format *format)
+{
+ string_list_clear(&format->bases, 0);
+ string_list_clear(&format->is_base_tips, 0);
+ ref_format_init(format);
+}
diff --git a/ref-filter.h b/ref-filter.h
index 1524bc463a..754038ab07 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -3,10 +3,10 @@
#include "gettext.h"
#include "oid-array.h"
-#include "refs.h"
#include "commit.h"
#include "string-list.h"
#include "strvec.h"
+#include "commit-reach.h"
/* Quoting styles */
#define QUOTE_NONE 0
@@ -19,10 +19,13 @@
#define FILTER_REFS_BRANCHES 0x0004
#define FILTER_REFS_REMOTES 0x0008
#define FILTER_REFS_OTHERS 0x0010
-#define FILTER_REFS_ALL (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \
+#define FILTER_REFS_REGULAR (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \
FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)
#define FILTER_REFS_DETACHED_HEAD 0x0020
-#define FILTER_REFS_KIND_MASK (FILTER_REFS_ALL | FILTER_REFS_DETACHED_HEAD)
+#define FILTER_REFS_PSEUDOREFS 0x0040
+#define FILTER_REFS_ROOT_REFS 0x0080
+#define FILTER_REFS_KIND_MASK (FILTER_REFS_REGULAR | FILTER_REFS_DETACHED_HEAD | \
+ FILTER_REFS_PSEUDOREFS | FILTER_REFS_ROOT_REFS)
struct atom_value;
struct ref_sorting;
@@ -45,6 +48,7 @@ struct ref_array_item {
struct commit *commit;
struct atom_value *value;
struct ahead_behind_count **counts;
+ char **is_base;
char refname[FLEX_ARRAY];
};
@@ -75,6 +79,11 @@ struct ref_filter {
lines;
int abbrev,
verbose;
+
+ struct {
+ struct contains_cache contains_cache;
+ struct contains_cache no_contains_cache;
+ } internal;
};
struct ref_format {
@@ -92,6 +101,14 @@ struct ref_format {
/* List of bases for ahead-behind counts. */
struct string_list bases;
+
+ /* List of bases for is-base indicators. */
+ struct string_list is_base_tips;
+
+ struct {
+ int max_count;
+ int omit_empty;
+ } array_opts;
};
#define REF_FILTER_INIT { \
@@ -101,6 +118,7 @@ struct ref_format {
#define REF_FORMAT_INIT { \
.use_color = -1, \
.bases = STRING_LIST_INIT_DUP, \
+ .is_base_tips = STRING_LIST_INIT_DUP, \
}
/* Macros for checking --merged and --no-merged options */
@@ -126,6 +144,14 @@ struct ref_format {
* filtered refs in the ref_array structure.
*/
int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type);
+/*
+ * Filter refs using the given ref_filter and type, sort the contents
+ * according to the given ref_sorting, format the filtered refs with the
+ * given ref_format, and print them to stdout.
+ */
+void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
+ struct ref_sorting *sorting,
+ struct ref_format *format);
/* Clear all memory allocated to ref_array */
void ref_array_clear(struct ref_array *array);
/* Used to verify if the given format is correct and to parse out the used atoms */
@@ -151,6 +177,12 @@ char *get_head_description(void);
void setup_ref_filter_porcelain_msg(void);
/*
+ * Print up to maxcount ref_array elements to stdout using the given
+ * ref_format.
+ */
+void print_formatted_ref_array(struct ref_array *array, struct ref_format *format);
+
+/*
* Print a single ref, outside of any ref-filter. Note that the
* name must be a fully qualified refname.
*/
@@ -176,7 +208,20 @@ void filter_ahead_behind(struct repository *r,
struct ref_format *format,
struct ref_array *array);
+/*
+ * If the provided format includes is-base atoms, then compute the base checks
+ * for those tips against all refs.
+ *
+ * If this is not called, then any is-base atoms will be blank.
+ */
+void filter_is_base(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);
+void ref_format_init(struct ref_format *format);
+void ref_format_clear(struct ref_format *format);
+
#endif /* REF_FILTER_H */
diff --git a/reflog-walk.c b/reflog-walk.c
index d216f6f966..c7070b13b0 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit.h"
#include "refs.h"
@@ -67,24 +69,32 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)
struct complete_reflogs *reflogs =
xcalloc(1, sizeof(struct complete_reflogs));
reflogs->ref = xstrdup(ref);
- for_each_reflog_ent(ref, read_one_reflog, reflogs);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository), ref,
+ read_one_reflog, reflogs);
if (reflogs->nr == 0) {
const char *name;
void *name_to_free;
- name = name_to_free = resolve_refdup(ref, RESOLVE_REF_READING,
- NULL, NULL);
+ name = name_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+ ref,
+ RESOLVE_REF_READING,
+ NULL, NULL);
if (name) {
- for_each_reflog_ent(name, read_one_reflog, reflogs);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ name, read_one_reflog,
+ reflogs);
free(name_to_free);
}
}
if (reflogs->nr == 0) {
char *refname = xstrfmt("refs/%s", ref);
- for_each_reflog_ent(refname, read_one_reflog, reflogs);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ refname, read_one_reflog, reflogs);
if (reflogs->nr == 0) {
free(refname);
refname = xstrfmt("refs/heads/%s", ref);
- for_each_reflog_ent(refname, read_one_reflog, reflogs);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ refname, read_one_reflog,
+ reflogs);
}
free(refname);
}
@@ -174,7 +184,8 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
else {
if (*branch == '\0') {
free(branch);
- branch = resolve_refdup("HEAD", 0, NULL, NULL);
+ branch = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, NULL);
if (!branch)
die("no current branch");
@@ -182,8 +193,8 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
reflogs = read_complete_reflog(branch);
if (!reflogs || reflogs->nr == 0) {
char *b;
- int ret = dwim_log(branch, strlen(branch),
- NULL, &b);
+ int ret = repo_dwim_log(the_repository, branch, strlen(branch),
+ NULL, &b);
if (ret > 1)
free(b);
else if (ret == 1) {
@@ -223,7 +234,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
void get_reflog_selector(struct strbuf *sb,
struct reflog_walk_info *reflog_info,
- const struct date_mode *dmode, int force_date,
+ struct date_mode dmode, int force_date,
int shorten)
{
struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
@@ -236,7 +247,9 @@ void get_reflog_selector(struct strbuf *sb,
if (shorten) {
if (!commit_reflog->reflogs->short_ref)
commit_reflog->reflogs->short_ref
- = shorten_unambiguous_ref(commit_reflog->reflogs->ref, 0);
+ = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ commit_reflog->reflogs->ref,
+ 0);
printed_ref = commit_reflog->reflogs->short_ref;
} else {
printed_ref = commit_reflog->reflogs->ref;
@@ -297,7 +310,7 @@ timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info)
}
void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
- const struct date_mode *dmode, int force_date)
+ struct date_mode dmode, int force_date)
{
if (reflog_info && reflog_info->last_commit_reflog) {
struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
diff --git a/reflog-walk.h b/reflog-walk.h
index 4d93a26957..989583dc55 100644
--- a/reflog-walk.h
+++ b/reflog-walk.h
@@ -10,14 +10,14 @@ void reflog_walk_info_release(struct reflog_walk_info *info);
int add_reflog_for_walk(struct reflog_walk_info *info,
struct commit *commit, const char *name);
void show_reflog_message(struct reflog_walk_info *info, int,
- const struct date_mode *, int force_date);
+ struct date_mode, int force_date);
void get_reflog_message(struct strbuf *sb,
struct reflog_walk_info *reflog_info);
const char *get_reflog_ident(struct reflog_walk_info *reflog_info);
timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info);
void get_reflog_selector(struct strbuf *sb,
struct reflog_walk_info *reflog_info,
- const struct date_mode *dmode, int force_date,
+ struct date_mode dmode, int force_date,
int shorten);
int reflog_walk_empty(struct reflog_walk_info *walk);
diff --git a/reflog.c b/reflog.c
index 9ad50e7d93..aeab78c9b7 100644
--- a/reflog.c
+++ b/reflog.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "object-store-ll.h"
@@ -6,7 +8,6 @@
#include "revision.h"
#include "tree.h"
#include "tree-walk.h"
-#include "worktree.h"
/* Remember to update object flag allocation in object.h */
#define INCOMPLETE (1u<<10)
@@ -40,7 +41,7 @@ static int tree_is_complete(const struct object_id *oid)
tree->buffer = data;
tree->size = size;
}
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
complete = 1;
while (tree_entry(&desc, &entry)) {
if (!repo_has_object_file(the_repository, &entry.oid) ||
@@ -209,7 +210,7 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb)
cb->mark_list = leftover;
}
-static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
+static int is_unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
{
/*
* We may or may not have the commit yet - if not, look it
@@ -264,7 +265,7 @@ int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
return 1;
case UE_NORMAL:
case UE_HEAD:
- if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
+ if (is_unreachable(cb, old_commit, ooid) || is_unreachable(cb, new_commit, noid))
return 1;
break;
}
@@ -299,6 +300,7 @@ int should_expire_reflog_ent_verbose(struct object_id *ooid,
}
static int push_tip_to_list(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags, void *cb_data)
{
@@ -331,7 +333,8 @@ void reflog_expiry_prepare(const char *refname,
if (!cb->cmd.expire_unreachable || is_head(refname)) {
cb->unreachable_expire_kind = UE_HEAD;
} else {
- commit = lookup_commit(the_repository, oid);
+ commit = lookup_commit_reference_gently(the_repository,
+ oid, 1);
if (commit && is_null_oid(&commit->object.oid))
commit = NULL;
cb->unreachable_expire_kind = commit ? UE_NORMAL : UE_ALWAYS;
@@ -344,7 +347,8 @@ void reflog_expiry_prepare(const char *refname,
case UE_ALWAYS:
return;
case UE_HEAD:
- for_each_ref(push_tip_to_list, &cb->tips);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ push_tip_to_list, &cb->tips);
for (elem = cb->tips; elem; elem = elem->next)
commit_list_insert(elem->item, &cb->mark_list);
break;
@@ -409,7 +413,7 @@ int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)
if (!spec)
return error(_("not a reflog: %s"), rev);
- if (!dwim_log(rev, spec - rev, NULL, &ref)) {
+ if (!repo_dwim_log(the_repository, rev, spec - rev, NULL, &ref)) {
status |= error(_("no reflog for '%s'"), rev);
goto cleanup;
}
@@ -417,19 +421,22 @@ int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)
recno = strtoul(spec + 2, &ep, 10);
if (*ep == '}') {
cmd.recno = -recno;
- for_each_reflog_ent(ref, count_reflog_ent, &cmd);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ ref, count_reflog_ent, &cmd);
} else {
cmd.expire_total = approxidate(spec + 2);
- for_each_reflog_ent(ref, count_reflog_ent, &cmd);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ ref, count_reflog_ent, &cmd);
cmd.expire_total = 0;
}
cb.cmd = cmd;
- status |= reflog_expire(ref, flags,
- reflog_expiry_prepare,
- should_prune_fn,
- reflog_expiry_cleanup,
- &cb);
+ status |= refs_reflog_expire(get_main_ref_store(the_repository), ref,
+ flags,
+ reflog_expiry_prepare,
+ should_prune_fn,
+ reflog_expiry_cleanup,
+ &cb);
cleanup:
free(ref);
diff --git a/refs.c b/refs.c
index fcae5dddc6..762f3e324d 100644
--- a/refs.c
+++ b/refs.c
@@ -2,11 +2,13 @@
* The backend-independent part of the reference module.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "config.h"
#include "environment.h"
-#include "hashmap.h"
+#include "strmap.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
@@ -19,11 +21,10 @@
#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 "repo-settings.h"
#include "setup.h"
#include "sigchain.h"
#include "date.h"
@@ -33,17 +34,35 @@
/*
* List of all available backends
*/
-static struct ref_storage_be *refs_backends = &refs_be_files;
+static const struct ref_storage_be *refs_backends[] = {
+ [REF_STORAGE_FORMAT_FILES] = &refs_be_files,
+ [REF_STORAGE_FORMAT_REFTABLE] = &refs_be_reftable,
+};
-static struct ref_storage_be *find_ref_storage_backend(const char *name)
+static const struct ref_storage_be *find_ref_storage_backend(
+ enum ref_storage_format ref_storage_format)
{
- struct ref_storage_be *be;
- for (be = refs_backends; be; be = be->next)
- if (!strcmp(be->name, name))
- return be;
+ if (ref_storage_format < ARRAY_SIZE(refs_backends))
+ return refs_backends[ref_storage_format];
return NULL;
}
+enum ref_storage_format ref_storage_format_by_name(const char *name)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(refs_backends); i++)
+ if (refs_backends[i] && !strcmp(refs_backends[i]->name, name))
+ return i;
+ return REF_STORAGE_FORMAT_UNKNOWN;
+}
+
+const char *ref_storage_format_to_name(enum ref_storage_format ref_storage_format)
+{
+ const struct ref_storage_be *be = find_ref_storage_backend(ref_storage_format);
+ if (!be)
+ return "unknown";
+ return be->name;
+}
+
/*
* How to handle various characters in refnames:
* 0: An acceptable character for refs
@@ -142,7 +161,7 @@ void update_ref_namespace(enum ref_namespace namespace, char *ref)
{
struct ref_namespace_info *info = &ref_namespace[namespace];
if (info->ref_updated)
- free(info->ref);
+ free((char *)info->ref);
info->ref = ref;
info->ref_updated = 1;
}
@@ -299,6 +318,12 @@ int check_refname_format(const char *refname, int flags)
return check_or_sanitize_refname(refname, flags, NULL);
}
+int refs_fsck(struct ref_store *refs, struct fsck_options *o,
+ struct worktree *wt)
+{
+ return refs->be->fsck(refs, o, wt);
+}
+
void sanitize_refname_component(const char *refname, struct strbuf *out)
{
if (check_or_sanitize_refname(refname, REFNAME_ALLOW_ONELEVEL, out))
@@ -367,14 +392,6 @@ char *refs_resolve_refdup(struct ref_store *refs,
return xstrdup_or_null(result);
}
-char *resolve_refdup(const char *refname, int resolve_flags,
- struct object_id *oid, int *flags)
-{
- return refs_resolve_refdup(get_main_ref_store(the_repository),
- refname, resolve_flags,
- oid, flags);
-}
-
/* The argument to for_each_filter_refs */
struct for_each_ref_filter {
const char *pattern;
@@ -383,19 +400,18 @@ struct for_each_ref_filter {
void *cb_data;
};
-int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags)
+int refs_read_ref_full(struct ref_store *refs, const char *refname,
+ int resolve_flags, struct object_id *oid, int *flags)
{
- struct ref_store *refs = get_main_ref_store(the_repository);
-
if (refs_resolve_ref_unsafe(refs, refname, resolve_flags,
oid, flags))
return 0;
return -1;
}
-int read_ref(const char *refname, struct object_id *oid)
+int refs_read_ref(struct ref_store *refs, const char *refname, struct object_id *oid)
{
- return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL);
+ return refs_read_ref_full(refs, refname, RESOLVE_REF_READING, oid, NULL);
}
int refs_ref_exists(struct ref_store *refs, const char *refname)
@@ -404,12 +420,7 @@ int refs_ref_exists(struct ref_store *refs, const char *refname)
NULL, NULL);
}
-int ref_exists(const char *refname)
-{
- return refs_ref_exists(get_main_ref_store(the_repository), refname);
-}
-
-static int for_each_filter_refs(const char *refname,
+static int for_each_filter_refs(const char *refname, const char *referent,
const struct object_id *oid,
int flags, void *data)
{
@@ -419,38 +430,18 @@ static int for_each_filter_refs(const char *refname,
return 0;
if (filter->prefix)
skip_prefix(refname, filter->prefix, &refname);
- return filter->fn(refname, oid, flags, filter->cb_data);
-}
-
-enum peel_status peel_object(const struct object_id *name, struct object_id *oid)
-{
- struct object *o = lookup_unknown_object(the_repository, name);
-
- if (o->type == OBJ_NONE) {
- int type = oid_object_info(the_repository, name, NULL);
- if (type < 0 || !object_as_type(o, type, 0))
- return PEEL_INVALID;
- }
-
- if (o->type != OBJ_TAG)
- return PEEL_NON_TAG;
-
- o = deref_tag_noverify(o);
- if (!o)
- return PEEL_INVALID;
-
- oidcpy(oid, &o->oid);
- return PEEL_PEELED;
+ return filter->fn(refname, referent, oid, flags, filter->cb_data);
}
struct warn_if_dangling_data {
+ struct ref_store *refs;
FILE *fp;
const char *refname;
const struct string_list *refnames;
const char *msg_fmt;
};
-static int warn_if_dangling_symref(const char *refname,
+static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags, void *cb_data)
{
@@ -460,7 +451,7 @@ static int warn_if_dangling_symref(const char *refname,
if (!(flags & REF_ISSYMREF))
return 0;
- resolves_to = resolve_ref_unsafe(refname, 0, NULL, NULL);
+ resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL);
if (!resolves_to
|| (d->refname
? strcmp(resolves_to, d->refname)
@@ -473,26 +464,28 @@ static int warn_if_dangling_symref(const char *refname,
return 0;
}
-void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
+void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,
+ const char *msg_fmt, const char *refname)
{
- struct warn_if_dangling_data data;
-
- data.fp = fp;
- data.refname = refname;
- data.refnames = NULL;
- data.msg_fmt = msg_fmt;
- for_each_rawref(warn_if_dangling_symref, &data);
+ struct warn_if_dangling_data data = {
+ .refs = refs,
+ .fp = fp,
+ .refname = refname,
+ .msg_fmt = msg_fmt,
+ };
+ refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
}
-void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)
+void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
+ const char *msg_fmt, const struct string_list *refnames)
{
- struct warn_if_dangling_data data;
-
- data.fp = fp;
- data.refname = NULL;
- data.refnames = refnames;
- data.msg_fmt = msg_fmt;
- for_each_rawref(warn_if_dangling_symref, &data);
+ struct warn_if_dangling_data data = {
+ .refs = refs,
+ .fp = fp,
+ .refnames = refnames,
+ .msg_fmt = msg_fmt,
+ };
+ refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
}
int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@@ -500,32 +493,17 @@ int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
return refs_for_each_ref_in(refs, "refs/tags/", fn, cb_data);
}
-int for_each_tag_ref(each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_tag_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/heads/", fn, cb_data);
}
-int for_each_branch_ref(each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_branch_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return refs_for_each_ref_in(refs, "refs/remotes/", fn, cb_data);
}
-int for_each_remote_ref(each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_remote_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-int head_ref_namespaced(each_ref_fn fn, void *cb_data)
+int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
struct strbuf buf = STRBUF_INIT;
int ret = 0;
@@ -533,8 +511,8 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)
int flag;
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
- if (!read_ref_full(buf.buf, RESOLVE_REF_READING, &oid, &flag))
- ret = fn(buf.buf, &oid, flag, cb_data);
+ if (!refs_read_ref_full(refs, buf.buf, RESOLVE_REF_READING, &oid, &flag))
+ ret = fn(buf.buf, NULL, &oid, flag, cb_data);
strbuf_release(&buf);
return ret;
@@ -566,8 +544,8 @@ void normalize_glob_ref(struct string_list_item *item, const char *prefix,
strbuf_release(&normalized_pattern);
}
-int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
- const char *prefix, void *cb_data)
+int refs_for_each_glob_ref_in(struct ref_store *refs, each_ref_fn fn,
+ const char *pattern, const char *prefix, void *cb_data)
{
struct strbuf real_pattern = STRBUF_INIT;
struct for_each_ref_filter filter;
@@ -590,15 +568,16 @@ 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(for_each_filter_refs, &filter);
+ ret = refs_for_each_ref(refs, for_each_filter_refs, &filter);
strbuf_release(&real_pattern);
return ret;
}
-int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
+int refs_for_each_glob_ref(struct ref_store *refs, each_ref_fn fn,
+ const char *pattern, void *cb_data)
{
- return for_each_glob_ref_in(fn, pattern, NULL, cb_data);
+ return refs_for_each_glob_ref_in(refs, fn, pattern, NULL, cb_data);
}
const char *prettify_refname(const char *name)
@@ -694,16 +673,6 @@ char *repo_default_branch_name(struct repository *r, int quiet)
return ret;
}
-const char *git_default_branch_name(int quiet)
-{
- static char *ret;
-
- if (!ret)
- ret = repo_default_branch_name(the_repository, quiet);
-
- return ret;
-}
-
/*
* *string and *len will only be substituted, and *string returned (for
* later free()ing) if the string passed in is a magic short-hand form
@@ -762,7 +731,7 @@ int expand_ref(struct repository *repo, const char *str, int len,
if (r) {
if (!refs_found++)
*ref = xstrdup(r);
- if (!warn_ambiguous_refs)
+ if (!repo_settings_get_warn_ambiguous_refs(repo))
break;
} else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) {
warning(_("ignoring dangling symref %s"), fullref.buf);
@@ -807,7 +776,7 @@ int repo_dwim_log(struct repository *r, const char *str, int len,
if (oid)
oidcpy(oid, &hash);
}
- if (!warn_ambiguous_refs)
+ if (!repo_settings_get_warn_ambiguous_refs(r))
break;
}
strbuf_release(&path);
@@ -815,11 +784,6 @@ int repo_dwim_log(struct repository *r, const char *str, int len,
return logs_found;
}
-int dwim_log(const char *str, int len, struct object_id *oid, char **log)
-{
- return repo_dwim_log(the_repository, str, len, oid, log);
-}
-
int is_per_worktree_ref(const char *refname)
{
return starts_with(refname, "refs/worktree/") ||
@@ -827,7 +791,22 @@ int is_per_worktree_ref(const char *refname)
starts_with(refname, "refs/rewritten/");
}
-static int is_pseudoref_syntax(const char *refname)
+int is_pseudo_ref(const char *refname)
+{
+ static const char * const pseudo_refs[] = {
+ "FETCH_HEAD",
+ "MERGE_HEAD",
+ };
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(pseudo_refs); i++)
+ if (!strcmp(refname, pseudo_refs[i]))
+ return 1;
+
+ return 0;
+}
+
+static int is_root_ref_syntax(const char *refname)
{
const char *c;
@@ -836,15 +815,37 @@ static int is_pseudoref_syntax(const char *refname)
return 0;
}
- /*
- * HEAD is not a pseudoref, but it certainly uses the
- * pseudoref syntax.
- */
return 1;
}
+int is_root_ref(const char *refname)
+{
+ static const char *const irregular_root_refs[] = {
+ "HEAD",
+ "AUTO_MERGE",
+ "BISECT_EXPECTED_REV",
+ "NOTES_MERGE_PARTIAL",
+ "NOTES_MERGE_REF",
+ "MERGE_AUTOSTASH",
+ };
+ size_t i;
+
+ if (!is_root_ref_syntax(refname) ||
+ is_pseudo_ref(refname))
+ return 0;
+
+ if (ends_with(refname, "_HEAD"))
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE(irregular_root_refs); i++)
+ if (!strcmp(refname, irregular_root_refs[i]))
+ return 1;
+
+ return 0;
+}
+
static int is_current_worktree_ref(const char *ref) {
- return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);
+ return is_root_ref_syntax(ref) || is_per_worktree_ref(ref);
}
enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
@@ -918,10 +919,10 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- transaction = ref_store_transaction_begin(refs, &err);
+ transaction = ref_store_transaction_begin(refs, 0, &err);
if (!transaction ||
ref_transaction_delete(transaction, refname, old_oid,
- flags, msg, &err) ||
+ NULL, flags, msg, &err) ||
ref_transaction_commit(transaction, &err)) {
error("%s", err.buf);
ref_transaction_free(transaction);
@@ -933,13 +934,6 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
return 0;
}
-int delete_ref(const char *msg, const char *refname,
- const struct object_id *old_oid, unsigned int flags)
-{
- return refs_delete_ref(get_main_ref_store(the_repository), msg, refname,
- old_oid, flags);
-}
-
static void copy_reflog_msg(struct strbuf *sb, const char *msg)
{
char c;
@@ -965,7 +959,8 @@ static char *normalize_reflog_message(const char *msg)
return strbuf_detach(&sb, NULL);
}
-int should_autocreate_reflog(const char *refname)
+int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
+ const char *refname)
{
switch (log_all_ref_updates) {
case LOG_REFS_ALWAYS:
@@ -1022,55 +1017,40 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
const char *message, void *cb_data)
{
struct read_ref_at_cb *cb = cb_data;
- int reached_count;
cb->tz = tz;
cb->date = timestamp;
- /*
- * It is not possible for cb->cnt == 0 on the first iteration because
- * that special case is handled in read_ref_at().
- */
- if (cb->cnt > 0)
- cb->cnt--;
- reached_count = cb->cnt == 0 && !is_null_oid(ooid);
- if (timestamp <= cb->at_time || reached_count) {
+ if (timestamp <= cb->at_time || cb->cnt == 0) {
set_read_ref_cutoffs(cb, timestamp, tz, message);
/*
* we have not yet updated cb->[n|o]oid so they still
* hold the values for the previous record.
*/
- if (!is_null_oid(&cb->ooid) && !oideq(&cb->ooid, noid))
- warning(_("log for ref %s has gap after %s"),
+ if (!is_null_oid(&cb->ooid)) {
+ oidcpy(cb->oid, noid);
+ if (!oideq(&cb->ooid, noid))
+ warning(_("log for ref %s has gap after %s"),
cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
- if (reached_count)
- oidcpy(cb->oid, ooid);
- else if (!is_null_oid(&cb->ooid) || cb->date == cb->at_time)
+ }
+ else if (cb->date == cb->at_time)
oidcpy(cb->oid, noid);
else if (!oideq(noid, cb->oid))
warning(_("log for ref %s unexpectedly ended on %s"),
cb->refname, show_date(cb->date, cb->tz,
DATE_MODE(RFC2822)));
+ cb->reccnt++;
+ oidcpy(&cb->ooid, ooid);
+ oidcpy(&cb->noid, noid);
cb->found_it = 1;
+ return 1;
}
cb->reccnt++;
oidcpy(&cb->ooid, ooid);
oidcpy(&cb->noid, noid);
- return cb->found_it;
-}
-
-static int read_ref_at_ent_newest(struct object_id *ooid UNUSED,
- struct object_id *noid,
- const char *email UNUSED,
- timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
-{
- struct read_ref_at_cb *cb = cb_data;
-
- set_read_ref_cutoffs(cb, timestamp, tz, message);
- oidcpy(cb->oid, noid);
- /* We just want the first entry */
- return 1;
+ if (cb->cnt > 0)
+ cb->cnt--;
+ return 0;
}
static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
@@ -1082,7 +1062,7 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid
set_read_ref_cutoffs(cb, timestamp, tz, message);
oidcpy(cb->oid, ooid);
- if (is_null_oid(cb->oid))
+ if (cb->at_time && is_null_oid(cb->oid))
oidcpy(cb->oid, noid);
/* We just want the first entry */
return 1;
@@ -1105,14 +1085,24 @@ int read_ref_at(struct ref_store *refs, const char *refname,
cb.cutoff_cnt = cutoff_cnt;
cb.oid = oid;
- if (cb.cnt == 0) {
- refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent_newest, &cb);
- return 0;
- }
-
refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent, &cb);
if (!cb.reccnt) {
+ if (cnt == 0) {
+ /*
+ * The caller asked for ref@{0}, and we had no entries.
+ * It's a bit subtle, but in practice all callers have
+ * prepped the "oid" field with the current value of
+ * the ref, which is the most reasonable fallback.
+ *
+ * We'll put dummy values into the out-parameters (so
+ * they're not just uninitialized garbage), and the
+ * caller can take our return value as a hint that
+ * we did not find any such reflog.
+ */
+ set_read_ref_cutoffs(&cb, 0, 0, "empty reflog");
+ return 1;
+ }
if (flags & GET_OID_QUIETLY)
exit(128);
else
@@ -1127,6 +1117,7 @@ int read_ref_at(struct ref_store *refs, const char *refname,
}
struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs,
+ unsigned int flags,
struct strbuf *err)
{
struct ref_transaction *tr;
@@ -1134,14 +1125,10 @@ struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs,
CALLOC_ARRAY(tr, 1);
tr->ref_store = refs;
+ tr->flags = flags;
return tr;
}
-struct ref_transaction *ref_transaction_begin(struct strbuf *err)
-{
- return ref_store_transaction_begin(get_main_ref_store(the_repository), err);
-}
-
void ref_transaction_free(struct ref_transaction *transaction)
{
size_t i;
@@ -1164,6 +1151,8 @@ void ref_transaction_free(struct ref_transaction *transaction)
for (i = 0; i < transaction->nr; i++) {
free(transaction->updates[i]->msg);
+ free((char *)transaction->updates[i]->new_target);
+ free((char *)transaction->updates[i]->old_target);
free(transaction->updates[i]);
}
free(transaction->updates);
@@ -1175,6 +1164,7 @@ struct ref_update *ref_transaction_add_update(
const char *refname, unsigned int flags,
const struct object_id *new_oid,
const struct object_id *old_oid,
+ const char *new_target, const char *old_target,
const char *msg)
{
struct ref_update *update;
@@ -1182,17 +1172,26 @@ struct ref_update *ref_transaction_add_update(
if (transaction->state != REF_TRANSACTION_OPEN)
BUG("update called for transaction that is not open");
+ if (old_oid && old_target)
+ BUG("only one of old_oid and old_target should be non NULL");
+ if (new_oid && new_target)
+ BUG("only one of new_oid and new_target should be non NULL");
+
FLEX_ALLOC_STR(update, refname, refname);
ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
transaction->updates[transaction->nr++] = update;
update->flags = flags;
- if (flags & REF_HAVE_NEW)
+ update->new_target = xstrdup_or_null(new_target);
+ update->old_target = xstrdup_or_null(old_target);
+ if ((flags & REF_HAVE_NEW) && new_oid)
oidcpy(&update->new_oid, new_oid);
- if (flags & REF_HAVE_OLD)
+ if ((flags & REF_HAVE_OLD) && old_oid)
oidcpy(&update->old_oid, old_oid);
- update->msg = normalize_reflog_message(msg);
+ if (!(flags & REF_SKIP_CREATE_REFLOG))
+ update->msg = normalize_reflog_message(msg);
+
return update;
}
@@ -1200,11 +1199,19 @@ int ref_transaction_update(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
const struct object_id *old_oid,
+ const char *new_target,
+ const char *old_target,
unsigned int flags, const char *msg,
struct strbuf *err)
{
assert(err);
+ if ((flags & REF_FORCE_CREATE_REFLOG) &&
+ (flags & REF_SKIP_CREATE_REFLOG)) {
+ strbuf_addstr(err, _("refusing to force and skip creation of reflog"));
+ return -1;
+ }
+
if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&
((new_oid && !is_null_oid(new_oid)) ?
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
@@ -1214,6 +1221,13 @@ int ref_transaction_update(struct ref_transaction *transaction,
return -1;
}
+ if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&
+ is_pseudo_ref(refname)) {
+ strbuf_addf(err, _("refusing to update pseudoref '%s'"),
+ refname);
+ return -1;
+ }
+
if (flags & ~REF_TRANSACTION_UPDATE_ALLOWED_FLAGS)
BUG("illegal flags 0x%x passed to ref_transaction_update()", flags);
@@ -1225,49 +1239,68 @@ int ref_transaction_update(struct ref_transaction *transaction,
flags &= REF_TRANSACTION_UPDATE_ALLOWED_FLAGS;
flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
+ flags |= (new_target ? REF_HAVE_NEW : 0) | (old_target ? REF_HAVE_OLD : 0);
ref_transaction_add_update(transaction, refname, flags,
- new_oid, old_oid, msg);
+ new_oid, old_oid, new_target,
+ old_target, msg);
return 0;
}
int ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
+ const char *new_target,
unsigned int flags, const char *msg,
struct strbuf *err)
{
- if (!new_oid || is_null_oid(new_oid)) {
- strbuf_addf(err, "'%s' has a null OID", refname);
+ if (new_oid && new_target)
+ BUG("create called with both new_oid and new_target set");
+ if ((!new_oid || is_null_oid(new_oid)) && !new_target) {
+ strbuf_addf(err, "'%s' has neither a valid OID nor a target", refname);
return 1;
}
return ref_transaction_update(transaction, refname, new_oid,
- null_oid(), flags, msg, err);
+ null_oid(), new_target, NULL, flags,
+ msg, err);
}
int ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
const struct object_id *old_oid,
- unsigned int flags, const char *msg,
+ const char *old_target,
+ unsigned int flags,
+ const char *msg,
struct strbuf *err)
{
if (old_oid && is_null_oid(old_oid))
BUG("delete called with old_oid set to zeros");
+ if (old_oid && old_target)
+ BUG("delete called with both old_oid and old_target set");
+ if (old_target && !(flags & REF_NO_DEREF))
+ BUG("delete cannot operate on symrefs with deref mode");
return ref_transaction_update(transaction, refname,
null_oid(), old_oid,
- flags, msg, err);
+ NULL, old_target, flags,
+ msg, err);
}
int ref_transaction_verify(struct ref_transaction *transaction,
const char *refname,
const struct object_id *old_oid,
+ const char *old_target,
unsigned int flags,
struct strbuf *err)
{
- if (!old_oid)
- BUG("verify called with old_oid set to NULL");
+ if (!old_target && !old_oid)
+ BUG("verify called with old_oid and old_target set to NULL");
+ if (old_oid && old_target)
+ BUG("verify called with both old_oid and old_target set");
+ if (old_target && !(flags & REF_NO_DEREF))
+ BUG("verify cannot operate on symrefs with deref mode");
return ref_transaction_update(transaction, refname,
NULL, old_oid,
+ NULL, old_target,
flags, NULL, err);
}
@@ -1280,10 +1313,10 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
struct strbuf err = STRBUF_INIT;
int ret = 0;
- t = ref_store_transaction_begin(refs, &err);
+ t = ref_store_transaction_begin(refs, 0, &err);
if (!t ||
- ref_transaction_update(t, refname, new_oid, old_oid, flags, msg,
- &err) ||
+ ref_transaction_update(t, refname, new_oid, old_oid, NULL, NULL,
+ flags, msg, &err) ||
ref_transaction_commit(t, &err)) {
ret = 1;
ref_transaction_free(t);
@@ -1310,15 +1343,6 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
return 0;
}
-int update_ref(const char *msg, const char *refname,
- const struct object_id *new_oid,
- const struct object_id *old_oid,
- unsigned int flags, enum action_on_err onerr)
-{
- return refs_update_ref(get_main_ref_store(the_repository), msg, refname, new_oid,
- old_oid, flags, onerr);
-}
-
/*
* Check that the string refname matches a rule of the form
* "{prefix}%.*s{suffix}". So "foo/bar/baz" would match the rule
@@ -1420,12 +1444,6 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
return xstrdup(refname);
}
-char *shorten_unambiguous_ref(const char *refname, int strict)
-{
- return refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
- refname, strict);
-}
-
int parse_hide_refs_config(const char *var, const char *value, const char *section,
struct strvec *hide_refs)
{
@@ -1504,6 +1522,19 @@ const char **hidden_refs_to_excludes(const struct strvec *hide_refs)
return hide_refs->v;
}
+const char **get_namespaced_exclude_patterns(const char **exclude_patterns,
+ const char *namespace,
+ struct strvec *out)
+{
+ if (!namespace || !*namespace || !exclude_patterns || !*exclude_patterns)
+ return exclude_patterns;
+
+ for (size_t i = 0; exclude_patterns[i]; i++)
+ strvec_pushf(out, "%s%s", namespace, exclude_patterns[i]);
+
+ return out->v;
+}
+
const char *find_descendant_ref(const char *dirname,
const struct string_list *extras,
const struct string_list *skip)
@@ -1539,16 +1570,11 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
if (refs_resolve_ref_unsafe(refs, "HEAD", RESOLVE_REF_READING,
&oid, &flag))
- return fn("HEAD", &oid, flag, cb_data);
+ return fn("HEAD", NULL, &oid, flag, cb_data);
return 0;
}
-int head_ref(each_ref_fn fn, void *cb_data)
-{
- return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
struct ref_iterator *refs_ref_iterator_begin(
struct ref_store *refs,
const char *prefix,
@@ -1577,60 +1603,15 @@ struct ref_iterator *refs_ref_iterator_begin(
if (trim)
iter = prefix_ref_iterator_begin(iter, "", trim);
- /* Sanity check for subclasses: */
- if (!iter->ordered)
- BUG("reference iterator is not ordered");
-
return iter;
}
-/*
- * Call fn for each reference in the specified submodule for which the
- * refname begins with prefix. If trim is non-zero, then trim that
- * many characters off the beginning of each refname before passing
- * the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to
- * include broken references in the iteration. If fn ever returns a
- * non-zero value, stop the iteration and return that value;
- * otherwise, return 0.
- */
-static int do_for_each_repo_ref(struct repository *r, const char *prefix,
- each_repo_ref_fn fn, int trim, int flags,
- void *cb_data)
-{
- struct ref_iterator *iter;
- struct ref_store *refs = get_main_ref_store(r);
-
- if (!refs)
- return 0;
-
- iter = refs_ref_iterator_begin(refs, prefix, NULL, trim, flags);
-
- return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
-}
-
-struct do_for_each_ref_help {
- each_ref_fn *fn;
- void *cb_data;
-};
-
-static int do_for_each_ref_helper(struct repository *r UNUSED,
- const char *refname,
- const struct object_id *oid,
- int flags,
- void *cb_data)
-{
- struct do_for_each_ref_help *hp = cb_data;
-
- return hp->fn(refname, oid, flags, hp->cb_data);
-}
-
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)
{
struct ref_iterator *iter;
- struct do_for_each_ref_help hp = { fn, cb_data };
if (!refs)
return 0;
@@ -1638,8 +1619,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
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);
+ return do_for_each_ref_iterator(iter, fn, cb_data);
}
int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@@ -1647,28 +1627,12 @@ int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *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)
-{
- return refs_for_each_ref(get_main_ref_store(the_repository), fn, 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, NULL, fn, strlen(prefix), 0, cb_data);
}
-int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, 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, 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)
@@ -1676,23 +1640,31 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
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)
+int refs_for_each_replace_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
- return do_for_each_repo_ref(r, git_replace_ref_base, fn,
- strlen(git_replace_ref_base),
- DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
+ return do_for_each_ref(refs, git_replace_ref_base, NULL, fn,
+ strlen(git_replace_ref_base),
+ DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
-int for_each_namespaced_ref(const char **exclude_patterns,
- each_ref_fn fn, void *cb_data)
+int refs_for_each_namespaced_ref(struct ref_store *refs,
+ const char **exclude_patterns,
+ each_ref_fn fn, void *cb_data)
{
- struct strbuf buf = STRBUF_INIT;
+ struct strvec namespaced_exclude_patterns = STRVEC_INIT;
+ struct strbuf prefix = STRBUF_INIT;
int ret;
- strbuf_addf(&buf, "%srefs/", get_git_namespace());
- ret = do_for_each_ref(get_main_ref_store(the_repository),
- buf.buf, exclude_patterns, fn, 0, 0, cb_data);
- strbuf_release(&buf);
+
+ exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
+ get_git_namespace(),
+ &namespaced_exclude_patterns);
+
+ strbuf_addf(&prefix, "%srefs/", get_git_namespace());
+ ret = do_for_each_ref(refs, prefix.buf, exclude_patterns, fn, 0, 0, cb_data);
+
+ strvec_clear(&namespaced_exclude_patterns);
+ strbuf_release(&prefix);
return ret;
}
@@ -1702,9 +1674,11 @@ int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
-int for_each_rawref(each_ref_fn fn, void *cb_data)
+int refs_for_each_include_root_refs(struct ref_store *refs, each_ref_fn fn,
+ void *cb_data)
{
- return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
+ return do_for_each_ref(refs, "", NULL, fn, 0,
+ DO_FOR_EACH_INCLUDE_ROOT_REFS, cb_data);
}
static int qsort_strcmp(const void *va, const void *vb)
@@ -1771,6 +1745,7 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data)
{
+ struct strvec namespaced_exclude_patterns = STRVEC_INIT;
struct string_list prefixes = STRING_LIST_INIT_DUP;
struct string_list_item *prefix;
struct strbuf buf = STRBUF_INIT;
@@ -1782,6 +1757,10 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
strbuf_addstr(&buf, namespace);
namespace_len = buf.len;
+ exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
+ namespace,
+ &namespaced_exclude_patterns);
+
for_each_string_list_item(prefix, &prefixes) {
strbuf_addstr(&buf, prefix->string);
ret = refs_for_each_fullref_in(ref_store, buf.buf,
@@ -1791,6 +1770,7 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
strbuf_setlen(&buf, namespace_len);
}
+ strvec_clear(&namespaced_exclude_patterns);
string_list_clear(&prefixes, 0);
strbuf_release(&buf);
return ret;
@@ -1806,11 +1786,13 @@ static int refs_read_special_head(struct ref_store *ref_store,
int result = -1;
strbuf_addf(&full_path, "%s/%s", ref_store->gitdir, refname);
- if (strbuf_read_file(&content, full_path.buf, 0) < 0)
+ if (strbuf_read_file(&content, full_path.buf, 0) < 0) {
+ *failure_errno = errno;
goto done;
+ }
- result = parse_loose_ref_contents(content.buf, oid, referent, type,
- failure_errno);
+ result = parse_loose_ref_contents(ref_store->repo->hash_algo, content.buf,
+ oid, referent, type, NULL, failure_errno);
done:
strbuf_release(&full_path);
@@ -1823,10 +1805,9 @@ int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
unsigned int *type, int *failure_errno)
{
assert(failure_errno);
- if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) {
+ if (is_pseudo_ref(refname))
return refs_read_special_head(ref_store, refname, oid, referent,
type, failure_errno);
- }
return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
type, failure_errno);
@@ -1894,7 +1875,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
failure_errno != ENOTDIR)
return NULL;
- oidclr(oid);
+ oidclr(oid, refs->repo->hash_algo);
if (*flags & REF_BAD_NAME)
*flags |= REF_ISBROKEN;
return refname;
@@ -1904,7 +1885,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
if (!(read_flags & REF_ISSYMREF)) {
if (*flags & REF_BAD_NAME) {
- oidclr(oid);
+ oidclr(oid, refs->repo->hash_algo);
*flags |= REF_ISBROKEN;
}
return refname;
@@ -1912,7 +1893,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
refname = sb_refname.buf;
if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
- oidclr(oid);
+ oidclr(oid, refs->repo->hash_algo);
return refname;
}
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
@@ -1928,28 +1909,24 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
}
/* backend functions */
-int refs_init_db(struct strbuf *err)
+int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)
{
- struct ref_store *refs = get_main_ref_store(the_repository);
-
- return refs->be->init_db(refs, err);
+ return refs->be->create_on_disk(refs, flags, err);
}
-const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
- struct object_id *oid, int *flags)
+int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err)
{
- return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname,
- resolve_flags, oid, flags);
+ return refs->be->remove_on_disk(refs, err);
}
-int resolve_gitlink_ref(const char *submodule, const char *refname,
- struct object_id *oid)
+int repo_resolve_gitlink_ref(struct repository *r,
+ const char *submodule, const char *refname,
+ struct object_id *oid)
{
struct ref_store *refs;
int flags;
- refs = get_submodule_ref_store(submodule);
-
+ refs = repo_get_submodule_ref_store(r, submodule);
if (!refs)
return -1;
@@ -1959,87 +1936,49 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
return 0;
}
-struct ref_store_hash_entry
-{
- struct hashmap_entry ent;
-
- struct ref_store *refs;
-
- /* NUL-terminated identifier of the ref store: */
- char name[FLEX_ARRAY];
-};
-
-static int ref_store_hash_cmp(const void *cmp_data UNUSED,
- const struct hashmap_entry *eptr,
- const struct hashmap_entry *entry_or_key,
- const void *keydata)
-{
- const struct ref_store_hash_entry *e1, *e2;
- const char *name;
-
- e1 = container_of(eptr, const struct ref_store_hash_entry, ent);
- e2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent);
- name = keydata ? keydata : e2->name;
-
- return strcmp(e1->name, name);
-}
-
-static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
- const char *name, struct ref_store *refs)
-{
- struct ref_store_hash_entry *entry;
-
- FLEX_ALLOC_STR(entry, name, name);
- hashmap_entry_init(&entry->ent, strhash(name));
- entry->refs = refs;
- return entry;
-}
-
-/* A hashmap of ref_stores, stored by submodule name: */
-static struct hashmap submodule_ref_stores;
-
-/* A hashmap of ref_stores, stored by worktree id: */
-static struct hashmap worktree_ref_stores;
-
/*
* Look up a ref store by name. If that ref_store hasn't been
* registered yet, return NULL.
*/
-static struct ref_store *lookup_ref_store_map(struct hashmap *map,
+static struct ref_store *lookup_ref_store_map(struct strmap *map,
const char *name)
{
- struct ref_store_hash_entry *entry;
- unsigned int hash;
+ struct strmap_entry *entry;
- if (!map->tablesize)
+ if (!map->map.tablesize)
/* It's initialized on demand in register_ref_store(). */
return NULL;
- hash = strhash(name);
- entry = hashmap_get_entry_from_hash(map, hash, name,
- struct ref_store_hash_entry, ent);
- return entry ? entry->refs : NULL;
+ entry = strmap_get_entry(map, name);
+ return entry ? entry->value : NULL;
}
/*
* Create, record, and return a ref_store instance for the specified
- * gitdir.
+ * gitdir using the given ref storage format.
*/
static struct ref_store *ref_store_init(struct repository *repo,
+ enum ref_storage_format format,
const char *gitdir,
unsigned int flags)
{
- const char *be_name = "files";
- struct ref_storage_be *be = find_ref_storage_backend(be_name);
+ const struct ref_storage_be *be;
struct ref_store *refs;
+ be = find_ref_storage_backend(format);
if (!be)
- BUG("reference backend %s is unknown", be_name);
+ BUG("reference backend is unknown");
refs = be->init(repo, gitdir, flags);
return refs;
}
+void ref_store_release(struct ref_store *ref_store)
+{
+ ref_store->be->release(ref_store);
+ free(ref_store->gitdir);
+}
+
struct ref_store *get_main_ref_store(struct repository *r)
{
if (r->refs_private)
@@ -2048,7 +1987,8 @@ struct ref_store *get_main_ref_store(struct repository *r)
if (!r->gitdir)
BUG("attempting to get main_ref_store outside of repository");
- r->refs_private = ref_store_init(r, r->gitdir, REF_STORE_ALL_CAPS);
+ r->refs_private = ref_store_init(r, r->ref_storage_format,
+ r->gitdir, REF_STORE_ALL_CAPS);
r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
return r->refs_private;
}
@@ -2057,22 +1997,19 @@ struct ref_store *get_main_ref_store(struct repository *r)
* Associate a ref store with a name. It is a fatal error to call this
* function twice for the same name.
*/
-static void register_ref_store_map(struct hashmap *map,
+static void register_ref_store_map(struct strmap *map,
const char *type,
struct ref_store *refs,
const char *name)
{
- struct ref_store_hash_entry *entry;
-
- if (!map->tablesize)
- hashmap_init(map, ref_store_hash_cmp, NULL, 0);
-
- entry = alloc_ref_store_hash_entry(name, refs);
- if (hashmap_put(map, &entry->ent))
+ if (!map->map.tablesize)
+ strmap_init(map);
+ if (strmap_put(map, name, refs))
BUG("%s ref_store '%s' initialized twice", type, name);
}
-struct ref_store *get_submodule_ref_store(const char *submodule)
+struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
+ const char *submodule)
{
struct strbuf submodule_sb = STRBUF_INIT;
struct ref_store *refs;
@@ -2093,7 +2030,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
/* We need to strip off one or more trailing slashes */
submodule = to_free = xmemdupz(submodule, len);
- refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
+ refs = lookup_ref_store_map(&repo->submodule_ref_stores, submodule);
if (refs)
goto done;
@@ -2105,20 +2042,16 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
goto done;
subrepo = xmalloc(sizeof(*subrepo));
- /*
- * NEEDSWORK: Make get_submodule_ref_store() work with arbitrary
- * superprojects other than the_repository. This probably should be
- * done by making it take a struct repository * parameter instead of a
- * submodule path.
- */
- if (repo_submodule_init(subrepo, the_repository, submodule,
+
+ if (repo_submodule_init(subrepo, repo, submodule,
null_oid())) {
free(subrepo);
goto done;
}
- refs = ref_store_init(subrepo, submodule_sb.buf,
+ refs = ref_store_init(subrepo, subrepo->ref_storage_format,
+ submodule_sb.buf,
REF_STORE_READ | REF_STORE_ODB);
- register_ref_store_map(&submodule_ref_stores, "submodule",
+ register_ref_store_map(&repo->submodule_ref_stores, "submodule",
refs, submodule);
done:
@@ -2134,25 +2067,29 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
const char *id;
if (wt->is_current)
- return get_main_ref_store(the_repository);
+ return get_main_ref_store(wt->repo);
id = wt->id ? wt->id : "/";
- refs = lookup_ref_store_map(&worktree_ref_stores, id);
+ refs = lookup_ref_store_map(&wt->repo->worktree_ref_stores, id);
if (refs)
return refs;
- if (wt->id)
- refs = ref_store_init(the_repository,
- git_common_path("worktrees/%s", wt->id),
- REF_STORE_ALL_CAPS);
- else
- refs = ref_store_init(the_repository,
- get_git_common_dir(),
- REF_STORE_ALL_CAPS);
+ if (wt->id) {
+ struct strbuf common_path = STRBUF_INIT;
+ strbuf_git_common_path(&common_path, wt->repo,
+ "worktrees/%s", wt->id);
+ refs = ref_store_init(wt->repo, wt->repo->ref_storage_format,
+ common_path.buf, REF_STORE_ALL_CAPS);
+ strbuf_release(&common_path);
+ } else {
+ refs = ref_store_init(wt->repo, wt->repo->ref_storage_format,
+ wt->repo->commondir, REF_STORE_ALL_CAPS);
+ }
if (refs)
- register_ref_store_map(&worktree_ref_stores, "worktree",
- refs, id);
+ register_ref_store_map(&wt->repo->worktree_ref_stores,
+ "worktree", refs, id);
+
return refs;
}
@@ -2170,36 +2107,37 @@ int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts)
return refs->be->pack_refs(refs, opts);
}
-int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)
+int peel_iterated_oid(struct repository *r, const struct object_id *base, struct object_id *peeled)
{
if (current_ref_iter &&
(current_ref_iter->oid == base ||
oideq(current_ref_iter->oid, base)))
return ref_iterator_peel(current_ref_iter, peeled);
- return peel_object(base, peeled) ? -1 : 0;
+ return peel_object(r, base, peeled) ? -1 : 0;
}
-int refs_create_symref(struct ref_store *refs,
- const char *ref_target,
- const char *refs_heads_master,
- const char *logmsg)
+int refs_update_symref(struct ref_store *refs, const char *ref,
+ const char *target, const char *logmsg)
{
- char *msg;
- int retval;
+ struct ref_transaction *transaction;
+ struct strbuf err = STRBUF_INIT;
+ int ret = 0;
- msg = normalize_reflog_message(logmsg);
- retval = refs->be->create_symref(refs, ref_target, refs_heads_master,
- msg);
- free(msg);
- return retval;
-}
+ transaction = ref_store_transaction_begin(refs, 0, &err);
+ if (!transaction ||
+ ref_transaction_update(transaction, ref, NULL, NULL,
+ target, NULL, REF_NO_DEREF,
+ logmsg, &err) ||
+ ref_transaction_commit(transaction, &err)) {
+ ret = error("%s", err.buf);
+ }
-int create_symref(const char *ref_target, const char *refs_heads_master,
- const char *logmsg)
-{
- return refs_create_symref(get_main_ref_store(the_repository), ref_target,
- refs_heads_master, logmsg);
+ strbuf_release(&err);
+ if (transaction)
+ ref_transaction_free(transaction);
+
+ return ret;
}
int ref_update_reject_duplicates(struct string_list *refnames,
@@ -2233,7 +2171,7 @@ static int run_transaction_hook(struct ref_transaction *transaction,
const char *hook;
int ret = 0, i;
- hook = find_hook("reference-transaction");
+ hook = find_hook(transaction->ref_store->repo, "reference-transaction");
if (!hook)
return ret;
@@ -2251,11 +2189,26 @@ static int run_transaction_hook(struct ref_transaction *transaction,
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
+ if (update->flags & REF_LOG_ONLY)
+ continue;
+
strbuf_reset(&buf);
- strbuf_addf(&buf, "%s %s %s\n",
- oid_to_hex(&update->old_oid),
- oid_to_hex(&update->new_oid),
- update->refname);
+
+ if (!(update->flags & REF_HAVE_OLD))
+ strbuf_addf(&buf, "%s ", oid_to_hex(null_oid()));
+ else if (update->old_target)
+ strbuf_addf(&buf, "ref:%s ", update->old_target);
+ else
+ strbuf_addf(&buf, "%s ", oid_to_hex(&update->old_oid));
+
+ if (!(update->flags & REF_HAVE_NEW))
+ strbuf_addf(&buf, "%s ", oid_to_hex(null_oid()));
+ else if (update->new_target)
+ strbuf_addf(&buf, "ref:%s ", update->new_target);
+ else
+ strbuf_addf(&buf, "%s ", oid_to_hex(&update->new_oid));
+
+ strbuf_addf(&buf, "%s\n", update->refname);
if (write_in_full(proc.in, buf.buf, buf.len) < 0) {
if (errno != EPIPE) {
@@ -2367,7 +2320,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
}
ret = refs->be->transaction_finish(refs, transaction, err);
- if (!ret)
+ if (!ret && !(transaction->flags & REF_TRANSACTION_FLAG_INITIAL))
run_transaction_hook(transaction, "committed");
return ret;
}
@@ -2376,6 +2329,7 @@ int refs_verify_refname_available(struct ref_store *refs,
const char *refname,
const struct string_list *extras,
const struct string_list *skip,
+ unsigned int initial_transaction,
struct strbuf *err)
{
const char *slash;
@@ -2384,8 +2338,6 @@ int refs_verify_refname_available(struct ref_store *refs,
struct strbuf referent = STRBUF_INIT;
struct object_id oid;
unsigned int type;
- struct ref_iterator *iter;
- int ok;
int ret = -1;
/*
@@ -2415,7 +2367,8 @@ int refs_verify_refname_available(struct ref_store *refs,
if (skip && string_list_has_string(skip, dirname.buf))
continue;
- if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent,
+ if (!initial_transaction &&
+ !refs_read_raw_ref(refs, dirname.buf, &oid, &referent,
&type, &ignore_errno)) {
strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
dirname.buf, refname);
@@ -2440,21 +2393,26 @@ 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, NULL, 0,
- DO_FOR_EACH_INCLUDE_BROKEN);
- while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- if (skip &&
- string_list_has_string(skip, iter->refname))
- continue;
+ if (!initial_transaction) {
+ struct ref_iterator *iter;
+ int ok;
- strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
- iter->refname, refname);
- ref_iterator_abort(iter);
- goto cleanup;
- }
+ 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 &&
+ string_list_has_string(skip, iter->refname))
+ continue;
+
+ strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
+ iter->refname, refname);
+ ref_iterator_abort(iter);
+ goto cleanup;
+ }
- if (ok != ITER_DONE)
- BUG("error while iterating over references");
+ if (ok != ITER_DONE)
+ BUG("error while iterating over references");
+ }
extra_refname = find_descendant_ref(dirname.buf, extras, skip);
if (extra_refname)
@@ -2469,20 +2427,29 @@ cleanup:
return ret;
}
-int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
+struct do_for_each_reflog_help {
+ each_reflog_fn *fn;
+ void *cb_data;
+};
+
+static int do_for_each_reflog_helper(const char *refname,
+ const char *referent UNUSED,
+ const struct object_id *oid UNUSED,
+ int flags UNUSED,
+ void *cb_data)
+{
+ struct do_for_each_reflog_help *hp = cb_data;
+ return hp->fn(refname, hp->cb_data);
+}
+
+int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_data)
{
struct ref_iterator *iter;
- struct do_for_each_ref_help hp = { fn, cb_data };
+ struct do_for_each_reflog_help hp = { fn, cb_data };
iter = refs->be->reflog_iterator_begin(refs);
- return do_for_each_repo_ref_iterator(the_repository, iter,
- do_for_each_ref_helper, &hp);
-}
-
-int for_each_reflog(each_ref_fn fn, void *cb_data)
-{
- return refs_for_each_reflog(get_main_ref_store(the_repository), fn, cb_data);
+ return do_for_each_ref_iterator(iter, do_for_each_reflog_helper, &hp);
}
int refs_for_each_reflog_ent_reverse(struct ref_store *refs,
@@ -2494,58 +2461,28 @@ int refs_for_each_reflog_ent_reverse(struct ref_store *refs,
fn, cb_data);
}
-int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,
- void *cb_data)
-{
- return refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository),
- refname, fn, cb_data);
-}
-
int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,
each_reflog_ent_fn fn, void *cb_data)
{
return refs->be->for_each_reflog_ent(refs, refname, fn, cb_data);
}
-int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn,
- void *cb_data)
-{
- return refs_for_each_reflog_ent(get_main_ref_store(the_repository), refname,
- fn, cb_data);
-}
-
int refs_reflog_exists(struct ref_store *refs, const char *refname)
{
return refs->be->reflog_exists(refs, refname);
}
-int reflog_exists(const char *refname)
-{
- return refs_reflog_exists(get_main_ref_store(the_repository), refname);
-}
-
int refs_create_reflog(struct ref_store *refs, const char *refname,
struct strbuf *err)
{
return refs->be->create_reflog(refs, refname, err);
}
-int safe_create_reflog(const char *refname, struct strbuf *err)
-{
- return refs_create_reflog(get_main_ref_store(the_repository), refname,
- err);
-}
-
int refs_delete_reflog(struct ref_store *refs, const char *refname)
{
return refs->be->delete_reflog(refs, refname);
}
-int delete_reflog(const char *refname)
-{
- return refs_delete_reflog(get_main_ref_store(the_repository), refname);
-}
-
int refs_reflog_expire(struct ref_store *refs,
const char *refname,
unsigned int flags,
@@ -2559,27 +2496,6 @@ int refs_reflog_expire(struct ref_store *refs,
cleanup_fn, policy_cb_data);
}
-int reflog_expire(const char *refname,
- unsigned int flags,
- reflog_expiry_prepare_fn prepare_fn,
- reflog_expiry_should_prune_fn should_prune_fn,
- reflog_expiry_cleanup_fn cleanup_fn,
- void *policy_cb_data)
-{
- return refs_reflog_expire(get_main_ref_store(the_repository),
- refname, flags,
- prepare_fn, should_prune_fn,
- cleanup_fn, policy_cb_data);
-}
-
-int initial_ref_transaction_commit(struct ref_transaction *transaction,
- struct strbuf *err)
-{
- struct ref_store *refs = transaction->ref_store;
-
- return refs->be->initial_transaction_commit(refs, transaction, err);
-}
-
void ref_transaction_for_each_queued_update(struct ref_transaction *transaction,
ref_transaction_for_each_queued_update_fn cb,
void *cb_data)
@@ -2599,19 +2515,55 @@ void ref_transaction_for_each_queued_update(struct ref_transaction *transaction,
int refs_delete_refs(struct ref_store *refs, const char *logmsg,
struct string_list *refnames, unsigned int flags)
{
+ struct ref_transaction *transaction;
+ struct strbuf err = STRBUF_INIT;
+ struct string_list_item *item;
+ int ret = 0, failures = 0;
char *msg;
- int retval;
+
+ if (!refnames->nr)
+ return 0;
msg = normalize_reflog_message(logmsg);
- retval = refs->be->delete_refs(refs, msg, refnames, flags);
- free(msg);
- return retval;
-}
-int delete_refs(const char *msg, struct string_list *refnames,
- unsigned int flags)
-{
- return refs_delete_refs(get_main_ref_store(the_repository), msg, refnames, flags);
+ /*
+ * Since we don't check the references' old_oids, the
+ * individual updates can't fail, so we can pack all of the
+ * updates into a single transaction.
+ */
+ transaction = ref_store_transaction_begin(refs, 0, &err);
+ if (!transaction) {
+ ret = error("%s", err.buf);
+ goto out;
+ }
+
+ for_each_string_list_item(item, refnames) {
+ ret = ref_transaction_delete(transaction, item->string,
+ NULL, NULL, flags, msg, &err);
+ if (ret) {
+ warning(_("could not delete reference %s: %s"),
+ item->string, err.buf);
+ strbuf_reset(&err);
+ failures = 1;
+ }
+ }
+
+ ret = ref_transaction_commit(transaction, &err);
+ if (ret) {
+ if (refnames->nr == 1)
+ error(_("could not delete reference %s: %s"),
+ refnames->items[0].string, err.buf);
+ else
+ error(_("could not delete references: %s"), err.buf);
+ }
+
+out:
+ if (!ret && failures)
+ ret = -1;
+ ref_transaction_free(transaction);
+ strbuf_release(&err);
+ free(msg);
+ return ret;
}
int refs_rename_ref(struct ref_store *refs, const char *oldref,
@@ -2626,11 +2578,6 @@ int refs_rename_ref(struct ref_store *refs, const char *oldref,
return retval;
}
-int rename_ref(const char *oldref, const char *newref, const char *logmsg)
-{
- return refs_rename_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
-}
-
int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
const char *newref, const char *logmsg)
{
@@ -2643,7 +2590,360 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
return retval;
}
-int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg)
+const char *ref_update_original_update_refname(struct ref_update *update)
+{
+ while (update->parent_update)
+ update = update->parent_update;
+
+ return update->refname;
+}
+
+int ref_update_has_null_new_value(struct ref_update *update)
+{
+ return !update->new_target && is_null_oid(&update->new_oid);
+}
+
+int ref_update_check_old_target(const char *referent, struct ref_update *update,
+ struct strbuf *err)
{
- return refs_copy_existing_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
+ if (!update->old_target)
+ BUG("called without old_target set");
+
+ if (!strcmp(referent, update->old_target))
+ return 0;
+
+ if (!strcmp(referent, ""))
+ strbuf_addf(err, "verifying symref target: '%s': "
+ "reference is missing but expected %s",
+ ref_update_original_update_refname(update),
+ update->old_target);
+ else
+ strbuf_addf(err, "verifying symref target: '%s': "
+ "is at %s but expected %s",
+ ref_update_original_update_refname(update),
+ referent, update->old_target);
+ return -1;
}
+
+struct migration_data {
+ struct ref_store *old_refs;
+ struct ref_transaction *transaction;
+ struct strbuf *errbuf;
+};
+
+static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+ int flags, void *cb_data)
+{
+ struct migration_data *data = cb_data;
+ struct strbuf symref_target = STRBUF_INIT;
+ int ret;
+
+ if (flags & REF_ISSYMREF) {
+ ret = refs_read_symbolic_ref(data->old_refs, refname, &symref_target);
+ if (ret < 0)
+ goto done;
+
+ ret = ref_transaction_update(data->transaction, refname, NULL, null_oid(),
+ symref_target.buf, NULL,
+ REF_SKIP_CREATE_REFLOG | REF_NO_DEREF, NULL, data->errbuf);
+ if (ret < 0)
+ goto done;
+ } else {
+ ret = ref_transaction_create(data->transaction, refname, oid, NULL,
+ REF_SKIP_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION,
+ NULL, data->errbuf);
+ if (ret < 0)
+ goto done;
+ }
+
+done:
+ strbuf_release(&symref_target);
+ return ret;
+}
+
+static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf)
+{
+ struct strbuf from_buf = STRBUF_INIT, to_buf = STRBUF_INIT;
+ size_t from_len, to_len;
+ DIR *from_dir;
+ int ret;
+
+ from_dir = opendir(from_path);
+ if (!from_dir) {
+ strbuf_addf(errbuf, "could not open source directory '%s': %s",
+ from_path, strerror(errno));
+ ret = -1;
+ goto done;
+ }
+
+ strbuf_addstr(&from_buf, from_path);
+ strbuf_complete(&from_buf, '/');
+ from_len = from_buf.len;
+
+ strbuf_addstr(&to_buf, to_path);
+ strbuf_complete(&to_buf, '/');
+ to_len = to_buf.len;
+
+ while (1) {
+ struct dirent *ent;
+
+ errno = 0;
+ ent = readdir(from_dir);
+ if (!ent)
+ break;
+
+ if (!strcmp(ent->d_name, ".") ||
+ !strcmp(ent->d_name, ".."))
+ continue;
+
+ strbuf_setlen(&from_buf, from_len);
+ strbuf_addstr(&from_buf, ent->d_name);
+
+ strbuf_setlen(&to_buf, to_len);
+ strbuf_addstr(&to_buf, ent->d_name);
+
+ ret = rename(from_buf.buf, to_buf.buf);
+ if (ret < 0) {
+ strbuf_addf(errbuf, "could not link file '%s' to '%s': %s",
+ from_buf.buf, to_buf.buf, strerror(errno));
+ goto done;
+ }
+ }
+
+ if (errno) {
+ strbuf_addf(errbuf, "could not read entry from directory '%s': %s",
+ from_path, strerror(errno));
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ strbuf_release(&from_buf);
+ strbuf_release(&to_buf);
+ if (from_dir)
+ closedir(from_dir);
+ return ret;
+}
+
+static int count_reflogs(const char *reflog UNUSED, void *payload)
+{
+ size_t *reflog_count = payload;
+ (*reflog_count)++;
+ return 0;
+}
+
+static int has_worktrees(void)
+{
+ struct worktree **worktrees = get_worktrees();
+ int ret = 0;
+ size_t i;
+
+ for (i = 0; worktrees[i]; i++) {
+ if (is_main_worktree(worktrees[i]))
+ continue;
+ ret = 1;
+ }
+
+ free_worktrees(worktrees);
+ return ret;
+}
+
+int repo_migrate_ref_storage_format(struct repository *repo,
+ enum ref_storage_format format,
+ unsigned int flags,
+ struct strbuf *errbuf)
+{
+ struct ref_store *old_refs = NULL, *new_refs = NULL;
+ struct ref_transaction *transaction = NULL;
+ struct strbuf new_gitdir = STRBUF_INIT;
+ struct migration_data data;
+ size_t reflog_count = 0;
+ int did_migrate_refs = 0;
+ int ret;
+
+ if (repo->ref_storage_format == format) {
+ strbuf_addstr(errbuf, "current and new ref storage format are equal");
+ ret = -1;
+ goto done;
+ }
+
+ old_refs = get_main_ref_store(repo);
+
+ /*
+ * We do not have any interfaces that would allow us to write many
+ * reflog entries. Once we have them we can remove this restriction.
+ */
+ if (refs_for_each_reflog(old_refs, count_reflogs, &reflog_count) < 0) {
+ strbuf_addstr(errbuf, "cannot count reflogs");
+ ret = -1;
+ goto done;
+ }
+ if (reflog_count) {
+ strbuf_addstr(errbuf, "migrating reflogs is not supported yet");
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * Worktrees complicate the migration because every worktree has a
+ * separate ref storage. While it should be feasible to implement, this
+ * is pushed out to a future iteration.
+ *
+ * TODO: we should really be passing the caller-provided repository to
+ * `has_worktrees()`, but our worktree subsystem doesn't yet support
+ * that.
+ */
+ if (has_worktrees()) {
+ strbuf_addstr(errbuf, "migrating repositories with worktrees is not supported yet");
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * The overall logic looks like this:
+ *
+ * 1. Set up a new temporary directory and initialize it with the new
+ * format. This is where all refs will be migrated into.
+ *
+ * 2. Enumerate all refs and write them into the new ref storage.
+ * This operation is safe as we do not yet modify the main
+ * repository.
+ *
+ * 3. If we're in dry-run mode then we are done and can hand over the
+ * directory to the caller for inspection. If not, we now start
+ * with the destructive part.
+ *
+ * 4. Delete the old ref storage from disk. As we have a copy of refs
+ * in the new ref storage it's okay(ish) if we now get interrupted
+ * as there is an equivalent copy of all refs available.
+ *
+ * 5. Move the new ref storage files into place.
+ *
+ * 6. Change the repository format to the new ref format.
+ */
+ strbuf_addf(&new_gitdir, "%s/%s", old_refs->gitdir, "ref_migration.XXXXXX");
+ if (!mkdtemp(new_gitdir.buf)) {
+ strbuf_addf(errbuf, "cannot create migration directory: %s",
+ strerror(errno));
+ ret = -1;
+ goto done;
+ }
+
+ new_refs = ref_store_init(repo, format, new_gitdir.buf,
+ REF_STORE_ALL_CAPS);
+ ret = ref_store_create_on_disk(new_refs, 0, errbuf);
+ if (ret < 0)
+ goto done;
+
+ transaction = ref_store_transaction_begin(new_refs, REF_TRANSACTION_FLAG_INITIAL,
+ errbuf);
+ if (!transaction)
+ goto done;
+
+ data.old_refs = old_refs;
+ data.transaction = transaction;
+ data.errbuf = errbuf;
+
+ /*
+ * We need to use the internal `do_for_each_ref()` here so that we can
+ * also include broken refs and symrefs. These would otherwise be
+ * skipped silently.
+ *
+ * Ideally, we would do this call while locking the old ref storage
+ * such that there cannot be any concurrent modifications. We do not
+ * have the infra for that though, and the "files" backend does not
+ * allow for a central lock due to its design. It's thus on the user to
+ * ensure that there are no concurrent writes.
+ */
+ ret = do_for_each_ref(old_refs, "", NULL, migrate_one_ref, 0,
+ DO_FOR_EACH_INCLUDE_ROOT_REFS | DO_FOR_EACH_INCLUDE_BROKEN,
+ &data);
+ if (ret < 0)
+ goto done;
+
+ ret = ref_transaction_commit(transaction, errbuf);
+ if (ret < 0)
+ goto done;
+ did_migrate_refs = 1;
+
+ if (flags & REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN) {
+ printf(_("Finished dry-run migration of refs, "
+ "the result can be found at '%s'\n"), new_gitdir.buf);
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Release the new ref store such that any potentially-open files will
+ * be closed. This is required for platforms like Cygwin, where
+ * renaming an open file results in EPERM.
+ */
+ ref_store_release(new_refs);
+ FREE_AND_NULL(new_refs);
+
+ /*
+ * Until now we were in the non-destructive phase, where we only
+ * populated the new ref store. From hereon though we are about
+ * to get hands by deleting the old ref store and then moving
+ * the new one into place.
+ *
+ * Assuming that there were no concurrent writes, the new ref
+ * store should have all information. So if we fail from hereon
+ * we may be in an in-between state, but it would still be able
+ * to recover by manually moving remaining files from the
+ * temporary migration directory into place.
+ */
+ ret = ref_store_remove_on_disk(old_refs, errbuf);
+ if (ret < 0)
+ goto done;
+
+ ret = move_files(new_gitdir.buf, old_refs->gitdir, errbuf);
+ if (ret < 0)
+ goto done;
+
+ if (rmdir(new_gitdir.buf) < 0)
+ warning_errno(_("could not remove temporary migration directory '%s'"),
+ new_gitdir.buf);
+
+ /*
+ * We have migrated the repository, so we now need to adjust the
+ * repository format so that clients will use the new ref store.
+ * We also need to swap out the repository's main ref store.
+ */
+ initialize_repository_version(hash_algo_by_ptr(repo->hash_algo), format, 1);
+
+ /*
+ * Unset the old ref store and release it. `get_main_ref_store()` will
+ * make sure to lazily re-initialize the repository's ref store with
+ * the new format.
+ */
+ ref_store_release(old_refs);
+ FREE_AND_NULL(old_refs);
+ repo->refs_private = NULL;
+
+ ret = 0;
+
+done:
+ if (ret && did_migrate_refs) {
+ strbuf_complete(errbuf, '\n');
+ strbuf_addf(errbuf, _("migrated refs can be found at '%s'"),
+ new_gitdir.buf);
+ }
+
+ if (new_refs) {
+ ref_store_release(new_refs);
+ free(new_refs);
+ }
+ ref_transaction_free(transaction);
+ strbuf_release(&new_gitdir);
+ return ret;
+}
+
+int ref_update_expects_existing_old_ref(struct ref_update *update)
+{
+ return (update->flags & REF_HAVE_OLD) &&
+ (!is_null_oid(&update->old_oid) || update->old_target);
+}
+
diff --git a/refs.h b/refs.h
index 23211a5ea1..a5bedf48cf 100644
--- a/refs.h
+++ b/refs.h
@@ -2,17 +2,22 @@
#define REFS_H
#include "commit.h"
+#include "repository.h"
+#include "repo-settings.h"
+struct fsck_options;
struct object_id;
struct ref_store;
-struct repository;
struct strbuf;
struct string_list;
struct string_list_item;
struct worktree;
+enum ref_storage_format ref_storage_format_by_name(const char *name);
+const char *ref_storage_format_to_name(enum ref_storage_format ref_storage_format);
+
/*
- * Resolve a reference, recursively following symbolic refererences.
+ * Resolve a reference, recursively following symbolic references.
*
* Return the name of the non-symbolic reference that ultimately pointed
* at the resolved object name. The return value, if not NULL, is a
@@ -56,37 +61,27 @@ struct worktree;
* Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
* directory and do not consist of all caps and underscores cannot be
* resolved. The function returns NULL for such ref names.
- * Caps and underscores refers to the special refs, such as HEAD,
+ * Caps and underscores refers to the pseudorefs, such as HEAD,
* FETCH_HEAD and friends, that all live outside of the refs/ directory.
*/
#define RESOLVE_REF_READING 0x01
#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,
struct object_id *oid,
int *flags);
-const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
- struct object_id *oid, int *flags);
-
char *refs_resolve_refdup(struct ref_store *refs,
const char *refname, int resolve_flags,
struct object_id *oid, int *flags);
-char *resolve_refdup(const char *refname, int resolve_flags,
- struct object_id *oid, int *flags);
-int read_ref_full(const char *refname, int resolve_flags,
- struct object_id *oid, int *flags);
-int read_ref(const char *refname, struct object_id *oid);
+int refs_read_ref_full(struct ref_store *refs, const char *refname,
+ int resolve_flags, struct object_id *oid, int *flags);
+
+int refs_read_ref(struct ref_store *refs, const char *refname, struct object_id *oid);
int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
struct strbuf *referent);
@@ -106,36 +101,51 @@ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
* both "foo" and with "foo/bar/baz" but not with "foo/bar" or
* "foo/barbados".
*
+ * If `initial_transaction` is truish, then all collision checks with
+ * preexisting refs are skipped.
+ *
* extras and skip must be sorted.
*/
-
int refs_verify_refname_available(struct ref_store *refs,
const char *refname,
const struct string_list *extras,
const struct string_list *skip,
+ unsigned int initial_transaction,
struct strbuf *err);
int refs_ref_exists(struct ref_store *refs, const char *refname);
-int ref_exists(const char *refname);
-
-int should_autocreate_reflog(const char *refname);
+int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
+ const char *refname);
int is_branch(const char *refname);
-int refs_init_db(struct strbuf *err);
+#define REF_STORE_CREATE_ON_DISK_IS_WORKTREE (1 << 0)
+
+int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err);
+
+/*
+ * Release all memory and resources associated with the ref store.
+ */
+void ref_store_release(struct ref_store *ref_store);
+
+/*
+ * Remove the ref store from disk. This deletes all associated data.
+ */
+int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err);
/*
* Return the peeled value of the oid currently being iterated via
* for_each_ref(), etc. This is equivalent to calling:
*
- * peel_object(oid, &peeled);
+ * peel_object(r, oid, &peeled);
*
* with the "oid" value given to the each_ref_fn callback, except
* that some ref storage may be able to answer the query without
* actually loading the object in memory.
*/
-int peel_iterated_oid(const struct object_id *base, struct object_id *peeled);
+int peel_iterated_oid(struct repository *r,
+ const struct object_id *base, struct object_id *peeled);
/**
* Resolve refname in the nested "gitlink" repository in the specified
@@ -143,8 +153,9 @@ int peel_iterated_oid(const struct object_id *base, struct object_id *peeled);
* successful, return 0 and set oid to the name of the object;
* otherwise, return a non-zero value.
*/
-int resolve_gitlink_ref(const char *submodule, const char *refname,
- struct object_id *oid);
+int repo_resolve_gitlink_ref(struct repository *r,
+ const char *submodule, const char *refname,
+ struct object_id *oid);
/*
* Return true iff abbrev_name is a possible abbreviation for
@@ -164,15 +175,12 @@ 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);
-int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
/*
* Retrieves the default branch name for newly-initialized repositories.
*
- * The return value of `repo_default_branch_name()` is an allocated string. The
- * return value of `git_default_branch_name()` is a singleton.
+ * The return value is an allocated string.
*/
-const char *git_default_branch_name(int quiet);
char *repo_default_branch_name(struct repository *r, int quiet);
/*
@@ -209,11 +217,9 @@ char *repo_default_branch_name(struct repository *r, int quiet);
*
* Or
*
- * - Call `initial_ref_transaction_commit()` if the ref database is
- * known to be empty and have no other writers (e.g. during
- * clone). This is likely to be much faster than
- * `ref_transaction_commit()`. `ref_transaction_prepare()` should
- * *not* be called before `initial_ref_transaction_commit()`.
+ * - Call `ref_transaction_begin()` with REF_TRANSACTION_FLAG_INITIAL if the
+ * ref database is known to be empty and have no other writers (e.g. during
+ * clone). This is likely to be much faster than without the flag.
*
* - Then finally, call `ref_transaction_free()` to free the
* `ref_transaction` data structure.
@@ -229,7 +235,7 @@ char *repo_default_branch_name(struct repository *r, int quiet);
* struct strbuf err = STRBUF_INIT;
* int ret = 0;
*
- * transaction = ref_store_transaction_begin(refs, &err);
+ * transaction = ref_store_transaction_begin(refs, 0, &err);
* if (!transaction ||
* ref_transaction_update(...) ||
* ref_transaction_create(...) ||
@@ -296,20 +302,10 @@ struct ref_transaction;
* arguments is only guaranteed to be valid for the duration of a
* single callback invocation.
*/
-typedef int each_ref_fn(const char *refname,
+typedef int each_ref_fn(const char *refname, const char *referent,
const struct object_id *oid, int flags, void *cb_data);
/*
- * The same as each_ref_fn, but also with a repository argument that
- * contains the repository associated with the callback.
- */
-typedef int each_repo_ref_fn(struct repository *r,
- const char *refname,
- const struct object_id *oid,
- int flags,
- void *cb_data);
-
-/*
* The following functions invoke the specified callback function for
* each reference indicated. If the function ever returns a nonzero
* value, stop the iteration and return that value. Please note that
@@ -330,18 +326,8 @@ int refs_for_each_branch_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_remote_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
-
-/* just iterates the head ref. */
-int head_ref(each_ref_fn fn, void *cb_data);
-
-/* iterates all refs. */
-int for_each_ref(each_ref_fn fn, void *cb_data);
-
-/**
- * iterates all refs which have a defined prefix and strips that prefix from
- * the passed variable refname.
- */
-int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
+int refs_for_each_replace_ref(struct ref_store *refs,
+ each_ref_fn fn, void *cb_data);
/*
* references matching any pattern in "exclude_patterns" are omitted from the
@@ -350,7 +336,6 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *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);
-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
@@ -367,31 +352,31 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *refs,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
-/**
- * iterate refs from the respective area.
- */
-int for_each_tag_ref(each_ref_fn fn, void *cb_data);
-int for_each_branch_ref(each_ref_fn fn, void *cb_data);
-int for_each_remote_ref(each_ref_fn fn, void *cb_data);
-int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
-
/* iterates all refs that match the specified glob pattern. */
-int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
+int refs_for_each_glob_ref(struct ref_store *refs, each_ref_fn fn,
+ const char *pattern, void *cb_data);
-int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
- const char *prefix, void *cb_data);
+int refs_for_each_glob_ref_in(struct ref_store *refs, each_ref_fn fn,
+ const char *pattern, const char *prefix, void *cb_data);
+
+int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_data);
-int head_ref_namespaced(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);
+int refs_for_each_namespaced_ref(struct ref_store *refs,
+ 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);
-int for_each_rawref(each_ref_fn fn, void *cb_data);
+
+/*
+ * Iterates over all refs including root refs, i.e. pseudorefs and HEAD.
+ */
+int refs_for_each_include_root_refs(struct ref_store *refs, each_ref_fn fn,
+ void *cb_data);
/*
* Normalizes partial refs to their fully qualified form.
@@ -410,17 +395,26 @@ static inline const char *has_glob_specials(const char *pattern)
return strpbrk(pattern, "?*[");
}
-void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
-void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
- const struct string_list *refnames);
+void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,
+ const char *msg_fmt, const char *refname);
+void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
+ const char *msg_fmt, const struct string_list *refnames);
/*
* Flags for controlling behaviour of pack_refs()
* PACK_REFS_PRUNE: Prune loose refs after packing
- * PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
+ * PACK_REFS_AUTO: Pack refs on a best effort basis. The heuristics and end
+ * result are decided by the ref backend. Backends may ignore
+ * this flag and fall back to a normal repack.
*/
-#define PACK_REFS_PRUNE 0x0001
-#define PACK_REFS_ALL 0x0002
+#define PACK_REFS_PRUNE (1 << 0)
+#define PACK_REFS_AUTO (1 << 1)
+
+struct pack_refs_opts {
+ unsigned int flags;
+ struct ref_exclusions *exclusions;
+ struct string_list *includes;
+};
/*
* Write a packed-refs file for the current repository.
@@ -433,9 +427,21 @@ int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts);
*/
int refs_create_reflog(struct ref_store *refs, const char *refname,
struct strbuf *err);
-int safe_create_reflog(const char *refname, struct strbuf *err);
-/** Reads log for the value of ref during at_time. **/
+/**
+ * Reads log for the value of ref during at_time (in which case "cnt" should be
+ * negative) or the reflog "cnt" entries from the top (in which case "at_time"
+ * should be 0).
+ *
+ * If we found the reflog entry in question, returns 0 (and details of the
+ * entry can be found in the out-parameters).
+ *
+ * If we ran out of reflog entries, the out-parameters are filled with the
+ * details of the oldest entry we did find, and the function returns 1. Note
+ * that there is one important special case here! If the reflog was empty
+ * and the caller asked for the 0-th cnt, we will return "1" but leave the
+ * "oid" field untouched.
+ **/
int read_ref_at(struct ref_store *refs,
const char *refname, unsigned int flags,
timestamp_t at_time, int cnt,
@@ -444,7 +450,6 @@ int read_ref_at(struct ref_store *refs,
/** Check if a particular reflog exists */
int refs_reflog_exists(struct ref_store *refs, const char *refname);
-int reflog_exists(const char *refname);
/*
* Delete the specified reference. If old_oid is non-NULL, then
@@ -458,8 +463,6 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
const char *refname,
const struct object_id *old_oid,
unsigned int flags);
-int delete_ref(const char *msg, const char *refname,
- const struct object_id *old_oid, unsigned int flags);
/*
* Delete the specified references. If there are any problems, emit
@@ -469,12 +472,9 @@ int delete_ref(const char *msg, const char *refname,
*/
int refs_delete_refs(struct ref_store *refs, const char *msg,
struct string_list *refnames, unsigned int flags);
-int delete_refs(const char *msg, struct string_list *refnames,
- unsigned int flags);
/** Delete a reflog */
int refs_delete_reflog(struct ref_store *refs, const char *refname);
-int delete_reflog(const char *refname);
/*
* Callback to process a reflog entry found by the iteration functions (see
@@ -491,7 +491,7 @@ int delete_reflog(const char *refname);
* from UTC. Its absolute value is formed by multiplying the hour
* part by 100 and adding the minute part. For example, 1 hour ahead
* of UTC, CET == "+0100", is represented as positive one hundred (not
- * postiive sixty).
+ * positive sixty).
*
* The msg parameter is a single complete line; a reflog message given
* to refs_delete_ref, refs_update_ref, etc. is returned to the
@@ -520,21 +520,17 @@ int refs_for_each_reflog_ent_reverse(struct ref_store *refs,
void *cb_data);
/*
- * Iterate over reflog entries in the log for `refname` in the main ref store.
+ * The signature for the callback function for the refs_for_each_reflog()
+ * functions below. The memory pointed to by the refname argument is only
+ * guaranteed to be valid for the duration of a single callback invocation.
*/
-
-/* oldest entry first */
-int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);
-
-/* youngest entry first */
-int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data);
+typedef int each_reflog_fn(const char *refname, void *cb_data);
/*
* Calls the specified function for each reflog file until it returns nonzero,
* and returns the value. Reflog file order is unspecified.
*/
-int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data);
-int for_each_reflog(each_ref_fn fn, void *cb_data);
+int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_data);
#define REFNAME_ALLOW_ONELEVEL 1
#define REFNAME_REFSPEC_PATTERN 2
@@ -550,6 +546,14 @@ int for_each_reflog(each_ref_fn fn, void *cb_data);
int check_refname_format(const char *refname, int flags);
/*
+ * Check the reference database for consistency. Return 0 if refs and
+ * reflogs are consistent, and non-zero otherwise. The errors will be
+ * written to stderr.
+ */
+int refs_fsck(struct ref_store *refs, struct fsck_options *o,
+ struct worktree *wt);
+
+/*
* Apply the rules from check_refname_format, but mutate the result until it
* is acceptable, and place the result in "out".
*/
@@ -559,23 +563,17 @@ const char *prettify_refname(const char *refname);
char *refs_shorten_unambiguous_ref(struct ref_store *refs,
const char *refname, int strict);
-char *shorten_unambiguous_ref(const char *refname, int strict);
/** rename ref, return 0 on success **/
int refs_rename_ref(struct ref_store *refs, const char *oldref,
const char *newref, const char *logmsg);
-int rename_ref(const char *oldref, const char *newref,
- const char *logmsg);
/** copy ref, return 0 on success **/
int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
const char *newref, const char *logmsg);
-int copy_existing_ref(const char *oldref, const char *newref,
- const char *logmsg);
-int refs_create_symref(struct ref_store *refs, const char *refname,
+int refs_update_symref(struct ref_store *refs, const char *refname,
const char *target, const char *logmsg);
-int create_symref(const char *refname, const char *target, const char *logmsg);
enum action_on_err {
UPDATE_REFS_MSG_ON_ERR,
@@ -583,13 +581,28 @@ enum action_on_err {
UPDATE_REFS_QUIET_ON_ERR
};
+enum ref_transaction_flag {
+ /*
+ * The ref transaction is part of the initial creation of the ref store
+ * and can thus assume that the ref store is completely empty. This
+ * allows the backend to perform the transaction more efficiently by
+ * skipping certain checks.
+ *
+ * It is a bug to set this flag when there might be other processes
+ * accessing the repository or if there are existing references that
+ * might conflict with the ones being created. All old_oid values must
+ * either be absent or null_oid.
+ */
+ REF_TRANSACTION_FLAG_INITIAL = (1 << 0),
+};
+
/*
* Begin a reference transaction. The reference transaction must
* be freed by calling ref_transaction_free().
*/
struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs,
+ unsigned int flags,
struct strbuf *err);
-struct ref_transaction *ref_transaction_begin(struct strbuf *err);
/*
* Reference transaction updates
@@ -615,6 +628,16 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
* before the update. A copy of this value is made in the
* transaction.
*
+ * new_target -- the target reference that the reference will be
+ * updated to point to. If the reference is a regular reference,
+ * it will be converted to a symbolic reference. Cannot be set
+ * together with `new_oid`. A copy of this value is made in the
+ * transaction.
+ *
+ * old_target -- the reference that the reference must be pointing to.
+ * Canont be set together with `old_oid`. A copy of this value is
+ * made in the transaction.
+ *
* flags -- flags affecting the update, passed to
* update_ref_lock(). Possible flags: REF_NO_DEREF,
* REF_FORCE_CREATE_REFLOG. See those constants for more
@@ -664,12 +687,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
#define REF_SKIP_REFNAME_VERIFICATION (1 << 11)
/*
+ * Skip creation of a reflog entry, even if it would have otherwise been
+ * created.
+ */
+#define REF_SKIP_CREATE_REFLOG (1 << 12)
+
+/*
* Bitmask of all of the flags that are allowed to be passed in to
* ref_transaction_update() and friends:
*/
#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \
- REF_SKIP_REFNAME_VERIFICATION)
+ REF_SKIP_REFNAME_VERIFICATION | REF_SKIP_CREATE_REFLOG)
/*
* Add a reference update to transaction. `new_oid` is the value that
@@ -680,7 +709,11 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
* beforehand. The old value is checked after the lock is taken to
* prevent races. If the old value doesn't agree with old_oid, the
* whole transaction fails. If old_oid is NULL, then the previous
- * value is not checked.
+ * value is not checked. If `old_target` is not NULL, treat the reference
+ * as a symbolic ref and validate that its target before the update is
+ * `old_target`. If the `new_target` is not NULL, then the reference
+ * will be updated to a symbolic ref which targets `new_target`.
+ * Together, these allow us to update between regular refs and symrefs.
*
* See the above comment "Reference transaction updates" for more
* information.
@@ -689,6 +722,8 @@ int ref_transaction_update(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
const struct object_id *old_oid,
+ const char *new_target,
+ const char *old_target,
unsigned int flags, const char *msg,
struct strbuf *err);
@@ -704,6 +739,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
int ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
+ const char *new_target,
unsigned int flags, const char *msg,
struct strbuf *err);
@@ -718,7 +754,9 @@ int ref_transaction_create(struct ref_transaction *transaction,
int ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
const struct object_id *old_oid,
- unsigned int flags, const char *msg,
+ const char *old_target,
+ unsigned int flags,
+ const char *msg,
struct strbuf *err);
/*
@@ -732,6 +770,7 @@ int ref_transaction_delete(struct ref_transaction *transaction,
int ref_transaction_verify(struct ref_transaction *transaction,
const char *refname,
const struct object_id *old_oid,
+ const char *old_target,
unsigned int flags,
struct strbuf *err);
@@ -777,20 +816,6 @@ int ref_transaction_abort(struct ref_transaction *transaction,
struct strbuf *err);
/*
- * Like ref_transaction_commit(), but optimized for creating
- * references when originally initializing a repository (e.g., by "git
- * clone"). It writes the new references directly to packed-refs
- * without locking the individual references.
- *
- * It is a bug to call this function when there might be other
- * processes accessing the repository or if there are existing
- * references that might conflict with the ones being created. All
- * old_oid values must either be absent or null_oid.
- */
-int initial_ref_transaction_commit(struct ref_transaction *transaction,
- struct strbuf *err);
-
-/*
* Execute the given callback function for each of the reference updates which
* have been queued in the given transaction. `old_oid` and `new_oid` may be
* `NULL` pointers depending on whether the update has these object IDs set or
@@ -820,9 +845,6 @@ void ref_transaction_free(struct ref_transaction *transaction);
int refs_update_ref(struct ref_store *refs, const char *msg, const char *refname,
const struct object_id *new_oid, const struct object_id *old_oid,
unsigned int flags, enum action_on_err onerr);
-int update_ref(const char *msg, const char *refname,
- const struct object_id *new_oid, const struct object_id *old_oid,
- unsigned int flags, enum action_on_err onerr);
int parse_hide_refs_config(const char *var, const char *value, const char *,
struct strvec *);
@@ -843,6 +865,15 @@ int ref_is_hidden(const char *, const char *, const struct strvec *);
*/
const char **hidden_refs_to_excludes(const struct strvec *hide_refs);
+/*
+ * Prefix all exclude patterns with the namespace, if any. This is required
+ * because exclude patterns apply to the stripped reference name, not the full
+ * reference name with the namespace.
+ */
+const char **get_namespaced_exclude_patterns(const char **exclude_patterns,
+ const char *namespace,
+ struct strvec *out);
+
/* Is this a per-worktree ref living in the refs/ namespace? */
int is_per_worktree_ref(const char *refname);
@@ -880,7 +911,7 @@ enum expire_reflog_flags {
/*
* The following interface is used for reflog expiration. The caller
- * calls reflog_expire(), supplying it with three callback functions,
+ * calls refs_reflog_expire(), supplying it with three callback functions,
* of the following types. The callback functions define the
* expiration policy that is desired.
*
@@ -917,12 +948,6 @@ int refs_reflog_expire(struct ref_store *refs,
reflog_expiry_should_prune_fn should_prune_fn,
reflog_expiry_cleanup_fn cleanup_fn,
void *policy_cb_data);
-int reflog_expire(const char *refname,
- unsigned int flags,
- reflog_expiry_prepare_fn prepare_fn,
- reflog_expiry_should_prune_fn should_prune_fn,
- reflog_expiry_cleanup_fn cleanup_fn,
- void *policy_cb_data);
struct ref_store *get_main_ref_store(struct repository *r);
@@ -970,17 +995,18 @@ struct ref_store *get_main_ref_store(struct repository *r);
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
-struct ref_store *get_submodule_ref_store(const char *submodule);
+struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
+ const char *submodule);
struct ref_store *get_worktree_ref_store(const struct worktree *wt);
/*
* Some of the names specified by refs have special meaning to Git.
- * Organize these namespaces in a comon 'ref_namespace' array for
+ * Organize these namespaces in a common 'ref_namespace' array for
* reference from multiple places in the codebase.
*/
struct ref_namespace_info {
- char *ref;
+ const char *ref;
enum decoration_type decoration;
/*
@@ -1018,4 +1044,69 @@ extern struct ref_namespace_info ref_namespace[NAMESPACE__COUNT];
*/
void update_ref_namespace(enum ref_namespace namespace, char *ref);
+/*
+ * Check whether the provided name names a root reference. This function only
+ * performs a syntactic check.
+ *
+ * A root ref is a reference that lives in the root of the reference hierarchy.
+ * These references must conform to special syntax:
+ *
+ * - Their name must be all-uppercase or underscores ("_").
+ *
+ * - Their name must end with "_HEAD". As a special rule, "HEAD" is a root
+ * ref, as well.
+ *
+ * - Their name may not contain a slash.
+ *
+ * There is a special set of irregular root refs that exist due to historic
+ * reasons, only. This list shall not be expanded in the future:
+ *
+ * - AUTO_MERGE
+ *
+ * - BISECT_EXPECTED_REV
+ *
+ * - NOTES_MERGE_PARTIAL
+ *
+ * - NOTES_MERGE_REF
+ *
+ * - MERGE_AUTOSTASH
+ */
+int is_root_ref(const char *refname);
+
+/*
+ * Pseudorefs are refs that have different semantics compared to
+ * "normal" refs. These refs can thus not be stored in the ref backend,
+ * but must always be accessed via the filesystem. The following refs
+ * are pseudorefs:
+ *
+ * - FETCH_HEAD may contain multiple object IDs, and each one of them
+ * carries additional metadata like where it came from.
+ *
+ * - MERGE_HEAD may contain multiple object IDs when merging multiple
+ * heads.
+ *
+ * Reading, writing or deleting references must consistently go either
+ * through the filesystem (pseudorefs) or through the reference
+ * backend (normal ones).
+ */
+int is_pseudo_ref(const char *refname);
+
+/*
+ * The following flags can be passed to `repo_migrate_ref_storage_format()`:
+ *
+ * - REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN: perform a dry-run migration
+ * without touching the main repository. The result will be written into a
+ * temporary ref storage directory.
+ */
+#define REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN (1 << 0)
+
+/*
+ * Migrate the ref storage format used by the repository to the
+ * specified one.
+ */
+int repo_migrate_ref_storage_format(struct repository *repo,
+ enum ref_storage_format format,
+ unsigned int flags,
+ struct strbuf *err);
+
#endif /* REFS_H */
diff --git a/refs/debug.c b/refs/debug.c
index b7ffc4ce67..a893ae0c90 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -33,11 +33,18 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor
return (struct ref_store *)res;
}
-static int debug_init_db(struct ref_store *refs, struct strbuf *err)
+static void debug_release(struct ref_store *refs)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
- int res = drefs->refs->be->init_db(drefs->refs, err);
- trace_printf_key(&trace_refs, "init_db: %d\n", res);
+ drefs->refs->be->release(drefs->refs);
+ trace_printf_key(&trace_refs, "release\n");
+}
+
+static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)
+{
+ struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
+ int res = drefs->refs->be->create_on_disk(drefs->refs, flags, err);
+ trace_printf_key(&trace_refs, "create_on_disk: %d\n", res);
return res;
}
@@ -111,18 +118,6 @@ static int debug_transaction_abort(struct ref_store *refs,
return res;
}
-static int debug_initial_transaction_commit(struct ref_store *refs,
- struct ref_transaction *transaction,
- struct strbuf *err)
-{
- struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
- int res;
- transaction->ref_store = drefs->refs;
- res = drefs->refs->be->initial_transaction_commit(drefs->refs,
- transaction, err);
- return res;
-}
-
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;
@@ -131,32 +126,6 @@ static int debug_pack_refs(struct ref_store *ref_store, struct pack_refs_opts *o
return res;
}
-static int debug_create_symref(struct ref_store *ref_store,
- const char *ref_name, const char *target,
- const char *logmsg)
-{
- struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
- int res = drefs->refs->be->create_symref(drefs->refs, ref_name, target,
- logmsg);
- trace_printf_key(&trace_refs, "create_symref: %s -> %s \"%s\": %d\n", ref_name,
- target, logmsg, res);
- return res;
-}
-
-static int debug_delete_refs(struct ref_store *ref_store, const char *msg,
- struct string_list *refnames, unsigned int flags)
-{
- struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
- int res =
- drefs->refs->be->delete_refs(drefs->refs, msg, refnames, flags);
- int i;
- trace_printf_key(&trace_refs, "delete_refs {\n");
- for (i = 0; i < refnames->nr; i++)
- trace_printf_key(&trace_refs, "%s\n", refnames->items[i].string);
- trace_printf_key(&trace_refs, "}: %d\n", res);
- return res;
-}
-
static int debug_rename_ref(struct ref_store *ref_store, const char *oldref,
const char *newref, const char *logmsg)
{
@@ -195,7 +164,6 @@ static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator)
trace_printf_key(&trace_refs, "iterator_advance: %s (0)\n",
diter->iter->refname);
- diter->base.ordered = diter->iter->ordered;
diter->base.refname = diter->iter->refname;
diter->base.oid = diter->iter->oid;
diter->base.flags = diter->iter->flags;
@@ -236,7 +204,7 @@ debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
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);
+ base_ref_iterator_init(&diter->base, &debug_ref_iterator_vtable);
diter->iter = res;
trace_printf_key(&trace_refs, "ref_iterator_begin: \"%s\" (0x%x)\n",
prefix, flags);
@@ -439,11 +407,21 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
return res;
}
+static int debug_fsck(struct ref_store *ref_store,
+ struct fsck_options *o,
+ struct worktree *wt)
+{
+ struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
+ int res = drefs->refs->be->fsck(drefs->refs, o, wt);
+ trace_printf_key(&trace_refs, "fsck: %d\n", res);
+ return res;
+}
+
struct ref_storage_be refs_be_debug = {
- .next = NULL,
.name = "debug",
.init = NULL,
- .init_db = debug_init_db,
+ .release = debug_release,
+ .create_on_disk = debug_create_on_disk,
/*
* None of these should be NULL. If the "files" backend (in
@@ -454,11 +432,8 @@ struct ref_storage_be refs_be_debug = {
.transaction_prepare = debug_transaction_prepare,
.transaction_finish = debug_transaction_finish,
.transaction_abort = debug_transaction_abort,
- .initial_transaction_commit = debug_initial_transaction_commit,
.pack_refs = debug_pack_refs,
- .create_symref = debug_create_symref,
- .delete_refs = debug_delete_refs,
.rename_ref = debug_rename_ref,
.copy_ref = debug_copy_ref,
@@ -473,4 +448,6 @@ struct ref_storage_be refs_be_debug = {
.create_reflog = debug_create_reflog,
.delete_reflog = debug_delete_reflog,
.reflog_expire = debug_reflog_expire,
+
+ .fsck = debug_fsck,
};
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 341354182b..64f51f0da9 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1,11 +1,16 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../git-compat-util.h"
+#include "../abspath.h"
#include "../config.h"
#include "../copy.h"
#include "../environment.h"
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
+#include "../fsck.h"
#include "../refs.h"
+#include "../repo-settings.h"
#include "refs-internal.h"
#include "ref-cache.h"
#include "packed-backend.h"
@@ -73,6 +78,8 @@ struct files_ref_store {
unsigned int store_flags;
char *gitcommondir;
+ enum log_refs_config log_all_ref_updates;
+ int prefer_symlink_refs;
struct ref_cache *loose;
@@ -91,9 +98,9 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
* Create a new submodule ref cache and add it to the internal
* set of caches.
*/
-static struct ref_store *files_ref_store_create(struct repository *repo,
- const char *gitdir,
- unsigned int flags)
+static struct ref_store *files_ref_store_init(struct repository *repo,
+ const char *gitdir,
+ unsigned int flags)
{
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
@@ -104,7 +111,9 @@ static struct ref_store *files_ref_store_create(struct repository *repo,
get_common_dir_noenv(&sb, gitdir);
refs->gitcommondir = strbuf_detach(&sb, NULL);
refs->packed_ref_store =
- packed_ref_store_create(repo, refs->gitcommondir, flags);
+ packed_ref_store_init(repo, refs->gitcommondir, flags);
+ refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
+ repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@@ -151,6 +160,15 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
+static void files_ref_store_release(struct ref_store *ref_store)
+{
+ struct files_ref_store *refs = files_downcast(ref_store, 0, "release");
+ free_ref_cache(refs->loose);
+ free(refs->gitcommondir);
+ ref_store_release(refs->packed_ref_store);
+ free(refs->packed_ref_store);
+}
+
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
@@ -231,6 +249,45 @@ static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dir
}
}
+static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
+ const char *refname,
+ struct ref_dir *dir)
+{
+ struct object_id oid;
+ int flag;
+ const char *referent = refs_resolve_ref_unsafe(&refs->base,
+ refname,
+ RESOLVE_REF_READING,
+ &oid, &flag);
+
+ if (!referent) {
+ oidclr(&oid, refs->base.repo->hash_algo);
+ flag |= REF_ISBROKEN;
+ } else if (is_null_oid(&oid)) {
+ /*
+ * It is so astronomically unlikely
+ * that null_oid is the OID of an
+ * actual object that we consider its
+ * appearance in a loose reference
+ * file to be repo corruption
+ * (probably due to a software bug).
+ */
+ flag |= REF_ISBROKEN;
+ }
+
+ if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+ if (!refname_is_safe(refname))
+ die("loose refname is dangerous: %s", refname);
+ oidclr(&oid, refs->base.repo->hash_algo);
+ flag |= REF_BAD_NAME | REF_ISBROKEN;
+ }
+
+ if (!(flag & REF_ISSYMREF))
+ referent = NULL;
+
+ add_entry_to_dir(dir, create_ref_entry(refname, referent, &oid, flag));
+}
+
/*
* Read the loose references from the namespace dirname into dir
* (without recursing). dirname must end with '/'. dir must be the
@@ -246,10 +303,8 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
int dirnamelen = strlen(dirname);
struct strbuf refname;
struct strbuf path = STRBUF_INIT;
- size_t path_baselen;
files_ref_path(refs, &path, dirname);
- path_baselen = path.len;
d = opendir(path.buf);
if (!d) {
@@ -261,54 +316,24 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
strbuf_add(&refname, dirname, dirnamelen);
while ((de = readdir(d)) != NULL) {
- struct object_id oid;
- struct stat st;
- int flag;
+ unsigned char dtype;
if (de->d_name[0] == '.')
continue;
if (ends_with(de->d_name, ".lock"))
continue;
strbuf_addstr(&refname, de->d_name);
- strbuf_addstr(&path, de->d_name);
- if (stat(path.buf, &st) < 0) {
- ; /* silently ignore */
- } else if (S_ISDIR(st.st_mode)) {
+
+ dtype = get_dtype(de, &path, 1);
+ if (dtype == DT_DIR) {
strbuf_addch(&refname, '/');
add_entry_to_dir(dir,
create_dir_entry(dir->cache, refname.buf,
refname.len));
- } else {
- if (!refs_resolve_ref_unsafe(&refs->base,
- refname.buf,
- RESOLVE_REF_READING,
- &oid, &flag)) {
- oidclr(&oid);
- flag |= REF_ISBROKEN;
- } else if (is_null_oid(&oid)) {
- /*
- * It is so astronomically unlikely
- * that null_oid is the OID of an
- * actual object that we consider its
- * appearance in a loose reference
- * file to be repo corruption
- * (probably due to a software bug).
- */
- flag |= REF_ISBROKEN;
- }
-
- if (check_refname_format(refname.buf,
- REFNAME_ALLOW_ONELEVEL)) {
- if (!refname_is_safe(refname.buf))
- die("loose refname is dangerous: %s", refname.buf);
- oidclr(&oid);
- flag |= REF_BAD_NAME | REF_ISBROKEN;
- }
- add_entry_to_dir(dir,
- create_ref_entry(refname.buf, &oid, flag));
+ } else if (dtype == DT_REG) {
+ loose_fill_ref_dir_regular_file(refs, refname.buf, dir);
}
strbuf_setlen(&refname, dirnamelen);
- strbuf_setlen(&path, path_baselen);
}
strbuf_release(&refname);
strbuf_release(&path);
@@ -317,9 +342,89 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
add_per_worktree_entries_to_dir(dir, dirname);
}
-static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
+static int for_each_root_ref(struct files_ref_store *refs,
+ int (*cb)(const char *refname, void *cb_data),
+ void *cb_data)
+{
+ struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT;
+ const char *dirname = refs->loose->root->name;
+ struct dirent *de;
+ size_t dirnamelen;
+ int ret;
+ DIR *d;
+
+ files_ref_path(refs, &path, dirname);
+
+ d = opendir(path.buf);
+ if (!d) {
+ strbuf_release(&path);
+ return -1;
+ }
+
+ strbuf_addstr(&refname, dirname);
+ dirnamelen = refname.len;
+
+ while ((de = readdir(d)) != NULL) {
+ unsigned char dtype;
+
+ if (de->d_name[0] == '.')
+ continue;
+ if (ends_with(de->d_name, ".lock"))
+ continue;
+ strbuf_addstr(&refname, de->d_name);
+
+ dtype = get_dtype(de, &path, 1);
+ if (dtype == DT_REG && is_root_ref(de->d_name)) {
+ ret = cb(refname.buf, cb_data);
+ if (ret)
+ goto done;
+ }
+
+ strbuf_setlen(&refname, dirnamelen);
+ }
+
+ ret = 0;
+
+done:
+ strbuf_release(&refname);
+ strbuf_release(&path);
+ closedir(d);
+ return ret;
+}
+
+struct fill_root_ref_data {
+ struct files_ref_store *refs;
+ struct ref_dir *dir;
+};
+
+static int fill_root_ref(const char *refname, void *cb_data)
+{
+ struct fill_root_ref_data *data = cb_data;
+ loose_fill_ref_dir_regular_file(data->refs, refname, data->dir);
+ return 0;
+}
+
+/*
+ * Add root refs to the ref dir by parsing the directory for any files which
+ * follow the root ref syntax.
+ */
+static void add_root_refs(struct files_ref_store *refs,
+ struct ref_dir *dir)
+{
+ struct fill_root_ref_data data = {
+ .refs = refs,
+ .dir = dir,
+ };
+
+ for_each_root_ref(refs, fill_root_ref, &data);
+}
+
+static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
+ unsigned int flags)
{
if (!refs->loose) {
+ struct ref_dir *dir;
+
/*
* Mark the top-level directory complete because we
* are about to read the only subdirectory that can
@@ -330,12 +435,16 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
/* We're going to fill the top level ourselves: */
refs->loose->root->flag &= ~REF_INCOMPLETE;
+ dir = get_ref_dir(refs->loose->root);
+
+ if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS)
+ add_root_refs(refs, dir);
+
/*
* Add an incomplete entry for "refs/" (to be filled
* lazily):
*/
- add_entry_to_dir(get_ref_dir(refs->loose->root),
- create_dir_entry(refs->loose, "refs/", 5));
+ add_entry_to_dir(dir, create_dir_entry(refs->loose, "refs/", 5));
}
return refs->loose;
}
@@ -460,7 +569,8 @@ stat_ref:
strbuf_rtrim(&sb_contents);
buf = sb_contents.buf;
- ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr);
+ ret = parse_loose_ref_contents(ref_store->repo->hash_algo, buf,
+ oid, referent, type, NULL, &myerr);
out:
if (ret && !myerr)
@@ -494,9 +604,10 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn
return !(type & REF_ISSYMREF);
}
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+ const char *buf, struct object_id *oid,
struct strbuf *referent, unsigned int *type,
- int *failure_errno)
+ const char **trailing, int *failure_errno)
{
const char *p;
if (skip_prefix(buf, "ref:", &buf)) {
@@ -512,12 +623,16 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
/*
* FETCH_HEAD has additional data after the sha.
*/
- if (parse_oid_hex(buf, oid, &p) ||
+ if (parse_oid_hex_algop(buf, oid, &p, algop) ||
(*p != '\0' && !isspace(*p))) {
*type |= REF_ISBROKEN;
*failure_errno = EINVAL;
return -1;
}
+
+ if (trailing)
+ *trailing = p;
+
return 0;
}
@@ -597,7 +712,7 @@ retry:
* reason to expect this error to be transitory.
*/
if (refs_verify_refname_available(&refs->base, refname,
- extras, NULL, err)) {
+ extras, NULL, 0, err)) {
if (mustexist) {
/*
* To the user the relevant error is
@@ -704,7 +819,7 @@ retry:
REMOVE_DIR_EMPTY_ONLY)) {
if (refs_verify_refname_available(
&refs->base, refname,
- extras, NULL, err)) {
+ extras, NULL, 0, err)) {
/*
* The error message set by
* verify_refname_available() is OK.
@@ -741,8 +856,10 @@ retry:
*/
if (refs_verify_refname_available(
refs->packed_ref_store, refname,
- extras, NULL, err))
+ extras, NULL, 0, err)) {
+ ret = TRANSACTION_NAME_CONFLICT;
goto error_return;
+ }
}
ret = 0;
@@ -792,6 +909,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
iter->base.refname = iter->iter0->refname;
iter->base.oid = iter->iter0->oid;
iter->base.flags = iter->iter0->flags;
+ iter->base.referent = iter->iter0->referent;
+
return ITER_OK;
}
@@ -863,7 +982,7 @@ static struct ref_iterator *files_ref_iterator_begin(
* disk, and re-reads it if not.
*/
- loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
+ loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, flags),
prefix, ref_store->repo, 1);
/*
@@ -885,8 +1004,7 @@ static struct ref_iterator *files_ref_iterator_begin(
CALLOC_ARRAY(iter, 1);
ref_iterator = &iter->base;
- base_ref_iterator_init(ref_iterator, &files_ref_iterator_vtable,
- overlay_iter->ordered);
+ base_ref_iterator_init(ref_iterator, &files_ref_iterator_vtable);
iter->iter0 = overlay_iter;
iter->repo = ref_store->repo;
iter->flags = flags;
@@ -1047,7 +1165,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
*/
if (is_null_oid(&lock->old_oid) &&
refs_verify_refname_available(refs->packed_ref_store, refname,
- NULL, NULL, err))
+ NULL, NULL, 0, err))
goto error_return;
lock->ref_name = xstrdup(refname);
@@ -1059,7 +1177,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
&lock->old_oid, NULL))
- oidclr(&lock->old_oid);
+ oidclr(&lock->old_oid, refs->base.repo->hash_algo);
goto out;
error_return:
@@ -1140,13 +1258,13 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)
if (check_refname_format(r->name, 0))
return;
- transaction = ref_store_transaction_begin(&refs->base, &err);
+ transaction = ref_store_transaction_begin(&refs->base, 0, &err);
if (!transaction)
goto cleanup;
ref_transaction_add_update(
transaction, r->name,
REF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING,
- null_oid(), &r->oid, NULL);
+ null_oid(), &r->oid, NULL, NULL, NULL);
if (ref_transaction_commit(transaction, &err))
goto cleanup;
@@ -1177,7 +1295,8 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
/*
* Return true if the specified reference should be packed.
*/
-static int should_pack_ref(const char *refname,
+static int should_pack_ref(struct files_ref_store *refs,
+ const char *refname,
const struct object_id *oid, unsigned int ref_flags,
struct pack_refs_opts *opts)
{
@@ -1193,7 +1312,7 @@ static int should_pack_ref(const char *refname,
return 0;
/* Do not pack broken refs: */
- if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
+ if (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))
return 0;
if (ref_excluded(opts->exclusions, refname))
@@ -1206,6 +1325,68 @@ static int should_pack_ref(const char *refname,
return 0;
}
+static int should_pack_refs(struct files_ref_store *refs,
+ struct pack_refs_opts *opts)
+{
+ struct ref_iterator *iter;
+ size_t packed_size;
+ size_t refcount = 0;
+ size_t limit;
+ int ret;
+
+ if (!(opts->flags & PACK_REFS_AUTO))
+ return 1;
+
+ ret = packed_refs_size(refs->packed_ref_store, &packed_size);
+ if (ret < 0)
+ die("cannot determine packed-refs size");
+
+ /*
+ * Packing loose references into the packed-refs file scales with the
+ * number of references we're about to write. We thus decide whether we
+ * repack refs by weighing the current size of the packed-refs file
+ * against the number of loose references. This is done such that we do
+ * not repack too often on repositories with a huge number of
+ * references, where we can expect a lot of churn in the number of
+ * references.
+ *
+ * As a heuristic, we repack if the number of loose references in the
+ * repository exceeds `log2(nr_packed_refs) * 5`, where we estimate
+ * `nr_packed_refs = packed_size / 100`, which scales as following:
+ *
+ * - 1kB ~ 10 packed refs: 16 refs
+ * - 10kB ~ 100 packed refs: 33 refs
+ * - 100kB ~ 1k packed refs: 49 refs
+ * - 1MB ~ 10k packed refs: 66 refs
+ * - 10MB ~ 100k packed refs: 82 refs
+ * - 100MB ~ 1m packed refs: 99 refs
+ *
+ * We thus allow roughly 16 additional loose refs per factor of ten of
+ * packed refs. This heuristic may be tweaked in the future, but should
+ * serve as a sufficiently good first iteration.
+ */
+ limit = log2u(packed_size / 100) * 5;
+ if (limit < 16)
+ limit = 16;
+
+ iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
+ refs->base.repo, 0);
+ while ((ret = ref_iterator_advance(iter)) == ITER_OK) {
+ if (should_pack_ref(refs, iter->refname, iter->oid,
+ iter->flags, opts))
+ refcount++;
+ if (refcount >= limit) {
+ ref_iterator_abort(iter);
+ return 1;
+ }
+ }
+
+ if (ret != ITER_DONE)
+ die("error while iterating over references");
+
+ return 0;
+}
+
static int files_pack_refs(struct ref_store *ref_store,
struct pack_refs_opts *opts)
{
@@ -1218,21 +1399,25 @@ static int files_pack_refs(struct ref_store *ref_store,
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
- transaction = ref_store_transaction_begin(refs->packed_ref_store, &err);
+ if (!should_pack_refs(refs, opts))
+ return 0;
+
+ transaction = ref_store_transaction_begin(refs->packed_ref_store,
+ 0, &err);
if (!transaction)
return -1;
packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
- iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL,
- the_repository, 0);
+ iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
+ refs->base.repo, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
/*
* If the loose reference can be packed, add an entry
* 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, opts))
+ if (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))
continue;
/*
@@ -1240,7 +1425,7 @@ static int files_pack_refs(struct ref_store *ref_store,
* packed-refs transaction:
*/
if (ref_transaction_update(transaction, iter->refname,
- iter->oid, NULL,
+ iter->oid, NULL, NULL, NULL,
REF_NO_DEREF, NULL, &err))
die("failure preparing to create packed reference %s: %s",
iter->refname, err.buf);
@@ -1269,54 +1454,6 @@ static int files_pack_refs(struct ref_store *ref_store,
return 0;
}
-static int files_delete_refs(struct ref_store *ref_store, const char *msg,
- struct string_list *refnames, unsigned int flags)
-{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
- struct strbuf err = STRBUF_INIT;
- int i, result = 0;
-
- if (!refnames->nr)
- return 0;
-
- if (packed_refs_lock(refs->packed_ref_store, 0, &err))
- goto error;
-
- if (refs_delete_refs(refs->packed_ref_store, msg, refnames, flags)) {
- packed_refs_unlock(refs->packed_ref_store);
- goto error;
- }
-
- packed_refs_unlock(refs->packed_ref_store);
-
- for (i = 0; i < refnames->nr; i++) {
- const char *refname = refnames->items[i].string;
-
- if (refs_delete_ref(&refs->base, msg, refname, NULL, flags))
- result |= error(_("could not remove reference %s"), refname);
- }
-
- strbuf_release(&err);
- return result;
-
-error:
- /*
- * If we failed to rewrite the packed-refs file, then it is
- * unsafe to try to remove loose refs, because doing so might
- * expose an obsolete packed value for a reference that might
- * even point at an object that has been garbage collected.
- */
- if (refnames->nr == 1)
- error(_("could not delete reference %s: %s"),
- refnames->items[0].string, err.buf);
- else
- error(_("could not delete references: %s"), err.buf);
-
- strbuf_release(&err);
- return -1;
-}
-
/*
* People using contrib's git-new-workdir have .git/logs/refs ->
* /some/other/path/.git/logs/refs, and that may live on another device.
@@ -1377,12 +1514,14 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
return ret;
}
-static int write_ref_to_lockfile(struct ref_lock *lock,
+static int write_ref_to_lockfile(struct files_ref_store *refs,
+ struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err);
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid, const char *logmsg,
+ int flags,
struct strbuf *err);
/*
@@ -1405,7 +1544,7 @@ static int refs_rename_ref_available(struct ref_store *refs,
string_list_insert(&skip, old_refname);
ok = !refs_verify_refname_available(refs, new_refname,
- NULL, &skip, &err);
+ NULL, &skip, 0, &err);
if (!ok)
error("%s", err.buf);
@@ -1525,8 +1664,8 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
}
oidcpy(&lock->old_oid, &orig_oid);
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
- commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
+ if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
+ commit_ref_update(refs, lock, &orig_oid, logmsg, 0, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
goto rollback;
@@ -1543,14 +1682,11 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
goto rollbacklog;
}
- flag = log_all_ref_updates;
- log_all_ref_updates = LOG_REFS_NONE;
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
- commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
+ if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
+ commit_ref_update(refs, lock, &orig_oid, NULL, REF_SKIP_CREATE_REFLOG, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
}
- log_all_ref_updates = flag;
rollbacklog:
if (logmoved && rename(sb_newref.buf, sb_oldref.buf))
@@ -1645,13 +1781,17 @@ static int log_ref_setup(struct files_ref_store *refs,
const char *refname, int force_create,
int *logfd, struct strbuf *err)
{
+ enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
struct strbuf logfile_sb = STRBUF_INIT;
char *logfile;
+ if (log_refs_cfg == LOG_REFS_UNSET)
+ log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+
files_reflog_path(refs, &logfile_sb, refname);
logfile = strbuf_detach(&logfile_sb, NULL);
- if (force_create || should_autocreate_reflog(refname)) {
+ if (force_create || should_autocreate_reflog(log_refs_cfg, refname)) {
if (raceproof_create_file(logfile, open_or_create_logfile, logfd)) {
if (errno == ENOENT)
strbuf_addf(err, "unable to create directory for '%s': "
@@ -1737,8 +1877,8 @@ static int files_log_ref_write(struct files_ref_store *refs,
{
int logfd, result;
- if (log_all_ref_updates == LOG_REFS_UNSET)
- log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+ if (flags & REF_SKIP_CREATE_REFLOG)
+ return 0;
result = log_ref_setup(refs, refname,
flags & REF_FORCE_CREATE_REFLOG,
@@ -1779,7 +1919,8 @@ static int files_log_ref_write(struct files_ref_store *refs,
* Write oid into the open lockfile, then close the lockfile. On
* errors, rollback the lockfile, fill in *err and return -1.
*/
-static int write_ref_to_lockfile(struct ref_lock *lock,
+static int write_ref_to_lockfile(struct files_ref_store *refs,
+ struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err)
{
@@ -1788,7 +1929,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
int fd;
if (!skip_oid_verification) {
- o = parse_object(the_repository, oid);
+ o = parse_object(refs->base.repo, oid);
if (!o) {
strbuf_addf(
err,
@@ -1807,7 +1948,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
}
}
fd = get_lock_file_fd(&lock->lk);
- if (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ if (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_in_full(fd, &term, 1) < 0 ||
fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&lock->lk)) < 0 ||
close_ref_gently(lock) < 0) {
@@ -1827,6 +1968,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid, const char *logmsg,
+ int flags,
struct strbuf *err)
{
files_assert_main_repository(refs, "commit_ref_update");
@@ -1834,7 +1976,7 @@ static int commit_ref_update(struct files_ref_store *refs,
clear_loose_ref_cache(refs);
if (files_log_ref_write(refs, lock->ref_name,
&lock->old_oid, oid,
- logmsg, 0, err)) {
+ logmsg, flags, err)) {
char *old_msg = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot update the ref '%s': %s",
lock->ref_name, old_msg);
@@ -1867,7 +2009,7 @@ static int commit_ref_update(struct files_ref_store *refs,
struct strbuf log_err = STRBUF_INIT;
if (files_log_ref_write(refs, "HEAD",
&lock->old_oid, oid,
- logmsg, 0, &log_err)) {
+ logmsg, flags, &log_err)) {
error("%s", log_err.buf);
strbuf_release(&log_err);
}
@@ -1884,10 +2026,13 @@ static int commit_ref_update(struct files_ref_store *refs,
return 0;
}
+#ifdef NO_SYMLINK_HEAD
+#define create_ref_symlink(a, b) (-1)
+#else
static int create_ref_symlink(struct ref_lock *lock, const char *target)
{
int ret = -1;
-#ifndef NO_SYMLINK_HEAD
+
char *ref_path = get_locked_file_path(&lock->lk);
unlink(ref_path);
ret = symlink(target, ref_path);
@@ -1895,70 +2040,26 @@ static int create_ref_symlink(struct ref_lock *lock, const char *target)
if (ret)
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
-#endif
return ret;
}
+#endif
-static void update_symref_reflog(struct files_ref_store *refs,
- struct ref_lock *lock, const char *refname,
- const char *target, const char *logmsg)
-{
- struct strbuf err = STRBUF_INIT;
- struct object_id new_oid;
-
- if (logmsg &&
- refs_resolve_ref_unsafe(&refs->base, target,
- RESOLVE_REF_READING, &new_oid, NULL) &&
- files_log_ref_write(refs, refname, &lock->old_oid,
- &new_oid, logmsg, 0, &err)) {
- error("%s", err.buf);
- strbuf_release(&err);
- }
-}
-
-static int create_symref_locked(struct files_ref_store *refs,
- struct ref_lock *lock, const char *refname,
- const char *target, const char *logmsg)
+static int create_symref_lock(struct ref_lock *lock, const char *target,
+ struct strbuf *err)
{
- if (prefer_symlink_refs && !create_ref_symlink(lock, target)) {
- update_symref_reflog(refs, lock, refname, target, logmsg);
- return 0;
+ if (!fdopen_lock_file(&lock->lk, "w")) {
+ strbuf_addf(err, "unable to fdopen %s: %s",
+ get_lock_file_path(&lock->lk), strerror(errno));
+ return -1;
}
- if (!fdopen_lock_file(&lock->lk, "w"))
- return error("unable to fdopen %s: %s",
+ if (fprintf(get_lock_file_fp(&lock->lk), "ref: %s\n", target) < 0) {
+ strbuf_addf(err, "unable to write to %s: %s",
get_lock_file_path(&lock->lk), strerror(errno));
-
- update_symref_reflog(refs, lock, refname, target, logmsg);
-
- /* no error check; commit_ref will check ferror */
- fprintf(get_lock_file_fp(&lock->lk), "ref: %s\n", target);
- if (commit_ref(lock) < 0)
- return error("unable to write symref for %s: %s", refname,
- strerror(errno));
- return 0;
-}
-
-static int files_create_symref(struct ref_store *ref_store,
- const char *refname, const char *target,
- const char *logmsg)
-{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE, "create_symref");
- struct strbuf err = STRBUF_INIT;
- struct ref_lock *lock;
- int ret;
-
- lock = lock_ref_oid_basic(refs, refname, &err);
- if (!lock) {
- error("%s", err.buf);
- strbuf_release(&err);
return -1;
}
- ret = create_symref_locked(refs, lock, refname, target, logmsg);
- unlock_ref(lock);
- return ret;
+ return 0;
}
static int files_reflog_exists(struct ref_store *ref_store,
@@ -1990,7 +2091,8 @@ static int files_delete_reflog(struct ref_store *ref_store,
return ret;
}
-static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
+static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
+ each_reflog_ent_fn fn, void *cb_data)
{
struct object_id ooid, noid;
char *email_end, *message;
@@ -2000,8 +2102,8 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c
/* old SP new SP name <email> SP time TAB msg LF */
if (!sb->len || sb->buf[sb->len - 1] != '\n' ||
- parse_oid_hex(p, &ooid, &p) || *p++ != ' ' ||
- parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
+ parse_oid_hex_algop(p, &ooid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
+ parse_oid_hex_algop(p, &noid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
!(email_end = strchr(p, '>')) ||
email_end[1] != ' ' ||
!(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||
@@ -2100,7 +2202,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
strbuf_reset(&sb);
if (ret)
break;
@@ -2112,7 +2214,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
* Process it, and we can end the loop.
*/
strbuf_splice(&sb, 0, 0, buf, endp - buf);
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
strbuf_reset(&sb);
break;
}
@@ -2162,7 +2264,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
return -1;
while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
fclose(logfp);
strbuf_release(&sb);
return ret;
@@ -2170,10 +2272,8 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
struct files_reflog_iterator {
struct ref_iterator base;
-
struct ref_store *ref_store;
struct dir_iterator *dir_iterator;
- struct object_id oid;
};
static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
@@ -2184,25 +2284,13 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
int ok;
while ((ok = dir_iterator_advance(diter)) == ITER_OK) {
- int flags;
-
if (!S_ISREG(diter->st.st_mode))
continue;
- if (diter->basename[0] == '.')
- continue;
- if (ends_with(diter->basename, ".lock"))
+ if (check_refname_format(diter->basename,
+ REFNAME_ALLOW_ONELEVEL))
continue;
- if (!refs_resolve_ref_unsafe(iter->ref_store,
- diter->relative_path, 0,
- &iter->oid, &flags)) {
- error("bad ref for %s", diter->path.buf);
- continue;
- }
-
iter->base.refname = diter->relative_path;
- iter->base.oid = &iter->oid;
- iter->base.flags = flags;
return ITER_OK;
}
@@ -2247,7 +2335,7 @@ static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
strbuf_addf(&sb, "%s/logs", gitdir);
- diter = dir_iterator_begin(sb.buf, 0);
+ diter = dir_iterator_begin(sb.buf, DIR_ITERATOR_SORTED);
if (!diter) {
strbuf_release(&sb);
return empty_ref_iterator_begin();
@@ -2256,7 +2344,7 @@ static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
CALLOC_ARRAY(iter, 1);
ref_iterator = &iter->base;
- base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable, 0);
+ base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
iter->dir_iterator = diter;
iter->ref_store = ref_store;
strbuf_release(&sb);
@@ -2264,32 +2352,6 @@ static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
return ref_iterator;
}
-static enum iterator_selection reflog_iterator_select(
- struct ref_iterator *iter_worktree,
- struct ref_iterator *iter_common,
- void *cb_data UNUSED)
-{
- if (iter_worktree) {
- /*
- * We're a bit loose here. We probably should ignore
- * common refs if they are accidentally added as
- * per-worktree refs.
- */
- return ITER_SELECT_0;
- } else if (iter_common) {
- if (parse_worktree_ref(iter_common->refname, NULL, NULL,
- NULL) == REF_WORKTREE_SHARED)
- return ITER_SELECT_1;
-
- /*
- * The main ref store may contain main worktree's
- * per-worktree refs, which should be ignored
- */
- return ITER_SKIP_1;
- } else
- return ITER_DONE;
-}
-
static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
{
struct files_ref_store *refs =
@@ -2300,9 +2362,9 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st
return reflog_iterator_begin(ref_store, refs->gitcommondir);
} else {
return merge_ref_iterator_begin(
- 0, reflog_iterator_begin(ref_store, refs->base.gitdir),
+ reflog_iterator_begin(ref_store, refs->base.gitdir),
reflog_iterator_begin(ref_store, refs->gitcommondir),
- reflog_iterator_select, refs);
+ ref_iterator_select, refs);
}
}
@@ -2320,6 +2382,7 @@ static int split_head_update(struct ref_update *update,
struct ref_update *new_update;
if ((update->flags & REF_LOG_ONLY) ||
+ (update->flags & REF_SKIP_CREATE_REFLOG) ||
(update->flags & REF_IS_PRUNING) ||
(update->flags & REF_UPDATE_VIA_HEAD))
return 0;
@@ -2345,7 +2408,7 @@ static int split_head_update(struct ref_update *update,
transaction, "HEAD",
update->flags | REF_LOG_ONLY | REF_NO_DEREF,
&update->new_oid, &update->old_oid,
- update->msg);
+ NULL, NULL, update->msg);
/*
* Add "HEAD". This insertion is O(N) in the transaction
@@ -2407,8 +2470,9 @@ static int split_symref_update(struct ref_update *update,
new_update = ref_transaction_add_update(
transaction, referent, new_flags,
- &update->new_oid, &update->old_oid,
- update->msg);
+ update->new_target ? NULL : &update->new_oid,
+ update->old_target ? NULL : &update->old_oid,
+ update->new_target, update->old_target, update->msg);
new_update->parent_update = update;
@@ -2437,17 +2501,6 @@ static int split_symref_update(struct ref_update *update,
}
/*
- * Return the refname under which update was originally requested.
- */
-static const char *original_update_refname(struct ref_update *update)
-{
- while (update->parent_update)
- update = update->parent_update;
-
- return update->refname;
-}
-
-/*
* Check whether the REF_HAVE_OLD and old_oid values stored in update
* are consistent with oid, which is the reference's current value. If
* everything is OK, return 0; otherwise, write an error message to
@@ -2463,16 +2516,16 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
if (is_null_oid(&update->old_oid))
strbuf_addf(err, "cannot lock ref '%s': "
"reference already exists",
- original_update_refname(update));
+ ref_update_original_update_refname(update));
else if (is_null_oid(oid))
strbuf_addf(err, "cannot lock ref '%s': "
"reference is missing but expected %s",
- original_update_refname(update),
+ ref_update_original_update_refname(update),
oid_to_hex(&update->old_oid));
else
strbuf_addf(err, "cannot lock ref '%s': "
"is at %s but expected %s",
- original_update_refname(update),
+ ref_update_original_update_refname(update),
oid_to_hex(oid),
oid_to_hex(&update->old_oid));
@@ -2500,14 +2553,13 @@ static int lock_ref_for_update(struct files_ref_store *refs,
struct strbuf *err)
{
struct strbuf referent = STRBUF_INIT;
- int mustexist = (update->flags & REF_HAVE_OLD) &&
- !is_null_oid(&update->old_oid);
+ int mustexist = ref_update_expects_existing_old_ref(update);
int ret = 0;
struct ref_lock *lock;
files_assert_main_repository(refs, "lock_ref_for_update");
- if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid))
+ if ((update->flags & REF_HAVE_NEW) && ref_update_has_null_new_value(update))
update->flags |= REF_DELETING;
if (head_ref) {
@@ -2526,7 +2578,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
reason = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot lock ref '%s': %s",
- original_update_refname(update), reason);
+ ref_update_original_update_refname(update), reason);
free(reason);
goto out;
}
@@ -2546,11 +2598,18 @@ static int lock_ref_for_update(struct files_ref_store *refs,
if (update->flags & REF_HAVE_OLD) {
strbuf_addf(err, "cannot lock ref '%s': "
"error reading reference",
- original_update_refname(update));
+ ref_update_original_update_refname(update));
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ }
+ }
+
+ if (update->old_target) {
+ if (ref_update_check_old_target(referent.buf, update, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
- } else if (check_old_oid(update, &lock->old_oid, err)) {
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
@@ -2571,7 +2630,19 @@ static int lock_ref_for_update(struct files_ref_store *refs,
} else {
struct ref_update *parent_update;
- if (check_old_oid(update, &lock->old_oid, err)) {
+ /*
+ * Even if the ref is a regular ref, if `old_target` is set, we
+ * fail with an error.
+ */
+ if (update->old_target) {
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "expected symref with target '%s': "
+ "but is a regular ref"),
+ ref_update_original_update_refname(update),
+ update->old_target);
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
@@ -2589,9 +2660,27 @@ static int lock_ref_for_update(struct files_ref_store *refs,
}
}
- if ((update->flags & REF_HAVE_NEW) &&
- !(update->flags & REF_DELETING) &&
- !(update->flags & REF_LOG_ONLY)) {
+ if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
+ if (create_symref_lock(lock, update->new_target, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ }
+
+ if (close_ref_gently(lock)) {
+ strbuf_addf(err, "couldn't close '%s.lock'",
+ update->refname);
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ }
+
+ /*
+ * Once we have created the symref lock, the commit
+ * phase of the transaction only needs to commit the lock.
+ */
+ update->flags |= REF_NEEDS_COMMIT;
+ } else if ((update->flags & REF_HAVE_NEW) &&
+ !(update->flags & REF_DELETING) &&
+ !(update->flags & REF_LOG_ONLY)) {
if (!(update->type & REF_ISSYMREF) &&
oideq(&lock->old_oid, &update->new_oid)) {
/*
@@ -2599,7 +2688,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* value, so we don't need to write it.
*/
} else if (write_ref_to_lockfile(
- lock, &update->new_oid,
+ refs, lock, &update->new_oid,
update->flags & REF_SKIP_OID_VERIFICATION,
err)) {
char *write_err = strbuf_detach(err, NULL);
@@ -2698,6 +2787,8 @@ static int files_transaction_prepare(struct ref_store *ref_store,
assert(err);
+ if (transaction->flags & REF_TRANSACTION_FLAG_INITIAL)
+ goto cleanup;
if (!transaction->nr)
goto cleanup;
@@ -2785,7 +2876,8 @@ static int files_transaction_prepare(struct ref_store *ref_store,
*/
if (!packed_transaction) {
packed_transaction = ref_store_transaction_begin(
- refs->packed_ref_store, err);
+ refs->packed_ref_store,
+ transaction->flags, err);
if (!packed_transaction) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
@@ -2799,7 +2891,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
packed_transaction, update->refname,
REF_HAVE_NEW | REF_NO_DEREF,
&update->new_oid, NULL,
- NULL);
+ NULL, NULL, NULL);
}
}
@@ -2854,6 +2946,164 @@ cleanup:
return ret;
}
+static int parse_and_write_reflog(struct files_ref_store *refs,
+ struct ref_update *update,
+ struct ref_lock *lock,
+ struct strbuf *err)
+{
+ if (update->new_target) {
+ /*
+ * We want to get the resolved OID for the target, to ensure
+ * that the correct value is added to the reflog.
+ */
+ if (!refs_resolve_ref_unsafe(&refs->base, update->new_target,
+ RESOLVE_REF_READING,
+ &update->new_oid, NULL)) {
+ /*
+ * TODO: currently we skip creating reflogs for dangling
+ * symref updates. It would be nice to capture this as
+ * zero oid updates however.
+ */
+ return 0;
+ }
+ }
+
+ if (files_log_ref_write(refs, lock->ref_name, &lock->old_oid,
+ &update->new_oid, update->msg, update->flags, err)) {
+ char *old_msg = strbuf_detach(err, NULL);
+
+ strbuf_addf(err, "cannot update the ref '%s': %s",
+ lock->ref_name, old_msg);
+ free(old_msg);
+ unlock_ref(lock);
+ update->backend_data = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ref_present(const char *refname, const char *referent UNUSED,
+ const struct object_id *oid UNUSED,
+ int flags UNUSED,
+ void *cb_data)
+{
+ struct string_list *affected_refnames = cb_data;
+
+ return string_list_has_string(affected_refnames, refname);
+}
+
+static int files_transaction_finish_initial(struct files_ref_store *refs,
+ struct ref_transaction *transaction,
+ struct strbuf *err)
+{
+ size_t i;
+ int ret = 0;
+ struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
+ struct ref_transaction *packed_transaction = NULL;
+ struct ref_transaction *loose_transaction = NULL;
+
+ assert(err);
+
+ if (transaction->state != REF_TRANSACTION_PREPARED)
+ BUG("commit called for transaction that is not prepared");
+
+ /* Fail if a refname appears more than once in the transaction: */
+ for (i = 0; i < transaction->nr; i++)
+ string_list_append(&affected_refnames,
+ transaction->updates[i]->refname);
+ string_list_sort(&affected_refnames);
+ if (ref_update_reject_duplicates(&affected_refnames, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * It's really undefined to call this function in an active
+ * repository or when there are existing references: we are
+ * only locking and changing packed-refs, so (1) any
+ * simultaneous processes might try to change a reference at
+ * the same time we do, and (2) any existing loose versions of
+ * the references that we are setting would have precedence
+ * over our values. But some remote helpers create the remote
+ * "HEAD" and "master" branches before calling this function,
+ * so here we really only check that none of the references
+ * that we are creating already exists.
+ */
+ if (refs_for_each_rawref(&refs->base, ref_present,
+ &affected_refnames))
+ BUG("initial ref transaction called with existing refs");
+
+ packed_transaction = ref_store_transaction_begin(refs->packed_ref_store,
+ transaction->flags, err);
+ if (!packed_transaction) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+
+ for (i = 0; i < transaction->nr; i++) {
+ struct ref_update *update = transaction->updates[i];
+
+ if ((update->flags & REF_HAVE_OLD) &&
+ !is_null_oid(&update->old_oid))
+ BUG("initial ref transaction with old_sha1 set");
+
+ if (refs_verify_refname_available(&refs->base, update->refname,
+ &affected_refnames, NULL, 1, err)) {
+ ret = TRANSACTION_NAME_CONFLICT;
+ goto cleanup;
+ }
+
+ /*
+ * packed-refs don't support symbolic refs and root refs, so we
+ * have to queue these references via the loose transaction.
+ */
+ if (update->new_target || is_root_ref(update->refname)) {
+ if (!loose_transaction) {
+ loose_transaction = ref_store_transaction_begin(&refs->base, 0, err);
+ if (!loose_transaction) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+ }
+
+ ref_transaction_add_update(loose_transaction, update->refname,
+ update->flags & ~REF_HAVE_OLD,
+ update->new_target ? NULL : &update->new_oid, NULL,
+ update->new_target, NULL, NULL);
+ } else {
+ ref_transaction_add_update(packed_transaction, update->refname,
+ update->flags & ~REF_HAVE_OLD,
+ &update->new_oid, &update->old_oid,
+ NULL, NULL, NULL);
+ }
+ }
+
+ if (packed_refs_lock(refs->packed_ref_store, 0, err) ||
+ ref_transaction_commit(packed_transaction, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+ packed_refs_unlock(refs->packed_ref_store);
+
+ if (loose_transaction) {
+ if (ref_transaction_prepare(loose_transaction, err) ||
+ ref_transaction_commit(loose_transaction, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (loose_transaction)
+ ref_transaction_free(loose_transaction);
+ if (packed_transaction)
+ ref_transaction_free(packed_transaction);
+ transaction->state = REF_TRANSACTION_CLOSED;
+ string_list_clear(&affected_refnames, 0);
+ return ret;
+}
+
static int files_transaction_finish(struct ref_store *ref_store,
struct ref_transaction *transaction,
struct strbuf *err)
@@ -2869,6 +3119,8 @@ static int files_transaction_finish(struct ref_store *ref_store,
assert(err);
+ if (transaction->flags & REF_TRANSACTION_FLAG_INITIAL)
+ return files_transaction_finish_initial(refs, transaction, err);
if (!transaction->nr) {
transaction->state = REF_TRANSACTION_CLOSED;
return 0;
@@ -2884,23 +3136,20 @@ static int files_transaction_finish(struct ref_store *ref_store,
if (update->flags & REF_NEEDS_COMMIT ||
update->flags & REF_LOG_ONLY) {
- if (files_log_ref_write(refs,
- lock->ref_name,
- &lock->old_oid,
- &update->new_oid,
- update->msg, update->flags,
- err)) {
- char *old_msg = strbuf_detach(err, NULL);
-
- strbuf_addf(err, "cannot update the ref '%s': %s",
- lock->ref_name, old_msg);
- free(old_msg);
- unlock_ref(lock);
- update->backend_data = NULL;
+ if (parse_and_write_reflog(refs, update, lock, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
}
+
+ /*
+ * We try creating a symlink, if that succeeds we continue to the
+ * next update. If not, we try and create a regular symref.
+ */
+ if (update->new_target && refs->prefer_symlink_refs)
+ if (!create_ref_symlink(lock, update->new_target))
+ continue;
+
if (update->flags & REF_NEEDS_COMMIT) {
clear_loose_ref_cache(refs);
if (commit_ref(lock)) {
@@ -3005,106 +3254,6 @@ static int files_transaction_abort(struct ref_store *ref_store,
return 0;
}
-static int ref_present(const char *refname,
- const struct object_id *oid UNUSED,
- int flags UNUSED,
- void *cb_data)
-{
- struct string_list *affected_refnames = cb_data;
-
- return string_list_has_string(affected_refnames, refname);
-}
-
-static int files_initial_transaction_commit(struct ref_store *ref_store,
- struct ref_transaction *transaction,
- struct strbuf *err)
-{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE,
- "initial_ref_transaction_commit");
- size_t i;
- int ret = 0;
- struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
- struct ref_transaction *packed_transaction = NULL;
-
- assert(err);
-
- if (transaction->state != REF_TRANSACTION_OPEN)
- BUG("commit called for transaction that is not open");
-
- /* Fail if a refname appears more than once in the transaction: */
- for (i = 0; i < transaction->nr; i++)
- string_list_append(&affected_refnames,
- transaction->updates[i]->refname);
- string_list_sort(&affected_refnames);
- if (ref_update_reject_duplicates(&affected_refnames, err)) {
- ret = TRANSACTION_GENERIC_ERROR;
- goto cleanup;
- }
-
- /*
- * It's really undefined to call this function in an active
- * repository or when there are existing references: we are
- * only locking and changing packed-refs, so (1) any
- * simultaneous processes might try to change a reference at
- * the same time we do, and (2) any existing loose versions of
- * the references that we are setting would have precedence
- * over our values. But some remote helpers create the remote
- * "HEAD" and "master" branches before calling this function,
- * so here we really only check that none of the references
- * that we are creating already exists.
- */
- if (refs_for_each_rawref(&refs->base, ref_present,
- &affected_refnames))
- BUG("initial ref transaction called with existing refs");
-
- packed_transaction = ref_store_transaction_begin(refs->packed_ref_store, err);
- if (!packed_transaction) {
- ret = TRANSACTION_GENERIC_ERROR;
- goto cleanup;
- }
-
- for (i = 0; i < transaction->nr; i++) {
- struct ref_update *update = transaction->updates[i];
-
- if ((update->flags & REF_HAVE_OLD) &&
- !is_null_oid(&update->old_oid))
- BUG("initial ref transaction with old_sha1 set");
- if (refs_verify_refname_available(&refs->base, update->refname,
- &affected_refnames, NULL,
- err)) {
- ret = TRANSACTION_NAME_CONFLICT;
- goto cleanup;
- }
-
- /*
- * Add a reference creation for this reference to the
- * packed-refs transaction:
- */
- ref_transaction_add_update(packed_transaction, update->refname,
- update->flags & ~REF_HAVE_OLD,
- &update->new_oid, &update->old_oid,
- NULL);
- }
-
- if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
- ret = TRANSACTION_GENERIC_ERROR;
- goto cleanup;
- }
-
- if (initial_ref_transaction_commit(packed_transaction, err)) {
- ret = TRANSACTION_GENERIC_ERROR;
- }
-
- packed_refs_unlock(refs->packed_ref_store);
-cleanup:
- if (packed_transaction)
- ref_transaction_free(packed_transaction);
- transaction->state = REF_TRANSACTION_CLOSED;
- string_list_clear(&affected_refnames, 0);
- return ret;
-}
-
struct expire_reflog_cb {
reflog_expiry_should_prune_fn *should_prune_fn;
void *policy_cb;
@@ -3248,7 +3397,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
rollback_lock_file(&reflog_lock);
} else if (update &&
(write_in_full(get_lock_file_fd(&lock->lk),
- oid_to_hex(&cb.last_kept_oid), the_hash_algo->hexsz) < 0 ||
+ oid_to_hex(&cb.last_kept_oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_str_in_full(get_lock_file_fd(&lock->lk), "\n") < 0 ||
close_ref_gently(lock) < 0)) {
status |= error("couldn't write %s",
@@ -3272,39 +3421,390 @@ static int files_reflog_expire(struct ref_store *ref_store,
return -1;
}
-static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
+static int files_ref_store_create_on_disk(struct ref_store *ref_store,
+ int flags,
+ struct strbuf *err UNUSED)
{
struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE, "init_db");
+ files_downcast(ref_store, REF_STORE_WRITE, "create");
struct strbuf sb = STRBUF_INIT;
/*
- * Create .git/refs/{heads,tags}
+ * We need to create a "refs" dir in any case so that older versions of
+ * Git can tell that this is a repository. This serves two main purposes:
+ *
+ * - Clients will know to stop walking the parent-directory chain when
+ * detecting the Git repository. Otherwise they may end up detecting
+ * a Git repository in a parent directory instead.
+ *
+ * - Instead of failing to detect a repository with unknown reference
+ * format altogether, old clients will print an error saying that
+ * they do not understand the reference format extension.
*/
- files_ref_path(refs, &sb, "refs/heads");
+ strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
safe_create_dir(sb.buf, 1);
+ adjust_shared_perm(sb.buf);
- strbuf_reset(&sb);
- files_ref_path(refs, &sb, "refs/tags");
- safe_create_dir(sb.buf, 1);
+ /*
+ * There is no need to create directories for common refs when creating
+ * a worktree ref store.
+ */
+ if (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE)) {
+ /*
+ * Create .git/refs/{heads,tags}
+ */
+ strbuf_reset(&sb);
+ files_ref_path(refs, &sb, "refs/heads");
+ safe_create_dir(sb.buf, 1);
+
+ strbuf_reset(&sb);
+ files_ref_path(refs, &sb, "refs/tags");
+ safe_create_dir(sb.buf, 1);
+ }
strbuf_release(&sb);
return 0;
}
+struct remove_one_root_ref_data {
+ const char *gitdir;
+ struct strbuf *err;
+};
+
+static int remove_one_root_ref(const char *refname,
+ void *cb_data)
+{
+ struct remove_one_root_ref_data *data = cb_data;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&buf, "%s/%s", data->gitdir, refname);
+
+ ret = unlink(buf.buf);
+ if (ret < 0)
+ strbuf_addf(data->err, "could not delete %s: %s\n",
+ refname, strerror(errno));
+
+ strbuf_release(&buf);
+ return ret;
+}
+
+static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_WRITE, "remove");
+ struct remove_one_root_ref_data data = {
+ .gitdir = refs->base.gitdir,
+ .err = err,
+ };
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete refs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/logs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete logs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0)
+ ret = -1;
+
+ if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0)
+ ret = -1;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+/*
+ * For refs and reflogs, they share a unified interface when scanning
+ * the whole directory. This function is used as the callback for each
+ * regular file or symlink in the directory.
+ */
+typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refname,
+ struct dir_iterator *iter);
+
+static int files_fsck_symref_target(struct fsck_options *o,
+ struct fsck_ref_report *report,
+ struct strbuf *referent,
+ unsigned int symbolic_link)
+{
+ int is_referent_root;
+ char orig_last_byte;
+ size_t orig_len;
+ int ret = 0;
+
+ orig_len = referent->len;
+ orig_last_byte = referent->buf[orig_len - 1];
+ if (!symbolic_link)
+ strbuf_rtrim(referent);
+
+ is_referent_root = is_root_ref(referent->buf);
+ if (!is_referent_root &&
+ !starts_with(referent->buf, "refs/") &&
+ !starts_with(referent->buf, "worktrees/")) {
+ ret = fsck_report_ref(o, report,
+ FSCK_MSG_SYMREF_TARGET_IS_NOT_A_REF,
+ "points to non-ref target '%s'", referent->buf);
+
+ }
+
+ if (!is_referent_root && check_refname_format(referent->buf, 0)) {
+ ret = fsck_report_ref(o, report,
+ FSCK_MSG_BAD_REFERENT_NAME,
+ "points to invalid refname '%s'", referent->buf);
+ goto out;
+ }
+
+ if (symbolic_link)
+ goto out;
+
+ if (referent->len == orig_len ||
+ (referent->len < orig_len && orig_last_byte != '\n')) {
+ ret = fsck_report_ref(o, report,
+ FSCK_MSG_REF_MISSING_NEWLINE,
+ "misses LF at the end");
+ }
+
+ if (referent->len != orig_len && referent->len != orig_len - 1) {
+ ret = fsck_report_ref(o, report,
+ FSCK_MSG_TRAILING_REF_CONTENT,
+ "has trailing whitespaces or newlines");
+ }
+
+out:
+ return ret;
+}
+
+static int files_fsck_refs_content(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *target_name,
+ struct dir_iterator *iter)
+{
+ struct strbuf ref_content = STRBUF_INIT;
+ struct strbuf abs_gitdir = STRBUF_INIT;
+ struct strbuf referent = STRBUF_INIT;
+ struct fsck_ref_report report = { 0 };
+ const char *trailing = NULL;
+ unsigned int type = 0;
+ int failure_errno = 0;
+ struct object_id oid;
+ int ret = 0;
+
+ report.path = target_name;
+
+ if (S_ISLNK(iter->st.st_mode)) {
+ const char *relative_referent_path = NULL;
+
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_SYMLINK_REF,
+ "use deprecated symbolic link for symref");
+
+ strbuf_add_absolute_path(&abs_gitdir, ref_store->repo->gitdir);
+ strbuf_normalize_path(&abs_gitdir);
+ if (!is_dir_sep(abs_gitdir.buf[abs_gitdir.len - 1]))
+ strbuf_addch(&abs_gitdir, '/');
+
+ strbuf_add_real_path(&ref_content, iter->path.buf);
+ skip_prefix(ref_content.buf, abs_gitdir.buf,
+ &relative_referent_path);
+
+ if (relative_referent_path)
+ strbuf_addstr(&referent, relative_referent_path);
+ else
+ strbuf_addbuf(&referent, &ref_content);
+
+ ret |= files_fsck_symref_target(o, &report, &referent, 1);
+ goto cleanup;
+ }
+
+ if (strbuf_read_file(&ref_content, iter->path.buf, 0) < 0) {
+ /*
+ * Ref file could be removed by another concurrent process. We should
+ * ignore this error and continue to the next ref.
+ */
+ if (errno == ENOENT)
+ goto cleanup;
+
+ ret = error_errno(_("cannot read ref file '%s'"), iter->path.buf);
+ goto cleanup;
+ }
+
+ if (parse_loose_ref_contents(ref_store->repo->hash_algo,
+ ref_content.buf, &oid, &referent,
+ &type, &trailing, &failure_errno)) {
+ strbuf_rtrim(&ref_content);
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_CONTENT,
+ "%s", ref_content.buf);
+ goto cleanup;
+ }
+
+ if (!(type & REF_ISSYMREF)) {
+ if (!*trailing) {
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_REF_MISSING_NEWLINE,
+ "misses LF at the end");
+ goto cleanup;
+ }
+ if (*trailing != '\n' || *(trailing + 1)) {
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_TRAILING_REF_CONTENT,
+ "has trailing garbage: '%s'", trailing);
+ goto cleanup;
+ }
+ } else {
+ ret = files_fsck_symref_target(o, &report, &referent, 0);
+ goto cleanup;
+ }
+
+cleanup:
+ strbuf_release(&ref_content);
+ strbuf_release(&referent);
+ strbuf_release(&abs_gitdir);
+ return ret;
+}
+
+static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o,
+ const char *refname,
+ struct dir_iterator *iter)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ /*
+ * Ignore the files ending with ".lock" as they may be lock files
+ * However, do not allow bare ".lock" files.
+ */
+ if (iter->basename[0] != '.' && ends_with(iter->basename, ".lock"))
+ goto cleanup;
+
+ /*
+ * This works right now because we never check the root refs.
+ */
+ if (check_refname_format(refname, 0)) {
+ struct fsck_ref_report report = { 0 };
+
+ report.path = refname;
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_NAME,
+ "invalid refname format");
+ }
+
+cleanup:
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int files_fsck_refs_dir(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ struct worktree *wt,
+ files_fsck_refs_fn *fsck_refs_fn)
+{
+ struct strbuf refname = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT;
+ struct dir_iterator *iter;
+ int iter_status;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/%s", ref_store->gitdir, refs_check_dir);
+
+ iter = dir_iterator_begin(sb.buf, 0);
+ if (!iter) {
+ ret = error_errno(_("cannot open directory %s"), sb.buf);
+ goto out;
+ }
+
+ while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
+ if (S_ISDIR(iter->st.st_mode)) {
+ continue;
+ } else if (S_ISREG(iter->st.st_mode) ||
+ S_ISLNK(iter->st.st_mode)) {
+ strbuf_reset(&refname);
+
+ if (!is_main_worktree(wt))
+ strbuf_addf(&refname, "worktrees/%s/", wt->id);
+ strbuf_addf(&refname, "%s/%s", refs_check_dir,
+ iter->relative_path);
+
+ if (o->verbose)
+ fprintf_ln(stderr, "Checking %s", refname.buf);
+
+ for (size_t i = 0; fsck_refs_fn[i]; i++) {
+ if (fsck_refs_fn[i](ref_store, o, refname.buf, iter))
+ ret = -1;
+ }
+ } else {
+ struct fsck_ref_report report = { .path = iter->basename };
+ if (fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_FILETYPE,
+ "unexpected file type"))
+ ret = -1;
+ }
+ }
+
+ if (iter_status != ITER_DONE)
+ ret = error(_("failed to iterate over '%s'"), sb.buf);
+
+out:
+ strbuf_release(&sb);
+ strbuf_release(&refname);
+ return ret;
+}
+
+static int files_fsck_refs(struct ref_store *ref_store,
+ struct fsck_options *o,
+ struct worktree *wt)
+{
+ files_fsck_refs_fn fsck_refs_fn[]= {
+ files_fsck_refs_name,
+ files_fsck_refs_content,
+ NULL,
+ };
+
+ if (o->verbose)
+ fprintf_ln(stderr, _("Checking references consistency"));
+ return files_fsck_refs_dir(ref_store, o, "refs", wt, fsck_refs_fn);
+}
+
+static int files_fsck(struct ref_store *ref_store,
+ struct fsck_options *o,
+ struct worktree *wt)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_READ, "fsck");
+
+ return files_fsck_refs(ref_store, o, wt) |
+ refs->packed_ref_store->be->fsck(refs->packed_ref_store, o, wt);
+}
+
struct ref_storage_be refs_be_files = {
- .next = NULL,
.name = "files",
- .init = files_ref_store_create,
- .init_db = files_init_db,
+ .init = files_ref_store_init,
+ .release = files_ref_store_release,
+ .create_on_disk = files_ref_store_create_on_disk,
+ .remove_on_disk = files_ref_store_remove_on_disk,
+
.transaction_prepare = files_transaction_prepare,
.transaction_finish = files_transaction_finish,
.transaction_abort = files_transaction_abort,
- .initial_transaction_commit = files_initial_transaction_commit,
.pack_refs = files_pack_refs,
- .create_symref = files_create_symref,
- .delete_refs = files_delete_refs,
.rename_ref = files_rename_ref,
.copy_ref = files_copy_ref,
@@ -3318,5 +3818,7 @@ struct ref_storage_be refs_be_files = {
.reflog_exists = files_reflog_exists,
.create_reflog = files_create_reflog,
.delete_reflog = files_delete_reflog,
- .reflog_expire = files_reflog_expire
+ .reflog_expire = files_reflog_expire,
+
+ .fsck = files_fsck,
};
diff --git a/refs/iterator.c b/refs/iterator.c
index 6b680f610e..8e999d81fc 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -25,12 +25,11 @@ int ref_iterator_abort(struct ref_iterator *ref_iterator)
}
void base_ref_iterator_init(struct ref_iterator *iter,
- struct ref_iterator_vtable *vtable,
- int ordered)
+ struct ref_iterator_vtable *vtable)
{
iter->vtable = vtable;
- iter->ordered = !!ordered;
iter->refname = NULL;
+ iter->referent = NULL;
iter->oid = NULL;
iter->flags = 0;
}
@@ -74,7 +73,7 @@ struct ref_iterator *empty_ref_iterator_begin(void)
struct empty_ref_iterator *iter = xcalloc(1, sizeof(*iter));
struct ref_iterator *ref_iterator = &iter->base;
- base_ref_iterator_init(ref_iterator, &empty_ref_iterator_vtable, 1);
+ base_ref_iterator_init(ref_iterator, &empty_ref_iterator_vtable);
return ref_iterator;
}
@@ -98,6 +97,49 @@ struct merge_ref_iterator {
struct ref_iterator **current;
};
+enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
+ struct ref_iterator *iter_common,
+ void *cb_data UNUSED)
+{
+ if (iter_worktree && !iter_common) {
+ /*
+ * Return the worktree ref if there are no more common refs.
+ */
+ return ITER_SELECT_0;
+ } else if (iter_common) {
+ /*
+ * In case we have pending worktree and common refs we need to
+ * yield them based on their lexicographical order. Worktree
+ * refs that have the same name as common refs shadow the
+ * latter.
+ */
+ if (iter_worktree) {
+ int cmp = strcmp(iter_worktree->refname,
+ iter_common->refname);
+ if (cmp < 0)
+ return ITER_SELECT_0;
+ else if (!cmp)
+ return ITER_SELECT_0_SKIP_1;
+ }
+
+ /*
+ * We now know that the lexicographically-next ref is a common
+ * ref. When the common ref is a shared one we return it.
+ */
+ if (parse_worktree_ref(iter_common->refname, NULL, NULL,
+ NULL) == REF_WORKTREE_SHARED)
+ return ITER_SELECT_1;
+
+ /*
+ * Otherwise, if the common ref is a per-worktree ref we skip
+ * it because it would belong to the main worktree, not ours.
+ */
+ return ITER_SKIP_1;
+ } else {
+ return ITER_DONE;
+ }
+}
+
static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
{
struct merge_ref_iterator *iter =
@@ -158,6 +200,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
if (selection & ITER_YIELD_CURRENT) {
+ iter->base.referent = (*iter->current)->referent;
iter->base.refname = (*iter->current)->refname;
iter->base.oid = (*iter->current)->oid;
iter->base.flags = (*iter->current)->flags;
@@ -207,7 +250,6 @@ static struct ref_iterator_vtable merge_ref_iterator_vtable = {
};
struct ref_iterator *merge_ref_iterator_begin(
- int ordered,
struct ref_iterator *iter0, struct ref_iterator *iter1,
ref_iterator_select_fn *select, void *cb_data)
{
@@ -222,7 +264,7 @@ struct ref_iterator *merge_ref_iterator_begin(
* references through only if they exist in both iterators.
*/
- base_ref_iterator_init(ref_iterator, &merge_ref_iterator_vtable, ordered);
+ base_ref_iterator_init(ref_iterator, &merge_ref_iterator_vtable);
iter->iter0 = iter0;
iter->iter1 = iter1;
iter->select = select;
@@ -271,12 +313,9 @@ struct ref_iterator *overlay_ref_iterator_begin(
} else if (is_empty_ref_iterator(back)) {
ref_iterator_abort(back);
return front;
- } else if (!front->ordered || !back->ordered) {
- BUG("overlay_ref_iterator requires ordered inputs");
}
- return merge_ref_iterator_begin(1, front, back,
- overlay_iterator_select, NULL);
+ return merge_ref_iterator_begin(front, back, overlay_iterator_select, NULL);
}
struct prefix_ref_iterator {
@@ -315,16 +354,12 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
if (cmp > 0) {
/*
- * If the source iterator is ordered, then we
+ * As the source iterator is ordered, we
* can stop the iteration as soon as we see a
* refname that comes after the prefix:
*/
- if (iter->iter0->ordered) {
- ok = ref_iterator_abort(iter->iter0);
- break;
- } else {
- continue;
- }
+ ok = ref_iterator_abort(iter->iter0);
+ break;
}
if (iter->trim) {
@@ -396,7 +431,7 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
CALLOC_ARRAY(iter, 1);
ref_iterator = &iter->base;
- base_ref_iterator_init(ref_iterator, &prefix_ref_iterator_vtable, iter0->ordered);
+ base_ref_iterator_init(ref_iterator, &prefix_ref_iterator_vtable);
iter->iter0 = iter0;
iter->prefix = xstrdup(prefix);
@@ -407,15 +442,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
struct ref_iterator *current_ref_iter = NULL;
-int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter,
- each_repo_ref_fn fn, void *cb_data)
+int do_for_each_ref_iterator(struct ref_iterator *iter,
+ each_ref_fn fn, void *cb_data)
{
int retval = 0, ok;
struct ref_iterator *old_ref_iter = current_ref_iter;
current_ref_iter = iter;
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- retval = fn(r, iter->refname, iter->oid, iter->flags, cb_data);
+ retval = fn(iter->refname, iter->referent, iter->oid, iter->flags, cb_data);
if (retval) {
/*
* If ref_iterator_abort() returns ITER_ERROR,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 59c78d7941..3406f1e71d 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1,6 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../git-compat-util.h"
-#include "../alloc.h"
#include "../config.h"
+#include "../dir.h"
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
@@ -11,6 +13,7 @@
#include "../lockfile.h"
#include "../chdir-notify.h"
#include "../statinfo.h"
+#include "../worktree.h"
#include "../wrapper.h"
#include "../write-or-die.h"
#include "../trace2.h"
@@ -201,9 +204,14 @@ static int release_snapshot(struct snapshot *snapshot)
}
}
-struct ref_store *packed_ref_store_create(struct repository *repo,
- const char *gitdir,
- unsigned int store_flags)
+static size_t snapshot_hexsz(const struct snapshot *snapshot)
+{
+ return snapshot->refs->base.repo->hash_algo->hexsz;
+}
+
+struct ref_store *packed_ref_store_init(struct repository *repo,
+ const char *gitdir,
+ unsigned int store_flags)
{
struct packed_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
@@ -253,6 +261,15 @@ static void clear_snapshot(struct packed_ref_store *refs)
}
}
+static void packed_ref_store_release(struct ref_store *ref_store)
+{
+ struct packed_ref_store *refs = packed_downcast(ref_store, 0, "release");
+ clear_snapshot(refs);
+ rollback_lock_file(&refs->lock);
+ delete_tempfile(&refs->tempfile);
+ free(refs->path);
+}
+
static NORETURN void die_unterminated_line(const char *path,
const char *p, size_t len)
{
@@ -281,11 +298,13 @@ struct snapshot_record {
size_t len;
};
-static int cmp_packed_ref_records(const void *v1, const void *v2)
+static int cmp_packed_ref_records(const void *v1, const void *v2,
+ void *cb_data)
{
+ const struct snapshot *snapshot = cb_data;
const struct snapshot_record *e1 = v1, *e2 = v2;
- const char *r1 = e1->start + the_hash_algo->hexsz + 1;
- const char *r2 = e2->start + the_hash_algo->hexsz + 1;
+ const char *r1 = e1->start + snapshot_hexsz(snapshot) + 1;
+ const char *r2 = e2->start + snapshot_hexsz(snapshot) + 1;
while (1) {
if (*r1 == '\n')
@@ -306,9 +325,9 @@ static int cmp_packed_ref_records(const void *v1, const void *v2)
* refname.
*/
static int cmp_record_to_refname(const char *rec, const char *refname,
- int start)
+ int start, const struct snapshot *snapshot)
{
- const char *r1 = rec + the_hash_algo->hexsz + 1;
+ const char *r1 = rec + snapshot_hexsz(snapshot) + 1;
const char *r2 = refname;
while (1) {
@@ -355,7 +374,7 @@ static void sort_snapshot(struct snapshot *snapshot)
if (!eol)
/* The safety check should prevent this. */
BUG("unterminated line found in packed-refs");
- if (eol - pos < the_hash_algo->hexsz + 2)
+ if (eol - pos < snapshot_hexsz(snapshot) + 2)
die_invalid_line(snapshot->refs->path,
pos, eof - pos);
eol++;
@@ -381,7 +400,7 @@ static void sort_snapshot(struct snapshot *snapshot)
if (sorted &&
nr > 1 &&
cmp_packed_ref_records(&records[nr - 2],
- &records[nr - 1]) >= 0)
+ &records[nr - 1], snapshot) >= 0)
sorted = 0;
pos = eol;
@@ -391,7 +410,7 @@ static void sort_snapshot(struct snapshot *snapshot)
goto cleanup;
/* We need to sort the memory. First we sort the records array: */
- QSORT(records, nr, cmp_packed_ref_records);
+ QSORT_S(records, nr, cmp_packed_ref_records, snapshot);
/*
* Allocate a new chunk of memory, and copy the old memory to
@@ -467,7 +486,8 @@ static void verify_buffer_safe(struct snapshot *snapshot)
return;
last_line = find_start_of_record(start, eof - 1);
- if (*(eof - 1) != '\n' || eof - last_line < the_hash_algo->hexsz + 2)
+ if (*(eof - 1) != '\n' ||
+ eof - last_line < snapshot_hexsz(snapshot) + 2)
die_invalid_line(snapshot->refs->path,
last_line, eof - last_line);
}
@@ -562,7 +582,7 @@ static const char *find_reference_location_1(struct snapshot *snapshot,
mid = lo + (hi - lo) / 2;
rec = find_start_of_record(lo, mid);
- cmp = cmp_record_to_refname(rec, refname, start);
+ cmp = cmp_record_to_refname(rec, refname, start, snapshot);
if (cmp < 0) {
lo = find_end_of_record(mid, hi);
} else if (cmp > 0) {
@@ -775,7 +795,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname,
return -1;
}
- if (get_oid_hex(rec, oid))
+ if (get_oid_hex_algop(rec, oid, ref_store->repo->hash_algo))
die_invalid_line(refs->path, rec, snapshot->eof - rec);
*type = REF_ISPACKED;
@@ -859,8 +879,8 @@ static int next_record(struct packed_ref_iterator *iter)
iter->base.flags = REF_ISPACKED;
p = iter->pos;
- if (iter->eof - p < the_hash_algo->hexsz + 2 ||
- parse_oid_hex(p, &iter->oid, &p) ||
+ if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
+ parse_oid_hex_algop(p, &iter->oid, &p, iter->repo->hash_algo) ||
!isspace(*p++))
die_invalid_line(iter->snapshot->refs->path,
iter->pos, iter->eof - iter->pos);
@@ -877,7 +897,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (!refname_is_safe(iter->base.refname))
die("packed refname is dangerous: %s",
iter->base.refname);
- oidclr(&iter->oid);
+ oidclr(&iter->oid, iter->repo->hash_algo);
iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN;
}
if (iter->snapshot->peeled == PEELED_FULLY ||
@@ -889,8 +909,8 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->pos < iter->eof && *iter->pos == '^') {
p = iter->pos + 1;
- if (iter->eof - p < the_hash_algo->hexsz + 1 ||
- parse_oid_hex(p, &iter->peeled, &p) ||
+ if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 ||
+ parse_oid_hex_algop(p, &iter->peeled, &p, iter->repo->hash_algo) ||
*p++ != '\n')
die_invalid_line(iter->snapshot->refs->path,
iter->pos, iter->eof - iter->pos);
@@ -902,13 +922,13 @@ static int next_record(struct packed_ref_iterator *iter)
* we suppress it if the reference is broken:
*/
if ((iter->base.flags & REF_ISBROKEN)) {
- oidclr(&iter->peeled);
+ oidclr(&iter->peeled, iter->repo->hash_algo);
iter->base.flags &= ~REF_KNOWS_PEELED;
} else {
iter->base.flags |= REF_KNOWS_PEELED;
}
} else {
- oidclr(&iter->peeled);
+ oidclr(&iter->peeled, iter->repo->hash_algo);
}
return ITER_OK;
@@ -945,16 +965,13 @@ static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
struct packed_ref_iterator *iter =
(struct packed_ref_iterator *)ref_iterator;
- if (iter->repo != the_repository)
- BUG("peeling for non-the_repository is not supported");
-
if ((iter->base.flags & REF_KNOWS_PEELED)) {
oidcpy(peeled, &iter->peeled);
return is_null_oid(&iter->peeled) ? -1 : 0;
} else if ((iter->base.flags & (REF_ISBROKEN | REF_ISSYMREF))) {
return -1;
} else {
- return peel_object(&iter->oid, peeled) ? -1 : 0;
+ return peel_object(iter->repo, &iter->oid, peeled) ? -1 : 0;
}
}
@@ -1112,7 +1129,7 @@ static struct ref_iterator *packed_ref_iterator_begin(
CALLOC_ARRAY(iter, 1);
ref_iterator = &iter->base;
- base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable, 1);
+ base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable);
if (exclude_patterns)
populate_excluded_jump_list(iter, snapshot, exclude_patterns);
@@ -1234,6 +1251,24 @@ int packed_refs_is_locked(struct ref_store *ref_store)
return is_lock_file_locked(&refs->lock);
}
+int packed_refs_size(struct ref_store *ref_store,
+ size_t *out)
+{
+ struct packed_ref_store *refs = packed_downcast(ref_store, REF_STORE_READ,
+ "packed_refs_size");
+ struct stat st;
+
+ if (stat(refs->path, &st) < 0) {
+ if (errno != ENOENT)
+ return -1;
+ *out = 0;
+ return 0;
+ }
+
+ *out = st.st_size;
+ return 0;
+}
+
/*
* The packed-refs header line that we write out. Perhaps other traits
* will be added later.
@@ -1245,13 +1280,27 @@ int packed_refs_is_locked(struct ref_store *ref_store)
static const char PACKED_REFS_HEADER[] =
"# pack-refs with: peeled fully-peeled sorted \n";
-static int packed_init_db(struct ref_store *ref_store UNUSED,
- struct strbuf *err UNUSED)
+static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED,
+ int flags UNUSED,
+ struct strbuf *err UNUSED)
{
/* Nothing to do. */
return 0;
}
+static int packed_ref_store_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct packed_ref_store *refs = packed_downcast(ref_store, 0, "remove");
+
+ if (remove_path(refs->path) < 0) {
+ strbuf_addstr(err, "could not delete packed-refs");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Write the packed refs from the current snapshot to the packed-refs
* tempfile, incorporating any changes from `updates`. `updates` must
@@ -1412,7 +1461,8 @@ static int write_with_updates(struct packed_ref_store *refs,
i++;
} else {
struct object_id peeled;
- int peel_error = peel_object(&update->new_oid,
+ int peel_error = peel_object(refs->base.repo,
+ &update->new_oid,
&peeled);
if (write_packed_entry(out, update->refname,
@@ -1681,62 +1731,6 @@ cleanup:
return ret;
}
-static int packed_initial_transaction_commit(struct ref_store *ref_store UNUSED,
- struct ref_transaction *transaction,
- struct strbuf *err)
-{
- return ref_transaction_commit(transaction, err);
-}
-
-static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
- struct string_list *refnames, unsigned int flags)
-{
- struct packed_ref_store *refs =
- packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
- struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction;
- struct string_list_item *item;
- int ret;
-
- (void)refs; /* We need the check above, but don't use the variable */
-
- if (!refnames->nr)
- return 0;
-
- /*
- * Since we don't check the references' old_oids, the
- * individual updates can't fail, so we can pack all of the
- * updates into a single transaction.
- */
-
- transaction = ref_store_transaction_begin(ref_store, &err);
- if (!transaction)
- return -1;
-
- for_each_string_list_item(item, refnames) {
- if (ref_transaction_delete(transaction, item->string, NULL,
- flags, msg, &err)) {
- warning(_("could not delete reference %s: %s"),
- item->string, err.buf);
- strbuf_reset(&err);
- }
- }
-
- ret = ref_transaction_commit(transaction, &err);
-
- if (ret) {
- if (refnames->nr == 1)
- error(_("could not delete reference %s: %s"),
- refnames->items[0].string, err.buf);
- else
- error(_("could not delete references: %s"), err.buf);
- }
-
- ref_transaction_free(transaction);
- strbuf_release(&err);
- return ret;
-}
-
static int packed_pack_refs(struct ref_store *ref_store UNUSED,
struct pack_refs_opts *pack_opts UNUSED)
{
@@ -1753,19 +1747,29 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
return empty_ref_iterator_begin();
}
+static int packed_fsck(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o UNUSED,
+ struct worktree *wt)
+{
+
+ if (!is_main_worktree(wt))
+ return 0;
+
+ return 0;
+}
+
struct ref_storage_be refs_be_packed = {
- .next = NULL,
.name = "packed",
- .init = packed_ref_store_create,
- .init_db = packed_init_db,
+ .init = packed_ref_store_init,
+ .release = packed_ref_store_release,
+ .create_on_disk = packed_ref_store_create_on_disk,
+ .remove_on_disk = packed_ref_store_remove_on_disk,
+
.transaction_prepare = packed_transaction_prepare,
.transaction_finish = packed_transaction_finish,
.transaction_abort = packed_transaction_abort,
- .initial_transaction_commit = packed_initial_transaction_commit,
.pack_refs = packed_pack_refs,
- .create_symref = NULL,
- .delete_refs = packed_delete_refs,
.rename_ref = NULL,
.copy_ref = NULL,
@@ -1780,4 +1784,6 @@ struct ref_storage_be refs_be_packed = {
.create_reflog = NULL,
.delete_reflog = NULL,
.reflog_expire = NULL,
+
+ .fsck = packed_fsck,
};
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index 9dd8a344c3..9481d5e7c2 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -13,9 +13,9 @@ struct ref_transaction;
* even among packed refs.
*/
-struct ref_store *packed_ref_store_create(struct repository *repo,
- const char *gitdir,
- unsigned int store_flags);
+struct ref_store *packed_ref_store_init(struct repository *repo,
+ const char *gitdir,
+ unsigned int store_flags);
/*
* Lock the packed-refs file for writing. Flags is passed to
@@ -28,6 +28,13 @@ void packed_refs_unlock(struct ref_store *ref_store);
int packed_refs_is_locked(struct ref_store *ref_store);
/*
+ * Obtain the size of the `packed-refs` file. Reports `0` as size in case there
+ * is no packed-refs file. Returns 0 on success, negative otherwise.
+ */
+int packed_refs_size(struct ref_store *ref_store,
+ size_t *out);
+
+/*
* Return true if `transaction` really needs to be carried out against
* the specified packed_ref_store, or false if it can be skipped
* (i.e., because it is an obvious NOOP). `ref_store` must be locked
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 2294c4564f..35bae7e05d 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -1,5 +1,4 @@
#include "../git-compat-util.h"
-#include "../alloc.h"
#include "../hash.h"
#include "../refs.h"
#include "../repository.h"
@@ -35,6 +34,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
}
struct ref_entry *create_ref_entry(const char *refname,
+ const char *referent,
const struct object_id *oid, int flag)
{
struct ref_entry *ref;
@@ -42,6 +42,8 @@ struct ref_entry *create_ref_entry(const char *refname,
FLEX_ALLOC_STR(ref, name, refname);
oidcpy(&ref->u.value.oid, oid);
ref->flag = flag;
+ ref->u.value.referent = xstrdup_or_null(referent);
+
return ref;
}
@@ -67,11 +69,14 @@ static void free_ref_entry(struct ref_entry *entry)
*/
clear_ref_dir(&entry->u.subdir);
}
+ free(entry->u.value.referent);
free(entry);
}
void free_ref_cache(struct ref_cache *cache)
{
+ if (!cache)
+ return;
free_ref_entry(cache->root);
free(cache);
}
@@ -412,7 +417,8 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
if (level->prefix_state == PREFIX_WITHIN_DIR) {
entry_prefix_state = overlaps_prefix(entry->name, iter->prefix);
- if (entry_prefix_state == PREFIX_EXCLUDES_DIR)
+ if (entry_prefix_state == PREFIX_EXCLUDES_DIR ||
+ (entry_prefix_state == PREFIX_WITHIN_DIR && !(entry->flag & REF_DIR)))
continue;
} else {
entry_prefix_state = level->prefix_state;
@@ -429,6 +435,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
level->index = -1;
} else {
iter->base.refname = entry->name;
+ iter->base.referent = entry->u.value.referent;
iter->base.oid = &entry->u.value.oid;
iter->base.flags = entry->flag;
return ITER_OK;
@@ -441,10 +448,7 @@ static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
{
struct cache_ref_iterator *iter =
(struct cache_ref_iterator *)ref_iterator;
-
- if (iter->repo != the_repository)
- BUG("peeling for non-the_repository is not supported");
- return peel_object(ref_iterator->oid, peeled) ? -1 : 0;
+ return peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;
}
static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator)
@@ -486,7 +490,7 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
CALLOC_ARRAY(iter, 1);
ref_iterator = &iter->base;
- base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable, 1);
+ base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable);
ALLOC_GROW(iter->levels, 10, iter->levels_alloc);
iter->levels_nr = 1;
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 95c76e27c8..5f04e518c3 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -1,7 +1,7 @@
#ifndef REFS_REF_CACHE_H
#define REFS_REF_CACHE_H
-#include "hash-ll.h"
+#include "hash.h"
struct ref_dir;
struct ref_store;
@@ -42,6 +42,7 @@ struct ref_value {
* referred to by the last reference in the symlink chain.
*/
struct object_id oid;
+ char *referent;
};
/*
@@ -173,6 +174,7 @@ struct ref_entry *create_dir_entry(struct ref_cache *cache,
const char *dirname, size_t len);
struct ref_entry *create_ref_entry(const char *refname,
+ const char *referent,
const struct object_id *oid, int flag);
/*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 9db8aec4da..58aa56d1b2 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -4,6 +4,7 @@
#include "refs.h"
#include "iterator.h"
+struct fsck_options;
struct ref_transaction;
/*
@@ -69,40 +70,6 @@ int ref_resolves_to_object(const char *refname,
const struct object_id *oid,
unsigned int flags);
-enum peel_status {
- /* object was peeled successfully: */
- PEEL_PEELED = 0,
-
- /*
- * object cannot be peeled because the named object (or an
- * object referred to by a tag in the peel chain), does not
- * exist.
- */
- PEEL_INVALID = -1,
-
- /* object cannot be peeled because it is not a tag: */
- PEEL_NON_TAG = -2,
-
- /* ref_entry contains no peeled value because it is a symref: */
- PEEL_IS_SYMREF = -3,
-
- /*
- * ref_entry cannot be peeled because it is broken (i.e., the
- * symbolic reference cannot even be resolved to an object
- * name):
- */
- PEEL_BROKEN = -4
-};
-
-/*
- * Peel the named object; i.e., if the object is a tag, resolve the
- * tag recursively until a non-tag is found. If successful, store the
- * result to oid and return PEEL_PEELED. If the object is not a tag
- * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,
- * and leave oid unchanged.
- */
-enum peel_status peel_object(const struct object_id *name, struct object_id *oid);
-
/**
* Information needed for a single ref update. Set new_oid to the new
* value or to null_oid to delete the ref. To check the old value
@@ -125,6 +92,19 @@ struct ref_update {
struct object_id old_oid;
/*
+ * If set, point the reference to this value. This can also be
+ * used to convert regular references to become symbolic refs.
+ * Cannot be set together with `new_oid`.
+ */
+ const char *new_target;
+
+ /*
+ * If set, check that the reference previously pointed to this
+ * value. Cannot be set together with `old_oid`.
+ */
+ const char *old_target;
+
+ /*
* One or more of REF_NO_DEREF, REF_FORCE_CREATE_REFLOG,
* REF_HAVE_NEW, REF_HAVE_OLD, or backend-specific flags.
*/
@@ -173,6 +153,7 @@ struct ref_update *ref_transaction_add_update(
const char *refname, unsigned int flags,
const struct object_id *new_oid,
const struct object_id *old_oid,
+ const char *new_target, const char *old_target,
const char *msg);
/*
@@ -212,6 +193,7 @@ struct ref_transaction {
size_t nr;
enum ref_transaction_state state;
void *backend_data;
+ unsigned int flags;
};
/*
@@ -260,6 +242,12 @@ enum do_for_each_ref_flags {
* INCLUDE_BROKEN, since they are otherwise not included at all.
*/
DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
+
+ /*
+ * Include root refs i.e. HEAD and pseudorefs along with the regular
+ * refs.
+ */
+ DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
};
/*
@@ -312,14 +300,8 @@ enum do_for_each_ref_flags {
*/
struct ref_iterator {
struct ref_iterator_vtable *vtable;
-
- /*
- * Does this `ref_iterator` iterate over references in order
- * by refname?
- */
- unsigned int ordered : 1;
-
const char *refname;
+ const char *referent;
const struct object_id *oid;
unsigned int flags;
};
@@ -387,14 +369,21 @@ typedef enum iterator_selection ref_iterator_select_fn(
void *cb_data);
/*
+ * An implementation of ref_iterator_select_fn that merges worktree and common
+ * refs. Per-worktree refs from the common iterator are ignored, worktree refs
+ * override common refs. Refs are selected lexicographically.
+ */
+enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
+ struct ref_iterator *iter_common,
+ void *cb_data);
+
+/*
* Iterate over the entries from iter0 and iter1, with the values
* interleaved as directed by the select function. The iterator takes
* ownership of iter0 and iter1 and frees them when the iteration is
- * over. A derived class should set `ordered` to 1 or 0 based on
- * whether it generates its output in order by reference name.
+ * over.
*/
struct ref_iterator *merge_ref_iterator_begin(
- int ordered,
struct ref_iterator *iter0, struct ref_iterator *iter1,
ref_iterator_select_fn *select, void *cb_data);
@@ -423,8 +412,6 @@ struct ref_iterator *overlay_ref_iterator_begin(
* As an convenience to callers, if prefix is the empty string and
* trim is zero, this function returns iter0 directly, without
* wrapping it.
- *
- * The resulting ref_iterator is ordered if iter0 is.
*/
struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
const char *prefix,
@@ -435,14 +422,11 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
/*
* Base class constructor for ref_iterators. Initialize the
* ref_iterator part of iter, setting its vtable pointer as specified.
- * `ordered` should be set to 1 if the iterator will iterate over
- * references in order by refname; otherwise it should be set to 0.
* This is meant to be called only by the initializers of derived
* classes.
*/
void base_ref_iterator_init(struct ref_iterator *iter,
- struct ref_iterator_vtable *vtable,
- int ordered);
+ struct ref_iterator_vtable *vtable);
/*
* Base class destructor for ref_iterators. Destroy the ref_iterator
@@ -502,9 +486,8 @@ extern struct ref_iterator *current_ref_iter;
* adapter between the callback style of reference iteration and the
* iterator style.
*/
-int do_for_each_repo_ref_iterator(struct repository *r,
- struct ref_iterator *iter,
- each_repo_ref_fn fn, void *cb_data);
+int do_for_each_ref_iterator(struct ref_iterator *iter,
+ each_ref_fn fn, void *cb_data);
struct ref_store;
@@ -528,8 +511,20 @@ struct ref_store;
typedef struct ref_store *ref_store_init_fn(struct repository *repo,
const char *gitdir,
unsigned int flags);
+/*
+ * Release all memory and resources associated with the ref store.
+ */
+typedef void ref_store_release_fn(struct ref_store *refs);
+
+typedef int ref_store_create_on_disk_fn(struct ref_store *refs,
+ int flags,
+ struct strbuf *err);
-typedef int ref_init_db_fn(struct ref_store *refs, struct strbuf *err);
+/*
+ * Remove the reference store from disk.
+ */
+typedef int ref_store_remove_on_disk_fn(struct ref_store *refs,
+ struct strbuf *err);
typedef int ref_transaction_prepare_fn(struct ref_store *refs,
struct ref_transaction *transaction,
@@ -549,12 +544,6 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,
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,
- const char *logmsg);
-typedef int delete_refs_fn(struct ref_store *ref_store, const char *msg,
- struct string_list *refnames, unsigned int flags);
typedef int rename_ref_fn(struct ref_store *ref_store,
const char *oldref, const char *newref,
const char *logmsg);
@@ -664,20 +653,22 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refname,
struct strbuf *referent);
+typedef int fsck_fn(struct ref_store *ref_store,
+ struct fsck_options *o,
+ struct worktree *wt);
+
struct ref_storage_be {
- struct ref_storage_be *next;
const char *name;
ref_store_init_fn *init;
- ref_init_db_fn *init_db;
+ ref_store_release_fn *release;
+ ref_store_create_on_disk_fn *create_on_disk;
+ ref_store_remove_on_disk_fn *remove_on_disk;
ref_transaction_prepare_fn *transaction_prepare;
ref_transaction_finish_fn *transaction_finish;
ref_transaction_abort_fn *transaction_abort;
- ref_transaction_commit_fn *initial_transaction_commit;
pack_refs_fn *pack_refs;
- create_symref_fn *create_symref;
- delete_refs_fn *delete_refs;
rename_ref_fn *rename_ref;
copy_ref_fn *copy_ref;
@@ -692,15 +683,18 @@ struct ref_storage_be {
create_reflog_fn *create_reflog;
delete_reflog_fn *delete_reflog;
reflog_expire_fn *reflog_expire;
+
+ fsck_fn *fsck;
};
extern struct ref_storage_be refs_be_files;
+extern struct ref_storage_be refs_be_reftable;
extern struct ref_storage_be refs_be_packed;
/*
* A representation of the reference store for the main repository or
* a submodule. The ref_store instances for submodules are kept in a
- * hash map; see get_submodule_ref_store() for more info.
+ * hash map; see repo_get_submodule_ref_store() for more info.
*/
struct ref_store {
/* The backend describing this ref_store's storage scheme: */
@@ -719,9 +713,10 @@ struct ref_store {
* Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for
* invalid contents.
*/
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+ const char *buf, struct object_id *oid,
struct strbuf *referent, unsigned int *type,
- int *failure_errno);
+ const char **trailing, int *failure_errno);
/*
* Fill in the generic part of refs and add it to our collection of
@@ -735,4 +730,31 @@ void base_ref_store_init(struct ref_store *refs, struct repository *repo,
*/
struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_store *store);
+/*
+ * Return the refname under which update was originally requested.
+ */
+const char *ref_update_original_update_refname(struct ref_update *update);
+
+/*
+ * Helper function to check if the new value is null, this
+ * takes into consideration that the update could be a regular
+ * ref or a symbolic ref.
+ */
+int ref_update_has_null_new_value(struct ref_update *update);
+
+/*
+ * Check whether the old_target values stored in update are consistent
+ * with the referent, which is the symbolic reference's current value.
+ * If everything is OK, return 0; otherwise, write an error message to
+ * err and return -1.
+ */
+int ref_update_check_old_target(const char *referent, struct ref_update *update,
+ struct strbuf *err);
+
+/*
+ * Check if the ref must exist, this means that the old_oid or
+ * old_target is non NULL.
+ */
+int ref_update_expects_existing_old_ref(struct ref_update *update);
+
#endif /* REFS_REFS_INTERNAL_H */
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
new file mode 100644
index 0000000000..647ef9b05b
--- /dev/null
+++ b/refs/reftable-backend.c
@@ -0,0 +1,2507 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "../git-compat-util.h"
+#include "../abspath.h"
+#include "../chdir-notify.h"
+#include "../config.h"
+#include "../dir.h"
+#include "../environment.h"
+#include "../gettext.h"
+#include "../hash.h"
+#include "../hex.h"
+#include "../iterator.h"
+#include "../ident.h"
+#include "../lockfile.h"
+#include "../object.h"
+#include "../path.h"
+#include "../refs.h"
+#include "../reftable/reftable-stack.h"
+#include "../reftable/reftable-record.h"
+#include "../reftable/reftable-error.h"
+#include "../reftable/reftable-iterator.h"
+#include "../repo-settings.h"
+#include "../setup.h"
+#include "../strmap.h"
+#include "../trace2.h"
+#include "parse.h"
+#include "refs-internal.h"
+
+/*
+ * Used as a flag in ref_update::flags when the ref_update was via an
+ * update to HEAD.
+ */
+#define REF_UPDATE_VIA_HEAD (1 << 8)
+
+struct reftable_ref_store {
+ struct ref_store base;
+
+ /*
+ * The main stack refers to the common dir and thus contains common
+ * refs as well as refs of the main repository.
+ */
+ struct reftable_stack *main_stack;
+ /*
+ * The worktree stack refers to the gitdir in case the refdb is opened
+ * via a worktree. It thus contains the per-worktree refs.
+ */
+ struct reftable_stack *worktree_stack;
+ /*
+ * Map of worktree stacks by their respective worktree names. The map
+ * is populated lazily when we try to resolve `worktrees/$worktree` refs.
+ */
+ struct strmap worktree_stacks;
+ struct reftable_write_options write_options;
+
+ unsigned int store_flags;
+ enum log_refs_config log_all_ref_updates;
+ int err;
+};
+
+/*
+ * Downcast ref_store to reftable_ref_store. Die if ref_store is not a
+ * reftable_ref_store. required_flags is compared with ref_store's store_flags
+ * to ensure the ref_store has all required capabilities. "caller" is used in
+ * any necessary error messages.
+ */
+static struct reftable_ref_store *reftable_be_downcast(struct ref_store *ref_store,
+ unsigned int required_flags,
+ const char *caller)
+{
+ struct reftable_ref_store *refs;
+
+ if (ref_store->be != &refs_be_reftable)
+ BUG("ref_store is type \"%s\" not \"reftables\" in %s",
+ ref_store->be->name, caller);
+
+ refs = (struct reftable_ref_store *)ref_store;
+
+ if ((refs->store_flags & required_flags) != required_flags)
+ BUG("operation %s requires abilities 0x%x, but only have 0x%x",
+ caller, required_flags, refs->store_flags);
+
+ return refs;
+}
+
+/*
+ * Some refs are global to the repository (refs/heads/{*}), while others are
+ * local to the worktree (eg. HEAD, refs/bisect/{*}). We solve this by having
+ * multiple separate databases (ie. multiple reftable/ directories), one for
+ * the shared refs, one for the current worktree refs, and one for each
+ * additional worktree. For reading, we merge the view of both the shared and
+ * the current worktree's refs, when necessary.
+ *
+ * This function also optionally assigns the rewritten reference name that is
+ * local to the stack. This translation is required when using worktree refs
+ * like `worktrees/$worktree/refs/heads/foo` as worktree stacks will store
+ * those references in their normalized form.
+ */
+static struct reftable_stack *stack_for(struct reftable_ref_store *store,
+ const char *refname,
+ const char **rewritten_ref)
+{
+ const char *wtname;
+ int wtname_len;
+
+ if (!refname)
+ return store->main_stack;
+
+ switch (parse_worktree_ref(refname, &wtname, &wtname_len, rewritten_ref)) {
+ case REF_WORKTREE_OTHER: {
+ static struct strbuf wtname_buf = STRBUF_INIT;
+ struct strbuf wt_dir = STRBUF_INIT;
+ struct reftable_stack *stack;
+
+ /*
+ * We're using a static buffer here so that we don't need to
+ * allocate the worktree name whenever we look up a reference.
+ * This could be avoided if the strmap interface knew how to
+ * handle keys with a length.
+ */
+ strbuf_reset(&wtname_buf);
+ strbuf_add(&wtname_buf, wtname, wtname_len);
+
+ /*
+ * There is an edge case here: when the worktree references the
+ * current worktree, then we set up the stack once via
+ * `worktree_stacks` and once via `worktree_stack`. This is
+ * wasteful, but in the reading case it shouldn't matter. And
+ * in the writing case we would notice that the stack is locked
+ * already and error out when trying to write a reference via
+ * both stacks.
+ */
+ stack = strmap_get(&store->worktree_stacks, wtname_buf.buf);
+ if (!stack) {
+ strbuf_addf(&wt_dir, "%s/worktrees/%s/reftable",
+ store->base.repo->commondir, wtname_buf.buf);
+
+ store->err = reftable_new_stack(&stack, wt_dir.buf,
+ &store->write_options);
+ assert(store->err != REFTABLE_API_ERROR);
+ strmap_put(&store->worktree_stacks, wtname_buf.buf, stack);
+ }
+
+ strbuf_release(&wt_dir);
+ return stack;
+ }
+ case REF_WORKTREE_CURRENT:
+ /*
+ * If there is no worktree stack then we're currently in the
+ * main worktree. We thus return the main stack in that case.
+ */
+ if (!store->worktree_stack)
+ return store->main_stack;
+ return store->worktree_stack;
+ case REF_WORKTREE_MAIN:
+ case REF_WORKTREE_SHARED:
+ return store->main_stack;
+ default:
+ BUG("unhandled worktree reference type");
+ }
+}
+
+static int should_write_log(struct reftable_ref_store *refs, const char *refname)
+{
+ enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
+ if (log_refs_cfg == LOG_REFS_UNSET)
+ log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+
+ switch (log_refs_cfg) {
+ case LOG_REFS_NONE:
+ return refs_reflog_exists(&refs->base, refname);
+ case LOG_REFS_ALWAYS:
+ return 1;
+ case LOG_REFS_NORMAL:
+ if (should_autocreate_reflog(log_refs_cfg, refname))
+ return 1;
+ return refs_reflog_exists(&refs->base, refname);
+ default:
+ BUG("unhandled core.logAllRefUpdates value %d", log_refs_cfg);
+ }
+}
+
+static void fill_reftable_log_record(struct reftable_log_record *log, const struct ident_split *split)
+{
+ const char *tz_begin;
+ int sign = 1;
+
+ reftable_log_record_release(log);
+ log->value_type = REFTABLE_LOG_UPDATE;
+ log->value.update.name =
+ xstrndup(split->name_begin, split->name_end - split->name_begin);
+ log->value.update.email =
+ xstrndup(split->mail_begin, split->mail_end - split->mail_begin);
+ log->value.update.time = atol(split->date_begin);
+
+ tz_begin = split->tz_begin;
+ if (*tz_begin == '-') {
+ sign = -1;
+ tz_begin++;
+ }
+ if (*tz_begin == '+') {
+ sign = 1;
+ tz_begin++;
+ }
+
+ log->value.update.tz_offset = sign * atoi(tz_begin);
+}
+
+static int read_ref_without_reload(struct reftable_ref_store *refs,
+ struct reftable_stack *stack,
+ const char *refname,
+ struct object_id *oid,
+ struct strbuf *referent,
+ unsigned int *type)
+{
+ struct reftable_ref_record ref = {0};
+ int ret;
+
+ ret = reftable_stack_read_ref(stack, refname, &ref);
+ if (ret)
+ goto done;
+
+ if (ref.value_type == REFTABLE_REF_SYMREF) {
+ strbuf_reset(referent);
+ strbuf_addstr(referent, ref.value.symref);
+ *type |= REF_ISSYMREF;
+ } else if (reftable_ref_record_val1(&ref)) {
+ oidread(oid, reftable_ref_record_val1(&ref),
+ refs->base.repo->hash_algo);
+ } else {
+ /* We got a tombstone, which should not happen. */
+ BUG("unhandled reference value type %d", ref.value_type);
+ }
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ reftable_ref_record_release(&ref);
+ return ret;
+}
+
+static int reftable_be_config(const char *var, const char *value,
+ const struct config_context *ctx,
+ void *_opts)
+{
+ struct reftable_write_options *opts = _opts;
+
+ if (!strcmp(var, "reftable.blocksize")) {
+ unsigned long block_size = git_config_ulong(var, value, ctx->kvi);
+ if (block_size > 16777215)
+ die("reftable block size cannot exceed 16MB");
+ opts->block_size = block_size;
+ } else if (!strcmp(var, "reftable.restartinterval")) {
+ unsigned long restart_interval = git_config_ulong(var, value, ctx->kvi);
+ if (restart_interval > UINT16_MAX)
+ die("reftable block size cannot exceed %u", (unsigned)UINT16_MAX);
+ opts->restart_interval = restart_interval;
+ } else if (!strcmp(var, "reftable.indexobjects")) {
+ opts->skip_index_objects = !git_config_bool(var, value);
+ } else if (!strcmp(var, "reftable.geometricfactor")) {
+ unsigned long factor = git_config_ulong(var, value, ctx->kvi);
+ if (factor > UINT8_MAX)
+ die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
+ opts->auto_compaction_factor = factor;
+ } else if (!strcmp(var, "reftable.locktimeout")) {
+ int64_t lock_timeout = git_config_int64(var, value, ctx->kvi);
+ if (lock_timeout > LONG_MAX)
+ die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX);
+ if (lock_timeout < 0 && lock_timeout != -1)
+ die("reftable lock timeout does not support negative values other than -1");
+ opts->lock_timeout_ms = lock_timeout;
+ }
+
+ return 0;
+}
+
+static struct ref_store *reftable_be_init(struct repository *repo,
+ const char *gitdir,
+ unsigned int store_flags)
+{
+ struct reftable_ref_store *refs = xcalloc(1, sizeof(*refs));
+ struct strbuf path = STRBUF_INIT;
+ int is_worktree;
+ mode_t mask;
+
+ mask = umask(0);
+ umask(mask);
+
+ base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
+ strmap_init(&refs->worktree_stacks);
+ refs->store_flags = store_flags;
+ refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
+
+ refs->write_options.hash_id = repo->hash_algo->format_id;
+ refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
+ refs->write_options.disable_auto_compact =
+ !git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
+ refs->write_options.lock_timeout_ms = 100;
+
+ git_config(reftable_be_config, &refs->write_options);
+
+ /*
+ * It is somewhat unfortunate that we have to mirror the default block
+ * size of the reftable library here. But given that the write options
+ * wouldn't be updated by the library here, and given that we require
+ * the proper block size to trim reflog message so that they fit, we
+ * must set up a proper value here.
+ */
+ if (!refs->write_options.block_size)
+ refs->write_options.block_size = 4096;
+
+ /*
+ * Set up the main reftable stack that is hosted in GIT_COMMON_DIR.
+ * This stack contains both the shared and the main worktree refs.
+ *
+ * Note that we don't try to resolve the path in case we have a
+ * worktree because `get_common_dir_noenv()` already does it for us.
+ */
+ is_worktree = get_common_dir_noenv(&path, gitdir);
+ if (!is_worktree) {
+ strbuf_reset(&path);
+ strbuf_realpath(&path, gitdir, 0);
+ }
+ strbuf_addstr(&path, "/reftable");
+ refs->err = reftable_new_stack(&refs->main_stack, path.buf,
+ &refs->write_options);
+ if (refs->err)
+ goto done;
+
+ /*
+ * If we're in a worktree we also need to set up the worktree reftable
+ * stack that is contained in the per-worktree GIT_DIR.
+ *
+ * Ideally, we would also add the stack to our worktree stack map. But
+ * we have no way to figure out the worktree name here and thus can't
+ * do it efficiently.
+ */
+ if (is_worktree) {
+ strbuf_reset(&path);
+ strbuf_addf(&path, "%s/reftable", gitdir);
+
+ refs->err = reftable_new_stack(&refs->worktree_stack, path.buf,
+ &refs->write_options);
+ if (refs->err)
+ goto done;
+ }
+
+ chdir_notify_reparent("reftables-backend $GIT_DIR", &refs->base.gitdir);
+
+done:
+ assert(refs->err != REFTABLE_API_ERROR);
+ strbuf_release(&path);
+ return &refs->base;
+}
+
+static void reftable_be_release(struct ref_store *ref_store)
+{
+ struct reftable_ref_store *refs = reftable_be_downcast(ref_store, 0, "release");
+ struct strmap_entry *entry;
+ struct hashmap_iter iter;
+
+ if (refs->main_stack) {
+ reftable_stack_destroy(refs->main_stack);
+ refs->main_stack = NULL;
+ }
+
+ if (refs->worktree_stack) {
+ reftable_stack_destroy(refs->worktree_stack);
+ refs->worktree_stack = NULL;
+ }
+
+ strmap_for_each_entry(&refs->worktree_stacks, &iter, entry)
+ reftable_stack_destroy(entry->value);
+ strmap_clear(&refs->worktree_stacks, 0);
+}
+
+static int reftable_be_create_on_disk(struct ref_store *ref_store,
+ int flags UNUSED,
+ struct strbuf *err UNUSED)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "create");
+ struct strbuf sb = STRBUF_INIT;
+
+ strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
+ safe_create_dir(sb.buf, 1);
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
+ write_file(sb.buf, "ref: refs/heads/.invalid");
+ adjust_shared_perm(sb.buf);
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ safe_create_dir(sb.buf, 1);
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
+ write_file(sb.buf, "this repository uses the reftable format");
+ adjust_shared_perm(sb.buf);
+
+ strbuf_release(&sb);
+ return 0;
+}
+
+static int reftable_be_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "remove");
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ /*
+ * Release the ref store such that all stacks are closed. This is
+ * required so that the "tables.list" file is not open anymore, which
+ * would otherwise make it impossible to remove the file on Windows.
+ */
+ reftable_be_release(ref_store);
+
+ strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete reftables: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
+ if (unlink(sb.buf) < 0) {
+ strbuf_addf(err, "could not delete stub HEAD: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
+ if (unlink(sb.buf) < 0) {
+ strbuf_addf(err, "could not delete stub heads: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ if (rmdir(sb.buf) < 0) {
+ strbuf_addf(err, "could not delete refs directory: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+struct reftable_ref_iterator {
+ struct ref_iterator base;
+ struct reftable_ref_store *refs;
+ struct reftable_iterator iter;
+ struct reftable_ref_record ref;
+ struct object_id oid;
+
+ const char *prefix;
+ size_t prefix_len;
+ char **exclude_patterns;
+ size_t exclude_patterns_index;
+ size_t exclude_patterns_strlen;
+ unsigned int flags;
+ int err;
+};
+
+/*
+ * Handle exclude patterns. Returns either `1`, which tells the caller that the
+ * current reference shall not be shown. Or `0`, which indicates that it should
+ * be shown.
+ */
+static int should_exclude_current_ref(struct reftable_ref_iterator *iter)
+{
+ while (iter->exclude_patterns[iter->exclude_patterns_index]) {
+ const char *pattern = iter->exclude_patterns[iter->exclude_patterns_index];
+ char *ref_after_pattern;
+ int cmp;
+
+ /*
+ * Lazily cache the pattern length so that we don't have to
+ * recompute it every time this function is called.
+ */
+ if (!iter->exclude_patterns_strlen)
+ iter->exclude_patterns_strlen = strlen(pattern);
+
+ /*
+ * When the reference name is lexicographically bigger than the
+ * current exclude pattern we know that it won't ever match any
+ * of the following references, either. We thus advance to the
+ * next pattern and re-check whether it matches.
+ *
+ * Otherwise, if it's smaller, then we do not have a match and
+ * thus want to show the current reference.
+ */
+ cmp = strncmp(iter->ref.refname, pattern,
+ iter->exclude_patterns_strlen);
+ if (cmp > 0) {
+ iter->exclude_patterns_index++;
+ iter->exclude_patterns_strlen = 0;
+ continue;
+ }
+ if (cmp < 0)
+ return 0;
+
+ /*
+ * The reference shares a prefix with the exclude pattern and
+ * shall thus be omitted. We skip all references that match the
+ * pattern by seeking to the first reference after the block of
+ * matches.
+ *
+ * This is done by appending the highest possible character to
+ * the pattern. Consequently, all references that have the
+ * pattern as prefix and whose suffix starts with anything in
+ * the range [0x00, 0xfe] are skipped. And given that 0xff is a
+ * non-printable character that shouldn't ever be in a ref name,
+ * we'd not yield any such record, either.
+ *
+ * Note that the seeked-to reference may also be excluded. This
+ * is not handled here though, but the caller is expected to
+ * loop and re-verify the next reference for us.
+ */
+ ref_after_pattern = xstrfmt("%s%c", pattern, 0xff);
+ iter->err = reftable_iterator_seek_ref(&iter->iter, ref_after_pattern);
+ iter->exclude_patterns_index++;
+ iter->exclude_patterns_strlen = 0;
+ trace2_counter_add(TRACE2_COUNTER_ID_REFTABLE_RESEEKS, 1);
+
+ free(ref_after_pattern);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
+{
+ struct reftable_ref_iterator *iter =
+ (struct reftable_ref_iterator *)ref_iterator;
+ struct reftable_ref_store *refs = iter->refs;
+ const char *referent = NULL;
+
+ while (!iter->err) {
+ int flags = 0;
+
+ iter->err = reftable_iterator_next_ref(&iter->iter, &iter->ref);
+ if (iter->err)
+ break;
+
+ /*
+ * The files backend only lists references contained in "refs/" unless
+ * the root refs are to be included. We emulate the same behaviour here.
+ */
+ if (!starts_with(iter->ref.refname, "refs/") &&
+ !(iter->flags & DO_FOR_EACH_INCLUDE_ROOT_REFS &&
+ is_root_ref(iter->ref.refname))) {
+ continue;
+ }
+
+ if (iter->prefix_len &&
+ strncmp(iter->prefix, iter->ref.refname, iter->prefix_len)) {
+ iter->err = 1;
+ break;
+ }
+
+ if (iter->exclude_patterns && should_exclude_current_ref(iter))
+ continue;
+
+ if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
+ parse_worktree_ref(iter->ref.refname, NULL, NULL, NULL) !=
+ REF_WORKTREE_CURRENT)
+ continue;
+
+ switch (iter->ref.value_type) {
+ case REFTABLE_REF_VAL1:
+ oidread(&iter->oid, iter->ref.value.val1,
+ refs->base.repo->hash_algo);
+ break;
+ case REFTABLE_REF_VAL2:
+ oidread(&iter->oid, iter->ref.value.val2.value,
+ refs->base.repo->hash_algo);
+ break;
+ case REFTABLE_REF_SYMREF:
+ referent = refs_resolve_ref_unsafe(&iter->refs->base,
+ iter->ref.refname,
+ RESOLVE_REF_READING,
+ &iter->oid, &flags);
+ if (!referent)
+ oidclr(&iter->oid, refs->base.repo->hash_algo);
+ break;
+ default:
+ BUG("unhandled reference value type %d", iter->ref.value_type);
+ }
+
+ if (is_null_oid(&iter->oid))
+ flags |= REF_ISBROKEN;
+
+ if (check_refname_format(iter->ref.refname, REFNAME_ALLOW_ONELEVEL)) {
+ if (!refname_is_safe(iter->ref.refname))
+ die(_("refname is dangerous: %s"), iter->ref.refname);
+ oidclr(&iter->oid, refs->base.repo->hash_algo);
+ flags |= REF_BAD_NAME | REF_ISBROKEN;
+ }
+
+ if (iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS &&
+ flags & REF_ISSYMREF &&
+ flags & REF_ISBROKEN)
+ continue;
+
+ if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
+ !ref_resolves_to_object(iter->ref.refname, refs->base.repo,
+ &iter->oid, flags))
+ continue;
+
+ iter->base.refname = iter->ref.refname;
+ iter->base.referent = referent;
+ iter->base.oid = &iter->oid;
+ iter->base.flags = flags;
+
+ break;
+ }
+
+ if (iter->err > 0) {
+ if (ref_iterator_abort(ref_iterator) != ITER_DONE)
+ return ITER_ERROR;
+ return ITER_DONE;
+ }
+
+ if (iter->err < 0) {
+ ref_iterator_abort(ref_iterator);
+ return ITER_ERROR;
+ }
+
+ return ITER_OK;
+}
+
+static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
+ struct object_id *peeled)
+{
+ struct reftable_ref_iterator *iter =
+ (struct reftable_ref_iterator *)ref_iterator;
+
+ if (iter->ref.value_type == REFTABLE_REF_VAL2) {
+ oidread(peeled, iter->ref.value.val2.target_value,
+ iter->refs->base.repo->hash_algo);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
+{
+ struct reftable_ref_iterator *iter =
+ (struct reftable_ref_iterator *)ref_iterator;
+ reftable_ref_record_release(&iter->ref);
+ reftable_iterator_destroy(&iter->iter);
+ if (iter->exclude_patterns) {
+ for (size_t i = 0; iter->exclude_patterns[i]; i++)
+ free(iter->exclude_patterns[i]);
+ free(iter->exclude_patterns);
+ }
+ free(iter);
+ return ITER_DONE;
+}
+
+static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
+ .advance = reftable_ref_iterator_advance,
+ .peel = reftable_ref_iterator_peel,
+ .abort = reftable_ref_iterator_abort
+};
+
+static int qsort_strcmp(const void *va, const void *vb)
+{
+ const char *a = *(const char **)va;
+ const char *b = *(const char **)vb;
+ return strcmp(a, b);
+}
+
+static char **filter_exclude_patterns(const char **exclude_patterns)
+{
+ size_t filtered_size = 0, filtered_alloc = 0;
+ char **filtered = NULL;
+
+ if (!exclude_patterns)
+ return NULL;
+
+ for (size_t i = 0; ; i++) {
+ const char *exclude_pattern = exclude_patterns[i];
+ int has_glob = 0;
+
+ if (!exclude_pattern)
+ break;
+
+ for (const char *p = exclude_pattern; *p; p++) {
+ has_glob = is_glob_special(*p);
+ if (has_glob)
+ break;
+ }
+ if (has_glob)
+ continue;
+
+ ALLOC_GROW(filtered, filtered_size + 1, filtered_alloc);
+ filtered[filtered_size++] = xstrdup(exclude_pattern);
+ }
+
+ if (filtered_size) {
+ QSORT(filtered, filtered_size, qsort_strcmp);
+ ALLOC_GROW(filtered, filtered_size + 1, filtered_alloc);
+ filtered[filtered_size++] = NULL;
+ }
+
+ return filtered;
+}
+
+static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_store *refs,
+ struct reftable_stack *stack,
+ const char *prefix,
+ const char **exclude_patterns,
+ int flags)
+{
+ struct reftable_ref_iterator *iter;
+ int ret;
+
+ iter = xcalloc(1, sizeof(*iter));
+ base_ref_iterator_init(&iter->base, &reftable_ref_iterator_vtable);
+ iter->prefix = prefix;
+ iter->prefix_len = prefix ? strlen(prefix) : 0;
+ iter->base.oid = &iter->oid;
+ iter->flags = flags;
+ iter->refs = refs;
+ iter->exclude_patterns = filter_exclude_patterns(exclude_patterns);
+
+ ret = refs->err;
+ if (ret)
+ goto done;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ goto done;
+
+ reftable_stack_init_ref_iterator(stack, &iter->iter);
+ ret = reftable_iterator_seek_ref(&iter->iter, prefix);
+ if (ret)
+ goto done;
+
+done:
+ iter->err = ret;
+ return iter;
+}
+
+static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_store,
+ const char *prefix,
+ const char **exclude_patterns,
+ unsigned int flags)
+{
+ struct reftable_ref_iterator *main_iter, *worktree_iter;
+ struct reftable_ref_store *refs;
+ unsigned int required_flags = REF_STORE_READ;
+
+ if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
+ required_flags |= REF_STORE_ODB;
+ refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin");
+
+ main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix,
+ exclude_patterns, flags);
+
+ /*
+ * The worktree stack is only set when we're in an actual worktree
+ * right now. If we aren't, then we return the common reftable
+ * iterator, only.
+ */
+ if (!refs->worktree_stack)
+ return &main_iter->base;
+
+ /*
+ * Otherwise we merge both the common and the per-worktree refs into a
+ * single iterator.
+ */
+ worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix,
+ exclude_patterns, flags);
+ return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
+ ref_iterator_select, NULL);
+}
+
+static int reftable_be_read_raw_ref(struct ref_store *ref_store,
+ const char *refname,
+ struct object_id *oid,
+ struct strbuf *referent,
+ unsigned int *type,
+ int *failure_errno)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ int ret;
+
+ if (refs->err < 0)
+ return refs->err;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ return ret;
+
+ ret = read_ref_without_reload(refs, stack, refname, oid, referent, type);
+ if (ret < 0)
+ return ret;
+ if (ret > 0) {
+ *failure_errno = ENOENT;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int reftable_be_read_symbolic_ref(struct ref_store *ref_store,
+ const char *refname,
+ struct strbuf *referent)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "read_symbolic_ref");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_ref_record ref = {0};
+ int ret;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ return ret;
+
+ ret = reftable_stack_read_ref(stack, refname, &ref);
+ if (ret == 0 && ref.value_type == REFTABLE_REF_SYMREF)
+ strbuf_addstr(referent, ref.value.symref);
+ else
+ ret = -1;
+
+ reftable_ref_record_release(&ref);
+ return ret;
+}
+
+struct reftable_transaction_update {
+ struct ref_update *update;
+ struct object_id current_oid;
+};
+
+struct write_transaction_table_arg {
+ struct reftable_ref_store *refs;
+ struct reftable_stack *stack;
+ struct reftable_addition *addition;
+ struct reftable_transaction_update *updates;
+ size_t updates_nr;
+ size_t updates_alloc;
+ size_t updates_expected;
+};
+
+struct reftable_transaction_data {
+ struct write_transaction_table_arg *args;
+ size_t args_nr, args_alloc;
+};
+
+static void free_transaction_data(struct reftable_transaction_data *tx_data)
+{
+ if (!tx_data)
+ return;
+ for (size_t i = 0; i < tx_data->args_nr; i++) {
+ reftable_addition_destroy(tx_data->args[i].addition);
+ free(tx_data->args[i].updates);
+ }
+ free(tx_data->args);
+ free(tx_data);
+}
+
+/*
+ * Prepare transaction update for the given reference update. This will cause
+ * us to lock the corresponding reftable stack for concurrent modification.
+ */
+static int prepare_transaction_update(struct write_transaction_table_arg **out,
+ struct reftable_ref_store *refs,
+ struct reftable_transaction_data *tx_data,
+ struct ref_update *update,
+ struct strbuf *err)
+{
+ struct reftable_stack *stack = stack_for(refs, update->refname, NULL);
+ struct write_transaction_table_arg *arg = NULL;
+ size_t i;
+ int ret;
+
+ /*
+ * Search for a preexisting stack update. If there is one then we add
+ * the update to it, otherwise we set up a new stack update.
+ */
+ for (i = 0; !arg && i < tx_data->args_nr; i++)
+ if (tx_data->args[i].stack == stack)
+ arg = &tx_data->args[i];
+
+ if (!arg) {
+ struct reftable_addition *addition;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ return ret;
+
+ ret = reftable_stack_new_addition(&addition, stack,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
+ if (ret) {
+ if (ret == REFTABLE_LOCK_ERROR)
+ strbuf_addstr(err, "cannot lock references");
+ return ret;
+ }
+
+ ALLOC_GROW(tx_data->args, tx_data->args_nr + 1,
+ tx_data->args_alloc);
+ arg = &tx_data->args[tx_data->args_nr++];
+ arg->refs = refs;
+ arg->stack = stack;
+ arg->addition = addition;
+ arg->updates = NULL;
+ arg->updates_nr = 0;
+ arg->updates_alloc = 0;
+ arg->updates_expected = 0;
+ }
+
+ arg->updates_expected++;
+
+ if (out)
+ *out = arg;
+
+ return 0;
+}
+
+/*
+ * Queue a reference update for the correct stack. We potentially need to
+ * handle multiple stack updates in a single transaction when it spans across
+ * multiple worktrees.
+ */
+static int queue_transaction_update(struct reftable_ref_store *refs,
+ struct reftable_transaction_data *tx_data,
+ struct ref_update *update,
+ struct object_id *current_oid,
+ struct strbuf *err)
+{
+ struct write_transaction_table_arg *arg = NULL;
+ int ret;
+
+ if (update->backend_data)
+ BUG("reference update queued more than once");
+
+ ret = prepare_transaction_update(&arg, refs, tx_data, update, err);
+ if (ret < 0)
+ return ret;
+
+ ALLOC_GROW(arg->updates, arg->updates_nr + 1,
+ arg->updates_alloc);
+ arg->updates[arg->updates_nr].update = update;
+ oidcpy(&arg->updates[arg->updates_nr].current_oid, current_oid);
+ update->backend_data = &arg->updates[arg->updates_nr++];
+
+ return 0;
+}
+
+static int reftable_be_transaction_prepare(struct ref_store *ref_store,
+ struct ref_transaction *transaction,
+ struct strbuf *err)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE|REF_STORE_MAIN, "ref_transaction_prepare");
+ struct strbuf referent = STRBUF_INIT, head_referent = STRBUF_INIT;
+ struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
+ struct reftable_transaction_data *tx_data = NULL;
+ struct object_id head_oid;
+ unsigned int head_type = 0;
+ size_t i;
+ int ret;
+
+ ret = refs->err;
+ if (ret < 0)
+ goto done;
+
+ tx_data = xcalloc(1, sizeof(*tx_data));
+
+ /*
+ * Preprocess all updates. For one we check that there are no duplicate
+ * reference updates in this transaction. Second, we lock all stacks
+ * that will be modified during the transaction.
+ */
+ for (i = 0; i < transaction->nr; i++) {
+ ret = prepare_transaction_update(NULL, refs, tx_data,
+ transaction->updates[i], err);
+ if (ret)
+ goto done;
+
+ string_list_append(&affected_refnames,
+ transaction->updates[i]->refname);
+ }
+
+ /*
+ * Now that we have counted updates per stack we can preallocate their
+ * arrays. This avoids having to reallocate many times.
+ */
+ for (i = 0; i < tx_data->args_nr; i++) {
+ CALLOC_ARRAY(tx_data->args[i].updates, tx_data->args[i].updates_expected);
+ tx_data->args[i].updates_alloc = tx_data->args[i].updates_expected;
+ }
+
+ /*
+ * Fail if a refname appears more than once in the transaction.
+ * This code is taken from the files backend and is a good candidate to
+ * be moved into the generic layer.
+ */
+ string_list_sort(&affected_refnames);
+ if (ref_update_reject_duplicates(&affected_refnames, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto done;
+ }
+
+ ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD",
+ &head_oid, &head_referent, &head_type);
+ if (ret < 0)
+ goto done;
+ ret = 0;
+
+ for (i = 0; i < transaction->nr; i++) {
+ struct ref_update *u = transaction->updates[i];
+ struct object_id current_oid = {0};
+ struct reftable_stack *stack;
+ const char *rewritten_ref;
+
+ stack = stack_for(refs, u->refname, &rewritten_ref);
+
+ /* Verify that the new object ID is valid. */
+ if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
+ !(u->flags & REF_SKIP_OID_VERIFICATION) &&
+ !(u->flags & REF_LOG_ONLY)) {
+ struct object *o = parse_object(refs->base.repo, &u->new_oid);
+ if (!o) {
+ strbuf_addf(err,
+ _("trying to write ref '%s' with nonexistent object %s"),
+ u->refname, oid_to_hex(&u->new_oid));
+ ret = -1;
+ goto done;
+ }
+
+ if (o->type != OBJ_COMMIT && is_branch(u->refname)) {
+ strbuf_addf(err, _("trying to write non-commit object %s to branch '%s'"),
+ oid_to_hex(&u->new_oid), u->refname);
+ ret = -1;
+ goto done;
+ }
+ }
+
+ /*
+ * When we update the reference that HEAD points to we enqueue
+ * a second log-only update for HEAD so that its reflog is
+ * updated accordingly.
+ */
+ if (head_type == REF_ISSYMREF &&
+ !(u->flags & REF_LOG_ONLY) &&
+ !(u->flags & REF_UPDATE_VIA_HEAD) &&
+ !strcmp(rewritten_ref, head_referent.buf)) {
+ struct ref_update *new_update;
+
+ /*
+ * First make sure that HEAD is not already in the
+ * transaction. This check is O(lg N) in the transaction
+ * size, but it happens at most once per transaction.
+ */
+ if (string_list_has_string(&affected_refnames, "HEAD")) {
+ /* An entry already existed */
+ strbuf_addf(err,
+ _("multiple updates for 'HEAD' (including one "
+ "via its referent '%s') are not allowed"),
+ u->refname);
+ ret = TRANSACTION_NAME_CONFLICT;
+ goto done;
+ }
+
+ new_update = ref_transaction_add_update(
+ transaction, "HEAD",
+ u->flags | REF_LOG_ONLY | REF_NO_DEREF,
+ &u->new_oid, &u->old_oid, NULL, NULL, u->msg);
+ string_list_insert(&affected_refnames, new_update->refname);
+ }
+
+ ret = read_ref_without_reload(refs, stack, rewritten_ref,
+ &current_oid, &referent, &u->type);
+ if (ret < 0)
+ goto done;
+ if (ret > 0 && !ref_update_expects_existing_old_ref(u)) {
+ /*
+ * The reference does not exist, and we either have no
+ * old object ID or expect the reference to not exist.
+ * We can thus skip below safety checks as well as the
+ * symref splitting. But we do want to verify that
+ * there is no conflicting reference here so that we
+ * can output a proper error message instead of failing
+ * at a later point.
+ */
+ ret = refs_verify_refname_available(ref_store, u->refname,
+ &affected_refnames, NULL,
+ transaction->flags & REF_TRANSACTION_FLAG_INITIAL,
+ err);
+ if (ret < 0)
+ goto done;
+
+ /*
+ * There is no need to write the reference deletion
+ * when the reference in question doesn't exist.
+ */
+ if ((u->flags & REF_HAVE_NEW) && !ref_update_has_null_new_value(u)) {
+ ret = queue_transaction_update(refs, tx_data, u,
+ &current_oid, err);
+ if (ret)
+ goto done;
+ }
+
+ continue;
+ }
+ if (ret > 0) {
+ /* The reference does not exist, but we expected it to. */
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "unable to resolve reference '%s'"),
+ ref_update_original_update_refname(u), u->refname);
+ ret = -1;
+ goto done;
+ }
+
+ if (u->type & REF_ISSYMREF) {
+ /*
+ * The reftable stack is locked at this point already,
+ * so it is safe to call `refs_resolve_ref_unsafe()`
+ * here without causing races.
+ */
+ const char *resolved = refs_resolve_ref_unsafe(&refs->base, u->refname, 0,
+ &current_oid, NULL);
+
+ if (u->flags & REF_NO_DEREF) {
+ if (u->flags & REF_HAVE_OLD && !resolved) {
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "error reading reference"), u->refname);
+ ret = -1;
+ goto done;
+ }
+ } else {
+ struct ref_update *new_update;
+ int new_flags;
+
+ new_flags = u->flags;
+ if (!strcmp(rewritten_ref, "HEAD"))
+ new_flags |= REF_UPDATE_VIA_HEAD;
+
+ /*
+ * If we are updating a symref (eg. HEAD), we should also
+ * update the branch that the symref points to.
+ *
+ * This is generic functionality, and would be better
+ * done in refs.c, but the current implementation is
+ * intertwined with the locking in files-backend.c.
+ */
+ new_update = ref_transaction_add_update(
+ transaction, referent.buf, new_flags,
+ u->new_target ? NULL : &u->new_oid,
+ u->old_target ? NULL : &u->old_oid,
+ u->new_target, u->old_target, u->msg);
+
+ new_update->parent_update = u;
+
+ /*
+ * Change the symbolic ref update to log only. Also, it
+ * doesn't need to check its old OID value, as that will be
+ * done when new_update is processed.
+ */
+ u->flags |= REF_LOG_ONLY | REF_NO_DEREF;
+ u->flags &= ~REF_HAVE_OLD;
+
+ if (string_list_has_string(&affected_refnames, new_update->refname)) {
+ strbuf_addf(err,
+ _("multiple updates for '%s' (including one "
+ "via symref '%s') are not allowed"),
+ referent.buf, u->refname);
+ ret = TRANSACTION_NAME_CONFLICT;
+ goto done;
+ }
+ string_list_insert(&affected_refnames, new_update->refname);
+ }
+ }
+
+ /*
+ * Verify that the old object matches our expectations. Note
+ * that the error messages here do not make a lot of sense in
+ * the context of the reftable backend as we never lock
+ * individual refs. But the error messages match what the files
+ * backend returns, which keeps our tests happy.
+ */
+ if (u->old_target) {
+ if (!(u->type & REF_ISSYMREF)) {
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "expected symref with target '%s': "
+ "but is a regular ref"),
+ ref_update_original_update_refname(u),
+ u->old_target);
+ ret = -1;
+ goto done;
+ }
+
+ if (ref_update_check_old_target(referent.buf, u, err)) {
+ ret = -1;
+ goto done;
+ }
+ } else if ((u->flags & REF_HAVE_OLD) && !oideq(&current_oid, &u->old_oid)) {
+ if (is_null_oid(&u->old_oid))
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "reference already exists"),
+ ref_update_original_update_refname(u));
+ else if (is_null_oid(&current_oid))
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "reference is missing but expected %s"),
+ ref_update_original_update_refname(u),
+ oid_to_hex(&u->old_oid));
+ else
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "is at %s but expected %s"),
+ ref_update_original_update_refname(u),
+ oid_to_hex(&current_oid),
+ oid_to_hex(&u->old_oid));
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * If all of the following conditions are true:
+ *
+ * - We're not about to write a symref.
+ * - We're not about to write a log-only entry.
+ * - Old and new object ID are different.
+ *
+ * Then we're essentially doing a no-op update that can be
+ * skipped. This is not only for the sake of efficiency, but
+ * also skips writing unneeded reflog entries.
+ */
+ if ((u->type & REF_ISSYMREF) ||
+ (u->flags & REF_LOG_ONLY) ||
+ (u->flags & REF_HAVE_NEW && !oideq(&current_oid, &u->new_oid))) {
+ ret = queue_transaction_update(refs, tx_data, u,
+ &current_oid, err);
+ if (ret)
+ goto done;
+ }
+ }
+
+ transaction->backend_data = tx_data;
+ transaction->state = REF_TRANSACTION_PREPARED;
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ if (ret < 0) {
+ free_transaction_data(tx_data);
+ transaction->state = REF_TRANSACTION_CLOSED;
+ if (!err->len)
+ strbuf_addf(err, _("reftable: transaction prepare: %s"),
+ reftable_error_str(ret));
+ }
+ string_list_clear(&affected_refnames, 0);
+ strbuf_release(&referent);
+ strbuf_release(&head_referent);
+
+ return ret;
+}
+
+static int reftable_be_transaction_abort(struct ref_store *ref_store UNUSED,
+ struct ref_transaction *transaction,
+ struct strbuf *err UNUSED)
+{
+ struct reftable_transaction_data *tx_data = transaction->backend_data;
+ free_transaction_data(tx_data);
+ transaction->state = REF_TRANSACTION_CLOSED;
+ return 0;
+}
+
+static int transaction_update_cmp(const void *a, const void *b)
+{
+ return strcmp(((struct reftable_transaction_update *)a)->update->refname,
+ ((struct reftable_transaction_update *)b)->update->refname);
+}
+
+static int write_transaction_table(struct reftable_writer *writer, void *cb_data)
+{
+ struct write_transaction_table_arg *arg = cb_data;
+ uint64_t ts = reftable_stack_next_update_index(arg->stack);
+ struct reftable_log_record *logs = NULL;
+ struct ident_split committer_ident = {0};
+ size_t logs_nr = 0, logs_alloc = 0, i;
+ const char *committer_info;
+ int ret = 0;
+
+ committer_info = git_committer_info(0);
+ if (split_ident_line(&committer_ident, committer_info, strlen(committer_info)))
+ BUG("failed splitting committer info");
+
+ QSORT(arg->updates, arg->updates_nr, transaction_update_cmp);
+
+ reftable_writer_set_limits(writer, ts, ts);
+
+ for (i = 0; i < arg->updates_nr; i++) {
+ struct reftable_transaction_update *tx_update = &arg->updates[i];
+ struct ref_update *u = tx_update->update;
+
+ /*
+ * Write a reflog entry when updating a ref to point to
+ * something new in either of the following cases:
+ *
+ * - The reference is about to be deleted. We always want to
+ * delete the reflog in that case.
+ * - REF_FORCE_CREATE_REFLOG is set, asking us to always create
+ * the reflog entry.
+ * - `core.logAllRefUpdates` tells us to create the reflog for
+ * the given ref.
+ */
+ if ((u->flags & REF_HAVE_NEW) &&
+ !(u->type & REF_ISSYMREF) &&
+ ref_update_has_null_new_value(u)) {
+ struct reftable_log_record log = {0};
+ struct reftable_iterator it = {0};
+
+ ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ if (ret < 0)
+ goto done;
+
+ /*
+ * When deleting refs we also delete all reflog entries
+ * with them. While it is not strictly required to
+ * delete reflogs together with their refs, this
+ * matches the behaviour of the files backend.
+ *
+ * Unfortunately, we have no better way than to delete
+ * all reflog entries one by one.
+ */
+ ret = reftable_iterator_seek_log(&it, u->refname);
+ while (ret == 0) {
+ struct reftable_log_record *tombstone;
+
+ ret = reftable_iterator_next_log(&it, &log);
+ if (ret < 0)
+ break;
+ if (ret > 0 || strcmp(log.refname, u->refname)) {
+ ret = 0;
+ break;
+ }
+
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ tombstone = &logs[logs_nr++];
+ tombstone->refname = xstrdup(u->refname);
+ tombstone->value_type = REFTABLE_LOG_DELETION;
+ tombstone->update_index = log.update_index;
+ }
+
+ reftable_log_record_release(&log);
+ reftable_iterator_destroy(&it);
+
+ if (ret)
+ goto done;
+ } else if (!(u->flags & REF_SKIP_CREATE_REFLOG) &&
+ (u->flags & REF_HAVE_NEW) &&
+ (u->flags & REF_FORCE_CREATE_REFLOG ||
+ should_write_log(arg->refs, u->refname))) {
+ struct reftable_log_record *log;
+ int create_reflog = 1;
+
+ if (u->new_target) {
+ if (!refs_resolve_ref_unsafe(&arg->refs->base, u->new_target,
+ RESOLVE_REF_READING, &u->new_oid, NULL)) {
+ /*
+ * TODO: currently we skip creating reflogs for dangling
+ * symref updates. It would be nice to capture this as
+ * zero oid updates however.
+ */
+ create_reflog = 0;
+ }
+ }
+
+ if (create_reflog) {
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ log = &logs[logs_nr++];
+ memset(log, 0, sizeof(*log));
+
+ fill_reftable_log_record(log, &committer_ident);
+ log->update_index = ts;
+ log->refname = xstrdup(u->refname);
+ memcpy(log->value.update.new_hash,
+ u->new_oid.hash, GIT_MAX_RAWSZ);
+ memcpy(log->value.update.old_hash,
+ tx_update->current_oid.hash, GIT_MAX_RAWSZ);
+ log->value.update.message =
+ xstrndup(u->msg, arg->refs->write_options.block_size / 2);
+ }
+ }
+
+ if (u->flags & REF_LOG_ONLY)
+ continue;
+
+ if (u->new_target) {
+ struct reftable_ref_record ref = {
+ .refname = (char *)u->refname,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *)u->new_target,
+ .update_index = ts,
+ };
+
+ ret = reftable_writer_add_ref(writer, &ref);
+ if (ret < 0)
+ goto done;
+ } else if ((u->flags & REF_HAVE_NEW) && ref_update_has_null_new_value(u)) {
+ struct reftable_ref_record ref = {
+ .refname = (char *)u->refname,
+ .update_index = ts,
+ .value_type = REFTABLE_REF_DELETION,
+ };
+
+ ret = reftable_writer_add_ref(writer, &ref);
+ if (ret < 0)
+ goto done;
+ } else if (u->flags & REF_HAVE_NEW) {
+ struct reftable_ref_record ref = {0};
+ struct object_id peeled;
+ int peel_error;
+
+ ref.refname = (char *)u->refname;
+ ref.update_index = ts;
+
+ peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled);
+ if (!peel_error) {
+ ref.value_type = REFTABLE_REF_VAL2;
+ memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
+ memcpy(ref.value.val2.value, u->new_oid.hash, GIT_MAX_RAWSZ);
+ } else if (!is_null_oid(&u->new_oid)) {
+ ref.value_type = REFTABLE_REF_VAL1;
+ memcpy(ref.value.val1, u->new_oid.hash, GIT_MAX_RAWSZ);
+ }
+
+ ret = reftable_writer_add_ref(writer, &ref);
+ if (ret < 0)
+ goto done;
+ }
+ }
+
+ /*
+ * Logs are written at the end so that we do not have intermixed ref
+ * and log blocks.
+ */
+ if (logs) {
+ ret = reftable_writer_add_logs(writer, logs, logs_nr);
+ if (ret < 0)
+ goto done;
+ }
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ for (i = 0; i < logs_nr; i++)
+ reftable_log_record_release(&logs[i]);
+ free(logs);
+ return ret;
+}
+
+static int reftable_be_transaction_finish(struct ref_store *ref_store UNUSED,
+ struct ref_transaction *transaction,
+ struct strbuf *err)
+{
+ struct reftable_transaction_data *tx_data = transaction->backend_data;
+ int ret = 0;
+
+ for (size_t i = 0; i < tx_data->args_nr; i++) {
+ ret = reftable_addition_add(tx_data->args[i].addition,
+ write_transaction_table, &tx_data->args[i]);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_addition_commit(tx_data->args[i].addition);
+ if (ret < 0)
+ goto done;
+ }
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ free_transaction_data(tx_data);
+ transaction->state = REF_TRANSACTION_CLOSED;
+
+ if (ret) {
+ strbuf_addf(err, _("reftable: transaction failure: %s"),
+ reftable_error_str(ret));
+ return -1;
+ }
+ return ret;
+}
+
+static int reftable_be_pack_refs(struct ref_store *ref_store,
+ struct pack_refs_opts *opts)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB, "pack_refs");
+ struct reftable_stack *stack;
+ int ret;
+
+ if (refs->err)
+ return refs->err;
+
+ stack = refs->worktree_stack;
+ if (!stack)
+ stack = refs->main_stack;
+
+ if (opts->flags & PACK_REFS_AUTO)
+ ret = reftable_stack_auto_compact(stack);
+ else
+ ret = reftable_stack_compact_all(stack, NULL);
+ if (ret < 0) {
+ ret = error(_("unable to compact stack: %s"),
+ reftable_error_str(ret));
+ goto out;
+ }
+
+ ret = reftable_stack_clean(stack);
+ if (ret)
+ goto out;
+
+out:
+ return ret;
+}
+
+struct write_create_symref_arg {
+ struct reftable_ref_store *refs;
+ struct reftable_stack *stack;
+ struct strbuf *err;
+ const char *refname;
+ const char *target;
+ const char *logmsg;
+};
+
+struct write_copy_arg {
+ struct reftable_ref_store *refs;
+ struct reftable_stack *stack;
+ const char *oldname;
+ const char *newname;
+ const char *logmsg;
+ int delete_old;
+};
+
+static int write_copy_table(struct reftable_writer *writer, void *cb_data)
+{
+ struct write_copy_arg *arg = cb_data;
+ uint64_t deletion_ts, creation_ts;
+ struct reftable_ref_record old_ref = {0}, refs[2] = {0};
+ struct reftable_log_record old_log = {0}, *logs = NULL;
+ struct reftable_iterator it = {0};
+ struct string_list skip = STRING_LIST_INIT_NODUP;
+ struct ident_split committer_ident = {0};
+ struct strbuf errbuf = STRBUF_INIT;
+ size_t logs_nr = 0, logs_alloc = 0, i;
+ const char *committer_info;
+ int ret;
+
+ committer_info = git_committer_info(0);
+ if (split_ident_line(&committer_ident, committer_info, strlen(committer_info)))
+ BUG("failed splitting committer info");
+
+ if (reftable_stack_read_ref(arg->stack, arg->oldname, &old_ref)) {
+ ret = error(_("refname %s not found"), arg->oldname);
+ goto done;
+ }
+ if (old_ref.value_type == REFTABLE_REF_SYMREF) {
+ ret = error(_("refname %s is a symbolic ref, copying it is not supported"),
+ arg->oldname);
+ goto done;
+ }
+
+ /*
+ * There's nothing to do in case the old and new name are the same, so
+ * we exit early in that case.
+ */
+ if (!strcmp(arg->oldname, arg->newname)) {
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Verify that the new refname is available.
+ */
+ if (arg->delete_old)
+ string_list_insert(&skip, arg->oldname);
+ ret = refs_verify_refname_available(&arg->refs->base, arg->newname,
+ NULL, &skip, 0, &errbuf);
+ if (ret < 0) {
+ error("%s", errbuf.buf);
+ goto done;
+ }
+
+ /*
+ * When deleting the old reference we have to use two update indices:
+ * once to delete the old ref and its reflog, and once to create the
+ * new ref and its reflog. They need to be staged with two separate
+ * indices because the new reflog needs to encode both the deletion of
+ * the old branch and the creation of the new branch, and we cannot do
+ * two changes to a reflog in a single update.
+ */
+ deletion_ts = creation_ts = reftable_stack_next_update_index(arg->stack);
+ if (arg->delete_old)
+ creation_ts++;
+ reftable_writer_set_limits(writer, deletion_ts, creation_ts);
+
+ /*
+ * Add the new reference. If this is a rename then we also delete the
+ * old reference.
+ */
+ refs[0] = old_ref;
+ refs[0].refname = xstrdup(arg->newname);
+ refs[0].update_index = creation_ts;
+ if (arg->delete_old) {
+ refs[1].refname = xstrdup(arg->oldname);
+ refs[1].value_type = REFTABLE_REF_DELETION;
+ refs[1].update_index = deletion_ts;
+ }
+ ret = reftable_writer_add_refs(writer, refs, arg->delete_old ? 2 : 1);
+ if (ret < 0)
+ goto done;
+
+ /*
+ * When deleting the old branch we need to create a reflog entry on the
+ * new branch name that indicates that the old branch has been deleted
+ * and then recreated. This is a tad weird, but matches what the files
+ * backend does.
+ */
+ if (arg->delete_old) {
+ struct strbuf head_referent = STRBUF_INIT;
+ struct object_id head_oid;
+ int append_head_reflog;
+ unsigned head_type = 0;
+
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ memset(&logs[logs_nr], 0, sizeof(logs[logs_nr]));
+ fill_reftable_log_record(&logs[logs_nr], &committer_ident);
+ logs[logs_nr].refname = xstrdup(arg->newname);
+ logs[logs_nr].update_index = deletion_ts;
+ logs[logs_nr].value.update.message =
+ xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2);
+ memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
+ logs_nr++;
+
+ ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid,
+ &head_referent, &head_type);
+ if (ret < 0)
+ goto done;
+ append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname);
+ strbuf_release(&head_referent);
+
+ /*
+ * The files backend uses `refs_delete_ref()` to delete the old
+ * branch name, which will append a reflog entry for HEAD in
+ * case it points to the old branch.
+ */
+ if (append_head_reflog) {
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ logs[logs_nr] = logs[logs_nr - 1];
+ logs[logs_nr].refname = xstrdup("HEAD");
+ logs[logs_nr].value.update.name =
+ xstrdup(logs[logs_nr].value.update.name);
+ logs[logs_nr].value.update.email =
+ xstrdup(logs[logs_nr].value.update.email);
+ logs[logs_nr].value.update.message =
+ xstrdup(logs[logs_nr].value.update.message);
+ logs_nr++;
+ }
+ }
+
+ /*
+ * Create the reflog entry for the newly created branch.
+ */
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ memset(&logs[logs_nr], 0, sizeof(logs[logs_nr]));
+ fill_reftable_log_record(&logs[logs_nr], &committer_ident);
+ logs[logs_nr].refname = xstrdup(arg->newname);
+ logs[logs_nr].update_index = creation_ts;
+ logs[logs_nr].value.update.message =
+ xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2);
+ memcpy(logs[logs_nr].value.update.new_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
+ logs_nr++;
+
+ /*
+ * In addition to writing the reflog entry for the new branch, we also
+ * copy over all log entries from the old reflog. Last but not least,
+ * when renaming we also have to delete all the old reflog entries.
+ */
+ ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_iterator_seek_log(&it, arg->oldname);
+ if (ret < 0)
+ goto done;
+
+ while (1) {
+ ret = reftable_iterator_next_log(&it, &old_log);
+ if (ret < 0)
+ goto done;
+ if (ret > 0 || strcmp(old_log.refname, arg->oldname)) {
+ ret = 0;
+ break;
+ }
+
+ free(old_log.refname);
+
+ /*
+ * Copy over the old reflog entry with the new refname.
+ */
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ logs[logs_nr] = old_log;
+ logs[logs_nr].refname = xstrdup(arg->newname);
+ logs_nr++;
+
+ /*
+ * Delete the old reflog entry in case we are renaming.
+ */
+ if (arg->delete_old) {
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ memset(&logs[logs_nr], 0, sizeof(logs[logs_nr]));
+ logs[logs_nr].refname = xstrdup(arg->oldname);
+ logs[logs_nr].value_type = REFTABLE_LOG_DELETION;
+ logs[logs_nr].update_index = old_log.update_index;
+ logs_nr++;
+ }
+
+ /*
+ * Transfer ownership of the log record we're iterating over to
+ * the array of log records. Otherwise, the pointers would get
+ * free'd or reallocated by the iterator.
+ */
+ memset(&old_log, 0, sizeof(old_log));
+ }
+
+ ret = reftable_writer_add_logs(writer, logs, logs_nr);
+ if (ret < 0)
+ goto done;
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ reftable_iterator_destroy(&it);
+ string_list_clear(&skip, 0);
+ strbuf_release(&errbuf);
+ for (i = 0; i < logs_nr; i++)
+ reftable_log_record_release(&logs[i]);
+ free(logs);
+ for (i = 0; i < ARRAY_SIZE(refs); i++)
+ reftable_ref_record_release(&refs[i]);
+ reftable_ref_record_release(&old_ref);
+ reftable_log_record_release(&old_log);
+ return ret;
+}
+
+static int reftable_be_rename_ref(struct ref_store *ref_store,
+ const char *oldrefname,
+ const char *newrefname,
+ const char *logmsg)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
+ struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname);
+ struct write_copy_arg arg = {
+ .refs = refs,
+ .stack = stack,
+ .oldname = oldrefname,
+ .newname = newrefname,
+ .logmsg = logmsg,
+ .delete_old = 1,
+ };
+ int ret;
+
+ ret = refs->err;
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ goto done;
+ ret = reftable_stack_add(stack, &write_copy_table, &arg);
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ return ret;
+}
+
+static int reftable_be_copy_ref(struct ref_store *ref_store,
+ const char *oldrefname,
+ const char *newrefname,
+ const char *logmsg)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref");
+ struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname);
+ struct write_copy_arg arg = {
+ .refs = refs,
+ .stack = stack,
+ .oldname = oldrefname,
+ .newname = newrefname,
+ .logmsg = logmsg,
+ };
+ int ret;
+
+ ret = refs->err;
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ goto done;
+ ret = reftable_stack_add(stack, &write_copy_table, &arg);
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ return ret;
+}
+
+struct reftable_reflog_iterator {
+ struct ref_iterator base;
+ struct reftable_ref_store *refs;
+ struct reftable_iterator iter;
+ struct reftable_log_record log;
+ struct strbuf last_name;
+ int err;
+};
+
+static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
+{
+ struct reftable_reflog_iterator *iter =
+ (struct reftable_reflog_iterator *)ref_iterator;
+
+ while (!iter->err) {
+ iter->err = reftable_iterator_next_log(&iter->iter, &iter->log);
+ if (iter->err)
+ break;
+
+ /*
+ * We want the refnames that we have reflogs for, so we skip if
+ * we've already produced this name. This could be faster by
+ * seeking directly to reflog@update_index==0.
+ */
+ if (!strcmp(iter->log.refname, iter->last_name.buf))
+ continue;
+
+ if (check_refname_format(iter->log.refname,
+ REFNAME_ALLOW_ONELEVEL))
+ continue;
+
+ strbuf_reset(&iter->last_name);
+ strbuf_addstr(&iter->last_name, iter->log.refname);
+ iter->base.refname = iter->log.refname;
+
+ break;
+ }
+
+ if (iter->err > 0) {
+ if (ref_iterator_abort(ref_iterator) != ITER_DONE)
+ return ITER_ERROR;
+ return ITER_DONE;
+ }
+
+ if (iter->err < 0) {
+ ref_iterator_abort(ref_iterator);
+ return ITER_ERROR;
+ }
+
+ return ITER_OK;
+}
+
+static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
+ struct object_id *peeled UNUSED)
+{
+ BUG("reftable reflog iterator cannot be peeled");
+ return -1;
+}
+
+static int reftable_reflog_iterator_abort(struct ref_iterator *ref_iterator)
+{
+ struct reftable_reflog_iterator *iter =
+ (struct reftable_reflog_iterator *)ref_iterator;
+ reftable_log_record_release(&iter->log);
+ reftable_iterator_destroy(&iter->iter);
+ strbuf_release(&iter->last_name);
+ free(iter);
+ return ITER_DONE;
+}
+
+static struct ref_iterator_vtable reftable_reflog_iterator_vtable = {
+ .advance = reftable_reflog_iterator_advance,
+ .peel = reftable_reflog_iterator_peel,
+ .abort = reftable_reflog_iterator_abort
+};
+
+static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftable_ref_store *refs,
+ struct reftable_stack *stack)
+{
+ struct reftable_reflog_iterator *iter;
+ int ret;
+
+ iter = xcalloc(1, sizeof(*iter));
+ base_ref_iterator_init(&iter->base, &reftable_reflog_iterator_vtable);
+ strbuf_init(&iter->last_name, 0);
+ iter->refs = refs;
+
+ ret = refs->err;
+ if (ret)
+ goto done;
+
+ ret = reftable_stack_reload(stack);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_init_log_iterator(stack, &iter->iter);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_iterator_seek_log(&iter->iter, "");
+ if (ret < 0)
+ goto done;
+
+done:
+ iter->err = ret;
+ return iter;
+}
+
+static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *ref_store)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_iterator_begin");
+ struct reftable_reflog_iterator *main_iter, *worktree_iter;
+
+ main_iter = reflog_iterator_for_stack(refs, refs->main_stack);
+ if (!refs->worktree_stack)
+ return &main_iter->base;
+
+ worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_stack);
+
+ return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
+ ref_iterator_select, NULL);
+}
+
+static int yield_log_record(struct reftable_ref_store *refs,
+ struct reftable_log_record *log,
+ each_reflog_ent_fn fn,
+ void *cb_data)
+{
+ struct object_id old_oid, new_oid;
+ const char *full_committer;
+
+ oidread(&old_oid, log->value.update.old_hash, refs->base.repo->hash_algo);
+ oidread(&new_oid, log->value.update.new_hash, refs->base.repo->hash_algo);
+
+ /*
+ * When both the old object ID and the new object ID are null
+ * then this is the reflog existence marker. The caller must
+ * not be aware of it.
+ */
+ if (is_null_oid(&old_oid) && is_null_oid(&new_oid))
+ return 0;
+
+ full_committer = fmt_ident(log->value.update.name, log->value.update.email,
+ WANT_COMMITTER_IDENT, NULL, IDENT_NO_DATE);
+ return fn(&old_oid, &new_oid, full_committer,
+ log->value.update.time, log->value.update.tz_offset,
+ log->value.update.message, cb_data);
+}
+
+static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
+ const char *refname,
+ each_reflog_ent_fn fn,
+ void *cb_data)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent_reverse");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_log_record log = {0};
+ struct reftable_iterator it = {0};
+ int ret;
+
+ if (refs->err < 0)
+ return refs->err;
+
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_iterator_seek_log(&it, refname);
+ while (!ret) {
+ ret = reftable_iterator_next_log(&it, &log);
+ if (ret < 0)
+ break;
+ if (ret > 0 || strcmp(log.refname, refname)) {
+ ret = 0;
+ break;
+ }
+
+ ret = yield_log_record(refs, &log, fn, cb_data);
+ if (ret)
+ break;
+ }
+
+done:
+ reftable_log_record_release(&log);
+ reftable_iterator_destroy(&it);
+ return ret;
+}
+
+static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
+ const char *refname,
+ each_reflog_ent_fn fn,
+ void *cb_data)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_log_record *logs = NULL;
+ struct reftable_iterator it = {0};
+ size_t logs_alloc = 0, logs_nr = 0, i;
+ int ret;
+
+ if (refs->err < 0)
+ return refs->err;
+
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_iterator_seek_log(&it, refname);
+ while (!ret) {
+ struct reftable_log_record log = {0};
+
+ ret = reftable_iterator_next_log(&it, &log);
+ if (ret < 0)
+ goto done;
+ if (ret > 0 || strcmp(log.refname, refname)) {
+ reftable_log_record_release(&log);
+ ret = 0;
+ break;
+ }
+
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ logs[logs_nr++] = log;
+ }
+
+ for (i = logs_nr; i--;) {
+ ret = yield_log_record(refs, &logs[i], fn, cb_data);
+ if (ret)
+ goto done;
+ }
+
+done:
+ reftable_iterator_destroy(&it);
+ for (i = 0; i < logs_nr; i++)
+ reftable_log_record_release(&logs[i]);
+ free(logs);
+ return ret;
+}
+
+static int reftable_be_reflog_exists(struct ref_store *ref_store,
+ const char *refname)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_exists");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_log_record log = {0};
+ struct reftable_iterator it = {0};
+ int ret;
+
+ ret = refs->err;
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_reload(stack);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_iterator_seek_log(&it, refname);
+ if (ret < 0)
+ goto done;
+
+ /*
+ * Check whether we get at least one log record for the given ref name.
+ * If so, the reflog exists, otherwise it doesn't.
+ */
+ ret = reftable_iterator_next_log(&it, &log);
+ if (ret < 0)
+ goto done;
+ if (ret > 0) {
+ ret = 0;
+ goto done;
+ }
+
+ ret = strcmp(log.refname, refname) == 0;
+
+done:
+ reftable_iterator_destroy(&it);
+ reftable_log_record_release(&log);
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+struct write_reflog_existence_arg {
+ struct reftable_ref_store *refs;
+ const char *refname;
+ struct reftable_stack *stack;
+};
+
+static int write_reflog_existence_table(struct reftable_writer *writer,
+ void *cb_data)
+{
+ struct write_reflog_existence_arg *arg = cb_data;
+ uint64_t ts = reftable_stack_next_update_index(arg->stack);
+ struct reftable_log_record log = {0};
+ int ret;
+
+ ret = reftable_stack_read_log(arg->stack, arg->refname, &log);
+ if (ret <= 0)
+ goto done;
+
+ reftable_writer_set_limits(writer, ts, ts);
+
+ /*
+ * The existence entry has both old and new object ID set to the
+ * null object ID. Our iterators are aware of this and will not present
+ * them to their callers.
+ */
+ log.refname = xstrdup(arg->refname);
+ log.update_index = ts;
+ log.value_type = REFTABLE_LOG_UPDATE;
+ ret = reftable_writer_add_log(writer, &log);
+
+done:
+ assert(ret != REFTABLE_API_ERROR);
+ reftable_log_record_release(&log);
+ return ret;
+}
+
+static int reftable_be_create_reflog(struct ref_store *ref_store,
+ const char *refname,
+ struct strbuf *errmsg UNUSED)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct write_reflog_existence_arg arg = {
+ .refs = refs,
+ .stack = stack,
+ .refname = refname,
+ };
+ int ret;
+
+ ret = refs->err;
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ goto done;
+
+ ret = reftable_stack_add(stack, &write_reflog_existence_table, &arg);
+
+done:
+ return ret;
+}
+
+struct write_reflog_delete_arg {
+ struct reftable_stack *stack;
+ const char *refname;
+};
+
+static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_data)
+{
+ struct write_reflog_delete_arg *arg = cb_data;
+ struct reftable_log_record log = {0}, tombstone = {0};
+ struct reftable_iterator it = {0};
+ uint64_t ts = reftable_stack_next_update_index(arg->stack);
+ int ret;
+
+ reftable_writer_set_limits(writer, ts, ts);
+
+ ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * In order to delete a table we need to delete all reflog entries one
+ * by one. This is inefficient, but the reftable format does not have a
+ * better marker right now.
+ */
+ ret = reftable_iterator_seek_log(&it, arg->refname);
+ while (ret == 0) {
+ ret = reftable_iterator_next_log(&it, &log);
+ if (ret < 0)
+ break;
+ if (ret > 0 || strcmp(log.refname, arg->refname)) {
+ ret = 0;
+ break;
+ }
+
+ tombstone.refname = (char *)arg->refname;
+ tombstone.value_type = REFTABLE_LOG_DELETION;
+ tombstone.update_index = log.update_index;
+
+ ret = reftable_writer_add_log(writer, &tombstone);
+ }
+
+out:
+ reftable_log_record_release(&log);
+ reftable_iterator_destroy(&it);
+ return ret;
+}
+
+static int reftable_be_delete_reflog(struct ref_store *ref_store,
+ const char *refname)
+{
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "delete_reflog");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct write_reflog_delete_arg arg = {
+ .stack = stack,
+ .refname = refname,
+ };
+ int ret;
+
+ ret = reftable_stack_reload(stack);
+ if (ret)
+ return ret;
+ ret = reftable_stack_add(stack, &write_reflog_delete_table, &arg);
+
+ assert(ret != REFTABLE_API_ERROR);
+ return ret;
+}
+
+struct reflog_expiry_arg {
+ struct reftable_ref_store *refs;
+ struct reftable_stack *stack;
+ struct reftable_log_record *records;
+ struct object_id update_oid;
+ const char *refname;
+ size_t len;
+};
+
+static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_data)
+{
+ struct reflog_expiry_arg *arg = cb_data;
+ uint64_t ts = reftable_stack_next_update_index(arg->stack);
+ uint64_t live_records = 0;
+ size_t i;
+ int ret;
+
+ for (i = 0; i < arg->len; i++)
+ if (arg->records[i].value_type == REFTABLE_LOG_UPDATE)
+ live_records++;
+
+ reftable_writer_set_limits(writer, ts, ts);
+
+ if (!is_null_oid(&arg->update_oid)) {
+ struct reftable_ref_record ref = {0};
+ struct object_id peeled;
+
+ ref.refname = (char *)arg->refname;
+ ref.update_index = ts;
+
+ if (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled)) {
+ ref.value_type = REFTABLE_REF_VAL2;
+ memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
+ memcpy(ref.value.val2.value, arg->update_oid.hash, GIT_MAX_RAWSZ);
+ } else {
+ ref.value_type = REFTABLE_REF_VAL1;
+ memcpy(ref.value.val1, arg->update_oid.hash, GIT_MAX_RAWSZ);
+ }
+
+ ret = reftable_writer_add_ref(writer, &ref);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * When there are no more entries left in the reflog we empty it
+ * completely, but write a placeholder reflog entry that indicates that
+ * the reflog still exists.
+ */
+ if (!live_records) {
+ struct reftable_log_record log = {
+ .refname = (char *)arg->refname,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .update_index = ts,
+ };
+
+ ret = reftable_writer_add_log(writer, &log);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < arg->len; i++) {
+ ret = reftable_writer_add_log(writer, &arg->records[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int reftable_be_reflog_expire(struct ref_store *ref_store,
+ const char *refname,
+ unsigned int flags,
+ reflog_expiry_prepare_fn prepare_fn,
+ reflog_expiry_should_prune_fn should_prune_fn,
+ reflog_expiry_cleanup_fn cleanup_fn,
+ void *policy_cb_data)
+{
+ /*
+ * For log expiry, we write tombstones for every single reflog entry
+ * that is to be expired. This means that the entries are still
+ * retrievable by delving into the stack, and expiring entries
+ * paradoxically takes extra memory. This memory is only reclaimed when
+ * compacting the reftable stack.
+ *
+ * It would be better if the refs backend supported an API that sets a
+ * criterion for all refs, passing the criterion to pack_refs().
+ *
+ * On the plus side, because we do the expiration per ref, we can easily
+ * insert the reflog existence dummies.
+ */
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_WRITE, "reflog_expire");
+ struct reftable_stack *stack = stack_for(refs, refname, &refname);
+ struct reftable_log_record *logs = NULL;
+ struct reftable_log_record *rewritten = NULL;
+ struct reftable_ref_record ref_record = {0};
+ struct reftable_iterator it = {0};
+ struct reftable_addition *add = NULL;
+ struct reflog_expiry_arg arg = {0};
+ struct object_id oid = {0};
+ uint8_t *last_hash = NULL;
+ size_t logs_nr = 0, logs_alloc = 0, i;
+ int ret;
+
+ if (refs->err < 0)
+ return refs->err;
+
+ ret = reftable_stack_reload(stack);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_iterator_seek_log(&it, refname);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_new_addition(&add, stack, 0);
+ if (ret < 0)
+ goto done;
+
+ ret = reftable_stack_read_ref(stack, refname, &ref_record);
+ if (ret < 0)
+ goto done;
+ if (reftable_ref_record_val1(&ref_record))
+ oidread(&oid, reftable_ref_record_val1(&ref_record),
+ ref_store->repo->hash_algo);
+ prepare_fn(refname, &oid, policy_cb_data);
+
+ while (1) {
+ struct reftable_log_record log = {0};
+ struct object_id old_oid, new_oid;
+
+ ret = reftable_iterator_next_log(&it, &log);
+ if (ret < 0)
+ goto done;
+ if (ret > 0 || strcmp(log.refname, refname)) {
+ reftable_log_record_release(&log);
+ break;
+ }
+
+ oidread(&old_oid, log.value.update.old_hash,
+ ref_store->repo->hash_algo);
+ oidread(&new_oid, log.value.update.new_hash,
+ ref_store->repo->hash_algo);
+
+ /*
+ * Skip over the reflog existence marker. We will add it back
+ * in when there are no live reflog records.
+ */
+ if (is_null_oid(&old_oid) && is_null_oid(&new_oid)) {
+ reftable_log_record_release(&log);
+ continue;
+ }
+
+ ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+ logs[logs_nr++] = log;
+ }
+
+ /*
+ * We need to rewrite all reflog entries according to the pruning
+ * callback function:
+ *
+ * - If a reflog entry shall be pruned we mark the record for
+ * deletion.
+ *
+ * - Otherwise we may have to rewrite the chain of reflog entries so
+ * that gaps created by just-deleted records get backfilled.
+ */
+ CALLOC_ARRAY(rewritten, logs_nr);
+ for (i = logs_nr; i--;) {
+ struct reftable_log_record *dest = &rewritten[i];
+ struct object_id old_oid, new_oid;
+
+ *dest = logs[i];
+ oidread(&old_oid, logs[i].value.update.old_hash,
+ ref_store->repo->hash_algo);
+ oidread(&new_oid, logs[i].value.update.new_hash,
+ ref_store->repo->hash_algo);
+
+ if (should_prune_fn(&old_oid, &new_oid, logs[i].value.update.email,
+ (timestamp_t)logs[i].value.update.time,
+ logs[i].value.update.tz_offset,
+ logs[i].value.update.message,
+ policy_cb_data)) {
+ dest->value_type = REFTABLE_LOG_DELETION;
+ } else {
+ if ((flags & EXPIRE_REFLOGS_REWRITE) && last_hash)
+ memcpy(dest->value.update.old_hash, last_hash, GIT_MAX_RAWSZ);
+ last_hash = logs[i].value.update.new_hash;
+ }
+ }
+
+ if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash &&
+ reftable_ref_record_val1(&ref_record))
+ oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo);
+
+ arg.refs = refs;
+ arg.records = rewritten;
+ arg.len = logs_nr;
+ arg.stack = stack,
+ arg.refname = refname,
+
+ ret = reftable_addition_add(add, &write_reflog_expiry_table, &arg);
+ if (ret < 0)
+ goto done;
+
+ /*
+ * Future improvement: we could skip writing records that were
+ * not changed.
+ */
+ if (!(flags & EXPIRE_REFLOGS_DRY_RUN))
+ ret = reftable_addition_commit(add);
+
+done:
+ if (add)
+ cleanup_fn(policy_cb_data);
+ assert(ret != REFTABLE_API_ERROR);
+
+ reftable_ref_record_release(&ref_record);
+ reftable_iterator_destroy(&it);
+ reftable_addition_destroy(add);
+ for (i = 0; i < logs_nr; i++)
+ reftable_log_record_release(&logs[i]);
+ free(logs);
+ free(rewritten);
+ return ret;
+}
+
+static int reftable_be_fsck(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o UNUSED,
+ struct worktree *wt UNUSED)
+{
+ return 0;
+}
+
+struct ref_storage_be refs_be_reftable = {
+ .name = "reftable",
+ .init = reftable_be_init,
+ .release = reftable_be_release,
+ .create_on_disk = reftable_be_create_on_disk,
+ .remove_on_disk = reftable_be_remove_on_disk,
+
+ .transaction_prepare = reftable_be_transaction_prepare,
+ .transaction_finish = reftable_be_transaction_finish,
+ .transaction_abort = reftable_be_transaction_abort,
+
+ .pack_refs = reftable_be_pack_refs,
+ .rename_ref = reftable_be_rename_ref,
+ .copy_ref = reftable_be_copy_ref,
+
+ .iterator_begin = reftable_be_iterator_begin,
+ .read_raw_ref = reftable_be_read_raw_ref,
+ .read_symbolic_ref = reftable_be_read_symbolic_ref,
+
+ .reflog_iterator_begin = reftable_be_reflog_iterator_begin,
+ .for_each_reflog_ent = reftable_be_for_each_reflog_ent,
+ .for_each_reflog_ent_reverse = reftable_be_for_each_reflog_ent_reverse,
+ .reflog_exists = reftable_be_reflog_exists,
+ .create_reflog = reftable_be_create_reflog,
+ .delete_reflog = reftable_be_delete_reflog,
+ .reflog_expire = reftable_be_reflog_expire,
+
+ .fsck = reftable_be_fsck,
+};
diff --git a/refspec.c b/refspec.c
index d60932f4de..994901f55b 100644
--- a/refspec.c
+++ b/refspec.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hash.h"
@@ -7,19 +9,6 @@
#include "refspec.h"
#include "strbuf.h"
-static struct refspec_item s_tag_refspec = {
- .force = 0,
- .pattern = 1,
- .matching = 0,
- .exact_sha1 = 0,
- .negative = 0,
- .src = "refs/tags/*",
- .dst = "refs/tags/*",
-};
-
-/* See TAG_REFSPEC for the string version */
-const struct refspec_item *tag_refspec = &s_tag_refspec;
-
/*
* Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
* Returns 1 if successful and 0 if the refspec is invalid.
@@ -164,6 +153,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
{
memset(item, 0, sizeof(*item));
+ item->raw = xstrdup(refspec);
return parse_refspec(item, refspec, fetch);
}
@@ -178,6 +168,7 @@ void refspec_item_clear(struct refspec_item *item)
{
FREE_AND_NULL(item->src);
FREE_AND_NULL(item->dst);
+ FREE_AND_NULL(item->raw);
item->force = 0;
item->pattern = 0;
item->matching = 0;
@@ -190,31 +181,29 @@ void refspec_init(struct refspec *rs, int fetch)
rs->fetch = fetch;
}
-static void refspec_append_nodup(struct refspec *rs, char *refspec)
+void refspec_append(struct refspec *rs, const char *refspec)
{
struct refspec_item item;
refspec_item_init_or_die(&item, refspec, rs->fetch);
ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
- rs->items[rs->nr++] = item;
-
- ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc);
- rs->raw[rs->raw_nr++] = refspec;
-}
+ rs->items[rs->nr] = item;
-void refspec_append(struct refspec *rs, const char *refspec)
-{
- refspec_append_nodup(rs, xstrdup(refspec));
+ rs->nr++;
}
void refspec_appendf(struct refspec *rs, const char *fmt, ...)
{
va_list ap;
+ char *buf;
va_start(ap, fmt);
- refspec_append_nodup(rs, xstrvfmt(fmt, ap));
+ buf = xstrvfmt(fmt, ap);
va_end(ap);
+
+ refspec_append(rs, buf);
+ free(buf);
}
void refspec_appendn(struct refspec *rs, const char **refspecs, int nr)
@@ -235,12 +224,6 @@ void refspec_clear(struct refspec *rs)
rs->alloc = 0;
rs->nr = 0;
- for (i = 0; i < rs->raw_nr; i++)
- free((char *)rs->raw[i]);
- FREE_AND_NULL(rs->raw);
- rs->raw_alloc = 0;
- rs->raw_nr = 0;
-
rs->fetch = 0;
}
diff --git a/refspec.h b/refspec.h
index 8c0c446993..69d693c87d 100644
--- a/refspec.h
+++ b/refspec.h
@@ -2,7 +2,6 @@
#define REFSPEC_H
#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
-extern const struct refspec_item *tag_refspec;
/**
* A struct refspec_item holds the parsed interpretation of a refspec. If it
@@ -27,6 +26,8 @@ struct refspec_item {
char *src;
char *dst;
+
+ char *raw;
};
#define REFSPEC_FETCH 1
@@ -44,10 +45,6 @@ struct refspec {
int alloc;
int nr;
- const char **raw;
- int raw_alloc;
- int raw_nr;
-
int fetch;
};
diff --git a/reftable/basics.c b/reftable/basics.c
index f761e48028..bc4fcc9144 100644
--- a/reftable/basics.c
+++ b/reftable/basics.c
@@ -6,7 +6,142 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#define REFTABLE_ALLOW_BANNED_ALLOCATORS
#include "basics.h"
+#include "reftable-basics.h"
+#include "reftable-error.h"
+
+static void *(*reftable_malloc_ptr)(size_t sz);
+static void *(*reftable_realloc_ptr)(void *, size_t);
+static void (*reftable_free_ptr)(void *);
+
+void *reftable_malloc(size_t sz)
+{
+ if (reftable_malloc_ptr)
+ return (*reftable_malloc_ptr)(sz);
+ return malloc(sz);
+}
+
+void *reftable_realloc(void *p, size_t sz)
+{
+ if (reftable_realloc_ptr)
+ return (*reftable_realloc_ptr)(p, sz);
+ return realloc(p, sz);
+}
+
+void reftable_free(void *p)
+{
+ if (reftable_free_ptr)
+ reftable_free_ptr(p);
+ else
+ free(p);
+}
+
+void *reftable_calloc(size_t nelem, size_t elsize)
+{
+ void *p;
+
+ if (nelem && elsize > SIZE_MAX / nelem)
+ return NULL;
+
+ p = reftable_malloc(nelem * elsize);
+ if (!p)
+ return NULL;
+
+ memset(p, 0, nelem * elsize);
+ return p;
+}
+
+char *reftable_strdup(const char *str)
+{
+ size_t len = strlen(str);
+ char *result = reftable_malloc(len + 1);
+ if (!result)
+ return NULL;
+ memcpy(result, str, len + 1);
+ return result;
+}
+
+void reftable_set_alloc(void *(*malloc)(size_t),
+ void *(*realloc)(void *, size_t), void (*free)(void *))
+{
+ reftable_malloc_ptr = malloc;
+ reftable_realloc_ptr = realloc;
+ reftable_free_ptr = free;
+}
+
+void reftable_buf_init(struct reftable_buf *buf)
+{
+ struct reftable_buf empty = REFTABLE_BUF_INIT;
+ *buf = empty;
+}
+
+void reftable_buf_release(struct reftable_buf *buf)
+{
+ reftable_free(buf->buf);
+ reftable_buf_init(buf);
+}
+
+void reftable_buf_reset(struct reftable_buf *buf)
+{
+ if (buf->alloc) {
+ buf->len = 0;
+ buf->buf[0] = '\0';
+ }
+}
+
+int reftable_buf_setlen(struct reftable_buf *buf, size_t len)
+{
+ if (len > buf->len)
+ return -1;
+ if (len == buf->len)
+ return 0;
+ buf->buf[len] = '\0';
+ buf->len = len;
+ return 0;
+}
+
+int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b)
+{
+ size_t len = a->len < b->len ? a->len : b->len;
+ if (len) {
+ int cmp = memcmp(a->buf, b->buf, len);
+ if (cmp)
+ return cmp;
+ }
+ return a->len < b->len ? -1 : a->len != b->len;
+}
+
+int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len)
+{
+ size_t newlen = buf->len + len;
+
+ if (newlen + 1 > buf->alloc) {
+ char *reallocated = buf->buf;
+ REFTABLE_ALLOC_GROW(reallocated, newlen + 1, buf->alloc);
+ if (!reallocated)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+ buf->buf = reallocated;
+ }
+
+ memcpy(buf->buf + buf->len, data, len);
+ buf->buf[newlen] = '\0';
+ buf->len = newlen;
+
+ return 0;
+}
+
+int reftable_buf_addstr(struct reftable_buf *buf, const char *s)
+{
+ return reftable_buf_add(buf, s, strlen(s));
+}
+
+char *reftable_buf_detach(struct reftable_buf *buf)
+{
+ char *result = buf->buf;
+ reftable_buf_init(buf);
+ return result;
+}
void put_be24(uint8_t *out, uint32_t i)
{
@@ -27,7 +162,7 @@ void put_be16(uint8_t *out, uint16_t i)
out[1] = (uint8_t)(i & 0xff);
}
-int binsearch(size_t sz, int (*f)(size_t k, void *args), void *args)
+size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args)
{
size_t lo = 0;
size_t hi = sz;
@@ -39,8 +174,11 @@ int binsearch(size_t sz, int (*f)(size_t k, void *args), void *args)
*/
while (hi - lo > 1) {
size_t mid = lo + (hi - lo) / 2;
+ int ret = f(mid, args);
+ if (ret < 0)
+ return sz;
- if (f(mid, args))
+ if (ret > 0)
hi = mid;
else
lo = mid;
@@ -64,23 +202,22 @@ void free_names(char **a)
reftable_free(a);
}
-int names_length(char **names)
+size_t names_length(const char **names)
{
- char **p = names;
- for (; *p; p++) {
- /* empty */
- }
+ const char **p = names;
+ while (*p)
+ p++;
return p - names;
}
-void parse_names(char *buf, int size, char ***namesp)
+char **parse_names(char *buf, int size)
{
char **names = NULL;
size_t names_cap = 0;
size_t names_len = 0;
-
char *p = buf;
char *end = buf + size;
+
while (p < end) {
char *next = strchr(p, '\n');
if (next && next < end) {
@@ -89,34 +226,41 @@ void parse_names(char *buf, int size, char ***namesp)
next = end;
}
if (p < next) {
- if (names_len == names_cap) {
- names_cap = 2 * names_cap + 1;
- names = reftable_realloc(
- names, names_cap * sizeof(*names));
- }
- names[names_len++] = xstrdup(p);
+ char **names_grown = names;
+ REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap);
+ if (!names_grown)
+ goto err;
+ names = names_grown;
+
+ names[names_len] = reftable_strdup(p);
+ if (!names[names_len++])
+ goto err;
}
p = next + 1;
}
- names = reftable_realloc(names, (names_len + 1) * sizeof(*names));
+ REFTABLE_REALLOC_ARRAY(names, names_len + 1);
names[names_len] = NULL;
- *namesp = names;
+
+ return names;
+
+err:
+ for (size_t i = 0; i < names_len; i++)
+ reftable_free(names[i]);
+ reftable_free(names);
+ return NULL;
}
-int names_equal(char **a, char **b)
+int names_equal(const char **a, const char **b)
{
- int i = 0;
- for (; a[i] && b[i]; i++) {
- if (strcmp(a[i], b[i])) {
+ size_t i = 0;
+ for (; a[i] && b[i]; i++)
+ if (strcmp(a[i], b[i]))
return 0;
- }
- }
-
return a[i] == b[i];
}
-int common_prefix_size(struct strbuf *a, struct strbuf *b)
+int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
{
int p = 0;
for (; p < a->len && p < b->len; p++) {
@@ -126,3 +270,15 @@ int common_prefix_size(struct strbuf *a, struct strbuf *b)
return p;
}
+
+int hash_size(uint32_t id)
+{
+ switch (id) {
+ case 0:
+ case GIT_SHA1_FORMAT_ID:
+ return GIT_SHA1_RAWSZ;
+ case GIT_SHA256_FORMAT_ID:
+ return GIT_SHA256_RAWSZ;
+ }
+ abort();
+}
diff --git a/reftable/basics.h b/reftable/basics.h
index 096b36862b..7aa46d7c30 100644
--- a/reftable/basics.h
+++ b/reftable/basics.h
@@ -14,6 +14,65 @@ https://developers.google.com/open-source/licenses/bsd
*/
#include "system.h"
+#include "reftable-basics.h"
+
+struct reftable_buf {
+ size_t alloc;
+ size_t len;
+ char *buf;
+};
+#define REFTABLE_BUF_INIT { 0 }
+
+/*
+ * Initialize the buffer such that it is ready for use. This is equivalent to
+ * using REFTABLE_BUF_INIT for stack-allocated variables.
+ */
+void reftable_buf_init(struct reftable_buf *buf);
+
+/*
+ * Release memory associated with the buffer. The buffer is reinitialized such
+ * that it can be reused for subsequent operations.
+ */
+void reftable_buf_release(struct reftable_buf *buf);
+
+/*
+ * Reset the buffer such that it is effectively empty, without releasing the
+ * memory that this structure holds on to. This is equivalent to calling
+ * `reftable_buf_setlen(buf, 0)`.
+ */
+void reftable_buf_reset(struct reftable_buf *buf);
+
+/*
+ * Trim the buffer to a shorter length by updating the `len` member and writing
+ * a NUL byte to `buf[len]`. Returns 0 on success, -1 when `len` points outside
+ * of the array.
+ */
+int reftable_buf_setlen(struct reftable_buf *buf, size_t len);
+
+/*
+ * Lexicographically compare the two buffers. Returns 0 when both buffers have
+ * the same contents, -1 when `a` is lexicographically smaller than `b`, and 1
+ * otherwise.
+ */
+int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b);
+
+/*
+ * Append `len` bytes from `data` to the buffer. This function works with
+ * arbitrary byte sequences, including ones that contain embedded NUL
+ * characters. As such, we use `void *` as input type. Returns 0 on success,
+ * REFTABLE_OUT_OF_MEMORY_ERROR on allocation failure.
+ */
+int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len);
+
+/* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */
+int reftable_buf_addstr(struct reftable_buf *buf, const char *s);
+
+/*
+ * Detach the buffer from the structure such that the underlying memory is now
+ * owned by the caller. The buffer is reinitialized such that it can be reused
+ * for subsequent operations.
+ */
+char *reftable_buf_detach(struct reftable_buf *buf);
/* Bigendian en/decoding of integers */
@@ -22,13 +81,14 @@ uint32_t get_be24(uint8_t *in);
void put_be16(uint8_t *out, uint16_t i);
/*
- * find smallest index i in [0, sz) at which f(i) is true, assuming
- * that f is ascending. Return sz if f(i) is false for all indices.
+ * find smallest index i in [0, sz) at which `f(i) > 0`, assuming that f is
+ * ascending. Return sz if `f(i) == 0` for all indices. The search is aborted
+ * and `sz` is returned in case `f(i) < 0`.
*
* Contrary to bsearch(3), this returns something useful if the argument is not
* found.
*/
-int binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
+size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
/*
* Frees a NULL terminated array of malloced strings. The array itself is also
@@ -36,25 +96,58 @@ int binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
*/
void free_names(char **a);
-/* parse a newline separated list of names. `size` is the length of the buffer,
- * without terminating '\0'. Empty names are discarded. */
-void parse_names(char *buf, int size, char ***namesp);
+/*
+ * Parse a newline separated list of names. `size` is the length of the buffer,
+ * without terminating '\0'. Empty names are discarded. Returns a `NULL`
+ * pointer when allocations fail.
+ */
+char **parse_names(char *buf, int size);
/* compares two NULL-terminated arrays of strings. */
-int names_equal(char **a, char **b);
+int names_equal(const char **a, const char **b);
/* returns the array size of a NULL-terminated array of strings. */
-int names_length(char **names);
+size_t names_length(const char **names);
/* Allocation routines; they invoke the functions set through
* reftable_set_alloc() */
void *reftable_malloc(size_t sz);
void *reftable_realloc(void *p, size_t sz);
void reftable_free(void *p);
-void *reftable_calloc(size_t sz);
+void *reftable_calloc(size_t nelem, size_t elsize);
+char *reftable_strdup(const char *str);
+
+#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
+#define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
+#define REFTABLE_REALLOC_ARRAY(x, alloc) (x) = reftable_realloc((x), st_mult(sizeof(*(x)), (alloc)))
+#define REFTABLE_ALLOC_GROW(x, nr, alloc) \
+ do { \
+ if ((nr) > alloc) { \
+ alloc = 2 * (alloc) + 1; \
+ if (alloc < (nr)) \
+ alloc = (nr); \
+ REFTABLE_REALLOC_ARRAY(x, alloc); \
+ } \
+ } while (0)
+#define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0)
+
+#ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS
+# define REFTABLE_BANNED(func) use_reftable_##func##_instead
+# undef malloc
+# define malloc(sz) REFTABLE_BANNED(malloc)
+# undef realloc
+# define realloc(ptr, sz) REFTABLE_BANNED(realloc)
+# undef free
+# define free(ptr) REFTABLE_BANNED(free)
+# undef calloc
+# define calloc(nelem, elsize) REFTABLE_BANNED(calloc)
+# undef strdup
+# define strdup(str) REFTABLE_BANNED(strdup)
+#endif
/* Find the longest shared prefix size of `a` and `b` */
-struct strbuf;
-int common_prefix_size(struct strbuf *a, struct strbuf *b);
+int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
+
+int hash_size(uint32_t id);
#endif
diff --git a/reftable/basics_test.c b/reftable/basics_test.c
deleted file mode 100644
index 1fcd229725..0000000000
--- a/reftable/basics_test.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-
-#include "basics.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-struct binsearch_args {
- int key;
- int *arr;
-};
-
-static int binsearch_func(size_t i, void *void_args)
-{
- struct binsearch_args *args = void_args;
-
- return args->key < args->arr[i];
-}
-
-static void test_binsearch(void)
-{
- int arr[] = { 2, 4, 6, 8, 10 };
- size_t sz = ARRAY_SIZE(arr);
- struct binsearch_args args = {
- .arr = arr,
- };
-
- int i = 0;
- for (i = 1; i < 11; i++) {
- int res;
- args.key = i;
- res = binsearch(sz, &binsearch_func, &args);
-
- if (res < sz) {
- EXPECT(args.key < arr[res]);
- if (res > 0) {
- EXPECT(args.key >= arr[res - 1]);
- }
- } else {
- EXPECT(args.key == 10 || args.key == 11);
- }
- }
-}
-
-static void test_names_length(void)
-{
- char *a[] = { "a", "b", NULL };
- EXPECT(names_length(a) == 2);
-}
-
-static void test_parse_names_normal(void)
-{
- char in[] = "a\nb\n";
- char **out = NULL;
- parse_names(in, strlen(in), &out);
- EXPECT(!strcmp(out[0], "a"));
- EXPECT(!strcmp(out[1], "b"));
- EXPECT(!out[2]);
- free_names(out);
-}
-
-static void test_parse_names_drop_empty(void)
-{
- char in[] = "a\n\n";
- char **out = NULL;
- parse_names(in, strlen(in), &out);
- EXPECT(!strcmp(out[0], "a"));
- EXPECT(!out[1]);
- free_names(out);
-}
-
-static void test_common_prefix(void)
-{
- struct strbuf s1 = STRBUF_INIT;
- struct strbuf s2 = STRBUF_INIT;
- strbuf_addstr(&s1, "abcdef");
- strbuf_addstr(&s2, "abc");
- EXPECT(common_prefix_size(&s1, &s2) == 3);
- strbuf_release(&s1);
- strbuf_release(&s2);
-}
-
-int basics_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_common_prefix);
- RUN_TEST(test_parse_names_normal);
- RUN_TEST(test_parse_names_drop_empty);
- RUN_TEST(test_binsearch);
- RUN_TEST(test_names_length);
- return 0;
-}
diff --git a/reftable/block.c b/reftable/block.c
index 34d4d07369..0198078485 100644
--- a/reftable/block.c
+++ b/reftable/block.c
@@ -38,9 +38,11 @@ int footer_size(int version)
}
static int block_writer_register_restart(struct block_writer *w, int n,
- int is_restart, struct strbuf *key)
+ int is_restart, struct reftable_buf *key)
{
- int rlen = w->restart_len;
+ int rlen, err;
+
+ rlen = w->restart_len;
if (rlen >= MAX_RESTARTS) {
is_restart = 0;
}
@@ -51,41 +53,49 @@ static int block_writer_register_restart(struct block_writer *w, int n,
if (2 + 3 * rlen + n > w->block_size - w->next)
return -1;
if (is_restart) {
- if (w->restart_len == w->restart_cap) {
- w->restart_cap = w->restart_cap * 2 + 1;
- w->restarts = reftable_realloc(
- w->restarts, sizeof(uint32_t) * w->restart_cap);
- }
-
+ REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap);
+ if (!w->restarts)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
w->restarts[w->restart_len++] = w->next;
}
w->next += n;
- strbuf_reset(&w->last_key);
- strbuf_addbuf(&w->last_key, key);
+ reftable_buf_reset(&w->last_key);
+ err = reftable_buf_add(&w->last_key, key->buf, key->len);
+ if (err < 0)
+ return err;
+
w->entries++;
return 0;
}
-void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
- uint32_t block_size, uint32_t header_off, int hash_size)
+int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *block,
+ uint32_t block_size, uint32_t header_off, int hash_size)
{
- bw->buf = buf;
+ bw->block = block;
bw->hash_size = hash_size;
bw->block_size = block_size;
bw->header_off = header_off;
- bw->buf[header_off] = typ;
+ bw->block[header_off] = typ;
bw->next = header_off + 4;
bw->restart_interval = 16;
bw->entries = 0;
bw->restart_len = 0;
bw->last_key.len = 0;
+ if (!bw->zstream) {
+ REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
+ if (!bw->zstream)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+ deflateInit(bw->zstream, 9);
+ }
+
+ return 0;
}
uint8_t block_writer_type(struct block_writer *bw)
{
- return bw->buf[bw->header_off];
+ return bw->block[bw->header_off];
}
/* Adds the reftable_record to the block. Returns -1 if it does not fit, 0 on
@@ -93,42 +103,45 @@ uint8_t block_writer_type(struct block_writer *bw)
empty key. */
int block_writer_add(struct block_writer *w, struct reftable_record *rec)
{
- struct strbuf empty = STRBUF_INIT;
- struct strbuf last =
+ struct reftable_buf empty = REFTABLE_BUF_INIT;
+ struct reftable_buf last =
w->entries % w->restart_interval == 0 ? empty : w->last_key;
struct string_view out = {
- .buf = w->buf + w->next,
+ .buf = w->block + w->next,
.len = w->block_size - w->next,
};
-
struct string_view start = out;
-
int is_restart = 0;
- struct strbuf key = STRBUF_INIT;
int n = 0;
- int err = -1;
+ int err;
+
+ err = reftable_record_key(rec, &w->scratch);
+ if (err < 0)
+ goto done;
- reftable_record_key(rec, &key);
- if (!key.len) {
+ if (!w->scratch.len) {
err = REFTABLE_API_ERROR;
goto done;
}
- n = reftable_encode_key(&is_restart, out, last, key,
+ n = reftable_encode_key(&is_restart, out, last, w->scratch,
reftable_record_val_type(rec));
- if (n < 0)
+ if (n < 0) {
+ err = -1;
goto done;
+ }
string_view_consume(&out, n);
n = reftable_record_encode(rec, out, w->hash_size);
- if (n < 0)
+ if (n < 0) {
+ err = -1;
goto done;
+ }
string_view_consume(&out, n);
err = block_writer_register_restart(w, start.len - out.len, is_restart,
- &key);
+ &w->scratch);
done:
- strbuf_release(&key);
return err;
}
@@ -136,51 +149,65 @@ int block_writer_finish(struct block_writer *w)
{
int i;
for (i = 0; i < w->restart_len; i++) {
- put_be24(w->buf + w->next, w->restarts[i]);
+ put_be24(w->block + w->next, w->restarts[i]);
w->next += 3;
}
- put_be16(w->buf + w->next, w->restart_len);
+ put_be16(w->block + w->next, w->restart_len);
w->next += 2;
- put_be24(w->buf + 1 + w->header_off, w->next);
+ put_be24(w->block + 1 + w->header_off, w->next);
+ /*
+ * Log records are stored zlib-compressed. Note that the compression
+ * also spans over the restart points we have just written.
+ */
if (block_writer_type(w) == BLOCK_TYPE_LOG) {
int block_header_skip = 4 + w->header_off;
- uLongf src_len = w->next - block_header_skip;
- uLongf dest_cap = src_len * 1.001 + 12;
-
- uint8_t *compressed = reftable_malloc(dest_cap);
- while (1) {
- uLongf out_dest_len = dest_cap;
- int zresult = compress2(compressed, &out_dest_len,
- w->buf + block_header_skip,
- src_len, 9);
- if (zresult == Z_BUF_ERROR && dest_cap < LONG_MAX) {
- dest_cap *= 2;
- compressed =
- reftable_realloc(compressed, dest_cap);
- if (compressed)
- continue;
- }
+ uLongf src_len = w->next - block_header_skip, compressed_len;
+ int ret;
- if (Z_OK != zresult) {
- reftable_free(compressed);
- return REFTABLE_ZLIB_ERROR;
- }
+ ret = deflateReset(w->zstream);
+ if (ret != Z_OK)
+ return REFTABLE_ZLIB_ERROR;
- memcpy(w->buf + block_header_skip, compressed,
- out_dest_len);
- w->next = out_dest_len + block_header_skip;
- reftable_free(compressed);
- break;
+ /*
+ * Precompute the upper bound of how many bytes the compressed
+ * data may end up with. Combined with `Z_FINISH`, `deflate()`
+ * is guaranteed to return `Z_STREAM_END`.
+ */
+ compressed_len = deflateBound(w->zstream, src_len);
+ REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap);
+ if (!w->compressed) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ return ret;
}
+
+ w->zstream->next_out = w->compressed;
+ w->zstream->avail_out = compressed_len;
+ w->zstream->next_in = w->block + block_header_skip;
+ w->zstream->avail_in = src_len;
+
+ /*
+ * We want to perform all decompression in a single step, which
+ * is why we can pass Z_FINISH here. As we have precomputed the
+ * deflated buffer's size via `deflateBound()` this function is
+ * guaranteed to succeed according to the zlib documentation.
+ */
+ ret = deflate(w->zstream, Z_FINISH);
+ if (ret != Z_STREAM_END)
+ return REFTABLE_ZLIB_ERROR;
+
+ /*
+ * Overwrite the uncompressed data we have already written and
+ * adjust the `next` pointer to point right after the
+ * compressed data.
+ */
+ memcpy(w->block + block_header_skip, w->compressed,
+ w->zstream->total_out);
+ w->next = w->zstream->total_out + block_header_skip;
}
- return w->next;
-}
-uint8_t block_reader_type(struct block_reader *r)
-{
- return r->block.data[r->header_off];
+ return w->next;
}
int block_reader_init(struct block_reader *br, struct reftable_block *block,
@@ -194,7 +221,8 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
uint16_t restart_count = 0;
uint32_t restart_start = 0;
uint8_t *restart_bytes = NULL;
- uint8_t *uncompressed = NULL;
+
+ reftable_block_done(&br->block);
if (!reftable_is_block_type(typ)) {
err = REFTABLE_FORMAT_ERROR;
@@ -202,37 +230,66 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
}
if (typ == BLOCK_TYPE_LOG) {
- int block_header_skip = 4 + header_off;
- uLongf dst_len = sz - block_header_skip; /* total size of dest
- buffer. */
- uLongf src_len = block->len - block_header_skip;
- /* Log blocks specify the *uncompressed* size in their header.
- */
- uncompressed = reftable_malloc(sz);
+ uint32_t block_header_skip = 4 + header_off;
+ uLong dst_len = sz - block_header_skip;
+ uLong src_len = block->len - block_header_skip;
+
+ /* Log blocks specify the *uncompressed* size in their header. */
+ REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
+ br->uncompressed_cap);
+ if (!br->uncompressed_data) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
/* Copy over the block header verbatim. It's not compressed. */
- memcpy(uncompressed, block->data, block_header_skip);
+ memcpy(br->uncompressed_data, block->data, block_header_skip);
+
+ if (!br->zstream) {
+ REFTABLE_CALLOC_ARRAY(br->zstream, 1);
+ if (!br->zstream) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
- /* Uncompress */
- if (Z_OK !=
- uncompress2(uncompressed + block_header_skip, &dst_len,
- block->data + block_header_skip, &src_len)) {
+ err = inflateInit(br->zstream);
+ } else {
+ err = inflateReset(br->zstream);
+ }
+ if (err != Z_OK) {
err = REFTABLE_ZLIB_ERROR;
goto done;
}
- if (dst_len + block_header_skip != sz) {
+ br->zstream->next_in = block->data + block_header_skip;
+ br->zstream->avail_in = src_len;
+ br->zstream->next_out = br->uncompressed_data + block_header_skip;
+ br->zstream->avail_out = dst_len;
+
+ /*
+ * We know both input as well as output size, and we know that
+ * the sizes should never be bigger than `uInt_MAX` because
+ * blocks can at most be 16MB large. We can thus use `Z_FINISH`
+ * here to instruct zlib to inflate the data in one go, which
+ * is more efficient than using `Z_NO_FLUSH`.
+ */
+ err = inflate(br->zstream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ err = REFTABLE_ZLIB_ERROR;
+ goto done;
+ }
+ err = 0;
+
+ if (br->zstream->total_out + block_header_skip != sz) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
/* We're done with the input data. */
reftable_block_done(block);
- block->data = uncompressed;
- uncompressed = NULL;
+ block->data = br->uncompressed_data;
block->len = sz;
- block->source = malloc_block_source();
- full_block_size = src_len + block_header_skip;
+ full_block_size = src_len + block_header_skip - br->zstream->avail_in;
} else if (full_block_size == 0) {
full_block_size = sz;
} else if (sz < full_block_size && sz < block->len &&
@@ -260,183 +317,256 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
br->restart_bytes = restart_bytes;
done:
- reftable_free(uncompressed);
return err;
}
-static uint32_t block_reader_restart_offset(struct block_reader *br, int i)
+void block_reader_release(struct block_reader *br)
+{
+ inflateEnd(br->zstream);
+ reftable_free(br->zstream);
+ reftable_free(br->uncompressed_data);
+ reftable_block_done(&br->block);
+}
+
+uint8_t block_reader_type(const struct block_reader *r)
+{
+ return r->block.data[r->header_off];
+}
+
+int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key)
+{
+ int off = br->header_off + 4, n;
+ struct string_view in = {
+ .buf = br->block.data + off,
+ .len = br->block_len - off,
+ };
+ uint8_t extra = 0;
+
+ reftable_buf_reset(key);
+
+ n = reftable_decode_key(key, &extra, in);
+ if (n < 0)
+ return n;
+ if (!key->len)
+ return REFTABLE_FORMAT_ERROR;
+
+ return 0;
+}
+
+static uint32_t block_reader_restart_offset(const struct block_reader *br, size_t idx)
{
- return get_be24(br->restart_bytes + 3 * i);
+ return get_be24(br->restart_bytes + 3 * idx);
}
-void block_reader_start(struct block_reader *br, struct block_iter *it)
+void block_iter_seek_start(struct block_iter *it, const struct block_reader *br)
{
- it->br = br;
- strbuf_reset(&it->last_key);
+ it->block = br->block.data;
+ it->block_len = br->block_len;
+ it->hash_size = br->hash_size;
+ reftable_buf_reset(&it->last_key);
it->next_off = br->header_off + 4;
}
-struct restart_find_args {
+struct restart_needle_less_args {
int error;
- struct strbuf key;
- struct block_reader *r;
+ struct reftable_buf needle;
+ const struct block_reader *reader;
};
-static int restart_key_less(size_t idx, void *args)
+static int restart_needle_less(size_t idx, void *_args)
{
- struct restart_find_args *a = args;
- uint32_t off = block_reader_restart_offset(a->r, idx);
+ struct restart_needle_less_args *args = _args;
+ uint32_t off = block_reader_restart_offset(args->reader, idx);
struct string_view in = {
- .buf = a->r->block.data + off,
- .len = a->r->block_len - off,
+ .buf = args->reader->block.data + off,
+ .len = args->reader->block_len - off,
};
-
- /* the restart key is verbatim in the block, so this could avoid the
- alloc for decoding the key */
- struct strbuf rkey = STRBUF_INIT;
- struct strbuf last_key = STRBUF_INIT;
- uint8_t unused_extra;
- int n = reftable_decode_key(&rkey, &unused_extra, last_key, in);
- int result;
- if (n < 0) {
- a->error = 1;
+ uint64_t prefix_len, suffix_len;
+ uint8_t extra;
+ int n;
+
+ /*
+ * Records at restart points are stored without prefix compression, so
+ * there is no need to fully decode the record key here. This removes
+ * the need for allocating memory.
+ */
+ n = reftable_decode_keylen(in, &prefix_len, &suffix_len, &extra);
+ if (n < 0 || prefix_len) {
+ args->error = 1;
return -1;
}
- result = strbuf_cmp(&a->key, &rkey);
- strbuf_release(&rkey);
- return result;
-}
+ string_view_consume(&in, n);
+ if (suffix_len > in.len) {
+ args->error = 1;
+ return -1;
+ }
-void block_iter_copy_from(struct block_iter *dest, struct block_iter *src)
-{
- dest->br = src->br;
- dest->next_off = src->next_off;
- strbuf_reset(&dest->last_key);
- strbuf_addbuf(&dest->last_key, &src->last_key);
+ n = memcmp(args->needle.buf, in.buf,
+ args->needle.len < suffix_len ? args->needle.len : suffix_len);
+ if (n)
+ return n < 0;
+ return args->needle.len < suffix_len;
}
int block_iter_next(struct block_iter *it, struct reftable_record *rec)
{
struct string_view in = {
- .buf = it->br->block.data + it->next_off,
- .len = it->br->block_len - it->next_off,
+ .buf = (unsigned char *) it->block + it->next_off,
+ .len = it->block_len - it->next_off,
};
struct string_view start = in;
- struct strbuf key = STRBUF_INIT;
uint8_t extra = 0;
int n = 0;
- if (it->next_off >= it->br->block_len)
+ if (it->next_off >= it->block_len)
return 1;
- n = reftable_decode_key(&key, &extra, it->last_key, in);
+ n = reftable_decode_key(&it->last_key, &extra, in);
if (n < 0)
return -1;
-
- if (!key.len)
+ if (!it->last_key.len)
return REFTABLE_FORMAT_ERROR;
string_view_consume(&in, n);
- n = reftable_record_decode(rec, key, extra, in, it->br->hash_size);
+ n = reftable_record_decode(rec, it->last_key, extra, in, it->hash_size,
+ &it->scratch);
if (n < 0)
return -1;
string_view_consume(&in, n);
- strbuf_reset(&it->last_key);
- strbuf_addbuf(&it->last_key, &key);
it->next_off += start.len - in.len;
- strbuf_release(&key);
- return 0;
-}
-
-int block_reader_first_key(struct block_reader *br, struct strbuf *key)
-{
- struct strbuf empty = STRBUF_INIT;
- int off = br->header_off + 4;
- struct string_view in = {
- .buf = br->block.data + off,
- .len = br->block_len - off,
- };
-
- uint8_t extra = 0;
- int n = reftable_decode_key(key, &extra, empty, in);
- if (n < 0)
- return n;
- if (!key->len)
- return REFTABLE_FORMAT_ERROR;
-
return 0;
}
-int block_iter_seek(struct block_iter *it, struct strbuf *want)
+void block_iter_reset(struct block_iter *it)
{
- return block_reader_seek(it->br, it, want);
+ reftable_buf_reset(&it->last_key);
+ it->next_off = 0;
+ it->block = NULL;
+ it->block_len = 0;
+ it->hash_size = 0;
}
void block_iter_close(struct block_iter *it)
{
- strbuf_release(&it->last_key);
+ reftable_buf_release(&it->last_key);
+ reftable_buf_release(&it->scratch);
}
-int block_reader_seek(struct block_reader *br, struct block_iter *it,
- struct strbuf *want)
+int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
+ struct reftable_buf *want)
{
- struct restart_find_args args = {
- .key = *want,
- .r = br,
+ struct restart_needle_less_args args = {
+ .needle = *want,
+ .reader = br,
};
- struct reftable_record rec = reftable_new_record(block_reader_type(br));
- struct strbuf key = STRBUF_INIT;
+ struct reftable_record rec;
int err = 0;
- struct block_iter next = {
- .last_key = STRBUF_INIT,
- };
-
- int i = binsearch(br->restart_count, &restart_key_less, &args);
+ size_t i;
+
+ /*
+ * Perform a binary search over the block's restart points, which
+ * avoids doing a linear scan over the whole block. Like this, we
+ * identify the section of the block that should contain our key.
+ *
+ * Note that we explicitly search for the first restart point _greater_
+ * than the sought-after record, not _greater or equal_ to it. In case
+ * the sought-after record is located directly at the restart point we
+ * would otherwise start doing the linear search at the preceding
+ * restart point. While that works alright, we would end up scanning
+ * too many record.
+ */
+ i = binsearch(br->restart_count, &restart_needle_less, &args);
if (args.error) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
- it->br = br;
- if (i > 0) {
- i--;
- it->next_off = block_reader_restart_offset(br, i);
- } else {
+ /*
+ * Now there are multiple cases:
+ *
+ * - `i == 0`: The wanted record is smaller than the record found at
+ * the first restart point. As the first restart point is the first
+ * record in the block, our wanted record cannot be located in this
+ * block at all. We still need to position the iterator so that the
+ * next call to `block_iter_next()` will yield an end-of-iterator
+ * signal.
+ *
+ * - `i == restart_count`: The wanted record was not found at any of
+ * the restart points. As there is no restart point at the end of
+ * the section the record may thus be contained in the last block.
+ *
+ * - `i > 0`: The wanted record must be contained in the section
+ * before the found restart point. We thus do a linear search
+ * starting from the preceding restart point.
+ */
+ if (i > 0)
+ it->next_off = block_reader_restart_offset(br, i - 1);
+ else
it->next_off = br->header_off + 4;
- }
-
- /* We're looking for the last entry less/equal than the wanted key, so
- we have to go one entry too far and then back up.
- */
+ it->block = br->block.data;
+ it->block_len = br->block_len;
+ it->hash_size = br->hash_size;
+
+ reftable_record_init(&rec, block_reader_type(br));
+
+ /*
+ * We're looking for the last entry less than the wanted key so that
+ * the next call to `block_reader_next()` would yield the wanted
+ * record. We thus don't want to position our reader at the sought
+ * after record, but one before. To do so, we have to go one entry too
+ * far and then back up.
+ */
while (1) {
- block_iter_copy_from(&next, it);
- err = block_iter_next(&next, &rec);
+ size_t prev_off = it->next_off;
+
+ err = block_iter_next(it, &rec);
if (err < 0)
goto done;
-
- reftable_record_key(&rec, &key);
- if (err > 0 || strbuf_cmp(&key, want) >= 0) {
+ if (err > 0) {
+ it->next_off = prev_off;
err = 0;
goto done;
}
- block_iter_copy_from(it, &next);
+ err = reftable_record_key(&rec, &it->last_key);
+ if (err < 0)
+ goto done;
+
+ /*
+ * Check whether the current key is greater or equal to the
+ * sought-after key. In case it is greater we know that the
+ * record does not exist in the block and can thus abort early.
+ * In case it is equal to the sought-after key we have found
+ * the desired record.
+ *
+ * Note that we store the next record's key record directly in
+ * `last_key` without restoring the key of the preceding record
+ * in case we need to go one record back. This is safe to do as
+ * `block_iter_next()` would return the ref whose key is equal
+ * to `last_key` now, and naturally all keys share a prefix
+ * with themselves.
+ */
+ if (reftable_buf_cmp(&it->last_key, want) >= 0) {
+ it->next_off = prev_off;
+ goto done;
+ }
}
done:
- strbuf_release(&key);
- strbuf_release(&next.last_key);
reftable_record_release(&rec);
-
return err;
}
void block_writer_release(struct block_writer *bw)
{
- FREE_AND_NULL(bw->restarts);
- strbuf_release(&bw->last_key);
+ deflateEnd(bw->zstream);
+ REFTABLE_FREE_AND_NULL(bw->zstream);
+ REFTABLE_FREE_AND_NULL(bw->restarts);
+ REFTABLE_FREE_AND_NULL(bw->compressed);
+ reftable_buf_release(&bw->scratch);
+ reftable_buf_release(&bw->last_key);
/* the block is not owned. */
}
diff --git a/reftable/block.h b/reftable/block.h
index 87c77539b5..0431e8591f 100644
--- a/reftable/block.h
+++ b/reftable/block.h
@@ -18,14 +18,18 @@ https://developers.google.com/open-source/licenses/bsd
* allocation overhead.
*/
struct block_writer {
- uint8_t *buf;
+ z_stream *zstream;
+ unsigned char *compressed;
+ size_t compressed_cap;
+
+ uint8_t *block;
uint32_t block_size;
/* Offset of the global header. Nonzero in the first block only. */
uint32_t header_off;
/* How often to restart keys. */
- int restart_interval;
+ uint16_t restart_interval;
int hash_size;
/* Offset of next uint8_t to write. */
@@ -34,15 +38,17 @@ struct block_writer {
uint32_t restart_len;
uint32_t restart_cap;
- struct strbuf last_key;
+ struct reftable_buf last_key;
+ /* Scratch buffer used to avoid allocations. */
+ struct reftable_buf scratch;
int entries;
};
/*
- * initializes the blockwriter to write `typ` entries, using `buf` as temporary
- * storage. `buf` is not owned by the block_writer. */
-void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
- uint32_t block_size, uint32_t header_off, int hash_size);
+ * initializes the blockwriter to write `typ` entries, using `block` as temporary
+ * storage. `block` is not owned by the block_writer. */
+int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *block,
+ uint32_t block_size, uint32_t header_off, int hash_size);
/* returns the block type (eg. 'r' for ref records. */
uint8_t block_writer_type(struct block_writer *bw);
@@ -56,6 +62,8 @@ int block_writer_finish(struct block_writer *w);
/* clears out internally allocated block_writer members. */
void block_writer_release(struct block_writer *bw);
+struct z_stream;
+
/* Read a block. */
struct block_reader {
/* offset of the block header; nonzero for the first block in a
@@ -66,6 +74,11 @@ struct block_reader {
struct reftable_block block;
int hash_size;
+ /* Uncompressed data for log entries. */
+ z_stream *zstream;
+ unsigned char *uncompressed_data;
+ size_t uncompressed_cap;
+
/* size of the data, excluding restart data. */
uint32_t block_len;
uint8_t *restart_bytes;
@@ -76,41 +89,49 @@ struct block_reader {
uint32_t full_block_size;
};
+/* initializes a block reader. */
+int block_reader_init(struct block_reader *br, struct reftable_block *bl,
+ uint32_t header_off, uint32_t table_block_size,
+ int hash_size);
+
+void block_reader_release(struct block_reader *br);
+
+/* Returns the block type (eg. 'r' for refs) */
+uint8_t block_reader_type(const struct block_reader *r);
+
+/* Decodes the first key in the block */
+int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key);
+
/* Iterate over entries in a block */
struct block_iter {
/* offset within the block of the next entry to read. */
uint32_t next_off;
- struct block_reader *br;
+ const unsigned char *block;
+ size_t block_len;
+ int hash_size;
/* key for last entry we read. */
- struct strbuf last_key;
+ struct reftable_buf last_key;
+ struct reftable_buf scratch;
};
-/* initializes a block reader. */
-int block_reader_init(struct block_reader *br, struct reftable_block *bl,
- uint32_t header_off, uint32_t table_block_size,
- int hash_size);
+#define BLOCK_ITER_INIT { \
+ .last_key = REFTABLE_BUF_INIT, \
+ .scratch = REFTABLE_BUF_INIT, \
+}
/* Position `it` at start of the block */
-void block_reader_start(struct block_reader *br, struct block_iter *it);
+void block_iter_seek_start(struct block_iter *it, const struct block_reader *br);
/* Position `it` to the `want` key in the block */
-int block_reader_seek(struct block_reader *br, struct block_iter *it,
- struct strbuf *want);
-
-/* Returns the block type (eg. 'r' for refs) */
-uint8_t block_reader_type(struct block_reader *r);
-
-/* Decodes the first key in the block */
-int block_reader_first_key(struct block_reader *br, struct strbuf *key);
-
-void block_iter_copy_from(struct block_iter *dest, struct block_iter *src);
+int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
+ struct reftable_buf *want);
/* return < 0 for error, 0 for OK, > 0 for EOF. */
int block_iter_next(struct block_iter *it, struct reftable_record *rec);
-/* Seek to `want` with in the block pointed to by `it` */
-int block_iter_seek(struct block_iter *it, struct strbuf *want);
+/* Reset the block iterator to pristine state without releasing its memory. */
+void block_iter_reset(struct block_iter *it);
/* deallocate memory for `it`. The block reader and its block is left intact. */
void block_iter_close(struct block_iter *it);
diff --git a/reftable/block_test.c b/reftable/block_test.c
deleted file mode 100644
index cb88af4a56..0000000000
--- a/reftable/block_test.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "block.h"
-
-#include "system.h"
-#include "blocksource.h"
-#include "basics.h"
-#include "constants.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-static void test_block_read_write(void)
-{
- const int header_off = 21; /* random */
- char *names[30];
- const int N = ARRAY_SIZE(names);
- const int block_size = 1024;
- struct reftable_block block = { NULL };
- struct block_writer bw = {
- .last_key = STRBUF_INIT,
- };
- struct reftable_record rec = {
- .type = BLOCK_TYPE_REF,
- };
- int i = 0;
- int n;
- struct block_reader br = { 0 };
- struct block_iter it = { .last_key = STRBUF_INIT };
- int j = 0;
- struct strbuf want = STRBUF_INIT;
-
- block.data = reftable_calloc(block_size);
- block.len = block_size;
- block.source = malloc_block_source();
- block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
- header_off, hash_size(GIT_SHA1_FORMAT_ID));
-
- rec.u.ref.refname = "";
- rec.u.ref.value_type = REFTABLE_REF_DELETION;
- n = block_writer_add(&bw, &rec);
- EXPECT(n == REFTABLE_API_ERROR);
-
- for (i = 0; i < N; i++) {
- char name[100];
- uint8_t hash[GIT_SHA1_RAWSZ];
- snprintf(name, sizeof(name), "branch%02d", i);
- memset(hash, i, sizeof(hash));
-
- rec.u.ref.refname = name;
- rec.u.ref.value_type = REFTABLE_REF_VAL1;
- rec.u.ref.value.val1 = hash;
-
- names[i] = xstrdup(name);
- n = block_writer_add(&bw, &rec);
- rec.u.ref.refname = NULL;
- rec.u.ref.value_type = REFTABLE_REF_DELETION;
- EXPECT(n == 0);
- }
-
- n = block_writer_finish(&bw);
- EXPECT(n > 0);
-
- block_writer_release(&bw);
-
- block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
-
- block_reader_start(&br, &it);
-
- while (1) {
- int r = block_iter_next(&it, &rec);
- EXPECT(r >= 0);
- if (r > 0) {
- break;
- }
- EXPECT_STREQ(names[j], rec.u.ref.refname);
- j++;
- }
-
- reftable_record_release(&rec);
- block_iter_close(&it);
-
- for (i = 0; i < N; i++) {
- struct block_iter it = { .last_key = STRBUF_INIT };
- strbuf_reset(&want);
- strbuf_addstr(&want, names[i]);
-
- n = block_reader_seek(&br, &it, &want);
- EXPECT(n == 0);
-
- n = block_iter_next(&it, &rec);
- EXPECT(n == 0);
-
- EXPECT_STREQ(names[i], rec.u.ref.refname);
-
- want.len--;
- n = block_reader_seek(&br, &it, &want);
- EXPECT(n == 0);
-
- n = block_iter_next(&it, &rec);
- EXPECT(n == 0);
- EXPECT_STREQ(names[10 * (i / 10)], rec.u.ref.refname);
-
- block_iter_close(&it);
- }
-
- reftable_record_release(&rec);
- reftable_block_done(&br.block);
- strbuf_release(&want);
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
-}
-
-int block_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_block_read_write);
- return 0;
-}
diff --git a/reftable/blocksource.c b/reftable/blocksource.c
index 8331b34e82..52e0915a67 100644
--- a/reftable/blocksource.c
+++ b/reftable/blocksource.c
@@ -13,71 +13,53 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-blocksource.h"
#include "reftable-error.h"
-static void strbuf_return_block(void *b, struct reftable_block *dest)
+static void reftable_buf_return_block(void *b UNUSED, struct reftable_block *dest)
{
if (dest->len)
memset(dest->data, 0xff, dest->len);
reftable_free(dest->data);
}
-static void strbuf_close(void *b)
+static void reftable_buf_close(void *b UNUSED)
{
}
-static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
- uint32_t size)
+static int reftable_buf_read_block(void *v, struct reftable_block *dest,
+ uint64_t off, uint32_t size)
{
- struct strbuf *b = v;
+ struct reftable_buf *b = v;
assert(off + size <= b->len);
- dest->data = reftable_calloc(size);
+ REFTABLE_CALLOC_ARRAY(dest->data, size);
+ if (!dest->data)
+ return -1;
memcpy(dest->data, b->buf + off, size);
dest->len = size;
return size;
}
-static uint64_t strbuf_size(void *b)
+static uint64_t reftable_buf_size(void *b)
{
- return ((struct strbuf *)b)->len;
+ return ((struct reftable_buf *)b)->len;
}
-static struct reftable_block_source_vtable strbuf_vtable = {
- .size = &strbuf_size,
- .read_block = &strbuf_read_block,
- .return_block = &strbuf_return_block,
- .close = &strbuf_close,
+static struct reftable_block_source_vtable reftable_buf_vtable = {
+ .size = &reftable_buf_size,
+ .read_block = &reftable_buf_read_block,
+ .return_block = &reftable_buf_return_block,
+ .close = &reftable_buf_close,
};
-void block_source_from_strbuf(struct reftable_block_source *bs,
- struct strbuf *buf)
+void block_source_from_buf(struct reftable_block_source *bs,
+ struct reftable_buf *buf)
{
assert(!bs->ops);
- bs->ops = &strbuf_vtable;
+ bs->ops = &reftable_buf_vtable;
bs->arg = buf;
}
-static void malloc_return_block(void *b, struct reftable_block *dest)
-{
- if (dest->len)
- memset(dest->data, 0xff, dest->len);
- reftable_free(dest->data);
-}
-
-static struct reftable_block_source_vtable malloc_vtable = {
- .return_block = &malloc_return_block,
-};
-
-static struct reftable_block_source malloc_block_source_instance = {
- .ops = &malloc_vtable,
-};
-
-struct reftable_block_source malloc_block_source(void)
-{
- return malloc_block_source_instance;
-}
-
struct file_block_source {
- int fd;
uint64_t size;
+ unsigned char *data;
};
static uint64_t file_size(void *b)
@@ -85,21 +67,14 @@ static uint64_t file_size(void *b)
return ((struct file_block_source *)b)->size;
}
-static void file_return_block(void *b, struct reftable_block *dest)
+static void file_return_block(void *b UNUSED, struct reftable_block *dest UNUSED)
{
- if (dest->len)
- memset(dest->data, 0xff, dest->len);
- reftable_free(dest->data);
}
-static void file_close(void *b)
+static void file_close(void *v)
{
- int fd = ((struct file_block_source *)b)->fd;
- if (fd > 0) {
- close(fd);
- ((struct file_block_source *)b)->fd = 0;
- }
-
+ struct file_block_source *b = v;
+ munmap(b->data, b->size);
reftable_free(b);
}
@@ -108,9 +83,7 @@ static int file_read_block(void *v, struct reftable_block *dest, uint64_t off,
{
struct file_block_source *b = v;
assert(off + size <= b->size);
- dest->data = reftable_malloc(size);
- if (pread(b->fd, dest->data, size, off) != size)
- return -1;
+ dest->data = b->data + off;
dest->len = size;
return size;
}
@@ -125,29 +98,42 @@ static struct reftable_block_source_vtable file_vtable = {
int reftable_block_source_from_file(struct reftable_block_source *bs,
const char *name)
{
- struct stat st = { 0 };
- int err = 0;
- int fd = open(name, O_RDONLY);
- struct file_block_source *p = NULL;
+ struct file_block_source *p;
+ struct stat st;
+ int fd, err;
+
+ fd = open(name, O_RDONLY);
if (fd < 0) {
- if (errno == ENOENT) {
+ if (errno == ENOENT)
return REFTABLE_NOT_EXIST_ERROR;
- }
- return -1;
+ err = -1;
+ goto out;
}
- err = fstat(fd, &st);
- if (err < 0) {
- close(fd);
- return REFTABLE_IO_ERROR;
+ if (fstat(fd, &st) < 0) {
+ err = REFTABLE_IO_ERROR;
+ goto out;
+ }
+
+ REFTABLE_CALLOC_ARRAY(p, 1);
+ if (!p) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
- p = reftable_calloc(sizeof(struct file_block_source));
p->size = st.st_size;
- p->fd = fd;
+ p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
assert(!bs->ops);
bs->ops = &file_vtable;
bs->arg = p;
+
+ err = 0;
+
+out:
+ if (fd >= 0)
+ close(fd);
+ if (err < 0)
+ reftable_free(p);
return 0;
}
diff --git a/reftable/blocksource.h b/reftable/blocksource.h
index 072e2727ad..a84a3ccd89 100644
--- a/reftable/blocksource.h
+++ b/reftable/blocksource.h
@@ -12,11 +12,10 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
struct reftable_block_source;
+struct reftable_buf;
/* Create an in-memory block source for reading reftables */
-void block_source_from_strbuf(struct reftable_block_source *bs,
- struct strbuf *buf);
-
-struct reftable_block_source malloc_block_source(void);
+void block_source_from_buf(struct reftable_block_source *bs,
+ struct reftable_buf *buf);
#endif
diff --git a/reftable/constants.h b/reftable/constants.h
index 5eee72c4c1..f6beb843eb 100644
--- a/reftable/constants.h
+++ b/reftable/constants.h
@@ -17,5 +17,6 @@ https://developers.google.com/open-source/licenses/bsd
#define MAX_RESTARTS ((1 << 16) - 1)
#define DEFAULT_BLOCK_SIZE 4096
+#define DEFAULT_GEOMETRIC_FACTOR 2
#endif
diff --git a/reftable/dump.c b/reftable/dump.c
deleted file mode 100644
index ce936b4e18..0000000000
--- a/reftable/dump.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "git-compat-util.h"
-#include "hash-ll.h"
-
-#include "reftable-blocksource.h"
-#include "reftable-error.h"
-#include "reftable-merged.h"
-#include "reftable-record.h"
-#include "reftable-tests.h"
-#include "reftable-writer.h"
-#include "reftable-iterator.h"
-#include "reftable-reader.h"
-#include "reftable-stack.h"
-#include "reftable-generic.h"
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-static int compact_stack(const char *stackdir)
-{
- struct reftable_stack *stack = NULL;
- struct reftable_write_options cfg = { 0 };
-
- int err = reftable_new_stack(&stack, stackdir, cfg);
- if (err < 0)
- goto done;
-
- err = reftable_stack_compact_all(stack, NULL);
- if (err < 0)
- goto done;
-done:
- if (stack) {
- reftable_stack_destroy(stack);
- }
- return err;
-}
-
-static void print_help(void)
-{
- printf("usage: dump [-cst] arg\n\n"
- "options: \n"
- " -c compact\n"
- " -t dump table\n"
- " -s dump stack\n"
- " -6 sha256 hash format\n"
- " -h this help\n"
- "\n");
-}
-
-int reftable_dump_main(int argc, char *const *argv)
-{
- int err = 0;
- int opt_dump_table = 0;
- int opt_dump_stack = 0;
- int opt_compact = 0;
- uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
- const char *arg = NULL, *argv0 = argv[0];
-
- for (; argc > 1; argv++, argc--)
- if (*argv[1] != '-')
- break;
- else if (!strcmp("-t", argv[1]))
- opt_dump_table = 1;
- else if (!strcmp("-6", argv[1]))
- opt_hash_id = GIT_SHA256_FORMAT_ID;
- else if (!strcmp("-s", argv[1]))
- opt_dump_stack = 1;
- else if (!strcmp("-c", argv[1]))
- opt_compact = 1;
- else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
- print_help();
- return 2;
- }
-
- if (argc != 2) {
- fprintf(stderr, "need argument\n");
- print_help();
- return 2;
- }
-
- arg = argv[1];
-
- if (opt_dump_table) {
- err = reftable_reader_print_file(arg);
- } else if (opt_dump_stack) {
- err = reftable_stack_print_directory(arg, opt_hash_id);
- } else if (opt_compact) {
- err = compact_stack(arg);
- }
-
- if (err < 0) {
- fprintf(stderr, "%s: %s: %s\n", argv0, arg,
- reftable_error_str(err));
- return 1;
- }
- return 0;
-}
diff --git a/reftable/error.c b/reftable/error.c
index 0d1766735e..660d029617 100644
--- a/reftable/error.c
+++ b/reftable/error.c
@@ -22,19 +22,21 @@ const char *reftable_error_str(int err)
case REFTABLE_NOT_EXIST_ERROR:
return "file does not exist";
case REFTABLE_LOCK_ERROR:
- return "data is outdated";
+ return "data is locked";
case REFTABLE_API_ERROR:
return "misuse of the reftable API";
case REFTABLE_ZLIB_ERROR:
return "zlib failure";
- case REFTABLE_NAME_CONFLICT:
- return "file/directory conflict";
case REFTABLE_EMPTY_TABLE_ERROR:
return "wrote empty table";
case REFTABLE_REFNAME_ERROR:
return "invalid refname";
case REFTABLE_ENTRY_TOO_BIG_ERROR:
return "entry too large";
+ case REFTABLE_OUTDATED_ERROR:
+ return "data concurrently modified";
+ case REFTABLE_OUT_OF_MEMORY_ERROR:
+ return "out of memory";
case -1:
return "general error";
default:
diff --git a/reftable/generic.c b/reftable/generic.c
deleted file mode 100644
index 57f8032db9..0000000000
--- a/reftable/generic.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "basics.h"
-#include "constants.h"
-#include "record.h"
-#include "generic.h"
-#include "reftable-iterator.h"
-#include "reftable-generic.h"
-
-int reftable_table_seek_ref(struct reftable_table *tab,
- struct reftable_iterator *it, const char *name)
-{
- struct reftable_record rec = { .type = BLOCK_TYPE_REF,
- .u.ref = {
- .refname = (char *)name,
- } };
- return tab->ops->seek_record(tab->table_arg, it, &rec);
-}
-
-int reftable_table_seek_log(struct reftable_table *tab,
- struct reftable_iterator *it, const char *name)
-{
- struct reftable_record rec = { .type = BLOCK_TYPE_LOG,
- .u.log = {
- .refname = (char *)name,
- .update_index = ~((uint64_t)0),
- } };
- return tab->ops->seek_record(tab->table_arg, it, &rec);
-}
-
-int reftable_table_read_ref(struct reftable_table *tab, const char *name,
- struct reftable_ref_record *ref)
-{
- struct reftable_iterator it = { NULL };
- int err = reftable_table_seek_ref(tab, &it, name);
- if (err)
- goto done;
-
- err = reftable_iterator_next_ref(&it, ref);
- if (err)
- goto done;
-
- if (strcmp(ref->refname, name) ||
- reftable_ref_record_is_deletion(ref)) {
- reftable_ref_record_release(ref);
- err = 1;
- goto done;
- }
-
-done:
- reftable_iterator_destroy(&it);
- return err;
-}
-
-int reftable_table_print(struct reftable_table *tab) {
- struct reftable_iterator it = { NULL };
- struct reftable_ref_record ref = { NULL };
- struct reftable_log_record log = { NULL };
- uint32_t hash_id = reftable_table_hash_id(tab);
- int err = reftable_table_seek_ref(tab, &it, "");
- if (err < 0) {
- return err;
- }
-
- while (1) {
- err = reftable_iterator_next_ref(&it, &ref);
- if (err > 0) {
- break;
- }
- if (err < 0) {
- return err;
- }
- reftable_ref_record_print(&ref, hash_id);
- }
- reftable_iterator_destroy(&it);
- reftable_ref_record_release(&ref);
-
- err = reftable_table_seek_log(tab, &it, "");
- if (err < 0) {
- return err;
- }
- while (1) {
- err = reftable_iterator_next_log(&it, &log);
- if (err > 0) {
- break;
- }
- if (err < 0) {
- return err;
- }
- reftable_log_record_print(&log, hash_id);
- }
- reftable_iterator_destroy(&it);
- reftable_log_record_release(&log);
- return 0;
-}
-
-uint64_t reftable_table_max_update_index(struct reftable_table *tab)
-{
- return tab->ops->max_update_index(tab->table_arg);
-}
-
-uint64_t reftable_table_min_update_index(struct reftable_table *tab)
-{
- return tab->ops->min_update_index(tab->table_arg);
-}
-
-uint32_t reftable_table_hash_id(struct reftable_table *tab)
-{
- return tab->ops->hash_id(tab->table_arg);
-}
-
-void reftable_iterator_destroy(struct reftable_iterator *it)
-{
- if (!it->ops) {
- return;
- }
- it->ops->close(it->iter_arg);
- it->ops = NULL;
- FREE_AND_NULL(it->iter_arg);
-}
-
-int reftable_iterator_next_ref(struct reftable_iterator *it,
- struct reftable_ref_record *ref)
-{
- struct reftable_record rec = {
- .type = BLOCK_TYPE_REF,
- .u = {
- .ref = *ref
- },
- };
- int err = iterator_next(it, &rec);
- *ref = rec.u.ref;
- return err;
-}
-
-int reftable_iterator_next_log(struct reftable_iterator *it,
- struct reftable_log_record *log)
-{
- struct reftable_record rec = {
- .type = BLOCK_TYPE_LOG,
- .u = {
- .log = *log,
- },
- };
- int err = iterator_next(it, &rec);
- *log = rec.u.log;
- return err;
-}
-
-int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
-{
- return it->ops->next(it->iter_arg, rec);
-}
-
-static int empty_iterator_next(void *arg, struct reftable_record *rec)
-{
- return 1;
-}
-
-static void empty_iterator_close(void *arg)
-{
-}
-
-static struct reftable_iterator_vtable empty_vtable = {
- .next = &empty_iterator_next,
- .close = &empty_iterator_close,
-};
-
-void iterator_set_empty(struct reftable_iterator *it)
-{
- assert(!it->ops);
- it->iter_arg = NULL;
- it->ops = &empty_vtable;
-}
diff --git a/reftable/generic.h b/reftable/generic.h
deleted file mode 100644
index 98886a0640..0000000000
--- a/reftable/generic.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef GENERIC_H
-#define GENERIC_H
-
-#include "record.h"
-#include "reftable-generic.h"
-
-/* generic interface to reftables */
-struct reftable_table_vtable {
- int (*seek_record)(void *tab, struct reftable_iterator *it,
- struct reftable_record *);
- uint32_t (*hash_id)(void *tab);
- uint64_t (*min_update_index)(void *tab);
- uint64_t (*max_update_index)(void *tab);
-};
-
-struct reftable_iterator_vtable {
- int (*next)(void *iter_arg, struct reftable_record *rec);
- void (*close)(void *iter_arg);
-};
-
-void iterator_set_empty(struct reftable_iterator *it);
-int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
-
-#endif
diff --git a/reftable/iter.c b/reftable/iter.c
index a8d174c040..86e801ca9f 100644
--- a/reftable/iter.c
+++ b/reftable/iter.c
@@ -11,23 +11,61 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
#include "block.h"
-#include "generic.h"
#include "constants.h"
#include "reader.h"
#include "reftable-error.h"
-int iterator_is_null(struct reftable_iterator *it)
+int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
{
- return !it->ops;
+ return it->ops->seek(it->iter_arg, want);
+}
+
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
+{
+ return it->ops->next(it->iter_arg, rec);
+}
+
+static int empty_iterator_seek(void *arg UNUSED, struct reftable_record *want UNUSED)
+{
+ return 0;
+}
+
+static int empty_iterator_next(void *arg UNUSED, struct reftable_record *rec UNUSED)
+{
+ return 1;
+}
+
+static void empty_iterator_close(void *arg UNUSED)
+{
+}
+
+static struct reftable_iterator_vtable empty_vtable = {
+ .seek = &empty_iterator_seek,
+ .next = &empty_iterator_next,
+ .close = &empty_iterator_close,
+};
+
+void iterator_set_empty(struct reftable_iterator *it)
+{
+ assert(!it->ops);
+ it->iter_arg = NULL;
+ it->ops = &empty_vtable;
}
static void filtering_ref_iterator_close(void *iter_arg)
{
struct filtering_ref_iterator *fri = iter_arg;
- strbuf_release(&fri->oid);
+ reftable_buf_release(&fri->oid);
reftable_iterator_destroy(&fri->it);
}
+static int filtering_ref_iterator_seek(void *iter_arg,
+ struct reftable_record *want)
+{
+ struct filtering_ref_iterator *fri = iter_arg;
+ return iterator_seek(&fri->it, want);
+}
+
static int filtering_ref_iterator_next(void *iter_arg,
struct reftable_record *rec)
{
@@ -40,26 +78,6 @@ static int filtering_ref_iterator_next(void *iter_arg,
break;
}
- if (fri->double_check) {
- struct reftable_iterator it = { NULL };
-
- err = reftable_table_seek_ref(&fri->tab, &it,
- ref->refname);
- if (err == 0) {
- err = reftable_iterator_next_ref(&it, ref);
- }
-
- reftable_iterator_destroy(&it);
-
- if (err < 0) {
- break;
- }
-
- if (err > 0) {
- continue;
- }
- }
-
if (ref->value_type == REFTABLE_REF_VAL2 &&
(!memcmp(fri->oid.buf, ref->value.val2.target_value,
fri->oid.len) ||
@@ -78,6 +96,7 @@ static int filtering_ref_iterator_next(void *iter_arg,
}
static struct reftable_iterator_vtable filtering_ref_iterator_vtable = {
+ .seek = &filtering_ref_iterator_seek,
.next = &filtering_ref_iterator_next,
.close = &filtering_ref_iterator_close,
};
@@ -96,7 +115,7 @@ static void indexed_table_ref_iter_close(void *p)
block_iter_close(&it->cur);
reftable_block_done(&it->block_reader.block);
reftable_free(it->offsets);
- strbuf_release(&it->oid);
+ reftable_buf_release(&it->oid);
}
static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
@@ -120,10 +139,17 @@ static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
/* indexed block does not exist. */
return REFTABLE_FORMAT_ERROR;
}
- block_reader_start(&it->block_reader, &it->cur);
+ block_iter_seek_start(&it->cur, &it->block_reader);
return 0;
}
+static int indexed_table_ref_iter_seek(void *p UNUSED,
+ struct reftable_record *want UNUSED)
+{
+ BUG("seeking indexed table is not supported");
+ return -1;
+}
+
static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
{
struct indexed_table_ref_iter *it = p;
@@ -155,32 +181,47 @@ static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
}
}
-int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
+int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len)
{
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
- struct indexed_table_ref_iter *itr =
- reftable_calloc(sizeof(struct indexed_table_ref_iter));
+ struct indexed_table_ref_iter *itr;
int err = 0;
+ itr = reftable_calloc(1, sizeof(*itr));
+ if (!itr) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
*itr = empty;
itr->r = r;
- strbuf_add(&itr->oid, oid, oid_len);
+
+ err = reftable_buf_add(&itr->oid, oid, oid_len);
+ if (err < 0)
+ goto out;
itr->offsets = offsets;
itr->offset_len = offset_len;
err = indexed_table_ref_iter_next_block(itr);
+ if (err < 0)
+ goto out;
+
+ *dest = itr;
+ err = 0;
+
+out:
if (err < 0) {
+ *dest = NULL;
reftable_free(itr);
- } else {
- *dest = itr;
}
return err;
}
static struct reftable_iterator_vtable indexed_table_ref_iter_vtable = {
+ .seek = &indexed_table_ref_iter_seek,
.next = &indexed_table_ref_iter_next,
.close = &indexed_table_ref_iter_close,
};
@@ -192,3 +233,71 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
it->iter_arg = itr;
it->ops = &indexed_table_ref_iter_vtable;
}
+
+void reftable_iterator_destroy(struct reftable_iterator *it)
+{
+ if (!it->ops)
+ return;
+ it->ops->close(it->iter_arg);
+ it->ops = NULL;
+ REFTABLE_FREE_AND_NULL(it->iter_arg);
+}
+
+int reftable_iterator_seek_ref(struct reftable_iterator *it,
+ const char *name)
+{
+ struct reftable_record want = {
+ .type = BLOCK_TYPE_REF,
+ .u.ref = {
+ .refname = (char *)name,
+ },
+ };
+ return it->ops->seek(it->iter_arg, &want);
+}
+
+int reftable_iterator_next_ref(struct reftable_iterator *it,
+ struct reftable_ref_record *ref)
+{
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_REF,
+ .u = {
+ .ref = *ref
+ },
+ };
+ int err = iterator_next(it, &rec);
+ *ref = rec.u.ref;
+ return err;
+}
+
+int reftable_iterator_seek_log_at(struct reftable_iterator *it,
+ const char *name, uint64_t update_index)
+{
+ struct reftable_record want = {
+ .type = BLOCK_TYPE_LOG,
+ .u.log = {
+ .refname = (char *)name,
+ .update_index = update_index,
+ },
+ };
+ return it->ops->seek(it->iter_arg, &want);
+}
+
+int reftable_iterator_seek_log(struct reftable_iterator *it,
+ const char *name)
+{
+ return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
+}
+
+int reftable_iterator_next_log(struct reftable_iterator *it,
+ struct reftable_log_record *log)
+{
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_LOG,
+ .u = {
+ .log = *log,
+ },
+ };
+ int err = iterator_next(it, &rec);
+ *log = rec.u.log;
+ return err;
+}
diff --git a/reftable/iter.h b/reftable/iter.h
index 09eb0cbfa5..40f98893b8 100644
--- a/reftable/iter.h
+++ b/reftable/iter.h
@@ -14,22 +14,42 @@ https://developers.google.com/open-source/licenses/bsd
#include "record.h"
#include "reftable-iterator.h"
-#include "reftable-generic.h"
-/* Returns true for a zeroed out iterator, such as the one returned from
- * iterator_destroy. */
-int iterator_is_null(struct reftable_iterator *it);
+/*
+ * The virtual function table for implementing generic reftable iterators.
+ */
+struct reftable_iterator_vtable {
+ int (*seek)(void *iter_arg, struct reftable_record *want);
+ int (*next)(void *iter_arg, struct reftable_record *rec);
+ void (*close)(void *iter_arg);
+};
+
+/*
+ * Position the iterator at the wanted record such that a call to
+ * `iterator_next()` would return that record, if it exists.
+ */
+int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
+
+/*
+ * Yield the next record and advance the iterator. Returns <0 on error, 0 when
+ * a record was yielded, and >0 when the iterator hit an error.
+ */
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
+
+/*
+ * Set up the iterator such that it behaves the same as an iterator with no
+ * entries.
+ */
+void iterator_set_empty(struct reftable_iterator *it);
/* iterator that produces only ref records that point to `oid` */
struct filtering_ref_iterator {
- int double_check;
- struct reftable_table tab;
- struct strbuf oid;
+ struct reftable_buf oid;
struct reftable_iterator it;
};
#define FILTERING_REF_ITERATOR_INIT \
{ \
- .oid = STRBUF_INIT \
+ .oid = REFTABLE_BUF_INIT \
}
void iterator_from_filtering_ref_iterator(struct reftable_iterator *,
@@ -40,7 +60,7 @@ void iterator_from_filtering_ref_iterator(struct reftable_iterator *,
*/
struct indexed_table_ref_iter {
struct reftable_reader *r;
- struct strbuf oid;
+ struct reftable_buf oid;
/* mutable */
uint64_t *offsets;
@@ -53,16 +73,16 @@ struct indexed_table_ref_iter {
int is_finished;
};
-#define INDEXED_TABLE_REF_ITER_INIT \
- { \
- .cur = { .last_key = STRBUF_INIT }, .oid = STRBUF_INIT, \
- }
+#define INDEXED_TABLE_REF_ITER_INIT { \
+ .cur = BLOCK_ITER_INIT, \
+ .oid = REFTABLE_BUF_INIT, \
+}
void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
struct indexed_table_ref_iter *itr);
/* Takes ownership of `offsets` */
-int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
+int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len);
diff --git a/reftable/merged.c b/reftable/merged.c
index 5ded470c08..514d6facf4 100644
--- a/reftable/merged.c
+++ b/reftable/merged.c
@@ -13,89 +13,112 @@ https://developers.google.com/open-source/licenses/bsd
#include "pq.h"
#include "reader.h"
#include "record.h"
-#include "generic.h"
#include "reftable-merged.h"
#include "reftable-error.h"
#include "system.h"
-static int merged_iter_init(struct merged_iter *mi)
-{
- int i = 0;
- for (i = 0; i < mi->stack_len; i++) {
- struct reftable_record rec = reftable_new_record(mi->typ);
- int err = iterator_next(&mi->stack[i], &rec);
- if (err < 0) {
- return err;
- }
-
- if (err > 0) {
- reftable_iterator_destroy(&mi->stack[i]);
- reftable_record_release(&rec);
- } else {
- struct pq_entry e = {
- .rec = rec,
- .index = i,
- };
- merged_iter_pqueue_add(&mi->pq, &e);
- }
- }
+struct merged_subiter {
+ struct reftable_iterator iter;
+ struct reftable_record rec;
+};
- return 0;
-}
+struct merged_iter {
+ struct merged_subiter *subiters;
+ struct merged_iter_pqueue pq;
+ size_t subiters_len;
+ int suppress_deletions;
+ ssize_t advance_index;
+};
static void merged_iter_close(void *p)
{
struct merged_iter *mi = p;
- int i = 0;
+
merged_iter_pqueue_release(&mi->pq);
- for (i = 0; i < mi->stack_len; i++) {
- reftable_iterator_destroy(&mi->stack[i]);
+ for (size_t i = 0; i < mi->subiters_len; i++) {
+ reftable_iterator_destroy(&mi->subiters[i].iter);
+ reftable_record_release(&mi->subiters[i].rec);
}
- reftable_free(mi->stack);
+ reftable_free(mi->subiters);
}
-static int merged_iter_advance_nonnull_subiter(struct merged_iter *mi,
- size_t idx)
+static int merged_iter_advance_subiter(struct merged_iter *mi, size_t idx)
{
struct pq_entry e = {
- .rec = reftable_new_record(mi->typ),
.index = idx,
+ .rec = &mi->subiters[idx].rec,
};
- int err = iterator_next(&mi->stack[idx], &e.rec);
- if (err < 0)
+ int err;
+
+ err = iterator_next(&mi->subiters[idx].iter, &mi->subiters[idx].rec);
+ if (err)
return err;
- if (err > 0) {
- reftable_iterator_destroy(&mi->stack[idx]);
- reftable_record_release(&e.rec);
- return 0;
- }
+ err = merged_iter_pqueue_add(&mi->pq, &e);
+ if (err)
+ return err;
- merged_iter_pqueue_add(&mi->pq, &e);
return 0;
}
-static int merged_iter_advance_subiter(struct merged_iter *mi, size_t idx)
+static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want)
{
- if (iterator_is_null(&mi->stack[idx]))
- return 0;
- return merged_iter_advance_nonnull_subiter(mi, idx);
+ int err;
+
+ mi->advance_index = -1;
+
+ for (size_t i = 0; i < mi->subiters_len; i++) {
+ err = iterator_seek(&mi->subiters[i].iter, want);
+ if (err < 0)
+ return err;
+ if (err > 0)
+ continue;
+
+ err = merged_iter_advance_subiter(mi, i);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
}
static int merged_iter_next_entry(struct merged_iter *mi,
struct reftable_record *rec)
{
- struct strbuf entry_key = STRBUF_INIT;
struct pq_entry entry = { 0 };
- int err = 0;
+ int err = 0, empty;
+
+ empty = merged_iter_pqueue_is_empty(mi->pq);
+
+ if (mi->advance_index >= 0) {
+ /*
+ * When there are no pqueue entries then we only have a single
+ * subiter left. There is no need to use the pqueue in that
+ * case anymore as we know that the subiter will return entries
+ * in the correct order already.
+ *
+ * While this may sound like a very specific edge case, it may
+ * happen more frequently than you think. Most repositories
+ * will end up having a single large base table that contains
+ * most of the refs. It's thus likely that we exhaust all
+ * subiters but the one from that base ref.
+ */
+ if (empty)
+ return iterator_next(&mi->subiters[mi->advance_index].iter,
+ rec);
+
+ err = merged_iter_advance_subiter(mi, mi->advance_index);
+ if (err < 0)
+ return err;
+ if (!err)
+ empty = 0;
+ mi->advance_index = -1;
+ }
- if (merged_iter_pqueue_is_empty(mi->pq))
+ if (empty)
return 1;
entry = merged_iter_pqueue_remove(&mi->pq);
- err = merged_iter_advance_subiter(mi, entry.index);
- if (err < 0)
- return err;
/*
One can also use reftable as datacenter-local storage, where the ref
@@ -105,58 +128,45 @@ static int merged_iter_next_entry(struct merged_iter *mi,
such a deployment, the loop below must be changed to collect all
entries for the same key, and return new the newest one.
*/
- reftable_record_key(&entry.rec, &entry_key);
while (!merged_iter_pqueue_is_empty(mi->pq)) {
struct pq_entry top = merged_iter_pqueue_top(mi->pq);
- struct strbuf k = STRBUF_INIT;
- int err = 0, cmp = 0;
-
- reftable_record_key(&top.rec, &k);
+ int cmp;
- cmp = strbuf_cmp(&k, &entry_key);
- strbuf_release(&k);
-
- if (cmp > 0) {
+ cmp = reftable_record_cmp(top.rec, entry.rec);
+ if (cmp > 0)
break;
- }
merged_iter_pqueue_remove(&mi->pq);
err = merged_iter_advance_subiter(mi, top.index);
- if (err < 0) {
+ if (err < 0)
return err;
- }
- reftable_record_release(&top.rec);
}
- reftable_record_copy_from(rec, &entry.rec, hash_size(mi->hash_id));
- reftable_record_release(&entry.rec);
- strbuf_release(&entry_key);
+ mi->advance_index = entry.index;
+ SWAP(*rec, *entry.rec);
return 0;
}
-static int merged_iter_next(struct merged_iter *mi, struct reftable_record *rec)
+static int merged_iter_seek_void(void *it, struct reftable_record *want)
{
- while (1) {
- int err = merged_iter_next_entry(mi, rec);
- if (err == 0 && mi->suppress_deletions &&
- reftable_record_is_deletion(rec)) {
- continue;
- }
-
- return err;
- }
+ return merged_iter_seek(it, want);
}
static int merged_iter_next_void(void *p, struct reftable_record *rec)
{
struct merged_iter *mi = p;
- if (merged_iter_pqueue_is_empty(mi->pq))
- return 1;
-
- return merged_iter_next(mi, rec);
+ while (1) {
+ int err = merged_iter_next_entry(mi, rec);
+ if (err)
+ return err;
+ if (mi->suppress_deletions && reftable_record_is_deletion(rec))
+ continue;
+ return 0;
+ }
}
static struct reftable_iterator_vtable merged_iter_vtable = {
+ .seek = merged_iter_seek_void,
.next = &merged_iter_next_void,
.close = &merged_iter_close,
};
@@ -169,19 +179,19 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
it->ops = &merged_iter_vtable;
}
-int reftable_new_merged_table(struct reftable_merged_table **dest,
- struct reftable_table *stack, int n,
+int reftable_merged_table_new(struct reftable_merged_table **dest,
+ struct reftable_reader **readers, size_t n,
uint32_t hash_id)
{
struct reftable_merged_table *m = NULL;
uint64_t last_max = 0;
uint64_t first_min = 0;
- int i = 0;
- for (i = 0; i < n; i++) {
- uint64_t min = reftable_table_min_update_index(&stack[i]);
- uint64_t max = reftable_table_max_update_index(&stack[i]);
- if (reftable_table_hash_id(&stack[i]) != hash_id) {
+ for (size_t i = 0; i < n; i++) {
+ uint64_t min = reftable_reader_min_update_index(readers[i]);
+ uint64_t max = reftable_reader_max_update_index(readers[i]);
+
+ if (reftable_reader_hash_id(readers[i]) != hash_id) {
return REFTABLE_FORMAT_ERROR;
}
if (i == 0 || min < first_min) {
@@ -192,9 +202,12 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
}
}
- m = reftable_calloc(sizeof(struct reftable_merged_table));
- m->stack = stack;
- m->stack_len = n;
+ REFTABLE_CALLOC_ARRAY(m, 1);
+ if (!m)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ m->readers = readers;
+ m->readers_len = n;
m->min = first_min;
m->max = last_max;
m->hash_id = hash_id;
@@ -202,19 +215,10 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
return 0;
}
-/* clears the list of subtable, without affecting the readers themselves. */
-void merged_table_release(struct reftable_merged_table *mt)
-{
- FREE_AND_NULL(mt->stack);
- mt->stack_len = 0;
-}
-
void reftable_merged_table_free(struct reftable_merged_table *mt)
{
- if (!mt) {
+ if (!mt)
return;
- }
- merged_table_release(mt);
reftable_free(mt);
}
@@ -230,132 +234,66 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt)
return mt->min;
}
-static int reftable_table_seek_record(struct reftable_table *tab,
- struct reftable_iterator *it,
- struct reftable_record *rec)
+int merged_table_init_iter(struct reftable_merged_table *mt,
+ struct reftable_iterator *it,
+ uint8_t typ)
{
- return tab->ops->seek_record(tab->table_arg, it, rec);
-}
-
-static int merged_table_seek_record(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- struct reftable_record *rec)
-{
- struct reftable_iterator *iters = reftable_calloc(
- sizeof(struct reftable_iterator) * mt->stack_len);
- struct merged_iter merged = {
- .stack = iters,
- .typ = reftable_record_type(rec),
- .hash_id = mt->hash_id,
- .suppress_deletions = mt->suppress_deletions,
- };
- int n = 0;
- int err = 0;
- int i = 0;
- for (i = 0; i < mt->stack_len && err == 0; i++) {
- int e = reftable_table_seek_record(&mt->stack[i], &iters[n],
- rec);
- if (e < 0) {
- err = e;
- }
- if (e == 0) {
- n++;
- }
+ struct merged_subiter *subiters;
+ struct merged_iter *mi = NULL;
+ int ret;
+
+ REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
+ if (!subiters) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
- if (err < 0) {
- int i = 0;
- for (i = 0; i < n; i++) {
- reftable_iterator_destroy(&iters[i]);
- }
- reftable_free(iters);
- return err;
+
+ for (size_t i = 0; i < mt->readers_len; i++) {
+ reftable_record_init(&subiters[i].rec, typ);
+ ret = reader_init_iter(mt->readers[i], &subiters[i].iter, typ);
+ if (ret < 0)
+ goto out;
}
- merged.stack_len = n;
- err = merged_iter_init(&merged);
- if (err < 0) {
- merged_iter_close(&merged);
- return err;
- } else {
- struct merged_iter *p =
- reftable_malloc(sizeof(struct merged_iter));
- *p = merged;
- iterator_from_merged_iter(it, p);
+ REFTABLE_CALLOC_ARRAY(mi, 1);
+ if (!mi) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+ mi->advance_index = -1;
+ mi->suppress_deletions = mt->suppress_deletions;
+ mi->subiters = subiters;
+ mi->subiters_len = mt->readers_len;
+
+ iterator_from_merged_iter(it, mi);
+ ret = 0;
+
+out:
+ if (ret < 0) {
+ for (size_t i = 0; subiters && i < mt->readers_len; i++) {
+ reftable_iterator_destroy(&subiters[i].iter);
+ reftable_record_release(&subiters[i].rec);
+ }
+ reftable_free(subiters);
+ reftable_free(mi);
}
- return 0;
-}
-int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- const char *name)
-{
- struct reftable_record rec = {
- .type = BLOCK_TYPE_REF,
- .u.ref = {
- .refname = (char *)name,
- },
- };
- return merged_table_seek_record(mt, it, &rec);
+ return ret;
}
-int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- const char *name, uint64_t update_index)
+int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it)
{
- struct reftable_record rec = { .type = BLOCK_TYPE_LOG,
- .u.log = {
- .refname = (char *)name,
- .update_index = update_index,
- } };
- return merged_table_seek_record(mt, it, &rec);
+ return merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
}
-int reftable_merged_table_seek_log(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- const char *name)
+int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it)
{
- uint64_t max = ~((uint64_t)0);
- return reftable_merged_table_seek_log_at(mt, it, name, max);
+ return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
}
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
{
return mt->hash_id;
}
-
-static int reftable_merged_table_seek_void(void *tab,
- struct reftable_iterator *it,
- struct reftable_record *rec)
-{
- return merged_table_seek_record(tab, it, rec);
-}
-
-static uint32_t reftable_merged_table_hash_id_void(void *tab)
-{
- return reftable_merged_table_hash_id(tab);
-}
-
-static uint64_t reftable_merged_table_min_update_index_void(void *tab)
-{
- return reftable_merged_table_min_update_index(tab);
-}
-
-static uint64_t reftable_merged_table_max_update_index_void(void *tab)
-{
- return reftable_merged_table_max_update_index(tab);
-}
-
-static struct reftable_table_vtable merged_table_vtable = {
- .seek_record = reftable_merged_table_seek_void,
- .hash_id = reftable_merged_table_hash_id_void,
- .min_update_index = reftable_merged_table_min_update_index_void,
- .max_update_index = reftable_merged_table_max_update_index_void,
-};
-
-void reftable_table_from_merged_table(struct reftable_table *tab,
- struct reftable_merged_table *merged)
-{
- assert(!tab->ops);
- tab->ops = &merged_table_vtable;
- tab->table_arg = merged;
-}
diff --git a/reftable/merged.h b/reftable/merged.h
index 7d9f95d27e..89bd0c4b35 100644
--- a/reftable/merged.h
+++ b/reftable/merged.h
@@ -9,11 +9,11 @@ https://developers.google.com/open-source/licenses/bsd
#ifndef MERGED_H
#define MERGED_H
-#include "pq.h"
+#include "system.h"
struct reftable_merged_table {
- struct reftable_table *stack;
- size_t stack_len;
+ struct reftable_reader **readers;
+ size_t readers_len;
uint32_t hash_id;
/* If unset, produce deletions. This is useful for compaction. For the
@@ -24,15 +24,10 @@ struct reftable_merged_table {
uint64_t max;
};
-struct merged_iter {
- struct reftable_iterator *stack;
- uint32_t hash_id;
- size_t stack_len;
- uint8_t typ;
- int suppress_deletions;
- struct merged_iter_pqueue pq;
-};
+struct reftable_iterator;
-void merged_table_release(struct reftable_merged_table *mt);
+int merged_table_init_iter(struct reftable_merged_table *mt,
+ struct reftable_iterator *it,
+ uint8_t typ);
#endif
diff --git a/reftable/merged_test.c b/reftable/merged_test.c
deleted file mode 100644
index d08c16abef..0000000000
--- a/reftable/merged_test.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "merged.h"
-
-#include "system.h"
-
-#include "basics.h"
-#include "blocksource.h"
-#include "constants.h"
-#include "reader.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-merged.h"
-#include "reftable-tests.h"
-#include "reftable-generic.h"
-#include "reftable-writer.h"
-
-static void write_test_table(struct strbuf *buf,
- struct reftable_ref_record refs[], int n)
-{
- uint64_t min = 0xffffffff;
- uint64_t max = 0;
- int i = 0;
- int err;
-
- struct reftable_write_options opts = {
- .block_size = 256,
- };
- struct reftable_writer *w = NULL;
- for (i = 0; i < n; i++) {
- uint64_t ui = refs[i].update_index;
- if (ui > max) {
- max = ui;
- }
- if (ui < min) {
- min = ui;
- }
- }
-
- w = reftable_new_writer(&strbuf_add_void, buf, &opts);
- reftable_writer_set_limits(w, min, max);
-
- for (i = 0; i < n; i++) {
- uint64_t before = refs[i].update_index;
- int n = reftable_writer_add_ref(w, &refs[i]);
- EXPECT(n == 0);
- EXPECT(before == refs[i].update_index);
- }
-
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
-
- reftable_writer_free(w);
-}
-
-static void write_test_log_table(struct strbuf *buf,
- struct reftable_log_record logs[], int n,
- uint64_t update_index)
-{
- int i = 0;
- int err;
-
- struct reftable_write_options opts = {
- .block_size = 256,
- .exact_log_message = 1,
- };
- struct reftable_writer *w = NULL;
- w = reftable_new_writer(&strbuf_add_void, buf, &opts);
- reftable_writer_set_limits(w, update_index, update_index);
-
- for (i = 0; i < n; i++) {
- int err = reftable_writer_add_log(w, &logs[i]);
- EXPECT_ERR(err);
- }
-
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
-
- reftable_writer_free(w);
-}
-
-static struct reftable_merged_table *
-merged_table_from_records(struct reftable_ref_record **refs,
- struct reftable_block_source **source,
- struct reftable_reader ***readers, int *sizes,
- struct strbuf *buf, int n)
-{
- int i = 0;
- struct reftable_merged_table *mt = NULL;
- int err;
- struct reftable_table *tabs =
- reftable_calloc(n * sizeof(struct reftable_table));
- *readers = reftable_calloc(n * sizeof(struct reftable_reader *));
- *source = reftable_calloc(n * sizeof(**source));
- for (i = 0; i < n; i++) {
- write_test_table(&buf[i], refs[i], sizes[i]);
- block_source_from_strbuf(&(*source)[i], &buf[i]);
-
- err = reftable_new_reader(&(*readers)[i], &(*source)[i],
- "name");
- EXPECT_ERR(err);
- reftable_table_from_reader(&tabs[i], (*readers)[i]);
- }
-
- err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
- EXPECT_ERR(err);
- return mt;
-}
-
-static void readers_destroy(struct reftable_reader **readers, size_t n)
-{
- int i = 0;
- for (; i < n; i++)
- reftable_reader_free(readers[i]);
- reftable_free(readers);
-}
-
-static void test_merged_between(void)
-{
- uint8_t hash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 0 };
-
- struct reftable_ref_record r1[] = { {
- .refname = "b",
- .update_index = 1,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash1,
- } };
- struct reftable_ref_record r2[] = { {
- .refname = "a",
- .update_index = 2,
- .value_type = REFTABLE_REF_DELETION,
- } };
-
- struct reftable_ref_record *refs[] = { r1, r2 };
- int sizes[] = { 1, 1 };
- struct strbuf bufs[2] = { STRBUF_INIT, STRBUF_INIT };
- struct reftable_block_source *bs = NULL;
- struct reftable_reader **readers = NULL;
- struct reftable_merged_table *mt =
- merged_table_from_records(refs, &bs, &readers, sizes, bufs, 2);
- int i;
- struct reftable_ref_record ref = { NULL };
- struct reftable_iterator it = { NULL };
- int err = reftable_merged_table_seek_ref(mt, &it, "a");
- EXPECT_ERR(err);
-
- err = reftable_iterator_next_ref(&it, &ref);
- EXPECT_ERR(err);
- EXPECT(ref.update_index == 2);
- reftable_ref_record_release(&ref);
- reftable_iterator_destroy(&it);
- readers_destroy(readers, 2);
- reftable_merged_table_free(mt);
- for (i = 0; i < ARRAY_SIZE(bufs); i++) {
- strbuf_release(&bufs[i]);
- }
- reftable_free(bs);
-}
-
-static void test_merged(void)
-{
- uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
- uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
- struct reftable_ref_record r1[] = {
- {
- .refname = "a",
- .update_index = 1,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash1,
- },
- {
- .refname = "b",
- .update_index = 1,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash1,
- },
- {
- .refname = "c",
- .update_index = 1,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash1,
- }
- };
- struct reftable_ref_record r2[] = { {
- .refname = "a",
- .update_index = 2,
- .value_type = REFTABLE_REF_DELETION,
- } };
- struct reftable_ref_record r3[] = {
- {
- .refname = "c",
- .update_index = 3,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash2,
- },
- {
- .refname = "d",
- .update_index = 3,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash1,
- },
- };
-
- struct reftable_ref_record *want[] = {
- &r2[0],
- &r1[1],
- &r3[0],
- &r3[1],
- };
-
- struct reftable_ref_record *refs[] = { r1, r2, r3 };
- int sizes[3] = { 3, 1, 2 };
- struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
- struct reftable_block_source *bs = NULL;
- struct reftable_reader **readers = NULL;
- struct reftable_merged_table *mt =
- merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
-
- struct reftable_iterator it = { NULL };
- int err = reftable_merged_table_seek_ref(mt, &it, "a");
- struct reftable_ref_record *out = NULL;
- size_t len = 0;
- size_t cap = 0;
- int i = 0;
-
- EXPECT_ERR(err);
- EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID);
- EXPECT(reftable_merged_table_min_update_index(mt) == 1);
-
- while (len < 100) { /* cap loops/recursion. */
- struct reftable_ref_record ref = { NULL };
- int err = reftable_iterator_next_ref(&it, &ref);
- if (err > 0) {
- break;
- }
- if (len == cap) {
- cap = 2 * cap + 1;
- out = reftable_realloc(
- out, sizeof(struct reftable_ref_record) * cap);
- }
- out[len++] = ref;
- }
- reftable_iterator_destroy(&it);
-
- EXPECT(ARRAY_SIZE(want) == len);
- for (i = 0; i < len; i++) {
- EXPECT(reftable_ref_record_equal(want[i], &out[i],
- GIT_SHA1_RAWSZ));
- }
- for (i = 0; i < len; i++) {
- reftable_ref_record_release(&out[i]);
- }
- reftable_free(out);
-
- for (i = 0; i < 3; i++) {
- strbuf_release(&bufs[i]);
- }
- readers_destroy(readers, 3);
- reftable_merged_table_free(mt);
- reftable_free(bs);
-}
-
-static struct reftable_merged_table *
-merged_table_from_log_records(struct reftable_log_record **logs,
- struct reftable_block_source **source,
- struct reftable_reader ***readers, int *sizes,
- struct strbuf *buf, int n)
-{
- int i = 0;
- struct reftable_merged_table *mt = NULL;
- int err;
- struct reftable_table *tabs =
- reftable_calloc(n * sizeof(struct reftable_table));
- *readers = reftable_calloc(n * sizeof(struct reftable_reader *));
- *source = reftable_calloc(n * sizeof(**source));
- for (i = 0; i < n; i++) {
- write_test_log_table(&buf[i], logs[i], sizes[i], i + 1);
- block_source_from_strbuf(&(*source)[i], &buf[i]);
-
- err = reftable_new_reader(&(*readers)[i], &(*source)[i],
- "name");
- EXPECT_ERR(err);
- reftable_table_from_reader(&tabs[i], (*readers)[i]);
- }
-
- err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
- EXPECT_ERR(err);
- return mt;
-}
-
-static void test_merged_logs(void)
-{
- uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
- uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
- uint8_t hash3[GIT_SHA1_RAWSZ] = { 3 };
- struct reftable_log_record r1[] = {
- {
- .refname = "a",
- .update_index = 2,
- .value_type = REFTABLE_LOG_UPDATE,
- .value.update = {
- .old_hash = hash2,
- /* deletion */
- .name = "jane doe",
- .email = "jane@invalid",
- .message = "message2",
- }
- },
- {
- .refname = "a",
- .update_index = 1,
- .value_type = REFTABLE_LOG_UPDATE,
- .value.update = {
- .old_hash = hash1,
- .new_hash = hash2,
- .name = "jane doe",
- .email = "jane@invalid",
- .message = "message1",
- }
- },
- };
- struct reftable_log_record r2[] = {
- {
- .refname = "a",
- .update_index = 3,
- .value_type = REFTABLE_LOG_UPDATE,
- .value.update = {
- .new_hash = hash3,
- .name = "jane doe",
- .email = "jane@invalid",
- .message = "message3",
- }
- },
- };
- struct reftable_log_record r3[] = {
- {
- .refname = "a",
- .update_index = 2,
- .value_type = REFTABLE_LOG_DELETION,
- },
- };
- struct reftable_log_record *want[] = {
- &r2[0],
- &r3[0],
- &r1[1],
- };
-
- struct reftable_log_record *logs[] = { r1, r2, r3 };
- int sizes[3] = { 2, 1, 1 };
- struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
- struct reftable_block_source *bs = NULL;
- struct reftable_reader **readers = NULL;
- struct reftable_merged_table *mt = merged_table_from_log_records(
- logs, &bs, &readers, sizes, bufs, 3);
-
- struct reftable_iterator it = { NULL };
- int err = reftable_merged_table_seek_log(mt, &it, "a");
- struct reftable_log_record *out = NULL;
- size_t len = 0;
- size_t cap = 0;
- int i = 0;
-
- EXPECT_ERR(err);
- EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID);
- EXPECT(reftable_merged_table_min_update_index(mt) == 1);
-
- while (len < 100) { /* cap loops/recursion. */
- struct reftable_log_record log = { NULL };
- int err = reftable_iterator_next_log(&it, &log);
- if (err > 0) {
- break;
- }
- if (len == cap) {
- cap = 2 * cap + 1;
- out = reftable_realloc(
- out, sizeof(struct reftable_log_record) * cap);
- }
- out[len++] = log;
- }
- reftable_iterator_destroy(&it);
-
- EXPECT(ARRAY_SIZE(want) == len);
- for (i = 0; i < len; i++) {
- EXPECT(reftable_log_record_equal(want[i], &out[i],
- GIT_SHA1_RAWSZ));
- }
-
- err = reftable_merged_table_seek_log_at(mt, &it, "a", 2);
- EXPECT_ERR(err);
- reftable_log_record_release(&out[0]);
- err = reftable_iterator_next_log(&it, &out[0]);
- EXPECT_ERR(err);
- EXPECT(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ));
- reftable_iterator_destroy(&it);
-
- for (i = 0; i < len; i++) {
- reftable_log_record_release(&out[i]);
- }
- reftable_free(out);
-
- for (i = 0; i < 3; i++) {
- strbuf_release(&bufs[i]);
- }
- readers_destroy(readers, 3);
- reftable_merged_table_free(mt);
- reftable_free(bs);
-}
-
-static void test_default_write_opts(void)
-{
- struct reftable_write_options opts = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
-
- struct reftable_ref_record rec = {
- .refname = "master",
- .update_index = 1,
- };
- int err;
- struct reftable_block_source source = { NULL };
- struct reftable_table *tab = reftable_calloc(sizeof(*tab) * 1);
- uint32_t hash_id;
- struct reftable_reader *rd = NULL;
- struct reftable_merged_table *merged = NULL;
-
- reftable_writer_set_limits(w, 1, 1);
-
- err = reftable_writer_add_ref(w, &rec);
- EXPECT_ERR(err);
-
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
- reftable_writer_free(w);
-
- block_source_from_strbuf(&source, &buf);
-
- err = reftable_new_reader(&rd, &source, "filename");
- EXPECT_ERR(err);
-
- hash_id = reftable_reader_hash_id(rd);
- EXPECT(hash_id == GIT_SHA1_FORMAT_ID);
-
- reftable_table_from_reader(&tab[0], rd);
- err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID);
- EXPECT_ERR(err);
-
- reftable_reader_free(rd);
- reftable_merged_table_free(merged);
- strbuf_release(&buf);
-}
-
-/* XXX test refs_for(oid) */
-
-int merged_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_merged_logs);
- RUN_TEST(test_merged_between);
- RUN_TEST(test_merged);
- RUN_TEST(test_default_write_opts);
- return 0;
-}
diff --git a/reftable/pq.c b/reftable/pq.c
index dcefeb793a..6ee1164dd3 100644
--- a/reftable/pq.c
+++ b/reftable/pq.c
@@ -8,62 +8,36 @@ https://developers.google.com/open-source/licenses/bsd
#include "pq.h"
+#include "reftable-error.h"
#include "reftable-record.h"
#include "system.h"
#include "basics.h"
int pq_less(struct pq_entry *a, struct pq_entry *b)
{
- struct strbuf ak = STRBUF_INIT;
- struct strbuf bk = STRBUF_INIT;
- int cmp = 0;
- reftable_record_key(&a->rec, &ak);
- reftable_record_key(&b->rec, &bk);
-
- cmp = strbuf_cmp(&ak, &bk);
-
- strbuf_release(&ak);
- strbuf_release(&bk);
-
+ int cmp = reftable_record_cmp(a->rec, b->rec);
if (cmp == 0)
return a->index > b->index;
-
return cmp < 0;
}
-struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq)
-{
- return pq.heap[0];
-}
-
-int merged_iter_pqueue_is_empty(struct merged_iter_pqueue pq)
-{
- return pq.len == 0;
-}
-
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
{
- int i = 0;
+ size_t i = 0;
struct pq_entry e = pq->heap[0];
pq->heap[0] = pq->heap[pq->len - 1];
pq->len--;
- i = 0;
while (i < pq->len) {
- int min = i;
- int j = 2 * i + 1;
- int k = 2 * i + 2;
- if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i])) {
+ size_t min = i;
+ size_t j = 2 * i + 1;
+ size_t k = 2 * i + 2;
+ if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i]))
min = j;
- }
- if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min])) {
+ if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min]))
min = k;
- }
-
- if (min == i) {
+ if (min == i)
break;
- }
-
SWAP(pq->heap[i], pq->heap[min]);
i = min;
}
@@ -71,36 +45,29 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
return e;
}
-void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
+int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
{
- int i = 0;
-
- if (pq->len == pq->cap) {
- pq->cap = 2 * pq->cap + 1;
- pq->heap = reftable_realloc(pq->heap,
- pq->cap * sizeof(struct pq_entry));
- }
+ size_t i = 0;
+ REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap);
+ if (!pq->heap)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
pq->heap[pq->len++] = *e;
+
i = pq->len - 1;
while (i > 0) {
- int j = (i - 1) / 2;
- if (pq_less(&pq->heap[j], &pq->heap[i])) {
+ size_t j = (i - 1) / 2;
+ if (pq_less(&pq->heap[j], &pq->heap[i]))
break;
- }
-
SWAP(pq->heap[j], pq->heap[i]);
-
i = j;
}
+
+ return 0;
}
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq)
{
- int i = 0;
- for (i = 0; i < pq->len; i++) {
- reftable_record_release(&pq->heap[i].rec);
- }
- FREE_AND_NULL(pq->heap);
- pq->len = pq->cap = 0;
+ REFTABLE_FREE_AND_NULL(pq->heap);
+ memset(pq, 0, sizeof(*pq));
}
diff --git a/reftable/pq.h b/reftable/pq.h
index e85bac9b52..83c062eeca 100644
--- a/reftable/pq.h
+++ b/reftable/pq.h
@@ -12,8 +12,8 @@ https://developers.google.com/open-source/licenses/bsd
#include "record.h"
struct pq_entry {
- int index;
- struct reftable_record rec;
+ size_t index;
+ struct reftable_record *rec;
};
struct merged_iter_pqueue {
@@ -22,12 +22,19 @@ struct merged_iter_pqueue {
size_t cap;
};
-struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq);
-int merged_iter_pqueue_is_empty(struct merged_iter_pqueue pq);
-void merged_iter_pqueue_check(struct merged_iter_pqueue pq);
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
-void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
+int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
int pq_less(struct pq_entry *a, struct pq_entry *b);
+static inline struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq)
+{
+ return pq.heap[0];
+}
+
+static inline int merged_iter_pqueue_is_empty(struct merged_iter_pqueue pq)
+{
+ return pq.len == 0;
+}
+
#endif
diff --git a/reftable/pq_test.c b/reftable/pq_test.c
deleted file mode 100644
index 011b5c7502..0000000000
--- a/reftable/pq_test.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-
-#include "basics.h"
-#include "constants.h"
-#include "pq.h"
-#include "record.h"
-#include "reftable-tests.h"
-#include "test_framework.h"
-
-void merged_iter_pqueue_check(struct merged_iter_pqueue pq)
-{
- int i;
- for (i = 1; i < pq.len; i++) {
- int parent = (i - 1) / 2;
-
- EXPECT(pq_less(&pq.heap[parent], &pq.heap[i]));
- }
-}
-
-static void test_pq(void)
-{
- char *names[54] = { NULL };
- int N = ARRAY_SIZE(names) - 1;
-
- struct merged_iter_pqueue pq = { NULL };
- char *last = NULL;
-
- int i = 0;
- for (i = 0; i < N; i++) {
- char name[100];
- snprintf(name, sizeof(name), "%02d", i);
- names[i] = xstrdup(name);
- }
-
- i = 1;
- do {
- struct pq_entry e = { .rec = { .type = BLOCK_TYPE_REF,
- .u.ref = {
- .refname = names[i],
- } } };
- merged_iter_pqueue_add(&pq, &e);
- merged_iter_pqueue_check(pq);
- i = (i * 7) % N;
- } while (i != 1);
-
- while (!merged_iter_pqueue_is_empty(pq)) {
- struct pq_entry e = merged_iter_pqueue_remove(&pq);
- struct reftable_record *rec = &e.rec;
- merged_iter_pqueue_check(pq);
-
- EXPECT(reftable_record_type(rec) == BLOCK_TYPE_REF);
- if (last) {
- EXPECT(strcmp(last, rec->u.ref.refname) < 0);
- }
- // this is names[i], so don't dealloc.
- last = rec->u.ref.refname;
- rec->u.ref.refname = NULL;
- reftable_record_release(rec);
- }
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
-
- merged_iter_pqueue_release(&pq);
-}
-
-int pq_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_pq);
- return 0;
-}
diff --git a/reftable/publicbasics.c b/reftable/publicbasics.c
deleted file mode 100644
index bcb82530d6..0000000000
--- a/reftable/publicbasics.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-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"
-
-static void *(*reftable_malloc_ptr)(size_t sz);
-static void *(*reftable_realloc_ptr)(void *, size_t);
-static void (*reftable_free_ptr)(void *);
-
-void *reftable_malloc(size_t sz)
-{
- if (reftable_malloc_ptr)
- return (*reftable_malloc_ptr)(sz);
- return malloc(sz);
-}
-
-void *reftable_realloc(void *p, size_t sz)
-{
- if (reftable_realloc_ptr)
- return (*reftable_realloc_ptr)(p, sz);
- return realloc(p, sz);
-}
-
-void reftable_free(void *p)
-{
- if (reftable_free_ptr)
- reftable_free_ptr(p);
- else
- free(p);
-}
-
-void *reftable_calloc(size_t sz)
-{
- void *p = reftable_malloc(sz);
- memset(p, 0, sz);
- return p;
-}
-
-void reftable_set_alloc(void *(*malloc)(size_t),
- void *(*realloc)(void *, size_t), void (*free)(void *))
-{
- reftable_malloc_ptr = malloc;
- reftable_realloc_ptr = realloc;
- reftable_free_ptr = free;
-}
-
-int hash_size(uint32_t id)
-{
- switch (id) {
- case 0:
- case GIT_SHA1_FORMAT_ID:
- return GIT_SHA1_RAWSZ;
- case GIT_SHA256_FORMAT_ID:
- return GIT_SHA256_RAWSZ;
- }
- abort();
-}
diff --git a/reftable/reader.c b/reftable/reader.c
index b4db23ce18..90dc950b57 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -11,12 +11,9 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"
#include "block.h"
#include "constants.h"
-#include "generic.h"
#include "iter.h"
#include "record.h"
#include "reftable-error.h"
-#include "reftable-generic.h"
-#include "tree.h"
uint64_t block_source_size(struct reftable_block_source *source)
{
@@ -165,78 +162,23 @@ done:
return err;
}
-int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
- const char *name)
-{
- struct reftable_block footer = { NULL };
- struct reftable_block header = { NULL };
- int err = 0;
- uint64_t file_size = block_source_size(source);
-
- /* Need +1 to read type of first block. */
- uint32_t read_size = header_size(2) + 1; /* read v2 because it's larger. */
- memset(r, 0, sizeof(struct reftable_reader));
-
- if (read_size > file_size) {
- err = REFTABLE_FORMAT_ERROR;
- goto done;
- }
-
- err = block_source_read_block(source, &header, 0, read_size);
- if (err != read_size) {
- err = REFTABLE_IO_ERROR;
- goto done;
- }
-
- if (memcmp(header.data, "REFT", 4)) {
- err = REFTABLE_FORMAT_ERROR;
- goto done;
- }
- r->version = header.data[4];
- if (r->version != 1 && r->version != 2) {
- err = REFTABLE_FORMAT_ERROR;
- goto done;
- }
-
- r->size = file_size - footer_size(r->version);
- r->source = *source;
- r->name = xstrdup(name);
- r->hash_id = 0;
-
- err = block_source_read_block(source, &footer, r->size,
- footer_size(r->version));
- if (err != footer_size(r->version)) {
- err = REFTABLE_IO_ERROR;
- goto done;
- }
-
- err = parse_footer(r, footer.data, header.data);
-done:
- reftable_block_done(&footer);
- reftable_block_done(&header);
- return err;
-}
-
struct table_iter {
struct reftable_reader *r;
uint8_t typ;
uint64_t block_off;
+ struct block_reader br;
struct block_iter bi;
int is_finished;
};
-#define TABLE_ITER_INIT \
- { \
- .bi = {.last_key = STRBUF_INIT } \
- }
-static void table_iter_copy_from(struct table_iter *dest,
- struct table_iter *src)
+static int table_iter_init(struct table_iter *ti, struct reftable_reader *r)
{
- dest->r = src->r;
- dest->typ = src->typ;
- dest->block_off = src->block_off;
- dest->is_finished = src->is_finished;
- block_iter_copy_from(&dest->bi, &src->bi);
+ struct block_iter bi = BLOCK_ITER_INIT;
+ memset(ti, 0, sizeof(*ti));
+ reftable_reader_incref(r);
+ ti->r = r;
+ ti->bi = bi;
+ return 0;
}
static int table_iter_next_in_block(struct table_iter *ti,
@@ -252,14 +194,8 @@ static int table_iter_next_in_block(struct table_iter *ti,
static void table_iter_block_done(struct table_iter *ti)
{
- if (!ti->bi.br) {
- return;
- }
- reftable_block_done(&ti->bi.br->block);
- FREE_AND_NULL(ti->bi.br);
-
- ti->bi.last_key.len = 0;
- ti->bi.next_off = 0;
+ block_reader_release(&ti->br);
+ block_iter_reset(&ti->bi);
}
static int32_t extract_block_size(uint8_t *data, uint8_t *typ, uint64_t off,
@@ -323,32 +259,28 @@ done:
return err;
}
-static int table_iter_next_block(struct table_iter *dest,
- struct table_iter *src)
+static void table_iter_close(struct table_iter *ti)
{
- uint64_t next_block_off = src->block_off + src->bi.br->full_block_size;
- struct block_reader br = { 0 };
- int err = 0;
+ table_iter_block_done(ti);
+ block_iter_close(&ti->bi);
+ reftable_reader_decref(ti->r);
+}
- dest->r = src->r;
- dest->typ = src->typ;
- dest->block_off = next_block_off;
+static int table_iter_next_block(struct table_iter *ti)
+{
+ uint64_t next_block_off = ti->block_off + ti->br.full_block_size;
+ int err;
- err = reader_init_block_reader(src->r, &br, next_block_off, src->typ);
- if (err > 0) {
- dest->is_finished = 1;
- return 1;
- }
- if (err != 0)
+ err = reader_init_block_reader(ti->r, &ti->br, next_block_off, ti->typ);
+ if (err > 0)
+ ti->is_finished = 1;
+ if (err)
return err;
- else {
- struct block_reader *brp =
- reftable_malloc(sizeof(struct block_reader));
- *brp = br;
- dest->is_finished = 0;
- block_reader_start(brp, &dest->bi);
- }
+ ti->block_off = next_block_off;
+ ti->is_finished = 0;
+ block_iter_seek_start(&ti->bi, &ti->br);
+
return 0;
}
@@ -358,79 +290,51 @@ static int table_iter_next(struct table_iter *ti, struct reftable_record *rec)
return REFTABLE_API_ERROR;
while (1) {
- struct table_iter next = TABLE_ITER_INIT;
- int err = 0;
- if (ti->is_finished) {
+ int err;
+
+ if (ti->is_finished)
return 1;
- }
+ /*
+ * Check whether the current block still has more records. If
+ * so, return it. If the iterator returns positive then the
+ * current block has been exhausted.
+ */
err = table_iter_next_in_block(ti, rec);
- if (err <= 0) {
+ if (err <= 0)
return err;
- }
- err = table_iter_next_block(&next, ti);
- if (err != 0) {
+ /*
+ * Otherwise, we need to continue to the next block in the
+ * table and retry. If there are no more blocks then the
+ * iterator is drained.
+ */
+ err = table_iter_next_block(ti);
+ if (err) {
ti->is_finished = 1;
- }
- table_iter_block_done(ti);
- if (err != 0) {
return err;
}
- table_iter_copy_from(ti, &next);
- block_iter_close(&next.bi);
}
}
-static int table_iter_next_void(void *ti, struct reftable_record *rec)
-{
- return table_iter_next(ti, rec);
-}
-
-static void table_iter_close(void *p)
+static int table_iter_seek_to(struct table_iter *ti, uint64_t off, uint8_t typ)
{
- struct table_iter *ti = p;
- table_iter_block_done(ti);
- block_iter_close(&ti->bi);
-}
-
-static struct reftable_iterator_vtable table_iter_vtable = {
- .next = &table_iter_next_void,
- .close = &table_iter_close,
-};
-
-static void iterator_from_table_iter(struct reftable_iterator *it,
- struct table_iter *ti)
-{
- assert(!it->ops);
- it->iter_arg = ti;
- it->ops = &table_iter_vtable;
-}
-
-static int reader_table_iter_at(struct reftable_reader *r,
- struct table_iter *ti, uint64_t off,
- uint8_t typ)
-{
- struct block_reader br = { 0 };
- struct block_reader *brp = NULL;
+ int err;
- int err = reader_init_block_reader(r, &br, off, typ);
+ err = reader_init_block_reader(ti->r, &ti->br, off, typ);
if (err != 0)
return err;
- brp = reftable_malloc(sizeof(struct block_reader));
- *brp = br;
- ti->r = r;
- ti->typ = block_reader_type(brp);
+ ti->typ = block_reader_type(&ti->br);
ti->block_off = off;
- block_reader_start(brp, &ti->bi);
+ block_iter_seek_start(&ti->bi, &ti->br);
+ ti->is_finished = 0;
return 0;
}
-static int reader_start(struct reftable_reader *r, struct table_iter *ti,
- uint8_t typ, int index)
+static int table_iter_seek_start(struct table_iter *ti, uint8_t typ, int index)
{
- struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
+ struct reftable_reader_offsets *offs = reader_offsets_for(ti->r, typ);
uint64_t off = offs->offset;
if (index) {
off = offs->index_offset;
@@ -440,220 +344,345 @@ static int reader_start(struct reftable_reader *r, struct table_iter *ti,
typ = BLOCK_TYPE_INDEX;
}
- return reader_table_iter_at(r, ti, off, typ);
+ return table_iter_seek_to(ti, off, typ);
}
-static int reader_seek_linear(struct table_iter *ti,
- struct reftable_record *want)
+static int table_iter_seek_linear(struct table_iter *ti,
+ struct reftable_record *want)
{
- struct reftable_record rec =
- reftable_new_record(reftable_record_type(want));
- struct strbuf want_key = STRBUF_INIT;
- struct strbuf got_key = STRBUF_INIT;
- struct table_iter next = TABLE_ITER_INIT;
- int err = -1;
+ struct reftable_buf want_key = REFTABLE_BUF_INIT;
+ struct reftable_buf got_key = REFTABLE_BUF_INIT;
+ struct reftable_record rec;
+ int err;
- reftable_record_key(want, &want_key);
+ reftable_record_init(&rec, reftable_record_type(want));
+ err = reftable_record_key(want, &want_key);
+ if (err < 0)
+ goto done;
+ /*
+ * First we need to locate the block that must contain our record. To
+ * do so we scan through blocks linearly until we find the first block
+ * whose first key is bigger than our wanted key. Once we have found
+ * that block we know that the key must be contained in the preceding
+ * block.
+ *
+ * This algorithm is somewhat unfortunate because it means that we
+ * always have to seek one block too far and then back up. But as we
+ * can only decode the _first_ key of a block but not its _last_ key we
+ * have no other way to do this.
+ */
while (1) {
- err = table_iter_next_block(&next, ti);
+ struct table_iter next = *ti;
+
+ /*
+ * We must be careful to not modify underlying data of `ti`
+ * because we may find that `next` does not contain our desired
+ * block, but that `ti` does. In that case, we would discard
+ * `next` and continue with `ti`.
+ *
+ * This also means that we cannot reuse allocated memory for
+ * `next` here. While it would be great if we could, it should
+ * in practice not be too bad given that we should only ever
+ * end up doing linear seeks with at most three blocks. As soon
+ * as we have more than three blocks we would have an index, so
+ * we would not do a linear search there anymore.
+ */
+ memset(&next.br.block, 0, sizeof(next.br.block));
+ next.br.zstream = NULL;
+ next.br.uncompressed_data = NULL;
+ next.br.uncompressed_cap = 0;
+
+ err = table_iter_next_block(&next);
if (err < 0)
goto done;
-
- if (err > 0) {
+ if (err > 0)
break;
- }
- err = block_reader_first_key(next.bi.br, &got_key);
+ err = block_reader_first_key(&next.br, &got_key);
if (err < 0)
goto done;
- if (strbuf_cmp(&got_key, &want_key) > 0) {
+ if (reftable_buf_cmp(&got_key, &want_key) > 0) {
table_iter_block_done(&next);
break;
}
table_iter_block_done(ti);
- table_iter_copy_from(ti, &next);
+ *ti = next;
}
- err = block_iter_seek(&ti->bi, &want_key);
+ /*
+ * We have located the block that must contain our record, so we seek
+ * the wanted key inside of it. If the block does not contain our key
+ * we know that the corresponding record does not exist.
+ */
+ err = block_iter_seek_key(&ti->bi, &ti->br, &want_key);
if (err < 0)
goto done;
err = 0;
done:
- block_iter_close(&next.bi);
reftable_record_release(&rec);
- strbuf_release(&want_key);
- strbuf_release(&got_key);
+ reftable_buf_release(&want_key);
+ reftable_buf_release(&got_key);
return err;
}
-static int reader_seek_indexed(struct reftable_reader *r,
- struct reftable_iterator *it,
- struct reftable_record *rec)
+static int table_iter_seek_indexed(struct table_iter *ti,
+ struct reftable_record *rec)
{
struct reftable_record want_index = {
- .type = BLOCK_TYPE_INDEX, .u.idx = { .last_key = STRBUF_INIT }
+ .type = BLOCK_TYPE_INDEX, .u.idx = { .last_key = REFTABLE_BUF_INIT }
};
struct reftable_record index_result = {
.type = BLOCK_TYPE_INDEX,
- .u.idx = { .last_key = STRBUF_INIT },
+ .u.idx = { .last_key = REFTABLE_BUF_INIT },
};
- struct table_iter index_iter = TABLE_ITER_INIT;
- struct table_iter next = TABLE_ITER_INIT;
- int err = 0;
+ int err;
+
+ err = reftable_record_key(rec, &want_index.u.idx.last_key);
+ if (err < 0)
+ goto done;
- reftable_record_key(rec, &want_index.u.idx.last_key);
- err = reader_start(r, &index_iter, reftable_record_type(rec), 1);
+ /*
+ * The index may consist of multiple levels, where each level may have
+ * multiple index blocks. We start by doing a linear search in the
+ * highest layer that identifies the relevant index block as well as
+ * the record inside that block that corresponds to our wanted key.
+ */
+ err = table_iter_seek_linear(ti, &want_index);
if (err < 0)
goto done;
- err = reader_seek_linear(&index_iter, &want_index);
+ /*
+ * Traverse down the levels until we find a non-index entry.
+ */
while (1) {
- err = table_iter_next(&index_iter, &index_result);
- table_iter_block_done(&index_iter);
+ /*
+ * In case we seek a record that does not exist the index iter
+ * will tell us that the iterator is over. This works because
+ * the last index entry of the current level will contain the
+ * last key it knows about. So in case our seeked key is larger
+ * than the last indexed key we know that it won't exist.
+ *
+ * There is one subtlety in the layout of the index section
+ * that makes this work as expected: the highest-level index is
+ * at end of the section and will point backwards and thus we
+ * start reading from the end of the index section, not the
+ * beginning.
+ *
+ * If that wasn't the case and the order was reversed then the
+ * linear seek would seek into the lower levels and traverse
+ * all levels of the index only to find out that the key does
+ * not exist.
+ */
+ err = table_iter_next(ti, &index_result);
if (err != 0)
goto done;
- err = reader_table_iter_at(r, &next, index_result.u.idx.offset,
- 0);
+ err = table_iter_seek_to(ti, index_result.u.idx.offset, 0);
if (err != 0)
goto done;
- err = block_iter_seek(&next.bi, &want_index.u.idx.last_key);
+ err = block_iter_seek_key(&ti->bi, &ti->br, &want_index.u.idx.last_key);
if (err < 0)
goto done;
- if (next.typ == reftable_record_type(rec)) {
+ if (ti->typ == reftable_record_type(rec)) {
err = 0;
break;
}
- if (next.typ != BLOCK_TYPE_INDEX) {
+ if (ti->typ != BLOCK_TYPE_INDEX) {
err = REFTABLE_FORMAT_ERROR;
- break;
+ goto done;
}
-
- table_iter_copy_from(&index_iter, &next);
}
- if (err == 0) {
- struct table_iter empty = TABLE_ITER_INIT;
- struct table_iter *malloced =
- reftable_calloc(sizeof(struct table_iter));
- *malloced = empty;
- table_iter_copy_from(malloced, &next);
- iterator_from_table_iter(it, malloced);
- }
done:
- block_iter_close(&next.bi);
- table_iter_close(&index_iter);
reftable_record_release(&want_index);
reftable_record_release(&index_result);
return err;
}
-static int reader_seek_internal(struct reftable_reader *r,
- struct reftable_iterator *it,
- struct reftable_record *rec)
+static int table_iter_seek(struct table_iter *ti,
+ struct reftable_record *want)
{
- struct reftable_reader_offsets *offs =
- reader_offsets_for(r, reftable_record_type(rec));
- uint64_t idx = offs->index_offset;
- struct table_iter ti = TABLE_ITER_INIT;
- int err = 0;
- if (idx > 0)
- return reader_seek_indexed(r, it, rec);
+ uint8_t typ = reftable_record_type(want);
+ struct reftable_reader_offsets *offs = reader_offsets_for(ti->r, typ);
+ int err;
- err = reader_start(r, &ti, reftable_record_type(rec), 0);
- if (err < 0)
- return err;
- err = reader_seek_linear(&ti, rec);
+ err = table_iter_seek_start(ti, reftable_record_type(want),
+ !!offs->index_offset);
if (err < 0)
- return err;
- else {
- struct table_iter *p =
- reftable_malloc(sizeof(struct table_iter));
- *p = ti;
- iterator_from_table_iter(it, p);
- }
+ goto out;
- return 0;
+ if (offs->index_offset)
+ err = table_iter_seek_indexed(ti, want);
+ else
+ err = table_iter_seek_linear(ti, want);
+ if (err)
+ goto out;
+
+out:
+ return err;
}
-static int reader_seek(struct reftable_reader *r, struct reftable_iterator *it,
- struct reftable_record *rec)
+static int table_iter_seek_void(void *ti, struct reftable_record *want)
{
- uint8_t typ = reftable_record_type(rec);
+ return table_iter_seek(ti, want);
+}
- struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
- if (!offs->is_present) {
- iterator_set_empty(it);
- return 0;
- }
+static int table_iter_next_void(void *ti, struct reftable_record *rec)
+{
+ return table_iter_next(ti, rec);
+}
- return reader_seek_internal(r, it, rec);
+static void table_iter_close_void(void *ti)
+{
+ table_iter_close(ti);
}
-int reftable_reader_seek_ref(struct reftable_reader *r,
- struct reftable_iterator *it, const char *name)
+static struct reftable_iterator_vtable table_iter_vtable = {
+ .seek = &table_iter_seek_void,
+ .next = &table_iter_next_void,
+ .close = &table_iter_close_void,
+};
+
+static void iterator_from_table_iter(struct reftable_iterator *it,
+ struct table_iter *ti)
{
- struct reftable_record rec = {
- .type = BLOCK_TYPE_REF,
- .u.ref = {
- .refname = (char *)name,
- },
- };
- return reader_seek(r, it, &rec);
+ assert(!it->ops);
+ it->iter_arg = ti;
+ it->ops = &table_iter_vtable;
}
-int reftable_reader_seek_log_at(struct reftable_reader *r,
- struct reftable_iterator *it, const char *name,
- uint64_t update_index)
+int reader_init_iter(struct reftable_reader *r,
+ struct reftable_iterator *it,
+ uint8_t typ)
{
- struct reftable_record rec = { .type = BLOCK_TYPE_LOG,
- .u.log = {
- .refname = (char *)name,
- .update_index = update_index,
- } };
- return reader_seek(r, it, &rec);
+ struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
+
+ if (offs->is_present) {
+ struct table_iter *ti;
+ REFTABLE_ALLOC_ARRAY(ti, 1);
+ if (!ti)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ table_iter_init(ti, r);
+ iterator_from_table_iter(it, ti);
+ } else {
+ iterator_set_empty(it);
+ }
+
+ return 0;
}
-int reftable_reader_seek_log(struct reftable_reader *r,
- struct reftable_iterator *it, const char *name)
+int reftable_reader_init_ref_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it)
{
- uint64_t max = ~((uint64_t)0);
- return reftable_reader_seek_log_at(r, it, name, max);
+ return reader_init_iter(r, it, BLOCK_TYPE_REF);
}
-void reader_close(struct reftable_reader *r)
+int reftable_reader_init_log_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it)
{
- block_source_close(&r->source);
- FREE_AND_NULL(r->name);
+ return reader_init_iter(r, it, BLOCK_TYPE_LOG);
}
-int reftable_new_reader(struct reftable_reader **p,
- struct reftable_block_source *src, char const *name)
+int reftable_reader_new(struct reftable_reader **out,
+ struct reftable_block_source *source, char const *name)
{
- struct reftable_reader *rd =
- reftable_calloc(sizeof(struct reftable_reader));
- int err = init_reader(rd, src, name);
- if (err == 0) {
- *p = rd;
- } else {
- block_source_close(src);
- reftable_free(rd);
+ struct reftable_block footer = { 0 };
+ struct reftable_block header = { 0 };
+ struct reftable_reader *r;
+ uint64_t file_size = block_source_size(source);
+ uint32_t read_size;
+ int err;
+
+ REFTABLE_CALLOC_ARRAY(r, 1);
+ if (!r) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ /*
+ * We need one extra byte to read the type of first block. We also
+ * pretend to always be reading v2 of the format because it is larger.
+ */
+ read_size = header_size(2) + 1;
+ if (read_size > file_size) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
+
+ err = block_source_read_block(source, &header, 0, read_size);
+ if (err != read_size) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
+ if (memcmp(header.data, "REFT", 4)) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
+ r->version = header.data[4];
+ if (r->version != 1 && r->version != 2) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
+
+ r->size = file_size - footer_size(r->version);
+ r->source = *source;
+ r->name = reftable_strdup(name);
+ if (!r->name) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+ r->hash_id = 0;
+ r->refcount = 1;
+
+ err = block_source_read_block(source, &footer, r->size,
+ footer_size(r->version));
+ if (err != footer_size(r->version)) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
+ err = parse_footer(r, footer.data, header.data);
+ if (err)
+ goto done;
+
+ *out = r;
+
+done:
+ reftable_block_done(&footer);
+ reftable_block_done(&header);
+ if (err) {
+ reftable_free(r);
+ block_source_close(source);
}
return err;
}
-void reftable_reader_free(struct reftable_reader *r)
+void reftable_reader_incref(struct reftable_reader *r)
+{
+ if (!r->refcount)
+ BUG("cannot increment ref counter of dead reader");
+ r->refcount++;
+}
+
+void reftable_reader_decref(struct reftable_reader *r)
{
if (!r)
return;
- reader_close(r);
+ if (!r->refcount)
+ BUG("cannot decrement ref counter of dead reader");
+ if (--r->refcount)
+ return;
+ block_source_close(&r->source);
+ REFTABLE_FREE_AND_NULL(r->name);
reftable_free(r);
}
@@ -677,7 +706,11 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
struct indexed_table_ref_iter *itr = NULL;
/* Look through the reverse index. */
- err = reader_seek(r, &oit, &want);
+ err = reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
+ if (err < 0)
+ goto done;
+
+ err = iterator_seek(&oit, &want);
if (err != 0)
goto done;
@@ -694,7 +727,7 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
goto done;
}
- err = new_indexed_table_ref_iter(&itr, r, oid, hash_size(r->hash_id),
+ err = indexed_table_ref_iter_new(&itr, r, oid, hash_size(r->hash_id),
got.u.obj.offsets,
got.u.obj.offset_len);
if (err < 0)
@@ -712,30 +745,47 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t *oid)
{
- struct table_iter ti_empty = TABLE_ITER_INIT;
- struct table_iter *ti = reftable_calloc(sizeof(struct table_iter));
+ struct table_iter *ti;
struct filtering_ref_iterator *filter = NULL;
struct filtering_ref_iterator empty = FILTERING_REF_ITERATOR_INIT;
int oid_len = hash_size(r->hash_id);
int err;
- *ti = ti_empty;
- err = reader_start(r, ti, BLOCK_TYPE_REF, 0);
- if (err < 0) {
- reftable_free(ti);
- return err;
+ REFTABLE_ALLOC_ARRAY(ti, 1);
+ if (!ti) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
- filter = reftable_malloc(sizeof(struct filtering_ref_iterator));
+ table_iter_init(ti, r);
+ err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
+ if (err < 0)
+ goto out;
+
+ filter = reftable_malloc(sizeof(*filter));
+ if (!filter) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
*filter = empty;
- strbuf_add(&filter->oid, oid, oid_len);
- reftable_table_from_reader(&filter->tab, r);
- filter->double_check = 0;
+ err = reftable_buf_add(&filter->oid, oid, oid_len);
+ if (err < 0)
+ goto out;
+
iterator_from_table_iter(&filter->it, ti);
iterator_from_filtering_ref_iterator(it, filter);
- return 0;
+
+ err = 0;
+
+out:
+ if (err < 0) {
+ if (ti)
+ table_iter_close(ti);
+ reftable_free(ti);
+ }
+ return err;
}
int reftable_reader_refs_for(struct reftable_reader *r,
@@ -756,61 +806,67 @@ uint64_t reftable_reader_min_update_index(struct reftable_reader *r)
return r->min_update_index;
}
-/* generic table interface. */
-
-static int reftable_reader_seek_void(void *tab, struct reftable_iterator *it,
- struct reftable_record *rec)
+int reftable_reader_print_blocks(const char *tablename)
{
- return reader_seek(tab, it, rec);
-}
+ struct {
+ const char *name;
+ int type;
+ } sections[] = {
+ {
+ .name = "ref",
+ .type = BLOCK_TYPE_REF,
+ },
+ {
+ .name = "obj",
+ .type = BLOCK_TYPE_OBJ,
+ },
+ {
+ .name = "log",
+ .type = BLOCK_TYPE_LOG,
+ },
+ };
+ struct reftable_block_source src = { 0 };
+ struct reftable_reader *r = NULL;
+ struct table_iter ti = { 0 };
+ size_t i;
+ int err;
-static uint32_t reftable_reader_hash_id_void(void *tab)
-{
- return reftable_reader_hash_id(tab);
-}
+ err = reftable_block_source_from_file(&src, tablename);
+ if (err < 0)
+ goto done;
-static uint64_t reftable_reader_min_update_index_void(void *tab)
-{
- return reftable_reader_min_update_index(tab);
-}
+ err = reftable_reader_new(&r, &src, tablename);
+ if (err < 0)
+ goto done;
-static uint64_t reftable_reader_max_update_index_void(void *tab)
-{
- return reftable_reader_max_update_index(tab);
-}
+ table_iter_init(&ti, r);
-static struct reftable_table_vtable reader_vtable = {
- .seek_record = reftable_reader_seek_void,
- .hash_id = reftable_reader_hash_id_void,
- .min_update_index = reftable_reader_min_update_index_void,
- .max_update_index = reftable_reader_max_update_index_void,
-};
+ printf("header:\n");
+ printf(" block_size: %d\n", r->block_size);
-void reftable_table_from_reader(struct reftable_table *tab,
- struct reftable_reader *reader)
-{
- assert(!tab->ops);
- tab->ops = &reader_vtable;
- tab->table_arg = reader;
-}
+ for (i = 0; i < ARRAY_SIZE(sections); i++) {
+ err = table_iter_seek_start(&ti, sections[i].type, 0);
+ if (err < 0)
+ goto done;
+ if (err > 0)
+ continue;
+ printf("%s:\n", sections[i].name);
-int reftable_reader_print_file(const char *tablename)
-{
- struct reftable_block_source src = { NULL };
- int err = reftable_block_source_from_file(&src, tablename);
- struct reftable_reader *r = NULL;
- struct reftable_table tab = { NULL };
- if (err < 0)
- goto done;
+ while (1) {
+ printf(" - length: %u\n", ti.br.block_len);
+ printf(" restarts: %u\n", ti.br.restart_count);
- err = reftable_new_reader(&r, &src, tablename);
- if (err < 0)
- goto done;
+ err = table_iter_next_block(&ti);
+ if (err < 0)
+ goto done;
+ if (err > 0)
+ break;
+ }
+ }
- reftable_table_from_reader(&tab, r);
- err = reftable_table_print(&tab);
done:
- reftable_reader_free(r);
+ reftable_reader_decref(r);
+ table_iter_close(&ti);
return err;
}
diff --git a/reftable/reader.h b/reftable/reader.h
index e869165f23..010fbfe851 100644
--- a/reftable/reader.h
+++ b/reftable/reader.h
@@ -30,7 +30,7 @@ struct reftable_reader_offsets {
/* The state for reading a reftable file. */
struct reftable_reader {
- /* for convience, associate a name with the instance. */
+ /* for convenience, associate a name with the instance. */
char *name;
struct reftable_block_source source;
@@ -50,13 +50,16 @@ struct reftable_reader {
struct reftable_reader_offsets ref_offsets;
struct reftable_reader_offsets obj_offsets;
struct reftable_reader_offsets log_offsets;
+
+ uint64_t refcount;
};
-int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
- const char *name);
-void reader_close(struct reftable_reader *r);
const char *reader_name(struct reftable_reader *r);
+int reader_init_iter(struct reftable_reader *r,
+ struct reftable_iterator *it,
+ uint8_t typ);
+
/* initialize a block reader to read from `r` */
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
uint64_t next_off, uint8_t want_typ);
diff --git a/reftable/readwrite_test.c b/reftable/readwrite_test.c
deleted file mode 100644
index 469ab79a5a..0000000000
--- a/reftable/readwrite_test.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-
-#include "basics.h"
-#include "block.h"
-#include "blocksource.h"
-#include "constants.h"
-#include "reader.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-#include "reftable-writer.h"
-
-static const int update_index = 5;
-
-static void test_buffer(void)
-{
- struct strbuf buf = STRBUF_INIT;
- struct reftable_block_source source = { NULL };
- struct reftable_block out = { NULL };
- int n;
- uint8_t in[] = "hello";
- strbuf_add(&buf, in, sizeof(in));
- block_source_from_strbuf(&source, &buf);
- EXPECT(block_source_size(&source) == 6);
- n = block_source_read_block(&source, &out, 0, sizeof(in));
- EXPECT(n == sizeof(in));
- EXPECT(!memcmp(in, out.data, n));
- reftable_block_done(&out);
-
- n = block_source_read_block(&source, &out, 1, 2);
- EXPECT(n == 2);
- EXPECT(!memcmp(out.data, "el", 2));
-
- reftable_block_done(&out);
- block_source_close(&source);
- strbuf_release(&buf);
-}
-
-static void write_table(char ***names, struct strbuf *buf, int N,
- int block_size, uint32_t hash_id)
-{
- struct reftable_write_options opts = {
- .block_size = block_size,
- .hash_id = hash_id,
- };
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, buf, &opts);
- struct reftable_ref_record ref = { NULL };
- int i = 0, n;
- struct reftable_log_record log = { NULL };
- const struct reftable_stats *stats = NULL;
- *names = reftable_calloc(sizeof(char *) * (N + 1));
- reftable_writer_set_limits(w, update_index, update_index);
- for (i = 0; i < N; i++) {
- uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
- char name[100];
- int n;
-
- set_test_hash(hash, i);
-
- snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
-
- ref.refname = name;
- ref.update_index = update_index;
- ref.value_type = REFTABLE_REF_VAL1;
- ref.value.val1 = hash;
- (*names)[i] = xstrdup(name);
-
- n = reftable_writer_add_ref(w, &ref);
- EXPECT(n == 0);
- }
-
- for (i = 0; i < N; i++) {
- uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
- char name[100];
- int n;
-
- set_test_hash(hash, i);
-
- snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
-
- log.refname = name;
- log.update_index = update_index;
- log.value_type = REFTABLE_LOG_UPDATE;
- log.value.update.new_hash = hash;
- log.value.update.message = "message";
-
- n = reftable_writer_add_log(w, &log);
- EXPECT(n == 0);
- }
-
- n = reftable_writer_close(w);
- EXPECT(n == 0);
-
- stats = reftable_writer_stats(w);
- for (i = 0; i < stats->ref_stats.blocks; i++) {
- int off = i * opts.block_size;
- if (off == 0) {
- off = header_size(
- (hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1);
- }
- EXPECT(buf->buf[off] == 'r');
- }
-
- EXPECT(stats->log_stats.blocks > 0);
- reftable_writer_free(w);
-}
-
-static void test_log_buffer_size(void)
-{
- struct strbuf buf = STRBUF_INIT;
- struct reftable_write_options opts = {
- .block_size = 4096,
- };
- int err;
- int i;
- struct reftable_log_record
- log = { .refname = "refs/heads/master",
- .update_index = 0xa,
- .value_type = REFTABLE_LOG_UPDATE,
- .value = { .update = {
- .name = "Han-Wen Nienhuys",
- .email = "hanwen@google.com",
- .tz_offset = 100,
- .time = 0x5e430672,
- .message = "commit: 9\n",
- } } };
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
-
- /* This tests buffer extension for log compression. Must use a random
- hash, to ensure that the compressed part is larger than the original.
- */
- uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
- for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
- hash1[i] = (uint8_t)(rand() % 256);
- hash2[i] = (uint8_t)(rand() % 256);
- }
- log.value.update.old_hash = hash1;
- log.value.update.new_hash = hash2;
- reftable_writer_set_limits(w, update_index, update_index);
- err = reftable_writer_add_log(w, &log);
- EXPECT_ERR(err);
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
- reftable_writer_free(w);
- strbuf_release(&buf);
-}
-
-static void test_log_overflow(void)
-{
- struct strbuf buf = STRBUF_INIT;
- char msg[256] = { 0 };
- struct reftable_write_options opts = {
- .block_size = ARRAY_SIZE(msg),
- };
- int err;
- struct reftable_log_record
- log = { .refname = "refs/heads/master",
- .update_index = 0xa,
- .value_type = REFTABLE_LOG_UPDATE,
- .value = { .update = {
- .name = "Han-Wen Nienhuys",
- .email = "hanwen@google.com",
- .tz_offset = 100,
- .time = 0x5e430672,
- .message = msg,
- } } };
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
-
- uint8_t hash1[GIT_SHA1_RAWSZ] = {1}, hash2[GIT_SHA1_RAWSZ] = { 2 };
-
- memset(msg, 'x', sizeof(msg) - 1);
- log.value.update.old_hash = hash1;
- log.value.update.new_hash = hash2;
- reftable_writer_set_limits(w, update_index, update_index);
- err = reftable_writer_add_log(w, &log);
- EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
- reftable_writer_free(w);
- strbuf_release(&buf);
-}
-
-static void test_log_write_read(void)
-{
- int N = 2;
- char **names = reftable_calloc(sizeof(char *) * (N + 1));
- int err;
- struct reftable_write_options opts = {
- .block_size = 256,
- };
- struct reftable_ref_record ref = { NULL };
- int i = 0;
- struct reftable_log_record log = { NULL };
- int n;
- struct reftable_iterator it = { NULL };
- struct reftable_reader rd = { NULL };
- struct reftable_block_source source = { NULL };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- const struct reftable_stats *stats = NULL;
- reftable_writer_set_limits(w, 0, N);
- for (i = 0; i < N; i++) {
- char name[256];
- struct reftable_ref_record ref = { NULL };
- snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
- names[i] = xstrdup(name);
- ref.refname = name;
- ref.update_index = i;
-
- err = reftable_writer_add_ref(w, &ref);
- EXPECT_ERR(err);
- }
- for (i = 0; i < N; i++) {
- uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
- struct reftable_log_record log = { NULL };
- set_test_hash(hash1, i);
- set_test_hash(hash2, i + 1);
-
- log.refname = names[i];
- log.update_index = i;
- log.value_type = REFTABLE_LOG_UPDATE;
- log.value.update.old_hash = hash1;
- log.value.update.new_hash = hash2;
-
- err = reftable_writer_add_log(w, &log);
- EXPECT_ERR(err);
- }
-
- n = reftable_writer_close(w);
- EXPECT(n == 0);
-
- stats = reftable_writer_stats(w);
- EXPECT(stats->log_stats.blocks > 0);
- reftable_writer_free(w);
- w = NULL;
-
- block_source_from_strbuf(&source, &buf);
-
- err = init_reader(&rd, &source, "file.log");
- EXPECT_ERR(err);
-
- err = reftable_reader_seek_ref(&rd, &it, names[N - 1]);
- EXPECT_ERR(err);
-
- err = reftable_iterator_next_ref(&it, &ref);
- EXPECT_ERR(err);
-
- /* end of iteration. */
- err = reftable_iterator_next_ref(&it, &ref);
- EXPECT(0 < err);
-
- reftable_iterator_destroy(&it);
- reftable_ref_record_release(&ref);
-
- err = reftable_reader_seek_log(&rd, &it, "");
- EXPECT_ERR(err);
-
- i = 0;
- while (1) {
- int err = reftable_iterator_next_log(&it, &log);
- if (err > 0) {
- break;
- }
-
- EXPECT_ERR(err);
- EXPECT_STREQ(names[i], log.refname);
- EXPECT(i == log.update_index);
- i++;
- reftable_log_record_release(&log);
- }
-
- EXPECT(i == N);
- reftable_iterator_destroy(&it);
-
- /* cleanup. */
- strbuf_release(&buf);
- free_names(names);
- reader_close(&rd);
-}
-
-static void test_log_zlib_corruption(void)
-{
- struct reftable_write_options opts = {
- .block_size = 256,
- };
- struct reftable_iterator it = { 0 };
- struct reftable_reader rd = { 0 };
- struct reftable_block_source source = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- const struct reftable_stats *stats = NULL;
- uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
- uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
- char message[100] = { 0 };
- int err, i, n;
-
- struct reftable_log_record log = {
- .refname = "refname",
- .value_type = REFTABLE_LOG_UPDATE,
- .value = {
- .update = {
- .new_hash = hash1,
- .old_hash = hash2,
- .name = "My Name",
- .email = "myname@invalid",
- .message = message,
- },
- },
- };
-
- for (i = 0; i < sizeof(message) - 1; i++)
- message[i] = (uint8_t)(rand() % 64 + ' ');
-
- reftable_writer_set_limits(w, 1, 1);
-
- err = reftable_writer_add_log(w, &log);
- EXPECT_ERR(err);
-
- n = reftable_writer_close(w);
- EXPECT(n == 0);
-
- stats = reftable_writer_stats(w);
- EXPECT(stats->log_stats.blocks > 0);
- reftable_writer_free(w);
- w = NULL;
-
- /* corrupt the data. */
- buf.buf[50] ^= 0x99;
-
- block_source_from_strbuf(&source, &buf);
-
- err = init_reader(&rd, &source, "file.log");
- EXPECT_ERR(err);
-
- err = reftable_reader_seek_log(&rd, &it, "refname");
- EXPECT(err == REFTABLE_ZLIB_ERROR);
-
- reftable_iterator_destroy(&it);
-
- /* cleanup. */
- strbuf_release(&buf);
- reader_close(&rd);
-}
-
-static void test_table_read_write_sequential(void)
-{
- char **names;
- struct strbuf buf = STRBUF_INIT;
- int N = 50;
- struct reftable_iterator it = { NULL };
- struct reftable_block_source source = { NULL };
- struct reftable_reader rd = { NULL };
- int err = 0;
- int j = 0;
-
- write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
-
- block_source_from_strbuf(&source, &buf);
-
- err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
-
- err = reftable_reader_seek_ref(&rd, &it, "");
- EXPECT_ERR(err);
-
- while (1) {
- struct reftable_ref_record ref = { NULL };
- int r = reftable_iterator_next_ref(&it, &ref);
- EXPECT(r >= 0);
- if (r > 0) {
- break;
- }
- EXPECT(0 == strcmp(names[j], ref.refname));
- EXPECT(update_index == ref.update_index);
-
- j++;
- reftable_ref_record_release(&ref);
- }
- EXPECT(j == N);
- reftable_iterator_destroy(&it);
- strbuf_release(&buf);
- free_names(names);
-
- reader_close(&rd);
-}
-
-static void test_table_write_small_table(void)
-{
- char **names;
- struct strbuf buf = STRBUF_INIT;
- int N = 1;
- write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
- EXPECT(buf.len < 200);
- strbuf_release(&buf);
- free_names(names);
-}
-
-static void test_table_read_api(void)
-{
- char **names;
- struct strbuf buf = STRBUF_INIT;
- int N = 50;
- struct reftable_reader rd = { NULL };
- struct reftable_block_source source = { NULL };
- int err;
- int i;
- struct reftable_log_record log = { NULL };
- struct reftable_iterator it = { NULL };
-
- write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
-
- block_source_from_strbuf(&source, &buf);
-
- err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
-
- err = reftable_reader_seek_ref(&rd, &it, names[0]);
- EXPECT_ERR(err);
-
- err = reftable_iterator_next_log(&it, &log);
- EXPECT(err == REFTABLE_API_ERROR);
-
- strbuf_release(&buf);
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
- reftable_iterator_destroy(&it);
- reftable_free(names);
- reader_close(&rd);
- strbuf_release(&buf);
-}
-
-static void test_table_read_write_seek(int index, int hash_id)
-{
- char **names;
- struct strbuf buf = STRBUF_INIT;
- int N = 50;
- struct reftable_reader rd = { NULL };
- struct reftable_block_source source = { NULL };
- int err;
- int i = 0;
-
- struct reftable_iterator it = { NULL };
- struct strbuf pastLast = STRBUF_INIT;
- struct reftable_ref_record ref = { NULL };
-
- write_table(&names, &buf, N, 256, hash_id);
-
- block_source_from_strbuf(&source, &buf);
-
- err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
- EXPECT(hash_id == reftable_reader_hash_id(&rd));
-
- if (!index) {
- rd.ref_offsets.index_offset = 0;
- } else {
- EXPECT(rd.ref_offsets.index_offset > 0);
- }
-
- for (i = 1; i < N; i++) {
- int err = reftable_reader_seek_ref(&rd, &it, names[i]);
- EXPECT_ERR(err);
- err = reftable_iterator_next_ref(&it, &ref);
- EXPECT_ERR(err);
- EXPECT(0 == strcmp(names[i], ref.refname));
- EXPECT(REFTABLE_REF_VAL1 == ref.value_type);
- EXPECT(i == ref.value.val1[0]);
-
- reftable_ref_record_release(&ref);
- reftable_iterator_destroy(&it);
- }
-
- strbuf_addstr(&pastLast, names[N - 1]);
- strbuf_addstr(&pastLast, "/");
-
- err = reftable_reader_seek_ref(&rd, &it, pastLast.buf);
- if (err == 0) {
- struct reftable_ref_record ref = { NULL };
- int err = reftable_iterator_next_ref(&it, &ref);
- EXPECT(err > 0);
- } else {
- EXPECT(err > 0);
- }
-
- strbuf_release(&pastLast);
- reftable_iterator_destroy(&it);
-
- strbuf_release(&buf);
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
- reftable_free(names);
- reader_close(&rd);
-}
-
-static void test_table_read_write_seek_linear(void)
-{
- test_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
-}
-
-static void test_table_read_write_seek_linear_sha256(void)
-{
- test_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
-}
-
-static void test_table_read_write_seek_index(void)
-{
- test_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
-}
-
-static void test_table_refs_for(int indexed)
-{
- int N = 50;
- char **want_names = reftable_calloc(sizeof(char *) * (N + 1));
- int want_names_len = 0;
- uint8_t want_hash[GIT_SHA1_RAWSZ];
-
- struct reftable_write_options opts = {
- .block_size = 256,
- };
- struct reftable_ref_record ref = { NULL };
- int i = 0;
- int n;
- int err;
- struct reftable_reader rd;
- struct reftable_block_source source = { NULL };
-
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
-
- struct reftable_iterator it = { NULL };
- int j;
-
- set_test_hash(want_hash, 4);
-
- for (i = 0; i < N; i++) {
- uint8_t hash[GIT_SHA1_RAWSZ];
- char fill[51] = { 0 };
- char name[100];
- uint8_t hash1[GIT_SHA1_RAWSZ];
- uint8_t hash2[GIT_SHA1_RAWSZ];
- struct reftable_ref_record ref = { NULL };
-
- memset(hash, i, sizeof(hash));
- memset(fill, 'x', 50);
- /* Put the variable part in the start */
- snprintf(name, sizeof(name), "br%02d%s", i, fill);
- name[40] = 0;
- ref.refname = name;
-
- set_test_hash(hash1, i / 4);
- set_test_hash(hash2, 3 + i / 4);
- ref.value_type = REFTABLE_REF_VAL2;
- ref.value.val2.value = hash1;
- ref.value.val2.target_value = hash2;
-
- /* 80 bytes / entry, so 3 entries per block. Yields 17
- */
- /* blocks. */
- n = reftable_writer_add_ref(w, &ref);
- EXPECT(n == 0);
-
- if (!memcmp(hash1, want_hash, GIT_SHA1_RAWSZ) ||
- !memcmp(hash2, want_hash, GIT_SHA1_RAWSZ)) {
- want_names[want_names_len++] = xstrdup(name);
- }
- }
-
- n = reftable_writer_close(w);
- EXPECT(n == 0);
-
- reftable_writer_free(w);
- w = NULL;
-
- block_source_from_strbuf(&source, &buf);
-
- err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
- if (!indexed) {
- rd.obj_offsets.is_present = 0;
- }
-
- err = reftable_reader_seek_ref(&rd, &it, "");
- EXPECT_ERR(err);
- reftable_iterator_destroy(&it);
-
- err = reftable_reader_refs_for(&rd, &it, want_hash);
- EXPECT_ERR(err);
-
- j = 0;
- while (1) {
- int err = reftable_iterator_next_ref(&it, &ref);
- EXPECT(err >= 0);
- if (err > 0) {
- break;
- }
-
- EXPECT(j < want_names_len);
- EXPECT(0 == strcmp(ref.refname, want_names[j]));
- j++;
- reftable_ref_record_release(&ref);
- }
- EXPECT(j == want_names_len);
-
- strbuf_release(&buf);
- free_names(want_names);
- reftable_iterator_destroy(&it);
- reader_close(&rd);
-}
-
-static void test_table_refs_for_no_index(void)
-{
- test_table_refs_for(0);
-}
-
-static void test_table_refs_for_obj_index(void)
-{
- test_table_refs_for(1);
-}
-
-static void test_write_empty_table(void)
-{
- struct reftable_write_options opts = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- struct reftable_block_source source = { NULL };
- struct reftable_reader *rd = NULL;
- struct reftable_ref_record rec = { NULL };
- struct reftable_iterator it = { NULL };
- int err;
-
- reftable_writer_set_limits(w, 1, 1);
-
- err = reftable_writer_close(w);
- EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
- reftable_writer_free(w);
-
- EXPECT(buf.len == header_size(1) + footer_size(1));
-
- block_source_from_strbuf(&source, &buf);
-
- err = reftable_new_reader(&rd, &source, "filename");
- EXPECT_ERR(err);
-
- err = reftable_reader_seek_ref(rd, &it, "");
- EXPECT_ERR(err);
-
- err = reftable_iterator_next_ref(&it, &rec);
- EXPECT(err > 0);
-
- reftable_iterator_destroy(&it);
- reftable_reader_free(rd);
- strbuf_release(&buf);
-}
-
-static void test_write_object_id_min_length(void)
-{
- struct reftable_write_options opts = {
- .block_size = 75,
- };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- uint8_t hash[GIT_SHA1_RAWSZ] = {42};
- struct reftable_ref_record ref = {
- .update_index = 1,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash,
- };
- int err;
- int i;
-
- reftable_writer_set_limits(w, 1, 1);
-
- /* Write the same hash in many refs. If there is only 1 hash, the
- * disambiguating prefix is length 0 */
- for (i = 0; i < 256; i++) {
- char name[256];
- snprintf(name, sizeof(name), "ref%05d", i);
- ref.refname = name;
- err = reftable_writer_add_ref(w, &ref);
- EXPECT_ERR(err);
- }
-
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
- EXPECT(reftable_writer_stats(w)->object_id_len == 2);
- reftable_writer_free(w);
- strbuf_release(&buf);
-}
-
-static void test_write_object_id_length(void)
-{
- struct reftable_write_options opts = {
- .block_size = 75,
- };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- uint8_t hash[GIT_SHA1_RAWSZ] = {42};
- struct reftable_ref_record ref = {
- .update_index = 1,
- .value_type = REFTABLE_REF_VAL1,
- .value.val1 = hash,
- };
- int err;
- int i;
-
- reftable_writer_set_limits(w, 1, 1);
-
- /* Write the same hash in many refs. If there is only 1 hash, the
- * disambiguating prefix is length 0 */
- for (i = 0; i < 256; i++) {
- char name[256];
- snprintf(name, sizeof(name), "ref%05d", i);
- ref.refname = name;
- ref.value.val1[15] = i;
- err = reftable_writer_add_ref(w, &ref);
- EXPECT_ERR(err);
- }
-
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
- EXPECT(reftable_writer_stats(w)->object_id_len == 16);
- reftable_writer_free(w);
- strbuf_release(&buf);
-}
-
-static void test_write_empty_key(void)
-{
- struct reftable_write_options opts = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- struct reftable_ref_record ref = {
- .refname = "",
- .update_index = 1,
- .value_type = REFTABLE_REF_DELETION,
- };
- int err;
-
- reftable_writer_set_limits(w, 1, 1);
- err = reftable_writer_add_ref(w, &ref);
- EXPECT(err == REFTABLE_API_ERROR);
-
- err = reftable_writer_close(w);
- EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
- reftable_writer_free(w);
- strbuf_release(&buf);
-}
-
-static void test_write_key_order(void)
-{
- struct reftable_write_options opts = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- struct reftable_ref_record refs[2] = {
- {
- .refname = "b",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value = {
- .symref = "target",
- },
- }, {
- .refname = "a",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value = {
- .symref = "target",
- },
- }
- };
- int err;
-
- reftable_writer_set_limits(w, 1, 1);
- err = reftable_writer_add_ref(w, &refs[0]);
- EXPECT_ERR(err);
- err = reftable_writer_add_ref(w, &refs[1]);
- EXPECT(err == REFTABLE_API_ERROR);
- reftable_writer_close(w);
- reftable_writer_free(w);
- strbuf_release(&buf);
-}
-
-static void test_corrupt_table_empty(void)
-{
- struct strbuf buf = STRBUF_INIT;
- struct reftable_block_source source = { NULL };
- struct reftable_reader rd = { NULL };
- int err;
-
- block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.log");
- EXPECT(err == REFTABLE_FORMAT_ERROR);
-}
-
-static void test_corrupt_table(void)
-{
- uint8_t zeros[1024] = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_block_source source = { NULL };
- struct reftable_reader rd = { NULL };
- int err;
- strbuf_add(&buf, zeros, sizeof(zeros));
-
- block_source_from_strbuf(&source, &buf);
- err = init_reader(&rd, &source, "file.log");
- EXPECT(err == REFTABLE_FORMAT_ERROR);
- strbuf_release(&buf);
-}
-
-int readwrite_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_log_zlib_corruption);
- RUN_TEST(test_corrupt_table);
- RUN_TEST(test_corrupt_table_empty);
- RUN_TEST(test_log_write_read);
- RUN_TEST(test_write_key_order);
- RUN_TEST(test_table_read_write_seek_linear_sha256);
- RUN_TEST(test_log_buffer_size);
- RUN_TEST(test_table_write_small_table);
- RUN_TEST(test_buffer);
- RUN_TEST(test_table_read_api);
- RUN_TEST(test_table_read_write_sequential);
- RUN_TEST(test_table_read_write_seek_linear);
- RUN_TEST(test_table_read_write_seek_index);
- RUN_TEST(test_table_refs_for_no_index);
- RUN_TEST(test_table_refs_for_obj_index);
- RUN_TEST(test_write_empty_key);
- RUN_TEST(test_write_empty_table);
- RUN_TEST(test_log_overflow);
- RUN_TEST(test_write_object_id_length);
- RUN_TEST(test_write_object_id_min_length);
- return 0;
-}
diff --git a/reftable/record.c b/reftable/record.c
index fbaa1fbef5..fb5652ed57 100644
--- a/reftable/record.c
+++ b/reftable/record.c
@@ -76,7 +76,7 @@ int reftable_is_block_type(uint8_t typ)
return 0;
}
-uint8_t *reftable_ref_record_val1(const struct reftable_ref_record *rec)
+const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec)
{
switch (rec->value_type) {
case REFTABLE_REF_VAL1:
@@ -88,7 +88,7 @@ uint8_t *reftable_ref_record_val1(const struct reftable_ref_record *rec)
}
}
-uint8_t *reftable_ref_record_val2(const struct reftable_ref_record *rec)
+const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec)
{
switch (rec->value_type) {
case REFTABLE_REF_VAL2:
@@ -98,25 +98,30 @@ uint8_t *reftable_ref_record_val2(const struct reftable_ref_record *rec)
}
}
-static int decode_string(struct strbuf *dest, struct string_view in)
+static int decode_string(struct reftable_buf *dest, struct string_view in)
{
int start_len = in.len;
uint64_t tsize = 0;
- int n = get_var_int(&tsize, &in);
+ int n, err;
+
+ n = get_var_int(&tsize, &in);
if (n <= 0)
return -1;
string_view_consume(&in, n);
if (in.len < tsize)
return -1;
- strbuf_reset(dest);
- strbuf_add(dest, in.buf, tsize);
+ reftable_buf_reset(dest);
+ err = reftable_buf_add(dest, in.buf, tsize);
+ if (err < 0)
+ return err;
+
string_view_consume(&in, tsize);
return start_len - in.len;
}
-static int encode_string(char *str, struct string_view s)
+static int encode_string(const char *str, struct string_view s)
{
struct string_view start = s;
int l = strlen(str);
@@ -133,7 +138,7 @@ static int encode_string(char *str, struct string_view s)
}
int reftable_encode_key(int *restart, struct string_view dest,
- struct strbuf prev_key, struct strbuf key,
+ struct reftable_buf prev_key, struct reftable_buf key,
uint8_t extra)
{
struct string_view start = dest;
@@ -159,132 +164,124 @@ int reftable_encode_key(int *restart, struct string_view dest,
return start.len - dest.len;
}
-int reftable_decode_key(struct strbuf *key, uint8_t *extra,
- struct strbuf last_key, struct string_view in)
+int reftable_decode_keylen(struct string_view in,
+ uint64_t *prefix_len,
+ uint64_t *suffix_len,
+ uint8_t *extra)
{
- int start_len = in.len;
- uint64_t prefix_len = 0;
- uint64_t suffix_len = 0;
- int n = get_var_int(&prefix_len, &in);
+ size_t start_len = in.len;
+ int n;
+
+ n = get_var_int(prefix_len, &in);
if (n < 0)
return -1;
string_view_consume(&in, n);
- if (prefix_len > last_key.len)
- return -1;
-
- n = get_var_int(&suffix_len, &in);
+ n = get_var_int(suffix_len, &in);
if (n <= 0)
return -1;
string_view_consume(&in, n);
- *extra = (uint8_t)(suffix_len & 0x7);
- suffix_len >>= 3;
+ *extra = (uint8_t)(*suffix_len & 0x7);
+ *suffix_len >>= 3;
+
+ return start_len - in.len;
+}
- if (in.len < suffix_len)
+int reftable_decode_key(struct reftable_buf *last_key, uint8_t *extra,
+ struct string_view in)
+{
+ int start_len = in.len;
+ uint64_t prefix_len = 0;
+ uint64_t suffix_len = 0;
+ int err, n;
+
+ n = reftable_decode_keylen(in, &prefix_len, &suffix_len, extra);
+ if (n < 0)
+ return -1;
+ string_view_consume(&in, n);
+
+ if (in.len < suffix_len ||
+ prefix_len > last_key->len)
return -1;
- strbuf_reset(key);
- strbuf_add(key, last_key.buf, prefix_len);
- strbuf_add(key, in.buf, suffix_len);
+ err = reftable_buf_setlen(last_key, prefix_len);
+ if (err < 0)
+ return err;
+
+ err = reftable_buf_add(last_key, in.buf, suffix_len);
+ if (err < 0)
+ return err;
+
string_view_consume(&in, suffix_len);
return start_len - in.len;
}
-static void reftable_ref_record_key(const void *r, struct strbuf *dest)
+static int reftable_ref_record_key(const void *r, struct reftable_buf *dest)
{
const struct reftable_ref_record *rec =
(const struct reftable_ref_record *)r;
- strbuf_reset(dest);
- strbuf_addstr(dest, rec->refname);
+ reftable_buf_reset(dest);
+ return reftable_buf_addstr(dest, rec->refname);
}
-static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
- int hash_size)
+static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
+ int hash_size)
{
struct reftable_ref_record *ref = rec;
const struct reftable_ref_record *src = src_rec;
+ char *refname = NULL;
+ size_t refname_cap = 0;
+ int err;
+
assert(hash_size > 0);
- /* This is simple and correct, but we could probably reuse the hash
- * fields. */
+ SWAP(refname, ref->refname);
+ SWAP(refname_cap, ref->refname_cap);
reftable_ref_record_release(ref);
+ SWAP(ref->refname, refname);
+ SWAP(ref->refname_cap, refname_cap);
+
if (src->refname) {
- ref->refname = xstrdup(src->refname);
+ size_t refname_len = strlen(src->refname);
+
+ REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1,
+ ref->refname_cap);
+ if (!ref->refname) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
+ memcpy(ref->refname, src->refname, refname_len);
+ ref->refname[refname_len] = 0;
}
+
ref->update_index = src->update_index;
ref->value_type = src->value_type;
switch (src->value_type) {
case REFTABLE_REF_DELETION:
break;
case REFTABLE_REF_VAL1:
- ref->value.val1 = reftable_malloc(hash_size);
memcpy(ref->value.val1, src->value.val1, hash_size);
break;
case REFTABLE_REF_VAL2:
- ref->value.val2.value = reftable_malloc(hash_size);
memcpy(ref->value.val2.value, src->value.val2.value, hash_size);
- ref->value.val2.target_value = reftable_malloc(hash_size);
memcpy(ref->value.val2.target_value,
src->value.val2.target_value, hash_size);
break;
case REFTABLE_REF_SYMREF:
- ref->value.symref = xstrdup(src->value.symref);
- break;
- }
-}
-
-static char hexdigit(int c)
-{
- if (c <= 9)
- return '0' + c;
- return 'a' + (c - 10);
-}
-
-static void hex_format(char *dest, uint8_t *src, int hash_size)
-{
- assert(hash_size > 0);
- if (src) {
- int i = 0;
- for (i = 0; i < hash_size; i++) {
- dest[2 * i] = hexdigit(src[i] >> 4);
- dest[2 * i + 1] = hexdigit(src[i] & 0xf);
+ ref->value.symref = reftable_strdup(src->value.symref);
+ if (!ref->value.symref) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
- dest[2 * hash_size] = 0;
- }
-}
-
-static void reftable_ref_record_print_sz(const struct reftable_ref_record *ref,
- int hash_size)
-{
- char hex[GIT_MAX_HEXSZ + 1] = { 0 }; /* BUG */
- printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
- switch (ref->value_type) {
- case REFTABLE_REF_SYMREF:
- printf("=> %s", ref->value.symref);
- break;
- case REFTABLE_REF_VAL2:
- hex_format(hex, ref->value.val2.value, hash_size);
- printf("val 2 %s", hex);
- hex_format(hex, ref->value.val2.target_value,
- hash_size);
- printf("(T %s)", hex);
- break;
- case REFTABLE_REF_VAL1:
- hex_format(hex, ref->value.val1, hash_size);
- printf("val 1 %s", hex);
- break;
- case REFTABLE_REF_DELETION:
- printf("delete");
break;
}
- printf("}\n");
-}
-void reftable_ref_record_print(const struct reftable_ref_record *ref,
- uint32_t hash_id) {
- reftable_ref_record_print_sz(ref, hash_size(hash_id));
+ err = 0;
+out:
+ return err;
}
static void reftable_ref_record_release_void(void *rec)
@@ -299,11 +296,8 @@ void reftable_ref_record_release(struct reftable_ref_record *ref)
reftable_free(ref->value.symref);
break;
case REFTABLE_REF_VAL2:
- reftable_free(ref->value.val2.target_value);
- reftable_free(ref->value.val2.value);
break;
case REFTABLE_REF_VAL1:
- reftable_free(ref->value.val1);
break;
case REFTABLE_REF_DELETION:
break;
@@ -367,60 +361,72 @@ static int reftable_ref_record_encode(const void *rec, struct string_view s,
return start.len - s.len;
}
-static int reftable_ref_record_decode(void *rec, struct strbuf key,
+static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
uint8_t val_type, struct string_view in,
- int hash_size)
+ int hash_size, struct reftable_buf *scratch)
{
struct reftable_ref_record *r = rec;
struct string_view start = in;
uint64_t update_index = 0;
- int n = get_var_int(&update_index, &in);
+ const char *refname = NULL;
+ size_t refname_cap = 0;
+ int n, err;
+
+ assert(hash_size > 0);
+
+ n = get_var_int(&update_index, &in);
if (n < 0)
return n;
string_view_consume(&in, n);
+ SWAP(refname, r->refname);
+ SWAP(refname_cap, r->refname_cap);
reftable_ref_record_release(r);
+ SWAP(r->refname, refname);
+ SWAP(r->refname_cap, refname_cap);
- assert(hash_size > 0);
-
- r->refname = reftable_realloc(r->refname, key.len + 1);
+ REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->refname_cap);
+ if (!r->refname) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
memcpy(r->refname, key.buf, key.len);
- r->update_index = update_index;
r->refname[key.len] = 0;
+
+ r->update_index = update_index;
r->value_type = val_type;
switch (val_type) {
case REFTABLE_REF_VAL1:
if (in.len < hash_size) {
- return -1;
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
}
- r->value.val1 = reftable_malloc(hash_size);
memcpy(r->value.val1, in.buf, hash_size);
string_view_consume(&in, hash_size);
break;
case REFTABLE_REF_VAL2:
if (in.len < 2 * hash_size) {
- return -1;
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
}
- r->value.val2.value = reftable_malloc(hash_size);
memcpy(r->value.val2.value, in.buf, hash_size);
string_view_consume(&in, hash_size);
- r->value.val2.target_value = reftable_malloc(hash_size);
memcpy(r->value.val2.target_value, in.buf, hash_size);
string_view_consume(&in, hash_size);
break;
case REFTABLE_REF_SYMREF: {
- struct strbuf dest = STRBUF_INIT;
- int n = decode_string(&dest, in);
+ int n = decode_string(scratch, in);
if (n < 0) {
- return -1;
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
}
string_view_consume(&in, n);
- r->value.symref = dest.buf;
+ r->value.symref = reftable_buf_detach(scratch);
} break;
case REFTABLE_REF_DELETION:
@@ -431,6 +437,9 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
}
return start.len - in.len;
+
+done:
+ return err;
}
static int reftable_ref_record_is_deletion_void(const void *p)
@@ -439,7 +448,6 @@ static int reftable_ref_record_is_deletion_void(const void *p)
(const struct reftable_ref_record *)p);
}
-
static int reftable_ref_record_equal_void(const void *a,
const void *b, int hash_size)
{
@@ -448,10 +456,11 @@ static int reftable_ref_record_equal_void(const void *a,
return reftable_ref_record_equal(ra, rb, hash_size);
}
-static void reftable_ref_record_print_void(const void *rec,
- int hash_size)
+static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
{
- reftable_ref_record_print_sz((struct reftable_ref_record *) rec, hash_size);
+ const struct reftable_ref_record *a = _a;
+ const struct reftable_ref_record *b = _b;
+ return strcmp(a->refname, b->refname);
}
static struct reftable_record_vtable reftable_ref_record_vtable = {
@@ -464,56 +473,47 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
.release = &reftable_ref_record_release_void,
.is_deletion = &reftable_ref_record_is_deletion_void,
.equal = &reftable_ref_record_equal_void,
- .print = &reftable_ref_record_print_void,
+ .cmp = &reftable_ref_record_cmp_void,
};
-static void reftable_obj_record_key(const void *r, struct strbuf *dest)
+static int reftable_obj_record_key(const void *r, struct reftable_buf *dest)
{
const struct reftable_obj_record *rec =
(const struct reftable_obj_record *)r;
- strbuf_reset(dest);
- strbuf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
+ reftable_buf_reset(dest);
+ return reftable_buf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
}
static void reftable_obj_record_release(void *rec)
{
struct reftable_obj_record *obj = rec;
- FREE_AND_NULL(obj->hash_prefix);
- FREE_AND_NULL(obj->offsets);
+ REFTABLE_FREE_AND_NULL(obj->hash_prefix);
+ REFTABLE_FREE_AND_NULL(obj->offsets);
memset(obj, 0, sizeof(struct reftable_obj_record));
}
-static void reftable_obj_record_print(const void *rec, int hash_size)
-{
- const struct reftable_obj_record *obj = rec;
- char hex[GIT_MAX_HEXSZ + 1] = { 0 };
- struct strbuf offset_str = STRBUF_INIT;
- int i;
-
- for (i = 0; i < obj->offset_len; i++)
- strbuf_addf(&offset_str, "%" PRIu64 " ", obj->offsets[i]);
- hex_format(hex, obj->hash_prefix, obj->hash_prefix_len);
- printf("prefix %s (len %d), offsets [%s]\n",
- hex, obj->hash_prefix_len, offset_str.buf);
- strbuf_release(&offset_str);
-}
-
-static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
- int hash_size)
+static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
+ int hash_size UNUSED)
{
struct reftable_obj_record *obj = rec;
- const struct reftable_obj_record *src =
- (const struct reftable_obj_record *)src_rec;
+ const struct reftable_obj_record *src = src_rec;
reftable_obj_record_release(obj);
- obj->hash_prefix = reftable_malloc(src->hash_prefix_len);
+
+ REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
+ if (!obj->hash_prefix)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->hash_prefix_len = src->hash_prefix_len;
if (src->hash_prefix_len)
memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
- obj->offsets = reftable_malloc(src->offset_len * sizeof(uint64_t));
+ REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
+ if (!obj->offsets)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->offset_len = src->offset_len;
COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
+
+ return 0;
}
static uint8_t reftable_obj_record_val_type(const void *rec)
@@ -525,7 +525,7 @@ static uint8_t reftable_obj_record_val_type(const void *rec)
}
static int reftable_obj_record_encode(const void *rec, struct string_view s,
- int hash_size)
+ int hash_size UNUSED)
{
const struct reftable_obj_record *r = rec;
struct string_view start = s;
@@ -558,9 +558,10 @@ static int reftable_obj_record_encode(const void *rec, struct string_view s,
return start.len - s.len;
}
-static int reftable_obj_record_decode(void *rec, struct strbuf key,
+static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
uint8_t val_type, struct string_view in,
- int hash_size)
+ int hash_size UNUSED,
+ struct reftable_buf *scratch UNUSED)
{
struct string_view start = in;
struct reftable_obj_record *r = rec;
@@ -568,7 +569,12 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
int n = 0;
uint64_t last;
int j;
- r->hash_prefix = reftable_malloc(key.len);
+
+ reftable_obj_record_release(r);
+
+ REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
+ if (!r->hash_prefix)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
memcpy(r->hash_prefix, key.buf, key.len);
r->hash_prefix_len = key.len;
@@ -586,7 +592,9 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
if (count == 0)
return start.len - in.len;
- r->offsets = reftable_malloc(count * sizeof(uint64_t));
+ REFTABLE_ALLOC_ARRAY(r->offsets, count);
+ if (!r->offsets)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
r->offset_len = count;
n = get_var_int(&r->offsets[0], &in);
@@ -610,12 +618,13 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
return start.len - in.len;
}
-static int not_a_deletion(const void *p)
+static int not_a_deletion(const void *p UNUSED)
{
return 0;
}
-static int reftable_obj_record_equal_void(const void *a, const void *b, int hash_size)
+static int reftable_obj_record_equal_void(const void *a, const void *b,
+ int hash_size UNUSED)
{
struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
@@ -634,6 +643,25 @@ static int reftable_obj_record_equal_void(const void *a, const void *b, int hash
return 1;
}
+static int reftable_obj_record_cmp_void(const void *_a, const void *_b)
+{
+ const struct reftable_obj_record *a = _a;
+ const struct reftable_obj_record *b = _b;
+ int cmp;
+
+ cmp = memcmp(a->hash_prefix, b->hash_prefix,
+ a->hash_prefix_len > b->hash_prefix_len ?
+ a->hash_prefix_len : b->hash_prefix_len);
+ if (cmp)
+ return cmp;
+
+ /*
+ * When the prefix is the same then the object record that is longer is
+ * considered to be bigger.
+ */
+ return a->hash_prefix_len - b->hash_prefix_len;
+}
+
static struct reftable_record_vtable reftable_obj_record_vtable = {
.key = &reftable_obj_record_key,
.type = BLOCK_TYPE_OBJ,
@@ -644,97 +672,82 @@ static struct reftable_record_vtable reftable_obj_record_vtable = {
.release = &reftable_obj_record_release,
.is_deletion = &not_a_deletion,
.equal = &reftable_obj_record_equal_void,
- .print = &reftable_obj_record_print,
+ .cmp = &reftable_obj_record_cmp_void,
};
-static void reftable_log_record_print_sz(struct reftable_log_record *log,
- int hash_size)
-{
- char hex[GIT_MAX_HEXSZ + 1] = { 0 };
-
- switch (log->value_type) {
- case REFTABLE_LOG_DELETION:
- printf("log{%s(%" PRIu64 ") delete\n", log->refname,
- log->update_index);
- break;
- case REFTABLE_LOG_UPDATE:
- printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
- log->refname, log->update_index,
- log->value.update.name ? log->value.update.name : "",
- log->value.update.email ? log->value.update.email : "",
- log->value.update.time,
- log->value.update.tz_offset);
- hex_format(hex, log->value.update.old_hash, hash_size);
- printf("%s => ", hex);
- hex_format(hex, log->value.update.new_hash, hash_size);
- printf("%s\n\n%s\n}\n", hex,
- log->value.update.message ? log->value.update.message : "");
- break;
- }
-}
-
-void reftable_log_record_print(struct reftable_log_record *log,
- uint32_t hash_id)
-{
- reftable_log_record_print_sz(log, hash_size(hash_id));
-}
-
-static void reftable_log_record_key(const void *r, struct strbuf *dest)
+static int reftable_log_record_key(const void *r, struct reftable_buf *dest)
{
const struct reftable_log_record *rec =
(const struct reftable_log_record *)r;
- int len = strlen(rec->refname);
+ int len = strlen(rec->refname), err;
uint8_t i64[8];
uint64_t ts = 0;
- strbuf_reset(dest);
- strbuf_add(dest, (uint8_t *)rec->refname, len + 1);
+
+ reftable_buf_reset(dest);
+ err = reftable_buf_add(dest, (uint8_t *)rec->refname, len + 1);
+ if (err < 0)
+ return err;
ts = (~ts) - rec->update_index;
put_be64(&i64[0], ts);
- strbuf_add(dest, i64, sizeof(i64));
+
+ err = reftable_buf_add(dest, i64, sizeof(i64));
+ if (err < 0)
+ return err;
+
+ return 0;
}
-static void reftable_log_record_copy_from(void *rec, const void *src_rec,
- int hash_size)
+static int reftable_log_record_copy_from(void *rec, const void *src_rec,
+ int hash_size)
{
struct reftable_log_record *dst = rec;
const struct reftable_log_record *src =
(const struct reftable_log_record *)src_rec;
+ int ret;
reftable_log_record_release(dst);
*dst = *src;
+
if (dst->refname) {
- dst->refname = xstrdup(dst->refname);
+ dst->refname = reftable_strdup(dst->refname);
+ if (!dst->refname) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
}
+
switch (dst->value_type) {
case REFTABLE_LOG_DELETION:
break;
case REFTABLE_LOG_UPDATE:
- if (dst->value.update.email) {
+ if (dst->value.update.email)
dst->value.update.email =
- xstrdup(dst->value.update.email);
- }
- if (dst->value.update.name) {
+ reftable_strdup(dst->value.update.email);
+ if (dst->value.update.name)
dst->value.update.name =
- xstrdup(dst->value.update.name);
- }
- if (dst->value.update.message) {
+ reftable_strdup(dst->value.update.name);
+ if (dst->value.update.message)
dst->value.update.message =
- xstrdup(dst->value.update.message);
- }
+ reftable_strdup(dst->value.update.message);
- if (dst->value.update.new_hash) {
- dst->value.update.new_hash = reftable_malloc(hash_size);
- memcpy(dst->value.update.new_hash,
- src->value.update.new_hash, hash_size);
- }
- if (dst->value.update.old_hash) {
- dst->value.update.old_hash = reftable_malloc(hash_size);
- memcpy(dst->value.update.old_hash,
- src->value.update.old_hash, hash_size);
+ if (!dst->value.update.email ||
+ !dst->value.update.name ||
+ !dst->value.update.message) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
+
+ memcpy(dst->value.update.new_hash,
+ src->value.update.new_hash, hash_size);
+ memcpy(dst->value.update.old_hash,
+ src->value.update.old_hash, hash_size);
break;
}
+
+ ret = 0;
+out:
+ return ret;
}
static void reftable_log_record_release_void(void *rec)
@@ -750,8 +763,6 @@ void reftable_log_record_release(struct reftable_log_record *r)
case REFTABLE_LOG_DELETION:
break;
case REFTABLE_LOG_UPDATE:
- reftable_free(r->value.update.new_hash);
- reftable_free(r->value.update.old_hash);
reftable_free(r->value.update.name);
reftable_free(r->value.update.email);
reftable_free(r->value.update.message);
@@ -768,33 +779,20 @@ static uint8_t reftable_log_record_val_type(const void *rec)
return reftable_log_record_is_deletion(log) ? 0 : 1;
}
-static uint8_t zero[GIT_SHA256_RAWSZ] = { 0 };
-
static int reftable_log_record_encode(const void *rec, struct string_view s,
int hash_size)
{
const struct reftable_log_record *r = rec;
struct string_view start = s;
int n = 0;
- uint8_t *oldh = NULL;
- uint8_t *newh = NULL;
if (reftable_log_record_is_deletion(r))
return 0;
- oldh = r->value.update.old_hash;
- newh = r->value.update.new_hash;
- if (!oldh) {
- oldh = zero;
- }
- if (!newh) {
- newh = zero;
- }
-
if (s.len < 2 * hash_size)
return -1;
- memcpy(s.buf, oldh, hash_size);
- memcpy(s.buf + hash_size, newh, hash_size);
+ memcpy(s.buf, r->value.update.old_hash, hash_size);
+ memcpy(s.buf + hash_size, r->value.update.new_hash, hash_size);
string_view_consume(&s, 2 * hash_size);
n = encode_string(r->value.update.name ? r->value.update.name : "", s);
@@ -828,21 +826,25 @@ static int reftable_log_record_encode(const void *rec, struct string_view s,
return start.len - s.len;
}
-static int reftable_log_record_decode(void *rec, struct strbuf key,
+static int reftable_log_record_decode(void *rec, struct reftable_buf key,
uint8_t val_type, struct string_view in,
- int hash_size)
+ int hash_size, struct reftable_buf *scratch)
{
struct string_view start = in;
struct reftable_log_record *r = rec;
uint64_t max = 0;
uint64_t ts = 0;
- struct strbuf dest = STRBUF_INIT;
- int n;
+ int err, n;
if (key.len <= 9 || key.buf[key.len - 9] != 0)
return REFTABLE_FORMAT_ERROR;
- r->refname = reftable_realloc(r->refname, key.len - 8);
+ REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap);
+ if (!r->refname) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
memcpy(r->refname, key.buf, key.len - 8);
ts = get_be64(key.buf + key.len - 8);
@@ -851,11 +853,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type != r->value_type) {
switch (r->value_type) {
case REFTABLE_LOG_UPDATE:
- FREE_AND_NULL(r->value.update.old_hash);
- FREE_AND_NULL(r->value.update.new_hash);
- FREE_AND_NULL(r->value.update.message);
- FREE_AND_NULL(r->value.update.email);
- FREE_AND_NULL(r->value.update.name);
+ REFTABLE_FREE_AND_NULL(r->value.update.message);
+ r->value.update.message_cap = 0;
+ REFTABLE_FREE_AND_NULL(r->value.update.email);
+ REFTABLE_FREE_AND_NULL(r->value.update.name);
break;
case REFTABLE_LOG_DELETION:
break;
@@ -866,74 +867,105 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type == REFTABLE_LOG_DELETION)
return 0;
- if (in.len < 2 * hash_size)
- return REFTABLE_FORMAT_ERROR;
-
- r->value.update.old_hash =
- reftable_realloc(r->value.update.old_hash, hash_size);
- r->value.update.new_hash =
- reftable_realloc(r->value.update.new_hash, hash_size);
+ if (in.len < 2 * hash_size) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
memcpy(r->value.update.old_hash, in.buf, hash_size);
memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
string_view_consume(&in, 2 * hash_size);
- n = decode_string(&dest, in);
- if (n < 0)
+ n = decode_string(scratch, in);
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
- r->value.update.name =
- reftable_realloc(r->value.update.name, dest.len + 1);
- memcpy(r->value.update.name, dest.buf, dest.len);
- r->value.update.name[dest.len] = 0;
+ /*
+ * In almost all cases we can expect the reflog name to not change for
+ * reflog entries as they are tied to the local identity, not to the
+ * target commits. As an optimization for this common case we can thus
+ * skip copying over the name in case it's accurate already.
+ */
+ if (!r->value.update.name ||
+ strcmp(r->value.update.name, scratch->buf)) {
+ char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
+ if (!name) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
- strbuf_reset(&dest);
- n = decode_string(&dest, in);
- if (n < 0)
+ r->value.update.name = name;
+ memcpy(r->value.update.name, scratch->buf, scratch->len);
+ r->value.update.name[scratch->len] = 0;
+ }
+
+ n = decode_string(scratch, in);
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
- r->value.update.email =
- reftable_realloc(r->value.update.email, dest.len + 1);
- memcpy(r->value.update.email, dest.buf, dest.len);
- r->value.update.email[dest.len] = 0;
+ /* Same as above, but for the reflog email. */
+ if (!r->value.update.email ||
+ strcmp(r->value.update.email, scratch->buf)) {
+ char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
+ if (!email) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ r->value.update.email = email;
+ memcpy(r->value.update.email, scratch->buf, scratch->len);
+ r->value.update.email[scratch->len] = 0;
+ }
ts = 0;
n = get_var_int(&ts, &in);
- if (n < 0)
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
r->value.update.time = ts;
- if (in.len < 2)
+ if (in.len < 2) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
r->value.update.tz_offset = get_be16(in.buf);
string_view_consume(&in, 2);
- strbuf_reset(&dest);
- n = decode_string(&dest, in);
- if (n < 0)
+ n = decode_string(scratch, in);
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
- r->value.update.message =
- reftable_realloc(r->value.update.message, dest.len + 1);
- memcpy(r->value.update.message, dest.buf, dest.len);
- r->value.update.message[dest.len] = 0;
+ REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
+ r->value.update.message_cap);
+ if (!r->value.update.message) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ memcpy(r->value.update.message, scratch->buf, scratch->len);
+ r->value.update.message[scratch->len] = 0;
- strbuf_release(&dest);
return start.len - in.len;
done:
- strbuf_release(&dest);
- return REFTABLE_FORMAT_ERROR;
+ return err;
}
-static int null_streq(char *a, char *b)
+static int null_streq(const char *a, const char *b)
{
- char *empty = "";
+ const char *empty = "";
if (!a)
a = empty;
@@ -943,17 +975,6 @@ static int null_streq(char *a, char *b)
return 0 == strcmp(a, b);
}
-static int zero_hash_eq(uint8_t *a, uint8_t *b, int sz)
-{
- if (!a)
- a = zero;
-
- if (!b)
- b = zero;
-
- return !memcmp(a, b, sz);
-}
-
static int reftable_log_record_equal_void(const void *a,
const void *b, int hash_size)
{
@@ -962,6 +983,22 @@ static int reftable_log_record_equal_void(const void *a,
hash_size);
}
+static int reftable_log_record_cmp_void(const void *_a, const void *_b)
+{
+ const struct reftable_log_record *a = _a;
+ const struct reftable_log_record *b = _b;
+ int cmp = strcmp(a->refname, b->refname);
+ if (cmp)
+ return cmp;
+
+ /*
+ * Note that the comparison here is reversed. This is because the
+ * update index is reversed when comparing keys. For reference, see how
+ * we handle this in reftable_log_record_key()`.
+ */
+ return b->update_index - a->update_index;
+}
+
int reftable_log_record_equal(const struct reftable_log_record *a,
const struct reftable_log_record *b, int hash_size)
{
@@ -981,10 +1018,10 @@ int reftable_log_record_equal(const struct reftable_log_record *a,
b->value.update.email) &&
null_streq(a->value.update.message,
b->value.update.message) &&
- zero_hash_eq(a->value.update.old_hash,
- b->value.update.old_hash, hash_size) &&
- zero_hash_eq(a->value.update.new_hash,
- b->value.update.new_hash, hash_size);
+ !memcmp(a->value.update.old_hash,
+ b->value.update.old_hash, hash_size) &&
+ !memcmp(a->value.update.new_hash,
+ b->value.update.new_hash, hash_size);
}
abort();
@@ -996,11 +1033,6 @@ static int reftable_log_record_is_deletion_void(const void *p)
(const struct reftable_log_record *)p);
}
-static void reftable_log_record_print_void(const void *rec, int hash_size)
-{
- reftable_log_record_print_sz((struct reftable_log_record*)rec, hash_size);
-}
-
static struct reftable_record_vtable reftable_log_record_vtable = {
.key = &reftable_log_record_key,
.type = BLOCK_TYPE_LOG,
@@ -1011,40 +1043,45 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
.release = &reftable_log_record_release_void,
.is_deletion = &reftable_log_record_is_deletion_void,
.equal = &reftable_log_record_equal_void,
- .print = &reftable_log_record_print_void,
+ .cmp = &reftable_log_record_cmp_void,
};
-static void reftable_index_record_key(const void *r, struct strbuf *dest)
+static int reftable_index_record_key(const void *r, struct reftable_buf *dest)
{
const struct reftable_index_record *rec = r;
- strbuf_reset(dest);
- strbuf_addbuf(dest, &rec->last_key);
+ reftable_buf_reset(dest);
+ return reftable_buf_add(dest, rec->last_key.buf, rec->last_key.len);
}
-static void reftable_index_record_copy_from(void *rec, const void *src_rec,
- int hash_size)
+static int reftable_index_record_copy_from(void *rec, const void *src_rec,
+ int hash_size UNUSED)
{
struct reftable_index_record *dst = rec;
const struct reftable_index_record *src = src_rec;
+ int err;
- strbuf_reset(&dst->last_key);
- strbuf_addbuf(&dst->last_key, &src->last_key);
+ reftable_buf_reset(&dst->last_key);
+ err = reftable_buf_add(&dst->last_key, src->last_key.buf, src->last_key.len);
+ if (err < 0)
+ return err;
dst->offset = src->offset;
+
+ return 0;
}
static void reftable_index_record_release(void *rec)
{
struct reftable_index_record *idx = rec;
- strbuf_release(&idx->last_key);
+ reftable_buf_release(&idx->last_key);
}
-static uint8_t reftable_index_record_val_type(const void *rec)
+static uint8_t reftable_index_record_val_type(const void *rec UNUSED)
{
return 0;
}
static int reftable_index_record_encode(const void *rec, struct string_view out,
- int hash_size)
+ int hash_size UNUSED)
{
const struct reftable_index_record *r =
(const struct reftable_index_record *)rec;
@@ -1059,16 +1096,20 @@ static int reftable_index_record_encode(const void *rec, struct string_view out,
return start.len - out.len;
}
-static int reftable_index_record_decode(void *rec, struct strbuf key,
- uint8_t val_type, struct string_view in,
- int hash_size)
+static int reftable_index_record_decode(void *rec, struct reftable_buf key,
+ uint8_t val_type UNUSED,
+ struct string_view in,
+ int hash_size UNUSED,
+ struct reftable_buf *scratch UNUSED)
{
struct string_view start = in;
struct reftable_index_record *r = rec;
- int n = 0;
+ int err, n = 0;
- strbuf_reset(&r->last_key);
- strbuf_addbuf(&r->last_key, &key);
+ reftable_buf_reset(&r->last_key);
+ err = reftable_buf_add(&r->last_key, key.buf, key.len);
+ if (err < 0)
+ return err;
n = get_var_int(&r->offset, &in);
if (n < 0)
@@ -1078,19 +1119,20 @@ static int reftable_index_record_decode(void *rec, struct strbuf key,
return start.len - in.len;
}
-static int reftable_index_record_equal(const void *a, const void *b, int hash_size)
+static int reftable_index_record_equal(const void *a, const void *b,
+ int hash_size UNUSED)
{
struct reftable_index_record *ia = (struct reftable_index_record *) a;
struct reftable_index_record *ib = (struct reftable_index_record *) b;
- return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key);
+ return ia->offset == ib->offset && !reftable_buf_cmp(&ia->last_key, &ib->last_key);
}
-static void reftable_index_record_print(const void *rec, int hash_size)
+static int reftable_index_record_cmp(const void *_a, const void *_b)
{
- const struct reftable_index_record *idx = rec;
- /* TODO: escape null chars? */
- printf("\"%s\" %" PRIu64 "\n", idx->last_key.buf, idx->offset);
+ const struct reftable_index_record *a = _a;
+ const struct reftable_index_record *b = _b;
+ return reftable_buf_cmp(&a->last_key, &b->last_key);
}
static struct reftable_record_vtable reftable_index_record_vtable = {
@@ -1103,17 +1145,12 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
.release = &reftable_index_record_release,
.is_deletion = &not_a_deletion,
.equal = &reftable_index_record_equal,
- .print = &reftable_index_record_print,
+ .cmp = &reftable_index_record_cmp,
};
-void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
-{
- reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
-}
-
-uint8_t reftable_record_type(struct reftable_record *rec)
+int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest)
{
- return rec->type;
+ return reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
}
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
@@ -1123,14 +1160,14 @@ int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
dest, hash_size);
}
-void reftable_record_copy_from(struct reftable_record *rec,
+int reftable_record_copy_from(struct reftable_record *rec,
struct reftable_record *src, int hash_size)
{
assert(src->type == rec->type);
- reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
- reftable_record_data(src),
- hash_size);
+ return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
+ reftable_record_data(src),
+ hash_size);
}
uint8_t reftable_record_val_type(struct reftable_record *rec)
@@ -1138,11 +1175,13 @@ uint8_t reftable_record_val_type(struct reftable_record *rec)
return reftable_record_vtable(rec)->val_type(reftable_record_data(rec));
}
-int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
- uint8_t extra, struct string_view src, int hash_size)
+int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key,
+ uint8_t extra, struct string_view src, int hash_size,
+ struct reftable_buf *scratch)
{
return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
- key, extra, src, hash_size);
+ key, extra, src, hash_size,
+ scratch);
}
void reftable_record_release(struct reftable_record *rec)
@@ -1156,6 +1195,14 @@ int reftable_record_is_deletion(struct reftable_record *rec)
reftable_record_data(rec));
}
+int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
+{
+ if (a->type != b->type)
+ BUG("cannot compare reftable records of different type");
+ return reftable_record_vtable(a)->cmp(
+ reftable_record_data(a), reftable_record_data(b));
+}
+
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
{
if (a->type != b->type)
@@ -1164,7 +1211,7 @@ int reftable_record_equal(struct reftable_record *a, struct reftable_record *b,
reftable_record_data(a), reftable_record_data(b), hash_size);
}
-static int hash_equal(uint8_t *a, uint8_t *b, int hash_size)
+static int hash_equal(const unsigned char *a, const unsigned char *b, int hash_size)
{
if (a && b)
return !memcmp(a, b, hash_size);
@@ -1229,12 +1276,6 @@ int reftable_log_record_is_deletion(const struct reftable_log_record *log)
return (log->value_type == REFTABLE_LOG_DELETION);
}
-void string_view_consume(struct string_view *s, int n)
-{
- s->buf += n;
- s->len -= n;
-}
-
static void *reftable_record_data(struct reftable_record *rec)
{
switch (rec->type) {
@@ -1266,49 +1307,20 @@ reftable_record_vtable(struct reftable_record *rec)
abort();
}
-struct reftable_record reftable_new_record(uint8_t typ)
+void reftable_record_init(struct reftable_record *rec, uint8_t typ)
{
- struct reftable_record clean = {
- .type = typ,
- };
+ memset(rec, 0, sizeof(*rec));
+ rec->type = typ;
- /* the following is involved, but the naive solution (just return
- * `clean` as is, except for BLOCK_TYPE_INDEX), returns a garbage
- * clean.u.obj.offsets pointer on Windows VS CI. Go figure.
- */
switch (typ) {
- case BLOCK_TYPE_OBJ:
- {
- struct reftable_obj_record obj = { 0 };
- clean.u.obj = obj;
- break;
- }
- case BLOCK_TYPE_INDEX:
- {
- struct reftable_index_record idx = {
- .last_key = STRBUF_INIT,
- };
- clean.u.idx = idx;
- break;
- }
case BLOCK_TYPE_REF:
- {
- struct reftable_ref_record ref = { 0 };
- clean.u.ref = ref;
- break;
- }
case BLOCK_TYPE_LOG:
- {
- struct reftable_log_record log = { 0 };
- clean.u.log = log;
- break;
- }
+ case BLOCK_TYPE_OBJ:
+ return;
+ case BLOCK_TYPE_INDEX:
+ reftable_buf_init(&rec->u.idx.last_key);
+ return;
+ default:
+ BUG("unhandled record type");
}
- return clean;
-}
-
-void reftable_record_print(struct reftable_record *rec, int hash_size)
-{
- printf("'%c': ", rec->type);
- reftable_record_vtable(rec)->print(reftable_record_data(rec), hash_size);
}
diff --git a/reftable/record.h b/reftable/record.h
index fd80cd451d..25aa908c85 100644
--- a/reftable/record.h
+++ b/reftable/record.h
@@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd
#ifndef RECORD_H
#define RECORD_H
+#include "basics.h"
#include "system.h"
#include <stdint.h>
@@ -25,7 +26,11 @@ struct string_view {
};
/* Advance `s.buf` by `n`, and decrease length. */
-void string_view_consume(struct string_view *s, int n);
+static inline void string_view_consume(struct string_view *s, int n)
+{
+ s->buf += n;
+ s->len -= n;
+}
/* utilities for de/encoding varints */
@@ -34,13 +39,13 @@ int put_var_int(struct string_view *dest, uint64_t val);
/* Methods for records. */
struct reftable_record_vtable {
- /* encode the key of to a uint8_t strbuf. */
- void (*key)(const void *rec, struct strbuf *dest);
+ /* encode the key of to a uint8_t reftable_buf. */
+ int (*key)(const void *rec, struct reftable_buf *dest);
/* The record type of ('r' for ref). */
uint8_t type;
- void (*copy_from)(void *dest, const void *src, int hash_size);
+ int (*copy_from)(void *dest, const void *src, int hash_size);
/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
* vs ref deletion) */
@@ -50,8 +55,9 @@ struct reftable_record_vtable {
int (*encode)(const void *rec, struct string_view dest, int hash_size);
/* decode data from `src` into the record. */
- int (*decode)(void *rec, struct strbuf key, uint8_t extra,
- struct string_view src, int hash_size);
+ int (*decode)(void *rec, struct reftable_buf key, uint8_t extra,
+ struct string_view src, int hash_size,
+ struct reftable_buf *scratch);
/* deallocate and null the record. */
void (*release)(void *rec);
@@ -62,6 +68,12 @@ struct reftable_record_vtable {
/* Are two records equal? This assumes they have the same type. Returns 0 for non-equal. */
int (*equal)(const void *a, const void *b, int hash_size);
+ /*
+ * Compare keys of two records with each other. The records must have
+ * the same type.
+ */
+ int (*cmp)(const void *a, const void *b);
+
/* Print on stdout, for debugging. */
void (*print)(const void *rec, int hash_size);
};
@@ -69,23 +81,29 @@ struct reftable_record_vtable {
/* returns true for recognized block types. Block start with the block type. */
int reftable_is_block_type(uint8_t typ);
-/* return an initialized record for the given type */
-struct reftable_record reftable_new_record(uint8_t typ);
-
/* Encode `key` into `dest`. Sets `is_restart` to indicate a restart. Returns
* number of bytes written. */
int reftable_encode_key(int *is_restart, struct string_view dest,
- struct strbuf prev_key, struct strbuf key,
+ struct reftable_buf prev_key, struct reftable_buf key,
uint8_t extra);
-/* Decode into `key` and `extra` from `in` */
-int reftable_decode_key(struct strbuf *key, uint8_t *extra,
- struct strbuf last_key, struct string_view in);
+/* Decode a record's key lengths. */
+int reftable_decode_keylen(struct string_view in,
+ uint64_t *prefix_len,
+ uint64_t *suffix_len,
+ uint8_t *extra);
+
+/*
+ * Decode into `last_key` and `extra` from `in`. `last_key` is expected to
+ * contain the decoded key of the preceding record, if any.
+ */
+int reftable_decode_key(struct reftable_buf *last_key, uint8_t *extra,
+ struct string_view in);
/* reftable_index_record are used internally to speed up lookups. */
struct reftable_index_record {
uint64_t offset; /* Offset of block */
- struct strbuf last_key; /* Last key of the block. */
+ struct reftable_buf last_key; /* Last key of the block. */
};
/* reftable_obj_record stores an object ID => ref mapping. */
@@ -100,8 +118,8 @@ struct reftable_obj_record {
/* record is a generic wrapper for different types of records. It is normally
* created on the stack, or embedded within another struct. If the type is
* known, a fresh instance can be initialized explicitly. Otherwise, use
- * reftable_new_record() to initialize generically (as the index_record is not
- * valid as 0-initialized structure)
+ * `reftable_record_init()` to initialize generically (as the index_record is
+ * not valid as 0-initialized structure)
*/
struct reftable_record {
uint8_t type;
@@ -113,21 +131,28 @@ struct reftable_record {
} u;
};
+/* Initialize the reftable record for the given type */
+void reftable_record_init(struct reftable_record *rec, uint8_t typ);
+
/* see struct record_vtable */
+int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
-void reftable_record_print(struct reftable_record *rec, int hash_size);
-void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
-uint8_t reftable_record_type(struct reftable_record *rec);
-void reftable_record_copy_from(struct reftable_record *rec,
- struct reftable_record *src, int hash_size);
+int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest);
+int reftable_record_copy_from(struct reftable_record *rec,
+ struct reftable_record *src, int hash_size);
uint8_t reftable_record_val_type(struct reftable_record *rec);
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
int hash_size);
-int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
+int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key,
uint8_t extra, struct string_view src,
- int hash_size);
+ int hash_size, struct reftable_buf *scratch);
int reftable_record_is_deletion(struct reftable_record *rec);
+static inline uint8_t reftable_record_type(struct reftable_record *rec)
+{
+ return rec->type;
+}
+
/* frees and zeroes out the embedded record */
void reftable_record_release(struct reftable_record *rec);
diff --git a/reftable/record_test.c b/reftable/record_test.c
deleted file mode 100644
index 70ae78feca..0000000000
--- a/reftable/record_test.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- Copyright 2020 Google LLC
-
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file or at
- https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "record.h"
-
-#include "system.h"
-#include "basics.h"
-#include "constants.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-static void test_copy(struct reftable_record *rec)
-{
- struct reftable_record copy = { 0 };
- uint8_t typ;
-
- typ = reftable_record_type(rec);
- copy = reftable_new_record(typ);
- reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
- /* do it twice to catch memory leaks */
- reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
- EXPECT(reftable_record_equal(rec, &copy, GIT_SHA1_RAWSZ));
-
- puts("testing print coverage:\n");
- reftable_record_print(&copy, GIT_SHA1_RAWSZ);
-
- reftable_record_release(&copy);
-}
-
-static void test_varint_roundtrip(void)
-{
- uint64_t inputs[] = { 0,
- 1,
- 27,
- 127,
- 128,
- 257,
- 4096,
- ((uint64_t)1 << 63),
- ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 };
- int i = 0;
- for (i = 0; i < ARRAY_SIZE(inputs); i++) {
- uint8_t dest[10];
-
- struct string_view out = {
- .buf = dest,
- .len = sizeof(dest),
- };
- uint64_t in = inputs[i];
- int n = put_var_int(&out, in);
- uint64_t got = 0;
-
- EXPECT(n > 0);
- out.len = n;
- n = get_var_int(&got, &out);
- EXPECT(n > 0);
-
- EXPECT(got == in);
- }
-}
-
-static void test_common_prefix(void)
-{
- struct {
- const char *a, *b;
- int want;
- } cases[] = {
- { "abc", "ab", 2 },
- { "", "abc", 0 },
- { "abc", "abd", 2 },
- { "abc", "pqr", 0 },
- };
-
- int i = 0;
- for (i = 0; i < ARRAY_SIZE(cases); i++) {
- struct strbuf a = STRBUF_INIT;
- struct strbuf b = STRBUF_INIT;
- strbuf_addstr(&a, cases[i].a);
- strbuf_addstr(&b, cases[i].b);
- EXPECT(common_prefix_size(&a, &b) == cases[i].want);
-
- strbuf_release(&a);
- strbuf_release(&b);
- }
-}
-
-static void set_hash(uint8_t *h, int j)
-{
- int i = 0;
- for (i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) {
- h[i] = (j >> i) & 0xff;
- }
-}
-
-static void test_reftable_ref_record_roundtrip(void)
-{
- int i = 0;
-
- for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
- struct reftable_record in = {
- .type = BLOCK_TYPE_REF,
- };
- struct reftable_record out = { .type = BLOCK_TYPE_REF };
- struct strbuf key = STRBUF_INIT;
- uint8_t buffer[1024] = { 0 };
- struct string_view dest = {
- .buf = buffer,
- .len = sizeof(buffer),
- };
- int n, m;
-
- in.u.ref.value_type = i;
- switch (i) {
- case REFTABLE_REF_DELETION:
- break;
- case REFTABLE_REF_VAL1:
- in.u.ref.value.val1 = reftable_malloc(GIT_SHA1_RAWSZ);
- set_hash(in.u.ref.value.val1, 1);
- break;
- case REFTABLE_REF_VAL2:
- in.u.ref.value.val2.value =
- reftable_malloc(GIT_SHA1_RAWSZ);
- set_hash(in.u.ref.value.val2.value, 1);
- in.u.ref.value.val2.target_value =
- reftable_malloc(GIT_SHA1_RAWSZ);
- set_hash(in.u.ref.value.val2.target_value, 2);
- break;
- case REFTABLE_REF_SYMREF:
- in.u.ref.value.symref = xstrdup("target");
- break;
- }
- in.u.ref.refname = xstrdup("refs/heads/master");
-
- test_copy(&in);
-
- EXPECT(reftable_record_val_type(&in) == i);
-
- reftable_record_key(&in, &key);
- n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
- EXPECT(n > 0);
-
- /* decode into a non-zero reftable_record to test for leaks. */
- m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ);
- EXPECT(n == m);
-
- EXPECT(reftable_ref_record_equal(&in.u.ref, &out.u.ref,
- GIT_SHA1_RAWSZ));
- reftable_record_release(&in);
-
- strbuf_release(&key);
- reftable_record_release(&out);
- }
-}
-
-static void test_reftable_log_record_equal(void)
-{
- struct reftable_log_record in[2] = {
- {
- .refname = xstrdup("refs/heads/master"),
- .update_index = 42,
- },
- {
- .refname = xstrdup("refs/heads/master"),
- .update_index = 22,
- }
- };
-
- EXPECT(!reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
- in[1].update_index = in[0].update_index;
- EXPECT(reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
- reftable_log_record_release(&in[0]);
- reftable_log_record_release(&in[1]);
-}
-
-static void test_reftable_log_record_roundtrip(void)
-{
- int i;
-
- struct reftable_log_record in[] = {
- {
- .refname = xstrdup("refs/heads/master"),
- .update_index = 42,
- .value_type = REFTABLE_LOG_UPDATE,
- .value = {
- .update = {
- .old_hash = reftable_malloc(GIT_SHA1_RAWSZ),
- .new_hash = reftable_malloc(GIT_SHA1_RAWSZ),
- .name = xstrdup("han-wen"),
- .email = xstrdup("hanwen@google.com"),
- .message = xstrdup("test"),
- .time = 1577123507,
- .tz_offset = 100,
- },
- }
- },
- {
- .refname = xstrdup("refs/heads/master"),
- .update_index = 22,
- .value_type = REFTABLE_LOG_DELETION,
- },
- {
- .refname = xstrdup("branch"),
- .update_index = 33,
- .value_type = REFTABLE_LOG_UPDATE,
- .value = {
- .update = {
- .old_hash = reftable_malloc(GIT_SHA1_RAWSZ),
- .new_hash = reftable_malloc(GIT_SHA1_RAWSZ),
- /* rest of fields left empty. */
- },
- },
- }
- };
- set_test_hash(in[0].value.update.new_hash, 1);
- set_test_hash(in[0].value.update.old_hash, 2);
- set_test_hash(in[2].value.update.new_hash, 3);
- set_test_hash(in[2].value.update.old_hash, 4);
- for (i = 0; i < ARRAY_SIZE(in); i++) {
- struct reftable_record rec = { .type = BLOCK_TYPE_LOG };
- struct strbuf key = STRBUF_INIT;
- uint8_t buffer[1024] = { 0 };
- struct string_view dest = {
- .buf = buffer,
- .len = sizeof(buffer),
- };
- /* populate out, to check for leaks. */
- struct reftable_record out = {
- .type = BLOCK_TYPE_LOG,
- .u.log = {
- .refname = xstrdup("old name"),
- .value_type = REFTABLE_LOG_UPDATE,
- .value = {
- .update = {
- .new_hash = reftable_calloc(GIT_SHA1_RAWSZ),
- .old_hash = reftable_calloc(GIT_SHA1_RAWSZ),
- .name = xstrdup("old name"),
- .email = xstrdup("old@email"),
- .message = xstrdup("old message"),
- },
- },
- },
- };
- int n, m, valtype;
-
- rec.u.log = in[i];
-
- test_copy(&rec);
-
- reftable_record_key(&rec, &key);
-
- n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
- EXPECT(n >= 0);
- valtype = reftable_record_val_type(&rec);
- m = reftable_record_decode(&out, key, valtype, dest,
- GIT_SHA1_RAWSZ);
- EXPECT(n == m);
-
- EXPECT(reftable_log_record_equal(&in[i], &out.u.log,
- GIT_SHA1_RAWSZ));
- reftable_log_record_release(&in[i]);
- strbuf_release(&key);
- reftable_record_release(&out);
- }
-}
-
-static void test_u24_roundtrip(void)
-{
- uint32_t in = 0x112233;
- uint8_t dest[3];
- uint32_t out;
- put_be24(dest, in);
- out = get_be24(dest);
- EXPECT(in == out);
-}
-
-static void test_key_roundtrip(void)
-{
- uint8_t buffer[1024] = { 0 };
- struct string_view dest = {
- .buf = buffer,
- .len = sizeof(buffer),
- };
- struct strbuf last_key = STRBUF_INIT;
- struct strbuf key = STRBUF_INIT;
- struct strbuf roundtrip = STRBUF_INIT;
- int restart;
- uint8_t extra;
- int n, m;
- uint8_t rt_extra;
-
- strbuf_addstr(&last_key, "refs/heads/master");
- strbuf_addstr(&key, "refs/tags/bla");
- extra = 6;
- n = reftable_encode_key(&restart, dest, last_key, key, extra);
- EXPECT(!restart);
- EXPECT(n > 0);
-
- m = reftable_decode_key(&roundtrip, &rt_extra, last_key, dest);
- EXPECT(n == m);
- EXPECT(0 == strbuf_cmp(&key, &roundtrip));
- EXPECT(rt_extra == extra);
-
- strbuf_release(&last_key);
- strbuf_release(&key);
- strbuf_release(&roundtrip);
-}
-
-static void test_reftable_obj_record_roundtrip(void)
-{
- uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 };
- uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 };
- struct reftable_obj_record recs[3] = { {
- .hash_prefix = testHash1,
- .hash_prefix_len = 5,
- .offsets = till9,
- .offset_len = 3,
- },
- {
- .hash_prefix = testHash1,
- .hash_prefix_len = 5,
- .offsets = till9,
- .offset_len = 9,
- },
- {
- .hash_prefix = testHash1,
- .hash_prefix_len = 5,
- } };
- int i = 0;
- for (i = 0; i < ARRAY_SIZE(recs); i++) {
- uint8_t buffer[1024] = { 0 };
- struct string_view dest = {
- .buf = buffer,
- .len = sizeof(buffer),
- };
- struct reftable_record in = {
- .type = BLOCK_TYPE_OBJ,
- .u = {
- .obj = recs[i],
- },
- };
- struct strbuf key = STRBUF_INIT;
- struct reftable_record out = { .type = BLOCK_TYPE_OBJ };
- int n, m;
- uint8_t extra;
-
- test_copy(&in);
- reftable_record_key(&in, &key);
- n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
- EXPECT(n > 0);
- extra = reftable_record_val_type(&in);
- m = reftable_record_decode(&out, key, extra, dest,
- GIT_SHA1_RAWSZ);
- EXPECT(n == m);
-
- EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
- strbuf_release(&key);
- reftable_record_release(&out);
- }
-}
-
-static void test_reftable_index_record_roundtrip(void)
-{
- struct reftable_record in = {
- .type = BLOCK_TYPE_INDEX,
- .u.idx = {
- .offset = 42,
- .last_key = STRBUF_INIT,
- },
- };
- uint8_t buffer[1024] = { 0 };
- struct string_view dest = {
- .buf = buffer,
- .len = sizeof(buffer),
- };
- struct strbuf key = STRBUF_INIT;
- struct reftable_record out = {
- .type = BLOCK_TYPE_INDEX,
- .u.idx = { .last_key = STRBUF_INIT },
- };
- int n, m;
- uint8_t extra;
-
- strbuf_addstr(&in.u.idx.last_key, "refs/heads/master");
- reftable_record_key(&in, &key);
- test_copy(&in);
-
- EXPECT(0 == strbuf_cmp(&key, &in.u.idx.last_key));
- n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
- EXPECT(n > 0);
-
- extra = reftable_record_val_type(&in);
- m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ);
- EXPECT(m == n);
-
- EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
-
- reftable_record_release(&out);
- strbuf_release(&key);
- strbuf_release(&in.u.idx.last_key);
-}
-
-int record_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_reftable_log_record_equal);
- RUN_TEST(test_reftable_log_record_roundtrip);
- RUN_TEST(test_reftable_ref_record_roundtrip);
- RUN_TEST(test_varint_roundtrip);
- RUN_TEST(test_key_roundtrip);
- RUN_TEST(test_common_prefix);
- RUN_TEST(test_reftable_obj_record_roundtrip);
- RUN_TEST(test_reftable_index_record_roundtrip);
- RUN_TEST(test_u24_roundtrip);
- return 0;
-}
diff --git a/reftable/refname.c b/reftable/refname.c
deleted file mode 100644
index 9573496932..0000000000
--- a/reftable/refname.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- Copyright 2020 Google LLC
-
- Use of this source code is governed by a BSD-style
- 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 "basics.h"
-#include "refname.h"
-#include "reftable-iterator.h"
-
-struct find_arg {
- char **names;
- const char *want;
-};
-
-static int find_name(size_t k, void *arg)
-{
- struct find_arg *f_arg = arg;
- return strcmp(f_arg->names[k], f_arg->want) >= 0;
-}
-
-static int modification_has_ref(struct modification *mod, const char *name)
-{
- struct reftable_ref_record ref = { NULL };
- int err = 0;
-
- if (mod->add_len > 0) {
- struct find_arg arg = {
- .names = mod->add,
- .want = name,
- };
- int idx = binsearch(mod->add_len, find_name, &arg);
- if (idx < mod->add_len && !strcmp(mod->add[idx], name)) {
- return 0;
- }
- }
-
- if (mod->del_len > 0) {
- struct find_arg arg = {
- .names = mod->del,
- .want = name,
- };
- int idx = binsearch(mod->del_len, find_name, &arg);
- if (idx < mod->del_len && !strcmp(mod->del[idx], name)) {
- return 1;
- }
- }
-
- err = reftable_table_read_ref(&mod->tab, name, &ref);
- reftable_ref_record_release(&ref);
- return err;
-}
-
-static void modification_release(struct modification *mod)
-{
- /* don't delete the strings themselves; they're owned by ref records.
- */
- FREE_AND_NULL(mod->add);
- FREE_AND_NULL(mod->del);
- mod->add_len = 0;
- mod->del_len = 0;
-}
-
-static int modification_has_ref_with_prefix(struct modification *mod,
- const char *prefix)
-{
- struct reftable_iterator it = { NULL };
- struct reftable_ref_record ref = { NULL };
- int err = 0;
-
- if (mod->add_len > 0) {
- struct find_arg arg = {
- .names = mod->add,
- .want = prefix,
- };
- int idx = binsearch(mod->add_len, find_name, &arg);
- if (idx < mod->add_len &&
- !strncmp(prefix, mod->add[idx], strlen(prefix)))
- goto done;
- }
- err = reftable_table_seek_ref(&mod->tab, &it, prefix);
- if (err)
- goto done;
-
- while (1) {
- err = reftable_iterator_next_ref(&it, &ref);
- if (err)
- goto done;
-
- if (mod->del_len > 0) {
- struct find_arg arg = {
- .names = mod->del,
- .want = ref.refname,
- };
- int idx = binsearch(mod->del_len, find_name, &arg);
- if (idx < mod->del_len &&
- !strcmp(ref.refname, mod->del[idx])) {
- continue;
- }
- }
-
- if (strncmp(ref.refname, prefix, strlen(prefix))) {
- err = 1;
- goto done;
- }
- err = 0;
- goto done;
- }
-
-done:
- reftable_ref_record_release(&ref);
- reftable_iterator_destroy(&it);
- return err;
-}
-
-static int validate_refname(const char *name)
-{
- while (1) {
- char *next = strchr(name, '/');
- if (!*name) {
- return REFTABLE_REFNAME_ERROR;
- }
- if (!next) {
- return 0;
- }
- if (next - name == 0 || (next - name == 1 && *name == '.') ||
- (next - name == 2 && name[0] == '.' && name[1] == '.'))
- return REFTABLE_REFNAME_ERROR;
- name = next + 1;
- }
- return 0;
-}
-
-int validate_ref_record_addition(struct reftable_table tab,
- struct reftable_ref_record *recs, size_t sz)
-{
- struct modification mod = {
- .tab = tab,
- .add = reftable_calloc(sizeof(char *) * sz),
- .del = reftable_calloc(sizeof(char *) * sz),
- };
- int i = 0;
- int err = 0;
- for (; i < sz; i++) {
- if (reftable_ref_record_is_deletion(&recs[i])) {
- mod.del[mod.del_len++] = recs[i].refname;
- } else {
- mod.add[mod.add_len++] = recs[i].refname;
- }
- }
-
- err = modification_validate(&mod);
- modification_release(&mod);
- return err;
-}
-
-static void strbuf_trim_component(struct strbuf *sl)
-{
- while (sl->len > 0) {
- int is_slash = (sl->buf[sl->len - 1] == '/');
- strbuf_setlen(sl, sl->len - 1);
- if (is_slash)
- break;
- }
-}
-
-int modification_validate(struct modification *mod)
-{
- struct strbuf slashed = STRBUF_INIT;
- int err = 0;
- int i = 0;
- for (; i < mod->add_len; i++) {
- err = validate_refname(mod->add[i]);
- if (err)
- goto done;
- strbuf_reset(&slashed);
- strbuf_addstr(&slashed, mod->add[i]);
- strbuf_addstr(&slashed, "/");
-
- err = modification_has_ref_with_prefix(mod, slashed.buf);
- if (err == 0) {
- err = REFTABLE_NAME_CONFLICT;
- goto done;
- }
- if (err < 0)
- goto done;
-
- strbuf_reset(&slashed);
- strbuf_addstr(&slashed, mod->add[i]);
- while (slashed.len) {
- strbuf_trim_component(&slashed);
- err = modification_has_ref(mod, slashed.buf);
- if (err == 0) {
- err = REFTABLE_NAME_CONFLICT;
- goto done;
- }
- if (err < 0)
- goto done;
- }
- }
- err = 0;
-done:
- strbuf_release(&slashed);
- return err;
-}
diff --git a/reftable/refname.h b/reftable/refname.h
deleted file mode 100644
index a24b40fcb4..0000000000
--- a/reftable/refname.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- Copyright 2020 Google LLC
-
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file or at
- https://developers.google.com/open-source/licenses/bsd
-*/
-#ifndef REFNAME_H
-#define REFNAME_H
-
-#include "reftable-record.h"
-#include "reftable-generic.h"
-
-struct modification {
- struct reftable_table tab;
-
- char **add;
- size_t add_len;
-
- char **del;
- size_t del_len;
-};
-
-int validate_ref_record_addition(struct reftable_table tab,
- struct reftable_ref_record *recs, size_t sz);
-
-int modification_validate(struct modification *mod);
-
-#endif
diff --git a/reftable/refname_test.c b/reftable/refname_test.c
deleted file mode 100644
index 8645cd93bb..0000000000
--- a/reftable/refname_test.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "basics.h"
-#include "block.h"
-#include "blocksource.h"
-#include "constants.h"
-#include "reader.h"
-#include "record.h"
-#include "refname.h"
-#include "reftable-error.h"
-#include "reftable-writer.h"
-#include "system.h"
-
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-struct testcase {
- char *add;
- char *del;
- int error_code;
-};
-
-static void test_conflict(void)
-{
- struct reftable_write_options opts = { 0 };
- struct strbuf buf = STRBUF_INIT;
- struct reftable_writer *w =
- reftable_new_writer(&strbuf_add_void, &buf, &opts);
- struct reftable_ref_record rec = {
- .refname = "a/b",
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "destination", /* make sure it's not a symref.
- */
- .update_index = 1,
- };
- int err;
- int i;
- struct reftable_block_source source = { NULL };
- struct reftable_reader *rd = NULL;
- struct reftable_table tab = { NULL };
- struct testcase cases[] = {
- { "a/b/c", NULL, REFTABLE_NAME_CONFLICT },
- { "b", NULL, 0 },
- { "a", NULL, REFTABLE_NAME_CONFLICT },
- { "a", "a/b", 0 },
-
- { "p/", NULL, REFTABLE_REFNAME_ERROR },
- { "p//q", NULL, REFTABLE_REFNAME_ERROR },
- { "p/./q", NULL, REFTABLE_REFNAME_ERROR },
- { "p/../q", NULL, REFTABLE_REFNAME_ERROR },
-
- { "a/b/c", "a/b", 0 },
- { NULL, "a//b", 0 },
- };
- reftable_writer_set_limits(w, 1, 1);
-
- err = reftable_writer_add_ref(w, &rec);
- EXPECT_ERR(err);
-
- err = reftable_writer_close(w);
- EXPECT_ERR(err);
- reftable_writer_free(w);
-
- block_source_from_strbuf(&source, &buf);
- err = reftable_new_reader(&rd, &source, "filename");
- EXPECT_ERR(err);
-
- reftable_table_from_reader(&tab, rd);
-
- for (i = 0; i < ARRAY_SIZE(cases); i++) {
- struct modification mod = {
- .tab = tab,
- };
-
- if (cases[i].add) {
- mod.add = &cases[i].add;
- mod.add_len = 1;
- }
- if (cases[i].del) {
- mod.del = &cases[i].del;
- mod.del_len = 1;
- }
-
- err = modification_validate(&mod);
- EXPECT(err == cases[i].error_code);
- }
-
- reftable_reader_free(rd);
- strbuf_release(&buf);
-}
-
-int refname_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_conflict);
- return 0;
-}
diff --git a/reftable/reftable-basics.h b/reftable/reftable-basics.h
new file mode 100644
index 0000000000..6e8e636b71
--- /dev/null
+++ b/reftable/reftable-basics.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://developers.google.com/open-source/licenses/bsd
+*/
+
+#ifndef REFTABLE_BASICS_H
+#define REFTABLE_BASICS_H
+
+#include <stddef.h>
+
+/* Overrides the functions to use for memory management. */
+void reftable_set_alloc(void *(*malloc)(size_t),
+ void *(*realloc)(void *, size_t), void (*free)(void *));
+
+#endif
diff --git a/reftable/reftable-error.h b/reftable/reftable-error.h
index 4c457aaaf8..f404826562 100644
--- a/reftable/reftable-error.h
+++ b/reftable/reftable-error.h
@@ -25,7 +25,7 @@ enum reftable_error {
*/
REFTABLE_NOT_EXIST_ERROR = -4,
- /* Trying to write out-of-date data. */
+ /* Trying to access locked data. */
REFTABLE_LOCK_ERROR = -5,
/* Misuse of the API:
@@ -48,15 +48,18 @@ enum reftable_error {
/* Wrote a table without blocks. */
REFTABLE_EMPTY_TABLE_ERROR = -8,
- /* Dir/file conflict. */
- REFTABLE_NAME_CONFLICT = -9,
-
/* Invalid ref name. */
REFTABLE_REFNAME_ERROR = -10,
/* Entry does not fit. This can happen when writing outsize reflog
messages. */
REFTABLE_ENTRY_TOO_BIG_ERROR = -11,
+
+ /* Trying to write out-of-date data. */
+ REFTABLE_OUTDATED_ERROR = -12,
+
+ /* An allocation has failed due to an out-of-memory situation. */
+ REFTABLE_OUT_OF_MEMORY_ERROR = -13,
};
/* convert the numeric error code to a string. The string should not be
diff --git a/reftable/reftable-generic.h b/reftable/reftable-generic.h
deleted file mode 100644
index d239751a77..0000000000
--- a/reftable/reftable-generic.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_GENERIC_H
-#define REFTABLE_GENERIC_H
-
-#include "reftable-iterator.h"
-
-struct reftable_table_vtable;
-
-/*
- * Provides a unified API for reading tables, either merged tables, or single
- * readers. */
-struct reftable_table {
- struct reftable_table_vtable *ops;
- void *table_arg;
-};
-
-int reftable_table_seek_log(struct reftable_table *tab,
- struct reftable_iterator *it, const char *name);
-
-int reftable_table_seek_ref(struct reftable_table *tab,
- struct reftable_iterator *it, const char *name);
-
-/* returns the hash ID from a generic reftable_table */
-uint32_t reftable_table_hash_id(struct reftable_table *tab);
-
-/* returns the max update_index covered by this table. */
-uint64_t reftable_table_max_update_index(struct reftable_table *tab);
-
-/* returns the min update_index covered by this table. */
-uint64_t reftable_table_min_update_index(struct reftable_table *tab);
-
-/* convenience function to read a single ref. Returns < 0 for error, 0
- for success, and 1 if ref not found. */
-int reftable_table_read_ref(struct reftable_table *tab, const char *name,
- struct reftable_ref_record *ref);
-
-/* dump table contents onto stdout for debugging */
-int reftable_table_print(struct reftable_table *tab);
-
-#endif
diff --git a/reftable/reftable-iterator.h b/reftable/reftable-iterator.h
index d3eee7af35..e3bf688d53 100644
--- a/reftable/reftable-iterator.h
+++ b/reftable/reftable-iterator.h
@@ -21,12 +21,33 @@ struct reftable_iterator {
void *iter_arg;
};
+/*
+ * Position the iterator at the ref record with given name such that the next
+ * call to `next_ref()` would yield the record.
+ */
+int reftable_iterator_seek_ref(struct reftable_iterator *it,
+ const char *name);
+
/* reads the next reftable_ref_record. Returns < 0 for error, 0 for OK and > 0:
* end of iteration.
*/
int reftable_iterator_next_ref(struct reftable_iterator *it,
struct reftable_ref_record *ref);
+/*
+ * Position the iterator at the log record with given name and update index
+ * such that the next call to `next_log()` would yield the record.
+ */
+int reftable_iterator_seek_log_at(struct reftable_iterator *it,
+ const char *name, uint64_t update_index);
+
+/*
+ * Position the iterator at the newest log record with given name such that the
+ * next call to `next_log()` would yield the record.
+ */
+int reftable_iterator_seek_log(struct reftable_iterator *it,
+ const char *name);
+
/* reads the next reftable_log_record. Returns < 0 for error, 0 for OK and > 0:
* end of iteration.
*/
diff --git a/reftable/reftable-malloc.h b/reftable/reftable-malloc.h
deleted file mode 100644
index 5f2185f1f3..0000000000
--- a/reftable/reftable-malloc.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_H
-#define REFTABLE_H
-
-#include <stddef.h>
-
-/* Overrides the functions to use for memory management. */
-void reftable_set_alloc(void *(*malloc)(size_t),
- void *(*realloc)(void *, size_t), void (*free)(void *));
-
-#endif
diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h
index 1a6d16915a..a970d5dd89 100644
--- a/reftable/reftable-merged.h
+++ b/reftable/reftable-merged.h
@@ -26,30 +26,23 @@ https://developers.google.com/open-source/licenses/bsd
/* A merged table is implements seeking/iterating over a stack of tables. */
struct reftable_merged_table;
-/* A generic reftable; see below. */
-struct reftable_table;
+struct reftable_reader;
-/* reftable_new_merged_table creates a new merged table. It takes ownership of
- the stack array.
-*/
-int reftable_new_merged_table(struct reftable_merged_table **dest,
- struct reftable_table *stack, int n,
+/*
+ * reftable_merged_table_new creates a new merged table. The readers must be
+ * kept alive as long as the merged table is still in use.
+ */
+int reftable_merged_table_new(struct reftable_merged_table **dest,
+ struct reftable_reader **readers, size_t n,
uint32_t hash_id);
-/* returns an iterator positioned just before 'name' */
-int reftable_merged_table_seek_ref(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- const char *name);
+/* Initialize a merged table iterator for reading refs. */
+int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it);
-/* returns an iterator for log entry, at given update_index */
-int reftable_merged_table_seek_log_at(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- const char *name, uint64_t update_index);
-
-/* like reftable_merged_table_seek_log_at but look for the newest entry. */
-int reftable_merged_table_seek_log(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- const char *name);
+/* Initialize a merged table iterator for reading logs. */
+int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it);
/* returns the max update_index covered by this merged table. */
uint64_t
@@ -65,8 +58,4 @@ void reftable_merged_table_free(struct reftable_merged_table *m);
/* return the hash ID of the merged table. */
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
-/* create a generic table from reftable_merged_table */
-void reftable_table_from_merged_table(struct reftable_table *tab,
- struct reftable_merged_table *table);
-
#endif
diff --git a/reftable/reftable-reader.h b/reftable/reftable-reader.h
index 4a4bc2fdf8..6a2d0b693f 100644
--- a/reftable/reftable-reader.h
+++ b/reftable/reftable-reader.h
@@ -23,64 +23,39 @@
/* The reader struct is a handle to an open reftable file. */
struct reftable_reader;
-/* Generic table. */
-struct reftable_table;
-
-/* reftable_new_reader opens a reftable for reading. If successful,
+/* reftable_reader_new opens a reftable for reading. If successful,
* returns 0 code and sets pp. The name is used for creating a
* stack. Typically, it is the basename of the file. The block source
* `src` is owned by the reader, and is closed on calling
* reftable_reader_destroy(). On error, the block source `src` is
* closed as well.
*/
-int reftable_new_reader(struct reftable_reader **pp,
+int reftable_reader_new(struct reftable_reader **pp,
struct reftable_block_source *src, const char *name);
-/* reftable_reader_seek_ref returns an iterator where 'name' would be inserted
- in the table. To seek to the start of the table, use name = "".
+/*
+ * Manage the reference count of the reftable reader. A newly initialized
+ * reader starts with a refcount of 1 and will be deleted once the refcount has
+ * reached 0.
+ *
+ * This is required because readers may have longer lifetimes than the stack
+ * they belong to. The stack may for example be reloaded while the old tables
+ * are still being accessed by an iterator.
+ */
+void reftable_reader_incref(struct reftable_reader *reader);
+void reftable_reader_decref(struct reftable_reader *reader);
- example:
+/* Initialize a reftable iterator for reading refs. */
+int reftable_reader_init_ref_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it);
- struct reftable_reader *r = NULL;
- int err = reftable_new_reader(&r, &src, "filename");
- if (err < 0) { ... }
- struct reftable_iterator it = {0};
- err = reftable_reader_seek_ref(r, &it, "refs/heads/master");
- if (err < 0) { ... }
- struct reftable_ref_record ref = {0};
- while (1) {
- err = reftable_iterator_next_ref(&it, &ref);
- if (err > 0) {
- break;
- }
- if (err < 0) {
- ..error handling..
- }
- ..found..
- }
- reftable_iterator_destroy(&it);
- reftable_ref_record_release(&ref);
-*/
-int reftable_reader_seek_ref(struct reftable_reader *r,
- struct reftable_iterator *it, const char *name);
+/* Initialize a reftable iterator for reading logs. */
+int reftable_reader_init_log_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it);
/* returns the hash ID used in this table. */
uint32_t reftable_reader_hash_id(struct reftable_reader *r);
-/* seek to logs for the given name, older than update_index. To seek to the
- start of the table, use name = "".
-*/
-int reftable_reader_seek_log_at(struct reftable_reader *r,
- struct reftable_iterator *it, const char *name,
- uint64_t update_index);
-
-/* seek to newest log entry for given name. */
-int reftable_reader_seek_log(struct reftable_reader *r,
- struct reftable_iterator *it, const char *name);
-
-/* closes and deallocates a reader. */
-void reftable_reader_free(struct reftable_reader *);
-
/* return an iterator for the refs pointing to `oid`. */
int reftable_reader_refs_for(struct reftable_reader *r,
struct reftable_iterator *it, uint8_t *oid);
@@ -91,11 +66,7 @@ uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
/* return the min_update_index for a table */
uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
-/* creates a generic table from a file reader. */
-void reftable_table_from_reader(struct reftable_table *tab,
- struct reftable_reader *reader);
-
-/* print table onto stdout for debugging. */
-int reftable_reader_print_file(const char *tablename);
+/* print blocks onto stdout for debugging. */
+int reftable_reader_print_blocks(const char *tablename);
#endif
diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h
index 67104f8fbf..2d42463c58 100644
--- a/reftable/reftable-record.h
+++ b/reftable/reftable-record.h
@@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd
#ifndef REFTABLE_RECORD_H
#define REFTABLE_RECORD_H
+#include "hash.h"
#include <stdint.h>
/*
@@ -21,6 +22,7 @@ https://developers.google.com/open-source/licenses/bsd
/* reftable_ref_record holds a ref database entry target_value */
struct reftable_ref_record {
char *refname; /* Name of the ref, malloced. */
+ size_t refname_cap;
uint64_t update_index; /* Logical timestamp at which this value is
* written */
@@ -38,10 +40,10 @@ struct reftable_ref_record {
#define REFTABLE_NR_REF_VALUETYPES 4
} value_type;
union {
- uint8_t *val1; /* malloced hash. */
+ unsigned char val1[GIT_MAX_RAWSZ];
struct {
- uint8_t *value; /* first value, malloced hash */
- uint8_t *target_value; /* second value, malloced hash */
+ unsigned char value[GIT_MAX_RAWSZ]; /* first hash */
+ unsigned char target_value[GIT_MAX_RAWSZ]; /* second hash */
} val2;
char *symref; /* referent, malloced 0-terminated string */
} value;
@@ -49,19 +51,15 @@ struct reftable_ref_record {
/* Returns the first hash, or NULL if `rec` is not of type
* REFTABLE_REF_VAL1 or REFTABLE_REF_VAL2. */
-uint8_t *reftable_ref_record_val1(const struct reftable_ref_record *rec);
+const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec);
/* Returns the second hash, or NULL if `rec` is not of type
* REFTABLE_REF_VAL2. */
-uint8_t *reftable_ref_record_val2(const struct reftable_ref_record *rec);
+const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec);
/* returns whether 'ref' represents a deletion */
int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
-/* prints a reftable_ref_record onto stdout. Useful for debugging. */
-void reftable_ref_record_print(const struct reftable_ref_record *ref,
- uint32_t hash_id);
-
/* frees and nulls all pointer values inside `ref`. */
void reftable_ref_record_release(struct reftable_ref_record *ref);
@@ -72,6 +70,7 @@ int reftable_ref_record_equal(const struct reftable_ref_record *a,
/* reftable_log_record holds a reflog entry */
struct reftable_log_record {
char *refname;
+ size_t refname_cap;
uint64_t update_index; /* logical timestamp of a transactional update.
*/
@@ -86,13 +85,14 @@ struct reftable_log_record {
union {
struct {
- uint8_t *new_hash;
- uint8_t *old_hash;
+ unsigned char new_hash[GIT_MAX_RAWSZ];
+ unsigned char old_hash[GIT_MAX_RAWSZ];
char *name;
char *email;
uint64_t time;
int16_t tz_offset;
char *message;
+ size_t message_cap;
} update;
} value;
};
@@ -107,8 +107,4 @@ void reftable_log_record_release(struct reftable_log_record *log);
int reftable_log_record_equal(const struct reftable_log_record *a,
const struct reftable_log_record *b, int hash_size);
-/* dumps a reftable_log_record on stdout, for debugging/testing. */
-void reftable_log_record_print(struct reftable_log_record *log,
- uint32_t hash_id);
-
#endif
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index 1b602dda58..54787f2ef5 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -29,7 +29,7 @@ struct reftable_stack;
* stored in 'dir'. Typically, this should be .git/reftables.
*/
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
- struct reftable_write_options config);
+ const struct reftable_write_options *opts);
/* returns the update_index at which a next table should be written. */
uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
@@ -37,12 +37,21 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
/* holds a transaction to add tables at the top of a stack. */
struct reftable_addition;
+enum {
+ /*
+ * Reload the stack when the stack is out-of-date after locking it.
+ */
+ REFTABLE_STACK_NEW_ADDITION_RELOAD = (1 << 0),
+};
+
/*
* returns a new transaction to add reftables to the given stack. As a side
- * effect, the ref database is locked.
+ * effect, the ref database is locked. Accepts REFTABLE_STACK_NEW_ADDITION_*
+ * flags.
*/
int reftable_stack_new_addition(struct reftable_addition **dest,
- struct reftable_stack *st);
+ struct reftable_stack *st,
+ unsigned int flags);
/* Adds a reftable to transaction. */
int reftable_addition_add(struct reftable_addition *add,
@@ -66,6 +75,24 @@ int reftable_stack_add(struct reftable_stack *st,
void *write_arg),
void *write_arg);
+struct reftable_iterator;
+
+/*
+ * Initialize an iterator for the merged tables contained in the stack that can
+ * be used to iterate through refs. The iterator is valid until the next reload
+ * or write.
+ */
+int reftable_stack_init_ref_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it);
+
+/*
+ * Initialize an iterator for the merged tables contained in the stack that can
+ * be used to iterate through logs. The iterator is valid until the next reload
+ * or write.
+ */
+int reftable_stack_init_log_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it);
+
/* returns the merged_table for seeking. This table is valid until the
* next write or reload, and should not be closed or deleted.
*/
@@ -122,7 +149,4 @@ struct reftable_compaction_stats {
struct reftable_compaction_stats *
reftable_stack_compaction_stats(struct reftable_stack *st);
-/* print the entire stack represented by the directory */
-int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id);
-
#endif
diff --git a/reftable/reftable-tests.h b/reftable/reftable-tests.h
deleted file mode 100644
index 0019cbcfa4..0000000000
--- a/reftable/reftable-tests.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_TESTS_H
-#define REFTABLE_TESTS_H
-
-int basics_test_main(int argc, const char **argv);
-int block_test_main(int argc, const char **argv);
-int merged_test_main(int argc, const char **argv);
-int pq_test_main(int argc, const char **argv);
-int record_test_main(int argc, const char **argv);
-int refname_test_main(int argc, const char **argv);
-int readwrite_test_main(int argc, const char **argv);
-int stack_test_main(int argc, const char **argv);
-int tree_test_main(int argc, const char **argv);
-int reftable_dump_main(int argc, char *const *argv);
-
-#endif
diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h
index db8de197f6..e4fc953788 100644
--- a/reftable/reftable-writer.h
+++ b/reftable/reftable-writer.h
@@ -28,7 +28,7 @@ struct reftable_write_options {
unsigned skip_index_objects : 1;
/* how often to write complete keys in each block. */
- int restart_interval;
+ uint16_t restart_interval;
/* 4-byte identifier ("sha1", "s256") of the hash.
* Defaults to SHA1 if unset
@@ -38,14 +38,30 @@ struct reftable_write_options {
/* Default mode for creating files. If unset, use 0666 (+umask) */
unsigned int default_permissions;
- /* boolean: do not check ref names for validity or dir/file conflicts.
- */
- unsigned skip_name_check : 1;
-
/* boolean: copy log messages exactly. If unset, check that the message
* is a single line, and add '\n' if missing.
*/
unsigned exact_log_message : 1;
+
+ /* boolean: Prevent auto-compaction of tables. */
+ unsigned disable_auto_compact : 1;
+
+ /*
+ * Geometric sequence factor used by auto-compaction to decide which
+ * tables to compact. Defaults to 2 if unset.
+ */
+ uint8_t auto_compaction_factor;
+
+ /*
+ * The number of milliseconds to wait when trying to lock "tables.list".
+ * Note that this does not apply to locking individual tables, as these
+ * should only ever be locked when already holding the "tables.list"
+ * lock.
+ *
+ * Passing 0 will fail immediately when the file is locked, passing a
+ * negative value will cause us to block indefinitely.
+ */
+ long lock_timeout_ms;
};
/* reftable_block_stats holds statistics for a single block type */
@@ -85,10 +101,13 @@ struct reftable_stats {
int object_id_len;
};
-/* reftable_new_writer creates a new writer */
-struct reftable_writer *
-reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
- void *writer_arg, struct reftable_write_options *opts);
+struct reftable_writer;
+
+/* Create a new writer. */
+int reftable_writer_new(struct reftable_writer **out,
+ ssize_t (*writer_func)(void *, const void *, size_t),
+ int (*flush_func)(void *),
+ void *writer_arg, const struct reftable_write_options *opts);
/* Set the range of update indices for the records we will add. When writing a
table into a stack, the min should be at least
diff --git a/reftable/stack.c b/reftable/stack.c
index ddbdf1b9c8..c33979536e 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -8,71 +8,99 @@ https://developers.google.com/open-source/licenses/bsd
#include "stack.h"
+#include "../write-or-die.h"
#include "system.h"
+#include "constants.h"
#include "merged.h"
#include "reader.h"
-#include "refname.h"
#include "reftable-error.h"
#include "reftable-record.h"
#include "reftable-merged.h"
#include "writer.h"
+#include "tempfile.h"
static int stack_try_add(struct reftable_stack *st,
int (*write_table)(struct reftable_writer *wr,
void *arg),
void *arg);
static int stack_write_compact(struct reftable_stack *st,
- struct reftable_writer *wr, int first, int last,
+ struct reftable_writer *wr,
+ size_t first, size_t last,
struct reftable_log_expiry_config *config);
-static int stack_check_addition(struct reftable_stack *st,
- const char *new_tab_name);
static void reftable_addition_close(struct reftable_addition *add);
static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
int reuse_open);
-static void stack_filename(struct strbuf *dest, struct reftable_stack *st,
- const char *name)
+static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st,
+ const char *name)
{
- strbuf_reset(dest);
- strbuf_addstr(dest, st->reftable_dir);
- strbuf_addstr(dest, "/");
- strbuf_addstr(dest, name);
+ int err;
+ reftable_buf_reset(dest);
+ if ((err = reftable_buf_addstr(dest, st->reftable_dir)) < 0 ||
+ (err = reftable_buf_addstr(dest, "/")) < 0 ||
+ (err = reftable_buf_addstr(dest, name)) < 0)
+ return err;
+ return 0;
}
static ssize_t reftable_fd_write(void *arg, const void *data, size_t sz)
{
int *fdp = (int *)arg;
- return write(*fdp, data, sz);
+ return write_in_full(*fdp, data, sz);
+}
+
+static int reftable_fd_flush(void *arg)
+{
+ int *fdp = (int *)arg;
+
+ return fsync_component(FSYNC_COMPONENT_REFERENCE, *fdp);
}
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
- struct reftable_write_options config)
+ const struct reftable_write_options *_opts)
{
- struct reftable_stack *p =
- reftable_calloc(sizeof(struct reftable_stack));
- struct strbuf list_file_name = STRBUF_INIT;
- int err = 0;
+ struct reftable_buf list_file_name = REFTABLE_BUF_INIT;
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *p;
+ int err;
- if (config.hash_id == 0) {
- config.hash_id = GIT_SHA1_FORMAT_ID;
+ p = reftable_calloc(1, sizeof(*p));
+ if (!p) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
+ if (_opts)
+ opts = *_opts;
+ if (opts.hash_id == 0)
+ opts.hash_id = GIT_SHA1_FORMAT_ID;
+
*dest = NULL;
- strbuf_reset(&list_file_name);
- strbuf_addstr(&list_file_name, dir);
- strbuf_addstr(&list_file_name, "/tables.list");
+ reftable_buf_reset(&list_file_name);
+ if ((err = reftable_buf_addstr(&list_file_name, dir)) < 0 ||
+ (err = reftable_buf_addstr(&list_file_name, "/tables.list")) < 0)
+ goto out;
- p->list_file = strbuf_detach(&list_file_name, NULL);
- p->reftable_dir = xstrdup(dir);
- p->config = config;
+ p->list_file = reftable_buf_detach(&list_file_name);
+ p->list_fd = -1;
+ p->opts = opts;
+ p->reftable_dir = reftable_strdup(dir);
+ if (!p->reftable_dir) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
err = reftable_stack_reload_maybe_reuse(p, 1);
- if (err < 0) {
+ if (err < 0)
+ goto out;
+
+ *dest = p;
+ err = 0;
+
+out:
+ if (err < 0)
reftable_stack_destroy(p);
- } else {
- *dest = p;
- }
return err;
}
@@ -91,14 +119,23 @@ static int fd_read_lines(int fd, char ***namesp)
goto done;
}
- buf = reftable_malloc(size + 1);
- if (read(fd, buf, size) != size) {
+ REFTABLE_ALLOC_ARRAY(buf, size + 1);
+ if (!buf) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ if (read_in_full(fd, buf, size) != size) {
err = REFTABLE_IO_ERROR;
goto done;
}
buf[size] = 0;
- parse_names(buf, size, namesp);
+ *namesp = parse_names(buf, size);
+ if (!*namesp) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
done:
reftable_free(buf);
@@ -111,7 +148,9 @@ int read_lines(const char *filename, char ***namesp)
int err = 0;
if (fd < 0) {
if (errno == ENOENT) {
- *namesp = reftable_calloc(sizeof(char *));
+ REFTABLE_CALLOC_ARRAY(*namesp, 1);
+ if (!*namesp)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
return 0;
}
@@ -122,6 +161,20 @@ int read_lines(const char *filename, char ***namesp)
return err;
}
+int reftable_stack_init_ref_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it)
+{
+ return merged_table_init_iter(reftable_stack_merged_table(st),
+ it, BLOCK_TYPE_REF);
+}
+
+int reftable_stack_init_log_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it)
+{
+ return merged_table_init_iter(reftable_stack_merged_table(st),
+ it, BLOCK_TYPE_LOG);
+}
+
struct reftable_merged_table *
reftable_stack_merged_table(struct reftable_stack *st)
{
@@ -143,6 +196,10 @@ void reftable_stack_destroy(struct reftable_stack *st)
{
char **names = NULL;
int err = 0;
+
+ if (!st)
+ return;
+
if (st->merged) {
reftable_merged_table_free(st->merged);
st->merged = NULL;
@@ -150,144 +207,188 @@ void reftable_stack_destroy(struct reftable_stack *st)
err = read_lines(st->list_file, &names);
if (err < 0) {
- FREE_AND_NULL(names);
+ REFTABLE_FREE_AND_NULL(names);
}
if (st->readers) {
int i = 0;
- struct strbuf filename = STRBUF_INIT;
+ struct reftable_buf filename = REFTABLE_BUF_INIT;
for (i = 0; i < st->readers_len; i++) {
const char *name = reader_name(st->readers[i]);
- strbuf_reset(&filename);
+ int try_unlinking = 1;
+
+ reftable_buf_reset(&filename);
if (names && !has_name(names, name)) {
- stack_filename(&filename, st, name);
+ if (stack_filename(&filename, st, name) < 0)
+ try_unlinking = 0;
}
- reftable_reader_free(st->readers[i]);
+ reftable_reader_decref(st->readers[i]);
- if (filename.len) {
+ if (try_unlinking && filename.len) {
/* On Windows, can only unlink after closing. */
unlink(filename.buf);
}
}
- strbuf_release(&filename);
+ reftable_buf_release(&filename);
st->readers_len = 0;
- FREE_AND_NULL(st->readers);
+ REFTABLE_FREE_AND_NULL(st->readers);
+ }
+
+ if (st->list_fd >= 0) {
+ close(st->list_fd);
+ st->list_fd = -1;
}
- FREE_AND_NULL(st->list_file);
- FREE_AND_NULL(st->reftable_dir);
+
+ REFTABLE_FREE_AND_NULL(st->list_file);
+ REFTABLE_FREE_AND_NULL(st->reftable_dir);
reftable_free(st);
free_names(names);
}
static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
- int cur_len)
+ size_t cur_len)
{
- struct reftable_reader **cur =
- reftable_calloc(sizeof(struct reftable_reader *) * cur_len);
- int i = 0;
- for (i = 0; i < cur_len; i++) {
+ struct reftable_reader **cur = reftable_calloc(cur_len, sizeof(*cur));
+ if (!cur)
+ return NULL;
+ for (size_t i = 0; i < cur_len; i++)
cur[i] = st->readers[i];
- }
return cur;
}
-static int reftable_stack_reload_once(struct reftable_stack *st, char **names,
+static int reftable_stack_reload_once(struct reftable_stack *st,
+ const char **names,
int reuse_open)
{
- int cur_len = !st->merged ? 0 : st->merged->stack_len;
- struct reftable_reader **cur = stack_copy_readers(st, cur_len);
- int err = 0;
- int names_len = names_length(names);
- struct reftable_reader **new_readers =
- reftable_calloc(sizeof(struct reftable_reader *) * names_len);
- struct reftable_table *new_tables =
- reftable_calloc(sizeof(struct reftable_table) * names_len);
- int new_readers_len = 0;
+ size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
+ struct reftable_reader **cur;
+ struct reftable_reader **reused = NULL;
+ struct reftable_reader **new_readers;
+ size_t reused_len = 0, reused_alloc = 0, names_len;
+ size_t new_readers_len = 0;
struct reftable_merged_table *new_merged = NULL;
- int i;
+ struct reftable_buf table_path = REFTABLE_BUF_INIT;
+ int err = 0;
+ size_t i;
+
+ cur = stack_copy_readers(st, cur_len);
+ if (!cur) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ names_len = names_length(names);
+
+ new_readers = reftable_calloc(names_len, sizeof(*new_readers));
+ if (!new_readers) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
while (*names) {
struct reftable_reader *rd = NULL;
- char *name = *names++;
+ const char *name = *names++;
/* this is linear; we assume compaction keeps the number of
tables under control so this is not quadratic. */
- int j = 0;
- for (j = 0; reuse_open && j < cur_len; j++) {
- if (cur[j] && 0 == strcmp(cur[j]->name, name)) {
- rd = cur[j];
- cur[j] = NULL;
+ for (i = 0; reuse_open && i < cur_len; i++) {
+ if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
+ rd = cur[i];
+ cur[i] = NULL;
+
+ /*
+ * When reloading the stack fails, we end up
+ * releasing all new readers. This also
+ * includes the reused readers, even though
+ * they are still in used by the old stack. We
+ * thus need to keep them alive here, which we
+ * do by bumping their refcount.
+ */
+ REFTABLE_ALLOC_GROW(reused, reused_len + 1, reused_alloc);
+ if (!reused) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+ reused[reused_len++] = rd;
+ reftable_reader_incref(rd);
break;
}
}
if (!rd) {
struct reftable_block_source src = { NULL };
- struct strbuf table_path = STRBUF_INIT;
- stack_filename(&table_path, st, name);
+
+ err = stack_filename(&table_path, st, name);
+ if (err < 0)
+ goto done;
err = reftable_block_source_from_file(&src,
table_path.buf);
- strbuf_release(&table_path);
-
if (err < 0)
goto done;
- err = reftable_new_reader(&rd, &src, name);
+ err = reftable_reader_new(&rd, &src, name);
if (err < 0)
goto done;
}
new_readers[new_readers_len] = rd;
- reftable_table_from_reader(&new_tables[new_readers_len], rd);
new_readers_len++;
}
/* success! */
- err = reftable_new_merged_table(&new_merged, new_tables,
- new_readers_len, st->config.hash_id);
+ err = reftable_merged_table_new(&new_merged, new_readers,
+ new_readers_len, st->opts.hash_id);
if (err < 0)
goto done;
- new_tables = NULL;
- st->readers_len = new_readers_len;
- if (st->merged) {
- merged_table_release(st->merged);
- reftable_merged_table_free(st->merged);
- }
- if (st->readers) {
- reftable_free(st->readers);
- }
- st->readers = new_readers;
- new_readers = NULL;
- new_readers_len = 0;
-
- new_merged->suppress_deletions = 1;
- st->merged = new_merged;
+ /*
+ * Close the old, non-reused readers and proactively try to unlink
+ * them. This is done for systems like Windows, where the underlying
+ * file of such an open reader wouldn't have been possible to be
+ * unlinked by the compacting process.
+ */
for (i = 0; i < cur_len; i++) {
if (cur[i]) {
const char *name = reader_name(cur[i]);
- struct strbuf filename = STRBUF_INIT;
- stack_filename(&filename, st, name);
- reader_close(cur[i]);
- reftable_reader_free(cur[i]);
-
- /* On Windows, can only unlink after closing. */
- unlink(filename.buf);
+ err = stack_filename(&table_path, st, name);
+ if (err < 0)
+ goto done;
- strbuf_release(&filename);
+ reftable_reader_decref(cur[i]);
+ unlink(table_path.buf);
}
}
+ /* Update the stack to point to the new tables. */
+ if (st->merged)
+ reftable_merged_table_free(st->merged);
+ new_merged->suppress_deletions = 1;
+ st->merged = new_merged;
+
+ if (st->readers)
+ reftable_free(st->readers);
+ st->readers = new_readers;
+ st->readers_len = new_readers_len;
+ new_readers = NULL;
+ new_readers_len = 0;
+
+ /*
+ * Decrement the refcount of reused readers again. This only needs to
+ * happen on the successful case, because on the unsuccessful one we
+ * decrement their refcount via `new_readers`.
+ */
+ for (i = 0; i < reused_len; i++)
+ reftable_reader_decref(reused[i]);
+
done:
- for (i = 0; i < new_readers_len; i++) {
- reader_close(new_readers[i]);
- reftable_reader_free(new_readers[i]);
- }
+ for (i = 0; i < new_readers_len; i++)
+ reftable_reader_decref(new_readers[i]);
reftable_free(new_readers);
- reftable_free(new_tables);
+ reftable_free(reused);
reftable_free(cur);
+ reftable_buf_release(&table_path);
return err;
}
@@ -306,69 +407,139 @@ static int tv_cmp(struct timeval *a, struct timeval *b)
static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
int reuse_open)
{
- struct timeval deadline = { 0 };
- int err = gettimeofday(&deadline, NULL);
+ char **names = NULL, **names_after = NULL;
+ struct timeval deadline;
int64_t delay = 0;
- int tries = 0;
- if (err < 0)
- return err;
+ int tries = 0, err;
+ int fd = -1;
+ err = gettimeofday(&deadline, NULL);
+ if (err < 0)
+ goto out;
deadline.tv_sec += 3;
+
while (1) {
- char **names = NULL;
- char **names_after = NULL;
- struct timeval now = { 0 };
- int err = gettimeofday(&now, NULL);
- int err2 = 0;
- if (err < 0) {
- return err;
- }
+ struct timeval now;
+
+ err = gettimeofday(&now, NULL);
+ if (err < 0)
+ goto out;
- /* Only look at deadlines after the first few times. This
- simplifies debugging in GDB */
+ /*
+ * Only look at deadlines after the first few times. This
+ * simplifies debugging in GDB.
+ */
tries++;
- if (tries > 3 && tv_cmp(&now, &deadline) >= 0) {
- break;
- }
+ if (tries > 3 && tv_cmp(&now, &deadline) >= 0)
+ goto out;
- err = read_lines(st->list_file, &names);
- if (err < 0) {
- free_names(names);
- return err;
- }
- err = reftable_stack_reload_once(st, names, reuse_open);
- if (err == 0) {
- free_names(names);
- break;
- }
- if (err != REFTABLE_NOT_EXIST_ERROR) {
- free_names(names);
- return err;
- }
+ fd = open(st->list_file, O_RDONLY);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ err = REFTABLE_IO_ERROR;
+ goto out;
+ }
- /* err == REFTABLE_NOT_EXIST_ERROR can be caused by a concurrent
- writer. Check if there was one by checking if the name list
- changed.
- */
- err2 = read_lines(st->list_file, &names_after);
- if (err2 < 0) {
- free_names(names);
- return err2;
+ REFTABLE_CALLOC_ARRAY(names, 1);
+ if (!names) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+ } else {
+ err = fd_read_lines(fd, &names);
+ if (err < 0)
+ goto out;
}
- if (names_equal(names_after, names)) {
- free_names(names);
- free_names(names_after);
- return err;
+ err = reftable_stack_reload_once(st, (const char **) names, reuse_open);
+ if (!err)
+ break;
+ if (err != REFTABLE_NOT_EXIST_ERROR)
+ goto out;
+
+ /*
+ * REFTABLE_NOT_EXIST_ERROR can be caused by a concurrent
+ * writer. Check if there was one by checking if the name list
+ * changed.
+ */
+ err = read_lines(st->list_file, &names_after);
+ if (err < 0)
+ goto out;
+ if (names_equal((const char **) names_after,
+ (const char **) names)) {
+ err = REFTABLE_NOT_EXIST_ERROR;
+ goto out;
}
+
free_names(names);
+ names = NULL;
free_names(names_after);
+ names_after = NULL;
+ close(fd);
+ fd = -1;
delay = delay + (delay * rand()) / RAND_MAX + 1;
sleep_millisec(delay);
}
- return 0;
+out:
+ /*
+ * Invalidate the stat cache. It is sufficient to only close the file
+ * descriptor and keep the cached stat info because we never use the
+ * latter when the former is negative.
+ */
+ if (st->list_fd >= 0) {
+ close(st->list_fd);
+ st->list_fd = -1;
+ }
+
+ /*
+ * Cache stat information in case it provides a useful signal to us.
+ * According to POSIX, "The st_ino and st_dev fields taken together
+ * uniquely identify the file within the system." That being said,
+ * Windows is not POSIX compliant and we do not have these fields
+ * available. So the information we have there is insufficient to
+ * determine whether two file descriptors point to the same file.
+ *
+ * While we could fall back to using other signals like the file's
+ * mtime, those are not sufficient to avoid races. We thus refrain from
+ * using the stat cache on such systems and fall back to the secondary
+ * caching mechanism, which is to check whether contents of the file
+ * have changed.
+ *
+ * On other systems which are POSIX compliant we must keep the file
+ * descriptor open. This is to avoid a race condition where two
+ * processes access the reftable stack at the same point in time:
+ *
+ * 1. A reads the reftable stack and caches its stat info.
+ *
+ * 2. B updates the stack, appending a new table to "tables.list".
+ * This will both use a new inode and result in a different file
+ * size, thus invalidating A's cache in theory.
+ *
+ * 3. B decides to auto-compact the stack and merges two tables. The
+ * file size now matches what A has cached again. Furthermore, the
+ * filesystem may decide to recycle the inode number of the file
+ * we have replaced in (2) because it is not in use anymore.
+ *
+ * 4. A reloads the reftable stack. Neither the inode number nor the
+ * file size changed. If the timestamps did not change either then
+ * we think the cached copy of our stack is up-to-date.
+ *
+ * By keeping the file descriptor open the inode number cannot be
+ * recycled, mitigating the race.
+ */
+ if (!err && fd >= 0 && !fstat(fd, &st->list_st) &&
+ st->list_st.st_dev && st->list_st.st_ino) {
+ st->list_fd = fd;
+ fd = -1;
+ }
+
+ if (fd >= 0)
+ close(fd);
+ free_names(names);
+ free_names(names_after);
+ return err;
}
/* -1 = error
@@ -377,8 +548,44 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
static int stack_uptodate(struct reftable_stack *st)
{
char **names = NULL;
- int err = read_lines(st->list_file, &names);
+ int err;
int i = 0;
+
+ /*
+ * When we have cached stat information available then we use it to
+ * verify whether the file has been rewritten.
+ *
+ * Note that we explicitly do not want to use `stat_validity_check()`
+ * and friends here because they may end up not comparing the `st_dev`
+ * and `st_ino` fields. These functions thus cannot guarantee that we
+ * indeed still have the same file.
+ */
+ if (st->list_fd >= 0) {
+ struct stat list_st;
+
+ if (stat(st->list_file, &list_st) < 0) {
+ /*
+ * It's fine for "tables.list" to not exist. In that
+ * case, we have to refresh when the loaded stack has
+ * any readers.
+ */
+ if (errno == ENOENT)
+ return !!st->readers_len;
+ return REFTABLE_IO_ERROR;
+ }
+
+ /*
+ * When "tables.list" refers to the same file we can assume
+ * that it didn't change. This is because we always use
+ * rename(3P) to update the file and never write to it
+ * directly.
+ */
+ if (st->list_st.st_dev == list_st.st_dev &&
+ st->list_st.st_ino == list_st.st_ino)
+ return 0;
+ }
+
+ err = read_lines(st->list_file, &names);
if (err < 0)
return err;
@@ -394,7 +601,7 @@ static int stack_uptodate(struct reftable_stack *st)
}
}
- if (names[st->merged->stack_len]) {
+ if (names[st->merged->readers_len]) {
err = 1;
goto done;
}
@@ -418,59 +625,53 @@ int reftable_stack_add(struct reftable_stack *st,
{
int err = stack_try_add(st, write, arg);
if (err < 0) {
- if (err == REFTABLE_LOCK_ERROR) {
+ if (err == REFTABLE_OUTDATED_ERROR) {
/* Ignore error return, we want to propagate
- REFTABLE_LOCK_ERROR.
+ REFTABLE_OUTDATED_ERROR.
*/
reftable_stack_reload(st);
}
return err;
}
- if (!st->disable_auto_compact)
- return reftable_stack_auto_compact(st);
-
return 0;
}
-static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
+static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max)
{
char buf[100];
- uint32_t rnd = (uint32_t)rand();
+ uint32_t rnd = (uint32_t)git_rand();
snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
min, max, rnd);
- strbuf_reset(dest);
- strbuf_addstr(dest, buf);
+ reftable_buf_reset(dest);
+ return reftable_buf_addstr(dest, buf);
}
struct reftable_addition {
- int lock_file_fd;
- struct strbuf lock_file_name;
+ struct lock_file tables_list_lock;
struct reftable_stack *stack;
char **new_tables;
- int new_tables_len;
+ size_t new_tables_len, new_tables_cap;
uint64_t next_update_index;
};
-#define REFTABLE_ADDITION_INIT \
- { \
- .lock_file_name = STRBUF_INIT \
- }
+#define REFTABLE_ADDITION_INIT {0}
static int reftable_stack_init_addition(struct reftable_addition *add,
- struct reftable_stack *st)
+ struct reftable_stack *st,
+ unsigned int flags)
{
- int err = 0;
- add->stack = st;
+ struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
+ int err;
- strbuf_reset(&add->lock_file_name);
- strbuf_addstr(&add->lock_file_name, st->list_file);
- strbuf_addstr(&add->lock_file_name, ".lock");
+ add->stack = st;
- add->lock_file_fd = open(add->lock_file_name.buf,
- O_EXCL | O_CREAT | O_WRONLY, 0666);
- if (add->lock_file_fd < 0) {
+ err = hold_lock_file_for_update_timeout(&add->tables_list_lock,
+ st->list_file,
+ LOCK_NO_DEREF,
+ st->opts.lock_timeout_ms);
+ if (err < 0) {
if (errno == EEXIST) {
err = REFTABLE_LOCK_ERROR;
} else {
@@ -478,8 +679,9 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
}
goto done;
}
- if (st->config.default_permissions) {
- if (chmod(add->lock_file_name.buf, st->config.default_permissions) < 0) {
+ if (st->opts.default_permissions) {
+ if (chmod(get_lock_file_path(&add->tables_list_lock),
+ st->opts.default_permissions) < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
@@ -488,44 +690,42 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
err = stack_uptodate(st);
if (err < 0)
goto done;
-
- if (err > 1) {
- err = REFTABLE_LOCK_ERROR;
+ if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
+ err = reftable_stack_reload_maybe_reuse(add->stack, 1);
+ if (err)
+ goto done;
+ }
+ if (err > 0) {
+ err = REFTABLE_OUTDATED_ERROR;
goto done;
}
add->next_update_index = reftable_stack_next_update_index(st);
done:
- if (err) {
+ if (err)
reftable_addition_close(add);
- }
+ reftable_buf_release(&lock_file_name);
return err;
}
static void reftable_addition_close(struct reftable_addition *add)
{
- int i = 0;
- struct strbuf nm = STRBUF_INIT;
+ struct reftable_buf nm = REFTABLE_BUF_INIT;
+ size_t i;
+
for (i = 0; i < add->new_tables_len; i++) {
- stack_filename(&nm, add->stack, add->new_tables[i]);
- unlink(nm.buf);
+ if (!stack_filename(&nm, add->stack, add->new_tables[i]))
+ unlink(nm.buf);
reftable_free(add->new_tables[i]);
add->new_tables[i] = NULL;
}
reftable_free(add->new_tables);
add->new_tables = NULL;
add->new_tables_len = 0;
+ add->new_tables_cap = 0;
- if (add->lock_file_fd > 0) {
- close(add->lock_file_fd);
- add->lock_file_fd = 0;
- }
- if (add->lock_file_name.len > 0) {
- unlink(add->lock_file_name.buf);
- strbuf_release(&add->lock_file_name);
- }
-
- strbuf_release(&nm);
+ rollback_lock_file(&add->tables_list_lock);
+ reftable_buf_release(&nm);
}
void reftable_addition_destroy(struct reftable_addition *add)
@@ -539,64 +739,88 @@ void reftable_addition_destroy(struct reftable_addition *add)
int reftable_addition_commit(struct reftable_addition *add)
{
- struct strbuf table_list = STRBUF_INIT;
- int i = 0;
+ struct reftable_buf table_list = REFTABLE_BUF_INIT;
+ int lock_file_fd = get_lock_file_fd(&add->tables_list_lock);
int err = 0;
+ size_t i;
+
if (add->new_tables_len == 0)
goto done;
- for (i = 0; i < add->stack->merged->stack_len; i++) {
- strbuf_addstr(&table_list, add->stack->readers[i]->name);
- strbuf_addstr(&table_list, "\n");
+ for (i = 0; i < add->stack->merged->readers_len; i++) {
+ if ((err = reftable_buf_addstr(&table_list, add->stack->readers[i]->name)) < 0 ||
+ (err = reftable_buf_addstr(&table_list, "\n")) < 0)
+ goto done;
}
for (i = 0; i < add->new_tables_len; i++) {
- strbuf_addstr(&table_list, add->new_tables[i]);
- strbuf_addstr(&table_list, "\n");
+ if ((err = reftable_buf_addstr(&table_list, add->new_tables[i])) < 0 ||
+ (err = reftable_buf_addstr(&table_list, "\n")) < 0)
+ goto done;
}
- err = write(add->lock_file_fd, table_list.buf, table_list.len);
- strbuf_release(&table_list);
+ err = write_in_full(lock_file_fd, table_list.buf, table_list.len);
+ reftable_buf_release(&table_list);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- err = close(add->lock_file_fd);
- add->lock_file_fd = 0;
+ err = fsync_component(FSYNC_COMPONENT_REFERENCE, lock_file_fd);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- err = rename(add->lock_file_name.buf, add->stack->list_file);
+ err = commit_lock_file(&add->tables_list_lock);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
/* success, no more state to clean up. */
- strbuf_release(&add->lock_file_name);
- for (i = 0; i < add->new_tables_len; i++) {
+ for (i = 0; i < add->new_tables_len; i++)
reftable_free(add->new_tables[i]);
- }
reftable_free(add->new_tables);
add->new_tables = NULL;
add->new_tables_len = 0;
+ add->new_tables_cap = 0;
+
+ err = reftable_stack_reload_maybe_reuse(add->stack, 1);
+ if (err)
+ goto done;
+
+ if (!add->stack->opts.disable_auto_compact) {
+ /*
+ * Auto-compact the stack to keep the number of tables in
+ * control. It is possible that a concurrent writer is already
+ * trying to compact parts of the stack, which would lead to a
+ * `REFTABLE_LOCK_ERROR` because parts of the stack are locked
+ * already. This is a benign error though, so we ignore it.
+ */
+ err = reftable_stack_auto_compact(add->stack);
+ if (err < 0 && err != REFTABLE_LOCK_ERROR)
+ goto done;
+ err = 0;
+ }
- err = reftable_stack_reload(add->stack);
done:
reftable_addition_close(add);
return err;
}
int reftable_stack_new_addition(struct reftable_addition **dest,
- struct reftable_stack *st)
+ struct reftable_stack *st,
+ unsigned int flags)
{
int err = 0;
struct reftable_addition empty = REFTABLE_ADDITION_INIT;
- *dest = reftable_calloc(sizeof(**dest));
+
+ REFTABLE_CALLOC_ARRAY(*dest, 1);
+ if (!*dest)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
**dest = empty;
- err = reftable_stack_init_addition(*dest, st);
+ err = reftable_stack_init_addition(*dest, st, flags);
if (err) {
reftable_free(*dest);
*dest = NULL;
@@ -610,13 +834,9 @@ static int stack_try_add(struct reftable_stack *st,
void *arg)
{
struct reftable_addition add = REFTABLE_ADDITION_INIT;
- int err = reftable_stack_init_addition(&add, st);
+ int err = reftable_stack_init_addition(&add, st, 0);
if (err < 0)
goto done;
- if (err > 0) {
- err = REFTABLE_LOCK_ERROR;
- goto done;
- }
err = reftable_addition_add(&add, write_table, arg);
if (err < 0)
@@ -633,32 +853,47 @@ int reftable_addition_add(struct reftable_addition *add,
void *arg),
void *arg)
{
- struct strbuf temp_tab_file_name = STRBUF_INIT;
- struct strbuf tab_file_name = STRBUF_INIT;
- struct strbuf next_name = STRBUF_INIT;
+ struct reftable_buf temp_tab_file_name = REFTABLE_BUF_INIT;
+ struct reftable_buf tab_file_name = REFTABLE_BUF_INIT;
+ struct reftable_buf next_name = REFTABLE_BUF_INIT;
struct reftable_writer *wr = NULL;
+ struct tempfile *tab_file = NULL;
int err = 0;
- int tab_fd = 0;
+ int tab_fd;
- strbuf_reset(&next_name);
- format_name(&next_name, add->next_update_index, add->next_update_index);
+ reftable_buf_reset(&next_name);
+
+ err = format_name(&next_name, add->next_update_index, add->next_update_index);
+ if (err < 0)
+ goto done;
+
+ err = stack_filename(&temp_tab_file_name, add->stack, next_name.buf);
+ if (err < 0)
+ goto done;
- stack_filename(&temp_tab_file_name, add->stack, next_name.buf);
- strbuf_addstr(&temp_tab_file_name, ".temp.XXXXXX");
+ err = reftable_buf_addstr(&temp_tab_file_name, ".temp.XXXXXX");
+ if (err < 0)
+ goto done;
- tab_fd = mkstemp(temp_tab_file_name.buf);
- if (tab_fd < 0) {
+ tab_file = mks_tempfile(temp_tab_file_name.buf);
+ if (!tab_file) {
err = REFTABLE_IO_ERROR;
goto done;
}
- if (add->stack->config.default_permissions) {
- if (chmod(temp_tab_file_name.buf, add->stack->config.default_permissions)) {
+ if (add->stack->opts.default_permissions) {
+ if (chmod(get_tempfile_path(tab_file),
+ add->stack->opts.default_permissions)) {
err = REFTABLE_IO_ERROR;
goto done;
}
}
- wr = reftable_new_writer(reftable_fd_write, &tab_fd,
- &add->stack->config);
+ tab_fd = get_tempfile_fd(tab_file);
+
+ err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
+ &tab_fd, &add->stack->opts);
+ if (err < 0)
+ goto done;
+
err = write_table(wr, arg);
if (err < 0)
goto done;
@@ -671,142 +906,158 @@ int reftable_addition_add(struct reftable_addition *add,
if (err < 0)
goto done;
- err = close(tab_fd);
- tab_fd = 0;
+ err = close_tempfile_gently(tab_file);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- err = stack_check_addition(add->stack, temp_tab_file_name.buf);
- if (err < 0)
- goto done;
-
if (wr->min_update_index < add->next_update_index) {
err = REFTABLE_API_ERROR;
goto done;
}
- format_name(&next_name, wr->min_update_index, wr->max_update_index);
- strbuf_addstr(&next_name, ".ref");
+ err = format_name(&next_name, wr->min_update_index, wr->max_update_index);
+ if (err < 0)
+ goto done;
- stack_filename(&tab_file_name, add->stack, next_name.buf);
+ err = reftable_buf_addstr(&next_name, ".ref");
+ if (err < 0)
+ goto done;
+
+ err = stack_filename(&tab_file_name, add->stack, next_name.buf);
+ if (err < 0)
+ goto done;
/*
On windows, this relies on rand() picking a unique destination name.
Maybe we should do retry loop as well?
*/
- err = rename(temp_tab_file_name.buf, tab_file_name.buf);
+ err = rename_tempfile(&tab_file, tab_file_name.buf);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
- add->new_tables = reftable_realloc(add->new_tables,
- sizeof(*add->new_tables) *
- (add->new_tables_len + 1));
- add->new_tables[add->new_tables_len] = strbuf_detach(&next_name, NULL);
- add->new_tables_len++;
-done:
- if (tab_fd > 0) {
- close(tab_fd);
- tab_fd = 0;
- }
- if (temp_tab_file_name.len > 0) {
- unlink(temp_tab_file_name.buf);
+ REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1,
+ add->new_tables_cap);
+ if (!add->new_tables) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
}
+ add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name);
- strbuf_release(&temp_tab_file_name);
- strbuf_release(&tab_file_name);
- strbuf_release(&next_name);
+done:
+ delete_tempfile(&tab_file);
+ reftable_buf_release(&temp_tab_file_name);
+ reftable_buf_release(&tab_file_name);
+ reftable_buf_release(&next_name);
reftable_writer_free(wr);
return err;
}
uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
{
- int sz = st->merged->stack_len;
+ int sz = st->merged->readers_len;
if (sz > 0)
return reftable_reader_max_update_index(st->readers[sz - 1]) +
1;
return 1;
}
-static int stack_compact_locked(struct reftable_stack *st, int first, int last,
- struct strbuf *temp_tab,
- struct reftable_log_expiry_config *config)
+static int stack_compact_locked(struct reftable_stack *st,
+ size_t first, size_t last,
+ struct reftable_log_expiry_config *config,
+ struct tempfile **tab_file_out)
{
- struct strbuf next_name = STRBUF_INIT;
- int tab_fd = -1;
+ struct reftable_buf next_name = REFTABLE_BUF_INIT;
+ struct reftable_buf tab_file_path = REFTABLE_BUF_INIT;
struct reftable_writer *wr = NULL;
- int err = 0;
+ struct tempfile *tab_file;
+ int tab_fd, err = 0;
- format_name(&next_name,
- reftable_reader_min_update_index(st->readers[first]),
- reftable_reader_max_update_index(st->readers[last]));
+ err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]),
+ reftable_reader_max_update_index(st->readers[last]));
+ if (err < 0)
+ goto done;
+
+ err = stack_filename(&tab_file_path, st, next_name.buf);
+ if (err < 0)
+ goto done;
+
+ err = reftable_buf_addstr(&tab_file_path, ".temp.XXXXXX");
+ if (err < 0)
+ goto done;
- stack_filename(temp_tab, st, next_name.buf);
- strbuf_addstr(temp_tab, ".temp.XXXXXX");
+ tab_file = mks_tempfile(tab_file_path.buf);
+ if (!tab_file) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+ tab_fd = get_tempfile_fd(tab_file);
- tab_fd = mkstemp(temp_tab->buf);
- wr = reftable_new_writer(reftable_fd_write, &tab_fd, &st->config);
+ if (st->opts.default_permissions &&
+ chmod(get_tempfile_path(tab_file), st->opts.default_permissions) < 0) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
+ err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
+ &tab_fd, &st->opts);
+ if (err < 0)
+ goto done;
err = stack_write_compact(st, wr, first, last, config);
if (err < 0)
goto done;
+
err = reftable_writer_close(wr);
if (err < 0)
goto done;
- err = close(tab_fd);
- tab_fd = 0;
+ err = close_tempfile_gently(tab_file);
+ if (err < 0)
+ goto done;
+
+ *tab_file_out = tab_file;
+ tab_file = NULL;
done:
+ delete_tempfile(&tab_file);
reftable_writer_free(wr);
- if (tab_fd > 0) {
- close(tab_fd);
- tab_fd = 0;
- }
- if (err != 0 && temp_tab->len > 0) {
- unlink(temp_tab->buf);
- strbuf_release(temp_tab);
- }
- strbuf_release(&next_name);
+ reftable_buf_release(&next_name);
+ reftable_buf_release(&tab_file_path);
return err;
}
static int stack_write_compact(struct reftable_stack *st,
- struct reftable_writer *wr, int first, int last,
+ struct reftable_writer *wr,
+ size_t first, size_t last,
struct reftable_log_expiry_config *config)
{
- int subtabs_len = last - first + 1;
- struct reftable_table *subtabs = reftable_calloc(
- sizeof(struct reftable_table) * (last - first + 1));
struct reftable_merged_table *mt = NULL;
- int err = 0;
struct reftable_iterator it = { NULL };
struct reftable_ref_record ref = { NULL };
struct reftable_log_record log = { NULL };
-
+ size_t subtabs_len = last - first + 1;
uint64_t entries = 0;
+ int err = 0;
- int i = 0, j = 0;
- for (i = first, j = 0; i <= last; i++) {
- struct reftable_reader *t = st->readers[i];
- reftable_table_from_reader(&subtabs[j++], t);
- st->stats.bytes += t->size;
- }
+ for (size_t i = first; i <= last; i++)
+ st->stats.bytes += st->readers[i]->size;
reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
st->readers[last]->max_update_index);
- err = reftable_new_merged_table(&mt, subtabs, subtabs_len,
- st->config.hash_id);
- if (err < 0) {
- reftable_free(subtabs);
+ err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
+ st->opts.hash_id);
+ if (err < 0)
goto done;
- }
- err = reftable_merged_table_seek_ref(mt, &it, "");
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+ if (err < 0)
+ goto done;
+
+ err = reftable_iterator_seek_ref(&it, "");
if (err < 0)
goto done;
@@ -816,23 +1067,25 @@ static int stack_write_compact(struct reftable_stack *st,
err = 0;
break;
}
- if (err < 0) {
- break;
- }
+ if (err < 0)
+ goto done;
if (first == 0 && reftable_ref_record_is_deletion(&ref)) {
continue;
}
err = reftable_writer_add_ref(wr, &ref);
- if (err < 0) {
- break;
- }
+ if (err < 0)
+ goto done;
entries++;
}
reftable_iterator_destroy(&it);
- err = reftable_merged_table_seek_log(mt, &it, "");
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+ if (err < 0)
+ goto done;
+
+ err = reftable_iterator_seek_log(&it, "");
if (err < 0)
goto done;
@@ -842,9 +1095,8 @@ static int stack_write_compact(struct reftable_stack *st,
err = 0;
break;
}
- if (err < 0) {
- break;
- }
+ if (err < 0)
+ goto done;
if (first == 0 && reftable_log_record_is_deletion(&log)) {
continue;
}
@@ -860,45 +1112,55 @@ static int stack_write_compact(struct reftable_stack *st,
}
err = reftable_writer_add_log(wr, &log);
- if (err < 0) {
- break;
- }
+ if (err < 0)
+ goto done;
entries++;
}
done:
reftable_iterator_destroy(&it);
- if (mt) {
- merged_table_release(mt);
+ if (mt)
reftable_merged_table_free(mt);
- }
reftable_ref_record_release(&ref);
reftable_log_record_release(&log);
st->stats.entries_written += entries;
return err;
}
-/* < 0: error. 0 == OK, > 0 attempt failed; could retry. */
-static int stack_compact_range(struct reftable_stack *st, int first, int last,
- struct reftable_log_expiry_config *expiry)
+enum stack_compact_range_flags {
+ /*
+ * Perform a best-effort compaction. That is, even if we cannot lock
+ * all tables in the specified range, we will try to compact the
+ * remaining slice.
+ */
+ STACK_COMPACT_RANGE_BEST_EFFORT = (1 << 0),
+};
+
+/*
+ * Compact all tables in the range `[first, last)` into a single new table.
+ *
+ * This function returns `0` on success or a code `< 0` on failure. When the
+ * stack or any of the tables in the specified range are already locked then
+ * this function returns `REFTABLE_LOCK_ERROR`. This is a benign error that
+ * callers can either ignore, or they may choose to retry compaction after some
+ * amount of time.
+ */
+static int stack_compact_range(struct reftable_stack *st,
+ size_t first, size_t last,
+ struct reftable_log_expiry_config *expiry,
+ unsigned int flags)
{
- struct strbuf temp_tab_file_name = STRBUF_INIT;
- struct strbuf new_table_name = STRBUF_INIT;
- struct strbuf lock_file_name = STRBUF_INIT;
- struct strbuf ref_list_contents = STRBUF_INIT;
- struct strbuf new_table_path = STRBUF_INIT;
- int err = 0;
- int have_lock = 0;
- int lock_file_fd = -1;
- int compact_count = last - first + 1;
- char **listp = NULL;
- char **delete_on_success =
- reftable_calloc(sizeof(char *) * (compact_count + 1));
- char **subtable_locks =
- reftable_calloc(sizeof(char *) * (compact_count + 1));
- int i = 0;
- int j = 0;
- int is_empty_table = 0;
+ struct reftable_buf tables_list_buf = REFTABLE_BUF_INIT;
+ struct reftable_buf new_table_name = REFTABLE_BUF_INIT;
+ struct reftable_buf new_table_path = REFTABLE_BUF_INIT;
+ struct reftable_buf table_name = REFTABLE_BUF_INIT;
+ struct lock_file tables_list_lock = LOCK_INIT;
+ struct lock_file *table_locks = NULL;
+ struct tempfile *new_table = NULL;
+ int is_empty_table = 0, err = 0;
+ size_t first_to_replace, last_to_replace;
+ size_t i, nlocks = 0;
+ char **names = NULL;
if (first > last || (!expiry && first == last)) {
err = 0;
@@ -907,197 +1169,355 @@ static int stack_compact_range(struct reftable_stack *st, int first, int last,
st->stats.attempts++;
- strbuf_reset(&lock_file_name);
- strbuf_addstr(&lock_file_name, st->list_file);
- strbuf_addstr(&lock_file_name, ".lock");
-
- lock_file_fd =
- open(lock_file_name.buf, O_EXCL | O_CREAT | O_WRONLY, 0666);
- if (lock_file_fd < 0) {
- if (errno == EEXIST) {
- err = 1;
- } else {
+ /*
+ * Hold the lock so that we can read "tables.list" and lock all tables
+ * which are part of the user-specified range.
+ */
+ err = hold_lock_file_for_update_timeout(&tables_list_lock,
+ st->list_file,
+ LOCK_NO_DEREF,
+ st->opts.lock_timeout_ms);
+ if (err < 0) {
+ if (errno == EEXIST)
+ err = REFTABLE_LOCK_ERROR;
+ else
err = REFTABLE_IO_ERROR;
- }
goto done;
}
- /* Don't want to write to the lock for now. */
- close(lock_file_fd);
- lock_file_fd = -1;
- have_lock = 1;
err = stack_uptodate(st);
- if (err != 0)
+ if (err)
goto done;
- for (i = first, j = 0; i <= last; i++) {
- struct strbuf subtab_file_name = STRBUF_INIT;
- struct strbuf subtab_lock = STRBUF_INIT;
- int sublock_file_fd = -1;
-
- stack_filename(&subtab_file_name, st,
- reader_name(st->readers[i]));
+ /*
+ * Lock all tables in the user-provided range. This is the slice of our
+ * stack which we'll compact.
+ *
+ * Note that we lock tables in reverse order from last to first. The
+ * intent behind this is to allow a newer process to perform best
+ * effort compaction of tables that it has added in the case where an
+ * older process is still busy compacting tables which are preexisting
+ * from the point of view of the newer process.
+ */
+ REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
+ if (!table_locks) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
- strbuf_reset(&subtab_lock);
- strbuf_addbuf(&subtab_lock, &subtab_file_name);
- strbuf_addstr(&subtab_lock, ".lock");
+ for (i = last + 1; i > first; i--) {
+ err = stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
+ if (err < 0)
+ goto done;
- sublock_file_fd = open(subtab_lock.buf,
- O_EXCL | O_CREAT | O_WRONLY, 0666);
- if (sublock_file_fd >= 0) {
- close(sublock_file_fd);
- } else if (sublock_file_fd < 0) {
- if (errno == EEXIST) {
- err = 1;
+ err = hold_lock_file_for_update(&table_locks[nlocks],
+ table_name.buf, LOCK_NO_DEREF);
+ if (err < 0) {
+ /*
+ * When the table is locked already we may do a
+ * best-effort compaction and compact only the tables
+ * that we have managed to lock so far. This of course
+ * requires that we have been able to lock at least two
+ * tables, otherwise there would be nothing to compact.
+ * In that case, we return a lock error to our caller.
+ */
+ if (errno == EEXIST && last - (i - 1) >= 2 &&
+ flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
+ err = 0;
+ /*
+ * The subtraction is to offset the index, the
+ * addition is to only compact up to the table
+ * of the preceding iteration. They obviously
+ * cancel each other out, but that may be
+ * non-obvious when it was omitted.
+ */
+ first = (i - 1) + 1;
+ break;
+ } else if (errno == EEXIST) {
+ err = REFTABLE_LOCK_ERROR;
+ goto done;
} else {
err = REFTABLE_IO_ERROR;
+ goto done;
}
}
- subtable_locks[j] = subtab_lock.buf;
- delete_on_success[j] = subtab_file_name.buf;
- j++;
-
- if (err != 0)
+ /*
+ * We need to close the lockfiles as we might otherwise easily
+ * run into file descriptor exhaustion when we compress a lot
+ * of tables.
+ */
+ err = close_lock_file_gently(&table_locks[nlocks++]);
+ if (err < 0) {
+ err = REFTABLE_IO_ERROR;
goto done;
+ }
}
- err = unlink(lock_file_name.buf);
- if (err < 0)
+ /*
+ * We have locked all tables in our range and can thus release the
+ * "tables.list" lock while compacting the locked tables. This allows
+ * concurrent updates to the stack to proceed.
+ */
+ err = rollback_lock_file(&tables_list_lock);
+ if (err < 0) {
+ err = REFTABLE_IO_ERROR;
goto done;
- have_lock = 0;
+ }
- err = stack_compact_locked(st, first, last, &temp_tab_file_name,
- expiry);
- /* Compaction + tombstones can create an empty table out of non-empty
- * tables. */
- is_empty_table = (err == REFTABLE_EMPTY_TABLE_ERROR);
- if (is_empty_table) {
- err = 0;
+ /*
+ * Compact the now-locked tables into a new table. Note that compacting
+ * these tables may end up with an empty new table in case tombstones
+ * end up cancelling out all refs in that range.
+ */
+ err = stack_compact_locked(st, first, last, expiry, &new_table);
+ if (err < 0) {
+ if (err != REFTABLE_EMPTY_TABLE_ERROR)
+ goto done;
+ is_empty_table = 1;
}
- if (err < 0)
- goto done;
- lock_file_fd =
- open(lock_file_name.buf, O_EXCL | O_CREAT | O_WRONLY, 0666);
- if (lock_file_fd < 0) {
- if (errno == EEXIST) {
- err = 1;
- } else {
+ /*
+ * Now that we have written the new, compacted table we need to re-lock
+ * "tables.list". We'll then replace the compacted range of tables with
+ * the new table.
+ */
+ err = hold_lock_file_for_update_timeout(&tables_list_lock,
+ st->list_file,
+ LOCK_NO_DEREF,
+ st->opts.lock_timeout_ms);
+ if (err < 0) {
+ if (errno == EEXIST)
+ err = REFTABLE_LOCK_ERROR;
+ else
err = REFTABLE_IO_ERROR;
- }
goto done;
}
- have_lock = 1;
- if (st->config.default_permissions) {
- if (chmod(lock_file_name.buf, st->config.default_permissions) < 0) {
+
+ if (st->opts.default_permissions) {
+ if (chmod(get_lock_file_path(&tables_list_lock),
+ st->opts.default_permissions) < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
}
- format_name(&new_table_name, st->readers[first]->min_update_index,
- st->readers[last]->max_update_index);
- strbuf_addstr(&new_table_name, ".ref");
+ /*
+ * As we have unlocked the stack while compacting our slice of tables
+ * it may have happened that a concurrently running process has updated
+ * the stack while we were compacting. In that case, we need to check
+ * whether the tables that we have just compacted still exist in the
+ * stack in the exact same order as we have compacted them.
+ *
+ * If they do exist, then it is fine to continue and replace those
+ * tables with our compacted version. If they don't, then we need to
+ * abort.
+ */
+ err = stack_uptodate(st);
+ if (err < 0)
+ goto done;
+ if (err > 0) {
+ ssize_t new_offset = -1;
+ int fd;
+
+ fd = open(st->list_file, O_RDONLY);
+ if (fd < 0) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
- stack_filename(&new_table_path, st, new_table_name.buf);
+ err = fd_read_lines(fd, &names);
+ close(fd);
+ if (err < 0)
+ goto done;
+
+ /*
+ * Search for the offset of the first table that we have
+ * compacted in the updated "tables.list" file.
+ */
+ for (size_t i = 0; names[i]; i++) {
+ if (strcmp(names[i], st->readers[first]->name))
+ continue;
+
+ /*
+ * We have found the first entry. Verify that all the
+ * subsequent tables we have compacted still exist in
+ * the modified stack in the exact same order as we
+ * have compacted them.
+ */
+ for (size_t j = 1; j < last - first + 1; j++) {
+ const char *old = first + j < st->merged->readers_len ?
+ st->readers[first + j]->name : NULL;
+ const char *new = names[i + j];
+
+ /*
+ * If some entries are missing or in case the tables
+ * have changed then we need to bail out. Again, this
+ * shouldn't ever happen because we have locked the
+ * tables we are compacting.
+ */
+ if (!old || !new || strcmp(old, new)) {
+ err = REFTABLE_OUTDATED_ERROR;
+ goto done;
+ }
+ }
+
+ new_offset = i;
+ break;
+ }
+ /*
+ * In case we didn't find our compacted tables in the stack we
+ * need to bail out. In theory, this should have never happened
+ * because we locked the tables we are compacting.
+ */
+ if (new_offset < 0) {
+ err = REFTABLE_OUTDATED_ERROR;
+ goto done;
+ }
+
+ /*
+ * We have found the new range that we want to replace, so
+ * let's update the range of tables that we want to replace.
+ */
+ first_to_replace = new_offset;
+ last_to_replace = last + (new_offset - first);
+ } else {
+ /*
+ * `fd_read_lines()` uses a `NULL` sentinel to indicate that
+ * the array is at its end. As we use `free_names()` to free
+ * the array, we need to include this sentinel value here and
+ * thus have to allocate `readers_len + 1` many entries.
+ */
+ REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
+ if (!names) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ for (size_t i = 0; i < st->merged->readers_len; i++) {
+ names[i] = reftable_strdup(st->readers[i]->name);
+ if (!names[i]) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+ }
+ first_to_replace = first;
+ last_to_replace = last;
+ }
+
+ /*
+ * If the resulting compacted table is not empty, then we need to move
+ * it into place now.
+ */
if (!is_empty_table) {
- /* retry? */
- err = rename(temp_tab_file_name.buf, new_table_path.buf);
+ err = format_name(&new_table_name, st->readers[first]->min_update_index,
+ st->readers[last]->max_update_index);
+ if (err < 0)
+ goto done;
+
+ err = reftable_buf_addstr(&new_table_name, ".ref");
+ if (err < 0)
+ goto done;
+
+ err = stack_filename(&new_table_path, st, new_table_name.buf);
+ if (err < 0)
+ goto done;
+
+ err = rename_tempfile(&new_table, new_table_path.buf);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
}
- for (i = 0; i < first; i++) {
- strbuf_addstr(&ref_list_contents, st->readers[i]->name);
- strbuf_addstr(&ref_list_contents, "\n");
+ /*
+ * Write the new "tables.list" contents with the compacted table we
+ * have just written. In case the compacted table became empty we
+ * simply skip writing it.
+ */
+ for (i = 0; i < first_to_replace; i++) {
+ if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
+ (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
+ goto done;
}
if (!is_empty_table) {
- strbuf_addbuf(&ref_list_contents, &new_table_name);
- strbuf_addstr(&ref_list_contents, "\n");
+ if ((err = reftable_buf_addstr(&tables_list_buf, new_table_name.buf)) < 0 ||
+ (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
+ goto done;
}
- for (i = last + 1; i < st->merged->stack_len; i++) {
- strbuf_addstr(&ref_list_contents, st->readers[i]->name);
- strbuf_addstr(&ref_list_contents, "\n");
+ for (i = last_to_replace + 1; names[i]; i++) {
+ if ((err = reftable_buf_addstr(&tables_list_buf, names[i])) < 0 ||
+ (err = reftable_buf_addstr(&tables_list_buf, "\n")) < 0)
+ goto done;
}
- err = write(lock_file_fd, ref_list_contents.buf, ref_list_contents.len);
+ err = write_in_full(get_lock_file_fd(&tables_list_lock),
+ tables_list_buf.buf, tables_list_buf.len);
if (err < 0) {
err = REFTABLE_IO_ERROR;
unlink(new_table_path.buf);
goto done;
}
- err = close(lock_file_fd);
- lock_file_fd = -1;
+
+ err = fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&tables_list_lock));
if (err < 0) {
err = REFTABLE_IO_ERROR;
unlink(new_table_path.buf);
goto done;
}
- err = rename(lock_file_name.buf, st->list_file);
+ err = commit_lock_file(&tables_list_lock);
if (err < 0) {
err = REFTABLE_IO_ERROR;
unlink(new_table_path.buf);
goto done;
}
- have_lock = 0;
- /* Reload the stack before deleting. On windows, we can only delete the
- files after we closed them.
- */
+ /*
+ * Reload the stack before deleting the compacted tables. We can only
+ * delete the files after we closed them on Windows, so this needs to
+ * happen first.
+ */
err = reftable_stack_reload_maybe_reuse(st, first < last);
+ if (err < 0)
+ goto done;
- listp = delete_on_success;
- while (*listp) {
- if (strcmp(*listp, new_table_path.buf)) {
- unlink(*listp);
- }
- listp++;
+ /*
+ * Delete the old tables. They may still be in use by concurrent
+ * readers, so it is expected that unlinking tables may fail.
+ */
+ for (i = 0; i < nlocks; i++) {
+ struct lock_file *table_lock = &table_locks[i];
+ char *table_path = get_locked_file_path(table_lock);
+ unlink(table_path);
+ reftable_free(table_path);
}
done:
- free_names(delete_on_success);
-
- listp = subtable_locks;
- while (*listp) {
- unlink(*listp);
- listp++;
- }
- free_names(subtable_locks);
- if (lock_file_fd >= 0) {
- close(lock_file_fd);
- lock_file_fd = -1;
- }
- if (have_lock) {
- unlink(lock_file_name.buf);
- }
- strbuf_release(&new_table_name);
- strbuf_release(&new_table_path);
- strbuf_release(&ref_list_contents);
- strbuf_release(&temp_tab_file_name);
- strbuf_release(&lock_file_name);
+ rollback_lock_file(&tables_list_lock);
+ for (i = 0; table_locks && i < nlocks; i++)
+ rollback_lock_file(&table_locks[i]);
+ reftable_free(table_locks);
+
+ delete_tempfile(&new_table);
+ reftable_buf_release(&new_table_name);
+ reftable_buf_release(&new_table_path);
+ reftable_buf_release(&tables_list_buf);
+ reftable_buf_release(&table_name);
+ free_names(names);
+
+ if (err == REFTABLE_LOCK_ERROR)
+ st->stats.failures++;
+
return err;
}
int reftable_stack_compact_all(struct reftable_stack *st,
struct reftable_log_expiry_config *config)
{
- return stack_compact_range(st, 0, st->merged->stack_len - 1, config);
-}
-
-static int stack_compact_range_stats(struct reftable_stack *st, int first,
- int last,
- struct reftable_log_expiry_config *config)
-{
- int err = stack_compact_range(st, first, last, config);
- if (err > 0) {
- st->stats.failures++;
- }
- return err;
+ size_t last = st->merged->readers_len ? st->merged->readers_len - 1 : 0;
+ return stack_compact_range(st, 0, last, config, 0);
}
static int segment_size(struct segment *s)
@@ -1105,102 +1525,114 @@ static int segment_size(struct segment *s)
return s->end - s->start;
}
-int fastlog2(uint64_t sz)
+struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
+ uint8_t factor)
{
- int l = 0;
- if (sz == 0)
- return 0;
- for (; sz; sz /= 2) {
- l++;
- }
- return l - 1;
-}
+ struct segment seg = { 0 };
+ uint64_t bytes;
+ size_t i;
-struct segment *sizes_to_segments(int *seglen, uint64_t *sizes, int n)
-{
- struct segment *segs = reftable_calloc(sizeof(struct segment) * n);
- int next = 0;
- struct segment cur = { 0 };
- int i = 0;
+ if (!factor)
+ factor = DEFAULT_GEOMETRIC_FACTOR;
- if (n == 0) {
- *seglen = 0;
- return segs;
- }
- for (i = 0; i < n; i++) {
- int log = fastlog2(sizes[i]);
- if (cur.log != log && cur.bytes > 0) {
- struct segment fresh = {
- .start = i,
- };
+ /*
+ * If there are no tables or only a single one then we don't have to
+ * compact anything. The sequence is geometric by definition already.
+ */
+ if (n <= 1)
+ return seg;
- segs[next++] = cur;
- cur = fresh;
+ /*
+ * Find the ending table of the compaction segment needed to restore the
+ * geometric sequence. Note that the segment end is exclusive.
+ *
+ * To do so, we iterate backwards starting from the most recent table
+ * until a valid segment end is found. If the preceding table is smaller
+ * than the current table multiplied by the geometric factor (2), the
+ * compaction segment end has been identified.
+ *
+ * Tables after the ending point are not added to the byte count because
+ * they are already valid members of the geometric sequence. Due to the
+ * properties of a geometric sequence, it is not possible for the sum of
+ * these tables to exceed the value of the ending point table.
+ *
+ * Example table size sequence requiring no compaction:
+ * 64, 32, 16, 8, 4, 2, 1
+ *
+ * Example table size sequence where compaction segment end is set to
+ * the last table. Since the segment end is exclusive, the last table is
+ * excluded during subsequent compaction and the table with size 3 is
+ * the final table included:
+ * 64, 32, 16, 8, 4, 3, 1
+ */
+ for (i = n - 1; i > 0; i--) {
+ if (sizes[i - 1] < sizes[i] * factor) {
+ seg.end = i + 1;
+ bytes = sizes[i];
+ break;
}
-
- cur.log = log;
- cur.end = i + 1;
- cur.bytes += sizes[i];
}
- segs[next++] = cur;
- *seglen = next;
- return segs;
-}
-
-struct segment suggest_compaction_segment(uint64_t *sizes, int n)
-{
- int seglen = 0;
- struct segment *segs = sizes_to_segments(&seglen, sizes, n);
- struct segment min_seg = {
- .log = 64,
- };
- int i = 0;
- for (i = 0; i < seglen; i++) {
- if (segment_size(&segs[i]) == 1) {
- continue;
- }
- if (segs[i].log < min_seg.log) {
- min_seg = segs[i];
- }
- }
+ /*
+ * Find the starting table of the compaction segment by iterating
+ * through the remaining tables and keeping track of the accumulated
+ * size of all tables seen from the segment end table. The previous
+ * table is compared to the accumulated size because the tables from the
+ * segment end are merged backwards recursively.
+ *
+ * Note that we keep iterating even after we have found the first
+ * starting point. This is because there may be tables in the stack
+ * preceding that first starting point which violate the geometric
+ * sequence.
+ *
+ * Example compaction segment start set to table with size 32:
+ * 128, 32, 16, 8, 4, 3, 1
+ */
+ for (; i > 0; i--) {
+ uint64_t curr = bytes;
+ bytes += sizes[i - 1];
- while (min_seg.start > 0) {
- int prev = min_seg.start - 1;
- if (fastlog2(min_seg.bytes) < fastlog2(sizes[prev])) {
- break;
+ if (sizes[i - 1] < curr * factor) {
+ seg.start = i - 1;
+ seg.bytes = bytes;
}
-
- min_seg.start = prev;
- min_seg.bytes += sizes[prev];
}
- reftable_free(segs);
- return min_seg;
+ return seg;
}
static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
{
- uint64_t *sizes =
- reftable_calloc(sizeof(uint64_t) * st->merged->stack_len);
- int version = (st->config.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
+ int version = (st->opts.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
int overhead = header_size(version) - 1;
- int i = 0;
- for (i = 0; i < st->merged->stack_len; i++) {
+ uint64_t *sizes;
+
+ REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
+ if (!sizes)
+ return NULL;
+
+ for (size_t i = 0; i < st->merged->readers_len; i++)
sizes[i] = st->readers[i]->size - overhead;
- }
+
return sizes;
}
int reftable_stack_auto_compact(struct reftable_stack *st)
{
- uint64_t *sizes = stack_table_sizes_for_compaction(st);
- struct segment seg =
- suggest_compaction_segment(sizes, st->merged->stack_len);
+ struct segment seg;
+ uint64_t *sizes;
+
+ sizes = stack_table_sizes_for_compaction(st);
+ if (!sizes)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ seg = suggest_compaction_segment(sizes, st->merged->readers_len,
+ st->opts.auto_compaction_factor);
reftable_free(sizes);
+
if (segment_size(&seg) > 0)
- return stack_compact_range_stats(st, seg.start, seg.end - 1,
- NULL);
+ return stack_compact_range(st, seg.start, seg.end - 1,
+ NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
return 0;
}
@@ -1214,17 +1646,44 @@ reftable_stack_compaction_stats(struct reftable_stack *st)
int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
struct reftable_ref_record *ref)
{
- struct reftable_table tab = { NULL };
- reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
- return reftable_table_read_ref(&tab, refname, ref);
+ struct reftable_iterator it = { 0 };
+ int ret;
+
+ ret = reftable_merged_table_init_ref_iterator(st->merged, &it);
+ if (ret)
+ goto out;
+
+ ret = reftable_iterator_seek_ref(&it, refname);
+ if (ret)
+ goto out;
+
+ ret = reftable_iterator_next_ref(&it, ref);
+ if (ret)
+ goto out;
+
+ if (strcmp(ref->refname, refname) ||
+ reftable_ref_record_is_deletion(ref)) {
+ reftable_ref_record_release(ref);
+ ret = 1;
+ goto out;
+ }
+
+out:
+ reftable_iterator_destroy(&it);
+ return ret;
}
int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
struct reftable_log_record *log)
{
- struct reftable_iterator it = { NULL };
- struct reftable_merged_table *mt = reftable_stack_merged_table(st);
- int err = reftable_merged_table_seek_log(mt, &it, refname);
+ struct reftable_iterator it = {0};
+ int err;
+
+ err = reftable_stack_init_log_iterator(st, &it);
+ if (err)
+ goto done;
+
+ err = reftable_iterator_seek_log(&it, refname);
if (err)
goto done;
@@ -1246,70 +1705,6 @@ done:
return err;
}
-static int stack_check_addition(struct reftable_stack *st,
- const char *new_tab_name)
-{
- int err = 0;
- struct reftable_block_source src = { NULL };
- struct reftable_reader *rd = NULL;
- struct reftable_table tab = { NULL };
- struct reftable_ref_record *refs = NULL;
- struct reftable_iterator it = { NULL };
- int cap = 0;
- int len = 0;
- int i = 0;
-
- if (st->config.skip_name_check)
- return 0;
-
- err = reftable_block_source_from_file(&src, new_tab_name);
- if (err < 0)
- goto done;
-
- err = reftable_new_reader(&rd, &src, new_tab_name);
- if (err < 0)
- goto done;
-
- err = reftable_reader_seek_ref(rd, &it, "");
- if (err > 0) {
- err = 0;
- goto done;
- }
- if (err < 0)
- goto done;
-
- while (1) {
- struct reftable_ref_record ref = { NULL };
- err = reftable_iterator_next_ref(&it, &ref);
- if (err > 0) {
- break;
- }
- if (err < 0)
- goto done;
-
- if (len >= cap) {
- cap = 2 * cap + 1;
- refs = reftable_realloc(refs, cap * sizeof(refs[0]));
- }
-
- refs[len++] = ref;
- }
-
- reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
-
- err = validate_ref_record_addition(tab, refs, len);
-
-done:
- for (i = 0; i < len; i++) {
- reftable_ref_record_release(&refs[i]);
- }
-
- free(refs);
- reftable_iterator_destroy(&it);
- reftable_reader_free(rd);
- return err;
-}
-
static int is_table_name(const char *s)
{
const char *dot = strrchr(s, '.');
@@ -1323,25 +1718,28 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
uint64_t update_idx = 0;
struct reftable_block_source src = { NULL };
struct reftable_reader *rd = NULL;
- struct strbuf table_path = STRBUF_INIT;
- stack_filename(&table_path, st, name);
+ struct reftable_buf table_path = REFTABLE_BUF_INIT;
+
+ err = stack_filename(&table_path, st, name);
+ if (err < 0)
+ goto done;
err = reftable_block_source_from_file(&src, table_path.buf);
if (err < 0)
goto done;
- err = reftable_new_reader(&rd, &src, name);
+ err = reftable_reader_new(&rd, &src, name);
if (err < 0)
goto done;
update_idx = reftable_reader_max_update_index(rd);
- reftable_reader_free(rd);
+ reftable_reader_decref(rd);
if (update_idx <= max) {
unlink(table_path.buf);
}
done:
- strbuf_release(&table_path);
+ reftable_buf_release(&table_path);
}
static int reftable_stack_clean_locked(struct reftable_stack *st)
@@ -1376,7 +1774,7 @@ static int reftable_stack_clean_locked(struct reftable_stack *st)
int reftable_stack_clean(struct reftable_stack *st)
{
struct reftable_addition *add = NULL;
- int err = reftable_stack_new_addition(&add, st);
+ int err = reftable_stack_new_addition(&add, st, 0);
if (err < 0) {
goto done;
}
@@ -1392,23 +1790,3 @@ done:
reftable_addition_destroy(add);
return err;
}
-
-int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id)
-{
- struct reftable_stack *stack = NULL;
- struct reftable_write_options cfg = { .hash_id = hash_id };
- struct reftable_merged_table *merged = NULL;
- struct reftable_table table = { NULL };
-
- int err = reftable_new_stack(&stack, stackdir, cfg);
- if (err < 0)
- goto done;
-
- merged = reftable_stack_merged_table(stack);
- reftable_table_from_merged_table(&table, merged);
- err = reftable_table_print(&table);
-done:
- if (stack)
- reftable_stack_destroy(stack);
- return err;
-}
diff --git a/reftable/stack.h b/reftable/stack.h
index f57005846e..5b45cff4f7 100644
--- a/reftable/stack.h
+++ b/reftable/stack.h
@@ -14,11 +14,13 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-stack.h"
struct reftable_stack {
+ struct stat list_st;
char *list_file;
+ int list_fd;
+
char *reftable_dir;
- int disable_auto_compact;
- struct reftable_write_options config;
+ struct reftable_write_options opts;
struct reftable_reader **readers;
size_t readers_len;
@@ -29,13 +31,11 @@ struct reftable_stack {
int read_lines(const char *filename, char ***lines);
struct segment {
- int start, end;
- int log;
+ size_t start, end;
uint64_t bytes;
};
-int fastlog2(uint64_t sz);
-struct segment *sizes_to_segments(int *seglen, uint64_t *sizes, int n);
-struct segment suggest_compaction_segment(uint64_t *sizes, int n);
+struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
+ uint8_t factor);
#endif
diff --git a/reftable/stack_test.c b/reftable/stack_test.c
deleted file mode 100644
index d0b717510f..0000000000
--- a/reftable/stack_test.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "stack.h"
-
-#include "system.h"
-
-#include "reftable-reader.h"
-#include "merged.h"
-#include "basics.h"
-#include "constants.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-#include "reader.h"
-
-#include <sys/types.h>
-#include <dirent.h>
-
-static void clear_dir(const char *dirname)
-{
- struct strbuf path = STRBUF_INIT;
- strbuf_addstr(&path, dirname);
- remove_dir_recursively(&path, 0);
- strbuf_release(&path);
-}
-
-static int count_dir_entries(const char *dirname)
-{
- DIR *dir = opendir(dirname);
- int len = 0;
- struct dirent *d;
- if (!dir)
- return 0;
-
- while ((d = readdir(dir))) {
- if (!strcmp(d->d_name, "..") || !strcmp(d->d_name, "."))
- continue;
- len++;
- }
- closedir(dir);
- return len;
-}
-
-/*
- * Work linenumber into the tempdir, so we can see which tests forget to
- * cleanup.
- */
-static char *get_tmp_template(int linenumber)
-{
- const char *tmp = getenv("TMPDIR");
- static char template[1024];
- snprintf(template, sizeof(template) - 1, "%s/stack_test-%d.XXXXXX",
- tmp ? tmp : "/tmp", linenumber);
- return template;
-}
-
-static char *get_tmp_dir(int linenumber)
-{
- char *dir = get_tmp_template(linenumber);
- EXPECT(mkdtemp(dir));
- return dir;
-}
-
-static void test_read_file(void)
-{
- char *fn = get_tmp_template(__LINE__);
- int fd = mkstemp(fn);
- char out[1024] = "line1\n\nline2\nline3";
- int n, err;
- char **names = NULL;
- char *want[] = { "line1", "line2", "line3" };
- int i = 0;
-
- EXPECT(fd > 0);
- n = write(fd, out, strlen(out));
- EXPECT(n == strlen(out));
- err = close(fd);
- EXPECT(err >= 0);
-
- err = read_lines(fn, &names);
- EXPECT_ERR(err);
-
- for (i = 0; names[i]; i++) {
- EXPECT(0 == strcmp(want[i], names[i]));
- }
- free_names(names);
- (void) remove(fn);
-}
-
-static void test_parse_names(void)
-{
- char buf[] = "line\n";
- char **names = NULL;
- parse_names(buf, strlen(buf), &names);
-
- EXPECT(NULL != names[0]);
- EXPECT(0 == strcmp(names[0], "line"));
- EXPECT(NULL == names[1]);
- free_names(names);
-}
-
-static void test_names_equal(void)
-{
- char *a[] = { "a", "b", "c", NULL };
- char *b[] = { "a", "b", "d", NULL };
- char *c[] = { "a", "b", NULL };
-
- EXPECT(names_equal(a, a));
- EXPECT(!names_equal(a, b));
- EXPECT(!names_equal(a, c));
-}
-
-static int write_test_ref(struct reftable_writer *wr, void *arg)
-{
- struct reftable_ref_record *ref = arg;
- reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
- return reftable_writer_add_ref(wr, ref);
-}
-
-struct write_log_arg {
- struct reftable_log_record *log;
- uint64_t update_index;
-};
-
-static int write_test_log(struct reftable_writer *wr, void *arg)
-{
- struct write_log_arg *wla = arg;
-
- reftable_writer_set_limits(wr, wla->update_index, wla->update_index);
- return reftable_writer_add_log(wr, wla->log);
-}
-
-static void test_reftable_stack_add_one(void)
-{
- char *dir = get_tmp_dir(__LINE__);
- struct strbuf scratch = STRBUF_INIT;
- int mask = umask(002);
- struct reftable_write_options cfg = {
- .default_permissions = 0660,
- };
- struct reftable_stack *st = NULL;
- int err;
- struct reftable_ref_record ref = {
- .refname = "HEAD",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- struct reftable_ref_record dest = { NULL };
- struct stat stat_result = { 0 };
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st, &write_test_ref, &ref);
- EXPECT_ERR(err);
-
- err = reftable_stack_read_ref(st, ref.refname, &dest);
- EXPECT_ERR(err);
- EXPECT(0 == strcmp("master", dest.value.symref));
- EXPECT(st->readers_len > 0);
-
- printf("testing print functionality:\n");
- err = reftable_stack_print_directory(dir, GIT_SHA1_FORMAT_ID);
- EXPECT_ERR(err);
-
- err = reftable_stack_print_directory(dir, GIT_SHA256_FORMAT_ID);
- EXPECT(err == REFTABLE_FORMAT_ERROR);
-
-#ifndef GIT_WINDOWS_NATIVE
- strbuf_addstr(&scratch, dir);
- strbuf_addstr(&scratch, "/tables.list");
- err = stat(scratch.buf, &stat_result);
- EXPECT(!err);
- EXPECT((stat_result.st_mode & 0777) == cfg.default_permissions);
-
- strbuf_reset(&scratch);
- strbuf_addstr(&scratch, dir);
- strbuf_addstr(&scratch, "/");
- /* do not try at home; not an external API for reftable. */
- strbuf_addstr(&scratch, st->readers[0]->name);
- err = stat(scratch.buf, &stat_result);
- EXPECT(!err);
- EXPECT((stat_result.st_mode & 0777) == cfg.default_permissions);
-#else
- (void) stat_result;
-#endif
-
- reftable_ref_record_release(&dest);
- reftable_stack_destroy(st);
- strbuf_release(&scratch);
- clear_dir(dir);
- umask(mask);
-}
-
-static void test_reftable_stack_uptodate(void)
-{
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st1 = NULL;
- struct reftable_stack *st2 = NULL;
- char *dir = get_tmp_dir(__LINE__);
-
- int err;
- struct reftable_ref_record ref1 = {
- .refname = "HEAD",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- struct reftable_ref_record ref2 = {
- .refname = "branch2",
- .update_index = 2,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
-
-
- /* simulate multi-process access to the same stack
- by creating two stacks for the same directory.
- */
- err = reftable_new_stack(&st1, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_new_stack(&st2, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st1, &write_test_ref, &ref1);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st2, &write_test_ref, &ref2);
- EXPECT(err == REFTABLE_LOCK_ERROR);
-
- err = reftable_stack_reload(st2);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st2, &write_test_ref, &ref2);
- EXPECT_ERR(err);
- reftable_stack_destroy(st1);
- reftable_stack_destroy(st2);
- clear_dir(dir);
-}
-
-static void test_reftable_stack_transaction_api(void)
-{
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err;
- struct reftable_addition *add = NULL;
-
- struct reftable_ref_record ref = {
- .refname = "HEAD",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- struct reftable_ref_record dest = { NULL };
-
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- reftable_addition_destroy(add);
-
- err = reftable_stack_new_addition(&add, st);
- EXPECT_ERR(err);
-
- err = reftable_addition_add(add, &write_test_ref, &ref);
- EXPECT_ERR(err);
-
- err = reftable_addition_commit(add);
- EXPECT_ERR(err);
-
- reftable_addition_destroy(add);
-
- err = reftable_stack_read_ref(st, ref.refname, &dest);
- EXPECT_ERR(err);
- EXPECT(REFTABLE_REF_SYMREF == dest.value_type);
- EXPECT(0 == strcmp("master", dest.value.symref));
-
- reftable_ref_record_release(&dest);
- reftable_stack_destroy(st);
- clear_dir(dir);
-}
-
-static void test_reftable_stack_validate_refname(void)
-{
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err;
- char *dir = get_tmp_dir(__LINE__);
-
- int i;
- struct reftable_ref_record ref = {
- .refname = "a/b",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- char *additions[] = { "a", "a/b/c" };
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st, &write_test_ref, &ref);
- EXPECT_ERR(err);
-
- for (i = 0; i < ARRAY_SIZE(additions); i++) {
- struct reftable_ref_record ref = {
- .refname = additions[i],
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
-
- err = reftable_stack_add(st, &write_test_ref, &ref);
- EXPECT(err == REFTABLE_NAME_CONFLICT);
- }
-
- reftable_stack_destroy(st);
- clear_dir(dir);
-}
-
-static int write_error(struct reftable_writer *wr, void *arg)
-{
- return *((int *)arg);
-}
-
-static void test_reftable_stack_update_index_check(void)
-{
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err;
- struct reftable_ref_record ref1 = {
- .refname = "name1",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- struct reftable_ref_record ref2 = {
- .refname = "name2",
- .update_index = 1,
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st, &write_test_ref, &ref1);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st, &write_test_ref, &ref2);
- EXPECT(err == REFTABLE_API_ERROR);
- reftable_stack_destroy(st);
- clear_dir(dir);
-}
-
-static void test_reftable_stack_lock_failure(void)
-{
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err, i;
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
- for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) {
- err = reftable_stack_add(st, &write_error, &i);
- EXPECT(err == i);
- }
-
- reftable_stack_destroy(st);
- clear_dir(dir);
-}
-
-static void test_reftable_stack_add(void)
-{
- int i = 0;
- int err = 0;
- struct reftable_write_options cfg = {
- .exact_log_message = 1,
- };
- struct reftable_stack *st = NULL;
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_ref_record refs[2] = { { NULL } };
- struct reftable_log_record logs[2] = { { NULL } };
- int N = ARRAY_SIZE(refs);
-
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
- st->disable_auto_compact = 1;
-
- for (i = 0; i < N; i++) {
- char buf[256];
- snprintf(buf, sizeof(buf), "branch%02d", i);
- refs[i].refname = xstrdup(buf);
- refs[i].update_index = i + 1;
- refs[i].value_type = REFTABLE_REF_VAL1;
- refs[i].value.val1 = reftable_malloc(GIT_SHA1_RAWSZ);
- set_test_hash(refs[i].value.val1, i);
-
- logs[i].refname = xstrdup(buf);
- logs[i].update_index = N + i + 1;
- logs[i].value_type = REFTABLE_LOG_UPDATE;
-
- logs[i].value.update.new_hash = reftable_malloc(GIT_SHA1_RAWSZ);
- logs[i].value.update.email = xstrdup("identity@invalid");
- set_test_hash(logs[i].value.update.new_hash, i);
- }
-
- for (i = 0; i < N; i++) {
- int err = reftable_stack_add(st, &write_test_ref, &refs[i]);
- EXPECT_ERR(err);
- }
-
- for (i = 0; i < N; i++) {
- struct write_log_arg arg = {
- .log = &logs[i],
- .update_index = reftable_stack_next_update_index(st),
- };
- int err = reftable_stack_add(st, &write_test_log, &arg);
- EXPECT_ERR(err);
- }
-
- err = reftable_stack_compact_all(st, NULL);
- EXPECT_ERR(err);
-
- for (i = 0; i < N; i++) {
- struct reftable_ref_record dest = { NULL };
-
- int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
- EXPECT_ERR(err);
- EXPECT(reftable_ref_record_equal(&dest, refs + i,
- GIT_SHA1_RAWSZ));
- reftable_ref_record_release(&dest);
- }
-
- for (i = 0; i < N; i++) {
- struct reftable_log_record dest = { NULL };
- int err = reftable_stack_read_log(st, refs[i].refname, &dest);
- EXPECT_ERR(err);
- EXPECT(reftable_log_record_equal(&dest, logs + i,
- GIT_SHA1_RAWSZ));
- reftable_log_record_release(&dest);
- }
-
- /* cleanup */
- reftable_stack_destroy(st);
- for (i = 0; i < N; i++) {
- reftable_ref_record_release(&refs[i]);
- reftable_log_record_release(&logs[i]);
- }
- clear_dir(dir);
-}
-
-static void test_reftable_stack_log_normalize(void)
-{
- int err = 0;
- struct reftable_write_options cfg = {
- 0,
- };
- struct reftable_stack *st = NULL;
- char *dir = get_tmp_dir(__LINE__);
-
- uint8_t h1[GIT_SHA1_RAWSZ] = { 0x01 }, h2[GIT_SHA1_RAWSZ] = { 0x02 };
-
- struct reftable_log_record input = { .refname = "branch",
- .update_index = 1,
- .value_type = REFTABLE_LOG_UPDATE,
- .value = { .update = {
- .new_hash = h1,
- .old_hash = h2,
- } } };
- struct reftable_log_record dest = {
- .update_index = 0,
- };
- struct write_log_arg arg = {
- .log = &input,
- .update_index = 1,
- };
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- input.value.update.message = "one\ntwo";
- err = reftable_stack_add(st, &write_test_log, &arg);
- EXPECT(err == REFTABLE_API_ERROR);
-
- input.value.update.message = "one";
- err = reftable_stack_add(st, &write_test_log, &arg);
- EXPECT_ERR(err);
-
- err = reftable_stack_read_log(st, input.refname, &dest);
- EXPECT_ERR(err);
- EXPECT(0 == strcmp(dest.value.update.message, "one\n"));
-
- input.value.update.message = "two\n";
- arg.update_index = 2;
- err = reftable_stack_add(st, &write_test_log, &arg);
- EXPECT_ERR(err);
- err = reftable_stack_read_log(st, input.refname, &dest);
- EXPECT_ERR(err);
- EXPECT(0 == strcmp(dest.value.update.message, "two\n"));
-
- /* cleanup */
- reftable_stack_destroy(st);
- reftable_log_record_release(&dest);
- clear_dir(dir);
-}
-
-static void test_reftable_stack_tombstone(void)
-{
- int i = 0;
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err;
- struct reftable_ref_record refs[2] = { { NULL } };
- struct reftable_log_record logs[2] = { { NULL } };
- int N = ARRAY_SIZE(refs);
- struct reftable_ref_record dest = { NULL };
- struct reftable_log_record log_dest = { NULL };
-
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- /* even entries add the refs, odd entries delete them. */
- for (i = 0; i < N; i++) {
- const char *buf = "branch";
- refs[i].refname = xstrdup(buf);
- refs[i].update_index = i + 1;
- if (i % 2 == 0) {
- refs[i].value_type = REFTABLE_REF_VAL1;
- refs[i].value.val1 = reftable_malloc(GIT_SHA1_RAWSZ);
- set_test_hash(refs[i].value.val1, i);
- }
-
- logs[i].refname = xstrdup(buf);
- /* update_index is part of the key. */
- logs[i].update_index = 42;
- if (i % 2 == 0) {
- logs[i].value_type = REFTABLE_LOG_UPDATE;
- logs[i].value.update.new_hash =
- reftable_malloc(GIT_SHA1_RAWSZ);
- set_test_hash(logs[i].value.update.new_hash, i);
- logs[i].value.update.email =
- xstrdup("identity@invalid");
- }
- }
- for (i = 0; i < N; i++) {
- int err = reftable_stack_add(st, &write_test_ref, &refs[i]);
- EXPECT_ERR(err);
- }
-
- for (i = 0; i < N; i++) {
- struct write_log_arg arg = {
- .log = &logs[i],
- .update_index = reftable_stack_next_update_index(st),
- };
- int err = reftable_stack_add(st, &write_test_log, &arg);
- EXPECT_ERR(err);
- }
-
- err = reftable_stack_read_ref(st, "branch", &dest);
- EXPECT(err == 1);
- reftable_ref_record_release(&dest);
-
- err = reftable_stack_read_log(st, "branch", &log_dest);
- EXPECT(err == 1);
- reftable_log_record_release(&log_dest);
-
- err = reftable_stack_compact_all(st, NULL);
- EXPECT_ERR(err);
-
- err = reftable_stack_read_ref(st, "branch", &dest);
- EXPECT(err == 1);
-
- err = reftable_stack_read_log(st, "branch", &log_dest);
- EXPECT(err == 1);
- reftable_ref_record_release(&dest);
- reftable_log_record_release(&log_dest);
-
- /* cleanup */
- reftable_stack_destroy(st);
- for (i = 0; i < N; i++) {
- reftable_ref_record_release(&refs[i]);
- reftable_log_record_release(&logs[i]);
- }
- clear_dir(dir);
-}
-
-static void test_reftable_stack_hash_id(void)
-{
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err;
-
- struct reftable_ref_record ref = {
- .refname = "master",
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "target",
- .update_index = 1,
- };
- struct reftable_write_options cfg32 = { .hash_id = GIT_SHA256_FORMAT_ID };
- struct reftable_stack *st32 = NULL;
- struct reftable_write_options cfg_default = { 0 };
- struct reftable_stack *st_default = NULL;
- struct reftable_ref_record dest = { NULL };
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st, &write_test_ref, &ref);
- EXPECT_ERR(err);
-
- /* can't read it with the wrong hash ID. */
- err = reftable_new_stack(&st32, dir, cfg32);
- EXPECT(err == REFTABLE_FORMAT_ERROR);
-
- /* check that we can read it back with default config too. */
- err = reftable_new_stack(&st_default, dir, cfg_default);
- EXPECT_ERR(err);
-
- err = reftable_stack_read_ref(st_default, "master", &dest);
- EXPECT_ERR(err);
-
- EXPECT(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
- reftable_ref_record_release(&dest);
- reftable_stack_destroy(st);
- reftable_stack_destroy(st_default);
- clear_dir(dir);
-}
-
-static void test_log2(void)
-{
- EXPECT(1 == fastlog2(3));
- EXPECT(2 == fastlog2(4));
- EXPECT(2 == fastlog2(5));
-}
-
-static void test_sizes_to_segments(void)
-{
- uint64_t sizes[] = { 2, 3, 4, 5, 7, 9 };
- /* .................0 1 2 3 4 5 */
-
- int seglen = 0;
- struct segment *segs =
- sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes));
- EXPECT(segs[2].log == 3);
- EXPECT(segs[2].start == 5);
- EXPECT(segs[2].end == 6);
-
- EXPECT(segs[1].log == 2);
- EXPECT(segs[1].start == 2);
- EXPECT(segs[1].end == 5);
- reftable_free(segs);
-}
-
-static void test_sizes_to_segments_empty(void)
-{
- int seglen = 0;
- struct segment *segs = sizes_to_segments(&seglen, NULL, 0);
- EXPECT(seglen == 0);
- reftable_free(segs);
-}
-
-static void test_sizes_to_segments_all_equal(void)
-{
- uint64_t sizes[] = { 5, 5 };
-
- int seglen = 0;
- struct segment *segs =
- sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes));
- EXPECT(seglen == 1);
- EXPECT(segs[0].start == 0);
- EXPECT(segs[0].end == 2);
- reftable_free(segs);
-}
-
-static void test_suggest_compaction_segment(void)
-{
- uint64_t sizes[] = { 128, 64, 17, 16, 9, 9, 9, 16, 16 };
- /* .................0 1 2 3 4 5 6 */
- struct segment min =
- suggest_compaction_segment(sizes, ARRAY_SIZE(sizes));
- EXPECT(min.start == 2);
- EXPECT(min.end == 7);
-}
-
-static void test_suggest_compaction_segment_nothing(void)
-{
- uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 };
- struct segment result =
- suggest_compaction_segment(sizes, ARRAY_SIZE(sizes));
- EXPECT(result.start == result.end);
-}
-
-static void test_reflog_expire(void)
-{
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- struct reftable_log_record logs[20] = { { NULL } };
- int N = ARRAY_SIZE(logs) - 1;
- int i = 0;
- int err;
- struct reftable_log_expiry_config expiry = {
- .time = 10,
- };
- struct reftable_log_record log = { NULL };
-
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- for (i = 1; i <= N; i++) {
- char buf[256];
- snprintf(buf, sizeof(buf), "branch%02d", i);
-
- logs[i].refname = xstrdup(buf);
- logs[i].update_index = i;
- logs[i].value_type = REFTABLE_LOG_UPDATE;
- logs[i].value.update.time = i;
- logs[i].value.update.new_hash = reftable_malloc(GIT_SHA1_RAWSZ);
- logs[i].value.update.email = xstrdup("identity@invalid");
- set_test_hash(logs[i].value.update.new_hash, i);
- }
-
- for (i = 1; i <= N; i++) {
- struct write_log_arg arg = {
- .log = &logs[i],
- .update_index = reftable_stack_next_update_index(st),
- };
- int err = reftable_stack_add(st, &write_test_log, &arg);
- EXPECT_ERR(err);
- }
-
- err = reftable_stack_compact_all(st, NULL);
- EXPECT_ERR(err);
-
- err = reftable_stack_compact_all(st, &expiry);
- EXPECT_ERR(err);
-
- err = reftable_stack_read_log(st, logs[9].refname, &log);
- EXPECT(err == 1);
-
- err = reftable_stack_read_log(st, logs[11].refname, &log);
- EXPECT_ERR(err);
-
- expiry.min_update_index = 15;
- err = reftable_stack_compact_all(st, &expiry);
- EXPECT_ERR(err);
-
- err = reftable_stack_read_log(st, logs[14].refname, &log);
- EXPECT(err == 1);
-
- err = reftable_stack_read_log(st, logs[16].refname, &log);
- EXPECT_ERR(err);
-
- /* cleanup */
- reftable_stack_destroy(st);
- for (i = 0; i <= N; i++) {
- reftable_log_record_release(&logs[i]);
- }
- clear_dir(dir);
- reftable_log_record_release(&log);
-}
-
-static int write_nothing(struct reftable_writer *wr, void *arg)
-{
- reftable_writer_set_limits(wr, 1, 1);
- return 0;
-}
-
-static void test_empty_add(void)
-{
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- int err;
- char *dir = get_tmp_dir(__LINE__);
-
- struct reftable_stack *st2 = NULL;
-
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_add(st, &write_nothing, NULL);
- EXPECT_ERR(err);
-
- err = reftable_new_stack(&st2, dir, cfg);
- EXPECT_ERR(err);
- clear_dir(dir);
- reftable_stack_destroy(st);
- reftable_stack_destroy(st2);
-}
-
-static void test_reftable_stack_auto_compaction(void)
-{
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st = NULL;
- char *dir = get_tmp_dir(__LINE__);
-
- int err, i;
- int N = 100;
-
- err = reftable_new_stack(&st, dir, cfg);
- EXPECT_ERR(err);
-
- st->disable_auto_compact = 1; /* call manually below for coverage. */
- for (i = 0; i < N; i++) {
- char name[100];
- struct reftable_ref_record ref = {
- .refname = name,
- .update_index = reftable_stack_next_update_index(st),
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- snprintf(name, sizeof(name), "branch%04d", i);
-
- err = reftable_stack_add(st, &write_test_ref, &ref);
- EXPECT_ERR(err);
-
- err = reftable_stack_auto_compact(st);
- EXPECT_ERR(err);
- EXPECT(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
- }
-
- EXPECT(reftable_stack_compaction_stats(st)->entries_written <
- (uint64_t)(N * fastlog2(N)));
-
- reftable_stack_destroy(st);
- clear_dir(dir);
-}
-
-static void test_reftable_stack_compaction_concurrent(void)
-{
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st1 = NULL, *st2 = NULL;
- char *dir = get_tmp_dir(__LINE__);
-
- int err, i;
- int N = 3;
-
- err = reftable_new_stack(&st1, dir, cfg);
- EXPECT_ERR(err);
-
- for (i = 0; i < N; i++) {
- char name[100];
- struct reftable_ref_record ref = {
- .refname = name,
- .update_index = reftable_stack_next_update_index(st1),
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- snprintf(name, sizeof(name), "branch%04d", i);
-
- err = reftable_stack_add(st1, &write_test_ref, &ref);
- EXPECT_ERR(err);
- }
-
- err = reftable_new_stack(&st2, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_compact_all(st1, NULL);
- EXPECT_ERR(err);
-
- reftable_stack_destroy(st1);
- reftable_stack_destroy(st2);
-
- EXPECT(count_dir_entries(dir) == 2);
- clear_dir(dir);
-}
-
-static void unclean_stack_close(struct reftable_stack *st)
-{
- /* break abstraction boundary to simulate unclean shutdown. */
- int i = 0;
- for (; i < st->readers_len; i++) {
- reftable_reader_free(st->readers[i]);
- }
- st->readers_len = 0;
- FREE_AND_NULL(st->readers);
-}
-
-static void test_reftable_stack_compaction_concurrent_clean(void)
-{
- struct reftable_write_options cfg = { 0 };
- struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL;
- char *dir = get_tmp_dir(__LINE__);
-
- int err, i;
- int N = 3;
-
- err = reftable_new_stack(&st1, dir, cfg);
- EXPECT_ERR(err);
-
- for (i = 0; i < N; i++) {
- char name[100];
- struct reftable_ref_record ref = {
- .refname = name,
- .update_index = reftable_stack_next_update_index(st1),
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = "master",
- };
- snprintf(name, sizeof(name), "branch%04d", i);
-
- err = reftable_stack_add(st1, &write_test_ref, &ref);
- EXPECT_ERR(err);
- }
-
- err = reftable_new_stack(&st2, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_compact_all(st1, NULL);
- EXPECT_ERR(err);
-
- unclean_stack_close(st1);
- unclean_stack_close(st2);
-
- err = reftable_new_stack(&st3, dir, cfg);
- EXPECT_ERR(err);
-
- err = reftable_stack_clean(st3);
- EXPECT_ERR(err);
- EXPECT(count_dir_entries(dir) == 2);
-
- reftable_stack_destroy(st1);
- reftable_stack_destroy(st2);
- reftable_stack_destroy(st3);
-
- clear_dir(dir);
-}
-
-int stack_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_empty_add);
- RUN_TEST(test_log2);
- RUN_TEST(test_names_equal);
- RUN_TEST(test_parse_names);
- RUN_TEST(test_read_file);
- RUN_TEST(test_reflog_expire);
- RUN_TEST(test_reftable_stack_add);
- RUN_TEST(test_reftable_stack_add_one);
- RUN_TEST(test_reftable_stack_auto_compaction);
- RUN_TEST(test_reftable_stack_compaction_concurrent);
- RUN_TEST(test_reftable_stack_compaction_concurrent_clean);
- RUN_TEST(test_reftable_stack_hash_id);
- RUN_TEST(test_reftable_stack_lock_failure);
- RUN_TEST(test_reftable_stack_log_normalize);
- RUN_TEST(test_reftable_stack_tombstone);
- RUN_TEST(test_reftable_stack_transaction_api);
- RUN_TEST(test_reftable_stack_update_index_check);
- RUN_TEST(test_reftable_stack_uptodate);
- RUN_TEST(test_reftable_stack_validate_refname);
- RUN_TEST(test_sizes_to_segments);
- RUN_TEST(test_sizes_to_segments_all_equal);
- RUN_TEST(test_sizes_to_segments_empty);
- RUN_TEST(test_suggest_compaction_segment);
- RUN_TEST(test_suggest_compaction_segment_nothing);
- return 0;
-}
diff --git a/reftable/system.h b/reftable/system.h
index 6b74a81514..5ec8583343 100644
--- a/reftable/system.h
+++ b/reftable/system.h
@@ -12,8 +12,9 @@ https://developers.google.com/open-source/licenses/bsd
/* This header glues the reftable library to the rest of Git */
#include "git-compat-util.h"
-#include "strbuf.h"
-#include "hash-ll.h" /* hash ID, sizes.*/
+#include "lockfile.h"
+#include "tempfile.h"
+#include "hash.h" /* hash ID, sizes.*/
#include "dir.h" /* remove_dir_recursively, for tests.*/
int hash_size(uint32_t id);
diff --git a/reftable/test_framework.c b/reftable/test_framework.c
deleted file mode 100644
index 84ac972cad..0000000000
--- a/reftable/test_framework.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-#include "test_framework.h"
-
-#include "basics.h"
-
-void set_test_hash(uint8_t *p, int i)
-{
- memset(p, (uint8_t)i, hash_size(GIT_SHA1_FORMAT_ID));
-}
-
-ssize_t strbuf_add_void(void *b, const void *data, size_t sz)
-{
- strbuf_add(b, data, sz);
- return sz;
-}
diff --git a/reftable/test_framework.h b/reftable/test_framework.h
deleted file mode 100644
index 774cb275bf..0000000000
--- a/reftable/test_framework.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef TEST_FRAMEWORK_H
-#define TEST_FRAMEWORK_H
-
-#include "system.h"
-#include "reftable-error.h"
-
-#define EXPECT_ERR(c) \
- if (c != 0) { \
- fflush(stderr); \
- fflush(stdout); \
- fprintf(stderr, "%s: %d: error == %d (%s), want 0\n", \
- __FILE__, __LINE__, c, reftable_error_str(c)); \
- abort(); \
- }
-
-#define EXPECT_STREQ(a, b) \
- if (strcmp(a, b)) { \
- fflush(stderr); \
- fflush(stdout); \
- fprintf(stderr, "%s:%d: %s (%s) != %s (%s)\n", __FILE__, \
- __LINE__, #a, a, #b, b); \
- abort(); \
- }
-
-#define EXPECT(c) \
- if (!(c)) { \
- fflush(stderr); \
- fflush(stdout); \
- fprintf(stderr, "%s: %d: failed assertion %s\n", __FILE__, \
- __LINE__, #c); \
- abort(); \
- }
-
-#define RUN_TEST(f) \
- fprintf(stderr, "running %s\n", #f); \
- fflush(stderr); \
- f();
-
-void set_test_hash(uint8_t *p, int i);
-
-/* Like strbuf_add, but suitable for passing to reftable_new_writer
- */
-ssize_t strbuf_add_void(void *b, const void *data, size_t sz);
-
-#endif
diff --git a/reftable/tree.c b/reftable/tree.c
index a5bf880985..f4dbe72090 100644
--- a/reftable/tree.c
+++ b/reftable/tree.c
@@ -11,53 +11,64 @@ https://developers.google.com/open-source/licenses/bsd
#include "basics.h"
-struct tree_node *tree_search(void *key, struct tree_node **rootp,
- int (*compare)(const void *, const void *),
- int insert)
+struct tree_node *tree_search(struct tree_node *tree,
+ void *key,
+ int (*compare)(const void *, const void *))
{
int res;
+ if (!tree)
+ return NULL;
+ res = compare(key, tree->key);
+ if (res < 0)
+ return tree_search(tree->left, key, compare);
+ else if (res > 0)
+ return tree_search(tree->right, key, compare);
+ return tree;
+}
+
+struct tree_node *tree_insert(struct tree_node **rootp,
+ void *key,
+ int (*compare)(const void *, const void *))
+{
+ int res;
+
if (!*rootp) {
- if (!insert) {
+ struct tree_node *n;
+
+ REFTABLE_CALLOC_ARRAY(n, 1);
+ if (!n)
return NULL;
- } else {
- struct tree_node *n =
- reftable_calloc(sizeof(struct tree_node));
- n->key = key;
- *rootp = n;
- return *rootp;
- }
+
+ n->key = key;
+ *rootp = n;
+ return *rootp;
}
res = compare(key, (*rootp)->key);
if (res < 0)
- return tree_search(key, &(*rootp)->left, compare, insert);
+ return tree_insert(&(*rootp)->left, key, compare);
else if (res > 0)
- return tree_search(key, &(*rootp)->right, compare, insert);
+ return tree_insert(&(*rootp)->right, key, compare);
return *rootp;
}
void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
void *arg)
{
- if (t->left) {
+ if (t->left)
infix_walk(t->left, action, arg);
- }
action(arg, t->key);
- if (t->right) {
+ if (t->right)
infix_walk(t->right, action, arg);
- }
}
void tree_free(struct tree_node *t)
{
- if (!t) {
+ if (!t)
return;
- }
- if (t->left) {
+ if (t->left)
tree_free(t->left);
- }
- if (t->right) {
+ if (t->right)
tree_free(t->right);
- }
reftable_free(t);
}
diff --git a/reftable/tree.h b/reftable/tree.h
index fbdd002e23..9604453b6d 100644
--- a/reftable/tree.h
+++ b/reftable/tree.h
@@ -15,12 +15,23 @@ struct tree_node {
struct tree_node *left, *right;
};
-/* looks for `key` in `rootp` using `compare` as comparison function. If insert
- * is set, insert the key if it's not found. Else, return NULL.
+/*
+ * Search the tree for the node matching the given key using `compare` as
+ * comparison function. Returns the node whose key matches or `NULL` in case
+ * the key does not exist in the tree.
+ */
+struct tree_node *tree_search(struct tree_node *tree,
+ void *key,
+ int (*compare)(const void *, const void *));
+
+/*
+ * Insert a node into the tree. Returns the newly inserted node if the key does
+ * not yet exist. Otherwise it returns the preexisting node. Returns `NULL`
+ * when allocating the new node fails.
*/
-struct tree_node *tree_search(void *key, struct tree_node **rootp,
- int (*compare)(const void *, const void *),
- int insert);
+struct tree_node *tree_insert(struct tree_node **rootp,
+ void *key,
+ int (*compare)(const void *, const void *));
/* performs an infix walk of the tree. */
void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
diff --git a/reftable/tree_test.c b/reftable/tree_test.c
deleted file mode 100644
index ac3a045ad4..0000000000
--- a/reftable/tree_test.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-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 "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-static int test_compare(const void *a, const void *b)
-{
- return (char *)a - (char *)b;
-}
-
-struct curry {
- void *last;
-};
-
-static void check_increasing(void *arg, void *key)
-{
- struct curry *c = arg;
- if (c->last) {
- EXPECT(test_compare(c->last, key) < 0);
- }
- c->last = key;
-}
-
-static void test_tree(void)
-{
- struct tree_node *root = NULL;
-
- void *values[11] = { NULL };
- struct tree_node *nodes[11] = { NULL };
- int i = 1;
- struct curry c = { NULL };
- do {
- nodes[i] = tree_search(values + i, &root, &test_compare, 1);
- i = (i * 7) % 11;
- } while (i != 1);
-
- for (i = 1; i < ARRAY_SIZE(nodes); i++) {
- EXPECT(values + i == nodes[i]->key);
- EXPECT(nodes[i] ==
- tree_search(values + i, &root, &test_compare, 0));
- }
-
- infix_walk(root, check_increasing, &c);
- tree_free(root);
-}
-
-int tree_test_main(int argc, const char *argv[])
-{
- RUN_TEST(test_tree);
- return 0;
-}
diff --git a/reftable/writer.c b/reftable/writer.c
index 2e322a5683..be0fae6cb2 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -49,8 +49,14 @@ static int padded_write(struct reftable_writer *w, uint8_t *data, size_t len,
{
int n = 0;
if (w->pending_padding > 0) {
- uint8_t *zeroed = reftable_calloc(w->pending_padding);
- int n = w->write(w->write_arg, zeroed, w->pending_padding);
+ uint8_t *zeroed;
+ int n;
+
+ zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
+ if (!zeroed)
+ return -1;
+
+ n = w->write(w->write_arg, zeroed, w->pending_padding);
if (n < 0)
return n;
@@ -102,43 +108,61 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
return header_size(writer_version(w));
}
-static void writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
+static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
{
- int block_start = 0;
- if (w->next == 0) {
+ int block_start = 0, ret;
+
+ if (w->next == 0)
block_start = header_size(writer_version(w));
- }
- strbuf_release(&w->last_key);
- block_writer_init(&w->block_writer_data, typ, w->block,
- w->opts.block_size, block_start,
- hash_size(w->opts.hash_id));
+ reftable_buf_reset(&w->last_key);
+ ret = block_writer_init(&w->block_writer_data, typ, w->block,
+ w->opts.block_size, block_start,
+ hash_size(w->opts.hash_id));
+ if (ret < 0)
+ return ret;
+
w->block_writer = &w->block_writer_data;
w->block_writer->restart_interval = w->opts.restart_interval;
-}
-static struct strbuf reftable_empty_strbuf = STRBUF_INIT;
+ return 0;
+}
-struct reftable_writer *
-reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
- void *writer_arg, struct reftable_write_options *opts)
+int reftable_writer_new(struct reftable_writer **out,
+ ssize_t (*writer_func)(void *, const void *, size_t),
+ int (*flush_func)(void *),
+ void *writer_arg, const struct reftable_write_options *_opts)
{
- struct reftable_writer *wp =
- reftable_calloc(sizeof(struct reftable_writer));
- strbuf_init(&wp->block_writer_data.last_key, 0);
- options_set_defaults(opts);
- if (opts->block_size >= (1 << 24)) {
- /* TODO - error return? */
- abort();
+ struct reftable_write_options opts = {0};
+ struct reftable_writer *wp;
+
+ wp = reftable_calloc(1, sizeof(*wp));
+ if (!wp)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ if (_opts)
+ opts = *_opts;
+ options_set_defaults(&opts);
+ if (opts.block_size >= (1 << 24))
+ BUG("configured block size exceeds 16MB");
+
+ reftable_buf_init(&wp->block_writer_data.last_key);
+ reftable_buf_init(&wp->last_key);
+ reftable_buf_init(&wp->scratch);
+ REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size);
+ if (!wp->block) {
+ reftable_free(wp);
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
}
- wp->last_key = reftable_empty_strbuf;
- wp->block = reftable_calloc(opts->block_size);
wp->write = writer_func;
wp->write_arg = writer_arg;
- wp->opts = *opts;
+ wp->opts = opts;
+ wp->flush = flush_func;
writer_reinit_block_writer(wp, BLOCK_TYPE_REF);
- return wp;
+ *out = wp;
+
+ return 0;
}
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
@@ -148,16 +172,27 @@ void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
w->max_update_index = max;
}
+static void writer_release(struct reftable_writer *w)
+{
+ if (w) {
+ reftable_free(w->block);
+ w->block = NULL;
+ block_writer_release(&w->block_writer_data);
+ w->block_writer = NULL;
+ writer_clear_index(w);
+ reftable_buf_release(&w->last_key);
+ reftable_buf_release(&w->scratch);
+ }
+}
+
void reftable_writer_free(struct reftable_writer *w)
{
- if (!w)
- return;
- reftable_free(w->block);
+ writer_release(w);
reftable_free(w);
}
struct obj_index_tree_node {
- struct strbuf hash;
+ struct reftable_buf hash;
uint64_t *offsets;
size_t offset_len;
size_t offset_cap;
@@ -165,90 +200,119 @@ struct obj_index_tree_node {
#define OBJ_INDEX_TREE_NODE_INIT \
{ \
- .hash = STRBUF_INIT \
+ .hash = REFTABLE_BUF_INIT \
}
static int obj_index_tree_node_compare(const void *a, const void *b)
{
- return strbuf_cmp(&((const struct obj_index_tree_node *)a)->hash,
+ return reftable_buf_cmp(&((const struct obj_index_tree_node *)a)->hash,
&((const struct obj_index_tree_node *)b)->hash);
}
-static void writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
+static int writer_index_hash(struct reftable_writer *w, struct reftable_buf *hash)
{
uint64_t off = w->next;
-
struct obj_index_tree_node want = { .hash = *hash };
+ struct obj_index_tree_node *key;
+ struct tree_node *node;
- struct tree_node *node = tree_search(&want, &w->obj_index_tree,
- &obj_index_tree_node_compare, 0);
- struct obj_index_tree_node *key = NULL;
+ node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare);
if (!node) {
struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT;
- key = reftable_malloc(sizeof(struct obj_index_tree_node));
+ int err;
+
+ key = reftable_malloc(sizeof(*key));
+ if (!key)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
*key = empty;
- strbuf_reset(&key->hash);
- strbuf_addbuf(&key->hash, hash);
- tree_search((void *)key, &w->obj_index_tree,
- &obj_index_tree_node_compare, 1);
+ reftable_buf_reset(&key->hash);
+ err = reftable_buf_add(&key->hash, hash->buf, hash->len);
+ if (err < 0)
+ return err;
+ tree_insert(&w->obj_index_tree, key,
+ &obj_index_tree_node_compare);
} else {
key = node->key;
}
- if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) {
- return;
- }
-
- if (key->offset_len == key->offset_cap) {
- key->offset_cap = 2 * key->offset_cap + 1;
- key->offsets = reftable_realloc(
- key->offsets, sizeof(uint64_t) * key->offset_cap);
- }
+ if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off)
+ return 0;
+ REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap);
+ if (!key->offsets)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
key->offsets[key->offset_len++] = off;
+
+ return 0;
}
static int writer_add_record(struct reftable_writer *w,
struct reftable_record *rec)
{
- struct strbuf key = STRBUF_INIT;
- int err = -1;
- reftable_record_key(rec, &key);
- if (strbuf_cmp(&w->last_key, &key) >= 0) {
+ int err;
+
+ err = reftable_record_key(rec, &w->scratch);
+ if (err < 0)
+ goto done;
+
+ if (reftable_buf_cmp(&w->last_key, &w->scratch) >= 0) {
err = REFTABLE_API_ERROR;
goto done;
}
- strbuf_reset(&w->last_key);
- strbuf_addbuf(&w->last_key, &key);
+ reftable_buf_reset(&w->last_key);
+ err = reftable_buf_add(&w->last_key, w->scratch.buf, w->scratch.len);
+ if (err < 0)
+ goto done;
+
if (!w->block_writer) {
- writer_reinit_block_writer(w, reftable_record_type(rec));
+ err = writer_reinit_block_writer(w, reftable_record_type(rec));
+ if (err < 0)
+ goto done;
}
- assert(block_writer_type(w->block_writer) == reftable_record_type(rec));
+ if (block_writer_type(w->block_writer) != reftable_record_type(rec))
+ BUG("record of type %d added to writer of type %d",
+ reftable_record_type(rec), block_writer_type(w->block_writer));
- if (block_writer_add(w->block_writer, rec) == 0) {
+ /*
+ * Try to add the record to the writer. If this succeeds then we're
+ * done. Otherwise the block writer may have hit the block size limit
+ * and needs to be flushed.
+ */
+ if (!block_writer_add(w->block_writer, rec)) {
err = 0;
goto done;
}
+ /*
+ * The current block is full, so we need to flush and reinitialize the
+ * writer to start writing the next block.
+ */
err = writer_flush_block(w);
- if (err < 0) {
+ if (err < 0)
+ goto done;
+ err = writer_reinit_block_writer(w, reftable_record_type(rec));
+ if (err < 0)
goto done;
- }
- writer_reinit_block_writer(w, reftable_record_type(rec));
+ /*
+ * Try to add the record to the writer again. If this still fails then
+ * the record does not fit into the block size.
+ *
+ * TODO: it would be great to have `block_writer_add()` return proper
+ * error codes so that we don't have to second-guess the failure
+ * mode here.
+ */
err = block_writer_add(w->block_writer, rec);
- if (err == -1) {
- /* we are writing into memory, so an error can only mean it
- * doesn't fit. */
+ if (err) {
err = REFTABLE_ENTRY_TOO_BIG_ERROR;
goto done;
}
done:
- strbuf_release(&key);
return err;
}
@@ -261,11 +325,10 @@ int reftable_writer_add_ref(struct reftable_writer *w,
.ref = *ref
},
};
- int err = 0;
+ int err;
- if (!ref->refname)
- return REFTABLE_API_ERROR;
- if (ref->update_index < w->min_update_index ||
+ if (!ref->refname ||
+ ref->update_index < w->min_update_index ||
ref->update_index > w->max_update_index)
return REFTABLE_API_ERROR;
@@ -273,24 +336,36 @@ int reftable_writer_add_ref(struct reftable_writer *w,
err = writer_add_record(w, &rec);
if (err < 0)
- return err;
+ goto out;
if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) {
- struct strbuf h = STRBUF_INIT;
- strbuf_add(&h, (char *)reftable_ref_record_val1(ref),
- hash_size(w->opts.hash_id));
- writer_index_hash(w, &h);
- strbuf_release(&h);
+ reftable_buf_reset(&w->scratch);
+ err = reftable_buf_add(&w->scratch, (char *)reftable_ref_record_val1(ref),
+ hash_size(w->opts.hash_id));
+ if (err < 0)
+ goto out;
+
+ err = writer_index_hash(w, &w->scratch);
+ if (err < 0)
+ goto out;
}
if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) {
- struct strbuf h = STRBUF_INIT;
- strbuf_add(&h, reftable_ref_record_val2(ref),
- hash_size(w->opts.hash_id));
- writer_index_hash(w, &h);
- strbuf_release(&h);
+ reftable_buf_reset(&w->scratch);
+ err = reftable_buf_add(&w->scratch, reftable_ref_record_val2(ref),
+ hash_size(w->opts.hash_id));
+ if (err < 0)
+ goto out;
+
+ err = writer_index_hash(w, &w->scratch);
+ if (err < 0)
+ goto out;
}
- return 0;
+
+ err = 0;
+
+out:
+ return err;
}
int reftable_writer_add_refs(struct reftable_writer *w,
@@ -330,7 +405,7 @@ int reftable_writer_add_log(struct reftable_writer *w,
struct reftable_log_record *log)
{
char *input_log_message = NULL;
- struct strbuf cleaned_message = STRBUF_INIT;
+ struct reftable_buf cleaned_message = REFTABLE_BUF_INIT;
int err = 0;
if (log->value_type == REFTABLE_LOG_DELETION)
@@ -341,24 +416,34 @@ int reftable_writer_add_log(struct reftable_writer *w,
input_log_message = log->value.update.message;
if (!w->opts.exact_log_message && log->value.update.message) {
- strbuf_addstr(&cleaned_message, log->value.update.message);
+ err = reftable_buf_addstr(&cleaned_message, log->value.update.message);
+ if (err < 0)
+ goto done;
+
while (cleaned_message.len &&
- cleaned_message.buf[cleaned_message.len - 1] == '\n')
- strbuf_setlen(&cleaned_message,
- cleaned_message.len - 1);
+ cleaned_message.buf[cleaned_message.len - 1] == '\n') {
+ err = reftable_buf_setlen(&cleaned_message,
+ cleaned_message.len - 1);
+ if (err < 0)
+ goto done;
+ }
if (strchr(cleaned_message.buf, '\n')) {
/* multiple lines not allowed. */
err = REFTABLE_API_ERROR;
goto done;
}
- strbuf_addstr(&cleaned_message, "\n");
+
+ err = reftable_buf_addstr(&cleaned_message, "\n");
+ if (err < 0)
+ goto done;
+
log->value.update.message = cleaned_message.buf;
}
err = reftable_writer_add_log_verbatim(w, log);
log->value.update.message = input_log_message;
done:
- strbuf_release(&cleaned_message);
+ reftable_buf_release(&cleaned_message);
return err;
}
@@ -377,24 +462,45 @@ int reftable_writer_add_logs(struct reftable_writer *w,
static int writer_finish_section(struct reftable_writer *w)
{
+ struct reftable_block_stats *bstats = NULL;
uint8_t typ = block_writer_type(w->block_writer);
uint64_t index_start = 0;
int max_level = 0;
- int threshold = w->opts.unpadded ? 1 : 3;
+ size_t threshold = w->opts.unpadded ? 1 : 3;
int before_blocks = w->stats.idx_stats.blocks;
- int err = writer_flush_block(w);
- int i = 0;
- struct reftable_block_stats *bstats = NULL;
+ int err;
+
+ err = writer_flush_block(w);
if (err < 0)
return err;
+ /*
+ * When the section we are about to index has a lot of blocks then the
+ * index itself may span across multiple blocks, as well. This would
+ * require a linear scan over index blocks only to find the desired
+ * indexed block, which is inefficient. Instead, we write a multi-level
+ * index where index records of level N+1 will refer to index blocks of
+ * level N. This isn't constant time, either, but at least logarithmic.
+ *
+ * This loop handles writing this multi-level index. Note that we write
+ * the lowest-level index pointing to the indexed blocks first. We then
+ * continue writing additional index levels until the current level has
+ * less blocks than the threshold so that the highest level will be at
+ * the end of the index section.
+ *
+ * Readers are thus required to start reading the index section from
+ * its end, which is why we set `index_start` to the beginning of the
+ * last index section.
+ */
while (w->index_len > threshold) {
struct reftable_index_record *idx = NULL;
- int idx_len = 0;
+ size_t i, idx_len;
max_level++;
index_start = w->next;
- writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
+ err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
+ if (err < 0)
+ return err;
idx = w->index;
idx_len = w->index_len;
@@ -409,48 +515,41 @@ static int writer_finish_section(struct reftable_writer *w)
.idx = idx[i],
},
};
- if (block_writer_add(w->block_writer, &rec) == 0) {
- continue;
- }
- err = writer_flush_block(w);
+ err = writer_add_record(w, &rec);
if (err < 0)
return err;
+ }
- writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
+ err = writer_flush_block(w);
+ if (err < 0)
+ return err;
- err = block_writer_add(w->block_writer, &rec);
- if (err != 0) {
- /* write into fresh block should always succeed
- */
- abort();
- }
- }
- for (i = 0; i < idx_len; i++) {
- strbuf_release(&idx[i].last_key);
- }
+ for (i = 0; i < idx_len; i++)
+ reftable_buf_release(&idx[i].last_key);
reftable_free(idx);
}
+ /*
+ * The index may still contain a number of index blocks lower than the
+ * threshold. Clear it so that these entries don't leak into the next
+ * index section.
+ */
writer_clear_index(w);
- err = writer_flush_block(w);
- if (err < 0)
- return err;
-
bstats = writer_reftable_block_stats(w, typ);
bstats->index_blocks = w->stats.idx_stats.blocks - before_blocks;
bstats->index_offset = index_start;
bstats->max_index_level = max_level;
/* Reinit lastKey, as the next section can start with any key. */
- w->last_key.len = 0;
+ reftable_buf_reset(&w->last_key);
return 0;
}
struct common_prefix_arg {
- struct strbuf *last;
+ struct reftable_buf *last;
int max;
};
@@ -495,7 +594,10 @@ static void write_object_record(void *void_arg, void *key)
if (arg->err < 0)
goto done;
- writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
+ arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
+ if (arg->err < 0)
+ goto done;
+
arg->err = block_writer_add(arg->w->block_writer, &rec);
if (arg->err == 0)
goto done;
@@ -509,12 +611,12 @@ static void write_object_record(void *void_arg, void *key)
done:;
}
-static void object_record_free(void *void_arg, void *key)
+static void object_record_free(void *void_arg UNUSED, void *key)
{
struct obj_index_tree_node *entry = key;
- FREE_AND_NULL(entry->offsets);
- strbuf_release(&entry->hash);
+ REFTABLE_FREE_AND_NULL(entry->offsets);
+ reftable_buf_release(&entry->hash);
reftable_free(entry);
}
@@ -524,16 +626,18 @@ static int writer_dump_object_index(struct reftable_writer *w)
struct common_prefix_arg common = {
.max = 1, /* obj_id_len should be >= 2. */
};
- if (w->obj_index_tree) {
+ int err;
+
+ if (w->obj_index_tree)
infix_walk(w->obj_index_tree, &update_common, &common);
- }
w->stats.object_id_len = common.max + 1;
- writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
+ err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
+ if (err < 0)
+ return err;
- if (w->obj_index_tree) {
+ if (w->obj_index_tree)
infix_walk(w->obj_index_tree, &write_object_record, &closure);
- }
if (closure.err < 0)
return closure.err;
@@ -603,6 +707,12 @@ int reftable_writer_close(struct reftable_writer *w)
put_be32(p, crc32(0, footer, p - footer));
p += 4;
+ err = w->flush(w->write_arg);
+ if (err < 0) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
err = padded_write(w, footer, footer_size(writer_version(w)), 0);
if (err < 0)
goto done;
@@ -613,82 +723,93 @@ int reftable_writer_close(struct reftable_writer *w)
}
done:
- /* free up memory. */
- block_writer_release(&w->block_writer_data);
- writer_clear_index(w);
- strbuf_release(&w->last_key);
+ writer_release(w);
return err;
}
static void writer_clear_index(struct reftable_writer *w)
{
- int i = 0;
- for (i = 0; i < w->index_len; i++) {
- strbuf_release(&w->index[i].last_key);
- }
-
- FREE_AND_NULL(w->index);
+ for (size_t i = 0; w->index && i < w->index_len; i++)
+ reftable_buf_release(&w->index[i].last_key);
+ REFTABLE_FREE_AND_NULL(w->index);
w->index_len = 0;
w->index_cap = 0;
}
-static const int debug = 0;
-
static int writer_flush_nonempty_block(struct reftable_writer *w)
{
+ struct reftable_index_record index_record = {
+ .last_key = REFTABLE_BUF_INIT,
+ };
uint8_t typ = block_writer_type(w->block_writer);
- struct reftable_block_stats *bstats =
- writer_reftable_block_stats(w, typ);
- uint64_t block_typ_off = (bstats->blocks == 0) ? w->next : 0;
- int raw_bytes = block_writer_finish(w->block_writer);
- int padding = 0;
- int err = 0;
- struct reftable_index_record ir = { .last_key = STRBUF_INIT };
+ struct reftable_block_stats *bstats;
+ int raw_bytes, padding = 0, err;
+ uint64_t block_typ_off;
+
+ /*
+ * Finish the current block. This will cause the block writer to emit
+ * restart points and potentially compress records in case we are
+ * writing a log block.
+ *
+ * Note that this is still happening in memory.
+ */
+ raw_bytes = block_writer_finish(w->block_writer);
if (raw_bytes < 0)
return raw_bytes;
- if (!w->opts.unpadded && typ != BLOCK_TYPE_LOG) {
+ /*
+ * By default, all records except for log records are padded to the
+ * block size.
+ */
+ if (!w->opts.unpadded && typ != BLOCK_TYPE_LOG)
padding = w->opts.block_size - raw_bytes;
- }
- if (block_typ_off > 0) {
+ bstats = writer_reftable_block_stats(w, typ);
+ block_typ_off = (bstats->blocks == 0) ? w->next : 0;
+ if (block_typ_off > 0)
bstats->offset = block_typ_off;
- }
-
bstats->entries += w->block_writer->entries;
bstats->restarts += w->block_writer->restart_len;
bstats->blocks++;
w->stats.blocks++;
- if (debug) {
- fprintf(stderr, "block %c off %" PRIu64 " sz %d (%d)\n", typ,
- w->next, raw_bytes,
- get_be24(w->block + w->block_writer->header_off + 1));
- }
-
- if (w->next == 0) {
+ /*
+ * If this is the first block we're writing to the table then we need
+ * to also write the reftable header.
+ */
+ if (!w->next)
writer_write_header(w, w->block);
- }
err = padded_write(w, w->block, raw_bytes, padding);
if (err < 0)
return err;
- if (w->index_cap == w->index_len) {
- w->index_cap = 2 * w->index_cap + 1;
- w->index = reftable_realloc(
- w->index,
- sizeof(struct reftable_index_record) * w->index_cap);
- }
-
- ir.offset = w->next;
- strbuf_reset(&ir.last_key);
- strbuf_addbuf(&ir.last_key, &w->block_writer->last_key);
- w->index[w->index_len] = ir;
-
+ /*
+ * Add an index record for every block that we're writing. If we end up
+ * having more than a threshold of index records we will end up writing
+ * an index section in `writer_finish_section()`. Each index record
+ * contains the last record key of the block it is indexing as well as
+ * the offset of that block.
+ *
+ * Note that this also applies when flushing index blocks, in which
+ * case we will end up with a multi-level index.
+ */
+ REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap);
+ if (!w->index)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ index_record.offset = w->next;
+ reftable_buf_reset(&index_record.last_key);
+ err = reftable_buf_add(&index_record.last_key, w->block_writer->last_key.buf,
+ w->block_writer->last_key.len);
+ if (err < 0)
+ return err;
+ w->index[w->index_len] = index_record;
w->index_len++;
+
w->next += padding + raw_bytes;
w->block_writer = NULL;
+
return 0;
}
diff --git a/reftable/writer.h b/reftable/writer.h
index 09b88673d9..1f4788a430 100644
--- a/reftable/writer.h
+++ b/reftable/writer.h
@@ -16,9 +16,12 @@ https://developers.google.com/open-source/licenses/bsd
struct reftable_writer {
ssize_t (*write)(void *, const void *, size_t);
+ int (*flush)(void *);
void *write_arg;
int pending_padding;
- struct strbuf last_key;
+ struct reftable_buf last_key;
+ /* Scratch buffer used to avoid allocations. */
+ struct reftable_buf scratch;
/* offset of next block to write. */
uint64_t next;
diff --git a/remote-curl.c b/remote-curl.c
index dad241e89d..9a71e04301 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "git-curl-compat.h"
#include "config.h"
@@ -9,11 +11,9 @@
#include "strbuf.h"
#include "walker.h"
#include "http.h"
-#include "exec-cmd.h"
#include "run-command.h"
#include "pkt-line.h"
#include "string-list.h"
-#include "sideband.h"
#include "strvec.h"
#include "credential.h"
#include "oid-array.h"
@@ -23,6 +23,7 @@
#include "quote.h"
#include "trace2.h"
#include "transport.h"
+#include "url.h"
#include "write-or-die.h"
static struct remote *remote;
@@ -59,9 +60,9 @@ struct options {
static struct options options;
static struct string_list cas_options = STRING_LIST_INIT_DUP;
-static int set_option(const char *name, const char *value)
+static int set_option(const char *name, size_t namelen, const char *value)
{
- if (!strcmp(name, "verbosity")) {
+ if (!strncmp(name, "verbosity", namelen)) {
char *end;
int v = strtol(value, &end, 10);
if (value == end || *end)
@@ -69,7 +70,7 @@ static int set_option(const char *name, const char *value)
options.verbosity = v;
return 0;
}
- else if (!strcmp(name, "progress")) {
+ else if (!strncmp(name, "progress", namelen)) {
if (!strcmp(value, "true"))
options.progress = 1;
else if (!strcmp(value, "false"))
@@ -78,7 +79,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "depth")) {
+ else if (!strncmp(name, "depth", namelen)) {
char *end;
unsigned long v = strtoul(value, &end, 10);
if (value == end || *end)
@@ -86,15 +87,15 @@ static int set_option(const char *name, const char *value)
options.depth = v;
return 0;
}
- else if (!strcmp(name, "deepen-since")) {
+ else if (!strncmp(name, "deepen-since", namelen)) {
options.deepen_since = xstrdup(value);
return 0;
}
- else if (!strcmp(name, "deepen-not")) {
+ else if (!strncmp(name, "deepen-not", namelen)) {
string_list_append(&options.deepen_not, value);
return 0;
}
- else if (!strcmp(name, "deepen-relative")) {
+ else if (!strncmp(name, "deepen-relative", namelen)) {
if (!strcmp(value, "true"))
options.deepen_relative = 1;
else if (!strcmp(value, "false"))
@@ -103,7 +104,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "followtags")) {
+ else if (!strncmp(name, "followtags", namelen)) {
if (!strcmp(value, "true"))
options.followtags = 1;
else if (!strcmp(value, "false"))
@@ -112,7 +113,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "dry-run")) {
+ else if (!strncmp(name, "dry-run", namelen)) {
if (!strcmp(value, "true"))
options.dry_run = 1;
else if (!strcmp(value, "false"))
@@ -121,7 +122,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "check-connectivity")) {
+ else if (!strncmp(name, "check-connectivity", namelen)) {
if (!strcmp(value, "true"))
options.check_self_contained_and_connected = 1;
else if (!strcmp(value, "false"))
@@ -130,7 +131,7 @@ static int set_option(const char *name, const char *value)
return -1;
return 0;
}
- else if (!strcmp(name, "cas")) {
+ else if (!strncmp(name, "cas", namelen)) {
struct strbuf val = STRBUF_INIT;
strbuf_addstr(&val, "--force-with-lease=");
if (*value != '"')
@@ -140,7 +141,7 @@ static int set_option(const char *name, const char *value)
string_list_append(&cas_options, val.buf);
strbuf_release(&val);
return 0;
- } else if (!strcmp(name, TRANS_OPT_FORCE_IF_INCLUDES)) {
+ } else if (!strncmp(name, TRANS_OPT_FORCE_IF_INCLUDES, namelen)) {
if (!strcmp(value, "true"))
options.force_if_includes = 1;
else if (!strcmp(value, "false"))
@@ -148,7 +149,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "cloning")) {
+ } else if (!strncmp(name, "cloning", namelen)) {
if (!strcmp(value, "true"))
options.cloning = 1;
else if (!strcmp(value, "false"))
@@ -156,7 +157,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "update-shallow")) {
+ } else if (!strncmp(name, "update-shallow", namelen)) {
if (!strcmp(value, "true"))
options.update_shallow = 1;
else if (!strcmp(value, "false"))
@@ -164,7 +165,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "pushcert")) {
+ } else if (!strncmp(name, "pushcert", namelen)) {
if (!strcmp(value, "true"))
options.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
else if (!strcmp(value, "false"))
@@ -174,7 +175,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "atomic")) {
+ } else if (!strncmp(name, "atomic", namelen)) {
if (!strcmp(value, "true"))
options.atomic = 1;
else if (!strcmp(value, "false"))
@@ -182,7 +183,7 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "push-option")) {
+ } else if (!strncmp(name, "push-option", namelen)) {
if (*value != '"')
string_list_append(&options.push_options, value);
else {
@@ -193,7 +194,7 @@ static int set_option(const char *name, const char *value)
strbuf_detach(&unquoted, NULL));
}
return 0;
- } else if (!strcmp(name, "family")) {
+ } else if (!strncmp(name, "family", namelen)) {
if (!strcmp(value, "ipv4"))
git_curl_ipresolve = CURL_IPRESOLVE_V4;
else if (!strcmp(value, "ipv6"))
@@ -203,24 +204,19 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
- } else if (!strcmp(name, "from-promisor")) {
+ } else if (!strncmp(name, "from-promisor", namelen)) {
options.from_promisor = 1;
return 0;
- } else if (!strcmp(name, "refetch")) {
+ } else if (!strncmp(name, "refetch", namelen)) {
options.refetch = 1;
return 0;
- } else if (!strcmp(name, "filter")) {
+ } else if (!strncmp(name, "filter", namelen)) {
options.filter = xstrdup(value);
return 0;
- } else if (!strcmp(name, "object-format")) {
- int algo;
+ } else if (!strncmp(name, "object-format", namelen)) {
options.object_format = 1;
- if (strcmp(value, "true")) {
- algo = hash_algo_by_name(value);
- if (algo == GIT_HASH_UNKNOWN)
- die("unknown object format '%s'", value);
- options.hash_algo = &hash_algos[algo];
- }
+ if (strcmp(value, "true"))
+ die(_("unknown value for object-format: %s"), value);
return 0;
} else {
return 1 /* unsupported */;
@@ -272,12 +268,23 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
return list;
}
+/*
+ * Try to detect the hash algorithm used by the remote repository when using
+ * the dumb HTTP transport. As dumb transports cannot tell us the object hash
+ * directly have to derive it from the advertised ref lengths.
+ */
static const struct git_hash_algo *detect_hash_algo(struct discovery *heads)
{
const char *p = memchr(heads->buf, '\t', heads->len);
int algo;
+
+ /*
+ * In case the remote has no refs we have no way to reliably determine
+ * the object hash used by that repository. In that case we simply fall
+ * back to SHA1, which may or may not be correct.
+ */
if (!p)
- return the_hash_algo;
+ return &hash_algos[GIT_HASH_SHA1];
algo = hash_algo_by_length((p - heads->buf) / 2);
if (algo == GIT_HASH_UNKNOWN)
@@ -301,6 +308,12 @@ static struct ref *parse_info_refs(struct discovery *heads)
"is this a git repository?",
transport_anonymize_url(url.buf));
+ /*
+ * Set the repository's hash algo to whatever we have just detected.
+ * This ensures that we can correctly parse the remote references.
+ */
+ repo_set_hash_algo(the_repository, hash_algo_by_ptr(options.hash_algo));
+
data = heads->buf;
start = NULL;
mid = data;
@@ -334,7 +347,7 @@ static struct ref *parse_info_refs(struct discovery *heads)
ref->next = refs;
refs = ref;
} else {
- free(ref);
+ free_one_ref(ref);
}
return refs;
@@ -895,7 +908,7 @@ static curl_off_t xcurl_off_t(size_t len)
static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_received)
{
struct active_request_slot *slot;
- struct curl_slist *headers = http_copy_default_headers();
+ struct curl_slist *headers = NULL;
int use_gzip = rpc->gzip_request;
char *gzip_body = NULL;
size_t gzip_size = 0;
@@ -928,20 +941,24 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
do {
err = probe_rpc(rpc, &results);
if (err == HTTP_REAUTH)
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 0);
} while (err == HTTP_REAUTH);
if (err != HTTP_OK)
return -1;
- if (results.auth_avail & CURLAUTH_GSSNEGOTIATE)
+ if (results.auth_avail & CURLAUTH_GSSNEGOTIATE || http_auth.authtype)
needs_100_continue = 1;
}
+retry:
+ headers = http_copy_default_headers();
headers = curl_slist_append(headers, rpc->hdr_content_type);
headers = curl_slist_append(headers, rpc->hdr_accept);
headers = curl_slist_append(headers, needs_100_continue ?
"Expect: 100-continue" : "Expect:");
+ headers = http_append_auth_header(&http_auth, headers);
+
/* Add Accept-Language header */
if (rpc->hdr_accept_language)
headers = curl_slist_append(headers, rpc->hdr_accept_language);
@@ -950,7 +967,6 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
if (rpc->protocol_header)
headers = curl_slist_append(headers, rpc->protocol_header);
-retry:
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
@@ -1047,7 +1063,8 @@ retry:
rpc->any_written = 0;
err = run_slot(slot, NULL);
if (err == HTTP_REAUTH && !large_request) {
- credential_fill(&http_auth);
+ credential_fill(&http_auth, 0);
+ curl_slist_free_all(headers);
goto retry;
}
if (err != HTTP_OK)
@@ -1450,8 +1467,14 @@ static int stateless_connect(const char *service_name)
* establish a stateless connection, otherwise we need to tell the
* client to fallback to using other transport helper functions to
* complete their request.
+ *
+ * The "git-upload-archive" service is a read-only operation. Fallback
+ * to use "git-upload-pack" service to discover protocol version.
*/
- discover = discover_refs(service_name, 0);
+ if (!strcmp(service_name, "git-upload-archive"))
+ discover = discover_refs("git-upload-pack", 0);
+ else
+ discover = discover_refs(service_name, 0);
if (discover->version != protocol_v2) {
printf("fallback\n");
fflush(stdout);
@@ -1489,9 +1512,11 @@ static int stateless_connect(const char *service_name)
/*
* Dump the capability listing that we got from the server earlier
- * during the info/refs request.
+ * during the info/refs request. This does not work with the
+ * "git-upload-archive" service.
*/
- write_or_die(rpc.in, discover->buf, discover->len);
+ if (strcmp(service_name, "git-upload-archive"))
+ write_or_die(rpc.in, discover->buf, discover->len);
/* Until we see EOF keep sending POSTs */
while (1) {
@@ -1551,7 +1576,7 @@ int cmd_main(int argc, const char **argv)
if (argc > 2) {
end_url_with_slash(&url, argv[2]);
} else {
- end_url_with_slash(&url, remote->url[0]);
+ end_url_with_slash(&url, remote->url.v[0]);
}
http_init(remote, url.buf, 0);
@@ -1567,8 +1592,11 @@ int cmd_main(int argc, const char **argv)
if (buf.len == 0)
break;
if (starts_with(buf.buf, "fetch ")) {
- if (nongit)
- die(_("remote-curl: fetch attempted without a local repo"));
+ if (nongit) {
+ setup_git_directory_gently(&nongit);
+ if (nongit)
+ die(_("remote-curl: fetch attempted without a local repo"));
+ }
parse_fetch(&buf);
} else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
@@ -1579,15 +1607,16 @@ int cmd_main(int argc, const char **argv)
parse_push(&buf);
} else if (skip_prefix(buf.buf, "option ", &arg)) {
- char *value = strchr(arg, ' ');
+ const char *value = strchrnul(arg, ' ');
+ size_t arglen = value - arg;
int result;
- if (value)
- *value++ = '\0';
+ if (*value)
+ value++; /* skip over SP */
else
value = "true";
- result = set_option(arg, value);
+ result = set_option(arg, arglen, value);
if (!result)
printf("ok\n");
else if (result < 0)
diff --git a/remote.c b/remote.c
index abb24822be..10104d11e3 100644
--- a/remote.c
+++ b/remote.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
@@ -15,7 +17,6 @@
#include "diff.h"
#include "revision.h"
#include "dir.h"
-#include "tag.h"
#include "setup.h"
#include "string-list.h"
#include "strvec.h"
@@ -23,6 +24,7 @@
#include "advice.h"
#include "connect.h"
#include "parse-options.h"
+#include "transport.h"
enum map_direction { FROM_SRC, FROM_DST };
@@ -33,10 +35,10 @@ struct counted_string {
static int valid_remote(const struct remote *remote)
{
- return (!!remote->url) || (!!remote->foreign_vcs);
+ return !!remote->url.nr;
}
-static const char *alias_url(const char *url, struct rewrites *r)
+static char *alias_url(const char *url, struct rewrites *r)
{
int i, j;
struct counted_string *longest;
@@ -57,36 +59,43 @@ static const char *alias_url(const char *url, struct rewrites *r)
}
}
if (!longest)
- return url;
+ return NULL;
return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
}
static void add_url(struct remote *remote, const char *url)
{
- ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
- remote->url[remote->url_nr++] = url;
+ if (*url)
+ strvec_push(&remote->url, url);
+ else
+ strvec_clear(&remote->url);
}
static void add_pushurl(struct remote *remote, const char *pushurl)
{
- ALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc);
- remote->pushurl[remote->pushurl_nr++] = pushurl;
+ if (*pushurl)
+ strvec_push(&remote->pushurl, pushurl);
+ else
+ strvec_clear(&remote->pushurl);
}
static void add_pushurl_alias(struct remote_state *remote_state,
struct remote *remote, const char *url)
{
- const char *pushurl = alias_url(url, &remote_state->rewrites_push);
- if (pushurl != url)
- add_pushurl(remote, pushurl);
+ char *alias = alias_url(url, &remote_state->rewrites_push);
+ if (alias)
+ add_pushurl(remote, alias);
+ free(alias);
}
static void add_url_alias(struct remote_state *remote_state,
struct remote *remote, const char *url)
{
- add_url(remote, alias_url(url, &remote_state->rewrites));
+ char *alias = alias_url(url, &remote_state->rewrites);
+ add_url(remote, alias ? alias : url);
add_pushurl_alias(remote_state, remote, url);
+ free(alias);
}
struct remotes_hash_key {
@@ -106,7 +115,7 @@ static int remotes_hash_cmp(const void *cmp_data UNUSED,
b = container_of(entry_or_key, const struct remote, ent);
if (key)
- return strncmp(a->name, key->str, key->len) || a->name[key->len];
+ return !!xstrncmpz(a->name, key->str, key->len);
else
return strcmp(a->name, b->name);
}
@@ -135,6 +144,7 @@ static struct remote *make_remote(struct remote_state *remote_state,
ret->name = xstrndup(name, len);
refspec_init(&ret->push, REFSPEC_PUSH);
refspec_init(&ret->fetch, REFSPEC_FETCH);
+ string_list_init_dup(&ret->server_options);
ALLOC_GROW(remote_state->remotes, remote_state->remotes_nr + 1,
remote_state->remotes_alloc);
@@ -148,22 +158,17 @@ static struct remote *make_remote(struct remote_state *remote_state,
static void remote_clear(struct remote *remote)
{
- int i;
-
free((char *)remote->name);
free((char *)remote->foreign_vcs);
- for (i = 0; i < remote->url_nr; i++)
- free((char *)remote->url[i]);
- FREE_AND_NULL(remote->url);
+ strvec_clear(&remote->url);
+ strvec_clear(&remote->pushurl);
- for (i = 0; i < remote->pushurl_nr; i++)
- free((char *)remote->pushurl[i]);
- FREE_AND_NULL(remote->pushurl);
free((char *)remote->receivepack);
free((char *)remote->uploadpack);
FREE_AND_NULL(remote->http_proxy);
FREE_AND_NULL(remote->http_proxy_authmethod);
+ string_list_clear(&remote->server_options, 0);
}
static void add_merge(struct branch *branch, const char *name)
@@ -190,8 +195,7 @@ static int branches_hash_cmp(const void *cmp_data UNUSED,
b = container_of(entry_or_key, const struct branch, ent);
if (key)
- return strncmp(a->name, key->str, key->len) ||
- a->name[key->len];
+ return !!xstrncmpz(a->name, key->str, key->len);
else
return strcmp(a->name, b->name);
}
@@ -242,6 +246,17 @@ static struct branch *make_branch(struct remote_state *remote_state,
return ret;
}
+static void branch_release(struct branch *branch)
+{
+ free((char *)branch->name);
+ free((char *)branch->refname);
+ free(branch->remote_name);
+ free(branch->pushremote_name);
+ for (int i = 0; i < branch->merge_nr; i++)
+ refspec_item_clear(branch->merge[i]);
+ free(branch->merge);
+}
+
static struct rewrite *make_rewrite(struct rewrites *r,
const char *base, size_t len)
{
@@ -262,6 +277,14 @@ static struct rewrite *make_rewrite(struct rewrites *r,
return ret;
}
+static void rewrites_release(struct rewrites *r)
+{
+ for (int i = 0; i < r->rewrite_nr; i++)
+ free((char *)r->rewrite[i]->base);
+ free(r->rewrite);
+ memset(r, 0, sizeof(*r));
+}
+
static void add_instead_of(struct rewrite *rewrite, const char *instead_of)
{
ALLOC_GROW(rewrite->instead_of, rewrite->instead_of_nr + 1, rewrite->instead_of_alloc);
@@ -294,7 +317,7 @@ static void read_remotes_file(struct remote_state *remote_state,
if (skip_prefix(buf.buf, "URL:", &v))
add_url_alias(remote_state, remote,
- xstrdup(skip_spaces(v)));
+ skip_spaces(v));
else if (skip_prefix(buf.buf, "Push:", &v))
refspec_append(&remote->push, skip_spaces(v));
else if (skip_prefix(buf.buf, "Pull:", &v))
@@ -307,7 +330,7 @@ static void read_remotes_file(struct remote_state *remote_state,
static void read_branches_file(struct remote_state *remote_state,
struct remote *remote)
{
- char *frag;
+ char *frag, *to_free = NULL;
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r");
@@ -335,9 +358,9 @@ static void read_branches_file(struct remote_state *remote_state,
if (frag)
*(frag++) = '\0';
else
- frag = (char *)git_default_branch_name(0);
+ frag = to_free = repo_default_branch_name(the_repository, 0);
- add_url_alias(remote_state, remote, strbuf_detach(&buf, NULL));
+ add_url_alias(remote_state, remote, buf.buf);
refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
frag, remote->name);
@@ -347,6 +370,9 @@ static void read_branches_file(struct remote_state *remote_state,
*/
refspec_appendf(&remote->push, "HEAD:refs/heads/%s", frag);
remote->fetch_tags = 1; /* always auto-follow */
+
+ strbuf_release(&buf);
+ free(to_free);
}
static int handle_config(const char *key, const char *value,
@@ -369,8 +395,10 @@ static int handle_config(const char *key, const char *value,
return -1;
branch = make_branch(remote_state, name, namelen);
if (!strcmp(subkey, "remote")) {
+ FREE_AND_NULL(branch->remote_name);
return git_config_string(&branch->remote_name, key, value);
} else if (!strcmp(subkey, "pushremote")) {
+ FREE_AND_NULL(branch->pushremote_name);
return git_config_string(&branch->pushremote_name, key, value);
} else if (!strcmp(subkey, "merge")) {
if (!value)
@@ -402,9 +430,11 @@ static int handle_config(const char *key, const char *value,
return 0;
/* Handle remote.* variables */
- if (!name && !strcmp(subkey, "pushdefault"))
+ if (!name && !strcmp(subkey, "pushdefault")) {
+ FREE_AND_NULL(remote_state->pushremote_name);
return git_config_string(&remote_state->pushremote_name, key,
value);
+ }
if (!name)
return 0;
@@ -430,29 +460,27 @@ static int handle_config(const char *key, const char *value,
else if (!strcmp(subkey, "prunetags"))
remote->prune_tags = git_config_bool(key, value);
else if (!strcmp(subkey, "url")) {
- const char *v;
- if (git_config_string(&v, key, value))
- return -1;
- add_url(remote, v);
+ if (!value)
+ return config_error_nonbool(key);
+ add_url(remote, value);
} else if (!strcmp(subkey, "pushurl")) {
- const char *v;
- if (git_config_string(&v, key, value))
- return -1;
- add_pushurl(remote, v);
+ if (!value)
+ return config_error_nonbool(key);
+ add_pushurl(remote, value);
} else if (!strcmp(subkey, "push")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
refspec_append(&remote->push, v);
- free((char *)v);
+ free(v);
} else if (!strcmp(subkey, "fetch")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
refspec_append(&remote->fetch, v);
- free((char *)v);
+ free(v);
} else if (!strcmp(subkey, "receivepack")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
if (!remote->receivepack)
@@ -460,7 +488,7 @@ static int handle_config(const char *key, const char *value,
else
error(_("more than one receivepack given, using the first"));
} else if (!strcmp(subkey, "uploadpack")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
if (!remote->uploadpack)
@@ -473,13 +501,19 @@ static int handle_config(const char *key, const char *value,
else if (!strcmp(value, "--tags"))
remote->fetch_tags = 2;
} else if (!strcmp(subkey, "proxy")) {
- return git_config_string((const char **)&remote->http_proxy,
+ FREE_AND_NULL(remote->http_proxy);
+ return git_config_string(&remote->http_proxy,
key, value);
} else if (!strcmp(subkey, "proxyauthmethod")) {
- return git_config_string((const char **)&remote->http_proxy_authmethod,
+ FREE_AND_NULL(remote->http_proxy_authmethod);
+ return git_config_string(&remote->http_proxy_authmethod,
key, value);
} else if (!strcmp(subkey, "vcs")) {
+ FREE_AND_NULL(remote->foreign_vcs);
return git_config_string(&remote->foreign_vcs, key, value);
+ } else if (!strcmp(subkey, "serveroption")) {
+ return parse_transport_option(key, value,
+ &remote->server_options);
}
return 0;
}
@@ -491,25 +525,32 @@ static void alias_all_urls(struct remote_state *remote_state)
int add_pushurl_aliases;
if (!remote_state->remotes[i])
continue;
- for (j = 0; j < remote_state->remotes[i]->pushurl_nr; j++) {
- remote_state->remotes[i]->pushurl[j] =
- alias_url(remote_state->remotes[i]->pushurl[j],
- &remote_state->rewrites);
+ for (j = 0; j < remote_state->remotes[i]->pushurl.nr; j++) {
+ char *alias = alias_url(remote_state->remotes[i]->pushurl.v[j],
+ &remote_state->rewrites);
+ if (alias)
+ strvec_replace(&remote_state->remotes[i]->pushurl,
+ j, alias);
+ free(alias);
}
- add_pushurl_aliases = remote_state->remotes[i]->pushurl_nr == 0;
- for (j = 0; j < remote_state->remotes[i]->url_nr; j++) {
+ add_pushurl_aliases = remote_state->remotes[i]->pushurl.nr == 0;
+ for (j = 0; j < remote_state->remotes[i]->url.nr; j++) {
+ char *alias;
if (add_pushurl_aliases)
add_pushurl_alias(
remote_state, remote_state->remotes[i],
- remote_state->remotes[i]->url[j]);
- remote_state->remotes[i]->url[j] =
- alias_url(remote_state->remotes[i]->url[j],
+ remote_state->remotes[i]->url.v[j]);
+ alias = alias_url(remote_state->remotes[i]->url.v[j],
&remote_state->rewrites);
+ if (alias)
+ strvec_replace(&remote_state->remotes[i]->url,
+ j, alias);
+ free(alias);
}
}
}
-static void read_config(struct repository *repo)
+static void read_config(struct repository *repo, int early)
{
int flag;
@@ -518,7 +559,7 @@ static void read_config(struct repository *repo)
repo->remote_state->initialized = 1;
repo->remote_state->current_branch = NULL;
- if (startup_info->have_repository) {
+ if (startup_info->have_repository && !early) {
const char *head_ref = refs_resolve_ref_unsafe(
get_main_ref_store(repo), "HEAD", 0, NULL, &flag);
if (head_ref && (flag & REF_ISSYMREF) &&
@@ -561,7 +602,7 @@ static const char *remotes_remote_for_branch(struct remote_state *remote_state,
const char *remote_for_branch(struct branch *branch, int *explicit)
{
- read_config(the_repository);
+ read_config(the_repository, 0);
die_on_missing_branch(the_repository, branch);
return remotes_remote_for_branch(the_repository->remote_state, branch,
@@ -587,7 +628,7 @@ remotes_pushremote_for_branch(struct remote_state *remote_state,
const char *pushremote_for_branch(struct branch *branch, int *explicit)
{
- read_config(the_repository);
+ read_config(the_repository, 0);
die_on_missing_branch(the_repository, branch);
return remotes_pushremote_for_branch(the_repository->remote_state,
@@ -597,19 +638,19 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)
static struct remote *remotes_remote_get(struct remote_state *remote_state,
const char *name);
-const char *remote_ref_for_branch(struct branch *branch, int for_push)
+char *remote_ref_for_branch(struct branch *branch, int for_push)
{
- read_config(the_repository);
+ read_config(the_repository, 0);
die_on_missing_branch(the_repository, branch);
if (branch) {
if (!for_push) {
if (branch->merge_nr) {
- return branch->merge_name[0];
+ return xstrdup(branch->merge_name[0]);
}
} else {
- const char *dst,
- *remote_name = remotes_pushremote_for_branch(
+ char *dst;
+ const char *remote_name = remotes_pushremote_for_branch(
the_repository->remote_state, branch,
NULL);
struct remote *remote = remotes_remote_get(
@@ -644,10 +685,10 @@ static void validate_remote_url(struct remote *remote)
else
die(_("unrecognized value transfer.credentialsInUrl: '%s'"), value);
- for (i = 0; i < remote->url_nr; i++) {
+ for (i = 0; i < remote->url.nr; i++) {
struct url_info url_info = { 0 };
- if (!url_normalize(remote->url[i], &url_info) ||
+ if (!url_normalize(remote->url.v[i], &url_info) ||
!url_info.passwd_off)
goto loop_cleanup;
@@ -709,7 +750,13 @@ remotes_remote_get(struct remote_state *remote_state, const char *name)
struct remote *remote_get(const char *name)
{
- read_config(the_repository);
+ read_config(the_repository, 0);
+ return remotes_remote_get(the_repository->remote_state, name);
+}
+
+struct remote *remote_get_early(const char *name)
+{
+ read_config(the_repository, 1);
return remotes_remote_get(the_repository->remote_state, name);
}
@@ -722,7 +769,7 @@ remotes_pushremote_get(struct remote_state *remote_state, const char *name)
struct remote *pushremote_get(const char *name)
{
- read_config(the_repository);
+ read_config(the_repository, 0);
return remotes_pushremote_get(the_repository->remote_state, name);
}
@@ -738,7 +785,7 @@ int remote_is_configured(struct remote *remote, int in_repo)
int for_each_remote(each_remote_fn fn, void *priv)
{
int i, result = 0;
- read_config(the_repository);
+ read_config(the_repository, 0);
for (i = 0; i < the_repository->remote_state->remotes_nr && !result;
i++) {
struct remote *remote =
@@ -815,13 +862,32 @@ struct ref *ref_remove_duplicates(struct ref *ref_map)
int remote_has_url(struct remote *remote, const char *url)
{
int i;
- for (i = 0; i < remote->url_nr; i++) {
- if (!strcmp(remote->url[i], url))
+ for (i = 0; i < remote->url.nr; i++) {
+ if (!strcmp(remote->url.v[i], url))
return 1;
}
return 0;
}
+struct strvec *push_url_of_remote(struct remote *remote)
+{
+ return remote->pushurl.nr ? &remote->pushurl : &remote->url;
+}
+
+void ref_push_report_free(struct ref_push_report *report)
+{
+ while (report) {
+ struct ref_push_report *next = report->next;
+
+ free(report->ref_name);
+ free(report->old_oid);
+ free(report->new_oid);
+ free(report);
+
+ report = next;
+ }
+}
+
static int match_name_with_pattern(const char *key, const char *name,
const char *value, char **result)
{
@@ -1076,7 +1142,9 @@ void free_one_ref(struct ref *ref)
if (!ref)
return;
free_one_ref(ref->peer_ref);
+ ref_push_report_free(ref->report);
free(ref->remote_status);
+ free(ref->tracking_ref);
free(ref->symref);
free(ref);
}
@@ -1158,7 +1226,7 @@ static void tail_link_ref(struct ref *ref, struct ref ***tail)
static struct ref *alloc_delete_ref(void)
{
struct ref *ref = alloc_ref("(delete)");
- oidclr(&ref->new_oid);
+ oidclr(&ref->new_oid, the_repository->hash_algo);
return ref;
}
@@ -1194,8 +1262,10 @@ static char *guess_ref(const char *name, struct ref *peer)
{
struct strbuf buf = STRBUF_INIT;
- const char *r = resolve_ref_unsafe(peer->name, RESOLVE_REF_READING,
- NULL, NULL);
+ const char *r = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ peer->name,
+ RESOLVE_REF_READING,
+ NULL, NULL);
if (!r)
return NULL;
@@ -1296,25 +1366,29 @@ static int match_explicit(struct ref *src, struct ref *dst,
struct ref ***dst_tail,
struct refspec_item *rs)
{
- struct ref *matched_src, *matched_dst;
- int allocated_src;
+ struct ref *matched_src = NULL, *matched_dst = NULL;
+ int allocated_src = 0, ret;
const char *dst_value = rs->dst;
char *dst_guess;
- if (rs->pattern || rs->matching || rs->negative)
- return 0;
+ if (rs->pattern || rs->matching || rs->negative) {
+ ret = 0;
+ goto out;
+ }
- matched_src = matched_dst = NULL;
- if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0)
- return -1;
+ if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0) {
+ ret = -1;
+ goto out;
+ }
if (!dst_value) {
int flag;
- dst_value = resolve_ref_unsafe(matched_src->name,
- RESOLVE_REF_READING,
- NULL, &flag);
+ dst_value = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ matched_src->name,
+ RESOLVE_REF_READING,
+ NULL, &flag);
if (!dst_value ||
((flag & REF_ISSYMREF) &&
!starts_with(dst_value, "refs/heads/")))
@@ -1345,18 +1419,30 @@ static int match_explicit(struct ref *src, struct ref *dst,
dst_value);
break;
}
- if (!matched_dst)
- return -1;
- if (matched_dst->peer_ref)
- return error(_("dst ref %s receives from more than one src"),
- matched_dst->name);
- else {
+
+ if (!matched_dst) {
+ ret = -1;
+ goto out;
+ }
+
+ if (matched_dst->peer_ref) {
+ ret = error(_("dst ref %s receives from more than one src"),
+ matched_dst->name);
+ goto out;
+ } else {
matched_dst->peer_ref = allocated_src ?
matched_src :
copy_ref(matched_src);
matched_dst->force = rs->force;
+ matched_src = NULL;
}
- return 0;
+
+ ret = 0;
+
+out:
+ if (allocated_src)
+ free_one_ref(matched_src);
+ return ret;
}
static int match_explicit_refs(struct ref *src, struct ref *dst,
@@ -1769,7 +1855,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 (!repo_has_object_file(the_repository, &ref->old_oid))
+ else if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
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))
@@ -1831,7 +1917,7 @@ struct branch *branch_get(const char *name)
{
struct branch *ret;
- read_config(the_repository);
+ read_config(the_repository, 0);
if (!name || !*name || !strcmp(name, "HEAD"))
ret = the_repository->remote_state->current_branch;
else
@@ -1878,7 +1964,7 @@ const char *branch_get_upstream(struct branch *branch, struct strbuf *err)
* or because it is not a real branch, and get_branch
* auto-vivified it?
*/
- if (!ref_exists(branch->refname))
+ if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname))
return error_buf(err, _("no such branch: '%s'"),
branch->name);
return error_buf(err,
@@ -1973,7 +2059,7 @@ static const char *branch_get_push_1(struct remote_state *remote_state,
const char *branch_get_push(struct branch *branch, struct strbuf *err)
{
- read_config(the_repository);
+ read_config(the_repository, 0);
die_on_missing_branch(the_repository, branch);
if (!branch)
@@ -2017,6 +2103,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
!ignore_symref_update(expn_name, &scratch)) {
struct ref *cpy = copy_ref(ref);
+ if (cpy->peer_ref)
+ free_one_ref(cpy->peer_ref);
cpy->peer_ref = alloc_ref(expn_name);
if (refspec->force)
cpy->peer_ref->force = 1;
@@ -2164,13 +2252,13 @@ static int stat_branch_pair(const char *branch_name, const char *base,
struct strvec argv = STRVEC_INIT;
/* Cannot stat if what we used to build on no longer exists */
- if (read_ref(base, &oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), base, &oid))
return -1;
theirs = lookup_commit_reference(the_repository, &oid);
if (!theirs)
return -1;
- if (read_ref(branch_name, &oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), branch_name, &oid))
return -1;
ours = lookup_commit_reference(the_repository, &oid);
if (!ours)
@@ -2274,7 +2362,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
upstream_is_gone = 1;
}
- base = shorten_unambiguous_ref(full_base, 0);
+ base = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ full_base, 0);
if (upstream_is_gone) {
strbuf_addf(sb,
_("Your branch is based on '%s', but the upstream is gone.\n"),
@@ -2332,7 +2421,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
return 1;
}
-static int one_local_ref(const char *refname, const struct object_id *oid,
+static int one_local_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -2354,7 +2443,8 @@ struct ref *get_local_heads(void)
{
struct ref *local_refs = NULL, **local_tail = &local_refs;
- for_each_ref(one_local_ref, &local_tail);
+ refs_for_each_ref(get_main_ref_store(the_repository), one_local_ref,
+ &local_tail);
return local_refs;
}
@@ -2379,11 +2469,13 @@ struct ref *guess_remote_head(const struct ref *head,
/* If a remote branch exists with the default branch name, let's use it. */
if (!all) {
- char *ref = xstrfmt("refs/heads/%s",
- git_default_branch_name(0));
+ char *default_branch = repo_default_branch_name(the_repository, 0);
+ char *ref = xstrfmt("refs/heads/%s", default_branch);
r = find_ref_by_name(refs, ref);
free(ref);
+ free(default_branch);
+
if (r && oideq(&r->old_oid, &head->old_oid))
return copy_ref(r);
@@ -2414,7 +2506,7 @@ struct stale_heads_info {
struct refspec *rs;
};
-static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
+static int get_stale_heads_cb(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags, void *cb_data)
{
struct stale_heads_info *info = cb_data;
@@ -2464,7 +2556,8 @@ struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map)
for (ref = fetch_map; ref; ref = ref->next)
string_list_append(&ref_names, ref->name);
string_list_sort(&ref_names);
- for_each_ref(get_stale_heads_cb, &info);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ get_stale_heads_cb, &info);
string_list_clear(&ref_names, 0);
return stale_refs;
}
@@ -2472,7 +2565,7 @@ struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map)
/*
* Compare-and-swap
*/
-static void clear_cas_option(struct push_cas_option *cas)
+void clear_cas_option(struct push_cas_option *cas)
{
int i;
@@ -2517,7 +2610,7 @@ static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, i
if (!*colon)
entry->use_tracking = 1;
else if (!colon[1])
- oidclr(&entry->expect);
+ oidclr(&entry->expect, the_repository->hash_algo);
else if (repo_get_oid(the_repository, colon + 1, &entry->expect))
return error(_("cannot parse expected object name '%s'"),
colon + 1);
@@ -2549,8 +2642,10 @@ static int remote_tracking(struct remote *remote, const char *refname,
dst = apply_refspecs(&remote->fetch, refname);
if (!dst)
return -1; /* no tracking ref for refname at remote */
- if (read_ref(dst, oid))
+ if (refs_read_ref(get_main_ref_store(the_repository), dst, oid)) {
+ free(dst);
return -1; /* we know what the tracking ref is but we cannot read it */
+ }
*dst_refname = dst;
return 0;
@@ -2655,12 +2750,16 @@ static int is_reachable_in_reflog(const char *local, const struct ref *remote)
* Get the timestamp from the latest entry
* of the remote-tracking ref's reflog.
*/
- for_each_reflog_ent_reverse(remote->tracking_ref, peek_reflog, &date);
+ refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository),
+ remote->tracking_ref, peek_reflog,
+ &date);
cb.remote_commit = commit;
cb.local_commits = &arr;
cb.remote_reflog_timestamp = date;
- ret = for_each_reflog_ent_reverse(local, check_and_collect_until, &cb);
+ ret = refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository),
+ local, check_and_collect_until,
+ &cb);
/* We found an entry in the reflog. */
if (ret > 0)
@@ -2675,7 +2774,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 = repo_in_merge_bases_many(the_repository, commit, size, chunk)))
+ if ((ret = repo_in_merge_bases_many(the_repository, commit, size, chunk, 0)))
break;
}
@@ -2696,6 +2795,7 @@ static void check_if_includes_upstream(struct ref *remote)
if (is_reachable_in_reflog(local->name, remote) <= 0)
remote->unreachable = 1;
+ free_one_ref(local);
}
static void apply_cas(struct push_cas_option *cas,
@@ -2715,7 +2815,7 @@ static void apply_cas(struct push_cas_option *cas,
else if (remote_tracking(remote, ref->name,
&ref->old_oid_expect,
&ref->tracking_ref))
- oidclr(&ref->old_oid_expect);
+ oidclr(&ref->old_oid_expect, the_repository->hash_algo);
else
ref->check_reachable = cas->use_force_if_includes;
return;
@@ -2729,7 +2829,7 @@ static void apply_cas(struct push_cas_option *cas,
if (remote_tracking(remote, ref->name,
&ref->old_oid_expect,
&ref->tracking_ref))
- oidclr(&ref->old_oid_expect);
+ oidclr(&ref->old_oid_expect, the_repository->hash_algo);
else
ref->check_reachable = cas->use_force_if_includes;
}
@@ -2765,16 +2865,26 @@ struct remote_state *remote_state_new(void)
void remote_state_clear(struct remote_state *remote_state)
{
+ struct hashmap_iter iter;
+ struct branch *b;
int i;
for (i = 0; i < remote_state->remotes_nr; i++)
remote_clear(remote_state->remotes[i]);
FREE_AND_NULL(remote_state->remotes);
+ FREE_AND_NULL(remote_state->pushremote_name);
remote_state->remotes_alloc = 0;
remote_state->remotes_nr = 0;
+ rewrites_release(&remote_state->rewrites);
+ rewrites_release(&remote_state->rewrites_push);
+
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
- hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
+ hashmap_for_each_entry(&remote_state->branches_hash, &iter, b, ent) {
+ branch_release(b);
+ free(b);
+ }
+ hashmap_clear(&remote_state->branches_hash);
}
/*
diff --git a/remote.h b/remote.h
index cdc8b1db42..a7e5c4e07c 100644
--- a/remote.h
+++ b/remote.h
@@ -1,9 +1,11 @@
#ifndef REMOTE_H
#define REMOTE_H
-#include "hash-ll.h"
+#include "hash.h"
#include "hashmap.h"
#include "refspec.h"
+#include "string-list.h"
+#include "strvec.h"
struct option;
struct transport_ls_refs_options;
@@ -46,7 +48,7 @@ struct remote_state {
struct hashmap branches_hash;
struct branch *current_branch;
- const char *pushremote_name;
+ char *pushremote_name;
struct rewrites rewrites;
struct rewrites rewrites_push;
@@ -65,19 +67,12 @@ struct remote {
int origin, configured_in_repo;
- const char *foreign_vcs;
+ char *foreign_vcs;
/* An array of all of the url_nr URLs configured for the remote */
- const char **url;
-
- int url_nr;
- int url_alloc;
-
+ struct strvec url;
/* An array of all of the pushurl_nr push URLs configured for the remote */
- const char **pushurl;
-
- int pushurl_nr;
- int pushurl_alloc;
+ struct strvec pushurl;
struct refspec push;
@@ -110,6 +105,8 @@ struct remote {
/* The method used for authenticating against `http_proxy`. */
char *http_proxy_authmethod;
+
+ struct string_list server_options;
};
/**
@@ -118,6 +115,7 @@ struct remote {
* and configuration.
*/
struct remote *remote_get(const char *name);
+struct remote *remote_get_early(const char *name);
struct remote *pushremote_get(const char *name);
int remote_is_configured(struct remote *remote, int in_repo);
@@ -128,15 +126,18 @@ typedef int each_remote_fn(struct remote *remote, void *priv);
int for_each_remote(each_remote_fn fn, void *priv);
int remote_has_url(struct remote *remote, const char *url);
+struct strvec *push_url_of_remote(struct remote *remote);
struct ref_push_report {
- const char *ref_name;
+ char *ref_name;
struct object_id *old_oid;
struct object_id *new_oid;
unsigned int forced_update:1;
struct ref_push_report *next;
};
+void ref_push_report_free(struct ref_push_report *);
+
struct ref {
struct ref *next;
struct object_id old_oid;
@@ -199,7 +200,7 @@ struct ref {
};
#define REF_NORMAL (1u << 0)
-#define REF_HEADS (1u << 1)
+#define REF_BRANCHES (1u << 1)
#define REF_TAGS (1u << 2)
struct ref *find_ref_by_name(const struct ref *list, const char *name);
@@ -308,9 +309,9 @@ struct branch {
const char *refname;
/* The name of the remote listed in the configuration. */
- const char *remote_name;
+ char *remote_name;
- const char *pushremote_name;
+ char *pushremote_name;
/* An array of the "merge" lines in the configuration. */
const char **merge_name;
@@ -333,7 +334,7 @@ struct branch {
struct branch *branch_get(const char *name);
const char *remote_for_branch(struct branch *branch, int *explicit);
const char *pushremote_for_branch(struct branch *branch, int *explicit);
-const char *remote_ref_for_branch(struct branch *branch, int for_push);
+char *remote_ref_for_branch(struct branch *branch, int for_push);
/* returns true if the given branch has merge configuration given. */
int branch_has_merge_config(struct branch *branch);
@@ -400,8 +401,6 @@ struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map);
/*
* Compare-and-swap
*/
-#define CAS_OPT_NAME "force-with-lease"
-
struct push_cas_option {
unsigned use_tracking_for_rest:1;
unsigned use_force_if_includes:1;
@@ -415,6 +414,7 @@ struct push_cas_option {
};
int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
+void clear_cas_option(struct push_cas_option *);
int is_empty_cas(const struct push_cas_option *);
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
diff --git a/replace-object.c b/replace-object.c
index 523215589d..9a3cdd809a 100644
--- a/replace-object.c
+++ b/replace-object.c
@@ -8,18 +8,20 @@
#include "repository.h"
#include "commit.h"
-static int register_replace_ref(struct repository *r,
- const char *refname,
+static int register_replace_ref(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
- void *cb_data UNUSED)
+ void *cb_data)
{
+ struct repository *r = cb_data;
+
/* Get sha1 from refname */
const char *slash = strrchr(refname, '/');
const char *hash = slash ? slash + 1 : refname;
struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj));
- if (get_oid_hex(hash, &repl_obj->original.oid)) {
+ if (get_oid_hex_algop(hash, &repl_obj->original.oid, r->hash_algo)) {
free(repl_obj);
warning(_("bad replace ref name: %s"), refname);
return 0;
@@ -50,7 +52,8 @@ void prepare_replace_object(struct repository *r)
xmalloc(sizeof(*r->objects->replace_map));
oidmap_init(r->objects->replace_map, 0);
- for_each_replace_ref(r, register_replace_ref, NULL);
+ refs_for_each_replace_ref(get_main_ref_store(r),
+ register_replace_ref, r);
r->objects->replace_map_initialized = 1;
pthread_mutex_unlock(&r->objects->replace_mutex);
diff --git a/repo-settings.c b/repo-settings.c
index 525f69c0c7..4699b4b365 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -1,8 +1,8 @@
#include "git-compat-util.h"
#include "config.h"
+#include "repo-settings.h"
#include "repository.h"
#include "midx.h"
-#include "compat/fsmonitor/fsm-listen.h"
static void repo_cfg_bool(struct repository *r, const char *key, int *dest,
int def)
@@ -20,21 +20,21 @@ static void repo_cfg_int(struct repository *r, const char *key, int *dest,
void prepare_repo_settings(struct repository *r)
{
+ const struct repo_settings defaults = REPO_SETTINGS_INIT;
int experimental;
int value;
const char *strval;
int manyfiles;
+ int read_changed_paths;
if (!r->gitdir)
BUG("Cannot add settings for uninitialized repository");
- if (r->settings.initialized++)
+ if (r->settings.initialized)
return;
- /* Defaults */
- r->settings.index_version = -1;
- r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP;
- r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE;
+ memcpy(&r->settings, &defaults, sizeof(defaults));
+ r->settings.initialized++;
/* Booleans config or default, cascades to other settings */
repo_cfg_bool(r, "feature.manyfiles", &manyfiles, 0);
@@ -44,6 +44,7 @@ void prepare_repo_settings(struct repository *r)
if (experimental) {
r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
r->settings.pack_use_bitmap_boundary_traversal = 1;
+ r->settings.pack_use_multi_pack_reuse = 1;
}
if (manyfiles) {
r->settings.index_version = 4;
@@ -54,7 +55,10 @@ void prepare_repo_settings(struct repository *r)
/* Commit graph config or default, does not cascade (simple) */
repo_cfg_bool(r, "core.commitgraph", &r->settings.core_commit_graph, 1);
repo_cfg_int(r, "commitgraph.generationversion", &r->settings.commit_graph_generation_version, 2);
- repo_cfg_bool(r, "commitgraph.readchangedpaths", &r->settings.commit_graph_read_changed_paths, 1);
+ repo_cfg_bool(r, "commitgraph.readchangedpaths", &read_changed_paths, 1);
+ repo_cfg_int(r, "commitgraph.changedpathsversion",
+ &r->settings.commit_graph_changed_paths_version,
+ read_changed_paths ? -1 : 0);
repo_cfg_bool(r, "gc.writecommitgraph", &r->settings.gc_write_commit_graph, 1);
repo_cfg_bool(r, "fetch.writecommitgraph", &r->settings.fetch_write_commit_graph, 0);
@@ -120,3 +124,28 @@ void prepare_repo_settings(struct repository *r)
*/
r->settings.command_requires_full_index = 1;
}
+
+enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
+{
+ const char *value;
+
+ if (!repo_config_get_string_tmp(repo, "core.logallrefupdates", &value)) {
+ if (value && !strcasecmp(value, "always"))
+ return LOG_REFS_ALWAYS;
+ else if (git_config_bool("core.logallrefupdates", value))
+ return LOG_REFS_NORMAL;
+ else
+ return LOG_REFS_NONE;
+ }
+
+ return LOG_REFS_UNSET;
+}
+
+int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
+{
+ prepare_repo_settings(repo);
+ if (repo->settings.warn_ambiguous_refs < 0)
+ repo_cfg_bool(repo, "core.warnambiguousrefs",
+ &repo->settings.warn_ambiguous_refs, 1);
+ return repo->settings.warn_ambiguous_refs;
+}
diff --git a/repo-settings.h b/repo-settings.h
new file mode 100644
index 0000000000..51d6156a11
--- /dev/null
+++ b/repo-settings.h
@@ -0,0 +1,75 @@
+#ifndef REPO_SETTINGS_H
+#define REPO_SETTINGS_H
+
+struct fsmonitor_settings;
+struct repository;
+
+enum untracked_cache_setting {
+ UNTRACKED_CACHE_KEEP,
+ UNTRACKED_CACHE_REMOVE,
+ UNTRACKED_CACHE_WRITE,
+};
+
+enum fetch_negotiation_setting {
+ FETCH_NEGOTIATION_CONSECUTIVE,
+ FETCH_NEGOTIATION_SKIPPING,
+ FETCH_NEGOTIATION_NOOP,
+};
+
+enum log_refs_config {
+ LOG_REFS_UNSET = -1,
+ LOG_REFS_NONE = 0,
+ LOG_REFS_NORMAL,
+ LOG_REFS_ALWAYS
+};
+
+struct repo_settings {
+ int initialized;
+
+ int core_commit_graph;
+ int commit_graph_generation_version;
+ int commit_graph_changed_paths_version;
+ int gc_write_commit_graph;
+ int fetch_write_commit_graph;
+ int command_requires_full_index;
+ int sparse_index;
+ int pack_read_reverse_index;
+ int pack_use_bitmap_boundary_traversal;
+ int pack_use_multi_pack_reuse;
+
+ /*
+ * 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 */
+
+ int index_version;
+ int index_skip_hash;
+ enum untracked_cache_setting core_untracked_cache;
+
+ int pack_use_sparse;
+ enum fetch_negotiation_setting fetch_negotiation_algorithm;
+
+ int core_multi_pack_index;
+ int warn_ambiguous_refs; /* lazily loaded via accessor */
+};
+#define REPO_SETTINGS_INIT { \
+ .index_version = -1, \
+ .core_untracked_cache = UNTRACKED_CACHE_KEEP, \
+ .fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \
+ .warn_ambiguous_refs = -1, \
+}
+
+void prepare_repo_settings(struct repository *r);
+
+/* Read the value for "core.logAllRefUpdates". */
+enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo);
+/* Read the value for "core.warnAmbiguousRefs". */
+int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
+
+#endif /* REPO_SETTINGS_H */
diff --git a/repository.c b/repository.c
index 789569b5bc..f988b8ae68 100644
--- a/repository.c
+++ b/repository.c
@@ -1,8 +1,3 @@
-/*
- * not really _using_ the compat macros, just make sure the_index
- * declaration matches the definition in this file.
- */
-#define USE_THE_INDEX_VARIABLE
#include "git-compat-util.h"
#include "abspath.h"
#include "repository.h"
@@ -14,28 +9,76 @@
#include "read-cache-ll.h"
#include "remote.h"
#include "setup.h"
+#include "loose.h"
#include "submodule-config.h"
#include "sparse-index.h"
#include "trace2.h"
#include "promisor-remote.h"
+#include "refs.h"
+
+/*
+ * We do not define `USE_THE_REPOSITORY_VARIABLE` in this file because we do
+ * not want to rely on functions that implicitly use `the_repository`. This
+ * means that the `extern` declaration of `the_repository` isn't visible here,
+ * which makes sparse unhappy. We thus declare it here.
+ */
+extern struct repository *the_repository;
/* The main repository */
static struct repository the_repo;
-struct repository *the_repository;
-struct index_state the_index;
+struct repository *the_repository = &the_repo;
-void initialize_the_repository(void)
+/*
+ * An escape hatch: if we hit a bug in the production code that fails
+ * to set an appropriate hash algorithm (most likely to happen when
+ * running outside a repository), we can tell the user who reported
+ * the crash to set the environment variable to "sha1" (all lowercase)
+ * to revert to the historical behaviour of defaulting to SHA-1.
+ */
+static void set_default_hash_algo(struct repository *repo)
{
- the_repository = &the_repo;
+ const char *hash_name;
+ int algo;
+
+ hash_name = getenv("GIT_TEST_DEFAULT_HASH_ALGO");
+ if (!hash_name)
+ return;
+ algo = hash_algo_by_name(hash_name);
+ if (algo == GIT_HASH_UNKNOWN)
+ return;
- the_repo.index = &the_index;
- the_repo.objects = raw_object_store_new();
- the_repo.remote_state = remote_state_new();
- the_repo.parsed_objects = parsed_object_pool_new();
+ repo_set_hash_algo(repo, algo);
+}
- index_state_init(&the_index, the_repository);
+void initialize_repository(struct repository *repo)
+{
+ repo->objects = raw_object_store_new();
+ repo->remote_state = remote_state_new();
+ repo->parsed_objects = parsed_object_pool_new(repo);
+ ALLOC_ARRAY(repo->index, 1);
+ index_state_init(repo->index, repo);
- repo_set_hash_algo(&the_repo, GIT_HASH_SHA1);
+ /*
+ * When a command runs inside a repository, it learns what
+ * hash algorithm is in use from the repository, but some
+ * commands are designed to work outside a repository, yet
+ * they want to access the_hash_algo, if only for the length
+ * of the hashed value to see if their input looks like a
+ * plausible hash value.
+ *
+ * We are in the process of identifying such code paths and
+ * giving them an appropriate default individually; any
+ * unconverted code paths that try to access the_hash_algo
+ * will thus fail. The end-users however have an escape hatch
+ * to set GIT_TEST_DEFAULT_HASH_ALGO environment variable to
+ * "sha1" to get back the old behaviour of defaulting to SHA-1.
+ *
+ * This escape hatch is deliberately kept unadvertised, so
+ * that they see crashes and we can get a report before
+ * telling them about it.
+ */
+ if (repo == the_repository)
+ set_default_hash_algo(repo);
}
static void expand_base_dir(char **out, const char *in,
@@ -48,6 +91,46 @@ static void expand_base_dir(char **out, const char *in,
*out = xstrfmt("%s/%s", base_dir, def_in);
}
+const char *repo_get_git_dir(struct repository *repo)
+{
+ if (!repo->gitdir)
+ BUG("repository hasn't been set up");
+ return repo->gitdir;
+}
+
+const char *repo_get_common_dir(struct repository *repo)
+{
+ if (!repo->commondir)
+ BUG("repository hasn't been set up");
+ return repo->commondir;
+}
+
+const char *repo_get_object_directory(struct repository *repo)
+{
+ if (!repo->objects->odb)
+ BUG("repository hasn't been set up");
+ return repo->objects->odb->path;
+}
+
+const char *repo_get_index_file(struct repository *repo)
+{
+ if (!repo->index_file)
+ BUG("repository hasn't been set up");
+ return repo->index_file;
+}
+
+const char *repo_get_graft_file(struct repository *repo)
+{
+ if (!repo->graft_file)
+ BUG("repository hasn't been set up");
+ return repo->graft_file;
+}
+
+const char *repo_get_work_tree(struct repository *repo)
+{
+ return repo->worktree;
+}
+
static void repo_set_commondir(struct repository *repo,
const char *commondir)
{
@@ -104,6 +187,21 @@ void repo_set_hash_algo(struct repository *repo, int hash_algo)
repo->hash_algo = &hash_algos[hash_algo];
}
+void repo_set_compat_hash_algo(struct repository *repo, int algo)
+{
+ if (hash_algo_by_ptr(repo->hash_algo) == algo)
+ BUG("hash_algo and compat_hash_algo match");
+ repo->compat_hash_algo = algo ? &hash_algos[algo] : NULL;
+ if (repo->compat_hash_algo)
+ repo_read_loose_object_map(repo);
+}
+
+void repo_set_ref_storage_format(struct repository *repo,
+ enum ref_storage_format format)
+{
+ repo->ref_storage_format = format;
+}
+
/*
* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
* Return 0 upon success and a non-zero value upon failure.
@@ -173,9 +271,7 @@ int repo_init(struct repository *repo,
struct repository_format format = REPOSITORY_FORMAT_INIT;
memset(repo, 0, sizeof(*repo));
- repo->objects = raw_object_store_new();
- repo->parsed_objects = parsed_object_pool_new();
- repo->remote_state = remote_state_new();
+ initialize_repository(repo);
if (repo_init_gitdir(repo, gitdir))
goto error;
@@ -184,6 +280,8 @@ int repo_init(struct repository *repo,
goto error;
repo_set_hash_algo(repo, format.hash_algo);
+ repo_set_compat_hash_algo(repo, format.compat_hash_algo);
+ repo_set_ref_storage_format(repo, format.ref_storage_format);
repo->repository_format_worktree_config = format.worktree_config;
/* take ownership of format.partial_clone */
@@ -193,6 +291,9 @@ int repo_init(struct repository *repo,
if (worktree)
repo_set_worktree(repo, worktree);
+ if (repo->compat_hash_algo)
+ repo_read_loose_object_map(repo);
+
clear_repository_format(&format);
return 0;
@@ -256,14 +357,15 @@ static void repo_clear_path_cache(struct repo_path_cache *cache)
FREE_AND_NULL(cache->merge_rr);
FREE_AND_NULL(cache->merge_mode);
FREE_AND_NULL(cache->merge_head);
- FREE_AND_NULL(cache->merge_autostash);
- FREE_AND_NULL(cache->auto_merge);
FREE_AND_NULL(cache->fetch_head);
FREE_AND_NULL(cache->shallow);
}
void repo_clear(struct repository *repo)
{
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+
FREE_AND_NULL(repo->gitdir);
FREE_AND_NULL(repo->commondir);
FREE_AND_NULL(repo->graft_file);
@@ -291,8 +393,7 @@ void repo_clear(struct repository *repo)
if (repo->index) {
discard_index(repo->index);
- if (repo->index != &the_index)
- FREE_AND_NULL(repo->index);
+ FREE_AND_NULL(repo->index);
}
if (repo->promisor_remote_config) {
@@ -305,6 +406,14 @@ void repo_clear(struct repository *repo)
FREE_AND_NULL(repo->remote_state);
}
+ strmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)
+ ref_store_release(e->value);
+ strmap_clear(&repo->submodule_ref_stores, 1);
+
+ strmap_for_each_entry(&repo->worktree_ref_stores, &iter, e)
+ ref_store_release(e->value);
+ strmap_clear(&repo->worktree_ref_stores, 1);
+
repo_clear_path_cache(&repo->cached_paths);
}
diff --git a/repository.h b/repository.h
index 5f18486f64..24a66a496a 100644
--- a/repository.h
+++ b/repository.h
@@ -1,8 +1,10 @@
#ifndef REPOSITORY_H
#define REPOSITORY_H
+#include "strmap.h"
+#include "repo-settings.h"
+
struct config_set;
-struct fsmonitor_settings;
struct git_hash_algo;
struct index_state;
struct lock_file;
@@ -12,50 +14,10 @@ struct submodule_cache;
struct promisor_remote_config;
struct remote_state;
-enum untracked_cache_setting {
- UNTRACKED_CACHE_KEEP,
- UNTRACKED_CACHE_REMOVE,
- UNTRACKED_CACHE_WRITE,
-};
-
-enum fetch_negotiation_setting {
- FETCH_NEGOTIATION_CONSECUTIVE,
- FETCH_NEGOTIATION_SKIPPING,
- FETCH_NEGOTIATION_NOOP,
-};
-
-struct repo_settings {
- int initialized;
-
- int core_commit_graph;
- int commit_graph_generation_version;
- int commit_graph_read_changed_paths;
- int gc_write_commit_graph;
- int fetch_write_commit_graph;
- 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 */
-
- int index_version;
- int index_skip_hash;
- enum untracked_cache_setting core_untracked_cache;
-
- int pack_use_sparse;
- enum fetch_negotiation_setting fetch_negotiation_algorithm;
-
- int core_multi_pack_index;
+enum ref_storage_format {
+ REF_STORAGE_FORMAT_UNKNOWN,
+ REF_STORAGE_FORMAT_FILES,
+ REF_STORAGE_FORMAT_REFTABLE,
};
struct repo_path_cache {
@@ -64,8 +26,6 @@ struct repo_path_cache {
char *merge_rr;
char *merge_mode;
char *merge_head;
- char *merge_autostash;
- char *auto_merge;
char *fetch_head;
char *shallow;
};
@@ -106,6 +66,18 @@ struct repository {
struct ref_store *refs_private;
/*
+ * A strmap of ref_stores, stored by submodule name, accessible via
+ * `repo_get_submodule_ref_store()`.
+ */
+ struct strmap submodule_ref_stores;
+
+ /*
+ * A strmap of ref_stores, stored by worktree id, accessible via
+ * `get_worktree_ref_store()`.
+ */
+ struct strmap worktree_ref_stores;
+
+ /*
* Contains path to often used file names.
*/
struct repo_path_cache cached_paths;
@@ -160,6 +132,12 @@ struct repository {
/* Repository's current hash algorithm, as serialized on disk. */
const struct git_hash_algo *hash_algo;
+ /* Repository's compatibility hash algorithm. */
+ const struct git_hash_algo *compat_hash_algo;
+
+ /* Repository's reference storage format, as serialized on disk. */
+ enum ref_storage_format ref_storage_format;
+
/* A unique-id for tracing purposes. */
int trace2_repo_id;
@@ -177,11 +155,17 @@ struct repository {
unsigned different_commondir:1;
};
+#ifdef USE_THE_REPOSITORY_VARIABLE
extern struct repository *the_repository;
-#ifdef USE_THE_INDEX_VARIABLE
-extern struct index_state the_index;
#endif
+const char *repo_get_git_dir(struct repository *repo);
+const char *repo_get_common_dir(struct repository *repo);
+const char *repo_get_object_directory(struct repository *repo);
+const char *repo_get_index_file(struct repository *repo);
+const char *repo_get_graft_file(struct repository *repo);
+const char *repo_get_work_tree(struct repository *repo);
+
/*
* Define a custom repository layout. Any field can be NULL, which
* will default back to the path according to the default layout.
@@ -199,7 +183,10 @@ void repo_set_gitdir(struct repository *repo, const char *root,
const struct set_gitdir_args *extra_args);
void repo_set_worktree(struct repository *repo, const char *path);
void repo_set_hash_algo(struct repository *repo, int algo);
-void initialize_the_repository(void);
+void repo_set_compat_hash_algo(struct repository *repo, int compat_algo);
+void repo_set_ref_storage_format(struct repository *repo,
+ enum ref_storage_format format);
+void initialize_repository(struct repository *repo);
RESULT_MUST_BE_USED
int repo_init(struct repository *r, const char *gitdir, const char *worktree);
@@ -239,8 +226,6 @@ int repo_read_index_unmerged(struct repository *);
*/
void repo_update_index_if_able(struct repository *, struct lock_file *);
-void prepare_repo_settings(struct repository *r);
-
/*
* Return 1 if upgrade repository format to target_version succeeded,
* 0 if no upgrade is necessary, and -1 when upgrade is not possible.
diff --git a/rerere.c b/rerere.c
index 725c1b6a95..d01e98bf65 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
@@ -12,12 +14,10 @@
#include "dir.h"
#include "resolve-undo.h"
#include "merge-ll.h"
-#include "attr.h"
#include "path.h"
#include "pathspec.h"
#include "object-file.h"
#include "object-store-ll.h"
-#include "hash-lookup.h"
#include "strmap.h"
#define RESOLVED 0
@@ -221,6 +221,11 @@ static void read_rr(struct repository *r, struct string_list *rr)
buf.buf[hexsz] = '\0';
id = new_rerere_id_hex(buf.buf);
id->variant = variant;
+ /*
+ * make sure id->collection->status has enough space
+ * for the variant we are interested in
+ */
+ fit_variant(id->collection, variant);
string_list_insert(rr, path)->util = id;
}
strbuf_release(&buf);
@@ -846,6 +851,8 @@ static int do_plain_rerere(struct repository *r,
if (update.nr)
update_paths(r, &update);
+ string_list_clear(&conflict, 0);
+ string_list_clear(&update, 0);
return write_rr(rr, fd);
}
@@ -909,6 +916,7 @@ int repo_rerere(struct repository *r, int flags)
return 0;
status = do_plain_rerere(r, &merge_rr, fd);
free_rerere_dirs();
+ string_list_clear(&merge_rr, 1);
return status;
}
@@ -975,6 +983,9 @@ static int handle_cache(struct index_state *istate,
mmfile[i].ptr = repo_read_object_file(the_repository,
&ce->oid, &type,
&size);
+ if (!mmfile[i].ptr)
+ die(_("unable to read %s"),
+ oid_to_hex(&ce->oid));
mmfile[i].size = size;
}
}
@@ -1096,7 +1107,7 @@ fail_exit:
int rerere_forget(struct repository *r, struct pathspec *pathspec)
{
- int i, fd;
+ int i, fd, ret;
struct string_list conflict = STRING_LIST_INIT_DUP;
struct string_list merge_rr = STRING_LIST_INIT_DUP;
@@ -1112,7 +1123,7 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
* recover the original conflicted state and then
* find the conflicted paths.
*/
- unmerge_index(r->index, pathspec);
+ unmerge_index(r->index, pathspec, 0);
find_conflict(r, &conflict);
for (i = 0; i < conflict.nr; i++) {
struct string_list_item *it = &conflict.items[i];
@@ -1121,7 +1132,12 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
continue;
rerere_forget_one_path(r->index, it->string, &merge_rr);
}
- return write_rr(&merge_rr, fd);
+
+ ret = write_rr(&merge_rr, fd);
+
+ string_list_clear(&conflict, 0);
+ string_list_clear(&merge_rr, 1);
+ return ret;
}
/*
@@ -1192,8 +1208,10 @@ void rerere_gc(struct repository *r, struct string_list *rr)
if (setup_rerere(r, rr, 0) < 0)
return;
- git_config_get_expiry_in_days("gc.rerereresolved", &cutoff_resolve, now);
- git_config_get_expiry_in_days("gc.rerereunresolved", &cutoff_noresolve, now);
+ repo_config_get_expiry_in_days(the_repository, "gc.rerereresolved",
+ &cutoff_resolve, now);
+ repo_config_get_expiry_in_days(the_repository, "gc.rerereunresolved",
+ &cutoff_noresolve, now);
git_config(git_default_config, NULL);
dir = opendir(git_path("rr-cache"));
if (!dir)
diff --git a/reset.c b/reset.c
index 48da0adf85..b22b1be792 100644
--- a/reset.c
+++ b/reset.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "cache-tree.h"
#include "gettext.h"
@@ -6,7 +8,6 @@
#include "object-name.h"
#include "refs.h"
#include "reset.h"
-#include "run-command.h"
#include "tree-walk.h"
#include "tree.h"
#include "unpack-trees.h"
@@ -48,11 +49,13 @@ static int update_refs(const struct reset_head_opts *opts,
strbuf_addstr(&msg, "updating ORIG_HEAD");
reflog_orig_head = msg.buf;
}
- update_ref(reflog_orig_head, "ORIG_HEAD",
- orig_head ? orig_head : head,
- old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
+ refs_update_ref(get_main_ref_store(the_repository),
+ reflog_orig_head, "ORIG_HEAD",
+ orig_head ? orig_head : head,
+ old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
- delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, "ORIG_HEAD", old_orig, 0);
}
if (!reflog_head) {
@@ -61,19 +64,22 @@ static int update_refs(const struct reset_head_opts *opts,
reflog_head = msg.buf;
}
if (!switch_to_branch)
- ret = update_ref(reflog_head, "HEAD", oid, head,
- detach_head ? REF_NO_DEREF : 0,
- UPDATE_REFS_MSG_ON_ERR);
+ ret = refs_update_ref(get_main_ref_store(the_repository),
+ reflog_head, "HEAD", oid, head,
+ detach_head ? REF_NO_DEREF : 0,
+ UPDATE_REFS_MSG_ON_ERR);
else {
- ret = update_ref(reflog_branch ? reflog_branch : reflog_head,
- switch_to_branch, oid, NULL, 0,
- UPDATE_REFS_MSG_ON_ERR);
+ ret = refs_update_ref(get_main_ref_store(the_repository),
+ reflog_branch ? reflog_branch : reflog_head,
+ switch_to_branch, oid, NULL, 0,
+ UPDATE_REFS_MSG_ON_ERR);
if (!ret)
- ret = create_symref("HEAD", switch_to_branch,
- reflog_head);
+ ret = refs_update_symref(get_main_ref_store(the_repository),
+ "HEAD", switch_to_branch,
+ reflog_head);
}
if (!ret && run_hook)
- run_hooks_l("post-checkout",
+ run_hooks_l(the_repository, "post-checkout",
oid_to_hex(head ? head : null_oid()),
oid_to_hex(oid), "1", NULL);
strbuf_release(&msg);
@@ -158,6 +164,11 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
}
tree = parse_tree_indirect(oid);
+ if (!tree) {
+ ret = error(_("unable to read tree (%s)"), oid_to_hex(oid));
+ goto leave_reset_head;
+ }
+
prime_cache_tree(r, r->index, tree);
if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) {
diff --git a/reset.h b/reset.h
index 10708d8ddc..a28f81829d 100644
--- a/reset.h
+++ b/reset.h
@@ -1,7 +1,7 @@
#ifndef RESET_H
#define RESET_H
-#include "hash-ll.h"
+#include "hash.h"
#include "repository.h"
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
diff --git a/resolve-undo.c b/resolve-undo.c
index 7817f5d6db..8c9911affb 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "dir.h"
#include "hash.h"
@@ -93,7 +95,8 @@ struct string_list *resolve_undo_read(const char *data, unsigned long size)
continue;
if (size < rawsz)
goto error;
- oidread(&ui->oid[i], (const unsigned char *)data);
+ oidread(&ui->oid[i], (const unsigned char *)data,
+ the_repository->hash_algo);
size -= rawsz;
data += rawsz;
}
@@ -117,86 +120,59 @@ void resolve_undo_clear_index(struct index_state *istate)
istate->cache_changed |= RESOLVE_UNDO_CHANGED;
}
-int unmerge_index_entry_at(struct index_state *istate, int pos)
+int unmerge_index_entry(struct index_state *istate, const char *path,
+ struct resolve_undo_info *ru, unsigned ce_flags)
{
- const struct cache_entry *ce;
- struct string_list_item *item;
- struct resolve_undo_info *ru;
- int i, err = 0, matched;
- char *name;
-
- if (!istate->resolve_undo)
- return pos;
-
- ce = istate->cache[pos];
- if (ce_stage(ce)) {
- /* already unmerged */
- while ((pos < istate->cache_nr) &&
- ! strcmp(istate->cache[pos]->name, ce->name))
- pos++;
- return pos - 1; /* return the last entry processed */
+ int i = index_name_pos(istate, path, strlen(path));
+
+ if (i < 0) {
+ /* unmerged? */
+ i = -i - 1;
+ if (i < istate->cache_nr &&
+ !strcmp(istate->cache[i]->name, path))
+ /* yes, it is already unmerged */
+ return 0;
+ /* fallthru: resolved to removal */
+ } else {
+ /* merged - remove it to replace it with unmerged entries */
+ remove_index_entry_at(istate, i);
}
- item = string_list_lookup(istate->resolve_undo, ce->name);
- if (!item)
- return pos;
- ru = item->util;
- if (!ru)
- return pos;
- matched = ce->ce_flags & CE_MATCHED;
- name = xstrdup(ce->name);
- remove_index_entry_at(istate, pos);
+
for (i = 0; i < 3; i++) {
- struct cache_entry *nce;
+ struct cache_entry *ce;
if (!ru->mode[i])
continue;
- nce = make_cache_entry(istate,
- ru->mode[i],
- &ru->oid[i],
- name, i + 1, 0);
- if (matched)
- nce->ce_flags |= CE_MATCHED;
- if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
- err = 1;
- error("cannot unmerge '%s'", name);
- }
+ ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
+ path, i + 1, 0);
+ ce->ce_flags |= ce_flags;
+ if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
+ return error("cannot unmerge '%s'", path);
}
- free(name);
- if (err)
- return pos;
- free(ru);
- item->util = NULL;
- return unmerge_index_entry_at(istate, pos);
+ return 0;
}
-void unmerge_marked_index(struct index_state *istate)
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,
+ unsigned ce_flags)
{
- int i;
+ struct string_list_item *item;
if (!istate->resolve_undo)
return;
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(istate);
- for (i = 0; i < istate->cache_nr; i++) {
- const struct cache_entry *ce = istate->cache[i];
- if (ce->ce_flags & CE_MATCHED)
- i = unmerge_index_entry_at(istate, i);
- }
-}
-void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
-{
- int i;
-
- if (!istate->resolve_undo)
- return;
-
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(istate);
- for (i = 0; i < istate->cache_nr; i++) {
- const struct cache_entry *ce = istate->cache[i];
- if (!ce_path_match(istate, ce, pathspec, NULL))
+ for_each_string_list_item(item, istate->resolve_undo) {
+ const char *path = item->string;
+ struct resolve_undo_info *ru = item->util;
+ if (!item->util)
+ continue;
+ if (!match_pathspec(istate, pathspec,
+ item->string, strlen(item->string),
+ 0, NULL, 0))
continue;
- i = unmerge_index_entry_at(istate, i);
+ unmerge_index_entry(istate, path, ru, ce_flags);
+ free(ru);
+ item->util = NULL;
}
}
diff --git a/resolve-undo.h b/resolve-undo.h
index c5deafc92f..89a3227262 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -6,7 +6,7 @@ struct index_state;
struct pathspec;
struct string_list;
-#include "hash-ll.h"
+#include "hash.h"
struct resolve_undo_info {
unsigned int mode[3];
@@ -17,8 +17,7 @@ void record_resolve_undo(struct index_state *, struct cache_entry *);
void resolve_undo_write(struct strbuf *, struct string_list *);
struct string_list *resolve_undo_read(const char *, unsigned long);
void resolve_undo_clear_index(struct index_state *);
-int unmerge_index_entry_at(struct index_state *, int);
-void unmerge_index(struct index_state *, const struct pathspec *);
-void unmerge_marked_index(struct index_state *);
+int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned);
+void unmerge_index(struct index_state *, const struct pathspec *, unsigned);
#endif
diff --git a/revision.c b/revision.c
index 0ae1c76db3..347dabf7f9 100644
--- a/revision.c
+++ b/revision.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -6,6 +8,7 @@
#include "object-name.h"
#include "object-file.h"
#include "object-store-ll.h"
+#include "oidset.h"
#include "tag.h"
#include "blob.h"
#include "tree.h"
@@ -20,16 +23,15 @@
#include "reflog-walk.h"
#include "patch-ids.h"
#include "decorate.h"
-#include "log-tree.h"
#include "string-list.h"
#include "line-log.h"
#include "mailmap.h"
#include "commit-slab.h"
-#include "dir.h"
#include "cache-tree.h"
#include "bisect.h"
#include "packfile.h"
#include "worktree.h"
+#include "path.h"
#include "read-cache.h"
#include "setup.h"
#include "sparse-index.h"
@@ -49,8 +51,8 @@
volatile show_early_output_fn_t show_early_output;
-static const char *term_bad;
-static const char *term_good;
+static char *term_bad;
+static char *term_good;
implement_shared_commit_slab(revision_sources, char *);
@@ -82,7 +84,7 @@ static void mark_tree_contents_uninteresting(struct repository *r,
if (parse_tree_gently(tree, 1) < 0)
return;
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
switch (object_type(entry.mode)) {
case OBJ_TREE:
@@ -189,7 +191,7 @@ static void add_children_by_path(struct repository *r,
if (parse_tree_gently(tree, 1) < 0)
return;
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
switch (object_type(entry.mode)) {
case OBJ_TREE:
@@ -382,13 +384,18 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
object = parse_object_with_flags(revs->repo, oid,
revs->verify_objects ? 0 :
- PARSE_OBJECT_SKIP_HASH_CHECK);
+ PARSE_OBJECT_SKIP_HASH_CHECK |
+ PARSE_OBJECT_DISCARD_TREE);
if (!object) {
if (revs->ignore_missing)
- return object;
+ return NULL;
if (revs->exclude_promisor_objects && is_promisor_object(oid))
return NULL;
+ if (revs->do_not_die_on_missing_objects) {
+ oidset_insert(&revs->missing_commits, oid);
+ return NULL;
+ }
die("bad object %s", name);
}
object->flags |= flags;
@@ -416,15 +423,21 @@ static struct commit *handle_commit(struct rev_info *revs,
*/
while (object->type == OBJ_TAG) {
struct tag *tag = (struct tag *) object;
+ struct object_id *oid;
if (revs->tag_objects && !(flags & UNINTERESTING))
add_pending_object(revs, object, tag->tag);
- object = parse_object(revs->repo, get_tagged_oid(tag));
+ oid = get_tagged_oid(tag);
+ object = parse_object(revs->repo, oid);
if (!object) {
if (revs->ignore_missing_links || (flags & UNINTERESTING))
return NULL;
if (revs->exclude_promisor_objects &&
is_promisor_object(&tag->tagged->oid))
return NULL;
+ if (revs->do_not_die_on_missing_objects && oid) {
+ oidset_insert(&revs->missing_commits, oid);
+ return NULL;
+ }
die("bad object %s", oid_to_hex(&tag->tagged->oid));
}
object->flags |= flags;
@@ -834,17 +847,28 @@ static int rev_compare_tree(struct rev_info *revs,
return tree_difference;
}
-static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
+static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit,
+ int nth_parent)
{
struct tree *t1 = repo_get_commit_tree(the_repository, commit);
+ int bloom_ret = -1;
if (!t1)
return 0;
+ if (!nth_parent && revs->bloom_keys_nr) {
+ bloom_ret = check_maybe_different_in_bloom_filter(revs, commit);
+ if (!bloom_ret)
+ return 1;
+ }
+
tree_difference = REV_TREE_SAME;
revs->pruning.flags.has_changes = 0;
diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning);
+ if (bloom_ret == 1 && tree_difference == REV_TREE_SAME)
+ count_bloom_filter_false_positive++;
+
return tree_difference == REV_TREE_SAME;
}
@@ -882,7 +906,7 @@ static int compact_treesame(struct rev_info *revs, struct commit *commit, unsign
if (nth_parent != 0)
die("compact_treesame %u", nth_parent);
old_same = !!(commit->object.flags & TREESAME);
- if (rev_same_tree_as_empty(revs, commit))
+ if (rev_same_tree_as_empty(revs, commit, nth_parent))
commit->object.flags |= TREESAME;
else
commit->object.flags &= ~TREESAME;
@@ -978,7 +1002,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
return;
if (!commit->parents) {
- if (rev_same_tree_as_empty(revs, commit))
+ /*
+ * Pretend as if we are comparing ourselves to the
+ * (non-existent) first parent of this commit object. Even
+ * though no such parent exists, its changed-path Bloom filter
+ * (if one exists) is relative to the empty tree, using Bloom
+ * filters is allowed here.
+ */
+ if (rev_same_tree_as_empty(revs, commit, 0))
commit->object.flags |= TREESAME;
return;
}
@@ -1040,7 +1071,11 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
ts->treesame[nth_parent] = 1;
continue;
}
+
+ free_commit_list(parent->next);
parent->next = NULL;
+ while (commit->parents != parent)
+ pop_commit(&commit->parents);
commit->parents = parent;
/*
@@ -1059,7 +1094,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
case REV_TREE_NEW:
if (revs->remove_empty_trees &&
- rev_same_tree_as_empty(revs, p)) {
+ rev_same_tree_as_empty(revs, p, nth_parent)) {
/* We are adding all the specified
* paths from this parent, so the
* history beyond this parent is not
@@ -1072,6 +1107,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
die("cannot simplify commit %s (invalid %s)",
oid_to_hex(&commit->object.oid),
oid_to_hex(&p->object.oid));
+ free_commit_list(p->parents);
p->parents = NULL;
}
/* fallthrough */
@@ -1112,6 +1148,9 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
if (commit->object.flags & ADDED)
return 0;
+ if (revs->do_not_die_on_missing_objects &&
+ oidset_contains(&revs->missing_commits, &commit->object.oid))
+ return 0;
commit->object.flags |= ADDED;
if (revs->include_check &&
@@ -1168,7 +1207,8 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
for (parent = commit->parents; parent; parent = parent->next) {
struct commit *p = parent->item;
int gently = revs->ignore_missing_links ||
- revs->exclude_promisor_objects;
+ revs->exclude_promisor_objects ||
+ revs->do_not_die_on_missing_objects;
if (repo_parse_commit_gently(revs->repo, p, gently) < 0) {
if (revs->exclude_promisor_objects &&
is_promisor_object(&p->object.oid)) {
@@ -1176,7 +1216,11 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
break;
continue;
}
- return -1;
+
+ if (revs->do_not_die_on_missing_objects)
+ oidset_insert(&revs->missing_commits, &p->object.oid);
+ else
+ return -1; /* corrupt repository */
}
if (revs->sources) {
char **slot = revision_sources_at(revs->sources, p);
@@ -1609,7 +1653,7 @@ struct all_refs_cb {
struct worktree *wt;
};
-static int handle_one_ref(const char *path, const struct object_id *oid,
+static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -1679,9 +1723,7 @@ static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
return 0;
}
-static int handle_one_reflog(const char *refname_in_wt,
- const struct object_id *oid UNUSED,
- int flag UNUSED, void *cb_data)
+static int handle_one_reflog(const char *refname_in_wt, void *cb_data)
{
struct all_refs_cb *cb = cb_data;
struct strbuf refname = STRBUF_INIT;
@@ -1722,7 +1764,8 @@ void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
cb.all_revs = revs;
cb.all_flags = flags;
cb.wt = NULL;
- for_each_reflog(handle_one_reflog, &cb);
+ refs_for_each_reflog(get_main_ref_store(the_repository),
+ handle_one_reflog, &cb);
if (!revs->single_worktree)
add_other_reflogs_to_pending(&cb);
@@ -1834,7 +1877,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
continue; /* current index already taken care of */
if (read_index_from(&istate,
- worktree_git_path(wt, "index"),
+ worktree_git_path(the_repository, wt, "index"),
get_worktree_git_dir(wt)) > 0)
do_add_index_objects_to_pending(revs, &istate, flags);
discard_index(&istate);
@@ -1940,6 +1983,7 @@ void repo_init_revisions(struct repository *r,
init_display_notes(&revs->notes_opt);
list_objects_filter_init(&revs->filter);
init_ref_exclusions(&revs->ref_excludes);
+ oidset_init(&revs->missing_commits, 0);
}
static void add_pending_commit_list(struct rev_info *revs,
@@ -1954,11 +1998,31 @@ static void add_pending_commit_list(struct rev_info *revs,
}
}
+static const char *lookup_other_head(struct object_id *oid)
+{
+ int i;
+ static const char *const other_head[] = {
+ "MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "REBASE_HEAD"
+ };
+
+ for (i = 0; i < ARRAY_SIZE(other_head); i++)
+ if (!refs_read_ref_full(get_main_ref_store(the_repository), other_head[i],
+ RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ oid, NULL)) {
+ if (is_null_oid(oid))
+ die(_("%s exists but is a symbolic ref"), other_head[i]);
+ return other_head[i];
+ }
+
+ die(_("--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD or REBASE_HEAD"));
+}
+
static void prepare_show_merge(struct rev_info *revs)
{
- struct commit_list *bases;
+ struct commit_list *bases = NULL;
struct commit *head, *other;
struct object_id oid;
+ const char *other_name;
const char **prune = NULL;
int i, prune_num = 1; /* counting terminating NULL */
struct index_state *istate = revs->repo->index;
@@ -1966,12 +2030,12 @@ static void prepare_show_merge(struct rev_info *revs)
if (repo_get_oid(the_repository, "HEAD", &oid))
die("--merge without HEAD?");
head = lookup_commit_or_die(&oid, "HEAD");
- if (repo_get_oid(the_repository, "MERGE_HEAD", &oid))
- die("--merge without MERGE_HEAD?");
- other = lookup_commit_or_die(&oid, "MERGE_HEAD");
+ other_name = lookup_other_head(&oid);
+ other = lookup_commit_or_die(&oid, other_name);
add_pending_object(revs, &head->object, "HEAD");
- add_pending_object(revs, &other->object, "MERGE_HEAD");
- bases = repo_get_merge_bases(the_repository, head, other);
+ add_pending_object(revs, &other->object, other_name);
+ if (repo_get_merge_bases(the_repository, head, other, &bases) < 0)
+ exit(128);
add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases);
@@ -2059,14 +2123,17 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
} else {
/* A...B -- find merge bases between the two */
struct commit *a, *b;
- struct commit_list *exclude;
+ struct commit_list *exclude = NULL;
a = lookup_commit_reference(revs->repo, &a_obj->oid);
b = lookup_commit_reference(revs->repo, &b_obj->oid);
if (!a || !b)
return dotdot_missing(arg, dotdot, revs, symmetric);
- exclude = repo_get_merge_bases(the_repository, a, b);
+ if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0) {
+ free_commit_list(exclude);
+ return -1;
+ }
add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
flags_exclude);
add_pending_commit_list(revs, exclude, flags_exclude);
@@ -2089,30 +2156,26 @@ static int handle_dotdot(const char *arg,
struct rev_info *revs, int flags,
int cant_be_filename)
{
- struct object_context a_oc, b_oc;
+ struct object_context a_oc = {0}, b_oc = {0};
char *dotdot = strstr(arg, "..");
int ret;
if (!dotdot)
return -1;
- memset(&a_oc, 0, sizeof(a_oc));
- memset(&b_oc, 0, sizeof(b_oc));
-
*dotdot = '\0';
ret = handle_dotdot_1(arg, dotdot, revs, flags, cant_be_filename,
&a_oc, &b_oc);
*dotdot = '.';
- free(a_oc.path);
- free(b_oc.path);
-
+ object_context_release(&a_oc);
+ object_context_release(&b_oc);
return ret;
}
static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
{
- struct object_context oc;
+ struct object_context oc = {0};
char *mark;
struct object *object;
struct object_id oid;
@@ -2120,6 +2183,7 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
const char *arg = arg_;
int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
unsigned get_sha1_flags = GET_OID_RECORD_PATH;
+ int ret;
flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;
@@ -2128,17 +2192,22 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
* Just ".."? That is not a range but the
* pathspec for the parent directory.
*/
- return -1;
+ ret = -1;
+ goto out;
}
- if (!handle_dotdot(arg, revs, flags, revarg_opt))
- return 0;
+ if (!handle_dotdot(arg, revs, flags, revarg_opt)) {
+ ret = 0;
+ goto out;
+ }
mark = strstr(arg, "^@");
if (mark && !mark[2]) {
*mark = 0;
- if (add_parents_only(revs, arg, flags, 0))
- return 0;
+ if (add_parents_only(revs, arg, flags, 0)) {
+ ret = 0;
+ goto out;
+ }
*mark = '^';
}
mark = strstr(arg, "^!");
@@ -2153,8 +2222,10 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
if (mark[2]) {
if (strtol_i(mark + 2, 10, &exclude_parent) ||
- exclude_parent < 1)
- return -1;
+ exclude_parent < 1) {
+ ret = -1;
+ goto out;
+ }
}
*mark = 0;
@@ -2171,17 +2242,30 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
if (revarg_opt & REVARG_COMMITTISH)
get_sha1_flags |= GET_OID_COMMITTISH;
- if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc))
- return revs->ignore_missing ? 0 : -1;
+ /*
+ * Even if revs->do_not_die_on_missing_objects is set, we
+ * should error out if we can't even get an oid, as
+ * `--missing=print` should be able to report missing oids.
+ */
+ if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc)) {
+ ret = revs->ignore_missing ? 0 : -1;
+ goto out;
+ }
if (!cant_be_filename)
verify_non_filename(revs->prefix, arg);
object = get_reference(revs, arg, &oid, flags ^ local_flags);
- if (!object)
- return revs->ignore_missing ? 0 : -1;
+ if (!object) {
+ ret = (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1;
+ goto out;
+ }
add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
- free(oc.path);
- return 0;
+
+ ret = 0;
+
+out:
+ object_context_release(&oc);
+ return ret;
}
int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt)
@@ -2214,6 +2298,27 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
add_grep(revs, pattern, GREP_PATTERN_BODY);
}
+static int parse_count(const char *arg)
+{
+ int count;
+
+ if (strtol_i(arg, 10, &count) < 0)
+ die("'%s': not an integer", arg);
+ return count;
+}
+
+static timestamp_t parse_age(const char *arg)
+{
+ timestamp_t num;
+ char *p;
+
+ errno = 0;
+ num = parse_timestamp(arg, &p, 10);
+ if (errno || *p || p == arg)
+ die("'%s': not a number of seconds since epoch", arg);
+ return num;
+}
+
static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
int *unkc, const char **unkv,
const struct setup_revision_opt* opt)
@@ -2240,29 +2345,27 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
}
if ((argcount = parse_long_opt("max-count", argv, &optarg))) {
- revs->max_count = atoi(optarg);
+ revs->max_count = parse_count(optarg);
revs->no_walk = 0;
return argcount;
} else if ((argcount = parse_long_opt("skip", argv, &optarg))) {
- revs->skip_count = atoi(optarg);
+ revs->skip_count = parse_count(optarg);
return argcount;
} else if ((*arg == '-') && isdigit(arg[1])) {
/* accept -<digit>, like traditional "head" */
- if (strtol_i(arg + 1, 10, &revs->max_count) < 0 ||
- revs->max_count < 0)
- die("'%s': not a non-negative integer", arg + 1);
+ revs->max_count = parse_count(arg + 1);
revs->no_walk = 0;
} else if (!strcmp(arg, "-n")) {
if (argc <= 1)
return error("-n requires an argument");
- revs->max_count = atoi(argv[1]);
+ revs->max_count = parse_count(argv[1]);
revs->no_walk = 0;
return 2;
} else if (skip_prefix(arg, "-n", &optarg)) {
- revs->max_count = atoi(optarg);
+ revs->max_count = parse_count(optarg);
revs->no_walk = 0;
} else if ((argcount = parse_long_opt("max-age", argv, &optarg))) {
- revs->max_age = atoi(optarg);
+ revs->max_age = parse_age(optarg);
return argcount;
} else if ((argcount = parse_long_opt("since", argv, &optarg))) {
revs->max_age = approxidate(optarg);
@@ -2274,7 +2377,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->max_age = approxidate(optarg);
return argcount;
} else if ((argcount = parse_long_opt("min-age", argv, &optarg))) {
- revs->min_age = atoi(optarg);
+ revs->min_age = parse_age(optarg);
return argcount;
} else if ((argcount = parse_long_opt("before", argv, &optarg))) {
revs->min_age = approxidate(optarg);
@@ -2294,7 +2397,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (skip_prefix(arg, "--ancestry-path=", &optarg)) {
struct commit *c;
struct object_id oid;
- const char *msg = _("could not get commit for ancestry-path argument %s");
+ const char *msg = _("could not get commit for --ancestry-path argument %s");
revs->ancestry_path = 1;
revs->simplify_history = 0;
@@ -2362,11 +2465,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--no-merges")) {
revs->max_parents = 1;
} else if (skip_prefix(arg, "--min-parents=", &optarg)) {
- revs->min_parents = atoi(optarg);
+ revs->min_parents = parse_count(optarg);
} else if (!strcmp(arg, "--no-min-parents")) {
revs->min_parents = 0;
} else if (skip_prefix(arg, "--max-parents=", &optarg)) {
- revs->max_parents = atoi(optarg);
+ revs->max_parents = parse_count(optarg);
} else if (!strcmp(arg, "--no-max-parents")) {
revs->max_parents = -1;
} else if (!strcmp(arg, "--boundary")) {
@@ -2375,8 +2478,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->left_right = 1;
} else if (!strcmp(arg, "--left-only")) {
if (revs->right_only)
- die("--left-only is incompatible with --right-only"
- " or --cherry");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--left-only", "--right-only/--cherry");
revs->left_only = 1;
} else if (!strcmp(arg, "--right-only")) {
if (revs->left_only)
@@ -2484,6 +2587,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->break_bar = xstrdup(optarg);
revs->track_linear = 1;
revs->track_first_time = 1;
+ } else if (!strcmp(arg, "--show-notes-by-default")) {
+ revs->show_notes_by_default = 1;
} else if (skip_prefix(arg, "--show-notes=", &optarg) ||
skip_prefix(arg, "--notes=", &optarg)) {
if (starts_with(arg, "--show-notes=") &&
@@ -2583,10 +2688,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--invert-grep")) {
revs->grep_filter.no_body_match = 1;
} else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
+ free(git_log_output_encoding);
if (strcmp(optarg, "none"))
git_log_output_encoding = xstrdup(optarg);
else
- git_log_output_encoding = "";
+ git_log_output_encoding = xstrdup("");
return argcount;
} else if (!strcmp(arg, "--reverse")) {
revs->reverse ^= 1;
@@ -2698,7 +2804,8 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
clear_ref_exclusions(&revs->ref_excludes);
} else if (!strcmp(arg, "--branches")) {
if (revs->ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --branches"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--branches");
handle_refs(refs, revs, *flags, refs_for_each_branch_ref);
clear_ref_exclusions(&revs->ref_excludes);
} else if (!strcmp(arg, "--bisect")) {
@@ -2709,18 +2816,21 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
revs->bisect = 1;
} else if (!strcmp(arg, "--tags")) {
if (revs->ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --tags"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--tags");
handle_refs(refs, revs, *flags, refs_for_each_tag_ref);
clear_ref_exclusions(&revs->ref_excludes);
} else if (!strcmp(arg, "--remotes")) {
if (revs->ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --remotes"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--remotes");
handle_refs(refs, revs, *flags, refs_for_each_remote_ref);
clear_ref_exclusions(&revs->ref_excludes);
} else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
- for_each_glob_ref(handle_one_ref, optarg, &cb);
+ refs_for_each_glob_ref(get_main_ref_store(the_repository),
+ handle_one_ref, optarg, &cb);
clear_ref_exclusions(&revs->ref_excludes);
return argcount;
} else if ((argcount = parse_long_opt("exclude", argv, &optarg))) {
@@ -2732,23 +2842,32 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
} else if (skip_prefix(arg, "--branches=", &optarg)) {
struct all_refs_cb cb;
if (revs->ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --branches"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--branches");
init_all_refs_cb(&cb, revs, *flags);
- for_each_glob_ref_in(handle_one_ref, optarg, "refs/heads/", &cb);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ handle_one_ref, optarg,
+ "refs/heads/", &cb);
clear_ref_exclusions(&revs->ref_excludes);
} else if (skip_prefix(arg, "--tags=", &optarg)) {
struct all_refs_cb cb;
if (revs->ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --tags"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--tags");
init_all_refs_cb(&cb, revs, *flags);
- for_each_glob_ref_in(handle_one_ref, optarg, "refs/tags/", &cb);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ handle_one_ref, optarg,
+ "refs/tags/", &cb);
clear_ref_exclusions(&revs->ref_excludes);
} else if (skip_prefix(arg, "--remotes=", &optarg)) {
struct all_refs_cb cb;
if (revs->ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --remotes"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--remotes");
init_all_refs_cb(&cb, revs, *flags);
- for_each_glob_ref_in(handle_one_ref, optarg, "refs/remotes/", &cb);
+ refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+ handle_one_ref, optarg,
+ "refs/remotes/", &cb);
clear_ref_exclusions(&revs->ref_excludes);
} else if (!strcmp(arg, "--reflog")) {
add_reflogs_to_pending(revs, *flags);
@@ -2788,13 +2907,13 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
}
static void read_revisions_from_stdin(struct rev_info *revs,
- struct strvec *prune,
- int *flags)
+ struct strvec *prune)
{
struct strbuf sb;
int seen_dashdash = 0;
int seen_end_of_options = 0;
int save_warning;
+ int flags = 0;
save_warning = warn_on_object_refname_ambiguity;
warn_on_object_refname_ambiguity = 0;
@@ -2817,13 +2936,13 @@ static void read_revisions_from_stdin(struct rev_info *revs,
continue;
}
- if (handle_revision_pseudo_opt(revs, argv, flags) > 0)
+ 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,
+ if (handle_revision_arg(sb.buf, revs, flags,
REVARG_CANNOT_BE_FILENAME))
die("bad revision '%s'", sb.buf);
}
@@ -2839,7 +2958,8 @@ static void NORETURN diagnose_missing_default(const char *def)
int flags;
const char *refname;
- refname = resolve_ref_unsafe(def, 0, NULL, &flags);
+ refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ def, 0, NULL, &flags);
if (!refname || !(flags & REF_ISSYMREF) || (flags & REF_ISBROKEN))
die(_("your current branch appears to be broken"));
@@ -2906,7 +3026,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, &flags);
+ read_revisions_from_stdin(revs, &prune_data);
continue;
}
@@ -2981,6 +3101,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
diagnose_missing_default(revs->def);
object = get_reference(revs, revs->def, &oid, 0);
add_pending_object_with_mode(revs, object, revs->def, oc.mode);
+ object_context_release(&oc);
}
/* Did the user ask for any diff output? Run the diff! */
@@ -3025,8 +3146,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
revs->grep_filter.ignore_locale = 1;
compile_grep_patterns(&revs->grep_filter);
- if (revs->reverse && revs->reflog_info)
- die(_("options '%s' and '%s' cannot be used together"), "--reverse", "--walk-reflogs");
if (revs->reflog_info && revs->limited)
die("cannot combine --walk-reflogs with history-limiting options");
if (revs->rewrite_parents && revs->children.name)
@@ -3037,11 +3156,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
/*
* Limitations on the graph functionality
*/
- if (revs->reverse && revs->graph)
- die(_("options '%s' and '%s' cannot be used together"), "--reverse", "--graph");
+ die_for_incompatible_opt3(!!revs->graph, "--graph",
+ !!revs->reverse, "--reverse",
+ !!revs->reflog_info, "--walk-reflogs");
- if (revs->reflog_info && revs->graph)
- die(_("options '%s' and '%s' cannot be used together"), "--walk-reflogs", "--graph");
if (revs->no_walk && revs->graph)
die(_("options '%s' and '%s' cannot be used together"), "--no-walk", "--graph");
if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
@@ -3054,6 +3172,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (revs->expand_tabs_in_log < 0)
revs->expand_tabs_in_log = revs->expand_tabs_in_log_default;
+ if (!revs->show_notes_given && revs->show_notes_by_default) {
+ enable_default_display_notes(&revs->notes_opt, &revs->show_notes);
+ revs->show_notes_given = 1;
+ }
+
return left;
}
@@ -3085,6 +3208,7 @@ void release_revisions(struct rev_info *revs)
{
free_commit_list(revs->commits);
free_commit_list(revs->ancestry_path_bottoms);
+ release_display_notes(&revs->notes_opt);
object_array_clear(&revs->pending);
object_array_clear(&revs->boundary_commits);
release_revisions_cmdline(&revs->cmdline);
@@ -3094,7 +3218,7 @@ void release_revisions(struct rev_info *revs)
release_revisions_mailmap(revs->mailmap);
free_grep_patterns(&revs->grep_filter);
graph_clear(revs->graph);
- /* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */
+ diff_free(&revs->diffopt);
diff_free(&revs->pruning);
reflog_walk_info_release(revs->reflog_info);
release_revisions_topo_walk_info(revs->topo_walk_info);
@@ -3102,6 +3226,12 @@ void release_revisions(struct rev_info *revs)
clear_decoration(&revs->merge_simplification, free);
clear_decoration(&revs->treesame, free);
line_log_free(revs);
+ oidset_clear(&revs->missing_commits);
+
+ for (int i = 0; i < revs->bloom_keys_nr; i++)
+ clear_bloom_key(&revs->bloom_keys[i]);
+ FREE_AND_NULL(revs->bloom_keys);
+ revs->bloom_keys_nr = 0;
}
static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
@@ -3125,6 +3255,7 @@ static int remove_duplicate_parents(struct rev_info *revs, struct commit *commit
struct commit *parent = p->item;
if (parent->object.flags & TMP_MARK) {
*pp = p->next;
+ free(p);
if (ts)
compact_treesame(revs, commit, surviving_parents);
continue;
@@ -3880,6 +4011,7 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,
break;
case rewrite_one_noparents:
*pp = parent->next;
+ free(parent);
continue;
case rewrite_one_error:
return -1;
@@ -4080,10 +4212,18 @@ static void save_parents(struct rev_info *revs, struct commit *commit)
*pp = EMPTY_PARENT_LIST;
}
+static void free_saved_parent(struct commit_list **parents)
+{
+ if (*parents != EMPTY_PARENT_LIST)
+ free_commit_list(*parents);
+}
+
static void free_saved_parents(struct rev_info *revs)
{
- if (revs->saved_parents_slab)
- clear_saved_parents(revs->saved_parents_slab);
+ if (!revs->saved_parents_slab)
+ return;
+ deep_clear_saved_parents(revs->saved_parents_slab, free_saved_parent);
+ FREE_AND_NULL(revs->saved_parents_slab);
}
struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
@@ -4287,6 +4427,7 @@ static struct commit *get_revision_internal(struct rev_info *revs)
c = get_revision_1(revs);
if (!c)
break;
+ free_commit_buffer(revs->repo->parsed_objects, c);
}
}
@@ -4346,6 +4487,7 @@ struct commit *get_revision(struct rev_info *revs)
reversed = NULL;
while ((c = get_revision_internal(revs)))
commit_list_insert(c, &reversed);
+ free_commit_list(revs->commits);
revs->commits = reversed;
revs->reverse = 0;
revs->reverse_output_stage = 1;
diff --git a/revision.h b/revision.h
index 82ab400139..71e984c452 100644
--- a/revision.h
+++ b/revision.h
@@ -4,6 +4,7 @@
#include "commit.h"
#include "grep.h"
#include "notes.h"
+#include "oidset.h"
#include "pretty.h"
#include "diff.h"
#include "commit-slab-decl.h"
@@ -141,6 +142,7 @@ struct rev_info {
/* Basic information */
const char *prefix;
const char *def;
+ char *ps_matched; /* optionally record matches of prune_data */
struct pathspec prune_data;
/*
@@ -212,18 +214,19 @@ struct rev_info {
/*
* Blobs are shown without regard for their existence.
- * But not so for trees: unless exclude_promisor_objects
+ * But not so for trees/commits: unless exclude_promisor_objects
* is set and the tree in question is a promisor object;
* OR ignore_missing_links is set, the revision walker
- * dies with a "bad tree object HASH" message when
- * encountering a missing tree. For callers that can
- * handle missing trees and want them to be filterable
+ * dies with a "bad <type> object HASH" message when
+ * encountering a missing object. For callers that can
+ * handle missing trees/commits and want them to be filterable
* and showable, set this to true. The revision walker
- * will filter and show such a missing tree as usual,
- * but will not attempt to recurse into this tree
- * object.
+ * will filter and show such a missing object as usual,
+ * but will not attempt to recurse into this tree/commit
+ * object. The revision walker will also set the MISSING
+ * flag for such objects.
*/
- do_not_die_on_missing_tree:1,
+ do_not_die_on_missing_objects:1,
/* for internal use only */
exclude_promisor_objects:1;
@@ -253,6 +256,7 @@ struct rev_info {
shown_dashes:1,
show_merge:1,
show_notes_given:1,
+ show_notes_by_default:1,
show_signature:1,
pretty_given:1,
abbrev_commit:1,
@@ -371,6 +375,9 @@ struct rev_info {
/* Location where temporary objects for remerge-diff are written. */
struct tmp_objdir *remerge_objdir;
+
+ /* Missing commits to be tracked without failing traversal. */
+ struct oidset missing_commits;
};
/**
@@ -542,7 +549,7 @@ int rewrite_parents(struct rev_info *revs,
* The log machinery saves the original parent list so that
* get_saved_parents() can later tell what the real parents of the
* commits are, when commit->parents has been modified by history
- * simpification.
+ * simplification.
*
* get_saved_parents() will transparently return commit->parents if
* history simplification is off.
diff --git a/run-command.c b/run-command.c
index a558042c87..94f2f3079f 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "run-command.h"
#include "environment.h"
@@ -14,9 +16,7 @@
#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)
{
@@ -274,17 +274,24 @@ int sane_execvp(const char *file, char * const argv[])
return -1;
}
+char *git_shell_path(void)
+{
+#ifndef GIT_WINDOWS_NATIVE
+ return xstrdup(SHELL_PATH);
+#else
+ char *p = locate_in_PATH("sh");
+ convert_slashes(p);
+ return p;
+#endif
+}
+
static const char **prepare_shell_cmd(struct strvec *out, const char **argv)
{
if (!argv[0])
BUG("shell command is empty");
if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
-#ifndef GIT_WINDOWS_NATIVE
- strvec_push(out, SHELL_PATH);
-#else
- strvec_push(out, "sh");
-#endif
+ strvec_push_nodup(out, git_shell_path());
strvec_push(out, "-c");
/*
@@ -665,7 +672,7 @@ int start_command(struct child_process *cmd)
int need_in, need_out, need_err;
int fdin[2], fdout[2], fderr[2];
int failed_errno;
- char *str;
+ const char *str;
/*
* In case of errors we must keep the promise to close FDs
@@ -748,6 +755,8 @@ fail_pipe:
goto end_of_spawn;
}
+ trace_argv_printf(&argv.v[1], "trace: start_command:");
+
if (pipe(notify_pipe))
notify_pipe[0] = notify_pipe[1] = -1;
@@ -915,6 +924,7 @@ end_of_spawn:
else if (cmd->use_shell)
cmd->args.v = prepare_shell_cmd(&nargv, sargv);
+ trace_argv_printf(cmd->args.v, "trace: start_command:");
cmd->pid = mingw_spawnvpe(cmd->args.v[0], cmd->args.v,
(char**) cmd->env.v,
cmd->dir, fhin, fhout, fherr);
@@ -1755,7 +1765,8 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
if (do_trace2)
trace2_region_enter_printf(tr2_category, tr2_label, NULL,
- "max:%d", opts->processes);
+ "max:%"PRIuMAX,
+ (uintmax_t)opts->processes);
pp_init(&pp, opts, &pp_sig);
while (1) {
@@ -1795,20 +1806,37 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
trace2_region_leave(tr2_category, tr2_label, NULL);
}
-int run_auto_maintenance(int quiet)
+int prepare_auto_maintenance(int quiet, struct child_process *maint)
{
- int enabled;
- struct child_process maint = CHILD_PROCESS_INIT;
+ int enabled, auto_detach;
if (!git_config_get_bool("maintenance.auto", &enabled) &&
!enabled)
return 0;
- maint.git_cmd = 1;
- maint.close_object_store = 1;
- strvec_pushl(&maint.args, "maintenance", "run", "--auto", NULL);
- strvec_push(&maint.args, quiet ? "--quiet" : "--no-quiet");
+ /*
+ * When `maintenance.autoDetach` isn't set, then we fall back to
+ * honoring `gc.autoDetach`. This is somewhat weird, but required to
+ * retain behaviour from when we used to run git-gc(1) here.
+ */
+ if (git_config_get_bool("maintenance.autodetach", &auto_detach) &&
+ git_config_get_bool("gc.autodetach", &auto_detach))
+ auto_detach = 1;
+
+ maint->git_cmd = 1;
+ maint->close_object_store = 1;
+ strvec_pushl(&maint->args, "maintenance", "run", "--auto", NULL);
+ strvec_push(&maint->args, quiet ? "--quiet" : "--no-quiet");
+ strvec_push(&maint->args, auto_detach ? "--detach" : "--no-detach");
+ return 1;
+}
+
+int run_auto_maintenance(int quiet)
+{
+ struct child_process maint = CHILD_PROCESS_INIT;
+ if (!prepare_auto_maintenance(quiet, &maint))
+ return 0;
return run_command(&maint);
}
diff --git a/run-command.h b/run-command.h
index 1f22cc3827..0df25e445f 100644
--- a/run-command.h
+++ b/run-command.h
@@ -196,6 +196,11 @@ int is_executable(const char *name);
int exists_in_PATH(const char *command);
/**
+ * Return the path that is used to execute Unix shell command-lines.
+ */
+char *git_shell_path(void);
+
+/**
* Start a sub-process. Takes a pointer to a `struct child_process`
* that specifies the details and returns pipe FDs (if requested).
* See below for details.
@@ -218,6 +223,13 @@ int finish_command_in_signal(struct child_process *);
int run_command(struct child_process *);
/*
+ * Prepare a `struct child_process` to run auto-maintenance. Returns 1 if the
+ * process has been prepared and is ready to run, or 0 in case auto-maintenance
+ * should be skipped.
+ */
+int prepare_auto_maintenance(int quiet, struct child_process *maint);
+
+/*
* Trigger an auto-gc
*/
int run_auto_maintenance(int quiet);
@@ -523,7 +535,7 @@ enum start_bg_result {
/* timeout expired waiting for child to become "ready" */
SBGR_TIMEOUT,
- /* child process exited or was signalled before becomming "ready" */
+ /* child process exited or was signalled before becoming "ready" */
SBGR_DIED,
};
diff --git a/scalar.c b/scalar.c
index fb2940c2a0..ac0cb579d3 100644
--- a/scalar.c
+++ b/scalar.c
@@ -2,6 +2,8 @@
* The Scalar command-line interface.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "gettext.h"
@@ -70,6 +72,7 @@ static void setup_enlistment_directory(int argc, const char **argv,
strbuf_release(&path);
}
+LAST_ARG_MUST_BE_NULL
static int run_git(const char *arg, ...)
{
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -288,6 +291,7 @@ static int unregister_dir(void)
}
/* printf-style interface, expects `<key>=<value>` argument */
+__attribute__((format (printf, 1, 2)))
static int set_config(const char *fmt, ...)
{
struct strbuf buf = STRBUF_INIT;
@@ -361,16 +365,13 @@ static char *remote_default_branch(const char *url)
static int delete_enlistment(struct strbuf *enlistment)
{
-#ifdef WIN32
struct strbuf parent = STRBUF_INIT;
size_t offset;
char *path_sep;
-#endif
if (unregister_dir())
return error(_("failed to unregister repository"));
-#ifdef WIN32
/*
* Change the current directory to one outside of the enlistment so
* that we may delete everything underneath it.
@@ -385,7 +386,6 @@ static int delete_enlistment(struct strbuf *enlistment)
return res;
}
strbuf_release(&parent);
-#endif
if (have_fsmonitor_support() && stop_fsmonitor_daemon())
return error(_("failed to stop the FSMonitor daemon"));
@@ -400,7 +400,8 @@ static int delete_enlistment(struct strbuf *enlistment)
* Dummy implementation; Using `get_version_info()` would cause a link error
* without this.
*/
-void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
+void load_builtin_commands(const char *prefix UNUSED,
+ struct cmdnames *cmds UNUSED)
{
die("not implemented");
}
@@ -409,7 +410,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;
+ int src = 1, tags = 1;
struct option clone_options[] = {
OPT_STRING('b', "branch", &branch, N_("<branch>"),
N_("branch to checkout after clone")),
@@ -420,11 +421,13 @@ static int cmd_clone(int argc, const char **argv)
"be checked out")),
OPT_BOOL(0, "src", &src,
N_("create repository within 'src' directory")),
+ OPT_BOOL(0, "tags", &tags,
+ N_("specify if tags should be fetched during clone")),
OPT_END(),
};
const char * const clone_usage[] = {
N_("scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
- "\t[--[no-]src] <url> [<enlistment>]"),
+ "\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"),
NULL
};
const char *url;
@@ -503,6 +506,11 @@ static int cmd_clone(int argc, const char **argv)
goto cleanup;
}
+ if (!tags && set_config("remote.origin.tagOpt=--no-tags")) {
+ res = error(_("could not disable tags in '%s'"), dir);
+ goto cleanup;
+ }
+
if (!full_clone &&
(res = run_git("sparse-checkout", "init", "--cone", NULL)))
goto cleanup;
@@ -512,7 +520,9 @@ static int cmd_clone(int argc, const char **argv)
if ((res = run_git("fetch", "--quiet",
show_progress ? "--progress" : "--no-progress",
- "origin", NULL))) {
+ "origin",
+ (tags ? NULL : "--no-tags"),
+ NULL))) {
warning(_("partial clone failed; attempting full clone"));
if (set_config("remote.origin.promisor") ||
@@ -645,7 +655,6 @@ static int cmd_reconfigure(int argc, const char **argv)
};
struct string_list scalar_repos = STRING_LIST_INIT_DUP;
int i, res = 0;
- struct repository r = { NULL };
struct strbuf commondir = STRBUF_INIT, gitdir = STRBUF_INIT;
argc = parse_options(argc, argv, NULL, options,
@@ -665,6 +674,7 @@ static int cmd_reconfigure(int argc, const char **argv)
for (i = 0; i < scalar_repos.nr; i++) {
int succeeded = 0;
+ struct repository *old_repo, r = { NULL };
const char *dir = scalar_repos.items[i].string;
strbuf_reset(&commondir);
@@ -712,13 +722,21 @@ static int cmd_reconfigure(int argc, const char **argv)
git_config_clear();
+ if (repo_init(&r, gitdir.buf, commondir.buf))
+ goto loop_end;
+
+ old_repo = the_repository;
the_repository = &r;
- r.commondir = commondir.buf;
- r.gitdir = gitdir.buf;
if (set_recommended_config(1) >= 0)
succeeded = 1;
+ the_repository = old_repo;
+ repo_clear(&r);
+
+ if (toggle_maintenance(1) >= 0)
+ succeeded = 1;
+
loop_end:
if (!succeeded) {
res = -1;
diff --git a/send-pack.c b/send-pack.c
index 89aca9d829..6677c44e8a 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -1,10 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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-ll.h"
#include "pkt-line.h"
#include "sideband.h"
@@ -12,7 +13,6 @@
#include "remote.h"
#include "connect.h"
#include "send-pack.h"
-#include "quote.h"
#include "transport.h"
#include "version.h"
#include "oid-array.h"
@@ -75,6 +75,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
int i;
int rc;
+ trace2_region_enter("send_pack", "pack_objects", the_repository);
strvec_push(&po.args, "pack-objects");
strvec_push(&po.args, "--all-progress-implied");
strvec_push(&po.args, "--revs");
@@ -146,8 +147,10 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
*/
if (rc > 128 && rc != 141)
error("pack-objects died of signal %d", rc - 128);
+ trace2_region_leave("send_pack", "pack_objects", the_repository);
return -1;
}
+ trace2_region_leave("send_pack", "pack_objects", the_repository);
return 0;
}
@@ -170,6 +173,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
int new_report = 0;
int once = 0;
+ trace2_region_enter("send_pack", "receive_status", the_repository);
hint = NULL;
ret = receive_unpack_status(reader);
while (1) {
@@ -261,13 +265,14 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
if (p)
hint->remote_status = xstrdup(p);
else
- hint->remote_status = "failed";
+ hint->remote_status = xstrdup("failed");
} else {
hint->status = REF_STATUS_OK;
hint->remote_status = xstrdup_or_null(p);
new_report = 1;
}
}
+ trace2_region_leave("send_pack", "receive_status", the_repository);
return ret;
}
@@ -348,7 +353,8 @@ static int generate_push_cert(struct strbuf *req_buf,
{
const struct ref *ref;
struct string_list_item *item;
- char *signing_key_id = xstrdup(get_signing_key_id());
+ char *signing_key_id = get_signing_key_id();
+ char *signing_key = get_signing_key();
const char *cp, *np;
struct strbuf cert = STRBUF_INIT;
int update_seen = 0;
@@ -381,7 +387,7 @@ static int generate_push_cert(struct strbuf *req_buf,
if (!update_seen)
goto free_return;
- if (sign_buffer(&cert, &cert, get_signing_key()))
+ if (sign_buffer(&cert, &cert, signing_key))
die(_("failed to sign the push certificate"));
packet_buf_write(req_buf, "push-cert%c%s", 0, cap_string);
@@ -394,6 +400,7 @@ static int generate_push_cert(struct strbuf *req_buf,
free_return:
free(signing_key_id);
+ free(signing_key);
strbuf_release(&cert);
return update_seen;
}
@@ -427,17 +434,26 @@ static void get_commons_through_negotiation(const char *url,
struct child_process child = CHILD_PROCESS_INIT;
const struct ref *ref;
int len = the_hash_algo->hexsz + 1; /* hash + NL */
+ int nr_negotiation_tip = 0;
child.git_cmd = 1;
child.no_stdin = 1;
child.out = -1;
strvec_pushl(&child.args, "fetch", "--negotiate-only", NULL);
for (ref = remote_refs; ref; ref = ref->next) {
- if (!is_null_oid(&ref->new_oid))
- strvec_pushf(&child.args, "--negotiation-tip=%s", oid_to_hex(&ref->new_oid));
+ if (!is_null_oid(&ref->new_oid)) {
+ strvec_pushf(&child.args, "--negotiation-tip=%s",
+ oid_to_hex(&ref->new_oid));
+ nr_negotiation_tip++;
+ }
}
strvec_push(&child.args, url);
+ if (!nr_negotiation_tip) {
+ child_process_clear(&child);
+ return;
+ }
+
if (start_command(&child))
die(_("send-pack: unable to fork off fetch subprocess"));
@@ -492,19 +508,23 @@ int send_pack(struct send_pack_args *args,
unsigned cmds_sent = 0;
int ret;
struct async demux;
- const char *push_cert_nonce = NULL;
+ char *push_cert_nonce = NULL;
struct packet_reader reader;
int use_bitmaps;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
"Perhaps you should specify a branch.\n");
- return 0;
+ ret = 0;
+ goto out;
}
git_config_get_bool("push.negotiate", &push_negotiate);
- if (push_negotiate)
+ if (push_negotiate) {
+ trace2_region_enter("send_pack", "push_negotiate", the_repository);
get_commons_through_negotiation(args->url, remote_refs, &commons);
+ trace2_region_leave("send_pack", "push_negotiate", the_repository);
+ }
if (!git_config_get_bool("push.usebitmaps", &use_bitmaps))
args->disable_bitmaps = !use_bitmaps;
@@ -540,10 +560,11 @@ int send_pack(struct send_pack_args *args,
if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
size_t len;
- push_cert_nonce = server_feature_value("push-cert", &len);
- if (push_cert_nonce) {
- reject_invalid_nonce(push_cert_nonce, len);
- push_cert_nonce = xmemdupz(push_cert_nonce, len);
+ const char *nonce = server_feature_value("push-cert", &len);
+
+ if (nonce) {
+ reject_invalid_nonce(nonce, len);
+ push_cert_nonce = xmemdupz(nonce, len);
} else if (args->push_cert == SEND_PACK_PUSH_CERT_ALWAYS) {
die(_("the receiving end does not support --signed push"));
} else if (args->push_cert == SEND_PACK_PUSH_CERT_IF_ASKED) {
@@ -606,12 +627,11 @@ int send_pack(struct send_pack_args *args,
* atomically, abort the whole operation.
*/
if (use_atomic) {
- strbuf_release(&req_buf);
- strbuf_release(&cap_buf);
reject_atomic_push(remote_refs, args->send_mirror);
- error("atomic push failed for ref %s. status: %d\n",
+ error("atomic push failed for ref %s. status: %d",
ref->name, ref->status);
- return args->porcelain ? 0 : -1;
+ ret = args->porcelain ? 0 : -1;
+ goto out;
}
/* else fallthrough */
default:
@@ -632,10 +652,11 @@ int send_pack(struct send_pack_args *args,
/*
* Finally, tell the other end!
*/
- if (!args->dry_run && push_cert_nonce)
+ if (!args->dry_run && push_cert_nonce) {
cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
cap_buf.buf, push_cert_nonce);
- else if (!args->dry_run)
+ trace2_printf("Generated push certificate");
+ } else if (!args->dry_run) {
for (ref = remote_refs; ref; ref = ref->next) {
char *old_hex, *new_hex;
@@ -655,6 +676,7 @@ int send_pack(struct send_pack_args *args,
old_hex, new_hex, ref->name);
}
}
+ }
if (use_push_options) {
struct string_list_item *item;
@@ -673,8 +695,6 @@ int send_pack(struct send_pack_args *args,
write_or_die(out, req_buf.buf, req_buf.len);
packet_flush(out);
}
- strbuf_release(&req_buf);
- strbuf_release(&cap_buf);
if (use_sideband && cmds_sent) {
memset(&demux, 0, sizeof(demux));
@@ -712,7 +732,9 @@ int send_pack(struct send_pack_args *args,
finish_async(&demux);
}
fd[1] = -1;
- return -1;
+
+ ret = -1;
+ goto out;
}
if (!args->stateless_rpc)
/* Closed by pack_objects() via start_command() */
@@ -737,10 +759,12 @@ int send_pack(struct send_pack_args *args,
}
if (ret < 0)
- return ret;
+ goto out;
- if (args->porcelain)
- return 0;
+ if (args->porcelain) {
+ ret = 0;
+ goto out;
+ }
for (ref = remote_refs; ref; ref = ref->next) {
switch (ref->status) {
@@ -749,8 +773,17 @@ int send_pack(struct send_pack_args *args,
case REF_STATUS_OK:
break;
default:
- return -1;
+ ret = -1;
+ goto out;
}
}
- return 0;
+
+ ret = 0;
+
+out:
+ oid_array_clear(&commons);
+ strbuf_release(&req_buf);
+ strbuf_release(&cap_buf);
+ free(push_cert_nonce);
+ return ret;
}
diff --git a/sequencer.c b/sequencer.c
index 42f495c4b4..287f4e5e87 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
@@ -15,10 +17,8 @@
#include "pager.h"
#include "commit.h"
#include "sequencer.h"
-#include "tag.h"
#include "run-command.h"
#include "hook.h"
-#include "exec-cmd.h"
#include "utf8.h"
#include "cache-tree.h"
#include "diff.h"
@@ -39,7 +39,6 @@
#include "notes-utils.h"
#include "sigchain.h"
#include "unpack-trees.h"
-#include "worktree.h"
#include "oidmap.h"
#include "oidset.h"
#include "commit-slab.h"
@@ -210,6 +209,46 @@ static GIT_PATH_FUNC(rebase_path_no_reschedule_failed_exec, "rebase-merge/no-res
static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
+/*
+ * A 'struct replay_ctx' represents the private state of the sequencer.
+ */
+struct replay_ctx {
+ /*
+ * The commit message that will be used except at the end of a
+ * chain of fixup and squash commands.
+ */
+ struct strbuf message;
+ /*
+ * The list of completed fixup and squash commands in the
+ * current chain.
+ */
+ struct strbuf current_fixups;
+ /*
+ * Stores the reflog message that will be used when creating a
+ * commit. Points to a static buffer and should not be free()'d.
+ */
+ const char *reflog_message;
+ /*
+ * The number of completed fixup and squash commands in the
+ * current chain.
+ */
+ int current_fixup_count;
+ /*
+ * Whether message contains a commit message.
+ */
+ unsigned have_message :1;
+};
+
+struct replay_ctx* replay_ctx_new(void)
+{
+ struct replay_ctx *ctx = xcalloc(1, sizeof(*ctx));
+
+ strbuf_init(&ctx->current_fixups, 0);
+ strbuf_init(&ctx->message, 0);
+
+ return ctx;
+}
+
/**
* A 'struct update_refs_record' represents a value in the update-refs
* list. We use a string_list to map refs to these (before, after) pairs.
@@ -229,7 +268,7 @@ static struct update_ref_record *init_update_ref_record(const char *ref)
oidcpy(&rec->after, null_oid());
/* This may fail, but that's fine, we will keep the null OID. */
- read_ref(ref, &rec->before);
+ refs_read_ref(get_main_ref_store(the_repository), ref, &rec->before);
return rec;
}
@@ -238,43 +277,39 @@ 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;
if (!strcmp(k, "commit.cleanup")) {
- const char *s;
-
- status = git_config_string(&s, k, v);
- if (status)
- return status;
+ if (!v)
+ return config_error_nonbool(k);
- if (!strcmp(s, "verbatim")) {
+ if (!strcmp(v, "verbatim")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
opts->explicit_cleanup = 1;
- } else if (!strcmp(s, "whitespace")) {
+ } else if (!strcmp(v, "whitespace")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
opts->explicit_cleanup = 1;
- } else if (!strcmp(s, "strip")) {
+ } else if (!strcmp(v, "strip")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
opts->explicit_cleanup = 1;
- } else if (!strcmp(s, "scissors")) {
+ } else if (!strcmp(v, "scissors")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
opts->explicit_cleanup = 1;
} else {
warning(_("invalid commit message cleanup mode '%s'"),
- s);
+ v);
}
- free((char *)s);
- return status;
+ return 0;
}
if (!strcmp(k, "commit.gpgsign")) {
+ free(opts->gpg_sign);
opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
return 0;
}
if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
- int ret = git_config_string((const char**)&opts->default_strategy, k, v);
+ int ret = git_config_string(&opts->default_strategy, k, v);
if (ret == 0) {
/*
* pull.twohead is allowed to be multi-valued; we only
@@ -327,35 +362,32 @@ static const char *get_todo_path(const struct replay_opts *opts)
static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
size_t ignore_footer)
{
- struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
- struct trailer_info info;
- size_t i;
+ struct trailer_iterator iter;
+ size_t i = 0;
int found_sob = 0, found_sob_last = 0;
char saved_char;
- opts.no_divider = 1;
-
if (ignore_footer) {
saved_char = sb->buf[sb->len - ignore_footer];
sb->buf[sb->len - ignore_footer] = '\0';
}
- trailer_info_get(&info, sb->buf, &opts);
+ trailer_iterator_init(&iter, sb->buf);
if (ignore_footer)
sb->buf[sb->len - ignore_footer] = saved_char;
- if (info.trailer_start == info.trailer_end)
- return 0;
+ while (trailer_iterator_advance(&iter)) {
+ i++;
+ if (sob && !strncmp(iter.raw, sob->buf, sob->len))
+ found_sob = i;
+ }
+ trailer_iterator_release(&iter);
- for (i = 0; i < info.trailer_nr; i++)
- if (sob && !strncmp(info.trailers[i], sob->buf, sob->len)) {
- found_sob = 1;
- if (i == info.trailer_nr - 1)
- found_sob_last = 1;
- }
+ if (!i)
+ return 0;
- trailer_info_release(&info);
+ found_sob_last = (int)i == found_sob;
if (found_sob_last)
return 3;
@@ -374,17 +406,26 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
return buf.buf;
}
+static void replay_ctx_release(struct replay_ctx *ctx)
+{
+ strbuf_release(&ctx->current_fixups);
+ strbuf_release(&ctx->message);
+}
+
void replay_opts_release(struct replay_opts *opts)
{
+ struct replay_ctx *ctx = opts->ctx;
+
free(opts->gpg_sign);
free(opts->reflog_action);
free(opts->default_strategy);
free(opts->strategy);
strvec_clear (&opts->xopts);
- strbuf_release(&opts->current_fixups);
if (opts->revs)
release_revisions(opts->revs);
free(opts->revs);
+ replay_ctx_release(ctx);
+ free(opts->ctx);
}
int sequencer_remove_state(struct replay_opts *opts)
@@ -399,7 +440,7 @@ int sequencer_remove_state(struct replay_opts *opts)
char *eol = strchr(p, '\n');
if (eol)
*eol = '\0';
- if (delete_ref("(rebase) cleanup", p, NULL, 0) < 0) {
+ if (refs_delete_ref(get_main_ref_store(the_repository), "(rebase) cleanup", p, NULL, 0) < 0) {
warning(_("could not delete '%s'"), p);
ret = -1;
}
@@ -438,10 +479,9 @@ struct commit_message {
const char *message;
};
-static const char *short_commit_name(struct commit *commit)
+static const char *short_commit_name(struct repository *r, struct commit *commit)
{
- return repo_find_unique_abbrev(the_repository, &commit->object.oid,
- DEFAULT_ABBREV);
+ return repo_find_unique_abbrev(r, &commit->object.oid, DEFAULT_ABBREV);
}
static int get_message(struct commit *commit, struct commit_message *out)
@@ -451,7 +491,7 @@ static int get_message(struct commit *commit, struct commit_message *out)
out->message = repo_logmsg_reencode(the_repository, commit, NULL,
get_commit_output_encoding());
- abbrev = short_commit_name(commit);
+ abbrev = short_commit_name(the_repository, commit);
subject_len = find_commit_subject(out->message, &subject);
@@ -470,41 +510,56 @@ static void free_message(struct commit *commit, struct commit_message *msg)
repo_unuse_commit_buffer(the_repository, commit, msg->message);
}
+const char *rebase_resolvemsg =
+N_("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\".");
+
static void print_advice(struct repository *r, int show_hint,
struct replay_opts *opts)
{
- char *msg = getenv("GIT_CHERRY_PICK_HELP");
+ const char *msg;
+
+ if (is_rebase_i(opts))
+ msg = rebase_resolvemsg;
+ else
+ msg = getenv("GIT_CHERRY_PICK_HELP");
if (msg) {
- advise("%s\n", msg);
+ advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", msg);
/*
* A conflict has occurred but the porcelain
* (typically rebase --interactive) wants to take care
* of the commit itself so remove CHERRY_PICK_HEAD
*/
refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
- NULL, 0);
+ NULL, REF_NO_DEREF);
return;
}
if (show_hint) {
if (opts->no_commit)
- advise(_("after resolving the conflicts, mark the corrected paths\n"
- "with 'git add <paths>' or 'git rm <paths>'"));
+ advise_if_enabled(ADVICE_MERGE_CONFLICT,
+ _("after resolving the conflicts, mark the corrected paths\n"
+ "with 'git add <paths>' or 'git rm <paths>'"));
else if (opts->action == REPLAY_PICK)
- advise(_("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\"."));
+ advise_if_enabled(ADVICE_MERGE_CONFLICT,
+ _("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\"."));
else if (opts->action == REPLAY_REVERT)
- advise(_("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\"."));
+ advise_if_enabled(ADVICE_MERGE_CONFLICT,
+ _("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\"."));
else
BUG("unexpected pick action in print_advice()");
}
@@ -606,11 +661,12 @@ static int fast_forward_to(struct repository *r,
strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction ||
ref_transaction_update(transaction, "HEAD",
to, unborn && !is_rebase_i(opts) ?
- null_oid() : from,
+ null_oid() : from, NULL, NULL,
0, sb.buf, &err) ||
ref_transaction_commit(transaction, &err)) {
ref_transaction_free(transaction);
@@ -672,15 +728,15 @@ void append_conflicts_hint(struct index_state *istate,
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
strbuf_addch(msgbuf, '\n');
wt_status_append_cut_line(msgbuf);
- strbuf_addch(msgbuf, comment_line_char);
+ strbuf_addstr(msgbuf, comment_line_str);
}
strbuf_addch(msgbuf, '\n');
- strbuf_commented_addf(msgbuf, comment_line_char, "Conflicts:\n");
+ strbuf_commented_addf(msgbuf, comment_line_str, "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, comment_line_char,
+ strbuf_commented_addf(msgbuf, comment_line_str,
"\t%s\n", ce->name);
while (i < istate->cache_nr &&
!strcmp(ce->name, istate->cache[i]->name))
@@ -707,7 +763,7 @@ static int do_recursive_merge(struct repository *r,
repo_read_index(r);
- init_merge_options(&o, r);
+ init_ui_merge_options(&o, r);
o.ancestor = base ? base_label : "(empty tree)";
o.branch1 = "HEAD";
o.branch2 = next ? next_label : "(empty tree)";
@@ -716,6 +772,8 @@ static int do_recursive_merge(struct repository *r,
o.show_rename_progress = 1;
head_tree = parse_tree_indirect(head);
+ if (!head_tree)
+ return error(_("unable to read tree (%s)"), oid_to_hex(head));
next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
@@ -779,29 +837,43 @@ static struct object_id *get_cache_tree_oid(struct index_state *istate)
static int is_index_unchanged(struct repository *r)
{
struct object_id head_oid, *cache_tree_oid;
+ const struct object_id *head_tree_oid;
struct commit *head_commit;
struct index_state *istate = r->index;
+ const char *head_name;
+
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL)) {
+ /* Check to see if this is an unborn branch */
+ head_name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD",
+ RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ &head_oid, NULL);
+ if (!head_name ||
+ !starts_with(head_name, "refs/heads/") ||
+ !is_null_oid(&head_oid))
+ return error(_("could not resolve HEAD commit"));
+ head_tree_oid = the_hash_algo->empty_tree;
+ } else {
+ head_commit = lookup_commit(r, &head_oid);
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
- return error(_("could not resolve HEAD commit"));
-
- head_commit = lookup_commit(r, &head_oid);
+ /*
+ * If head_commit is NULL, check_commit, called from
+ * lookup_commit, would have indicated that head_commit is not
+ * a commit object already. repo_parse_commit() will return failure
+ * without further complaints in such a case. Otherwise, if
+ * the commit is invalid, repo_parse_commit() will complain. So
+ * there is nothing for us to say here. Just return failure.
+ */
+ if (repo_parse_commit(r, head_commit))
+ return -1;
- /*
- * If head_commit is NULL, check_commit, called from
- * lookup_commit, would have indicated that head_commit is not
- * a commit object already. repo_parse_commit() will return failure
- * without further complaints in such a case. Otherwise, if
- * the commit is invalid, repo_parse_commit() will complain. So
- * there is nothing for us to say here. Just return failure.
- */
- if (repo_parse_commit(r, head_commit))
- return -1;
+ head_tree_oid = get_commit_tree_oid(head_commit);
+ }
if (!(cache_tree_oid = get_cache_tree_oid(istate)))
return -1;
- return oideq(cache_tree_oid, get_commit_tree_oid(head_commit));
+ return oideq(cache_tree_oid, head_tree_oid);
}
static int write_author_script(const char *message)
@@ -1063,6 +1135,7 @@ static int run_git_commit(const char *defmsg,
struct replay_opts *opts,
unsigned int flags)
{
+ struct replay_ctx *ctx = opts->ctx;
struct child_process cmd = CHILD_PROCESS_INIT;
if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
@@ -1080,7 +1153,7 @@ static int run_git_commit(const char *defmsg,
gpg_opt, gpg_opt);
}
- strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", opts->reflog_message);
+ strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", ctx->reflog_message);
if (opts->committer_date_is_author_date)
strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
@@ -1161,7 +1234,7 @@ void cleanup_message(struct strbuf *msgbuf,
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 ? comment_line_char : '\0');
+ cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_str : NULL);
}
/*
@@ -1193,7 +1266,7 @@ int template_untouched(const struct strbuf *sb, const char *template_file,
return 0;
strbuf_stripspace(&tmpl,
- cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
+ cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_str : NULL);
if (!skip_prefix(sb->buf, tmpl.buf, &start))
start = sb->buf;
strbuf_release(&tmpl);
@@ -1223,11 +1296,12 @@ int update_head_with_reflog(const struct commit *old_head,
strbuf_addch(&sb, '\n');
}
- transaction = ref_transaction_begin(err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, err);
if (!transaction ||
ref_transaction_update(transaction, "HEAD", new_head,
old_head ? &old_head->object.oid : null_oid(),
- 0, sb.buf, err) ||
+ NULL, NULL, 0, sb.buf, err) ||
ref_transaction_commit(transaction, err)) {
ret = -1;
}
@@ -1243,7 +1317,7 @@ static int run_rewrite_hook(const struct object_id *oldoid,
struct child_process proc = CHILD_PROCESS_INIT;
int code;
struct strbuf sb = STRBUF_INIT;
- const char *hook_path = find_hook("post-rewrite");
+ const char *hook_path = find_hook(the_repository, "post-rewrite");
if (!hook_path)
return 0;
@@ -1466,6 +1540,7 @@ static int try_to_commit(struct repository *r,
struct replay_opts *opts, unsigned int flags,
struct object_id *oid)
{
+ struct replay_ctx *ctx = opts->ctx;
struct object_id tree;
struct commit *current_head = NULL;
struct commit_list *parents = NULL;
@@ -1540,7 +1615,7 @@ static int try_to_commit(struct repository *r,
}
}
- if (hook_exists("prepare-commit-msg")) {
+ if (hook_exists(r, "prepare-commit-msg")) {
res = run_prepare_commit_msg_hook(r, msg, hook_commit);
if (res)
goto out;
@@ -1566,7 +1641,7 @@ static int try_to_commit(struct repository *r,
if (cleanup != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(msg,
- cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
+ cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_str : NULL);
if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
res = 1; /* run 'git commit' to display error message */
goto out;
@@ -1627,7 +1702,7 @@ static int try_to_commit(struct repository *r,
goto out;
}
- if (update_head_with_reflog(current_head, oid, opts->reflog_message,
+ if (update_head_with_reflog(current_head, oid, ctx->reflog_message,
msg, &err)) {
res = error("%s", err.buf);
goto out;
@@ -1639,6 +1714,7 @@ static int try_to_commit(struct repository *r,
out:
free_commit_extra_headers(extra);
+ free_commit_list(parents);
strbuf_release(&err);
strbuf_release(&commit_msg);
free(amend_author);
@@ -1648,8 +1724,8 @@ out:
static int write_rebase_head(struct object_id *oid)
{
- if (update_ref("rebase", "REBASE_HEAD", oid,
- NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
+ if (refs_update_ref(get_main_ref_store(the_repository), "rebase", "REBASE_HEAD", oid,
+ NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
return error(_("could not update %s"), "REBASE_HEAD");
return 0;
@@ -1676,7 +1752,7 @@ static int do_commit(struct repository *r,
strbuf_release(&sb);
if (!res) {
refs_delete_ref(get_main_ref_store(r), "",
- "CHERRY_PICK_HEAD", NULL, 0);
+ "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF);
unlink(git_path_merge_msg(r));
if (!is_rebase_i(opts))
print_commit_summary(r, NULL, &oid,
@@ -1728,34 +1804,25 @@ static int allow_empty(struct repository *r,
int index_unchanged, originally_empty;
/*
- * Four cases:
- *
- * (1) we do not allow empty at all and error out.
+ * For a commit that is initially empty, allow_empty determines if it
+ * should be kept or not
*
- * (2) we allow ones that were initially empty, and
- * just drop the ones that become empty
- *
- * (3) we allow ones that were initially empty, but
- * halt for the ones that become empty;
- *
- * (4) we allow both.
+ * For a commit that becomes empty, keep_redundant_commits and
+ * drop_redundant_commits determine whether the commit should be kept or
+ * dropped. If neither is specified, halt.
*/
- if (!opts->allow_empty)
- return 0; /* let "git commit" barf as necessary */
-
index_unchanged = is_index_unchanged(r);
if (index_unchanged < 0)
return index_unchanged;
if (!index_unchanged)
return 0; /* we do not have to say --allow-empty */
- if (opts->keep_redundant_commits)
- return 1;
-
originally_empty = is_original_commit_empty(commit);
if (originally_empty < 0)
return originally_empty;
if (originally_empty)
+ return opts->allow_empty;
+ else if (opts->keep_redundant_commits)
return 1;
else if (opts->drop_redundant_commits)
return 2;
@@ -1788,6 +1855,8 @@ static const char *command_to_string(const enum todo_command command)
{
if (command < TODO_COMMENT)
return todo_command_info[command].str;
+ if (command == TODO_COMMENT)
+ return comment_line_str;
die(_("unknown command: %d"), command);
}
@@ -1795,7 +1864,7 @@ static char command_to_char(const enum todo_command command)
{
if (command < TODO_COMMENT)
return todo_command_info[command].c;
- return comment_line_char;
+ return 0;
}
static int is_noop(const enum todo_command command)
@@ -1849,7 +1918,7 @@ static int is_fixup_flag(enum todo_command command, unsigned flag)
static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
{
const char *s = str;
- while (len > 0 && s[0] == comment_line_char) {
+ while (starts_with_mem(s, len, comment_line_str)) {
size_t count;
const char *n = memchr(s, '\n', len);
if (!n)
@@ -1860,14 +1929,14 @@ 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, comment_line_char);
+ strbuf_add_commented_lines(buf, s, len, comment_line_str);
}
/* Does the current fixup chain contain a squash command? */
-static int seen_squash(struct replay_opts *opts)
+static int seen_squash(struct replay_ctx *ctx)
{
- return starts_with(opts->current_fixups.buf, "squash") ||
- strstr(opts->current_fixups.buf, "\nsquash");
+ return starts_with(ctx->current_fixups.buf, "squash") ||
+ strstr(ctx->current_fixups.buf, "\nsquash");
}
static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)
@@ -1943,6 +2012,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
enum todo_command command, struct replay_opts *opts,
unsigned flag)
{
+ struct replay_ctx *ctx = opts->ctx;
const char *fixup_msg;
size_t commented_len = 0, fixup_off;
/*
@@ -1951,21 +2021,21 @@ static int append_squash_message(struct strbuf *buf, const char *body,
* squashing commit messages.
*/
if (starts_with(body, "amend!") ||
- ((command == TODO_SQUASH || seen_squash(opts)) &&
+ ((command == TODO_SQUASH || seen_squash(ctx)) &&
(starts_with(body, "squash!") || starts_with(body, "fixup!"))))
commented_len = commit_subject_length(body);
- strbuf_addf(buf, "\n%c ", comment_line_char);
+ strbuf_addf(buf, "\n%s ", comment_line_str);
strbuf_addf(buf, _(nth_commit_msg_fmt),
- ++opts->current_fixup_count + 1);
+ ++ctx->current_fixup_count + 1);
strbuf_addstr(buf, "\n\n");
- strbuf_add_commented_lines(buf, body, commented_len, comment_line_char);
+ strbuf_add_commented_lines(buf, body, commented_len, comment_line_str);
/* buf->buf may be reallocated so store an offset into the buffer */
fixup_off = buf->len;
strbuf_addstr(buf, body + commented_len);
/* fixup -C after squash behaves like squash */
- if (is_fixup_flag(command, flag) && !seen_squash(opts)) {
+ if (is_fixup_flag(command, flag) && !seen_squash(ctx)) {
/*
* We're replacing the commit message so we need to
* append the Signed-off-by: trailer if the user
@@ -1999,12 +2069,13 @@ static int update_squash_messages(struct repository *r,
struct replay_opts *opts,
unsigned flag)
{
+ struct replay_ctx *ctx = opts->ctx;
struct strbuf buf = STRBUF_INIT;
int res = 0;
const char *message, *body;
const char *encoding = get_commit_output_encoding();
- if (opts->current_fixup_count > 0) {
+ if (ctx->current_fixup_count > 0) {
struct strbuf header = STRBUF_INIT;
char *eol;
@@ -2012,15 +2083,15 @@ static int update_squash_messages(struct repository *r,
return error(_("could not read '%s'"),
rebase_path_squash_msg());
- eol = buf.buf[0] != comment_line_char ?
+ eol = !starts_with(buf.buf, comment_line_str) ?
buf.buf : strchrnul(buf.buf, '\n');
- strbuf_addf(&header, "%c ", comment_line_char);
+ strbuf_addf(&header, "%s ", comment_line_str);
strbuf_addf(&header, _(combined_commit_msg_fmt),
- opts->current_fixup_count + 2);
+ ctx->current_fixup_count + 2);
strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
strbuf_release(&header);
- if (is_fixup_flag(command, flag) && !seen_squash(opts))
+ if (is_fixup_flag(command, flag) && !seen_squash(ctx))
update_squash_message_for_fixup(&buf);
} else {
struct object_id head;
@@ -2041,16 +2112,16 @@ static int update_squash_messages(struct repository *r,
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);
+ strbuf_addf(&buf, "%s ", comment_line_str);
strbuf_addf(&buf, _(combined_commit_msg_fmt), 2);
- strbuf_addf(&buf, "\n%c ", comment_line_char);
+ strbuf_addf(&buf, "\n%s ", comment_line_str);
strbuf_addstr(&buf, is_fixup_flag(command, flag) ?
_(skip_first_commit_msg_str) :
_(first_commit_msg_str));
strbuf_addstr(&buf, "\n\n");
if (is_fixup_flag(command, flag))
strbuf_add_commented_lines(&buf, body, strlen(body),
- comment_line_char);
+ comment_line_str);
else
strbuf_addstr(&buf, body);
@@ -2065,12 +2136,12 @@ static int update_squash_messages(struct repository *r,
if (command == TODO_SQUASH || is_fixup_flag(command, flag)) {
res = append_squash_message(&buf, body, command, opts, flag);
} else if (command == TODO_FIXUP) {
- strbuf_addf(&buf, "\n%c ", comment_line_char);
+ strbuf_addf(&buf, "\n%s ", comment_line_str);
strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
- ++opts->current_fixup_count + 1);
+ ++ctx->current_fixup_count + 1);
strbuf_addstr(&buf, "\n\n");
strbuf_add_commented_lines(&buf, body, strlen(body),
- comment_line_char);
+ comment_line_str);
} else
return error(_("unknown command: %d"), command);
repo_unuse_commit_buffer(r, commit, message);
@@ -2081,12 +2152,12 @@ static int update_squash_messages(struct repository *r,
strbuf_release(&buf);
if (!res) {
- strbuf_addf(&opts->current_fixups, "%s%s %s",
- opts->current_fixups.len ? "\n" : "",
+ strbuf_addf(&ctx->current_fixups, "%s%s %s",
+ ctx->current_fixups.len ? "\n" : "",
command_to_string(command),
oid_to_hex(&commit->object.oid));
- res = write_message(opts->current_fixups.buf,
- opts->current_fixups.len,
+ res = write_message(ctx->current_fixups.buf,
+ ctx->current_fixups.len,
rebase_path_current_fixups(), 0);
}
@@ -2164,6 +2235,7 @@ static int do_pick_commit(struct repository *r,
struct replay_opts *opts,
int final_fixup, int *check_todo)
{
+ struct replay_ctx *ctx = opts->ctx;
unsigned int flags = should_edit(opts) ? EDIT_MSG : 0;
const char *msg_file = should_edit(opts) ? NULL : git_path_merge_msg(r);
struct object_id head;
@@ -2171,7 +2243,6 @@ static int do_pick_commit(struct repository *r,
const char *base_label, *next_label;
char *author = NULL;
struct commit_message msg = { NULL, NULL, NULL, NULL };
- struct strbuf msgbuf = STRBUF_INIT;
int res, unborn = 0, reword = 0, allow, drop_commit;
enum todo_command command = item->command;
struct commit *commit = item->commit;
@@ -2196,7 +2267,7 @@ static int do_pick_commit(struct repository *r,
unborn = 1;
} else if (unborn)
oidcpy(&head, the_hash_algo->empty_tree);
- if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD",
+ if (index_differs_from(r, unborn ? empty_tree_oid_hex(the_repository->hash_algo) : "HEAD",
NULL, 0))
return error_dirty_index(r, opts);
}
@@ -2263,26 +2334,37 @@ static int do_pick_commit(struct repository *r,
*/
if (command == TODO_REVERT) {
+ const char *orig_subject;
+
base = commit;
base_label = msg.label;
next = parent;
next_label = msg.parent_label;
if (opts->commit_use_reference) {
- strbuf_addstr(&msgbuf,
+ strbuf_addstr(&ctx->message,
"# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
+ } else if (skip_prefix(msg.subject, "Revert \"", &orig_subject) &&
+ /*
+ * We don't touch pre-existing repeated reverts, because
+ * theoretically these can be nested arbitrarily deeply,
+ * thus requiring excessive complexity to deal with.
+ */
+ !starts_with(orig_subject, "Revert \"")) {
+ strbuf_addstr(&ctx->message, "Reapply \"");
+ strbuf_addstr(&ctx->message, orig_subject);
} else {
- strbuf_addstr(&msgbuf, "Revert \"");
- strbuf_addstr(&msgbuf, msg.subject);
- strbuf_addstr(&msgbuf, "\"");
+ strbuf_addstr(&ctx->message, "Revert \"");
+ strbuf_addstr(&ctx->message, msg.subject);
+ strbuf_addstr(&ctx->message, "\"");
}
- strbuf_addstr(&msgbuf, "\n\nThis reverts commit ");
- refer_to_commit(opts, &msgbuf, commit);
+ strbuf_addstr(&ctx->message, "\n\nThis reverts commit ");
+ refer_to_commit(opts, &ctx->message, commit);
if (commit->parents && commit->parents->next) {
- strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
- refer_to_commit(opts, &msgbuf, parent);
+ strbuf_addstr(&ctx->message, ", reversing\nchanges made to ");
+ refer_to_commit(opts, &ctx->message, parent);
}
- strbuf_addstr(&msgbuf, ".\n");
+ strbuf_addstr(&ctx->message, ".\n");
} else {
const char *p;
@@ -2291,21 +2373,22 @@ static int do_pick_commit(struct repository *r,
next = commit;
next_label = msg.label;
- /* Append the commit log message to msgbuf. */
+ /* Append the commit log message to ctx->message. */
if (find_commit_subject(msg.message, &p))
- strbuf_addstr(&msgbuf, p);
+ strbuf_addstr(&ctx->message, p);
if (opts->record_origin) {
- strbuf_complete_line(&msgbuf);
- if (!has_conforming_footer(&msgbuf, NULL, 0))
- strbuf_addch(&msgbuf, '\n');
- strbuf_addstr(&msgbuf, cherry_picked_prefix);
- strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
- strbuf_addstr(&msgbuf, ")\n");
+ strbuf_complete_line(&ctx->message);
+ if (!has_conforming_footer(&ctx->message, NULL, 0))
+ strbuf_addch(&ctx->message, '\n');
+ strbuf_addstr(&ctx->message, cherry_picked_prefix);
+ strbuf_addstr(&ctx->message, oid_to_hex(&commit->object.oid));
+ strbuf_addstr(&ctx->message, ")\n");
}
if (!is_fixup(command))
author = get_author(msg.message);
}
+ ctx->have_message = 1;
if (command == TODO_REWORD)
reword = 1;
@@ -2336,7 +2419,7 @@ static int do_pick_commit(struct repository *r,
}
if (opts->signoff && !is_fixup(command))
- append_signoff(&msgbuf, 0, 0);
+ append_signoff(&ctx->message, 0, 0);
if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
res = -1;
@@ -2345,17 +2428,17 @@ static int do_pick_commit(struct repository *r,
!strcmp(opts->strategy, "ort") ||
command == TODO_REVERT) {
res = do_recursive_merge(r, base, next, base_label, next_label,
- &head, &msgbuf, opts);
+ &head, &ctx->message, opts);
if (res < 0)
goto leave;
- res |= write_message(msgbuf.buf, msgbuf.len,
+ res |= write_message(ctx->message.buf, ctx->message.len,
git_path_merge_msg(r), 0);
} else {
struct commit_list *common = NULL;
struct commit_list *remotes = NULL;
- res = write_message(msgbuf.buf, msgbuf.len,
+ res = write_message(ctx->message.buf, ctx->message.len,
git_path_merge_msg(r), 0);
commit_list_insert(base, &common);
@@ -2376,19 +2459,19 @@ static int do_pick_commit(struct repository *r,
if ((command == TODO_PICK || command == TODO_REWORD ||
command == TODO_EDIT) && !opts->no_commit &&
(res == 0 || res == 1) &&
- update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
- REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
+ refs_update_ref(get_main_ref_store(the_repository), NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
res = -1;
if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
- update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL,
- REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
+ refs_update_ref(get_main_ref_store(the_repository), NULL, "REVERT_HEAD", &commit->object.oid, NULL,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
res = -1;
if (res) {
error(command == TODO_REVERT
? _("could not revert %s... %s")
: _("could not apply %s... %s"),
- short_commit_name(commit), msg.subject);
+ short_commit_name(r, commit), msg.subject);
print_advice(r, res == 1, opts);
repo_rerere(r, opts->allow_rerere_auto);
goto leave;
@@ -2404,9 +2487,10 @@ static int do_pick_commit(struct repository *r,
} else if (allow == 2) {
drop_commit = 1;
refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
- NULL, 0);
+ NULL, REF_NO_DEREF);
unlink(git_path_merge_msg(r));
- unlink(git_path_auto_merge(r));
+ refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
+ NULL, REF_NO_DEREF);
fprintf(stderr,
_("dropping %s %s -- patch contents already upstream\n"),
oid_to_hex(&commit->object.oid), msg.subject);
@@ -2432,14 +2516,13 @@ fast_forward_edit:
unlink(rebase_path_fixup_msg());
unlink(rebase_path_squash_msg());
unlink(rebase_path_current_fixups());
- strbuf_reset(&opts->current_fixups);
- opts->current_fixup_count = 0;
+ strbuf_reset(&ctx->current_fixups);
+ ctx->current_fixup_count = 0;
}
leave:
free_message(commit, &msg);
free(author);
- strbuf_release(&msgbuf);
update_abort_safety_file();
return res;
@@ -2547,8 +2630,63 @@ static int check_label_or_ref_arg(enum todo_command command, const char *arg)
return 0;
}
-static int parse_insn_line(struct repository *r, struct todo_item *item,
- const char *buf, const char *bol, char *eol)
+static int check_merge_commit_insn(enum todo_command command)
+{
+ switch(command) {
+ case TODO_PICK:
+ error(_("'%s' does not accept merge commits"),
+ todo_command_info[command].str);
+ advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _(
+ /*
+ * TRANSLATORS: 'pick' and 'merge -C' should not be
+ * translated.
+ */
+ "'pick' does not take a merge commit. If you wanted to\n"
+ "replay the merge, use 'merge -C' on the commit."));
+ return -1;
+
+ case TODO_REWORD:
+ error(_("'%s' does not accept merge commits"),
+ todo_command_info[command].str);
+ advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _(
+ /*
+ * TRANSLATORS: 'reword' and 'merge -c' should not be
+ * translated.
+ */
+ "'reword' does not take a merge commit. If you wanted to\n"
+ "replay the merge and reword the commit message, use\n"
+ "'merge -c' on the commit"));
+ return -1;
+
+ case TODO_EDIT:
+ error(_("'%s' does not accept merge commits"),
+ todo_command_info[command].str);
+ advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _(
+ /*
+ * TRANSLATORS: 'edit', 'merge -C' and 'break' should
+ * not be translated.
+ */
+ "'edit' does not take a merge commit. If you wanted to\n"
+ "replay the merge, use 'merge -C' on the commit, and then\n"
+ "'break' to give the control back to you so that you can\n"
+ "do 'git commit --amend && git rebase --continue'."));
+ return -1;
+
+ case TODO_FIXUP:
+ case TODO_SQUASH:
+ return error(_("cannot squash merge commit into another commit"));
+
+ case TODO_MERGE:
+ return 0;
+
+ default:
+ BUG("unexpected todo_command");
+ }
+}
+
+static int parse_insn_line(struct repository *r, struct replay_opts *opts,
+ struct todo_item *item, const char *buf,
+ const char *bol, char *eol)
{
struct object_id commit_oid;
char *end_of_object_name;
@@ -2559,7 +2697,7 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
/* left-trim */
bol += strspn(bol, " \t");
- if (bol == eol || *bol == '\r' || *bol == comment_line_char) {
+ if (bol == eol || *bol == '\r' || starts_with_mem(bol, eol - bol, comment_line_str)) {
item->command = TODO_COMMENT;
item->commit = NULL;
item->arg_offset = bol - buf;
@@ -2652,10 +2790,15 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
return status;
item->commit = lookup_commit_reference(r, &commit_oid);
- return item->commit ? 0 : -1;
+ if (!item->commit)
+ return -1;
+ if (is_rebase_i(opts) &&
+ item->commit->parents && item->commit->parents->next)
+ return check_merge_commit_insn(item->command);
+ return 0;
}
-int sequencer_get_last_command(struct repository *r, enum replay_action *action)
+int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action *action)
{
const char *todo_file, *bol;
struct strbuf buf = STRBUF_INIT;
@@ -2682,8 +2825,8 @@ int sequencer_get_last_command(struct repository *r, enum replay_action *action)
return ret;
}
-int todo_list_parse_insn_buffer(struct repository *r, char *buf,
- struct todo_list *todo_list)
+int todo_list_parse_insn_buffer(struct repository *r, struct replay_opts *opts,
+ char *buf, struct todo_list *todo_list)
{
struct todo_item *item;
char *p = buf, *next_p;
@@ -2701,7 +2844,7 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf,
item = append_new_todo(todo_list);
item->offset_in_buf = p - todo_list->buf.buf;
- if (parse_insn_line(r, item, buf, p, eol)) {
+ if (parse_insn_line(r, opts, item, buf, p, eol)) {
res = error(_("invalid line %d: %.*s"),
i, (int)(eol - p), p);
item->command = TODO_COMMENT + 1;
@@ -2800,7 +2943,7 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose)
if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
if (!refs_delete_ref(get_main_ref_store(r), "",
- "CHERRY_PICK_HEAD", NULL, 0) &&
+ "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF) &&
verbose)
warning(_("cancelling a cherry picking in progress"));
opts.action = REPLAY_PICK;
@@ -2809,22 +2952,25 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose)
if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
if (!refs_delete_ref(get_main_ref_store(r), "", "REVERT_HEAD",
- NULL, 0) &&
+ NULL, REF_NO_DEREF) &&
verbose)
warning(_("cancelling a revert in progress"));
opts.action = REPLAY_REVERT;
need_cleanup = 1;
}
- unlink(git_path_auto_merge(r));
+ refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
+ NULL, REF_NO_DEREF);
if (!need_cleanup)
- return;
+ goto out;
if (!have_finished_the_last_pick())
- return;
+ goto out;
sequencer_remove_state(&opts);
+out:
+ replay_opts_release(&opts);
}
static void todo_list_write_total_nr(struct todo_list *todo_list)
@@ -2848,7 +2994,7 @@ static int read_populate_todo(struct repository *r,
if (strbuf_read_file_or_whine(&todo_list->buf, todo_file) < 0)
return -1;
- res = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list);
+ res = todo_list_parse_insn_buffer(r, opts, todo_list->buf.buf, todo_list);
if (res) {
if (is_rebase_i(opts))
return error(_("please fix this using "
@@ -2878,7 +3024,7 @@ static int read_populate_todo(struct repository *r,
struct todo_list done = TODO_LIST_INIT;
if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
- !todo_list_parse_insn_buffer(r, done.buf.buf, &done))
+ !todo_list_parse_insn_buffer(r, opts, done.buf.buf, &done))
todo_list->done_nr = count_commands(&done);
else
todo_list->done_nr = 0;
@@ -2922,6 +3068,9 @@ static int populate_opts_cb(const char *key, const char *value,
else if (!strcmp(key, "options.allow-empty-message"))
opts->allow_empty_message =
git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
+ else if (!strcmp(key, "options.drop-redundant-commits"))
+ opts->drop_redundant_commits =
+ 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, ctx->kvi, &error_flag);
@@ -2992,6 +3141,8 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
static int read_populate_opts(struct replay_opts *opts)
{
+ struct replay_ctx *ctx = opts->ctx;
+
if (is_rebase_i(opts)) {
struct strbuf buf = STRBUF_INIT;
int ret = 0;
@@ -3051,13 +3202,13 @@ static int read_populate_opts(struct replay_opts *opts)
read_strategy_opts(opts, &buf);
strbuf_reset(&buf);
- if (read_oneliner(&opts->current_fixups,
+ if (read_oneliner(&ctx->current_fixups,
rebase_path_current_fixups(),
READ_ONELINER_SKIP_IF_EMPTY)) {
- const char *p = opts->current_fixups.buf;
- opts->current_fixup_count = 1;
+ const char *p = ctx->current_fixups.buf;
+ ctx->current_fixup_count = 1;
while ((p = strchr(p, '\n'))) {
- opts->current_fixup_count++;
+ ctx->current_fixup_count++;
p++;
}
}
@@ -3177,7 +3328,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
item->offset_in_buf = todo_list->buf.len;
subject_len = find_commit_subject(commit_buffer, &subject);
strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string,
- short_commit_name(commit), subject_len, subject);
+ short_commit_name(the_repository, commit),
+ subject_len, subject);
repo_unuse_commit_buffer(the_repository, commit,
commit_buffer);
}
@@ -3246,12 +3398,12 @@ static int rollback_is_safe(void)
strbuf_release(&sb);
}
else if (errno == ENOENT)
- oidclr(&expected_head);
+ oidclr(&expected_head, the_repository->hash_algo);
else
die_errno(_("could not read '%s'"), git_path_abort_safety_file());
if (repo_get_oid(the_repository, "HEAD", &actual_head))
- oidclr(&actual_head);
+ oidclr(&actual_head, the_repository->hash_algo);
return oideq(&actual_head, &expected_head);
}
@@ -3276,7 +3428,7 @@ static int rollback_single_pick(struct repository *r)
if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
!refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
return error(_("no cherry-pick or revert in progress"));
- if (read_ref_full("HEAD", 0, &head_oid, NULL))
+ if (refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0, &head_oid, NULL))
return error(_("cannot resolve HEAD"));
if (is_null_oid(&head_oid))
return error(_("cannot abort from a branch yet to be born"));
@@ -3287,7 +3439,7 @@ static int skip_single_pick(void)
{
struct object_id head;
- if (read_ref_full("HEAD", 0, &head, NULL))
+ if (refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0, &head, NULL))
return error(_("cannot resolve HEAD"));
return reset_merge(&head);
}
@@ -3455,54 +3607,57 @@ static int save_opts(struct replay_opts *opts)
if (opts->no_commit)
res |= git_config_set_in_file_gently(opts_file,
- "options.no-commit", "true");
+ "options.no-commit", NULL, "true");
if (opts->edit >= 0)
- res |= git_config_set_in_file_gently(opts_file, "options.edit",
+ res |= git_config_set_in_file_gently(opts_file, "options.edit", NULL,
opts->edit ? "true" : "false");
if (opts->allow_empty)
res |= git_config_set_in_file_gently(opts_file,
- "options.allow-empty", "true");
+ "options.allow-empty", NULL, "true");
if (opts->allow_empty_message)
res |= git_config_set_in_file_gently(opts_file,
- "options.allow-empty-message", "true");
+ "options.allow-empty-message", NULL, "true");
+ if (opts->drop_redundant_commits)
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.drop-redundant-commits", NULL, "true");
if (opts->keep_redundant_commits)
res |= git_config_set_in_file_gently(opts_file,
- "options.keep-redundant-commits", "true");
+ "options.keep-redundant-commits", NULL, "true");
if (opts->signoff)
res |= git_config_set_in_file_gently(opts_file,
- "options.signoff", "true");
+ "options.signoff", NULL, "true");
if (opts->record_origin)
res |= git_config_set_in_file_gently(opts_file,
- "options.record-origin", "true");
+ "options.record-origin", NULL, "true");
if (opts->allow_ff)
res |= git_config_set_in_file_gently(opts_file,
- "options.allow-ff", "true");
+ "options.allow-ff", NULL, "true");
if (opts->mainline) {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%d", opts->mainline);
res |= git_config_set_in_file_gently(opts_file,
- "options.mainline", buf.buf);
+ "options.mainline", NULL, buf.buf);
strbuf_release(&buf);
}
if (opts->strategy)
res |= git_config_set_in_file_gently(opts_file,
- "options.strategy", opts->strategy);
+ "options.strategy", NULL, opts->strategy);
if (opts->gpg_sign)
res |= git_config_set_in_file_gently(opts_file,
- "options.gpg-sign", opts->gpg_sign);
+ "options.gpg-sign", NULL, opts->gpg_sign);
for (size_t i = 0; i < opts->xopts.nr; i++)
res |= git_config_set_multivar_in_file_gently(opts_file,
"options.strategy-option",
- opts->xopts.v[i], "^$", 0);
+ opts->xopts.v[i], "^$", NULL, 0);
if (opts->allow_rerere_auto)
res |= git_config_set_in_file_gently(opts_file,
- "options.allow-rerere-auto",
+ "options.allow-rerere-auto", NULL,
opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
"true" : "false");
if (opts->explicit_cleanup)
res |= git_config_set_in_file_gently(opts_file,
- "options.default-msg-cleanup",
+ "options.default-msg-cleanup", NULL,
describe_cleanup_mode(opts->default_msg_cleanup));
return res;
}
@@ -3574,13 +3729,24 @@ static int error_with_patch(struct repository *r,
struct replay_opts *opts,
int exit_code, int to_amend)
{
- if (commit) {
- if (make_patch(r, commit, opts))
+ struct replay_ctx *ctx = opts->ctx;
+
+ /*
+ * Write the commit message to be used by "git rebase
+ * --continue". If a "fixup" or "squash" command has conflicts
+ * then we will have already written rebase_path_message() in
+ * error_failed_squash(). If an "edit" command was
+ * fast-forwarded then we don't have a message in ctx->message
+ * and rely on make_patch() to write rebase_path_message()
+ * instead.
+ */
+ if (ctx->have_message && !file_exists(rebase_path_message()) &&
+ write_message(ctx->message.buf, ctx->message.len,
+ rebase_path_message(), 0))
+ return error(_("could not write commit message file"));
+
+ if (commit && make_patch(r, commit, opts))
return -1;
- } else if (copy_file(rebase_path_message(),
- git_path_merge_msg(r), 0666))
- return error(_("unable to copy '%s' to '%s'"),
- git_path_merge_msg(r), rebase_path_message());
if (to_amend) {
if (intend_to_amend())
@@ -3598,7 +3764,7 @@ static int error_with_patch(struct repository *r,
} else if (exit_code) {
if (commit)
fprintf_ln(stderr, _("Could not apply %s... %.*s"),
- short_commit_name(commit), subject_len, subject);
+ short_commit_name(r, commit), subject_len, subject);
else
/*
* We don't have the hash of the parent so
@@ -3628,14 +3794,16 @@ static int error_failed_squash(struct repository *r,
return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
}
-static int do_exec(struct repository *r, const char *command_line)
+static int do_exec(struct repository *r, const char *command_line, int quiet)
{
struct child_process cmd = CHILD_PROCESS_INIT;
int dirty, status;
- fprintf(stderr, _("Executing: %s\n"), command_line);
+ if (!quiet)
+ fprintf(stderr, _("Executing: %s\n"), command_line);
cmd.use_shell = 1;
strvec_push(&cmd.args, command_line);
+ strvec_push(&cmd.env, "GIT_CHERRY_PICK_HELP");
status = run_command(&cmd);
/* force re-reading of the cache */
@@ -3722,15 +3890,16 @@ static int do_label(struct repository *r, const char *name, int len)
strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
strbuf_addf(&msg, "rebase (label) '%.*s'", len, name);
- transaction = ref_store_transaction_begin(refs, &err);
+ transaction = ref_store_transaction_begin(refs, 0, &err);
if (!transaction) {
error("%s", err.buf);
ret = -1;
} 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,
- NULL, 0, msg.buf, &err) < 0 ||
+ } else if (ref_transaction_update(transaction, ref_name.buf,
+ &head_oid, NULL, NULL, NULL,
+ 0, msg.buf, &err) < 0 ||
ref_transaction_commit(transaction, &err)) {
error("%s", err.buf);
ret = -1;
@@ -3788,7 +3957,7 @@ static struct commit *lookup_label(struct repository *r, const char *label,
strbuf_reset(buf);
strbuf_addf(buf, "refs/rewritten/%.*s", len, label);
- if (!read_ref(buf->buf, &oid)) {
+ if (!refs_read_ref(get_main_ref_store(the_repository), buf->buf, &oid)) {
commit = lookup_commit_object(r, &oid);
} else {
/* fall back to non-rewritten ref or commit */
@@ -3876,15 +4045,18 @@ static int do_reset(struct repository *r,
}
tree = parse_tree_indirect(&oid);
+ if (!tree)
+ return error(_("unable to read tree (%s)"), oid_to_hex(&oid));
prime_cache_tree(r, r->index, tree);
if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
ret = error(_("could not write index"));
if (!ret)
- ret = update_ref(reflog_message(opts, "reset", "'%.*s'",
- len, name), "HEAD", &oid,
- NULL, 0, UPDATE_REFS_MSG_ON_ERR);
+ ret = refs_update_ref(get_main_ref_store(the_repository), reflog_message(opts, "reset", "'%.*s'",
+ len, name),
+ "HEAD", &oid,
+ NULL, 0, UPDATE_REFS_MSG_ON_ERR);
cleanup:
free((void *)desc.buffer);
if (ret < 0)
@@ -3899,10 +4071,11 @@ static int do_merge(struct repository *r,
const char *arg, int arg_len,
int flags, int *check_todo, struct replay_opts *opts)
{
+ struct replay_ctx *ctx = opts->ctx;
int run_commit_flags = 0;
struct strbuf ref_name = STRBUF_INIT;
struct commit *head_commit, *merge_commit, *i;
- struct commit_list *bases, *j;
+ struct commit_list *bases = NULL, *j;
struct commit_list *to_merge = NULL, **tail = &to_merge;
const char *strategy = !opts->xopts.nr &&
(!opts->strategy ||
@@ -4027,40 +4200,31 @@ static int do_merge(struct repository *r,
write_author_script(message);
find_commit_subject(message, &body);
len = strlen(body);
- ret = write_message(body, len, git_path_merge_msg(r), 0);
+ strbuf_add(&ctx->message, body, len);
repo_unuse_commit_buffer(r, commit, message);
- if (ret) {
- error_errno(_("could not write '%s'"),
- git_path_merge_msg(r));
- goto leave_merge;
- }
} else {
struct strbuf buf = STRBUF_INIT;
- int len;
strbuf_addf(&buf, "author %s", git_author_info(0));
write_author_script(buf.buf);
- strbuf_reset(&buf);
+ strbuf_release(&buf);
if (oneline_offset < arg_len) {
- p = arg + oneline_offset;
- len = arg_len - oneline_offset;
+ strbuf_add(&ctx->message, arg + oneline_offset,
+ arg_len - oneline_offset);
} else {
- strbuf_addf(&buf, "Merge %s '%.*s'",
+ strbuf_addf(&ctx->message, "Merge %s '%.*s'",
to_merge->next ? "branches" : "branch",
merge_arg_len, arg);
- p = buf.buf;
- len = buf.len;
- }
-
- ret = write_message(p, len, git_path_merge_msg(r), 0);
- strbuf_release(&buf);
- if (ret) {
- error_errno(_("could not write '%s'"),
- git_path_merge_msg(r));
- goto leave_merge;
}
}
+ ctx->have_message = 1;
+ if (write_message(ctx->message.buf, ctx->message.len,
+ git_path_merge_msg(r), 0)) {
+ ret = error_errno(_("could not write '%s'"),
+ git_path_merge_msg(r));
+ goto leave_merge;
+ }
if (strategy || to_merge->next) {
/* Octopus merge */
@@ -4113,7 +4277,7 @@ static int do_merge(struct repository *r,
strbuf_release(&ref_name);
refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
- NULL, 0);
+ NULL, REF_NO_DEREF);
rollback_lock_file(&lock);
ret = run_command(&cmd);
@@ -4128,7 +4292,11 @@ static int do_merge(struct repository *r,
}
merge_commit = to_merge->item;
- bases = repo_get_merge_bases(r, head_commit, merge_commit);
+ if (repo_get_merge_bases(r, head_commit, merge_commit, &bases) < 0) {
+ ret = -1;
+ goto leave_merge;
+ }
+
if (bases && oideq(&merge_commit->object.oid,
&bases->item->object.oid)) {
ret = 0;
@@ -4143,7 +4311,7 @@ static int do_merge(struct repository *r,
bases = reverse_commit_list(bases);
repo_read_index(r);
- init_merge_options(&o, r);
+ init_ui_merge_options(&o, r);
o.branch1 = "HEAD";
o.branch2 = ref_name.buf;
o.buffer_output = 2;
@@ -4211,6 +4379,7 @@ leave_merge:
strbuf_release(&ref_name);
rollback_lock_file(&lock);
free_commit_list(to_merge);
+ free_commit_list(bases);
return ret;
}
@@ -4370,7 +4539,7 @@ static int do_update_ref(struct repository *r, const char *refname)
for_each_string_list_item(item, &list) {
if (!strcmp(item->string, refname)) {
struct update_ref_record *rec = item->util;
- if (read_ref("HEAD", &rec->after))
+ if (refs_read_ref(get_main_ref_store(the_repository), "HEAD", &rec->after))
return -1;
break;
}
@@ -4458,12 +4627,17 @@ static enum todo_command peek_command(struct todo_list *todo_list, int offset)
return -1;
}
-void create_autostash(struct repository *r, const char *path)
+static void create_autostash_internal(struct repository *r,
+ const char *path,
+ const char *refname)
{
struct strbuf buf = STRBUF_INIT;
struct lock_file lock_file = LOCK_INIT;
int fd;
+ if (path && refname)
+ BUG("can only pass path or refname");
+
fd = repo_hold_locked_index(r, &lock_file, 0);
refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
@@ -4490,10 +4664,16 @@ void create_autostash(struct repository *r, const char *path)
strbuf_reset(&buf);
strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
- if (safe_create_leading_directories_const(path))
- die(_("Could not create directory for '%s'"),
- path);
- write_file(path, "%s", oid_to_hex(&oid));
+ if (path) {
+ if (safe_create_leading_directories_const(path))
+ die(_("Could not create directory for '%s'"),
+ path);
+ write_file(path, "%s", oid_to_hex(&oid));
+ } else {
+ refs_update_ref(get_main_ref_store(r), "", refname,
+ &oid, null_oid(), 0, UPDATE_REFS_DIE_ON_ERR);
+ }
+
printf(_("Created autostash: %s\n"), buf.buf);
if (reset_head(r, &ropts) < 0)
die(_("could not reset --hard"));
@@ -4504,6 +4684,16 @@ void create_autostash(struct repository *r, const char *path)
strbuf_release(&buf);
}
+void create_autostash(struct repository *r, const char *path)
+{
+ create_autostash_internal(r, path, NULL);
+}
+
+void create_autostash_ref(struct repository *r, const char *refname)
+{
+ create_autostash_internal(r, NULL, refname);
+}
+
static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply)
{
struct child_process child = CHILD_PROCESS_INIT;
@@ -4581,6 +4771,41 @@ int apply_autostash_oid(const char *stash_oid)
return apply_save_autostash_oid(stash_oid, 1);
}
+static int apply_save_autostash_ref(struct repository *r, const char *refname,
+ int attempt_apply)
+{
+ struct object_id stash_oid;
+ char stash_oid_hex[GIT_MAX_HEXSZ + 1];
+ int flag, ret;
+
+ if (!refs_ref_exists(get_main_ref_store(r), refname))
+ return 0;
+
+ if (!refs_resolve_ref_unsafe(get_main_ref_store(r), refname,
+ RESOLVE_REF_READING, &stash_oid, &flag))
+ return -1;
+ if (flag & REF_ISSYMREF)
+ return error(_("autostash reference is a symref"));
+
+ oid_to_hex_r(stash_oid_hex, &stash_oid);
+ ret = apply_save_autostash_oid(stash_oid_hex, attempt_apply);
+
+ refs_delete_ref(get_main_ref_store(r), "", refname,
+ &stash_oid, REF_NO_DEREF);
+
+ return ret;
+}
+
+int save_autostash_ref(struct repository *r, const char *refname)
+{
+ return apply_save_autostash_ref(r, refname, 0);
+}
+
+int apply_autostash_ref(struct repository *r, const char *refname)
+{
+ return apply_save_autostash_ref(r, refname, 1);
+}
+
static int checkout_onto(struct repository *r, struct replay_opts *opts,
const char *onto_name, const struct object_id *onto,
const struct object_id *orig_head)
@@ -4661,11 +4886,12 @@ static int pick_one_commit(struct repository *r,
struct replay_opts *opts,
int *check_todo, int* reschedule)
{
+ struct replay_ctx *ctx = opts->ctx;
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(
+ ctx->reflog_message = reflog_message(
opts, command_to_string(item->command), NULL);
res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
@@ -4681,7 +4907,7 @@ static int pick_one_commit(struct repository *r,
if (!opts->verbose)
term_clear_line();
fprintf(stderr, _("Stopped at %s... %.*s\n"),
- short_commit_name(commit), item->arg_len, arg);
+ short_commit_name(r, commit), item->arg_len, arg);
}
return error_with_patch(r, commit,
arg, item->arg_len, opts, res, !res);
@@ -4722,9 +4948,10 @@ static int pick_commits(struct repository *r,
struct todo_list *todo_list,
struct replay_opts *opts)
{
+ struct replay_ctx *ctx = opts->ctx;
int res = 0, reschedule = 0;
- opts->reflog_message = sequencer_reflog_action(opts);
+ ctx->reflog_message = sequencer_reflog_action(opts);
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || should_edit(opts) ||
@@ -4763,8 +4990,10 @@ static int pick_commits(struct repository *r,
}
unlink(rebase_path_author_script());
unlink(git_path_merge_head(r));
- unlink(git_path_auto_merge(r));
- delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
+ NULL, REF_NO_DEREF);
+ refs_delete_ref(get_main_ref_store(r), "", "REBASE_HEAD",
+ NULL, REF_NO_DEREF);
if (item->command == TODO_BREAK) {
if (!opts->verbose)
@@ -4772,6 +5001,8 @@ static int pick_commits(struct repository *r,
return stopped_at_head(r);
}
}
+ strbuf_reset(&ctx->message);
+ ctx->have_message = 0;
if (item->command <= TODO_SQUASH) {
res = pick_one_commit(r, todo_list, opts, &check_todo,
&reschedule);
@@ -4784,7 +5015,7 @@ static int pick_commits(struct repository *r,
if (!opts->verbose)
term_clear_line();
*end_of_arg = '\0';
- res = do_exec(r, arg);
+ res = do_exec(r, arg, opts->quiet);
*end_of_arg = saved;
if (res) {
@@ -4868,15 +5099,15 @@ cleanup_head_ref:
}
msg = reflog_message(opts, "finish", "%s onto %s",
head_ref.buf, buf.buf);
- if (update_ref(msg, head_ref.buf, &head, &orig,
- REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
+ if (refs_update_ref(get_main_ref_store(the_repository), msg, head_ref.buf, &head, &orig,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
res = error(_("could not update %s"),
head_ref.buf);
goto cleanup_head_ref;
}
msg = reflog_message(opts, "finish", "returning to %s",
head_ref.buf);
- if (create_symref("HEAD", head_ref.buf, msg)) {
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, msg)) {
res = error(_("could not update HEAD to %s"),
head_ref.buf);
goto cleanup_head_ref;
@@ -4920,7 +5151,7 @@ cleanup_head_ref:
hook_opt.path_to_stdin = rebase_path_rewritten_list();
strvec_push(&hook_opt.args, "rebase");
- run_hooks_opt("post-rewrite", &hook_opt);
+ run_hooks_opt(r, "post-rewrite", &hook_opt);
}
apply_autostash(rebase_path_autostash());
@@ -4977,35 +5208,50 @@ static int commit_staged_changes(struct repository *r,
struct replay_opts *opts,
struct todo_list *todo_list)
{
+ struct replay_ctx *ctx = opts->ctx;
unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
unsigned int final_fixup = 0, is_clean;
+ struct strbuf rev = STRBUF_INIT;
+ int ret;
- if (has_unstaged_changes(r, 1))
- return error(_("cannot rebase: You have unstaged changes."));
+ if (has_unstaged_changes(r, 1)) {
+ ret = error(_("cannot rebase: You have unstaged changes."));
+ goto out;
+ }
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);
+ ret = error(_(staged_changes_advice), gpg_opt, gpg_opt);
+ goto out;
}
+
if (file_exists(rebase_path_amend())) {
- struct strbuf rev = STRBUF_INIT;
struct object_id head, to_amend;
- 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());
- if (get_oid_hex(rev.buf, &to_amend))
- return error(_("invalid contents: '%s'"),
- rebase_path_amend());
- if (!is_clean && !oideq(&head, &to_amend))
- return error(_("\nYou have uncommitted changes in your "
- "working tree. Please, commit them\n"
- "first and then run 'git rebase "
- "--continue' again."));
+ if (repo_get_oid(r, "HEAD", &head)) {
+ ret = error(_("cannot amend non-existing commit"));
+ goto out;
+ }
+
+ if (!read_oneliner(&rev, rebase_path_amend(), 0)) {
+ ret = error(_("invalid file: '%s'"), rebase_path_amend());
+ goto out;
+ }
+
+ if (get_oid_hex(rev.buf, &to_amend)) {
+ ret = error(_("invalid contents: '%s'"),
+ rebase_path_amend());
+ goto out;
+ }
+ if (!is_clean && !oideq(&head, &to_amend)) {
+ ret = error(_("\nYou have uncommitted changes in your "
+ "working tree. Please, commit them\n"
+ "first and then run 'git rebase "
+ "--continue' again."));
+ goto out;
+ }
/*
* When skipping a failed fixup/squash, we need to edit the
* commit message, the current fixup list and count, and if it
@@ -5013,7 +5259,7 @@ static int commit_staged_changes(struct repository *r,
* the commit message and if there was a squash, let the user
* edit it.
*/
- if (!is_clean || !opts->current_fixup_count)
+ if (!is_clean || !ctx->current_fixup_count)
; /* this is not the final fixup */
else if (!oideq(&head, &to_amend) ||
!file_exists(rebase_path_stopped_sha())) {
@@ -5022,24 +5268,26 @@ static int commit_staged_changes(struct repository *r,
unlink(rebase_path_fixup_msg());
unlink(rebase_path_squash_msg());
unlink(rebase_path_current_fixups());
- strbuf_reset(&opts->current_fixups);
- opts->current_fixup_count = 0;
+ strbuf_reset(&ctx->current_fixups);
+ ctx->current_fixup_count = 0;
}
} else {
/* we are in a fixup/squash chain */
- const char *p = opts->current_fixups.buf;
- int len = opts->current_fixups.len;
+ const char *p = ctx->current_fixups.buf;
+ int len = ctx->current_fixups.len;
- opts->current_fixup_count--;
+ ctx->current_fixup_count--;
if (!len)
BUG("Incorrect current_fixups:\n%s", p);
while (len && p[len - 1] != '\n')
len--;
- strbuf_setlen(&opts->current_fixups, len);
+ strbuf_setlen(&ctx->current_fixups, len);
if (write_message(p, len, rebase_path_current_fixups(),
- 0) < 0)
- return error(_("could not write file: '%s'"),
- rebase_path_current_fixups());
+ 0) < 0) {
+ ret = error(_("could not write file: '%s'"),
+ rebase_path_current_fixups());
+ goto out;
+ }
/*
* If a fixup/squash in a fixup/squash chain failed, the
@@ -5052,7 +5300,7 @@ static int commit_staged_changes(struct repository *r,
* actually need to re-commit with a cleaned up commit
* message.
*/
- if (opts->current_fixup_count > 0 &&
+ if (ctx->current_fixup_count > 0 &&
!is_fixup(peek_command(todo_list, 0))) {
final_fixup = 1;
/*
@@ -5069,35 +5317,38 @@ 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))
- return error(_("could not parse HEAD"));
+ if (parse_head(r, &commit)) {
+ ret = error(_("could not parse HEAD"));
+ goto out;
+ }
p = repo_logmsg_reencode(r, commit, NULL, encoding);
if (!p) {
- res = error(_("could not parse commit %s"),
+ ret = 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: "
+ ret = error(_("could not write file: "
"'%s'"), path);
goto unuse_commit_buffer;
}
+
+ ret = 0;
+
unuse_commit_buffer:
repo_unuse_commit_buffer(r, commit, p);
- if (res)
- return res;
+ if (ret)
+ goto out;
}
}
- strbuf_release(&rev);
flags |= AMEND_MSG;
}
@@ -5105,39 +5356,57 @@ static int commit_staged_changes(struct repository *r,
if (refs_ref_exists(get_main_ref_store(r),
"CHERRY_PICK_HEAD") &&
refs_delete_ref(get_main_ref_store(r), "",
- "CHERRY_PICK_HEAD", NULL, 0))
- return error(_("could not remove CHERRY_PICK_HEAD"));
- if (unlink(git_path_merge_msg(r)) && errno != ENOENT)
- return error_errno(_("could not remove '%s'"),
- git_path_merge_msg(r));
- if (!final_fixup)
- return 0;
+ "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF)) {
+ ret = error(_("could not remove CHERRY_PICK_HEAD"));
+ goto out;
+ }
+
+ if (unlink(git_path_merge_msg(r)) && errno != ENOENT) {
+ ret = error_errno(_("could not remove '%s'"),
+ git_path_merge_msg(r));
+ goto out;
+ }
+
+ if (!final_fixup) {
+ ret = 0;
+ goto out;
+ }
}
if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
- opts, flags))
- return error(_("could not commit staged changes."));
+ opts, flags)) {
+ ret = error(_("could not commit staged changes."));
+ goto out;
+ }
+
unlink(rebase_path_amend());
unlink(git_path_merge_head(r));
- unlink(git_path_auto_merge(r));
+ refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
+ NULL, REF_NO_DEREF);
if (final_fixup) {
unlink(rebase_path_fixup_msg());
unlink(rebase_path_squash_msg());
}
- if (opts->current_fixup_count > 0) {
+ if (ctx->current_fixup_count > 0) {
/*
* Whether final fixup or not, we just cleaned up the commit
* message...
*/
unlink(rebase_path_current_fixups());
- strbuf_reset(&opts->current_fixups);
- opts->current_fixup_count = 0;
+ strbuf_reset(&ctx->current_fixups);
+ ctx->current_fixup_count = 0;
}
- return 0;
+
+ ret = 0;
+
+out:
+ strbuf_release(&rev);
+ return ret;
}
int sequencer_continue(struct repository *r, struct replay_opts *opts)
{
+ struct replay_ctx *ctx = opts->ctx;
struct todo_list todo_list = TODO_LIST_INIT;
int res;
@@ -5151,13 +5420,14 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
goto release_todo_list;
if (file_exists(rebase_path_dropped())) {
- if ((res = todo_list_check_against_backup(r, &todo_list)))
+ if ((res = todo_list_check_against_backup(r, opts,
+ &todo_list)))
goto release_todo_list;
unlink(rebase_path_dropped());
}
- opts->reflog_message = reflog_message(opts, "continue", NULL);
+ ctx->reflog_message = reflog_message(opts, "continue", NULL);
if (commit_staged_changes(r, opts, &todo_list)) {
res = -1;
goto release_todo_list;
@@ -5209,7 +5479,7 @@ static int single_pick(struct repository *r,
TODO_PICK : TODO_REVERT;
item.commit = cmit;
- opts->reflog_message = sequencer_reflog_action(opts);
+ opts->ctx->reflog_message = sequencer_reflog_action(opts);
return do_pick_commit(r, &item, opts, 0, &check_todo);
}
@@ -5221,8 +5491,10 @@ int sequencer_pick_revisions(struct repository *r,
int i, res;
assert(opts->revs);
- if (read_and_refresh_cache(r, opts))
- return -1;
+ if (read_and_refresh_cache(r, opts)) {
+ res = -1;
+ goto out;
+ }
for (i = 0; i < opts->revs->pending.nr; i++) {
struct object_id oid;
@@ -5237,11 +5509,14 @@ int sequencer_pick_revisions(struct repository *r,
enum object_type type = oid_object_info(r,
&oid,
NULL);
- return error(_("%s: can't cherry-pick a %s"),
- name, type_name(type));
+ res = error(_("%s: can't cherry-pick a %s"),
+ name, type_name(type));
+ goto out;
}
- } else
- return error(_("%s: bad revision"), name);
+ } else {
+ res = error(_("%s: bad revision"), name);
+ goto out;
+ }
}
/*
@@ -5256,14 +5531,23 @@ int sequencer_pick_revisions(struct repository *r,
opts->revs->no_walk &&
!opts->revs->cmdline.rev->flags) {
struct commit *cmit;
- if (prepare_revision_walk(opts->revs))
- return error(_("revision walk setup failed"));
+
+ if (prepare_revision_walk(opts->revs)) {
+ res = error(_("revision walk setup failed"));
+ goto out;
+ }
+
cmit = get_revision(opts->revs);
- if (!cmit)
- return error(_("empty commit set passed"));
+ if (!cmit) {
+ res = error(_("empty commit set passed"));
+ goto out;
+ }
+
if (get_revision(opts->revs))
BUG("unexpected extra commit from walk");
- return single_pick(r, cmit, opts);
+
+ res = single_pick(r, cmit, opts);
+ goto out;
}
/*
@@ -5273,16 +5557,30 @@ int sequencer_pick_revisions(struct repository *r,
*/
if (walk_revs_populate_todo(&todo_list, opts) ||
- create_seq_dir(r) < 0)
- return -1;
- if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
- return error(_("can't revert as initial commit"));
- if (save_head(oid_to_hex(&oid)))
- return -1;
- if (save_opts(opts))
- return -1;
+ create_seq_dir(r) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT)) {
+ res = error(_("can't revert as initial commit"));
+ goto out;
+ }
+
+ if (save_head(oid_to_hex(&oid))) {
+ res = -1;
+ goto out;
+ }
+
+ if (save_opts(opts)) {
+ res = -1;
+ goto out;
+ }
+
update_abort_safety_file();
res = pick_commits(r, &todo_list, opts);
+
+out:
todo_list_release(&todo_list);
return res;
}
@@ -5521,7 +5819,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
int skipped_commit = 0;
struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
- struct strbuf label = STRBUF_INIT;
+ struct strbuf label_from_message = STRBUF_INIT;
struct commit_list *commits = NULL, **tail = &commits, *iter;
struct commit_list *tips = NULL, **tips_tail = &tips;
struct commit *commit;
@@ -5544,6 +5842,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
oidmap_init(&state.commit2label, 0);
hashmap_init(&state.labels, labels_cmp, NULL, 0);
strbuf_init(&state.buf, 32);
+ load_branch_decorations();
if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {
struct labels_entry *onto_label_entry;
@@ -5576,7 +5875,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
if (!is_empty && (commit->object.flags & PATCHSAME)) {
if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
warning(_("skipped previously applied commit %s"),
- short_commit_name(commit));
+ short_commit_name(the_repository, commit));
skipped_commit = 1;
continue;
}
@@ -5594,8 +5893,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
oid_to_hex(&commit->object.oid),
oneline.buf);
if (is_empty)
- strbuf_addf(&buf, " %c empty",
- comment_line_char);
+ strbuf_addf(&buf, " %s empty",
+ comment_line_str);
FLEX_ALLOC_STR(entry, string, buf.buf);
oidcpy(&entry->entry.oid, &commit->object.oid);
@@ -5604,18 +5903,18 @@ static int make_script_with_merges(struct pretty_print_context *pp,
continue;
}
- /* Create a label */
- strbuf_reset(&label);
+ /* Create a label from the commit message */
+ strbuf_reset(&label_from_message);
if (skip_prefix(oneline.buf, "Merge ", &p1) &&
(p1 = strchr(p1, '\'')) &&
(p2 = strchr(++p1, '\'')))
- strbuf_add(&label, p1, p2 - p1);
+ strbuf_add(&label_from_message, p1, p2 - p1);
else if (skip_prefix(oneline.buf, "Merge pull request ",
&p1) &&
(p1 = strstr(p1, " from ")))
- strbuf_addstr(&label, p1 + strlen(" from "));
+ strbuf_addstr(&label_from_message, p1 + strlen(" from "));
else
- strbuf_addbuf(&label, &oneline);
+ strbuf_addbuf(&label_from_message, &oneline);
strbuf_reset(&buf);
strbuf_addf(&buf, "%s -C %s",
@@ -5623,6 +5922,14 @@ static int make_script_with_merges(struct pretty_print_context *pp,
/* label the tips of merged branches */
for (; to_merge; to_merge = to_merge->next) {
+ const char *label = label_from_message.buf;
+ const struct name_decoration *decoration =
+ get_name_decoration(&to_merge->item->object);
+
+ if (decoration)
+ skip_prefix(decoration->name, "refs/heads/",
+ &label);
+
oid = &to_merge->item->object.oid;
strbuf_addch(&buf, ' ');
@@ -5635,7 +5942,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
tips_tail = &commit_list_insert(to_merge->item,
tips_tail)->next;
- strbuf_addstr(&buf, label_oid(oid, label.buf, &state));
+ strbuf_addstr(&buf, label_oid(oid, label, &state));
}
strbuf_addf(&buf, " # %s", oneline.buf);
@@ -5685,7 +5992,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
entry = oidmap_get(&state.commit2label, &commit->object.oid);
if (entry)
- strbuf_addf(out, "\n%c Branch %s\n", comment_line_char, entry->string);
+ strbuf_addf(out, "\n%s Branch %s\n", comment_line_str, entry->string);
else
strbuf_addch(out, '\n');
@@ -5743,10 +6050,13 @@ static int make_script_with_merges(struct pretty_print_context *pp,
free_commit_list(commits);
free_commit_list(tips);
- strbuf_release(&label);
+ strbuf_release(&label_from_message);
strbuf_release(&oneline);
strbuf_release(&buf);
+ oidset_clear(&interesting);
+ oidset_clear(&child_seen);
+ oidset_clear(&shown);
oidmap_free(&commit2todo, 1);
oidmap_free(&state.commit2label, 1);
hashmap_clear_and_free(&state.labels, struct labels_entry, entry);
@@ -5812,7 +6122,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
if (!is_empty && (commit->object.flags & PATCHSAME)) {
if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
warning(_("skipped previously applied commit %s"),
- short_commit_name(commit));
+ short_commit_name(r, commit));
skipped_commit = 1;
continue;
}
@@ -5822,7 +6132,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
oid_to_hex(&commit->object.oid));
pretty_print_commit(&pp, commit, out);
if (is_empty)
- strbuf_addf(out, " %c empty", comment_line_char);
+ strbuf_addf(out, " %s empty", comment_line_str);
strbuf_addch(out, '\n');
}
if (skipped_commit)
@@ -5904,7 +6214,8 @@ static void todo_list_add_exec_commands(struct todo_list *todo_list,
todo_list->alloc = alloc;
}
-static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_list,
+static void todo_list_to_strbuf(struct repository *r,
+ struct todo_list *todo_list,
struct strbuf *buf, int num, unsigned flags)
{
struct todo_item *item;
@@ -5933,7 +6244,7 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis
/* add commit id */
if (item->commit) {
const char *oid = flags & TODO_LIST_SHORTEN_IDS ?
- short_commit_name(item->commit) :
+ short_commit_name(r, item->commit) :
oid_to_hex(&item->commit->object.oid);
if (item->command == TODO_FIXUP) {
@@ -6042,10 +6353,11 @@ static int add_decorations_to_list(const struct commit *commit,
struct todo_add_branch_context *ctx)
{
const struct name_decoration *decoration = get_name_decoration(&commit->object);
- const char *head_ref = resolve_ref_unsafe("HEAD",
- RESOLVE_REF_READING,
- NULL,
- NULL);
+ const char *head_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD",
+ RESOLVE_REF_READING,
+ NULL,
+ NULL);
while (decoration) {
struct todo_item *item;
@@ -6100,14 +6412,6 @@ static int add_decorations_to_list(const struct commit *commit,
static int todo_list_add_update_ref_commands(struct todo_list *todo_list)
{
int i, res;
- static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
- static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
- static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
- struct decoration_filter decoration_filter = {
- .include_ref_pattern = &decorate_refs_include,
- .exclude_ref_pattern = &decorate_refs_exclude,
- .exclude_ref_config_pattern = &decorate_refs_exclude_config,
- };
struct todo_add_branch_context ctx = {
.buf = &todo_list->buf,
.refs_to_oids = STRING_LIST_INIT_DUP,
@@ -6116,8 +6420,7 @@ static int todo_list_add_update_ref_commands(struct todo_list *todo_list)
ctx.items_alloc = 2 * todo_list->nr + 1;
ALLOC_ARRAY(ctx.items, ctx.items_alloc);
- string_list_append(&decorate_refs_include, "refs/heads/");
- load_ref_decorations(&decoration_filter, 0);
+ load_branch_decorations();
for (i = 0; i < todo_list->nr; ) {
struct todo_item *item = &todo_list->items[i];
@@ -6193,7 +6496,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
return error(_("nothing to do"));
}
- res = edit_todo_list(r, todo_list, &new_todo, shortrevisions,
+ res = edit_todo_list(r, opts, todo_list, &new_todo, shortrevisions,
shortonto, flags);
if (res == -1)
return -1;
@@ -6221,7 +6524,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
strbuf_release(&buf2);
/* 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)
+ if (todo_list_parse_insn_buffer(r, opts, new_todo.buf.buf, &new_todo) < 0)
BUG("invalid todo list after expanding IDs:\n%s",
new_todo.buf.buf);
@@ -6292,7 +6595,7 @@ static int skip_fixupish(const char *subject, const char **p) {
int todo_list_rearrange_squash(struct todo_list *todo_list)
{
struct hashmap subject2item;
- int rearranged = 0, *next, *tail, i, nr = 0, alloc = 0;
+ int rearranged = 0, *next, *tail, i, nr = 0;
char **subjects;
struct commit_todo_item commit_todo;
struct todo_item *items = NULL;
@@ -6404,6 +6707,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
}
if (rearranged) {
+ ALLOC_ARRAY(items, todo_list->nr);
+
for (i = 0; i < todo_list->nr; i++) {
enum todo_command command = todo_list->items[i].command;
int cur = i;
@@ -6416,16 +6721,15 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
continue;
while (cur >= 0) {
- ALLOC_GROW(items, nr + 1, alloc);
items[nr++] = todo_list->items[cur];
cur = next[cur];
}
}
+ assert(nr == todo_list->nr);
+ todo_list->alloc = nr;
FREE_AND_NULL(todo_list->items);
todo_list->items = items;
- todo_list->nr = nr;
- todo_list->alloc = alloc;
}
free(next);
diff --git a/sequencer.h b/sequencer.h
index 913a0f652d..304ba4b4d3 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -14,6 +14,8 @@ const char *rebase_path_todo(void);
const char *rebase_path_todo_backup(void);
const char *rebase_path_dropped(void);
+extern const char *rebase_resolvemsg;
+
#define APPEND_SIGNOFF_DEDUP (1u << 0)
enum replay_action {
@@ -29,6 +31,9 @@ enum commit_msg_cleanup_mode {
COMMIT_MSG_CLEANUP_ALL
};
+struct replay_ctx;
+struct replay_ctx* replay_ctx_new(void);
+
struct replay_opts {
enum replay_action action;
@@ -66,10 +71,6 @@ struct replay_opts {
/* Reflog */
char *reflog_action;
- /* Used by fixup/squash */
- struct strbuf current_fixups;
- int current_fixup_count;
-
/* placeholder commit for -i --root */
struct object_id squash_onto;
int have_squash_onto;
@@ -78,13 +79,13 @@ struct replay_opts {
struct rev_info *revs;
/* Private use */
- const char *reflog_message;
+ struct replay_ctx *ctx;
};
#define REPLAY_OPTS_INIT { \
.edit = -1, \
.action = -1, \
- .current_fixups = STRBUF_INIT, \
.xopts = STRVEC_INIT, \
+ .ctx = replay_ctx_new(), \
}
/*
@@ -135,8 +136,8 @@ struct todo_list {
.buf = STRBUF_INIT, \
}
-int todo_list_parse_insn_buffer(struct repository *r, char *buf,
- struct todo_list *todo_list);
+int todo_list_parse_insn_buffer(struct repository *r, struct replay_opts *opts,
+ char *buf, struct todo_list *todo_list);
int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list,
const char *file, const char *shortrevisions,
const char *shortonto, int num, unsigned flags);
@@ -225,9 +226,12 @@ void commit_post_rewrite(struct repository *r,
const struct object_id *new_head);
void create_autostash(struct repository *r, const char *path);
+void create_autostash_ref(struct repository *r, const char *refname);
int save_autostash(const char *path);
+int save_autostash_ref(struct repository *r, const char *refname);
int apply_autostash(const char *path);
int apply_autostash_oid(const char *stash_oid);
+int apply_autostash_ref(struct repository *r, const char *refname);
#define SUMMARY_INITIAL_COMMIT (1 << 0)
#define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
diff --git a/serve.c b/serve.c
index a1d71134d4..d674764a25 100644
--- a/serve.c
+++ b/serve.c
@@ -1,7 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "repository.h"
#include "config.h"
-#include "hash-ll.h"
+#include "hash.h"
#include "pkt-line.h"
#include "version.h"
#include "ls-refs.h"
@@ -12,6 +14,7 @@
#include "trace2.h"
static int advertise_sid = -1;
+static int advertise_object_info = -1;
static int client_hash_algo = GIT_HASH_SHA1;
static int always_advertise(struct repository *r UNUSED,
@@ -67,6 +70,17 @@ static void session_id_receive(struct repository *r UNUSED,
trace2_data_string("transfer", NULL, "client-sid", client_sid);
}
+static int object_info_advertise(struct repository *r, struct strbuf *value UNUSED)
+{
+ if (advertise_object_info == -1 &&
+ repo_config_get_bool(r, "transfer.advertiseobjectinfo",
+ &advertise_object_info)) {
+ /* disabled by default */
+ advertise_object_info = 0;
+ }
+ return advertise_object_info;
+}
+
struct protocol_capability {
/*
* The name of the capability. The server uses this name when
@@ -135,7 +149,7 @@ static struct protocol_capability capabilities[] = {
},
{
.name = "object-info",
- .advertise = always_advertise,
+ .advertise = object_info_advertise,
.command = cap_object_info,
},
{
@@ -309,7 +323,7 @@ static int process_request(void)
die("no command requested");
if (client_hash_algo != hash_algo_by_ptr(the_repository->hash_algo))
- die("mismatched object format: server %s; client %s\n",
+ die("mismatched object format: server %s; client %s",
the_repository->hash_algo->name,
hash_algos[client_hash_algo].name);
diff --git a/server-info.c b/server-info.c
index e2fe0f9143..c5af4cd98a 100644
--- a/server-info.c
+++ b/server-info.c
@@ -1,6 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "dir.h"
-#include "environment.h"
#include "hex.h"
#include "repository.h"
#include "refs.h"
@@ -13,6 +14,7 @@
#include "object-store-ll.h"
#include "server-info.h"
#include "strbuf.h"
+#include "tempfile.h"
struct update_info_ctx {
FILE *cur_fp;
@@ -75,9 +77,8 @@ static int update_info_file(char *path,
int force)
{
char *tmp = mkpathdup("%s_XXXXXX", path);
+ struct tempfile *f = NULL;
int ret = -1;
- int fd = -1;
- FILE *to_close;
struct update_info_ctx uic = {
.cur_fp = NULL,
.old_fp = NULL,
@@ -86,13 +87,12 @@ static int update_info_file(char *path,
};
safe_create_leading_directories(path);
- fd = git_mkstemp_mode(tmp, 0666);
- if (fd < 0)
+ f = mks_tempfile_m(tmp, 0666);
+ if (!f)
goto out;
- to_close = uic.cur_fp = fdopen(fd, "w");
+ uic.cur_fp = fdopen_tempfile(f, "w");
if (!uic.cur_fp)
goto out;
- fd = -1;
/* no problem on ENOENT and old_fp == NULL, it's stale, now */
if (!force)
@@ -121,27 +121,22 @@ static int update_info_file(char *path,
}
uic.cur_fp = NULL;
- if (fclose(to_close))
- goto out;
if (uic_is_stale(&uic)) {
- if (adjust_shared_perm(tmp) < 0)
+ if (adjust_shared_perm(get_tempfile_path(f)) < 0)
goto out;
- if (rename(tmp, path) < 0)
+ if (rename_tempfile(&f, path) < 0)
goto out;
} else {
- unlink(tmp);
+ delete_tempfile(&f);
}
ret = 0;
out:
if (ret) {
error_errno("unable to update %s", path);
- if (uic.cur_fp)
- fclose(uic.cur_fp);
- else if (fd >= 0)
- close(fd);
- unlink(tmp);
+ if (f)
+ delete_tempfile(&f);
}
free(tmp);
if (uic.old_fp)
@@ -151,7 +146,7 @@ out:
return ret;
}
-static int add_info_ref(const char *path, const struct object_id *oid,
+static int add_info_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -175,7 +170,8 @@ static int add_info_ref(const char *path, const struct object_id *oid,
static int generate_info_refs(struct update_info_ctx *uic)
{
- return for_each_ref(add_info_ref, uic);
+ return refs_for_each_ref(get_main_ref_store(the_repository),
+ add_info_ref, uic);
}
static int update_info_refs(int force)
@@ -345,7 +341,8 @@ static int write_pack_info_file(struct update_info_ctx *uic)
static int update_info_packs(int force)
{
- char *infofile = mkpathdup("%s/info/packs", get_object_directory());
+ char *infofile = mkpathdup("%s/info/packs",
+ repo_get_object_directory(the_repository));
int ret;
init_pack_info(infofile, force);
diff --git a/setup.c b/setup.c
index 881935f095..7b648de027 100644
--- a/setup.c
+++ b/setup.c
@@ -1,20 +1,28 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "copy.h"
#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
#include "object-name.h"
#include "refs.h"
+#include "replace-object.h"
#include "repository.h"
#include "config.h"
#include "dir.h"
#include "setup.h"
+#include "shallow.h"
#include "string-list.h"
+#include "strvec.h"
#include "chdir-notify.h"
#include "path.h"
-#include "promisor-remote.h"
#include "quote.h"
+#include "tmp-objdir.h"
+#include "trace.h"
#include "trace2.h"
#include "worktree.h"
#include "exec-cmd.h"
@@ -49,7 +57,7 @@ static int abspath_part_inside_repo(char *path)
size_t wtlen;
char *path0;
int off;
- const char *work_tree = get_git_work_tree();
+ const char *work_tree = precompose_string_if_needed(repo_get_work_tree(the_repository));
struct strbuf realpath = STRBUF_INIT;
if (!work_tree)
@@ -145,9 +153,9 @@ char *prefix_path(const char *prefix, int len, const char *path)
{
char *r = prefix_path_gently(prefix, len, NULL, path);
if (!r) {
- const char *hint_path = get_git_work_tree();
+ const char *hint_path = repo_get_work_tree(the_repository);
if (!hint_path)
- hint_path = get_git_dir();
+ hint_path = repo_get_git_dir(the_repository);
die(_("'%s' is outside repository at '%s'"), path,
absolute_path(hint_path));
}
@@ -343,6 +351,58 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)
return ret;
}
+static int validate_headref(const char *path)
+{
+ struct stat st;
+ char buffer[256];
+ const char *refname;
+ struct object_id oid;
+ int fd;
+ ssize_t len;
+
+ if (lstat(path, &st) < 0)
+ return -1;
+
+ /* Make sure it is a "refs/.." symlink */
+ if (S_ISLNK(st.st_mode)) {
+ len = readlink(path, buffer, sizeof(buffer)-1);
+ if (len >= 5 && !memcmp("refs/", buffer, 5))
+ return 0;
+ return -1;
+ }
+
+ /*
+ * Anything else, just open it and try to see if it is a symbolic ref.
+ */
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ len = read_in_full(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+
+ if (len < 0)
+ return -1;
+ buffer[len] = '\0';
+
+ /*
+ * Is it a symbolic ref?
+ */
+ if (skip_prefix(buffer, "ref:", &refname)) {
+ while (isspace(*refname))
+ refname++;
+ if (starts_with(refname, "refs/"))
+ return 0;
+ }
+
+ /*
+ * Is this a detached HEAD?
+ */
+ if (get_oid_hex_any(buffer, &oid) != GIT_HASH_UNKNOWN)
+ return 0;
+
+ return -1;
+}
+
/*
* Test if it looks like we're at a git directory.
* We want to see:
@@ -414,14 +474,14 @@ int is_nonbare_repository_dir(struct strbuf *path)
int is_inside_git_dir(void)
{
if (inside_git_dir < 0)
- inside_git_dir = is_inside_dir(get_git_dir());
+ inside_git_dir = is_inside_dir(repo_get_git_dir(the_repository));
return inside_git_dir;
}
int is_inside_work_tree(void)
{
if (inside_work_tree < 0)
- inside_work_tree = is_inside_dir(get_git_work_tree());
+ inside_work_tree = is_inside_dir(repo_get_work_tree(the_repository));
return inside_work_tree;
}
@@ -436,7 +496,7 @@ void setup_work_tree(void)
if (work_tree_config_is_bogus)
die(_("unable to set up work tree using invalid config"));
- work_tree = get_git_work_tree();
+ work_tree = repo_get_work_tree(the_repository);
if (!work_tree || chdir_notify(work_tree))
die(_("this operation must be run in a work tree"));
@@ -464,7 +524,7 @@ static void setup_original_cwd(void)
* directory we inherited from our parent process, which is a
* directory we want to avoid removing.
*
- * For convience, we would like to have the path relative to the
+ * For convenience, we would like to have the path relative to the
* worktree instead of an absolute path.
*
* Yes, startup_info->original_cwd is usually the same as 'prefix',
@@ -493,7 +553,7 @@ static void setup_original_cwd(void)
* Get our worktree; we only protect the current working directory
* if it's in the worktree.
*/
- worktree = get_git_work_tree();
+ worktree = repo_get_work_tree(the_repository);
if (!worktree)
goto no_prevention_needed;
@@ -560,6 +620,8 @@ static enum extension_result handle_extension_v0(const char *var,
data->precious_objects = git_config_bool(var, value);
return EXTENSION_OK;
} else if (!strcmp(ext, "partialclone")) {
+ if (!value)
+ return config_error_nonbool(var);
data->partial_clone = xstrdup(value);
return EXTENSION_OK;
} else if (!strcmp(ext, "worktreeconfig")) {
@@ -591,6 +653,36 @@ static enum extension_result handle_extension(const char *var,
"extensions.objectformat", value);
data->hash_algo = format;
return EXTENSION_OK;
+ } else if (!strcmp(ext, "compatobjectformat")) {
+ struct string_list_item *item;
+ int format;
+
+ if (!value)
+ return config_error_nonbool(var);
+ format = hash_algo_by_name(value);
+ if (format == GIT_HASH_UNKNOWN)
+ return error(_("invalid value for '%s': '%s'"),
+ "extensions.compatobjectformat", value);
+ /* For now only support compatObjectFormat being specified once. */
+ for_each_string_list_item(item, &data->v1_only_extensions) {
+ if (!strcmp(item->string, "compatobjectformat"))
+ return error(_("'%s' already specified as '%s'"),
+ "extensions.compatobjectformat",
+ hash_algos[data->compat_hash_algo].name);
+ }
+ data->compat_hash_algo = format;
+ return EXTENSION_OK;
+ } else if (!strcmp(ext, "refstorage")) {
+ unsigned int format;
+
+ if (!value)
+ return config_error_nonbool(var);
+ format = ref_storage_format_by_name(value);
+ if (format == REF_STORAGE_FORMAT_UNKNOWN)
+ return error(_("invalid value for '%s': '%s'"),
+ "extensions.refstorage", value);
+ data->ref_storage_format = format;
+ return EXTENSION_OK;
}
return EXTENSION_UNKNOWN;
}
@@ -694,29 +786,39 @@ int upgrade_repository_format(int target_version)
struct strbuf err = STRBUF_INIT;
struct strbuf repo_version = STRBUF_INIT;
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+ int ret;
strbuf_git_common_path(&sb, the_repository, "config");
read_repository_format(&repo_fmt, sb.buf);
strbuf_release(&sb);
- if (repo_fmt.version >= target_version)
- return 0;
+ if (repo_fmt.version >= target_version) {
+ ret = 0;
+ goto out;
+ }
if (verify_repository_format(&repo_fmt, &err) < 0) {
- error("cannot upgrade repository format from %d to %d: %s",
- repo_fmt.version, target_version, err.buf);
- strbuf_release(&err);
- return -1;
+ ret = error("cannot upgrade repository format from %d to %d: %s",
+ repo_fmt.version, target_version, err.buf);
+ goto out;
+ }
+ if (!repo_fmt.version && repo_fmt.unknown_extensions.nr) {
+ ret = error("cannot upgrade repository format: "
+ "unknown extension %s",
+ repo_fmt.unknown_extensions.items[0].string);
+ goto out;
}
- if (!repo_fmt.version && repo_fmt.unknown_extensions.nr)
- return error("cannot upgrade repository format: "
- "unknown extension %s",
- repo_fmt.unknown_extensions.items[0].string);
strbuf_addf(&repo_version, "%d", target_version);
git_config_set("core.repositoryformatversion", repo_version.buf);
+
+ ret = 1;
+
+out:
+ clear_repository_format(&repo_fmt);
strbuf_release(&repo_version);
- return 1;
+ strbuf_release(&err);
+ return ret;
}
static void init_repository_format(struct repository_format *format)
@@ -966,9 +1068,9 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
set_git_work_tree(".");
/* set_git_work_tree() must have been called by now */
- worktree = get_git_work_tree();
+ worktree = repo_get_work_tree(the_repository);
- /* both get_git_work_tree() and cwd are already normalized */
+ /* both repo_get_work_tree() and cwd are already normalized */
if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */
set_git_dir(gitdirenv, 0);
free(gitfile);
@@ -1119,7 +1221,7 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
}
struct safe_directory_data {
- const char *path;
+ char *path;
int is_safe;
};
@@ -1136,13 +1238,48 @@ static int safe_directory_cb(const char *key, const char *value,
} else if (!strcmp(value, "*")) {
data->is_safe = 1;
} else {
- const char *interpolated = NULL;
+ char *allowed = NULL;
- if (!git_config_pathname(&interpolated, key, value) &&
- !fspathcmp(data->path, interpolated ? interpolated : value))
- data->is_safe = 1;
+ if (!git_config_pathname(&allowed, key, value)) {
+ char *normalized = NULL;
+
+ /*
+ * Setting safe.directory to a non-absolute path
+ * makes little sense---it won't be relative to
+ * the configuration file the item is defined in.
+ * Except for ".", which means "if we are at the top
+ * level of a repository, then it is OK", which is
+ * slightly tighter than "*" that allows discovery.
+ */
+ if (!is_absolute_path(allowed) && strcmp(allowed, ".")) {
+ warning(_("safe.directory '%s' not absolute"),
+ allowed);
+ goto next;
+ }
- free((char *)interpolated);
+ /*
+ * A .gitconfig in $HOME may be shared across
+ * different machines and safe.directory entries
+ * may or may not exist as paths on all of these
+ * machines. In other words, it is not a warning
+ * worthy event when there is no such path on this
+ * machine---the entry may be useful elsewhere.
+ */
+ normalized = real_pathdup(allowed, 0);
+ if (!normalized)
+ goto next;
+
+ if (ends_with(normalized, "/*")) {
+ size_t len = strlen(normalized);
+ if (!fspathncmp(normalized, data->path, len - 1))
+ data->is_safe = 1;
+ } else if (!fspathcmp(data->path, normalized)) {
+ data->is_safe = 1;
+ }
+ next:
+ free(normalized);
+ free(allowed);
+ }
}
return 0;
@@ -1160,9 +1297,7 @@ static int ensure_valid_ownership(const char *gitfile,
const char *worktree, const char *gitdir,
struct strbuf *report)
{
- struct safe_directory_data data = {
- .path = worktree ? worktree : gitdir
- };
+ struct safe_directory_data data = { 0 };
if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
(!gitfile || is_path_owned_by_current_user(gitfile, report)) &&
@@ -1171,12 +1306,22 @@ static int ensure_valid_ownership(const char *gitfile,
return 1;
/*
+ * normalize the data.path for comparison with normalized paths
+ * that come from the configuration file. The path is unsafe
+ * if it cannot be normalized.
+ */
+ data.path = real_pathdup(worktree ? worktree : gitdir, 0);
+ if (!data.path)
+ return 0;
+
+ /*
* data.path is the "path" that identifies the repository and it is
* constant regardless of what failed above. data.is_safe should be
* initialized to false, and might be changed by the callback.
*/
git_protected_config(safe_directory_cb, &data);
+ free(data.path);
return data.is_safe;
}
@@ -1243,6 +1388,32 @@ static const char *allowed_bare_repo_to_string(
return NULL;
}
+static int is_implicit_bare_repo(const char *path)
+{
+ /*
+ * what we found is a ".git" directory at the root of
+ * the working tree.
+ */
+ if (ends_with_path_components(path, ".git"))
+ return 1;
+
+ /*
+ * we are inside $GIT_DIR of a secondary worktree of a
+ * non-bare repository.
+ */
+ if (strstr(path, "/.git/worktrees/"))
+ return 1;
+
+ /*
+ * we are inside $GIT_DIR of a worktree of a non-embedded
+ * submodule, whose superproject is not a bare repository.
+ */
+ if (strstr(path, "/.git/modules/"))
+ return 1;
+
+ return 0;
+}
+
/*
* 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.
@@ -1371,7 +1542,8 @@ 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)
+ if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT &&
+ !is_implicit_bare_repo(dir->buf))
return GIT_DIR_DISALLOWED_BARE;
if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
return GIT_DIR_INVALID_OWNERSHIP;
@@ -1447,6 +1619,106 @@ enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
return result;
}
+void setup_git_env(const char *git_dir)
+{
+ char *git_replace_ref_base;
+ const char *shallow_file;
+ const char *replace_ref_base;
+ struct set_gitdir_args args = { NULL };
+ struct strvec to_free = STRVEC_INIT;
+
+ args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT);
+ args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT);
+ args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
+ args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
+ args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
+ if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
+ args.disable_ref_updates = 1;
+ }
+
+ repo_set_gitdir(the_repository, git_dir, &args);
+ strvec_clear(&to_free);
+
+ if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
+ 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/");
+ update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
+
+ shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
+ if (shallow_file)
+ set_alternate_shallow_file(the_repository, shallow_file, 0);
+
+ if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
+ fetch_if_missing = 0;
+}
+
+static void set_git_dir_1(const char *path)
+{
+ xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
+ setup_git_env(path);
+}
+
+static void update_relative_gitdir(const char *name UNUSED,
+ const char *old_cwd,
+ const char *new_cwd,
+ void *data UNUSED)
+{
+ char *path = reparent_relative_path(old_cwd, new_cwd,
+ repo_get_git_dir(the_repository));
+ struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
+
+ trace_printf_key(&trace_setup_key,
+ "setup: move $GIT_DIR to '%s'",
+ path);
+ set_git_dir_1(path);
+ if (tmp_objdir)
+ tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd);
+ free(path);
+}
+
+void set_git_dir(const char *path, int make_realpath)
+{
+ struct strbuf realpath = STRBUF_INIT;
+
+ if (make_realpath) {
+ strbuf_realpath(&realpath, path, 1);
+ path = realpath.buf;
+ }
+
+ set_git_dir_1(path);
+ if (!is_absolute_path(path))
+ chdir_notify_register(NULL, update_relative_gitdir, NULL);
+
+ strbuf_release(&realpath);
+}
+
+static int git_work_tree_initialized;
+
+/*
+ * Note. This works only before you used a work tree. This was added
+ * primarily to support git-clone to work in a new repository it just
+ * created, and is not meant to flip between different work trees.
+ */
+void set_git_work_tree(const char *new_work_tree)
+{
+ if (git_work_tree_initialized) {
+ struct strbuf realpath = STRBUF_INIT;
+
+ strbuf_realpath(&realpath, new_work_tree, 1);
+ new_work_tree = realpath.buf;
+ if (strcmp(new_work_tree, the_repository->worktree))
+ die("internal error: work tree has already been set\n"
+ "Current worktree: %s\nNew worktree: %s",
+ the_repository->worktree, new_work_tree);
+ strbuf_release(&realpath);
+ return;
+ }
+ git_work_tree_initialized = 1;
+ repo_set_worktree(the_repository, new_work_tree);
+}
+
const char *setup_git_directory_gently(int *nongit_ok)
{
static struct strbuf cwd = STRBUF_INIT;
@@ -1576,6 +1848,10 @@ const char *setup_git_directory_gently(int *nongit_ok)
}
if (startup_info->have_repository) {
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
+ repo_set_compat_hash_algo(the_repository,
+ repo_fmt.compat_hash_algo);
+ repo_set_ref_storage_format(the_repository,
+ repo_fmt.ref_storage_format);
the_repository->repository_format_worktree_config =
repo_fmt.worktree_config;
/* take ownership of repo_fmt.partial_clone */
@@ -1666,9 +1942,12 @@ void check_repository_format(struct repository_format *fmt)
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
if (!fmt)
fmt = &repo_fmt;
- check_repository_format_gently(get_git_dir(), fmt, NULL);
+ check_repository_format_gently(repo_get_git_dir(the_repository), fmt, NULL);
startup_info->have_repository = 1;
repo_set_hash_algo(the_repository, fmt->hash_algo);
+ repo_set_compat_hash_algo(the_repository, fmt->compat_hash_algo);
+ repo_set_ref_storage_format(the_repository,
+ fmt->ref_storage_format);
the_repository->repository_format_worktree_config =
fmt->worktree_config;
the_repository->repository_format_partial_clone =
@@ -1734,7 +2013,7 @@ struct template_dir_cb_data {
};
static int template_dir_cb(const char *key, const char *value,
- const struct config_context *ctx, void *d)
+ const struct config_context *ctx UNUSED, void *d)
{
struct template_dir_cb_data *data = d;
@@ -1747,7 +2026,7 @@ static int template_dir_cb(const char *key, const char *value,
char *path = NULL;
FREE_AND_NULL(data->path);
- if (!git_config_pathname((const char **)&path, key, value))
+ if (!git_config_pathname(&path, key, value))
data->path = path ? path : xstrdup(value);
}
@@ -1895,7 +2174,7 @@ static void copy_templates(const char *option_template)
goto close_free_return;
}
- strbuf_addstr(&path, get_git_common_dir());
+ strbuf_addstr(&path, repo_get_common_dir(the_repository));
strbuf_complete(&path, '/');
copy_templates_1(&path, &template_path, dir);
close_free_return:
@@ -1921,12 +2200,22 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
return 1;
}
-void initialize_repository_version(int hash_algo, int reinit)
+void initialize_repository_version(int hash_algo,
+ enum ref_storage_format ref_storage_format,
+ int reinit)
{
char repo_version_string[10];
int repo_version = GIT_REPO_VERSION;
- if (hash_algo != GIT_HASH_SHA1)
+ /*
+ * Note that we initialize the repository version to 1 when the ref
+ * storage format is unknown. This is on purpose so that we can add the
+ * correct object format to the config during git-clone(1). The format
+ * version will get adjusted by git-clone(1) once it has learned about
+ * the remote repository's format.
+ */
+ if (hash_algo != GIT_HASH_SHA1 ||
+ ref_storage_format != REF_STORAGE_FORMAT_FILES)
repo_version = GIT_REPO_VERSION_READ;
/* This forces creation of new config file */
@@ -1934,29 +2223,82 @@ void initialize_repository_version(int hash_algo, int reinit)
"%d", repo_version);
git_config_set("core.repositoryformatversion", repo_version_string);
- if (hash_algo != GIT_HASH_SHA1)
+ if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN)
git_config_set("extensions.objectformat",
hash_algos[hash_algo].name);
else if (reinit)
git_config_set_gently("extensions.objectformat", NULL);
+
+ if (ref_storage_format != REF_STORAGE_FORMAT_FILES)
+ git_config_set("extensions.refstorage",
+ ref_storage_format_to_name(ref_storage_format));
+ else if (reinit)
+ git_config_set_gently("extensions.refstorage", NULL);
+}
+
+static int is_reinit(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+ char junk[2];
+ int ret;
+
+ git_path_buf(&buf, "HEAD");
+ ret = !access(buf.buf, R_OK) || readlink(buf.buf, junk, sizeof(junk) - 1) != -1;
+ strbuf_release(&buf);
+ return ret;
+}
+
+void create_reference_database(enum ref_storage_format ref_storage_format,
+ const char *initial_branch, int quiet)
+{
+ struct strbuf err = STRBUF_INIT;
+ char *to_free = NULL;
+ int reinit = is_reinit();
+
+ repo_set_ref_storage_format(the_repository, ref_storage_format);
+ if (ref_store_create_on_disk(get_main_ref_store(the_repository), 0, &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.
+ */
+ if (!reinit) {
+ char *ref;
+
+ if (!initial_branch)
+ initial_branch = to_free =
+ repo_default_branch_name(the_repository, quiet);
+
+ ref = xstrfmt("refs/heads/%s", initial_branch);
+ if (check_refname_format(ref, 0) < 0)
+ die(_("invalid initial branch name: '%s'"),
+ initial_branch);
+
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL) < 0)
+ exit(1);
+ free(ref);
+ }
+
+ if (reinit && initial_branch)
+ warning(_("re-init: ignored --initial-branch=%s"),
+ initial_branch);
+
+ strbuf_release(&err);
+ free(to_free);
}
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)
+ int init_shared_repository)
{
struct stat st1;
struct strbuf buf = STRBUF_INIT;
char *path;
- char junk[2];
int reinit;
int filemode;
- struct strbuf err = STRBUF_INIT;
- const char *work_tree = get_git_work_tree();
+ const char *work_tree = repo_get_work_tree(the_repository);
/*
* First copy the templates -- we might have the default
@@ -1972,83 +2314,26 @@ static int create_default_files(const char *template_path,
reset_shared_repository();
git_config(git_default_config, NULL);
+ reinit = is_reinit();
+
/*
* 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.
- */
+
+ is_bare_repository_cfg = !work_tree;
/*
* 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);
+ adjust_shared_perm(repo_get_git_dir(the_repository));
}
- initialize_repository_version(fmt->hash_algo, 0);
+ initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, 0);
/* Check filemode trustability */
path = git_path_buf(&buf, "config");
@@ -2069,7 +2354,7 @@ static int create_default_files(const char *template_path,
else {
git_config_set("core.bare", "false");
/* allow template config file to override the default */
- if (log_all_ref_updates == LOG_REFS_UNSET)
+ if (repo_settings_get_log_all_ref_updates(the_repository) == 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);
@@ -2103,7 +2388,7 @@ static void create_object_directory(void)
struct strbuf path = STRBUF_INIT;
size_t baselen;
- strbuf_addstr(&path, get_object_directory());
+ strbuf_addstr(&path, repo_get_object_directory(the_repository));
baselen = path.len;
safe_create_dir(path.buf, 1);
@@ -2135,20 +2420,73 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
if (rename(src, git_dir))
die_errno(_("unable to move %s to %s"), src, git_dir);
- repair_worktrees(NULL, NULL);
+ repair_worktrees_after_gitdir_move(src);
}
write_file(git_link, "gitdir: %s", git_dir);
}
-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
+struct default_format_config {
+ int hash;
+ enum ref_storage_format ref_format;
+};
+
+static int read_default_format_config(const char *key, const char *value,
+ const struct config_context *ctx UNUSED,
+ void *payload)
{
- const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
+ struct default_format_config *cfg = payload;
+ char *str = NULL;
+ int ret;
+
+ if (!strcmp(key, "init.defaultobjectformat")) {
+ ret = git_config_string(&str, key, value);
+ if (ret)
+ goto out;
+ cfg->hash = hash_algo_by_name(str);
+ if (cfg->hash == GIT_HASH_UNKNOWN)
+ warning(_("unknown hash algorithm '%s'"), str);
+ goto out;
+ }
+
+ if (!strcmp(key, "init.defaultrefformat")) {
+ ret = git_config_string(&str, key, value);
+ if (ret)
+ goto out;
+ cfg->ref_format = ref_storage_format_by_name(str);
+ if (cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN)
+ warning(_("unknown ref storage format '%s'"), str);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(str);
+ return ret;
+}
+
+static void repository_format_configure(struct repository_format *repo_fmt,
+ int hash, enum ref_storage_format ref_format)
+{
+ struct default_format_config cfg = {
+ .hash = GIT_HASH_UNKNOWN,
+ .ref_format = REF_STORAGE_FORMAT_UNKNOWN,
+ };
+ struct config_options opts = {
+ .respect_includes = 1,
+ .ignore_repo = 1,
+ .ignore_worktree = 1,
+ };
+ const char *env;
+
+ config_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);
+
/*
* 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.
*/
+ env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
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)
@@ -2158,18 +2496,39 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
if (env_algo == GIT_HASH_UNKNOWN)
die(_("unknown hash algorithm '%s'"), env);
repo_fmt->hash_algo = env_algo;
- }
+ } else if (cfg.hash != GIT_HASH_UNKNOWN) {
+ repo_fmt->hash_algo = cfg.hash;
+ }
+ repo_set_hash_algo(the_repository, repo_fmt->hash_algo);
+
+ env = getenv("GIT_DEFAULT_REF_FORMAT");
+ if (repo_fmt->version >= 0 &&
+ ref_format != REF_STORAGE_FORMAT_UNKNOWN &&
+ ref_format != repo_fmt->ref_storage_format) {
+ die(_("attempt to reinitialize repository with different reference storage format"));
+ } else if (ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
+ repo_fmt->ref_storage_format = ref_format;
+ } else if (env) {
+ ref_format = ref_storage_format_by_name(env);
+ if (ref_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), env);
+ repo_fmt->ref_storage_format = ref_format;
+ } else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
+ repo_fmt->ref_storage_format = cfg.ref_format;
+ }
+ repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);
}
int init_db(const char *git_dir, const char *real_git_dir,
- const char *template_dir, int hash, const char *initial_branch,
+ const char *template_dir, int hash,
+ enum ref_storage_format ref_storage_format,
+ 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;
@@ -2181,40 +2540,40 @@ int init_db(const char *git_dir, const char *real_git_dir,
die(_("%s already exists"), real_git_dir);
set_git_dir(real_git_dir, 1);
- git_dir = get_git_dir();
+ git_dir = repo_get_git_dir(the_repository);
separate_git_dir(git_dir, original_git_dir);
}
else {
set_git_dir(git_dir, 1);
- git_dir = get_git_dir();
+ git_dir = repo_get_git_dir(the_repository);
}
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.
+ /*
+ * 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);
+ repository_format_configure(&repo_fmt, hash, ref_storage_format);
+
+ /*
+ * Ensure `core.hidedotfiles` is processed. This must happen after we
+ * have set up the repository format such that we can evaluate
+ * includeIf conditions correctly in the case of re-initialization.
+ */
+ git_config(platform_core_config, NULL);
+
+ safe_create_dir(git_dir, 0);
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);
+ &repo_fmt, init_shared_repository);
+ if (!(flags & INIT_DB_SKIP_REFDB))
+ create_reference_database(repo_fmt.ref_storage_format,
+ initial_branch, flags & INIT_DB_QUIET);
create_object_directory();
if (get_shared_repository()) {
@@ -2253,6 +2612,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
}
+ clear_repository_format(&repo_fmt);
free(original_git_dir);
return 0;
}
diff --git a/setup.h b/setup.h
index 01a6ad7735..e496ab3e4d 100644
--- a/setup.h
+++ b/setup.h
@@ -1,6 +1,7 @@
#ifndef SETUP_H
#define SETUP_H
+#include "refs.h"
#include "string-list.h"
int is_inside_git_dir(void);
@@ -93,6 +94,9 @@ static inline int discover_git_directory(struct strbuf *commondir,
return 0;
}
+void set_git_dir(const char *path, int make_realpath);
+void set_git_work_tree(const char *tree);
+
const char *setup_git_directory_gently(int *);
const char *setup_git_directory(void);
char *prefix_path(const char *prefix, int len, const char *path);
@@ -127,6 +131,8 @@ struct repository_format {
int worktree_config;
int is_bare;
int hash_algo;
+ int compat_hash_algo;
+ enum ref_storage_format ref_storage_format;
int sparse_index;
char *work_tree;
struct string_list unknown_extensions;
@@ -143,6 +149,7 @@ struct repository_format {
.version = -1, \
.is_bare = -1, \
.hash_algo = GIT_HASH_SHA1, \
+ .ref_storage_format = REF_STORAGE_FORMAT_FILES, \
.unknown_extensions = STRING_LIST_INIT_DUP, \
.v1_only_extensions = STRING_LIST_INIT_DUP, \
}
@@ -172,7 +179,7 @@ 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(),
+ * Check the repository format version in the path found in repo_get_git_dir(the_repository),
* 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?".
@@ -183,14 +190,20 @@ void check_repository_format(struct repository_format *fmt);
const char *get_template_dir(const char *option_template);
-#define INIT_DB_QUIET 0x0001
-#define INIT_DB_EXIST_OK 0x0002
+#define INIT_DB_QUIET (1 << 0)
+#define INIT_DB_EXIST_OK (1 << 1)
+#define INIT_DB_SKIP_REFDB (1 << 2)
int init_db(const char *git_dir, const char *real_git_dir,
const char *template_dir, int hash_algo,
+ enum ref_storage_format ref_storage_format,
const char *initial_branch, int init_shared_repository,
unsigned int flags);
-void initialize_repository_version(int hash_algo, int reinit);
+void initialize_repository_version(int hash_algo,
+ enum ref_storage_format ref_storage_format,
+ int reinit);
+void create_reference_database(enum ref_storage_format ref_storage_format,
+ const char *initial_branch, int quiet);
/*
* NOTE NOTE NOTE!!
diff --git a/sh-i18n--envsubst.c b/sh-i18n--envsubst.c
index 133496bd4d..f69fd16610 100644
--- a/sh-i18n--envsubst.c
+++ b/sh-i18n--envsubst.c
@@ -31,7 +31,7 @@
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/>. */
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
/* closeout.c - close standard output and standard error
Copyright (C) 1998-2007 Free Software Foundation, Inc.
@@ -47,7 +47,7 @@
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/>. */
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <stdio.h>
diff --git a/sha1/openssl.h b/sha1/openssl.h
index 006c1f4ba5..1038af47da 100644
--- a/sha1/openssl.h
+++ b/sha1/openssl.h
@@ -40,10 +40,12 @@ static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst,
EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
}
+#ifndef platform_SHA_CTX
#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
#endif /* SHA1_OPENSSL_H */
diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c
index dede2cbddf..f993ef9c69 100644
--- a/sha1dc/sha1.c
+++ b/sha1dc/sha1.c
@@ -88,7 +88,7 @@
/*
* Should define Big Endian for a whitelist of known processors. See
* https://sourceforge.net/p/predef/wiki/Endianness/ and
- * http://www.oracle.com/technetwork/server-storage/solaris/portingtosolaris-138514.html
+ * https://web.archive.org/web/20140421151132/http://www.perforce.com/perforce/doc.current/manuals/p4sag/chapter.superuser.html
*/
#define SHA1DC_BIGENDIAN
diff --git a/sha1dc_git.h b/sha1dc_git.h
index 60e3ce8439..f6f880cabe 100644
--- a/sha1dc_git.h
+++ b/sha1dc_git.h
@@ -18,7 +18,10 @@ void git_SHA1DCFinal(unsigned char [20], SHA1_CTX *);
void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *data, unsigned long len);
#define platform_SHA_IS_SHA1DC /* used by "test-tool sha1-is-sha1dc" */
+
+#ifndef platform_SHA_CTX
#define platform_SHA_CTX SHA1_CTX
#define platform_SHA1_Init git_SHA1DCInit
#define platform_SHA1_Update git_SHA1DCUpdate
#define platform_SHA1_Final git_SHA1DCFinal
+#endif
diff --git a/shallow.c b/shallow.c
index 5413719fd4..4bb1518dbc 100644
--- a/shallow.c
+++ b/shallow.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "hex.h"
#include "repository.h"
@@ -7,7 +9,6 @@
#include "commit.h"
#include "tag.h"
#include "pkt-line.h"
-#include "remote.h"
#include "refs.h"
#include "oid-array.h"
#include "path.h"
@@ -38,8 +39,10 @@ int register_shallow(struct repository *r, const struct object_id *oid)
oidcpy(&graft->oid, oid);
graft->nr_parent = -1;
- if (commit && commit->object.parsed)
+ if (commit && commit->object.parsed) {
+ free_commit_list(commit->parents);
commit->parents = NULL;
+ }
return register_commit_graft(r, graft, 0);
}
@@ -48,6 +51,7 @@ int unregister_shallow(const struct object_id *oid)
int pos = commit_graft_pos(the_repository, oid);
if (pos < 0)
return -1;
+ free(the_repository->parsed_objects->grafts[pos]);
if (pos + 1 < the_repository->parsed_objects->grafts_nr)
MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
the_repository->parsed_objects->grafts + pos + 1,
@@ -94,7 +98,7 @@ static void reset_repository_shallow(struct repository *r)
{
r->parsed_objects->is_shallow = -1;
stat_validity_clear(r->parsed_objects->shallow_stat);
- reset_commit_grafts(r);
+ parsed_object_pool_reset_commit_grafts(r->parsed_objects);
}
int commit_shallow_file(struct repository *r, struct shallow_lock *lk)
@@ -484,6 +488,15 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
void clear_shallow_info(struct shallow_info *info)
{
+ if (info->used_shallow) {
+ for (size_t i = 0; i < info->shallow->nr; i++)
+ free(info->used_shallow[i]);
+ free(info->used_shallow);
+ }
+
+ free(info->need_reachability_test);
+ free(info->reachable);
+ free(info->shallow_ref);
free(info->ours);
free(info->theirs);
}
@@ -609,6 +622,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
}
static int mark_uninteresting(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data UNUSED)
@@ -677,8 +691,10 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,
* connect to old refs. If not (e.g. force ref updates) it'll
* have to go down to the current shallow commits.
*/
- head_ref(mark_uninteresting, NULL);
- for_each_ref(mark_uninteresting, NULL);
+ refs_head_ref(get_main_ref_store(the_repository), mark_uninteresting,
+ NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ mark_uninteresting, NULL);
/* Mark potential bottoms so we won't go out of bound */
for (i = 0; i < nr_shallow; i++) {
@@ -722,6 +738,7 @@ struct commit_array {
};
static int add_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data)
@@ -781,8 +798,8 @@ static void post_assign_shallow(struct shallow_info *info,
info->nr_theirs = dst;
memset(&ca, 0, sizeof(ca));
- head_ref(add_ref, &ca);
- for_each_ref(add_ref, &ca);
+ refs_head_ref(get_main_ref_store(the_repository), add_ref, &ca);
+ refs_for_each_ref(get_main_ref_store(the_repository), add_ref, &ca);
/* Remove unreachable shallow commits from "ours" */
for (i = dst = 0; i < info->nr_ours; i++) {
@@ -793,12 +810,16 @@ static void post_assign_shallow(struct shallow_info *info,
if (!*bitmap)
continue;
for (j = 0; j < bitmap_nr; j++)
- if (bitmap[0][j] &&
- /* Step 7, reachability test at commit level */
- !repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits)) {
- update_refstatus(ref_status, info->ref->nr, *bitmap);
- dst++;
- break;
+ if (bitmap[0][j]) {
+ /* Step 7, reachability test at commit level */
+ int ret = repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits, 1);
+ if (ret < 0)
+ exit(128);
+ if (!ret) {
+ update_refstatus(ref_status, info->ref->nr, *bitmap);
+ dst++;
+ break;
+ }
}
}
info->nr_ours = dst;
@@ -817,8 +838,10 @@ int delayed_reachability_test(struct shallow_info *si, int c)
struct commit_array ca;
memset(&ca, 0, sizeof(ca));
- head_ref(add_ref, &ca);
- for_each_ref(add_ref, &ca);
+ refs_head_ref(get_main_ref_store(the_repository),
+ add_ref, &ca);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ add_ref, &ca);
si->commits = ca.commits;
si->nr_commits = ca.nr;
}
@@ -826,7 +849,10 @@ int delayed_reachability_test(struct shallow_info *si, int c)
si->reachable[c] = repo_in_merge_bases_many(the_repository,
commit,
si->nr_commits,
- si->commits);
+ si->commits,
+ 1);
+ if (si->reachable[c] < 0)
+ exit(128);
si->need_reachability_test[c] = 0;
}
return si->reachable[c];
diff --git a/shared.mak b/shared.mak
index aeb80fc4d5..29bebd30d8 100644
--- a/shared.mak
+++ b/shared.mak
@@ -108,3 +108,11 @@ endif
define mkdir_p_parent_template
$(if $(wildcard $(@D)),,$(QUIET_MKDIR_P_PARENT)$(shell mkdir -p $(@D)))
endef
+
+## Getting sick of writing -L$(SOMELIBDIR) $(CC_LD_DYNPATH)$(SOMELIBDIR)?
+## Write $(call libpath_template,$(SOMELIBDIR)) instead, perhaps?
+## With CC_LD_DYNPATH set to either an empty string or to "-L", the
+## the directory is not shown the second time.
+define libpath_template
+-L$(1) $(if $(filter-out -L,$(CC_LD_DYNPATH)),$(CC_LD_DYNPATH)$(1))
+endef
diff --git a/shell.c b/shell.c
index 5c67e7bd97..76333c8068 100644
--- a/shell.c
+++ b/shell.c
@@ -4,7 +4,6 @@
#include "strbuf.h"
#include "run-command.h"
#include "alias.h"
-#include "prompt.h"
#define COMMAND_DIR "git-shell-commands"
#define HELP_COMMAND COMMAND_DIR "/help"
@@ -144,6 +143,7 @@ static void run_shell(void)
}
free(argv);
+ free(split_args);
free(rawargs);
} while (!done);
}
@@ -217,9 +217,8 @@ int cmd_main(int argc, const char **argv)
count = split_cmdline(prog, &user_argv);
if (count >= 0) {
if (is_valid_cmd_name(user_argv[0])) {
- prog = make_cmd(user_argv[0]);
- user_argv[0] = prog;
- execv(user_argv[0], (char *const *) user_argv);
+ char *cmd = make_cmd(user_argv[0]);
+ execv(cmd, (char *const *) user_argv);
}
free(prog);
free(user_argv);
diff --git a/sideband.c b/sideband.c
index 6cbfd391c4..02805573fa 100644
--- a/sideband.c
+++ b/sideband.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "color.h"
#include "config.h"
@@ -30,28 +32,27 @@ static int use_sideband_colors(void)
const char *key = "color.remote";
struct strbuf sb = STRBUF_INIT;
- char *value;
+ const char *value;
int i;
if (use_sideband_colors_cached >= 0)
return use_sideband_colors_cached;
- if (!git_config_get_string(key, &value)) {
+ if (!git_config_get_string_tmp(key, &value))
use_sideband_colors_cached = git_config_colorbool(key, value);
- } else if (!git_config_get_string("color.ui", &value)) {
+ else if (!git_config_get_string_tmp("color.ui", &value))
use_sideband_colors_cached = git_config_colorbool("color.ui", value);
- } else {
+ else
use_sideband_colors_cached = GIT_COLOR_AUTO;
- }
for (i = 0; i < ARRAY_SIZE(keywords); i++) {
strbuf_reset(&sb);
strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);
- if (git_config_get_string(sb.buf, &value))
- continue;
- if (color_parse(value, keywords[i].color))
+ if (git_config_get_string_tmp(sb.buf, &value))
continue;
+ color_parse(value, keywords[i].color);
}
+
strbuf_release(&sb);
return use_sideband_colors_cached;
}
@@ -69,7 +70,10 @@ void list_config_color_sideband_slots(struct string_list *list, const char *pref
* of the line. This should be called for a single line only, which is
* passed as the first N characters of the SRC array.
*
- * NEEDSWORK: use "size_t n" instead for clarity.
+ * It is fine to use "int n" here instead of "size_t n" as all calls to this
+ * function pass an 'int' parameter. Additionally, the buffer involved in
+ * storing these 'int' values takes input from a packet via the pkt-line
+ * interface, which is capable of transferring only 64kB at a time.
*/
static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
{
@@ -187,7 +191,7 @@ int demultiplex_sideband(const char *me, int status,
int linelen = brk - b;
/*
- * For message accross packet boundary, there would have
+ * For message across packet boundary, there would have
* a nonempty "scratch" buffer from last call of this
* function, and there may have a leading CR/LF in "buf".
* For this case we should add a clear-to-eol suffix to
@@ -217,7 +221,7 @@ int demultiplex_sideband(const char *me, int status,
}
strbuf_addch(scratch, *brk);
- xwrite(2, scratch->buf, scratch->len);
+ write_in_full(2, scratch->buf, scratch->len);
strbuf_reset(scratch);
b = brk + 1;
@@ -244,7 +248,7 @@ cleanup:
die("%s", scratch->buf);
if (scratch->len) {
strbuf_addch(scratch, '\n');
- xwrite(2, scratch->buf, scratch->len);
+ write_in_full(2, scratch->buf, scratch->len);
}
strbuf_release(scratch);
return 1;
diff --git a/simple-ipc.h b/simple-ipc.h
index a849d9f841..3916eaf70d 100644
--- a/simple-ipc.h
+++ b/simple-ipc.h
@@ -179,11 +179,20 @@ struct ipc_server_opts
* When a client IPC message is received, the `application_cb` will be
* called (possibly on a random thread) to handle the message and
* optionally compose a reply message.
+ *
+ * This initializes all threads but no actual work will be done until
+ * ipc_server_start_async() is called.
+ */
+int ipc_server_init_async(struct ipc_server_data **returned_server_data,
+ const char *path, const struct ipc_server_opts *opts,
+ ipc_server_application_cb *application_cb,
+ void *application_data);
+
+/*
+ * Let an async server start running. This needs to be called only once
+ * after initialization.
*/
-int ipc_server_run_async(struct ipc_server_data **returned_server_data,
- const char *path, const struct ipc_server_opts *opts,
- ipc_server_application_cb *application_cb,
- void *application_data);
+void ipc_server_start_async(struct ipc_server_data *server_data);
/*
* Gently signal the IPC server pool to shutdown. No new client
diff --git a/sparse-index.c b/sparse-index.c
index 1fdb07a9e6..2107840bfc 100644
--- a/sparse-index.c
+++ b/sparse-index.c
@@ -1,5 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
+#include "ewah/ewok.h"
#include "gettext.h"
#include "name-hash.h"
#include "read-cache-ll.h"
@@ -12,6 +15,23 @@
#include "config.h"
#include "dir.h"
#include "fsmonitor-ll.h"
+#include "advice.h"
+
+/**
+ * This global is used by expand_index() to determine if we should give the
+ * advice for advice.sparseIndexExpanded when expanding a sparse index to a full
+ * one. However, this is sometimes done on purpose, such as in the sparse-checkout
+ * builtin, even when index.sparse=false. This may be disabled in
+ * convert_to_sparse() or by commands that know they will lead to a full
+ * expansion, but this message is not actionable.
+ */
+int give_advice_on_expansion = 1;
+#define ADVICE_MSG \
+ "The sparse index is expanding to a full index, a slow operation.\n" \
+ "Your working directory likely has contents that are outside of\n" \
+ "your sparse-checkout patterns. Use 'git sparse-checkout list' to\n" \
+ "see your sparse-checkout definition and compare it to your working\n" \
+ "directory contents. Running 'git clean' may assist in this cleanup."
struct modify_index_context {
struct index_state *write;
@@ -184,6 +204,12 @@ int convert_to_sparse(struct index_state *istate, int flags)
return 0;
/*
+ * If we are purposefully collapsing a full index, then don't give
+ * advice when it is expanded later.
+ */
+ give_advice_on_expansion = 0;
+
+ /*
* NEEDSWORK: If we have unmerged entries, then stay full.
* Unmerged entries prevent the cache-tree extension from working.
*/
@@ -217,7 +243,8 @@ int convert_to_sparse(struct index_state *istate, int flags)
cache_tree_update(istate, 0);
istate->fsmonitor_has_run_once = 0;
- FREE_AND_NULL(istate->fsmonitor_dirty);
+ ewah_free(istate->fsmonitor_dirty);
+ istate->fsmonitor_dirty = NULL;
FREE_AND_NULL(istate->fsmonitor_last_update);
istate->sparse_index = INDEX_COLLAPSED;
@@ -328,6 +355,12 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
pl = NULL;
}
+ if (!pl && give_advice_on_expansion) {
+ give_advice_on_expansion = 0;
+ advise_if_enabled(ADVICE_SPARSE_INDEX_EXPANDED,
+ _(ADVICE_MSG));
+ }
+
/*
* A NULL pattern set indicates we are expanding a full index, so
* we use a special region name that indicates the full expansion.
@@ -391,7 +424,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
strbuf_setlen(&base, 0);
strbuf_add(&base, ce->name, strlen(ce->name));
- read_tree_at(istate->repo, tree, &base, &ps,
+ read_tree_at(istate->repo, tree, &base, 0, &ps,
add_path_to_index, &ctx);
/* free directory entries. full entries are re-used */
@@ -407,7 +440,8 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
istate->cache_nr = full->cache_nr;
istate->cache_alloc = full->cache_alloc;
istate->fsmonitor_has_run_once = 0;
- FREE_AND_NULL(istate->fsmonitor_dirty);
+ ewah_free(istate->fsmonitor_dirty);
+ istate->fsmonitor_dirty = NULL;
FREE_AND_NULL(istate->fsmonitor_last_update);
strbuf_release(&base);
@@ -439,96 +473,208 @@ void ensure_correct_sparsity(struct index_state *istate)
ensure_full_index(istate);
}
-static int path_found(const char *path, const char **dirname, size_t *dir_len,
- int *dir_found)
+struct path_found_data {
+ /**
+ * The path stored in 'dir', if non-empty, corresponds to the most-
+ * recent path that we checked where:
+ *
+ * 1. The path should be a directory, according to the index.
+ * 2. The path does not exist.
+ * 3. The parent path _does_ exist. (This may be the root of the
+ * working directory.)
+ */
+ struct strbuf dir;
+ size_t lstat_count;
+};
+
+#define PATH_FOUND_DATA_INIT { \
+ .dir = STRBUF_INIT \
+}
+
+static void clear_path_found_data(struct path_found_data *data)
+{
+ strbuf_release(&data->dir);
+}
+
+/**
+ * Return the length of the longest common substring that ends in a
+ * slash ('/') to indicate the longest common parent directory. Returns
+ * zero if no common directory exists.
+ */
+static size_t max_common_dir_prefix(const char *path1, const char *path2)
+{
+ size_t common_prefix = 0;
+ for (size_t i = 0; path1[i] && path2[i]; i++) {
+ if (path1[i] != path2[i])
+ break;
+
+ /*
+ * If they agree at a directory separator, then add one
+ * to make sure it is included in the common prefix string.
+ */
+ if (path1[i] == '/')
+ common_prefix = i + 1;
+ }
+
+ return common_prefix;
+}
+
+static int path_found(const char *path, struct path_found_data *data)
{
struct stat st;
- char *newdir;
- char *tmp;
+ size_t common_prefix;
/*
- * If dirname corresponds to a directory that doesn't exist, and this
- * path starts with dirname, then path can't exist.
+ * If data->dir is non-empty, then it contains a path that doesn't
+ * exist, including an ending slash ('/'). If it is a prefix of 'path',
+ * then we can return 0.
*/
- if (!*dir_found && !memcmp(path, *dirname, *dir_len))
+ if (data->dir.len && !memcmp(path, data->dir.buf, data->dir.len))
return 0;
/*
- * If path itself exists, return 1.
+ * Otherwise, we must check if the current path exists. If it does, then
+ * return 1. The cached directory will be skipped until we come across
+ * a missing path again.
*/
+ data->lstat_count++;
if (!lstat(path, &st))
return 1;
/*
- * Otherwise, path does not exist so we'll return 0...but we'll first
- * determine some info about its parent directory so we can avoid
- * lstat calls for future cache entries.
+ * At this point, we know that 'path' doesn't exist, and we know that
+ * the parent directory of 'data->dir' does exist. Let's set 'data->dir'
+ * to be the top-most non-existing directory of 'path'. If the first
+ * parent of 'path' exists, then we will act as though 'path'
+ * corresponds to a directory (by adding a slash).
*/
- newdir = strrchr(path, '/');
- if (!newdir)
- return 0; /* Didn't find a parent dir; just return 0 now. */
+ common_prefix = max_common_dir_prefix(path, data->dir.buf);
/*
- * If path starts with directory (which we already lstat'ed and found),
- * then no need to lstat parent directory again.
+ * At this point, 'path' and 'data->dir' have a common existing parent
+ * directory given by path[0..common_prefix] (which could have length 0).
+ * We "grow" the data->dir buffer by checking for existing directories
+ * along 'path'.
*/
- if (*dir_found && *dirname && memcmp(path, *dirname, *dir_len))
- return 0;
- /* Free previous dirname, and cache path's dirname */
- *dirname = path;
- *dir_len = newdir - path + 1;
+ strbuf_setlen(&data->dir, common_prefix);
+ while (1) {
+ /* Find the next directory in 'path'. */
+ const char *rest = path + data->dir.len;
+ const char *next_slash = strchr(rest, '/');
+
+ /*
+ * If there are no more slashes, then 'path' doesn't contain a
+ * non-existent _parent_ directory. Set 'data->dir' to be equal
+ * to 'path' plus an additional slash, so it can be used for
+ * caching in the future. The filename of 'path' is considered
+ * a non-existent directory.
+ *
+ * Note: if "{path}/" exists as a directory, then it will never
+ * appear as a prefix of other callers to this method, assuming
+ * the context from the clear_skip_worktree... methods. If this
+ * method is reused, then this must be reconsidered.
+ */
+ if (!next_slash) {
+ strbuf_addstr(&data->dir, rest);
+ strbuf_addch(&data->dir, '/');
+ break;
+ }
- tmp = xstrndup(path, *dir_len);
- *dir_found = !lstat(tmp, &st);
- free(tmp);
+ /*
+ * Now that we have a slash, let's grow 'data->dir' to include
+ * this slash, then test if we should stop.
+ */
+ strbuf_add(&data->dir, rest, next_slash - rest + 1);
+
+ /* If the parent dir doesn't exist, then stop here. */
+ data->lstat_count++;
+ if (lstat(data->dir.buf, &st))
+ return 0;
+ }
+ /*
+ * At this point, 'data->dir' is equal to 'path' plus a slash character,
+ * and the parent directory of 'path' definitely exists. Moreover, we
+ * know that 'path' doesn't exist, or we would have returned 1 earlier.
+ */
return 0;
}
-void clear_skip_worktree_from_present_files(struct index_state *istate)
+static int clear_skip_worktree_from_present_files_sparse(struct index_state *istate)
{
- const char *last_dirname = NULL;
- size_t dir_len = 0;
- int dir_found = 1;
-
- int i;
- int path_count[2] = {0, 0};
- int restarted = 0;
+ struct path_found_data data = PATH_FOUND_DATA_INIT;
- if (!core_apply_sparse_checkout ||
- sparse_expect_files_outside_of_patterns)
- return;
+ int path_count = 0;
+ int to_restart = 0;
- trace2_region_enter("index", "clear_skip_worktree_from_present_files",
+ trace2_region_enter("index", "clear_skip_worktree_from_present_files_sparse",
istate->repo);
-restart:
- for (i = 0; i < istate->cache_nr; i++) {
+ for (int i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce = istate->cache[i];
if (ce_skip_worktree(ce)) {
- path_count[restarted]++;
- if (path_found(ce->name, &last_dirname, &dir_len, &dir_found)) {
+ path_count++;
+ if (path_found(ce->name, &data)) {
if (S_ISSPARSEDIR(ce->ce_mode)) {
- if (restarted)
- BUG("ensure-full-index did not fully flatten?");
- ensure_full_index(istate);
- restarted = 1;
- goto restart;
+ to_restart = 1;
+ break;
}
ce->ce_flags &= ~CE_SKIP_WORKTREE;
}
}
}
- if (path_count[0])
- trace2_data_intmax("index", istate->repo,
- "sparse_path_count", path_count[0]);
- if (restarted)
- trace2_data_intmax("index", istate->repo,
- "sparse_path_count_full", path_count[1]);
- trace2_region_leave("index", "clear_skip_worktree_from_present_files",
+ trace2_data_intmax("index", istate->repo,
+ "sparse_path_count", path_count);
+ trace2_data_intmax("index", istate->repo,
+ "sparse_lstat_count", data.lstat_count);
+ trace2_region_leave("index", "clear_skip_worktree_from_present_files_sparse",
istate->repo);
+ clear_path_found_data(&data);
+ return to_restart;
+}
+
+static void clear_skip_worktree_from_present_files_full(struct index_state *istate)
+{
+ struct path_found_data data = PATH_FOUND_DATA_INIT;
+
+ int path_count = 0;
+
+ trace2_region_enter("index", "clear_skip_worktree_from_present_files_full",
+ istate->repo);
+ for (int i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+
+ if (S_ISSPARSEDIR(ce->ce_mode))
+ BUG("ensure-full-index did not fully flatten?");
+
+ if (ce_skip_worktree(ce)) {
+ path_count++;
+ if (path_found(ce->name, &data))
+ ce->ce_flags &= ~CE_SKIP_WORKTREE;
+ }
+ }
+
+ trace2_data_intmax("index", istate->repo,
+ "full_path_count", path_count);
+ trace2_data_intmax("index", istate->repo,
+ "full_lstat_count", data.lstat_count);
+ trace2_region_leave("index", "clear_skip_worktree_from_present_files_full",
+ istate->repo);
+ clear_path_found_data(&data);
+}
+
+void clear_skip_worktree_from_present_files(struct index_state *istate)
+{
+ if (!core_apply_sparse_checkout ||
+ sparse_expect_files_outside_of_patterns)
+ return;
+
+ if (clear_skip_worktree_from_present_files_sparse(istate)) {
+ ensure_full_index(istate);
+ clear_skip_worktree_from_present_files_full(istate);
+ }
}
/*
@@ -579,8 +725,9 @@ void expand_to_path(struct index_state *istate,
replace++;
temp = *replace;
*replace = '\0';
+ substr_len = replace - path_mutable.buf;
if (index_file_exists(istate, path_mutable.buf,
- path_mutable.len, icase)) {
+ substr_len, icase)) {
/*
* We found a parent directory in the name-hash
* hashtable, because only sparse directory entries
@@ -593,7 +740,6 @@ void expand_to_path(struct index_state *istate,
}
*replace = temp;
- substr_len = replace - path_mutable.buf;
}
cleanup:
diff --git a/sparse-index.h b/sparse-index.h
index a16f3e67d7..727034be7c 100644
--- a/sparse-index.h
+++ b/sparse-index.h
@@ -1,6 +1,13 @@
#ifndef SPARSE_INDEX_H__
#define SPARSE_INDEX_H__
+/*
+ * If performing an operation where the index is supposed to expand to a
+ * full index, then disable the advice message by setting this global to
+ * zero.
+ */
+extern int give_advice_on_expansion;
+
struct index_state;
#define SPARSE_INDEX_MEMORY_ONLY (1 << 0)
int is_sparse_index_allowed(struct index_state *istate, int flags);
diff --git a/split-index.c b/split-index.c
index 8c38687c04..cfbc773e6c 100644
--- a/split-index.c
+++ b/split-index.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hash.h"
@@ -29,7 +31,7 @@ int read_link_extension(struct index_state *istate,
if (sz < the_hash_algo->rawsz)
return error("corrupt link extension (too short)");
si = init_split_index(istate);
- oidread(&si->base_oid, data);
+ oidread(&si->base_oid, data, the_repository->hash_algo);
data += the_hash_algo->rawsz;
sz -= the_hash_algo->rawsz;
if (!sz)
@@ -95,7 +97,11 @@ void move_cache_to_base_index(struct index_state *istate)
mem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);
}
- ALLOC_ARRAY(si->base, 1);
+ if (si->base)
+ release_index(si->base);
+ else
+ ALLOC_ARRAY(si->base, 1);
+
index_state_init(si->base, istate->repo);
si->base->version = istate->version;
/* zero timestamp disables racy test in ce_write_index() */
diff --git a/split-index.h b/split-index.h
index 15a29cd08c..1a153f47ba 100644
--- a/split-index.h
+++ b/split-index.h
@@ -1,7 +1,7 @@
#ifndef SPLIT_INDEX_H
#define SPLIT_INDEX_H
-#include "hash-ll.h"
+#include "hash.h"
struct index_state;
struct strbuf;
diff --git a/statinfo.c b/statinfo.c
index 17bb8966c3..30a164b0e6 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -1,7 +1,25 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "statinfo.h"
+/*
+ * Munge st_size into an unsigned int.
+ */
+static unsigned int munge_st_size(off_t st_size) {
+ unsigned int sd_size = st_size;
+
+ /*
+ * If the file is an exact multiple of 4 GiB, modify the value so it
+ * doesn't get marked as racily clean (zero).
+ */
+ if (!sd_size && st_size)
+ return 0x80000000;
+ else
+ return sd_size;
+}
+
void fill_stat_data(struct stat_data *sd, struct stat *st)
{
sd->sd_ctime.sec = (unsigned int)st->st_ctime;
@@ -12,7 +30,34 @@ void fill_stat_data(struct stat_data *sd, struct stat *st)
sd->sd_ino = st->st_ino;
sd->sd_uid = st->st_uid;
sd->sd_gid = st->st_gid;
- sd->sd_size = st->st_size;
+ sd->sd_size = munge_st_size(st->st_size);
+}
+
+static void set_times(struct stat *st, const struct stat_data *sd)
+{
+ st->st_ctime = sd->sd_ctime.sec;
+ st->st_mtime = sd->sd_mtime.sec;
+#ifdef NO_NSEC
+ ; /* nothing */
+#else
+#ifdef USE_ST_TIMESPEC
+ st->st_ctimespec.tv_nsec = sd->sd_ctime.nsec;
+ st->st_mtimespec.tv_nsec = sd->sd_mtime.nsec;
+#else
+ st->st_ctim.tv_nsec = sd->sd_ctime.nsec;
+ st->st_mtim.tv_nsec = sd->sd_mtime.nsec;
+#endif
+#endif
+}
+
+void fake_lstat_data(const struct stat_data *sd, struct stat *st)
+{
+ set_times(st, sd);
+ st->st_dev = sd->sd_dev;
+ st->st_ino = sd->sd_ino;
+ st->st_uid = sd->sd_uid;
+ st->st_gid = sd->sd_gid;
+ st->st_size = sd->sd_size;
}
int match_stat_data(const struct stat_data *sd, struct stat *st)
@@ -51,7 +96,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
changed |= INODE_CHANGED;
#endif
- if (sd->sd_size != (unsigned int) st->st_size)
+ if (sd->sd_size != munge_st_size(st->st_size))
changed |= DATA_CHANGED;
return changed;
diff --git a/statinfo.h b/statinfo.h
index 700f502ac0..5b21a30f90 100644
--- a/statinfo.h
+++ b/statinfo.h
@@ -47,6 +47,14 @@ struct stat_validity {
void fill_stat_data(struct stat_data *sd, struct stat *st);
/*
+ * The inverse of the above. When we know the cache_entry that
+ * contains sd is up-to-date, but still need to pretend we called
+ * lstat() to learn that fact, this function fills "st" enough to
+ * fool ie_match_stat().
+ */
+void fake_lstat_data(const 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,
diff --git a/strbuf.c b/strbuf.c
index 4c9ac6dc5e..3d2189a7f6 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,6 +1,6 @@
#include "git-compat-util.h"
#include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
#include "strbuf.h"
#include "string-list.h"
#include "utf8.h"
@@ -24,6 +24,17 @@ int istarts_with(const char *str, const char *prefix)
return 0;
}
+int starts_with_mem(const char *str, size_t len, const char *prefix)
+{
+ const char *end = str + len;
+ for (; ; str++, prefix++) {
+ if (!*prefix)
+ return 1;
+ else if (str == end || *str != *prefix)
+ return 0;
+ }
+}
+
int skip_to_optional_arg_default(const char *str, const char *prefix,
const char **arg, const char *def)
{
@@ -266,7 +277,7 @@ void strbuf_vinsertf(struct strbuf *sb, size_t pos, const char *fmt, va_list ap)
len = vsnprintf(sb->buf + sb->len, 0, fmt, cp);
va_end(cp);
if (len < 0)
- BUG("your vsnprintf is broken (returned %d)", len);
+ die(_("unable to format message: %s"), fmt);
if (!len)
return; /* nothing to do */
if (unsigned_add_overflows(sb->len, len))
@@ -302,6 +313,15 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
strbuf_setlen(sb, sb->len + len);
}
+void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n)
+{
+ size_t len = strlen(s);
+
+ strbuf_grow(sb, st_mult(len, n));
+ for (size_t i = 0; i < n; i++)
+ strbuf_add(sb, s, len);
+}
+
void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
{
strbuf_grow(sb, sb2->len);
@@ -340,18 +360,17 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
}
static void add_lines(struct strbuf *out,
- const char *prefix1,
- const char *prefix2,
- const char *buf, size_t size)
+ const char *prefix,
+ const char *buf, size_t size,
+ int space_after_prefix)
{
while (size) {
- const char *prefix;
const char *next = memchr(buf, '\n', size);
next = next ? (next + 1) : (buf + size);
- prefix = ((prefix2 && (buf[0] == '\n' || buf[0] == '\t'))
- ? prefix2 : prefix1);
strbuf_addstr(out, prefix);
+ if (space_after_prefix && buf[0] != '\n' && buf[0] != '\t')
+ strbuf_addch(out, ' ');
strbuf_add(out, buf, next - buf);
size -= next - buf;
buf = next;
@@ -360,19 +379,12 @@ static void add_lines(struct strbuf *out,
}
void strbuf_add_commented_lines(struct strbuf *out, const char *buf,
- size_t size, char comment_line_char)
+ size_t size, const char *comment_prefix)
{
- static char prefix1[3];
- static char prefix2[2];
-
- if (prefix1[0] != comment_line_char) {
- xsnprintf(prefix1, sizeof(prefix1), "%c ", comment_line_char);
- xsnprintf(prefix2, sizeof(prefix2), "%c", comment_line_char);
- }
- add_lines(out, prefix1, prefix2, buf, size);
+ add_lines(out, comment_prefix, buf, size, 1);
}
-void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,
+void strbuf_commented_addf(struct strbuf *sb, const char *comment_prefix,
const char *fmt, ...)
{
va_list params;
@@ -383,7 +395,7 @@ void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,
strbuf_vaddf(&buf, fmt, params);
va_end(params);
- strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);
+ strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_prefix);
if (incomplete_line)
sb->buf[--sb->len] = '\0';
@@ -401,7 +413,7 @@ void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
va_end(cp);
if (len < 0)
- BUG("your vsnprintf is broken (returned %d)", len);
+ die(_("unable to format message: %s"), fmt);
if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
@@ -442,6 +454,26 @@ size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder)
return 0;
}
+void strbuf_expand_bad_format(const char *format, const char *command)
+{
+ const char *end;
+
+ if (*format != '(')
+ /* TRANSLATORS: The first %s is a command like "ls-tree". */
+ die(_("bad %s format: element '%s' does not start with '('"),
+ command, format);
+
+ end = strchr(format + 1, ')');
+ if (!end)
+ /* TRANSLATORS: The first %s is a command like "ls-tree". */
+ die(_("bad %s format: element '%s' does not end in ')'"),
+ command, format);
+
+ /* TRANSLATORS: %s is a command like "ls-tree". */
+ die(_("bad %s format: %%%.*s"),
+ command, (int)(end - format + 1), format);
+}
+
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
{
size_t i, len = src->len;
@@ -668,8 +700,10 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
int strbuf_appendwholeline(struct strbuf *sb, FILE *fp, int term)
{
struct strbuf line = STRBUF_INIT;
- if (strbuf_getwholeline(&line, fp, term))
+ if (strbuf_getwholeline(&line, fp, term)) {
+ strbuf_release(&line);
return EOF;
+ }
strbuf_addbuf(sb, &line);
strbuf_release(&line);
return 0;
@@ -750,7 +784,7 @@ ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
void strbuf_add_lines(struct strbuf *out, const char *prefix,
const char *buf, size_t size)
{
- add_lines(out, prefix, NULL, buf, size);
+ add_lines(out, prefix, buf, size, 0);
}
void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
@@ -1005,10 +1039,10 @@ static size_t cleanup(char *line, size_t len)
*
* If last line does not have a newline at the end, one is added.
*
- * Pass a non-NUL comment_line_char to skip every line starting
+ * Pass a non-NULL comment_prefix to skip every line starting
* with it.
*/
-void strbuf_stripspace(struct strbuf *sb, char comment_line_char)
+void strbuf_stripspace(struct strbuf *sb, const char *comment_prefix)
{
size_t empties = 0;
size_t i, j, len, newlen;
@@ -1021,8 +1055,8 @@ void strbuf_stripspace(struct strbuf *sb, char comment_line_char)
eol = memchr(sb->buf + i, '\n', sb->len - i);
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
- if (comment_line_char && len &&
- sb->buf[i] == comment_line_char) {
+ if (comment_prefix && len &&
+ starts_with(sb->buf + i, comment_prefix)) {
newlen = 0;
continue;
}
diff --git a/strbuf.h b/strbuf.h
index fd43c46433..003f880ff7 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -12,9 +12,9 @@
struct string_list;
/**
- * strbuf's are meant to be used with all the usual C string and memory
+ * strbufs are meant to be used with all the usual C string and memory
* APIs. Given that the length of the buffer is known, it's often better to
- * use the mem* functions than a str* one (memchr vs. strchr e.g.).
+ * use the mem* functions than a str* one (e.g., memchr vs. strchr).
* Though, one has to be careful about the fact that str* functions often
* stop on NULs and that strbufs may have embedded NULs.
*
@@ -24,7 +24,7 @@ struct string_list;
* strbufs have some invariants that are very important to keep in mind:
*
* - The `buf` member is never NULL, so it can be used in any usual C
- * string operations safely. strbuf's _have_ to be initialized either by
+ * string operations safely. strbufs _have_ to be initialized either by
* `strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
*
* Do *not* assume anything on what `buf` really is (e.g. if it is
@@ -37,7 +37,7 @@ struct string_list;
*
* - The `buf` member is a byte array that has at least `len + 1` bytes
* allocated. The extra byte is used to store a `'\0'`, allowing the
- * `buf` member to be a valid C-string. Every strbuf function ensure this
+ * `buf` member to be a valid C-string. All strbuf functions ensure this
* invariant is preserved.
*
* NOTE: It is OK to "play" with the buffer directly if you work it this
@@ -288,7 +288,7 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
*/
void strbuf_add_commented_lines(struct strbuf *out,
const char *buf, size_t size,
- char comment_line_char);
+ const char *comment_prefix);
/**
@@ -311,6 +311,11 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s)
}
/**
+ * Add a NUL-terminated string the specified number of times to the buffer.
+ */
+void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n);
+
+/**
* Copy the contents of another buffer at the end of the current one.
*/
void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
@@ -338,6 +343,11 @@ size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder);
int strbuf_expand_step(struct strbuf *sb, const char **formatp);
/**
+ * Used with `strbuf_expand_step` to report unknown placeholders.
+ */
+void strbuf_expand_bad_format(const char *format, const char *command);
+
+/**
* Append the contents of one strbuf to another, quoting any
* percent signs ("%") into double-percents ("%%") in the
* destination. This is useful for literal data to be fed to either
@@ -379,7 +389,7 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
* blank to the buffer.
*/
__attribute__((format (printf, 3, 4)))
-void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);
+void strbuf_commented_addf(struct strbuf *sb, const char *comment_prefix, const char *fmt, ...);
__attribute__((format (printf,2,0)))
void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
@@ -513,11 +523,11 @@ int strbuf_getcwd(struct strbuf *sb);
int strbuf_normalize_path(struct strbuf *sb);
/**
- * Strip whitespace from a buffer. If comment_line_char is non-NUL,
+ * Strip whitespace from a buffer. If comment_prefix is non-NULL,
* then lines beginning with that character are considered comments,
* thus removed.
*/
-void strbuf_stripspace(struct strbuf *buf, char comment_line_char);
+void strbuf_stripspace(struct strbuf *buf, const char *comment_prefix);
static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
{
@@ -673,6 +683,7 @@ char *xstrfmt(const char *fmt, ...);
int starts_with(const char *str, const char *prefix);
int istarts_with(const char *str, const char *prefix);
+int starts_with_mem(const char *str, size_t len, const char *prefix);
/*
* If the string "str" is the same as the string in "prefix", then the "arg"
diff --git a/streaming.c b/streaming.c
index 10adf625b2..38839511af 100644
--- a/streaming.c
+++ b/streaming.c
@@ -1,6 +1,9 @@
/*
* Copyright (c) 2011, Google Inc.
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "convert.h"
#include "environment.h"
diff --git a/strvec.c b/strvec.c
index 89dc9e7e75..d1cf4e2496 100644
--- a/strvec.c
+++ b/strvec.c
@@ -1,6 +1,5 @@
#include "git-compat-util.h"
#include "strvec.h"
-#include "hex.h"
#include "strbuf.h"
const char *empty_strvec[] = { NULL };
@@ -11,7 +10,7 @@ void strvec_init(struct strvec *array)
memcpy(array, &blank, sizeof(*array));
}
-static void strvec_push_nodup(struct strvec *array, const char *value)
+void strvec_push_nodup(struct strvec *array, char *value)
{
if (array->v == empty_strvec)
array->v = NULL;
@@ -57,6 +56,45 @@ void strvec_pushv(struct strvec *array, const char **items)
strvec_push(array, *items);
}
+void strvec_splice(struct strvec *array, size_t idx, size_t len,
+ const char **replacement, size_t replacement_len)
+{
+ if (idx + len > array->nr)
+ BUG("range outside of array boundary");
+ if (replacement_len > len)
+ ALLOC_GROW(array->v, array->nr + (replacement_len - len) + 1,
+ array->alloc);
+ for (size_t i = 0; i < len; i++)
+ free((char *)array->v[idx + i]);
+ if (replacement_len != len) {
+ memmove(array->v + idx + replacement_len, array->v + idx + len,
+ (array->nr - idx - len + 1) * sizeof(char *));
+ array->nr += (replacement_len - len);
+ }
+ for (size_t i = 0; i < replacement_len; i++)
+ array->v[idx + i] = xstrdup(replacement[i]);
+}
+
+const char *strvec_replace(struct strvec *array, size_t idx, const char *replacement)
+{
+ char *to_free;
+ if (idx >= array->nr)
+ BUG("index outside of array boundary");
+ to_free = (char *) array->v[idx];
+ array->v[idx] = xstrdup(replacement);
+ free(to_free);
+ return array->v[idx];
+}
+
+void strvec_remove(struct strvec *array, size_t idx)
+{
+ if (idx >= array->nr)
+ BUG("index outside of array boundary");
+ free((char *)array->v[idx]);
+ memmove(array->v + idx, array->v + idx + 1, (array->nr - idx) * sizeof(char *));
+ array->nr--;
+}
+
void strvec_pop(struct strvec *array)
{
if (!array->nr)
diff --git a/strvec.h b/strvec.h
index 9f55c8766b..f74e061e14 100644
--- a/strvec.h
+++ b/strvec.h
@@ -4,8 +4,8 @@
/**
* The strvec API allows one to dynamically build and store
* NULL-terminated arrays of strings. A strvec maintains the invariant that the
- * `items` member always points to a non-NULL array, and that the array is
- * always NULL-terminated at the element pointed to by `items[nr]`. This
+ * `v` member always points to a non-NULL array, and that the array is
+ * always NULL-terminated at the element pointed to by `v[nr]`. This
* makes the result suitable for passing to functions expecting to receive
* argv from main().
*
@@ -22,7 +22,7 @@ extern const char *empty_strvec[];
/**
* A single array. This should be initialized by assignment from
- * `STRVEC_INIT`, or by calling `strvec_init`. The `items`
+ * `STRVEC_INIT`, or by calling `strvec_init`. The `v`
* member contains the actual array; the `nr` member contains the
* number of elements in the array, not including the terminating
* NULL.
@@ -46,6 +46,9 @@ void strvec_init(struct strvec *);
/* Push a copy of a string onto the end of the array. */
const char *strvec_push(struct strvec *, const char *);
+/* Push an allocated string onto the end of the array, taking ownership. */
+void strvec_push_nodup(struct strvec *array, char *value);
+
/**
* Format a string and push it onto the end of the array. This is a
* convenience wrapper combining `strbuf_addf` and `strvec_push`.
@@ -64,6 +67,28 @@ void strvec_pushl(struct strvec *, ...);
/* Push a null-terminated array of strings onto the end of the array. */
void strvec_pushv(struct strvec *, const char **);
+/*
+ * Replace `len` values starting at `idx` with the provided replacement
+ * strings. If `len` is zero this is effectively an insert at the given `idx`.
+ * If `replacement_len` is zero this is effectively a delete of `len` items
+ * starting at `idx`.
+ */
+void strvec_splice(struct strvec *array, size_t idx, size_t len,
+ const char **replacement, size_t replacement_len);
+
+/**
+ * Replace the value at the given index with a new value. The index must be
+ * valid. Returns a pointer to the inserted value.
+ */
+const char *strvec_replace(struct strvec *array, size_t idx, const char *replacement);
+
+/*
+ * Remove the value at the given index. The remainder of the array will be
+ * moved to fill the resulting gap. The provided index must point into the
+ * array.
+ */
+void strvec_remove(struct strvec *array, size_t idx);
+
/**
* Remove the final element from the array. If there are no
* elements in the array, do nothing.
@@ -80,7 +105,7 @@ void strvec_split(struct strvec *, const char *);
void strvec_clear(struct strvec *);
/**
- * Disconnect the `items` member from the `strvec` struct and
+ * Disconnect the `v` member from the `strvec` struct and
* return it. The caller is responsible for freeing the memory used
* by the array, and by the strings it references. After detaching,
* the `strvec` is in a reinitialized state and can be pushed
diff --git a/submodule-config.c b/submodule-config.c
index 6a48fd12f6..9c8c37b259 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "dir.h"
#include "environment.h"
@@ -14,6 +16,8 @@
#include "parse-options.h"
#include "thread-utils.h"
#include "tree-walk.h"
+#include "url.h"
+#include "urlmatch.h"
/*
* submodule cache lookup structure
@@ -89,7 +93,9 @@ static void free_one_config(struct submodule_entry *entry)
free((void *) entry->config->path);
free((void *) entry->config->name);
free((void *) entry->config->branch);
- free((void *) entry->config->update_strategy.command);
+ free((void *) entry->config->url);
+ free((void *) entry->config->ignore);
+ submodule_update_strategy_release(&entry->config->update_strategy);
free(entry->config);
}
@@ -228,6 +234,144 @@ in_component:
return 0;
}
+static int starts_with_dot_slash(const char *const path)
+{
+ return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
+ PATH_MATCH_XPLATFORM);
+}
+
+static int starts_with_dot_dot_slash(const char *const path)
+{
+ return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
+ PATH_MATCH_XPLATFORM);
+}
+
+static int submodule_url_is_relative(const char *url)
+{
+ return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
+}
+
+/*
+ * Count directory components that a relative submodule URL should chop
+ * from the remote_url it is to be resolved against.
+ *
+ * In other words, this counts "../" components at the start of a
+ * submodule URL.
+ *
+ * Returns the number of directory components to chop and writes a
+ * pointer to the next character of url after all leading "./" and
+ * "../" components to out.
+ */
+static int count_leading_dotdots(const char *url, const char **out)
+{
+ int result = 0;
+ while (1) {
+ if (starts_with_dot_dot_slash(url)) {
+ result++;
+ url += strlen("../");
+ continue;
+ }
+ if (starts_with_dot_slash(url)) {
+ url += strlen("./");
+ continue;
+ }
+ *out = url;
+ return result;
+ }
+}
+/*
+ * Check whether a transport is implemented by git-remote-curl.
+ *
+ * If it is, returns 1 and writes the URL that would be passed to
+ * git-remote-curl to the "out" parameter.
+ *
+ * Otherwise, returns 0 and leaves "out" untouched.
+ *
+ * Examples:
+ * http::https://example.com/repo.git -> 1, https://example.com/repo.git
+ * https://example.com/repo.git -> 1, https://example.com/repo.git
+ * git://example.com/repo.git -> 0
+ *
+ * This is for use in checking for previously exploitable bugs that
+ * required a submodule URL to be passed to git-remote-curl.
+ */
+static int url_to_curl_url(const char *url, const char **out)
+{
+ /*
+ * We don't need to check for case-aliases, "http.exe", and so
+ * on because in the default configuration, is_transport_allowed
+ * prevents URLs with those schemes from being cloned
+ * automatically.
+ */
+ if (skip_prefix(url, "http::", out) ||
+ skip_prefix(url, "https::", out) ||
+ skip_prefix(url, "ftp::", out) ||
+ skip_prefix(url, "ftps::", out))
+ return 1;
+ if (starts_with(url, "http://") ||
+ starts_with(url, "https://") ||
+ starts_with(url, "ftp://") ||
+ starts_with(url, "ftps://")) {
+ *out = url;
+ return 1;
+ }
+ return 0;
+}
+
+int check_submodule_url(const char *url)
+{
+ const char *curl_url;
+
+ if (looks_like_command_line_option(url))
+ return -1;
+
+ if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
+ char *decoded;
+ const char *next;
+ int has_nl;
+
+ /*
+ * This could be appended to an http URL and url-decoded;
+ * check for malicious characters.
+ */
+ decoded = url_decode(url);
+ has_nl = !!strchr(decoded, '\n');
+
+ free(decoded);
+ if (has_nl)
+ return -1;
+
+ /*
+ * URLs which escape their root via "../" can overwrite
+ * the host field and previous components, resolving to
+ * URLs like https::example.com/submodule.git and
+ * https:///example.com/submodule.git that were
+ * susceptible to CVE-2020-11008.
+ */
+ if (count_leading_dotdots(url, &next) > 0 &&
+ (*next == ':' || *next == '/'))
+ return -1;
+ }
+
+ else if (url_to_curl_url(url, &curl_url)) {
+ int ret = 0;
+ char *normalized = url_normalize(curl_url, NULL);
+ if (normalized) {
+ char *decoded = url_decode(normalized);
+ if (strchr(decoded, '\n'))
+ ret = -1;
+ free(normalized);
+ free(decoded);
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+ }
+
+ return 0;
+}
+
static int name_and_item_from_var(const char *var, struct strbuf *name,
struct strbuf *item)
{
@@ -516,7 +660,9 @@ static int parse_config(const char *var, const char *value,
submodule->recommend_shallow =
git_config_bool(var, value);
} else if (!strcmp(item.buf, "branch")) {
- if (!me->overwrite && submodule->branch)
+ if (!value)
+ ret = config_error_nonbool(var);
+ else if (!me->overwrite && submodule->branch)
warn_multiple_config(me->treeish_name, submodule->name,
"branch");
else {
@@ -538,7 +684,7 @@ static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
int ret = 0;
if (is_null_oid(treeish_name)) {
- oidclr(gitmodules_oid);
+ oidclr(gitmodules_oid, the_repository->hash_algo);
return 1;
}
@@ -753,27 +899,26 @@ static void traverse_tree_submodules(struct repository *r,
{
struct tree_desc tree;
struct submodule_tree_entry *st_entry;
- struct name_entry *name_entry;
+ struct name_entry name_entry;
char *tree_path = NULL;
+ char *tree_buf;
- name_entry = xmalloc(sizeof(*name_entry));
-
- fill_tree_descriptor(r, &tree, treeish_name);
- while (tree_entry(&tree, name_entry)) {
+ tree_buf = fill_tree_descriptor(r, &tree, treeish_name);
+ while (tree_entry(&tree, &name_entry)) {
if (prefix)
tree_path =
- mkpathdup("%s/%s", prefix, name_entry->path);
+ mkpathdup("%s/%s", prefix, name_entry.path);
else
- tree_path = xstrdup(name_entry->path);
+ tree_path = xstrdup(name_entry.path);
- if (S_ISGITLINK(name_entry->mode) &&
+ if (S_ISGITLINK(name_entry.mode) &&
is_tree_submodule_active(r, root_tree, tree_path)) {
ALLOC_GROW(out->entries, out->entry_nr + 1,
out->entry_alloc);
st_entry = &out->entries[out->entry_nr++];
st_entry->name_entry = xmalloc(sizeof(*st_entry->name_entry));
- *st_entry->name_entry = *name_entry;
+ *st_entry->name_entry = name_entry;
st_entry->submodule =
submodule_from_path(r, root_tree, tree_path);
st_entry->repo = xmalloc(sizeof(*st_entry->repo));
@@ -781,11 +926,13 @@ static void traverse_tree_submodules(struct repository *r,
root_tree))
FREE_AND_NULL(st_entry->repo);
- } else if (S_ISDIR(name_entry->mode))
+ } else if (S_ISDIR(name_entry.mode))
traverse_tree_submodules(r, root_tree, tree_path,
- &name_entry->oid, out);
+ &name_entry.oid, out);
free(tree_path);
}
+
+ free(tree_buf);
}
void submodules_of_tree(struct repository *r,
@@ -799,6 +946,16 @@ void submodules_of_tree(struct repository *r,
traverse_tree_submodules(r, treeish_name, NULL, treeish_name, out);
}
+void submodule_entry_list_release(struct submodule_entry_list *list)
+{
+ for (size_t i = 0; i < list->entry_nr; i++) {
+ free(list->entries[i].name_entry);
+ repo_clear(list->entries[i].repo);
+ free(list->entries[i].repo);
+ }
+ free(list->entries);
+}
+
void submodule_free(struct repository *r)
{
if (r->submodule_cache)
@@ -836,7 +993,7 @@ int config_set_in_gitmodules_file_gently(const char *key, const char *value)
{
int ret;
- ret = git_config_set_in_file_gently(GITMODULES_FILE, key, value);
+ ret = git_config_set_in_file_gently(GITMODULES_FILE, key, NULL, value);
if (ret < 0)
/* Maybe the user already did that, don't error out here */
warning(_("Could not update .gitmodules entry %s"), key);
diff --git a/submodule-config.h b/submodule-config.h
index 2a37689cc2..f55d4e3b61 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -2,9 +2,7 @@
#define SUBMODULE_CONFIG_CACHE_H
#include "config.h"
-#include "hashmap.h"
#include "submodule.h"
-#include "strbuf.h"
#include "tree-walk.h"
/**
@@ -91,6 +89,9 @@ int config_set_in_gitmodules_file_gently(const char *key, const char *value);
*/
int check_submodule_name(const char *name);
+/* Returns 0 if the URL valid per RFC3986 and -1 otherwise. */
+int check_submodule_url(const char *url);
+
/*
* Note: these helper functions exist solely to maintain backward
* compatibility with 'fetch' and 'update_clone' storing configuration in
@@ -135,4 +136,7 @@ struct submodule_entry_list {
void submodules_of_tree(struct repository *r,
const struct object_id *treeish_name,
struct submodule_entry_list *ret);
+
+void submodule_entry_list_release(struct submodule_entry_list *list);
+
#endif /* SUBMODULE_CONFIG_H */
diff --git a/submodule.c b/submodule.c
index e425122075..7ec564854d 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "repository.h"
@@ -17,10 +19,8 @@
#include "string-list.h"
#include "oid-array.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"
@@ -30,7 +30,6 @@
#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;
@@ -102,7 +101,8 @@ int is_staging_gitmodules_ok(struct index_state *istate)
static int for_each_remote_ref_submodule(const char *submodule,
each_ref_fn fn, void *cb_data)
{
- return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
+ return refs_for_each_remote_ref(repo_get_submodule_ref_store(the_repository,
+ submodule),
fn, cb_data);
}
@@ -159,7 +159,7 @@ int remove_path_from_gitmodules(const char *path)
}
strbuf_addstr(&sect, "submodule.");
strbuf_addstr(&sect, submodule->name);
- if (git_config_rename_section_in_file(GITMODULES_FILE, sect.buf, NULL) < 0) {
+ if (repo_config_rename_section_in_file(the_repository, GITMODULES_FILE, sect.buf, NULL) < 0) {
/* Maybe the user already did that, don't error out here */
warning(_("Could not remove .gitmodules entry for %s"), path);
strbuf_release(&sect);
@@ -175,11 +175,11 @@ void stage_updated_gitmodules(struct index_state *istate)
die(_("staging updated .gitmodules failed"));
}
-static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_NODUP;
+static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_DUP;
void add_submodule_odb_by_path(const char *path)
{
- string_list_insert(&added_submodule_odb_paths, xstrdup(path));
+ string_list_insert(&added_submodule_odb_paths, path);
}
int register_all_submodule_odb_as_alternates(void)
@@ -424,6 +424,11 @@ int parse_submodule_update_strategy(const char *value,
return 0;
}
+void submodule_update_strategy_release(struct submodule_update_strategy *strategy)
+{
+ free((char *) strategy->command);
+}
+
const char *submodule_update_type_to_string(enum submodule_update_type type)
{
switch (type) {
@@ -595,7 +600,12 @@ static void show_submodule_header(struct diff_options *o,
(!is_null_oid(two) && !*right))
message = "(commits not present)";
- *merge_bases = repo_get_merge_bases(sub, *left, *right);
+ *merge_bases = NULL;
+ if (repo_get_merge_bases(sub, *left, *right, merge_bases) < 0) {
+ message = "(corrupt repository)";
+ goto output_header;
+ }
+
if (*merge_bases) {
if ((*merge_bases)->item == *left)
fast_forward = 1;
@@ -948,6 +958,7 @@ static void free_submodules_data(struct string_list *submodules)
}
static int has_remote(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data UNUSED)
{
@@ -1163,8 +1174,8 @@ static int push_submodule(const char *path,
if (remote->origin != REMOTE_UNCONFIGURED) {
int i;
strvec_push(&cp.args, remote->name);
- for (i = 0; i < rs->raw_nr; i++)
- strvec_push(&cp.args, rs->raw[i]);
+ for (i = 0; i < rs->nr; i++)
+ strvec_push(&cp.args, rs->items[i].raw);
}
prepare_submodule_repo_env(&cp.env);
@@ -1198,8 +1209,8 @@ static void submodule_push_check(const char *path, const char *head,
strvec_push(&cp.args, head);
strvec_push(&cp.args, remote->name);
- for (i = 0; i < rs->raw_nr; i++)
- strvec_push(&cp.args, rs->raw[i]);
+ for (i = 0; i < rs->nr; i++)
+ strvec_push(&cp.args, rs->items[i].raw);
prepare_submodule_repo_env(&cp.env);
cp.git_cmd = 1;
@@ -1240,7 +1251,8 @@ int push_unpushed_submodules(struct repository *r,
char *head;
struct object_id head_oid;
- head = resolve_refdup("HEAD", 0, &head_oid, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
@@ -1267,6 +1279,7 @@ int push_unpushed_submodules(struct repository *r,
}
static int append_oid_to_array(const char *ref UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *data)
{
@@ -1278,7 +1291,8 @@ static int append_oid_to_array(const char *ref UNUSED,
void check_for_new_submodule_commits(struct object_id *oid)
{
if (!initialized_fetch_ref_tips) {
- for_each_ref(append_oid_to_array, &ref_tips_before_fetch);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ append_oid_to_array, &ref_tips_before_fetch);
initialized_fetch_ref_tips = 1;
}
@@ -1489,7 +1503,7 @@ static const struct submodule *get_non_gitmodules_submodule(const char *path)
return (const struct submodule *) ret;
}
-static void fetch_task_release(struct fetch_task *p)
+static void fetch_task_free(struct fetch_task *p)
{
if (p->free_sub)
free((void*)p->sub);
@@ -1501,6 +1515,7 @@ static void fetch_task_release(struct fetch_task *p)
FREE_AND_NULL(p->repo);
strvec_clear(&p->git_args);
+ free(p);
}
static struct repository *get_submodule_repo_for(struct repository *r,
@@ -1569,8 +1584,7 @@ static struct fetch_task *fetch_task_create(struct submodule_parallel_fetch *spf
return task;
cleanup:
- fetch_task_release(task);
- free(task);
+ fetch_task_free(task);
return NULL;
}
@@ -1600,8 +1614,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
} else {
struct strbuf empty_submodule_path = STRBUF_INIT;
- fetch_task_release(task);
- free(task);
+ fetch_task_free(task);
/*
* An empty directory is normal,
@@ -1647,8 +1660,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
cs_data->path,
repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV));
- fetch_task_release(task);
- free(task);
+ fetch_task_free(task);
continue;
}
@@ -1702,8 +1714,6 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
task = get_fetch_task_from_changed(spf, err);
if (task) {
- struct strbuf submodule_prefix = STRBUF_INIT;
-
child_process_init(cp);
cp->dir = task->repo->gitdir;
prepare_submodule_repo_env_in_gitdir(&cp->env);
@@ -1713,15 +1723,11 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
strvec_pushv(&cp->args, task->git_args.v);
strvec_pushv(&cp->args, spf->args.v);
strvec_push(&cp->args, task->default_argv);
- strvec_push(&cp->args, "--submodule-prefix");
+ strvec_pushf(&cp->args, "--submodule-prefix=%s%s/",
+ spf->prefix, task->sub->path);
- strbuf_addf(&submodule_prefix, "%s%s/",
- spf->prefix,
- task->sub->path);
- strvec_push(&cp->args, submodule_prefix.buf);
*task_cb = task;
- strbuf_release(&submodule_prefix);
string_list_insert(&spf->seen_submodule_names, task->sub->name);
return 1;
}
@@ -1729,12 +1735,8 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
if (spf->oid_fetch_tasks_nr) {
struct fetch_task *task =
spf->oid_fetch_tasks[spf->oid_fetch_tasks_nr - 1];
- struct strbuf submodule_prefix = STRBUF_INIT;
spf->oid_fetch_tasks_nr--;
- strbuf_addf(&submodule_prefix, "%s%s/",
- spf->prefix, task->sub->path);
-
child_process_init(cp);
prepare_submodule_repo_env_in_gitdir(&cp->env);
cp->git_cmd = 1;
@@ -1743,8 +1745,8 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
strvec_init(&cp->args);
strvec_pushv(&cp->args, spf->args.v);
strvec_push(&cp->args, "on-demand");
- strvec_push(&cp->args, "--submodule-prefix");
- strvec_push(&cp->args, submodule_prefix.buf);
+ strvec_pushf(&cp->args, "--submodule-prefix=%s%s/",
+ spf->prefix, task->sub->path);
/* NEEDSWORK: have get_default_remote from submodule--helper */
strvec_push(&cp->args, "origin");
@@ -1752,7 +1754,6 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
append_oid_to_argv, &cp->args);
*task_cb = task;
- strbuf_release(&submodule_prefix);
return 1;
}
@@ -1767,7 +1768,7 @@ static int fetch_start_failure(struct strbuf *err UNUSED,
spf->result = 1;
- fetch_task_release(task);
+ fetch_task_free(task);
return 0;
}
@@ -1832,8 +1833,7 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
}
out:
- fetch_task_release(task);
-
+ fetch_task_free(task);
return 0;
}
@@ -1887,6 +1887,9 @@ int fetch_submodules(struct repository *r,
strvec_clear(&spf.args);
out:
free_submodules_data(&spf.changed_submodule_names);
+ string_list_clear(&spf.seen_submodule_names, 0);
+ strbuf_release(&spf.submodules_with_errors);
+ free(spf.oid_fetch_tasks);
return spf.result;
}
@@ -2079,7 +2082,7 @@ void submodule_unset_core_worktree(const struct submodule *sub)
submodule_name_to_gitdir(&config_path, the_repository, sub->name);
strbuf_addstr(&config_path, "/config");
- if (git_config_set_in_file_gently(config_path.buf, "core.worktree", NULL))
+ if (git_config_set_in_file_gently(config_path.buf, "core.worktree", NULL, NULL))
warning(_("Could not unset core.worktree setting in submodule '%s'"),
sub->path);
@@ -2125,7 +2128,7 @@ static void submodule_reset_index(const char *path, const char *super_prefix)
strvec_pushf(&cp.args, "--super-prefix=%s%s/",
(super_prefix ? super_prefix : ""), path);
- strvec_push(&cp.args, empty_tree_oid_hex());
+ strvec_push(&cp.args, empty_tree_oid_hex(the_repository->hash_algo));
if (run_command(&cp))
die(_("could not reset submodule index"));
@@ -2235,9 +2238,9 @@ int submodule_move_head(const char *path, const char *super_prefix,
strvec_push(&cp.args, "-m");
if (!(flags & SUBMODULE_MOVE_HEAD_FORCE))
- strvec_push(&cp.args, old_head ? old_head : empty_tree_oid_hex());
+ strvec_push(&cp.args, old_head ? old_head : empty_tree_oid_hex(the_repository->hash_algo));
- strvec_push(&cp.args, new_head ? new_head : empty_tree_oid_hex());
+ strvec_push(&cp.args, new_head ? new_head : empty_tree_oid_hex(the_repository->hash_algo));
if (run_command(&cp)) {
ret = error(_("Submodule '%s' could not be updated."), path);
@@ -2466,7 +2469,7 @@ void absorb_git_dir_into_superproject(const char *path,
} else {
/* Is it already absorbed into the superprojects git dir? */
char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
- char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
+ char *real_common_git_dir = real_pathdup(repo_get_common_dir(the_repository), 1);
if (!starts_with(real_sub_git_dir, real_common_git_dir))
relocate_single_git_dir_into_superproject(path, super_prefix);
diff --git a/submodule.h b/submodule.h
index b50d29eba4..4deb1b5f84 100644
--- a/submodule.h
+++ b/submodule.h
@@ -41,6 +41,10 @@ struct submodule_update_strategy {
.type = SM_UPDATE_UNSPECIFIED, \
}
+int parse_submodule_update_strategy(const char *value,
+ struct submodule_update_strategy *dst);
+void submodule_update_strategy_release(struct submodule_update_strategy *strategy);
+
int is_gitmodules_unmerged(struct index_state *istate);
int is_writing_gitmodules_ok(void);
int is_staging_gitmodules_ok(struct index_state *istate);
@@ -70,8 +74,6 @@ void die_in_unpopulated_submodule(struct index_state *istate,
void die_path_inside_submodule(struct index_state *istate,
const struct pathspec *ps);
enum submodule_update_type parse_submodule_update_type(const char *value);
-int parse_submodule_update_strategy(const char *value,
- struct submodule_update_strategy *dst);
const char *submodule_update_type_to_string(enum submodule_update_type type);
void handle_ignore_submodules_arg(struct diff_options *, const char *);
void show_submodule_diff_summary(struct diff_options *o, const char *path,
diff --git a/t/.gitattributes b/t/.gitattributes
index b9cea1795d..7664c6e027 100644
--- a/t/.gitattributes
+++ b/t/.gitattributes
@@ -1,5 +1,5 @@
t[0-9][0-9][0-9][0-9]/* -whitespace
-/chainlint/*.expect eol=lf
+/chainlint/*.expect eol=lf -whitespace
/t0110/url-* binary
/t3206/* eol=lf
/t3900/*.txt eol=lf
diff --git a/t/Makefile b/t/Makefile
index 3e00cdd801..131ffd778f 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
# Import tree-wide shared Makefile behavior and libraries
include ../shared.mak
@@ -6,6 +9,7 @@ include ../shared.mak
# Copyright (c) 2005 Junio C Hamano
#
+-include ../config.mak.uname
-include ../config.mak.autogen
-include ../config.mak
@@ -17,6 +21,7 @@ TAR ?= $(TAR)
RM ?= rm -f
PROVE ?= prove
DEFAULT_TEST_TARGET ?= test
+DEFAULT_UNIT_TEST_TARGET ?= unit-tests-raw
TEST_LINT ?= test-lint
ifdef TEST_OUTPUT_DIRECTORY
@@ -41,13 +46,18 @@ TPERF = $(sort $(wildcard perf/p[0-9][0-9][0-9][0-9]-*.sh))
TINTEROP = $(sort $(wildcard interop/i[0-9][0-9][0-9][0-9]-*.sh))
CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.test)))
CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl
+UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c)
+UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES))
+UNIT_TEST_PROGRAMS += unit-tests/bin/unit-tests$(X)
+UNIT_TESTS = $(sort $(UNIT_TEST_PROGRAMS))
+UNIT_TESTS_NO_DIR = $(notdir $(UNIT_TESTS))
# `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 run the external "chainlint.pl" script themselves
CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT &&
-all: $(DEFAULT_TEST_TARGET)
+all:: $(DEFAULT_TEST_TARGET)
test: pre-clean check-chainlint $(TEST_LINT)
$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup
@@ -59,12 +69,31 @@ failed:
test -z "$$failed" || $(MAKE) $$failed
prove: pre-clean check-chainlint $(TEST_LINT)
- @echo "*** prove ***"; $(CHAINLINTSUPPRESS) $(PROVE) --exec '$(TEST_SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
+ @echo "*** prove (shell & unit tests) ***"
+ @$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
$(MAKE) clean-except-prove-cache
$(T):
@echo "*** $@ ***"; '$(TEST_SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
+$(UNIT_TESTS):
+ @echo "*** $@ ***"; $@
+
+.PHONY: unit-tests unit-tests-raw unit-tests-prove unit-tests-test-tool
+unit-tests: $(DEFAULT_UNIT_TEST_TARGET)
+
+unit-tests-raw: $(UNIT_TESTS)
+
+unit-tests-prove:
+ @echo "*** prove - unit tests ***"; $(PROVE) $(GIT_PROVE_OPTS) $(UNIT_TESTS)
+
+unit-tests-test-tool:
+ @echo "*** test-tool - unit tests **"
+ ( \
+ cd unit-tests/bin && \
+ ../../helper/test-tool$X run-command testsuite $(UNIT_TESTS_NO_DIR)\
+ )
+
pre-clean:
$(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
@@ -81,29 +110,9 @@ clean-chainlint:
check-chainlint:
@mkdir -p '$(CHAINLINTTMP_SQ)' && \
- for i in $(CHAINLINTTESTS); do \
- echo "test_expect_success '$$i' '" && \
- sed -e '/^# LINT: /d' chainlint/$$i.test && \
- echo "'"; \
- done >'$(CHAINLINTTMP_SQ)'/tests && \
- { \
- echo "# chainlint: $(CHAINLINTTMP_SQ)/tests" && \
- for i in $(CHAINLINTTESTS); do \
- echo "# chainlint: $$i" && \
- sed -e '/^[ ]*$$/d' chainlint/$$i.expect; \
- done \
- } >'$(CHAINLINTTMP_SQ)'/expect && \
- $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests | \
- sed -e 's/^[1-9][0-9]* //;/^[ ]*$$/d' >'$(CHAINLINTTMP_SQ)'/actual && \
- if test -f ../GIT-BUILD-OPTIONS; then \
- . ../GIT-BUILD-OPTIONS; \
- fi && \
- if test -x ../git$$X; then \
- DIFFW="../git$$X --no-pager diff -w --no-index"; \
- else \
- DIFFW="diff -w -u"; \
- fi && \
- $$DIFFW '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual
+ '$(PERL_PATH_SQ)' chainlint-cat.pl '$(CHAINLINTTMP_SQ)' $(CHAINLINTTESTS) && \
+ { $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests >'$(CHAINLINTTMP_SQ)'/actual || true; } && \
+ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual
test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
test-lint-filenames
@@ -149,4 +158,4 @@ perf:
$(MAKE) -C perf/ all
.PHONY: pre-clean $(T) aggregate-results clean valgrind perf \
- check-chainlint clean-chainlint test-chainlint
+ check-chainlint clean-chainlint test-chainlint $(UNIT_TESTS)
diff --git a/t/README b/t/README
index 6108085989..e84824dc00 100644
--- a/t/README
+++ b/t/README
@@ -32,7 +32,14 @@ the tests.
ok 2 - plain with GIT_WORK_TREE
ok 3 - plain bare
-Since the tests all output TAP (see http://testanything.org) they can
+t/Makefile defines a target for each test file, such that you can also use
+shell pattern matching to run a subset of the tests:
+
+ make *checkout*
+
+will run all tests with 'checkout' in their filename.
+
+Since the tests all output TAP (see https://testanything.org) they can
be run with any TAP harness. Here's an example of parallel testing
powered by a recent version of prove(1):
@@ -262,8 +269,8 @@ The argument for --run, <test-selector>, is a list of description
substrings or globs or individual test numbers or ranges with an
optional negation prefix (of '!') that define what tests in a test
suite to include (or exclude, if negated) in the run. A range is two
-numbers separated with a dash and matches a range of tests with both
-ends been included. You may omit the first or the second number to
+numbers separated with a dash and specifies an inclusive range of tests
+to run. You may omit the first or the second number to
mean "from the first test" or "up to the very last test" respectively.
The argument to --run is split on commas into separate strings,
@@ -274,10 +281,10 @@ text that you want to match includes a comma, use the glob character
on all tests that match either the glob *rebase* or the glob
*merge?cherry-pick*.
-If --run starts with an unprefixed number or range the initial
-set of tests to run is empty. If the first item starts with '!'
+If --run starts with an unprefixed number or range, the initial
+set of tests to run is empty. If the first item starts with '!',
all the tests are added to the initial set. After initial set is
-determined every test number or range is added or excluded from
+determined, every test number or range is added or excluded from
the set one by one, from left to right.
For example, to run only tests up to a specific test (21), one
@@ -361,48 +368,6 @@ excluded as so much relies on it, but this might change in the future.
GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole
test suite. Accept any boolean values that are accepted by git-config.
-GIT_TEST_PASSING_SANITIZE_LEAK=true skips those tests that haven't
-declared themselves as leak-free by setting
-"TEST_PASSES_SANITIZE_LEAK=true" before sourcing "test-lib.sh". This
-test mode is used by the "linux-leaks" CI target.
-
-GIT_TEST_PASSING_SANITIZE_LEAK=check checks that our
-"TEST_PASSES_SANITIZE_LEAK=true" markings are current. Rather than
-skipping those tests that haven't set "TEST_PASSES_SANITIZE_LEAK=true"
-before sourcing "test-lib.sh" this mode runs them with
-"--invert-exit-code". This is used to check that there's a one-to-one
-mapping between "TEST_PASSES_SANITIZE_LEAK=true" and those tests that
-pass under "SANITIZE=leak". This is especially useful when testing a
-series that fixes various memory leaks with "git rebase -x".
-
-GIT_TEST_SANITIZE_LEAK_LOG=true will log memory leaks to
-"test-results/$TEST_NAME.leak/trace.*" files. The logs include a
-"dedup_token" (see +"ASAN_OPTIONS=help=1 ./git") and other options to
-make logs +machine-readable.
-
-With GIT_TEST_SANITIZE_LEAK_LOG=true we'll look at the leak logs
-before exiting and exit on failure if the logs showed that we had a
-memory leak, even if the test itself would have otherwise passed. This
-allows us to catch e.g. missing &&-chaining. This is especially useful
-when combined with "GIT_TEST_PASSING_SANITIZE_LEAK", see below.
-
-GIT_TEST_PASSING_SANITIZE_LEAK=check when combined with "--immediate"
-will run to completion faster, and result in the same failing
-tests. The only practical reason to run
-GIT_TEST_PASSING_SANITIZE_LEAK=check without "--immediate" is to
-combine it with "GIT_TEST_SANITIZE_LEAK_LOG=true". If we stop at the
-first failing test case our leak logs won't show subsequent leaks we
-might have run into.
-
-GIT_TEST_PASSING_SANITIZE_LEAK=(true|check) will not catch all memory
-leaks unless combined with GIT_TEST_SANITIZE_LEAK_LOG=true. Some tests
-run "git" (or "test-tool" etc.) without properly checking the exit
-code, or git will invoke itself and fail to ferry the abort() exit
-code to the original caller. When the two modes are combined we'll
-look at the "test-results/$TEST_NAME.leak/trace.*" files at the end of
-the test run to see if had memory leaks which the test itself didn't
-catch.
-
GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version'
default to n.
@@ -462,9 +427,9 @@ GIT_TEST_MULTI_PACK_INDEX=<boolean>, when true, forces the multi-pack-
index to be written after every 'git repack' command, and overrides the
'core.multiPackIndex' setting to true.
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=<boolean>, when true, sets the
-'--bitmap' option on all invocations of 'git multi-pack-index write',
-and ignores pack-objects' '--write-bitmap-index'.
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=<boolean>, when true, sets
+the '--incremental' option on all invocations of 'git multi-pack-index
+write'.
GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the
'uploadpack.allowSidebandAll' setting to true, and when false, forces
@@ -479,6 +444,10 @@ 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_DEFAULT_REF_FORMAT=<format> specifies which ref storage format to use
+in the test scripts. Recognized values for <format> are "files" and
+"reftable".
+
GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the
'pack.writeReverseIndex' setting.
@@ -579,11 +548,11 @@ This test harness library does the following things:
Recommended style
-----------------
-Here are some recommented styles when writing test case.
- - Keep test title the same line with test helper function itself.
+ - Keep the test_expect_* function call and test title on
+ the same line.
- Take test_expect_success helper for example, write it like:
+ For example, with test_expect_success, write it like:
test_expect_success 'test title' '
... test body ...
@@ -595,10 +564,9 @@ Here are some recommented styles when writing test case.
'test title' \
'... test body ...'
+ - End the line with an opening single quote.
- - End the line with a single quote.
-
- - Indent the body of here-document, and use "<<-" instead of "<<"
+ - Indent here-document bodies, and use "<<-" instead of "<<"
to strip leading TABs used for indentation:
test_expect_success 'test something' '
@@ -624,7 +592,7 @@ Here are some recommented styles when writing test case.
'
- Quote or escape the EOF delimiter that begins a here-document if
- there is no parameter and other expansion in it, to signal readers
+ there is no parameter or other expansion in it, to signal readers
that they can skim it more casually:
cmd <<-\EOF
@@ -638,7 +606,7 @@ Do's & don'ts
Here are a few examples of things you probably should and shouldn't do
when writing tests.
-Here are the "do's:"
+The "do's:"
- Put all code inside test_expect_success and other assertions.
@@ -722,6 +690,26 @@ Here are the "do's:"
Note that we still &&-chain the loop to propagate failures from
earlier commands.
+ - Repeat tests with slightly different arguments in a loop.
+
+ In some cases it may make sense to re-run the same set of tests with
+ different options or commands to ensure that the command behaves
+ despite the different parameters. This can be achieved by looping
+ around a specific parameter:
+
+ for arg in '' "--foo"
+ do
+ test_expect_success "test command ${arg:-without arguments}" '
+ command $arg
+ '
+ done
+
+ Note that while the test title uses double quotes ("), the test body
+ should continue to use single quotes (') to avoid breakage in case the
+ values contain e.g. quoting characters. The loop variable will be
+ accessible regardless of the single quotes as the test body is passed
+ to `eval`.
+
And here are the "don'ts:"
@@ -877,6 +865,14 @@ see test-lib-functions.sh for the full list and their options.
'git-write-tree should be able to write an empty tree.' \
'tree=$(git-write-tree)'
+ If <script> is `-` (a single dash), then the script to run is read
+ from stdin. This lets you more easily use single quotes within the
+ script by using a here-doc. For example:
+
+ test_expect_success 'output contains expected string' - <<\EOT
+ grep "this string has 'quotes' in it" output
+ EOT
+
If you supply three parameters the first will be taken to be a
prerequisite; see the test_set_prereq and test_have_prereq
documentation below:
@@ -888,7 +884,7 @@ see test-lib-functions.sh for the full list and their options.
rare case where your test depends on more than one:
test_expect_success PERL,PYTHON 'yo dawg' \
- ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" '
+ ' test $(perl -E '\''print eval "1 +" . qx[python -c "print(2)"]'\'') = "4" '
- test_expect_failure [<prereq>] <message> <script>
@@ -1237,8 +1233,8 @@ and it knows that the object ID of an empty tree is a certain
because the things the very basic core test tries to achieve is
to serve as a basis for people who are changing the Git internals
drastically. For these people, after making certain changes,
-not seeing failures from the basic test _is_ a failure. And
-such drastic changes to the core Git that even changes these
+not seeing failures from the basic test _is_ a failure. Any
+Git core changes so drastic that they change even these
otherwise supposedly stable object IDs should be accompanied by
an update to t0000-basic.sh.
@@ -1248,7 +1244,7 @@ knowledge of the core Git internals. If all the test scripts
hardcoded the object IDs like t0000-basic.sh does, that defeats
the purpose of t0000-basic.sh, which is to isolate that level of
validation in one place. Your test also ends up needing
-updating when such a change to the internal happens, so do _not_
+an update whenever the internals change, so do _not_
do it and leave the low level of validation to t0000-basic.sh.
Test coverage
@@ -1279,7 +1275,7 @@ Devel::Cover module. To install it do:
sudo aptitude install libdevel-cover-perl
# From the CPAN with cpanminus
- curl -L http://cpanmin.us | perl - --sudo --self-upgrade
+ curl -L https://cpanmin.us/ | perl - --sudo --self-upgrade
cpanm --sudo Devel::Cover
Then, at the top-level:
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index 5e21e84f38..87572459e4 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -532,7 +532,7 @@ test_expect_success 'blame -L :funcname with userdiff driver' '
"$(cat file.template)" &&
test_commit --author "B <B@test.git>" \
"change" "$fortran_file" \
- "$(cat file.template | sed -e s/ChangeMe/IWasChanged/)" &&
+ "$(sed -e s/ChangeMe/IWasChanged/ file.template)" &&
check_count -f "$fortran_file" -L:RIGHT A 3 B 1
'
diff --git a/t/chainlint-cat.pl b/t/chainlint-cat.pl
new file mode 100644
index 0000000000..388f6e1e41
--- /dev/null
+++ b/t/chainlint-cat.pl
@@ -0,0 +1,29 @@
+#!/usr/bin/env perl
+
+my $outdir = shift;
+open(my $tests, '>', "$outdir/tests")
+ or die "unable to open $outdir/tests: $!";
+open(my $expect, '>', "$outdir/expect")
+ or die "unable to open $outdir/expect: $!";
+
+print $expect "# chainlint: $outdir/tests\n";
+
+my $offset = 0;
+for my $script (@ARGV) {
+ print $expect "# chainlint: $script\n";
+
+ open(my $expect_in, '<', "chainlint/$script.expect")
+ or die "unable to open chainlint/$script.expect: $!";
+ while (<$expect_in>) {
+ s/^\d+/$& + $offset/e;
+ print $expect $_;
+ }
+
+ open(my $test_in, '<', "chainlint/$script.test")
+ or die "unable to open chainlint/$script.test: $!";
+ while (<$test_in>) {
+ /^# LINT: / and next;
+ print $tests $_;
+ $offset++;
+ }
+}
diff --git a/t/chainlint.pl b/t/chainlint.pl
index 556ee91a15..f0598e3934 100755
--- a/t/chainlint.pl
+++ b/t/chainlint.pl
@@ -9,9 +9,9 @@
# Input arguments are pathnames of shell scripts containing test definitions,
# or globs referencing a collection of scripts. For each problem discovered,
# the pathname of the script containing the test is printed along with the test
-# name and the test body with a `?!FOO?!` annotation at the location of each
-# detected problem, where "FOO" is a tag such as "AMP" which indicates a broken
-# &&-chain. Returns zero if no problems are discovered, otherwise non-zero.
+# name and the test body with a `?!LINT: ...?!` annotation at the location of
+# each detected problem, where "..." is an explanation of the problem. Returns
+# zero if no problems are discovered, otherwise non-zero.
use warnings;
use strict;
@@ -174,10 +174,14 @@ sub swallow_heredocs {
$$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc;
if (pos($$b) > $start) {
my $body = substr($$b, $start, pos($$b) - $start);
+ $self->{parser}->{heredocs}->{$$tag[0]} = {
+ content => substr($body, 0, length($body) - length($&)),
+ start_line => $self->{lineno},
+ };
$self->{lineno} += () = $body =~ /\n/sg;
next;
}
- push(@{$self->{parser}->{problems}}, ['UNCLOSED-HEREDOC', $tag]);
+ push(@{$self->{parser}->{problems}}, ['HEREDOC', $tag]);
$$b =~ /(?:\G|\n).*\z/gc; # consume rest of input
my $body = substr($$b, $start, pos($$b) - $start);
$self->{lineno} += () = $body =~ /\n/sg;
@@ -232,7 +236,9 @@ sub new {
my $self = bless {
buff => [],
stop => [],
- output => []
+ output => [],
+ heredocs => {},
+ insubshell => 0,
} => $class;
$self->{lexer} = Lexer->new($self, $s);
return $self;
@@ -291,8 +297,11 @@ sub parse_group {
sub parse_subshell {
my $self = shift @_;
- return ($self->parse(qr/^\)$/),
- $self->expect(')'));
+ $self->{insubshell}++;
+ my @tokens = ($self->parse(qr/^\)$/),
+ $self->expect(')'));
+ $self->{insubshell}--;
+ return @tokens;
}
sub parse_case_pattern {
@@ -523,7 +532,7 @@ sub parse_loop_body {
return @tokens if ends_with(\@tokens, [qr/^\|\|$/, "\n", qr/^echo$/, qr/^.+$/]);
# flag missing "return/exit" handling explicit failure in loop body
my $n = find_non_nl(\@tokens);
- push(@{$self->{problems}}, ['LOOP', $tokens[$n]]);
+ push(@{$self->{problems}}, [$self->{insubshell} ? 'LOOPEXIT' : 'LOOPRETURN', $tokens[$n]]);
return @tokens;
}
@@ -582,6 +591,7 @@ sub new {
my $class = shift @_;
my $self = $class->SUPER::new(@_);
$self->{ntests} = 0;
+ $self->{nerrs} = 0;
return $self;
}
@@ -614,30 +624,50 @@ sub unwrap {
return $s
}
+sub format_problem {
+ local $_ = shift;
+ /^AMP$/ && return "missing '&&'";
+ /^LOOPRETURN$/ && return "missing '|| return 1'";
+ /^LOOPEXIT$/ && return "missing '|| exit 1'";
+ /^HEREDOC$/ && return 'unclosed heredoc';
+ die("unrecognized problem type '$_'\n");
+}
+
sub check_test {
my $self = shift @_;
- my ($title, $body) = map(unwrap, @_);
+ my $title = unwrap(shift @_);
+ my $body = shift @_;
+ my $lineno = $body->[3];
+ $body = unwrap($body);
+ if ($body eq '-') {
+ my $herebody = shift @_;
+ $body = $herebody->{content};
+ $lineno = $herebody->{start_line};
+ }
$self->{ntests}++;
my $parser = TestParser->new(\$body);
my @tokens = $parser->parse();
my $problems = $parser->{problems};
+ $self->{nerrs} += @$problems;
return unless $emit_all || @$problems;
my $c = main::fd_colors(1);
- my $lineno = $_[1]->[3];
+ my ($erropen, $errclose) = -t 1 ? ("$c->{rev}$c->{red}", $c->{reset}) : ('?!', '?!');
my $start = 0;
my $checked = '';
for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) {
my ($label, $token) = @$_;
my $pos = $token->[2];
- $checked .= substr($body, $start, $pos - $start) . " ?!$label?! ";
+ my $err = format_problem($label);
+ $checked .= substr($body, $start, $pos - $start);
+ $checked .= ' ' unless $checked =~ /\s$/;
+ $checked .= "${erropen}LINT: $err$errclose";
+ $checked .= ' ' unless $pos >= length($body) ||
+ substr($body, $pos, 1) =~ /^\s/;
$start = $pos;
}
$checked .= substr($body, $start);
$checked =~ s/^/$lineno++ . ' '/mge;
$checked =~ s/^\d+ \n//;
- $checked =~ s/(\s) \?!/$1?!/mg;
- $checked =~ s/\?! (\s)/?!$1/mg;
- $checked =~ s/(\?![^?]+\?!)/$c->{rev}$c->{red}$1$c->{reset}/mg;
$checked =~ s/^\d+/$c->{dim}$&$c->{reset}/mg;
$checked .= "\n" unless $checked =~ /\n$/;
push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked");
@@ -649,8 +679,13 @@ sub parse_cmd {
return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/;
my $n = $#tokens;
$n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/;
- $self->check_test($tokens[1], $tokens[2]) if $n == 2; # title body
- $self->check_test($tokens[2], $tokens[3]) if $n > 2; # prereq title body
+ my $herebody;
+ if ($n >= 2 && $tokens[$n-1]->[0] eq '-' && $tokens[$n]->[0] =~ /^<<-?(.+)$/) {
+ $herebody = $self->{heredocs}->{$1};
+ $n--;
+ }
+ $self->check_test($tokens[1], $tokens[2], $herebody) if $n == 2; # title body
+ $self->check_test($tokens[2], $tokens[3], $herebody) if $n > 2; # prereq title body
return @tokens;
}
@@ -716,11 +751,25 @@ sub fd_colors {
sub ncores {
# Windows
- return $ENV{NUMBER_OF_PROCESSORS} if exists($ENV{NUMBER_OF_PROCESSORS});
+ if (exists($ENV{NUMBER_OF_PROCESSORS})) {
+ my $ncpu = $ENV{NUMBER_OF_PROCESSORS};
+ return $ncpu > 0 ? $ncpu : 1;
+ }
# Linux / MSYS2 / Cygwin / WSL
- do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor[\s\d]*:/, <>)); } if -r '/proc/cpuinfo';
+ if (open my $fh, '<', '/proc/cpuinfo') {
+ my $cpuinfo = do { local $/; <$fh> };
+ close($fh);
+ if ($cpuinfo =~ /^n?cpus active\s*:\s*(\d+)/m) {
+ return $1 if $1 > 0;
+ }
+ my @matches = ($cpuinfo =~ /^(processor|CPU)[\s\d]*:/mg);
+ return @matches ? scalar(@matches) : 1;
+ }
# macOS & BSD
- return qx/sysctl -n hw.ncpu/ if $^O =~ /(?:^darwin$|bsd)/;
+ if ($^O =~ /(?:^darwin$|bsd)/) {
+ my $ncpu = qx/sysctl -n hw.ncpu/;
+ return $ncpu > 0 ? $ncpu : 1;
+ }
return 1;
}
@@ -748,7 +797,7 @@ sub check_script {
while (my $path = $next_script->()) {
$nscripts++;
my $fh;
- unless (open($fh, "<", $path)) {
+ unless (open($fh, "<:unix:crlf", $path)) {
$emit->("?!ERR?! $path: $!\n");
next;
}
@@ -760,9 +809,9 @@ sub check_script {
my $c = fd_colors(1);
my $s = join('', @{$parser->{output}});
$emit->("$c->{bold}$c->{blue}# chainlint: $path$c->{reset}\n" . $s);
- $nerrs += () = $s =~ /\?![^?]+\?!/g;
}
$ntests += $parser->{ntests};
+ $nerrs += $parser->{nerrs};
}
return [$id, $nscripts, $ntests, $nerrs];
}
@@ -792,8 +841,10 @@ unless (@scripts) {
show_stats($start_time, \@stats) if $show_stats;
exit;
}
+$jobs = @scripts if @scripts < $jobs;
-unless ($Config{useithreads} && eval {
+unless ($jobs > 1 &&
+ $Config{useithreads} && eval {
require threads; threads->import();
require Thread::Queue; Thread::Queue->import();
1;
diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect
index 46ee1046af..5677e16cad 100644
--- a/t/chainlint/arithmetic-expansion.expect
+++ b/t/chainlint/arithmetic-expansion.expect
@@ -1,9 +1,9 @@
-(
- foo &&
- bar=$((42 + 1)) &&
- baz
-) &&
-(
- bar=$((42 + 1)) ?!AMP?!
- baz
-)
+2 (
+3 foo &&
+4 bar=$((42 + 1)) &&
+5 baz
+6 ) &&
+7 (
+8 bar=$((42 + 1)) ?!LINT: missing '&&'?!
+9 baz
+10 )
diff --git a/t/chainlint/arithmetic-expansion.test b/t/chainlint/arithmetic-expansion.test
index 16206960d8..7b4c5c9a41 100644
--- a/t/chainlint/arithmetic-expansion.test
+++ b/t/chainlint/arithmetic-expansion.test
@@ -1,3 +1,4 @@
+test_expect_success 'arithmetic-expansion' '
(
foo &&
# LINT: closing ")" of $((...)) not misinterpreted as subshell-closing ")"
@@ -9,3 +10,4 @@
bar=$((42 + 1))
baz
)
+'
diff --git a/t/chainlint/bash-array.expect b/t/chainlint/bash-array.expect
index 4c34eaee45..435dc8bdc8 100644
--- a/t/chainlint/bash-array.expect
+++ b/t/chainlint/bash-array.expect
@@ -1,10 +1,10 @@
-(
- foo &&
- bar=(gumbo stumbo wumbo) &&
- baz
-) &&
-(
- foo &&
- bar=${#bar[@]} &&
- baz
-)
+2 (
+3 foo &&
+4 bar=(gumbo stumbo wumbo) &&
+5 baz
+6 ) &&
+7 (
+8 foo &&
+9 bar=${#bar[@]} &&
+10 baz
+11 )
diff --git a/t/chainlint/bash-array.test b/t/chainlint/bash-array.test
index 92bbb777b8..4ca977d299 100644
--- a/t/chainlint/bash-array.test
+++ b/t/chainlint/bash-array.test
@@ -1,3 +1,4 @@
+test_expect_success 'bash-array' '
(
foo &&
# LINT: ")" in Bash array assignment not misinterpreted as subshell-closing ")"
@@ -10,3 +11,4 @@
bar=${#bar[@]} &&
baz
)
+'
diff --git a/t/chainlint/blank-line-before-esac.expect b/t/chainlint/blank-line-before-esac.expect
index 48ed4eb124..b88ba919eb 100644
--- a/t/chainlint/blank-line-before-esac.expect
+++ b/t/chainlint/blank-line-before-esac.expect
@@ -1,18 +1,18 @@
-test_done ( ) {
- case "$test_failure" in
- 0 )
- test_at_end_hook_
-
- exit 0 ;;
-
- * )
- if test $test_external_has_tap -eq 0
- then
- say_color error "# failed $test_failure among $msg"
- say "1..$test_count"
- fi
-
- exit 1 ;;
-
- esac
-}
+2 test_done () {
+3 case "$test_failure" in
+4 0)
+5 test_at_end_hook_
+6
+7 exit 0 ;;
+8
+9 *)
+10 if test $test_external_has_tap -eq 0
+11 then
+12 say_color error "# failed $test_failure among $msg"
+13 say "1..$test_count"
+14 fi
+15
+16 exit 1 ;;
+17
+18 esac
+19 }
diff --git a/t/chainlint/blank-line-before-esac.test b/t/chainlint/blank-line-before-esac.test
index cecccad19f..51f02ea0c5 100644
--- a/t/chainlint/blank-line-before-esac.test
+++ b/t/chainlint/blank-line-before-esac.test
@@ -1,3 +1,4 @@
+test_expect_success 'blank-line-before-esac' '
# LINT: blank line before "esac"
test_done () {
case "$test_failure" in
@@ -17,3 +18,4 @@ test_done () {
esac
}
+'
diff --git a/t/chainlint/blank-line.expect b/t/chainlint/blank-line.expect
index f76fde1ffb..6ae39dd174 100644
--- a/t/chainlint/blank-line.expect
+++ b/t/chainlint/blank-line.expect
@@ -1,4 +1,8 @@
-(
- nothing &&
- something
-)
+2 (
+3
+4 nothing &&
+5
+6 something
+7
+8
+9 )
diff --git a/t/chainlint/blank-line.test b/t/chainlint/blank-line.test
index 0fdf15b3e1..6f29a491de 100644
--- a/t/chainlint/blank-line.test
+++ b/t/chainlint/blank-line.test
@@ -1,3 +1,4 @@
+test_expect_success 'blank-line' '
(
nothing &&
@@ -8,3 +9,4 @@
)
+'
diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect
index df2beea888..7926936c18 100644
--- a/t/chainlint/block-comment.expect
+++ b/t/chainlint/block-comment.expect
@@ -1,8 +1,8 @@
-(
- {
- # show a
- echo a &&
- # show b
- echo b
- }
-)
+2 (
+3 {
+4 # show a
+5 echo a &&
+6 # show b
+7 echo b
+8 }
+9 )
diff --git a/t/chainlint/block-comment.test b/t/chainlint/block-comment.test
index df2beea888..934ef4113a 100644
--- a/t/chainlint/block-comment.test
+++ b/t/chainlint/block-comment.test
@@ -1,3 +1,4 @@
+test_expect_success 'block-comment' '
(
{
# show a
@@ -6,3 +7,4 @@
echo b
}
)
+'
diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect
index a3bcea492a..3d3f854c0d 100644
--- a/t/chainlint/block.expect
+++ b/t/chainlint/block.expect
@@ -1,23 +1,23 @@
-(
- foo &&
- {
- echo a ?!AMP?!
- echo b
- } &&
- bar &&
- {
- echo c
- } ?!AMP?!
- baz
-) &&
-
-{
- echo a ; ?!AMP?! echo b
-} &&
-{ echo a ; ?!AMP?! echo b ; } &&
-
-{
- echo "${var}9" &&
- echo "done"
-} &&
-finis
+2 (
+3 foo &&
+4 {
+5 echo a ?!LINT: missing '&&'?!
+6 echo b
+7 } &&
+8 bar &&
+9 {
+10 echo c
+11 } ?!LINT: missing '&&'?!
+12 baz
+13 ) &&
+14
+15 {
+16 echo a; ?!LINT: missing '&&'?! echo b
+17 } &&
+18 { echo a; ?!LINT: missing '&&'?! echo b; } &&
+19
+20 {
+21 echo "${var}9" &&
+22 echo "done"
+23 } &&
+24 finis
diff --git a/t/chainlint/block.test b/t/chainlint/block.test
index 4ab69a4afc..a1b6b4dd32 100644
--- a/t/chainlint/block.test
+++ b/t/chainlint/block.test
@@ -1,3 +1,4 @@
+test_expect_success 'block' '
(
# LINT: missing "&&" after first "echo"
foo &&
@@ -25,3 +26,4 @@
echo "done"
} &&
finis
+'
diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect
index cfb58fb6b9..b7b1ce8509 100644
--- a/t/chainlint/broken-chain.expect
+++ b/t/chainlint/broken-chain.expect
@@ -1,6 +1,6 @@
-(
- foo &&
- bar ?!AMP?!
- baz &&
- wop
-)
+2 (
+3 foo &&
+4 bar ?!LINT: missing '&&'?!
+5 baz &&
+6 wop
+7 )
diff --git a/t/chainlint/broken-chain.test b/t/chainlint/broken-chain.test
index 2a44aa73b7..1966499ef9 100644
--- a/t/chainlint/broken-chain.test
+++ b/t/chainlint/broken-chain.test
@@ -1,3 +1,4 @@
+test_expect_success 'broken-chain' '
(
foo &&
# LINT: missing "&&" from "bar"
@@ -6,3 +7,4 @@
# LINT: final statement before closing ")" legitimately lacks "&&"
wop
)
+'
diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect
index 641c157b98..2442dd5f25 100644
--- a/t/chainlint/case-comment.expect
+++ b/t/chainlint/case-comment.expect
@@ -1,11 +1,11 @@
-(
- case "$x" in
- # found foo
- x) foo ;;
- # found other
- *)
- # treat it as bar
- bar
- ;;
- esac
-)
+2 (
+3 case "$x" in
+4 # found foo
+5 x) foo ;;
+6 # found other
+7 *)
+8 # treat it as bar
+9 bar
+10 ;;
+11 esac
+12 )
diff --git a/t/chainlint/case-comment.test b/t/chainlint/case-comment.test
index 641c157b98..3f31ae9010 100644
--- a/t/chainlint/case-comment.test
+++ b/t/chainlint/case-comment.test
@@ -1,3 +1,4 @@
+test_expect_success 'case-comment' '
(
case "$x" in
# found foo
@@ -9,3 +10,4 @@
;;
esac
)
+'
diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect
index 31f280d8ce..0a3b09e470 100644
--- a/t/chainlint/case.expect
+++ b/t/chainlint/case.expect
@@ -1,19 +1,19 @@
-(
- case "$x" in
- x) foo ;;
- *) bar ;;
- esac &&
- foobar
-) &&
-(
- case "$x" in
- x) foo ;;
- *) bar ;;
- esac ?!AMP?!
- foobar
-) &&
-(
- case "$x" in 1) true;; esac &&
- case "$y" in 2) false;; esac ?!AMP?!
- foobar
-)
+2 (
+3 case "$x" in
+4 x) foo ;;
+5 *) bar ;;
+6 esac &&
+7 foobar
+8 ) &&
+9 (
+10 case "$x" in
+11 x) foo ;;
+12 *) bar ;;
+13 esac ?!LINT: missing '&&'?!
+14 foobar
+15 ) &&
+16 (
+17 case "$x" in 1) true;; esac &&
+18 case "$y" in 2) false;; esac ?!LINT: missing '&&'?!
+19 foobar
+20 )
diff --git a/t/chainlint/case.test b/t/chainlint/case.test
index 4cb086bf87..bea21fee4f 100644
--- a/t/chainlint/case.test
+++ b/t/chainlint/case.test
@@ -1,3 +1,4 @@
+test_expect_success 'case' '
(
# LINT: "...)" arms in "case" not misinterpreted as subshell-closing ")"
case "$x" in
@@ -21,3 +22,4 @@
case "$y" in 2) false;; esac
foobar
)
+'
diff --git a/t/chainlint/chain-break-background.expect b/t/chainlint/chain-break-background.expect
index 28f9114f42..d06deadae7 100644
--- a/t/chainlint/chain-break-background.expect
+++ b/t/chainlint/chain-break-background.expect
@@ -1,9 +1,9 @@
-JGIT_DAEMON_PID= &&
-git init --bare empty.git &&
-> empty.git/git-daemon-export-ok &&
-mkfifo jgit_daemon_output &&
-{
- jgit daemon --port="$JGIT_DAEMON_PORT" . > jgit_daemon_output &
- JGIT_DAEMON_PID=$!
-} &&
-test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
+2 JGIT_DAEMON_PID= &&
+3 git init --bare empty.git &&
+4 >empty.git/git-daemon-export-ok &&
+5 mkfifo jgit_daemon_output &&
+6 {
+7 jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output &
+8 JGIT_DAEMON_PID=$!
+9 } &&
+10 test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
diff --git a/t/chainlint/chain-break-background.test b/t/chainlint/chain-break-background.test
index e10f656b05..c68e1b04d5 100644
--- a/t/chainlint/chain-break-background.test
+++ b/t/chainlint/chain-break-background.test
@@ -1,3 +1,4 @@
+test_expect_success 'chain-break-background' '
JGIT_DAEMON_PID= &&
git init --bare empty.git &&
>empty.git/git-daemon-export-ok &&
@@ -8,3 +9,4 @@ mkfifo jgit_daemon_output &&
JGIT_DAEMON_PID=$!
} &&
test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
+'
diff --git a/t/chainlint/chain-break-continue.expect b/t/chainlint/chain-break-continue.expect
index 47a3457710..4bb60aae25 100644
--- a/t/chainlint/chain-break-continue.expect
+++ b/t/chainlint/chain-break-continue.expect
@@ -1,12 +1,12 @@
-git ls-tree --name-only -r refs/notes/many_notes |
-while read path
-do
- test "$path" = "foobar/non-note.txt" && continue
- test "$path" = "deadbeef" && continue
- test "$path" = "de/adbeef" && continue
-
- if test $(expr length "$path") -ne $hexsz
- then
- return 1
- fi
-done
+2 git ls-tree --name-only -r refs/notes/many_notes |
+3 while read path
+4 do
+5 test "$path" = "foobar/non-note.txt" && continue
+6 test "$path" = "deadbeef" && continue
+7 test "$path" = "de/adbeef" && continue
+8
+9 if test $(expr length "$path") -ne $hexsz
+10 then
+11 return 1
+12 fi
+13 done
diff --git a/t/chainlint/chain-break-continue.test b/t/chainlint/chain-break-continue.test
index f0af71d8bd..de8119b204 100644
--- a/t/chainlint/chain-break-continue.test
+++ b/t/chainlint/chain-break-continue.test
@@ -1,3 +1,4 @@
+test_expect_success 'chain-break-continue' '
git ls-tree --name-only -r refs/notes/many_notes |
while read path
do
@@ -11,3 +12,4 @@ do
return 1
fi
done
+'
diff --git a/t/chainlint/chain-break-false.expect b/t/chainlint/chain-break-false.expect
index 989766fb85..f6a0a301e9 100644
--- a/t/chainlint/chain-break-false.expect
+++ b/t/chainlint/chain-break-false.expect
@@ -1,9 +1,9 @@
-if condition not satisified
-then
- echo it did not work...
- echo failed!
- false
-else
- echo it went okay ?!AMP?!
- congratulate user
-fi
+2 if condition not satisified
+3 then
+4 echo it did not work...
+5 echo failed!
+6 false
+7 else
+8 echo it went okay ?!LINT: missing '&&'?!
+9 congratulate user
+10 fi
diff --git a/t/chainlint/chain-break-false.test b/t/chainlint/chain-break-false.test
index a5aaff8c8a..f78ad911fc 100644
--- a/t/chainlint/chain-break-false.test
+++ b/t/chainlint/chain-break-false.test
@@ -1,3 +1,4 @@
+test_expect_success 'chain-break-false' '
# LINT: broken &&-chain okay if explicit "false" signals failure
if condition not satisified
then
@@ -8,3 +9,4 @@ else
echo it went okay
congratulate user
fi
+'
diff --git a/t/chainlint/chain-break-return-exit.expect b/t/chainlint/chain-break-return-exit.expect
index 1732d221c3..ba0ec51aa0 100644
--- a/t/chainlint/chain-break-return-exit.expect
+++ b/t/chainlint/chain-break-return-exit.expect
@@ -1,19 +1,19 @@
-case "$(git ls-files)" in
-one ) echo pass one ;;
-* ) echo bad one ; return 1 ;;
-esac &&
-(
- case "$(git ls-files)" in
- two ) echo pass two ;;
- * ) echo bad two ; exit 1 ;;
-esac
-) &&
-case "$(git ls-files)" in
-dir/two"$LF"one ) echo pass both ;;
-* ) echo bad ; return 1 ;;
-esac &&
-
-for i in 1 2 3 4 ; do
- git checkout main -b $i || return $?
- test_commit $i $i $i tag$i || return $?
-done
+2 case "$(git ls-files)" in
+3 one) echo pass one ;;
+4 *) echo bad one; return 1 ;;
+5 esac &&
+6 (
+7 case "$(git ls-files)" in
+8 two) echo pass two ;;
+9 *) echo bad two; exit 1 ;;
+10 esac
+11 ) &&
+12 case "$(git ls-files)" in
+13 dir/two"$LF"one) echo pass both ;;
+14 *) echo bad; return 1 ;;
+15 esac &&
+16
+17 for i in 1 2 3 4 ; do
+18 git checkout main -b $i || return $?
+19 test_commit $i $i $i tag$i || return $?
+20 done
diff --git a/t/chainlint/chain-break-return-exit.test b/t/chainlint/chain-break-return-exit.test
index 46542edf88..b6f519bb4d 100644
--- a/t/chainlint/chain-break-return-exit.test
+++ b/t/chainlint/chain-break-return-exit.test
@@ -1,3 +1,4 @@
+test_expect_success 'chain-break-return-exit' '
case "$(git ls-files)" in
one) echo pass one ;;
# LINT: broken &&-chain okay if explicit "return 1" signals failuire
@@ -21,3 +22,4 @@ for i in 1 2 3 4 ; do
git checkout main -b $i || return $?
test_commit $i $i $i tag$i || return $?
done
+'
diff --git a/t/chainlint/chain-break-status.expect b/t/chainlint/chain-break-status.expect
index f4bada9463..23c0caa7d8 100644
--- a/t/chainlint/chain-break-status.expect
+++ b/t/chainlint/chain-break-status.expect
@@ -1,9 +1,9 @@
-OUT=$(( ( large_git ; echo $? 1 >& 3 ) | : ) 3 >& 1) &&
-test_match_signal 13 "$OUT" &&
-
-{ test-tool sigchain > actual ; ret=$? ; } &&
-{
- test_match_signal 15 "$ret" ||
- test "$ret" = 3
-} &&
-test_cmp expect actual
+2 OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) &&
+3 test_match_signal 13 "$OUT" &&
+4
+5 { test-tool sigchain >actual; ret=$?; } &&
+6 {
+7 test_match_signal 15 "$ret" ||
+8 test "$ret" = 3
+9 } &&
+10 test_cmp expect actual
diff --git a/t/chainlint/chain-break-status.test b/t/chainlint/chain-break-status.test
index a6602a7b99..d9fee190d9 100644
--- a/t/chainlint/chain-break-status.test
+++ b/t/chainlint/chain-break-status.test
@@ -1,3 +1,4 @@
+test_expect_success 'chain-break-status' '
# LINT: broken &&-chain okay if next command handles "$?" explicitly
OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) &&
test_match_signal 13 "$OUT" &&
@@ -9,3 +10,4 @@ test_match_signal 13 "$OUT" &&
test "$ret" = 3
} &&
test_cmp expect actual
+'
diff --git a/t/chainlint/chained-block.expect b/t/chainlint/chained-block.expect
index 574cdceb07..f2501bba90 100644
--- a/t/chainlint/chained-block.expect
+++ b/t/chainlint/chained-block.expect
@@ -1,9 +1,9 @@
-echo nobody home && {
- test the doohicky ?!AMP?!
- right now
-} &&
-
-GIT_EXTERNAL_DIFF=echo git diff | {
- read path oldfile oldhex oldmode newfile newhex newmode &&
- test "z$oh" = "z$oldhex"
-}
+2 echo nobody home && {
+3 test the doohicky ?!LINT: missing '&&'?!
+4 right now
+5 } &&
+6
+7 GIT_EXTERNAL_DIFF=echo git diff | {
+8 read path oldfile oldhex oldmode newfile newhex newmode &&
+9 test "z$oh" = "z$oldhex"
+10 }
diff --git a/t/chainlint/chained-block.test b/t/chainlint/chained-block.test
index 86f81ece63..71ef1d0b7f 100644
--- a/t/chainlint/chained-block.test
+++ b/t/chainlint/chained-block.test
@@ -1,3 +1,4 @@
+test_expect_success 'chained-block' '
# LINT: start of block chained to preceding command
echo nobody home && {
test the doohicky
@@ -9,3 +10,4 @@ GIT_EXTERNAL_DIFF=echo git diff | {
read path oldfile oldhex oldmode newfile newhex newmode &&
test "z$oh" = "z$oldhex"
}
+'
diff --git a/t/chainlint/chained-subshell.expect b/t/chainlint/chained-subshell.expect
index af0369d328..93fb1a6578 100644
--- a/t/chainlint/chained-subshell.expect
+++ b/t/chainlint/chained-subshell.expect
@@ -1,10 +1,10 @@
-mkdir sub && (
- cd sub &&
- foo the bar ?!AMP?!
- nuff said
-) &&
-
-cut "-d " -f actual | ( read s1 s2 s3 &&
-test -f $s1 ?!AMP?!
-test $(cat $s2) = tree2path1 &&
-test $(cat $s3) = tree3path1 )
+2 mkdir sub && (
+3 cd sub &&
+4 foo the bar ?!LINT: missing '&&'?!
+5 nuff said
+6 ) &&
+7
+8 cut "-d " -f actual | (read s1 s2 s3 &&
+9 test -f $s1 ?!LINT: missing '&&'?!
+10 test $(cat $s2) = tree2path1 &&
+11 test $(cat $s3) = tree3path1)
diff --git a/t/chainlint/chained-subshell.test b/t/chainlint/chained-subshell.test
index 4ff6ddd8cb..1f11f65398 100644
--- a/t/chainlint/chained-subshell.test
+++ b/t/chainlint/chained-subshell.test
@@ -1,3 +1,4 @@
+test_expect_success 'chained-subshell' '
# LINT: start of subshell chained to preceding command
mkdir sub && (
cd sub &&
@@ -11,3 +12,4 @@ test -f $s1
test $(cat $s2) = tree2path1 &&
# LINT: closing subshell ")" correctly detected on same line as "$(...)"
test $(cat $s3) = tree3path1)
+'
diff --git a/t/chainlint/close-nested-and-parent-together.expect b/t/chainlint/close-nested-and-parent-together.expect
index 72d482f76d..4167e54a59 100644
--- a/t/chainlint/close-nested-and-parent-together.expect
+++ b/t/chainlint/close-nested-and-parent-together.expect
@@ -1,3 +1,3 @@
-(cd foo &&
- (bar &&
- baz))
+2 (cd foo &&
+3 (bar &&
+4 baz))
diff --git a/t/chainlint/close-nested-and-parent-together.test b/t/chainlint/close-nested-and-parent-together.test
index 72d482f76d..56b28b186b 100644
--- a/t/chainlint/close-nested-and-parent-together.test
+++ b/t/chainlint/close-nested-and-parent-together.test
@@ -1,3 +1,5 @@
+test_expect_success 'close-nested-and-parent-together' '
(cd foo &&
(bar &&
baz))
+'
diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect
index 2192a2870a..a272cfe72e 100644
--- a/t/chainlint/close-subshell.expect
+++ b/t/chainlint/close-subshell.expect
@@ -1,26 +1,26 @@
-(
- foo
-) &&
-(
- bar
-) >out &&
-(
- baz
-) 2>err &&
-(
- boo
-) <input &&
-(
- bip
-) | wuzzle &&
-(
- bop
-) | fazz \
- fozz &&
-(
- bup
-) |
-fuzzle &&
-(
- yop
-)
+2 (
+3 foo
+4 ) &&
+5 (
+6 bar
+7 ) >out &&
+8 (
+9 baz
+10 ) 2>err &&
+11 (
+12 boo
+13 ) <input &&
+14 (
+15 bip
+16 ) | wuzzle &&
+17 (
+18 bop
+19 ) | fazz \
+20 fozz &&
+21 (
+22 bup
+23 ) |
+24 fuzzle &&
+25 (
+26 yop
+27 )
diff --git a/t/chainlint/close-subshell.test b/t/chainlint/close-subshell.test
index 508ca447fd..b99f80569d 100644
--- a/t/chainlint/close-subshell.test
+++ b/t/chainlint/close-subshell.test
@@ -1,3 +1,4 @@
+test_expect_success 'close-subshell' '
# LINT: closing ")" with various decorations ("&&", ">", "|", etc.)
(
foo
@@ -25,3 +26,4 @@ fuzzle &&
(
yop
)
+'
diff --git a/t/chainlint/command-substitution-subsubshell.expect b/t/chainlint/command-substitution-subsubshell.expect
index ab2f79e845..f2a9312dc8 100644
--- a/t/chainlint/command-substitution-subsubshell.expect
+++ b/t/chainlint/command-substitution-subsubshell.expect
@@ -1,2 +1,2 @@
-OUT=$(( ( large_git 1 >& 3 ) | : ) 3 >& 1) &&
-test_match_signal 13 "$OUT"
+2 OUT=$( ((large_git 1>&3) | :) 3>&1 ) &&
+3 test_match_signal 13 "$OUT"
diff --git a/t/chainlint/command-substitution-subsubshell.test b/t/chainlint/command-substitution-subsubshell.test
index 321de2951c..4ea772d60a 100644
--- a/t/chainlint/command-substitution-subsubshell.test
+++ b/t/chainlint/command-substitution-subsubshell.test
@@ -1,3 +1,5 @@
+test_expect_success 'command-substitution-subsubshell' '
# LINT: subshell nested in subshell nested in command substitution
OUT=$( ((large_git 1>&3) | :) 3>&1 ) &&
test_match_signal 13 "$OUT"
+'
diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect
index c72e4df9e7..73809fd585 100644
--- a/t/chainlint/command-substitution.expect
+++ b/t/chainlint/command-substitution.expect
@@ -1,9 +1,9 @@
-(
- foo &&
- bar=$(gobble) &&
- baz
-) &&
-(
- bar=$(gobble blocks) ?!AMP?!
- baz
-)
+2 (
+3 foo &&
+4 bar=$(gobble) &&
+5 baz
+6 ) &&
+7 (
+8 bar=$(gobble blocks) ?!LINT: missing '&&'?!
+9 baz
+10 )
diff --git a/t/chainlint/command-substitution.test b/t/chainlint/command-substitution.test
index 3bbb002a4c..494d671e80 100644
--- a/t/chainlint/command-substitution.test
+++ b/t/chainlint/command-substitution.test
@@ -1,3 +1,4 @@
+test_expect_success 'command-substitution' '
(
foo &&
# LINT: closing ")" of $(...) not misinterpreted as subshell-closing ")"
@@ -9,3 +10,4 @@
bar=$(gobble blocks)
baz
)
+'
diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect
index a68f1f9d7c..584098d6ba 100644
--- a/t/chainlint/comment.expect
+++ b/t/chainlint/comment.expect
@@ -1,8 +1,8 @@
-(
- # comment 1
- nothing &&
- # comment 2
- something
- # comment 3
- # comment 4
-)
+2 (
+3 # comment 1
+4 nothing &&
+5 # comment 2
+6 something
+7 # comment 3
+8 # comment 4
+9 )
diff --git a/t/chainlint/comment.test b/t/chainlint/comment.test
index 113c0c466f..c488beac0d 100644
--- a/t/chainlint/comment.test
+++ b/t/chainlint/comment.test
@@ -1,3 +1,4 @@
+test_expect_success 'comment' '
(
# LINT: swallow comment lines
# comment 1
@@ -9,3 +10,4 @@
# comment 3
# comment 4
)
+'
diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect
index dac2d0fd1d..e66bb2d5d0 100644
--- a/t/chainlint/complex-if-in-cuddled-loop.expect
+++ b/t/chainlint/complex-if-in-cuddled-loop.expect
@@ -1,9 +1,9 @@
-(for i in a b c; do
- if test "$(echo $(waffle bat))" = "eleventeen" &&
- test "$x" = "$y"; then
- :
- else
- echo >file
- fi ?!LOOP?!
- done) &&
-test ! -f file
+2 (for i in a b c; do
+3 if test "$(echo $(waffle bat))" = "eleventeen" &&
+4 test "$x" = "$y"; then
+5 :
+6 else
+7 echo >file
+8 fi ?!LINT: missing '|| exit 1'?!
+9 done) &&
+10 test ! -f file
diff --git a/t/chainlint/complex-if-in-cuddled-loop.test b/t/chainlint/complex-if-in-cuddled-loop.test
index 5efeda58b2..f98ae4c42d 100644
--- a/t/chainlint/complex-if-in-cuddled-loop.test
+++ b/t/chainlint/complex-if-in-cuddled-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'complex-if-in-cuddled-loop' '
# LINT: "for" loop cuddled with "(" and ")" and nested "if" with complex
# LINT: multi-line condition; indented with spaces, not tabs
(for i in a b c; do
@@ -9,3 +10,4 @@
fi
done) &&
test ! -f file
+'
diff --git a/t/chainlint/cuddled-if-then-else.expect b/t/chainlint/cuddled-if-then-else.expect
index 1d8ed58c49..72da8794cb 100644
--- a/t/chainlint/cuddled-if-then-else.expect
+++ b/t/chainlint/cuddled-if-then-else.expect
@@ -1,6 +1,6 @@
-(if test -z ""; then
- echo empty
- else
- echo bizzy
- fi) &&
-echo foobar
+2 (if test -z ""; then
+3 echo empty
+4 else
+5 echo bizzy
+6 fi) &&
+7 echo foobar
diff --git a/t/chainlint/cuddled-if-then-else.test b/t/chainlint/cuddled-if-then-else.test
index 7c53f4efe3..b1b42e1aac 100644
--- a/t/chainlint/cuddled-if-then-else.test
+++ b/t/chainlint/cuddled-if-then-else.test
@@ -1,3 +1,4 @@
+test_expect_success 'cuddled-if-then-else' '
# LINT: "if" cuddled with "(" and ")"; indented with spaces, not tabs
(if test -z ""; then
echo empty
@@ -5,3 +6,4 @@
echo bizzy
fi) &&
echo foobar
+'
diff --git a/t/chainlint/cuddled-loop.expect b/t/chainlint/cuddled-loop.expect
index 9cf260708e..c38585c756 100644
--- a/t/chainlint/cuddled-loop.expect
+++ b/t/chainlint/cuddled-loop.expect
@@ -1,4 +1,4 @@
-( while read x
- do foobar bop || exit 1
- done <file ) &&
-outside subshell
+2 ( while read x
+3 do foobar bop || exit 1
+4 done <file ) &&
+5 outside subshell
diff --git a/t/chainlint/cuddled-loop.test b/t/chainlint/cuddled-loop.test
index 3c2a62f751..6fccb6ac22 100644
--- a/t/chainlint/cuddled-loop.test
+++ b/t/chainlint/cuddled-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'cuddled-loop' '
# LINT: "while" loop cuddled with "(" and ")", with embedded (allowed)
# LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed
# LINT: loop; indented with spaces, not tabs
@@ -5,3 +6,4 @@
do foobar bop || exit 1
done <file ) &&
outside subshell
+'
diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect
index c3e0be4047..1864b3fc8b 100644
--- a/t/chainlint/cuddled.expect
+++ b/t/chainlint/cuddled.expect
@@ -1,17 +1,17 @@
-(cd foo &&
- bar
-) &&
-
-(cd foo ?!AMP?!
- bar
-) &&
-
-(
- cd foo &&
- bar) &&
-
-(cd foo &&
- bar) &&
-
-(cd foo ?!AMP?!
- bar)
+2 (cd foo &&
+3 bar
+4 ) &&
+5
+6 (cd foo ?!LINT: missing '&&'?!
+7 bar
+8 ) &&
+9
+10 (
+11 cd foo &&
+12 bar) &&
+13
+14 (cd foo &&
+15 bar) &&
+16
+17 (cd foo ?!LINT: missing '&&'?!
+18 bar)
diff --git a/t/chainlint/cuddled.test b/t/chainlint/cuddled.test
index 257b5b5eed..5a6ef7a4a6 100644
--- a/t/chainlint/cuddled.test
+++ b/t/chainlint/cuddled.test
@@ -1,3 +1,4 @@
+test_expect_success 'cuddled' '
# LINT: first subshell statement cuddled with opening "("
(cd foo &&
bar
@@ -20,3 +21,4 @@
# LINT: same with missing "&&"
(cd foo
bar)
+'
diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect
index cd584a4357..48c04ecd58 100644
--- a/t/chainlint/double-here-doc.expect
+++ b/t/chainlint/double-here-doc.expect
@@ -1,12 +1,12 @@
-run_sub_test_lib_test_err run-inv-range-start \
- "--run invalid range start" \
- --run="a-5" <<-\EOF &&
-test_expect_success "passing test #1" "true"
-test_done
-EOF
-check_sub_test_lib_test_err run-inv-range-start \
- <<-\EOF_OUT 3<<-EOF_ERR
-> FATAL: Unexpected exit with code 1
-EOF_OUT
-> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ}
-EOF_ERR
+2 run_sub_test_lib_test_err run-inv-range-start \
+3 "--run invalid range start" \
+4 --run="a-5" <<-\EOF &&
+5 test_expect_success "passing test #1" "true"
+6 test_done
+7 EOF
+8 check_sub_test_lib_test_err run-inv-range-start \
+9 <<-\EOF_OUT 3<<-EOF_ERR
+10 > FATAL: Unexpected exit with code 1
+11 EOF_OUT
+12 > error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ}
+13 EOF_ERR
diff --git a/t/chainlint/double-here-doc.test b/t/chainlint/double-here-doc.test
index cd584a4357..1b69b7a651 100644
--- a/t/chainlint/double-here-doc.test
+++ b/t/chainlint/double-here-doc.test
@@ -1,3 +1,4 @@
+test_expect_success 'double-here-doc' '
run_sub_test_lib_test_err run-inv-range-start \
"--run invalid range start" \
--run="a-5" <<-\EOF &&
@@ -10,3 +11,4 @@ check_sub_test_lib_test_err run-inv-range-start \
EOF_OUT
> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ}
EOF_ERR
+'
diff --git a/t/chainlint/dqstring-line-splice.expect b/t/chainlint/dqstring-line-splice.expect
index bf9ced60d4..2ca1c92cd6 100644
--- a/t/chainlint/dqstring-line-splice.expect
+++ b/t/chainlint/dqstring-line-splice.expect
@@ -1,3 +1,5 @@
-echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' > expect &&
-test_must_fail git commit --fixup=reword:HEAD~ $1 2 > actual &&
-test_cmp expect actual
+2
+3 echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' >expect &&
+4 test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual &&
+5 test_cmp expect actual
+6
diff --git a/t/chainlint/dqstring-line-splice.test b/t/chainlint/dqstring-line-splice.test
index b40714439f..f6aa637be8 100644
--- a/t/chainlint/dqstring-line-splice.test
+++ b/t/chainlint/dqstring-line-splice.test
@@ -1,3 +1,4 @@
+test_expect_success 'dqstring-line-splice' '
# LINT: line-splice within DQ-string
'"
echo 'fatal: reword option of --fixup is mutually exclusive with'\
@@ -5,3 +6,4 @@ echo 'fatal: reword option of --fixup is mutually exclusive with'\
test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual &&
test_cmp expect actual
"'
+'
diff --git a/t/chainlint/dqstring-no-interpolate.expect b/t/chainlint/dqstring-no-interpolate.expect
index 10724987a5..c9f75849c5 100644
--- a/t/chainlint/dqstring-no-interpolate.expect
+++ b/t/chainlint/dqstring-no-interpolate.expect
@@ -1,11 +1,12 @@
-grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out &&
-
-grep "^\.git$" output.txt &&
-
-
-(
- cd client$version &&
- GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input)
-) > output &&
- cut -d ' ' -f 2 < output | sort > actual &&
- test_cmp expect actual
+2 grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out &&
+3
+4 grep "^\.git$" output.txt &&
+5
+6
+7 (
+8 cd client$version &&
+9 GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input)
+10 ) >output &&
+11 cut -d ' ' -f 2 <output | sort >actual &&
+12 test_cmp expect actual
+13
diff --git a/t/chainlint/dqstring-no-interpolate.test b/t/chainlint/dqstring-no-interpolate.test
index d2f4219cbb..7ae079b558 100644
--- a/t/chainlint/dqstring-no-interpolate.test
+++ b/t/chainlint/dqstring-no-interpolate.test
@@ -1,3 +1,4 @@
+test_expect_success 'dqstring-no-interpolate' '
# LINT: regex dollar-sign eol anchor in double-quoted string not special
grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out &&
@@ -13,3 +14,4 @@ grep "^\\.git\$" output.txt &&
cut -d ' ' -f 2 <output | sort >actual &&
test_cmp expect actual
"'
+'
diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect
index e8733c97c6..54b33f823a 100644
--- a/t/chainlint/empty-here-doc.expect
+++ b/t/chainlint/empty-here-doc.expect
@@ -1,4 +1,4 @@
-git ls-tree $tree path > current &&
-cat > expected <<\EOF &&
-EOF
-test_output
+2 git ls-tree $tree path >current &&
+3 cat >expected <<\EOF &&
+4 EOF
+5 test_output
diff --git a/t/chainlint/empty-here-doc.test b/t/chainlint/empty-here-doc.test
index 24fc165de3..8b7ab6eb5f 100644
--- a/t/chainlint/empty-here-doc.test
+++ b/t/chainlint/empty-here-doc.test
@@ -1,5 +1,7 @@
+test_expect_success 'empty-here-doc' '
git ls-tree $tree path >current &&
# LINT: empty here-doc
cat >expected <<\EOF &&
EOF
test_output
+'
diff --git a/t/chainlint/exclamation.expect b/t/chainlint/exclamation.expect
index 2d961a58c6..078744b61b 100644
--- a/t/chainlint/exclamation.expect
+++ b/t/chainlint/exclamation.expect
@@ -1,4 +1,4 @@
-if ! condition ; then echo nope ; else yep ; fi &&
-test_prerequisite !MINGW &&
-mail uucp!address &&
-echo !whatever!
+2 if ! condition; then echo nope; else yep; fi &&
+3 test_prerequisite !MINGW &&
+4 mail uucp!address &&
+5 echo !whatever!
diff --git a/t/chainlint/exclamation.test b/t/chainlint/exclamation.test
index 323595b5bd..796de21b7c 100644
--- a/t/chainlint/exclamation.test
+++ b/t/chainlint/exclamation.test
@@ -1,3 +1,4 @@
+test_expect_success 'exclamation' '
# LINT: "! word" is two tokens
if ! condition; then echo nope; else yep; fi &&
# LINT: "!word" is single token, not two tokens "!" and "word"
@@ -6,3 +7,4 @@ test_prerequisite !MINGW &&
mail uucp!address &&
# LINT: "!word!" is single token, not three tokens "!", "word", and "!"
echo !whatever!
+'
diff --git a/t/chainlint/exit-loop.expect b/t/chainlint/exit-loop.expect
index f76aa60466..407278094c 100644
--- a/t/chainlint/exit-loop.expect
+++ b/t/chainlint/exit-loop.expect
@@ -1,24 +1,24 @@
-(
- for i in a b c
- do
- foo || exit 1
- bar &&
- baz
- done
-) &&
-(
- while true
- do
- foo || exit 1
- bar &&
- baz
- done
-) &&
-(
- i=0 &&
- while test $i -lt 10
- do
- echo $i || exit
- i=$(($i + 1))
- done
-)
+2 (
+3 for i in a b c
+4 do
+5 foo || exit 1
+6 bar &&
+7 baz
+8 done
+9 ) &&
+10 (
+11 while true
+12 do
+13 foo || exit 1
+14 bar &&
+15 baz
+16 done
+17 ) &&
+18 (
+19 i=0 &&
+20 while test $i -lt 10
+21 do
+22 echo $i || exit
+23 i=$(($i + 1))
+24 done
+25 )
diff --git a/t/chainlint/exit-loop.test b/t/chainlint/exit-loop.test
index 2f038207e1..7e8b68b465 100644
--- a/t/chainlint/exit-loop.test
+++ b/t/chainlint/exit-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'exit-loop' '
(
for i in a b c
do
@@ -25,3 +26,4 @@
i=$(($i + 1))
done
)
+'
diff --git a/t/chainlint/exit-subshell.expect b/t/chainlint/exit-subshell.expect
index da80339f78..793db12453 100644
--- a/t/chainlint/exit-subshell.expect
+++ b/t/chainlint/exit-subshell.expect
@@ -1,5 +1,5 @@
-(
- foo || exit 1
- bar &&
- baz
-)
+2 (
+3 foo || exit 1
+4 bar &&
+5 baz
+6 )
diff --git a/t/chainlint/exit-subshell.test b/t/chainlint/exit-subshell.test
index 4e6ab69b88..05dff55cd7 100644
--- a/t/chainlint/exit-subshell.test
+++ b/t/chainlint/exit-subshell.test
@@ -1,6 +1,8 @@
+test_expect_success 'exit-subshell' '
(
# LINT: "|| exit {n}" valid subshell escape without hurting &&-chain
foo || exit 1
bar &&
baz
)
+'
diff --git a/t/chainlint/for-loop-abbreviated.expect b/t/chainlint/for-loop-abbreviated.expect
index a21007a63f..5574831976 100644
--- a/t/chainlint/for-loop-abbreviated.expect
+++ b/t/chainlint/for-loop-abbreviated.expect
@@ -1,5 +1,5 @@
-for it
-do
- path=$(expr "$it" : ( [^:]*) ) &&
- git update-index --add "$path" || exit
-done
+2 for it
+3 do
+4 path=$(expr "$it" : ([^:]*)) &&
+5 git update-index --add "$path" || exit
+6 done
diff --git a/t/chainlint/for-loop-abbreviated.test b/t/chainlint/for-loop-abbreviated.test
index 1084eccb89..1dd14f2a44 100644
--- a/t/chainlint/for-loop-abbreviated.test
+++ b/t/chainlint/for-loop-abbreviated.test
@@ -1,6 +1,8 @@
+test_expect_success 'for-loop-abbreviated' '
# LINT: for-loop lacking optional "in [word...]" before "do"
for it
do
path=$(expr "$it" : '\([^:]*\)') &&
git update-index --add "$path" || exit
done
+'
diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect
index d65c82129a..5029eacce3 100644
--- a/t/chainlint/for-loop.expect
+++ b/t/chainlint/for-loop.expect
@@ -1,13 +1,14 @@
-(
- for i in a b c
- do
- echo $i ?!AMP?!
- cat <<-\EOF ?!LOOP?!
- bar
- EOF
- done ?!AMP?!
- for i in a b c; do
- echo $i &&
- cat $i ?!LOOP?!
- done
-)
+2 (
+3 for i in a b c
+4 do
+5 echo $i ?!LINT: missing '&&'?!
+6 cat <<-\EOF ?!LINT: missing '|| exit 1'?!
+7 bar
+8 EOF
+9 done ?!LINT: missing '&&'?!
+10
+11 for i in a b c; do
+12 echo $i &&
+13 cat $i ?!LINT: missing '|| exit 1'?!
+14 done
+15 )
diff --git a/t/chainlint/for-loop.test b/t/chainlint/for-loop.test
index 6cb3428158..6f2489eb19 100644
--- a/t/chainlint/for-loop.test
+++ b/t/chainlint/for-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'for-loop' '
(
# LINT: "for", "do", "done" do not need "&&"
for i in a b c
@@ -17,3 +18,4 @@
cat $i
done
)
+'
diff --git a/t/chainlint/function.expect b/t/chainlint/function.expect
index a14388e6b9..9e46a3554a 100644
--- a/t/chainlint/function.expect
+++ b/t/chainlint/function.expect
@@ -1,11 +1,11 @@
-sha1_file ( ) {
- echo "$*" | sed "s#..#.git/objects/&/#"
-} &&
-
-remove_object ( ) {
- file=$(sha1_file "$*") &&
- test -e "$file" ?!AMP?!
- rm -f "$file"
-} ?!AMP?!
-
-sha1_file arg && remove_object arg
+2 sha1_file() {
+3 echo "$*" | sed "s#..#.git/objects/&/#"
+4 } &&
+5
+6 remove_object() {
+7 file=$(sha1_file "$*") &&
+8 test -e "$file" ?!LINT: missing '&&'?!
+9 rm -f "$file"
+10 } ?!LINT: missing '&&'?!
+11
+12 sha1_file arg && remove_object arg
diff --git a/t/chainlint/function.test b/t/chainlint/function.test
index 5ee59562c9..763fcf3f87 100644
--- a/t/chainlint/function.test
+++ b/t/chainlint/function.test
@@ -1,3 +1,4 @@
+test_expect_success 'function' '
# LINT: "()" in function definition not mistaken for subshell
sha1_file() {
echo "$*" | sed "s#..#.git/objects/&/#"
@@ -11,3 +12,4 @@ remove_object() {
}
sha1_file arg && remove_object arg
+'
diff --git a/t/chainlint/here-doc-body-indent.expect b/t/chainlint/here-doc-body-indent.expect
new file mode 100644
index 0000000000..4306faee86
--- /dev/null
+++ b/t/chainlint/here-doc-body-indent.expect
@@ -0,0 +1,2 @@
+2 echo "we should find this" ?!LINT: missing '&&'?!
+3 echo "even though our heredoc has its indent stripped"
diff --git a/t/chainlint/here-doc-body-indent.test b/t/chainlint/here-doc-body-indent.test
new file mode 100644
index 0000000000..39ff970ef3
--- /dev/null
+++ b/t/chainlint/here-doc-body-indent.test
@@ -0,0 +1,4 @@
+test_expect_success 'here-doc-body-indent' - <<-\EOT
+ echo "we should find this"
+ echo "even though our heredoc has its indent stripped"
+EOT
diff --git a/t/chainlint/here-doc-body-pathological.expect b/t/chainlint/here-doc-body-pathological.expect
new file mode 100644
index 0000000000..2f8ea03a47
--- /dev/null
+++ b/t/chainlint/here-doc-body-pathological.expect
@@ -0,0 +1,7 @@
+2 echo "outer here-doc does not allow indented end-tag" ?!LINT: missing '&&'?!
+3 cat >file <<-\EOF &&
+4 but this inner here-doc
+5 does allow indented EOF
+6 EOF
+7 echo "missing chain after" ?!LINT: missing '&&'?!
+8 echo "but this line is OK because it's the end"
diff --git a/t/chainlint/here-doc-body-pathological.test b/t/chainlint/here-doc-body-pathological.test
new file mode 100644
index 0000000000..7d2daa44f9
--- /dev/null
+++ b/t/chainlint/here-doc-body-pathological.test
@@ -0,0 +1,9 @@
+test_expect_success 'here-doc-body-pathological' - <<\EOF
+ echo "outer here-doc does not allow indented end-tag"
+ cat >file <<-\EOF &&
+ but this inner here-doc
+ does allow indented EOF
+ EOF
+ echo "missing chain after"
+ echo "but this line is OK because it's the end"
+EOF
diff --git a/t/chainlint/here-doc-body.expect b/t/chainlint/here-doc-body.expect
new file mode 100644
index 0000000000..df8d79bc0a
--- /dev/null
+++ b/t/chainlint/here-doc-body.expect
@@ -0,0 +1,7 @@
+2 echo "missing chain before" ?!LINT: missing '&&'?!
+3 cat >file <<-\EOF &&
+4 inside inner here-doc
+5 these are not shell commands
+6 EOF
+7 echo "missing chain after" ?!LINT: missing '&&'?!
+8 echo "but this line is OK because it's the end"
diff --git a/t/chainlint/here-doc-body.test b/t/chainlint/here-doc-body.test
new file mode 100644
index 0000000000..989ac2f4e1
--- /dev/null
+++ b/t/chainlint/here-doc-body.test
@@ -0,0 +1,9 @@
+test_expect_success 'here-doc-body' - <<\EOT
+ echo "missing chain before"
+ cat >file <<-\EOF &&
+ inside inner here-doc
+ these are not shell commands
+ EOF
+ echo "missing chain after"
+ echo "but this line is OK because it's the end"
+EOT
diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect
index 7d9c2b5607..965813f463 100644
--- a/t/chainlint/here-doc-close-subshell.expect
+++ b/t/chainlint/here-doc-close-subshell.expect
@@ -1,4 +1,4 @@
-(
- cat <<-\INPUT)
- fizz
- INPUT
+2 (
+3 cat <<-\INPUT)
+4 fizz
+5 INPUT
diff --git a/t/chainlint/here-doc-close-subshell.test b/t/chainlint/here-doc-close-subshell.test
index b857ff5467..2458f3323b 100644
--- a/t/chainlint/here-doc-close-subshell.test
+++ b/t/chainlint/here-doc-close-subshell.test
@@ -1,5 +1,7 @@
+test_expect_success 'here-doc-close-subshell' '
(
# LINT: line contains here-doc and closes nested subshell
cat <<-\INPUT)
fizz
INPUT
+'
diff --git a/t/chainlint/here-doc-double.expect b/t/chainlint/here-doc-double.expect
new file mode 100644
index 0000000000..e5e981889f
--- /dev/null
+++ b/t/chainlint/here-doc-double.expect
@@ -0,0 +1,2 @@
+8 echo "actual test commands" ?!LINT: missing '&&'?!
+9 echo "that should be checked"
diff --git a/t/chainlint/here-doc-double.test b/t/chainlint/here-doc-double.test
new file mode 100644
index 0000000000..777389f0d9
--- /dev/null
+++ b/t/chainlint/here-doc-double.test
@@ -0,0 +1,10 @@
+# This is obviously a ridiculous thing to do, but we should be able
+# to handle two here-docs on the same line, and attribute them
+# correctly.
+test_expect_success "$(cat <<END_OF_PREREQS)" 'here-doc-double' - <<\EOT
+SOME
+PREREQS
+END_OF_PREREQS
+ echo "actual test commands"
+ echo "that should be checked"
+EOT
diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect
index f92a7ce999..ec0e61505b 100644
--- a/t/chainlint/here-doc-indent-operator.expect
+++ b/t/chainlint/here-doc-indent-operator.expect
@@ -1,11 +1,11 @@
-cat >expect <<- EOF &&
-header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
-num_commits: $1
-chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
-EOF
-
-cat >expect << -EOF ?!AMP?!
-this is not indented
--EOF
-
-cleanup
+2 cat >expect <<- EOF &&
+3 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
+4 num_commits: $1
+5 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
+6 EOF
+7
+8 cat >expect << -EOF ?!LINT: missing '&&'?!
+9 this is not indented
+10 -EOF
+11
+12 cleanup
diff --git a/t/chainlint/here-doc-indent-operator.test b/t/chainlint/here-doc-indent-operator.test
index c8a6f18eb4..a2656f47c1 100644
--- a/t/chainlint/here-doc-indent-operator.test
+++ b/t/chainlint/here-doc-indent-operator.test
@@ -1,3 +1,4 @@
+test_expect_success 'here-doc-indent-operator' '
# LINT: whitespace between operator "<<-" and tag legal
cat >expect <<- EOF &&
header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
@@ -11,3 +12,4 @@ this is not indented
-EOF
cleanup
+'
diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect
index b7364c82c8..8128f15b92 100644
--- a/t/chainlint/here-doc-multi-line-command-subst.expect
+++ b/t/chainlint/here-doc-multi-line-command-subst.expect
@@ -1,8 +1,8 @@
-(
- x=$(bobble <<-\END &&
- fossil
- vegetable
- END
- wiffle) ?!AMP?!
- echo $x
-)
+2 (
+3 x=$(bobble <<-\END &&
+4 fossil
+5 vegetable
+6 END
+7 wiffle) ?!LINT: missing '&&'?!
+8 echo $x
+9 )
diff --git a/t/chainlint/here-doc-multi-line-command-subst.test b/t/chainlint/here-doc-multi-line-command-subst.test
index 899bc5de8b..8710a8c483 100644
--- a/t/chainlint/here-doc-multi-line-command-subst.test
+++ b/t/chainlint/here-doc-multi-line-command-subst.test
@@ -1,3 +1,4 @@
+test_expect_success 'here-doc-multi-line-command-subst' '
(
# LINT: line contains here-doc and opens multi-line $(...)
x=$(bobble <<-\END &&
@@ -7,3 +8,4 @@
wiffle)
echo $x
)
+'
diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect
index 6c13bdcbfb..a03a04ff3d 100644
--- a/t/chainlint/here-doc-multi-line-string.expect
+++ b/t/chainlint/here-doc-multi-line-string.expect
@@ -1,7 +1,7 @@
-(
- cat <<-\TXT && echo "multi-line
- string" ?!AMP?!
- fizzle
- TXT
- bap
-)
+2 (
+3 cat <<-\TXT && echo "multi-line
+4 string" ?!LINT: missing '&&'?!
+5 fizzle
+6 TXT
+7 bap
+8 )
diff --git a/t/chainlint/here-doc-multi-line-string.test b/t/chainlint/here-doc-multi-line-string.test
index a53edbcc8d..2f496002fd 100644
--- a/t/chainlint/here-doc-multi-line-string.test
+++ b/t/chainlint/here-doc-multi-line-string.test
@@ -1,3 +1,4 @@
+test_expect_success 'here-doc-multi-line-string' '
(
# LINT: line contains here-doc and opens multi-line string
cat <<-\TXT && echo "multi-line
@@ -6,3 +7,4 @@
TXT
bap
)
+'
diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect
index 1df3f78282..2c382dd8eb 100644
--- a/t/chainlint/here-doc.expect
+++ b/t/chainlint/here-doc.expect
@@ -1,25 +1,25 @@
-boodle wobba \
- gorgo snoot \
- wafta snurb <<EOF &&
-quoth the raven,
-nevermore...
-EOF
-
-cat <<-Arbitrary_Tag_42 >foo &&
-snoz
-boz
-woz
-Arbitrary_Tag_42
-
-cat <<"zump" >boo &&
-snoz
-boz
-woz
-zump
-
-horticulture <<\EOF
-gomez
-morticia
-wednesday
-pugsly
-EOF
+2 boodle wobba \
+3 gorgo snoot \
+4 wafta snurb <<EOF &&
+5 quoth the raven,
+6 nevermore...
+7 EOF
+8
+9 cat <<-Arbitrary_Tag_42 >foo &&
+10 snoz
+11 boz
+12 woz
+13 Arbitrary_Tag_42
+14
+15 cat <<"zump" >boo &&
+16 snoz
+17 boz
+18 woz
+19 zump
+20
+21 horticulture <<\EOF
+22 gomez
+23 morticia
+24 wednesday
+25 pugsly
+26 EOF
diff --git a/t/chainlint/here-doc.test b/t/chainlint/here-doc.test
index 3f5f92cad3..c91b695319 100644
--- a/t/chainlint/here-doc.test
+++ b/t/chainlint/here-doc.test
@@ -1,3 +1,4 @@
+test_expect_success 'here-doc' '
# LINT: stitch together incomplete \-ending lines
# LINT: swallow here-doc to avoid false positives in content
boodle wobba \
@@ -28,3 +29,4 @@ morticia
wednesday
pugsly
EOF
+'
diff --git a/t/chainlint/if-condition-split.expect b/t/chainlint/if-condition-split.expect
index ee745ef8d7..6d2a03dfdb 100644
--- a/t/chainlint/if-condition-split.expect
+++ b/t/chainlint/if-condition-split.expect
@@ -1,7 +1,7 @@
-if bob &&
- marcia ||
- kevin
-then
- echo "nomads" ?!AMP?!
- echo "for sure"
-fi
+2 if bob &&
+3 marcia ||
+4 kevin
+5 then
+6 echo "nomads" ?!LINT: missing '&&'?!
+7 echo "for sure"
+8 fi
diff --git a/t/chainlint/if-condition-split.test b/t/chainlint/if-condition-split.test
index 240daa9fd5..9a3b3ed04a 100644
--- a/t/chainlint/if-condition-split.test
+++ b/t/chainlint/if-condition-split.test
@@ -1,3 +1,4 @@
+test_expect_success 'if-condition-split' '
# LINT: "if" condition split across multiple lines at "&&" or "||"
if bob &&
marcia ||
@@ -6,3 +7,4 @@ then
echo "nomads"
echo "for sure"
fi
+'
diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect
index d6514ae749..7e3ba740de 100644
--- a/t/chainlint/if-in-loop.expect
+++ b/t/chainlint/if-in-loop.expect
@@ -1,12 +1,12 @@
-(
- for i in a b c
- do
- if false
- then
- echo "err"
- exit 1
- fi ?!AMP?!
- foo
- done ?!AMP?!
- bar
-)
+2 (
+3 for i in a b c
+4 do
+5 if false
+6 then
+7 echo "err"
+8 exit 1
+9 fi ?!LINT: missing '&&'?!
+10 foo
+11 done ?!LINT: missing '&&'?!
+12 bar
+13 )
diff --git a/t/chainlint/if-in-loop.test b/t/chainlint/if-in-loop.test
index 90c23976fe..5be9d1cfa5 100644
--- a/t/chainlint/if-in-loop.test
+++ b/t/chainlint/if-in-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'if-in-loop' '
(
for i in a b c
do
@@ -13,3 +14,4 @@
done
bar
)
+'
diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect
index cbaaf857d4..924caa2e4e 100644
--- a/t/chainlint/if-then-else.expect
+++ b/t/chainlint/if-then-else.expect
@@ -1,22 +1,22 @@
-(
- if test -n ""
- then
- echo very ?!AMP?!
- echo empty
- elif test -z ""
- then
- echo foo
- else
- echo foo &&
- cat <<-\EOF
- bar
- EOF
- fi ?!AMP?!
- echo poodle
-) &&
-(
- if test -n ""; then
- echo very &&
- echo empty
- fi
-)
+2 (
+3 if test -n ""
+4 then
+5 echo very ?!LINT: missing '&&'?!
+6 echo empty
+7 elif test -z ""
+8 then
+9 echo foo
+10 else
+11 echo foo &&
+12 cat <<-\EOF
+13 bar
+14 EOF
+15 fi ?!LINT: missing '&&'?!
+16 echo poodle
+17 ) &&
+18 (
+19 if test -n ""; then
+20 echo very &&
+21 echo empty
+22 fi
+23 )
diff --git a/t/chainlint/if-then-else.test b/t/chainlint/if-then-else.test
index 2055336c2b..6582a7f440 100644
--- a/t/chainlint/if-then-else.test
+++ b/t/chainlint/if-then-else.test
@@ -1,3 +1,4 @@
+test_expect_success 'if-then-else' '
(
# LINT: "if", "then", "elif", "else", "fi" do not need "&&"
if test -n ""
@@ -27,3 +28,4 @@
echo empty
fi
)
+'
diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect
index 134d3a14f5..b15e00b901 100644
--- a/t/chainlint/incomplete-line.expect
+++ b/t/chainlint/incomplete-line.expect
@@ -1,10 +1,10 @@
-line 1 \
-line 2 \
-line 3 \
-line 4 &&
-(
- line 5 \
- line 6 \
- line 7 \
- line 8
-)
+2 line 1 \
+3 line 2 \
+4 line 3 \
+5 line 4 &&
+6 (
+7 line 5 \
+8 line 6 \
+9 line 7 \
+10 line 8
+11 )
diff --git a/t/chainlint/incomplete-line.test b/t/chainlint/incomplete-line.test
index d856658083..74a93021eb 100644
--- a/t/chainlint/incomplete-line.test
+++ b/t/chainlint/incomplete-line.test
@@ -1,3 +1,4 @@
+test_expect_success 'incomplete-line' '
# LINT: stitch together all incomplete \-ending lines
line 1 \
line 2 \
@@ -10,3 +11,4 @@ line 4 &&
line 7 \
line 8
)
+'
diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect
index 6bad218530..4b4080124e 100644
--- a/t/chainlint/inline-comment.expect
+++ b/t/chainlint/inline-comment.expect
@@ -1,8 +1,8 @@
-(
- foobar && # comment 1
- barfoo ?!AMP?! # wrong position for &&
- flibble "not a # comment"
-) &&
-
-(cd foo &&
- flibble "not a # comment")
+2 (
+3 foobar && # comment 1
+4 barfoo ?!LINT: missing '&&'?! # wrong position for &&
+5 flibble "not a # comment"
+6 ) &&
+7
+8 (cd foo &&
+9 flibble "not a # comment")
diff --git a/t/chainlint/inline-comment.test b/t/chainlint/inline-comment.test
index 8f26856e77..4fbbf1058a 100644
--- a/t/chainlint/inline-comment.test
+++ b/t/chainlint/inline-comment.test
@@ -1,3 +1,4 @@
+test_expect_success 'inline-comment' '
(
# LINT: swallow inline comment (leaving command intact)
foobar && # comment 1
@@ -10,3 +11,4 @@
# LINT: "#" in string in cuddled subshell not misinterpreted as comment
(cd foo &&
flibble "not a # comment")
+'
diff --git a/t/chainlint/loop-detect-failure.expect b/t/chainlint/loop-detect-failure.expect
index a66025c39d..7d846b878d 100644
--- a/t/chainlint/loop-detect-failure.expect
+++ b/t/chainlint/loop-detect-failure.expect
@@ -1,15 +1,15 @@
-git init r1 &&
-for n in 1 2 3 4 5
-do
- echo "This is file: $n" > r1/file.$n &&
- git -C r1 add file.$n &&
- git -C r1 commit -m "$n" || return 1
-done &&
-
-git init r2 &&
-for n in 1000 10000
-do
- printf "%"$n"s" X > r2/large.$n &&
- git -C r2 add large.$n &&
- git -C r2 commit -m "$n" ?!LOOP?!
-done
+2 git init r1 &&
+3 for n in 1 2 3 4 5
+4 do
+5 echo "This is file: $n" > r1/file.$n &&
+6 git -C r1 add file.$n &&
+7 git -C r1 commit -m "$n" || return 1
+8 done &&
+9
+10 git init r2 &&
+11 for n in 1000 10000
+12 do
+13 printf "%"$n"s" X > r2/large.$n &&
+14 git -C r2 add large.$n &&
+15 git -C r2 commit -m "$n" ?!LINT: missing '|| return 1'?!
+16 done
diff --git a/t/chainlint/loop-detect-failure.test b/t/chainlint/loop-detect-failure.test
index b9791cc802..44673aa394 100644
--- a/t/chainlint/loop-detect-failure.test
+++ b/t/chainlint/loop-detect-failure.test
@@ -1,3 +1,4 @@
+test_expect_success 'loop-detect-failure' '
git init r1 &&
# LINT: loop handles failure explicitly with "|| return 1"
for n in 1 2 3 4 5
@@ -15,3 +16,4 @@ do
git -C r2 add large.$n &&
git -C r2 commit -m "$n"
done
+'
diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect
index 24da9e86d5..0f180b08de 100644
--- a/t/chainlint/loop-detect-status.expect
+++ b/t/chainlint/loop-detect-status.expect
@@ -1,18 +1,18 @@
-( while test $i -le $blobcount
-do
- printf "Generating blob $i/$blobcount\r" >& 2 &&
- printf "blob\nmark :$i\ndata $blobsize\n" &&
- #test-tool genrandom $i $blobsize &&
- printf "%-${blobsize}s" $i &&
- echo "M 100644 :$i $i" >> commit &&
- i=$(($i+1)) ||
- echo $? > exit-status
-done &&
-echo "commit refs/heads/main" &&
-echo "author A U Thor <author@email.com> 123456789 +0000" &&
-echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
-echo "data 5" &&
-echo ">2gb" &&
-cat commit ) |
-git fast-import --big-file-threshold=2 &&
-test ! -f exit-status
+2 (while test $i -le $blobcount
+3 do
+4 printf "Generating blob $i/$blobcount\r" >&2 &&
+5 printf "blob\nmark :$i\ndata $blobsize\n" &&
+6 #test-tool genrandom $i $blobsize &&
+7 printf "%-${blobsize}s" $i &&
+8 echo "M 100644 :$i $i" >> commit &&
+9 i=$(($i+1)) ||
+10 echo $? > exit-status
+11 done &&
+12 echo "commit refs/heads/main" &&
+13 echo "author A U Thor <author@email.com> 123456789 +0000" &&
+14 echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
+15 echo "data 5" &&
+16 echo ">2gb" &&
+17 cat commit) |
+18 git fast-import --big-file-threshold=2 &&
+19 test ! -f exit-status
diff --git a/t/chainlint/loop-detect-status.test b/t/chainlint/loop-detect-status.test
index 1c6c23cfc9..8b639be073 100644
--- a/t/chainlint/loop-detect-status.test
+++ b/t/chainlint/loop-detect-status.test
@@ -1,3 +1,4 @@
+test_expect_success 'loop-detect-status' '
# LINT: "$?" handled explicitly within loop body
(while test $i -le $blobcount
do
@@ -17,3 +18,4 @@
cat commit) |
git fast-import --big-file-threshold=2 &&
test ! -f exit-status
+'
diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect
index 6c5d6e5b24..32e076ad1b 100644
--- a/t/chainlint/loop-in-if.expect
+++ b/t/chainlint/loop-in-if.expect
@@ -1,12 +1,12 @@
-(
- if true
- then
- while true
- do
- echo "pop" ?!AMP?!
- echo "glup" ?!LOOP?!
- done ?!AMP?!
- foo
- fi ?!AMP?!
- bar
-)
+2 (
+3 if true
+4 then
+5 while true
+6 do
+7 echo "pop" ?!LINT: missing '&&'?!
+8 echo "glup" ?!LINT: missing '|| exit 1'?!
+9 done ?!LINT: missing '&&'?!
+10 foo
+11 fi ?!LINT: missing '&&'?!
+12 bar
+13 )
diff --git a/t/chainlint/loop-in-if.test b/t/chainlint/loop-in-if.test
index dfcc3f98fb..b0d0d393cf 100644
--- a/t/chainlint/loop-in-if.test
+++ b/t/chainlint/loop-in-if.test
@@ -1,3 +1,4 @@
+test_expect_success 'loop-in-if' '
(
if true
then
@@ -13,3 +14,4 @@
fi
bar
)
+'
diff --git a/t/chainlint/loop-upstream-pipe.expect b/t/chainlint/loop-upstream-pipe.expect
index 0b82ecc4b9..bef82479ca 100644
--- a/t/chainlint/loop-upstream-pipe.expect
+++ b/t/chainlint/loop-upstream-pipe.expect
@@ -1,10 +1,10 @@
-(
- git rev-list --objects --no-object-names base..loose |
- while read oid
- do
- path="$objdir/$(test_oid_to_path "$oid")" &&
- printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" ||
- echo "object list generation failed for $oid"
- done |
- sort -k1
-) >expect &&
+2 (
+3 git rev-list --objects --no-object-names base..loose |
+4 while read oid
+5 do
+6 path="$objdir/$(test_oid_to_path "$oid")" &&
+7 printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" ||
+8 echo "object list generation failed for $oid"
+9 done |
+10 sort -k1
+11 ) >expect &&
diff --git a/t/chainlint/loop-upstream-pipe.test b/t/chainlint/loop-upstream-pipe.test
index efb77da897..8415a4db27 100644
--- a/t/chainlint/loop-upstream-pipe.test
+++ b/t/chainlint/loop-upstream-pipe.test
@@ -1,3 +1,4 @@
+test_expect_success 'loop-upstream-pipe' '
(
git rev-list --objects --no-object-names base..loose |
while read oid
@@ -9,3 +10,4 @@
done |
sort -k1
) >expect &&
+'
diff --git a/t/chainlint/multi-line-nested-command-substitution.expect b/t/chainlint/multi-line-nested-command-substitution.expect
index 300058341b..ad27e43e05 100644
--- a/t/chainlint/multi-line-nested-command-substitution.expect
+++ b/t/chainlint/multi-line-nested-command-substitution.expect
@@ -1,18 +1,18 @@
-(
- foo &&
- x=$(
- echo bar |
- cat
- ) &&
- echo ok
-) |
-sort &&
-(
- bar &&
- x=$(echo bar |
- cat
- ) &&
- y=$(echo baz |
- fip) &&
- echo fail
-)
+2 (
+3 foo &&
+4 x=$(
+5 echo bar |
+6 cat
+7 ) &&
+8 echo ok
+9 ) |
+10 sort &&
+11 (
+12 bar &&
+13 x=$(echo bar |
+14 cat
+15 ) &&
+16 y=$(echo baz |
+17 fip) &&
+18 echo fail
+19 )
diff --git a/t/chainlint/multi-line-nested-command-substitution.test b/t/chainlint/multi-line-nested-command-substitution.test
index 300058341b..e811c63f2b 100644
--- a/t/chainlint/multi-line-nested-command-substitution.test
+++ b/t/chainlint/multi-line-nested-command-substitution.test
@@ -1,3 +1,4 @@
+test_expect_success 'multi-line-nested-command-substitution' '
(
foo &&
x=$(
@@ -16,3 +17,4 @@ sort &&
fip) &&
echo fail
)
+'
diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect
index 27ff95218e..9d33297525 100644
--- a/t/chainlint/multi-line-string.expect
+++ b/t/chainlint/multi-line-string.expect
@@ -1,14 +1,14 @@
-(
- x="line 1
- line 2
- line 3" &&
- y="line 1
- line2" ?!AMP?!
- foobar
-) &&
-(
- echo "xyz" "abc
- def
- ghi" &&
- barfoo
-)
+2 (
+3 x="line 1
+4 line 2
+5 line 3" &&
+6 y="line 1
+7 line2" ?!LINT: missing '&&'?!
+8 foobar
+9 ) &&
+10 (
+11 echo "xyz" "abc
+12 def
+13 ghi" &&
+14 barfoo
+15 )
diff --git a/t/chainlint/multi-line-string.test b/t/chainlint/multi-line-string.test
index 4a0af2107d..7b5048d2ea 100644
--- a/t/chainlint/multi-line-string.test
+++ b/t/chainlint/multi-line-string.test
@@ -1,3 +1,4 @@
+test_expect_success 'multi-line-string' '
(
x="line 1
line 2
@@ -13,3 +14,4 @@
ghi" &&
barfoo
)
+'
diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect
index ad4c2d949e..0a6f3c29b2 100644
--- a/t/chainlint/negated-one-liner.expect
+++ b/t/chainlint/negated-one-liner.expect
@@ -1,5 +1,5 @@
-! (foo && bar) &&
-! (foo && bar) >baz &&
-
-! (foo; ?!AMP?! bar) &&
-! (foo; ?!AMP?! bar) >baz
+2 ! (foo && bar) &&
+3 ! (foo && bar) >baz &&
+4
+5 ! (foo; ?!LINT: missing '&&'?! bar) &&
+6 ! (foo; ?!LINT: missing '&&'?! bar) >baz
diff --git a/t/chainlint/negated-one-liner.test b/t/chainlint/negated-one-liner.test
index c9598e9153..30f4cc5a9b 100644
--- a/t/chainlint/negated-one-liner.test
+++ b/t/chainlint/negated-one-liner.test
@@ -1,3 +1,4 @@
+test_expect_success 'negated-one-liner' '
# LINT: top-level one-liner subshell
! (foo && bar) &&
! (foo && bar) >baz &&
@@ -5,3 +6,4 @@
# LINT: top-level one-liner subshell missing internal "&&"
! (foo; bar) &&
! (foo; bar) >baz
+'
diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect
index 2a86885ee6..fec2c74274 100644
--- a/t/chainlint/nested-cuddled-subshell.expect
+++ b/t/chainlint/nested-cuddled-subshell.expect
@@ -1,19 +1,25 @@
-(
- (cd foo &&
- bar
- ) &&
- (cd foo &&
- bar
- ) ?!AMP?!
- (
- cd foo &&
- bar) &&
- (
- cd foo &&
- bar) ?!AMP?!
- (cd foo &&
- bar) &&
- (cd foo &&
- bar) ?!AMP?!
- foobar
-)
+2 (
+3 (cd foo &&
+4 bar
+5 ) &&
+6
+7 (cd foo &&
+8 bar
+9 ) ?!LINT: missing '&&'?!
+10
+11 (
+12 cd foo &&
+13 bar) &&
+14
+15 (
+16 cd foo &&
+17 bar) ?!LINT: missing '&&'?!
+18
+19 (cd foo &&
+20 bar) &&
+21
+22 (cd foo &&
+23 bar) ?!LINT: missing '&&'?!
+24
+25 foobar
+26 )
diff --git a/t/chainlint/nested-cuddled-subshell.test b/t/chainlint/nested-cuddled-subshell.test
index 8fd656c7b5..31e92d3be4 100644
--- a/t/chainlint/nested-cuddled-subshell.test
+++ b/t/chainlint/nested-cuddled-subshell.test
@@ -1,3 +1,4 @@
+test_expect_success 'nested-cuddled-subshell' '
(
# LINT: opening "(" cuddled with first nested subshell statement
(cd foo &&
@@ -29,3 +30,4 @@
foobar
)
+'
diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect
index 29b3832a98..571f4c9514 100644
--- a/t/chainlint/nested-here-doc.expect
+++ b/t/chainlint/nested-here-doc.expect
@@ -1,30 +1,30 @@
-cat <<ARBITRARY >foop &&
-naddle
-fub <<EOF
- nozzle
- noodle
-EOF
-formp
-ARBITRARY
-
-(
- cat <<-\INPUT_END &&
- fish are mice
- but geese go slow
- data <<EOF
- perl is lerp
- and nothing else
- EOF
- toink
- INPUT_END
-
- cat <<-\EOT ?!AMP?!
- text goes here
- data <<EOF
- data goes here
- EOF
- more test here
- EOT
-
- foobar
-)
+2 cat <<ARBITRARY >foop &&
+3 naddle
+4 fub <<EOF
+5 nozzle
+6 noodle
+7 EOF
+8 formp
+9 ARBITRARY
+10
+11 (
+12 cat <<-\INPUT_END &&
+13 fish are mice
+14 but geese go slow
+15 data <<EOF
+16 perl is lerp
+17 and nothing else
+18 EOF
+19 toink
+20 INPUT_END
+21
+22 cat <<-\EOT ?!LINT: missing '&&'?!
+23 text goes here
+24 data <<EOF
+25 data goes here
+26 EOF
+27 more test here
+28 EOT
+29
+30 foobar
+31 )
diff --git a/t/chainlint/nested-here-doc.test b/t/chainlint/nested-here-doc.test
index f35404bf0f..9505c47a34 100644
--- a/t/chainlint/nested-here-doc.test
+++ b/t/chainlint/nested-here-doc.test
@@ -1,3 +1,4 @@
+test_expect_success 'nested-here-doc' '
# LINT: inner "EOF" not misintrepreted as closing ARBITRARY here-doc
cat <<ARBITRARY >foop &&
naddle
@@ -31,3 +32,4 @@ ARBITRARY
foobar
)
+'
diff --git a/t/chainlint/nested-loop-detect-failure.expect b/t/chainlint/nested-loop-detect-failure.expect
index 4793a0e8e1..b4aaa621a2 100644
--- a/t/chainlint/nested-loop-detect-failure.expect
+++ b/t/chainlint/nested-loop-detect-failure.expect
@@ -1,31 +1,31 @@
-for i in 0 1 2 3 4 5 6 7 8 9 ;
-do
- for j in 0 1 2 3 4 5 6 7 8 9 ;
- do
- echo "$i$j" > "path$i$j" ?!LOOP?!
- done ?!LOOP?!
-done &&
-
-for i in 0 1 2 3 4 5 6 7 8 9 ;
-do
- for j in 0 1 2 3 4 5 6 7 8 9 ;
- do
- echo "$i$j" > "path$i$j" || return 1
- done
-done &&
-
-for i in 0 1 2 3 4 5 6 7 8 9 ;
-do
- for j in 0 1 2 3 4 5 6 7 8 9 ;
- do
- echo "$i$j" > "path$i$j" ?!LOOP?!
- done || return 1
-done &&
-
-for i in 0 1 2 3 4 5 6 7 8 9 ;
-do
- for j in 0 1 2 3 4 5 6 7 8 9 ;
- do
- echo "$i$j" > "path$i$j" || return 1
- done || return 1
-done
+2 for i in 0 1 2 3 4 5 6 7 8 9;
+3 do
+4 for j in 0 1 2 3 4 5 6 7 8 9;
+5 do
+6 echo "$i$j" >"path$i$j" ?!LINT: missing '|| return 1'?!
+7 done ?!LINT: missing '|| return 1'?!
+8 done &&
+9
+10 for i in 0 1 2 3 4 5 6 7 8 9;
+11 do
+12 for j in 0 1 2 3 4 5 6 7 8 9;
+13 do
+14 echo "$i$j" >"path$i$j" || return 1
+15 done
+16 done &&
+17
+18 for i in 0 1 2 3 4 5 6 7 8 9;
+19 do
+20 for j in 0 1 2 3 4 5 6 7 8 9;
+21 do
+22 echo "$i$j" >"path$i$j" ?!LINT: missing '|| return 1'?!
+23 done || return 1
+24 done &&
+25
+26 for i in 0 1 2 3 4 5 6 7 8 9;
+27 do
+28 for j in 0 1 2 3 4 5 6 7 8 9;
+29 do
+30 echo "$i$j" >"path$i$j" || return 1
+31 done || return 1
+32 done
diff --git a/t/chainlint/nested-loop-detect-failure.test b/t/chainlint/nested-loop-detect-failure.test
index e6f0c1acfb..3d4b657412 100644
--- a/t/chainlint/nested-loop-detect-failure.test
+++ b/t/chainlint/nested-loop-detect-failure.test
@@ -1,3 +1,4 @@
+test_expect_success 'nested-loop-detect-failure' '
# LINT: neither loop handles failure explicitly with "|| return 1"
for i in 0 1 2 3 4 5 6 7 8 9;
do
@@ -33,3 +34,4 @@ do
echo "$i$j" >"path$i$j" || return 1
done || return 1
done
+'
diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect
index 9138cf386d..078c6f275f 100644
--- a/t/chainlint/nested-subshell-comment.expect
+++ b/t/chainlint/nested-subshell-comment.expect
@@ -1,11 +1,11 @@
-(
- foo &&
- (
- bar &&
- # bottles wobble while fiddles gobble
- # minor numbers of cows (or do they?)
- baz &&
- snaff
- ) ?!AMP?!
- fuzzy
-)
+2 (
+3 foo &&
+4 (
+5 bar &&
+6 # bottles wobble while fiddles gobble
+7 # minor numbers of cows (or do they?)
+8 baz &&
+9 snaff
+10 ) ?!LINT: missing '&&'?!
+11 fuzzy
+12 )
diff --git a/t/chainlint/nested-subshell-comment.test b/t/chainlint/nested-subshell-comment.test
index 0215cdb192..b430580ce0 100644
--- a/t/chainlint/nested-subshell-comment.test
+++ b/t/chainlint/nested-subshell-comment.test
@@ -1,3 +1,4 @@
+test_expect_success 'nested-subshell-comment' '
(
foo &&
(
@@ -11,3 +12,4 @@
)
fuzzy
)
+'
diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect
index 02e0a9f1bb..a8d85d5d5b 100644
--- a/t/chainlint/nested-subshell.expect
+++ b/t/chainlint/nested-subshell.expect
@@ -1,12 +1,13 @@
-(
- cd foo &&
- (
- echo a &&
- echo b
- ) >file &&
- cd foo &&
- (
- echo a ?!AMP?!
- echo b
- ) >file
-)
+2 (
+3 cd foo &&
+4 (
+5 echo a &&
+6 echo b
+7 ) >file &&
+8
+9 cd foo &&
+10 (
+11 echo a ?!LINT: missing '&&'?!
+12 echo b
+13 ) >file
+14 )
diff --git a/t/chainlint/nested-subshell.test b/t/chainlint/nested-subshell.test
index 440ee9992d..c31da34b73 100644
--- a/t/chainlint/nested-subshell.test
+++ b/t/chainlint/nested-subshell.test
@@ -1,3 +1,4 @@
+test_expect_success 'nested-subshell' '
(
cd foo &&
(
@@ -11,3 +12,4 @@
echo b
) >file
)
+'
diff --git a/t/chainlint/not-heredoc.expect b/t/chainlint/not-heredoc.expect
index 2e9bb135fe..5d51705a7a 100644
--- a/t/chainlint/not-heredoc.expect
+++ b/t/chainlint/not-heredoc.expect
@@ -1,14 +1,14 @@
-echo "<<<<<<< ours" &&
-echo ourside &&
-echo "=======" &&
-echo theirside &&
-echo ">>>>>>> theirs" &&
-
-(
- echo "<<<<<<< ours" &&
- echo ourside &&
- echo "=======" &&
- echo theirside &&
- echo ">>>>>>> theirs" ?!AMP?!
- poodle
-) >merged
+2 echo "<<<<<<< ours" &&
+3 echo ourside &&
+4 echo "=======" &&
+5 echo theirside &&
+6 echo ">>>>>>> theirs" &&
+7
+8 (
+9 echo "<<<<<<< ours" &&
+10 echo ourside &&
+11 echo "=======" &&
+12 echo theirside &&
+13 echo ">>>>>>> theirs" ?!LINT: missing '&&'?!
+14 poodle
+15 ) >merged
diff --git a/t/chainlint/not-heredoc.test b/t/chainlint/not-heredoc.test
index 9aa57346cd..09711e45e0 100644
--- a/t/chainlint/not-heredoc.test
+++ b/t/chainlint/not-heredoc.test
@@ -1,3 +1,4 @@
+test_expect_success 'not-heredoc' '
# LINT: "<< ours" inside string is not here-doc
echo "<<<<<<< ours" &&
echo ourside &&
@@ -14,3 +15,4 @@ echo ">>>>>>> theirs" &&
echo ">>>>>>> theirs"
poodle
) >merged
+'
diff --git a/t/chainlint/one-liner-for-loop.expect b/t/chainlint/one-liner-for-loop.expect
index 51a3dc7c54..e1fcbd3639 100644
--- a/t/chainlint/one-liner-for-loop.expect
+++ b/t/chainlint/one-liner-for-loop.expect
@@ -1,9 +1,9 @@
-git init dir-rename-and-content &&
-(
- cd dir-rename-and-content &&
- test_write_lines 1 2 3 4 5 >foo &&
- mkdir olddir &&
- for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?!
- git add foo olddir &&
- git commit -m "original" &&
-)
+2 git init dir-rename-and-content &&
+3 (
+4 cd dir-rename-and-content &&
+5 test_write_lines 1 2 3 4 5 >foo &&
+6 mkdir olddir &&
+7 for i in a b c; do echo $i >olddir/$i; ?!LINT: missing '|| exit 1'?! done ?!LINT: missing '&&'?!
+8 git add foo olddir &&
+9 git commit -m "original" &&
+10 )
diff --git a/t/chainlint/one-liner-for-loop.test b/t/chainlint/one-liner-for-loop.test
index 4bd8c066c7..00afd7ef76 100644
--- a/t/chainlint/one-liner-for-loop.test
+++ b/t/chainlint/one-liner-for-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'one-liner-for-loop' '
git init dir-rename-and-content &&
(
cd dir-rename-and-content &&
@@ -8,3 +9,4 @@ git init dir-rename-and-content &&
git add foo olddir &&
git commit -m "original" &&
)
+'
diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect
index 57a7a444c1..5deeb05070 100644
--- a/t/chainlint/one-liner.expect
+++ b/t/chainlint/one-liner.expect
@@ -1,9 +1,9 @@
-(foo && bar) &&
-(foo && bar) |
-(foo && bar) >baz &&
-
-(foo; ?!AMP?! bar) &&
-(foo; ?!AMP?! bar) |
-(foo; ?!AMP?! bar) >baz &&
-
-(foo "bar; baz")
+2 (foo && bar) &&
+3 (foo && bar) |
+4 (foo && bar) >baz &&
+5
+6 (foo; ?!LINT: missing '&&'?! bar) &&
+7 (foo; ?!LINT: missing '&&'?! bar) |
+8 (foo; ?!LINT: missing '&&'?! bar) >baz &&
+9
+10 (foo "bar; baz")
diff --git a/t/chainlint/one-liner.test b/t/chainlint/one-liner.test
index be9858fa29..6e42ee1b5e 100644
--- a/t/chainlint/one-liner.test
+++ b/t/chainlint/one-liner.test
@@ -1,3 +1,4 @@
+test_expect_success 'one-liner' '
# LINT: top-level one-liner subshell
(foo && bar) &&
(foo && bar) |
@@ -10,3 +11,4 @@
# LINT: ";" in string not misinterpreted as broken &&-chain
(foo "bar; baz")
+'
diff --git a/t/chainlint/p4-filespec.expect b/t/chainlint/p4-filespec.expect
index 1290fd1ff2..cff3e4e3d1 100644
--- a/t/chainlint/p4-filespec.expect
+++ b/t/chainlint/p4-filespec.expect
@@ -1,4 +1,4 @@
-(
- p4 print -1 //depot/fiddle#42 >file &&
- foobar
-)
+2 (
+3 p4 print -1 //depot/fiddle#42 >file &&
+4 foobar
+5 )
diff --git a/t/chainlint/p4-filespec.test b/t/chainlint/p4-filespec.test
index 4fd2d6e2b8..8ba6b911dc 100644
--- a/t/chainlint/p4-filespec.test
+++ b/t/chainlint/p4-filespec.test
@@ -1,5 +1,7 @@
+test_expect_success 'p4-filespec' '
(
# LINT: Perforce revspec in filespec not misinterpreted as in-line comment
p4 print -1 //depot/fiddle#42 >file &&
foobar
)
+'
diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect
index 2cfc028297..d947c76584 100644
--- a/t/chainlint/pipe.expect
+++ b/t/chainlint/pipe.expect
@@ -1,8 +1,10 @@
-(
- foo |
- bar |
- baz &&
- fish |
- cow ?!AMP?!
- sunder
-)
+2 (
+3 foo |
+4 bar |
+5 baz &&
+6
+7 fish |
+8 cow ?!LINT: missing '&&'?!
+9
+10 sunder
+11 )
diff --git a/t/chainlint/pipe.test b/t/chainlint/pipe.test
index dd82534c66..1af81c243b 100644
--- a/t/chainlint/pipe.test
+++ b/t/chainlint/pipe.test
@@ -1,3 +1,4 @@
+test_expect_success 'pipe' '
(
# LINT: no "&&" needed on line ending with "|"
foo |
@@ -10,3 +11,4 @@
sunder
)
+'
diff --git a/t/chainlint/return-loop.expect b/t/chainlint/return-loop.expect
index cfc0549bef..da8f9abea3 100644
--- a/t/chainlint/return-loop.expect
+++ b/t/chainlint/return-loop.expect
@@ -1,5 +1,5 @@
-while test $i -lt $((num - 5))
-do
- git notes add -m "notes for commit$i" HEAD~$i || return 1
- i=$((i + 1))
-done
+2 while test $i -lt $((num - 5))
+3 do
+4 git notes add -m "notes for commit$i" HEAD~$i || return 1
+5 i=$((i + 1))
+6 done
diff --git a/t/chainlint/return-loop.test b/t/chainlint/return-loop.test
index f90b171300..ea76c3593a 100644
--- a/t/chainlint/return-loop.test
+++ b/t/chainlint/return-loop.test
@@ -1,6 +1,8 @@
+test_expect_success 'return-loop' '
while test $i -lt $((num - 5))
do
# LINT: "|| return {n}" valid loop escape outside subshell; no "&&" needed
git notes add -m "notes for commit$i" HEAD~$i || return 1
i=$((i + 1))
done
+'
diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect
index 3aa2259f36..2b499fbe70 100644
--- a/t/chainlint/semicolon.expect
+++ b/t/chainlint/semicolon.expect
@@ -1,19 +1,19 @@
-(
- cat foo ; ?!AMP?! echo bar ?!AMP?!
- cat foo ; ?!AMP?! echo bar
-) &&
-(
- cat foo ; ?!AMP?! echo bar &&
- cat foo ; ?!AMP?! echo bar
-) &&
-(
- echo "foo; bar" &&
- cat foo; ?!AMP?! echo bar
-) &&
-(
- foo;
-) &&
-(cd foo &&
- for i in a b c; do
- echo; ?!LOOP?!
- done)
+2 (
+3 cat foo ; ?!LINT: missing '&&'?! echo bar ?!LINT: missing '&&'?!
+4 cat foo ; ?!LINT: missing '&&'?! echo bar
+5 ) &&
+6 (
+7 cat foo ; ?!LINT: missing '&&'?! echo bar &&
+8 cat foo ; ?!LINT: missing '&&'?! echo bar
+9 ) &&
+10 (
+11 echo "foo; bar" &&
+12 cat foo; ?!LINT: missing '&&'?! echo bar
+13 ) &&
+14 (
+15 foo;
+16 ) &&
+17 (cd foo &&
+18 for i in a b c; do
+19 echo; ?!LINT: missing '|| exit 1'?!
+20 done)
diff --git a/t/chainlint/semicolon.test b/t/chainlint/semicolon.test
index 67e1192c50..fc0ba1b539 100644
--- a/t/chainlint/semicolon.test
+++ b/t/chainlint/semicolon.test
@@ -1,3 +1,4 @@
+test_expect_success 'semicolon' '
(
# LINT: missing internal "&&" and ending "&&"
cat foo ; echo bar
@@ -23,3 +24,4 @@
# LINT: semicolon unnecessary but legitimate
echo;
done)
+'
diff --git a/t/chainlint/sqstring-in-sqstring.expect b/t/chainlint/sqstring-in-sqstring.expect
index cf0b591cf7..ba5d3c3a6d 100644
--- a/t/chainlint/sqstring-in-sqstring.expect
+++ b/t/chainlint/sqstring-in-sqstring.expect
@@ -1,4 +1,4 @@
-perl -e '
- defined($_ = -s $_) or die for @ARGV;
- exit 1 if $ARGV[0] <= $ARGV[1];
-' test-2-$packname_2.pack test-3-$packname_3.pack
+2 perl -e '
+3 defined($_ = -s $_) or die for @ARGV;
+4 exit 1 if $ARGV[0] <= $ARGV[1];
+5 ' test-2-$packname_2.pack test-3-$packname_3.pack
diff --git a/t/chainlint/sqstring-in-sqstring.test b/t/chainlint/sqstring-in-sqstring.test
index 77a425e0c7..24169724a5 100644
--- a/t/chainlint/sqstring-in-sqstring.test
+++ b/t/chainlint/sqstring-in-sqstring.test
@@ -1,5 +1,7 @@
+test_expect_success 'sqstring-in-sqstring' '
# LINT: SQ-string Perl code fragment within SQ-string
perl -e '\''
defined($_ = -s $_) or die for @ARGV;
exit 1 if $ARGV[0] <= $ARGV[1];
'\'' test-2-$packname_2.pack test-3-$packname_3.pack
+'
diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect
index 52789278d1..e450caf948 100644
--- a/t/chainlint/subshell-here-doc.expect
+++ b/t/chainlint/subshell-here-doc.expect
@@ -1,30 +1,30 @@
-(
- echo wobba \
- gorgo snoot \
- wafta snurb <<-EOF &&
- quoth the raven,
- nevermore...
- EOF
-
- cat <<EOF >bip ?!AMP?!
- fish fly high
-EOF
-
- echo <<-\EOF >bop
- gomez
- morticia
- wednesday
- pugsly
- EOF
-) &&
-(
- cat <<-\ARBITRARY >bup &&
- glink
- FIZZ
- ARBITRARY
- cat <<-"ARBITRARY3" >bup3 &&
- glink
- FIZZ
- ARBITRARY3
- meep
-)
+2 (
+3 echo wobba \
+4 gorgo snoot \
+5 wafta snurb <<-EOF &&
+6 quoth the raven,
+7 nevermore...
+8 EOF
+9
+10 cat <<EOF >bip ?!LINT: missing '&&'?!
+11 fish fly high
+12 EOF
+13
+14 echo <<-\EOF >bop
+15 gomez
+16 morticia
+17 wednesday
+18 pugsly
+19 EOF
+20 ) &&
+21 (
+22 cat <<-\ARBITRARY >bup &&
+23 glink
+24 FIZZ
+25 ARBITRARY
+26 cat <<-"ARBITRARY3" >bup3 &&
+27 glink
+28 FIZZ
+29 ARBITRARY3
+30 meep
+31 )
diff --git a/t/chainlint/subshell-here-doc.test b/t/chainlint/subshell-here-doc.test
index d40eb65583..4a38f47f01 100644
--- a/t/chainlint/subshell-here-doc.test
+++ b/t/chainlint/subshell-here-doc.test
@@ -1,3 +1,4 @@
+test_expect_success 'subshell-here-doc' '
(
# LINT: stitch together incomplete \-ending lines
# LINT: swallow here-doc to avoid false positives in content
@@ -33,3 +34,4 @@ EOF
ARBITRARY3
meep
)
+'
diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect
index b7015361bf..265d996a21 100644
--- a/t/chainlint/subshell-one-liner.expect
+++ b/t/chainlint/subshell-one-liner.expect
@@ -1,14 +1,19 @@
-(
- (foo && bar) &&
- (foo && bar) |
- (foo && bar) >baz &&
- (foo; ?!AMP?! bar) &&
- (foo; ?!AMP?! bar) |
- (foo; ?!AMP?! bar) >baz &&
- (foo || exit 1) &&
- (foo || exit 1) |
- (foo || exit 1) >baz &&
- (foo && bar) ?!AMP?!
- (foo && bar; ?!AMP?! baz) ?!AMP?!
- foobar
-)
+2 (
+3 (foo && bar) &&
+4 (foo && bar) |
+5 (foo && bar) >baz &&
+6
+7 (foo; ?!LINT: missing '&&'?! bar) &&
+8 (foo; ?!LINT: missing '&&'?! bar) |
+9 (foo; ?!LINT: missing '&&'?! bar) >baz &&
+10
+11 (foo || exit 1) &&
+12 (foo || exit 1) |
+13 (foo || exit 1) >baz &&
+14
+15 (foo && bar) ?!LINT: missing '&&'?!
+16
+17 (foo && bar; ?!LINT: missing '&&'?! baz) ?!LINT: missing '&&'?!
+18
+19 foobar
+20 )
diff --git a/t/chainlint/subshell-one-liner.test b/t/chainlint/subshell-one-liner.test
index 37fa643c20..dac536afcc 100644
--- a/t/chainlint/subshell-one-liner.test
+++ b/t/chainlint/subshell-one-liner.test
@@ -1,3 +1,4 @@
+test_expect_success 'subshell-one-liner' '
(
# LINT: nested one-liner subshell
(foo && bar) &&
@@ -22,3 +23,4 @@
foobar
)
+'
diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect
index 71b3b3bc20..9e60338bcf 100644
--- a/t/chainlint/t7900-subtree.expect
+++ b/t/chainlint/t7900-subtree.expect
@@ -1,21 +1,22 @@
-(
- chks="sub1
-sub2
-sub3
-sub4" &&
- chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
-$chks
-TXT
-) &&
- chkms="main-sub1
-main-sub2
-main-sub3
-main-sub4" &&
- chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
-$chkms
-TXT
-) &&
- subfiles=$(git ls-files) &&
- check_equal "$subfiles" "$chkms
-$chks"
-)
+2 (
+3 chks="sub1
+4 sub2
+5 sub3
+6 sub4" &&
+7 chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
+8 $chks
+9 TXT
+10 ) &&
+11 chkms="main-sub1
+12 main-sub2
+13 main-sub3
+14 main-sub4" &&
+15 chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
+16 $chkms
+17 TXT
+18 ) &&
+19
+20 subfiles=$(git ls-files) &&
+21 check_equal "$subfiles" "$chkms
+22 $chks"
+23 )
diff --git a/t/chainlint/t7900-subtree.test b/t/chainlint/t7900-subtree.test
index 02f3129232..1f4f03300f 100644
--- a/t/chainlint/t7900-subtree.test
+++ b/t/chainlint/t7900-subtree.test
@@ -1,3 +1,4 @@
+test_expect_success 't7900-subtree' '
(
chks="sub1
sub2
@@ -20,3 +21,4 @@ TXT
check_equal "$subfiles" "$chkms
$chks"
)
+'
diff --git a/t/chainlint/token-pasting.expect b/t/chainlint/token-pasting.expect
index 342360bcd0..387189b6de 100644
--- a/t/chainlint/token-pasting.expect
+++ b/t/chainlint/token-pasting.expect
@@ -1,27 +1,27 @@
-git config filter.rot13.smudge ./rot13.sh &&
-git config filter.rot13.clean ./rot13.sh &&
-
-{
- echo "*.t filter=rot13" ?!AMP?!
- echo "*.i ident"
-} > .gitattributes &&
-
-{
- echo a b c d e f g h i j k l m ?!AMP?!
- echo n o p q r s t u v w x y z ?!AMP?!
- echo '$Id$'
-} > test &&
-cat test > test.t &&
-cat test > test.o &&
-cat test > test.i &&
-git add test test.t test.i &&
-rm -f test test.t test.i &&
-git checkout -- test test.t test.i &&
-
-echo "content-test2" > test2.o &&
-echo "content-test3 - filename with special characters" > "test3 'sq',$x=.o" ?!AMP?!
-
-downstream_url_for_sed=$(
- printf "%sn" "$downstream_url" |
- sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g'
-)
+2 git config filter.rot13.smudge ./rot13.sh &&
+3 git config filter.rot13.clean ./rot13.sh &&
+4
+5 {
+6 echo "*.t filter=rot13" ?!LINT: missing '&&'?!
+7 echo "*.i ident"
+8 } >.gitattributes &&
+9
+10 {
+11 echo a b c d e f g h i j k l m ?!LINT: missing '&&'?!
+12 echo n o p q r s t u v w x y z ?!LINT: missing '&&'?!
+13 echo '$Id$'
+14 } >test &&
+15 cat test >test.t &&
+16 cat test >test.o &&
+17 cat test >test.i &&
+18 git add test test.t test.i &&
+19 rm -f test test.t test.i &&
+20 git checkout -- test test.t test.i &&
+21
+22 echo "content-test2" >test2.o &&
+23 echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!LINT: missing '&&'?!
+24
+25 downstream_url_for_sed=$(
+26 printf "%sn" "$downstream_url" |
+27 sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g'
+28 )
diff --git a/t/chainlint/token-pasting.test b/t/chainlint/token-pasting.test
index b4610ce815..590914b733 100644
--- a/t/chainlint/token-pasting.test
+++ b/t/chainlint/token-pasting.test
@@ -1,3 +1,4 @@
+test_expect_success 'token-pasting' '
# LINT: single token; composite of multiple strings
git config filter.rot13.smudge ./rot13.sh &&
git config filter.rot13.clean ./rot13.sh &&
@@ -30,3 +31,4 @@ downstream_url_for_sed=$(
# LINT: exit/enter string context; "&" inside string not command terminator
sed -e '\''s/\\/\\\\/g'\'' -e '\''s/[[/.*^$]/\\&/g'\''
)
+'
diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect
index 7c30a1a024..156906c85a 100644
--- a/t/chainlint/unclosed-here-doc-indent.expect
+++ b/t/chainlint/unclosed-here-doc-indent.expect
@@ -1,4 +1,4 @@
-command_which_is_run &&
-cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! &&
-we forget to end the here-doc
-command_which_is_gobbled
+2 command_which_is_run &&
+3 cat >expect <<-\EOF ?!LINT: unclosed heredoc?! &&
+4 we forget to end the here-doc
+5 command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test
index 5c841a9dfd..7ac9d0f7d7 100644
--- a/t/chainlint/unclosed-here-doc-indent.test
+++ b/t/chainlint/unclosed-here-doc-indent.test
@@ -1,4 +1,6 @@
+test_expect_success 'unclosed-here-doc-indent' '
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
index d65e50f78d..752c608862 100644
--- a/t/chainlint/unclosed-here-doc.expect
+++ b/t/chainlint/unclosed-here-doc.expect
@@ -1,7 +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
+2 command_which_is_run &&
+3 cat >expect <<\EOF ?!LINT: unclosed heredoc?! &&
+4 we try to end the here-doc below,
+5 but the indentation throws us off
+6 since the operator is not "<<-".
+7 EOF
+8 command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test
index 69d3786c34..68e78f06f3 100644
--- a/t/chainlint/unclosed-here-doc.test
+++ b/t/chainlint/unclosed-here-doc.test
@@ -1,3 +1,4 @@
+test_expect_success 'unclosed-here-doc' '
command_which_is_run &&
cat >expect <<\EOF &&
we try to end the here-doc below,
@@ -5,3 +6,4 @@ cat >expect <<\EOF &&
since the operator is not "<<-".
EOF
command_which_is_gobbled
+'
diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect
index 1f5eaea0fd..2ba5582165 100644
--- a/t/chainlint/while-loop.expect
+++ b/t/chainlint/while-loop.expect
@@ -1,13 +1,14 @@
-(
- while true
- do
- echo foo ?!AMP?!
- cat <<-\EOF ?!LOOP?!
- bar
- EOF
- done ?!AMP?!
- while true; do
- echo foo &&
- cat bar ?!LOOP?!
- done
-)
+2 (
+3 while true
+4 do
+5 echo foo ?!LINT: missing '&&'?!
+6 cat <<-\EOF ?!LINT: missing '|| exit 1'?!
+7 bar
+8 EOF
+9 done ?!LINT: missing '&&'?!
+10
+11 while true; do
+12 echo foo &&
+13 cat bar ?!LINT: missing '|| exit 1'?!
+14 done
+15 )
diff --git a/t/chainlint/while-loop.test b/t/chainlint/while-loop.test
index d09fb016e4..33a201906a 100644
--- a/t/chainlint/while-loop.test
+++ b/t/chainlint/while-loop.test
@@ -1,3 +1,4 @@
+test_expect_success 'while-loop' '
(
# LINT: "while", "do", "done" do not need "&&"
while true
@@ -17,3 +18,4 @@
cat bar
done
)
+'
diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl
index dd8107cd7d..6ee7700eb4 100755
--- a/t/check-non-portable-shell.pl
+++ b/t/check-non-portable-shell.pl
@@ -47,8 +47,10 @@ while (<>) {
/\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)';
/\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)';
/\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)';
- /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and
- err '"FOO=bar shell_func" assignment extends beyond "shell_func"';
+ /\blocal\s+[A-Za-z0-9_]*=\$([A-Za-z0-9_{]|[(][^(])/ and
+ err q(quote "$val" in 'local var=$val');
+ /\b([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and !/test_env.+=/ and exists($func{$4}) and
+ err '"FOO=bar shell_func" is not portable (use test_env FOO=bar shell_func)';
$line = '';
# this resets our $. for each file
close ARGV if eof;
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
index 8a3fd0009a..6967c8e25c 100644
--- a/t/helper/test-advise.c
+++ b/t/helper/test-advise.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "advice.h"
#include "config.h"
diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c
index af43ee1cb5..3f23f21072 100644
--- a/t/helper/test-bitmap.c
+++ b/t/helper/test-bitmap.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "git-compat-util.h"
#include "pack-bitmap.h"
@@ -13,21 +15,41 @@ static int bitmap_dump_hashes(void)
return test_bitmap_hashes(the_repository);
}
+static int bitmap_dump_pseudo_merges(void)
+{
+ return test_bitmap_pseudo_merges(the_repository);
+}
+
+static int bitmap_dump_pseudo_merge_commits(uint32_t n)
+{
+ return test_bitmap_pseudo_merge_commits(the_repository, n);
+}
+
+static int bitmap_dump_pseudo_merge_objects(uint32_t n)
+{
+ return test_bitmap_pseudo_merge_objects(the_repository, n);
+}
+
int cmd__bitmap(int argc, const char **argv)
{
setup_git_directory();
- if (argc != 2)
- goto usage;
-
- if (!strcmp(argv[1], "list-commits"))
+ if (argc == 2 && !strcmp(argv[1], "list-commits"))
return bitmap_list_commits();
- if (!strcmp(argv[1], "dump-hashes"))
+ if (argc == 2 && !strcmp(argv[1], "dump-hashes"))
return bitmap_dump_hashes();
+ if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges"))
+ return bitmap_dump_pseudo_merges();
+ if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-commits"))
+ return bitmap_dump_pseudo_merge_commits(atoi(argv[2]));
+ if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-objects"))
+ return bitmap_dump_pseudo_merge_objects(atoi(argv[2]));
-usage:
usage("\ttest-tool bitmap list-commits\n"
- "\ttest-tool bitmap dump-hashes");
+ "\ttest-tool bitmap dump-hashes\n"
+ "\ttest-tool bitmap dump-pseudo-merges\n"
+ "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n"
+ "\ttest-tool bitmap dump-pseudo-merge-objects <n>");
return -1;
}
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index aabe31d724..97541daf71 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "bloom.h"
#include "hex.h"
@@ -40,7 +42,6 @@ static void get_bloom_filter_for_commit(const struct object_id *commit_oid)
{
struct commit *c;
struct bloom_filter *filter;
- setup_git_directory();
c = lookup_commit(the_repository, commit_oid);
filter = get_or_compute_bloom_filter(the_repository, c, 1,
&settings,
@@ -50,6 +51,7 @@ static void get_bloom_filter_for_commit(const struct object_id *commit_oid)
static const char *bloom_usage = "\n"
" test-tool bloom get_murmur3 <string>\n"
+" test-tool bloom get_murmur3_seven_highbit\n"
" test-tool bloom generate_filter <string> [<string>...]\n"
" test-tool bloom get_filter_for_commit <commit-hex>\n";
@@ -64,7 +66,13 @@ int cmd__bloom(int argc, const char **argv)
uint32_t hashed;
if (argc < 3)
usage(bloom_usage);
- hashed = murmur3_seeded(0, argv[2], strlen(argv[2]));
+ hashed = murmur3_seeded_v2(0, argv[2], strlen(argv[2]));
+ printf("Murmur3 Hash with seed=0:0x%08x\n", hashed);
+ }
+
+ if (!strcmp(argv[1], "get_murmur3_seven_highbit")) {
+ uint32_t hashed;
+ hashed = murmur3_seeded_v2(0, "\x99\xaa\xbb\xcc\xdd\xee\xff", 7);
printf("Murmur3 Hash with seed=0:0x%08x\n", hashed);
}
diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c
index 475058592d..0c5fa723d8 100644
--- a/t/helper/test-bundle-uri.c
+++ b/t/helper/test-bundle-uri.c
@@ -5,9 +5,7 @@
#include "strbuf.h"
#include "string-list.h"
#include "transport.h"
-#include "ref-filter.h"
#include "remote.h"
-#include "refs.h"
enum input_mode {
KEY_VALUE_PAIRS,
@@ -90,8 +88,6 @@ static int cmd_ls_remote(int argc, const char **argv)
die(_("bad repository '%s'"), dest);
die(_("no remote configured to get bundle URIs from"));
}
- if (!remote->url_nr)
- die(_("remote '%s' has no configured URL"), dest);
transport = transport_get(remote, NULL);
if (transport_get_remote_bundle_uri(transport) < 0) {
diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c
index e7236392c8..5cdef3ebef 100644
--- a/t/helper/test-cache-tree.c
+++ b/t/helper/test-cache-tree.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "gettext.h"
#include "hex.h"
@@ -38,29 +39,29 @@ int cmd__cache_tree(int argc, const char **argv)
if (repo_read_index(the_repository) < 0)
die(_("unable to read index file"));
- oidcpy(&oid, &the_index.cache_tree->oid);
+ oidcpy(&oid, &the_repository->index->cache_tree->oid);
tree = parse_tree_indirect(&oid);
if (!tree)
die(_("not a tree object: %s"), oid_to_hex(&oid));
if (empty) {
/* clear the cache tree & allocate a new one */
- cache_tree_free(&the_index.cache_tree);
- the_index.cache_tree = cache_tree();
+ cache_tree_free(&the_repository->index->cache_tree);
+ the_repository->index->cache_tree = cache_tree();
} else if (invalidate_qty) {
/* invalidate the specified number of unique paths */
- float f_interval = (float)the_index.cache_nr / invalidate_qty;
+ float f_interval = (float)the_repository->index->cache_nr / invalidate_qty;
int interval = f_interval < 1.0 ? 1 : (int)f_interval;
- for (i = 0; i < invalidate_qty && i * interval < the_index.cache_nr; i++)
- cache_tree_invalidate_path(&the_index, the_index.cache[i * interval]->name);
+ for (i = 0; i < invalidate_qty && i * interval < the_repository->index->cache_nr; i++)
+ cache_tree_invalidate_path(the_repository->index, the_repository->index->cache[i * interval]->name);
}
if (argc != 1)
usage_with_options(test_cache_tree_usage, options);
else if (!strcmp(argv[0], "prime"))
- prime_cache_tree(the_repository, &the_index, tree);
+ prime_cache_tree(the_repository, the_repository->index, tree);
else if (!strcmp(argv[0], "update"))
- cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+ cache_tree_update(the_repository->index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
/* use "control" subcommand to specify no-op */
else if (!!strcmp(argv[0], "control"))
die(_("Unhandled subcommand '%s'"), argv[0]);
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index ed444ca4c2..33247f0e92 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "config.h"
#include "setup.h"
@@ -94,7 +96,8 @@ int cmd__config(int argc, const char **argv)
struct config_set cs;
if (argc == 3 && !strcmp(argv[1], "read_early_config")) {
- read_early_config(early_config_cb, (void *)argv[2]);
+ read_early_config(the_repository, early_config_cb,
+ (void *)argv[2]);
return 0;
}
diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c
deleted file mode 100644
index e5659df40b..0000000000
--- a/t/helper/test-ctype.c
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "test-tool.h"
-
-static int rc;
-
-static void report_error(const char *class, int ch)
-{
- printf("%s classifies char %d (0x%02x) wrongly\n", class, ch, ch);
- rc = 1;
-}
-
-static int is_in(const char *s, int ch)
-{
- /*
- * We can't find NUL using strchr. Accept it as the first
- * character in the spec -- there are no empty classes.
- */
- if (ch == '\0')
- return ch == *s;
- if (*s == '\0')
- s++;
- return !!strchr(s, ch);
-}
-
-#define TEST_CLASS(t,s) { \
- int i; \
- for (i = 0; i < 256; i++) { \
- if (is_in(s, i) != t(i)) \
- report_error(#t, i); \
- } \
- if (t(EOF)) \
- report_error(#t, EOF); \
-}
-
-#define DIGIT "0123456789"
-#define LOWER "abcdefghijklmnopqrstuvwxyz"
-#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
-#define ASCII \
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
- "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
- "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \
- "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \
- "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \
- "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \
- "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \
- "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
-#define CNTRL \
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
- "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
- "\x7f"
-
-int cmd__ctype(int argc UNUSED, const char **argv UNUSED)
-{
- TEST_CLASS(isdigit, DIGIT);
- TEST_CLASS(isspace, " \n\r\t");
- TEST_CLASS(isalpha, LOWER UPPER);
- TEST_CLASS(isalnum, LOWER UPPER DIGIT);
- TEST_CLASS(is_glob_special, "*?[\\");
- TEST_CLASS(is_regex_special, "$()*+.?[\\^{|");
- TEST_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~");
- TEST_CLASS(isascii, ASCII);
- TEST_CLASS(islower, LOWER);
- TEST_CLASS(isupper, UPPER);
- TEST_CLASS(iscntrl, CNTRL);
- TEST_CLASS(ispunct, PUNCT);
- TEST_CLASS(isxdigit, DIGIT "abcdefABCDEF");
- TEST_CLASS(isprint, LOWER UPPER DIGIT PUNCT " ");
-
- return rc;
-}
diff --git a/t/helper/test-date.c b/t/helper/test-date.c
index 0683d46574..f25512de9a 100644
--- a/t/helper/test-date.c
+++ b/t/helper/test-date.c
@@ -52,7 +52,7 @@ static void show_dates(const char **argv, const char *format)
arg++;
tz = atoi(arg);
- printf("%s -> %s\n", *argv, show_date(t, tz, &mode));
+ printf("%s -> %s\n", *argv, show_date(t, tz, mode));
}
date_mode_release(&mode);
diff --git a/t/helper/test-delete-gpgsig.c b/t/helper/test-delete-gpgsig.c
new file mode 100644
index 0000000000..e36831af03
--- /dev/null
+++ b/t/helper/test-delete-gpgsig.c
@@ -0,0 +1,62 @@
+#include "test-tool.h"
+#include "gpg-interface.h"
+#include "strbuf.h"
+
+
+int cmd__delete_gpgsig(int argc, const char **argv)
+{
+ struct strbuf buf = STRBUF_INIT;
+ const char *pattern = "gpgsig";
+ const char *bufptr, *tail, *eol;
+ int deleting = 0;
+ size_t plen;
+
+ if (argc >= 2) {
+ pattern = argv[1];
+ argv++;
+ argc--;
+ }
+
+ plen = strlen(pattern);
+ strbuf_read(&buf, 0, 0);
+
+ if (!strcmp(pattern, "trailer")) {
+ size_t payload_size = parse_signed_buffer(buf.buf, buf.len);
+ fwrite(buf.buf, 1, payload_size, stdout);
+ fflush(stdout);
+ return 0;
+ }
+
+ bufptr = buf.buf;
+ tail = bufptr + buf.len;
+
+ while (bufptr < tail) {
+ /* Find the end of the line */
+ eol = memchr(bufptr, '\n', tail - bufptr);
+ if (!eol)
+ eol = tail;
+
+ /* Drop continuation lines */
+ if (deleting && (bufptr < eol) && (bufptr[0] == ' ')) {
+ bufptr = eol + 1;
+ continue;
+ }
+ deleting = 0;
+
+ /* Does the line match the prefix? */
+ if (((bufptr + plen) < eol) &&
+ !memcmp(bufptr, pattern, plen) &&
+ (bufptr[plen] == ' ')) {
+ deleting = 1;
+ bufptr = eol + 1;
+ continue;
+ }
+
+ /* Print all other lines */
+ fwrite(bufptr, 1, (eol - bufptr) + 1, stdout);
+ bufptr = eol + 1;
+ }
+ fflush(stdout);
+
+ return 0;
+}
diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
index c38f546e4f..3f0c7d0ed0 100644
--- a/t/helper/test-dump-cache-tree.c
+++ b/t/helper/test-dump-cache-tree.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "hash.h"
#include "hex.h"
@@ -68,10 +69,10 @@ int cmd__dump_cache_tree(int ac UNUSED, const char **av UNUSED)
setup_git_directory();
if (repo_read_index(the_repository) < 0)
die("unable to read index file");
- istate = the_index;
+ istate = *the_repository->index;
istate.cache_tree = another;
cache_tree_update(&istate, WRITE_TREE_DRY_RUN);
- ret = dump_cache_tree(the_index.cache_tree, another, "");
+ ret = dump_cache_tree(the_repository->index->cache_tree, another, "");
cache_tree_free(&another);
return ret;
diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c
index 4f215fea02..1b7f37a84f 100644
--- a/t/helper/test-dump-fsmonitor.c
+++ b/t/helper/test-dump-fsmonitor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "read-cache-ll.h"
#include "repository.h"
diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c
index f29d18ef94..a6720faf9c 100644
--- a/t/helper/test-dump-split-index.c
+++ b/t/helper/test-dump-split-index.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "hex.h"
#include "read-cache-ll.h"
@@ -19,16 +20,16 @@ int cmd__dump_split_index(int ac UNUSED, const char **av)
setup_git_directory();
- do_read_index(&the_index, av[1], 1);
- printf("own %s\n", oid_to_hex(&the_index.oid));
- si = the_index.split_index;
+ do_read_index(the_repository->index, av[1], 1);
+ printf("own %s\n", oid_to_hex(&the_repository->index->oid));
+ si = the_repository->index->split_index;
if (!si) {
printf("not a split index\n");
return 0;
}
printf("base %s\n", oid_to_hex(&si->base_oid));
- for (i = 0; i < the_index.cache_nr; i++) {
- struct cache_entry *ce = the_index.cache[i];
+ for (i = 0; i < the_repository->index->cache_nr; i++) {
+ struct cache_entry *ce = the_repository->index->cache[i];
printf("%06o %s %d\t%s\n", ce->ce_mode,
oid_to_hex(&ce->oid), ce_stage(ce), ce->name);
}
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index b4af9712fe..b2e70837a9 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "dir.h"
#include "hex.h"
@@ -56,7 +57,7 @@ int cmd__dump_untracked_cache(int ac UNUSED, const char **av UNUSED)
setup_git_directory();
if (repo_read_index(the_repository) < 0)
die("unable to read index file");
- uc = the_index.untracked;
+ uc = the_repository->index->untracked;
if (!uc) {
printf("no untracked cache\n");
return 0;
@@ -67,5 +68,7 @@ int cmd__dump_untracked_cache(int ac UNUSED, const char **av UNUSED)
printf("flags %08x\n", uc->dir_flags);
if (uc->root)
dump(uc->root, &base);
+
+ strbuf_release(&base);
return 0;
}
diff --git a/t/helper/test-env-helper.c b/t/helper/test-env-helper.c
index 66c88b8ff3..1c486888a4 100644
--- a/t/helper/test-env-helper.c
+++ b/t/helper/test-env-helper.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "config.h"
+#include "parse.h"
#include "parse-options.h"
static char const * const env__helper_usage[] = {
diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c
deleted file mode 100644
index 8f59f6be4c..0000000000
--- a/t/helper/test-example-decorate.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "test-tool.h"
-#include "git-compat-util.h"
-#include "object.h"
-#include "decorate.h"
-#include "repository.h"
-
-int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
-{
- struct decoration n;
- struct object_id one_oid = { {1} };
- struct object_id two_oid = { {2} };
- struct object_id three_oid = { {3} };
- struct object *one, *two, *three;
-
- int decoration_a, decoration_b;
-
- void *ret;
-
- int i, objects_noticed = 0;
-
- /*
- * The struct must be zero-initialized.
- */
- memset(&n, 0, sizeof(n));
-
- /*
- * Add 2 objects, one with a non-NULL decoration and one with a NULL
- * decoration.
- */
- one = lookup_unknown_object(the_repository, &one_oid);
- two = lookup_unknown_object(the_repository, &two_oid);
- ret = add_decoration(&n, one, &decoration_a);
- if (ret)
- BUG("when adding a brand-new object, NULL should be returned");
- ret = add_decoration(&n, two, NULL);
- if (ret)
- BUG("when adding a brand-new object, NULL should be returned");
-
- /*
- * When re-adding an already existing object, the old decoration is
- * returned.
- */
- ret = add_decoration(&n, one, NULL);
- if (ret != &decoration_a)
- BUG("when readding an already existing object, existing decoration should be returned");
- ret = add_decoration(&n, two, &decoration_b);
- if (ret)
- BUG("when readding an already existing object, existing decoration should be returned");
-
- /*
- * Lookup returns the added declarations, or NULL if the object was
- * never added.
- */
- ret = lookup_decoration(&n, one);
- if (ret)
- BUG("lookup should return added declaration");
- ret = lookup_decoration(&n, two);
- if (ret != &decoration_b)
- BUG("lookup should return added declaration");
- three = lookup_unknown_object(the_repository, &three_oid);
- ret = lookup_decoration(&n, three);
- if (ret)
- BUG("lookup for unknown object should return NULL");
-
- /*
- * The user can also loop through all entries.
- */
- for (i = 0; i < n.size; i++) {
- if (n.entries[i].base)
- objects_noticed++;
- }
- if (objects_noticed != 2)
- BUG("should have 2 objects");
-
- clear_decoration(&n, NULL);
-
- return 0;
-}
diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c
new file mode 100644
index 0000000000..229d495ecf
--- /dev/null
+++ b/t/helper/test-example-tap.c
@@ -0,0 +1,131 @@
+#include "test-tool.h"
+#include "t/unit-tests/test-lib.h"
+
+/*
+ * The purpose of this "unit test" is to verify a few invariants of the unit
+ * test framework itself, as well as to provide examples of output from actually
+ * failing tests. As such, it is intended that this test fails, and thus it
+ * should not be run as part of `make unit-tests`. Instead, we verify it behaves
+ * as expected in the integration test t0080-unit-test-output.sh
+ */
+
+/* Used to store the return value of check_int(). */
+static int check_res;
+
+/* Used to store the return value of TEST(). */
+static int test_res;
+
+static void t_res(int expect)
+{
+ check_int(check_res, ==, expect);
+ check_int(test_res, ==, expect);
+}
+
+static void t_todo(int x)
+{
+ check_res = TEST_TODO(check(x));
+}
+
+static void t_skip(void)
+{
+ check(0);
+ test_skip("missing prerequisite");
+ check(1);
+}
+
+static int do_skip(void)
+{
+ test_skip("missing prerequisite");
+ return 1;
+}
+
+static void t_skip_todo(void)
+{
+ check_res = TEST_TODO(do_skip());
+}
+
+static void t_todo_after_fail(void)
+{
+ check(0);
+ TEST_TODO(check(0));
+}
+
+static void t_fail_after_todo(void)
+{
+ check(1);
+ TEST_TODO(check(0));
+ check(0);
+}
+
+static void t_messages(void)
+{
+ check_str("\thello\\", "there\"\n");
+ check_str("NULL", NULL);
+ check_char('a', ==, '\n');
+ check_char('\\', ==, '\'');
+}
+
+static void t_empty(void)
+{
+ ; /* empty */
+}
+
+int cmd__example_tap(int argc UNUSED, const char **argv UNUSED)
+{
+ check(1);
+
+ test_res = TEST(check_res = check_int(1, ==, 1), "passing test");
+ TEST(t_res(1), "passing test and assertion return 1");
+ test_res = TEST(check_res = check_int(1, ==, 2), "failing test");
+ TEST(t_res(0), "failing test and assertion return 0");
+ test_res = TEST(t_todo(0), "passing TEST_TODO()");
+ TEST(t_res(1), "passing TEST_TODO() returns 1");
+ test_res = TEST(t_todo(1), "failing TEST_TODO()");
+ TEST(t_res(0), "failing TEST_TODO() returns 0");
+ test_res = TEST(t_skip(), "test_skip()");
+ TEST(check_int(test_res, ==, 1), "skipped test returns 1");
+ test_res = TEST(t_skip_todo(), "test_skip() inside TEST_TODO()");
+ TEST(t_res(1), "test_skip() inside TEST_TODO() returns 1");
+ test_res = TEST(t_todo_after_fail(), "TEST_TODO() after failing check");
+ TEST(check_int(test_res, ==, 0), "TEST_TODO() after failing check returns 0");
+ test_res = TEST(t_fail_after_todo(), "failing check after TEST_TODO()");
+ TEST(check_int(test_res, ==, 0), "failing check after TEST_TODO() returns 0");
+ TEST(t_messages(), "messages from failing string and char comparison");
+ test_res = TEST(t_empty(), "test with no checks");
+ TEST(check_int(test_res, ==, 0), "test with no checks returns 0");
+
+ if_test ("if_test passing test")
+ check_int(1, ==, 1);
+ if_test ("if_test failing test")
+ check_int(1, ==, 2);
+ if_test ("if_test passing TEST_TODO()")
+ TEST_TODO(check(0));
+ if_test ("if_test failing TEST_TODO()")
+ TEST_TODO(check(1));
+ if_test ("if_test test_skip()") {
+ check(0);
+ test_skip("missing prerequisite");
+ check(1);
+ }
+ if_test ("if_test test_skip() inside TEST_TODO()")
+ TEST_TODO((test_skip("missing prerequisite"), 1));
+ if_test ("if_test TEST_TODO() after failing check") {
+ check(0);
+ TEST_TODO(check(0));
+ }
+ if_test ("if_test failing check after TEST_TODO()") {
+ check(1);
+ TEST_TODO(check(0));
+ check(0);
+ }
+ if_test ("if_test messages from failing string and char comparison") {
+ check_str("\thello\\", "there\"\n");
+ check_str("NULL", NULL);
+ check_char('a', ==, '\n');
+ check_char('\\', ==, '\'');
+ }
+ if_test ("if_test test with no checks")
+ ; /* nothing */
+
+ return test_done();
+}
diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c
deleted file mode 100644
index cac20a72b3..0000000000
--- a/t/helper/test-fast-rebase.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * "git fast-rebase" builtin command
- *
- * FAST: Forking Any Subprocesses (is) Taboo
- *
- * This is meant SOLELY as a demo of what is possible. sequencer.c and
- * rebase.c should be refactored to use the ideas here, rather than attempting
- * to extend this file to replace those (unless Phillip or Dscho say that
- * refactoring is too hard and we need a clean slate, but I'm guessing that
- * refactoring is the better route).
- */
-
-#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 repo_find_unique_abbrev(the_repository, &commit->object.oid,
- DEFAULT_ABBREV);
-}
-
-static struct commit *peel_committish(const char *name)
-{
- struct object *obj;
- struct object_id oid;
-
- if (repo_get_oid(the_repository, name, &oid))
- return NULL;
- obj = parse_object(the_repository, &oid);
- return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
- OBJ_COMMIT);
-}
-
-static char *get_author(const char *message)
-{
- size_t len;
- const char *a;
-
- a = find_commit_header(message, "author", &len);
- if (a)
- return xmemdupz(a, len);
-
- return NULL;
-}
-
-static struct commit *create_commit(struct tree *tree,
- struct commit *based_on,
- struct commit *parent)
-{
- struct object_id ret;
- struct object *obj;
- struct commit_list *parents = NULL;
- char *author;
- char *sign_commit = NULL;
- struct commit_extra_header *extra;
- struct strbuf msg = STRBUF_INIT;
- const char *out_enc = get_commit_output_encoding();
- const char *message = repo_logmsg_reencode(the_repository, based_on,
- NULL, out_enc);
- const char *orig_message = NULL;
- const char *exclude_gpgsig[] = { "gpgsig", NULL };
-
- commit_list_insert(parent, &parents);
- extra = read_commit_extra_headers(based_on, exclude_gpgsig);
- find_commit_subject(message, &orig_message);
- strbuf_addstr(&msg, orig_message);
- author = get_author(message);
- reset_ident_date();
- if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents,
- &ret, author, NULL, sign_commit, extra)) {
- error(_("failed to write commit object"));
- return NULL;
- }
- free(author);
- strbuf_release(&msg);
-
- obj = parse_object(the_repository, &ret);
- return (struct commit *)obj;
-}
-
-int cmd__fast_rebase(int argc, const char **argv)
-{
- struct commit *onto;
- struct commit *last_commit = NULL, *last_picked_commit = NULL;
- struct object_id head;
- struct lock_file lock = LOCK_INIT;
- struct strvec rev_walk_args = STRVEC_INIT;
- struct rev_info revs;
- struct commit *commit;
- struct merge_options merge_opt;
- struct tree *next_tree, *base_tree, *head_tree;
- struct merge_result result;
- struct strbuf reflog_msg = STRBUF_INIT;
- struct strbuf branch_name = STRBUF_INIT;
- int ret = 0;
-
- /*
- * test-tool stuff doesn't set up the git directory by default; need to
- * do that manually.
- */
- setup_git_directory();
-
- if (argc == 2 && !strcmp(argv[1], "-h")) {
- printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
- exit(129);
- }
-
- if (argc != 5 || strcmp(argv[1], "--onto"))
- die("usage: read the code, figure out how to use it, then do so");
-
- onto = peel_committish(argv[2]);
- strbuf_addf(&branch_name, "refs/heads/%s", argv[4]);
-
- /* Sanity check */
- if (repo_get_oid(the_repository, "HEAD", &head))
- die(_("Cannot read HEAD"));
- assert(oideq(&onto->object.oid, &head));
-
- repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
- if (repo_read_index(the_repository) < 0)
- BUG("Could not read index");
-
- repo_init_revisions(the_repository, &revs, NULL);
- revs.verbose_header = 1;
- revs.max_parents = 1;
- revs.cherry_mark = 1;
- revs.limited = 1;
- revs.reverse = 1;
- revs.right_only = 1;
- revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
- revs.topo_order = 1;
- strvec_pushl(&rev_walk_args, "", argv[4], "--not", argv[3], NULL);
-
- if (setup_revisions(rev_walk_args.nr, rev_walk_args.v, &revs, NULL) > 1) {
- ret = error(_("unhandled options"));
- goto cleanup;
- }
-
- strvec_clear(&rev_walk_args);
-
- if (prepare_revision_walk(&revs) < 0) {
- ret = error(_("error preparing revisions"));
- goto cleanup;
- }
-
- init_merge_options(&merge_opt, the_repository);
- memset(&result, 0, sizeof(result));
- merge_opt.show_rename_progress = 1;
- merge_opt.branch1 = "HEAD";
- head_tree = repo_get_commit_tree(the_repository, onto);
- result.tree = head_tree;
- last_commit = onto;
- while ((commit = get_revision(&revs))) {
- struct commit *base;
-
- fprintf(stderr, "Rebasing %s...\r",
- oid_to_hex(&commit->object.oid));
- assert(commit->parents && !commit->parents->next);
- base = commit->parents->item;
-
- 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);
-
- merge_incore_nonrecursive(&merge_opt,
- base_tree,
- result.tree,
- next_tree,
- &result);
-
- free((char*)merge_opt.ancestor);
- merge_opt.ancestor = NULL;
- if (!result.clean)
- break;
- last_picked_commit = commit;
- last_commit = create_commit(result.tree, commit, last_commit);
- }
-
- merge_switch_to_result(&merge_opt, head_tree, &result, 1, !result.clean);
-
- if (result.clean < 0)
- exit(128);
-
- if (result.clean) {
- fprintf(stderr, "\nDone.\n");
- strbuf_addf(&reflog_msg, "finish rebase %s onto %s",
- oid_to_hex(&last_picked_commit->object.oid),
- oid_to_hex(&last_commit->object.oid));
- if (update_ref(reflog_msg.buf, branch_name.buf,
- &last_commit->object.oid,
- &last_picked_commit->object.oid,
- REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
- error(_("could not update %s"), argv[4]);
- die("Failed to update %s", argv[4]);
- }
- if (create_symref("HEAD", branch_name.buf, reflog_msg.buf) < 0)
- die(_("unable to update HEAD"));
-
- prime_cache_tree(the_repository, the_repository->index,
- result.tree);
- } else {
- fprintf(stderr, "\nAborting: Hit a conflict.\n");
- strbuf_addf(&reflog_msg, "rebase progress up to %s",
- oid_to_hex(&last_picked_commit->object.oid));
- if (update_ref(reflog_msg.buf, "HEAD",
- &last_commit->object.oid,
- &head,
- REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
- error(_("could not update %s"), argv[4]);
- die("Failed to update %s", argv[4]);
- }
- }
- if (write_locked_index(&the_index, &lock,
- COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die(_("unable to write %s"), get_index_file());
-
- ret = (result.clean == 0);
-cleanup:
- strbuf_release(&reflog_msg);
- strbuf_release(&branch_name);
- release_revisions(&revs);
- return ret;
-}
diff --git a/t/helper/test-find-pack.c b/t/helper/test-find-pack.c
new file mode 100644
index 0000000000..85a69a4e55
--- /dev/null
+++ b/t/helper/test-find-pack.c
@@ -0,0 +1,52 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "test-tool.h"
+#include "object-name.h"
+#include "object-store.h"
+#include "packfile.h"
+#include "parse-options.h"
+#include "setup.h"
+
+/*
+ * Display the path(s), one per line, of the packfile(s) containing
+ * the given object.
+ *
+ * If '--check-count <n>' is passed, then error out if the number of
+ * packfiles containing the object is not <n>.
+ */
+
+static const char *find_pack_usage[] = {
+ "test-tool find-pack [--check-count <n>] <object>",
+ NULL
+};
+
+int cmd__find_pack(int argc, const char **argv)
+{
+ struct object_id oid;
+ struct packed_git *p;
+ int count = -1, actual_count = 0;
+ const char *prefix = setup_git_directory();
+
+ struct option options[] = {
+ OPT_INTEGER('c', "check-count", &count, "expected number of packs"),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, options, find_pack_usage, 0);
+ if (argc != 1)
+ usage(find_pack_usage[0]);
+
+ if (repo_get_oid(the_repository, argv[0], &oid))
+ die("cannot parse %s as an object name", argv[0]);
+
+ for (p = get_all_packs(the_repository); p; p = p->next)
+ if (find_pack_entry_one(&oid, p)) {
+ printf("%s\n", p->pack_name);
+ actual_count++;
+ }
+
+ if (count > -1 && count != actual_count)
+ die("bad packfile count %d instead of %d", actual_count, count);
+
+ return 0;
+}
diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c
index 8280984d08..02bfe92e8d 100644
--- a/t/helper/test-fsmonitor-client.c
+++ b/t/helper/test-fsmonitor-client.c
@@ -3,6 +3,8 @@
* a `git fsmonitor--daemon` daemon.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "parse-options.h"
#include "fsmonitor-ipc.h"
diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c
index b235da594f..7de822af51 100644
--- a/t/helper/test-hash-speed.c
+++ b/t/helper/test-hash-speed.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "hash-ll.h"
+#include "hash.h"
#define NUM_SECONDS 3
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 0eb0b3d49c..7782ae585e 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -12,11 +12,6 @@ struct test_entry
char key[FLEX_ARRAY];
};
-static const char *get_value(const struct test_entry *e)
-{
- return e->key + strlen(e->key) + 1;
-}
-
static int test_entry_cmp(const void *cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
@@ -36,7 +31,8 @@ static int test_entry_cmp(const void *cmp_data,
}
static struct test_entry *alloc_test_entry(unsigned int hash,
- char *key, char *value)
+ const char *key,
+ const char *value)
{
size_t klen = strlen(key);
size_t vlen = strlen(value);
@@ -140,30 +136,16 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
/*
* Read stdin line by line and print result of commands to stdout:
*
- * hash key -> strhash(key) memhash(key) strihash(key) memihash(key)
- * put key value -> NULL / old value
- * get key -> NULL / value
- * remove key -> NULL / old value
- * iterate -> key1 value1\nkey2 value2\n...
- * size -> tablesize numentries
- *
* perfhashmap method rounds -> test hashmap.[ch] performance
*/
-int cmd__hashmap(int argc, const char **argv)
+int cmd__hashmap(int argc UNUSED, const char **argv UNUSED)
{
struct string_list parts = STRING_LIST_INIT_NODUP;
struct strbuf line = STRBUF_INIT;
- int icase;
- struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
-
- /* init hash map */
- icase = argc > 1 && !strcmp("ignorecase", argv[1]);
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
char *cmd, *p1, *p2;
- unsigned int hash = 0;
- struct test_entry *entry;
/* break line into command and up to two parameters */
string_list_setlen(&parts, 0);
@@ -179,84 +161,8 @@ int cmd__hashmap(int argc, const char **argv)
cmd = parts.items[0].string;
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
- if (p1)
- hash = icase ? strihash(p1) : strhash(p1);
-
- if (!strcmp("add", cmd) && p1 && p2) {
-
- /* create entry with key = p1, value = p2 */
- entry = alloc_test_entry(hash, p1, p2);
-
- /* add to hashmap */
- hashmap_add(&map, &entry->ent);
-
- } else if (!strcmp("put", cmd) && p1 && p2) {
-
- /* create entry with key = p1, value = p2 */
- entry = alloc_test_entry(hash, p1, p2);
-
- /* add / replace entry */
- entry = hashmap_put_entry(&map, entry, ent);
-
- /* print and free replaced entry, if any */
- puts(entry ? get_value(entry) : "NULL");
- free(entry);
-
- } else if (!strcmp("get", cmd) && p1) {
- /* lookup entry in hashmap */
- entry = hashmap_get_entry_from_hash(&map, hash, p1,
- struct test_entry, ent);
-
- /* print result */
- if (!entry)
- puts("NULL");
- hashmap_for_each_entry_from(&map, entry, ent)
- puts(get_value(entry));
-
- } else if (!strcmp("remove", cmd) && p1) {
-
- /* setup static key */
- struct hashmap_entry key;
- struct hashmap_entry *rm;
- hashmap_entry_init(&key, hash);
-
- /* remove entry from hashmap */
- rm = hashmap_remove(&map, &key, p1);
- entry = rm ? container_of(rm, struct test_entry, ent)
- : NULL;
-
- /* print result and free entry*/
- puts(entry ? get_value(entry) : "NULL");
- free(entry);
-
- } else if (!strcmp("iterate", cmd)) {
- struct hashmap_iter iter;
-
- hashmap_for_each_entry(&map, &iter, entry,
- ent /* member name */)
- printf("%s %s\n", entry->key, get_value(entry));
-
- } else if (!strcmp("size", cmd)) {
-
- /* print table sizes */
- printf("%u %u\n", map.tablesize,
- hashmap_get_size(&map));
-
- } else if (!strcmp("intern", cmd) && p1) {
-
- /* test that strintern works */
- const char *i1 = strintern(p1);
- const char *i2 = strintern(p1);
- if (strcmp(i1, p1))
- printf("strintern(%s) returns %s\n", p1, i1);
- else if (i1 == p1)
- printf("strintern(%s) returns input pointer\n", p1);
- else if (i1 != i2)
- printf("strintern(%s) != strintern(%s)", i1, i2);
- else
- printf("%s\n", i1);
- } else if (!strcmp("perfhashmap", cmd) && p1 && p2) {
+ if (!strcmp("perfhashmap", cmd) && p1 && p2) {
perf_hashmap(atoi(p1), atoi(p2));
@@ -269,6 +175,5 @@ int cmd__hashmap(int argc, const char **argv)
string_list_clear(&parts, 0);
strbuf_release(&line);
- hashmap_clear_and_free(&map, struct test_entry, ent);
return 0;
}
diff --git a/t/helper/test-index-version.c b/t/helper/test-index-version.c
deleted file mode 100644
index f3c2dbe0a2..0000000000
--- a/t/helper/test-index-version.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "test-tool.h"
-#include "read-cache-ll.h"
-
-int cmd__index_version(int argc UNUSED, const char **argv UNUSED)
-{
- struct cache_header hdr;
- int version;
-
- memset(&hdr,0,sizeof(hdr));
- if (read(0, &hdr, sizeof(hdr)) != sizeof(hdr))
- return 0;
- version = ntohl(hdr.hdr_version);
- printf("%d\n", version);
- return 0;
-}
diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c
index afe393f597..a288069b04 100644
--- a/t/helper/test-json-writer.c
+++ b/t/helper/test-json-writer.c
@@ -174,7 +174,7 @@ static void make_arr4(int pretty)
jw_end(&arr4);
}
-static char *expect_nest1 =
+static const char *expect_nest1 =
"{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}";
static struct json_writer nest1 = JSON_WRITER_INIT;
@@ -195,10 +195,10 @@ static void make_nest1(int pretty)
jw_release(&arr1);
}
-static char *expect_inline1 =
+static const char *expect_inline1 =
"{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}";
-static char *pretty_inline1 =
+static const char *pretty_inline1 =
("{\n"
" \"obj1\": {\n"
" \"a\": \"abc\",\n"
@@ -236,10 +236,10 @@ static void make_inline1(int pretty)
jw_end(&inline1);
}
-static char *expect_inline2 =
+static const char *expect_inline2 =
"[[1,2],[3,4],{\"a\":\"abc\"}]";
-static char *pretty_inline2 =
+static const char *pretty_inline2 =
("[\n"
" [\n"
" 1,\n"
@@ -415,6 +415,7 @@ static void get_i(struct line *line, intmax_t *s_in)
get_s(line, &s);
+ errno = 0;
*s_in = strtol(s, &endptr, 10);
if (*endptr || errno == ERANGE)
die("line[%d]: invalid integer value", line->nr);
@@ -427,6 +428,7 @@ static void get_d(struct line *line, double *s_in)
get_s(line, &s);
+ errno = 0;
*s_in = strtod(s, &endptr);
if (*endptr || errno == ERANGE)
die("line[%d]: invalid float value", line->nr);
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
index 187a115d57..40f5df4412 100644
--- a/t/helper/test-lazy-init-name-hash.c
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "environment.h"
#include "name-hash.h"
@@ -40,22 +41,22 @@ static void dump_run(void)
repo_read_index(the_repository);
if (single) {
- test_lazy_init_name_hash(&the_index, 0);
+ test_lazy_init_name_hash(the_repository->index, 0);
} else {
- int nr_threads_used = test_lazy_init_name_hash(&the_index, 1);
+ int nr_threads_used = test_lazy_init_name_hash(the_repository->index, 1);
if (!nr_threads_used)
die("non-threaded code path used");
}
- hashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir,
+ hashmap_for_each_entry(&the_repository->index->dir_hash, &iter_dir, dir,
ent /* member name */)
printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name);
- hashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce,
+ hashmap_for_each_entry(&the_repository->index->name_hash, &iter_cache, ce,
ent /* member name */)
printf("name %08x %s\n", ce->ent.hash, ce->name);
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
/*
@@ -74,7 +75,7 @@ static uint64_t time_runs(int try_threaded)
t0 = getnanotime();
repo_read_index(the_repository);
t1 = getnanotime();
- nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded);
+ nr_threads_used = test_lazy_init_name_hash(the_repository->index, try_threaded);
t2 = getnanotime();
sum += (t2 - t1);
@@ -86,16 +87,16 @@ static uint64_t time_runs(int try_threaded)
printf("%f %f %d multi %d\n",
((double)(t1 - t0))/1000000000,
((double)(t2 - t1))/1000000000,
- the_index.cache_nr,
+ the_repository->index->cache_nr,
nr_threads_used);
else
printf("%f %f %d single\n",
((double)(t1 - t0))/1000000000,
((double)(t2 - t1))/1000000000,
- the_index.cache_nr);
+ the_repository->index->cache_nr);
fflush(stdout);
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
avg = sum / count;
@@ -120,8 +121,8 @@ static void analyze_run(void)
int nr;
repo_read_index(the_repository);
- cache_nr_limit = the_index.cache_nr;
- discard_index(&the_index);
+ cache_nr_limit = the_repository->index->cache_nr;
+ discard_index(the_repository->index);
nr = analyze;
while (1) {
@@ -135,22 +136,22 @@ static void analyze_run(void)
for (i = 0; i < count; i++) {
repo_read_index(the_repository);
- the_index.cache_nr = nr; /* cheap truncate of index */
+ the_repository->index->cache_nr = nr; /* cheap truncate of index */
t1s = getnanotime();
- test_lazy_init_name_hash(&the_index, 0);
+ test_lazy_init_name_hash(the_repository->index, 0);
t2s = getnanotime();
sum_single += (t2s - t1s);
- the_index.cache_nr = cache_nr_limit;
- discard_index(&the_index);
+ the_repository->index->cache_nr = cache_nr_limit;
+ discard_index(the_repository->index);
repo_read_index(the_repository);
- the_index.cache_nr = nr; /* cheap truncate of index */
+ the_repository->index->cache_nr = nr; /* cheap truncate of index */
t1m = getnanotime();
- nr_threads_used = test_lazy_init_name_hash(&the_index, 1);
+ nr_threads_used = test_lazy_init_name_hash(the_repository->index, 1);
t2m = getnanotime();
sum_multi += (t2m - t1m);
- the_index.cache_nr = cache_nr_limit;
- discard_index(&the_index);
+ the_repository->index->cache_nr = cache_nr_limit;
+ discard_index(the_repository->index);
if (!nr_threads_used)
printf(" [size %8d] [single %f] non-threaded code path used\n",
diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c
index d0db5ff26f..e0e2048320 100644
--- a/t/helper/test-match-trees.c
+++ b/t/helper/test-match-trees.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "hex.h"
#include "match-trees.h"
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index 42ccc87051..328bfe2977 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -122,7 +122,7 @@ static const struct dist *get_dist_by_name(const char *name)
return NULL;
}
-static void mode_copy(int *arr, int n)
+static void mode_copy(int *arr UNUSED, int n UNUSED)
{
/* nothing */
}
diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c
deleted file mode 100644
index aafe398ef0..0000000000
--- a/t/helper/test-oid-array.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "test-tool.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 UNUSED)
-{
- puts(oid_to_hex(oid));
- return 0;
-}
-
-int cmd__oid_array(int argc UNUSED, const char **argv UNUSED)
-{
- struct oid_array array = OID_ARRAY_INIT;
- struct strbuf line = STRBUF_INIT;
- int nongit_ok;
-
- setup_git_directory_gently(&nongit_ok);
-
- while (strbuf_getline(&line, stdin) != EOF) {
- const char *arg;
- struct object_id oid;
-
- if (skip_prefix(line.buf, "append ", &arg)) {
- if (get_oid_hex(arg, &oid))
- die("not a hexadecimal oid: %s", arg);
- oid_array_append(&array, &oid);
- } else if (skip_prefix(line.buf, "lookup ", &arg)) {
- if (get_oid_hex(arg, &oid))
- die("not a hexadecimal oid: %s", arg);
- printf("%d\n", oid_array_lookup(&array, &oid));
- } else if (!strcmp(line.buf, "clear"))
- oid_array_clear(&array);
- else if (!strcmp(line.buf, "for_each_unique"))
- oid_array_for_each_unique(&array, print_oid, NULL);
- else
- die("unknown command: %s", line.buf);
- }
-
- strbuf_release(&line);
- oid_array_clear(&array);
-
- return 0;
-}
diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c
deleted file mode 100644
index bd30244a54..0000000000
--- a/t/helper/test-oidmap.c
+++ /dev/null
@@ -1,123 +0,0 @@
-#include "test-tool.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 {
- struct oidmap_entry entry;
- char name[FLEX_ARRAY];
-};
-
-#define DELIM " \t\r\n"
-
-/*
- * Read stdin line by line and print result of commands to stdout:
- *
- * hash oidkey -> sha1hash(oidkey)
- * put oidkey namevalue -> NULL / old namevalue
- * get oidkey -> NULL / namevalue
- * remove oidkey -> NULL / old namevalue
- * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n...
- *
- */
-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;
-
- setup_git_directory();
-
- /* init oidmap */
- oidmap_init(&map, 0);
-
- /* process commands from stdin */
- while (strbuf_getline(&line, stdin) != EOF) {
- char *cmd, *p1, *p2;
- struct test_entry *entry;
- struct object_id oid;
-
- /* break line into command and up to two parameters */
- string_list_setlen(&parts, 0);
- string_list_split_in_place(&parts, line.buf, DELIM, 2);
- string_list_remove_empty_items(&parts, 0);
-
- /* ignore empty lines */
- if (!parts.nr)
- continue;
- if (!*parts.items[0].string || *parts.items[0].string == '#')
- continue;
-
- 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 (repo_get_oid(the_repository, p1, &oid)) {
- printf("Unknown oid: %s\n", p1);
- continue;
- }
-
- /* create entry with oid_key = p1, name_value = p2 */
- FLEX_ALLOC_STR(entry, name, p2);
- oidcpy(&entry->entry.oid, &oid);
-
- /* add / replace entry */
- entry = oidmap_put(&map, entry);
-
- /* print and free replaced entry, if any */
- puts(entry ? entry->name : "NULL");
- free(entry);
-
- } else if (!strcmp("get", cmd) && p1) {
-
- if (repo_get_oid(the_repository, p1, &oid)) {
- printf("Unknown oid: %s\n", p1);
- continue;
- }
-
- /* lookup entry in oidmap */
- entry = oidmap_get(&map, &oid);
-
- /* print result */
- puts(entry ? entry->name : "NULL");
-
- } else if (!strcmp("remove", cmd) && p1) {
-
- if (repo_get_oid(the_repository, p1, &oid)) {
- printf("Unknown oid: %s\n", p1);
- continue;
- }
-
- /* remove entry from oidmap */
- entry = oidmap_remove(&map, &oid);
-
- /* print result and free entry*/
- puts(entry ? entry->name : "NULL");
- free(entry);
-
- } else if (!strcmp("iterate", cmd)) {
-
- struct oidmap_iter iter;
- oidmap_iter_init(&map, &iter);
- while ((entry = oidmap_iter_next(&iter)))
- printf("%s %s\n", oid_to_hex(&entry->entry.oid), entry->name);
-
- } else {
-
- printf("Unknown command %s\n", cmd);
-
- }
- }
-
- string_list_clear(&parts, 0);
- strbuf_release(&line);
- oidmap_free(&map, 1);
- return 0;
-}
diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c
deleted file mode 100644
index c7a1d4c642..0000000000
--- a/t/helper/test-oidtree.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "test-tool.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 UNUSED)
-{
- puts(oid_to_hex(oid));
- return CB_CONTINUE;
-}
-
-int cmd__oidtree(int argc UNUSED, const char **argv UNUSED)
-{
- struct oidtree ot;
- struct strbuf line = STRBUF_INIT;
- int nongit_ok;
- int algo = GIT_HASH_UNKNOWN;
-
- oidtree_init(&ot);
- setup_git_directory_gently(&nongit_ok);
-
- while (strbuf_getline(&line, stdin) != EOF) {
- const char *arg;
- struct object_id oid;
-
- if (skip_prefix(line.buf, "insert ", &arg)) {
- if (get_oid_hex_any(arg, &oid) == GIT_HASH_UNKNOWN)
- die("insert not a hexadecimal oid: %s", arg);
- algo = oid.algo;
- oidtree_insert(&ot, &oid);
- } else if (skip_prefix(line.buf, "contains ", &arg)) {
- if (get_oid_hex(arg, &oid))
- die("contains not a hexadecimal oid: %s", arg);
- printf("%d\n", oidtree_contains(&ot, &oid));
- } else if (skip_prefix(line.buf, "each ", &arg)) {
- char buf[GIT_MAX_HEXSZ + 1] = { '0' };
- memset(&oid, 0, sizeof(oid));
- memcpy(buf, arg, strlen(arg));
- buf[hash_algos[algo].hexsz] = '\0';
- get_oid_hex_any(buf, &oid);
- oid.algo = algo;
- oidtree_each(&ot, &oid, strlen(arg), print_oid, NULL);
- } else if (!strcmp(line.buf, "clear")) {
- oidtree_clear(&ot);
- } else {
- die("unknown command: %s", line.buf);
- }
- }
-
- strbuf_release(&line);
-
- return 0;
-}
diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c
index 67a964ef90..f8f9afbb5b 100644
--- a/t/helper/test-pack-mtimes.c
+++ b/t/helper/test-pack-mtimes.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "hex.h"
#include "strbuf.h"
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index a4f6e24b0c..5250913d99 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -21,6 +21,19 @@ static struct {
int unset;
} length_cb;
+static int mode34_callback(const struct option *opt, const char *arg, int unset)
+{
+ if (unset)
+ *(int *)opt->value = 0;
+ else if (!strcmp(arg, "3"))
+ *(int *)opt->value = 3;
+ else if (!strcmp(arg, "4"))
+ *(int *)opt->value = 4;
+ else
+ return error("invalid value for '%s': '%s'", "--mode34", arg);
+ return 0;
+}
+
static int length_callback(const struct option *opt, const char *arg, int unset)
{
length_cb.called = 1;
@@ -124,6 +137,9 @@ int cmd__parse_options(int argc, const char **argv)
OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
+ OPT_CALLBACK_F(0, "mode34", &integer, "(3|4)",
+ "set integer to 3 or 4 (cmdmode option)",
+ PARSE_OPT_CMDMODE, mode34_callback),
OPT_CALLBACK('L', "length", &integer, "str",
"get length of <str>", length_callback),
OPT_FILENAME('F', "file", &file, "set file to <file>"),
@@ -191,6 +207,7 @@ int cmd__parse_options(int argc, const char **argv)
expect.strdup_strings = 1;
string_list_clear(&expect, 0);
string_list_clear(&list, 0);
+ free(file);
return ret;
}
diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c
index 910a128614..a1af9710c3 100644
--- a/t/helper/test-partial-clone.c
+++ b/t/helper/test-partial-clone.c
@@ -21,11 +21,13 @@ static void object_info(const char *gitdir, const char *oid_hex)
if (repo_init(&r, gitdir, NULL))
die("could not init repo");
- if (parse_oid_hex(oid_hex, &oid, &p))
+ if (parse_oid_hex_algop(oid_hex, &oid, &p, r.hash_algo))
die("could not parse oid");
if (oid_object_info_extended(&r, &oid, &oi, 0))
die("could not obtain object info");
printf("%d\n", (int) size);
+
+ repo_clear(&r);
}
int cmd__partial_clone(int argc, const char **argv)
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index bf0e23ed50..3129aa28fd 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "abspath.h"
#include "environment.h"
@@ -38,7 +40,7 @@ static void normalize_argv_string(const char **var, const char *input)
*var = input;
if (*var && (**var == '<' || **var == '('))
- die("Bad value: %s\n", input);
+ die("Bad value: %s", input);
}
struct test_data {
@@ -78,12 +80,12 @@ static int test_function(struct test_data *data, char *(*func)(char *input),
if (!strcmp(to, data[i].to))
continue;
if (!data[i].alternative)
- error("FAIL: %s(%s) => '%s' != '%s'\n",
+ error("FAIL: %s(%s) => '%s' != '%s'",
funcname, data[i].from, to, data[i].to);
else if (!strcmp(to, data[i].alternative))
continue;
else
- error("FAIL: %s(%s) => '%s' != '%s', '%s'\n",
+ error("FAIL: %s(%s) => '%s' != '%s', '%s'",
funcname, data[i].from, to, data[i].to,
data[i].alternative);
failed = 1;
diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c
index f4d134a145..4daa82f00f 100644
--- a/t/helper/test-pkt-line.c
+++ b/t/helper/test-pkt-line.c
@@ -1,7 +1,9 @@
#include "git-compat-util.h"
#include "test-tool.h"
#include "pkt-line.h"
+#include "sideband.h"
#include "write-or-die.h"
+#include "parse-options.h"
static void pack_line(const char *line)
{
@@ -64,12 +66,33 @@ static void unpack(void)
}
}
-static void unpack_sideband(void)
+static void unpack_sideband(int argc, const char **argv)
{
struct packet_reader reader;
- packet_reader_init(&reader, 0, NULL, 0,
- PACKET_READ_GENTLE_ON_EOF |
- PACKET_READ_CHOMP_NEWLINE);
+ int options = PACKET_READ_GENTLE_ON_EOF;
+ int chomp_newline = 1;
+ int reader_use_sideband = 0;
+ const char *const unpack_sideband_usage[] = {
+ "test_tool unpack_sideband [options...]", NULL
+ };
+ struct option cmd_options[] = {
+ OPT_BOOL(0, "reader-use-sideband", &reader_use_sideband,
+ "set use_sideband bit for packet reader (Default: off)"),
+ OPT_BOOL(0, "chomp-newline", &chomp_newline,
+ "chomp newline in packet (Default: on)"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, "", cmd_options, unpack_sideband_usage,
+ 0);
+ if (argc > 0)
+ usage_msg_opt(_("too many arguments"), unpack_sideband_usage,
+ cmd_options);
+
+ if (chomp_newline)
+ options |= PACKET_READ_CHOMP_NEWLINE;
+ packet_reader_init(&reader, 0, NULL, 0, options);
+ reader.use_sideband = reader_use_sideband;
while (packet_reader_read(&reader) != PACKET_READ_EOF) {
int band;
@@ -79,6 +102,17 @@ static void unpack_sideband(void)
case PACKET_READ_EOF:
break;
case PACKET_READ_NORMAL:
+ /*
+ * When the "use_sideband" field of the reader is turned
+ * on, sideband packets other than the payload have been
+ * parsed and consumed in packet_reader_read(), and only
+ * the payload arrives here.
+ */
+ if (reader.use_sideband) {
+ write_or_die(1, reader.line, reader.pktlen - 1);
+ break;
+ }
+
band = reader.line[0] & 0xff;
if (band < 1 || band > 2)
continue; /* skip non-sideband packets */
@@ -97,15 +131,31 @@ static void unpack_sideband(void)
static int send_split_sideband(void)
{
+ const char *foo = "Foo.\n";
+ const char *bar = "Bar.\n";
const char *part1 = "Hello,";
const char *primary = "\001primary: regular output\n";
const char *part2 = " world!\n";
+ /* Each sideband message has a trailing newline character. */
+ send_sideband(1, 2, foo, strlen(foo), LARGE_PACKET_MAX);
+ send_sideband(1, 2, bar, strlen(bar), LARGE_PACKET_MAX);
+
+ /*
+ * One sideband message is divided into part1 and part2
+ * by the primary message.
+ */
send_sideband(1, 2, part1, strlen(part1), LARGE_PACKET_MAX);
packet_write(1, primary, strlen(primary));
send_sideband(1, 2, part2, strlen(part2), LARGE_PACKET_MAX);
packet_response_end(1);
+ /*
+ * We use unpack_sideband() to consume packets. A flush packet
+ * is required to end parsing.
+ */
+ packet_flush(1);
+
return 0;
}
@@ -126,7 +176,7 @@ int cmd__pkt_line(int argc, const char **argv)
else if (!strcmp(argv[1], "unpack"))
unpack();
else if (!strcmp(argv[1], "unpack-sideband"))
- unpack_sideband();
+ unpack_sideband(argc - 1, argv + 1);
else if (!strcmp(argv[1], "send-split-sideband"))
send_split_sideband();
else if (!strcmp(argv[1], "receive-sideband"))
diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c
deleted file mode 100644
index f0bf255f5f..0000000000
--- a/t/helper/test-prio-queue.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "test-tool.h"
-#include "prio-queue.h"
-
-static int intcmp(const void *va, const void *vb, void *data UNUSED)
-{
- const int *a = va, *b = vb;
- return *a - *b;
-}
-
-static void show(int *v)
-{
- if (!v)
- printf("NULL\n");
- else
- printf("%d\n", *v);
- free(v);
-}
-
-int cmd__prio_queue(int argc UNUSED, const char **argv)
-{
- struct prio_queue pq = { intcmp };
-
- while (*++argv) {
- if (!strcmp(*argv, "get")) {
- void *peek = prio_queue_peek(&pq);
- void *get = prio_queue_get(&pq);
- if (peek != get)
- BUG("peek and get results do not match");
- show(get);
- } else if (!strcmp(*argv, "dump")) {
- void *peek;
- void *get;
- while ((peek = prio_queue_peek(&pq))) {
- get = prio_queue_get(&pq);
- if (peek != get)
- BUG("peek and get results do not match");
- show(get);
- }
- } else if (!strcmp(*argv, "stack")) {
- pq.compare = NULL;
- } else {
- int *v = xmalloc(sizeof(*v));
- *v = atoi(*argv);
- prio_queue_put(&pq, v);
- }
- }
-
- clear_prio_queue(&pq);
-
- return 0;
-}
diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c
index f30022d222..3703f734f3 100644
--- a/t/helper/test-proc-receive.c
+++ b/t/helper/test-proc-receive.c
@@ -3,8 +3,8 @@
#include "hex.h"
#include "parse-options.h"
#include "pkt-line.h"
-#include "setup.h"
#include "sigchain.h"
+#include "string-list.h"
static const char *proc_receive_usage[] = {
"test-tool proc-receive [<options>]",
@@ -92,9 +92,9 @@ static void proc_receive_read_commands(struct packet_reader *reader,
if (die_read_commands)
die("die with the --die-read-commands option");
- if (parse_oid_hex(reader->line, &old_oid, &p) ||
+ if (parse_oid_hex_any(reader->line, &old_oid, &p) == GIT_HASH_UNKNOWN ||
*p++ != ' ' ||
- parse_oid_hex(p, &new_oid, &p) ||
+ parse_oid_hex_any(p, &new_oid, &p) == GIT_HASH_UNKNOWN ||
*p++ != ' ')
die("protocol error: expected 'old new ref', got '%s'",
reader->line);
@@ -128,7 +128,6 @@ static void proc_receive_read_push_options(struct packet_reader *reader,
int cmd__proc_receive(int argc, const char **argv)
{
- int nongit_ok = 0;
struct packet_reader reader;
struct command *commands = NULL;
struct string_list push_options = STRING_LIST_INIT_DUP;
@@ -154,8 +153,6 @@ int cmd__proc_receive(int argc, const char **argv)
OPT_END()
};
- setup_git_directory_gently(&nongit_ok);
-
argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0);
if (argc > 0)
usage_msg_opt("Too many arguments.", proc_receive_usage, options);
@@ -199,5 +196,12 @@ int cmd__proc_receive(int argc, const char **argv)
packet_flush(1);
sigchain_pop(SIGPIPE);
+ while (commands) {
+ struct command *next = commands->next;
+ free(commands);
+ commands = next;
+ }
+ string_list_clear(&push_options, 0);
+
return 0;
}
diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c
index 66acb6a06c..44be2645e9 100644
--- a/t/helper/test-progress.c
+++ b/t/helper/test-progress.c
@@ -62,13 +62,13 @@ int cmd__progress(int argc, const char **argv)
else if (*end == ' ')
title = string_list_insert(&titles, end + 1)->string;
else
- die("invalid input: '%s'\n", line.buf);
+ die("invalid input: '%s'", line.buf);
progress = start_progress(title, total);
} else if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
uint64_t item_count = strtoull(end, &end, 10);
if (*end != '\0')
- die("invalid input: '%s'\n", line.buf);
+ die("invalid input: '%s'", line.buf);
display_progress(progress, item_count);
} else if (skip_prefix(line.buf, "throughput ",
(const char **) &end)) {
@@ -76,10 +76,10 @@ int cmd__progress(int argc, const char **argv)
byte_count = strtoull(end, &end, 10);
if (*end != ' ')
- die("invalid input: '%s'\n", line.buf);
+ die("invalid input: '%s'", line.buf);
test_ms = strtoull(end + 1, &end, 10);
if (*end != '\0')
- die("invalid input: '%s'\n", line.buf);
+ die("invalid input: '%s'", line.buf);
progress_test_ns = test_ms * 1000 * 1000;
display_throughput(progress, byte_count);
} else if (!strcmp(line.buf, "update")) {
@@ -87,7 +87,7 @@ int cmd__progress(int argc, const char **argv)
} else if (!strcmp(line.buf, "stop")) {
stop_progress(&progress);
} else {
- die("invalid input: '%s'\n", line.buf);
+ die("invalid input: '%s'", line.buf);
}
}
strbuf_release(&line);
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index 3e173399a0..84deee604a 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -1,11 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.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"
@@ -64,16 +64,16 @@ int cmd__reach(int ac, const char **av)
die("failed to resolve %s", buf.buf + 2);
orig = parse_object(r, &oid);
- peeled = deref_tag_noverify(orig);
+ peeled = deref_tag_noverify(the_repository, orig);
if (!peeled)
- die("failed to load commit for input %s resulting in oid %s\n",
+ die("failed to load commit for input %s resulting in oid %s",
buf.buf, oid_to_hex(&oid));
c = object_as_type(peeled, OBJ_COMMIT, 0);
if (!c)
- die("failed to load commit for input %s resulting in oid %s\n",
+ die("failed to load commit for input %s resulting in oid %s",
buf.buf, oid_to_hex(&oid));
switch (buf.buf[0]) {
@@ -113,19 +113,26 @@ int cmd__reach(int ac, const char **av)
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],
- repo_in_merge_bases_many(the_repository, A, X_nr, X_array));
+ repo_in_merge_bases_many(the_repository, A, X_nr, X_array, 0));
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_branch_base_for_tip"))
+ printf("%s(A,X):%d\n", av[1], get_branch_base_for_tip(r, A, X_array, X_nr));
else if (!strcmp(av[1], "get_merge_bases_many")) {
- struct commit_list *list = repo_get_merge_bases_many(the_repository,
- A, X_nr,
- X_array);
+ struct commit_list *list = NULL;
+ if (repo_get_merge_bases_many(the_repository,
+ A, X_nr,
+ X_array,
+ &list) < 0)
+ exit(128);
printf("%s(A,X):\n", av[1]);
print_sorted_commit_ids(list);
+ free_commit_list(list);
} else if (!strcmp(av[1], "reduce_heads")) {
struct commit_list *list = reduce_heads(X);
printf("%s(X):\n", av[1]);
print_sorted_commit_ids(list);
+ free_commit_list(list);
} else if (!strcmp(av[1], "can_all_from_reach")) {
printf("%s(X,Y):%d\n", av[1], can_all_from_reach(X, Y, 1));
} else if (!strcmp(av[1], "can_all_from_reach_with_flag")) {
@@ -148,6 +155,7 @@ int cmd__reach(int ac, const char **av)
filter.with_commit_tag_algo = 0;
printf("%s(_,A,X,_):%d\n", av[1], commit_contains(&filter, A, X, &cache));
+ clear_contains_cache(&cache);
} else if (!strcmp(av[1], "get_reachable_subset")) {
const int reachable_flag = 1;
int i, count = 0;
@@ -171,7 +179,14 @@ int cmd__reach(int ac, const char **av)
die(_("too many commits marked reachable"));
print_sorted_commit_ids(list);
+ free_commit_list(list);
}
+ object_array_clear(&X_obj);
+ strbuf_release(&buf);
+ free_commit_list(X);
+ free_commit_list(Y);
+ free(X_array);
+ free(Y_array);
return 0;
}
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index 1acd362346..e277dde8e7 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "config.h"
#include "read-cache-ll.h"
@@ -10,8 +11,6 @@ int cmd__read_cache(int argc, const char **argv)
int i, cnt = 1;
const char *name = NULL;
- initialize_the_repository();
-
if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) {
argc--;
argv++;
@@ -27,16 +26,16 @@ int cmd__read_cache(int argc, const char **argv)
if (name) {
int pos;
- refresh_index(&the_index, REFRESH_QUIET,
+ refresh_index(the_repository->index, REFRESH_QUIET,
NULL, NULL, NULL);
- pos = index_name_pos(&the_index, name, strlen(name));
+ pos = index_name_pos(the_repository->index, name, strlen(name));
if (pos < 0)
die("%s not in index", name);
printf("%s is%s up to date\n", name,
- ce_uptodate(the_index.cache[pos]) ? "" : " not");
+ ce_uptodate(the_repository->index->cache[pos]) ? "" : " not");
write_file(name, "%d\n", i);
}
- discard_index(&the_index);
+ discard_index(the_repository->index);
}
return 0;
}
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index 8c7a83f578..811dde1cb3 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "commit-graph.h"
#include "repository.h"
@@ -5,20 +7,8 @@
#include "bloom.h"
#include "setup.h"
-int cmd__read_graph(int argc UNUSED, const char **argv UNUSED)
+static void dump_graph_info(struct commit_graph *graph)
{
- struct commit_graph *graph = NULL;
- struct object_directory *odb;
-
- setup_git_directory();
- odb = the_repository->objects->odb;
-
- prepare_repo_settings(the_repository);
-
- graph = read_commit_graph_one(the_repository, odb);
- if (!graph)
- return 1;
-
printf("header: %08x %d %d %d %d\n",
ntohl(*(uint32_t*)graph->data),
*(unsigned char*)(graph->data + 4),
@@ -57,8 +47,56 @@ int cmd__read_graph(int argc UNUSED, const char **argv UNUSED)
if (graph->topo_levels)
printf(" topo_levels");
printf("\n");
+}
+
+static void dump_graph_bloom_filters(struct commit_graph *graph)
+{
+ uint32_t i;
+
+ for (i = 0; i < graph->num_commits + graph->num_commits_in_base; i++) {
+ struct bloom_filter filter = { 0 };
+ size_t j;
+
+ if (load_bloom_filter_from_graph(graph, &filter, i) < 0) {
+ fprintf(stderr, "missing Bloom filter for graph "
+ "position %"PRIu32"\n", i);
+ continue;
+ }
+
+ for (j = 0; j < filter.len; j++)
+ printf("%02x", filter.data[j]);
+ if (filter.len)
+ printf("\n");
+ }
+}
+
+int cmd__read_graph(int argc, const char **argv)
+{
+ struct commit_graph *graph = NULL;
+ struct object_directory *odb;
+ int ret = 0;
+
+ setup_git_directory();
+ odb = the_repository->objects->odb;
+
+ prepare_repo_settings(the_repository);
+
+ graph = read_commit_graph_one(the_repository, odb);
+ if (!graph) {
+ ret = 1;
+ goto done;
+ }
- UNLEAK(graph);
+ if (argc <= 1)
+ dump_graph_info(graph);
+ else if (!strcmp(argv[1], "bloom-filters"))
+ dump_graph_bloom_filters(graph);
+ else {
+ fprintf(stderr, "unknown sub-command: '%s'\n", argv[1]);
+ ret = 1;
+ }
- return 0;
+done:
+ free_commit_graph(graph);
+ return ret;
}
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index e9a444ddba..438fb9fc61 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "hex.h"
#include "midx.h"
@@ -6,8 +8,11 @@
#include "pack-bitmap.h"
#include "packfile.h"
#include "setup.h"
+#include "gettext.h"
+#include "pack-revindex.h"
-static int read_midx_file(const char *object_dir, int show_objects)
+static int read_midx_file(const char *object_dir, const char *checksum,
+ int show_objects)
{
uint32_t i;
struct multi_pack_index *m;
@@ -18,6 +23,13 @@ static int read_midx_file(const char *object_dir, int show_objects)
if (!m)
return 1;
+ if (checksum) {
+ while (m && strcmp(hash_to_hex(get_midx_checksum(m)), checksum))
+ m = m->base_midx;
+ if (!m)
+ return 1;
+ }
+
printf("header: %08x %d %d %d %d\n",
m->signature,
m->version,
@@ -51,7 +63,8 @@ static int read_midx_file(const char *object_dir, int show_objects)
struct pack_entry e;
for (i = 0; i < m->num_objects; i++) {
- nth_midxed_object_oid(&oid, m, i);
+ nth_midxed_object_oid(&oid, m,
+ i + m->num_objects_in_base);
fill_midx_entry(the_repository, &oid, &e, m);
printf("%s %"PRIu64"\t%s\n",
@@ -73,13 +86,15 @@ static int read_midx_checksum(const char *object_dir)
if (!m)
return 1;
printf("%s\n", hash_to_hex(get_midx_checksum(m)));
+
+ close_midx(m);
return 0;
}
static int read_midx_preferred_pack(const char *object_dir)
{
struct multi_pack_index *midx = NULL;
- struct bitmap_index *bitmap = NULL;
+ uint32_t preferred_pack;
setup_git_directory();
@@ -87,29 +102,57 @@ static int read_midx_preferred_pack(const char *object_dir)
if (!midx)
return 1;
- bitmap = prepare_bitmap_git(the_repository);
- if (!bitmap)
+ if (midx_preferred_pack(midx, &preferred_pack) < 0) {
+ warning(_("could not determine MIDX preferred pack"));
+ close_midx(midx);
return 1;
- if (!bitmap_is_midx(bitmap)) {
- free_bitmap_index(bitmap);
+ }
+
+ printf("%s\n", midx->pack_names[preferred_pack]);
+ close_midx(midx);
+ return 0;
+}
+
+static int read_midx_bitmapped_packs(const char *object_dir)
+{
+ struct multi_pack_index *midx = NULL;
+ struct bitmapped_pack pack;
+ uint32_t i;
+
+ setup_git_directory();
+
+ midx = load_multi_pack_index(object_dir, 1);
+ if (!midx)
return 1;
+
+ for (i = 0; i < midx->num_packs + midx->num_packs_in_base; i++) {
+ if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0) {
+ close_midx(midx);
+ return 1;
+ }
+
+ printf("%s\n", pack_basename(pack.p));
+ printf(" bitmap_pos: %"PRIuMAX"\n", (uintmax_t)pack.bitmap_pos);
+ printf(" bitmap_nr: %"PRIuMAX"\n", (uintmax_t)pack.bitmap_nr);
}
- printf("%s\n", midx->pack_names[midx_preferred_pack(bitmap)]);
- free_bitmap_index(bitmap);
+ close_midx(midx);
+
return 0;
}
int cmd__read_midx(int argc, const char **argv)
{
- if (!(argc == 2 || argc == 3))
- usage("read-midx [--show-objects|--checksum|--preferred-pack] <object-dir>");
+ if (!(argc == 2 || argc == 3 || argc == 4))
+ usage("read-midx [--show-objects|--checksum|--preferred-pack|--bitmap] <object-dir> <checksum>");
if (!strcmp(argv[1], "--show-objects"))
- return read_midx_file(argv[2], 1);
+ return read_midx_file(argv[2], argv[3], 1);
else if (!strcmp(argv[1], "--checksum"))
return read_midx_checksum(argv[2]);
else if (!strcmp(argv[1], "--preferred-pack"))
return read_midx_preferred_pack(argv[2]);
- return read_midx_file(argv[1], 0);
+ else if (!strcmp(argv[1], "--bitmap"))
+ return read_midx_bitmapped_packs(argv[2]);
+ return read_midx_file(argv[1], argv[2], 0);
}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 48552e6a9e..240f6fc29d 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "hex.h"
#include "refs.h"
@@ -82,7 +84,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)
add_to_alternates_memory(sb.buf);
strbuf_release(&sb);
- *refs = get_submodule_ref_store(gitdir);
+ *refs = repo_get_submodule_ref_store(the_repository, gitdir);
} else if (skip_prefix(argv[0], "worktree:", &gitdir)) {
struct worktree **p, **worktrees = get_worktrees();
@@ -112,32 +114,13 @@ static const char **get_store(const char **argv, struct ref_store **refs)
return argv + 1;
}
-static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
- FLAG_DEF(PACK_REFS_ALL),
- { NULL, 0 } };
-
-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 };
-
- 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)
{
const char *refname = notnull(*argv++, "refname");
const char *target = notnull(*argv++, "target");
const char *logmsg = *argv++;
- return refs_create_symref(refs, refname, target, logmsg);
+ return refs_update_symref(refs, refname, target, logmsg);
}
static struct flag_definition transaction_flags[] = {
@@ -145,6 +128,7 @@ static struct flag_definition transaction_flags[] = {
FLAG_DEF(REF_FORCE_CREATE_REFLOG),
FLAG_DEF(REF_SKIP_OID_VERIFICATION),
FLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),
+ FLAG_DEF(REF_SKIP_CREATE_REFLOG),
{ NULL, 0 }
};
@@ -172,7 +156,7 @@ static int cmd_rename_ref(struct ref_store *refs, const char **argv)
return refs_rename_ref(refs, oldref, newref, logmsg);
}
-static int each_ref(const char *refname, const struct object_id *oid,
+static int each_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags, void *cb_data UNUSED)
{
printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags);
@@ -215,21 +199,27 @@ static int cmd_verify_ref(struct ref_store *refs, const char **argv)
struct strbuf err = STRBUF_INIT;
int ret;
- ret = refs_verify_refname_available(refs, refname, NULL, NULL, &err);
+ ret = refs_verify_refname_available(refs, refname, NULL, NULL, 0, &err);
if (err.len)
puts(err.buf);
return ret;
}
+static int each_reflog(const char *refname, void *cb_data UNUSED)
+{
+ printf("%s\n", refname);
+ return 0;
+}
+
static int cmd_for_each_reflog(struct ref_store *refs,
const char **argv UNUSED)
{
- return refs_for_each_reflog(refs, each_ref, NULL);
+ return refs_for_each_reflog(refs, each_reflog, NULL);
}
-static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,
- const char *committer, timestamp_t timestamp,
- int tz, const char *msg, void *cb_data UNUSED)
+static int each_reflog_ent(struct object_id *old_oid, struct object_id *new_oid,
+ const char *committer, timestamp_t timestamp,
+ int tz, const char *msg, void *cb_data UNUSED)
{
printf("%s %s %s %" PRItime " %+05d%s%s", oid_to_hex(old_oid),
oid_to_hex(new_oid), committer, timestamp, tz,
@@ -241,14 +231,14 @@ static int cmd_for_each_reflog_ent(struct ref_store *refs, const char **argv)
{
const char *refname = notnull(*argv++, "refname");
- return refs_for_each_reflog_ent(refs, refname, each_reflog, refs);
+ return refs_for_each_reflog_ent(refs, refname, each_reflog_ent, refs);
}
static int cmd_for_each_reflog_ent_reverse(struct ref_store *refs, const char **argv)
{
const char *refname = notnull(*argv++, "refname");
- return refs_for_each_reflog_ent_reverse(refs, refname, each_reflog, refs);
+ return refs_for_each_reflog_ent_reverse(refs, refname, each_reflog_ent, refs);
}
static int cmd_reflog_exists(struct ref_store *refs, const char **argv)
@@ -298,16 +288,19 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv)
const char *new_sha1_buf = notnull(*argv++, "new-sha1");
const char *old_sha1_buf = notnull(*argv++, "old-sha1");
unsigned int flags = arg_flags(*argv++, "flags", transaction_flags);
- struct object_id old_oid;
+ struct object_id old_oid, *old_oid_ptr = NULL;
struct object_id new_oid;
- if (get_oid_hex(old_sha1_buf, &old_oid))
- die("cannot parse %s as %s", old_sha1_buf, the_hash_algo->name);
+ if (*old_sha1_buf) {
+ if (get_oid_hex(old_sha1_buf, &old_oid))
+ die("cannot parse %s as %s", old_sha1_buf, the_hash_algo->name);
+ old_oid_ptr = &old_oid;
+ }
if (get_oid_hex(new_sha1_buf, &new_oid))
die("cannot parse %s as %s", new_sha1_buf, the_hash_algo->name);
return refs_update_ref(refs, msg, refname,
- &new_oid, &old_oid,
+ &new_oid, old_oid_ptr,
flags, UPDATE_REFS_DIE_ON_ERR);
}
@@ -317,7 +310,6 @@ struct command {
};
static struct command commands[] = {
- { "pack-refs", cmd_pack_refs },
{ "create-symref", cmd_create_symref },
{ "delete-refs", cmd_delete_refs },
{ "rename-ref", cmd_rename_ref },
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index 00237ef0d9..5c8849d115 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -1,23 +1,200 @@
+#include "git-compat-util.h"
+#include "hash.h"
+#include "hex.h"
#include "reftable/system.h"
-#include "reftable/reftable-tests.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-merged.h"
+#include "reftable/reftable-reader.h"
+#include "reftable/reftable-stack.h"
#include "test-tool.h"
-int cmd__reftable(int argc, const char **argv)
+static void print_help(void)
{
- /* test from simple to complex. */
- basics_test_main(argc, argv);
- record_test_main(argc, argv);
- block_test_main(argc, argv);
- tree_test_main(argc, argv);
- pq_test_main(argc, argv);
- readwrite_test_main(argc, argv);
- merged_test_main(argc, argv);
- stack_test_main(argc, argv);
- refname_test_main(argc, argv);
+ printf("usage: dump [-st] arg\n\n"
+ "options: \n"
+ " -b dump blocks\n"
+ " -t dump table\n"
+ " -s dump stack\n"
+ " -6 sha256 hash format\n"
+ " -h this help\n"
+ "\n");
+}
+
+static int dump_table(struct reftable_merged_table *mt)
+{
+ struct reftable_iterator it = { NULL };
+ struct reftable_ref_record ref = { NULL };
+ struct reftable_log_record log = { NULL };
+ const struct git_hash_algo *algop;
+ int err;
+
+ err = reftable_merged_table_init_ref_iterator(mt, &it);
+ if (err < 0)
+ return err;
+
+ err = reftable_iterator_seek_ref(&it, "");
+ if (err < 0)
+ return err;
+
+ algop = &hash_algos[hash_algo_by_id(reftable_merged_table_hash_id(mt))];
+
+ while (1) {
+ err = reftable_iterator_next_ref(&it, &ref);
+ if (err > 0)
+ break;
+ if (err < 0)
+ return err;
+
+ printf("ref{%s(%" PRIu64 ") ", ref.refname, ref.update_index);
+ switch (ref.value_type) {
+ case REFTABLE_REF_SYMREF:
+ printf("=> %s", ref.value.symref);
+ break;
+ case REFTABLE_REF_VAL2:
+ printf("val 2 %s", hash_to_hex_algop(ref.value.val2.value, algop));
+ printf("(T %s)", hash_to_hex_algop(ref.value.val2.target_value, algop));
+ break;
+ case REFTABLE_REF_VAL1:
+ printf("val 1 %s", hash_to_hex_algop(ref.value.val1, algop));
+ break;
+ case REFTABLE_REF_DELETION:
+ printf("delete");
+ break;
+ }
+ printf("}\n");
+ }
+ reftable_iterator_destroy(&it);
+ reftable_ref_record_release(&ref);
+
+ err = reftable_merged_table_init_log_iterator(mt, &it);
+ if (err < 0)
+ return err;
+
+ err = reftable_iterator_seek_log(&it, "");
+ if (err < 0)
+ return err;
+
+ while (1) {
+ err = reftable_iterator_next_log(&it, &log);
+ if (err > 0)
+ break;
+ if (err < 0)
+ return err;
+
+ switch (log.value_type) {
+ case REFTABLE_LOG_DELETION:
+ printf("log{%s(%" PRIu64 ") delete\n", log.refname,
+ log.update_index);
+ break;
+ case REFTABLE_LOG_UPDATE:
+ printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
+ log.refname, log.update_index,
+ log.value.update.name ? log.value.update.name : "",
+ log.value.update.email ? log.value.update.email : "",
+ log.value.update.time,
+ log.value.update.tz_offset);
+ printf("%s => ", hash_to_hex_algop(log.value.update.old_hash, algop));
+ printf("%s\n\n%s\n}\n", hash_to_hex_algop(log.value.update.new_hash, algop),
+ log.value.update.message ? log.value.update.message : "");
+ break;
+ }
+ }
+ reftable_iterator_destroy(&it);
+ reftable_log_record_release(&log);
return 0;
}
+static int dump_stack(const char *stackdir, uint32_t hash_id)
+{
+ struct reftable_stack *stack = NULL;
+ struct reftable_write_options opts = { .hash_id = hash_id };
+ struct reftable_merged_table *merged = NULL;
+
+ int err = reftable_new_stack(&stack, stackdir, &opts);
+ if (err < 0)
+ goto done;
+
+ merged = reftable_stack_merged_table(stack);
+ err = dump_table(merged);
+done:
+ if (stack)
+ reftable_stack_destroy(stack);
+ return err;
+}
+
+static int dump_reftable(const char *tablename)
+{
+ struct reftable_block_source src = { 0 };
+ struct reftable_merged_table *mt = NULL;
+ struct reftable_reader *r = NULL;
+ int err;
+
+ err = reftable_block_source_from_file(&src, tablename);
+ if (err < 0)
+ goto done;
+
+ err = reftable_reader_new(&r, &src, tablename);
+ if (err < 0)
+ goto done;
+
+ err = reftable_merged_table_new(&mt, &r, 1,
+ reftable_reader_hash_id(r));
+ if (err < 0)
+ goto done;
+
+ err = dump_table(mt);
+
+done:
+ reftable_merged_table_free(mt);
+ reftable_reader_decref(r);
+ return err;
+}
+
int cmd__dump_reftable(int argc, const char **argv)
{
- return reftable_dump_main(argc, (char *const *)argv);
+ int err = 0;
+ int opt_dump_blocks = 0;
+ int opt_dump_table = 0;
+ int opt_dump_stack = 0;
+ uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
+ const char *arg = NULL, *argv0 = argv[0];
+
+ for (; argc > 1; argv++, argc--)
+ if (*argv[1] != '-')
+ break;
+ else if (!strcmp("-b", argv[1]))
+ opt_dump_blocks = 1;
+ else if (!strcmp("-t", argv[1]))
+ opt_dump_table = 1;
+ else if (!strcmp("-6", argv[1]))
+ opt_hash_id = GIT_SHA256_FORMAT_ID;
+ else if (!strcmp("-s", argv[1]))
+ opt_dump_stack = 1;
+ else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
+ print_help();
+ return 2;
+ }
+
+ if (argc != 2) {
+ fprintf(stderr, "need argument\n");
+ print_help();
+ return 2;
+ }
+
+ arg = argv[1];
+
+ if (opt_dump_blocks) {
+ err = reftable_reader_print_blocks(arg);
+ } else if (opt_dump_table) {
+ err = dump_reftable(arg);
+ } else if (opt_dump_stack) {
+ err = dump_stack(arg, opt_hash_id);
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "%s: %s: %s\n", argv0, arg,
+ reftable_error_str(err));
+ return 1;
+ }
+ return 0;
}
diff --git a/t/helper/test-regex.c b/t/helper/test-regex.c
index bd871a735b..366bd70976 100644
--- a/t/helper/test-regex.c
+++ b/t/helper/test-regex.c
@@ -20,8 +20,8 @@ static struct reg_flag reg_flags[] = {
static int test_regex_bug(void)
{
- char *pat = "[^={} \t]+";
- char *str = "={}\nfred";
+ const char *pat = "[^={} \t]+";
+ const char *str = "={}\nfred";
regex_t r;
regmatch_t m[1];
@@ -30,7 +30,7 @@ static int test_regex_bug(void)
if (regexec(&r, str, 1, m, 0))
die("no match of pattern '%s' to string '%s'", pat, str);
- /* http://sourceware.org/bugzilla/show_bug.cgi?id=3957 */
+ /* https://sourceware.org/bugzilla/show_bug.cgi?id=3957 */
if (m[0].rm_so == 3) /* matches '\n' when it should not */
die("regex bug confirmed: re-build git with NO_REGEX=1");
diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c
index 4cd8a952e5..63c37de33d 100644
--- a/t/helper/test-repository.c
+++ b/t/helper/test-repository.c
@@ -1,10 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "commit-graph.h"
#include "commit.h"
-#include "config.h"
#include "environment.h"
#include "hex.h"
-#include "object-store-ll.h"
#include "object.h"
#include "repository.h"
#include "setup.h"
@@ -19,7 +19,7 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
setup_git_env(gitdir);
- memset(the_repository, 0, sizeof(*the_repository));
+ repo_clear(the_repository);
if (repo_init(&r, gitdir, worktree))
die("Couldn't init repo");
@@ -49,7 +49,7 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
setup_git_env(gitdir);
- memset(the_repository, 0, sizeof(*the_repository));
+ repo_clear(the_repository);
if (repo_init(&r, gitdir, worktree))
die("Couldn't init repo");
diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c
index f346951bc2..071f5bd1e2 100644
--- a/t/helper/test-revision-walking.c
+++ b/t/helper/test-revision-walking.c
@@ -8,6 +8,8 @@
* published by the Free Software Foundation.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "commit.h"
#include "diff.h"
diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c
index f8d564c622..ff407b575c 100644
--- a/t/helper/test-rot13-filter.c
+++ b/t/helper/test-rot13-filter.c
@@ -9,7 +9,7 @@
* ("clean", "smudge", etc).
*
* When --always-delay is given all pathnames with the "can-delay" flag
- * that don't appear on the list bellow are delayed with a count of 1
+ * that don't appear on the list below are delayed with a count of 1
* (see more below).
*
* This implementation supports special test cases:
@@ -136,7 +136,7 @@ static void free_delay_entries(void)
strmap_clear(&delay, 0);
}
-static void add_delay_entry(char *pathname, int count, int requested)
+static void add_delay_entry(const char *pathname, int count, int requested)
{
struct delay_entry *entry = xcalloc(1, sizeof(*entry));
entry->count = count;
@@ -189,7 +189,8 @@ static void reply_list_available_blobs_cmd(void)
static void command_loop(void)
{
for (;;) {
- char *buf, *output;
+ char *buf;
+ const char *output;
char *pathname;
struct delay_entry *entry;
struct strbuf input = STRBUF_INIT;
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index c0ed8722c8..61eb1175fe 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -65,6 +65,7 @@ struct testsuite {
struct string_list tests, failed;
int next;
int quiet, immediate, verbose, verbose_log, trace, write_junit_xml;
+ const char *shell_path;
};
#define TESTSUITE_INIT { \
.tests = STRING_LIST_INIT_DUP, \
@@ -80,7 +81,9 @@ static int next_test(struct child_process *cp, struct strbuf *err, void *cb,
return 0;
test = suite->tests.items[suite->next++].string;
- strvec_pushl(&cp->args, "sh", test, NULL);
+ if (suite->shell_path)
+ strvec_push(&cp->args, suite->shell_path);
+ strvec_push(&cp->args, test);
if (suite->quiet)
strvec_push(&cp->args, "--quiet");
if (suite->immediate)
@@ -155,6 +158,8 @@ static int testsuite(int argc, const char **argv)
.task_finished = test_finished,
.data = &suite,
};
+ struct strbuf progpath = STRBUF_INIT;
+ size_t path_prefix_len;
argc = parse_options(argc, argv, NULL, options,
testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION);
@@ -162,26 +167,36 @@ static int testsuite(int argc, const char **argv)
if (max_jobs <= 0)
max_jobs = online_cpus();
+ /*
+ * If we run without a shell, execute the programs directly from CWD.
+ */
+ suite.shell_path = getenv("TEST_SHELL_PATH");
+ if (!suite.shell_path)
+ strbuf_addstr(&progpath, "./");
+ path_prefix_len = progpath.len;
+
dir = opendir(".");
if (!dir)
die("Could not open the current directory");
while ((d = readdir(dir))) {
const char *p = d->d_name;
- if (*p != 't' || !isdigit(p[1]) || !isdigit(p[2]) ||
- !isdigit(p[3]) || !isdigit(p[4]) || p[5] != '-' ||
- !ends_with(p, ".sh"))
+ if (!strcmp(p, ".") || !strcmp(p, ".."))
continue;
/* No pattern: match all */
if (!argc) {
- string_list_append(&suite.tests, p);
+ strbuf_setlen(&progpath, path_prefix_len);
+ strbuf_addstr(&progpath, p);
+ string_list_append(&suite.tests, progpath.buf);
continue;
}
for (i = 0; i < argc; i++)
if (!wildmatch(argv[i], p, 0)) {
- string_list_append(&suite.tests, p);
+ strbuf_setlen(&progpath, path_prefix_len);
+ strbuf_addstr(&progpath, p);
+ string_list_append(&suite.tests, progpath.buf);
break;
}
}
@@ -208,6 +223,7 @@ static int testsuite(int argc, const char **argv)
string_list_clear(&suite.tests, 0);
string_list_clear(&suite.failed, 0);
+ strbuf_release(&progpath);
return ret;
}
diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
index 0a816a96e2..64fff6e9e3 100644
--- a/t/helper/test-scrap-cache-tree.c
+++ b/t/helper/test-scrap-cache-tree.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "lockfile.h"
#include "read-cache-ll.h"
@@ -15,9 +16,9 @@ int cmd__scrap_cache_tree(int ac UNUSED, const char **av UNUSED)
repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
if (repo_read_index(the_repository) < 0)
die("unable to read index file");
- cache_tree_free(&the_index.cache_tree);
- the_index.cache_tree = NULL;
- if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
+ cache_tree_free(&the_repository->index->cache_tree);
+ the_repository->index->cache_tree = NULL;
+ if (write_locked_index(the_repository->index, &index_lock, COMMIT_LOCK))
die("unable to write index file");
return 0;
}
diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c
index dcb7f6c003..e60d000c03 100644
--- a/t/helper/test-sha1.c
+++ b/t/helper/test-sha1.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "hash-ll.h"
+#include "hash.h"
int cmd__sha1(int ac, const char **av)
{
diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c
index 08cf149001..2fb20438f3 100644
--- a/t/helper/test-sha256.c
+++ b/t/helper/test-sha256.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "hash-ll.h"
+#include "hash.h"
int cmd__sha256(int ac, const char **av)
{
diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c
index 3d1436da59..fb5927775d 100644
--- a/t/helper/test-simple-ipc.c
+++ b/t/helper/test-simple-ipc.c
@@ -4,7 +4,6 @@
#include "test-tool.h"
#include "gettext.h"
-#include "strbuf.h"
#include "simple-ipc.h"
#include "parse-options.h"
#include "thread-utils.h"
@@ -278,7 +277,8 @@ static int daemon__run_server(void)
static start_bg_wait_cb bg_wait_cb;
-static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+ void *cb_data UNUSED)
{
int s = ipc_get_active_state(cl_args.path);
diff --git a/t/helper/test-strcmp-offset.c b/t/helper/test-strcmp-offset.c
deleted file mode 100644
index d8473cf2fc..0000000000
--- a/t/helper/test-strcmp-offset.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "test-tool.h"
-#include "read-cache-ll.h"
-
-int cmd__strcmp_offset(int argc UNUSED, const char **argv)
-{
- int result;
- size_t offset;
-
- if (!argv[1] || !argv[2])
- die("usage: %s <string1> <string2>", argv[0]);
-
- result = strcmp_offset(argv[1], argv[2], &offset);
-
- /*
- * Because different CRTs behave differently, only rely on signs
- * of the result values.
- */
- result = (result < 0 ? -1 :
- result > 0 ? 1 :
- 0);
- printf("%d %"PRIuMAX"\n", result, (uintmax_t)offset);
- return 0;
-}
diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c
index 9df2f03ac8..cbe93f2f9e 100644
--- a/t/helper/test-submodule-config.c
+++ b/t/helper/test-submodule-config.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "config.h"
#include "hash.h"
@@ -44,7 +46,7 @@ int cmd__submodule_config(int argc, const char **argv)
path_or_name = arg[1];
if (commit[0] == '\0')
- oidclr(&commit_oid);
+ oidclr(&commit_oid, the_repository->hash_algo);
else if (repo_get_oid(the_repository, commit, &commit_oid) < 0)
die_usage(argc, argv, "Commit not found.");
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
index ecd40ded99..6dce957153 100644
--- a/t/helper/test-submodule-nested-repo-config.c
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "repository.h"
#include "setup.h"
@@ -27,6 +29,6 @@ int cmd__submodule_nested_repo_config(int argc, const char **argv)
print_config_from_gitmodules(&subrepo, argv[2]);
submodule_free(the_repository);
-
+ repo_clear(&subrepo);
return 0;
}
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
index 356e0a26c5..22e518d229 100644
--- a/t/helper/test-submodule.c
+++ b/t/helper/test-submodule.c
@@ -1,19 +1,29 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "test-tool-utils.h"
#include "parse-options.h"
#include "remote.h"
#include "repository.h"
#include "setup.h"
+#include "strbuf.h"
#include "submodule-config.h"
#include "submodule.h"
#define TEST_TOOL_CHECK_NAME_USAGE \
- "test-tool submodule check-name <name>"
+ "test-tool submodule check-name"
static const char *submodule_check_name_usage[] = {
TEST_TOOL_CHECK_NAME_USAGE,
NULL
};
+#define TEST_TOOL_CHECK_URL_USAGE \
+ "test-tool submodule check-url"
+static const char *submodule_check_url_usage[] = {
+ TEST_TOOL_CHECK_URL_USAGE,
+ NULL
+};
+
#define TEST_TOOL_IS_ACTIVE_USAGE \
"test-tool submodule is-active <name>"
static const char *submodule_is_active_usage[] = {
@@ -30,31 +40,26 @@ static const char *submodule_resolve_relative_url_usage[] = {
static const char *submodule_usage[] = {
TEST_TOOL_CHECK_NAME_USAGE,
+ TEST_TOOL_CHECK_URL_USAGE,
TEST_TOOL_IS_ACTIVE_USAGE,
TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,
NULL
};
+typedef int (*check_fn_t)(const char *);
+
/*
- * Exit non-zero if any of the submodule names given on the command line is
- * invalid. If no names are given, filter stdin to print only valid names
- * (which is primarily intended for testing).
+ * Apply 'check_fn' to each line of stdin, printing values that pass the check
+ * to stdout.
*/
-static int check_name(int argc, const char **argv)
+static int check_submodule(check_fn_t check_fn)
{
- if (argc > 1) {
- while (*++argv) {
- if (check_submodule_name(*argv) < 0)
- return 1;
- }
- } else {
- struct strbuf buf = STRBUF_INIT;
- while (strbuf_getline(&buf, stdin) != EOF) {
- if (!check_submodule_name(buf.buf))
- printf("%s\n", buf.buf);
- }
- strbuf_release(&buf);
+ struct strbuf buf = STRBUF_INIT;
+ while (strbuf_getline(&buf, stdin) != EOF) {
+ if (!check_fn(buf.buf))
+ printf("%s\n", buf.buf);
}
+ strbuf_release(&buf);
return 0;
}
@@ -68,7 +73,20 @@ static int cmd__submodule_check_name(int argc, const char **argv)
if (argc)
usage_with_options(submodule_check_name_usage, options);
- return check_name(argc, argv);
+ return check_submodule(check_submodule_name);
+}
+
+static int cmd__submodule_check_url(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, "test-tools", options,
+ submodule_check_url_usage, 0);
+ if (argc)
+ usage_with_options(submodule_check_url_usage, options);
+
+ return check_submodule(check_submodule_url);
}
static int cmd__submodule_is_active(int argc, const char **argv)
@@ -194,6 +212,7 @@ static int cmd__submodule_config_writeable(int argc, const char **argv UNUSED)
static struct test_cmd cmds[] = {
{ "check-name", cmd__submodule_check_name },
+ { "check-url", cmd__submodule_check_url },
{ "is-active", cmd__submodule_is_active },
{ "resolve-relative-url", cmd__submodule_resolve_relative_url},
{ "config-list", cmd__submodule_config_list },
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index abe8a785eb..1ebb69a5dc 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -19,18 +19,19 @@ static struct test_cmd cmds[] = {
{ "config", cmd__config },
{ "crontab", cmd__crontab },
{ "csprng", cmd__csprng },
- { "ctype", cmd__ctype },
{ "date", cmd__date },
+ { "delete-gpgsig", cmd__delete_gpgsig },
{ "delta", cmd__delta },
{ "dir-iterator", cmd__dir_iterator },
{ "drop-caches", cmd__drop_caches },
{ "dump-cache-tree", cmd__dump_cache_tree },
{ "dump-fsmonitor", cmd__dump_fsmonitor },
+ { "dump-reftable", cmd__dump_reftable },
{ "dump-split-index", cmd__dump_split_index },
{ "dump-untracked-cache", cmd__dump_untracked_cache },
{ "env-helper", cmd__env_helper },
- { "example-decorate", cmd__example_decorate },
- { "fast-rebase", cmd__fast_rebase },
+ { "example-tap", cmd__example_tap },
+ { "find-pack", cmd__find_pack },
{ "fsmonitor-client", cmd__fsmonitor_client },
{ "genrandom", cmd__genrandom },
{ "genzeros", cmd__genzeros },
@@ -38,15 +39,11 @@ static struct test_cmd cmds[] = {
{ "hashmap", cmd__hashmap },
{ "hash-speed", cmd__hash_speed },
{ "hexdump", cmd__hexdump },
- { "index-version", cmd__index_version },
{ "json-writer", cmd__json_writer },
{ "lazy-init-name-hash", cmd__lazy_init_name_hash },
{ "match-trees", cmd__match_trees },
{ "mergesort", cmd__mergesort },
{ "mktemp", cmd__mktemp },
- { "oid-array", cmd__oid_array },
- { "oidmap", cmd__oidmap },
- { "oidtree", cmd__oidtree },
{ "online-cpus", cmd__online_cpus },
{ "pack-mtimes", cmd__pack_mtimes },
{ "parse-options", cmd__parse_options },
@@ -57,7 +54,6 @@ static struct test_cmd cmds[] = {
{ "path-utils", cmd__path_utils },
{ "pcre2-config", cmd__pcre2_config },
{ "pkt-line", cmd__pkt_line },
- { "prio-queue", cmd__prio_queue },
{ "proc-receive", cmd__proc_receive },
{ "progress", cmd__progress },
{ "reach", cmd__reach },
@@ -65,9 +61,7 @@ static struct test_cmd cmds[] = {
{ "read-graph", cmd__read_graph },
{ "read-midx", cmd__read_midx },
{ "ref-store", cmd__ref_store },
- { "reftable", cmd__reftable },
{ "rot13-filter", cmd__rot13_filter },
- { "dump-reftable", cmd__dump_reftable },
{ "regex", cmd__regex },
{ "repository", cmd__repository },
{ "revision-walking", cmd__revision_walking },
@@ -79,15 +73,14 @@ static struct test_cmd cmds[] = {
{ "sha256", cmd__sha256 },
{ "sigchain", cmd__sigchain },
{ "simple-ipc", cmd__simple_ipc },
- { "strcmp-offset", cmd__strcmp_offset },
{ "string-list", cmd__string_list },
{ "submodule", cmd__submodule },
{ "submodule-config", cmd__submodule_config },
{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
{ "subprocess", cmd__subprocess },
{ "trace2", cmd__trace2 },
+ { "truncate", cmd__truncate },
{ "userdiff", cmd__userdiff },
- { "urlmatch-normalization", cmd__urlmatch_normalization },
{ "xml-encode", cmd__xml_encode },
{ "wildmatch", cmd__wildmatch },
#ifdef GIT_WINDOWS_NATIVE
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index ea2672436c..21802ac27d 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -12,9 +12,9 @@ int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
int cmd__crontab(int argc, const char **argv);
int cmd__csprng(int argc, const char **argv);
-int cmd__ctype(int argc, const char **argv);
int cmd__date(int argc, const char **argv);
int cmd__delta(int argc, const char **argv);
+int cmd__delete_gpgsig(int argc, const char **argv);
int cmd__dir_iterator(int argc, const char **argv);
int cmd__drop_caches(int argc, const char **argv);
int cmd__dump_cache_tree(int argc, const char **argv);
@@ -23,8 +23,8 @@ int cmd__dump_split_index(int argc, const char **argv);
int cmd__dump_untracked_cache(int argc, const char **argv);
int cmd__dump_reftable(int argc, const char **argv);
int cmd__env_helper(int argc, const char **argv);
-int cmd__example_decorate(int argc, const char **argv);
-int cmd__fast_rebase(int argc, const char **argv);
+int cmd__example_tap(int argc, const char **argv);
+int cmd__find_pack(int argc, const char **argv);
int cmd__fsmonitor_client(int argc, const char **argv);
int cmd__genrandom(int argc, const char **argv);
int cmd__genzeros(int argc, const char **argv);
@@ -32,14 +32,11 @@ int cmd__getcwd(int argc, const char **argv);
int cmd__hashmap(int argc, const char **argv);
int cmd__hash_speed(int argc, const char **argv);
int cmd__hexdump(int argc, const char **argv);
-int cmd__index_version(int argc, const char **argv);
int cmd__json_writer(int argc, const char **argv);
int cmd__lazy_init_name_hash(int argc, const char **argv);
int cmd__match_trees(int argc, const char **argv);
int cmd__mergesort(int argc, const char **argv);
int cmd__mktemp(int argc, const char **argv);
-int cmd__oidmap(int argc, const char **argv);
-int cmd__oidtree(int argc, const char **argv);
int cmd__online_cpus(int argc, const char **argv);
int cmd__pack_mtimes(int argc, const char **argv);
int cmd__parse_options(int argc, const char **argv);
@@ -50,7 +47,6 @@ int cmd__partial_clone(int argc, const char **argv);
int cmd__path_utils(int argc, const char **argv);
int cmd__pcre2_config(int argc, const char **argv);
int cmd__pkt_line(int argc, const char **argv);
-int cmd__prio_queue(int argc, const char **argv);
int cmd__proc_receive(int argc, const char **argv);
int cmd__progress(int argc, const char **argv);
int cmd__reach(int argc, const char **argv);
@@ -59,7 +55,6 @@ int cmd__read_graph(int argc, const char **argv);
int cmd__read_midx(int argc, const char **argv);
int cmd__ref_store(int argc, const char **argv);
int cmd__rot13_filter(int argc, const char **argv);
-int cmd__reftable(int argc, const char **argv);
int cmd__regex(int argc, const char **argv);
int cmd__repository(int argc, const char **argv);
int cmd__revision_walking(int argc, const char **argv);
@@ -68,19 +63,17 @@ int cmd__scrap_cache_tree(int argc, const char **argv);
int cmd__serve_v2(int argc, const char **argv);
int cmd__sha1(int argc, const char **argv);
int cmd__sha1_is_sha1dc(int argc, const char **argv);
-int cmd__oid_array(int argc, const char **argv);
int cmd__sha256(int argc, const char **argv);
int cmd__sigchain(int argc, const char **argv);
int cmd__simple_ipc(int argc, const char **argv);
-int cmd__strcmp_offset(int argc, const char **argv);
int cmd__string_list(int argc, const char **argv);
int cmd__submodule(int argc, const char **argv);
int cmd__submodule_config(int argc, const char **argv);
int cmd__submodule_nested_repo_config(int argc, const char **argv);
int cmd__subprocess(int argc, const char **argv);
int cmd__trace2(int argc, const char **argv);
+int cmd__truncate(int argc, const char **argv);
int cmd__userdiff(int argc, const char **argv);
-int cmd__urlmatch_normalization(int argc, const char **argv);
int cmd__xml_encode(int argc, const char **argv);
int cmd__wildmatch(int argc, const char **argv);
#ifdef GIT_WINDOWS_NATIVE
diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c
index 20c7495f38..c588c273ce 100644
--- a/t/helper/test-trace2.c
+++ b/t/helper/test-trace2.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "strvec.h"
#include "run-command.h"
@@ -24,6 +26,7 @@ static int get_i(int *p_value, const char *data)
if (!data || !*data)
return MyError;
+ errno = 0;
*p_value = strtol(data, &endptr, 10);
if (*endptr || errno == ERANGE)
return MyError;
@@ -45,7 +48,7 @@ static int get_i(int *p_value, const char *data)
* [] "def_param" events for all of the "interesting" pre-defined
* config settings.
*/
-static int ut_001return(int argc, const char **argv)
+static int ut_001return(int argc UNUSED, const char **argv)
{
int rc;
@@ -65,7 +68,7 @@ static int ut_001return(int argc, const char **argv)
* [] "def_param" events for all of the "interesting" pre-defined
* config settings.
*/
-static int ut_002exit(int argc, const char **argv)
+static int ut_002exit(int argc UNUSED, const char **argv)
{
int rc;
@@ -201,7 +204,7 @@ static int ut_006data(int argc, const char **argv)
return 0;
}
-static int ut_007BUG(int argc, const char **argv)
+static int ut_007BUG(int argc UNUSED, const char **argv UNUSED)
{
/*
* Exercise BUG() to ensure that the message is printed to trace2.
@@ -412,6 +415,56 @@ static int ut_201counter(int argc, const char **argv)
return 0;
}
+static int ut_300redact_start(int argc, const char **argv)
+{
+ if (!argc)
+ die("expect <argv...>");
+
+ trace2_cmd_start(argv);
+
+ return 0;
+}
+
+static int ut_301redact_child_start(int argc, const char **argv)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ int k;
+
+ if (!argc)
+ die("expect <argv...>");
+
+ for (k = 0; argv[k]; k++)
+ strvec_push(&cmd.args, argv[k]);
+
+ trace2_child_start(&cmd);
+
+ strvec_clear(&cmd.args);
+
+ return 0;
+}
+
+static int ut_302redact_exec(int argc, const char **argv)
+{
+ if (!argc)
+ die("expect <exe> <argv...>");
+
+ trace2_exec(argv[0], &argv[1]);
+
+ return 0;
+}
+
+static int ut_303redact_def_param(int argc, const char **argv)
+{
+ struct key_value_info kvi = KVI_INIT;
+
+ if (argc < 2)
+ die("expect <key> <value>");
+
+ trace2_def_param(argv[0], argv[1], &kvi);
+
+ return 0;
+}
+
/*
* Usage:
* test-tool trace2 <ut_name_1> <ut_usage_1>
@@ -438,6 +491,11 @@ static struct unit_test ut_table[] = {
{ ut_200counter, "200counter", "<v1> [<v2> [<v3> [...]]]" },
{ ut_201counter, "201counter", "<v1> <v2> <threads>" },
+
+ { ut_300redact_start, "300redact_start", "<argv...>" },
+ { ut_301redact_child_start, "301redact_child_start", "<argv...>" },
+ { ut_302redact_exec, "302redact_exec", "<exe> <argv...>" },
+ { ut_303redact_def_param, "303redact_def_param", "<key> <value>" },
};
/* clang-format on */
diff --git a/t/helper/test-truncate.c b/t/helper/test-truncate.c
new file mode 100644
index 0000000000..3931deaec7
--- /dev/null
+++ b/t/helper/test-truncate.c
@@ -0,0 +1,25 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+
+/*
+ * Truncate a file to the given size.
+ */
+int cmd__truncate(int argc, const char **argv)
+{
+ char *p = NULL;
+ uintmax_t sz = 0;
+ int fd = -1;
+
+ if (argc != 3)
+ die("expected filename and size");
+
+ sz = strtoumax(argv[2], &p, 0);
+ if (*p)
+ die("invalid size");
+
+ fd = xopen(argv[1], O_WRONLY | O_CREAT, 0600);
+
+ if (ftruncate(fd, (off_t) sz) < 0)
+ die_errno("failed to truncate file");
+ return 0;
+}
diff --git a/t/helper/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c
deleted file mode 100644
index 86edd454f5..0000000000
--- a/t/helper/test-urlmatch-normalization.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "test-tool.h"
-#include "git-compat-util.h"
-#include "urlmatch.h"
-
-int cmd__urlmatch_normalization(int argc, const char **argv)
-{
- const char usage[] = "test-tool urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
- char *url1 = NULL, *url2 = NULL;
- int opt_p = 0, opt_l = 0;
- int ret = 0;
-
- /*
- * For one url, succeed if url_normalize succeeds on it, fail otherwise.
- * For two urls, succeed only if url_normalize succeeds on both and
- * the results compare equal with strcmp. If -p is given (one url only)
- * and url_normalize succeeds, print the result followed by "\n". If
- * -l is given (one url only) and url_normalize succeeds, print the
- * returned length in decimal followed by "\n".
- */
-
- if (argc > 1 && !strcmp(argv[1], "-p")) {
- opt_p = 1;
- argc--;
- argv++;
- } else if (argc > 1 && !strcmp(argv[1], "-l")) {
- opt_l = 1;
- argc--;
- argv++;
- }
-
- if (argc < 2 || argc > 3)
- die("%s", usage);
-
- if (argc == 2) {
- struct url_info info;
- url1 = url_normalize(argv[1], &info);
- if (!url1)
- return 1;
- if (opt_p)
- printf("%s\n", url1);
- if (opt_l)
- printf("%u\n", (unsigned)info.url_len);
- goto cleanup;
- }
-
- if (opt_p || opt_l)
- die("%s", usage);
-
- url1 = url_normalize(argv[1], NULL);
- url2 = url_normalize(argv[2], NULL);
- ret = (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
-cleanup:
- free(url1);
- free(url2);
- return ret;
-}
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
index 0ce31ce59f..94c48ababb 100644
--- a/t/helper/test-userdiff.c
+++ b/t/helper/test-userdiff.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "setup.h"
#include "userdiff.h"
diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c
index f084034d38..b37dd2c5d6 100644
--- a/t/helper/test-write-cache.c
+++ b/t/helper/test-write-cache.c
@@ -1,4 +1,5 @@
-#define USE_THE_INDEX_VARIABLE
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "lockfile.h"
#include "read-cache-ll.h"
@@ -16,7 +17,7 @@ int cmd__write_cache(int argc, const char **argv)
for (i = 0; i < cnt; i++) {
repo_hold_locked_index(the_repository, &index_lock,
LOCK_DIE_ON_ERROR);
- if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
+ if (write_locked_index(the_repository->index, &index_lock, COMMIT_LOCK))
die("unable to write index file");
}
diff --git a/t/interop/README b/t/interop/README
index 72d42bd856..4e0608f857 100644
--- a/t/interop/README
+++ b/t/interop/README
@@ -83,3 +83,10 @@ You can then use test_expect_success as usual, with a few differences:
should create one with the appropriate version of git.
At the end of the script, call test_done as usual.
+
+Some older versions may need a few build knobs tweaked (e.g., ancient
+versions of Git no longer build with modern OpenSSL). Your script can
+set MAKE_OPTS_A and MAKE_OPTS_B, which will be passed alongside
+GIT_INTEROP_MAKE_OPTS. Users can override them per-script by setting
+GIT_INTEROP_MAKE_OPTS_{A,B} in the environment, just like they can set
+GIT_TEST_VERSION_{A,B}.
diff --git a/t/interop/i5500-git-daemon.sh b/t/interop/i5500-git-daemon.sh
index 4d22e42f84..88712d1b5d 100755
--- a/t/interop/i5500-git-daemon.sh
+++ b/t/interop/i5500-git-daemon.sh
@@ -2,6 +2,7 @@
VERSION_A=.
VERSION_B=v1.0.0
+MAKE_OPTS_B="NO_OPENSSL=TooOld"
: ${LIB_GIT_DAEMON_PORT:=5500}
LIB_GIT_DAEMON_COMMAND='git.a daemon'
diff --git a/t/interop/interop-lib.sh b/t/interop/interop-lib.sh
index 62f4481b6e..1b5864d2a7 100644
--- a/t/interop/interop-lib.sh
+++ b/t/interop/interop-lib.sh
@@ -45,7 +45,7 @@ build_version () {
(
cd "$dir" &&
- make $GIT_INTEROP_MAKE_OPTS >&2 &&
+ make $2 $GIT_INTEROP_MAKE_OPTS >&2 &&
touch .built
) || return 1
@@ -76,9 +76,11 @@ generate_wrappers () {
VERSION_A=${GIT_TEST_VERSION_A:-$VERSION_A}
VERSION_B=${GIT_TEST_VERSION_B:-$VERSION_B}
+MAKE_OPTS_A=${GIT_INTEROP_MAKE_OPTS_A:-$MAKE_OPTS_A}
+MAKE_OPTS_B=${GIT_INTEROP_MAKE_OPTS_B:-$MAKE_OPTS_B}
-if ! DIR_A=$(build_version "$VERSION_A") ||
- ! DIR_B=$(build_version "$VERSION_B")
+if ! DIR_A=$(build_version "$VERSION_A" "$MAKE_OPTS_A") ||
+ ! DIR_B=$(build_version "$VERSION_B" "$MAKE_OPTS_B")
then
echo >&2 "fatal: unable to build git versions"
exit 1
diff --git a/t/lib-bitmap.sh b/t/lib-bitmap.sh
index f595937094..62aa6744a6 100644
--- a/t/lib-bitmap.sh
+++ b/t/lib-bitmap.sh
@@ -1,6 +1,8 @@
# Helpers for scripts testing bitmap functionality; see t5310 for
# example usage.
+. "$TEST_DIRECTORY"/lib-midx.sh
+
objdir=.git/objects
midx=$objdir/pack/multi-pack-index
@@ -264,10 +266,6 @@ have_delta () {
test_cmp expect actual
}
-midx_checksum () {
- test-tool read-midx --checksum "$1"
-}
-
# midx_pack_source <obj>
midx_pack_source () {
test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh
index a4a1af8d02..de09b6b02e 100644
--- a/t/lib-bundle-uri-protocol.sh
+++ b/t/lib-bundle-uri-protocol.sh
@@ -18,7 +18,7 @@ git)
start_git_daemon --export-all --enable=receive-pack
BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent"
BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent"
- BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+ BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl"
test_set_prereq BUNDLE_URI_GIT
;;
http)
@@ -26,7 +26,7 @@ http)
start_httpd
BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent"
BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent"
- BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+ BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URL/fake.bdl"
test_set_prereq BUNDLE_URI_HTTP
;;
*)
diff --git a/t/lib-bundle.sh b/t/lib-bundle.sh
index cf7ed818b2..62b7bb13c8 100644
--- a/t/lib-bundle.sh
+++ b/t/lib-bundle.sh
@@ -11,7 +11,7 @@ convert_bundle_to_pack () {
}
# Check count of objects in a bundle file.
-# We can use "--thin" opiton to check thin pack, which must be fixed by
+# We can use "--thin" option to check thin pack, which must be fixed by
# command `git-index-pack --fix-thin --stdin`.
test_bundle_object_count () {
thin=
diff --git a/t/lib-chunk.sh b/t/lib-chunk.sh
new file mode 100644
index 0000000000..9f01df190b
--- /dev/null
+++ b/t/lib-chunk.sh
@@ -0,0 +1,18 @@
+# Shell library for working with "chunk" files (commit-graph, midx, etc).
+
+# corrupt_chunk_file <fn> <chunk> <offset> <bytes>
+#
+# Corrupt a chunk-based file (like a commit-graph) by overwriting the bytes
+# found in the chunk specified by the 4-byte <chunk> identifier. If <offset> is
+# "clear", replace the chunk entirely. Otherwise, overwrite data <offset> bytes
+# into the chunk.
+#
+# The <bytes> are interpreted as pairs of hex digits (so "000000FE" would be
+# big-endian 254).
+corrupt_chunk_file () {
+ fn=$1; shift
+ perl "$TEST_DIRECTORY"/lib-chunk/corrupt-chunk-file.pl \
+ "$@" <"$fn" >"$fn.tmp" &&
+ # some vintages of macOS 'mv' fails to overwrite a read-only file.
+ mv -f "$fn.tmp" "$fn"
+}
diff --git a/t/lib-chunk/corrupt-chunk-file.pl b/t/lib-chunk/corrupt-chunk-file.pl
new file mode 100644
index 0000000000..0e11aadda8
--- /dev/null
+++ b/t/lib-chunk/corrupt-chunk-file.pl
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+
+my ($chunk, $seek, $bytes) = @ARGV;
+$bytes =~ s/../chr(hex($&))/ge;
+
+binmode STDIN;
+binmode STDOUT;
+
+# A few helpers to read bytes, or read and copy them to the
+# output.
+sub get {
+ my $n = shift;
+ return unless $n;
+ read(STDIN, my $buf, $n)
+ or die "read error or eof: $!\n";
+ return $buf;
+}
+sub copy {
+ my $buf = get(@_);
+ print $buf;
+ return $buf;
+}
+
+# Some platforms' perl builds don't support 64-bit integers, and hence do not
+# allow packing/unpacking quadwords with "Q". The chunk format uses 64-bit file
+# offsets to support files of any size, but in practice our test suite will
+# only use small files. So we can fake it by asking for two 32-bit values and
+# discarding the first (most significant) one, which is equivalent as long as
+# it's just zero.
+sub unpack_quad {
+ my $bytes = shift;
+ my ($n1, $n2) = unpack("NN", $bytes);
+ die "quad value exceeds 32 bits" if $n1;
+ return $n2;
+}
+sub pack_quad {
+ my $n = shift;
+ my $ret = pack("NN", 0, $n);
+ # double check that our original $n did not exceed the 32-bit limit.
+ # This is presumably impossible on a 32-bit system (which would have
+ # truncated much earlier), but would still alert us on a 64-bit build
+ # of a new test that would fail on a 32-bit build (though we'd
+ # presumably see the die() from unpack_quad() in such a case).
+ die "quad round-trip failed" if unpack_quad($ret) != $n;
+ return $ret;
+}
+
+# read until we find table-of-contents entry for chunk;
+# note that we cheat a bit by assuming 4-byte alignment and
+# that no ToC entry will accidentally look like a header.
+#
+# If we don't find the entry, copy() will hit EOF and exit
+# (which should cause the caller to fail the test).
+while (copy(4) ne $chunk) { }
+my $offset = unpack_quad(copy(8));
+
+# In clear mode, our length will change. So figure out
+# the length by comparing to the offset of the next chunk, and
+# then adjust that offset (and all subsequent) ones.
+my $len;
+if ($seek eq "clear") {
+ my $id;
+ do {
+ $id = copy(4);
+ my $next = unpack_quad(get(8));
+ if (!defined $len) {
+ $len = $next - $offset;
+ }
+ print pack_quad($next - $len + length($bytes));
+ } while (unpack("N", $id));
+}
+
+# and now copy up to our existing chunk data
+copy($offset - tell(STDIN));
+if ($seek eq "clear") {
+ # if clearing, skip past existing data
+ get($len);
+} else {
+ # otherwise, copy up to the requested offset,
+ # and skip past the overwritten bytes
+ copy($seek);
+ get(length($bytes));
+}
+
+# now write out the requested bytes, along
+# with any other remaining data
+print $bytes;
+while (read(STDIN, my $buf, 4096)) {
+ print $buf;
+}
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 032b2d8fcc..58b9c74060 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -43,11 +43,14 @@ helper_test_clean() {
reject $1 https example.com store-user
reject $1 https example.com user1
reject $1 https example.com user2
+ reject $1 https example.com user-expiry
+ reject $1 https example.com user-expiry-overwrite
reject $1 https example.com user4
reject $1 https example.com user-distinct-pass
reject $1 https example.com user-overwrite
reject $1 https example.com user-erase1
reject $1 https example.com user-erase2
+ reject $1 https victim.example.com user
reject $1 http path.tld user
reject $1 https timeout.tld user
reject $1 https sso.tld
@@ -431,6 +434,81 @@ helper_test_timeout() {
'
}
+helper_test_password_expiry_utc() {
+ HELPER=$1
+
+ test_expect_success "helper ($HELPER) stores password_expiry_utc" '
+ check approve $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user-expiry
+ password=pass
+ password_expiry_utc=9999999999
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) gets password_expiry_utc" '
+ check fill $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user-expiry
+ --
+ protocol=https
+ host=example.com
+ username=user-expiry
+ password=pass
+ password_expiry_utc=9999999999
+ --
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) overwrites when password_expiry_utc changes" '
+ check approve $HELPER <<-\EOF &&
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ password=pass1
+ password_expiry_utc=9999999998
+ EOF
+ check approve $HELPER <<-\EOF &&
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ password=pass2
+ password_expiry_utc=9999999999
+ EOF
+ check fill $HELPER <<-\EOF &&
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ --
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ password=pass2
+ password_expiry_utc=9999999999
+ EOF
+ check reject $HELPER <<-\EOF &&
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ password=pass2
+ EOF
+ check fill $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ --
+ protocol=https
+ host=example.com
+ username=user-expiry-overwrite
+ password=askpass-password
+ --
+ askpass: Password for '\''https://user-expiry-overwrite@example.com'\'':
+ EOF
+ '
+}
+
helper_test_oauth_refresh_token() {
HELPER=$1
@@ -460,6 +538,129 @@ helper_test_oauth_refresh_token() {
'
}
+helper_test_authtype() {
+ HELPER=$1
+
+ test_expect_success "helper ($HELPER) stores authtype and credential" '
+ check approve $HELPER <<-\EOF
+ capability[]=authtype
+ authtype=Bearer
+ credential=random-token
+ protocol=https
+ host=git.example.com
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) gets authtype and credential" '
+ check fill $HELPER <<-\EOF
+ capability[]=authtype
+ protocol=https
+ host=git.example.com
+ --
+ capability[]=authtype
+ authtype=Bearer
+ credential=random-token
+ protocol=https
+ host=git.example.com
+ --
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) stores authtype and credential with username" '
+ check approve $HELPER <<-\EOF
+ capability[]=authtype
+ authtype=Bearer
+ credential=other-token
+ protocol=https
+ host=git.example.com
+ username=foobar
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) gets authtype and credential with username" '
+ check fill $HELPER <<-\EOF
+ capability[]=authtype
+ protocol=https
+ host=git.example.com
+ username=foobar
+ --
+ capability[]=authtype
+ authtype=Bearer
+ credential=other-token
+ protocol=https
+ host=git.example.com
+ username=foobar
+ --
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) does not get authtype and credential with different username" '
+ check fill $HELPER <<-\EOF
+ capability[]=authtype
+ protocol=https
+ host=git.example.com
+ username=barbaz
+ --
+ protocol=https
+ host=git.example.com
+ username=barbaz
+ password=askpass-password
+ --
+ askpass: Password for '\''https://barbaz@git.example.com'\'':
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) does not store ephemeral authtype and credential" '
+ check approve $HELPER <<-\EOF &&
+ capability[]=authtype
+ authtype=Bearer
+ credential=git2-token
+ protocol=https
+ host=git2.example.com
+ ephemeral=1
+ EOF
+
+ check fill $HELPER <<-\EOF
+ capability[]=authtype
+ protocol=https
+ host=git2.example.com
+ --
+ protocol=https
+ host=git2.example.com
+ username=askpass-username
+ password=askpass-password
+ --
+ askpass: Username for '\''https://git2.example.com'\'':
+ askpass: Password for '\''https://askpass-username@git2.example.com'\'':
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) does not store ephemeral username and password" '
+ check approve $HELPER <<-\EOF &&
+ capability[]=authtype
+ protocol=https
+ host=git2.example.com
+ user=barbaz
+ password=secret
+ ephemeral=1
+ EOF
+
+ check fill $HELPER <<-\EOF
+ capability[]=authtype
+ protocol=https
+ host=git2.example.com
+ --
+ protocol=https
+ host=git2.example.com
+ username=askpass-username
+ password=askpass-password
+ --
+ askpass: Username for '\''https://git2.example.com'\'':
+ askpass: Password for '\''https://askpass-username@git2.example.com'\'':
+ EOF
+ '
+}
+
write_script askpass <<\EOF
echo >&2 askpass: $*
what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z)
diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh
index 32b3473379..57b9b2db9b 100644
--- a/t/lib-cvs.sh
+++ b/t/lib-cvs.sh
@@ -71,8 +71,8 @@ test_cmp_branch_tree () {
find . -type d -name .git -prune -o -type f -print
) | sort >module-git-"$1".list &&
test_cmp module-cvs-"$1".list module-git-"$1".list &&
- cat module-cvs-"$1".list | while read f
+ while read f
do
test_cmp_branch_file "$1" "$f" || return 1
- done
+ done <module-cvs-"$1".list
}
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index ea28971e8e..2fde2353fd 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -1,7 +1,3 @@
-if test -z "$TEST_FAILS_SANITIZE_LEAK"
-then
- TEST_PASSES_SANITIZE_LEAK=true
-fi
. ./test-lib.sh
if test -n "$NO_SVN_TESTS"
diff --git a/t/lib-gitweb.sh b/t/lib-gitweb.sh
index 1f32ca66ea..7f9808ec20 100644
--- a/t/lib-gitweb.sh
+++ b/t/lib-gitweb.sh
@@ -48,8 +48,8 @@ EOF
test -f "$SCRIPT_NAME" ||
error "Cannot find gitweb at $GITWEB_TEST_INSTALLED."
say "# Testing $SCRIPT_NAME"
- else # normal case, use source version of gitweb
- SCRIPT_NAME="$GIT_BUILD_DIR/gitweb/gitweb.perl"
+ else # normal case, use built version of gitweb
+ SCRIPT_NAME="$GIT_BUILD_DIR/gitweb/gitweb.cgi"
fi
export SCRIPT_NAME
}
diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index 83b83c9abb..3845b6ac44 100644
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -6,14 +6,14 @@
# executed in an eval'ed subshell that changes the working directory to a
# temporary one.
-GNUPGHOME="$PWD/gpghome"
+GNUPGHOME="$(pwd)/gpghome"
export GNUPGHOME
test_lazy_prereq GPG '
gpg_version=$(gpg --version 2>&1)
test $? != 127 || exit 1
- # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
+ # As said here: https://web.archive.org/web/20130212022238/https://www.gnupg.org/faq/gnupg-faq.html#why-does-gnupg-1.0.6-bail-out-on-keyrings-used-with-1.0.7
# the gpg version 1.0.6 did not parse trust packets correctly, so for
# that version, creation of signed tags using the generated key fails.
case "$gpg_version" in
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 2fb1b2ae56..d83bafeab3 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -55,21 +55,31 @@ fi
HTTPD_PARA=""
-for DEFAULT_HTTPD_PATH in '/usr/sbin/httpd' '/usr/sbin/apache2'
+for DEFAULT_HTTPD_PATH in '/usr/sbin/httpd' \
+ '/usr/sbin/apache2' \
+ "$(command -v httpd)" \
+ "$(command -v apache2)"
do
- if test -x "$DEFAULT_HTTPD_PATH"
+ if test -n "$DEFAULT_HTTPD_PATH" && test -x "$DEFAULT_HTTPD_PATH"
then
break
fi
done
+if test -x "$DEFAULT_HTTPD_PATH"
+then
+ DETECTED_HTTPD_ROOT="$("$DEFAULT_HTTPD_PATH" -V 2>/dev/null | sed -n 's/^ -D HTTPD_ROOT="\(.*\)"$/\1/p')"
+fi
+
for DEFAULT_HTTPD_MODULE_PATH in '/usr/libexec/apache2' \
'/usr/lib/apache2/modules' \
'/usr/lib64/httpd/modules' \
'/usr/lib/httpd/modules' \
- '/usr/libexec/httpd'
+ '/usr/libexec/httpd' \
+ '/usr/lib/apache2' \
+ "${DETECTED_HTTPD_ROOT:+${DETECTED_HTTPD_ROOT}/modules}"
do
- if test -d "$DEFAULT_HTTPD_MODULE_PATH"
+ if test -n "$DEFAULT_HTTPD_MODULE_PATH" && test -d "$DEFAULT_HTTPD_MODULE_PATH"
then
break
fi
@@ -127,6 +137,20 @@ else
"Could not identify web server at '$LIB_HTTPD_PATH'"
fi
+if test -n "$LIB_HTTPD_DAV" && test -f /etc/os-release
+then
+ case "$(grep "^ID=" /etc/os-release | cut -d= -f2-)" in
+ alpine)
+ # The WebDAV module in Alpine Linux is broken at least up to
+ # Alpine v3.16 as the default DBM driver is missing.
+ #
+ # https://gitlab.alpinelinux.org/alpine/aports/-/issues/13112
+ test_skip_or_die GIT_TEST_HTTPD \
+ "Apache WebDAV module does not have default DBM backend driver"
+ ;;
+ esac
+fi
+
install_script () {
write_script "$HTTPD_ROOT_PATH/$1" <"$TEST_PATH/$1"
}
@@ -255,7 +279,7 @@ test_http_push_nonff () {
'
test_expect_success 'non-fast-forward push shows help message' '
- test_i18ngrep "Updates were rejected because" output
+ test_grep "Updates were rejected because" output
'
test_expect_${EXPECT_CAS_RESULT} 'force with lease aka cas' '
diff --git a/t/lib-httpd/nph-custom-auth.sh b/t/lib-httpd/nph-custom-auth.sh
index f5345e775e..d408d2caad 100644
--- a/t/lib-httpd/nph-custom-auth.sh
+++ b/t/lib-httpd/nph-custom-auth.sh
@@ -19,21 +19,30 @@ CHALLENGE_FILE=custom-auth.challenge
#
if test -n "$HTTP_AUTHORIZATION" && \
- grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE"
+ grep -Fqs "creds=${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE"
then
+ idno=$(grep -F "creds=${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" | sed -e 's/^id=\([a-z0-9-][a-z0-9-]*\) .*$/\1/')
+ status=$(sed -ne "s/^id=$idno.*status=\\([0-9][0-9][0-9]\\).*\$/\\1/p" "$CHALLENGE_FILE" | head -n1)
# 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
+ echo "HTTP/1.1 $status Nonspecific Reason Phrase"
+ if test "$status" -eq 200
+ then
+ exec "$GIT_EXEC_PATH"/git-http-backend
+ else
+ sed -ne "s/^id=$idno.*response=//p" "$CHALLENGE_FILE"
+ echo
+ exit
+ fi
fi
echo 'HTTP/1.1 401 Authorization Required'
if test -f "$CHALLENGE_FILE"
then
- cat "$CHALLENGE_FILE"
+ sed -ne 's/^id=default.*response=//p' "$CHALLENGE_FILE"
fi
echo
diff --git a/t/lib-httpd/passwd b/t/lib-httpd/passwd
index 99a34d6487..d9c122f348 100644
--- a/t/lib-httpd/passwd
+++ b/t/lib-httpd/passwd
@@ -1 +1 @@
-user@host:xb4E8pqD81KQs
+user@host:$apr1$LGPmCZWj$9vxEwj5Z5GzQLBMxp3mCx1
diff --git a/t/lib-httpd/proxy-passwd b/t/lib-httpd/proxy-passwd
index 77c25138e0..2ad7705d9a 100644
--- a/t/lib-httpd/proxy-passwd
+++ b/t/lib-httpd/proxy-passwd
@@ -1 +1 @@
-proxuser:2x7tAukjAED5M
+proxuser:$apr1$RxS6MLkD$DYsqQdflheq4GPNxzJpx5.
diff --git a/t/lib-midx.sh b/t/lib-midx.sh
index 1261994744..e38c609604 100644
--- a/t/lib-midx.sh
+++ b/t/lib-midx.sh
@@ -6,3 +6,31 @@ test_midx_consistent () {
test_cmp expect actual &&
git multi-pack-index --object-dir=$1 verify
}
+
+midx_checksum () {
+ test-tool read-midx --checksum "$1"
+}
+
+midx_git_two_modes () {
+ git -c core.multiPackIndex=false $1 >expect &&
+ git -c core.multiPackIndex=true $1 >actual &&
+ if [ "$2" = "sorted" ]
+ then
+ sort <expect >expect.sorted &&
+ mv expect.sorted expect &&
+ sort <actual >actual.sorted &&
+ mv actual.sorted actual
+ fi &&
+ test_cmp expect actual
+}
+
+compare_results_with_midx () {
+ MSG=$1
+ test_expect_success "check normal git operations: $MSG" '
+ midx_git_two_modes "rev-list --objects --all" &&
+ midx_git_two_modes "log --raw" &&
+ midx_git_two_modes "count-objects --verbose" &&
+ midx_git_two_modes "cat-file --batch-all-objects --batch-check" &&
+ midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted
+ '
+}
diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh
index acaee9cbb6..8324d6c96d 100644
--- a/t/lib-parallel-checkout.sh
+++ b/t/lib-parallel-checkout.sh
@@ -20,7 +20,7 @@ test_checkout_workers () {
BUG "too few arguments to test_checkout_workers"
fi &&
- local expected_workers=$1 &&
+ local expected_workers="$1" &&
shift &&
local trace_file=trace-test-checkout-workers &&
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 7ca5b918f0..0dd764310d 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -8,18 +8,21 @@
# - check that non-commit messages have a certain line count with $EXPECT_COUNT
# - check the commit count in the commit message header with $EXPECT_HEADER_COUNT
# - rewrite a rebase -i script as directed by $FAKE_LINES.
-# $FAKE_LINES consists of a sequence of words separated by spaces.
-# The following word combinations are possible:
+# $FAKE_LINES consists of a sequence of words separated by spaces;
+# spaces inside the words are encoded as underscores.
+# The following words are possible:
#
-# "<lineno>" -- add a "pick" line with the SHA1 taken from the
-# specified line.
+# "<cmd>" -- override the command for the next line specification. Can be
+# "pick", "squash", "fixup[_-(c|C)]", "edit", "reword", "drop",
+# "merge[_-(c|C)_<rev>]", or "bad" for an invalid command.
#
-# "<cmd> <lineno>" -- add a line with the specified command
-# ("pick", "squash", "fixup"|"fixup_-C"|"fixup_-c", "edit", "reword" or "drop")
-# and the SHA1 taken from the specified line.
+# "<lineno>" -- add a command, using the specified line as a template.
+# If the command has not been overridden, the line will be copied
+# verbatim, usually resulting in a "pick" line.
#
-# "_" -- add a space, like "fixup_-C" implies "fixup -C" and
-# "exec_cmd_with_args" add an "exec cmd with args" line.
+# "fakesha" -- add a command ("pick" by default), using a fake SHA1.
+#
+# "exec_[command...]", "break" -- add the specified command.
#
# "#" -- Add a comment line.
#
@@ -49,7 +52,7 @@ set_fake_editor () {
action=\&
for line in $FAKE_LINES; do
case $line in
- pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d|label|l|reset|r|merge|m)
+ pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d|label|l|reset|t|merge|m)
action="$line";;
exec_*|x_*|break|b)
echo "$line" | sed 's/_/ /g' >> "$1";;
@@ -64,7 +67,7 @@ set_fake_editor () {
fakesha)
test \& != "$action" || action=pick
echo "$action XXXXXXX False commit" >> "$1"
- action=pick;;
+ action=\&;;
*)
sed -n "${line}s/^[a-z][a-z]*/$action/p" < "$1".tmp >> "$1"
action=\&;;
@@ -184,7 +187,7 @@ set_reword_editor () {
exit 1
fi
fi &&
- # There should be no uncommited changes
+ # There should be no uncommitted changes
git diff --exit-code HEAD &&
# The todo-list should be re-read after a reword
GIT_SEQUENCE_EDITOR="\"$PWD/reword-sequence-editor.sh\"" \
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 9acb0d5d19..36f767cb74 100644
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -830,7 +830,7 @@ test_submodule_recursing_with_args_common () {
cd submodule_update &&
git branch -t invalid_sub1 origin/invalid_sub1 &&
test_must_fail $command invalid_sub1 2>err &&
- test_i18ngrep sub1 err &&
+ test_grep sub1 err &&
test_superproject_content origin/add_sub1 &&
test_submodule_content sub1 origin/add_sub1
)
diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh
index b4d7788f4e..477e0fdc04 100644
--- a/t/lib-sudo.sh
+++ b/t/lib-sudo.sh
@@ -6,7 +6,7 @@ run_with_sudo () {
local RUN="$TEST_DIRECTORY/$$.sh"
write_script "$RUN" "$TEST_SHELL_PATH"
# avoid calling "$RUN" directly so sudo doesn't get a chance to
- # override the shell, add aditional restrictions or even reject
+ # override the shell, add additional restrictions or even reject
# running the script because its security policy deem it unsafe
sudo "$TEST_SHELL_PATH" -c "\"$RUN\""
ret=$?
diff --git a/t/lib-unicode-nfc-nfd.sh b/t/lib-unicode-nfc-nfd.sh
index 22232247ef..aed0a4dd44 100755
--- a/t/lib-unicode-nfc-nfd.sh
+++ b/t/lib-unicode-nfc-nfd.sh
@@ -74,7 +74,7 @@ test_lazy_prereq UNICODE_NFD_PRESERVED '
# Yielding: \xcf \x89 + \xcc \x94 + \xcd \x82
#
# Note that I've used the canonical ordering of the
-# combinining characters. It is also possible to
+# combining characters. It is also possible to
# swap them. My testing shows that that non-standard
# ordering also causes a collision in mkdir. However,
# the resulting names don't draw correctly on the
diff --git a/t/oid-info/hash-info b/t/oid-info/hash-info
index d0736dd1a0..b8a5bcb187 100644
--- a/t/oid-info/hash-info
+++ b/t/oid-info/hash-info
@@ -15,3 +15,15 @@ empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a3037218
empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321
+
+blob17_1 sha1:263
+blob17_1 sha256:34
+
+blob17_2 sha1:410
+blob17_2 sha256:174
+
+blob17_3 sha1:523
+blob17_3 sha256:313
+
+blob17_4 sha1:790
+blob17_4 sha256:481
diff --git a/t/perf/p1500-graph-walks.sh b/t/perf/p1500-graph-walks.sh
index e14e7620cc..5b23ce5db9 100755
--- a/t/perf/p1500-graph-walks.sh
+++ b/t/perf/p1500-graph-walks.sh
@@ -20,6 +20,21 @@ test_expect_success 'setup' '
echo tag-$ref ||
return 1
done >tags &&
+
+ echo "A:HEAD" >test-tool-refs &&
+ for line in $(cat refs)
+ do
+ echo "X:$line" >>test-tool-refs || return 1
+ done &&
+ echo "A:HEAD" >test-tool-tags &&
+ for line in $(cat tags)
+ do
+ echo "X:$line" >>test-tool-tags || return 1
+ done &&
+
+ commit=$(git commit-tree $(git rev-parse HEAD^{tree})) &&
+ git update-ref refs/heads/disjoint-base $commit &&
+
git commit-graph write --reachable
'
@@ -47,4 +62,20 @@ test_perf 'contains: git tag --merged' '
xargs git tag --merged=HEAD <tags
'
+test_perf 'is-base check: test-tool reach (refs)' '
+ test-tool reach get_branch_base_for_tip <test-tool-refs
+'
+
+test_perf 'is-base check: test-tool reach (tags)' '
+ test-tool reach get_branch_base_for_tip <test-tool-tags
+'
+
+test_perf 'is-base check: git for-each-ref' '
+ git for-each-ref --format="%(is-base:HEAD)" --stdin <refs
+'
+
+test_perf 'is-base check: git for-each-ref (disjoint-base)' '
+ git for-each-ref --format="%(is-base:refs/heads/disjoint-base)" --stdin <refs
+'
+
test_done
diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh
index 96ed3e1d69..39e92b0841 100755
--- a/t/perf/p2000-sparse-operations.sh
+++ b/t/perf/p2000-sparse-operations.sh
@@ -134,5 +134,6 @@ test_perf_on_all git diff-files -- $SPARSE_CONE/a
test_perf_on_all git diff-tree HEAD
test_perf_on_all git diff-tree HEAD -- $SPARSE_CONE/a
test_perf_on_all "git worktree add ../temp && git worktree remove ../temp"
+test_perf_on_all git check-attr -a -- $SPARSE_CONE/a
test_done
diff --git a/t/perf/p5332-multi-pack-reuse.sh b/t/perf/p5332-multi-pack-reuse.sh
new file mode 100755
index 0000000000..5c6c575d62
--- /dev/null
+++ b/t/perf/p5332-multi-pack-reuse.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+test_description='tests pack performance with multi-pack reuse'
+
+. ./perf-lib.sh
+. "${TEST_DIRECTORY}/perf/lib-pack.sh"
+
+packdir=.git/objects/pack
+
+test_perf_large_repo
+
+find_pack () {
+ for idx in $packdir/pack-*.idx
+ do
+ if git show-index <$idx | grep -q "$1"
+ then
+ basename $idx
+ fi || return 1
+ done
+}
+
+repack_into_n_chunks () {
+ git repack -adk &&
+
+ test "$1" -eq 1 && return ||
+
+ find $packdir -type f | sort >packs.before &&
+
+ # partition the repository into $1 chunks of consecutive commits, and
+ # then create $1 packs with the objects reachable from each chunk
+ # (excluding any objects reachable from the previous chunks)
+ sz="$(($(git rev-list --count --all) / $1))"
+ for rev in $(git rev-list --all | awk "NR % $sz == 0" | tac)
+ do
+ pack="$(echo "$rev" | git pack-objects --revs \
+ --honor-pack-keep --delta-base-offset $packdir/pack)" &&
+ touch $packdir/pack-$pack.keep || return 1
+ done
+
+ # grab any remaining objects not packed by the previous step(s)
+ git pack-objects --revs --all --honor-pack-keep --delta-base-offset \
+ $packdir/pack &&
+
+ find $packdir -type f | sort >packs.after &&
+
+ # and install the whole thing
+ for f in $(comm -12 packs.before packs.after)
+ do
+ rm -f "$f" || return 1
+ done
+ rm -fr $packdir/*.keep
+}
+
+for nr_packs in 1 10 100
+do
+ test_expect_success "create $nr_packs-pack scenario" '
+ repack_into_n_chunks $nr_packs
+ '
+
+ test_expect_success "setup bitmaps for $nr_packs-pack scenario" '
+ find $packdir -type f -name "*.idx" | sed -e "s/.*\/\(.*\)$/+\1/g" |
+ git multi-pack-index write --stdin-packs --bitmap \
+ --preferred-pack="$(find_pack $(git rev-parse HEAD))"
+ '
+
+ for reuse in single multi
+ do
+ test_perf "clone for $nr_packs-pack scenario ($reuse-pack reuse)" "
+ git for-each-ref --format='%(objectname)' refs/heads refs/tags >in &&
+ git -c pack.allowPackReuse=$reuse pack-objects \
+ --revs --delta-base-offset --use-bitmap-index \
+ --stdout <in >result
+ "
+
+ test_size "clone size for $nr_packs-pack scenario ($reuse-pack reuse)" '
+ wc -c <result
+ '
+ done
+done
+
+test_done
diff --git a/t/perf/p5333-pseudo-merge-bitmaps.sh b/t/perf/p5333-pseudo-merge-bitmaps.sh
new file mode 100755
index 0000000000..2e8b1d2635
--- /dev/null
+++ b/t/perf/p5333-pseudo-merge-bitmaps.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+test_description='pseudo-merge bitmaps'
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+test_expect_success 'setup' '
+ git \
+ -c bitmapPseudoMerge.all.pattern="refs/" \
+ -c bitmapPseudoMerge.all.threshold=now \
+ -c bitmapPseudoMerge.all.stableThreshold=never \
+ -c bitmapPseudoMerge.all.maxMerges=64 \
+ -c pack.writeBitmapLookupTable=true \
+ repack -adb
+'
+
+test_perf 'git rev-list --count --all --objects (no bitmaps)' '
+ git rev-list --objects --all
+'
+
+test_perf 'git rev-list --count --all --objects (no pseudo-merges)' '
+ GIT_TEST_USE_PSEUDO_MERGES=0 \
+ git rev-list --objects --all --use-bitmap-index
+'
+
+test_perf 'git rev-list --count --all --objects (with pseudo-merges)' '
+ GIT_TEST_USE_PSEUDO_MERGES=1 \
+ git rev-list --objects --all --use-bitmap-index
+'
+
+test_done
diff --git a/t/perf/p6300-for-each-ref.sh b/t/perf/p6300-for-each-ref.sh
new file mode 100755
index 0000000000..fa7289c752
--- /dev/null
+++ b/t/perf/p6300-for-each-ref.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+test_description='performance of for-each-ref'
+. ./perf-lib.sh
+
+test_perf_fresh_repo
+
+ref_count_per_type=10000
+test_iteration_count=10
+
+test_expect_success "setup" '
+ test_commit_bulk $(( 1 + $ref_count_per_type )) &&
+
+ # Create refs
+ test_seq $ref_count_per_type |
+ sed "s,.*,update refs/heads/branch_& HEAD~&\nupdate refs/custom/special_& HEAD~&," |
+ git update-ref --stdin &&
+
+ # Create annotated tags
+ for i in $(test_seq $ref_count_per_type)
+ do
+ # Base tags
+ echo "tag tag_$i" &&
+ echo "mark :$i" &&
+ echo "from HEAD~$i" &&
+ printf "tagger %s <%s> %s\n" \
+ "$GIT_COMMITTER_NAME" \
+ "$GIT_COMMITTER_EMAIL" \
+ "$GIT_COMMITTER_DATE" &&
+ echo "data <<EOF" &&
+ echo "tag $i" &&
+ echo "EOF" &&
+
+ # Nested tags
+ echo "tag nested_$i" &&
+ echo "from :$i" &&
+ printf "tagger %s <%s> %s\n" \
+ "$GIT_COMMITTER_NAME" \
+ "$GIT_COMMITTER_EMAIL" \
+ "$GIT_COMMITTER_DATE" &&
+ echo "data <<EOF" &&
+ echo "nested tag $i" &&
+ echo "EOF" || return 1
+ done | git fast-import
+'
+
+test_for_each_ref () {
+ title="for-each-ref"
+ if test $# -gt 0; then
+ title="$title ($1)"
+ shift
+ fi
+ args="$@"
+
+ test_perf "$title" "
+ for i in \$(test_seq $test_iteration_count); do
+ git for-each-ref $args >/dev/null
+ done
+ "
+}
+
+run_tests () {
+ test_for_each_ref "$1"
+ test_for_each_ref "$1, no sort" --no-sort
+ test_for_each_ref "$1, --count=1" --count=1
+ test_for_each_ref "$1, --count=1, no sort" --no-sort --count=1
+ test_for_each_ref "$1, tags" refs/tags/
+ test_for_each_ref "$1, tags, no sort" --no-sort refs/tags/
+ test_for_each_ref "$1, tags, dereferenced" '--format="%(refname) %(objectname) %(*objectname)"' refs/tags/
+ test_for_each_ref "$1, tags, dereferenced, no sort" --no-sort '--format="%(refname) %(objectname) %(*objectname)"' refs/tags/
+
+ test_perf "for-each-ref ($1, tags) + cat-file --batch-check (dereferenced)" "
+ for i in \$(test_seq $test_iteration_count); do
+ git for-each-ref --format='%(objectname)^{} %(refname) %(objectname)' refs/tags/ | \
+ git cat-file --batch-check='%(objectname) %(rest)' >/dev/null
+ done
+ "
+}
+
+run_tests "loose"
+
+test_expect_success 'pack refs' '
+ git pack-refs --all
+'
+run_tests "packed"
+
+test_done
diff --git a/t/perf/p7527-builtin-fsmonitor.sh b/t/perf/p7527-builtin-fsmonitor.sh
index c3f9a4caa4..90164327e8 100755
--- a/t/perf/p7527-builtin-fsmonitor.sh
+++ b/t/perf/p7527-builtin-fsmonitor.sh
@@ -95,7 +95,7 @@ test_expect_success "Setup borrowed repo (fsm+uc)" "
# time is not useful.
#
# Create a temp branch and do all work relative to it so that we don't
-# accidentially alter the real ballast branch.
+# accidentally alter the real ballast branch.
#
test_expect_success "Setup borrowed repo (temp ballast branch)" "
test_might_fail git -C $REPO checkout $BALLAST_BR &&
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index e7786775a9..8ab6d9c469 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -15,7 +15,7 @@
# 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/ .
+# along with this program. If not, see https://www.gnu.org/licenses/ .
# These variables must be set before the inclusion of test-lib.sh below,
# because it will change our working directory.
@@ -31,7 +31,7 @@ unset GIT_CONFIG_NOSYSTEM
GIT_CONFIG_SYSTEM="$TEST_DIRECTORY/perf/config"
export GIT_CONFIG_SYSTEM
-if test -n "$GIT_TEST_INSTALLED" -a -z "$PERF_SET_GIT_TEST_INSTALLED"
+if test -n "$GIT_TEST_INSTALLED" && test -z "$PERF_SET_GIT_TEST_INSTALLED"
then
error "Do not use GIT_TEST_INSTALLED with the perf tests.
@@ -282,7 +282,7 @@ test_perf_ () {
# Run the performance test script specified in perf-test with
# optional prerequisite and setup steps.
# Options:
-# --prereq prerequisites: Skip the test if prequisites aren't met
+# --prereq prerequisites: Skip the test if prerequisites aren't met
# --setup "setup-steps": Run setup steps prior to each measured iteration
#
test_perf () {
@@ -309,7 +309,7 @@ test_size_ () {
# prerequisites and setup steps. Returns the numeric value
# returned by size-test.
# Options:
-# --prereq prerequisites: Skip the test if prequisites aren't met
+# --prereq prerequisites: Skip the test if prerequisites aren't met
# --setup "setup-steps": Run setup steps prior to the size measurement
test_size () {
diff --git a/t/perf/repos/inflate-repo.sh b/t/perf/repos/inflate-repo.sh
index fcfc992b5b..412e4b450b 100755
--- a/t/perf/repos/inflate-repo.sh
+++ b/t/perf/repos/inflate-repo.sh
@@ -33,7 +33,7 @@ do
done
git ls-tree -r HEAD >GEN_src_list
-nr_src_files=$(cat GEN_src_list | wc -l)
+nr_src_files=$(wc -l <GEN_src_list)
src_branch=$(git symbolic-ref --short HEAD)
diff --git a/t/perf/run b/t/perf/run
index 34115edec3..486ead2198 100755
--- a/t/perf/run
+++ b/t/perf/run
@@ -91,10 +91,10 @@ set_git_test_installed () {
run_dirs_helper () {
mydir=${1%/}
shift
- while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do
+ while test $# -gt 0 && test "$1" != -- && test ! -f "$1"; do
shift
done
- if test $# -gt 0 -a "$1" = --; then
+ if test $# -gt 0 && test "$1" = --; then
shift
fi
@@ -124,7 +124,7 @@ run_dirs_helper () {
}
run_dirs () {
- while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do
+ while test $# -gt 0 && test "$1" != -- && test ! -f "$1"; do
run_dirs_helper "$@"
shift
done
@@ -180,7 +180,8 @@ run_subsection () {
GIT_PERF_AGGREGATING_LATER=t
export GIT_PERF_AGGREGATING_LATER
- if test $# = 0 -o "$1" = -- -o -f "$1"; then
+ if test $# = 0 || test "$1" = -- || test -f "$1"
+ then
set -- . "$@"
fi
diff --git a/t/run-test.sh b/t/run-test.sh
new file mode 100755
index 0000000000..63328ac630
--- /dev/null
+++ b/t/run-test.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# A simple wrapper to run shell tests via TEST_SHELL_PATH,
+# or exec unit tests directly.
+
+case "$1" in
+*.sh)
+ if test -z "${TEST_SHELL_PATH}"
+ then
+ echo >&2 "ERROR: TEST_SHELL_PATH is empty or not set"
+ exit 1
+ fi
+ exec "${TEST_SHELL_PATH}" "$@" ${TEST_OPTIONS}
+ ;;
+*)
+ exec "$@"
+ ;;
+esac
diff --git a/t/socks4-proxy.pl b/t/socks4-proxy.pl
new file mode 100644
index 0000000000..4c3a35c008
--- /dev/null
+++ b/t/socks4-proxy.pl
@@ -0,0 +1,48 @@
+use strict;
+use IO::Select;
+use IO::Socket::UNIX;
+use IO::Socket::INET;
+
+my $path = shift;
+
+unlink($path);
+my $server = IO::Socket::UNIX->new(Listen => 1, Local => $path)
+ or die "unable to listen on $path: $!";
+
+$| = 1;
+print "ready\n";
+
+while (my $client = $server->accept()) {
+ sysread $client, my $buf, 8;
+ my ($version, $cmd, $port, $ip) = unpack 'CCnN', $buf;
+ next unless $version == 4; # socks4
+ next unless $cmd == 1; # TCP stream connection
+
+ # skip NUL-terminated id
+ while (sysread $client, my $char, 1) {
+ last unless ord($char);
+ }
+
+ # version(0), reply(5a == granted), port (ignored), ip (ignored)
+ syswrite $client, "\x00\x5a\x00\x00\x00\x00\x00\x00";
+
+ my $remote = IO::Socket::INET->new(PeerHost => $ip, PeerPort => $port)
+ or die "unable to connect to $ip/$port: $!";
+
+ my $io = IO::Select->new($client, $remote);
+ while ($io->count) {
+ for my $fh ($io->can_read(0)) {
+ for my $pair ([$client, $remote], [$remote, $client]) {
+ my ($from, $to) = @$pair;
+ next unless $fh == $from;
+
+ my $r = sysread $from, my $buf, 1024;
+ if (!defined $r || $r <= 0) {
+ $io->remove($from);
+ next;
+ }
+ syswrite $to, $buf;
+ }
+ }
+ }
+}
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 98b81e4d63..35c5c2b4f9 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -684,7 +684,7 @@ test_expect_success 'subtest: tests respect lazy prerequisites' '
write_and_run_sub_test_lib_test lazy-prereqs <<-\EOF &&
test_lazy_prereq LAZY_TRUE true
- test_expect_success LAZY_TRUE "lazy prereq is satisifed" "true"
+ test_expect_success LAZY_TRUE "lazy prereq is satisfied" "true"
test_expect_success !LAZY_TRUE "negative lazy prereq" "false"
test_lazy_prereq LAZY_FALSE false
@@ -695,7 +695,7 @@ test_expect_success 'subtest: tests respect lazy prerequisites' '
EOF
check_sub_test_lib_test lazy-prereqs <<-\EOF
- ok 1 - lazy prereq is satisifed
+ ok 1 - lazy prereq is satisfied
ok 2 # skip negative lazy prereq (missing !LAZY_TRUE)
ok 3 # skip lazy prereq not satisfied (missing LAZY_FALSE)
ok 4 - negative false prereq
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 30a6edca1d..4890dff4b2 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -2,7 +2,6 @@
test_description='git init'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_config () {
@@ -168,8 +167,8 @@ test_expect_success 'reinit' '
git -c init.defaultBranch=initial init >out1 2>err1 &&
git init >out2 2>err2
) &&
- test_i18ngrep "Initialized empty" again/out1 &&
- test_i18ngrep "Reinitialized existing" again/out2 &&
+ test_grep "Initialized empty" again/out1 &&
+ test_grep "Reinitialized existing" again/out2 &&
test_must_be_empty again/err1 &&
test_must_be_empty again/err2
'
@@ -332,7 +331,7 @@ test_expect_success 'init with separate gitdir' '
test_expect_success 'explicit bare & --separate-git-dir incompatible' '
test_must_fail git init --bare --separate-git-dir goop.git bare.git 2>err &&
- test_i18ngrep "cannot be used together" err
+ test_grep "cannot be used together" err
'
test_expect_success 'implicit bare & --separate-git-dir incompatible' '
@@ -340,7 +339,7 @@ test_expect_success 'implicit bare & --separate-git-dir incompatible' '
mkdir -p bare.git &&
test_must_fail env GIT_DIR=. \
git -C bare.git init --separate-git-dir goop.git 2>err &&
- test_i18ngrep "incompatible" err
+ test_grep "incompatible" err
'
test_expect_success 'bare & --separate-git-dir incompatible within worktree' '
@@ -349,7 +348,7 @@ test_expect_success 'bare & --separate-git-dir incompatible within worktree' '
git clone --bare . bare.git &&
git -C bare.git worktree add --detach ../linkwt &&
test_must_fail git -C linkwt init --separate-git-dir seprepo 2>err &&
- test_i18ngrep "incompatible" err
+ test_grep "incompatible" err
'
test_lazy_prereq GETCWD_IGNORES_PERMS '
@@ -500,6 +499,7 @@ test_expect_success 're-init from a linked worktree' '
'
test_expect_success 'init honors GIT_DEFAULT_HASH' '
+ test_when_finished "rm -rf sha1 sha256" &&
GIT_DEFAULT_HASH=sha1 git init sha1 &&
git -C sha1 rev-parse --show-object-format >actual &&
echo sha1 >expected &&
@@ -511,6 +511,7 @@ test_expect_success 'init honors GIT_DEFAULT_HASH' '
'
test_expect_success 'init honors --object-format' '
+ test_when_finished "rm -rf explicit-sha1 explicit-sha256" &&
git init --object-format=sha1 explicit-sha1 &&
git -C explicit-sha1 rev-parse --show-object-format >actual &&
echo sha1 >expected &&
@@ -521,7 +522,58 @@ test_expect_success 'init honors --object-format' '
test_cmp expected actual
'
+test_expect_success 'init honors init.defaultObjectFormat' '
+ test_when_finished "rm -rf sha1 sha256" &&
+
+ test_config_global init.defaultObjectFormat sha1 &&
+ (
+ sane_unset GIT_DEFAULT_HASH &&
+ git init sha1 &&
+ git -C sha1 rev-parse --show-object-format >actual &&
+ echo sha1 >expected &&
+ test_cmp expected actual
+ ) &&
+
+ test_config_global init.defaultObjectFormat sha256 &&
+ (
+ sane_unset GIT_DEFAULT_HASH &&
+ git init sha256 &&
+ git -C sha256 rev-parse --show-object-format >actual &&
+ echo sha256 >expected &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'init warns about invalid init.defaultObjectFormat' '
+ test_when_finished "rm -rf repo" &&
+ test_config_global init.defaultObjectFormat garbage &&
+
+ echo "warning: unknown hash algorithm ${SQ}garbage${SQ}" >expect &&
+ git init repo 2>err &&
+ test_cmp expect err &&
+
+ git -C repo rev-parse --show-object-format >actual &&
+ echo $GIT_DEFAULT_HASH >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success '--object-format overrides GIT_DEFAULT_HASH' '
+ test_when_finished "rm -rf repo" &&
+ GIT_DEFAULT_HASH=sha1 git init --object-format=sha256 repo &&
+ git -C repo rev-parse --show-object-format >actual &&
+ echo sha256 >expected
+'
+
+test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' '
+ test_when_finished "rm -rf repo" &&
+ test_config_global init.defaultObjectFormat sha1 &&
+ GIT_DEFAULT_HASH=sha256 git init repo &&
+ git -C repo rev-parse --show-object-format >actual &&
+ echo sha256 >expected
+'
+
test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '
+ test_when_finished "rm -rf explicit-v0" &&
git init --object-format=sha256 explicit-v0 &&
git -C explicit-v0 config core.repositoryformatversion 0 &&
test_must_fail git -C explicit-v0 rev-parse --show-object-format
@@ -532,6 +584,167 @@ test_expect_success 'init rejects attempts to initialize with different hash' '
test_must_fail git -C sha256 init --object-format=sha1
'
+test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage is not allowed with repo version 0' '
+ test_when_finished "rm -rf refstorage" &&
+ git init refstorage &&
+ git -C refstorage config extensions.refStorage files &&
+ test_must_fail git -C refstorage rev-parse 2>err &&
+ grep "repo version is 0, but v1-only extension found" err
+'
+
+test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with files backend' '
+ test_when_finished "rm -rf refstorage" &&
+ git init refstorage &&
+ git -C refstorage config core.repositoryformatversion 1 &&
+ git -C refstorage config extensions.refStorage files &&
+ test_commit -C refstorage A &&
+ git -C refstorage rev-parse --verify HEAD
+'
+
+test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown backend' '
+ test_when_finished "rm -rf refstorage" &&
+ git init refstorage &&
+ git -C refstorage config core.repositoryformatversion 1 &&
+ git -C refstorage config extensions.refStorage garbage &&
+ test_must_fail git -C refstorage rev-parse 2>err &&
+ grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err
+'
+
+test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
+ test_when_finished "rm -rf refformat" &&
+ cat >expect <<-EOF &&
+ fatal: unknown ref storage format ${SQ}garbage${SQ}
+ EOF
+ test_must_fail env GIT_DEFAULT_REF_FORMAT=garbage git init refformat 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'init warns about invalid init.defaultRefFormat' '
+ test_when_finished "rm -rf repo" &&
+ test_config_global init.defaultRefFormat garbage &&
+
+ echo "warning: unknown ref storage format ${SQ}garbage${SQ}" >expect &&
+ git init repo 2>err &&
+ test_cmp expect err &&
+
+ git -C repo rev-parse --show-ref-format >actual &&
+ echo $GIT_DEFAULT_REF_FORMAT >expected &&
+ test_cmp expected actual
+'
+
+backends="files reftable"
+for format in $backends
+do
+ test_expect_success DEFAULT_REPO_FORMAT "init with GIT_DEFAULT_REF_FORMAT=$format" '
+ test_when_finished "rm -rf refformat" &&
+ GIT_DEFAULT_REF_FORMAT=$format git init refformat &&
+
+ if test $format = files
+ then
+ test_must_fail git -C refformat config extensions.refstorage &&
+ echo 0 >expect
+ else
+ git -C refformat config extensions.refstorage &&
+ echo 1 >expect
+ fi &&
+ git -C refformat config core.repositoryformatversion >actual &&
+ test_cmp expect actual &&
+
+ echo $format >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "init with --ref-format=$format" '
+ test_when_finished "rm -rf refformat" &&
+ git init --ref-format=$format refformat &&
+ echo $format >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "init with init.defaultRefFormat=$format" '
+ test_when_finished "rm -rf refformat" &&
+ test_config_global init.defaultRefFormat $format &&
+ (
+ sane_unset GIT_DEFAULT_REF_FORMAT &&
+ git init refformat
+ ) &&
+
+ echo $format >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "--ref-format=$format overrides GIT_DEFAULT_REF_FORMAT" '
+ test_when_finished "rm -rf refformat" &&
+ GIT_DEFAULT_REF_FORMAT=garbage git init --ref-format=$format refformat &&
+ echo $format >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+done
+
+test_expect_success "--ref-format= overrides GIT_DEFAULT_REF_FORMAT" '
+ test_when_finished "rm -rf refformat" &&
+ GIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat &&
+ echo reftable >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat" '
+ test_when_finished "rm -rf refformat" &&
+ test_config_global init.defaultRefFormat files &&
+
+ GIT_DEFAULT_REF_FORMAT=reftable git init refformat &&
+ echo reftable >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+for from_format in $backends
+do
+ test_expect_success "re-init with same format ($from_format)" '
+ test_when_finished "rm -rf refformat" &&
+ git init --ref-format=$from_format refformat &&
+ git init --ref-format=$from_format refformat &&
+ echo $from_format >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+
+ for to_format in $backends
+ do
+ if test "$from_format" = "$to_format"
+ then
+ continue
+ fi
+
+ test_expect_success "re-init with different format fails ($from_format -> $to_format)" '
+ test_when_finished "rm -rf refformat" &&
+ git init --ref-format=$from_format refformat &&
+ cat >expect <<-EOF &&
+ fatal: attempt to reinitialize repository with different reference storage format
+ EOF
+ test_must_fail git init --ref-format=$to_format refformat 2>err &&
+ test_cmp expect err &&
+ echo $from_format >expect &&
+ git -C refformat rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+ done
+done
+
+test_expect_success 'init with --ref-format=garbage' '
+ test_when_finished "rm -rf refformat" &&
+ cat >expect <<-EOF &&
+ fatal: unknown ref storage format ${SQ}garbage${SQ}
+ EOF
+ test_must_fail git init --ref-format=garbage refformat 2>err &&
+ test_cmp expect err
+'
+
test_expect_success MINGW 'core.hidedotfiles = false' '
git config --global core.hidedotfiles false &&
rm -rf newdir &&
@@ -563,7 +776,7 @@ test_expect_success '--initial-branch' '
: re-initializing should not change the branch name &&
git init --initial-branch=ignore initial-branch-option 2>err &&
- test_i18ngrep "ignored --initial-branch" err &&
+ test_grep "ignored --initial-branch" err &&
git -C initial-branch-option symbolic-ref HEAD >actual &&
grep hello actual
'
@@ -579,7 +792,7 @@ test_expect_success 'advice on unconfigured init.defaultBranch' '
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git -c color.advice=always \
init unconfigured-default-branch-name 2>err &&
test_decode_color <err >decoded &&
- test_i18ngrep "<YELLOW>hint: " decoded
+ test_grep "<YELLOW>hint: " decoded
'
test_expect_success 'overridden default main branch name (env)' '
@@ -592,7 +805,7 @@ test_expect_success 'overridden default main branch name (env)' '
test_expect_success 'invalid default branch name' '
test_must_fail env GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME="with space" \
git init initial-branch-invalid 2>err &&
- test_i18ngrep "invalid branch name" err
+ test_grep "invalid branch name" err
'
test_expect_success 'branch -m with the initial branch' '
@@ -608,4 +821,64 @@ test_expect_success 'branch -m with the initial branch' '
test_cmp expect actual
'
+test_expect_success 'init with includeIf.onbranch condition' '
+ test_when_finished "rm -rf repo" &&
+ git -c includeIf.onbranch:main.path=nonexistent init repo &&
+ echo $GIT_DEFAULT_REF_FORMAT >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'init with includeIf.onbranch condition with existing directory' '
+ test_when_finished "rm -rf repo" &&
+ mkdir repo &&
+ git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo &&
+ echo $GIT_DEFAULT_REF_FORMAT >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 're-init with includeIf.onbranch condition' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo &&
+ echo $GIT_DEFAULT_REF_FORMAT >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 're-init with includeIf.onbranch condition' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo &&
+ echo $GIT_DEFAULT_REF_FORMAT >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 're-init skips non-matching includeIf.onbranch' '
+ test_when_finished "rm -rf repo config" &&
+ cat >config <<-EOF &&
+ [
+ garbage
+ EOF
+ git init repo &&
+ git -c includeIf.onbranch:nonexistent.path="$(test-tool path-utils absolute_path config)" init repo
+'
+
+test_expect_success 're-init reads matching includeIf.onbranch' '
+ test_when_finished "rm -rf repo config" &&
+ cat >config <<-EOF &&
+ [
+ garbage
+ EOF
+ path="$(test-tool path-utils absolute_path config)" &&
+ git init --initial-branch=branch repo &&
+ cat >expect <<-EOF &&
+ fatal: bad config line 1 in file $path
+ EOF
+ test_must_fail git -c includeIf.onbranch:branch.path="$path" init repo 2>err &&
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh
index e013d38f48..dfbcdddbcc 100755
--- a/t/t0002-gitfile.sh
+++ b/t/t0002-gitfile.sh
@@ -7,7 +7,6 @@ Verify that plumbing commands work when .git is a file
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
objpath() {
@@ -22,13 +21,13 @@ test_expect_success 'initial setup' '
test_expect_success 'bad setup: invalid .git file format' '
echo "gitdir $REAL" >.git &&
test_must_fail git rev-parse 2>.err &&
- test_i18ngrep "invalid gitfile format" .err
+ test_grep "invalid gitfile format" .err
'
test_expect_success 'bad setup: invalid .git file path' '
echo "gitdir: $REAL.not" >.git &&
test_must_fail git rev-parse 2>.err &&
- test_i18ngrep "not a git repository" .err
+ test_grep "not a git repository" .err
'
test_expect_success 'final setup + check rev-parse --git-dir' '
@@ -40,7 +39,7 @@ test_expect_success 'final setup + check rev-parse --git-dir' '
test_expect_success 'check hash-object' '
echo "foo" >bar &&
- SHA=$(cat bar | git hash-object -w --stdin) &&
+ SHA=$(git hash-object -w --stdin <bar) &&
test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 26e082f05b..3c98b622f2 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -2,7 +2,6 @@
test_description=gitattributes
-TEST_PASSES_SANITIZE_LEAK=true
TEST_CREATE_REPO_NO_TEMPLATE=1
. ./test-lib.sh
@@ -19,6 +18,20 @@ attr_check () {
test_must_be_empty err
}
+attr_check_object_mode_basic () {
+ path="$1" &&
+ expect="$2" &&
+ check_opts="$3" &&
+ git check-attr $check_opts builtin_objectmode -- "$path" >actual 2>err &&
+ echo "$path: builtin_objectmode: $expect" >expect &&
+ test_cmp expect actual
+}
+
+attr_check_object_mode () {
+ attr_check_object_mode_basic "$@" &&
+ test_must_be_empty err
+}
+
attr_check_quote () {
path="$1" quoted_path="$2" expect="$3" &&
@@ -40,6 +53,10 @@ attr_check_source () {
test_cmp expect actual &&
test_must_be_empty err
+ git $git_opts -c "attr.tree=$source" check-attr test -- "$path" >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
+
GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err &&
test_cmp expect actual &&
test_must_be_empty err
@@ -259,7 +276,7 @@ test_expect_success 'root subdir attribute test' '
test_expect_success 'negative patterns' '
echo "!f test=bar" >.gitattributes &&
git check-attr test -- '"'"'!f'"'"' 2>errors &&
- test_i18ngrep "Negative patterns are ignored" errors
+ test_grep "Negative patterns are ignored" errors
'
test_expect_success 'patterns starting with exclamation' '
@@ -342,6 +359,95 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' '
)
'
+bad_attr_source_err="fatal: bad --attr-source or GIT_ATTR_SOURCE"
+
+test_expect_success '--attr-source is bad' '
+ test_when_finished rm -rf empty &&
+ git init empty &&
+ (
+ cd empty &&
+ echo "$bad_attr_source_err" >expect_err &&
+ test_must_fail git --attr-source=HEAD check-attr test -- f/path 2>err &&
+ test_cmp expect_err err
+ )
+'
+
+test_expect_success 'attr.tree when HEAD is unborn' '
+ test_when_finished rm -rf empty &&
+ git init empty &&
+ (
+ cd empty &&
+ echo "f/path: test: unspecified" >expect &&
+ git -c attr.tree=HEAD check-attr test -- f/path >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'bad attr source defaults to reading .gitattributes file' '
+ test_when_finished rm -rf empty &&
+ git init empty &&
+ (
+ cd empty &&
+ echo "f/path test=val" >.gitattributes &&
+ echo "f/path: test: val" >expect &&
+ git -c attr.tree=HEAD check-attr test -- f/path >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'bare repo no longer defaults to reading .gitattributes from HEAD' '
+ test_when_finished rm -rf test bare_with_gitattribute &&
+ git init test &&
+ test_commit -C test gitattributes .gitattributes "f/path test=val" &&
+ git clone --bare test bare_with_gitattribute &&
+
+ echo "f/path: test: unspecified" >expect &&
+ git -C bare_with_gitattribute check-attr test -- f/path >actual &&
+ test_cmp expect actual &&
+
+ echo "f/path: test: val" >expect &&
+ git -C bare_with_gitattribute -c attr.tree=HEAD \
+ check-attr test -- f/path >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'precedence of --attr-source, GIT_ATTR_SOURCE, then attr.tree' '
+ test_when_finished rm -rf empty &&
+ git init empty &&
+ (
+ cd empty &&
+ git checkout -b attr-source &&
+ test_commit "val1" .gitattributes "f/path test=val1" &&
+ git checkout -b attr-tree &&
+ test_commit "val2" .gitattributes "f/path test=val2" &&
+ git checkout attr-source &&
+ echo "f/path: test: val1" >expect &&
+ GIT_ATTR_SOURCE=attr-source git -c attr.tree=attr-tree --attr-source=attr-source \
+ check-attr test -- f/path >actual &&
+ test_cmp expect actual &&
+ GIT_ATTR_SOURCE=attr-source git -c attr.tree=attr-tree \
+ check-attr test -- f/path >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'diff without repository with attr source' '
+ mkdir -p "$TRASH_DIRECTORY/outside/nongit" &&
+ (
+ cd "$TRASH_DIRECTORY/outside/nongit" &&
+ GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/outside" &&
+ export GIT_CEILING_DIRECTORIES &&
+ touch file &&
+ cat >expect <<-EOF &&
+ fatal: cannot use --attr-source or GIT_ATTR_SOURCE without repo
+ EOF
+ test_must_fail env GIT_ATTR_SOURCE=HEAD git grep --no-index foo file 2>err &&
+ test_cmp expect err
+ )
+'
+
test_expect_success 'bare repository: with --source' '
(
cd bare.git &&
@@ -424,7 +530,7 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
mkdir subdir &&
ln -s ../attr subdir/.gitattributes &&
attr_check_basic subdir/file unspecified &&
- test_i18ngrep "unable to access.*gitattributes" err
+ test_grep "unable to access.*gitattributes" err
'
test_expect_success 'large attributes line ignored in tree' '
@@ -486,4 +592,76 @@ test_expect_success EXPENSIVE 'large attributes file ignored in index' '
test_cmp expect err
'
+test_expect_success EXPENSIVE 'large attributes blob ignored' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(dd if=/dev/zero bs=1048576 count=101 2>/dev/null | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ tree="$(git write-tree)" &&
+ git check-attr --cached --all --source="$tree" path >/dev/null 2>err &&
+ echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'builtin object mode attributes work (dir and regular paths)' '
+ >normal &&
+ attr_check_object_mode normal 100644 &&
+ mkdir dir &&
+ attr_check_object_mode dir 040000
+'
+
+test_expect_success POSIXPERM 'builtin object mode attributes work (executable)' '
+ >exec &&
+ chmod +x exec &&
+ attr_check_object_mode exec 100755
+'
+
+test_expect_success SYMLINKS 'builtin object mode attributes work (symlinks)' '
+ ln -s to_sym sym &&
+ attr_check_object_mode sym 120000
+'
+
+test_expect_success 'native object mode attributes work with --cached' '
+ >normal &&
+ git add normal &&
+ empty_blob=$(git rev-parse :normal) &&
+ git update-index --index-info <<-EOF &&
+ 100755 $empty_blob 0 exec
+ 120000 $empty_blob 0 symlink
+ EOF
+ attr_check_object_mode normal 100644 --cached &&
+ attr_check_object_mode exec 100755 --cached &&
+ attr_check_object_mode symlink 120000 --cached
+'
+
+test_expect_success 'check object mode attributes work for submodules' '
+ mkdir sub &&
+ (
+ cd sub &&
+ git init &&
+ mv .git .real &&
+ echo "gitdir: .real" >.git &&
+ test_commit first
+ ) &&
+ attr_check_object_mode sub 160000 &&
+ attr_check_object_mode sub unspecified --cached &&
+ git add sub &&
+ attr_check_object_mode sub 160000 --cached
+'
+
+test_expect_success 'we do not allow user defined builtin_* attributes' '
+ echo "foo* builtin_foo" >.gitattributes &&
+ git add .gitattributes 2>actual &&
+ echo "builtin_foo is not a valid attribute name: .gitattributes:1" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'user defined builtin_objectmode values are ignored' '
+ echo "foo* builtin_objectmode=12345" >.gitattributes &&
+ git add .gitattributes &&
+ >foo_1 &&
+ attr_check_object_mode_basic foo_1 100644 &&
+ echo "builtin_objectmode is not a valid attribute name: .gitattributes:1" >expect &&
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh
index 8114fac73b..3bdafbae0f 100755
--- a/t/t0004-unwritable.sh
+++ b/t/t0004-unwritable.sh
@@ -2,7 +2,6 @@
test_description='detect unwritable repository and fail correctly'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh
index eba75a2490..afba0fc3fc 100755
--- a/t/t0005-signals.sh
+++ b/t/t0005-signals.sh
@@ -2,7 +2,6 @@
test_description='signals work as we expect'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >expect <<EOF
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index e18b160286..53ced36df4 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -2,12 +2,16 @@
test_description='test date parsing and printing'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# arbitrary reference time: 2009-08-30 19:20:00
GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW
+if test_have_prereq TIME_IS_64BIT,TIME_T_IS_64BIT
+then
+ test_set_prereq HAVE_64BIT_TIME
+fi
+
check_relative() {
t=$(($GIT_TEST_DATE_NOW - $1))
echo "$t -> $2" >expect
@@ -46,6 +50,7 @@ check_show () {
TIME='1466000000 +0200'
check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200'
check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00'
+check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z'
check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200'
check_show short "$TIME" '2016-06-15'
check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200'
@@ -69,16 +74,25 @@ check_show 'format:%s' '123456789 +1234' 123456789
check_show 'format:%s' '123456789 -1234' 123456789
check_show 'format-local:%s' '123456789 -1234' 123456789
+# negative TZ offset
+TIME='1466000000 -0200'
+check_show iso8601 "$TIME" '2016-06-15 12:13:20 -0200'
+check_show iso8601-strict "$TIME" '2016-06-15T12:13:20-02:00'
+check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 12:13:20 -0200'
+check_show default "$TIME" 'Wed Jun 15 12:13:20 2016 -0200'
+check_show raw "$TIME" '1466000000 -0200'
+
# arbitrary time absurdly far in the future
FUTURE="5758122296 -0400"
-check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" TIME_IS_64BIT,TIME_T_IS_64BIT
-check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" TIME_IS_64BIT,TIME_T_IS_64BIT
+check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" HAVE_64BIT_TIME
+check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" HAVE_64BIT_TIME
-check_parse() {
+REQUIRE_64BIT_TIME=
+check_parse () {
echo "$1 -> $2" >expect
- test_expect_${4:-success} "parse date ($1${3:+ TZ=$3})" "
- TZ=${3:-$TZ} test-tool date parse '$1' >actual &&
- test_cmp expect actual
+ test_expect_success $REQUIRE_64BIT_TIME "parse date ($1${3:+ TZ=$3}) -> $2" "
+ TZ=${3:-$TZ} test-tool date parse '$1' >actual &&
+ test_cmp expect actual
"
}
@@ -108,6 +122,39 @@ check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700'
+check_parse '1970-01-01 00:00:00' '1970-01-01 00:00:00 +0000'
+check_parse '1970-01-01 00:00:00 +00' '1970-01-01 00:00:00 +0000'
+check_parse '1970-01-01 00:00:00 Z' '1970-01-01 00:00:00 +0000'
+check_parse '1970-01-01 00:00:00 -01' '1970-01-01 00:00:00 -0100'
+check_parse '1970-01-01 00:00:00 +01' bad
+check_parse '1970-01-01 00:00:00 +11' bad
+check_parse '1970-01-01 00:59:59 +01' bad
+check_parse '1970-01-01 01:00:00 +01' '1970-01-01 01:00:00 +0100'
+check_parse '1970-01-01 01:00:00 +11' bad
+check_parse '1970-01-02 00:00:00 +11' '1970-01-02 00:00:00 +1100'
+check_parse '1969-12-31 23:59:59' bad
+check_parse '1969-12-31 23:59:59 +00' bad
+check_parse '1969-12-31 23:59:59 Z' bad
+check_parse '1969-12-31 23:59:59 +11' bad
+check_parse '1969-12-31 23:59:59 -11' bad
+
+REQUIRE_64BIT_TIME=HAVE_64BIT_TIME
+check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000'
+check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000'
+check_parse '2099-12-31 23:59:59 Z' '2099-12-31 23:59:59 +0000'
+check_parse '2099-12-31 23:59:59 +01' '2099-12-31 23:59:59 +0100'
+check_parse '2099-12-31 23:59:59 -01' bad
+check_parse '2099-12-31 23:59:59 -11' bad
+check_parse '2099-12-31 23:00:00 -01' bad
+check_parse '2099-12-31 22:59:59 -01' '2099-12-31 22:59:59 -0100'
+check_parse '2100-00-00 00:00:00' bad
+check_parse '2099-12-30 00:00:00 -11' '2099-12-30 00:00:00 -1100'
+check_parse '2100-00-00 00:00:00 +00' bad
+check_parse '2100-00-00 00:00:00 Z' bad
+check_parse '2100-00-00 00:00:00 -11' bad
+check_parse '2100-00-00 00:00:00 +11' bad
+REQUIRE_64BIT_TIME=
+
check_approxidate() {
echo "$1 -> $2 +0000" >expect
test_expect_${3:-success} "parse approxidate ($1)" "
diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh
index ff4fd9348c..2b60317758 100755
--- a/t/t0007-git-var.sh
+++ b/t/t0007-git-var.sh
@@ -2,7 +2,6 @@
test_description='basic sanity checks for git var'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
sane_unset_all_editors () {
@@ -157,7 +156,7 @@ test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' '
test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' '
shellpath=$(git var GIT_SHELL_PATH) &&
case "$shellpath" in
- *sh) ;;
+ [A-Z]:/*/sh.exe) test -f "$shellpath";;
*) return 1;;
esac
'
diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index c70d11bc91..c9376dffb5 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -2,7 +2,6 @@
test_description=check-ignore
-TEST_PASSES_SANITIZE_LEAK=true
TEST_CREATE_REPO_NO_TEMPLATE=1
. ./test-lib.sh
@@ -49,7 +48,7 @@ broken_c_unquote_verbose () {
stderr_contains () {
regexp="$1"
- if test_i18ngrep "$regexp" "$HOME/stderr"
+ if test_grep "$regexp" "$HOME/stderr"
then
return 0
else
@@ -942,7 +941,15 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
ln -s ignore subdir/.gitignore &&
test_must_fail git check-ignore subdir/file >actual 2>err &&
test_must_be_empty actual &&
- test_i18ngrep "unable to access.*gitignore" err
+ test_grep "unable to access.*gitignore" err
+'
+
+test_expect_success EXPENSIVE 'large exclude file ignored in tree' '
+ test_when_finished "rm .gitignore" &&
+ dd if=/dev/zero of=.gitignore bs=101M count=1 &&
+ git ls-files -o --exclude-standard 2>err &&
+ echo "warning: ignoring excessively large pattern file: .gitignore" >expect &&
+ test_cmp expect err
'
test_done
diff --git a/t/t0009-prio-queue.sh b/t/t0009-prio-queue.sh
deleted file mode 100755
index eea99107a4..0000000000
--- a/t/t0009-prio-queue.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/sh
-
-test_description='basic tests for priority queue implementation'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-cat >expect <<'EOF'
-1
-2
-3
-4
-5
-5
-6
-7
-8
-9
-10
-EOF
-test_expect_success 'basic ordering' '
- test-tool prio-queue 2 6 3 10 9 5 7 4 5 8 1 dump >actual &&
- test_cmp expect actual
-'
-
-cat >expect <<'EOF'
-2
-3
-4
-1
-5
-6
-EOF
-test_expect_success 'mixed put and get' '
- test-tool prio-queue 6 2 4 get 5 3 get get 1 dump >actual &&
- test_cmp expect actual
-'
-
-cat >expect <<'EOF'
-1
-2
-NULL
-1
-2
-NULL
-EOF
-test_expect_success 'notice empty queue' '
- test-tool prio-queue 1 2 get get get 1 2 get get get >actual &&
- test_cmp expect actual
-'
-
-cat >expect <<'EOF'
-3
-2
-6
-4
-5
-1
-8
-EOF
-test_expect_success 'stack order' '
- test-tool prio-queue stack 8 1 5 4 6 2 3 dump >actual &&
- test_cmp expect actual
-'
-
-test_done
diff --git a/t/t0010-racy-git.sh b/t/t0010-racy-git.sh
index 837c8b7228..45229f57b8 100755
--- a/t/t0010-racy-git.sh
+++ b/t/t0010-racy-git.sh
@@ -2,7 +2,6 @@
test_description='racy GIT'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This test can give false success if your machine is sufficiently
@@ -10,25 +9,24 @@ TEST_PASSES_SANITIZE_LEAK=true
for trial in 0 1 2 3 4
do
- rm -f .git/index
- echo frotz >infocom
- git update-index --add infocom
- echo xyzzy >infocom
-
- files=$(git diff-files -p)
- test_expect_success \
- "Racy GIT trial #$trial part A" \
- 'test "" != "$files"'
-
+ test_expect_success "Racy git trial #$trial part A" '
+ rm -f .git/index &&
+ echo frotz >infocom &&
+ git update-index --add infocom &&
+ echo xyzzy >infocom &&
+
+ git diff-files -p >out &&
+ test_file_not_empty out
+ '
sleep 1
- echo xyzzy >cornerstone
- git update-index --add cornerstone
- files=$(git diff-files -p)
- test_expect_success \
- "Racy GIT trial #$trial part B" \
- 'test "" != "$files"'
+ test_expect_success "Racy git trial #$trial part B" '
+ echo xyzzy >cornerstone &&
+ git update-index --add cornerstone &&
+ git diff-files -p >out &&
+ test_file_not_empty out
+ '
done
test_done
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
deleted file mode 100755
index 1cb6aa6824..0000000000
--- a/t/t0011-hashmap.sh
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/bin/sh
-
-test_description='test hashmap and string hash functions'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_hashmap() {
- echo "$1" | test-tool hashmap $3 > actual &&
- echo "$2" > expect &&
- test_cmp expect actual
-}
-
-test_expect_success 'put' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-size" "NULL
-NULL
-NULL
-NULL
-64 4"
-
-'
-
-test_expect_success 'put (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-size" "NULL
-NULL
-NULL
-64 3" ignorecase
-
-'
-
-test_expect_success 'replace' '
-
-test_hashmap "put key1 value1
-put key1 value2
-put fooBarFrotz value3
-put fooBarFrotz value4
-size" "NULL
-value1
-NULL
-value3
-64 2"
-
-'
-
-test_expect_success 'replace (case insensitive)' '
-
-test_hashmap "put key1 value1
-put Key1 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-size" "NULL
-value1
-NULL
-value3
-64 2" ignorecase
-
-'
-
-test_expect_success 'get' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-get key1
-get key2
-get fooBarFrotz
-get notInMap" "NULL
-NULL
-NULL
-NULL
-value1
-value2
-value3
-NULL"
-
-'
-
-test_expect_success 'get (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-get Key1
-get keY2
-get foobarfrotz
-get notInMap" "NULL
-NULL
-NULL
-value1
-value2
-value3
-NULL" ignorecase
-
-'
-
-test_expect_success 'add' '
-
-test_hashmap "add key1 value1
-add key1 value2
-add fooBarFrotz value3
-add fooBarFrotz value4
-get key1
-get fooBarFrotz
-get notInMap" "value2
-value1
-value4
-value3
-NULL"
-
-'
-
-test_expect_success 'add (case insensitive)' '
-
-test_hashmap "add key1 value1
-add Key1 value2
-add fooBarFrotz value3
-add foobarfrotz value4
-get key1
-get Foobarfrotz
-get notInMap" "value2
-value1
-value4
-value3
-NULL" ignorecase
-
-'
-
-test_expect_success 'remove' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-remove key1
-remove key2
-remove notInMap
-size" "NULL
-NULL
-NULL
-value1
-value2
-NULL
-64 1"
-
-'
-
-test_expect_success 'remove (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-remove Key1
-remove keY2
-remove notInMap
-size" "NULL
-NULL
-NULL
-value1
-value2
-NULL
-64 1" ignorecase
-
-'
-
-test_expect_success 'iterate' '
- test-tool hashmap >actual.raw <<-\EOF &&
- put key1 value1
- put key2 value2
- put fooBarFrotz value3
- iterate
- EOF
-
- cat >expect <<-\EOF &&
- NULL
- NULL
- NULL
- fooBarFrotz value3
- key1 value1
- key2 value2
- EOF
-
- sort <actual.raw >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'iterate (case insensitive)' '
- test-tool hashmap ignorecase >actual.raw <<-\EOF &&
- put key1 value1
- put key2 value2
- put fooBarFrotz value3
- iterate
- EOF
-
- cat >expect <<-\EOF &&
- NULL
- NULL
- NULL
- fooBarFrotz value3
- key1 value1
- key2 value2
- EOF
-
- sort <actual.raw >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'grow / shrink' '
-
- rm -f in &&
- rm -f expect &&
- for n in $(test_seq 51)
- do
- echo put key$n value$n >> in &&
- echo NULL >> expect || return 1
- done &&
- echo size >> in &&
- echo 64 51 >> expect &&
- echo put key52 value52 >> in &&
- echo NULL >> expect &&
- echo size >> in &&
- echo 256 52 >> expect &&
- for n in $(test_seq 12)
- do
- echo remove key$n >> in &&
- echo value$n >> expect || return 1
- done &&
- echo size >> in &&
- echo 256 40 >> expect &&
- echo remove key40 >> in &&
- echo value40 >> expect &&
- echo size >> in &&
- echo 64 39 >> expect &&
- cat in | test-tool hashmap > out &&
- test_cmp expect out
-
-'
-
-test_expect_success 'string interning' '
-
-test_hashmap "intern value1
-intern Value1
-intern value2
-intern value2
-" "value1
-Value1
-value2
-value2"
-
-'
-
-test_done
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
index dbfc5c8267..1d273d91c2 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -100,17 +100,17 @@ test_expect_success "--help does not work for guides" "
test_expect_success 'git help' '
git help >help.output &&
- test_i18ngrep "^ clone " help.output &&
- test_i18ngrep "^ add " help.output &&
- test_i18ngrep "^ log " help.output &&
- test_i18ngrep "^ commit " help.output &&
- test_i18ngrep "^ fetch " help.output
+ test_grep "^ clone " help.output &&
+ test_grep "^ add " help.output &&
+ test_grep "^ log " help.output &&
+ test_grep "^ commit " help.output &&
+ test_grep "^ fetch " help.output
'
test_expect_success 'git help -g' '
git help -g >help.output &&
- test_i18ngrep "^ everyday " help.output &&
- test_i18ngrep "^ tutorial " help.output
+ test_grep "^ everyday " help.output &&
+ test_grep "^ tutorial " help.output
'
test_expect_success 'git help fails for non-existing html pages' '
@@ -257,7 +257,7 @@ do
export GIT_CEILING_DIRECTORIES &&
test_expect_code 129 git -C sub $builtin -h >output 2>&1
) &&
- test_i18ngrep usage output
+ test_grep usage output
'
done <builtins
diff --git a/t/t0013-sha1dc.sh b/t/t0013-sha1dc.sh
index 5324047689..ce3d81227a 100755
--- a/t/t0013-sha1dc.sh
+++ b/t/t0013-sha1dc.sh
@@ -2,7 +2,6 @@
test_description='test sha1 collision detection'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
TEST_DATA="$TEST_DIRECTORY/t0013"
@@ -16,7 +15,7 @@ fi
test_expect_success 'test-sha1 detects shattered pdf' '
test_must_fail test-tool sha1 <"$TEST_DATA/shattered-1.pdf" 2>err &&
- test_i18ngrep collision err &&
+ test_grep collision err &&
grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err
'
diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh
index 8d3d9144c0..854d59ec58 100755
--- a/t/t0014-alias.sh
+++ b/t/t0014-alias.sh
@@ -8,7 +8,7 @@ test_expect_success 'nested aliases - internal execution' '
git config alias.nested-internal-1 nested-internal-2 &&
git config alias.nested-internal-2 status &&
git nested-internal-1 >output &&
- test_i18ngrep "^On branch " output
+ test_grep "^On branch " output
'
test_expect_success 'nested aliases - mixed execution' '
@@ -16,7 +16,7 @@ test_expect_success 'nested aliases - mixed execution' '
git config alias.nested-external-2 "!git nested-external-3" &&
git config alias.nested-external-3 status &&
git nested-external-1 >output &&
- test_i18ngrep "^On branch " output
+ test_grep "^On branch " output
'
test_expect_success 'looping aliases - internal execution' '
@@ -24,7 +24,7 @@ test_expect_success 'looping aliases - internal execution' '
git config alias.loop-internal-2 loop-internal-3 &&
git config alias.loop-internal-3 loop-internal-2 &&
test_must_fail git loop-internal-1 2>output &&
- test_i18ngrep "^fatal: alias loop detected: expansion of" output
+ test_grep "^fatal: alias loop detected: expansion of" output
'
# This test is disabled until external loops are fixed, because would block
@@ -34,7 +34,7 @@ test_expect_success 'looping aliases - internal execution' '
# git config alias.loop-mixed-1 loop-mixed-2 &&
# git config alias.loop-mixed-2 "!git loop-mixed-1" &&
# test_must_fail git loop-mixed-1 2>output &&
-# test_i18ngrep "^fatal: alias loop detected: expansion of" output
+# test_grep "^fatal: alias loop detected: expansion of" output
#'
test_expect_success 'run-command formats empty args properly' '
@@ -44,4 +44,15 @@ test_expect_success 'run-command formats empty args properly' '
test_cmp expect actual
'
+test_expect_success 'tracing a shell alias with arguments shows trace of prepared command' '
+ cat >expect <<-EOF &&
+ trace: start_command: SHELL -c ${SQ}echo \$* "\$@"${SQ} ${SQ}echo \$*${SQ} arg
+ EOF
+ git config alias.echo "!echo \$*" &&
+ env GIT_TRACE=1 git echo arg 2>output &&
+ # redact platform differences
+ sed -n -e "s/^\(trace: start_command:\) .* -c /\1 SHELL -c /p" output >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh
deleted file mode 100755
index 0a087a1983..0000000000
--- a/t/t0015-hash.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-test_description='test basic hash implementation'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_expect_success 'test basic SHA-1 hash values' '
- test-tool sha1 </dev/null >actual &&
- grep da39a3ee5e6b4b0d3255bfef95601890afd80709 actual &&
- printf "a" | test-tool sha1 >actual &&
- grep 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 actual &&
- printf "abc" | test-tool sha1 >actual &&
- grep a9993e364706816aba3e25717850c26c9cd0d89d actual &&
- printf "message digest" | test-tool sha1 >actual &&
- grep c12252ceda8be8994d5fa0290a47231c1d16aae3 actual &&
- printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha1 >actual &&
- grep 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 actual &&
- perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" |
- test-tool sha1 >actual &&
- grep 34aa973cd4c4daa4f61eeb2bdbad27316534016f actual &&
- printf "blob 0\0" | test-tool sha1 >actual &&
- grep e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 actual &&
- printf "blob 3\0abc" | test-tool sha1 >actual &&
- grep f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f actual &&
- printf "tree 0\0" | test-tool sha1 >actual &&
- grep 4b825dc642cb6eb9a060e54bf8d69288fbee4904 actual
-'
-
-test_expect_success 'test basic SHA-256 hash values' '
- test-tool sha256 </dev/null >actual &&
- grep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 actual &&
- printf "a" | test-tool sha256 >actual &&
- grep ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb actual &&
- printf "abc" | test-tool sha256 >actual &&
- grep ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad actual &&
- printf "message digest" | test-tool sha256 >actual &&
- grep f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650 actual &&
- printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha256 >actual &&
- grep 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 actual &&
- # Try to exercise the chunking code by turning autoflush on.
- perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" |
- test-tool sha256 >actual &&
- grep cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 actual &&
- perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" |
- test-tool sha256 >actual &&
- grep e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35 actual &&
- printf "blob 0\0" | test-tool sha256 >actual &&
- grep 473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 actual &&
- printf "blob 3\0abc" | test-tool sha256 >actual &&
- grep c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6 actual &&
- printf "tree 0\0" | test-tool sha256 >actual &&
- grep 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 actual
-'
-
-test_done
diff --git a/t/t0016-oidmap.sh b/t/t0016-oidmap.sh
deleted file mode 100755
index 0faef1f4f1..0000000000
--- a/t/t0016-oidmap.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/sh
-
-test_description='test oidmap'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-# This purposefully is very similar to t0011-hashmap.sh
-
-test_oidmap () {
- echo "$1" | test-tool oidmap $3 >actual &&
- echo "$2" >expect &&
- test_cmp expect actual
-}
-
-
-test_expect_success 'setup' '
-
- test_commit one &&
- test_commit two &&
- test_commit three &&
- test_commit four
-
-'
-
-test_expect_success 'put' '
-
-test_oidmap "put one 1
-put two 2
-put invalidOid 4
-put three 3" "NULL
-NULL
-Unknown oid: invalidOid
-NULL"
-
-'
-
-test_expect_success 'replace' '
-
-test_oidmap "put one 1
-put two 2
-put three 3
-put invalidOid 4
-put two deux
-put one un" "NULL
-NULL
-NULL
-Unknown oid: invalidOid
-2
-1"
-
-'
-
-test_expect_success 'get' '
-
-test_oidmap "put one 1
-put two 2
-put three 3
-get two
-get four
-get invalidOid
-get one" "NULL
-NULL
-NULL
-2
-NULL
-Unknown oid: invalidOid
-1"
-
-'
-
-test_expect_success 'remove' '
-
-test_oidmap "put one 1
-put two 2
-put three 3
-remove one
-remove two
-remove invalidOid
-remove four" "NULL
-NULL
-NULL
-1
-2
-Unknown oid: invalidOid
-NULL"
-
-'
-
-test_expect_success 'iterate' '
- test-tool oidmap >actual.raw <<-\EOF &&
- put one 1
- put two 2
- put three 3
- iterate
- EOF
-
- # sort "expect" too so we do not rely on the order of particular oids
- sort >expect <<-EOF &&
- NULL
- NULL
- NULL
- $(git rev-parse one) 1
- $(git rev-parse two) 2
- $(git rev-parse three) 3
- EOF
-
- sort <actual.raw >actual &&
- test_cmp expect actual
-'
-
-test_done
diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh
index fc14ba091c..32fe848179 100755
--- a/t/t0017-env-helper.sh
+++ b/t/t0017-env-helper.sh
@@ -2,7 +2,6 @@
test_description='test test-tool env-helper'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
@@ -91,9 +90,16 @@ test_expect_success 'test-tool env-helper reads config thanks to trace2' '
git config -l 2>err &&
grep "exceeded maximum include depth" err &&
+ # This validates that the assumption that we attempt to
+ # read the configuration and fail very early in the start-up
+ # sequence (due to trace2 subsystem), even before we notice
+ # that the directory named with "test-tool -C" does not exist
+ # and die. It is a dubious thing to test, though.
test_must_fail \
env HOME="$(pwd)/home" GIT_TEST_ENV_HELPER=true \
- test-tool -C cycle env-helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err &&
+ test-tool -C no-such-directory \
+ env-helper --type=bool --default=0 \
+ --exit-code GIT_TEST_ENV_HELPER 2>err &&
grep "exceeded maximum include depth" err
'
diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh
index c13057a4ca..9a3db02fde 100755
--- a/t/t0018-advice.sh
+++ b/t/t0018-advice.sh
@@ -2,7 +2,9 @@
test_description='Test advise_if_enabled functionality'
-TEST_PASSES_SANITIZE_LEAK=true
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=trunk
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
. ./test-lib.sh
test_expect_success 'advice should be printed when config variable is unset' '
@@ -17,7 +19,6 @@ test_expect_success 'advice should be printed when config variable is unset' '
test_expect_success 'advice should be printed when config variable is set to true' '
cat >expect <<-\EOF &&
hint: This is a piece of advice
- hint: Disable this message with "git config advice.nestedTag false"
EOF
test_config advice.nestedTag true &&
test-tool advise "This is a piece of advice" 2>actual &&
@@ -30,4 +31,71 @@ test_expect_success 'advice should not be printed when config variable is set to
test_must_be_empty actual
'
+test_expect_success 'advice should not be printed when --no-advice is used' '
+ q_to_tab >expect <<-\EOF &&
+ On branch trunk
+
+ No commits yet
+
+ Untracked files:
+ QREADME
+
+ nothing added to commit but untracked files present
+ EOF
+
+ test_when_finished "rm -fr advice-test" &&
+ git init advice-test &&
+ (
+ cd advice-test &&
+ >README &&
+ git --no-advice status
+ ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'advice should not be printed when GIT_ADVICE is set to false' '
+ q_to_tab >expect <<-\EOF &&
+ On branch trunk
+
+ No commits yet
+
+ Untracked files:
+ QREADME
+
+ nothing added to commit but untracked files present
+ EOF
+
+ test_when_finished "rm -fr advice-test" &&
+ git init advice-test &&
+ (
+ cd advice-test &&
+ >README &&
+ GIT_ADVICE=false git status
+ ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'advice should be printed when GIT_ADVICE is set to true' '
+ q_to_tab >expect <<-\EOF &&
+ On branch trunk
+
+ No commits yet
+
+ Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+ QREADME
+
+ nothing added to commit but untracked files present (use "git add" to track)
+ EOF
+
+ test_when_finished "rm -fr advice-test" &&
+ git init advice-test &&
+ (
+ cd advice-test &&
+ >README &&
+ GIT_ADVICE=true git status
+ ) >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0019-json-writer.sh b/t/t0019-json-writer.sh
index 19a730c29e..3a4e1cc7e3 100755
--- a/t/t0019-json-writer.sh
+++ b/t/t0019-json-writer.sh
@@ -2,7 +2,6 @@
test_description='test json-writer JSON generation'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'unit test of json-writer routines' '
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 81946e87cc..fd1cae09ed 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -5,7 +5,6 @@ test_description='CRLF conversion'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
has_cr() {
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 46abbeed68..3f6433d304 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -263,7 +263,7 @@ test_expect_success 'required filter with absent clean field' '
echo test >test.ac &&
test_must_fail git add test.ac 2>stderr &&
- test_i18ngrep "fatal: test.ac: clean filter .absentclean. failed" stderr
+ test_grep "fatal: test.ac: clean filter .absentclean. failed" stderr
'
test_expect_success 'required filter with absent smudge field' '
@@ -276,7 +276,7 @@ test_expect_success 'required filter with absent smudge field' '
git add test.as &&
rm -f test.as &&
test_must_fail git checkout -- test.as 2>stderr &&
- test_i18ngrep "fatal: test.as: smudge filter absentsmudge failed" stderr
+ test_grep "fatal: test.as: smudge filter absentsmudge failed" stderr
'
test_expect_success 'filtering large input to small output should use little memory' '
@@ -733,7 +733,7 @@ test_expect_success 'process filter should restart after unexpected write failur
git checkout --quiet --no-progress . 2>git-stderr.log &&
grep "smudge write error" git-stderr.log &&
- test_i18ngrep "error: external filter" git-stderr.log &&
+ test_grep "error: external filter" git-stderr.log &&
cat >expected.log <<-EOF &&
START
@@ -1115,11 +1115,11 @@ do
test_delayed_checkout_progress test_terminal git checkout $opt
'
- test_expect_success PERL "delayed checkout ommits progress on non-tty ($mode checkout)" '
+ test_expect_success PERL "delayed checkout omits progress on non-tty ($mode checkout)" '
test_delayed_checkout_progress ! git checkout $opt
'
- test_expect_success PERL,TTY "delayed checkout ommits progress with --quiet ($mode checkout)" '
+ test_expect_success PERL,TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt
'
diff --git a/t/t0022-crlf-rename.sh b/t/t0022-crlf-rename.sh
index 9fe9891251..9bd863a970 100755
--- a/t/t0022-crlf-rename.sh
+++ b/t/t0022-crlf-rename.sh
@@ -2,7 +2,6 @@
test_description='ignore CR in CRLF sequence while computing similiarity'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh
index 575805513a..f9bbb91f64 100755
--- a/t/t0023-crlf-am.sh
+++ b/t/t0023-crlf-am.sh
@@ -2,7 +2,6 @@
test_description='Test am with auto.crlf'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >patchfile <<\EOF
diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh
index a34de56420..44958cb2c2 100755
--- a/t/t0024-crlf-archive.sh
+++ b/t/t0024-crlf-archive.sh
@@ -2,14 +2,13 @@
test_description='respect crlf in git archive'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
git config core.autocrlf true &&
- printf "CRLF line ending\r\nAnd another\r\n" > sample &&
+ printf "CRLF line ending\r\nAnd another\r\n" >sample &&
git add sample &&
test_tick &&
@@ -19,8 +18,9 @@ test_expect_success setup '
test_expect_success 'tar archive' '
- git archive --format=tar HEAD |
- ( mkdir untarred && cd untarred && "$TAR" -xf - ) &&
+ git archive --format=tar HEAD >test.tar &&
+ mkdir untarred &&
+ "$TAR" xf test.tar -C untarred &&
test_cmp sample untarred/sample
@@ -30,7 +30,11 @@ test_expect_success UNZIP 'zip archive' '
git archive --format=zip HEAD >test.zip &&
- ( mkdir unzipped && cd unzipped && "$GIT_UNZIP" ../test.zip ) &&
+ mkdir unzipped &&
+ (
+ cd unzipped &&
+ "$GIT_UNZIP" ../test.zip
+ ) &&
test_cmp sample unzipped/sample
diff --git a/t/t0025-crlf-renormalize.sh b/t/t0025-crlf-renormalize.sh
index f7202c192e..2e28feb69c 100755
--- a/t/t0025-crlf-renormalize.sh
+++ b/t/t0025-crlf-renormalize.sh
@@ -2,7 +2,6 @@
test_description='CRLF renormalization'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t0026-eol-config.sh b/t/t0026-eol-config.sh
index f426a185bb..493b01a0e7 100755
--- a/t/t0026-eol-config.sh
+++ b/t/t0026-eol-config.sh
@@ -2,7 +2,6 @@
test_description='CRLF conversion'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
has_cr() {
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 2f57c8669c..49dbf09da7 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -2,7 +2,6 @@
test_description='CRLF conversion all combinations'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
compare_files () {
diff --git a/t/t0028-working-tree-encoding.sh b/t/t0028-working-tree-encoding.sh
index c196fdb0ee..50b3b4649b 100755
--- a/t/t0028-working-tree-encoding.sh
+++ b/t/t0028-working-tree-encoding.sh
@@ -5,13 +5,18 @@ test_description='working-tree-encoding conversion via gitattributes'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
TEST_CREATE_REPO_NO_TEMPLATE=1
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-encoding.sh"
GIT_TRACE_WORKING_TREE_ENCODING=1 && export GIT_TRACE_WORKING_TREE_ENCODING
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping working tree encoding tests; iconv not available'
+ test_done
+fi
+
test_expect_success 'setup test files' '
git config core.eol lf &&
@@ -92,23 +97,23 @@ do
# In these cases the BOM is prohibited.
cp bebom.utf${i}be.raw bebom.utf${i}be &&
test_must_fail git add bebom.utf${i}be 2>err.out &&
- test_i18ngrep "fatal: BOM is prohibited .* utf-${i}be" err.out &&
- test_i18ngrep "use UTF-${i} as working-tree-encoding" err.out &&
+ test_grep "fatal: BOM is prohibited .* utf-${i}be" err.out &&
+ test_grep "use UTF-${i} as working-tree-encoding" err.out &&
cp lebom.utf${i}le.raw lebom.utf${i}be &&
test_must_fail git add lebom.utf${i}be 2>err.out &&
- test_i18ngrep "fatal: BOM is prohibited .* utf-${i}be" err.out &&
- test_i18ngrep "use UTF-${i} as working-tree-encoding" err.out &&
+ test_grep "fatal: BOM is prohibited .* utf-${i}be" err.out &&
+ test_grep "use UTF-${i} as working-tree-encoding" err.out &&
cp bebom.utf${i}be.raw bebom.utf${i}le &&
test_must_fail git add bebom.utf${i}le 2>err.out &&
- test_i18ngrep "fatal: BOM is prohibited .* utf-${i}LE" err.out &&
- test_i18ngrep "use UTF-${i} as working-tree-encoding" err.out &&
+ test_grep "fatal: BOM is prohibited .* utf-${i}LE" err.out &&
+ test_grep "use UTF-${i} as working-tree-encoding" err.out &&
cp lebom.utf${i}le.raw lebom.utf${i}le &&
test_must_fail git add lebom.utf${i}le 2>err.out &&
- test_i18ngrep "fatal: BOM is prohibited .* utf-${i}LE" err.out &&
- test_i18ngrep "use UTF-${i} as working-tree-encoding" err.out
+ test_grep "fatal: BOM is prohibited .* utf-${i}LE" err.out &&
+ test_grep "use UTF-${i} as working-tree-encoding" err.out
'
test_expect_success "check required UTF-${i} BOM" '
@@ -118,21 +123,21 @@ do
cp nobom.utf${i}be.raw nobom.utf${i} &&
test_must_fail git add nobom.utf${i} 2>err.out &&
- test_i18ngrep "fatal: BOM is required .* utf-${i}" err.out &&
- test_i18ngrep "use UTF-${i}BE or UTF-${i}LE" err.out &&
+ test_grep "fatal: BOM is required .* utf-${i}" err.out &&
+ test_grep "use UTF-${i}BE or UTF-${i}LE" err.out &&
cp nobom.utf${i}le.raw nobom.utf${i} &&
test_must_fail git add nobom.utf${i} 2>err.out &&
- test_i18ngrep "fatal: BOM is required .* utf-${i}" err.out &&
- test_i18ngrep "use UTF-${i}BE or UTF-${i}LE" err.out
+ test_grep "fatal: BOM is required .* utf-${i}" err.out &&
+ test_grep "use UTF-${i}BE or UTF-${i}LE" err.out
'
test_expect_success "eol conversion for UTF-${i} encoded files on checkout" '
test_when_finished "rm -f crlf.utf${i}.raw lf.utf${i}.raw" &&
test_when_finished "git reset --hard HEAD^" &&
- cat lf.utf8.raw | write_utf${i} >lf.utf${i}.raw &&
- cat crlf.utf8.raw | write_utf${i} >crlf.utf${i}.raw &&
+ write_utf${i} <lf.utf8.raw >lf.utf${i}.raw &&
+ write_utf${i} <crlf.utf8.raw >crlf.utf${i}.raw &&
cp crlf.utf${i}.raw eol.utf${i} &&
cat >expectIndexLF <<-EOF &&
@@ -169,7 +174,7 @@ test_expect_success 'check unsupported encodings' '
echo "*.set text working-tree-encoding" >.gitattributes &&
printf "set" >t.set &&
test_must_fail git add t.set 2>err.out &&
- test_i18ngrep "true/false are no valid working-tree-encodings" err.out &&
+ test_grep "true/false are no valid working-tree-encodings" err.out &&
echo "*.unset text -working-tree-encoding" >.gitattributes &&
printf "unset" >t.unset &&
@@ -182,7 +187,7 @@ test_expect_success 'check unsupported encodings' '
echo "*.garbage text working-tree-encoding=garbage" >.gitattributes &&
printf "garbage" >t.garbage &&
test_must_fail git add t.garbage 2>err.out &&
- test_i18ngrep "failed to encode" err.out
+ test_grep "failed to encode" err.out
'
test_expect_success 'error if encoding round trip is not the same during refresh' '
@@ -201,7 +206,7 @@ test_expect_success 'error if encoding round trip is not the same during refresh
git update-ref refs/heads/main $COMMIT &&
test_must_fail git checkout HEAD^ 2>err.out &&
- test_i18ngrep "error: .* overwritten by checkout:" err.out
+ test_grep "error: .* overwritten by checkout:" err.out
'
test_expect_success 'error if encoding garbage is already in Git' '
@@ -217,7 +222,7 @@ test_expect_success 'error if encoding garbage is already in Git' '
git update-ref refs/heads/main $COMMIT &&
git diff 2>err.out &&
- test_i18ngrep "error: BOM is required" err.out
+ test_grep "error: BOM is required" err.out
'
test_lazy_prereq ICONV_SHIFT_JIS '
diff --git a/t/t0029-core-unsetenvvars.sh b/t/t0029-core-unsetenvvars.sh
index 4e8e90dd98..baa1b7e85b 100755
--- a/t/t0029-core-unsetenvvars.sh
+++ b/t/t0029-core-unsetenvvars.sh
@@ -2,7 +2,6 @@
test_description='test the Windows-only core.unsetenvvars setting'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
if ! test_have_prereq MINGW
diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh
index d1b3be8725..43155f6bd8 100755
--- a/t/t0030-stripspace.sh
+++ b/t/t0030-stripspace.sh
@@ -5,7 +5,6 @@
test_description='git stripspace'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
t40='A quick brown fox jumps over the lazy do'
@@ -401,6 +400,21 @@ test_expect_success 'strip comments with changed comment char' '
test -z "$(echo "; comment" | git -c core.commentchar=";" stripspace -s)"
'
+test_expect_success 'strip comments with changed comment string' '
+ test ! -z "$(echo "// comment" | git -c core.commentchar=// stripspace)" &&
+ test -z "$(echo "// comment" | git -c core.commentchar="//" stripspace -s)"
+'
+
+test_expect_success 'newline as commentchar is forbidden' '
+ test_must_fail git -c core.commentChar="$LF" stripspace -s 2>err &&
+ grep "core.commentchar cannot contain newline" err
+'
+
+test_expect_success 'empty commentchar is forbidden' '
+ test_must_fail git -c core.commentchar= stripspace -s 2>err &&
+ grep "core.commentchar must have at least one character" err
+'
+
test_expect_success '-c with single line' '
printf "# foo\n" >expect &&
printf "foo" | git stripspace -c >actual &&
diff --git a/t/t0032-reftable-unittest.sh b/t/t0032-reftable-unittest.sh
deleted file mode 100755
index 471cb37ac2..0000000000
--- a/t/t0032-reftable-unittest.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2020 Google LLC
-#
-
-test_description='reftable unittests'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_expect_success 'unittests' '
- TMPDIR=$(pwd) && export TMPDIR &&
- test-tool reftable
-'
-
-test_done
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
index 11c3e8f28e..e103fe7109 100755
--- a/t/t0033-safe-directory.sh
+++ b/t/t0033-safe-directory.sh
@@ -2,7 +2,6 @@
test_description='verify safe.directory checks'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
GIT_TEST_ASSUME_DIFFERENT_OWNER=1
@@ -71,7 +70,22 @@ test_expect_success 'safe.directory=*, but is reset' '
expect_rejected_dir
'
+test_expect_success 'safe.directory with matching glob' '
+ git config --global --unset-all safe.directory &&
+ p=$(pwd) &&
+ git config --global safe.directory "${p%/*}/*" &&
+ git status
+'
+
+test_expect_success 'safe.directory with unmatching glob' '
+ git config --global --unset-all safe.directory &&
+ p=$(pwd) &&
+ git config --global safe.directory "${p%/*}no/*" &&
+ expect_rejected_dir
+'
+
test_expect_success 'safe.directory in included file' '
+ git config --global --unset-all safe.directory &&
cat >gitconfig-include <<-EOF &&
[safe]
directory = "$(pwd)"
@@ -104,4 +118,182 @@ test_expect_success 'local clone of unowned repo accepted in safe directory' '
test_path_is_dir target
'
+test_expect_success SYMLINKS 'checked paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ git init repository &&
+ ln -s repository repo &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repository"
+ ) &&
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repo for-each-ref &&
+ git -C repo/ for-each-ref &&
+ test_must_fail git -C repository/.git for-each-ref &&
+ test_must_fail git -C repository/.git/ for-each-ref &&
+ test_must_fail git -C repo/.git for-each-ref &&
+ test_must_fail git -C repo/.git/ for-each-ref
+'
+
+test_expect_success SYMLINKS 'checked leading paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository &&
+ git init repository/s &&
+ ln -s repository repo &&
+ (
+ cd repository/s &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repository/*"
+ ) &&
+ git -C repository/s for-each-ref &&
+ git -C repository/s/ for-each-ref &&
+ git -C repo/s for-each-ref &&
+ git -C repo/s/ for-each-ref &&
+ git -C repository/s/.git for-each-ref &&
+ git -C repository/s/.git/ for-each-ref &&
+ git -C repo/s/.git for-each-ref &&
+ git -C repo/s/.git/ for-each-ref
+'
+
+test_expect_success SYMLINKS 'configured paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ git init repository &&
+ ln -s repository repo &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repo"
+ ) &&
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repo for-each-ref &&
+ git -C repo/ for-each-ref &&
+ test_must_fail git -C repository/.git for-each-ref &&
+ test_must_fail git -C repository/.git/ for-each-ref &&
+ test_must_fail git -C repo/.git for-each-ref &&
+ test_must_fail git -C repo/.git/ for-each-ref
+'
+
+test_expect_success SYMLINKS 'configured leading paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository &&
+ git init repository/s &&
+ ln -s repository repo &&
+ (
+ cd repository/s &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repo/*"
+ ) &&
+ git -C repository/s for-each-ref &&
+ git -C repository/s/ for-each-ref &&
+ git -C repository/s/.git for-each-ref &&
+ git -C repository/s/.git/ for-each-ref &&
+ git -C repo/s for-each-ref &&
+ git -C repo/s/ for-each-ref &&
+ git -C repo/s/.git for-each-ref &&
+ git -C repo/s/.git/ for-each-ref
+'
+
+test_expect_success 'safe.directory set to a dot' '
+ test_when_finished "rm -rf repository" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository/subdir &&
+ git init repository &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "."
+ ) &&
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repository/.git for-each-ref &&
+ git -C repository/.git/ for-each-ref &&
+
+ # What is allowed is repository/subdir but the repository
+ # path is repository.
+ test_must_fail git -C repository/subdir for-each-ref &&
+
+ # Likewise, repository .git/refs is allowed with "." but
+ # repository/.git that is accessed is not allowed.
+ test_must_fail git -C repository/.git/refs for-each-ref
+'
+
+test_expect_success 'safe.directory set to asterisk' '
+ test_when_finished "rm -rf repository" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository/subdir &&
+ git init repository &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "*"
+ ) &&
+ # these are trivial
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repository/.git for-each-ref &&
+ git -C repository/.git/ for-each-ref &&
+
+ # With "*", everything is allowed, and the repository is
+ # discovered, which is different behaviour from "." above.
+ git -C repository/subdir for-each-ref &&
+
+ # Likewise.
+ git -C repository/.git/refs for-each-ref
+'
+
test_done
diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh
index 038b8b788d..ae7ef092ab 100755
--- a/t/t0035-safe-bare-repository.sh
+++ b/t/t0035-safe-bare-repository.sh
@@ -2,7 +2,6 @@
test_description='verify safe.bareRepository checks'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pwd="$(pwd)"
@@ -29,9 +28,20 @@ expect_rejected () {
grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
}
-test_expect_success 'setup bare repo in worktree' '
+test_expect_success 'setup an embedded bare repo, secondary worktree and submodule' '
git init outer-repo &&
- git init --bare outer-repo/bare-repo
+ git init --bare --initial-branch=main outer-repo/bare-repo &&
+ git -C outer-repo worktree add ../outer-secondary &&
+ test_path_is_dir outer-secondary &&
+ (
+ cd outer-repo &&
+ test_commit A &&
+ git push bare-repo +HEAD:refs/heads/main &&
+ git -c protocol.file.allow=always \
+ submodule add --name subn -- ./bare-repo subd
+ ) &&
+ test_path_is_dir outer-repo/.git/worktrees/outer-secondary &&
+ test_path_is_dir outer-repo/.git/modules/subn
'
test_expect_success 'safe.bareRepository unset' '
@@ -53,8 +63,7 @@ test_expect_success 'safe.bareRepository in the repository' '
# safe.bareRepository must not be "explicit", otherwise
# git config fails with "fatal: not in a git directory" (like
# safe.directory)
- test_config -C outer-repo/bare-repo safe.bareRepository \
- all &&
+ test_config -C outer-repo/bare-repo safe.bareRepository all &&
test_config_global safe.bareRepository explicit &&
expect_rejected -C outer-repo/bare-repo
'
@@ -78,4 +87,20 @@ test_expect_success 'no trace when GIT_DIR is explicitly provided' '
expect_accepted_explicit "$pwd/outer-repo/bare-repo"
'
+test_expect_success 'no trace when "bare repository" is .git' '
+ expect_accepted_implicit -C outer-repo/.git
+'
+
+test_expect_success 'no trace when "bare repository" is a subdir of .git' '
+ expect_accepted_implicit -C outer-repo/.git/objects
+'
+
+test_expect_success 'no trace in $GIT_DIR of secondary worktree' '
+ expect_accepted_implicit -C outer-repo/.git/worktrees/outer-secondary
+'
+
+test_expect_success 'no trace in $GIT_DIR of a submodule' '
+ expect_accepted_implicit -C outer-repo/.git/modules/subn
+'
+
test_done
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index e19a199636..2fe3522305 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -5,7 +5,6 @@
test_description='our own option parser'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >expect <<\EOF
@@ -13,30 +12,36 @@ usage: test-tool parse-options <options>
A helper function for the parse-options API.
- --yes get a boolean
+ --[no-]yes get a boolean
-D, --no-doubt begins with 'no-'
+ --doubt opposite of --no-doubt
-B, --no-fear be brave
- -b, --boolean increment by one
- -4, --or4 bitwise-or boolean with ...0100
- --neg-or4 same as --no-or4
+ -b, --[no-]boolean increment by one
+ -4, --[no-]or4 bitwise-or boolean with ...0100
+ --[no-]neg-or4 same as --no-or4
- -i, --integer <n> get a integer
+ -i, --[no-]integer <n>
+ get a integer
-j <n> get a integer, too
-m, --magnitude <n> get a magnitude
- --set23 set integer to 23
+ --[no-]set23 set integer to 23
--mode1 set integer to 1 (cmdmode option)
--mode2 set integer to 2 (cmdmode option)
- -L, --length <str> get length of <str>
- -F, --file <file> set file to <file>
+ --[no-]mode34 (3|4) set integer to 3 or 4 (cmdmode option)
+ -L, --[no-]length <str>
+ get length of <str>
+ -F, --[no-]file <file>
+ set file to <file>
String options
- -s, --string <string> get a string
- --string2 <str> get another string
- --st <st> get another string (pervert ordering)
+ -s, --[no-]string <string>
+ get a string
+ --[no-]string2 <str> get another string
+ --[no-]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
+ --[no-]list <str> add str to list
Magic arguments
-NUM set integer to NUM
@@ -45,16 +50,17 @@ Magic arguments
--no-ambiguous negative ambiguity
Standard options
- --abbrev[=<n>] use <n> digits to display object names
- -v, --verbose be verbose
- -n, --dry-run dry run
- -q, --quiet be quiet
- --expect <string> expected output in the variable dump
+ --[no-]abbrev[=<n>] use <n> digits to display object names
+ -v, --[no-]verbose be verbose
+ -n, --[no-]dry-run dry run
+ -q, --[no-]quiet be quiet
+ --[no-]expect <string>
+ expected output in the variable dump
Alias
- -A, --alias-source <string>
+ -A, --[no-]alias-source <string>
get a string
- -Z, --alias-target <string>
+ -Z, --[no-]alias-target <string>
alias of --alias-source
EOF
@@ -169,6 +175,23 @@ test_expect_success 'long options' '
test_cmp expect output
'
+test_expect_success 'abbreviate to something longer than SHA1 length' '
+ cat >expect <<-EOF &&
+ boolean: 0
+ integer: 0
+ magnitude: 0
+ timestamp: 0
+ string: (not set)
+ abbrev: 100
+ verbose: -1
+ quiet: 0
+ dry run: no
+ file: (not set)
+ EOF
+ test-tool parse-options --abbrev=100 >output &&
+ test_cmp expect output
+'
+
test_expect_success 'missing required value' '
cat >expect <<-\EOF &&
error: switch `s'\'' requires a value
@@ -203,6 +226,22 @@ test_expect_success 'superfluous value provided: boolean' '
test_cmp expect actual
'
+test_expect_success 'superfluous value provided: boolean, abbreviated' '
+ cat >expect <<-\EOF &&
+ error: option `yes'\'' takes no value
+ EOF
+ test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
+ test-tool parse-options --ye=hi 2>actual &&
+ test_cmp expect actual &&
+
+ cat >expect <<-\EOF &&
+ error: option `no-yes'\'' takes no value
+ EOF
+ test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
+ test-tool parse-options --no-ye=hi 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'superfluous value provided: cmdmode' '
cat >expect <<-\EOF &&
error: option `mode1'\'' takes no value
@@ -360,19 +399,41 @@ test_expect_success 'OPT_NEGBIT() works' '
'
test_expect_success 'OPT_CMDMODE() works' '
- test-tool parse-options --expect="integer: 1" --mode1
+ test-tool parse-options --expect="integer: 1" --mode1 &&
+ test-tool parse-options --expect="integer: 3" --mode34=3
'
-test_expect_success 'OPT_CMDMODE() detects incompatibility' '
+test_expect_success 'OPT_CMDMODE() detects incompatibility (1)' '
test_must_fail test-tool parse-options --mode1 --mode2 >output 2>output.err &&
test_must_be_empty output &&
- test_i18ngrep "incompatible with --mode" output.err
+ test_grep "mode1" output.err &&
+ test_grep "mode2" output.err &&
+ test_grep "cannot be used together" output.err
'
-test_expect_success 'OPT_CMDMODE() detects incompatibility with something else' '
+test_expect_success 'OPT_CMDMODE() detects incompatibility (2)' '
test_must_fail test-tool parse-options --set23 --mode2 >output 2>output.err &&
test_must_be_empty output &&
- test_i18ngrep "incompatible with something else" output.err
+ test_grep "mode2" output.err &&
+ test_grep "set23" output.err &&
+ test_grep "cannot be used together" output.err
+'
+
+test_expect_success 'OPT_CMDMODE() detects incompatibility (3)' '
+ test_must_fail test-tool parse-options --mode2 --set23 >output 2>output.err &&
+ test_must_be_empty output &&
+ test_grep "mode2" output.err &&
+ test_grep "set23" output.err &&
+ test_grep "cannot be used together" output.err
+'
+
+test_expect_success 'OPT_CMDMODE() detects incompatibility (4)' '
+ test_must_fail test-tool parse-options --mode2 --mode34=3 \
+ >output 2>output.err &&
+ test_must_be_empty output &&
+ test_grep "mode2" output.err &&
+ test_grep "mode34.3" output.err &&
+ test_grep "cannot be used together" output.err
'
test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
diff --git a/t/t0041-usage.sh b/t/t0041-usage.sh
index 9ea974b0c6..a0f6f134c7 100755
--- a/t/t0041-usage.sh
+++ b/t/t0041-usage.sh
@@ -5,7 +5,6 @@ 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 ' '
@@ -21,8 +20,8 @@ test_expect_success 'tag --contains <existent_tag>' '
test_expect_success 'tag --contains <inexistent_tag>' '
test_must_fail git tag --contains "notag" >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "error" actual.err &&
- test_i18ngrep ! "usage" actual.err
+ test_grep "error" actual.err &&
+ test_grep ! "usage" actual.err
'
test_expect_success 'tag --no-contains <existent_tag>' '
@@ -34,27 +33,27 @@ test_expect_success 'tag --no-contains <existent_tag>' '
test_expect_success 'tag --no-contains <inexistent_tag>' '
test_must_fail git tag --no-contains "notag" >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "error" actual.err &&
- test_i18ngrep ! "usage" actual.err
+ test_grep "error" actual.err &&
+ test_grep ! "usage" actual.err
'
test_expect_success 'tag usage error' '
test_must_fail git tag --noopt >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "usage" actual.err
+ test_grep "usage" actual.err
'
test_expect_success 'branch --contains <existent_commit>' '
git branch --contains "main" >actual 2>actual.err &&
- test_i18ngrep "main" actual &&
+ test_grep "main" actual &&
test_line_count = 0 actual.err
'
test_expect_success 'branch --contains <inexistent_commit>' '
test_must_fail git branch --no-contains "nocommit" >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "error" actual.err &&
- test_i18ngrep ! "usage" actual.err
+ test_grep "error" actual.err &&
+ test_grep ! "usage" actual.err
'
test_expect_success 'branch --no-contains <existent_commit>' '
@@ -66,14 +65,14 @@ test_expect_success 'branch --no-contains <existent_commit>' '
test_expect_success 'branch --no-contains <inexistent_commit>' '
test_must_fail git branch --no-contains "nocommit" >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "error" actual.err &&
- test_i18ngrep ! "usage" actual.err
+ test_grep "error" actual.err &&
+ test_grep ! "usage" actual.err
'
test_expect_success 'branch usage error' '
test_must_fail git branch --noopt >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "usage" actual.err
+ test_grep "usage" actual.err
'
test_expect_success 'for-each-ref --contains <existent_object>' '
@@ -85,8 +84,8 @@ test_expect_success 'for-each-ref --contains <existent_object>' '
test_expect_success 'for-each-ref --contains <inexistent_object>' '
test_must_fail git for-each-ref --no-contains "noobject" >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "error" actual.err &&
- test_i18ngrep ! "usage" actual.err
+ test_grep "error" actual.err &&
+ test_grep ! "usage" actual.err
'
test_expect_success 'for-each-ref --no-contains <existent_object>' '
@@ -98,14 +97,14 @@ test_expect_success 'for-each-ref --no-contains <existent_object>' '
test_expect_success 'for-each-ref --no-contains <inexistent_object>' '
test_must_fail git for-each-ref --no-contains "noobject" >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "error" actual.err &&
- test_i18ngrep ! "usage" actual.err
+ test_grep "error" actual.err &&
+ test_grep ! "usage" actual.err
'
test_expect_success 'for-each-ref usage error' '
test_must_fail git for-each-ref --noopt >actual 2>actual.err &&
test_line_count = 0 actual &&
- test_i18ngrep "usage" actual.err
+ test_grep "usage" actual.err
'
test_done
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index 325eb1c3cd..5c9dc90d0b 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -5,7 +5,6 @@ test_description='Various filesystem issues'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
auml=$(printf '\303\244')
diff --git a/t/t0052-simple-ipc.sh b/t/t0052-simple-ipc.sh
index 1a36a53574..ff98be31a5 100755
--- a/t/t0052-simple-ipc.sh
+++ b/t/t0052-simple-ipc.sh
@@ -2,7 +2,6 @@
test_description='simple command server'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test-tool simple-ipc SUPPORTS_SIMPLE_IPC || {
diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh
index c3eb1158ef..d0740038b8 100755
--- a/t/t0055-beyond-symlinks.sh
+++ b/t/t0055-beyond-symlinks.sh
@@ -2,7 +2,6 @@
test_description='update-index and add refuse to add beyond symlinks'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success SYMLINKS setup '
diff --git a/t/t0056-git-C.sh b/t/t0056-git-C.sh
index 752aa8c945..2630e756da 100755
--- a/t/t0056-git-C.sh
+++ b/t/t0056-git-C.sh
@@ -2,7 +2,6 @@
test_description='"-C <path>" option and its effects on other path-related options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success '"git -C <path>" runs git from the directory <path>' '
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 0afa3d0d31..dbb2e73bcd 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -5,7 +5,6 @@
test_description='Test various path utilities'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
norm_path() {
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index e2411f6a9b..76d4936a87 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -5,7 +5,6 @@
test_description='Test run command'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >hello-script <<-EOF
@@ -19,12 +18,12 @@ test_expect_success MINGW 'subprocess inherits only std handles' '
test_expect_success 'start_command reports ENOENT (slash)' '
test-tool run-command start-command-ENOENT ./does-not-exist 2>err &&
- test_i18ngrep "\./does-not-exist" err
+ test_grep "\./does-not-exist" err
'
test_expect_success 'start_command reports ENOENT (no slash)' '
test-tool run-command start-command-ENOENT does-not-exist 2>err &&
- test_i18ngrep "does-not-exist" err
+ test_grep "does-not-exist" err
'
test_expect_success 'run_command can run a command' '
@@ -49,7 +48,7 @@ test_expect_success !RUNS_COMMANDS_FROM_PWD 'run_command is restricted to PATH'
echo yikes
EOF
test_must_fail test-tool run-command run-command should-not-run 2>err &&
- test_i18ngrep "should-not-run" err
+ test_grep "should-not-run" err
'
test_expect_success !MINGW 'run_command can run a script without a #! line' '
diff --git a/t/t0062-revision-walking.sh b/t/t0062-revision-walking.sh
index b9480c8178..8e215867b8 100755
--- a/t/t0062-revision-walking.sh
+++ b/t/t0062-revision-walking.sh
@@ -5,7 +5,6 @@
test_description='Test revision walking api'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >run_twice_expected <<-EOF
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
index 1fee6d9010..aac63ba506 100755
--- a/t/t0063-string-list.sh
+++ b/t/t0063-string-list.sh
@@ -5,7 +5,6 @@
test_description='Test string list functionality'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_split () {
diff --git a/t/t0064-oid-array.sh b/t/t0064-oid-array.sh
deleted file mode 100755
index 88c89e8f48..0000000000
--- a/t/t0064-oid-array.sh
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/bin/sh
-
-test_description='basic tests for the oid array implementation'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-echoid () {
- prefix="${1:+$1 }"
- shift
- while test $# -gt 0
- do
- echo "$prefix$ZERO_OID" | sed -e "s/00/$1/g"
- shift
- done
-}
-
-test_expect_success 'ordered enumeration' '
- echoid "" 44 55 88 aa >expect &&
- {
- echoid append 88 44 aa 55 &&
- echo for_each_unique
- } | test-tool oid-array >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'ordered enumeration with duplicate suppression' '
- echoid "" 44 55 88 aa >expect &&
- {
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echo for_each_unique
- } | test-tool oid-array >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'lookup' '
- {
- echoid append 88 44 aa 55 &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -eq 1
-'
-
-test_expect_success 'lookup non-existing entry' '
- {
- echoid append 88 44 aa 55 &&
- echoid lookup 33
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -lt 0
-'
-
-test_expect_success 'lookup with duplicates' '
- {
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -ge 3 &&
- test "$n" -le 5
-'
-
-test_expect_success 'lookup non-existing entry with duplicates' '
- {
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid append 88 44 aa 55 &&
- echoid lookup 66
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -lt 0
-'
-
-test_expect_success 'lookup with almost duplicate values' '
- # n-1 5s
- root=$(echoid "" 55) &&
- root=${root%5} &&
- {
- id1="${root}5" &&
- id2="${root}f" &&
- echo "append $id1" &&
- echo "append $id2" &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -eq 0
-'
-
-test_expect_success 'lookup with single duplicate value' '
- {
- echoid append 55 55 &&
- echoid lookup 55
- } | test-tool oid-array >actual &&
- n=$(cat actual) &&
- test "$n" -ge 0 &&
- test "$n" -le 1
-'
-
-test_done
diff --git a/t/t0065-strcmp-offset.sh b/t/t0065-strcmp-offset.sh
deleted file mode 100755
index 94e34c83ed..0000000000
--- a/t/t0065-strcmp-offset.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-test_description='Test strcmp_offset functionality'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-while read s1 s2 expect
-do
- test_expect_success "strcmp_offset($s1, $s2)" '
- echo "$expect" >expect &&
- test-tool strcmp-offset "$s1" "$s2" >actual &&
- test_cmp expect actual
- '
-done <<-EOF
-abc abc 0 3
-abc def -1 0
-abc abz -1 2
-abc abcdef -1 3
-EOF
-
-test_done
diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh
index 7d0a0da8c0..df3e9f5fa5 100755
--- a/t/t0066-dir-iterator.sh
+++ b/t/t0066-dir-iterator.sh
@@ -2,7 +2,6 @@
test_description='Test the dir-iterator functionality'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t0067-parse_pathspec_file.sh b/t/t0067-parse_pathspec_file.sh
index 0188d0423a..7bab49f361 100755
--- a/t/t0067-parse_pathspec_file.sh
+++ b/t/t0067-parse_pathspec_file.sh
@@ -2,7 +2,6 @@
test_description='Test parse_pathspec_file()'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'one item from stdin' '
diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh
index 4b90b74d5d..f2f3e50031 100755
--- a/t/t0068-for-each-repo.sh
+++ b/t/t0068-for-each-repo.sh
@@ -2,7 +2,6 @@
test_description='git for-each-repo builtin'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'run based on configured value' '
@@ -59,4 +58,20 @@ test_expect_success 'error on NULL value for config keys' '
test_cmp expect actual
'
+test_expect_success '--keep-going' '
+ git config keep.going non-existing &&
+ git config --add keep.going . &&
+
+ test_must_fail git for-each-repo --config=keep.going \
+ -- branch >out 2>err &&
+ test_grep "cannot change to .*non-existing" err &&
+ test_must_be_empty out &&
+
+ test_must_fail git for-each-repo --config=keep.going --keep-going \
+ -- branch >out 2>err &&
+ test_grep "cannot change to .*non-existing" err &&
+ git branch >expect &&
+ test_cmp expect out
+'
+
test_done
diff --git a/t/t0069-oidtree.sh b/t/t0069-oidtree.sh
deleted file mode 100755
index 889db50818..0000000000
--- a/t/t0069-oidtree.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-
-test_description='basic tests for the oidtree implementation'
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-maxhexsz=$(test_oid hexsz)
-echoid () {
- prefix="${1:+$1 }"
- shift
- while test $# -gt 0
- do
- shortoid="$1"
- shift
- difference=$(($maxhexsz - ${#shortoid}))
- printf "%s%s%0${difference}d\\n" "$prefix" "$shortoid" "0"
- done
-}
-
-test_expect_success 'oidtree insert and contains' '
- cat >expect <<-\EOF &&
- 0
- 0
- 0
- 1
- 1
- 0
- EOF
- {
- echoid insert 444 1 2 3 4 5 a b c d e &&
- echoid contains 44 441 440 444 4440 4444 &&
- echo clear
- } | test-tool oidtree >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'oidtree each' '
- echoid "" 123 321 321 >expect &&
- {
- echoid insert f 9 8 123 321 a b c d e &&
- echo each 12300 &&
- echo each 3211 &&
- echo each 3210 &&
- echo each 32100 &&
- echo clear
- } | test-tool oidtree >actual &&
- test_cmp expect actual
-'
-
-test_done
diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh
index 574de34198..6b9dcf984b 100755
--- a/t/t0070-fundamental.sh
+++ b/t/t0070-fundamental.sh
@@ -6,13 +6,8 @@ test_description='check that the most basic functions work
Verify wrappers and compatibility functions.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
-test_expect_success 'character classes (isspace, isalpha etc.)' '
- test-tool ctype
-'
-
test_expect_success 'mktemp to nonexistent directory prints filename' '
test_must_fail test-tool mktemp doesnotexist/testXXXXXX 2>err &&
grep "doesnotexist/test" err
@@ -44,13 +39,71 @@ test_expect_success 'incomplete sideband messages are reassembled' '
test_expect_success 'eof on sideband message is reported' '
printf 1234 >input &&
test-tool pkt-line receive-sideband <input 2>err &&
- test_i18ngrep "unexpected disconnect" err
+ test_grep "unexpected disconnect" err
'
test_expect_success 'missing sideband designator is reported' '
printf 0004 >input &&
test-tool pkt-line receive-sideband <input 2>err &&
- test_i18ngrep "missing sideband" err
+ test_grep "missing sideband" err
+'
+
+test_expect_success 'unpack-sideband: --no-chomp-newline' '
+ test_when_finished "rm -f expect-out expect-err" &&
+ test-tool pkt-line send-split-sideband >split-sideband &&
+ test-tool pkt-line unpack-sideband \
+ --no-chomp-newline <split-sideband >out 2>err &&
+ cat >expect-out <<-EOF &&
+ primary: regular output
+ EOF
+ cat >expect-err <<-EOF &&
+ Foo.
+ Bar.
+ Hello, world!
+ EOF
+ test_cmp expect-out out &&
+ test_cmp expect-err err
+'
+
+test_expect_success 'unpack-sideband: --chomp-newline (default)' '
+ test_when_finished "rm -f expect-out expect-err" &&
+ test-tool pkt-line send-split-sideband >split-sideband &&
+ test-tool pkt-line unpack-sideband \
+ --chomp-newline <split-sideband >out 2>err &&
+ printf "primary: regular output" >expect-out &&
+ printf "Foo.Bar.Hello, world!" >expect-err &&
+ test_cmp expect-out out &&
+ test_cmp expect-err err
+'
+
+test_expect_success 'unpack-sideband: packet_reader_read() consumes sideband, no chomp payload' '
+ test_when_finished "rm -f expect-out expect-err" &&
+ test-tool pkt-line send-split-sideband >split-sideband &&
+ test-tool pkt-line unpack-sideband \
+ --reader-use-sideband \
+ --no-chomp-newline <split-sideband >out 2>err &&
+ cat >expect-out <<-EOF &&
+ primary: regular output
+ EOF
+ printf "remote: Foo. \n" >expect-err &&
+ printf "remote: Bar. \n" >>expect-err &&
+ printf "remote: Hello, world! \n" >>expect-err &&
+ test_cmp expect-out out &&
+ test_cmp expect-err err
+'
+
+test_expect_success 'unpack-sideband: packet_reader_read() consumes sideband, chomp payload' '
+ test_when_finished "rm -f expect-out expect-err" &&
+ test-tool pkt-line send-split-sideband >split-sideband &&
+ test-tool pkt-line unpack-sideband \
+ --reader-use-sideband \
+ --chomp-newline <split-sideband >out 2>err &&
+ printf "primary: regular output" >expect-out &&
+ printf "remote: Foo. \n" >expect-err &&
+ printf "remote: Bar. \n" >>expect-err &&
+ printf "remote: Hello, world! \n" >>expect-err &&
+ test_cmp expect-out out &&
+ test_cmp expect-err err
'
test_done
diff --git a/t/t0071-sort.sh b/t/t0071-sort.sh
index ba8ad1d1ca..2236a7e956 100755
--- a/t/t0071-sort.sh
+++ b/t/t0071-sort.sh
@@ -2,7 +2,6 @@
test_description='verify sort functions'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'DEFINE_LIST_SORT_DEBUG' '
diff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh
new file mode 100755
index 0000000000..3db10f095c
--- /dev/null
+++ b/t/t0080-unit-test-output.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='Test the output of the unit test framework'
+
+. ./test-lib.sh
+
+test_expect_success 'TAP output from unit tests' - <<\EOT
+ cat >expect <<-EOF &&
+ # BUG: check outside of test at t/helper/test-example-tap.c:75
+ ok 1 - passing test
+ ok 2 - passing test and assertion return 1
+ # check "1 == 2" failed at t/helper/test-example-tap.c:79
+ # left: 1
+ # right: 2
+ not ok 3 - failing test
+ ok 4 - failing test and assertion return 0
+ not ok 5 - passing TEST_TODO() # TODO
+ ok 6 - passing TEST_TODO() returns 1
+ # todo check 'check(x)' succeeded at t/helper/test-example-tap.c:26
+ not ok 7 - failing TEST_TODO()
+ ok 8 - failing TEST_TODO() returns 0
+ # check "0" failed at t/helper/test-example-tap.c:31
+ # skipping test - missing prerequisite
+ # skipping check '1' at t/helper/test-example-tap.c:33
+ ok 9 - test_skip() # SKIP
+ ok 10 - skipped test returns 1
+ # skipping test - missing prerequisite
+ ok 11 - test_skip() inside TEST_TODO() # SKIP
+ ok 12 - test_skip() inside TEST_TODO() returns 1
+ # check "0" failed at t/helper/test-example-tap.c:49
+ not ok 13 - TEST_TODO() after failing check
+ ok 14 - TEST_TODO() after failing check returns 0
+ # check "0" failed at t/helper/test-example-tap.c:57
+ not ok 15 - failing check after TEST_TODO()
+ ok 16 - failing check after TEST_TODO() returns 0
+ # check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:62
+ # left: "\011hello\\\\"
+ # right: "there\"\012"
+ # check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:63
+ # left: "NULL"
+ # right: NULL
+ # check "'a' == '\n'" failed at t/helper/test-example-tap.c:64
+ # left: 'a'
+ # right: '\012'
+ # check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:65
+ # left: '\\\\'
+ # right: '\\''
+ not ok 17 - messages from failing string and char comparison
+ # BUG: test has no checks at t/helper/test-example-tap.c:94
+ not ok 18 - test with no checks
+ ok 19 - test with no checks returns 0
+ ok 20 - if_test passing test
+ # check "1 == 2" failed at t/helper/test-example-tap.c:100
+ # left: 1
+ # right: 2
+ not ok 21 - if_test failing test
+ not ok 22 - if_test passing TEST_TODO() # TODO
+ # todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104
+ not ok 23 - if_test failing TEST_TODO()
+ # check "0" failed at t/helper/test-example-tap.c:106
+ # skipping test - missing prerequisite
+ # skipping check '1' at t/helper/test-example-tap.c:108
+ ok 24 - if_test test_skip() # SKIP
+ # skipping test - missing prerequisite
+ ok 25 - if_test test_skip() inside TEST_TODO() # SKIP
+ # check "0" failed at t/helper/test-example-tap.c:113
+ not ok 26 - if_test TEST_TODO() after failing check
+ # check "0" failed at t/helper/test-example-tap.c:119
+ not ok 27 - if_test failing check after TEST_TODO()
+ # check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:122
+ # left: "\011hello\\\\"
+ # right: "there\"\012"
+ # check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:123
+ # left: "NULL"
+ # right: NULL
+ # check "'a' == '\n'" failed at t/helper/test-example-tap.c:124
+ # left: 'a'
+ # right: '\012'
+ # check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:125
+ # left: '\\\\'
+ # right: '\\''
+ not ok 28 - if_test messages from failing string and char comparison
+ # BUG: test has no checks at t/helper/test-example-tap.c:127
+ not ok 29 - if_test test with no checks
+ 1..29
+ EOF
+
+ ! test-tool example-tap >actual &&
+ test_cmp expect actual
+EOT
+
+test_done
diff --git a/t/t0081-find-pack.sh b/t/t0081-find-pack.sh
new file mode 100755
index 0000000000..5a628bf735
--- /dev/null
+++ b/t/t0081-find-pack.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+test_description='test `test-tool find-pack`'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ test_commit four &&
+ test_commit five
+'
+
+test_expect_success 'repack everything into a single packfile' '
+ git repack -a -d --no-write-bitmap-index &&
+
+ head_commit_pack=$(test-tool find-pack HEAD) &&
+ head_tree_pack=$(test-tool find-pack HEAD^{tree}) &&
+ one_pack=$(test-tool find-pack HEAD:one.t) &&
+ three_pack=$(test-tool find-pack HEAD:three.t) &&
+ old_commit_pack=$(test-tool find-pack HEAD~4) &&
+
+ test-tool find-pack --check-count 1 HEAD &&
+ test-tool find-pack --check-count=1 HEAD^{tree} &&
+ ! test-tool find-pack --check-count=0 HEAD:one.t &&
+ ! test-tool find-pack -c 2 HEAD:one.t &&
+ test-tool find-pack -c 1 HEAD:three.t &&
+
+ # Packfile exists at the right path
+ case "$head_commit_pack" in
+ ".git/objects/pack/pack-"*".pack") true ;;
+ *) false ;;
+ esac &&
+ test -f "$head_commit_pack" &&
+
+ # Everything is in the same pack
+ test "$head_commit_pack" = "$head_tree_pack" &&
+ test "$head_commit_pack" = "$one_pack" &&
+ test "$head_commit_pack" = "$three_pack" &&
+ test "$head_commit_pack" = "$old_commit_pack"
+'
+
+test_expect_success 'add more packfiles' '
+ git rev-parse HEAD^{tree} HEAD:two.t HEAD:four.t >objects &&
+ git pack-objects .git/objects/pack/mypackname1 >packhash1 <objects &&
+
+ git rev-parse HEAD~ HEAD~^{tree} HEAD:five.t >objects &&
+ git pack-objects .git/objects/pack/mypackname2 >packhash2 <objects &&
+
+ head_commit_pack=$(test-tool find-pack HEAD) &&
+
+ # HEAD^{tree} is in 2 packfiles
+ test-tool find-pack HEAD^{tree} >head_tree_packs &&
+ grep "$head_commit_pack" head_tree_packs &&
+ grep mypackname1 head_tree_packs &&
+ ! grep mypackname2 head_tree_packs &&
+ test-tool find-pack --check-count 2 HEAD^{tree} &&
+ ! test-tool find-pack --check-count 1 HEAD^{tree} &&
+
+ # HEAD:five.t is also in 2 packfiles
+ test-tool find-pack HEAD:five.t >five_packs &&
+ grep "$head_commit_pack" five_packs &&
+ ! grep mypackname1 five_packs &&
+ grep mypackname2 five_packs &&
+ test-tool find-pack -c 2 HEAD:five.t &&
+ ! test-tool find-pack --check-count=0 HEAD:five.t
+'
+
+test_expect_success 'add more commits (as loose objects)' '
+ test_commit six &&
+ test_commit seven &&
+
+ test -z "$(test-tool find-pack HEAD)" &&
+ test -z "$(test-tool find-pack HEAD:six.t)" &&
+ test-tool find-pack --check-count 0 HEAD &&
+ test-tool find-pack -c 0 HEAD:six.t &&
+ ! test-tool find-pack -c 1 HEAD:seven.t
+'
+
+test_done
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index d8e2fc42e1..ab80c9ef13 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -6,7 +6,6 @@ Tests whether various commands properly update and/or rewrite the
cache-tree extension.
"
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cmp_cache_tree () {
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
index f6998269be..e11d819b62 100755
--- a/t/t0091-bugreport.sh
+++ b/t/t0091-bugreport.sh
@@ -2,7 +2,6 @@
test_description='git bugreport'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create a report' '
@@ -39,9 +38,9 @@ test_expect_success 'sanity check "System Info" section' '
sed -ne "/^\[System Info\]$/,/^$/p" <git-bugreport-format.txt >system &&
- # The beginning should match "git version --build-info" verbatim,
+ # The beginning should match "git version --build-options" verbatim,
# but rather than checking bit-for-bit equality, just test some basics.
- grep "git version [0-9]." system &&
+ grep "git version " system &&
grep "shell-path: ." system &&
# After the version, there should be some more info.
@@ -65,7 +64,14 @@ test_expect_success '--output-directory puts the report in the provided dir' '
test_expect_success 'incorrect arguments abort with usage' '
test_must_fail git bugreport --false 2>output &&
- test_i18ngrep usage output &&
+ test_grep usage output &&
+ test_path_is_missing git-bugreport-*
+'
+
+test_expect_success 'incorrect positional arguments abort with usage and hint' '
+ test_must_fail git bugreport false 2>output &&
+ test_grep usage output &&
+ test_grep false output &&
test_path_is_missing git-bugreport-*
'
diff --git a/t/t0092-diagnose.sh b/t/t0092-diagnose.sh
index 133e5747d6..6cabd6e67b 100755
--- a/t/t0092-diagnose.sh
+++ b/t/t0092-diagnose.sh
@@ -2,7 +2,6 @@
test_description='git diagnose'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success UNZIP 'creates diagnostics zip archive' '
diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh
index b567383eb8..8f0c3b7325 100755
--- a/t/t0095-bloom.sh
+++ b/t/t0095-bloom.sh
@@ -2,7 +2,6 @@
test_description='Testing the various Bloom filter computations in bloom.c'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'compute unseeded murmur3 hash for empty string' '
@@ -29,6 +28,14 @@ test_expect_success 'compute unseeded murmur3 hash for test string 2' '
test_cmp expect actual
'
+test_expect_success 'compute unseeded murmur3 hash for test string 3' '
+ cat >expect <<-\EOF &&
+ Murmur3 Hash with seed=0:0xa183ccfd
+ EOF
+ test-tool bloom get_murmur3_seven_highbit >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'compute bloom key for empty string' '
cat >expect <<-\EOF &&
Hashes:0x5615800c|0x5b966560|0x61174ab4|0x66983008|0x6c19155c|0x7199fab0|0x771ae004|
@@ -69,7 +76,7 @@ test_expect_success 'compute bloom key for test string 2' '
test_cmp expect actual
'
-test_expect_success !SANITIZE_LEAK 'get bloom filters for commit with no changes' '
+test_expect_success 'get bloom filters for commit with no changes' '
git init &&
git commit --allow-empty -m "c0" &&
cat >expect <<-\EOF &&
diff --git a/t/t0100-previous.sh b/t/t0100-previous.sh
index 70a3223f21..dd5d9b4e5e 100755
--- a/t/t0100-previous.sh
+++ b/t/t0100-previous.sh
@@ -5,7 +5,6 @@ test_description='previous branch syntax @{-n}'
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 'branch -d @{-1}' '
diff --git a/t/t0101-at-syntax.sh b/t/t0101-at-syntax.sh
index 878aadd64c..023b4c6f0b 100755
--- a/t/t0101-at-syntax.sh
+++ b/t/t0101-at-syntax.sh
@@ -2,7 +2,6 @@
test_description='various @{whatever} syntax tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh
deleted file mode 100755
index 12d817fbd3..0000000000
--- a/t/t0110-urlmatch-normalization.sh
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/bin/sh
-
-test_description='urlmatch URL normalization'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-# The base name of the test url files
-tu="$TEST_DIRECTORY/t0110/url"
-
-# Note that only file: URLs should be allowed without a host
-
-test_expect_success 'url scheme' '
- ! test-tool urlmatch-normalization "" &&
- ! test-tool urlmatch-normalization "_" &&
- ! test-tool urlmatch-normalization "scheme" &&
- ! test-tool urlmatch-normalization "scheme:" &&
- ! test-tool urlmatch-normalization "scheme:/" &&
- ! test-tool urlmatch-normalization "scheme://" &&
- ! test-tool urlmatch-normalization "file" &&
- ! test-tool urlmatch-normalization "file:" &&
- ! test-tool urlmatch-normalization "file:/" &&
- test-tool urlmatch-normalization "file://" &&
- ! test-tool urlmatch-normalization "://acme.co" &&
- ! test-tool urlmatch-normalization "x_test://acme.co" &&
- ! test-tool urlmatch-normalization "-test://acme.co" &&
- ! test-tool urlmatch-normalization "0test://acme.co" &&
- ! test-tool urlmatch-normalization "+test://acme.co" &&
- ! test-tool urlmatch-normalization ".test://acme.co" &&
- ! test-tool urlmatch-normalization "schem%6e://" &&
- test-tool urlmatch-normalization "x-Test+v1.0://acme.co" &&
- test "$(test-tool urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/"
-'
-
-test_expect_success 'url authority' '
- ! test-tool urlmatch-normalization "scheme://user:pass@" &&
- ! test-tool urlmatch-normalization "scheme://?" &&
- ! test-tool urlmatch-normalization "scheme://#" &&
- ! test-tool urlmatch-normalization "scheme:///" &&
- ! test-tool urlmatch-normalization "scheme://:" &&
- ! test-tool urlmatch-normalization "scheme://:555" &&
- test-tool urlmatch-normalization "file://user:pass@" &&
- test-tool urlmatch-normalization "file://?" &&
- test-tool urlmatch-normalization "file://#" &&
- test-tool urlmatch-normalization "file:///" &&
- test-tool urlmatch-normalization "file://:" &&
- ! test-tool urlmatch-normalization "file://:555" &&
- test-tool urlmatch-normalization "scheme://user:pass@host" &&
- test-tool urlmatch-normalization "scheme://@host" &&
- test-tool urlmatch-normalization "scheme://%00@host" &&
- ! test-tool urlmatch-normalization "scheme://%%@host" &&
- test-tool urlmatch-normalization "scheme://host_" &&
- test-tool urlmatch-normalization "scheme://user:pass@host/" &&
- test-tool urlmatch-normalization "scheme://@host/" &&
- test-tool urlmatch-normalization "scheme://host/" &&
- test-tool urlmatch-normalization "scheme://host?x" &&
- test-tool urlmatch-normalization "scheme://host#x" &&
- test-tool urlmatch-normalization "scheme://host/@" &&
- test-tool urlmatch-normalization "scheme://host?@x" &&
- test-tool urlmatch-normalization "scheme://host#@x" &&
- test-tool urlmatch-normalization "scheme://[::1]" &&
- test-tool urlmatch-normalization "scheme://[::1]/" &&
- ! test-tool urlmatch-normalization "scheme://hos%41/" &&
- test-tool urlmatch-normalization "scheme://[invalid....:/" &&
- test-tool urlmatch-normalization "scheme://invalid....:]/" &&
- ! test-tool urlmatch-normalization "scheme://invalid....:[/" &&
- ! test-tool urlmatch-normalization "scheme://invalid....:["
-'
-
-test_expect_success 'url port checks' '
- test-tool urlmatch-normalization "xyz://q@some.host:" &&
- test-tool urlmatch-normalization "xyz://q@some.host:456/" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:0" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:0000000" &&
- test-tool urlmatch-normalization "xyz://q@some.host:0000001?" &&
- test-tool urlmatch-normalization "xyz://q@some.host:065535#" &&
- test-tool urlmatch-normalization "xyz://q@some.host:65535" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:65536" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:99999" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:100000" &&
- ! test-tool urlmatch-normalization "xyz://q@some.host:100001" &&
- test-tool urlmatch-normalization "http://q@some.host:80" &&
- test-tool urlmatch-normalization "https://q@some.host:443" &&
- test-tool urlmatch-normalization "http://q@some.host:80/" &&
- test-tool urlmatch-normalization "https://q@some.host:443?" &&
- ! test-tool urlmatch-normalization "http://q@:8008" &&
- ! test-tool urlmatch-normalization "http://:8080" &&
- ! test-tool urlmatch-normalization "http://:" &&
- test-tool urlmatch-normalization "xyz://q@some.host:456/" &&
- test-tool urlmatch-normalization "xyz://[::1]:456/" &&
- test-tool urlmatch-normalization "xyz://[::1]:/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:000/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:0%300/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:0x80/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:4294967297/" &&
- ! test-tool urlmatch-normalization "xyz://[::1]:030f/"
-'
-
-test_expect_success 'url port normalization' '
- test "$(test-tool urlmatch-normalization -p "http://x:800")" = "http://x:800/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:0800")" = "http://x:800/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:1")" = "http://x:1/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:80")" = "http://x/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:080")" = "http://x/" &&
- test "$(test-tool urlmatch-normalization -p "http://x:000000080")" = "http://x/" &&
- test "$(test-tool urlmatch-normalization -p "https://x:443")" = "https://x/" &&
- test "$(test-tool urlmatch-normalization -p "https://x:0443")" = "https://x/" &&
- test "$(test-tool urlmatch-normalization -p "https://x:000000443")" = "https://x/"
-'
-
-test_expect_success 'url general escapes' '
- ! test-tool urlmatch-normalization "http://x.y?%fg" &&
- test "$(test-tool urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" &&
- test "$(test-tool urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" &&
- test "$(test-tool urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" &&
- test "$(test-tool urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" &&
- test "$(test-tool urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'"
-'
-
-test_expect_success !MINGW 'url high-bit escapes' '
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" &&
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
-'
-
-test_expect_success 'url utf-8 escapes' '
- test "$(test-tool urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD"
-'
-
-test_expect_success 'url username/password escapes' '
- test "$(test-tool urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/"
-'
-
-test_expect_success 'url normalized lengths' '
- test "$(test-tool urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 &&
- test "$(test-tool urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 &&
- test "$(test-tool urlmatch-normalization -l "http://@x.y/^")" = 15
-'
-
-test_expect_success 'url . and .. segments' '
- test "$(test-tool urlmatch-normalization -p "x://y/.")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/./")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/.")" = "x://y/a" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/.?")" = "x://y/?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/./?")" = "x://y/?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" &&
- ! test-tool urlmatch-normalization "x://y/a/./b/.././../c/././.././.." &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." &&
- test "$(test-tool urlmatch-normalization -p "x://y/%2e/")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/%2E/")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" &&
- test "$(test-tool urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/"
-'
-
-# http://@foo specifies an empty user name but does not specify a password
-# http://foo specifies neither a user name nor a password
-# So they should not be equivalent
-test_expect_success 'url equivalents' '
- test-tool urlmatch-normalization "httP://x" "Http://X/" &&
- test-tool urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" &&
- ! test-tool urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" &&
- test-tool urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" &&
- test-tool urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" &&
- test-tool urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/"
-'
-
-test_done
diff --git a/t/t0110/README b/t/t0110/README
deleted file mode 100644
index ad4a50ecd8..0000000000
--- a/t/t0110/README
+++ /dev/null
@@ -1,9 +0,0 @@
-The url data files in this directory contain URLs with characters
-in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization
-of unprintable characters.
-
-A select few characters in the 0x01-0x1f range are skipped to help
-avoid problems running the test itself.
-
-The urls are in test files in this directory rather than being
-embedded in the test script for portability.
diff --git a/t/t0110/url-1 b/t/t0110/url-1
deleted file mode 100644
index 519019c5ce..0000000000
--- a/t/t0110/url-1
+++ /dev/null
@@ -1 +0,0 @@
-x://q/
diff --git a/t/t0110/url-10 b/t/t0110/url-10
deleted file mode 100644
index b9965de6a5..0000000000
--- a/t/t0110/url-10
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ðñòóôõö÷øùúûüýþÿ
diff --git a/t/t0110/url-11 b/t/t0110/url-11
deleted file mode 100644
index f0a50f1009..0000000000
--- a/t/t0110/url-11
+++ /dev/null
@@ -1 +0,0 @@
-x://q/€߿ࠀ�ð€€ð¯¿½
diff --git a/t/t0110/url-2 b/t/t0110/url-2
deleted file mode 100644
index 43334b05b2..0000000000
--- a/t/t0110/url-2
+++ /dev/null
@@ -1 +0,0 @@
-x://q/
diff --git a/t/t0110/url-3 b/t/t0110/url-3
deleted file mode 100644
index 7378c7bec2..0000000000
--- a/t/t0110/url-3
+++ /dev/null
@@ -1 +0,0 @@
-x://q/€‚ƒ„…†‡ˆ‰Š‹ŒŽ
diff --git a/t/t0110/url-4 b/t/t0110/url-4
deleted file mode 100644
index 220b198c97..0000000000
--- a/t/t0110/url-4
+++ /dev/null
@@ -1 +0,0 @@
-x://q/‘’“”•–—˜™š›œžŸ
diff --git a/t/t0110/url-5 b/t/t0110/url-5
deleted file mode 100644
index 1ccd927779..0000000000
--- a/t/t0110/url-5
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ ¡¢£¤¥¦§¨©ª«¬­®¯
diff --git a/t/t0110/url-6 b/t/t0110/url-6
deleted file mode 100644
index e8283aac6d..0000000000
--- a/t/t0110/url-6
+++ /dev/null
@@ -1 +0,0 @@
-x://q/°±²³´µ¶·¸¹º»¼½¾¿
diff --git a/t/t0110/url-7 b/t/t0110/url-7
deleted file mode 100644
index fa7c10b615..0000000000
--- a/t/t0110/url-7
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
diff --git a/t/t0110/url-8 b/t/t0110/url-8
deleted file mode 100644
index 79a0ba836f..0000000000
--- a/t/t0110/url-8
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ÐÑÒÓÔÕÖרÙÚÛÜÝÞß
diff --git a/t/t0110/url-9 b/t/t0110/url-9
deleted file mode 100644
index 8b44bec48b..0000000000
--- a/t/t0110/url-9
+++ /dev/null
@@ -1 +0,0 @@
-x://q/àáâãäåæçèéêëìíîï
diff --git a/t/t0200-gettext-basic.sh b/t/t0200-gettext-basic.sh
index 522fb2ae69..8853d8afb9 100755
--- a/t/t0200-gettext-basic.sh
+++ b/t/t0200-gettext-basic.sh
@@ -5,7 +5,6 @@
test_description='Gettext support for Git'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
test_expect_success "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" '
diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh
index 8724ce1052..6c74df0dc6 100755
--- a/t/t0201-gettext-fallbacks.sh
+++ b/t/t0201-gettext-fallbacks.sh
@@ -8,7 +8,6 @@ test_description='Gettext Shell fallbacks'
GIT_INTERNAL_GETTEXT_TEST_FALLBACKS=YesPlease
export GIT_INTERNAL_GETTEXT_TEST_FALLBACKS
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
test_expect_success "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" '
diff --git a/t/t0202-gettext-perl.sh b/t/t0202-gettext-perl.sh
index 5a6f28051b..b15cb65d5d 100755
--- a/t/t0202-gettext-perl.sh
+++ b/t/t0202-gettext-perl.sh
@@ -5,7 +5,6 @@
test_description='Perl gettext interface (Git::I18N)'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
. "$TEST_DIRECTORY"/lib-perl.sh
skip_all_if_no_Test_More
diff --git a/t/t0202/test.pl b/t/t0202/test.pl
index 2cbf7b9590..47d96a2a13 100755
--- a/t/t0202/test.pl
+++ b/t/t0202/test.pl
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-use 5.008;
+use 5.008001;
use lib (split(/:/, $ENV{GITPERLLIB}));
use strict;
use warnings;
diff --git a/t/t0203-gettext-setlocale-sanity.sh b/t/t0203-gettext-setlocale-sanity.sh
index 86cff324ff..0ce1f22eff 100755
--- a/t/t0203-gettext-setlocale-sanity.sh
+++ b/t/t0203-gettext-setlocale-sanity.sh
@@ -5,7 +5,6 @@
test_description="The Git C functions aren't broken by setlocale(3)"
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
test_expect_success 'git show a ISO-8859-1 commit under C locale' '
diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh
index 4f2e0dcb02..28d92bb9b7 100755
--- a/t/t0204-gettext-reencode-sanity.sh
+++ b/t/t0204-gettext-reencode-sanity.sh
@@ -5,7 +5,6 @@
test_description="Gettext reencoding of our *.po/*.mo files works"
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
# The constants used in a tricky observation for undefined behaviour
@@ -82,7 +81,7 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext.c: git init UTF-8 -> ISO-8859-1'
printf "Bjó til tóma Git lind" >expect &&
LANGUAGE=is LC_ALL="$is_IS_iso_locale" git init repo >actual &&
test_when_finished "rm -rf repo" &&
- grep "^$(cat expect | iconv -f UTF-8 -t ISO8859-1) " actual
+ grep "^$(iconv -f UTF-8 -t ISO8859-1 <expect) " actual
'
test_done
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index 80e76a4695..eff9a59dbd 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -2,7 +2,6 @@
test_description='test trace2 facility (normal target)'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Turn off any inherited trace2 settings for this test.
@@ -283,4 +282,22 @@ test_expect_success 'using global config with include' '
test_cmp expect actual
'
+test_expect_success 'unsafe URLs are redacted by default' '
+ test_when_finished \
+ "rm -r trace.normal unredacted.normal clone clone2" &&
+
+ test_config_global \
+ "url.$(pwd).insteadOf" https://user:pwd@example.com/ &&
+ test_config_global trace2.configParams "core.*,remote.*.url" &&
+
+ GIT_TRACE2="$(pwd)/trace.normal" \
+ git clone https://user:pwd@example.com/ clone &&
+ ! grep user:pwd trace.normal &&
+
+ GIT_TRACE2_REDACT=0 GIT_TRACE2="$(pwd)/unredacted.normal" \
+ git clone https://user:pwd@example.com/ clone2 &&
+ grep "start .* clone https://user:pwd@example.com" unredacted.normal &&
+ grep "remote.origin.url=https://user:pwd@example.com" unredacted.normal
+'
+
test_done
diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh
index cfba686132..bac9046540 100755
--- a/t/t0211-trace2-perf.sh
+++ b/t/t0211-trace2-perf.sh
@@ -2,7 +2,6 @@
test_description='test trace2 facility (perf target)'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Turn off any inherited trace2 settings for this test.
@@ -233,7 +232,7 @@ have_counter_event () {
pattern="d0|${thread}|${event}||||${category}|name:${name} value:${value}" &&
- grep "${patern}" ${file}
+ grep "${pattern}" ${file}
}
test_expect_success 'global counter test/test1' '
@@ -268,4 +267,256 @@ test_expect_success PTHREADS 'global counter test/test2' '
have_counter_event "main" "counter" "test" "test2" 60 actual
'
+test_expect_success 'unsafe URLs are redacted by default' '
+ test_when_finished \
+ "rm -r actual trace.perf unredacted.perf clone clone2" &&
+
+ test_config_global \
+ "url.$(pwd).insteadOf" https://user:pwd@example.com/ &&
+ test_config_global trace2.configParams "core.*,remote.*.url" &&
+
+ GIT_TRACE2_PERF="$(pwd)/trace.perf" \
+ git clone https://user:pwd@example.com/ clone &&
+ ! grep user:pwd trace.perf &&
+
+ GIT_TRACE2_REDACT=0 GIT_TRACE2_PERF="$(pwd)/unredacted.perf" \
+ git clone https://user:pwd@example.com/ clone2 &&
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <unredacted.perf >actual &&
+ grep "d0|main|start|.* clone https://user:pwd@example.com" actual &&
+ grep "d0|main|def_param|.*|remote.origin.url:https://user:pwd@example.com" actual
+'
+
+# Confirm that the requested command produces a "cmd_name" and a
+# set of "def_param" events.
+#
+try_simple () {
+ test_when_finished "rm prop.perf actual" &&
+
+ cmd=$1 &&
+ cmd_name=$2 &&
+
+ test_config_global "trace2.configParams" "cfg.prop.*" &&
+ test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" &&
+
+ test_config_global "cfg.prop.foo" "red" &&
+
+ ENV_PROP_FOO=blue \
+ GIT_TRACE2_PERF="$(pwd)/prop.perf" \
+ $cmd &&
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual &&
+ grep "d0|main|cmd_name|.*|$cmd_name" actual &&
+ grep "d0|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual
+}
+
+# Representative mainstream builtin Git command dispatched
+# in run_builtin() in git.c
+#
+test_expect_success 'expect def_params for normal builtin command' '
+ try_simple "git version" "version"
+'
+
+# Representative query command dispatched in handle_options()
+# in git.c
+#
+test_expect_success 'expect def_params for query command' '
+ try_simple "git --man-path" "_query_"
+'
+
+# remote-curl.c does not use the builtin setup in git.c, so confirm
+# that executables built from remote-curl.c emit def_params.
+#
+# Also tests the dashed-command handling where "git foo" silently
+# spawns "git-foo". Make sure that both commands should emit
+# def_params.
+#
+# Pass bogus arguments to remote-https and allow the command to fail
+# because we don't actually have a remote to fetch from. We just want
+# to see the run-dashed code run an executable built from
+# remote-curl.c rather than git.c. Confirm that we get def_param
+# events from both layers.
+#
+test_expect_success LIBCURL \
+ 'expect def_params for remote-curl and _run_dashed_' '
+ test_when_finished "rm prop.perf actual" &&
+
+ test_config_global "trace2.configParams" "cfg.prop.*" &&
+ test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" &&
+
+ test_config_global "cfg.prop.foo" "red" &&
+
+ test_might_fail env \
+ ENV_PROP_FOO=blue \
+ GIT_TRACE2_PERF="$(pwd)/prop.perf" \
+ git remote-http x y &&
+
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual &&
+
+ grep "d0|main|cmd_name|.*|_run_dashed_" actual &&
+ grep "d0|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual &&
+
+ grep "d1|main|cmd_name|.*|remote-curl" actual &&
+ grep "d1|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual
+'
+
+# Similarly, `git-http-fetch` is not built from git.c so do a
+# trivial fetch so that the main git.c run-dashed code spawns
+# an executable built from http-fetch.c. Confirm that we get
+# def_param events from both layers.
+#
+test_expect_success LIBCURL \
+ 'expect def_params for http-fetch and _run_dashed_' '
+ test_when_finished "rm prop.perf actual" &&
+
+ test_config_global "trace2.configParams" "cfg.prop.*" &&
+ test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" &&
+
+ test_config_global "cfg.prop.foo" "red" &&
+
+ test_might_fail env \
+ ENV_PROP_FOO=blue \
+ GIT_TRACE2_PERF="$(pwd)/prop.perf" \
+ git http-fetch --stdin file:/// <<-EOF &&
+ EOF
+
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual &&
+
+ grep "d0|main|cmd_name|.*|_run_dashed_" actual &&
+ grep "d0|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual &&
+
+ grep "d1|main|cmd_name|.*|http-fetch" actual &&
+ grep "d1|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual
+'
+
+# Historically, alias expansion explicitly emitted the def_param
+# events (independent of whether the command was a builtin, a Git
+# command or arbitrary shell command) so that it wasn't dependent
+# upon the unpeeling of the alias. Let's make sure that we preserve
+# the net effect.
+#
+test_expect_success 'expect def_params during git alias expansion' '
+ test_when_finished "rm prop.perf actual" &&
+
+ test_config_global "trace2.configParams" "cfg.prop.*" &&
+ test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" &&
+
+ test_config_global "cfg.prop.foo" "red" &&
+
+ test_config_global "alias.xxx" "version" &&
+
+ ENV_PROP_FOO=blue \
+ GIT_TRACE2_PERF="$(pwd)/prop.perf" \
+ git xxx &&
+
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual &&
+
+ # "git xxx" is first mapped to "git-xxx" and the child will fail.
+ grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_)" actual &&
+
+ # We unpeel that and substitute "version" into "xxx" (giving
+ # "git version") and update the cmd_name event.
+ grep "d0|main|cmd_name|.*|_run_git_alias_ (_run_dashed_/_run_git_alias_)" actual &&
+
+ # These def_param events could be associated with either of the
+ # above cmd_name events. It does not matter.
+ grep "d0|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual &&
+
+ # The "git version" child sees a different cmd_name hierarchy.
+ # Also test the def_param (only for completeness).
+ grep "d1|main|cmd_name|.*|version (_run_dashed_/_run_git_alias_/version)" actual &&
+ grep "d1|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual
+'
+
+test_expect_success 'expect def_params during shell alias expansion' '
+ test_when_finished "rm prop.perf actual" &&
+
+ test_config_global "trace2.configParams" "cfg.prop.*" &&
+ test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" &&
+
+ test_config_global "cfg.prop.foo" "red" &&
+
+ test_config_global "alias.xxx" "!git version" &&
+
+ ENV_PROP_FOO=blue \
+ GIT_TRACE2_PERF="$(pwd)/prop.perf" \
+ git xxx &&
+
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual &&
+
+ # "git xxx" is first mapped to "git-xxx" and the child will fail.
+ grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_)" actual &&
+
+ # We unpeel that and substitute "git version" for "git xxx" (as a
+ # shell command. Another cmd_name event is emitted as we unpeel.
+ grep "d0|main|cmd_name|.*|_run_shell_alias_ (_run_dashed_/_run_shell_alias_)" actual &&
+
+ # These def_param events could be associated with either of the
+ # above cmd_name events. It does not matter.
+ grep "d0|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual &&
+
+ # We get the following only because we used a git command for the
+ # shell command. In general, it could have been a shell script and
+ # we would see nothing.
+ #
+ # The child knows the cmd_name hierarchy so it includes it.
+ grep "d1|main|cmd_name|.*|version (_run_dashed_/_run_shell_alias_/version)" actual &&
+ grep "d1|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual
+'
+
+test_expect_success 'expect def_params during nested git alias expansion' '
+ test_when_finished "rm prop.perf actual" &&
+
+ test_config_global "trace2.configParams" "cfg.prop.*" &&
+ test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" &&
+
+ test_config_global "cfg.prop.foo" "red" &&
+
+ test_config_global "alias.xxx" "yyy" &&
+ test_config_global "alias.yyy" "version" &&
+
+ ENV_PROP_FOO=blue \
+ GIT_TRACE2_PERF="$(pwd)/prop.perf" \
+ git xxx &&
+
+ perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual &&
+
+ # "git xxx" is first mapped to "git-xxx" and try to spawn "git-xxx"
+ # and the child will fail.
+ grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_)" actual &&
+ grep "d0|main|child_start|.*|.* class:dashed argv:\[git-xxx\]" actual &&
+
+ # We unpeel that and substitute "yyy" into "xxx" (giving "git yyy")
+ # and spawn "git-yyy" and the child will fail.
+ grep "d0|main|alias|.*|alias:xxx argv:\[yyy\]" actual &&
+ grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_/_run_dashed_)" actual &&
+ grep "d0|main|child_start|.*|.* class:dashed argv:\[git-yyy\]" actual &&
+
+ # We unpeel that and substitute "version" into "xxx" (giving
+ # "git version") and update the cmd_name event.
+ grep "d0|main|alias|.*|alias:yyy argv:\[version\]" actual &&
+ grep "d0|main|cmd_name|.*|_run_git_alias_ (_run_dashed_/_run_dashed_/_run_git_alias_)" actual &&
+
+ # These def_param events could be associated with any of the
+ # above cmd_name events. It does not matter.
+ grep "d0|main|def_param|.*|cfg.prop.foo:red" actual >actual.matches &&
+ grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual &&
+
+ # However, we do not want them repeated each time we unpeel.
+ test_line_count = 1 actual.matches &&
+
+ # The "git version" child sees a different cmd_name hierarchy.
+ # Also test the def_param (only for completeness).
+ grep "d1|main|cmd_name|.*|version (_run_dashed_/_run_dashed_/_run_git_alias_/version)" actual &&
+ grep "d1|main|def_param|.*|cfg.prop.foo:red" actual &&
+ grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual
+'
+
test_done
diff --git a/t/t0212-trace2-event.sh b/t/t0212-trace2-event.sh
index 6d3374ff77..1211db9f46 100755
--- a/t/t0212-trace2-event.sh
+++ b/t/t0212-trace2-event.sh
@@ -2,7 +2,6 @@
test_description='test trace2 facility'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Turn off any inherited trace2 settings for this test.
@@ -323,4 +322,44 @@ test_expect_success 'discard traces when there are too many files' '
head -n2 trace_target_dir/git-trace2-discard | tail -n1 | grep \"event\":\"too_many_files\"
'
+# In the following "...redact..." tests, skip testing the GIT_TRACE2_REDACT=0
+# case because we would need to exactly model the full JSON event stream like
+# we did in the basic tests above and I do not think it is worth it.
+
+test_expect_success 'unsafe URLs are redacted by default in cmd_start events' '
+ test_when_finished \
+ "rm -r trace.event" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ test-tool trace2 300redact_start git clone https://user:pwd@example.com/ clone2 &&
+ ! grep user:pwd trace.event
+'
+
+test_expect_success 'unsafe URLs are redacted by default in child_start events' '
+ test_when_finished \
+ "rm -r trace.event" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ test-tool trace2 301redact_child_start git clone https://user:pwd@example.com/ clone2 &&
+ ! grep user:pwd trace.event
+'
+
+test_expect_success 'unsafe URLs are redacted by default in exec events' '
+ test_when_finished \
+ "rm -r trace.event" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ test-tool trace2 302redact_exec git clone https://user:pwd@example.com/ clone2 &&
+ ! grep user:pwd trace.event
+'
+
+test_expect_success 'unsafe URLs are redacted by default in def_param events' '
+ test_when_finished \
+ "rm -r trace.event" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ test-tool trace2 303redact_def_param url https://user:pwd@example.com/ &&
+ ! grep user:pwd trace.event
+'
+
test_done
diff --git a/t/t0212/parse_events.perl b/t/t0212/parse_events.perl
index 30a9f51e9f..7146476c69 100644
--- a/t/t0212/parse_events.perl
+++ b/t/t0212/parse_events.perl
@@ -204,7 +204,7 @@ while (<>) {
}
# A series of potentially nested and threaded region and data events
- # is fundamentally incompatibile with the type of summary record we
+ # is fundamentally incompatible with the type of summary record we
# are building in this script. Since they are intended for
# perf-trace-like analysis rather than a result summary, we ignore
# most of them here.
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index a4f5bba507..17952e52d6 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='basic credential helper tests'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-credential.sh
@@ -12,7 +13,13 @@ test_expect_success 'setup helper scripts' '
IFS==
while read key value; do
echo >&2 "$whoami: $key=$value"
- eval "$key=$value"
+ if test -z "${key%%*\[\]}"
+ then
+ key=${key%%\[\]}
+ eval "$key=\"\$$key $value\""
+ else
+ eval "$key=$value"
+ fi
done
IFS=$OIFS
EOF
@@ -35,6 +42,30 @@ test_expect_success 'setup helper scripts' '
test -z "$pass" || echo password=$pass
EOF
+ write_script git-credential-verbatim-cred <<-\EOF &&
+ authtype=$1; shift
+ credential=$1; shift
+ . ./dump
+ echo capability[]=authtype
+ echo capability[]=state
+ test -z "${capability##*authtype*}" || exit 0
+ test -z "$authtype" || echo authtype=$authtype
+ test -z "$credential" || echo credential=$credential
+ test -z "${capability##*state*}" || exit 0
+ echo state[]=verbatim-cred:foo
+ EOF
+
+ write_script git-credential-verbatim-ephemeral <<-\EOF &&
+ authtype=$1; shift
+ credential=$1; shift
+ . ./dump
+ echo capability[]=authtype
+ test -z "${capability##*authtype*}" || exit 0
+ test -z "$authtype" || echo authtype=$authtype
+ test -z "$credential" || echo credential=$credential
+ echo "ephemeral=1"
+ EOF
+
write_script git-credential-verbatim-with-expiry <<-\EOF &&
user=$1; shift
pass=$1; shift
@@ -64,6 +95,67 @@ test_expect_success 'credential_fill invokes helper' '
EOF
'
+test_expect_success 'credential_fill invokes helper with credential' '
+ check fill "verbatim-cred Bearer token" <<-\EOF
+ capability[]=authtype
+ protocol=http
+ host=example.com
+ --
+ capability[]=authtype
+ authtype=Bearer
+ credential=token
+ protocol=http
+ host=example.com
+ --
+ verbatim-cred: get
+ verbatim-cred: capability[]=authtype
+ verbatim-cred: protocol=http
+ verbatim-cred: host=example.com
+ EOF
+'
+
+test_expect_success 'credential_fill invokes helper with ephemeral credential' '
+ check fill "verbatim-ephemeral Bearer token" <<-\EOF
+ capability[]=authtype
+ protocol=http
+ host=example.com
+ --
+ capability[]=authtype
+ authtype=Bearer
+ credential=token
+ ephemeral=1
+ protocol=http
+ host=example.com
+ --
+ verbatim-ephemeral: get
+ verbatim-ephemeral: capability[]=authtype
+ verbatim-ephemeral: protocol=http
+ verbatim-ephemeral: host=example.com
+ EOF
+'
+test_expect_success 'credential_fill invokes helper with credential and state' '
+ check fill "verbatim-cred Bearer token" <<-\EOF
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=example.com
+ --
+ capability[]=authtype
+ capability[]=state
+ authtype=Bearer
+ credential=token
+ protocol=http
+ host=example.com
+ state[]=verbatim-cred:foo
+ --
+ verbatim-cred: get
+ verbatim-cred: capability[]=authtype
+ verbatim-cred: capability[]=state
+ verbatim-cred: protocol=http
+ verbatim-cred: host=example.com
+ EOF
+'
+
test_expect_success 'credential_fill invokes multiple helpers' '
check fill useless "verbatim foo bar" <<-\EOF
protocol=http
@@ -83,6 +175,45 @@ test_expect_success 'credential_fill invokes multiple helpers' '
EOF
'
+test_expect_success 'credential_fill response does not get capabilities when helpers are incapable' '
+ check fill useless "verbatim foo bar" <<-\EOF
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=example.com
+ --
+ protocol=http
+ host=example.com
+ username=foo
+ password=bar
+ --
+ useless: get
+ useless: capability[]=authtype
+ useless: capability[]=state
+ useless: protocol=http
+ useless: host=example.com
+ verbatim: get
+ verbatim: capability[]=authtype
+ verbatim: capability[]=state
+ verbatim: protocol=http
+ verbatim: host=example.com
+ EOF
+'
+
+test_expect_success 'credential_fill response does not get capabilities when caller is incapable' '
+ check fill "verbatim-cred Bearer token" <<-\EOF
+ protocol=http
+ host=example.com
+ --
+ protocol=http
+ host=example.com
+ --
+ verbatim-cred: get
+ verbatim-cred: protocol=http
+ verbatim-cred: host=example.com
+ EOF
+'
+
test_expect_success 'credential_fill stops when we get a full response' '
check fill "verbatim one two" "verbatim three four" <<-\EOF
protocol=http
@@ -99,6 +230,25 @@ test_expect_success 'credential_fill stops when we get a full response' '
EOF
'
+test_expect_success 'credential_fill thinks a credential is a full response' '
+ check fill "verbatim-cred Bearer token" "verbatim three four" <<-\EOF
+ capability[]=authtype
+ protocol=http
+ host=example.com
+ --
+ capability[]=authtype
+ authtype=Bearer
+ credential=token
+ protocol=http
+ host=example.com
+ --
+ verbatim-cred: get
+ verbatim-cred: capability[]=authtype
+ verbatim-cred: protocol=http
+ verbatim-cred: host=example.com
+ EOF
+'
+
test_expect_success 'credential_fill continues through partial response' '
check fill "verbatim one \"\"" "verbatim two three" <<-\EOF
protocol=http
@@ -175,6 +325,20 @@ test_expect_success 'credential_fill passes along metadata' '
EOF
'
+test_expect_success 'credential_fill produces no credential without capability' '
+ check fill "verbatim-cred Bearer token" <<-\EOF
+ protocol=http
+ host=example.com
+ --
+ protocol=http
+ host=example.com
+ --
+ verbatim-cred: get
+ verbatim-cred: protocol=http
+ verbatim-cred: host=example.com
+ EOF
+'
+
test_expect_success 'credential_approve calls all helpers' '
check approve useless "verbatim one two" <<-\EOF
protocol=http
@@ -827,7 +991,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 2>stderr &&
- test_i18ngrep "skipping credential lookup for key" stderr
+ test_grep "skipping credential lookup for key" stderr
'
test_done
diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh
index c02a3b5969..dc30289f75 100755
--- a/t/t0301-credential-cache.sh
+++ b/t/t0301-credential-cache.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='credential-cache tests'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-credential.sh
@@ -8,6 +9,14 @@ test -z "$NO_UNIX_SOCKETS" || {
skip_all='skipping credential-cache tests, unix sockets not available'
test_done
}
+if test_have_prereq MINGW
+then
+ service_running=$(sc query afunix | grep "4 RUNNING")
+ test -z "$service_running" || {
+ skip_all='skipping credential-cache tests, unix sockets not available'
+ test_done
+ }
+fi
uname_s=$(uname -s)
case $uname_s in
@@ -29,7 +38,9 @@ test_atexit 'git credential-cache exit'
# test that the daemon works with no special setup
helper_test cache
+helper_test_password_expiry_utc cache
helper_test_oauth_refresh_token cache
+helper_test_authtype cache
test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
test_when_finished "
diff --git a/t/t0302-credential-store.sh b/t/t0302-credential-store.sh
index 716bf1af9f..c1cd60edd0 100755
--- a/t/t0302-credential-store.sh
+++ b/t/t0302-credential-store.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='credential-store tests'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-credential.sh
diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh
index f028fd1418..72ae405c3e 100755
--- a/t/t0303-credential-external.sh
+++ b/t/t0303-credential-external.sh
@@ -32,9 +32,24 @@ commands.
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-credential.sh
+# If we're not given a specific external helper to run against,
+# there isn't much to test. But we can still run through our
+# battery of tests with a fake helper and check that the
+# test themselves are self-consistent and clean up after
+# themselves.
+#
+# We'll use the "store" helper, since we can easily inspect
+# its state by looking at the on-disk file. But since it doesn't
+# implement any caching or expiry logic, we'll cheat and override
+# the "check" function to just report all results as OK.
if test -z "$GIT_TEST_CREDENTIAL_HELPER"; then
- skip_all="used to test external credential helpers"
- test_done
+ GIT_TEST_CREDENTIAL_HELPER=store
+ GIT_TEST_CREDENTIAL_HELPER_TIMEOUT=store
+ check () {
+ test "$1" = "approve" || return 0
+ git -c credential.helper=store credential approve
+ }
+ check_cleanup=t
fi
test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" ||
@@ -45,6 +60,8 @@ test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" ||
helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER"
helper_test "$GIT_TEST_CREDENTIAL_HELPER"
+helper_test_password_expiry_utc "$GIT_TEST_CREDENTIAL_HELPER"
+helper_test_oauth_refresh_token "$GIT_TEST_CREDENTIAL_HELPER"
if test -z "$GIT_TEST_CREDENTIAL_HELPER_TIMEOUT"; then
say "# skipping timeout tests (GIT_TEST_CREDENTIAL_HELPER_TIMEOUT not set)"
@@ -57,4 +74,11 @@ fi
# might be long-term system storage
helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER"
+if test "$check_cleanup" = "t"
+then
+ test_expect_success 'test cleanup removes everything' '
+ test_must_be_empty "$HOME/.git-credentials"
+ '
+fi
+
test_done
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index 5b7bee888d..2a5bdbeeb8 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -3,9 +3,8 @@
test_description='partial clone'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
-# missing promisor objects cause repacks which write bitmaps to fail
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
# When enabled, some commands will write commit-graphs. This causes fsck
# to fail when delete_object() is called because fsck will attempt to
# verify the out-of-sync commit graph.
@@ -49,7 +48,7 @@ test_expect_success 'convert shallow clone to partial clone' '
test_cmp_config -C client 1 core.repositoryformatversion
'
-test_expect_success SHA1 'convert to partial clone with noop extension' '
+test_expect_success DEFAULT_REPO_FORMAT 'convert to partial clone with noop extension' '
rm -fr server client &&
test_create_repo server &&
test_commit -C server my_commit 1 &&
@@ -60,7 +59,7 @@ test_expect_success SHA1 'convert to partial clone with noop extension' '
git -C client fetch --unshallow --filter="blob:none"
'
-test_expect_success SHA1 'converting to partial clone fails with unrecognized extension' '
+test_expect_success DEFAULT_REPO_FORMAT 'converting to partial clone fails with unrecognized extension' '
rm -fr server client &&
test_create_repo server &&
test_commit -C server my_commit 1 &&
@@ -241,7 +240,7 @@ test_expect_success 'fetching of missing objects works with ref-in-want enabled'
grep "fetch< fetch=.*ref-in-want" trace
'
-test_expect_success 'fetching of missing objects from another promisor remote' '
+test_expect_success 'fetching from another promisor remote' '
git clone "file://$(pwd)/server" server2 &&
test_commit -C server2 bar &&
git -C server2 repack -a -d --write-bitmap-index &&
@@ -264,8 +263,8 @@ test_expect_success 'fetching of missing objects from another promisor remote' '
grep "$HASH2" out
'
-test_expect_success 'fetching of missing objects configures a promisor remote' '
- git clone "file://$(pwd)/server" server3 &&
+test_expect_success 'fetching with --filter configures a promisor remote' '
+ test_create_repo server3 &&
test_commit -C server3 baz &&
git -C server3 repack -a -d --write-bitmap-index &&
HASH3=$(git -C server3 rev-parse baz) &&
@@ -665,6 +664,21 @@ test_expect_success 'lazy-fetch when accessing object not in the_repository' '
git -C partial.git rev-list --objects --missing=print HEAD >out &&
grep "[?]$FILE_HASH" out &&
+ # The no-lazy-fetch mechanism prevents Git from fetching
+ test_must_fail env GIT_NO_LAZY_FETCH=1 \
+ git -C partial.git cat-file -e "$FILE_HASH" &&
+
+ # The same with command line option to "git"
+ test_must_fail git --no-lazy-fetch -C partial.git cat-file -e "$FILE_HASH" &&
+
+ # The same, forcing a subprocess via an alias
+ test_must_fail git --no-lazy-fetch -C partial.git \
+ -c alias.foo="!git cat-file" foo -e "$FILE_HASH" &&
+
+ # Sanity check that the file is still missing
+ git -C partial.git rev-list --objects --missing=print HEAD >out &&
+ grep "[?]$FILE_HASH" out &&
+
git -C full cat-file -s "$FILE_HASH" >expect &&
test-tool partial-clone object-info partial.git "$FILE_HASH" >actual &&
test_cmp expect actual &&
@@ -674,6 +688,67 @@ test_expect_success 'lazy-fetch when accessing object not in the_repository' '
! grep "[?]$FILE_HASH" out
'
+test_expect_success 'push should not fetch new commit objects' '
+ rm -rf server client &&
+ test_create_repo server &&
+ test_config -C server uploadpack.allowfilter 1 &&
+ test_config -C server uploadpack.allowanysha1inwant 1 &&
+ test_commit -C server server1 &&
+
+ git clone --filter=blob:none "file://$(pwd)/server" client &&
+ test_commit -C client client1 &&
+
+ test_commit -C server server2 &&
+ COMMIT=$(git -C server rev-parse server2) &&
+
+ test_must_fail git -C client push 2>err &&
+ grep "fetch first" err &&
+ git -C client rev-list --objects --missing=print "$COMMIT" >objects &&
+ grep "^[?]$COMMIT" objects
+'
+
+test_expect_success 'setup for promisor.quiet tests' '
+ rm -rf server &&
+ test_create_repo server &&
+ test_commit -C server foo &&
+ git -C server rm foo.t &&
+ git -C server commit -m remove &&
+ git -C server config uploadpack.allowanysha1inwant 1 &&
+ git -C server config uploadpack.allowfilter 1
+'
+
+test_expect_success TTY 'promisor.quiet=false shows progress messages' '
+ rm -rf repo &&
+ git clone --filter=blob:none "file://$(pwd)/server" repo &&
+ git -C repo config promisor.quiet "false" &&
+
+ test_terminal git -C repo cat-file -p foo:foo.t 2>err &&
+
+ # Ensure that progress messages are written
+ grep "Receiving objects" err
+'
+
+test_expect_success TTY 'promisor.quiet=true does not show progress messages' '
+ rm -rf repo &&
+ git clone --filter=blob:none "file://$(pwd)/server" repo &&
+ git -C repo config promisor.quiet "true" &&
+
+ test_terminal git -C repo cat-file -p foo:foo.t 2>err &&
+
+ # Ensure that no progress messages are written
+ ! grep "Receiving objects" err
+'
+
+test_expect_success TTY 'promisor.quiet=unconfigured shows progress messages' '
+ rm -rf repo &&
+ git clone --filter=blob:none "file://$(pwd)/server" repo &&
+
+ test_terminal git -C repo cat-file -p foo:foo.t 2>err &&
+
+ # Ensure that progress messages are written
+ grep "Receiving objects" err
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
index b3d6ddc4bc..c98d501869 100755
--- a/t/t0411-clone-from-partial.sh
+++ b/t/t0411-clone-from-partial.sh
@@ -28,8 +28,8 @@ test_expect_success 'local clone must not fetch from promisor remote and execute
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
evil clone1 2>err &&
- grep "detected dubious ownership" err &&
- ! grep "fake-upload-pack running" err &&
+ test_grep "detected dubious ownership" err &&
+ test_grep ! "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -38,8 +38,8 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
"file://$(pwd)/evil" clone2 2>err &&
- grep "detected dubious ownership" err &&
- ! grep "fake-upload-pack running" err &&
+ test_grep "detected dubious ownership" err &&
+ test_grep ! "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -48,22 +48,22 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a
test_must_fail git fetch \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
"file://$(pwd)/evil" 2>err &&
- grep "detected dubious ownership" err &&
- ! grep "fake-upload-pack running" err &&
+ test_grep "detected dubious ownership" err &&
+ test_grep ! "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
test_expect_success 'pack-objects should fetch from promisor remote and execute script' '
rm -f script-executed &&
echo "HEAD" | test_must_fail git -C evil pack-objects --revs --stdout >/dev/null 2>err &&
- grep "fake-upload-pack running" err &&
+ test_grep "fake-upload-pack running" err &&
test_path_is_file script-executed
'
test_expect_success 'clone from promisor remote does not lazy-fetch by default' '
rm -f script-executed &&
test_must_fail git clone evil no-lazy 2>err &&
- grep "lazy fetching disabled" err &&
+ test_grep "lazy fetching disabled" err &&
test_path_is_missing script-executed
'
@@ -71,7 +71,7 @@ test_expect_success 'promisor lazy-fetching can be re-enabled' '
rm -f script-executed &&
test_must_fail env GIT_NO_LAZY_FETCH=0 \
git clone evil lazy-ok 2>err &&
- grep "fake-upload-pack running" err &&
+ test_grep "fake-upload-pack running" err &&
test_path_is_file script-executed
'
diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh
index cd3969e852..853101b86e 100755
--- a/t/t0450-txt-doc-vs-help.sh
+++ b/t/t0450-txt-doc-vs-help.sh
@@ -5,7 +5,6 @@ test_description='assert (unbuilt) Documentation/*.txt and -h output
Run this with --debug to see a summary of where we still fail to make
the two versions consistent with one another.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: list of builtins' '
@@ -56,12 +55,11 @@ txt_to_synopsis () {
fi &&
b2t="$(builtin_to_txt "$builtin")" &&
sed -n \
- -e '/^\[verse\]$/,/^$/ {
+ -E '/^\[(verse|synopsis)\]$/,/^$/ {
/^$/d;
- /^\[verse\]$/d;
-
- s/{litdd}/--/g;
- s/'\''\(git[ a-z-]*\)'\''/\1/g;
+ /^\[(verse|synopsis)\]$/d;
+ s/\{litdd\}/--/g;
+ s/'\''(git[ a-z-]*)'\''/\1/g;
p;
}' \
diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches
index a0777acd66..28003f18c9 100644
--- a/t/t0450/txt-help-mismatches
+++ b/t/t0450/txt-help-mismatches
@@ -10,7 +10,6 @@ checkout
checkout-index
clone
column
-config
credential
credential-cache
credential-store
diff --git a/t/t0500-progress-display.sh b/t/t0500-progress-display.sh
index 1eb3a8306b..d1a498a216 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -2,7 +2,6 @@
test_description='progress display'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
show_cr () {
diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh
new file mode 100755
index 0000000000..1e62c791d9
--- /dev/null
+++ b/t/t0600-reffiles-backend.sh
@@ -0,0 +1,502 @@
+#!/bin/sh
+
+test_description='Test reffiles backend'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=files
+export GIT_TEST_DEFAULT_REF_FORMAT
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ git commit --allow-empty -m Initial &&
+ C=$(git rev-parse HEAD) &&
+ git commit --allow-empty -m Second &&
+ D=$(git rev-parse HEAD) &&
+ git commit --allow-empty -m Third &&
+ E=$(git rev-parse HEAD)
+'
+
+test_expect_success 'empty directory should not fool rev-parse' '
+ prefix=refs/e-rev-parse &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ echo "$C" >expected &&
+ git rev-parse $prefix/foo >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'empty directory should not fool for-each-ref' '
+ prefix=refs/e-for-each-ref &&
+ git update-ref $prefix/foo $C &&
+ git for-each-ref $prefix >expected &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ git for-each-ref $prefix >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'empty directory should not fool create' '
+ prefix=refs/e-create &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ printf "create %s $C\n" $prefix/foo |
+ git update-ref --stdin
+'
+
+test_expect_success 'empty directory should not fool verify' '
+ prefix=refs/e-verify &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ printf "verify %s $C\n" $prefix/foo |
+ git update-ref --stdin
+'
+
+test_expect_success 'empty directory should not fool 1-arg update' '
+ prefix=refs/e-update-1 &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ printf "update %s $D\n" $prefix/foo |
+ git update-ref --stdin
+'
+
+test_expect_success 'empty directory should not fool 2-arg update' '
+ prefix=refs/e-update-2 &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ printf "update %s $D $C\n" $prefix/foo |
+ git update-ref --stdin
+'
+
+test_expect_success 'empty directory should not fool 0-arg delete' '
+ prefix=refs/e-delete-0 &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ printf "delete %s\n" $prefix/foo |
+ git update-ref --stdin
+'
+
+test_expect_success 'empty directory should not fool 1-arg delete' '
+ prefix=refs/e-delete-1 &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ mkdir -p .git/$prefix/foo/bar/baz &&
+ printf "delete %s $C\n" $prefix/foo |
+ git update-ref --stdin
+'
+
+test_expect_success 'non-empty directory blocks create' - <<\EOT
+ prefix=refs/ne-create &&
+ mkdir -p .git/$prefix/foo/bar &&
+ : >.git/$prefix/foo/bar/baz.lock &&
+ test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/foo': there is a non-empty directory '.git/$prefix/foo' blocking reference '$prefix/foo'
+ EOF
+ printf "%s\n" "update $prefix/foo $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo'
+ EOF
+ printf "%s\n" "update $prefix/foo $D $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err
+EOT
+
+test_expect_success 'broken reference blocks create' - <<\EOT
+ prefix=refs/broken-create &&
+ mkdir -p .git/$prefix &&
+ echo "gobbledigook" >.git/$prefix/foo &&
+ test_when_finished "rm -f .git/$prefix/foo" &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo': reference broken
+ EOF
+ printf "%s\n" "update $prefix/foo $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo': reference broken
+ EOF
+ printf "%s\n" "update $prefix/foo $D $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err
+EOT
+
+test_expect_success 'non-empty directory blocks indirect create' - <<\EOT
+ prefix=refs/ne-indirect-create &&
+ git symbolic-ref $prefix/symref $prefix/foo &&
+ mkdir -p .git/$prefix/foo/bar &&
+ : >.git/$prefix/foo/bar/baz.lock &&
+ test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/symref': there is a non-empty directory '.git/$prefix/foo' blocking reference '$prefix/foo'
+ EOF
+ printf "%s\n" "update $prefix/symref $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo'
+ EOF
+ printf "%s\n" "update $prefix/symref $D $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err
+EOT
+
+test_expect_success 'broken reference blocks indirect create' - <<\EOT
+ prefix=refs/broken-indirect-create &&
+ git symbolic-ref $prefix/symref $prefix/foo &&
+ echo "gobbledigook" >.git/$prefix/foo &&
+ test_when_finished "rm -f .git/$prefix/foo" &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo': reference broken
+ EOF
+ printf "%s\n" "update $prefix/symref $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err &&
+ cat >expected <<-EOF &&
+ fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo': reference broken
+ EOF
+ printf "%s\n" "update $prefix/symref $D $C" |
+ test_must_fail git update-ref --stdin 2>output.err &&
+ test_cmp expected output.err
+EOT
+
+test_expect_success 'no bogus intermediate values during delete' '
+ prefix=refs/slow-transaction &&
+ # Set up a reference with differing loose and packed versions:
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ git update-ref $prefix/foo $D &&
+ # 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 &&
+ test_when_finished "rm -f .git/packed-refs.lock" &&
+ {
+ # Note: the following command is intentionally run in the
+ # background. We increase the timeout so that `update-ref`
+ # attempts to acquire the `packed-refs` lock for much longer
+ # than it takes for us to do the check then delete it:
+ git -c core.packedrefstimeout=30000 update-ref -d $prefix/foo &
+ } &&
+ pid2=$! &&
+ # Give update-ref plenty of time to get to the point where it tries
+ # to lock packed-refs:
+ sleep 1 &&
+ # Make sure that update-ref did not complete despite the lock:
+ kill -0 $pid2 &&
+ # Verify that the reference still has its old value:
+ sha1=$(git rev-parse --verify --quiet $prefix/foo || echo undefined) &&
+ case "$sha1" in
+ $D)
+ # This is what we hope for; it means that nothing
+ # user-visible has changed yet.
+ : ;;
+ undefined)
+ # This is not correct; it means the deletion has happened
+ # already even though update-ref should not have been
+ # able to acquire the lock yet.
+ echo "$prefix/foo deleted prematurely" &&
+ break
+ ;;
+ $C)
+ # This value should never be seen. Probably the loose
+ # reference has been deleted but the packed reference
+ # is still there:
+ echo "$prefix/foo incorrectly observed to be C" &&
+ break
+ ;;
+ *)
+ # WTF?
+ echo "unexpected value observed for $prefix/foo: $sha1" &&
+ break
+ ;;
+ esac >out &&
+ rm -f .git/packed-refs.lock &&
+ wait $pid2 &&
+ test_must_be_empty out &&
+ test_must_fail git rev-parse --verify --quiet $prefix/foo
+'
+
+test_expect_success 'delete fails cleanly if packed-refs file is locked' - <<\EOT
+ prefix=refs/locked-packed-refs &&
+ # Set up a reference with differing loose and packed versions:
+ 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 delete it while the `packed-refs` lock is held:
+ : >.git/packed-refs.lock &&
+ test_when_finished "rm -f .git/packed-refs.lock" &&
+ test_must_fail git update-ref -d $prefix/foo >out 2>err &&
+ git for-each-ref $prefix >actual &&
+ test_grep "Unable to create '.*packed-refs.lock': " err &&
+ test_cmp unchanged actual
+EOT
+
+test_expect_success 'delete fails cleanly if packed-refs.new write fails' '
+ # Setup and expectations are similar to the test above.
+ prefix=refs/failed-packed-refs &&
+ git update-ref $prefix/foo $C &&
+ git pack-refs --all &&
+ git update-ref $prefix/foo $D &&
+ git for-each-ref $prefix >unchanged &&
+ # This should not happen in practice, but it is an easy way to get a
+ # reliable error (we open with create_tempfile(), which uses O_EXCL).
+ : >.git/packed-refs.new &&
+ test_when_finished "rm -f .git/packed-refs.new" &&
+ test_must_fail git update-ref -d $prefix/foo &&
+ git for-each-ref $prefix >actual &&
+ test_cmp unchanged actual
+'
+
+RWT="test-tool ref-store worktree:wt"
+RMAIN="test-tool ref-store worktree:main"
+
+test_expect_success 'setup worktree' '
+ test_commit first &&
+ git worktree add -b wt-main wt &&
+ (
+ cd wt &&
+ test_commit second
+ )
+'
+
+# Some refs (refs/bisect/*, pseudorefs) are kept per worktree, so they should
+# only appear in the for-each-reflog output if it is called from the correct
+# worktree, which is exercised in this test. This test is poorly written for
+# multiple reasons: 1) it creates invalidly formatted log entries. 2) it uses
+# direct FS access for creating the reflogs. 3) PSEUDO-WT and refs/bisect/random
+# do not create reflogs by default, so it is not testing a realistic scenario.
+test_expect_success 'for_each_reflog()' '
+ echo $ZERO_OID >.git/logs/PSEUDO_MAIN_HEAD &&
+ mkdir -p .git/logs/refs/bisect &&
+ echo $ZERO_OID >.git/logs/refs/bisect/random &&
+
+ echo $ZERO_OID >.git/worktrees/wt/logs/PSEUDO_WT_HEAD &&
+ mkdir -p .git/worktrees/wt/logs/refs/bisect &&
+ echo $ZERO_OID >.git/worktrees/wt/logs/refs/bisect/wt-random &&
+
+ $RWT for-each-reflog >actual &&
+ cat >expected <<-\EOF &&
+ HEAD
+ PSEUDO_WT_HEAD
+ refs/bisect/wt-random
+ refs/heads/main
+ refs/heads/wt-main
+ EOF
+ test_cmp expected actual &&
+
+ $RMAIN for-each-reflog >actual &&
+ cat >expected <<-\EOF &&
+ HEAD
+ PSEUDO_MAIN_HEAD
+ refs/bisect/random
+ refs/heads/main
+ refs/heads/wt-main
+ EOF
+ test_cmp expected actual
+'
+
+# Triggering the bug detected by this test requires a newline to fall
+# exactly BUFSIZ-1 bytes from the end of the file. We don't know
+# what that value is, since it's platform dependent. However, if
+# we choose some value N, we also catch any D which divides N evenly
+# (since we will read backwards in chunks of D). So we choose 8K,
+# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
+#
+# Each line is 114 characters, so we need 75 to still have a few before the
+# last 8K. The 89-character padding on the final entry lines up our
+# newline exactly.
+test_expect_success SHA1 'parsing reverse reflogs at BUFSIZ boundaries' '
+ git checkout -b reflogskip &&
+ zf=$(test_oid zero_2) &&
+ ident="abc <xyz> 0000000001 +0000" &&
+ for i in $(test_seq 1 75); do
+ printf "$zf%02d $zf%02d %s\t" $i $(($i+1)) "$ident" &&
+ if test $i = 75; then
+ for j in $(test_seq 1 89); do
+ printf X || return 1
+ done
+ else
+ printf X
+ fi &&
+ printf "\n" || return 1
+ done >.git/logs/refs/heads/reflogskip &&
+ git rev-parse reflogskip@{73} >actual &&
+ echo ${zf}03 >expect &&
+ test_cmp expect actual
+'
+
+# This test takes a lock on an individual ref; this is not supported in
+# reftable.
+test_expect_success 'reflog expire operates on symref not referrent' '
+ git branch --create-reflog the_symref &&
+ git branch --create-reflog referrent &&
+ git update-ref referrent HEAD &&
+ git symbolic-ref refs/heads/the_symref refs/heads/referrent &&
+ test_when_finished "rm -f .git/refs/heads/referrent.lock" &&
+ touch .git/refs/heads/referrent.lock &&
+ git reflog expire --expire=all the_symref
+'
+
+test_expect_success 'empty reflog' '
+ test_when_finished "rm -rf empty" &&
+ git init empty &&
+ test_commit -C empty A &&
+ >empty/.git/logs/refs/heads/foo &&
+ git -C empty reflog expire --all 2>err &&
+ test_must_be_empty err
+'
+
+test_expect_success SYMLINKS 'ref resolution not confused by broken symlinks' '
+ ln -s does-not-exist .git/refs/heads/broken &&
+ test_must_fail git rev-parse --verify broken
+'
+
+test_expect_success 'log diagnoses bogus HEAD hash' '
+ git init empty &&
+ test_when_finished "rm -rf empty" &&
+ echo 1234abcd >empty/.git/refs/heads/main &&
+ test_must_fail git -C empty log 2>stderr &&
+ test_grep broken stderr
+'
+
+test_expect_success 'log diagnoses bogus HEAD symref' '
+ git init empty &&
+ test-tool -C empty ref-store main create-symref HEAD refs/heads/invalid.lock &&
+ test_must_fail git -C empty log 2>stderr &&
+ test_grep broken stderr &&
+ test_must_fail git -C empty log --default totally-bogus 2>stderr &&
+ test_grep broken stderr
+'
+
+test_expect_success 'empty directory removal' '
+ git branch d1/d2/r1 HEAD &&
+ git branch d1/r2 HEAD &&
+ test_path_is_file .git/refs/heads/d1/d2/r1 &&
+ test_path_is_file .git/logs/refs/heads/d1/d2/r1 &&
+ git branch -d d1/d2/r1 &&
+ test_must_fail git show-ref --verify -q refs/heads/d1/d2 &&
+ test_must_fail git show-ref --verify -q logs/refs/heads/d1/d2 &&
+ test_path_is_file .git/refs/heads/d1/r2 &&
+ test_path_is_file .git/logs/refs/heads/d1/r2
+'
+
+test_expect_success 'symref empty directory removal' '
+ git branch e1/e2/r1 HEAD &&
+ git branch e1/r2 HEAD &&
+ git checkout e1/e2/r1 &&
+ test_when_finished "git checkout main" &&
+ test_path_is_file .git/refs/heads/e1/e2/r1 &&
+ test_path_is_file .git/logs/refs/heads/e1/e2/r1 &&
+ git update-ref -d HEAD &&
+ test_must_fail git show-ref --verify -q refs/heads/e1/e2 &&
+ test_must_fail git show-ref --verify -q logs/refs/heads/e1/e2 &&
+ test_path_is_file .git/refs/heads/e1/r2 &&
+ test_path_is_file .git/logs/refs/heads/e1/r2 &&
+ test_path_is_file .git/logs/HEAD
+'
+
+test_expect_success 'directory not created deleting packed ref' '
+ git branch d1/d2/r1 HEAD &&
+ git pack-refs --all &&
+ test_path_is_missing .git/refs/heads/d1/d2 &&
+ git update-ref -d refs/heads/d1/d2/r1 &&
+ test_path_is_missing .git/refs/heads/d1/d2 &&
+ test_path_is_missing .git/refs/heads/d1
+'
+
+test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for u is a symlink' '
+ git branch --create-reflog u &&
+ mv .git/logs/refs/heads/u real-u &&
+ ln -s real-u .git/logs/refs/heads/u &&
+ test_must_fail git branch -m u v
+'
+
+test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' '
+ test_when_finished "rm -rf subdir" &&
+ git init --bare subdir &&
+
+ rm -rf subdir/refs subdir/objects subdir/packed-refs &&
+ ln -s ../.git/refs subdir/refs &&
+ ln -s ../.git/objects subdir/objects &&
+ ln -s ../.git/packed-refs subdir/packed-refs &&
+
+ git -C subdir rev-parse --absolute-git-dir >subdir.dir &&
+ git rev-parse --absolute-git-dir >our.dir &&
+ ! test_cmp subdir.dir our.dir &&
+
+ git -C subdir log &&
+ git -C subdir branch rename-src &&
+ git rev-parse rename-src >expect &&
+ git -C subdir branch -m rename-src rename-dest &&
+ git rev-parse rename-dest >actual &&
+ test_cmp expect actual &&
+ git branch -D rename-dest
+'
+
+test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' '
+ git checkout main &&
+ mv .git/logs actual_logs &&
+ cmd //c "mklink /D .git\logs ..\actual_logs" &&
+ git rebase -f HEAD^ &&
+ test -L .git/logs &&
+ rm .git/logs &&
+ mv actual_logs .git/logs
+'
+
+test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
+ umask 077 &&
+ git config core.sharedRepository group &&
+ git reflog expire --all &&
+ actual="$(ls -l .git/logs/refs/heads/main)" &&
+ case "$actual" in
+ -rw-rw-*)
+ : happy
+ ;;
+ *)
+ echo Ooops, .git/logs/refs/heads/main is not 066x [$actual]
+ false
+ ;;
+ esac
+'
+
+test_expect_success SYMLINKS 'symref transaction supports symlinks' '
+ test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" &&
+ git update-ref refs/heads/new @ &&
+ test_config core.prefersymlinkrefs true &&
+ cat >stdin <<-EOF &&
+ start
+ symref-create TEST_SYMREF_HEAD refs/heads/new
+ prepare
+ commit
+ EOF
+ git update-ref --no-deref --stdin <stdin &&
+ test_path_is_symlink .git/TEST_SYMREF_HEAD &&
+ test "$(test_readlink .git/TEST_SYMREF_HEAD)" = refs/heads/new
+'
+
+test_expect_success 'symref transaction supports false symlink config' '
+ test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" &&
+ git update-ref refs/heads/new @ &&
+ test_config core.prefersymlinkrefs false &&
+ cat >stdin <<-EOF &&
+ start
+ symref-create TEST_SYMREF_HEAD refs/heads/new
+ prepare
+ commit
+ EOF
+ git update-ref --no-deref --stdin <stdin &&
+ test_path_is_file .git/TEST_SYMREF_HEAD &&
+ git symbolic-ref TEST_SYMREF_HEAD >actual &&
+ echo refs/heads/new >expect &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3210-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh
index 7326adb70f..aa7f6ecd81 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t0601-reffiles-pack-refs.sh
@@ -9,10 +9,12 @@ test_description='git pack-refs should not change the branch semantic
This test runs git pack-refs and git show-ref and checks that the branch
semantic is still the same.
'
+
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=files
+export GIT_TEST_DEFAULT_REF_FORMAT
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'enable reflogs' '
@@ -26,6 +28,19 @@ test_expect_success 'prepare a trivial repository' '
HEAD=$(git rev-parse --verify HEAD)
'
+test_expect_success 'pack-refs --prune --all' '
+ test_path_is_missing .git/packed-refs &&
+ git pack-refs --no-prune --all &&
+ test_path_is_file .git/packed-refs &&
+ N=$(find .git/refs -type f | wc -l) &&
+ test "$N" != 0 &&
+
+ git pack-refs --prune --all &&
+ test_path_is_file .git/packed-refs &&
+ N=$(find .git/refs -type f) &&
+ test -z "$N"
+'
+
SHA1=
test_expect_success 'see if git show-ref works as expected' '
@@ -227,7 +242,7 @@ test_expect_success 'notice d/f conflict with existing directory' '
test_expect_success 'existing directory reports concrete ref' '
test_must_fail git branch foo 2>stderr &&
- test_i18ngrep refs/heads/foo/bar/baz stderr
+ test_grep refs/heads/foo/bar/baz stderr
'
test_expect_success 'notice d/f conflict with existing ref' '
@@ -294,4 +309,140 @@ test_expect_success SYMLINKS 'pack symlinked packed-refs' '
test "$(test_readlink .git/packed-refs)" = "my-deviant-packed-refs"
'
+# The 'packed-refs' file is stored directly in .git/. This means it is global
+# to the repository, and can only contain refs that are shared across all
+# worktrees.
+test_expect_success 'refs/worktree must not be packed' '
+ test_commit initial &&
+ test_commit wt1 &&
+ test_commit wt2 &&
+ git worktree add wt1 wt1 &&
+ git worktree add wt2 wt2 &&
+ git checkout initial &&
+ git update-ref refs/worktree/foo HEAD &&
+ git -C wt1 update-ref refs/worktree/foo HEAD &&
+ git -C wt2 update-ref refs/worktree/foo HEAD &&
+ git pack-refs --all &&
+ test_path_is_missing .git/refs/tags/wt1 &&
+ test_path_is_file .git/refs/worktree/foo &&
+ test_path_is_file .git/worktrees/wt1/refs/worktree/foo &&
+ test_path_is_file .git/worktrees/wt2/refs/worktree/foo
+'
+
+# we do not want to count on running pack-refs to
+# actually pack it, as it is perfectly reasonable to
+# skip processing a broken ref
+test_expect_success 'create packed-refs file with broken ref' '
+ test_tick && git commit --allow-empty -m one &&
+ recoverable=$(git rev-parse HEAD) &&
+ test_tick && git commit --allow-empty -m two &&
+ missing=$(git rev-parse HEAD) &&
+ rm -f .git/refs/heads/main &&
+ cat >.git/packed-refs <<-EOF &&
+ $missing refs/heads/main
+ $recoverable refs/heads/other
+ EOF
+ echo $missing >expect &&
+ git rev-parse refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'pack-refs does not silently delete broken packed ref' '
+ git pack-refs --all --prune &&
+ git rev-parse refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'pack-refs does not drop broken refs during deletion' '
+ git update-ref -d refs/heads/other &&
+ git rev-parse refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+for command in "git pack-refs --all --auto" "git maintenance run --task=pack-refs --auto"
+do
+ test_expect_success "$command does not repack below 16 refs without packed-refs" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config set maintenance.auto false &&
+ git commit --allow-empty --message "initial" &&
+
+ # Create 14 additional references, which brings us to
+ # 15 together with the default branch.
+ printf "create refs/heads/loose-%d HEAD\n" $(test_seq 14) >stdin &&
+ git update-ref --stdin <stdin &&
+ test_path_is_missing .git/packed-refs &&
+ git pack-refs --auto --all &&
+ test_path_is_missing .git/packed-refs &&
+
+ # Create the 16th reference, which should cause us to repack.
+ git update-ref refs/heads/loose-15 HEAD &&
+ git pack-refs --auto --all &&
+ test_path_is_file .git/packed-refs
+ )
+ '
+
+ test_expect_success "$command does not repack below 16 refs with small packed-refs" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config set maintenance.auto false &&
+ git commit --allow-empty --message "initial" &&
+
+ git pack-refs --all &&
+ test_line_count = 2 .git/packed-refs &&
+
+ # Create 15 loose references.
+ printf "create refs/heads/loose-%d HEAD\n" $(test_seq 15) >stdin &&
+ git update-ref --stdin <stdin &&
+ git pack-refs --auto --all &&
+ test_line_count = 2 .git/packed-refs &&
+
+ # Create the 16th loose reference, which should cause us to repack.
+ git update-ref refs/heads/loose-17 HEAD &&
+ git pack-refs --auto --all &&
+ test_line_count = 18 .git/packed-refs
+ )
+ '
+
+ test_expect_success "$command scales with size of packed-refs" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config set maintenance.auto false &&
+ git commit --allow-empty --message "initial" &&
+
+ # Create 99 packed refs. This should cause the heuristic
+ # to require more than the minimum amount of loose refs.
+ test_seq 99 |
+ while read i
+ do
+ printf "create refs/heads/packed-%d HEAD\n" $i || return 1
+ done >stdin &&
+ git update-ref --stdin <stdin &&
+ git pack-refs --all &&
+ test_line_count = 101 .git/packed-refs &&
+
+ # Create 24 loose refs, which should not yet cause us to repack.
+ printf "create refs/heads/loose-%d HEAD\n" $(test_seq 24) >stdin &&
+ git update-ref --stdin <stdin &&
+ git pack-refs --auto --all &&
+ test_line_count = 101 .git/packed-refs &&
+
+ # Create another handful of refs to cross the border.
+ # Note that we explicitly do not check for strict
+ # boundaries here, as this also depends on the size of
+ # the object hash.
+ printf "create refs/heads/addn-%d HEAD\n" $(test_seq 10) >stdin &&
+ git update-ref --stdin <stdin &&
+ git pack-refs --auto --all &&
+ test_line_count = 135 .git/packed-refs
+ )
+ '
+done
+
test_done
diff --git a/t/t0602-reffiles-fsck.sh b/t/t0602-reffiles-fsck.sh
new file mode 100755
index 0000000000..d4a08b823b
--- /dev/null
+++ b/t/t0602-reffiles-fsck.sh
@@ -0,0 +1,599 @@
+#!/bin/sh
+
+test_description='Test reffiles backend consistency check'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=files
+export GIT_TEST_DEFAULT_REF_FORMAT
+
+. ./test-lib.sh
+
+test_expect_success 'ref name should be checked' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+
+ git commit --allow-empty -m initial &&
+ git checkout -b default-branch &&
+ git tag default-tag &&
+ git tag multi_hierarchy/default-tag &&
+
+ cp $branch_dir_prefix/default-branch $branch_dir_prefix/@ &&
+ git refs verify 2>err &&
+ test_must_be_empty err &&
+ rm $branch_dir_prefix/@ &&
+
+ cp $tag_dir_prefix/default-tag $tag_dir_prefix/tag-1.lock &&
+ git refs verify 2>err &&
+ rm $tag_dir_prefix/tag-1.lock &&
+ test_must_be_empty err &&
+
+ cp $tag_dir_prefix/default-tag $tag_dir_prefix/.lock &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/tags/.lock: badRefName: invalid refname format
+ EOF
+ rm $tag_dir_prefix/.lock &&
+ test_cmp expect err &&
+
+ for refname in ".refname-starts-with-dot" "~refname-has-stride"
+ do
+ cp $branch_dir_prefix/default-branch "$branch_dir_prefix/$refname" &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/$refname: badRefName: invalid refname format
+ EOF
+ rm "$branch_dir_prefix/$refname" &&
+ test_cmp expect err || return 1
+ done &&
+
+ for refname in ".refname-starts-with-dot" "~refname-has-stride"
+ do
+ cp $tag_dir_prefix/default-tag "$tag_dir_prefix/$refname" &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/tags/$refname: badRefName: invalid refname format
+ EOF
+ rm "$tag_dir_prefix/$refname" &&
+ test_cmp expect err || return 1
+ done &&
+
+ for refname in ".refname-starts-with-dot" "~refname-has-stride"
+ do
+ cp $tag_dir_prefix/multi_hierarchy/default-tag "$tag_dir_prefix/multi_hierarchy/$refname" &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/tags/multi_hierarchy/$refname: badRefName: invalid refname format
+ EOF
+ rm "$tag_dir_prefix/multi_hierarchy/$refname" &&
+ test_cmp expect err || return 1
+ done &&
+
+ for refname in ".refname-starts-with-dot" "~refname-has-stride"
+ do
+ mkdir "$branch_dir_prefix/$refname" &&
+ cp $branch_dir_prefix/default-branch "$branch_dir_prefix/$refname/default-branch" &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/$refname/default-branch: badRefName: invalid refname format
+ EOF
+ rm -r "$branch_dir_prefix/$refname" &&
+ test_cmp expect err || return 1
+ done
+'
+
+test_expect_success 'ref name check should be adapted into fsck messages' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ cd repo &&
+ git commit --allow-empty -m initial &&
+ git checkout -b branch-1 &&
+
+ cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
+ git -c fsck.badRefName=warn refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/.branch-1: badRefName: invalid refname format
+ EOF
+ rm $branch_dir_prefix/.branch-1 &&
+ test_cmp expect err &&
+
+ cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
+ git -c fsck.badRefName=ignore refs verify 2>err &&
+ test_must_be_empty err
+'
+
+test_expect_success 'ref name check should work for multiple worktrees' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+
+ cd repo &&
+ test_commit initial &&
+ git checkout -b branch-1 &&
+ test_commit second &&
+ git checkout -b branch-2 &&
+ test_commit third &&
+ git checkout -b branch-3 &&
+ git worktree add ./worktree-1 branch-1 &&
+ git worktree add ./worktree-2 branch-2 &&
+ worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree &&
+ worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree &&
+
+ (
+ cd worktree-1 &&
+ git update-ref refs/worktree/branch-4 refs/heads/branch-3
+ ) &&
+ (
+ cd worktree-2 &&
+ git update-ref refs/worktree/branch-4 refs/heads/branch-3
+ ) &&
+
+ cp $worktree1_refdir_prefix/branch-4 $worktree1_refdir_prefix/'\'' branch-5'\'' &&
+ cp $worktree2_refdir_prefix/branch-4 $worktree2_refdir_prefix/'\''~branch-6'\'' &&
+
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format
+ error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format
+ EOF
+ sort err >sorted_err &&
+ test_cmp expect sorted_err &&
+
+ for worktree in "worktree-1" "worktree-2"
+ do
+ (
+ cd $worktree &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format
+ error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format
+ EOF
+ sort err >sorted_err &&
+ test_cmp expect sorted_err || return 1
+ )
+ done
+'
+
+test_expect_success 'regular ref content should be checked (individual)' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ cd repo &&
+ test_commit default &&
+ mkdir -p "$branch_dir_prefix/a/b" &&
+
+ git refs verify 2>err &&
+ test_must_be_empty err &&
+
+ for bad_content in "$(git rev-parse main)x" "xfsazqfxcadas" "Xfsazqfxcadas"
+ do
+ printf "%s" $bad_content >$branch_dir_prefix/branch-bad &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/branch-bad: badRefContent: $bad_content
+ EOF
+ rm $branch_dir_prefix/branch-bad &&
+ test_cmp expect err || return 1
+ done &&
+
+ for bad_content in "$(git rev-parse main)x" "xfsazqfxcadas" "Xfsazqfxcadas"
+ do
+ printf "%s" $bad_content >$branch_dir_prefix/a/b/branch-bad &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/a/b/branch-bad: badRefContent: $bad_content
+ EOF
+ rm $branch_dir_prefix/a/b/branch-bad &&
+ test_cmp expect err || return 1
+ done &&
+
+ printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end
+ EOF
+ rm $branch_dir_prefix/branch-no-newline &&
+ test_cmp expect err &&
+
+ for trailing_content in " garbage" " more garbage"
+ do
+ printf "%s" "$(git rev-parse main)$trailing_content" >$branch_dir_prefix/branch-garbage &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\''$trailing_content'\''
+ EOF
+ rm $branch_dir_prefix/branch-garbage &&
+ test_cmp expect err || return 1
+ done &&
+
+ printf "%s\n\n\n" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\''
+
+
+ '\''
+ EOF
+ rm $branch_dir_prefix/branch-garbage-special &&
+ test_cmp expect err &&
+
+ printf "%s\n\n\n garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\''
+
+
+ garbage'\''
+ EOF
+ rm $branch_dir_prefix/branch-garbage-special &&
+ test_cmp expect err
+'
+
+test_expect_success 'regular ref content should be checked (aggregate)' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+ test_commit default &&
+ mkdir -p "$branch_dir_prefix/a/b" &&
+
+ bad_content_1=$(git rev-parse main)x &&
+ bad_content_2=xfsazqfxcadas &&
+ bad_content_3=Xfsazqfxcadas &&
+ printf "%s" $bad_content_1 >$tag_dir_prefix/tag-bad-1 &&
+ printf "%s" $bad_content_2 >$tag_dir_prefix/tag-bad-2 &&
+ printf "%s" $bad_content_3 >$branch_dir_prefix/a/b/branch-bad &&
+ printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline &&
+ printf "%s garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage &&
+
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/a/b/branch-bad: badRefContent: $bad_content_3
+ error: refs/tags/tag-bad-1: badRefContent: $bad_content_1
+ error: refs/tags/tag-bad-2: badRefContent: $bad_content_2
+ warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\''
+ warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end
+ EOF
+ sort err >sorted_err &&
+ test_cmp expect sorted_err
+'
+
+test_expect_success 'textual symref content should be checked (individual)' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ cd repo &&
+ test_commit default &&
+ mkdir -p "$branch_dir_prefix/a/b" &&
+
+ for good_referent in "refs/heads/branch" "HEAD"
+ do
+ printf "ref: %s\n" $good_referent >$branch_dir_prefix/branch-good &&
+ git refs verify 2>err &&
+ rm $branch_dir_prefix/branch-good &&
+ test_must_be_empty err || return 1
+ done &&
+
+ for bad_referent in "refs/heads/.branch" "refs/heads/~branch" "refs/heads/?branch"
+ do
+ printf "ref: %s\n" $bad_referent >$branch_dir_prefix/branch-bad &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/branch-bad: badReferentName: points to invalid refname '\''$bad_referent'\''
+ EOF
+ rm $branch_dir_prefix/branch-bad &&
+ test_cmp expect err || return 1
+ done &&
+
+ printf "ref: refs/heads/branch" >$branch_dir_prefix/branch-no-newline &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end
+ EOF
+ rm $branch_dir_prefix/branch-no-newline &&
+ test_cmp expect err &&
+
+ printf "ref: refs/heads/branch " >$branch_dir_prefix/a/b/branch-trailing-1 &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/a/b/branch-trailing-1: refMissingNewline: misses LF at the end
+ warning: refs/heads/a/b/branch-trailing-1: trailingRefContent: has trailing whitespaces or newlines
+ EOF
+ rm $branch_dir_prefix/a/b/branch-trailing-1 &&
+ test_cmp expect err &&
+
+ printf "ref: refs/heads/branch\n\n" >$branch_dir_prefix/a/b/branch-trailing-2 &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/a/b/branch-trailing-2: trailingRefContent: has trailing whitespaces or newlines
+ EOF
+ rm $branch_dir_prefix/a/b/branch-trailing-2 &&
+ test_cmp expect err &&
+
+ printf "ref: refs/heads/branch \n" >$branch_dir_prefix/a/b/branch-trailing-3 &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/a/b/branch-trailing-3: trailingRefContent: has trailing whitespaces or newlines
+ EOF
+ rm $branch_dir_prefix/a/b/branch-trailing-3 &&
+ test_cmp expect err &&
+
+ printf "ref: refs/heads/branch \n " >$branch_dir_prefix/a/b/branch-complicated &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/a/b/branch-complicated: refMissingNewline: misses LF at the end
+ warning: refs/heads/a/b/branch-complicated: trailingRefContent: has trailing whitespaces or newlines
+ EOF
+ rm $branch_dir_prefix/a/b/branch-complicated &&
+ test_cmp expect err
+'
+
+test_expect_success 'textual symref content should be checked (aggregate)' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+ test_commit default &&
+ mkdir -p "$branch_dir_prefix/a/b" &&
+
+ printf "ref: refs/heads/branch\n" >$branch_dir_prefix/branch-good &&
+ printf "ref: HEAD\n" >$branch_dir_prefix/branch-head &&
+ printf "ref: refs/heads/branch" >$branch_dir_prefix/branch-no-newline-1 &&
+ printf "ref: refs/heads/branch " >$branch_dir_prefix/a/b/branch-trailing-1 &&
+ printf "ref: refs/heads/branch\n\n" >$branch_dir_prefix/a/b/branch-trailing-2 &&
+ printf "ref: refs/heads/branch \n" >$branch_dir_prefix/a/b/branch-trailing-3 &&
+ printf "ref: refs/heads/branch \n " >$branch_dir_prefix/a/b/branch-complicated &&
+ printf "ref: refs/heads/.branch\n" >$branch_dir_prefix/branch-bad-1 &&
+
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/branch-bad-1: badReferentName: points to invalid refname '\''refs/heads/.branch'\''
+ warning: refs/heads/a/b/branch-complicated: refMissingNewline: misses LF at the end
+ warning: refs/heads/a/b/branch-complicated: trailingRefContent: has trailing whitespaces or newlines
+ warning: refs/heads/a/b/branch-trailing-1: refMissingNewline: misses LF at the end
+ warning: refs/heads/a/b/branch-trailing-1: trailingRefContent: has trailing whitespaces or newlines
+ warning: refs/heads/a/b/branch-trailing-2: trailingRefContent: has trailing whitespaces or newlines
+ warning: refs/heads/a/b/branch-trailing-3: trailingRefContent: has trailing whitespaces or newlines
+ warning: refs/heads/branch-no-newline-1: refMissingNewline: misses LF at the end
+ EOF
+ sort err >sorted_err &&
+ test_cmp expect sorted_err
+'
+
+test_expect_success 'the target of the textual symref should be checked' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+ test_commit default &&
+ mkdir -p "$branch_dir_prefix/a/b" &&
+
+ for good_referent in "refs/heads/branch" "HEAD" "refs/tags/tag"
+ do
+ printf "ref: %s\n" $good_referent >$branch_dir_prefix/branch-good &&
+ git refs verify 2>err &&
+ rm $branch_dir_prefix/branch-good &&
+ test_must_be_empty err || return 1
+ done &&
+
+ for nonref_referent in "refs-back/heads/branch" "refs-back/tags/tag" "reflogs/refs/heads/branch"
+ do
+ printf "ref: %s\n" $nonref_referent >$branch_dir_prefix/branch-bad-1 &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-bad-1: symrefTargetIsNotARef: points to non-ref target '\''$nonref_referent'\''
+ EOF
+ rm $branch_dir_prefix/branch-bad-1 &&
+ test_cmp expect err || return 1
+ done
+'
+
+test_expect_success SYMLINKS 'symlink symref content should be checked' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+ test_commit default &&
+ mkdir -p "$branch_dir_prefix/a/b" &&
+
+ ln -sf ./main $branch_dir_prefix/branch-symbolic-good &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref
+ EOF
+ rm $branch_dir_prefix/branch-symbolic-good &&
+ test_cmp expect err &&
+
+ ln -sf ../../logs/branch-escape $branch_dir_prefix/branch-symbolic &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-symbolic: symlinkRef: use deprecated symbolic link for symref
+ warning: refs/heads/branch-symbolic: symrefTargetIsNotARef: points to non-ref target '\''logs/branch-escape'\''
+ EOF
+ rm $branch_dir_prefix/branch-symbolic &&
+ test_cmp expect err &&
+
+ ln -sf ./"branch " $branch_dir_prefix/branch-symbolic-bad &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-symbolic-bad: symlinkRef: use deprecated symbolic link for symref
+ error: refs/heads/branch-symbolic-bad: badReferentName: points to invalid refname '\''refs/heads/branch '\''
+ EOF
+ rm $branch_dir_prefix/branch-symbolic-bad &&
+ test_cmp expect err &&
+
+ ln -sf ./".tag" $tag_dir_prefix/tag-symbolic-1 &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/tags/tag-symbolic-1: symlinkRef: use deprecated symbolic link for symref
+ error: refs/tags/tag-symbolic-1: badReferentName: points to invalid refname '\''refs/tags/.tag'\''
+ EOF
+ rm $tag_dir_prefix/tag-symbolic-1 &&
+ test_cmp expect err
+'
+
+test_expect_success SYMLINKS 'symlink symref content should be checked (worktree)' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ cd repo &&
+ test_commit default &&
+ git branch branch-1 &&
+ git branch branch-2 &&
+ git branch branch-3 &&
+ git worktree add ./worktree-1 branch-2 &&
+ git worktree add ./worktree-2 branch-3 &&
+ main_worktree_refdir_prefix=.git/refs/heads &&
+ worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree &&
+ worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree &&
+
+ (
+ cd worktree-1 &&
+ git update-ref refs/worktree/branch-4 refs/heads/branch-1
+ ) &&
+ (
+ cd worktree-2 &&
+ git update-ref refs/worktree/branch-4 refs/heads/branch-1
+ ) &&
+
+ ln -sf ../../../../refs/heads/good-branch $worktree1_refdir_prefix/branch-symbolic-good &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-1/refs/worktree/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref
+ EOF
+ rm $worktree1_refdir_prefix/branch-symbolic-good &&
+ test_cmp expect err &&
+
+ ln -sf ../../../../worktrees/worktree-1/good-branch $worktree2_refdir_prefix/branch-symbolic-good &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-2/refs/worktree/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref
+ EOF
+ rm $worktree2_refdir_prefix/branch-symbolic-good &&
+ test_cmp expect err &&
+
+ ln -sf ../../worktrees/worktree-2/good-branch $main_worktree_refdir_prefix/branch-symbolic-good &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref
+ EOF
+ rm $main_worktree_refdir_prefix/branch-symbolic-good &&
+ test_cmp expect err &&
+
+ ln -sf ../../../../logs/branch-escape $worktree1_refdir_prefix/branch-symbolic &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-1/refs/worktree/branch-symbolic: symlinkRef: use deprecated symbolic link for symref
+ warning: worktrees/worktree-1/refs/worktree/branch-symbolic: symrefTargetIsNotARef: points to non-ref target '\''logs/branch-escape'\''
+ EOF
+ rm $worktree1_refdir_prefix/branch-symbolic &&
+ test_cmp expect err &&
+
+ for bad_referent_name in ".tag" "branch "
+ do
+ ln -sf ./"$bad_referent_name" $worktree1_refdir_prefix/bad-symbolic &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-1/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref
+ error: worktrees/worktree-1/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''worktrees/worktree-1/refs/worktree/$bad_referent_name'\''
+ EOF
+ rm $worktree1_refdir_prefix/bad-symbolic &&
+ test_cmp expect err &&
+
+ ln -sf ../../../../refs/heads/"$bad_referent_name" $worktree1_refdir_prefix/bad-symbolic &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-1/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref
+ error: worktrees/worktree-1/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''refs/heads/$bad_referent_name'\''
+ EOF
+ rm $worktree1_refdir_prefix/bad-symbolic &&
+ test_cmp expect err &&
+
+ ln -sf ./"$bad_referent_name" $worktree2_refdir_prefix/bad-symbolic &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-2/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref
+ error: worktrees/worktree-2/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''worktrees/worktree-2/refs/worktree/$bad_referent_name'\''
+ EOF
+ rm $worktree2_refdir_prefix/bad-symbolic &&
+ test_cmp expect err &&
+
+ ln -sf ../../../../refs/heads/"$bad_referent_name" $worktree2_refdir_prefix/bad-symbolic &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-2/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref
+ error: worktrees/worktree-2/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''refs/heads/$bad_referent_name'\''
+ EOF
+ rm $worktree2_refdir_prefix/bad-symbolic &&
+ test_cmp expect err || return 1
+ done
+'
+
+test_expect_success 'ref content checks should work with worktrees' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ cd repo &&
+ test_commit default &&
+ git branch branch-1 &&
+ git branch branch-2 &&
+ git branch branch-3 &&
+ git worktree add ./worktree-1 branch-2 &&
+ git worktree add ./worktree-2 branch-3 &&
+ worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree &&
+ worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree &&
+
+ (
+ cd worktree-1 &&
+ git update-ref refs/worktree/branch-4 refs/heads/branch-1
+ ) &&
+ (
+ cd worktree-2 &&
+ git update-ref refs/worktree/branch-4 refs/heads/branch-1
+ ) &&
+
+ for bad_content in "$(git rev-parse HEAD)x" "xfsazqfxcadas" "Xfsazqfxcadas"
+ do
+ printf "%s" $bad_content >$worktree1_refdir_prefix/bad-branch-1 &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: worktrees/worktree-1/refs/worktree/bad-branch-1: badRefContent: $bad_content
+ EOF
+ rm $worktree1_refdir_prefix/bad-branch-1 &&
+ test_cmp expect err || return 1
+ done &&
+
+ for bad_content in "$(git rev-parse HEAD)x" "xfsazqfxcadas" "Xfsazqfxcadas"
+ do
+ printf "%s" $bad_content >$worktree2_refdir_prefix/bad-branch-2 &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: worktrees/worktree-2/refs/worktree/bad-branch-2: badRefContent: $bad_content
+ EOF
+ rm $worktree2_refdir_prefix/bad-branch-2 &&
+ test_cmp expect err || return 1
+ done &&
+
+ printf "%s" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-no-newline &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-1/refs/worktree/branch-no-newline: refMissingNewline: misses LF at the end
+ EOF
+ rm $worktree1_refdir_prefix/branch-no-newline &&
+ test_cmp expect err &&
+
+ printf "%s garbage" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-garbage &&
+ git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: worktrees/worktree-1/refs/worktree/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\''
+ EOF
+ rm $worktree1_refdir_prefix/branch-garbage &&
+ test_cmp expect err
+'
+
+test_done
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
new file mode 100755
index 0000000000..4618ffc108
--- /dev/null
+++ b/t/t0610-reftable-basics.sh
@@ -0,0 +1,1136 @@
+#!/bin/sh
+#
+# Copyright (c) 2020 Google LLC
+#
+
+test_description='reftable basics'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=reftable
+export GIT_TEST_DEFAULT_REF_FORMAT
+
+. ./test-lib.sh
+
+INVALID_OID=$(test_oid 001)
+
+test_expect_success 'init: creates basic reftable structures' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_path_is_dir repo/.git/reftable &&
+ test_path_is_file repo/.git/reftable/tables.list &&
+ echo reftable >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'init: sha256 object format via environment variable' '
+ test_when_finished "rm -rf repo" &&
+ GIT_DEFAULT_HASH=sha256 git init repo &&
+ cat >expect <<-EOF &&
+ sha256
+ reftable
+ EOF
+ git -C repo rev-parse --show-object-format --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'init: sha256 object format via option' '
+ test_when_finished "rm -rf repo" &&
+ git init --object-format=sha256 repo &&
+ cat >expect <<-EOF &&
+ sha256
+ reftable
+ EOF
+ git -C repo rev-parse --show-object-format --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'init: reinitializing reftable backend succeeds' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo for-each-ref >expect &&
+ git init --ref-format=reftable repo &&
+ git -C repo for-each-ref >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'init: reinitializing files with reftable backend fails' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=files repo &&
+ test_commit -C repo file &&
+
+ cp repo/.git/HEAD expect &&
+ test_must_fail git init --ref-format=reftable repo &&
+ test_cmp expect repo/.git/HEAD
+'
+
+test_expect_success 'init: reinitializing reftable with files backend fails' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=reftable repo &&
+ test_commit -C repo file &&
+
+ cp repo/.git/HEAD expect &&
+ test_must_fail git init --ref-format=files repo &&
+ test_cmp expect repo/.git/HEAD
+'
+
+test_expect_perms () {
+ local perms="$1" &&
+ local file="$2" &&
+ local actual="$(ls -l "$file")" &&
+
+ case "$actual" in
+ $perms*)
+ : happy
+ ;;
+ *)
+ echo "$(basename $2) is not $perms but $actual"
+ false
+ ;;
+ esac
+}
+
+test_expect_reftable_perms () {
+ local umask="$1"
+ local shared="$2"
+ local expect="$3"
+
+ test_expect_success POSIXPERM "init: honors --shared=$shared with umask $umask" '
+ test_when_finished "rm -rf repo" &&
+ (
+ umask $umask &&
+ git init --shared=$shared repo
+ ) &&
+ test_expect_perms "$expect" repo/.git/reftable/tables.list &&
+ for table in repo/.git/reftable/*.ref
+ do
+ test_expect_perms "$expect" "$table" ||
+ return 1
+ done
+ '
+
+ test_expect_success POSIXPERM "pack-refs: honors --shared=$shared with umask $umask" '
+ test_when_finished "rm -rf repo" &&
+ (
+ umask $umask &&
+ git init --shared=$shared repo &&
+ test_commit -C repo A &&
+ test_line_count = 2 repo/.git/reftable/tables.list &&
+ git -C repo pack-refs
+ ) &&
+ test_expect_perms "$expect" repo/.git/reftable/tables.list &&
+ for table in repo/.git/reftable/*.ref
+ do
+ test_expect_perms "$expect" "$table" ||
+ return 1
+ done
+ '
+}
+
+test_expect_reftable_perms 002 umask "-rw-rw-r--"
+test_expect_reftable_perms 022 umask "-rw-r--r--"
+test_expect_reftable_perms 027 umask "-rw-r-----"
+
+test_expect_reftable_perms 002 group "-rw-rw-r--"
+test_expect_reftable_perms 022 group "-rw-rw-r--"
+test_expect_reftable_perms 027 group "-rw-rw----"
+
+test_expect_reftable_perms 002 world "-rw-rw-r--"
+test_expect_reftable_perms 022 world "-rw-rw-r--"
+test_expect_reftable_perms 027 world "-rw-rw-r--"
+
+test_expect_success 'clone: can clone reftable repository' '
+ test_when_finished "rm -rf repo clone" &&
+ git init repo &&
+ test_commit -C repo message1 file1 &&
+
+ git clone repo cloned &&
+ echo reftable >expect &&
+ git -C cloned rev-parse --show-ref-format >actual &&
+ test_cmp expect actual &&
+ test_path_is_file cloned/file1
+'
+
+test_expect_success 'clone: can clone reffiles into reftable repository' '
+ test_when_finished "rm -rf reffiles reftable" &&
+ git init --ref-format=files reffiles &&
+ test_commit -C reffiles A &&
+ git clone --ref-format=reftable ./reffiles reftable &&
+
+ git -C reffiles rev-parse HEAD >expect &&
+ git -C reftable rev-parse HEAD >actual &&
+ test_cmp expect actual &&
+
+ git -C reftable rev-parse --show-ref-format >actual &&
+ echo reftable >expect &&
+ test_cmp expect actual &&
+
+ git -C reffiles rev-parse --show-ref-format >actual &&
+ echo files >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone: can clone reftable into reffiles repository' '
+ test_when_finished "rm -rf reffiles reftable" &&
+ git init --ref-format=reftable reftable &&
+ test_commit -C reftable A &&
+ git clone --ref-format=files ./reftable reffiles &&
+
+ git -C reftable rev-parse HEAD >expect &&
+ git -C reffiles rev-parse HEAD >actual &&
+ test_cmp expect actual &&
+
+ git -C reftable rev-parse --show-ref-format >actual &&
+ echo reftable >expect &&
+ test_cmp expect actual &&
+
+ git -C reffiles rev-parse --show-ref-format >actual &&
+ echo files >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'ref transaction: corrupted tables cause failure' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file1 &&
+ for f in .git/reftable/*.ref
+ do
+ : >"$f" || return 1
+ done &&
+ test_must_fail git update-ref refs/heads/main HEAD
+ )
+'
+
+test_expect_success 'ref transaction: corrupted tables.list cause failure' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file1 &&
+ echo garbage >.git/reftable/tables.list &&
+ test_must_fail git update-ref refs/heads/main HEAD
+ )
+'
+
+test_expect_success 'ref transaction: refuses to write ref causing F/D conflict' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo file &&
+ test_must_fail git -C repo update-ref refs/heads/main/forbidden
+'
+
+test_expect_success 'ref transaction: deleting ref with invalid name fails' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo file &&
+ test_must_fail git -C repo update-ref -d ../../my-private-file
+'
+
+test_expect_success 'ref transaction: can skip object ID verification' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID 0 &&
+ test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION
+'
+
+test_expect_success 'ref transaction: updating same ref multiple times fails' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo A &&
+ cat >updates <<-EOF &&
+ update refs/heads/main $A
+ update refs/heads/main $A
+ EOF
+ cat >expect <<-EOF &&
+ fatal: multiple updates for ref ${SQ}refs/heads/main${SQ} not allowed
+ EOF
+ test_must_fail git -C repo update-ref --stdin <updates 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'ref transaction: can delete symbolic self-reference with git-symbolic-ref(1)' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -C repo symbolic-ref refs/heads/self refs/heads/self &&
+ git -C repo symbolic-ref -d refs/heads/self
+'
+
+test_expect_success 'ref transaction: deleting symbolic self-reference without --no-deref fails' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -C repo symbolic-ref refs/heads/self refs/heads/self &&
+ cat >expect <<-EOF &&
+ error: multiple updates for ${SQ}refs/heads/self${SQ} (including one via symref ${SQ}refs/heads/self${SQ}) are not allowed
+ EOF
+ test_must_fail git -C repo update-ref -d refs/heads/self 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'ref transaction: deleting symbolic self-reference with --no-deref succeeds' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -C repo symbolic-ref refs/heads/self refs/heads/self &&
+ git -C repo update-ref -d --no-deref refs/heads/self
+'
+
+test_expect_success 'ref transaction: creating symbolic ref fails with F/D conflict' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo A &&
+ cat >expect <<-EOF &&
+ error: ${SQ}refs/heads/main${SQ} exists; cannot create ${SQ}refs/heads${SQ}
+ EOF
+ test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'ref transaction: ref deletion' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file &&
+ HEAD_OID=$(git show-ref -s --verify HEAD) &&
+ cat >expect <<-EOF &&
+ $HEAD_OID refs/heads/main
+ $HEAD_OID refs/tags/file
+ EOF
+ git show-ref >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail git update-ref -d refs/tags/file $INVALID_OID &&
+ git show-ref >actual &&
+ test_cmp expect actual &&
+
+ git update-ref -d refs/tags/file $HEAD_OID &&
+ echo "$HEAD_OID refs/heads/main" >expect &&
+ git show-ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'ref transaction: writes cause auto-compaction' '
+ test_when_finished "rm -rf repo" &&
+
+ git init repo &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ test_commit -C repo --no-tag A &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ test_commit -C repo --no-tag B &&
+ test_line_count = 1 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'ref transaction: env var disables compaction' '
+ test_when_finished "rm -rf repo" &&
+
+ git init repo &&
+ test_commit -C repo A &&
+
+ start=$(wc -l <repo/.git/reftable/tables.list) &&
+ iterations=5 &&
+ expected=$((start + iterations)) &&
+
+ for i in $(test_seq $iterations)
+ do
+ GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
+ git -C repo update-ref branch-$i HEAD || return 1
+ done &&
+ test_line_count = $expected repo/.git/reftable/tables.list &&
+
+ git -C repo update-ref foo HEAD &&
+ test_line_count -lt $expected repo/.git/reftable/tables.list
+'
+
+test_expect_success 'ref transaction: alternating table sizes are compacted' '
+ test_when_finished "rm -rf repo" &&
+
+ git init repo &&
+ test_commit -C repo A &&
+ for i in $(test_seq 5)
+ do
+ git -C repo branch -f foo &&
+ git -C repo branch -d foo || return 1
+ done &&
+ test_line_count = 2 repo/.git/reftable/tables.list
+'
+
+check_fsync_events () {
+ local trace="$1" &&
+ shift &&
+
+ cat >expect &&
+ sed -n \
+ -e '/^{"event":"counter",.*"category":"fsync",/ {
+ s/.*"category":"fsync",//;
+ s/}$//;
+ p;
+ }' \
+ <"$trace" >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'ref transaction: writes are synced' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo initial &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ GIT_TEST_FSYNC=true \
+ git -C repo -c core.fsync=reference \
+ -c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD &&
+ check_fsync_events trace2.txt <<-EOF
+ "name":"hardware-flush","count":4
+ EOF
+'
+
+test_expect_success 'ref transaction: empty transaction in empty repo' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo --no-tag A &&
+ git -C repo update-ref -d refs/heads/main &&
+ test-tool -C repo ref-store main delete-refs REF_NO_DEREF msg HEAD &&
+ git -C repo update-ref --stdin <<-EOF
+ prepare
+ commit
+ EOF
+'
+
+test_expect_success 'ref transaction: fails gracefully when auto compaction fails' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ for i in $(test_seq 10)
+ do
+ git branch branch-$i &&
+ for table in .git/reftable/*.ref
+ do
+ touch "$table.lock" || exit 1
+ done ||
+ exit 1
+ done &&
+ test_line_count = 10 .git/reftable/tables.list
+ )
+'
+
+test_expect_success 'ref transaction: timeout acquiring tables.list lock' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ >.git/reftable/tables.list.lock &&
+ test_must_fail git update-ref refs/heads/branch HEAD 2>err &&
+ test_grep "cannot lock references" err
+ )
+'
+
+test_expect_success 'ref transaction: retry acquiring tables.list lock' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ LOCK=.git/reftable/tables.list.lock &&
+ >$LOCK &&
+ {
+ ( sleep 1 && rm -f $LOCK ) &
+ } &&
+ git -c reftable.lockTimeout=5000 update-ref refs/heads/branch HEAD
+ )
+'
+
+# This test fails most of the time on Cygwin systems. The root cause is
+# that Windows does not allow us to rename the "tables.list.lock" file into
+# place when "tables.list" is open for reading by a concurrent process. We have
+# worked around that in our MinGW-based rename emulation, but the Cygwin
+# emulation seems to be insufficient.
+test_expect_success !CYGWIN 'ref transaction: many concurrent writers' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ # Set a high timeout. While a couple of seconds should be
+ # plenty, using the address sanitizer will significantly slow
+ # us down here. So we are aiming way higher than you would ever
+ # think is necessary just to keep us from flaking. We could
+ # also lock indefinitely by passing -1, but that could
+ # potentially block CI jobs indefinitely if there was a bug
+ # here.
+ git config set reftable.lockTimeout 300000 &&
+ test_commit --no-tag initial &&
+
+ head=$(git rev-parse HEAD) &&
+ for i in $(test_seq 100)
+ do
+ printf "%s commit\trefs/heads/branch-%s\n" "$head" "$i" ||
+ return 1
+ done >expect &&
+ printf "%s commit\trefs/heads/main\n" "$head" >>expect &&
+
+ for i in $(test_seq 100)
+ do
+ { git update-ref refs/heads/branch-$i HEAD& } ||
+ return 1
+ done &&
+
+ wait &&
+ git for-each-ref --sort=v:refname >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'pack-refs: compacts tables' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+
+ test_commit -C repo A &&
+ ls -1 repo/.git/reftable >table-files &&
+ test_line_count = 3 table-files &&
+ test_line_count = 2 repo/.git/reftable/tables.list &&
+
+ git -C repo pack-refs &&
+ ls -1 repo/.git/reftable >table-files &&
+ test_line_count = 2 table-files &&
+ test_line_count = 1 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'pack-refs: compaction raises locking errors' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo A &&
+ touch repo/.git/reftable/tables.list.lock &&
+ cat >expect <<-EOF &&
+ error: unable to compact stack: data is locked
+ EOF
+ test_must_fail git -C repo pack-refs 2>err &&
+ test_cmp expect err
+'
+
+for command in pack-refs gc "maintenance run --task=pack-refs"
+do
+test_expect_success "$command: auto compaction" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+
+ # We need a bit of setup to ensure that git-gc(1) actually
+ # triggers, and that it does not write anything to the refdb.
+ git config gc.auto 1 &&
+ git config gc.autoDetach 0 &&
+ git config gc.reflogExpire never &&
+ git config gc.reflogExpireUnreachable never &&
+ test_oid blob17_1 | git hash-object -w --stdin &&
+
+ # The tables should have been auto-compacted, and thus auto
+ # compaction should not have to do anything.
+ ls -1 .git/reftable >tables-expect &&
+ test_line_count = 3 tables-expect &&
+ git $command --auto &&
+ ls -1 .git/reftable >tables-actual &&
+ test_cmp tables-expect tables-actual &&
+
+ test_oid blob17_2 | git hash-object -w --stdin &&
+
+ # Lock all tables, write some refs. Auto-compaction will be
+ # unable to compact tables and thus fails gracefully,
+ # compacting only those tables which are not locked.
+ ls .git/reftable/*.ref | sort |
+ while read table
+ do
+ touch "$table.lock" &&
+ basename "$table" >>tables.expect || exit 1
+ done &&
+ test_line_count = 2 .git/reftable/tables.list &&
+ git branch B &&
+ git branch C &&
+
+ # The new tables are auto-compacted, but the locked tables are
+ # left intact.
+ test_line_count = 3 .git/reftable/tables.list &&
+ head -n 2 .git/reftable/tables.list >tables.head &&
+ test_cmp tables.expect tables.head &&
+
+ rm .git/reftable/*.lock &&
+ git $command --auto &&
+ test_line_count = 1 .git/reftable/tables.list
+ )
+'
+done
+
+test_expect_success 'pack-refs: prunes stale tables' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ touch repo/.git/reftable/stale-table.ref &&
+ git -C repo pack-refs &&
+ test_path_is_missing repo/.git/reftable/stable-ref.ref
+'
+
+test_expect_success 'pack-refs: does not prune non-table files' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ touch repo/.git/reftable/garbage &&
+ git -C repo pack-refs &&
+ test_path_is_file repo/.git/reftable/garbage
+'
+
+test_expect_success 'packed-refs: writes are synced' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo initial &&
+ test_line_count = 2 table-files &&
+
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ GIT_TEST_FSYNC=true \
+ git -C repo -c core.fsync=reference \
+ -c core.fsyncMethod=fsync pack-refs &&
+ check_fsync_events trace2.txt <<-EOF
+ "name":"hardware-flush","count":2
+ EOF
+'
+
+test_expect_success 'ref iterator: bogus names are flagged' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit --no-tag file &&
+ test-tool ref-store main update-ref msg "refs/heads/bogus..name" $(git rev-parse HEAD) $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
+
+ cat >expect <<-EOF &&
+ $ZERO_OID refs/heads/bogus..name 0xc
+ $(git rev-parse HEAD) refs/heads/main 0x0
+ EOF
+ test-tool ref-store main for-each-ref "" >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'ref iterator: missing object IDs are not flagged' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test-tool ref-store main update-ref msg "refs/heads/broken-hash" $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION &&
+
+ cat >expect <<-EOF &&
+ $INVALID_OID refs/heads/broken-hash 0x0
+ EOF
+ test-tool ref-store main for-each-ref "" >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'basic: commit and list refs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo file &&
+ test_write_lines refs/heads/main refs/tags/file >expect &&
+ git -C repo for-each-ref --format="%(refname)" >actual &&
+ test_cmp actual expect
+'
+
+test_expect_success 'basic: can write large commit message' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ perl -e "
+ print \"this is a long commit message\" x 50000
+ " >commit-msg &&
+ git -C repo commit --allow-empty --file=../commit-msg
+'
+
+test_expect_success 'basic: show-ref fails with empty repository' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo show-ref >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'basic: can check out unborn branch' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ git -C repo checkout -b main
+'
+
+test_expect_success 'basic: peeled tags are stored' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo file &&
+ git -C repo tag -m "annotated tag" test_tag HEAD &&
+ for ref in refs/heads/main refs/tags/file refs/tags/test_tag refs/tags/test_tag^{}
+ do
+ echo "$(git -C repo rev-parse "$ref") $ref" || return 1
+ done >expect &&
+ git -C repo show-ref -d >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'basic: for-each-ref can print symrefs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file &&
+ git branch &&
+ git symbolic-ref refs/heads/sym refs/heads/main &&
+ cat >expected <<-EOF &&
+ refs/heads/main
+ EOF
+ git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'basic: notes' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ write_script fake_editor <<-\EOF &&
+ echo "$MSG" >"$1"
+ echo "$MSG" >&2
+ EOF
+
+ test_commit 1st &&
+ test_commit 2nd &&
+ GIT_EDITOR=./fake_editor MSG=b4 git notes add &&
+ GIT_EDITOR=./fake_editor MSG=b3 git notes edit &&
+ echo b4 >expect &&
+ git notes --ref commits@{1} show >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'basic: stash' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file &&
+ git stash list >expect &&
+ test_line_count = 0 expect &&
+
+ echo hoi >>file.t &&
+ git stash push -m stashed &&
+ git stash list >expect &&
+ test_line_count = 1 expect &&
+
+ git stash clear &&
+ git stash list >expect &&
+ test_line_count = 0 expect
+ )
+'
+
+test_expect_success 'basic: cherry-pick' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit message1 file1 &&
+ test_commit message2 file2 &&
+ git branch source &&
+ git checkout HEAD^ &&
+ test_commit message3 file3 &&
+ git cherry-pick source &&
+ test_path_is_file file2
+ )
+'
+
+test_expect_success 'basic: rebase' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit message1 file1 &&
+ test_commit message2 file2 &&
+ git branch source &&
+ git checkout HEAD^ &&
+ test_commit message3 file3 &&
+ git rebase source &&
+ test_path_is_file file2
+ )
+'
+
+test_expect_success 'reflog: can delete separate reflog entries' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit file &&
+ test_commit file2 &&
+ test_commit file3 &&
+ test_commit file4 &&
+ git reflog >actual &&
+ grep file3 actual &&
+
+ git reflog delete HEAD@{1} &&
+ git reflog >actual &&
+ ! grep file3 actual
+ )
+'
+
+test_expect_success 'reflog: can switch to previous branch' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file1 &&
+ git checkout -b branch1 &&
+ test_commit file2 &&
+ git checkout -b branch2 &&
+ git switch - &&
+ git rev-parse --symbolic-full-name HEAD >actual &&
+ echo refs/heads/branch1 >expect &&
+ test_cmp actual expect
+ )
+'
+
+test_expect_success 'reflog: copying branch writes reflog entry' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit file1 &&
+ test_commit file2 &&
+ oid=$(git rev-parse --short HEAD) &&
+ git branch src &&
+ cat >expect <<-EOF &&
+ ${oid} dst@{0}: Branch: copied refs/heads/src to refs/heads/dst
+ ${oid} dst@{1}: branch: Created from main
+ EOF
+ git branch -c src dst &&
+ git reflog dst >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'reflog: renaming branch writes reflog entry' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git symbolic-ref HEAD refs/heads/before &&
+ test_commit file &&
+ git show-ref >expected.refs &&
+ sed s/before/after/g <expected.refs >expected &&
+ git branch -M after &&
+ git show-ref >actual &&
+ test_cmp expected actual &&
+ echo refs/heads/after >expected &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'reflog: can store empty logs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_must_fail test-tool ref-store main reflog-exists refs/heads/branch &&
+ test-tool ref-store main create-reflog refs/heads/branch &&
+ test-tool ref-store main reflog-exists refs/heads/branch &&
+ test-tool ref-store main for-each-reflog-ent-reverse refs/heads/branch >actual &&
+ test_must_be_empty actual
+ )
+'
+
+test_expect_success 'reflog: expiry empties reflog' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit initial &&
+ git checkout -b branch &&
+ test_commit fileA &&
+ test_commit fileB &&
+
+ cat >expect <<-EOF &&
+ commit: fileB
+ commit: fileA
+ branch: Created from HEAD
+ EOF
+ git reflog show --format="%gs" refs/heads/branch >actual &&
+ test_cmp expect actual &&
+
+ git reflog expire branch --expire=all &&
+ git reflog show --format="%gs" refs/heads/branch >actual &&
+ test_must_be_empty actual &&
+ test-tool ref-store main reflog-exists refs/heads/branch
+ )
+'
+
+test_expect_success 'reflog: can be deleted' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ test-tool ref-store main reflog-exists refs/heads/main &&
+ test-tool ref-store main delete-reflog refs/heads/main &&
+ test_must_fail test-tool ref-store main reflog-exists refs/heads/main
+ )
+'
+
+test_expect_success 'reflog: garbage collection deletes reflog entries' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ for count in $(test_seq 1 10)
+ do
+ test_commit "number $count" file.t $count number-$count ||
+ return 1
+ done &&
+ git reflog refs/heads/main >actual &&
+ test_line_count = 10 actual &&
+ grep "commit (initial): number 1" actual &&
+ grep "commit: number 10" actual &&
+
+ git gc &&
+ git reflog refs/heads/main >actual &&
+ test_line_count = 0 actual
+ )
+'
+
+test_expect_success 'reflog: updates via HEAD update HEAD reflog' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit main-one &&
+ git checkout -b new-branch &&
+ test_commit new-one &&
+ test_commit new-two &&
+
+ echo new-one >expect &&
+ git log -1 --format=%s HEAD@{1} >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'branch: copying branch with D/F conflict' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ git branch branch &&
+ cat >expect <<-EOF &&
+ error: ${SQ}refs/heads/branch${SQ} exists; cannot create ${SQ}refs/heads/branch/moved${SQ}
+ fatal: branch copy failed
+ EOF
+ test_must_fail git branch -c branch branch/moved 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'branch: moving branch with D/F conflict' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ git branch branch &&
+ git branch conflict &&
+ cat >expect <<-EOF &&
+ error: ${SQ}refs/heads/conflict${SQ} exists; cannot create ${SQ}refs/heads/conflict/moved${SQ}
+ fatal: branch rename failed
+ EOF
+ test_must_fail git branch -m branch conflict/moved 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'worktree: adding worktree creates separate stack' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo worktree add ../worktree &&
+ test_path_is_file repo/.git/worktrees/worktree/refs/heads &&
+ echo "ref: refs/heads/.invalid" >expect &&
+ test_cmp expect repo/.git/worktrees/worktree/HEAD &&
+ test_path_is_dir repo/.git/worktrees/worktree/reftable &&
+ test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list
+'
+
+test_expect_success 'worktree: pack-refs in main repo packs main refs' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
+ git -C repo worktree add ../worktree &&
+ GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
+ git -C worktree update-ref refs/worktree/per-worktree HEAD &&
+
+ test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 3 repo/.git/reftable/tables.list &&
+ git -C repo pack-refs &&
+ test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: pack-refs in worktree packs worktree refs' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
+ git -C repo worktree add ../worktree &&
+ GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
+ git -C worktree update-ref refs/worktree/per-worktree HEAD &&
+
+ test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 3 repo/.git/reftable/tables.list &&
+ git -C worktree pack-refs &&
+ test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 3 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: creating shared ref updates main stack' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo worktree add ../worktree &&
+ git -C repo pack-refs &&
+ git -C worktree pack-refs &&
+ test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
+ git -C worktree update-ref refs/heads/shared HEAD &&
+ test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 2 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: creating per-worktree ref updates worktree stack' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo worktree add ../worktree &&
+ git -C repo pack-refs &&
+ git -C worktree pack-refs &&
+ test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ git -C worktree update-ref refs/bisect/per-worktree HEAD &&
+ test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: creating per-worktree ref from main repo' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo worktree add ../worktree &&
+ git -C repo pack-refs &&
+ git -C worktree pack-refs &&
+ test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD &&
+ test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: creating per-worktree ref from second worktree' '
+ test_when_finished "rm -rf repo wt1 wt2" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo worktree add ../wt1 &&
+ git -C repo worktree add ../wt2 &&
+ git -C repo pack-refs &&
+ git -C wt1 pack-refs &&
+ git -C wt2 pack-refs &&
+ test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&
+ test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD &&
+ test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&
+ test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: can create shared and per-worktree ref in one transaction' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo A &&
+
+ git -C repo worktree add ../worktree &&
+ git -C repo pack-refs &&
+ git -C worktree pack-refs &&
+ test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 1 repo/.git/reftable/tables.list &&
+
+ cat >stdin <<-EOF &&
+ create worktrees/worktree/refs/bisect/per-worktree HEAD
+ create refs/branches/shared HEAD
+ EOF
+ git -C repo update-ref --stdin <stdin &&
+ test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
+ test_line_count = 2 repo/.git/reftable/tables.list
+'
+
+test_expect_success 'worktree: can access common refs' '
+ test_when_finished "rm -rf repo worktree" &&
+ git init repo &&
+ test_commit -C repo file1 &&
+ git -C repo branch branch1 &&
+ git -C repo worktree add ../worktree &&
+
+ echo refs/heads/worktree >expect &&
+ git -C worktree symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
+ git -C worktree checkout branch1
+'
+
+test_expect_success 'worktree: adds worktree with detached HEAD' '
+ test_when_finished "rm -rf repo worktree" &&
+
+ git init repo &&
+ test_commit -C repo A &&
+ git -C repo rev-parse main >expect &&
+
+ git -C repo worktree add --detach ../worktree main &&
+ git -C worktree rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch: accessing FETCH_HEAD special ref works' '
+ test_when_finished "rm -rf repo sub" &&
+
+ git init sub &&
+ test_commit -C sub two &&
+ git -C sub rev-parse HEAD >expect &&
+
+ git init repo &&
+ test_commit -C repo one &&
+ git -C repo fetch ../sub &&
+ git -C repo rev-parse FETCH_HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t0611-reftable-httpd.sh b/t/t0611-reftable-httpd.sh
new file mode 100755
index 0000000000..5e05b9c1f2
--- /dev/null
+++ b/t/t0611-reftable-httpd.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+test_description='reftable HTTPD tests'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+
+start_httpd
+
+REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
+
+test_expect_success 'serving ls-remote' '
+ git init --ref-format=reftable -b main "$REPO" &&
+ cd "$REPO" &&
+ test_commit m1 &&
+ >.git/git-daemon-export-ok &&
+ git ls-remote "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" | cut -f 2-2 -d " " >actual &&
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/main
+ refs/tags/m1
+ EOF
+ test_cmp actual expect
+'
+
+test_done
diff --git a/t/t0612-reftable-jgit-compatibility.sh b/t/t0612-reftable-jgit-compatibility.sh
new file mode 100755
index 0000000000..d0d7e80b49
--- /dev/null
+++ b/t/t0612-reftable-jgit-compatibility.sh
@@ -0,0 +1,132 @@
+#!/bin/sh
+
+test_description='reftables are compatible with JGit'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=reftable
+export GIT_TEST_DEFAULT_REF_FORMAT
+
+# JGit does not support the 'link' DIRC extension.
+GIT_TEST_SPLIT_INDEX=0
+export GIT_TEST_SPLIT_INDEX
+
+. ./test-lib.sh
+
+if ! test_have_prereq JGIT
+then
+ skip_all='skipping reftable JGit tests; JGit is not present in PATH'
+ test_done
+fi
+
+if ! test_have_prereq SHA1
+then
+ skip_all='skipping reftable JGit tests; JGit does not support SHA256 reftables'
+ test_done
+fi
+
+test_commit_jgit () {
+ touch "$1" &&
+ jgit add "$1" &&
+ jgit commit -m "$1"
+}
+
+test_same_refs () {
+ git show-ref --head >cgit.actual &&
+ jgit show-ref >jgit-tabs.actual &&
+ tr "\t" " " <jgit-tabs.actual >jgit.actual &&
+ test_cmp cgit.actual jgit.actual
+}
+
+test_same_ref () {
+ git rev-parse "$1" >cgit.actual &&
+ jgit rev-parse "$1" >jgit.actual &&
+ test_cmp cgit.actual jgit.actual
+}
+
+test_same_reflog () {
+ git reflog "$*" >cgit.actual &&
+ jgit reflog "$*" >jgit-newline.actual &&
+ sed '/^$/d' <jgit-newline.actual >jgit.actual &&
+ test_cmp cgit.actual jgit.actual
+}
+
+test_expect_success 'CGit repository can be read by JGit' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ test_same_refs &&
+ test_same_ref HEAD &&
+ test_same_reflog HEAD
+ )
+'
+
+test_expect_success 'JGit repository can be read by CGit' '
+ test_when_finished "rm -rf repo" &&
+ jgit init repo &&
+ (
+ cd repo &&
+
+ touch file &&
+ jgit add file &&
+ jgit commit -m "initial commit" &&
+
+ # Note that we must convert the ref storage after we have
+ # written the default branch. Otherwise JGit will end up with
+ # no HEAD at all.
+ jgit convert-ref-storage --format=reftable &&
+
+ test_same_refs &&
+ test_same_ref HEAD &&
+ # Interestingly, JGit cannot read its own reflog here. CGit can
+ # though.
+ printf "%s HEAD@{0}: commit (initial): initial commit" "$(git rev-parse --short HEAD)" >expect &&
+ git reflog HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'mixed writes from JGit and CGit' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ test_commit_jgit B &&
+ test_commit C &&
+ test_commit_jgit D &&
+
+ test_same_refs &&
+ test_same_ref HEAD &&
+ test_same_reflog HEAD
+ )
+'
+
+test_expect_success 'JGit can read multi-level index' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ awk "
+ BEGIN {
+ print \"start\";
+ for (i = 0; i < 10000; i++)
+ printf \"create refs/heads/branch-%d HEAD\n\", i;
+ print \"commit\";
+ }
+ " >input &&
+ git update-ref --stdin <input &&
+
+ test_same_refs &&
+ test_same_ref refs/heads/branch-1 &&
+ test_same_ref refs/heads/branch-5738 &&
+ test_same_ref refs/heads/branch-9999
+ )
+'
+
+test_done
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
new file mode 100755
index 0000000000..e2708e11d5
--- /dev/null
+++ b/t/t0613-reftable-write-options.sh
@@ -0,0 +1,286 @@
+#!/bin/sh
+
+test_description='reftable write options'
+
+GIT_TEST_DEFAULT_REF_FORMAT=reftable
+export GIT_TEST_DEFAULT_REF_FORMAT
+# Disable auto-compaction for all tests as we explicitly control repacking of
+# refs.
+GIT_TEST_REFTABLE_AUTOCOMPACTION=false
+export GIT_TEST_REFTABLE_AUTOCOMPACTION
+# Block sizes depend on the hash function, so we force SHA1 here.
+GIT_TEST_DEFAULT_HASH=sha1
+export GIT_TEST_DEFAULT_HASH
+# Block sizes also depend on the actual refs we write, so we force "master" to
+# be the default initial branch name.
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'default write options' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git pack-refs &&
+ cat >expect <<-EOF &&
+ header:
+ block_size: 4096
+ ref:
+ - length: 129
+ restarts: 2
+ log:
+ - length: 262
+ restarts: 2
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'disabled reflog writes no log blocks' '
+ test_config_global core.logAllRefUpdates false &&
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git pack-refs &&
+ cat >expect <<-EOF &&
+ header:
+ block_size: 4096
+ ref:
+ - length: 129
+ restarts: 2
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'many refs results in multiple blocks' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ for i in $(test_seq 200)
+ do
+ printf "update refs/heads/branch-%d HEAD\n" "$i" ||
+ return 1
+ done >input &&
+ git update-ref --stdin <input &&
+ git pack-refs &&
+
+ cat >expect <<-EOF &&
+ header:
+ block_size: 4096
+ ref:
+ - length: 4049
+ restarts: 11
+ - length: 1136
+ restarts: 3
+ log:
+ - length: 4041
+ restarts: 4
+ - length: 4015
+ restarts: 3
+ - length: 4014
+ restarts: 3
+ - length: 4012
+ restarts: 3
+ - length: 3289
+ restarts: 3
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'tiny block size leads to error' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ cat >expect <<-EOF &&
+ error: unable to compact stack: entry too large
+ EOF
+ test_must_fail git -c reftable.blockSize=50 pack-refs 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'small block size leads to multiple ref blocks' '
+ test_config_global core.logAllRefUpdates false &&
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ test_commit B &&
+ git -c reftable.blockSize=100 pack-refs &&
+
+ cat >expect <<-EOF &&
+ header:
+ block_size: 100
+ ref:
+ - length: 53
+ restarts: 1
+ - length: 74
+ restarts: 1
+ - length: 38
+ restarts: 1
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'small block size fails with large reflog message' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ perl -e "print \"a\" x 500" >logmsg &&
+ cat >expect <<-EOF &&
+ fatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large
+ EOF
+ test_must_fail git -c reftable.blockSize=100 \
+ update-ref -m "$(cat logmsg)" refs/heads/logme HEAD 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'block size exceeding maximum supported size' '
+ test_config_global core.logAllRefUpdates false &&
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ test_commit B &&
+ cat >expect <<-EOF &&
+ fatal: reftable block size cannot exceed 16MB
+ EOF
+ test_must_fail git -c reftable.blockSize=16777216 pack-refs 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'restart interval at every single record' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ for i in $(test_seq 10)
+ do
+ printf "update refs/heads/branch-%d HEAD\n" "$i" ||
+ return 1
+ done >input &&
+ git update-ref --stdin <input &&
+ git -c reftable.restartInterval=1 pack-refs &&
+
+ cat >expect <<-EOF &&
+ header:
+ block_size: 4096
+ ref:
+ - length: 566
+ restarts: 13
+ log:
+ - length: 1393
+ restarts: 12
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'restart interval exceeding maximum supported interval' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ cat >expect <<-EOF &&
+ fatal: reftable block size cannot exceed 65535
+ EOF
+ test_must_fail git -c reftable.restartInterval=65536 pack-refs 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'object index gets written by default with ref index' '
+ test_config_global core.logAllRefUpdates false &&
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ for i in $(test_seq 5)
+ do
+ printf "update refs/heads/branch-%d HEAD\n" "$i" ||
+ return 1
+ done >input &&
+ git update-ref --stdin <input &&
+ git -c reftable.blockSize=100 pack-refs &&
+
+ cat >expect <<-EOF &&
+ header:
+ block_size: 100
+ ref:
+ - length: 53
+ restarts: 1
+ - length: 95
+ restarts: 1
+ - length: 71
+ restarts: 1
+ - length: 80
+ restarts: 1
+ obj:
+ - length: 11
+ restarts: 1
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'object index can be disabled' '
+ test_config_global core.logAllRefUpdates false &&
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ for i in $(test_seq 5)
+ do
+ printf "update refs/heads/branch-%d HEAD\n" "$i" ||
+ return 1
+ done >input &&
+ git update-ref --stdin <input &&
+ git -c reftable.blockSize=100 -c reftable.indexObjects=false pack-refs &&
+
+ cat >expect <<-EOF &&
+ header:
+ block_size: 100
+ ref:
+ - length: 53
+ restarts: 1
+ - length: 95
+ restarts: 1
+ - length: 71
+ restarts: 1
+ - length: 80
+ restarts: 1
+ EOF
+ test-tool dump-reftable -b .git/reftable/*.ref >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_done
diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh
index 0e8c0dfbbe..b9dd21cfb6 100755
--- a/t/t1000-read-tree-m-3way.sh
+++ b/t/t1000-read-tree-m-3way.sh
@@ -72,7 +72,6 @@ In addition:
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
. "$TEST_DIRECTORY"/lib-read-tree-m-3way.sh
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 88c524f655..4a88bb9ef0 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -21,7 +21,6 @@ In the test, these paths are used:
yomin - not in H or M
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
@@ -397,7 +396,7 @@ test_expect_success 'a/b vs a, plus c/d case setup.' '
test_expect_success 'a/b vs a, plus c/d case test.' '
read_tree_u_must_succeed -u -m "$treeH" "$treeM" &&
- git ls-files --stage | tee >treeMcheck.out &&
+ git ls-files --stage >treeMcheck.out &&
test_cmp treeM.out treeMcheck.out
'
diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index a7c2ed0d7c..df6ef53725 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -9,7 +9,6 @@ This is identical to t1001, but uses -u to update the work tree as well.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh
index c860c08ecb..66e2bf4aec 100755
--- a/t/t1003-read-tree-prefix.sh
+++ b/t/t1003-read-tree-prefix.sh
@@ -6,7 +6,6 @@
test_description='git read-tree --prefix test.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index 26be4a2b5a..6b5033d0ce 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -2,7 +2,6 @@
test_description='read-tree -u --reset'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index d73a0be1b9..ff9bf213aa 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -6,7 +6,7 @@ test_description='git cat-file'
test_cmdmode_usage () {
test_expect_code 129 "$@" 2>err &&
- grep "^error:.*is incompatible with" err
+ grep "^error: .* cannot be used together" err
}
for switches in \
@@ -112,65 +112,65 @@ strlen () {
run_tests () {
type=$1
- sha1=$2
+ oid=$2
size=$3
content=$4
pretty_content=$5
- batch_output="$sha1 $type $size
+ batch_output="$oid $type $size
$content"
test_expect_success "$type exists" '
- git cat-file -e $sha1
+ git cat-file -e $oid
'
test_expect_success "Type of $type is correct" '
echo $type >expect &&
- git cat-file -t $sha1 >actual &&
+ git cat-file -t $oid >actual &&
test_cmp expect actual
'
test_expect_success "Size of $type is correct" '
echo $size >expect &&
- git cat-file -s $sha1 >actual &&
+ git cat-file -s $oid >actual &&
test_cmp expect actual
'
test_expect_success "Type of $type is correct using --allow-unknown-type" '
echo $type >expect &&
- git cat-file -t --allow-unknown-type $sha1 >actual &&
+ git cat-file -t --allow-unknown-type $oid >actual &&
test_cmp expect actual
'
test_expect_success "Size of $type is correct using --allow-unknown-type" '
echo $size >expect &&
- git cat-file -s --allow-unknown-type $sha1 >actual &&
+ git cat-file -s --allow-unknown-type $oid >actual &&
test_cmp expect actual
'
test -z "$content" ||
test_expect_success "Content of $type is correct" '
echo_without_newline "$content" >expect &&
- git cat-file $type $sha1 >actual &&
+ git cat-file $type $oid >actual &&
test_cmp expect actual
'
test_expect_success "Pretty content of $type is correct" '
echo_without_newline "$pretty_content" >expect &&
- git cat-file -p $sha1 >actual &&
+ git cat-file -p $oid >actual &&
test_cmp expect actual
'
test -z "$content" ||
test_expect_success "--batch output of $type is correct" '
echo "$batch_output" >expect &&
- echo $sha1 | git cat-file --batch >actual &&
+ echo $oid | git cat-file --batch >actual &&
test_cmp expect actual
'
test_expect_success "--batch-check output of $type is correct" '
- echo "$sha1 $type $size" >expect &&
- echo_without_newline $sha1 | git cat-file --batch-check >actual &&
+ echo "$oid $type $size" >expect &&
+ echo_without_newline $oid | git cat-file --batch-check >actual &&
test_cmp expect actual
'
@@ -179,33 +179,33 @@ $content"
test -z "$content" ||
test_expect_success "--batch-command $opt output of $type content is correct" '
echo "$batch_output" >expect &&
- test_write_lines "contents $sha1" | git cat-file --batch-command $opt >actual &&
+ test_write_lines "contents $oid" | git cat-file --batch-command $opt >actual &&
test_cmp expect actual
'
test_expect_success "--batch-command $opt output of $type info is correct" '
- echo "$sha1 $type $size" >expect &&
- test_write_lines "info $sha1" |
+ echo "$oid $type $size" >expect &&
+ test_write_lines "info $oid" |
git cat-file --batch-command $opt >actual &&
test_cmp expect actual
'
done
test_expect_success "custom --batch-check format" '
- echo "$type $sha1" >expect &&
- echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
+ echo "$type $oid" >expect &&
+ echo $oid | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
test_cmp expect actual
'
test_expect_success "custom --batch-command format" '
- echo "$type $sha1" >expect &&
- echo "info $sha1" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
+ echo "$type $oid" >expect &&
+ echo "info $oid" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
test_cmp expect actual
'
test_expect_success '--batch-check with %(rest)' '
echo "$type this is some extra content" >expect &&
- echo "$sha1 this is some extra content" |
+ echo "$oid this is some extra content" |
git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
test_cmp expect actual
'
@@ -216,7 +216,7 @@ $content"
echo "$size" &&
echo "$content"
} >expect &&
- echo $sha1 | git cat-file --batch="%(objectsize)" >actual &&
+ echo $oid | git cat-file --batch="%(objectsize)" >actual &&
test_cmp expect actual
'
@@ -226,114 +226,154 @@ $content"
echo "$type" &&
echo "$content"
} >expect &&
- echo $sha1 | git cat-file --batch="%(objecttype)" >actual &&
+ echo $oid | git cat-file --batch="%(objecttype)" >actual &&
test_cmp expect actual
'
}
hello_content="Hello World"
hello_size=$(strlen "$hello_content")
-hello_sha1=$(echo_without_newline "$hello_content" | git hash-object --stdin)
+hello_oid=$(echo_without_newline "$hello_content" | git hash-object --stdin)
test_expect_success "setup" '
+ git config core.repositoryformatversion 1 &&
+ git config extensions.objectformat $test_hash_algo &&
+ git config extensions.compatobjectformat $test_compat_hash_algo &&
echo_without_newline "$hello_content" > hello &&
git update-index --add hello
'
-run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
+run_blob_tests () {
+ oid=$1
-test_expect_success '--batch-command --buffer with flush for blob info' '
- echo "$hello_sha1 blob $hello_size" >expect &&
- test_write_lines "info $hello_sha1" "flush" |
+ run_tests 'blob' $oid $hello_size "$hello_content" "$hello_content"
+
+ test_expect_success '--batch-command --buffer with flush for blob info' '
+ echo "$oid blob $hello_size" >expect &&
+ test_write_lines "info $oid" "flush" |
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
git cat-file --batch-command --buffer >actual &&
test_cmp expect actual
-'
+ '
-test_expect_success '--batch-command --buffer without flush for blob info' '
+ test_expect_success '--batch-command --buffer without flush for blob info' '
touch output &&
- test_write_lines "info $hello_sha1" |
+ test_write_lines "info $oid" |
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
git cat-file --batch-command --buffer >>output &&
test_must_be_empty output
-'
+ '
+}
+
+hello_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $hello_oid)
+run_blob_tests $hello_oid
+run_blob_tests $hello_compat_oid
test_expect_success '--batch-check without %(rest) considers whole line' '
- echo "$hello_sha1 blob $hello_size" >expect &&
- git update-index --add --cacheinfo 100644 $hello_sha1 "white space" &&
+ echo "$hello_oid blob $hello_size" >expect &&
+ git update-index --add --cacheinfo 100644 $hello_oid "white space" &&
test_when_finished "git update-index --remove \"white space\"" &&
echo ":white space" | git cat-file --batch-check >actual &&
test_cmp expect actual
'
-tree_sha1=$(git write-tree)
+tree_oid=$(git write-tree)
+tree_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tree_oid)
tree_size=$(($(test_oid rawsz) + 13))
-tree_pretty_content="100644 blob $hello_sha1 hello${LF}"
+tree_compat_size=$(($(test_oid --hash=compat rawsz) + 13))
+tree_pretty_content="100644 blob $hello_oid hello${LF}"
+tree_compat_pretty_content="100644 blob $hello_compat_oid hello${LF}"
-run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
+run_tests 'tree' $tree_oid $tree_size "" "$tree_pretty_content"
+run_tests 'tree' $tree_compat_oid $tree_compat_size "" "$tree_compat_pretty_content"
commit_message="Initial commit"
-commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
+commit_oid=$(echo_without_newline "$commit_message" | git commit-tree $tree_oid)
+commit_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $commit_oid)
commit_size=$(($(test_oid hexsz) + 137))
-commit_content="tree $tree_sha1
+commit_compat_size=$(($(test_oid --hash=compat hexsz) + 137))
+commit_content="tree $tree_oid
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"
+commit_compat_content="tree $tree_compat_oid
+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_oid $commit_size "$commit_content" "$commit_content"
+run_tests 'commit' $commit_compat_oid $commit_compat_size "$commit_compat_content" "$commit_compat_content"
-tag_header_without_timestamp="object $hello_sha1
-type blob
+tag_header_without_oid="type blob
tag hellotag
tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+tag_header_without_timestamp="object $hello_oid
+$tag_header_without_oid"
+tag_compat_header_without_timestamp="object $hello_compat_oid
+$tag_header_without_oid"
tag_description="This is a tag"
tag_content="$tag_header_without_timestamp 0 +0000
$tag_description"
+tag_compat_content="$tag_compat_header_without_timestamp 0 +0000
-tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
+$tag_description"
+
+tag_oid=$(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"
+tag_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tag_oid)
+tag_compat_size=$(strlen "$tag_compat_content")
+
+run_tests 'tag' $tag_oid $tag_size "$tag_content" "$tag_content"
+run_tests 'tag' $tag_compat_oid $tag_compat_size "$tag_compat_content" "$tag_compat_content"
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 &&
+ git cat-file blob $tag_oid >actual &&
test_cmp expect actual
'
-for batch in batch batch-check batch-command
+for oid in $hello_oid $hello_compat_oid
do
- for opt in t s e p
+ for batch in batch batch-check batch-command
do
+ for opt in t s e p
+ do
test_expect_success "Passing -$opt with --$batch fails" '
- test_must_fail git cat-file --$batch -$opt $hello_sha1
+ test_must_fail git cat-file --$batch -$opt $oid
'
test_expect_success "Passing --$batch with -$opt fails" '
- test_must_fail git cat-file -$opt --$batch $hello_sha1
+ test_must_fail git cat-file -$opt --$batch $oid
'
- done
+ done
- test_expect_success "Passing <type> with --$batch fails" '
- test_must_fail git cat-file --$batch blob $hello_sha1
- '
+ test_expect_success "Passing <type> with --$batch fails" '
+ test_must_fail git cat-file --$batch blob $oid
+ '
- test_expect_success "Passing --$batch with <type> fails" '
- test_must_fail git cat-file blob --$batch $hello_sha1
- '
+ test_expect_success "Passing --$batch with <type> fails" '
+ test_must_fail git cat-file blob --$batch $oid
+ '
- test_expect_success "Passing sha1 with --$batch fails" '
- test_must_fail git cat-file --$batch $hello_sha1
- '
+ test_expect_success "Passing oid with --$batch fails" '
+ test_must_fail git cat-file --$batch $oid
+ '
+ done
done
-for opt in t s e p
+for oid in $hello_oid $hello_compat_oid
do
- test_expect_success "Passing -$opt with --follow-symlinks fails" '
- test_must_fail git cat-file --follow-symlinks -$opt $hello_sha1
+ for opt in t s e p
+ do
+ test_expect_success "Passing -$opt with --follow-symlinks fails" '
+ test_must_fail git cat-file --follow-symlinks -$opt $oid
'
+ done
done
test_expect_success "--batch-check for a non-existent named object" '
@@ -360,12 +400,12 @@ test_expect_success "--batch-check for a non-existent hash" '
test_expect_success "--batch for an existent and a non-existent hash" '
cat >expect <<-EOF &&
- $tag_sha1 tag $tag_size
+ $tag_oid tag $tag_size
$tag_content
0000000000000000000000000000000000000000 missing
EOF
- printf "$tag_sha1\n0000000000000000000000000000000000000000" >in &&
+ printf "$tag_oid\n0000000000000000000000000000000000000000" >in &&
git cat-file --batch <in >actual &&
test_cmp expect actual
'
@@ -386,112 +426,102 @@ test_expect_success 'empty --batch-check notices missing object' '
test_cmp expect actual
'
-batch_input="$hello_sha1
-$commit_sha1
-$tag_sha1
+batch_tests () {
+ boid=$1
+ loid=$2
+ lsize=$3
+ coid=$4
+ csize=$5
+ ccontent=$6
+ toid=$7
+ tsize=$8
+ tcontent=$9
+
+ batch_input="$boid
+$coid
+$toid
deadbeef
"
-printf "%s\0" \
- "$hello_sha1 blob $hello_size" \
+ printf "%s\0" \
+ "$boid blob $hello_size" \
"$hello_content" \
- "$commit_sha1 commit $commit_size" \
- "$commit_content" \
- "$tag_sha1 tag $tag_size" \
- "$tag_content" \
+ "$coid commit $csize" \
+ "$ccontent" \
+ "$toid tag $tsize" \
+ "$tcontent" \
"deadbeef missing" \
" missing" >batch_output
-test_expect_success '--batch with multiple sha1s gives correct format' '
+ test_expect_success '--batch with multiple oids gives correct format' '
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' '
+ test_expect_success '--batch, -z with multiple oids gives correct format' '
echo_without_newline_nul "$batch_input" >in &&
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' '
+ test_expect_success '--batch, -Z with multiple oids 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
-$tree_sha1
-$commit_sha1
-$tag_sha1
+batch_check_input="$boid
+$loid
+$coid
+$toid
deadbeef
"
-printf "%s\0" \
- "$hello_sha1 blob $hello_size" \
- "$tree_sha1 tree $tree_size" \
- "$commit_sha1 commit $commit_size" \
- "$tag_sha1 tag $tag_size" \
+ printf "%s\0" \
+ "$boid blob $hello_size" \
+ "$loid tree $lsize" \
+ "$coid commit $csize" \
+ "$toid tag $tsize" \
"deadbeef missing" \
" missing" >batch_check_output
-test_expect_success "--batch-check with multiple sha1s gives correct format" '
+ test_expect_success "--batch-check with multiple oids gives correct format" '
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" '
+ test_expect_success "--batch-check, -z with multiple oids gives correct format" '
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 "--batch-check, -Z with multiple sha1s gives correct format" '
+ test_expect_success "--batch-check, -Z with multiple oids 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
-'
-
-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
-info $tag_sha1
+batch_command_multiple_info="info $boid
+info $loid
+info $coid
+info $toid
info deadbeef"
-test_expect_success '--batch-command with multiple info calls gives correct format' '
+ test_expect_success '--batch-command with multiple info calls gives correct format' '
cat >expect <<-EOF &&
- $hello_sha1 blob $hello_size
- $tree_sha1 tree $tree_size
- $commit_sha1 commit $commit_size
- $tag_sha1 tag $tag_size
+ $boid blob $hello_size
+ $loid tree $lsize
+ $coid commit $csize
+ $toid tag $tsize
deadbeef missing
EOF
@@ -510,22 +540,22 @@ test_expect_success '--batch-command with multiple info calls gives correct form
git cat-file --batch-command --buffer -Z <in >actual &&
test_cmp expect_nul actual
-'
+ '
-batch_command_multiple_contents="contents $hello_sha1
-contents $commit_sha1
-contents $tag_sha1
+batch_command_multiple_contents="contents $boid
+contents $coid
+contents $toid
contents deadbeef
flush"
-test_expect_success '--batch-command with multiple command calls gives correct format' '
+ test_expect_success '--batch-command with multiple command calls gives correct format' '
printf "%s\0" \
- "$hello_sha1 blob $hello_size" \
+ "$boid blob $hello_size" \
"$hello_content" \
- "$commit_sha1 commit $commit_size" \
- "$commit_content" \
- "$tag_sha1 tag $tag_size" \
- "$tag_content" \
+ "$coid commit $csize" \
+ "$ccontent" \
+ "$toid tag $tsize" \
+ "$tcontent" \
"deadbeef missing" >expect_nul &&
tr "\0" "\n" <expect_nul >expect &&
@@ -543,6 +573,33 @@ test_expect_success '--batch-command with multiple command calls gives correct f
git cat-file --batch-command --buffer -Z <in >actual &&
test_cmp expect_nul actual
+ '
+
+}
+
+batch_tests $hello_oid $tree_oid $tree_size $commit_oid $commit_size "$commit_content" $tag_oid $tag_size "$tag_content"
+batch_tests $hello_compat_oid $tree_compat_oid $tree_compat_size $commit_compat_oid $commit_compat_size "$commit_compat_content" $tag_compat_oid $tag_compat_size "$tag_compat_content"
+
+
+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
+'
+
+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
'
test_expect_success 'setup blobs which are likely to delta' '
@@ -569,7 +626,7 @@ test_expect_success 'confirm that neither loose blob is a delta' '
# we will check only that one of the two objects is a delta
# against the other, but not the order. We can do so by just
# asking for the base of both, and checking whether either
-# sha1 appears in the output.
+# oid appears in the output.
test_expect_success '%(deltabase) reports packed delta bases' '
git repack -ad &&
git cat-file --batch-check="%(deltabase)" <blobs >actual &&
@@ -583,12 +640,12 @@ test_expect_success 'setup bogus data' '
bogus_short_type="bogus" &&
bogus_short_content="bogus" &&
bogus_short_size=$(strlen "$bogus_short_content") &&
- bogus_short_sha1=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) &&
+ bogus_short_oid=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) &&
bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" &&
bogus_long_content="bogus" &&
bogus_long_size=$(strlen "$bogus_long_content") &&
- bogus_long_sha1=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin)
+ bogus_long_oid=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin)
'
for arg1 in '' --allow-unknown-type
@@ -608,9 +665,9 @@ do
if test "$arg1" = "--allow-unknown-type"
then
- git cat-file $arg1 $arg2 $bogus_short_sha1
+ git cat-file $arg1 $arg2 $bogus_short_oid
else
- test_must_fail git cat-file $arg1 $arg2 $bogus_short_sha1 >out 2>actual &&
+ test_must_fail git cat-file $arg1 $arg2 $bogus_short_oid >out 2>actual &&
test_must_be_empty out &&
test_cmp expect actual
fi
@@ -620,21 +677,21 @@ do
if test "$arg2" = "-p"
then
cat >expect <<-EOF
- error: header for $bogus_long_sha1 too long, exceeds 32 bytes
- fatal: Not a valid object name $bogus_long_sha1
+ error: header for $bogus_long_oid too long, exceeds 32 bytes
+ fatal: Not a valid object name $bogus_long_oid
EOF
else
cat >expect <<-EOF
- error: header for $bogus_long_sha1 too long, exceeds 32 bytes
+ error: header for $bogus_long_oid too long, exceeds 32 bytes
fatal: git cat-file: could not get object info
EOF
fi &&
if test "$arg1" = "--allow-unknown-type"
then
- git cat-file $arg1 $arg2 $bogus_short_sha1
+ git cat-file $arg1 $arg2 $bogus_short_oid
else
- test_must_fail git cat-file $arg1 $arg2 $bogus_long_sha1 >out 2>actual &&
+ test_must_fail git cat-file $arg1 $arg2 $bogus_long_oid >out 2>actual &&
test_must_be_empty out &&
test_cmp expect actual
fi
@@ -668,28 +725,28 @@ do
done
test_expect_success '-e is OK with a broken object without --allow-unknown-type' '
- git cat-file -e $bogus_short_sha1
+ git cat-file -e $bogus_short_oid
'
test_expect_success '-e can not be combined with --allow-unknown-type' '
- test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_sha1
+ test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_oid
'
test_expect_success '-p cannot print a broken object even with --allow-unknown-type' '
- test_must_fail git cat-file -p $bogus_short_sha1 &&
- test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_sha1
+ test_must_fail git cat-file -p $bogus_short_oid &&
+ test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_oid
'
test_expect_success '<type> <hash> does not work with objects of broken types' '
cat >err.expect <<-\EOF &&
fatal: invalid object type "bogus"
EOF
- test_must_fail git cat-file $bogus_short_type $bogus_short_sha1 2>err.actual &&
+ test_must_fail git cat-file $bogus_short_type $bogus_short_oid 2>err.actual &&
test_cmp err.expect err.actual
'
test_expect_success 'broken types combined with --batch and --batch-check' '
- echo $bogus_short_sha1 >bogus-oid &&
+ echo $bogus_short_oid >bogus-oid &&
cat >err.expect <<-\EOF &&
fatal: invalid object type
@@ -711,52 +768,52 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme
cat >expect <<-EOF &&
$bogus_short_type
EOF
- git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
+ git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
test_cmp expect actual &&
# Create it manually, as "git replace" will die on bogus
# types.
head=$(git rev-parse --verify HEAD) &&
- test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1" &&
- test-tool ref-store main update-ref msg "refs/replace/$bogus_short_sha1" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&
+ test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_oid" &&
+ test-tool ref-store main update-ref msg "refs/replace/$bogus_short_oid" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&
cat >expect <<-EOF &&
commit
EOF
- git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
+ git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
test_cmp expect actual
'
test_expect_success "Type of broken object is correct" '
echo $bogus_short_type >expect &&
- git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
+ git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
test_cmp expect actual
'
test_expect_success "Size of broken object is correct" '
echo $bogus_short_size >expect &&
- git cat-file -s --allow-unknown-type $bogus_short_sha1 >actual &&
+ git cat-file -s --allow-unknown-type $bogus_short_oid >actual &&
test_cmp expect actual
'
test_expect_success 'clean up broken object' '
- rm .git/objects/$(test_oid_to_path $bogus_short_sha1)
+ rm .git/objects/$(test_oid_to_path $bogus_short_oid)
'
test_expect_success "Type of broken object is correct when type is large" '
echo $bogus_long_type >expect &&
- git cat-file -t --allow-unknown-type $bogus_long_sha1 >actual &&
+ git cat-file -t --allow-unknown-type $bogus_long_oid >actual &&
test_cmp expect actual
'
test_expect_success "Size of large broken object is correct when type is large" '
echo $bogus_long_size >expect &&
- git cat-file -s --allow-unknown-type $bogus_long_sha1 >actual &&
+ git cat-file -s --allow-unknown-type $bogus_long_oid >actual &&
test_cmp expect actual
'
test_expect_success 'clean up broken object' '
- rm .git/objects/$(test_oid_to_path $bogus_long_sha1)
+ rm .git/objects/$(test_oid_to_path $bogus_long_oid)
'
test_expect_success 'cat-file -t and -s on corrupt loose object' '
@@ -853,7 +910,7 @@ test_expect_success 'prep for symlink tests' '
test_ln_s_add loop2 loop1 &&
git add morx dir/subdir/ind2 dir/ind1 &&
git commit -am "test" &&
- echo $hello_sha1 blob $hello_size >found
+ echo $hello_oid blob $hello_size >found
'
test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' '
@@ -941,7 +998,7 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/
echo HEAD:dirlink/morx >>expect &&
echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
- echo $hello_sha1 blob $hello_size >expect &&
+ echo $hello_oid blob $hello_size >expect &&
echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual
'
@@ -1100,6 +1157,42 @@ test_expect_success 'cat-file --batch="batman" with --batch-all-objects will wor
cmp expect actual
'
+test_expect_success 'cat-file %(objectsize:disk) with --batch-all-objects' '
+ # our state has both loose and packed objects,
+ # so find both for our expected output
+ {
+ find .git/objects/?? -type f |
+ awk -F/ "{ print \$0, \$3\$4 }" |
+ while read path oid
+ do
+ size=$(test_file_size "$path") &&
+ echo "$oid $size" ||
+ return 1
+ done &&
+ rawsz=$(test_oid rawsz) &&
+ find .git/objects/pack -name "*.idx" |
+ while read idx
+ do
+ git show-index <"$idx" >idx.raw &&
+ sort -nr <idx.raw >idx.sorted &&
+ packsz=$(test_file_size "${idx%.idx}.pack") &&
+ end=$((packsz - rawsz)) &&
+ while read start oid rest
+ do
+ size=$((end - start)) &&
+ end=$start &&
+ echo "$oid $size" ||
+ return 1
+ done <idx.sorted ||
+ return 1
+ done
+ } >expect.raw &&
+ sort <expect.raw >expect &&
+ git cat-file --batch-all-objects \
+ --batch-check="%(objectname) %(objectsize:disk)" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'set up replacement object' '
orig=$(git rev-parse HEAD) &&
git cat-file commit $orig >orig &&
@@ -1201,4 +1294,34 @@ test_expect_success 'batch-command flush without --buffer' '
grep "^fatal:.*flush is only for --buffer mode.*" err
'
+script='
+use warnings;
+use strict;
+use IPC::Open2;
+my ($opt, $oid, $expect, @pfx) = @ARGV;
+my @cmd = (qw(git cat-file), $opt);
+my $pid = open2(my $out, my $in, @cmd) or die "open2: @cmd";
+print $in @pfx, $oid, "\n" or die "print $!";
+my $rvec = "";
+vec($rvec, fileno($out), 1) = 1;
+select($rvec, undef, undef, 30) or die "no response to `@pfx $oid` from @cmd";
+my $info = <$out>;
+chop($info) eq "\n" or die "no LF";
+$info eq $expect or die "`$info` != `$expect`";
+close $in or die "close in $!";
+close $out or die "close out $!";
+waitpid $pid, 0;
+$? == 0 or die "\$?=$?";
+'
+
+expect="$hello_oid blob $hello_size"
+
+test_expect_success PERL '--batch-check is unbuffered by default' '
+ perl -e "$script" -- --batch-check $hello_oid "$expect"
+'
+
+test_expect_success PERL '--batch-command info is unbuffered by default' '
+ perl -e "$script" -- --batch-command $hello_oid "$expect" "info "
+'
+
test_done
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index ac3d173767..a0481139de 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -2,7 +2,6 @@
test_description="git hash-object"
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
echo_without_newline() {
@@ -124,8 +123,8 @@ test_expect_success 'check that appropriate filter is invoke when --path is used
path0_sha=$(git hash-object --path=file0 file1) &&
test "$file0_sha" = "$path0_sha" &&
test "$file1_sha" = "$path1_sha" &&
- path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) &&
- path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) &&
+ path1_sha=$(git hash-object --path=file1 --stdin <file0) &&
+ path0_sha=$(git hash-object --path=file0 --stdin <file1) &&
test "$file0_sha" = "$path0_sha" &&
test "$file1_sha" = "$path1_sha"
'
@@ -154,7 +153,7 @@ test_expect_success '--path works in a subdirectory' '
test_expect_success 'check that --no-filters option works' '
nofilters_file1=$(git hash-object --no-filters file1) &&
test "$file0_sha" = "$nofilters_file1" &&
- nofilters_file1=$(cat file1 | git hash-object --stdin) &&
+ nofilters_file1=$(git hash-object --stdin <file1) &&
test "$file0_sha" = "$nofilters_file1"
'
@@ -260,4 +259,10 @@ test_expect_success '--literally with extra-long type' '
echo example | git hash-object -t $t --literally --stdin
'
+test_expect_success '--stdin outside of repository (uses SHA-1)' '
+ nongit git hash-object --stdin <hello >actual &&
+ echo "$(test_oid --hash=sha1 hello)" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1008-read-tree-overlay.sh b/t/t1008-read-tree-overlay.sh
index ad5936e54d..4512fb0b6e 100755
--- a/t/t1008-read-tree-overlay.sh
+++ b/t/t1008-read-tree-overlay.sh
@@ -5,7 +5,6 @@ test_description='test multi-tree read-tree without merging'
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-read-tree.sh
diff --git a/t/t1009-read-tree-new-index.sh b/t/t1009-read-tree-new-index.sh
index fc179ac5dd..2935f68f8d 100755
--- a/t/t1009-read-tree-new-index.sh
+++ b/t/t1009-read-tree-new-index.sh
@@ -5,7 +5,6 @@ test_description='test read-tree into a fresh index file'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 22875ba598..c291a2b33d 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -2,7 +2,6 @@
test_description='git mktree'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 595b24c0ad..742f0fa909 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -12,7 +12,6 @@ test_description='sparse checkout tests
'
TEST_CREATE_REPO_NO_TEMPLATE=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
diff --git a/t/t1012-read-tree-df.sh b/t/t1012-read-tree-df.sh
index cde93d22cd..57f0770df1 100755
--- a/t/t1012-read-tree-df.sh
+++ b/t/t1012-read-tree-df.sh
@@ -2,7 +2,6 @@
test_description='read-tree D/F conflict corner cases'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
diff --git a/t/t1014-read-tree-confusing.sh b/t/t1014-read-tree-confusing.sh
index 8ea8d36818..0c0e6da5cf 100755
--- a/t/t1014-read-tree-confusing.sh
+++ b/t/t1014-read-tree-confusing.sh
@@ -2,7 +2,6 @@
test_description='check that read-tree rejects confusing paths'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create base tree' '
diff --git a/t/t1015-read-index-unmerged.sh b/t/t1015-read-index-unmerged.sh
index 55d22da32c..9b965d0294 100755
--- a/t/t1015-read-index-unmerged.sh
+++ b/t/t1015-read-index-unmerged.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='Test various callers of read_index_unmerged'
+
. ./test-lib.sh
test_expect_success 'setup modify/delete + directory/file conflict' '
diff --git a/t/t1016-compatObjectFormat.sh b/t/t1016-compatObjectFormat.sh
new file mode 100755
index 0000000000..e88362fbe4
--- /dev/null
+++ b/t/t1016-compatObjectFormat.sh
@@ -0,0 +1,278 @@
+#!/bin/sh
+#
+# Copyright (c) 2023 Eric Biederman
+#
+
+test_description='Test how well compatObjectFormat works'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-gpg.sh
+
+# All of the follow variables must be defined in the environment:
+# GIT_AUTHOR_NAME
+# GIT_AUTHOR_EMAIL
+# GIT_AUTHOR_DATE
+# GIT_COMMITTER_NAME
+# GIT_COMMITTER_EMAIL
+# GIT_COMMITTER_DATE
+#
+# The test relies on these variables being set so that the two
+# different commits in two different repositories encoded with two
+# different hash functions result in the same content in the commits.
+# This means that when the commit is translated between hash functions
+# the commit is identical to the commit in the other repository.
+
+compat_hash () {
+ case "$1" in
+ "sha1")
+ echo "sha256"
+ ;;
+ "sha256")
+ echo "sha1"
+ ;;
+ esac
+}
+
+hello_oid () {
+ case "$1" in
+ "sha1")
+ echo "$hello_sha1_oid"
+ ;;
+ "sha256")
+ echo "$hello_sha256_oid"
+ ;;
+ esac
+}
+
+tree_oid () {
+ case "$1" in
+ "sha1")
+ echo "$tree_sha1_oid"
+ ;;
+ "sha256")
+ echo "$tree_sha256_oid"
+ ;;
+ esac
+}
+
+commit_oid () {
+ case "$1" in
+ "sha1")
+ echo "$commit_sha1_oid"
+ ;;
+ "sha256")
+ echo "$commit_sha256_oid"
+ ;;
+ esac
+}
+
+commit2_oid () {
+ case "$1" in
+ "sha1")
+ echo "$commit2_sha1_oid"
+ ;;
+ "sha256")
+ echo "$commit2_sha256_oid"
+ ;;
+ esac
+}
+
+del_sigcommit () {
+ local delete="$1"
+
+ if test "$delete" = "sha256" ; then
+ local pattern="gpgsig-sha256"
+ else
+ local pattern="gpgsig"
+ fi
+ test-tool delete-gpgsig "$pattern"
+}
+
+del_sigtag () {
+ local storage="$1"
+ local delete="$2"
+
+ if test "$storage" = "$delete" ; then
+ local pattern="trailer"
+ elif test "$storage" = "sha256" ; then
+ local pattern="gpgsig"
+ else
+ local pattern="gpgsig-sha256"
+ fi
+ test-tool delete-gpgsig "$pattern"
+}
+
+base=$(pwd)
+for hash in sha1 sha256
+do
+ cd "$base"
+ mkdir -p repo-$hash
+ cd repo-$hash
+
+ test_expect_success "setup $hash repository" '
+ git init --object-format=$hash &&
+ git config core.repositoryformatversion 1 &&
+ git config extensions.objectformat $hash &&
+ git config extensions.compatobjectformat $(compat_hash $hash) &&
+ test_config gpg.program $TEST_DIRECTORY/t1016/gpg &&
+ echo "Hello World!" >hello &&
+ eval hello_${hash}_oid=$(git hash-object hello) &&
+ git update-index --add hello &&
+ git commit -m "Initial commit" &&
+ eval commit_${hash}_oid=$(git rev-parse HEAD) &&
+ eval tree_${hash}_oid=$(git rev-parse HEAD^{tree})
+ '
+ test_expect_success "create a $hash tagged blob" '
+ git tag --no-sign -m "This is a tag" hellotag $(hello_oid $hash) &&
+ eval hellotag_${hash}_oid=$(git rev-parse hellotag)
+ '
+ test_expect_success "create a $hash tagged tree" '
+ git tag --no-sign -m "This is a tag" treetag $(tree_oid $hash) &&
+ eval treetag_${hash}_oid=$(git rev-parse treetag)
+ '
+ test_expect_success "create a $hash tagged commit" '
+ git tag --no-sign -m "This is a tag" committag $(commit_oid $hash) &&
+ eval committag_${hash}_oid=$(git rev-parse committag)
+ '
+ test_expect_success GPG2 "create a $hash signed commit" '
+ git commit --gpg-sign --allow-empty -m "This is a signed commit" &&
+ eval signedcommit_${hash}_oid=$(git rev-parse HEAD)
+ '
+ test_expect_success GPG2 "create a $hash signed tag" '
+ git tag -s -m "This is a signed tag" signedtag HEAD &&
+ eval signedtag_${hash}_oid=$(git rev-parse signedtag)
+ '
+ test_expect_success "create a $hash branch" '
+ git checkout -b branch $(commit_oid $hash) &&
+ echo "More more more give me more!" >more &&
+ eval more_${hash}_oid=$(git hash-object more) &&
+ echo "Another and another and another" >another &&
+ eval another_${hash}_oid=$(git hash-object another) &&
+ git update-index --add more another &&
+ git commit -m "Add more files!" &&
+ eval commit2_${hash}_oid=$(git rev-parse HEAD) &&
+ eval tree2_${hash}_oid=$(git rev-parse HEAD^{tree})
+ '
+ test_expect_success GPG2 "create another $hash signed tag" '
+ git tag -s -m "This is another signed tag" signedtag2 $(commit2_oid $hash) &&
+ eval signedtag2_${hash}_oid=$(git rev-parse signedtag2)
+ '
+ test_expect_success GPG2 "merge the $hash branches together" '
+ git merge -S -m "merge some signed tags together" signedtag signedtag2 &&
+ eval signedcommit2_${hash}_oid=$(git rev-parse HEAD)
+ '
+ test_expect_success GPG2 "create additional $hash signed commits" '
+ git commit --gpg-sign --allow-empty -m "This is an additional signed commit" &&
+ git cat-file commit HEAD | del_sigcommit sha256 >"../${hash}_signedcommit3" &&
+ git cat-file commit HEAD | del_sigcommit sha1 >"../${hash}_signedcommit4" &&
+ eval signedcommit3_${hash}_oid=$(git hash-object -t commit -w ../${hash}_signedcommit3) &&
+ eval signedcommit4_${hash}_oid=$(git hash-object -t commit -w ../${hash}_signedcommit4)
+ '
+ test_expect_success GPG2 "create additional $hash signed tags" '
+ git tag -s -m "This is an additional signed tag" signedtag34 HEAD &&
+ git cat-file tag signedtag34 | del_sigtag "${hash}" sha256 >../${hash}_signedtag3 &&
+ git cat-file tag signedtag34 | del_sigtag "${hash}" sha1 >../${hash}_signedtag4 &&
+ eval signedtag3_${hash}_oid=$(git hash-object -t tag -w ../${hash}_signedtag3) &&
+ eval signedtag4_${hash}_oid=$(git hash-object -t tag -w ../${hash}_signedtag4)
+ '
+done
+cd "$base"
+
+compare_oids () {
+ test "$#" = 5 && { local PREREQ="$1"; shift; } || PREREQ=
+ local type="$1"
+ local name="$2"
+ local sha1_oid="$3"
+ local sha256_oid="$4"
+
+ echo ${sha1_oid} >${name}_sha1_expected
+ echo ${sha256_oid} >${name}_sha256_expected
+ echo ${type} >${name}_type_expected
+
+ git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} >${name}_sha1_sha256_found
+ git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} >${name}_sha256_sha1_found
+ local sha1_sha256_oid="$(cat ${name}_sha1_sha256_found)"
+ local sha256_sha1_oid="$(cat ${name}_sha256_sha1_found)"
+
+ test_expect_success $PREREQ "Verify ${type} ${name}'s sha1 oid" '
+ git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} >${name}_sha1 &&
+ test_cmp ${name}_sha1 ${name}_sha1_expected
+ '
+
+ test_expect_success $PREREQ "Verify ${type} ${name}'s sha256 oid" '
+ git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} >${name}_sha256 &&
+ test_cmp ${name}_sha256 ${name}_sha256_expected
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha1 type" '
+ git --git-dir=repo-sha1/.git cat-file -t ${sha1_oid} >${name}_type1 &&
+ git --git-dir=repo-sha256/.git cat-file -t ${sha256_sha1_oid} >${name}_type2 &&
+ test_cmp ${name}_type1 ${name}_type2 &&
+ test_cmp ${name}_type1 ${name}_type_expected
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha256 type" '
+ git --git-dir=repo-sha256/.git cat-file -t ${sha256_oid} >${name}_type3 &&
+ git --git-dir=repo-sha1/.git cat-file -t ${sha1_sha256_oid} >${name}_type4 &&
+ test_cmp ${name}_type3 ${name}_type4 &&
+ test_cmp ${name}_type3 ${name}_type_expected
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha1 size" '
+ git --git-dir=repo-sha1/.git cat-file -s ${sha1_oid} >${name}_size1 &&
+ git --git-dir=repo-sha256/.git cat-file -s ${sha256_sha1_oid} >${name}_size2 &&
+ test_cmp ${name}_size1 ${name}_size2
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha256 size" '
+ git --git-dir=repo-sha256/.git cat-file -s ${sha256_oid} >${name}_size3 &&
+ git --git-dir=repo-sha1/.git cat-file -s ${sha1_sha256_oid} >${name}_size4 &&
+ test_cmp ${name}_size3 ${name}_size4
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha1 pretty content" '
+ git --git-dir=repo-sha1/.git cat-file -p ${sha1_oid} >${name}_content1 &&
+ git --git-dir=repo-sha256/.git cat-file -p ${sha256_sha1_oid} >${name}_content2 &&
+ test_cmp ${name}_content1 ${name}_content2
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha256 pretty content" '
+ git --git-dir=repo-sha256/.git cat-file -p ${sha256_oid} >${name}_content3 &&
+ git --git-dir=repo-sha1/.git cat-file -p ${sha1_sha256_oid} >${name}_content4 &&
+ test_cmp ${name}_content3 ${name}_content4
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha1 content" '
+ git --git-dir=repo-sha1/.git cat-file ${type} ${sha1_oid} >${name}_content5 &&
+ git --git-dir=repo-sha256/.git cat-file ${type} ${sha256_sha1_oid} >${name}_content6 &&
+ test_cmp ${name}_content5 ${name}_content6
+ '
+
+ test_expect_success $PREREQ "Verify ${name}'s sha256 content" '
+ git --git-dir=repo-sha256/.git cat-file ${type} ${sha256_oid} >${name}_content7 &&
+ git --git-dir=repo-sha1/.git cat-file ${type} ${sha1_sha256_oid} >${name}_content8 &&
+ test_cmp ${name}_content7 ${name}_content8
+ '
+}
+
+compare_oids 'blob' hello "$hello_sha1_oid" "$hello_sha256_oid"
+compare_oids 'tree' tree "$tree_sha1_oid" "$tree_sha256_oid"
+compare_oids 'commit' commit "$commit_sha1_oid" "$commit_sha256_oid"
+compare_oids GPG2 'commit' signedcommit "$signedcommit_sha1_oid" "$signedcommit_sha256_oid"
+compare_oids 'tag' hellotag "$hellotag_sha1_oid" "$hellotag_sha256_oid"
+compare_oids 'tag' treetag "$treetag_sha1_oid" "$treetag_sha256_oid"
+compare_oids 'tag' committag "$committag_sha1_oid" "$committag_sha256_oid"
+compare_oids GPG2 'tag' signedtag "$signedtag_sha1_oid" "$signedtag_sha256_oid"
+
+compare_oids 'blob' more "$more_sha1_oid" "$more_sha256_oid"
+compare_oids 'blob' another "$another_sha1_oid" "$another_sha256_oid"
+compare_oids 'tree' tree2 "$tree2_sha1_oid" "$tree2_sha256_oid"
+compare_oids 'commit' commit2 "$commit2_sha1_oid" "$commit2_sha256_oid"
+compare_oids GPG2 'tag' signedtag2 "$signedtag2_sha1_oid" "$signedtag2_sha256_oid"
+compare_oids GPG2 'commit' signedcommit2 "$signedcommit2_sha1_oid" "$signedcommit2_sha256_oid"
+compare_oids GPG2 'commit' signedcommit3 "$signedcommit3_sha1_oid" "$signedcommit3_sha256_oid"
+compare_oids GPG2 'commit' signedcommit4 "$signedcommit4_sha1_oid" "$signedcommit4_sha256_oid"
+compare_oids GPG2 'tag' signedtag3 "$signedtag3_sha1_oid" "$signedtag3_sha256_oid"
+compare_oids GPG2 'tag' signedtag4 "$signedtag4_sha1_oid" "$signedtag4_sha256_oid"
+
+test_done
diff --git a/t/t1016/gpg b/t/t1016/gpg
new file mode 100755
index 0000000000..2601cb18a5
--- /dev/null
+++ b/t/t1016/gpg
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec gpg --faked-system-time "20230918T154812" "$@"
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index 45eef9457f..9fdbb2af80 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -6,7 +6,6 @@
test_description='Try various core-level commands in subdirectory.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh
index cca4380e43..d390d7d5f8 100755
--- a/t/t1022-read-tree-partial-clone.sh
+++ b/t/t1022-read-tree-partial-clone.sh
@@ -3,7 +3,6 @@
test_description='git read-tree in partial clones'
TEST_NO_CREATE_REPO=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'read-tree in partial clone prefetches in one batch' '
diff --git a/t/t1051-large-conversion.sh b/t/t1051-large-conversion.sh
index f6709c9f56..361afb679b 100755
--- a/t/t1051-large-conversion.sh
+++ b/t/t1051-large-conversion.sh
@@ -2,7 +2,6 @@
test_description='test conversion filters on large files'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
set_attr() {
diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh
index 35261afc9d..502a5ea1c5 100755
--- a/t/t1060-object-corruption.sh
+++ b/t/t1060-object-corruption.sh
@@ -2,7 +2,6 @@
test_description='see how we handle various forms of corruption'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# convert "1234abcd" to ".git/objects/12/34abcd"
@@ -125,7 +124,7 @@ test_expect_success 'fetch into corrupted repo with index-pack' '
cd bit-error-cp &&
test_must_fail git -c transfer.unpackLimit=1 \
fetch ../no-bit-error 2>stderr &&
- test_i18ngrep ! -i collision stderr
+ test_grep ! -i collision stderr
)
'
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 9ceb17f911..ab3a105fff 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -47,7 +47,7 @@ test_expect_success 'setup' '
test_expect_success 'git sparse-checkout list (not sparse)' '
test_must_fail git -C repo sparse-checkout list >list 2>err &&
test_must_be_empty list &&
- test_i18ngrep "this worktree is not sparse" err
+ test_grep "this worktree is not sparse" err
'
test_expect_success 'git sparse-checkout list (not sparse)' '
@@ -55,7 +55,7 @@ test_expect_success 'git sparse-checkout list (not sparse)' '
rm repo/.git/info/sparse-checkout &&
git -C repo sparse-checkout list >list 2>err &&
test_must_be_empty list &&
- test_i18ngrep "this worktree is not sparse (sparse-checkout file may not exist)" err
+ test_grep "this worktree is not sparse (sparse-checkout file may not exist)" err
'
test_expect_success 'git sparse-checkout list (populated)' '
@@ -230,7 +230,7 @@ test_expect_success 'cone mode: match patterns' '
git -C repo config --worktree core.sparseCheckoutCone true &&
rm -rf repo/a repo/folder1 repo/folder2 &&
git -C repo read-tree -mu HEAD 2>err &&
- test_i18ngrep ! "disabling cone patterns" err &&
+ test_grep ! "disabling cone patterns" err &&
git -C repo reset --hard &&
check_files repo a folder1 folder2
'
@@ -240,7 +240,7 @@ test_expect_success 'cone mode: warn on bad pattern' '
cp repo/.git/info/sparse-checkout . &&
echo "!/deep/deeper/*/" >>repo/.git/info/sparse-checkout &&
git -C repo read-tree -mu HEAD 2>err &&
- test_i18ngrep "unrecognized negative pattern" err
+ test_grep "unrecognized negative pattern" err
'
test_expect_success 'sparse-checkout disable' '
@@ -283,7 +283,7 @@ test_expect_success 'sparse-index enabled and disabled' '
test_expect_success 'cone mode: init and set' '
git -C repo sparse-checkout init --cone &&
git -C repo config --list >config &&
- test_i18ngrep "core.sparsecheckoutcone=true" config &&
+ test_grep "core.sparsecheckoutcone=true" config &&
list_files repo >dir &&
echo a >expect &&
test_cmp expect dir &&
@@ -334,7 +334,7 @@ test_expect_success 'cone mode: set with nested folders' '
test_expect_success 'cone mode: add independent path' '
git -C repo sparse-checkout set deep/deeper1 &&
- git -C repo sparse-checkout add folder1 &&
+ git -C repo sparse-checkout add --end-of-options folder1 &&
cat >expect <<-\EOF &&
/*
!/*/
@@ -386,7 +386,7 @@ test_expect_success 'not-up-to-date does not block rest of sparsification' '
git -C repo sparse-checkout set deep/deeper1 2>err &&
- test_i18ngrep "The following paths are not up to date" err &&
+ test_grep "The following paths are not up to date" err &&
test_cmp expect repo/.git/info/sparse-checkout &&
check_files repo/deep a deeper1 deeper2 &&
check_files repo/deep/deeper1 a deepest &&
@@ -401,8 +401,8 @@ test_expect_success 'revert to old sparse-checkout on empty update' '
git add file &&
git commit -m "test" &&
git sparse-checkout set nothing 2>err &&
- test_i18ngrep ! "Sparse checkout leaves no entry on working directory" err &&
- test_i18ngrep ! ".git/index.lock" err &&
+ test_grep ! "Sparse checkout leaves no entry on working directory" err &&
+ test_grep ! ".git/index.lock" err &&
git sparse-checkout set --no-cone file
)
'
@@ -411,14 +411,14 @@ test_expect_success 'fail when lock is taken' '
test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
touch repo/.git/info/sparse-checkout.lock &&
test_must_fail git -C repo sparse-checkout set deep 2>err &&
- test_i18ngrep "Unable to create .*\.lock" err
+ test_grep "Unable to create .*\.lock" err
'
test_expect_success '.gitignore should not warn about cone mode' '
git -C repo config --worktree core.sparseCheckoutCone true &&
echo "**/bin/*" >repo/.gitignore &&
git -C repo reset --hard 2>err &&
- test_i18ngrep ! "disabling cone patterns" err
+ test_grep ! "disabling cone patterns" err
'
test_expect_success 'sparse-checkout (init|set|disable) warns with dirty status' '
@@ -426,10 +426,10 @@ test_expect_success 'sparse-checkout (init|set|disable) warns with dirty status'
echo dirty >dirty/folder1/a &&
git -C dirty sparse-checkout init --no-cone 2>err &&
- test_i18ngrep "warning.*The following paths are not up to date" err &&
+ test_grep "warning.*The following paths are not up to date" err &&
git -C dirty sparse-checkout set /folder2/* /deep/deeper1/* 2>err &&
- test_i18ngrep "warning.*The following paths are not up to date" err &&
+ test_grep "warning.*The following paths are not up to date" err &&
test_path_is_file dirty/folder1/a &&
git -C dirty sparse-checkout disable 2>err &&
@@ -453,14 +453,14 @@ test_expect_success 'sparse-checkout (init|set|disable) warns with unmerged stat
git -C unmerged update-index --index-info <input &&
git -C unmerged sparse-checkout init --no-cone 2>err &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
git -C unmerged sparse-checkout set /folder2/* /deep/deeper1/* 2>err &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
test_path_is_file dirty/folder1/a &&
git -C unmerged sparse-checkout disable 2>err &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
git -C unmerged reset --hard &&
git -C unmerged sparse-checkout init --no-cone &&
@@ -480,24 +480,24 @@ test_expect_failure 'sparse-checkout reapply' '
git -C tweak update-index --index-info <input &&
git -C tweak sparse-checkout init --cone 2>err &&
- test_i18ngrep "warning.*The following paths are not up to date" err &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are not up to date" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
git -C tweak sparse-checkout set folder2 deep/deeper1 2>err &&
- test_i18ngrep "warning.*The following paths are not up to date" err &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are not up to date" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
git -C tweak sparse-checkout reapply 2>err &&
- test_i18ngrep "warning.*The following paths are not up to date" err &&
+ test_grep "warning.*The following paths are not up to date" err &&
test_path_is_file tweak/deep/deeper2/a &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
test_path_is_file tweak/folder1/a &&
git -C tweak checkout HEAD deep/deeper2/a &&
git -C tweak sparse-checkout reapply 2>err &&
- test_i18ngrep ! "warning.*The following paths are not up to date" err &&
+ test_grep ! "warning.*The following paths are not up to date" err &&
test_path_is_missing tweak/deep/deeper2/a &&
- test_i18ngrep "warning.*The following paths are unmerged" err &&
+ test_grep "warning.*The following paths are unmerged" err &&
test_path_is_file tweak/folder1/a &&
# NEEDSWORK: We are asking to update a file outside of the
@@ -578,8 +578,8 @@ 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_grep ! "modules/" check-rules-matches &&
+ test_grep "folder1/" check-rules-matches
'
test_expect_success 'different sparse-checkouts with worktrees' '
@@ -616,7 +616,7 @@ check_read_tree_errors () {
then
test_must_be_empty err
else
- test_i18ngrep "$ERRORS" err
+ test_grep "$ERRORS" err
fi &&
check_files $REPO $FILES
}
@@ -886,6 +886,12 @@ test_expect_success 'by default, cone mode will error out when passed files' '
grep ".gitignore.*is not a directory" error
'
+test_expect_success 'error on mistyped command line options' '
+ test_must_fail git -C repo sparse-checkout add --sikp-checks .gitignore 2>error &&
+
+ grep "unknown option.*sikp-checks" error
+'
+
test_expect_success 'by default, non-cone mode will warn on individual files' '
git -C repo sparse-checkout reapply --no-cone &&
git -C repo sparse-checkout add .gitignore 2>warning &&
@@ -898,32 +904,32 @@ test_expect_success 'setup bare repo' '
'
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_grep "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_grep "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_grep "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_grep "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_grep "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_grep "this operation must be run in a work tree" err
'
test_expect_success 'setup clean' '
@@ -946,8 +952,8 @@ test_expect_success 'check-rules cone mode' '
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_grep "deep/deeper1/deepest/a" check-rules-file &&
+ test_grep ! "deep/deeper2" check-rules-file &&
test_cmp check-rules-file ls-files &&
test_cmp check-rules-file check-rules-default
@@ -962,7 +968,7 @@ test_expect_success 'check-rules non-cone mode' '
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 sparse-checkout set --no-cone --stdin <rules &&
git -C repo ls-files -t >out &&
sed -n "/^S /!s/^. //p" out >ls-files &&
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 8a95adf4b5..a4c7c41fc0 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -159,7 +159,10 @@ init_repos () {
git -C sparse-checkout sparse-checkout set deep &&
git -C sparse-index sparse-checkout init --cone --sparse-index &&
test_cmp_config -C sparse-index true index.sparse &&
- git -C sparse-index sparse-checkout set deep
+ git -C sparse-index sparse-checkout set deep &&
+
+ # Disable this message to keep stderr the same.
+ git -C sparse-index config advice.sparseIndexExpanded false
}
init_repos_as_submodules () {
@@ -176,22 +179,26 @@ init_repos_as_submodules () {
}
run_on_sparse () {
+ cat >run-on-sparse-input &&
+
(
cd sparse-checkout &&
GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err
- ) &&
+ ) <run-on-sparse-input &&
(
cd sparse-index &&
GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err
- )
+ ) <run-on-sparse-input
}
run_on_all () {
+ cat >run-on-all-input &&
+
(
cd full-checkout &&
GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err
- ) &&
- run_on_sparse "$@"
+ ) <run-on-all-input &&
+ run_on_sparse "$@" <run-on-all-input
}
test_all_match () {
@@ -218,7 +225,7 @@ test_sparse_unstaged () {
done
}
-# Usage: test_sprase_checkout_set "<c1> ... <cN>" "<s1> ... <sM>"
+# Usage: test_sparse_checkout_set "<c1> ... <cN>" "<s1> ... <sM>"
# Verifies that "git sparse-checkout set <c1> ... <cN>" succeeds and
# leaves the sparse index in a state where <s1> ... <sM> are sparse
# directories (and <c1> ... <cN> are not).
@@ -337,8 +344,8 @@ test_expect_success 'status reports sparse-checkout' '
init_repos &&
git -C sparse-checkout status >full &&
git -C sparse-index status >sparse &&
- test_i18ngrep "You are in a sparse checkout with " full &&
- test_i18ngrep "You are in a sparse checkout." sparse
+ test_grep "You are in a sparse checkout with " full &&
+ test_grep "You are in a sparse checkout." sparse
'
test_expect_success 'add, commit, checkout' '
@@ -700,7 +707,7 @@ test_expect_success 'reset with wildcard pathspec' '
test_all_match git ls-files -s -- deep &&
# The following `git reset`s result in updating the index on files with
- # `skip-worktree` enabled. To avoid failing due to discrepencies in reported
+ # `skip-worktree` enabled. To avoid failing due to discrepancies in reported
# "modified" files, `test_sparse_match` reset is performed separately from
# "full-checkout" reset, then the index contents of all repos are verified.
@@ -800,6 +807,8 @@ test_expect_success 'update-index --remove outside sparse definition' '
test_sparse_match git diff --cached --name-status &&
test_cmp expect sparse-checkout-out &&
+ test_sparse_match git diff-index --cached HEAD &&
+
# Reset the state
test_all_match git reset --hard &&
@@ -809,10 +818,12 @@ test_expect_success 'update-index --remove outside sparse definition' '
test_sparse_match git diff --cached --name-status &&
test_must_be_empty sparse-checkout-out &&
+ test_sparse_match git diff-index --cached HEAD &&
+
# Reset the state
test_all_match git reset --hard &&
- # --force-remove supercedes --ignore-skip-worktree-entries, removing
+ # --force-remove supersedes --ignore-skip-worktree-entries, removing
# a skip-worktree file from the index (and disk) when both are specified
# with --remove
test_sparse_match git update-index --force-remove --ignore-skip-worktree-entries folder1/a &&
@@ -820,7 +831,9 @@ test_expect_success 'update-index --remove outside sparse definition' '
D folder1/a
EOF
test_sparse_match git diff --cached --name-status &&
- test_cmp expect sparse-checkout-out
+ test_cmp expect sparse-checkout-out &&
+
+ test_sparse_match git diff-index --cached HEAD
'
test_expect_success 'update-index with directories' '
@@ -1182,7 +1195,7 @@ test_expect_success 'checkout-index outside sparse definition' '
# Without --ignore-skip-worktree-bits, outside-of-cone files will trigger
# an error
test_sparse_match test_must_fail git checkout-index -- folder1/a &&
- test_i18ngrep "folder1/a has skip-worktree enabled" sparse-checkout-err &&
+ test_grep "folder1/a has skip-worktree enabled" sparse-checkout-err &&
test_path_is_missing folder1/a &&
# With --ignore-skip-worktree-bits, outside-of-cone files are checked out
@@ -1548,7 +1561,7 @@ test_expect_success 'sparse-index is not expanded: describe' '
ensure_not_expanded describe
'
-test_expect_success 'sparse index is not expanded: diff' '
+test_expect_success 'sparse index is not expanded: diff and diff-index' '
init_repos &&
write_script edit-contents <<-\EOF &&
@@ -1565,6 +1578,7 @@ test_expect_success 'sparse index is not expanded: diff' '
test_all_match git diff --cached &&
ensure_not_expanded diff &&
ensure_not_expanded diff --cached &&
+ ensure_not_expanded diff-index --cached HEAD &&
# Add file outside cone
test_all_match git reset --hard &&
@@ -1579,6 +1593,7 @@ test_expect_success 'sparse index is not expanded: diff' '
test_all_match git diff --cached &&
ensure_not_expanded diff &&
ensure_not_expanded diff --cached &&
+ ensure_not_expanded diff-index --cached HEAD &&
# Merge conflict outside cone
# The sparse checkout will report a warning that is not in the
@@ -1591,7 +1606,8 @@ test_expect_success 'sparse index is not expanded: diff' '
test_all_match git diff &&
test_all_match git diff --cached &&
ensure_not_expanded diff &&
- ensure_not_expanded diff --cached
+ ensure_not_expanded diff --cached &&
+ ensure_not_expanded diff-index --cached HEAD
'
test_expect_success 'sparse index is not expanded: show and rev-parse' '
@@ -2064,7 +2080,7 @@ test_expect_success 'grep is not expanded' '
test_expect_failure 'grep within submodules is not expanded' '
init_repos_as_submodules &&
- # do not use ensure_not_expanded() here, becasue `grep` should be
+ # do not use ensure_not_expanded() here, because `grep` should be
# run in the superproject, not in "./sparse-index"
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
git grep --cached --recurse-submodules a -- "*/folder1/*" &&
@@ -2259,4 +2275,126 @@ test_expect_success 'worktree is not expanded' '
ensure_not_expanded worktree remove .worktrees/hotfix
'
+test_expect_success 'check-attr with pathspec inside sparse definition' '
+ init_repos &&
+
+ echo "a -crlf myAttr" >>.gitattributes &&
+ run_on_all cp ../.gitattributes ./deep &&
+
+ test_all_match git check-attr -a -- deep/a &&
+
+ test_all_match git add deep/.gitattributes &&
+ test_all_match git check-attr -a --cached -- deep/a
+'
+
+test_expect_success 'check-attr with pathspec outside sparse definition' '
+ init_repos &&
+
+ echo "a -crlf myAttr" >>.gitattributes &&
+ run_on_sparse mkdir folder1 &&
+ run_on_all cp ../.gitattributes ./folder1 &&
+ run_on_all cp a folder1/a &&
+
+ test_all_match git check-attr -a -- folder1/a &&
+
+ git -C full-checkout add folder1/.gitattributes &&
+ test_sparse_match git add --sparse folder1/.gitattributes &&
+ test_all_match git commit -m "add .gitattributes" &&
+ test_sparse_match git sparse-checkout reapply &&
+ test_all_match git check-attr -a --cached -- folder1/a
+'
+
+# NEEDSWORK: The 'diff --check' test is left as 'test_expect_failure' due
+# to an underlying issue in oneway_diff() within diff-lib.c.
+# 'do_oneway_diff()' is not called as expected for paths that could match
+# inside of a sparse directory. Specifically, the 'ce_path_match()' function
+# fails to recognize files inside a sparse directory (e.g., when 'folder1/'
+# is a sparse directory, 'folder1/a' cannot be recognized). The goal is to
+# proceed with 'do_oneway_diff()' if the pathspec could match inside of a
+# sparse directory.
+test_expect_failure 'diff --check with pathspec outside sparse definition' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo "a " >"$1"
+ EOF
+
+ test_all_match git config core.whitespace -trailing-space,-space-before-tab &&
+
+ echo "a whitespace=trailing-space,space-before-tab" >>.gitattributes &&
+ run_on_all mkdir -p folder1 &&
+ run_on_all cp ../.gitattributes ./folder1 &&
+ test_all_match git add --sparse folder1/.gitattributes &&
+ run_on_all ../edit-contents folder1/a &&
+ test_all_match git add --sparse folder1/a &&
+
+ test_sparse_match git sparse-checkout reapply &&
+ test_all_match test_must_fail git diff --check --cached -- folder1/a
+'
+
+test_expect_success 'sparse-index is not expanded: check-attr' '
+ init_repos &&
+
+ echo "a -crlf myAttr" >>.gitattributes &&
+ mkdir ./sparse-index/folder1 &&
+ cp ./sparse-index/a ./sparse-index/folder1/a &&
+ cp .gitattributes ./sparse-index/deep &&
+ cp .gitattributes ./sparse-index/folder1 &&
+
+ git -C sparse-index add deep/.gitattributes &&
+ git -C sparse-index add --sparse folder1/.gitattributes &&
+ ensure_not_expanded check-attr -a --cached -- deep/a &&
+ ensure_not_expanded check-attr -a --cached -- folder1/a
+'
+
+test_expect_success 'advice.sparseIndexExpanded' '
+ init_repos &&
+
+ git -C sparse-index config --unset advice.sparseIndexExpanded &&
+ git -C sparse-index sparse-checkout set deep/deeper1 &&
+ mkdir -p sparse-index/deep/deeper2/deepest &&
+ touch sparse-index/deep/deeper2/deepest/bogus &&
+ git -C sparse-index status 2>err &&
+ grep "The sparse index is expanding to a full index" err &&
+
+ git -C sparse-index sparse-checkout disable 2>err &&
+ test_line_count = 0 err
+'
+
+test_expect_success 'cat-file -p' '
+ init_repos &&
+ echo "new content" >>full-checkout/deep/a &&
+ echo "new content" >>sparse-checkout/deep/a &&
+ echo "new content" >>sparse-index/deep/a &&
+ run_on_all git add deep/a &&
+
+ test_all_match git cat-file -p :deep/a &&
+ ensure_not_expanded cat-file -p :deep/a &&
+ test_all_match git cat-file -p :folder1/a &&
+ ensure_expanded cat-file -p :folder1/a
+'
+
+test_expect_success 'cat-file --batch' '
+ init_repos &&
+ echo "new content" >>full-checkout/deep/a &&
+ echo "new content" >>sparse-checkout/deep/a &&
+ echo "new content" >>sparse-index/deep/a &&
+ run_on_all git add deep/a &&
+
+ echo ":deep/a" >in &&
+ test_all_match git cat-file --batch <in &&
+ ensure_not_expanded cat-file --batch <in &&
+
+ echo ":folder1/a" >in &&
+ test_all_match git cat-file --batch <in &&
+ ensure_expanded cat-file --batch <in &&
+
+ cat >in <<-\EOF &&
+ :deep/a
+ :folder1/a
+ EOF
+ test_all_match git cat-file --batch <in &&
+ ensure_expanded cat-file --batch <in
+'
+
test_done
diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh
index 0f37a43fd3..ae66ba5bab 100755
--- a/t/t1100-commit-tree-options.sh
+++ b/t/t1100-commit-tree-options.sh
@@ -12,7 +12,6 @@ Also make sure that command line parser understands the normal
"flags first and then non flag arguments" command line.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >expected <<EOF
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 387d336c91..51a85e83c2 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -8,9 +8,128 @@ test_description='Test git config in different settings'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
+for mode in legacy subcommands
+do
+
+case "$mode" in
+legacy)
+ mode_prefix="--"
+ mode_get=""
+ mode_get_all="--get-all"
+ mode_get_regexp="--get-regexp"
+ mode_set=""
+ mode_replace_all="--replace-all"
+ mode_unset="--unset"
+ mode_unset_all="--unset-all"
+ ;;
+subcommands)
+ mode_prefix=""
+ mode_get="get"
+ mode_get_all="get --all"
+ mode_get_regexp="get --regexp --all --show-names"
+ mode_set="set"
+ mode_replace_all="set --all"
+ mode_unset="unset"
+ mode_unset_all="unset --all"
+ ;;
+*)
+ BUG "unknown mode $mode";;
+esac
+
+test_expect_success 'setup whitespace config' '
+ sed -e "s/^|//" \
+ -e "s/[$]$//" \
+ -e "s/X/ /g" >.git/config <<-\EOF
+ [section]
+ | solid = rock
+ | sparse = big XX blue
+ | sparseAndTail = big XX blue $
+ | sparseAndTailQuoted = "big XX blue "
+ | sparseAndBiggerTail = big XX blue X X
+ | sparseAndBiggerTailQuoted = "big XX blue X X"
+ | sparseAndBiggerTailQuotedPlus = "big XX blue X X"X $
+ | headAndTail = Xbig blue $
+ | headAndTailQuoted = "Xbig blue "
+ | headAndTailQuotedPlus = "Xbig blue " $
+ | annotated = big blueX# to be discarded
+ | annotatedQuoted = "big blue"X# to be discarded
+ EOF
+'
+
+test_expect_success 'no internal whitespace' '
+ echo "rock" >expect &&
+ git config --get section.solid >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal whitespace' '
+ echo "big QQ blue" | q_to_tab >expect &&
+ git config --get section.sparse >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and trailing whitespace' '
+ echo "big QQ blue" | q_to_tab >expect &&
+ git config --get section.sparseAndTail >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and trailing whitespace, all quoted' '
+ echo "big QQ blue " | q_to_tab >expect &&
+ git config --get section.sparseAndTailQuoted >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and more trailing whitespace' '
+ echo "big QQ blue" | q_to_tab >expect &&
+ git config --get section.sparseAndBiggerTail >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and more trailing whitespace, all quoted' '
+ echo "big QQ blue Q Q" | q_to_tab >expect &&
+ git config --get section.sparseAndBiggerTailQuoted >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and more trailing whitespace, not all quoted' '
+ echo "big QQ blue Q Q" | q_to_tab >expect &&
+ git config --get section.sparseAndBiggerTailQuotedPlus >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'leading and trailing whitespace' '
+ echo "big blue" >expect &&
+ git config --get section.headAndTail >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'leading and trailing whitespace, all quoted' '
+ echo "Qbig blue " | q_to_tab >expect &&
+ git config --get section.headAndTailQuoted >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'leading and trailing whitespace, not all quoted' '
+ echo "Qbig blue " | q_to_tab >expect &&
+ git config --get section.headAndTailQuotedPlus >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inline comment' '
+ echo "big blue" >expect &&
+ git config --get section.annotated >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inline comment, quoted' '
+ echo "big blue" >expect &&
+ git config --get section.annotatedQuoted >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'clear default config' '
rm -f .git/config
'
@@ -20,7 +139,7 @@ cat > expect << EOF
penguin = little blue
EOF
test_expect_success 'initial' '
- git config section.penguin "little blue" &&
+ git config ${mode_set} section.penguin "little blue" &&
test_cmp expect .git/config
'
@@ -30,7 +149,7 @@ cat > expect << EOF
Movie = BadPhysics
EOF
test_expect_success 'mixed case' '
- git config Section.Movie BadPhysics &&
+ git config ${mode_set} Section.Movie BadPhysics &&
test_cmp expect .git/config
'
@@ -42,7 +161,7 @@ cat > expect << EOF
WhatEver = Second
EOF
test_expect_success 'similar section' '
- git config Sections.WhatEver Second &&
+ git config ${mode_set} Sections.WhatEver Second &&
test_cmp expect .git/config
'
@@ -55,7 +174,7 @@ cat > expect << EOF
WhatEver = Second
EOF
test_expect_success 'uppercase section' '
- git config SECTION.UPPERCASE true &&
+ git config ${mode_set} SECTION.UPPERCASE true &&
test_cmp expect .git/config
'
@@ -69,14 +188,32 @@ test_expect_success 'replace with non-match (actually matching)' '
cat > expect << EOF
[section]
- penguin = very blue
Movie = BadPhysics
UPPERCASE = true
- penguin = kingpin
+ penguin = gentoo # Pygoscelis papua
+ disposition = peckish # find fish
+ foo = bar #abc
+ spsp = value # and comment
+ htsp = value # and comment
[Sections]
WhatEver = Second
EOF
+test_expect_success 'append comments' '
+ git config --replace-all --comment="Pygoscelis papua" section.penguin gentoo &&
+ git config ${mode_set} --comment="find fish" section.disposition peckish &&
+ git config ${mode_set} --comment="#abc" section.foo bar &&
+
+ git config --comment="and comment" section.spsp value &&
+ git config --comment=" # and comment" section.htsp value &&
+
+ test_cmp expect .git/config
+'
+
+test_expect_success 'Prohibited LF in comment' '
+ test_must_fail git config ${mode_set} --comment="a${LF}b" section.k v
+'
+
test_expect_success 'non-match result' 'test_cmp expect .git/config'
test_expect_success 'find mixed-case key by canonical name' '
@@ -125,7 +262,7 @@ foo = bar
EOF
test_expect_success 'unset with cont. lines' '
- git config --unset beta.baz
+ git config ${mode_unset} beta.baz
'
cat > expect <<\EOF
@@ -152,7 +289,7 @@ EOF
cp .git/config .git/config2
test_expect_success 'multiple unset' '
- git config --unset-all beta.haha
+ git config ${mode_unset_all} beta.haha
'
cat > expect << EOF
@@ -171,14 +308,14 @@ test_expect_success 'multiple unset is correct' '
cp .git/config2 .git/config
test_expect_success '--replace-all missing value' '
- test_must_fail git config --replace-all beta.haha &&
+ test_must_fail git config ${mode_replace_all} beta.haha &&
test_cmp .git/config2 .git/config
'
rm .git/config2
test_expect_success '--replace-all' '
- git config --replace-all beta.haha gamma
+ git config ${mode_replace_all} beta.haha gamma
'
cat > expect << EOF
@@ -205,7 +342,7 @@ noIndent= sillyValue ; 'nother silly comment
[nextSection] noNewline = ouch
EOF
test_expect_success 'really mean test' '
- git config beta.haha alpha &&
+ git config ${mode_set} beta.haha alpha &&
test_cmp expect .git/config
'
@@ -220,7 +357,7 @@ noIndent= sillyValue ; 'nother silly comment
nonewline = wow
EOF
test_expect_success 'really really mean test' '
- git config nextsection.nonewline wow &&
+ git config ${mode_set} nextsection.nonewline wow &&
test_cmp expect .git/config
'
@@ -238,7 +375,7 @@ noIndent= sillyValue ; 'nother silly comment
nonewline = wow
EOF
test_expect_success 'unset' '
- git config --unset beta.haha &&
+ git config ${mode_unset} beta.haha &&
test_cmp expect .git/config
'
@@ -274,7 +411,7 @@ test_expect_success 'multi-valued get-all returns all' '
wow
wow2 for me
EOF
- git config --get-all nextsection.nonewline >actual &&
+ git config ${mode_get_all} nextsection.nonewline >actual &&
test_cmp expect actual
'
@@ -294,11 +431,11 @@ test_expect_success 'multivar replace' '
'
test_expect_success 'ambiguous unset' '
- test_must_fail git config --unset nextsection.nonewline
+ test_must_fail git config ${mode_unset} nextsection.nonewline
'
test_expect_success 'invalid unset' '
- test_must_fail git config --unset somesection.nonewline
+ test_must_fail git config ${mode_unset} somesection.nonewline
'
cat > expect << EOF
@@ -312,7 +449,12 @@ noIndent= sillyValue ; 'nother silly comment
EOF
test_expect_success 'multivar unset' '
- git config --unset nextsection.nonewline "wow3$" &&
+ case "$mode" in
+ legacy)
+ git config --unset nextsection.nonewline "wow3$";;
+ subcommands)
+ git config unset --value="wow3$" nextsection.nonewline;;
+ esac &&
test_cmp expect .git/config
'
@@ -350,11 +492,11 @@ version.1.2.3eX.alpha=beta
EOF
test_expect_success 'working --list' '
- git config --list > output &&
+ git config ${mode_prefix}list > output &&
test_cmp expect output
'
test_expect_success '--list without repo produces empty output' '
- git --git-dir=nonexistent config --list >output &&
+ git --git-dir=nonexistent config ${mode_prefix}list >output &&
test_must_be_empty output
'
@@ -366,7 +508,7 @@ version.1.2.3eX.alpha
EOF
test_expect_success '--name-only --list' '
- git config --name-only --list >output &&
+ git config ${mode_prefix}list --name-only >output &&
test_cmp expect output
'
@@ -376,7 +518,7 @@ nextsection.nonewline wow2 for me
EOF
test_expect_success '--get-regexp' '
- git config --get-regexp in >output &&
+ git config ${mode_get_regexp} in >output &&
test_cmp expect output
'
@@ -386,7 +528,7 @@ nextsection.nonewline
EOF
test_expect_success '--name-only --get-regexp' '
- git config --name-only --get-regexp in >output &&
+ git config ${mode_get_regexp} --name-only in >output &&
test_cmp expect output
'
@@ -397,7 +539,7 @@ EOF
test_expect_success '--add' '
git config --add nextsection.nonewline "wow4 for you" &&
- git config --get-all nextsection.nonewline > output &&
+ git config ${mode_get_all} nextsection.nonewline > output &&
test_cmp expect output
'
@@ -419,21 +561,21 @@ test_expect_success 'get variable with empty value' '
echo novalue.variable > expect
test_expect_success 'get-regexp variable with no value' '
- git config --get-regexp novalue > output &&
+ git config ${mode_get_regexp} novalue > output &&
test_cmp expect output
'
echo 'novalue.variable true' > expect
test_expect_success 'get-regexp --bool variable with no value' '
- git config --bool --get-regexp novalue > output &&
+ git config ${mode_get_regexp} --bool novalue > output &&
test_cmp expect output
'
echo 'emptyvalue.variable ' > expect
test_expect_success 'get-regexp variable with empty value' '
- git config --get-regexp emptyvalue > output &&
+ git config ${mode_get_regexp} emptyvalue > output &&
test_cmp expect output
'
@@ -453,7 +595,8 @@ test_expect_success 'get bool variable with empty value' '
test_expect_success 'no arguments, but no crash' '
test_must_fail git config >output 2>&1 &&
- test_i18ngrep usage output
+ echo "error: no action specified" >expect &&
+ test_cmp expect output
'
cat > .git/config << EOF
@@ -504,17 +647,17 @@ ein.bahn=strasse
EOF
test_expect_success 'alternative GIT_CONFIG' '
- GIT_CONFIG=other-config git config --list >output &&
+ GIT_CONFIG=other-config git config ${mode_prefix}list >output &&
test_cmp expect output
'
test_expect_success 'alternative GIT_CONFIG (--file)' '
- git config --file other-config --list >output &&
+ git config ${mode_prefix}list --file other-config >output &&
test_cmp expect output
'
test_expect_success 'alternative GIT_CONFIG (--file=-)' '
- git config --file - --list <other-config >output &&
+ git config ${mode_prefix}list --file - <other-config >output &&
test_cmp expect output
'
@@ -523,10 +666,11 @@ test_expect_success 'setting a value in stdin is an error' '
'
test_expect_success 'editing stdin is an error' '
- test_must_fail git config --file - --edit
+ test_must_fail git config ${mode_prefix}edit --file -
'
test_expect_success 'refer config from subdirectory' '
+ test_when_finished "rm -r x" &&
mkdir x &&
test_cmp_config -C x strasse --file=../other-config --get ein.bahn
'
@@ -555,7 +699,7 @@ weird
EOF
test_expect_success 'rename section' '
- git config --rename-section branch.eins branch.zwei
+ git config ${mode_prefix}rename-section branch.eins branch.zwei
'
cat > expect << EOF
@@ -574,7 +718,7 @@ test_expect_success 'rename succeeded' '
'
test_expect_success 'rename non-existing section' '
- test_must_fail git config --rename-section \
+ test_must_fail git config ${mode_prefix}rename-section \
branch."world domination" branch.drei
'
@@ -583,7 +727,7 @@ test_expect_success 'rename succeeded' '
'
test_expect_success 'rename another section' '
- git config --rename-section branch."1 234 blabl/a" branch.drei
+ git config ${mode_prefix}rename-section branch."1 234 blabl/a" branch.drei
'
cat > expect << EOF
@@ -606,7 +750,7 @@ cat >> .git/config << EOF
EOF
test_expect_success 'rename a section with a var on the same line' '
- git config --rename-section branch.vier branch.zwei
+ git config ${mode_prefix}rename-section branch.vier branch.zwei
'
cat > expect << EOF
@@ -627,11 +771,11 @@ test_expect_success 'rename succeeded' '
'
test_expect_success 'renaming empty section name is rejected' '
- test_must_fail git config --rename-section branch.zwei ""
+ test_must_fail git config ${mode_prefix}rename-section branch.zwei ""
'
test_expect_success 'renaming to bogus section is rejected' '
- test_must_fail git config --rename-section branch.zwei "bogus name"
+ test_must_fail git config ${mode_prefix}rename-section branch.zwei "bogus name"
'
test_expect_success 'renaming a section with a long line' '
@@ -640,7 +784,7 @@ test_expect_success 'renaming a section with a long line' '
printf " c = d %1024s [a] e = f\\n" " " &&
printf "[a] g = h\\n"
} >y &&
- git config -f y --rename-section a xyz &&
+ git config ${mode_prefix}rename-section -f y a xyz &&
test_must_fail git config -f y b.e
'
@@ -650,7 +794,7 @@ test_expect_success 'renaming an embedded section with a long line' '
printf " c = d %1024s [a] [foo] e = f\\n" " " &&
printf "[a] g = h\\n"
} >y &&
- git config -f y --rename-section a xyz &&
+ git config ${mode_prefix}rename-section -f y a xyz &&
test_must_fail git config -f y foo.e
'
@@ -660,7 +804,7 @@ test_expect_success 'renaming a section with an overly-long line' '
printf " c = d %525000s e" " " &&
printf "[a] g = h\\n"
} >y &&
- test_must_fail git config -f y --rename-section a xyz 2>err &&
+ test_must_fail git config ${mode_prefix}rename-section -f y a xyz 2>err &&
grep "refusing to work with overly long line in .y. on line 2" err
'
@@ -669,7 +813,7 @@ cat >> .git/config << EOF
EOF
test_expect_success 'remove section' '
- git config --remove-section branch.zwei
+ git config ${mode_prefix}remove-section branch.zwei
'
cat > expect << EOF
@@ -693,16 +837,16 @@ EOF
test_expect_success 'section ending' '
rm -f .git/config &&
- git config gitcvs.enabled true &&
- git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
- git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
+ git config ${mode_set} gitcvs.enabled true &&
+ git config ${mode_set} gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
+ git config ${mode_set} gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
test_cmp expect .git/config
'
test_expect_success numbers '
- git config kilo.gram 1k &&
- git config mega.ton 1m &&
+ git config ${mode_set} kilo.gram 1k &&
+ git config ${mode_set} mega.ton 1m &&
echo 1024 >expect &&
echo 1048576 >>expect &&
git config --int --get kilo.gram >actual &&
@@ -711,34 +855,34 @@ test_expect_success numbers '
'
test_expect_success '--int is at least 64 bits' '
- git config giga.watts 121g &&
+ git config ${mode_set} giga.watts 121g &&
echo >expect &&
test_cmp_config 129922760704 --int --get giga.watts
'
test_expect_success 'invalid unit' '
- git config aninvalid.unit "1auto" &&
+ git config ${mode_set} aninvalid.unit "1auto" &&
test_cmp_config 1auto aninvalid.unit &&
test_must_fail git config --int --get aninvalid.unit 2>actual &&
- test_i18ngrep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual
+ test_grep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual
'
test_expect_success 'invalid unit boolean' '
- git config commit.gpgsign "1true" &&
+ git config ${mode_set} commit.gpgsign "1true" &&
test_cmp_config 1true commit.gpgsign &&
test_must_fail git config --bool --get commit.gpgsign 2>actual &&
- test_i18ngrep "bad boolean config value .1true. for .commit.gpgsign." actual
+ test_grep "bad boolean config value .1true. for .commit.gpgsign." actual
'
test_expect_success 'line number is reported correctly' '
printf "[bool]\n\tvar\n" >invalid &&
test_must_fail git config -f invalid --path bool.var 2>actual &&
- test_i18ngrep "line 2" actual
+ test_grep "line 2" actual
'
test_expect_success 'invalid stdin config' '
- echo "[broken" | test_must_fail git config --list --file - >output 2>&1 &&
- test_i18ngrep "bad config line 1 in standard input" output
+ echo "[broken" | test_must_fail git config ${mode_prefix}list --file - >output 2>&1 &&
+ test_grep "bad config line 1 in standard input" output
'
cat > expect << EOF
@@ -754,14 +898,14 @@ EOF
test_expect_success bool '
- git config bool.true1 01 &&
- git config bool.true2 -1 &&
- git config bool.true3 YeS &&
- git config bool.true4 true &&
- git config bool.false1 000 &&
- git config bool.false2 "" &&
- git config bool.false3 nO &&
- git config bool.false4 FALSE &&
+ git config ${mode_set} bool.true1 01 &&
+ git config ${mode_set} bool.true2 -1 &&
+ git config ${mode_set} bool.true3 YeS &&
+ git config ${mode_set} bool.true4 true &&
+ git config ${mode_set} bool.false1 000 &&
+ git config ${mode_set} bool.false2 "" &&
+ git config ${mode_set} bool.false3 nO &&
+ git config ${mode_set} bool.false4 FALSE &&
rm -f result &&
for i in 1 2 3 4
do
@@ -772,7 +916,7 @@ test_expect_success bool '
test_expect_success 'invalid bool (--get)' '
- git config bool.nobool foobar &&
+ git config ${mode_set} bool.nobool foobar &&
test_must_fail git config --bool --get bool.nobool'
test_expect_success 'invalid bool (set)' '
@@ -919,7 +1063,7 @@ test_expect_success !MINGW 'get --path copes with unset $HOME' '
git config --get --path path.normal >>result &&
git config --get --path path.trailingtilde >>result
) &&
- test_i18ngrep "[Ff]ailed to expand.*~/" msg &&
+ test_grep "[Ff]ailed to expand.*~/" msg &&
test_cmp expect result
'
@@ -961,7 +1105,7 @@ test_expect_success 'get --expiry-date' '
test_expect_success 'get --type=color' '
rm .git/config &&
- git config foo.color "red" &&
+ git config ${mode_set} foo.color "red" &&
git config --get --type=color foo.color >actual.raw &&
test_decode_color <actual.raw >actual &&
echo "<RED>" >expect &&
@@ -986,7 +1130,7 @@ test_expect_success 'get --type=color barfs on non-color' '
test_expect_success 'set --type=color barfs on non-color' '
test_must_fail git config --type=color foo.color "not-a-color" 2>error &&
- test_i18ngrep "cannot parse color" error
+ test_grep "cannot parse color" error
'
cat > expect << EOF
@@ -998,18 +1142,18 @@ cat > expect << EOF
EOF
test_expect_success 'quoting' '
rm -f .git/config &&
- git config quote.leading " test" &&
- git config quote.ending "test " &&
- git config quote.semicolon "test;test" &&
- git config quote.hash "test#test" &&
+ git config ${mode_set} quote.leading " test" &&
+ git config ${mode_set} quote.ending "test " &&
+ git config ${mode_set} quote.semicolon "test;test" &&
+ git config ${mode_set} quote.hash "test#test" &&
test_cmp expect .git/config
'
test_expect_success 'key with newline' '
- test_must_fail git config "key.with
+ test_must_fail git config ${mode_get} "key.with
newline" 123'
-test_expect_success 'value with newline' 'git config key.sub value.with\\\
+test_expect_success 'value with newline' 'git config ${mode_set} key.sub value.with\\\
newline'
cat > .git/config <<\EOF
@@ -1029,7 +1173,7 @@ section.quotecont=cont;inued
EOF
test_expect_success 'value continued on next line' '
- git config --list > result &&
+ git config ${mode_prefix}list > result &&
test_cmp expect result
'
@@ -1053,25 +1197,42 @@ Qsection.sub=section.val4
Qsection.sub=section.val5Q
EOF
test_expect_success '--null --list' '
- git config --null --list >result.raw &&
+ git config ${mode_prefix}list --null >result.raw &&
nul_to_q <result.raw >result &&
echo >>result &&
test_cmp expect result
'
test_expect_success '--null --get-regexp' '
- git config --null --get-regexp "val[0-9]" >result.raw &&
+ git config ${mode_get_regexp} --null "val[0-9]" >result.raw &&
nul_to_q <result.raw >result &&
echo >>result &&
test_cmp expect result
'
-test_expect_success 'inner whitespace kept verbatim' '
- git config section.val "foo bar" &&
- test_cmp_config "foo bar" section.val
+test_expect_success 'inner whitespace kept verbatim, spaces only' '
+ echo "foo bar" >expect &&
+ git config ${mode_set} section.val "foo bar" &&
+ git config ${mode_get} section.val >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' '
+ echo "fooQQbar" | q_to_tab >expect &&
+ git config ${mode_set} section.val "$(cat expect)" &&
+ git config ${mode_get} section.val >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' '
+ echo "foo Q bar" | q_to_tab >expect &&
+ git config ${mode_set} section.val "$(cat expect)" &&
+ git config ${mode_get} section.val >actual &&
+ test_cmp expect actual
'
test_expect_success SYMLINKS 'symlinked configuration' '
+ test_when_finished "rm myconfig" &&
ln -s notyet myconfig &&
git config --file=myconfig test.frotz nitfol &&
test -h myconfig &&
@@ -1092,21 +1253,27 @@ test_expect_success SYMLINKS 'symlinked configuration' '
'
test_expect_success SYMLINKS 'symlink to nonexistent configuration' '
+ test_when_finished "rm linktonada linktolinktonada" &&
ln -s doesnotexist linktonada &&
ln -s linktonada linktolinktonada &&
- test_must_fail git config --file=linktonada --list &&
- test_must_fail git config --file=linktolinktonada --list
+ test_must_fail git config ${mode_prefix}list --file=linktonada &&
+ test_must_fail git config ${mode_prefix}list --file=linktolinktonada
'
-test_expect_success 'check split_cmdline return' "
- git config alias.split-cmdline-fix 'echo \"' &&
- test_must_fail git split-cmdline-fix &&
- echo foo > foo &&
- git add foo &&
- git commit -m 'initial commit' &&
- git config branch.main.mergeoptions 'echo \"' &&
- test_must_fail git merge main
-"
+test_expect_success 'check split_cmdline return' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config ${mode_set} alias.split-cmdline-fix "echo \"" &&
+ test_must_fail git split-cmdline-fix &&
+ echo foo >foo &&
+ git add foo &&
+ git commit -m "initial commit" &&
+ git config ${mode_set} branch.main.mergeoptions "echo \"" &&
+ test_must_fail git merge main
+ )
+'
test_expect_success 'git -c "key=value" support' '
cat >expect <<-\EOF &&
@@ -1135,18 +1302,18 @@ test_expect_success 'git -c can represent empty string' '
'
test_expect_success 'key sanity-checking' '
- test_must_fail git config foo=bar &&
- test_must_fail git config foo=.bar &&
- test_must_fail git config foo.ba=r &&
- test_must_fail git config foo.1bar &&
- test_must_fail git config foo."ba
+ test_must_fail git config ${mode_get} foo=bar &&
+ test_must_fail git config ${mode_get} foo=.bar &&
+ test_must_fail git config ${mode_get} foo.ba=r &&
+ test_must_fail git config ${mode_get} foo.1bar &&
+ test_must_fail git config ${mode_get} foo."ba
z".bar &&
- test_must_fail git config . false &&
- test_must_fail git config .foo false &&
- test_must_fail git config foo. false &&
- test_must_fail git config .foo. false &&
- git config foo.bar true &&
- git config foo."ba =z".bar false
+ test_must_fail git config ${mode_set} . false &&
+ test_must_fail git config ${mode_set} .foo false &&
+ test_must_fail git config ${mode_set} foo. false &&
+ test_must_fail git config ${mode_set} .foo. false &&
+ git config ${mode_set} foo.bar true &&
+ git config ${mode_set} foo."ba =z".bar false
'
test_expect_success 'git -c works with aliases of builtins' '
@@ -1157,10 +1324,16 @@ test_expect_success 'git -c works with aliases of builtins' '
'
test_expect_success 'aliases can be CamelCased' '
- test_config alias.CamelCased "rev-parse HEAD" &&
- git CamelCased >out &&
- git rev-parse HEAD >expect &&
- test_cmp expect out
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ git config alias.CamelCased "rev-parse HEAD" &&
+ git CamelCased >out &&
+ git rev-parse HEAD >expect &&
+ test_cmp expect out
+ )
'
test_expect_success 'git -c does not split values on equals' '
@@ -1182,7 +1355,7 @@ test_expect_success 'git -c complains about empty key and value' '
'
test_expect_success 'multiple git -c appends config' '
- test_config alias.x "!git -c x.two=2 config --get-regexp ^x\.*" &&
+ test_config alias.x "!git -c x.two=2 config ${mode_get_regexp} ^x\.*" &&
cat >expect <<-\EOF &&
x.one 1
x.two 2
@@ -1341,14 +1514,14 @@ do
done
test_expect_success 'git -c is not confused by empty environment' '
- GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
+ GIT_CONFIG_PARAMETERS="" git -c x.one=1 config ${mode_prefix}list
'
test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' '
v="${SQ}key.one=foo${SQ}" &&
v="$v ${SQ}key.two=bar${SQ}" &&
v="$v ${SQ}key.ambiguous=section.whatever=value${SQ}" &&
- GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
+ GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF &&
key.one foo
key.two bar
@@ -1361,7 +1534,7 @@ test_expect_success 'GIT_CONFIG_PARAMETERS handles new-style entries' '
v="${SQ}key.one${SQ}=${SQ}foo${SQ}" &&
v="$v ${SQ}key.two${SQ}=${SQ}bar${SQ}" &&
v="$v ${SQ}key.ambiguous=section.whatever${SQ}=${SQ}value${SQ}" &&
- GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
+ GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF &&
key.one foo
key.two bar
@@ -1375,7 +1548,7 @@ test_expect_success 'old and new-style entries can mix' '
v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" &&
v="$v ${SQ}key.oldtwo=oldbar${SQ}" &&
v="$v ${SQ}key.newtwo${SQ}=${SQ}newbar${SQ}" &&
- GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
+ GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF &&
key.oldone oldfoo
key.newone newfoo
@@ -1388,7 +1561,7 @@ test_expect_success 'old and new-style entries can mix' '
test_expect_success 'old and new bools with ambiguous subsection' '
v="${SQ}key.with=equals.oldbool${SQ}" &&
v="$v ${SQ}key.with=equals.newbool${SQ}=" &&
- GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
+ GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF &&
key.with equals.oldbool
key.with=equals.newbool
@@ -1402,7 +1575,7 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
env.two two
EOF
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \
- git config --get-regexp "env.*" >actual &&
+ git config ${mode_get_regexp} "env.*" >actual &&
test_cmp expect actual &&
cat >expect <<-EOF &&
@@ -1410,12 +1583,12 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
env.two two
EOF
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \
- git config --get-regexp "env.*" >actual &&
+ git config ${mode_get_regexp} "env.*" >actual &&
test_cmp expect actual &&
test_must_fail env \
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \
- git config --get-regexp "env.*"
+ git config ${mode_get_regexp} "env.*"
'
test_expect_success 'git --config-env=key=envvar support' '
@@ -1447,12 +1620,12 @@ test_expect_success 'git --config-env with missing value' '
test_expect_success 'git --config-env fails with invalid parameters' '
test_must_fail git --config-env=foo.flag config --bool foo.flag 2>error &&
- test_i18ngrep "invalid config format: foo.flag" error &&
+ test_grep "invalid config format: foo.flag" error &&
test_must_fail git --config-env=foo.flag= config --bool foo.flag 2>error &&
- test_i18ngrep "missing environment variable name for configuration ${SQ}foo.flag${SQ}" error &&
+ test_grep "missing environment variable name for configuration ${SQ}foo.flag${SQ}" error &&
sane_unset NONEXISTENT &&
test_must_fail git --config-env=foo.flag=NONEXISTENT config --bool foo.flag 2>error &&
- test_i18ngrep "missing environment variable ${SQ}NONEXISTENT${SQ} for configuration ${SQ}foo.flag${SQ}" error
+ test_grep "missing environment variable ${SQ}NONEXISTENT${SQ} for configuration ${SQ}foo.flag${SQ}" error
'
test_expect_success 'git -c and --config-env work together' '
@@ -1463,7 +1636,7 @@ test_expect_success 'git -c and --config-env work together' '
ENVVAR=env-value git \
-c bar.cmd=cmd-value \
--config-env=bar.env=ENVVAR \
- config --get-regexp "^bar.*" >actual &&
+ config ${mode_get_regexp} "^bar.*" >actual &&
test_cmp expect actual
'
@@ -1491,7 +1664,7 @@ test_expect_success 'git config handles environment config pairs' '
GIT_CONFIG_COUNT=2 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="bar" \
- git config --get-regexp "pair.*" >actual &&
+ git config ${mode_get_regexp} "pair.*" >actual &&
cat >expect <<-EOF &&
pair.one foo
pair.two bar
@@ -1501,7 +1674,7 @@ test_expect_success 'git config handles environment config pairs' '
test_expect_success 'git config ignores pairs without count' '
test_must_fail env GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one 2>error &&
+ git config ${mode_get} pair.one 2>error &&
test_must_be_empty error
'
@@ -1509,7 +1682,7 @@ 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 2>error &&
+ git config ${mode_get_regexp} "pair.*" >actual 2>error &&
cat >expect <<-EOF &&
pair.one value
EOF
@@ -1520,43 +1693,43 @@ test_expect_success 'git config ignores pairs exceeding count' '
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 2>error &&
+ git config ${mode_get} 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 2>error &&
+ git config ${mode_get} pair.one 2>error &&
test_must_be_empty error
'
test_expect_success 'git config fails with invalid count' '
- test_must_fail env GIT_CONFIG_COUNT=10a git config --list 2>error &&
- test_i18ngrep "bogus count" error &&
- test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config --list 2>error &&
- test_i18ngrep "too many entries" error
+ test_must_fail env GIT_CONFIG_COUNT=10a git config ${mode_prefix}list 2>error &&
+ test_grep "bogus count" error &&
+ test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config ${mode_prefix}list 2>error &&
+ test_grep "too many entries" error
'
test_expect_success 'git config fails with missing config key' '
test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_VALUE_0="value" \
- git config --list 2>error &&
- test_i18ngrep "missing config key" error
+ git config ${mode_prefix}list 2>error &&
+ test_grep "missing config key" error
'
test_expect_success 'git config fails with missing config value' '
test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0="pair.one" \
- git config --list 2>error &&
- test_i18ngrep "missing config value" error
+ git config ${mode_prefix}list 2>error &&
+ test_grep "missing config value" error
'
test_expect_success 'git config fails with invalid config pair key' '
test_must_fail env GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0= GIT_CONFIG_VALUE_0=value \
- git config --list &&
+ git config ${mode_prefix}list &&
test_must_fail env GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=missing-section GIT_CONFIG_VALUE_0=value \
- git config --list
+ git config ${mode_prefix}list
'
test_expect_success 'environment overrides config file' '
@@ -1566,7 +1739,7 @@ test_expect_success 'environment overrides config file' '
one = value
EOF
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=override \
- git config pair.one >actual &&
+ git config ${mode_get} pair.one >actual &&
cat >expect <<-EOF &&
override
EOF
@@ -1576,7 +1749,7 @@ test_expect_success 'environment overrides config file' '
test_expect_success 'GIT_CONFIG_PARAMETERS overrides environment config' '
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \
GIT_CONFIG_PARAMETERS="${SQ}pair.one=override${SQ}" \
- git config pair.one >actual &&
+ git config ${mode_get} pair.one >actual &&
cat >expect <<-EOF &&
override
EOF
@@ -1595,8 +1768,8 @@ test_expect_success 'command line overrides environment config' '
test_expect_success 'git config --edit works' '
git config -f tmp test.value no &&
echo test.value=yes >expect &&
- GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit &&
- git config -f tmp --list >actual &&
+ GIT_EDITOR="echo [test]value=yes >" git config ${mode_prefix}edit -f tmp &&
+ git config ${mode_prefix}list -f tmp >actual &&
test_cmp expect actual
'
@@ -1604,8 +1777,8 @@ test_expect_success 'git config --edit respects core.editor' '
git config -f tmp test.value no &&
echo test.value=yes >expect &&
test_config core.editor "echo [test]value=yes >" &&
- git config -f tmp --edit &&
- git config -f tmp --list >actual &&
+ git config ${mode_prefix}edit -f tmp &&
+ git config ${mode_prefix}list -f tmp >actual &&
test_cmp expect actual
'
@@ -1617,7 +1790,7 @@ test_expect_success 'barf on syntax error' '
key garbage
EOF
test_must_fail git config --get section.key 2>error &&
- test_i18ngrep " line 3 " error
+ test_grep " line 3 " error
'
test_expect_success 'barf on incomplete section header' '
@@ -1627,7 +1800,7 @@ test_expect_success 'barf on incomplete section header' '
key = value
EOF
test_must_fail git config --get section.key 2>error &&
- test_i18ngrep " line 2 " error
+ test_grep " line 2 " error
'
test_expect_success 'barf on incomplete string' '
@@ -1637,7 +1810,7 @@ test_expect_success 'barf on incomplete string' '
key = "value string
EOF
test_must_fail git config --get section.key 2>error &&
- test_i18ngrep " line 3 " error
+ test_grep " line 3 " error
'
test_expect_success 'urlmatch' '
@@ -1651,20 +1824,28 @@ test_expect_success 'urlmatch' '
test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual &&
test_must_be_empty actual &&
+ test_expect_code 1 git config get --url=https://good.example.com --bool doesnt.exist >actual &&
+ test_must_be_empty actual &&
echo true >expect &&
git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual &&
test_cmp expect actual &&
+ git config get --bool --url=https://good.example.com http.SSLverify >actual &&
+ test_cmp expect actual &&
echo false >expect &&
git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual &&
test_cmp expect actual &&
+ git config get --bool --url=https://weak.example.com http.sslverify >actual &&
+ test_cmp expect actual &&
{
echo http.cookiefile /tmp/cookie.txt &&
echo http.sslverify false
} >expect &&
git config --get-urlmatch HTTP https://weak.example.com >actual &&
+ test_cmp expect actual &&
+ git config get --url=https://weak.example.com HTTP >actual &&
test_cmp expect actual
'
@@ -1680,6 +1861,8 @@ test_expect_success 'urlmatch with --show-scope' '
local http.sslverify false
EOF
git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual &&
+ test_cmp expect actual &&
+ git config get --url=https://weak.example.com --show-scope HTTP >actual &&
test_cmp expect actual
'
@@ -1712,45 +1895,67 @@ test_expect_success 'urlmatch favors more specific URLs' '
echo http.cookiefile /tmp/root.txt >expect &&
git config --get-urlmatch HTTP https://example.com >actual &&
test_cmp expect actual &&
+ git config get --url=https://example.com HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://example.com/subdirectory >actual &&
test_cmp expect actual &&
+ git config get --url=https://example.com/subdirectory HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual &&
test_cmp expect actual &&
+ git config get --url=https://example.com/subdirectory/nested HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/user.txt >expect &&
git config --get-urlmatch HTTP https://user@example.com/ >actual &&
test_cmp expect actual &&
+ git config get --url=https://user@example.com/ HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual &&
test_cmp expect actual &&
+ git config get --url=https://averylonguser@example.com/subdirectory HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/preceding.txt >expect &&
git config --get-urlmatch HTTP https://preceding.example.com >actual &&
test_cmp expect actual &&
+ git config get --url=https://preceding.example.com HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/wildcard.txt >expect &&
git config --get-urlmatch HTTP https://wildcard.example.com >actual &&
test_cmp expect actual &&
+ git config get --url=https://wildcard.example.com HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/sub.txt >expect &&
git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual &&
test_cmp expect actual &&
+ git config get --url=https://sub.example.com/wildcardwithsubdomain HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/trailing.txt >expect &&
git config --get-urlmatch HTTP https://trailing.example.com >actual &&
test_cmp expect actual &&
+ git config get --url=https://trailing.example.com HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/sub.txt >expect &&
git config --get-urlmatch HTTP https://user@sub.example.com >actual &&
test_cmp expect actual &&
+ git config get --url=https://user@sub.example.com HTTP >actual &&
+ test_cmp expect actual &&
echo http.cookiefile /tmp/multiwildcard.txt >expect &&
git config --get-urlmatch HTTP https://wildcard.example.org >actual &&
+ test_cmp expect actual &&
+ git config get --url=https://wildcard.example.org HTTP >actual &&
test_cmp expect actual
'
@@ -1817,7 +2022,7 @@ test_expect_success '--unset last key removes section (except if commented)' '
# please be careful when you update the above variable
EOF
- git config --unset section.key &&
+ git config ${mode_unset} section.key &&
test_cmp expect .git/config &&
cat >.git/config <<-\EOF &&
@@ -1830,7 +2035,7 @@ test_expect_success '--unset last key removes section (except if commented)' '
[next-section]
EOF
- git config --unset section.key &&
+ git config ${mode_unset} section.key &&
test_cmp expect .git/config &&
q_to_tab >.git/config <<-\EOF &&
@@ -1840,7 +2045,7 @@ test_expect_success '--unset last key removes section (except if commented)' '
[two]
key = true
EOF
- git config --unset two.key &&
+ git config ${mode_unset} two.key &&
! grep two .git/config &&
q_to_tab >.git/config <<-\EOF &&
@@ -1850,7 +2055,7 @@ test_expect_success '--unset last key removes section (except if commented)' '
[one]
key = true
EOF
- git config --unset-all one.key &&
+ git config ${mode_unset_all} one.key &&
test_line_count = 0 .git/config &&
q_to_tab >.git/config <<-\EOF &&
@@ -1860,7 +2065,7 @@ test_expect_success '--unset last key removes section (except if commented)' '
[two]
Qkey = true
EOF
- git config --unset two.key &&
+ git config ${mode_unset} two.key &&
grep two .git/config &&
q_to_tab >.git/config <<-\EOF &&
@@ -1872,8 +2077,8 @@ test_expect_success '--unset last key removes section (except if commented)' '
[TWO "subsection"]
[one]
EOF
- git config --unset two.subsection.key &&
- test "not [two subsection]" = "$(git config one.key)" &&
+ git config ${mode_unset} two.subsection.key &&
+ test "not [two subsection]" = "$(git config ${mode_get} one.key)" &&
test_line_count = 3 .git/config
'
@@ -1884,7 +2089,7 @@ test_expect_success '--unset-all removes section if empty & uncommented' '
key = value2
EOF
- git config --unset-all section.key &&
+ git config ${mode_unset_all} section.key &&
test_line_count = 0 .git/config
'
@@ -1907,7 +2112,7 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' '
git config imap.pass Hunter2 &&
perl -e \
"die q(badset) if ((stat(q(.git/config)))[2] & 07777) != 0600" &&
- git config --rename-section imap pop &&
+ git config ${mode_prefix}rename-section imap pop &&
perl -e \
"die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600"
'
@@ -1956,7 +2161,7 @@ test_expect_success '--show-origin with --list' '
command line: user.cmdline=true
EOF
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.environ GIT_CONFIG_VALUE_0=true\
- git -c user.cmdline=true config --list --show-origin >output &&
+ git -c user.cmdline=true config ${mode_prefix}list --show-origin >output &&
test_cmp expect output
'
@@ -1973,7 +2178,7 @@ test_expect_success '--show-origin with --list --null' '
includeQcommand line:Quser.cmdline
trueQ
EOF
- git -c user.cmdline=true config --null --list --show-origin >output.raw &&
+ git -c user.cmdline=true config ${mode_prefix}list --null --show-origin >output.raw &&
nul_to_q <output.raw >output &&
# The here-doc above adds a newline that the --null output would not
# include. Add it here to make the two comparable.
@@ -1987,7 +2192,7 @@ test_expect_success '--show-origin with single file' '
file:.git/config user.override=local
file:.git/config include.path=../include/relative.include
EOF
- git config --local --list --show-origin >output &&
+ git config ${mode_prefix}list --local --show-origin >output &&
test_cmp expect output
'
@@ -1996,7 +2201,7 @@ test_expect_success '--show-origin with --get-regexp' '
file:$HOME/.gitconfig user.global true
file:.git/config user.local true
EOF
- git config --show-origin --get-regexp "user\.[g|l].*" >output &&
+ git config ${mode_get_regexp} --show-origin "user\.[g|l].*" >output &&
test_cmp expect output
'
@@ -2004,16 +2209,16 @@ test_expect_success '--show-origin getting a single key' '
cat >expect <<-\EOF &&
file:.git/config local
EOF
- git config --show-origin user.override >output &&
+ git config ${mode_get} --show-origin user.override >output &&
test_cmp expect output
'
test_expect_success 'set up custom config file' '
- CUSTOM_CONFIG_FILE="custom.conf" &&
- cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
+ cat >"custom.conf" <<-\EOF &&
[user]
custom = true
EOF
+ CUSTOM_CONFIG_FILE="$(test-tool path-utils real_path custom.conf)"
'
test_expect_success !MINGW 'set up custom config file with special name characters' '
@@ -2025,7 +2230,7 @@ test_expect_success !MINGW '--show-origin escape special file name characters' '
cat >expect <<-\EOF &&
file:"file\" (dq) and spaces.conf" user.custom=true
EOF
- git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
+ git config ${mode_prefix}list --file "$WEIRDLY_NAMED_FILE" --show-origin >output &&
test_cmp expect output
'
@@ -2033,7 +2238,7 @@ test_expect_success '--show-origin stdin' '
cat >expect <<-\EOF &&
standard input: user.custom=true
EOF
- git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output &&
+ git config ${mode_prefix}list --file - --show-origin <"$CUSTOM_CONFIG_FILE" >output &&
test_cmp expect output
'
@@ -2052,22 +2257,33 @@ test_expect_success '--show-origin stdin with file include' '
'
test_expect_success '--show-origin blob' '
- blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
- cat >expect <<-EOF &&
- blob:$blob user.custom=true
- EOF
- git config --blob=$blob --show-origin --list >output &&
- test_cmp expect output
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
+ cat >expect <<-EOF &&
+ blob:$blob user.custom=true
+ EOF
+ git config ${mode_prefix}list --blob=$blob --show-origin >output &&
+ test_cmp expect output
+ )
'
test_expect_success '--show-origin blob ref' '
- cat >expect <<-\EOF &&
- blob:main:custom.conf user.custom=true
- EOF
- git add "$CUSTOM_CONFIG_FILE" &&
- git commit -m "new config file" &&
- git config --blob=main:"$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
- test_cmp expect output
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ cat >expect <<-\EOF &&
+ blob:main:custom.conf user.custom=true
+ EOF
+ cp "$CUSTOM_CONFIG_FILE" custom.conf &&
+ git add custom.conf &&
+ git commit -m "new config file" &&
+ git config ${mode_prefix}list --blob=main:custom.conf --show-origin >output &&
+ test_cmp expect output
+ )
'
test_expect_success '--show-origin with --default' '
@@ -2091,13 +2307,14 @@ test_expect_success '--show-scope with --list' '
worktree user.worktree=true
command user.cmdline=true
EOF
+ test_when_finished "git worktree remove wt1" &&
git worktree add wt1 &&
# We need these to test for worktree scope, but outside of this
# test, this is just noise
test_config core.repositoryformatversion 1 &&
test_config extensions.worktreeConfig true &&
git config --worktree user.worktree true &&
- git -c user.cmdline=true config --list --show-scope >output &&
+ git -c user.cmdline=true config ${mode_prefix}list --show-scope >output &&
test_cmp expect output
'
@@ -2106,7 +2323,7 @@ test_expect_success !MINGW '--show-scope with --blob' '
cat >expect <<-EOF &&
command user.custom=true
EOF
- git config --blob=$blob --show-scope --list >output &&
+ git config ${mode_prefix}list --blob=$blob --show-scope >output &&
test_cmp expect output
'
@@ -2116,7 +2333,7 @@ test_expect_success '--show-scope with --local' '
local user.override=local
local include.path=../include/relative.include
EOF
- git config --local --list --show-scope >output &&
+ git config ${mode_prefix}list --local --show-scope >output &&
test_cmp expect output
'
@@ -2124,7 +2341,7 @@ test_expect_success '--show-scope getting a single value' '
cat >expect <<-\EOF &&
local true
EOF
- git config --show-scope --get user.local >output &&
+ git config ${mode_get} --show-scope user.local >output &&
test_cmp expect output
'
@@ -2140,7 +2357,7 @@ test_expect_success '--show-scope with --show-origin' '
local file:.git/../include/relative.include user.relative=include
command command line: user.cmdline=true
EOF
- git -c user.cmdline=true config --list --show-origin --show-scope >output &&
+ git -c user.cmdline=true config ${mode_prefix}list --show-origin --show-scope >output &&
test_cmp expect output
'
@@ -2181,7 +2398,7 @@ test_expect_success 'override global and system config' '
global home.config=true
local local.config=true
EOF
- git config --show-scope --list >output &&
+ git config ${mode_prefix}list --show-scope >output &&
test_cmp expect output &&
cat >expect <<-EOF &&
@@ -2190,20 +2407,20 @@ test_expect_success 'override global and system config' '
local local.config=true
EOF
GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=custom-system-config GIT_CONFIG_GLOBAL=custom-global-config \
- git config --show-scope --list >output &&
+ git config ${mode_prefix}list --show-scope >output &&
test_cmp expect output &&
cat >expect <<-EOF &&
local local.config=true
EOF
GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_GLOBAL=/dev/null \
- git config --show-scope --list >output &&
+ git config ${mode_prefix}list --show-scope >output &&
test_cmp expect output
'
test_expect_success 'override global and system config with missing file' '
- test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list &&
- test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list &&
+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config ${mode_prefix}list --global &&
+ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config ${mode_prefix}list --system &&
GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
'
@@ -2266,17 +2483,17 @@ test_expect_success 'identical mixed --type specifiers are allowed' '
test_expect_success 'non-identical modern --type specifiers are not allowed' '
test_must_fail git config --type=int --type=bool section.big 2>error &&
- test_i18ngrep "only one type at a time" error
+ test_grep "only one type at a time" error
'
test_expect_success 'non-identical legacy --type specifiers are not allowed' '
test_must_fail git config --int --bool section.big 2>error &&
- test_i18ngrep "only one type at a time" error
+ test_grep "only one type at a time" error
'
test_expect_success 'non-identical mixed --type specifiers are not allowed' '
test_must_fail git config --type=int --bool section.big 2>error &&
- test_i18ngrep "only one type at a time" error
+ test_grep "only one type at a time" error
'
test_expect_success '--type allows valid type specifiers' '
@@ -2293,7 +2510,7 @@ test_expect_success 'unset type specifiers may be reset to conflicting ones' '
test_expect_success '--type rejects unknown specifiers' '
test_must_fail git config --type=nonsense section.foo 2>error &&
- test_i18ngrep "unrecognized --type argument" error
+ test_grep "unrecognized --type argument" error
'
test_expect_success '--type=int requires at least one digit' '
@@ -2319,7 +2536,7 @@ test_expect_success '--replace-all does not invent newlines' '
[abc]
Qkey = b
EOF
- git config --replace-all abc.key b &&
+ git config ${mode_replace_all} abc.key b &&
test_cmp expect .git/config
'
@@ -2330,7 +2547,7 @@ test_expect_success 'set all config with value-pattern' '
# no match => add new entry
cp initial config &&
git config --file=config abc.key two a+ &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-\EOF &&
abc.key=one
abc.key=two
@@ -2339,11 +2556,11 @@ test_expect_success 'set all config with value-pattern' '
# multiple matches => failure
test_must_fail git config --file=config abc.key three o+ 2>err &&
- test_i18ngrep "has multiple values" err &&
+ test_grep "has multiple values" err &&
# multiple values, no match => add
git config --file=config abc.key three a+ &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-\EOF &&
abc.key=one
abc.key=two
@@ -2353,7 +2570,7 @@ test_expect_success 'set all config with value-pattern' '
# single match => replace
git config --file=config abc.key four h+ &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-\EOF &&
abc.key=one
abc.key=two
@@ -2368,7 +2585,7 @@ test_expect_success '--replace-all and value-pattern' '
git config --file=config --add abc.key two &&
git config --file=config --add abc.key three &&
git config --file=config --replace-all abc.key four "o+" &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-\EOF &&
abc.key=four
abc.key=three
@@ -2384,20 +2601,20 @@ test_expect_success 'refuse --fixed-value for incompatible actions' '
test_must_fail git config --file=config --fixed-value --add dev.null bogus &&
test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus &&
test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus &&
- test_must_fail git config --file=config --fixed-value --rename-section dev null &&
- test_must_fail git config --file=config --fixed-value --remove-section dev &&
- test_must_fail git config --file=config --fixed-value --list &&
+ test_must_fail git config ${mode_prefix}rename-section --file=config --fixed-value dev null &&
+ test_must_fail git config ${mode_prefix}remove-section --file=config --fixed-value dev &&
+ test_must_fail git config ${mode_prefix}list --file=config --fixed-value &&
test_must_fail git config --file=config --fixed-value --get-color dev.null &&
test_must_fail git config --file=config --fixed-value --get-colorbool dev.null &&
# These modes complain when --fixed-value has no value-pattern
- test_must_fail git config --file=config --fixed-value dev.null bogus &&
- test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus &&
- test_must_fail git config --file=config --fixed-value --get dev.null &&
- test_must_fail git config --file=config --fixed-value --get-all dev.null &&
- test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" &&
- test_must_fail git config --file=config --fixed-value --unset dev.null &&
- test_must_fail git config --file=config --fixed-value --unset-all dev.null
+ test_must_fail git config ${mode_set} --file=config --fixed-value dev.null bogus &&
+ test_must_fail git config ${mode_replace_all} --file=config --fixed-value dev.null bogus &&
+ test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null &&
+ test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null &&
+ test_must_fail git config ${mode_get_regexp} --file=config --fixed-value "dev.*" &&
+ test_must_fail git config ${mode_unset} --file=config --fixed-value dev.null &&
+ test_must_fail git config ${mode_unset_all} --file=config --fixed-value dev.null
'
test_expect_success '--fixed-value uses exact string matching' '
@@ -2407,7 +2624,7 @@ test_expect_success '--fixed-value uses exact string matching' '
cp initial config &&
git config --file=config fixed.test bogus "$META" &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-EOF &&
fixed.test=$META
fixed.test=bogus
@@ -2416,7 +2633,7 @@ test_expect_success '--fixed-value uses exact string matching' '
cp initial config &&
git config --file=config --fixed-value fixed.test bogus "$META" &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-\EOF &&
fixed.test=bogus
EOF
@@ -2425,16 +2642,21 @@ test_expect_success '--fixed-value uses exact string matching' '
cp initial config &&
test_must_fail git config --file=config --unset fixed.test "$META" &&
git config --file=config --fixed-value --unset fixed.test "$META" &&
- test_must_fail git config --file=config fixed.test &&
+ test_must_fail git config ${mode_get} --file=config fixed.test &&
+
+ cp initial config &&
+ test_must_fail git config unset --file=config --value="$META" fixed.test &&
+ git config unset --file=config --fixed-value --value="$META" fixed.test &&
+ test_must_fail git config ${mode_get} --file=config fixed.test &&
cp initial config &&
test_must_fail git config --file=config --unset-all fixed.test "$META" &&
git config --file=config --fixed-value --unset-all fixed.test "$META" &&
- test_must_fail git config --file=config fixed.test &&
+ test_must_fail git config ${mode_get} --file=config fixed.test &&
cp initial config &&
- git config --file=config --replace-all fixed.test bogus "$META" &&
- git config --file=config --list >actual &&
+ git config --file=config fixed.test bogus "$META" &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-EOF &&
fixed.test=$META
fixed.test=bogus
@@ -2442,7 +2664,7 @@ test_expect_success '--fixed-value uses exact string matching' '
test_cmp expect actual &&
git config --file=config --fixed-value --replace-all fixed.test bogus "$META" &&
- git config --file=config --list >actual &&
+ git config ${mode_prefix}list --file=config >actual &&
cat >expect <<-EOF &&
fixed.test=bogus
fixed.test=bogus
@@ -2457,21 +2679,39 @@ test_expect_success '--get and --get-all with --fixed-value' '
git config --file=config --add fixed.test "$META" &&
git config --file=config --get fixed.test bogus &&
+ git config get --file=config --value=bogus fixed.test &&
test_must_fail git config --file=config --get fixed.test "$META" &&
+ test_must_fail git config get --file=config --value="$META" fixed.test &&
git config --file=config --get --fixed-value fixed.test "$META" &&
+ git config get --file=config --fixed-value --value="$META" fixed.test &&
test_must_fail git config --file=config --get --fixed-value fixed.test non-existent &&
git config --file=config --get-all fixed.test bogus &&
+ git config get --all --file=config --value=bogus fixed.test &&
test_must_fail git config --file=config --get-all fixed.test "$META" &&
+ test_must_fail git config get --all --file=config --value="$META" fixed.test &&
git config --file=config --get-all --fixed-value fixed.test "$META" &&
+ git config get --all --file=config --value="$META" --fixed-value fixed.test &&
test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent &&
git config --file=config --get-regexp fixed+ bogus &&
+ git config get --regexp --file=config --value=bogus fixed+ &&
test_must_fail git config --file=config --get-regexp fixed+ "$META" &&
+ test_must_fail git config get --regexp --file=config --value="$META" fixed+ &&
git config --file=config --get-regexp --fixed-value fixed+ "$META" &&
+ git config get --regexp --file=config --fixed-value --value="$META" fixed+ &&
test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent
'
+test_expect_success '--fixed-value with value-less configuration' '
+ test_when_finished rm -f config &&
+ cat >config <<-\EOF &&
+ [section]
+ key
+ EOF
+ git config --file=config --fixed-value section.key value pattern
+'
+
test_expect_success 'includeIf.hasconfig:remote.*.url' '
git init hasremoteurlTest &&
test_when_finished "rm -rf hasremoteurlTest" &&
@@ -2590,4 +2830,25 @@ test_expect_success 'includeIf.hasconfig:remote.*.url forbids remote url in such
grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err
'
+test_expect_success 'negated mode causes failure' '
+ test_must_fail git config --no-get 2>err &&
+ grep "unknown option \`no-get${SQ}" err
+'
+
+test_expect_success 'specifying multiple modes causes failure' '
+ cat >expect <<-EOF &&
+ error: options ${SQ}--get-all${SQ} and ${SQ}--get${SQ} cannot be used together
+ EOF
+ test_must_fail git config --get --get-all 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'writing to stdin is rejected' '
+ echo "fatal: writing to stdin is not supported" >expect &&
+ test_must_fail git config ${mode_set} --file - foo.bar baz 2>err &&
+ test_cmp expect err
+'
+
+done
+
test_done
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index e5a0d65caa..630a47af21 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -9,7 +9,6 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_CREATE_REPO_NO_TEMPLATE=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Remove a default ACL from the test dir if possible.
@@ -52,7 +51,7 @@ test_expect_success 'shared=all' '
test 2 = $(git config core.sharedrepository)
'
-test_expect_failure 'template can set core.bare' '
+test_expect_success 'template cannot set core.bare' '
test_when_finished "rm -rf subdir" &&
test_when_finished "rm -rf templates" &&
test_config core.bare true &&
@@ -60,18 +59,7 @@ test_expect_failure 'template can set core.bare' '
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_path_is_missing subdir/HEAD
'
test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository' '
@@ -137,22 +125,6 @@ test_expect_success POSIXPERM 'info/refs respects umask in unshared repo' '
test_cmp expect actual
'
-test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
- umask 077 &&
- git config core.sharedRepository group &&
- git reflog expire --all &&
- actual="$(ls -l .git/logs/refs/heads/main)" &&
- case "$actual" in
- -rw-rw-*)
- : happy
- ;;
- *)
- echo Ooops, .git/logs/refs/heads/main is not 066x [$actual]
- false
- ;;
- esac
-'
-
test_expect_success POSIXPERM 'forced modes' '
test_when_finished "rm -rf new" &&
mkdir -p templates/hooks &&
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index 179474fa65..69723b88ff 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -5,14 +5,9 @@
test_description='Test repository version check'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
- test_oid_cache <<-\EOF &&
- version sha1:0
- version sha256:1
- EOF
cat >test.patch <<-\EOF &&
diff --git a/test.txt b/test.txt
new file mode 100644
@@ -28,7 +23,12 @@ test_expect_success 'setup' '
'
test_expect_success 'gitdir selection on normal repos' '
- test_oid version >expect &&
+ if test_have_prereq DEFAULT_REPO_FORMAT
+ then
+ echo 0
+ else
+ echo 1
+ fi >expect &&
git config core.repositoryformatversion >actual &&
git -C test config core.repositoryformatversion >actual2 &&
test_cmp expect actual &&
@@ -79,8 +79,13 @@ mkconfig () {
while read outcome version extensions; do
test_expect_success "$outcome version=$version $extensions" "
- mkconfig $version $extensions >.git/config &&
- check_${outcome}
+ test_when_finished 'rm -rf extensions' &&
+ git init extensions &&
+ (
+ cd extensions &&
+ mkconfig $version $extensions >.git/config &&
+ check_${outcome}
+ )
"
done <<\EOF
allow 0
@@ -94,7 +99,8 @@ allow 1 noop-v1
EOF
test_expect_success 'precious-objects allowed' '
- mkconfig 1 preciousObjects >.git/config &&
+ git config core.repositoryFormatVersion 1 &&
+ git config extensions.preciousObjects 1 &&
check_allow
'
diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh
index 0506f3d6bb..d971925ed0 100755
--- a/t/t1303-wacky-config.sh
+++ b/t/t1303-wacky-config.sh
@@ -2,7 +2,6 @@
test_description='Test wacky input to git config'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Leaving off the newline is intentional!
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
index 31b89dd969..c69ae41306 100755
--- a/t/t1304-default-acl.sh
+++ b/t/t1304-default-acl.sh
@@ -9,7 +9,6 @@ test_description='Test repository with default ACL'
# => this must come before . ./test-lib.sh
umask 077
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# We need an arbitrary other user give permission to using ACLs. root
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
index 5cde79ef8c..8ff2b0c232 100755
--- a/t/t1305-config-include.sh
+++ b/t/t1305-config-include.sh
@@ -1,7 +1,6 @@
#!/bin/sh
test_description='test config file include directives'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Force setup_explicit_git_dir() to run until the end. This is needed
@@ -357,4 +356,44 @@ test_expect_success 'include cycles are detected' '
grep "exceeded maximum include depth" stderr
'
+test_expect_success 'onbranch with unborn branch' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config set includeIf.onbranch:"*".path config.inc &&
+ git config set -f .git/config.inc foo.bar baz &&
+ git config get foo.bar
+ )
+'
+
+test_expect_success 'onbranch with detached HEAD' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config set "includeIf.onbranch:*.path" config.inc &&
+ git config set -f .git/config.inc foo.bar baz &&
+ test_commit initial &&
+ git switch --detach HEAD &&
+ test_must_fail git config get foo.bar
+ )
+'
+
+test_expect_success 'onbranch without repository' '
+ test_when_finished "rm -f .gitconfig config.inc" &&
+ git config set -f .gitconfig "includeIf.onbranch:**.path" config.inc &&
+ git config set -f config.inc foo.bar baz &&
+ git config get foo.bar &&
+ test_must_fail nongit git config get foo.bar
+'
+
+test_expect_success 'onbranch without repository but explicit nonexistent Git directory' '
+ test_when_finished "rm -f .gitconfig config.inc" &&
+ git config set -f .gitconfig "includeIf.onbranch:**.path" config.inc &&
+ git config set -f config.inc foo.bar baz &&
+ git config get foo.bar &&
+ test_must_fail nongit git --git-dir=nonexistent config get foo.bar
+'
+
test_done
diff --git a/t/t1307-config-blob.sh b/t/t1307-config-blob.sh
index 0a7099d6f5..5cb546dd00 100755
--- a/t/t1307-config-blob.sh
+++ b/t/t1307-config-blob.sh
@@ -2,7 +2,6 @@
test_description='support for reading config from a blob'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create config blob' '
@@ -63,7 +62,7 @@ test_expect_success 'parse errors in blobs are properly attributed' '
git commit -m broken &&
test_must_fail git config --blob=HEAD:config some.value 2>err &&
- test_i18ngrep "HEAD:config" err
+ test_grep "HEAD:config" err
'
test_expect_success 'can parse blob ending with CR' '
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index 777648722c..e0e49053f0 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -2,7 +2,6 @@
test_description='Test git config-set API in different settings'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# 'check_config get_* section.key value' verifies that the entry for
@@ -172,7 +171,7 @@ test_expect_success 'find string value for a key' '
test_expect_success 'check line error when NULL string is queried' '
test_expect_code 128 test-tool config get_string case.foo 2>result &&
- test_i18ngrep "fatal: .*case\.foo.*\.git/config.*line 7" result
+ test_grep "fatal: .*case\.foo.*\.git/config.*line 7" result
'
test_expect_success 'find integer if value is non parse-able' '
@@ -342,14 +341,14 @@ test_expect_success 'check line errors for malformed values' '
br
EOF
test_expect_code 128 git br 2>result &&
- test_i18ngrep "missing value for .alias\.br" result &&
- test_i18ngrep "fatal: .*\.git/config" result &&
- test_i18ngrep "fatal: .*line 2" result
+ test_grep "missing value for .alias\.br" result &&
+ test_grep "fatal: .*\.git/config" result &&
+ test_grep "fatal: .*line 2" result
'
test_expect_success 'error on modifying repo config without repo' '
nongit test_must_fail git config a.b c 2>err &&
- test_i18ngrep "not in a git directory" err
+ test_grep "not in a git directory" err
'
cmdline_config="'foo.bar=from-cmdline'"
diff --git a/t/t1309-early-config.sh b/t/t1309-early-config.sh
index 537435b90a..9710ee0ca4 100755
--- a/t/t1309-early-config.sh
+++ b/t/t1309-early-config.sh
@@ -2,7 +2,6 @@
test_description='Test read_early_config()'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'read early config' '
@@ -78,7 +77,7 @@ test_with_config () {
test_expect_success 'ignore .git/ with incompatible repository version' '
test_with_config "[core]repositoryformatversion = 999999" 2>err &&
- test_i18ngrep "warning:.* Expected git repo version <= [1-9]" err
+ test_grep "warning:.* Expected git repo version <= [1-9]" err
'
test_expect_failure 'ignore .git/ with invalid repository version' '
diff --git a/t/t1310-config-default.sh b/t/t1310-config-default.sh
index 09b10c144b..69e64c6c86 100755
--- a/t/t1310-config-default.sh
+++ b/t/t1310-config-default.sh
@@ -2,7 +2,6 @@
test_description='Test git config in different settings (with --default)'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'uses --default when entry missing' '
@@ -26,12 +25,12 @@ test_expect_success 'canonicalizes --default with appropriate type' '
test_expect_success 'dies when --default cannot be parsed' '
test_must_fail git config -f config --type=expiry-date --default=x --get \
not.a.section 2>error &&
- test_i18ngrep "failed to format default config value" error
+ test_grep "failed to format default config value" error
'
test_expect_success 'does not allow --default without --get' '
test_must_fail git config --default=quux --unset a.section >output 2>&1 &&
- test_i18ngrep "\-\-default is only applicable to" output
+ test_grep "\-\-default is only applicable to" output
'
test_done
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 4d66cd7f4a..e2316f1dd4 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -4,13 +4,12 @@
#
test_description='Test git update-ref and basic ref logging'
+
. ./test-lib.sh
Z=$ZERO_OID
m=refs/heads/main
-n_dir=refs/heads/gu
-n=$n_dir/fixes
outside=refs/foo
bare=bare-repo
@@ -62,10 +61,10 @@ test_expect_success "delete $m without oldvalue verification" '
test_must_fail git show-ref --verify -q $m
'
-test_expect_success "fail to create $n" '
- test_when_finished "rm -f .git/$n_dir" &&
- touch .git/$n_dir &&
- test_must_fail git update-ref $n $A
+test_expect_success "fail to create $n due to file/directory conflict" '
+ test_when_finished "git update-ref -d refs/heads/gu" &&
+ git update-ref refs/heads/gu $A &&
+ test_must_fail git update-ref refs/heads/gu/fixes $A
'
test_expect_success "create $m (by HEAD)" '
@@ -92,7 +91,8 @@ test_expect_success "deleting current branch adds message to HEAD's log" '
git symbolic-ref HEAD $m &&
git update-ref -m delete-$m -d $m &&
test_must_fail git show-ref --verify -q $m &&
- grep "delete-$m$" .git/logs/HEAD
+ test-tool ref-store main for-each-reflog-ent HEAD >actual &&
+ grep "delete-$m$" actual
'
test_expect_success "deleting by HEAD adds message to HEAD's log" '
@@ -101,7 +101,8 @@ test_expect_success "deleting by HEAD adds message to HEAD's log" '
git symbolic-ref HEAD $m &&
git update-ref -m delete-by-head -d HEAD &&
test_must_fail git show-ref --verify -q $m &&
- grep "delete-by-head$" .git/logs/HEAD
+ test-tool ref-store main for-each-reflog-ent HEAD >actual &&
+ grep "delete-by-head$" actual
'
test_expect_success 'update-ref does not create reflogs by default' '
@@ -132,7 +133,7 @@ test_expect_success 'creates no reflog in bare repository' '
test_expect_success 'core.logAllRefUpdates=true creates reflog in bare repository' '
test_when_finished "git -C $bare config --unset core.logAllRefUpdates && \
- rm $bare/logs/$m" &&
+ test-tool ref-store main delete-reflog $m" &&
git -C $bare config core.logAllRefUpdates true &&
git -C $bare update-ref $m $bareB &&
git -C $bare rev-parse $bareB >expect &&
@@ -221,27 +222,27 @@ test_expect_success 'delete symref without dereference when the referred ref is
'
test_expect_success 'update-ref -d is not confused by self-reference' '
+ test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF refs/heads/self" &&
git symbolic-ref refs/heads/self refs/heads/self &&
- test_when_finished "rm -f .git/refs/heads/self" &&
- test_path_is_file .git/refs/heads/self &&
+ git symbolic-ref --no-recurse refs/heads/self &&
test_must_fail git update-ref -d refs/heads/self &&
- test_path_is_file .git/refs/heads/self
+ git symbolic-ref --no-recurse refs/heads/self
'
test_expect_success 'update-ref --no-deref -d can delete self-reference' '
+ test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF refs/heads/self" &&
git symbolic-ref refs/heads/self refs/heads/self &&
- test_when_finished "rm -f .git/refs/heads/self" &&
- test_path_is_file .git/refs/heads/self &&
+ git symbolic-ref --no-recurse refs/heads/self &&
git update-ref --no-deref -d refs/heads/self &&
test_must_fail git show-ref --verify -q refs/heads/self
'
-test_expect_success 'update-ref --no-deref -d can delete reference to bad ref' '
+test_expect_success REFFILES 'update-ref --no-deref -d can delete reference to bad ref' '
>.git/refs/heads/bad &&
test_when_finished "rm -f .git/refs/heads/bad" &&
git symbolic-ref refs/heads/ref-to-bad refs/heads/bad &&
test_when_finished "git update-ref -d refs/heads/ref-to-bad" &&
- test_path_is_file .git/refs/heads/ref-to-bad &&
+ git symbolic-ref --no-recurse refs/heads/ref-to-bad &&
git update-ref --no-deref -d refs/heads/ref-to-bad &&
test_must_fail git show-ref --verify -q refs/heads/ref-to-bad
'
@@ -265,7 +266,10 @@ test_expect_success "(not) changed .git/$m" '
! test $B = $(git show-ref -s --verify $m)
'
-rm -f .git/logs/refs/heads/main
+test_expect_success "clean up reflog" '
+ test-tool ref-store main delete-reflog $m
+'
+
test_expect_success "create $m (logged by touch)" '
test_config core.logAllRefUpdates false &&
GIT_COMMITTER_DATE="2005-05-26 23:30" \
@@ -285,40 +289,13 @@ test_expect_success "set $m (logged by touch)" '
test $A = $(git show-ref -s --verify $m)
'
-test_expect_success 'empty directory removal' '
- git branch d1/d2/r1 HEAD &&
- git branch d1/r2 HEAD &&
- test_path_is_file .git/refs/heads/d1/d2/r1 &&
- test_path_is_file .git/logs/refs/heads/d1/d2/r1 &&
- git branch -d d1/d2/r1 &&
- test_must_fail git show-ref --verify -q refs/heads/d1/d2 &&
- test_must_fail git show-ref --verify -q logs/refs/heads/d1/d2 &&
- test_path_is_file .git/refs/heads/d1/r2 &&
- test_path_is_file .git/logs/refs/heads/d1/r2
-'
-
-test_expect_success 'symref empty directory removal' '
- git branch e1/e2/r1 HEAD &&
- git branch e1/r2 HEAD &&
- git checkout e1/e2/r1 &&
- test_when_finished "git checkout main" &&
- test_path_is_file .git/refs/heads/e1/e2/r1 &&
- test_path_is_file .git/logs/refs/heads/e1/e2/r1 &&
- git update-ref -d HEAD &&
- test_must_fail git show-ref --verify -q refs/heads/e1/e2 &&
- test_must_fail git show-ref --verify -q logs/refs/heads/e1/e2 &&
- test_path_is_file .git/refs/heads/e1/r2 &&
- test_path_is_file .git/logs/refs/heads/e1/r2 &&
- test_path_is_file .git/logs/HEAD
-'
-
cat >expect <<EOF
$Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 Initial Creation
$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150260 +0000 Switch
$B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000
EOF
test_expect_success "verifying $m's log (logged by touch)" '
- test_when_finished "git update-ref -d $m && rm -rf .git/logs actual expect" &&
+ test_when_finished "git update-ref -d $m && git reflog expire --expire=all --all && rm -rf actual expect" &&
test-tool ref-store main for-each-reflog-ent $m >actual &&
test_cmp actual expect
'
@@ -348,20 +325,34 @@ $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 +0000 Switch
$B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 +0000
EOF
test_expect_success "verifying $m's log (logged by config)" '
- test_when_finished "git update-ref -d $m && rm -rf .git/logs actual expect" &&
+ test_when_finished "git update-ref -d $m && git reflog expire --expire=all --all && rm -rf actual expect" &&
test-tool ref-store main for-each-reflog-ent $m >actual &&
test_cmp actual expect
'
test_expect_success 'set up for querying the reflog' '
+ git update-ref -d $m &&
+ test-tool ref-store main delete-reflog $m &&
+
+ GIT_COMMITTER_DATE="1117150320 -0500" git update-ref $m $C &&
+ GIT_COMMITTER_DATE="1117150350 -0500" git update-ref $m $A &&
+ GIT_COMMITTER_DATE="1117150380 -0500" git update-ref $m $B &&
+ GIT_COMMITTER_DATE="1117150680 -0500" git update-ref $m $F &&
+ GIT_COMMITTER_DATE="1117150980 -0500" git update-ref $m $E &&
git update-ref $m $D &&
- cat >.git/logs/$m <<-EOF
+ # Delete the last reflog entry so that the tip of m and the reflog for
+ # it disagree.
+ git reflog delete $m@{0} &&
+
+ cat >expect <<-EOF &&
$Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
$C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500
$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
- $F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
- $Z $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500
+ $B $F $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
+ $F $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500
EOF
+ test-tool ref-store main for-each-reflog-ent $m >actual &&
+ test_cmp expect actual
'
ed="Thu, 26 May 2005 18:32:00 -0500"
@@ -409,13 +400,12 @@ test_expect_success 'Query "main@{2005-05-26 23:33:01}" (middle of history with
test_when_finished "rm -f o e" &&
git rev-parse --verify "main@{2005-05-26 23:33:01}" >o 2>e &&
echo "$B" >expect &&
- test_cmp expect o &&
- test_i18ngrep -F "warning: log for ref $m has gap after $gd" e
+ test_cmp expect o
'
test_expect_success 'Query "main@{2005-05-26 23:38:00}" (middle of history)' '
test_when_finished "rm -f o e" &&
git rev-parse --verify "main@{2005-05-26 23:38:00}" >o 2>e &&
- echo "$Z" >expect &&
+ echo "$F" >expect &&
test_cmp expect o &&
test_must_be_empty e
'
@@ -431,10 +421,27 @@ test_expect_success 'Query "main@{2005-05-28}" (past end of history)' '
git rev-parse --verify "main@{2005-05-28}" >o 2>e &&
echo "$D" >expect &&
test_cmp expect o &&
- test_i18ngrep -F "warning: log for ref $m unexpectedly ended on $ld" e
+ test_grep -F "warning: log for ref $m unexpectedly ended on $ld" e
'
-rm -f .git/$m .git/logs/$m expect
+rm -f expect
+git update-ref -d $m
+
+test_expect_success 'query reflog with gap' '
+ test_when_finished "git update-ref -d $m" &&
+
+ GIT_COMMITTER_DATE="1117150320 -0500" git update-ref $m $A &&
+ GIT_COMMITTER_DATE="1117150380 -0500" git update-ref $m $B &&
+ GIT_COMMITTER_DATE="1117150480 -0500" git update-ref $m $C &&
+ GIT_COMMITTER_DATE="1117150580 -0500" git update-ref $m $D &&
+ GIT_COMMITTER_DATE="1117150680 -0500" git update-ref $m $F &&
+ git reflog delete $m@{2} &&
+
+ git rev-parse --verify "main@{2005-05-26 23:33:01}" >actual 2>stderr &&
+ echo "$B" >expect &&
+ test_cmp expect actual &&
+ test_grep -F "warning: log for ref $m has gap after $gd" stderr
+'
test_expect_success 'creating initial files' '
test_when_finished rm -f M &&
@@ -486,57 +493,57 @@ test_expect_success 'git cat-file blob main@{2005-05-26 23:42}:F (expect OTHER)'
test_expect_success 'given old value for missing pseudoref, do not create' '
test_must_fail git update-ref PSEUDOREF $A $B 2>err &&
test_must_fail git rev-parse PSEUDOREF &&
- test_i18ngrep "unable to resolve reference" err
+ test_grep "unable to resolve reference" err
'
test_expect_success 'create pseudoref' '
git update-ref PSEUDOREF $A &&
- test $A = $(git rev-parse PSEUDOREF)
+ test $A = $(git show-ref -s --verify PSEUDOREF)
'
test_expect_success 'overwrite pseudoref with no old value given' '
git update-ref PSEUDOREF $B &&
- test $B = $(git rev-parse PSEUDOREF)
+ test $B = $(git show-ref -s --verify PSEUDOREF)
'
test_expect_success 'overwrite pseudoref with correct old value' '
git update-ref PSEUDOREF $C $B &&
- test $C = $(git rev-parse PSEUDOREF)
+ test $C = $(git show-ref -s --verify PSEUDOREF)
'
test_expect_success 'do not overwrite pseudoref with wrong old value' '
test_must_fail git update-ref PSEUDOREF $D $E 2>err &&
- test $C = $(git rev-parse PSEUDOREF) &&
- test_i18ngrep "cannot lock ref.*expected" err
+ test $C = $(git show-ref -s --verify PSEUDOREF) &&
+ test_grep "cannot lock ref.*expected" err
'
test_expect_success 'delete pseudoref' '
git update-ref -d PSEUDOREF &&
- test_must_fail git rev-parse PSEUDOREF
+ test_must_fail git show-ref -s --verify PSEUDOREF
'
test_expect_success 'do not delete pseudoref with wrong old value' '
git update-ref PSEUDOREF $A &&
test_must_fail git update-ref -d PSEUDOREF $B 2>err &&
- test $A = $(git rev-parse PSEUDOREF) &&
- test_i18ngrep "cannot lock ref.*expected" err
+ test $A = $(git show-ref -s --verify PSEUDOREF) &&
+ test_grep "cannot lock ref.*expected" err
'
test_expect_success 'delete pseudoref with correct old value' '
git update-ref -d PSEUDOREF $A &&
- test_must_fail git rev-parse PSEUDOREF
+ test_must_fail git show-ref -s --verify PSEUDOREF
'
test_expect_success 'create pseudoref with old OID zero' '
git update-ref PSEUDOREF $A $Z &&
- test $A = $(git rev-parse PSEUDOREF)
+ test $A = $(git show-ref -s --verify PSEUDOREF)
'
test_expect_success 'do not overwrite pseudoref with old OID zero' '
test_when_finished git update-ref -d PSEUDOREF &&
test_must_fail git update-ref PSEUDOREF $B $Z 2>err &&
- test $A = $(git rev-parse PSEUDOREF) &&
- test_i18ngrep "already exists" err
+ test $A = $(git show-ref -s --verify PSEUDOREF) &&
+ test_grep "already exists" err
'
# Test --stdin
@@ -556,7 +563,7 @@ test_expect_success 'stdin test setup' '
test_expect_success '-z fails without --stdin' '
test_must_fail git update-ref -z $m $m $m 2>err &&
- test_i18ngrep "usage: git update-ref" err
+ test_grep "usage: git update-ref" err
'
test_expect_success 'stdin works with no input' '
@@ -616,7 +623,7 @@ test_expect_success 'stdin fails create with no ref' '
test_expect_success 'stdin fails create with no new value' '
echo "create $a" >stdin &&
test_must_fail git update-ref --stdin <stdin 2>err &&
- grep "fatal: create $a: missing <newvalue>" err
+ grep "fatal: create $a: missing <new-oid>" err
'
test_expect_success 'stdin fails create with too many arguments' '
@@ -634,7 +641,7 @@ test_expect_success 'stdin fails update with no ref' '
test_expect_success 'stdin fails update with no new value' '
echo "update $a" >stdin &&
test_must_fail git update-ref --stdin <stdin 2>err &&
- grep "fatal: update $a: missing <newvalue>" err
+ grep "fatal: update $a: missing <new-oid>" err
'
test_expect_success 'stdin fails update with too many arguments' '
@@ -674,7 +681,7 @@ test_expect_success 'stdin fails with duplicate refs' '
create $a $m
EOF
test_must_fail git update-ref --stdin <stdin 2>err &&
- test_i18ngrep "fatal: multiple updates for ref '"'"'$a'"'"' not allowed" err
+ test_grep "fatal: multiple updates for ref '"'"'$a'"'"' not allowed" err
'
test_expect_success 'stdin create ref works' '
@@ -759,21 +766,21 @@ test_expect_success 'stdin update ref fails with wrong old value' '
test_expect_success 'stdin update ref fails with bad old value' '
echo "update $c $m does-not-exist" >stdin &&
test_must_fail git update-ref --stdin <stdin 2>err &&
- grep "fatal: update $c: invalid <oldvalue>: does-not-exist" err &&
+ grep "fatal: update $c: invalid <old-oid>: does-not-exist" err &&
test_must_fail git rev-parse --verify -q $c
'
test_expect_success 'stdin create ref fails with bad new value' '
echo "create $c does-not-exist" >stdin &&
test_must_fail git update-ref --stdin <stdin 2>err &&
- grep "fatal: create $c: invalid <newvalue>: does-not-exist" err &&
+ grep "fatal: create $c: invalid <new-oid>: does-not-exist" err &&
test_must_fail git rev-parse --verify -q $c
'
test_expect_success 'stdin create ref fails with zero new value' '
echo "create $c " >stdin &&
test_must_fail git update-ref --stdin <stdin 2>err &&
- grep "fatal: create $c: zero <newvalue>" err &&
+ grep "fatal: create $c: zero <new-oid>" err &&
test_must_fail git rev-parse --verify -q $c
'
@@ -797,7 +804,7 @@ test_expect_success 'stdin delete ref fails with wrong old value' '
test_expect_success 'stdin delete ref fails with zero old value' '
echo "delete $a " >stdin &&
test_must_fail git update-ref --stdin <stdin 2>err &&
- grep "fatal: delete $a: zero <oldvalue>" err &&
+ grep "fatal: delete $a: zero <old-oid>" err &&
git rev-parse $m >expect &&
git rev-parse $a >actual &&
test_cmp expect actual
@@ -884,17 +891,23 @@ test_expect_success 'stdin update/create/verify combination works' '
'
test_expect_success 'stdin verify succeeds for correct value' '
+ test-tool ref-store main for-each-reflog-ent $m >before &&
git rev-parse $m >expect &&
echo "verify $m $m" >stdin &&
git update-ref --stdin <stdin &&
git rev-parse $m >actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test-tool ref-store main for-each-reflog-ent $m >after &&
+ test_cmp before after
'
test_expect_success 'stdin verify succeeds for missing reference' '
+ test-tool ref-store main for-each-reflog-ent $m >before &&
echo "verify refs/heads/missing $Z" >stdin &&
git update-ref --stdin <stdin &&
- test_must_fail git rev-parse --verify -q refs/heads/missing
+ test_must_fail git rev-parse --verify -q refs/heads/missing &&
+ test-tool ref-store main for-each-reflog-ent $m >after &&
+ test_cmp before after
'
test_expect_success 'stdin verify treats no value as missing' '
@@ -1021,7 +1034,7 @@ test_expect_success 'stdin -z fails create with no ref' '
test_expect_success 'stdin -z fails create with no new value' '
printf $F "create $a" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: create $a: unexpected end of input when reading <newvalue>" err
+ grep "fatal: create $a: unexpected end of input when reading <new-oid>" err
'
test_expect_success 'stdin -z fails create with too many arguments' '
@@ -1039,27 +1052,27 @@ test_expect_success 'stdin -z fails update with no ref' '
test_expect_success 'stdin -z fails update with too few args' '
printf $F "update $a" "$m" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err
+ grep "fatal: update $a: unexpected end of input when reading <old-oid>" err
'
test_expect_success 'stdin -z emits warning with empty new value' '
git update-ref $a $m &&
printf $F "update $a" "" "" >stdin &&
git update-ref -z --stdin <stdin 2>err &&
- grep "warning: update $a: missing <newvalue>, treating as zero" err &&
+ grep "warning: update $a: missing <new-oid>, treating as zero" err &&
test_must_fail git rev-parse --verify -q $a
'
test_expect_success 'stdin -z fails update with no new value' '
printf $F "update $a" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: update $a: unexpected end of input when reading <newvalue>" err
+ grep "fatal: update $a: unexpected end of input when reading <new-oid>" err
'
test_expect_success 'stdin -z fails update with no old value' '
printf $F "update $a" "$m" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err
+ grep "fatal: update $a: unexpected end of input when reading <old-oid>" err
'
test_expect_success 'stdin -z fails update with too many arguments' '
@@ -1077,7 +1090,7 @@ test_expect_success 'stdin -z fails delete with no ref' '
test_expect_success 'stdin -z fails delete with no old value' '
printf $F "delete $a" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: delete $a: unexpected end of input when reading <oldvalue>" err
+ grep "fatal: delete $a: unexpected end of input when reading <old-oid>" err
'
test_expect_success 'stdin -z fails delete with too many arguments' '
@@ -1095,7 +1108,7 @@ test_expect_success 'stdin -z fails verify with too many arguments' '
test_expect_success 'stdin -z fails verify with no old value' '
printf $F "verify $a" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: verify $a: unexpected end of input when reading <oldvalue>" err
+ grep "fatal: verify $a: unexpected end of input when reading <old-oid>" err
'
test_expect_success 'stdin -z fails option with unknown name' '
@@ -1107,7 +1120,7 @@ test_expect_success 'stdin -z fails option with unknown name' '
test_expect_success 'stdin -z fails with duplicate refs' '
printf $F "create $a" "$m" "create $b" "$m" "create $a" "$m" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- test_i18ngrep "fatal: multiple updates for ref '"'"'$a'"'"' not allowed" err
+ test_grep "fatal: multiple updates for ref '"'"'$a'"'"' not allowed" err
'
test_expect_success 'stdin -z create ref works' '
@@ -1154,7 +1167,7 @@ test_expect_success 'stdin -z update ref fails with wrong old value' '
test_expect_success 'stdin -z update ref fails with bad old value' '
printf $F "update $c" "$m" "does-not-exist" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: update $c: invalid <oldvalue>: does-not-exist" err &&
+ grep "fatal: update $c: invalid <old-oid>: does-not-exist" err &&
test_must_fail git rev-parse --verify -q $c
'
@@ -1172,14 +1185,14 @@ test_expect_success 'stdin -z create ref fails with bad new value' '
git update-ref -d "$c" &&
printf $F "create $c" "does-not-exist" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: create $c: invalid <newvalue>: does-not-exist" err &&
+ grep "fatal: create $c: invalid <new-oid>: does-not-exist" err &&
test_must_fail git rev-parse --verify -q $c
'
test_expect_success 'stdin -z create ref fails with empty new value' '
printf $F "create $c" "" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: create $c: missing <newvalue>" err &&
+ grep "fatal: create $c: missing <new-oid>" err &&
test_must_fail git rev-parse --verify -q $c
'
@@ -1203,7 +1216,7 @@ test_expect_success 'stdin -z delete ref fails with wrong old value' '
test_expect_success 'stdin -z delete ref fails with zero old value' '
printf $F "delete $a" "$Z" >stdin &&
test_must_fail git update-ref -z --stdin <stdin 2>err &&
- grep "fatal: delete $a: zero <oldvalue>" err &&
+ grep "fatal: delete $a: zero <old-oid>" err &&
git rev-parse $m >expect &&
git rev-parse $a >actual &&
test_cmp expect actual
@@ -1338,7 +1351,7 @@ test_expect_success 'fails with duplicate HEAD update' '
update HEAD $B
EOF
test_must_fail git update-ref --stdin <stdin 2>err &&
- test_i18ngrep "fatal: multiple updates for '\''HEAD'\'' (including one via its referent .refs/heads/target1.) are not allowed" err &&
+ test_grep "fatal: multiple updates for '\''HEAD'\'' (including one via its referent .refs/heads/target1.) are not allowed" err &&
echo "refs/heads/target1" >expect &&
git symbolic-ref HEAD >actual &&
test_cmp expect actual &&
@@ -1348,6 +1361,7 @@ test_expect_success 'fails with duplicate HEAD update' '
'
test_expect_success 'fails with duplicate ref update via symref' '
+ test_when_finished "git symbolic-ref -d refs/heads/symref2" &&
git branch target2 $A &&
git symbolic-ref refs/heads/symref2 refs/heads/target2 &&
cat >stdin <<-EOF &&
@@ -1355,7 +1369,7 @@ test_expect_success 'fails with duplicate ref update via symref' '
update refs/heads/symref2 $B
EOF
test_must_fail git update-ref --stdin <stdin 2>err &&
- test_i18ngrep "fatal: multiple updates for '\''refs/heads/target2'\'' (including one via symref .refs/heads/symref2.) are not allowed" err &&
+ test_grep "fatal: multiple updates for '\''refs/heads/target2'\'' (including one via symref .refs/heads/symref2.) are not allowed" err &&
echo "refs/heads/target2" >expect &&
git symbolic-ref refs/heads/symref2 >actual &&
test_cmp expect actual &&
@@ -1635,13 +1649,423 @@ test_expect_success PIPE 'transaction flushes status updates' '
test_cmp expected actual
'
-test_expect_success 'directory not created deleting packed ref' '
- git branch d1/d2/r1 HEAD &&
- git pack-refs --all &&
- test_path_is_missing .git/refs/heads/d1/d2 &&
- git update-ref -d refs/heads/d1/d2/r1 &&
- test_path_is_missing .git/refs/heads/d1/d2 &&
- test_path_is_missing .git/refs/heads/d1
-'
+format_command () {
+ if test "$1" = "-z"
+ then
+ shift
+ printf "$F" "$@"
+ else
+ echo "$@"
+ fi
+}
+
+for type in "" "-z"
+do
+
+ test_expect_success "stdin $type symref-verify fails without --no-deref" '
+ git symbolic-ref refs/heads/symref $a &&
+ format_command $type "symref-verify refs/heads/symref" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type <stdin 2>err &&
+ grep "fatal: symref-verify: cannot operate with deref mode" err
+ '
+
+ test_expect_success "stdin $type symref-verify fails with too many arguments" '
+ format_command $type "symref-verify refs/heads/symref" "$a" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ if test "$type" = "-z"
+ then
+ grep "fatal: unknown command: $a" err
+ else
+ grep "fatal: symref-verify refs/heads/symref: extra input: $a" err
+ fi
+ '
+
+ test_expect_success "stdin $type symref-verify succeeds for correct value" '
+ git symbolic-ref refs/heads/symref >expect &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/symref >before &&
+ format_command $type "symref-verify refs/heads/symref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/symref >after &&
+ test_cmp before after
+ '
+
+ test_expect_success "stdin $type symref-verify fails with no value" '
+ git symbolic-ref refs/heads/symref >expect &&
+ format_command $type "symref-verify refs/heads/symref" "" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin
+ '
+
+ test_expect_success "stdin $type symref-verify succeeds for dangling reference" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref2" &&
+ test_must_fail git symbolic-ref refs/heads/nonexistent &&
+ git symbolic-ref refs/heads/symref2 refs/heads/nonexistent &&
+ format_command $type "symref-verify refs/heads/symref2" "refs/heads/nonexistent" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin
+ '
+
+ test_expect_success "stdin $type symref-verify fails for missing reference" '
+ test-tool ref-store main for-each-reflog-ent refs/heads/symref >before &&
+ format_command $type "symref-verify refs/heads/missing" "refs/heads/unknown" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ grep "fatal: cannot lock ref ${SQ}refs/heads/missing${SQ}: unable to resolve reference ${SQ}refs/heads/missing${SQ}" err &&
+ test_must_fail git rev-parse --verify -q refs/heads/missing &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/symref >after &&
+ test_cmp before after
+ '
+
+ test_expect_success "stdin $type symref-verify fails for wrong value" '
+ git symbolic-ref refs/heads/symref >expect &&
+ format_command $type "symref-verify refs/heads/symref" "$b" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-verify fails for mistaken null value" '
+ git symbolic-ref refs/heads/symref >expect &&
+ format_command $type "symref-verify refs/heads/symref" "$Z" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-delete fails without --no-deref" '
+ git symbolic-ref refs/heads/symref $a &&
+ format_command $type "symref-delete refs/heads/symref" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type <stdin 2>err &&
+ grep "fatal: symref-delete: cannot operate with deref mode" err
+ '
+
+ test_expect_success "stdin $type symref-delete fails with no ref" '
+ format_command $type "symref-delete " >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ grep "fatal: symref-delete: missing <ref>" err
+ '
+
+ test_expect_success "stdin $type symref-delete fails deleting regular ref" '
+ test_when_finished "git update-ref -d refs/heads/regularref" &&
+ git update-ref refs/heads/regularref $a &&
+ format_command $type "symref-delete refs/heads/regularref" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ grep "fatal: cannot lock ref ${SQ}refs/heads/regularref${SQ}: expected symref with target ${SQ}$a${SQ}: but is a regular ref" err
+ '
+
+ test_expect_success "stdin $type symref-delete fails with too many arguments" '
+ format_command $type "symref-delete refs/heads/symref" "$a" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ if test "$type" = "-z"
+ then
+ grep "fatal: unknown command: $a" err
+ else
+ grep "fatal: symref-delete refs/heads/symref: extra input: $a" err
+ fi
+ '
+
+ test_expect_success "stdin $type symref-delete fails with wrong old value" '
+ format_command $type "symref-delete refs/heads/symref" "$m" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ grep "fatal: verifying symref target: ${SQ}refs/heads/symref${SQ}: is at $a but expected refs/heads/main" err &&
+ git symbolic-ref refs/heads/symref >expect &&
+ echo $a >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-delete works with right old value" '
+ format_command $type "symref-delete refs/heads/symref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ test_must_fail git rev-parse --verify -q refs/heads/symref
+ '
+
+ test_expect_success "stdin $type symref-delete works with empty old value" '
+ git symbolic-ref refs/heads/symref $a >stdin &&
+ format_command $type "symref-delete refs/heads/symref" "" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ test_must_fail git rev-parse --verify -q $b
+ '
+
+ test_expect_success "stdin $type symref-delete succeeds for dangling reference" '
+ test_must_fail git symbolic-ref refs/heads/nonexistent &&
+ git symbolic-ref refs/heads/symref2 refs/heads/nonexistent &&
+ format_command $type "symref-delete refs/heads/symref2" "refs/heads/nonexistent" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ test_must_fail git symbolic-ref -d refs/heads/symref2
+ '
+
+ test_expect_success "stdin $type symref-delete deletes regular ref without target" '
+ git update-ref refs/heads/regularref $a &&
+ format_command $type "symref-delete refs/heads/regularref" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin
+ '
+
+ test_expect_success "stdin $type symref-create fails with too many arguments" '
+ format_command $type "symref-create refs/heads/symref" "$a" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ if test "$type" = "-z"
+ then
+ grep "fatal: unknown command: $a" err
+ else
+ grep "fatal: symref-create refs/heads/symref: extra input: $a" err
+ fi
+ '
+
+ test_expect_success "stdin $type symref-create fails with no target" '
+ format_command $type "symref-create refs/heads/symref" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin
+ '
+
+ test_expect_success "stdin $type symref-create fails with empty target" '
+ format_command $type "symref-create refs/heads/symref" "" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin
+ '
+
+ test_expect_success "stdin $type symref-create works" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-create refs/heads/symref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/heads/symref >expect &&
+ echo $a >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-create works with --no-deref" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-create refs/heads/symref" "$a" &&
+ git update-ref --stdin $type <stdin 2>err
+ '
+
+ test_expect_success "stdin $type create dangling symref ref works" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-create refs/heads/symref" "refs/heads/unknown" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/heads/symref >expect &&
+ echo refs/heads/unknown >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-create does not create reflogs by default" '
+ test_when_finished "git symbolic-ref -d refs/symref" &&
+ format_command $type "symref-create refs/symref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/symref >expect &&
+ echo $a >actual &&
+ test_cmp expect actual &&
+ test_must_fail git reflog exists refs/symref
+ '
+
+ test_expect_success "stdin $type symref-create reflogs with --create-reflog" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-create refs/heads/symref" "$a" >stdin &&
+ git update-ref --create-reflog --stdin $type --no-deref <stdin &&
+ git symbolic-ref refs/heads/symref >expect &&
+ echo $a >actual &&
+ test_cmp expect actual &&
+ git reflog exists refs/heads/symref
+ '
+
+ test_expect_success "stdin $type symref-update fails with too many arguments" '
+ format_command $type "symref-update refs/heads/symref" "$a" "ref" "$a" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ if test "$type" = "-z"
+ then
+ grep "fatal: unknown command: $a" err
+ else
+ grep "fatal: symref-update refs/heads/symref: extra input: $a" err
+ fi
+ '
+
+ test_expect_success "stdin $type symref-update fails with wrong old value argument" '
+ format_command $type "symref-update refs/heads/symref" "$a" "foo" "$a" "$a" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ grep "fatal: symref-update refs/heads/symref: invalid arg ${SQ}foo${SQ} for old value" err
+ '
+
+ test_expect_success "stdin $type symref-update creates with zero old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-update refs/heads/symref" "$a" "oid" "$Z" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo $a >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update creates with no old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-update refs/heads/symref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo $a >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update creates dangling" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ test_must_fail git rev-parse refs/heads/nonexistent &&
+ format_command $type "symref-update refs/heads/symref" "refs/heads/nonexistent" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo refs/heads/nonexistent >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update fails with wrong old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ git symbolic-ref refs/heads/symref $a &&
+ format_command $type "symref-update refs/heads/symref" "$m" "ref" "$b" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err &&
+ grep "fatal: verifying symref target: ${SQ}refs/heads/symref${SQ}: is at $a but expected $b" err &&
+ test_must_fail git rev-parse --verify -q $c
+ '
+
+ test_expect_success "stdin $type symref-update updates dangling ref" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ test_must_fail git rev-parse refs/heads/nonexistent &&
+ git symbolic-ref refs/heads/symref refs/heads/nonexistent &&
+ format_command $type "symref-update refs/heads/symref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo $a >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update updates dangling ref with old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ test_must_fail git rev-parse refs/heads/nonexistent &&
+ git symbolic-ref refs/heads/symref refs/heads/nonexistent &&
+ format_command $type "symref-update refs/heads/symref" "$a" "ref" "refs/heads/nonexistent" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo $a >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update fails update dangling ref with wrong old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ test_must_fail git rev-parse refs/heads/nonexistent &&
+ git symbolic-ref refs/heads/symref refs/heads/nonexistent &&
+ format_command $type "symref-update refs/heads/symref" "$a" "ref" "refs/heads/wrongref" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin &&
+ echo refs/heads/nonexistent >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update works with right old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ git symbolic-ref refs/heads/symref $a &&
+ format_command $type "symref-update refs/heads/symref" "$m" "ref" "$a" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo $m >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update works with no old value" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ git symbolic-ref refs/heads/symref $a &&
+ format_command $type "symref-update refs/heads/symref" "$m" >stdin &&
+ git update-ref --stdin $type --no-deref <stdin &&
+ echo $m >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update fails with empty old ref-target" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ git symbolic-ref refs/heads/symref $a &&
+ format_command $type "symref-update refs/heads/symref" "$m" "ref" "" >stdin &&
+ test_must_fail git update-ref --stdin $type --no-deref <stdin &&
+ echo $a >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update creates (with deref)" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ format_command $type "symref-update refs/heads/symref" "$a" >stdin &&
+ git update-ref --stdin $type <stdin &&
+ echo $a >expect &&
+ git symbolic-ref --no-recurse refs/heads/symref >actual &&
+ test_cmp expect actual &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/symref >actual &&
+ grep "$Z $(git rev-parse $a)" actual
+ '
+
+ test_expect_success "stdin $type symref-update regular ref to symref with correct old-oid" '
+ test_when_finished "git symbolic-ref -d --no-recurse refs/heads/regularref" &&
+ git update-ref --no-deref refs/heads/regularref $a &&
+ format_command $type "symref-update refs/heads/regularref" "$a" "oid" "$(git rev-parse $a)" >stdin &&
+ git update-ref --stdin $type <stdin &&
+ echo $a >expect &&
+ git symbolic-ref --no-recurse refs/heads/regularref >actual &&
+ test_cmp expect actual &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/regularref >actual &&
+ grep "$(git rev-parse $a) $(git rev-parse $a)" actual
+ '
+
+ test_expect_success "stdin $type symref-update regular ref to symref fails with wrong old-oid" '
+ test_when_finished "git update-ref -d refs/heads/regularref" &&
+ git update-ref --no-deref refs/heads/regularref $a &&
+ format_command $type "symref-update refs/heads/regularref" "$a" "oid" "$(git rev-parse refs/heads/target2)" >stdin &&
+ test_must_fail git update-ref --stdin $type <stdin 2>err &&
+ grep "fatal: cannot lock ref ${SQ}refs/heads/regularref${SQ}: is at $(git rev-parse $a) but expected $(git rev-parse refs/heads/target2)" err &&
+ echo $(git rev-parse $a) >expect &&
+ git rev-parse refs/heads/regularref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update regular ref to symref fails with invalid old-oid" '
+ test_when_finished "git update-ref -d refs/heads/regularref" &&
+ git update-ref --no-deref refs/heads/regularref $a &&
+ format_command $type "symref-update refs/heads/regularref" "$a" "oid" "not-a-ref-oid" >stdin &&
+ test_must_fail git update-ref --stdin $type <stdin 2>err &&
+ grep "fatal: symref-update refs/heads/regularref: invalid oid: not-a-ref-oid" err &&
+ echo $(git rev-parse $a) >expect &&
+ git rev-parse refs/heads/regularref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update existing symref with zero old-oid" '
+ test_when_finished "git symbolic-ref -d --no-recurse refs/heads/symref" &&
+ git symbolic-ref refs/heads/symref refs/heads/target2 &&
+ format_command $type "symref-update refs/heads/symref" "$a" "oid" "$Z" >stdin &&
+ test_must_fail git update-ref --stdin $type <stdin 2>err &&
+ grep "fatal: cannot lock ref ${SQ}refs/heads/symref${SQ}: reference already exists" err &&
+ echo refs/heads/target2 >expect &&
+ git symbolic-ref refs/heads/symref >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "stdin $type symref-update regular ref to symref (with deref)" '
+ test_when_finished "git symbolic-ref -d refs/heads/symref" &&
+ test_when_finished "git update-ref -d --no-deref refs/heads/symref2" &&
+ git update-ref refs/heads/symref2 $a &&
+ git symbolic-ref --no-recurse refs/heads/symref refs/heads/symref2 &&
+ format_command $type "symref-update refs/heads/symref" "$a" >stdin &&
+ git update-ref $type --stdin <stdin &&
+ echo $a >expect &&
+ git symbolic-ref --no-recurse refs/heads/symref2 >actual &&
+ test_cmp expect actual &&
+ echo refs/heads/symref2 >expect &&
+ git symbolic-ref --no-recurse refs/heads/symref >actual &&
+ test_cmp expect actual &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/symref >actual &&
+ grep "$(git rev-parse $a) $(git rev-parse $a)" actual
+ '
+
+ test_expect_success "stdin $type symref-update regular ref to symref" '
+ test_when_finished "git symbolic-ref -d --no-recurse refs/heads/regularref" &&
+ git update-ref --no-deref refs/heads/regularref $a &&
+ format_command $type "symref-update refs/heads/regularref" "$a" >stdin &&
+ git update-ref $type --stdin <stdin &&
+ echo $a >expect &&
+ git symbolic-ref --no-recurse refs/heads/regularref >actual &&
+ test_cmp expect actual &&
+ test-tool ref-store main for-each-reflog-ent refs/heads/regularref >actual &&
+ grep "$(git rev-parse $a) $(git rev-parse $a)" actual
+ '
+
+done
test_done
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index c7745e1bf6..a2a7e94716 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -2,7 +2,6 @@
test_description='basic symbolic-ref tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# If the tests munging HEAD fail, they can break detection of
@@ -16,7 +15,7 @@ reset_to_sane() {
test_expect_success 'setup' '
git symbolic-ref HEAD refs/heads/foo &&
test_commit file &&
- "$TAR" cf .git.tar .git/
+ "$TAR" cf .git.tar .git
'
test_expect_success 'symbolic-ref read/write roundtrip' '
@@ -106,9 +105,8 @@ test_expect_success LONG_REF 'we can parse long symbolic ref' '
'
test_expect_success 'symbolic-ref reports failure in exit code' '
- test_when_finished "rm -f .git/HEAD.lock" &&
- >.git/HEAD.lock &&
- test_must_fail git symbolic-ref HEAD refs/heads/whatever
+ # Create d/f conflict to simulate failure.
+ test_must_fail git symbolic-ref refs/heads refs/heads/foo
'
test_expect_success 'symbolic-ref writes reflog entry' '
@@ -171,8 +169,8 @@ test_expect_success 'symbolic-ref refuses invalid target for non-HEAD' '
'
test_expect_success 'symbolic-ref allows top-level target for non-HEAD' '
- git symbolic-ref refs/heads/top-level FETCH_HEAD &&
- git update-ref FETCH_HEAD HEAD &&
+ git symbolic-ref refs/heads/top-level ORIG_HEAD &&
+ git update-ref ORIG_HEAD HEAD &&
test_cmp_rev top-level HEAD
'
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 5ed9d7318e..cabc516ae9 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -2,7 +2,6 @@
test_description='Test git check-ref-format'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
valid_ref() {
diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
index 9252a581ab..9d698b3cc3 100755
--- a/t/t1403-show-ref.sh
+++ b/t/t1403-show-ref.sh
@@ -4,7 +4,6 @@ test_description='show-ref'
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 '
@@ -121,13 +120,13 @@ test_expect_success 'show-ref -d' '
'
-test_expect_success 'show-ref --heads, --tags, --head, pattern' '
+test_expect_success 'show-ref --branches, --tags, --head, pattern' '
for branch in B main side
do
echo $(git rev-parse refs/heads/$branch) refs/heads/$branch || return 1
- done >expect.heads &&
- git show-ref --heads >actual &&
- test_cmp expect.heads actual &&
+ done >expect.branches &&
+ git show-ref --branches >actual &&
+ test_cmp expect.branches actual &&
for tag in A B C
do
@@ -136,15 +135,15 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' '
git show-ref --tags >actual &&
test_cmp expect.tags actual &&
- cat expect.heads expect.tags >expect &&
- git show-ref --heads --tags >actual &&
+ cat expect.branches expect.tags >expect &&
+ git show-ref --branches --tags >actual &&
test_cmp expect actual &&
{
echo $(git rev-parse HEAD) HEAD &&
- cat expect.heads expect.tags
+ cat expect.branches expect.tags
} >expect &&
- git show-ref --heads --tags --head >actual &&
+ git show-ref --branches --tags --head >actual &&
test_cmp expect actual &&
{
@@ -165,6 +164,14 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' '
test_cmp expect actual
'
+test_expect_success 'show-ref --heads is deprecated and hidden' '
+ test_expect_code 129 git show-ref -h >short-help &&
+ test_grep ! -e --heads short-help &&
+ git show-ref --heads >actual 2>warning &&
+ test_grep ! deprecated warning &&
+ test_cmp expect.branches actual
+'
+
test_expect_success 'show-ref --verify HEAD' '
echo $(git rev-parse HEAD) HEAD >expect &&
git show-ref --verify HEAD >actual &&
@@ -174,6 +181,14 @@ test_expect_success 'show-ref --verify HEAD' '
test_must_be_empty actual
'
+test_expect_success 'show-ref --verify pseudorefs' '
+ git update-ref CHERRY_PICK_HEAD HEAD $ZERO_OID &&
+ test_when_finished "git update-ref -d CHERRY_PICK_HEAD" &&
+ git show-ref -s --verify HEAD >actual &&
+ git show-ref -s --verify CHERRY_PICK_HEAD >expect &&
+ test_cmp actual expect
+'
+
test_expect_success 'show-ref --verify with dangling ref' '
sha1_file() {
echo "$*" | sed "s#..#.git/objects/&/#"
@@ -196,4 +211,86 @@ test_expect_success 'show-ref --verify with dangling ref' '
)
'
+test_expect_success 'show-ref sub-modes are mutually exclusive' '
+ test_must_fail git show-ref --verify --exclude-existing 2>err &&
+ grep "verify" err &&
+ grep "exclude-existing" err &&
+ grep "cannot be used together" err &&
+
+ test_must_fail git show-ref --verify --exists 2>err &&
+ grep "verify" err &&
+ grep "exists" err &&
+ grep "cannot be used together" err &&
+
+ test_must_fail git show-ref --exclude-existing --exists 2>err &&
+ grep "exclude-existing" err &&
+ grep "exists" err &&
+ grep "cannot be used together" err
+'
+
+test_expect_success '--exists with existing reference' '
+ git show-ref --exists refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+'
+
+test_expect_success '--exists with missing reference' '
+ test_expect_code 2 git show-ref --exists refs/heads/does-not-exist
+'
+
+test_expect_success '--exists does not use DWIM' '
+ test_expect_code 2 git show-ref --exists $GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 2>err &&
+ grep "reference does not exist" err
+'
+
+test_expect_success '--exists with HEAD' '
+ git show-ref --exists HEAD
+'
+
+test_expect_success '--exists with bad reference name' '
+ test_when_finished "git update-ref -d refs/heads/bad...name" &&
+ new_oid=$(git rev-parse HEAD) &&
+ test-tool ref-store main update-ref msg refs/heads/bad...name $new_oid $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
+ git show-ref --exists refs/heads/bad...name
+'
+
+test_expect_success '--exists with arbitrary symref' '
+ test_when_finished "git symbolic-ref -d refs/symref" &&
+ git symbolic-ref refs/symref refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME &&
+ git show-ref --exists refs/symref
+'
+
+test_expect_success '--exists with dangling symref' '
+ test_when_finished "git symbolic-ref -d refs/heads/dangling" &&
+ git symbolic-ref refs/heads/dangling refs/heads/does-not-exist &&
+ git show-ref --exists refs/heads/dangling
+'
+
+test_expect_success '--exists with nonexistent object ID' '
+ test-tool ref-store main update-ref msg refs/heads/missing-oid $(test_oid 001) $ZERO_OID REF_SKIP_OID_VERIFICATION &&
+ git show-ref --exists refs/heads/missing-oid
+'
+
+test_expect_success '--exists with non-commit object' '
+ tree_oid=$(git rev-parse HEAD^{tree}) &&
+ test-tool ref-store main update-ref msg refs/heads/tree ${tree_oid} $ZERO_OID REF_SKIP_OID_VERIFICATION &&
+ git show-ref --exists refs/heads/tree
+'
+
+test_expect_success '--exists with directory fails with generic error' '
+ cat >expect <<-EOF &&
+ error: reference does not exist
+ EOF
+ test_expect_code 2 git show-ref --exists refs/heads 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success '--exists with non-existent special ref' '
+ test_expect_code 2 git show-ref --exists FETCH_HEAD
+'
+
+test_expect_success '--exists with existing special ref' '
+ test_when_finished "rm .git/FETCH_HEAD" &&
+ git rev-parse HEAD >.git/FETCH_HEAD &&
+ git show-ref --exists FETCH_HEAD
+'
+
test_done
diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh
index 937ae0d733..28e6c380d7 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -2,7 +2,6 @@
test_description='Test git update-ref error handling'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Create some references, perhaps run pack-refs --all, then try to
@@ -29,7 +28,7 @@ test_update_rejected () {
fi &&
printf "create $prefix/%s $C\n" $create >input &&
test_must_fail git update-ref --stdin <input 2>output.err &&
- test_i18ngrep -F "$error" output.err &&
+ test_grep -F "$error" output.err &&
git for-each-ref $prefix >actual &&
test_cmp unchanged actual
}
@@ -92,9 +91,6 @@ df_test() {
else
delname="$delref"
fi &&
- cat >expected-err <<-EOF &&
- fatal: cannot lock ref $SQ$addname$SQ: $SQ$delref$SQ exists; cannot create $SQ$addref$SQ
- EOF
$pack &&
if $add_del
then
@@ -103,13 +99,13 @@ df_test() {
printf "%s\n" "delete $delname" "create $addname $D"
fi >commands &&
test_must_fail git update-ref --stdin <commands 2>output.err &&
- test_cmp expected-err output.err &&
+ grep -E "fatal:( cannot lock ref '$addname':)? '$delref' exists; cannot create '$addref'" output.err &&
printf "%s\n" "$C $delref" >expected-refs &&
git for-each-ref --format="%(objectname) %(refname)" $prefix/r >actual-refs &&
test_cmp expected-refs actual-refs
}
-test_expect_success 'setup' '
+test_expect_success 'setup' - <<\EOT
git commit --allow-empty -m Initial &&
C=$(git rev-parse HEAD) &&
@@ -117,520 +113,283 @@ test_expect_success 'setup' '
D=$(git rev-parse HEAD) &&
git commit --allow-empty -m Third &&
E=$(git rev-parse HEAD)
-'
+EOT
-test_expect_success 'existing loose ref is a simple prefix of new' '
+test_expect_success 'existing loose ref is a simple prefix of new' - <<\EOT
prefix=refs/1l &&
test_update_rejected "a c e" false "b c/x d" \
- "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ"
+ "'$prefix/c' exists; cannot create '$prefix/c/x'"
-'
+EOT
-test_expect_success 'existing packed ref is a simple prefix of new' '
+test_expect_success 'existing packed ref is a simple prefix of new' - <<\EOT
prefix=refs/1p &&
test_update_rejected "a c e" true "b c/x d" \
- "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ"
+ "'$prefix/c' exists; cannot create '$prefix/c/x'"
-'
+EOT
-test_expect_success 'existing loose ref is a deeper prefix of new' '
+test_expect_success 'existing loose ref is a deeper prefix of new' - <<\EOT
prefix=refs/2l &&
test_update_rejected "a c e" false "b c/x/y d" \
- "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ"
+ "'$prefix/c' exists; cannot create '$prefix/c/x/y'"
-'
+EOT
-test_expect_success 'existing packed ref is a deeper prefix of new' '
+test_expect_success 'existing packed ref is a deeper prefix of new' - <<\EOT
prefix=refs/2p &&
test_update_rejected "a c e" true "b c/x/y d" \
- "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ"
+ "'$prefix/c' exists; cannot create '$prefix/c/x/y'"
-'
+EOT
-test_expect_success 'new ref is a simple prefix of existing loose' '
+test_expect_success 'new ref is a simple prefix of existing loose' - <<\EOT
prefix=refs/3l &&
test_update_rejected "a c/x e" false "b c d" \
- "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ"
+ "'$prefix/c/x' exists; cannot create '$prefix/c'"
-'
+EOT
-test_expect_success 'new ref is a simple prefix of existing packed' '
+test_expect_success 'new ref is a simple prefix of existing packed' - <<\EOT
prefix=refs/3p &&
test_update_rejected "a c/x e" true "b c d" \
- "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ"
+ "'$prefix/c/x' exists; cannot create '$prefix/c'"
-'
+EOT
-test_expect_success 'new ref is a deeper prefix of existing loose' '
+test_expect_success 'new ref is a deeper prefix of existing loose' - <<\EOT
prefix=refs/4l &&
test_update_rejected "a c/x/y e" false "b c d" \
- "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ"
+ "'$prefix/c/x/y' exists; cannot create '$prefix/c'"
-'
+EOT
-test_expect_success 'new ref is a deeper prefix of existing packed' '
+test_expect_success 'new ref is a deeper prefix of existing packed' - <<\EOT
prefix=refs/4p &&
test_update_rejected "a c/x/y e" true "b c d" \
- "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ"
+ "'$prefix/c/x/y' exists; cannot create '$prefix/c'"
-'
+EOT
-test_expect_success 'one new ref is a simple prefix of another' '
+test_expect_success 'one new ref is a simple prefix of another' - <<\EOT
prefix=refs/5 &&
test_update_rejected "a e" false "b c c/x d" \
- "cannot process $SQ$prefix/c$SQ and $SQ$prefix/c/x$SQ at the same time"
-
-'
+ "cannot process '$prefix/c' and '$prefix/c/x' at the same time"
-test_expect_success REFFILES 'empty directory should not fool rev-parse' '
- prefix=refs/e-rev-parse &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- echo "$C" >expected &&
- git rev-parse $prefix/foo >actual &&
- test_cmp expected actual
-'
-
-test_expect_success REFFILES 'empty directory should not fool for-each-ref' '
- prefix=refs/e-for-each-ref &&
- git update-ref $prefix/foo $C &&
- git for-each-ref $prefix >expected &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- git for-each-ref $prefix >actual &&
- test_cmp expected actual
-'
-
-test_expect_success REFFILES 'empty directory should not fool create' '
- prefix=refs/e-create &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- printf "create %s $C\n" $prefix/foo |
- git update-ref --stdin
-'
-
-test_expect_success REFFILES 'empty directory should not fool verify' '
- prefix=refs/e-verify &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- printf "verify %s $C\n" $prefix/foo |
- git update-ref --stdin
-'
-
-test_expect_success REFFILES 'empty directory should not fool 1-arg update' '
- prefix=refs/e-update-1 &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- printf "update %s $D\n" $prefix/foo |
- git update-ref --stdin
-'
-
-test_expect_success REFFILES 'empty directory should not fool 2-arg update' '
- prefix=refs/e-update-2 &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- printf "update %s $D $C\n" $prefix/foo |
- git update-ref --stdin
-'
-
-test_expect_success REFFILES 'empty directory should not fool 0-arg delete' '
- prefix=refs/e-delete-0 &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- printf "delete %s\n" $prefix/foo |
- git update-ref --stdin
-'
-
-test_expect_success REFFILES 'empty directory should not fool 1-arg delete' '
- prefix=refs/e-delete-1 &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- mkdir -p .git/$prefix/foo/bar/baz &&
- printf "delete %s $C\n" $prefix/foo |
- git update-ref --stdin
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents add long + delete short' '
+test_expect_success 'D/F conflict prevents add long + delete short' - <<\EOT
df_test refs/df-al-ds --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents add short + delete long' '
+test_expect_success 'D/F conflict prevents add short + delete long' - <<\EOT
df_test refs/df-as-dl --add-del foo foo/bar
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents delete long + add short' '
+test_expect_success 'D/F conflict prevents delete long + add short' - <<\EOT
df_test refs/df-dl-as --del-add foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents delete short + add long' '
+test_expect_success 'D/F conflict prevents delete short + add long' - <<\EOT
df_test refs/df-ds-al --del-add foo foo/bar
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents add long + delete short packed' '
+test_expect_success 'D/F conflict prevents add long + delete short packed' - <<\EOT
df_test refs/df-al-dsp --pack --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents add short + delete long packed' '
+test_expect_success 'D/F conflict prevents add short + delete long packed' - <<\EOT
df_test refs/df-as-dlp --pack --add-del foo foo/bar
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents delete long packed + add short' '
+test_expect_success 'D/F conflict prevents delete long packed + add short' - <<\EOT
df_test refs/df-dlp-as --pack --del-add foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents delete short packed + add long' '
+test_expect_success 'D/F conflict prevents delete short packed + add long' - <<\EOT
df_test refs/df-dsp-al --pack --del-add foo foo/bar
-'
+EOT
# Try some combinations involving symbolic refs...
-test_expect_success REFFILES 'D/F conflict prevents indirect add long + delete short' '
+test_expect_success 'D/F conflict prevents indirect add long + delete short' - <<\EOT
df_test refs/df-ial-ds --sym-add --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents indirect add long + indirect delete short' '
+test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' - <<\EOT
df_test refs/df-ial-ids --sym-add --sym-del --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents indirect add short + indirect delete long' '
+test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' - <<\EOT
df_test refs/df-ias-idl --sym-add --sym-del --add-del foo foo/bar
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents indirect delete long + indirect add short' '
+test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' - <<\EOT
df_test refs/df-idl-ias --sym-add --sym-del --del-add foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents indirect add long + delete short packed' '
+test_expect_success 'D/F conflict prevents indirect add long + delete short packed' - <<\EOT
df_test refs/df-ial-dsp --sym-add --pack --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents indirect add long + indirect delete short packed' '
+test_expect_success 'D/F conflict prevents indirect add long + indirect delete short packed' - <<\EOT
df_test refs/df-ial-idsp --sym-add --sym-del --pack --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents add long + indirect delete short packed' '
+test_expect_success 'D/F conflict prevents add long + indirect delete short packed' - <<\EOT
df_test refs/df-al-idsp --sym-del --pack --add-del foo/bar foo
-'
+EOT
-test_expect_success REFFILES 'D/F conflict prevents indirect delete long packed + indirect add short' '
+test_expect_success 'D/F conflict prevents indirect delete long packed + indirect add short' - <<\EOT
df_test refs/df-idlp-ias --sym-add --sym-del --pack --del-add foo/bar foo
-'
+EOT
# Test various errors when reading the old values of references...
-test_expect_success 'missing old value blocks update' '
+test_expect_success 'missing old value blocks update' - <<\EOT
prefix=refs/missing-update &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ
+ fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo'
EOF
printf "%s\n" "update $prefix/foo $E $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'incorrect old value blocks update' '
+test_expect_success 'incorrect old value blocks update' - <<\EOT
prefix=refs/incorrect-update &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D
+ fatal: cannot lock ref '$prefix/foo': is at $C but expected $D
EOF
printf "%s\n" "update $prefix/foo $E $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'existing old value blocks create' '
+test_expect_success 'existing old value blocks create' - <<\EOT
prefix=refs/existing-create &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: reference already exists
+ fatal: cannot lock ref '$prefix/foo': reference already exists
EOF
printf "%s\n" "create $prefix/foo $E" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'incorrect old value blocks delete' '
+test_expect_success 'incorrect old value blocks delete' - <<\EOT
prefix=refs/incorrect-delete &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D
+ fatal: cannot lock ref '$prefix/foo': is at $C but expected $D
EOF
printf "%s\n" "delete $prefix/foo $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'missing old value blocks indirect update' '
+test_expect_success 'missing old value blocks indirect update' - <<\EOT
prefix=refs/missing-indirect-update &&
git symbolic-ref $prefix/symref $prefix/foo &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ
+ fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo'
EOF
printf "%s\n" "update $prefix/symref $E $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'incorrect old value blocks indirect update' '
+test_expect_success 'incorrect old value blocks indirect update' - <<\EOT
prefix=refs/incorrect-indirect-update &&
git symbolic-ref $prefix/symref $prefix/foo &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
+ fatal: cannot lock ref '$prefix/symref': is at $C but expected $D
EOF
printf "%s\n" "update $prefix/symref $E $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'existing old value blocks indirect create' '
+test_expect_success 'existing old value blocks indirect create' - <<\EOT
prefix=refs/existing-indirect-create &&
git symbolic-ref $prefix/symref $prefix/foo &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists
+ fatal: cannot lock ref '$prefix/symref': reference already exists
EOF
printf "%s\n" "create $prefix/symref $E" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'incorrect old value blocks indirect delete' '
+test_expect_success 'incorrect old value blocks indirect delete' - <<\EOT
prefix=refs/incorrect-indirect-delete &&
git symbolic-ref $prefix/symref $prefix/foo &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
+ fatal: cannot lock ref '$prefix/symref': is at $C but expected $D
EOF
printf "%s\n" "delete $prefix/symref $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'missing old value blocks indirect no-deref update' '
+test_expect_success 'missing old value blocks indirect no-deref update' - <<\EOT
prefix=refs/missing-noderef-update &&
git symbolic-ref $prefix/symref $prefix/foo &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: reference is missing but expected $D
+ fatal: cannot lock ref '$prefix/symref': reference is missing but expected $D
EOF
printf "%s\n" "option no-deref" "update $prefix/symref $E $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'incorrect old value blocks indirect no-deref update' '
+test_expect_success 'incorrect old value blocks indirect no-deref update' - <<\EOT
prefix=refs/incorrect-noderef-update &&
git symbolic-ref $prefix/symref $prefix/foo &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
+ fatal: cannot lock ref '$prefix/symref': is at $C but expected $D
EOF
printf "%s\n" "option no-deref" "update $prefix/symref $E $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'existing old value blocks indirect no-deref create' '
+test_expect_success 'existing old value blocks indirect no-deref create' - <<\EOT
prefix=refs/existing-noderef-create &&
git symbolic-ref $prefix/symref $prefix/foo &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists
+ fatal: cannot lock ref '$prefix/symref': reference already exists
EOF
printf "%s\n" "option no-deref" "create $prefix/symref $E" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
+EOT
-test_expect_success 'incorrect old value blocks indirect no-deref delete' '
+test_expect_success 'incorrect old value blocks indirect no-deref delete' - <<\EOT
prefix=refs/incorrect-noderef-delete &&
git symbolic-ref $prefix/symref $prefix/foo &&
git update-ref $prefix/foo $C &&
cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D
+ fatal: cannot lock ref '$prefix/symref': is at $C but expected $D
EOF
printf "%s\n" "option no-deref" "delete $prefix/symref $D" |
test_must_fail git update-ref --stdin 2>output.err &&
test_cmp expected output.err
-'
-
-test_expect_success REFFILES 'non-empty directory blocks create' '
- prefix=refs/ne-create &&
- mkdir -p .git/$prefix/foo/bar &&
- : >.git/$prefix/foo/bar/baz.lock &&
- test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ
- EOF
- printf "%s\n" "update $prefix/foo $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ
- EOF
- printf "%s\n" "update $prefix/foo $D $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err
-'
-
-test_expect_success REFFILES 'broken reference blocks create' '
- prefix=refs/broken-create &&
- mkdir -p .git/$prefix &&
- echo "gobbledigook" >.git/$prefix/foo &&
- test_when_finished "rm -f .git/$prefix/foo" &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
- EOF
- printf "%s\n" "update $prefix/foo $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
- EOF
- printf "%s\n" "update $prefix/foo $D $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err
-'
-
-test_expect_success REFFILES 'non-empty directory blocks indirect create' '
- prefix=refs/ne-indirect-create &&
- git symbolic-ref $prefix/symref $prefix/foo &&
- mkdir -p .git/$prefix/foo/bar &&
- : >.git/$prefix/foo/bar/baz.lock &&
- test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ
- EOF
- printf "%s\n" "update $prefix/symref $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ
- EOF
- printf "%s\n" "update $prefix/symref $D $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err
-'
-
-test_expect_success REFFILES 'broken reference blocks indirect create' '
- prefix=refs/broken-indirect-create &&
- git symbolic-ref $prefix/symref $prefix/foo &&
- echo "gobbledigook" >.git/$prefix/foo &&
- test_when_finished "rm -f .git/$prefix/foo" &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
- EOF
- printf "%s\n" "update $prefix/symref $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err &&
- cat >expected <<-EOF &&
- fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken
- EOF
- printf "%s\n" "update $prefix/symref $D $C" |
- test_must_fail git update-ref --stdin 2>output.err &&
- test_cmp expected output.err
-'
-
-test_expect_success REFFILES 'no bogus intermediate values during delete' '
- prefix=refs/slow-transaction &&
- # Set up a reference with differing loose and packed versions:
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- git update-ref $prefix/foo $D &&
- # 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 &&
- test_when_finished "rm -f .git/packed-refs.lock" &&
- {
- # Note: the following command is intentionally run in the
- # background. We increase the timeout so that `update-ref`
- # attempts to acquire the `packed-refs` lock for much longer
- # than it takes for us to do the check then delete it:
- git -c core.packedrefstimeout=30000 update-ref -d $prefix/foo &
- } &&
- pid2=$! &&
- # Give update-ref plenty of time to get to the point where it tries
- # to lock packed-refs:
- sleep 1 &&
- # Make sure that update-ref did not complete despite the lock:
- kill -0 $pid2 &&
- # Verify that the reference still has its old value:
- sha1=$(git rev-parse --verify --quiet $prefix/foo || echo undefined) &&
- case "$sha1" in
- $D)
- # This is what we hope for; it means that nothing
- # user-visible has changed yet.
- : ;;
- undefined)
- # This is not correct; it means the deletion has happened
- # already even though update-ref should not have been
- # able to acquire the lock yet.
- echo "$prefix/foo deleted prematurely" &&
- break
- ;;
- $C)
- # This value should never be seen. Probably the loose
- # reference has been deleted but the packed reference
- # is still there:
- echo "$prefix/foo incorrectly observed to be C" &&
- break
- ;;
- *)
- # WTF?
- echo "unexpected value observed for $prefix/foo: $sha1" &&
- break
- ;;
- esac >out &&
- rm -f .git/packed-refs.lock &&
- wait $pid2 &&
- test_must_be_empty out &&
- test_must_fail git rev-parse --verify --quiet $prefix/foo
-'
-
-test_expect_success REFFILES 'delete fails cleanly if packed-refs file is locked' '
- prefix=refs/locked-packed-refs &&
- # Set up a reference with differing loose and packed versions:
- 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 delete it while the `packed-refs` lock is held:
- : >.git/packed-refs.lock &&
- test_when_finished "rm -f .git/packed-refs.lock" &&
- test_must_fail git update-ref -d $prefix/foo >out 2>err &&
- git for-each-ref $prefix >actual &&
- test_i18ngrep "Unable to create $SQ.*packed-refs.lock$SQ: " err &&
- test_cmp unchanged actual
-'
-
-test_expect_success REFFILES 'delete fails cleanly if packed-refs.new write fails' '
- # Setup and expectations are similar to the test above.
- prefix=refs/failed-packed-refs &&
- git update-ref $prefix/foo $C &&
- git pack-refs --all &&
- git update-ref $prefix/foo $D &&
- git for-each-ref $prefix >unchanged &&
- # This should not happen in practice, but it is an easy way to get a
- # reliable error (we open with create_tempfile(), which uses O_EXCL).
- : >.git/packed-refs.new &&
- test_when_finished "rm -f .git/packed-refs.new" &&
- test_must_fail git update-ref -d $prefix/foo &&
- git for-each-ref $prefix >actual &&
- test_cmp unchanged actual
-'
+EOT
test_done
diff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh
index e4627cf1b6..6d8f401a2a 100755
--- a/t/t1405-main-ref-store.sh
+++ b/t/t1405-main-ref-store.sh
@@ -5,7 +5,6 @@ test_description='test main ref store api'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
RUN="test-tool ref-store main"
@@ -15,14 +14,6 @@ test_expect_success 'setup' '
test_commit one
'
-test_expect_success REFFILES 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' '
- N=`find .git/refs -type f | wc -l` &&
- test "$N" != 0 &&
- $RUN pack-refs PACK_REFS_PRUNE,PACK_REFS_ALL &&
- N=`find .git/refs -type f` &&
- test -z "$N"
-'
-
test_expect_success 'create_symref(FOO, refs/heads/main)' '
$RUN create-symref FOO refs/heads/main nothing &&
echo refs/heads/main >expected &&
@@ -41,12 +32,6 @@ test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '
test_must_fail git rev-parse refs/tags/new-tag --
'
-# In reftable, we keep the reflogs around for deleted refs.
-test_expect_success !REFFILES 'delete-reflog(FOO, refs/tags/new-tag)' '
- $RUN delete-reflog FOO &&
- $RUN delete-reflog refs/tags/new-tag
-'
-
test_expect_success 'rename_refs(main, new-main)' '
git rev-parse main >expected &&
$RUN rename-ref refs/heads/main refs/heads/new-main &&
@@ -82,11 +67,11 @@ test_expect_success 'verify_ref(new-main)' '
'
test_expect_success 'for_each_reflog()' '
- $RUN for-each-reflog | sort -k2 | cut -d" " -f 2- >actual &&
+ $RUN for-each-reflog >actual &&
cat >expected <<-\EOF &&
- HEAD 0x1
- refs/heads/main 0x0
- refs/heads/new-main 0x0
+ HEAD
+ refs/heads/main
+ refs/heads/new-main
EOF
test_cmp expected actual
'
@@ -112,7 +97,7 @@ test_expect_success 'delete_reflog(HEAD)' '
test_must_fail git reflog exists HEAD
'
-test_expect_success REFFILES 'create-reflog(HEAD)' '
+test_expect_success 'create-reflog(HEAD)' '
$RUN create-reflog HEAD &&
git reflog exists HEAD
'
diff --git a/t/t1406-submodule-ref-store.sh b/t/t1406-submodule-ref-store.sh
index e6a7f7334b..9b9e5d0766 100755
--- a/t/t1406-submodule-ref-store.sh
+++ b/t/t1406-submodule-ref-store.sh
@@ -5,7 +5,6 @@ test_description='test submodule ref store api'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
RUN="test-tool ref-store submodule:sub"
@@ -63,11 +62,11 @@ test_expect_success 'verify_ref(new-main)' '
'
test_expect_success 'for_each_reflog()' '
- $RUN for-each-reflog | sort | cut -d" " -f 2- >actual &&
+ $RUN for-each-reflog >actual &&
cat >expected <<-\EOF &&
- HEAD 0x1
- refs/heads/main 0x0
- refs/heads/new-main 0x0
+ HEAD
+ refs/heads/main
+ refs/heads/new-main
EOF
test_cmp expected actual
'
diff --git a/t/t1407-worktree-ref-store.sh b/t/t1407-worktree-ref-store.sh
index 05b1881c59..9d8e1a1343 100755
--- a/t/t1407-worktree-ref-store.sh
+++ b/t/t1407-worktree-ref-store.sh
@@ -5,7 +5,6 @@ test_description='test worktree ref store api'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
RWT="test-tool ref-store worktree:wt"
@@ -53,41 +52,4 @@ test_expect_success 'create_symref(FOO, refs/heads/main)' '
test_cmp expected actual
'
-# Some refs (refs/bisect/*, pseudorefs) are kept per worktree, so they should
-# only appear in the for-each-reflog output if it is called from the correct
-# worktree, which is exercised in this test. This test is poorly written (and
-# therefore marked REFFILES) for mulitple reasons: 1) it creates invalidly
-# formatted log entres. 2) it uses direct FS access for creating the reflogs. 3)
-# PSEUDO-WT and refs/bisect/random do not create reflogs by default, so it is
-# not testing a realistic scenario.
-test_expect_success REFFILES 'for_each_reflog()' '
- echo $ZERO_OID > .git/logs/PSEUDO-MAIN &&
- mkdir -p .git/logs/refs/bisect &&
- echo $ZERO_OID > .git/logs/refs/bisect/random &&
-
- echo $ZERO_OID > .git/worktrees/wt/logs/PSEUDO-WT &&
- mkdir -p .git/worktrees/wt/logs/refs/bisect &&
- echo $ZERO_OID > .git/worktrees/wt/logs/refs/bisect/wt-random &&
-
- $RWT for-each-reflog | cut -d" " -f 2- | sort >actual &&
- cat >expected <<-\EOF &&
- HEAD 0x1
- PSEUDO-WT 0x0
- refs/bisect/wt-random 0x0
- refs/heads/main 0x0
- refs/heads/wt-main 0x0
- EOF
- test_cmp expected actual &&
-
- $RMAIN for-each-reflog | cut -d" " -f 2- | sort >actual &&
- cat >expected <<-\EOF &&
- HEAD 0x1
- PSEUDO-MAIN 0x0
- refs/bisect/random 0x0
- refs/heads/main 0x0
- refs/heads/wt-main 0x0
- EOF
- test_cmp expected actual
-'
-
test_done
diff --git a/t/t1408-packed-refs.sh b/t/t1408-packed-refs.sh
index 9469c79a58..41ba1f1d7f 100755
--- a/t/t1408-packed-refs.sh
+++ b/t/t1408-packed-refs.sh
@@ -5,7 +5,6 @@ test_description='packed-refs entries are covered by loose refs'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t1409-avoid-packing-refs.sh b/t/t1409-avoid-packing-refs.sh
index f23c0152a8..e3c501848a 100755
--- a/t/t1409-avoid-packing-refs.sh
+++ b/t/t1409-avoid-packing-refs.sh
@@ -2,9 +2,14 @@
test_description='avoid rewriting packed-refs unnecessarily'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
+if test_have_prereq !REFFILES
+then
+ skip_all='skipping files-backend specific pack-refs tests'
+ test_done
+fi
+
# Add an identifying mark to the packed-refs file header line. This
# shouldn't upset readers, and it should be omitted if the file is
# ever rewritten.
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 6c45965b1e..388fdf9ae5 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -7,7 +7,6 @@ test_description='Test prune and reflog expiration'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_have () {
@@ -29,7 +28,7 @@ check_fsck () {
'')
test_must_be_empty fsck.output ;;
*)
- test_i18ngrep "$1" fsck.output ;;
+ test_grep "$1" fsck.output ;;
esac
}
@@ -146,6 +145,14 @@ test_expect_success rewind '
test_line_count = 5 output
'
+test_expect_success 'reflog expire should not barf on an annotated tag' '
+ test_when_finished "git tag -d v0.tag || :" &&
+ git -c core.logAllRefUpdates=always \
+ tag -a -m "tag name" v0.tag main &&
+ git reflog expire --dry-run refs/tags/v0.tag 2>err &&
+ test_grep ! "error: [Oo]bject .* not a commit" err
+'
+
test_expect_success 'corrupt and check' '
corrupt $F &&
@@ -308,9 +315,9 @@ test_expect_success 'git reflog expire unknown reference' '
test_config gc.reflogexpireunreachable never &&
test_must_fail git reflog expire main@{123} 2>stderr &&
- test_i18ngrep "points nowhere" stderr &&
+ test_grep "points nowhere" stderr &&
test_must_fail git reflog expire does-not-exist 2>stderr &&
- test_i18ngrep "points nowhere" stderr
+ test_grep "points nowhere" stderr
'
test_expect_success 'checkout should not delete log for packed ref' '
@@ -354,36 +361,6 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' '
test_must_be_empty actual
'
-# Triggering the bug detected by this test requires a newline to fall
-# exactly BUFSIZ-1 bytes from the end of the file. We don't know
-# what that value is, since it's platform dependent. However, if
-# we choose some value N, we also catch any D which divides N evenly
-# (since we will read backwards in chunks of D). So we choose 8K,
-# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
-#
-# Each line is 114 characters, so we need 75 to still have a few before the
-# last 8K. The 89-character padding on the final entry lines up our
-# newline exactly.
-test_expect_success REFFILES,SHA1 'parsing reverse reflogs at BUFSIZ boundaries' '
- git checkout -b reflogskip &&
- zf=$(test_oid zero_2) &&
- ident="abc <xyz> 0000000001 +0000" &&
- for i in $(test_seq 1 75); do
- printf "$zf%02d $zf%02d %s\t" $i $(($i+1)) "$ident" &&
- if test $i = 75; then
- for j in $(test_seq 1 89); do
- printf X || return 1
- done
- else
- printf X
- fi &&
- printf "\n" || return 1
- done >.git/logs/refs/heads/reflogskip &&
- git rev-parse reflogskip@{73} >actual &&
- echo ${zf}03 >expect &&
- test_cmp expect actual
-'
-
test_expect_success 'no segfaults for reflog containing non-commit sha1s' '
git update-ref --create-reflog -m "Creating ref" \
refs/tests/tree-in-reflog HEAD &&
@@ -397,18 +374,6 @@ test_expect_failure 'reflog with non-commit entries displays all entries' '
test_line_count = 3 actual
'
-# This test takes a lock on an individual ref; this is not supported in
-# reftable.
-test_expect_success REFFILES 'reflog expire operates on symref not referrent' '
- git branch --create-reflog the_symref &&
- git branch --create-reflog referrent &&
- git update-ref referrent HEAD &&
- git symbolic-ref refs/heads/the_symref refs/heads/referrent &&
- test_when_finished "rm -f .git/refs/heads/referrent.lock" &&
- touch .git/refs/heads/referrent.lock &&
- git reflog expire --expire=all the_symref
-'
-
test_expect_success 'continue walking past root commits' '
git init orphanage &&
(
@@ -446,13 +411,144 @@ test_expect_success 'expire with multiple worktrees' '
)
'
-test_expect_success REFFILES 'empty reflog' '
+test_expect_success 'expire one of multiple worktrees' '
+ git init main-wt2 &&
+ (
+ cd main-wt2 &&
+ test_tick &&
+ test_commit foo &&
+ git worktree add link-wt &&
+ test_tick &&
+ test_commit -C link-wt foobar &&
+ test_tick &&
+ test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \
+ >expect-link-wt &&
+ git reflog expire --verbose --all --expire=$test_tick \
+ --single-worktree &&
+ test-tool ref-store worktree:main for-each-reflog-ent HEAD \
+ >actual-main &&
+ test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \
+ >actual-link-wt &&
+ test_must_be_empty actual-main &&
+ test_cmp expect-link-wt actual-link-wt
+ )
+'
+
+test_expect_success 'empty reflog' '
test_when_finished "rm -rf empty" &&
git init empty &&
test_commit -C empty A &&
- >empty/.git/logs/refs/heads/foo &&
+ test-tool ref-store main create-reflog refs/heads/foo &&
git -C empty reflog expire --all 2>err &&
test_must_be_empty err
'
+test_expect_success 'list reflogs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git reflog list >actual &&
+ test_must_be_empty actual &&
+
+ test_commit A &&
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/main
+ EOF
+ git reflog list >actual &&
+ test_cmp expect actual &&
+
+ git branch b &&
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/b
+ refs/heads/main
+ EOF
+ git reflog list >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'list reflogs with worktree' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ git worktree add wt &&
+ git -c core.logAllRefUpdates=always \
+ update-ref refs/worktree/main HEAD &&
+ git -c core.logAllRefUpdates=always \
+ update-ref refs/worktree/per-worktree HEAD &&
+ git -c core.logAllRefUpdates=always -C wt \
+ update-ref refs/worktree/per-worktree HEAD &&
+ git -c core.logAllRefUpdates=always -C wt \
+ update-ref refs/worktree/worktree HEAD &&
+
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/main
+ refs/heads/wt
+ refs/worktree/main
+ refs/worktree/per-worktree
+ EOF
+ git reflog list >actual &&
+ test_cmp expect actual &&
+
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/main
+ refs/heads/wt
+ refs/worktree/per-worktree
+ refs/worktree/worktree
+ EOF
+ git -C wt reflog list >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'reflog list returns error with additional args' '
+ cat >expect <<-EOF &&
+ error: list does not accept arguments: ${SQ}bogus${SQ}
+ EOF
+ test_must_fail git reflog list bogus 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'reflog for symref with unborn target can be listed' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ git symbolic-ref HEAD refs/heads/unborn &&
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/main
+ EOF
+ git reflog list >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'reflog with invalid object ID can be listed' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ test-tool ref-store main update-ref msg refs/heads/missing \
+ $(test_oid deadbeef) "$ZERO_OID" REF_SKIP_OID_VERIFICATION &&
+ cat >expect <<-EOF &&
+ HEAD
+ refs/heads/main
+ refs/heads/missing
+ EOF
+ git reflog list >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index da581ec19a..975c4ea83a 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -4,7 +4,6 @@ test_description='Test reflog display routines'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t1412-reflog-loop.sh b/t/t1412-reflog-loop.sh
index ff30874f94..f7d69b66ff 100755
--- a/t/t1412-reflog-loop.sh
+++ b/t/t1412-reflog-loop.sh
@@ -2,7 +2,6 @@
test_description='reflog walk shows repeated commits again'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup commits' '
diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh
index d2a4822d46..934688a1ee 100755
--- a/t/t1413-reflog-detach.sh
+++ b/t/t1413-reflog-detach.sh
@@ -4,7 +4,6 @@ test_description='Test reflog interaction with detached HEAD'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
reset_state () {
diff --git a/t/t1414-reflog-walk.sh b/t/t1414-reflog-walk.sh
index ea64cecf47..be6c3f472c 100755
--- a/t/t1414-reflog-walk.sh
+++ b/t/t1414-reflog-walk.sh
@@ -121,13 +121,12 @@ test_expect_success 'min/max age uses entry date to limit' '
# Create a situation where the reflog and ref database disagree about the latest
# state of HEAD.
-test_expect_success REFFILES 'walk prefers reflog to ref tip' '
+test_expect_success 'walk prefers reflog to ref tip' '
+ test_commit A &&
+ test_commit B &&
+ git reflog delete HEAD@{0} &&
head=$(git rev-parse HEAD) &&
- one=$(git rev-parse one) &&
- ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" &&
- echo "$head $one $ident broken reflog entry" >>.git/logs/HEAD &&
-
- echo $one >expect &&
+ git rev-parse A >expect &&
git log -g --format=%H -1 >actual &&
test_cmp expect actual
'
diff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh
index 3b531842dd..51d79bae83 100755
--- a/t/t1415-worktree-refs.sh
+++ b/t/t1415-worktree-refs.sh
@@ -2,7 +2,6 @@
test_description='per-worktree refs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -17,17 +16,6 @@ test_expect_success 'setup' '
git -C wt2 update-ref refs/worktree/foo HEAD
'
-# The 'packed-refs' file is stored directly in .git/. This means it is global
-# to the repository, and can only contain refs that are shared across all
-# worktrees.
-test_expect_success REFFILES 'refs/worktree must not be packed' '
- git pack-refs --all &&
- test_path_is_missing .git/refs/tags/wt1 &&
- test_path_is_file .git/refs/worktree/foo &&
- test_path_is_file .git/worktrees/wt1/refs/worktree/foo &&
- test_path_is_file .git/worktrees/wt2/refs/worktree/foo
-'
-
test_expect_success 'refs/worktree are per-worktree' '
test_cmp_rev worktree/foo initial &&
( cd wt1 && test_cmp_rev worktree/foo wt1 ) &&
diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh
index b32ca798f9..8c777f7cf8 100755
--- a/t/t1416-ref-transaction-hooks.sh
+++ b/t/t1416-ref-transaction-hooks.sh
@@ -5,7 +5,6 @@ test_description='reference transaction 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 '
@@ -37,7 +36,7 @@ test_expect_success 'hook aborts updating ref in prepared state' '
fi
EOF
test_must_fail git update-ref HEAD POST 2>err &&
- test_i18ngrep "ref updates aborted by hook" err
+ test_grep "ref updates aborted by hook" err
'
test_expect_success 'hook gets all queued updates in prepared state' '
@@ -53,7 +52,6 @@ test_expect_success 'hook gets all queued updates in prepared state' '
fi
EOF
cat >expect <<-EOF &&
- $ZERO_OID $POST_OID HEAD
$ZERO_OID $POST_OID refs/heads/main
EOF
git update-ref HEAD POST <<-EOF &&
@@ -76,7 +74,6 @@ test_expect_success 'hook gets all queued updates in committed state' '
fi
EOF
cat >expect <<-EOF &&
- $ZERO_OID $POST_OID HEAD
$ZERO_OID $POST_OID refs/heads/main
EOF
git update-ref HEAD POST &&
@@ -134,4 +131,81 @@ test_expect_success 'interleaving hook calls succeed' '
test_cmp expect target-repo.git/actual
'
+test_expect_success 'hook captures git-symbolic-ref updates' '
+ test_when_finished "rm actual" &&
+
+ test_hook reference-transaction <<-\EOF &&
+ echo "$*" >>actual
+ while read -r line
+ do
+ printf "%s\n" "$line"
+ done >>actual
+ EOF
+
+ git symbolic-ref refs/heads/symref refs/heads/main &&
+
+ cat >expect <<-EOF &&
+ prepared
+ $ZERO_OID ref:refs/heads/main refs/heads/symref
+ committed
+ $ZERO_OID ref:refs/heads/main refs/heads/symref
+ EOF
+
+ test_cmp expect actual
+'
+
+test_expect_success 'hook gets all queued symref updates' '
+ test_when_finished "rm actual" &&
+
+ git update-ref refs/heads/branch $POST_OID &&
+ git symbolic-ref refs/heads/symref refs/heads/main &&
+ git symbolic-ref refs/heads/symrefd refs/heads/main &&
+ git symbolic-ref refs/heads/symrefu refs/heads/main &&
+
+ test_hook reference-transaction <<-\EOF &&
+ echo "$*" >>actual
+ while read -r line
+ do
+ printf "%s\n" "$line"
+ done >>actual
+ EOF
+
+ # In the files backend, "delete" also triggers an additional transaction
+ # update on the packed-refs backend, which constitutes additional reflog
+ # entries.
+ if test_have_prereq REFFILES
+ then
+ cat >expect <<-EOF
+ aborted
+ $ZERO_OID $ZERO_OID refs/heads/symrefd
+ EOF
+ else
+ >expect
+ fi &&
+
+ cat >>expect <<-EOF &&
+ prepared
+ ref:refs/heads/main $ZERO_OID refs/heads/symref
+ ref:refs/heads/main $ZERO_OID refs/heads/symrefd
+ $ZERO_OID ref:refs/heads/main refs/heads/symrefc
+ ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu
+ committed
+ ref:refs/heads/main $ZERO_OID refs/heads/symref
+ ref:refs/heads/main $ZERO_OID refs/heads/symrefd
+ $ZERO_OID ref:refs/heads/main refs/heads/symrefc
+ ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu
+ EOF
+
+ git update-ref --no-deref --stdin <<-EOF &&
+ start
+ symref-verify refs/heads/symref refs/heads/main
+ symref-delete refs/heads/symrefd refs/heads/main
+ symref-create refs/heads/symrefc refs/heads/main
+ symref-update refs/heads/symrefu refs/heads/branch ref refs/heads/main
+ prepare
+ commit
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1417-reflog-updateref.sh b/t/t1417-reflog-updateref.sh
index 14f13b57c6..2f37402536 100755
--- a/t/t1417-reflog-updateref.sh
+++ b/t/t1417-reflog-updateref.sh
@@ -2,7 +2,6 @@
test_description='git reflog --updateref'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -14,9 +13,13 @@ test_expect_success 'setup' '
test_commit B &&
test_commit C &&
- cp .git/logs/HEAD HEAD.old &&
+ git reflog HEAD >expect &&
git reset --hard HEAD~ &&
- cp HEAD.old .git/logs/HEAD
+ # Make sure that the reflog does not point to the same commit
+ # as HEAD.
+ git reflog delete HEAD@{0} &&
+ git reflog HEAD >actual &&
+ test_cmp expect actual
)
'
@@ -25,7 +28,7 @@ test_reflog_updateref () {
shift
args="$@"
- test_expect_success REFFILES "get '$exp' with '$args'" '
+ test_expect_success "get '$exp' with '$args'" '
test_when_finished "rm -rf copy" &&
cp -R repo copy &&
diff --git a/t/t1418-reflog-exists.sh b/t/t1418-reflog-exists.sh
index 2268bca3c1..d51ecd5e92 100755
--- a/t/t1418-reflog-exists.sh
+++ b/t/t1418-reflog-exists.sh
@@ -4,7 +4,6 @@ test_description='Test reflog display routines'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t1419-exclude-refs.sh b/t/t1419-exclude-refs.sh
index 5d8c86b657..c04eeb7211 100755
--- a/t/t1419-exclude-refs.sh
+++ b/t/t1419-exclude-refs.sh
@@ -5,7 +5,6 @@ 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 () {
@@ -22,7 +21,14 @@ assert_jumps () {
local nr="$1"
local trace="$2"
- grep -q "name:jumps_made value:$nr$" $trace
+ case "$GIT_DEFAULT_REF_FORMAT" in
+ files)
+ grep -q "name:jumps_made value:$nr$" $trace;;
+ reftable)
+ grep -q "name:reseeks_made value:$nr$" $trace;;
+ *)
+ BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+ esac
}
assert_no_jumps () {
@@ -83,7 +89,14 @@ test_expect_success 'adjacent, non-overlapping excluded regions' '
for_each_ref refs/heads/foo refs/heads/quux >expect &&
test_cmp expect actual &&
- assert_jumps 1 perf
+ case "$GIT_DEFAULT_REF_FORMAT" in
+ files)
+ assert_jumps 1 perf;;
+ reftable)
+ assert_jumps 2 perf;;
+ *)
+ BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+ esac
'
test_expect_success 'overlapping excluded regions' '
@@ -100,7 +113,30 @@ test_expect_success 'several overlapping excluded regions' '
for_each_ref refs/heads/quux >expect &&
test_cmp expect actual &&
- assert_jumps 1 perf
+ case "$GIT_DEFAULT_REF_FORMAT" in
+ files)
+ assert_jumps 1 perf;;
+ reftable)
+ assert_jumps 3 perf;;
+ *)
+ BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+ esac
+'
+
+test_expect_success 'unordered excludes' '
+ for_each_ref__exclude refs/heads \
+ refs/heads/foo refs/heads/baz >actual 2>perf &&
+ for_each_ref refs/heads/bar refs/heads/quux >expect &&
+
+ test_cmp expect actual &&
+ case "$GIT_DEFAULT_REF_FORMAT" in
+ files)
+ assert_jumps 1 perf;;
+ reftable)
+ assert_jumps 2 perf;;
+ *)
+ BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+ esac
'
test_expect_success 'non-matching excluded section' '
diff --git a/t/t1420-lost-found.sh b/t/t1420-lost-found.sh
index dbe15a0be1..2fb2f44f02 100755
--- a/t/t1420-lost-found.sh
+++ b/t/t1420-lost-found.sh
@@ -5,7 +5,6 @@
test_description='Test fsck --lost-found'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index ff1c967d55..3ab65f72cd 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -4,7 +4,6 @@ test_description='Test handling of ref names that check-ref-format rejects'
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 '
@@ -47,7 +46,7 @@ test_expect_success 'git branch shows badly named ref as warning' '
test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
git branch >output 2>error &&
- test_i18ngrep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
+ test_grep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
! grep -e "broken\.\.\.ref" output
'
@@ -158,23 +157,23 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '
git rev-parse --verify one >expect &&
git rev-parse --verify shadow >actual 2>err &&
test_cmp expect actual &&
- test_i18ngrep "ignoring dangling symref refs/tags/shadow" err
+ test_grep "ignoring dangling symref refs/tags/shadow" err
'
test_expect_success 'for-each-ref emits warnings for broken names' '
test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
- printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
+ test-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname" &&
- printf "ref: refs/heads/main\n" >.git/refs/heads/broken...symref &&
+ test-tool ref-store main create-symref refs/heads/broken...symref refs/heads/main &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref" &&
git for-each-ref >output 2>error &&
! grep -e "broken\.\.\.ref" output &&
! grep -e "badname" output &&
! grep -e "broken\.\.\.symref" output &&
- test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
- test_i18ngrep ! "ignoring broken ref refs/heads/badname" error &&
- test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.symref" error
+ test_grep "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
+ test_grep ! "ignoring broken ref refs/heads/badname" error &&
+ test_grep "ignoring ref with broken name refs/heads/broken\.\.\.symref" error
'
test_expect_success 'update-ref -d can delete broken name' '
@@ -192,7 +191,7 @@ test_expect_success 'branch -d can delete broken name' '
test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
git branch -d broken...ref >output 2>error &&
- test_i18ngrep "Deleted branch broken...ref (was broken)" output &&
+ test_grep "Deleted branch broken...ref (was broken)" output &&
test_must_be_empty error &&
git branch >output 2>error &&
! grep -e "broken\.\.\.ref" error &&
@@ -205,8 +204,9 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
test-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname" &&
+ test_ref_exists refs/heads/badname &&
git update-ref --no-deref -d refs/heads/badname >output 2>error &&
- test_path_is_missing .git/refs/heads/badname &&
+ test_ref_missing refs/heads/badname &&
test_must_be_empty output &&
test_must_be_empty error
'
@@ -216,17 +216,19 @@ test_expect_success 'branch -d can delete symref to broken name' '
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
test-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname" &&
+ test_ref_exists refs/heads/badname &&
git branch -d badname >output 2>error &&
- test_path_is_missing .git/refs/heads/badname &&
- test_i18ngrep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output &&
+ test_ref_missing refs/heads/badname &&
+ test_grep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output &&
test_must_be_empty error
'
test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '
test-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname" &&
+ test_ref_exists refs/heads/badname &&
git update-ref --no-deref -d refs/heads/badname >output 2>error &&
- test_path_is_missing .git/refs/heads/badname &&
+ test_ref_missing refs/heads/badname &&
test_must_be_empty output &&
test_must_be_empty error
'
@@ -234,9 +236,10 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok
test_expect_success 'branch -d can delete dangling symref to broken name' '
test-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname" &&
+ test_ref_exists refs/heads/badname &&
git branch -d badname >output 2>error &&
- test_path_is_missing .git/refs/heads/badname &&
- test_i18ngrep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output &&
+ test_ref_missing refs/heads/badname &&
+ test_grep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output &&
test_must_be_empty error
'
@@ -245,45 +248,50 @@ test_expect_success 'update-ref -d can delete broken name through symref' '
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
test-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname" &&
+ test_ref_exists refs/heads/broken...ref &&
git update-ref -d refs/heads/badname >output 2>error &&
- test_path_is_missing .git/refs/heads/broken...ref &&
+ test_ref_missing refs/heads/broken...ref &&
test_must_be_empty output &&
test_must_be_empty error
'
test_expect_success 'update-ref --no-deref -d can delete symref with broken name' '
- printf "ref: refs/heads/main\n" >.git/refs/heads/broken...symref &&
+ test-tool ref-store main create-symref refs/heads/broken...symref refs/heads/main &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref" &&
+ test_ref_exists refs/heads/broken...symref &&
git update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&
- test_path_is_missing .git/refs/heads/broken...symref &&
+ test_ref_missing refs/heads/broken...symref &&
test_must_be_empty output &&
test_must_be_empty error
'
test_expect_success 'branch -d can delete symref with broken name' '
- printf "ref: refs/heads/main\n" >.git/refs/heads/broken...symref &&
+ test-tool ref-store main create-symref refs/heads/broken...symref refs/heads/main &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref" &&
+ test_ref_exists refs/heads/broken...symref &&
git branch -d broken...symref >output 2>error &&
- test_path_is_missing .git/refs/heads/broken...symref &&
- test_i18ngrep "Deleted branch broken...symref (was refs/heads/main)" output &&
+ test_ref_missing refs/heads/broken...symref &&
+ test_grep "Deleted branch broken...symref (was refs/heads/main)" output &&
test_must_be_empty error
'
test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' '
- printf "ref: refs/heads/idonotexist\n" >.git/refs/heads/broken...symref &&
+ test-tool ref-store main create-symref refs/heads/broken...symref refs/heads/idonotexist &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref" &&
+ test_ref_exists refs/heads/broken...symref &&
git update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&
- test_path_is_missing .git/refs/heads/broken...symref &&
+ test_ref_missing refs/heads/broken...symref &&
test_must_be_empty output &&
test_must_be_empty error
'
test_expect_success 'branch -d can delete dangling symref with broken name' '
- printf "ref: refs/heads/idonotexist\n" >.git/refs/heads/broken...symref &&
+ test-tool ref-store main create-symref refs/heads/broken...symref refs/heads/idonotexist &&
test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref" &&
+ test_ref_exists refs/heads/broken...symref &&
git branch -d broken...symref >output 2>error &&
- test_path_is_missing .git/refs/heads/broken...symref &&
- test_i18ngrep "Deleted branch broken...symref (was refs/heads/idonotexist)" output &&
+ test_ref_missing refs/heads/broken...symref &&
+ test_grep "Deleted branch broken...symref (was refs/heads/idonotexist)" output &&
test_must_be_empty error
'
@@ -292,7 +300,7 @@ test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
echo precious >expect &&
test_must_fail git update-ref -d my-private-file >output 2>error &&
test_must_be_empty output &&
- test_i18ngrep -e "refusing to update ref with bad name" error &&
+ test_grep -e "refusing to update ref with bad name" error &&
test_cmp expect .git/my-private-file
'
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 5805d47eb9..8a456b1142 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -15,6 +15,7 @@ test_expect_success setup '
git config --unset i18n.commitencoding &&
git checkout HEAD^0 &&
test_commit B fileB two &&
+ orig_head=$(git rev-parse HEAD) &&
git tag -d A B &&
git reflog expire --expire=now --all
'
@@ -115,63 +116,62 @@ test_expect_success 'zlib corrupt loose object output ' '
'
test_expect_success 'branch pointing to non-commit' '
- git rev-parse HEAD^{tree} >.git/refs/heads/invalid &&
+ tree_oid=$(git rev-parse --verify HEAD^{tree}) &&
test_when_finished "git update-ref -d refs/heads/invalid" &&
+ test-tool ref-store main update-ref msg refs/heads/invalid $tree_oid $ZERO_OID REF_SKIP_OID_VERIFICATION &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "not a commit" out
+ test_grep "not a commit" out
'
-test_expect_success 'HEAD link pointing at a funny object' '
- test_when_finished "mv .git/SAVED_HEAD .git/HEAD" &&
- mv .git/HEAD .git/SAVED_HEAD &&
+test_expect_success REFFILES 'HEAD link pointing at a funny object' '
+ test_when_finished "git update-ref HEAD $orig_head" &&
echo $ZERO_OID >.git/HEAD &&
# avoid corrupt/broken HEAD from interfering with repo discovery
test_must_fail env GIT_DIR=.git git fsck 2>out &&
- test_i18ngrep "detached HEAD points" out
+ test_grep "detached HEAD points" out
'
test_expect_success 'HEAD link pointing at a funny place' '
- test_when_finished "mv .git/SAVED_HEAD .git/HEAD" &&
- mv .git/HEAD .git/SAVED_HEAD &&
- echo "ref: refs/funny/place" >.git/HEAD &&
+ test_when_finished "git update-ref --no-deref HEAD $orig_head" &&
+ test-tool ref-store main create-symref HEAD refs/funny/place &&
# avoid corrupt/broken HEAD from interfering with repo discovery
test_must_fail env GIT_DIR=.git git fsck 2>out &&
- test_i18ngrep "HEAD points to something strange" out
+ test_grep "HEAD points to something strange" out
'
-test_expect_success 'HEAD link pointing at a funny object (from different wt)' '
- test_when_finished "mv .git/SAVED_HEAD .git/HEAD" &&
- test_when_finished "rm -rf .git/worktrees wt" &&
+test_expect_success REFFILES 'HEAD link pointing at a funny object (from different wt)' '
+ test_when_finished "git update-ref HEAD $orig_head" &&
+ test_when_finished "git worktree remove -f wt" &&
git worktree add wt &&
- mv .git/HEAD .git/SAVED_HEAD &&
echo $ZERO_OID >.git/HEAD &&
# avoid corrupt/broken HEAD from interfering with repo discovery
test_must_fail git -C wt fsck 2>out &&
- test_i18ngrep "main-worktree/HEAD: detached HEAD points" out
+ test_grep "main-worktree/HEAD: detached HEAD points" out
'
-test_expect_success 'other worktree HEAD link pointing at a funny object' '
- test_when_finished "rm -rf .git/worktrees other" &&
+test_expect_success REFFILES 'other worktree HEAD link pointing at a funny object' '
+ test_when_finished "git worktree remove -f other" &&
git worktree add other &&
echo $ZERO_OID >.git/worktrees/other/HEAD &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "worktrees/other/HEAD: detached HEAD points" out
+ test_grep "worktrees/other/HEAD: detached HEAD points" out
'
test_expect_success 'other worktree HEAD link pointing at missing object' '
- test_when_finished "rm -rf .git/worktrees other" &&
+ test_when_finished "git worktree remove -f other" &&
git worktree add other &&
- echo "Contents missing from repo" | git hash-object --stdin >.git/worktrees/other/HEAD &&
+ object_id=$(echo "Contents missing from repo" | git hash-object --stdin) &&
+ test-tool -C other ref-store main update-ref msg HEAD $object_id "" REF_NO_DEREF,REF_SKIP_OID_VERIFICATION &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "worktrees/other/HEAD: invalid sha1 pointer" out
+ test_grep "worktrees/other/HEAD: invalid sha1 pointer" out
'
test_expect_success 'other worktree HEAD link pointing at a funny place' '
- test_when_finished "rm -rf .git/worktrees other" &&
+ test_when_finished "git worktree remove -f other" &&
git worktree add other &&
- echo "ref: refs/funny/place" >.git/worktrees/other/HEAD &&
+ git -C other symbolic-ref HEAD refs/funny/place &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "worktrees/other/HEAD points to something strange" out
+ test_grep "worktrees/other/HEAD points to something strange" out
'
test_expect_success 'commit with multiple signatures is okay' '
@@ -217,7 +217,7 @@ test_expect_success 'email with embedded > is not okay' '
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $new" out
+ test_grep "error in commit $new" out
'
test_expect_success 'missing < email delimiter is reported nicely' '
@@ -228,7 +228,7 @@ test_expect_success 'missing < email delimiter is reported nicely' '
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $new.* - bad name" out
+ test_grep "error in commit $new.* - bad name" out
'
test_expect_success 'missing email is reported nicely' '
@@ -239,7 +239,7 @@ test_expect_success 'missing email is reported nicely' '
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $new.* - missing email" out
+ test_grep "error in commit $new.* - missing email" out
'
test_expect_success '> in name is reported' '
@@ -250,7 +250,7 @@ test_expect_success '> in name is reported' '
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $new" out
+ test_grep "error in commit $new" out
'
# date is 2^64 + 1
@@ -263,7 +263,7 @@ test_expect_success 'integer overflow in timestamps is reported' '
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $new.*integer overflow" out
+ test_grep "error in commit $new.*integer overflow" out
'
test_expect_success 'commit with NUL in header' '
@@ -274,7 +274,7 @@ test_expect_success 'commit with NUL in header' '
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $new.*unterminated header: NUL at offset" out
+ test_grep "error in commit $new.*unterminated header: NUL at offset" out
'
test_expect_success 'tree object with duplicate entries' '
@@ -295,7 +295,7 @@ test_expect_success 'tree object with duplicate entries' '
git hash-object --literally -w -t tree --stdin
) &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in tree .*contains duplicate file entries" out
+ test_grep "error in tree .*contains duplicate file entries" out
'
check_duplicate_names () {
@@ -318,8 +318,8 @@ check_duplicate_names () {
done >badtree &&
badtree=$(git mktree <badtree) &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "$badtree" out &&
- test_i18ngrep "error in tree .*contains duplicate file entries" out
+ test_grep "$badtree" out &&
+ test_grep "error in tree .*contains duplicate file entries" out
'
}
@@ -341,9 +341,9 @@ test_expect_success 'unparseable tree object' '
commit_sha1=$(git commit-tree $tree_sha1) &&
git update-ref refs/heads/wrong $commit_sha1 &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error: empty filename in tree entry" out &&
- test_i18ngrep "$tree_sha1" out &&
- test_i18ngrep ! "fatal: empty filename in tree entry" out
+ test_grep "error: empty filename in tree entry" out &&
+ test_grep "$tree_sha1" out &&
+ test_grep ! "fatal: empty filename in tree entry" out
'
test_expect_success 'tree entry with type mismatch' '
@@ -360,8 +360,8 @@ test_expect_success 'tree entry with type mismatch' '
commit=$(git commit-tree $tree) &&
git update-ref refs/heads/type_mismatch $commit &&
test_must_fail git fsck >out 2>&1 &&
- test_i18ngrep "is a blob, not a tree" out &&
- test_i18ngrep ! "dangling blob" out
+ test_grep "is a blob, not a tree" out &&
+ test_grep ! "dangling blob" out
'
test_expect_success 'tree entry with bogus mode' '
@@ -391,10 +391,10 @@ test_expect_success 'tag pointing to nonexistent' '
tag=$(git hash-object -t tag -w --stdin <invalid-tag) &&
test_when_finished "remove_object $tag" &&
- echo $tag >.git/refs/tags/invalid &&
+ git update-ref refs/tags/invalid $tag &&
test_when_finished "git update-ref -d refs/tags/invalid" &&
test_must_fail git fsck --tags >out &&
- test_i18ngrep "broken link" out
+ test_grep "broken link" out
'
test_expect_success 'tag pointing to something else than its type' '
@@ -411,7 +411,7 @@ test_expect_success 'tag pointing to something else than its type' '
tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
test_when_finished "remove_object $tag" &&
- echo $tag >.git/refs/tags/wrong &&
+ git update-ref refs/tags/wrong $tag &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
test_must_fail git fsck --tags
'
@@ -428,7 +428,7 @@ test_expect_success 'tag with incorrect tag name & missing tagger' '
tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) &&
test_when_finished "remove_object $tag" &&
- echo $tag >.git/refs/tags/wrong &&
+ git update-ref refs/tags/wrong $tag &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
git fsck --tags 2>out &&
@@ -452,10 +452,10 @@ test_expect_success 'tag with bad tagger' '
tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) &&
test_when_finished "remove_object $tag" &&
- echo $tag >.git/refs/tags/wrong &&
+ git update-ref refs/tags/wrong $tag &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
test_must_fail git fsck --tags 2>out &&
- test_i18ngrep "error in tag .*: invalid author/committer" out
+ test_grep "error in tag .*: invalid author/committer" out
'
test_expect_success 'tag with NUL in header' '
@@ -471,10 +471,10 @@ test_expect_success 'tag with NUL in header' '
tag=$(git hash-object --literally -t tag -w --stdin <tag-NUL-header) &&
test_when_finished "remove_object $tag" &&
- echo $tag >.git/refs/tags/wrong &&
+ git update-ref refs/tags/wrong $tag &&
test_when_finished "git update-ref -d refs/tags/wrong" &&
test_must_fail git fsck --tags 2>out &&
- test_i18ngrep "error in tag $tag.*unterminated header: NUL at offset" out
+ test_grep "error in tag $tag.*unterminated header: NUL at offset" out
'
test_expect_success 'cleaned up' '
@@ -504,7 +504,7 @@ test_expect_success 'rev-list --verify-objects with bad sha1' '
test_when_finished "git update-ref -d refs/heads/bogus" &&
test_might_fail git rev-list --verify-objects refs/heads/bogus >/dev/null 2>out &&
- test_i18ngrep -q "error: hash mismatch $(dirname $new)$(test_oid ff_2)" out
+ test_grep -q "error: hash mismatch $(dirname $new)$(test_oid ff_2)" out
'
# An actual bit corruption is more likely than swapped commits, but
@@ -575,7 +575,7 @@ test_expect_success 'fsck notices blob entry pointing to null sha1' '
sha=$(printf "100644 file$_bz$_bzoid" |
git hash-object --literally -w --stdin -t tree) &&
git fsck 2>out &&
- test_i18ngrep "warning.*null sha1" out
+ test_grep "warning.*null sha1" out
)
'
@@ -585,7 +585,17 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' '
sha=$(printf "160000 submodule$_bz$_bzoid" |
git hash-object --literally -w --stdin -t tree) &&
git fsck 2>out &&
- test_i18ngrep "warning.*null sha1" out
+ test_grep "warning.*null sha1" out
+ )
+'
+
+test_expect_success 'fsck notices excessively large tree entry name' '
+ git init large-name &&
+ (
+ cd large-name &&
+ test_commit a-long-name &&
+ git -c fsck.largePathname=warn:10 fsck 2>out &&
+ grep "warning.*large pathname" out
)
'
@@ -606,7 +616,7 @@ while read name path pretty; do
printf "$mode $type %s\t%s" "$value" "$path" >bad &&
bad_tree=$(git mktree <bad) &&
git fsck 2>out &&
- test_i18ngrep "warning.*tree $bad_tree" out
+ test_grep "warning.*tree $bad_tree" out
)'
done <<-\EOF
100644 blob
@@ -652,9 +662,9 @@ test_expect_success 'NUL in commit' '
git branch bad $(cat name) &&
test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 &&
- test_i18ngrep nulInCommit warn.1 &&
+ test_grep nulInCommit warn.1 &&
git fsck 2>warn.2 &&
- test_i18ngrep nulInCommit warn.2
+ test_grep nulInCommit warn.2
)
'
@@ -774,7 +784,7 @@ test_expect_success 'fsck --name-objects' '
tree=$(git rev-parse --verify julius:) &&
git tag -d julius &&
test_must_fail git fsck --name-objects >out &&
- test_i18ngrep "$tree (refs/tags/augustus44\\^:" out
+ test_grep "$tree (refs/tags/augustus44\\^:" out
)
'
@@ -787,7 +797,7 @@ test_expect_success 'alternate objects are correctly blamed' '
mkdir alt.git/objects/$(dirname $path) &&
>alt.git/objects/$(dirname $path)/$(basename $path) &&
test_must_fail git fsck >out 2>&1 &&
- test_i18ngrep alt.git out
+ test_grep alt.git out
'
test_expect_success 'fsck errors in packed objects' '
@@ -806,8 +816,8 @@ test_expect_success 'fsck errors in packed objects' '
remove_object $one &&
remove_object $two &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "error in commit $one.* - bad name" out &&
- test_i18ngrep "error in commit $two.* - bad name" out &&
+ test_grep "error in commit $one.* - bad name" out &&
+ test_grep "error in commit $two.* - bad name" out &&
! grep corrupt out
'
@@ -824,7 +834,7 @@ test_expect_success 'fsck fails on corrupt packfile' '
test_when_finished "rm -f .git/objects/pack/pack-$pack.*" &&
remove_object $hsh &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "checksum mismatch" out
+ test_grep "checksum mismatch" out
'
test_expect_success 'fsck finds problems in duplicate loose objects' '
@@ -861,7 +871,7 @@ test_expect_success 'fsck detects trailing loose garbage (commit)' '
chmod +w "$file" &&
echo garbage >>"$file" &&
test_must_fail git fsck 2>out &&
- test_i18ngrep "garbage.*$commit" out
+ test_grep "garbage.*$commit" out
'
test_expect_success 'fsck detects trailing loose garbage (large blob)' '
@@ -871,7 +881,7 @@ test_expect_success 'fsck detects trailing loose garbage (large blob)' '
chmod +w "$file" &&
echo garbage >>"$file" &&
test_must_fail git -c core.bigfilethreshold=5 fsck 2>out &&
- test_i18ngrep "garbage.*$blob" out
+ test_grep "garbage.*$blob" out
'
test_expect_success 'fsck detects truncated loose object' '
@@ -887,10 +897,10 @@ test_expect_success 'fsck detects truncated loose object' '
# check both regular and streaming code paths
test_must_fail git fsck 2>out &&
- test_i18ngrep corrupt.*$blob out &&
+ test_grep corrupt.*$blob out &&
test_must_fail git -c core.bigfilethreshold=128 fsck 2>out &&
- test_i18ngrep corrupt.*$blob out
+ test_grep corrupt.*$blob out
'
# for each of type, we have one version which is referenced by another object
@@ -979,7 +989,7 @@ test_expect_success 'detect corrupt index file in fsck' '
test_when_finished "mv .git/index.backup .git/index" &&
corrupt_index_checksum &&
test_must_fail git fsck --cache 2>errors &&
- test_i18ngrep "bad index file" errors
+ test_grep "bad index file" errors
'
test_expect_success 'fsck error and recovery on invalid object type' '
diff --git a/t/t1451-fsck-buffer.sh b/t/t1451-fsck-buffer.sh
index 3413da40e4..3a3d33f405 100755
--- a/t/t1451-fsck-buffer.sh
+++ b/t/t1451-fsck-buffer.sh
@@ -15,7 +15,6 @@ These tests _might_ catch such overruns in normal use, but should be run with
ASan or valgrind for more confidence.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# the general idea for tags and commits is to build up the "base" file
diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh
new file mode 100755
index 0000000000..1bfff3a7af
--- /dev/null
+++ b/t/t1460-refs-migrate.sh
@@ -0,0 +1,242 @@
+#!/bin/sh
+
+test_description='migration of ref storage backends'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_migration () {
+ git -C "$1" for-each-ref --include-root-refs \
+ --format='%(refname) %(objectname) %(symref)' >expect &&
+ git -C "$1" refs migrate --ref-format="$2" &&
+ git -C "$1" for-each-ref --include-root-refs \
+ --format='%(refname) %(objectname) %(symref)' >actual &&
+ test_cmp expect actual &&
+
+ git -C "$1" rev-parse --show-ref-format >actual &&
+ echo "$2" >expect &&
+ test_cmp expect actual
+}
+
+test_expect_success 'setup' '
+ rm -rf .git &&
+ # The migration does not yet support reflogs.
+ git config --global core.logAllRefUpdates false
+'
+
+test_expect_success "superfluous arguments" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo refs migrate foo 2>err &&
+ cat >expect <<-EOF &&
+ usage: too many arguments
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success "missing ref storage format" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo refs migrate 2>err &&
+ cat >expect <<-EOF &&
+ usage: missing --ref-format=<format>
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success "unknown ref storage format" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=unknown 2>err &&
+ cat >expect <<-EOF &&
+ error: unknown ref storage format ${SQ}unknown${SQ}
+ EOF
+ test_cmp expect err
+'
+
+ref_formats="files reftable"
+for from_format in $ref_formats
+do
+ for to_format in $ref_formats
+ do
+ if test "$from_format" = "$to_format"
+ then
+ continue
+ fi
+
+ test_expect_success "$from_format: migration to same format fails" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=$from_format 2>err &&
+ cat >expect <<-EOF &&
+ error: repository already uses ${SQ}$from_format${SQ} format
+ EOF
+ test_cmp expect err
+ '
+
+ test_expect_success "$from_format -> $to_format: migration with reflog fails" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_config -C repo core.logAllRefUpdates true &&
+ test_commit -C repo logged &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=$to_format 2>err &&
+ cat >expect <<-EOF &&
+ error: migrating reflogs is not supported yet
+ EOF
+ test_cmp expect err
+ '
+
+ test_expect_success "$from_format -> $to_format: migration with worktree fails" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ git -C repo worktree add wt &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=$to_format 2>err &&
+ cat >expect <<-EOF &&
+ error: migrating repositories with worktrees is not supported yet
+ EOF
+ test_cmp expect err
+ '
+
+ test_expect_success "$from_format -> $to_format: unborn HEAD" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: single ref" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: bare repository" '
+ test_when_finished "rm -rf repo repo.git" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git clone --ref-format=$from_format --mirror repo repo.git &&
+ test_migration repo.git "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: dangling symref" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo symbolic-ref BROKEN_HEAD refs/heads/nonexistent &&
+ test_migration repo "$to_format" &&
+ echo refs/heads/nonexistent >expect &&
+ git -C repo symbolic-ref BROKEN_HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$from_format -> $to_format: broken ref" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ test-tool -C repo ref-store main update-ref "" refs/heads/broken \
+ "$(test_oid 001)" "$ZERO_OID" REF_SKIP_CREATE_REFLOG,REF_SKIP_OID_VERIFICATION &&
+ test_migration repo "$to_format" &&
+ test_oid 001 >expect &&
+ git -C repo rev-parse refs/heads/broken >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$from_format -> $to_format: pseudo-refs" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo update-ref FOO_HEAD HEAD &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: special refs are left alone" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo rev-parse HEAD >repo/.git/MERGE_HEAD &&
+ git -C repo rev-parse MERGE_HEAD &&
+ test_migration repo "$to_format" &&
+ test_path_is_file repo/.git/MERGE_HEAD
+ '
+
+ test_expect_success "$from_format -> $to_format: a bunch of refs" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+
+ test_commit -C repo initial &&
+ cat >input <<-EOF &&
+ create FOO_HEAD HEAD
+ create refs/heads/branch-1 HEAD
+ create refs/heads/branch-2 HEAD
+ create refs/heads/branch-3 HEAD
+ create refs/heads/branch-4 HEAD
+ create refs/tags/tag-1 HEAD
+ create refs/tags/tag-2 HEAD
+ EOF
+ git -C repo update-ref --stdin <input &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: dry-run migration does not modify repository" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo refs migrate --dry-run \
+ --ref-format=$to_format >output &&
+ grep "Finished dry-run migration of refs" output &&
+ test_path_is_dir repo/.git/ref_migration.* &&
+ echo $from_format >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+ done
+done
+
+test_expect_success 'migrating from files format deletes backend files' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=files repo &&
+ test_commit -C repo first &&
+ git -C repo pack-refs --all &&
+ test_commit -C repo second &&
+ git -C repo update-ref ORIG_HEAD HEAD &&
+ git -C repo rev-parse HEAD >repo/.git/FETCH_HEAD &&
+
+ test_path_is_file repo/.git/HEAD &&
+ test_path_is_file repo/.git/ORIG_HEAD &&
+ test_path_is_file repo/.git/refs/heads/main &&
+ test_path_is_file repo/.git/packed-refs &&
+
+ test_migration repo reftable &&
+
+ echo "ref: refs/heads/.invalid" >expect &&
+ test_cmp expect repo/.git/HEAD &&
+ echo "this repository uses the reftable format" >expect &&
+ test_cmp expect repo/.git/refs/heads &&
+ test_path_is_file repo/.git/FETCH_HEAD &&
+ test_path_is_missing repo/.git/ORIG_HEAD &&
+ test_path_is_missing repo/.git/refs/heads/main &&
+ test_path_is_missing repo/.git/logs &&
+ test_path_is_missing repo/.git/packed-refs
+'
+
+test_expect_success 'migrating from reftable format deletes backend files' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=reftable repo &&
+ test_commit -C repo first &&
+
+ test_path_is_dir repo/.git/reftable &&
+ test_migration repo files &&
+
+ test_path_is_missing repo/.git/reftable &&
+ echo "ref: refs/heads/main" >expect &&
+ test_cmp expect repo/.git/HEAD &&
+ test_path_is_file repo/.git/packed-refs
+'
+
+test_done
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 37ee5091b5..bf2a90df94 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -4,7 +4,6 @@ test_description='test git rev-parse'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_one () {
@@ -208,6 +207,23 @@ test_expect_success 'rev-parse --show-object-format in repo' '
grep "unknown mode for --show-object-format: squeamish-ossifrage" err
'
+test_expect_success 'rev-parse --show-ref-format' '
+ test_detect_ref_format >expect &&
+ git rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-parse --show-ref-format with invalid storage' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ git config extensions.refstorage broken &&
+ test_must_fail git rev-parse --show-ref-format 2>err &&
+ grep "error: invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}broken${SQ}" err
+ )
+'
+
test_expect_success '--show-toplevel from subdir of working tree' '
pwd >expect &&
git -C sub/dir rev-parse --show-toplevel >actual &&
@@ -264,4 +280,33 @@ test_expect_success 'rev-parse --since= unsqueezed ordering' '
test_cmp expect actual
'
+test_expect_success 'rev-parse --bisect includes bad, excludes good' '
+ test_commit_bulk 6 &&
+
+ git update-ref refs/bisect/bad-1 HEAD~1 &&
+ git update-ref refs/bisect/b HEAD~2 &&
+ git update-ref refs/bisect/bad-3 HEAD~3 &&
+ git update-ref refs/bisect/good-3 HEAD~3 &&
+ git update-ref refs/bisect/bad-4 HEAD~4 &&
+ git update-ref refs/bisect/go HEAD~4 &&
+
+ # Note: refs/bisect/b and refs/bisect/go should be ignored because they
+ # do not match the refs/bisect/bad or refs/bisect/good prefixes.
+ cat >expect <<-EOF &&
+ refs/bisect/bad-1
+ refs/bisect/bad-3
+ refs/bisect/bad-4
+ ^refs/bisect/good-3
+ EOF
+
+ git rev-parse --symbolic-full-name --bisect >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--short= truncates to the actual hash length' '
+ git rev-parse HEAD >expect &&
+ git rev-parse --short=100 HEAD >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh
index ae6528aece..8c94ac2e70 100755
--- a/t/t1501-work-tree.sh
+++ b/t/t1501-work-tree.sh
@@ -2,7 +2,6 @@
test_description='test separate work tree'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index dd811b7fb4..3962f1d288 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -1,15 +1,32 @@
#!/bin/sh
test_description='test git rev-parse --parseopt'
+
. ./test-lib.sh
+check_invalid_long_option () {
+ spec="$1"
+ opt="$2"
+ test_expect_success "test --parseopt invalid switch $opt help output for $spec" '
+ {
+ cat <<-\EOF &&
+ error: unknown option `'${opt#--}\''
+ EOF
+ sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/$spec.help"
+ } >expect &&
+ test_expect_code 129 git rev-parse --parseopt -- $opt \
+ 2>output <"$TEST_DIRECTORY/t1502/$spec" &&
+ test_cmp expect output
+ '
+}
+
test_expect_success 'setup optionspec' '
sed -e "s/^|//" >optionspec <<\EOF
|some-command [options] <args>...
|
|some-command does foo and bar!
|--
-|h,help show the help
+|h,help! show the help
|
|foo some nifty option --foo
|bar= some cool option --bar with an argument
@@ -58,44 +75,8 @@ EOF
'
test_expect_success 'test --parseopt help output' '
- sed -e "s/^|//" >expect <<\END_EXPECT &&
-|cat <<\EOF
-|usage: some-command [options] <args>...
-|
-| some-command does foo and bar!
-|
-| -h, --help show the help
-| --foo some nifty option --foo
-| --bar ... some cool option --bar with an argument
-| -b, --baz a short and long option
-|
-|An option group Header
-| -C[...] option C with an optional argument
-| -d, --data[=...] short and long option with an optional argument
-|
-|Argument hints
-| -B <arg> short option required argument
-| --bar2 <arg> long option required argument
-| -e, --fuz <with-space>
-| short and long option required argument
-| -s[<some>] short option optional argument
-| --long[=<data>] long option optional argument
-| -g, --fluf[=<path>] short and long option optional argument
-| --longest <very-long-argument-hint>
-| a very long argument hint
-| --pair <key=value> with an equals sign in the hint
-| --aswitch help te=t contains? fl*g characters!`
-| --bswitch <hint> hint has trailing tab character
-| --cswitch switch has trailing tab character
-| --short-hint <a> with a one symbol hint
-|
-|Extras
-| --extra1 line above used to cause a segfault but no longer does
-|
-|EOF
-END_EXPECT
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
- test_cmp expect output
+ test_cmp "$TEST_DIRECTORY/t1502/optionspec.help" output
'
test_expect_success 'test --parseopt help output no switches' '
@@ -131,7 +112,7 @@ test_expect_success 'test --parseopt help-all output hidden switches' '
|
| some-command does foo and bar!
|
-| --hidden1 A hidden switch
+| --[no-]hidden1 A hidden switch
|
|EOF
END_EXPECT
@@ -140,41 +121,12 @@ END_EXPECT
'
test_expect_success 'test --parseopt invalid switch help output' '
- sed -e "s/^|//" >expect <<\END_EXPECT &&
-|error: unknown option `does-not-exist'\''
-|usage: some-command [options] <args>...
-|
-| some-command does foo and bar!
-|
-| -h, --help show the help
-| --foo some nifty option --foo
-| --bar ... some cool option --bar with an argument
-| -b, --baz a short and long option
-|
-|An option group Header
-| -C[...] option C with an optional argument
-| -d, --data[=...] short and long option with an optional argument
-|
-|Argument hints
-| -B <arg> short option required argument
-| --bar2 <arg> long option required argument
-| -e, --fuz <with-space>
-| short and long option required argument
-| -s[<some>] short option optional argument
-| --long[=<data>] long option optional argument
-| -g, --fluf[=<path>] short and long option optional argument
-| --longest <very-long-argument-hint>
-| a very long argument hint
-| --pair <key=value> with an equals sign in the hint
-| --aswitch help te=t contains? fl*g characters!`
-| --bswitch <hint> hint has trailing tab character
-| --cswitch switch has trailing tab character
-| --short-hint <a> with a one symbol hint
-|
-|Extras
-| --extra1 line above used to cause a segfault but no longer does
-|
-END_EXPECT
+ {
+ cat <<-\EOF &&
+ error: unknown option `does-not-exist'\''
+ EOF
+ sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/optionspec.help"
+ } >expect &&
test_expect_code 129 git rev-parse --parseopt -- --does-not-exist 1>/dev/null 2>output < optionspec &&
test_cmp expect output
'
@@ -288,7 +240,7 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
| [--another-option]
|cmd [--yet-another-option]
|--
- |h,help show the help
+ |h,help! show the help
EOF
sed -e "s/^|//" >expect <<-\END_EXPECT &&
@@ -322,7 +274,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
|line
|blurb
|--
- |h,help show the help
+ |h,help! show the help
EOF
sed -e "s/^|//" >expect <<-\END_EXPECT &&
@@ -343,4 +295,43 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
test_cmp expect actual
'
+test_expect_success 'test --parseopt help output for optionspec-neg' '
+ test_expect_code 129 git rev-parse --parseopt -- \
+ -h >output <"$TEST_DIRECTORY/t1502/optionspec-neg" &&
+ test_cmp "$TEST_DIRECTORY/t1502/optionspec-neg.help" output
+'
+
+test_expect_success 'test --parseopt valid options for optionspec-neg' '
+ cat >expect <<-\EOF &&
+ set -- --foo --no-foo --no-bar --positive-only --no-negative --
+ EOF
+ git rev-parse --parseopt -- <"$TEST_DIRECTORY/t1502/optionspec-neg" >output \
+ --foo --no-foo --no-bar --positive-only --no-negative &&
+ test_cmp expect output
+'
+
+test_expect_success 'test --parseopt positivated option for optionspec-neg' '
+ cat >expect <<-\EOF &&
+ set -- --no-no-bar --no-no-bar --
+ EOF
+ git rev-parse --parseopt -- <"$TEST_DIRECTORY/t1502/optionspec-neg" >output \
+ --no-no-bar --bar &&
+ test_cmp expect output
+'
+
+check_invalid_long_option optionspec-neg --no-positive-only
+check_invalid_long_option optionspec-neg --negative
+check_invalid_long_option optionspec-neg --no-no-negative
+
+test_expect_success 'ambiguous: --no matches both --noble and --no-noble' '
+ cat >spec <<-\EOF &&
+ some-command [options]
+ --
+ noble The feudal switch.
+ EOF
+ test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
+ git rev-parse --parseopt -- <spec 2>err --no &&
+ grep "error: ambiguous option: no (could be --noble or --no-noble)" err
+'
+
test_done
diff --git a/t/t1502/.gitattributes b/t/t1502/.gitattributes
new file mode 100644
index 0000000000..562b12e16e
--- /dev/null
+++ b/t/t1502/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/t/t1502/optionspec-neg b/t/t1502/optionspec-neg
new file mode 100644
index 0000000000..392f43eb0b
--- /dev/null
+++ b/t/t1502/optionspec-neg
@@ -0,0 +1,8 @@
+some-command [options] <args>...
+
+some-command does foo and bar!
+--
+foo can be negated
+no-bar can be positivated
+positive-only! cannot be negated
+no-negative! cannot be positivated
diff --git a/t/t1502/optionspec-neg.help b/t/t1502/optionspec-neg.help
new file mode 100644
index 0000000000..7a29f8cb03
--- /dev/null
+++ b/t/t1502/optionspec-neg.help
@@ -0,0 +1,12 @@
+cat <<\EOF
+usage: some-command [options] <args>...
+
+ some-command does foo and bar!
+
+ --[no-]foo can be negated
+ --no-bar can be positivated
+ --bar opposite of --no-bar
+ --positive-only cannot be negated
+ --no-negative cannot be positivated
+
+EOF
diff --git a/t/t1502/optionspec.help b/t/t1502/optionspec.help
new file mode 100755
index 0000000000..cbdd54d41b
--- /dev/null
+++ b/t/t1502/optionspec.help
@@ -0,0 +1,36 @@
+cat <<\EOF
+usage: some-command [options] <args>...
+
+ some-command does foo and bar!
+
+ -h, --help show the help
+ --[no-]foo some nifty option --foo
+ --[no-]bar ... some cool option --bar with an argument
+ -b, --[no-]baz a short and long option
+
+An option group Header
+ -C[...] option C with an optional argument
+ -d, --[no-]data[=...] short and long option with an optional argument
+
+Argument hints
+ -B <arg> short option required argument
+ --[no-]bar2 <arg> long option required argument
+ -e, --[no-]fuz <with-space>
+ short and long option required argument
+ -s[<some>] short option optional argument
+ --[no-]long[=<data>] long option optional argument
+ -g, --[no-]fluf[=<path>]
+ short and long option optional argument
+ --[no-]longest <very-long-argument-hint>
+ a very long argument hint
+ --[no-]pair <key=value>
+ with an equals sign in the hint
+ --[no-]aswitch help te=t contains? fl*g characters!`
+ --[no-]bswitch <hint> hint has trailing tab character
+ --[no-]cswitch switch has trailing tab character
+ --[no-]short-hint <a> with a one symbol hint
+
+Extras
+ --[no-]extra1 line above used to cause a segfault but no longer does
+
+EOF
diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
index bc136833c1..75a708f9ba 100755
--- a/t/t1503-rev-parse-verify.sh
+++ b/t/t1503-rev-parse-verify.sh
@@ -9,7 +9,6 @@ exec </dev/null
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
add_line_into_file()
@@ -144,11 +143,6 @@ test_expect_success 'main@{n} for various n' '
test_must_fail git rev-parse --verify main@{$Np1}
'
-test_expect_success SYMLINKS,REFFILES 'ref resolution not confused by broken symlinks' '
- ln -s does-not-exist .git/refs/heads/broken &&
- test_must_fail git rev-parse --verify broken
-'
-
test_expect_success 'options can appear after --verify' '
git rev-parse --verify HEAD >expect &&
git rev-parse --verify -q HEAD >actual &&
diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh
index c1679e31d8..e04420f436 100755
--- a/t/t1504-ceiling-dirs.sh
+++ b/t/t1504-ceiling-dirs.sh
@@ -2,7 +2,6 @@
test_description='test GIT_CEILING_DIRECTORIES'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_prefix() {
diff --git a/t/t1505-rev-parse-last.sh b/t/t1505-rev-parse-last.sh
index 4a5758f08a..2803ca9489 100755
--- a/t/t1505-rev-parse-last.sh
+++ b/t/t1505-rev-parse-last.sh
@@ -5,7 +5,6 @@ test_description='test @{-N} syntax'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index 18688cae17..722884e65f 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -7,7 +7,6 @@ exec </dev/null
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_did_you_mean ()
@@ -107,16 +106,16 @@ test_expect_success 'correct relative file objects (6)' '
test_expect_success 'incorrect revision id' '
test_must_fail git rev-parse foobar:file.txt 2>error &&
- test_i18ngrep "invalid object name .foobar." error &&
+ test_grep "invalid object name .foobar." error &&
test_must_fail git rev-parse foobar 2>error &&
- test_i18ngrep "unknown revision or path not in the working tree." error
+ test_grep "unknown revision or path not in the working tree." error
'
test_expect_success 'incorrect file in sha1:path' '
test_must_fail git rev-parse HEAD:nothing.txt 2>error &&
- test_i18ngrep "path .nothing.txt. does not exist in .HEAD." error &&
+ test_grep "path .nothing.txt. does not exist in .HEAD." error &&
test_must_fail git rev-parse HEAD:index-only.txt 2>error &&
- test_i18ngrep "path .index-only.txt. exists on disk, but not in .HEAD." error &&
+ test_grep "path .index-only.txt. exists on disk, but not in .HEAD." error &&
(cd subdir &&
test_must_fail git rev-parse HEAD:file2.txt 2>error &&
test_did_you_mean HEAD subdir/ file2.txt exists )
@@ -124,9 +123,9 @@ test_expect_success 'incorrect file in sha1:path' '
test_expect_success 'incorrect file in :path and :N:path' '
test_must_fail git rev-parse :nothing.txt 2>error &&
- test_i18ngrep "path .nothing.txt. does not exist (neither on disk nor in the index)" error &&
+ test_grep "path .nothing.txt. does not exist (neither on disk nor in the index)" error &&
test_must_fail git rev-parse :1:nothing.txt 2>error &&
- test_i18ngrep "path .nothing.txt. does not exist (neither on disk nor in the index)" error &&
+ test_grep "path .nothing.txt. does not exist (neither on disk nor in the index)" error &&
test_must_fail git rev-parse :1:file.txt 2>error &&
test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" &&
(cd subdir &&
@@ -137,42 +136,42 @@ test_expect_success 'incorrect file in :path and :N:path' '
test_must_fail git rev-parse :2:file2.txt 2>error &&
test_did_you_mean :0 subdir/ file2.txt "is in the index") &&
test_must_fail git rev-parse :disk-only.txt 2>error &&
- test_i18ngrep "path .disk-only.txt. exists on disk, but not in the index" error
+ test_grep "path .disk-only.txt. exists on disk, but not in the index" error
'
test_expect_success 'invalid @{n} reference' '
test_must_fail git rev-parse main@{99999} >output 2>error &&
test_must_be_empty output &&
- test_i18ngrep "log for [^ ]* only has [0-9][0-9]* entries" error &&
+ test_grep "log for [^ ]* only has [0-9][0-9]* entries" error &&
test_must_fail git rev-parse --verify main@{99999} >output 2>error &&
test_must_be_empty output &&
- test_i18ngrep "log for [^ ]* only has [0-9][0-9]* entries" error
+ test_grep "log for [^ ]* only has [0-9][0-9]* entries" error
'
test_expect_success 'relative path not found' '
(
cd subdir &&
test_must_fail git rev-parse HEAD:./nonexistent.txt 2>error &&
- test_i18ngrep subdir/nonexistent.txt error
+ test_grep subdir/nonexistent.txt error
)
'
test_expect_success 'relative path outside worktree' '
test_must_fail git rev-parse HEAD:../file.txt >output 2>error &&
test_must_be_empty output &&
- test_i18ngrep "outside repository" error
+ test_grep "outside repository" error
'
test_expect_success 'relative path when cwd is outside worktree' '
test_must_fail git --git-dir=.git --work-tree=subdir rev-parse HEAD:./file.txt >output 2>error &&
test_must_be_empty output &&
- test_i18ngrep "relative path syntax can.t be used outside working tree" error
+ test_grep "relative path syntax can.t be used outside working tree" error
'
test_expect_success '<commit>:file correctly diagnosed after a pathname' '
test_must_fail git rev-parse file.txt HEAD:file.txt 1>actual 2>error &&
- test_i18ngrep ! "exists on disk" error &&
- test_i18ngrep "no such path in the working tree" error &&
+ test_grep ! "exists on disk" error &&
+ test_grep "no such path in the working tree" error &&
cat >expect <<-\EOF &&
file.txt
HEAD:file.txt
@@ -195,7 +194,7 @@ test_expect_success 'dotdot is not an empty set' '
'
test_expect_success 'dotdot does not peel endpoints' '
- git tag -a -m "annote" annotated HEAD &&
+ git tag -a -m "annotate" annotated HEAD &&
A=$(git rev-parse annotated) &&
H=$(git rev-parse annotated^0) &&
{
@@ -214,13 +213,13 @@ test_expect_success 'dotdot does not peel endpoints' '
test_expect_success 'arg before dashdash must be a revision (missing)' '
test_must_fail git rev-parse foobar -- 2>stderr &&
- test_i18ngrep "bad revision" stderr
+ test_grep "bad revision" stderr
'
test_expect_success 'arg before dashdash must be a revision (file)' '
>foobar &&
test_must_fail git rev-parse foobar -- 2>stderr &&
- test_i18ngrep "bad revision" stderr
+ test_grep "bad revision" stderr
'
test_expect_success 'arg before dashdash must be a revision (ambiguous)' '
@@ -269,7 +268,7 @@ test_expect_success 'arg after dashdash not interpreted as option' '
test_expect_success 'arg after end-of-options not interpreted as option' '
test_must_fail git rev-parse --end-of-options --not-real -- 2>err &&
- test_i18ngrep bad.revision.*--not-real err
+ test_grep bad.revision.*--not-real err
'
test_expect_success 'end-of-options still allows --' '
diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index b9af6b3ac0..cb9ef7e329 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -5,7 +5,6 @@ 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
diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh
index e841309d0e..87a4286414 100755
--- a/t/t1508-at-combinations.sh
+++ b/t/t1508-at-combinations.sh
@@ -4,7 +4,6 @@ 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() {
diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh
index 6d47e2c725..dc997e0a64 100755
--- a/t/t1509/prepare-chroot.sh
+++ b/t/t1509/prepare-chroot.sh
@@ -43,7 +43,7 @@ rsync --exclude-from t/t1509/excludes -Ha . "$R$(pwd)"
# env might slip through, see test-lib.sh, unset.*PERL_PATH
sed 's|^PERL_PATH=.*|PERL_PATH=/bin/true|' GIT-BUILD-OPTIONS > "$R$(pwd)/GIT-BUILD-OPTIONS"
for cmd in git $BB;do
- ldd $cmd | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do
+ ldd $cmd | sed -n '/\//s,.*\s\(/[^ ]*\).*,\1,p' | while read i; do
mkdir -p "$R$(dirname $i)"
cp "$i" "$R/$i"
done
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
index 591505a39c..bbfe05b8e4 100755
--- a/t/t1510-repo-setup.sh
+++ b/t/t1510-repo-setup.sh
@@ -43,7 +43,6 @@ A few rules for repo setup:
# This test heavily relies on the standard error of nested function calls.
test_untraceable=UnfortunatelyYes
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
here=$(pwd)
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 98cefe3b70..70f1e0a998 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -129,7 +129,7 @@ test_expect_success 'blob and tree' '
test_expect_success 'warn ambiguity when no candidate matches type hint' '
test_must_fail git rev-parse --verify 000000000^{commit} 2>actual &&
- test_i18ngrep "short object ID 000000000 is ambiguous" actual
+ test_grep "short object ID 000000000 is ambiguous" actual
'
test_expect_success 'disambiguate tree-ish' '
@@ -470,10 +470,10 @@ test_expect_success 'cat-file --batch and --batch-check show ambiguous' '
echo "0000 ambiguous" >expect &&
echo 0000 | git cat-file --batch-check >actual 2>err &&
test_cmp expect actual &&
- test_i18ngrep hint: err &&
+ test_grep hint: err &&
echo 0000 | git cat-file --batch >actual 2>err &&
test_cmp expect actual &&
- test_i18ngrep hint: err
+ test_grep hint: err
'
test_done
diff --git a/t/t1513-rev-parse-prefix.sh b/t/t1513-rev-parse-prefix.sh
index ba43387bf1..5f437be8c9 100755
--- a/t/t1513-rev-parse-prefix.sh
+++ b/t/t1513-rev-parse-prefix.sh
@@ -5,7 +5,6 @@ test_description='Tests for rev-parse --prefix'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh
index a835a196aa..d868a08110 100755
--- a/t/t1514-rev-parse-push.sh
+++ b/t/t1514-rev-parse-push.sh
@@ -4,7 +4,6 @@ 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 () {
diff --git a/t/t1515-rev-parse-outside-repo.sh b/t/t1515-rev-parse-outside-repo.sh
index cdb26a30d7..75e89c4b6e 100755
--- a/t/t1515-rev-parse-outside-repo.sh
+++ b/t/t1515-rev-parse-outside-repo.sh
@@ -2,7 +2,6 @@
test_description='check that certain rev-parse options work outside repo'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up non-repo directory' '
diff --git a/t/t1517-outside-repo.sh b/t/t1517-outside-repo.sh
new file mode 100755
index 0000000000..dbd8cd6906
--- /dev/null
+++ b/t/t1517-outside-repo.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+test_description='check random commands outside repo'
+
+. ./test-lib.sh
+
+test_expect_success 'set up a non-repo directory and test file' '
+ GIT_CEILING_DIRECTORIES=$(pwd) &&
+ export GIT_CEILING_DIRECTORIES &&
+ mkdir non-repo &&
+ (
+ cd non-repo &&
+ # confirm that git does not find a repo
+ test_must_fail git rev-parse --git-dir
+ ) &&
+ test_write_lines one two three four >nums &&
+ git add nums &&
+ cp nums nums.old &&
+ test_write_lines five >>nums &&
+ git diff >sample.patch
+'
+
+test_expect_success 'compute a patch-id outside repository (uses SHA-1)' '
+ nongit env GIT_DEFAULT_HASH=sha1 \
+ git patch-id <sample.patch >patch-id.expect &&
+ nongit \
+ git patch-id <sample.patch >patch-id.actual &&
+ test_cmp patch-id.expect patch-id.actual
+'
+
+test_expect_success 'hash-object outside repository (uses SHA-1)' '
+ nongit env GIT_DEFAULT_HASH=sha1 \
+ git hash-object --stdin <sample.patch >hash.expect &&
+ nongit \
+ git hash-object --stdin <sample.patch >hash.actual &&
+ test_cmp hash.expect hash.actual
+'
+
+test_expect_success 'apply a patch outside repository' '
+ (
+ cd non-repo &&
+ cp ../nums.old nums &&
+ git apply ../sample.patch
+ ) &&
+ test_cmp nums non-repo/nums
+'
+
+test_expect_success 'grep outside repository' '
+ git grep --cached two >expect &&
+ (
+ cd non-repo &&
+ cp ../nums.old nums &&
+ git grep --no-index two >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'imap-send outside repository' '
+ test_config_global imap.host imaps://localhost &&
+ test_config_global imap.folder Drafts &&
+
+ echo nothing to send >expect &&
+ test_must_fail git imap-send -v </dev/null 2>actual &&
+ test_cmp expect actual &&
+
+ (
+ cd non-repo &&
+ test_must_fail git imap-send -v </dev/null 2>../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-ref-format outside repository' '
+ git check-ref-format --branch refs/heads/xyzzy >expect &&
+ nongit git check-ref-format --branch refs/heads/xyzzy >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'diff outside repository' '
+ echo one >one &&
+ echo two >two &&
+ test_must_fail git diff --no-index one two >expect.raw &&
+ (
+ cd non-repo &&
+ cp ../one . &&
+ cp ../two . &&
+ test_must_fail git diff one two >../actual.raw
+ ) &&
+ # outside repository diff falls back to SHA-1 but
+ # GIT_DEFAULT_HASH may be set to sha256 on the in-repo side.
+ sed -e "/^index /d" expect.raw >expect &&
+ sed -e "/^index /d" actual.raw >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stripspace outside repository' '
+ nongit git stripspace -s </dev/null
+'
+
+test_expect_success LIBCURL 'remote-http outside repository' '
+ test_must_fail git remote-http 2>actual &&
+ test_grep "^error: remote-curl" actual &&
+ (
+ cd non-repo &&
+ test_must_fail git remote-http 2>../actual
+ ) &&
+ test_grep "^error: remote-curl" actual
+'
+
+test_done
diff --git a/t/t1600-index.sh b/t/t1600-index.sh
index 9368d82f7d..03239e9faa 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -2,7 +2,6 @@
test_description='index file specific tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
sane_unset GIT_TEST_SPLIT_INDEX
@@ -118,7 +117,7 @@ test_index_version () {
fi &&
git add a &&
echo $EXPECTED_OUTPUT_VERSION >expect &&
- test-tool index-version <.git/index >actual &&
+ git update-index --show-index-version >actual &&
test_cmp expect actual
)
}
diff --git a/t/t1601-index-bogus.sh b/t/t1601-index-bogus.sh
index 4171f1e141..a45a8b4eb0 100755
--- a/t/t1601-index-bogus.sh
+++ b/t/t1601-index-bogus.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test handling of bogus index entries'
+
. ./test-lib.sh
test_expect_success 'create tree with null sha1' '
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index b4ab166369..ac4a5b2734 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -43,7 +43,7 @@ test_expect_success 'enable split index' '
git config splitIndex.maxPercentChange 100 &&
git update-index --split-index &&
test-tool dump-split-index .git/index >actual &&
- indexversion=$(test-tool index-version <.git/index) &&
+ indexversion=$(git update-index --show-index-version) &&
# NEEDSWORK: Stop hard-coding checksums.
if test "$indexversion" = "4"
@@ -527,7 +527,7 @@ test_expect_success 'reading split index at alternate location' '
# ... and, for backwards compatibility, in the current GIT_DIR
# as well.
- mv -v ./reading-alternate-location/.git/sharedindex.* .git &&
+ mv ./reading-alternate-location/.git/sharedindex.* .git &&
GIT_INDEX_FILE=./reading-alternate-location/.git/index \
git ls-files --cached >actual &&
test_cmp expect actual
diff --git a/t/t1701-racy-split-index.sh b/t/t1701-racy-split-index.sh
index d8fa489998..5dc221ef38 100755
--- a/t/t1701-racy-split-index.sh
+++ b/t/t1701-racy-split-index.sh
@@ -5,7 +5,6 @@
test_description='racy split index'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 8b0234cf2d..4feaf0d7be 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -2,7 +2,6 @@
test_description='git-hook command'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
diff --git a/t/t2000-conflict-when-checking-files-out.sh b/t/t2000-conflict-when-checking-files-out.sh
index 79fc97f1d7..f18616ad2b 100755
--- a/t/t2000-conflict-when-checking-files-out.sh
+++ b/t/t2000-conflict-when-checking-files-out.sh
@@ -21,7 +21,6 @@ test_description='git conflicts when checking files out test.'
# path1 is occupied by a non-directory. With "-f" flag, it should remove
# the conflicting paths and succeed.
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
show_files() {
diff --git a/t/t2002-checkout-cache-u.sh b/t/t2002-checkout-cache-u.sh
index fc95cf9048..70361c806e 100755
--- a/t/t2002-checkout-cache-u.sh
+++ b/t/t2002-checkout-cache-u.sh
@@ -8,7 +8,6 @@ test_description='git checkout-index -u test.
With -u flag, git checkout-index internally runs the equivalent of
git update-index --refresh on the checked out entry.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success \
diff --git a/t/t2003-checkout-cache-mkdir.sh b/t/t2003-checkout-cache-mkdir.sh
index f0fd441d81..ff163cf675 100755
--- a/t/t2003-checkout-cache-mkdir.sh
+++ b/t/t2003-checkout-cache-mkdir.sh
@@ -10,7 +10,6 @@ also verifies that such leading path may contain symlinks, unlike
the GIT controlled paths.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
index b16d69ca4a..b92d96fdc4 100755
--- a/t/t2004-checkout-cache-temp.sh
+++ b/t/t2004-checkout-cache-temp.sh
@@ -8,7 +8,6 @@ test_description='git checkout-index --temp test.
With --temp flag, git checkout-index writes to temporary merge files
rather than the tracked path.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -93,7 +92,7 @@ test_expect_success 'checkout all stages of unknown path' '
rm -f path* .merge_* actual &&
test_must_fail git checkout-index --stage=all --temp \
-- does-not-exist 2>stderr &&
- test_i18ngrep not.in.the.cache stderr
+ test_grep not.in.the.cache stderr
'
test_expect_success 'checkout all stages/one file to nothing' '
@@ -117,6 +116,26 @@ test_expect_success 'checkout all stages/one file to temporary files' '
test $(cat $s3) = tree3path1)
'
+test_expect_success '--stage=all implies --temp' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all -- path1 &&
+ test_path_is_missing path1
+'
+
+test_expect_success 'overriding --stage=all resets implied --temp' '
+ rm -f path* .merge_* actual &&
+ git checkout-index --stage=all --stage=2 -- path1 &&
+ echo tree2path1 >expect &&
+ test_cmp expect path1
+'
+
+test_expect_success '--stage=all --no-temp is rejected' '
+ rm -f path* .merge_* actual &&
+ test_must_fail git checkout-index --stage=all --no-temp -- path1 2>err &&
+ grep -v "already exists" err &&
+ grep "options .--stage=all. and .--no-temp. cannot be used together" err
+'
+
test_expect_success 'checkout some stages/one file to temporary files' '
rm -f path* .merge_* actual &&
git checkout-index --stage=all --temp -- path2 >actual &&
diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh
index 67d18cfa10..91b08e0371 100755
--- a/t/t2005-checkout-index-symlinks.sh
+++ b/t/t2005-checkout-index-symlinks.sh
@@ -8,7 +8,6 @@ test_description='git checkout-index on filesystem w/o symlinks test.
This tests that git checkout-index creates a symbolic link as a plain
file if core.symlinks is false.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success \
diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh
index 5d119871d4..bac231b167 100755
--- a/t/t2006-checkout-index-basic.sh
+++ b/t/t2006-checkout-index-basic.sh
@@ -3,12 +3,11 @@
test_description='basic checkout-index tests
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'checkout-index --gobbledegook' '
test_expect_code 129 git checkout-index --gobbledegook 2>err &&
- test_i18ngrep "[Uu]sage" err
+ test_grep "[Uu]sage" err
'
test_expect_success 'checkout-index -h in broken repository' '
@@ -19,18 +18,18 @@ test_expect_success 'checkout-index -h in broken repository' '
>.git/index &&
test_expect_code 129 git checkout-index -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage" broken/usage
+ test_grep "[Uu]sage" broken/usage
'
test_expect_success 'checkout-index reports errors (cmdline)' '
test_must_fail git checkout-index -- does-not-exist 2>stderr &&
- test_i18ngrep not.in.the.cache stderr
+ test_grep not.in.the.cache stderr
'
test_expect_success 'checkout-index reports errors (stdin)' '
echo does-not-exist |
test_must_fail git checkout-index --stdin 2>stderr &&
- test_i18ngrep not.in.the.cache stderr
+ test_grep not.in.the.cache stderr
'
for mode in 'case' 'utf-8'
do
@@ -88,8 +87,8 @@ test_expect_success 'checkout-index --temp correctly reports error on missing bl
git update-index --index-info <objs &&
test_must_fail git checkout-index --temp symlink file 2>stderr &&
- test_i18ngrep "unable to read sha1 file of file ($missing_blob)" stderr &&
- test_i18ngrep "unable to read sha1 file of symlink ($missing_blob)" stderr
+ test_grep "unable to read sha1 file of file ($missing_blob)" stderr &&
+ test_grep "unable to read sha1 file of symlink ($missing_blob)" stderr
'
test_expect_success 'checkout-index --temp correctly reports error for submodules' '
@@ -98,7 +97,7 @@ test_expect_success 'checkout-index --temp correctly reports error for submodule
git submodule add ./sub &&
git commit -m sub &&
test_must_fail git checkout-index --temp sub 2>stderr &&
- test_i18ngrep "cannot create temporary submodule sub" stderr
+ test_grep "cannot create temporary submodule sub" stderr
'
test_done
diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh
index bd9e9e7530..6f0b90ce12 100755
--- a/t/t2007-checkout-symlink.sh
+++ b/t/t2007-checkout-symlink.sh
@@ -7,7 +7,6 @@ test_description='git checkout to switch between branches with symlink<->dir'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2008-checkout-subdir.sh b/t/t2008-checkout-subdir.sh
index 8a518a44ea..eadb9434ae 100755
--- a/t/t2008-checkout-subdir.sh
+++ b/t/t2008-checkout-subdir.sh
@@ -4,7 +4,6 @@
test_description='git checkout from subdirectories'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2009-checkout-statinfo.sh b/t/t2009-checkout-statinfo.sh
index 71195dd28f..b0540636ae 100755
--- a/t/t2009-checkout-statinfo.sh
+++ b/t/t2009-checkout-statinfo.sh
@@ -5,7 +5,6 @@ test_description='checkout should leave clean stat info'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh
index 9d4b37526a..3a3d56018e 100755
--- a/t/t2010-checkout-ambiguous.sh
+++ b/t/t2010-checkout-ambiguous.sh
@@ -5,7 +5,6 @@ test_description='checkout and pathspecs/refspecs ambiguities'
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' '
@@ -62,8 +61,8 @@ test_expect_success 'disambiguate checking out from a tree-ish' '
test_expect_success 'accurate error message with more than one ref' '
test_must_fail git checkout HEAD main -- 2>actual &&
- test_i18ngrep 2 actual &&
- test_i18ngrep "one reference expected, 2 given" actual
+ test_grep 2 actual &&
+ test_grep "one reference expected, 2 given" actual
'
test_done
diff --git a/t/t2011-checkout-invalid-head.sh b/t/t2011-checkout-invalid-head.sh
index d9997e7b6b..61417c7567 100755
--- a/t/t2011-checkout-invalid-head.sh
+++ b/t/t2011-checkout-invalid-head.sh
@@ -5,7 +5,6 @@ test_description='checkout switching away from an invalid branch'
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' '
@@ -18,12 +17,12 @@ test_expect_success 'checkout should not start branch from a tree' '
test_must_fail git checkout -b newbranch main^{tree}
'
-test_expect_success 'checkout main from invalid HEAD' '
+test_expect_success REFFILES 'checkout main from invalid HEAD' '
echo $ZERO_OID >.git/HEAD &&
git checkout main --
'
-test_expect_success 'checkout notices failure to lock HEAD' '
+test_expect_success REFFILES 'checkout notices failure to lock HEAD' '
test_when_finished "rm -f .git/HEAD.lock" &&
>.git/HEAD.lock &&
test_must_fail git checkout -b other
@@ -31,11 +30,8 @@ test_expect_success 'checkout notices failure to lock HEAD' '
test_expect_success 'create ref directory/file conflict scenario' '
git update-ref refs/heads/outer/inner main &&
-
- # do not rely on symbolic-ref to get a known state,
- # as it may use the same code we are testing
reset_to_df () {
- echo "ref: refs/heads/outer" >.git/HEAD
+ git symbolic-ref HEAD refs/heads/outer
}
'
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 4b6372f4c3..1f6c4ed042 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -5,7 +5,6 @@ test_description='checkout can switch to last branch and merge base'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2014-checkout-switch.sh b/t/t2014-checkout-switch.sh
index c138bdde4f..3e757c6e4e 100755
--- a/t/t2014-checkout-switch.sh
+++ b/t/t2014-checkout-switch.sh
@@ -2,7 +2,6 @@
test_description='Peter MacMillan'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh
index fb0e13881c..1820300c62 100755
--- a/t/t2015-checkout-unborn.sh
+++ b/t/t2015-checkout-unborn.sh
@@ -4,7 +4,6 @@ test_description='checkout from unborn branch'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh
index 747eb5563e..c4f9bf09aa 100755
--- a/t/t2016-checkout-patch.sh
+++ b/t/t2016-checkout-patch.sh
@@ -38,26 +38,32 @@ test_expect_success 'git checkout -p with staged changes' '
verify_state dir/foo index index
'
-test_expect_success 'git checkout -p HEAD with NO staged changes: abort' '
- set_and_save_state dir/foo work head &&
- test_write_lines n y n | git checkout -p HEAD &&
- verify_saved_state bar &&
- verify_saved_state dir/foo
-'
-
-test_expect_success 'git checkout -p HEAD with NO staged changes: apply' '
- test_write_lines n y y | git checkout -p HEAD &&
- verify_saved_state bar &&
- verify_state dir/foo head head
-'
-
-test_expect_success 'git checkout -p HEAD with change already staged' '
- set_state dir/foo index index &&
- # the third n is to get out in case it mistakenly does not apply
- test_write_lines n y n | git checkout -p HEAD &&
- verify_saved_state bar &&
- verify_state dir/foo head head
-'
+for opt in "HEAD" "@"
+do
+ test_expect_success "git checkout -p $opt with NO staged changes: abort" '
+ set_and_save_state dir/foo work head &&
+ test_write_lines n y n | git checkout -p $opt >output &&
+ verify_saved_state bar &&
+ verify_saved_state dir/foo &&
+ test_grep "Discard" output
+ '
+
+ test_expect_success "git checkout -p $opt with NO staged changes: apply" '
+ test_write_lines n y y | git checkout -p $opt >output &&
+ verify_saved_state bar &&
+ verify_state dir/foo head head &&
+ test_grep "Discard" output
+ '
+
+ test_expect_success "git checkout -p $opt with change already staged" '
+ set_state dir/foo index index &&
+ # the third n is to get out in case it mistakenly does not apply
+ test_write_lines n y n | git checkout -p $opt >output &&
+ verify_saved_state bar &&
+ verify_state dir/foo head head &&
+ test_grep "Discard" output
+ '
+done
test_expect_success 'git checkout -p HEAD^...' '
# the third n is to get out in case it mistakenly does not apply
diff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh
index 947d1587ac..80ac661815 100755
--- a/t/t2017-checkout-orphan.sh
+++ b/t/t2017-checkout-orphan.sh
@@ -10,7 +10,6 @@ Main Tests for --orphan functionality.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
TEST_FILE=foo
@@ -86,7 +85,7 @@ test_expect_success '--orphan makes reflog by default' '
git rev-parse --verify delta@{0}
'
-test_expect_success REFFILES '--orphan does not make reflog when core.logAllRefUpdates = false' '
+test_expect_success '--orphan does not make reflog when core.logAllRefUpdates = false' '
git checkout main &&
git config core.logAllRefUpdates false &&
git checkout --orphan epsilon &&
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 8581ad3437..a48ebdbf4d 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -3,7 +3,6 @@
test_description='checkout'
TEST_CREATE_REPO_NO_TEMPLATE=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Arguments: [!] <branch> <oid> [<checkout options>]
@@ -278,12 +277,12 @@ test_expect_success 'checkout -b to a new branch preserves mergeable changes des
test_expect_success 'checkout -b rejects an invalid start point' '
test_must_fail git checkout -b branch4 file1 2>err &&
- test_i18ngrep "is not a commit" err
+ test_grep "is not a commit" err
'
test_expect_success 'checkout -b rejects an extra path argument' '
test_must_fail git checkout -b branch5 branch1 file1 2>err &&
- test_i18ngrep "Cannot update paths and switch to branch" err
+ test_grep "Cannot update paths and switch to branch" err
'
test_done
diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh
index 9540588664..1fcef4be95 100755
--- a/t/t2019-checkout-ambiguous-ref.sh
+++ b/t/t2019-checkout-ambiguous-ref.sh
@@ -2,7 +2,6 @@
test_description='checkout handling of ambiguous (branch/tag) refs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup ambiguous refs' '
@@ -32,8 +31,8 @@ test_expect_success 'checkout chooses branch over tag' '
'
test_expect_success 'checkout reports switch to branch' '
- test_i18ngrep "Switched to branch" stderr &&
- test_i18ngrep ! "^HEAD is now at" stderr
+ test_grep "Switched to branch" stderr &&
+ test_grep ! "^HEAD is now at" stderr
'
test_expect_success 'checkout vague ref succeeds' '
@@ -54,8 +53,8 @@ test_expect_success VAGUENESS_SUCCESS 'checkout chooses branch over tag' '
'
test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
- test_i18ngrep "Switched to branch" stderr &&
- test_i18ngrep ! "^HEAD is now at" stderr
+ test_grep "Switched to branch" stderr &&
+ test_grep ! "^HEAD is now at" stderr
'
test_done
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
index 2eab6474f8..28bbbe6c05 100755
--- a/t/t2020-checkout-detach.sh
+++ b/t/t2020-checkout-detach.sh
@@ -4,7 +4,6 @@ test_description='checkout into detached HEAD state'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_detached () {
@@ -17,12 +16,12 @@ check_not_detached () {
PREV_HEAD_DESC='Previous HEAD position was'
check_orphan_warning() {
- test_i18ngrep "you are leaving $2 behind" "$1" &&
- test_i18ngrep ! "$PREV_HEAD_DESC" "$1"
+ test_grep "you are leaving $2 behind" "$1" &&
+ test_grep ! "$PREV_HEAD_DESC" "$1"
}
check_no_orphan_warning() {
- test_i18ngrep ! "you are leaving .* commit.*behind" "$1" &&
- test_i18ngrep "$PREV_HEAD_DESC" "$1"
+ test_grep ! "you are leaving .* commit.*behind" "$1" &&
+ test_grep "$PREV_HEAD_DESC" "$1"
}
reset () {
@@ -45,6 +44,18 @@ test_expect_success 'checkout branch does not detach' '
check_not_detached
'
+for opt in "HEAD" "@"
+do
+ test_expect_success "checkout $opt no-op/don't detach" '
+ reset &&
+ cat .git/HEAD >expect &&
+ git checkout $opt &&
+ cat .git/HEAD >actual &&
+ check_not_detached &&
+ test_cmp expect actual
+ '
+done
+
test_expect_success 'checkout tag detaches' '
reset &&
git checkout tag &&
@@ -164,7 +175,10 @@ test_expect_success 'tracking count is accurate after orphan check' '
git config branch.child.merge refs/heads/main &&
git checkout child^ &&
git checkout child >stdout &&
- test_cmp expect stdout
+ test_cmp expect stdout &&
+
+ git checkout --detach child >stdout &&
+ test_grep ! "can be fast-forwarded\." stdout
'
test_expect_success 'no advice given for explicit detached head state' '
diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh
index ecfacf0f7f..a5c03d5d4a 100755
--- a/t/t2021-checkout-overwrite.sh
+++ b/t/t2021-checkout-overwrite.sh
@@ -2,7 +2,6 @@
test_description='checkout must not overwrite an untracked objects'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh
index f1b709d58b..c49ba7f9bd 100755
--- a/t/t2022-checkout-paths.sh
+++ b/t/t2022-checkout-paths.sh
@@ -4,7 +4,6 @@ test_description='checkout $tree -- $paths'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2023-checkout-m.sh b/t/t2023-checkout-m.sh
index 81e772fb4e..7b327b7544 100755
--- a/t/t2023-checkout-m.sh
+++ b/t/t2023-checkout-m.sh
@@ -7,7 +7,6 @@ Ensures that checkout -m on a resolved file restores the conflicted file'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
index 74049a9812..a3b1449ef1 100755
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@ -93,7 +93,7 @@ test_expect_success 'when arg matches multiple remotes, do not fallback to inter
test_must_fail git checkout ambiguous_branch_and_file 2>err &&
- test_i18ngrep "matched multiple (2) remote tracking branches" err &&
+ test_grep "matched multiple (2) remote tracking branches" err &&
# file must not be altered
test_cmp expect ambiguous_branch_and_file
@@ -105,20 +105,20 @@ test_expect_success 'checkout of branch from multiple remotes fails with advice'
test_must_fail git checkout foo 2>stderr &&
test_branch main &&
status_uno_is_clean &&
- test_i18ngrep "^hint: " stderr &&
+ test_grep "^hint: " stderr &&
test_must_fail git -c advice.checkoutAmbiguousRemoteBranchName=false \
checkout foo 2>stderr &&
test_branch main &&
status_uno_is_clean &&
- test_i18ngrep ! "^hint: " stderr
+ test_grep ! "^hint: " stderr
'
-test_expect_success PERL 'checkout -p with multiple remotes does not print advice' '
+test_expect_success 'checkout -p with multiple remotes does not print advice' '
git checkout -B main &&
test_might_fail git branch -D foo &&
git checkout -p foo 2>stderr &&
- test_i18ngrep ! "^hint: " stderr &&
+ test_grep ! "^hint: " stderr &&
status_uno_is_clean
'
diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh
index 3832c3de81..dda169bbc4 100755
--- a/t/t2025-checkout-no-overlay.sh
+++ b/t/t2025-checkout-no-overlay.sh
@@ -2,7 +2,6 @@
test_description='checkout --no-overlay <tree-ish> -- <pathspec>'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -26,7 +25,7 @@ test_expect_success 'checkout --no-overlay removing last file from directory' '
test_expect_success 'checkout -p --overlay is disallowed' '
test_must_fail git checkout -p --overlay HEAD 2>actual &&
- test_i18ngrep "fatal: options .-p. and .--overlay. cannot be used together" actual
+ test_grep "fatal: options .-p. and .--overlay. cannot be used together" actual
'
test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '
diff --git a/t/t2026-checkout-pathspec-file.sh b/t/t2026-checkout-pathspec-file.sh
index 9c651aefbc..161da054b6 100755
--- a/t/t2026-checkout-pathspec-file.sh
+++ b/t/t2026-checkout-pathspec-file.sh
@@ -2,7 +2,6 @@
test_description='checkout --pathspec-from-file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_tick
@@ -149,16 +148,16 @@ test_expect_success 'error conditions' '
echo fileA.t >list &&
test_must_fail git checkout --pathspec-from-file=list --detach 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--detach. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--detach. cannot be used together" err &&
test_must_fail git checkout --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git checkout --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git checkout --pathspec-file-nul 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err
'
test_done
diff --git a/t/t2027-checkout-track.sh b/t/t2027-checkout-track.sh
index a8bbc60954..a397790df5 100755
--- a/t/t2027-checkout-track.sh
+++ b/t/t2027-checkout-track.sh
@@ -5,7 +5,6 @@ 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' '
@@ -22,7 +21,7 @@ test_expect_success 'checkout --track -b creates a new tracking branch' '
test_expect_success 'checkout --track -b rejects an extra path argument' '
test_must_fail git checkout --track -b branch2 main one.t 2>err &&
- test_i18ngrep "cannot be used with updating paths" err
+ test_grep "cannot be used with updating paths" err
'
test_expect_success 'checkout --track -b overrides autoSetupMerge=inherit' '
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index 2d8c70b03a..be3fcdde07 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -37,11 +37,17 @@ prime_resolve_undo () {
git checkout second^0 &&
test_tick &&
test_must_fail git merge third^0 &&
- echo merge does not leave anything &&
check_resolve_undo empty &&
- echo different >fi/le &&
- git add fi/le &&
- echo resolving records &&
+
+ # how should the conflict be resolved?
+ case "$1" in
+ remove)
+ rm -f file/le && git rm fi/le
+ ;;
+ *) # modify
+ echo different >fi/le && git add fi/le
+ ;;
+ esac
check_resolve_undo recorded fi/le initial:fi/le second:fi/le third:fi/le
}
@@ -122,6 +128,37 @@ test_expect_success 'add records checkout -m undoes' '
test_expect_success 'unmerge with plumbing' '
prime_resolve_undo &&
git update-index --unresolve fi/le &&
+ git ls-files --resolve-undo fi/le >actual &&
+ test_must_be_empty actual &&
+ git ls-files -u >actual &&
+ test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge can be done even after committing' '
+ prime_resolve_undo &&
+ git commit -m "record to nuke MERGE_HEAD" &&
+ git update-index --unresolve fi/le &&
+ git ls-files --resolve-undo fi/le >actual &&
+ test_must_be_empty actual &&
+ git ls-files -u >actual &&
+ test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge removal' '
+ prime_resolve_undo remove &&
+ git update-index --unresolve fi/le &&
+ git ls-files --resolve-undo fi/le >actual &&
+ test_must_be_empty actual &&
+ git ls-files -u >actual &&
+ test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge removal after committing' '
+ prime_resolve_undo remove &&
+ git commit -m "record to nuke MERGE_HEAD" &&
+ git update-index --unresolve fi/le &&
+ git ls-files --resolve-undo fi/le >actual &&
+ test_must_be_empty actual &&
git ls-files -u >actual &&
test_line_count = 3 actual
'
@@ -191,7 +228,7 @@ test_expect_success 'rerere forget (add-add conflict)' '
git commit -m "add differently" &&
test_must_fail git merge fifth &&
git rerere forget add-differently 2>actual &&
- test_i18ngrep "no remembered" actual
+ test_grep "no remembered" actual
'
test_expect_success 'resolve-undo keeps blobs from gc' '
diff --git a/t/t2050-git-dir-relative.sh b/t/t2050-git-dir-relative.sh
index 1f193cde96..21f4659a9d 100755
--- a/t/t2050-git-dir-relative.sh
+++ b/t/t2050-git-dir-relative.sh
@@ -12,7 +12,6 @@ into the subdir while keeping the worktree location,
and tries commits from the top and the subdir, checking
that the commit-hook still gets called.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
COMMIT_FILE="$(pwd)/output"
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index e247a4735b..c91c4db936 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -170,8 +170,10 @@ test_expect_success 'switch back when temporarily detached and checked out elsew
# we test in both worktrees to ensure that works
# as expected with "first" and "next" worktrees
test_must_fail git -C wt1 switch shared &&
+ test_must_fail git -C wt1 switch -C shared &&
git -C wt1 switch --ignore-other-worktrees shared &&
test_must_fail git -C wt2 switch shared &&
+ test_must_fail git -C wt2 switch -C shared &&
git -C wt2 switch --ignore-other-worktrees shared
'
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index c5d19dd973..16d6348b69 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -137,11 +137,78 @@ test_expect_success 'restore --staged invalidates cache tree for deletions' '
test_must_fail git rev-parse HEAD:new1
'
-test_expect_success 'restore with merge options rejects --staged' '
+test_expect_success 'restore --merge to unresolve' '
+ O=$(echo original | git hash-object -w --stdin) &&
+ A=$(echo ourside | git hash-object -w --stdin) &&
+ B=$(echo theirside | git hash-object -w --stdin) &&
+ {
+ echo "100644 $O 1 file" &&
+ echo "100644 $A 2 file" &&
+ echo "100644 $B 3 file"
+ } | git update-index --index-info &&
+ echo nothing >file &&
+ git restore --worktree --merge file &&
+ cat >expect <<-\EOF &&
+ <<<<<<< ours
+ ourside
+ =======
+ theirside
+ >>>>>>> theirs
+ EOF
+ test_cmp expect file
+'
+
+test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
+ O=$(echo original | git hash-object -w --stdin) &&
+ A=$(echo ourside | git hash-object -w --stdin) &&
+ B=$(echo theirside | git hash-object -w --stdin) &&
+ {
+ echo "100644 $O 1 file" &&
+ echo "100644 $A 2 file" &&
+ echo "100644 $B 3 file"
+ } | git update-index --index-info &&
+ echo nothing >file &&
+ git add file &&
+ git restore --worktree --merge file &&
+ cat >expect <<-\EOF &&
+ <<<<<<< ours
+ ourside
+ =======
+ theirside
+ >>>>>>> theirs
+ EOF
+ test_cmp expect file
+'
+
+test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
+ O=$(echo original | git hash-object -w --stdin) &&
+ A=$(echo ourside | git hash-object -w --stdin) &&
+ B=$(echo theirside | git hash-object -w --stdin) &&
+ {
+ echo "100644 $O 1 file" &&
+ echo "100644 $A 2 file" &&
+ echo "100644 $B 3 file"
+ } | git update-index --index-info &&
+ git rm -f file &&
+ git restore --worktree --merge file &&
+ cat >expect <<-\EOF &&
+ <<<<<<< ours
+ ourside
+ =======
+ theirside
+ >>>>>>> theirs
+ EOF
+ test_cmp expect file
+'
+
+test_expect_success 'restore with merge options are incompatible with certain options' '
for opts in \
"--staged --ours" \
"--staged --theirs" \
"--staged --merge" \
+ "--source=HEAD --ours" \
+ "--source=HEAD --theirs" \
+ "--source=HEAD --merge" \
"--staged --conflict=diff3" \
"--staged --worktree --ours" \
"--staged --worktree --theirs" \
@@ -149,7 +216,7 @@ test_expect_success 'restore with merge options rejects --staged' '
"--staged --worktree --conflict=zdiff3"
do
test_must_fail git restore $opts . 2>err &&
- grep "cannot be used with --staged" err || return
+ grep "cannot be used" err || return
done
'
diff --git a/t/t2071-restore-patch.sh b/t/t2071-restore-patch.sh
index b5c5c0ff7e..27e85be40a 100755
--- a/t/t2071-restore-patch.sh
+++ b/t/t2071-restore-patch.sh
@@ -4,7 +4,7 @@ test_description='git restore --patch'
. ./lib-patch-mode.sh
-test_expect_success PERL 'setup' '
+test_expect_success 'setup' '
mkdir dir &&
echo parent >dir/foo &&
echo dummy >bar &&
@@ -16,43 +16,47 @@ test_expect_success PERL 'setup' '
save_head
'
-test_expect_success PERL 'restore -p without pathspec is fine' '
+test_expect_success 'restore -p without pathspec is fine' '
echo q >cmd &&
git restore -p <cmd
'
# note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar'
-test_expect_success PERL 'saying "n" does nothing' '
+test_expect_success 'saying "n" does nothing' '
set_and_save_state dir/foo work head &&
test_write_lines n n | git restore -p &&
verify_saved_state bar &&
verify_saved_state dir/foo
'
-test_expect_success PERL 'git restore -p' '
+test_expect_success 'git restore -p' '
set_and_save_state dir/foo work head &&
test_write_lines n y | git restore -p &&
verify_saved_state bar &&
verify_state dir/foo head head
'
-test_expect_success PERL 'git restore -p with staged changes' '
+test_expect_success 'git restore -p with staged changes' '
set_state dir/foo work index &&
test_write_lines n y | git restore -p &&
verify_saved_state bar &&
verify_state dir/foo index index
'
-test_expect_success PERL 'git restore -p --source=HEAD' '
- set_state dir/foo work index &&
- # the third n is to get out in case it mistakenly does not apply
- test_write_lines n y n | git restore -p --source=HEAD &&
- verify_saved_state bar &&
- verify_state dir/foo head index
-'
-
-test_expect_success PERL 'git restore -p --source=HEAD^' '
+for opt in "HEAD" "@"
+do
+ test_expect_success "git restore -p --source=$opt" '
+ set_state dir/foo work index &&
+ # the third n is to get out in case it mistakenly does not apply
+ test_write_lines n y n | git restore -p --source=$opt >output &&
+ verify_saved_state bar &&
+ verify_state dir/foo head index &&
+ test_grep "Discard" output
+ '
+done
+
+test_expect_success 'git restore -p --source=HEAD^' '
set_state dir/foo work index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git restore -p --source=HEAD^ &&
@@ -60,7 +64,7 @@ test_expect_success PERL 'git restore -p --source=HEAD^' '
verify_state dir/foo parent index
'
-test_expect_success PERL 'git restore -p --source=HEAD^...' '
+test_expect_success 'git restore -p --source=HEAD^...' '
set_state dir/foo work index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git restore -p --source=HEAD^... &&
@@ -68,7 +72,7 @@ test_expect_success PERL 'git restore -p --source=HEAD^...' '
verify_state dir/foo parent index
'
-test_expect_success PERL 'git restore -p handles deletion' '
+test_expect_success 'git restore -p handles deletion' '
set_state dir/foo work index &&
rm dir/foo &&
test_write_lines n y | git restore -p &&
@@ -81,21 +85,21 @@ test_expect_success PERL 'git restore -p handles deletion' '
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
# the failure case (and thus get out of the loop).
-test_expect_success PERL 'path limiting works: dir' '
+test_expect_success 'path limiting works: dir' '
set_state dir/foo work head &&
test_write_lines y n | git restore -p dir &&
verify_saved_state bar &&
verify_state dir/foo head head
'
-test_expect_success PERL 'path limiting works: -- dir' '
+test_expect_success 'path limiting works: -- dir' '
set_state dir/foo work head &&
test_write_lines y n | git restore -p -- dir &&
verify_saved_state bar &&
verify_state dir/foo head head
'
-test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
+test_expect_success 'path limiting works: HEAD^ -- dir' '
set_state dir/foo work head &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines y n n | git restore -p --source=HEAD^ -- dir &&
@@ -103,7 +107,7 @@ test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
verify_state dir/foo parent head
'
-test_expect_success PERL 'path limiting works: foo inside dir' '
+test_expect_success 'path limiting works: foo inside dir' '
set_state dir/foo work head &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines y n n | (cd dir && git restore -p foo) &&
@@ -111,7 +115,7 @@ test_expect_success PERL 'path limiting works: foo inside dir' '
verify_state dir/foo head head
'
-test_expect_success PERL 'none of this moved HEAD' '
+test_expect_success 'none of this moved HEAD' '
verify_saved_head
'
diff --git a/t/t2072-restore-pathspec-file.sh b/t/t2072-restore-pathspec-file.sh
index c22669b39f..8198a1e578 100755
--- a/t/t2072-restore-pathspec-file.sh
+++ b/t/t2072-restore-pathspec-file.sh
@@ -152,16 +152,16 @@ test_expect_success 'error conditions' '
>empty_list &&
test_must_fail git restore --pathspec-from-file=list --patch --source=HEAD^1 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git restore --pathspec-from-file=list --source=HEAD^1 -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git restore --pathspec-file-nul --source=HEAD^1 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
test_must_fail git restore --pathspec-from-file=empty_list --source=HEAD^1 2>err &&
- test_i18ngrep -e "you must specify path(s) to restore" err
+ test_grep -e "you must specify path(s) to restore" err
'
test_expect_success 'wildcard pathspec matches file in subdirectory' '
diff --git a/t/t2081-parallel-checkout-collisions.sh b/t/t2081-parallel-checkout-collisions.sh
index 6acdb89d12..f6fcfc0c1e 100755
--- a/t/t2081-parallel-checkout-collisions.sh
+++ b/t/t2081-parallel-checkout-collisions.sh
@@ -11,7 +11,6 @@ The tests in this file exercise parallel checkout's collision detection code in
both these mechanics.
"
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-parallel-checkout.sh"
diff --git a/t/t2082-parallel-checkout-attributes.sh b/t/t2082-parallel-checkout-attributes.sh
index f3511cd43a..79fb11f139 100755
--- a/t/t2082-parallel-checkout-attributes.sh
+++ b/t/t2082-parallel-checkout-attributes.sh
@@ -33,7 +33,7 @@ test_expect_success 'parallel-checkout with ident' '
)
'
-test_expect_success 'parallel-checkout with re-encoding' '
+test_expect_success ICONV 'parallel-checkout with re-encoding' '
set_checkout_config 2 0 &&
git init encoding &&
(
@@ -90,7 +90,7 @@ test_expect_success 'parallel-checkout with eol conversions' '
# Entries that require an external filter are not eligible for parallel
# checkout. Check that both the parallel-eligible and non-eligible entries are
-# properly writen in a single checkout operation.
+# properly written in a single checkout operation.
#
test_expect_success 'parallel-checkout and external filter' '
set_checkout_config 2 0 &&
diff --git a/t/t2100-update-cache-badpath.sh b/t/t2100-update-cache-badpath.sh
index 7915e7b821..2df3fdde8b 100755
--- a/t/t2100-update-cache-badpath.sh
+++ b/t/t2100-update-cache-badpath.sh
@@ -22,7 +22,6 @@ and tries to git update-index --add the following:
All of the attempts should fail.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
mkdir path2 path3
diff --git a/t/t2101-update-index-reupdate.sh b/t/t2101-update-index-reupdate.sh
index e3c7acdbf9..6c32d42c8c 100755
--- a/t/t2101-update-index-reupdate.sh
+++ b/t/t2101-update-index-reupdate.sh
@@ -6,7 +6,6 @@
test_description='git update-index --again test.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'update-index --add' '
diff --git a/t/t2102-update-index-symlinks.sh b/t/t2102-update-index-symlinks.sh
index c49cdfb6e5..9b11130ab9 100755
--- a/t/t2102-update-index-symlinks.sh
+++ b/t/t2102-update-index-symlinks.sh
@@ -8,7 +8,6 @@ test_description='git update-index on filesystem w/o symlinks test.
This tests that git update-index keeps the symbolic link property
even if a plain file is in the working tree if core.symlinks is false.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success \
diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh
index e9451cd567..6938ecca86 100755
--- a/t/t2103-update-index-ignore-missing.sh
+++ b/t/t2103-update-index-ignore-missing.sh
@@ -2,7 +2,6 @@
test_description='update-index with options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success basics '
diff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh
index b8686aabd3..7a0778ed98 100755
--- a/t/t2104-update-index-skip-worktree.sh
+++ b/t/t2104-update-index-skip-worktree.sh
@@ -5,33 +5,32 @@
test_description='skip-worktree bit test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
sane_unset GIT_TEST_SPLIT_INDEX
test_set_index_version () {
- GIT_INDEX_VERSION="$1"
- export GIT_INDEX_VERSION
+ GIT_INDEX_VERSION="$1"
+ export GIT_INDEX_VERSION
}
test_set_index_version 3
-cat >expect.full <<EOF
-H 1
-H 2
-H sub/1
-H sub/2
-EOF
+test_expect_success 'setup' '
+ cat >expect.full <<-\EOF &&
+ H 1
+ H 2
+ H sub/1
+ H sub/2
+ EOF
-cat >expect.skip <<EOF
-S 1
-H 2
-S sub/1
-H sub/2
-EOF
+ cat >expect.skip <<-\EOF &&
+ S 1
+ H 2
+ S sub/1
+ H sub/2
+ EOF
-test_expect_success 'setup' '
mkdir sub &&
touch ./1 ./2 sub/1 sub/2 &&
git add 1 2 sub/1 sub/2 &&
@@ -39,7 +38,7 @@ test_expect_success 'setup' '
'
test_expect_success 'index is at version 2' '
- test "$(test-tool index-version < .git/index)" = 2
+ test "$(git update-index --show-index-version)" = 2
'
test_expect_success 'update-index --skip-worktree' '
@@ -48,7 +47,7 @@ test_expect_success 'update-index --skip-worktree' '
'
test_expect_success 'index is at version 3 after having some skip-worktree entries' '
- test "$(test-tool index-version < .git/index)" = 3
+ test "$(git update-index --show-index-version)" = 3
'
test_expect_success 'ls-files -t' '
@@ -61,7 +60,7 @@ test_expect_success 'update-index --no-skip-worktree' '
'
test_expect_success 'index version is back to 2 when there is no skip-worktree entry' '
- test "$(test-tool index-version < .git/index)" = 2
+ test "$(git update-index --show-index-version)" = 2
'
test_done
diff --git a/t/t2105-update-index-gitfile.sh b/t/t2105-update-index-gitfile.sh
index 963ebe77eb..a7f3d47aec 100755
--- a/t/t2105-update-index-gitfile.sh
+++ b/t/t2105-update-index-gitfile.sh
@@ -6,7 +6,6 @@
test_description='git update-index for gitlink to .git file.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'submodule with absolute .git file' '
diff --git a/t/t2106-update-index-assume-unchanged.sh b/t/t2106-update-index-assume-unchanged.sh
index d943ddf47e..6b2ccc21a9 100755
--- a/t/t2106-update-index-assume-unchanged.sh
+++ b/t/t2106-update-index-assume-unchanged.sh
@@ -3,7 +3,6 @@
test_description='git update-index --assume-unchanged test.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -22,7 +21,7 @@ test_expect_success 'do not switch branches with dirty file' '
echo dirt >file &&
git update-index --assume-unchanged file &&
test_must_fail git checkout - 2>err &&
- test_i18ngrep overwritten err
+ test_grep overwritten err
'
test_done
diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh
index 89b285fa3a..cc72ead79f 100755
--- a/t/t2107-update-index-basic.sh
+++ b/t/t2107-update-index-basic.sh
@@ -14,7 +14,7 @@ test_expect_success 'update-index --nonsense fails' '
test_expect_success 'update-index --nonsense dumps usage' '
test_expect_code 129 git update-index --nonsense 2>err &&
- test_i18ngrep "[Uu]sage: git update-index" err
+ test_grep "[Uu]sage: git update-index" err
'
test_expect_success 'update-index -h with corrupt index' '
@@ -25,7 +25,7 @@ test_expect_success 'update-index -h with corrupt index' '
>.git/index &&
test_expect_code 129 git update-index -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage: git update-index" broken/usage
+ test_grep "[Uu]sage: git update-index" broken/usage
'
test_expect_success '--cacheinfo complains of missing arguments' '
@@ -111,4 +111,35 @@ test_expect_success '--chmod=+x and chmod=-x in the same argument list' '
test_cmp expect actual
'
+test_expect_success '--index-version' '
+ git commit --allow-empty -m snap &&
+ git reset --hard &&
+ git rm -f -r --cached . &&
+
+ # The default index version is 2 --- update this test
+ # when you change it in the code
+ git update-index --show-index-version >actual &&
+ echo 2 >expect &&
+ test_cmp expect actual &&
+
+ # The next test wants us to be using version 2
+ git update-index --index-version 2 &&
+
+ git update-index --index-version 4 --verbose >actual &&
+ echo "index-version: was 2, set to 4" >expect &&
+ test_cmp expect actual &&
+
+ git update-index --index-version 4 --verbose >actual &&
+ echo "index-version: was 4, set to 4" >expect &&
+ test_cmp expect actual &&
+
+ git update-index --index-version 2 --verbose >actual &&
+ echo "index-version: was 4, set to 2" >expect &&
+ test_cmp expect actual &&
+
+ # non-verbose should be silent
+ git update-index --index-version 4 >actual &&
+ test_must_be_empty actual
+'
+
test_done
diff --git a/t/t2108-update-index-refresh-racy.sh b/t/t2108-update-index-refresh-racy.sh
index bc5f2886fa..b31dd8ece5 100755
--- a/t/t2108-update-index-refresh-racy.sh
+++ b/t/t2108-update-index-refresh-racy.sh
@@ -2,7 +2,6 @@
test_description='update-index refresh tests related to racy timestamps'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
reset_files () {
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index c01492f33f..06e83d3333 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -14,7 +14,6 @@ only the updates to dir/sub.
Also tested are "git add -u" without limiting, and "git add -u"
without contents changes, and other conditions'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -65,6 +64,16 @@ test_expect_success 'update did not touch untracked files' '
test_must_be_empty out
'
+test_expect_success 'error out when passing untracked path' '
+ git reset --hard &&
+ echo content >>baz &&
+ echo content >>top &&
+ test_must_fail git add -u baz top 2>err &&
+ test_grep -e "error: pathspec .baz. did not match any file(s) known to git" err &&
+ git diff --cached --name-only >actual &&
+ test_must_be_empty actual
+'
+
test_expect_success 'cache tree has not been corrupted' '
git ls-files -s |
diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh
index dba62d69c6..687be974d4 100755
--- a/t/t2201-add-update-typechange.sh
+++ b/t/t2201-add-update-typechange.sh
@@ -2,7 +2,6 @@
test_description='more git add -u'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh
index 24c60bfd79..9ee659098c 100755
--- a/t/t2202-add-addremove.sh
+++ b/t/t2202-add-addremove.sh
@@ -2,7 +2,6 @@
test_description='git add --all'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh
index ebf58db2d1..192ad14b5f 100755
--- a/t/t2203-add-intent.sh
+++ b/t/t2203-add-intent.sh
@@ -2,7 +2,6 @@
test_description='Intent to add'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'intent to add' '
@@ -173,7 +172,7 @@ test_expect_success 'rename detection finds the right names' '
git add -N third &&
git status | grep -v "^?" >actual.1 &&
- test_i18ngrep "renamed: *first -> third" actual.1 &&
+ test_grep "renamed: *first -> third" actual.1 &&
git status --porcelain | grep -v "^?" >actual.2 &&
cat >expected.2 <<-\EOF &&
@@ -213,8 +212,8 @@ test_expect_success 'double rename detection in status' '
git add -N third &&
git status | grep -v "^?" >actual.1 &&
- test_i18ngrep "renamed: *first -> second" actual.1 &&
- test_i18ngrep "renamed: *second -> third" actual.1 &&
+ test_grep "renamed: *first -> second" actual.1 &&
+ test_grep "renamed: *second -> third" actual.1 &&
git status --porcelain | grep -v "^?" >actual.2 &&
cat >expected.2 <<-\EOF &&
diff --git a/t/t2204-add-ignored.sh b/t/t2204-add-ignored.sh
index 89424abccd..31eb233df5 100755
--- a/t/t2204-add-ignored.sh
+++ b/t/t2204-add-ignored.sh
@@ -2,7 +2,6 @@
test_description='giving ignored paths to git add'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -36,7 +35,7 @@ do
'
test_expect_success "complaints for ignored $i output" '
- test_i18ngrep -e "Use -f if" err
+ test_grep -e "Use -f if" err
'
test_expect_success "complaints for ignored $i with unignored file" '
@@ -46,7 +45,7 @@ do
test_must_be_empty out
'
test_expect_success "complaints for ignored $i with unignored file output" '
- test_i18ngrep -e "Use -f if" err
+ test_grep -e "Use -f if" err
'
done
@@ -65,7 +64,7 @@ do
test_expect_success "complaints for ignored $i in dir output" '
(
cd dir &&
- test_i18ngrep -e "Use -f if" err
+ test_grep -e "Use -f if" err
)
'
done
@@ -85,7 +84,7 @@ do
test_expect_success "complaints for ignored $i in sub output" '
(
cd sub &&
- test_i18ngrep -e "Use -f if" err
+ test_grep -e "Use -f if" err
)
'
done
diff --git a/t/t2205-add-worktree-config.sh b/t/t2205-add-worktree-config.sh
index 98265ba1b4..43d950de64 100755
--- a/t/t2205-add-worktree-config.sh
+++ b/t/t2205-add-worktree-config.sh
@@ -17,7 +17,6 @@ outside the repository. Two instances for which this can occur are tested:
repository can be added to the index.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success '1a: setup--config worktree' '
diff --git a/t/t2300-cd-to-toplevel.sh b/t/t2300-cd-to-toplevel.sh
index b40eeb263f..c8de6d8a19 100755
--- a/t/t2300-cd-to-toplevel.sh
+++ b/t/t2300-cd-to-toplevel.sh
@@ -2,7 +2,6 @@
test_description='cd_to_toplevel'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
EXEC_PATH="$(git --exec-path)"
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 051363acbb..ba320dc417 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -121,7 +121,30 @@ test_expect_success '"add" worktree creating new branch' '
test_expect_success 'die the same branch is already checked out' '
(
cd here &&
- test_must_fail git checkout newmain
+ test_must_fail git checkout newmain 2>actual &&
+ grep "already used by worktree at" actual
+ )
+'
+
+test_expect_success 'refuse to reset a branch in use elsewhere' '
+ (
+ cd here &&
+
+ # we know we are on detached HEAD but just in case ...
+ git checkout --detach HEAD &&
+ git rev-parse --verify HEAD >old.head &&
+
+ git rev-parse --verify refs/heads/newmain >old.branch &&
+ test_must_fail git checkout -B newmain 2>error &&
+ git rev-parse --verify refs/heads/newmain >new.branch &&
+ git rev-parse --verify HEAD >new.head &&
+
+ grep "already used by worktree at" error &&
+ test_cmp old.branch new.branch &&
+ test_cmp old.head new.head &&
+
+ # and we must be still on the same detached HEAD state
+ test_must_fail git symbolic-ref HEAD
)
'
@@ -404,7 +427,7 @@ test_expect_success '"add" worktree with orphan branch, lock, and reason' '
# Note: Quoted arguments containing spaces are not supported.
test_wt_add_orphan_hint () {
local context="$1" &&
- local use_branch=$2 &&
+ local use_branch="$2" &&
shift 2 &&
local opts="$*" &&
test_expect_success "'worktree add' show orphan hint in bad/orphan HEAD w/ $context" '
@@ -414,7 +437,7 @@ test_wt_add_orphan_hint () {
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 &&
+ grep "hint: If you meant to create a worktree containing a new unborn branch" actual &&
if [ $use_branch -eq 1 ]
then
grep -E "^hint: +git worktree add --orphan -b [^ ]+ [^ ]+$" actual
@@ -435,7 +458,7 @@ test_expect_success "'worktree add' doesn't show orphan hint in bad/orphan HEAD
(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
+ ! grep "hint: If you meant to create a worktree containing a new unborn branch" actual
'
test_expect_success 'local clone from linked checkout' '
@@ -467,7 +490,8 @@ test_expect_success 'put a worktree under rebase' '
cd under-rebase &&
set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
- git worktree list | grep "under-rebase.*detached HEAD"
+ git worktree list >actual &&
+ grep "under-rebase.*detached HEAD" actual
)
'
@@ -508,7 +532,8 @@ test_expect_success 'checkout a branch under bisect' '
git bisect start &&
git bisect bad &&
git bisect good HEAD~2 &&
- git worktree list | grep "under-bisect.*detached HEAD" &&
+ git worktree list >actual &&
+ grep "under-bisect.*detached HEAD" actual &&
test_must_fail git worktree add new-bisect under-bisect &&
! test -d new-bisect
)
@@ -708,9 +733,9 @@ 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 orphan_hint="hint: If you meant to create a worktree containing a new unborn branch" &&
local invalid_ref_regex="^fatal: invalid reference: " &&
- local bad_combo_regex="^fatal: '[-a-z]*' and '[-a-z]*' cannot be used together" &&
+ local bad_combo_regex="^fatal: options '[-a-z]*' and '[-a-z]*' cannot be used together" &&
local git_ns="repo" &&
local dashc_args="-C $git_ns" &&
diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh
index 568a47ec42..aa5b42c0f7 100755
--- a/t/t2401-worktree-prune.sh
+++ b/t/t2401-worktree-prune.sh
@@ -5,7 +5,6 @@ test_description='prune $GIT_DIR/worktrees'
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 initialize '
@@ -47,7 +46,7 @@ test_expect_success SANITY 'prune directories with unreadable gitdir' '
: >.git/worktrees/def/gitdir &&
chmod u-r .git/worktrees/def/gitdir &&
git worktree prune --verbose 2>actual &&
- test_i18ngrep "Removing worktrees/def: unable to read gitdir file" actual &&
+ test_grep "Removing worktrees/def: unable to read gitdir file" actual &&
! test -d .git/worktrees/def &&
! test -d .git/worktrees
'
@@ -57,7 +56,7 @@ test_expect_success 'prune directories with invalid gitdir' '
: >.git/worktrees/def/def &&
: >.git/worktrees/def/gitdir &&
git worktree prune --verbose 2>actual &&
- test_i18ngrep "Removing worktrees/def: invalid gitdir file" actual &&
+ test_grep "Removing worktrees/def: invalid gitdir file" actual &&
! test -d .git/worktrees/def &&
! test -d .git/worktrees
'
@@ -67,7 +66,7 @@ test_expect_success 'prune directories with gitdir pointing to nowhere' '
: >.git/worktrees/def/def &&
echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir &&
git worktree prune --verbose 2>actual &&
- test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual &&
+ test_grep "Removing worktrees/def: gitdir file points to non-existent location" actual &&
! test -d .git/worktrees/def &&
! test -d .git/worktrees
'
@@ -103,7 +102,7 @@ test_expect_success 'prune duplicate (linked/linked)' '
sed "s/w2/w1/" .git/worktrees/w2/gitdir >.git/worktrees/w2/gitdir.new &&
mv .git/worktrees/w2/gitdir.new .git/worktrees/w2/gitdir &&
git worktree prune --verbose 2>actual &&
- test_i18ngrep "duplicate entry" actual &&
+ test_grep "duplicate entry" actual &&
test -d .git/worktrees/w1 &&
! test -d .git/worktrees/w2
'
@@ -116,8 +115,27 @@ test_expect_success 'prune duplicate (main/linked)' '
rm -fr wt &&
mv repo wt &&
git -C wt worktree prune --verbose 2>actual &&
- test_i18ngrep "duplicate entry" actual &&
+ test_grep "duplicate entry" actual &&
! test -d .git/worktrees/wt
'
+test_expect_success 'not prune proper worktrees when run inside linked worktree' '
+ test_when_finished rm -rf repo wt_ext &&
+ git init repo &&
+ (
+ cd repo &&
+ echo content >file &&
+ git add file &&
+ git commit -m msg &&
+ git worktree add ../wt_ext &&
+ git worktree add wt_int &&
+ cd wt_int &&
+ git worktree prune -v >out &&
+ test_must_be_empty out &&
+ cd ../../wt_ext &&
+ git worktree prune -v >out &&
+ test_must_be_empty out
+ )
+'
+
test_done
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index 9ad9be0c20..cb125ec226 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -5,7 +5,6 @@ test_description='test git worktree list'
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' '
@@ -143,7 +142,7 @@ test_expect_success '"list" all worktrees --porcelain with prunable' '
rm -rf prunable &&
git worktree list --porcelain >out &&
sed -n "/^worktree .*\/prunable$/,/^$/p" <out >only_prunable &&
- test_i18ngrep "^prunable gitdir file points to non-existent location$" only_prunable
+ test_grep "^prunable gitdir file points to non-existent location$" only_prunable
'
test_expect_success '"list" all worktrees with prunable consistent with "prune"' '
@@ -155,8 +154,8 @@ test_expect_success '"list" all worktrees with prunable consistent with "prune"'
grep "/prunable *[0-9a-f].* prunable$" out &&
! grep "/unprunable *[0-9a-f].* unprunable$" out &&
git worktree prune --verbose 2>out &&
- test_i18ngrep "^Removing worktrees/prunable" out &&
- test_i18ngrep ! "^Removing worktrees/unprunable" out
+ test_grep "^Removing worktrees/prunable" out &&
+ test_grep ! "^Removing worktrees/unprunable" out
'
test_expect_success '"list" --verbose and --porcelain mutually exclusive' '
diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh
index 230a55e99a..08531deb5b 100755
--- a/t/t2403-worktree-move.sh
+++ b/t/t2403-worktree-move.sh
@@ -2,7 +2,6 @@
test_description='test git worktree move, remove, lock and unlock'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -202,7 +201,7 @@ test_expect_success 'proper error when worktree not found' '
for i in noodle noodle/bork
do
test_must_fail git worktree lock $i 2>err &&
- test_i18ngrep "not a working tree" err || return 1
+ test_grep "not a working tree" err || return 1
done
'
diff --git a/t/t2404-worktree-config.sh b/t/t2404-worktree-config.sh
index 842937bfb9..9536d10919 100755
--- a/t/t2404-worktree-config.sh
+++ b/t/t2404-worktree-config.sh
@@ -2,7 +2,6 @@
test_description="config file in multi worktree"
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh
index 8970780efc..bf340b8772 100755
--- a/t/t2406-worktree-repair.sh
+++ b/t/t2406-worktree-repair.sh
@@ -2,7 +2,6 @@
test_description='test git worktree repair'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -25,7 +24,7 @@ test_expect_success 'worktree path not directory' '
>notdir &&
test_must_fail git worktree repair >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "not a directory" err
+ test_grep "not a directory" err
'
test_expect_success "don't clobber .git repo" '
@@ -35,7 +34,7 @@ test_expect_success "don't clobber .git repo" '
test_create_repo repo &&
test_must_fail git worktree repair >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep ".git is not a file" err
+ test_grep ".git is not a file" err
'
test_corrupt_gitfile () {
@@ -47,7 +46,7 @@ test_corrupt_gitfile () {
git -C corrupt rev-parse --absolute-git-dir >expect &&
eval "$butcher" &&
git -C "$repairdir" worktree repair 2>err &&
- test_i18ngrep "$problem" err &&
+ test_grep "$problem" err &&
git -C corrupt rev-parse --absolute-git-dir >actual &&
test_cmp expect actual
}
@@ -93,7 +92,7 @@ test_expect_success 'repair .git file from bare.git' '
test_expect_success 'invalid worktree path' '
test_must_fail git worktree repair /notvalid >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "not a valid path" err
+ test_grep "not a valid path" err
'
test_expect_success 'repo not found; .git not file' '
@@ -101,7 +100,7 @@ test_expect_success 'repo not found; .git not file' '
test_create_repo not-a-worktree &&
test_must_fail git worktree repair not-a-worktree >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep ".git is not a file" err
+ test_grep ".git is not a file" err
'
test_expect_success 'repo not found; .git not referencing repo' '
@@ -111,7 +110,7 @@ test_expect_success 'repo not found; .git not referencing repo' '
mv side/.newgit side/.git &&
mkdir not-a-repo &&
test_must_fail git worktree repair side 2>err &&
- test_i18ngrep ".git file does not reference a repository" err
+ test_grep ".git file does not reference a repository" err
'
test_expect_success 'repo not found; .git file broken' '
@@ -121,7 +120,7 @@ test_expect_success 'repo not found; .git file broken' '
mv orig moved &&
test_must_fail git worktree repair moved >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep ".git file broken" err
+ test_grep ".git file broken" err
'
test_expect_success 'repair broken gitdir' '
@@ -132,7 +131,7 @@ test_expect_success 'repair broken gitdir' '
mv orig moved &&
git worktree repair moved 2>err &&
test_cmp expect .git/worktrees/orig/gitdir &&
- test_i18ngrep "gitdir unreadable" err
+ test_grep "gitdir unreadable" err
'
test_expect_success 'repair incorrect gitdir' '
@@ -142,7 +141,7 @@ test_expect_success 'repair incorrect gitdir' '
mv orig moved &&
git worktree repair moved 2>err &&
test_cmp expect .git/worktrees/orig/gitdir &&
- test_i18ngrep "gitdir incorrect" err
+ test_grep "gitdir incorrect" err
'
test_expect_success 'repair gitdir (implicit) from linked worktree' '
@@ -152,7 +151,7 @@ test_expect_success 'repair gitdir (implicit) from linked worktree' '
mv orig moved &&
git -C moved worktree repair 2>err &&
test_cmp expect .git/worktrees/orig/gitdir &&
- test_i18ngrep "gitdir incorrect" err
+ test_grep "gitdir incorrect" err
'
test_expect_success 'unable to repair gitdir (implicit) from main worktree' '
@@ -177,8 +176,8 @@ test_expect_success 'repair multiple gitdir files' '
git worktree repair moved1 moved2 2>err &&
test_cmp expect1 .git/worktrees/orig1/gitdir &&
test_cmp expect2 .git/worktrees/orig2/gitdir &&
- test_i18ngrep "gitdir incorrect:.*orig1/gitdir$" err &&
- test_i18ngrep "gitdir incorrect:.*orig2/gitdir$" err
+ test_grep "gitdir incorrect:.*orig1/gitdir$" err &&
+ test_grep "gitdir incorrect:.*orig2/gitdir$" err
'
test_expect_success 'repair moved main and linked worktrees' '
@@ -197,4 +196,23 @@ test_expect_success 'repair moved main and linked worktrees' '
test_cmp expect-gitfile sidemoved/.git
'
+test_expect_success 'repair copied main and linked worktrees' '
+ test_when_finished "rm -rf orig dup" &&
+ mkdir -p orig &&
+ git -C orig init main &&
+ test_commit -C orig/main nothing &&
+ git -C orig/main worktree add ../linked &&
+ cp orig/main/.git/worktrees/linked/gitdir orig/main.expect &&
+ cp orig/linked/.git orig/linked.expect &&
+ cp -R orig dup &&
+ sed "s,orig/linked/\.git$,dup/linked/.git," orig/main.expect >dup/main.expect &&
+ sed "s,orig/main/\.git/worktrees/linked$,dup/main/.git/worktrees/linked," \
+ orig/linked.expect >dup/linked.expect &&
+ git -C dup/main worktree repair ../linked &&
+ test_cmp orig/main.expect orig/main/.git/worktrees/linked/gitdir &&
+ test_cmp orig/linked.expect orig/linked/.git &&
+ test_cmp dup/main.expect dup/main/.git/worktrees/linked/gitdir &&
+ test_cmp dup/linked.expect dup/linked/.git
+'
+
test_done
diff --git a/t/t2407-worktree-heads.sh b/t/t2407-worktree-heads.sh
index 469443d8ae..57c201869f 100755
--- a/t/t2407-worktree-heads.sh
+++ b/t/t2407-worktree-heads.sh
@@ -2,7 +2,6 @@
test_description='test operations trying to overwrite refs at worktree HEAD'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -45,11 +44,11 @@ test_expect_success 'refuse to overwrite: checked out in worktree' '
grep "cannot force update the branch" err &&
test_must_fail git branch -D wt-$i 2>err &&
- grep "Cannot delete branch" err || return 1
+ grep "cannot delete branch" err || return 1
done
'
-test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in bisect' '
+test_expect_success 'refuse to overwrite: worktree in bisect' '
test_when_finished git -C wt-4 bisect reset &&
# Set up a bisect so HEAD no longer points to wt-4.
@@ -61,7 +60,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in bisect' '
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)' '
+test_expect_success 'refuse to overwrite: worktree in rebase (apply)' '
test_when_finished git -C wt-2 rebase --abort &&
# This will fail part-way through due to a conflict.
@@ -71,7 +70,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (app
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)' '
+test_expect_success 'refuse to overwrite: worktree in rebase (merge)' '
test_when_finished git -C wt-2 rebase --abort &&
# This will fail part-way through due to a conflict.
@@ -81,7 +80,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (mer
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' '
+test_expect_success 'refuse to overwrite: worktree in rebase with --update-refs' '
test_when_finished git -C wt-3 rebase --abort &&
git branch -f can-be-updated wt-3 &&
@@ -95,7 +94,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase with
done
'
-test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: checked out' '
+test_expect_success 'refuse to fetch over ref: checked out' '
test_must_fail git fetch server +refs/heads/wt-3:refs/heads/wt-3 2>err &&
grep "refusing to fetch into branch '\''refs/heads/wt-3'\''" err &&
@@ -105,7 +104,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: checked out' '
grep "refusing to fetch into branch" err
'
-test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: worktree in bisect' '
+test_expect_success 'refuse to fetch over ref: worktree in bisect' '
test_when_finished git -C wt-4 bisect reset &&
# Set up a bisect so HEAD no longer points to wt-4.
@@ -117,7 +116,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: worktree in bisect
grep "refusing to fetch into branch" err
'
-test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: worktree in rebase' '
+test_expect_success 'refuse to fetch over ref: worktree in rebase' '
test_when_finished git -C wt-3 rebase --abort &&
# This will fail part-way through due to a conflict.
@@ -157,7 +156,7 @@ test_expect_success 'refuse to overwrite when in error states' '
. "$TEST_DIRECTORY"/lib-rebase.sh
-test_expect_success !SANITIZE_LEAK 'refuse to overwrite during rebase with --update-refs' '
+test_expect_success 'refuse to overwrite during rebase with --update-refs' '
git commit --fixup HEAD~2 --allow-empty &&
(
set_cat_todo_editor &&
diff --git a/t/t2408-worktree-relative.sh b/t/t2408-worktree-relative.sh
new file mode 100755
index 0000000000..d51cc8c5ab
--- /dev/null
+++ b/t/t2408-worktree-relative.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='test worktrees linked with relative paths'
+
+. ./test-lib.sh
+
+test_expect_success 'links worktrees with relative paths' '
+ test_when_finished rm -rf repo &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git worktree add wt1 &&
+ echo "../../../wt1/.git" >expected_gitdir &&
+ cat .git/worktrees/wt1/gitdir >actual_gitdir &&
+ echo "gitdir: ../.git/worktrees/wt1" >expected_git &&
+ cat wt1/.git >actual_git &&
+ test_cmp expected_gitdir actual_gitdir &&
+ test_cmp expected_git actual_git
+ )
+'
+
+test_expect_success 'move repo without breaking relative internal links' '
+ test_when_finished rm -rf repo moved &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git worktree add wt1 &&
+ cd .. &&
+ mv repo moved &&
+ cd moved/wt1 &&
+ git status >out 2>err &&
+ test_must_be_empty err
+ )
+'
+
+test_done
diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh
index 11af4552f7..13f66fd649 100755
--- a/t/t3000-ls-files-others.sh
+++ b/t/t3000-ls-files-others.sh
@@ -16,7 +16,6 @@ filesystem.
path4 - an empty directory
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup ' '
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index 1ed0aa967e..4b67646285 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -8,7 +8,6 @@ test_description='git ls-files --others --exclude
This test runs git ls-files --others and tests --exclude patterns.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
rm -fr one three
diff --git a/t/t3002-ls-files-dashpath.sh b/t/t3002-ls-files-dashpath.sh
index 4dd24550eb..31462cb441 100755
--- a/t/t3002-ls-files-dashpath.sh
+++ b/t/t3002-ls-files-dashpath.sh
@@ -13,7 +13,6 @@ filesystem.
-- - another file with a funny name.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3003-ls-files-exclude.sh b/t/t3003-ls-files-exclude.sh
index 7933dff9b3..ac3c811f46 100755
--- a/t/t3003-ls-files-exclude.sh
+++ b/t/t3003-ls-files-exclude.sh
@@ -2,7 +2,6 @@
test_description='ls-files --exclude does not affect index files'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create repo with file' '
diff --git a/t/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh
index a16e25c79b..a1078f8701 100755
--- a/t/t3004-ls-files-basic.sh
+++ b/t/t3004-ls-files-basic.sh
@@ -6,7 +6,6 @@ This test runs git ls-files with various unusual or malformed
command-line arguments.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'ls-files in empty repository' '
@@ -21,7 +20,7 @@ test_expect_success 'ls-files with nonexistent path' '
test_expect_success 'ls-files with nonsense option' '
test_expect_code 129 git ls-files --nonsense 2>actual &&
- test_i18ngrep "[Uu]sage: git ls-files" actual
+ test_grep "[Uu]sage: git ls-files" actual
'
test_expect_success 'ls-files -h in corrupt repository' '
@@ -32,7 +31,7 @@ test_expect_success 'ls-files -h in corrupt repository' '
>.git/index &&
test_expect_code 129 git ls-files -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage: git ls-files " broken/usage
+ test_grep "[Uu]sage: git ls-files " broken/usage
'
test_expect_success SYMLINKS 'ls-files with absolute paths to symlinks' '
diff --git a/t/t3005-ls-files-relative.sh b/t/t3005-ls-files-relative.sh
index fbfa210a50..db13aabf62 100755
--- a/t/t3005-ls-files-relative.sh
+++ b/t/t3005-ls-files-relative.sh
@@ -5,7 +5,6 @@ test_description='ls-files tests with relative paths
This test runs git ls-files with various relative path arguments.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'prepare' '
diff --git a/t/t3006-ls-files-long.sh b/t/t3006-ls-files-long.sh
index 2aaf91ebc8..22c7256c3a 100755
--- a/t/t3006-ls-files-long.sh
+++ b/t/t3006-ls-files-long.sh
@@ -2,7 +2,6 @@
test_description='overly long paths'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh
index 7308a3d4e2..61771eec83 100755
--- a/t/t3007-ls-files-recurse-submodules.sh
+++ b/t/t3007-ls-files-recurse-submodules.sh
@@ -296,7 +296,7 @@ test_expect_success '--recurse-submodules and relative paths' '
test_expect_success '--recurse-submodules does not support --error-unmatch' '
test_must_fail git ls-files --recurse-submodules --error-unmatch 2>actual &&
- test_i18ngrep "does not support --error-unmatch" actual
+ test_grep "does not support --error-unmatch" actual
'
test_expect_success '--recurse-submodules parses submodule repo config' '
@@ -335,7 +335,7 @@ test_expect_success '--recurse-submodules submodules ignore super project worktr
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 &&
- test_i18ngrep 'unsupported mode' actual
+ test_grep 'unsupported mode' actual
"
}
diff --git a/t/t3008-ls-files-lazy-init-name-hash.sh b/t/t3008-ls-files-lazy-init-name-hash.sh
index 51d3dffaa6..85f3704958 100755
--- a/t/t3008-ls-files-lazy-init-name-hash.sh
+++ b/t/t3008-ls-files-lazy-init-name-hash.sh
@@ -2,7 +2,6 @@
test_description='Test the lazy init name hash with various folder structures'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
if test 1 -eq $(test-tool online-cpus)
diff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh
index 14218b3424..963f3462b7 100755
--- a/t/t3009-ls-files-others-nonsubmodule.sh
+++ b/t/t3009-ls-files-others-nonsubmodule.sh
@@ -18,7 +18,6 @@ This test runs git ls-files --others with the following working tree:
git repository with a commit and an untracked file
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: directories' '
diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh
index 054178703d..7af4532cd1 100755
--- a/t/t3010-ls-files-killed-modified.sh
+++ b/t/t3010-ls-files-killed-modified.sh
@@ -42,7 +42,6 @@ We should report path0, path1, path2/file2, path3/file3, path7 and path8
modified without reporting path9 and path10. submod1 is also modified.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'git update-index --add to add various paths.' '
diff --git a/t/t3012-ls-files-dedup.sh b/t/t3012-ls-files-dedup.sh
index 190e2f6eed..2682b1f43a 100755
--- a/t/t3012-ls-files-dedup.sh
+++ b/t/t3012-ls-files-dedup.sh
@@ -2,7 +2,6 @@
test_description='git ls-files --deduplicate test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3013-ls-files-format.sh b/t/t3013-ls-files-format.sh
index 6e6ea0b6f3..8bdaacd85a 100755
--- a/t/t3013-ls-files-format.sh
+++ b/t/t3013-ls-files-format.sh
@@ -2,7 +2,6 @@
test_description='git ls-files --format test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
for flag in -s -o -k -t --resolve-undo --deduplicate --eol
diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh
index 133593d23c..ac82c9cee8 100755
--- a/t/t3020-ls-files-error-unmatch.sh
+++ b/t/t3020-ls-files-error-unmatch.sh
@@ -10,7 +10,6 @@ returns an error when a non-existent path is provided on the command
line.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh
index bd65dfcffc..768d702fbb 100755
--- a/t/t3040-subprojects-basic.sh
+++ b/t/t3040-subprojects-basic.sh
@@ -2,7 +2,6 @@
test_description='Basic subproject functionality'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: create superproject' '
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 3884694165..f1f09abdd9 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -2,7 +2,6 @@
test_description='fetching and pushing project with subproject'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 5a06732ca7..eb69da61fe 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -9,7 +9,6 @@ This test runs git ls-files --with-tree and in particular in
a scenario known to trigger a crash with some versions of git.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 4dd42df38c..3da824117c 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -2,7 +2,6 @@
test_description='wildmatch tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
should_create_test_file() {
diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh
index 436de44971..8f294d9832 100755
--- a/t/t3100-ls-tree-restrict.sh
+++ b/t/t3100-ls-tree-restrict.sh
@@ -17,7 +17,6 @@ The new path restriction code should do the right thing for path2 and
path2/baz. Also path0/ should snow nothing.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success \
diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh
index 5af2dac0e4..ac44525810 100755
--- a/t/t3101-ls-tree-dirname.sh
+++ b/t/t3101-ls-tree-dirname.sh
@@ -20,7 +20,6 @@ Test the handling of multiple directories which have matching file
entries. Also test odd filename and missing entries handling.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh
index 3942db2290..1e16c6b8ea 100755
--- a/t/t3102-ls-tree-wildcards.sh
+++ b/t/t3102-ls-tree-wildcards.sh
@@ -2,7 +2,6 @@
test_description='ls-tree with(out) globs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3103-ls-tree-misc.sh b/t/t3103-ls-tree-misc.sh
index 81c6343962..e7636f6908 100755
--- a/t/t3103-ls-tree-misc.sh
+++ b/t/t3103-ls-tree-misc.sh
@@ -7,7 +7,6 @@ Miscellaneous tests for git ls-tree.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh
index 3adb206a93..a1b2069a25 100755
--- a/t/t3104-ls-tree-format.sh
+++ b/t/t3104-ls-tree-format.sh
@@ -2,7 +2,6 @@
test_description='ls-tree --format'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-t3100.sh
diff --git a/t/t3105-ls-tree-output.sh b/t/t3105-ls-tree-output.sh
index ce2391e28b..8bdf400682 100755
--- a/t/t3105-ls-tree-output.sh
+++ b/t/t3105-ls-tree-output.sh
@@ -2,7 +2,6 @@
test_description='ls-tree output'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-t3100.sh
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index daf1666df7..2295db3dcb 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -8,7 +8,6 @@ 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
@@ -25,10 +24,10 @@ test_expect_success 'prepare a trivial repository' '
test_expect_success 'git branch --help should not have created a bogus branch' '
test_might_fail git branch --man --help </dev/null >/dev/null 2>&1 &&
- test_path_is_missing .git/refs/heads/--help
+ test_ref_missing refs/heads/--help
'
-test_expect_success 'branch -h in broken repository' '
+test_expect_success REFFILES 'branch -h in broken repository' '
mkdir broken &&
(
cd broken &&
@@ -36,11 +35,12 @@ test_expect_success 'branch -h in broken repository' '
>.git/refs/heads/main &&
test_expect_code 129 git branch -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage" broken/usage
+ test_grep "[Uu]sage" broken/usage
'
test_expect_success 'git branch abc should create a branch' '
- git branch abc && test_path_is_file .git/refs/heads/abc
+ git branch abc &&
+ test_ref_exists refs/heads/abc
'
test_expect_success 'git branch abc should fail when abc exists' '
@@ -61,31 +61,33 @@ test_expect_success 'git branch --force abc should succeed when abc exists' '
'
test_expect_success 'git branch a/b/c should create a branch' '
- git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c
+ git branch a/b/c &&
+ test_ref_exists refs/heads/a/b/c
'
test_expect_success 'git branch mb main... should create a branch' '
- git branch mb main... && test_path_is_file .git/refs/heads/mb
+ git branch mb main... &&
+ test_ref_exists refs/heads/mb
'
test_expect_success 'git branch HEAD should fail' '
test_must_fail git branch HEAD
'
-cat >expect <<EOF
-$ZERO_OID $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from main
-EOF
test_expect_success 'git branch --create-reflog d/e/f should create a branch and a log' '
GIT_COMMITTER_DATE="2005-05-26 23:30" \
git -c core.logallrefupdates=false branch --create-reflog d/e/f &&
- test_path_is_file .git/refs/heads/d/e/f &&
- test_path_is_file .git/logs/refs/heads/d/e/f &&
- test_cmp expect .git/logs/refs/heads/d/e/f
+ test_ref_exists refs/heads/d/e/f &&
+ cat >expect <<-EOF &&
+ $HEAD refs/heads/d/e/f@{0}: branch: Created from main
+ EOF
+ git reflog show --no-abbrev-commit refs/heads/d/e/f >actual &&
+ test_cmp expect actual
'
test_expect_success 'git branch -d d/e/f should delete a branch and a log' '
git branch -d d/e/f &&
- test_path_is_missing .git/refs/heads/d/e/f &&
+ test_ref_missing refs/heads/d/e/f &&
test_must_fail git reflog exists refs/heads/d/e/f
'
@@ -103,7 +105,7 @@ test_expect_success 'git branch l should work after branch l/m has been deleted'
test_expect_success 'git branch -m dumps usage' '
test_expect_code 128 git branch -m 2>err &&
- test_i18ngrep "branch name required" err
+ test_grep "branch name required" err
'
test_expect_success 'git branch -m m broken_symref should work' '
@@ -200,10 +202,9 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
test $(git rev-parse --abbrev-ref HEAD) = bam
'
-test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' '
- msg="Branch: renamed refs/heads/baz to refs/heads/bam" &&
- grep " $ZERO_OID.*$msg$" .git/logs/HEAD &&
- grep "^$ZERO_OID.*$msg$" .git/logs/HEAD
+test_expect_success 'git branch -M baz bam should add entries to HEAD reflog' '
+ git reflog show HEAD >actual &&
+ grep "HEAD@{0}: Branch: renamed refs/heads/baz to refs/heads/bam" actual
'
test_expect_success 'git branch -M should leave orphaned HEAD alone' '
@@ -212,17 +213,20 @@ test_expect_success 'git branch -M should leave orphaned HEAD alone' '
cd orphan &&
test_commit initial &&
git checkout --orphan lonely &&
- grep lonely .git/HEAD &&
- test_path_is_missing .git/refs/head/lonely &&
+ git symbolic-ref HEAD >expect &&
+ echo refs/heads/lonely >actual &&
+ test_cmp expect actual &&
+ test_ref_missing refs/head/lonely &&
git branch -M main mistress &&
- grep lonely .git/HEAD
+ git symbolic-ref HEAD >expect &&
+ test_cmp expect actual
)
'
test_expect_success 'resulting reflog can be shown by log -g' '
oid=$(git rev-parse HEAD) &&
cat >expect <<-EOF &&
- HEAD@{0} $oid $msg
+ HEAD@{0} $oid Branch: renamed refs/heads/baz to refs/heads/bam
HEAD@{2} $oid checkout: moving from foo to baz
EOF
git log -g --format="%gd %H %gs" -2 HEAD >actual &&
@@ -240,7 +244,7 @@ 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' '
+test_expect_success REFFILES '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 &&
@@ -291,10 +295,10 @@ test_expect_success 'git branch -M topic topic should work when main is checked
test_expect_success 'git branch -M and -C fail on detached HEAD' '
git checkout HEAD^{} &&
test_when_finished git checkout - &&
- echo "fatal: cannot rename the current branch while not on any." >expect &&
+ echo "fatal: cannot rename the current branch while not on any" >expect &&
test_must_fail git branch -M must-fail 2>err &&
test_cmp expect err &&
- echo "fatal: cannot copy the current branch while not on any." >expect &&
+ echo "fatal: cannot copy the current branch while not on any" >expect &&
test_must_fail git branch -C must-fail 2>err &&
test_cmp expect err
'
@@ -435,10 +439,10 @@ test_expect_success 'git branch --list -v with --abbrev' '
test_expect_success 'git branch --column' '
COLUMNS=81 git branch --column=column >actual &&
- cat >expect <<\EOF &&
- a/b/c bam foo l * main n o/p r
- abc bar j/k m/m mb o/o q topic
-EOF
+ cat >expect <<-\EOF &&
+ a/b/c bam foo l * main n o/p r
+ abc bar j/k m/m mb o/o q topic
+ EOF
test_cmp expect actual
'
@@ -448,25 +452,25 @@ test_expect_success 'git branch --column with an extremely long branch name' '
test_when_finished "git branch -d $long" &&
git branch $long &&
COLUMNS=80 git branch --column=column >actual &&
- cat >expect <<EOF &&
- a/b/c
- abc
- bam
- bar
- foo
- j/k
- l
- m/m
-* main
- mb
- n
- o/o
- o/p
- q
- r
- topic
- $long
-EOF
+ cat >expect <<-EOF &&
+ a/b/c
+ abc
+ bam
+ bar
+ foo
+ j/k
+ l
+ m/m
+ * main
+ mb
+ n
+ o/o
+ o/p
+ q
+ r
+ topic
+ $long
+ EOF
test_cmp expect actual
'
@@ -476,10 +480,10 @@ test_expect_success 'git branch with column.*' '
COLUMNS=80 git branch >actual &&
git config --unset column.branch &&
git config --unset column.ui &&
- cat >expect <<\EOF &&
- a/b/c bam foo l * main n o/p r
- abc bar j/k m/m mb o/o q topic
-EOF
+ cat >expect <<-\EOF &&
+ a/b/c bam foo l * main n o/p r
+ abc bar j/k m/m mb o/o q topic
+ EOF
test_cmp expect actual
'
@@ -491,39 +495,36 @@ test_expect_success 'git branch -v with column.ui ignored' '
git config column.ui column &&
COLUMNS=80 git branch -v | cut -c -8 | sed "s/ *$//" >actual &&
git config --unset column.ui &&
- cat >expect <<\EOF &&
- a/b/c
- abc
- bam
- bar
- foo
- j/k
- l
- m/m
-* main
- mb
- n
- o/o
- o/p
- q
- r
- topic
-EOF
+ cat >expect <<-\EOF &&
+ a/b/c
+ abc
+ bam
+ bar
+ foo
+ j/k
+ l
+ m/m
+ * main
+ mb
+ n
+ o/o
+ o/p
+ q
+ r
+ topic
+ EOF
test_cmp expect actual
'
-mv .git/config .git/config-saved
-
-test_expect_success SHA1 'git branch -m q q2 without config should succeed' '
+test_expect_success DEFAULT_REPO_FORMAT 'git branch -m q q2 without config should succeed' '
+ test_when_finished mv .git/config-saved .git/config &&
+ mv .git/config .git/config-saved &&
git branch -m q q2 &&
git branch -m q2 q
'
-mv .git/config-saved .git/config
-
-git config branch.s/s.dummy Hello
-
test_expect_success 'git branch -m s/s s should work when s/t is deleted' '
+ git config branch.s/s.dummy Hello &&
git branch --create-reflog s/s &&
git reflog exists refs/heads/s/s &&
git branch --create-reflog s/t &&
@@ -574,19 +575,19 @@ EOF
# ...and that the comments for those sections are also
# preserved.
- cat config.branch | sed "s/\"source\"/\"dest\"/" >expect &&
+ sed "s/\"source\"/\"dest\"/" config.branch >expect &&
sed -n -e "/Note the lack/,\$p" .git/config >actual &&
test_cmp expect actual
'
test_expect_success 'git branch -c dumps usage' '
test_expect_code 128 git branch -c 2>err &&
- test_i18ngrep "branch name required" err
+ test_grep "branch name required" err
'
test_expect_success 'git branch --copy dumps usage' '
test_expect_code 128 git branch --copy 2>err &&
- test_i18ngrep "branch name required" err
+ test_grep "branch name required" err
'
test_expect_success 'git branch -c d e should work' '
@@ -696,7 +697,8 @@ test_expect_success 'git branch -C c1 c2 should succeed when c1 is checked out'
test_expect_success 'git branch -C c1 c2 should never touch HEAD' '
msg="Branch: copied refs/heads/c1 to refs/heads/c2" &&
- ! grep "$msg$" .git/logs/HEAD
+ git reflog HEAD >actual &&
+ ! grep "$msg$" actual
'
test_expect_success 'git branch -C main should work when main is checked out' '
@@ -799,26 +801,26 @@ test_expect_success 'deleting a symref' '
git symbolic-ref refs/heads/symref refs/heads/target &&
echo "Deleted branch symref (was refs/heads/target)." >expect &&
git branch -d symref >actual &&
- test_path_is_file .git/refs/heads/target &&
- test_path_is_missing .git/refs/heads/symref &&
+ test_ref_exists refs/heads/target &&
+ test_ref_missing refs/heads/symref &&
test_cmp expect actual
'
test_expect_success 'deleting a dangling symref' '
git symbolic-ref refs/heads/dangling-symref nowhere &&
- test_path_is_file .git/refs/heads/dangling-symref &&
+ git symbolic-ref --no-recurse refs/heads/dangling-symref &&
echo "Deleted branch dangling-symref (was nowhere)." >expect &&
git branch -d dangling-symref >actual &&
- test_path_is_missing .git/refs/heads/dangling-symref &&
+ test_ref_missing refs/heads/dangling-symref &&
test_cmp expect actual
'
test_expect_success 'deleting a self-referential symref' '
git symbolic-ref refs/heads/self-reference refs/heads/self-reference &&
- test_path_is_file .git/refs/heads/self-reference &&
+ test_ref_exists refs/heads/self-reference &&
echo "Deleted branch self-reference (was refs/heads/self-reference)." >expect &&
git branch -d self-reference >actual &&
- test_path_is_missing .git/refs/heads/self-reference &&
+ test_ref_missing refs/heads/self-reference &&
test_cmp expect actual
'
@@ -826,37 +828,8 @@ test_expect_success 'renaming a symref is not allowed' '
git symbolic-ref refs/heads/topic refs/heads/main &&
test_must_fail git branch -m topic new-topic &&
git symbolic-ref refs/heads/topic &&
- test_path_is_file .git/refs/heads/main &&
- test_path_is_missing .git/refs/heads/new-topic
-'
-
-test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for u is a symlink' '
- git branch --create-reflog u &&
- mv .git/logs/refs/heads/u real-u &&
- ln -s real-u .git/logs/refs/heads/u &&
- test_must_fail git branch -m u v
-'
-
-test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' '
- test_when_finished "rm -rf subdir" &&
- git init --bare subdir &&
-
- rm -rfv subdir/refs subdir/objects subdir/packed-refs &&
- ln -s ../.git/refs subdir/refs &&
- ln -s ../.git/objects subdir/objects &&
- ln -s ../.git/packed-refs subdir/packed-refs &&
-
- git -C subdir rev-parse --absolute-git-dir >subdir.dir &&
- git rev-parse --absolute-git-dir >our.dir &&
- ! test_cmp subdir.dir our.dir &&
-
- git -C subdir log &&
- git -C subdir branch rename-src &&
- git rev-parse rename-src >expect &&
- git -C subdir branch -m rename-src rename-dest &&
- git rev-parse rename-dest >actual &&
- test_cmp expect actual &&
- git branch -D rename-dest
+ test_ref_exists refs/heads/main &&
+ test_ref_missing refs/heads/new-topic
'
test_expect_success 'test tracking setup via --track' '
@@ -942,7 +915,19 @@ test_expect_success 'test deleting branch without config' '
test_expect_success 'deleting currently checked out branch fails' '
git worktree add -b my7 my7 &&
test_must_fail git -C my7 branch -d my7 &&
- test_must_fail git branch -d my7 &&
+ test_must_fail git branch -d my7 2>actual &&
+ grep "^error: cannot delete branch .my7. used by worktree at " actual &&
+ rm -r my7 &&
+ git worktree prune
+'
+
+test_expect_success 'deleting in-use branch fails' '
+ git worktree add my7 &&
+ test_commit -C my7 bt7 &&
+ git -C my7 bisect start HEAD HEAD~2 &&
+ test_must_fail git -C my7 branch -d my7 &&
+ test_must_fail git branch -d my7 2>actual &&
+ grep "^error: cannot delete branch .my7. used by worktree at " actual &&
rm -r my7 &&
git worktree prune
'
@@ -1012,7 +997,7 @@ test_expect_success '--set-upstream-to fails on multiple branches' '
test_expect_success '--set-upstream-to fails on detached HEAD' '
git checkout HEAD^{} &&
test_when_finished git checkout - &&
- echo "fatal: could not set upstream of HEAD to main when it does not point to any branch." >expect &&
+ echo "fatal: could not set upstream of HEAD to main when it does not point to any branch" >expect &&
test_must_fail git branch --set-upstream-to main 2>err &&
test_cmp expect err
'
@@ -1025,7 +1010,7 @@ test_expect_success '--set-upstream-to fails on a missing dst branch' '
test_expect_success '--set-upstream-to fails on a missing src branch' '
test_must_fail git branch --set-upstream-to does-not-exist main 2>err &&
- test_i18ngrep "the requested upstream branch '"'"'does-not-exist'"'"' does not exist" err
+ test_grep "the requested upstream branch '"'"'does-not-exist'"'"' does not exist" err
'
test_expect_success '--set-upstream-to fails on a non-ref' '
@@ -1039,7 +1024,7 @@ test_expect_success '--set-upstream-to fails on locked config' '
>.git/config.lock &&
git branch locked &&
test_must_fail git branch --set-upstream-to locked 2>err &&
- test_i18ngrep "could not lock config file .git/config" err
+ test_grep "could not lock config file .git/config" err
'
test_expect_success 'use --set-upstream-to modify HEAD' '
@@ -1060,7 +1045,7 @@ test_expect_success 'use --set-upstream-to modify a particular branch' '
'
test_expect_success '--unset-upstream should fail if given a non-existent branch' '
- echo "fatal: Branch '"'"'i-dont-exist'"'"' has no upstream information" >expect &&
+ echo "fatal: branch '"'"'i-dont-exist'"'"' has no upstream information" >expect &&
test_must_fail git branch --unset-upstream i-dont-exist 2>err &&
test_cmp expect err
'
@@ -1070,7 +1055,7 @@ test_expect_success '--unset-upstream should fail if config is locked' '
git branch --set-upstream-to locked &&
>.git/config.lock &&
test_must_fail git branch --unset-upstream 2>err &&
- test_i18ngrep "could not lock config file .git/config" err
+ test_grep "could not lock config file .git/config" err
'
test_expect_success 'test --unset-upstream on HEAD' '
@@ -1082,7 +1067,7 @@ test_expect_success 'test --unset-upstream on HEAD' '
test_must_fail git config branch.main.remote &&
test_must_fail git config branch.main.merge &&
# fail for a branch without upstream set
- echo "fatal: Branch '"'"'main'"'"' has no upstream information" >expect &&
+ echo "fatal: branch '"'"'main'"'"' has no upstream information" >expect &&
test_must_fail git branch --unset-upstream 2>err &&
test_cmp expect err
'
@@ -1096,7 +1081,7 @@ test_expect_success '--unset-upstream should fail on multiple branches' '
test_expect_success '--unset-upstream should fail on detached HEAD' '
git checkout HEAD^{} &&
test_when_finished git checkout - &&
- echo "fatal: could not unset upstream of HEAD when it does not point to any branch." >expect &&
+ echo "fatal: could not unset upstream of HEAD when it does not point to any branch" >expect &&
test_must_fail git branch --unset-upstream 2>err &&
test_cmp expect err
'
@@ -1123,16 +1108,16 @@ test_expect_success '--set-upstream-to notices an error to set branch as own ups
test_cmp expect actual
"
-# Keep this test last, as it changes the current branch
-cat >expect <<EOF
-$ZERO_OID $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from main
-EOF
test_expect_success 'git checkout -b g/h/i -l should create a branch and a log' '
+ test_when_finished git checkout main &&
GIT_COMMITTER_DATE="2005-05-26 23:30" \
git checkout -b g/h/i -l main &&
- test_path_is_file .git/refs/heads/g/h/i &&
- test_path_is_file .git/logs/refs/heads/g/h/i &&
- test_cmp expect .git/logs/refs/heads/g/h/i
+ test_ref_exists refs/heads/g/h/i &&
+ cat >expect <<-EOF &&
+ $HEAD refs/heads/g/h/i@{0}: branch: Created from main
+ EOF
+ git reflog show --no-abbrev-commit refs/heads/g/h/i >actual &&
+ test_cmp expect actual
'
test_expect_success 'checkout -b makes reflog by default' '
@@ -1168,9 +1153,9 @@ test_expect_success 'avoid ambiguous track and advise' '
hint: tracking ref '\''refs/heads/main'\'':
hint: ambi1
hint: ambi2
- hint: ''
+ hint:
hint: This is typically a configuration error.
- hint: ''
+ hint:
hint: To support setting up tracking branches, ensure that
hint: different remotes'\'' fetch refspecs map into different
hint: tracking namespaces.
@@ -1506,7 +1491,7 @@ test_expect_success '--list during rebase' '
set_fake_editor &&
git rebase -i HEAD~2 &&
git branch --list >actual &&
- test_i18ngrep "rebasing main" actual
+ test_grep "rebasing main" actual
'
test_expect_success '--list during rebase from detached HEAD' '
@@ -1518,7 +1503,7 @@ test_expect_success '--list during rebase from detached HEAD' '
set_fake_editor &&
git rebase -i HEAD~2 &&
git branch --list >actual &&
- test_i18ngrep "rebasing detached HEAD $oid" actual
+ test_grep "rebasing detached HEAD $oid" actual
'
test_expect_success 'tracking with unexpected .fetch refspec' '
@@ -1558,9 +1543,10 @@ test_expect_success 'tracking with unexpected .fetch refspec' '
test_expect_success 'configured committerdate sort' '
git init -b main sort &&
+ test_config -C sort branch.sort "committerdate" &&
+
(
cd sort &&
- git config branch.sort committerdate &&
test_commit initial &&
git checkout -b a &&
test_commit a &&
@@ -1580,9 +1566,10 @@ test_expect_success 'configured committerdate sort' '
'
test_expect_success 'option override configured sort' '
+ test_config -C sort branch.sort "committerdate" &&
+
(
cd sort &&
- git config branch.sort committerdate &&
git branch --sort=refname >actual &&
cat >expect <<-\EOF &&
a
@@ -1594,10 +1581,70 @@ test_expect_success 'option override configured sort' '
)
'
+test_expect_success '--no-sort cancels config sort keys' '
+ test_config -C sort branch.sort "-refname" &&
+
+ (
+ cd sort &&
+
+ # objecttype is identical for all of them, so sort falls back on
+ # default (ascending refname)
+ git branch \
+ --no-sort \
+ --sort="objecttype" >actual &&
+ cat >expect <<-\EOF &&
+ a
+ * b
+ c
+ main
+ EOF
+ test_cmp expect actual
+ )
+
+'
+
+test_expect_success '--no-sort cancels command line sort keys' '
+ (
+ cd sort &&
+
+ # objecttype is identical for all of them, so sort falls back on
+ # default (ascending refname)
+ git branch \
+ --sort="-refname" \
+ --no-sort \
+ --sort="objecttype" >actual &&
+ cat >expect <<-\EOF &&
+ a
+ * b
+ c
+ main
+ EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--no-sort without subsequent --sort prints expected branches' '
+ (
+ cd sort &&
+
+ # Sort the results with `sort` for a consistent comparison
+ # against expected
+ git branch --no-sort | sort >actual &&
+ cat >expect <<-\EOF &&
+ a
+ c
+ main
+ * b
+ EOF
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'invalid sort parameter in configuration' '
+ test_config -C sort branch.sort "v:notvalid" &&
+
(
cd sort &&
- git config branch.sort "v:notvalid" &&
# this works in the "listing" mode, so bad sort key
# is a dying offence.
@@ -1645,4 +1692,14 @@ test_expect_success '--track overrides branch.autoSetupMerge' '
test_cmp_config "" --default "" branch.foo5.merge
'
+test_expect_success 'errors if given a bad branch name' '
+ cat <<-\EOF >expect &&
+ fatal: '\''foo..bar'\'' is not a valid branch name
+ hint: See `man git check-ref-format`
+ hint: Disable this message with "git config advice.refSyntax false"
+ EOF
+ test_must_fail git branch foo..bar >actual 2>&1 &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
index b17f388f56..a1139f79e2 100755
--- a/t/t3202-show-branch.sh
+++ b/t/t3202-show-branch.sh
@@ -4,13 +4,10 @@ test_description='test show-branch'
. ./test-lib.sh
-# arbitrary reference time: 2009-08-30 19:20:00
-GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW
-
test_expect_success 'error descriptions on empty repository' '
current=$(git branch --show-current) &&
cat >expect <<-EOF &&
- error: No commit on branch '\''$current'\'' yet.
+ error: no commit on branch '\''$current'\'' yet
EOF
test_must_fail git branch --edit-description 2>actual &&
test_cmp expect actual &&
@@ -21,7 +18,7 @@ test_expect_success 'error descriptions on empty repository' '
test_expect_success 'fatal descriptions on empty repository' '
current=$(git branch --show-current) &&
cat >expect <<-EOF &&
- fatal: No commit on branch '\''$current'\'' yet.
+ fatal: no commit on branch '\''$current'\'' yet
EOF
test_must_fail git branch --set-upstream-to=non-existent 2>actual &&
test_cmp expect actual &&
@@ -187,18 +184,6 @@ test_expect_success 'show branch --merge-base with N arguments' '
test_cmp expect actual
'
-test_expect_success 'show branch --reflog=2' '
- sed "s/^> //" >expect <<-\EOF &&
- > ! [refs/heads/branch10@{0}] (4 years, 5 months ago) commit: branch10
- > ! [refs/heads/branch10@{1}] (4 years, 5 months ago) commit: branch10
- > --
- > + [refs/heads/branch10@{0}] branch10
- > ++ [refs/heads/branch10@{1}] initial
- EOF
- git show-branch --reflog=2 >actual &&
- test_cmp actual expect
-'
-
# incompatible options
while read combo
do
@@ -224,7 +209,7 @@ done
test_expect_success 'error descriptions on non-existent branch' '
cat >expect <<-EOF &&
- error: No branch named '\''non-existent'\'.'
+ error: no branch named '\''non-existent'\''
EOF
test_must_fail git branch --edit-description non-existent 2>actual &&
test_cmp expect actual
@@ -238,7 +223,7 @@ test_expect_success 'fatal descriptions on non-existent branch' '
test_cmp expect actual &&
cat >expect <<-EOF &&
- fatal: No branch named '\''non-existent'\''.
+ fatal: no branch named '\''non-existent'\''
EOF
test_must_fail git branch -c non-existent new-branch 2>actual &&
test_cmp expect actual &&
@@ -253,7 +238,7 @@ test_expect_success 'error descriptions on orphan branch' '
test_branch_op_in_wt() {
test_orphan_error() {
test_must_fail git $* 2>actual &&
- test_i18ngrep "No commit on branch .orphan-branch. yet.$" actual
+ test_grep "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
@@ -264,4 +249,38 @@ test_expect_success 'error descriptions on orphan branch' '
test_branch_op_in_wt -c new-branch
'
+test_expect_success 'setup reflogs' '
+ test_commit base &&
+ git checkout -b branch &&
+ test_commit one &&
+ git reset --hard HEAD^ &&
+ test_commit two &&
+ test_commit three
+'
+
+test_expect_success '--reflog shows reflog entries' '
+ cat >expect <<-\EOF &&
+ ! [branch@{0}] (0 seconds ago) commit: three
+ ! [branch@{1}] (60 seconds ago) commit: two
+ ! [branch@{2}] (2 minutes ago) reset: moving to HEAD^
+ ! [branch@{3}] (2 minutes ago) commit: one
+ ----
+ + [branch@{0}] three
+ ++ [branch@{1}] two
+ + [branch@{3}] one
+ ++++ [branch@{2}] base
+ EOF
+ # the output always contains relative timestamps; use
+ # a known time to get deterministic results
+ GIT_TEST_DATE_NOW=$test_tick \
+ git show-branch --reflog branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--reflog handles missing reflog' '
+ git reflog expire --expire=now branch &&
+ git show-branch --reflog branch >actual &&
+ test_must_be_empty actual
+'
+
test_done
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 758963b189..500c9d0e72 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git branch display tests'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
diff --git a/t/t3204-branch-name-interpretation.sh b/t/t3204-branch-name-interpretation.sh
index 594e3e43e1..3399344f25 100755
--- a/t/t3204-branch-name-interpretation.sh
+++ b/t/t3204-branch-name-interpretation.sh
@@ -9,7 +9,6 @@ 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() {
diff --git a/t/t3205-branch-color.sh b/t/t3205-branch-color.sh
index 0b61da92b3..da1c202fa7 100755
--- a/t/t3205-branch-color.sh
+++ b/t/t3205-branch-color.sh
@@ -1,7 +1,6 @@
#!/bin/sh
test_description='basic branch output coloring'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up some sample branches' '
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index b5f4d6a653..d2ca43d6aa 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -195,7 +195,7 @@ test_expect_success 'A^! and A^-<n> (unmodified)' '
test_expect_success 'A^{/..} is not mistaken for a range' '
test_must_fail git range-diff topic^.. topic^{/..} -- 2>error &&
- test_i18ngrep "not a commit range" error
+ test_grep "not a commit range" error
'
test_expect_success 'trivial reordering' '
@@ -533,11 +533,11 @@ test_expect_success 'dual-coloring' '
for prev in topic main..topic
do
test_expect_success "format-patch --range-diff=$prev" '
+ test_when_finished "rm -f 000?-*" &&
git format-patch --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
- test_i18ngrep "^Range-diff:$" 0000-* &&
+ test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
grep "= 2: .* s/4/A" 0000-* &&
grep "= 3: .* s/11/B" 0000-* &&
@@ -545,35 +545,49 @@ do
'
done
+test_expect_success "--range-diff implies --cover-letter for multi-patch series" '
+ test_when_finished "rm -f v2-000?-*" &&
+ git format-patch -v2 --range-diff=topic main..unmodified &&
+ test_grep "^Range-diff against v1:$" v2-0000-cover-letter.patch
+'
+
+test_expect_success "explicit --no-cover-letter defeats implied --cover-letter" '
+ test_when_finished "rm -f v2-000?-*" &&
+ test_must_fail git format-patch --no-cover-letter \
+ -v2 --range-diff=topic main..unmodified &&
+ test_must_fail git -c format.coverLetter=no format-patch \
+ -v2 --range-diff=topic main..unmodified
+'
+
test_expect_success 'format-patch --range-diff as commentary' '
+ test_when_finished "rm -f 0001-*" &&
git format-patch --range-diff=HEAD~1 HEAD~1 >actual &&
- test_when_finished "rm 0001-*" &&
test_line_count = 1 actual &&
- test_i18ngrep "^Range-diff:$" 0001-* &&
+ test_grep "^Range-diff:$" 0001-* &&
grep "> 1: .* new message" 0001-*
'
test_expect_success 'format-patch --range-diff reroll-count with a non-integer' '
+ test_when_finished "rm -f v2.9-0001-*" &&
git format-patch --range-diff=HEAD~1 -v2.9 HEAD~1 >actual &&
- test_when_finished "rm v2.9-0001-*" &&
test_line_count = 1 actual &&
- test_i18ngrep "^Range-diff:$" v2.9-0001-* &&
+ test_grep "^Range-diff:$" v2.9-0001-* &&
grep "> 1: .* new message" v2.9-0001-*
'
test_expect_success 'format-patch --range-diff reroll-count with a integer' '
+ test_when_finished "rm -f v2-0001-*" &&
git format-patch --range-diff=HEAD~1 -v2 HEAD~1 >actual &&
- test_when_finished "rm v2-0001-*" &&
test_line_count = 1 actual &&
- test_i18ngrep "^Range-diff ..* v1:$" v2-0001-* &&
+ test_grep "^Range-diff ..* v1:$" v2-0001-* &&
grep "> 1: .* new message" v2-0001-*
'
test_expect_success 'format-patch --range-diff with v0' '
+ test_when_finished "rm -f v0-0001-*" &&
git format-patch --range-diff=HEAD~1 -v0 HEAD~1 >actual &&
- test_when_finished "rm v0-0001-*" &&
test_line_count = 1 actual &&
- test_i18ngrep "^Range-diff:$" v0-0001-* &&
+ test_grep "^Range-diff:$" v0-0001-* &&
grep "> 1: .* new message" v0-0001-*
'
@@ -592,9 +606,9 @@ test_expect_success 'basic with modified format.pretty without "commit "' '
'
test_expect_success 'range-diff compares notes by default' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
git range-diff --no-color main..topic main..unmodified \
>actual &&
sed s/Z/\ /g >expect <<-EOF &&
@@ -616,9 +630,9 @@ test_expect_success 'range-diff compares notes by default' '
'
test_expect_success 'range-diff with --no-notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
git range-diff --no-color --no-notes main..topic main..unmodified \
>actual &&
cat >expect <<-EOF &&
@@ -631,12 +645,12 @@ test_expect_success 'range-diff with --no-notes' '
'
test_expect_success 'range-diff with multiple --notes' '
+ test_when_finished "git notes --ref=note1 remove topic unmodified || :" &&
git notes --ref=note1 add -m "topic note1" topic &&
git notes --ref=note1 add -m "unmodified note1" unmodified &&
- test_when_finished git notes --ref=note1 remove topic unmodified &&
+ test_when_finished "git notes --ref=note2 remove topic unmodified || :" &&
git notes --ref=note2 add -m "topic note2" topic &&
git notes --ref=note2 add -m "unmodified note2" unmodified &&
- test_when_finished git notes --ref=note2 remove topic unmodified &&
git range-diff --no-color --notes=note1 --notes=note2 main..topic main..unmodified \
>actual &&
sed s/Z/\ /g >expect <<-EOF &&
@@ -662,15 +676,29 @@ test_expect_success 'range-diff with multiple --notes' '
test_cmp expect actual
'
+# `range-diff` should act like `log` with regards to notes
+test_expect_success 'range-diff with --notes=custom does not show default notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
+ git notes add -m "topic note" topic &&
+ git notes add -m "unmodified note" unmodified &&
+ test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
+ git notes --ref=custom add -m "topic note" topic &&
+ git notes --ref=custom add -m "unmodified note" unmodified &&
+ git range-diff --notes=custom main..topic main..unmodified \
+ >actual &&
+ ! grep "## Notes ##" actual &&
+ grep "## Notes (custom) ##" actual
+'
+
test_expect_success 'format-patch --range-diff does not compare notes by default' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
- test_i18ngrep "^Range-diff:$" 0000-* &&
+ test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
grep "= 2: .* s/4/A" 0000-* &&
grep "= 3: .* s/11/B" 0000-* &&
@@ -679,15 +707,29 @@ test_expect_success 'format-patch --range-diff does not compare notes by default
! grep "note" 0000-*
'
+test_expect_success 'format-patch --notes=custom --range-diff only compares custom notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
+ git notes add -m "topic note" topic &&
+ git notes add -m "unmodified note" unmodified &&
+ test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
+ git notes --ref=custom add -m "topic note (custom)" topic &&
+ git notes --ref=custom add -m "unmodified note (custom)" unmodified &&
+ test_when_finished "rm -f 000?-*" &&
+ git format-patch --notes=custom --cover-letter --range-diff=$prev \
+ main..unmodified >actual &&
+ grep "## Notes (custom) ##" 0000-* &&
+ ! grep "## Notes ##" 0000-*
+'
+
test_expect_success 'format-patch --range-diff with --no-notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --no-notes --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
- test_i18ngrep "^Range-diff:$" 0000-* &&
+ test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
grep "= 2: .* s/4/A" 0000-* &&
grep "= 3: .* s/11/B" 0000-* &&
@@ -697,14 +739,14 @@ test_expect_success 'format-patch --range-diff with --no-notes' '
'
test_expect_success 'format-patch --range-diff with --notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --notes --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
- test_i18ngrep "^Range-diff:$" 0000-* &&
+ test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
grep "= 2: .* s/4/A" 0000-* &&
grep "= 3: .* s/11/B" 0000-* &&
@@ -725,15 +767,15 @@ test_expect_success 'format-patch --range-diff with --notes' '
'
test_expect_success 'format-patch --range-diff with format.notes config' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
test_config format.notes true &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
- test_i18ngrep "^Range-diff:$" 0000-* &&
+ test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
grep "= 2: .* s/4/A" 0000-* &&
grep "= 3: .* s/11/B" 0000-* &&
@@ -754,17 +796,17 @@ test_expect_success 'format-patch --range-diff with format.notes config' '
'
test_expect_success 'format-patch --range-diff with multiple notes' '
+ test_when_finished "git notes --ref=note1 remove topic unmodified || :" &&
git notes --ref=note1 add -m "topic note1" topic &&
git notes --ref=note1 add -m "unmodified note1" unmodified &&
- test_when_finished git notes --ref=note1 remove topic unmodified &&
+ test_when_finished "git notes --ref=note2 remove topic unmodified || :" &&
git notes --ref=note2 add -m "topic note2" topic &&
git notes --ref=note2 add -m "unmodified note2" unmodified &&
- test_when_finished git notes --ref=note2 remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --notes=note1 --notes=note2 --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
- test_i18ngrep "^Range-diff:$" 0000-* &&
+ test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
grep "= 2: .* s/4/A" 0000-* &&
grep "= 3: .* s/11/B" 0000-* &&
diff --git a/t/t3211-peel-ref.sh b/t/t3211-peel-ref.sh
index 9cbc34fc58..37b9d26f4b 100755
--- a/t/t3211-peel-ref.sh
+++ b/t/t3211-peel-ref.sh
@@ -4,7 +4,6 @@ test_description='tests for the peel_ref optimization of packed-refs'
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 'create annotated tag in refs/tags' '
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index d3ac826283..f5bf16abcd 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -9,7 +9,6 @@ This test tries pathnames with funny characters in the working
tree, index, and tree objects.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
HT=' '
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index d734000d2f..d6c50460d0 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -1469,9 +1469,9 @@ test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' '
test_expect_success 'git notes copy diagnoses too many or too few arguments' '
test_must_fail git notes copy 2>error &&
- test_i18ngrep "too few arguments" error &&
+ test_grep "too few arguments" error &&
test_must_fail git notes copy one two three 2>error &&
- test_i18ngrep "too many arguments" error
+ test_grep "too many arguments" error
'
test_expect_success 'git notes get-ref expands refs/heads/main to refs/notes/refs/heads/main' '
@@ -1556,4 +1556,77 @@ test_expect_success 'empty notes are displayed by git log' '
test_cmp expect actual
'
+test_expect_success 'empty notes do not invoke the editor' '
+ test_commit 18th &&
+ GIT_EDITOR="false" git notes add -C "$empty_blob" --allow-empty &&
+ git notes remove HEAD &&
+ GIT_EDITOR="false" git notes add -m "" --allow-empty &&
+ git notes remove HEAD &&
+ GIT_EDITOR="false" git notes add -F /dev/null --allow-empty &&
+ git notes remove HEAD
+'
+
+test_expect_success 'git notes add with -m/-F invokes editor with -e' '
+ test_commit 19th &&
+ echo "edited" >expect &&
+ MSG="$(cat expect)" git notes add -m "initial" -e &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove HEAD &&
+
+ # Add a note using -F and edit it
+ echo "initial" >note_file &&
+ MSG="$(cat expect)" git notes add -F note_file -e &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git notes append with -m/-F invokes the editor with -e' '
+ test_commit 20th &&
+ cat >expect <<-EOF &&
+ initial
+
+ edited
+ EOF
+ git notes add -m "initial" &&
+ MSG="edited" git notes append -m "appended" -e &&
+
+ # Verify the note content was appended and edited
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove HEAD &&
+
+ # Append a note using -F and edit it
+ echo "note from file" >note_file &&
+ git notes add -m "initial" &&
+ MSG="edited" git notes append -F note_file -e &&
+
+ # Verify notes from file has been edited in editor and appended
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git notes with a combination of -m, -F and -e invokes editor' '
+ test_commit 21st &&
+ echo "foo-file-1" >note_1 &&
+ echo "foo-file-2" >note_2 &&
+ echo "edited" >expect &&
+
+ MSG=$(cat expect) git notes append -F note_1 -m "message-1" -F note_2 -e &&
+
+ # Verify that combined messages from file and -m have been edited
+ git notes show >actual &&
+ test_cmp expect actual
+'
+test_expect_success 'git notes append aborts when editor fails with -e' '
+ test_commit 22nd &&
+ echo "foo-file-1" >note_1 &&
+
+ # Try to append a note with -F and -e, but make the editor fail
+ test_env GIT_EDITOR="false" test_must_fail git notes append -F note_1 -e &&
+
+ # Verify that no note was added due to editor failure
+ test_must_fail git notes show
+'
+
test_done
diff --git a/t/t3302-notes-index-expensive.sh b/t/t3302-notes-index-expensive.sh
index d0c4d38b4d..bb5fea02a0 100755
--- a/t/t3302-notes-index-expensive.sh
+++ b/t/t3302-notes-index-expensive.sh
@@ -8,7 +8,6 @@ test_description='Test commit notes index (expensive!)'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
create_repo () {
diff --git a/t/t3303-notes-subtrees.sh b/t/t3303-notes-subtrees.sh
index bc9b791d1b..eac193757b 100755
--- a/t/t3303-notes-subtrees.sh
+++ b/t/t3303-notes-subtrees.sh
@@ -5,7 +5,6 @@ test_description='Test commit notes organized in subtrees'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
number_of_commits=100
diff --git a/t/t3304-notes-mixed.sh b/t/t3304-notes-mixed.sh
index 2c3a245266..03dfcd3954 100755
--- a/t/t3304-notes-mixed.sh
+++ b/t/t3304-notes-mixed.sh
@@ -5,7 +5,6 @@ test_description='Test notes trees that also contain non-notes'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
number_of_commits=100
diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh
index 1ec1fb6715..fcecdc94ff 100755
--- a/t/t3305-notes-fanout.sh
+++ b/t/t3305-notes-fanout.sh
@@ -2,7 +2,6 @@
test_description='Test that adding/removing many notes triggers automatic fanout restructuring'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
path_has_fanout() {
diff --git a/t/t3307-notes-man.sh b/t/t3307-notes-man.sh
index ae316502c4..1aa366a410 100755
--- a/t/t3307-notes-man.sh
+++ b/t/t3307-notes-man.sh
@@ -4,7 +4,6 @@ test_description='Examples from the git-notes man page
Make sure the manual is not full of lies.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index d3d72e25fe..597df5ebc0 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -216,7 +216,7 @@ test_expect_success 'merge z into m (== y) with default ("manual") resolver => C
git config core.notesRef refs/notes/m &&
test_must_fail git notes merge z >output 2>&1 &&
# Output should point to where to resolve conflicts
- test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
+ test_grep "\\.git/NOTES_MERGE_WORKTREE" output &&
# Inspect merge conflicts
ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
test_cmp expect_conflicts output_conflicts &&
@@ -263,7 +263,7 @@ test_expect_success 'cannot do merge w/conflicts when previous merge is unfinish
test -d .git/NOTES_MERGE_WORKTREE &&
test_must_fail git notes merge z >output 2>&1 &&
# Output should indicate what is wrong
- test_i18ngrep -q "\\.git/NOTES_MERGE_\\* exists" output
+ test_grep -q "\\.git/NOTES_MERGE_\\* exists" output
'
# Setup non-conflicting merge between x and new notes ref w
@@ -417,7 +417,7 @@ test_expect_success 'redo merge of z into m (== y) with default ("manual") resol
git config core.notesRef refs/notes/m &&
test_must_fail git notes merge z >output 2>&1 &&
# Output should point to where to resolve conflicts
- test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
+ test_grep "\\.git/NOTES_MERGE_WORKTREE" output &&
# Inspect merge conflicts
ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
test_cmp expect_conflicts output_conflicts &&
@@ -449,7 +449,7 @@ git rev-parse refs/notes/z > pre_merge_z
test_expect_success 'redo merge of z into m (== y) with default ("manual") resolver => Conflicting 3-way merge' '
test_must_fail git notes merge z >output 2>&1 &&
# Output should point to where to resolve conflicts
- test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
+ test_grep "\\.git/NOTES_MERGE_WORKTREE" output &&
# Inspect merge conflicts
ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
test_cmp expect_conflicts output_conflicts &&
@@ -528,7 +528,7 @@ test_expect_success 'redo merge of z into m (== y) with default ("manual") resol
git update-ref refs/notes/m refs/notes/y &&
test_must_fail git notes merge z >output 2>&1 &&
# Output should point to where to resolve conflicts
- test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
+ test_grep "\\.git/NOTES_MERGE_WORKTREE" output &&
# Inspect merge conflicts
ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
test_cmp expect_conflicts output_conflicts &&
@@ -561,9 +561,9 @@ y and z notes on 4th commit
EOF
# Fail to finalize merge
test_must_fail git notes merge --commit >output 2>&1 &&
- # .git/NOTES_MERGE_* must remain
- test -f .git/NOTES_MERGE_PARTIAL &&
- test -f .git/NOTES_MERGE_REF &&
+ # NOTES_MERGE_* refs and .git/NOTES_MERGE_* state files must remain
+ git rev-parse --verify NOTES_MERGE_PARTIAL &&
+ git rev-parse --verify NOTES_MERGE_REF &&
test -f .git/NOTES_MERGE_WORKTREE/$commit_sha1 &&
test -f .git/NOTES_MERGE_WORKTREE/$commit_sha2 &&
test -f .git/NOTES_MERGE_WORKTREE/$commit_sha3 &&
@@ -573,9 +573,9 @@ EOF
test "$(git rev-parse refs/notes/y)" = "$(git rev-parse NOTES_MERGE_PARTIAL^1)" &&
test "$(git rev-parse refs/notes/m)" != "$(git rev-parse NOTES_MERGE_PARTIAL^1)" &&
# Mention refs/notes/m, and its current and expected value in output
- test_i18ngrep -q "refs/notes/m" output &&
- test_i18ngrep -q "$(git rev-parse refs/notes/m)" output &&
- test_i18ngrep -q "$(git rev-parse NOTES_MERGE_PARTIAL^1)" output &&
+ test_grep -q "refs/notes/m" output &&
+ test_grep -q "$(git rev-parse refs/notes/m)" output &&
+ test_grep -q "$(git rev-parse NOTES_MERGE_PARTIAL^1)" output &&
# Verify that other notes refs has not changed (w, x, y and z)
verify_notes w &&
verify_notes x &&
diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh
index bff0aea550..96243b7222 100755
--- a/t/t3320-notes-merge-worktrees.sh
+++ b/t/t3320-notes-merge-worktrees.sh
@@ -8,7 +8,6 @@ test_description='Test merging of notes trees in multiple worktrees'
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 commit' '
@@ -57,7 +56,7 @@ test_expect_success 'merge z into y while mid-merge in another workdir fails' '
cd worktree &&
git config core.notesRef refs/notes/y &&
test_must_fail git notes merge z 2>err &&
- test_i18ngrep "a notes merge into refs/notes/y is already in-progress at" err
+ test_grep "a notes merge into refs/notes/y is already in-progress at" err
) &&
test_must_fail git -C worktree symbolic-ref NOTES_MERGE_REF
'
@@ -67,7 +66,7 @@ test_expect_success 'merge z into x while mid-merge on y succeeds' '
cd worktree2 &&
git config core.notesRef refs/notes/x &&
test_must_fail git notes merge z >out 2>&1 &&
- test_i18ngrep "Automatic notes merge failed" out &&
+ test_grep "Automatic notes merge failed" out &&
grep -v "A notes merge into refs/notes/x is already in-progress in" out
) &&
echo "refs/notes/x" >expect &&
diff --git a/t/t3321-notes-stripspace.sh b/t/t3321-notes-stripspace.sh
index 36abdca5ee..c4a7839540 100755
--- a/t/t3321-notes-stripspace.sh
+++ b/t/t3321-notes-stripspace.sh
@@ -5,7 +5,6 @@
test_description='Test commit notes with stripspace behavior'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
MULTI_LF="$LF$LF$LF"
@@ -429,7 +428,7 @@ test_expect_success 'add notes with empty messages' '
git notes add -m "${LF}" \
-m "${MULTI_LF}" \
-m "${LF}" >actual 2>&1 &&
- test_i18ngrep "Removing note for object" actual
+ test_grep "Removing note for object" actual
'
test_expect_success 'add note by specifying "-C", "--no-stripspace" is the default behavior' '
@@ -442,7 +441,7 @@ test_expect_success 'add note by specifying "-C", "--no-stripspace" is the defau
${LF}
EOF
- cat expect | git hash-object -w --stdin >blob &&
+ git hash-object -w --stdin <expect >blob &&
git notes add -C $(cat blob) &&
git notes show >actual &&
test_cmp expect actual &&
@@ -468,7 +467,7 @@ test_expect_success 'reuse note by specifying "-C" and "--stripspace"' '
second-line
EOF
- cat data | git hash-object -w --stdin >blob &&
+ git hash-object -w --stdin <data >blob &&
git notes add --stripspace -C $(cat blob) &&
git notes show >actual &&
test_cmp expect actual
@@ -492,7 +491,7 @@ test_expect_success 'reuse with "-C" and add note with "-m", "-m" will stripspac
third-line
EOF
- cat data | git hash-object -w --stdin >blob &&
+ git hash-object -w --stdin <data >blob &&
git notes add -C $(cat blob) -m "third-line" &&
git notes show >actual &&
test_cmp expect actual
@@ -511,7 +510,7 @@ test_expect_success 'add note with "-m" and reuse note with "-C", "-C" will not
second-line
EOF
- cat data | git hash-object -w --stdin >blob &&
+ git hash-object -w --stdin <data >blob &&
git notes add -m "first-line" -C $(cat blob) &&
git notes show >actual &&
test_cmp expect actual
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 3ce918fdb8..bab675938a 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -143,8 +143,10 @@ test_expect_success 'Show verbose error when HEAD could not be detached' '
>B &&
test_when_finished "rm -f B" &&
test_must_fail git rebase topic 2>output.err >output.out &&
- test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" output.err &&
- test_i18ngrep B output.err
+ test_grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
+ test_grep B output.err &&
+ test_must_fail git rebase --quit 2>err &&
+ test_grep "no rebase in progress" err
'
test_expect_success 'fail when upstream arg is missing and not on branch' '
@@ -234,6 +236,12 @@ test_expect_success 'rebase --merge -q is quiet' '
test_must_be_empty output.out
'
+test_expect_success 'rebase --exec -q is quiet' '
+ git checkout -B quiet topic &&
+ git rebase --exec true -q main >output.out 2>&1 &&
+ test_must_be_empty output.out
+'
+
test_expect_success 'Rebase a commit that sprinkles CRs in' '
(
echo "One" &&
@@ -421,17 +429,9 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' '
git checkout main &&
git worktree add wt &&
test_must_fail git -C wt rebase main main 2>err &&
- test_i18ngrep "already checked out" err
-'
-
-test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' '
- git checkout main &&
- mv .git/logs actual_logs &&
- cmd //c "mklink /D .git\logs ..\actual_logs" &&
- git rebase -f HEAD^ &&
- test -L .git/logs &&
- rm .git/logs &&
- mv actual_logs .git/logs
+ test_grep "already used by worktree at" err &&
+ test_must_fail git -C wt rebase --quit 2>err &&
+ test_grep "no rebase in progress" err
'
test_expect_success 'rebase when inside worktree subdirectory' '
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index e9e03ca4b5..761de63b6b 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -8,7 +8,6 @@ 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
@@ -171,7 +170,7 @@ test_expect_success '--reapply-cherry-picks' '
# Regular rebase fails, because the 1-11 commit is deduplicated
test_must_fail git -C repo rebase --merge main 2> err &&
- test_i18ngrep "error: could not apply.*add 12 in another branch" err &&
+ test_grep "error: could not apply.*add 12 in another branch" err &&
git -C repo rebase --abort &&
# With --reapply-cherry-picks, it works
diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh
index f6e4864497..a1911c4a9d 100755
--- a/t/t3403-rebase-skip.sh
+++ b/t/t3403-rebase-skip.sh
@@ -108,10 +108,10 @@ test_expect_success 'correct advice upon picking empty commit' '
test_when_finished "git rebase --abort" &&
test_must_fail git rebase -i --onto goodbye \
amended-goodbye^ amended-goodbye 2>err &&
- test_i18ngrep "previous cherry-pick is now empty" err &&
- test_i18ngrep "git rebase --skip" err &&
+ test_grep "previous cherry-pick is now empty" err &&
+ test_grep "git rebase --skip" err &&
test_must_fail git commit &&
- test_i18ngrep "git rebase --skip" err
+ test_grep "git rebase --skip" err
'
test_expect_success 'correct authorship when committing empty pick' '
@@ -131,10 +131,10 @@ test_expect_success 'correct advice upon rewording empty commit' '
test_must_fail env FAKE_LINES="reword 1" git rebase -i \
--onto goodbye amended-goodbye^ amended-goodbye 2>err
) &&
- test_i18ngrep "previous cherry-pick is now empty" err &&
- test_i18ngrep "git rebase --skip" err &&
+ test_grep "previous cherry-pick is now empty" err &&
+ test_grep "git rebase --skip" err &&
test_must_fail git commit &&
- test_i18ngrep "git rebase --skip" err
+ test_grep "git rebase --skip" err
'
test_expect_success 'correct advice upon editing empty commit' '
@@ -144,10 +144,10 @@ test_expect_success 'correct advice upon editing empty commit' '
test_must_fail env FAKE_LINES="edit 1" git rebase -i \
--onto goodbye amended-goodbye^ amended-goodbye 2>err
) &&
- test_i18ngrep "previous cherry-pick is now empty" err &&
- test_i18ngrep "git rebase --skip" err &&
+ test_grep "previous cherry-pick is now empty" err &&
+ test_grep "git rebase --skip" err &&
test_must_fail git commit &&
- test_i18ngrep "git rebase --skip" err
+ test_grep "git rebase --skip" err
'
test_expect_success 'correct advice upon cherry-picking an empty commit during a rebase' '
@@ -157,10 +157,10 @@ test_expect_success 'correct advice upon cherry-picking an empty commit during a
test_must_fail env FAKE_LINES="1 exec_git_cherry-pick_amended-goodbye" \
git rebase -i goodbye^ goodbye 2>err
) &&
- test_i18ngrep "previous cherry-pick is now empty" err &&
- test_i18ngrep "git cherry-pick --skip" err &&
+ test_grep "previous cherry-pick is now empty" err &&
+ test_grep "git cherry-pick --skip" err &&
test_must_fail git commit 2>err &&
- test_i18ngrep "git cherry-pick --skip" err
+ test_grep "git cherry-pick --skip" err
'
test_expect_success 'correct advice upon multi cherry-pick picking an empty commit during a rebase' '
@@ -170,10 +170,10 @@ test_expect_success 'correct advice upon multi cherry-pick picking an empty comm
test_must_fail env FAKE_LINES="1 exec_git_cherry-pick_goodbye_amended-goodbye" \
git rebase -i goodbye^^ goodbye 2>err
) &&
- test_i18ngrep "previous cherry-pick is now empty" err &&
- test_i18ngrep "git cherry-pick --skip" err &&
+ test_grep "previous cherry-pick is now empty" err &&
+ test_grep "git cherry-pick --skip" err &&
test_must_fail git commit 2>err &&
- test_i18ngrep "git cherry-pick --skip" err
+ test_grep "git cherry-pick --skip" err
'
test_expect_success 'fixup that empties commit fails' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8ea2bf1302..b11f04eb33 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -153,6 +153,18 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git rebase --continue
'
+test_expect_success 'cherry-pick works with rebase --exec' '
+ test_when_finished "git cherry-pick --abort; \
+ git rebase --abort; \
+ git checkout primary" &&
+ echo "exec git cherry-pick G" >todo &&
+ (
+ set_replace_editor todo &&
+ test_must_fail git rebase -i D D
+ ) &&
+ test_cmp_rev G CHERRY_PICK_HEAD
+'
+
test_expect_success 'rebase -x with empty command fails' '
test_when_finished "git rebase --abort ||:" &&
test_must_fail env git rebase -x "" @ 2>actual &&
@@ -268,8 +280,9 @@ test_expect_success 'stop on conflicting pick' '
test_cmp expect2 file1 &&
test "$(git diff --name-status |
sed -n -e "/^U/s/^U[^a-z]*//p")" = file1 &&
- test 4 = $(grep -v "^#" < .git/rebase-merge/done | wc -l) &&
- test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo)
+ grep -v "^#" <.git/rebase-merge/done >actual &&
+ test_line_count = 4 actual &&
+ test 0 = $(grep -c "^[^#]" <.git/rebase-merge/git-rebase-todo)
'
test_expect_success 'show conflicted patch' '
@@ -291,9 +304,9 @@ test_expect_success 'abort with error when new base cannot be checked out' '
git rm --cached file1 &&
git commit -m "remove file in base" &&
test_must_fail git rebase -i primary > output 2>&1 &&
- test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" \
+ test_grep "The following untracked working tree files would be overwritten by checkout:" \
output &&
- test_i18ngrep "file1" output &&
+ test_grep "file1" output &&
test_path_is_missing .git/rebase-merge &&
rm file1 &&
git reset --hard HEAD^
@@ -306,7 +319,8 @@ test_expect_success 'retain authorship' '
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
git tag twerp &&
git rebase -i --onto primary HEAD^ &&
- git show HEAD | grep "^Author: Twerp Snog"
+ git show HEAD >actual &&
+ grep "^Author: Twerp Snog" actual
'
test_expect_success 'retain authorship w/ conflicts' '
@@ -347,7 +361,8 @@ test_expect_success 'squash' '
'
test_expect_success 'retain authorship when squashing' '
- git show HEAD | grep "^Author: Twerp Snog"
+ git show HEAD >actual &&
+ grep "^Author: Twerp Snog" actual
'
test_expect_success '--continue tries to commit' '
@@ -361,7 +376,8 @@ test_expect_success '--continue tries to commit' '
FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue
) &&
test_cmp_rev HEAD^ new-branch1 &&
- git show HEAD | grep chouette
+ git show HEAD >actual &&
+ grep chouette actual
'
test_expect_success 'verbose flag is heeded, even after --continue' '
@@ -384,7 +400,9 @@ test_expect_success 'multi-squash only fires up editor once' '
git rebase -i $base
) &&
test $base = $(git rev-parse HEAD^) &&
- test 1 = $(git show | grep ONCE | wc -l)
+ git show >output &&
+ grep ONCE output >actual &&
+ test_line_count = 1 actual
'
test_expect_success 'multi-fixup does not fire up editor' '
@@ -397,7 +415,8 @@ test_expect_success 'multi-fixup does not fire up editor' '
git rebase -i $base
) &&
test $base = $(git rev-parse HEAD^) &&
- test 0 = $(git show | grep NEVER | wc -l) &&
+ git show >output &&
+ ! grep NEVER output &&
git checkout @{-1} &&
git branch -D multi-fixup
'
@@ -415,7 +434,9 @@ test_expect_success 'commit message used after conflict' '
git rebase --continue
) &&
test $base = $(git rev-parse HEAD^) &&
- test 1 = $(git show | grep ONCE | wc -l) &&
+ git show >output &&
+ grep ONCE output >actual &&
+ test_line_count = 1 actual &&
git checkout @{-1} &&
git branch -D conflict-fixup
'
@@ -433,7 +454,9 @@ test_expect_success 'commit message retained after conflict' '
git rebase --continue
) &&
test $base = $(git rev-parse HEAD^) &&
- test 2 = $(git show | grep TWICE | wc -l) &&
+ git show >output &&
+ grep TWICE output >actual &&
+ test_line_count = 2 actual &&
git checkout @{-1} &&
git branch -D conflict-squash
'
@@ -457,10 +480,10 @@ test_expect_success 'squash and fixup generate correct log messages' '
) &&
git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
test_cmp expect-squash-fixup actual-squash-fixup &&
- git cat-file commit HEAD@{2} |
- grep "^# This is a combination of 3 commits\." &&
- git cat-file commit HEAD@{3} |
- grep "^# This is a combination of 2 commits\." &&
+ git cat-file commit HEAD@{2} >actual &&
+ grep "^# This is a combination of 3 commits\." actual &&
+ git cat-file commit HEAD@{3} >actual &&
+ grep "^# This is a combination of 2 commits\." actual &&
git checkout @{-1} &&
git branch -D squash-fixup
'
@@ -476,7 +499,9 @@ test_expect_success 'squash ignores comments' '
git rebase -i $base
) &&
test $base = $(git rev-parse HEAD^) &&
- test 1 = $(git show | grep ONCE | wc -l) &&
+ git show >output &&
+ grep ONCE output >actual &&
+ test_line_count = 1 actual &&
git checkout @{-1} &&
git branch -D skip-comments
'
@@ -492,7 +517,9 @@ test_expect_success 'squash ignores blank lines' '
git rebase -i $base
) &&
test $base = $(git rev-parse HEAD^) &&
- test 1 = $(git show | grep ONCE | wc -l) &&
+ git show >output &&
+ grep ONCE output >actual &&
+ test_line_count = 1 actual &&
git checkout @{-1} &&
git branch -D skip-blank-lines
'
@@ -559,7 +586,8 @@ test_expect_success '--continue tries to commit, even for "edit"' '
FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue
) &&
test edited = $(git show HEAD:file7) &&
- git show HEAD | grep chouette &&
+ git show HEAD >actual &&
+ grep chouette actual &&
test $parent = $(git rev-parse HEAD^)
'
@@ -604,8 +632,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 ! "could not open.*for reading" error
+ test_grep "you have staged changes in your working tree" error &&
+ test_grep ! "could not open.*for reading" error
'
test_expect_success 'rebase a detached HEAD' '
@@ -744,19 +772,23 @@ test_expect_success 'reword' '
set_fake_editor &&
FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" \
git rebase -i A &&
- git show HEAD | grep "E changed" &&
+ git show HEAD >actual &&
+ grep "E changed" actual &&
test $(git rev-parse primary) != $(git rev-parse HEAD) &&
test_cmp_rev primary^ HEAD^ &&
FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" \
git rebase -i A &&
- git show HEAD^ | grep "D changed" &&
+ git show HEAD^ >actual &&
+ grep "D changed" actual &&
FAKE_LINES="reword 1 2 3 4" FAKE_COMMIT_MESSAGE="B changed" \
git rebase -i A &&
- git show HEAD~3 | grep "B changed" &&
+ git show HEAD~3 >actual &&
+ grep "B changed" actual &&
FAKE_LINES="1 r 2 pick 3 p 4" FAKE_COMMIT_MESSAGE="C changed" \
git rebase -i A
) &&
- git show HEAD~2 | grep "C changed"
+ git show HEAD~2 >actual &&
+ grep "C changed" actual
'
test_expect_success 'no uncommitted changes when rewording and the todo list is reloaded' '
@@ -956,7 +988,7 @@ test_expect_success 'rebase --exec works without -i ' '
git reset --hard execute &&
rm -rf exec_output &&
EDITOR="echo >invoked_editor" git rebase --exec "echo a line >>exec_output" HEAD~2 2>actual &&
- test_i18ngrep "Successfully rebased and updated" actual &&
+ test_grep "Successfully rebased and updated" actual &&
test_line_count = 2 exec_output &&
test_path_is_missing invoked_editor
'
@@ -964,7 +996,7 @@ test_expect_success 'rebase --exec works without -i ' '
test_expect_success 'rebase -i --exec without <CMD>' '
git reset --hard execute &&
test_must_fail git rebase -i --exec 2>actual &&
- test_i18ngrep "requires a value" actual &&
+ test_grep "requires a value" actual &&
git checkout primary
'
@@ -990,8 +1022,10 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
set_fake_editor &&
FAKE_LINES="2" git rebase -i --root
) &&
- git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
- git cat-file commit HEAD | grep -q "^different author$"
+ git cat-file commit HEAD >output &&
+ grep -q "^author Twerp Snog" output &&
+ git cat-file commit HEAD >actual &&
+ grep -q "^different author$" actual
'
test_expect_success 'rebase -i --root temporary sentinel commit' '
@@ -1000,7 +1034,8 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
set_fake_editor &&
test_must_fail env FAKE_LINES="2" git rebase -i --root
) &&
- git cat-file commit HEAD | grep "^tree $EMPTY_TREE" &&
+ git cat-file commit HEAD >actual &&
+ grep "^tree $EMPTY_TREE" actual &&
git rebase --abort
'
@@ -1023,7 +1058,8 @@ test_expect_success 'rebase -i --root reword original root commit' '
FAKE_LINES="reword 1 2" FAKE_COMMIT_MESSAGE="A changed" \
git rebase -i --root
) &&
- git show HEAD^ | grep "A changed" &&
+ git show HEAD^ >actual &&
+ grep "A changed" actual &&
test -z "$(git show -s --format=%p HEAD^)"
'
@@ -1035,7 +1071,8 @@ test_expect_success 'rebase -i --root reword new root commit' '
FAKE_LINES="reword 3 1" FAKE_COMMIT_MESSAGE="C changed" \
git rebase -i --root
) &&
- git show HEAD^ | grep "C changed" &&
+ git show HEAD^ >actual &&
+ grep "C changed" actual &&
test -z "$(git show -s --format=%p HEAD^)"
'
@@ -1273,7 +1310,7 @@ test_expect_success 'todo count' '
test_set_editor "$(pwd)/dump-raw.sh" &&
git rebase -i HEAD~4 >actual
) &&
- test_i18ngrep "^# Rebase ..* onto ..* ([0-9]" actual
+ test_grep "^# Rebase ..* onto ..* ([0-9]" actual
'
test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
@@ -1408,7 +1445,7 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' '
FAKE_LINES="1 2 3 4" git rebase -i --root 2>actual
) &&
test D = $(git cat-file commit HEAD | sed -ne \$p) &&
- test_i18ngrep \
+ test_grep \
"Successfully rebased and updated refs/heads/missing-commit" \
actual
'
@@ -1471,7 +1508,7 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = ig
git rebase --continue 2>actual
) &&
test D = $(git cat-file commit HEAD | sed -ne \$p) &&
- test_i18ngrep \
+ test_grep \
"Successfully rebased and updated refs/heads/missing-commit" \
actual
'
@@ -1506,7 +1543,7 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa
git rebase --continue 2>actual
) &&
test D = $(git cat-file commit HEAD | sed -ne \$p) &&
- test_i18ngrep \
+ test_grep \
"Successfully rebased and updated refs/heads/missing-commit" \
actual
'
@@ -1554,7 +1591,7 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = er
git rebase --continue 2>actual
) &&
test D = $(git cat-file commit HEAD | sed -ne \$p) &&
- test_i18ngrep \
+ test_grep \
"Successfully rebased and updated refs/heads/missing-commit" \
actual
'
@@ -1614,9 +1651,9 @@ test_expect_success 'static check of bad command' '
set_fake_editor &&
test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
git rebase -i --root 2>actual &&
- test_i18ngrep "pickled $(git rev-list --oneline -1 primary~1)" \
+ test_grep "pickled $(git rev-list --oneline -1 primary~1)" \
actual &&
- test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
+ test_grep "You can fix this with .git rebase --edit-todo.." \
actual &&
FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo
) &&
@@ -1674,8 +1711,8 @@ test_expect_success 'static check of bad SHA-1' '
set_fake_editor &&
test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \
git rebase -i --root 2>actual &&
- test_i18ngrep "edit XXXXXXX False commit" actual &&
- test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
+ test_grep "edit XXXXXXX False commit" actual &&
+ test_grep "You can fix this with .git rebase --edit-todo.." \
actual &&
FAKE_LINES="1 2 4 5 6" git rebase --edit-todo
) &&
@@ -1702,7 +1739,7 @@ test_expect_success 'rebase -i --gpg-sign=<key-id>' '
FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" \
HEAD^ >out 2>err
) &&
- test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
+ test_grep "$SQ-S\"S I Gner\"$SQ" err
'
test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
@@ -1713,7 +1750,7 @@ test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" \
HEAD^ >out 2>err
) &&
- test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
+ test_grep "$SQ-S\"S I Gner\"$SQ" err
'
test_expect_success 'valid author header after --root swap' '
@@ -1767,7 +1804,7 @@ test_expect_success 'correct error message for partial commit after empty pick'
) &&
echo x >file1 &&
test_must_fail git commit file1 2>err &&
- test_i18ngrep "cannot do a partial commit during a rebase." err
+ test_grep "cannot do a partial commit during a rebase." err
'
test_expect_success 'correct error message for commit --amend after empty pick' '
@@ -1780,13 +1817,13 @@ test_expect_success 'correct error message for commit --amend after empty pick'
) &&
echo x>file1 &&
test_must_fail git commit -a --amend 2>err &&
- test_i18ngrep "middle of a rebase -- cannot amend." err
+ test_grep "middle of a rebase -- cannot amend." err
'
test_expect_success 'todo has correct onto hash' '
GIT_SEQUENCE_EDITOR=cat git rebase -i no-conflict-branch~4 no-conflict-branch >actual &&
onto=$(git rev-parse --short HEAD~4) &&
- test_i18ngrep "^# Rebase ..* onto $onto" actual
+ test_grep "^# Rebase ..* onto $onto" actual
'
test_expect_success 'ORIG_HEAD is updated correctly' '
@@ -1857,7 +1894,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
pick $(git log -1 --format=%h branch2~1) F
pick $(git log -1 --format=%h branch2) I
update-ref refs/heads/branch2
- label merge
+ label branch2
reset onto
pick $(git log -1 --format=%h refs/heads/second) J
update-ref refs/heads/second
@@ -1868,7 +1905,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
update-ref refs/heads/third
pick $(git log -1 --format=%h HEAD~2) M
update-ref refs/heads/no-conflict-branch
- merge -C $(git log -1 --format=%h HEAD~1) merge # merge
+ merge -C $(git log -1 --format=%h HEAD~1) branch2 # merge
update-ref refs/heads/merge-branch
EOF
@@ -1904,18 +1941,17 @@ test_expect_success '--update-refs updates refs correctly' '
test_cmp_rev HEAD~1 refs/heads/third &&
test_cmp_rev HEAD refs/heads/no-conflict-branch &&
- cat >expect <<-\EOF &&
+ q_to_tab >expect <<-\EOF &&
Successfully rebased and updated refs/heads/update-refs.
Updated the following refs with --update-refs:
- refs/heads/first
- refs/heads/no-conflict-branch
- refs/heads/second
- refs/heads/third
+ Qrefs/heads/first
+ Qrefs/heads/no-conflict-branch
+ Qrefs/heads/second
+ Qrefs/heads/third
EOF
# Clear "Rebasing (X/Y)" progress lines and drop leading tabs.
- sed -e "s/Rebasing.*Successfully/Successfully/g" -e "s/^\t//g" \
- <err >err.trimmed &&
+ sed "s/Rebasing.*Successfully/Successfully/g" <err >err.trimmed &&
test_cmp expect err.trimmed
'
@@ -2160,24 +2196,23 @@ test_expect_success '--update-refs: check failed ref update' '
# recorded in the update-refs file. We will force-update the
# "second" ref, but "git branch -f" will not work because of
# the lock in the update-refs file.
- git rev-parse third >.git/refs/heads/second &&
+ git update-ref refs/heads/second third &&
test_must_fail git rebase --continue 2>err &&
grep "update_ref failed for ref '\''refs/heads/second'\''" err &&
- cat >expect <<-\EOF &&
+ q_to_tab >expect <<-\EOF &&
Updated the following refs with --update-refs:
- refs/heads/first
- refs/heads/no-conflict-branch
- refs/heads/third
+ Qrefs/heads/first
+ Qrefs/heads/no-conflict-branch
+ Qrefs/heads/third
Failed to update the following refs with --update-refs:
- refs/heads/second
+ Qrefs/heads/second
EOF
# Clear "Rebasing (X/Y)" progress lines and drop leading tabs.
tail -n 6 err >err.last &&
- sed -e "s/Rebasing.*Successfully/Successfully/g" -e "s/^\t//g" \
- <err.last >err.trimmed &&
+ sed "s/Rebasing.*Successfully/Successfully/g" <err.last >err.trimmed &&
test_cmp expect err.trimmed
'
@@ -2203,6 +2238,51 @@ test_expect_success 'bad labels and refs rejected when parsing todo list' '
test_path_is_missing execed
'
+test_expect_success 'non-merge commands reject merge commits' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ git checkout E &&
+ git merge I &&
+ oid=$(git rev-parse HEAD) &&
+ cat >todo <<-EOF &&
+ pick $oid
+ reword $oid
+ edit $oid
+ fixup $oid
+ squash $oid
+ EOF
+ (
+ set_replace_editor todo &&
+ test_must_fail git rebase -i HEAD 2>actual
+ ) &&
+ cat >expect <<-EOF &&
+ error: ${SQ}pick${SQ} does not accept merge commits
+ hint: ${SQ}pick${SQ} does not take a merge commit. If you wanted to
+ hint: replay the merge, use ${SQ}merge -C${SQ} on the commit.
+ hint: Disable this message with "git config advice.rebaseTodoError false"
+ error: invalid line 1: pick $oid
+ error: ${SQ}reword${SQ} does not accept merge commits
+ hint: ${SQ}reword${SQ} does not take a merge commit. If you wanted to
+ hint: replay the merge and reword the commit message, use
+ hint: ${SQ}merge -c${SQ} on the commit
+ hint: Disable this message with "git config advice.rebaseTodoError false"
+ error: invalid line 2: reword $oid
+ error: ${SQ}edit${SQ} does not accept merge commits
+ hint: ${SQ}edit${SQ} does not take a merge commit. If you wanted to
+ hint: replay the merge, use ${SQ}merge -C${SQ} on the commit, and then
+ hint: ${SQ}break${SQ} to give the control back to you so that you can
+ hint: do ${SQ}git commit --amend && git rebase --continue${SQ}.
+ hint: Disable this message with "git config advice.rebaseTodoError false"
+ error: invalid line 3: edit $oid
+ error: cannot squash merge commit into another commit
+ error: invalid line 4: fixup $oid
+ error: cannot squash merge commit into another commit
+ error: invalid line 5: squash $oid
+ You can fix this with ${SQ}git rebase --edit-todo${SQ} and then run ${SQ}git rebase --continue${SQ}.
+ Or you can abort the rebase with ${SQ}git rebase --abort${SQ}.
+ EOF
+ test_cmp expect actual
+'
+
# This must be the last test in this file
test_expect_success '$EDITOR and friends are unchanged' '
test_editor_unchanged
diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh
index 8979bc3407..2524331861 100755
--- a/t/t3405-rebase-malformed.sh
+++ b/t/t3405-rebase-malformed.sh
@@ -5,7 +5,6 @@ test_description='rebase should handle arbitrary git message'
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
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index ceca160005..a1d7fa7f7c 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -33,24 +33,24 @@ test_expect_success 'rebase -m' '
test_expect_success 'rebase against main twice' '
git rebase --apply main >out &&
- test_i18ngrep "Current branch topic is up to date" out
+ test_grep "Current branch topic is up to date" out
'
test_expect_success 'rebase against main twice with --force' '
git rebase --force-rebase --apply main >out &&
- test_i18ngrep "Current branch topic is up to date, rebase forced" out
+ test_grep "Current branch topic is up to date, rebase forced" out
'
test_expect_success 'rebase against main twice from another branch' '
git checkout topic^ &&
git rebase --apply main topic >out &&
- test_i18ngrep "Current branch topic is up to date" out
+ test_grep "Current branch topic is up to date" out
'
test_expect_success 'rebase fast-forward to main' '
git checkout topic^ &&
git rebase --apply topic >out &&
- test_i18ngrep "Fast-forwarded HEAD to topic" out
+ test_grep "Fast-forwarded HEAD to topic" out
'
test_expect_success 'rebase --stat' '
@@ -75,14 +75,14 @@ test_expect_success 'rebase -n overrides config rebase.stat config' '
test_expect_success 'rebase --onto outputs the invalid ref' '
test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err &&
- test_i18ngrep "invalid-ref" err
+ test_grep "invalid-ref" err
'
test_expect_success 'error out early upon -C<n> or --whitespace=<bad>' '
test_must_fail git rebase -Cnot-a-number HEAD 2>err &&
- test_i18ngrep "numerical value" err &&
+ test_grep "numerical value" err &&
test_must_fail git rebase --whitespace=bad HEAD 2>err &&
- test_i18ngrep "Invalid whitespace option" err
+ test_grep "Invalid whitespace option" err
'
write_reflog_expect () {
@@ -251,8 +251,8 @@ test_expect_success 'rebase -i onto unrelated history' '
git -C unrelated remote add -f origin "$PWD" &&
git -C unrelated branch --set-upstream-to=origin/main &&
git -C unrelated -c core.editor=true rebase -i -v --stat >actual &&
- test_i18ngrep "Changes to " actual &&
- test_i18ngrep "5 files changed" actual
+ test_grep "Changes to " actual &&
+ test_grep "5 files changed" actual
'
test_done
diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh
index ebbaed147a..9f49c4228b 100755
--- a/t/t3407-rebase-abort.sh
+++ b/t/t3407-rebase-abort.sh
@@ -40,9 +40,24 @@ testrebase() {
test_path_is_missing "$state_dir"
'
+ test_expect_success "pre rebase$type head is marked as reachable" '
+ # Clean up the state from the previous one
+ git checkout -f --detach pre-rebase &&
+ test_tick &&
+ git commit --amend --only -m "reworded" &&
+ orig_head=$(git rev-parse HEAD) &&
+ test_must_fail git rebase$type main &&
+ # Stop ORIG_HEAD marking $state_dir/orig-head as reachable
+ git update-ref -d ORIG_HEAD &&
+ git reflog expire --expire="$GIT_COMMITTER_DATE" --all &&
+ git prune --expire=now &&
+ git rebase --abort &&
+ test_cmp_rev $orig_head HEAD
+ '
+
test_expect_success "rebase$type --abort after --skip" '
# Clean up the state from the previous one
- git reset --hard pre-rebase &&
+ git checkout -B to-rebase pre-rebase &&
test_must_fail git rebase$type main &&
test_path_is_dir "$state_dir" &&
test_must_fail git rebase --skip &&
diff --git a/t/t3408-rebase-multi-line.sh b/t/t3408-rebase-multi-line.sh
index 7b4607d72f..cde3562e3a 100755
--- a/t/t3408-rebase-multi-line.sh
+++ b/t/t3408-rebase-multi-line.sh
@@ -5,7 +5,6 @@ test_description='rebasing a commit with multi-line first paragraph.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3409-rebase-environ.sh b/t/t3409-rebase-environ.sh
index acaf5558db..83ffb39d9f 100755
--- a/t/t3409-rebase-environ.sh
+++ b/t/t3409-rebase-environ.sh
@@ -2,7 +2,6 @@
test_description='git rebase interactive environment'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index e75b3d0e07..58371d8a54 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -7,7 +7,6 @@ Tests if git rebase --root --onto <newparent> can rebase the root commit.
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
log_with_names () {
diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh
index e8456831e8..b4ff614987 100755
--- a/t/t3413-rebase-hook.sh
+++ b/t/t3413-rebase-hook.sh
@@ -5,7 +5,6 @@ test_description='git rebase with its hook(s)'
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 '
@@ -110,7 +109,9 @@ test_expect_success 'pre-rebase hook stops rebase (1)' '
git reset --hard side &&
test_must_fail git rebase main &&
test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
- test 0 = $(git rev-list HEAD...side | wc -l)
+ test 0 = $(git rev-list HEAD...side | wc -l) &&
+ test_must_fail git rebase --quit 2>err &&
+ test_grep "no rebase in progress" err
'
test_expect_success 'pre-rebase hook stops rebase (2)' '
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index a364530d76..fcc40d6fe1 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -43,7 +43,7 @@ test_auto_fixup () {
git tag $1 &&
test_tick &&
- git rebase $2 -i HEAD^^^ &&
+ git rebase $2 HEAD^^^ &&
git log --oneline >actual &&
if test -n "$no_squash"
then
@@ -61,15 +61,24 @@ test_auto_fixup () {
}
test_expect_success 'auto fixup (option)' '
- test_auto_fixup final-fixup-option --autosquash
+ test_auto_fixup fixup-option --autosquash &&
+ test_auto_fixup fixup-option-i "--autosquash -i"
'
-test_expect_success 'auto fixup (config)' '
+test_expect_success 'auto fixup (config true)' '
git config rebase.autosquash true &&
- test_auto_fixup final-fixup-config-true &&
+ test_auto_fixup ! fixup-config-true &&
+ test_auto_fixup fixup-config-true-i -i &&
test_auto_fixup ! fixup-config-true-no --no-autosquash &&
+ test_auto_fixup ! fixup-config-true-i-no "-i --no-autosquash"
+'
+
+test_expect_success 'auto fixup (config false)' '
git config rebase.autosquash false &&
- test_auto_fixup ! final-fixup-config-false
+ test_auto_fixup ! fixup-config-false &&
+ test_auto_fixup ! fixup-config-false-i -i &&
+ test_auto_fixup fixup-config-false-yes --autosquash &&
+ test_auto_fixup fixup-config-false-i-yes "-i --autosquash"
'
test_auto_squash () {
@@ -87,7 +96,7 @@ test_auto_squash () {
git commit -m "squash! first" -m "extra para for first" &&
git tag $1 &&
test_tick &&
- git rebase $2 -i HEAD^^^ &&
+ git rebase $2 HEAD^^^ &&
git log --oneline >actual &&
if test -n "$no_squash"
then
@@ -105,15 +114,24 @@ test_auto_squash () {
}
test_expect_success 'auto squash (option)' '
- test_auto_squash final-squash --autosquash
+ test_auto_squash squash-option --autosquash &&
+ test_auto_squash squash-option-i "--autosquash -i"
'
-test_expect_success 'auto squash (config)' '
+test_expect_success 'auto squash (config true)' '
git config rebase.autosquash true &&
- test_auto_squash final-squash-config-true &&
+ test_auto_squash ! squash-config-true &&
+ test_auto_squash squash-config-true-i -i &&
test_auto_squash ! squash-config-true-no --no-autosquash &&
+ test_auto_squash ! squash-config-true-i-no "-i --no-autosquash"
+'
+
+test_expect_success 'auto squash (config false)' '
git config rebase.autosquash false &&
- test_auto_squash ! final-squash-config-false
+ test_auto_squash ! squash-config-false &&
+ test_auto_squash ! squash-config-false-i -i &&
+ test_auto_squash squash-config-false-yes --autosquash &&
+ test_auto_squash squash-config-false-i-yes "-i --autosquash"
'
test_expect_success 'misspelled auto squash' '
diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh
index f8c4ed78c9..ea501f2b42 100755
--- a/t/t3416-rebase-onto-threedots.sh
+++ b/t/t3416-rebase-onto-threedots.sh
@@ -5,7 +5,6 @@ test_description='git rebase --onto A...B'
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"
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index c4e2fcac67..127216f722 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -182,8 +182,8 @@ test_expect_success '--skip after failed fixup cleans commit message' '
: Final squash failed, but there was still a squash &&
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_grep "# This is a combination of 3 commits" first-line &&
+ test_grep "# This is the commit message #3:" .git/copy.txt
'
test_expect_success 'setup rerere database' '
@@ -294,7 +294,7 @@ test_expect_success '--reschedule-failed-exec' '
test_must_fail git -c rebase.rescheduleFailedExec=true \
rebase -x false HEAD^ 2>err &&
grep "^exec false" .git/rebase-merge/git-rebase-todo &&
- test_i18ngrep "has been rescheduled" err
+ test_grep "has been rescheduled" err
'
test_expect_success 'rebase.rescheduleFailedExec only affects `rebase -i`' '
diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh
index 6c61f240cf..7181f176b8 100755
--- a/t/t3419-rebase-patch-id.sh
+++ b/t/t3419-rebase-patch-id.sh
@@ -5,7 +5,6 @@ test_description='git rebase - test patch id computation'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
scramble () {
diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index 693934ee8b..ad3ba6a984 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -81,6 +81,46 @@ testrebase () {
type=$1
dotest=$2
+ test_expect_success "rebase$type: restore autostash when pre-rebase hook fails" '
+ git checkout -f feature-branch &&
+ test_hook pre-rebase <<-\EOF &&
+ exit 1
+ EOF
+
+ echo changed >file0 &&
+ test_must_fail git rebase $type --autostash -f HEAD^ &&
+ test_must_fail git rebase --quit 2>err &&
+ test_grep "no rebase in progress" err &&
+ echo changed >expect &&
+ test_cmp expect file0
+ '
+
+ test_expect_success "rebase$type: restore autostash when checkout onto fails" '
+ git checkout -f --detach feature-branch &&
+ echo uncommitted-content >file0 &&
+ echo untracked >file4 &&
+ test_when_finished "rm file4" &&
+ test_must_fail git rebase $type --autostash \
+ unrelated-onto-branch &&
+ test_must_fail git rebase --quit 2>err &&
+ test_grep "no rebase in progress" err &&
+ echo uncommitted-content >expect &&
+ test_cmp expect file0
+ '
+
+ test_expect_success "rebase$type: restore autostash when branch checkout fails" '
+ git checkout -f unrelated-onto-branch^ &&
+ echo uncommitted-content >file0 &&
+ echo untracked >file4 &&
+ test_when_finished "rm file4" &&
+ test_must_fail git rebase $type --autostash HEAD \
+ unrelated-onto-branch &&
+ test_must_fail git rebase --quit 2>err &&
+ test_grep "no rebase in progress" err &&
+ echo uncommitted-content >expect &&
+ test_cmp expect file0
+ '
+
test_expect_success "rebase$type: dirty worktree, --no-autostash" '
test_config rebase.autostash true &&
git reset --hard &&
@@ -333,4 +373,14 @@ test_expect_success 'never change active branch' '
test_cmp_rev not-the-feature-branch unrelated-onto-branch
'
+test_expect_success 'autostash commit is marked as reachable' '
+ echo changed >file0 &&
+ git rebase --autostash --exec "git prune --expire=now" \
+ feature-branch^ feature-branch &&
+ # git rebase succeeds if the stash cannot be applied so we need to check
+ # the contents of file0
+ echo changed >expect &&
+ test_cmp expect file0
+'
+
test_done
diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh
index 62d86d557d..f5b7807abd 100755
--- a/t/t3421-rebase-topology-linear.sh
+++ b/t/t3421-rebase-topology-linear.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='basic rebase topology tests'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh
index 2eba00bdf5..b9408f9ba1 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -2,7 +2,6 @@
test_description='test if rebase detects and aborts on incompatible options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -100,12 +99,6 @@ test_rebase_am_only () {
test_must_fail git rebase $opt --root A
"
- test_expect_success "$opt incompatible with rebase.autosquash" "
- git checkout B^0 &&
- test_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&
- 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 &&
@@ -118,12 +111,6 @@ test_rebase_am_only () {
grep -e --no-update-refs err
"
- test_expect_success "$opt okay with overridden rebase.autosquash" "
- test_when_finished \"git reset --hard B^0\" &&
- git checkout B^0 &&
- 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 &&
diff --git a/t/t3423-rebase-reword.sh b/t/t3423-rebase-reword.sh
index 2fab703d61..4859bb8f72 100755
--- a/t/t3423-rebase-reword.sh
+++ b/t/t3423-rebase-reword.sh
@@ -2,7 +2,6 @@
test_description='git rebase interactive with rewording'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3424-rebase-empty.sh b/t/t3424-rebase-empty.sh
index 5e1045a0af..1ee6b00fd5 100755
--- a/t/t3424-rebase-empty.sh
+++ b/t/t3424-rebase-empty.sh
@@ -72,6 +72,17 @@ test_expect_success 'rebase --merge --empty=keep' '
test_cmp expect actual
'
+test_expect_success 'rebase --merge --empty=stop' '
+ git checkout -B testing localmods &&
+ test_must_fail git rebase --merge --empty=stop upstream &&
+
+ git rebase --skip &&
+
+ test_write_lines D C B A >expect &&
+ git log --format=%s >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'rebase --merge --empty=ask' '
git checkout -B testing localmods &&
test_must_fail git rebase --merge --empty=ask upstream &&
@@ -101,9 +112,9 @@ test_expect_success 'rebase --interactive --empty=keep' '
test_cmp expect actual
'
-test_expect_success 'rebase --interactive --empty=ask' '
+test_expect_success 'rebase --interactive --empty=stop' '
git checkout -B testing localmods &&
- test_must_fail git rebase --interactive --empty=ask upstream &&
+ test_must_fail git rebase --interactive --empty=stop upstream &&
git rebase --skip &&
@@ -112,7 +123,7 @@ test_expect_success 'rebase --interactive --empty=ask' '
test_cmp expect actual
'
-test_expect_success 'rebase --interactive uses default of --empty=ask' '
+test_expect_success 'rebase --interactive uses default of --empty=stop' '
git checkout -B testing localmods &&
test_must_fail git rebase --interactive upstream &&
@@ -167,4 +178,42 @@ test_expect_success 'rebase --merge does not leave state laying around' '
test_path_is_missing .git/MERGE_MSG
'
+test_expect_success 'rebase --exec --empty=drop' '
+ git checkout -B testing localmods &&
+ git rebase --exec "true" --empty=drop upstream &&
+
+ test_write_lines D C B A >expect &&
+ git log --format=%s >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rebase --exec --empty=keep' '
+ git checkout -B testing localmods &&
+ git rebase --exec "true" --empty=keep upstream &&
+
+ test_write_lines D C2 C B A >expect &&
+ git log --format=%s >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rebase --exec uses default of --empty=keep' '
+ git checkout -B testing localmods &&
+ git rebase --exec "true" upstream &&
+
+ test_write_lines D C2 C B A >expect &&
+ git log --format=%s >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rebase --exec --empty=stop' '
+ git checkout -B testing localmods &&
+ test_must_fail git rebase --exec "true" --empty=stop upstream &&
+
+ git rebase --skip &&
+
+ test_write_lines D C B A >expect &&
+ git log --format=%s >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh
index a16428bdf5..675491234a 100755
--- a/t/t3425-rebase-topology-merges.sh
+++ b/t/t3425-rebase-topology-merges.sh
@@ -2,7 +2,6 @@
test_description='rebase topology tests with merges'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh
index e1b1e94764..6f57aed9fa 100755
--- a/t/t3428-rebase-signoff.sh
+++ b/t/t3428-rebase-signoff.sh
@@ -5,81 +5,136 @@ test_description='git rebase --signoff
This test runs git rebase --signoff and make sure that it works.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
-# A simple file to commit
-cat >file <<EOF
-a
-EOF
+test_expect_success 'setup' '
+ git commit --allow-empty -m "Initial empty commit" &&
+ test_commit first file a &&
+ test_commit second file &&
+ git checkout -b conflict-branch first &&
+ test_commit file-2 file-2 &&
+ test_commit conflict file &&
+ test_commit third file &&
+
+ ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
+
+ # Expected commit message for initial commit after rebase --signoff
+ cat >expected-initial-signed <<-EOF &&
+ Initial empty commit
+
+ Signed-off-by: $ident
+ EOF
+
+ # Expected commit message after rebase --signoff
+ cat >expected-signed <<-EOF &&
+ first
+
+ Signed-off-by: $ident
+ EOF
+
+ # Expected commit message after conflict resolution for rebase --signoff
+ cat >expected-signed-conflict <<-EOF &&
+ third
+
+ Signed-off-by: $ident
-# Expected commit message for initial commit after rebase --signoff
-cat >expected-initial-signed <<EOF
-Initial empty commit
+ conflict
-Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/")
-EOF
+ Signed-off-by: $ident
-# Expected commit message after rebase --signoff
-cat >expected-signed <<EOF
-first
+ file-2
-Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/")
-EOF
+ Signed-off-by: $ident
-# Expected commit message after rebase without --signoff (or with --no-signoff)
-cat >expected-unsigned <<EOF
-first
-EOF
+ EOF
+ # Expected commit message after rebase without --signoff (or with --no-signoff)
+ cat >expected-unsigned <<-EOF &&
+ first
+ EOF
+
+ git config alias.rbs "rebase --signoff"
+'
# We configure an alias to do the rebase --signoff so that
# on the next subtest we can show that --no-signoff overrides the alias
-test_expect_success 'rebase --signoff adds a sign-off line' '
- git commit --allow-empty -m "Initial empty commit" &&
- git add file && git commit -m first &&
- git config alias.rbs "rebase --signoff" &&
- git rbs HEAD^ &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
- test_cmp expected-signed actual
+test_expect_success 'rebase --apply --signoff adds a sign-off line' '
+ test_must_fail git rbs --apply second third &&
+ git checkout --theirs file &&
+ git add file &&
+ git rebase --continue &&
+ git log --format=%B -n3 >actual &&
+ test_cmp expected-signed-conflict actual
'
test_expect_success 'rebase --no-signoff does not add a sign-off line' '
git commit --amend -m "first" &&
git rbs --no-signoff HEAD^ &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
- test_cmp expected-unsigned actual
+ test_commit_message HEAD expected-unsigned
'
test_expect_success 'rebase --exec --signoff adds a sign-off line' '
test_when_finished "rm exec" &&
- git commit --amend -m "first" &&
- git rebase --exec "touch exec" --signoff HEAD^ &&
+ git rebase --exec "touch exec" --signoff first^ first &&
test_path_is_file exec &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
- test_cmp expected-signed actual
+ test_commit_message HEAD expected-signed
'
test_expect_success 'rebase --root --signoff adds a sign-off line' '
- git commit --amend -m "first" &&
+ git checkout first &&
git rebase --root --keep-empty --signoff &&
- git cat-file commit HEAD^ | sed -e "1,/^\$/d" >actual &&
- test_cmp expected-initial-signed actual &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
- test_cmp expected-signed actual
+ test_commit_message HEAD^ expected-initial-signed &&
+ test_commit_message HEAD expected-signed
'
-test_expect_success 'rebase -i --signoff fails' '
- git commit --amend -m "first" &&
- git rebase -i --signoff HEAD^ &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
- test_cmp expected-signed actual
+test_expect_success 'rebase -m --signoff adds a sign-off line' '
+ test_must_fail git rebase -m --signoff second third &&
+ git checkout --theirs file &&
+ git add file &&
+ GIT_EDITOR="sed -n /Conflicts:/,/^\\\$/p >actual" \
+ git rebase --continue &&
+ cat >expect <<-\EOF &&
+ # Conflicts:
+ # file
+
+ EOF
+ test_cmp expect actual &&
+ git log --format=%B -n3 >actual &&
+ test_cmp expected-signed-conflict actual
'
-test_expect_success 'rebase -m --signoff fails' '
- git commit --amend -m "first" &&
- git rebase -m --signoff HEAD^ &&
- git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
- test_cmp expected-signed actual
+test_expect_success 'rebase -i --signoff adds a sign-off line when editing commit' '
+ (
+ set_fake_editor &&
+ FAKE_LINES="edit 1 edit 3 edit 2" \
+ git rebase -i --signoff first third
+ ) &&
+ echo a >a &&
+ git add a &&
+ test_must_fail git rebase --continue &&
+ git checkout --ours file &&
+ echo b >a &&
+ git add a file &&
+ git rebase --continue &&
+ echo c >a &&
+ git add a &&
+ git log --format=%B -n3 >actual &&
+ cat >expect <<-EOF &&
+ conflict
+
+ Signed-off-by: $ident
+
+ third
+
+ Signed-off-by: $ident
+
+ file-2
+
+ Signed-off-by: $ident
+
+ EOF
+ test_cmp expect actual
'
+
test_done
diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh
index 8e0d03969a..abd66f3602 100755
--- a/t/t3429-rebase-edit-todo.sh
+++ b/t/t3429-rebase-edit-todo.sh
@@ -2,7 +2,6 @@
test_description='rebase should reread the todo file if an exec modifies it'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 59b5d6b6f2..2593711fec 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -107,19 +107,19 @@ test_expect_success 'generate correct todo list' '
reset onto
pick $b B
- label E
+ label first
reset onto
pick $c C
label branch-point
pick $f F
pick $g G
- label H
+ label second
reset branch-point # C
pick $d D
- merge -C $e E # E
- merge -C $h H # H
+ merge -C $e first # E
+ merge -C $h second # H
EOF
@@ -391,8 +391,7 @@ test_expect_success 'refuse to merge ancestors of HEAD' '
test_expect_success 'root commits' '
git checkout --orphan unrelated &&
- (GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \
- test_commit second-root) &&
+ test_commit --author "Parsnip <root@example.com>" second-root &&
test_commit third-root &&
cat >script-from-scratch <<-\EOF &&
pick third-root
@@ -462,11 +461,11 @@ test_expect_success 'A root commit can be a cousin, treat it that way' '
'
test_expect_success 'labels that are object IDs are rewritten' '
- git checkout -b third B &&
+ git checkout --detach B &&
test_commit I &&
third=$(git rev-parse HEAD) &&
git checkout -b labels main &&
- git merge --no-commit third &&
+ git merge --no-commit $third &&
test_tick &&
git commit -m "Merge commit '\''$third'\'' into labels" &&
echo noop >script-from-scratch &&
diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh
index 4bfc779bb8..be09fc78c1 100755
--- a/t/t3431-rebase-fork-point.sh
+++ b/t/t3431-rebase-fork-point.sh
@@ -8,7 +8,6 @@ test_description='git rebase --fork-point test'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# A---B---D---E (main)
@@ -74,7 +73,7 @@ test_rebase 'G F C D B A' --onto D main
test_rebase 'G F C B A' --keep-base refs/heads/main
test_rebase 'G F C B A' --keep-base main
-test_expect_success 'git rebase --fork-point with ambigous refname' '
+test_expect_success 'git rebase --fork-point with ambiguous refname' '
git checkout main &&
git checkout -b one &&
git checkout side &&
@@ -84,7 +83,7 @@ test_expect_success 'git rebase --fork-point with ambigous refname' '
test_expect_success '--fork-point and --root both given' '
test_must_fail git rebase --fork-point --root 2>err &&
- test_i18ngrep "cannot be used together" err
+ test_grep "cannot be used together" err
'
test_expect_success 'rebase.forkPoint set to false' '
diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh
index 7f1a5dd3de..5086e14c02 100755
--- a/t/t3432-rebase-fast-forward.sh
+++ b/t/t3432-rebase-fast-forward.sh
@@ -8,7 +8,6 @@ test_description='ensure rebase fast-forwards commits when possible'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3433-rebase-across-mode-change.sh b/t/t3433-rebase-across-mode-change.sh
index c8172b0852..05df964670 100755
--- a/t/t3433-rebase-across-mode-change.sh
+++ b/t/t3433-rebase-across-mode-change.sh
@@ -2,7 +2,6 @@
test_description='git rebase across mode change'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3434-rebase-i18n.sh b/t/t3434-rebase-i18n.sh
index e6fef696bb..8c94fdffc4 100755
--- a/t/t3434-rebase-i18n.sh
+++ b/t/t3434-rebase-i18n.sh
@@ -19,6 +19,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping rebase i18n tests; iconv not available'
+ test_done
+fi
+
compare_msg () {
iconv -f "$2" -t "$3" "$TEST_DIRECTORY/t3434/$1" >expect &&
git cat-file commit HEAD >raw &&
@@ -71,7 +77,7 @@ test_rebase_continue_update_encode () {
git config i18n.commitencoding $new &&
test_must_fail git rebase -m main &&
test -f .git/rebase-merge/message &&
- git stripspace <.git/rebase-merge/message >two.t &&
+ git stripspace -s <.git/rebase-merge/message >two.t &&
git add two.t &&
git rebase --continue &&
compare_msg $msgfile $old $new &&
diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh
index 7929e2e2e3..6f9307e0e3 100755
--- a/t/t3437-rebase-fixup-options.sh
+++ b/t/t3437-rebase-fixup-options.sh
@@ -14,7 +14,6 @@ to the "fixup" command that works with "fixup!", "fixup -C" works with
"amend!" upon --autosquash.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3438-rebase-broken-files.sh b/t/t3438-rebase-broken-files.sh
index c614c4f2e4..78d42f4c79 100755
--- a/t/t3438-rebase-broken-files.sh
+++ b/t/t3438-rebase-broken-files.sh
@@ -2,7 +2,6 @@
test_description='rebase behavior when on-disk files are broken'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up conflicting branches' '
@@ -58,4 +57,13 @@ test_expect_success 'unknown key in author-script' '
check_resolve_fails
'
+test_expect_success POSIXPERM,SANITY 'unwritable rebased-patches does not leak' '
+ >.git/rebased-patches &&
+ chmod a-w .git/rebased-patches &&
+
+ git checkout -b side HEAD^ &&
+ test_commit unrelated &&
+ test_must_fail git rebase --apply --onto tmp HEAD^
+'
+
test_done
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index e2ef619323..17a9937962 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -5,7 +5,6 @@ test_description='miscellaneous basic tests for cherry-pick and revert'
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 '
@@ -43,7 +42,7 @@ test_expect_success 'cherry-pick --nonsense' '
git diff --exit-code HEAD &&
test_must_fail git cherry-pick --nonsense 2>msg &&
git diff --exit-code HEAD "$pos" &&
- test_i18ngrep "[Uu]sage:" msg
+ test_grep "[Uu]sage:" msg
'
test_expect_success 'revert --nonsense' '
@@ -52,7 +51,7 @@ test_expect_success 'revert --nonsense' '
git diff --exit-code HEAD &&
test_must_fail git revert --nonsense 2>msg &&
git diff --exit-code HEAD "$pos" &&
- test_i18ngrep "[Uu]sage:" msg
+ test_grep "[Uu]sage:" msg
'
# the following two test cherry-pick and revert with renames
@@ -99,16 +98,24 @@ test_expect_success 'revert forbidden on dirty working tree' '
echo content >extra_file &&
git add extra_file &&
test_must_fail git revert HEAD 2>errors &&
- test_i18ngrep "your local changes would be overwritten by " errors
+ test_grep "your local changes would be overwritten by " errors
'
test_expect_success 'cherry-pick on unborn branch' '
- git checkout --orphan unborn &&
+ git switch --orphan unborn &&
git rm --cached -r . &&
- rm -rf * &&
git cherry-pick initial &&
- git diff --quiet initial &&
+ git diff --exit-code initial &&
+ test_cmp_rev ! initial HEAD
+'
+
+test_expect_success 'cherry-pick on unborn branch with --allow-empty' '
+ git checkout --detach &&
+ git branch -D unborn &&
+ git switch --orphan unborn &&
+ git cherry-pick initial --allow-empty &&
+ git diff --exit-code initial &&
test_cmp_rev ! initial HEAD
'
@@ -170,12 +177,36 @@ test_expect_success 'advice from failed revert' '
hint: You can instead skip this commit with "git revert --skip".
hint: To abort and get back to the state before "git revert",
hint: run "git revert --abort".
+ hint: Disable this message with "git config advice.mergeConflict false"
EOF
test_commit --append --no-tag "double-add dream" dream dream &&
test_must_fail git revert HEAD^ 2>actual &&
test_cmp expected actual
'
+test_expect_subject () {
+ echo "$1" >expect &&
+ git log -1 --pretty=%s >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'titles of fresh reverts' '
+ test_commit --no-tag A file1 &&
+ test_commit --no-tag B file1 &&
+ git revert --no-edit HEAD &&
+ test_expect_subject "Revert \"B\"" &&
+ git revert --no-edit HEAD &&
+ test_expect_subject "Reapply \"B\"" &&
+ git revert --no-edit HEAD &&
+ test_expect_subject "Revert \"Reapply \"B\"\""
+'
+
+test_expect_success 'title of legacy double revert' '
+ test_commit --no-tag "Revert \"Revert \"B\"\"" file1 &&
+ git revert --no-edit HEAD &&
+ test_expect_subject "Revert \"Revert \"Revert \"B\"\"\""
+'
+
test_expect_success 'identification of reverted commit (default)' '
test_commit to-ident &&
test_when_finished "git reset --hard to-ident" &&
diff --git a/t/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh
index 1b2c0d6aca..5495eacfec 100755
--- a/t/t3502-cherry-pick-merge.sh
+++ b/t/t3502-cherry-pick-merge.sh
@@ -11,7 +11,6 @@ test_description='cherry picking and reverting a merge
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh
index 76d393dc8a..95fe4feaee 100755
--- a/t/t3503-cherry-pick-root.sh
+++ b/t/t3503-cherry-pick-root.sh
@@ -5,7 +5,6 @@ test_description='test cherry-picking (and reverting) a root commit'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3504-cherry-pick-rerere.sh b/t/t3504-cherry-pick-rerere.sh
index 4581ae98b8..18aeba161c 100755
--- a/t/t3504-cherry-pick-rerere.sh
+++ b/t/t3504-cherry-pick-rerere.sh
@@ -42,7 +42,7 @@ test_expect_success 'cherry-pick conflict with --rerere-autoupdate' '
git reset --hard bar-dev
'
-test_expect_success 'cherry-pick conflict repsects rerere.autoUpdate' '
+test_expect_success 'cherry-pick conflict respects rerere.autoUpdate' '
test_config rerere.autoUpdate true &&
test_must_fail git cherry-pick foo..bar-main &&
test_cmp foo-expect foo &&
diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index eba3c38d5a..9748443530 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -84,7 +84,7 @@ test_expect_success 'cherry-pick a commit that becomes no-op (prep)' '
git commit -m "add file2 on the side"
'
-test_expect_success 'cherry-pick a no-op without --keep-redundant' '
+test_expect_success 'cherry-pick a no-op with neither --keep-redundant nor --empty' '
git reset --hard &&
git checkout fork^0 &&
test_must_fail git cherry-pick main
@@ -99,4 +99,53 @@ test_expect_success 'cherry-pick a no-op with --keep-redundant' '
test_cmp expect actual
'
+test_expect_success '--keep-redundant-commits is incompatible with operations' '
+ test_must_fail git cherry-pick HEAD 2>output &&
+ test_grep "The previous cherry-pick is now empty" output &&
+ test_must_fail git cherry-pick --keep-redundant-commits --continue 2>output &&
+ test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --continue" output &&
+ test_must_fail git cherry-pick --keep-redundant-commits --skip 2>output &&
+ test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --skip" output &&
+ test_must_fail git cherry-pick --keep-redundant-commits --abort 2>output &&
+ test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --abort" output &&
+ test_must_fail git cherry-pick --keep-redundant-commits --quit 2>output &&
+ test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --quit" output &&
+ git cherry-pick --abort
+'
+
+test_expect_success '--empty is incompatible with operations' '
+ test_must_fail git cherry-pick HEAD 2>output &&
+ test_grep "The previous cherry-pick is now empty" output &&
+ test_must_fail git cherry-pick --empty=stop --continue 2>output &&
+ test_grep "fatal: cherry-pick: --empty cannot be used with --continue" output &&
+ test_must_fail git cherry-pick --empty=stop --skip 2>output &&
+ test_grep "fatal: cherry-pick: --empty cannot be used with --skip" output &&
+ test_must_fail git cherry-pick --empty=stop --abort 2>output &&
+ test_grep "fatal: cherry-pick: --empty cannot be used with --abort" output &&
+ test_must_fail git cherry-pick --empty=stop --quit 2>output &&
+ test_grep "fatal: cherry-pick: --empty cannot be used with --quit" output &&
+ git cherry-pick --abort
+'
+
+test_expect_success 'cherry-pick a no-op with --empty=stop' '
+ git reset --hard &&
+ git checkout fork^0 &&
+ test_must_fail git cherry-pick --empty=stop main 2>output &&
+ test_grep "The previous cherry-pick is now empty" output
+'
+
+test_expect_success 'cherry-pick a no-op with --empty=drop' '
+ git reset --hard &&
+ git checkout fork^0 &&
+ git cherry-pick --empty=drop main &&
+ test_commit_message HEAD -m "add file2 on the side"
+'
+
+test_expect_success 'cherry-pick a no-op with --empty=keep' '
+ git reset --hard &&
+ git checkout fork^0 &&
+ git cherry-pick --empty=keep main &&
+ test_commit_message HEAD -m "add file2 on main"
+'
+
test_done
diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh
index b71bad17b8..7e11bd4a4c 100755
--- a/t/t3506-cherry-pick-ff.sh
+++ b/t/t3506-cherry-pick-ff.sh
@@ -5,7 +5,6 @@ test_description='test cherry-picking with --ff option'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index f32799e046..f3947b400a 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -60,6 +60,7 @@ test_expect_success 'advice from failed cherry-pick' '
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
+ hint: Disable this message with "git config advice.mergeConflict false"
EOF
test_must_fail git cherry-pick picked 2>actual &&
@@ -74,6 +75,7 @@ test_expect_success 'advice from failed cherry-pick --no-commit' "
error: could not apply \$picked... picked
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
+ hint: Disable this message with \"git config advice.mergeConflict false\"
EOF
test_must_fail git cherry-pick --no-commit picked 2>actual &&
@@ -177,7 +179,7 @@ test_expect_success 'partial commit of cherry-pick fails' '
git add foo &&
test_must_fail git commit foo 2>err &&
- test_i18ngrep "cannot do a partial commit during a cherry-pick." err
+ test_grep "cannot do a partial commit during a cherry-pick." err
'
test_expect_success 'commit --amend of cherry-pick fails' '
@@ -188,7 +190,7 @@ test_expect_success 'commit --amend of cherry-pick fails' '
git add foo &&
test_must_fail git commit --amend 2>err &&
- test_i18ngrep "in the middle of a cherry-pick -- cannot amend." err
+ test_grep "in the middle of a cherry-pick -- cannot amend." err
'
test_expect_success 'successful final commit clears cherry-pick state' '
@@ -498,7 +500,7 @@ test_expect_success \
test_expect_success 'failed cherry-pick does not forget -s' '
pristine_detach initial &&
test_must_fail git cherry-pick -s picked &&
- test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG
+ test_grep -e "Signed-off-by" .git/MERGE_MSG
'
test_expect_success 'commit after failed cherry-pick does not add duplicated -s' '
@@ -563,7 +565,7 @@ test_expect_success 'cherry-pick preserves sparse-checkout' '
echo /unrelated >.git/info/sparse-checkout &&
git read-tree --reset -u HEAD &&
test_must_fail git cherry-pick -Xours picked>actual &&
- test_i18ngrep ! "Changes not staged for commit:" actual
+ test_grep ! "Changes not staged for commit:" actual
'
test_expect_success 'cherry-pick --continue remembers --keep-redundant-commits' '
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 3b0fa66c33..7eb52b12ed 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -90,6 +90,38 @@ test_expect_success 'cherry-pick persists opts correctly' '
test_cmp expect actual
'
+test_expect_success 'cherry-pick persists --empty=stop correctly' '
+ pristine_detach yetanotherpick &&
+ # Picking `anotherpick` forces a conflict so that we stop. That
+ # commit is then skipped, after which we pick `yetanotherpick`
+ # while already on `yetanotherpick` to cause an empty commit
+ test_must_fail git cherry-pick --empty=stop anotherpick yetanotherpick &&
+ test_must_fail git cherry-pick --skip 2>msg &&
+ test_grep "The previous cherry-pick is now empty" msg &&
+ rm msg &&
+ git cherry-pick --abort
+'
+
+test_expect_success 'cherry-pick persists --empty=drop correctly' '
+ pristine_detach yetanotherpick &&
+ # Picking `anotherpick` forces a conflict so that we stop. That
+ # commit is then skipped, after which we pick `yetanotherpick`
+ # while already on `yetanotherpick` to cause an empty commit
+ test_must_fail git cherry-pick --empty=drop anotherpick yetanotherpick &&
+ git cherry-pick --skip &&
+ test_cmp_rev yetanotherpick HEAD
+'
+
+test_expect_success 'cherry-pick persists --empty=keep correctly' '
+ pristine_detach yetanotherpick &&
+ # Picking `anotherpick` forces a conflict so that we stop. That
+ # commit is then skipped, after which we pick `yetanotherpick`
+ # while already on `yetanotherpick` to cause an empty commit
+ test_must_fail git cherry-pick --empty=keep anotherpick yetanotherpick &&
+ git cherry-pick --skip &&
+ test_cmp_rev yetanotherpick HEAD^
+'
+
test_expect_success 'revert persists opts correctly' '
pristine_detach initial &&
# to make sure that the session to revert a sequence
@@ -154,7 +186,7 @@ test_expect_success 'skip "empty" commit' '
pristine_detach picked &&
test_commit dummy foo d &&
test_must_fail git cherry-pick anotherpick 2>err &&
- test_i18ngrep "git cherry-pick --skip" err &&
+ test_grep "git cherry-pick --skip" err &&
git cherry-pick --skip &&
test_cmp_rev dummy HEAD
'
@@ -314,7 +346,7 @@ test_expect_success '--abort does not unsafely change HEAD' '
git reset --hard base &&
test_must_fail git cherry-pick picked anotherpick &&
git cherry-pick --abort 2>actual &&
- test_i18ngrep "You seem to have moved HEAD" actual &&
+ test_grep "You seem to have moved HEAD" actual &&
test_cmp_rev base HEAD
'
@@ -520,7 +552,7 @@ test_expect_success '--continue asks for help after resolving patch to nil' '
test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
git checkout HEAD -- unrelated &&
test_must_fail git cherry-pick --continue 2>msg &&
- test_i18ngrep "The previous cherry-pick is now empty" msg
+ test_grep "The previous cherry-pick is now empty" msg
'
test_expect_success 'follow advice and skip nil patch' '
diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh
index dd5d92ef30..84a587daf3 100755
--- a/t/t3511-cherry-pick-x.sh
+++ b/t/t3511-cherry-pick-x.sh
@@ -2,7 +2,6 @@
test_description='Test cherry-pick -x and -s'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pristine_detach () {
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 0e8afe49ed..98259e2ada 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -276,7 +276,7 @@ test_expect_success 'Resolving by removal is not a warning-worthy event' '
blob=$(echo blob | git hash-object -w --stdin) &&
printf "100644 $blob %d\tblob\n" 1 2 3 | git update-index --index-info &&
git rm blob >msg 2>&1 &&
- test_i18ngrep ! "needs merge" msg &&
+ test_grep ! "needs merge" msg &&
test_must_fail git ls-files -s --error-unmatch blob
'
@@ -631,7 +631,7 @@ test_expect_success 'rm of a populated submodule with a .git directory migrates
test_path_is_missing submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
test_file_not_empty actual &&
- test_i18ngrep Migrating output.err
+ test_grep Migrating output.err
'
cat >expect.deepmodified <<EOF
@@ -722,7 +722,7 @@ test_expect_success "rm absorbs submodule's nested .git directory" '
test_path_is_missing submod/subsubmod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
test_file_not_empty actual &&
- test_i18ngrep Migrating output.err
+ test_grep Migrating output.err
'
test_expect_success 'checking out a commit after submodule removal needs manual updates' '
@@ -731,7 +731,7 @@ test_expect_success 'checking out a commit after submodule removal needs manual
git submodule update &&
git checkout -q HEAD^ &&
git checkout -q main 2>actual &&
- test_i18ngrep "^warning: unable to rmdir '\''submod'\'':" actual &&
+ test_grep "^warning: unable to rmdir '\''submod'\'':" actual &&
git status -s submod >actual &&
echo "?? submod/" >expected &&
test_cmp expected actual &&
diff --git a/t/t3601-rm-pathspec-file.sh b/t/t3601-rm-pathspec-file.sh
index a2a0c820fe..31bd9960fc 100755
--- a/t/t3601-rm-pathspec-file.sh
+++ b/t/t3601-rm-pathspec-file.sh
@@ -2,7 +2,6 @@
test_description='rm --pathspec-from-file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_tick
@@ -67,14 +66,14 @@ test_expect_success 'error conditions' '
echo fileA.t >list &&
test_must_fail git rm --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git rm --pathspec-file-nul 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
>empty_list &&
test_must_fail git rm --pathspec-from-file=empty_list 2>err &&
- test_i18ngrep -e "No pathspec was given. Which files should I remove?" err
+ test_grep -e "No pathspec was given. Which files should I remove?" err
'
test_done
diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh
new file mode 100755
index 0000000000..389670262e
--- /dev/null
+++ b/t/t3650-replay-basics.sh
@@ -0,0 +1,198 @@
+#!/bin/sh
+
+test_description='basic git replay tests'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+GIT_AUTHOR_NAME=author@name
+GIT_AUTHOR_EMAIL=bogus@email@address
+export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+
+test_expect_success 'setup' '
+ test_commit A &&
+ test_commit B &&
+
+ git switch -c topic1 &&
+ test_commit C &&
+ git switch -c topic2 &&
+ test_commit D &&
+ test_commit E &&
+ git switch topic1 &&
+ test_commit F &&
+ git switch -c topic3 &&
+ test_commit G &&
+ test_commit H &&
+ git switch -c topic4 main &&
+ test_commit I &&
+ test_commit J &&
+
+ git switch -c next main &&
+ test_commit K &&
+ git merge -m "Merge topic1" topic1 &&
+ git merge -m "Merge topic2" topic2 &&
+ git merge -m "Merge topic3" topic3 &&
+ >evil &&
+ git add evil &&
+ git commit --amend &&
+ git merge -m "Merge topic4" topic4 &&
+
+ git switch main &&
+ test_commit L &&
+ test_commit M &&
+
+ git switch -c conflict B &&
+ test_commit C.conflict C.t conflict
+'
+
+test_expect_success 'setup bare' '
+ git clone --bare . bare
+'
+
+test_expect_success 'using replay to rebase two branches, one on top of other' '
+ git replay --onto main topic1..topic2 >result &&
+
+ test_line_count = 1 result &&
+
+ git log --format=%s $(cut -f 3 -d " " result) >actual &&
+ test_write_lines E D M L B A >expect &&
+ test_cmp expect actual &&
+
+ printf "update refs/heads/topic2 " >expect &&
+ printf "%s " $(cut -f 3 -d " " result) >>expect &&
+ git rev-parse topic2 >>expect &&
+
+ test_cmp expect result
+'
+
+test_expect_success 'using replay on bare repo to rebase two branches, one on top of other' '
+ git -C bare replay --onto main topic1..topic2 >result-bare &&
+ test_cmp expect result-bare
+'
+
+test_expect_success 'using replay to rebase with a conflict' '
+ test_expect_code 1 git replay --onto topic1 B..conflict
+'
+
+test_expect_success 'using replay on bare repo to rebase with a conflict' '
+ test_expect_code 1 git -C bare replay --onto topic1 B..conflict
+'
+
+test_expect_success 'using replay to perform basic cherry-pick' '
+ # The differences between this test and previous ones are:
+ # --advance vs --onto
+ # 2nd field of result is refs/heads/main vs. refs/heads/topic2
+ # 4th field of result is hash for main instead of hash for topic2
+
+ git replay --advance main topic1..topic2 >result &&
+
+ test_line_count = 1 result &&
+
+ git log --format=%s $(cut -f 3 -d " " result) >actual &&
+ test_write_lines E D M L B A >expect &&
+ test_cmp expect actual &&
+
+ printf "update refs/heads/main " >expect &&
+ printf "%s " $(cut -f 3 -d " " result) >>expect &&
+ git rev-parse main >>expect &&
+
+ test_cmp expect result
+'
+
+test_expect_success 'using replay on bare repo to perform basic cherry-pick' '
+ git -C bare replay --advance main topic1..topic2 >result-bare &&
+ test_cmp expect result-bare
+'
+
+test_expect_success 'replay on bare repo fails with both --advance and --onto' '
+ test_must_fail git -C bare replay --advance main --onto main topic1..topic2 >result-bare
+'
+
+test_expect_success 'replay fails when both --advance and --onto are omitted' '
+ test_must_fail git replay topic1..topic2 >result
+'
+
+test_expect_success 'using replay to also rebase a contained branch' '
+ git replay --contained --onto main main..topic3 >result &&
+
+ test_line_count = 2 result &&
+ cut -f 3 -d " " result >new-branch-tips &&
+
+ git log --format=%s $(head -n 1 new-branch-tips) >actual &&
+ test_write_lines F C M L B A >expect &&
+ test_cmp expect actual &&
+
+ git log --format=%s $(tail -n 1 new-branch-tips) >actual &&
+ test_write_lines H G F C M L B A >expect &&
+ test_cmp expect actual &&
+
+ printf "update refs/heads/topic1 " >expect &&
+ printf "%s " $(head -n 1 new-branch-tips) >>expect &&
+ git rev-parse topic1 >>expect &&
+ printf "update refs/heads/topic3 " >>expect &&
+ printf "%s " $(tail -n 1 new-branch-tips) >>expect &&
+ git rev-parse topic3 >>expect &&
+
+ test_cmp expect result
+'
+
+test_expect_success 'using replay on bare repo to also rebase a contained branch' '
+ git -C bare replay --contained --onto main main..topic3 >result-bare &&
+ test_cmp expect result-bare
+'
+
+test_expect_success 'using replay to rebase multiple divergent branches' '
+ git replay --onto main ^topic1 topic2 topic4 >result &&
+
+ test_line_count = 2 result &&
+ cut -f 3 -d " " result >new-branch-tips &&
+
+ git log --format=%s $(head -n 1 new-branch-tips) >actual &&
+ test_write_lines E D M L B A >expect &&
+ test_cmp expect actual &&
+
+ git log --format=%s $(tail -n 1 new-branch-tips) >actual &&
+ test_write_lines J I M L B A >expect &&
+ test_cmp expect actual &&
+
+ printf "update refs/heads/topic2 " >expect &&
+ printf "%s " $(head -n 1 new-branch-tips) >>expect &&
+ git rev-parse topic2 >>expect &&
+ printf "update refs/heads/topic4 " >>expect &&
+ printf "%s " $(tail -n 1 new-branch-tips) >>expect &&
+ git rev-parse topic4 >>expect &&
+
+ test_cmp expect result
+'
+
+test_expect_success 'using replay on bare repo to rebase multiple divergent branches, including contained ones' '
+ git -C bare replay --contained --onto main ^main topic2 topic3 topic4 >result &&
+
+ test_line_count = 4 result &&
+ cut -f 3 -d " " result >new-branch-tips &&
+
+ >expect &&
+ for i in 2 1 3 4
+ do
+ printf "update refs/heads/topic$i " >>expect &&
+ printf "%s " $(grep topic$i result | cut -f 3 -d " ") >>expect &&
+ git -C bare rev-parse topic$i >>expect || return 1
+ done &&
+
+ test_cmp expect result &&
+
+ test_write_lines F C M L B A >expect1 &&
+ test_write_lines E D C M L B A >expect2 &&
+ test_write_lines H G F C M L B A >expect3 &&
+ test_write_lines J I M L B A >expect4 &&
+
+ for i in 1 2 3 4
+ do
+ git -C bare log --format=%s $(grep topic$i result | cut -f 3 -d " ") >actual &&
+ test_cmp expect$i actual || return 1
+ done
+'
+
+test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 7623689da2..4c543a1a7e 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -5,7 +5,6 @@
test_description='Test of git add, including the -- option.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-unique-files.sh
@@ -28,6 +27,16 @@ test_expect_success 'Test of git add' '
touch foo && git add foo
'
+test_expect_success 'Test with no pathspecs' '
+ cat >expect <<-EOF &&
+ Nothing specified, nothing added.
+ hint: Maybe you wanted to say ${SQ}git add .${SQ}?
+ hint: Disable this message with "git config advice.addEmptyPathspec false"
+ EOF
+ git add 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'Post-check that foo is in the index' '
git ls-files foo | grep foo
'
@@ -339,6 +348,40 @@ test_expect_success '"git add ." in empty repo' '
)
'
+test_expect_success '"git add" a embedded repository' '
+ rm -fr outer && git init outer &&
+ (
+ cd outer &&
+ for i in 1 2
+ do
+ name=inner$i &&
+ git init $name &&
+ git -C $name commit --allow-empty -m $name ||
+ return 1
+ done &&
+ git add . 2>actual &&
+ cat >expect <<-EOF &&
+ warning: adding embedded git repository: inner1
+ hint: You${SQ}ve added another git repository inside your current repository.
+ hint: Clones of the outer repository will not contain the contents of
+ hint: the embedded repository and will not know how to obtain it.
+ hint: If you meant to add a submodule, use:
+ hint:
+ hint: git submodule add <url> inner1
+ hint:
+ hint: If you added this path by mistake, you can remove it from the
+ hint: index with:
+ hint:
+ hint: git rm --cached inner1
+ hint:
+ hint: See "git help submodule" for more information.
+ hint: Disable this message with "git config advice.addEmbeddedRepo false"
+ warning: adding embedded git repository: inner2
+ EOF
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'error on a repository with no commits' '
rm -fr empty &&
git init empty &&
@@ -370,8 +413,7 @@ cat >expect.err <<\EOF
The following paths are ignored by one of your .gitignore files:
ignored-file
hint: Use -f if you really want to add them.
-hint: Turn this message off by running
-hint: "git config advice.addIgnoredFile false"
+hint: Disable this message with "git config advice.addIgnoredFile false"
EOF
cat >expect.out <<\EOF
add 'track-this'
@@ -438,7 +480,7 @@ test_expect_success 'git add --chmod fails with non regular files (but updates t
test_ln_s_add foo foo3 &&
touch foo4 &&
test_must_fail git add --chmod=+x foo3 foo4 2>stderr &&
- test_i18ngrep "cannot chmod +x .foo3." stderr &&
+ test_grep "cannot chmod +x .foo3." stderr &&
test_mode_in_index 120000 foo3 &&
test_mode_in_index 100755 foo4
'
@@ -455,12 +497,12 @@ test_expect_success 'git add --chmod --dry-run reports error for non regular fil
git reset --hard &&
test_ln_s_add foo foo4 &&
test_must_fail git add --chmod=+x --dry-run foo4 2>stderr &&
- test_i18ngrep "cannot chmod +x .foo4." stderr
+ test_grep "cannot chmod +x .foo4." stderr
'
test_expect_success 'git add --chmod --dry-run reports error for unmatched pathspec' '
test_must_fail git add --chmod=+x --dry-run nonexistent 2>stderr &&
- test_i18ngrep "pathspec .nonexistent. did not match any files" stderr
+ test_grep "pathspec .nonexistent. did not match any files" stderr
'
test_expect_success 'no file status change if no pathspec is given' '
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 34aabb7f5f..b8a05d95f3 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -7,6 +7,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
+SP=" "
+
diff_cmp () {
for x
do
@@ -40,19 +42,17 @@ force_color () {
)
}
-test_expect_success 'warn about add.interactive.useBuiltin' '
- cat >expect <<-\EOF &&
- warning: the add.interactive.useBuiltin setting has been removed!
- See its entry in '\''git help config'\'' for details.
- No changes.
+test_expect_success 'unknown command' '
+ test_when_finished "git reset --hard; rm -f command" &&
+ echo W >command &&
+ git add -N command &&
+ git diff command >expect &&
+ cat >>expect <<-EOF &&
+ (1/1) Stage addition [y,n,q,a,d,e,p,?]? Unknown command ${SQ}W${SQ} (use ${SQ}?${SQ} for help)
+ (1/1) Stage addition [y,n,q,a,d,e,p,?]?$SP
EOF
-
- for v in = =true =false
- do
- git -c "add.interactive.useBuiltin$v" add -p >out 2>actual &&
- test_must_be_empty out &&
- test_cmp expect actual || return 1
- done
+ git add -p -- command <command >actual 2>&1 &&
+ test_cmp expect actual
'
test_expect_success 'setup (initial)' '
@@ -144,6 +144,14 @@ test_expect_success 'revert works (commit)' '
grep "unchanged *+3/-0 file" output
'
+test_expect_success 'reject multi-key input' '
+ saved=$(git hash-object -w file) &&
+ test_when_finished "git cat-file blob $saved >file" &&
+ echo an extra line >>file &&
+ test_write_lines aa | git add -p >actual &&
+ test_grep "is expected, got ${SQ}aa${SQ}" actual
+'
+
test_expect_success 'setup expected' '
cat >expected <<-\EOF
EOF
@@ -231,7 +239,6 @@ test_expect_success 'setup file' '
'
test_expect_success 'setup patch' '
- SP=" " &&
NULL="" &&
cat >patch <<-EOF
@@ -1,4 +1,4 @@
@@ -325,22 +332,22 @@ test_expect_success 'different prompts for mode change/deleted' '
git -c core.filemode=true add -p >actual &&
sed -n "s/^\(([0-9/]*) Stage .*?\).*/\1/p" actual >actual.filtered &&
cat >expect <<-\EOF &&
- (1/1) Stage deletion [y,n,q,a,d,?]?
- (1/2) Stage mode change [y,n,q,a,d,j,J,g,/,?]?
- (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?
+ (1/1) Stage deletion [y,n,q,a,d,p,?]?
+ (1/2) Stage mode change [y,n,q,a,d,j,J,g,/,p,?]?
+ (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]?
EOF
test_cmp expect actual.filtered
'
test_expect_success 'correct message when there is nothing to do' '
git reset --hard &&
- git add -p 2>err &&
- test_i18ngrep "No changes" err &&
+ git add -p >out &&
+ test_grep "No changes" out &&
printf "\\0123" >binary &&
git add binary &&
printf "\\0abc" >binary &&
- git add -p 2>err &&
- test_i18ngrep "Only binary files changed" err
+ git add -p >out &&
+ test_grep "Only binary files changed" out
'
test_expect_success 'setup again' '
@@ -497,7 +504,7 @@ test_expect_success 'adding an empty file' '
echo y | git checkout -p added-file -- >actual &&
test_path_is_file empty &&
- test_i18ngrep "Apply addition to index and worktree" actual
+ test_grep "Apply addition to index and worktree" actual
)
'
@@ -511,36 +518,110 @@ test_expect_success 'split hunk setup' '
test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
'
-test_expect_success 'goto hunk' '
+test_expect_success 'goto hunk 1 with "g 1"' '
test_when_finished "git reset" &&
tr _ " " >expect <<-EOF &&
- (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? + 1: -1,2 +1,3 +15
+ (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? + 1: -1,2 +1,3 +15
_ 2: -2,4 +3,8 +21
go to which hunk? @@ -1,2 +1,3 @@
_10
+15
_20
- (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
+ (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
EOF
test_write_lines s y g 1 | git add -p >actual &&
tail -n 7 <actual >actual.trimmed &&
test_cmp expect actual.trimmed
'
-test_expect_success 'navigate to hunk via regex' '
+test_expect_success 'goto hunk 1 with "g1"' '
test_when_finished "git reset" &&
tr _ " " >expect <<-EOF &&
- (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@
_10
+15
_20
- (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
+ (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
+ EOF
+ test_write_lines s y g1 | git add -p >actual &&
+ tail -n 4 <actual >actual.trimmed &&
+ test_cmp expect actual.trimmed
+'
+
+test_expect_success 'navigate to hunk via regex /pattern' '
+ test_when_finished "git reset" &&
+ tr _ " " >expect <<-EOF &&
+ (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? @@ -1,2 +1,3 @@
+ _10
+ +15
+ _20
+ (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
EOF
test_write_lines s y /1,2 | git add -p >actual &&
tail -n 5 <actual >actual.trimmed &&
test_cmp expect actual.trimmed
'
+test_expect_success 'navigate to hunk via regex / pattern' '
+ test_when_finished "git reset" &&
+ tr _ " " >expect <<-EOF &&
+ _10
+ +15
+ _20
+ (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
+ EOF
+ test_write_lines s y / 1,2 | git add -p >actual &&
+ tail -n 4 <actual >actual.trimmed &&
+ test_cmp expect actual.trimmed
+'
+
+test_expect_success 'print again the hunk' '
+ test_when_finished "git reset" &&
+ tr _ " " >expect <<-EOF &&
+ +15
+ 20
+ (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? @@ -1,2 +1,3 @@
+ 10
+ +15
+ 20
+ (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
+ EOF
+ test_write_lines s y g 1 p | git add -p >actual &&
+ tail -n 7 <actual >actual.trimmed &&
+ test_cmp expect actual.trimmed
+'
+
+test_expect_success TTY 'print again the hunk (PAGER)' '
+ test_when_finished "git reset" &&
+ cat >expect <<-EOF &&
+ <GREEN>+<RESET><GREEN>15<RESET>
+ 20<RESET>
+ <BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET>
+ PAGER 10<RESET>
+ PAGER <GREEN>+<RESET><GREEN>15<RESET>
+ PAGER 20<RESET>
+ <BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>
+ EOF
+ test_write_lines s y g 1 P |
+ (
+ GIT_PAGER="sed s/^/PAGER\ /" &&
+ export GIT_PAGER &&
+ test_terminal git add -p >actual
+ ) &&
+ tail -n 7 <actual | test_decode_color >actual.trimmed &&
+ test_cmp expect actual.trimmed
+'
+
+test_expect_success TTY 'P handles SIGPIPE when writing to pager' '
+ test_when_finished "rm -f huge_file; git reset" &&
+ printf "\n%2500000s" Y >huge_file &&
+ git add -N huge_file &&
+ test_write_lines P q | (
+ GIT_PAGER="head -n 1" &&
+ export GIT_PAGER &&
+ test_terminal git add -p
+ )
+'
+
test_expect_success 'split hunk "add -p (edit)"' '
# Split, say Edit and do nothing. Then:
#
@@ -715,21 +796,21 @@ test_expect_success 'colors can be overridden' '
<BLUE>+<RESET><BLUE>new<RESET>
<CYAN> more-context<RESET>
<BLUE>+<RESET><BLUE>another-one<RESET>
- <YELLOW>(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? <RESET><BOLD>Split into 2 hunks.<RESET>
+ <YELLOW>(1/1) Stage this hunk [y,n,q,a,d,s,e,p,?]? <RESET><BOLD>Split into 2 hunks.<RESET>
<MAGENTA>@@ -1,3 +1,3 @@<RESET>
<CYAN> context<RESET>
<BOLD>-old<RESET>
<BLUE>+<RESET><BLUE>new<RESET>
<CYAN> more-context<RESET>
- <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET>
+ <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET>
<CYAN> more-context<RESET>
<BLUE>+<RESET><BLUE>another-one<RESET>
- <YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET>
+ <YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET>
<CYAN> context<RESET>
<BOLD>-old<RESET>
<BLUE>+new<RESET>
<CYAN> more-context<RESET>
- <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET>
+ <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>
EOF
test_cmp expect actual
'
@@ -838,7 +919,7 @@ test_expect_success 'diff.algorithm is passed to `git diff-files`' '
git add file &&
echo changed >file &&
test_must_fail git -c diff.algorithm=bogus add -p 2>err &&
- test_i18ngrep "error: option diff-algorithm accepts " err
+ test_grep "error: option diff-algorithm accepts " err
'
test_expect_success 'patch-mode via -i prompts for files' '
@@ -1130,4 +1211,23 @@ test_expect_success 'reset -p with unmerged files' '
test_must_be_empty staged
'
+test_expect_success 'hunk splitting works with diff.suppressBlankEmpty' '
+ test_config diff.suppressBlankEmpty true &&
+ write_script fake-editor.sh <<-\EOF &&
+ tr F G <"$1" >"$1.tmp" &&
+ mv "$1.tmp" "$1"
+ EOF
+
+ test_write_lines a b "" c d "" e f "" >file &&
+ git add file &&
+ test_write_lines A b "" c D "" e F "" >file &&
+ (
+ test_set_editor "$(pwd)/fake-editor.sh" &&
+ test_write_lines s n y e q | git add -p file
+ ) &&
+ git cat-file blob :file >actual &&
+ test_write_lines a b "" c D "" e G "" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh
index 82bfb2fd2a..8bacacbac6 100755
--- a/t/t3702-add-edit.sh
+++ b/t/t3702-add-edit.sh
@@ -5,7 +5,6 @@
test_description='add -e basic tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t3703-add-magic-pathspec.sh b/t/t3703-add-magic-pathspec.sh
index d84071038e..3ef525a559 100755
--- a/t/t3703-add-magic-pathspec.sh
+++ b/t/t3703-add-magic-pathspec.sh
@@ -2,7 +2,6 @@
test_description='magic pathspec tests using git-add'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3704-add-pathspec-file.sh b/t/t3704-add-pathspec-file.sh
index 4e6b5177c9..b9c96e273f 100755
--- a/t/t3704-add-pathspec-file.sh
+++ b/t/t3704-add-pathspec-file.sh
@@ -2,7 +2,6 @@
test_description='add --pathspec-from-file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_tick
@@ -138,23 +137,23 @@ test_expect_success 'error conditions' '
>empty_list &&
test_must_fail git add --pathspec-from-file=list --interactive 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git add --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git add --pathspec-from-file=list --edit 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--edit. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--edit. cannot be used together" err &&
test_must_fail git add --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git add --pathspec-file-nul 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
# This case succeeds, but still prints to stderr
git add --pathspec-from-file=empty_list 2>err &&
- test_i18ngrep -e "Nothing specified, nothing added." err
+ test_grep -e "Nothing specified, nothing added." err
'
test_done
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index d3e428ff46..e3cf0ffbe5 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -4,7 +4,6 @@
test_description='git mktag: tag object verify test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
###########################################################
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index bfab245eb3..3c930ec202 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -7,6 +7,12 @@ test_description='commit and log output encodings'
. ./test-lib.sh
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping commit i18n tests; iconv not available'
+ test_done
+fi
+
compare_with () {
git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' >current &&
case "$3" in
@@ -45,7 +51,7 @@ test_expect_success 'UTF-8 invalid characters refused' '
printf "Commit message\n\nInvalid surrogate:\355\240\200\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- test_i18ngrep "did not conform" "$HOME"/stderr
+ test_grep "did not conform" "$HOME"/stderr
'
test_expect_success 'UTF-8 overlong sequences rejected' '
@@ -55,7 +61,7 @@ test_expect_success 'UTF-8 overlong sequences rejected' '
printf "\340\202\251ommit message\n\nThis is not a space:\300\240\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- test_i18ngrep "did not conform" "$HOME"/stderr
+ test_grep "did not conform" "$HOME"/stderr
'
test_expect_success 'UTF-8 non-characters refused' '
@@ -64,7 +70,7 @@ test_expect_success 'UTF-8 non-characters refused' '
printf "Commit message\n\nNon-character:\364\217\277\276\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- test_i18ngrep "did not conform" "$HOME"/stderr
+ test_grep "did not conform" "$HOME"/stderr
'
test_expect_success 'UTF-8 non-characters refused' '
@@ -73,7 +79,7 @@ test_expect_success 'UTF-8 non-characters refused' '
printf "Commit message\n\nNon-character:\357\267\220\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- test_i18ngrep "did not conform" "$HOME"/stderr
+ test_grep "did not conform" "$HOME"/stderr
'
for H in ISO8859-1 eucJP ISO-2022-JP
diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 4f16a735d9..f03601b49a 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -10,6 +10,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping patch i18n tests; iconv not available'
+ test_done
+fi
+
check_encoding () {
# Make sure characters are not corrupted
cnt="$1" header="$2" i=1 j=0
@@ -298,7 +304,7 @@ test_expect_success 'am --no-utf8 (U/L)' '
# commit-tree will warn that the commit message does not contain valid UTF-8
# as mailinfo did not convert it
- test_i18ngrep "did not conform" err &&
+ test_grep "did not conform" err &&
check_encoding 2
'
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
index 72a5a565e9..f528008c36 100755
--- a/t/t3902-quoted.sh
+++ b/t/t3902-quoted.sh
@@ -5,7 +5,6 @@
test_description='quoted output'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
FN='濱野'
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 0b3dfeaea2..74666ff3e4 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -200,7 +200,7 @@ test_expect_success 'drop stash reflog updates refs/stash' '
test_cmp expect actual
'
-test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' '
+test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
git init repo &&
(
cd repo &&
@@ -213,16 +213,16 @@ test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite'
new_oid="$(git -C repo rev-parse stash@{0})" &&
cat >expect <<-EOF &&
- $(test_oid zero) $old_oid
- $old_oid $new_oid
+ $new_oid
+ $old_oid
EOF
- cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ git -C repo reflog show refs/stash --format=%H >actual &&
test_cmp expect actual &&
git -C repo stash drop stash@{1} &&
- cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ git -C repo reflog show refs/stash --format=%H >actual &&
cat >expect <<-EOF &&
- $(test_oid zero) $new_oid
+ $new_oid
EOF
test_cmp expect actual
'
@@ -393,9 +393,18 @@ test_expect_success 'stash --staged' '
test bar,bar4 = $(cat file),$(cat file2)
'
+test_expect_success 'stash --staged with binary file' '
+ printf "\0" >file &&
+ git add file &&
+ git stash --staged &&
+ git stash pop &&
+ printf "\0" >expect &&
+ test_cmp expect file
+'
+
test_expect_success 'dont assume push with non-option args' '
test_must_fail git stash -q drop 2>err &&
- test_i18ngrep -e "subcommand wasn'\''t specified; '\''push'\'' can'\''t be assumed due to unexpected token '\''drop'\''" err
+ test_grep -e "subcommand wasn'\''t specified; '\''push'\'' can'\''t be assumed due to unexpected token '\''drop'\''" err
'
test_expect_success 'stash --invalid-option' '
@@ -596,7 +605,7 @@ test_expect_success 'giving too many ref arguments does not modify files' '
for type in apply pop "branch stash-branch"
do
test_must_fail git stash $type stash@{0} stash@{1} 2>err &&
- test_i18ngrep "Too many revisions" err &&
+ test_grep "Too many revisions" err &&
test 123456789 = $(test-tool chmtime -g file2) || return 1
done
'
@@ -604,14 +613,14 @@ test_expect_success 'giving too many ref arguments does not modify files' '
test_expect_success 'drop: too many arguments errors out (does nothing)' '
git stash list >expect &&
test_must_fail git stash drop stash@{0} stash@{1} 2>err &&
- test_i18ngrep "Too many revisions" err &&
+ test_grep "Too many revisions" err &&
git stash list >actual &&
test_cmp expect actual
'
test_expect_success 'show: too many arguments errors out (does nothing)' '
test_must_fail git stash show stash@{0} stash@{1} 2>err 1>out &&
- test_i18ngrep "Too many revisions" err &&
+ test_grep "Too many revisions" err &&
test_must_be_empty out
'
@@ -654,7 +663,7 @@ test_expect_success 'stash branch - stashes on stack, stash-like argument' '
test_expect_success 'stash branch complains with no arguments' '
test_must_fail git stash branch 2>err &&
- test_i18ngrep "No branch name specified" err
+ test_grep "No branch name specified" err
'
test_expect_success 'stash show format defaults to --stat' '
@@ -931,6 +940,10 @@ test_expect_success 'store called with invalid commit' '
test_must_fail git stash store foo
'
+test_expect_success 'store called with non-stash commit' '
+ test_must_fail git stash store HEAD
+'
+
test_expect_success 'store updates stash ref and reflog' '
git stash clear &&
git reset --hard &&
@@ -1384,6 +1397,21 @@ test_expect_success 'stash --keep-index with file deleted in index does not resu
test_path_is_missing to-remove
'
+test_expect_success 'stash --keep-index --include-untracked with empty tree' '
+ test_when_finished "rm -rf empty" &&
+ git init empty &&
+ (
+ cd empty &&
+ git commit --allow-empty --message "empty" &&
+ echo content >file &&
+ git stash push --keep-index --include-untracked &&
+ test_path_is_missing file &&
+ git stash pop &&
+ echo content >expect &&
+ test_cmp expect file
+ )
+'
+
test_expect_success 'stash apply should succeed with unmodified file' '
echo base >file &&
git add file &&
@@ -1512,4 +1540,56 @@ test_expect_success 'restore untracked files even when we hit conflicts' '
)
'
+test_expect_success 'stash create reports a locked index' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A A.file &&
+ echo change >A.file &&
+ touch .git/index.lock &&
+
+ cat >expect <<-EOF &&
+ error: could not write index
+ EOF
+ test_must_fail git stash create 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'stash push reports a locked index' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A A.file &&
+ echo change >A.file &&
+ touch .git/index.lock &&
+
+ cat >expect <<-EOF &&
+ error: could not write index
+ EOF
+ test_must_fail git stash push 2>err &&
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'stash apply reports a locked index' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A A.file &&
+ echo change >A.file &&
+ git stash push &&
+ touch .git/index.lock &&
+
+ cat >expect <<-EOF &&
+ error: could not write index
+ EOF
+ test_must_fail git stash apply 2>err &&
+ test_cmp expect err
+ )
+'
+
test_done
diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh
index accfe3845c..ae313e3c70 100755
--- a/t/t3904-stash-patch.sh
+++ b/t/t3904-stash-patch.sh
@@ -1,13 +1,8 @@
#!/bin/sh
test_description='stash -p'
-. ./lib-patch-mode.sh
-if ! test_have_prereq PERL
-then
- skip_all='skipping stash -p tests, perl not available'
- test_done
-fi
+. ./lib-patch-mode.sh
test_expect_success 'setup' '
mkdir dir &&
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index 5390eec4e3..1289ae3e07 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -404,7 +404,7 @@ test_expect_success 'stash show --include-untracked errors on duplicate files' '
) &&
w_commit=$(git commit-tree -p HEAD -p "$i_commit" -p "$u_commit" -m "WIP on any-branch" "$tree") &&
test_must_fail git stash show --include-untracked "$w_commit" 2>err &&
- test_i18ngrep "worktree and untracked commit have duplicate entries: tracked" err
+ test_grep "worktree and untracked commit have duplicate entries: tracked" err
'
test_expect_success 'stash show --{include,only}-untracked on stashes without untracked entries' '
diff --git a/t/t3908-stash-in-worktree.sh b/t/t3908-stash-in-worktree.sh
index 347a89b030..2b2b366ef9 100755
--- a/t/t3908-stash-in-worktree.sh
+++ b/t/t3908-stash-in-worktree.sh
@@ -5,7 +5,6 @@
test_description='Test git stash in a worktree'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3909-stash-pathspec-file.sh b/t/t3909-stash-pathspec-file.sh
index dead9f18d9..73f2dbdeb0 100755
--- a/t/t3909-stash-pathspec-file.sh
+++ b/t/t3909-stash-pathspec-file.sh
@@ -88,13 +88,13 @@ test_expect_success 'error conditions' '
echo fileA.t >list &&
test_must_fail git stash push --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git stash push --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git stash push --pathspec-file-nul 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err
'
test_done
diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh
index 898267a6bd..6d5918c8fe 100755
--- a/t/t3910-mac-os-precompose.sh
+++ b/t/t3910-mac-os-precompose.sh
@@ -37,6 +37,27 @@ Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte
Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte
Alongc=$Alongc$AEligatu$AEligatu #254 Byte
+
+ls_files_nfc_nfd () {
+ test_when_finished "git config --global --unset core.precomposeunicode" &&
+ prglbl=$1
+ prlocl=$2
+ aumlcreat=$3
+ aumllist=$4
+ git config --global core.precomposeunicode $prglbl &&
+ (
+ rm -rf .git &&
+ mkdir -p "somewhere/$prglbl/$prlocl/$aumlcreat" &&
+ mypwd=$PWD &&
+ cd "somewhere/$prglbl/$prlocl/$aumlcreat" &&
+ git init &&
+ git config core.precomposeunicode $prlocl &&
+ git --literal-pathspecs ls-files "$mypwd/somewhere/$prglbl/$prlocl/$aumllist" 2>err &&
+ >expected &&
+ test_cmp expected err
+ )
+}
+
test_expect_success "detect if nfd needed" '
precomposeunicode=$(git config core.precomposeunicode) &&
test "$precomposeunicode" = true &&
@@ -211,8 +232,8 @@ test_expect_success "unicode decomposed: git restore -p . " '
'
# Test if the global core.precomposeunicode stops autosensing
-# Must be the last test case
test_expect_success "respect git config --global core.precomposeunicode" '
+ test_when_finished "git config --global --unset core.precomposeunicode" &&
git config --global core.precomposeunicode true &&
rm -rf .git &&
git init &&
@@ -220,4 +241,20 @@ test_expect_success "respect git config --global core.precomposeunicode" '
test "$precomposeunicode" = "true"
'
+test_expect_success "ls-files false false nfd nfd" '
+ ls_files_nfc_nfd false false $Adiarnfd $Adiarnfd
+'
+
+test_expect_success "ls-files false true nfd nfd" '
+ ls_files_nfc_nfd false true $Adiarnfd $Adiarnfd
+'
+
+test_expect_success "ls-files true false nfd nfd" '
+ ls_files_nfc_nfd true false $Adiarnfd $Adiarnfd
+'
+
+test_expect_success "ls-files true true nfd nfd" '
+ ls_files_nfc_nfd true true $Adiarnfd $Adiarnfd
+'
+
test_done
diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
index 67fd2345af..e2e1251a05 100755
--- a/t/t3920-crlf-messages.sh
+++ b/t/t3920-crlf-messages.sh
@@ -2,7 +2,6 @@
test_description='Test ref-filter and pretty APIs for commit and tag messages using CRLF'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
LIB_CRLF_BRANCHES=""
@@ -10,7 +9,7 @@ LIB_CRLF_BRANCHES=""
create_crlf_ref () {
branch="$1" &&
cat >.crlf-orig-$branch.txt &&
- cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
+ append_cr <.crlf-orig-$branch.txt >.crlf-message-$branch.txt &&
grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&
grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt &&
LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
@@ -82,7 +81,7 @@ test_crlf_subject_body_and_contents() {
test_expect_success 'Setup refs with commit and tag messages using CRLF' '
- test_commit inital &&
+ test_commit initial &&
create_crlf_refs
'
@@ -97,7 +96,7 @@ test_expect_success 'branch: --verbose works with messages using CRLF' '
git branch -v >tmp &&
# Remove first two columns, and the line for the currently checked out branch
current=$(git branch --show-current) &&
- grep -v $current <tmp | awk "{\$1=\$2=\"\"}1" >actual &&
+ awk "/$current/ { next } { \$1 = \$2 = \"\" } 1" <tmp >actual &&
test_cmp expect actual
'
diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh
index 8d50331b8c..a51f881b1c 100755
--- a/t/t4000-diff-format.sh
+++ b/t/t4000-diff-format.sh
@@ -10,7 +10,6 @@ same command line parser, so testing one should be sufficient; pick
diff-files as a representative.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index 3dc9047044..4f520d600d 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -3,9 +3,8 @@
# Copyright (c) 2005 Junio C Hamano
#
-test_description='Test rename detection in diff engine.
+test_description='Test rename detection in diff engine.'
-'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
@@ -135,25 +134,25 @@ test_expect_success 'favour same basenames over different ones' '
mkdir subdir &&
git mv another-path subdir/path1 &&
git status >out &&
- test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+ test_grep "renamed: .*path1 -> subdir/path1" out
'
test_expect_success 'test diff.renames=true for git status' '
git -c diff.renames=true status >out &&
- test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+ test_grep "renamed: .*path1 -> subdir/path1" out
'
test_expect_success 'test diff.renames=false for git status' '
git -c diff.renames=false status >out &&
- test_i18ngrep ! "renamed: .*path1 -> subdir/path1" out &&
- test_i18ngrep "new file: .*subdir/path1" out &&
- test_i18ngrep "deleted: .*[^/]path1" out
+ test_grep ! "renamed: .*path1 -> subdir/path1" out &&
+ test_grep "new file: .*subdir/path1" out &&
+ test_grep "deleted: .*[^/]path1" out
'
test_expect_success 'favour same basenames even with minor differences' '
git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
git status >out &&
- test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+ test_grep "renamed: .*path1 -> subdir/path1" out
'
test_expect_success 'two files with same basename and same content' '
@@ -165,7 +164,7 @@ test_expect_success 'two files with same basename and same content' '
git commit -m 2 &&
git mv dir other-dir &&
git status >out &&
- test_i18ngrep "renamed: .*dir/A/file -> other-dir/A/file" out
+ test_grep "renamed: .*dir/A/file -> other-dir/A/file" out
'
test_expect_success 'setup for many rename source candidates' '
@@ -202,9 +201,9 @@ test_expect_success 'rename pretty print with nothing in common' '
git mv a/b/c c/b/a &&
git commit -m "a/b/c -> c/b/a" &&
git diff -M --summary HEAD^ HEAD >output &&
- test_i18ngrep " a/b/c => c/b/a " output &&
+ test_grep " a/b/c => c/b/a " output &&
git diff -M --stat HEAD^ HEAD >output &&
- test_i18ngrep " a/b/c => c/b/a " output
+ test_grep " a/b/c => c/b/a " output
'
test_expect_success 'rename pretty print with common prefix' '
@@ -212,9 +211,9 @@ test_expect_success 'rename pretty print with common prefix' '
git mv c/b/a c/d/e &&
git commit -m "c/b/a -> c/d/e" &&
git diff -M --summary HEAD^ HEAD >output &&
- test_i18ngrep " c/{b/a => d/e} " output &&
+ test_grep " c/{b/a => d/e} " output &&
git diff -M --stat HEAD^ HEAD >output &&
- test_i18ngrep " c/{b/a => d/e} " output
+ test_grep " c/{b/a => d/e} " output
'
test_expect_success 'rename pretty print with common suffix' '
@@ -222,9 +221,9 @@ test_expect_success 'rename pretty print with common suffix' '
git mv c/d/e d/e &&
git commit -m "c/d/e -> d/e" &&
git diff -M --summary HEAD^ HEAD >output &&
- test_i18ngrep " {c/d => d}/e " output &&
+ test_grep " {c/d => d}/e " output &&
git diff -M --stat HEAD^ HEAD >output &&
- test_i18ngrep " {c/d => d}/e " output
+ test_grep " {c/d => d}/e " output
'
test_expect_success 'rename pretty print with common prefix and suffix' '
@@ -232,9 +231,9 @@ test_expect_success 'rename pretty print with common prefix and suffix' '
git mv d/e d/f/e &&
git commit -m "d/e -> d/f/e" &&
git diff -M --summary HEAD^ HEAD >output &&
- test_i18ngrep " d/{ => f}/e " output &&
+ test_grep " d/{ => f}/e " output &&
git diff -M --stat HEAD^ HEAD >output &&
- test_i18ngrep " d/{ => f}/e " output
+ test_grep " d/{ => f}/e " output
'
test_expect_success 'rename pretty print common prefix and suffix overlap' '
@@ -242,9 +241,9 @@ test_expect_success 'rename pretty print common prefix and suffix overlap' '
git mv d/f/e d/f/f/e &&
git commit -m "d/f/e d/f/f/e" &&
git diff -M --summary HEAD^ HEAD >output &&
- test_i18ngrep " d/f/{ => f}/e " output &&
+ test_grep " d/f/{ => f}/e " output &&
git diff -M --stat HEAD^ HEAD >output &&
- test_i18ngrep " d/f/{ => f}/e " output
+ test_grep " d/f/{ => f}/e " output
'
test_expect_success 'diff-tree -l0 defaults to a big rename limit, not zero' '
@@ -286,4 +285,28 @@ test_expect_success 'basename similarity vs best similarity' '
test_cmp expected actual
'
+test_expect_success 'last line matters too' '
+ {
+ test_write_lines a 0 1 2 3 4 5 6 7 8 9 &&
+ printf "git ignores final up to 63 characters if not newline terminated"
+ } >no-final-lf &&
+ git add no-final-lf &&
+ git commit -m "original version of file with no final newline" &&
+
+ # Change ONLY the first character of the whole file
+ {
+ test_write_lines b 0 1 2 3 4 5 6 7 8 9 &&
+ printf "git ignores final up to 63 characters if not newline terminated"
+ } >no-final-lf &&
+ git add no-final-lf &&
+ git mv no-final-lf still-absent-final-lf &&
+ git commit -a -m "rename no-final-lf -> still-absent-final-lf" &&
+ git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
+ sed -e "s/^R[0-9]* /R /" actual >actual.munged &&
+ cat >expected <<-\EOF &&
+ R no-final-lf still-absent-final-lf
+ EOF
+ test_cmp expected actual.munged
+'
+
test_done
diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh
index 7afc883ec3..e44648e6f3 100755
--- a/t/t4002-diff-basic.sh
+++ b/t/t4002-diff-basic.sh
@@ -7,7 +7,6 @@ test_description='Test diff raw-output.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree-m-3way.sh
@@ -405,7 +404,7 @@ test_expect_success 'diff-tree -r B A == diff-tree -r -R A 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 &&
+ sed "/^index/d; s#/-#/NN#" >.test-a &&
test_must_fail git diff --no-index -- MN NN |
grep -v "^index" >.test-b &&
test_cmp .test-a .test-b
diff --git a/t/t4003-diff-rename-1.sh b/t/t4003-diff-rename-1.sh
index ebe091828c..fd4faee5d2 100755
--- a/t/t4003-diff-rename-1.sh
+++ b/t/t4003-diff-rename-1.sh
@@ -7,7 +7,6 @@ test_description='More rename detection
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh
index 1d70d4d221..faf3465deb 100755
--- a/t/t4004-diff-rename-symlink.sh
+++ b/t/t4004-diff-rename-symlink.sh
@@ -10,7 +10,6 @@ copy of symbolic links, but should not produce rename/copy followed
by an edit for them.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
diff --git a/t/t4005-diff-rename-2.sh b/t/t4005-diff-rename-2.sh
index 5c756dc243..92d1141fbe 100755
--- a/t/t4005-diff-rename-2.sh
+++ b/t/t4005-diff-rename-2.sh
@@ -6,7 +6,6 @@
test_description='Same rename detection as t4003 but testing diff-raw.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index dbd4c0da21..2299b91fc4 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -7,7 +7,6 @@ test_description='Test mode change diffs.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
sed_script='s/\(:100644 100755\) \('"$OID_REGEX"'\) \2 /\1 X X /'
diff --git a/t/t4007-rename-3.sh b/t/t4007-rename-3.sh
index b86165cbac..e8faf0dd2e 100755
--- a/t/t4007-rename-3.sh
+++ b/t/t4007-rename-3.sh
@@ -7,7 +7,6 @@ test_description='Rename interaction with pathspec.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh
index 562aaf3a2a..c187c52dab 100755
--- a/t/t4008-diff-break-rewrite.sh
+++ b/t/t4008-diff-break-rewrite.sh
@@ -21,6 +21,7 @@ With -B, this should be detected as two complete rewrites.
Further, with -B and -M together, these should turn into two renames.
'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t4009-diff-rename-4.sh b/t/t4009-diff-rename-4.sh
index 3480781dab..59e71e3acd 100755
--- a/t/t4009-diff-rename-4.sh
+++ b/t/t4009-diff-rename-4.sh
@@ -7,7 +7,6 @@ test_description='Same rename detection as t4003 but testing diff-raw -z.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh
index 9d9650eba7..c84c3fa05b 100755
--- a/t/t4010-diff-pathspec.sh
+++ b/t/t4010-diff-pathspec.sh
@@ -10,7 +10,6 @@ Prepare:
path1/file1
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh
index d7a5f7ae78..ac837b6c9e 100755
--- a/t/t4011-diff-symlink.sh
+++ b/t/t4011-diff-symlink.sh
@@ -7,19 +7,18 @@ test_description='Test diff of symlinks.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
# Print the short OID of a symlink with the given name.
symlink_oid () {
- local oid=$(printf "%s" "$1" | git hash-object --stdin) &&
+ local oid="$(printf "%s" "$1" | git hash-object --stdin)" &&
git rev-parse --short "$oid"
}
# Print the short OID of the given file.
short_oid () {
- local oid=$(git hash-object "$1") &&
+ local oid="$(git hash-object "$1")" &&
git rev-parse --short "$oid"
}
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index c64d9d2f40..d1d30ac2a9 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -6,7 +6,6 @@
test_description='Binary diff and apply
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >expect.binary-numstat <<\EOF
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 5de1d19075..3855d68dbc 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -178,32 +178,29 @@ process_diffs () {
V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g')
while read magic cmd
do
- status=success
case "$magic" in
'' | '#'*)
continue ;;
- :*)
- magic=${magic#:}
+ :noellipses)
+ magic=noellipses
label="$magic-$cmd"
- case "$magic" in
- noellipses) ;;
- failure)
- status=failure
- magic=
- label="$cmd" ;;
- *)
- BUG "unknown magic $magic" ;;
- esac ;;
+ ;;
+ :*)
+ BUG "unknown magic $magic"
+ ;;
*)
- cmd="$magic $cmd" magic=
- label="$cmd" ;;
+ cmd="$magic $cmd"
+ magic=
+ label="$cmd"
+ ;;
esac
+
test=$(echo "$label" | sed -e 's|[/ ][/ ]*|_|g')
pfx=$(printf "%04d" $test_count)
expect="$TEST_DIRECTORY/t4013/diff.$test"
actual="$pfx-diff.$test"
- test_expect_$status "git $cmd # magic is ${magic:-(not used)}" '
+ test_expect_success "git $cmd # magic is ${magic:-(not used)}" '
{
echo "$ git $cmd"
case "$magic" in
@@ -473,6 +470,14 @@ test_expect_success 'log --diff-merges=on matches --diff-merges=separate' '
test_cmp expected actual
'
+test_expect_success 'log --dd matches --diff-merges=1 -p' '
+ git log --diff-merges=1 -p master >result &&
+ process_diffs result >expected &&
+ git log --dd master >result &&
+ process_diffs result >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'deny wrong log.diffMerges config' '
test_config log.diffMerges wrong-value &&
test_expect_code 128 git log
@@ -514,7 +519,7 @@ test_expect_success 'log -S requires an argument' '
'
test_expect_success 'diff --cached on unborn branch' '
- echo ref: refs/heads/unborn >.git/HEAD &&
+ git symbolic-ref HEAD refs/heads/unborn &&
git diff --cached >result &&
process_diffs result >actual &&
process_diffs "$TEST_DIRECTORY/t4013/diff.diff_--cached" >expected &&
@@ -613,7 +618,7 @@ test_expect_success 'diff -I<regex> --stat' '
test_expect_success 'diff -I<regex>: detect malformed regex' '
test_expect_code 129 git diff --ignore-matching-lines="^[124-9" 2>error &&
- test_i18ngrep "invalid regex given to -I: " error
+ test_grep "invalid regex given to -I: " error
'
# check_prefix <patch> <src> <dst>
@@ -628,8 +633,8 @@ check_prefix () {
test_cmp expect actual.paths
}
-test_expect_success 'diff-files does not respect diff.noprefix' '
- git -c diff.noprefix diff-files -p >actual &&
+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
'
@@ -638,24 +643,65 @@ test_expect_success 'diff-files respects --no-prefix' '
check_prefix actual file0 file0
'
-test_expect_success 'diff respects diff.noprefix' '
- git -c diff.noprefix diff >actual &&
+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 &&
+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 &&
+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 &&
+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_expect_success 'diff respects diff.srcPrefix' '
+ git -c diff.srcPrefix=x/ diff >actual &&
+ check_prefix actual x/file0 b/file0
+'
+
+test_expect_success 'diff respects diff.dstPrefix' '
+ git -c diff.dstPrefix=y/ diff >actual &&
+ check_prefix actual a/file0 y/file0
+'
+
+test_expect_success 'diff --src-prefix overrides diff.srcPrefix' '
+ git -c diff.srcPrefix=y/ diff --src-prefix=z/ >actual &&
+ check_prefix actual z/file0 b/file0
+'
+
+test_expect_success 'diff --dst-prefix overrides diff.dstPrefix' '
+ git -c diff.dstPrefix=y/ diff --dst-prefix=z/ >actual &&
+ check_prefix actual a/file0 z/file0
+'
+
+test_expect_success 'diff.{src,dst}Prefix ignored with diff.noPrefix' '
+ git -c diff.dstPrefix=y/ -c diff.srcPrefix=x/ -c diff.noPrefix diff >actual &&
+ check_prefix actual file0 file0
+'
+
+test_expect_success 'diff.{src,dst}Prefix ignored with diff.mnemonicPrefix' '
+ git -c diff.dstPrefix=x/ -c diff.srcPrefix=y/ -c diff.mnemonicPrefix diff >actual &&
+ check_prefix actual i/file0 w/file0
+'
+
+test_expect_success 'diff.{src,dst}Prefix ignored with --default-prefix' '
+ git -c diff.dstPrefix=x/ -c diff.srcPrefix=y/ diff --default-prefix >actual &&
+ check_prefix actual a/file0 b/file0
+'
+
+test_expect_success 'diff --no-renames cannot be abbreviated' '
+ test_expect_code 129 git diff --no-rename >actual 2>error &&
+ test_must_be_empty actual &&
+ grep "invalid option: --no-rename" error
+'
+
test_done
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 3cf2b7a7fb..884f83fb8a 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -820,8 +820,8 @@ test_expect_success 'format-patch --notes --signoff' '
'
test_expect_success 'format-patch notes output control' '
+ test_when_finished "git notes remove HEAD || :" &&
git notes add -m "notes config message" HEAD &&
- test_when_finished git notes remove HEAD &&
git format-patch -1 --stdout >out &&
! grep "notes config message" out &&
@@ -848,10 +848,10 @@ test_expect_success 'format-patch notes output control' '
'
test_expect_success 'format-patch with multiple notes refs' '
+ test_when_finished "git notes --ref note1 remove HEAD;
+ git notes --ref note2 remove HEAD || :" &&
git notes --ref note1 add -m "this is note 1" HEAD &&
- test_when_finished git notes --ref note1 remove HEAD &&
git notes --ref note2 add -m "this is note 2" HEAD &&
- test_when_finished git notes --ref note2 remove HEAD &&
git format-patch -1 --stdout >out &&
! grep "this is note 1" out &&
@@ -892,10 +892,10 @@ test_expect_success 'format-patch with multiple notes refs' '
test_expect_success 'format-patch with multiple notes refs in config' '
test_when_finished "test_unconfig format.notes" &&
+ test_when_finished "git notes --ref note1 remove HEAD;
+ git notes --ref note2 remove HEAD || :" &&
git notes --ref note1 add -m "this is note 1" HEAD &&
- test_when_finished git notes --ref note1 remove HEAD &&
git notes --ref note2 add -m "this is note 2" HEAD &&
- test_when_finished git notes --ref note2 remove HEAD &&
git config format.notes note1 &&
git format-patch -1 --stdout >out &&
@@ -1368,15 +1368,82 @@ test_expect_success 'empty subject prefix does not have extra space' '
test_cmp expect actual
'
-test_expect_success '--rfc' '
+test_expect_success '--rfc and --no-rfc' '
cat >expect <<-\EOF &&
Subject: [RFC PATCH 1/1] header with . in it
EOF
git format-patch -n -1 --stdout --rfc >patch &&
- grep ^Subject: patch >actual &&
+ grep "^Subject:" patch >actual &&
+ test_cmp expect actual &&
+ git format-patch -n -1 --stdout --rfc --no-rfc >patch &&
+ sed -e "s/RFC //" expect >expect-raw &&
+ grep "^Subject:" patch >actual &&
+ test_cmp expect-raw actual
+'
+
+test_expect_success '--rfc=WIP and --rfc=' '
+ cat >expect <<-\EOF &&
+ Subject: [WIP PATCH 1/1] header with . in it
+ EOF
+ git format-patch -n -1 --stdout --rfc=WIP >patch &&
+ grep "^Subject:" patch >actual &&
+ test_cmp expect actual &&
+ git format-patch -n -1 --stdout --rfc --rfc= >patch &&
+ sed -e "s/WIP //" expect >expect-raw &&
+ grep "^Subject:" patch >actual &&
+ test_cmp expect-raw actual
+'
+
+test_expect_success '--rfc=-(WIP) appends' '
+ cat >expect <<-\EOF &&
+ Subject: [PATCH (WIP) 1/1] header with . in it
+ EOF
+ git format-patch -n -1 --stdout --rfc="-(WIP)" >patch &&
+ grep "^Subject:" patch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--rfc does not overwrite prefix' '
+ cat >expect <<-\EOF &&
+ Subject: [RFC PATCH foobar 1/1] header with . in it
+ EOF
+ git -c format.subjectPrefix="PATCH foobar" \
+ format-patch -n -1 --stdout --rfc >patch &&
+ grep "^Subject:" patch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--rfc is argument order independent' '
+ cat >expect <<-\EOF &&
+ Subject: [RFC PATCH foobar 1/1] header with . in it
+ EOF
+ git format-patch -n -1 --stdout --rfc \
+ --subject-prefix="PATCH foobar" >patch &&
+ grep "^Subject:" patch >actual &&
test_cmp expect actual
'
+test_expect_success '--subject-prefix="<non-empty>" and -k cannot be used together' '
+ echo "fatal: options '\''--subject-prefix/--rfc'\'' and '\''-k'\'' cannot be used together" >expect.err &&
+ test_must_fail git format-patch -1 --stdout --subject-prefix="MYPREFIX" -k >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect.err actual.err
+'
+
+test_expect_success '--subject-prefix="" and -k cannot be used together' '
+ echo "fatal: options '\''--subject-prefix/--rfc'\'' and '\''-k'\'' cannot be used together" >expect.err &&
+ test_must_fail git format-patch -1 --stdout --subject-prefix="" -k >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect.err actual.err
+'
+
+test_expect_success '--rfc and -k cannot be used together' '
+ echo "fatal: options '\''--subject-prefix/--rfc'\'' and '\''-k'\'' cannot be used together" >expect.err &&
+ test_must_fail git format-patch -1 --stdout --rfc -k >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect.err actual.err
+'
+
test_expect_success '--from=ident notices bogus ident' '
test_must_fail git format-patch -1 --stdout --from=foo >patch
'
@@ -1886,6 +1953,16 @@ body" &&
grep "^body$" actual
'
+test_expect_success 'cover letter with --cover-from-description subject (UTF-8 subject line)' '
+ test_config branch.rebuild-1.description "Café?
+
+body" &&
+ git checkout rebuild-1 &&
+ git format-patch --stdout --cover-letter --cover-from-description subject --encode-email-headers main >actual &&
+ grep "^Subject: \[PATCH 0/2\] =?UTF-8?q?Caf=C3=A9=3F?=$" actual &&
+ ! grep "Café" actual
+'
+
test_expect_success 'cover letter with format.coverFromDescription = auto (short subject line)' '
test_config branch.rebuild-1.description "config subject
@@ -1991,6 +2068,20 @@ test_expect_success 'cover letter using branch description (6)' '
grep hello actual
'
+test_expect_success 'cover letter with --description-file' '
+ test_when_finished "rm -f description.txt" &&
+ cat >description.txt <<-\EOF &&
+ subject from file
+
+ body from file
+ EOF
+ git checkout rebuild-1 &&
+ git format-patch --stdout --cover-letter --cover-from-description auto \
+ --description-file description.txt main >actual &&
+ grep "^Subject: \[PATCH 0/2\] subject from file$" actual &&
+ grep "^body from file$" actual
+'
+
test_expect_success 'cover letter with nothing' '
git format-patch --stdout --cover-letter >actual &&
test_line_count = 0 actual
@@ -2369,38 +2460,77 @@ test_expect_success 'interdiff: cover-letter' '
--q
EOF
git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
- test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
- test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
+ test_grep "^Interdiff:$" 0000-cover-letter.patch &&
+ test_grep ! "^Interdiff:$" 0001-fleep.patch &&
sed "1,/^@@ /d; /^-- $/q" 0000-cover-letter.patch >actual &&
test_cmp expect actual
'
test_expect_success 'interdiff: reroll-count' '
git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
- test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
+ test_grep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
'
test_expect_success 'interdiff: reroll-count with a non-integer' '
git format-patch --cover-letter --interdiff=boop~2 -v2.2 -1 boop &&
- test_i18ngrep "^Interdiff:$" v2.2-0000-cover-letter.patch
+ test_grep "^Interdiff:$" v2.2-0000-cover-letter.patch
'
test_expect_success 'interdiff: reroll-count with a integer' '
git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
- test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
+ test_grep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
'
test_expect_success 'interdiff: solo-patch' '
- cat >expect <<-\EOF &&
- +fleep
-
- EOF
git format-patch --interdiff=boop~2 -1 boop &&
- test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
- sed "1,/^ @@ /d; /^$/q" 0001-fleep.patch >actual &&
+
+ # remove up to the last "patch" output line,
+ # and remove everything below the signature mark.
+ sed -e "1,/^+fleep\$/d" -e "/^-- /,\$d" 0001-fleep.patch >actual &&
+
+ # fabricate Interdiff output.
+ git diff boop~2 boop >inter &&
+ {
+ echo &&
+ echo "Interdiff:" &&
+ sed -e "s/^/ /" inter
+ } >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'range-diff: solo-patch' '
+ git format-patch --creation-factor=999 \
+ --range-diff=boop~2..boop~1 -1 boop &&
+
+ # remove up to the last "patch" output line,
+ # and remove everything below the signature mark.
+ sed -e "1,/^+fleep\$/d" -e "/^-- /,\$d" 0001-fleep.patch >actual &&
+
+ # fabricate range-diff output.
+ {
+ echo &&
+ echo "Range-diff:" &&
+ git range-diff --creation-factor=999 \
+ boop~2..boop~1 boop~1..boop
+ } >expect &&
test_cmp expect actual
'
+test_expect_success 'interdiff: multi-patch, implicit --cover-letter' '
+ test_when_finished "rm -f v23-0*.patch" &&
+ git format-patch --interdiff=boop~2 -2 -v23 &&
+ test_grep "^Interdiff against v22:$" v23-0000-cover-letter.patch &&
+ test_cmp expect actual
+'
+
+test_expect_success 'interdiff: explicit --no-cover-letter defeats implied --cover-letter' '
+ test_when_finished "rm -f v23-0*.patch" &&
+ test_must_fail git format-patch --no-cover-letter \
+ --interdiff=boop~2 -2 -v23 &&
+ test_must_fail git -c format.coverLetter=no format-patch \
+ --interdiff=boop~2 -2 -v23
+'
+
test_expect_success 'format-patch does not respect diff.noprefix' '
git -c diff.noprefix format-patch -1 --stdout >actual &&
grep "^--- a/blorp" actual
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index fcd2473e52..52e3e476ff 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -7,7 +7,6 @@ test_description='Test special whitespace in diff engine.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
@@ -946,7 +945,7 @@ test_expect_success 'combined diff with autocrlf conversion' '
git commit -m "the other side" x &&
git config core.autocrlf true &&
test_must_fail git merge one-side >actual &&
- test_i18ngrep "Automatic merge failed" actual &&
+ test_grep "Automatic merge failed" actual &&
git diff >actual.raw &&
sed -e "1,/^@@@/d" actual.raw >actual &&
@@ -1184,6 +1183,15 @@ test_expect_success 'detect moved code, complete file' '
test_cmp expected actual
'
+test_expect_success '--color-moved with --no-ext-diff' '
+ test_config color.diff.oldMoved "yellow" &&
+ test_config color.diff.newMoved "blue" &&
+ args="--color --color-moved=zebra --no-renames HEAD" &&
+ git diff $args >expect &&
+ git -c diff.external=echo diff --no-ext-diff $args >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'detect malicious moved code, inside file' '
test_config color.diff.oldMoved "normal red" &&
test_config color.diff.newMoved "normal green" &&
@@ -2224,27 +2232,27 @@ test_expect_success 'compare whitespace delta across moved blocks' '
test_expect_success 'bogus settings in move detection erroring out' '
test_must_fail git diff --color-moved=bogus 2>err &&
- test_i18ngrep "must be one of" err &&
- test_i18ngrep bogus err &&
+ test_grep "must be one of" err &&
+ test_grep bogus err &&
test_must_fail git -c diff.colormoved=bogus diff 2>err &&
- test_i18ngrep "must be one of" err &&
- test_i18ngrep "from command-line config" err &&
+ test_grep "must be one of" err &&
+ test_grep "from command-line config" err &&
test_must_fail git diff --color-moved-ws=bogus 2>err &&
- test_i18ngrep "possible values" err &&
- test_i18ngrep bogus err &&
+ test_grep "possible values" err &&
+ test_grep bogus err &&
test_must_fail git -c diff.colormovedws=bogus diff 2>err &&
- test_i18ngrep "possible values" err &&
- test_i18ngrep "from command-line config" err
+ test_grep "possible values" err &&
+ test_grep "from command-line config" err
'
test_expect_success 'compare whitespace delta incompatible with other space options' '
test_must_fail git diff \
--color-moved-ws=allow-indentation-change,ignore-all-space \
2>err &&
- test_i18ngrep allow-indentation-change err
+ test_grep allow-indentation-change err
'
EMPTY=''
diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh
index 5a8d887683..876271d682 100755
--- a/t/t4016-diff-quote.sh
+++ b/t/t4016-diff-quote.sh
@@ -6,7 +6,6 @@
test_description='Quoting paths in diff output.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
P0='pathname'
diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh
index f439f469bd..c2863c99b7 100755
--- a/t/t4017-diff-retval.sh
+++ b/t/t4017-diff-retval.sh
@@ -5,7 +5,6 @@ test_description='Return value of diffs'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -143,4 +142,49 @@ test_expect_success 'option errors are not confused by --exit-code' '
grep '^usage:' err
'
+for option in --exit-code --quiet
+do
+ test_expect_success "git diff $option returns 1 for changed binary file" "
+ test_when_finished 'rm -f .gitattributes' &&
+ git reset --hard &&
+ echo a binary >.gitattributes &&
+ echo 2 >>a &&
+ test_expect_code 1 git diff $option
+ "
+
+ test_expect_success "git diff $option returns 1 for copied file" "
+ git reset --hard &&
+ cp a copy &&
+ git add copy &&
+ test_expect_code 1 git diff $option --cached --find-copies-harder
+ "
+
+ test_expect_success "git diff $option returns 1 for renamed file" "
+ git reset --hard &&
+ git mv a renamed &&
+ test_expect_code 1 git diff $option --cached
+ "
+done
+
+test_expect_success 'setup dirty subrepo' '
+ git reset --hard &&
+ test_create_repo subrepo &&
+ test_commit -C subrepo subrepo-file &&
+ test_tick &&
+ git add subrepo &&
+ git commit -m subrepo &&
+ test_commit -C subrepo another-subrepo-file
+'
+
+for option in --exit-code --quiet
+do
+ for submodule_format in diff log short
+ do
+ opts="$option --submodule=$submodule_format" &&
+ test_expect_success "git diff $opts returns 1 for dirty subrepo" "
+ test_expect_code 1 git diff $opts
+ "
+ done
+done
+
test_done
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index c8d555771d..e026fac1f4 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -53,15 +53,15 @@ do
echo "*.java diff=$p" >.gitattributes &&
test_expect_code 1 git diff --no-index \
A.java B.java 2>msg &&
- test_i18ngrep ! fatal msg &&
- test_i18ngrep ! error msg
+ test_grep ! fatal msg &&
+ test_grep ! error msg
'
test_expect_success "builtin $p wordRegex pattern compiles" '
echo "*.java diff=$p" >.gitattributes &&
test_expect_code 1 git diff --no-index --word-diff \
A.java B.java 2>msg &&
- test_i18ngrep ! fatal msg &&
- test_i18ngrep ! error msg
+ test_grep ! fatal msg &&
+ test_grep ! error msg
'
test_expect_success "builtin $p pattern compiles on bare repo with --attr-source" '
@@ -79,8 +79,8 @@ do
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
+ test_grep ! fatal msg &&
+ test_grep ! error msg
'
done
@@ -88,7 +88,7 @@ test_expect_success 'last regexp must not be negated' '
echo "*.java diff=java" >.gitattributes &&
test_config diff.java.funcname "!static" &&
test_expect_code 128 git diff --no-index A.java B.java 2>msg &&
- test_i18ngrep ": Last expression must not be negated:" msg
+ test_grep ": Last expression must not be negated:" msg
'
test_expect_success 'setup hunk header tests' '
diff --git a/t/t4018/csharp-exclude-assignments b/t/t4018/csharp-exclude-assignments
new file mode 100644
index 0000000000..239f312963
--- /dev/null
+++ b/t/t4018/csharp-exclude-assignments
@@ -0,0 +1,20 @@
+class Example
+{
+ string Method(int RIGHT)
+ {
+ var constantAssignment = "test";
+ var methodAssignment = MethodCall();
+ var multiLineMethodAssignment = MethodCall(
+ );
+ var multiLine = "first"
+ + MethodCall()
+ +
+ ( MethodCall()
+ )
+ + MethodCall();
+
+ return "ChangeMe";
+ }
+
+ string MethodCall(int a = 0, int b = 0) => "test";
+}
diff --git a/t/t4018/csharp-exclude-control-statements b/t/t4018/csharp-exclude-control-statements
new file mode 100644
index 0000000000..3a0f404ee1
--- /dev/null
+++ b/t/t4018/csharp-exclude-control-statements
@@ -0,0 +1,34 @@
+class Example
+{
+ string Method(int RIGHT)
+ {
+ if (false)
+ {
+ return "out";
+ }
+ else { }
+ if (true) MethodCall(
+ );
+ else MethodCall(
+ );
+ switch ("test")
+ {
+ case "one":
+ return MethodCall(
+ );
+ case "two":
+ break;
+ }
+ (int, int) tuple = (1, 4);
+ switch (tuple)
+ {
+ case (1, 4):
+ MethodCall();
+ break;
+ }
+
+ return "ChangeMe";
+ }
+
+ string MethodCall(int a = 0, int b = 0) => "test";
+}
diff --git a/t/t4018/csharp-exclude-exceptions b/t/t4018/csharp-exclude-exceptions
new file mode 100644
index 0000000000..b1e64256cf
--- /dev/null
+++ b/t/t4018/csharp-exclude-exceptions
@@ -0,0 +1,29 @@
+using System;
+
+class Example
+{
+ string Method(int RIGHT)
+ {
+ try
+ {
+ throw new Exception("fail");
+ }
+ catch (Exception)
+ {
+ }
+ finally
+ {
+ }
+ try { } catch (Exception) {}
+ try
+ {
+ throw GetException(
+ );
+ }
+ catch (Exception) { }
+
+ return "ChangeMe";
+ }
+
+ Exception GetException() => new Exception("fail");
+}
diff --git a/t/t4018/csharp-exclude-generic-method-calls b/t/t4018/csharp-exclude-generic-method-calls
new file mode 100644
index 0000000000..31af546665
--- /dev/null
+++ b/t/t4018/csharp-exclude-generic-method-calls
@@ -0,0 +1,12 @@
+class Example
+{
+ string Method(int RIGHT)
+ {
+ GenericMethodCall<int, int>(
+ );
+
+ return "ChangeMe";
+ }
+
+ string GenericMethodCall<T, T2>() => "test";
+}
diff --git a/t/t4018/csharp-exclude-init-dispose b/t/t4018/csharp-exclude-init-dispose
new file mode 100644
index 0000000000..2bc8e194e2
--- /dev/null
+++ b/t/t4018/csharp-exclude-init-dispose
@@ -0,0 +1,22 @@
+using System;
+
+class Example : IDisposable
+{
+ string Method(int RIGHT)
+ {
+ new Example();
+ new Example(
+ );
+ new Example { };
+ using (this)
+ {
+ }
+ var def =
+ this is default(
+ Example);
+
+ return "ChangeMe";
+ }
+
+ public void Dispose() {}
+}
diff --git a/t/t4018/csharp-exclude-iterations b/t/t4018/csharp-exclude-iterations
new file mode 100644
index 0000000000..960aa182ae
--- /dev/null
+++ b/t/t4018/csharp-exclude-iterations
@@ -0,0 +1,26 @@
+using System.Linq;
+
+class Example
+{
+ string Method(int RIGHT)
+ {
+ do { } while (true);
+ do MethodCall(
+ ); while (true);
+ while (true);
+ while (true) {
+ break;
+ }
+ for (int i = 0; i < 10; ++i)
+ {
+ }
+ foreach (int i in Enumerable.Range(0, 10))
+ {
+ }
+ int[] numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0];
+
+ return "ChangeMe";
+ }
+
+ string MethodCall(int a = 0, int b = 0) => "test";
+}
diff --git a/t/t4018/csharp-exclude-method-calls b/t/t4018/csharp-exclude-method-calls
new file mode 100644
index 0000000000..51e2dc2040
--- /dev/null
+++ b/t/t4018/csharp-exclude-method-calls
@@ -0,0 +1,20 @@
+class Example
+{
+ string Method(int RIGHT)
+ {
+ MethodCall();
+ MethodCall(1, 2);
+ MethodCall(
+ 1, 2);
+ MethodCall(
+ 1, 2,
+ 3);
+ MethodCall(
+ 1, MethodCall(),
+ 2);
+
+ return "ChangeMe";
+ }
+
+ int MethodCall(int a = 0, int b = 0, int c = 0) => 42;
+}
diff --git a/t/t4018/csharp-exclude-other b/t/t4018/csharp-exclude-other
new file mode 100644
index 0000000000..4d5581cf3e
--- /dev/null
+++ b/t/t4018/csharp-exclude-other
@@ -0,0 +1,18 @@
+class Example
+{
+ string Method(int RIGHT)
+ {
+ lock (this)
+ {
+ }
+ unsafe
+ {
+ byte[] bytes = [1, 2, 3];
+ fixed (byte* pointerToFirst = bytes)
+ {
+ }
+ }
+
+ return "ChangeMe";
+ }
+}
diff --git a/t/t4018/csharp-method b/t/t4018/csharp-method
new file mode 100644
index 0000000000..16b367aca2
--- /dev/null
+++ b/t/t4018/csharp-method
@@ -0,0 +1,10 @@
+class Example
+{
+ string Method(int RIGHT)
+ {
+ // Filler
+ // Filler
+
+ return "ChangeMe";
+ }
+}
diff --git a/t/t4018/csharp-method-array b/t/t4018/csharp-method-array
new file mode 100644
index 0000000000..1126de8201
--- /dev/null
+++ b/t/t4018/csharp-method-array
@@ -0,0 +1,10 @@
+class Example
+{
+ string[] Method(int RIGHT)
+ {
+ // Filler
+ // Filler
+
+ return ["ChangeMe"];
+ }
+}
diff --git a/t/t4018/csharp-method-explicit b/t/t4018/csharp-method-explicit
new file mode 100644
index 0000000000..5a710116cc
--- /dev/null
+++ b/t/t4018/csharp-method-explicit
@@ -0,0 +1,12 @@
+using System;
+
+class Example : IDisposable
+{
+ void IDisposable.Dispose() // RIGHT
+ {
+ // Filler
+ // Filler
+
+ // ChangeMe
+ }
+}
diff --git a/t/t4018/csharp-method-generics b/t/t4018/csharp-method-generics
new file mode 100644
index 0000000000..b3216bfb2a
--- /dev/null
+++ b/t/t4018/csharp-method-generics
@@ -0,0 +1,11 @@
+class Example<T1, T2>
+{
+ Example<int, string> Method<TA, TB>(TA RIGHT, TB b)
+ {
+ // Filler
+ // Filler
+
+ // ChangeMe
+ return null;
+ }
+}
diff --git a/t/t4018/csharp-method-generics-alternate-spaces b/t/t4018/csharp-method-generics-alternate-spaces
new file mode 100644
index 0000000000..9583621743
--- /dev/null
+++ b/t/t4018/csharp-method-generics-alternate-spaces
@@ -0,0 +1,11 @@
+class Example<T1, T2>
+{
+ Example<int,string> Method<TA ,TB>(TA RIGHT, TB b)
+ {
+ // Filler
+ // Filler
+
+ // ChangeMe
+ return null;
+ }
+}
diff --git a/t/t4018/csharp-method-modifiers b/t/t4018/csharp-method-modifiers
new file mode 100644
index 0000000000..caefa8ee99
--- /dev/null
+++ b/t/t4018/csharp-method-modifiers
@@ -0,0 +1,13 @@
+using System.Threading.Tasks;
+
+class Example
+{
+ static internal async Task Method(int RIGHT)
+ {
+ // Filler
+ // Filler
+
+ // ChangeMe
+ await Task.Delay(1);
+ }
+}
diff --git a/t/t4018/csharp-method-multiline b/t/t4018/csharp-method-multiline
new file mode 100644
index 0000000000..3983ff42f5
--- /dev/null
+++ b/t/t4018/csharp-method-multiline
@@ -0,0 +1,10 @@
+class Example
+{
+ string Method_RIGHT(
+ int a,
+ int b,
+ int c)
+ {
+ return "ChangeMe";
+ }
+}
diff --git a/t/t4018/csharp-method-params b/t/t4018/csharp-method-params
new file mode 100644
index 0000000000..3f00410ba1
--- /dev/null
+++ b/t/t4018/csharp-method-params
@@ -0,0 +1,10 @@
+class Example
+{
+ string Method(int RIGHT, int b, int c = 42)
+ {
+ // Filler
+ // Filler
+
+ return "ChangeMe";
+ }
+}
diff --git a/t/t4018/csharp-method-special-chars b/t/t4018/csharp-method-special-chars
new file mode 100644
index 0000000000..e6c7bc01a1
--- /dev/null
+++ b/t/t4018/csharp-method-special-chars
@@ -0,0 +1,11 @@
+class @Some_Type
+{
+ @Some_Type @Method_With_Underscore(int RIGHT)
+ {
+ // Filler
+ // Filler
+
+ // ChangeMe
+ return new @Some_Type();
+ }
+}
diff --git a/t/t4018/csharp-method-with-spacing b/t/t4018/csharp-method-with-spacing
new file mode 100644
index 0000000000..233bb976cc
--- /dev/null
+++ b/t/t4018/csharp-method-with-spacing
@@ -0,0 +1,10 @@
+class Example
+{
+ string Method ( int RIGHT )
+ {
+ // Filler
+ // Filler
+
+ return "ChangeMe";
+ }
+}
diff --git a/t/t4018/csharp-property b/t/t4018/csharp-property
new file mode 100644
index 0000000000..e56dfce34c
--- /dev/null
+++ b/t/t4018/csharp-property
@@ -0,0 +1,11 @@
+class Example
+{
+ public bool RIGHT
+ {
+ get { return true; }
+ set
+ {
+ // ChangeMe
+ }
+ }
+}
diff --git a/t/t4018/csharp-property-braces-same-line b/t/t4018/csharp-property-braces-same-line
new file mode 100644
index 0000000000..608131d3d3
--- /dev/null
+++ b/t/t4018/csharp-property-braces-same-line
@@ -0,0 +1,10 @@
+class Example
+{
+ public bool RIGHT {
+ get { return true; }
+ set
+ {
+ // ChangeMe
+ }
+ }
+}
diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh
index d2b3109c2d..4001dacee3 100755
--- a/t/t4019-diff-wserror.sh
+++ b/t/t4019-diff-wserror.sh
@@ -2,7 +2,6 @@
test_description='diff whitespace error detection'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index c1ac09ecc7..f1efe482a5 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -2,7 +2,6 @@
test_description='external diff interface test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -102,7 +101,7 @@ test_expect_success 'diff attribute' '
test_cmp expect actual
'
-test_expect_success !SANITIZE_LEAK 'diff attribute should apply only to diff' '
+test_expect_success 'diff attribute should apply only to diff' '
git log -p -1 HEAD >out &&
grep "^diff --git a/file b/file" out
@@ -129,7 +128,7 @@ test_expect_success 'diff attribute' '
test_cmp expect actual
'
-test_expect_success !SANITIZE_LEAK 'diff attribute should apply only to diff' '
+test_expect_success 'diff attribute should apply only to diff' '
git log -p -1 HEAD >out &&
grep "^diff --git a/file b/file" out
@@ -172,6 +171,72 @@ test_expect_success 'no diff with -diff' '
grep Binary out
'
+check_external_diff () {
+ expect_code=$1
+ expect_out=$2
+ expect_err=$3
+ command_code=$4
+ trust_exit_code=$5
+ shift 5
+ options="$@"
+
+ command="echo output; exit $command_code;"
+ desc="external diff '$command' with trustExitCode=$trust_exit_code"
+ with_options="${options:+ with }$options"
+
+ test_expect_success "$desc via attribute$with_options" "
+ test_config diff.foo.command \"$command\" &&
+ test_config diff.foo.trustExitCode $trust_exit_code &&
+ echo \"file diff=foo\" >.gitattributes &&
+ test_expect_code $expect_code git diff $options >out 2>err &&
+ test_cmp $expect_out out &&
+ test_cmp $expect_err err
+ "
+
+ test_expect_success "$desc via diff.external$with_options" "
+ test_config diff.external \"$command\" &&
+ test_config diff.trustExitCode $trust_exit_code &&
+ >.gitattributes &&
+ test_expect_code $expect_code git diff $options >out 2>err &&
+ test_cmp $expect_out out &&
+ test_cmp $expect_err err
+ "
+
+ test_expect_success "$desc via GIT_EXTERNAL_DIFF$with_options" "
+ >.gitattributes &&
+ test_expect_code $expect_code env \
+ GIT_EXTERNAL_DIFF=\"$command\" \
+ GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE=$trust_exit_code \
+ git diff $options >out 2>err &&
+ test_cmp $expect_out out &&
+ test_cmp $expect_err err
+ "
+}
+
+test_expect_success 'setup output files' '
+ : >empty &&
+ echo output >output &&
+ echo "fatal: external diff died, stopping at file" >error
+'
+
+check_external_diff 0 output empty 0 off
+check_external_diff 128 output error 1 off
+check_external_diff 0 output empty 0 on
+check_external_diff 0 output empty 1 on
+check_external_diff 128 output error 2 on
+
+check_external_diff 1 output empty 0 off --exit-code
+check_external_diff 128 output error 1 off --exit-code
+check_external_diff 0 output empty 0 on --exit-code
+check_external_diff 1 output empty 1 on --exit-code
+check_external_diff 128 output error 2 on --exit-code
+
+check_external_diff 1 empty empty 0 off --quiet
+check_external_diff 1 empty empty 1 off --quiet # we don't even call the program
+check_external_diff 0 empty empty 0 on --quiet
+check_external_diff 1 empty empty 1 on --quiet
+check_external_diff 128 empty error 2 on --quiet
+
echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
test_expect_success 'force diff with "diff"' '
@@ -232,7 +297,7 @@ keep_only_cr () {
test_expect_success 'external diff with autocrlf = true' '
test_config core.autocrlf true &&
GIT_EXTERNAL_DIFF=./fake-diff.sh git diff &&
- test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c)
+ test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
'
test_expect_success 'diff --cached' '
diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh
index 1219aa226d..9be65fd444 100755
--- a/t/t4021-format-patch-numbered.sh
+++ b/t/t4021-format-patch-numbered.sh
@@ -5,7 +5,6 @@
test_description='Format-patch numbering options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh
index e2f0eca4af..b98ac0a0c0 100755
--- a/t/t4024-diff-optimize-common.sh
+++ b/t/t4024-diff-optimize-common.sh
@@ -2,7 +2,6 @@
test_description='common tail optimization'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
z=zzzzzzzz ;# 8
diff --git a/t/t4025-hunk-header.sh b/t/t4025-hunk-header.sh
index 5397cb7d42..c39bb07a41 100755
--- a/t/t4025-hunk-header.sh
+++ b/t/t4025-hunk-header.sh
@@ -2,7 +2,6 @@
test_description='diff hunk header truncation'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
N='日本語'
diff --git a/t/t4026-color.sh b/t/t4026-color.sh
index cc3f60d468..08f6805e1c 100755
--- a/t/t4026-color.sh
+++ b/t/t4026-color.sh
@@ -5,7 +5,6 @@
test_description='Test diff/status color escape codes'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
ESC=$(printf '\033')
@@ -96,8 +95,8 @@ test_expect_success '256 colors' '
color "254 bold 255" "[1;38;5;254;48;5;255m"
'
-test_expect_success '24-bit colors' '
- color "#ff00ff black" "[38;2;255;0;255;40m"
+test_expect_success 'RGB colors' '
+ color "#ff00ff #0f0" "[38;2;255;0;255;48;2;0;255;0m"
'
test_expect_success '"default" foreground' '
@@ -112,7 +111,7 @@ test_expect_success '"default" can be combined with attributes' '
color "default default no-reverse bold" "[1;27;39;49m"
'
-test_expect_success '"normal" yields no color at all"' '
+test_expect_success '"normal" yields no color at all' '
color "normal black" "[40m"
'
@@ -140,6 +139,26 @@ test_expect_success 'extra character after attribute' '
invalid_color "dimX"
'
+test_expect_success 'non-hex character in RGB color' '
+ invalid_color "#x23456" &&
+ invalid_color "#1x3456" &&
+ invalid_color "#12x456" &&
+ invalid_color "#123x56" &&
+ invalid_color "#1234x6" &&
+ invalid_color "#12345x" &&
+ invalid_color "#x23" &&
+ invalid_color "#1x3" &&
+ invalid_color "#12x"
+'
+
+test_expect_success 'wrong number of letters in RGB color' '
+ invalid_color "#1" &&
+ invalid_color "#23" &&
+ invalid_color "#789a" &&
+ invalid_color "#bcdef" &&
+ invalid_color "#1234567"
+'
+
test_expect_success 'unknown color slots are ignored (diff)' '
git config color.diff.nosuchslotwilleverbedefined white &&
git diff --color
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
index 40164ae07d..295da987cc 100755
--- a/t/t4027-diff-submodule.sh
+++ b/t/t4027-diff-submodule.sh
@@ -2,7 +2,6 @@
test_description='difference in submodules'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
diff --git a/t/t4028-format-patch-mime-headers.sh b/t/t4028-format-patch-mime-headers.sh
index 60cb819c42..a06a747926 100755
--- a/t/t4028-format-patch-mime-headers.sh
+++ b/t/t4028-format-patch-mime-headers.sh
@@ -2,7 +2,6 @@
test_description='format-patch mime headers and extra headers do not conflict'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create commit with utf-8 body' '
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index 5f8ffef74b..32b6e9a4e7 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -4,7 +4,6 @@
#
test_description='diff honors config option, diff.suppressBlankEmpty'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat <<\EOF >expected ||
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index a39a626664..daebf9796f 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='diff.*.textconv tests'
+
. ./test-lib.sh
find_diff() {
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index eacc6694f7..c4394a27b5 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -53,7 +53,7 @@ test_expect_success 'rewrite diff --numstat shows binary changes' '
test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
git diff -B --stat --summary >diff &&
grep "Bin" diff &&
- test_i18ngrep "0 insertions.*0 deletions" diff &&
+ test_grep "0 insertions.*0 deletions" diff &&
grep " rewrite file" diff
'
diff --git a/t/t4032-diff-inter-hunk-context.sh b/t/t4032-diff-inter-hunk-context.sh
index 7db92d0d9f..bada0cbd32 100755
--- a/t/t4032-diff-inter-hunk-context.sh
+++ b/t/t4032-diff-inter-hunk-context.sh
@@ -2,7 +2,6 @@
test_description='diff hunk fusing'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
f() {
diff --git a/t/t4033-diff-patience.sh b/t/t4033-diff-patience.sh
index f7be7f5ef0..113304dc59 100755
--- a/t/t4033-diff-patience.sh
+++ b/t/t4033-diff-patience.sh
@@ -2,7 +2,6 @@
test_description='patience diff algorithm'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-alternative.sh
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 74586f3813..f51d3557f1 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -2,7 +2,6 @@
test_description='word diff colors'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
@@ -70,7 +69,7 @@ test_language_driver () {
word_diff --color-words
'
test_expect_success "diff driver '$lang' in Islandic" '
- LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \
+ test_env LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \
word_diff --color-words
'
}
diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh
index 76f8034c60..0352bf81a9 100755
--- a/t/t4035-diff-quiet.sh
+++ b/t/t4035-diff-quiet.sh
@@ -2,7 +2,6 @@
test_description='Return value of diffs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4036-format-patch-signer-mime.sh b/t/t4036-format-patch-signer-mime.sh
index 48655bcc78..98d9713d8b 100755
--- a/t/t4036-format-patch-signer-mime.sh
+++ b/t/t4036-format-patch-signer-mime.sh
@@ -2,7 +2,6 @@
test_description='format-patch -s should force MIME encoding as needed'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4037-diff-r-t-dirs.sh b/t/t4037-diff-r-t-dirs.sh
index b5f96fe23b..f5ce3b29a2 100755
--- a/t/t4037-diff-r-t-dirs.sh
+++ b/t/t4037-diff-r-t-dirs.sh
@@ -2,7 +2,6 @@
test_description='diff -r -t shows directory additions and deletions'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4039-diff-assume-unchanged.sh b/t/t4039-diff-assume-unchanged.sh
index 78090e6852..0eb0314a8b 100755
--- a/t/t4039-diff-assume-unchanged.sh
+++ b/t/t4039-diff-assume-unchanged.sh
@@ -2,7 +2,6 @@
test_description='diff with assume-unchanged entries'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# external diff has been tested in t4020-diff-external.sh
diff --git a/t/t4040-whitespace-status.sh b/t/t4040-whitespace-status.sh
index eec3d73dc2..1b27a0e381 100755
--- a/t/t4040-whitespace-status.sh
+++ b/t/t4040-whitespace-status.sh
@@ -2,7 +2,6 @@
test_description='diff --exit-code with whitespace'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 0c1502d4b0..28f9d83d4c 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -14,12 +14,18 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
-# Tested non-UTF-8 encoding
-test_encoding="ISO8859-1"
+# Test non-UTF-8 encoding in case iconv is available.
+if test_have_prereq ICONV
+then
+ test_encoding="ISO8859-1"
+ # String "added" in German (translated with Google Translate), encoded in UTF-8,
+ # used in sample commit log messages in add_file() function below.
+ added=$(printf "hinzugef\303\274gt")
+else
+ test_encoding="UTF-8"
+ added="added"
+fi
-# String "added" in German (translated with Google Translate), encoded in UTF-8,
-# used in sample commit log messages in add_file() function below.
-added=$(printf "hinzugef\303\274gt")
add_file () {
(
cd "$1" &&
diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh
index bf33aedf4b..ff0e73531b 100755
--- a/t/t4042-diff-textconv-caching.sh
+++ b/t/t4042-diff-textconv-caching.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test textconv caching'
+
. ./test-lib.sh
cat >helper <<'EOF'
@@ -118,4 +119,26 @@ test_expect_success 'log notes cache and still use cache for -p' '
git log --no-walk -p refs/notes/textconv/magic HEAD
'
+test_expect_success 'caching is silently ignored outside repo' '
+ mkdir -p non-repo &&
+ echo one >non-repo/one &&
+ echo two >non-repo/two &&
+ echo "* diff=test" >attr &&
+ test_expect_code 1 \
+ nongit git -c core.attributesFile="$PWD/attr" \
+ -c diff.test.textconv="tr a-z A-Z <" \
+ -c diff.test.cachetextconv=true \
+ diff --no-index one two >actual &&
+ cat >expect <<-\EOF &&
+ diff --git a/one b/two
+ index 5626abf..f719efd 100644
+ --- a/one
+ +++ b/two
+ @@ -1 +1 @@
+ -ONE
+ +TWO
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4044-diff-index-unique-abbrev.sh b/t/t4044-diff-index-unique-abbrev.sh
index 9f6043daba..8400bfbd3c 100755
--- a/t/t4044-diff-index-unique-abbrev.sh
+++ b/t/t4044-diff-index-unique-abbrev.sh
@@ -2,7 +2,6 @@
test_description='test unique sha1 abbreviation on "index from..to" line'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index 9b46c4c1be..2c8493fe66 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -2,7 +2,6 @@
test_description='diff --relative tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh
index ffaf69335f..7c27f05366 100755
--- a/t/t4046-diff-unmerged.sh
+++ b/t/t4046-diff-unmerged.sh
@@ -2,7 +2,6 @@
test_description='diff with unmerged index entries'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -20,13 +19,15 @@ test_expect_success setup '
for t in o x
do
path="$b$o$t" &&
- case "$path" in ooo) continue ;; esac &&
- paths="$paths$path " &&
- p=" $path" &&
- case "$b" in x) echo "$m1$p" ;; esac &&
- case "$o" in x) echo "$m2$p" ;; esac &&
- case "$t" in x) echo "$m3$p" ;; esac ||
- return 1
+ if test "$path" != ooo
+ then
+ paths="$paths$path " &&
+ p=" $path" &&
+ case "$b" in x) echo "$m1$p" ;; esac &&
+ case "$o" in x) echo "$m2$p" ;; esac &&
+ case "$t" in x) echo "$m3$p" ;; esac ||
+ return 1
+ fi
done
done
done >ls-files-s.expect &&
@@ -96,4 +97,12 @@ test_expect_success 'diff --stat' '
test_cmp diff-stat.expect diff-stat.actual
'
+test_expect_success 'diff --quiet' '
+ test_expect_code 1 git diff --cached --quiet
+'
+
+test_expect_success 'diff --quiet --ignore-all-space' '
+ test_expect_code 1 git diff --cached --quiet --ignore-all-space
+'
+
test_done
diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh
index 70224c3da1..a7ce8d3161 100755
--- a/t/t4047-diff-dirstat.sh
+++ b/t/t4047-diff-dirstat.sh
@@ -2,7 +2,6 @@
test_description='diff --dirstat tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# set up two commits where the second commit has these files
@@ -943,37 +942,37 @@ test_expect_success '--dirstat=future_param,lines,0 should fail loudly' '
test_must_fail git diff --dirstat=future_param,lines,0 HEAD^..HEAD >actual_diff_dirstat 2>actual_error &&
test_debug "cat actual_error" &&
test_must_be_empty actual_diff_dirstat &&
- test_i18ngrep -q "future_param" actual_error &&
- test_i18ngrep -q "\--dirstat" actual_error
+ test_grep -q "future_param" actual_error &&
+ test_grep -q "\--dirstat" actual_error
'
test_expect_success '--dirstat=dummy1,cumulative,2dummy should report both unrecognized parameters' '
test_must_fail git diff --dirstat=dummy1,cumulative,2dummy HEAD^..HEAD >actual_diff_dirstat 2>actual_error &&
test_debug "cat actual_error" &&
test_must_be_empty actual_diff_dirstat &&
- test_i18ngrep -q "dummy1" actual_error &&
- test_i18ngrep -q "2dummy" actual_error &&
- test_i18ngrep -q "\--dirstat" actual_error
+ test_grep -q "dummy1" actual_error &&
+ test_grep -q "2dummy" actual_error &&
+ test_grep -q "\--dirstat" actual_error
'
test_expect_success 'diff.dirstat=future_param,0,lines should warn, but still work' '
git -c diff.dirstat=future_param,0,lines diff --dirstat HEAD^..HEAD >actual_diff_dirstat 2>actual_error &&
test_debug "cat actual_error" &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
- test_i18ngrep -q "future_param" actual_error &&
- test_i18ngrep -q "diff\\.dirstat" actual_error &&
+ test_grep -q "future_param" actual_error &&
+ test_grep -q "diff\\.dirstat" actual_error &&
git -c diff.dirstat=future_param,0,lines diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M 2>actual_error &&
test_debug "cat actual_error" &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
- test_i18ngrep -q "future_param" actual_error &&
- test_i18ngrep -q "diff\\.dirstat" actual_error &&
+ test_grep -q "future_param" actual_error &&
+ test_grep -q "diff\\.dirstat" actual_error &&
git -c diff.dirstat=future_param,0,lines diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC 2>actual_error &&
test_debug "cat actual_error" &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC &&
- test_i18ngrep -q "future_param" actual_error &&
- test_i18ngrep -q "diff\\.dirstat" actual_error
+ test_grep -q "future_param" actual_error &&
+ test_grep -q "diff\\.dirstat" actual_error
'
test_expect_success '--shortstat --dirstat should output only one dirstat' '
diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh
index 0a4fc735d4..eceb47c859 100755
--- a/t/t4049-diff-stat-count.sh
+++ b/t/t4049-diff-stat-count.sh
@@ -3,7 +3,6 @@
test_description='diff --stat-count'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4050-diff-histogram.sh b/t/t4050-diff-histogram.sh
index c61b30f96d..fd3e86a74f 100755
--- a/t/t4050-diff-histogram.sh
+++ b/t/t4050-diff-histogram.sh
@@ -2,7 +2,6 @@
test_description='histogram diff algorithm'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-alternative.sh
diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh
index 725278ad19..4838a1df8b 100755
--- a/t/t4051-diff-function-context.sh
+++ b/t/t4051-diff-function-context.sh
@@ -2,7 +2,6 @@
test_description='diff function context'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
dir="$TEST_DIRECTORY/t4051"
diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh
index 3ee27e277d..740bb97091 100755
--- a/t/t4052-stat-output.sh
+++ b/t/t4052-stat-output.sh
@@ -8,11 +8,10 @@ test_description='test --stat output of various commands'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
-# 120 character name
+# 120-character name
name=aaaaaaaaaa
name=$name$name$name$name$name$name$name$name$name$name$name$name
test_expect_success 'preparation' '
@@ -49,12 +48,41 @@ log -1 --stat
EOF
cat >expect.60 <<-'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
cat >expect.6030 <<-'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
-cat >expect2.60 <<-'EOF'
+while read verb expect cmd args
+do
+ # No width limit applied when statNameWidth is ignored
+ case "$expect" in expect72|expect.6030)
+ test_expect_success "$cmd $verb diff.statNameWidth with long name" '
+ git -c diff.statNameWidth=30 $cmd $args >output &&
+ grep " | " output >actual &&
+ test_cmp $expect actual
+ ';;
+ esac
+ # Maximum width limit still applied when statNameWidth is ignored
+ case "$expect" in expect.60|expect.6030)
+ test_expect_success "$cmd --stat=width $verb diff.statNameWidth with long name" '
+ git -c diff.statNameWidth=30 $cmd $args --stat=60 >output &&
+ grep " | " output >actual &&
+ test_cmp $expect actual
+ ';;
+ esac
+done <<\EOF
+ignores expect72 format-patch -1 --stdout
+ignores expect.60 format-patch -1 --stdout
+respects expect.6030 diff HEAD^ HEAD --stat
+respects expect.6030 show --stat
+respects expect.6030 log -1 --stat
+EOF
+
+cat >expect.40 <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+EOF
+cat >expect2.40 <<-'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
@@ -67,22 +95,22 @@ do
test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" '
git $cmd $args --stat=40 >output &&
grep " | " output >actual &&
- test_cmp $expect.60 actual
+ test_cmp $expect.40 actual
'
test_expect_success "$cmd --stat-width=width with long name" '
git $cmd $args --stat-width=40 >output &&
grep " | " output >actual &&
- test_cmp $expect.60 actual
+ test_cmp $expect.40 actual
'
- test_expect_success "$cmd --stat=...,name-width with long name" '
+ test_expect_success "$cmd --stat=width,name-width with long name" '
git $cmd $args --stat=60,30 >output &&
grep " | " output >actual &&
test_cmp $expect.6030 actual
'
- test_expect_success "$cmd --stat-name-width with long name" '
+ test_expect_success "$cmd --stat-name-width=width with long name" '
git $cmd $args --stat-name-width=30 >output &&
grep " | " output >actual &&
test_cmp $expect.6030 actual
@@ -94,8 +122,7 @@ expect show --stat
expect log -1 --stat
EOF
-
-test_expect_success 'preparation for big change tests' '
+test_expect_success 'preparation for big-change tests' '
>abcd &&
git add abcd &&
git commit -m message &&
@@ -111,7 +138,7 @@ cat >expect72 <<'EOF'
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
-test_expect_success "format-patch --cover-letter ignores COLUMNS (big change)" '
+test_expect_success "format-patch --cover-letter ignores COLUMNS with big change" '
COLUMNS=200 git format-patch -1 --stdout --cover-letter >output &&
grep " | " output >actual &&
test_cmp expect72 actual
@@ -131,7 +158,7 @@ cat >expect200-graph <<'EOF'
EOF
while read verb expect cmd args
do
- test_expect_success "$cmd $verb COLUMNS (big change)" '
+ test_expect_success "$cmd $verb COLUMNS with big change" '
COLUMNS=200 git $cmd $args >output &&
grep " | " output >actual &&
test_cmp "$expect" actual
@@ -139,7 +166,7 @@ do
case "$cmd" in diff|show) continue;; esac
- test_expect_success "$cmd --graph $verb COLUMNS (big change)" '
+ test_expect_success "$cmd --graph $verb COLUMNS with big change" '
COLUMNS=200 git $cmd $args --graph >output &&
grep " | " output >actual &&
test_cmp "$expect-graph" actual
@@ -159,7 +186,7 @@ cat >expect40-graph <<'EOF'
EOF
while read verb expect cmd args
do
- test_expect_success "$cmd $verb not enough COLUMNS (big change)" '
+ test_expect_success "$cmd $verb not enough COLUMNS with big change" '
COLUMNS=40 git $cmd $args >output &&
grep " | " output >actual &&
test_cmp "$expect" actual
@@ -167,7 +194,7 @@ do
case "$cmd" in diff|show) continue;; esac
- test_expect_success "$cmd --graph $verb not enough COLUMNS (big change)" '
+ test_expect_success "$cmd --graph $verb not enough COLUMNS with big change" '
COLUMNS=40 git $cmd $args --graph >output &&
grep " | " output >actual &&
test_cmp "$expect-graph" actual
@@ -187,7 +214,7 @@ cat >expect40-graph <<'EOF'
EOF
while read verb expect cmd args
do
- test_expect_success "$cmd $verb statGraphWidth config" '
+ test_expect_success "$cmd $verb diff.statGraphWidth" '
git -c diff.statGraphWidth=26 $cmd $args >output &&
grep " | " output >actual &&
test_cmp "$expect" actual
@@ -195,7 +222,7 @@ do
case "$cmd" in diff|show) continue;; esac
- test_expect_success "$cmd --graph $verb statGraphWidth config" '
+ test_expect_success "$cmd --graph $verb diff.statGraphWidth" '
git -c diff.statGraphWidth=26 $cmd $args --graph >output &&
grep " | " output >actual &&
test_cmp "$expect-graph" actual
@@ -207,7 +234,6 @@ respects expect40 show --stat
respects expect40 log -1 --stat
EOF
-
cat >expect <<'EOF'
abcd | 1000 ++++++++++++++++++++++++++
EOF
@@ -228,7 +254,7 @@ do
test_cmp expect actual
'
- test_expect_success "$cmd --stat-graph-width with big change" '
+ test_expect_success "$cmd --stat-graph-width=width with big change" '
git $cmd $args --stat-graph-width=26 >output &&
grep " | " output >actual &&
test_cmp expect actual
@@ -242,7 +268,7 @@ do
test_cmp expect-graph actual
'
- test_expect_success "$cmd --stat-graph-width --graph with big change" '
+ test_expect_success "$cmd --stat-graph-width=width --graph with big change" '
git $cmd $args --stat-graph-width=26 --graph >output &&
grep " | " output >actual &&
test_cmp expect-graph actual
@@ -254,7 +280,7 @@ show --stat
log -1 --stat
EOF
-test_expect_success 'preparation for long filename tests' '
+test_expect_success 'preparation for long-name tests' '
cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
git commit -m message
@@ -302,7 +328,7 @@ cat >expect200-graph <<'EOF'
EOF
while read verb expect cmd args
do
- test_expect_success "$cmd $verb COLUMNS (long filename)" '
+ test_expect_success "$cmd $verb COLUMNS with long name" '
COLUMNS=200 git $cmd $args >output &&
grep " | " output >actual &&
test_cmp "$expect" actual
@@ -310,7 +336,7 @@ do
case "$cmd" in diff|show) continue;; esac
- test_expect_success "$cmd --graph $verb COLUMNS (long filename)" '
+ test_expect_success "$cmd --graph $verb COLUMNS with long name" '
COLUMNS=200 git $cmd $args --graph >output &&
grep " | " output >actual &&
test_cmp "$expect-graph" actual
@@ -331,7 +357,7 @@ EOF
while read verb expect cmd args
do
test_expect_success COLUMNS_CAN_BE_1 \
- "$cmd $verb prefix greater than COLUMNS (big change)" '
+ "$cmd $verb prefix greater than COLUMNS with big change" '
COLUMNS=1 git $cmd $args >output &&
grep " | " output >actual &&
test_cmp "$expect" actual
@@ -340,7 +366,7 @@ do
case "$cmd" in diff|show) continue;; esac
test_expect_success COLUMNS_CAN_BE_1 \
- "$cmd --graph $verb prefix greater than COLUMNS (big change)" '
+ "$cmd --graph $verb prefix greater than COLUMNS with big change" '
COLUMNS=1 git $cmd $args --graph >output &&
grep " | " output >actual &&
test_cmp "$expect-graph" actual
@@ -355,8 +381,14 @@ EOF
cat >expect <<'EOF'
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
-test_expect_success 'merge --stat respects COLUMNS (big change)' '
- git checkout -b branch HEAD^^ &&
+test_expect_success 'merge --stat respects diff.statGraphWidth with big change' '
+ git checkout -b branch1 HEAD^^ &&
+ git -c diff.statGraphWidth=26 merge --stat --no-ff main^ >output &&
+ grep " | " output >actual &&
+ test_cmp expect40 actual
+'
+test_expect_success 'merge --stat respects COLUMNS with big change' '
+ git checkout -b branch2 HEAD^^ &&
COLUMNS=100 git merge --stat --no-ff main^ >output &&
grep " | " output >actual &&
test_cmp expect actual
@@ -365,7 +397,17 @@ test_expect_success 'merge --stat respects COLUMNS (big change)' '
cat >expect <<'EOF'
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++
EOF
-test_expect_success 'merge --stat respects COLUMNS (long filename)' '
+cat >expect.30 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++
+EOF
+test_expect_success 'merge --stat respects diff.statNameWidth with long name' '
+ git switch branch1 &&
+ git -c diff.statNameWidth=30 merge --stat --no-ff main >output &&
+ grep " | " output >actual &&
+ test_cmp expect.30 actual
+'
+test_expect_success 'merge --stat respects COLUMNS with long name' '
+ git switch branch2 &&
COLUMNS=100 git merge --stat --no-ff main >output &&
grep " | " output >actual &&
test_cmp expect actual
diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 5f059f65fc..5e5bad61ca 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -2,7 +2,6 @@
test_description='diff --no-index'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -56,7 +55,7 @@ test_expect_success 'git diff --no-index executed outside repo gives correct err
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
test_must_fail git diff --no-index a 2>actual.err &&
- test_i18ngrep "usage: git diff --no-index" actual.err
+ test_grep "usage: git diff --no-index" actual.err
)
'
@@ -205,6 +204,18 @@ test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not lik
test_cmp expected actual
'
+test_expect_success POSIXPERM 'external diff with mode-only change' '
+ echo content >not-executable &&
+ echo content >executable &&
+ chmod +x executable &&
+ echo executable executable $(test_oid zero) 100755 \
+ not-executable $(test_oid zero) 100644 not-executable \
+ >expect &&
+ test_expect_code 1 git -c diff.external=echo diff \
+ --no-index executable not-executable >actual &&
+ test_cmp expect actual
+'
+
test_expect_success "diff --no-index treats '-' as stdin" '
cat >expect <<-EOF &&
diff --git a/- b/a/1
diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh
index 05c88f8cdf..1131431fe0 100755
--- a/t/t4054-diff-bogus-tree.sh
+++ b/t/t4054-diff-bogus-tree.sh
@@ -2,7 +2,6 @@
test_description='test diff with a bogus tree containing the null sha1'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create bogus tree' '
diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh
index 73048d0a52..f7ff234cf9 100755
--- a/t/t4055-diff-context.sh
+++ b/t/t4055-diff-context.sh
@@ -5,7 +5,6 @@
test_description='diff.context configuration'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -74,13 +73,13 @@ test_expect_success 'plumbing not affected' '
test_expect_success 'non-integer config parsing' '
git config diff.context no &&
test_must_fail git diff 2>output &&
- test_i18ngrep "bad numeric config value" output
+ test_grep "bad numeric config value" output
'
test_expect_success 'negative integer config parsing' '
git config diff.context -1 &&
test_must_fail git diff 2>output &&
- test_i18ngrep "bad config variable" output
+ test_grep "bad config variable" output
'
test_expect_success '-U0 is valid, so is diff.context=0' '
diff --git a/t/t4057-diff-combined-paths.sh b/t/t4057-diff-combined-paths.sh
index 9a7505cbb8..04b8a1542a 100755
--- a/t/t4057-diff-combined-paths.sh
+++ b/t/t4057-diff-combined-paths.sh
@@ -5,7 +5,6 @@ test_description='combined diff show only paths that are different to all parent
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# verify that diffc.expect matches output of
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 2501c89c1c..2fce4a9897 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -10,6 +10,7 @@
# that the diff output isn't wildly unreasonable.
test_description='test tree diff when trees have duplicate entries'
+
. ./test-lib.sh
# make_tree_entry <mode> <mode> <sha1>
@@ -132,22 +133,23 @@ test_expect_success 'create a few commits' '
rm commit_id up final
'
-test_expect_failure 'git read-tree does not segfault' '
- test_when_finished rm .git/index.lock &&
- test_might_fail git read-tree --reset base
+test_expect_success 'git read-tree does not segfault' '
+ test_must_fail git read-tree --reset base 2>err &&
+ test_grep "error: corrupted cache-tree has entries not present in index" err
'
-test_expect_failure 'reset --hard does not segfault' '
- test_when_finished rm .git/index.lock &&
+test_expect_success 'reset --hard does not segfault' '
git checkout base &&
- test_might_fail git reset --hard
+ test_must_fail git reset --hard 2>err &&
+ test_grep "error: corrupted cache-tree has entries not present in index" err
'
-test_expect_failure 'git diff HEAD does not segfault' '
+test_expect_success 'git diff HEAD does not segfault' '
git checkout base &&
GIT_TEST_CHECK_CACHE_TREE=false &&
git reset --hard &&
- test_might_fail git diff HEAD
+ test_must_fail git diff HEAD 2>err &&
+ test_grep "error: corrupted cache-tree has entries not present in index" err
'
test_expect_failure 'can switch to another branch when status is empty' '
diff --git a/t/t4059-diff-submodule-not-initialized.sh b/t/t4059-diff-submodule-not-initialized.sh
index d489230df8..0fe81056d5 100755
--- a/t/t4059-diff-submodule-not-initialized.sh
+++ b/t/t4059-diff-submodule-not-initialized.sh
@@ -11,12 +11,18 @@ initialized previously but the checkout has since been removed.
. ./test-lib.sh
-# Tested non-UTF-8 encoding
-test_encoding="ISO8859-1"
-# String "added" in German (translated with Google Translate), encoded in UTF-8,
-# used in sample commit log messages in add_file() function below.
-added=$(printf "hinzugef\303\274gt")
+# Test non-UTF-8 encoding in case iconv is available.
+if test_have_prereq ICONV
+then
+ test_encoding="ISO8859-1"
+ # String "added" in German (translated with Google Translate), encoded in UTF-8,
+ # used in sample commit log messages in add_file() function below.
+ added=$(printf "hinzugef\303\274gt")
+else
+ test_encoding="UTF-8"
+ added="added"
+fi
add_file () {
(
diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh
index 97c6424cd5..76b83101d3 100755
--- a/t/t4060-diff-submodule-option-diff-format.sh
+++ b/t/t4060-diff-submodule-option-diff-format.sh
@@ -12,12 +12,17 @@ This test tries to verify the sanity of --submodule=diff option of git diff.
. ./test-lib.sh
-# Tested non-UTF-8 encoding
-test_encoding="ISO8859-1"
-
-# String "added" in German (translated with Google Translate), encoded in UTF-8,
-# used in sample commit log messages in add_file() function below.
-added=$(printf "hinzugef\303\274gt")
+# Test non-UTF-8 encoding in case iconv is available.
+if test_have_prereq ICONV
+then
+ test_encoding="ISO8859-1"
+ # String "added" in German (translated with Google Translate), encoded in UTF-8,
+ # used in sample commit log messages in add_file() function below.
+ added=$(printf "hinzugef\303\274gt")
+else
+ test_encoding="UTF-8"
+ added="added"
+fi
add_file () {
(
diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh
index a90b46b678..8ad3d79957 100755
--- a/t/t4062-diff-pickaxe.sh
+++ b/t/t4062-diff-pickaxe.sh
@@ -5,7 +5,6 @@
test_description='Pickaxe options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4063-diff-blobs.sh b/t/t4063-diff-blobs.sh
index 7e6c9d6384..50fdb5ea52 100755
--- a/t/t4063-diff-blobs.sh
+++ b/t/t4063-diff-blobs.sh
@@ -2,7 +2,6 @@
test_description='test direct comparison of blobs via git-diff'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
run_diff () {
diff --git a/t/t4064-diff-oidfind.sh b/t/t4064-diff-oidfind.sh
index 6d8c8986fc..e86bba679e 100755
--- a/t/t4064-diff-oidfind.sh
+++ b/t/t4064-diff-oidfind.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test finding specific blobs in the revision walking'
+
. ./test-lib.sh
test_expect_success 'setup ' '
diff --git a/t/t4066-diff-emit-delay.sh b/t/t4066-diff-emit-delay.sh
index 0ecb391541..a1de63b77f 100755
--- a/t/t4066-diff-emit-delay.sh
+++ b/t/t4066-diff-emit-delay.sh
@@ -4,7 +4,6 @@ test_description='test combined/stat/moved interaction'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This test covers a weird 3-way interaction between "--cc -p", which will run
diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh
index 7af3a08862..581250dd2d 100755
--- a/t/t4067-diff-partial-clone.sh
+++ b/t/t4067-diff-partial-clone.sh
@@ -2,7 +2,6 @@
test_description='behavior of diff when reading objects in a partial clone'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'git show batches blobs' '
diff --git a/t/t4068-diff-symmetric-merge-base.sh b/t/t4068-diff-symmetric-merge-base.sh
index 2d650d8f10..eff63c16b0 100755
--- a/t/t4068-diff-symmetric-merge-base.sh
+++ b/t/t4068-diff-symmetric-merge-base.sh
@@ -34,7 +34,7 @@ test_expect_success setup '
echo c >c &&
git add c &&
git commit -m C &&
- git tag commit-C &&
+ git tag -m commit-C commit-C &&
git merge -m D main &&
git tag commit-D &&
git checkout main &&
@@ -68,27 +68,27 @@ test_expect_success 'diff with two merge bases' '
test_expect_success 'diff with no merge bases' '
test_must_fail git diff br2...br3 2>err &&
- test_i18ngrep "fatal: br2...br3: no merge base" err
+ test_grep "fatal: br2...br3: no merge base" err
'
test_expect_success 'diff with too many symmetric differences' '
test_must_fail git diff br1...main br2...br3 2>err &&
- test_i18ngrep "usage" err
+ test_grep "usage" err
'
test_expect_success 'diff with symmetric difference and extraneous arg' '
test_must_fail git diff main br1...main 2>err &&
- test_i18ngrep "usage" err
+ test_grep "usage" err
'
test_expect_success 'diff with two ranges' '
test_must_fail git diff main br1..main br2..br3 2>err &&
- test_i18ngrep "usage" err
+ test_grep "usage" err
'
test_expect_success 'diff with ranges and extra arg' '
test_must_fail git diff main br1..main commit-D 2>err &&
- test_i18ngrep "usage" err
+ test_grep "usage" err
'
test_expect_success 'diff --merge-base with no commits' '
@@ -97,7 +97,7 @@ test_expect_success 'diff --merge-base with no commits' '
test_expect_success 'diff --merge-base with three commits' '
test_must_fail git diff --merge-base br1 br2 main 2>err &&
- test_i18ngrep "usage" err
+ test_grep "usage" err
'
for cmd in diff-index diff
@@ -109,6 +109,13 @@ do
test_cmp expect actual
'
+ test_expect_success "$cmd --merge-base with annotated tag" '
+ git checkout main &&
+ git $cmd commit-C >expect &&
+ git $cmd --merge-base commit-C >actual &&
+ test_cmp expect actual
+ '
+
test_expect_success "$cmd --merge-base with one commit and unstaged changes" '
git checkout main &&
test_when_finished git reset --hard &&
@@ -143,19 +150,19 @@ do
test_expect_success "$cmd --merge-base with non-commit" '
git checkout main &&
test_must_fail git $cmd --merge-base main^{tree} 2>err &&
- test_i18ngrep "fatal: --merge-base only works with commits" err
+ test_grep "is a tree, not a commit" err
'
test_expect_success "$cmd --merge-base with no merge bases and one commit" '
git checkout main &&
test_must_fail git $cmd --merge-base br3 2>err &&
- test_i18ngrep "fatal: no merge base found" err
+ test_grep "fatal: no merge base found" err
'
test_expect_success "$cmd --merge-base with multiple merge bases and one commit" '
git checkout main &&
test_must_fail git $cmd --merge-base br1 2>err &&
- test_i18ngrep "fatal: multiple merge bases found" err
+ test_grep "fatal: multiple merge bases found" err
'
done
@@ -169,28 +176,28 @@ do
test_expect_success "$cmd --merge-base commit and non-commit" '
test_must_fail git $cmd --merge-base br2 main^{tree} 2>err &&
- test_i18ngrep "fatal: --merge-base only works with commits" err
+ test_grep "is a tree, not a commit" err
'
test_expect_success "$cmd --merge-base with no merge bases and two commits" '
test_must_fail git $cmd --merge-base br2 br3 2>err &&
- test_i18ngrep "fatal: no merge base found" err
+ test_grep "fatal: no merge base found" err
'
test_expect_success "$cmd --merge-base with multiple merge bases and two commits" '
test_must_fail git $cmd --merge-base main br1 2>err &&
- test_i18ngrep "fatal: multiple merge bases found" err
+ test_grep "fatal: multiple merge bases found" err
'
done
test_expect_success 'diff-tree --merge-base with one commit' '
test_must_fail git diff-tree --merge-base main 2>err &&
- test_i18ngrep "fatal: --merge-base only works with two commits" err
+ test_grep "fatal: --merge-base only works with two commits" err
'
test_expect_success 'diff --merge-base with range' '
test_must_fail git diff --merge-base br2..br3 2>err &&
- test_i18ngrep "fatal: --merge-base does not work with ranges" err
+ test_grep "fatal: --merge-base does not work with ranges" err
'
test_done
diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh
index 07323ebafe..ca8f999cab 100755
--- a/t/t4069-remerge-diff.sh
+++ b/t/t4069-remerge-diff.sh
@@ -110,6 +110,41 @@ test_expect_success 'can filter out additional headers with pickaxe' '
test_must_be_empty actual
'
+test_expect_success 'remerge-diff also works for git-diff-tree' '
+ # With a clean merge
+ git diff-tree -r -p --remerge-diff --no-commit-id bc_resolution >actual &&
+ test_must_be_empty actual &&
+
+ # With both a resolved conflict and an unrelated change
+ cat <<-EOF >tmp &&
+ diff --git a/numbers b/numbers
+ remerge CONFLICT (content): Merge conflict in numbers
+ index a1fb731..6875544 100644
+ --- a/numbers
+ +++ b/numbers
+ @@ -1,13 +1,9 @@
+ 1
+ 2
+ -<<<<<<< b0ed5cb (change_a)
+ -three
+ -=======
+ -tres
+ ->>>>>>> 6cd3f82 (change_b)
+ +drei
+ 4
+ 5
+ 6
+ 7
+ -eight
+ +acht
+ 9
+ EOF
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+ git diff-tree -r -p --remerge-diff --no-commit-id ab_resolution >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup non-content conflicts' '
git switch --orphan base &&
diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh
index d503547732..146e73d8f5 100755
--- a/t/t4100-apply-stat.sh
+++ b/t/t4100-apply-stat.sh
@@ -7,7 +7,6 @@ test_description='git apply --stat --summary test, with --recount
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
UNC='s/^\(@@ -[1-9][0-9]*\),[0-9]* \(+[1-9][0-9]*\),[0-9]* @@/\1,999 \2,999 @@/'
diff --git a/t/t4101-apply-nonl.sh b/t/t4101-apply-nonl.sh
index b1169193ef..4df74baa24 100755
--- a/t/t4101-apply-nonl.sh
+++ b/t/t4101-apply-nonl.sh
@@ -7,7 +7,6 @@ test_description='git apply should handle files with incomplete lines.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# setup
diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh
index d1e06fc1ac..e42a31c917 100755
--- a/t/t4102-apply-rename.sh
+++ b/t/t4102-apply-rename.sh
@@ -7,7 +7,6 @@ test_description='git apply handling copy/rename patch.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# setup
diff --git a/t/t4105-apply-fuzz.sh b/t/t4105-apply-fuzz.sh
index ed814a839e..b59785166d 100755
--- a/t/t4105-apply-fuzz.sh
+++ b/t/t4105-apply-fuzz.sh
@@ -3,7 +3,6 @@
test_description='apply with fuzz and offset'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
dotest () {
diff --git a/t/t4106-apply-stdin.sh b/t/t4106-apply-stdin.sh
index 5c150f3b0b..aa2fff7afa 100755
--- a/t/t4106-apply-stdin.sh
+++ b/t/t4106-apply-stdin.sh
@@ -3,7 +3,6 @@
test_description='git apply --numstat - <patch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4107-apply-ignore-whitespace.sh b/t/t4107-apply-ignore-whitespace.sh
index ac72eeaf27..94ba6dd4e0 100755
--- a/t/t4107-apply-ignore-whitespace.sh
+++ b/t/t4107-apply-ignore-whitespace.sh
@@ -3,9 +3,8 @@
# Copyright (c) 2009 Giuseppe Bilotta
#
-test_description='git-apply --ignore-whitespace.
+test_description='git-apply --ignore-whitespace.'
-'
. ./test-lib.sh
# This primes main.c file that indents without using HT at all.
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
index c558282bc0..f30e85659d 100755
--- a/t/t4108-apply-threeway.sh
+++ b/t/t4108-apply-threeway.sh
@@ -81,6 +81,46 @@ test_expect_success 'apply with --3way with merge.conflictStyle = diff3' '
test_apply_with_3way
'
+test_apply_with_3way_favoritism () {
+ apply_arg=$1
+ merge_arg=$2
+
+ # Merging side should be similar to applying this patch
+ git diff ...side >P.diff &&
+
+ # The corresponding conflicted merge
+ git reset --hard &&
+ git checkout main^0 &&
+ git merge --no-commit $merge_arg side &&
+ git ls-files -s >expect.ls &&
+ print_sanitized_conflicted_diff >expect.diff &&
+
+ # should apply successfully
+ git reset --hard &&
+ git checkout main^0 &&
+ git apply --index --3way $apply_arg P.diff &&
+ git ls-files -s >actual.ls &&
+ print_sanitized_conflicted_diff >actual.diff &&
+
+ # The result should resemble the corresponding merge
+ test_cmp expect.ls actual.ls &&
+ test_cmp expect.diff actual.diff
+}
+
+test_expect_success 'apply with --3way --ours' '
+ test_apply_with_3way_favoritism --ours -Xours
+'
+
+test_expect_success 'apply with --3way --theirs' '
+ test_apply_with_3way_favoritism --theirs -Xtheirs
+'
+
+test_expect_success 'apply with --3way --union' '
+ echo "* merge=union" >.gitattributes &&
+ test_apply_with_3way_favoritism --union &&
+ rm .gitattributes
+'
+
test_expect_success 'apply with --3way with rerere enabled' '
test_config rerere.enabled true &&
diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh
index 4dc6d8e7d3..ac523a5d56 100755
--- a/t/t4109-apply-multifrag.sh
+++ b/t/t4109-apply-multifrag.sh
@@ -7,7 +7,6 @@
test_description='git apply test patches with multiple fragments.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cp "$TEST_DIRECTORY/t4109/patch1.patch" .
diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh
index 266302a182..cc17ff2ab9 100755
--- a/t/t4110-apply-scan.sh
+++ b/t/t4110-apply-scan.sh
@@ -8,7 +8,6 @@ test_description='git apply test for patches which require scanning forwards and
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'git apply scan' '
diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh
index e9a87d761d..1618a6dbc7 100755
--- a/t/t4111-apply-subdir.sh
+++ b/t/t4111-apply-subdir.sh
@@ -2,7 +2,6 @@
test_description='patching from inconvenient places'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4112-apply-renames.sh b/t/t4112-apply-renames.sh
index d53aa4222e..bb5d529bec 100755
--- a/t/t4112-apply-renames.sh
+++ b/t/t4112-apply-renames.sh
@@ -8,7 +8,6 @@ test_description='git apply should not get confused with rename/copy.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# setup
diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh
index 8ff3640766..da3e64f811 100755
--- a/t/t4114-apply-typechange.sh
+++ b/t/t4114-apply-typechange.sh
@@ -7,7 +7,6 @@ test_description='git apply should not get confused with type changes.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup repository and commits' '
diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index a22a90d552..769b0e4f9d 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -7,7 +7,6 @@ test_description='git apply symlinks and partial files
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -136,7 +135,7 @@ test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' '
ln -s foo file.t.rej &&
test_must_fail git apply patch --reject 2>err &&
- test_i18ngrep "Rejected hunk" err &&
+ test_grep "Rejected hunk" err &&
test_path_is_missing foo &&
test_path_is_file file.t.rej
'
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index a9f4ddda6c..0784ba033a 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -8,7 +8,6 @@ test_description='git apply in reverse
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh
index 69c9c48e72..c1dcbd7d35 100755
--- a/t/t4118-apply-empty-context.sh
+++ b/t/t4118-apply-empty-context.sh
@@ -8,7 +8,6 @@ test_description='git apply with new style GNU diff with empty context
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4119-apply-config.sh b/t/t4119-apply-config.sh
index 208c961d37..f3b43e2216 100755
--- a/t/t4119-apply-config.sh
+++ b/t/t4119-apply-config.sh
@@ -8,7 +8,6 @@ test_description='git apply --whitespace=strip and configuration file.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh
index 497b62868d..697e86c0ff 100755
--- a/t/t4120-apply-popt.sh
+++ b/t/t4120-apply-popt.sh
@@ -31,7 +31,7 @@ test_expect_success 'apply git diff with -p2' '
test_expect_success 'apply with too large -p' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.file 2>err &&
- test_i18ngrep "removing 3 leading" err
+ test_grep "removing 3 leading" err
'
test_expect_success 'apply (-p2) traditional diff with funny filenames' '
@@ -53,7 +53,7 @@ test_expect_success 'apply (-p2) traditional diff with funny filenames' '
test_expect_success 'apply with too large -p and fancy filename' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.escaped 2>err &&
- test_i18ngrep "removing 3 leading" err
+ test_grep "removing 3 leading" err
'
test_expect_success 'apply (-p2) diff, mode change only' '
diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh
index a80cec9d11..b45454aaf4 100755
--- a/t/t4121-apply-diffs.sh
+++ b/t/t4121-apply-diffs.sh
@@ -4,7 +4,6 @@ test_description='git apply for contextually independent diffs'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
echo '1
diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh
index 9696537303..3340ab4370 100755
--- a/t/t4122-apply-symlink-inside.sh
+++ b/t/t4122-apply-symlink-inside.sh
@@ -4,7 +4,6 @@ test_description='apply to deeper directory without getting fooled with symlink'
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 '
@@ -95,19 +94,19 @@ test_expect_success SYMLINKS 'do not follow symbolic link (same input)' '
# same input creates a confusing symbolic link
test_must_fail git apply patch 2>error-wt &&
- test_i18ngrep "beyond a symbolic link" error-wt &&
+ test_grep "beyond a symbolic link" error-wt &&
test_path_is_missing arch/x86_64/dir &&
test_path_is_missing arch/i386/dir/file &&
test_must_fail git apply --index patch 2>error-ix &&
- test_i18ngrep "beyond a symbolic link" error-ix &&
+ test_grep "beyond a symbolic link" error-ix &&
test_path_is_missing arch/x86_64/dir &&
test_path_is_missing arch/i386/dir/file &&
test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
test_must_fail git ls-files --error-unmatch arch/i386/dir &&
test_must_fail git apply --cached patch 2>error-ct &&
- test_i18ngrep "beyond a symbolic link" error-ct &&
+ test_grep "beyond a symbolic link" error-ct &&
test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
test_must_fail git ls-files --error-unmatch arch/i386/dir &&
@@ -135,23 +134,23 @@ test_expect_success SYMLINKS 'do not follow symbolic link (existing)' '
git add arch/x86_64/dir &&
test_must_fail git apply add_file.patch 2>error-wt-add &&
- test_i18ngrep "beyond a symbolic link" error-wt-add &&
+ test_grep "beyond a symbolic link" error-wt-add &&
test_path_is_missing arch/i386/dir/file &&
mkdir arch/i386/dir &&
>arch/i386/dir/file &&
test_must_fail git apply del_file.patch 2>error-wt-del &&
- test_i18ngrep "beyond a symbolic link" error-wt-del &&
+ test_grep "beyond a symbolic link" error-wt-del &&
test_path_is_file arch/i386/dir/file &&
rm arch/i386/dir/file &&
test_must_fail git apply --index add_file.patch 2>error-ix-add &&
- test_i18ngrep "beyond a symbolic link" error-ix-add &&
+ test_grep "beyond a symbolic link" error-ix-add &&
test_path_is_missing arch/i386/dir/file &&
test_must_fail git ls-files --error-unmatch arch/i386/dir &&
test_must_fail git apply --cached add_file.patch 2>error-ct-file &&
- test_i18ngrep "beyond a symbolic link" error-ct-file &&
+ test_grep "beyond a symbolic link" error-ct-file &&
test_must_fail git ls-files --error-unmatch arch/i386/dir
'
diff --git a/t/t4126-apply-empty.sh b/t/t4126-apply-empty.sh
index ece9fae207..eff783f8d6 100755
--- a/t/t4126-apply-empty.sh
+++ b/t/t4126-apply-empty.sh
@@ -2,7 +2,6 @@
test_description='apply empty'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -66,4 +65,28 @@ test_expect_success 'apply --index create' '
git diff --exit-code
'
+test_expect_success !MINGW 'apply with no-contents and a funny pathname' '
+ test_when_finished "rm -fr \"funny \"; git reset --hard" &&
+
+ mkdir "funny " &&
+ >"funny /empty" &&
+ git add "funny /empty" &&
+ git diff HEAD -- "funny /" >sample.patch &&
+ git diff -R HEAD -- "funny /" >elpmas.patch &&
+
+ git reset --hard &&
+
+ git apply --stat --check --apply sample.patch &&
+ test_must_be_empty "funny /empty" &&
+
+ git apply --stat --check --apply elpmas.patch &&
+ test_path_is_missing "funny /empty" &&
+
+ git apply -R --stat --check --apply elpmas.patch &&
+ test_must_be_empty "funny /empty" &&
+
+ git apply -R --stat --check --apply sample.patch &&
+ test_path_is_missing "funny /empty"
+'
+
test_done
diff --git a/t/t4127-apply-same-fn.sh b/t/t4127-apply-same-fn.sh
index aa5cfae2b6..bd516c4aad 100755
--- a/t/t4127-apply-same-fn.sh
+++ b/t/t4127-apply-same-fn.sh
@@ -3,7 +3,6 @@
test_description='apply same filename'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
modify () {
diff --git a/t/t4128-apply-root.sh b/t/t4128-apply-root.sh
index ed94c90204..f6db5a79dd 100755
--- a/t/t4128-apply-root.sh
+++ b/t/t4128-apply-root.sh
@@ -2,7 +2,6 @@
test_description='apply same filename'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh
index a1c7686519..2149ad5da4 100755
--- a/t/t4129-apply-samemode.sh
+++ b/t/t4129-apply-samemode.sh
@@ -3,7 +3,6 @@
test_description='applying patch with mode bits'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -41,7 +40,8 @@ test_expect_success FILEMODE 'same mode (index only)' '
chmod +x file &&
git add file &&
git apply --cached patch-0.txt &&
- git ls-files -s file | grep "^100755"
+ git ls-files -s file >ls-files-output &&
+ test_grep "^100755" ls-files-output
'
test_expect_success FILEMODE 'mode update (no index)' '
@@ -60,19 +60,20 @@ test_expect_success FILEMODE 'mode update (with index)' '
test_expect_success FILEMODE 'mode update (index only)' '
git reset --hard &&
git apply --cached patch-1.txt &&
- git ls-files -s file | grep "^100755"
+ git ls-files -s file >ls-files-output &&
+ test_grep "^100755" ls-files-output
'
test_expect_success FILEMODE 'empty mode is rejected' '
git reset --hard &&
test_must_fail git apply patch-empty-mode.txt 2>err &&
- test_i18ngrep "invalid mode" err
+ test_grep "invalid mode" err
'
test_expect_success FILEMODE 'bogus mode is rejected' '
git reset --hard &&
test_must_fail git apply patch-bogus-mode.txt 2>err &&
- test_i18ngrep "invalid mode" err
+ test_grep "invalid mode" err
'
test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree files' '
@@ -101,4 +102,93 @@ test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree
)
'
+test_expect_success 'git apply respects core.fileMode' '
+ test_config core.fileMode false &&
+ echo true >script.sh &&
+ git add --chmod=+x script.sh &&
+ git ls-files -s script.sh >ls-files-output &&
+ test_grep "^100755" ls-files-output &&
+ test_tick && git commit -m "Add script" &&
+ git ls-tree -r HEAD script.sh >ls-tree-output &&
+ test_grep "^100755" ls-tree-output &&
+
+ echo true >>script.sh &&
+ test_tick && git commit -m "Modify script" script.sh &&
+ git format-patch -1 --stdout >patch &&
+ test_grep "^index.*100755$" patch &&
+
+ git switch -c branch HEAD^ &&
+ git apply --index patch 2>err &&
+ test_grep ! "has type 100644, expected 100755" err &&
+ git reset --hard &&
+
+ git apply patch 2>err &&
+ test_grep ! "has type 100644, expected 100755" err &&
+
+ git apply --cached patch 2>err &&
+ test_grep ! "has type 100644, expected 100755" err
+'
+
+test_expect_success POSIXPERM 'patch mode for new file is canonicalized' '
+ cat >patch <<-\EOF &&
+ diff --git a/non-canon b/non-canon
+ new file mode 100660
+ --- /dev/null
+ +++ b/non-canon
+ +content
+ EOF
+ test_when_finished "git reset --hard" &&
+ (
+ umask 0 &&
+ git apply --index patch 2>err
+ ) &&
+ test_must_be_empty err &&
+ git ls-files -s -- non-canon >staged &&
+ test_grep "^100644" staged &&
+ ls -l non-canon >worktree &&
+ test_grep "^-rw-rw-rw" worktree
+'
+
+test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '
+ test_when_finished "git reset --hard" &&
+ echo content >non-canon &&
+ chmod 666 non-canon &&
+ git add non-canon &&
+
+ cat >patch <<-\EOF &&
+ diff --git a/non-canon b/non-canon
+ deleted file mode 100660
+ --- a/non-canon
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -content
+ EOF
+ git apply --index patch 2>err &&
+ test_must_be_empty err &&
+ git ls-files -- non-canon >staged &&
+ test_must_be_empty staged &&
+ test_path_is_missing non-canon
+'
+
+test_expect_success POSIXPERM 'patch mode for mode change is canonicalized' '
+ test_when_finished "git reset --hard" &&
+ echo content >non-canon &&
+ git add non-canon &&
+
+ cat >patch <<-\EOF &&
+ diff --git a/non-canon b/non-canon
+ old mode 100660
+ new mode 100770
+ EOF
+ (
+ umask 0 &&
+ git apply --index patch 2>err
+ ) &&
+ test_must_be_empty err &&
+ git ls-files -s -- non-canon >staged &&
+ test_grep "^100755" staged &&
+ ls -l non-canon >worktree &&
+ test_grep "^-rwxrwxrwx" worktree
+'
+
test_done
diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh
index f3ea632742..211ef1c7e7 100755
--- a/t/t4130-apply-criss-cross-rename.sh
+++ b/t/t4130-apply-criss-cross-rename.sh
@@ -2,7 +2,6 @@
test_description='git apply handling criss-cross rename patch.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
create_file() {
diff --git a/t/t4132-apply-removal.sh b/t/t4132-apply-removal.sh
index c1e3049c04..ab1628d27d 100755
--- a/t/t4132-apply-removal.sh
+++ b/t/t4132-apply-removal.sh
@@ -5,7 +5,6 @@
test_description='git-apply notices removal patches generated by GNU diff'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4133-apply-filenames.sh b/t/t4133-apply-filenames.sh
index 35f1060bc8..3cab1038cf 100755
--- a/t/t4133-apply-filenames.sh
+++ b/t/t4133-apply-filenames.sh
@@ -6,7 +6,6 @@
test_description='git apply filename consistency check'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -32,9 +31,9 @@ EOF
test_expect_success 'apply diff with inconsistent filenames in headers' '
test_must_fail git apply bad1.patch 2>err &&
- test_i18ngrep "inconsistent new filename" err &&
+ test_grep "inconsistent new filename" err &&
test_must_fail git apply bad2.patch 2>err &&
- test_i18ngrep "inconsistent old filename" err
+ test_grep "inconsistent old filename" err
'
test_expect_success 'apply diff with new filename missing from headers' '
@@ -46,7 +45,7 @@ test_expect_success 'apply diff with new filename missing from headers' '
+1
EOF
test_must_fail git apply missing_new_filename.diff 2>err &&
- test_i18ngrep "lacks filename information" err
+ test_grep "lacks filename information" err
'
test_expect_success 'apply diff with old filename missing from headers' '
@@ -58,7 +57,7 @@ test_expect_success 'apply diff with old filename missing from headers' '
-1
EOF
test_must_fail git apply missing_old_filename.diff 2>err &&
- test_i18ngrep "lacks filename information" err
+ test_grep "lacks filename information" err
'
test_done
diff --git a/t/t4134-apply-submodule.sh b/t/t4134-apply-submodule.sh
index aceb4c42b0..8cea75cf7b 100755
--- a/t/t4134-apply-submodule.sh
+++ b/t/t4134-apply-submodule.sh
@@ -6,7 +6,6 @@
test_description='git apply submodule tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh
index d3502c6fdd..6bc3fb97a7 100755
--- a/t/t4135-apply-weird-filenames.sh
+++ b/t/t4135-apply-weird-filenames.sh
@@ -2,7 +2,6 @@
test_description='git apply with weird postimage filenames'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4136-apply-check.sh b/t/t4136-apply-check.sh
index dfec1c5f0f..82f2f2e475 100755
--- a/t/t4136-apply-check.sh
+++ b/t/t4136-apply-check.sh
@@ -3,7 +3,6 @@
test_description='git apply should exit non-zero with unrecognized input.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4139-apply-escape.sh b/t/t4139-apply-escape.sh
index e5c7439df1..e07fb9ef08 100755
--- a/t/t4139-apply-escape.sh
+++ b/t/t4139-apply-escape.sh
@@ -2,7 +2,6 @@
test_description='paths written by git-apply cannot escape the working tree'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# tests will try to write to ../foo, and we do not
diff --git a/t/t4140-apply-ita.sh b/t/t4140-apply-ita.sh
index b375aca0d7..c614eaf04c 100755
--- a/t/t4140-apply-ita.sh
+++ b/t/t4140-apply-ita.sh
@@ -2,7 +2,6 @@
test_description='git apply of i-t-a file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4141-apply-too-large.sh b/t/t4141-apply-too-large.sh
index 20cc1209f6..eac6f7e151 100755
--- a/t/t4141-apply-too-large.sh
+++ b/t/t4141-apply-too-large.sh
@@ -2,7 +2,6 @@
test_description='git apply with too-large patch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success EXPENSIVE 'git apply rejects patches that are too large' '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 2935fe1b2d..5e2b6c80ea 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -779,7 +779,7 @@ test_expect_success 'am --resolved fails if index has unmerged entries' '
test_must_fail git am --resolved >err &&
test_path_is_dir .git/rebase-apply &&
test_cmp_rev second HEAD &&
- test_i18ngrep "still have unmerged paths" err
+ test_grep "still have unmerged paths" err
'
test_expect_success 'am takes patches from a Pine mailbox' '
@@ -913,7 +913,7 @@ test_expect_success 'am newline in subject' '
test_tick &&
sed -e "s/second/second \\\n foo/" patch1 >patchnl &&
git am <patchnl >output.out 2>&1 &&
- test_i18ngrep "^Applying: second \\\n foo$" output.out
+ test_grep "^Applying: second \\\n foo$" output.out
'
test_expect_success 'am -q is quiet' '
@@ -1224,8 +1224,8 @@ test_expect_success 'record as an empty commit when meeting e-mail message that
test_expect_success 'skip an empty patch in the middle of an am session' '
git checkout empty-commit^ &&
- test_must_fail git am empty-commit.patch >err &&
- grep "Patch is empty." err &&
+ test_must_fail git am empty-commit.patch >out 2>err &&
+ grep "Patch is empty." out &&
grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
git am --skip &&
test_path_is_missing .git/rebase-apply &&
@@ -1236,8 +1236,8 @@ test_expect_success 'skip an empty patch in the middle of an am session' '
test_expect_success 'record an empty patch as an empty commit in the middle of an am session' '
git checkout empty-commit^ &&
- test_must_fail git am empty-commit.patch >err &&
- grep "Patch is empty." err &&
+ test_must_fail git am empty-commit.patch >out 2>err &&
+ grep "Patch is empty." out &&
grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
git am --allow-empty >output &&
grep "No changes - recorded it as an empty commit." output &&
diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh
index 5ed7e22827..edb38da701 100755
--- a/t/t4151-am-abort.sh
+++ b/t/t4151-am-abort.sh
@@ -46,7 +46,7 @@ do
test_expect_success "am$with3 --skip continue after failed am$with3" '
test_must_fail git am$with3 --skip >output &&
- test_i18ngrep "^Applying: 6$" output &&
+ test_grep "^Applying: 6$" output &&
test_cmp file-2-expect file-2 &&
test ! -f .git/MERGE_RR
'
diff --git a/t/t4152-am-subjects.sh b/t/t4152-am-subjects.sh
index 9f2edba1f8..768495b131 100755
--- a/t/t4152-am-subjects.sh
+++ b/t/t4152-am-subjects.sh
@@ -2,7 +2,6 @@
test_description='test subject preservation with format-patch | am'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
make_patches() {
diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
index b7c3861407..9bec989a0e 100755
--- a/t/t4153-am-resume-override-opts.sh
+++ b/t/t4153-am-resume-override-opts.sh
@@ -3,7 +3,6 @@
test_description='git-am command-line options override saved options'
. ./test-lib.sh
-. "$TEST_DIRECTORY"/lib-terminal.sh
format_patch () {
git format-patch --stdout -1 "$1" >"$1".eml
@@ -27,7 +26,12 @@ test_expect_success 'setup' '
format_patch side2
'
-test_expect_success TTY '--3way overrides --no-3way' '
+test_expect_success '--retry fails without in-progress operation' '
+ test_must_fail git am --retry 2>err &&
+ test_grep "operation not in progress" err
+'
+
+test_expect_success '--3way overrides --no-3way' '
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout renamed-file &&
@@ -40,7 +44,7 @@ test_expect_success TTY '--3way overrides --no-3way' '
# Applying side1 with am --3way will succeed due to the threeway-merge.
# Applying side2 will fail as --3way does not apply to it.
- test_must_fail test_terminal git am --3way </dev/zero &&
+ test_must_fail git am --retry --3way &&
test_path_is_dir .git/rebase-apply &&
test side1 = "$(cat file2)"
'
@@ -53,7 +57,7 @@ test_expect_success '--no-quiet overrides --quiet' '
# Applying side1 will be quiet.
test_must_fail git am --quiet side[123].eml >out &&
test_path_is_dir .git/rebase-apply &&
- test_i18ngrep ! "^Applying: " out &&
+ test_grep ! "^Applying: " out &&
echo side1 >file &&
git add file &&
@@ -84,7 +88,7 @@ test_expect_success '--signoff overrides --no-signoff' '
test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0
'
-test_expect_success TTY '--reject overrides --no-reject' '
+test_expect_success '--reject overrides --no-reject' '
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout first &&
@@ -94,7 +98,7 @@ test_expect_success TTY '--reject overrides --no-reject' '
test_path_is_dir .git/rebase-apply &&
test_path_is_missing file.rej &&
- test_must_fail test_terminal git am --reject </dev/zero &&
+ test_must_fail git am --retry --reject &&
test_path_is_dir .git/rebase-apply &&
test_path_is_file file.rej
'
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 7025cfdae5..b0a3e84984 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -433,13 +433,13 @@ test_expect_success 'rerere --no-no-rerere-autoupdate' '
git update-index --index-info <failedmerge &&
cp file3.conflict file3 &&
test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
- test_i18ngrep [Uu]sage err &&
+ test_grep [Uu]sage err &&
test_must_fail git update-index --refresh
'
test_expect_success 'rerere -h' '
test_must_fail git rerere -h >help &&
- test_i18ngrep [Uu]sage help
+ test_grep [Uu]sage help
'
concat_insert () {
@@ -671,4 +671,67 @@ test_expect_success 'test simple stage 1 handling' '
)
'
+test_expect_success 'rerere does not crash with missing preimage' '
+ git config rerere.enabled true &&
+
+ echo bar >test &&
+ git add test &&
+ git commit -m "one" &&
+ git branch rerere_no_crash &&
+
+ echo foo >>test &&
+ git add test &&
+ git commit -m "two" &&
+
+ git checkout rerere_no_crash &&
+ echo "bar" >>test &&
+ git add test &&
+ git commit -m "three" &&
+
+ test_must_fail git rebase main &&
+ rm .git/rr-cache/*/preimage &&
+ git rebase --abort
+'
+
+test_expect_success 'rerere does not crash with unmatched conflict marker' '
+ git config rerere.enabled true &&
+
+ echo bar >test &&
+ git add test &&
+ git commit -m "one" &&
+ git branch rerere_no_preimage &&
+
+ cat >test <<-EOF &&
+ test
+ bar
+ foobar
+ EOF
+ git add test &&
+ git commit -m "two" &&
+
+ git checkout rerere_no_preimage &&
+ echo "bar" >>test &&
+ git add test &&
+ git commit -m "three" &&
+
+ cat >test <<-EOF &&
+ foobar
+ bar
+ bar
+ EOF
+ git add test &&
+ git commit -m "four" &&
+
+ test_must_fail git rebase main &&
+ cat >test <<-EOF &&
+ test
+ bar
+ <<<<<<< HEAD
+ foobar
+ bar
+ EOF
+ git add test &&
+ test_must_fail git rebase --continue
+'
+
test_done
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 8e4effebdb..5f23fc147b 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -104,7 +104,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
test_cmp expect log.predictable
'
-test_expect_success !MINGW 'shortlog wrapping' '
+test_expect_success !MINGW,ICONV 'shortlog wrapping' '
cat >expect <<\EOF &&
A U Thor (5):
Test
@@ -125,13 +125,13 @@ EOF
test_cmp expect out
'
-test_expect_success !MINGW 'shortlog from non-git directory' '
+test_expect_success !MINGW,ICONV 'shortlog from non-git directory' '
git log --no-expand-tabs HEAD >log &&
GIT_DIR=non-existing git shortlog -w <log >out &&
test_cmp expect out
'
-test_expect_success !MINGW 'shortlog can read --format=raw output' '
+test_expect_success !MINGW,ICONV 'shortlog can read --format=raw output' '
git log --format=raw HEAD >log &&
GIT_DIR=non-existing git shortlog -w <log >out &&
test_cmp expect out
@@ -139,7 +139,11 @@ test_expect_success !MINGW 'shortlog can read --format=raw output' '
test_expect_success 'shortlog from non-git directory refuses extra arguments' '
test_must_fail env GIT_DIR=non-existing git shortlog foo 2>out &&
- test_i18ngrep "too many arguments" out
+ test_grep "too many arguments" out
+'
+
+test_expect_success 'shortlog --author from non-git directory does not segfault' '
+ nongit git shortlog --author=author </dev/null
'
test_expect_success 'shortlog should add newline when input line matches wraplen' '
@@ -181,7 +185,7 @@ $DSCHO (2):
EOF
-test_expect_success !MINGW 'shortlog encoding' '
+test_expect_success !MINGW,ICONV 'shortlog encoding' '
git reset --hard "$commit" &&
git config --unset i18n.commitencoding &&
echo 2 > a1 &&
@@ -312,6 +316,38 @@ test_expect_success 'shortlog de-duplicates trailers in a single commit' '
test_cmp expect actual
'
+# Trailers that have unfolded (single line) and folded (multiline) values which
+# are otherwise identical are treated as the same trailer for de-duplication.
+test_expect_success 'shortlog de-duplicates trailers in a single commit (folded/unfolded values)' '
+ git commit --allow-empty -F - <<-\EOF &&
+ subject one
+
+ this message has two distinct values, plus a repeat (folded)
+
+ Repeated-trailer: Foo foo foo
+ Repeated-trailer: Bar
+ Repeated-trailer: Foo
+ foo foo
+ EOF
+
+ git commit --allow-empty -F - <<-\EOF &&
+ subject two
+
+ similar to the previous, but without the second distinct value
+
+ Repeated-trailer: Foo foo foo
+ Repeated-trailer: Foo
+ foo foo
+ EOF
+
+ cat >expect <<-\EOF &&
+ 2 Foo foo foo
+ 1 Bar
+ EOF
+ git shortlog -ns --group=trailer:repeated-trailer -2 HEAD >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'shortlog can match multiple groups' '
git commit --allow-empty -F - <<-\EOF &&
subject one
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index af4a123cd2..51f7beb59f 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -1237,6 +1237,30 @@ test_expect_success 'log.abbrevCommit configuration' '
test_cmp expect.whatchanged.full actual
'
+test_expect_success '--abbrev-commit with core.abbrev=false' '
+ git log --no-abbrev >expect &&
+ git -c core.abbrev=false log --abbrev-commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--abbrev-commit with --no-abbrev' '
+ git log --no-abbrev >expect &&
+ git log --abbrev-commit --no-abbrev >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--abbrev-commit with core.abbrev=9000' '
+ git log --no-abbrev >expect &&
+ git -c core.abbrev=9000 log --abbrev-commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--abbrev-commit with --abbrev=9000' '
+ git log --no-abbrev >expect &&
+ git log --abbrev-commit --abbrev=9000 >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'show added path under "--follow -M"' '
# This tests for a regression introduced in v1.7.2-rc0~103^2~2
test_create_repo regression &&
@@ -1884,7 +1908,7 @@ test_expect_success '--no-graph does not unset --parents' '
test_expect_success '--reverse and --graph conflict' '
test_must_fail git log --reverse --graph 2>stderr &&
- test_i18ngrep "cannot be used together" stderr
+ test_grep "cannot be used together" stderr
'
test_expect_success '--reverse --graph --no-graph works' '
@@ -1895,7 +1919,7 @@ test_expect_success '--reverse --graph --no-graph works' '
test_expect_success '--show-linear-break and --graph conflict' '
test_must_fail git log --show-linear-break --graph 2>stderr &&
- test_i18ngrep "cannot be used together" stderr
+ test_grep "cannot be used together" stderr
'
test_expect_success '--show-linear-break --graph --no-graph works' '
@@ -1906,7 +1930,7 @@ test_expect_success '--show-linear-break --graph --no-graph works' '
test_expect_success '--no-walk and --graph conflict' '
test_must_fail git log --no-walk --graph 2>stderr &&
- test_i18ngrep "cannot be used together" stderr
+ test_grep "cannot be used together" stderr
'
test_expect_success '--no-walk --graph --no-graph works' '
@@ -1917,8 +1941,8 @@ test_expect_success '--no-walk --graph --no-graph works' '
test_expect_success '--walk-reflogs and --graph conflict' '
test_must_fail git log --walk-reflogs --graph 2>stderr &&
- (test_i18ngrep "cannot combine" stderr ||
- test_i18ngrep "cannot be used together" stderr)
+ (test_grep "cannot combine" stderr ||
+ test_grep "cannot be used together" stderr)
'
test_expect_success '--walk-reflogs --graph --no-graph works' '
@@ -2022,7 +2046,7 @@ test_expect_success GPGSM 'log --graph --show-signature x509' '
test_expect_success GPGSSH 'log --graph --show-signature ssh' '
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
git log --graph --show-signature -n1 signed-ssh >actual &&
- grep "${GOOD_SIGNATURE_TRUSTED}" actual
+ grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
'
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure on expired signature key' '
@@ -2252,24 +2276,7 @@ test_expect_success 'log on empty repo fails' '
git init empty &&
test_when_finished "rm -rf empty" &&
test_must_fail git -C empty log 2>stderr &&
- test_i18ngrep does.not.have.any.commits stderr
-'
-
-test_expect_success REFFILES 'log diagnoses bogus HEAD hash' '
- git init empty &&
- test_when_finished "rm -rf empty" &&
- echo 1234abcd >empty/.git/refs/heads/main &&
- test_must_fail git -C empty log 2>stderr &&
- test_i18ngrep broken stderr
-'
-
-test_expect_success REFFILES 'log diagnoses bogus HEAD symref' '
- git init empty &&
- echo "ref: refs/heads/invalid.lock" > empty/.git/HEAD &&
- test_must_fail git -C empty log 2>stderr &&
- test_i18ngrep broken stderr &&
- test_must_fail git -C empty log --default totally-bogus 2>stderr &&
- test_i18ngrep broken stderr
+ test_grep does.not.have.any.commits stderr
'
test_expect_success 'log does not default to HEAD when rev input is given' '
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 2016132f51..2421491931 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -71,12 +71,46 @@ test_expect_success 'check-mailmap --stdin arguments: mapping' '
test_cmp expect actual
'
-test_expect_success 'check-mailmap bogus contact' '
- test_must_fail git check-mailmap bogus
+test_expect_success 'check-mailmap simple address: mapping' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-EOF &&
+ New Name <$GIT_AUTHOR_EMAIL>
+ EOF
+ cat .mailmap >expect &&
+ git check-mailmap "$GIT_AUTHOR_EMAIL" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap --stdin simple address: mapping' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-EOF &&
+ New Name <$GIT_AUTHOR_EMAIL>
+ EOF
+ cat >stdin <<-EOF &&
+ $GIT_AUTHOR_EMAIL
+ EOF
+ cat .mailmap >expect &&
+ git check-mailmap --stdin <stdin >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap simple address: no mapping' '
+ cat >expect <<-EOF &&
+ <bugs@company.xx>
+ EOF
+ git check-mailmap "bugs@company.xx" >actual &&
+ test_cmp expect actual
'
-test_expect_success 'check-mailmap bogus contact --stdin' '
- test_must_fail git check-mailmap --stdin bogus </dev/null
+test_expect_success 'check-mailmap --stdin simple address: no mapping' '
+ cat >expect <<-EOF &&
+ <bugs@company.xx>
+ EOF
+ cat >stdin <<-EOF &&
+ bugs@company.xx
+ EOF
+ git check-mailmap --stdin <stdin >actual &&
+ test_cmp expect actual
'
test_expect_success 'No mailmap' '
@@ -360,7 +394,7 @@ test_expect_success 'mailmap.blob might be the wrong type' '
cp default.map .mailmap &&
git -c mailmap.blob=HEAD: shortlog HEAD >actual 2>err &&
- test_i18ngrep "mailmap is not a blob" err &&
+ test_grep "mailmap is not a blob" err &&
test_cmp expect actual
'
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index a7fa94ce0a..605faea0c7 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -310,4 +310,38 @@ test_expect_success 'patch-id handles diffs with one line of before/after' '
test_config patchid.stable true &&
calc_patch_id diffu1stable <diffu1
'
+
+test_expect_failure 'patch-id computes same ID with different object hashes' '
+ test_when_finished "rm -rf repo-sha1 repo-sha256" &&
+
+ cat >diff <<-\EOF &&
+ diff --git a/bar b/bar
+ index bdaf90f..31051f6 100644
+ --- a/bar
+ +++ b/bar
+ @@ -2 +2,2 @@
+ b
+ +c
+ EOF
+
+ git init --object-format=sha1 repo-sha1 &&
+ git -C repo-sha1 patch-id <diff >patch-id-sha1 &&
+ git init --object-format=sha256 repo-sha256 &&
+ git -C repo-sha256 patch-id <diff >patch-id-sha256 &&
+ test_cmp patch-id-sha1 patch-id-sha256
+'
+
+test_expect_success 'patch-id without repository' '
+ cat >diff <<-\EOF &&
+ diff --git a/bar b/bar
+ index bdaf90f..31051f6 100644
+ --- a/bar
+ +++ b/bar
+ @@ -2 +2,2 @@
+ b
+ +c
+ EOF
+ nongit git patch-id <diff
+'
+
test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index dd9035aa38..f81e42a84d 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -5,6 +5,7 @@
#
test_description='Test pretty formats'
+
. ./test-lib.sh
# Tested non-UTF-8 encoding
@@ -30,40 +31,46 @@ test_expect_success 'set up basic repos' '
>bar &&
git add foo &&
test_tick &&
- git config i18n.commitEncoding $test_encoding &&
+ test_config i18n.commitEncoding $test_encoding &&
commit_msg $test_encoding | git commit -F - &&
git add bar &&
test_tick &&
- git commit -m "add bar" &&
- git config --unset i18n.commitEncoding
+ git commit -m "add bar"
'
test_expect_success 'alias builtin format' '
git log --pretty=oneline >expected &&
- git config pretty.test-alias oneline &&
+ test_config pretty.test-alias oneline &&
git log --pretty=test-alias >actual &&
test_cmp expected actual
'
test_expect_success 'alias masking builtin format' '
git log --pretty=oneline >expected &&
- git config pretty.oneline "%H" &&
+ test_config pretty.oneline "%H" &&
git log --pretty=oneline >actual &&
test_cmp expected actual
'
test_expect_success 'alias user-defined format' '
git log --pretty="format:%h" >expected &&
- git config pretty.test-alias "format:%h" &&
+ test_config pretty.test-alias "format:%h" &&
git log --pretty=test-alias >actual &&
test_cmp expected actual
'
+test_expect_success 'alias user-defined format is matched case-insensitively' '
+ git log --pretty="format:%h" >expected &&
+ test_config pretty.testone "format:%h" &&
+ test_config pretty.testtwo testOne &&
+ git log --pretty=testTwo >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'alias user-defined tformat with %s (ISO8859-1 encoding)' '
- git config i18n.logOutputEncoding $test_encoding &&
+ test_config i18n.logOutputEncoding $test_encoding &&
git log --oneline >expected-s &&
git log --pretty="tformat:%h %s" >actual-s &&
- git config --unset i18n.logOutputEncoding &&
test_cmp expected-s actual-s
'
@@ -75,50 +82,50 @@ test_expect_success 'alias user-defined tformat with %s (utf-8 encoding)' '
test_expect_success 'alias user-defined tformat' '
git log --pretty="tformat:%h" >expected &&
- git config pretty.test-alias "tformat:%h" &&
+ test_config pretty.test-alias "tformat:%h" &&
git log --pretty=test-alias >actual &&
test_cmp expected actual
'
test_expect_success 'alias non-existent format' '
- git config pretty.test-alias format-that-will-never-exist &&
+ test_config pretty.test-alias format-that-will-never-exist &&
test_must_fail git log --pretty=test-alias
'
test_expect_success 'alias of an alias' '
git log --pretty="tformat:%h" >expected &&
- git config pretty.test-foo "tformat:%h" &&
- git config pretty.test-bar test-foo &&
+ test_config pretty.test-foo "tformat:%h" &&
+ test_config pretty.test-bar test-foo &&
git log --pretty=test-bar >actual && test_cmp expected actual
'
test_expect_success 'alias masking an alias' '
git log --pretty=format:"Two %H" >expected &&
- git config pretty.duplicate "format:One %H" &&
- git config --add pretty.duplicate "format:Two %H" &&
+ test_config pretty.duplicate "format:One %H" &&
+ test_config pretty.duplicate "format:Two %H" --add &&
git log --pretty=duplicate >actual &&
test_cmp expected actual
'
test_expect_success 'alias loop' '
- git config pretty.test-foo test-bar &&
- git config pretty.test-bar test-foo &&
+ test_config pretty.test-foo test-bar &&
+ test_config pretty.test-bar test-foo &&
test_must_fail git log --pretty=test-foo
'
-test_expect_success 'NUL separation' '
+test_expect_success ICONV 'NUL separation' '
printf "add bar\0$(commit_msg)" >expected &&
git log -z --pretty="format:%s" >actual &&
test_cmp expected actual
'
-test_expect_success 'NUL termination' '
+test_expect_success ICONV 'NUL termination' '
printf "add bar\0$(commit_msg)\0" >expected &&
git log -z --pretty="tformat:%s" >actual &&
test_cmp expected actual
'
-test_expect_success 'NUL separation with --stat' '
+test_expect_success ICONV 'NUL separation with --stat' '
stat0_part=$(git diff --stat HEAD^ HEAD) &&
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n" >expected &&
@@ -129,7 +136,7 @@ test_expect_success 'NUL separation with --stat' '
test_expect_failure 'NUL termination with --stat' '
stat0_part=$(git diff --stat HEAD^ HEAD) &&
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
- printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n0" >expected &&
+ printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n\0" >expected &&
git log -z --stat --pretty="tformat:%s" >actual &&
test_cmp expected actual
'
@@ -156,7 +163,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '
for r in $revs
do
git show -s --pretty=oneline "$r" >raw &&
- cat raw | lf_to_nul || return 1
+ lf_to_nul <raw || return 1
done >expect &&
# the trailing NUL is already produced so we do not need to
# output another one
@@ -173,7 +180,7 @@ test_expect_success 'setup more commits' '
head4=$(git rev-parse --verify --short HEAD~3)
'
-test_expect_success 'left alignment formatting' '
+test_expect_success ICONV 'left alignment formatting' '
git log --pretty="tformat:%<(40)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
message two Z
@@ -184,7 +191,7 @@ test_expect_success 'left alignment formatting' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting. i18n.logOutputEncoding' '
+test_expect_success ICONV 'left alignment formatting. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(40)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
message two Z
@@ -195,7 +202,7 @@ test_expect_success 'left alignment formatting. i18n.logOutputEncoding' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting at the nth column' '
+test_expect_success ICONV 'left alignment formatting at the nth column' '
git log --pretty="tformat:%h %<|(40)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
$head1 message two Z
@@ -206,7 +213,7 @@ test_expect_success 'left alignment formatting at the nth column' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting at the nth column' '
+test_expect_success ICONV 'left alignment formatting at the nth column' '
COLUMNS=50 git log --pretty="tformat:%h %<|(-10)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
$head1 message two Z
@@ -217,7 +224,7 @@ test_expect_success 'left alignment formatting at the nth column' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting at the nth column. i18n.logOutputEncoding' '
+test_expect_success ICONV 'left alignment formatting at the nth column. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%h %<|(40)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
$head1 message two Z
@@ -228,7 +235,7 @@ test_expect_success 'left alignment formatting at the nth column. i18n.logOutput
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with no padding' '
+test_expect_success ICONV 'left alignment formatting with no padding' '
git log --pretty="tformat:%<(1)%s" >actual &&
cat <<-EOF >expected &&
message two
@@ -250,7 +257,7 @@ test_expect_success 'left alignment formatting with no padding. i18n.logOutputEn
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with trunc' '
+test_expect_success ICONV 'left alignment formatting with trunc' '
git log --pretty="tformat:%<(10,trunc)%s" >actual &&
qz_to_tab_space <<-\EOF >expected &&
message ..
@@ -261,7 +268,7 @@ test_expect_success 'left alignment formatting with trunc' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with trunc. i18n.logOutputEncoding' '
+test_expect_success ICONV 'left alignment formatting with trunc. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,trunc)%s" >actual &&
qz_to_tab_space <<-\EOF | iconv -f utf-8 -t $test_encoding >expected &&
message ..
@@ -272,7 +279,7 @@ test_expect_success 'left alignment formatting with trunc. i18n.logOutputEncodin
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with ltrunc' '
+test_expect_success ICONV 'left alignment formatting with ltrunc' '
git log --pretty="tformat:%<(10,ltrunc)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
..sage two
@@ -283,7 +290,7 @@ test_expect_success 'left alignment formatting with ltrunc' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with ltrunc. i18n.logOutputEncoding' '
+test_expect_success ICONV 'left alignment formatting with ltrunc. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,ltrunc)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
..sage two
@@ -294,7 +301,7 @@ test_expect_success 'left alignment formatting with ltrunc. i18n.logOutputEncodi
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with mtrunc' '
+test_expect_success ICONV 'left alignment formatting with mtrunc' '
git log --pretty="tformat:%<(10,mtrunc)%s" >actual &&
qz_to_tab_space <<-\EOF >expected &&
mess.. two
@@ -305,7 +312,7 @@ test_expect_success 'left alignment formatting with mtrunc' '
test_cmp expected actual
'
-test_expect_success 'left alignment formatting with mtrunc. i18n.logOutputEncoding' '
+test_expect_success ICONV 'left alignment formatting with mtrunc. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,mtrunc)%s" >actual &&
qz_to_tab_space <<-\EOF | iconv -f utf-8 -t $test_encoding >expected &&
mess.. two
@@ -316,7 +323,7 @@ test_expect_success 'left alignment formatting with mtrunc. i18n.logOutputEncodi
test_cmp expected actual
'
-test_expect_success 'right alignment formatting' '
+test_expect_success ICONV 'right alignment formatting' '
git log --pretty="tformat:%>(40)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
Z message two
@@ -327,7 +334,7 @@ test_expect_success 'right alignment formatting' '
test_cmp expected actual
'
-test_expect_success 'right alignment formatting. i18n.logOutputEncoding' '
+test_expect_success ICONV 'right alignment formatting. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%>(40)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
Z message two
@@ -338,7 +345,7 @@ test_expect_success 'right alignment formatting. i18n.logOutputEncoding' '
test_cmp expected actual
'
-test_expect_success 'right alignment formatting at the nth column' '
+test_expect_success ICONV 'right alignment formatting at the nth column' '
git log --pretty="tformat:%h %>|(40)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
$head1 message two
@@ -349,7 +356,7 @@ test_expect_success 'right alignment formatting at the nth column' '
test_cmp expected actual
'
-test_expect_success 'right alignment formatting at the nth column' '
+test_expect_success ICONV 'right alignment formatting at the nth column' '
COLUMNS=50 git log --pretty="tformat:%h %>|(-10)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
$head1 message two
@@ -360,7 +367,7 @@ test_expect_success 'right alignment formatting at the nth column' '
test_cmp expected actual
'
-test_expect_success 'right alignment formatting at the nth column. i18n.logOutputEncoding' '
+test_expect_success ICONV 'right alignment formatting at the nth column. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%h %>|(40)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
$head1 message two
@@ -373,7 +380,7 @@ test_expect_success 'right alignment formatting at the nth column. i18n.logOutpu
# Note: Space between 'message' and 'two' should be in the same column
# as in previous test.
-test_expect_success 'right alignment formatting at the nth column with --graph. i18n.logOutputEncoding' '
+test_expect_success ICONV 'right alignment formatting at the nth column with --graph. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --graph --pretty="tformat:%h %>|(40)%s" >actual &&
iconv -f utf-8 -t $test_encoding >expected <<-EOF &&
* $head1 message two
@@ -384,7 +391,7 @@ test_expect_success 'right alignment formatting at the nth column with --graph.
test_cmp expected actual
'
-test_expect_success 'right alignment formatting with no padding' '
+test_expect_success ICONV 'right alignment formatting with no padding' '
git log --pretty="tformat:%>(1)%s" >actual &&
cat <<-EOF >expected &&
message two
@@ -395,7 +402,7 @@ test_expect_success 'right alignment formatting with no padding' '
test_cmp expected actual
'
-test_expect_success 'right alignment formatting with no padding and with --graph' '
+test_expect_success ICONV 'right alignment formatting with no padding and with --graph' '
git log --graph --pretty="tformat:%>(1)%s" >actual &&
cat <<-EOF >expected &&
* message two
@@ -406,7 +413,7 @@ test_expect_success 'right alignment formatting with no padding and with --graph
test_cmp expected actual
'
-test_expect_success 'right alignment formatting with no padding. i18n.logOutputEncoding' '
+test_expect_success ICONV 'right alignment formatting with no padding. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%>(1)%s" >actual &&
cat <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
message two
@@ -417,7 +424,7 @@ test_expect_success 'right alignment formatting with no padding. i18n.logOutputE
test_cmp expected actual
'
-test_expect_success 'center alignment formatting' '
+test_expect_success ICONV 'center alignment formatting' '
git log --pretty="tformat:%><(40)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
Z message two Z
@@ -428,7 +435,7 @@ test_expect_success 'center alignment formatting' '
test_cmp expected actual
'
-test_expect_success 'center alignment formatting. i18n.logOutputEncoding' '
+test_expect_success ICONV 'center alignment formatting. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%><(40)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
Z message two Z
@@ -438,7 +445,7 @@ test_expect_success 'center alignment formatting. i18n.logOutputEncoding' '
EOF
test_cmp expected actual
'
-test_expect_success 'center alignment formatting at the nth column' '
+test_expect_success ICONV 'center alignment formatting at the nth column' '
git log --pretty="tformat:%h %><|(40)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
$head1 message two Z
@@ -449,7 +456,7 @@ test_expect_success 'center alignment formatting at the nth column' '
test_cmp expected actual
'
-test_expect_success 'center alignment formatting at the nth column' '
+test_expect_success ICONV 'center alignment formatting at the nth column' '
COLUMNS=70 git log --pretty="tformat:%h %><|(-30)%s" >actual &&
qz_to_tab_space <<-EOF >expected &&
$head1 message two Z
@@ -460,7 +467,7 @@ test_expect_success 'center alignment formatting at the nth column' '
test_cmp expected actual
'
-test_expect_success 'center alignment formatting at the nth column. i18n.logOutputEncoding' '
+test_expect_success ICONV 'center alignment formatting at the nth column. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%h %><|(40)%s" >actual &&
qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
$head1 message two Z
@@ -471,7 +478,7 @@ test_expect_success 'center alignment formatting at the nth column. i18n.logOutp
test_cmp expected actual
'
-test_expect_success 'center alignment formatting with no padding' '
+test_expect_success ICONV 'center alignment formatting with no padding' '
git log --pretty="tformat:%><(1)%s" >actual &&
cat <<-EOF >expected &&
message two
@@ -485,7 +492,7 @@ test_expect_success 'center alignment formatting with no padding' '
# save HEAD's SHA-1 digest (with no abbreviations) to use it below
# as far as the next test amends HEAD
old_head1=$(git rev-parse --verify HEAD~0)
-test_expect_success 'center alignment formatting with no padding. i18n.logOutputEncoding' '
+test_expect_success ICONV 'center alignment formatting with no padding. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%><(1)%s" >actual &&
cat <<-EOF | iconv -f utf-8 -t $test_encoding >expected &&
message two
@@ -496,7 +503,7 @@ test_expect_success 'center alignment formatting with no padding. i18n.logOutput
test_cmp expected actual
'
-test_expect_success 'left/right alignment formatting with stealing' '
+test_expect_success ICONV 'left/right alignment formatting with stealing' '
git commit --amend -m short --author "long long long <long@me.com>" &&
git log --pretty="tformat:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual &&
cat <<-\EOF >expected &&
@@ -507,7 +514,7 @@ test_expect_success 'left/right alignment formatting with stealing' '
EOF
test_cmp expected actual
'
-test_expect_success 'left/right alignment formatting with stealing. i18n.logOutputEncoding' '
+test_expect_success ICONV 'left/right alignment formatting with stealing. i18n.logOutputEncoding' '
git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual &&
cat <<-\EOF | iconv -f utf-8 -t $test_encoding >expected &&
short long long long
@@ -556,26 +563,74 @@ test_expect_success 'log decoration properly follows tag chain' '
git tag -d tag1 &&
git commit --amend -m shorter &&
git log --no-walk --tags --pretty="%H %d" --decorate=full >actual &&
- cat <<-EOF >expected &&
- $head2 (tag: refs/tags/message-one)
- $old_head1 (tag: refs/tags/message-two)
- $head1 (tag: refs/tags/tag2)
- EOF
+ if test_have_prereq ICONV
+ then
+ cat <<-EOF >expected
+ $head2 (tag: refs/tags/message-one)
+ $old_head1 (tag: refs/tags/message-two)
+ $head1 (tag: refs/tags/tag2)
+ EOF
+ else
+ cat <<-EOF >expected
+ $head2 (tag: refs/tags/message-one)
+ $old_head1 (tag: refs/tags/tag2, tag: refs/tags/message-two)
+ EOF
+ fi &&
sort -k3 actual >actual1 &&
test_cmp expected actual1
'
test_expect_success 'clean log decoration' '
git log --no-walk --tags --pretty="%H %D" --decorate=full >actual &&
- cat >expected <<-EOF &&
- $head2 tag: refs/tags/message-one
- $old_head1 tag: refs/tags/message-two
- $head1 tag: refs/tags/tag2
- EOF
+ if test_have_prereq ICONV
+ then
+ cat <<-EOF >expected
+ $head2 tag: refs/tags/message-one
+ $old_head1 tag: refs/tags/message-two
+ $head1 tag: refs/tags/tag2
+ EOF
+ else
+ cat <<-EOF >expected
+ $head2 tag: refs/tags/message-one
+ $old_head1 tag: refs/tags/tag2, tag: refs/tags/message-two
+ EOF
+ fi &&
sort -k3 actual >actual1 &&
test_cmp expected actual1
'
+test_expect_success 'pretty format %decorate' '
+ git checkout -b foo &&
+ git commit --allow-empty -m "new commit" &&
+ git tag bar &&
+ git branch qux &&
+
+ echo " (HEAD -> foo, tag: bar, qux)" >expect1 &&
+ git log --format="%(decorate)" -1 >actual1 &&
+ test_cmp expect1 actual1 &&
+
+ echo "HEAD -> foo, tag: bar, qux" >expect2 &&
+ git log --format="%(decorate:prefix=,suffix=)" -1 >actual2 &&
+ test_cmp expect2 actual2 &&
+
+ echo "[ bar; qux; foo ]" >expect3 &&
+ git log --format="%(decorate:prefix=[ ,suffix= ],separator=%x3B ,tag=)" \
+ --decorate-refs=refs/ -1 >actual3 &&
+ test_cmp expect3 actual3 &&
+
+ # Try with a typo (in "separator"), in which case the placeholder should
+ # not be replaced.
+ echo "%(decorate:prefix=[ ,suffix= ],separater=; )" >expect4 &&
+ git log --format="%(decorate:prefix=[ ,suffix= ],separater=%x3B )" \
+ -1 >actual4 &&
+ test_cmp expect4 actual4 &&
+
+ echo "HEAD->foo bar qux" >expect5 &&
+ git log --format="%(decorate:prefix=,suffix=,separator= ,tag=,pointer=->)" \
+ -1 >actual5 &&
+ test_cmp expect5 actual5
+'
+
cat >trailers <<EOF
Signed-off-by: A U Thor <author@example.com>
Acked-by: A U Thor <author@example.com>
@@ -924,6 +979,36 @@ test_expect_success '%S in git log --format works with other placeholders (part
test_cmp expect actual
'
+test_expect_success 'setup more commits for %S with --bisect' '
+ test_commit four &&
+ test_commit five &&
+
+ head1=$(git rev-parse --verify HEAD~0) &&
+ head2=$(git rev-parse --verify HEAD~1) &&
+ head3=$(git rev-parse --verify HEAD~2) &&
+ head4=$(git rev-parse --verify HEAD~3)
+'
+
+test_expect_success '%S with --bisect labels commits with refs/bisect/bad ref' '
+ git update-ref refs/bisect/bad-$head1 $head1 &&
+ git update-ref refs/bisect/go $head1 &&
+ git update-ref refs/bisect/bad-$head2 $head2 &&
+ git update-ref refs/bisect/b $head3 &&
+ git update-ref refs/bisect/bad-$head4 $head4 &&
+ git update-ref refs/bisect/good-$head4 $head4 &&
+
+ # We expect to see the range of commits betwee refs/bisect/good-$head4
+ # and refs/bisect/bad-$head1. The "source" ref is the nearest bisect ref
+ # from which the commit is reachable.
+ cat >expect <<-EOF &&
+ $head1 refs/bisect/bad-$head1
+ $head2 refs/bisect/bad-$head2
+ $head3 refs/bisect/bad-$head2
+ EOF
+ git log --bisect --format="%H %S" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'log --pretty=reference' '
git log --pretty="tformat:%h (%s, %as)" >expect &&
git log --pretty=reference >actual &&
diff --git a/t/t4206-log-follow-harder-copies.sh b/t/t4206-log-follow-harder-copies.sh
index 9167b0351f..bcab71c8e8 100755
--- a/t/t4206-log-follow-harder-copies.sh
+++ b/t/t4206-log-follow-harder-copies.sh
@@ -7,7 +7,6 @@ test_description='Test --follow should always find copies hard in git log.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index ded33a82e2..0614511656 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -8,7 +8,6 @@ test_description='test "git log --decorate" colors'
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 '
@@ -53,35 +52,45 @@ cmp_filtered_decorations () {
# to this test since it does not contain any decoration, hence --first-parent
test_expect_success 'commit decorations colored correctly' '
cat >expect <<-EOF &&
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
-${c_reset}${c_branch}main${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit}, \
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\
+${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \
${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset} \
-On main: Changes to A.t
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
EOF
git log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&
cmp_filtered_decorations
'
+remove_replace_refs () {
+ git for-each-ref 'refs/replace*/**' --format='delete %(refname)' >in &&
+ git update-ref --stdin <in &&
+ rm in
+}
+
test_expect_success 'test coloring with replace-objects' '
- test_when_finished rm -rf .git/refs/replace* &&
+ test_when_finished remove_replace_refs &&
test_commit C &&
test_commit D &&
git replace HEAD~1 HEAD~2 &&
cat >expect <<-EOF &&
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
-${c_reset}${c_branch}main${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: D${c_reset}${c_commit})${c_reset} D
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: C${c_reset}${c_commit}, \
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\
+${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \
${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
EOF
git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
@@ -95,18 +104,20 @@ EOF
'
test_expect_success 'test coloring with grafted commit' '
- test_when_finished rm -rf .git/refs/replace* &&
+ test_when_finished remove_replace_refs &&
git replace --graft HEAD HEAD~2 &&
cat >expect <<-EOF &&
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
-${c_reset}${c_branch}main${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: D${c_reset}${c_commit}, \
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\
+${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \
${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
- ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
+ ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
EOF
git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh
index 2e8f5ad7b8..806b2809d4 100755
--- a/t/t4208-log-magic-pathspec.sh
+++ b/t/t4208-log-magic-pathspec.sh
@@ -21,7 +21,7 @@ test_expect_success '"git log :/" should not be ambiguous' '
test_expect_success '"git log :/a" should be ambiguous (applied both rev and worktree)' '
: >a &&
test_must_fail git log :/a 2>error &&
- test_i18ngrep ambiguous error
+ test_grep ambiguous error
'
test_expect_success '"git log :/a -- " should not be ambiguous' '
@@ -65,7 +65,7 @@ test_expect_success '"git log :/in" should not be ambiguous' '
test_expect_success '"git log :" should be ambiguous' '
test_must_fail git log : 2>error &&
- test_i18ngrep ambiguous error
+ test_grep ambiguous error
'
test_expect_success 'git log -- :' '
@@ -104,7 +104,7 @@ test_expect_success '"git log :(exclude)sub --" must resolve as an object' '
test_expect_success '"git log :(unknown-magic) complains of bogus magic' '
test_must_fail git log ":(unknown-magic)" 2>error &&
- test_i18ngrep pathspec.magic error
+ test_grep pathspec.magic error
'
test_expect_success 'command line pathspec parsing for "git log"' '
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
index 7f6bb27f14..a675ace081 100755
--- a/t/t4209-log-pickaxe.sh
+++ b/t/t4209-log-pickaxe.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='log --grep/--author/--regexp-ignore-case/-S/-G'
+
. ./test-lib.sh
test_log () {
@@ -57,10 +58,10 @@ test_expect_success setup '
test_expect_success 'usage' '
test_expect_code 129 git log -S 2>err &&
- test_i18ngrep "switch.*requires a value" err &&
+ test_grep "switch.*requires a value" err &&
test_expect_code 129 git log -G 2>err &&
- test_i18ngrep "switch.*requires a value" err &&
+ test_grep "switch.*requires a value" err &&
test_expect_code 128 git log -Gregex -Sstring 2>err &&
grep "cannot be used together" err &&
diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh
index d2dfcf164e..26dda0db38 100755
--- a/t/t4210-log-i18n.sh
+++ b/t/t4210-log-i18n.sh
@@ -1,8 +1,15 @@
#!/bin/sh
test_description='test log with i18n features'
+
. ./lib-gettext.sh
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping log i18n tests; iconv not available'
+ test_done
+fi
+
# two forms of é
utf8_e=$(printf '\303\251')
latin1_e=$(printf '\351')
@@ -64,7 +71,7 @@ test_expect_success 'log --grep does not find non-reencoded values (latin1)' '
'
triggers_undefined_behaviour () {
- local engine=$1
+ local engine="$1"
case $engine in
fixed)
@@ -85,7 +92,7 @@ triggers_undefined_behaviour () {
}
mismatched_git_log () {
- local pattern=$1
+ local pattern="$1"
LC_ALL=$is_IS_locale git log --encoding=ISO-8859-1 --format=%s \
--grep=$pattern
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index c6540e822f..950451cf6a 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -19,7 +19,7 @@ test_expect_success 'basic command line parsing' '
# -L requires there is no pathspec
test_must_fail git log -L1,1:b.c -- b.c 2>error &&
- test_i18ngrep "cannot be used with pathspec" error &&
+ test_grep "cannot be used with pathspec" error &&
# This would fail because --follow wants a single path, but
# we may fail due to incompatibility between -L/--follow in
@@ -50,7 +50,7 @@ canned_test_failure () {
test_bad_opts () {
test_expect_success "invalid args: $1" "
test_must_fail git log $1 2>errors &&
- test_i18ngrep '$2' errors
+ test_grep '$2' errors
"
}
@@ -337,4 +337,32 @@ test_expect_success 'zero-width regex .* matches any function name' '
test_cmp expect actual
'
+test_expect_success 'show line-log with graph' '
+ qz_to_tab_space >expect <<-EOF &&
+ * $head_oid Modify func2() in file.c
+ |Z
+ | diff --git a/file.c b/file.c
+ | --- a/file.c
+ | +++ b/file.c
+ | @@ -6,4 +6,4 @@
+ | int func2()
+ | {
+ | - return F2;
+ | + return F2 + 2;
+ | }
+ * $root_oid Add func1() and func2() in file.c
+ ZZ
+ diff --git a/file.c b/file.c
+ --- /dev/null
+ +++ b/file.c
+ @@ -0,0 +6,4 @@
+ +int func2()
+ +{
+ + return F2;
+ +}
+ EOF
+ git log --graph --oneline -L:func2:file.c >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
index 85e90acb09..64d818bc70 100755
--- a/t/t4212-log-corrupt.sh
+++ b/t/t4212-log-corrupt.sh
@@ -2,7 +2,6 @@
test_description='git log with invalid commit headers'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -17,7 +16,7 @@ test_expect_success 'setup' '
test_expect_success 'fsck notices broken commit' '
test_must_fail git fsck 2>actual &&
- test_i18ngrep invalid.author actual
+ test_grep invalid.author actual
'
test_expect_success 'git log with broken author email' '
diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh
index 590fce95e9..53a4af3244 100755
--- a/t/t4213-log-tabexpand.sh
+++ b/t/t4213-log-tabexpand.sh
@@ -2,7 +2,6 @@
test_description='log/show --expand-tabs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
HT=" "
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index fa9d32facf..3f163dc396 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -5,6 +5,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
GIT_TEST_COMMIT_GRAPH=0
GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
@@ -81,7 +82,23 @@ test_bloom_filters_used () {
test_bloom_filters_not_used () {
log_args=$1
setup "$log_args" &&
- ! grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf" &&
+
+ if grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf"
+ then
+ # if the Bloom filter system is initialized, ensure that no
+ # filters were used
+ data="statistics:{"
+ # unusable filters (e.g., those computed with a
+ # different value of commitGraph.changedPathsVersion)
+ # are counted in the filter_not_present bucket, so any
+ # value is OK there.
+ data="$data\"filter_not_present\":[0-9][0-9]*,"
+ data="$data\"maybe\":0,"
+ data="$data\"definitely_not\":0,"
+ data="$data\"false_positive\":0}"
+
+ grep -q "$data" "$TRASH_DIRECTORY/trace.perf"
+ fi &&
test_cmp log_wo_bloom log_w_bloom
}
@@ -162,7 +179,7 @@ test_expect_success 'setup - add commit-graph to the chain with Bloom filters' '
test_bloom_filters_used_when_some_filters_are_missing () {
log_args=$1
- bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":9"
+ bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":10"
setup "$log_args" &&
grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
test_cmp log_wo_bloom log_w_bloom
@@ -205,6 +222,10 @@ test_filter_trunc_large () {
grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2
}
+test_filter_upgraded () {
+ grep "\"key\":\"filter-upgraded\",\"value\":\"$1\"" $2
+}
+
test_expect_success 'correctly report changes over limit' '
git init limits &&
(
@@ -404,4 +425,352 @@ test_expect_success 'Bloom generation backfills empty commits' '
)
'
+graph=.git/objects/info/commit-graph
+graphdir=.git/objects/info/commit-graphs
+chain=$graphdir/commit-graph-chain
+
+test_expect_success 'setup for mixed Bloom setting tests' '
+ repo=mixed-bloom-settings &&
+
+ git init $repo &&
+ for i in one two three
+ do
+ test_commit -C $repo $i file || return 1
+ done
+'
+
+test_expect_success 'ensure Bloom filters with incompatible settings are ignored' '
+ # Compute Bloom filters with "unusual" settings.
+ git -C $repo rev-parse one >in &&
+ GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=3 git -C $repo commit-graph write \
+ --stdin-commits --changed-paths --split <in &&
+ layer=$(head -n 1 $repo/$chain) &&
+
+ # A commit-graph layer without Bloom filters "hides" the layers
+ # below ...
+ git -C $repo rev-parse two >in &&
+ git -C $repo commit-graph write --stdin-commits --no-changed-paths \
+ --split=no-merge <in &&
+
+ # Another commit-graph layer that has Bloom filters, but with
+ # standard settings, and is thus incompatible with the base
+ # layer written above.
+ git -C $repo rev-parse HEAD >in &&
+ git -C $repo commit-graph write --stdin-commits --changed-paths \
+ --split=no-merge <in &&
+
+ test_line_count = 3 $repo/$chain &&
+
+ # Ensure that incompatible Bloom filters are ignored.
+ git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- file \
+ >expect 2>err &&
+ git -C $repo log --oneline --no-decorate -- file >actual 2>err &&
+ test_cmp expect actual &&
+ grep "disabling Bloom filters for commit-graph layer .$layer." err
+'
+
+test_expect_success 'merge graph layers with incompatible Bloom settings' '
+ # Ensure that incompatible Bloom filters are ignored when
+ # merging existing layers.
+ >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git -C $repo commit-graph write --reachable --changed-paths 2>err &&
+ grep "disabling Bloom filters for commit-graph layer .$layer." err &&
+ grep "{\"hash_version\":1,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt &&
+
+ test_path_is_file $repo/$graph &&
+ test_dir_is_empty $repo/$graphdir &&
+
+ git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- \
+ file >expect &&
+ trace_out="$(pwd)/trace.perf" &&
+ GIT_TRACE2_PERF="$trace_out" \
+ git -C $repo log --oneline --no-decorate -- file >actual 2>err &&
+
+ test_cmp expect actual &&
+ grep "statistics:{\"filter_not_present\":0," trace.perf &&
+ test_must_be_empty err
+'
+
+# chosen to be the same under all Unicode normalization forms
+CENT=$(printf "\302\242")
+
+test_expect_success 'ensure Bloom filter with incompatible versions are ignored' '
+ rm "$repo/$graph" &&
+
+ git -C $repo log --oneline --no-decorate -- $CENT >expect &&
+
+ # Compute v1 Bloom filters for commits at the bottom.
+ git -C $repo rev-parse HEAD^ >in &&
+ git -C $repo commit-graph write --stdin-commits --changed-paths \
+ --split <in &&
+
+ # Compute v2 Bloomfilters for the rest of the commits at the top.
+ git -C $repo rev-parse HEAD >in &&
+ git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write \
+ --stdin-commits --changed-paths --split=no-merge <in &&
+
+ test_line_count = 2 $repo/$chain &&
+
+ git -C $repo log --oneline --no-decorate -- $CENT >actual 2>err &&
+ test_cmp expect actual &&
+
+ layer="$(head -n 1 $repo/$chain)" &&
+ cat >expect.err <<-EOF &&
+ warning: disabling Bloom filters for commit-graph layer $SQ$layer$SQ due to incompatible settings
+ EOF
+ test_cmp expect.err err &&
+
+ # Merge the two layers with incompatible bloom filter versions,
+ # ensuring that the v2 filters are used.
+ >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write --reachable --changed-paths 2>err &&
+ grep "disabling Bloom filters for commit-graph layer .$layer." err &&
+ grep "{\"hash_version\":2,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt
+'
+
+get_first_changed_path_filter () {
+ test-tool read-graph bloom-filters >filters.dat &&
+ head -n 1 filters.dat
+}
+
+test_expect_success 'set up repo with high bit path, version 1 changed-path' '
+ git init highbit1 &&
+ test_commit -C highbit1 c1 "$CENT" &&
+ git -C highbit1 commit-graph write --reachable --changed-paths
+'
+
+test_expect_success 'setup check value of version 1 changed-path' '
+ (
+ cd highbit1 &&
+ echo "52a9" >expect &&
+ get_first_changed_path_filter >actual
+ )
+'
+
+# expect will not match actual if char is unsigned by default. Write the test
+# in this way, so that a user running this test script can still see if the two
+# files match. (It will appear as an ordinary success if they match, and a skip
+# if not.)
+if test_cmp highbit1/expect highbit1/actual
+then
+ test_set_prereq SIGNED_CHAR_BY_DEFAULT
+fi
+test_expect_success SIGNED_CHAR_BY_DEFAULT 'check value of version 1 changed-path' '
+ # Only the prereq matters for this test.
+ true
+'
+
+test_expect_success 'setup make another commit' '
+ # "git log" does not use Bloom filters for root commits - see how, in
+ # revision.c, rev_compare_tree() (the only code path that eventually calls
+ # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit
+ # has one parent. Therefore, make another commit so that we perform the tests on
+ # a non-root commit.
+ test_commit -C highbit1 anotherc1 "another$CENT"
+'
+
+test_expect_success 'version 1 changed-path used when version 1 requested' '
+ (
+ cd highbit1 &&
+ test_bloom_filters_used "-- another$CENT"
+ )
+'
+
+test_expect_success 'version 1 changed-path not used when version 2 requested' '
+ (
+ cd highbit1 &&
+ git config --add commitGraph.changedPathsVersion 2 &&
+ test_bloom_filters_not_used "-- another$CENT"
+ )
+'
+
+test_expect_success 'version 1 changed-path used when autodetect requested' '
+ (
+ cd highbit1 &&
+ git config --add commitGraph.changedPathsVersion -1 &&
+ test_bloom_filters_used "-- another$CENT"
+ )
+'
+
+test_expect_success 'when writing another commit graph, preserve existing version 1 of changed-path' '
+ test_commit -C highbit1 c1double "$CENT$CENT" &&
+ git -C highbit1 commit-graph write --reachable --changed-paths &&
+ (
+ cd highbit1 &&
+ git config --add commitGraph.changedPathsVersion -1 &&
+ echo "options: bloom(1,10,7) read_generation_data" >expect &&
+ test-tool read-graph >full &&
+ grep options full >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'set up repo with high bit path, version 2 changed-path' '
+ git init highbit2 &&
+ git -C highbit2 config --add commitGraph.changedPathsVersion 2 &&
+ test_commit -C highbit2 c2 "$CENT" &&
+ git -C highbit2 commit-graph write --reachable --changed-paths
+'
+
+test_expect_success 'check value of version 2 changed-path' '
+ (
+ cd highbit2 &&
+ echo "c01f" >expect &&
+ get_first_changed_path_filter >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'setup make another commit' '
+ # "git log" does not use Bloom filters for root commits - see how, in
+ # revision.c, rev_compare_tree() (the only code path that eventually calls
+ # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit
+ # has one parent. Therefore, make another commit so that we perform the tests on
+ # a non-root commit.
+ test_commit -C highbit2 anotherc2 "another$CENT"
+'
+
+test_expect_success 'version 2 changed-path used when version 2 requested' '
+ (
+ cd highbit2 &&
+ test_bloom_filters_used "-- another$CENT"
+ )
+'
+
+test_expect_success 'version 2 changed-path not used when version 1 requested' '
+ (
+ cd highbit2 &&
+ git config --add commitGraph.changedPathsVersion 1 &&
+ test_bloom_filters_not_used "-- another$CENT"
+ )
+'
+
+test_expect_success 'version 2 changed-path used when autodetect requested' '
+ (
+ cd highbit2 &&
+ git config --add commitGraph.changedPathsVersion -1 &&
+ test_bloom_filters_used "-- another$CENT"
+ )
+'
+
+test_expect_success 'when writing another commit graph, preserve existing version 2 of changed-path' '
+ test_commit -C highbit2 c2double "$CENT$CENT" &&
+ git -C highbit2 commit-graph write --reachable --changed-paths &&
+ (
+ cd highbit2 &&
+ git config --add commitGraph.changedPathsVersion -1 &&
+ echo "options: bloom(2,10,7) read_generation_data" >expect &&
+ test-tool read-graph >full &&
+ grep options full >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'when writing commit graph, do not reuse changed-path of another version' '
+ git init doublewrite &&
+ test_commit -C doublewrite c "$CENT" &&
+
+ git -C doublewrite config --add commitGraph.changedPathsVersion 1 &&
+ >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git -C doublewrite commit-graph write --reachable --changed-paths &&
+ test_filter_computed 1 trace2.txt &&
+ test_filter_upgraded 0 trace2.txt &&
+
+ git -C doublewrite commit-graph write --reachable --changed-paths &&
+ for v in -2 3
+ do
+ git -C doublewrite config --add commitGraph.changedPathsVersion $v &&
+ git -C doublewrite commit-graph write --reachable --changed-paths 2>err &&
+ cat >expect <<-EOF &&
+ warning: attempting to write a commit-graph, but ${SQ}commitGraph.changedPathsVersion${SQ} ($v) is not supported
+ EOF
+ test_cmp expect err || return 1
+ done &&
+
+ git -C doublewrite config --add commitGraph.changedPathsVersion 2 &&
+ >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git -C doublewrite commit-graph write --reachable --changed-paths &&
+ test_filter_computed 1 trace2.txt &&
+ test_filter_upgraded 0 trace2.txt &&
+
+ (
+ cd doublewrite &&
+ echo "c01f" >expect &&
+ get_first_changed_path_filter >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'when writing commit graph, reuse changed-path of another version where possible' '
+ git init upgrade &&
+
+ test_commit -C upgrade base no-high-bits &&
+
+ git -C upgrade config --add commitGraph.changedPathsVersion 1 &&
+ >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git -C upgrade commit-graph write --reachable --changed-paths &&
+ test_filter_computed 1 trace2.txt &&
+ test_filter_upgraded 0 trace2.txt &&
+
+ git -C upgrade config --add commitGraph.changedPathsVersion 2 &&
+ >trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git -C upgrade commit-graph write --reachable --changed-paths &&
+ test_filter_computed 0 trace2.txt &&
+ test_filter_upgraded 1 trace2.txt
+'
+
+corrupt_graph () {
+ test_when_finished "rm -rf $graph" &&
+ git commit-graph write --reachable --changed-paths &&
+ corrupt_chunk_file $graph "$@"
+}
+
+check_corrupt_graph () {
+ corrupt_graph "$@" &&
+ git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
+ git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
+ test_cmp expect.out out
+}
+
+test_expect_success 'Bloom reader notices too-small data chunk' '
+ check_corrupt_graph BDAT clear 00000000 &&
+ echo "warning: ignoring too-small changed-path chunk" \
+ "(4 < 12) in commit-graph file" >expect.err &&
+ test_cmp expect.err err
+'
+
+test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '
+ check_corrupt_graph BIDX 12 FFFFFFFF &&
+ # use grep to avoid depending on exact chunk size
+ grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
+'
+
+test_expect_success 'Bloom reader notices too-small index chunk' '
+ # replace the index with a single entry, making most
+ # lookups out-of-bounds
+ check_corrupt_graph BIDX clear 00000000 &&
+ echo "warning: commit-graph changed-path index chunk" \
+ "is too small" >expect.err &&
+ test_cmp expect.err err
+'
+
+test_expect_success 'Bloom reader notices out-of-order index offsets' '
+ # we do not know any real offsets, but we can pick
+ # something plausible; we should not get to the point of
+ # actually reading from the bogus offsets anyway.
+ corrupt_graph BIDX 4 0000000c00000005 &&
+ echo "warning: ignoring decreasing changed-path index offsets" \
+ "(12 > 5) for positions 1 and 2 of .git/objects/info/commit-graph" >expect.err &&
+ git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
+ git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
+ test_cmp expect.out out &&
+ test_cmp expect.err err
+'
+
test_done
diff --git a/t/t4217-log-limit.sh b/t/t4217-log-limit.sh
index 613f0710e9..6e01e2629c 100755
--- a/t/t4217-log-limit.sh
+++ b/t/t4217-log-limit.sh
@@ -2,7 +2,6 @@
test_description='git log with filter options limiting the output'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup test' '
diff --git a/t/t4252-am-options.sh b/t/t4252-am-options.sh
index e758e634a3..bda8822b3d 100755
--- a/t/t4252-am-options.sh
+++ b/t/t4252-am-options.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git am with options and not losing them'
+
. ./test-lib.sh
tm="$TEST_DIRECTORY/t4252"
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
index 45f1d4f95e..ae0a56cf5e 100755
--- a/t/t4254-am-corrupt.sh
+++ b/t/t4254-am-corrupt.sh
@@ -2,9 +2,14 @@
test_description='git am with corrupt input'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping am encoding corruption tests; iconv not available'
+ test_done
+fi
+
make_mbox_with_nul () {
space=' '
q_nul_in_subject=
@@ -59,7 +64,7 @@ test_expect_success setup '
# Also, it had the unwanted side-effect of deleting f.
test_expect_success 'try to apply corrupted patch' '
test_when_finished "git am --abort" &&
- test_must_fail git -c advice.amWorkDir=false am bad-patch.diff 2>actual &&
+ test_must_fail git -c advice.amWorkDir=false -c advice.mergeConflict=false am bad-patch.diff 2>actual &&
echo "error: git diff header lacks filename information (line 4)" >expected &&
test_path_is_file f &&
test_cmp expected actual
diff --git a/t/t4256-am-format-flowed.sh b/t/t4256-am-format-flowed.sh
index 1015273bc8..ac9db285f3 100755
--- a/t/t4256-am-format-flowed.sh
+++ b/t/t4256-am-format-flowed.sh
@@ -2,7 +2,6 @@
test_description='test format=flowed support of git am'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -13,7 +12,7 @@ test_expect_success 'setup' '
test_expect_success 'am with format=flowed' '
git am <"$TEST_DIRECTORY/t4256/1/patch" 2>stderr &&
- test_i18ngrep "warning: Patch sent with format=flowed" stderr &&
+ test_grep "warning: Patch sent with format=flowed" stderr &&
test_cmp "$TEST_DIRECTORY/t4256/1/mailinfo.c" mailinfo.c
'
diff --git a/t/t4257-am-interactive.sh b/t/t4257-am-interactive.sh
index f26d7fd2db..30a565cbea 100755
--- a/t/t4257-am-interactive.sh
+++ b/t/t4257-am-interactive.sh
@@ -2,7 +2,6 @@
test_description='am --interactive tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up patches to apply' '
diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index 57c4f26e46..27fbe193bc 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -5,7 +5,6 @@
test_description='git merge-tree'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -86,6 +85,33 @@ EXPECTED
test_cmp expected actual
'
+test_expect_success '3-way merge with --attr-source' '
+ test_when_finished rm -rf 3-way &&
+ git init 3-way &&
+ (
+ cd 3-way &&
+ test_commit initial file1 foo &&
+ base=$(git rev-parse HEAD) &&
+ git checkout -b brancha &&
+ echo bar >>file1 &&
+ git commit -am "adding bar" &&
+ source=$(git rev-parse HEAD) &&
+ git checkout @{-1} &&
+ git checkout -b branchb &&
+ echo baz >>file1 &&
+ git commit -am "adding baz" &&
+ merge=$(git rev-parse HEAD) &&
+ git checkout -b gitattributes &&
+ test_commit "gitattributes" .gitattributes "file1 merge=union" &&
+ git checkout @{-1} &&
+ tree=$(git --attr-source=gitattributes merge-tree --write-tree \
+ --merge-base "$base" --end-of-options "$source" "$merge") &&
+ test_write_lines foo bar baz >expect &&
+ git cat-file -p "$tree:file1" >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'file change A, B (same)' '
git reset --hard initial &&
test_commit "change-a-b-same-A" "initial-file" "AAA" &&
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index 250f721795..eea19907b5 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -22,6 +22,7 @@ test_expect_success setup '
git branch side1 &&
git branch side2 &&
git branch side3 &&
+ git branch side4 &&
git checkout side1 &&
test_write_lines 1 2 3 4 5 6 >numbers &&
@@ -46,6 +47,13 @@ test_expect_success setup '
test_tick &&
git commit -m rename-numbers &&
+ git checkout side4 &&
+ test_write_lines 0 1 2 3 4 5 >numbers &&
+ echo yo >greeting &&
+ git add numbers greeting &&
+ test_tick &&
+ git commit -m other-content-modifications &&
+
git switch --orphan unrelated &&
>something-else &&
git add something-else &&
@@ -97,6 +105,21 @@ test_expect_success 'Content merge and a few conflicts' '
test_cmp expect actual
'
+test_expect_success 'Auto resolve conflicts by "ours" strategy option' '
+ git checkout side1^0 &&
+
+ # make sure merge conflict exists
+ test_must_fail git merge side4 &&
+ git merge --abort &&
+
+ git merge -X ours side4 &&
+ git rev-parse HEAD^{tree} >expected &&
+
+ git merge-tree -X ours side1 side4 >actual &&
+
+ test_cmp expected actual
+'
+
test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' '
# Mis-spell with single "s" instead of double "s"
test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect &&
@@ -290,7 +313,7 @@ test_expect_success 'rename/add handling' '
# First, check that the bar that appears at stage 3 does not
# correspond to an individual blob anywhere in history
#
- hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
+ hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
git rev-list --objects --all >all_blobs &&
! grep $hash all_blobs &&
@@ -357,7 +380,7 @@ test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' '
# First, check that the bar that appears at stage 3 does not
# correspond to an individual blob anywhere in history
#
- hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
+ hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
git rev-list --objects --all >all_blobs &&
! grep $hash all_blobs &&
@@ -607,8 +630,8 @@ test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via collidi
# conflict entries do not appear as individual blobs anywhere
# in history.
#
- hash1=$(cat out | tr "\0" "\n" | head | grep 2.four | cut -f 2 -d " ") &&
- hash2=$(cat out | tr "\0" "\n" | head | grep 3.two | cut -f 2 -d " ") &&
+ hash1=$(tr "\0" "\n" <out | head | grep 2.four | cut -f 2 -d " ") &&
+ hash2=$(tr "\0" "\n" <out | head | grep 3.two | cut -f 2 -d " ") &&
git rev-list --objects --all >all_blobs &&
! grep $hash1 all_blobs &&
! grep $hash2 all_blobs &&
@@ -864,7 +887,7 @@ test_expect_success '--stdin with both a successful and a conflicted merge' '
test_expect_success '--merge-base is incompatible with --stdin' '
test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
- grep "^fatal: --merge-base is incompatible with --stdin" expect
+ grep "^fatal: .*merge-base.*stdin.* cannot be used together" expect
'
# specify merge-base as parent of branch2
@@ -922,4 +945,49 @@ test_expect_success 'check the input format when --stdin is passed' '
test_cmp expect actual
'
+test_expect_success '--merge-base with tree OIDs' '
+ git merge-tree --merge-base=side1^ side1 side3 >with-commits &&
+ git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >with-trees &&
+ test_cmp with-commits with-trees
+'
+
+test_expect_success 'error out on missing tree objects' '
+ git init --bare missing-tree.git &&
+ git rev-list side3 >list &&
+ git rev-parse side3^: >>list &&
+ git pack-objects missing-tree.git/objects/pack/side3-tree-is-missing <list &&
+ side3=$(git rev-parse side3) &&
+ test_must_fail git --git-dir=missing-tree.git merge-tree $side3^ $side3 >actual 2>err &&
+ test_grep "Could not read $(git rev-parse $side3:)" err &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'error out on missing blob objects' '
+ echo 1 | git hash-object -w --stdin >blob1 &&
+ echo 2 | git hash-object -w --stdin >blob2 &&
+ echo 3 | git hash-object -w --stdin >blob3 &&
+ printf "100644 blob $(cat blob1)\tblob\n" | git mktree >tree1 &&
+ printf "100644 blob $(cat blob2)\tblob\n" | git mktree >tree2 &&
+ printf "100644 blob $(cat blob3)\tblob\n" | git mktree >tree3 &&
+ git init --bare missing-blob.git &&
+ cat blob1 blob3 tree1 tree2 tree3 |
+ git pack-objects missing-blob.git/objects/pack/side1-whatever-is-missing &&
+ test_must_fail git --git-dir=missing-blob.git >actual 2>err \
+ merge-tree --merge-base=$(cat tree1) $(cat tree2) $(cat tree3) &&
+ test_grep "unable to read blob object $(cat blob2)" err &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'error out on missing commits as well' '
+ git init --bare missing-commit.git &&
+ git rev-list --objects side1 side3 >list-including-initial &&
+ grep -v ^$(git rev-parse side1^) <list-including-initial >list &&
+ git pack-objects missing-commit.git/objects/pack/missing-initial <list &&
+ side1=$(git rev-parse side1) &&
+ side3=$(git rev-parse side3) &&
+ test_must_fail git --git-dir=missing-commit.git \
+ merge-tree --allow-unrelated-histories $side1 $side3 >actual &&
+ test_must_be_empty actual
+'
+
test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 4b4c3315d8..5465054f17 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -124,8 +124,20 @@ test_expect_success 'setup' '
EOF
'
+test_expect_success '--list notices extra parameters' '
+ test_must_fail git archive --list blah &&
+ test_must_fail git archive --remote=. --list blah
+'
+
+test_expect_success 'end-of-options is correctly eaten' '
+ git archive --list --end-of-options &&
+ git archive --remote=. --list --end-of-options
+'
+
test_expect_success 'populate workdir' '
mkdir a &&
+ echo "a files_named_a" >.gitattributes &&
+ git add .gitattributes &&
echo simple textfile >a/a &&
ten=0123456789 &&
hundred="$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten" &&
@@ -439,6 +451,16 @@ test_expect_success 'allow pathspecs that resolve to the current directory' '
test_cmp expect actual
'
+test_expect_success 'attr pathspec in bare repo' '
+ test_expect_code 0 git --git-dir=bare.git archive -v HEAD \
+ ":(attr:files_named_a)" >/dev/null 2>actual &&
+ cat >expect <<-\EOF &&
+ a/
+ a/a
+ 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
diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh
index 0ff47a239d..e745076441 100755
--- a/t/t5001-archive-attr.sh
+++ b/t/t5001-archive-attr.sh
@@ -3,7 +3,6 @@
test_description='git archive attribute tests'
TEST_CREATE_REPO_NO_TEMPLATE=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
SUBSTFORMAT='%H (%h)%n'
@@ -133,12 +132,13 @@ test_expect_success 'git archive vs. bare' '
'
test_expect_success 'git archive with worktree attributes, bare' '
- (cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar &&
+ (cd bare &&
+ git -c attr.tree=HEAD archive --worktree-attributes HEAD) >bare-worktree.tar &&
(mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar
'
test_expect_missing bare-worktree/ignored
-test_expect_exists bare-worktree/ignored-by-tree
+test_expect_missing bare-worktree/ignored-by-tree
test_expect_exists bare-worktree/ignored-by-worktree
test_expect_success 'export-subst' '
diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh
index 78ab75f1bc..97c93f6c44 100755
--- a/t/t5002-archive-attr-pattern.sh
+++ b/t/t5002-archive-attr-pattern.sh
@@ -2,7 +2,6 @@
test_description='git archive attribute pattern tests'
-TEST_PASSES_SANITIZE_LEAK=true
TEST_CREATE_REPO_NO_TEMPLATE=1
. ./test-lib.sh
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
index fc499cdff0..961c6aac25 100755
--- a/t/t5003-archive-zip.sh
+++ b/t/t5003-archive-zip.sh
@@ -239,4 +239,38 @@ check_zip with_untracked2
check_added with_untracked2 untracked one/untracked
check_added with_untracked2 untracked two/untracked
+# Test remote archive over HTTP protocol.
+#
+# Note: this should be the last part of this test suite, because
+# by including lib-httpd.sh, the test may end early if httpd tests
+# should not be run.
+#
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success "setup for HTTP protocol" '
+ cp -R bare.git "$HTTPD_DOCUMENT_ROOT_PATH/bare.git" &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/bare.git" \
+ config http.uploadpack true &&
+ set_askpass user@host pass@host
+'
+
+setup_askpass_helper
+
+test_expect_success 'remote archive does not work with protocol v1' '
+ test_must_fail git -c protocol.version=1 archive \
+ --remote="$HTTPD_URL/auth/smart/bare.git" \
+ --output=remote-http.zip HEAD >actual 2>&1 &&
+ cat >expect <<-EOF &&
+ fatal: can${SQ}t connect to subservice git-upload-archive
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'archive remote http repository' '
+ git archive --remote="$HTTPD_URL/auth/smart/bare.git" \
+ --output=remote-http.zip HEAD &&
+ test_cmp_bin d.zip remote-http.zip
+'
+
test_done
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 9f2c6da80e..50344e17ca 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -2,7 +2,6 @@
test_description='test corner cases of git-archive'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# the 10knuls.tar file is used to test for an empty git generated tar
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index db11cababd..e57e1ae739 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -27,7 +27,12 @@ check_mailinfo () {
for mail in 00*
do
- test_expect_success "mailinfo $mail" '
+ case "$mail" in
+ 0004)
+ prereq=ICONV;;
+ esac
+
+ test_expect_success $prereq "mailinfo $mail" '
check_mailinfo "$mail" "" &&
if test -f "$DATA/msg$mail--scissors"
then
@@ -55,7 +60,12 @@ test_expect_success 'split box with rfc2047 samples' \
for mail in rfc2047/00*
do
- test_expect_success "mailinfo $mail" '
+ case "$mail" in
+ rfc2047/0001)
+ prereq=ICONV;;
+ esac
+
+ test_expect_success $prereq "mailinfo $mail" '
git mailinfo -u "$mail-msg" "$mail-patch" <"$mail" >"$mail-info" &&
echo msg &&
test_cmp "$DATA/empty" "$mail-msg" &&
@@ -70,7 +80,7 @@ test_expect_success 'respect NULs' '
git mailsplit -d3 -o. "$DATA/nul-plain" &&
test_cmp "$DATA/nul-plain" 001 &&
- (cat 001 | git mailinfo msg patch) &&
+ git mailinfo msg patch <001 &&
test_line_count = 4 patch
'
@@ -268,4 +278,26 @@ test_expect_success 'mailinfo warn CR in base64 encoded email' '
test_must_be_empty quoted-cr/0002.err
'
+test_expect_success 'from line with unterminated quoted string' '
+ echo "From: bob \"unterminated string smith <bob@example.com>" >in &&
+ git mailinfo /dev/null /dev/null <in >actual &&
+ cat >expect <<-\EOF &&
+ Author: bob unterminated string smith
+ Email: bob@example.com
+
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'from line with unterminated comment' '
+ echo "From: bob (unterminated comment smith <bob@example.com>" >in &&
+ git mailinfo /dev/null /dev/null <in >actual &&
+ cat >expect <<-\EOF &&
+ Author: bob (unterminated comment smith
+ Email: bob@example.com
+
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5100/comment.expect b/t/t5100/comment.expect
index 7228177984..bd71956a47 100644
--- a/t/t5100/comment.expect
+++ b/t/t5100/comment.expect
@@ -1,4 +1,4 @@
-Author: A U Thor (this is (really) a comment (honestly))
+Author: (this is (really) a "comment" (honestly)) A U Thor
Email: somebody@example.com
Subject: testing comments
Date: Sun, 25 May 2008 00:38:18 -0700
diff --git a/t/t5100/comment.in b/t/t5100/comment.in
index c53a192dfe..0b7e903b06 100644
--- a/t/t5100/comment.in
+++ b/t/t5100/comment.in
@@ -1,5 +1,5 @@
From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001
-From: "A U Thor" <somebody@example.com> (this is \(really\) a comment (honestly))
+From: (this is \(really\) a "comment" (honestly)) "A U Thor" <somebody@example.com>
Date: Sun, 25 May 2008 00:38:18 -0700
Subject: [PATCH] testing comments
diff --git a/t/t5200-update-server-info.sh b/t/t5200-update-server-info.sh
index ed9dfd624c..8365907055 100755
--- a/t/t5200-update-server-info.sh
+++ b/t/t5200-update-server-info.sh
@@ -2,7 +2,6 @@
test_description='Test git update-server-info'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' 'test_commit file'
@@ -39,4 +38,12 @@ test_expect_success 'info/refs updates when changes are made' '
! test_cmp a b
'
+test_expect_success 'midx does not create duplicate pack entries' '
+ git repack -d --write-midx &&
+ git repack -d &&
+ grep ^P .git/objects/info/packs >packs &&
+ uniq -d <packs >dups &&
+ test_must_be_empty dups
+'
+
test_done
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 745089479c..53dc3cbf90 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -3,9 +3,8 @@
# Copyright (c) 2005 Junio C Hamano
#
-test_description='git pack-object
+test_description='git pack-object'
-'
. ./test-lib.sh
test_expect_success 'setup' '
@@ -156,6 +155,11 @@ test_expect_success 'pack without delta' '
check_deltas stderr = 0
'
+test_expect_success 'negative window clamps to 0' '
+ git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr &&
+ check_deltas stderr = 0
+'
+
test_expect_success 'pack-objects with bogus arguments' '
test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list
'
@@ -327,10 +331,8 @@ test_expect_success 'build pack index for an existing 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 &&
+ git index-pack 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 &&
@@ -441,6 +443,47 @@ test_expect_success 'index-pack with --strict' '
)
'
+test_expect_success 'setup for --strict and --fsck-objects downgrading fsck msgs' '
+ git init strict &&
+ (
+ cd strict &&
+ test_commit first hello &&
+ cat >commit <<-EOF &&
+ tree $(git rev-parse HEAD^{tree})
+ parent $(git rev-parse HEAD)
+ author A U Thor
+ committer A U Thor
+
+ commit: this is a commit with bad emails
+
+ EOF
+ git hash-object --literally -t commit -w --stdin <commit >commit_list &&
+ git pack-objects test <commit_list >pack-name
+ )
+'
+
+test_with_bad_commit () {
+ must_fail_arg="$1" &&
+ must_pass_arg="$2" &&
+ (
+ cd strict &&
+ test_must_fail git index-pack "$must_fail_arg" "test-$(cat pack-name).pack" &&
+ git index-pack "$must_pass_arg" "test-$(cat pack-name).pack"
+ )
+}
+
+test_expect_success 'index-pack with --strict downgrading fsck msgs' '
+ test_with_bad_commit --strict --strict="missingEmail=ignore"
+'
+
+test_expect_success 'index-pack with --fsck-objects downgrading fsck msgs' '
+ test_with_bad_commit --fsck-objects --fsck-objects="missingEmail=ignore"
+'
+
+test_expect_success 'cleanup for --strict and --fsck-objects downgrading fsck msgs' '
+ rm -rf strict
+'
+
test_expect_success 'honor pack.packSizeLimit' '
git config pack.packSizeLimit 3m &&
packname_10=$(git pack-objects test-10 <obj-list) &&
@@ -541,7 +584,7 @@ test_expect_success 'make sure index-pack detects the SHA1 collision' '
(
cd corrupt &&
test_must_fail git index-pack -o ../bad.idx ../test-3.pack 2>msg &&
- test_i18ngrep "SHA1 COLLISION FOUND" msg
+ test_grep "SHA1 COLLISION FOUND" msg
)
'
@@ -549,7 +592,7 @@ test_expect_success 'make sure index-pack detects the SHA1 collision (large blob
(
cd corrupt &&
test_must_fail git -c core.bigfilethreshold=1 index-pack -o ../bad.idx ../test-3.pack 2>msg &&
- test_i18ngrep "SHA1 COLLISION FOUND" msg
+ test_grep "SHA1 COLLISION FOUND" msg
)
'
@@ -589,9 +632,43 @@ test_expect_success 'prefetch objects' '
test_line_count = 1 donelines
'
-test_expect_success 'negative window clamps to 0' '
- git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr &&
- check_deltas stderr = 0
-'
+for hash in sha1 sha256
+do
+ test_expect_success "verify-pack with $hash packfile" '
+ test_when_finished "rm -rf repo" &&
+ git init --object-format=$hash repo &&
+ test_commit -C repo initial &&
+ git -C repo repack -ad &&
+ git -C repo verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx &&
+ if test $hash = sha1
+ then
+ nongit git verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx
+ else
+ # We have no way to identify the hash used by packfiles
+ # or indices, so we always fall back to SHA1.
+ nongit test_must_fail git verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx &&
+ # But with an explicit object format we should succeed.
+ nongit git verify-pack --object-format=$hash "$(pwd)"/repo/.git/objects/pack/*.idx
+ fi
+ '
+
+ test_expect_success "index-pack outside of a $hash repository" '
+ test_when_finished "rm -rf repo" &&
+ git init --object-format=$hash repo &&
+ test_commit -C repo initial &&
+ git -C repo repack -ad &&
+ git -C repo index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack &&
+ if test $hash = sha1
+ then
+ nongit git index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack
+ else
+ # We have no way to identify the hash used by packfiles
+ # or indices, so we always fall back to SHA1.
+ nongit test_must_fail git index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack 2>err &&
+ # But with an explicit object format we should succeed.
+ nongit git index-pack --object-format=$hash --verify "$(pwd)"/repo/.git/objects/pack/*.pack
+ fi
+ '
+done
test_done
diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh
index 226490d60d..ff6b5159a3 100755
--- a/t/t5301-sliding-window.sh
+++ b/t/t5301-sliding-window.sh
@@ -5,7 +5,6 @@
test_description='mmap sliding window tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index f89809be53..413c99274c 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -5,7 +5,6 @@
test_description='pack index with 64-bit offsets and object CRC'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -282,8 +281,8 @@ test_expect_success 'index-pack --fsck-objects also warns upon missing tagger in
test_expect_success 'index-pack -v --stdin produces progress for both phases' '
pack=$(git pack-objects --all pack </dev/null) &&
GIT_PROGRESS_DELAY=0 git index-pack -v --stdin <pack-$pack.pack 2>err &&
- test_i18ngrep "Receiving objects" err &&
- test_i18ngrep "Resolving deltas" err
+ test_grep "Receiving objects" err &&
+ test_grep "Resolving deltas" err
'
test_expect_success 'too-large packs report the breach' '
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index 61469ef4a6..de58ca654a 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -5,7 +5,6 @@
test_description='resilience to pack corruptions with redundant objects'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Note: the test objects are created with knowledge of their pack encoding
@@ -15,7 +14,7 @@ TEST_PASSES_SANITIZE_LEAK=true
# 1) blob_2 is a delta with blob_1 for base and blob_3 is a delta with blob2
# for base, such that blob_3 delta depth is 2;
#
-# 2) the bulk of object data is uncompressible so the text part remains
+# 2) the bulk of object data is incompressible so the text part remains
# visible;
#
# 3) object header is always 2 bytes.
@@ -44,9 +43,14 @@ create_new_pack() {
}
do_repack() {
+ for f in $pack.*
+ do
+ mv $f "$(echo $f | sed -e 's/pack-/pack-corrupt-/')" || return 1
+ done &&
pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" |
git pack-objects $@ .git/objects/pack/pack) &&
- pack=".git/objects/pack/pack-${pack}"
+ pack=".git/objects/pack/pack-${pack}" &&
+ rm -f .git/objects/pack/pack-corrupt-*
}
do_corrupt_object() {
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index b4df545e5a..1f1f664871 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -318,10 +318,10 @@ test_expect_success 'prune: handle HEAD reflog in multiple worktrees' '
test_expect_success 'prune: handle expire option correctly' '
test_must_fail git prune --expire 2>error &&
- test_i18ngrep "requires a value" error &&
+ test_grep "requires a value" error &&
test_must_fail git prune --expire=nyah 2>error &&
- test_i18ngrep "malformed expiration" error &&
+ test_grep "malformed expiration" error &&
git prune --no-expire
'
diff --git a/t/t5306-pack-nobase.sh b/t/t5306-pack-nobase.sh
index 0d50c6b4bc..805d60ff31 100755
--- a/t/t5306-pack-nobase.sh
+++ b/t/t5306-pack-nobase.sh
@@ -7,7 +7,6 @@ test_description='git-pack-object with missing base
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Create A-B chain
diff --git a/t/t5307-pack-missing-commit.sh b/t/t5307-pack-missing-commit.sh
index 1e02c305c4..fa4bc269fe 100755
--- a/t/t5307-pack-missing-commit.sh
+++ b/t/t5307-pack-missing-commit.sh
@@ -2,7 +2,6 @@
test_description='pack should notice missing commit objects'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5308-pack-detect-duplicates.sh b/t/t5308-pack-detect-duplicates.sh
index 655cafa054..0f84137867 100755
--- a/t/t5308-pack-detect-duplicates.sh
+++ b/t/t5308-pack-detect-duplicates.sh
@@ -2,7 +2,6 @@
test_description='handling of duplicate objects in incoming packfiles'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pack.sh
diff --git a/t/t5309-pack-delta-cycles.sh b/t/t5309-pack-delta-cycles.sh
index 4e910c5b9d..60fc710bac 100755
--- a/t/t5309-pack-delta-cycles.sh
+++ b/t/t5309-pack-delta-cycles.sh
@@ -2,7 +2,6 @@
test_description='test index-pack handling of delta cycles in packfiles'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pack.sh
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 78c1c6c923..eabfcd7ff6 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -5,10 +5,6 @@ test_description='exercise basic bitmap functionality'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bitmap.sh
-# t5310 deals only with single-pack bitmaps, so don't write MIDX bitmaps in
-# their place.
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
-
# Likewise, allow individual tests to control whether or not they use
# the boundary-based traversal.
sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
@@ -271,7 +267,7 @@ test_bitmap_cases () {
mv -f $bitmap.tmp $bitmap &&
git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
test_cmp expect actual &&
- test_i18ngrep corrupt.ewah.bitmap stderr
+ test_grep corrupt.ewah.bitmap stderr
'
test_expect_success 'truncated bitmap fails gracefully (cache)' '
@@ -284,7 +280,7 @@ test_bitmap_cases () {
mv -f $bitmap.tmp $bitmap &&
git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
test_cmp expect actual &&
- test_i18ngrep corrupted.bitmap.index stderr
+ test_grep corrupted.bitmap.index stderr
'
# Create a state of history with these properties:
@@ -471,7 +467,7 @@ 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 &&
- test_i18ngrep "Incremental repacks are incompatible with bitmap" err
+ test_grep "Incremental repacks are incompatible with bitmap" err
'
test_expect_success 'incremental repack can disable bitmaps' '
@@ -506,6 +502,18 @@ test_expect_success 'boundary-based traversal is used when requested' '
done
'
+test_expect_success 'left-right not confused by bitmap index' '
+ git rev-list --left-right other...HEAD >expect &&
+ git rev-list --use-bitmap-index --left-right other...HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'left-right count not confused by bitmap-index' '
+ git rev-list --left-right --count other...HEAD >expect &&
+ git rev-list --use-bitmap-index --left-right --count other...HEAD >actual &&
+ test_cmp expect actual
+'
+
test_bitmap_cases "pack.writeBitmapLookupTable"
test_expect_success 'verify writing bitmap lookup table when enabled' '
@@ -524,7 +532,7 @@ test_expect_success 'truncated bitmap fails gracefully (lookup table)' '
mv -f $bitmap.tmp $bitmap &&
git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
test_cmp expect actual &&
- test_i18ngrep corrupted.bitmap.index stderr
+ test_grep corrupted.bitmap.index stderr
'
test_done
diff --git a/t/t5311-pack-bitmaps-shallow.sh b/t/t5311-pack-bitmaps-shallow.sh
index 9dae60f73e..012852c156 100755
--- a/t/t5311-pack-bitmaps-shallow.sh
+++ b/t/t5311-pack-bitmaps-shallow.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='check bitmap operation with shallow repositories'
+
. ./test-lib.sh
# We want to create a situation where the shallow, grafted
diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh
index 230cb38712..c37ef3818d 100755
--- a/t/t5312-prune-corruption.sh
+++ b/t/t5312-prune-corruption.sh
@@ -14,7 +14,6 @@ what currently happens. If that changes, these tests should be revisited.
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 'disable reflogs' '
@@ -111,30 +110,4 @@ test_expect_success 'pack-refs does not silently delete broken loose ref' '
test_cmp expect actual
'
-# we do not want to count on running pack-refs to
-# actually pack it, as it is perfectly reasonable to
-# skip processing a broken ref
-test_expect_success REFFILES 'create packed-refs file with broken ref' '
- rm -f .git/refs/heads/main &&
- cat >.git/packed-refs <<-EOF &&
- $missing refs/heads/main
- $recoverable refs/heads/other
- EOF
- echo $missing >expect &&
- git rev-parse refs/heads/main >actual &&
- test_cmp expect actual
-'
-
-test_expect_success REFFILES 'pack-refs does not silently delete broken packed ref' '
- git pack-refs --all --prune &&
- git rev-parse refs/heads/main >actual &&
- test_cmp expect actual
-'
-
-test_expect_success REFFILES 'pack-refs does not drop broken refs during deletion' '
- git update-ref -d refs/heads/other &&
- git rev-parse refs/heads/main >actual &&
- test_cmp expect actual
-'
-
test_done
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
index ceaa6700a2..5be01260d7 100755
--- a/t/t5313-pack-bounds-checks.sh
+++ b/t/t5313-pack-bounds-checks.sh
@@ -2,16 +2,15 @@
test_description='bounds-checking of access to mmapped on-disk file formats'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
clear_base () {
test_when_finished 'restore_base' &&
- rm -f $base
+ rm -r -f $base
}
restore_base () {
- cp base-backup/* .git/objects/pack/
+ cp -r base-backup/* .git/objects/pack/
}
do_pack () {
@@ -64,9 +63,9 @@ test_expect_success 'set up base packfile and variables' '
git commit -m base &&
git repack -ad &&
base=$(echo .git/objects/pack/*) &&
- chmod +w $base &&
+ chmod -R +w $base &&
mkdir base-backup &&
- cp $base base-backup/ &&
+ cp -r $base base-backup/ &&
object=$(git rev-parse HEAD:file)
'
diff --git a/t/t5314-pack-cycle-detection.sh b/t/t5314-pack-cycle-detection.sh
index 82734b9a3c..9cd18c1e6b 100755
--- a/t/t5314-pack-cycle-detection.sh
+++ b/t/t5314-pack-cycle-detection.sh
@@ -50,7 +50,6 @@ will always find a delta for "file", because its lookup will always come
immediately after the lookup for "dummy".
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Create a pack containing the tree $1 and blob $1:file, with
diff --git a/t/t5315-pack-objects-compression.sh b/t/t5315-pack-objects-compression.sh
index c80ea9e8b7..8bacd96275 100755
--- a/t/t5315-pack-objects-compression.sh
+++ b/t/t5315-pack-objects-compression.sh
@@ -2,7 +2,6 @@
test_description='pack-object compression configuration'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index eb4ef3dda4..32cf422745 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -2,7 +2,6 @@
test_description='pack-objects breaks long cross-pack delta chains'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This mirrors a repeated push setup:
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index b26d476c64..501d715b9a 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -5,7 +5,6 @@ test_description='git pack-objects using object filtering'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Test blob:none filter.
@@ -53,6 +52,14 @@ test_expect_success 'verify blob:none packfile has no blobs' '
! grep blob verify_result
'
+test_expect_success 'verify blob:none packfile without --stdout' '
+ git -C r1 pack-objects --revs --filter=blob:none mypackname >packhash <<-EOF &&
+ HEAD
+ EOF
+ git -C r1 verify-pack -v "mypackname-$(cat packhash).pack" >verify_result &&
+ ! grep blob verify_result
+'
+
test_expect_success 'verify normal and blob:none packfiles have same commits/trees' '
git -C r1 verify-pack -v ../all.pack >verify_result &&
grep -E "commit|tree" verify_result |
@@ -447,7 +454,7 @@ test_expect_success 'setup r1 - delete loose blobs' '
test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
- for id in `cat expected | sed "s|..|&/|"`
+ for id in `sed "s|..|&/|" expected`
do
rm r1/.git/objects/$id || return 1
done
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index ba65f17dd9..f68f64cd85 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -1,7 +1,9 @@
#!/bin/sh
test_description='commit graph'
+
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
@@ -47,7 +49,7 @@ test_expect_success 'exit with correct error on bad input to --stdin-packs' '
echo doesnotexist >in &&
test_expect_code 1 git -C full commit-graph write --stdin-packs \
<in 2>stderr &&
- test_i18ngrep "error adding pack" stderr
+ test_grep "error adding pack" stderr
'
test_expect_success 'create commits and repack' '
@@ -67,11 +69,11 @@ test_expect_success 'exit with correct error on bad input to --stdin-commits' '
# invalid, non-hex OID
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 &&
+ test_grep "unexpected non-hex object ID: HEAD" stderr &&
# non-existent OID
echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \
--stdin-commits 2>stderr &&
- test_i18ngrep "invalid object" stderr &&
+ test_grep "invalid object" stderr &&
# valid commit and tree OID
git -C full rev-parse HEAD HEAD^{tree} >in &&
git -C full commit-graph write --stdin-commits <in &&
@@ -143,7 +145,7 @@ test_expect_success 'commit-graph write --stdin-commits force progress on for st
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_grep "Collecting commits from input" err
'
test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' '
@@ -383,13 +385,13 @@ test_expect_success 'warn on improper hash version' '
cd sha1 &&
mv ../cg-sha256 .git/objects/info/commit-graph &&
git log -1 2>err &&
- test_i18ngrep "commit-graph hash version 2 does not match version 1" err
+ test_grep "commit-graph hash version 2 does not match version 1" err
) &&
(
cd sha256 &&
mv ../cg-sha1 .git/objects/info/commit-graph &&
git log -1 2>err &&
- test_i18ngrep "commit-graph hash version 1 does not match version 2" err
+ test_grep "commit-graph hash version 1 does not match version 2" err
)
'
@@ -474,7 +476,7 @@ corrupt_graph_verify() {
grepstr=$1
test_must_fail git -C full commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "$grepstr" err &&
+ test_grep "$grepstr" err &&
if test "$2" != "no-copy"
then
cp full/$objdir/info/commit-graph commit-graph-pre-write-test
@@ -539,17 +541,17 @@ test_expect_success 'detect low chunk count' '
test_expect_success 'detect missing OID fanout chunk' '
corrupt_graph_and_verify $GRAPH_BYTE_OID_FANOUT_ID "\0" \
- "missing the OID Fanout chunk"
+ "commit-graph required OID fanout chunk missing or corrupted"
'
test_expect_success 'detect missing OID lookup chunk' '
corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_ID "\0" \
- "missing the OID Lookup chunk"
+ "commit-graph required OID lookup chunk missing or corrupted"
'
test_expect_success 'detect missing commit data chunk' '
corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATA_ID "\0" \
- "missing the Commit Data chunk"
+ "commit-graph required commit data chunk missing or corrupted"
'
test_expect_success 'detect incorrect fanout' '
@@ -559,7 +561,7 @@ test_expect_success 'detect incorrect fanout' '
test_expect_success 'detect incorrect fanout final value' '
corrupt_graph_and_verify $GRAPH_BYTE_FANOUT2 "\01" \
- "fanout value"
+ "OID lookup chunk is the wrong size"
'
test_expect_success 'detect incorrect OID order' '
@@ -720,7 +722,7 @@ test_expect_success 'corrupt commit-graph write (broken parent)' '
git commit-tree -p "$broken" -m "good commit" "$empty" >good &&
test_must_fail git commit-graph write --stdin-commits \
<good 2>test_err &&
- test_i18ngrep "unable to parse commit" test_err
+ test_grep "unable to parse commit" test_err
)
'
@@ -741,7 +743,7 @@ test_expect_success 'corrupt commit-graph write (missing tree)' '
git commit-tree -p "$broken" -m "good" "$tree" >good &&
test_must_fail git commit-graph write --stdin-commits \
<good 2>test_err &&
- test_i18ngrep "unable to parse commit" test_err
+ test_grep "unable to parse commit" test_err
)
'
@@ -821,4 +823,127 @@ test_expect_success 'overflow during generation version upgrade' '
)
'
+corrupt_chunk () {
+ graph=full/.git/objects/info/commit-graph &&
+ test_when_finished "rm -rf $graph" &&
+ git -C full commit-graph write --reachable &&
+ corrupt_chunk_file $graph "$@"
+}
+
+check_corrupt_chunk () {
+ corrupt_chunk "$@" &&
+ git -C full -c core.commitGraph=false log >expect.out &&
+ git -C full -c core.commitGraph=true log >out 2>err &&
+ test_cmp expect.out out
+}
+
+test_expect_success 'reader notices too-small oid fanout chunk' '
+ # make it big enough that the graph file is plausible,
+ # otherwise we hit an earlier check
+ check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph oid fanout chunk is wrong size
+ error: commit-graph required OID fanout chunk missing or corrupted
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices fanout/lookup table mismatch' '
+ check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph OID lookup chunk is the wrong size
+ error: commit-graph required OID lookup chunk missing or corrupted
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds fanout' '
+ # Rather than try to corrupt a specific hash, we will just
+ # wreck them all. But we cannot just set them all to 0xFFFFFFFF or
+ # similar, as they are used for hi/lo starts in a binary search (so if
+ # they are identical, that indicates that the search should abort
+ # immediately). Instead, we will give them high values that differ by
+ # 2^24, ensuring that any that are used would cause an out-of-bounds
+ # read.
+ check_corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph fanout values out of order
+ error: commit-graph required OID fanout chunk missing or corrupted
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small commit data chunk' '
+ check_corrupt_chunk CDAT clear 00000000 &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph commit data chunk is wrong size
+ error: commit-graph required commit data chunk missing or corrupted
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds extra edge' '
+ check_corrupt_chunk EDGE clear &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph extra-edges pointer out of bounds
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small generations chunk' '
+ check_corrupt_chunk GDA2 clear 00000000 &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph generations chunk is wrong size
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'stale commit cannot be parsed when given directly' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ test_commit B &&
+ git commit-graph write --reachable &&
+
+ oid=$(git rev-parse B) &&
+ rm .git/objects/"$(test_oid_to_path "$oid")" &&
+
+ # Verify that it is possible to read the commit from the
+ # commit graph when not being paranoid, ...
+ git rev-list B &&
+ # ... but parsing the commit when double checking that
+ # it actually exists in the object database should fail.
+ test_must_fail env GIT_COMMIT_GRAPH_PARANOIA=true git rev-list -1 B
+ )
+'
+
+test_expect_success 'stale commit cannot be parsed when traversing graph' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+ git commit-graph write --reachable &&
+
+ # Corrupt the repository by deleting the intermediate commit
+ # object. Commands should notice that this object is absent and
+ # thus that the repository is corrupt even if the commit graph
+ # exists.
+ oid=$(git rev-parse B) &&
+ rm .git/objects/"$(test_oid_to_path "$oid")" &&
+
+ # Again, we should be able to parse the commit when not
+ # being paranoid about commit graph staleness...
+ git rev-parse HEAD~2 &&
+ # ... but fail when we are paranoid.
+ test_must_fail env GIT_COMMIT_GRAPH_PARANOIA=true git rev-parse HEAD~2 2>error &&
+ grep "error: commit $oid exists in commit-graph but not in the object database" error
+ )
+'
+
test_done
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 1bcc02004d..0f215ad2e8 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1,9 +1,14 @@
#!/bin/sh
test_description='multi-pack-indexes'
+
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
+. "$TEST_DIRECTORY"/lib-midx.sh
GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
objdir=.git/objects
HASH_LEN=$(test_oid rawsz)
@@ -106,30 +111,6 @@ test_expect_success 'write midx with one v1 pack' '
midx_read_expect 1 18 4 $objdir
'
-midx_git_two_modes () {
- git -c core.multiPackIndex=false $1 >expect &&
- git -c core.multiPackIndex=true $1 >actual &&
- if [ "$2" = "sorted" ]
- then
- sort <expect >expect.sorted &&
- mv expect.sorted expect &&
- sort <actual >actual.sorted &&
- mv actual.sorted actual
- fi &&
- test_cmp expect actual
-}
-
-compare_results_with_midx () {
- MSG=$1
- test_expect_success "check normal git operations: $MSG" '
- midx_git_two_modes "rev-list --objects --all" &&
- midx_git_two_modes "log --raw" &&
- midx_git_two_modes "count-objects --verbose" &&
- midx_git_two_modes "cat-file --batch-all-objects --batch-check" &&
- midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted
- '
-}
-
test_expect_success 'write midx with one v2 pack' '
git pack-objects --index-version=2,0x40 $objdir/pack/test <obj-list &&
git multi-pack-index --object-dir=$objdir write &&
@@ -279,13 +260,13 @@ test_expect_success 'warn on improper hash version' '
cd sha1 &&
mv ../mpi-sha256 .git/objects/pack/multi-pack-index &&
git log -1 2>err &&
- test_i18ngrep "multi-pack-index hash version 2 does not match version 1" err
+ test_grep "multi-pack-index hash version 2 does not match version 1" err
) &&
(
cd sha256 &&
mv ../mpi-sha1 .git/objects/pack/multi-pack-index &&
git log -1 2>err &&
- test_i18ngrep "multi-pack-index hash version 1 does not match version 2" err
+ test_grep "multi-pack-index hash version 1 does not match version 2" err
)
'
@@ -349,6 +330,29 @@ test_expect_success 'preferred packs must be non-empty' '
)
'
+test_expect_success 'preferred pack from existing MIDX without bitmaps' '
+ git init preferred-without-bitmaps &&
+ (
+ cd preferred-without-bitmaps &&
+
+ test_commit one &&
+ pack="$(git pack-objects --all $objdir/pack/pack </dev/null)" &&
+
+ git multi-pack-index write &&
+
+ # make another pack so that the subsequent MIDX write
+ # has something to do
+ test_commit two &&
+ git repack -d &&
+
+ # write a new MIDX without bitmaps reusing the singular
+ # pack from the existing MIDX as the preferred pack in
+ # the new MIDX
+ git multi-pack-index write --preferred-pack=pack-$pack.pack
+ )
+
+'
+
test_expect_success 'verify multi-pack-index success' '
git multi-pack-index verify --object-dir=$objdir
'
@@ -386,7 +390,7 @@ corrupt_midx_and_verify() {
printf "$DATA" | dd of="$FILE" bs=1 seek="$POS" conv=notrunc &&
test_must_fail $COMMAND 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "$GREPSTR" err
+ test_grep "$GREPSTR" err
}
test_expect_success 'verify bad signature' '
@@ -438,7 +442,7 @@ test_expect_success 'verify extended chunk count' '
test_expect_success 'verify missing required chunk' '
corrupt_midx_and_verify $MIDX_BYTE_CHUNK_ID "\01" $objdir \
- "missing required"
+ "required pack-name chunk missing"
'
test_expect_success 'verify invalid chunk offset' '
@@ -501,7 +505,7 @@ test_expect_success 'corrupt MIDX is not reused' '
corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \
"incorrect object offset" &&
git multi-pack-index write 2>err &&
- test_i18ngrep checksum.mismatch err &&
+ test_grep checksum.mismatch err &&
git multi-pack-index verify
'
@@ -576,8 +580,7 @@ test_expect_success 'repack preserves multi-pack-index when creating packs' '
compare_results_with_midx "after repack"
test_expect_success 'multi-pack-index and pack-bitmap' '
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -c repack.writeBitmaps=true repack -ad &&
+ git -c repack.writeBitmaps=true repack -ad &&
git multi-pack-index write &&
git rev-list --test-bitmap HEAD
'
@@ -1003,6 +1006,61 @@ test_expect_success 'repack --batch-size=<large> repacks everything' '
)
'
+test_expect_success 'repack/expire loop' '
+ git init repack-expire &&
+ test_when_finished "rm -fr repack-expire" &&
+ (
+ cd repack-expire &&
+
+ test_commit_bulk 5 &&
+
+ # Create three overlapping pack-files
+ git rev-list --objects HEAD~3 >in-1 &&
+ git rev-list --objects HEAD~4..HEAD~2 >in-2 &&
+ git rev-list --objects HEAD~3..HEAD >in-3 &&
+
+ # Create disconnected blobs
+ obj1=$(git hash-object -w in-1) &&
+ obj2=$(git hash-object -w in-2) &&
+ obj3=$(git hash-object -w in-3) &&
+
+ echo $obj2 >>in-2 &&
+ echo $obj3 >>in-3 &&
+
+ for i in $(test_seq 3)
+ do
+ git pack-objects .git/objects/pack/test-$i <in-$i \
+ || return 1
+ done &&
+
+ rm -fr .git/objects/pack/pack-* &&
+ git multi-pack-index write &&
+
+ for i in $(test_seq 3)
+ do
+ for file in $(ls .git/objects/pack/test-$i*)
+ do
+ test-tool chmtime =+$((3600*$i-25000)) $file || return 1
+ done || return 1
+ done &&
+
+ pack1=$(ls .git/objects/pack/test-1-*.pack) &&
+ pack2=$(ls .git/objects/pack/test-2-*.pack) &&
+ pack3=$(ls .git/objects/pack/test-3-*.pack) &&
+
+ # Prevent test-1 from being rewritten.
+ touch "${pack1%.pack}.keep" &&
+
+ # This repack-expire loop should repack all non-kept packs
+ # into a new pack and then delete the old packs.
+ git multi-pack-index repack &&
+ git multi-pack-index expire &&
+
+ test_path_is_missing $pack3 &&
+ test_path_is_missing $pack2
+ )
+'
+
test_expect_success 'load reverse index when missing .idx, .pack' '
git init repo &&
test_when_finished "rm -fr repo" &&
@@ -1031,7 +1089,7 @@ test_expect_success 'load reverse index when missing .idx, .pack' '
test_expect_success 'usage shown without sub-command' '
test_expect_code 129 git multi-pack-index 2>err &&
- ! test_i18ngrep "unrecognized subcommand" err
+ ! test_grep "unrecognized subcommand" err
'
test_expect_success 'complains when run outside of a repository' '
@@ -1055,4 +1113,154 @@ test_expect_success 'repack with delta islands' '
)
'
+corrupt_chunk () {
+ midx=.git/objects/pack/multi-pack-index &&
+ test_when_finished "rm -rf $midx" &&
+ git repack -ad --write-midx &&
+ corrupt_chunk_file $midx "$@"
+}
+
+test_expect_success 'reader notices too-small oid fanout chunk' '
+ corrupt_chunk OIDF clear 00000000 &&
+ test_must_fail git log 2>err &&
+ cat >expect <<-\EOF &&
+ error: multi-pack-index OID fanout is of the wrong size
+ fatal: multi-pack-index required OID fanout chunk missing or corrupted
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success 'reader notices too-small oid lookup chunk' '
+ corrupt_chunk OIDL clear 00000000 &&
+ test_must_fail git log 2>err &&
+ cat >expect <<-\EOF &&
+ error: multi-pack-index OID lookup chunk is the wrong size
+ fatal: multi-pack-index required OID lookup chunk missing or corrupted
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success 'reader notices too-small pack names chunk' '
+ # There is no NUL to terminate the name here, so the
+ # chunk is too short.
+ corrupt_chunk PNAM clear 70656666 &&
+ test_must_fail git log 2>err &&
+ cat >expect <<-\EOF &&
+ fatal: multi-pack-index pack-name chunk is too short
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success 'reader handles unaligned chunks' '
+ # A 9-byte PNAM means all of the subsequent chunks
+ # will no longer be 4-byte aligned, but it is still
+ # a valid one-pack chunk on its own (it is "foo.pack\0").
+ corrupt_chunk PNAM clear 666f6f2e7061636b00 &&
+ git -c core.multipackindex=false log >expect.out &&
+ git -c core.multipackindex=true log >out 2>err &&
+ test_cmp expect.out out &&
+ cat >expect.err <<-\EOF &&
+ error: chunk id 4f494446 not 4-byte aligned
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small object offset chunk' '
+ corrupt_chunk OOFF clear 00000000 &&
+ test_must_fail git log 2>err &&
+ cat >expect <<-\EOF &&
+ error: multi-pack-index object offset chunk is the wrong size
+ fatal: multi-pack-index required object offsets chunk missing or corrupted
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success 'reader bounds-checks large offset table' '
+ # re-use the objects64 dir here to cheaply get access to a midx
+ # with large offsets.
+ git init repo &&
+ test_when_finished "rm -rf repo" &&
+ (
+ cd repo &&
+ (cd ../objects64 && pwd) >.git/objects/info/alternates &&
+ git multi-pack-index --object-dir=../objects64 write &&
+ midx=../objects64/pack/multi-pack-index &&
+ corrupt_chunk_file $midx LOFF clear &&
+ # using only %(objectsize) is important here; see the commit
+ # message for more details
+ test_must_fail git cat-file --batch-all-objects \
+ --batch-check="%(objectsize)" 2>err &&
+ cat >expect <<-\EOF &&
+ fatal: multi-pack-index large offset out of bounds
+ EOF
+ test_cmp expect err
+ )
+'
+
+test_expect_success 'reader notices too-small revindex chunk' '
+ # We only get a revindex with bitmaps (and likewise only
+ # load it when they are asked for).
+ test_config repack.writeBitmaps true &&
+ corrupt_chunk RIDX clear 00000000 &&
+ git -c core.multipackIndex=false rev-list \
+ --all --use-bitmap-index >expect.out &&
+ git -c core.multipackIndex=true rev-list \
+ --all --use-bitmap-index >out 2>err &&
+ test_cmp expect.out out &&
+ cat >expect.err <<-\EOF &&
+ error: multi-pack-index reverse-index chunk is the wrong size
+ warning: multi-pack bitmap is missing required reverse index
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds fanout' '
+ # This is similar to the out-of-bounds fanout test in t5318. The values
+ # in adjacent entries should be large but not identical (they
+ # are used as hi/lo starts for a binary search, which would then abort
+ # immediately).
+ corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) &&
+ test_must_fail git log 2>err &&
+ cat >expect <<-\EOF &&
+ error: oid fanout out of order: fanout[254] = fe000000 > 5c = fanout[255]
+ fatal: multi-pack-index required OID fanout chunk missing or corrupted
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success 'bitmapped packs are stored via the BTMP chunk' '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ for i in 1 2 3 4 5
+ do
+ test_commit "$i" &&
+ git repack -d || return 1
+ done &&
+
+ find $objdir/pack -type f -name "*.idx" | xargs -n 1 basename |
+ sort >packs &&
+
+ git multi-pack-index write --stdin-packs <packs &&
+ test_must_fail test-tool read-midx --bitmap $objdir 2>err &&
+ cat >expect <<-\EOF &&
+ error: MIDX does not contain the BTMP chunk
+ EOF
+ test_cmp expect err &&
+
+ git multi-pack-index write --stdin-packs --bitmap \
+ --preferred-pack="$(head -n1 <packs)" <packs &&
+ test-tool read-midx --bitmap $objdir >actual &&
+ for i in $(test_seq $(wc -l <packs))
+ do
+ sed -ne "${i}s/\.idx$/\.pack/p" packs &&
+ echo " bitmap_pos: $((($i - 1) * 3))" &&
+ echo " bitmap_nr: 3" || return 1
+ done >expect &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t5320-delta-islands.sh b/t/t5320-delta-islands.sh
index 406363381f..2c961c7096 100755
--- a/t/t5320-delta-islands.sh
+++ b/t/t5320-delta-islands.sh
@@ -2,7 +2,6 @@
test_description='exercise delta islands'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# returns true iff $1 is a delta based on $2
diff --git a/t/t5321-pack-large-objects.sh b/t/t5321-pack-large-objects.sh
index 70770fe274..51aaca1fcf 100755
--- a/t/t5321-pack-large-objects.sh
+++ b/t/t5321-pack-large-objects.sh
@@ -7,7 +7,6 @@ test_description='git pack-object with "large" deltas
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pack.sh
diff --git a/t/t5322-pack-objects-sparse.sh b/t/t5322-pack-objects-sparse.sh
index 770695c927..d39958c066 100755
--- a/t/t5322-pack-objects-sparse.sh
+++ b/t/t5322-pack-objects-sparse.sh
@@ -4,7 +4,6 @@ test_description='pack-objects object selection using sparse algorithm'
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 repo' '
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 36c4141e67..a32be3867d 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -1,7 +1,9 @@
#!/bin/sh
test_description='split commit graph'
+
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
GIT_TEST_COMMIT_GRAPH=0
GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
@@ -10,7 +12,8 @@ test_expect_success 'setup repo' '
git init &&
git config core.commitGraph true &&
git config gc.writeCommitGraph false &&
- infodir=".git/objects/info" &&
+ objdir=".git/objects" &&
+ infodir="$objdir/info" &&
graphdir="$infodir/commit-graphs" &&
test_oid_cache <<-EOM
shallow sha1:2132
@@ -199,7 +202,7 @@ then
graph_git_behavior 'alternate: commit 13 vs 6' commits/13 origin/commits/6 "fork"
fi
-test_expect_success 'test merge stragety constants' '
+test_expect_success 'test merge strategy constants' '
git clone . merge-2 &&
(
cd merge-2 &&
@@ -281,7 +284,33 @@ test_expect_success 'verify hashes along chain, even in shallow' '
corrupt_file "$base_file" $(test_oid shallow) "\01" &&
test_must_fail git commit-graph verify --shallow 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "incorrect checksum" err
+ test_grep "incorrect checksum" err
+ )
+'
+
+test_expect_success 'verify notices chain slice which is bogus (base)' '
+ git clone --no-hardlinks . verify-chain-bogus-base &&
+ (
+ cd verify-chain-bogus-base &&
+ git commit-graph verify &&
+ base_file=$graphdir/graph-$(sed -n 1p $graphdir/commit-graph-chain).graph &&
+ echo "garbage" >$base_file &&
+ test_must_fail git commit-graph verify 2>test_err &&
+ grep -v "^+" test_err >err &&
+ grep "commit-graph file is too small" err
+ )
+'
+
+test_expect_success 'verify notices chain slice which is bogus (tip)' '
+ git clone --no-hardlinks . verify-chain-bogus-tip &&
+ (
+ cd verify-chain-bogus-tip &&
+ git commit-graph verify &&
+ tip_file=$graphdir/graph-$(sed -n 2p $graphdir/commit-graph-chain).graph &&
+ echo "garbage" >$tip_file &&
+ test_must_fail git commit-graph verify 2>test_err &&
+ grep -v "^+" test_err >err &&
+ grep "commit-graph file is too small" err
)
'
@@ -291,11 +320,11 @@ test_expect_success 'verify --shallow does not check base contents' '
cd verify-shallow &&
git commit-graph verify &&
base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph &&
- corrupt_file "$base_file" 1000 "\01" &&
+ corrupt_file "$base_file" 1500 "\01" &&
git commit-graph verify --shallow &&
test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "incorrect checksum" err
+ test_grep "incorrect checksum" err
)
'
@@ -306,24 +335,51 @@ test_expect_success 'warn on base graph chunk incorrect' '
git commit-graph verify &&
base_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
corrupt_file "$base_file" $(test_oid base) "\01" &&
- git commit-graph verify --shallow 2>test_err &&
+ test_must_fail git commit-graph verify --shallow 2>test_err &&
+ grep -v "^+" test_err >err &&
+ test_grep "commit-graph chain does not match" err
+ )
+'
+
+test_expect_success 'verify after commit-graph-chain corruption (base)' '
+ git clone --no-hardlinks . verify-chain-base &&
+ (
+ cd verify-chain-base &&
+ corrupt_file "$graphdir/commit-graph-chain" 30 "G" &&
+ test_must_fail git commit-graph verify 2>test_err &&
+ grep -v "^+" test_err >err &&
+ test_grep "invalid commit-graph chain" err &&
+ corrupt_file "$graphdir/commit-graph-chain" 30 "A" &&
+ test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "commit-graph chain does not match" err
+ test_grep "unable to find all commit-graph files" err
)
'
-test_expect_success 'verify after commit-graph-chain corruption' '
- git clone --no-hardlinks . verify-chain &&
+test_expect_success 'verify after commit-graph-chain corruption (tip)' '
+ git clone --no-hardlinks . verify-chain-tip &&
(
- cd verify-chain &&
- corrupt_file "$graphdir/commit-graph-chain" 60 "G" &&
- git commit-graph verify 2>test_err &&
+ cd verify-chain-tip &&
+ corrupt_file "$graphdir/commit-graph-chain" 70 "G" &&
+ test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "invalid commit-graph chain" err &&
- corrupt_file "$graphdir/commit-graph-chain" 60 "A" &&
- git commit-graph verify 2>test_err &&
+ test_grep "invalid commit-graph chain" err &&
+ corrupt_file "$graphdir/commit-graph-chain" 70 "A" &&
+ test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "unable to find all commit-graph files" err
+ test_grep "unable to find all commit-graph files" err
+ )
+'
+
+test_expect_success 'verify notices too-short chain file' '
+ git clone --no-hardlinks . verify-chain-short &&
+ (
+ cd verify-chain-short &&
+ git commit-graph verify &&
+ echo "garbage" >$graphdir/commit-graph-chain &&
+ test_must_fail git commit-graph verify 2>test_err &&
+ grep -v "^+" test_err >err &&
+ grep "commit-graph chain file too small" err
)
'
@@ -338,10 +394,23 @@ test_expect_success 'verify across alternates' '
test_commit extra &&
git commit-graph write --reachable --split &&
tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
- corrupt_file "$tip_file" 100 "\01" &&
+ corrupt_file "$tip_file" 1500 "\01" &&
test_must_fail git commit-graph verify --shallow 2>test_err &&
grep -v "^+" test_err >err &&
- test_i18ngrep "commit-graph has incorrect fanout value" err
+ test_grep "incorrect checksum" err
+ )
+'
+
+test_expect_success 'reader bounds-checks base-graph chunk' '
+ git clone --no-hardlinks . corrupt-base-chunk &&
+ (
+ cd corrupt-base-chunk &&
+ tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
+ corrupt_chunk_file "$tip_file" BASE clear 01020304 &&
+ git -c core.commitGraph=false log >expect.out &&
+ git -c core.commitGraph=true log >out 2>err &&
+ test_cmp expect.out out &&
+ grep "commit-graph base graphs chunk is too small" err
)
'
@@ -353,7 +422,7 @@ test_expect_success 'add octopus merge' '
git commit-graph verify --progress 2>err &&
test_line_count = 1 err &&
grep "Verifying commits in commit graph: 100% (18/18)" err &&
- test_i18ngrep ! warning err &&
+ test_grep ! warning err &&
test_line_count = 3 $graphdir/commit-graph-chain
'
@@ -455,7 +524,7 @@ test_expect_success 'prevent regression for duplicate commits across layers' '
git init dup &&
git -C dup commit --allow-empty -m one &&
git -C dup -c core.commitGraph=false commit-graph write --split=no-merge --reachable 2>err &&
- test_i18ngrep "attempting to write a commit-graph" err &&
+ test_grep "attempting to write a commit-graph" err &&
git -C dup commit-graph write --split=no-merge --reachable &&
git -C dup commit --allow-empty -m two &&
git -C dup commit-graph write --split=no-merge --reachable &&
@@ -649,4 +718,27 @@ test_expect_success 'write generation data chunk when commit-graph chain is repl
)
'
+test_expect_success 'temporary graph layer is discarded upon failure' '
+ git init layer-discard &&
+ (
+ cd layer-discard &&
+
+ test_commit A &&
+ test_commit B &&
+
+ # Intentionally remove commit "A" from the object store
+ # so that the commit-graph machinery fails to parse the
+ # parents of "B".
+ #
+ # This takes place after the commit-graph machinery has
+ # initialized a new temporary file to store the contents
+ # of the new graph layer, so will allow us to ensure
+ # that the temporary file is discarded upon failure.
+ rm $objdir/$(test_oid_to_path $(git rev-parse HEAD^)) &&
+
+ test_must_fail git commit-graph write --reachable --split &&
+ test_dir_is_empty $graphdir
+ )
+'
+
test_done
diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh
index 431a603ca0..285c8b4a49 100755
--- a/t/t5325-reverse-index.sh
+++ b/t/t5325-reverse-index.sh
@@ -2,7 +2,6 @@
test_description='on-disk reverse index'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# The below tests want control over the 'pack.writeReverseIndex' setting
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 70d1b58709..d27557b9b0 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -1,13 +1,14 @@
#!/bin/sh
test_description='exercise basic multi-pack bitmap functionality'
+
. ./test-lib.sh
. "${TEST_DIRECTORY}/lib-bitmap.sh"
-# We'll be writing our own midx and bitmaps, so avoid getting confused by the
+# We'll be writing our own MIDX, so avoid getting confused by the
# automatic ones.
GIT_TEST_MULTI_PACK_INDEX=0
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
# This test exercise multi-pack bitmap functionality where the object order is
# stored and read from a special chunk within the MIDX, so use the default
@@ -434,6 +435,27 @@ test_expect_success 'tagged commits are selected for bitmapping' '
)
'
+test_expect_success 'do not follow replace objects for MIDX bitmap' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ test_commit B &&
+ git checkout --orphan=orphan A &&
+ test_commit orphan &&
+
+ git replace A HEAD &&
+ git repack -ad --write-midx --write-bitmap-index &&
+
+ # generating reachability bitmaps with replace refs
+ # enabled will result in broken clones
+ git clone --no-local --bare . clone.git
+ )
+'
+
corrupt_file () {
chmod a+w "$1" &&
printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc
@@ -513,4 +535,51 @@ test_expect_success 'corrupt MIDX with bitmap causes fallback' '
)
'
+for allow_pack_reuse in single multi
+do
+ test_expect_success "reading MIDX without BTMP chunk does not complain with $allow_pack_reuse pack reuse" '
+ test_when_finished "rm -rf midx-without-btmp" &&
+ git init midx-without-btmp &&
+ (
+ cd midx-without-btmp &&
+ test_commit initial &&
+
+ git repack -Adbl --write-bitmap-index --write-midx &&
+ GIT_TEST_MIDX_READ_BTMP=false git -c pack.allowPackReuse=$allow_pack_reuse \
+ pack-objects --all --use-bitmap-index --stdout </dev/null >/dev/null 2>err &&
+ test_must_be_empty err
+ )
+ '
+done
+
+test_expect_success 'remove one packfile between MIDX bitmap writes' '
+ git init remove-pack-between-writes &&
+ (
+ cd remove-pack-between-writes &&
+
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+
+ # Create packs with the prefix "pack-A", "pack-B",
+ # "pack-C" to impose a lexicographic order on these
+ # packs so the pack being removed is always from the
+ # middle.
+ packdir=.git/objects/pack &&
+ A="$(echo A | git pack-objects $packdir/pack-A --revs)" &&
+ B="$(echo B | git pack-objects $packdir/pack-B --revs)" &&
+ C="$(echo C | git pack-objects $packdir/pack-C --revs)" &&
+
+ git multi-pack-index write --bitmap &&
+
+ cat >in <<-EOF &&
+ pack-A-$A.idx
+ pack-C-$C.idx
+ EOF
+ git multi-pack-index write --bitmap --stdin-packs <in &&
+
+ git rev-list --test-bitmap HEAD
+ )
+'
+
test_done
diff --git a/t/t5327-multi-pack-bitmaps-rev.sh b/t/t5327-multi-pack-bitmaps-rev.sh
index e65e311cd7..9cac03a94b 100755
--- a/t/t5327-multi-pack-bitmaps-rev.sh
+++ b/t/t5327-multi-pack-bitmaps-rev.sh
@@ -5,10 +5,10 @@ test_description='exercise basic multi-pack bitmap functionality (.rev files)'
. ./test-lib.sh
. "${TEST_DIRECTORY}/lib-bitmap.sh"
-# We'll be writing our own midx and bitmaps, so avoid getting confused by the
-# automatic ones.
+# We'll be writing our own MIDX, so avoid getting confused by the automatic
+# ones.
GIT_TEST_MULTI_PACK_INDEX=0
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
# Unlike t5326, this test exercise multi-pack bitmap functionality where the
# object order is stored in a separate .rev file.
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
index e9c521c061..a766a3e3f8 100755
--- a/t/t5328-commit-graph-64bit-time.sh
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='commit graph with 64-bit timestamps'
+
. ./test-lib.sh
if ! test_have_prereq TIME_IS_64BIT || ! test_have_prereq TIME_T_IS_64BIT
@@ -10,6 +11,7 @@ then
fi
. "$TEST_DIRECTORY"/lib-commit-graph.sh
+. "$TEST_DIRECTORY/lib-chunk.sh"
UNIX_EPOCH_ZERO="@0 +0000"
FUTURE_DATE="@4147483646 +0000"
@@ -72,4 +74,13 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
git -C repo-uint32-max commit-graph verify
'
+test_expect_success 'reader notices out-of-bounds generation overflow' '
+ graph=.git/objects/info/commit-graph &&
+ test_when_finished "rm -rf $graph" &&
+ git commit-graph write --reachable &&
+ corrupt_chunk_file $graph GDO2 clear &&
+ test_must_fail git log 2>err &&
+ grep "commit-graph overflow generation data is too small" err
+'
+
test_done
diff --git a/t/t5329-pack-objects-cruft.sh b/t/t5329-pack-objects-cruft.sh
index 45667d4999..b71a0aef40 100755
--- a/t/t5329-pack-objects-cruft.sh
+++ b/t/t5329-pack-objects-cruft.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='cruft pack related pack-objects tests'
+
. ./test-lib.sh
objdir=.git/objects
@@ -573,23 +574,54 @@ test_expect_success 'cruft repack with no reachable objects' '
)
'
-test_expect_success 'cruft repack ignores --max-pack-size' '
+write_blob () {
+ test-tool genrandom "$@" >in &&
+ git hash-object -w -t blob in
+}
+
+find_pack () {
+ for idx in $(ls $packdir/pack-*.idx)
+ do
+ git show-index <$idx >out &&
+ if grep -q "$1" out
+ then
+ echo $idx
+ fi || return 1
+ done
+}
+
+test_expect_success 'cruft repack with --max-pack-size' '
git init max-pack-size &&
(
cd max-pack-size &&
test_commit base &&
+
# two cruft objects which exceed the maximum pack size
- test-tool genrandom foo 1048576 | git hash-object --stdin -w &&
- test-tool genrandom bar 1048576 | git hash-object --stdin -w &&
+ foo=$(write_blob foo 1048576) &&
+ bar=$(write_blob bar 1048576) &&
+ test-tool chmtime --get -1000 \
+ "$objdir/$(test_oid_to_path $foo)" >foo.mtime &&
+ test-tool chmtime --get -2000 \
+ "$objdir/$(test_oid_to_path $bar)" >bar.mtime &&
git repack --cruft --max-pack-size=1M &&
find $packdir -name "*.mtimes" >cruft &&
- test_line_count = 1 cruft &&
- test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects &&
- test_line_count = 2 objects
+ test_line_count = 2 cruft &&
+
+ foo_mtimes="$(basename $(find_pack $foo) .idx).mtimes" &&
+ bar_mtimes="$(basename $(find_pack $bar) .idx).mtimes" &&
+ test-tool pack-mtimes $foo_mtimes >foo.actual &&
+ test-tool pack-mtimes $bar_mtimes >bar.actual &&
+
+ echo "$foo $(cat foo.mtime)" >foo.expect &&
+ echo "$bar $(cat bar.mtime)" >bar.expect &&
+
+ test_cmp foo.expect foo.actual &&
+ test_cmp bar.expect bar.actual &&
+ test "$foo_mtimes" != "$bar_mtimes"
)
'
-test_expect_success 'cruft repack ignores pack.packSizeLimit' '
+test_expect_success 'cruft repack with pack.packSizeLimit' '
(
cd max-pack-size &&
# repack everything back together to remove the existing cruft
@@ -599,9 +631,12 @@ test_expect_success 'cruft repack ignores pack.packSizeLimit' '
# ensure the same post condition is met when --max-pack-size
# would otherwise be inferred from the configuration
find $packdir -name "*.mtimes" >cruft &&
- test_line_count = 1 cruft &&
- test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects &&
- test_line_count = 2 objects
+ test_line_count = 2 cruft &&
+ for pack in $(cat cruft)
+ do
+ test-tool pack-mtimes "$(basename $pack)" >objects &&
+ test_line_count = 1 objects || return 1
+ done
)
'
@@ -654,7 +689,7 @@ test_expect_success 'cruft --local drops unreachable objects' '
test_when_finished "rm -fr alternate repo" &&
test_commit -C alternate base &&
- # Pack all objects in alterate so that the cruft repack in "repo" sees
+ # Pack all objects in alternate so that the cruft repack in "repo" sees
# the object it dropped due to `--local` as packed. Otherwise this
# object would not appear packed anywhere (since it is not packed in
# alternate and likewise not part of the cruft pack in the other repo
diff --git a/t/t5330-no-lazy-fetch-with-commit-graph.sh b/t/t5330-no-lazy-fetch-with-commit-graph.sh
index 5eb28f0512..313eadba98 100755
--- a/t/t5330-no-lazy-fetch-with-commit-graph.sh
+++ b/t/t5330-no-lazy-fetch-with-commit-graph.sh
@@ -2,7 +2,6 @@
test_description='test for no lazy fetch with the commit-graph'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: prepare a repository with a commit' '
@@ -38,9 +37,9 @@ test_expect_success 'fetch any commit from promisor with the usage of the commit
git -C with-commit-graph config remote.origin.partialclonefilter blob:none &&
test_commit -C with-commit any-commit &&
anycommit=$(git -C with-commit rev-parse HEAD) &&
- GIT_TRACE="$(pwd)/trace.txt" \
+ test_must_fail env GIT_TRACE="$(pwd)/trace.txt" \
git -C with-commit-graph fetch origin $anycommit 2>err &&
- ! grep "fatal: promisor-remote: unable to fork off fetch subprocess" err &&
+ test_grep ! "fatal: promisor-remote: unable to fork off fetch subprocess" err &&
grep "git fetch origin" trace.txt >actual &&
test_line_count = 1 actual
'
diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh
index acab31667a..b48c0cbe8f 100755
--- a/t/t5331-pack-objects-stdin.sh
+++ b/t/t5331-pack-objects-stdin.sh
@@ -4,7 +4,6 @@ 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 () {
@@ -65,7 +64,7 @@ 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_grep "cannot use --filter with --stdin-packs" err
)
'
@@ -74,7 +73,7 @@ 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_grep "cannot use internal rev list with --stdin-packs" err
)
'
diff --git a/t/t5332-multi-pack-reuse.sh b/t/t5332-multi-pack-reuse.sh
new file mode 100755
index 0000000000..57cad7708f
--- /dev/null
+++ b/t/t5332-multi-pack-reuse.sh
@@ -0,0 +1,283 @@
+#!/bin/sh
+
+test_description='pack-objects multi-pack reuse'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-bitmap.sh
+
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
+objdir=.git/objects
+packdir=$objdir/pack
+
+test_pack_reused () {
+ test_trace2_data pack-objects pack-reused "$1"
+}
+
+test_packs_reused () {
+ test_trace2_data pack-objects packs-reused "$1"
+}
+
+
+# pack_position <object> </path/to/pack.idx
+pack_position () {
+ git show-index >objects &&
+ grep "$1" objects | cut -d" " -f1
+}
+
+# test_pack_objects_reused_all <pack-reused> <packs-reused>
+test_pack_objects_reused_all () {
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT="$PWD/trace2.txt" \
+ git pack-objects --stdout --revs --all --delta-base-offset \
+ >got.pack &&
+
+ test_pack_reused "$1" <trace2.txt &&
+ test_packs_reused "$2" <trace2.txt &&
+
+ git index-pack --strict -o got.idx got.pack
+}
+
+# test_pack_objects_reused <pack-reused> <packs-reused>
+test_pack_objects_reused () {
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT="$PWD/trace2.txt" \
+ git pack-objects --stdout --revs >got.pack &&
+
+ test_pack_reused "$1" <trace2.txt &&
+ test_packs_reused "$2" <trace2.txt &&
+
+ git index-pack --strict -o got.idx got.pack
+}
+
+test_expect_success 'preferred pack is reused for single-pack reuse' '
+ test_config pack.allowPackReuse single &&
+
+ for i in A B
+ do
+ test_commit "$i" &&
+ git repack -d || return 1
+ done &&
+
+ git multi-pack-index write --bitmap &&
+
+ test_pack_objects_reused_all 3 1
+'
+
+test_expect_success 'multi-pack reuse is disabled by default' '
+ test_pack_objects_reused_all 3 1
+'
+
+test_expect_success 'feature.experimental implies multi-pack reuse' '
+ test_config feature.experimental true &&
+
+ test_pack_objects_reused_all 6 2
+'
+
+test_expect_success 'multi-pack reuse can be disabled with feature.experimental' '
+ test_config feature.experimental true &&
+ test_config pack.allowPackReuse single &&
+
+ test_pack_objects_reused_all 3 1
+'
+
+test_expect_success 'enable multi-pack reuse' '
+ git config pack.allowPackReuse multi
+'
+
+test_expect_success 'reuse all objects from subset of bitmapped packs' '
+ test_commit C &&
+ git repack -d &&
+
+ git multi-pack-index write --bitmap &&
+
+ cat >in <<-EOF &&
+ $(git rev-parse C)
+ ^$(git rev-parse A)
+ EOF
+
+ test_pack_objects_reused 6 2 <in
+'
+
+test_expect_success 'reuse all objects from all packs' '
+ test_pack_objects_reused_all 9 3
+'
+
+test_expect_success 'reuse objects from first pack with middle gap' '
+ for i in D E F
+ do
+ test_commit "$i" || return 1
+ done &&
+
+ # Set "pack.window" to zero to ensure that we do not create any
+ # deltas, which could alter the amount of pack reuse we perform
+ # (if, for e.g., we are not sending one or more bases).
+ D="$(git -c pack.window=0 pack-objects --all --unpacked $packdir/pack)" &&
+
+ d_pos="$(pack_position $(git rev-parse D) <$packdir/pack-$D.idx)" &&
+ e_pos="$(pack_position $(git rev-parse E) <$packdir/pack-$D.idx)" &&
+ f_pos="$(pack_position $(git rev-parse F) <$packdir/pack-$D.idx)" &&
+
+ # commits F, E, and D, should appear in that order at the
+ # beginning of the pack
+ test $f_pos -lt $e_pos &&
+ test $e_pos -lt $d_pos &&
+
+ # Ensure that the pack we are constructing sorts ahead of any
+ # other packs in lexical/bitmap order by choosing it as the
+ # preferred pack.
+ git multi-pack-index write --bitmap --preferred-pack="pack-$D.idx" &&
+
+ cat >in <<-EOF &&
+ $(git rev-parse E)
+ ^$(git rev-parse D)
+ EOF
+
+ test_pack_objects_reused 3 1 <in
+'
+
+test_expect_success 'reuse objects from middle pack with middle gap' '
+ rm -fr $packdir/multi-pack-index* &&
+
+ # Ensure that the pack we are constructing sort into any
+ # position *but* the first one, by choosing a different pack as
+ # the preferred one.
+ git multi-pack-index write --bitmap --preferred-pack="pack-$A.idx" &&
+
+ cat >in <<-EOF &&
+ $(git rev-parse E)
+ ^$(git rev-parse D)
+ EOF
+
+ test_pack_objects_reused 3 1 <in
+'
+
+test_expect_success 'omit delta with uninteresting base (same pack)' '
+ git repack -adk &&
+
+ test_seq 32 >f &&
+ git add f &&
+ test_tick &&
+ git commit -m "delta" &&
+ delta="$(git rev-parse HEAD)" &&
+
+ test_seq 64 >f &&
+ test_tick &&
+ git commit -a -m "base" &&
+ base="$(git rev-parse HEAD)" &&
+
+ test_commit other &&
+
+ git repack -d &&
+
+ have_delta "$(git rev-parse $delta:f)" "$(git rev-parse $base:f)" &&
+
+ git multi-pack-index write --bitmap &&
+
+ cat >in <<-EOF &&
+ $(git rev-parse other)
+ ^$base
+ EOF
+
+ # We can only reuse the 3 objects corresponding to "other" from
+ # the latest pack.
+ #
+ # This is because even though we want "delta", we do not want
+ # "base", meaning that we have to inflate the delta/base-pair
+ # corresponding to the blob in commit "delta", which bypasses
+ # the pack-reuse mechanism.
+ #
+ # The remaining objects from the other pack are similarly not
+ # reused because their objects are on the uninteresting side of
+ # the query.
+ test_pack_objects_reused 3 1 <in
+'
+
+test_expect_success 'omit delta from uninteresting base (cross pack)' '
+ cat >in <<-EOF &&
+ $(git rev-parse $base)
+ ^$(git rev-parse $delta)
+ EOF
+
+ P="$(git pack-objects --revs $packdir/pack <in)" &&
+
+ git multi-pack-index write --bitmap --preferred-pack="pack-$P.idx" &&
+
+ packs_nr="$(find $packdir -type f -name "pack-*.pack" | wc -l)" &&
+ objects_nr="$(git rev-list --count --all --objects)" &&
+
+ test_pack_objects_reused_all $(($objects_nr - 1)) $packs_nr
+'
+
+test_expect_success 'non-omitted delta in MIDX preferred pack' '
+ test_config pack.allowPackReuse single &&
+
+ cat >p1.objects <<-EOF &&
+ $(git rev-parse $base)
+ ^$(git rev-parse $delta^)
+ EOF
+ cat >p2.objects <<-EOF &&
+ $(git rev-parse F)
+ EOF
+
+ p1="$(git pack-objects --revs $packdir/pack <p1.objects)" &&
+ p2="$(git pack-objects --revs $packdir/pack <p2.objects)" &&
+
+ cat >in <<-EOF &&
+ pack-$p1.idx
+ pack-$p2.idx
+ EOF
+ git multi-pack-index write --bitmap --stdin-packs \
+ --preferred-pack=pack-$p1.pack <in &&
+
+ git show-index <$packdir/pack-$p1.idx >expect &&
+
+ test_pack_objects_reused_all $(wc -l <expect) 1
+'
+
+test_expect_success 'duplicate objects' '
+ git init duplicate-objects &&
+ (
+ cd duplicate-objects &&
+
+ git config pack.allowPackReuse multi &&
+
+ test_commit base &&
+
+ git repack -a &&
+
+ git rev-parse HEAD^{tree} >in &&
+ p="$(git pack-objects $packdir/pack <in)" &&
+
+ git multi-pack-index write --bitmap --preferred-pack=pack-$p.idx &&
+
+ objects_nr="$(git rev-list --count --all --objects)" &&
+ packs_nr="$(find $packdir -type f -name "pack-*.pack" | wc -l)" &&
+
+ test_pack_objects_reused_all $objects_nr $packs_nr
+ )
+'
+
+test_expect_success 'duplicate objects with verbatim reuse' '
+ git init duplicate-objects-verbatim &&
+ (
+ cd duplicate-objects-verbatim &&
+
+ git config pack.allowPackReuse multi &&
+
+ test_commit_bulk 64 &&
+
+ # take the first object from the main pack...
+ git show-index <$(ls $packdir/pack-*.idx) >obj.raw &&
+ sort -nk1 <obj.raw | head -n1 | cut -d" " -f2 >in &&
+
+ # ...and create a separate pack containing just that object
+ p="$(git pack-objects $packdir/pack <in)" &&
+
+ git multi-pack-index write --bitmap --preferred-pack=pack-$p.idx &&
+
+ test_pack_objects_reused_all 192 2
+ )
+'
+
+test_done
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
new file mode 100755
index 0000000000..1dd6284756
--- /dev/null
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -0,0 +1,449 @@
+#!/bin/sh
+
+test_description='pseudo-merge bitmaps'
+
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+
+. ./test-lib.sh
+
+test_pseudo_merges () {
+ test-tool bitmap dump-pseudo-merges
+}
+
+test_pseudo_merge_commits () {
+ test-tool bitmap dump-pseudo-merge-commits "$1"
+}
+
+test_pseudo_merges_satisfied () {
+ test_trace2_data bitmap pseudo_merges_satisfied "$1"
+}
+
+test_pseudo_merges_cascades () {
+ test_trace2_data bitmap pseudo_merges_cascades "$1"
+}
+
+test_pseudo_merges_reused () {
+ test_trace2_data pack-bitmap-write building_bitmaps_pseudo_merge_reused "$1"
+}
+
+tag_everything () {
+ git rev-list --all --no-object-names >in &&
+ perl -lne '
+ print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
+ ' <in | git update-ref --stdin
+}
+
+test_expect_success 'setup' '
+ test_commit_bulk 512 &&
+ tag_everything
+'
+
+test_expect_success 'bitmap traversal without pseudo-merges' '
+ git repack -adb &&
+
+ git rev-list --count --all --objects >expect &&
+
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
+
+ test_pseudo_merges_satisfied 0 <trace2.txt &&
+ test_pseudo_merges_cascades 0 <trace2.txt &&
+ test_pseudo_merges >merges &&
+ test_must_be_empty merges &&
+ test_cmp expect actual
+'
+
+test_expect_success 'pseudo-merges accurately represent their objects' '
+ test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
+ test_config bitmapPseudoMerge.test.maxMerges 8 &&
+ test_config bitmapPseudoMerge.test.stableThreshold never &&
+
+ git repack -adb &&
+
+ test_pseudo_merges >merges &&
+ test_line_count = 8 merges &&
+
+ for i in $(test_seq 0 $(($(wc -l <merges)-1)))
+ do
+ test-tool bitmap dump-pseudo-merge-commits $i >commits &&
+
+ git rev-list --objects --no-object-names --stdin <commits >expect.raw &&
+ test-tool bitmap dump-pseudo-merge-objects $i >actual.raw &&
+
+ sort -u <expect.raw >expect &&
+ sort -u <actual.raw >actual &&
+
+ test_cmp expect actual || return 1
+ done
+'
+
+test_expect_success 'bitmap traversal with pseudo-merges' '
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
+ git rev-list --count --all --objects >expect &&
+
+ test_pseudo_merges_satisfied 8 <trace2.txt &&
+ test_pseudo_merges_cascades 1 <trace2.txt &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stale bitmap traversal with pseudo-merges' '
+ test_commit other &&
+
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
+ git rev-list --count --all --objects >expect &&
+
+ test_pseudo_merges_satisfied 8 <trace2.txt &&
+ test_pseudo_merges_cascades 1 <trace2.txt &&
+ test_cmp expect actual
+'
+
+test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
+ test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
+ test_config bitmapPseudoMerge.test.maxMerges 1 &&
+ test_config bitmapPseudoMerge.test.stableThreshold never &&
+
+ commits_nr=$(git rev-list --all --count) &&
+
+ for rate in 1.0 0.5 0.25
+ do
+ git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb &&
+
+ test_pseudo_merges >merges &&
+ test_line_count = 1 merges &&
+ test_pseudo_merge_commits 0 >commits &&
+
+ test-tool bitmap list-commits >bitmaps &&
+ bitmaps_nr="$(wc -l <bitmaps)" &&
+
+ perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \
+ "$rate" "$commits_nr" "$bitmaps_nr" >expect &&
+
+ test $(cat expect) -eq $(wc -l <commits) || return 1
+ done
+'
+
+test_expect_success 'bitmapPseudoMerge.threshold excludes newer commits' '
+ git init pseudo-merge-threshold &&
+ (
+ cd pseudo-merge-threshold &&
+
+ new="1672549200" && # 2023-01-01
+ old="1641013200" && # 2022-01-01
+
+ GIT_COMMITTER_DATE="$new +0000" &&
+ export GIT_COMMITTER_DATE &&
+ test_commit_bulk --message="new" --notick 128 &&
+
+ GIT_COMMITTER_DATE="$old +0000" &&
+ export GIT_COMMITTER_DATE &&
+ test_commit_bulk --message="old" --notick 128 &&
+
+ tag_everything &&
+
+ git \
+ -c bitmapPseudoMerge.test.pattern="refs/tags/" \
+ -c bitmapPseudoMerge.test.maxMerges=1 \
+ -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \
+ -c bitmapPseudoMerge.test.stableThreshold=never \
+ repack -adb &&
+
+ test_pseudo_merges >merges &&
+ test_line_count = 1 merges &&
+
+ test_pseudo_merge_commits 0 >oids &&
+ git cat-file --batch <oids >commits &&
+
+ test $(wc -l <oids) = $(grep -c "^committer.*$old +0000$" commits)
+ )
+'
+
+test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' '
+ (
+ cd pseudo-merge-threshold &&
+
+ new="1672549200" && # 2023-01-01
+ mid="1654059600" && # 2022-06-01
+ old="1641013200" && # 2022-01-01
+
+ GIT_COMMITTER_DATE="$mid +0000" &&
+ export GIT_COMMITTER_DATE &&
+ test_commit_bulk --message="mid" --notick 128 &&
+
+ git for-each-ref --format="delete %(refname)" refs/tags >in &&
+ git update-ref --stdin <in &&
+
+ tag_everything &&
+
+ git \
+ -c bitmapPseudoMerge.test.pattern="refs/tags/" \
+ -c bitmapPseudoMerge.test.maxMerges=1 \
+ -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \
+ -c bitmapPseudoMerge.test.stableThreshold=$(($mid - 1)) \
+ -c bitmapPseudoMerge.test.stableSize=10 \
+ repack -adb &&
+
+ test_pseudo_merges >merges &&
+ merges_nr="$(wc -l <merges)" &&
+
+ for i in $(test_seq $(($merges_nr - 1)))
+ do
+ test_pseudo_merge_commits 0 >oids &&
+ git cat-file --batch <oids >commits &&
+
+ expect="$(grep -c "^committer.*$old +0000$" commits)" &&
+ actual="$(wc -l <oids)" &&
+
+ test $expect = $actual || return 1
+ done &&
+
+ test_pseudo_merge_commits $(($merges_nr - 1)) >oids &&
+ git cat-file --batch <oids >commits &&
+ test $(wc -l <oids) = $(grep -c "^committer.*$mid +0000$" commits)
+ )
+'
+
+test_expect_success 'out of order thresholds are rejected' '
+ test_must_fail git \
+ -c bitmapPseudoMerge.test.pattern="refs/*" \
+ -c bitmapPseudoMerge.test.threshold=1.month.ago \
+ -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \
+ repack -adb 2>err &&
+
+ cat >expect <<-EOF &&
+ fatal: pseudo-merge group ${SQ}test${SQ} has unstable threshold before stable one
+ EOF
+
+ test_cmp expect err
+'
+
+test_expect_success 'pseudo-merge pattern with capture groups' '
+ git init pseudo-merge-captures &&
+ (
+ cd pseudo-merge-captures &&
+
+ test_commit_bulk 128 &&
+ tag_everything &&
+
+ for r in $(test_seq 8)
+ do
+ test_commit_bulk 16 &&
+
+ git rev-list HEAD~16.. >in &&
+
+ perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
+ git update-ref --stdin || return 1
+ done &&
+
+ git \
+ -c bitmapPseudoMerge.tags.pattern="refs/remotes/([0-9]+)/tags/" \
+ -c bitmapPseudoMerge.tags.maxMerges=1 \
+ repack -adb &&
+
+ git for-each-ref --format="%(objectname) %(refname)" >refs &&
+
+ test_pseudo_merges >merges &&
+ for m in $(test_seq 0 $(($(wc -l <merges) - 1)))
+ do
+ test_pseudo_merge_commits $m >oids &&
+ grep -f oids refs |
+ perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" |
+ sort -u || return 1
+ done >remotes &&
+
+ test $(wc -l <remotes) -eq $(sort -u <remotes | wc -l)
+ )
+'
+
+test_expect_success 'pseudo-merge overlap setup' '
+ git init pseudo-merge-overlap &&
+ (
+ cd pseudo-merge-overlap &&
+
+ test_commit_bulk 256 &&
+ tag_everything &&
+
+ git \
+ -c bitmapPseudoMerge.all.pattern="refs/" \
+ -c bitmapPseudoMerge.all.maxMerges=1 \
+ -c bitmapPseudoMerge.all.stableThreshold=never \
+ -c bitmapPseudoMerge.tags.pattern="refs/tags/" \
+ -c bitmapPseudoMerge.tags.maxMerges=1 \
+ -c bitmapPseudoMerge.tags.stableThreshold=never \
+ repack -adb
+ )
+'
+
+test_expect_success 'pseudo-merge overlap generates overlapping groups' '
+ (
+ cd pseudo-merge-overlap &&
+
+ test_pseudo_merges >merges &&
+ test_line_count = 2 merges &&
+
+ test_pseudo_merge_commits 0 >commits-0.raw &&
+ test_pseudo_merge_commits 1 >commits-1.raw &&
+
+ sort commits-0.raw >commits-0 &&
+ sort commits-1.raw >commits-1 &&
+
+ comm -12 commits-0 commits-1 >overlap &&
+
+ test_line_count -gt 0 overlap
+ )
+'
+
+test_expect_success 'pseudo-merge overlap traversal' '
+ (
+ cd pseudo-merge-overlap &&
+
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
+ git rev-list --count --all --objects >expect &&
+
+ test_pseudo_merges_satisfied 2 <trace2.txt &&
+ test_pseudo_merges_cascades 1 <trace2.txt &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'pseudo-merge overlap stale traversal' '
+ (
+ cd pseudo-merge-overlap &&
+
+ test_commit other &&
+
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
+ git rev-list --count --all --objects >expect &&
+
+ test_pseudo_merges_satisfied 2 <trace2.txt &&
+ test_pseudo_merges_cascades 1 <trace2.txt &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'pseudo-merge reuse' '
+ git init pseudo-merge-reuse &&
+ (
+ cd pseudo-merge-reuse &&
+
+ stable="1641013200" && # 2022-01-01
+ unstable="1672549200" && # 2023-01-01
+
+ GIT_COMMITTER_DATE="$stable +0000" &&
+ export GIT_COMMITTER_DATE &&
+ test_commit_bulk --notick 128 &&
+ GIT_COMMITTER_DATE="$unstable +0000" &&
+ export GIT_COMMITTER_DATE &&
+ test_commit_bulk --notick 128 &&
+
+ tag_everything &&
+
+ git \
+ -c bitmapPseudoMerge.test.pattern="refs/tags/" \
+ -c bitmapPseudoMerge.test.maxMerges=1 \
+ -c bitmapPseudoMerge.test.threshold=now \
+ -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \
+ -c bitmapPseudoMerge.test.stableSize=512 \
+ repack -adb &&
+
+ test_pseudo_merges >merges &&
+ test_line_count = 2 merges &&
+
+ test_pseudo_merge_commits 0 >stable-oids.before &&
+ test_pseudo_merge_commits 1 >unstable-oids.before &&
+
+ : >trace2.txt &&
+ GIT_TRACE2_EVENT=$PWD/trace2.txt git \
+ -c bitmapPseudoMerge.test.pattern="refs/tags/" \
+ -c bitmapPseudoMerge.test.maxMerges=2 \
+ -c bitmapPseudoMerge.test.threshold=now \
+ -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \
+ -c bitmapPseudoMerge.test.stableSize=512 \
+ repack -adb &&
+
+ test_pseudo_merges_reused 1 <trace2.txt &&
+
+ test_pseudo_merges >merges &&
+ test_line_count = 3 merges &&
+
+ test_pseudo_merge_commits 0 >stable-oids.after &&
+ for i in 1 2
+ do
+ test_pseudo_merge_commits $i || return 1
+ done >unstable-oids.after &&
+
+ sort -u <stable-oids.before >expect &&
+ sort -u <stable-oids.after >actual &&
+ test_cmp expect actual &&
+
+ sort -u <unstable-oids.before >expect &&
+ sort -u <unstable-oids.after >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'empty pseudo-merge group' '
+ git init pseudo-merge-empty-group &&
+ (
+ cd pseudo-merge-empty-group &&
+
+ # Ensure that a pseudo-merge group with no unstable
+ # commits does not generate an empty pseudo-merge
+ # bitmap.
+ git config bitmapPseudoMerge.empty.pattern refs/ &&
+
+ test_commit base &&
+ git repack -adb &&
+
+ test-tool bitmap dump-pseudo-merges >merges &&
+ test_line_count = 1 merges &&
+
+ test 0 -eq "$(grep -c commits=0 <merges)"
+ )
+'
+
+test_expect_success 'pseudo-merge closure' '
+ git init pseudo-merge-closure &&
+ (
+ cd pseudo-merge-closure &&
+
+ test_commit A &&
+ git repack -d &&
+
+ test_commit B &&
+
+ # Note that the contents of A is packed, but B is not. A
+ # (and the objects reachable from it) are thus visible
+ # to the MIDX, but the same is not true for B and its
+ # objects.
+ #
+ # Ensure that we do not attempt to create a pseudo-merge
+ # for B, depsite it matching the below pseudo-merge
+ # group pattern, as doing so would result in a failure
+ # to write a non-closed bitmap.
+ git config bitmapPseudoMerge.test.pattern refs/ &&
+ git config bitmapPseudoMerge.test.threshold now &&
+
+ git multi-pack-index write --bitmap &&
+
+ test-tool bitmap dump-pseudo-merges >pseudo-merges &&
+ test_line_count = 1 pseudo-merges &&
+
+ git rev-parse A >expect &&
+
+ test-tool bitmap list-commits >actual &&
+ test_cmp expect actual &&
+ test-tool bitmap dump-pseudo-merge-commits 0 >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_done
diff --git a/t/t5334-incremental-multi-pack-index.sh b/t/t5334-incremental-multi-pack-index.sh
new file mode 100755
index 0000000000..26257e5660
--- /dev/null
+++ b/t/t5334-incremental-multi-pack-index.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+test_description='incremental multi-pack-index'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-midx.sh
+
+GIT_TEST_MULTI_PACK_INDEX=0
+export GIT_TEST_MULTI_PACK_INDEX
+
+objdir=.git/objects
+packdir=$objdir/pack
+midxdir=$packdir/multi-pack-index.d
+midx_chain=$midxdir/multi-pack-index-chain
+
+test_expect_success 'convert non-incremental MIDX to incremental' '
+ test_commit base &&
+ git repack -ad &&
+ git multi-pack-index write &&
+
+ test_path_is_file $packdir/multi-pack-index &&
+ old_hash="$(midx_checksum $objdir)" &&
+
+ test_commit other &&
+ git repack -d &&
+ git multi-pack-index write --incremental &&
+
+ test_path_is_missing $packdir/multi-pack-index &&
+ test_path_is_file $midx_chain &&
+ test_line_count = 2 $midx_chain &&
+ grep $old_hash $midx_chain
+'
+
+compare_results_with_midx 'incremental MIDX'
+
+test_expect_success 'convert incremental to non-incremental' '
+ test_commit squash &&
+ git repack -d &&
+ git multi-pack-index write &&
+
+ test_path_is_file $packdir/multi-pack-index &&
+ test_dir_is_empty $midxdir
+'
+
+compare_results_with_midx 'non-incremental MIDX conversion'
+
+test_done
diff --git a/t/t5351-unpack-large-objects.sh b/t/t5351-unpack-large-objects.sh
index 43cbcd5d49..d76eb4be93 100755
--- a/t/t5351-unpack-large-objects.sh
+++ b/t/t5351-unpack-large-objects.sh
@@ -5,7 +5,6 @@
test_description='git unpack-objects with large objects'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
prepare_dest () {
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 001b7a17ad..723d1e17ec 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -4,6 +4,7 @@
#
test_description='Test the update hook infrastructure.'
+
. ./test-lib.sh
test_expect_success setup '
@@ -123,7 +124,7 @@ remote: STDOUT post-update
remote: STDERR post-update
EOF
test_expect_success 'send-pack stderr contains hook messages' '
- grep ^remote: send.err | sed "s/ *\$//" >actual &&
+ sed -n "/^remote:/s/ *\$//p" send.err >actual &&
test_cmp expect actual
'
@@ -133,10 +134,8 @@ test_expect_success 'pre-receive hook that forgets to read its input' '
EOF
rm -f victim.git/hooks/update victim.git/hooks/post-update &&
- for v in $(test_seq 100 999)
- do
- git branch branch_$v main || return
- done &&
+ printf "create refs/heads/branch_%d main\n" $(test_seq 100 999) >input &&
+ git update-ref --stdin <input &&
git push ./victim.git "+refs/heads/*:refs/heads/*"
'
diff --git a/t/t5402-post-merge-hook.sh b/t/t5402-post-merge-hook.sh
index 46ebdfbeeb..915af2de95 100755
--- a/t/t5402-post-merge-hook.sh
+++ b/t/t5402-post-merge-hook.sh
@@ -7,7 +7,6 @@ test_description='Test the post-merge hook.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index cfaae54739..978f240cda 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -7,7 +7,6 @@ test_description='Test the post-checkout hook.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 51737eeafe..cc07889667 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -5,7 +5,6 @@ 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' '
diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh
index 1686ac13aa..11f03239a0 100755
--- a/t/t5405-send-pack-rewind.sh
+++ b/t/t5405-send-pack-rewind.sh
@@ -5,7 +5,6 @@ test_description='forced push to replace commit we do not have'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index d6a9946633..dcbeb42082 100755
--- a/t/t5406-remote-rejects.sh
+++ b/t/t5406-remote-rejects.sh
@@ -2,7 +2,6 @@
test_description='remote push rejects are reported by client'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t5408-send-pack-stdin.sh b/t/t5408-send-pack-stdin.sh
index e8737df6f9..526a675045 100755
--- a/t/t5408-send-pack-stdin.sh
+++ b/t/t5408-send-pack-stdin.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='send-pack --stdin tests'
+
. ./test-lib.sh
create_ref () {
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 7a45d4c311..0b28e4e452 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -5,7 +5,6 @@ test_description='git receive-pack with alternate ref filtering'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh
index 6dfc7b1c0d..510fff38da 100644
--- a/t/t5411/test-0026-push-options.sh
+++ b/t/t5411/test-0026-push-options.sh
@@ -18,7 +18,7 @@ test_expect_success "proc-receive: not support push options ($PROTOCOL)" '
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- test_i18ngrep "fatal: the receiving end does not support push options" \
+ test_grep "fatal: the receiving end does not support push options" \
actual &&
test_cmp_refs -C "$upstream" <<-EOF
diff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh
index 768880b40f..9435457de0 100644
--- a/t/t5411/test-0027-push-options--porcelain.sh
+++ b/t/t5411/test-0027-push-options--porcelain.sh
@@ -19,7 +19,7 @@ test_expect_success "proc-receive: not support push options ($PROTOCOL/porcelain
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
- test_i18ngrep "fatal: the receiving end does not support push options" \
+ test_grep "fatal: the receiving end does not support push options" \
actual &&
test_cmp_refs -C "$upstream" <<-EOF
diff --git a/t/t5411/test-0034-report-ft.sh b/t/t5411/test-0034-report-ft.sh
index 0e37535065..78d0b63876 100644
--- a/t/t5411/test-0034-report-ft.sh
+++ b/t/t5411/test-0034-report-ft.sh
@@ -10,7 +10,7 @@ test_expect_success "setup proc-receive hook (ft, $PROTOCOL)" '
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/main/topic(B)
-test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL)" '
+test_expect_success "proc-receive: fall through, let receive-pack to execute ($PROTOCOL)" '
git -C workbench push origin \
$B:refs/for/main/topic \
>out 2>&1 &&
diff --git a/t/t5411/test-0035-report-ft--porcelain.sh b/t/t5411/test-0035-report-ft--porcelain.sh
index b9a05181f1..df5fc212be 100644
--- a/t/t5411/test-0035-report-ft--porcelain.sh
+++ b/t/t5411/test-0035-report-ft--porcelain.sh
@@ -10,7 +10,7 @@ test_expect_success "setup proc-receive hook (fall-through, $PROTOCOL/porcelain)
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/main/topic(B)
-test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL/porcelain)" '
+test_expect_success "proc-receive: fall through, let receive-pack to execute ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
$B:refs/for/main/topic \
>out 2>&1 &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index d18f2823d8..2677cd5faa 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -132,13 +132,18 @@ test_expect_success 'single branch object count' '
'
test_expect_success 'single given branch clone' '
- git clone --single-branch --branch A "file://$(pwd)/." branch-a &&
- test_must_fail git --git-dir=branch-a/.git rev-parse origin/B
+ GIT_TRACE2_EVENT="$(pwd)/branch-a/trace2_event" \
+ git clone --single-branch --branch A "file://$(pwd)/." branch-a &&
+ test_must_fail git --git-dir=branch-a/.git rev-parse origin/B &&
+ grep \"fetch-info\".*\"haves\":0 branch-a/trace2_event &&
+ grep \"fetch-info\".*\"wants\":1 branch-a/trace2_event
'
test_expect_success 'clone shallow depth 1' '
- git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 &&
- test "$(git --git-dir=shallow0/.git rev-list --count HEAD)" = 1
+ GIT_TRACE2_EVENT="$(pwd)/shallow0/trace2_event" \
+ git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 &&
+ test "$(git --git-dir=shallow0/.git rev-list --count HEAD)" = 1 &&
+ grep \"fetch-info\".*\"depth\":1 shallow0/trace2_event
'
test_expect_success 'clone shallow depth 1 with fsck' '
@@ -235,7 +240,10 @@ test_expect_success 'add two more (part 2)' '
test_expect_success 'deepening pull in shallow repo' '
(
cd shallow &&
- git pull --depth 4 .. B
+ GIT_TRACE2_EVENT="$(pwd)/trace2_event" \
+ git pull --depth 4 .. B &&
+ grep \"fetch-info\".*\"depth\":4 trace2_event &&
+ grep \"fetch-info\".*\"shallows\":2 trace2_event
)
'
@@ -306,9 +314,12 @@ test_expect_success 'fetch --depth --no-shallow' '
test_expect_success 'turn shallow to complete repository' '
(
cd shallow &&
- git fetch --unshallow &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2_event" \
+ git fetch --unshallow &&
! test -f .git/shallow &&
- git fsck --full
+ git fsck --full &&
+ grep \"fetch-info\".*\"shallows\":2 trace2_event &&
+ grep \"fetch-info\".*\"depth\":2147483647 trace2_event
)
'
@@ -403,10 +414,10 @@ test_expect_success 'in_vain not triggered before first ACK' '
test_commit -C myserver bar &&
git -C myclient fetch --progress origin 2>log &&
- test_i18ngrep "remote: Total 3 " log
+ test_grep "remote: Total 3 " log
'
-test_expect_success 'in_vain resetted upon ACK' '
+test_expect_success 'in_vain reset upon ACK' '
test_when_finished rm -f log trace2 &&
rm -rf myserver myclient &&
git init myserver &&
@@ -435,7 +446,7 @@ test_expect_success 'in_vain resetted upon ACK' '
# the client reports that first_anotherbranch_commit is common.
GIT_TRACE2_EVENT="$(pwd)/trace2" git -C myclient fetch --progress origin main 2>log &&
grep \"key\":\"total_rounds\",\"value\":\"6\" trace2 &&
- test_i18ngrep "Total 3 " log
+ test_grep "Total 3 " log
'
test_expect_success 'fetch in shallow repo unreachable shallow objects' '
@@ -459,7 +470,7 @@ test_expect_success 'fetch creating new shallow root' '
git fetch --depth=1 --progress 2>actual &&
# This should fetch only the empty commit, no tree or
# blob objects
- test_i18ngrep "remote: Total 1" actual
+ test_grep "remote: Total 1" actual
)
'
@@ -694,7 +705,7 @@ test_expect_success 'fetch-pack cannot fetch a raw sha1 that is not advertised a
# unadvertised objects, so restrict this test to v0.
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -C client fetch-pack ../server \
$(git -C server rev-parse refs/heads/main^) 2>err &&
- test_i18ngrep "Server does not allow request for unadvertised object" err
+ test_grep "Server does not allow request for unadvertised object" err
'
check_prot_path () {
@@ -762,7 +773,7 @@ do
# file with scheme
for p in file
do
- test_expect_success !MINGW "fetch-pack --diag-url $p://$h/$r" '
+ test_expect_success !WINDOWS "fetch-pack --diag-url $p://$h/$r" '
check_prot_path $p://$h/$r $p "/$r"
'
test_expect_success MINGW "fetch-pack --diag-url $p://$h/$r" '
@@ -772,7 +783,7 @@ do
check_prot_path $p:///$r $p "/$r"
'
# No "/~" -> "~" conversion for file
- test_expect_success !MINGW "fetch-pack --diag-url $p://$h/~$r" '
+ test_expect_success !WINDOWS "fetch-pack --diag-url $p://$h/~$r" '
check_prot_path $p://$h/~$r $p "/~$r"
'
test_expect_success MINGW "fetch-pack --diag-url $p://$h/~$r" '
@@ -794,11 +805,17 @@ do
p=ssh
for h in host [::1]
do
- test_expect_success "fetch-pack --diag-url $h:$r" '
+ expectation="success"
+ if test_have_prereq CYGWIN && test "$h" = "[::1]"
+ then
+ expectation="failure"
+ fi
+
+ test_expect_$expectation "fetch-pack --diag-url $h:$r" '
check_prot_host_port_path $h:$r $p "$h" NONE "$r"
'
# Do "/~" -> "~" conversion
- test_expect_success "fetch-pack --diag-url $h:/~$r" '
+ test_expect_$expectation "fetch-pack --diag-url $h:/~$r" '
check_prot_host_port_path $h:/~$r $p "$h" NONE "~$r"
'
done
@@ -826,13 +843,15 @@ test_expect_success 'clone shallow since ...' '
'
test_expect_success 'fetch shallow since ...' '
- git -C shallow11 fetch --shallow-since "200000000 +0700" origin &&
+ GIT_TRACE2_EVENT=$(pwd)/shallow11/trace2_event \
+ git -C shallow11 fetch --shallow-since "200000000 +0700" origin &&
git -C shallow11 log --pretty=tformat:%s origin/main >actual &&
cat >expected <<-\EOF &&
three
two
EOF
- test_cmp expected actual
+ test_cmp expected actual &&
+ grep \"fetch-info\".*\"deepen-since\":true shallow11/trace2_event
'
test_expect_success 'clone shallow since selects no commits' '
@@ -906,6 +925,13 @@ test_expect_success 'fetch exclude tag one' '
test_cmp expected actual
'
+test_expect_success 'fetch exclude tag one as revision' '
+ test_when_finished rm -f rev err &&
+ git -C shallow-exclude rev-parse one >rev &&
+ test_must_fail git -C shallow12 fetch --shallow-exclude $(cat rev) origin 2>err &&
+ grep "deepen-not is not a ref:" err
+'
+
test_expect_success 'fetching deepen' '
test_create_repo shallow-deepen &&
(
@@ -980,6 +1006,16 @@ test_expect_success 'ensure bogus fetch.negotiationAlgorithm yields error' '
fetch origin server_has both_have_2
'
+test_expect_success 'fetch-pack with fsckObjects and keep-file does not segfault' '
+ rm -rf server client &&
+ test_create_repo server &&
+ test_commit -C server one &&
+
+ test_create_repo client &&
+ git -c fetch.fsckObjects=true \
+ -C client fetch-pack -k -k ../server HEAD
+'
+
test_expect_success 'filtering by size' '
rm -rf server client &&
test_create_repo server &&
@@ -987,13 +1023,16 @@ test_expect_success 'filtering by size' '
test_config -C server uploadpack.allowfilter 1 &&
test_create_repo client &&
- git -C client fetch-pack --filter=blob:limit=0 ../server HEAD &&
+ GIT_TRACE2_EVENT=$(pwd)/client/trace2_event \
+ git -C client fetch-pack --filter=blob:limit=0 ../server HEAD &&
# Ensure that object is not inadvertently fetched
commit=$(git -C server rev-parse HEAD) &&
blob=$(git hash-object server/one.t) &&
git -C client rev-list --objects --missing=allow-any "$commit" >oids &&
- ! grep "$blob" oids
+ ! grep "$blob" oids &&
+
+ grep \"fetch-info\".*\"filter\":\"blob:limit\" client/trace2_event
'
test_expect_success 'filtering by size has no effect if support for it is not advertised' '
@@ -1010,7 +1049,7 @@ test_expect_success 'filtering by size has no effect if support for it is not ad
git -C client rev-list --objects --missing=allow-any "$commit" >oids &&
grep "$blob" oids &&
- test_i18ngrep "filtering not recognized by server" err
+ test_grep "filtering not recognized by server" err
'
fetch_filter_blob_limit_zero () {
@@ -1030,7 +1069,7 @@ fetch_filter_blob_limit_zero () {
# Ensure that commit is fetched, but blob is not
commit=$(git -C "$SERVER" rev-parse two) &&
- blob=$(git hash-object server/two.t) &&
+ blob=$(git hash-object "$SERVER/two.t") &&
git -C client rev-list --objects --missing=allow-any "$commit" >oids &&
grep "$commit" oids &&
! grep "$blob" oids
diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh
index 7b3ff21b98..b160f8b7fb 100755
--- a/t/t5502-quickfetch.sh
+++ b/t/t5502-quickfetch.sh
@@ -5,7 +5,6 @@ test_description='test quickfetch from local'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 5ebbaa4896..195fc64dd4 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -5,7 +5,6 @@ test_description='test automatic tag following'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# End state of the repository:
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 0b8ab4afdb..53dbc8ce3a 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -4,7 +4,6 @@ test_description='fetch/receive strict mode'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup and inject "corrupt or missing" object' '
@@ -144,7 +143,7 @@ test_expect_success 'setup bogus commit' '
test_expect_success 'fsck with no skipList input' '
test_must_fail git fsck 2>err &&
- test_i18ngrep "missingEmail" err
+ test_grep "missingEmail" err
'
test_expect_success 'setup sorted and unsorted skipLists' '
@@ -169,9 +168,9 @@ test_expect_success 'fsck with unsorted skipList' '
test_expect_success 'fsck with invalid or bogus skipList input' '
git -c fsck.skipList=/dev/null -c fsck.missingEmail=ignore fsck &&
test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err &&
- test_i18ngrep "could not open.*: does-not-exist" err &&
+ test_grep "could not open.*: does-not-exist" err &&
test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err &&
- test_i18ngrep "invalid object name: \[core\]" err
+ test_grep "invalid object name: \[core\]" err
'
test_expect_success 'fsck with other accepted skipList input (comments & empty lines)' '
@@ -180,14 +179,14 @@ test_expect_success 'fsck with other accepted skipList input (comments & empty l
$(test_oid 001)
EOF
test_must_fail git -c fsck.skipList=SKIP.with-comment fsck 2>err-with-comment &&
- test_i18ngrep "missingEmail" err-with-comment &&
+ test_grep "missingEmail" err-with-comment &&
cat >SKIP.with-empty-line <<-EOF &&
$(test_oid 001)
$(test_oid 002)
EOF
test_must_fail git -c fsck.skipList=SKIP.with-empty-line fsck 2>err-with-empty-line &&
- test_i18ngrep "missingEmail" err-with-empty-line
+ test_grep "missingEmail" err-with-empty-line
'
test_expect_success 'fsck no garbage output from comments & empty lines errors' '
@@ -198,7 +197,7 @@ test_expect_success 'fsck no garbage output from comments & empty lines errors'
test_expect_success 'fsck with invalid abbreviated skipList input' '
echo $commit | test_copy_bytes 20 >SKIP.abbreviated &&
test_must_fail git -c fsck.skipList=SKIP.abbreviated fsck 2>err-abbreviated &&
- test_i18ngrep "^fatal: invalid object name: " err-abbreviated
+ test_grep "^fatal: invalid object name: " err-abbreviated
'
test_expect_success 'fsck with exhaustive accepted skipList input (various types of comments etc.)' '
@@ -231,10 +230,10 @@ test_expect_success 'push with receive.fsck.skipList' '
test_must_fail git push --porcelain dst bogus &&
git --git-dir=dst/.git config receive.fsck.skipList does-not-exist &&
test_must_fail git push --porcelain dst bogus 2>err &&
- test_i18ngrep "could not open.*: does-not-exist" err &&
+ test_grep "could not open.*: does-not-exist" err &&
git --git-dir=dst/.git config receive.fsck.skipList config &&
test_must_fail git push --porcelain dst bogus 2>err &&
- test_i18ngrep "invalid object name: \[core\]" err &&
+ test_grep "invalid object name: \[core\]" err &&
git --git-dir=dst/.git config receive.fsck.skipList SKIP &&
git push --porcelain dst bogus
@@ -260,10 +259,10 @@ test_expect_success 'fetch with fetch.fsck.skipList' '
test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec &&
git --git-dir=dst/.git config fetch.fsck.skipList does-not-exist &&
test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err &&
- test_i18ngrep "could not open.*: does-not-exist" err &&
+ test_grep "could not open.*: does-not-exist" err &&
git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/config &&
test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err &&
- test_i18ngrep "invalid object name: \[core\]" err &&
+ test_grep "invalid object name: \[core\]" err &&
git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/SKIP &&
git --git-dir=dst/.git fetch "file://$(pwd)" $refspec
@@ -271,7 +270,7 @@ test_expect_success 'fetch with fetch.fsck.skipList' '
test_expect_success 'fsck.<unknownmsg-id> dies' '
test_must_fail git -c fsck.whatEver=ignore fsck 2>err &&
- test_i18ngrep "Unhandled message id: whatever" err
+ test_grep "Unhandled message id: whatever" err
'
test_expect_success 'push with receive.fsck.missingEmail=warn' '
@@ -293,7 +292,7 @@ test_expect_success 'push with receive.fsck.missingEmail=warn' '
receive.fsck.missingEmail warn &&
git push --porcelain dst bogus >act 2>&1 &&
grep "missingEmail" act &&
- test_i18ngrep "skipping unknown msg id.*whatever" act &&
+ test_grep "skipping unknown msg id.*whatever" act &&
git --git-dir=dst/.git branch -D bogus &&
git --git-dir=dst/.git config --add \
receive.fsck.missingEmail ignore &&
@@ -321,7 +320,7 @@ test_expect_success 'fetch with fetch.fsck.missingEmail=warn' '
fetch.fsck.missingEmail warn &&
git --git-dir=dst/.git fetch "file://$(pwd)" $refspec >act 2>&1 &&
grep "missingEmail" act &&
- test_i18ngrep "Skipping unknown msg id.*whatever" act &&
+ test_grep "Skipping unknown msg id.*whatever" act &&
rm -rf dst &&
git init dst &&
git --git-dir=dst/.git config fetch.fsckobjects true &&
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 43b7bcd715..08424e878e 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1075,7 +1075,7 @@ test_expect_success 'remote prune to cause a dangling symref' '
cd eight &&
git remote prune origin
) >err 2>&1 &&
- test_i18ngrep "has become dangling" err &&
+ test_grep "has become dangling" err &&
: And the dangling symref will not cause other annoying errors &&
(
@@ -1087,7 +1087,7 @@ test_expect_success 'remote prune to cause a dangling symref' '
cd eight &&
test_must_fail git branch nomore origin
) 2>err &&
- test_i18ngrep "dangling symref" err
+ test_grep "dangling symref" err
'
test_expect_success 'show empty remote' '
@@ -1419,7 +1419,7 @@ test_expect_success 'extra args: setup' '
test_extra_arg () {
test_expect_success "extra args: $*" "
test_must_fail git remote $* bogus_extra_arg 2>actual &&
- test_i18ngrep '^usage:' actual
+ test_grep '^usage:' actual
"
}
@@ -1453,12 +1453,12 @@ test_expect_success 'unqualified <dst> refspec DWIM and advice' '
oid=$(git rev-parse some-tag^{$type})
fi &&
test_must_fail git push origin $oid:dst 2>err &&
- test_i18ngrep "error: The destination you" err &&
- test_i18ngrep "hint: Did you mean" err &&
+ test_grep "error: The destination you" err &&
+ test_grep "hint: Did you mean" err &&
test_must_fail git -c advice.pushUnqualifiedRefName=false \
push origin $oid:dst 2>err &&
- test_i18ngrep "error: The destination you" err &&
- test_i18ngrep ! "hint: Did you mean" err ||
+ test_grep "error: The destination you" err &&
+ test_grep ! "hint: Did you mean" err ||
exit 1
done
)
@@ -1479,17 +1479,53 @@ test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and
git fetch --no-tags two &&
test_must_fail git push origin refs/remotes/two/another:dst 2>err &&
- test_i18ngrep "error: The destination you" err &&
+ test_grep "error: The destination you" err &&
test_must_fail git push origin refs/remotes/tags-from-two/my-tag:dst-tag 2>err &&
- test_i18ngrep "error: The destination you" err &&
+ test_grep "error: The destination you" err &&
test_must_fail git push origin refs/remotes/trees-from-two/my-head-tree:dst-tree 2>err &&
- test_i18ngrep "error: The destination you" err &&
+ test_grep "error: The destination you" err &&
test_must_fail git push origin refs/remotes/blobs-from-two/my-file-blob:dst-blob 2>err &&
- test_i18ngrep "error: The destination you" err
+ test_grep "error: The destination you" err
)
'
+test_expect_success 'empty config clears remote.*.url list' '
+ test_when_finished "git config --remove-section remote.multi" &&
+ git config --add remote.multi.url wrong-one &&
+ git config --add remote.multi.url wrong-two &&
+ git -c remote.multi.url= \
+ -c remote.multi.url=right-one \
+ -c remote.multi.url=right-two \
+ remote show -n multi >actual.raw &&
+ grep URL actual.raw >actual &&
+ cat >expect <<-\EOF &&
+ Fetch URL: right-one
+ Push URL: right-one
+ Push URL: right-two
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'empty config clears remote.*.pushurl list' '
+ test_when_finished "git config --remove-section remote.multi" &&
+ git config --add remote.multi.url right &&
+ git config --add remote.multi.url will-be-ignored &&
+ git config --add remote.multi.pushurl wrong-push-one &&
+ git config --add remote.multi.pushurl wrong-push-two &&
+ git -c remote.multi.pushurl= \
+ -c remote.multi.pushurl=right-push-one \
+ -c remote.multi.pushurl=right-push-two \
+ remote show -n multi >actual.raw &&
+ grep URL actual.raw >actual &&
+ cat >expect <<-\EOF &&
+ Fetch URL: right
+ Push URL: right-push-one
+ Push URL: right-push-two
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh
index 0e176175a3..16e9a1bc2f 100755
--- a/t/t5506-remote-groups.sh
+++ b/t/t5506-remote-groups.sh
@@ -4,7 +4,6 @@ test_description='git remote group handling'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
mark() {
diff --git a/t/t5507-remote-environment.sh b/t/t5507-remote-environment.sh
index c6a6957c50..a41d5b370b 100755
--- a/t/t5507-remote-environment.sh
+++ b/t/t5507-remote-environment.sh
@@ -2,7 +2,6 @@
test_description='check environment showed to remote side of transports'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up "remote" push situation' '
diff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh
index 31553b48df..095df1a753 100755
--- a/t/t5509-fetch-push-namespaces.sh
+++ b/t/t5509-fetch-push-namespaces.sh
@@ -95,6 +95,7 @@ test_expect_success 'hide namespaced refs with transfer.hideRefs' '
'
test_expect_success 'check that transfer.hideRefs does not match unstripped refs' '
+ git -C pushee pack-refs --all &&
GIT_NAMESPACE=namespace \
git -C pushee -c transfer.hideRefs=refs/namespaces/namespace/refs/tags \
ls-remote "ext::git %s ." >actual &&
@@ -122,6 +123,14 @@ test_expect_success 'try to update a ref that is not hidden' '
git -C original push pushee-namespaced main
'
+test_expect_success 'git-receive-pack(1) with transfer.hideRefs does not match unstripped refs during advertisement' '
+ git -C pushee update-ref refs/namespaces/namespace/refs/heads/foo/1 refs/namespaces/namespace/refs/heads/main &&
+ git -C pushee pack-refs --all &&
+ test_config -C pushee transfer.hideRefs refs/namespaces/namespace/refs/heads/foo &&
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C original push pushee-namespaced main &&
+ test_grep refs/heads/foo/1 trace
+'
+
test_expect_success 'try to update a hidden full ref' '
test_config -C pushee transfer.hideRefs "^refs/namespaces/namespace/refs/heads/main" &&
test_must_fail git -C original push pushee-namespaced main
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 5399feda92..3b3991ab86 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -169,6 +169,7 @@ test_expect_success REFFILES 'fetch --prune fails to delete branches' '
git clone . prune-fail &&
cd prune-fail &&
git update-ref refs/remotes/origin/extrabranch main &&
+ git pack-refs --all &&
: this will prevent --prune from locking packed-refs for deleting refs, but adding loose refs still succeeds &&
>.git/packed-refs.new &&
@@ -415,9 +416,9 @@ test_expect_success 'fetch uses remote ref names to describe new refs' '
(
cd descriptive &&
git fetch o 2>actual &&
- test_i18ngrep "new branch.* -> refs/crazyheads/descriptive-branch$" actual &&
- test_i18ngrep "new tag.* -> descriptive-tag$" actual &&
- test_i18ngrep "new ref.* -> crazy$" actual
+ test_grep "new branch.* -> refs/crazyheads/descriptive-branch$" actual &&
+ test_grep "new tag.* -> descriptive-tag$" actual &&
+ test_grep "new ref.* -> crazy$" actual
) &&
git checkout main
'
@@ -517,7 +518,7 @@ test_expect_success 'fetch with a non-applying branch.<name>.merge' '
test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [1]' '
one_head=$(cd one && git rev-parse HEAD) &&
this_head=$(git rev-parse HEAD) &&
- git update-ref -d FETCH_HEAD &&
+ rm .git/FETCH_HEAD &&
git fetch one &&
test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
test $this_head = "$(git rev-parse --verify HEAD)"
@@ -529,7 +530,7 @@ test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge
one_ref=$(cd one && git symbolic-ref HEAD) &&
git config branch.main.remote blub &&
git config branch.main.merge "$one_ref" &&
- git update-ref -d FETCH_HEAD &&
+ rm .git/FETCH_HEAD &&
git fetch one &&
test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
test $this_head = "$(git rev-parse --verify HEAD)"
@@ -539,7 +540,7 @@ test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge
# the merge spec does not match the branch the remote HEAD points to
test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [3]' '
git config branch.main.merge "${one_ref}_not" &&
- git update-ref -d FETCH_HEAD &&
+ rm .git/FETCH_HEAD &&
git fetch one &&
test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
test $this_head = "$(git rev-parse --verify HEAD)"
@@ -802,7 +803,8 @@ test_expect_success 'fetch.writeCommitGraph with submodules' '
cd super-clone &&
rm -rf .git/objects/info &&
git -c fetch.writeCommitGraph=true fetch origin &&
- test_path_is_file .git/objects/info/commit-graphs/commit-graph-chain
+ test_path_is_file .git/objects/info/commit-graphs/commit-graph-chain &&
+ git -c fetch.writeCommitGraph=true fetch --recurse-submodules origin
)
'
@@ -1089,6 +1091,22 @@ test_expect_success 'branchname D/F conflict resolved by --prune' '
test_cmp expect actual
'
+test_expect_success 'branchname D/F conflict rejected with targeted error message' '
+ git clone . df-conflict-error &&
+ git branch dir_conflict &&
+ (
+ cd df-conflict-error &&
+ git update-ref refs/remotes/origin/dir_conflict/file HEAD &&
+ test_must_fail git fetch 2>err &&
+ test_grep "error: some local refs could not be updated; try running" err &&
+ test_grep " ${SQ}git remote prune origin${SQ} to remove any old, conflicting branches" err &&
+ git pack-refs --all &&
+ test_must_fail git fetch 2>err-packed &&
+ test_grep "error: some local refs could not be updated; try running" err-packed &&
+ test_grep " ${SQ}git remote prune origin${SQ} to remove any old, conflicting branches" err-packed
+ )
+'
+
test_expect_success 'fetching a one-level ref works' '
test_commit extra &&
git reset --hard HEAD^ &&
@@ -1113,7 +1131,7 @@ test_expect_success 'fetching with auto-gc does not lock up' '
git config gc.autoPackLimit 1 &&
git config gc.autoDetach false &&
GIT_ASK_YESNO="$D/askyesno" git fetch --verbose >fetch.out 2>&1 &&
- test_i18ngrep "Auto packing the repository" fetch.out &&
+ test_grep "Auto packing the repository" fetch.out &&
! grep "Should I try again" fetch.out
)
'
@@ -1270,7 +1288,7 @@ test_expect_success SYMLINKS 'clone does not get confused by a D/F conflict' '
git commit -m post-checkout
) &&
git clone df-conflict clone 2>err &&
- ! grep WHOOPS err &&
+ test_grep ! WHOOPS err &&
test_path_is_missing whoops
'
diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh
index fc55681a3f..be025b90f9 100755
--- a/t/t5511-refspec.sh
+++ b/t/t5511-refspec.sh
@@ -2,7 +2,6 @@
test_description='refspec parsing'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_refspec () {
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 151c76eb09..3a67992a7d 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -47,6 +47,7 @@ test_expect_success setup '
git show-ref -d >refs &&
sed -e "s/ / /" refs >>expected.all &&
+ grep refs/heads/ expected.all >expected.branches &&
git remote add self "$(pwd)/.git" &&
git remote add self2 "."
'
@@ -71,6 +72,27 @@ test_expect_success 'ls-remote self' '
test_cmp expected.all actual
'
+test_expect_success 'ls-remote --branches self' '
+ git ls-remote --branches self >actual &&
+ test_cmp expected.branches actual &&
+ git ls-remote -b self >actual &&
+ test_cmp expected.branches actual
+'
+
+test_expect_success 'ls-remote -h is deprecated w/o warning' '
+ git ls-remote -h self >actual 2>warning &&
+ test_cmp expected.branches actual &&
+ test_grep ! deprecated warning
+'
+
+test_expect_success 'ls-remote --heads is deprecated and hidden w/o warning' '
+ test_expect_code 129 git ls-remote -h >short-help &&
+ test_grep ! -e --head short-help &&
+ git ls-remote --heads self >actual 2>warning &&
+ test_cmp expected.branches actual &&
+ test_grep ! deprecated warning
+'
+
test_expect_success 'ls-remote --sort="version:refname" --tags self' '
generate_references \
refs/tags/mark \
@@ -275,7 +297,7 @@ test_expect_success 'ls-remote with filtered symref (refname)' '
test_cmp expect actual
'
-test_expect_success 'ls-remote with filtered symref (--heads)' '
+test_expect_success 'ls-remote with filtered symref (--branches)' '
git symbolic-ref refs/heads/foo refs/tags/mark &&
cat >expect.v2 <<-EOF &&
ref: refs/tags/mark refs/heads/foo
@@ -283,9 +305,9 @@ test_expect_success 'ls-remote with filtered symref (--heads)' '
$rev refs/heads/main
EOF
grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 &&
- git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 &&
+ git -c protocol.version=0 ls-remote --symref --branches . >actual.v0 &&
test_cmp expect.v0 actual.v0 &&
- git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 &&
+ git -c protocol.version=2 ls-remote --symref --branches . >actual.v2 &&
test_cmp expect.v2 actual.v2
'
@@ -320,7 +342,7 @@ test_expect_success 'ls-remote works outside repository' '
test_expect_success 'ls-remote --sort fails gracefully outside repository' '
# Use a sort key that requires access to the referenced objects.
nongit test_must_fail git ls-remote --sort=authordate "$TRASH_DIRECTORY" 2>err &&
- test_i18ngrep "^fatal: not a git repository, but the field '\''authordate'\'' requires access to object data" err
+ test_grep "^fatal: not a git repository, but the field '\''authordate'\'' requires access to object data" err
'
test_expect_success 'ls-remote patterns work with all protocol versions' '
@@ -335,9 +357,9 @@ 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=0 ls-remote --heads --tags . >actual.v0 &&
+ git -c protocol.version=0 ls-remote --branches --tags . >actual.v0 &&
test_cmp expect actual.v0 &&
- git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 &&
+ git -c protocol.version=2 ls-remote --branches --tags . >actual.v2 &&
test_cmp expect actual.v2
'
@@ -380,4 +402,18 @@ test_expect_success 'v0 clients can handle multiple symrefs' '
test_cmp expect actual
'
+test_expect_success 'helper with refspec capability fails gracefully' '
+ mkdir test-bin &&
+ write_script test-bin/git-remote-foo <<-EOF &&
+ read capabilities
+ echo import
+ echo refspec ${SQ}*:*${SQ}
+ EOF
+ (
+ PATH="$PWD/test-bin:$PATH" &&
+ export PATH &&
+ test_must_fail nongit git ls-remote foo::bar
+ )
+'
+
test_done
diff --git a/t/t5513-fetch-track.sh b/t/t5513-fetch-track.sh
index c46c4dbaef..65d1e05bd6 100755
--- a/t/t5513-fetch-track.sh
+++ b/t/t5513-fetch-track.sh
@@ -2,7 +2,6 @@
test_description='fetch follows remote-tracking branches correctly'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 98f034aa77..25772c85c5 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -24,6 +24,15 @@ setup_repository () {
)
}
+setup_test_clone () {
+ test_dir="$1" &&
+ git clone one "$test_dir" &&
+ for r in one two three
+ do
+ git -C "$test_dir" remote add "$r" "../$r" || return 1
+ done
+}
+
test_expect_success setup '
setup_repository one &&
setup_repository two &&
@@ -200,8 +209,8 @@ test_expect_success 'parallel' '
test_must_fail env GIT_TRACE="$PWD/trace" \
git fetch --jobs=2 --multiple one two 2>err &&
grep "preparing to run up to 2 tasks" trace &&
- test_i18ngrep "could not fetch .one.*128" err &&
- test_i18ngrep "could not fetch .two.*128" err
+ test_grep "could not fetch .one.*128" err &&
+ test_grep "could not fetch .two.*128" err
'
test_expect_success 'git fetch --multiple --jobs=0 picks a default' '
@@ -209,4 +218,156 @@ test_expect_success 'git fetch --multiple --jobs=0 picks a default' '
git fetch --multiple --jobs=0)
'
+create_fetch_all_expect () {
+ cat >expect <<-\EOF
+ one/main
+ one/side
+ origin/HEAD -> origin/main
+ origin/main
+ origin/side
+ three/another
+ three/main
+ three/side
+ two/another
+ two/main
+ two/side
+ EOF
+}
+
+for fetch_all in true false
+do
+ test_expect_success "git fetch --all (works with fetch.all = $fetch_all)" '
+ test_dir="test_fetch_all_$fetch_all" &&
+ setup_test_clone "$test_dir" &&
+ (
+ cd "$test_dir" &&
+ git config fetch.all $fetch_all &&
+ git fetch --all &&
+ create_fetch_all_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+ '
+done
+
+test_expect_success 'git fetch (fetch all remotes with fetch.all = true)' '
+ setup_test_clone test9 &&
+ (
+ cd test9 &&
+ git config fetch.all true &&
+ git fetch &&
+ git branch -r >actual &&
+ create_fetch_all_expect &&
+ test_cmp expect actual
+ )
+'
+
+create_fetch_one_expect () {
+ cat >expect <<-\EOF
+ one/main
+ one/side
+ origin/HEAD -> origin/main
+ origin/main
+ origin/side
+ EOF
+}
+
+test_expect_success 'git fetch one (explicit remote overrides fetch.all)' '
+ setup_test_clone test10 &&
+ (
+ cd test10 &&
+ git config fetch.all true &&
+ git fetch one &&
+ create_fetch_one_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+'
+
+create_fetch_two_as_origin_expect () {
+ cat >expect <<-\EOF
+ origin/HEAD -> origin/main
+ origin/another
+ origin/main
+ origin/side
+ EOF
+}
+
+test_expect_success 'git config fetch.all false (fetch only default remote)' '
+ setup_test_clone test11 &&
+ (
+ cd test11 &&
+ git config fetch.all false &&
+ git remote set-url origin ../two &&
+ git fetch &&
+ create_fetch_two_as_origin_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+'
+
+for fetch_all in true false
+do
+ test_expect_success "git fetch --no-all (fetch only default remote with fetch.all = $fetch_all)" '
+ test_dir="test_no_all_fetch_all_$fetch_all" &&
+ setup_test_clone "$test_dir" &&
+ (
+ cd "$test_dir" &&
+ git config fetch.all $fetch_all &&
+ git remote set-url origin ../two &&
+ git fetch --no-all &&
+ create_fetch_two_as_origin_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+ '
+done
+
+test_expect_success 'git fetch --no-all (fetch only default remote without fetch.all)' '
+ setup_test_clone test12 &&
+ (
+ cd test12 &&
+ git config --unset-all fetch.all || true &&
+ git remote set-url origin ../two &&
+ git fetch --no-all &&
+ create_fetch_two_as_origin_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'git fetch --all --no-all (fetch only default remote)' '
+ setup_test_clone test13 &&
+ (
+ cd test13 &&
+ git remote set-url origin ../two &&
+ git fetch --all --no-all &&
+ create_fetch_two_as_origin_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'git fetch --no-all one (fetch only explicit remote)' '
+ setup_test_clone test14 &&
+ (
+ cd test14 &&
+ git fetch --no-all one &&
+ create_fetch_one_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'git fetch --no-all --all (fetch all remotes)' '
+ setup_test_clone test15 &&
+ (
+ cd test15 &&
+ git fetch --no-all --all &&
+ create_fetch_all_expect &&
+ git branch -r >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index c100a809c5..320d26796d 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -14,7 +14,6 @@ export GIT_TEST_PROTOCOL_VERSION
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
build_script () {
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 87163d7745..9d693eb57f 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -227,7 +227,17 @@ test_expect_success 'push with negotiation proceeds anyway even if negotiation f
GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" \
git -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
grep_wrote 5 event && # 2 commits, 2 trees, 1 blob
- test_i18ngrep "push negotiation failed" err
+ test_grep "push negotiation failed" err
+'
+
+test_expect_success 'push deletion with negotiation' '
+ mk_empty testrepo &&
+ git push testrepo $the_first_commit:refs/heads/master &&
+ git -c push.negotiate=1 push testrepo \
+ :master $the_first_commit:refs/heads/next 2>errors-2 &&
+ test_grep ! "negotiate-only needs one or " errors-2 &&
+ git -c push.negotiate=1 push testrepo :next 2>errors-1 &&
+ test_grep ! "negotiate-only needs one or " errors-1
'
test_expect_success 'push with negotiation does not attempt to fetch submodules' '
@@ -1267,7 +1277,7 @@ test_expect_success 'fetch exact SHA1' '
# fetching the hidden object should fail by default
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
git fetch -v ../testrepo $the_commit:refs/heads/copy 2>err &&
- test_i18ngrep "Server does not allow request for unadvertised object" err &&
+ test_grep "Server does not allow request for unadvertised object" err &&
test_must_fail git rev-parse --verify refs/heads/copy &&
# the server side can allow it to succeed
@@ -1369,7 +1379,7 @@ do
git fetch ../testrepo/.git $SHA1_3 2>err &&
# ideally we would insist this be on a "remote error:"
# line, but it is racy; see the commit message
- test_i18ngrep "not our ref.*$SHA1_3\$" err
+ test_grep "not our ref.*$SHA1_3\$" err
)
'
done
@@ -1407,7 +1417,7 @@ test_expect_success 'peeled advertisements are not considered ref tips' '
oid=$(git -C testrepo rev-parse mytag^{commit}) &&
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
git fetch testrepo $oid 2>err &&
- test_i18ngrep "Server does not allow request for unadvertised object" err
+ test_grep "Server does not allow request for unadvertised object" err
'
test_expect_success 'pushing a specific ref applies remote.$name.push as refmap' '
diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh
index 6d4944a728..a448e169bd 100755
--- a/t/t5517-push-mirror.sh
+++ b/t/t5517-push-mirror.sh
@@ -5,7 +5,6 @@ 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)
diff --git a/t/t5518-fetch-exit-status.sh b/t/t5518-fetch-exit-status.sh
index c13120088f..5c4ac2556e 100755
--- a/t/t5518-fetch-exit-status.sh
+++ b/t/t5518-fetch-exit-status.sh
@@ -8,7 +8,6 @@ test_description='fetch exit status test'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 0b72112fb1..47534f1062 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -31,7 +31,7 @@ test_pull_autostash_fail () {
echo dirty >new_file &&
git add new_file &&
test_must_fail git pull "$@" . copy 2>err &&
- test_i18ngrep -E "uncommitted changes.|overwritten by merge:" err
+ test_grep -E "uncommitted changes.|overwritten by merge:" err
}
test_expect_success setup '
@@ -151,7 +151,7 @@ test_expect_success 'fail if wildcard spec does not match any refs' '
echo file >expect &&
test_cmp expect file &&
test_must_fail git pull . "refs/nonexisting1/*:refs/nonexisting2/*" 2>err &&
- test_i18ngrep "no candidates for merging" err &&
+ test_grep "no candidates for merging" err &&
test_cmp expect file
'
@@ -164,7 +164,7 @@ test_expect_success 'fail if no branches specified with non-default remote' '
test_cmp expect file &&
test_config branch.test.remote origin &&
test_must_fail git pull test_remote 2>err &&
- test_i18ngrep "specify a branch on the command line" err &&
+ test_grep "specify a branch on the command line" err &&
test_cmp expect file
'
@@ -176,7 +176,7 @@ test_expect_success 'fail if not on a branch' '
echo file >expect &&
test_cmp expect file &&
test_must_fail git pull 2>err &&
- test_i18ngrep "not currently on a branch" err &&
+ test_grep "not currently on a branch" err &&
test_cmp expect file
'
@@ -189,7 +189,7 @@ test_expect_success 'fail if no configuration for current branch' '
echo file >expect &&
test_cmp expect file &&
test_must_fail git pull 2>err &&
- test_i18ngrep "no tracking information" err &&
+ test_grep "no tracking information" err &&
test_cmp expect file
'
@@ -202,7 +202,7 @@ test_expect_success 'pull --all: fail if no configuration for current branch' '
echo file >expect &&
test_cmp expect file &&
test_must_fail git pull --all 2>err &&
- test_i18ngrep "There is no tracking information" err &&
+ test_grep "There is no tracking information" err &&
test_cmp expect file
'
@@ -214,7 +214,7 @@ test_expect_success 'fail if upstream branch does not exist' '
echo file >expect &&
test_cmp expect file &&
test_must_fail git pull 2>err &&
- test_i18ngrep "no such ref was fetched" err &&
+ test_grep "no such ref was fetched" err &&
test_cmp expect file
'
@@ -248,13 +248,13 @@ test_expect_success 'fail if the index has unresolved entries' '
test_file_not_empty unmerged &&
cp file expected &&
test_must_fail git pull . second 2>err &&
- test_i18ngrep "Pulling is not possible because you have unmerged files." err &&
+ test_grep "Pulling is not possible because you have unmerged files." err &&
test_cmp expected file &&
git add file &&
git ls-files -u >unmerged &&
test_must_be_empty unmerged &&
test_must_fail git pull . second 2>err &&
- test_i18ngrep "You have not concluded your merge" err &&
+ test_grep "You have not concluded your merge" err &&
test_cmp expected file
'
@@ -264,7 +264,7 @@ test_expect_success 'fast-forwards working tree if branch head is updated' '
echo file >expect &&
test_cmp expect file &&
git pull . second:third 2>err &&
- test_i18ngrep "fetch updated the current branch head" err &&
+ test_grep "fetch updated the current branch head" err &&
echo modified >expect &&
test_cmp expect file &&
test_cmp_rev third second
@@ -277,7 +277,7 @@ test_expect_success 'fast-forward fails with conflicting work tree' '
test_cmp expect file &&
echo conflict >file &&
test_must_fail git pull . second:third 2>err &&
- test_i18ngrep "Cannot fast-forward your working tree" err &&
+ test_grep "Cannot fast-forward your working tree" err &&
echo conflict >expect &&
test_cmp expect file &&
test_cmp_rev third second
@@ -375,7 +375,7 @@ test_expect_success '--rebase with conflicts shows advice' '
test_tick &&
git commit -m "Create conflict" seq.txt &&
test_must_fail git pull --rebase . seq 2>err >out &&
- test_i18ngrep "Resolve all conflicts manually" err
+ test_grep "Resolve all conflicts manually" err
'
test_expect_success 'failed --rebase shows advice' '
@@ -389,14 +389,14 @@ test_expect_success 'failed --rebase shows advice' '
git checkout -f -b fails-to-rebase HEAD^ &&
test_commit v2-without-cr file "2" file2-lf &&
test_must_fail git pull --rebase . diverging 2>err >out &&
- test_i18ngrep "Resolve all conflicts manually" err
+ test_grep "Resolve all conflicts manually" err
'
test_expect_success '--rebase fails with multiple branches' '
git reset --hard before-rebase &&
test_must_fail git pull --rebase . copy main 2>err &&
test_cmp_rev HEAD before-rebase &&
- test_i18ngrep "Cannot rebase onto multiple branches" err &&
+ test_grep "Cannot rebase onto multiple branches" err &&
echo modified >expect &&
git show HEAD:file >actual &&
test_cmp expect actual
@@ -520,7 +520,7 @@ test_expect_success 'pull --rebase warns on --verify-signatures' '
echo new >expect &&
git show HEAD:file2 >actual &&
test_cmp expect actual &&
- test_i18ngrep "ignoring --verify-signatures for rebase" err
+ test_grep "ignoring --verify-signatures for rebase" err
'
test_expect_success 'pull --rebase does not warn on --no-verify-signatures' '
@@ -530,7 +530,7 @@ test_expect_success 'pull --rebase does not warn on --no-verify-signatures' '
echo new >expect &&
git show HEAD:file2 >actual &&
test_cmp expect actual &&
- test_i18ngrep ! "verify-signatures" err
+ test_grep ! "verify-signatures" err
'
# add a feature branch, keep-merge, that is merged into main, so the
@@ -740,7 +740,7 @@ test_expect_success 'pull --rebase fails on unborn branch with staged changes' '
test_cmp expect actual &&
git show :staged-file >actual &&
test_cmp expect actual &&
- test_i18ngrep "unborn branch with changes added to the index" err
+ test_grep "unborn branch with changes added to the index" err
)
'
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index 264de29c35..5e420c208c 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -93,7 +93,7 @@ test_expect_success 'git pull --no-write-fetch-head fails' '
(cd clonedwfh && git init &&
test_expect_code 129 git pull --no-write-fetch-head "../parent" >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "no-write-fetch-head" err)
+ test_grep "no-write-fetch-head" err)
'
test_expect_success 'git pull --force' '
@@ -142,7 +142,7 @@ test_expect_success 'git pull --dry-run' '
cd clonedry &&
git pull --dry-run ../parent &&
test_path_is_missing .git/FETCH_HEAD &&
- test_path_is_missing .git/refs/heads/main &&
+ test_ref_missing refs/heads/main &&
test_path_is_missing .git/index &&
test_path_is_missing file
)
@@ -156,7 +156,7 @@ test_expect_success 'git pull --all --dry-run' '
git remote add origin ../parent &&
git pull --all --dry-run &&
test_path_is_missing .git/FETCH_HEAD &&
- test_path_is_missing .git/refs/remotes/origin/main &&
+ test_ref_missing refs/remotes/origin/main &&
test_path_is_missing .git/index &&
test_path_is_missing file
)
diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh
index cc5496e28f..9fb73a8c3e 100755
--- a/t/t5522-pull-symlink.sh
+++ b/t/t5522-pull-symlink.sh
@@ -2,7 +2,6 @@
test_description='pulling from symlinked subdir'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# The scenario we are building:
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index 1b8d609879..22d3e1162c 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -4,7 +4,6 @@ test_description='push with --set-upstream'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
@@ -87,7 +86,7 @@ test_expect_success TTY 'progress messages go to tty' '
ensure_fresh_upstream &&
test_terminal git push -u upstream main >out 2>err &&
- test_i18ngrep "Writing objects" err
+ test_grep "Writing objects" err
'
test_expect_success 'progress messages do not go to non-tty' '
@@ -95,7 +94,7 @@ test_expect_success 'progress messages do not go to non-tty' '
# skip progress messages, since stderr is non-tty
git push -u upstream main >out 2>err &&
- test_i18ngrep ! "Writing objects" err
+ test_grep ! "Writing objects" err
'
test_expect_success 'progress messages go to non-tty (forced)' '
@@ -103,35 +102,35 @@ test_expect_success 'progress messages go to non-tty (forced)' '
# force progress messages to stderr, even though it is non-tty
git push -u --progress upstream main >out 2>err &&
- test_i18ngrep "Writing objects" err
+ test_grep "Writing objects" err
'
test_expect_success TTY 'push -q suppresses progress' '
ensure_fresh_upstream &&
test_terminal git push -u -q upstream main >out 2>err &&
- test_i18ngrep ! "Writing objects" err
+ test_grep ! "Writing objects" err
'
test_expect_success TTY 'push --no-progress suppresses progress' '
ensure_fresh_upstream &&
test_terminal git push -u --no-progress upstream main >out 2>err &&
- test_i18ngrep ! "Unpacking objects" err &&
- test_i18ngrep ! "Writing objects" err
+ test_grep ! "Unpacking objects" err &&
+ test_grep ! "Writing objects" err
'
test_expect_success TTY 'quiet push' '
ensure_fresh_upstream &&
- test_terminal git push --quiet --no-progress upstream main 2>&1 | tee output &&
+ test_terminal git push --quiet --no-progress upstream main >output 2>&1 &&
test_must_be_empty output
'
test_expect_success TTY 'quiet push -u' '
ensure_fresh_upstream &&
- test_terminal git push --quiet -u --no-progress upstream main 2>&1 | tee output &&
+ test_terminal git push --quiet -u --no-progress upstream main >output 2>&1 &&
test_must_be_empty output
'
diff --git a/t/t5524-pull-msg.sh b/t/t5524-pull-msg.sh
index 56716e29dd..b2be3605f5 100755
--- a/t/t5524-pull-msg.sh
+++ b/t/t5524-pull-msg.sh
@@ -2,7 +2,6 @@
test_description='git pull message generation'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
dollar='$Dollar'
diff --git a/t/t5525-fetch-tagopt.sh b/t/t5525-fetch-tagopt.sh
index 3a28f1ded5..45815f7378 100755
--- a/t/t5525-fetch-tagopt.sh
+++ b/t/t5525-fetch-tagopt.sh
@@ -2,7 +2,6 @@
test_description='tagopt variable affects "git fetch" and is overridden by commandline.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
setup_clone () {
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 26e933f93a..5e566205ba 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -771,7 +771,7 @@ test_expect_success 'fetching submodule into a broken repository' '
git -C dst fetch --recurse-submodules &&
# Break the receiving submodule
- rm -f dst/sub/.git/HEAD &&
+ rm -r dst/sub/.git/objects &&
# NOTE: without the fix the following tests will recurse forever!
# They should terminate with an error.
diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh
index 98ece27c6a..e2770e4541 100755
--- a/t/t5527-fetch-odd-refs.sh
+++ b/t/t5527-fetch-odd-refs.sh
@@ -4,7 +4,6 @@ test_description='test fetching of oddly-named refs'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# afterwards we will have:
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
index 284e20fefd..2bd8759a68 100755
--- a/t/t5528-push-default.sh
+++ b/t/t5528-push-default.sh
@@ -146,7 +146,7 @@ test_expect_success 'push from/to new branch fails with upstream and simple ' '
# - the default push succeeds
#
# A previous test expected this to fail, but for the wrong reasons:
-# it expected a fail becaause the branch is new and cannot be pushed, but
+# it expected to fail because the branch is new and cannot be pushed, but
# in fact it was failing because of an ambiguous remote
#
test_expect_failure 'push from/to new branch fails with matching ' '
@@ -179,7 +179,7 @@ test_expect_success 'push from/to new branch succeeds with simple if push.autoSe
test_expect_success '"matching" fails if none match' '
git init --bare empty &&
test_must_fail git push empty : 2>actual &&
- test_i18ngrep "Perhaps you should specify a branch" actual
+ test_grep "Perhaps you should specify a branch" actual
'
test_expect_success 'push ambiguously named branch with upstream, matching and simple' '
diff --git a/t/t5529-push-errors.sh b/t/t5529-push-errors.sh
index 0247137cb3..80b06a0cd2 100755
--- a/t/t5529-push-errors.sh
+++ b/t/t5529-push-errors.sh
@@ -2,7 +2,9 @@
test_description='detect some push errors early (before contacting remote)'
-TEST_PASSES_SANITIZE_LEAK=true
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
. ./test-lib.sh
test_expect_success 'setup commits' '
@@ -38,6 +40,20 @@ test_expect_success 'detect missing sha1 expressions early' '
test_cmp expect rp-ran
'
+# We use an existing local_ref, since it follows a different flow in
+# 'builtin/push.c:set_refspecs()' and we want to test that regression.
+test_expect_success 'detect empty remote with existing local ref' '
+ test_must_fail git push "" main 2> stderr &&
+ grep "fatal: bad repository ${SQ}${SQ}" stderr
+'
+
+# While similar to the previous test, here we want to ensure that
+# even targeted refspecs are handled.
+test_expect_success 'detect empty remote with targeted refspec' '
+ test_must_fail git push "" HEAD:refs/heads/main 2> stderr &&
+ grep "fatal: bad repository ${SQ}${SQ}" stderr
+'
+
test_expect_success 'detect ambiguous refs early' '
git branch foo &&
git tag foo &&
diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh
index 7c1460eaa9..558eedf25a 100755
--- a/t/t5530-upload-pack-error.sh
+++ b/t/t5530-upload-pack-error.sh
@@ -35,8 +35,8 @@ test_expect_success 'upload-pack fails due to error in pack-objects packing' '
printf "%04xwant %s\n00000009done\n0000" \
$(($hexsz + 10)) $head >input &&
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
- test_i18ngrep "unable to read" output.err &&
- test_i18ngrep "pack-objects died" output.err
+ test_grep "unable to read" output.err &&
+ test_grep "pack-objects died" output.err
'
test_expect_success 'corrupt repo differently' '
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index 302e4cbdba..05debd1134 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -203,7 +203,7 @@ test_expect_success 'push recurse-submodules last one wins on command line' '
cd work/gar/bage &&
>recurse-check-on-command-line-overriding-earlier-command-line &&
git add recurse-check-on-command-line-overriding-earlier-command-line &&
- git commit -m "Recurse on command-line overridiing earlier command-line junk"
+ git commit -m "Recurse on command-line overriding earlier command-line junk"
) &&
(
cd work &&
@@ -311,7 +311,7 @@ test_expect_success 'submodule entry pointing at a tag is error' '
git -C work commit -m "bad commit" &&
test_when_finished "git -C work reset --hard HEAD^" &&
test_must_fail git -C work push --recurse-submodules=on-demand ../pub.git main 2>err &&
- test_i18ngrep "is a tag, not a commit" err
+ test_grep "is a tag, not a commit" err
'
test_expect_success 'push fails if recurse submodules option passed as yes' '
diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh
index d664912799..3755822629 100755
--- a/t/t5532-fetch-proxy.sh
+++ b/t/t5532-fetch-proxy.sh
@@ -2,7 +2,6 @@
test_description='fetching via git:// using core.gitproxy'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup remote repo' '
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 7c0a148e73..c91a62b77a 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -68,13 +68,13 @@ test_expect_success 'talking with a receiver without push certificate support' '
test_expect_success 'push --signed fails with a receiver without push certificate support' '
prepare_dst &&
test_must_fail git push --signed dst noop ff +noff 2>err &&
- test_i18ngrep "the receiving end does not support" err
+ test_grep "the receiving end does not support" err
'
test_expect_success 'push --signed=1 is accepted' '
prepare_dst &&
test_must_fail git push --signed=1 dst noop ff +noff 2>err &&
- test_i18ngrep "the receiving end does not support" err
+ test_grep "the receiving end does not support" err
'
test_expect_success GPG 'no certificate for a signed push with no update' '
@@ -303,7 +303,7 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
EOF
sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
) >expect.in &&
- key=$(cat "${GNUPGHOME}/trustlist.txt" | cut -d" " -f1 | tr -d ":") &&
+ key=$(cut -d" " -f1 <"${GNUPGHOME}/trustlist.txt" | tr -d ":") &&
sed -e "s/^KEY=/KEY=${key}/" expect.in >expect &&
noop=$(git rev-parse noop) &&
@@ -378,7 +378,7 @@ test_expect_success GPG 'failed atomic push does not execute GPG' '
--signed --atomic --porcelain \
dst noop ff noff >out 2>err &&
- test_i18ngrep ! "gpg failed to sign" err &&
+ test_grep ! "gpg failed to sign" err &&
cat >expect <<-EOF &&
To dst
= refs/heads/noop:refs/heads/noop [up to date]
diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh
index 91f28c2f78..23bf696170 100755
--- a/t/t5536-fetch-conflicts.sh
+++ b/t/t5536-fetch-conflicts.sh
@@ -40,7 +40,7 @@ test_expect_success 'fetch conflict: config vs. config' '
"+refs/heads/branch2:refs/remotes/origin/branch1" && (
cd ccc &&
test_must_fail git fetch origin 2>error &&
- test_i18ngrep "fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1" error
+ test_grep "fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1" error
)
'
@@ -67,7 +67,7 @@ test_expect_success 'fetch conflict: arg vs. arg' '
test_must_fail git fetch origin \
refs/heads/*:refs/remotes/origin/* \
refs/heads/branch2:refs/remotes/origin/branch1 2>error &&
- test_i18ngrep "fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1" error
+ test_grep "fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1" error
)
'
@@ -78,8 +78,8 @@ test_expect_success 'fetch conflict: criss-cross args' '
git fetch origin \
refs/heads/branch1:refs/remotes/origin/branch2 \
refs/heads/branch2:refs/remotes/origin/branch1 2>error &&
- test_i18ngrep "warning: refs/remotes/origin/branch1 usually tracks refs/heads/branch1, not refs/heads/branch2" error &&
- test_i18ngrep "warning: refs/remotes/origin/branch2 usually tracks refs/heads/branch2, not refs/heads/branch1" error
+ test_grep "warning: refs/remotes/origin/branch1 usually tracks refs/heads/branch1, not refs/heads/branch2" error &&
+ test_grep "warning: refs/remotes/origin/branch2 usually tracks refs/heads/branch2, not refs/heads/branch1" error
)
'
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index d0211cd8be..71428f3d5c 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -153,7 +153,7 @@ test_expect_success 'push fails for non-fast-forward refs unmatched by remote he
'
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: our output' '
- test_i18ngrep "Updates were rejected because" \
+ test_grep "Updates were rejected because" \
output
'
@@ -232,8 +232,9 @@ test_expect_success 'push --atomic fails on server-side errors' '
test_config -C "$d" http.receivepack true &&
up="$HTTPD_URL"/smart/atomic-branches.git &&
- # break ref updates for other on the remote site
- mkdir "$d/refs/heads/other.lock" &&
+ # Create d/f conflict to break ref updates for other on the remote site.
+ git -C "$d" update-ref -d refs/heads/other &&
+ git -C "$d" update-ref refs/heads/other/conflict HEAD &&
# add the new commit to other
git branch -f other collateral &&
@@ -241,18 +242,9 @@ test_expect_success 'push --atomic fails on server-side errors' '
# --atomic should cause entire push to be rejected
test_must_fail git push --atomic "$up" atomic other 2>output &&
- # the new branch should not have been created upstream
- test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
-
- # upstream should still reflect atomic2, the last thing we pushed
- # successfully
- git rev-parse atomic2 >expected &&
- # ...to other.
- git -C "$d" rev-parse refs/heads/other >actual &&
- test_cmp expected actual &&
-
- # the new branch should not have been created upstream
+ # The atomic and other branches should not be created upstream.
test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
+ test_must_fail git -C "$d" show-ref --verify refs/heads/other &&
# the failed refs should be indicated to the user
grep "^ ! .*rejected.* other -> other .*atomic transaction failed" output &&
@@ -297,7 +289,7 @@ test_expect_success TTY 'push shows progress when stderr is a tty' '
cd "$ROOT_PATH"/test_repo_clone &&
test_commit noisy &&
test_terminal git push >output 2>&1 &&
- test_i18ngrep "^Writing objects" output
+ test_grep "^Writing objects" output
'
test_expect_success TTY 'push --quiet silences status and progress' '
@@ -311,16 +303,16 @@ test_expect_success TTY 'push --no-progress silences progress but not status' '
cd "$ROOT_PATH"/test_repo_clone &&
test_commit no-progress &&
test_terminal git push --no-progress >output 2>&1 &&
- test_i18ngrep "^To http" output &&
- test_i18ngrep ! "^Writing objects" output
+ test_grep "^To http" output &&
+ test_grep ! "^Writing objects" output
'
test_expect_success 'push --progress shows progress to non-tty' '
cd "$ROOT_PATH"/test_repo_clone &&
test_commit progress &&
git push --progress >output 2>&1 &&
- test_i18ngrep "^To http" output &&
- test_i18ngrep "^Writing objects" output
+ test_grep "^To http" output &&
+ test_grep "^Writing objects" output
'
test_expect_success 'http push gives sane defaults to reflog' '
@@ -489,10 +481,10 @@ test_expect_success 'colorize errors/hints' '
-c color.push=always \
push origin origin/main^:main 2>act &&
test_decode_color <act >decoded &&
- test_i18ngrep "<RED>.*rejected.*<RESET>" decoded &&
- test_i18ngrep "<RED>error: failed to push some refs" decoded &&
- test_i18ngrep "<YELLOW>hint: " decoded &&
- test_i18ngrep ! "^hint: " decoded
+ test_grep "<RED>.*rejected.*<RESET>" decoded &&
+ test_grep "<RED>error: failed to push some refs" decoded &&
+ test_grep "<YELLOW>hint: " decoded &&
+ test_grep ! "^hint: " decoded
'
test_expect_success 'report error server does not provide ref status' '
diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh
index 1a9e14bbcc..89147a052e 100755
--- a/t/t5544-pack-objects-hook.sh
+++ b/t/t5544-pack-objects-hook.sh
@@ -2,7 +2,6 @@
test_description='test custom script in place of pack-objects'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create some history to fetch' '
diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh
index a158e7d2c0..fb13549da7 100755
--- a/t/t5545-push-options.sh
+++ b/t/t5545-push-options.sh
@@ -252,7 +252,7 @@ test_expect_success 'push option denied properly by http server' '
mk_http_pair false &&
test_commit -C test_http_clone one &&
test_must_fail git -C test_http_clone push --push-option=asdf origin main 2>actual &&
- test_i18ngrep "the receiving end does not support push options" actual &&
+ test_grep "the receiving end does not support push options" actual &&
git -C test_http_clone push origin main
'
diff --git a/t/t5546-receive-limits.sh b/t/t5546-receive-limits.sh
index 9fc9ba552f..f1e61c9f09 100755
--- a/t/t5546-receive-limits.sh
+++ b/t/t5546-receive-limits.sh
@@ -2,7 +2,6 @@
test_description='check receive input limits'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Let's run tests with different unpack limits: 1 and 10000
diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
index 9f899b8c7d..0798ddab02 100755
--- a/t/t5547-push-quarantine.sh
+++ b/t/t5547-push-quarantine.sh
@@ -2,7 +2,6 @@
test_description='check quarantine of objects during push'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create picky dest repo' '
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index 8f182a3cbf..21795a19bf 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -25,6 +25,12 @@ test_expect_success 'setup repository' '
git commit -m two
'
+test_expect_success 'packfile without repository does not crash' '
+ echo "fatal: not a git repository" >expect &&
+ test_must_fail nongit git http-fetch --packfile=abc 2>err &&
+ test_cmp expect err
+'
+
setup_post_update_server_info_hook () {
test_hook --setup -C "$1" post-update <<-\EOF &&
exec git update-server-info
@@ -55,6 +61,21 @@ test_expect_success 'list refs from outside any repository' '
test_cmp expect actual
'
+
+test_expect_success 'list detached HEAD from outside any repository' '
+ git clone --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" \
+ update-ref --no-deref HEAD refs/heads/main &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" update-server-info &&
+ cat >expect <<-EOF &&
+ $(git rev-parse main) HEAD
+ $(git rev-parse main) refs/heads/main
+ EOF
+ nongit git ls-remote "$HTTPD_URL/dumb/repo-detached.git" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'create password-protected repository' '
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
@@ -66,11 +87,11 @@ test_expect_success 'create empty remote repository' '
setup_post_update_server_info_hook "$HTTPD_DOCUMENT_ROOT_PATH/empty.git"
'
-test_expect_success 'empty dumb HTTP repository has default hash algorithm' '
+test_expect_success 'empty dumb HTTP repository falls back to SHA1' '
test_when_finished "rm -fr clone-empty" &&
git clone $HTTPD_URL/dumb/empty.git clone-empty &&
git -C clone-empty rev-parse --show-object-format >empty-format &&
- test "$(cat empty-format)" = "$(test_oid algo)"
+ test "$(cat empty-format)" = sha1
'
setup_askpass_helper
@@ -285,6 +306,14 @@ test_expect_success 'fetch notices corrupt idx' '
)
'
+# usage: count_fetches <nr> <extension> <trace_file>
+count_fetches () {
+ # ignore grep exit code; it may return non-zero if we are expecting no
+ # matches
+ grep "GET .*objects/pack/pack-[a-z0-9]*.$2" "$3" >trace.count
+ test_line_count = "$1" trace.count
+}
+
test_expect_success 'fetch can handle previously-fetched .idx files' '
git checkout --orphan branch1 &&
echo base >file &&
@@ -299,8 +328,14 @@ test_expect_success 'fetch can handle previously-fetched .idx files' '
git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch2 &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
git --bare init clone_packed_branches.git &&
- git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch1:branch1 &&
- git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch2:branch2
+ GIT_TRACE_CURL=$PWD/one.trace git --git-dir=clone_packed_branches.git \
+ fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch1:branch1 &&
+ count_fetches 2 idx one.trace &&
+ count_fetches 1 pack one.trace &&
+ GIT_TRACE_CURL=$PWD/two.trace git --git-dir=clone_packed_branches.git \
+ fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch2:branch2 &&
+ count_fetches 1 idx two.trace &&
+ count_fetches 1 pack two.trace
'
test_expect_success 'did not use upload-pack service' '
@@ -322,12 +357,12 @@ test_expect_success 'git client shows text/plain with a charset' '
grep "this is the error message" stderr
'
-test_expect_success 'http error messages are reencoded' '
+test_expect_success ICONV 'http error messages are reencoded' '
test_must_fail git clone "$HTTPD_URL/error/utf16" 2>stderr &&
grep "this is the error message" stderr
'
-test_expect_success 'reencoding is robust to whitespace oddities' '
+test_expect_success ICONV 'reencoding is robust to whitespace oddities' '
test_must_fail git clone "$HTTPD_URL/error/odd-spacing" 2>stderr &&
grep "this is the error message" stderr
'
@@ -376,7 +411,7 @@ test_expect_success 'git client send an empty Accept-Language' '
test_expect_success 'remote-http complains cleanly about malformed urls' '
test_must_fail git remote-http http::/example.com/repo.git 2>stderr &&
- test_i18ngrep "url has no scheme" stderr
+ test_grep "url has no scheme" stderr
'
# NEEDSWORK: Writing commands to git-remote-curl can race against the latter
@@ -385,7 +420,7 @@ test_expect_success 'remote-http complains cleanly about malformed urls' '
test_expect_success 'remote-http complains cleanly about empty scheme' '
test_must_fail ok=sigpipe git ls-remote \
http::${HTTPD_URL#http}/dumb/repo.git 2>stderr &&
- test_i18ngrep "url has no scheme" stderr
+ test_grep "url has no scheme" stderr
'
test_expect_success 'redirects can be forbidden/allowed' '
@@ -397,7 +432,7 @@ test_expect_success 'redirects can be forbidden/allowed' '
test_expect_success 'redirects are reported to stderr' '
# just look for a snippet of the redirected-to URL
- test_i18ngrep /dumb/ stderr
+ test_grep /dumb/ stderr
'
test_expect_success 'non-initial redirects can be forbidden' '
@@ -466,7 +501,7 @@ test_expect_success 'can redirect through non-"info/refs?service=git-upload-pack
test_expect_success 'print HTTP error when any intermediate redirect throws error' '
test_must_fail git clone "$HTTPD_URL/redir-to/502" 2> stderr &&
- test_i18ngrep "unable to access.*/redir-to/502" stderr
+ test_grep "unable to access.*/redir-to/502" stderr
'
test_expect_success 'fetching via http alternates works' '
@@ -485,4 +520,14 @@ test_expect_success 'fetching via http alternates works' '
git -c http.followredirects=true clone "$HTTPD_URL/dumb/alt-child.git"
'
+test_expect_success 'dumb http can fetch index v1' '
+ server=$HTTPD_DOCUMENT_ROOT_PATH/idx-v1.git &&
+ git init --bare "$server" &&
+ git -C "$server" --work-tree=. commit --allow-empty -m foo &&
+ git -C "$server" -c pack.indexVersion=1 gc &&
+
+ git clone "$HTTPD_URL/dumb/idx-v1.git" &&
+ git -C idx-v1 fsck
+'
+
test_done
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 21b7767cbd..ceb3336a5c 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -186,6 +186,28 @@ test_expect_success 'clone from password-protected repository' '
test_cmp expect actual
'
+test_expect_success 'credential.interactive=false skips askpass' '
+ set_askpass bogus nonsense &&
+ (
+ GIT_TRACE2_EVENT="$(pwd)/interactive-true" &&
+ export GIT_TRACE2_EVENT &&
+ test_must_fail git clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-true-dir &&
+ test_region credential interactive interactive-true &&
+
+ GIT_TRACE2_EVENT="$(pwd)/interactive-false" &&
+ export GIT_TRACE2_EVENT &&
+ test_must_fail git -c credential.interactive=false \
+ clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-false-dir &&
+ test_region ! credential interactive interactive-false &&
+
+ GIT_TRACE2_EVENT="$(pwd)/interactive-never" &&
+ export GIT_TRACE2_EVENT &&
+ test_must_fail git -c credential.interactive=never \
+ clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-never-dir &&
+ test_region ! credential interactive interactive-never
+ )
+'
+
test_expect_success 'clone from auth-only-for-push repository' '
echo two >expect &&
set_askpass wrong &&
@@ -275,7 +297,7 @@ test_expect_success 'GIT_SMART_HTTP can disable smart http' '
test_expect_success 'invalid Content-Type rejected' '
test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual &&
- test_i18ngrep "not valid:" actual
+ test_grep "not valid:" actual
'
test_expect_success 'create namespaced refs' '
@@ -359,7 +381,9 @@ create_tags () {
# now assign tags to all the dangling commits we created above
tag=$(perl -e "print \"bla\" x 30") &&
- sed -e "s|^:\([^ ]*\) \(.*\)$|\2 refs/tags/$tag-\1|" <marks >>packed-refs
+ sed -e "s|^:\([^ ]*\) \(.*\)$|create refs/tags/$tag-\1 \2|" <marks >input &&
+ git update-ref --stdin <input &&
+ rm input
}
test_expect_success 'create 2,000 tags in the repo' '
@@ -558,7 +582,7 @@ test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '
test_expect_success 'server-side error detected' '
test_must_fail git clone $HTTPD_URL/error_smart/repo.git 2>actual &&
- test_i18ngrep "server-side error" actual
+ test_grep "server-side error" actual
'
test_expect_success 'http auth remembers successful credentials' '
@@ -641,7 +665,6 @@ test_expect_success 'clone empty SHA-256 repository with protocol v0' '
test_expect_success 'passing hostname resolution information works' '
BOGUS_HOST=gitbogusexamplehost.invalid &&
BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT &&
- test_must_fail git ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null &&
git -c "http.curloptResolve=$BOGUS_HOST:$LIB_HTTPD_PORT:127.0.0.1" ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null
'
@@ -731,4 +754,22 @@ test_expect_success 'no empty path components' '
! grep "//" log
'
+test_expect_success 'tag following always works over v0 http' '
+ upstream=$HTTPD_DOCUMENT_ROOT_PATH/tags &&
+ git init "$upstream" &&
+ (
+ cd "$upstream" &&
+ git commit --allow-empty -m base &&
+ git tag not-annotated &&
+ git tag -m foo annotated
+ ) &&
+ git init tags &&
+ git -C tags -c protocol.version=0 \
+ fetch --depth 1 $HTTPD_URL/smart/tags \
+ refs/tags/annotated:refs/tags/annotated &&
+ git -C "$upstream" for-each-ref refs/tags >expect &&
+ git -C tags for-each-ref >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh
index b55a9f65e6..eeddb85b1d 100755
--- a/t/t5552-skipping-fetch-negotiator.sh
+++ b/t/t5552-skipping-fetch-negotiator.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test skipping fetch negotiator'
+
. ./test-lib.sh
test_expect_success 'fetch.negotiationalgorithm config' '
diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh
index 48050162c2..70e3376d31 100755
--- a/t/t5553-set-upstream.sh
+++ b/t/t5553-set-upstream.sh
@@ -73,10 +73,10 @@ test_expect_success 'fetch --set-upstream main:other does not set the branch oth
check_config_missing other2
'
-test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails with invalid url' '
+test_expect_success 'fetch --set-upstream ./does-not-exist fails with invalid url' '
# main explicitly not cleared, we check that it is not touched from previous value
clear_config other other2 &&
- test_must_fail git fetch --set-upstream http://nosuchdomain.example.com &&
+ test_must_fail git fetch --set-upstream ./does-not-exist &&
check_config main upstream refs/heads/other &&
check_config_missing other &&
check_config_missing other2
@@ -143,10 +143,10 @@ test_expect_success 'pull --set-upstream upstream tag does not set the tag' '
check_config_missing three
'
-test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails with invalid url' '
+test_expect_success 'pull --set-upstream ./does-not-exist fails with invalid url' '
# main explicitly not cleared, we check that it is not touched from previous value
clear_config other other2 three &&
- test_must_fail git pull --set-upstream http://nosuchdomain.example.com &&
+ test_must_fail git pull --set-upstream ./does-not-exist &&
check_config main upstream refs/heads/other &&
check_config_missing other &&
check_config_missing other2 &&
diff --git a/t/t5554-noop-fetch-negotiator.sh b/t/t5554-noop-fetch-negotiator.sh
index 06991e8e8a..17e73b606d 100755
--- a/t/t5554-noop-fetch-negotiator.sh
+++ b/t/t5554-noop-fetch-negotiator.sh
@@ -2,7 +2,6 @@
test_description='test noop fetch negotiator'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'noop negotiator does not emit any "have"' '
diff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh
index b1cfe8b7db..e47ea1ad10 100755
--- a/t/t5555-http-smart-common.sh
+++ b/t/t5555-http-smart-common.sh
@@ -2,7 +2,6 @@
test_description='test functionality common to smart fetch & push'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -131,7 +130,6 @@ test_expect_success 'git upload-pack --advertise-refs: v2' '
fetch=shallow wait-for-done
server-option
object-format=$(test_oid algo)
- object-info
0000
EOF
diff --git a/t/t5557-http-get.sh b/t/t5557-http-get.sh
index 76a4bbd16a..67fcc23f11 100755
--- a/t/t5557-http-get.sh
+++ b/t/t5557-http-get.sh
@@ -2,7 +2,6 @@
test_description='test downloading a file by URL'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh
index 996a08e90c..3816ed5058 100755
--- a/t/t5558-clone-bundle-uri.sh
+++ b/t/t5558-clone-bundle-uri.sh
@@ -3,6 +3,7 @@
test_description='test fetching bundles with --bundle-uri'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-bundle.sh
test_expect_success 'fail to clone from non-existent file' '
test_when_finished rm -rf test &&
@@ -19,10 +20,39 @@ test_expect_success 'fail to clone from non-bundle file' '
test_expect_success 'create bundle' '
git init clone-from &&
- git -C clone-from checkout -b topic &&
- test_commit -C clone-from A &&
- test_commit -C clone-from B &&
- git -C clone-from bundle create B.bundle topic
+ (
+ cd clone-from &&
+ git checkout -b topic &&
+
+ test_commit A &&
+ git bundle create A.bundle topic &&
+
+ test_commit B &&
+ git bundle create B.bundle topic &&
+
+ # Create a bundle with reference pointing to non-existent object.
+ commit_a=$(git rev-parse A) &&
+ commit_b=$(git rev-parse B) &&
+ sed -e "/^$/q" -e "s/$commit_a /$commit_b /" \
+ <A.bundle >bad-header.bundle &&
+ convert_bundle_to_pack \
+ <A.bundle >>bad-header.bundle &&
+
+ tree_b=$(git rev-parse B^{tree}) &&
+ cat >data <<-EOF &&
+ tree $tree_b
+ parent $commit_b
+ author A U Thor
+ committer A U Thor
+
+ commit: this is a commit with bad emails
+
+ EOF
+ bad_commit=$(git hash-object --literally -t commit -w --stdin <data) &&
+ git branch bad $bad_commit &&
+ git bundle create bad-object.bundle bad &&
+ git update-ref -d refs/heads/bad
+ )
'
test_expect_success 'clone with path bundle' '
@@ -33,6 +63,42 @@ test_expect_success 'clone with path bundle' '
test_cmp expect actual
'
+test_expect_success 'clone with bundle that has bad header' '
+ # Write bundle ref fails, but clone can still proceed.
+ git clone --bundle-uri="clone-from/bad-header.bundle" \
+ clone-from clone-bad-header 2>err &&
+ commit_b=$(git -C clone-from rev-parse B) &&
+ test_grep "trying to write ref '\''refs/bundles/topic'\'' with nonexistent object $commit_b" err &&
+ git -C clone-bad-header for-each-ref --format="%(refname)" >refs &&
+ test_grep ! "refs/bundles/" refs
+'
+
+test_expect_success 'clone with bundle that has bad object' '
+ # Unbundle succeeds if no fsckObjects configured.
+ git clone --bundle-uri="clone-from/bad-object.bundle" \
+ clone-from clone-bad-object-no-fsck &&
+ git -C clone-bad-object-no-fsck for-each-ref --format="%(refname)" >refs &&
+ grep "refs/bundles/" refs >actual &&
+ test_write_lines refs/bundles/bad >expect &&
+ test_cmp expect actual &&
+
+ # Unbundle fails with fsckObjects set true, but clone can still proceed.
+ git -c fetch.fsckObjects=true clone --bundle-uri="clone-from/bad-object.bundle" \
+ clone-from clone-bad-object-fsck 2>err &&
+ test_grep "missingEmail" err &&
+ git -C clone-bad-object-fsck for-each-ref --format="%(refname)" >refs &&
+ test_grep ! "refs/bundles/" refs
+'
+
+test_expect_success 'clone with path bundle and non-default hash' '
+ test_when_finished "rm -rf clone-path-non-default-hash" &&
+ GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="clone-from/B.bundle" \
+ clone-from clone-path-non-default-hash &&
+ git -C clone-path-non-default-hash rev-parse refs/bundles/topic >actual &&
+ git -C clone-from rev-parse topic >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'clone with file:// bundle' '
git clone --bundle-uri="file://$(pwd)/clone-from/B.bundle" \
clone-from clone-file &&
@@ -250,6 +316,128 @@ test_expect_success 'clone bundle list (file, any mode, all failures)' '
! grep "refs/bundles/" refs
'
+test_expect_success 'negotiation: bundle with part of wanted commits' '
+ test_when_finished "rm -f trace*.txt" &&
+ GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \
+ git clone --no-local --bundle-uri="clone-from/A.bundle" \
+ clone-from nego-bundle-part &&
+ git -C nego-bundle-part for-each-ref --format="%(refname)" >refs &&
+ grep "refs/bundles/" refs >actual &&
+ test_write_lines refs/bundles/topic >expect &&
+ test_cmp expect actual &&
+ # Ensure that refs/bundles/topic are sent as "have".
+ tip=$(git -C clone-from rev-parse A) &&
+ test_grep "clone> have $tip" trace-packet.txt
+'
+
+test_expect_success 'negotiation: bundle with all wanted commits' '
+ test_when_finished "rm -f trace*.txt" &&
+ GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \
+ git clone --no-local --single-branch --branch=topic --no-tags \
+ --bundle-uri="clone-from/B.bundle" \
+ clone-from nego-bundle-all &&
+ git -C nego-bundle-all for-each-ref --format="%(refname)" >refs &&
+ grep "refs/bundles/" refs >actual &&
+ test_write_lines refs/bundles/topic >expect &&
+ test_cmp expect actual &&
+ # We already have all needed commits so no "want" needed.
+ test_grep ! "clone> want " trace-packet.txt
+'
+
+test_expect_success 'negotiation: bundle list (no heuristic)' '
+ test_when_finished "rm -f trace*.txt" &&
+ cat >bundle-list <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+
+ [bundle "bundle-1"]
+ uri = file://$(pwd)/clone-from/bundle-1.bundle
+
+ [bundle "bundle-2"]
+ uri = file://$(pwd)/clone-from/bundle-2.bundle
+ EOF
+
+ GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \
+ git clone --no-local --bundle-uri="file://$(pwd)/bundle-list" \
+ clone-from nego-bundle-list-no-heuristic &&
+
+ git -C nego-bundle-list-no-heuristic for-each-ref --format="%(refname)" >refs &&
+ grep "refs/bundles/" refs >actual &&
+ cat >expect <<-\EOF &&
+ refs/bundles/base
+ refs/bundles/left
+ EOF
+ test_cmp expect actual &&
+ tip=$(git -C nego-bundle-list-no-heuristic rev-parse refs/bundles/left) &&
+ test_grep "clone> have $tip" trace-packet.txt
+'
+
+test_expect_success 'negotiation: bundle list (creationToken)' '
+ test_when_finished "rm -f trace*.txt" &&
+ cat >bundle-list <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken
+
+ [bundle "bundle-1"]
+ uri = file://$(pwd)/clone-from/bundle-1.bundle
+ creationToken = 1
+
+ [bundle "bundle-2"]
+ uri = file://$(pwd)/clone-from/bundle-2.bundle
+ creationToken = 2
+ EOF
+
+ GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \
+ git clone --no-local --bundle-uri="file://$(pwd)/bundle-list" \
+ clone-from nego-bundle-list-heuristic &&
+
+ git -C nego-bundle-list-heuristic for-each-ref --format="%(refname)" >refs &&
+ grep "refs/bundles/" refs >actual &&
+ cat >expect <<-\EOF &&
+ refs/bundles/base
+ refs/bundles/left
+ EOF
+ test_cmp expect actual &&
+ tip=$(git -C nego-bundle-list-heuristic rev-parse refs/bundles/left) &&
+ test_grep "clone> have $tip" trace-packet.txt
+'
+
+test_expect_success 'negotiation: bundle list with all wanted commits' '
+ test_when_finished "rm -f trace*.txt" &&
+ cat >bundle-list <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken
+
+ [bundle "bundle-1"]
+ uri = file://$(pwd)/clone-from/bundle-1.bundle
+ creationToken = 1
+
+ [bundle "bundle-2"]
+ uri = file://$(pwd)/clone-from/bundle-2.bundle
+ creationToken = 2
+ EOF
+
+ GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \
+ git clone --no-local --single-branch --branch=left --no-tags \
+ --bundle-uri="file://$(pwd)/bundle-list" \
+ clone-from nego-bundle-list-all &&
+
+ git -C nego-bundle-list-all for-each-ref --format="%(refname)" >refs &&
+ grep "refs/bundles/" refs >actual &&
+ cat >expect <<-\EOF &&
+ refs/bundles/base
+ refs/bundles/left
+ EOF
+ test_cmp expect actual &&
+ # We already have all needed commits so no "want" needed.
+ test_grep ! "clone> want " trace-packet.txt
+'
+
#########################################################################
# HTTP tests begin here
@@ -284,6 +472,15 @@ test_expect_success 'clone HTTP bundle' '
test_config -C clone-http log.excludedecoration refs/bundle/
'
+test_expect_success 'clone HTTP bundle with non-default hash' '
+ test_when_finished "rm -rf clone-http-non-default-hash" &&
+ GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="$HTTPD_URL/B.bundle" \
+ "$HTTPD_URL/smart/fetch.git" clone-http-non-default-hash &&
+ git -C clone-http-non-default-hash rev-parse refs/bundles/topic >actual &&
+ git -C clone-from rev-parse topic >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'clone bundle list (HTTP, no heuristic)' '
test_when_finished rm -f trace*.txt &&
@@ -748,7 +945,7 @@ test_expect_success 'creationToken heuristic with failed downloads (clone)' '
--bundle-uri="$HTTPD_URL/bundle-list" \
"$HTTPD_URL/smart/fetch.git" download-3 &&
- # As long as we have continguous successful downloads,
+ # As long as we have contiguous successful downloads,
# we _do_ set these configs.
test_cmp_config -C download-3 "$HTTPD_URL/bundle-list" fetch.bundleuri &&
test_cmp_config -C download-3 3 fetch.bundlecreationtoken &&
@@ -992,7 +1189,7 @@ test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
GIT_TRACE2_EVENT="$(pwd)/trace-fetch-3.txt" \
git -C fetch-3 fetch origin &&
- # As long as we have continguous successful downloads,
+ # As long as we have contiguous successful downloads,
# we _do_ set the maximum creation token.
test_cmp_config -C fetch-3 6 fetch.bundlecreationtoken &&
diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh
index f75068de64..d30cf4f5b8 100755
--- a/t/t5560-http-backend-noserver.sh
+++ b/t/t5560-http-backend-noserver.sh
@@ -4,7 +4,6 @@ test_description='test git-http-backend-noserver'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY"
diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh
index e1d3b8caed..9c57d84315 100755
--- a/t/t5561-http-backend.sh
+++ b/t/t5561-http-backend.sh
@@ -4,7 +4,6 @@ test_description='test git-http-backend'
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-httpd.sh
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index 7ee9858a78..f3b158274c 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -2,7 +2,6 @@
test_description='test git-http-backend respects CONTENT_LENGTH'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_lazy_prereq GZIP 'gzip --version'
diff --git a/t/t5562/invoke-with-content-length.pl b/t/t5562/invoke-with-content-length.pl
index 718dd9b49d..9babb9a375 100644
--- a/t/t5562/invoke-with-content-length.pl
+++ b/t/t5562/invoke-with-content-length.pl
@@ -1,4 +1,4 @@
-use 5.008;
+use 5.008001;
use strict;
use warnings;
diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh
index ab8a721ccc..317f33af5a 100755
--- a/t/t5563-simple-http-auth.sh
+++ b/t/t5563-simple-http-auth.sh
@@ -21,9 +21,17 @@ test_expect_success 'setup_credential_helper' '
CREDENTIAL_HELPER="$TRASH_DIRECTORY/bin/git-credential-test-helper" &&
write_script "$CREDENTIAL_HELPER" <<-\EOF
cmd=$1
- teefile=$cmd-query.cred
+ teefile=$cmd-query-temp.cred
catfile=$cmd-reply.cred
sed -n -e "/^$/q" -e "p" >>$teefile
+ state=$(sed -ne "s/^state\[\]=helper://p" "$teefile")
+ if test -z "$state"
+ then
+ mv "$teefile" "$cmd-query.cred"
+ else
+ mv "$teefile" "$cmd-query-$state.cred"
+ catfile="$cmd-reply-$state.cred"
+ fi
if test "$cmd" = "get"
then
cat $catfile
@@ -32,13 +40,15 @@ test_expect_success 'setup_credential_helper' '
'
set_credential_reply () {
- cat >"$TRASH_DIRECTORY/$1-reply.cred"
+ local suffix="$(test -n "$2" && echo "-$2")"
+ cat >"$TRASH_DIRECTORY/$1-reply$suffix.cred"
}
expect_credential_query () {
- cat >"$TRASH_DIRECTORY/$1-expect.cred" &&
- test_cmp "$TRASH_DIRECTORY/$1-expect.cred" \
- "$TRASH_DIRECTORY/$1-query.cred"
+ local suffix="$(test -n "$2" && echo "-$2")"
+ cat >"$TRASH_DIRECTORY/$1-expect$suffix.cred" &&
+ test_cmp "$TRASH_DIRECTORY/$1-expect$suffix.cred" \
+ "$TRASH_DIRECTORY/$1-query$suffix.cred"
}
per_test_cleanup () {
@@ -63,17 +73,20 @@ test_expect_success 'access using basic auth' '
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
EOF
cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
- WWW-Authenticate: Basic realm="example.com"
+ id=1 status=200
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=Basic realm="example.com"
@@ -87,6 +100,45 @@ test_expect_success 'access using basic auth' '
EOF
'
+test_expect_success 'access using basic auth via authtype' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ capability[]=authtype
+ authtype=Basic
+ credential=YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ # Basic base64(alice:secret-passwd)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default response=WWW-Authenticate: Basic realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ GIT_CURL_VERBOSE=1 git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ capability[]=authtype
+ authtype=Basic
+ credential=YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ protocol=http
+ host=$HTTPD_DEST
+ EOF
+'
+
test_expect_success 'access using basic auth invalid credentials' '
test_when_finished "per_test_cleanup" &&
@@ -97,17 +149,20 @@ test_expect_success 'access using basic auth invalid credentials' '
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
EOF
cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
- WWW-Authenticate: Basic realm="example.com"
+ id=1 status=200
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=Basic realm="example.com"
@@ -122,6 +177,122 @@ test_expect_success 'access using basic auth invalid credentials' '
EOF
'
+test_expect_success 'access using basic proactive 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 &&
+ id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default status=403
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ test_config_global http.proactiveAuth basic &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=Basic
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using auto proactive auth with basic default' '
+ 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 &&
+ id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default status=403
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ test_config_global http.proactiveAuth auto &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=$HTTPD_DEST
+ EOF
+
+ expect_credential_query store <<-EOF
+ protocol=http
+ host=$HTTPD_DEST
+ username=alice
+ password=secret-passwd
+ EOF
+'
+
+test_expect_success 'access using auto proactive auth with authtype from credential helper' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ capability[]=authtype
+ authtype=Bearer
+ credential=YS1naXQtdG9rZW4=
+ EOF
+
+ # Basic base64(a-git-token)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ id=1 creds=Bearer YS1naXQtdG9rZW4=
+ EOF
+
+ CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default status=403
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ test_config_global http.proactiveAuth auto &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=$HTTPD_DEST
+ EOF
+
+ expect_credential_query store <<-EOF
+ capability[]=authtype
+ authtype=Bearer
+ credential=YS1naXQtdG9rZW4=
+ protocol=http
+ host=$HTTPD_DEST
+ EOF
+'
+
test_expect_success 'access using basic auth with extra challenges' '
test_when_finished "per_test_cleanup" &&
@@ -132,19 +303,22 @@ test_expect_success 'access using basic auth with extra challenges' '
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=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"
+ id=1 status=200
+ id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2"
+ id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=FooBar param1="value1" param2="value2"
@@ -170,19 +344,22 @@ test_expect_success 'access using basic auth mixed-case wwwauth header name' '
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=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"
+ id=1 status=200
+ id=default response=www-authenticate: foobar param1="value1" param2="value2"
+ id=default response=WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=foobar param1="value1" param2="value2"
@@ -208,24 +385,27 @@ test_expect_success 'access using basic auth with wwwauth header continuations'
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=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"
+ id=1 status=200
+ id=default response=WWW-Authenticate: FooBar param1="value1"
+ id=default response= param2="value2"
+ id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com"
+ id=default response= p=1
+ id=default response= q=0
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=FooBar param1="value1" param2="value2"
@@ -251,26 +431,29 @@ test_expect_success 'access using basic auth with wwwauth header empty continuat
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=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" &&
+ printf "id=1 status=200\n" >"$CHALLENGE" &&
+ printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" &&
+ printf "id=default response= \r\n" >>"$CHALLENGE" &&
+ printf "id=default response= param2=\"value2\"\r\n" >>"$CHALLENGE" &&
+ printf "id=default response=WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" &&
+ printf "id=default response= p=1\r\n" >>"$CHALLENGE" &&
+ printf "id=default response= \r\n" >>"$CHALLENGE" &&
+ printf "id=default response= q=0\r\n" >>"$CHALLENGE" &&
+ printf "id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=FooBar param1="value1" param2="value2"
@@ -296,22 +479,25 @@ test_expect_success 'access using basic auth with wwwauth header mixed line-endi
# Basic base64(alice:secret-passwd)
cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
- Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA==
+ id=1 creds=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" &&
+ printf "id=1 status=200\n" >"$CHALLENGE" &&
+ printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" &&
+ printf "id=default response= \r\n" >>"$CHALLENGE" &&
+ printf "id=default response=\tparam2=\"value2\"\r\n" >>"$CHALLENGE" &&
+ printf "id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
protocol=http
host=$HTTPD_DEST
wwwauth[]=FooBar param1="value1" param2="value2"
@@ -326,4 +512,166 @@ test_expect_success 'access using basic auth with wwwauth header mixed line-endi
EOF
'
+test_expect_success 'access using bearer auth' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ capability[]=authtype
+ authtype=Bearer
+ credential=YS1naXQtdG9rZW4=
+ EOF
+
+ # Basic base64(a-git-token)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ id=1 creds=Bearer YS1naXQtdG9rZW4=
+ EOF
+
+ CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2"
+ id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
+ 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
+ capability[]=authtype
+ authtype=Bearer
+ credential=YS1naXQtdG9rZW4=
+ protocol=http
+ host=$HTTPD_DEST
+ EOF
+'
+
+test_expect_success 'access using bearer auth with invalid credentials' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ capability[]=authtype
+ authtype=Bearer
+ credential=incorrect-token
+ EOF
+
+ # Basic base64(a-git-token)
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ id=1 creds=Bearer YS1naXQtdG9rZW4=
+ EOF
+
+ CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2"
+ id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ id=default response=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 &&
+ capability[]=authtype
+ capability[]=state
+ 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 erase <<-EOF
+ capability[]=authtype
+ authtype=Bearer
+ credential=incorrect-token
+ 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
+'
+
+test_expect_success 'access using three-legged auth' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ authtype=Multistage
+ credential=YS1naXQtdG9rZW4=
+ state[]=helper:foobar
+ continue=1
+ EOF
+
+ set_credential_reply get foobar <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ authtype=Multistage
+ credential=YW5vdGhlci10b2tlbg==
+ state[]=helper:bazquux
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ id=1 creds=Multistage YS1naXQtdG9rZW4=
+ id=2 creds=Multistage YW5vdGhlci10b2tlbg==
+ EOF
+
+ CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" &&
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=401 response=WWW-Authenticate: Multistage challenge="456"
+ id=1 status=401 response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ id=2 status=200
+ id=default response=WWW-Authenticate: Multistage challenge="123"
+ id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ git ls-remote "$HTTPD_URL/custom_auth/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=Multistage challenge="123"
+ wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+ EOF
+
+ expect_credential_query get foobar <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ authtype=Multistage
+ protocol=http
+ host=$HTTPD_DEST
+ wwwauth[]=Multistage challenge="456"
+ wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+ state[]=helper:foobar
+ EOF
+
+ expect_credential_query store bazquux <<-EOF
+ capability[]=authtype
+ capability[]=state
+ authtype=Multistage
+ credential=YW5vdGhlci10b2tlbg==
+ protocol=http
+ host=$HTTPD_DEST
+ state[]=helper:bazquux
+ EOF
+'
+
test_done
diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh
index 9da5134614..b27e481f95 100755
--- a/t/t5564-http-proxy.sh
+++ b/t/t5564-http-proxy.sh
@@ -38,4 +38,59 @@ test_expect_success 'clone can prompt for proxy password' '
expect_askpass pass proxuser
'
+start_socks() {
+ mkfifo socks_output &&
+ {
+ "$PERL_PATH" "$TEST_DIRECTORY/socks4-proxy.pl" "$1" >socks_output &
+ echo $! > "$TRASH_DIRECTORY/socks.pid"
+ } &&
+ read line <socks_output &&
+ test "$line" = ready
+}
+
+# The %30 tests that the correct amount of percent-encoding is applied to the
+# proxy string passed to curl.
+test_lazy_prereq SOCKS_PROXY '
+ test_have_prereq PERL &&
+ start_socks "$TRASH_DIRECTORY/%30.sock"
+'
+
+test_atexit '
+ test ! -e "$TRASH_DIRECTORY/socks.pid" ||
+ kill "$(cat "$TRASH_DIRECTORY/socks.pid")"
+'
+
+# The below tests morally ought to be gated on a prerequisite that Git is
+# linked with a libcurl that supports Unix socket paths for proxies (7.84 or
+# later), but this is not easy to test right now. Instead, we || the tests with
+# this function.
+old_libcurl_error() {
+ grep -Fx "fatal: libcurl 7.84 or later is required to support paths in proxy URLs" "$1"
+}
+
+test_expect_success SOCKS_PROXY 'clone via Unix socket' '
+ test_when_finished "rm -rf clone" &&
+ test_config_global http.proxy "socks4://localhost$PWD/%2530.sock" && {
+ {
+ GIT_TRACE_CURL=$PWD/trace git clone "$HTTPD_URL/smart/repo.git" clone 2>err &&
+ grep -i "SOCKS4 request granted" trace
+ } ||
+ old_libcurl_error err
+ }
+'
+
+test_expect_success 'Unix socket requires socks*:' - <<\EOT
+ ! git clone -c http.proxy=localhost/path https://example.com/repo.git 2>err && {
+ grep -Fx "fatal: Invalid proxy URL 'localhost/path': only SOCKS proxies support paths" err ||
+ old_libcurl_error err
+ }
+EOT
+
+test_expect_success 'Unix socket requires localhost' - <<\EOT
+ ! git clone -c http.proxy=socks4://127.0.0.1/path https://example.com/repo.git 2>err && {
+ grep -Fx "fatal: Invalid proxy URL 'socks4://127.0.0.1/path': host must be localhost if a path is present" err ||
+ old_libcurl_error err
+ }
+EOT
+
test_done
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index 1131503b76..8df4001b72 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -7,12 +7,37 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-git-daemon.sh
+
+test_expect_success 'daemon rejects invalid --init-timeout values' '
+ for arg in "3a" "-3"
+ do
+ test_must_fail git daemon --init-timeout="$arg" 2>err &&
+ test_grep "fatal: invalid init-timeout ${SQ}$arg${SQ}, expecting a non-negative integer" err ||
+ return 1
+ done
+'
+
+test_expect_success 'daemon rejects invalid --timeout values' '
+ for arg in "3a" "-3"
+ do
+ test_must_fail git daemon --timeout="$arg" 2>err &&
+ test_grep "fatal: invalid timeout ${SQ}$arg${SQ}, expecting a non-negative integer" err ||
+ return 1
+ done
+'
+
+test_expect_success 'daemon rejects invalid --max-connections values' '
+ arg='3a' &&
+ test_must_fail git daemon --max-connections=3a 2>err &&
+ test_grep "fatal: invalid max-connections ${SQ}$arg${SQ}, expecting an integer" err
+'
+
start_git_daemon
check_verbose_connect () {
- test_i18ngrep -F "Looking up 127.0.0.1 ..." stderr &&
- test_i18ngrep -F "Connecting to 127.0.0.1 (port " stderr &&
- test_i18ngrep -F "done." stderr
+ test_grep -F "Looking up 127.0.0.1 ..." stderr &&
+ test_grep -F "Connecting to 127.0.0.1 (port " stderr &&
+ test_grep -F "done." stderr
}
test_expect_success 'setup repository' '
@@ -108,7 +133,7 @@ test_expect_success 'fetch notices corrupt idx' '
test_expect_success 'client refuses to ask for repo with newline' '
test_must_fail git clone "$GIT_DAEMON_URL/repo$LF.git" dst 2>stderr &&
- test_i18ngrep newline.is.forbidden stderr
+ test_grep newline.is.forbidden stderr
'
test_remote_error()
@@ -148,7 +173,7 @@ test_remote_error()
fi
test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" "$@" 2>output &&
- test_i18ngrep "fatal: remote error: $msg: /$repo" output &&
+ test_grep "fatal: remote error: $msg: /$repo" output &&
ret=$?
chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
(exit $ret)
diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh
index 448134c4bf..a11b20e378 100755
--- a/t/t5571-pre-push-hook.sh
+++ b/t/t5571-pre-push-hook.sh
@@ -4,7 +4,6 @@ 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' '
diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh
index 4e917bf87d..f7650e8475 100755
--- a/t/t5572-pull-submodule.sh
+++ b/t/t5572-pull-submodule.sh
@@ -177,7 +177,7 @@ test_expect_success 'pull --rebase --recurse-submodules fails if both sides reco
# submodule itself, but the merge strategy in submodules
# does not support rebase:
test_must_fail git -C super pull --rebase --recurse-submodules 2>err &&
- test_i18ngrep "locally recorded submodule modifications" err
+ test_grep "locally recorded submodule modifications" err
'
test_expect_success 'pull --rebase --recurse-submodules (no submodule changes, no fork-point)' '
@@ -229,6 +229,7 @@ test_expect_success 'branch has no merge base with remote-tracking counterpart'
test_create_repo a-submodule &&
test_commit -C a-submodule foo &&
+ test_commit -C a-submodule bar &&
test_create_repo parent &&
git -C parent submodule add "$(pwd)/a-submodule" &&
@@ -245,4 +246,23 @@ test_expect_success 'branch has no merge base with remote-tracking counterpart'
git -C child pull --recurse-submodules --rebase
'
+test_expect_success 'fetch submodule remote of different name from superproject' '
+ git -C child remote rename origin o1 &&
+ git -C child submodule update --init &&
+
+ # Needs to create unreachable commit from current master branch.
+ git -C a-submodule checkout -b newmain HEAD^ &&
+ test_commit -C a-submodule echo &&
+ test_commit -C a-submodule moreecho &&
+ subc=$(git -C a-submodule rev-parse --short HEAD) &&
+
+ git -C parent/a-submodule fetch &&
+ git -C parent/a-submodule checkout "$subc" &&
+ git -C parent commit -m "update submodule" a-submodule &&
+ git -C a-submodule reset --hard HEAD^^ &&
+
+ git -C child pull --no-recurse-submodules &&
+ git -C child submodule update
+'
+
test_done
diff --git a/t/t5573-pull-verify-signatures.sh b/t/t5573-pull-verify-signatures.sh
index 1221ac0597..a76b54d7de 100755
--- a/t/t5573-pull-verify-signatures.sh
+++ b/t/t5573-pull-verify-signatures.sh
@@ -2,7 +2,6 @@
test_description='pull signature verification tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-gpg.sh"
@@ -47,46 +46,46 @@ test_expect_success GPG 'create repositories with signed commits' '
test_expect_success GPG 'pull unsigned commit with --verify-signatures' '
test_when_finished "git reset --hard && git checkout initial" &&
test_must_fail git pull --ff-only --verify-signatures unsigned 2>pullerror &&
- test_i18ngrep "does not have a GPG signature" pullerror
+ test_grep "does not have a GPG signature" pullerror
'
test_expect_success GPG 'pull commit with bad signature with --verify-signatures' '
test_when_finished "git reset --hard && git checkout initial" &&
test_must_fail git pull --ff-only --verify-signatures bad 2>pullerror &&
- test_i18ngrep "has a bad GPG signature" pullerror
+ test_grep "has a bad GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures' '
test_when_finished "git reset --hard && git checkout initial" &&
test_must_fail git pull --ff-only --verify-signatures untrusted 2>pullerror &&
- test_i18ngrep "has an untrusted GPG signature" pullerror
+ test_grep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures and minTrustLevel=ultimate' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel ultimate &&
test_must_fail git pull --ff-only --verify-signatures untrusted 2>pullerror &&
- test_i18ngrep "has an untrusted GPG signature" pullerror
+ test_grep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures and minTrustLevel=marginal' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel marginal &&
test_must_fail git pull --ff-only --verify-signatures untrusted 2>pullerror &&
- test_i18ngrep "has an untrusted GPG signature" pullerror
+ test_grep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures and minTrustLevel=undefined' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel undefined &&
git pull --ff-only --verify-signatures untrusted >pulloutput &&
- test_i18ngrep "has a good GPG signature" pulloutput
+ test_grep "has a good GPG signature" pulloutput
'
test_expect_success GPG 'pull signed commit with --verify-signatures' '
test_when_finished "git reset --hard && git checkout initial" &&
git pull --verify-signatures signed >pulloutput &&
- test_i18ngrep "has a good GPG signature" pulloutput
+ test_grep "has a good GPG signature" pulloutput
'
test_expect_success GPG 'pull commit with bad signature without verification' '
@@ -106,7 +105,7 @@ test_expect_success GPG 'pull unsigned commit into unborn branch' '
git init empty-repo &&
test_must_fail \
git -C empty-repo pull --verify-signatures .. 2>pullerror &&
- test_i18ngrep "does not have a GPG signature" pullerror
+ test_grep "does not have a GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with bad signature and --verify-signatures' '
@@ -114,7 +113,7 @@ test_expect_success GPG 'pull commit into unborn branch with bad signature and -
git init empty-repo &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../bad 2>pullerror &&
- test_i18ngrep "has a bad GPG signature" pullerror
+ test_grep "has a bad GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures' '
@@ -122,7 +121,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature
git init empty-repo &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&
- test_i18ngrep "has an untrusted GPG signature" pullerror
+ test_grep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=ultimate' '
@@ -131,7 +130,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature
test_config_global gpg.minTrustLevel ultimate &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&
- test_i18ngrep "has an untrusted GPG signature" pullerror
+ test_grep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=marginal' '
@@ -140,7 +139,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature
test_config_global gpg.minTrustLevel marginal &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&
- test_i18ngrep "has an untrusted GPG signature" pullerror
+ test_grep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=undefined' '
@@ -148,7 +147,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature
git init empty-repo &&
test_config_global gpg.minTrustLevel undefined &&
git -C empty-repo pull --ff-only --verify-signatures ../untrusted >pulloutput &&
- test_i18ngrep "has a good GPG signature" pulloutput
+ test_grep "has a good GPG signature" pulloutput
'
test_done
diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh
index 90e6dcb9a7..5883839a04 100755
--- a/t/t5574-fetch-output.sh
+++ b/t/t5574-fetch-output.sh
@@ -61,11 +61,10 @@ test_expect_success 'fetch compact output' '
test_cmp expect actual
'
-test_expect_success 'fetch porcelain output' '
- test_when_finished "rm -rf porcelain" &&
-
+test_expect_success 'setup for fetch porcelain output' '
# Set up a bunch of references that we can use to demonstrate different
# kinds of flag symbols in the output format.
+ test_commit commit-for-porcelain-output &&
MAIN_OLD=$(git rev-parse HEAD) &&
git branch "fast-forward" &&
git branch "deleted-branch" &&
@@ -74,15 +73,10 @@ test_expect_success 'fetch porcelain output' '
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 &&
+ # Backup to preseed.git
+ git clone --mirror . preseed.git &&
- # Now that we have set up the client repositories we can change our
- # local references.
+ # Continue changing our local references.
git branch new-branch &&
git branch -d deleted-branch &&
git checkout fast-forward &&
@@ -91,36 +85,53 @@ test_expect_success 'fetch porcelain output' '
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
+ FORCE_UPDATED_NEW=$(git rev-parse HEAD)
'
+for opt in "" "--atomic"
+do
+ test_expect_success "fetch porcelain output ${opt:+(atomic)}" '
+ test_when_finished "rm -rf porcelain" &&
+
+ # 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 preseed.git porcelain &&
+ git -C porcelain fetch origin $opt $refspecs &&
+
+ 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
+
+ # Change the URL of the repository to fetch different references.
+ git -C porcelain remote set-url origin .. &&
+
+ # 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 $opt \
+ --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 $opt \
+ --porcelain --prune origin $refspecs >actual 2>stderr &&
+ test_cmp expect actual &&
+ test_must_be_empty stderr
+ '
+done
+
test_expect_success 'fetch porcelain with multiple remotes' '
test_when_finished "rm -rf porcelain" &&
@@ -281,12 +292,12 @@ test_expect_success '--no-show-forced-updates' '
(
cd forced-update-clone &&
git fetch --show-forced-updates origin 2>output &&
- test_i18ngrep "(forced update)" output
+ test_grep "(forced update)" output
) &&
(
cd no-forced-update-clone &&
git fetch --no-show-forced-updates origin 2>output &&
- test_i18ngrep ! "(forced update)" output
+ test_grep ! "(forced update)" output
)
'
diff --git a/t/t5580-unc-paths.sh b/t/t5580-unc-paths.sh
index cd7604fff9..65ef1a3628 100755
--- a/t/t5580-unc-paths.sh
+++ b/t/t5580-unc-paths.sh
@@ -4,7 +4,6 @@ test_description='various Windows-only path tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
if test_have_prereq CYGWIN
@@ -75,7 +74,7 @@ test_expect_success push '
test_expect_success MINGW 'remote nick cannot contain backslashes' '
BACKSLASHED="$(winpwd | tr / \\\\)" &&
git ls-remote "$BACKSLASHED" 2>err &&
- test_i18ngrep ! "unable to access" err
+ test_grep ! "unable to access" err
'
test_expect_success 'unc alternates' '
diff --git a/t/t5582-fetch-negative-refspec.sh b/t/t5582-fetch-negative-refspec.sh
index 7a80e47c2b..ae32f8178a 100755
--- a/t/t5582-fetch-negative-refspec.sh
+++ b/t/t5582-fetch-negative-refspec.sh
@@ -282,4 +282,8 @@ test_expect_success '--prefetch succeeds when refspec becomes empty' '
git -C one fetch --prefetch
'
+test_expect_success '--prefetch succeeds with empty command line refspec' '
+ git -C one fetch --prefetch origin +refs/tags/extra
+'
+
test_done
diff --git a/t/t5583-push-branches.sh b/t/t5583-push-branches.sh
index 320f49c753..e7e1b6dab6 100755
--- a/t/t5583-push-branches.sh
+++ b/t/t5583-push-branches.sh
@@ -5,7 +5,6 @@ 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() {
diff --git a/t/t5600-clone-fail-cleanup.sh b/t/t5600-clone-fail-cleanup.sh
index c814afa565..34b3df4027 100755
--- a/t/t5600-clone-fail-cleanup.sh
+++ b/t/t5600-clone-fail-cleanup.sh
@@ -13,7 +13,6 @@ Unless the directory already exists, in which case we clean up only what we
wrote.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
corrupt_repo () {
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 17c287d7b8..d0c18660e3 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -46,6 +46,13 @@ test_expect_success 'output from clone' '
test $(grep Clon output | wc -l) = 1
'
+test_expect_success 'output from clone with core.abbrev does not crash' '
+ rm -fr dst &&
+ echo "Cloning into ${SQ}dst${SQ}..." >expect &&
+ git -c core.abbrev=12 clone -n "file://$(pwd)/src" dst >actual 2>&1 &&
+ test_cmp expect actual
+'
+
test_expect_success 'clone does not keep pack' '
rm -fr dst &&
@@ -157,6 +164,23 @@ test_expect_success 'clone --mirror does not repeat tags' '
'
+test_expect_success 'clone with files ref format' '
+ test_when_finished "rm -rf ref-storage" &&
+ git clone --ref-format=files --mirror src ref-storage &&
+ echo files >expect &&
+ git -C ref-storage rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone with garbage ref format' '
+ cat >expect <<-EOF &&
+ fatal: unknown ref storage format ${SQ}garbage${SQ}
+ EOF
+ test_must_fail git clone --ref-format=garbage --mirror src ref-storage 2>err &&
+ test_cmp expect err &&
+ test_path_is_missing ref-storage
+'
+
test_expect_success 'clone to destination with trailing /' '
git clone src target-1/ &&
@@ -506,19 +530,30 @@ do
'
done
+# Parsing of paths that look like IPv6 addresses is broken on Cygwin.
+expectation_for_ipv6_tests=success
+if test_have_prereq CYGWIN
+then
+ expectation_for_ipv6_tests=failure
+fi
+
#ipv6
for repo in rep rep/home/project 123
do
- test_expect_success "clone [::1]:$repo" '
+ test_expect_$expectation_for_ipv6_tests "clone [::1]:$repo" '
test_clone_url [::1]:$repo ::1 "$repo"
'
done
-#home directory
-test_expect_success "clone host:/~repo" '
+
+# Home directory. All tests that use "~repo" are broken in our CI job when the
+# leak sanitizer is enabled. It seems like either a bug in the sanitizer or in
+# glibc, but when executing getpwnam(3p) with an invalid username we eventually
+# start recursing in a call to free(3p), until bust the stack and segfault.
+test_expect_success !SANITIZE_LEAK "clone host:/~repo" '
test_clone_url host:/~repo host "~repo"
'
-test_expect_success "clone [::1]:/~repo" '
+test_expect_$expectation_for_ipv6_tests !SANITIZE_LEAK "clone [::1]:/~repo" '
test_clone_url [::1]:/~repo ::1 "~repo"
'
@@ -538,9 +573,9 @@ do
test_clone_url "ssh://host.xz$tcol/home/user/repo" host.xz /home/user/repo
'
# from home directory
- test_expect_success "clone ssh://host.xz$tcol/~repo" '
- test_clone_url "ssh://host.xz$tcol/~repo" host.xz "~repo"
-'
+ test_expect_success !SANITIZE_LEAK "clone ssh://host.xz$tcol/~repo" '
+ test_clone_url "ssh://host.xz$tcol/~repo" host.xz "~repo"
+ '
done
# with port number
@@ -549,7 +584,7 @@ test_expect_success 'clone ssh://host.xz:22/home/user/repo' '
'
# from home directory with port number
-test_expect_success 'clone ssh://host.xz:22/~repo' '
+test_expect_success !SANITIZE_LEAK 'clone ssh://host.xz:22/~repo' '
test_clone_url "ssh://host.xz:22/~repo" "-p 22 host.xz" "~repo"
'
@@ -566,8 +601,8 @@ done
for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
do
euah=$(echo $tuah | tr -d "[]")
- test_expect_success "clone ssh://$tuah/~repo" "
- test_clone_url ssh://$tuah/~repo $euah '~repo'
+ test_expect_success !SANITIZE_LEAK "clone ssh://$tuah/~repo" "
+ test_clone_url ssh://$tuah/~repo $euah '~repo'
"
done
@@ -584,8 +619,8 @@ done
for tuah in [::1] user@[::1] [user@::1]
do
euah=$(echo $tuah | tr -d "[]")
- test_expect_success "clone ssh://$tuah:22/~repo" "
- test_clone_url ssh://$tuah:22/~repo '-p 22' $euah '~repo'
+ test_expect_success !SANITIZE_LEAK "clone ssh://$tuah:22/~repo" "
+ test_clone_url ssh://$tuah:22/~repo '-p 22' $euah '~repo'
"
done
@@ -630,7 +665,7 @@ test_expect_success 'clone on case-insensitive fs' '
test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
grep X icasefs/warning &&
grep x icasefs/warning &&
- test_i18ngrep "the following paths have collided" icasefs/warning
+ test_grep "the following paths have collided" icasefs/warning
'
test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \
@@ -711,7 +746,7 @@ test_expect_success 'partial clone: warn if server does not support object filte
git clone --filter=blob:limit=0 "file://$(pwd)/server" client 2> err &&
- test_i18ngrep "filtering not recognized by server" err
+ test_grep "filtering not recognized by server" err
'
test_expect_success 'batch missing blob request during checkout' '
@@ -774,6 +809,18 @@ test_expect_success 'batch missing blob request does not inadvertently try to fe
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
+test_expect_success 'clone with includeIf' '
+ test_when_finished "rm -rf repo \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\"" &&
+ git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+
+ test_when_finished "rm \"$HOME\"/.gitconfig" &&
+ cat >"$HOME"/.gitconfig <<-EOF &&
+ [includeIf "onbranch:something"]
+ path = /does/not/exist.inc
+ EOF
+ git clone $HTTPD_URL/smart/repo.git repo
+'
+
test_expect_success 'partial clone using HTTP' '
partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
'
@@ -782,7 +829,7 @@ test_expect_success 'reject cloning shallow repository using HTTP' '
test_when_finished "rm -rf repo" &&
git clone --bare --no-local --depth=1 src "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
test_must_fail git -c protocol.version=2 clone --reject-shallow $HTTPD_URL/smart/repo.git repo 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err &&
+ test_grep -e "source repository is shallow, reject to clone." err &&
git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
'
diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh
index 56329aa160..cbcceab9d5 100755
--- a/t/t5602-clone-remote-exec.sh
+++ b/t/t5602-clone-remote-exec.sh
@@ -2,7 +2,6 @@
test_description=clone
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5603-clone-dirname.sh b/t/t5603-clone-dirname.sh
index 8ca1f09423..80eb4e04f8 100755
--- a/t/t5603-clone-dirname.sh
+++ b/t/t5603-clone-dirname.sh
@@ -2,7 +2,6 @@
test_description='check output directory names used by git-clone'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# we use a fake ssh wrapper that ignores the arguments
diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
index 9845fc04d5..fa5ca4f522 100755
--- a/t/t5604-clone-reference.sh
+++ b/t/t5604-clone-reference.sh
@@ -7,7 +7,6 @@ test_description='test clone --reference'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
base_dir=$(pwd)
@@ -317,7 +316,7 @@ test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at obje
for option in --local --no-hardlinks --dissociate
do
test_must_fail git clone $option T T$option 2>err || return 1 &&
- test_i18ngrep "symlink.*exists" err || return 1
+ test_grep "symlink.*exists" err || return 1
done &&
# But `--shared` clones should still work, even when specifying
diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh
index 1d7b1abda1..339d8c786f 100755
--- a/t/t5605-clone-local.sh
+++ b/t/t5605-clone-local.sh
@@ -65,11 +65,11 @@ test_expect_success 'Even without -l, local will make a hardlink' '
'
test_expect_success 'local clone of repo with nonexistent ref in HEAD' '
- echo "ref: refs/heads/nonexistent" > a.git/HEAD &&
+ git -C a.git symbolic-ref HEAD refs/heads/nonexistent &&
git clone a d &&
(cd d &&
git fetch &&
- test ! -e .git/refs/remotes/origin/HEAD)
+ test_ref_missing refs/remotes/origin/HEAD)
'
test_expect_success 'bundle clone without .bundle suffix' '
@@ -157,13 +157,13 @@ test_expect_success 'cloning locally respects "-u" for fetching refs' '
test_must_fail git clone --bare -u false a should_not_work.git
'
-test_expect_success 'local clone from repo with corrupt refs fails gracefully' '
+test_expect_success REFFILES 'local clone from repo with corrupt refs fails gracefully' '
git init corrupt &&
test_commit -C corrupt one &&
echo a >corrupt/.git/refs/heads/topic &&
test_must_fail git clone corrupt working 2>err &&
- grep "has a null OID" err
+ grep "has neither a valid OID nor a target" err
'
test_done
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index 5890319b97..8a15237736 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -4,7 +4,6 @@ test_description='basic clone options'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -39,7 +38,7 @@ test_expect_success 'clone -o' '
test_expect_success 'rejects invalid -o/--origin' '
test_must_fail git clone -o "bad...name" parent clone-bad-name 2>err &&
- test_i18ngrep "'\''bad...name'\'' is not a valid remote name" err
+ test_grep "'\''bad...name'\'' is not a valid remote name" err
'
@@ -56,7 +55,7 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
test_must_fail git clone --bare --separate-git-dir dot-git-destiation parent clone-bare-sgd 2>err &&
test_debug "cat err" &&
- test_i18ngrep -e "options .--bare. and .--separate-git-dir. cannot be used together" err
+ test_grep -e "options .--bare. and .--separate-git-dir. cannot be used together" err
'
@@ -64,14 +63,14 @@ test_expect_success 'disallows --bundle-uri with shallow options' '
for option in --depth=1 --shallow-since=01-01-2000 --shallow-exclude=HEAD
do
test_must_fail git clone --bundle-uri=bundle $option from to 2>err &&
- grep "bundle-uri is incompatible" err || return 1
+ grep "bundle-uri.* cannot be used together" err || return 1
done
'
test_expect_success 'reject cloning shallow repository' '
test_when_finished "rm -rf repo" &&
test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err &&
+ test_grep -e "source repository is shallow, reject to clone." err &&
git clone --no-reject-shallow shallow-repo repo
'
@@ -79,7 +78,7 @@ test_expect_success 'reject cloning shallow repository' '
test_expect_success 'reject cloning non-local shallow repository' '
test_when_finished "rm -rf repo" &&
test_must_fail git clone --reject-shallow --no-local shallow-repo out 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err &&
+ test_grep -e "source repository is shallow, reject to clone." err &&
git clone --no-reject-shallow --no-local shallow-repo repo
'
@@ -120,14 +119,14 @@ test_expect_success 'prefers -c config over --template config' '
'
-test_expect_failure 'prefers --template config even for core.bare' '
+test_expect_success 'ignore --template config 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 "$(git -C clone-bare-config config --local core.bare)" = "false" &&
+ test_path_is_missing clone-bare-config/HEAD
'
test_expect_success 'prefers config "clone.defaultRemoteName" over default' '
@@ -149,7 +148,7 @@ test_expect_success 'redirected clone does not show progress' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
! grep % err &&
- test_i18ngrep ! "Checking connectivity" err
+ test_grep ! "Checking connectivity" err
'
diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh
index 51705aa86a..489c6570da 100755
--- a/t/t5607-clone-bundle.sh
+++ b/t/t5607-clone-bundle.sh
@@ -24,7 +24,7 @@ test_expect_success 'setup' '
test_expect_success '"verify" needs a worktree' '
git bundle create tip.bundle -1 main &&
nongit test_must_fail git bundle verify ../tip.bundle 2>err &&
- test_i18ngrep "need a repository" err
+ test_grep "need a repository" err
'
test_expect_success 'annotated tags can be excluded by rev-list options' '
@@ -138,6 +138,41 @@ test_expect_success 'fetch SHA-1 from bundle' '
git fetch --no-tags foo/tip.bundle "$(cat hash)"
'
+test_expect_success 'clone bundle with different fsckObjects configurations' '
+ test_create_repo bundle-fsck &&
+ (
+ cd bundle-fsck &&
+ test_commit A &&
+ commit_a=$(git rev-parse A) &&
+ tree_a=$(git rev-parse A^{tree}) &&
+ cat >data <<-EOF &&
+ tree $tree_a
+ parent $commit_a
+ author A U Thor
+ committer A U Thor
+
+ commit: this is a commit with bad emails
+
+ EOF
+ bad_commit=$(git hash-object --literally -t commit -w --stdin <data) &&
+ git branch bad $bad_commit &&
+ git bundle create bad.bundle bad
+ ) &&
+
+ git clone bundle-fsck/bad.bundle bundle-no-fsck &&
+
+ git -c fetch.fsckObjects=false -c transfer.fsckObjects=true \
+ clone bundle-fsck/bad.bundle bundle-fetch-no-fsck &&
+
+ test_must_fail git -c fetch.fsckObjects=true \
+ clone bundle-fsck/bad.bundle bundle-fetch-fsck 2>err &&
+ test_grep "missingEmail" err &&
+
+ test_must_fail git -c transfer.fsckObjects=true \
+ clone bundle-fsck/bad.bundle bundle-transfer-fsck 2>err &&
+ test_grep "missingEmail" err
+'
+
test_expect_success 'git bundle uses expected default format' '
git bundle create bundle HEAD^.. &&
cat >expect <<-EOF &&
@@ -166,7 +201,7 @@ test_expect_success 'git bundle v3 rejects unknown capabilities' '
@unknown=silly
EOF
test_must_fail git bundle verify new 2>output &&
- test_i18ngrep "unknown capability .unknown=silly." output
+ test_grep "unknown capability .unknown=silly." output
'
test_done
diff --git a/t/t5609-clone-branch.sh b/t/t5609-clone-branch.sh
index 252e1f7c20..f86a674a03 100755
--- a/t/t5609-clone-branch.sh
+++ b/t/t5609-clone-branch.sh
@@ -4,7 +4,6 @@ test_description='clone --branch option'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_HEAD() {
diff --git a/t/t5610-clone-detached.sh b/t/t5610-clone-detached.sh
index 022ed3d87c..a7ec21eda5 100755
--- a/t/t5610-clone-detached.sh
+++ b/t/t5610-clone-detached.sh
@@ -4,7 +4,6 @@ test_description='test cloning a repository with detached HEAD'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
head_is_detached() {
diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh
index 727caff443..4873089a8c 100755
--- a/t/t5611-clone-config.sh
+++ b/t/t5611-clone-config.sh
@@ -4,7 +4,6 @@ test_description='tests for git clone -c key=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 'clone -c sets config in cloned repo' '
@@ -103,7 +102,7 @@ test_expect_success 'set up shallow repository' '
test_expect_success 'clone.rejectshallow=true should reject cloning shallow repo' '
test_when_finished "rm -rf out" &&
test_must_fail git -c clone.rejectshallow=true clone --no-local shallow-repo out 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err &&
+ test_grep -e "source repository is shallow, reject to clone." err &&
git -c clone.rejectshallow=false clone --no-local shallow-repo out
'
@@ -111,7 +110,7 @@ test_expect_success 'clone.rejectshallow=true should reject cloning shallow repo
test_expect_success 'option --[no-]reject-shallow override clone.rejectshallow config' '
test_when_finished "rm -rf out" &&
test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local shallow-repo out 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err &&
+ test_grep -e "source repository is shallow, reject to clone." err &&
git -c clone.rejectshallow=true clone --no-reject-shallow --no-local shallow-repo out
'
diff --git a/t/t5613-info-alternate.sh b/t/t5613-info-alternate.sh
index 7708cbafa9..c752804a8e 100755
--- a/t/t5613-info-alternate.sh
+++ b/t/t5613-info-alternate.sh
@@ -5,7 +5,6 @@
test_description='test transitive info/alternate entries'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'preparing first repository' '
diff --git a/t/t5614-clone-submodules-shallow.sh b/t/t5614-clone-submodules-shallow.sh
index c2a2bb453e..0c85ef834a 100755
--- a/t/t5614-clone-submodules-shallow.sh
+++ b/t/t5614-clone-submodules-shallow.sh
@@ -2,7 +2,6 @@
test_description='Test shallow cloning of repos with submodules'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pwd=$(pwd)
diff --git a/t/t5615-alternate-env.sh b/t/t5615-alternate-env.sh
index 83513e46a3..9d6aa2187f 100755
--- a/t/t5615-alternate-env.sh
+++ b/t/t5615-alternate-env.sh
@@ -2,7 +2,6 @@
test_description='handling of alternates in environment variables'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
check_obj () {
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 8759fc2853..4650451964 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -229,7 +229,7 @@ test_expect_success 'fetch --refetch triggers repacking' '
GIT_TRACE2_EVENT="$PWD/trace1.event" \
git -C pc1 fetch --refetch origin &&
- test_subcommand git maintenance run --auto --no-quiet <trace1.event &&
+ test_subcommand git maintenance run --auto --no-quiet --detach <trace1.event &&
grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace1.event &&
grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace1.event &&
@@ -238,7 +238,7 @@ test_expect_success 'fetch --refetch triggers repacking' '
-c gc.autoPackLimit=0 \
-c maintenance.incremental-repack.auto=1234 \
-C pc1 fetch --refetch origin &&
- test_subcommand git maintenance run --auto --no-quiet <trace2.event &&
+ test_subcommand git maintenance run --auto --no-quiet --detach <trace2.event &&
grep \"param\":\"gc.autopacklimit\",\"value\":\"0\" trace2.event &&
grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace2.event &&
@@ -247,7 +247,7 @@ test_expect_success 'fetch --refetch triggers repacking' '
-c gc.autoPackLimit=1234 \
-c maintenance.incremental-repack.auto=0 \
-C pc1 fetch --refetch origin &&
- test_subcommand git maintenance run --auto --no-quiet <trace3.event &&
+ test_subcommand git maintenance run --auto --no-quiet --detach <trace3.event &&
grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace3.event &&
grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"0\" trace3.event
'
@@ -353,14 +353,14 @@ test_expect_success 'upload-pack complains of bogus filter config' '
test_must_fail git \
-c uploadpackfilter.tree.maxdepth \
upload-pack . >/dev/null 2>err &&
- test_i18ngrep "unable to parse.*tree.maxdepth" err
+ test_grep "unable to parse.*tree.maxdepth" err
'
test_expect_success 'upload-pack fails banned object filters' '
test_config -C srv.bare uploadpackfilter.blob:none.allow false &&
test_must_fail ok=sigpipe git clone --no-checkout --filter=blob:none \
"file://$(pwd)/srv.bare" pc3 2>err &&
- test_i18ngrep "filter '\''blob:none'\'' not supported" err
+ test_grep "filter '\''blob:none'\'' not supported" err
'
test_expect_success 'upload-pack fails banned combine object filters' '
@@ -370,14 +370,14 @@ test_expect_success 'upload-pack fails banned combine object filters' '
test_config -C srv.bare uploadpackfilter.blob:none.allow false &&
test_must_fail ok=sigpipe git clone --no-checkout --filter=tree:1 \
--filter=blob:none "file://$(pwd)/srv.bare" pc3 2>err &&
- test_i18ngrep "filter '\''blob:none'\'' not supported" err
+ test_grep "filter '\''blob:none'\'' not supported" err
'
test_expect_success 'upload-pack fails banned object filters with fallback' '
test_config -C srv.bare uploadpackfilter.allow false &&
test_must_fail ok=sigpipe git clone --no-checkout --filter=blob:none \
"file://$(pwd)/srv.bare" pc3 2>err &&
- test_i18ngrep "filter '\''blob:none'\'' not supported" err
+ test_grep "filter '\''blob:none'\'' not supported" err
'
test_expect_success 'upload-pack limits tree depth filters' '
@@ -386,7 +386,7 @@ test_expect_success 'upload-pack limits tree depth filters' '
test_config -C srv.bare uploadpackfilter.tree.maxDepth 0 &&
test_must_fail ok=sigpipe git clone --no-checkout --filter=tree:1 \
"file://$(pwd)/srv.bare" pc3 2>err &&
- test_i18ngrep "tree filter allows max depth 0, but got 1" err &&
+ test_grep "tree filter allows max depth 0, but got 1" err &&
git clone --no-checkout --filter=tree:0 "file://$(pwd)/srv.bare" pc4 &&
@@ -394,7 +394,7 @@ test_expect_success 'upload-pack limits tree depth filters' '
git clone --no-checkout --filter=tree:5 "file://$(pwd)/srv.bare" pc5 &&
test_must_fail ok=sigpipe git clone --no-checkout --filter=tree:6 \
"file://$(pwd)/srv.bare" pc6 2>err &&
- test_i18ngrep "tree filter allows max depth 5, but got 6" err
+ test_grep "tree filter allows max depth 5, but got 6" err
'
test_expect_success 'partial clone fetches blobs pointed to by refs even if normally filtered out' '
@@ -459,11 +459,11 @@ test_expect_success 'partial clone with unresolvable sparse filter fails cleanly
test_must_fail git clone --no-local --bare \
--filter=sparse:oid=main:no-such-name \
sparse-src dst.git 2>err &&
- test_i18ngrep "unable to access sparse blob in .main:no-such-name" err &&
+ test_grep "unable to access sparse blob in .main:no-such-name" err &&
test_must_fail git clone --no-local --bare \
--filter=sparse:oid=main \
sparse-src dst.git 2>err &&
- test_i18ngrep "unable to parse sparse filter data in" err
+ test_grep "unable to parse sparse filter data in" err
'
setup_triangle () {
@@ -493,8 +493,8 @@ setup_triangle () {
TREE_HASH=$(git -C server rev-parse HEAD~1^{tree}) &&
git -C promisor-remote fetch --keep "file://$(pwd)/server" "$TREE_HASH" &&
git -C promisor-remote count-objects -v >object-count &&
- test_i18ngrep "count: 0" object-count &&
- test_i18ngrep "in-pack: 2" object-count &&
+ test_grep "count: 0" object-count &&
+ test_grep "in-pack: 2" object-count &&
# Set it as the promisor remote of client. Thus, whenever
# the client lazy fetches, the lazy fetch will succeed only if it is
@@ -693,6 +693,36 @@ test_expect_success 'lazy-fetch in submodule succeeds' '
git -C client restore --recurse-submodules --source=HEAD^ :/
'
+test_expect_success 'after fetching descendants of non-promisor commits, gc works' '
+ # Setup
+ git init full &&
+ git -C full config uploadpack.allowfilter 1 &&
+ git -C full config uploadpack.allowanysha1inwant 1 &&
+ touch full/foo &&
+ git -C full add foo &&
+ git -C full commit -m "commit 1" &&
+ git -C full checkout --detach &&
+
+ # Partial clone and push commit to remote
+ git clone "file://$(pwd)/full" --filter=blob:none partial &&
+ echo "hello" > partial/foo &&
+ git -C partial commit -a -m "commit 2" &&
+ git -C partial push &&
+
+ # gc in partial repo
+ git -C partial gc --prune=now &&
+
+ # Create another commit in normal repo
+ git -C full checkout main &&
+ echo " world" >> full/foo &&
+ git -C full commit -a -m "commit 3" &&
+
+ # Pull from remote in partial repo, and run gc again
+ git -C partial pull &&
+ git -C partial gc --prune=now
+'
+
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
@@ -748,7 +778,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
test_must_fail git -c protocol.version=2 clone \
--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&
- test_i18ngrep "did not send all necessary objects" err &&
+ test_grep "did not send all necessary objects" err &&
# Ensure that the one-time-perl script was used.
! test -e "$HTTPD_ROOT_PATH/one-time-perl"
diff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh
index 5a4d7936a7..6884338249 100755
--- a/t/t5617-clone-submodules-remote.sh
+++ b/t/t5617-clone-submodules-remote.sh
@@ -5,7 +5,6 @@ test_description='Test cloning repos with submodules using remote-tracking branc
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pwd=$(pwd)
diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh
index f905db0a3f..2fb6d549d3 100755
--- a/t/t5618-alternate-refs.sh
+++ b/t/t5618-alternate-refs.sh
@@ -2,7 +2,6 @@
test_description='test handling of --alternate-refs traversal'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Avoid test_commit because we want a specific and known set of refs:
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index f21e5e9d33..de904c1655 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -5,7 +5,6 @@ test_description='test protocol v2 server commands'
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 'test capability advertisement' '
@@ -20,7 +19,6 @@ test_expect_success 'test capability advertisement' '
fetch=shallow wait-for-done
server-option
object-format=$(test_oid algo)
- object-info
EOF
cat >expect.trailer <<-EOF &&
0000
@@ -52,7 +50,7 @@ test_expect_success 'request invalid capability' '
0000
EOF
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
- test_i18ngrep "unknown capability" err
+ test_grep "unknown capability" err
'
test_expect_success 'request with no command' '
@@ -62,7 +60,7 @@ test_expect_success 'request with no command' '
0000
EOF
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
- test_i18ngrep "no command requested" err
+ test_grep "no command requested" err
'
test_expect_success 'request invalid command' '
@@ -73,7 +71,7 @@ test_expect_success 'request invalid command' '
0000
EOF
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
- test_i18ngrep "invalid command" err
+ test_grep "invalid command" err
'
test_expect_success 'request capability as command' '
@@ -115,7 +113,7 @@ test_expect_success 'wrong object-format' '
0000
EOF
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
- test_i18ngrep "mismatched object format" err
+ test_grep "mismatched object format" err
'
# Test the basics of ls-refs
@@ -323,6 +321,8 @@ test_expect_success 'unexpected lines are not allowed in fetch request' '
# Test the basics of object-info
#
test_expect_success 'basics of object-info' '
+ test_config transfer.advertiseObjectInfo true &&
+
test-tool pkt-line pack >in <<-EOF &&
command=object-info
object-format=$(test_oid algo)
@@ -380,4 +380,25 @@ test_expect_success 'basics of bundle-uri: dies if not enabled' '
test_must_be_empty out
'
+test_expect_success 'object-info missing from capabilities when disabled' '
+ test_config transfer.advertiseObjectInfo false &&
+
+ GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
+ --advertise-capabilities >out &&
+ test-tool pkt-line unpack <out >actual &&
+
+ ! grep object.info actual
+'
+
+test_expect_success 'object-info commands rejected when disabled' '
+ test_config transfer.advertiseObjectInfo false &&
+
+ test-tool pkt-line pack >in <<-EOF &&
+ command=object-info
+ EOF
+
+ test_must_fail test-tool serve-v2 --stateless-rpc <in 2>err &&
+ grep invalid.command err
+'
+
test_done
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 6af5c2062f..d3df81e785 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -185,12 +185,49 @@ test_expect_success 'server-options are sent when using ls-remote' '
grep "server-option=world" log
'
+test_expect_success 'server-options from configuration are used by ls-remote' '
+ test_when_finished "rm -rf log myclone" &&
+ git clone "file://$(pwd)/file_parent" myclone &&
+ cat >expect <<-EOF &&
+ $(git -C file_parent rev-parse refs/heads/main)$(printf "\t")refs/heads/main
+ EOF
+
+ # Default server options from configuration are used
+ git -C myclone config --add remote.origin.serverOption foo &&
+ git -C myclone config --add remote.origin.serverOption bar &&
+ GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
+ ls-remote origin main >actual &&
+ test_cmp expect actual &&
+ test_grep "ls-remote> server-option=foo" log &&
+ test_grep "ls-remote> server-option=bar" log &&
+ rm -f log &&
+
+ # Empty value of remote.<name>.serverOption clears the list
+ git -C myclone config --add remote.origin.serverOption "" &&
+ git -C myclone config --add remote.origin.serverOption tar &&
+ GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
+ ls-remote origin main >actual &&
+ test_cmp expect actual &&
+ test_grep "ls-remote> server-option=tar" log &&
+ test_grep ! "ls-remote> server-option=foo" log &&
+ test_grep ! "ls-remote> server-option=bar" log &&
+ rm -f log &&
+
+ # Server option from command line overrides those from configuration
+ GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
+ ls-remote -o hello -o world origin main >actual &&
+ test_cmp expect actual &&
+ test_grep "ls-remote> server-option=hello" log &&
+ test_grep "ls-remote> server-option=world" log &&
+ test_grep ! "ls-remote> server-option=tar" log
+'
+
test_expect_success 'warn if using server-option with ls-remote with legacy protocol' '
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
ls-remote -o hello -o world "file://$(pwd)/file_parent" main 2>err &&
- test_i18ngrep "see protocol.version in" err &&
- test_i18ngrep "server options require protocol version 2 or later" err
+ test_grep "see protocol.version in" err &&
+ test_grep "server options require protocol version 2 or later" err
'
test_expect_success 'clone with file:// using protocol v2' '
@@ -221,7 +258,9 @@ test_expect_success 'clone of empty repo propagates name of default branch' '
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
git -c init.defaultBranch=main -c protocol.version=2 \
clone "file://$(pwd)/file_empty_parent" file_empty_child &&
- grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD
+ echo refs/heads/mydefaultbranch >expect &&
+ git -C file_empty_child symbolic-ref HEAD >actual &&
+ test_cmp expect actual
'
test_expect_success '...but not if explicitly forbidden by config' '
@@ -234,7 +273,9 @@ test_expect_success '...but not if explicitly forbidden by config' '
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \
git -c init.defaultBranch=main -c protocol.version=2 \
clone "file://$(pwd)/file_empty_parent" file_empty_child &&
- ! grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD
+ echo refs/heads/main >expect &&
+ git -C file_empty_child symbolic-ref HEAD >actual &&
+ test_cmp expect actual
'
test_expect_success 'bare clone propagates empty default branch' '
@@ -247,7 +288,9 @@ test_expect_success 'bare clone propagates empty default branch' '
git -c init.defaultBranch=main -c protocol.version=2 \
clone --bare \
"file://$(pwd)/file_empty_parent" file_empty_child.git &&
- grep "refs/heads/mydefaultbranch" file_empty_child.git/HEAD
+ echo "refs/heads/mydefaultbranch" >expect &&
+ git -C file_empty_child.git symbolic-ref HEAD >actual &&
+ test_cmp expect actual
'
test_expect_success 'clone propagates unborn HEAD from non-empty repo' '
@@ -265,7 +308,9 @@ test_expect_success 'clone propagates unborn HEAD from non-empty repo' '
git -c init.defaultBranch=main -c protocol.version=2 \
clone "file://$(pwd)/file_unborn_parent" \
file_unborn_child 2>stderr &&
- grep "refs/heads/mydefaultbranch" file_unborn_child/.git/HEAD &&
+ echo "refs/heads/mydefaultbranch" >expect &&
+ git -C file_unborn_child symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
grep "warning: remote HEAD refers to nonexistent ref" stderr
'
@@ -295,7 +340,9 @@ test_expect_success 'bare clone propagates unborn HEAD from non-empty repo' '
git -c init.defaultBranch=main -c protocol.version=2 \
clone --bare "file://$(pwd)/file_unborn_parent" \
file_unborn_child.git 2>stderr &&
- grep "refs/heads/mydefaultbranch" file_unborn_child.git/HEAD &&
+ echo "refs/heads/mydefaultbranch" >expect &&
+ git -C file_unborn_child.git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
! grep "warning:" stderr
'
@@ -315,7 +362,9 @@ test_expect_success 'defaulted HEAD uses remote branch if available' '
git -c init.defaultBranch=branchwithstuff -c protocol.version=2 \
clone "file://$(pwd)/file_unborn_parent" \
file_unborn_child 2>stderr &&
- grep "refs/heads/branchwithstuff" file_unborn_child/.git/HEAD &&
+ echo "refs/heads/branchwithstuff" >expect &&
+ git -C file_unborn_child symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
test_path_is_file file_unborn_child/stuff.t &&
! grep "warning:" stderr
'
@@ -369,6 +418,54 @@ test_expect_success 'server-options are sent when fetching' '
grep "server-option=world" log
'
+test_expect_success 'server-options are sent when fetch multiple remotes' '
+ test_when_finished "rm -f log server_options_sent" &&
+ git clone "file://$(pwd)/file_parent" child_multi_remotes &&
+ git -C child_multi_remotes remote add another "file://$(pwd)/file_parent" &&
+ GIT_TRACE_PACKET="$(pwd)/log" git -C child_multi_remotes -c protocol.version=2 \
+ fetch -o hello --all &&
+ grep "fetch> server-option=hello" log >server_options_sent &&
+ test_line_count = 2 server_options_sent
+'
+
+test_expect_success 'server-options from configuration are used by git-fetch' '
+ test_when_finished "rm -rf log myclone" &&
+ git clone "file://$(pwd)/file_parent" myclone &&
+ git -C file_parent log -1 --format=%s >expect &&
+
+ # Default server options from configuration are used
+ git -C myclone config --add remote.origin.serverOption foo &&
+ git -C myclone config --add remote.origin.serverOption bar &&
+ GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
+ fetch origin main &&
+ git -C myclone log -1 --format=%s origin/main >actual &&
+ test_cmp expect actual &&
+ test_grep "fetch> server-option=foo" log &&
+ test_grep "fetch> server-option=bar" log &&
+ rm -f log &&
+
+ # Empty value of remote.<name>.serverOption clears the list
+ git -C myclone config --add remote.origin.serverOption "" &&
+ git -C myclone config --add remote.origin.serverOption tar &&
+ GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
+ fetch origin main &&
+ git -C myclone log -1 --format=%s origin/main >actual &&
+ test_cmp expect actual &&
+ test_grep "fetch> server-option=tar" log &&
+ test_grep ! "fetch> server-option=foo" log &&
+ test_grep ! "fetch> server-option=bar" log &&
+ rm -f log &&
+
+ # Server option from command line overrides those from configuration
+ GIT_TRACE_PACKET="$(pwd)/log" git -C myclone -c protocol.version=2 \
+ fetch -o hello -o world origin main &&
+ git -C myclone log -1 --format=%s origin/main >actual &&
+ test_cmp expect actual &&
+ test_grep "fetch> server-option=hello" log &&
+ test_grep "fetch> server-option=world" log &&
+ test_grep ! "fetch> server-option=tar" log
+'
+
test_expect_success 'warn if using server-option with fetch with legacy protocol' '
test_when_finished "rm -rf temp_child" &&
@@ -377,8 +474,8 @@ test_expect_success 'warn if using server-option with fetch with legacy protocol
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 git -C temp_child -c protocol.version=0 \
fetch -o hello -o world "file://$(pwd)/file_parent" main 2>err &&
- test_i18ngrep "see protocol.version in" err &&
- test_i18ngrep "server options require protocol version 2 or later" err
+ test_grep "see protocol.version in" err &&
+ test_grep "server options require protocol version 2 or later" err
'
test_expect_success 'server-options are sent when cloning' '
@@ -392,6 +489,37 @@ test_expect_success 'server-options are sent when cloning' '
grep "server-option=world" log
'
+test_expect_success 'server-options from configuration are used by git-clone' '
+ test_when_finished "rm -rf log myclone" &&
+
+ # Default server options from configuration are used
+ GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
+ -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
+ clone "file://$(pwd)/file_parent" myclone &&
+ test_grep "clone> server-option=foo" log &&
+ test_grep "clone> server-option=bar" log &&
+ rm -rf log myclone &&
+
+ # Empty value of remote.<name>.serverOption clears the list
+ GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
+ -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
+ -c remote.origin.serverOption= -c remote.origin.serverOption=tar \
+ clone "file://$(pwd)/file_parent" myclone &&
+ test_grep "clone> server-option=tar" log &&
+ test_grep ! "clone> server-option=foo" log &&
+ test_grep ! "clone> server-option=bar" log &&
+ rm -rf log myclone &&
+
+ # Server option from command line overrides those from configuration
+ GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
+ -c remote.origin.serverOption=tar \
+ clone --server-option=hello --server-option=world \
+ "file://$(pwd)/file_parent" myclone &&
+ test_grep "clone> server-option=hello" log &&
+ test_grep "clone> server-option=world" log &&
+ test_grep ! "clone> server-option=tar" log
+'
+
test_expect_success 'warn if using server-option with clone with legacy protocol' '
test_when_finished "rm -rf myclone" &&
@@ -399,8 +527,25 @@ test_expect_success 'warn if using server-option with clone with legacy protocol
clone --server-option=hello --server-option=world \
"file://$(pwd)/file_parent" myclone 2>err &&
- test_i18ngrep "see protocol.version in" err &&
- test_i18ngrep "server options require protocol version 2 or later" err
+ test_grep "see protocol.version in" err &&
+ test_grep "server options require protocol version 2 or later" err
+'
+
+test_expect_success 'server-option configuration with legacy protocol is ok' '
+ test_when_finished "rm -rf myclone" &&
+
+ env GIT_TEST_PROTOCOL_VERSION=0 git -c protocol.version=0 \
+ -c remote.origin.serverOption=foo -c remote.origin.serverOption=bar \
+ clone "file://$(pwd)/file_parent" myclone
+'
+
+test_expect_success 'invalid server-option configuration' '
+ test_when_finished "rm -rf myclone" &&
+
+ test_must_fail git -c protocol.version=2 \
+ -c remote.origin.serverOption \
+ clone "file://$(pwd)/file_parent" myclone 2>err &&
+ test_grep "error: missing value for '\''remote.origin.serveroption'\''" err
'
test_expect_success 'upload-pack respects config using protocol v2' '
@@ -495,7 +640,7 @@ test_expect_success 'partial clone warns if filter is not advertised' '
git -C server config uploadpack.allowfilter 0 &&
git -c protocol.version=2 \
clone --filter=blob:none "file://$(pwd)/server" client 2>err &&
- test_i18ngrep "filtering not recognized by server, ignoring" err
+ test_grep "filtering not recognized by server, ignoring" err
'
test_expect_success 'even with handcrafted request, filter does not work if not advertised' '
@@ -736,7 +881,7 @@ test_expect_success 'file:// --negotiate-only with protocol v0' '
--negotiate-only \
--negotiation-tip=$(git -C client rev-parse HEAD) \
origin 2>err &&
- test_i18ngrep "negotiate-only requires protocol v2" err
+ test_grep "negotiate-only requires protocol v2" err
'
test_expect_success 'push with custom path does not request v2' '
@@ -766,6 +911,25 @@ test_expect_success 'archive with custom path does not request v2' '
! grep ^GIT_PROTOCOL env.trace
'
+test_expect_success 'reject client packfile-uris if not advertised' '
+ {
+ packetize command=fetch &&
+ packetize object-format=$(test_oid algo) &&
+ printf 0001 &&
+ packetize packfile-uris https &&
+ packetize done &&
+ printf 0000
+ } >input &&
+ test_must_fail env GIT_PROTOCOL=version=2 \
+ git upload-pack client <input &&
+ test_must_fail env GIT_PROTOCOL=version=2 \
+ git -c uploadpack.blobpackfileuri \
+ upload-pack client <input &&
+ GIT_PROTOCOL=version=2 \
+ git -c uploadpack.blobpackfileuri=anything \
+ upload-pack client <input
+'
+
# Test protocol v2 with 'http://' transport
#
. "$TEST_DIRECTORY"/lib-httpd.sh
@@ -809,7 +973,7 @@ test_expect_success 'clone repository with http:// using protocol v2 with incomp
# Server responded using protocol v2
grep "git< version 2" log &&
# Client reported appropriate failure
- test_i18ngrep "bytes of length header were received" err
+ test_grep "bytes of length header were received" err
'
test_expect_success 'clone repository with http:// using protocol v2 with incomplete pktline body' '
@@ -826,7 +990,7 @@ test_expect_success 'clone repository with http:// using protocol v2 with incomp
# Server responded using protocol v2
grep "git< version 2" log &&
# Client reported appropriate failure
- test_i18ngrep "bytes of body are still expected" err
+ test_grep "bytes of body are still expected" err
'
test_expect_success 'clone with http:// using protocol v2 and invalid parameters' '
@@ -973,7 +1137,7 @@ test_expect_success 'when server sends "ready", expect DELIM' '
test_must_fail git -C http_child -c protocol.version=2 \
fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
- test_i18ngrep "expected packfile to be sent after .ready." err
+ test_grep "expected packfile to be sent after .ready." err
'
test_expect_success 'when server does not send "ready", expect FLUSH' '
@@ -1001,7 +1165,7 @@ test_expect_success 'when server does not send "ready", expect FLUSH' '
fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
grep "fetch< .*acknowledgments" log &&
! grep "fetch< .*ready" log &&
- test_i18ngrep "expected no other sections to be sent after no .ready." err
+ test_grep "expected no other sections to be sent after no .ready." err
'
configure_exclusion () {
@@ -1111,7 +1275,7 @@ test_expect_success 'fetching with valid packfile URI but invalid hash fails' '
git -c protocol.version=2 \
-c fetch.uriprotocols=http,https \
clone "$HTTPD_URL/smart/http_parent" http_child 2>err &&
- test_i18ngrep "pack downloaded from.*does not match expected hash" err
+ test_grep "pack downloaded from.*does not match expected hash" err
'
test_expect_success 'packfile-uri with transfer.fsckobjects' '
@@ -1165,7 +1329,7 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails on bad object'
test_must_fail git -c protocol.version=2 -c transfer.fsckobjects=1 \
-c fetch.uriprotocols=http,https \
clone "$HTTPD_URL/smart/http_parent" http_child 2>error &&
- test_i18ngrep "invalid author/committer line - missing email" error
+ test_grep "invalid author/committer line - missing email" error
'
test_expect_success 'packfile-uri with transfer.fsckobjects succeeds when .gitmodules is separate from tree' '
@@ -1213,7 +1377,7 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails when .gitmodul
test_must_fail git -c protocol.version=2 -c transfer.fsckobjects=1 \
-c fetch.uriprotocols=http,https \
clone "$HTTPD_URL/smart/http_parent" http_child 2>err &&
- test_i18ngrep "disallowed submodule name" err
+ test_grep "disallowed submodule name" err
'
test_expect_success 'packfile-uri path redacted in trace' '
@@ -1296,7 +1460,7 @@ test_expect_success 'http:// --negotiate-only without wait-for-done support' '
--negotiate-only \
--negotiation-tip=$(git -C client rev-parse HEAD) \
origin 2>err &&
- test_i18ngrep "server does not support wait-for-done" err
+ test_grep "server does not support wait-for-done" err
'
test_expect_success 'http:// --negotiate-only with protocol v0' '
@@ -1310,7 +1474,7 @@ test_expect_success 'http:// --negotiate-only with protocol v0' '
--negotiate-only \
--negotiation-tip=$(git -C client rev-parse HEAD) \
origin 2>err &&
- test_i18ngrep "negotiate-only requires protocol v2" err
+ test_grep "negotiate-only requires protocol v2" err
'
# DO NOT add non-httpd-specific tests here, because the last part of this
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index df74f80061..191097171b 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -484,7 +484,7 @@ test_expect_success 'server is initially ahead - no ref in want' '
cp -r "$LOCAL_PRISTINE" local &&
inconsistency main $(test_oid numeric) &&
test_must_fail git -C local fetch 2>err &&
- test_i18ngrep "fatal: remote error: upload-pack: not our ref" err
+ test_grep "fatal: remote error: upload-pack: not our ref" err
'
test_expect_success 'server is initially ahead - ref in want' '
@@ -530,7 +530,7 @@ test_expect_success 'server loses a ref - ref in want' '
echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
test_must_fail git -C local fetch 2>err &&
- test_i18ngrep "fatal: remote error: unknown ref refs/heads/rain" err
+ test_grep "fatal: remote error: unknown ref refs/heads/rain" err
'
# DO NOT add non-httpd-specific tests here, because the last part of this
diff --git a/t/t5704-protocol-violations.sh b/t/t5704-protocol-violations.sh
index ae1a00afb0..2b33fced23 100755
--- a/t/t5704-protocol-violations.sh
+++ b/t/t5704-protocol-violations.sh
@@ -5,7 +5,6 @@ of these cases it will generally be acceptable for one side to break off
communications if the other side says something unexpected. We are mostly
making sure that we do not segfault or otherwise behave badly.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'extra delim packet in v2 ls-refs args' '
@@ -18,7 +17,7 @@ test_expect_success 'extra delim packet in v2 ls-refs args' '
} >input &&
test_must_fail env GIT_PROTOCOL=version=2 \
git upload-pack . <input 2>err &&
- test_i18ngrep "expected flush after ls-refs arguments" err
+ test_grep "expected flush after ls-refs arguments" err
'
test_expect_success 'extra delim packet in v2 fetch args' '
@@ -31,7 +30,7 @@ test_expect_success 'extra delim packet in v2 fetch args' '
} >input &&
test_must_fail env GIT_PROTOCOL=version=2 \
git upload-pack . <input 2>err &&
- test_i18ngrep "expected flush after fetch arguments" err
+ test_grep "expected flush after fetch arguments" err
'
test_expect_success 'bogus symref in v0 capabilities' '
diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh
index b8a722ec27..ed38c76c29 100755
--- a/t/t5705-session-id-in-capabilities.sh
+++ b/t/t5705-session-id-in-capabilities.sh
@@ -2,7 +2,6 @@
test_description='session ID in capabilities'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
REPO="$(pwd)/repo"
diff --git a/t/t5750-bundle-uri-parse.sh b/t/t5750-bundle-uri-parse.sh
index 81bdf58b94..80a3f83ffb 100755
--- a/t/t5750-bundle-uri-parse.sh
+++ b/t/t5750-bundle-uri-parse.sh
@@ -3,7 +3,6 @@
test_description="Test bundle-uri bundle_uri_parse_line()"
TEST_NO_CREATE_REPO=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'bundle_uri_parse_line() just URIs' '
diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh
index d386076dbd..d21877150e 100755
--- a/t/t5801-remote-helpers.sh
+++ b/t/t5801-remote-helpers.sh
@@ -38,6 +38,29 @@ test_expect_success 'cloning from local repo' '
test_cmp server/file local/file
'
+test_expect_success 'clone with remote.*.vcs config' '
+ GIT_TRACE=$PWD/vcs-clone.trace \
+ git clone --no-local -c remote.origin.vcs=testgit "$PWD/server" vcs-clone &&
+ test_grep remote-testgit vcs-clone.trace
+'
+
+test_expect_success 'fetch with configured remote.*.vcs' '
+ git init vcs-fetch &&
+ git -C vcs-fetch config remote.origin.vcs testgit &&
+ git -C vcs-fetch config remote.origin.url "$PWD/server" &&
+ GIT_TRACE=$PWD/vcs-fetch.trace \
+ git -C vcs-fetch fetch origin &&
+ test_grep remote-testgit vcs-fetch.trace
+'
+
+test_expect_success 'vcs remote with no url' '
+ NOURL_UPSTREAM=$PWD/server &&
+ export NOURL_UPSTREAM &&
+ git init vcs-nourl &&
+ git -C vcs-nourl config remote.origin.vcs nourl &&
+ git -C vcs-nourl fetch origin
+'
+
test_expect_success 'create new commit on remote' '
(cd server &&
echo content >>file &&
@@ -137,7 +160,7 @@ test_expect_success 'forced push' '
test_expect_success 'cloning without refspec' '
GIT_REMOTE_TESTGIT_NOREFSPEC=1 \
git clone "testgit::${PWD}/server" local2 2>error &&
- test_i18ngrep "this remote helper should implement refspec capability" error &&
+ test_grep "this remote helper should implement refspec capability" error &&
compare_refs local2 HEAD server HEAD
'
@@ -145,7 +168,7 @@ test_expect_success 'pulling without refspecs' '
(cd local2 &&
git reset --hard &&
GIT_REMOTE_TESTGIT_NOREFSPEC=1 git pull 2>../error) &&
- test_i18ngrep "this remote helper should implement refspec capability" error &&
+ test_grep "this remote helper should implement refspec capability" error &&
compare_refs local2 HEAD server HEAD
'
@@ -157,7 +180,7 @@ test_expect_success 'pushing without refspecs' '
GIT_REMOTE_TESTGIT_NOREFSPEC=1 &&
export GIT_REMOTE_TESTGIT_NOREFSPEC &&
test_must_fail git push 2>../error) &&
- test_i18ngrep "remote-helper doesn.t support push; refspec needed" error
+ test_grep "remote-helper doesn.t support push; refspec needed" error
'
test_expect_success 'pulling without marks' '
@@ -256,7 +279,7 @@ clean_mark () {
test_expect_success 'proper failure checks for fetching' '
(cd local &&
test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git fetch 2>error &&
- test_i18ngrep -q "error while running fast-import" error
+ test_grep -q "error while running fast-import" error
)
'
@@ -321,4 +344,15 @@ test_expect_success 'fetch tag' '
compare_refs local v1.0 server v1.0
'
+test_expect_success 'totally broken helper reports failure message' '
+ write_script git-remote-broken <<-\EOF &&
+ read cap_cmd
+ exit 1
+ EOF
+ test_must_fail \
+ env PATH="$PWD:$PATH" \
+ git clone broken://example.com/foo.git 2>stderr &&
+ grep aborted stderr
+'
+
test_done
diff --git a/t/t5801/git-remote-nourl b/t/t5801/git-remote-nourl
new file mode 100755
index 0000000000..09be6013c5
--- /dev/null
+++ b/t/t5801/git-remote-nourl
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec git-remote-testgit "$1" "$NOURL_UPSTREAM"
diff --git a/t/t5801/git-remote-testgit b/t/t5801/git-remote-testgit
index 1544d6dc6b..f8b476499f 100755
--- a/t/t5801/git-remote-testgit
+++ b/t/t5801/git-remote-testgit
@@ -12,6 +12,11 @@ url=$2
dir="$GIT_DIR/testgit/$alias"
+if ! git rev-parse --is-inside-git-dir
+then
+ exit 1
+fi
+
h_refspec="refs/heads/*:refs/testgit/$alias/heads/*"
t_refspec="refs/tags/*:refs/testgit/$alias/tags/*"
@@ -21,10 +26,12 @@ then
t_refspec=""
fi
-GIT_DIR="$url/.git"
+unset $(git rev-parse --local-env-vars)
+GIT_DIR=$(git -C "$url" rev-parse --absolute-git-dir)
export GIT_DIR
force=
+object_format=
mkdir -p "$dir"
@@ -56,7 +63,8 @@ do
echo
;;
list)
- echo ":object-format $(git rev-parse --show-object-format=storage)"
+ test -n "$object_format" &&
+ echo ":object-format $(git rev-parse --show-object-format=storage)"
git for-each-ref --format='? %(refname)' 'refs/heads/' 'refs/tags/'
head=$(git symbolic-ref HEAD)
echo "@$head HEAD"
diff --git a/t/t5802-connect-helper.sh b/t/t5802-connect-helper.sh
index c6c2661878..a7be375bce 100755
--- a/t/t5802-connect-helper.sh
+++ b/t/t5802-connect-helper.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='ext::cmd remote "connect" helper'
+
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5810-proto-disable-local.sh b/t/t5810-proto-disable-local.sh
index 862610256f..96a2c46e7a 100755
--- a/t/t5810-proto-disable-local.sh
+++ b/t/t5810-proto-disable-local.sh
@@ -2,7 +2,6 @@
test_description='test disabling of local paths in clone/fetch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
diff --git a/t/t5811-proto-disable-git.sh b/t/t5811-proto-disable-git.sh
index ed773e7432..b0061e6a37 100755
--- a/t/t5811-proto-disable-git.sh
+++ b/t/t5811-proto-disable-git.sh
@@ -2,7 +2,6 @@
test_description='test disabling of git-over-tcp in clone/fetch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
. "$TEST_DIRECTORY/lib-git-daemon.sh"
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
index d8da5f58d1..96187efaa8 100755
--- a/t/t5812-proto-disable-http.sh
+++ b/t/t5812-proto-disable-http.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test disabling of git-over-http in clone/fetch'
+
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
. "$TEST_DIRECTORY/lib-httpd.sh"
@@ -20,7 +21,7 @@ test_expect_success 'http(s) transport respects GIT_ALLOW_PROTOCOL' '
test_must_fail env GIT_ALLOW_PROTOCOL=http:https \
GIT_SMART_HTTP=0 \
git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr &&
- test_i18ngrep -E "(ftp.*disabled|your curl version is too old)" stderr
+ test_grep -E "(ftp.*disabled|your curl version is too old)" stderr
'
test_expect_success 'curl limits redirects' '
diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh
index 2e975dc70e..045e2fe6ce 100755
--- a/t/t5813-proto-disable-ssh.sh
+++ b/t/t5813-proto-disable-ssh.sh
@@ -2,7 +2,6 @@
test_description='test disabling of git-over-ssh in clone/fetch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
diff --git a/t/t5814-proto-disable-ext.sh b/t/t5814-proto-disable-ext.sh
index 9d6f7dfa2c..9587a842bc 100755
--- a/t/t5814-proto-disable-ext.sh
+++ b/t/t5814-proto-disable-ext.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test disabling of remote-helper paths in clone/fetch'
+
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
diff --git a/t/t5815-submodule-protos.sh b/t/t5815-submodule-protos.sh
index 4d5956cc18..081a07cbae 100755
--- a/t/t5815-submodule-protos.sh
+++ b/t/t5815-submodule-protos.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test protocol filtering with submodules'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-proto-disable.sh
diff --git a/t/t5900-repo-selection.sh b/t/t5900-repo-selection.sh
index a84faac242..923fc90f87 100755
--- a/t/t5900-repo-selection.sh
+++ b/t/t5900-repo-selection.sh
@@ -2,7 +2,6 @@
test_description='selecting remote repo in ambiguous cases'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
reset() {
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
index 12def7bcbf..6289a2e8b0 100755
--- a/t/t6000-rev-list-misc.sh
+++ b/t/t6000-rev-list-misc.sh
@@ -169,4 +169,17 @@ test_expect_success 'rev-list --count --objects' '
test_line_count = $count actual
'
+test_expect_success 'rev-list --unpacked' '
+ git repack -ad &&
+ test_commit unpacked &&
+
+ git rev-list --objects --no-object-names unpacked^.. >expect.raw &&
+ sort expect.raw >expect &&
+
+ git rev-list --all --objects --unpacked --no-object-names >actual.raw &&
+ sort actual.raw >actual &&
+
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh
index 16635ecc33..73a2465aa0 100755
--- a/t/t6001-rev-list-graft.sh
+++ b/t/t6001-rev-list-graft.sh
@@ -118,10 +118,10 @@ done
test_expect_success 'show advice that grafts are deprecated' '
git show HEAD 2>err &&
- test_i18ngrep "git replace" err &&
+ test_grep "git replace" err &&
test_config advice.graftFileDeprecated false &&
git show HEAD 2>err &&
- test_i18ngrep ! "git replace" err
+ test_grep ! "git replace" err
'
test_done
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index 162cf50778..b95a0212ad 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -4,7 +4,6 @@
#
test_description='Tests git rev-list --bisect functionality'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 5cf2cee74d..0d7055d46d 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -5,7 +5,6 @@
test_description='Tests git rev-list --topo-order functionality'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
diff --git a/t/t6005-rev-list-count.sh b/t/t6005-rev-list-count.sh
index 0729f800c3..6cde997e13 100755
--- a/t/t6005-rev-list-count.sh
+++ b/t/t6005-rev-list-count.sh
@@ -2,7 +2,6 @@
test_description='git rev-list --max-count and --skip test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -18,20 +17,34 @@ test_expect_success 'no options' '
'
test_expect_success '--max-count' '
+ test_must_fail git rev-list --max-count=1q HEAD 2>error &&
+ grep "not an integer" error &&
+
test_stdout_line_count = 0 git rev-list HEAD --max-count=0 &&
test_stdout_line_count = 3 git rev-list HEAD --max-count=3 &&
test_stdout_line_count = 5 git rev-list HEAD --max-count=5 &&
- test_stdout_line_count = 5 git rev-list HEAD --max-count=10
+ test_stdout_line_count = 5 git rev-list HEAD --max-count=10 &&
+ test_stdout_line_count = 5 git rev-list HEAD --max-count=-1
'
test_expect_success '--max-count all forms' '
+ test_must_fail git rev-list -1q HEAD 2>error &&
+ grep "not an integer" error &&
+ test_must_fail git rev-list --1 HEAD &&
+ test_must_fail git rev-list -n 1q HEAD 2>error &&
+ grep "not an integer" error &&
+
test_stdout_line_count = 1 git rev-list HEAD --max-count=1 &&
test_stdout_line_count = 1 git rev-list HEAD -1 &&
test_stdout_line_count = 1 git rev-list HEAD -n1 &&
- test_stdout_line_count = 1 git rev-list HEAD -n 1
+ test_stdout_line_count = 1 git rev-list HEAD -n 1 &&
+ test_stdout_line_count = 5 git rev-list HEAD -n -1
'
test_expect_success '--skip' '
+ test_must_fail git rev-list --skip 1q HEAD 2>error &&
+ grep "not an integer" error &&
+
test_stdout_line_count = 5 git rev-list HEAD --skip=0 &&
test_stdout_line_count = 2 git rev-list HEAD --skip=3 &&
test_stdout_line_count = 0 git rev-list HEAD --skip=5 &&
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 573eb97a0f..eb93d68d7d 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -12,21 +12,41 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. "$TEST_DIRECTORY"/lib-terminal.sh
test_tick
-# Tested non-UTF-8 encoding
-test_encoding="ISO8859-1"
-
-# String "added" in German
-# (translated with Google Translate),
-# encoded in UTF-8, used as a commit log message below.
-added_utf8_part=$(printf "\303\274")
-added_utf8_part_iso88591=$(echo "$added_utf8_part" | iconv -f utf-8 -t $test_encoding)
-added=$(printf "added (hinzugef${added_utf8_part}gt) foo")
-added_iso88591=$(echo "$added" | iconv -f utf-8 -t $test_encoding)
-# same but "changed"
-changed_utf8_part=$(printf "\303\244")
-changed_utf8_part_iso88591=$(echo "$changed_utf8_part" | iconv -f utf-8 -t $test_encoding)
-changed=$(printf "changed (ge${changed_utf8_part}ndert) foo")
-changed_iso88591=$(echo "$changed" | iconv -f utf-8 -t $test_encoding)
+
+if test_have_prereq ICONV
+then
+ # Tested non-UTF-8 encoding
+ test_encoding="ISO8859-1"
+
+ # String "added" in German
+ # (translated with Google Translate),
+ # encoded in UTF-8, used as a commit log message below.
+ added_utf8_part=$(printf "\303\274")
+ added_utf8_part_iso88591=$(echo "$added_utf8_part" | iconv -f utf-8 -t $test_encoding)
+ added=$(printf "added (hinzugef${added_utf8_part}gt) foo")
+ added_iso88591=$(echo "$added" | iconv -f utf-8 -t $test_encoding)
+ # same but "changed"
+ changed_utf8_part=$(printf "\303\244")
+ changed_utf8_part_iso88591=$(echo "$changed_utf8_part" | iconv -f utf-8 -t $test_encoding)
+ changed=$(printf "changed (ge${changed_utf8_part}ndert) foo")
+ changed_iso88591=$(echo "$changed" | iconv -f utf-8 -t $test_encoding)
+else
+ # Tested non-UTF-8 encoding
+ test_encoding="UTF-8"
+
+ # String "added" in German
+ # (translated with Google Translate),
+ # encoded in UTF-8, used as a commit log message below.
+ added_utf8_part="u"
+ added_utf8_part_iso88591="u"
+ added=$(printf "added (hinzugef${added_utf8_part}gt) foo")
+ added_iso88591="$added"
+ # same but "changed"
+ changed_utf8_part="a"
+ changed_utf8_part_iso88591="a"
+ changed=$(printf "changed (ge${changed_utf8_part}ndert) foo")
+ changed_iso88591="$changed"
+fi
# Count of char to truncate
# Number is chosen so, that non-ACSII characters
@@ -54,7 +74,7 @@ test_expect_success 'setup' '
git config --unset i18n.commitEncoding
'
-# usage: test_format [argument...] name format_string [failure] <expected_output
+# usage: test_format [argument...] name format_string [success|failure] [prereq] <expected_output
test_format () {
local args=
while true
@@ -68,7 +88,7 @@ test_format () {
esac
done
cat >expect.$1
- test_expect_${3:-success} "format $1" "
+ test_expect_${3:-success} $4 "format $1" "
git rev-list $args --pretty=format:'$2' main >output.$1 &&
test_cmp expect.$1 output.$1
"
@@ -197,7 +217,7 @@ Thu, 7 Apr 2005 15:13:13 -0700
1112911993
EOF
-test_format encoding %e <<EOF
+test_format encoding %e success ICONV <<EOF
commit $head2
$test_encoding
commit $head1
@@ -373,7 +393,7 @@ test_expect_success 'setup complex body' '
head3_short=$(git rev-parse --short $head3)
'
-test_format complex-encoding %e <<EOF
+test_format complex-encoding %e success ICONV <<EOF
commit $head3
$test_encoding
commit $head2
diff --git a/t/t6008-rev-list-submodule.sh b/t/t6008-rev-list-submodule.sh
index 2cdef6fdf9..a0a070b404 100755
--- a/t/t6008-rev-list-submodule.sh
+++ b/t/t6008-rev-list-submodule.sh
@@ -8,7 +8,6 @@ test_description='git rev-list involving submodules that this repo has'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh
index 5a67bbc760..9c9a8459af 100755
--- a/t/t6009-rev-list-parent.sh
+++ b/t/t6009-rev-list-parent.sh
@@ -62,6 +62,17 @@ test_expect_success 'setup roots, merges and octopuses' '
git checkout main
'
+test_expect_success 'parse --max-parents & --min-parents' '
+ test_must_fail git rev-list --max-parents=1q HEAD 2>error &&
+ grep "not an integer" error &&
+
+ test_must_fail git rev-list --min-parents=1q HEAD 2>error &&
+ grep "not an integer" error &&
+
+ git rev-list --max-parents=1 --min-parents=1 HEAD &&
+ git rev-list --max-parents=-1 --min-parents=-1 HEAD
+'
+
test_expect_success 'rev-list roots' '
check_revlist "--max-parents=0" one five
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index b2e422cf0f..bad02cf5b8 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -2,7 +2,6 @@
test_description='git rev-list should notice bad commits'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Note:
diff --git a/t/t6014-rev-list-all.sh b/t/t6014-rev-list-all.sh
index 16b8bd1d09..c9bedd29cb 100755
--- a/t/t6014-rev-list-all.sh
+++ b/t/t6014-rev-list-all.sh
@@ -2,7 +2,6 @@
test_description='--all includes detached HEADs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh
index a57f1ae2ba..4821b90e74 100755
--- a/t/t6017-rev-list-stdin.sh
+++ b/t/t6017-rev-list-stdin.sh
@@ -68,6 +68,7 @@ check --glob=refs/heads
check --glob=refs/heads --
check --glob=refs/heads -- file-1
check --end-of-options -dashed-branch
+check --all --not refs/heads/main
test_expect_success 'not only --stdin' '
cat >expect <<-EOF &&
@@ -127,4 +128,24 @@ test_expect_success 'unknown option without --end-of-options' '
test_cmp expect error
'
+test_expect_success '--not on command line does not influence revisions read via --stdin' '
+ cat >input <<-EOF &&
+ refs/heads/main
+ EOF
+ git rev-list refs/heads/main >expect &&
+
+ git rev-list refs/heads/main --not --stdin <input >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--not via stdin does not influence revisions from command line' '
+ cat >input <<-EOF &&
+ --not
+ EOF
+ git rev-list refs/heads/main >expect &&
+
+ git rev-list refs/heads/main --stdin refs/heads/main <input >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh
index 67d523d405..bb55c7e3c3 100755
--- a/t/t6018-rev-list-glob.sh
+++ b/t/t6018-rev-list-glob.sh
@@ -5,7 +5,6 @@ test_description='rev-list/rev-parse --glob'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
commit () {
@@ -214,15 +213,13 @@ do
for pseudoopt in branches tags remotes
do
test_expect_success "rev-parse --exclude-hidden=$section fails with --$pseudoopt" '
- echo "error: --exclude-hidden cannot be used together with --$pseudoopt" >expected &&
test_must_fail git rev-parse --exclude-hidden=$section --$pseudoopt 2>err &&
- test_cmp expected err
+ test_grep "error: options .--exclude-hidden. and .--$pseudoopt. cannot be used together" err
'
test_expect_success "rev-parse --exclude-hidden=$section fails with --$pseudoopt=pattern" '
- echo "error: --exclude-hidden cannot be used together with --$pseudoopt" >expected &&
test_must_fail git rev-parse --exclude-hidden=$section --$pseudoopt=pattern 2>err &&
- test_cmp expected err
+ test_grep "error: options .--exclude-hidden. and .--$pseudoopt. cannot be used together" err
'
done
done
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 3e6bcbf30c..5d444bfe20 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -651,4 +651,36 @@ test_expect_success 'send a bundle to standard output' '
test_cmp expect actual
'
+test_expect_success 'unbundle outside of a repository' '
+ git bundle create some.bundle HEAD &&
+ echo "fatal: Need a repository to unbundle." >expect &&
+ nongit test_must_fail git bundle unbundle "$(pwd)/some.bundle" 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'list-heads outside of a repository' '
+ git bundle create some.bundle HEAD &&
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ EOF
+ nongit git bundle list-heads "$(pwd)/some.bundle" >actual &&
+ test_cmp expect actual
+'
+
+for hash in sha1 sha256
+do
+ test_expect_success "list-heads with bundle using $hash" '
+ test_when_finished "rm -rf hash" &&
+ git init --object-format=$hash hash &&
+ test_commit -C hash initial &&
+ git -C hash bundle create hash.bundle HEAD &&
+
+ cat >expect <<-EOF &&
+ $(git -C hash rev-parse HEAD) HEAD
+ EOF
+ git bundle list-heads hash/hash.bundle >actual &&
+ test_cmp expect actual
+ '
+done
+
test_done
diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh
index 1a9d37e638..5fe942a293 100755
--- a/t/t6021-rev-list-exclude-hidden.sh
+++ b/t/t6021-rev-list-exclude-hidden.sh
@@ -2,7 +2,6 @@
test_description='git rev-list --exclude-hidden test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -151,12 +150,12 @@ do
do
test_expect_success "$section: fails with --$pseudoopt" '
test_must_fail git rev-list --exclude-hidden=$section --$pseudoopt 2>err &&
- test_i18ngrep "error: --exclude-hidden cannot be used together with --$pseudoopt" err
+ test_grep "error: options .--exclude-hidden. and .--$pseudoopt. cannot be used together" err
'
test_expect_success "$section: fails with --$pseudoopt=pattern" '
test_must_fail git rev-list --exclude-hidden=$section --$pseudoopt=pattern 2>err &&
- test_i18ngrep "error: --exclude-hidden cannot be used together with --$pseudoopt" err
+ test_grep "error: options .--exclude-hidden. and .--$pseudoopt. cannot be used together" err
'
done
done
diff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh
new file mode 100755
index 0000000000..7553a9cca2
--- /dev/null
+++ b/t/t6022-rev-list-missing.sh
@@ -0,0 +1,148 @@
+#!/bin/sh
+
+test_description='handling of missing objects in rev-list'
+
+. ./test-lib.sh
+
+# We setup the repository with two commits, this way HEAD is always
+# available and we can hide commit 1.
+test_expect_success 'create repository and alternate directory' '
+ test_commit 1 &&
+ test_commit 2 &&
+ test_commit 3 &&
+ git tag -m "tag message" annot_tag HEAD~1 &&
+ git tag regul_tag HEAD~1 &&
+ git branch a_branch HEAD~1
+'
+
+# We manually corrupt the repository, which means that the commit-graph may
+# contain references to already-deleted objects. We thus need to enable
+# commit-graph paranoia to not returned these deleted commits from the graph.
+GIT_COMMIT_GRAPH_PARANOIA=true
+export GIT_COMMIT_GRAPH_PARANOIA
+
+for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
+do
+ test_expect_success "rev-list --missing=error fails with missing object $obj" '
+ oid="$(git rev-parse $obj)" &&
+ path=".git/objects/$(test_oid_to_path $oid)" &&
+
+ mv "$path" "$path.hidden" &&
+ test_when_finished "mv $path.hidden $path" &&
+
+ test_must_fail git rev-list --missing=error --objects \
+ --no-object-names HEAD
+ '
+done
+
+for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
+do
+ for action in "allow-any" "print"
+ do
+ test_expect_success "rev-list --missing=$action with missing $obj" '
+ oid="$(git rev-parse $obj)" &&
+ path=".git/objects/$(test_oid_to_path $oid)" &&
+
+ # Before the object is made missing, we use rev-list to
+ # get the expected oids.
+ git rev-list --objects --no-object-names \
+ HEAD ^$obj >expect.raw &&
+
+ # Blobs are shared by all commits, so even though a commit/tree
+ # might be skipped, its blob must be accounted for.
+ if test $obj != "HEAD:1.t"
+ then
+ echo $(git rev-parse HEAD:1.t) >>expect.raw &&
+ echo $(git rev-parse HEAD:2.t) >>expect.raw
+ fi &&
+
+ mv "$path" "$path.hidden" &&
+ test_when_finished "mv $path.hidden $path" &&
+
+ git rev-list --missing=$action --objects --no-object-names \
+ HEAD >actual.raw &&
+
+ # When the action is to print, we should also add the missing
+ # oid to the expect list.
+ case $action in
+ allow-any)
+ ;;
+ print)
+ grep ?$oid actual.raw &&
+ echo ?$oid >>expect.raw
+ ;;
+ esac &&
+
+ sort actual.raw >actual &&
+ sort expect.raw >expect &&
+ test_cmp expect actual
+ '
+ done
+done
+
+for missing_tip in "annot_tag" "regul_tag" "a_branch" "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
+do
+ # We want to check that things work when both
+ # - all the tips passed are missing (case existing_tip = ""), and
+ # - there is one missing tip and one existing tip (case existing_tip = "HEAD")
+ for existing_tip in "" "HEAD"
+ do
+ for action in "allow-any" "print"
+ do
+ test_expect_success "--missing=$action with tip '$missing_tip' missing and tip '$existing_tip'" '
+ # Before the object is made missing, we use rev-list to
+ # get the expected oids.
+ if test "$existing_tip" = "HEAD"
+ then
+ git rev-list --objects --no-object-names \
+ HEAD ^$missing_tip >expect.raw
+ else
+ >expect.raw
+ fi &&
+
+ # Blobs are shared by all commits, so even though a commit/tree
+ # might be skipped, its blob must be accounted for.
+ if test "$existing_tip" = "HEAD" && test $missing_tip != "HEAD:1.t"
+ then
+ echo $(git rev-parse HEAD:1.t) >>expect.raw &&
+ echo $(git rev-parse HEAD:2.t) >>expect.raw
+ fi &&
+
+ missing_oid="$(git rev-parse $missing_tip)" &&
+
+ if test "$missing_tip" = "annot_tag"
+ then
+ oid="$(git rev-parse $missing_tip^{commit})" &&
+ echo "$missing_oid" >>expect.raw
+ else
+ oid="$missing_oid"
+ fi &&
+
+ path=".git/objects/$(test_oid_to_path $oid)" &&
+
+ mv "$path" "$path.hidden" &&
+ test_when_finished "mv $path.hidden $path" &&
+
+ git rev-list --missing=$action --objects --no-object-names \
+ $missing_oid $existing_tip >actual.raw &&
+
+ # When the action is to print, we should also add the missing
+ # oid to the expect list.
+ case $action in
+ allow-any)
+ ;;
+ print)
+ grep ?$oid actual.raw &&
+ echo ?$oid >>expect.raw
+ ;;
+ esac &&
+
+ sort actual.raw >actual &&
+ sort expect.raw >expect &&
+ test_cmp expect actual
+ '
+ done
+ done
+done
+
+test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index fb01bd6abc..cdc0270640 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -170,6 +170,12 @@ test_expect_success 'bisect reset when not bisecting' '
cmp branch.expect branch.output
'
+test_expect_success 'bisect reset cleans up even when not bisecting' '
+ echo garbage >.git/BISECT_LOG &&
+ git bisect reset &&
+ test_path_is_missing .git/BISECT_LOG
+'
+
test_expect_success 'bisect reset removes packed refs' '
git bisect reset &&
git bisect start &&
@@ -220,7 +226,7 @@ test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if
cp .git/BISECT_START saved &&
test_must_fail git bisect start $HASH4 foo -- &&
git branch > branch.output &&
- test_i18ngrep "* (no branch, bisect started on other)" branch.output > /dev/null &&
+ test_grep "* (no branch, bisect started on other)" branch.output > /dev/null &&
test_cmp saved .git/BISECT_START
'
test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
@@ -588,7 +594,7 @@ test_expect_success 'bisect starting with a detached HEAD' '
test_expect_success 'bisect errors out if bad and good are mistaken' '
git bisect reset &&
test_must_fail git bisect start $HASH2 $HASH4 2> rev_list_error &&
- test_i18ngrep "mistook good and bad" rev_list_error &&
+ test_grep "mistook good and bad" rev_list_error &&
git bisect reset
'
@@ -630,7 +636,7 @@ test_expect_success 'side branch creation' '
test_expect_success 'good merge base when good and bad are siblings' '
git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log.txt &&
+ test_grep "merge base must be tested" my_bisect_log.txt &&
grep $HASH4 my_bisect_log.txt &&
git bisect good > my_bisect_log.txt &&
! grep "merge base must be tested" my_bisect_log.txt &&
@@ -639,7 +645,7 @@ test_expect_success 'good merge base when good and bad are siblings' '
'
test_expect_success 'skipped merge base when good and bad are siblings' '
git bisect start "$SIDE_HASH7" "$HASH7" > my_bisect_log.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log.txt &&
+ test_grep "merge base must be tested" my_bisect_log.txt &&
grep $HASH4 my_bisect_log.txt &&
git bisect skip > my_bisect_log.txt 2>&1 &&
grep "warning" my_bisect_log.txt &&
@@ -649,11 +655,11 @@ test_expect_success 'skipped merge base when good and bad are siblings' '
test_expect_success 'bad merge base when good and bad are siblings' '
git bisect start "$HASH7" HEAD > my_bisect_log.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log.txt &&
+ test_grep "merge base must be tested" my_bisect_log.txt &&
grep $HASH4 my_bisect_log.txt &&
test_must_fail git bisect bad > my_bisect_log.txt 2>&1 &&
- test_i18ngrep "merge base $HASH4 is bad" my_bisect_log.txt &&
- test_i18ngrep "fixed between $HASH4 and \[$SIDE_HASH7\]" my_bisect_log.txt &&
+ test_grep "merge base $HASH4 is bad" my_bisect_log.txt &&
+ test_grep "fixed between $HASH4 and \[$SIDE_HASH7\]" my_bisect_log.txt &&
git bisect reset
'
@@ -704,9 +710,9 @@ test_expect_success '"git bisect run --first-parent" simple case' '
test_expect_success 'good merge bases when good and bad are siblings' '
git bisect start "$B_HASH" "$A_HASH" > my_bisect_log.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log.txt &&
+ test_grep "merge base must be tested" my_bisect_log.txt &&
git bisect good > my_bisect_log2.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log2.txt &&
+ test_grep "merge base must be tested" my_bisect_log2.txt &&
{
{
grep "$SIDE_HASH5" my_bisect_log.txt &&
@@ -721,14 +727,14 @@ test_expect_success 'good merge bases when good and bad are siblings' '
test_expect_success 'optimized merge base checks' '
git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log.txt &&
+ test_grep "merge base must be tested" my_bisect_log.txt &&
grep "$HASH4" my_bisect_log.txt &&
git bisect good > my_bisect_log2.txt &&
test -f ".git/BISECT_ANCESTORS_OK" &&
test "$HASH6" = $(git rev-parse --verify HEAD) &&
git bisect bad &&
git bisect good "$A_HASH" > my_bisect_log4.txt &&
- test_i18ngrep "merge base must be tested" my_bisect_log4.txt &&
+ test_grep "merge base must be tested" my_bisect_log4.txt &&
test_path_is_missing ".git/BISECT_ANCESTORS_OK"
'
@@ -806,7 +812,7 @@ test_expect_success 'skipping away from skipped commit' '
test_expect_success 'erroring out when using bad path arguments' '
test_must_fail git bisect start $PARA_HASH7 $HASH1 -- foobar 2> error.txt &&
- test_i18ngrep "bad path arguments" error.txt
+ test_grep "bad path arguments" error.txt
'
test_expect_success 'test bisection on bare repo - --no-checkout specified' '
@@ -872,7 +878,7 @@ test_expect_success 'broken branch creation' '
echo "" > expected.ok
cat > expected.missing-tree.default <<EOF
-fatal: unable to read tree $deleted
+fatal: unable to read tree ($deleted)
EOF
test_expect_success 'bisect fails if tree is broken on start commit' '
@@ -1176,7 +1182,7 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
git bisect bad $HASH4 &&
git bisect reset &&
test -z "$(git for-each-ref "refs/bisect/*")" &&
- test_path_is_missing ".git/BISECT_EXPECTED_REV" &&
+ test_ref_missing BISECT_EXPECTED_REV &&
test_path_is_missing ".git/BISECT_ANCESTORS_OK" &&
test_path_is_missing ".git/BISECT_LOG" &&
test_path_is_missing ".git/BISECT_RUN" &&
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 7ddbd96e58..0b719bbae6 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -5,7 +5,6 @@ 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 () {
@@ -83,13 +82,13 @@ test_expect_success 'checkout (diverged from upstream)' '
(
cd test && git checkout b1
) >actual &&
- test_i18ngrep "have 1 and 1 different" actual
+ test_grep "have 1 and 1 different" actual
'
test_expect_success 'checkout with local tracked branch' '
git checkout main &&
git checkout follower >actual &&
- test_i18ngrep "is ahead of" actual
+ test_grep "is ahead of" actual
'
test_expect_success 'checkout (upstream is gone)' '
@@ -97,14 +96,14 @@ test_expect_success 'checkout (upstream is gone)' '
cd test &&
git checkout b5
) >actual &&
- test_i18ngrep "is based on .*, but the upstream is gone." actual
+ test_grep "is based on .*, but the upstream is gone." actual
'
test_expect_success 'checkout (up-to-date with upstream)' '
(
cd test && git checkout b6
) >actual &&
- test_i18ngrep "Your branch is up to date with .origin/main" actual
+ test_grep "Your branch is up to date with .origin/main" actual
'
test_expect_success 'status (diverged from upstream)' '
@@ -114,7 +113,7 @@ test_expect_success 'status (diverged from upstream)' '
# reports nothing to commit
test_must_fail git commit --dry-run
) >actual &&
- test_i18ngrep "have 1 and 1 different" actual
+ test_grep "have 1 and 1 different" actual
'
test_expect_success 'status (upstream is gone)' '
@@ -124,7 +123,7 @@ test_expect_success 'status (upstream is gone)' '
# reports nothing to commit
test_must_fail git commit --dry-run
) >actual &&
- test_i18ngrep "is based on .*, but the upstream is gone." actual
+ test_grep "is based on .*, but the upstream is gone." actual
'
test_expect_success 'status (up-to-date with upstream)' '
@@ -134,7 +133,7 @@ test_expect_success 'status (up-to-date with upstream)' '
# reports nothing to commit
test_must_fail git commit --dry-run
) >actual &&
- test_i18ngrep "Your branch is up to date with .origin/main" actual
+ test_grep "Your branch is up to date with .origin/main" actual
'
cat >expect <<\EOF
@@ -253,7 +252,7 @@ test_expect_success 'fail to track lightweight tags' '
git checkout main &&
git tag light &&
test_must_fail git branch --track lighttrack light >actual &&
- test_i18ngrep ! "set up to track" actual &&
+ test_grep ! "set up to track" actual &&
test_must_fail git checkout lighttrack
'
@@ -261,7 +260,7 @@ test_expect_success 'fail to track annotated tags' '
git checkout main &&
git tag -m heavy heavy &&
test_must_fail git branch --track heavytrack heavy >actual &&
- test_i18ngrep ! "set up to track" actual &&
+ test_grep ! "set up to track" actual &&
test_must_fail git checkout heavytrack
'
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index c9925edf20..aa1b535187 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -44,7 +44,7 @@ commit_peeling_shows_parents ()
_parent_number=$(( $_parent_number + 1 ))
done &&
test_must_fail git rev-parse --verify $_commit^$_parent_number 2>err &&
- test_i18ngrep "Needed a single revision" err
+ test_grep "Needed a single revision" err
}
commit_has_parents ()
@@ -97,30 +97,42 @@ test_expect_success 'set up buggy branch' '
'
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 cat-file commit $HASH2 >actual &&
+ test_grep "author A U Thor" actual &&
+ R=$(sed -e "s/A U/O/" actual | git hash-object -t commit --stdin -w) &&
+ git cat-file commit $R >actual &&
+ test_grep "author O Thor" actual &&
git update-ref refs/replace/$HASH2 $R &&
- git show HEAD~5 | grep "O Thor" &&
- git show $HASH2 | grep "O Thor"
+ git show HEAD~5 >actual &&
+ test_grep "O Thor" actual &&
+ git show $HASH2 >actual &&
+ test_grep "O Thor" actual
'
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 >actual &&
+ test_grep "author O Thor" actual &&
+ git --no-replace-objects cat-file commit $HASH2 >actual &&
+ test_grep "author A U Thor" actual &&
+ git show $HASH2 >actual &&
+ test_grep "O Thor" actual &&
+ git --no-replace-objects show $HASH2 >actual &&
+ test_grep "A U Thor" actual
'
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 >actual &&
+ test_grep "author A U Thor" actual &&
+ GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 >actual &&
+ test_grep "A U Thor" actual
'
test_expect_success 'test core.usereplacerefs config option' '
test_config core.usereplacerefs false &&
- git cat-file commit $HASH2 | grep "author A U Thor" &&
- git show $HASH2 | grep "A U Thor"
+ git cat-file commit $HASH2 >actual &&
+ test_grep "author A U Thor" actual &&
+ git show $HASH2 >actual &&
+ test_grep "A U Thor" actual
'
cat >tag.sig <<EOF
@@ -137,8 +149,8 @@ test_expect_success 'tag replaced commit' '
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_grep "dangling commit $R" fsck_main.out &&
+ test_grep "dangling tag $(git show-ref -s refs/tags/mytag)" fsck_main.out &&
test -z "$(git fsck)"
'
@@ -147,14 +159,18 @@ test_expect_success 'repack, clone and fetch work' '
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 show HEAD~5 >actual &&
+ test_grep "A U Thor" actual &&
+ git show $HASH2 >actual &&
+ test_grep "A U Thor" actual &&
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 show HEAD~5 >actual &&
+ test_grep "O Thor" actual &&
+ git show $HASH2 >actual &&
+ test_grep "O Thor" actual &&
git cat-file commit $R
)
'
@@ -168,13 +184,15 @@ test_expect_success '"git replace" listing and deleting' '
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" &&
+ git show $HASH2 >actual &&
+ test_grep "A U Thor" actual &&
test -z "$(git replace -l)"
'
test_expect_success '"git replace" replacing' '
git replace $HASH2 $R &&
- git show $HASH2 | grep "O Thor" &&
+ git show $HASH2 >actual &&
+ test_grep "O Thor" actual &&
test_must_fail git replace $HASH2 $R &&
git replace -f $HASH2 $R &&
test_must_fail git replace -f &&
@@ -185,7 +203,8 @@ 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" &&
+ git show $HASH2 >actual &&
+ test_grep "O Thor" actual &&
test_must_fail git replace $HASH2 $R &&
git replace -f $HASH2 $R &&
test_must_fail git replace --force &&
@@ -208,10 +227,12 @@ test_expect_success '"git replace" resolves sha1' '
#
test_expect_success 'create parallel branch without the bug' '
git replace -d $HASH2 &&
- git show $HASH2 | grep "A U Thor" &&
+ git show $HASH2 >actual &&
+ test_grep "A U Thor" actual &&
git checkout $HASH1 &&
git cherry-pick $HASH2 &&
- git show $HASH5 | git apply &&
+ git show $HASH5 >actual &&
+ git apply actual &&
git commit --amend -m "hello: 4 more lines WITHOUT the bug" hello &&
PARA2=$(git rev-parse --verify HEAD) &&
git cherry-pick $HASH3 &&
@@ -224,7 +245,8 @@ test_expect_success 'create parallel branch without the bug' '
git checkout main &&
cur=$(git rev-parse --verify HEAD) &&
test "$cur" = "$HASH7" &&
- git log --pretty=oneline | grep $PARA2 &&
+ git log --pretty=oneline >actual &&
+ test_grep $PARA2 actual &&
git remote add cloned ./clone_dir
'
@@ -233,23 +255,30 @@ test_expect_success 'push to cloned repo' '
(
cd clone_dir &&
git checkout parallel &&
- git log --pretty=oneline | grep $PARA2
+ git log --pretty=oneline >actual &&
+ test_grep $PARA2 actual
)
'
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 cat-file commit $PARA3 >actual &&
+ test_grep "author A U Thor" actual &&
+ S=$(sed -e "s/A U/O/" actual | git hash-object -t commit --stdin -w) &&
+ git cat-file commit $S >actual &&
+ test_grep "author O Thor" actual &&
git replace $PARA3 $S &&
- git show $HASH6~2 | grep "O Thor" &&
- git show $PARA3 | grep "O Thor" &&
+ git show $HASH6~2 >actual &&
+ test_grep "O Thor" actual &&
+ git show $PARA3 >actual &&
+ test_grep "O Thor" actual &&
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 log --pretty=oneline >actual &&
+ test_grep $PARA3 actual &&
+ git show $PARA3 >actual &&
+ test_grep "A U Thor" actual
)
'
@@ -259,14 +288,14 @@ test_expect_success 'fetch branch with replacement' '
cd clone_dir &&
git fetch origin refs/heads/tofetch:refs/heads/parallel3 &&
git log --pretty=oneline parallel3 >output.txt &&
- ! grep $PARA3 output.txt &&
+ test_grep ! $PARA3 output.txt &&
git show $PARA3 >para3.txt &&
- grep "A U Thor" para3.txt &&
+ test_grep "A U Thor" para3.txt &&
git fetch origin "refs/replace/*:refs/replace/*" &&
git log --pretty=oneline parallel3 >output.txt &&
- grep $PARA3 output.txt &&
+ test_grep $PARA3 output.txt &&
git show $PARA3 >para3.txt &&
- grep "O Thor" para3.txt
+ test_grep "O Thor" para3.txt
)
'
@@ -283,8 +312,8 @@ test_expect_success 'bisect and replacements' '
'
test_expect_success 'index-pack and replacements' '
- git --no-replace-objects rev-list --objects HEAD |
- git --no-replace-objects pack-objects test- &&
+ git --no-replace-objects rev-list --objects HEAD >actual &&
+ git --no-replace-objects pack-objects test- <actual &&
git index-pack test-*.pack
'
@@ -318,7 +347,8 @@ test_expect_success '-f option bypasses the type check' '
'
test_expect_success 'git cat-file --batch works on replace objects' '
- git replace | grep $PARA3 &&
+ git replace >actual &&
+ test_grep $PARA3 actual &&
echo $PARA3 | git cat-file --batch
'
@@ -343,7 +373,8 @@ test_expect_success 'test --format medium' '
echo "$PARA3 -> $S" &&
echo "$MYTAG -> $HASH1"
} | sort >expected &&
- git replace -l --format medium | sort >actual &&
+ git replace -l --format medium >output &&
+ sort output >actual &&
test_cmp expected actual
'
@@ -355,7 +386,8 @@ test_expect_success 'test --format long' '
echo "$PARA3 (commit) -> $S (commit)" &&
echo "$MYTAG (tag) -> $HASH1 (commit)"
} | sort >expected &&
- git replace --format=long | sort >actual &&
+ git replace --format=long >output &&
+ sort output >actual &&
test_cmp expected actual
'
@@ -373,12 +405,16 @@ test_expect_success 'setup fake editors' '
test_expect_success '--edit with and without already replaced object' '
test_must_fail env GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" &&
GIT_EDITOR=./fakeeditor git replace --force --edit "$PARA3" &&
- git replace -l | grep "$PARA3" &&
- git cat-file commit "$PARA3" | grep "A fake Thor" &&
+ git replace -l >actual &&
+ test_grep "$PARA3" actual &&
+ git cat-file commit "$PARA3" >actual &&
+ test_grep "A fake Thor" actual &&
git replace -d "$PARA3" &&
GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" &&
- git replace -l | grep "$PARA3" &&
- git cat-file commit "$PARA3" | grep "A fake Thor"
+ git replace -l >actual &&
+ test_grep "$PARA3" actual &&
+ git cat-file commit "$PARA3" >actual &&
+ test_grep "A fake Thor" actual
'
test_expect_success '--edit and change nothing or command failed' '
@@ -386,8 +422,10 @@ test_expect_success '--edit and change nothing or command failed' '
test_must_fail env GIT_EDITOR=true git replace --edit "$PARA3" &&
test_must_fail env GIT_EDITOR="./failingfakeeditor" git replace --edit "$PARA3" &&
GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" &&
- git replace -l | grep "$PARA3" &&
- git cat-file commit "$PARA3" | grep "A fake Thor"
+ git replace -l >actual &&
+ test_grep "$PARA3" actual &&
+ git cat-file commit "$PARA3" >actual &&
+ test_grep "A fake Thor" actual
'
test_expect_success 'replace ref cleanup' '
@@ -467,7 +505,8 @@ test_expect_success GPG 'set up a merge commit with a mergetag' '
git checkout main &&
git merge -s ours test_tag &&
HASH10=$(git rev-parse --verify HEAD) &&
- git cat-file commit $HASH10 | grep "^mergetag object"
+ git cat-file commit $HASH10 >actual &&
+ test_grep "^mergetag object" actual
'
test_expect_success GPG '--graft on a commit with a mergetag' '
@@ -490,9 +529,9 @@ test_expect_success '--convert-graft-file' '
$(git rev-parse HEAD^^ HEAD^ HEAD^^ HEAD^2) \
>.git/info/grafts &&
git status 2>stderr &&
- test_i18ngrep "hint:.*grafts is deprecated" stderr &&
+ test_grep "hint:.*grafts is deprecated" stderr &&
git replace --convert-graft-file 2>stderr &&
- test_i18ngrep ! "hint:.*grafts is deprecated" stderr &&
+ test_grep ! "hint:.*grafts is deprecated" stderr &&
test_path_is_missing .git/info/grafts &&
: verify that the history is now "grafted" &&
@@ -503,8 +542,8 @@ test_expect_success '--convert-graft-file' '
test_when_finished "rm -f .git/info/grafts" &&
echo $EMPTY_BLOB $EMPTY_TREE >.git/info/grafts &&
test_must_fail git replace --convert-graft-file 2>err &&
- test_i18ngrep "$EMPTY_BLOB $EMPTY_TREE" err &&
- test_i18ngrep "$EMPTY_BLOB $EMPTY_TREE" .git/info/grafts
+ test_grep "$EMPTY_BLOB $EMPTY_TREE" err &&
+ test_grep "$EMPTY_BLOB $EMPTY_TREE" .git/info/grafts
'
test_done
diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh
index 1a8b64cce1..e6b3e6ec77 100755
--- a/t/t6060-merge-index.sh
+++ b/t/t6060-merge-index.sh
@@ -2,7 +2,6 @@
test_description='basic git merge-index / git-merge-one-file tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup diverging branches' '
diff --git a/t/t6100-rev-list-in-order.sh b/t/t6100-rev-list-in-order.sh
index 88ed7bd75a..e934bc239c 100755
--- a/t/t6100-rev-list-in-order.sh
+++ b/t/t6100-rev-list-in-order.sh
@@ -2,7 +2,6 @@
test_description='rev-list testing in-commit-order'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup a commit history with trees, blobs' '
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
index d20723d627..5f55ab98d3 100755
--- a/t/t6101-rev-parse-parents.sh
+++ b/t/t6101-rev-parse-parents.sh
@@ -8,7 +8,6 @@ test_description='Test git rev-parse with different parent options'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
TEST_CREATE_REPO_NO_TEMPLATE=1
. ./test-lib.sh
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 9350b5fd2c..22dfd6d978 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -2,7 +2,6 @@
test_description='git rev-list should handle unexpected object types'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup well-formed objects' '
@@ -28,7 +27,7 @@ test_expect_success 'TODO (should fail!): traverse unexpected non-blob entry (lo
test_expect_success 'traverse unexpected non-blob entry (seen)' '
test_must_fail git rev-list --objects $tree $broken_tree >output 2>&1 &&
- test_i18ngrep "is not a blob" output
+ test_grep "is not a blob" output
'
test_expect_success 'setup unexpected non-tree entry' '
@@ -42,7 +41,7 @@ test_expect_success 'traverse unexpected non-tree entry (lone)' '
test_expect_success 'traverse unexpected non-tree entry (seen)' '
test_must_fail git rev-list --objects $blob $broken_tree >output 2>&1 &&
- test_i18ngrep "is not a tree" output
+ test_grep "is not a tree" output
'
test_expect_success 'setup unexpected non-commit parent' '
@@ -54,13 +53,13 @@ test_expect_success 'setup unexpected non-commit parent' '
test_expect_success 'traverse unexpected non-commit parent (lone)' '
test_must_fail git rev-list --objects $broken_commit >output 2>&1 &&
- test_i18ngrep "not a commit" output
+ test_grep "not a commit" output
'
test_expect_success 'traverse unexpected non-commit parent (seen)' '
test_must_fail git rev-list --objects $blob $broken_commit \
>output 2>&1 &&
- test_i18ngrep "not a commit" output
+ test_grep "not a commit" output
'
test_expect_success 'setup unexpected non-tree root' '
@@ -76,7 +75,7 @@ test_expect_success 'traverse unexpected non-tree root (lone)' '
test_expect_success 'traverse unexpected non-tree root (seen)' '
test_must_fail git rev-list --objects $blob $broken_commit \
>output 2>&1 &&
- test_i18ngrep "not a tree" output
+ test_grep "not a tree" output
'
test_expect_success 'setup unexpected non-commit tag' '
@@ -93,7 +92,7 @@ test_expect_success 'traverse unexpected non-commit tag (lone)' '
test_expect_success 'traverse unexpected non-commit tag (seen)' '
test_must_fail git rev-list --objects $blob $tag >output 2>&1 &&
- test_i18ngrep "not a commit" output
+ test_grep "not a commit" output
'
test_expect_success 'setup unexpected non-tree tag' '
@@ -110,7 +109,7 @@ test_expect_success 'traverse unexpected non-tree tag (lone)' '
test_expect_success 'traverse unexpected non-tree tag (seen)' '
test_must_fail git rev-list --objects $blob $tag >output 2>&1 &&
- test_i18ngrep "not a tree" output
+ test_grep "not a tree" output
'
test_expect_success 'setup unexpected non-blob tag' '
@@ -127,7 +126,7 @@ test_expect_success 'traverse unexpected non-blob tag (lone)' '
test_expect_success 'traverse unexpected non-blob tag (seen)' '
test_must_fail git rev-list --objects $commit $tag >output 2>&1 &&
- test_i18ngrep "not a blob" output
+ test_grep "not a blob" output
'
test_done
diff --git a/t/t6110-rev-list-sparse.sh b/t/t6110-rev-list-sparse.sh
index ddefc7f24e..13c1da5352 100755
--- a/t/t6110-rev-list-sparse.sh
+++ b/t/t6110-rev-list-sparse.sh
@@ -4,7 +4,6 @@ test_description='operations that cull histories in unusual ways'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh
index 8d9d6604f0..0387f35a32 100755
--- a/t/t6112-rev-list-filters-objects.sh
+++ b/t/t6112-rev-list-filters-objects.sh
@@ -457,7 +457,7 @@ expect_invalid_filter_spec () {
test_must_fail git -C r3 rev-list --objects --filter="$spec" HEAD \
>actual 2>actual_stderr &&
test_must_be_empty actual &&
- test_i18ngrep "$err" actual_stderr
+ test_grep "$err" actual_stderr
}
test_expect_success 'combine:... while URL-encoding things that should not be' '
@@ -670,7 +670,7 @@ test_expect_success 'rev-list W/ --missing=print' '
awk -f print_2.awk ls_files_result |
sort >expected &&
- for id in `cat expected | sed "s|..|&/|"`
+ for id in `sed "s|..|&/|" expected`
do
rm r1/.git/objects/$id || return 1
done &&
@@ -701,4 +701,16 @@ test_expect_success 'expand blob limit in protocol' '
grep "blob:limit=1024" trace
'
+test_expect_success EXPENSIVE 'large sparse filter file ignored' '
+ blob=$(dd if=/dev/zero bs=101M count=1 |
+ git hash-object -w --stdin) &&
+ test_must_fail \
+ git rev-list --all --objects --filter=sparse:oid=$blob 2>err &&
+ cat >expect <<-EOF &&
+ warning: ignoring excessively large pattern blob: $blob
+ fatal: unable to parse sparse filter data in $blob
+ EOF
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t6113-rev-list-bitmap-filters.sh b/t/t6113-rev-list-bitmap-filters.sh
index 4d8e09167e..902854cbfa 100755
--- a/t/t6113-rev-list-bitmap-filters.sh
+++ b/t/t6113-rev-list-bitmap-filters.sh
@@ -1,9 +1,11 @@
#!/bin/sh
test_description='rev-list combining bitmaps and filters'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bitmap.sh
+
test_expect_success 'set up bitmapped repo' '
# one commit will have bitmaps, the other will not
test_commit one &&
@@ -141,4 +143,17 @@ test_expect_success 'combine filter with --filter-provided-objects' '
done <objects
'
+test_expect_success 'bitmap traversal with --unpacked' '
+ git repack -adb &&
+ test_commit unpacked &&
+
+ git rev-list --objects --no-object-names unpacked^.. >expect.raw &&
+ sort expect.raw >expect &&
+
+ git rev-list --use-bitmap-index --objects --all --unpacked >actual.raw &&
+ sort actual.raw >actual &&
+
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6114-keep-packs.sh b/t/t6114-keep-packs.sh
index 44246f8a63..a584522ef2 100755
--- a/t/t6114-keep-packs.sh
+++ b/t/t6114-keep-packs.sh
@@ -2,7 +2,6 @@
test_description='rev-list with .keep packs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index d59111dede..3385fe9f13 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='basic tests of rev-list --disk-usage'
+
. ./test-lib.sh
# we want a mix of reachable and unreachable, as well as
@@ -48,6 +49,13 @@ check_du HEAD
check_du --objects HEAD
check_du --objects HEAD^..HEAD
+test_expect_success 'setup for --unpacked tests' '
+ git repack -adb &&
+ test_commit unpacked
+'
+
+check_du --all --objects --unpacked
+
# As mentioned above, don't use hardcode sizes as actual size, but use the
# output from git cat-file.
test_expect_success 'rev-list --disk-usage=human' '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 0a5c487540..79e0f19deb 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -392,7 +392,7 @@ test_expect_success 'describe directly tagged blob' '
test_expect_success 'describe tag object' '
git tag test-blob-1 -a -m msg unique-file:file &&
test_must_fail git describe test-blob-1 2>actual &&
- test_i18ngrep "fatal: test-blob-1 is neither a commit nor blob" actual
+ test_grep "fatal: test-blob-1 is neither a commit nor blob" actual
'
test_expect_success ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
@@ -671,4 +671,40 @@ test_expect_success 'setup misleading taggerdates' '
check_describe newer-tag-older-commit~1 --contains unique-file~2
+test_expect_success 'describe --dirty with a file with changed stat' '
+ test_when_finished "rm -fr stat-dirty" &&
+ git init stat-dirty &&
+ (
+ cd stat-dirty &&
+
+ echo A >file &&
+ git add file &&
+ git commit -m A &&
+ git tag A -a -m A &&
+ echo "A" >expect &&
+
+ test-tool chmtime -10 file &&
+ git describe --dirty >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'describe --broken --dirty with a file with changed stat' '
+ test_when_finished "rm -fr stat-dirty" &&
+ git init stat-dirty &&
+ (
+ cd stat-dirty &&
+
+ echo A >file &&
+ git add file &&
+ git commit -m A &&
+ git tag A -a -m A &&
+ echo "A" >expect &&
+
+ test-tool chmtime -10 file &&
+ git describe --dirty --broken >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh
index ba7902c9cd..a7f2603cb4 100755
--- a/t/t6130-pathspec-noglob.sh
+++ b/t/t6130-pathspec-noglob.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test globbing (and noglob) of pathspec limiting'
+
. ./test-lib.sh
test_expect_success 'create commits with glob characters' '
diff --git a/t/t6131-pathspec-icase.sh b/t/t6131-pathspec-icase.sh
index 770cce026c..e64d938083 100755
--- a/t/t6131-pathspec-icase.sh
+++ b/t/t6131-pathspec-icase.sh
@@ -2,7 +2,6 @@
test_description='test case insensitive pathspec limiting'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
if test_have_prereq CASE_INSENSITIVE_FS
diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh
index a290ffca0d..0f722fb340 100755
--- a/t/t6133-pathspec-rev-dwim.sh
+++ b/t/t6133-pathspec-rev-dwim.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test dwim of revs versus pathspecs in revision parser'
+
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t6134-pathspec-in-submodule.sh b/t/t6134-pathspec-in-submodule.sh
index 3214d9db97..9b62a0a65f 100755
--- a/t/t6134-pathspec-in-submodule.sh
+++ b/t/t6134-pathspec-in-submodule.sh
@@ -2,7 +2,6 @@
test_description='test case exclude pathspec'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup a submodule' '
@@ -27,7 +26,7 @@ test_expect_success 'error message for path inside submodule' '
test_expect_success 'error message for path inside submodule from within submodule' '
test_must_fail git -C sub add . 2>actual &&
- test_i18ngrep "in unpopulated submodule" actual
+ test_grep "in unpopulated submodule" actual
'
test_done
diff --git a/t/t6135-pathspec-with-attrs.sh b/t/t6135-pathspec-with-attrs.sh
index f70c395e75..67d8c72147 100755
--- a/t/t6135-pathspec-with-attrs.sh
+++ b/t/t6135-pathspec-with-attrs.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test labels in pathspecs'
+
. ./test-lib.sh
test_expect_success 'setup a tree' '
@@ -64,12 +65,24 @@ test_expect_success 'setup .gitattributes' '
fileSetLabel label
fileValue label=foo
fileWrongLabel label☺
+ newFileA* labelA
+ newFileB* labelB
EOF
echo fileSetLabel label1 >sub/.gitattributes &&
git add .gitattributes sub/.gitattributes &&
git commit -m "add attributes"
'
+test_expect_success 'setup .gitignore' '
+ cat <<-\EOF >.gitignore &&
+ actual
+ expect
+ pathspec_file
+ EOF
+ git add .gitignore &&
+ git commit -m "add gitignore"
+'
+
test_expect_success 'check specific set attr' '
cat <<-\EOF >expect &&
fileSetLabel
@@ -150,6 +163,7 @@ test_expect_success 'check specific value attr (2)' '
test_expect_success 'check unspecified attr' '
cat <<-\EOF >expect &&
.gitattributes
+ .gitignore
fileA
fileAB
fileAC
@@ -175,6 +189,7 @@ test_expect_success 'check unspecified attr' '
test_expect_success 'check unspecified attr (2)' '
cat <<-\EOF >expect &&
HEAD:.gitattributes
+ HEAD:.gitignore
HEAD:fileA
HEAD:fileAB
HEAD:fileAC
@@ -200,6 +215,7 @@ test_expect_success 'check unspecified attr (2)' '
test_expect_success 'check multiple unspecified attr' '
cat <<-\EOF >expect &&
.gitattributes
+ .gitignore
fileC
fileNoLabel
fileWrongLabel
@@ -236,17 +252,100 @@ test_expect_success 'check label excluding other labels' '
test_expect_success 'fail on multiple attr specifiers in one pathspec item' '
test_must_fail git ls-files . ":(attr:labelB,attr:labelC)" 2>actual &&
- test_i18ngrep "Only one" actual
+ test_grep "Only one" actual
'
-test_expect_success 'fail if attr magic is used places not implemented' '
+test_expect_success 'fail if attr magic is used in places not implemented' '
# The main purpose of this test is to check that we actually fail
# when you attempt to use attr magic in commands that do not implement
- # attr magic. This test does not advocate git-add to stay that way,
- # though, but git-add is convenient as it has its own internal pathspec
- # parsing.
- test_must_fail git add ":(attr:labelB)" 2>actual &&
- test_i18ngrep "magic not supported" actual
+ # attr magic. This test does not advocate check-ignore to stay that way.
+ # When you teach the command to grok the pathspec, you need to find
+ # another command to replace it for the test.
+ test_must_fail git check-ignore ":(attr:labelB)" 2>actual &&
+ test_grep "magic not supported" actual
+'
+
+test_expect_success 'check that attr magic works for git stash push' '
+ cat <<-\EOF >expect &&
+ A sub/newFileA-foo
+ EOF
+ >sub/newFileA-foo &&
+ >sub/newFileB-foo &&
+ git stash push --include-untracked -- ":(exclude,attr:labelB)" &&
+ git stash show --include-untracked --name-status >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check that attr magic works for git add --all' '
+ cat <<-\EOF >expect &&
+ sub/newFileA-foo
+ EOF
+ >sub/newFileA-foo &&
+ >sub/newFileB-foo &&
+ git add --all ":(exclude,attr:labelB)" &&
+ git diff --name-only --cached >actual &&
+ git restore -W -S . &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check that attr magic works for git add -u' '
+ cat <<-\EOF >expect &&
+ sub/fileA
+ EOF
+ >sub/newFileA-foo &&
+ >sub/newFileB-foo &&
+ >sub/fileA &&
+ >sub/fileB &&
+ git add -u ":(exclude,attr:labelB)" &&
+ git diff --name-only --cached >actual &&
+ git restore -S -W . && rm sub/new* &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check that attr magic works for git add <path>' '
+ cat <<-\EOF >expect &&
+ fileA
+ fileB
+ sub/fileA
+ EOF
+ >fileA &&
+ >fileB &&
+ >sub/fileA &&
+ >sub/fileB &&
+ git add ":(exclude,attr:labelB)sub/*" &&
+ git diff --name-only --cached >actual &&
+ git restore -S -W . &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check that attr magic works for git -add .' '
+ cat <<-\EOF >expect &&
+ sub/fileA
+ EOF
+ >fileA &&
+ >fileB &&
+ >sub/fileA &&
+ >sub/fileB &&
+ cd sub &&
+ git add . ":(exclude,attr:labelB)" &&
+ cd .. &&
+ git diff --name-only --cached >actual &&
+ git restore -S -W . &&
+ test_cmp expect actual
+'
+
+test_expect_success 'check that attr magic works for git add --pathspec-from-file' '
+ cat <<-\EOF >pathspec_file &&
+ :(exclude,attr:labelB)
+ EOF
+ cat <<-\EOF >expect &&
+ sub/newFileA-foo
+ EOF
+ >sub/newFileA-foo &&
+ >sub/newFileB-foo &&
+ git add --all --pathspec-from-file=pathspec_file &&
+ git diff --name-only --cached >actual &&
+ test_cmp expect actual
'
test_expect_success 'abort on giving invalid label on the command line' '
@@ -269,12 +368,12 @@ test_expect_success 'check attribute list' '
test_expect_success 'backslash cannot be the last character' '
test_must_fail git ls-files ":(attr:label=foo\\ labelA=bar)" 2>actual &&
- test_i18ngrep "not allowed as last character in attr value" actual
+ test_grep "not allowed as last character in attr value" actual
'
test_expect_success 'backslash cannot be used as a value' '
test_must_fail git ls-files ":(attr:label=f\\\oo)" 2>actual &&
- test_i18ngrep "for value matching" actual
+ test_grep "for value matching" actual
'
test_expect_success 'reading from .gitattributes in a subdirectory (1)' '
@@ -295,4 +394,31 @@ test_expect_success 'reading from .gitattributes in a subdirectory (3)' '
test_cmp expect actual
'
+test_expect_success POSIXPERM 'pathspec with builtin_objectmode attr can be used' '
+ >mode_exec_file_1 &&
+
+ git status -s ":(attr:builtin_objectmode=100644)mode_exec_*" >actual &&
+ echo ?? mode_exec_file_1 >expect &&
+ test_cmp expect actual &&
+
+ git add mode_exec_file_1 &&
+ chmod +x mode_exec_file_1 &&
+ git status -s ":(attr:builtin_objectmode=100755)mode_exec_*" >actual &&
+ echo AM mode_exec_file_1 >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success POSIXPERM 'builtin_objectmode attr can be excluded' '
+ >mode_1_regular &&
+ >mode_1_exec &&
+ chmod +x mode_1_exec &&
+ git status -s ":(exclude,attr:builtin_objectmode=100644)" "mode_1_*" >actual &&
+ echo ?? mode_1_exec >expect &&
+ test_cmp expect actual &&
+
+ git status -s ":(exclude,attr:builtin_objectmode=100755)" "mode_1_*" >actual &&
+ echo ?? mode_1_regular >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6136-pathspec-in-bare.sh b/t/t6136-pathspec-in-bare.sh
index ae8b5379e2..1284fe0143 100755
--- a/t/t6136-pathspec-in-bare.sh
+++ b/t/t6136-pathspec-in-bare.sh
@@ -2,7 +2,6 @@
test_description='diagnosing out-of-scope pathspec'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup a bare and non-bare repository' '
@@ -15,11 +14,11 @@ test_expect_success 'log and ls-files in a bare repository' '
cd bare &&
test_must_fail git log -- .. >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "outside repository" err &&
+ test_grep "outside repository" err &&
test_must_fail git ls-files -- .. >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "outside repository" err
+ test_grep "outside repository" err
)
'
@@ -28,11 +27,11 @@ test_expect_success 'log and ls-files in .git directory' '
cd .git &&
test_must_fail git log -- .. >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "outside repository" err &&
+ test_grep "outside repository" err &&
test_must_fail git ls-files -- .. >out 2>err &&
test_must_be_empty out &&
- test_i18ngrep "outside repository" err
+ test_grep "outside repository" err
)
'
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 5a221f8ef1..011e5df1e6 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -607,34 +607,34 @@ test_expect_success 'merge-msg with "merging" an annotated tag' '
git checkout main^0 &&
git commit --allow-empty -m "One step ahead" &&
- git tag -a -m "An annotated one" annote HEAD &&
+ git tag -a -m "An annotated one" annotate HEAD &&
git checkout main &&
- git fetch . annote &&
+ git fetch . annotate &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
{
cat <<-\EOF
- Merge tag '\''annote'\''
+ Merge tag '\''annotate'\''
An annotated one
- * tag '\''annote'\'':
+ * tag '\''annotate'\'':
One step ahead
EOF
} >expected &&
test_cmp expected actual &&
test_when_finished "git reset --hard" &&
- annote=$(git rev-parse annote) &&
- git merge --no-commit --no-ff $annote &&
+ annotate=$(git rev-parse annotate) &&
+ git merge --no-commit --no-ff $annotate &&
{
cat <<-EOF
- Merge tag '\''$annote'\''
+ Merge tag '\''$annotate'\''
An annotated one
- * tag '\''$annote'\'':
+ * tag '\''$annotate'\'':
One step ahead
EOF
} >expected &&
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 7b943fd34c..a5c7794385 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -20,11 +20,19 @@ setdate_and_increment () {
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
+test_object_file_size () {
+ oid=$(git rev-parse "$1")
+ path=".git/objects/$(test_oid_to_path $oid)"
+ test_file_size "$path"
+}
+
test_expect_success setup '
- test_oid_cache <<-EOF &&
- disklen sha1:138
- disklen sha256:154
+ # setup .mailmap
+ cat >.mailmap <<-EOF &&
+ A Thor <athor@example.com> A U Thor <author@example.com>
+ C Mitter <cmitter@example.com> C O Mitter <committer@example.com>
EOF
+
setdate_and_increment &&
echo "Using $datestamp" > one &&
git add one &&
@@ -41,25 +49,29 @@ test_expect_success setup '
git config push.default current
'
-test_atom() {
+test_atom () {
case "$1" in
head) ref=refs/heads/main ;;
tag) ref=refs/tags/testtag ;;
sym) ref=refs/heads/sym ;;
*) ref=$1 ;;
esac
+ format=$2
+ test_do=test_expect_${4:-success}
+
printf '%s\n' "$3" >expected
- test_expect_${4:-success} $PREREQ "basic atom: $1 $2" "
- git for-each-ref --format='%($2)' $ref >actual &&
+ $test_do $PREREQ "basic atom: $ref $format" '
+ git for-each-ref --format="%($format)" "$ref" >actual &&
sanitize_pgp <actual >actual.clean &&
test_cmp expected actual.clean
- "
+ '
+
# Automatically test "contents:size" atom after testing "contents"
- if test "$2" = "contents"
+ if test "$format" = "contents"
then
# for commit leg, $3 is changed there
expect=$(printf '%s' "$3" | wc -c)
- test_expect_${4:-success} $PREREQ "basic atom: $1 contents:size" '
+ $test_do $PREREQ "basic atom: $ref contents:size" '
type=$(git cat-file -t "$ref") &&
case $type in
tag)
@@ -83,7 +95,6 @@ test_atom() {
}
hexlen=$(test_oid hexsz)
-disklen=$(test_oid disklen)
test_atom head refname refs/heads/main
test_atom head refname: refs/heads/main
@@ -118,7 +129,7 @@ test_atom head push:strip=1 remotes/myfork/main
test_atom head push:strip=-1 main
test_atom head objecttype commit
test_atom head objectsize $((131 + hexlen))
-test_atom head objectsize:disk $disklen
+test_atom head objectsize:disk $(test_object_file_size refs/heads/main)
test_atom head deltabase $ZERO_OID
test_atom head objectname $(git rev-parse refs/heads/main)
test_atom head objectname:short $(git rev-parse --short refs/heads/main)
@@ -141,15 +152,31 @@ test_atom head '*objectname' ''
test_atom head '*objecttype' ''
test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
test_atom head authorname 'A U Thor'
+test_atom head authorname:mailmap 'A Thor'
test_atom head authoremail '<author@example.com>'
test_atom head authoremail:trim 'author@example.com'
test_atom head authoremail:localpart 'author'
+test_atom head authoremail:trim,localpart 'author'
+test_atom head authoremail:mailmap '<athor@example.com>'
+test_atom head authoremail:mailmap,trim 'athor@example.com'
+test_atom head authoremail:trim,mailmap 'athor@example.com'
+test_atom head authoremail:mailmap,localpart 'athor'
+test_atom head authoremail:localpart,mailmap 'athor'
+test_atom head authoremail:mailmap,trim,localpart,mailmap,trim 'athor'
test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'
test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'
test_atom head committername 'C O Mitter'
+test_atom head committername:mailmap 'C Mitter'
test_atom head committeremail '<committer@example.com>'
test_atom head committeremail:trim 'committer@example.com'
test_atom head committeremail:localpart 'committer'
+test_atom head committeremail:localpart,trim 'committer'
+test_atom head committeremail:mailmap '<cmitter@example.com>'
+test_atom head committeremail:mailmap,trim 'cmitter@example.com'
+test_atom head committeremail:trim,mailmap 'cmitter@example.com'
+test_atom head committeremail:mailmap,localpart 'cmitter'
+test_atom head committeremail:localpart,mailmap 'cmitter'
+test_atom head committeremail:trim,mailmap,trim,trim,localpart 'cmitter'
test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'
test_atom head tag ''
test_atom head tagger ''
@@ -176,8 +203,8 @@ test_atom tag upstream ''
test_atom tag push ''
test_atom tag objecttype tag
test_atom tag objectsize $((114 + hexlen))
-test_atom tag objectsize:disk $disklen
-test_atom tag '*objectsize:disk' $disklen
+test_atom tag objectsize:disk $(test_object_file_size refs/tags/testtag)
+test_atom tag '*objectsize:disk' $(test_object_file_size refs/heads/main)
test_atom tag deltabase $ZERO_OID
test_atom tag '*deltabase' $ZERO_OID
test_atom tag objectname $(git rev-parse refs/tags/testtag)
@@ -199,22 +226,46 @@ test_atom tag '*objectname' $(git rev-parse refs/tags/testtag^{})
test_atom tag '*objecttype' 'commit'
test_atom tag author ''
test_atom tag authorname ''
+test_atom tag authorname:mailmap ''
test_atom tag authoremail ''
test_atom tag authoremail:trim ''
test_atom tag authoremail:localpart ''
+test_atom tag authoremail:trim,localpart ''
+test_atom tag authoremail:mailmap ''
+test_atom tag authoremail:mailmap,trim ''
+test_atom tag authoremail:trim,mailmap ''
+test_atom tag authoremail:mailmap,localpart ''
+test_atom tag authoremail:localpart,mailmap ''
+test_atom tag authoremail:mailmap,trim,localpart,mailmap,trim ''
test_atom tag authordate ''
test_atom tag committer ''
test_atom tag committername ''
+test_atom tag committername:mailmap ''
test_atom tag committeremail ''
test_atom tag committeremail:trim ''
test_atom tag committeremail:localpart ''
+test_atom tag committeremail:localpart,trim ''
+test_atom tag committeremail:mailmap ''
+test_atom tag committeremail:mailmap,trim ''
+test_atom tag committeremail:trim,mailmap ''
+test_atom tag committeremail:mailmap,localpart ''
+test_atom tag committeremail:localpart,mailmap ''
+test_atom tag committeremail:trim,mailmap,trim,trim,localpart ''
test_atom tag committerdate ''
test_atom tag tag 'testtag'
test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'
test_atom tag taggername 'C O Mitter'
+test_atom tag taggername:mailmap 'C Mitter'
test_atom tag taggeremail '<committer@example.com>'
test_atom tag taggeremail:trim 'committer@example.com'
test_atom tag taggeremail:localpart 'committer'
+test_atom tag taggeremail:trim,localpart 'committer'
+test_atom tag taggeremail:mailmap '<cmitter@example.com>'
+test_atom tag taggeremail:mailmap,trim 'cmitter@example.com'
+test_atom tag taggeremail:trim,mailmap 'cmitter@example.com'
+test_atom tag taggeremail:mailmap,localpart 'cmitter'
+test_atom tag taggeremail:localpart,mailmap 'cmitter'
+test_atom tag taggeremail:trim,mailmap,trim,localpart,localpart 'cmitter'
test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'
test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'
test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'
@@ -267,6 +318,66 @@ test_expect_success 'arguments to %(objectname:short=) must be positive integers
test_must_fail git for-each-ref --format="%(objectname:short=foo)"
'
+test_bad_atom () {
+ case "$1" in
+ head) ref=refs/heads/main ;;
+ tag) ref=refs/tags/testtag ;;
+ sym) ref=refs/heads/sym ;;
+ *) ref=$1 ;;
+ esac
+ format=$2
+ test_do=test_expect_${4:-success}
+
+ printf '%s\n' "$3" >expect
+ $test_do $PREREQ "err basic atom: $ref $format" '
+ test_must_fail git for-each-ref \
+ --format="%($format)" "$ref" 2>error &&
+ test_cmp expect error
+ '
+}
+
+test_bad_atom head 'authoremail:foo' \
+ 'fatal: unrecognized %(authoremail) argument: foo'
+
+test_bad_atom head 'authoremail:mailmap,trim,bar' \
+ 'fatal: unrecognized %(authoremail) argument: bar'
+
+test_bad_atom head 'authoremail:trim,' \
+ 'fatal: unrecognized %(authoremail) argument: '
+
+test_bad_atom head 'authoremail:mailmaptrim' \
+ 'fatal: unrecognized %(authoremail) argument: trim'
+
+test_bad_atom head 'committeremail: ' \
+ 'fatal: unrecognized %(committeremail) argument: '
+
+test_bad_atom head 'committeremail: trim,foo' \
+ 'fatal: unrecognized %(committeremail) argument: trim,foo'
+
+test_bad_atom head 'committeremail:mailmap,localpart ' \
+ 'fatal: unrecognized %(committeremail) argument: '
+
+test_bad_atom head 'committeremail:trim_localpart' \
+ 'fatal: unrecognized %(committeremail) argument: _localpart'
+
+test_bad_atom head 'committeremail:localpart,,,trim' \
+ 'fatal: unrecognized %(committeremail) argument: ,,trim'
+
+test_bad_atom tag 'taggeremail:mailmap,trim, foo ' \
+ 'fatal: unrecognized %(taggeremail) argument: foo '
+
+test_bad_atom tag 'taggeremail:trim,localpart,' \
+ 'fatal: unrecognized %(taggeremail) argument: '
+
+test_bad_atom tag 'taggeremail:mailmap;localpart trim' \
+ 'fatal: unrecognized %(taggeremail) argument: ;localpart trim'
+
+test_bad_atom tag 'taggeremail:localpart trim' \
+ 'fatal: unrecognized %(taggeremail) argument: trim'
+
+test_bad_atom tag 'taggeremail:mailmap,mailmap,trim,qux,localpart,trim' \
+ 'fatal: unrecognized %(taggeremail) argument: qux,localpart,trim'
+
test_date () {
f=$1 &&
committer_date=$2 &&
@@ -658,7 +769,7 @@ test_expect_success 'describe:abbrev=... vs describe --abbrev=...' '
refs/heads/master >actual &&
test_cmp expect actual &&
- # Make sure the hash used is atleast 14 digits long
+ # Make sure the hash used is at least 14 digits long
sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
test 15 -le $(wc -c <hexpart) &&
@@ -1224,6 +1335,73 @@ test_expect_success '--no-sort cancels the previous sort keys' '
test_cmp expected actual
'
+test_expect_success '--no-sort without subsequent --sort prints expected refs' '
+ cat >expected <<-\EOF &&
+ refs/tags/multi-ref1-100000-user1
+ refs/tags/multi-ref1-100000-user2
+ refs/tags/multi-ref1-200000-user1
+ refs/tags/multi-ref1-200000-user2
+ refs/tags/multi-ref2-100000-user1
+ refs/tags/multi-ref2-100000-user2
+ refs/tags/multi-ref2-200000-user1
+ refs/tags/multi-ref2-200000-user2
+ EOF
+
+ # Sort the results with `sort` for a consistent comparison against
+ # expected
+ git for-each-ref \
+ --format="%(refname)" \
+ --no-sort \
+ "refs/tags/multi-*" | sort >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'set up custom date sorting' '
+ # Dates:
+ # - Wed Feb 07 2024 21:34:20 +0000
+ # - Tue Dec 14 1999 00:05:22 +0000
+ # - Fri Jun 04 2021 11:26:51 +0000
+ # - Mon Jan 22 2007 16:44:01 GMT+0000
+ i=1 &&
+ for when in 1707341660 945129922 1622806011 1169484241
+ do
+ GIT_COMMITTER_DATE="@$when +0000" \
+ GIT_COMMITTER_EMAIL="user@example.com" \
+ git tag -m "tag $when" custom-dates-$i &&
+ i=$(($i+1)) || return 1
+ done
+'
+
+test_expect_success 'sort by date defaults to full timestamp' '
+ cat >expected <<-\EOF &&
+ 945129922 refs/tags/custom-dates-2
+ 1169484241 refs/tags/custom-dates-4
+ 1622806011 refs/tags/custom-dates-3
+ 1707341660 refs/tags/custom-dates-1
+ EOF
+
+ git for-each-ref \
+ --format="%(creatordate:unix) %(refname)" \
+ --sort=creatordate \
+ "refs/tags/custom-dates-*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'sort by custom date format' '
+ cat >expected <<-\EOF &&
+ 00:05:22 refs/tags/custom-dates-2
+ 11:26:51 refs/tags/custom-dates-3
+ 16:44:01 refs/tags/custom-dates-4
+ 21:34:20 refs/tags/custom-dates-1
+ EOF
+
+ git for-each-ref \
+ --format="%(creatordate:format:%H:%M:%S) %(refname)" \
+ --sort="creatordate:format:%H:%M:%S" \
+ "refs/tags/custom-dates-*" >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
test_when_finished "git checkout main" &&
git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
@@ -1382,6 +1560,25 @@ test_trailer_option '%(trailers:separator,key_value_separator) changes both sepa
Reviewed-by,A U Thor <author@example.com>,Signed-off-by,A U Thor <author@example.com>
EOF
+test_expect_success 'multiple %(trailers) use their own options' '
+ git tag -F - tag-with-trailers <<-\EOF &&
+ body
+
+ one: foo
+ one: bar
+ two: baz
+ two: qux
+ EOF
+ t1="%(trailers:key=one,key_value_separator=W,separator=X)" &&
+ t2="%(trailers:key=two,key_value_separator=Y,separator=Z)" &&
+ git for-each-ref --format="$t1%0a$t2" refs/tags/tag-with-trailers >actual &&
+ cat >expect <<-\EOF &&
+ oneWfooXoneWbar
+ twoYbazZtwoYqux
+ EOF
+ test_cmp expect actual
+'
+
test_failing_trailer_option () {
title=$1 option=$2
cat >expect
@@ -1657,6 +1854,24 @@ sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)"
sig_crlf=${sig_crlf%dummy}
test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
+test_expect_success 'set up tag with signature and trailers' '
+ git tag -F - fake-sig-trailer <<-\EOF
+ this is the subject
+
+ this is the body
+
+ My-Trailer: foo
+ -----BEGIN PGP SIGNATURE-----
+
+ not a real signature, but we just care about the
+ subject/body/trailer parsing.
+ -----END PGP SIGNATURE-----
+ EOF
+'
+
+# use "separator=" here to suppress the terminating newline
+test_atom refs/tags/fake-sig-trailer trailers:separator= 'My-Trailer: foo'
+
test_expect_success 'git for-each-ref --stdin: empty' '
>in &&
git for-each-ref --format="%(refname)" --stdin <in >actual &&
@@ -1707,6 +1922,37 @@ test_expect_success 'git for-each-ref with non-existing refs' '
test_must_be_empty actual
'
+test_expect_success 'git for-each-ref with nested tags' '
+ git tag -am "Normal tag" nested/base HEAD &&
+ git tag -am "Nested tag" nested/nest1 refs/tags/nested/base &&
+ git tag -am "Double nested tag" nested/nest2 refs/tags/nested/nest1 &&
+
+ head_oid="$(git rev-parse HEAD)" &&
+ base_tag_oid="$(git rev-parse refs/tags/nested/base)" &&
+ nest1_tag_oid="$(git rev-parse refs/tags/nested/nest1)" &&
+ nest2_tag_oid="$(git rev-parse refs/tags/nested/nest2)" &&
+
+ cat >expect <<-EOF &&
+ refs/tags/nested/base $base_tag_oid tag $head_oid commit
+ refs/tags/nested/nest1 $nest1_tag_oid tag $head_oid commit
+ refs/tags/nested/nest2 $nest2_tag_oid tag $head_oid commit
+ EOF
+
+ git for-each-ref \
+ --format="%(refname) %(objectname) %(objecttype) %(*objectname) %(*objecttype)" \
+ refs/tags/nested/ >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'is-base atom with non-commits' '
+ git for-each-ref --format="%(is-base:HEAD) %(refname)" >out 2>err &&
+ grep "(HEAD) refs/heads/main" out &&
+
+ test_line_count = 2 err &&
+ grep "error: object .* is a commit, not a blob" err &&
+ grep "error: bad tag pointer to" err
+'
+
GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
@@ -1794,8 +2040,7 @@ test_expect_success GPG 'show good signature with custom format' '
--format="$GRADE_FORMAT" >actual &&
test_cmp expect actual
'
-test_expect_success GPGSSH 'show good signature with custom format
- with ssh' '
+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 &&
diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh
index 2667dd13fe..e06feb06e9 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -2,7 +2,6 @@
test_description='for-each-ref errors for broken refs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
ZEROS=$ZERO_OID
@@ -15,7 +14,7 @@ test_expect_success setup '
git for-each-ref --format="%(objectname) %(refname)" >brief-list
'
-test_expect_success 'Broken refs are reported correctly' '
+test_expect_success REFFILES 'Broken refs are reported correctly' '
r=refs/heads/bogus &&
: >.git/$r &&
test_when_finished "rm -f .git/$r" &&
@@ -25,7 +24,7 @@ test_expect_success 'Broken refs are reported correctly' '
test_cmp broken-err err
'
-test_expect_success 'NULL_SHA1 refs are reported correctly' '
+test_expect_success REFFILES 'NULL_SHA1 refs are reported correctly' '
r=refs/heads/zeros &&
echo $ZEROS >.git/$r &&
test_when_finished "rm -f .git/$r" &&
@@ -39,15 +38,14 @@ test_expect_success 'NULL_SHA1 refs are reported correctly' '
'
test_expect_success 'Missing objects are reported correctly' '
- r=refs/heads/missing &&
- echo $MISSING >.git/$r &&
- test_when_finished "rm -f .git/$r" &&
- echo "fatal: missing object $MISSING for $r" >missing-err &&
+ test_when_finished "git update-ref -d refs/heads/missing" &&
+ test-tool ref-store main update-ref msg refs/heads/missing "$MISSING" "$ZERO_OID" REF_SKIP_OID_VERIFICATION &&
+ echo "fatal: missing object $MISSING for refs/heads/missing" >missing-err &&
test_must_fail git for-each-ref 2>err &&
test_cmp missing-err err &&
(
cat brief-list &&
- echo "$MISSING $r"
+ echo "$MISSING refs/heads/missing"
) | sort -k 2 >missing-brief-expected &&
git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err &&
test_cmp missing-brief-expected brief-out &&
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index af223e44d6..bb02b86c16 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -13,7 +13,7 @@ test_expect_success 'setup some history and refs' '
git checkout -b side &&
test_commit four &&
git tag -m "An annotated tag" annotated-tag &&
- git tag -m "Annonated doubly" doubly-annotated-tag annotated-tag &&
+ git tag -m "Annotated doubly" doubly-annotated-tag annotated-tag &&
# Note that these "signed" tags might not actually be signed.
# Tests which care about the distinction should be marked
@@ -31,6 +31,71 @@ test_expect_success 'setup some history and refs' '
git update-ref refs/odd/spot main
'
+test_expect_success '--include-root-refs pattern prints pseudorefs' '
+ cat >expect <<-\EOF &&
+ HEAD
+ ORIG_HEAD
+ refs/heads/main
+ refs/heads/side
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git update-ref ORIG_HEAD main &&
+ git for-each-ref --format="%(refname)" --include-root-refs >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--include-root-refs pattern does not print special refs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git rev-parse HEAD >.git/MERGE_HEAD &&
+ git for-each-ref --format="%(refname)" --include-root-refs >actual &&
+ cat >expect <<-EOF &&
+ HEAD
+ $(git symbolic-ref HEAD)
+ refs/tags/initial
+ EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--include-root-refs with other patterns' '
+ cat >expect <<-\EOF &&
+ HEAD
+ ORIG_HEAD
+ EOF
+ git update-ref ORIG_HEAD main &&
+ git for-each-ref --format="%(refname)" --include-root-refs "*HEAD" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--include-root-refs omits dangling symrefs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ git symbolic-ref DANGLING_HEAD refs/heads/missing &&
+ cat >expect <<-EOF &&
+ HEAD
+ $(git symbolic-ref HEAD)
+ refs/tags/initial
+ EOF
+ git for-each-ref --format="%(refname)" --include-root-refs >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'filtering with --points-at' '
cat >expect <<-\EOF &&
refs/heads/main
@@ -45,8 +110,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/doubly-annotated-tag four
+ refs/tags/doubly-signed-tag four
refs/tags/four Z
refs/tags/signed-tag four
EOF
@@ -277,7 +342,7 @@ test_expect_success 'check `%(contents:lines=1)`' '
side |four
odd/spot |three
annotated-tag |An annotated tag
- doubly-annotated-tag |Annonated doubly
+ doubly-annotated-tag |Annotated doubly
doubly-signed-tag |Signed doubly
four |four
one |one
@@ -313,7 +378,7 @@ test_expect_success 'check `%(contents:lines=99999)`' '
side |four
odd/spot |three
annotated-tag |An annotated tag
- doubly-annotated-tag |Annonated doubly
+ doubly-annotated-tag |Annotated doubly
doubly-signed-tag |Signed doubly
four |four
one |one
diff --git a/t/t6401-merge-criss-cross.sh b/t/t6401-merge-criss-cross.sh
index 1962310408..c8e5ff28e8 100755
--- a/t/t6401-merge-criss-cross.sh
+++ b/t/t6401-merge-criss-cross.sh
@@ -9,7 +9,6 @@
test_description='Test criss-cross merge'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'prepare repository' '
diff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh
index 772238e582..2738b50c2a 100755
--- a/t/t6402-merge-rename.sh
+++ b/t/t6402-merge-rename.sh
@@ -311,13 +311,13 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
git checkout -q renamed-file-has-no-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-in-way >output &&
- test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
- test_i18ngrep "Auto-merging dir" output &&
+ test_grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+ test_grep "Auto-merging dir" output &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test_i18ngrep "moving it to dir~HEAD instead" output
+ test_grep "moving it to dir~HEAD instead" output
else
- test_i18ngrep "Adding as dir~HEAD instead" output
+ test_grep "Adding as dir~HEAD instead" output
fi &&
test_stdout_line_count = 3 git ls-files -u &&
@@ -338,13 +338,13 @@ test_expect_success 'Same as previous, but merged other way' '
test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
! grep "error: refusing to lose untracked file at" errors &&
- test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
- test_i18ngrep "Auto-merging dir" output &&
+ test_grep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
+ test_grep "Auto-merging dir" output &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test_i18ngrep "moving it to dir~renamed-file-has-no-conflicts instead" output
+ test_grep "moving it to dir~renamed-file-has-no-conflicts instead" output
else
- test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output
+ test_grep "Adding as dir~renamed-file-has-no-conflicts instead" output
fi &&
test_stdout_line_count = 3 git ls-files -u &&
diff --git a/t/t6403-merge-file.sh b/t/t6403-merge-file.sh
index 1a7082323d..06ab4d7aed 100755
--- a/t/t6403-merge-file.sh
+++ b/t/t6403-merge-file.sh
@@ -2,7 +2,6 @@
test_description='RCS merge replacement: merge-file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -56,7 +55,67 @@ test_expect_success 'setup' '
deduxit me super semitas jusitiae,
EOF
- printf "propter nomen suum." >>new4.txt
+ printf "propter nomen suum." >>new4.txt &&
+
+ cat >base.c <<-\EOF &&
+ int f(int x, int y)
+ {
+ if (x == 0)
+ {
+ return y;
+ }
+ return x;
+ }
+
+ int g(size_t u)
+ {
+ while (u < 30)
+ {
+ u++;
+ }
+ return u;
+ }
+ EOF
+
+ cat >ours.c <<-\EOF &&
+ int g(size_t u)
+ {
+ while (u < 30)
+ {
+ u++;
+ }
+ return u;
+ }
+
+ int h(int x, int y, int z)
+ {
+ if (z == 0)
+ {
+ return x;
+ }
+ return y;
+ }
+ EOF
+
+ cat >theirs.c <<-\EOF
+ int f(int x, int y)
+ {
+ if (x == 0)
+ {
+ return y;
+ }
+ return x;
+ }
+
+ int g(size_t u)
+ {
+ while (u > 34)
+ {
+ u--;
+ }
+ return u;
+ }
+ EOF
'
test_expect_success 'merge with no changes' '
@@ -65,11 +124,30 @@ test_expect_success 'merge with no changes' '
test_cmp test.txt orig.txt
'
+test_expect_success 'merge with no changes with --object-id' '
+ git add orig.txt &&
+ git merge-file -p --object-id :orig.txt :orig.txt :orig.txt >actual &&
+ test_cmp actual orig.txt
+'
+
test_expect_success "merge without conflict" '
cp new1.txt test.txt &&
git merge-file test.txt orig.txt new2.txt
'
+test_expect_success 'merge without conflict with --object-id' '
+ git add orig.txt new2.txt &&
+ git merge-file --object-id :orig.txt :orig.txt :new2.txt >actual &&
+ git rev-parse :new2.txt >expected &&
+ test_cmp actual expected
+'
+
+test_expect_success 'can accept object ID with --object-id' '
+ git merge-file --object-id $(test_oid empty_blob) $(test_oid empty_blob) :new2.txt >actual &&
+ git rev-parse :new2.txt >expected &&
+ test_cmp actual expected
+'
+
test_expect_success 'works in subdirectory' '
mkdir dir &&
cp new1.txt dir/a.txt &&
@@ -138,6 +216,31 @@ test_expect_success "expected conflict markers" '
test_cmp expect.txt test.txt
'
+test_expect_success "merge with conflicts with --object-id" '
+ git add backup.txt orig.txt new3.txt &&
+ test_must_fail git merge-file -p --object-id :backup.txt :orig.txt :new3.txt >actual &&
+ sed -e "s/<< test.txt/<< :backup.txt/" \
+ -e "s/>> new3.txt/>> :new3.txt/" \
+ expect.txt >expect &&
+ test_cmp expect actual &&
+ test_must_fail git merge-file --object-id :backup.txt :orig.txt :new3.txt >oid &&
+ git cat-file blob "$(cat oid)" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success "merge with conflicts with --object-id with labels" '
+ git add backup.txt orig.txt new3.txt &&
+ test_must_fail git merge-file -p --object-id \
+ -L test.txt -L orig.txt -L new3.txt \
+ :backup.txt :orig.txt :new3.txt >actual &&
+ test_cmp expect.txt actual &&
+ test_must_fail git merge-file --object-id \
+ -L test.txt -L orig.txt -L new3.txt \
+ :backup.txt :orig.txt :new3.txt >oid &&
+ git cat-file blob "$(cat oid)" >actual &&
+ test_cmp expect.txt actual
+'
+
test_expect_success "merge conflicting with --ours" '
cp backup.txt test.txt &&
@@ -256,6 +359,14 @@ test_expect_success 'binary files cannot be merged' '
grep "Cannot merge binary files" merge.err
'
+test_expect_success 'binary files cannot be merged with --object-id' '
+ cp "$TEST_DIRECTORY"/test-binary-1.png . &&
+ git add orig.txt new1.txt test-binary-1.png &&
+ test_must_fail git merge-file --object-id \
+ :orig.txt :test-binary-1.png :new1.txt 2> merge.err &&
+ grep "Cannot merge binary files" merge.err
+'
+
test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '
sed -e "s/deerit.\$/deerit;/" -e "s/me;\$/me./" <new5.txt >new6.txt &&
sed -e "s/deerit.\$/deerit,/" -e "s/me;\$/me,/" <new5.txt >new7.txt &&
@@ -389,4 +500,72 @@ test_expect_success 'conflict sections match existing line endings' '
test $(tr "\015" Q <nolf.txt | grep "^[<=>].*Q$" | wc -l) = 0
'
+test_expect_success '--object-id fails without repository' '
+ empty="$(test_oid empty_blob)" &&
+ nongit test_must_fail git merge-file --object-id $empty $empty $empty 2>err &&
+ grep "not a git repository" err
+'
+
+test_expect_success 'merging C files with "myers" diff algorithm creates some spurious conflicts' '
+ cat >expect.c <<-\EOF &&
+ int g(size_t u)
+ {
+ while (u < 30)
+ {
+ u++;
+ }
+ return u;
+ }
+
+ int h(int x, int y, int z)
+ {
+ <<<<<<< ours.c
+ if (z == 0)
+ ||||||| base.c
+ while (u < 30)
+ =======
+ while (u > 34)
+ >>>>>>> theirs.c
+ {
+ <<<<<<< ours.c
+ return x;
+ ||||||| base.c
+ u++;
+ =======
+ u--;
+ >>>>>>> theirs.c
+ }
+ return y;
+ }
+ EOF
+
+ test_must_fail git merge-file -p --diff3 --diff-algorithm myers ours.c base.c theirs.c >myers_output.c &&
+ test_cmp expect.c myers_output.c
+'
+
+test_expect_success 'merging C files with "histogram" diff algorithm avoids some spurious conflicts' '
+ cat >expect.c <<-\EOF &&
+ int g(size_t u)
+ {
+ while (u > 34)
+ {
+ u--;
+ }
+ return u;
+ }
+
+ int h(int x, int y, int z)
+ {
+ if (z == 0)
+ {
+ return x;
+ }
+ return y;
+ }
+ EOF
+
+ git merge-file -p --diff3 --diff-algorithm histogram ours.c base.c theirs.c >histogram_output.c &&
+ test_cmp expect.c histogram_output.c
+'
+
test_done
diff --git a/t/t6404-recursive-merge.sh b/t/t6404-recursive-merge.sh
index 36215518b6..ae687f2ce5 100755
--- a/t/t6404-recursive-merge.sh
+++ b/t/t6404-recursive-merge.sh
@@ -4,7 +4,6 @@ test_description='Test merge without common ancestors'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This scenario is based on a real-world repository of Shawn Pearce.
@@ -88,7 +87,7 @@ test_expect_success 'result contains a conflict' '
'
test_expect_success 'virtual trees were processed' '
- # TODO: fragile test, relies on ambigious merge-base resolution
+ # TODO: fragile test, relies on ambiguous merge-base resolution
git ls-files --stage >out &&
cat >expect <<-EOF &&
diff --git a/t/t6405-merge-symlinks.sh b/t/t6405-merge-symlinks.sh
index 29e2b25ce5..7435fce71e 100755
--- a/t/t6405-merge-symlinks.sh
+++ b/t/t6405-merge-symlinks.sh
@@ -11,7 +11,6 @@ if core.symlinks is false.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh
index 9677180a5b..66e01464b5 100755
--- a/t/t6406-merge-attr.sh
+++ b/t/t6406-merge-attr.sh
@@ -8,7 +8,6 @@ test_description='per path merge controlled by merge attribute'
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 '
@@ -42,11 +41,15 @@ test_expect_success setup '
#!/bin/sh
orig="$1" ours="$2" theirs="$3" exit="$4" path=$5
+ orig_name="$6" our_name="$7" their_name="$8"
(
echo "orig is $orig"
echo "ours is $ours"
echo "theirs is $theirs"
echo "path is $path"
+ echo "orig_name is $orig_name"
+ echo "our_name is $our_name"
+ echo "their_name is $their_name"
echo "=== orig ==="
cat "$orig"
echo "=== ours ==="
@@ -114,6 +117,14 @@ test_expect_success 'retry the merge with longer context' '
grep "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" actual
'
+test_expect_success 'invalid conflict-marker-size 3a' '
+ cp .gitattributes .gitattributes.bak &&
+ echo "text conflict-marker-size=3a" >>.gitattributes &&
+ test_when_finished "mv .gitattributes.bak .gitattributes" &&
+ git checkout -m text 2>err &&
+ test_grep "warning: invalid marker-size ${SQ}3a${SQ}, expecting an integer" err
+'
+
test_expect_success 'custom merge backend' '
echo "* merge=union" >.gitattributes &&
@@ -121,7 +132,7 @@ test_expect_success 'custom merge backend' '
git reset --hard anchor &&
git config --replace-all \
- merge.custom.driver "./custom-merge %O %A %B 0 %P" &&
+ merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" &&
git config --replace-all \
merge.custom.name "custom merge driver for testing" &&
@@ -132,7 +143,8 @@ test_expect_success 'custom merge backend' '
o=$(git unpack-file main^:text) &&
a=$(git unpack-file side^:text) &&
b=$(git unpack-file main:text) &&
- sh -c "./custom-merge $o $a $b 0 text" &&
+ base_revid=$(git rev-parse --short main^) &&
+ sh -c "./custom-merge $o $a $b 0 text $base_revid HEAD main" &&
sed -e 1,3d $a >check-2 &&
cmp check-1 check-2 &&
rm -f $o $a $b
@@ -142,7 +154,7 @@ test_expect_success 'custom merge backend' '
git reset --hard anchor &&
git config --replace-all \
- merge.custom.driver "./custom-merge %O %A %B 1 %P" &&
+ merge.custom.driver "./custom-merge %O %A %B 1 %P %S %X %Y" &&
git config --replace-all \
merge.custom.name "custom merge driver for testing" &&
@@ -159,7 +171,8 @@ test_expect_success 'custom merge backend' '
o=$(git unpack-file main^:text) &&
a=$(git unpack-file anchor:text) &&
b=$(git unpack-file main:text) &&
- sh -c "./custom-merge $o $a $b 0 text" &&
+ base_revid=$(git rev-parse --short main^) &&
+ sh -c "./custom-merge $o $a $b 0 text $base_revid HEAD main" &&
sed -e 1,3d $a >check-2 &&
cmp check-1 check-2 &&
sed -e 1,3d -e 4q $a >check-3 &&
@@ -173,13 +186,14 @@ test_expect_success !WINDOWS 'custom merge driver that is killed with a signal'
git reset --hard anchor &&
git config --replace-all \
- merge.custom.driver "./custom-merge %O %A %B 0 %P" &&
+ merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" &&
git config --replace-all \
merge.custom.name "custom merge driver for testing" &&
>./please-abort &&
echo "* merge=custom" >.gitattributes &&
- test_must_fail git merge main &&
+ test_expect_code 2 git merge main 2>err &&
+ grep "^error: failed to execute internal merge" err &&
git ls-files -u >output &&
git diff --name-only HEAD >>output &&
test_must_be_empty output
@@ -254,4 +268,44 @@ test_expect_success 'binary files with union attribute' '
grep -i "warning.*cannot merge.*HEAD vs. bin-main" output
'
+test_expect_success !WINDOWS 'custom merge driver that is killed with a signal on recursive merge' '
+ test_when_finished "rm -f output please-abort" &&
+ test_when_finished "git checkout side" &&
+
+ git reset --hard anchor &&
+
+ git checkout -b base-a main^ &&
+ echo base-a >text &&
+ git commit -m base-a text &&
+
+ git checkout -b base-b main^ &&
+ echo base-b >text &&
+ git commit -m base-b text &&
+
+ git checkout -b recursive-a base-a &&
+ test_must_fail git merge base-b &&
+ echo recursive-a >text &&
+ git add text &&
+ git commit -m recursive-a &&
+
+ git checkout -b recursive-b base-b &&
+ test_must_fail git merge base-a &&
+ echo recursive-b >text &&
+ git add text &&
+ git commit -m recursive-b &&
+
+ git config --replace-all \
+ merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" &&
+ git config --replace-all \
+ merge.custom.name "custom merge driver for testing" &&
+
+ >./please-abort &&
+ echo "* merge=custom" >.gitattributes &&
+ test_expect_code 2 git merge recursive-a 2>err &&
+ grep "error: failed to execute internal merge" err &&
+ git ls-files -u >output &&
+ git diff --name-only HEAD >>output &&
+ test_must_be_empty output
+'
+
test_done
diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh
index 0753fc95f4..e8a28717ce 100755
--- a/t/t6407-merge-binary.sh
+++ b/t/t6407-merge-binary.sh
@@ -5,7 +5,6 @@ test_description='ask merge-recursive to merge binary files'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t6408-merge-up-to-date.sh b/t/t6408-merge-up-to-date.sh
index 8a1ba6d23a..7763c1ba98 100755
--- a/t/t6408-merge-up-to-date.sh
+++ b/t/t6408-merge-up-to-date.sh
@@ -2,7 +2,6 @@
test_description='merge fast-forward and up to date'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t6411-merge-filemode.sh b/t/t6411-merge-filemode.sh
index b6182723aa..6ae2489286 100755
--- a/t/t6411-merge-filemode.sh
+++ b/t/t6411-merge-filemode.sh
@@ -4,7 +4,6 @@ test_description='merge: handle file mode'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up mode change in one branch' '
diff --git a/t/t6413-merge-crlf.sh b/t/t6413-merge-crlf.sh
index b4f4a313f4..cd6adf6caa 100755
--- a/t/t6413-merge-crlf.sh
+++ b/t/t6413-merge-crlf.sh
@@ -11,7 +11,6 @@ test_description='merge conflict in crlf repo
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -34,14 +33,14 @@ test_expect_success setup '
test_expect_success 'Check "ours" is CRLF' '
git reset --hard initial &&
git merge side -s ours &&
- cat file | remove_cr | append_cr >file.temp &&
+ remove_cr <file | append_cr >file.temp &&
test_cmp file file.temp
'
test_expect_success 'Check that conflict file is CRLF' '
git reset --hard a &&
test_must_fail git merge side &&
- cat file | remove_cr | append_cr >file.temp &&
+ remove_cr <file | append_cr >file.temp &&
test_cmp file file.temp
'
diff --git a/t/t6414-merge-rename-nocruft.sh b/t/t6414-merge-rename-nocruft.sh
index 69fc1c9e69..d7e3c1fa6e 100755
--- a/t/t6414-merge-rename-nocruft.sh
+++ b/t/t6414-merge-rename-nocruft.sh
@@ -4,7 +4,6 @@ test_description='Merge-recursive merging renames'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh
index ae00492c76..2655e295f5 100755
--- a/t/t6415-merge-dir-to-symlink.sh
+++ b/t/t6415-merge-dir-to-symlink.sh
@@ -4,7 +4,6 @@ test_description='merging when a directory was replaced with a symlink'
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 'create a commit where dir a/b changed to symlink' '
diff --git a/t/t6417-merge-ours-theirs.sh b/t/t6417-merge-ours-theirs.sh
index 482b73a998..62d1406119 100755
--- a/t/t6417-merge-ours-theirs.sh
+++ b/t/t6417-merge-ours-theirs.sh
@@ -4,7 +4,6 @@ test_description='Merge-recursive ours and theirs variants'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh
index 711b709e75..b99f29ef9b 100755
--- a/t/t6421-merge-partial-clone.sh
+++ b/t/t6421-merge-partial-clone.sh
@@ -230,8 +230,9 @@ test_expect_merge_algorithm failure success 'Objects downloaded for single relev
grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual &&
test_cmp expect actual &&
- # Check the number of fetch commands exec-ed
- grep d0.*fetch.negotiationAlgorithm trace.output >fetches &&
+ # Check the number of fetch commands exec-ed by filtering trace to
+ # child_start events by the top-level program (2nd field == d0)
+ grep " d0 .* child_start .*fetch.negotiationAlgorithm" trace.output >fetches &&
test_line_count = 2 fetches &&
git rev-list --objects --all --missing=print |
@@ -318,8 +319,9 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory
grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual &&
test_cmp expect actual &&
- # Check the number of fetch commands exec-ed
- grep d0.*fetch.negotiationAlgorithm trace.output >fetches &&
+ # Check the number of fetch commands exec-ed by filtering trace to
+ # child_start events by the top-level program (2nd field == d0)
+ grep " d0 .* child_start .*fetch.negotiationAlgorithm" trace.output >fetches &&
test_line_count = 1 fetches &&
git rev-list --objects --all --missing=print |
@@ -422,8 +424,9 @@ test_expect_merge_algorithm failure success 'Objects downloaded with lots of ren
grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual &&
test_cmp expect actual &&
- # Check the number of fetch commands exec-ed
- grep d0.*fetch.negotiationAlgorithm trace.output >fetches &&
+ # Check the number of fetch commands exec-ed by filtering trace to
+ # child_start events by the top-level program (2nd field == d0)
+ grep " d0 .* child_start .*fetch.negotiationAlgorithm" trace.output >fetches &&
test_line_count = 4 fetches &&
git rev-list --objects --all --missing=print |
diff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh
index 076b6a74d5..62b49c67e2 100755
--- a/t/t6422-merge-rename-corner-cases.sh
+++ b/t/t6422-merge-rename-corner-cases.sh
@@ -6,7 +6,6 @@ test_description="recursive merge corner cases w/ renames but not criss-crosses"
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-merge.sh
@@ -476,7 +475,7 @@ test_expect_success 'handle rename-with-content-merge vs. add' '
git checkout A^0 &&
test_must_fail git merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (.*/add)" out &&
+ test_grep "CONFLICT (.*/add)" out &&
git ls-files -s >out &&
test_line_count = 2 out &&
@@ -522,7 +521,7 @@ test_expect_success 'handle rename-with-content-merge vs. add, merge other way'
git checkout B^0 &&
test_must_fail git merge -s recursive A^0 >out &&
- test_i18ngrep "CONFLICT (.*/add)" out &&
+ test_grep "CONFLICT (.*/add)" out &&
git ls-files -s >out &&
test_line_count = 2 out &&
@@ -602,7 +601,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
git checkout B^0 &&
test_must_fail git merge -s recursive C^0 >out &&
- test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
+ test_grep "CONFLICT (\(.*\)/\1)" out &&
git ls-files -s >out &&
test_line_count = 2 out &&
@@ -914,8 +913,8 @@ test_expect_merge_algorithm failure success 'rad-check: rename/add/delete confli
# be flexible in the type of console output message(s) reported
# for this particular case; we will be more stringent about the
# contents of the index and working directory.
- test_i18ngrep "CONFLICT (.*/add)" out &&
- test_i18ngrep "CONFLICT (rename.*/delete)" out &&
+ test_grep "CONFLICT (.*/add)" out &&
+ test_grep "CONFLICT (rename.*/delete)" out &&
test_must_be_empty err &&
git ls-files -s >file_count &&
@@ -988,8 +987,8 @@ test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/del
# be flexible in the type of console output message(s) reported
# for this particular case; we will be more stringent about the
# contents of the index and working directory.
- test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
- test_i18ngrep "CONFLICT (rename.*delete)" out &&
+ test_grep "CONFLICT (\(.*\)/\1)" out &&
+ test_grep "CONFLICT (rename.*delete)" out &&
test_must_be_empty err &&
git ls-files -s >file_count &&
@@ -1068,7 +1067,7 @@ test_expect_merge_algorithm failure success 'mod6-check: chains of rename/rename
test_must_fail git merge -s recursive B^0 >out 2>err &&
- test_i18ngrep "CONFLICT (rename/rename)" out &&
+ test_grep "CONFLICT (rename/rename)" out &&
test_must_be_empty err &&
git ls-files -s >file_count &&
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index 944de75b80..88d1cf2cde 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -276,7 +276,7 @@ test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict'
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
+ test_grep "CONFLICT (\(.*\)/\1)" out &&
git ls-files -s >out &&
test_line_count = 8 out &&
@@ -515,7 +515,7 @@ test_expect_success '2a: Directory split into two on one side, with equal number
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT.*directory rename split" out &&
+ test_grep "CONFLICT.*directory rename split" out &&
git ls-files -s >out &&
test_line_count = 3 out &&
@@ -591,7 +591,7 @@ test_expect_success '2b: Directory split into two on one side, with equal number
git rev-parse >expect \
O:z/b O:z/c B:x/d &&
test_cmp expect actual &&
- test_i18ngrep ! "CONFLICT.*directory rename split" out
+ test_grep ! "CONFLICT.*directory rename split" out
)
'
@@ -726,8 +726,8 @@ test_expect_success '3b: Avoid implicit rename if involved as source on current
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
- test_i18ngrep ! CONFLICT.*rename/rename.*y/d out &&
+ test_grep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
+ test_grep ! CONFLICT.*rename/rename.*y/d out &&
git ls-files -s >out &&
test_line_count = 5 out &&
@@ -938,7 +938,7 @@ test_expect_success '5a: Merge directories, other side adds files to original an
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT.*implicit dir rename" out &&
+ test_grep "CONFLICT.*implicit dir rename" out &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -1013,7 +1013,7 @@ test_expect_success '5b: Rename/delete in order to get add/add/add conflict' '
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (add/add).* y/d" out &&
+ test_grep "CONFLICT (add/add).* y/d" out &&
git ls-files -s >out &&
test_line_count = 5 out &&
@@ -1094,8 +1094,8 @@ test_expect_success '5c: Transitive rename would cause rename/rename/rename/add/
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
- test_i18ngrep "CONFLICT (add/add).* y/d" out &&
+ test_grep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
+ test_grep "CONFLICT (add/add).* y/d" out &&
git ls-files -s >out &&
test_line_count = 9 out &&
@@ -1179,7 +1179,7 @@ test_expect_success '5d: Directory/file/file conflict due to directory rename' '
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (file/directory).*y/d" out &&
+ test_grep "CONFLICT (file/directory).*y/d" out &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -1278,7 +1278,7 @@ test_expect_success '6a: Tricky rename/delete' '
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
+ test_grep "CONFLICT (rename/delete).*z/c.*y/c" out &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
@@ -1740,8 +1740,8 @@ test_expect_success '7a: rename-dir vs. rename-dir (NOT split evenly) PLUS add-o
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
- test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
+ test_grep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
+ test_grep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
git ls-files -s >out &&
test_line_count = 7 out &&
@@ -1813,7 +1813,7 @@ test_expect_success '7b: rename/rename(2to1), but only due to transitive rename'
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
+ test_grep "CONFLICT (\(.*\)/\1)" out &&
git ls-files -s >out &&
test_line_count = 4 out &&
@@ -1900,7 +1900,7 @@ test_expect_success '7c: rename/rename(1to...2or3); transitive rename may add co
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
+ test_grep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
git ls-files -s >out &&
test_line_count = 5 out &&
@@ -1965,7 +1965,7 @@ test_expect_success '7d: transitive rename involved in rename/delete; how is it
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
+ test_grep "CONFLICT (rename/delete).*x/d.*y/d" out &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
@@ -2071,7 +2071,7 @@ test_expect_success '7e: transitive rename in rename/delete AND dirs in the way'
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
+ test_grep "CONFLICT (rename/delete).*x/d.*y/d" out &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
@@ -2330,7 +2330,7 @@ test_expect_success '8c: modify/delete or rename+modify/delete' '
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&
+ test_grep "CONFLICT (modify/delete).* z/d" out &&
git ls-files -s >out &&
test_line_count = 5 out &&
@@ -2491,8 +2491,8 @@ test_expect_success '8e: Both sides rename, one side adds to original directory'
git checkout A^0 &&
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
- test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
+ test_grep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
+ test_grep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
git ls-files -s >out &&
test_line_count = 7 out &&
@@ -2741,7 +2741,7 @@ test_expect_success '9c: Doubly transitive rename?' '
git checkout A^0 &&
git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
+ test_grep "WARNING: Avoiding applying x -> z rename to x/f" out &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -2830,10 +2830,10 @@ test_expect_success '9d: N-way transitive rename?' '
git checkout A^0 &&
git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
- test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
- test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
- test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
- test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
+ test_grep "WARNING: Avoiding applying z -> y rename to z/t" out &&
+ test_grep "WARNING: Avoiding applying y -> x rename to y/a" out &&
+ test_grep "WARNING: Avoiding applying x -> w rename to x/b" out &&
+ test_grep "WARNING: Avoiding applying w -> v rename to w/c" out &&
git ls-files -s >out &&
test_line_count = 7 out &&
@@ -3215,7 +3215,7 @@ test_expect_success '10a: Overwrite untracked with normal rename/delete' '
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
+ test_grep "The following untracked working tree files would be overwritten by merge" err &&
git ls-files -s >out &&
test_line_count = 1 out &&
@@ -3287,7 +3287,7 @@ test_expect_success '10b: Overwrite untracked with dir rename + delete' '
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: The following untracked working tree files would be overwritten by merge" err &&
+ test_grep "error: The following untracked working tree files would be overwritten by merge" err &&
git ls-files -s >out &&
test_line_count = 1 out &&
@@ -3296,8 +3296,8 @@ test_expect_success '10b: Overwrite untracked with dir rename + delete' '
git ls-files -o >out &&
test_line_count = 5 out
else
- test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
- test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
+ test_grep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
+ test_grep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
git ls-files -s >out &&
test_line_count = 3 out &&
@@ -3377,7 +3377,7 @@ test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: The following untracked working tree files would be overwritten by merge" err &&
+ test_grep "error: The following untracked working tree files would be overwritten by merge" err &&
git ls-files -s >out &&
test_line_count = 4 out &&
@@ -3386,8 +3386,8 @@ test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '
git ls-files -o >out &&
test_line_count = 3 out
else
- test_i18ngrep "CONFLICT (rename/rename)" out &&
- test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
+ test_grep "CONFLICT (rename/rename)" out &&
+ test_grep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -3428,7 +3428,7 @@ test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), oth
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: The following untracked working tree files would be overwritten by merge" err &&
+ test_grep "error: The following untracked working tree files would be overwritten by merge" err &&
git ls-files -s >out &&
test_line_count = 4 out &&
@@ -3437,8 +3437,8 @@ test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), oth
git ls-files -o >out &&
test_line_count = 3 out
else
- test_i18ngrep "CONFLICT (rename/rename)" out &&
- test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~HEAD instead" out &&
+ test_grep "CONFLICT (rename/rename)" out &&
+ test_grep "Refusing to lose untracked file at y/c; adding as y/c~HEAD instead" out &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -3517,7 +3517,7 @@ test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: The following untracked working tree files would be overwritten by merge" err &&
+ test_grep "error: The following untracked working tree files would be overwritten by merge" err &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -3526,8 +3526,8 @@ test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '
git ls-files -o >out &&
test_line_count = 3 out
else
- test_i18ngrep "CONFLICT (rename/rename)" out &&
- test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
+ test_grep "CONFLICT (rename/rename)" out &&
+ test_grep "Refusing to lose untracked file at y/wham" out &&
git ls-files -s >out &&
test_line_count = 6 out &&
@@ -3606,7 +3606,7 @@ test_expect_merge_algorithm failure success '10e: Does git complain about untrac
echo random >z/c &&
git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
+ test_grep ! "following untracked working tree files would be overwritten by merge" err &&
git ls-files -s >out &&
test_line_count = 3 out &&
@@ -3690,9 +3690,9 @@ test_expect_success '11a: Avoid losing dirty contents with simple rename' '
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: Your local changes to the following files would be overwritten by merge" err
+ test_grep "error: Your local changes to the following files would be overwritten by merge" err
else
- test_i18ngrep "Refusing to lose dirty file at z/c" out &&
+ test_grep "Refusing to lose dirty file at z/c" out &&
git ls-files -s >out &&
test_line_count = 2 out &&
@@ -3770,10 +3770,10 @@ test_expect_success '11b: Avoid losing dirty file involved in directory rename'
then
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: Your local changes to the following files would be overwritten by merge" err
+ test_grep "error: Your local changes to the following files would be overwritten by merge" err
else
git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep "Refusing to lose dirty file at z/c" out &&
+ test_grep "Refusing to lose dirty file at z/c" out &&
git ls-files -s >out &&
test_line_count = 3 out &&
@@ -3853,9 +3853,9 @@ test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict'
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: Your local changes to the following files would be overwritten by merge" err
+ test_grep "error: Your local changes to the following files would be overwritten by merge" err
else
- test_i18ngrep "following files would be overwritten by merge" err
+ test_grep "following files would be overwritten by merge" err
fi &&
grep -q stuff y/c &&
@@ -3927,9 +3927,9 @@ test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict'
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: Your local changes to the following files would be overwritten by merge" err
+ test_grep "error: Your local changes to the following files would be overwritten by merge" err
else
- test_i18ngrep "Refusing to lose dirty file at z/c" out &&
+ test_grep "Refusing to lose dirty file at z/c" out &&
git ls-files -s >out &&
test_line_count = 4 out &&
@@ -4013,10 +4013,10 @@ test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: Your local changes to the following files would be overwritten by merge" err
+ test_grep "error: Your local changes to the following files would be overwritten by merge" err
else
- test_i18ngrep "CONFLICT (rename/rename)" out &&
- test_i18ngrep "Refusing to lose dirty file at y/c" out &&
+ test_grep "CONFLICT (rename/rename)" out &&
+ test_grep "Refusing to lose dirty file at y/c" out &&
git ls-files -s >out &&
test_line_count = 7 out &&
@@ -4102,10 +4102,10 @@ test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_path_is_missing .git/MERGE_HEAD &&
- test_i18ngrep "error: Your local changes to the following files would be overwritten by merge" err
+ test_grep "error: Your local changes to the following files would be overwritten by merge" err
else
- test_i18ngrep "CONFLICT (rename/rename)" out &&
- test_i18ngrep "Refusing to lose dirty file at y/wham" out &&
+ test_grep "CONFLICT (rename/rename)" out &&
+ test_grep "Refusing to lose dirty file at y/wham" out &&
git ls-files -s >out &&
test_line_count = 4 out &&
@@ -5417,8 +5417,8 @@ test_expect_success '13a(conflict): messages for newly added files' '
test_must_fail git merge -s recursive B^0 >out 2>err &&
- test_i18ngrep CONFLICT..file.location.*z/e/f.added.in.B^0.*y/e/f out &&
- test_i18ngrep CONFLICT..file.location.*z/d.added.in.B^0.*y/d out &&
+ test_grep CONFLICT..file.location.*z/e/f.added.in.B^0.*y/e/f out &&
+ test_grep CONFLICT..file.location.*z/d.added.in.B^0.*y/d out &&
git ls-files >paths &&
! grep z/ paths &&
@@ -5441,8 +5441,8 @@ test_expect_success '13a(info): messages for newly added files' '
git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep Path.updated:.*z/e/f.added.in.B^0.*y/e/f out &&
- test_i18ngrep Path.updated:.*z/d.added.in.B^0.*y/d out &&
+ test_grep Path.updated:.*z/e/f.added.in.B^0.*y/e/f out &&
+ test_grep Path.updated:.*z/d.added.in.B^0.*y/d out &&
git ls-files >paths &&
! grep z/ paths &&
@@ -5507,8 +5507,8 @@ test_expect_success '13b(conflict): messages for transitive rename with conflict
test_must_fail git merge -s recursive B^0 >out 2>err &&
- test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
- test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
+ test_grep CONFLICT.*content.*Merge.conflict.in.y/d out &&
+ test_grep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
git ls-files >paths &&
! grep z/ paths &&
@@ -5529,8 +5529,8 @@ test_expect_success '13b(info): messages for transitive rename with conflicted c
test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
- test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
+ test_grep CONFLICT.*content.*Merge.conflict.in.y/d out &&
+ test_grep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
git ls-files >paths &&
! grep z/ paths &&
@@ -5593,7 +5593,7 @@ test_expect_success '13c(conflict): messages for rename/rename(1to1) via transit
test_must_fail git merge -s recursive B^0 >out 2>err &&
- test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
+ test_grep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
git ls-files >paths &&
! grep z/ paths &&
@@ -5614,7 +5614,7 @@ test_expect_success '13c(info): messages for rename/rename(1to1) via transitive
git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
+ test_grep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
git ls-files >paths &&
! grep z/ paths &&
@@ -5682,8 +5682,8 @@ test_expect_success '13d(conflict): messages for rename/rename(1to1) via dual tr
test_must_fail git merge -s recursive B^0 >out 2>err &&
- test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.b/y.*moved.to.d/y out &&
- test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.c/y.*moved.to.d/y out &&
+ test_grep CONFLICT..file.location.*a/y.renamed.to.b/y.*moved.to.d/y out &&
+ test_grep CONFLICT..file.location.*a/y.renamed.to.c/y.*moved.to.d/y out &&
git ls-files >paths &&
! grep b/ paths &&
@@ -5706,8 +5706,8 @@ test_expect_success '13d(info): messages for rename/rename(1to1) via dual transi
git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
- test_i18ngrep Path.updated.*a/y.renamed.to.b/y.*moving.it.to.d/y out &&
- test_i18ngrep Path.updated.*a/y.renamed.to.c/y.*moving.it.to.d/y out &&
+ test_grep Path.updated.*a/y.renamed.to.b/y.*moving.it.to.d/y out &&
+ test_grep Path.updated.*a/y.renamed.to.c/y.*moving.it.to.d/y out &&
git ls-files >paths &&
! grep b/ paths &&
@@ -5821,9 +5821,9 @@ test_expect_success '13e: directory rename detection in recursive case' '
git -c merge.directoryRenames=conflict merge -s recursive C^0 >out 2>err &&
- test_i18ngrep ! CONFLICT out &&
- test_i18ngrep ! BUG: err &&
- test_i18ngrep ! core.dumped err &&
+ test_grep ! CONFLICT out &&
+ test_grep ! BUG: err &&
+ test_grep ! core.dumped err &&
test_must_be_empty err &&
git ls-files >paths &&
diff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh
index a61f20c22f..7677c5f08d 100755
--- a/t/t6424-merge-unrelated-index-changes.sh
+++ b/t/t6424-merge-unrelated-index-changes.sh
@@ -178,7 +178,7 @@ test_expect_success 'merge-recursive, when index==head but head!=HEAD' '
test_when_finished "git clean -fd" && # Do not leave untracked around
# Merge B & F, with B as "head"
git merge-recursive A -- B F > out &&
- test_i18ngrep "Already up to date" out
+ test_grep "Already up to date" out
'
test_expect_success 'recursive, when file has staged changes not matching HEAD nor what a merge would give' '
@@ -194,7 +194,7 @@ test_expect_success 'recursive, when file has staged changes not matching HEAD n
test_must_fail git merge -s recursive E^0 2>err &&
git rev-parse --verify :subdir/a >actual &&
test_cmp expect actual &&
- test_i18ngrep "changes to the following files would be overwritten" err
+ test_grep "changes to the following files would be overwritten" err
'
test_expect_success 'recursive, when file has staged changes matching what a merge would give' '
@@ -210,7 +210,7 @@ test_expect_success 'recursive, when file has staged changes matching what a mer
test_must_fail git merge -s recursive E^0 2>err &&
git rev-parse --verify :subdir/a >actual &&
test_cmp expect actual &&
- test_i18ngrep "changes to the following files would be overwritten" err
+ test_grep "changes to the following files would be overwritten" err
'
test_expect_success 'octopus, unrelated file touched' '
diff --git a/t/t6425-merge-rename-delete.sh b/t/t6425-merge-rename-delete.sh
index 93cd2869b1..c15d031b16 100755
--- a/t/t6425-merge-rename-delete.sh
+++ b/t/t6425-merge-rename-delete.sh
@@ -4,7 +4,6 @@ test_description='Merge-recursive rename/delete conflict message'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'rename/delete' '
@@ -21,8 +20,8 @@ test_expect_success 'rename/delete' '
git commit -m "delete" &&
test_must_fail git merge --strategy=recursive rename >output &&
- test_i18ngrep "CONFLICT (rename/delete): A.* renamed .*to B.* in rename" output &&
- test_i18ngrep "CONFLICT (rename/delete): A.*deleted in HEAD." output
+ test_grep "CONFLICT (rename/delete): A.* renamed .*to B.* in rename" output &&
+ test_grep "CONFLICT (rename/delete): A.*deleted in HEAD." output
'
test_done
diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh
index fd21c1a486..b059475ed0 100755
--- a/t/t6426-merge-skip-unneeded-updates.sh
+++ b/t/t6426-merge-skip-unneeded-updates.sh
@@ -375,7 +375,7 @@ test_expect_success '2c: Modify b & add c VS rename b->c' '
export GIT_MERGE_VERBOSITY &&
test_must_fail git merge -s recursive B^0 >out 2>err &&
- test_i18ngrep "CONFLICT (.*/add):" out &&
+ test_grep "CONFLICT (.*/add):" out &&
test_must_be_empty err &&
git ls-files -s >index_files &&
diff --git a/t/t6429-merge-sequence-rename-caching.sh b/t/t6429-merge-sequence-rename-caching.sh
index d02fa16614..0f39ed0d08 100755
--- a/t/t6429-merge-sequence-rename-caching.sh
+++ b/t/t6429-merge-sequence-rename-caching.sh
@@ -71,8 +71,9 @@ test_expect_success 'caching renames does not preclude finding new ones' '
git switch upstream &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream~1..topic
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
git ls-files >tracked-files &&
test_line_count = 2 tracked-files &&
@@ -140,8 +141,9 @@ test_expect_success 'cherry-pick both a commit and its immediate revert' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream~1..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 1 calls
@@ -199,8 +201,9 @@ test_expect_success 'rename same file identically, then reintroduce it' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream~1..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
git ls-files >tracked &&
test_line_count = 2 tracked &&
@@ -276,8 +279,9 @@ test_expect_success 'rename same file identically, then add file to old dir' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream~1..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
git ls-files >tracked &&
test_line_count = 4 tracked &&
@@ -353,10 +357,7 @@ test_expect_success 'cached dir rename does not prevent noticing later conflict'
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test_must_fail test-tool fast-rebase --onto HEAD upstream~1 topic >output &&
- #git cherry-pick upstream..topic &&
-
- grep CONFLICT..rename/rename output &&
+ test_must_fail git replay --onto HEAD upstream~1..topic >output &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 2 calls
@@ -455,8 +456,9 @@ test_expect_success 'dir rename unneeded, then add new file to old dir' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 2 calls &&
@@ -521,8 +523,9 @@ test_expect_success 'dir rename unneeded, then rename existing file into old dir
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 3 calls &&
@@ -623,8 +626,9 @@ test_expect_success 'caching renames only on upstream side, part 1' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 1 calls &&
@@ -681,8 +685,9 @@ test_expect_success 'caching renames only on upstream side, part 2' '
GIT_TRACE2_PERF="$(pwd)/trace.output" &&
export GIT_TRACE2_PERF &&
- test-tool fast-rebase --onto HEAD upstream~1 topic &&
- #git cherry-pick upstream..topic &&
+ git replay --onto HEAD upstream~1..topic >out &&
+ git update-ref --stdin <out &&
+ git checkout topic &&
grep region_enter.*diffcore_rename trace.output >calls &&
test_line_count = 2 calls &&
diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh
index 07067bb347..ca15e6dd6d 100755
--- a/t/t6430-merge-recursive.sh
+++ b/t/t6430-merge-recursive.sh
@@ -308,13 +308,13 @@ test_expect_success 'fail if the index has unresolved entries' '
test_must_fail git merge "$c5" &&
test_must_fail git merge "$c5" 2> out &&
- test_i18ngrep "not possible because you have unmerged files" out &&
+ test_grep "not possible because you have unmerged files" out &&
git add -u &&
test_must_fail git merge "$c5" 2> out &&
- test_i18ngrep "You have not concluded your merge" out &&
+ test_grep "You have not concluded your merge" out &&
rm -f .git/MERGE_HEAD &&
test_must_fail git merge "$c5" 2> out &&
- test_i18ngrep "Your local changes to the following files would be overwritten by merge:" out
+ test_grep "Your local changes to the following files would be overwritten by merge:" out
'
test_expect_success 'merge-recursive remove conflict' '
@@ -713,7 +713,7 @@ test_expect_success 'merge-recursive remembers the names of all base trees' '
test_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out &&
# ...but make sure it fails in the expected way
- test_i18ngrep CONFLICT.*rename/rename out &&
+ test_grep CONFLICT.*rename/rename out &&
# merge-recursive prints in reverse order, but we do not care
sort <trees >expect &&
diff --git a/t/t6431-merge-criscross.sh b/t/t6431-merge-criscross.sh
index 3fe14cd73e..3824756a02 100755
--- a/t/t6431-merge-criscross.sh
+++ b/t/t6431-merge-criscross.sh
@@ -2,7 +2,6 @@
test_description='merge-recursive backend test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# A <- create some files
diff --git a/t/t6433-merge-toplevel.sh b/t/t6433-merge-toplevel.sh
index b16031465f..0f611c4003 100755
--- a/t/t6433-merge-toplevel.sh
+++ b/t/t6433-merge-toplevel.sh
@@ -151,7 +151,7 @@ test_expect_success 'refuse two-project merge by default, quit before --autostas
echo change >>one.t &&
git diff >expect &&
test_must_fail git merge --autostash five 2>err &&
- test_i18ngrep ! "stash" err &&
+ test_grep ! "stash" err &&
git diff >actual &&
test_cmp expect actual
'
@@ -169,7 +169,7 @@ test_expect_success 'two-project merge with --allow-unrelated-histories with --a
echo change >>one.t &&
git diff one.t >expect &&
git merge --allow-unrelated-histories --autostash five 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git diff one.t >actual &&
test_cmp expect actual
'
diff --git a/t/t6435-merge-sparse.sh b/t/t6435-merge-sparse.sh
index 78628fb248..fde4aa3cd1 100755
--- a/t/t6435-merge-sparse.sh
+++ b/t/t6435-merge-sparse.sh
@@ -3,7 +3,6 @@
test_description='merge with sparse files'
TEST_CREATE_REPO_NO_TEMPLATE=1
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# test_file $filename $content
diff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh
index c0b7bd7c3f..4f4376421e 100755
--- a/t/t6436-merge-overwrite.sh
+++ b/t/t6436-merge-overwrite.sh
@@ -104,12 +104,12 @@ test_expect_success 'will not overwrite unstaged changes in renamed file' '
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_must_fail git merge c1a >out 2>err &&
- test_i18ngrep "would be overwritten by merge" err &&
+ test_grep "would be overwritten by merge" err &&
test_cmp important other.c &&
test_path_is_missing .git/MERGE_HEAD
else
test_must_fail git merge c1a >out &&
- test_i18ngrep "Refusing to lose dirty file at other.c" out &&
+ test_grep "Refusing to lose dirty file at other.c" out &&
test_path_is_file other.c~HEAD &&
test $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&
test_cmp important other.c
diff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh
index c9a86f2e94..4815559157 100755
--- a/t/t6437-submodule-merge.sh
+++ b/t/t6437-submodule-merge.sh
@@ -112,7 +112,7 @@ test_expect_success 'merging should conflict for non fast-forward' '
git checkout -b test-nonforward-a b &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test_must_fail git merge c >actual &&
+ test_must_fail git merge c 2>actual &&
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
grep "$sub_expect" actual
else
@@ -153,9 +153,9 @@ test_expect_success 'merging should conflict for non fast-forward (resolution ex
git rev-parse --short sub-d > ../expect) &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test_must_fail git merge c >actual &&
+ test_must_fail git merge c >actual 2>sub-actual &&
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
- grep "$sub_expect" actual
+ grep "$sub_expect" sub-actual
else
test_must_fail git merge c 2> actual
fi &&
@@ -180,9 +180,9 @@ test_expect_success 'merging should fail for ambiguous common parent' '
) &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
- test_must_fail git merge c >actual &&
+ test_must_fail git merge c >actual 2>sub-actual &&
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
- grep "$sub_expect" actual
+ grep "$sub_expect" sub-actual
else
test_must_fail git merge c 2> actual
fi &&
@@ -226,7 +226,7 @@ test_expect_success 'merging should fail for changes that are backwards' '
git commit -a -m "f" &&
git checkout -b test-backward e &&
- test_must_fail git merge f >actual &&
+ test_must_fail git merge f 2>actual &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)" &&
@@ -479,7 +479,7 @@ test_expect_merge_algorithm failure success !FAIL_PREREQS 'directory/submodule c
# We do not want files within the submodule to prevent the
# merge from starting; we should not be writing to such paths
# anyway.
- test_i18ngrep ! "refusing to lose untracked file at" err
+ test_grep ! "refusing to lose untracked file at" err
)
'
@@ -534,7 +534,7 @@ test_expect_success 'merging should fail with no merge base' '
git checkout -b b init &&
git add sub &&
git commit -m "b" &&
- test_must_fail git merge a >actual &&
+ test_must_fail git merge a 2>actual &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)" &&
diff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh
index 0cbec57cda..55bd744a3f 100755
--- a/t/t6439-merge-co-error-msgs.sh
+++ b/t/t6439-merge-co-error-msgs.sh
@@ -5,7 +5,6 @@ test_description='unpack-trees error messages'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
@@ -65,7 +64,7 @@ Please move or remove them before you merge.
Aborting
EOF
-test_expect_success 'untracked files or local changes ovewritten by merge' '
+test_expect_success 'untracked files or local changes overwritten by merge' '
git add two &&
git add three &&
git add four &&
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index 69509d0c11..5378455968 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -11,23 +11,7 @@ test_expect_success 'setup' '
# behavior, make sure we always pack everything to one pack by
# default
git config gc.bigPackThreshold 2g &&
-
- # These are simply values which, when hashed as a blob with a newline,
- # produce a hash where the first byte is 0x17 in their respective
- # algorithms.
- test_oid_cache <<-EOF
- obj1 sha1:263
- obj1 sha256:34
-
- obj2 sha1:410
- obj2 sha256:174
-
- obj3 sha1:523
- obj3 sha256:313
-
- obj4 sha1:790
- obj4 sha256:481
- EOF
+ test_oid_init
'
test_expect_success 'gc empty repository' '
@@ -41,7 +25,7 @@ test_expect_success 'gc does not leave behind pid file' '
test_expect_success 'gc --gobbledegook' '
test_expect_code 129 git gc --nonsense 2>err &&
- test_i18ngrep "[Uu]sage: git gc" err
+ test_grep "[Uu]sage: git gc" err
'
test_expect_success 'gc -h with invalid configuration' '
@@ -52,7 +36,7 @@ test_expect_success 'gc -h with invalid configuration' '
echo "[gc] pruneexpire = CORRUPT" >>.git/config &&
test_expect_code 129 git gc -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage" broken/usage
+ test_grep "[Uu]sage" broken/usage
'
test_expect_success 'gc is not aborted due to a stale symref' '
@@ -114,8 +98,8 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '
# We need to create two object whose sha1s start with 17
# since this is what git gc counts. As it happens, these
# two blobs will do so.
- test_commit "$(test_oid obj1)" &&
- test_commit "$(test_oid obj2)" &&
+ test_commit "$(test_oid blob17_1)" &&
+ test_commit "$(test_oid blob17_2)" &&
git gc --auto >../out.actual 2>../err.actual
) &&
@@ -146,16 +130,16 @@ test_expect_success 'auto gc with too many loose objects does not attempt to cre
# We need to create two object whose sha1s start with 17
# since this is what git gc counts. As it happens, these
# two blobs will do so.
- test_commit "$(test_oid obj1)" &&
- test_commit "$(test_oid obj2)" &&
+ test_commit "$(test_oid blob17_1)" &&
+ test_commit "$(test_oid blob17_2)" &&
# Our first gc will create a pack; our second will create a second pack
git gc --auto &&
ls .git/objects/pack/pack-*.pack | sort >existing_packs &&
- test_commit "$(test_oid obj3)" &&
- test_commit "$(test_oid obj4)" &&
+ test_commit "$(test_oid blob17_3)" &&
+ test_commit "$(test_oid blob17_4)" &&
git gc --auto 2>err &&
- test_i18ngrep ! "^warning:" err &&
+ test_grep ! "^warning:" err &&
ls .git/objects/pack/pack-*.pack | sort >post_packs &&
comm -1 -3 existing_packs post_packs >new &&
comm -2 -3 existing_packs post_packs >del &&
@@ -166,15 +150,15 @@ test_expect_success 'auto gc with too many loose objects does not attempt to cre
test_expect_success 'gc --no-quiet' '
GIT_PROGRESS_DELAY=0 git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr &&
test_must_be_empty stdout &&
- test_i18ngrep "Computing commit graph generation numbers" stderr
+ test_grep "Computing commit graph generation numbers" stderr
'
test_expect_success TTY 'with TTY: gc --no-quiet' '
test_terminal env GIT_PROGRESS_DELAY=0 \
git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr &&
test_must_be_empty stdout &&
- test_i18ngrep "Enumerating objects" stderr &&
- test_i18ngrep "Computing commit graph generation numbers" stderr
+ test_grep "Enumerating objects" stderr &&
+ test_grep "Computing commit graph generation numbers: 100% (4/4), done." stderr
'
test_expect_success 'gc --quiet' '
@@ -202,6 +186,30 @@ test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "e
grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out
'
+test_expect_success 'gc.repackFilter launches repack with a filter' '
+ git clone --no-local --bare . bare.git &&
+
+ git -C bare.git -c gc.cruftPacks=false gc &&
+ test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+
+ GIT_TRACE=$(pwd)/trace.out git -C bare.git -c gc.repackFilter=blob:none \
+ -c repack.writeBitmaps=false -c gc.cruftPacks=false gc &&
+ test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack &&
+ grep -E "^trace: (built-in|exec|run_command): git repack .* --filter=blob:none ?.*" trace.out
+'
+
+test_expect_success 'gc.repackFilterTo store filtered out objects' '
+ test_when_finished "rm -rf bare.git filtered.git" &&
+
+ git init --bare filtered.git &&
+ git -C bare.git -c gc.repackFilter=blob:none \
+ -c gc.repackFilterTo=../filtered.git/objects/pack/pack \
+ -c repack.writeBitmaps=false -c gc.cruftPacks=false gc &&
+
+ test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+ test_stdout_line_count = 1 ls filtered.git/objects/pack/*.pack
+'
+
prepare_cruft_history () {
test_commit base &&
@@ -303,14 +311,41 @@ test_expect_success 'gc.bigPackThreshold ignores cruft packs' '
)
'
-run_and_wait_for_auto_gc () {
+cruft_max_size_opts="git repack -d -l --cruft --cruft-expiration=2.weeks.ago"
+
+test_expect_success 'setup for --max-cruft-size tests' '
+ git init cruft--max-size &&
+ (
+ cd cruft--max-size &&
+ prepare_cruft_history
+ )
+'
+
+test_expect_success '--max-cruft-size sets appropriate repack options' '
+ GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size \
+ gc --cruft --max-cruft-size=1M &&
+ test_subcommand $cruft_max_size_opts --max-cruft-size=1048576 <trace2.txt
+'
+
+test_expect_success 'gc.maxCruftSize sets appropriate repack options' '
+ GIT_TRACE2_EVENT=$(pwd)/trace2.txt \
+ git -C cruft--max-size -c gc.maxCruftSize=2M gc --cruft &&
+ test_subcommand $cruft_max_size_opts --max-cruft-size=2097152 <trace2.txt &&
+
+ GIT_TRACE2_EVENT=$(pwd)/trace2.txt \
+ git -C cruft--max-size -c gc.maxCruftSize=2M gc --cruft \
+ --max-cruft-size=3M &&
+ test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt
+'
+
+run_and_wait_for_gc () {
# We read stdout from gc for the side effect of waiting until the
# background gc process exits, closing its fd 9. Furthermore, the
# variable assignment from a command substitution preserves the
# exit status of the main gc process.
# Note: this fd trickery doesn't work on Windows, but there is no
# need to, because on Win the auto gc always runs in the foreground.
- doesnt_matter=$(git gc --auto 9>&1)
+ doesnt_matter=$(git gc "$@" 9>&1)
}
test_expect_success 'background auto gc does not run if gc.log is present and recent but does if it is old' '
@@ -321,12 +356,12 @@ test_expect_success 'background auto gc does not run if gc.log is present and re
test_config gc.autodetach true &&
echo fleem >.git/gc.log &&
git gc --auto 2>err &&
- test_i18ngrep "^warning:" err &&
+ test_grep "^warning:" err &&
test_config gc.logexpiry 5.days &&
test-tool chmtime =-345600 .git/gc.log &&
git gc --auto &&
test_config gc.logexpiry 2.days &&
- run_and_wait_for_auto_gc &&
+ run_and_wait_for_gc --auto &&
ls .git/objects/pack/pack-*.pack >packs &&
test_line_count = 1 packs
'
@@ -356,11 +391,48 @@ test_expect_success 'background auto gc respects lock for all operations' '
printf "%d %s" "$shell_pid" "$hostname" >.git/gc.pid &&
# our gc should exit zero without doing anything
- run_and_wait_for_auto_gc &&
+ run_and_wait_for_gc --auto &&
(ls -1 .git/refs/heads .git/reftable >actual || true) &&
test_cmp expect actual
'
+test_expect_success '--detach overrides gc.autoDetach=false' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ # Prepare the repository such that git-gc(1) ends up repacking.
+ test_commit "$(test_oid blob17_1)" &&
+ test_commit "$(test_oid blob17_2)" &&
+ git config gc.autodetach false &&
+ git config gc.auto 2 &&
+
+ # Note that we cannot use `test_cmp` here to compare stderr
+ # because it may contain output from `set -x`.
+ run_and_wait_for_gc --auto --detach 2>actual &&
+ test_grep "Auto packing the repository in background for optimum performance." actual
+ )
+'
+
+test_expect_success '--no-detach overrides gc.autoDetach=true' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ # Prepare the repository such that git-gc(1) ends up repacking.
+ test_commit "$(test_oid blob17_1)" &&
+ test_commit "$(test_oid blob17_2)" &&
+ git config gc.autodetach true &&
+ git config gc.auto 2 &&
+
+ GIT_PROGRESS_DELAY=0 git gc --auto --no-detach 2>output &&
+ test_grep "Auto packing the repository for optimum performance." output &&
+ test_grep "Collecting referenced commits: 2, done." output
+ )
+'
+
# DO NOT leave a detached auto gc process running near the end of the
# test script: it can run long enough in the background to racily
# interfere with the cleanup in 'test_done'.
diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh
index 4521508b83..ddef1ca391 100755
--- a/t/t6501-freshen-objects.sh
+++ b/t/t6501-freshen-objects.sh
@@ -28,7 +28,6 @@ test_description='check pruning of dependent objects'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# We care about reachability, so we do not want to use
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index b330945f49..2591f8b8b3 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -612,4 +612,125 @@ test_expect_success 'for-each-ref merged:none' '
--format="%(refname)" --stdin
'
+# For get_branch_base_for_tip, we only care about
+# first-parent history. Here is the test graph with
+# second parents removed:
+#
+# (10,10)
+# /
+# (10,9) (9,10)
+# / /
+# (10,8) (9,9) (8,10)
+# / / /
+# ( continued...)
+# \ / / /
+# (3,1) (2,2) (1,3)
+# \ / /
+# (2,1) (1,2)
+# \ /
+# (1,1)
+#
+# In short, for a commit (i,j), the first-parent history
+# walks all commits (i, k) with k from j to 1, then the
+# commits (l, 1) with l from i to 1.
+
+test_expect_success 'get_branch_base_for_tip: none reach' '
+ # (2,3) branched from the first tip (i,4) in X with i > 2
+ cat >input <<-\EOF &&
+ A:commit-2-3
+ X:commit-1-2
+ X:commit-1-4
+ X:commit-4-4
+ X:commit-8-4
+ X:commit-10-4
+ EOF
+ echo "get_branch_base_for_tip(A,X):2" >expect &&
+ test_all_modes get_branch_base_for_tip
+'
+
+test_expect_success 'get_branch_base_for_tip: equal to tip' '
+ # (2,3) branched from the first tip (i,4) in X with i > 2
+ cat >input <<-\EOF &&
+ A:commit-8-4
+ X:commit-1-2
+ X:commit-1-4
+ X:commit-4-4
+ X:commit-8-4
+ X:commit-10-4
+ EOF
+ echo "get_branch_base_for_tip(A,X):3" >expect &&
+ test_all_modes get_branch_base_for_tip
+'
+
+test_expect_success 'get_branch_base_for_tip: all reach tip' '
+ # (2,3) branched from the first tip (i,4) in X with i > 2
+ cat >input <<-\EOF &&
+ A:commit-4-1
+ X:commit-4-2
+ X:commit-5-1
+ EOF
+ echo "get_branch_base_for_tip(A,X):0" >expect &&
+ test_all_modes get_branch_base_for_tip
+'
+
+test_expect_success 'for-each-ref is-base: none reach' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-4-2
+ refs/heads/commit-4-4
+ refs/heads/commit-8-4
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1:
+ refs/heads/commit-4-2:(commit-2-3)
+ refs/heads/commit-4-4:
+ refs/heads/commit-8-4:
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname):%(is-base:commit-2-3)" --stdin
+'
+
+test_expect_success 'for-each-ref is-base: all reach' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-4-2
+ refs/heads/commit-5-1
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-4-2:(commit-4-1)
+ refs/heads/commit-5-1:
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname):%(is-base:commit-4-1)" --stdin
+'
+
+test_expect_success 'for-each-ref is-base: equal to tip' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-4-2
+ refs/heads/commit-5-1
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-4-2:(commit-4-2)
+ refs/heads/commit-5-1:
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname):%(is-base:commit-4-2)" --stdin
+'
+
+test_expect_success 'for-each-ref is-base:multiple' '
+ cat >input <<-\EOF &&
+ refs/heads/commit-1-1
+ refs/heads/commit-4-2
+ refs/heads/commit-4-4
+ refs/heads/commit-8-4
+ EOF
+ cat >expect <<-\EOF &&
+ refs/heads/commit-1-1[-]
+ refs/heads/commit-4-2[(commit-2-3)-]
+ refs/heads/commit-4-4[-]
+ refs/heads/commit-8-4[-(commit-6-5)]
+ EOF
+ run_all_modes git for-each-ref \
+ --format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
+'
+
test_done
diff --git a/t/t6700-tree-depth.sh b/t/t6700-tree-depth.sh
new file mode 100755
index 0000000000..0f6a2ad9b5
--- /dev/null
+++ b/t/t6700-tree-depth.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+
+test_description='handling of deep trees in various commands'
+
+. ./test-lib.sh
+
+# We'll test against two depths here: a small one that will let us check the
+# behavior of the config setting easily, and a large one that should be
+# forbidden by default. Testing the default depth will let us know whether our
+# default is enough to prevent segfaults on systems that run the tests.
+small_depth=50
+big_depth=4100
+
+small_ok="-c core.maxtreedepth=$small_depth"
+small_no="-c core.maxtreedepth=$((small_depth-1))"
+
+# usage: mkdeep <name> <depth>
+# Create a tag <name> containing a file whose path has depth <depth>.
+#
+# We'll use fast-import here for two reasons:
+#
+# 1. It's faster than creating $big_depth tree objects.
+#
+# 2. As we tighten tree limits, it's more likely to allow large sizes
+# than trying to stuff a deep path into the index.
+mkdeep () {
+ {
+ echo "commit refs/tags/$1" &&
+ echo "committer foo <foo@example.com> 1234 -0000" &&
+ echo "data <<EOF" &&
+ echo "the commit message" &&
+ echo "EOF" &&
+
+ printf 'M 100644 inline ' &&
+ i=0 &&
+ while test $i -lt $2
+ do
+ printf 'a/'
+ i=$((i+1))
+ done &&
+ echo "file" &&
+
+ echo "data <<EOF" &&
+ echo "the file contents" &&
+ echo "EOF" &&
+ echo
+ } | git fast-import
+}
+
+test_expect_success 'create small tree' '
+ mkdeep small $small_depth
+'
+
+test_expect_success 'create big tree' '
+ mkdeep big $big_depth
+'
+
+test_expect_success 'limit recursion of git-archive' '
+ git $small_ok archive small >/dev/null &&
+ test_must_fail git $small_no archive small >/dev/null
+'
+
+test_expect_success 'default limit for git-archive fails gracefully' '
+ test_must_fail git archive big >/dev/null
+'
+
+test_expect_success 'limit recursion of ls-tree -r' '
+ git $small_ok ls-tree -r small &&
+ test_must_fail git $small_no ls-tree -r small
+'
+
+test_expect_success 'default limit for ls-tree fails gracefully' '
+ test_must_fail git ls-tree -r big >/dev/null
+'
+
+test_expect_success 'limit recursion of rev-list --objects' '
+ git $small_ok rev-list --objects small >/dev/null &&
+ test_must_fail git $small_no rev-list --objects small >/dev/null
+'
+
+test_expect_success 'default limit for rev-list fails gracefully' '
+ test_must_fail git rev-list --objects big >/dev/null
+'
+
+test_expect_success 'limit recursion of diff-tree -r' '
+ git $small_ok diff-tree -r $EMPTY_TREE small &&
+ test_must_fail git $small_no diff-tree -r $EMPTY_TREE small
+'
+
+test_expect_success 'default limit for diff-tree fails gracefully' '
+ test_must_fail git diff-tree -r $EMPTY_TREE big
+'
+
+test_done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index f136ea76f7..25334b5062 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git mv in subdirs'
+
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
@@ -296,7 +297,7 @@ test_expect_success 'git mv error on conflicted file' '
EOF
test_must_fail git mv conflict newname 2>actual &&
- test_i18ngrep "conflicted" actual
+ test_grep "conflicted" actual
'
test_expect_success 'git mv should overwrite symlink to a file' '
@@ -482,7 +483,7 @@ test_expect_success 'checking out a commit before submodule moved needs manual u
git mv sub sub2 &&
git commit -m "moved sub to sub2" &&
git checkout -q HEAD^ 2>actual &&
- test_i18ngrep "^warning: unable to rmdir '\''sub2'\'':" actual &&
+ test_grep "^warning: unable to rmdir '\''sub2'\'':" actual &&
git status -s sub2 >actual &&
echo "?? sub2/" >expected &&
test_cmp expected actual &&
@@ -549,4 +550,16 @@ test_expect_success 'moving nested submodules' '
git status
'
+test_expect_failure 'nonsense mv triggers assertion failure and partially updated index' '
+ test_when_finished git reset --hard HEAD &&
+ git reset --hard HEAD &&
+ mkdir -p a &&
+ mkdir -p b &&
+ >a/a.txt &&
+ git add a/a.txt &&
+ test_must_fail git mv a/a.txt a b &&
+ git status --porcelain >actual &&
+ grep "^A[ ]*a/a.txt$" actual
+'
+
test_done
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index f6aebe92ff..5ab4d41ee7 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -396,10 +396,7 @@ test_expect_success '--prune-empty is able to prune entire branch' '
git branch prune-entire B &&
git filter-branch -f --prune-empty --index-filter "git update-index --remove A.t B.t" prune-entire &&
test_must_fail git rev-parse refs/heads/prune-entire &&
- if test_have_prereq REFFILES
- then
- test_must_fail git reflog exists refs/heads/prune-entire
- fi
+ test_must_fail git reflog exists refs/heads/prune-entire
'
test_expect_success '--remap-to-ancestor with filename filters' '
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index e689db4292..b1316e62f4 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -61,8 +61,9 @@ test_expect_success 'sort tags, ignore case' '
)
'
-test_expect_success 'looking for a tag in an empty tree should fail' \
- '! (tag_exists mytag)'
+test_expect_success 'looking for a tag in an empty tree should fail' '
+ ! (tag_exists mytag)
+'
test_expect_success 'creating a tag in an empty tree should fail' '
test_must_fail git tag mynotag &&
@@ -129,10 +130,10 @@ test_expect_success 'listing all tags if one exists should succeed' '
git tag
'
-cat >expect <<EOF
-mytag
-EOF
test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '
+ cat >expect <<-\EOF &&
+ mytag
+ EOF
git tag -l -l >actual &&
test_cmp expect actual &&
git tag --list --list >actual &&
@@ -148,32 +149,33 @@ test_expect_success 'listing all tags if one exists should output that tag' '
# pattern matching:
-test_expect_success 'listing a tag using a matching pattern should succeed' \
- 'git tag -l mytag'
+test_expect_success 'listing a tag using a matching pattern should succeed' '
+ git tag -l mytag
+'
-test_expect_success 'listing a tag with --ignore-case' \
- 'test $(git tag -l --ignore-case MYTAG) = mytag'
+test_expect_success 'listing a tag with --ignore-case' '
+ test $(git tag -l --ignore-case MYTAG) = mytag
+'
-test_expect_success \
- 'listing a tag using a matching pattern should output that tag' \
- 'test $(git tag -l mytag) = mytag'
+test_expect_success 'listing a tag using a matching pattern should output that tag' '
+ test $(git tag -l mytag) = mytag
+'
-test_expect_success \
- 'listing tags using a non-matching pattern should succeed' \
- 'git tag -l xxx'
+test_expect_success 'listing tags using a non-matching pattern should succeed' '
+ git tag -l xxx
+'
-test_expect_success \
- 'listing tags using a non-matching pattern should output nothing' \
- 'test $(git tag -l xxx | wc -l) -eq 0'
+test_expect_success 'listing tags using a non-matching pattern should output nothing' '
+ test $(git tag -l xxx | wc -l) -eq 0
+'
# special cases for creating tags:
-test_expect_success \
- 'trying to create a tag with the name of one existing should fail' \
- 'test_must_fail git tag mytag'
+test_expect_success 'trying to create a tag with the name of one existing should fail' '
+ test_must_fail git tag mytag
+'
-test_expect_success \
- 'trying to create a tag with a non-valid name should fail' '
+test_expect_success 'trying to create a tag with a non-valid name should fail' '
test $(git tag -l | wc -l) -eq 1 &&
test_must_fail git tag "" &&
test_must_fail git tag .othertag &&
@@ -207,19 +209,19 @@ test_expect_success 'trying to delete an unknown tag should fail' '
test_must_fail git tag -d unknown-tag
'
-cat >expect <<EOF
-myhead
-mytag
-EOF
-test_expect_success \
- 'trying to delete tags without params should succeed and do nothing' '
- git tag -l > actual && test_cmp expect actual &&
+test_expect_success 'trying to delete tags without params should succeed and do nothing' '
+ cat >expect <<-\EOF &&
+ myhead
+ mytag
+ EOF
+ git tag -l >actual &&
+ test_cmp expect actual &&
git tag -d &&
- git tag -l > actual && test_cmp expect actual
+ git tag -l >actual &&
+ test_cmp expect actual
'
-test_expect_success \
- 'deleting two existing tags in one command should succeed' '
+test_expect_success 'deleting two existing tags in one command should succeed' '
tag_exists mytag &&
tag_exists myhead &&
git tag -d mytag myhead &&
@@ -227,15 +229,13 @@ test_expect_success \
! tag_exists myhead
'
-test_expect_success \
- 'creating a tag with the name of another deleted one should succeed' '
+test_expect_success 'creating a tag with the name of another deleted one should succeed' '
! tag_exists mytag &&
git tag mytag &&
tag_exists mytag
'
-test_expect_success \
- 'trying to delete two tags, existing and not, should fail in the 2nd' '
+test_expect_success 'trying to delete two tags, existing and not, should fail in the 2nd' '
tag_exists mytag &&
! tag_exists nonexistingtag &&
test_must_fail git tag -d mytag nonexistingtag &&
@@ -243,23 +243,24 @@ test_expect_success \
! tag_exists nonexistingtag
'
-test_expect_success 'trying to delete an already deleted tag should fail' \
- 'test_must_fail git tag -d mytag'
+test_expect_success 'trying to delete an already deleted tag should fail' '
+ test_must_fail git tag -d mytag
+'
# listing various tags with pattern matching:
-cat >expect <<EOF
-a1
-aa1
-cba
-t210
-t211
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
test_expect_success 'listing all tags should print them ordered' '
+ cat >expect <<-\EOF &&
+ a1
+ aa1
+ cba
+ t210
+ t211
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag v1.0.1 &&
git tag t211 &&
git tag aa1 &&
@@ -269,91 +270,89 @@ test_expect_success 'listing all tags should print them ordered' '
git tag a1 &&
git tag v1.0 &&
git tag t210 &&
- git tag -l > actual &&
+ git tag -l >actual &&
test_cmp expect actual &&
- git tag > actual &&
+ git tag >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-a1
-aa1
-cba
-EOF
-test_expect_success \
- 'listing tags with substring as pattern must print those matching' '
+test_expect_success 'listing tags with substring as pattern must print those matching' '
+ cat >expect <<-\EOF &&
+ a1
+ aa1
+ cba
+ EOF
rm *a* &&
- git tag -l "*a*" > current &&
+ git tag -l "*a*" >current &&
test_cmp expect current
'
-cat >expect <<EOF
-v0.2.1
-v1.0.1
-EOF
-test_expect_success \
- 'listing tags with a suffix as pattern must print those matching' '
- git tag -l "*.1" > actual &&
+test_expect_success 'listing tags with a suffix as pattern must print those matching' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0.1
+ EOF
+ git tag -l "*.1" >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-t210
-t211
-EOF
-test_expect_success \
- 'listing tags with a prefix as pattern must print those matching' '
- git tag -l "t21*" > actual &&
+test_expect_success 'listing tags with a prefix as pattern must print those matching' '
+ cat >expect <<-\EOF &&
+ t210
+ t211
+ EOF
+ git tag -l "t21*" >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-a1
-EOF
-test_expect_success \
- 'listing tags using a name as pattern must print that one matching' '
- git tag -l a1 > actual &&
+test_expect_success 'listing tags using a name as pattern must print that one matching' '
+ cat >expect <<-\EOF &&
+ a1
+ EOF
+ git tag -l a1 >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-v1.0
-EOF
-test_expect_success \
- 'listing tags using a name as pattern must print that one matching' '
- git tag -l v1.0 > actual &&
+test_expect_success 'listing tags using a name as pattern must print that one matching' '
+ cat >expect <<-\EOF &&
+ v1.0
+ EOF
+ git tag -l v1.0 >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-v1.0.1
-v1.1.3
-EOF
-test_expect_success \
- 'listing tags with ? in the pattern should print those matching' '
- git tag -l "v1.?.?" > actual &&
+test_expect_success 'listing tags with ? in the pattern should print those matching' '
+ cat >expect <<-\EOF &&
+ v1.0.1
+ v1.1.3
+ EOF
+ git tag -l "v1.?.?" >actual &&
test_cmp expect actual
'
-test_expect_success \
- 'listing tags using v.* should print nothing because none have v.' '
- git tag -l "v.*" > actual &&
+test_expect_success 'listing tags using v.* should print nothing because none have v.' '
+ git tag -l "v.*" >actual &&
test_must_be_empty actual
'
-cat >expect <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
-test_expect_success \
- 'listing tags using v* should print only those having v' '
- git tag -l "v*" > actual &&
+test_expect_success 'listing tags using v* should print only those having v' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
+ git tag -l "v*" >actual &&
test_cmp expect actual
'
test_expect_success 'tag -l can accept multiple patterns' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag -l "v1*" "v0*" >actual &&
test_cmp expect actual
'
@@ -367,16 +366,22 @@ test_expect_success 'tag -l can accept multiple patterns' '
# out if we're going to break this long-documented form of taking
# multiple patterns.
test_expect_success 'tag -l <pattern> -l <pattern> works, as our buggy documentation previously suggested' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag -l "v1*" -l "v0*" >actual &&
test_cmp expect actual
'
test_expect_success 'listing tags in column' '
COLUMNS=41 git tag -l --column=row >actual &&
- cat >expected <<\EOF &&
-a1 aa1 cba t210 t211
-v0.2.1 v1.0 v1.0.1 v1.1.3
-EOF
+ cat >expected <<-\EOF &&
+ a1 aa1 cba t210 t211
+ v0.2.1 v1.0 v1.0.1 v1.1.3
+ EOF
test_cmp expected actual
'
@@ -384,10 +389,10 @@ test_expect_success 'listing tags in column with column.*' '
test_config column.tag row &&
test_config column.ui dense &&
COLUMNS=40 git tag -l >actual &&
- cat >expected <<\EOF &&
-a1 aa1 cba t210 t211
-v0.2.1 v1.0 v1.0.1 v1.1.3
-EOF
+ cat >expected <<-\EOF &&
+ a1 aa1 cba t210 t211
+ v0.2.1 v1.0 v1.0.1 v1.1.3
+ EOF
test_cmp expected actual
'
@@ -398,39 +403,39 @@ test_expect_success 'listing tag with -n --column should fail' '
test_expect_success 'listing tags -n in column with column.ui ignored' '
test_config column.ui "row dense" &&
COLUMNS=40 git tag -l -n >actual &&
- cat >expected <<\EOF &&
-a1 Foo
-aa1 Foo
-cba Foo
-t210 Foo
-t211 Foo
-v0.2.1 Foo
-v1.0 Foo
-v1.0.1 Foo
-v1.1.3 Foo
-EOF
+ cat >expected <<-\EOF &&
+ a1 Foo
+ aa1 Foo
+ cba Foo
+ t210 Foo
+ t211 Foo
+ v0.2.1 Foo
+ v1.0 Foo
+ v1.0.1 Foo
+ v1.1.3 Foo
+ EOF
test_cmp expected actual
'
# creating and verifying lightweight tags:
-test_expect_success \
- 'a non-annotated tag created without parameters should point to HEAD' '
+test_expect_success 'a non-annotated tag created without parameters should point to HEAD' '
git tag non-annotated-tag &&
test $(git cat-file -t non-annotated-tag) = commit &&
test $(git rev-parse non-annotated-tag) = $(git rev-parse HEAD)
'
-test_expect_success 'trying to verify an unknown tag should fail' \
- 'test_must_fail git tag -v unknown-tag'
+test_expect_success 'trying to verify an unknown tag should fail' '
+ test_must_fail git tag -v unknown-tag
+'
-test_expect_success \
- 'trying to verify a non-annotated and non-signed tag should fail' \
- 'test_must_fail git tag -v non-annotated-tag'
+test_expect_success 'trying to verify a non-annotated and non-signed tag should fail' '
+ test_must_fail git tag -v non-annotated-tag
+'
-test_expect_success \
- 'trying to verify many non-annotated or unknown tags, should fail' \
- 'test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2'
+test_expect_success 'trying to verify many non-annotated or unknown tags, should fail' '
+ test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2
+'
# creating annotated tags:
@@ -449,83 +454,78 @@ tagger C O Mitter <committer@example.com> $4 -0700
EOF
}
-commit=$(git rev-parse HEAD)
-time=$test_tick
-
-get_tag_header annotated-tag $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success \
- 'creating an annotated tag with -m message should succeed' '
+test_expect_success 'creating an annotated tag with -m message should succeed' '
+ commit=$(git rev-parse HEAD) &&
+ time=$test_tick &&
+ get_tag_header annotated-tag $commit commit $time >expect &&
+ echo "A message" >>expect &&
git tag -m "A message" annotated-tag &&
get_tag_msg annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header annotated-tag-edit $commit commit $time >expect
-echo "An edited message" >>expect
test_expect_success 'set up editor' '
write_script fakeeditor <<-\EOF
sed -e "s/A message/An edited message/g" <"$1" >"$1-"
mv "$1-" "$1"
EOF
'
-test_expect_success \
- 'creating an annotated tag with -m message --edit should succeed' '
+
+test_expect_success 'creating an annotated tag with -m message --edit should succeed' '
+ get_tag_header annotated-tag-edit $commit commit $time >expect &&
+ echo "An edited message" >>expect &&
GIT_EDITOR=./fakeeditor git tag -m "A message" --edit annotated-tag-edit &&
get_tag_msg annotated-tag-edit >actual &&
test_cmp expect actual
'
-cat >msgfile <<EOF
-Another message
-in a file.
-EOF
-get_tag_header file-annotated-tag $commit commit $time >expect
-cat msgfile >>expect
-test_expect_success \
- 'creating an annotated tag with -F messagefile should succeed' '
+test_expect_success 'creating an annotated tag with -F messagefile should succeed' '
+ cat >msgfile <<-\EOF &&
+ Another message
+ in a file.
+ EOF
+ get_tag_header file-annotated-tag $commit commit $time >expect &&
+ cat msgfile >>expect &&
git tag -F msgfile file-annotated-tag &&
get_tag_msg file-annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header file-annotated-tag-edit $commit commit $time >expect
-sed -e "s/Another message/Another edited message/g" msgfile >>expect
test_expect_success 'set up editor' '
write_script fakeeditor <<-\EOF
sed -e "s/Another message/Another edited message/g" <"$1" >"$1-"
mv "$1-" "$1"
EOF
'
-test_expect_success \
- 'creating an annotated tag with -F messagefile --edit should succeed' '
+
+test_expect_success 'creating an annotated tag with -F messagefile --edit should succeed' '
+ get_tag_header file-annotated-tag-edit $commit commit $time >expect &&
+ sed -e "s/Another message/Another edited message/g" msgfile >>expect &&
GIT_EDITOR=./fakeeditor git tag -F msgfile --edit file-annotated-tag-edit &&
get_tag_msg file-annotated-tag-edit >actual &&
test_cmp expect actual
'
-cat >inputmsg <<EOF
-A message from the
-standard input
-EOF
-get_tag_header stdin-annotated-tag $commit commit $time >expect
-cat inputmsg >>expect
test_expect_success 'creating an annotated tag with -F - should succeed' '
+ cat >inputmsg <<-\EOF &&
+ A message from the
+ standard input
+ EOF
+ get_tag_header stdin-annotated-tag $commit commit $time >expect &&
+ cat inputmsg >>expect &&
git tag -F - stdin-annotated-tag <inputmsg &&
get_tag_msg stdin-annotated-tag >actual &&
test_cmp expect actual
'
-test_expect_success \
- 'trying to create a tag with a non-existing -F file should fail' '
+test_expect_success 'trying to create a tag with a non-existing -F file should fail' '
! test -f nonexistingfile &&
! tag_exists notag &&
test_must_fail git tag -F nonexistingfile notag &&
! tag_exists notag
'
-test_expect_success \
- 'trying to create tags giving both -m or -F options should fail' '
+test_expect_success 'trying to create tags giving both -m or -F options should fail' '
echo "message file 1" >msgfile1 &&
! tag_exists msgtag &&
test_must_fail git tag -m "message 1" -F msgfile1 msgtag &&
@@ -539,67 +539,61 @@ test_expect_success \
# blank and empty messages:
-get_tag_header empty-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with an empty -m message should succeed' '
+test_expect_success 'creating a tag with an empty -m message should succeed' '
+ get_tag_header empty-annotated-tag $commit commit $time >expect &&
git tag -m "" empty-annotated-tag &&
get_tag_msg empty-annotated-tag >actual &&
test_cmp expect actual
'
->emptyfile
-get_tag_header emptyfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with an empty -F messagefile should succeed' '
+test_expect_success 'creating a tag with an empty -F messagefile should succeed' '
+ >emptyfile &&
+ get_tag_header emptyfile-annotated-tag $commit commit $time >expect &&
git tag -F emptyfile emptyfile-annotated-tag &&
get_tag_msg emptyfile-annotated-tag >actual &&
test_cmp expect actual
'
-printf '\n\n \n\t\nLeading blank lines\n' >blanksfile
-printf '\n\t \t \nRepeated blank lines\n' >>blanksfile
-printf '\n\n\nTrailing spaces \t \n' >>blanksfile
-printf '\nTrailing blank lines\n\n\t \n\n' >>blanksfile
-get_tag_header blanks-annotated-tag $commit commit $time >expect
-cat >>expect <<EOF
-Leading blank lines
+test_expect_success 'extra blanks in the message for an annotated tag should be removed' '
+ printf "\n\n \n\t\nLeading blank lines\n" >blanksfile &&
+ printf "\n\t \t \nRepeated blank lines\n" >>blanksfile &&
+ printf "\n\n\nTrailing spaces \t \n" >>blanksfile &&
+ printf "\nTrailing blank lines\n\n\t \n\n" >>blanksfile &&
+ get_tag_header blanks-annotated-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ Leading blank lines
-Repeated blank lines
+ Repeated blank lines
-Trailing spaces
+ Trailing spaces
-Trailing blank lines
-EOF
-test_expect_success \
- 'extra blanks in the message for an annotated tag should be removed' '
+ Trailing blank lines
+ EOF
git tag -F blanksfile blanks-annotated-tag &&
get_tag_msg blanks-annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header blank-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with blank -m message with spaces should succeed' '
+test_expect_success 'creating a tag with blank -m message with spaces should succeed' '
+ get_tag_header blank-annotated-tag $commit commit $time >expect &&
git tag -m " " blank-annotated-tag &&
get_tag_msg blank-annotated-tag >actual &&
test_cmp expect actual
'
-echo ' ' >blankfile
-echo '' >>blankfile
-echo ' ' >>blankfile
-get_tag_header blankfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with blank -F messagefile with spaces should succeed' '
+test_expect_success 'creating a tag with blank -F messagefile with spaces should succeed' '
+ echo " " >blankfile &&
+ echo "" >>blankfile &&
+ echo " " >>blankfile &&
+ get_tag_header blankfile-annotated-tag $commit commit $time >expect &&
git tag -F blankfile blankfile-annotated-tag &&
get_tag_msg blankfile-annotated-tag >actual &&
test_cmp expect actual
'
-printf ' ' >blanknonlfile
-get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with -F file of spaces and no newline should succeed' '
+test_expect_success 'creating a tag with -F file of spaces and no newline should succeed' '
+ printf " " >blanknonlfile &&
+ get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect &&
git tag -F blanknonlfile blanknonlfile-annotated-tag &&
get_tag_msg blanknonlfile-annotated-tag >actual &&
test_cmp expect actual
@@ -607,71 +601,175 @@ test_expect_success \
# messages with commented lines:
-cat >commentsfile <<EOF
-# A comment
+test_expect_success 'creating a tag using a -F messagefile with #comments should succeed' '
+ cat >commentsfile <<-\EOF &&
+ # A comment
-############
-The message.
-############
-One line.
+ ############
+ The message.
+ ############
+ One line.
-# commented lines
-# commented lines
+ # commented lines
+ # commented lines
-Another line.
-# comments
+ Another line.
+ # comments
-Last line.
-EOF
-get_tag_header comments-annotated-tag $commit commit $time >expect
-cat >>expect <<EOF
-The message.
-One line.
+ Last line.
+ EOF
+ get_tag_header comments-annotated-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ The message.
+ One line.
-Another line.
+ Another line.
-Last line.
-EOF
-test_expect_success \
- 'creating a tag using a -F messagefile with #comments should succeed' '
+ Last line.
+ EOF
git tag -F commentsfile comments-annotated-tag &&
get_tag_msg comments-annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header comment-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with a #comment in the -m message should succeed' '
+test_expect_success 'creating a tag with a #comment in the -m message should succeed' '
+ get_tag_header comment-annotated-tag $commit commit $time >expect &&
git tag -m "#comment" comment-annotated-tag &&
get_tag_msg comment-annotated-tag >actual &&
test_cmp expect actual
'
-echo '#comment' >commentfile
-echo '' >>commentfile
-echo '####' >>commentfile
-get_tag_header commentfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with #comments in the -F messagefile should succeed' '
+test_expect_success 'creating a tag with #comments in the -F messagefile should succeed' '
+ echo "#comment" >commentfile &&
+ echo "" >>commentfile &&
+ echo "####" >>commentfile &&
+ get_tag_header commentfile-annotated-tag $commit commit $time >expect &&
git tag -F commentfile commentfile-annotated-tag &&
get_tag_msg commentfile-annotated-tag >actual &&
test_cmp expect actual
'
-printf '#comment' >commentnonlfile
-get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with a file of #comment and no newline should succeed' '
+test_expect_success 'creating a tag with a file of #comment and no newline should succeed' '
+ printf "#comment" >commentnonlfile &&
+ get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect &&
git tag -F commentnonlfile commentnonlfile-annotated-tag &&
get_tag_msg commentnonlfile-annotated-tag >actual &&
test_cmp expect actual
'
+# trailers
+
+test_expect_success 'create tag with -m and --trailer' '
+ get_tag_header tag-with-inline-message-and-trailers $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ create tag with trailers
+
+ my-trailer: here
+ alt-trailer: there
+ EOF
+ git tag -m "create tag with trailers" \
+ --trailer my-trailer=here \
+ --trailer alt-trailer=there \
+ tag-with-inline-message-and-trailers &&
+ get_tag_msg tag-with-inline-message-and-trailers >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'list tag extracting trailers' '
+ cat >expect <<-\EOF &&
+ my-trailer: here
+ alt-trailer: there
+
+ EOF
+ git tag --list --format="%(trailers)" tag-with-inline-message-and-trailers >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'create tag with -F and --trailer' '
+ echo "create tag from message file using --trailer" >messagefilewithnotrailers &&
+ get_tag_header tag-with-file-message-and-trailers $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ create tag from message file using --trailer
+
+ my-trailer: here
+ alt-trailer: there
+ EOF
+ git tag -F messagefilewithnotrailers \
+ --trailer my-trailer=here \
+ --trailer alt-trailer=there \
+ tag-with-file-message-and-trailers &&
+ get_tag_msg tag-with-file-message-and-trailers >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'create tag with -m and --trailer and --edit' '
+ write_script fakeeditor <<-\EOF &&
+ sed -e "1s/^/EDITED: /g" <"$1" >"$1-"
+ mv "$1-" "$1"
+ EOF
+ get_tag_header tag-with-edited-inline-message-and-trailers $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ EDITED: create tag with trailers
+
+ my-trailer: here
+ alt-trailer: there
+ EOF
+ GIT_EDITOR=./fakeeditor git tag --edit \
+ -m "create tag with trailers" \
+ --trailer my-trailer=here \
+ --trailer alt-trailer=there \
+ tag-with-edited-inline-message-and-trailers &&
+ get_tag_msg tag-with-edited-inline-message-and-trailers >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'create tag with -F and --trailer and --edit' '
+ echo "create tag from message file using --trailer" >messagefilewithnotrailers &&
+ get_tag_header tag-with-edited-file-message-and-trailers $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ EDITED: create tag from message file using --trailer
+
+ my-trailer: here
+ alt-trailer: there
+ EOF
+ GIT_EDITOR=./fakeeditor git tag --edit \
+ -F messagefilewithnotrailers \
+ --trailer my-trailer=here \
+ --trailer alt-trailer=there \
+ tag-with-edited-file-message-and-trailers &&
+ get_tag_msg tag-with-edited-file-message-and-trailers >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'create annotated tag and force editor when only --trailer is given' '
+ write_script fakeeditor <<-\EOF &&
+ echo "add a line" >"$1-"
+ cat <"$1" >>"$1-"
+ mv "$1-" "$1"
+ EOF
+ get_tag_header tag-with-trailers-and-no-message $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ add a line
+
+ my-trailer: here
+ alt-trailer: there
+ EOF
+ GIT_EDITOR=./fakeeditor git tag \
+ --trailer my-trailer=here \
+ --trailer alt-trailer=there \
+ tag-with-trailers-and-no-message &&
+ get_tag_msg tag-with-trailers-and-no-message >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'bad editor causes panic when only --trailer is given' '
+ test_must_fail env GIT_EDITOR=false git tag --trailer my-trailer=here tag-will-not-exist
+'
+
# listing messages for annotated non-signed tags:
-test_expect_success \
- 'listing the one-line message of a non-signed tag should succeed' '
+test_expect_success 'listing the one-line message of a non-signed tag should succeed' '
git tag -m "A msg" tag-one-line &&
echo "tag-one-line" >expect &&
@@ -710,8 +808,7 @@ test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' '
test_cmp expect actual
'
-test_expect_success \
- 'listing the zero-lines message of a non-signed tag should succeed' '
+test_expect_success 'listing the zero-lines message of a non-signed tag should succeed' '
git tag -m "" tag-zero-lines &&
echo "tag-zero-lines" >expect &&
@@ -735,11 +832,10 @@ test_expect_success \
test_cmp expect actual
'
-echo 'tag line one' >annotagmsg
-echo 'tag line two' >>annotagmsg
-echo 'tag line three' >>annotagmsg
-test_expect_success \
- 'listing many message lines of a non-signed tag should succeed' '
+test_expect_success 'listing many message lines of a non-signed tag should succeed' '
+ echo "tag line one" >annotagmsg &&
+ echo "tag line two" >>annotagmsg &&
+ echo "tag line three" >>annotagmsg &&
git tag -F annotagmsg tag-lines &&
echo "tag-lines" >expect &&
@@ -810,6 +906,11 @@ test_expect_success 'git tag --format with ahead-behind' '
refs/tags/tag-lines 0 1 !
refs/tags/tag-one-line 0 1 !
refs/tags/tag-right 0 0 !
+ refs/tags/tag-with-edited-file-message-and-trailers 0 1 !
+ refs/tags/tag-with-edited-inline-message-and-trailers 0 1 !
+ refs/tags/tag-with-file-message-and-trailers 0 1 !
+ refs/tags/tag-with-inline-message-and-trailers 0 1 !
+ refs/tags/tag-with-trailers-and-no-message 0 1 !
refs/tags/tag-zero-lines 0 1 !
EOF
git tag -l --format="%(refname) %(ahead-behind:HEAD) !" >actual 2>err &&
@@ -822,40 +923,37 @@ test_expect_success 'git tag --format with ahead-behind' '
# trying to verify annotated non-signed tags:
-test_expect_success GPG \
- 'trying to verify an annotated non-signed tag should fail' '
+test_expect_success GPG 'trying to verify an annotated non-signed tag should fail' '
tag_exists annotated-tag &&
test_must_fail git tag -v annotated-tag
'
-test_expect_success GPG \
- 'trying to verify a file-annotated non-signed tag should fail' '
+test_expect_success GPG 'trying to verify a file-annotated non-signed tag should fail' '
tag_exists file-annotated-tag &&
test_must_fail git tag -v file-annotated-tag
'
-test_expect_success GPG \
- 'trying to verify two annotated non-signed tags should fail' '
+test_expect_success GPG 'trying to verify two annotated non-signed tags should fail' '
tag_exists annotated-tag file-annotated-tag &&
test_must_fail git tag -v annotated-tag file-annotated-tag
'
# creating and verifying signed tags:
-get_tag_header signed-tag $commit commit $time >expect
-echo 'A signed tag message' >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'creating a signed tag with -m message should succeed' '
+ get_tag_header signed-tag $commit commit $time >expect &&
+ echo "A signed tag message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A signed tag message" signed-tag &&
get_tag_msg signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header u-signed-tag $commit commit $time >expect
-echo 'Another message' >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'sign with a given key id' '
+ get_tag_header u-signed-tag $commit commit $time >expect &&
+ echo "Another message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -u committer@example.com -m "Another message" u-signed-tag &&
get_tag_msg u-signed-tag >actual &&
test_cmp expect actual
@@ -875,137 +973,128 @@ test_expect_success GPG 'sign with an unknown id (2)' '
'
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-test -n "$1" && exec >"$1"
-echo A signed tag message
-echo from a fake editor.
-EOF
-chmod +x fakeeditor
-
-get_tag_header implied-sign $commit commit $time >expect
-./fakeeditor >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG '-u implies signed tag' '
+ write_script fakeeditor <<-\EOF &&
+ test -n "$1" && exec >"$1"
+ echo A signed tag message
+ echo from a fake editor.
+ EOF
+
+ get_tag_header implied-sign $commit commit $time >expect &&
+ ./fakeeditor >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
GIT_EDITOR=./fakeeditor git tag -u CDDE430D implied-sign &&
get_tag_msg implied-sign >actual &&
test_cmp expect actual
'
-cat >sigmsgfile <<EOF
-Another signed tag
-message in a file.
-EOF
-get_tag_header file-signed-tag $commit commit $time >expect
-cat sigmsgfile >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with -F messagefile should succeed' '
+ cat >sigmsgfile <<-\EOF &&
+ Another signed tag
+ message in a file.
+ EOF
+ get_tag_header file-signed-tag $commit commit $time >expect &&
+ cat sigmsgfile >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigmsgfile file-signed-tag &&
get_tag_msg file-signed-tag >actual &&
test_cmp expect actual
'
-cat >siginputmsg <<EOF
-A signed tag message from
-the standard input
-EOF
-get_tag_header stdin-signed-tag $commit commit $time >expect
-cat siginputmsg >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'creating a signed tag with -F - should succeed' '
+ cat >siginputmsg <<-\EOF &&
+ A signed tag message from
+ the standard input
+ EOF
+ get_tag_header stdin-signed-tag $commit commit $time >expect &&
+ cat siginputmsg >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F - stdin-signed-tag <siginputmsg &&
get_tag_msg stdin-signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header implied-annotate $commit commit $time >expect
-./fakeeditor >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG '-s implies annotated tag' '
+ get_tag_header implied-annotate $commit commit $time >expect &&
+ ./fakeeditor >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
GIT_EDITOR=./fakeeditor git tag -s implied-annotate &&
get_tag_msg implied-annotate >actual &&
test_cmp expect actual
'
-get_tag_header forcesignannotated-implied-sign $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'git tag -s implied if configured with tag.forcesignannotated' \
- 'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'git tag -s implied if configured with tag.forcesignannotated' '
+ get_tag_header forcesignannotated-implied-sign $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+ test_config tag.forcesignannotated true &&
git tag -m "A message" forcesignannotated-implied-sign &&
get_tag_msg forcesignannotated-implied-sign >actual &&
test_cmp expect actual
'
-test_expect_success GPG \
- 'lightweight with no message when configured with tag.forcesignannotated' \
- 'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'lightweight with no message when configured with tag.forcesignannotated' '
+ test_config tag.forcesignannotated true &&
git tag forcesignannotated-lightweight &&
tag_exists forcesignannotated-lightweight &&
test_must_fail git tag -v forcesignannotated-no-message
'
-get_tag_header forcesignannotated-annotate $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success GPG \
- 'git tag -a disable configured tag.forcesignannotated' \
- 'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'git tag -a disable configured tag.forcesignannotated' '
+ get_tag_header forcesignannotated-annotate $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ test_config tag.forcesignannotated true &&
git tag -a -m "A message" forcesignannotated-annotate &&
get_tag_msg forcesignannotated-annotate >actual &&
test_cmp expect actual &&
test_must_fail git tag -v forcesignannotated-annotate
'
-get_tag_header forcesignannotated-disabled $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'git tag --sign enable GPG sign' \
- 'test_config tag.forcesignannotated false &&
+test_expect_success GPG 'git tag --sign enable GPG sign' '
+ get_tag_header forcesignannotated-disabled $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+ test_config tag.forcesignannotated false &&
git tag --sign -m "A message" forcesignannotated-disabled &&
get_tag_msg forcesignannotated-disabled >actual &&
test_cmp expect actual
'
-get_tag_header gpgsign-enabled $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'git tag configured tag.gpgsign enables GPG sign' \
- 'test_config tag.gpgsign true &&
+test_expect_success GPG 'git tag configured tag.gpgsign enables GPG sign' '
+ get_tag_header gpgsign-enabled $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+ test_config tag.gpgsign true &&
git tag -m "A message" gpgsign-enabled &&
get_tag_msg gpgsign-enabled>actual &&
test_cmp expect actual
'
-get_tag_header no-sign $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success GPG \
- 'git tag --no-sign configured tag.gpgsign skip GPG sign' \
- 'test_config tag.gpgsign true &&
+test_expect_success GPG 'git tag --no-sign configured tag.gpgsign skip GPG sign' '
+ get_tag_header no-sign $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ test_config tag.gpgsign true &&
git tag -a --no-sign -m "A message" no-sign &&
get_tag_msg no-sign>actual &&
test_cmp expect actual
'
-test_expect_success GPG \
- 'trying to create a signed tag with non-existing -F file should fail' '
+test_expect_success GPG 'trying to create a signed tag with non-existing -F file should fail' '
! test -f nonexistingfile &&
! tag_exists nosigtag &&
test_must_fail git tag -s -F nonexistingfile nosigtag &&
! tag_exists nosigtag
'
-test_expect_success GPG 'verifying a signed tag should succeed' \
- 'git tag -v signed-tag'
+test_expect_success GPG 'verifying a signed tag should succeed' '
+ git tag -v signed-tag
+'
-test_expect_success GPG 'verifying two signed tags in one command should succeed' \
- 'git tag -v signed-tag file-signed-tag'
+test_expect_success GPG 'verifying two signed tags in one command should succeed' '
+ git tag -v signed-tag file-signed-tag
+'
-test_expect_success GPG \
- 'verifying many signed and non-signed tags should fail' '
+test_expect_success GPG 'verifying many signed and non-signed tags should fail' '
test_must_fail git tag -v signed-tag annotated-tag &&
test_must_fail git tag -v file-annotated-tag file-signed-tag &&
test_must_fail git tag -v annotated-tag \
@@ -1036,78 +1125,72 @@ test_expect_success GPG 'verifying a forged tag with --format should fail silent
# blank and empty messages for signed tags:
-get_tag_header empty-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with an empty -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with an empty -m message should succeed' '
+ get_tag_header empty-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "" empty-signed-tag &&
get_tag_msg empty-signed-tag >actual &&
test_cmp expect actual &&
git tag -v empty-signed-tag
'
->sigemptyfile
-get_tag_header emptyfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with an empty -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with an empty -F messagefile should succeed' '
+ >sigemptyfile &&
+ get_tag_header emptyfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigemptyfile emptyfile-signed-tag &&
get_tag_msg emptyfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v emptyfile-signed-tag
'
-printf '\n\n \n\t\nLeading blank lines\n' > sigblanksfile
-printf '\n\t \t \nRepeated blank lines\n' >>sigblanksfile
-printf '\n\n\nTrailing spaces \t \n' >>sigblanksfile
-printf '\nTrailing blank lines\n\n\t \n\n' >>sigblanksfile
-get_tag_header blanks-signed-tag $commit commit $time >expect
-cat >>expect <<EOF
-Leading blank lines
+test_expect_success GPG 'extra blanks in the message for a signed tag should be removed' '
+ printf "\n\n \n\t\nLeading blank lines\n" >sigblanksfile &&
+ printf "\n\t \t \nRepeated blank lines\n" >>sigblanksfile &&
+ printf "\n\n\nTrailing spaces \t \n" >>sigblanksfile &&
+ printf "\nTrailing blank lines\n\n\t \n\n" >>sigblanksfile &&
+ get_tag_header blanks-signed-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ Leading blank lines
-Repeated blank lines
+ Repeated blank lines
-Trailing spaces
+ Trailing spaces
-Trailing blank lines
-EOF
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'extra blanks in the message for a signed tag should be removed' '
+ Trailing blank lines
+ EOF
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigblanksfile blanks-signed-tag &&
get_tag_msg blanks-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blanks-signed-tag
'
-get_tag_header blank-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with a blank -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with a blank -m message should succeed' '
+ get_tag_header blank-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m " " blank-signed-tag &&
get_tag_msg blank-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blank-signed-tag
'
-echo ' ' >sigblankfile
-echo '' >>sigblankfile
-echo ' ' >>sigblankfile
-get_tag_header blankfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with blank -F file with spaces should succeed' '
+test_expect_success GPG 'creating a signed tag with blank -F file with spaces should succeed' '
+ echo " " >sigblankfile &&
+ echo "" >>sigblankfile &&
+ echo " " >>sigblankfile &&
+ get_tag_header blankfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigblankfile blankfile-signed-tag &&
get_tag_msg blankfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blankfile-signed-tag
'
-printf ' ' >sigblanknonlfile
-get_tag_header blanknonlfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with spaces and no newline should succeed' '
+test_expect_success GPG 'creating a signed tag with spaces and no newline should succeed' '
+ printf " " >sigblanknonlfile &&
+ get_tag_header blanknonlfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigblanknonlfile blanknonlfile-signed-tag &&
get_tag_msg blanknonlfile-signed-tag >actual &&
test_cmp expect actual &&
@@ -1127,69 +1210,65 @@ test_expect_success GPG 'signed tag with embedded PGP message' '
# messages with commented lines for signed tags:
-cat >sigcommentsfile <<EOF
-# A comment
+test_expect_success GPG 'creating a signed tag with a -F file with #comments should succeed' '
+ cat >sigcommentsfile <<-\EOF &&
+ # A comment
-############
-The message.
-############
-One line.
+ ############
+ The message.
+ ############
+ One line.
-# commented lines
-# commented lines
+ # commented lines
+ # commented lines
-Another line.
-# comments
+ Another line.
+ # comments
-Last line.
-EOF
-get_tag_header comments-signed-tag $commit commit $time >expect
-cat >>expect <<EOF
-The message.
-One line.
+ Last line.
+ EOF
+ get_tag_header comments-signed-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ The message.
+ One line.
-Another line.
+ Another line.
-Last line.
-EOF
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with a -F file with #comments should succeed' '
+ Last line.
+ EOF
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigcommentsfile comments-signed-tag &&
get_tag_msg comments-signed-tag >actual &&
test_cmp expect actual &&
git tag -v comments-signed-tag
'
-get_tag_header comment-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with #commented -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with #commented -m message should succeed' '
+ get_tag_header comment-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "#comment" comment-signed-tag &&
get_tag_msg comment-signed-tag >actual &&
test_cmp expect actual &&
git tag -v comment-signed-tag
'
-echo '#comment' >sigcommentfile
-echo '' >>sigcommentfile
-echo '####' >>sigcommentfile
-get_tag_header commentfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with #commented -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with #commented -F messagefile should succeed' '
+ echo "#comment" >sigcommentfile &&
+ echo "" >>sigcommentfile &&
+ echo "####" >>sigcommentfile &&
+ get_tag_header commentfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigcommentfile commentfile-signed-tag &&
get_tag_msg commentfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v commentfile-signed-tag
'
-printf '#comment' >sigcommentnonlfile
-get_tag_header commentnonlfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with a #comment and no newline should succeed' '
+test_expect_success GPG 'creating a signed tag with a #comment and no newline should succeed' '
+ printf "#comment" >sigcommentnonlfile &&
+ get_tag_header commentnonlfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigcommentnonlfile commentnonlfile-signed-tag &&
get_tag_msg commentnonlfile-signed-tag >actual &&
test_cmp expect actual &&
@@ -1198,8 +1277,7 @@ test_expect_success GPG \
# listing messages for signed tags:
-test_expect_success GPG \
- 'listing the one-line message of a signed tag should succeed' '
+test_expect_success GPG 'listing the one-line message of a signed tag should succeed' '
git tag -s -m "A message line signed" stag-one-line &&
echo "stag-one-line" >expect &&
@@ -1223,8 +1301,7 @@ test_expect_success GPG \
test_cmp expect actual
'
-test_expect_success GPG \
- 'listing the zero-lines message of a signed tag should succeed' '
+test_expect_success GPG 'listing the zero-lines message of a signed tag should succeed' '
git tag -s -m "" stag-zero-lines &&
echo "stag-zero-lines" >expect &&
@@ -1248,11 +1325,10 @@ test_expect_success GPG \
test_cmp expect actual
'
-echo 'stag line one' >sigtagmsg
-echo 'stag line two' >>sigtagmsg
-echo 'stag line three' >>sigtagmsg
-test_expect_success GPG \
- 'listing many message lines of a signed tag should succeed' '
+test_expect_success GPG 'listing many message lines of a signed tag should succeed' '
+ echo "stag line one" >sigtagmsg &&
+ echo "stag line two" >>sigtagmsg &&
+ echo "stag line three" >>sigtagmsg &&
git tag -s -F sigtagmsg stag-lines &&
echo "stag-lines" >expect &&
@@ -1294,74 +1370,64 @@ test_expect_success GPG \
# tags pointing to objects different from commits:
-tree=$(git rev-parse HEAD^{tree})
-blob=$(git rev-parse HEAD:foo)
-tag=$(git rev-parse signed-tag 2>/dev/null)
-
-get_tag_header tree-signed-tag $tree tree $time >expect
-echo "A message for a tree" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag pointing to a tree should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to a tree should succeed' '
+ tree=$(git rev-parse HEAD^{tree}) &&
+ get_tag_header tree-signed-tag $tree tree $time >expect &&
+ echo "A message for a tree" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} &&
get_tag_msg tree-signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header blob-signed-tag $blob blob $time >expect
-echo "A message for a blob" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag pointing to a blob should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to a blob should succeed' '
+ blob=$(git rev-parse HEAD:foo) &&
+ get_tag_header blob-signed-tag $blob blob $time >expect &&
+ echo "A message for a blob" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A message for a blob" blob-signed-tag HEAD:foo &&
get_tag_msg blob-signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header tag-signed-tag $tag tag $time >expect
-echo "A message for another tag" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag pointing to another tag should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to another tag should succeed' '
+ tag=$(git rev-parse signed-tag 2>/dev/null) &&
+ get_tag_header tag-signed-tag $tag tag $time >expect &&
+ echo "A message for another tag" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A message for another tag" tag-signed-tag signed-tag &&
get_tag_msg tag-signed-tag >actual &&
test_cmp expect actual
'
# usage with rfc1991 signatures
-get_tag_header rfc1991-signed-tag $commit commit $time >expect
-echo "RFC1991 signed tag" >>expect
-echo '-----BEGIN PGP MESSAGE-----' >>expect
-test_expect_success GPG,RFC1991 \
- 'creating a signed tag with rfc1991' '
+
+test_expect_success GPG,RFC1991 'creating a signed tag with rfc1991' '
+ get_tag_header rfc1991-signed-tag $commit commit $time >expect &&
+ echo "RFC1991 signed tag" >>expect &&
+ echo "-----BEGIN PGP MESSAGE-----" >>expect &&
echo "rfc1991" >gpghome/gpg.conf &&
git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
get_tag_msg rfc1991-signed-tag >actual &&
test_cmp expect actual
'
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-cp "$1" actual
-EOF
-chmod +x fakeeditor
-
-test_expect_success GPG,RFC1991 \
- 'reediting a signed tag body omits signature' '
+test_expect_success GPG,RFC1991 'reediting a signed tag body omits signature' '
+ write_script fakeeditor <<-\EOF &&
+ cp "$1" actual
+ EOF
echo "rfc1991" >gpghome/gpg.conf &&
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
test_cmp expect actual
'
-test_expect_success GPG,RFC1991 \
- 'verifying rfc1991 signature' '
+test_expect_success GPG,RFC1991 'verifying rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG,RFC1991 \
- 'list tag with rfc1991 signature' '
+test_expect_success GPG,RFC1991 'list tag with rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
@@ -1372,15 +1438,12 @@ test_expect_success GPG,RFC1991 \
test_cmp expect actual
'
-rm -f gpghome/gpg.conf
-
-test_expect_success GPG,RFC1991 \
- 'verifying rfc1991 signature without --rfc1991' '
+test_expect_success GPG,RFC1991 'verifying rfc1991 signature without --rfc1991' '
+ rm -f gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG,RFC1991 \
- 'list tag with rfc1991 signature without --rfc1991' '
+test_expect_success GPG,RFC1991 'list tag with rfc1991 signature without --rfc1991' '
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
test_cmp expect actual &&
@@ -1390,24 +1453,23 @@ test_expect_success GPG,RFC1991 \
test_cmp expect actual
'
-test_expect_success GPG,RFC1991 \
- 'reediting a signed tag body omits signature' '
+test_expect_success GPG,RFC1991 'reediting a signed tag body omits signature' '
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
test_cmp expect actual
'
# try to sign with bad user.signingkey
-test_expect_success GPG \
- 'git tag -s fails if gpg is misconfigured (bad key)' \
- 'test_config user.signingkey BobTheMouse &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPG 'git tag -s fails if gpg is misconfigured (bad key)' '
+ test_config user.signingkey BobTheMouse &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to produce invalid signature
-test_expect_success GPG \
- 'git tag -s fails if gpg is misconfigured (bad signature format)' \
- 'test_config gpg.program echo &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPG 'git tag -s fails if gpg is misconfigured (bad signature format)' '
+ test_config gpg.program echo &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to produce invalid signature
test_expect_success GPG 'git verifies tag is valid with double signature' '
@@ -1428,34 +1490,32 @@ test_expect_success GPG 'git verifies tag is valid with double signature' '
'
# try to sign with bad user.signingkey
-test_expect_success GPGSM \
- 'git tag -s fails if gpgsm is misconfigured (bad key)' \
- 'test_config user.signingkey BobTheMouse &&
- test_config gpg.format x509 &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPGSM 'git tag -s fails if gpgsm is misconfigured (bad key)' '
+ test_config user.signingkey BobTheMouse &&
+ test_config gpg.format x509 &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to produce invalid signature
-test_expect_success GPGSM \
- 'git tag -s fails if gpgsm is misconfigured (bad signature format)' \
- 'test_config gpg.x509.program echo &&
- test_config gpg.format x509 &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPGSM 'git tag -s fails if gpgsm is misconfigured (bad signature format)' '
+ test_config gpg.x509.program echo &&
+ test_config gpg.format x509 &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to verify without gpg:
-rm -rf gpghome
-test_expect_success GPG \
- 'verify signed tag fails when public key is not present' \
- 'test_must_fail git tag -v signed-tag'
+test_expect_success GPG 'verify signed tag fails when public key is not present' '
+ rm -rf gpghome &&
+ test_must_fail git tag -v signed-tag
+'
-test_expect_success \
- 'git tag -a fails if tag annotation is empty' '
+test_expect_success 'git tag -a fails if tag annotation is empty' '
! (GIT_EDITOR=cat git tag -a initial-comment)
'
-test_expect_success \
- 'message in editor has initial comment' '
- ! (GIT_EDITOR=cat git tag -a initial-comment > actual)
+test_expect_success 'message in editor has initial comment' '
+ ! (GIT_EDITOR=cat git tag -a initial-comment >actual)
'
test_expect_success 'message in editor has initial comment: first line' '
@@ -1465,17 +1525,15 @@ test_expect_success 'message in editor has initial comment: first line' '
test_cmp first.expect first.actual
'
-test_expect_success \
- 'message in editor has initial comment: remainder' '
+test_expect_success 'message in editor has initial comment: remainder' '
# remove commented lines from the remainder -- should be empty
sed -e 1d -e "/^#/d" <actual >rest.actual &&
test_must_be_empty rest.actual
'
-get_tag_header reuse $commit commit $time >expect
-echo "An annotation to be reused" >> expect
-test_expect_success \
- 'overwriting an annotated tag should use its previous body' '
+test_expect_success 'overwriting an annotated tag should use its previous body' '
+ get_tag_header reuse $commit commit $time >expect &&
+ echo "An annotation to be reused" >>expect &&
git tag -a -m "An annotation to be reused" reuse &&
GIT_EDITOR=true git tag -f -a reuse &&
get_tag_msg reuse >actual &&
@@ -1504,192 +1562,202 @@ test_expect_success 'filename for the message is relative to cwd' '
# create a few more commits to test --contains
-hash1=$(git rev-parse HEAD)
-
test_expect_success 'creating second commit and tag' '
+ hash1=$(git rev-parse HEAD) &&
echo foo-2.0 >foo &&
git add foo &&
git commit -m second &&
git tag v2.0
'
-hash2=$(git rev-parse HEAD)
-
test_expect_success 'creating third commit without tag' '
+ hash2=$(git rev-parse HEAD) &&
echo foo-dev >foo &&
git add foo &&
git commit -m third
'
-hash3=$(git rev-parse HEAD)
-
# simple linear checks of --continue
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
-
-test_expect_success 'checking that first commit is in all tags (hash)' "
+test_expect_success 'checking that first commit is in all tags (hash)' '
+ hash3=$(git rev-parse HEAD) &&
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
-"
+'
# other ways of specifying the commit
-test_expect_success 'checking that first commit is in all tags (tag)' "
+test_expect_success 'checking that first commit is in all tags (tag)' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --contains v1.0 v* >actual &&
test_cmp expected actual
-"
+'
-test_expect_success 'checking that first commit is in all tags (relative)' "
+test_expect_success 'checking that first commit is in all tags (relative)' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --contains HEAD~2 v* >actual &&
test_cmp expected actual
-"
+'
# All the --contains tests above, but with --no-contains
-test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' "
+test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' '
git tag -l --no-contains $hash1 v* >actual &&
test_must_be_empty actual
-"
+'
-test_expect_success 'checking that first commit is in all tags (tag)' "
+test_expect_success 'checking that first commit is in all tags (tag)' '
git tag -l --no-contains v1.0 v* >actual &&
test_must_be_empty actual
-"
+'
-test_expect_success 'checking that first commit is in all tags (relative)' "
+test_expect_success 'checking that first commit is in all tags (relative)' '
git tag -l --no-contains HEAD~2 v* >actual &&
test_must_be_empty actual
-"
-
-cat > expected <<EOF
-v2.0
-EOF
+'
-test_expect_success 'checking that second commit only has one tag' "
+test_expect_success 'checking that second commit only has one tag' '
+ cat >expected <<-\EOF &&
+ v2.0
+ EOF
git tag -l --contains $hash2 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
+'
-test_expect_success 'inverse of the last test, with --no-contains' "
+test_expect_success 'inverse of the last test, with --no-contains' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag -l --no-contains $hash2 v* >actual &&
test_cmp expected actual
-"
+'
-test_expect_success 'checking that third commit has no tags' "
+test_expect_success 'checking that third commit has no tags' '
git tag -l --contains $hash3 v* >actual &&
test_must_be_empty actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
+'
-test_expect_success 'conversely --no-contains on the third commit lists all tags' "
+test_expect_success 'conversely --no-contains on the third commit lists all tags' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --no-contains $hash3 v* >actual &&
test_cmp expected actual
-"
+'
# how about a simple merge?
test_expect_success 'creating simple branch' '
git branch stable v2.0 &&
git checkout stable &&
- echo foo-3.0 > foo &&
+ echo foo-3.0 >foo &&
git commit foo -m fourth &&
git tag v3.0
'
-hash4=$(git rev-parse HEAD)
-
-cat > expected <<EOF
-v3.0
-EOF
-
-test_expect_success 'checking that branch head only has one tag' "
+test_expect_success 'checking that branch head only has one tag' '
+ hash4=$(git rev-parse HEAD) &&
+ cat >expected <<-\EOF &&
+ v3.0
+ EOF
git tag -l --contains $hash4 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
+'
-test_expect_success 'checking that branch head with --no-contains lists all but one tag' "
+test_expect_success 'checking that branch head with --no-contains lists all but one tag' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --no-contains $hash4 v* >actual &&
test_cmp expected actual
-"
+'
test_expect_success 'merging original branch into this branch' '
git merge --strategy=ours main &&
git tag v4.0
'
-cat > expected <<EOF
-v4.0
-EOF
-
-test_expect_success 'checking that original branch head has one tag now' "
+test_expect_success 'checking that original branch head has one tag now' '
+ cat >expected <<-\EOF &&
+ v4.0
+ EOF
git tag -l --contains $hash3 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-v3.0
-EOF
+'
-test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' "
+test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ v3.0
+ EOF
git tag -l --no-contains $hash3 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-v3.0
-v4.0
-EOF
+'
-test_expect_success 'checking that initial commit is in all tags' "
+test_expect_success 'checking that initial commit is in all tags' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ v3.0
+ v4.0
+ EOF
git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
-"
+'
test_expect_success 'checking that --contains can be used in non-list mode' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ v3.0
+ v4.0
+ EOF
git tag --contains $hash1 v* >actual &&
test_cmp expected actual
'
-test_expect_success 'checking that initial commit is in all tags with --no-contains' "
+test_expect_success 'checking that initial commit is in all tags with --no-contains' '
git tag -l --no-contains $hash1 v* >actual &&
test_must_be_empty actual
-"
+'
# mixing modes and options:
@@ -1726,16 +1794,16 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '
for option in --contains --with --no-contains --without --merged --no-merged --points-at
do
- test_expect_success "mixing incompatible modes with $option is forbidden" "
+ test_expect_success "mixing incompatible modes with $option is forbidden" '
test_must_fail git tag -d $option HEAD &&
test_must_fail git tag -d $option HEAD some-tag &&
test_must_fail git tag -v $option HEAD
- "
- test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" "
+ '
+ test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" '
git tag -n $option HEAD HEAD &&
git tag $option HEAD HEAD &&
git tag $option
- "
+ '
done
# check points-at
@@ -1777,10 +1845,10 @@ test_expect_success '--points-at finds annotated tags of tags' '
'
test_expect_success 'recursive tagging should give advice' '
- sed -e "s/|$//" <<-EOF >expect &&
+ cat >expect <<-EOF &&
hint: You have created a nested tag. The object referred to by your new tag is
hint: already a tag. If you meant to tag the object that it points to, use:
- hint: |
+ hint:
hint: git tag -f nested annotated-v4.0^{}
hint: Disable this message with "git config advice.nestedTag false"
EOF
@@ -1862,6 +1930,51 @@ test_expect_success 'option override configured sort' '
test_cmp expect actual
'
+test_expect_success '--no-sort cancels config sort keys' '
+ test_config tag.sort "-refname" &&
+
+ # objecttype is identical for all of them, so sort falls back on
+ # default (ascending refname)
+ git tag -l \
+ --no-sort \
+ --sort="objecttype" \
+ "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.3
+ foo1.6
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success '--no-sort cancels command line sort keys' '
+ # objecttype is identical for all of them, so sort falls back on
+ # default (ascending refname)
+ git tag -l \
+ --sort="-refname" \
+ --no-sort \
+ --sort="objecttype" \
+ "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.3
+ foo1.6
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success '--no-sort without subsequent --sort prints expected tags' '
+ # Sort the results with `sort` for a consistent comparison against
+ # expected
+ git tag -l --no-sort "foo*" | sort >actual &&
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.3
+ foo1.6
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'invalid sort parameter on command line' '
test_must_fail git tag -l --sort=notvalid "foo*" >actual
'
@@ -2066,7 +2179,7 @@ test_expect_success 'git tag -l with --format="%(rest)" must fail' '
test_must_fail git tag -l --format="%(rest)" "v1*"
'
-test_expect_success "set up color tests" '
+test_expect_success 'set up color tests' '
echo "<RED>v1.0<RESET>" >expect.color &&
echo "v1.0" >expect.bare &&
color_args="--format=%(color:red)%(refname:short) --list v1.0"
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index e56ca5b0fa..932c26cb45 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -725,18 +725,11 @@ test_expect_success TTY 'git discards pager non-zero exit without SIGPIPE' '
test_path_is_file pager-used
'
-test_expect_success TTY 'git skips paging nonexisting command' '
- test_when_finished "rm trace.normal" &&
+test_expect_success TTY 'git errors when asked to execute nonexisting pager' '
+ test_when_finished "rm -f err" &&
test_config core.pager "does-not-exist" &&
- GIT_TRACE2="$(pwd)/trace.normal" &&
- export GIT_TRACE2 &&
- test_when_finished "unset GIT_TRACE2" &&
-
- test_terminal git log &&
-
- grep child_exit trace.normal >child-exits &&
- test_line_count = 1 child-exits &&
- grep " code:-1 " child-exits
+ test_must_fail test_terminal git log 2>err &&
+ test_grep "unable to execute pager" err
'
test_expect_success TTY 'git returns SIGPIPE on propagated signals from pager' '
@@ -762,7 +755,7 @@ test_expect_success TTY 'git returns SIGPIPE on propagated signals from pager' '
test_expect_success TTY 'non-existent pager doesnt cause crash' '
test_config pager.show invalid-pager &&
- test_terminal git show
+ test_must_fail test_terminal git show
'
test_done
diff --git a/t/t7007-show.sh b/t/t7007-show.sh
index f908a4d1ab..d6cc69e0f2 100755
--- a/t/t7007-show.sh
+++ b/t/t7007-show.sh
@@ -2,7 +2,6 @@
test_description='git show'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh
index 4adac5acd5..1ff2714cb4 100755
--- a/t/t7011-skip-worktree-reading.sh
+++ b/t/t7011-skip-worktree-reading.sh
@@ -5,7 +5,6 @@
test_description='skip-worktree bit test'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >expect.full <<EOF
@@ -32,24 +31,24 @@ setup_absent() {
}
test_absent() {
- echo "100644 $EMPTY_BLOB 0 1" > expected &&
- git ls-files --stage 1 > result &&
+ echo "100644 $EMPTY_BLOB 0 1" >expected &&
+ git ls-files --stage 1 >result &&
test_cmp expected result &&
test ! -f 1
}
setup_dirty() {
git update-index --force-remove 1 &&
- echo dirty > 1 &&
+ echo dirty >1 &&
git update-index --add --cacheinfo 100644 $EMPTY_BLOB 1 &&
git update-index --skip-worktree 1
}
test_dirty() {
- echo "100644 $EMPTY_BLOB 0 1" > expected &&
- git ls-files --stage 1 > result &&
+ echo "100644 $EMPTY_BLOB 0 1" >expected &&
+ git ls-files --stage 1 >result &&
test_cmp expected result &&
- echo dirty > expected
+ echo dirty >expected
test_cmp expected 1
}
@@ -59,7 +58,7 @@ test_expect_success 'setup' '
touch ./1 ./2 sub/1 sub/2 &&
git add 1 2 sub/1 sub/2 &&
git update-index --skip-worktree 1 sub/1 &&
- git ls-files -t > result &&
+ git ls-files -t >result &&
test_cmp expect.skip result
'
@@ -86,7 +85,7 @@ test_expect_success 'update-index --remove' '
setup_dirty &&
git update-index --remove 1 &&
test -z "$(git ls-files 1)" &&
- echo dirty > expected &&
+ echo dirty >expected &&
test_cmp expected 1
'
@@ -110,16 +109,16 @@ test_expect_success 'ls-files --modified' '
test -z "$(git ls-files -m)"
'
-echo ":000000 100644 $ZERO_OID $EMPTY_BLOB A 1" > expected
+echo ":000000 100644 $ZERO_OID $EMPTY_BLOB A 1" >expected
test_expect_success 'diff-index does not examine skip-worktree absent entries' '
setup_absent &&
- git diff-index HEAD -- 1 > result &&
+ git diff-index HEAD -- 1 >result &&
test_cmp expected result
'
test_expect_success 'diff-index does not examine skip-worktree dirty entries' '
setup_dirty &&
- git diff-index HEAD -- 1 > result &&
+ git diff-index HEAD -- 1 >result &&
test_cmp expected result
'
diff --git a/t/t7031-verify-tag-signed-ssh.sh b/t/t7031-verify-tag-signed-ssh.sh
index 20913b3713..80359d48f7 100755
--- a/t/t7031-verify-tag-signed-ssh.sh
+++ b/t/t7031-verify-tag-signed-ssh.sh
@@ -116,7 +116,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag succeeds with tag date
! grep "${GPGSSH_BAD_SIGNATURE}" actual
'
-test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag failes with tag date outside of key validity' '
+test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag fails with tag date outside of key validity' '
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
test_must_fail git verify-tag timeboxedinvalid-signed 2>actual &&
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index aaeb4a5334..0f4344c55e 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -5,7 +5,6 @@ test_description='basic work tree status reporting'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t7062-wtstatus-ignorecase.sh b/t/t7062-wtstatus-ignorecase.sh
index caf372a3d4..73709dbeee 100755
--- a/t/t7062-wtstatus-ignorecase.sh
+++ b/t/t7062-wtstatus-ignorecase.sh
@@ -2,7 +2,6 @@
test_description='git-status with core.ignorecase=true'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'status with hash collisions' '
diff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh
index 11884d2fc3..8bbc5ce6d9 100755
--- a/t/t7064-wtstatus-pv2.sh
+++ b/t/t7064-wtstatus-pv2.sh
@@ -76,7 +76,7 @@ test_expect_success 'before initial commit, things added (-z)' '
test_cmp expect actual
'
-test_expect_success 'make first commit, comfirm HEAD oid and branch' '
+test_expect_success 'make first commit, confirm HEAD oid and branch' '
git commit -m initial &&
H0=$(git rev-parse HEAD) &&
cat >expect <<-EOF &&
diff --git a/t/t7101-reset-empty-subdirs.sh b/t/t7101-reset-empty-subdirs.sh
index 89cf98b30c..33d5d5b76e 100755
--- a/t/t7101-reset-empty-subdirs.sh
+++ b/t/t7101-reset-empty-subdirs.sh
@@ -5,7 +5,6 @@
test_description='git reset should cull empty subdirs'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index 4287863ae6..0503a64d3f 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -12,21 +12,31 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
-commit_msg () {
- # String "modify 2nd file (changed)" partly in German
- # (translated with Google Translate),
- # encoded in UTF-8, used as a commit log message below.
- msg="modify 2nd file (ge\303\244ndert)\n"
- if test -n "$1"
- then
- printf "$msg" | iconv -f utf-8 -t "$1"
- else
- printf "$msg"
- fi
-}
-
-# Tested non-UTF-8 encoding
-test_encoding="ISO8859-1"
+if test_have_prereq ICONV
+then
+ commit_msg () {
+ # String "modify 2nd file (changed)" partly in German
+ # (translated with Google Translate),
+ # encoded in UTF-8, used as a commit log message below.
+ msg="modify 2nd file (ge\303\244ndert)\n"
+ if test -n "$1"
+ then
+ printf "$msg" | iconv -f utf-8 -t "$1"
+ else
+ printf "$msg"
+ fi
+ }
+
+ # Tested non-UTF-8 encoding
+ test_encoding="ISO8859-1"
+else
+ commit_msg () {
+ echo "modify 2nd file (geandert)"
+ }
+
+ # Tested non-UTF-8 encoding
+ test_encoding="UTF-8"
+fi
test_expect_success 'creating initial files and commits' '
test_tick &&
@@ -616,4 +626,12 @@ test_expect_success 'reset --mixed sets up work tree' '
test_must_be_empty actual
'
+test_expect_success 'reset handles --end-of-options' '
+ git update-ref refs/heads/--foo HEAD^ &&
+ git log -1 --format=%s refs/heads/--foo >expect &&
+ git reset --hard --end-of-options --foo &&
+ git log -1 --format=%s HEAD >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh
index 18bbd9975e..871e438118 100755
--- a/t/t7103-reset-bare.sh
+++ b/t/t7103-reset-bare.sh
@@ -2,7 +2,6 @@
test_description='git reset in a bare repository'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup non-bare' '
diff --git a/t/t7104-reset-hard.sh b/t/t7104-reset-hard.sh
index cf9697eba9..7948ec392b 100755
--- a/t/t7104-reset-hard.sh
+++ b/t/t7104-reset-hard.sh
@@ -2,7 +2,6 @@
test_description='reset --hard unmerged'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh
index 9b46da7aaa..fced8adabd 100755
--- a/t/t7105-reset-patch.sh
+++ b/t/t7105-reset-patch.sh
@@ -2,10 +2,9 @@
test_description='git reset --patch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-patch-mode.sh
-test_expect_success PERL 'setup' '
+test_expect_success 'setup' '
mkdir dir &&
echo parent > dir/foo &&
echo dummy > bar &&
@@ -19,42 +18,46 @@ test_expect_success PERL 'setup' '
# note: bar sorts before foo, so the first 'n' is always to skip 'bar'
-test_expect_success PERL 'saying "n" does nothing' '
+test_expect_success 'saying "n" does nothing' '
set_and_save_state dir/foo work work &&
test_write_lines n n | git reset -p &&
verify_saved_state dir/foo &&
verify_saved_state bar
'
-test_expect_success PERL 'git reset -p' '
- test_write_lines n y | git reset -p >output &&
- verify_state dir/foo work head &&
- verify_saved_state bar &&
- test_i18ngrep "Unstage" output
-'
-
-test_expect_success PERL 'git reset -p HEAD^' '
+for opt in "HEAD" "@" ""
+do
+ test_expect_success "git reset -p $opt" '
+ set_and_save_state dir/foo work work &&
+ test_write_lines n y | git reset -p $opt >output &&
+ verify_state dir/foo work head &&
+ verify_saved_state bar &&
+ test_grep "Unstage" output
+ '
+done
+
+test_expect_success 'git reset -p HEAD^' '
test_write_lines n y | git reset -p HEAD^ >output &&
verify_state dir/foo work parent &&
verify_saved_state bar &&
- test_i18ngrep "Apply" output
+ test_grep "Apply" output
'
-test_expect_success PERL 'git reset -p HEAD^^{tree}' '
+test_expect_success 'git reset -p HEAD^^{tree}' '
test_write_lines n y | git reset -p HEAD^^{tree} >output &&
verify_state dir/foo work parent &&
verify_saved_state bar &&
- test_i18ngrep "Apply" output
+ test_grep "Apply" output
'
-test_expect_success PERL 'git reset -p HEAD^:dir/foo (blob fails)' '
+test_expect_success 'git reset -p HEAD^:dir/foo (blob fails)' '
set_and_save_state dir/foo work work &&
test_must_fail git reset -p HEAD^:dir/foo &&
verify_saved_state dir/foo &&
verify_saved_state bar
'
-test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' '
+test_expect_success 'git reset -p aaaaaaaa (unknown fails)' '
set_and_save_state dir/foo work work &&
test_must_fail git reset -p aaaaaaaa &&
verify_saved_state dir/foo &&
@@ -66,27 +69,27 @@ test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' '
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
# the failure case (and thus get out of the loop).
-test_expect_success PERL 'git reset -p dir' '
+test_expect_success 'git reset -p dir' '
set_state dir/foo work work &&
test_write_lines y n | git reset -p dir &&
verify_state dir/foo work head &&
verify_saved_state bar
'
-test_expect_success PERL 'git reset -p -- foo (inside dir)' '
+test_expect_success 'git reset -p -- foo (inside dir)' '
set_state dir/foo work work &&
test_write_lines y n | (cd dir && git reset -p -- foo) &&
verify_state dir/foo work head &&
verify_saved_state bar
'
-test_expect_success PERL 'git reset -p HEAD^ -- dir' '
+test_expect_success 'git reset -p HEAD^ -- dir' '
test_write_lines y n | git reset -p HEAD^ -- dir &&
verify_state dir/foo work parent &&
verify_saved_state bar
'
-test_expect_success PERL 'none of this moved HEAD' '
+test_expect_success 'none of this moved HEAD' '
verify_saved_head
'
diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh
index a0b67a0b84..df20c0f0cc 100755
--- a/t/t7106-reset-unborn-branch.sh
+++ b/t/t7106-reset-unborn-branch.sh
@@ -2,7 +2,6 @@
test_description='git reset should work on unborn branch'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -34,7 +33,7 @@ test_expect_success 'reset $file' '
test_cmp expect actual
'
-test_expect_success PERL 'reset -p' '
+test_expect_success 'reset -p' '
rm .git/index &&
git add a &&
echo y >yes &&
@@ -42,7 +41,7 @@ test_expect_success PERL 'reset -p' '
git ls-files >actual &&
test_must_be_empty actual &&
- test_i18ngrep "Unstage" output
+ test_grep "Unstage" output
'
test_expect_success 'reset --soft is a no-op' '
diff --git a/t/t7107-reset-pathspec-file.sh b/t/t7107-reset-pathspec-file.sh
index af5ea406db..9162f591fb 100755
--- a/t/t7107-reset-pathspec-file.sh
+++ b/t/t7107-reset-pathspec-file.sh
@@ -2,7 +2,6 @@
test_description='reset --pathspec-from-file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_tick
@@ -161,19 +160,19 @@ test_expect_success 'error conditions' '
git rm fileA.t &&
test_must_fail git reset --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git reset --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git reset --pathspec-file-nul 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
test_must_fail git reset --soft --pathspec-from-file=list 2>err &&
- test_i18ngrep -e "fatal: Cannot do soft reset with paths" err &&
+ test_grep -e "fatal: Cannot do soft reset with paths" err &&
test_must_fail git reset --hard --pathspec-from-file=list 2>err &&
- test_i18ngrep -e "fatal: Cannot do hard reset with paths" err
+ test_grep -e "fatal: Cannot do hard reset with paths" err
'
test_done
diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh
index 772480a345..61669a2d21 100755
--- a/t/t7110-reset-merge.sh
+++ b/t/t7110-reset-merge.sh
@@ -5,7 +5,6 @@
test_description='Tests for "git reset" with "--merge" and "--keep" options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -238,7 +237,7 @@ 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
+ test_grep "middle of a merge" err.log
'
# The next test will test the following:
@@ -264,7 +263,7 @@ 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
+ test_grep "middle of a merge" err.log
'
test_expect_success '--merge is ok with added/deleted merge' '
@@ -290,7 +289,7 @@ test_expect_success '--keep fails with added/deleted merge' '
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_grep "middle of a merge" err.log
'
test_done
diff --git a/t/t7111-reset-table.sh b/t/t7111-reset-table.sh
index 01b7c3503c..07b919731a 100755
--- a/t/t7111-reset-table.sh
+++ b/t/t7111-reset-table.sh
@@ -5,7 +5,6 @@
test_description='Tests to check that "reset" options follow a known table'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh
index 58e55a7c77..c10d94fe3d 100755
--- a/t/t7113-post-index-change-hook.sh
+++ b/t/t7113-post-index-change-hook.sh
@@ -5,7 +5,6 @@ test_description='post index change hook'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 35b9e6ed6b..793da6e64e 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -217,7 +217,7 @@ test_expect_success 'switch to another branch while carrying a deletion' '
git rm two &&
test_must_fail git checkout simple 2>errs &&
- test_i18ngrep overwritten errs &&
+ test_grep overwritten errs &&
test_must_fail git read-tree --quiet -m -u HEAD simple 2>errs &&
test_must_be_empty errs
@@ -229,7 +229,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '
git checkout -f renamer &&
git clean -f &&
git checkout renamer^ 2>messages &&
- test_i18ngrep "HEAD is now at $rev" messages &&
+ test_grep "HEAD is now at $rev" messages &&
test_line_count = 1 messages &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/main) &&
@@ -497,6 +497,24 @@ test_expect_success 'checkout unmerged stage' '
test ztheirside = "z$(cat file)"
'
+test_expect_success 'checkout --ours is incompatible with switching' '
+ test_must_fail git checkout --ours 2>error &&
+ test_grep "needs the paths to check out" error &&
+
+ test_must_fail git checkout --ours HEAD 2>error &&
+ test_grep "cannot be used with switching" error &&
+
+ test_must_fail git checkout --ours main 2>error &&
+ test_grep "cannot be used with switching" error &&
+
+ git checkout --ours file
+'
+
+test_expect_success 'checkout path with --merge from tree-ish is a no-no' '
+ setup_conflicting_index &&
+ test_must_fail git checkout -m HEAD -- file
+'
+
test_expect_success 'checkout with --merge' '
setup_conflicting_index &&
echo "none of the above" >sample &&
@@ -517,6 +535,48 @@ test_expect_success 'checkout with --merge' '
test_cmp merged file
'
+test_expect_success 'checkout -m works after (mistaken) resolution' '
+ setup_conflicting_index &&
+ echo "none of the above" >sample &&
+ cat sample >fild &&
+ cat sample >file &&
+ cat sample >filf &&
+ # resolve to something
+ git add file &&
+ git checkout --merge -- fild file filf &&
+ {
+ echo "<<<<<<< ours" &&
+ echo ourside &&
+ echo "=======" &&
+ echo theirside &&
+ echo ">>>>>>> theirs"
+ } >merged &&
+ test_cmp expect fild &&
+ test_cmp expect filf &&
+ test_cmp merged file
+'
+
+test_expect_success 'checkout -m works after (mistaken) resolution to remove' '
+ setup_conflicting_index &&
+ echo "none of the above" >sample &&
+ cat sample >fild &&
+ cat sample >file &&
+ cat sample >filf &&
+ # resolve to remove
+ git rm file &&
+ git checkout --merge -- fild file filf &&
+ {
+ echo "<<<<<<< ours" &&
+ echo ourside &&
+ echo "=======" &&
+ echo theirside &&
+ echo ">>>>>>> theirs"
+ } >merged &&
+ test_cmp expect fild &&
+ test_cmp expect filf &&
+ test_cmp merged file
+'
+
test_expect_success 'checkout with --merge, in diff3 -m style' '
git config merge.conflictstyle diff3 &&
setup_conflicting_index &&
@@ -584,6 +644,72 @@ test_expect_success 'checkout --conflict=diff3' '
test_cmp merged file
'
+test_expect_success 'checkout --conflict=diff3 --no-conflict does not merge' '
+ setup_conflicting_index &&
+ echo "none of the above" >expect &&
+ cat expect >fild &&
+ cat expect >file &&
+ test_must_fail git checkout --conflict=diff3 --no-conflict -- fild file 2>err &&
+ test_cmp expect file &&
+ test_cmp expect fild &&
+ echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'checkout --conflict=diff3 --no-merge does not merge' '
+ setup_conflicting_index &&
+ echo "none of the above" >expect &&
+ cat expect >fild &&
+ cat expect >file &&
+ test_must_fail git checkout --conflict=diff3 --no-merge -- fild file 2>err &&
+ test_cmp expect file &&
+ test_cmp expect fild &&
+ echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'checkout --no-merge --conflict=diff3 does merge' '
+ setup_conflicting_index &&
+ echo "none of the above" >fild &&
+ echo "none of the above" >file &&
+ git checkout --no-merge --conflict=diff3 -- fild file &&
+ echo "ourside" >expect &&
+ test_cmp expect fild &&
+ cat >expect <<-\EOF &&
+ <<<<<<< ours
+ ourside
+ ||||||| base
+ original
+ =======
+ theirside
+ >>>>>>> theirs
+ EOF
+ test_cmp expect file
+'
+
+test_expect_success 'checkout --merge --conflict=diff3 --no-conflict does merge' '
+ setup_conflicting_index &&
+ echo "none of the above" >fild &&
+ echo "none of the above" >file &&
+ git checkout --merge --conflict=diff3 --no-conflict -- fild file &&
+ echo "ourside" >expect &&
+ test_cmp expect fild &&
+ cat >expect <<-\EOF &&
+ <<<<<<< ours
+ ourside
+ =======
+ theirside
+ >>>>>>> theirs
+ EOF
+ test_cmp expect file
+'
+
+test_expect_success 'checkout with invalid conflict style' '
+ test_must_fail git checkout --conflict=bad 2>actual -- file &&
+ echo "error: unknown conflict style ${SQ}bad${SQ}" >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'failing checkout -b should not break working tree' '
git clean -fd && # Remove untracked files in the way
git reset --hard main &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 0ef7b78457..00d4070156 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -28,15 +28,15 @@ test_expect_success 'git clean with skip-worktree .gitignore' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so &&
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so &&
git update-index --no-skip-worktree .gitignore &&
git checkout .gitignore
'
@@ -46,15 +46,15 @@ test_expect_success 'git clean' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -63,15 +63,15 @@ test_expect_success 'git clean src/' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean src/ &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -80,15 +80,15 @@ test_expect_success 'git clean src/ src/' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean src/ src/ &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -97,16 +97,16 @@ test_expect_success 'git clean with prefix' '
mkdir -p build docs src/test &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so src/test/1.c &&
(cd src/ && git clean) &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f src/part3.c &&
- test -f src/test/1.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file src/test/1.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -162,16 +162,16 @@ test_expect_success 'git clean -d with prefix and path' '
mkdir -p build docs src/feature &&
touch a.out src/part3.c src/feature/file.c docs/manual.txt obj.o build/lib.so &&
(cd src/ && git clean -d feature/) &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f src/part3.c &&
- test ! -f src/feature/file.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file src/part3.c &&
+ test_path_is_missing src/feature/file.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -181,16 +181,16 @@ test_expect_success SYMLINKS 'git clean symbolic link' '
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
ln -s docs/manual.txt src/part4.c &&
git clean &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test ! -f src/part4.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -198,13 +198,13 @@ test_expect_success 'git clean with wildcard' '
touch a.clean b.clean other.c &&
git clean "*.clean" &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.clean &&
- test ! -f b.clean &&
- test -f other.c
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.clean &&
+ test_path_is_missing b.clean &&
+ test_path_is_file other.c
'
@@ -213,15 +213,15 @@ test_expect_success 'git clean -n' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -n &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -230,15 +230,15 @@ test_expect_success 'git clean -d' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -d &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test ! -d docs &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing docs &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -247,16 +247,16 @@ test_expect_success 'git clean -d src/ examples/' '
mkdir -p build docs examples &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so examples/1.c &&
git clean -d src/ examples/ &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f src/part3.c &&
- test ! -f examples/1.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing examples/1.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -265,15 +265,15 @@ test_expect_success 'git clean -x' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -x &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test ! -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing obj.o &&
+ test_path_is_file build/lib.so
'
@@ -282,15 +282,15 @@ test_expect_success 'git clean -d -x' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -d -x &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test ! -d docs &&
- test ! -f obj.o &&
- test ! -d build
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing docs &&
+ test_path_is_missing obj.o &&
+ test_path_is_missing build
'
@@ -299,15 +299,15 @@ test_expect_success 'git clean -d -x with ignored tracked directory' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -d -x -e src &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f src/part3.c &&
- test ! -d docs &&
- test ! -f obj.o &&
- test ! -d build
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file src/part3.c &&
+ test_path_is_missing docs &&
+ test_path_is_missing obj.o &&
+ test_path_is_missing build
'
@@ -316,15 +316,15 @@ test_expect_success 'git clean -X' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -X &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f src/part3.c &&
- test -f docs/manual.txt &&
- test ! -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing obj.o &&
+ test_path_is_file build/lib.so
'
@@ -333,15 +333,15 @@ test_expect_success 'git clean -d -X' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -d -X &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f src/part3.c &&
- test -f docs/manual.txt &&
- test ! -f obj.o &&
- test ! -d build
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing obj.o &&
+ test_path_is_missing build
'
@@ -350,15 +350,15 @@ test_expect_success 'git clean -d -X with ignored tracked directory' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -d -X -e src &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test ! -f obj.o &&
- test ! -d build
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing obj.o &&
+ test_path_is_missing build
'
@@ -381,32 +381,38 @@ test_expect_success 'clean.requireForce and -n' '
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
git clean -n &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
test_expect_success 'clean.requireForce and -f' '
git clean -f &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
+test_expect_success 'clean.requireForce and --interactive' '
+ git clean --interactive </dev/null >output 2>error &&
+ test_grep ! "requireForce is true and" error &&
+ test_grep "\*\*\* Commands \*\*\*" output
+'
+
test_expect_success 'core.excludesfile' '
echo excludes >excludes &&
@@ -446,11 +452,11 @@ test_expect_success 'nested git work tree' '
test_commit deeply.nested deeper.world
) &&
git clean -f -d &&
- test -f foo/.git/index &&
- test -f foo/hello.world &&
- test -f baz/boo/.git/index &&
- test -f baz/boo/deeper.world &&
- ! test -d bar
+ test_path_is_file foo/.git/index &&
+ test_path_is_file foo/hello.world &&
+ test_path_is_file baz/boo/.git/index &&
+ test_path_is_file baz/boo/deeper.world &&
+ test_path_is_missing bar
'
test_expect_success 'should clean things that almost look like git but are not' '
@@ -517,8 +523,12 @@ test_expect_success 'nested (empty) git should be kept' '
git init empty_repo &&
mkdir to_clean &&
>to_clean/should_clean.this &&
+ # Note that we put the expect file in the .git directory so that it
+ # does not get cleaned.
+ find empty_repo | sort >.git/expect &&
git clean -f -d &&
- test_path_is_file empty_repo/.git/HEAD &&
+ find empty_repo | sort >actual &&
+ test_cmp .git/expect actual &&
test_path_is_missing to_clean
'
@@ -559,10 +569,10 @@ test_expect_success 'giving path in nested git work tree will NOT remove it' '
mkdir -p bar/baz &&
test_commit msg bar/baz/hello.world
) &&
+ find repo | sort >expect &&
git clean -f -d repo/bar/baz &&
- test_path_is_file repo/.git/HEAD &&
- test_path_is_dir repo/bar/ &&
- test_path_is_file repo/bar/baz/hello.world
+ find repo | sort >actual &&
+ test_cmp expect actual
'
test_expect_success 'giving path to nested .git will not remove it' '
@@ -573,10 +583,10 @@ test_expect_success 'giving path to nested .git will not remove it' '
git init &&
test_commit msg hello.world
) &&
+ find repo | sort >expect &&
git clean -f -d repo/.git &&
- test_path_is_file repo/.git/HEAD &&
- test_path_is_dir repo/.git/refs &&
- test_path_is_dir repo/.git/objects &&
+ find repo | sort >actual &&
+ test_cmp expect actual &&
test_path_is_dir untracked/
'
@@ -588,9 +598,10 @@ test_expect_success 'giving path to nested .git/ will NOT remove contents' '
git init &&
test_commit msg hello.world
) &&
+ find repo | sort >expect &&
git clean -f -d repo/.git/ &&
- test_path_is_dir repo/.git &&
- test_path_is_file repo/.git/HEAD &&
+ find repo | sort >actual &&
+ test_cmp expect actual &&
test_path_is_dir untracked/
'
@@ -612,9 +623,9 @@ test_expect_success 'force removal of nested git work tree' '
test_commit deeply.nested deeper.world
) &&
git clean -f -f -d &&
- ! test -d foo &&
- ! test -d bar &&
- ! test -d baz
+ test_path_is_missing foo &&
+ test_path_is_missing bar &&
+ test_path_is_missing baz
'
test_expect_success 'git clean -e' '
@@ -626,10 +637,10 @@ test_expect_success 'git clean -e' '
touch known 1 2 3 &&
git add known &&
git clean -f -e 1 -e 2 &&
- test -e 1 &&
- test -e 2 &&
- ! (test -e 3) &&
- test -e known
+ test_path_exists 1 &&
+ test_path_exists 2 &&
+ test_path_is_missing 3 &&
+ test_path_exists known
)
'
@@ -637,7 +648,7 @@ test_expect_success SANITY 'git clean -d with an unreadable empty directory' '
mkdir foo &&
chmod a= foo &&
git clean -dfx foo &&
- ! test -d foo
+ test_path_is_missing foo
'
test_expect_success 'git clean -d respects pathspecs (dir is prefix of pathspec)' '
@@ -735,7 +746,7 @@ test_expect_success MINGW 'handle clean & core.longpaths = false nicely' '
test_must_fail git clean -xdf 2>.git/err &&
# grepping for a strerror string is unportable but it is OK here with
# MINGW prereq
- test_i18ngrep "too long" .git/err
+ test_grep -e "too long" -e "No such file or directory" .git/err
'
test_expect_success 'clean untracked paths by pathspec' '
diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh
index d82a3210a1..f743e5b8f4 100755
--- a/t/t7301-clean-interactive.sh
+++ b/t/t7301-clean-interactive.sh
@@ -2,7 +2,6 @@
test_description='git clean -i basic tests'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
@@ -25,18 +24,18 @@ test_expect_success 'git clean -i (c: clean hotkey)' '
touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
docs/manual.txt obj.o build/lib.so &&
echo c | git clean -i &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test ! -f src/part3.h &&
- test ! -f src/part4.c &&
- test ! -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_missing src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -46,18 +45,18 @@ test_expect_success 'git clean -i (cl: clean prefix)' '
touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
docs/manual.txt obj.o build/lib.so &&
echo cl | git clean -i &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test ! -f src/part3.h &&
- test ! -f src/part4.c &&
- test ! -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_missing src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -67,18 +66,18 @@ test_expect_success 'git clean -i (quit)' '
touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
docs/manual.txt obj.o build/lib.so &&
echo quit | git clean -i &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f docs/manual.txt &&
- test -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -88,18 +87,18 @@ test_expect_success 'git clean -i (Ctrl+D)' '
touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
docs/manual.txt obj.o build/lib.so &&
echo "\04" | git clean -i &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f docs/manual.txt &&
- test -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -110,18 +109,18 @@ test_expect_success 'git clean -id (filter all)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines f "*" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f docs/manual.txt &&
- test -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -132,18 +131,18 @@ test_expect_success 'git clean -id (filter patterns)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines f "part3.* *.out" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f docs/manual.txt &&
- test -f src/part3.c &&
- test -f src/part3.h &&
- test ! -f src/part4.c &&
- test ! -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_missing src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -154,18 +153,18 @@ test_expect_success 'git clean -id (filter patterns 2)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines f "* !*.out" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -176,18 +175,18 @@ test_expect_success 'git clean -id (select - all)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "*" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test ! -f src/part3.h &&
- test ! -f src/part4.c &&
- test ! -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_missing src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -198,18 +197,18 @@ test_expect_success 'git clean -id (select - none)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f docs/manual.txt &&
- test -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -220,18 +219,18 @@ test_expect_success 'git clean -id (select - number)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s 3 "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -242,18 +241,18 @@ test_expect_success 'git clean -id (select - number 2)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "2 3" 5 "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test -f src/part3.h &&
- test ! -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -264,18 +263,18 @@ test_expect_success 'git clean -id (select - number 3)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "3,4 5" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test ! -f src/part3.h &&
- test ! -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -285,11 +284,11 @@ test_expect_success 'git clean -id (select - filenames)' '
touch a.out foo.txt bar.txt baz.txt &&
test_write_lines s "a.out fo ba bar" "" c |
git clean -id &&
- test -f Makefile &&
- test ! -f a.out &&
- test ! -f foo.txt &&
- test ! -f bar.txt &&
- test -f baz.txt &&
+ test_path_is_file Makefile &&
+ test_path_is_missing a.out &&
+ test_path_is_missing foo.txt &&
+ test_path_is_missing bar.txt &&
+ test_path_is_file baz.txt &&
rm baz.txt
'
@@ -301,18 +300,18 @@ test_expect_success 'git clean -id (select - range)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "1,3-4" 2 "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f src/part3.c &&
- test ! -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test ! -f docs/manual.txt &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -323,18 +322,18 @@ test_expect_success 'git clean -id (select - range 2)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "4- 1" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test -f src/part3.c &&
- test ! -f src/part3.h &&
- test ! -f src/part4.c &&
- test ! -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_missing src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -345,18 +344,18 @@ test_expect_success 'git clean -id (inverse select)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines s "*" "-5- 1 -2" "" c |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test ! -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -367,18 +366,18 @@ test_expect_success 'git clean -id (ask)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines a Y y no yes bad "" |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f docs/manual.txt &&
- test -f src/part3.c &&
- test ! -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -389,18 +388,18 @@ test_expect_success 'git clean -id (ask - Ctrl+D)' '
docs/manual.txt obj.o build/lib.so &&
test_write_lines a Y no yes "\04" |
git clean -id &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -412,18 +411,18 @@ test_expect_success 'git clean -id with prefix and path (filter)' '
(cd build/ &&
test_write_lines f docs "*.h" "" c |
git clean -id ..) &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test -f src/part3.h &&
- test ! -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_file docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -435,18 +434,18 @@ test_expect_success 'git clean -id with prefix and path (select by name)' '
(cd build/ &&
test_write_lines s ../docs/ ../src/part3.c ../src/part4.c "" c |
git clean -id ..) &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test -f a.out &&
- test ! -f docs/manual.txt &&
- test ! -f src/part3.c &&
- test -f src/part3.h &&
- test ! -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_file a.out &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_missing src/part3.c &&
+ test_path_is_file src/part3.h &&
+ test_path_is_missing src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
@@ -458,18 +457,18 @@ test_expect_success 'git clean -id with prefix and path (ask)' '
(cd build/ &&
test_write_lines a Y y no yes bad "" |
git clean -id ..) &&
- test -f Makefile &&
- test -f README &&
- test -f src/part1.c &&
- test -f src/part2.c &&
- test ! -f a.out &&
- test ! -f docs/manual.txt &&
- test -f src/part3.c &&
- test ! -f src/part3.h &&
- test -f src/part4.c &&
- test -f src/part4.h &&
- test -f obj.o &&
- test -f build/lib.so
+ test_path_is_file Makefile &&
+ test_path_is_file README &&
+ test_path_is_file src/part1.c &&
+ test_path_is_file src/part2.c &&
+ test_path_is_missing a.out &&
+ test_path_is_missing docs/manual.txt &&
+ test_path_is_file src/part3.c &&
+ test_path_is_missing src/part3.h &&
+ test_path_is_file src/part4.c &&
+ test_path_is_file src/part4.h &&
+ test_path_is_file obj.o &&
+ test_path_is_file build/lib.so
'
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 9918584464..981488885f 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -60,7 +60,7 @@ test_expect_success 'submodule init aborts on missing .gitmodules file' '
git update-index --add --cacheinfo 160000,$(git rev-parse HEAD),sub &&
# missing the .gitmodules file here
test_must_fail git submodule init 2>actual &&
- test_i18ngrep "No url found for submodule path" actual
+ test_grep "No url found for submodule path" actual
'
test_expect_success 'submodule update aborts on missing .gitmodules file' '
@@ -68,7 +68,7 @@ test_expect_success 'submodule update aborts on missing .gitmodules file' '
git update-index --add --cacheinfo 160000,$(git rev-parse HEAD),sub &&
# missing the .gitmodules file here
git submodule update sub 2>actual &&
- test_i18ngrep "Submodule path .sub. not initialized" actual
+ test_grep "Submodule path .sub. not initialized" actual
'
test_expect_success 'submodule update aborts on missing gitmodules url' '
@@ -100,7 +100,7 @@ test_expect_success 'status should ignore inner git repo when not added' '
) &&
test_must_fail git submodule status inner 2>output.err &&
rm -fr inner &&
- test_i18ngrep "^error: .*did not match any file(s) known to git" output.err
+ test_grep "^error: .*did not match any file(s) known to git" output.err
'
test_expect_success 'setup - repository in init subdirectory' '
@@ -196,7 +196,7 @@ test_expect_success 'redirected submodule add does not show progress' '
git -C addtest submodule add "file://$submodurl/parent" submod-redirected \
2>err &&
! grep % err &&
- test_i18ngrep ! "Checking connectivity" err
+ test_grep ! "Checking connectivity" err
'
test_expect_success 'redirected submodule add --progress does show progress' '
@@ -212,8 +212,7 @@ test_expect_success 'submodule add to .gitignored path fails' '
The following paths are ignored by one of your .gitignore files:
submod
hint: Use -f if you really want to add them.
- hint: Turn this message off by running
- hint: "git config advice.addIgnoredFile false"
+ hint: Disable this message with "git config advice.addIgnoredFile false"
EOF
# Does not use test_commit due to the ignore
echo "*" > .gitignore &&
@@ -263,7 +262,7 @@ test_expect_success 'submodule add relays add --dry-run stderr' '
cd addtest &&
: >.git/index.lock &&
! git submodule add "$submodurl" sub-while-locked 2>output.err &&
- test_i18ngrep "^fatal: .*index\.lock" output.err &&
+ test_grep "^fatal: .*index\.lock" output.err &&
test_path_is_missing sub-while-locked
)
'
@@ -405,7 +404,7 @@ test_expect_success 'submodule add in subdirectory with relative path should fai
cd addtest/sub &&
test_must_fail git submodule add ../../ submod3 2>../../output.err
) &&
- test_i18ngrep toplevel output.err
+ test_grep toplevel output.err
'
test_expect_success 'setup - add an example entry to .gitmodules' '
@@ -486,7 +485,7 @@ test_expect_success 'status should still be "missing" after initializing' '
test_failure_with_unknown_submodule () {
test_must_fail git submodule $1 no-such-submodule 2>output.err &&
- test_i18ngrep "^error: .*no-such-submodule" output.err
+ test_grep "^error: .*no-such-submodule" output.err
}
test_expect_success 'init should fail with unknown submodule' '
@@ -644,7 +643,7 @@ test_expect_success 'update --init' '
test_must_fail git config submodule.example.url &&
git submodule update init 2> update.out &&
- test_i18ngrep "not initialized" update.out &&
+ test_grep "not initialized" update.out &&
test_must_fail git rev-parse --resolve-git-dir init/.git &&
git submodule update --init init &&
@@ -661,7 +660,7 @@ test_expect_success 'update --init from subdirectory' '
(
cd sub &&
git submodule update ../init 2>update.out &&
- test_i18ngrep "not initialized" update.out &&
+ test_grep "not initialized" update.out &&
test_must_fail git rev-parse --resolve-git-dir ../init/.git &&
git submodule update --init ../init
@@ -1121,7 +1120,7 @@ test_expect_success 'submodule deinit from subdirectory' '
cd sub &&
git submodule deinit ../init >../output
) &&
- test_i18ngrep "\\.\\./init" output &&
+ test_grep "\\.\\./init" output &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
test -n "$(git config --get-regexp "submodule\.example2\.")" &&
test -f example2/.git &&
@@ -1136,8 +1135,8 @@ test_expect_success 'submodule deinit . deinits all initialized submodules' '
git submodule deinit . >actual &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
test -z "$(git config --get-regexp "submodule\.example2\.")" &&
- test_i18ngrep "Cleared directory .init" actual &&
- test_i18ngrep "Cleared directory .example2" actual &&
+ test_grep "Cleared directory .init" actual &&
+ test_grep "Cleared directory .example2" actual &&
rmdir init example2
'
@@ -1149,8 +1148,8 @@ test_expect_success 'submodule deinit --all deinits all initialized submodules'
git submodule deinit --all >actual &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
test -z "$(git config --get-regexp "submodule\.example2\.")" &&
- test_i18ngrep "Cleared directory .init" actual &&
- test_i18ngrep "Cleared directory .example2" actual &&
+ test_grep "Cleared directory .init" actual &&
+ test_grep "Cleared directory .example2" actual &&
rmdir init example2
'
@@ -1160,8 +1159,8 @@ test_expect_success 'submodule deinit deinits a submodule when its work tree is
git submodule deinit init example2 >actual &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
test -z "$(git config --get-regexp "submodule\.example2\.")" &&
- test_i18ngrep ! "Cleared directory .init" actual &&
- test_i18ngrep "Cleared directory .example2" actual &&
+ test_grep ! "Cleared directory .init" actual &&
+ test_grep "Cleared directory .example2" actual &&
rmdir init
'
@@ -1173,7 +1172,7 @@ test_expect_success 'submodule deinit fails when the submodule contains modifica
test -f example2/.git &&
git submodule deinit -f init >actual &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep "Cleared directory .init" actual &&
rmdir init
'
@@ -1185,7 +1184,7 @@ test_expect_success 'submodule deinit fails when the submodule contains untracke
test -f example2/.git &&
git submodule deinit -f init >actual &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep "Cleared directory .init" actual &&
rmdir init
'
@@ -1200,30 +1199,30 @@ test_expect_success 'submodule deinit fails when the submodule HEAD does not mat
test -f example2/.git &&
git submodule deinit -f init >actual &&
test -z "$(git config --get-regexp "submodule\.example\.")" &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep "Cleared directory .init" actual &&
rmdir init
'
test_expect_success 'submodule deinit is silent when used on an uninitialized submodule' '
git submodule update --init &&
git submodule deinit init >actual &&
- test_i18ngrep "Submodule .example. (.*) unregistered for path .init" actual &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_grep "Cleared directory .init" actual &&
git submodule deinit init >actual &&
- test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_grep "Cleared directory .init" actual &&
git submodule deinit . >actual &&
- test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
- test_i18ngrep "Submodule .example2. (.*) unregistered for path .example2" actual &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_grep "Submodule .example2. (.*) unregistered for path .example2" actual &&
+ test_grep "Cleared directory .init" actual &&
git submodule deinit . >actual &&
- test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
- test_i18ngrep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_grep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
+ test_grep "Cleared directory .init" actual &&
git submodule deinit --all >actual &&
- test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
- test_i18ngrep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
- test_i18ngrep "Cleared directory .init" actual &&
+ test_grep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+ test_grep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
+ test_grep "Cleared directory .init" actual &&
rmdir init example2
'
@@ -1472,13 +1471,13 @@ test_expect_success '`submodule init` and `init.templateDir`' '
test_must_fail git submodule \
add "$submodurl" sub-global 2>err &&
git config --global --unset init.templateDir &&
- grep HOOK-RUN err &&
+ test_grep HOOK-RUN err &&
test_path_is_file sub-global/hook.run &&
git config init.templateDir "$(pwd)/tmpl" &&
git submodule add "$submodurl" sub-local 2>err &&
git config --unset init.templateDir &&
- ! grep HOOK-RUN err &&
+ test_grep ! HOOK-RUN err &&
test_path_is_missing sub-local/hook.run
)
'
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index 542b3331a7..9c3cc4cf40 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -17,7 +17,6 @@ This test script tries to verify the sanity of summary subcommand of git submodu
# various reasons, one of them being that there are lots of commands taking place
# outside of 'test_expect_success' block, which is no longer in good-style.
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
add_file () {
diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh
index 2b3c363078..25b33a1e87 100755
--- a/t/t7402-submodule-rebase.sh
+++ b/t/t7402-submodule-rebase.sh
@@ -5,7 +5,6 @@
test_description='Test rebasing, stashing, etc. with submodules'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -116,7 +115,7 @@ test_expect_success 'rebasing submodule that should conflict' '
test_tick &&
git commit -m fourth &&
- test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 >actual_output &&
+ test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 2>actual_output &&
git ls-files -s submodule >actual &&
(
cd submodule &&
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index ff09443a0a..bf97d4f851 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -11,7 +11,6 @@ These tests exercise the "git submodule sync" subcommand.
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 '
@@ -163,7 +162,7 @@ test_expect_success '"git submodule sync" should update submodule URLs - subdire
cd sub &&
git submodule sync >../../output
) &&
- test_i18ngrep "\\.\\./submodule" output &&
+ test_grep "\\.\\./submodule" output &&
test -d "$(
cd super-clone/submodule &&
git config remote.origin.url
@@ -194,7 +193,7 @@ test_expect_success '"git submodule sync --recursive" should update all submodul
cd sub &&
git submodule sync --recursive >../../output
) &&
- test_i18ngrep "\\.\\./submodule/sub-submodule" output &&
+ test_grep "\\.\\./submodule/sub-submodule" output &&
test -d "$(
cd super-clone/submodule &&
git config remote.origin.url
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index fb82f760c3..297c6c3b5c 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -945,7 +945,7 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re
git clone super_update_r super_update_r2 &&
(cd super_update_r2 &&
git submodule update --init --recursive >actual &&
- test_i18ngrep "Submodule path .submodule/subsubmodule.: checked out" actual &&
+ test_grep "Submodule path .submodule/subsubmodule.: checked out" actual &&
(cd submodule/subsubmodule &&
git log > ../../expected
) &&
@@ -1025,7 +1025,7 @@ test_expect_success 'submodule update clone shallow submodule outside of depth'
# unadvertised objects, so restrict this test to v0.
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
git submodule update --init --depth=1 2>actual &&
- test_i18ngrep "Direct fetching of that commit failed." actual &&
+ test_grep "Direct fetching of that commit failed." actual &&
git -C ../submodule config uploadpack.allowReachableSHA1InWant true &&
git submodule update --init --depth=1 >actual &&
git -C submodule log --oneline >out &&
@@ -1039,7 +1039,7 @@ test_expect_success 'submodule update --recursive drops module name before recur
git checkout HEAD^
) &&
git submodule update --recursive deeper/submodule >actual &&
- test_i18ngrep "Submodule path .deeper/submodule/subsubmodule.: checked out" actual
+ test_grep "Submodule path .deeper/submodule/subsubmodule.: checked out" actual
)
'
@@ -1246,7 +1246,7 @@ test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \
test_path_is_missing "$tell_tale_path" &&
git clone --recursive captain hooked 2>err &&
- ! grep HOOK-RUN err &&
+ test_grep ! HOOK-RUN err &&
test_path_is_missing "$tell_tale_path"
'
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index d6040e0a33..f860e7bbf4 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -4,6 +4,7 @@
#
test_description='test clone --reference'
+
. ./test-lib.sh
base_dir=$(pwd)
diff --git a/t/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh
index 574a6fc526..374ed481e9 100755
--- a/t/t7409-submodule-detached-work-tree.sh
+++ b/t/t7409-submodule-detached-work-tree.sh
@@ -13,7 +13,6 @@ TEST_NO_CREATE_REPO=1
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index c0167944ab..31271f8e0a 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -45,7 +45,7 @@ test_expect_success 'configuration parsing with error' '
(
cd repo &&
test_must_fail test-tool submodule-config "" s 2>actual &&
- test_i18ngrep "bad config" actual
+ test_grep "bad config" actual
)
'
@@ -101,7 +101,7 @@ test_expect_success 'error in history of one submodule config lets continue, std
>actual \
2>actual_stderr &&
test_cmp expect_error actual &&
- test_i18ngrep "submodule-blob $sha1:.gitmodules" actual_stderr >/dev/null
+ test_grep "submodule-blob $sha1:.gitmodules" actual_stderr >/dev/null
)
'
diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh
index f778321857..0490499573 100755
--- a/t/t7412-submodule-absorbgitdirs.sh
+++ b/t/t7412-submodule-absorbgitdirs.sh
@@ -6,7 +6,6 @@ This test verifies that `git submodue absorbgitdirs` moves a submodules git
directory into the superproject.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup a real submodule' '
diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh
index 887d181b72..9509dc18fd 100755
--- a/t/t7413-submodule-is-active.sh
+++ b/t/t7413-submodule-is-active.sh
@@ -9,7 +9,6 @@ This is a unit test of the submodule.c is_submodule_active() function,
which is also indirectly tested elsewhere.
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -22,7 +21,7 @@ test_expect_success 'setup' '
git -C super submodule add ../sub sub2 &&
# Remove submodule.<name>.active entries in order to test in an
- # environment where only URLs are present in the conifg
+ # environment where only URLs are present in the config
git -C super config --unset submodule.sub1.active &&
git -C super config --unset submodule.sub2.active &&
diff --git a/t/t7414-submodule-mistakes.sh b/t/t7414-submodule-mistakes.sh
index 101afff30f..e2d75c7f16 100755
--- a/t/t7414-submodule-mistakes.sh
+++ b/t/t7414-submodule-mistakes.sh
@@ -2,7 +2,6 @@
test_description='handling of common mistakes people may make with submodules'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create embedded repository' '
@@ -13,13 +12,13 @@ test_expect_success 'create embedded repository' '
test_expect_success 'git-add on embedded repository warns' '
test_when_finished "git rm --cached -f embed" &&
git add embed 2>stderr &&
- test_i18ngrep warning stderr
+ test_grep warning stderr
'
test_expect_success '--no-warn-embedded-repo suppresses warning' '
test_when_finished "git rm --cached -f embed" &&
git add --no-warn-embedded-repo embed 2>stderr &&
- test_i18ngrep ! warning stderr
+ test_grep ! warning stderr
'
test_expect_success 'no warning when updating entry' '
@@ -27,14 +26,14 @@ test_expect_success 'no warning when updating entry' '
git add embed &&
git -C embed commit --allow-empty -m two &&
git add embed 2>stderr &&
- test_i18ngrep ! warning stderr
+ test_grep ! warning stderr
'
test_expect_success 'submodule add does not warn' '
test_when_finished "git rm -rf submodule .gitmodules" &&
git -c protocol.file.allow=always \
submodule add ./embed submodule 2>stderr &&
- test_i18ngrep ! warning stderr
+ test_grep ! warning stderr
'
test_done
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 7cf72b9a07..0c605fd271 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -2,7 +2,6 @@
test_description='check handling of disallowed .gitmodule urls'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -41,7 +40,7 @@ test_expect_success 'remove ./ protection from .gitmodules url' '
test_expect_success 'clone rejects unprotected dash' '
test_when_finished "rm -rf dst" &&
test_must_fail git clone --recurse-submodules . dst 2>err &&
- test_i18ngrep ignoring err
+ test_grep ignoring err
'
test_expect_success 'fsck rejects unprotected dash' '
@@ -63,7 +62,7 @@ test_expect_success 'trailing backslash is handled correctly' '
mv .new .gitmodules &&
git commit -am "Add testmodule" &&
test_must_fail git clone --verbose --recurse-submodules . dolly 2>err &&
- test_i18ngrep ! "unknown option" err
+ test_grep ! "unknown option" err
'
test_expect_success 'fsck rejects missing URL scheme' '
diff --git a/t/t7417-submodule-path-url.sh b/t/t7417-submodule-path-url.sh
index 2f4b25dfd7..5e3051da8b 100755
--- a/t/t7417-submodule-path-url.sh
+++ b/t/t7417-submodule-path-url.sh
@@ -21,7 +21,7 @@ test_expect_success 'create submodule with dash in path' '
test_expect_success 'clone rejects unprotected dash' '
test_when_finished "rm -rf dst" &&
git clone --recurse-submodules . dst 2>err &&
- test_i18ngrep ignoring err
+ test_grep ignoring err
'
test_expect_success 'fsck rejects unprotected dash' '
@@ -46,7 +46,7 @@ test_expect_success MINGW 'submodule paths disallows trailing spaces' '
git -C super update-ref refs/heads/main $commit &&
test_must_fail git clone --recurse-submodules super dst 2>err &&
- test_i18ngrep "sub " err
+ test_grep "sub " err
'
test_done
diff --git a/t/t7419-submodule-set-branch.sh b/t/t7419-submodule-set-branch.sh
index 232065504c..08ed51d34f 100755
--- a/t/t7419-submodule-set-branch.sh
+++ b/t/t7419-submodule-set-branch.sh
@@ -9,8 +9,11 @@ This test verifies that the set-branch subcommand of git-submodule is working
as expected.
'
-TEST_PASSES_SANITIZE_LEAK=true
TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
. ./test-lib.sh
test_expect_success 'setup' '
@@ -27,26 +30,28 @@ test_expect_success 'submodule config cache setup' '
git checkout -b topic &&
echo b >a &&
git add . &&
- git commit -mb
+ git commit -mb &&
+ git checkout main
) &&
mkdir super &&
(cd super &&
git init &&
git submodule add ../submodule &&
- git commit -m "add submodule"
+ git submodule add --name thename ../submodule thepath &&
+ git commit -m "add submodules"
)
'
test_expect_success 'ensure submodule branch is unset' '
(cd super &&
- ! grep branch .gitmodules
+ test_cmp_config "" -f .gitmodules --default "" submodule.submodule.branch
)
'
test_expect_success 'test submodule set-branch --branch' '
(cd super &&
git submodule set-branch --branch topic submodule &&
- grep "branch = topic" .gitmodules &&
+ test_cmp_config topic -f .gitmodules submodule.submodule.branch &&
git submodule update --remote &&
cat <<-\EOF >expect &&
b
@@ -57,13 +62,12 @@ test_expect_success 'test submodule set-branch --branch' '
'
test_expect_success 'test submodule set-branch --default' '
- test_commit -C submodule c &&
(cd super &&
git submodule set-branch --default submodule &&
- ! grep branch .gitmodules &&
+ test_cmp_config "" -f .gitmodules --default "" submodule.submodule.branch &&
git submodule update --remote &&
cat <<-\EOF >expect &&
- c
+ a
EOF
git -C submodule show -s --pretty=%s >actual &&
test_cmp expect actual
@@ -71,10 +75,9 @@ test_expect_success 'test submodule set-branch --default' '
'
test_expect_success 'test submodule set-branch -b' '
- test_commit -C submodule b &&
(cd super &&
git submodule set-branch -b topic submodule &&
- grep "branch = topic" .gitmodules &&
+ test_cmp_config topic -f .gitmodules submodule.submodule.branch &&
git submodule update --remote &&
cat <<-\EOF >expect &&
b
@@ -85,17 +88,43 @@ test_expect_success 'test submodule set-branch -b' '
'
test_expect_success 'test submodule set-branch -d' '
- test_commit -C submodule d &&
(cd super &&
git submodule set-branch -d submodule &&
- ! grep branch .gitmodules &&
+ test_cmp_config "" -f .gitmodules --default "" submodule.submodule.branch &&
git submodule update --remote &&
cat <<-\EOF >expect &&
- d
+ a
EOF
git -C submodule show -s --pretty=%s >actual &&
test_cmp expect actual
)
'
+test_expect_success 'test submodule set-branch --branch with named submodule' '
+ (cd super &&
+ git submodule set-branch --branch topic thepath &&
+ test_cmp_config topic -f .gitmodules submodule.thename.branch &&
+ test_cmp_config "" -f .gitmodules --default "" submodule.thepath.branch &&
+ git submodule update --remote &&
+ cat <<-\EOF >expect &&
+ b
+ EOF
+ git -C thepath show -s --pretty=%s >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'test submodule set-branch --default with named submodule' '
+ (cd super &&
+ git submodule set-branch --default thepath &&
+ test_cmp_config "" -f .gitmodules --default "" submodule.thename.branch &&
+ git submodule update --remote &&
+ cat <<-\EOF >expect &&
+ a
+ EOF
+ git -C thepath show -s --pretty=%s >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh
index d6bf62b3ac..bf7f15ee79 100755
--- a/t/t7420-submodule-set-url.sh
+++ b/t/t7420-submodule-set-url.sh
@@ -25,17 +25,26 @@ test_expect_success 'submodule config cache setup' '
git add file &&
git commit -ma
) &&
+ mkdir namedsubmodule &&
+ (
+ cd namedsubmodule &&
+ git init &&
+ echo 1 >file &&
+ git add file &&
+ git commit -m1
+ ) &&
mkdir super &&
(
cd super &&
git init &&
git submodule add ../submodule &&
- git commit -m "add submodule"
+ git submodule add --name thename ../namedsubmodule thepath &&
+ git commit -m "add submodules"
)
'
test_expect_success 'test submodule set-url' '
- # add a commit and move the submodule (change the url)
+ # add commits and move the submodules (change the urls)
(
cd submodule &&
echo b >>file &&
@@ -44,15 +53,28 @@ test_expect_success 'test submodule set-url' '
) &&
mv submodule newsubmodule &&
+ (
+ cd namedsubmodule &&
+ echo 2 >>file &&
+ git add file &&
+ git commit -m2
+ ) &&
+ mv namedsubmodule newnamedsubmodule &&
+
git -C newsubmodule show >expect &&
+ git -C newnamedsubmodule show >>expect &&
(
cd super &&
test_must_fail git submodule update --remote &&
git submodule set-url submodule ../newsubmodule &&
- grep -F "url = ../newsubmodule" .gitmodules &&
+ test_cmp_config ../newsubmodule -f .gitmodules submodule.submodule.url &&
+ git submodule set-url thepath ../newnamedsubmodule &&
+ test_cmp_config ../newnamedsubmodule -f .gitmodules submodule.thename.url &&
+ test_cmp_config "" -f .gitmodules --default "" submodule.thepath.url &&
git submodule update --remote
) &&
git -C super/submodule show >actual &&
+ git -C super/thepath show >>actual &&
test_cmp expect actual
'
diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh
index ab946ec940..f21e920367 100755
--- a/t/t7422-submodule-output.sh
+++ b/t/t7422-submodule-output.sh
@@ -2,7 +2,6 @@
test_description='submodule --cached, --quiet etc. output'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-t3100.sh
@@ -167,4 +166,11 @@ do
'
done
+test_expect_success !MINGW 'git submodule status --recursive propagates SIGPIPE' '
+ { git submodule status --recursive 2>err; echo $?>status; } |
+ grep -q X/S &&
+ test_must_be_empty err &&
+ test_match_signal 13 "$(cat status)"
+'
+
test_done
diff --git a/t/t7424-submodule-mixed-ref-formats.sh b/t/t7424-submodule-mixed-ref-formats.sh
new file mode 100755
index 0000000000..559713b607
--- /dev/null
+++ b/t/t7424-submodule-mixed-ref-formats.sh
@@ -0,0 +1,143 @@
+#!/bin/sh
+
+test_description='submodules handle mixed ref storage formats'
+
+. ./test-lib.sh
+
+test_ref_format () {
+ echo "$2" >expect &&
+ git -C "$1" rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+}
+
+for OTHER_FORMAT in files reftable
+do
+ if test "$OTHER_FORMAT" = "$GIT_DEFAULT_REF_FORMAT"
+ then
+ continue
+ fi
+
+test_expect_success 'setup' '
+ git config set --global protocol.file.allow always &&
+ # Some tests migrate the ref storage format, which does not work with
+ # reflogs at the time of writing these tests.
+ git config set --global core.logAllRefUpdates false
+'
+
+test_expect_success 'add existing repository with different ref storage format' '
+ test_when_finished "rm -rf parent" &&
+
+ git init parent &&
+ (
+ cd parent &&
+ test_commit parent &&
+ git init --ref-format=$OTHER_FORMAT submodule &&
+ test_commit -C submodule submodule &&
+ git submodule add ./submodule
+ )
+'
+
+test_expect_success 'add submodules with different ref storage format' '
+ test_when_finished "rm -rf submodule upstream" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
+ git -C upstream submodule add --ref-format="$OTHER_FORMAT" "file://$(pwd)/submodule" &&
+ test_ref_format upstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'recursive clone propagates ref storage format' '
+ test_when_finished "rm -rf submodule upstream downstream" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ git -C upstream submodule add "file://$(pwd)/submodule" &&
+ git -C upstream commit -am "add submodule" &&
+
+ # The upstream repository and its submodule should be using the default
+ # ref format.
+ test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
+ test_ref_format upstream/submodule "$GIT_DEFAULT_REF_FORMAT" &&
+
+ # The cloned repositories should use the other ref format that we have
+ # specified via `--ref-format`. The option should propagate to cloned
+ # submodules.
+ git clone --ref-format=$OTHER_FORMAT --recurse-submodules \
+ upstream downstream &&
+ test_ref_format downstream "$OTHER_FORMAT" &&
+ test_ref_format downstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'clone submodules with different ref storage format' '
+ test_when_finished "rm -rf submodule upstream downstream" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ git -C upstream submodule add "file://$(pwd)/submodule" &&
+ git -C upstream commit -m "upstream submodule" &&
+
+ git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
+ test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
+ git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
+ test_ref_format downstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'status with mixed submodule ref storages' '
+ test_when_finished "rm -rf submodule main" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init main &&
+ git -C main submodule add "file://$(pwd)/submodule" &&
+ git -C main commit -m "add submodule" &&
+ git -C main/submodule refs migrate --ref-format=$OTHER_FORMAT &&
+
+ # The main repository should use the default ref format now, whereas
+ # the submodule should use the other format.
+ test_ref_format main "$GIT_DEFAULT_REF_FORMAT" &&
+ test_ref_format main/submodule "$OTHER_FORMAT" &&
+
+ cat >expect <<-EOF &&
+ $(git -C main/submodule rev-parse HEAD) submodule (submodule-initial)
+ EOF
+ git -C main submodule status >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'recursive pull with mixed formats' '
+ test_when_finished "rm -rf submodule upstream downstream" &&
+
+ # Set up the initial structure with an upstream repository that has a
+ # submodule, as well as a downstream clone of the upstream repository.
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ git -C upstream submodule add "file://$(pwd)/submodule" &&
+ git -C upstream commit -m "upstream submodule" &&
+
+ # Clone the upstream repository such that the main repo and its
+ # submodules have different formats.
+ git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
+ git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
+ test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
+ test_ref_format downstream/submodule "$OTHER_FORMAT" &&
+
+ # Update the upstream submodule as well as the owning repository such
+ # that we can do a recursive pull.
+ test_commit -C submodule submodule-update &&
+ git -C upstream/submodule pull &&
+ git -C upstream commit -am "update the submodule" &&
+
+ git -C downstream pull --recurse-submodules &&
+ git -C upstream/submodule rev-parse HEAD >expect &&
+ git -C downstream/submodule rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+done
+
+test_done
diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh
index 60d627583d..9367794641 100755
--- a/t/t7450-bad-git-dotfiles.sh
+++ b/t/t7450-bad-git-dotfiles.sh
@@ -13,7 +13,6 @@ Such as:
- symlinked .gitmodules, etc
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pack.sh
@@ -45,6 +44,32 @@ test_expect_success 'check names' '
test_cmp expect actual
'
+test_expect_success 'check urls' '
+ cat >expect <<-\EOF &&
+ ./bar/baz/foo.git
+ https://example.com/foo.git
+ http://example.com:80/deeper/foo.git
+ EOF
+
+ test-tool submodule check-url >actual <<-\EOF &&
+ ./bar/baz/foo.git
+ https://example.com/foo.git
+ http://example.com:80/deeper/foo.git
+ -a./foo
+ ../../..//test/foo.git
+ ../../../../../:localhost:8080/foo.git
+ ..\../.\../:example.com/foo.git
+ ./%0ahost=example.com/foo.git
+ https://one.example.com/evil?%0ahost=two.example.com
+ https:///example.com/foo.git
+ http://example.com:test/foo.git
+ https::example.com/foo.git
+ http:::example.com/foo.git
+ EOF
+
+ test_cmp expect actual
+'
+
test_expect_success 'create innocent subrepo' '
git init innocent &&
git -C innocent commit --allow-empty -m foo
@@ -238,7 +263,7 @@ test_expect_success 'fsck detects non-blob .gitmodules' '
git ls-tree HEAD | sed s/subdir/.gitmodules/ | git mktree &&
test_must_fail git fsck 2>output &&
- test_i18ngrep gitmodulesBlob output
+ test_grep gitmodulesBlob output
)
'
@@ -252,8 +277,8 @@ test_expect_success 'fsck detects corrupt .gitmodules' '
git commit -m "broken gitmodules" &&
git fsck 2>output &&
- test_i18ngrep gitmodulesParse output &&
- test_i18ngrep ! "bad config" output
+ test_grep gitmodulesParse output &&
+ test_grep ! "bad config" output
)
'
@@ -275,7 +300,7 @@ test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
hash="$(echo x | git hash-object -w --stdin)" &&
test_must_fail git update-index --add \
--cacheinfo 160000,$rev,d\\a 2>err &&
- test_i18ngrep "Invalid path" err &&
+ test_grep "Invalid path" err &&
git -c core.protectNTFS=false update-index --add \
--cacheinfo 100644,$modules,.gitmodules \
--cacheinfo 160000,$rev,c \
@@ -289,7 +314,7 @@ test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
then
test_must_fail git -c core.protectNTFS=false \
clone --recurse-submodules squatting squatting-clone 2>err &&
- test_i18ngrep -e "directory not empty" -e "not an empty directory" err &&
+ test_grep -e "directory not empty" -e "not an empty directory" err &&
! grep gitdir squatting-clone/d/a/git~2
fi
'
@@ -317,7 +342,7 @@ test_expect_success 'setup submodules with nested git dirs' '
test_expect_success 'git dirs of sibling submodules must not be nested' '
test_must_fail git clone --recurse-submodules nested clone 2>err &&
- test_i18ngrep "is inside git dir" err
+ test_grep "is inside git dir" err
'
test_expect_success 'submodule git dir nesting detection must work with parallel cloning' '
diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
index 5fcaa0b4f2..4dca8d97a7 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -555,7 +555,7 @@ test_expect_success 'commit without staging files fails and displays hints' '
git commit -m initial &&
echo "changes" >>file &&
test_must_fail git commit -m update >actual &&
- test_i18ngrep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
+ test_grep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
'
test_done
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index fb5417d5e7..cc12f99f11 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -3,8 +3,7 @@
# Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
#
-# FIXME: Test the various index usages, -i and -o, test reflog,
-# signoff
+# FIXME: Test the various index usages, test reflog
test_description='git commit'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
@@ -21,7 +20,7 @@ test_expect_success 'initial status' '
echo bongo bongo >file &&
git add file &&
git status >actual &&
- test_i18ngrep "No commits yet" actual
+ test_grep "No commits yet" actual
'
test_expect_success 'fail initial amend' '
@@ -92,6 +91,20 @@ test_expect_success '--long fails with nothing to commit' '
test_must_fail git commit -m initial --long
'
+test_expect_success 'fail to commit untracked file (even with --include/--only)' '
+ echo content >baz &&
+ error="error: pathspec .baz. did not match any file(s) known to git" &&
+
+ test_must_fail git commit -m "baz" baz 2>err &&
+ test_grep -e "$error" err &&
+
+ test_must_fail git commit --only -m "baz" baz 2>err &&
+ test_grep -e "$error" err &&
+
+ test_must_fail git commit --include -m "baz" baz 2>err &&
+ test_grep -e "$error" err
+'
+
test_expect_success 'setup: non-initial commit' '
echo bongo bongo bongo >file &&
git commit -m next -a
@@ -117,6 +130,51 @@ test_expect_success '--long with stuff to commit returns ok' '
git commit -m next -a --long
'
+for opt in "" "-o" "--only"
+do
+ test_expect_success 'exclude additional staged changes when given pathspec' '
+ echo content >>file &&
+ echo content >>baz &&
+ git add baz &&
+ git commit $opt -m "file" file &&
+
+ git diff --name-only >actual &&
+ test_must_be_empty actual &&
+
+ test_write_lines baz >expect &&
+ git diff --name-only --cached >actual &&
+ test_cmp expect actual &&
+
+ test_write_lines file >expect &&
+ git diff --name-only HEAD^ HEAD >actual &&
+ test_cmp expect actual
+ '
+done
+
+test_expect_success '-i/--include includes staged changes' '
+ echo content >>file &&
+ echo content >>baz &&
+ git add file &&
+
+ # baz is in the index, therefore, it will be committed
+ git commit --include -m "file and baz" baz &&
+
+ git diff --name-only HEAD >remaining &&
+ test_must_be_empty remaining &&
+
+ test_write_lines baz file >expect &&
+ git diff --name-only HEAD^ HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--include and --only do not mix' '
+ test_when_finished "git reset --hard" &&
+ echo content >>file &&
+ echo content >>baz &&
+ test_must_fail git commit --include --only -m "file baz" file baz 2>actual &&
+ test_grep -e "fatal: options .-i/--include. and .-o/--only. cannot be used together" actual
+'
+
test_expect_success 'commit message from non-existing file' '
echo more bongo: bongo bongo bongo bongo >file &&
test_must_fail git commit -F gah -a
@@ -141,7 +199,7 @@ test_expect_success 'template "emptyness" check does not kick in with -F' '
test_expect_success 'template "emptyness" check' '
git checkout HEAD file && echo >>file && git add file &&
test_must_fail git commit -t file 2>err &&
- test_i18ngrep "did not edit" err
+ test_grep "did not edit" err
'
test_expect_success 'setup: commit message from file' '
@@ -389,6 +447,28 @@ test_expect_success 'amend commit to fix date' '
'
+test_expect_success 'amend commit to add signoff' '
+
+ test_commit "msg" file content &&
+ git commit --amend --signoff &&
+ test_commit_message HEAD <<-EOF
+ msg
+
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+'
+
+test_expect_success 'amend does not add signoff if it already exists' '
+
+ test_commit --signoff "tenor" file newcontent &&
+ git commit --amend --signoff &&
+ test_commit_message HEAD <<-EOF
+ tenor
+
+ Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+ EOF
+'
+
test_expect_success 'commit mentions forced date in output' '
git commit --amend --date=2010-01-02T03:04:05 >output &&
grep "Date: *Sat Jan 2 03:04:05 2010" output
@@ -671,7 +751,7 @@ test_expect_success 'commit a file whose name is a dash' '
git add ./- &&
test_tick &&
git commit -m "add dash" >output </dev/null &&
- test_i18ngrep " changed, 5 insertions" output
+ test_grep " changed, 5 insertions" output
'
test_expect_success '--only works on to-be-born branch' '
diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index b5bf7de7cd..b37e2018a7 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -485,6 +485,24 @@ test_expect_success 'commit --trailer not confused by --- separator' '
test_cmp expected actual
'
+test_expect_success 'commit --trailer with --verbose' '
+ cat >msg <<-\EOF &&
+ subject
+
+ body
+ EOF
+ GIT_EDITOR=: git commit --edit -F msg --allow-empty \
+ --trailer="my-trailer: value" --verbose &&
+ {
+ 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 &&
@@ -706,18 +724,23 @@ test_expect_success 'cleanup commit message (whitespace config, -m)' '
test_expect_success 'message shows author when it is not equal to committer' '
echo >>negative &&
git commit -e -m "sample" -a &&
- test_i18ngrep \
+ test_grep \
"^# Author: *A U Thor <author@example.com>\$" \
.git/COMMIT_EDITMSG
'
test_expect_success 'message shows date when it is explicitly set' '
git commit --allow-empty -e -m foo --date="2010-01-02T03:04:05" &&
- test_i18ngrep \
+ test_grep \
"^# Date: *Sat Jan 2 03:04:05 2010 +0000" \
.git/COMMIT_EDITMSG
'
+test_expect_success 'message does not have multiple scissors lines' '
+ git commit --cleanup=scissors -v --allow-empty -e -m foo &&
+ test $(grep -c -e "--- >8 ---" .git/COMMIT_EDITMSG) -eq 1
+'
+
test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
echo >>negative &&
@@ -728,7 +751,7 @@ test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
) &&
# the ident is calculated from the system, so we cannot
# check the actual value, only that it is there
- test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG
+ test_grep "^# Committer: " .git/COMMIT_EDITMSG
'
write_script .git/FAKE_EDITOR <<EOF
@@ -860,9 +883,9 @@ try_commit () {
GIT_EDITOR=.git/FAKE_EDITOR git commit -a $* $use_template &&
case "$use_template" in
'')
- test_i18ngrep ! "^## Custom template" .git/COMMIT_EDITMSG ;;
+ test_grep ! "^## Custom template" .git/COMMIT_EDITMSG ;;
*)
- test_i18ngrep "^## Custom template" .git/COMMIT_EDITMSG ;;
+ test_grep "^## Custom template" .git/COMMIT_EDITMSG ;;
esac
}
@@ -870,53 +893,53 @@ try_commit_status_combo () {
test_expect_success 'commit' '
try_commit "" &&
- test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status' '
try_commit --status &&
- test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status' '
try_commit --no-status &&
- test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit with commit.status = yes' '
test_config commit.status yes &&
try_commit "" &&
- test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit with commit.status = no' '
test_config commit.status no &&
try_commit "" &&
- test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status with commit.status = yes' '
test_config commit.status yes &&
try_commit --status &&
- test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status with commit.status = yes' '
test_config commit.status yes &&
try_commit --no-status &&
- test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --status with commit.status = no' '
test_config commit.status no &&
try_commit --status &&
- test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'commit --no-status with commit.status = no' '
test_config commit.status no &&
try_commit --no-status &&
- test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
}
@@ -930,13 +953,13 @@ try_commit_status_combo
test_expect_success 'commit --status with custom comment character' '
test_config core.commentchar ";" &&
try_commit --status &&
- test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^; Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'switch core.commentchar' '
test_commit "#foo" foo &&
GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend &&
- test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
+ test_grep "^; Changes to be committed:" .git/COMMIT_EDITMSG
'
test_expect_success 'switch core.commentchar but out of options' '
diff --git a/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
index aa004b70a8..ad1eb64ba0 100755
--- a/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
+++ b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
@@ -5,7 +5,6 @@ test_description='pre-commit and pre-merge-commit hooks'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'root commit' '
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index d1255228d5..c0f024eb1e 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -5,7 +5,6 @@ test_description='commit-msg hook'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'with no hook' '
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index d050091345..185fe7e78e 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -2,7 +2,6 @@
test_description='git status for submodule'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_create_repo_with_commit () {
@@ -37,19 +36,19 @@ test_expect_success 'setup' '
test_expect_success 'status clean' '
git status >output &&
- test_i18ngrep "nothing to commit" output
+ test_grep "nothing to commit" output
'
test_expect_success 'commit --dry-run -a clean' '
test_must_fail git commit --dry-run -a >output &&
- test_i18ngrep "nothing to commit" output
+ test_grep "nothing to commit" output
'
test_expect_success 'status with modified file in submodule' '
(cd sub && git reset --hard) &&
echo "changed" >sub/foo &&
git status >output &&
- test_i18ngrep "modified: sub (modified content)" output
+ test_grep "modified: sub (modified content)" output
'
test_expect_success 'status with modified file in submodule (porcelain)' '
@@ -73,7 +72,7 @@ test_expect_success 'status with modified file in submodule (short)' '
test_expect_success 'status with added file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
- test_i18ngrep "modified: sub (modified content)" output
+ test_grep "modified: sub (modified content)" output
'
test_expect_success 'status with added file in submodule (porcelain)' '
@@ -96,12 +95,12 @@ test_expect_success 'status with untracked file in submodule' '
(cd sub && git reset --hard) &&
echo "content" >sub/new-file &&
git status >output &&
- test_i18ngrep "modified: sub (untracked content)" output
+ test_grep "modified: sub (untracked content)" output
'
test_expect_success 'status -uno with untracked file in submodule' '
git status -uno >output &&
- test_i18ngrep "^nothing to commit" output
+ test_grep "^nothing to commit" output
'
test_expect_success 'status with untracked file in submodule (porcelain)' '
@@ -122,7 +121,7 @@ test_expect_success 'status with added and untracked file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
echo "content" >sub/new-file &&
git status >output &&
- test_i18ngrep "modified: sub (modified content, untracked content)" output
+ test_grep "modified: sub (modified content, untracked content)" output
'
test_expect_success 'status with added and untracked file in submodule (porcelain)' '
@@ -140,7 +139,7 @@ test_expect_success 'status with modified file in modified submodule' '
(cd sub && echo "next change" >foo && git commit -m "next change" foo) &&
echo "changed" >sub/foo &&
git status >output &&
- test_i18ngrep "modified: sub (new commits, modified content)" output
+ test_grep "modified: sub (new commits, modified content)" output
'
test_expect_success 'status with modified file in modified submodule (porcelain)' '
@@ -155,7 +154,7 @@ test_expect_success 'status with modified file in modified submodule (porcelain)
test_expect_success 'status with added file in modified submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
- test_i18ngrep "modified: sub (new commits, modified content)" output
+ test_grep "modified: sub (new commits, modified content)" output
'
test_expect_success 'status with added file in modified submodule (porcelain)' '
@@ -170,7 +169,7 @@ test_expect_success 'status with untracked file in modified submodule' '
(cd sub && git reset --hard) &&
echo "content" >sub/new-file &&
git status >output &&
- test_i18ngrep "modified: sub (new commits, untracked content)" output
+ test_grep "modified: sub (new commits, untracked content)" output
'
test_expect_success 'status with untracked file in modified submodule (porcelain)' '
@@ -184,7 +183,7 @@ test_expect_success 'status with added and untracked file in modified submodule'
(cd sub && git reset --hard && echo >foo && git add foo) &&
echo "content" >sub/new-file &&
git status >output &&
- test_i18ngrep "modified: sub (new commits, modified content, untracked content)" output
+ test_grep "modified: sub (new commits, modified content, untracked content)" output
'
test_expect_success 'status with added and untracked file in modified submodule (porcelain)' '
@@ -209,7 +208,7 @@ test_expect_success 'setup .git file for sub' '
test_expect_success 'status with added file in modified submodule with .git file' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
- test_i18ngrep "modified: sub (new commits, modified content)" output
+ test_grep "modified: sub (new commits, modified content)" output
'
test_expect_success 'status with a lot of untracked files in the submodule' '
@@ -234,12 +233,12 @@ test_expect_success 'rm submodule contents' '
test_expect_success 'status clean (empty submodule dir)' '
git status >output &&
- test_i18ngrep "nothing to commit" output
+ test_grep "nothing to commit" output
'
test_expect_success 'status -a clean (empty submodule dir)' '
test_must_fail git commit --dry-run -a >output &&
- test_i18ngrep "nothing to commit" output
+ test_grep "nothing to commit" output
'
cat >status_expect <<\EOF
diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh
index 916470c48b..b53d71c086 100755
--- a/t/t7507-commit-verbose.sh
+++ b/t/t7507-commit-verbose.sh
@@ -2,7 +2,6 @@
test_description='verbose commit template'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
write_script "check-for-diff" <<\EOF &&
@@ -89,7 +88,7 @@ test_expect_success 'submodule log is stripped out too with -v' '
export GIT_EDITOR &&
test_must_fail git commit -a -v 2>err
) &&
- test_i18ngrep "Aborting commit due to empty commit message." err
+ test_grep "Aborting commit due to empty commit message." err
'
test_expect_success 'verbose diff is stripped out with set core.commentChar' '
@@ -98,7 +97,17 @@ test_expect_success 'verbose diff is stripped out with set core.commentChar' '
export GIT_EDITOR &&
test_must_fail git -c core.commentchar=";" commit -a -v 2>err
) &&
- test_i18ngrep "Aborting commit due to empty commit message." err
+ test_grep "Aborting commit due to empty commit message." err
+'
+
+test_expect_success 'verbose diff is stripped with multi-byte comment char' '
+ (
+ GIT_EDITOR=cat &&
+ export GIT_EDITOR &&
+ test_must_fail git -c core.commentchar="foo>" commit -a -v >out 2>err
+ ) &&
+ grep "^foo> " out &&
+ test_grep "Aborting commit due to empty commit message." err
'
test_expect_success 'status does not verbose without --verbose' '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 6928fd89f5..f9a5c98f3f 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -5,7 +5,6 @@
test_description='git status'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
@@ -19,7 +18,7 @@ test_expect_success 'status -h in broken repository' '
echo "[status] showuntrackedfiles = CORRUPT" >>.git/config &&
test_expect_code 129 git status -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage" broken/usage
+ test_grep "[Uu]sage" broken/usage
'
test_expect_success 'commit -h in broken repository' '
@@ -31,7 +30,7 @@ test_expect_success 'commit -h in broken repository' '
echo "[status] showuntrackedfiles = CORRUPT" >>.git/config &&
test_expect_code 129 git commit -h >usage 2>&1
) &&
- test_i18ngrep "[Uu]sage" broken/usage
+ test_grep "[Uu]sage" broken/usage
'
test_expect_success 'create upstream branch' '
@@ -72,7 +71,7 @@ test_expect_success 'setup' '
'
test_expect_success 'status (1)' '
- test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
+ test_grep "use \"git rm --cached <file>\.\.\.\" to unstage" output
'
strip_comments () {
@@ -419,14 +418,19 @@ Changes not staged for commit:
Untracked files not listed (use -u option to show untracked files)
EOF
git status -uno >output &&
+ test_cmp expect output &&
+ git status -ufalse >output &&
test_cmp expect output
'
-test_expect_success 'status (status.showUntrackedFiles no)' '
- test_config status.showuntrackedfiles no &&
- git status >output &&
- test_cmp expect output
-'
+for no in no false 0
+do
+ test_expect_success "status (status.showUntrackedFiles $no)" '
+ test_config status.showuntrackedfiles "$no" &&
+ git status >output &&
+ test_cmp expect output
+ '
+done
test_expect_success 'status -uno (advice.statusHints false)' '
cat >expect <<EOF &&
@@ -488,14 +492,21 @@ Untracked files:
EOF
git status -unormal >output &&
+ test_cmp expect output &&
+ git status -utrue >output &&
+ test_cmp expect output &&
+ git status -uyes >output &&
test_cmp expect output
'
-test_expect_success 'status (status.showUntrackedFiles normal)' '
- test_config status.showuntrackedfiles normal &&
- git status >output &&
- test_cmp expect output
-'
+for normal in normal true 1
+do
+ test_expect_success "status (status.showUntrackedFiles $normal)" '
+ test_config status.showuntrackedfiles $normal &&
+ git status >output &&
+ test_cmp expect output
+ '
+done
cat >expect <<EOF
M dir1/modified
@@ -1403,7 +1414,9 @@ test_expect_success "status (core.commentchar with submodule summary)" '
test_expect_success "status (core.commentchar with two chars with submodule summary)" '
test_config core.commentchar ";;" &&
- test_must_fail git -c status.displayCommentPrefix=true status
+ sed "s/^/;/" <expect >expect.double &&
+ git -c status.displayCommentPrefix=true status >output &&
+ test_cmp expect.double output
'
test_expect_success "--ignore-submodules=all suppresses submodule summary" '
@@ -1542,12 +1555,12 @@ test_expect_success 'git commit will commit a staged but ignored submodule' '
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore all &&
git status -s --ignore-submodules=dirty >output &&
- test_i18ngrep "^M. sm" output &&
+ test_grep "^M. sm" output &&
GIT_EDITOR="echo hello >>\"\$1\"" &&
export GIT_EDITOR &&
git commit -uno &&
git status -s --ignore-submodules=dirty >output &&
- test_i18ngrep ! "^M. sm" output
+ test_grep ! "^M. sm" output
'
test_expect_success 'git commit --dry-run will show a staged but ignored submodule' '
@@ -1572,13 +1585,13 @@ EOF
git commit -uno --dry-run >output &&
test_cmp expect output &&
git status -s --ignore-submodules=dirty >output &&
- test_i18ngrep "^M. sm" output
+ test_grep "^M. sm" output
'
test_expect_success 'git commit -m will commit a staged but ignored submodule' '
git commit -uno -m message &&
git status -s --ignore-submodules=dirty >output &&
- test_i18ngrep ! "^M. sm" output &&
+ test_grep ! "^M. sm" output &&
git config --remove-section submodule.subname &&
git config -f .gitmodules --remove-section submodule.subname
'
@@ -1591,7 +1604,7 @@ test_expect_success 'show stash info with "--show-stash"' '
git stash &&
git status >expected_default &&
git status --show-stash >expected_with_stash &&
- test_i18ngrep "^Your stash currently has 1 entry$" expected_with_stash
+ test_grep "^Your stash currently has 1 entry$" expected_with_stash
'
test_expect_success 'no stash info with "--show-stash --no-show-stash"' '
@@ -1618,14 +1631,14 @@ test_expect_success 'no additional info if no stash entries' '
test_expect_success '"No commits yet" should be noted in status output' '
git checkout --orphan empty-branch-1 &&
git status >output &&
- test_i18ngrep "No commits yet" output
+ test_grep "No commits yet" output
'
test_expect_success '"No commits yet" should not be noted in status output' '
git checkout --orphan empty-branch-2 &&
test_commit test-commit-1 &&
git status >output &&
- test_i18ngrep ! "No commits yet" output
+ test_grep ! "No commits yet" output
'
test_expect_success '"Initial commit" should be noted in commit template' '
@@ -1633,7 +1646,7 @@ test_expect_success '"Initial commit" should be noted in commit template' '
touch to_be_committed_1 &&
git add to_be_committed_1 &&
git commit --dry-run >output &&
- test_i18ngrep "Initial commit" output
+ test_grep "Initial commit" output
'
test_expect_success '"Initial commit" should not be noted in commit template' '
@@ -1642,7 +1655,7 @@ test_expect_success '"Initial commit" should not be noted in commit template' '
touch to_be_committed_2 &&
git add to_be_committed_2 &&
git commit --dry-run >output &&
- test_i18ngrep ! "Initial commit" output
+ test_grep ! "Initial commit" output
'
test_expect_success '--no-optional-locks prevents index update' '
@@ -1745,4 +1758,20 @@ test_expect_success 'slow status advice when core.untrackedCache true, and fsmon
)
'
+test_expect_success EXPENSIVE 'status does not re-read unchanged 4 or 8 GiB file' '
+ (
+ mkdir large-file &&
+ cd large-file &&
+ # Files are 2 GiB, 4 GiB, and 8 GiB sparse files.
+ test-tool truncate file-a 0x080000000 &&
+ test-tool truncate file-b 0x100000000 &&
+ test-tool truncate file-c 0x200000000 &&
+ # This will be slow.
+ git add file-a file-b file-c &&
+ git commit -m "add large files" &&
+ git diff-index HEAD file-a file-b file-c >actual &&
+ test_must_be_empty actual
+ )
+'
+
test_done
diff --git a/t/t7509-commit-authorship.sh b/t/t7509-commit-authorship.sh
index 5d890949f7..8e373b566b 100755
--- a/t/t7509-commit-authorship.sh
+++ b/t/t7509-commit-authorship.sh
@@ -5,7 +5,6 @@
test_description='commit tests of various authorhip options. '
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
author_header () {
@@ -99,7 +98,7 @@ test_expect_success '--amend option with empty author' '
echo "Empty author test" >>foo &&
test_tick &&
test_must_fail git commit -a -m "empty author" --amend 2>err &&
- test_i18ngrep "empty ident" err
+ test_grep "empty ident" err
'
test_expect_success '--amend option with missing author' '
@@ -112,7 +111,7 @@ test_expect_success '--amend option with missing author' '
echo "Missing author test" >>foo &&
test_tick &&
test_must_fail git commit -a -m "malformed author" --amend 2>err &&
- test_i18ngrep "empty ident" err
+ test_grep "empty ident" err
'
test_expect_success '--reset-author makes the commit ours even with --amend option' '
diff --git a/t/t7511-status-index.sh b/t/t7511-status-index.sh
index 4ffa45a7bf..b5fdc048a5 100755
--- a/t/t7511-status-index.sh
+++ b/t/t7511-status-index.sh
@@ -2,7 +2,6 @@
test_description='git status with certain file name lengths'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
files="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"
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index c2ab8a444a..802f8f704c 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -692,6 +692,34 @@ EOF
'
+test_expect_success 'status when bisecting while rebasing' '
+ git reset --hard main &&
+ test_when_finished "git rebase --abort" &&
+ ONTO=$(git rev-parse --short HEAD^) &&
+ FAKE_LINES="break" git rebase -i HEAD^ &&
+ test_when_finished "git checkout -" &&
+ git checkout -b bisect_while_rebasing &&
+ test_when_finished "git bisect reset" &&
+ git bisect start &&
+ cat >expected <<EOF &&
+On branch bisect_while_rebasing
+Last command done (1 command done):
+ break
+No commands remaining.
+You are currently editing a commit while rebasing branch '\''bisect'\'' on '\''$ONTO'\''.
+ (use "git commit --amend" to amend the current commit)
+ (use "git rebase --continue" once you are satisfied with your changes)
+
+You are currently bisecting, started from branch '\''bisect_while_rebasing'\''.
+ (use "git bisect reset" to get back to the original branch)
+
+nothing to commit (use -u to show untracked files)
+EOF
+ git status --untracked-files=no >actual &&
+ test_cmp expected actual
+'
+
+
test_expect_success 'status when rebase --apply conflicts with statushints disabled' '
git reset --hard main &&
git checkout -b statushints_disabled &&
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index 97f10905d2..818a8dafbd 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -175,6 +175,46 @@ test_expect_success 'with only a title in the message' '
test_cmp expected actual
'
+test_expect_success 'with a bodiless message that lacks a trailing newline after the subject' '
+ cat >expected <<-\EOF &&
+ area: change
+
+ Reviewed-by: Peff
+ Acked-by: Johan
+ EOF
+ printf "area: change" |
+ git interpret-trailers --trailer "Reviewed-by: Peff" \
+ --trailer "Acked-by: Johan" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'with a bodied message that lacks a trailing newline after the body' '
+ cat >expected <<-\EOF &&
+ area: change
+
+ details about the change.
+
+ Reviewed-by: Peff
+ Acked-by: Johan
+ EOF
+ printf "area: change\n\ndetails about the change." |
+ git interpret-trailers --trailer "Reviewed-by: Peff" \
+ --trailer "Acked-by: Johan" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'with a message that lacks a trailing newline after the trailers' '
+ cat >expected <<-\EOF &&
+ area: change
+
+ Reviewed-by: Peff
+ Acked-by: Johan
+ EOF
+ printf "area: change\n\nReviewed-by: Peff" |
+ git interpret-trailers --trailer "Acked-by: Johan" >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'with multiline title in the message' '
cat >expected <<-\EOF &&
place of
@@ -489,7 +529,7 @@ test_expect_success 'multiline field treated as atomic for neighbor check' '
'
test_expect_success 'with config setup' '
- git config trailer.ack.key "Acked-by: " &&
+ test_config trailer.ack.key "Acked-by: " &&
cat >expected <<-\EOF &&
Acked-by: Peff
@@ -503,8 +543,8 @@ test_expect_success 'with config setup' '
'
test_expect_success 'with config setup and ":=" as separators' '
- git config trailer.separators ":=" &&
- git config trailer.ack.key "Acked-by= " &&
+ test_config trailer.separators ":=" &&
+ test_config trailer.ack.key "Acked-by= " &&
cat >expected <<-\EOF &&
Acked-by= Peff
@@ -518,7 +558,7 @@ test_expect_success 'with config setup and ":=" as separators' '
'
test_expect_success 'with config setup and "%" as separators' '
- git config trailer.separators "%" &&
+ test_config trailer.separators "%" &&
cat >expected <<-\EOF &&
bug% 42
@@ -532,6 +572,7 @@ test_expect_success 'with config setup and "%" as separators' '
'
test_expect_success 'with "%" as separators and a message with trailers' '
+ test_config trailer.separators "%" &&
cat >special_message <<-\EOF &&
Special Message
@@ -553,8 +594,8 @@ test_expect_success 'with "%" as separators and a message with trailers' '
'
test_expect_success 'with config setup and ":=#" as separators' '
- git config trailer.separators ":=#" &&
- git config trailer.bug.key "Bug #" &&
+ test_config trailer.separators ":=#" &&
+ test_config trailer.bug.key "Bug #" &&
cat >expected <<-\EOF &&
Bug #42
@@ -581,6 +622,8 @@ test_expect_success 'with basic patch' '
'
test_expect_success 'with commit complex message as argument' '
+ test_config trailer.separators ":=" &&
+ test_config trailer.ack.key "Acked-by= " &&
cat complex_message_body complex_message_trailers >complex_message &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
@@ -594,6 +637,8 @@ test_expect_success 'with commit complex message as argument' '
'
test_expect_success 'with 2 files arguments' '
+ test_config trailer.separators ":=" &&
+ test_config trailer.ack.key "Acked-by= " &&
cat basic_message >>expected &&
echo >>expected &&
cat basic_patch >>expected &&
@@ -677,6 +722,9 @@ test_expect_success 'with message that has an old style conflict block' '
'
test_expect_success 'with commit complex message and trailer args' '
+ test_config trailer.separators ":=#" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.bug.key "Bug #" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -692,6 +740,9 @@ test_expect_success 'with commit complex message and trailer args' '
'
test_expect_success 'with complex patch, args and --trim-empty' '
+ test_config trailer.separators ":=#" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.bug.key "Bug #" &&
cat complex_message >complex_patch &&
cat basic_patch >>complex_patch &&
cat complex_message_body >expected &&
@@ -746,7 +797,10 @@ test_expect_success POSIXPERM,SANITY "in-place editing doesn't clobber original
'
test_expect_success 'using "where = before"' '
- git config trailer.bug.where "before" &&
+ test_config trailer.separators ":=#" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -762,7 +816,9 @@ test_expect_success 'using "where = before"' '
'
test_expect_success 'overriding configuration with "--where after"' '
- git config trailer.ack.where "before" &&
+ test_config trailer.separators ":=" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "before" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -776,7 +832,12 @@ test_expect_success 'overriding configuration with "--where after"' '
test_cmp expected actual
'
-test_expect_success 'using "where = before" with "--no-where"' '
+test_expect_success 'using "--where after" with "--no-where"' '
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "before" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -791,8 +852,59 @@ test_expect_success 'using "where = before" with "--no-where"' '
test_cmp expected actual
'
+# Check whether using "--no-where" clears out only the "--where after", such
+# that we still use the configuration in trailer.where (which is different from
+# the hardcoded default (in WHERE_END) assuming the absence of .gitconfig).
+# Here, the "start" setting of trailer.where is respected, so the new "Acked-by"
+# and "Bug" trailers are placed at the beginning, and not at the end which is
+# the hardcoded default.
+test_expect_success 'using "--where after" with "--no-where" defaults to configuration' '
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.separators ":=#" &&
+ test_config trailer.where "start" &&
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Bug #42
+ Acked-by= Peff
+ Fixes: Z
+ Acked-by= Z
+ Reviewed-by: Z
+ Signed-off-by: Z
+ EOF
+ git interpret-trailers --where after --no-where --trailer "ack: Peff" \
+ --trailer "bug: 42" complex_message >actual &&
+ test_cmp expected actual
+'
+
+# The "--where after" will only get respected for the trailer that came
+# immediately after it. For the next trailer (Bug #42), we default to using the
+# hardcoded WHERE_END because we don't have any "trailer.where" or
+# "trailer.bug.where" configured.
+test_expect_success 'using "--no-where" defaults to hardcoded default if nothing configured' '
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.separators ":=#" &&
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Fixes: Z
+ Acked-by= Z
+ Acked-by= Peff
+ Reviewed-by: Z
+ Signed-off-by: Z
+ Bug #42
+ EOF
+ git interpret-trailers --where after --trailer "ack: Peff" --no-where \
+ --trailer "bug: 42" complex_message >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'using "where = after"' '
- git config trailer.ack.where "after" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -808,8 +920,11 @@ test_expect_success 'using "where = after"' '
'
test_expect_success 'using "where = end"' '
- git config trailer.review.key "Reviewed-by" &&
- git config trailer.review.where "end" &&
+ test_config trailer.review.key "Reviewed-by" &&
+ test_config trailer.review.where "end" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -827,8 +942,11 @@ test_expect_success 'using "where = end"' '
'
test_expect_success 'using "where = start"' '
- git config trailer.review.key "Reviewed-by" &&
- git config trailer.review.where "start" &&
+ test_config trailer.review.key "Reviewed-by" &&
+ test_config trailer.review.where "start" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Reviewed-by: Johannes
@@ -846,8 +964,13 @@ test_expect_success 'using "where = start"' '
'
test_expect_success 'using "where = before" for a token in the middle of the message' '
- git config trailer.review.key "Reviewed-by:" &&
- git config trailer.review.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.review.where "before" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -864,6 +987,12 @@ test_expect_success 'using "where = before" for a token in the middle of the mes
'
test_expect_success 'using "where = before" and --trim-empty' '
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
cat >>expected <<-\EOF &&
Bug #46
@@ -878,6 +1007,13 @@ test_expect_success 'using "where = before" and --trim-empty' '
'
test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' '
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.review.where "before" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -896,7 +1032,13 @@ test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' '
'
test_expect_success 'default "ifExists" is now "addIfDifferent"' '
- git config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -914,8 +1056,14 @@ test_expect_success 'default "ifExists" is now "addIfDifferent"' '
'
test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' '
- git config trailer.ack.ifExists "addIfDifferent" &&
- git config trailer.ack.where "end" &&
+ test_config trailer.ack.ifExists "addIfDifferent" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "end" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -932,8 +1080,14 @@ test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' '
'
test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' '
- git config trailer.ack.ifExists "addIfDifferent" &&
- git config trailer.ack.where "before" &&
+ test_config trailer.ack.ifExists "addIfDifferent" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "before" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -950,8 +1104,14 @@ test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' '
'
test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end"' '
- git config trailer.ack.ifExists "addIfDifferentNeighbor" &&
- git config trailer.ack.where "end" &&
+ test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "end" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -973,8 +1133,14 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end
'
test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = after"' '
- git config trailer.ack.ifExists "addIfDifferentNeighbor" &&
- git config trailer.ack.where "after" &&
+ test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -995,7 +1161,11 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = af
'
test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty' '
- git config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+ test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
cat >>expected <<-\EOF &&
Bug #42
@@ -1011,8 +1181,14 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty'
'
test_expect_success 'using "ifExists = add" with "where = end"' '
- git config trailer.ack.ifExists "add" &&
- git config trailer.ack.where "end" &&
+ test_config trailer.ack.ifExists "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "end" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1036,8 +1212,14 @@ test_expect_success 'using "ifExists = add" with "where = end"' '
'
test_expect_success 'using "ifExists = add" with "where = after"' '
- git config trailer.ack.ifExists "add" &&
- git config trailer.ack.where "after" &&
+ test_config trailer.ack.ifExists "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1058,8 +1240,15 @@ test_expect_success 'using "ifExists = add" with "where = after"' '
'
test_expect_success 'overriding configuration with "--if-exists replace"' '
- git config trailer.fix.key "Fixes: " &&
- git config trailer.fix.ifExists "add" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.review.where "before" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1074,9 +1263,66 @@ test_expect_success 'overriding configuration with "--if-exists replace"' '
test_cmp expected actual
'
+# "trailer.ifexists" is set to "doNothing", so using "--no-if-exists" defaults
+# to this "doNothing" behavior. So the "Fixes: 53" trailer does not get added.
+test_expect_success 'using "--if-exists replace" with "--no-if-exists" defaults to configuration' '
+ test_config trailer.ifexists "doNothing" &&
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Fixes: Z
+ Acked-by: Z
+ Reviewed-by: Z
+ Signed-off-by: Z
+ EOF
+ git interpret-trailers --if-exists replace --no-if-exists --trailer "Fixes: 53" \
+ <complex_message >actual &&
+ test_cmp expected actual
+'
+
+# No "ifexists" configuration is set, so using "--no-if-exists" makes it default
+# to addIfDifferentNeighbor. Because we do have a different neighbor "Fixes: 53"
+# (because it got added by overriding with "--if-exists replace" earlier in the
+# arguments list), we add "Signed-off-by: addme".
+test_expect_success 'using "--no-if-exists" defaults to hardcoded default if nothing configured' '
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Acked-by: Z
+ Reviewed-by: Z
+ Signed-off-by: Z
+ Fixes: 53
+ Signed-off-by: addme
+ EOF
+ git interpret-trailers --if-exists replace --trailer "Fixes: 53" --no-if-exists \
+ --trailer "Signed-off-by: addme" <complex_message >actual &&
+ test_cmp expected actual
+'
+
+# The second "Fixes: 53" trailer is discarded, because the "--no-if-exists" here
+# makes us default to addIfDifferentNeighbor, and we already added the "Fixes:
+# 53" trailer earlier in the argument list.
+test_expect_success 'using "--no-if-exists" defaults to hardcoded default if nothing configured (no addition)' '
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Acked-by: Z
+ Reviewed-by: Z
+ Signed-off-by: Z
+ Fixes: 53
+ EOF
+ git interpret-trailers --if-exists replace --trailer "Fixes: 53" --no-if-exists \
+ --trailer "Fixes: 53" <complex_message >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'using "ifExists = replace"' '
- git config trailer.fix.key "Fixes: " &&
- git config trailer.fix.ifExists "replace" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "replace" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1095,7 +1341,16 @@ test_expect_success 'using "ifExists = replace"' '
'
test_expect_success 'using "ifExists = replace" with "where = after"' '
- git config trailer.fix.where "after" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "replace" &&
+ test_config trailer.fix.where "after" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1114,7 +1369,15 @@ test_expect_success 'using "ifExists = replace" with "where = after"' '
'
test_expect_success 'using "ifExists = doNothing"' '
- git config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1133,8 +1396,17 @@ test_expect_success 'using "ifExists = doNothing"' '
'
test_expect_success 'the default is "ifMissing = add"' '
- git config trailer.cc.key "Cc: " &&
- git config trailer.cc.where "before" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.cc.key "Cc: " &&
+ test_config trailer.cc.where "before" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1154,7 +1426,14 @@ test_expect_success 'the default is "ifMissing = add"' '
'
test_expect_success 'overriding configuration with "--if-missing doNothing"' '
- git config trailer.ifmissing "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.ifmissing "add" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -1173,7 +1452,13 @@ test_expect_success 'overriding configuration with "--if-missing doNothing"' '
'
test_expect_success 'when default "ifMissing" is "doNothing"' '
- git config trailer.ifmissing "doNothing" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.ifmissing "doNothing" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -1187,14 +1472,21 @@ test_expect_success 'when default "ifMissing" is "doNothing"' '
--trailer "cc=Linus" --trailer "ack: Junio" \
--trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \
<complex_message >actual &&
- test_cmp expected actual &&
- git config trailer.ifmissing "add"
+ test_cmp expected actual
'
test_expect_success 'using "ifMissing = add" with "where = end"' '
- git config trailer.cc.key "Cc: " &&
- git config trailer.cc.where "end" &&
- git config trailer.cc.ifMissing "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.cc.key "Cc: " &&
+ test_config trailer.cc.ifMissing "add" &&
+ test_config trailer.cc.where "end" &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1214,9 +1506,17 @@ test_expect_success 'using "ifMissing = add" with "where = end"' '
'
test_expect_success 'using "ifMissing = add" with "where = before"' '
- git config trailer.cc.key "Cc: " &&
- git config trailer.cc.where "before" &&
- git config trailer.cc.ifMissing "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.cc.key "Cc: " &&
+ test_config trailer.cc.ifMissing "add" &&
+ test_config trailer.cc.where "before" &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Cc: Linus
@@ -1236,7 +1536,15 @@ test_expect_success 'using "ifMissing = add" with "where = before"' '
'
test_expect_success 'using "ifMissing = doNothing"' '
- git config trailer.cc.ifMissing "doNothing" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.cc.ifMissing "doNothing" &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1254,9 +1562,50 @@ test_expect_success 'using "ifMissing = doNothing"' '
test_cmp expected actual
'
+# Ignore the "IgnoredTrailer" because of "--if-missing doNothing", but also
+# ignore the "StillIgnoredTrailer" because we set "trailer.ifMissing" to
+# "doNothing" in configuration.
+test_expect_success 'using "--no-if-missing" defaults to configuration' '
+ test_config trailer.ifMissing "doNothing" &&
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Fixes: Z
+ Acked-by: Z
+ Reviewed-by: Z
+ Signed-off-by: Z
+ EOF
+ git interpret-trailers --if-missing doNothing --trailer "IgnoredTrailer: ignoreme" --no-if-missing \
+ --trailer "StillIgnoredTrailer: ignoreme" <complex_message >actual &&
+ test_cmp expected actual
+'
+
+# Add the "AddedTrailer" because the "--no-if-missing" clears the "--if-missing
+# doNothing" from earlier in the argument list.
+test_expect_success 'using "--no-if-missing" defaults to hardcoded default if nothing configured' '
+ cat complex_message_body >expected &&
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+ Fixes: Z
+ Acked-by: Z
+ Reviewed-by: Z
+ Signed-off-by: Z
+ AddedTrailer: addme
+ EOF
+ git interpret-trailers --if-missing doNothing --trailer "IgnoredTrailer: ignoreme" --no-if-missing \
+ --trailer "AddedTrailer: addme" <complex_message >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'default "where" is now "after"' '
git config trailer.where "after" &&
- git config --unset trailer.ack.where &&
+ test_config trailer.ack.ifExists "add" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.ack.where "after" &&
+ test_config trailer.bug.key "Bug #" &&
+ test_config trailer.bug.where "before" &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
@@ -1280,10 +1629,15 @@ test_expect_success 'default "where" is now "after"' '
'
test_expect_success 'with simple command' '
- git config trailer.sign.key "Signed-off-by: " &&
- git config trailer.sign.where "after" &&
- git config trailer.sign.ifExists "addIfDifferentNeighbor" &&
- git config trailer.sign.command "echo \"A U Thor <author@example.com>\"" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.sign.command "echo \"A U Thor <author@example.com>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.sign.ifExists "addIfDifferentNeighbor" &&
+ test_config trailer.sign.where "after" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -1298,8 +1652,14 @@ test_expect_success 'with simple command' '
'
test_expect_success 'with command using committer information' '
- git config trailer.sign.ifExists "addIfDifferent" &&
- git config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.sign.ifExists "addIfDifferent" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -1314,10 +1674,15 @@ test_expect_success 'with command using committer information' '
'
test_expect_success 'with command using author information' '
- git config trailer.sign.key "Signed-off-by: " &&
- git config trailer.sign.where "after" &&
- git config trailer.sign.ifExists "addIfDifferentNeighbor" &&
- git config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.fix.ifExists "doNothing" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.sign.ifExists "addIfDifferentNeighbor" &&
+ test_config trailer.sign.where "after" &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
@@ -1338,12 +1703,19 @@ test_expect_success 'setup a commit' '
'
test_expect_success 'cmd takes precedence over command' '
- test_when_finished "git config --unset trailer.fix.cmd" &&
- git config trailer.fix.ifExists "replace" &&
- git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
- --abbrev-commit --abbrev=14 \"\$1\" || true" &&
- git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
--abbrev-commit --abbrev=14 \$ARG" &&
+ test_config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
+ --abbrev-commit --abbrev=14 \"\$1\" || true" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "replace" &&
+ test_config trailer.fix.where "after" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=" &&
FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
cat complex_message_body >expected2 &&
sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
@@ -1359,8 +1731,16 @@ test_expect_success 'cmd takes precedence over command' '
'
test_expect_success 'with command using $ARG' '
- git config trailer.fix.ifExists "replace" &&
- git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "replace" &&
+ test_config trailer.fix.where "after" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=" &&
FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-EOF &&
@@ -1376,8 +1756,16 @@ test_expect_success 'with command using $ARG' '
'
test_expect_success 'with failing command using $ARG' '
- git config trailer.fix.ifExists "replace" &&
- git config trailer.fix.command "false \$ARG" &&
+ test_config trailer.ack.key "Acked-by= " &&
+ test_config trailer.fix.command "false \$ARG" &&
+ test_config trailer.fix.key "Fixes: " &&
+ test_config trailer.fix.ifExists "replace" &&
+ test_config trailer.fix.where "after" &&
+ test_config trailer.review.key "Reviewed-by:" &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.ifexists "addIfDifferent" &&
+ test_config trailer.separators ":=" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-EOF &&
Fixes: Z
@@ -1392,7 +1780,9 @@ test_expect_success 'with failing command using $ARG' '
'
test_expect_success 'with empty tokens' '
- git config --unset trailer.fix.command &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.sign.key "Signed-off-by: " &&
+ test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-EOF &&
Signed-off-by: A U Thor <author@example.com>
@@ -1403,7 +1793,8 @@ test_expect_success 'with empty tokens' '
'
test_expect_success 'with command but no key' '
- git config --unset trailer.sign.key &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-EOF &&
sign: A U Thor <author@example.com>
@@ -1414,7 +1805,9 @@ test_expect_success 'with command but no key' '
'
test_expect_success 'with no command and no key' '
- git config --unset trailer.review.key &&
+ test_config trailer.review.where "before" &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+ test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-EOF &&
review: Junio
@@ -1426,6 +1819,8 @@ test_expect_success 'with no command and no key' '
'
test_expect_success 'with cut line' '
+ test_config trailer.review.where "before" &&
+ test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
cat >expected <<-\EOF &&
my subject
@@ -1443,7 +1838,8 @@ test_expect_success 'with cut line' '
'
test_expect_success 'only trailers' '
- git config trailer.sign.command "echo config-value" &&
+ test_config trailer.sign.command "echo config-value" &&
+ test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-\EOF &&
existing: existing-value
sign: config-value
@@ -1462,7 +1858,7 @@ test_expect_success 'only trailers' '
'
test_expect_success 'only-trailers omits non-trailer in middle of block' '
- git config trailer.sign.command "echo config-value" &&
+ test_config trailer.sign.command "echo config-value" &&
cat >expected <<-\EOF &&
Signed-off-by: nobody <nobody@nowhere>
Signed-off-by: somebody <somebody@somewhere>
@@ -1482,7 +1878,7 @@ test_expect_success 'only-trailers omits non-trailer in middle of block' '
'
test_expect_success 'only input' '
- git config trailer.sign.command "echo config-value" &&
+ test_config trailer.sign.command "echo config-value" &&
cat >expected <<-\EOF &&
existing: existing-value
EOF
@@ -1560,4 +1956,37 @@ test_expect_success 'suppress --- handling' '
test_cmp expected actual
'
+test_expect_success 'suppressing --- does not disable cut-line handling' '
+ echo "real-trailer: before the cut" >expected &&
+
+ git interpret-trailers --parse --no-divider >actual <<-\EOF &&
+ subject
+
+ This input has a cut-line in it; we should stop parsing when we see it
+ and consider only trailers before that line.
+
+ real-trailer: before the cut
+
+ # ------------------------ >8 ------------------------
+ # Nothing below this line counts as part of the commit message.
+ not-a-trailer: too late
+ EOF
+
+ test_cmp expected actual
+'
+
+test_expect_success 'handling of --- lines in conjunction with cut-lines' '
+ echo "my-trailer: here" >expected &&
+
+ git interpret-trailers --parse >actual <<-\EOF &&
+ subject
+
+ my-trailer: here
+ ---
+ # ------------------------ >8 ------------------------
+ EOF
+
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7514-commit-patch.sh b/t/t7514-commit-patch.sh
index 998a2103c7..075db69b42 100755
--- a/t/t7514-commit-patch.sh
+++ b/t/t7514-commit-patch.sh
@@ -1,13 +1,8 @@
#!/bin/sh
test_description='hunk edit with "commit -p -m"'
-. ./test-lib.sh
-if ! test_have_prereq PERL
-then
- skip_all="skipping '$test_description' tests, perl not available"
- test_done
-fi
+. ./test-lib.sh
test_expect_success 'setup (initial)' '
echo line1 >file &&
diff --git a/t/t7515-status-symlinks.sh b/t/t7515-status-symlinks.sh
index e3d6bb67bf..9f989be01b 100755
--- a/t/t7515-status-symlinks.sh
+++ b/t/t7515-status-symlinks.sh
@@ -2,7 +2,6 @@
test_description='git status and symlinks'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh
index bb95f09810..de7c4ca790 100755
--- a/t/t7516-commit-races.sh
+++ b/t/t7516-commit-races.sh
@@ -2,7 +2,6 @@
test_description='git commit races'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'race to create orphan commit' '
diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh
index efc6496e2b..163ae80468 100755
--- a/t/t7517-per-repo-email.sh
+++ b/t/t7517-per-repo-email.sh
@@ -9,7 +9,6 @@ test_description='per-repo forced setting of email address'
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 a likely user.useConfigOnly use case' '
diff --git a/t/t7518-ident-corner-cases.sh b/t/t7518-ident-corner-cases.sh
index 9ab2ae2f3b..d3ea4d603f 100755
--- a/t/t7518-ident-corner-cases.sh
+++ b/t/t7518-ident-corner-cases.sh
@@ -2,7 +2,6 @@
test_description='corner cases in ident strings'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# confirm that we do not segfault _and_ that we do not say "(null)", as
@@ -15,7 +14,7 @@ test_expect_success 'empty name and missing email' '
sane_unset GIT_AUTHOR_EMAIL &&
GIT_AUTHOR_NAME= &&
test_must_fail git commit --allow-empty -m foo 2>err &&
- test_i18ngrep ! "(null)" err
+ test_grep ! "(null)" err
)
'
@@ -40,8 +39,8 @@ test_expect_success 'empty configured name does not auto-detect' '
sane_unset GIT_AUTHOR_NAME &&
test_must_fail \
git -c user.name= commit --allow-empty -m foo 2>err &&
- test_i18ngrep "empty ident name" err &&
- test_i18ngrep "Author identity unknown" err
+ test_grep "empty ident name" err &&
+ test_grep "Author identity unknown" err
)
'
@@ -50,8 +49,8 @@ test_expect_success 'empty configured name does not auto-detect for committer' '
sane_unset GIT_COMMITTER_NAME &&
test_must_fail \
git -c user.name= commit --allow-empty -m foo 2>err &&
- test_i18ngrep "empty ident name" err &&
- test_i18ngrep "Committer identity unknown" err
+ test_grep "empty ident name" err &&
+ test_grep "Committer identity unknown" err
)
'
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index 8348e3ae7d..7ee69ecdd4 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -322,14 +322,14 @@ do
rm -f marker &&
git status >actual &&
test_path_is_file marker &&
- test_i18ngrep ! "Changes not staged for commit:" actual &&
+ test_grep ! "Changes not staged for commit:" actual &&
if test $uc_val = true
then
- test_i18ngrep ! "Untracked files:" actual
+ test_grep ! "Untracked files:" actual
fi &&
if test $uc_val = false
then
- test_i18ngrep "Untracked files:" actual
+ test_grep "Untracked files:" actual
fi &&
rm -f marker
'
diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh
index 184b258989..bcfe15d51d 100755
--- a/t/t7520-ignored-hook-warning.sh
+++ b/t/t7520-ignored-hook-warning.sh
@@ -2,7 +2,6 @@
test_description='ignored hook warning'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -13,27 +12,27 @@ test_expect_success setup '
test_expect_success 'no warning if hook is not ignored' '
git commit --allow-empty -m "more" 2>message &&
- test_i18ngrep ! -e "hook was ignored" message
+ test_grep ! -e "hook was ignored" message
'
test_expect_success POSIXPERM 'warning if hook is ignored' '
test_hook --disable pre-commit &&
git commit --allow-empty -m "even more" 2>message &&
- test_i18ngrep -e "hook was ignored" message
+ test_grep -e "hook was ignored" message
'
test_expect_success POSIXPERM 'no warning if advice.ignoredHook set to false' '
test_config advice.ignoredHook false &&
test_hook --disable pre-commit &&
git commit --allow-empty -m "even more" 2>message &&
- test_i18ngrep ! -e "hook was ignored" message
+ test_grep ! -e "hook was ignored" message
'
test_expect_success 'no warning if unset advice.ignoredHook and hook removed' '
test_hook --remove pre-commit &&
test_unconfig advice.ignoredHook &&
git commit --allow-empty -m "even more" 2>message &&
- test_i18ngrep ! -e "hook was ignored" message
+ test_grep ! -e "hook was ignored" message
'
test_done
diff --git a/t/t7524-commit-summary.sh b/t/t7524-commit-summary.sh
index 47b2f1dc22..82b5e4aa41 100755
--- a/t/t7524-commit-summary.sh
+++ b/t/t7524-commit-summary.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git commit summary'
+
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7525-status-rename.sh b/t/t7525-status-rename.sh
index 22bf5c7e5d..d409de1a33 100755
--- a/t/t7525-status-rename.sh
+++ b/t/t7525-status-rename.sh
@@ -2,7 +2,6 @@
test_description='git status rename detection options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -21,81 +20,81 @@ test_expect_success 'setup' '
test_expect_success 'status no-options' '
git status >actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "renamed:" actual
'
test_expect_success 'status --no-renames' '
git status --no-renames >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'status.renames inherits from diff.renames false' '
git -c diff.renames=false status >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'status.renames inherits from diff.renames true' '
git -c diff.renames=true status >actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "renamed:" actual
'
test_expect_success 'status.renames overrides diff.renames false' '
git -c diff.renames=true -c status.renames=false status >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'status.renames overrides from diff.renames true' '
git -c diff.renames=false -c status.renames=true status >actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "renamed:" actual
'
test_expect_success 'status status.renames=false' '
git -c status.renames=false status >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'status status.renames=true' '
git -c status.renames=true status >actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "renamed:" actual
'
test_expect_success 'commit honors status.renames=false' '
git -c status.renames=false commit --dry-run >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'commit honors status.renames=true' '
git -c status.renames=true commit --dry-run >actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "renamed:" actual
'
test_expect_success 'status config overridden' '
git -c status.renames=true status --no-renames >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'status score=100%' '
git status -M=100% >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual &&
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual &&
git status --find-renames=100% >actual &&
- test_i18ngrep "deleted:" actual &&
- test_i18ngrep "new file:" actual
+ test_grep "deleted:" actual &&
+ test_grep "new file:" actual
'
test_expect_success 'status score=01%' '
git status -M=01% >actual &&
- test_i18ngrep "renamed:" actual &&
+ test_grep "renamed:" actual &&
git status --find-renames=01% >actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "renamed:" actual
'
test_expect_success 'copies not overridden by find-renames' '
@@ -103,12 +102,12 @@ test_expect_success 'copies not overridden by find-renames' '
git add copy &&
git -c status.renames=copies status -M=01% >actual &&
- test_i18ngrep "copied:" actual &&
- test_i18ngrep "renamed:" actual &&
+ test_grep "copied:" actual &&
+ test_grep "renamed:" actual &&
git -c status.renames=copies status --find-renames=01% >actual &&
- test_i18ngrep "copied:" actual &&
- test_i18ngrep "renamed:" actual
+ test_grep "copied:" actual &&
+ test_grep "renamed:" actual
'
test_done
diff --git a/t/t7526-commit-pathspec-file.sh b/t/t7526-commit-pathspec-file.sh
index ad011bb9f1..3aabbf35a1 100755
--- a/t/t7526-commit-pathspec-file.sh
+++ b/t/t7526-commit-pathspec-file.sh
@@ -2,7 +2,6 @@
test_description='commit --pathspec-from-file'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_tick
@@ -141,25 +140,25 @@ test_expect_success 'error conditions' '
>empty_list &&
test_must_fail git commit --pathspec-from-file=list --interactive -m "Commit" 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git commit --pathspec-from-file=list --patch -m "Commit" 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git commit --pathspec-from-file=list --all -m "Commit" 2>err &&
- test_i18ngrep -e "options .--pathspec-from-file. and .-a. cannot be used together" err &&
+ test_grep -e "options .--pathspec-from-file. and .-a. cannot be used together" err &&
test_must_fail git commit --pathspec-from-file=list -m "Commit" -- fileA.t 2>err &&
- test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
+ test_grep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git commit --pathspec-file-nul -m "Commit" 2>err &&
- test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
+ test_grep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
test_must_fail git commit --pathspec-from-file=empty_list --include -m "Commit" 2>err &&
- test_i18ngrep -e "No paths with --include/--only does not make sense." err &&
+ test_grep -e "No paths with --include/--only does not make sense." err &&
test_must_fail git commit --pathspec-from-file=empty_list --only -m "Commit" 2>err &&
- test_i18ngrep -e "No paths with --include/--only does not make sense." err
+ test_grep -e "No paths with --include/--only does not make sense." err
'
test_done
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 78503158fd..409cd0cd12 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -765,7 +765,7 @@ done
# by the FSMonitor response to skip those recursive calls. That is,
# even if FSMonitor says that the mtime of the submodule directory
# hasn't changed and it could be implicitly marked valid, we must
-# not take that shortcut. We need to force the recusion into the
+# not take that shortcut. We need to force the recursion into the
# submodule so that we get a summary of the status *within* the
# submodule.
@@ -907,6 +907,57 @@ test_expect_success "submodule absorbgitdirs implicitly starts daemon" '
test_subcommand git fsmonitor--daemon start <super-sub.trace
'
+start_git_in_background () {
+ git "$@" &
+ git_pid=$!
+ git_pgid=$(ps -o pgid= -p $git_pid)
+ nr_tries_left=10
+ while true
+ do
+ if test $nr_tries_left -eq 0
+ then
+ kill -- -$git_pgid
+ exit 1
+ fi
+ sleep 1
+ nr_tries_left=$(($nr_tries_left - 1))
+ done >/dev/null 2>&1 &
+ watchdog_pid=$!
+ wait $git_pid
+}
+
+stop_git () {
+ while kill -0 -- -$git_pgid
+ do
+ kill -- -$git_pgid
+ sleep 1
+ done
+}
+
+stop_watchdog () {
+ while kill -0 $watchdog_pid
+ do
+ kill $watchdog_pid
+ sleep 1
+ done
+}
+
+test_expect_success !MINGW "submodule implicitly starts daemon by pull" '
+ test_atexit "stop_watchdog" &&
+ test_when_finished "stop_git; rm -rf cloned super sub" &&
+
+ create_super super &&
+ create_sub sub &&
+
+ git -C super submodule add ../sub ./dir_1/dir_2/sub &&
+ git -C super commit -m "add sub" &&
+ git clone --recurse-submodules super cloned &&
+
+ git -C cloned/dir_1/dir_2/sub config core.fsmonitor true &&
+ set -m &&
+ start_git_in_background -C cloned pull --recurse-submodules
+'
+
# On a case-insensitive file system, confirm that the daemon
# notices when the .git directory is moved/renamed/deleted
# regardless of how it is spelled in the FS event.
@@ -978,7 +1029,7 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' '
mkdir test_unicode/nfd &&
mkdir test_unicode/nfd/d_${utf8_nfd} &&
- git -C test_unicode fsmonitor--daemon stop &&
+ test-tool -C test_unicode fsmonitor-client query --token 0 &&
if test_have_prereq UNICODE_NFC_PRESERVED
then
@@ -1037,4 +1088,227 @@ test_expect_success 'split-index and FSMonitor work well together' '
)
'
+# The FSMonitor daemon reports the OBSERVED pathname of modified files
+# and thus contains the OBSERVED spelling on case-insensitive file
+# systems. The daemon does not (and should not) load the .git/index
+# file and therefore does not know the expected case-spelling. Since
+# it is possible for the user to create files/subdirectories with the
+# incorrect case, a modified file event for a tracked will not have
+# the EXPECTED case. This can cause `index_name_pos()` to incorrectly
+# report that the file is untracked. This causes the client to fail to
+# mark the file as possibly dirty (keeping the CE_FSMONITOR_VALID bit
+# set) so that `git status` will avoid inspecting it and thus not
+# present in the status output.
+#
+# The setup is a little contrived.
+#
+test_expect_success CASE_INSENSITIVE_FS 'fsmonitor subdir case wrong on disk' '
+ test_when_finished "stop_daemon_delete_repo subdir_case_wrong" &&
+
+ git init subdir_case_wrong &&
+ (
+ cd subdir_case_wrong &&
+ echo x >AAA &&
+ echo x >BBB &&
+
+ mkdir dir1 &&
+ echo x >dir1/file1 &&
+ mkdir dir1/dir2 &&
+ echo x >dir1/dir2/file2 &&
+ mkdir dir1/dir2/dir3 &&
+ echo x >dir1/dir2/dir3/file3 &&
+
+ echo x >yyy &&
+ echo x >zzz &&
+ git add . &&
+ git commit -m "data" &&
+
+ # This will cause "dir1/" and everything under it
+ # to be deleted.
+ git sparse-checkout set --cone --sparse-index &&
+
+ # Create dir2 with the wrong case and then let Git
+ # repopulate dir3 -- it will not correct the spelling
+ # of dir2.
+ mkdir dir1 &&
+ mkdir dir1/DIR2 &&
+ git sparse-checkout add dir1/dir2/dir3
+ ) &&
+
+ start_daemon -C subdir_case_wrong --tf "$PWD/subdir_case_wrong.trace" &&
+
+ # Enable FSMonitor in the client. Run enough commands for
+ # the .git/index to sync up with the daemon with everything
+ # marked clean.
+ git -C subdir_case_wrong config core.fsmonitor true &&
+ git -C subdir_case_wrong update-index --fsmonitor &&
+ git -C subdir_case_wrong status &&
+
+ # Make some files dirty so that FSMonitor gets FSEvents for
+ # each of them.
+ echo xx >>subdir_case_wrong/AAA &&
+ echo xx >>subdir_case_wrong/dir1/DIR2/dir3/file3 &&
+ echo xx >>subdir_case_wrong/zzz &&
+
+ GIT_TRACE_FSMONITOR="$PWD/subdir_case_wrong.log" \
+ git -C subdir_case_wrong --no-optional-locks status --short \
+ >"$PWD/subdir_case_wrong.out" &&
+
+ # "git status" should have gotten file events for each of
+ # the 3 files.
+ #
+ # "dir2" should be in the observed case on disk.
+ grep "fsmonitor_refresh_callback" \
+ <"$PWD/subdir_case_wrong.log" \
+ >"$PWD/subdir_case_wrong.log1" &&
+
+ grep -q "AAA.*pos 0" "$PWD/subdir_case_wrong.log1" &&
+ grep -q "zzz.*pos 6" "$PWD/subdir_case_wrong.log1" &&
+
+ grep -q "dir1/DIR2/dir3/file3.*pos -3" "$PWD/subdir_case_wrong.log1" &&
+
+ # Verify that we get a mapping event to correct the case.
+ grep -q "MAP:.*dir1/DIR2/dir3/file3.*dir1/dir2/dir3/file3" \
+ "$PWD/subdir_case_wrong.log1" &&
+
+ # The refresh-callbacks should have caused "git status" to clear
+ # the CE_FSMONITOR_VALID bit on each of those files and caused
+ # the worktree scan to visit them and mark them as modified.
+ grep -q " M AAA" "$PWD/subdir_case_wrong.out" &&
+ grep -q " M zzz" "$PWD/subdir_case_wrong.out" &&
+ grep -q " M dir1/dir2/dir3/file3" "$PWD/subdir_case_wrong.out"
+'
+
+test_expect_success CASE_INSENSITIVE_FS 'fsmonitor file case wrong on disk' '
+ test_when_finished "stop_daemon_delete_repo file_case_wrong" &&
+
+ git init file_case_wrong &&
+ (
+ cd file_case_wrong &&
+ echo x >AAA &&
+ echo x >BBB &&
+
+ mkdir dir1 &&
+ mkdir dir1/dir2 &&
+ mkdir dir1/dir2/dir3 &&
+ echo x >dir1/dir2/dir3/FILE-3-B &&
+ echo x >dir1/dir2/dir3/XXXX-3-X &&
+ echo x >dir1/dir2/dir3/file-3-a &&
+ echo x >dir1/dir2/dir3/yyyy-3-y &&
+ mkdir dir1/dir2/dir4 &&
+ echo x >dir1/dir2/dir4/FILE-4-A &&
+ echo x >dir1/dir2/dir4/XXXX-4-X &&
+ echo x >dir1/dir2/dir4/file-4-b &&
+ echo x >dir1/dir2/dir4/yyyy-4-y &&
+
+ echo x >yyy &&
+ echo x >zzz &&
+ git add . &&
+ git commit -m "data"
+ ) &&
+
+ start_daemon -C file_case_wrong --tf "$PWD/file_case_wrong.trace" &&
+
+ # Enable FSMonitor in the client. Run enough commands for
+ # the .git/index to sync up with the daemon with everything
+ # marked clean.
+ git -C file_case_wrong config core.fsmonitor true &&
+ git -C file_case_wrong update-index --fsmonitor &&
+ git -C file_case_wrong status &&
+
+ # Make some files dirty so that FSMonitor gets FSEvents for
+ # each of them.
+ echo xx >>file_case_wrong/AAA &&
+ echo xx >>file_case_wrong/zzz &&
+
+ # Rename some files so that FSMonitor sees a create and delete
+ # FSEvent for each. (A simple "mv foo FOO" is not portable
+ # between macOS and Windows. It works on both platforms, but makes
+ # the test messy, since (1) one platform updates "ctime" on the
+ # moved file and one does not and (2) it causes a directory event
+ # on one platform and not on the other which causes additional
+ # scanning during "git status" which causes a "H" vs "h" discrepancy
+ # in "git ls-files -f".) So old-school it and move it out of the
+ # way and copy it to the case-incorrect name so that we get fresh
+ # "ctime" and "mtime" values.
+
+ mv file_case_wrong/dir1/dir2/dir3/file-3-a file_case_wrong/dir1/dir2/dir3/ORIG &&
+ cp file_case_wrong/dir1/dir2/dir3/ORIG file_case_wrong/dir1/dir2/dir3/FILE-3-A &&
+ rm file_case_wrong/dir1/dir2/dir3/ORIG &&
+ mv file_case_wrong/dir1/dir2/dir4/FILE-4-A file_case_wrong/dir1/dir2/dir4/ORIG &&
+ cp file_case_wrong/dir1/dir2/dir4/ORIG file_case_wrong/dir1/dir2/dir4/file-4-a &&
+ rm file_case_wrong/dir1/dir2/dir4/ORIG &&
+
+ # Run status enough times to fully sync.
+ #
+ # The first instance should get the create and delete FSEvents
+ # for each pair. Status should update the index with a new FSM
+ # token (so the next invocation will not see data for these
+ # events).
+
+ GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try1.log" \
+ git -C file_case_wrong status --short \
+ >"$PWD/file_case_wrong-try1.out" &&
+ grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try1.log" &&
+ grep -q "fsmonitor_refresh_callback.*file-3-a.*pos 4" "$PWD/file_case_wrong-try1.log" &&
+ grep -q "fsmonitor_refresh_callback.*FILE-4-A.*pos 6" "$PWD/file_case_wrong-try1.log" &&
+ grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try1.log" &&
+
+ # FSM refresh will have invalidated the FSM bit and cause a regular
+ # (real) scan of these tracked files, so they should have "H" status.
+ # (We will not see a "h" status until the next refresh (on the next
+ # command).)
+
+ git -C file_case_wrong ls-files -f >"$PWD/file_case_wrong-lsf1.out" &&
+ grep -q "H dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-lsf1.out" &&
+ grep -q "H dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-lsf1.out" &&
+
+
+ # Try the status again. We assume that the above status command
+ # advanced the token so that the next one will not see those events.
+
+ GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try2.log" \
+ git -C file_case_wrong status --short \
+ >"$PWD/file_case_wrong-try2.out" &&
+ ! grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos" "$PWD/file_case_wrong-try2.log" &&
+ ! grep -q "fsmonitor_refresh_callback.*file-3-a.*pos" "$PWD/file_case_wrong-try2.log" &&
+ ! grep -q "fsmonitor_refresh_callback.*FILE-4-A.*pos" "$PWD/file_case_wrong-try2.log" &&
+ ! grep -q "fsmonitor_refresh_callback.*file-4-a.*pos" "$PWD/file_case_wrong-try2.log" &&
+
+ # FSM refresh saw nothing, so it will mark all files as valid,
+ # so they should now have "h" status.
+
+ git -C file_case_wrong ls-files -f >"$PWD/file_case_wrong-lsf2.out" &&
+ grep -q "h dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-lsf2.out" &&
+ grep -q "h dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-lsf2.out" &&
+
+
+ # We now have files with clean content, but with case-incorrect
+ # file names. Modify them to see if status properly reports
+ # them.
+
+ echo xx >>file_case_wrong/dir1/dir2/dir3/FILE-3-A &&
+ echo xx >>file_case_wrong/dir1/dir2/dir4/file-4-a &&
+
+ GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try3.log" \
+ git -C file_case_wrong --no-optional-locks status --short \
+ >"$PWD/file_case_wrong-try3.out" &&
+
+ # Verify that we get a mapping event to correct the case.
+ grep -q "fsmonitor_refresh_callback MAP:.*dir1/dir2/dir3/FILE-3-A.*dir1/dir2/dir3/file-3-a" \
+ "$PWD/file_case_wrong-try3.log" &&
+ grep -q "fsmonitor_refresh_callback MAP:.*dir1/dir2/dir4/file-4-a.*dir1/dir2/dir4/FILE-4-A" \
+ "$PWD/file_case_wrong-try3.log" &&
+
+ # FSEvents are in observed case.
+ grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try3.log" &&
+ grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try3.log" &&
+
+ # The refresh-callbacks should have caused "git status" to clear
+ # the CE_FSMONITOR_VALID bit on each of those files and caused
+ # the worktree scan to visit them and mark them as modified.
+ grep -q " M dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-try3.out" &&
+ grep -q " M dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-try3.out"
+'
+
test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index fdc607277c..ef54cff4fa 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -175,7 +175,7 @@ test_expect_success 'merge -h with invalid index' '
>.git/index &&
test_expect_code 129 git merge -h 2>usage
) &&
- test_i18ngrep "[Uu]sage: git merge" broken/usage
+ test_grep "[Uu]sage: git merge" broken/usage
'
test_expect_success 'reject non-strategy with a git-merge-foo name' '
@@ -236,6 +236,16 @@ test_expect_success 'merge c1 with c2' '
verify_parents $c1 $c2
'
+test_expect_success 'merge c1 with c2 when index.lock exists' '
+ test_when_finished rm .git/index.lock &&
+ git reset --hard c1 &&
+ >.git/index.lock &&
+ test_must_fail git merge c2 &&
+ test_path_is_missing .git/MERGE_HEAD &&
+ test_path_is_missing .git/MERGE_MODE &&
+ test_path_is_missing .git/MERGE_MSG
+'
+
test_expect_success 'merge --squash c3 with c7' '
git reset --hard c3 &&
test_must_fail git merge --squash c7 &&
@@ -681,7 +691,7 @@ test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'in-index merge' '
git reset --hard c0 &&
git merge --no-ff -s resolve c1 >out &&
- test_i18ngrep "Wonderful." out &&
+ test_grep "Wonderful." out &&
verify_parents $c0 $c1
'
@@ -697,7 +707,7 @@ test_expect_success 'merge with --autostash' '
git reset --hard c1 &&
git merge-file file file.orig file.9 &&
git merge --autostash c2 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git show HEAD:file >merge-result &&
test_cmp result.1-5 merge-result &&
test_cmp result.1-5-9 file
@@ -708,7 +718,7 @@ test_expect_success 'merge with merge.autoStash' '
git reset --hard c1 &&
git merge-file file file.orig file.9 &&
git merge c2 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git show HEAD:file >merge-result &&
test_cmp result.1-5 merge-result &&
test_cmp result.1-5-9 file
@@ -718,7 +728,7 @@ test_expect_success 'fast-forward merge with --autostash' '
git reset --hard c0 &&
git merge-file file file.orig file.5 &&
git merge --autostash c1 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
test_cmp result.1-5 file
'
@@ -728,7 +738,7 @@ test_expect_success 'failed fast-forward merge with --autostash' '
cp file.5 other &&
test_when_finished "rm other" &&
test_must_fail git merge --autostash c1 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
test_cmp file.5 file
'
@@ -736,7 +746,7 @@ test_expect_success 'octopus merge with --autostash' '
git reset --hard c1 &&
git merge-file file file.orig file.3 &&
git merge --autostash c2 c3 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git show HEAD:file >merge-result &&
test_cmp result.1-5-9 merge-result &&
test_cmp result.1-3-5-9 file
@@ -746,7 +756,7 @@ test_expect_success 'failed merge (exit 2) with --autostash' '
git reset --hard c1 &&
git merge-file file file.orig file.5 &&
test_must_fail git merge -s recursive --autostash c2 c3 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
test_cmp result.1-5 file
'
@@ -755,7 +765,7 @@ test_expect_success 'conflicted merge with --autostash, --abort restores stash'
cp file.1 file &&
test_must_fail git merge --autostash c7 &&
git merge --abort 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
test_cmp file.1 file
'
@@ -767,7 +777,7 @@ test_expect_success 'completed merge (git commit) with --no-commit and --autosta
git stash show -p MERGE_AUTOSTASH >actual &&
test_cmp expect actual &&
git commit 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git show HEAD:file >merge-result &&
test_cmp result.1-5 merge-result &&
test_cmp result.1-5-9 file
@@ -781,7 +791,7 @@ test_expect_success 'completed merge (git merge --continue) with --no-commit and
git stash show -p MERGE_AUTOSTASH >actual &&
test_cmp expect actual &&
git merge --continue 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git show HEAD:file >merge-result &&
test_cmp result.1-5 merge-result &&
test_cmp result.1-5-9 file
@@ -795,7 +805,7 @@ test_expect_success 'aborted merge (merge --abort) with --no-commit and --autost
git stash show -p MERGE_AUTOSTASH >actual &&
test_cmp expect actual &&
git merge --abort 2>err &&
- test_i18ngrep "Applied autostash." err &&
+ test_grep "Applied autostash." err &&
git diff >actual &&
test_cmp expect actual
'
@@ -808,7 +818,7 @@ test_expect_success 'aborted merge (reset --hard) with --no-commit and --autosta
git stash show -p MERGE_AUTOSTASH >actual &&
test_cmp expect actual &&
git reset --hard 2>err &&
- test_i18ngrep "Autostash exists; creating a new stash entry." err &&
+ test_grep "Autostash exists; creating a new stash entry." err &&
git diff --exit-code
'
@@ -821,7 +831,7 @@ test_expect_success 'quit merge with --no-commit and --autostash' '
test_cmp expect actual &&
git diff HEAD >expect &&
git merge --quit 2>err &&
- test_i18ngrep "Autostash exists; creating a new stash entry." err &&
+ test_grep "Autostash exists; creating a new stash entry." err &&
git diff HEAD >actual &&
test_cmp expect actual
'
@@ -832,7 +842,7 @@ test_expect_success 'merge with conflicted --autostash changes' '
git diff >expect &&
test_when_finished "test_might_fail git stash drop" &&
git merge --autostash c3 2>err &&
- test_i18ngrep "Applying autostash resulted in conflicts." err &&
+ test_grep "Applying autostash resulted in conflicts." err &&
git show HEAD:file >merge-result &&
test_cmp result.1-9 merge-result &&
git stash show -p >actual &&
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index bd238d89b0..199a1d5db3 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -30,117 +30,117 @@ test_expect_success 'setup' '
test_expect_success 'pull.rebase not set, ff possible' '
git reset --hard c0 &&
git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=true' '
git reset --hard c0 &&
test_config pull.ff true &&
git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=false' '
git reset --hard c0 &&
test_config pull.ff false &&
git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=only' '
git reset --hard c0 &&
test_config pull.ff only &&
git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --rebase given' '
git reset --hard c0 &&
git pull --rebase . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-rebase given' '
git reset --hard c0 &&
git pull --no-rebase . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff given' '
git reset --hard c0 &&
git pull --ff . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-ff given' '
git reset --hard c0 &&
git pull --no-ff . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff-only given' '
git reset --hard c0 &&
git pull --ff-only . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set (not-fast-forward)' '
git reset --hard c2 &&
test_must_fail git -c color.advice=always pull . c1 2>err &&
test_decode_color <err >decoded &&
- test_i18ngrep "<YELLOW>hint: " decoded &&
- test_i18ngrep "You have divergent branches" decoded
+ test_grep "<YELLOW>hint: " decoded &&
+ test_grep "You have divergent branches" decoded
'
test_expect_success 'pull.rebase not set and pull.ff=true (not-fast-forward)' '
git reset --hard c2 &&
test_config pull.ff true &&
git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=false (not-fast-forward)' '
git reset --hard c2 &&
test_config pull.ff false &&
git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and pull.ff=only (not-fast-forward)' '
git reset --hard c2 &&
test_config pull.ff only &&
test_must_fail git pull . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --rebase given (not-fast-forward)' '
git reset --hard c2 &&
git pull --rebase . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-rebase given (not-fast-forward)' '
git reset --hard c2 &&
git pull --no-rebase . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff given (not-fast-forward)' '
git reset --hard c2 &&
git pull --ff . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --no-ff given (not-fast-forward)' '
git reset --hard c2 &&
git pull --no-ff . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_expect_success 'pull.rebase not set and --ff-only given (not-fast-forward)' '
git reset --hard c2 &&
test_must_fail git pull --ff-only . c1 2>err &&
- test_i18ngrep ! "You have divergent branches" err
+ test_grep ! "You have divergent branches" err
'
test_does_rebase () {
@@ -202,7 +202,7 @@ test_falls_back_to_full_merge () {
test_attempts_fast_forward () {
git reset --hard c2 &&
test_must_fail git "$@" . c1 2>err &&
- test_i18ngrep "Not possible to fast-forward, aborting" err
+ test_grep "Not possible to fast-forward, aborting" err
}
#
@@ -280,7 +280,7 @@ test_expect_success '--rebase overrides pull.ff unset' '
test_does_rebase pull --rebase
'
-# Group 4: --no-rebase heeds pull.ff=!only or explict --ff or --no-ff
+# Group 4: --no-rebase heeds pull.ff=!only or explicit --ff or --no-ff
test_expect_success '--no-rebase works with --no-ff' '
test_does_merge_when_ff_possible pull --no-rebase --no-ff
@@ -328,34 +328,34 @@ test_expect_success 'pull.rebase=false and --ff, ff not possible' '
test_expect_success 'Multiple heads warns about inability to fast forward' '
git reset --hard c1 &&
test_must_fail git pull . c2 c3 2>err &&
- test_i18ngrep "You have divergent branches" err
+ test_grep "You have divergent branches" err
'
test_expect_success 'Multiple can never be fast forwarded' '
git reset --hard c0 &&
test_must_fail git -c pull.ff=only pull . c1 c2 c3 2>err &&
- test_i18ngrep ! "You have divergent branches" err &&
+ test_grep ! "You have divergent branches" err &&
# In addition to calling out "cannot fast-forward", we very much
# want the "multiple branches" piece to be called out to users.
- test_i18ngrep "Cannot fast-forward to multiple branches" err
+ test_grep "Cannot fast-forward to multiple branches" err
'
test_expect_success 'Cannot rebase with multiple heads' '
git reset --hard c0 &&
test_must_fail git -c pull.rebase=true pull . c1 c2 c3 2>err &&
- test_i18ngrep ! "You have divergent branches" err &&
- test_i18ngrep "Cannot rebase onto multiple branches." err
+ test_grep ! "You have divergent branches" err &&
+ test_grep "Cannot rebase onto multiple branches." err
'
test_expect_success 'merge c1 with c2' '
git reset --hard c1 &&
- test -f c0.c &&
- test -f c1.c &&
- test ! -f c2.c &&
- test ! -f c3.c &&
+ test_path_is_file c0.c &&
+ test_path_is_file c1.c &&
+ test_path_is_missing c2.c &&
+ test_path_is_missing c3.c &&
git merge c2 &&
- test -f c1.c &&
- test -f c2.c
+ test_path_is_file c1.c &&
+ test_path_is_file c2.c
'
test_expect_success 'fast-forward pull succeeds with "true" in pull.ff' '
@@ -411,8 +411,8 @@ test_expect_success 'merge c1 with c2 (ours in pull.twohead)' '
git reset --hard c1 &&
git config pull.twohead ours &&
git merge c2 &&
- test -f c1.c &&
- ! test -f c2.c
+ test_path_is_file c1.c &&
+ test_path_is_missing c2.c
'
test_expect_success 'merge c1 with c2 and c3 (recursive in pull.octopus)' '
@@ -431,10 +431,10 @@ test_expect_success 'merge c1 with c2 and c3 (recursive and octopus in pull.octo
test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" &&
test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" &&
git diff --exit-code &&
- test -f c0.c &&
- test -f c1.c &&
- test -f c2.c &&
- test -f c3.c
+ test_path_is_file c0.c &&
+ test_path_is_file c1.c &&
+ test_path_is_file c2.c &&
+ test_path_is_file c3.c
'
conflict_count()
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index eca7555101..cd4f9607dc 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -4,7 +4,6 @@ test_description='git merge
Testing merge when using a custom message for the merge commit.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
create_merge_msgs() {
diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh
index 62d935d31c..5d56c38546 100755
--- a/t/t7605-merge-resolve.sh
+++ b/t/t7605-merge-resolve.sh
@@ -4,7 +4,6 @@ test_description='git merge
Testing the resolve strategy.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7609-mergetool--lib.sh b/t/t7609-mergetool--lib.sh
index 8b1c3bd39f..330d6d603d 100755
--- a/t/t7609-mergetool--lib.sh
+++ b/t/t7609-mergetool--lib.sh
@@ -4,7 +4,6 @@ test_description='git mergetool
Testing basic merge tools options'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'mergetool --tool=vimdiff creates the expected layout' '
diff --git a/t/t7611-merge-abort.sh b/t/t7611-merge-abort.sh
index c0e9425115..d6975ca48d 100755
--- a/t/t7611-merge-abort.sh
+++ b/t/t7611-merge-abort.sh
@@ -50,7 +50,7 @@ pre_merge_head="$(git rev-parse HEAD)"
test_expect_success 'fails without MERGE_HEAD (unstarted merge)' '
test_must_fail git merge --abort 2>output &&
- test_i18ngrep MERGE_HEAD output
+ test_grep MERGE_HEAD output
'
test_expect_success 'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity' '
@@ -64,7 +64,7 @@ test_expect_success 'fails without MERGE_HEAD (completed merge)' '
# Merge successfully completed
post_merge_head="$(git rev-parse HEAD)" &&
test_must_fail git merge --abort 2>output &&
- test_i18ngrep MERGE_HEAD output
+ test_grep MERGE_HEAD output
'
test_expect_success 'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity' '
diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh
index f5c90cc22a..337fac0d84 100755
--- a/t/t7612-merge-verify-signatures.sh
+++ b/t/t7612-merge-verify-signatures.sh
@@ -4,7 +4,6 @@ test_description='merge signature verification tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-gpg.sh"
@@ -41,54 +40,54 @@ test_expect_success GPG 'create signed commits' '
test_expect_success GPG 'merge unsigned commit with verification' '
test_when_finished "git reset --hard && git checkout initial" &&
test_must_fail git merge --ff-only --verify-signatures side-unsigned 2>mergeerror &&
- test_i18ngrep "does not have a GPG signature" mergeerror
+ test_grep "does not have a GPG signature" mergeerror
'
test_expect_success GPG 'merge unsigned commit with merge.verifySignatures=true' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config merge.verifySignatures true &&
test_must_fail git merge --ff-only side-unsigned 2>mergeerror &&
- test_i18ngrep "does not have a GPG signature" mergeerror
+ test_grep "does not have a GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with bad signature with verification' '
test_when_finished "git reset --hard && git checkout initial" &&
test_must_fail git merge --ff-only --verify-signatures $(cat forged.commit) 2>mergeerror &&
- test_i18ngrep "has a bad GPG signature" mergeerror
+ test_grep "has a bad GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with bad signature with merge.verifySignatures=true' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config merge.verifySignatures true &&
test_must_fail git merge --ff-only $(cat forged.commit) 2>mergeerror &&
- test_i18ngrep "has a bad GPG signature" mergeerror
+ test_grep "has a bad GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with untrusted signature with verification' '
test_when_finished "git reset --hard && git checkout initial" &&
test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror &&
- test_i18ngrep "has an untrusted GPG signature" mergeerror
+ test_grep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with untrusted signature with verification and high minTrustLevel' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel marginal &&
test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror &&
- test_i18ngrep "has an untrusted GPG signature" mergeerror
+ test_grep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with untrusted signature with verification and low minTrustLevel' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel undefined &&
git merge --ff-only --verify-signatures side-untrusted >mergeoutput &&
- test_i18ngrep "has a good GPG signature" mergeoutput
+ test_grep "has a good GPG signature" mergeoutput
'
test_expect_success GPG 'merge commit with untrusted signature with merge.verifySignatures=true' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config merge.verifySignatures true &&
test_must_fail git merge --ff-only side-untrusted 2>mergeerror &&
- test_i18ngrep "has an untrusted GPG signature" mergeerror
+ test_grep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with untrusted signature with merge.verifySignatures=true and minTrustLevel' '
@@ -96,20 +95,20 @@ test_expect_success GPG 'merge commit with untrusted signature with merge.verify
test_config merge.verifySignatures true &&
test_config gpg.minTrustLevel marginal &&
test_must_fail git merge --ff-only side-untrusted 2>mergeerror &&
- test_i18ngrep "has an untrusted GPG signature" mergeerror
+ test_grep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge signed commit with verification' '
test_when_finished "git reset --hard && git checkout initial" &&
git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput &&
- test_i18ngrep "has a good GPG signature" mergeoutput
+ test_grep "has a good GPG signature" mergeoutput
'
test_expect_success GPG 'merge signed commit with merge.verifySignatures=true' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config merge.verifySignatures true &&
git merge --verbose --ff-only side-signed >mergeoutput &&
- test_i18ngrep "has a good GPG signature" mergeoutput
+ test_grep "has a good GPG signature" mergeoutput
'
test_expect_success GPG 'merge commit with bad signature without verification' '
@@ -133,7 +132,7 @@ test_expect_success GPG 'merge unsigned commit into unborn branch' '
test_when_finished "git checkout initial" &&
git checkout --orphan unborn &&
test_must_fail git merge --verify-signatures side-unsigned 2>mergeerror &&
- test_i18ngrep "does not have a GPG signature" mergeerror
+ test_grep "does not have a GPG signature" mergeerror
'
test_done
diff --git a/t/t7614-merge-signoff.sh b/t/t7614-merge-signoff.sh
index cf96a35e8e..fee258d4f0 100755
--- a/t/t7614-merge-signoff.sh
+++ b/t/t7614-merge-signoff.sh
@@ -8,7 +8,6 @@ This test runs git merge --signoff and makes sure that it works.
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Setup test files
diff --git a/t/t7615-diff-algo-with-mergy-operations.sh b/t/t7615-diff-algo-with-mergy-operations.sh
new file mode 100755
index 0000000000..3b1aad0167
--- /dev/null
+++ b/t/t7615-diff-algo-with-mergy-operations.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='git merge and other operations that rely on merge
+
+Testing the influence of the diff algorithm on the merge output.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ cp "$TEST_DIRECTORY"/t7615/base.c file.c &&
+ git add file.c &&
+ git commit -m c0 &&
+ git tag c0 &&
+ cp "$TEST_DIRECTORY"/t7615/ours.c file.c &&
+ git add file.c &&
+ git commit -m c1 &&
+ git tag c1 &&
+ git reset --hard c0 &&
+ cp "$TEST_DIRECTORY"/t7615/theirs.c file.c &&
+ git add file.c &&
+ git commit -m c2 &&
+ git tag c2
+'
+
+GIT_TEST_MERGE_ALGORITHM=recursive
+
+test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '
+ git reset --hard c1 &&
+ test_must_fail git merge -s recursive c2
+'
+
+test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' '
+ git reset --hard c1 &&
+ git merge --strategy recursive -Xdiff-algorithm=histogram c2
+'
+
+test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' '
+ git reset --hard c1 &&
+ git config diff.algorithm histogram &&
+ git merge --strategy recursive c2
+'
+
+test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '
+ git reset --hard c1 &&
+ test_must_fail git cherry-pick -s recursive c2
+'
+
+test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' '
+ git reset --hard c1 &&
+ git cherry-pick --strategy recursive -Xdiff-algorithm=histogram c2
+'
+
+test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' '
+ git reset --hard c1 &&
+ git config diff.algorithm histogram &&
+ git cherry-pick --strategy recursive c2
+'
+
+test_done
diff --git a/t/t7615/base.c b/t/t7615/base.c
new file mode 100644
index 0000000000..c64abc5936
--- /dev/null
+++ b/t/t7615/base.c
@@ -0,0 +1,17 @@
+int f(int x, int y)
+{
+ if (x == 0)
+ {
+ return y;
+ }
+ return x;
+}
+
+int g(size_t u)
+{
+ while (u < 30)
+ {
+ u++;
+ }
+ return u;
+}
diff --git a/t/t7615/ours.c b/t/t7615/ours.c
new file mode 100644
index 0000000000..44d8251397
--- /dev/null
+++ b/t/t7615/ours.c
@@ -0,0 +1,17 @@
+int g(size_t u)
+{
+ while (u < 30)
+ {
+ u++;
+ }
+ return u;
+}
+
+int h(int x, int y, int z)
+{
+ if (z == 0)
+ {
+ return x;
+ }
+ return y;
+}
diff --git a/t/t7615/theirs.c b/t/t7615/theirs.c
new file mode 100644
index 0000000000..85f02146fe
--- /dev/null
+++ b/t/t7615/theirs.c
@@ -0,0 +1,17 @@
+int f(int x, int y)
+{
+ if (x == 0)
+ {
+ return y;
+ }
+ return x;
+}
+
+int g(size_t u)
+{
+ while (u > 34)
+ {
+ u--;
+ }
+ return u;
+}
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 27b66807cd..be1188e736 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -7,6 +7,9 @@ test_description='git repack works correctly'
. "${TEST_DIRECTORY}/lib-midx.sh"
. "${TEST_DIRECTORY}/lib-terminal.sh"
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
+
commit_and_pack () {
test_commit "$@" 1>&2 &&
incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) &&
@@ -70,14 +73,13 @@ test_expect_success 'objects in packs marked .keep are not repacked' '
test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' '
# build on $oid, $packid, and .keep state from previous
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 git repack -Adbl &&
+ git repack -Adbl &&
test_has_duplicate_object true
'
test_expect_success 'writing bitmaps via config can duplicate .keep objects' '
# build on $oid, $packid, and .keep state from previous
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -c repack.writebitmaps=true repack -Adl &&
+ git -c repack.writebitmaps=true repack -Adl &&
test_has_duplicate_object true
'
@@ -118,7 +120,7 @@ test_expect_success '--local disables writing bitmaps when connected to alternat
(
cd member &&
test_commit "object" &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err &&
+ git repack -Adl --write-bitmap-index 2>err &&
cat >expect <<-EOF &&
warning: disabling bitmap writing, as some objects are not being packed
EOF
@@ -271,7 +273,7 @@ test_expect_success 'repacking fails when missing .pack actually means missing o
ls .git/objects/pack/*.pack >before-pack-dir &&
test_must_fail git fsck &&
- test_must_fail git repack --cruft -d 2>err &&
+ test_must_fail env GIT_COMMIT_GRAPH_PARANOIA=true git repack --cruft -d 2>err &&
grep "bad object" err &&
# Before failing, the repack did not modify the
@@ -284,8 +286,7 @@ test_expect_success 'repacking fails when missing .pack actually means missing o
test_expect_success 'bitmaps are created by default in bare repos' '
git clone --bare .git bare.git &&
rm -f bare.git/objects/pack/*.bitmap &&
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -ad &&
+ git -C bare.git repack -ad &&
bitmap=$(ls bare.git/objects/pack/*.bitmap) &&
test_path_is_file "$bitmap"
'
@@ -296,8 +297,7 @@ test_expect_success 'incremental repack does not complain' '
'
test_expect_success 'bitmaps can be disabled on bare repos' '
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -c repack.writeBitmaps=false -C bare.git repack -ad &&
+ git -c repack.writeBitmaps=false -C bare.git repack -ad &&
bitmap=$(ls bare.git/objects/pack/*.bitmap || :) &&
test -z "$bitmap"
'
@@ -308,8 +308,7 @@ test_expect_success 'no bitmaps created if .keep files present' '
keep=${pack%.pack}.keep &&
test_when_finished "rm -f \"\$keep\"" &&
>"$keep" &&
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -ad 2>stderr &&
+ git -C bare.git repack -ad 2>stderr &&
test_must_be_empty stderr &&
find bare.git/objects/pack/ -type f -name "*.bitmap" >actual &&
test_must_be_empty actual
@@ -320,13 +319,207 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' '
blob=$(test-tool genrandom big $((1024*1024)) |
git -C bare.git hash-object -w --stdin) &&
git -C bare.git update-ref refs/tags/big $blob &&
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -ad 2>stderr &&
+ git -C bare.git repack -ad 2>stderr &&
test_must_be_empty stderr &&
find bare.git/objects/pack -type f -name "*.bitmap" >actual &&
test_must_be_empty actual
'
+test_expect_success 'repacking with a filter works' '
+ git -C bare.git repack -a -d &&
+ test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+ git -C bare.git -c repack.writebitmaps=false repack -a -d --filter=blob:none &&
+ test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack &&
+ commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) &&
+ blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) &&
+ test "$commit_pack" != "$blob_pack" &&
+ tree_pack=$(test-tool -C bare.git find-pack -c 1 HEAD^{tree}) &&
+ test "$tree_pack" = "$commit_pack" &&
+ blob_pack2=$(test-tool -C bare.git find-pack -c 1 HEAD:file2) &&
+ test "$blob_pack2" = "$blob_pack"
+'
+
+test_expect_success '--filter fails with --write-bitmap-index' '
+ test_must_fail git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
+'
+
+test_expect_success 'repacking with two filters works' '
+ git init two-filters &&
+ (
+ cd two-filters &&
+ mkdir subdir &&
+ test_commit foo &&
+ test_commit subdir_bar subdir/bar &&
+ test_commit subdir_baz subdir/baz
+ ) &&
+ git clone --no-local --bare two-filters two-filters.git &&
+ (
+ cd two-filters.git &&
+ test_stdout_line_count = 1 ls objects/pack/*.pack &&
+ git -c repack.writebitmaps=false repack -a -d \
+ --filter=blob:none --filter=tree:1 &&
+ test_stdout_line_count = 2 ls objects/pack/*.pack &&
+ commit_pack=$(test-tool find-pack -c 1 HEAD) &&
+ blob_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+ root_tree_pack=$(test-tool find-pack -c 1 HEAD^{tree}) &&
+ subdir_tree_hash=$(git ls-tree --object-only HEAD -- subdir) &&
+ subdir_tree_pack=$(test-tool find-pack -c 1 "$subdir_tree_hash") &&
+
+ # Root tree and subdir tree are not in the same packfiles
+ test "$commit_pack" != "$blob_pack" &&
+ test "$commit_pack" = "$root_tree_pack" &&
+ test "$blob_pack" = "$subdir_tree_pack"
+ )
+'
+
+prepare_for_keep_packs () {
+ git init keep-packs &&
+ (
+ cd keep-packs &&
+ test_commit foo &&
+ test_commit bar
+ ) &&
+ git clone --no-local --bare keep-packs keep-packs.git &&
+ (
+ cd keep-packs.git &&
+
+ # Create two packs
+ # The first pack will contain all of the objects except one blob
+ git rev-list --objects --all >objs &&
+ grep -v "bar.t" objs | git pack-objects pack &&
+ # The second pack will contain the excluded object and be kept
+ packid=$(grep "bar.t" objs | git pack-objects pack) &&
+ >pack-$packid.keep &&
+
+ # Replace the existing pack with the 2 new ones
+ rm -f objects/pack/pack* &&
+ mv pack-* objects/pack/
+ )
+}
+
+test_expect_success '--filter works with .keep packs' '
+ prepare_for_keep_packs &&
+ (
+ cd keep-packs.git &&
+
+ foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+ bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) &&
+ head_pack=$(test-tool find-pack -c 1 HEAD) &&
+
+ test "$foo_pack" != "$bar_pack" &&
+ test "$foo_pack" = "$head_pack" &&
+
+ git -c repack.writebitmaps=false repack -a -d --filter=blob:none &&
+
+ foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+ bar_pack_1=$(test-tool find-pack -c 1 HEAD:bar.t) &&
+ head_pack_1=$(test-tool find-pack -c 1 HEAD) &&
+
+ # Object bar is still only in the old .keep pack
+ test "$foo_pack_1" != "$foo_pack" &&
+ test "$bar_pack_1" = "$bar_pack" &&
+ test "$head_pack_1" != "$head_pack" &&
+
+ test "$foo_pack_1" != "$bar_pack_1" &&
+ test "$foo_pack_1" != "$head_pack_1" &&
+ test "$bar_pack_1" != "$head_pack_1"
+ )
+'
+
+test_expect_success '--filter works with --pack-kept-objects and .keep packs' '
+ rm -rf keep-packs keep-packs.git &&
+ prepare_for_keep_packs &&
+ (
+ cd keep-packs.git &&
+
+ foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+ bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) &&
+ head_pack=$(test-tool find-pack -c 1 HEAD) &&
+
+ test "$foo_pack" != "$bar_pack" &&
+ test "$foo_pack" = "$head_pack" &&
+
+ git -c repack.writebitmaps=false repack -a -d --filter=blob:none \
+ --pack-kept-objects &&
+
+ foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+ test-tool find-pack -c 2 HEAD:bar.t >bar_pack_1 &&
+ head_pack_1=$(test-tool find-pack -c 1 HEAD) &&
+
+ test "$foo_pack_1" != "$foo_pack" &&
+ test "$foo_pack_1" != "$bar_pack" &&
+ test "$head_pack_1" != "$head_pack" &&
+
+ # Object bar is in both the old .keep pack and the new
+ # pack that contained the filtered out objects
+ grep "$bar_pack" bar_pack_1 &&
+ grep "$foo_pack_1" bar_pack_1 &&
+ test "$foo_pack_1" != "$head_pack_1"
+ )
+'
+
+test_expect_success '--filter-to stores filtered out objects' '
+ git -C bare.git repack -a -d &&
+ test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+
+ git init --bare filtered.git &&
+ git -C bare.git -c repack.writebitmaps=false repack -a -d \
+ --filter=blob:none \
+ --filter-to=../filtered.git/objects/pack/pack &&
+ test_stdout_line_count = 1 ls bare.git/objects/pack/pack-*.pack &&
+ test_stdout_line_count = 1 ls filtered.git/objects/pack/pack-*.pack &&
+
+ commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) &&
+ blob_pack=$(test-tool -C bare.git find-pack -c 0 HEAD:file1) &&
+ blob_hash=$(git -C bare.git rev-parse HEAD:file1) &&
+ test -n "$blob_hash" &&
+ blob_pack=$(test-tool -C filtered.git find-pack -c 1 $blob_hash) &&
+
+ echo $(pwd)/filtered.git/objects >bare.git/objects/info/alternates &&
+ blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) &&
+ blob_content=$(git -C bare.git show $blob_hash) &&
+ test "$blob_content" = "content1"
+'
+
+test_expect_success '--filter works with --max-pack-size' '
+ rm -rf filtered.git &&
+ git init --bare filtered.git &&
+ git init max-pack-size &&
+ (
+ cd max-pack-size &&
+ test_commit base &&
+ # two blobs which exceed the maximum pack size
+ test-tool genrandom foo 1048576 >foo &&
+ git hash-object -w foo &&
+ test-tool genrandom bar 1048576 >bar &&
+ git hash-object -w bar &&
+ git add foo bar &&
+ git commit -m "adding foo and bar"
+ ) &&
+ git clone --no-local --bare max-pack-size max-pack-size.git &&
+ (
+ cd max-pack-size.git &&
+ git -c repack.writebitmaps=false repack -a -d --filter=blob:none \
+ --max-pack-size=1M \
+ --filter-to=../filtered.git/objects/pack/pack &&
+ echo $(cd .. && pwd)/filtered.git/objects >objects/info/alternates &&
+
+ # Check that the 3 blobs are in different packfiles in filtered.git
+ test_stdout_line_count = 3 ls ../filtered.git/objects/pack/pack-*.pack &&
+ test_stdout_line_count = 1 ls objects/pack/pack-*.pack &&
+ foo_pack=$(test-tool find-pack -c 1 HEAD:foo) &&
+ bar_pack=$(test-tool find-pack -c 1 HEAD:bar) &&
+ base_pack=$(test-tool find-pack -c 1 HEAD:base.t) &&
+ test "$foo_pack" != "$bar_pack" &&
+ test "$foo_pack" != "$base_pack" &&
+ test "$bar_pack" != "$base_pack" &&
+ for pack in "$foo_pack" "$bar_pack" "$base_pack"
+ do
+ case "$foo_pack" in */filtered.git/objects/pack/*) true ;; *) return 1 ;; esac
+ done
+ )
+'
+
objdir=.git/objects
midx=$objdir/pack/multi-pack-index
@@ -343,11 +536,11 @@ test_expect_success 'setup for --write-midx tests' '
test_expect_success '--write-midx unchanged' '
(
cd midx &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack &&
+ git repack &&
test_path_is_missing $midx &&
test_path_is_missing $midx-*.bitmap &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+ git repack --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-*.bitmap &&
@@ -360,7 +553,7 @@ test_expect_success '--write-midx with a new pack' '
cd midx &&
test_commit loose &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+ git repack --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-*.bitmap &&
@@ -371,7 +564,7 @@ test_expect_success '--write-midx with a new pack' '
test_expect_success '--write-midx with -b' '
(
cd midx &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -mb &&
+ git repack -mb &&
test_path_is_file $midx &&
test_path_is_file $midx-*.bitmap &&
@@ -384,7 +577,7 @@ test_expect_success '--write-midx with -d' '
cd midx &&
test_commit repack &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ad --write-midx &&
+ git repack -Ad --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-*.bitmap &&
@@ -397,21 +590,21 @@ test_expect_success 'cleans up MIDX when appropriate' '
cd midx &&
test_commit repack-2 &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+ git repack -Adb --write-midx &&
checksum=$(midx_checksum $objdir) &&
test_path_is_file $midx &&
test_path_is_file $midx-$checksum.bitmap &&
test_commit repack-3 &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+ git repack -Adb --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-$checksum.bitmap &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
test_commit repack-4 &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb &&
+ git repack -Adb &&
find $objdir/pack -type f -name "multi-pack-index*" >files &&
test_must_be_empty files
@@ -523,13 +716,13 @@ test_expect_success '--write-midx removes stale pack-based bitmaps' '
(
cd repo &&
test_commit base &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab &&
+ git repack -Ab &&
pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) &&
test_path_is_file "$pack_bitmap" &&
test_commit tip &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -bm &&
+ git repack -bm &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
@@ -633,125 +826,4 @@ test_expect_success '-n overrides repack.updateServerInfo=true' '
test_server_info_missing
'
-test_expect_success '--expire-to stores pruned objects (now)' '
- git init expire-to-now &&
- (
- cd expire-to-now &&
-
- git branch -M main &&
-
- test_commit base &&
-
- git checkout -b cruft &&
- test_commit --no-tag cruft &&
-
- git rev-list --objects --no-object-names main..cruft >moved.raw &&
- sort moved.raw >moved.want &&
-
- git rev-list --all --objects --no-object-names >expect.raw &&
- sort expect.raw >expect &&
-
- git checkout main &&
- git branch -D cruft &&
- git reflog expire --all --expire=all &&
-
- git init --bare expired.git &&
- git repack -d \
- --cruft --cruft-expiration="now" \
- --expire-to="expired.git/objects/pack/pack" &&
-
- expired="$(ls expired.git/objects/pack/pack-*.idx)" &&
- test_path_is_file "${expired%.idx}.mtimes" &&
-
- # Since the `--cruft-expiration` is "now", the effective
- # behavior is to move _all_ unreachable objects out to
- # the location in `--expire-to`.
- git show-index <$expired >expired.raw &&
- cut -d" " -f2 expired.raw | sort >expired.objects &&
- git rev-list --all --objects --no-object-names \
- >remaining.objects &&
-
- # ...in other words, the combined contents of this
- # repository and expired.git should be the same as the
- # set of objects we started with.
- cat expired.objects remaining.objects | sort >actual &&
- test_cmp expect actual &&
-
- # The "moved" objects (i.e., those in expired.git)
- # should be the same as the cruft objects which were
- # expired in the previous step.
- test_cmp moved.want expired.objects
- )
-'
-
-test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' '
- git init expire-to-5.minutes.ago &&
- (
- cd expire-to-5.minutes.ago &&
-
- git branch -M main &&
-
- test_commit base &&
-
- # Create two classes of unreachable objects, one which
- # is older than 5 minutes (stale), and another which is
- # newer (recent).
- for kind in stale recent
- do
- git checkout -b $kind main &&
- test_commit --no-tag $kind || return 1
- done &&
-
- git rev-list --objects --no-object-names main..stale >in &&
- stale="$(git pack-objects $objdir/pack/pack <in)" &&
- mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" &&
-
- # expect holds the set of objects we expect to find in
- # this repository after repacking
- git rev-list --objects --no-object-names recent >expect.raw &&
- sort expect.raw >expect &&
-
- # moved.want holds the set of objects we expect to find
- # in expired.git
- git rev-list --objects --no-object-names main..stale >out &&
- sort out >moved.want &&
-
- git checkout main &&
- git branch -D stale recent &&
- git reflog expire --all --expire=all &&
- git prune-packed &&
-
- git init --bare expired.git &&
- git repack -d \
- --cruft --cruft-expiration=5.minutes.ago \
- --expire-to="expired.git/objects/pack/pack" &&
-
- # Some of the remaining objects in this repository are
- # unreachable, so use `cat-file --batch-all-objects`
- # instead of `rev-list` to get their names
- git cat-file --batch-all-objects --batch-check="%(objectname)" \
- >remaining.objects &&
- sort remaining.objects >actual &&
- test_cmp expect actual &&
-
- (
- cd expired.git &&
-
- expired="$(ls objects/pack/pack-*.mtimes)" &&
- test-tool pack-mtimes $(basename $expired) >out &&
- cut -d" " -f1 out | sort >../moved.got &&
-
- # Ensure that there are as many objects with the
- # expected mtime as were moved to expired.git.
- #
- # In other words, ensure that the recorded
- # mtimes of any moved objects was written
- # correctly.
- grep " $mtime$" out >matching &&
- test_line_count = $(wc -l <../moved.want) matching
- ) &&
- test_cmp moved.want moved.got
- )
-'
-
test_done
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index fe6c3e77a3..5715f4d69a 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -5,7 +5,6 @@ test_description='git repack works correctly'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
fsha1=
diff --git a/t/t7702-repack-cyclic-alternate.sh b/t/t7702-repack-cyclic-alternate.sh
index f3cdb98eec..cd91766e78 100755
--- a/t/t7702-repack-cyclic-alternate.sh
+++ b/t/t7702-repack-cyclic-alternate.sh
@@ -5,7 +5,6 @@
test_description='repack involving cyclic alternate'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
@@ -18,7 +17,7 @@ test_expect_success setup '
echo "$(pwd)"/.git/objects/../objects >.git/objects/info/alternates
'
-test_expect_success 're-packing repository with itsself as alternate' '
+test_expect_success 're-packing repository with itself as alternate' '
git repack -adl &&
git fsck
'
diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh
index 00f28fb558..9fc1626fbf 100755
--- a/t/t7703-repack-geometric.sh
+++ b/t/t7703-repack-geometric.sh
@@ -23,7 +23,7 @@ test_expect_success '--geometric with no packs' '
cd geometric &&
git repack --write-midx --geometric 2 >out &&
- test_i18ngrep "Nothing new to pack" out
+ test_grep "Nothing new to pack" out
)
'
@@ -38,7 +38,7 @@ test_expect_success '--geometric with one pack' '
git repack --geometric 2 >out &&
- test_i18ngrep "Nothing new to pack" out
+ test_grep "Nothing new to pack" out
)
'
diff --git a/t/t7704-repack-cruft.sh b/t/t7704-repack-cruft.sh
new file mode 100755
index 0000000000..959e6e2648
--- /dev/null
+++ b/t/t7704-repack-cruft.sh
@@ -0,0 +1,414 @@
+#!/bin/sh
+
+test_description='git repack works correctly'
+
+. ./test-lib.sh
+
+objdir=.git/objects
+packdir=$objdir/pack
+
+test_expect_success '--expire-to stores pruned objects (now)' '
+ git init expire-to-now &&
+ (
+ cd expire-to-now &&
+
+ git branch -M main &&
+
+ test_commit base &&
+
+ git checkout -b cruft &&
+ test_commit --no-tag cruft &&
+
+ git rev-list --objects --no-object-names main..cruft >moved.raw &&
+ sort moved.raw >moved.want &&
+
+ git rev-list --all --objects --no-object-names >expect.raw &&
+ sort expect.raw >expect &&
+
+ git checkout main &&
+ git branch -D cruft &&
+ git reflog expire --all --expire=all &&
+
+ git init --bare expired.git &&
+ git repack -d \
+ --cruft --cruft-expiration="now" \
+ --expire-to="expired.git/objects/pack/pack" &&
+
+ expired="$(ls expired.git/objects/pack/pack-*.idx)" &&
+ test_path_is_file "${expired%.idx}.mtimes" &&
+
+ # Since the `--cruft-expiration` is "now", the effective
+ # behavior is to move _all_ unreachable objects out to
+ # the location in `--expire-to`.
+ git show-index <$expired >expired.raw &&
+ cut -d" " -f2 expired.raw | sort >expired.objects &&
+ git rev-list --all --objects --no-object-names \
+ >remaining.objects &&
+
+ # ...in other words, the combined contents of this
+ # repository and expired.git should be the same as the
+ # set of objects we started with.
+ sort expired.objects remaining.objects >actual &&
+ test_cmp expect actual &&
+
+ # The "moved" objects (i.e., those in expired.git)
+ # should be the same as the cruft objects which were
+ # expired in the previous step.
+ test_cmp moved.want expired.objects
+ )
+'
+
+test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' '
+ git init expire-to-5.minutes.ago &&
+ (
+ cd expire-to-5.minutes.ago &&
+
+ git branch -M main &&
+
+ test_commit base &&
+
+ # Create two classes of unreachable objects, one which
+ # is older than 5 minutes (stale), and another which is
+ # newer (recent).
+ for kind in stale recent
+ do
+ git checkout -b $kind main &&
+ test_commit --no-tag $kind || return 1
+ done &&
+
+ git rev-list --objects --no-object-names main..stale >in &&
+ stale="$(git pack-objects $objdir/pack/pack <in)" &&
+ mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" &&
+
+ # expect holds the set of objects we expect to find in
+ # this repository after repacking
+ git rev-list --objects --no-object-names recent >expect.raw &&
+ sort expect.raw >expect &&
+
+ # moved.want holds the set of objects we expect to find
+ # in expired.git
+ git rev-list --objects --no-object-names main..stale >out &&
+ sort out >moved.want &&
+
+ git checkout main &&
+ git branch -D stale recent &&
+ git reflog expire --all --expire=all &&
+ git prune-packed &&
+
+ git init --bare expired.git &&
+ git repack -d \
+ --cruft --cruft-expiration=5.minutes.ago \
+ --expire-to="expired.git/objects/pack/pack" &&
+
+ # Some of the remaining objects in this repository are
+ # unreachable, so use `cat-file --batch-all-objects`
+ # instead of `rev-list` to get their names
+ git cat-file --batch-all-objects --batch-check="%(objectname)" \
+ >remaining.objects &&
+ sort remaining.objects >actual &&
+ test_cmp expect actual &&
+
+ (
+ cd expired.git &&
+
+ expired="$(ls objects/pack/pack-*.mtimes)" &&
+ test-tool pack-mtimes $(basename $expired) >out &&
+ cut -d" " -f1 out | sort >../moved.got &&
+
+ # Ensure that there are as many objects with the
+ # expected mtime as were moved to expired.git.
+ #
+ # In other words, ensure that the recorded
+ # mtimes of any moved objects was written
+ # correctly.
+ grep " $mtime$" out >matching &&
+ test_line_count = $(wc -l <../moved.want) matching
+ ) &&
+ test_cmp moved.want moved.got
+ )
+'
+
+generate_random_blob() {
+ test-tool genrandom "$@" >blob &&
+ git hash-object -w -t blob blob &&
+ rm blob
+}
+
+pack_random_blob () {
+ generate_random_blob "$@" &&
+ git repack -d -q >/dev/null
+}
+
+generate_cruft_pack () {
+ pack_random_blob "$@" >/dev/null &&
+
+ ls $packdir/pack-*.pack | xargs -n 1 basename >in &&
+ pack="$(git pack-objects --cruft $packdir/pack <in)" &&
+ git prune-packed &&
+
+ echo "$packdir/pack-$pack.mtimes"
+}
+
+test_expect_success '--max-cruft-size creates new packs when above threshold' '
+ git init max-cruft-size-large &&
+ (
+ cd max-cruft-size-large &&
+ test_commit base &&
+
+ foo="$(pack_random_blob foo $((1*1024*1024)))" &&
+ git repack --cruft -d &&
+ cruft_foo="$(ls $packdir/pack-*.mtimes)" &&
+
+ bar="$(pack_random_blob bar $((1*1024*1024)))" &&
+ git repack --cruft -d --max-cruft-size=1M &&
+ cruft_bar="$(ls $packdir/pack-*.mtimes | grep -v $cruft_foo)" &&
+
+ test-tool pack-mtimes $(basename "$cruft_foo") >foo.objects &&
+ test-tool pack-mtimes $(basename "$cruft_bar") >bar.objects &&
+
+ grep "^$foo" foo.objects &&
+ test_line_count = 1 foo.objects &&
+ grep "^$bar" bar.objects &&
+ test_line_count = 1 bar.objects
+ )
+'
+
+test_expect_success '--max-cruft-size combines existing packs when below threshold' '
+ git init max-cruft-size-small &&
+ (
+ cd max-cruft-size-small &&
+ test_commit base &&
+
+ foo="$(pack_random_blob foo $((1*1024*1024)))" &&
+ git repack --cruft -d &&
+
+ bar="$(pack_random_blob bar $((1*1024*1024)))" &&
+ git repack --cruft -d --max-cruft-size=10M &&
+
+ cruft=$(ls $packdir/pack-*.mtimes) &&
+ test-tool pack-mtimes $(basename "$cruft") >cruft.objects &&
+
+ grep "^$foo" cruft.objects &&
+ grep "^$bar" cruft.objects &&
+ test_line_count = 2 cruft.objects
+ )
+'
+
+test_expect_success '--max-cruft-size combines smaller packs first' '
+ git init max-cruft-size-consume-small &&
+ (
+ cd max-cruft-size-consume-small &&
+
+ test_commit base &&
+ git repack -ad &&
+
+ cruft_foo="$(generate_cruft_pack foo 524288)" && # 0.5 MiB
+ cruft_bar="$(generate_cruft_pack bar 524288)" && # 0.5 MiB
+ cruft_baz="$(generate_cruft_pack baz 1048576)" && # 1.0 MiB
+ cruft_quux="$(generate_cruft_pack quux 1572864)" && # 1.5 MiB
+
+ test-tool pack-mtimes "$(basename $cruft_foo)" >expect.raw &&
+ test-tool pack-mtimes "$(basename $cruft_bar)" >>expect.raw &&
+ sort expect.raw >expect.objects &&
+
+ # repacking with `--max-cruft-size=2M` should combine
+ # both 0.5 MiB packs together, instead of, say, one of
+ # the 0.5 MiB packs with the 1.0 MiB pack
+ ls $packdir/pack-*.mtimes | sort >cruft.before &&
+ git repack -d --cruft --max-cruft-size=2M &&
+ ls $packdir/pack-*.mtimes | sort >cruft.after &&
+
+ comm -13 cruft.before cruft.after >cruft.new &&
+ comm -23 cruft.before cruft.after >cruft.removed &&
+
+ test_line_count = 1 cruft.new &&
+ test_line_count = 2 cruft.removed &&
+
+ # the two smaller packs should be rolled up first
+ printf "%s\n" $cruft_foo $cruft_bar | sort >expect.removed &&
+ test_cmp expect.removed cruft.removed &&
+
+ # ...and contain the set of objects rolled up
+ test-tool pack-mtimes "$(basename $(cat cruft.new))" >actual.raw &&
+ sort actual.raw >actual.objects &&
+
+ test_cmp expect.objects actual.objects
+ )
+'
+
+test_expect_success 'setup --max-cruft-size with freshened objects' '
+ git init max-cruft-size-freshen &&
+ (
+ cd max-cruft-size-freshen &&
+
+ test_commit base &&
+ git repack -ad &&
+
+ foo="$(generate_random_blob foo 64)" &&
+ test-tool chmtime --get -10000 \
+ "$objdir/$(test_oid_to_path "$foo")" >foo.mtime &&
+
+ git repack --cruft -d &&
+
+ cruft="$(ls $packdir/pack-*.mtimes)" &&
+ test-tool pack-mtimes "$(basename $cruft)" >actual &&
+ echo "$foo $(cat foo.mtime)" >expect &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--max-cruft-size with freshened objects (loose)' '
+ (
+ cd max-cruft-size-freshen &&
+
+ # regenerate the object, setting its mtime to be more recent
+ foo="$(generate_random_blob foo 64)" &&
+ test-tool chmtime --get -100 \
+ "$objdir/$(test_oid_to_path "$foo")" >foo.mtime &&
+
+ git repack --cruft -d &&
+
+ cruft="$(ls $packdir/pack-*.mtimes)" &&
+ test-tool pack-mtimes "$(basename $cruft)" >actual &&
+ echo "$foo $(cat foo.mtime)" >expect &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--max-cruft-size with freshened objects (packed)' '
+ (
+ cd max-cruft-size-freshen &&
+
+ # regenerate the object and store it in a packfile,
+ # setting its mtime to be more recent
+ #
+ # store it alongside another cruft object so that we
+ # do not create an identical copy of the existing
+ # cruft pack (which contains $foo).
+ foo="$(generate_random_blob foo 64)" &&
+ bar="$(generate_random_blob bar 64)" &&
+ foo_pack="$(printf "%s\n" $foo $bar | git pack-objects $packdir/pack)" &&
+ git prune-packed &&
+
+ test-tool chmtime --get -10 \
+ "$packdir/pack-$foo_pack.pack" >foo.mtime &&
+
+ git repack --cruft -d &&
+
+ cruft="$(ls $packdir/pack-*.mtimes)" &&
+ test-tool pack-mtimes "$(basename $cruft)" >actual &&
+ echo "$foo $(cat foo.mtime)" >expect.raw &&
+ echo "$bar $(cat foo.mtime)" >>expect.raw &&
+ sort expect.raw >expect &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success '--max-cruft-size with pruning' '
+ git init max-cruft-size-prune &&
+ (
+ cd max-cruft-size-prune &&
+
+ test_commit base &&
+ foo="$(generate_random_blob foo $((1024*1024)))" &&
+ bar="$(generate_random_blob bar $((1024*1024)))" &&
+ baz="$(generate_random_blob baz $((1024*1024)))" &&
+
+ test-tool chmtime -10000 "$objdir/$(test_oid_to_path "$foo")" &&
+
+ git repack -d --cruft --max-cruft-size=1M &&
+
+ # backdate the mtimes of all cruft packs to validate
+ # that they were rewritten as a result of pruning
+ ls $packdir/pack-*.mtimes | sort >cruft.before &&
+ for cruft in $(cat cruft.before)
+ do
+ mtime="$(test-tool chmtime --get -10000 "$cruft")" &&
+ echo $cruft $mtime >>mtimes || return 1
+ done &&
+
+ # repack (and prune) with a --max-cruft-size to ensure
+ # that we appropriately split the resulting set of packs
+ git repack -d --cruft --max-cruft-size=1M \
+ --cruft-expiration=1000.seconds.ago &&
+ ls $packdir/pack-*.mtimes | sort >cruft.after &&
+
+ for cruft in $(cat cruft.after)
+ do
+ old_mtime="$(grep $cruft mtimes | cut -d" " -f2)" &&
+ new_mtime="$(test-tool chmtime --get $cruft)" &&
+ test $old_mtime -lt $new_mtime || return 1
+ done &&
+
+ test_line_count = 3 cruft.before &&
+ test_line_count = 2 cruft.after &&
+ test_must_fail git cat-file -e $foo &&
+ git cat-file -e $bar &&
+ git cat-file -e $baz
+ )
+'
+
+test_expect_success '--max-cruft-size ignores non-local packs' '
+ repo="max-cruft-size-non-local" &&
+ git init $repo &&
+ (
+ cd $repo &&
+ test_commit base &&
+ generate_random_blob foo 64 &&
+ git repack --cruft -d
+ ) &&
+
+ git clone --reference=$repo $repo $repo-alt &&
+ (
+ cd $repo-alt &&
+
+ test_commit other &&
+ generate_random_blob bar 64 &&
+
+ # ensure that we do not attempt to pick up packs from
+ # the non-alternated repository, which would result in a
+ # crash
+ git repack --cruft --max-cruft-size=1M -d
+ )
+'
+
+test_expect_success 'reachable packs are preferred over cruft ones' '
+ repo="cruft-preferred-packs" &&
+ git init "$repo" &&
+ (
+ cd "$repo" &&
+
+ # This test needs to exercise careful control over when a MIDX
+ # is and is not written. Unset the corresponding TEST variable
+ # accordingly.
+ sane_unset GIT_TEST_MULTI_PACK_INDEX &&
+
+ test_commit base &&
+ test_commit --no-tag cruft &&
+
+ non_cruft="$(echo base | git pack-objects --revs $packdir/pack)" &&
+ # Write a cruft pack which both (a) sorts ahead of the non-cruft
+ # pack in lexical order, and (b) has an older mtime to appease
+ # the MIDX preferred pack selection routine.
+ cruft="$(echo pack-$non_cruft.pack | git pack-objects --cruft $packdir/pack-A)" &&
+ test-tool chmtime -1000 $packdir/pack-A-$cruft.pack &&
+
+ test_commit other &&
+ git repack -d &&
+
+ git repack --geometric 2 -d --write-midx --write-bitmap-index &&
+
+ # After repacking, there are two packs left: one reachable one
+ # (which is the result of combining both of the existing two
+ # non-cruft packs), and one cruft pack.
+ find .git/objects/pack -type f -name "*.pack" >packs &&
+ test_line_count = 2 packs &&
+
+ # Make sure that the pack we just wrote is marked as preferred,
+ # not the cruft one.
+ pack="$(test-tool read-midx --preferred-pack $objdir)" &&
+ test_path_is_missing "$packdir/$(basename "$pack" ".idx").mtimes"
+ )
+'
+
+test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 59d3847bf8..9b74db5563 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -28,14 +28,14 @@ prompt_given ()
test_expect_success 'basic usage requires no repo' '
test_expect_code 129 git difftool -h >output &&
- test_i18ngrep ^usage: output &&
+ test_grep ^usage: output &&
# create a ceiling directory to prevent Git from finding a repo
mkdir -p not/repo &&
test_when_finished rm -r not &&
test_expect_code 129 \
env GIT_CEILING_DIRECTORIES="$(pwd)/not" \
git -C not/repo difftool -h >output &&
- test_i18ngrep ^usage: output
+ test_grep ^usage: output
'
# Create a file on main and change it on branch
@@ -91,58 +91,67 @@ test_expect_success 'difftool forwards arguments to diff' '
rm for-diff
'
-test_expect_success 'difftool ignores exit code' '
- test_config difftool.error.cmd false &&
- git difftool -y -t error branch
-'
-
-test_expect_success 'difftool forwards exit code with --trust-exit-code' '
- test_config difftool.error.cmd false &&
- test_must_fail git difftool -y --trust-exit-code -t error branch
-'
-
-test_expect_success 'difftool forwards exit code with --trust-exit-code for built-ins' '
- test_config difftool.vimdiff.path false &&
- test_must_fail git difftool -y --trust-exit-code -t vimdiff branch
-'
-
-test_expect_success 'difftool honors difftool.trustExitCode = true' '
- test_config difftool.error.cmd false &&
- test_config difftool.trustExitCode true &&
- test_must_fail git difftool -y -t error branch
-'
-
-test_expect_success 'difftool honors difftool.trustExitCode = false' '
- test_config difftool.error.cmd false &&
- test_config difftool.trustExitCode false &&
- git difftool -y -t error branch
-'
-
-test_expect_success 'difftool ignores exit code with --no-trust-exit-code' '
- test_config difftool.error.cmd false &&
- test_config difftool.trustExitCode true &&
- git difftool -y --no-trust-exit-code -t error branch
-'
-
-test_expect_success 'difftool stops on error with --trust-exit-code' '
- test_when_finished "rm -f for-diff .git/fail-right-file" &&
- test_when_finished "git reset -- for-diff" &&
- write_script .git/fail-right-file <<-\EOF &&
- echo failed
- exit 1
- EOF
- >for-diff &&
- git add for-diff &&
- test_must_fail git difftool -y --trust-exit-code \
- --extcmd .git/fail-right-file branch >actual &&
- test_line_count = 1 actual
-'
-
-test_expect_success 'difftool honors exit status if command not found' '
- test_config difftool.nonexistent.cmd i-dont-exist &&
- test_config difftool.trustExitCode false &&
- test_must_fail git difftool -y -t nonexistent branch
-'
+for opt in '' '--dir-diff'
+do
+ test_expect_success "difftool ${opt:-without options} ignores exit code" '
+ test_config difftool.error.cmd false &&
+ git difftool ${opt} -y -t error branch
+ '
+
+ test_expect_success "difftool ${opt:-without options} forwards exit code with --trust-exit-code" '
+ test_config difftool.error.cmd false &&
+ test_must_fail git difftool ${opt} -y --trust-exit-code -t error branch
+ '
+
+ test_expect_success "difftool ${opt:-without options} forwards exit code with --trust-exit-code for built-ins" '
+ test_config difftool.vimdiff.path false &&
+ test_must_fail git difftool ${opt} -y --trust-exit-code -t vimdiff branch
+ '
+
+ test_expect_success "difftool ${opt:-without options} honors difftool.trustExitCode = true" '
+ test_config difftool.error.cmd false &&
+ test_config difftool.trustExitCode true &&
+ test_must_fail git difftool ${opt} -y -t error branch
+ '
+
+ test_expect_success "difftool ${opt:-without options} honors difftool.trustExitCode = false" '
+ test_config difftool.error.cmd false &&
+ test_config difftool.trustExitCode false &&
+ git difftool ${opt} -y -t error branch
+ '
+
+ test_expect_success "difftool ${opt:-without options} ignores exit code with --no-trust-exit-code" '
+ test_config difftool.error.cmd false &&
+ test_config difftool.trustExitCode true &&
+ git difftool ${opt} -y --no-trust-exit-code -t error branch
+ '
+
+ test_expect_success "difftool ${opt:-without options} stops on error with --trust-exit-code" '
+ test_when_finished "rm -f for-diff .git/fail-right-file" &&
+ test_when_finished "git reset -- for-diff" &&
+ write_script .git/fail-right-file <<-\EOF &&
+ echo failed
+ exit 1
+ EOF
+ >for-diff &&
+ git add for-diff &&
+ test_must_fail git difftool ${opt} -y --trust-exit-code \
+ --extcmd .git/fail-right-file branch >actual &&
+ test_line_count = 1 actual
+ '
+
+ test_expect_success "difftool ${opt:-without options} honors exit status if command not found" '
+ test_config difftool.nonexistent.cmd i-dont-exist &&
+ test_config difftool.trustExitCode false &&
+ if test "${opt}" = --dir-diff
+ then
+ expected_code=127
+ else
+ expected_code=128
+ fi &&
+ test_expect_code ${expected_code} git difftool ${opt} -y -t nonexistent branch
+ '
+done
test_expect_success 'difftool honors --gui' '
difftool_test_setup &&
@@ -656,6 +665,10 @@ run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
test_cmp expect file
'
+run_dir_diff_test 'difftool --dir-diff with no diff' '
+ git difftool -d main main
+'
+
write_script modify-file <<\EOF
echo "new content" >file
EOF
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 39d6d713ec..64ac4f04ee 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -31,6 +31,7 @@ int main(int argc, const char **argv)
return 0;
/* char ?? */
}
+
EOF
test_expect_success setup '
@@ -86,6 +87,7 @@ test_expect_success setup '
# Still a no-op.
function dummy() {}
EOF
+ printf "\200\nASCII\n" >invalid-utf8 &&
if test_have_prereq FUNNYNAMES
then
echo unusual >"\"unusual\" pathname" &&
@@ -533,6 +535,14 @@ do
test_cmp expected actual
'
+ test_expect_success "grep $L searches past invalid lines on UTF-8 locale" '
+ LC_ALL=en_US.UTF-8 git grep A. invalid-utf8 >actual &&
+ cat >expected <<-EOF &&
+ invalid-utf8:ASCII
+ EOF
+ test_cmp expected actual
+ '
+
test_expect_success FUNNYNAMES "grep $L should quote unusual pathnames" '
cat >expected <<-EOF &&
${HC}"\"unusual\" pathname":unusual
@@ -808,6 +818,19 @@ test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
test_cmp expected actual
'
+test_expect_success 'grep -f, use cwd relative file' '
+ test_when_finished "git rm -f sub/dir/file" &&
+ mkdir -p sub/dir &&
+ echo hit >sub/dir/file &&
+ git add sub/dir/file &&
+ echo hit >sub/dir/pattern &&
+ echo miss >pattern &&
+ (
+ cd sub/dir && git grep -f pattern file
+ ) &&
+ git -C sub/dir grep -f pattern file
+'
+
cat >expected <<EOF
y:y yy
--
@@ -1234,6 +1257,33 @@ test_expect_success 'outside of git repository with fallbackToNoIndex' '
)
'
+test_expect_success 'no repository with path outside $cwd' '
+ test_when_finished rm -fr non &&
+ rm -fr non &&
+ mkdir -p non/git/sub non/tig &&
+ (
+ GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd non/git &&
+ test_expect_code 128 git grep --no-index search .. 2>error &&
+ grep "is outside the directory tree" error
+ ) &&
+ (
+ GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd non/git &&
+ test_expect_code 128 git grep --no-index search ../tig 2>error &&
+ grep "is outside the directory tree" error
+ ) &&
+ (
+ GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd non/git &&
+ test_expect_code 128 git grep --no-index search ../non 2>error &&
+ grep "no such path in the working tree" error
+ )
+'
+
test_expect_success 'inside git repository but with --no-index' '
rm -fr is &&
mkdir -p is/git/sub &&
@@ -1386,7 +1436,7 @@ test_expect_success 'grep --no-index pattern -- path' '
test_expect_success 'grep --no-index complains of revs' '
test_must_fail git grep --no-index o main -- 2>err &&
- test_i18ngrep "cannot be used with revs" err
+ test_grep "cannot be used with revs" err
'
test_expect_success 'grep --no-index prefers paths to revs' '
@@ -1399,7 +1449,7 @@ test_expect_success 'grep --no-index prefers paths to revs' '
test_expect_success 'grep --no-index does not "diagnose" revs' '
test_must_fail git grep --no-index o :1:hello.c 2>err &&
- test_i18ngrep ! -i "did you mean" err
+ test_grep ! -i "did you mean" err
'
cat >expected <<EOF
diff --git a/t/t7811-grep-open.sh b/t/t7811-grep-open.sh
index 1dd07141a7..3160be59fd 100755
--- a/t/t7811-grep-open.sh
+++ b/t/t7811-grep-open.sh
@@ -3,7 +3,6 @@
test_description='git grep --open-files-in-pager
'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pager.sh
unset PAGER GIT_PAGER
@@ -63,7 +62,7 @@ test_expect_success SIMPLEPAGER 'git grep -O' '
test_expect_success 'git grep -O --cached' '
test_must_fail git grep --cached -O GREP_PATTERN >out 2>msg &&
- test_i18ngrep open-files-in-pager msg
+ test_grep open-files-in-pager msg
'
test_expect_success 'git grep -O --no-index' '
diff --git a/t/t7812-grep-icase-non-ascii.sh b/t/t7812-grep-icase-non-ascii.sh
index 31c66b63c2..ac7be54714 100755
--- a/t/t7812-grep-icase-non-ascii.sh
+++ b/t/t7812-grep-icase-non-ascii.sh
@@ -2,7 +2,6 @@
test_description='grep icase on non-English locales'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
doalarm () {
diff --git a/t/t7813-grep-icase-iso.sh b/t/t7813-grep-icase-iso.sh
index 1227885737..701e08a8e5 100755
--- a/t/t7813-grep-icase-iso.sh
+++ b/t/t7813-grep-icase-iso.sh
@@ -2,7 +2,6 @@
test_description='grep icase on non-English locales'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
test_expect_success GETTEXT_ISO_LOCALE 'setup' '
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index d37c83b464..167fe66150 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -348,7 +348,7 @@ test_incompatible_with_recurse_submodules ()
{
test_expect_success "--recurse-submodules and $1 are incompatible" "
test_must_fail git grep -e. --recurse-submodules $1 2>actual &&
- test_i18ngrep 'not supported with --recurse-submodules' actual
+ test_grep 'not supported with --recurse-submodules' actual
"
}
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index ac871287c0..90ebb64f46 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -2,7 +2,6 @@
test_description='git grep in binary files'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' "
diff --git a/t/t7816-grep-binary-pattern.sh b/t/t7816-grep-binary-pattern.sh
index fdb2355649..0088eaa0c9 100755
--- a/t/t7816-grep-binary-pattern.sh
+++ b/t/t7816-grep-binary-pattern.sh
@@ -2,7 +2,6 @@
test_description='git grep with a binary pattern files'
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
nul_match_internal () {
@@ -26,7 +25,7 @@ nul_match_internal () {
>stderr &&
printf '$pattern' | q_to_nul >f &&
test_must_fail env LC_ALL=\"$lc_all\" git grep $extra_flags -f f $flags a 2>stderr &&
- test_i18ngrep ! 'This is only supported with -P under PCRE v2' stderr
+ test_grep ! 'This is only supported with -P under PCRE v2' stderr
"
elif test "$matches" = P
then
@@ -34,7 +33,7 @@ nul_match_internal () {
>stderr &&
printf '$pattern' | q_to_nul >f &&
test_must_fail env LC_ALL=\"$lc_all\" git grep -f f $flags a 2>stderr &&
- test_i18ngrep 'This is only supported with -P under PCRE v2' stderr
+ test_grep 'This is only supported with -P under PCRE v2' stderr
"
else
test_expect_success "PANIC: Test framework error. Unknown matches value $matches" 'false'
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 487e326b3f..0ce4ba1cbe 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -33,13 +33,13 @@ test_systemd_analyze_verify () {
test_expect_success 'help text' '
test_expect_code 129 git maintenance -h >actual &&
- test_i18ngrep "usage: git maintenance <subcommand>" actual &&
+ test_grep "usage: git maintenance <subcommand>" actual &&
test_expect_code 129 git maintenance barf 2>err &&
- test_i18ngrep "unknown subcommand: \`barf'\''" err &&
- test_i18ngrep "usage: git maintenance" err &&
+ test_grep "unknown subcommand: \`barf'\''" err &&
+ test_grep "usage: git maintenance" err &&
test_expect_code 129 git maintenance 2>err &&
- test_i18ngrep "error: need a subcommand" err &&
- test_i18ngrep "usage: git maintenance" err
+ test_grep "error: need a subcommand" err &&
+ test_grep "usage: git maintenance" err
'
test_expect_success 'run [--auto|--quiet]' '
@@ -49,22 +49,92 @@ test_expect_success 'run [--auto|--quiet]' '
git maintenance run --auto 2>/dev/null &&
GIT_TRACE2_EVENT="$(pwd)/run-no-quiet.txt" \
git maintenance run --no-quiet 2>/dev/null &&
- test_subcommand git gc --quiet <run-no-auto.txt &&
- test_subcommand ! git gc --auto --quiet <run-auto.txt &&
- test_subcommand git gc --no-quiet <run-no-quiet.txt
+ test_subcommand git gc --quiet --no-detach <run-no-auto.txt &&
+ test_subcommand ! git gc --auto --quiet --no-detach <run-auto.txt &&
+ test_subcommand git gc --no-quiet --no-detach <run-no-quiet.txt
'
test_expect_success 'maintenance.auto config option' '
GIT_TRACE2_EVENT="$(pwd)/default" git commit --quiet --allow-empty -m 1 &&
- test_subcommand git maintenance run --auto --quiet <default &&
+ test_subcommand git maintenance run --auto --quiet --detach <default &&
GIT_TRACE2_EVENT="$(pwd)/true" \
git -c maintenance.auto=true \
commit --quiet --allow-empty -m 2 &&
- test_subcommand git maintenance run --auto --quiet <true &&
+ test_subcommand git maintenance run --auto --quiet --detach <true &&
GIT_TRACE2_EVENT="$(pwd)/false" \
git -c maintenance.auto=false \
commit --quiet --allow-empty -m 3 &&
- test_subcommand ! git maintenance run --auto --quiet <false
+ test_subcommand ! git maintenance run --auto --quiet --detach <false
+'
+
+for cfg in maintenance.autoDetach gc.autoDetach
+do
+ test_expect_success "$cfg=true config option" '
+ test_when_finished "rm -f trace" &&
+ test_config $cfg true &&
+ GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 &&
+ test_subcommand git maintenance run --auto --quiet --detach <trace
+ '
+
+ test_expect_success "$cfg=false config option" '
+ test_when_finished "rm -f trace" &&
+ test_config $cfg false &&
+ GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 &&
+ test_subcommand git maintenance run --auto --quiet --no-detach <trace
+ '
+done
+
+test_expect_success "maintenance.autoDetach overrides gc.autoDetach" '
+ test_when_finished "rm -f trace" &&
+ test_config maintenance.autoDetach false &&
+ test_config gc.autoDetach true &&
+ GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 &&
+ test_subcommand git maintenance run --auto --quiet --no-detach <trace
+'
+
+test_expect_success 'register uses XDG_CONFIG_HOME config if it exists' '
+ test_when_finished rm -r .config/git/config &&
+ (
+ XDG_CONFIG_HOME=.config &&
+ export XDG_CONFIG_HOME &&
+ mkdir -p $XDG_CONFIG_HOME/git &&
+ >$XDG_CONFIG_HOME/git/config &&
+ git maintenance register &&
+ git config --file=$XDG_CONFIG_HOME/git/config --get maintenance.repo >actual &&
+ pwd >expect &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'register does not need XDG_CONFIG_HOME config to exist' '
+ test_when_finished git maintenance unregister &&
+ test_path_is_missing $XDG_CONFIG_HOME/git/config &&
+ git maintenance register &&
+ git config --global --get maintenance.repo >actual &&
+ pwd >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'unregister uses XDG_CONFIG_HOME config if it exists' '
+ test_when_finished rm -r .config/git/config &&
+ (
+ XDG_CONFIG_HOME=.config &&
+ export XDG_CONFIG_HOME &&
+ mkdir -p $XDG_CONFIG_HOME/git &&
+ >$XDG_CONFIG_HOME/git/config &&
+ git maintenance register &&
+ git maintenance unregister &&
+ test_must_fail git config --file=$XDG_CONFIG_HOME/git/config --get maintenance.repo >actual &&
+ test_must_be_empty actual
+ )
+'
+
+test_expect_success 'unregister does not need XDG_CONFIG_HOME config to exist' '
+ test_path_is_missing $XDG_CONFIG_HOME/git/config &&
+ git maintenance register &&
+ git maintenance unregister &&
+ test_must_fail git config --global --get maintenance.repo >actual &&
+ test_must_be_empty actual
'
test_expect_success 'maintenance.<task>.enabled' '
@@ -84,9 +154,9 @@ test_expect_success 'run --task=<task>' '
git maintenance run --task=commit-graph 2>/dev/null &&
GIT_TRACE2_EVENT="$(pwd)/run-both.txt" \
git maintenance run --task=commit-graph --task=gc 2>/dev/null &&
- test_subcommand ! git gc --quiet <run-commit-graph.txt &&
- test_subcommand git gc --quiet <run-gc.txt &&
- test_subcommand git gc --quiet <run-both.txt &&
+ test_subcommand ! git gc --quiet --no-detach <run-commit-graph.txt &&
+ test_subcommand git gc --quiet --no-detach <run-gc.txt &&
+ test_subcommand git gc --quiet --no-detach <run-both.txt &&
test_subcommand git commit-graph write --split --reachable --no-progress <run-commit-graph.txt &&
test_subcommand ! git commit-graph write --split --reachable --no-progress <run-gc.txt &&
test_subcommand git commit-graph write --split --reachable --no-progress <run-both.txt
@@ -131,12 +201,12 @@ test_expect_success 'commit-graph auto condition' '
test_expect_success 'run --task=bogus' '
test_must_fail git maintenance run --task=bogus 2>err &&
- test_i18ngrep "is not a valid task" err
+ test_grep "is not a valid task" err
'
test_expect_success 'run --task duplicate' '
test_must_fail git maintenance run --task=gc --task=gc 2>err &&
- test_i18ngrep "cannot be selected multiple times" err
+ test_grep "cannot be selected multiple times" err
'
test_expect_success 'run --task=prefetch with no remotes' '
@@ -157,7 +227,8 @@ test_expect_success 'prefetch multiple remotes' '
fetchargs="--prefetch --prune --no-tags --no-write-fetch-head --recurse-submodules=no --quiet" &&
test_subcommand git fetch remote1 $fetchargs <run-prefetch.txt &&
test_subcommand git fetch remote2 $fetchargs <run-prefetch.txt &&
- test_path_is_missing .git/refs/remotes &&
+ git for-each-ref refs/remotes >actual &&
+ test_must_be_empty actual &&
git log prefetch/remotes/remote1/one &&
git log prefetch/remotes/remote2/two &&
git fetch --all &&
@@ -377,12 +448,12 @@ test_expect_success 'pack-refs task' '
test_expect_success '--auto and --schedule incompatible' '
test_must_fail git maintenance run --auto --schedule=daily 2>err &&
- test_i18ngrep "at most one" err
+ test_grep "at most one" err
'
test_expect_success 'invalid --schedule value' '
test_must_fail git maintenance run --schedule=annually 2>err &&
- test_i18ngrep "unrecognized --schedule" err
+ test_grep "unrecognized --schedule" err
'
test_expect_success '--schedule inheritance weekly -> daily -> hourly' '
@@ -574,17 +645,33 @@ test_expect_success !MINGW 'register and unregister with regex metacharacters' '
maintenance.repo "$(pwd)/$META"
'
+test_expect_success 'start without GIT_TEST_MAINT_SCHEDULER' '
+ test_when_finished "rm -rf systemctl.log script repo" &&
+ mkdir script &&
+ write_script script/systemctl <<-\EOF &&
+ echo "$*" >>../systemctl.log
+ EOF
+ git init repo &&
+ (
+ cd repo &&
+ sane_unset GIT_TEST_MAINT_SCHEDULER &&
+ PATH="$PWD/../script:$PATH" git maintenance start --scheduler=systemd
+ ) &&
+ test_grep -- "--user list-timers" systemctl.log &&
+ test_grep -- "enable --now git-maintenance@" systemctl.log
+'
+
test_expect_success 'start --scheduler=<scheduler>' '
test_expect_code 129 git maintenance start --scheduler=foo 2>err &&
- test_i18ngrep "unrecognized --scheduler argument" err &&
+ test_grep "unrecognized --scheduler argument" err &&
test_expect_code 129 git maintenance start --no-scheduler 2>err &&
- test_i18ngrep "unknown option" err &&
+ test_grep "unknown option" err &&
test_expect_code 128 \
env GIT_TEST_MAINT_SCHEDULER="launchctl:true,schtasks:true" \
git maintenance start --scheduler=crontab 2>err &&
- test_i18ngrep "fatal: crontab scheduler is not available" err
+ test_grep "fatal: crontab scheduler is not available" err
'
test_expect_success 'start from empty cron table' '
@@ -593,9 +680,9 @@ test_expect_success 'start from empty cron table' '
# start registers the repo
git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
- grep "for-each-repo --config=maintenance.repo maintenance run --schedule=daily" cron.txt &&
- grep "for-each-repo --config=maintenance.repo maintenance run --schedule=hourly" cron.txt &&
- grep "for-each-repo --config=maintenance.repo maintenance run --schedule=weekly" cron.txt
+ grep "for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=daily" cron.txt &&
+ grep "for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=hourly" cron.txt &&
+ grep "for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=weekly" cron.txt
'
test_expect_success 'stop from existing schedule' '
@@ -744,7 +831,18 @@ test_expect_success 'start and stop Linux/systemd maintenance' '
# start registers the repo
git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
- test_systemd_analyze_verify "systemd/user/git-maintenance@.service" &&
+ for schedule in hourly daily weekly
+ do
+ test_path_is_file "systemd/user/git-maintenance@$schedule.timer" || return 1
+ done &&
+ test_path_is_file "systemd/user/git-maintenance@.service" &&
+
+ test_systemd_analyze_verify "systemd/user/git-maintenance@hourly.service" &&
+ test_systemd_analyze_verify "systemd/user/git-maintenance@daily.service" &&
+ test_systemd_analyze_verify "systemd/user/git-maintenance@weekly.service" &&
+
+ grep "core.askPass=true" "systemd/user/git-maintenance@.service" &&
+ grep "credential.interactive=false" "systemd/user/git-maintenance@.service" &&
printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
test_cmp expect args &&
@@ -755,7 +853,10 @@ test_expect_success 'start and stop Linux/systemd maintenance' '
# stop does not unregister the repo
git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
- test_path_is_missing "systemd/user/git-maintenance@.timer" &&
+ for schedule in hourly daily weekly
+ do
+ test_path_is_missing "systemd/user/git-maintenance@$schedule.timer" || return 1
+ done &&
test_path_is_missing "systemd/user/git-maintenance@.service" &&
printf -- "--user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
@@ -838,4 +939,88 @@ test_expect_success 'register and unregister bare repo' '
)
'
+test_expect_success 'failed schedule prevents config change' '
+ git init --bare failcase &&
+
+ for scheduler in crontab launchctl schtasks systemctl
+ do
+ GIT_TEST_MAINT_SCHEDULER="$scheduler:false" &&
+ export GIT_TEST_MAINT_SCHEDULER &&
+ test_must_fail \
+ git -C failcase maintenance start &&
+ test_must_fail git -C failcase config maintenance.auto || return 1
+ done
+'
+
+test_expect_success '--no-detach causes maintenance to not run in background' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ # Prepare the repository such that git-maintenance(1) ends up
+ # outputting something.
+ test_commit something &&
+ git config set maintenance.gc.enabled false &&
+ git config set maintenance.loose-objects.enabled true &&
+ git config set maintenance.loose-objects.auto 1 &&
+ git config set maintenance.incremental-repack.enabled true &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+ git maintenance run --no-detach >out 2>&1 &&
+ ! test_region maintenance detach trace.txt
+ )
+'
+
+test_expect_success '--detach causes maintenance to run in background' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit something &&
+ git config set maintenance.gc.enabled false &&
+ git config set maintenance.loose-objects.enabled true &&
+ git config set maintenance.loose-objects.auto 1 &&
+ git config set maintenance.incremental-repack.enabled true &&
+
+ # The extra file descriptor gets inherited to the child
+ # process, and by reading stdout we thus essentially wait for
+ # that descriptor to get closed, which indicates that the child
+ # is done, too.
+ does_not_matter=$(GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+ git maintenance run --detach 9>&1) &&
+ test_region maintenance detach trace.txt
+ )
+'
+
+test_expect_success 'repacking loose objects is quiet' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit something &&
+ git config set maintenance.gc.enabled false &&
+ git config set maintenance.loose-objects.enabled true &&
+ git config set maintenance.loose-objects.auto 1 &&
+
+ git maintenance run --quiet >out 2>&1 &&
+ test_must_be_empty out
+ )
+'
+
+test_expect_success 'maintenance aborts with existing lock file' '
+ test_when_finished "rm -rf repo script" &&
+ mkdir script &&
+ write_script script/systemctl <<-\EOF &&
+ true
+ EOF
+
+ git init repo &&
+ : >repo/.git/objects/schedule.lock &&
+ test_must_fail env PATH="$PWD/script:$PATH" git -C repo maintenance start --scheduler=systemd 2>err &&
+ test_grep "Another scheduled git-maintenance(1) process seems to be running" err
+'
+
test_done
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
index 8bcd39e81b..731265541a 100755
--- a/t/t8003-blame-corner-cases.sh
+++ b/t/t8003-blame-corner-cases.sh
@@ -207,7 +207,7 @@ EOF
test_expect_success 'blame -L with invalid start' '
test_must_fail git blame -L5 tres 2>errors &&
- test_i18ngrep "has only 2 lines" errors
+ test_grep "has only 2 lines" errors
'
test_expect_success 'blame -L with invalid end' '
diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh
index 75da219ed1..81847ffb9a 100755
--- a/t/t8005-blame-i18n.sh
+++ b/t/t8005-blame-i18n.sh
@@ -1,8 +1,15 @@
#!/bin/sh
test_description='git blame encoding conversion'
+
. ./test-lib.sh
+if ! test_have_prereq ICONV
+then
+ skip_all='skipping blame i18n tests; iconv not available'
+ test_done
+fi
+
. "$TEST_DIRECTORY"/t8005/utf8.txt
. "$TEST_DIRECTORY"/t8005/euc-japan.txt
. "$TEST_DIRECTORY"/t8005/sjis.txt
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 7683515155..07a287ffd3 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git blame textconv support'
+
. ./test-lib.sh
find_blame() {
diff --git a/t/t8007-cat-file-textconv.sh b/t/t8007-cat-file-textconv.sh
index c8266f17f1..c3735fb50d 100755
--- a/t/t8007-cat-file-textconv.sh
+++ b/t/t8007-cat-file-textconv.sh
@@ -2,7 +2,6 @@
test_description='git cat-file textconv support'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >helper <<'EOF'
diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh
index ae4b579d24..c12a4196d6 100755
--- a/t/t8008-blame-formats.sh
+++ b/t/t8008-blame-formats.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='blame output in various formats on a simple case'
+
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t8009-blame-vs-topicbranches.sh b/t/t8009-blame-vs-topicbranches.sh
index 72596e38b2..c808b81962 100755
--- a/t/t8009-blame-vs-topicbranches.sh
+++ b/t/t8009-blame-vs-topicbranches.sh
@@ -1,6 +1,7 @@
#!/bin/sh
-test_description='blaming trough history with topic branches'
+test_description='blaming through history with topic branches'
+
. ./test-lib.sh
# Creates the history shown below. '*'s mark the first parent in the merges.
diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh
index ca04242ca0..b3be2aa387 100755
--- a/t/t8010-cat-file-filters.sh
+++ b/t/t8010-cat-file-filters.sh
@@ -2,7 +2,6 @@
test_description='git cat-file filters support'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup ' '
@@ -43,7 +42,7 @@ test_expect_success 'cat-file --textconv --path=<path> works' '
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" &&
git cat-file --textconv --path=hello.txt $sha1 >rot13 &&
- test uryyb = "$(cat rot13 | remove_cr)"
+ test uryyb = "$(remove_cr <rot13)"
'
test_expect_success '--path=<path> complains without --textconv/--filters' '
diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh
index bdda0c03fe..c66494f5ba 100755
--- a/t/t8011-blame-split-file.sh
+++ b/t/t8011-blame-split-file.sh
@@ -10,6 +10,7 @@ Note that we need to use "blame -C" to find the commit for all lines. We will
not bother testing that the non-C case fails to find it. That is how blame
behaves now, but it is not a property we want to make sure is retained.
'
+
. ./test-lib.sh
# help avoid typing and reading long strings of similar lines
diff --git a/t/t8013-blame-ignore-revs.sh b/t/t8013-blame-ignore-revs.sh
index b18633dee1..370b768149 100755
--- a/t/t8013-blame-ignore-revs.sh
+++ b/t/t8013-blame-ignore-revs.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='ignore revisions when blaming'
+
. ./test-lib.sh
# Creates:
@@ -25,11 +26,11 @@ test_expect_success setup '
git blame --line-porcelain file >blame_raw &&
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
git rev-parse X >expect &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
git rev-parse X >expect &&
test_cmp expect actual
'
@@ -53,11 +54,11 @@ do
test_expect_success "ignore_rev_changing_lines ($I)" '
git blame --line-porcelain --ignore-rev $I file >blame_raw &&
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
git rev-parse A >expect &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
git rev-parse B >expect &&
test_cmp expect actual
'
@@ -79,10 +80,10 @@ test_expect_success ignore_rev_adding_unblamable_lines '
git rev-parse Y >expect &&
git blame --line-porcelain file --ignore-rev Y >blame_raw &&
- grep -E "^[0-9a-f]+ [0-9]+ 3" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 3/s/ .*//p" blame_raw >actual &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 4" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 4/s/ .*//p" blame_raw >actual &&
test_cmp expect actual
'
@@ -92,11 +93,11 @@ test_expect_success ignore_revs_from_files '
git rev-parse Y >ignore_y &&
git blame --line-porcelain file --ignore-revs-file ignore_x --ignore-revs-file ignore_y >blame_raw &&
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
git rev-parse A >expect &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
git rev-parse B >expect &&
test_cmp expect actual
'
@@ -106,11 +107,11 @@ test_expect_success ignore_revs_from_configs_and_files '
git config --add blame.ignoreRevsFile ignore_x &&
git blame --line-porcelain file --ignore-revs-file ignore_y >blame_raw &&
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
git rev-parse A >expect &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
git rev-parse B >expect &&
test_cmp expect actual
'
@@ -121,22 +122,22 @@ test_expect_success override_ignore_revs_file '
git blame --line-porcelain file --ignore-revs-file "" --ignore-revs-file ignore_y >blame_raw &&
git rev-parse X >expect &&
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
test_cmp expect actual
'
test_expect_success bad_files_and_revs '
test_must_fail git blame file --ignore-rev NOREV 2>err &&
- test_i18ngrep "cannot find revision NOREV to ignore" err &&
+ test_grep "cannot find revision NOREV to ignore" err &&
test_must_fail git blame file --ignore-revs-file NOFILE 2>err &&
- test_i18ngrep "could not open.*: NOFILE" err &&
+ test_grep "could not open.*: NOFILE" err &&
echo NOREV >ignore_norev &&
test_must_fail git blame file --ignore-revs-file ignore_norev 2>err &&
- test_i18ngrep "invalid object name: NOREV" err
+ test_grep "invalid object name: NOREV" err
'
# For ignored revs that have added 'unblamable' lines, mark those lines with a
@@ -279,11 +280,11 @@ test_expect_success ignore_merge '
test_merge M B &&
git blame --line-porcelain file --ignore-rev M >blame_raw &&
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
git rev-parse B >expect &&
test_cmp expect actual &&
- grep -E "^[0-9a-f]+ [0-9]+ 9" blame_raw | sed -e "s/ .*//" >actual &&
+ sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 9/s/ .*//p" blame_raw >actual &&
git rev-parse C >expect &&
test_cmp expect actual
'
diff --git a/t/t8014-blame-ignore-fuzzy.sh b/t/t8014-blame-ignore-fuzzy.sh
index 0bd0341301..f5dcbd9e82 100755
--- a/t/t8014-blame-ignore-fuzzy.sh
+++ b/t/t8014-blame-ignore-fuzzy.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git blame ignore fuzzy heuristic'
+
. ./test-lib.sh
pick_author='s/^[0-9a-f^]* *(\([^ ]*\) .*/\1/'
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 263db3ad17..0c1af43f6f 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -4,7 +4,6 @@ test_description='git send-email'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# May be altered later in the test
@@ -371,7 +370,7 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'
--smtp-server="$(pwd)/fake.sendmail" \
--to=to@example.com \
$patches </dev/null 2>errors &&
- test_i18ngrep "tell me who you are" errors
+ test_grep "tell me who you are" errors
)
'
@@ -633,6 +632,25 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_cmp expect actual
'
+test_expect_success $PREREQ "--validate hook supports multiple addresses in arguments" '
+ hooks_path="$(pwd)/my-hooks" &&
+ test_config core.hooksPath "$hooks_path" &&
+ test_when_finished "rm my-hooks.ran" &&
+ test_must_fail git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com,abc@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --validate \
+ longline.patch 2>actual &&
+ 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> <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
@@ -1280,6 +1298,49 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' '
test_line_count = 1 msgfrom
'
+test_expect_success $PREREQ 'setup expect for cc list' "
+cat >expected-cc <<\EOF
+!recipient@example.com!
+!author@example.com!
+!one@example.com!
+!os@example.com!
+!odd_?=mail@example.com!
+!doug@example.com!
+!codev@example.com!
+!thor.au@example.com!
+EOF
+"
+
+test_expect_success $PREREQ 'cc list is sanitized' '
+ clean_fake_sendmail &&
+ test_commit weird_cc_body &&
+ test_when_finished "git reset --hard HEAD^" &&
+ git commit --amend -F - <<-EOF &&
+ Test Cc: sanitization.
+
+ Cc: Person, One <one@example.com>
+ Cc: Ronnie O${SQ}Sullivan <os@example.com>
+ Reviewed-by: Füñný Nâmé <odd_?=mail@example.com>
+ Reported-by: bugger on Jira
+ Reported-by: Douglas Reporter <doug@example.com> [from Jira profile]
+ BugID: 12345should-not-appear
+ Co-developed-by: "C. O. Developer" <codev@example.com>
+ Signed-off-by: A. U. Thor <thor.au@example.com>
+ EOF
+ git send-email -1 --to=recipient@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" >actual-show-all-headers &&
+ test_cmp expected-cc commandline1 &&
+ test_grep "^(body) Adding cc: \"Person, One\" <one@example.com>" actual-show-all-headers &&
+ test_grep "^(body) Adding cc: Ronnie O${SQ}Sullivan <os@example.com>" actual-show-all-headers &&
+ test_grep "^(body) Adding cc: =?UTF-8?q?F=C3=BC=C3=B1n=C3=BD=20N=C3=A2m=C3=A9?="\
+" <odd_?=mail@example.com>" actual-show-all-headers &&
+ test_grep "^(body) Ignoring Reported-by .* bugger on Jira" actual-show-all-headers &&
+ test_grep "^(body) Adding cc: Douglas Reporter <doug@example.com>" actual-show-all-headers &&
+ test_grep ! "12345should-not-appear" actual-show-all-headers &&
+ test_grep "^(body) Adding cc: \"C. O. Developer\" <codev@example.com>" actual-show-all-headers &&
+ test_grep "^(body) Adding cc: \"A. U. Thor\" <thor.au@example.com>" actual-show-all-headers
+'
+
test_expect_success $PREREQ 'sendemail.composeencoding works' '
clean_fake_sendmail &&
git config sendemail.composeencoding iso-8859-1 &&
@@ -2022,22 +2083,24 @@ test_dump_aliases '--dump-aliases mailrc format' \
'bob' \
'chloe' \
'eve' <<-\EOF
- alias alice Alice W Land <awol@example.com>
- alias eve Eve <eve@example.com>
- alias bob Robert Bobbyton <bob@example.com>
+ alias alice "Alice W Land <awol@example.com>"
+ alias eve "Eve <eve@example.com>"
+ alias bob "Robert Bobbyton <bob@example.com>"
alias chloe chloe@example.com
EOF
test_dump_aliases '--dump-aliases pine format' \
'pine' \
'alice' \
+ 'bcgrp' \
'bob' \
'chloe' \
'eve' <<-\EOF
- alice Alice W Land <awol@example.com>
- eve Eve <eve@example.com>
- bob Robert Bobbyton <bob@example.com>
+ alice Alice W Land awol@example.com Friend
+ eve Eve eve@example.com
+ bob Robert Bobbyton bob@example.com
chloe chloe@example.com
+ bcgrp (bob, chloe, Other <o@example.com>)
EOF
test_dump_aliases '--dump-aliases gnus format' \
@@ -2056,13 +2119,117 @@ test_expect_success '--dump-aliases must be used alone' '
test_must_fail git send-email --dump-aliases --to=janice@example.com -1 refs/heads/accounting
'
+test_translate_aliases () {
+ msg="$1" && shift &&
+ filetype="$1" && shift &&
+ aliases="$1" && shift &&
+ printf '%s\n' "$@" >expect &&
+ cat >.tmp-email-aliases &&
+ printf '%s\n' "$aliases" >aliases &&
+
+ test_expect_success $PREREQ "$msg" '
+ clean_fake_sendmail && rm -fr outdir &&
+ git config --replace-all sendemail.aliasesfile \
+ "$(pwd)/.tmp-email-aliases" &&
+ git config sendemail.aliasfiletype "$filetype" &&
+ git send-email --translate-aliases <aliases 2>errors >actual &&
+ test_cmp expect actual
+ '
+}
+
+test_translate_aliases '--translate-aliases sendmail format' \
+ 'sendmail' \
+ 'alice bcgrp' \
+ 'Alice W Land <awol@example.com>' \
+ 'Robert Bobbyton <bob@example.com>' \
+ 'chloe@example.com' \
+ 'Other <o@example.com>' <<-\EOF
+ alice: Alice W Land <awol@example.com>
+ bob: Robert Bobbyton <bob@example.com>
+ chloe: chloe@example.com
+ abgroup: alice, bob
+ bcgrp: bob, chloe, Other <o@example.com>
+ EOF
+
+test_translate_aliases '--translate-aliases mutt format' \
+ 'mutt' \
+ 'donald bob' \
+ 'Donald C Carlton <donc@example.com>' \
+ 'Robert Bobbyton <bob@example.com>' <<-\EOF
+ alias alice Alice W Land <awol@example.com>
+ alias donald Donald C Carlton <donc@example.com>
+ alias bob Robert Bobbyton <bob@example.com>
+ alias chloe chloe@example.com
+ EOF
+
+test_translate_aliases '--translate-aliases mailrc format' \
+ 'mailrc' \
+ 'chloe eve alice' \
+ 'chloe@example.com' \
+ 'Eve <eve@example.com>' \
+ 'Alice W Land <awol@example.com>' <<-\EOF
+ alias alice "Alice W Land <awol@example.com>"
+ alias eve "Eve <eve@example.com>"
+ alias bob "Robert Bobbyton <bob@example.com>"
+ alias chloe chloe@example.com
+ EOF
+
+test_translate_aliases '--translate-aliases pine format' \
+ 'pine' \
+ 'eve bob bcgrp' \
+ 'eve@example.com' \
+ 'bob@example.com' \
+ 'bob@example.com' \
+ 'chloe@example.com' \
+ 'Other <o@example.com>' <<-\EOF
+ alice Alice W Land awol@example.com Friend
+ eve Eve eve@example.com
+ bob Robert Bobbyton bob@example.com
+ chloe chloe@example.com
+ bcgrp (bob, chloe, Other <o@example.com>)
+ EOF
+
+test_translate_aliases '--translate-aliases gnus format' \
+ 'gnus' \
+ 'alice chloe eve' \
+ 'awol@example.com' \
+ 'chloe@example.com' \
+ 'eve@example.com' <<-\EOF
+ (define-mail-alias "alice" "awol@example.com")
+ (define-mail-alias "eve" "eve@example.com")
+ (define-mail-alias "bob" "bob@example.com")
+ (define-mail-alias "chloe" "chloe@example.com")
+ EOF
+
+test_expect_success $PREREQ '--translate-aliases passes valid addresses through' '
+ cat >expect <<-\EOF &&
+ Other <o@example.com>
+ EOF
+ cat >aliases <<-\EOF &&
+ Other <o@example.com>
+ EOF
+ git send-email --translate-aliases <aliases >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success $PREREQ '--translate-aliases passes unknown aliases through' '
+ cat >expect <<-\EOF &&
+ blargh
+ EOF
+ cat >aliases <<-\EOF &&
+ blargh
+ EOF
+ git send-email --translate-aliases <aliases >actual &&
+ test_cmp expect actual
+'
+
test_expect_success $PREREQ 'aliases and sendemail.identity' '
test_must_fail git \
-c sendemail.identity=cloud \
-c sendemail.aliasesfile=default-aliases \
-c sendemail.cloud.aliasesfile=cloud-aliases \
send-email -1 2>stderr &&
- test_i18ngrep "cloud-aliases" stderr
+ test_grep "cloud-aliases" stderr
'
test_sendmail_aliases () {
@@ -2317,6 +2484,128 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '
test_cmp expected-list actual-list
'
+test_expect_success $PREREQ 'mailmap support with --to' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --to=someone@example.org \
+ --mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap configuration' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --to=someone@example.org \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap.file configuration' '
+ clean_fake_sendmail &&
+ test_config sendemail.mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --to=someone@example.org \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap identity overrides configuration' '
+ clean_fake_sendmail &&
+ test_config sendemail.cloud.mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "false" &&
+ test_config sendemail.cloud.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --identity=cloud \
+ --to=someone@example.org \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ '--no-mailmap overrides configuration' '
+ clean_fake_sendmail &&
+ test_config sendemail.cloud.mailmap.file "mailmap.test" &&
+ test_config sendemail.mailmap "false" &&
+ test_config sendemail.cloud.mailmap "true" &&
+ cat >mailmap.test <<-EOF &&
+ Some Body <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --identity=cloud \
+ --to=someone@example.org \
+ --no-mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.org!$" commandline1
+'
+
+test_expect_success $PREREQ 'mailmap support in To header' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ cat >mailmap.test <<-EOF &&
+ <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 --to=someone@example.org >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'mailmap support in Cc header' '
+ clean_fake_sendmail &&
+ test_config mailmap.file "mailmap.test" &&
+ cat >mailmap.test <<-EOF &&
+ <someone@example.com> <someone@example.org>
+ EOF
+ git format-patch --stdout -1 --cc=someone@example.org >a.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --mailmap \
+ a.patch \
+ 2>errors >out &&
+ grep "^!someone@example\.com!$" commandline1
+'
+
test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
clean_fake_sendmail &&
PATH="$PWD:$PATH" \
@@ -2427,7 +2716,7 @@ test_expect_success $PREREQ 'invoke hook' '
--to=nobody@example.com \
--smtp-server="$(pwd)/../fake.sendmail" \
../another.patch 2>err &&
- test_i18ngrep "rejected by sendemail-validate hook" err
+ test_grep "rejected by sendemail-validate hook" err
)
'
@@ -2483,7 +2772,7 @@ test_expect_success $PREREQ 'test that sendmail config is rejected' '
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
HEAD^ 2>err &&
- test_i18ngrep "found configuration options for '"'"sendmail"'"'" err
+ test_grep "found configuration options for '"'"sendmail"'"'" err
'
test_expect_success $PREREQ 'test that sendmail config rejection is specific' '
@@ -2505,4 +2794,45 @@ test_expect_success $PREREQ 'test forbidSendmailVariables behavior override' '
HEAD^
'
+test_expect_success $PREREQ '--compose handles lowercase headers' '
+ write_script fake-editor <<-\EOF &&
+ sed "s/^[Ff][Rr][Oo][Mm]:.*/from: edited-from@example.com/" "$1" >"$1.tmp" &&
+ mv "$1.tmp" "$1"
+ EOF
+ clean_fake_sendmail &&
+ git send-email \
+ --compose \
+ --from="Example <from@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ HEAD^ &&
+ grep "From: edited-from@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose handles to headers' '
+ write_script fake-editor <<-\EOF &&
+ sed "s/^To: .*/&, edited-to@example.com/" <"$1" >"$1.tmp" &&
+ echo this is the body >>"$1.tmp" &&
+ mv "$1.tmp" "$1"
+ EOF
+ clean_fake_sendmail &&
+ GIT_SEND_EMAIL_NOTTY=1 \
+ git send-email \
+ --compose \
+ --from="Example <from@example.com>" \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ HEAD^ &&
+ # Check both that the cover letter used our modified "to" line,
+ # but also that it was picked up for the patch.
+ q_to_tab >expect <<-\EOF &&
+ To: nobody@example.com,
+ Qedited-to@example.com
+ EOF
+ grep -A1 "^To:" msgtxt1 >msgtxt1.to &&
+ test_cmp expect msgtxt1.to &&
+ grep -A1 "^To:" msgtxt2 >msgtxt2.to &&
+ test_cmp expect msgtxt2.to
+'
+
test_done
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index 6d3dbde3fe..7353815c11 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -195,4 +195,15 @@ EOF
test_cmp expected actual
'
+test_expect_success 'padding must be non-negative' '
+ cat >input <<\EOF &&
+1 2 3 4 5 6
+EOF
+ cat >expected <<\EOF &&
+fatal: --padding must be non-negative
+EOF
+ test_must_fail git column --mode=column --padding=-1 <input >actual 2>&1 &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index 14a704d0a8..85a5074b5e 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -2,7 +2,6 @@
test_description='help.autocorrect finding a match'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -65,7 +64,7 @@ test_expect_success 'autocorrect can be declined altogether' '
test_expect_success 'autocorrect works in work tree created from bare repo' '
git clone --bare . bare.git &&
git -C bare.git worktree add ../worktree &&
- git -C worktree -c help.autocorrect=immediate stauts
+ git -C worktree -c help.autocorrect=immediate status
'
test_done
diff --git a/t/t9004-example.sh b/t/t9004-example.sh
deleted file mode 100755
index 590aab0304..0000000000
--- a/t/t9004-example.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-test_description='check that example code compiles and runs'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_expect_success 'decorate' '
- test-tool example-decorate
-'
-
-test_done
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 52046e60d5..b2ee626b9a 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -21,32 +21,32 @@ a_empty_cr=
a_empty_crlf=
cd import
- cat >> kw.c <<\EOF
+ cat >>kw.c <<\EOF
/* Somebody prematurely put a keyword into this file */
/* $Id$ */
EOF
- printf "Hello\r\nWorld\r\n" > crlf
+ printf "Hello\r\nWorld\r\n" >crlf
a_crlf=$(git hash-object -w crlf)
- printf "Hello\rWorld\r" > cr
+ printf "Hello\rWorld\r" >cr
a_cr=$(git hash-object -w cr)
- printf "Hello\nWorld\n" > lf
+ printf "Hello\nWorld\n" >lf
a_lf=$(git hash-object -w lf)
- printf "Hello\r\nWorld" > ne_crlf
+ printf "Hello\r\nWorld" >ne_crlf
a_ne_crlf=$(git hash-object -w ne_crlf)
- printf "Hello\nWorld" > ne_lf
+ printf "Hello\nWorld" >ne_lf
a_ne_lf=$(git hash-object -w ne_lf)
- printf "Hello\rWorld" > ne_cr
+ printf "Hello\rWorld" >ne_cr
a_ne_cr=$(git hash-object -w ne_cr)
touch empty
a_empty=$(git hash-object -w empty)
- printf "\n" > empty_lf
+ printf "\n" >empty_lf
a_empty_lf=$(git hash-object -w empty_lf)
- printf "\r" > empty_cr
+ printf "\r" >empty_cr
a_empty_cr=$(git hash-object -w empty_cr)
- printf "\r\n" > empty_crlf
+ printf "\r\n" >empty_crlf
a_empty_crlf=$(git hash-object -w empty_crlf)
svn_cmd import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null
@@ -57,10 +57,10 @@ test_expect_success 'checkout working copy from svn' 'svn co "$svnrepo" test_wc'
test_expect_success 'setup some commits to svn' '
(
cd test_wc &&
- echo Greetings >> kw.c &&
+ echo Greetings >>kw.c &&
poke kw.c &&
svn_cmd commit -m "Not yet an Id" &&
- echo Hello world >> kw.c &&
+ echo Hello world >>kw.c &&
poke kw.c &&
svn_cmd commit -m "Modified file, but still not yet an Id" &&
svn_cmd propset svn:keywords Id kw.c &&
@@ -75,7 +75,7 @@ test_expect_success 'fetch revisions from svn' 'git svn fetch'
name='test svn:keywords ignoring'
test_expect_success "$name" \
'git checkout -b mybranch remotes/git-svn &&
- echo Hi again >> kw.c &&
+ echo Hi again >>kw.c &&
git commit -a -m "test keywords ignoring" &&
git svn set-tree remotes/git-svn..mybranch &&
git pull . remotes/git-svn'
@@ -106,8 +106,8 @@ done
cd test_wc
- printf '$Id$\rHello\rWorld\r' > cr
- printf '$Id$\rHello\rWorld' > ne_cr
+ printf '$Id$\rHello\rWorld\r' >cr
+ printf '$Id$\rHello\rWorld' >ne_cr
a_cr=$(printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin)
a_ne_cr=$(printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin)
test_expect_success 'Set CRLF on cr files' \
@@ -126,7 +126,7 @@ b_ne_cr="$(git hash-object ne_cr)"
test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'"
test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'"
-cat > show-ignore.expect <<\EOF
+cat >show-ignore.expect <<\EOF
# /
/no-such-file*
@@ -153,7 +153,7 @@ no-such-file*
' . &&
svn_cmd commit -m 'propset svn:ignore'
) &&
- git svn show-ignore > show-ignore.got &&
+ git svn show-ignore >show-ignore.got &&
cmp show-ignore.expect show-ignore.got
"
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 32317d6bca..e06538b1c8 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -27,7 +27,7 @@ cat << EOF
# 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/>.
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
#
EOF
}
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index 62de819a44..3b038c338f 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -17,32 +17,32 @@ test_expect_success 'setup svnrepo' '
test_expect_success 'basic clone' '
test ! -d trunk &&
git svn clone "$svnrepo"/project/trunk &&
- test -d trunk/.git/svn &&
- test -e trunk/foo &&
+ test_path_is_dir trunk/.git/svn &&
+ test_path_exists trunk/foo &&
rm -rf trunk
'
test_expect_success 'clone to target directory' '
test ! -d target &&
git svn clone "$svnrepo"/project/trunk target &&
- test -d target/.git/svn &&
- test -e target/foo &&
+ test_path_is_dir target/.git/svn &&
+ test_path_exists target/foo &&
rm -rf target
'
test_expect_success 'clone with --stdlayout' '
test ! -d project &&
git svn clone -s "$svnrepo"/project &&
- test -d project/.git/svn &&
- test -e project/foo &&
+ test_path_is_dir project/.git/svn &&
+ test_path_exists project/foo &&
rm -rf project
'
test_expect_success 'clone to target directory with --stdlayout' '
test ! -d target &&
git svn clone -s "$svnrepo"/project target &&
- test -d target/.git/svn &&
- test -e target/foo &&
+ test_path_is_dir target/.git/svn &&
+ test_path_exists target/foo &&
rm -rf target
'
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index a159ff96b7..a34fd46ecc 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -38,7 +38,7 @@ test_expect_success 'setup svnrepo' '
# SVN 1.7 will truncate "not-a%40{0]" to just "not-a".
# Look at what SVN wound up naming the branch and use that.
# Be sure to escape the @ if it shows up.
-non_reflog=$(svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/')
+non_reflog=$(svn_cmd ls "$svnrepo/pr ject/branches" | sed -ne '/not-a/ { s/\///; s/@/%40/; p; }')
test_expect_success 'test clone with funky branch names' '
git svn clone -s "$svnrepo/pr ject" project &&
diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh
index 185248a4cd..01e1e8a8f7 100755
--- a/t/t9129-git-svn-i18n-commitencoding.sh
+++ b/t/t9129-git-svn-i18n-commitencoding.sh
@@ -4,7 +4,6 @@
test_description='git svn honors i18n.commitEncoding in config'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
compare_git_head_with () {
diff --git a/t/t9133-git-svn-nested-git-repo.sh b/t/t9133-git-svn-nested-git-repo.sh
index d8d536269c..8ca24670ac 100755
--- a/t/t9133-git-svn-nested-git-repo.sh
+++ b/t/t9133-git-svn-nested-git-repo.sh
@@ -11,7 +11,7 @@ test_expect_success 'setup repo with a git repo inside it' '
(
cd s &&
git init &&
- test -f .git/HEAD &&
+ git symbolic-ref HEAD &&
> .git/a &&
echo a > a &&
svn_cmd add .git a &&
diff --git a/t/t9139-git-svn-non-utf8-commitencoding.sh b/t/t9139-git-svn-non-utf8-commitencoding.sh
index b7f756b2b7..22d80b0be2 100755
--- a/t/t9139-git-svn-non-utf8-commitencoding.sh
+++ b/t/t9139-git-svn-non-utf8-commitencoding.sh
@@ -4,7 +4,6 @@
test_description='git svn refuses to dcommit non-UTF8 messages'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
# ISO-2022-JP can pass for valid UTF-8, so skipping that in this test
diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh
index 09606f1b3c..926ac81439 100755
--- a/t/t9146-git-svn-empty-dirs.sh
+++ b/t/t9146-git-svn-empty-dirs.sh
@@ -20,11 +20,7 @@ test_expect_success 'empty directories exist' '
cd cloned &&
for i in a b c d d/e d/e/f "weird file name"
do
- if ! test -d "$i"
- then
- echo >&2 "$i does not exist" &&
- exit 1
- fi
+ test_path_is_dir "$i" || exit 1
done
)
'
@@ -37,11 +33,7 @@ test_expect_success 'option automkdirs set to false' '
git svn fetch &&
for i in a b c d d/e d/e/f "weird file name"
do
- if test -d "$i"
- then
- echo >&2 "$i exists" &&
- exit 1
- fi
+ test_path_is_missing "$i" || exit 1
done
)
'
@@ -52,7 +44,7 @@ test_expect_success 'more emptiness' '
test_expect_success 'git svn rebase creates empty directory' '
( cd cloned && git svn rebase ) &&
- test -d cloned/"! !"
+ test_path_is_dir cloned/"! !"
'
test_expect_success 'git svn mkdirs recreates empty directories' '
@@ -62,11 +54,7 @@ test_expect_success 'git svn mkdirs recreates empty directories' '
git svn mkdirs &&
for i in a b c d d/e d/e/f "weird file name" "! !"
do
- if ! test -d "$i"
- then
- echo >&2 "$i does not exist" &&
- exit 1
- fi
+ test_path_is_dir "$i" || exit 1
done
)
'
@@ -78,25 +66,13 @@ test_expect_success 'git svn mkdirs -r works' '
git svn mkdirs -r7 &&
for i in a b c d d/e d/e/f "weird file name"
do
- if ! test -d "$i"
- then
- echo >&2 "$i does not exist" &&
- exit 1
- fi
+ test_path_is_dir "$i" || exit 1
done &&
- if test -d "! !"
- then
- echo >&2 "$i should not exist" &&
- exit 1
- fi &&
+ test_path_is_missing "! !" || exit 1 &&
git svn mkdirs -r8 &&
- if ! test -d "! !"
- then
- echo >&2 "$i not exist" &&
- exit 1
- fi
+ test_path_is_dir "! !" || exit 1
)
'
@@ -114,11 +90,7 @@ test_expect_success 'empty directories in trunk exist' '
cd trunk &&
for i in a "weird file name"
do
- if ! test -d "$i"
- then
- echo >&2 "$i does not exist" &&
- exit 1
- fi
+ test_path_is_dir "$i" || exit 1
done
)
'
@@ -129,7 +101,7 @@ test_expect_success 'remove a top-level directory from svn' '
test_expect_success 'removed top-level directory does not exist' '
git svn clone "$svnrepo" removed &&
- test ! -e removed/d
+ test_path_is_missing removed/d
'
unhandled=.git/svn/refs/remotes/git-svn/unhandled.log
@@ -143,15 +115,11 @@ test_expect_success 'git svn gc-ed files work' '
svn_cmd mkdir -m gz "$svnrepo"/gz &&
git reset --hard $(git rev-list HEAD | tail -1) &&
git svn rebase &&
- test -f "$unhandled".gz &&
- test -f "$unhandled" &&
+ test_path_is_file "$unhandled".gz &&
+ test_path_is_file "$unhandled" &&
for i in a b c "weird file name" gz "! !"
do
- if ! test -d "$i"
- then
- echo >&2 "$i does not exist" &&
- exit 1
- fi
+ test_path_is_dir "$i" || exit 1
done
fi
)
diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh
index c8e6c0733f..d1dec89c3b 100755
--- a/t/t9164-git-svn-dcommit-concurrent.sh
+++ b/t/t9164-git-svn-dcommit-concurrent.sh
@@ -46,6 +46,14 @@ setup_hook()
"passed to setup_hook" >&2 ; return 1; }
echo "cnt=$skip_revs" > "$hook_type-counter"
rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks
+
+ # Subversion hooks run with an empty environment by default. We thus
+ # need to propagate PATH so that we can find executables.
+ cat >"$rawsvnrepo/conf/hooks-env" <<-EOF
+ [default]
+ PATH = ${PATH}
+ EOF
+
hook="$rawsvnrepo/hooks/$hook_type"
cat > "$hook" <<- 'EOF1'
#!/bin/sh
@@ -63,7 +71,6 @@ EOF1
if [ "$hook_type" = "pre-commit" ]; then
echo "echo 'commit disallowed' >&2; exit 1" >>"$hook"
else
- echo "PATH=\"$PATH\"; export PATH" >>"$hook"
echo "svnconf=\"$svnconf\"" >>"$hook"
cat >>"$hook" <<- 'EOF2'
cd work-auto-commits.svn
diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh
index 4432a30d10..027235d61a 100755
--- a/t/t9210-scalar.sh
+++ b/t/t9210-scalar.sh
@@ -154,7 +154,14 @@ test_expect_success 'scalar clone' '
test_cmp expect actual &&
test_path_is_missing 1/2 &&
- test_must_fail git rev-list --missing=print $second &&
+
+ # This relies on the fact that the presence of "--missing"
+ # on the command line forces lazy fetching off before
+ # "$second^{blob}" gets parsed. Without "^{blob}", a
+ # bare object name "$second" is taken into the queue and
+ # the command may not fail with a fixed "rev-list --missing".
+ test_must_fail git rev-list --missing=print "$second^{blob}" -- &&
+
git rev-list $second &&
git cat-file blob $second >actual &&
echo "second" >expect &&
@@ -162,6 +169,24 @@ test_expect_success 'scalar clone' '
)
'
+test_expect_success 'scalar clone --no-... opts' '
+ # Note: redirect stderr always to avoid having a verbose test
+ # run result in a difference in the --[no-]progress option.
+ GIT_TRACE2_EVENT="$(pwd)/no-opt-trace" scalar clone \
+ --no-tags --no-src \
+ "file://$(pwd)" no-opts --single-branch 2>/dev/null &&
+
+ test_subcommand git fetch --quiet --no-progress \
+ origin --no-tags <no-opt-trace &&
+ (
+ cd no-opts &&
+
+ test_cmp_config --no-tags remote.origin.tagopt &&
+ git for-each-ref --format="%(refname)" refs/tags/ >tags &&
+ test_line_count = 0 tags
+ )
+'
+
test_expect_success 'scalar reconfigure' '
git init one/src &&
scalar register one &&
@@ -169,8 +194,49 @@ test_expect_success 'scalar reconfigure' '
scalar reconfigure one &&
test true = "$(git -C one/src config core.preloadIndex)" &&
git -C one/src config core.preloadIndex false &&
- scalar reconfigure -a &&
- test true = "$(git -C one/src config core.preloadIndex)"
+ rm one/src/cron.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/reconfigure" scalar reconfigure -a &&
+ test_path_is_file one/src/cron.txt &&
+ test true = "$(git -C one/src config core.preloadIndex)" &&
+ test_subcommand git maintenance start <reconfigure
+'
+
+test_expect_success 'scalar reconfigure --all with includeIf.onbranch' '
+ repos="two three four" &&
+ for num in $repos
+ do
+ git init $num/src &&
+ scalar register $num/src &&
+ git -C $num/src config includeif."onbranch:foo".path something &&
+ git -C $num/src config core.preloadIndex false || return 1
+ done &&
+
+ scalar reconfigure --all &&
+
+ for num in $repos
+ do
+ test true = "$(git -C $num/src config core.preloadIndex)" || return 1
+ done
+'
+
+ test_expect_success 'scalar reconfigure --all with detached HEADs' '
+ repos="two three four" &&
+ for num in $repos
+ do
+ rm -rf $num/src &&
+ git init $num/src &&
+ scalar register $num/src &&
+ git -C $num/src config core.preloadIndex false &&
+ test_commit -C $num/src initial &&
+ git -C $num/src switch --detach HEAD || return 1
+ done &&
+
+ scalar reconfigure --all &&
+
+ for num in $repos
+ do
+ test true = "$(git -C $num/src config core.preloadIndex)" || return 1
+ done
'
test_expect_success '`reconfigure -a` removes stale config entries' '
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index ac237a1f90..27b2025f40 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -986,7 +986,7 @@ test_expect_success 'L: nested tree copy does not corrupt deltas' '
test_when_finished "git update-ref -d refs/heads/L2" &&
git fast-import <input &&
git ls-tree L2 g/b/ >tmp &&
- cat tmp | cut -f 2 >actual &&
+ cut -f 2 <tmp >actual &&
test_cmp expect actual &&
git fsck $(git rev-parse L2)
'
@@ -1059,30 +1059,33 @@ test_expect_success 'M: rename subdirectory to new subdirectory' '
compare_diff_raw expect actual
'
-test_expect_success 'M: rename root to subdirectory' '
- cat >input <<-INPUT_END &&
- commit refs/heads/M4
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- rename root
- COMMIT
+for root in '""' ''
+do
+ test_expect_success "M: rename root ($root) to subdirectory" '
+ cat >input <<-INPUT_END &&
+ commit refs/heads/M4
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ rename root
+ COMMIT
- from refs/heads/M2^0
- R "" sub
+ from refs/heads/M2^0
+ R $root sub
- INPUT_END
+ INPUT_END
- cat >expect <<-EOF &&
- :100644 100644 $oldf $oldf R100 file2/oldf sub/file2/oldf
- :100755 100755 $f4id $f4id R100 file4 sub/file4
- :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you
- :100755 100755 $f6id $f6id R100 newdir/exec.sh sub/newdir/exec.sh
- :100644 100644 $f5id $f5id R100 newdir/interesting sub/newdir/interesting
- EOF
- git fast-import <input &&
- git diff-tree -M -r M4^ M4 >actual &&
- compare_diff_raw expect actual
-'
+ cat >expect <<-EOF &&
+ :100644 100644 $oldf $oldf R100 file2/oldf sub/file2/oldf
+ :100755 100755 $f4id $f4id R100 file4 sub/file4
+ :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you
+ :100755 100755 $f6id $f6id R100 newdir/exec.sh sub/newdir/exec.sh
+ :100644 100644 $f5id $f5id R100 newdir/interesting sub/newdir/interesting
+ EOF
+ git fast-import <input &&
+ git diff-tree -M -r M4^ M4 >actual &&
+ compare_diff_raw expect actual
+ '
+done
###
### series N
@@ -1259,49 +1262,52 @@ test_expect_success PIPE 'N: empty directory reads as missing' '
test_cmp expect actual
'
-test_expect_success 'N: copy root directory by tree hash' '
- cat >expect <<-EOF &&
- :100755 000000 $newf $zero D file3/newf
- :100644 000000 $oldf $zero D file3/oldf
- EOF
- root=$(git rev-parse refs/heads/branch^0^{tree}) &&
- cat >input <<-INPUT_END &&
- commit refs/heads/N6
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- copy root directory by tree hash
- COMMIT
-
- from refs/heads/branch^0
- M 040000 $root ""
- INPUT_END
- git fast-import <input &&
- git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
- compare_diff_raw expect actual
-'
+for root in '""' ''
+do
+ test_expect_success "N: copy root ($root) by tree hash" '
+ cat >expect <<-EOF &&
+ :100755 000000 $newf $zero D file3/newf
+ :100644 000000 $oldf $zero D file3/oldf
+ EOF
+ root_tree=$(git rev-parse refs/heads/branch^0^{tree}) &&
+ cat >input <<-INPUT_END &&
+ commit refs/heads/N6
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy root directory by tree hash
+ COMMIT
-test_expect_success 'N: copy root by path' '
- cat >expect <<-EOF &&
- :100755 100755 $newf $newf C100 file2/newf oldroot/file2/newf
- :100644 100644 $oldf $oldf C100 file2/oldf oldroot/file2/oldf
- :100755 100755 $f4id $f4id C100 file4 oldroot/file4
- :100755 100755 $f6id $f6id C100 newdir/exec.sh oldroot/newdir/exec.sh
- :100644 100644 $f5id $f5id C100 newdir/interesting oldroot/newdir/interesting
- EOF
- cat >input <<-INPUT_END &&
- commit refs/heads/N-copy-root-path
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- copy root directory by (empty) path
- COMMIT
+ from refs/heads/branch^0
+ M 040000 $root_tree $root
+ INPUT_END
+ git fast-import <input &&
+ git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
+ compare_diff_raw expect actual
+ '
+
+ test_expect_success "N: copy root ($root) by path" '
+ cat >expect <<-EOF &&
+ :100755 100755 $newf $newf C100 file2/newf oldroot/file2/newf
+ :100644 100644 $oldf $oldf C100 file2/oldf oldroot/file2/oldf
+ :100755 100755 $f4id $f4id C100 file4 oldroot/file4
+ :100755 100755 $f6id $f6id C100 newdir/exec.sh oldroot/newdir/exec.sh
+ :100644 100644 $f5id $f5id C100 newdir/interesting oldroot/newdir/interesting
+ EOF
+ cat >input <<-INPUT_END &&
+ commit refs/heads/N-copy-root-path
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy root directory by (empty) path
+ COMMIT
- from refs/heads/branch^0
- C "" oldroot
- INPUT_END
- git fast-import <input &&
- git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
- compare_diff_raw expect actual
-'
+ from refs/heads/branch^0
+ C $root oldroot
+ INPUT_END
+ git fast-import <input &&
+ git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
+ compare_diff_raw expect actual
+ '
+done
test_expect_success 'N: delete directory by copying' '
cat >expect <<-\EOF &&
@@ -1431,98 +1437,102 @@ test_expect_success 'N: reject foo/ syntax in ls argument' '
INPUT_END
'
-test_expect_success 'N: copy to root by id and modify' '
- echo "hello, world" >expect.foo &&
- echo hello >expect.bar &&
- git fast-import <<-SETUP_END &&
- commit refs/heads/N7
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- hello, tree
- COMMIT
-
- deleteall
- M 644 inline foo/bar
- data <<EOF
- hello
- EOF
- SETUP_END
-
- tree=$(git rev-parse --verify N7:) &&
- git fast-import <<-INPUT_END &&
- commit refs/heads/N8
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- copy to root by id and modify
- COMMIT
+for root in '""' ''
+do
+ test_expect_success "N: copy to root ($root) by id and modify" '
+ echo "hello, world" >expect.foo &&
+ echo hello >expect.bar &&
+ git fast-import <<-SETUP_END &&
+ commit refs/heads/N7
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ hello, tree
+ COMMIT
- M 040000 $tree ""
- M 644 inline foo/foo
- data <<EOF
- hello, world
- EOF
- INPUT_END
- git show N8:foo/foo >actual.foo &&
- git show N8:foo/bar >actual.bar &&
- test_cmp expect.foo actual.foo &&
- test_cmp expect.bar actual.bar
-'
+ deleteall
+ M 644 inline foo/bar
+ data <<EOF
+ hello
+ EOF
+ SETUP_END
-test_expect_success 'N: extract subtree' '
- branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
- cat >input <<-INPUT_END &&
- commit refs/heads/N9
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- extract subtree branch:newdir
- COMMIT
+ tree=$(git rev-parse --verify N7:) &&
+ git fast-import <<-INPUT_END &&
+ commit refs/heads/N8
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy to root by id and modify
+ COMMIT
- M 040000 $branch ""
- C "newdir" ""
- INPUT_END
- git fast-import <input &&
- git diff --exit-code branch:newdir N9
-'
+ M 040000 $tree $root
+ M 644 inline foo/foo
+ data <<EOF
+ hello, world
+ EOF
+ INPUT_END
+ git show N8:foo/foo >actual.foo &&
+ git show N8:foo/bar >actual.bar &&
+ test_cmp expect.foo actual.foo &&
+ test_cmp expect.bar actual.bar
+ '
+
+ test_expect_success "N: extract subtree to the root ($root)" '
+ branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
+ cat >input <<-INPUT_END &&
+ commit refs/heads/N9
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ extract subtree branch:newdir
+ COMMIT
-test_expect_success 'N: modify subtree, extract it, and modify again' '
- echo hello >expect.baz &&
- echo hello, world >expect.qux &&
- git fast-import <<-SETUP_END &&
- commit refs/heads/N10
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- hello, tree
- COMMIT
+ M 040000 $branch $root
+ C "newdir" $root
+ INPUT_END
+ git fast-import <input &&
+ git diff --exit-code branch:newdir N9
+ '
+
+ test_expect_success "N: modify subtree, extract it to the root ($root), and modify again" '
+ echo hello >expect.baz &&
+ echo hello, world >expect.qux &&
+ git fast-import <<-SETUP_END &&
+ commit refs/heads/N10
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ hello, tree
+ COMMIT
- deleteall
- M 644 inline foo/bar/baz
- data <<EOF
- hello
- EOF
- SETUP_END
+ deleteall
+ M 644 inline foo/bar/baz
+ data <<EOF
+ hello
+ EOF
+ SETUP_END
- tree=$(git rev-parse --verify N10:) &&
- git fast-import <<-INPUT_END &&
- commit refs/heads/N11
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- copy to root by id and modify
- COMMIT
+ tree=$(git rev-parse --verify N10:) &&
+ git fast-import <<-INPUT_END &&
+ commit refs/heads/N11
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy to root by id and modify
+ COMMIT
- M 040000 $tree ""
- M 100644 inline foo/bar/qux
- data <<EOF
- hello, world
- EOF
- R "foo" ""
- C "bar/qux" "bar/quux"
- INPUT_END
- git show N11:bar/baz >actual.baz &&
- git show N11:bar/qux >actual.qux &&
- git show N11:bar/quux >actual.quux &&
- test_cmp expect.baz actual.baz &&
- test_cmp expect.qux actual.qux &&
- test_cmp expect.qux actual.quux'
+ M 040000 $tree $root
+ M 100644 inline foo/bar/qux
+ data <<EOF
+ hello, world
+ EOF
+ R "foo" $root
+ C "bar/qux" "bar/quux"
+ INPUT_END
+ git show N11:bar/baz >actual.baz &&
+ git show N11:bar/qux >actual.qux &&
+ git show N11:bar/quux >actual.quux &&
+ test_cmp expect.baz actual.baz &&
+ test_cmp expect.qux actual.qux &&
+ test_cmp expect.qux actual.quux
+ '
+done
###
### series O
@@ -2007,12 +2017,11 @@ test_expect_success 'Q: verify first notes commit' '
'
test_expect_success 'Q: verify first notes tree' '
- cat >expect.unsorted <<-EOF &&
+ sort >expect <<-EOF &&
100644 blob $commit1
100644 blob $commit2
100644 blob $commit3
EOF
- cat expect.unsorted | sort >expect &&
git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]* / /" >actual &&
test_cmp expect actual
'
@@ -2048,12 +2057,11 @@ test_expect_success 'Q: verify second notes commit' '
'
test_expect_success 'Q: verify second notes tree' '
- cat >expect.unsorted <<-EOF &&
+ sort >expect <<-EOF &&
100644 blob $commit1
100644 blob $commit2
100644 blob $commit3
EOF
- cat expect.unsorted | sort >expect &&
git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]* / /" >actual &&
test_cmp expect actual
'
@@ -2088,10 +2096,9 @@ test_expect_success 'Q: verify third notes commit' '
'
test_expect_success 'Q: verify third notes tree' '
- cat >expect.unsorted <<-EOF &&
+ sort >expect <<-EOF &&
100644 blob $commit1
EOF
- cat expect.unsorted | sort >expect &&
git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]* / /" >actual &&
test_cmp expect actual
'
@@ -2115,10 +2122,9 @@ test_expect_success 'Q: verify fourth notes commit' '
'
test_expect_success 'Q: verify fourth notes tree' '
- cat >expect.unsorted <<-EOF &&
+ sort >expect <<-EOF &&
100644 blob $commit2
EOF
- cat expect.unsorted | sort >expect &&
git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]* / /" >actual &&
test_cmp expect actual
'
@@ -2146,6 +2152,7 @@ test_expect_success 'Q: deny note on empty branch' '
EOF
test_must_fail git fast-import <input
'
+
###
### series R (feature and option)
###
@@ -2794,7 +2801,7 @@ test_expect_success 'R: blob appears only once' '
'
###
-### series S
+### series S (mark and path parsing)
###
#
# Make sure missing spaces and EOLs after mark references
@@ -2879,7 +2886,7 @@ test_expect_success 'S: filemodify with garbage after mark must fail' '
COMMIT
M 100644 :403x hello.c
EOF
- test_i18ngrep "space after mark" err
+ test_grep "space after mark" err
'
# inline is misspelled; fast-import thinks it is some unknown dataref
@@ -2895,7 +2902,7 @@ test_expect_success 'S: filemodify with garbage after inline must fail' '
inline
BLOB
EOF
- test_i18ngrep "nvalid dataref" err
+ test_grep "nvalid dataref" err
'
test_expect_success 'S: filemodify with garbage after sha1 must fail' '
@@ -2908,7 +2915,7 @@ test_expect_success 'S: filemodify with garbage after sha1 must fail' '
COMMIT
M 100644 ${sha1}x hello.c
EOF
- test_i18ngrep "space after SHA1" err
+ test_grep "space after SHA1" err
'
#
@@ -2923,7 +2930,7 @@ test_expect_success 'S: notemodify with garbage after mark dataref must fail' '
COMMIT
N :202x :302
EOF
- test_i18ngrep "space after mark" err
+ test_grep "space after mark" err
'
test_expect_success 'S: notemodify with garbage after inline dataref must fail' '
@@ -2938,7 +2945,7 @@ test_expect_success 'S: notemodify with garbage after inline dataref must fail'
note blob
BLOB
EOF
- test_i18ngrep "nvalid dataref" err
+ test_grep "nvalid dataref" err
'
test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
@@ -2951,7 +2958,7 @@ test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
COMMIT
N ${sha1}x :302
EOF
- test_i18ngrep "space after SHA1" err
+ test_grep "space after SHA1" err
'
#
@@ -2966,7 +2973,7 @@ test_expect_success 'S: notemodify with garbage after mark commit-ish must fail'
COMMIT
N :202 :302x
EOF
- test_i18ngrep "after mark" err
+ test_grep "after mark" err
'
#
@@ -2999,7 +3006,7 @@ test_expect_success 'S: from with garbage after mark must fail' '
EOF
# now evaluate the error
- test_i18ngrep "after mark" err
+ test_grep "after mark" err
'
@@ -3018,7 +3025,7 @@ test_expect_success 'S: merge with garbage after mark must fail' '
merge :303x
M 100644 :403 hello.c
EOF
- test_i18ngrep "after mark" err
+ test_grep "after mark" err
'
#
@@ -3033,7 +3040,7 @@ test_expect_success 'S: tag with garbage after mark must fail' '
tag S
TAG
EOF
- test_i18ngrep "after mark" err
+ test_grep "after mark" err
'
#
@@ -3043,7 +3050,7 @@ test_expect_success 'S: cat-blob with garbage after mark must fail' '
test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
cat-blob :403x
EOF
- test_i18ngrep "after mark" err
+ test_grep "after mark" err
'
#
@@ -3053,7 +3060,7 @@ test_expect_success 'S: ls with garbage after mark must fail' '
test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
ls :302x hello.c
EOF
- test_i18ngrep "space after mark" err
+ test_grep "space after mark" err
'
test_expect_success 'S: ls with garbage after sha1 must fail' '
@@ -3061,24 +3068,286 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
ls ${sha1}x hello.c
EOF
- test_i18ngrep "space after tree-ish" err
+ test_grep "space after tree-ish" err
'
+#
+# Path parsing
+#
+# There are two sorts of ways a path can be parsed, depending on whether it is
+# the last field on the line. Additionally, ls without a <dataref> has a special
+# case. Test every occurrence of <path> in the grammar against every error case.
+# Paths for the root (empty strings) are tested elsewhere.
+#
+
+#
+# Valid paths at the end of a line: filemodify, filedelete, filecopy (dest),
+# filerename (dest), and ls.
+#
+# commit :301 from root -- modify hello.c (for setup)
+# commit :302 from :301 -- modify $path
+# commit :303 from :302 -- delete $path
+# commit :304 from :301 -- copy hello.c $path
+# commit :305 from :301 -- rename hello.c $path
+# ls :305 $path
+#
+test_path_eol_success () {
+ local test="$1" path="$2" unquoted_path="$3"
+ test_expect_success "S: paths at EOL with $test must work" '
+ test_when_finished "git branch -D S-path-eol" &&
+
+ git fast-import --export-marks=marks.out <<-EOF >out 2>err &&
+ blob
+ mark :401
+ data <<BLOB
+ hello world
+ BLOB
+
+ blob
+ mark :402
+ data <<BLOB
+ hallo welt
+ BLOB
+
+ commit refs/heads/S-path-eol
+ mark :301
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ initial commit
+ COMMIT
+ M 100644 :401 hello.c
+
+ commit refs/heads/S-path-eol
+ mark :302
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit filemodify
+ COMMIT
+ from :301
+ M 100644 :402 $path
+
+ commit refs/heads/S-path-eol
+ mark :303
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit filedelete
+ COMMIT
+ from :302
+ D $path
+
+ commit refs/heads/S-path-eol
+ mark :304
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit filecopy dest
+ COMMIT
+ from :301
+ C hello.c $path
+
+ commit refs/heads/S-path-eol
+ mark :305
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit filerename dest
+ COMMIT
+ from :301
+ R hello.c $path
+
+ ls :305 $path
+ EOF
+
+ commit_m=$(grep :302 marks.out | cut -d\ -f2) &&
+ commit_d=$(grep :303 marks.out | cut -d\ -f2) &&
+ commit_c=$(grep :304 marks.out | cut -d\ -f2) &&
+ commit_r=$(grep :305 marks.out | cut -d\ -f2) &&
+ blob1=$(grep :401 marks.out | cut -d\ -f2) &&
+ blob2=$(grep :402 marks.out | cut -d\ -f2) &&
+
+ (
+ printf "100644 blob $blob2\t$unquoted_path\n" &&
+ printf "100644 blob $blob1\thello.c\n"
+ ) | sort >tree_m.exp &&
+ git ls-tree $commit_m | sort >tree_m.out &&
+ test_cmp tree_m.exp tree_m.out &&
+
+ printf "100644 blob $blob1\thello.c\n" >tree_d.exp &&
+ git ls-tree $commit_d >tree_d.out &&
+ test_cmp tree_d.exp tree_d.out &&
+
+ (
+ printf "100644 blob $blob1\t$unquoted_path\n" &&
+ printf "100644 blob $blob1\thello.c\n"
+ ) | sort >tree_c.exp &&
+ git ls-tree $commit_c | sort >tree_c.out &&
+ test_cmp tree_c.exp tree_c.out &&
+
+ printf "100644 blob $blob1\t$unquoted_path\n" >tree_r.exp &&
+ git ls-tree $commit_r >tree_r.out &&
+ test_cmp tree_r.exp tree_r.out &&
+
+ test_cmp out tree_r.exp
+ '
+}
+
+test_path_eol_success 'quoted spaces' '" hello world.c "' ' hello world.c '
+test_path_eol_success 'unquoted spaces' ' hello world.c ' ' hello world.c '
+test_path_eol_success 'octal escapes' '"\150\151\056\143"' 'hi.c'
+
+#
+# Valid paths before a space: filecopy (source) and filerename (source).
+#
+# commit :301 from root -- modify $path (for setup)
+# commit :302 from :301 -- copy $path hello2.c
+# commit :303 from :301 -- rename $path hello2.c
+#
+test_path_space_success () {
+ local test="$1" path="$2" unquoted_path="$3"
+ test_expect_success "S: paths before space with $test must work" '
+ test_when_finished "git branch -D S-path-space" &&
+
+ git fast-import --export-marks=marks.out <<-EOF 2>err &&
+ blob
+ mark :401
+ data <<BLOB
+ hello world
+ BLOB
+
+ commit refs/heads/S-path-space
+ mark :301
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ initial commit
+ COMMIT
+ M 100644 :401 $path
+
+ commit refs/heads/S-path-space
+ mark :302
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit filecopy source
+ COMMIT
+ from :301
+ C $path hello2.c
+
+ commit refs/heads/S-path-space
+ mark :303
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit filerename source
+ COMMIT
+ from :301
+ R $path hello2.c
+
+ EOF
+
+ commit_c=$(grep :302 marks.out | cut -d\ -f2) &&
+ commit_r=$(grep :303 marks.out | cut -d\ -f2) &&
+ blob=$(grep :401 marks.out | cut -d\ -f2) &&
+
+ (
+ printf "100644 blob $blob\t$unquoted_path\n" &&
+ printf "100644 blob $blob\thello2.c\n"
+ ) | sort >tree_c.exp &&
+ git ls-tree $commit_c | sort >tree_c.out &&
+ test_cmp tree_c.exp tree_c.out &&
+
+ printf "100644 blob $blob\thello2.c\n" >tree_r.exp &&
+ git ls-tree $commit_r >tree_r.out &&
+ test_cmp tree_r.exp tree_r.out
+ '
+}
+
+test_path_space_success 'quoted spaces' '" hello world.c "' ' hello world.c '
+test_path_space_success 'no unquoted spaces' 'hello_world.c' 'hello_world.c'
+test_path_space_success 'octal escapes' '"\150\151\056\143"' 'hi.c'
+
+#
+# Test a single commit change with an invalid path. Run it with all occurrences
+# of <path> in the grammar against all error kinds.
+#
+test_path_fail () {
+ local change="$1" what="$2" prefix="$3" path="$4" suffix="$5" err_grep="$6"
+ test_expect_success "S: $change with $what must fail" '
+ test_must_fail git fast-import <<-EOF 2>err &&
+ blob
+ mark :1
+ data <<BLOB
+ hello world
+ BLOB
+
+ commit refs/heads/S-path-fail
+ mark :2
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit setup
+ COMMIT
+ M 100644 :1 hello.c
+
+ commit refs/heads/S-path-fail
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ commit with bad path
+ COMMIT
+ from :2
+ $prefix$path$suffix
+ EOF
+
+ test_grep "$err_grep" err
+ '
+}
+
+test_path_base_fail () {
+ local change="$1" prefix="$2" field="$3" suffix="$4"
+ test_path_fail "$change" 'unclosed " in '"$field" "$prefix" '"hello.c' "$suffix" "Invalid $field"
+ test_path_fail "$change" "invalid escape in quoted $field" "$prefix" '"hello\xff"' "$suffix" "Invalid $field"
+ test_path_fail "$change" "escaped NUL in quoted $field" "$prefix" '"hello\000"' "$suffix" "NUL in $field"
+}
+test_path_eol_quoted_fail () {
+ local change="$1" prefix="$2" field="$3"
+ test_path_base_fail "$change" "$prefix" "$field" ''
+ test_path_fail "$change" "garbage after quoted $field" "$prefix" '"hello.c"' 'x' "Garbage after $field"
+ test_path_fail "$change" "space after quoted $field" "$prefix" '"hello.c"' ' ' "Garbage after $field"
+}
+test_path_eol_fail () {
+ local change="$1" prefix="$2" field="$3"
+ test_path_eol_quoted_fail "$change" "$prefix" "$field"
+}
+test_path_space_fail () {
+ local change="$1" prefix="$2" field="$3"
+ test_path_base_fail "$change" "$prefix" "$field" ' world.c'
+ test_path_fail "$change" "missing space after quoted $field" "$prefix" '"hello.c"' 'x world.c' "Missing space after $field"
+ test_path_fail "$change" "missing space after unquoted $field" "$prefix" 'hello.c' '' "Missing space after $field"
+}
+
+test_path_eol_fail filemodify 'M 100644 :1 ' path
+test_path_eol_fail filedelete 'D ' path
+test_path_space_fail filecopy 'C ' source
+test_path_eol_fail filecopy 'C hello.c ' dest
+test_path_space_fail filerename 'R ' source
+test_path_eol_fail filerename 'R hello.c ' dest
+test_path_eol_fail 'ls (in commit)' 'ls :2 ' path
+
+# When 'ls' has no <dataref>, the <path> must be quoted.
+test_path_eol_quoted_fail 'ls (without dataref in commit)' 'ls ' path
+
###
### series T (ls)
###
# Setup is carried over from series S.
-test_expect_success 'T: ls root tree' '
- sed -e "s/Z\$//" >expect <<-EOF &&
- 040000 tree $(git rev-parse S^{tree}) Z
- EOF
- sha1=$(git rev-parse --verify S) &&
- git fast-import --import-marks=marks <<-EOF >actual &&
- ls $sha1 ""
- EOF
- test_cmp expect actual
-'
+for root in '""' ''
+do
+ test_expect_success "T: ls root ($root) tree" '
+ sed -e "s/Z\$//" >expect <<-EOF &&
+ 040000 tree $(git rev-parse S^{tree}) Z
+ EOF
+ sha1=$(git rev-parse --verify S) &&
+ git fast-import --import-marks=marks <<-EOF >actual &&
+ ls $sha1 $root
+ EOF
+ test_cmp expect actual
+ '
+done
test_expect_success 'T: delete branch' '
git branch to-delete &&
@@ -3180,30 +3449,33 @@ test_expect_success 'U: validate directory delete result' '
compare_diff_raw expect actual
'
-test_expect_success 'U: filedelete root succeeds' '
- cat >input <<-INPUT_END &&
- commit refs/heads/U
- committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
- data <<COMMIT
- must succeed
- COMMIT
- from refs/heads/U^0
- D ""
+for root in '""' ''
+do
+ test_expect_success "U: filedelete root ($root) succeeds" '
+ cat >input <<-INPUT_END &&
+ commit refs/heads/U-delete-root
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ must succeed
+ COMMIT
+ from refs/heads/U^0
+ D $root
- INPUT_END
+ INPUT_END
- git fast-import <input
-'
+ git fast-import <input
+ '
-test_expect_success 'U: validate root delete result' '
- cat >expect <<-EOF &&
- :100644 000000 $f7id $ZERO_OID D hello.c
- EOF
+ test_expect_success "U: validate root ($root) delete result" '
+ cat >expect <<-EOF &&
+ :100644 000000 $f7id $ZERO_OID D hello.c
+ EOF
- git diff-tree -M -r U^1 U >actual &&
+ git diff-tree -M -r U U-delete-root >actual &&
- compare_diff_raw expect actual
-'
+ compare_diff_raw expect actual
+ '
+done
###
### series V (checkpoint)
@@ -3403,7 +3675,7 @@ test_expect_success !MINGW 'W: get-mark & empty orphan commit with erroneous thi
### series X (other new features)
###
-test_expect_success 'X: handling encoding' '
+test_expect_success ICONV 'X: handling encoding' '
test_tick &&
cat >input <<-INPUT_END &&
commit refs/heads/encoding
@@ -3419,6 +3691,34 @@ test_expect_success 'X: handling encoding' '
git log -1 --format=%B encoding | grep $(printf "\317\200")
'
+test_expect_success 'X: replace ref that becomes useless is removed' '
+ git init -qb main testrepo &&
+ cd testrepo &&
+ (
+ test_commit test &&
+
+ test_commit msg somename content &&
+
+ git mv somename othername &&
+ NEW_TREE=$(git write-tree) &&
+ MSG="$(git log -1 --format=%B HEAD)" &&
+ NEW_COMMIT=$(git commit-tree -p HEAD^1 -m "$MSG" $NEW_TREE) &&
+ git replace main $NEW_COMMIT &&
+
+ echo more >>othername &&
+ git add othername &&
+ git commit -qm more &&
+
+ git fast-export --all >tmp &&
+ sed -e s/othername/somename/ tmp >tmp2 &&
+ git fast-import --force <tmp2 2>msgs &&
+
+ grep "Dropping.*since it would point to itself" msgs &&
+ git show-ref >refs &&
+ ! grep refs/replace refs
+ )
+'
+
###
### series Y (submodules and hash algorithms)
###
diff --git a/t/t9301-fast-import-notes.sh b/t/t9301-fast-import-notes.sh
index 58413221e6..1ae4d7c0d3 100755
--- a/t/t9301-fast-import-notes.sh
+++ b/t/t9301-fast-import-notes.sh
@@ -7,7 +7,6 @@ test_description='test git fast-import of notes objects'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t9302-fast-import-unpack-limit.sh b/t/t9302-fast-import-unpack-limit.sh
index d8b1f9442e..ec8c8652c6 100755
--- a/t/t9302-fast-import-unpack-limit.sh
+++ b/t/t9302-fast-import-unpack-limit.sh
@@ -1,7 +1,6 @@
#!/bin/sh
test_description='test git fast-import unpack limit'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create loose objects on import' '
diff --git a/t/t9303-fast-import-compression.sh b/t/t9303-fast-import-compression.sh
index 4f5bf40587..f15c8c0213 100755
--- a/t/t9303-fast-import-compression.sh
+++ b/t/t9303-fast-import-compression.sh
@@ -2,7 +2,6 @@
test_description='compression setting of fast-import utility'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
import_large () {
diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh
index 410a871c52..6c50adca00 100755
--- a/t/t9304-fast-import-marks.sh
+++ b/t/t9304-fast-import-marks.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='test exotic situations with marks'
+
. ./test-lib.sh
test_expect_success 'setup dump of basic history' '
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 26c25c0eb2..aa33791b77 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -124,7 +124,7 @@ test_expect_success 'fast-export --show-original-ids | git fast-import' '
test $MUSS = $(git rev-parse --verify refs/tags/muss)
'
-test_expect_success 'reencoding iso-8859-7' '
+test_expect_success ICONV 'reencoding iso-8859-7' '
test_when_finished "git reset --hard HEAD~1" &&
test_config i18n.commitencoding iso-8859-7 &&
@@ -236,7 +236,7 @@ EOF
test_expect_success 'set up faked signed tag' '
- cat signed-tag-import | git fast-import
+ git fast-import <signed-tag-import
'
@@ -420,7 +420,7 @@ M 100644 :1 there
EOF
-test_expect_success 'dropping tag of filtered out object' '
+test_expect_success ICONV 'dropping tag of filtered out object' '
(
cd limit-by-paths &&
git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
@@ -437,7 +437,7 @@ msg
EOF
-test_expect_success 'rewriting tag of filtered out object' '
+test_expect_success ICONV 'rewriting tag of filtered out object' '
(
cd limit-by-paths &&
git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
@@ -537,7 +537,7 @@ test_expect_success 'full-tree re-shows unmodified files' '
test_expect_success 'set-up a few more tags for tag export tests' '
git checkout -f main &&
- HEAD_TREE=$(git show -s --pretty=raw HEAD | grep tree | sed "s/tree //") &&
+ HEAD_TREE=$(git show -s --pretty=raw HEAD | sed -n "/tree/s/tree //p") &&
git tag tree_tag -m "tagging a tree" $HEAD_TREE &&
git tag -a tree_tag-obj -m "tagging a tree" $HEAD_TREE &&
git tag tag-obj_tag -m "tagging a tag" tree_tag-obj &&
@@ -666,7 +666,7 @@ M 100644 :13 file
EOF
-test_expect_success 'avoid uninteresting refs' '
+test_expect_success ICONV 'avoid uninteresting refs' '
> tmp-marks &&
git fast-export --import-marks=tmp-marks \
--export-marks=tmp-marks main > /dev/null &&
@@ -685,7 +685,7 @@ from :14
EOF
-test_expect_success 'refs are updated even if no commits need to be exported' '
+test_expect_success ICONV 'refs are updated even if no commits need to be exported' '
> tmp-marks &&
git fast-export --import-marks=tmp-marks \
--export-marks=tmp-marks main > /dev/null &&
@@ -791,4 +791,14 @@ test_expect_success 'fast-export --first-parent outputs all revisions output by
)
'
+test_expect_success 'fast-export handles --end-of-options' '
+ git update-ref refs/heads/nodash HEAD &&
+ git update-ref refs/heads/--dashes HEAD &&
+ git fast-export --end-of-options nodash >expect &&
+ git fast-export --end-of-options --dashes >actual.raw &&
+ # fix up lines which mention the ref for comparison
+ sed s/--dashes/nodash/ <actual.raw >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 003c0b61d0..e499c7f955 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -117,12 +117,12 @@ END VERIFICATION REQUEST
EOF
test_expect_success 'pserver authentication' '
- cat request-anonymous | git-cvsserver pserver >log 2>&1 &&
+ git-cvsserver pserver <request-anonymous >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
+ if git-cvsserver pserver <request-git >log 2>&1
then
false
else
@@ -132,17 +132,17 @@ test_expect_success 'pserver authentication failure (non-anonymous user)' '
'
test_expect_success 'pserver authentication success (non-anonymous user with password)' '
- cat login-git-ok | git-cvsserver pserver >log 2>&1 &&
+ git-cvsserver pserver <login-git-ok >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 &&
+ git-cvsserver pserver <login-anonymous >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
+ if git-cvsserver pserver <login-git >log 2>&1
then
false
else
@@ -172,7 +172,7 @@ Root $WORKDIR
EOF
test_expect_success 'req_Root failure (relative pathname)' '
- if cat request-relative | git-cvsserver pserver >log 2>&1
+ if git-cvsserver pserver <request-relative >log 2>&1
then
echo unexpected success
false
@@ -183,28 +183,26 @@ test_expect_success 'req_Root failure (relative pathname)' '
'
test_expect_success 'req_Root failure (conflicting roots)' '
- cat request-conflict | git-cvsserver pserver >log 2>&1 &&
+ git-cvsserver pserver <request-conflict >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 &&
+ git-cvsserver --strict-paths pserver "$SERVERDIR" <request-anonymous >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
+ ! git-cvsserver --strict-paths pserver "$WORKDIR" <request-anonymous >log 2>&1
'
test_expect_success 'req_Root (w/o strict-paths)' '
- cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 &&
+ git-cvsserver pserver "$WORKDIR/" <request-anonymous >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
+ ! git-cvsserver pserver "$WORKDIR/gitcvs" <request-anonymous >log 2>&1
'
cat >request-base <<EOF
@@ -217,27 +215,26 @@ 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 &&
+ git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" <request-base >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
+ ! git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" <request-anonymous >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 &&
+ git-cvsserver --export-all pserver "$WORKDIR" <request-anonymous >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)'
+ ! (git-cvsserver --export-all pserver <request-anonymous >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 &&
+ git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" <request-base >log 2>&1 &&
sed -ne \$p log | grep "^I LOVE YOU\$"
'
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 0333065d4d..7679780fb8 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -627,6 +627,7 @@ test_expect_success \
test_expect_success 'setup' '
version=$(git config core.repositoryformatversion) &&
algo=$(test_might_fail git config extensions.objectformat) &&
+ refstorage=$(test_might_fail git config extensions.refstorage) &&
cat >.git/config <<-\EOF &&
# testing noval and alternate separator
[gitweb]
@@ -637,6 +638,10 @@ test_expect_success 'setup' '
if test -n "$algo"
then
git config extensions.objectformat "$algo"
+ fi &&
+ if test -n "$refstorage"
+ then
+ git config extensions.refstorage "$refstorage"
fi
'
diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh
index c900231079..32814e75df 100755
--- a/t/t9501-gitweb-standalone-http-status.sh
+++ b/t/t9501-gitweb-standalone-http-status.sh
@@ -13,7 +13,6 @@ code and message.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gitweb.sh
#
diff --git a/t/t9603-cvsimport-patchsets.sh b/t/t9603-cvsimport-patchsets.sh
index 19f38f78f2..1ee966c256 100755
--- a/t/t9603-cvsimport-patchsets.sh
+++ b/t/t9603-cvsimport-patchsets.sh
@@ -12,6 +12,7 @@
# bug.
test_description='git cvsimport testing for correct patchset estimation'
+
. ./lib-cvs.sh
setup_cvs_test_repository t9603
diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh
index 2ff4aa932d..57a3bef2ec 100755
--- a/t/t9604-cvsimport-timestamps.sh
+++ b/t/t9604-cvsimport-timestamps.sh
@@ -1,13 +1,31 @@
#!/bin/sh
test_description='git cvsimport timestamps'
+
. ./lib-cvs.sh
+test_lazy_prereq POSIX_TIMEZONE '
+ local tz=XST-1XDT,M3.5.0,M11.1.0
+ echo "1711846799 -> 2024-03-31 01:59:59 +0100" >expected &&
+ TZ="$tz" test-tool date show:iso-local 1711846799 >actual &&
+ test_cmp expected actual &&
+ echo "1711846800 -> 2024-03-31 03:00:00 +0200" >expected &&
+ TZ="$tz" test-tool date show:iso-local 1711846800 >actual &&
+ test_cmp expected actual &&
+ echo "1730591999 -> 2024-11-03 01:59:59 +0200" >expected &&
+ TZ="$tz" test-tool date show:iso-local 1730591999 >actual &&
+ test_cmp expected actual &&
+ echo "1730592000 -> 2024-11-03 01:00:00 +0100" >expected &&
+ TZ="$tz" test-tool date show:iso-local 1730592000 >actual &&
+ test_cmp expected actual
+'
+
setup_cvs_test_repository t9604
-test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' '
+test_expect_success PERL,POSIX_TIMEZONE 'check timestamps are UTC' '
- TZ=CST6CDT git cvsimport -p"-x" -C module-1 module &&
+ TZ=CST6CDT,M4.1.0,M10.5.0 \
+ git cvsimport -p"-x" -C module-1 module &&
git cvsimport -p"-x" -C module-1 module &&
(
cd module-1 &&
@@ -34,13 +52,13 @@ test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' '
test_cmp expect-1 actual-1
'
-test_expect_success PERL 'check timestamps with author-specific timezones' '
+test_expect_success PERL,POSIX_TIMEZONE 'check timestamps with author-specific timezones' '
cat >cvs-authors <<-EOF &&
user1=User One <user1@domain.org>
- user2=User Two <user2@domain.org> CST6CDT
- user3=User Three <user3@domain.org> EST5EDT
- user4=User Four <user4@domain.org> MST7MDT
+ user2=User Two <user2@domain.org> CST6CDT,M4.1.0,M10.5.0
+ user3=User Three <user3@domain.org> EST5EDT,M4.1.0,M10.5.0
+ user4=User Four <user4@domain.org> MST7MDT,M4.1.0,M10.5.0
EOF
git cvsimport -p"-x" -A cvs-authors -C module-2 module &&
(
diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh
index ccc8212d73..9c9e3b5eb1 100755
--- a/t/t9700-perl-git.sh
+++ b/t/t9700-perl-git.sh
@@ -5,7 +5,6 @@
test_description='perl interface (Git.pm)'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-perl.sh
@@ -45,7 +44,8 @@ test_expect_success 'set up test repository' '
'
test_expect_success 'set up bare repository' '
- git init --bare bare.git
+ git init --bare bare.git &&
+ git -C bare.git --work-tree=. commit --allow-empty -m "bare commit"
'
test_expect_success 'use t9700/test.pl to test Git.pm' '
diff --git a/t/t9700/test.pl b/t/t9700/test.pl
index 6d753708d2..2e1d50d4d1 100755
--- a/t/t9700/test.pl
+++ b/t/t9700/test.pl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use lib (split(/:/, $ENV{GITPERLLIB}));
-use 5.008;
+use 5.008001;
use warnings;
use strict;
@@ -147,6 +147,11 @@ close TEMPFILE3;
unlink $tmpfile3;
chdir($abs_repo_dir);
+# open alternate bare repo
+my $r4 = Git->repository(Directory => "$abs_repo_dir/bare.git");
+is($r4->command_oneline(qw(log --format=%s)), "bare commit",
+ "log of bare repo works");
+
# unquoting paths
is(Git::unquote_path('abc'), 'abc', 'unquote unquoted path');
is(Git::unquote_path('"abc def"'), 'abc def', 'unquote simple quoted path');
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index a4b3cb9492..0816763e46 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -54,7 +54,7 @@ test_expect_success 'git p4 sync uninitialized repo' '
(
cd "$git" &&
test_must_fail git p4 sync 2>errs &&
- test_i18ngrep "Perhaps you never did" errs
+ test_grep "Perhaps you never did" errs
)
'
@@ -86,7 +86,7 @@ test_expect_success 'git p4 sync existing branch without changes' '
test_commit head &&
git p4 sync --branch=depot //depot@all &&
git p4 sync --branch=refs/remotes/p4/depot >out &&
- test_i18ngrep "No changes to import!" out
+ test_grep "No changes to import!" out
)
'
@@ -101,7 +101,7 @@ test_expect_success 'git p4 sync existing branch with relative name' '
test_commit head &&
git p4 sync --branch=branch1 //depot@all &&
git p4 sync --branch=p4/branch1 >out &&
- test_i18ngrep "No changes to import!" out
+ test_grep "No changes to import!" out
)
'
@@ -116,7 +116,7 @@ test_expect_success 'git p4 sync existing branch with nested path' '
test_commit head &&
git p4 sync --branch=p4/some/path //depot@all &&
git p4 sync --branch=some/path >out &&
- test_i18ngrep "No changes to import!" out
+ test_grep "No changes to import!" out
)
'
@@ -131,7 +131,7 @@ test_expect_success 'git p4 sync branch explicit ref without p4 in path' '
test_commit head &&
git p4 sync --branch=refs/remotes/someremote/depot //depot@all &&
git p4 sync --branch=refs/remotes/someremote/depot >out &&
- test_i18ngrep "No changes to import!" out
+ test_grep "No changes to import!" out
)
'
@@ -143,7 +143,7 @@ test_expect_success 'git p4 sync nonexistent ref' '
test_commit head &&
git p4 sync --branch=depot //depot@all &&
test_must_fail git p4 sync --branch=depot2 2>errs &&
- test_i18ngrep "Perhaps you never did" errs
+ test_grep "Perhaps you never did" errs
)
'
@@ -155,7 +155,7 @@ test_expect_success 'git p4 sync existing non-p4-imported ref' '
test_commit head &&
git p4 sync --branch=depot //depot@all &&
test_must_fail git p4 sync --branch=refs/heads/master 2>errs &&
- test_i18ngrep "Perhaps you never did" errs
+ test_grep "Perhaps you never did" errs
)
'
@@ -290,18 +290,30 @@ test_expect_success 'exit when p4 fails to produce marshaled output' '
export PATH &&
test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1
) &&
- test_i18ngrep ! Traceback errs
+ test_grep ! Traceback errs
'
# Hide a file from p4d, make sure we catch its complaint. This won't fail in
# p4 changes, files, or describe; just in p4 print. If P4CLIENT is unset, the
# message will include "Librarian checkout".
test_expect_success 'exit gracefully for p4 server errors' '
- test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" &&
- mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden &&
+ # Note that newer Perforce versions started to store files
+ # compressed in directories. The case statement handles both
+ # old and new layout.
+ case "$(echo "$db"/depot/file1*)" in
+ *,v)
+ test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" &&
+ mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden;;
+ *,d)
+ path="$(echo "$db"/depot/file1,d/*.gz)" &&
+ test_when_finished "mv \"$path\",hidden \"$path\"" &&
+ mv "$path" "$path",hidden;;
+ *)
+ BUG "unhandled p4d layout";;
+ esac &&
test_when_finished cleanup_git &&
test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err &&
- test_i18ngrep "Error from p4 print" err
+ test_grep "Error from p4 print" err
'
test_expect_success 'clone --bare should make a bare repository' '
diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh
index 759a14fa87..c598011635 100755
--- a/t/t9801-git-p4-branch.sh
+++ b/t/t9801-git-p4-branch.sh
@@ -135,7 +135,7 @@ test_expect_success 'sync specific detected branch' '
(
cd "$git" &&
git p4 sync --branch=depot/branch2 >out &&
- test_i18ngrep "No changes to import!" out
+ test_grep "No changes to import!" out
)
'
@@ -466,7 +466,7 @@ test_expect_success 'git p4 clone complex branches with excluded files' '
)
'
-# From a report in http://stackoverflow.com/questions/11893688
+# From a report in https://stackoverflow.com/questions/11893688
# where --use-client-spec caused branch prefixes not to be removed;
# every file in git appeared into a subdirectory of the branch name.
test_expect_success 'use-client-spec detect-branches setup' '
diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh
index 2a6ee2a467..df01a5d338 100755
--- a/t/t9802-git-p4-filetype.sh
+++ b/t/t9802-git-p4-filetype.sh
@@ -175,7 +175,7 @@ test_expect_success 'keyword file create' '
cp k-text-k k-text-ko &&
p4 add -t text+ko k-text-ko &&
- cat k-text-k | iconv -f ascii -t utf-16 >k-utf16-k &&
+ iconv -f ascii -t utf-16 <k-text-k >k-utf16-k &&
p4 add -t utf16+k k-utf16-k &&
cp k-utf16-k k-utf16-ko &&
@@ -300,10 +300,22 @@ test_expect_success SYMLINKS 'empty symlink target' '
# text
# @@
#
+ # Note that newer Perforce versions started to store files
+ # compressed in directories. The case statement handles both
+ # old and new layout.
cd "$db/depot" &&
- sed "/@target1/{; s/target1/@/; n; d; }" \
- empty-symlink,v >empty-symlink,v.tmp &&
- mv empty-symlink,v.tmp empty-symlink,v
+ case "$(echo empty-symlink*)" in
+ empty-symlink,v)
+ sed "/@target1/{; s/target1/@/; n; d; }" \
+ empty-symlink,v >empty-symlink,v.tmp &&
+ mv empty-symlink,v.tmp empty-symlink,v;;
+ empty-symlink,d)
+ path="empty-symlink,d/$(ls empty-symlink,d/ | tail -n1)" &&
+ rm "$path" &&
+ gzip </dev/null >"$path";;
+ *)
+ BUG "unhandled p4d layout";;
+ esac
) &&
(
# Make sure symlink really is empty. Asking
diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh
index 7d4109f29d..6ae7ced51b 100755
--- a/t/t9807-git-p4-submit.sh
+++ b/t/t9807-git-p4-submit.sh
@@ -75,7 +75,7 @@ test_expect_success 'submit --dry-run' '
test_commit "dry-run1" &&
test_commit "dry-run2" &&
git p4 submit --dry-run >out &&
- test_i18ngrep "Would apply" out
+ test_grep "Would apply" out
) &&
(
cd "$cli" &&
@@ -99,7 +99,7 @@ test_expect_success 'submit --dry-run --export-labels' '
git commit -m "dry-run2" dry-run2 &&
git tag -m "dry-run-tag1" dry-run-tag1 HEAD^ &&
git p4 submit --dry-run --export-labels >out &&
- test_i18ngrep "Would create p4 label" out
+ test_grep "Would create p4 label" out
) &&
(
cd "$cli" &&
@@ -418,7 +418,7 @@ test_expect_success 'description with Jobs and values on separate lines' '
marshal_dump job0 <change &&
marshal_dump job1 <change
) | sort >jobs &&
- cat jobname1 jobname2 | sort >expected &&
+ sort jobname1 jobname2 >expected &&
test_cmp expected jobs
)
'
@@ -443,7 +443,7 @@ test_expect_success 'description with Jobs section and bogus following text' '
# build a job
make_job $(cat jobname) &&
test_must_fail git p4 submit 2>err &&
- test_i18ngrep "Unknown field name" err
+ test_grep "Unknown field name" err
) &&
(
cd "$cli" &&
@@ -461,9 +461,9 @@ test_expect_success 'submit --prepare-p4-only' '
git add prep-only-add &&
git commit -m "prep only add" &&
git p4 submit --prepare-p4-only >out &&
- test_i18ngrep "prepared for submission" out &&
- test_i18ngrep "must be deleted" out &&
- test_i18ngrep ! "everything below this line is just the diff" out
+ test_grep "prepared for submission" out &&
+ test_grep "must be deleted" out &&
+ test_grep ! "everything below this line is just the diff" out
) &&
(
cd "$cli" &&
diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh
index 0ca9937de6..c766fd159f 100755
--- a/t/t9815-git-p4-submit-fail.sh
+++ b/t/t9815-git-p4-submit-fail.sh
@@ -35,7 +35,7 @@ test_expect_success 'conflict on one commit' '
git add file1 &&
git commit -m "line3 in file1 will conflict" &&
test_expect_code 1 git p4 submit >out &&
- test_i18ngrep "No commits applied" out
+ test_grep "No commits applied" out
)
'
@@ -58,7 +58,7 @@ test_expect_success 'conflict on second of two commits' '
git add file1 &&
git commit -m "line4 in file1 will conflict" &&
test_expect_code 1 git p4 submit >out &&
- test_i18ngrep "Applied only the commits" out
+ test_grep "Applied only the commits" out
)
'
@@ -81,7 +81,7 @@ test_expect_success 'conflict on first of two commits, skip' '
# but this commit is okay
test_commit "okay_commit_after_skip" &&
echo s | test_expect_code 1 git p4 submit >out &&
- test_i18ngrep "Applied only the commits" out
+ test_grep "Applied only the commits" out
)
'
@@ -104,7 +104,7 @@ test_expect_success 'conflict on first of two commits, quit' '
# but this commit is okay
test_commit "okay_commit_after_quit" &&
echo q | test_expect_code 1 git p4 submit >out &&
- test_i18ngrep "No commits applied" out
+ test_grep "No commits applied" out
)
'
@@ -144,7 +144,7 @@ test_expect_success 'conflict on first of two commits, --conflict=skip' '
# but this commit is okay
test_commit "okay_commit_after_auto_skip" &&
test_expect_code 1 git p4 submit --conflict=skip >out &&
- test_i18ngrep "Applied only the commits" out
+ test_grep "Applied only the commits" out
)
'
@@ -167,7 +167,7 @@ test_expect_success 'conflict on first of two commits, --conflict=quit' '
# but this commit is okay
test_commit "okay_commit_after_auto_quit" &&
test_expect_code 1 git p4 submit --conflict=quit >out &&
- test_i18ngrep "No commits applied" out
+ test_grep "No commits applied" out
)
'
diff --git a/t/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh
index 932841003c..5e904ac80d 100755
--- a/t/t9816-git-p4-locked.sh
+++ b/t/t9816-git-p4-locked.sh
@@ -9,7 +9,7 @@ test_expect_success 'start p4d' '
'
# See
-# http://www.perforce.com/perforce/doc.current/manuals/p4sag/03_superuser.html#1088563
+# https://web.archive.org/web/20150602090517/http://www.perforce.com/perforce/doc.current/manuals/p4sag/chapter.superuser.html#superuser.basic.typemap_locking
# for suggestions on how to configure "sitewide pessimistic locking"
# where only one person can have a file open for edit at a time.
test_expect_success 'init depot' '
diff --git a/t/t9824-git-p4-git-lfs.sh b/t/t9824-git-p4-git-lfs.sh
index a28dbbdd56..80c8c31e32 100755
--- a/t/t9824-git-p4-git-lfs.sh
+++ b/t/t9824-git-p4-git-lfs.sh
@@ -17,8 +17,8 @@ test_file_in_lfs () {
sed -n '2,2 p' "$FILE" | grep "^oid " &&
sed -n '3,3 p' "$FILE" | grep "^size " &&
test_line_count = 3 "$FILE" &&
- cat "$FILE" | grep "size $SIZE" &&
- HASH=$(cat "$FILE" | grep "oid sha256:" | sed -e "s/oid sha256://g") &&
+ grep "size $SIZE" "$FILE" &&
+ HASH=$(sed -ne "/oid sha256:/s/oid sha256://gp" "$FILE") &&
LFS_FILE=".git/lfs/objects/$(echo "$HASH" | cut -c1-2)/$(echo "$HASH" | cut -c3-4)/$HASH" &&
echo $EXPECTED_CONTENT >expect &&
test_path_is_file "$FILE" &&
diff --git a/t/t9825-git-p4-handle-utf16-without-bom.sh b/t/t9825-git-p4-handle-utf16-without-bom.sh
index f049ff8229..6a60b32349 100755
--- a/t/t9825-git-p4-handle-utf16-without-bom.sh
+++ b/t/t9825-git-p4-handle-utf16-without-bom.sh
@@ -22,9 +22,25 @@ test_expect_success 'init depot with UTF-16 encoded file and artificially remove
cd db &&
p4d -jc &&
# P4D automatically adds a BOM. Remove it here to make the file invalid.
- sed -e "\$d" depot/file1,v >depot/file1,v.new &&
- mv depot/file1,v.new depot/file1,v &&
- printf "@$UTF16@" >>depot/file1,v &&
+ #
+ # Note that newer Perforce versions started to store files
+ # compressed in directories. The case statement handles both
+ # old and new layout.
+ case "$(echo depot/file1*)" in
+ depot/file1,v)
+ sed -e "\$d" depot/file1,v >depot/file1,v.new &&
+ mv depot/file1,v.new depot/file1,v &&
+ printf "@$UTF16@" >>depot/file1,v;;
+ depot/file1,d)
+ path="$(echo depot/file1,d/*.gz)" &&
+ gunzip -c "$path" >"$path.unzipped" &&
+ sed -e "\$d" "$path.unzipped" >"$path.new" &&
+ printf "$UTF16" >>"$path.new" &&
+ gzip -c "$path.new" >"$path" &&
+ rm "$path.unzipped" "$path.new";;
+ *)
+ BUG "unhandled p4d layout";;
+ esac &&
p4d -jrF checkpoint.1
)
'
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index cfc71c3bd4..36566ace21 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -1,6 +1,7 @@
#!/bin/sh
test_description='git shell tests'
+
. ./test-lib.sh
test_expect_success 'shell allows upload-pack' '
diff --git a/t/t9901-git-web--browse.sh b/t/t9901-git-web--browse.sh
index 19f56e5680..de7152f827 100755
--- a/t/t9901-git-web--browse.sh
+++ b/t/t9901-git-web--browse.sh
@@ -5,7 +5,6 @@ test_description='git web--browse basic tests
This test checks that git web--browse can handle various valid URLs.'
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_web_browse () {
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 47e20fb8b1..932d5ad759 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -5,6 +5,17 @@
test_description='test bash completion'
+# The Bash completion scripts must not print anything to either stdout or
+# stderr, which we try to verify. When tracing is enabled without support for
+# BASH_XTRACEFD this assertion will fail, so we have to mark the test as
+# untraceable with such ancient Bash versions.
+test_untraceable=UnfortunatelyYes
+
+# Override environment and always use master for the default initial branch
+# name for these tests, so that rev completion candidates are as expected.
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
. ./lib-bash.sh
complete ()
@@ -62,7 +73,7 @@ _get_comp_words_by_ref ()
print_comp ()
{
local IFS=$'\n'
- echo "${COMPREPLY[*]}" > out
+ printf '%s\n' "${COMPREPLY[*]}" > out
}
run_completion ()
@@ -87,9 +98,11 @@ test_completion ()
else
sed -e 's/Z$//' |sort >expected
fi &&
- run_completion "$1" &&
+ run_completion "$1" >"$TRASH_DIRECTORY"/bash-completion-output 2>&1 &&
sort out >out_sorted &&
- test_cmp expected out_sorted
+ test_cmp expected out_sorted &&
+ test_must_be_empty "$TRASH_DIRECTORY"/bash-completion-output &&
+ rm "$TRASH_DIRECTORY"/bash-completion-output
}
# Test __gitcomp.
@@ -1250,6 +1263,29 @@ test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' '
test_cmp expected out
'
+test_expect_success '__git_complete_worktree_paths' '
+ test_when_finished "git worktree remove other_wt" &&
+ git worktree add --orphan other_wt &&
+ run_completion "git worktree remove " &&
+ grep other_wt out
+'
+
+test_expect_success '__git_complete_worktree_paths - not a git repository' '
+ (
+ cd non-repo &&
+ GIT_CEILING_DIRECTORIES="$ROOT" &&
+ export GIT_CEILING_DIRECTORIES &&
+ test_completion "git worktree remove " ""
+ )
+'
+
+test_expect_success '__git_complete_worktree_paths with -C' '
+ test_when_finished "git -C otherrepo worktree remove otherrepo_wt" &&
+ git -C otherrepo worktree add --orphan otherrepo_wt &&
+ run_completion "git -C otherrepo worktree remove " &&
+ grep otherrepo_wt out
+'
+
test_expect_success 'git switch - with no options, complete local branches and unique remote branch names for DWIM logic' '
test_completion "git switch " <<-\EOF
branch-in-other Z
@@ -1259,6 +1295,142 @@ test_expect_success 'git switch - with no options, complete local branches and u
EOF
'
+test_expect_success 'git bisect - when not bisecting, complete only replay and start subcommands' '
+ test_completion "git bisect " <<-\EOF
+ replay Z
+ start Z
+ EOF
+'
+
+test_expect_success 'git bisect - complete options to start subcommand' '
+ test_completion "git bisect start --" <<-\EOF
+ --term-new Z
+ --term-bad Z
+ --term-old Z
+ --term-good Z
+ --no-checkout Z
+ --first-parent Z
+ EOF
+'
+
+test_expect_success 'setup for git-bisect tests requiring a repo' '
+ git init git-bisect &&
+ (
+ cd git-bisect &&
+ echo "initial contents" >file &&
+ git add file &&
+ git commit -am "Initial commit" &&
+ git tag initial &&
+ echo "new line" >>file &&
+ git commit -am "First change" &&
+ echo "another new line" >>file &&
+ git commit -am "Second change" &&
+ git tag final
+ )
+'
+
+test_expect_success 'git bisect - start subcommand arguments before double-dash are completed as revs' '
+ (
+ cd git-bisect &&
+ test_completion "git bisect start " <<-\EOF
+ HEAD Z
+ final Z
+ initial Z
+ master Z
+ EOF
+ )
+'
+
+# Note that these arguments are <pathspec>s, which in practice the fallback
+# completion (not the git completion) later ends up completing as paths.
+test_expect_success 'git bisect - start subcommand arguments after double-dash are not completed' '
+ (
+ cd git-bisect &&
+ test_completion "git bisect start final initial -- " ""
+ )
+'
+
+test_expect_success 'setup for git-bisect tests requiring ongoing bisection' '
+ (
+ cd git-bisect &&
+ git bisect start --term-new=custom_new --term-old=custom_old final initial
+ )
+'
+
+test_expect_success 'git-bisect - when bisecting all subcommands are candidates' '
+ (
+ cd git-bisect &&
+ test_completion "git bisect " <<-\EOF
+ start Z
+ bad Z
+ custom_new Z
+ custom_old Z
+ new Z
+ good Z
+ old Z
+ terms Z
+ skip Z
+ reset Z
+ visualize Z
+ replay Z
+ log Z
+ run Z
+ help Z
+ EOF
+ )
+'
+
+test_expect_success 'git-bisect - options to terms subcommand are candidates' '
+ (
+ cd git-bisect &&
+ test_completion "git bisect terms --" <<-\EOF
+ --term-bad Z
+ --term-good Z
+ --term-new Z
+ --term-old Z
+ EOF
+ )
+'
+
+test_expect_success 'git-bisect - git-log options to visualize subcommand are candidates' '
+ (
+ cd git-bisect &&
+ # The completion used for git-log and here does not complete
+ # every git-log option, so rather than hope to stay in sync
+ # with exactly what it does we will just spot-test here.
+ test_completion "git bisect visualize --sta" <<-\EOF &&
+ --stat Z
+ EOF
+ test_completion "git bisect visualize --summar" <<-\EOF
+ --summary Z
+ EOF
+ )
+'
+
+test_expect_success 'git-bisect - view subcommand is not a candidate' '
+ (
+ cd git-bisect &&
+ test_completion "git bisect vi" <<-\EOF
+ visualize Z
+ EOF
+ )
+'
+
+test_expect_success 'git-bisect - existing view subcommand is recognized and enables completion of git-log options' '
+ (
+ cd git-bisect &&
+ # The completion used for git-log and here does not complete
+ # every git-log option, so rather than hope to stay in sync
+ # with exactly what it does we will just spot-test here.
+ test_completion "git bisect view --sta" <<-\EOF &&
+ --stat Z
+ EOF
+ test_completion "git bisect view --summar" <<-\EOF
+ --summary Z
+ EOF
+ )
+'
+
test_expect_success 'git checkout - completes refs and unique remote branches for DWIM' '
test_completion "git checkout " <<-\EOF
HEAD Z
@@ -1571,7 +1743,7 @@ test_expect_success FUNNYNAMES,!CYGWIN 'cone mode sparse-checkout completes dire
)
'
-test_expect_success 'non-cone mode sparse-checkout uses bash completion' '
+test_expect_success 'non-cone mode sparse-checkout gives rooted paths' '
# reset sparse-checkout repo to non-cone mode
git -C sparse-checkout sparse-checkout disable &&
git -C sparse-checkout sparse-checkout set --no-cone &&
@@ -1581,7 +1753,12 @@ test_expect_success 'non-cone mode sparse-checkout uses bash completion' '
# expected to be empty since we have not configured
# custom completion for non-cone mode
test_completion "git sparse-checkout set f" <<-\EOF
-
+ /folder1/0/1/t.txt Z
+ /folder1/expected Z
+ /folder1/out Z
+ /folder1/out_sorted Z
+ /folder2/0/t.txt Z
+ /folder3/t.txt Z
EOF
)
'
@@ -1920,6 +2097,14 @@ test_expect_success 'git checkout - --orphan with branch already provided comple
EOF
'
+test_expect_success 'git restore completes modified files' '
+ test_commit A a.file &&
+ echo B >a.file &&
+ test_completion "git restore a." <<-\EOF
+ a.file
+ EOF
+'
+
test_expect_success 'teardown after ref completion' '
git branch -d matching-branch &&
git tag -d matching-tag &&
@@ -2333,6 +2518,29 @@ test_expect_success 'complete tree filename with metacharacters' '
EOF
'
+test_expect_success 'symbolic-ref completes builtin options' '
+ test_completion "git symbolic-ref --d" <<-\EOF
+ --delete Z
+ EOF
+'
+
+test_expect_success 'symbolic-ref completes short ref names' '
+ test_completion "git symbolic-ref foo m" <<-\EOF
+ main Z
+ mybranch Z
+ mytag Z
+ EOF
+'
+
+test_expect_success 'symbolic-ref completes full ref names' '
+ test_completion "git symbolic-ref foo refs/" <<-\EOF
+ refs/heads/main Z
+ refs/heads/mybranch Z
+ refs/tags/mytag Z
+ refs/tags/A Z
+ EOF
+'
+
test_expect_success PERL 'send-email' '
test_completion "git send-email --cov" <<-\EOF &&
--cover-from-description=Z
@@ -2464,6 +2672,24 @@ test_expect_success 'completion used <cmd> completion for alias: !f() { : git <c
EOF
'
+test_expect_success 'completion used <cmd> completion for alias: !f() { : <cmd> ; ... }' '
+ test_config alias.co "!f() { : checkout ; if ... } f" &&
+ test_completion "git co m" <<-\EOF
+ main Z
+ mybranch Z
+ mytag Z
+ EOF
+'
+
+test_expect_success 'completion used <cmd> completion for alias: !f() { : <cmd>; ... }' '
+ test_config alias.co "!f() { : checkout; if ... } f" &&
+ test_completion "git co m" <<-\EOF
+ main Z
+ mybranch Z
+ mytag Z
+ EOF
+'
+
test_expect_success 'completion without explicit _git_xxx function' '
test_completion "git version --" <<-\EOF
--build-options Z
@@ -2516,36 +2742,93 @@ do
'
done
-test_expect_success 'git config - section' '
- test_completion "git config br" <<-\EOF
+test_expect_success 'git config subcommand' '
+ test_completion "git config " <<-\EOF
+ edit Z
+ get Z
+ list Z
+ remove-section Z
+ rename-section Z
+ set Z
+ unset Z
+ EOF
+'
+
+test_expect_success 'git config subcommand options' '
+ test_completion "git config get --show-" <<-\EOF
+ --show-names Z
+ --show-origin Z
+ --show-scope Z
+ EOF
+'
+
+test_expect_success 'git config get' '
+ test_when_finished "rm -f cfgfile" &&
+ git config set --file cfgfile foo.bar baz &&
+ test_completion "git config get --file cfgfile foo." <<-\EOF
+ foo.bar Z
+ EOF
+'
+
+test_expect_success 'git config set - section' '
+ test_completion "git config set br" <<-\EOF
branch.Z
browser.Z
EOF
'
-test_expect_success 'git config - section include, includeIf' '
- test_completion "git config inclu" <<-\EOF
+test_expect_success 'git config set - section include, includeIf' '
+ test_completion "git config set inclu" <<-\EOF
include.Z
includeIf.Z
EOF
'
-test_expect_success 'git config - variable name' '
- test_completion "git config log.d" <<-\EOF
+test_expect_success 'git config set - variable name' '
+ test_completion "git config set log.d" <<-\EOF
log.date Z
log.decorate Z
log.diffMerges Z
EOF
'
-test_expect_success 'git config - variable name include' '
- test_completion "git config include.p" <<-\EOF
+test_expect_success 'git config set - variable name include' '
+ test_completion "git config set include.p" <<-\EOF
include.path Z
EOF
'
-test_expect_success 'git config - value' '
- test_completion "git config color.pager " <<-\EOF
+test_expect_success 'setup for git config submodule tests' '
+ test_create_repo sub &&
+ test_commit -C sub initial &&
+ git submodule add ./sub
+'
+
+test_expect_success 'git config set - variable name - submodule and __git_compute_first_level_config_vars_for_section' '
+ test_completion "git config set submodule." <<-\EOF
+ submodule.active Z
+ submodule.alternateErrorStrategy Z
+ submodule.alternateLocation Z
+ submodule.fetchJobs Z
+ submodule.propagateBranches Z
+ submodule.recurse Z
+ submodule.sub.Z
+ EOF
+'
+
+test_expect_success 'git config set - variable name - __git_compute_second_level_config_vars_for_section' '
+ test_completion "git config set submodule.sub." <<-\EOF
+ submodule.sub.url Z
+ submodule.sub.update Z
+ submodule.sub.branch Z
+ submodule.sub.fetchRecurseSubmodules Z
+ submodule.sub.ignore Z
+ submodule.sub.active Z
+ EOF
+'
+
+test_expect_success 'git config set - value' '
+ test_completion "git config set color.pager " <<-\EOF
false Z
true Z
EOF
@@ -2595,6 +2878,20 @@ test_expect_success 'git clone --config= - value' '
EOF
'
+test_expect_success 'git reflog show' '
+ test_when_finished "git checkout - && git branch -d shown" &&
+ git checkout -b shown &&
+ test_completion "git reflog sho" <<-\EOF &&
+ show Z
+ shown Z
+ EOF
+ test_completion "git reflog show sho" "shown " &&
+ test_completion "git reflog shown sho" "shown " &&
+ test_completion "git reflog --unt" "--until=" &&
+ test_completion "git reflog show --unt" "--until=" &&
+ test_completion "git reflog shown --unt" "--until="
+'
+
test_expect_success 'options with value' '
test_completion "git merge -X diff-algorithm=" <<-\EOF
@@ -2697,4 +2994,31 @@ test_expect_success '__git_complete' '
test_must_fail __git_complete ga missing
'
+test_expect_success '__git_pseudoref_exists' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ sane_unset __git_repo_path &&
+
+ # HEAD should exist, even if it points to an unborn branch.
+ __git_pseudoref_exists HEAD >output 2>&1 &&
+ test_must_be_empty output &&
+
+ # HEAD points to an existing branch, so it should exist.
+ test_commit A &&
+ __git_pseudoref_exists HEAD >output 2>&1 &&
+ test_must_be_empty output &&
+
+ # CHERRY_PICK_HEAD does not exist, so the existence check should fail.
+ ! __git_pseudoref_exists CHERRY_PICK_HEAD >output 2>&1 &&
+ test_must_be_empty output &&
+
+ # CHERRY_PICK_HEAD points to a commit, so it should exist.
+ git update-ref CHERRY_PICK_HEAD A &&
+ __git_pseudoref_exists CHERRY_PICK_HEAD >output 2>&1 &&
+ test_must_be_empty output
+ )
+'
+
test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 2f8868caa1..78e054ab50 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -14,7 +14,7 @@
# 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/ .
+# along with this program. If not, see https://www.gnu.org/licenses/ .
# The semantics of the editor variables are that of invoking
# sh -c "$EDITOR \"$@\"" files ...
@@ -251,6 +251,61 @@ debug () {
done
}
+# Usage: test_ref_exists [options] <ref>
+#
+# -C <dir>:
+# Run all git commands in directory <dir>
+#
+# This helper function checks whether a reference exists. Symrefs or object IDs
+# will not be resolved. Can be used to check references with bad names.
+test_ref_exists () {
+ local indir=
+
+ while test $# != 0
+ do
+ case "$1" in
+ -C)
+ indir="$2"
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+
+ indir=${indir:+"$indir"/} &&
+
+ if test "$#" != 1
+ then
+ BUG "expected exactly one reference"
+ fi &&
+
+ git ${indir:+ -C "$indir"} show-ref --exists "$1"
+}
+
+# Behaves the same as test_ref_exists, except that it checks for the absence of
+# a reference. This is preferable to `! test_ref_exists` as this function is
+# able to distinguish actually-missing references from other, generic errors.
+test_ref_missing () {
+ test_ref_exists "$@"
+ case "$?" in
+ 2)
+ # This is the good case.
+ return 0
+ ;;
+ 0)
+ echo >&4 "test_ref_missing: reference exists"
+ return 1
+ ;;
+ *)
+ echo >&4 "test_ref_missing: generic error"
+ return 1
+ ;;
+ esac
+}
+
# Usage: test_commit [options] <message> [<file> [<contents> [<tag>]]]
# -C <dir>:
# Run all git commands in directory <dir>
@@ -330,7 +385,7 @@ test_commit () {
shift
done &&
indir=${indir:+"$indir"/} &&
- local file=${2:-"$1.t"} &&
+ local file="${2:-"$1.t"}" &&
if test -n "$append"
then
$echo "${3-$1}" >>"$indir$file"
@@ -403,6 +458,7 @@ test_commit_bulk () {
indir=.
ref=HEAD
n=1
+ notick=
message='commit %s'
filename='%s.t'
contents='content %s'
@@ -433,6 +489,9 @@ test_commit_bulk () {
filename="${1#--*=}-%s.t"
contents="${1#--*=} %s"
;;
+ --notick)
+ notick=yes
+ ;;
-*)
BUG "invalid test_commit_bulk option: $1"
;;
@@ -452,7 +511,10 @@ test_commit_bulk () {
while test "$total" -gt 0
do
- test_tick &&
+ if test -z "$notick"
+ then
+ test_tick
+ fi &&
echo "commit $ref"
printf 'author %s <%s> %s\n' \
"$GIT_AUTHOR_NAME" \
@@ -810,6 +872,24 @@ test_verify_prereq () {
BUG "'$test_prereq' does not look like a prereq"
}
+# assign the variable named by "$1" with the contents of "$2";
+# if "$2" is "-", then read stdin into "$1" instead
+test_body_or_stdin () {
+ if test "$2" != "-"
+ then
+ eval "$1=\$2"
+ return
+ fi
+
+ # start with a newline, to match hanging newline from open-quote style
+ eval "$1=\$LF"
+ local test_line
+ while IFS= read -r test_line
+ do
+ eval "$1=\${$1}\${test_line}\${LF}"
+ done
+}
+
test_expect_failure () {
test_start_ "$@"
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
@@ -819,9 +899,11 @@ test_expect_failure () {
export test_prereq
if ! test_skip "$@"
then
+ local test_body
+ test_body_or_stdin test_body "$2"
test -n "$test_skip_test_preamble" ||
- say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $2"
- if test_run_ "$2" expecting_failure
+ say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $test_body"
+ if test_run_ "$test_body" expecting_failure
then
test_known_broken_ok_ "$1"
else
@@ -840,13 +922,16 @@ test_expect_success () {
export test_prereq
if ! test_skip "$@"
then
+ local test_body
+ test_body_or_stdin test_body "$2"
test -n "$test_skip_test_preamble" ||
- say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $2"
- if test_run_ "$2"
+ say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body"
+ if test_run_ "$test_body" &&
+ check_test_results_san_file_empty_
then
test_ok_ "$1"
else
- test_failure_ "$@"
+ test_failure_ "$1" "$test_body"
fi
fi
test_finish_
@@ -1041,6 +1126,11 @@ test_must_fail_acceptable () {
done
fi
+ if test "$1" = "nongit"
+ then
+ shift
+ fi
+
case "$1" in
git|__git*|scalar|test-tool|test_terminal)
return 0
@@ -1208,19 +1298,20 @@ test_cmp_bin () {
cmp "$@"
}
-# Wrapper for grep which used to be used for
-# GIT_TEST_GETTEXT_POISON=false. Only here as a shim for other
-# in-flight changes. Should not be used and will be removed soon.
test_i18ngrep () {
+ BUG "do not use test_i18ngrep---use test_grep instead"
+}
+
+test_grep () {
eval "last_arg=\${$#}"
test -f "$last_arg" ||
- BUG "test_i18ngrep requires a file to read as the last parameter"
+ BUG "test_grep requires a file to read as the last parameter"
if test $# -lt 2 ||
{ test "x!" = "x$1" && test $# -lt 3 ; }
then
- BUG "too few parameters to test_i18ngrep"
+ BUG "too few parameters to test_grep"
fi
if test "x!" = "x$1"
@@ -1599,7 +1690,21 @@ test_set_hash () {
# Detect the hash algorithm in use.
test_detect_hash () {
- test_hash_algo="${GIT_TEST_DEFAULT_HASH:-sha1}"
+ case "$GIT_TEST_DEFAULT_HASH" in
+ "sha256")
+ test_hash_algo=sha256
+ test_compat_hash_algo=sha1
+ ;;
+ *)
+ test_hash_algo=sha1
+ test_compat_hash_algo=sha256
+ ;;
+ esac
+}
+
+# Detect the hash algorithm in use.
+test_detect_ref_format () {
+ echo "${GIT_TEST_DEFAULT_REF_FORMAT:-files}"
}
# Load common hash metadata and common placeholder object IDs for use with
@@ -1651,6 +1756,12 @@ test_oid () {
local algo="${test_hash_algo}" &&
case "$1" in
+ --hash=storage)
+ algo="$test_hash_algo" &&
+ shift;;
+ --hash=compat)
+ algo="$test_compat_hash_algo" &&
+ shift;;
--hash=*)
algo="${1#--hash=}" &&
shift;;
@@ -1672,7 +1783,7 @@ test_oid () {
# Insert a slash into an object ID so it can be used to reference a location
# under ".git/objects". For example, "deadbeef..." becomes "de/adbeef..".
test_oid_to_path () {
- local basename=${1#??}
+ local basename="${1#??}"
echo "${1%$basename}/$basename"
}
@@ -1689,7 +1800,7 @@ test_parse_ls_tree_oids () {
# Choose a port number based on the test script's number and store it in
# the given variable name, unless that variable already contains a number.
test_set_port () {
- local var=$1 port
+ local var="$1" port
if test $# -ne 1 || test -z "$var"
then
@@ -1764,7 +1875,7 @@ test_subcommand () {
shift
fi
- local expr=$(printf '"%s",' "$@")
+ local expr="$(printf '"%s",' "$@")"
expr="${expr%,}"
if test -n "$negate"
@@ -1817,6 +1928,20 @@ test_region () {
return 0
}
+# Check that the given data fragment was included as part of the
+# trace2-format trace on stdin.
+#
+# test_trace2_data <category> <key> <value>
+#
+# For example, to look for trace2_data_intmax("pack-objects", repo,
+# "reused", N) in an invocation of "git pack-objects", run:
+#
+# GIT_TRACE2_EVENT="$(pwd)/trace.txt" git pack-objects ... &&
+# test_trace2_data pack-objects reused N <trace2.txt
+test_trace2_data () {
+ grep -e '"category":"'"$1"'","key":"'"$2"'","value":"'"$3"'"'
+}
+
# Given a GIT_TRACE2_EVENT log over stdin, writes to stdout a list of URLs
# sent to git-remote-https child processes.
test_remote_https_urls() {
@@ -1840,7 +1965,7 @@ test_readlink () {
# An optional increment to the magic timestamp may be specified as second
# argument.
test_set_magic_mtime () {
- local inc=${2:-0} &&
+ local inc="${2:-0}" &&
local mtime=$((1234567890 + $inc)) &&
test-tool chmtime =$mtime "$1" &&
test_is_magic_mtime "$1" $inc
@@ -1853,7 +1978,7 @@ test_set_magic_mtime () {
# argument. Usually, this should be the same increment which was used for
# the associated test_set_magic_mtime.
test_is_magic_mtime () {
- local inc=${2:-0} &&
+ local inc="${2:-0}" &&
local mtime=$((1234567890 + $inc)) &&
echo $mtime >.git/test-mtime-expect &&
test-tool chmtime --get "$1" >.git/test-mtime-actual &&
diff --git a/t/test-lib-github-workflow-markup.sh b/t/test-lib-github-workflow-markup.sh
index 9c5339c577..33405c90d7 100644
--- a/t/test-lib-github-workflow-markup.sh
+++ b/t/test-lib-github-workflow-markup.sh
@@ -14,7 +14,7 @@
# 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/ .
+# along with this program. If not, see https://www.gnu.org/licenses/ .
#
# The idea is for `test-lib.sh` to source this file when run in GitHub
# workflows; these functions will then override (empty) functions
@@ -42,8 +42,8 @@ finalize_test_case_output () {
fixed)
echo >>$github_markup_output "::notice::fixed: $this_test.$test_count $1"
;;
- ok)
- # Exit without printing the "ok" tests
+ ok|broken)
+ # Exit without printing the "ok" or ""broken" tests
return
;;
esac
diff --git a/t/test-lib-junit.sh b/t/test-lib-junit.sh
index 79c31c788b..76cbbd3299 100644
--- a/t/test-lib-junit.sh
+++ b/t/test-lib-junit.sh
@@ -15,7 +15,7 @@
# 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/ .
+# along with this program. If not, see https://www.gnu.org/licenses/ .
#
# The idea is for `test-lib.sh` to source this file when the user asks
# for JUnit XML; these functions will then override (empty) functions
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1656c9eed0..426036b33a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -13,7 +13,7 @@
# 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/ .
+# along with this program. If not, see https://www.gnu.org/licenses/ .
# Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in 'trash directory' subdirectory.
@@ -322,7 +322,6 @@ TEST_RESULTS_SAN_FILE_PFX=trace
TEST_RESULTS_SAN_DIR_SFX=leak
TEST_RESULTS_SAN_FILE=
TEST_RESULTS_SAN_DIR="$TEST_RESULTS_DIR/$TEST_NAME.$TEST_RESULTS_SAN_DIR_SFX"
-TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=
TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX"
test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
case "$TRASH_DIRECTORY" in
@@ -542,6 +541,8 @@ export EDITOR
GIT_DEFAULT_HASH="${GIT_TEST_DEFAULT_HASH:-sha1}"
export GIT_DEFAULT_HASH
+GIT_DEFAULT_REF_FORMAT="${GIT_TEST_DEFAULT_REF_FORMAT:-files}"
+export GIT_DEFAULT_REF_FORMAT
GIT_TEST_MERGE_ALGORITHM="${GIT_TEST_MERGE_ALGORITHM:-ort}"
export GIT_TEST_MERGE_ALGORITHM
@@ -576,53 +577,6 @@ case $GIT_TEST_FSYNC in
;;
esac
-# Add libc MALLOC and MALLOC_PERTURB test only if we are not executing
-# the test with valgrind and have not compiled with conflict SANITIZE
-# options.
-if test -n "$valgrind" ||
- test -n "$SANITIZE_ADDRESS" ||
- test -n "$SANITIZE_LEAK" ||
- test -n "$TEST_NO_MALLOC_CHECK"
-then
- setup_malloc_check () {
- : nothing
- }
- teardown_malloc_check () {
- : nothing
- }
-else
- _USE_GLIBC_TUNABLES=
- if _GLIBC_VERSION=$(getconf GNU_LIBC_VERSION 2>/dev/null) &&
- _GLIBC_VERSION=${_GLIBC_VERSION#"glibc "} &&
- expr 2.34 \<= "$_GLIBC_VERSION" >/dev/null
- then
- _USE_GLIBC_TUNABLES=YesPlease
- fi
- setup_malloc_check () {
- local g
- local t
- MALLOC_CHECK_=3 MALLOC_PERTURB_=165
- export MALLOC_CHECK_ MALLOC_PERTURB_
- if test -n "$_USE_GLIBC_TUNABLES"
- then
- g=
- LD_PRELOAD="libc_malloc_debug.so.0"
- for t in \
- glibc.malloc.check=1 \
- glibc.malloc.perturb=165
- do
- g="${g#:}:$t"
- done
- GLIBC_TUNABLES=$g
- export LD_PRELOAD GLIBC_TUNABLES
- fi
- }
- teardown_malloc_check () {
- unset MALLOC_CHECK_ MALLOC_PERTURB_
- unset LD_PRELOAD GLIBC_TUNABLES
- }
-fi
-
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH
@@ -846,6 +800,7 @@ test_failure_ () {
GIT_EXIT_OK=t
exit 0
fi
+ check_test_results_san_file_ "$test_failure"
_error_exit
fi
finalize_test_case_output failure "$failure_label" "$@"
@@ -1213,63 +1168,24 @@ test_atexit_handler () {
teardown_malloc_check
}
-sanitize_leak_log_message_ () {
- local new="$1" &&
- local old="$2" &&
- local file="$3" &&
-
- printf "With SANITIZE=leak at exit we have %d leak logs, but started with %d
-
-This means that we have a blindspot where git is leaking but we're
-losing the exit code somewhere, or not propagating it appropriately
-upwards!
-
-See the logs at \"%s.*\";
-those logs are reproduced below." \
- "$new" "$old" "$file"
+check_test_results_san_file_empty_ () {
+ test -z "$TEST_RESULTS_SAN_FILE" ||
+ test "$(nr_san_dir_leaks_)" = 0
}
check_test_results_san_file_ () {
- if test -z "$TEST_RESULTS_SAN_FILE"
+ if check_test_results_san_file_empty_
then
return
fi &&
- local old="$TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP" &&
- local new="$(nr_san_dir_leaks_)" &&
-
- if test $new -le $old
- then
- return
- fi &&
- local out="$(sanitize_leak_log_message_ "$new" "$old" "$TEST_RESULTS_SAN_FILE")" &&
- say_color error "$out" &&
- if test "$old" != 0
- then
- echo &&
- say_color error "The logs include output from past runs to avoid" &&
- say_color error "that remove 'test-results' between runs."
- fi &&
say_color error "$(cat "$TEST_RESULTS_SAN_FILE".*)" &&
- if test -n "$passes_sanitize_leak" && test "$test_failure" = 0
- then
- say "As TEST_PASSES_SANITIZE_LEAK=true and our logs show we're leaking, exit non-zero!" &&
- invert_exit_code=t
- elif test -n "$passes_sanitize_leak"
- then
- say "As TEST_PASSES_SANITIZE_LEAK=true and our logs show we're leaking, and we're failing for other reasons too..." &&
- invert_exit_code=
- elif test -n "$sanitize_leak_check" && test "$test_failure" = 0
- then
- say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" &&
- invert_exit_code=
- elif test -n "$sanitize_leak_check"
+ if test "$test_failure" = 0
then
- say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" &&
+ say "Our logs revealed a memory leak, exit non-zero!" &&
invert_exit_code=t
else
- say "With GIT_TEST_SANITIZE_LEAK_LOG=true our logs revealed a memory leak, exit non-zero!" &&
- invert_exit_code=t
+ say "Our logs revealed a memory leak..."
fi
}
@@ -1499,6 +1415,56 @@ GIT_ATTR_NOSYSTEM=1
GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/.."
export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM GIT_CEILING_DIRECTORIES
+# Add libc MALLOC and MALLOC_PERTURB test only if we are not executing
+# the test with valgrind and have not compiled with conflict SANITIZE
+# options.
+if test -n "$valgrind" ||
+ test -n "$SANITIZE_ADDRESS" ||
+ test -n "$SANITIZE_LEAK" ||
+ test -n "$TEST_NO_MALLOC_CHECK"
+then
+ setup_malloc_check () {
+ : nothing
+ }
+ teardown_malloc_check () {
+ : nothing
+ }
+else
+ _USE_GLIBC_TUNABLES=
+ _USE_GLIBC_PRELOAD=libc_malloc_debug.so.0
+ if _GLIBC_VERSION=$(getconf GNU_LIBC_VERSION 2>/dev/null) &&
+ _GLIBC_VERSION=${_GLIBC_VERSION#"glibc "} &&
+ expr 2.34 \<= "$_GLIBC_VERSION" >/dev/null &&
+ stderr=$(LD_PRELOAD=$_USE_GLIBC_PRELOAD git version 2>&1 >/dev/null) &&
+ test -z "$stderr"
+ then
+ _USE_GLIBC_TUNABLES=YesPlease
+ fi
+ setup_malloc_check () {
+ local g
+ local t
+ MALLOC_CHECK_=3 MALLOC_PERTURB_=165
+ export MALLOC_CHECK_ MALLOC_PERTURB_
+ if test -n "$_USE_GLIBC_TUNABLES"
+ then
+ g=
+ LD_PRELOAD=$_USE_GLIBC_PRELOAD
+ for t in \
+ glibc.malloc.check=1 \
+ glibc.malloc.perturb=165
+ do
+ g="${g#:}:$t"
+ done
+ GLIBC_TUNABLES=$g
+ export LD_PRELOAD GLIBC_TUNABLES
+ fi
+ }
+ teardown_malloc_check () {
+ unset MALLOC_CHECK_ MALLOC_PERTURB_
+ unset LD_PRELOAD GLIBC_TUNABLES
+ }
+fi
+
if test -z "$GIT_TEST_CMP"
then
if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT"
@@ -1531,77 +1497,29 @@ then
test_done
fi
-BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK () {
- BAIL_OUT "$1 has no effect except when compiled with SANITIZE=leak"
-}
-
if test -n "$SANITIZE_LEAK"
then
- # Normalize with test_bool_env
- passes_sanitize_leak=
-
- # We need to see TEST_PASSES_SANITIZE_LEAK in "test-tool
- # env-helper" (via test_bool_env)
- export TEST_PASSES_SANITIZE_LEAK
- if test_bool_env TEST_PASSES_SANITIZE_LEAK false
+ rm -rf "$TEST_RESULTS_SAN_DIR"
+ if ! mkdir -p "$TEST_RESULTS_SAN_DIR"
then
- passes_sanitize_leak=t
- fi
-
- if test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check"
- then
- sanitize_leak_check=t
- if test -n "$invert_exit_code"
- then
- BAIL_OUT "cannot use --invert-exit-code under GIT_TEST_PASSING_SANITIZE_LEAK=check"
- fi
-
- if test -z "$passes_sanitize_leak"
- then
- say "in GIT_TEST_PASSING_SANITIZE_LEAK=check mode, setting --invert-exit-code for TEST_PASSES_SANITIZE_LEAK != true"
- invert_exit_code=t
- fi
- elif test -z "$passes_sanitize_leak" &&
- test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
- then
- skip_all="skipping $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=true"
- test_done
- fi
-
- if test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false
- then
- if ! mkdir -p "$TEST_RESULTS_SAN_DIR"
- then
- BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR"
- fi &&
- TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX"
-
- # In case "test-results" is left over from a previous
- # run: Only report if new leaks show up.
- TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_)
+ BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR"
+ fi &&
+ TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX"
- # Don't litter *.leak dirs if there was nothing to report
- test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :"
+ # Don't litter *.leak dirs if there was nothing to report
+ test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :"
- prepend_var LSAN_OPTIONS : dedup_token_length=9999
- prepend_var LSAN_OPTIONS : log_exe_name=1
- prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\"
- export LSAN_OPTIONS
- fi
-elif test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" ||
- test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
-then
- BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_PASSING_SANITIZE_LEAK=true"
-elif test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false
-then
- BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true"
+ prepend_var LSAN_OPTIONS : dedup_token_length=9999
+ prepend_var LSAN_OPTIONS : log_exe_name=1
+ prepend_var LSAN_OPTIONS : log_path="'$TEST_RESULTS_SAN_FILE'"
+ export LSAN_OPTIONS
fi
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)"
+ BUG "lint error (see 'LINT' annotations above)"
fi
# Last-minute variable setup
@@ -1745,10 +1663,20 @@ parisc* | hppa*)
;;
esac
-test_set_prereq REFFILES
+case "$GIT_DEFAULT_REF_FORMAT" in
+files)
+ test_set_prereq REFFILES;;
+reftable)
+ test_set_prereq REFTABLE;;
+*)
+ echo 2>&1 "error: unknown ref format $GIT_DEFAULT_REF_FORMAT"
+ exit 1
+ ;;
+esac
( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1
test -z "$NO_CURL" && test_set_prereq LIBCURL
+test -z "$NO_ICONV" && test_set_prereq ICONV
test -z "$NO_PERL" && test_set_prereq PERL
test -z "$NO_PTHREADS" && test_set_prereq PTHREADS
test -z "$NO_PYTHON" && test_set_prereq PYTHON
@@ -1936,12 +1864,17 @@ test_lazy_prereq SHA1 '
esac
'
+test_lazy_prereq DEFAULT_REPO_FORMAT '
+ test_have_prereq SHA1,REFFILES
+'
+
# Ensure that no test accidentally triggers a Git command
# that runs the actual maintenance scheduler, affecting a user's
# system permanently.
# Tests that verify the scheduler integration must set this locally
# to avoid errors.
GIT_TEST_MAINT_SCHEDULER="none:exit 1"
+export GIT_TEST_MAINT_SCHEDULER
# Does this platform support `git fsmonitor--daemon`
#
diff --git a/t/test-terminal.perl b/t/test-terminal.perl
index 1bcf01a9a4..b8fd6a4f13 100755
--- a/t/test-terminal.perl
+++ b/t/test-terminal.perl
@@ -1,21 +1,19 @@
#!/usr/bin/perl
-use 5.008;
+use 5.008001;
use strict;
use warnings;
use IO::Pty;
use File::Copy;
-# Run @$argv in the background with stdio redirected to $in, $out and $err.
+# Run @$argv in the background with stdio redirected to $out and $err.
sub start_child {
- my ($argv, $in, $out, $err) = @_;
+ my ($argv, $out, $err) = @_;
my $pid = fork;
if (not defined $pid) {
die "fork failed: $!"
} elsif ($pid == 0) {
- open STDIN, "<&", $in;
open STDOUT, ">&", $out;
open STDERR, ">&", $err;
- close $in;
close $out;
exec(@$argv) or die "cannot exec '$argv->[0]': $!"
}
@@ -51,17 +49,6 @@ sub xsendfile {
copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
}
-sub copy_stdin {
- my ($in) = @_;
- my $pid = fork;
- if (!$pid) {
- xsendfile($in, \*STDIN);
- exit 0;
- }
- close($in);
- return $pid;
-}
-
sub copy_stdio {
my ($out, $err) = @_;
my $pid = fork;
@@ -81,25 +68,15 @@ if ($#ARGV < 1) {
die "usage: test-terminal program args";
}
$ENV{TERM} = 'vt100';
-my $parent_in = new IO::Pty;
my $parent_out = new IO::Pty;
my $parent_err = new IO::Pty;
-$parent_in->set_raw();
$parent_out->set_raw();
$parent_err->set_raw();
-$parent_in->slave->set_raw();
$parent_out->slave->set_raw();
$parent_err->slave->set_raw();
-my $pid = start_child(\@ARGV, $parent_in->slave, $parent_out->slave, $parent_err->slave);
-close $parent_in->slave;
+my $pid = start_child(\@ARGV, $parent_out->slave, $parent_err->slave);
close $parent_out->slave;
close $parent_err->slave;
-my $in_pid = copy_stdin($parent_in);
copy_stdio($parent_out, $parent_err);
my $ret = finish_child($pid);
-# If the child process terminates before our copy_stdin() process is able to
-# write all of its data to $parent_in, the copy_stdin() process could stall.
-# Send SIGTERM to it to ensure it terminates.
-kill 'TERM', $in_pid;
-finish_child($in_pid);
exit($ret);
diff --git a/t/unit-tests/.gitignore b/t/unit-tests/.gitignore
new file mode 100644
index 0000000000..d0632ec7f9
--- /dev/null
+++ b/t/unit-tests/.gitignore
@@ -0,0 +1,3 @@
+/bin
+/clar.suite
+/clar-decls.h
diff --git a/t/unit-tests/clar/.editorconfig b/t/unit-tests/clar/.editorconfig
new file mode 100644
index 0000000000..aa343a4288
--- /dev/null
+++ b/t/unit-tests/clar/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+charset = utf-8
+insert_final_newline = true
+
+[*.{c,h}]
+indent_style = tab
+tab_width = 8
+
+[CMakeLists.txt]
+indent_style = tab
+tab_width = 8
diff --git a/t/unit-tests/clar/.github/workflows/ci.yml b/t/unit-tests/clar/.github/workflows/ci.yml
new file mode 100644
index 0000000000..0065843d17
--- /dev/null
+++ b/t/unit-tests/clar/.github/workflows/ci.yml
@@ -0,0 +1,35 @@
+name: CI
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ platform:
+ - os: ubuntu-latest
+ generator: Unix Makefiles
+ - os: macos-latest
+ generator: Unix Makefiles
+ - os: windows-latest
+ generator: Visual Studio 17 2022
+ - os: windows-latest
+ generator: MSYS Makefiles
+ - os: windows-latest
+ generator: MinGW Makefiles
+
+ runs-on: ${{ matrix.platform.os }}
+
+ steps:
+ - name: Check out
+ uses: actions/checkout@v2
+ - name: Build
+ run: |
+ mkdir build
+ cd build
+ cmake .. -G "${{matrix.platform.generator}}"
+ cmake --build .
diff --git a/t/unit-tests/clar/.gitignore b/t/unit-tests/clar/.gitignore
new file mode 100644
index 0000000000..84c048a73c
--- /dev/null
+++ b/t/unit-tests/clar/.gitignore
@@ -0,0 +1 @@
+/build/
diff --git a/t/unit-tests/clar/CMakeLists.txt b/t/unit-tests/clar/CMakeLists.txt
new file mode 100644
index 0000000000..12d4af114f
--- /dev/null
+++ b/t/unit-tests/clar/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.16..3.29)
+
+project(clar LANGUAGES C)
+
+option(BUILD_TESTS "Build test executable" ON)
+
+add_library(clar INTERFACE)
+target_sources(clar INTERFACE
+ clar.c
+ clar.h
+ clar/fixtures.h
+ clar/fs.h
+ clar/print.h
+ clar/sandbox.h
+ clar/summary.h
+)
+set_target_properties(clar PROPERTIES
+ C_STANDARD 90
+ C_STANDARD_REQUIRED ON
+ C_EXTENSIONS OFF
+)
+
+if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
+ include(CTest)
+ if(BUILD_TESTING)
+ add_subdirectory(test)
+ endif()
+endif()
diff --git a/t/unit-tests/clar/COPYING b/t/unit-tests/clar/COPYING
new file mode 100644
index 0000000000..8983817f0c
--- /dev/null
+++ b/t/unit-tests/clar/COPYING
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2011-2015 Vicent Marti
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/t/unit-tests/clar/README.md b/t/unit-tests/clar/README.md
new file mode 100644
index 0000000000..a8961c5f10
--- /dev/null
+++ b/t/unit-tests/clar/README.md
@@ -0,0 +1,329 @@
+Come out and Clar
+=================
+
+In Catalan, "clar" means clear, easy to perceive. Using clar will make it
+easy to test and make clear the quality of your code.
+
+> _Historical note_
+>
+> Originally the clar project was named "clay" because the word "test" has its
+> roots in the latin word *"testum"*, meaning "earthen pot", and *"testa"*,
+> meaning "piece of burned clay"?
+>
+> This is because historically, testing implied melting metal in a pot to
+> check its quality. Clay is what tests are made of.
+
+## Quick Usage Overview
+
+Clar is a minimal C unit testing framework. It's been written to replace the
+old framework in [libgit2][libgit2], but it's both very versatile and
+straightforward to use.
+
+Can you count to funk?
+
+- **Zero: Initialize test directory**
+
+ ~~~~ sh
+ $ mkdir tests
+ $ cp -r $CLAR_ROOT/clar* tests
+ $ cp $CLAR_ROOT/test/clar_test.h tests
+ $ cp $CLAR_ROOT/test/main.c.sample tests/main.c
+ ~~~~
+
+- **One: Write some tests**
+
+ File: tests/adding.c:
+
+ ~~~~ c
+ /* adding.c for the "Adding" suite */
+ #include "clar.h"
+
+ static int *answer;
+
+ void test_adding__initialize(void)
+ {
+ answer = malloc(sizeof(int));
+ cl_assert_(answer != NULL, "No memory left?");
+ *answer = 42;
+ }
+
+ void test_adding__cleanup(void)
+ {
+ free(answer);
+ }
+
+ void test_adding__make_sure_math_still_works(void)
+ {
+ cl_assert_(5 > 3, "Five should probably be greater than three");
+ cl_assert_(-5 < 2, "Negative numbers are small, I think");
+ cl_assert_(*answer == 42, "The universe is doing OK. And the initializer too.");
+ }
+ ~~~~~
+
+- **Two: Build the test executable**
+
+ ~~~~ sh
+ $ cd tests
+ $ $CLAR_PATH/generate.py .
+ Written `clar.suite` (1 suites)
+ $ gcc -I. clar.c main.c adding.c -o testit
+ ~~~~
+
+- **Funk: Funk it.**
+
+ ~~~~ sh
+ $ ./testit
+ ~~~~
+
+## The Clar Test Suite
+
+Writing a test suite is pretty straightforward. Each test suite is a `*.c`
+file with a descriptive name: this encourages modularity.
+
+Each test suite has optional initialize and cleanup methods. These methods
+will be called before and after running **each** test in the suite, even if
+such test fails. As a rule of thumb, if a test needs a different initializer
+or cleanup method than another test in the same module, that means it
+doesn't belong in that module. Keep that in mind when grouping tests
+together.
+
+The `initialize` and `cleanup` methods have the following syntax, with
+`suitename` being the current suite name, e.g. `adding` for the `adding.c`
+suite.
+
+~~~~ c
+void test_suitename__initialize(void)
+{
+ /* init */
+}
+
+void test_suitename__cleanup(void)
+{
+ /* cleanup */
+}
+~~~~
+
+These methods are encouraged to use static, global variables to store the state
+that will be used by all tests inside the suite.
+
+~~~~ c
+static git_repository *_repository;
+
+void test_status__initialize(void)
+{
+ create_tmp_repo(STATUS_REPO);
+ git_repository_open(_repository, STATUS_REPO);
+}
+
+void test_status__cleanup(void)
+{
+ git_repository_close(_repository);
+ git_path_rm(STATUS_REPO);
+}
+
+void test_status__simple_test(void)
+{
+ /* do something with _repository */
+}
+~~~~
+
+Writing the actual tests is just as straightforward. Tests have the
+`void test_suitename__test_name(void)` signature, and they should **not**
+be static. Clar will automatically detect and list them.
+
+Tests are run as they appear on their original suites: they have no return
+value. A test is considered "passed" if it doesn't raise any errors. Check
+the "Clar API" section to see the various helper functions to check and
+raise errors during test execution.
+
+__Caution:__ If you use assertions inside of `test_suitename__initialize`,
+make sure that you do not rely on `__initialize` being completely run
+inside your `test_suitename__cleanup` function. Otherwise you might
+encounter ressource cleanup twice.
+
+## How does Clar work?
+
+To use Clar:
+
+1. copy the Clar boilerplate to your test directory
+2. copy (and probably modify) the sample `main.c` (from
+ `$CLAR_PATH/test/main.c.sample`)
+3. run the Clar mixer (a.k.a. `generate.py`) to scan your test directory and
+ write out the test suite metadata.
+4. compile your test files and the Clar boilerplate into a single test
+ executable
+5. run the executable to test!
+
+The Clar boilerplate gives you a set of useful test assertions and features
+(like accessing or making sandbox copies of fixture data). It consists of
+the `clar.c` and `clar.h` files, plus the code in the `clar/` subdirectory.
+You should not need to edit these files.
+
+The sample `main.c` (i.e. `$CLAR_PATH/test/main.c.sample`) file invokes
+`clar_test(argc, argv)` to run the tests. Usually, you will edit this file
+to perform any framework specific initialization and teardown that you need.
+
+The Clar mixer (`generate.py`) recursively scans your test directory for
+any `.c` files, parses them, and writes the `clar.suite` file with all of
+the metadata about your tests. When you build, the `clar.suite` file is
+included into `clar.c`.
+
+The mixer can be run with **Python 2.5, 2.6, 2.7, 3.0, 3.1, 3.2 and PyPy 1.6**.
+
+Commandline usage of the mixer is as follows:
+
+ $ ./generate.py .
+
+Where `.` is the folder where all the test suites can be found. The mixer
+will automatically locate all the relevant source files and build the
+testing metadata. The metadata will be written to `clar.suite`, in the same
+folder as all the test suites. This file is included by `clar.c` and so
+must be accessible via `#include` when building the test executable.
+
+ $ gcc -I. clar.c main.c suite1.c test2.c -o run_tests
+
+**Note that the Clar mixer only needs to be ran when adding new tests to a
+suite, in order to regenerate the metadata**. As a result, the `clar.suite`
+file can be checked into version control if you wish to be able to build
+your test suite without having to re-run the mixer.
+
+This is handy when e.g. generating tests in a local computer, and then
+building and testing them on an embedded device or a platform where Python
+is not available.
+
+### Fixtures
+
+Clar can create sandboxed fixtures for you to use in your test. You'll need to compile *clar.c* with an additional `CFLAG`, `-DCLAR_FIXTURE_PATH`. This should be an absolute path to your fixtures directory.
+
+Once that's done, you can use the fixture API as defined below.
+
+## The Clar API
+
+Clar makes the following methods available from all functions in a test
+suite.
+
+- `cl_must_pass(call)`, `cl_must_pass_(call, message)`: Verify that the given
+ function call passes, in the POSIX sense (returns a value greater or equal
+ to 0).
+
+- `cl_must_fail(call)`, `cl_must_fail_(call, message)`: Verify that the given
+ function call fails, in the POSIX sense (returns a value less than 0).
+
+- `cl_assert(expr)`, `cl_assert_(expr, message)`: Verify that `expr` is true.
+
+- `cl_check_pass(call)`, `cl_check_pass_(call, message)`: Verify that the
+ given function call passes, in the POSIX sense (returns a value greater or
+ equal to 0). If the function call doesn't succeed, a test failure will be
+ logged but the test's execution will continue.
+
+- `cl_check_fail(call)`, `cl_check_fail_(call, message)`: Verify that the
+ given function call fails, in the POSIX sense (returns a value less than
+ 0). If the function call doesn't fail, a test failure will be logged but
+ the test's execution will continue.
+
+- `cl_check(expr)`: Verify that `expr` is true. If `expr` is not
+ true, a test failure will be logged but the test's execution will continue.
+
+- `cl_fail(message)`: Fail the current test with the given message.
+
+- `cl_warning(message)`: Issue a warning. This warning will be
+ logged as a test failure but the test's execution will continue.
+
+- `cl_set_cleanup(void (*cleanup)(void *), void *opaque)`: Set the cleanup
+ method for a single test. This method will be called with `opaque` as its
+ argument before the test returns (even if the test has failed).
+ If a global cleanup method is also available, the local cleanup will be
+ called first, and then the global.
+
+- `cl_assert_equal_i(int,int)`: Verify that two integer values are equal.
+ The advantage of this over a simple `cl_assert` is that it will format
+ a much nicer error report if the values are not equal.
+
+- `cl_assert_equal_s(const char *,const char *)`: Verify that two strings
+ are equal. The expected value can also be NULL and this will correctly
+ test for that.
+
+- `cl_fixture_sandbox(const char *)`: Sets up a sandbox for a fixture
+ so that you can mutate the file directly.
+
+- `cl_fixture_cleanup(const char *)`: Tears down the previous fixture
+ sandbox.
+
+- `cl_fixture(const char *)`: Gets the full path to a fixture file.
+
+Please do note that these methods are *always* available whilst running a
+test, even when calling auxiliary/static functions inside the same file.
+
+It's strongly encouraged to perform test assertions in auxiliary methods,
+instead of returning error values. This is considered good Clar style.
+
+Style Example:
+
+~~~~ c
+/*
+ * Bad style: auxiliary functions return an error code
+ */
+
+static int check_string(const char *str)
+{
+ const char *aux = process_string(str);
+
+ if (aux == NULL)
+ return -1;
+
+ return strcmp(my_function(aux), str) == 0 ? 0 : -1;
+}
+
+void test_example__a_test_with_auxiliary_methods(void)
+{
+ cl_must_pass_(
+ check_string("foo"),
+ "String differs after processing"
+ );
+
+ cl_must_pass_(
+ check_string("bar"),
+ "String differs after processing"
+ );
+}
+~~~~
+
+~~~~ c
+/*
+ * Good style: auxiliary functions perform assertions
+ */
+
+static void check_string(const char *str)
+{
+ const char *aux = process_string(str);
+
+ cl_assert_(
+ aux != NULL,
+ "String processing failed"
+ );
+
+ cl_assert_(
+ strcmp(my_function(aux), str) == 0,
+ "String differs after processing"
+ );
+}
+
+void test_example__a_test_with_auxiliary_methods(void)
+{
+ check_string("foo");
+ check_string("bar");
+}
+~~~~
+
+About Clar
+==========
+
+Clar has been written from scratch by [Vicent Martí](https://github.com/vmg),
+to replace the old testing framework in [libgit2][libgit2].
+
+Do you know what languages are *in* on the SF startup scene? Node.js *and*
+Latin. Follow [@vmg](https://www.twitter.com/vmg) on Twitter to
+receive more lessons on word etymology. You can be hip too.
+
+
+[libgit2]: https://github.com/libgit2/libgit2
diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c
new file mode 100644
index 0000000000..d54e455367
--- /dev/null
+++ b/t/unit-tests/clar/clar.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+
+#define _BSD_SOURCE
+#define _DARWIN_C_SOURCE
+#define _DEFAULT_SOURCE
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <time.h>
+#include <inttypes.h>
+
+/* required for sandboxing */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_WCHAR__)
+ /*
+ * uClibc can optionally be built without wchar support, in which case
+ * the installed <wchar.h> is a stub that only defines the `whar_t`
+ * type but none of the functions typically declared by it.
+ */
+#else
+# define CLAR_HAVE_WCHAR
+#endif
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+# include <direct.h>
+
+# define _MAIN_CC __cdecl
+
+# ifndef stat
+# define stat(path, st) _stat(path, st)
+ typedef struct _stat STAT_T;
+# else
+ typedef struct stat STAT_T;
+# endif
+# ifndef mkdir
+# define mkdir(path, mode) _mkdir(path)
+# endif
+# ifndef chdir
+# define chdir(path) _chdir(path)
+# endif
+# ifndef access
+# define access(path, mode) _access(path, mode)
+# endif
+# ifndef strdup
+# define strdup(str) _strdup(str)
+# endif
+# ifndef strcasecmp
+# define strcasecmp(a,b) _stricmp(a,b)
+# endif
+
+# ifndef __MINGW32__
+# pragma comment(lib, "shell32")
+# ifndef strncpy
+# define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE)
+# endif
+# ifndef W_OK
+# define W_OK 02
+# endif
+# ifndef S_ISDIR
+# define S_ISDIR(x) ((x & _S_IFDIR) != 0)
+# endif
+# define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
+# else
+# define p_snprintf snprintf
+# endif
+#else
+# include <sys/wait.h> /* waitpid(2) */
+# include <unistd.h>
+# define _MAIN_CC
+# define p_snprintf snprintf
+ typedef struct stat STAT_T;
+#endif
+
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+#include "clar.h"
+
+static void fs_rm(const char *_source);
+static void fs_copy(const char *_source, const char *dest);
+
+#ifdef CLAR_FIXTURE_PATH
+static const char *
+fixture_path(const char *base, const char *fixture_name);
+#endif
+
+struct clar_error {
+ const char *file;
+ const char *function;
+ uintmax_t line_number;
+ const char *error_msg;
+ char *description;
+
+ struct clar_error *next;
+};
+
+struct clar_explicit {
+ size_t suite_idx;
+ const char *filter;
+
+ struct clar_explicit *next;
+};
+
+struct clar_report {
+ const char *test;
+ int test_number;
+ const char *suite;
+
+ enum cl_test_status status;
+ time_t start;
+ double elapsed;
+
+ struct clar_error *errors;
+ struct clar_error *last_error;
+
+ struct clar_report *next;
+};
+
+struct clar_summary {
+ const char *filename;
+ FILE *fp;
+};
+
+static struct {
+ enum cl_test_status test_status;
+
+ const char *active_test;
+ const char *active_suite;
+
+ int total_skipped;
+ int total_errors;
+
+ int tests_ran;
+ int suites_ran;
+
+ enum cl_output_format output_format;
+
+ int report_errors_only;
+ int exit_on_error;
+ int verbosity;
+
+ int write_summary;
+ char *summary_filename;
+ struct clar_summary *summary;
+
+ struct clar_explicit *explicit;
+ struct clar_explicit *last_explicit;
+
+ struct clar_report *reports;
+ struct clar_report *last_report;
+
+ void (*local_cleanup)(void *);
+ void *local_cleanup_payload;
+
+ jmp_buf trampoline;
+ int trampoline_enabled;
+
+ cl_trace_cb *pfn_trace_cb;
+ void *trace_payload;
+
+} _clar;
+
+struct clar_func {
+ const char *name;
+ void (*ptr)(void);
+};
+
+struct clar_suite {
+ const char *name;
+ struct clar_func initialize;
+ struct clar_func cleanup;
+ const struct clar_func *tests;
+ size_t test_count;
+ int enabled;
+};
+
+/* From clar_print_*.c */
+static void clar_print_init(int test_count, int suite_count, const char *suite_names);
+static void clar_print_shutdown(int test_count, int suite_count, int error_count);
+static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error);
+static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status failed);
+static void clar_print_onsuite(const char *suite_name, int suite_index);
+static void clar_print_onabortv(const char *msg, va_list argp);
+static void clar_print_onabort(const char *msg, ...);
+
+/* From clar_sandbox.c */
+static void clar_unsandbox(void);
+static void clar_sandbox(void);
+
+/* From summary.h */
+static struct clar_summary *clar_summary_init(const char *filename);
+static int clar_summary_shutdown(struct clar_summary *fp);
+
+/* Load the declarations for the test suite */
+#include "clar.suite"
+
+
+#define CL_TRACE(ev) \
+ do { \
+ if (_clar.pfn_trace_cb) \
+ _clar.pfn_trace_cb(ev, \
+ _clar.active_suite, \
+ _clar.active_test, \
+ _clar.trace_payload); \
+ } while (0)
+
+static void clar_abort(const char *msg, ...)
+{
+ va_list argp;
+ va_start(argp, msg);
+ clar_print_onabortv(msg, argp);
+ va_end(argp);
+ exit(-1);
+}
+
+void cl_trace_register(cl_trace_cb *cb, void *payload)
+{
+ _clar.pfn_trace_cb = cb;
+ _clar.trace_payload = payload;
+}
+
+
+/* Core test functions */
+static void
+clar_report_errors(struct clar_report *report)
+{
+ struct clar_error *error;
+ int i = 1;
+
+ for (error = report->errors; error; error = error->next)
+ clar_print_error(i++, _clar.last_report, error);
+}
+
+static void
+clar_report_all(void)
+{
+ struct clar_report *report;
+ struct clar_error *error;
+ int i = 1;
+
+ for (report = _clar.reports; report; report = report->next) {
+ if (report->status != CL_TEST_FAILURE)
+ continue;
+
+ for (error = report->errors; error; error = error->next)
+ clar_print_error(i++, report, error);
+ }
+}
+
+#ifdef WIN32
+# define clar_time DWORD
+
+static void clar_time_now(clar_time *out)
+{
+ *out = GetTickCount();
+}
+
+static double clar_time_diff(clar_time *start, clar_time *end)
+{
+ return ((double)*end - (double)*start) / 1000;
+}
+#else
+# include <sys/time.h>
+
+# define clar_time struct timeval
+
+static void clar_time_now(clar_time *out)
+{
+ gettimeofday(out, NULL);
+}
+
+static double clar_time_diff(clar_time *start, clar_time *end)
+{
+ return ((double)end->tv_sec + (double)end->tv_usec / 1.0E6) -
+ ((double)start->tv_sec + (double)start->tv_usec / 1.0E6);
+}
+#endif
+
+static void
+clar_run_test(
+ const struct clar_suite *suite,
+ const struct clar_func *test,
+ const struct clar_func *initialize,
+ const struct clar_func *cleanup)
+{
+ clar_time start, end;
+
+ _clar.trampoline_enabled = 1;
+
+ CL_TRACE(CL_TRACE__TEST__BEGIN);
+
+ _clar.last_report->start = time(NULL);
+ clar_time_now(&start);
+
+ if (setjmp(_clar.trampoline) == 0) {
+ if (initialize->ptr != NULL)
+ initialize->ptr();
+
+ CL_TRACE(CL_TRACE__TEST__RUN_BEGIN);
+ test->ptr();
+ CL_TRACE(CL_TRACE__TEST__RUN_END);
+ }
+
+ clar_time_now(&end);
+
+ _clar.trampoline_enabled = 0;
+
+ if (_clar.last_report->status == CL_TEST_NOTRUN)
+ _clar.last_report->status = CL_TEST_OK;
+
+ _clar.last_report->elapsed = clar_time_diff(&start, &end);
+
+ if (_clar.local_cleanup != NULL)
+ _clar.local_cleanup(_clar.local_cleanup_payload);
+
+ if (cleanup->ptr != NULL)
+ cleanup->ptr();
+
+ CL_TRACE(CL_TRACE__TEST__END);
+
+ _clar.tests_ran++;
+
+ /* remove any local-set cleanup methods */
+ _clar.local_cleanup = NULL;
+ _clar.local_cleanup_payload = NULL;
+
+ if (_clar.report_errors_only) {
+ clar_report_errors(_clar.last_report);
+ } else {
+ clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status);
+ }
+}
+
+static void
+clar_run_suite(const struct clar_suite *suite, const char *filter)
+{
+ const struct clar_func *test = suite->tests;
+ size_t i, matchlen;
+ struct clar_report *report;
+ int exact = 0;
+
+ if (!suite->enabled)
+ return;
+
+ if (_clar.exit_on_error && _clar.total_errors)
+ return;
+
+ if (!_clar.report_errors_only)
+ clar_print_onsuite(suite->name, ++_clar.suites_ran);
+
+ _clar.active_suite = suite->name;
+ _clar.active_test = NULL;
+ CL_TRACE(CL_TRACE__SUITE_BEGIN);
+
+ if (filter) {
+ size_t suitelen = strlen(suite->name);
+ matchlen = strlen(filter);
+ if (matchlen <= suitelen) {
+ filter = NULL;
+ } else {
+ filter += suitelen;
+ while (*filter == ':')
+ ++filter;
+ matchlen = strlen(filter);
+
+ if (matchlen && filter[matchlen - 1] == '$') {
+ exact = 1;
+ matchlen--;
+ }
+ }
+ }
+
+ for (i = 0; i < suite->test_count; ++i) {
+ if (filter && strncmp(test[i].name, filter, matchlen))
+ continue;
+
+ if (exact && strlen(test[i].name) != matchlen)
+ continue;
+
+ _clar.active_test = test[i].name;
+
+ if ((report = calloc(1, sizeof(*report))) == NULL)
+ clar_abort("Failed to allocate report.\n");
+ report->suite = _clar.active_suite;
+ report->test = _clar.active_test;
+ report->test_number = _clar.tests_ran;
+ report->status = CL_TEST_NOTRUN;
+
+ if (_clar.reports == NULL)
+ _clar.reports = report;
+
+ if (_clar.last_report != NULL)
+ _clar.last_report->next = report;
+
+ _clar.last_report = report;
+
+ clar_run_test(suite, &test[i], &suite->initialize, &suite->cleanup);
+
+ if (_clar.exit_on_error && _clar.total_errors)
+ return;
+ }
+
+ _clar.active_test = NULL;
+ CL_TRACE(CL_TRACE__SUITE_END);
+}
+
+static void
+clar_usage(const char *arg)
+{
+ printf("Usage: %s [options]\n\n", arg);
+ printf("Options:\n");
+ printf(" -sname Run only the suite with `name` (can go to individual test name)\n");
+ printf(" -iname Include the suite with `name`\n");
+ printf(" -xname Exclude the suite with `name`\n");
+ printf(" -v Increase verbosity (show suite names)\n");
+ printf(" -q Only report tests that had an error\n");
+ printf(" -Q Quit as soon as a test fails\n");
+ printf(" -t Display results in tap format\n");
+ printf(" -l Print suite names\n");
+ printf(" -r[filename] Write summary file (to the optional filename)\n");
+ exit(-1);
+}
+
+static void
+clar_parse_args(int argc, char **argv)
+{
+ int i;
+
+ /* Verify options before execute */
+ for (i = 1; i < argc; ++i) {
+ char *argument = argv[i];
+
+ if (argument[0] != '-' || argument[1] == '\0'
+ || strchr("sixvqQtlr", argument[1]) == NULL) {
+ clar_usage(argv[0]);
+ }
+ }
+
+ for (i = 1; i < argc; ++i) {
+ char *argument = argv[i];
+
+ switch (argument[1]) {
+ case 's':
+ case 'i':
+ case 'x': { /* given suite name */
+ int offset = (argument[2] == '=') ? 3 : 2, found = 0;
+ char action = argument[1];
+ size_t j, arglen, suitelen, cmplen;
+
+ argument += offset;
+ arglen = strlen(argument);
+
+ if (arglen == 0)
+ clar_usage(argv[0]);
+
+ for (j = 0; j < _clar_suite_count; ++j) {
+ suitelen = strlen(_clar_suites[j].name);
+ cmplen = (arglen < suitelen) ? arglen : suitelen;
+
+ if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) {
+ int exact = (arglen >= suitelen);
+
+ /* Do we have a real suite prefix separated by a
+ * trailing '::' or just a matching substring? */
+ if (arglen > suitelen && (argument[suitelen] != ':'
+ || argument[suitelen + 1] != ':'))
+ continue;
+
+ ++found;
+
+ if (!exact)
+ _clar.verbosity = MAX(_clar.verbosity, 1);
+
+ switch (action) {
+ case 's': {
+ struct clar_explicit *explicit;
+
+ if ((explicit = calloc(1, sizeof(*explicit))) == NULL)
+ clar_abort("Failed to allocate explicit test.\n");
+
+ explicit->suite_idx = j;
+ explicit->filter = argument;
+
+ if (_clar.explicit == NULL)
+ _clar.explicit = explicit;
+
+ if (_clar.last_explicit != NULL)
+ _clar.last_explicit->next = explicit;
+
+ _clar_suites[j].enabled = 1;
+ _clar.last_explicit = explicit;
+ break;
+ }
+ case 'i': _clar_suites[j].enabled = 1; break;
+ case 'x': _clar_suites[j].enabled = 0; break;
+ }
+
+ if (exact)
+ break;
+ }
+ }
+
+ if (!found)
+ clar_abort("No suite matching '%s' found.\n", argument);
+ break;
+ }
+
+ case 'q':
+ _clar.report_errors_only = 1;
+ break;
+
+ case 'Q':
+ _clar.exit_on_error = 1;
+ break;
+
+ case 't':
+ _clar.output_format = CL_OUTPUT_TAP;
+ break;
+
+ case 'l': {
+ size_t j;
+ printf("Test suites (use -s<name> to run just one):\n");
+ for (j = 0; j < _clar_suite_count; ++j)
+ printf(" %3d: %s\n", (int)j, _clar_suites[j].name);
+
+ exit(0);
+ }
+
+ case 'v':
+ _clar.verbosity++;
+ break;
+
+ case 'r':
+ _clar.write_summary = 1;
+ free(_clar.summary_filename);
+ if (*(argument + 2)) {
+ if ((_clar.summary_filename = strdup(argument + 2)) == NULL)
+ clar_abort("Failed to allocate summary filename.\n");
+ } else {
+ _clar.summary_filename = NULL;
+ }
+ break;
+
+ default:
+ clar_abort("Unexpected commandline argument '%s'.\n",
+ argument[1]);
+ }
+ }
+}
+
+void
+clar_test_init(int argc, char **argv)
+{
+ const char *summary_env;
+
+ if (argc > 1)
+ clar_parse_args(argc, argv);
+
+ clar_print_init(
+ (int)_clar_callback_count,
+ (int)_clar_suite_count,
+ ""
+ );
+
+ if (!_clar.summary_filename &&
+ (summary_env = getenv("CLAR_SUMMARY")) != NULL) {
+ _clar.write_summary = 1;
+ if ((_clar.summary_filename = strdup(summary_env)) == NULL)
+ clar_abort("Failed to allocate summary filename.\n");
+ }
+
+ if (_clar.write_summary && !_clar.summary_filename)
+ if ((_clar.summary_filename = strdup("summary.xml")) == NULL)
+ clar_abort("Failed to allocate summary filename.\n");
+
+ if (_clar.write_summary)
+ _clar.summary = clar_summary_init(_clar.summary_filename);
+
+ clar_sandbox();
+}
+
+int
+clar_test_run(void)
+{
+ size_t i;
+ struct clar_explicit *explicit;
+
+ if (_clar.explicit) {
+ for (explicit = _clar.explicit; explicit; explicit = explicit->next)
+ clar_run_suite(&_clar_suites[explicit->suite_idx], explicit->filter);
+ } else {
+ for (i = 0; i < _clar_suite_count; ++i)
+ clar_run_suite(&_clar_suites[i], NULL);
+ }
+
+ return _clar.total_errors;
+}
+
+void
+clar_test_shutdown(void)
+{
+ struct clar_explicit *explicit, *explicit_next;
+ struct clar_report *report, *report_next;
+
+ clar_print_shutdown(
+ _clar.tests_ran,
+ (int)_clar_suite_count,
+ _clar.total_errors
+ );
+
+ clar_unsandbox();
+
+ if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0)
+ clar_abort("Failed to write the summary file '%s: %s.\n",
+ _clar.summary_filename, strerror(errno));
+
+ for (explicit = _clar.explicit; explicit; explicit = explicit_next) {
+ explicit_next = explicit->next;
+ free(explicit);
+ }
+
+ for (report = _clar.reports; report; report = report_next) {
+ report_next = report->next;
+ free(report);
+ }
+
+ free(_clar.summary_filename);
+}
+
+int
+clar_test(int argc, char **argv)
+{
+ int errors;
+
+ clar_test_init(argc, argv);
+ errors = clar_test_run();
+ clar_test_shutdown();
+
+ return errors;
+}
+
+static void abort_test(void)
+{
+ if (!_clar.trampoline_enabled) {
+ clar_print_onabort(
+ "Fatal error: a cleanup method raised an exception.\n");
+ clar_report_errors(_clar.last_report);
+ exit(-1);
+ }
+
+ CL_TRACE(CL_TRACE__TEST__LONGJMP);
+ longjmp(_clar.trampoline, -1);
+}
+
+void clar__skip(void)
+{
+ _clar.last_report->status = CL_TEST_SKIP;
+ _clar.total_skipped++;
+ abort_test();
+}
+
+void clar__fail(
+ const char *file,
+ const char *function,
+ size_t line,
+ const char *error_msg,
+ const char *description,
+ int should_abort)
+{
+ struct clar_error *error;
+
+ if ((error = calloc(1, sizeof(*error))) == NULL)
+ clar_abort("Failed to allocate error.\n");
+
+ if (_clar.last_report->errors == NULL)
+ _clar.last_report->errors = error;
+
+ if (_clar.last_report->last_error != NULL)
+ _clar.last_report->last_error->next = error;
+
+ _clar.last_report->last_error = error;
+
+ error->file = file;
+ error->function = function;
+ error->line_number = line;
+ error->error_msg = error_msg;
+
+ if (description != NULL &&
+ (error->description = strdup(description)) == NULL)
+ clar_abort("Failed to allocate description.\n");
+
+ _clar.total_errors++;
+ _clar.last_report->status = CL_TEST_FAILURE;
+
+ if (should_abort)
+ abort_test();
+}
+
+void clar__assert(
+ int condition,
+ const char *file,
+ const char *function,
+ size_t line,
+ const char *error_msg,
+ const char *description,
+ int should_abort)
+{
+ if (condition)
+ return;
+
+ clar__fail(file, function, line, error_msg, description, should_abort);
+}
+
+void clar__assert_equal(
+ const char *file,
+ const char *function,
+ size_t line,
+ const char *err,
+ int should_abort,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ char buf[4096];
+ int is_equal = 1;
+
+ va_start(args, fmt);
+
+ if (!strcmp("%s", fmt)) {
+ const char *s1 = va_arg(args, const char *);
+ const char *s2 = va_arg(args, const char *);
+ is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2);
+
+ if (!is_equal) {
+ if (s1 && s2) {
+ int pos;
+ for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos)
+ /* find differing byte offset */;
+ p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)",
+ s1, s2, pos);
+ } else {
+ p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2);
+ }
+ }
+ }
+ else if(!strcmp("%.*s", fmt)) {
+ const char *s1 = va_arg(args, const char *);
+ const char *s2 = va_arg(args, const char *);
+ int len = va_arg(args, int);
+ is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len);
+
+ if (!is_equal) {
+ if (s1 && s2) {
+ int pos;
+ for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos)
+ /* find differing byte offset */;
+ p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)",
+ len, s1, len, s2, pos);
+ } else {
+ p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2);
+ }
+ }
+ }
+#ifdef CLAR_HAVE_WCHAR
+ else if (!strcmp("%ls", fmt)) {
+ const wchar_t *wcs1 = va_arg(args, const wchar_t *);
+ const wchar_t *wcs2 = va_arg(args, const wchar_t *);
+ is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2);
+
+ if (!is_equal) {
+ if (wcs1 && wcs2) {
+ int pos;
+ for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos)
+ /* find differing byte offset */;
+ p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)",
+ wcs1, wcs2, pos);
+ } else {
+ p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2);
+ }
+ }
+ }
+ else if(!strcmp("%.*ls", fmt)) {
+ const wchar_t *wcs1 = va_arg(args, const wchar_t *);
+ const wchar_t *wcs2 = va_arg(args, const wchar_t *);
+ int len = va_arg(args, int);
+ is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len);
+
+ if (!is_equal) {
+ if (wcs1 && wcs2) {
+ int pos;
+ for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos)
+ /* find differing byte offset */;
+ p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)",
+ len, wcs1, len, wcs2, pos);
+ } else {
+ p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2);
+ }
+ }
+ }
+#endif /* CLAR_HAVE_WCHAR */
+ else if (!strcmp("%"PRIuMAX, fmt) || !strcmp("%"PRIxMAX, fmt)) {
+ uintmax_t sz1 = va_arg(args, uintmax_t), sz2 = va_arg(args, uintmax_t);
+ is_equal = (sz1 == sz2);
+ if (!is_equal) {
+ int offset = p_snprintf(buf, sizeof(buf), fmt, sz1);
+ strncat(buf, " != ", sizeof(buf) - offset);
+ p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2);
+ }
+ }
+ else if (!strcmp("%p", fmt)) {
+ void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *);
+ is_equal = (p1 == p2);
+ if (!is_equal)
+ p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2);
+ }
+ else {
+ int i1 = va_arg(args, int), i2 = va_arg(args, int);
+ is_equal = (i1 == i2);
+ if (!is_equal) {
+ int offset = p_snprintf(buf, sizeof(buf), fmt, i1);
+ strncat(buf, " != ", sizeof(buf) - offset);
+ p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2);
+ }
+ }
+
+ va_end(args);
+
+ if (!is_equal)
+ clar__fail(file, function, line, err, buf, should_abort);
+}
+
+void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
+{
+ _clar.local_cleanup = cleanup;
+ _clar.local_cleanup_payload = opaque;
+}
+
+#include "clar/sandbox.h"
+#include "clar/fixtures.h"
+#include "clar/fs.h"
+#include "clar/print.h"
+#include "clar/summary.h"
diff --git a/t/unit-tests/clar/clar.h b/t/unit-tests/clar/clar.h
new file mode 100644
index 0000000000..8c22382bd5
--- /dev/null
+++ b/t/unit-tests/clar/clar.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+#ifndef __CLAR_TEST_H__
+#define __CLAR_TEST_H__
+
+#include <stdlib.h>
+
+enum cl_test_status {
+ CL_TEST_OK,
+ CL_TEST_FAILURE,
+ CL_TEST_SKIP,
+ CL_TEST_NOTRUN,
+};
+
+enum cl_output_format {
+ CL_OUTPUT_CLAP,
+ CL_OUTPUT_TAP,
+};
+
+/** Setup clar environment */
+void clar_test_init(int argc, char *argv[]);
+int clar_test_run(void);
+void clar_test_shutdown(void);
+
+/** One shot setup & run */
+int clar_test(int argc, char *argv[]);
+
+const char *clar_sandbox_path(void);
+
+void cl_set_cleanup(void (*cleanup)(void *), void *opaque);
+void cl_fs_cleanup(void);
+
+/**
+ * cl_trace_* is a hook to provide a simple global tracing
+ * mechanism.
+ *
+ * The goal here is to let main() provide clar-proper
+ * with a callback to optionally write log info for
+ * test operations into the same stream used by their
+ * actual tests. This would let them print test names
+ * and maybe performance data as they choose.
+ *
+ * The goal is NOT to alter the flow of control or to
+ * override test selection/skipping. (So the callback
+ * does not return a value.)
+ *
+ * The goal is NOT to duplicate the existing
+ * pass/fail/skip reporting. (So the callback
+ * does not accept a status/errorcode argument.)
+ *
+ */
+typedef enum cl_trace_event {
+ CL_TRACE__SUITE_BEGIN,
+ CL_TRACE__SUITE_END,
+ CL_TRACE__TEST__BEGIN,
+ CL_TRACE__TEST__END,
+ CL_TRACE__TEST__RUN_BEGIN,
+ CL_TRACE__TEST__RUN_END,
+ CL_TRACE__TEST__LONGJMP,
+} cl_trace_event;
+
+typedef void (cl_trace_cb)(
+ cl_trace_event ev,
+ const char *suite_name,
+ const char *test_name,
+ void *payload);
+
+/**
+ * Register a callback into CLAR to send global trace events.
+ * Pass NULL to disable.
+ */
+void cl_trace_register(cl_trace_cb *cb, void *payload);
+
+
+#ifdef CLAR_FIXTURE_PATH
+const char *cl_fixture(const char *fixture_name);
+void cl_fixture_sandbox(const char *fixture_name);
+void cl_fixture_cleanup(const char *fixture_name);
+const char *cl_fixture_basename(const char *fixture_name);
+#endif
+
+/**
+ * Assertion macros with explicit error message
+ */
+#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 1)
+#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
+#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 1)
+
+/**
+ * Check macros with explicit error message
+ */
+#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 0)
+#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
+#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 0)
+
+/**
+ * Assertion macros with no error message
+ */
+#define cl_must_pass(expr) cl_must_pass_(expr, NULL)
+#define cl_must_fail(expr) cl_must_fail_(expr, NULL)
+#define cl_assert(expr) cl_assert_(expr, NULL)
+
+/**
+ * Check macros with no error message
+ */
+#define cl_check_pass(expr) cl_check_pass_(expr, NULL)
+#define cl_check_fail(expr) cl_check_fail_(expr, NULL)
+#define cl_check(expr) cl_check_(expr, NULL)
+
+/**
+ * Forced failure/warning
+ */
+#define cl_fail(desc) clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1)
+#define cl_warning(desc) clar__fail(__FILE__, __func__, __LINE__, "Warning during test execution:", desc, 0)
+
+#define cl_skip() clar__skip()
+
+/**
+ * Typed assertion macros
+ */
+#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2))
+#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2))
+
+#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2))
+#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2))
+
+#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len))
+#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len))
+
+#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
+#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
+
+#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
+#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
+#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
+
+#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__func__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
+
+#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__func__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2))
+
+void clar__skip(void);
+
+void clar__fail(
+ const char *file,
+ const char *func,
+ size_t line,
+ const char *error,
+ const char *description,
+ int should_abort);
+
+void clar__assert(
+ int condition,
+ const char *file,
+ const char *func,
+ size_t line,
+ const char *error,
+ const char *description,
+ int should_abort);
+
+void clar__assert_equal(
+ const char *file,
+ const char *func,
+ size_t line,
+ const char *err,
+ int should_abort,
+ const char *fmt,
+ ...);
+
+#endif
diff --git a/t/unit-tests/clar/clar/fixtures.h b/t/unit-tests/clar/clar/fixtures.h
new file mode 100644
index 0000000000..6ec6423484
--- /dev/null
+++ b/t/unit-tests/clar/clar/fixtures.h
@@ -0,0 +1,50 @@
+#ifdef CLAR_FIXTURE_PATH
+static const char *
+fixture_path(const char *base, const char *fixture_name)
+{
+ static char _path[4096];
+ size_t root_len;
+
+ root_len = strlen(base);
+ strncpy(_path, base, sizeof(_path));
+
+ if (_path[root_len - 1] != '/')
+ _path[root_len++] = '/';
+
+ if (fixture_name[0] == '/')
+ fixture_name++;
+
+ strncpy(_path + root_len,
+ fixture_name,
+ sizeof(_path) - root_len);
+
+ return _path;
+}
+
+const char *cl_fixture(const char *fixture_name)
+{
+ return fixture_path(CLAR_FIXTURE_PATH, fixture_name);
+}
+
+void cl_fixture_sandbox(const char *fixture_name)
+{
+ fs_copy(cl_fixture(fixture_name), _clar_path);
+}
+
+const char *cl_fixture_basename(const char *fixture_name)
+{
+ const char *p;
+
+ for (p = fixture_name; *p; p++) {
+ if (p[0] == '/' && p[1] && p[1] != '/')
+ fixture_name = p+1;
+ }
+
+ return fixture_name;
+}
+
+void cl_fixture_cleanup(const char *fixture_name)
+{
+ fs_rm(fixture_path(_clar_path, cl_fixture_basename(fixture_name)));
+}
+#endif
diff --git a/t/unit-tests/clar/clar/fs.h b/t/unit-tests/clar/clar/fs.h
new file mode 100644
index 0000000000..8b206179fc
--- /dev/null
+++ b/t/unit-tests/clar/clar/fs.h
@@ -0,0 +1,524 @@
+/*
+ * By default, use a read/write loop to copy files on POSIX systems.
+ * On Linux, use sendfile by default as it's slightly faster. On
+ * macOS, we avoid fcopyfile by default because it's slightly slower.
+ */
+#undef USE_FCOPYFILE
+#define USE_SENDFILE 1
+
+#ifdef _WIN32
+
+#ifdef CLAR_WIN32_LONGPATHS
+# define CLAR_MAX_PATH 4096
+#else
+# define CLAR_MAX_PATH MAX_PATH
+#endif
+
+#define RM_RETRY_COUNT 5
+#define RM_RETRY_DELAY 10
+
+#ifdef __MINGW32__
+
+/* These security-enhanced functions are not available
+ * in MinGW, so just use the vanilla ones */
+#define wcscpy_s(a, b, c) wcscpy((a), (c))
+#define wcscat_s(a, b, c) wcscat((a), (c))
+
+#endif /* __MINGW32__ */
+
+static int
+fs__dotordotdot(WCHAR *_tocheck)
+{
+ return _tocheck[0] == '.' &&
+ (_tocheck[1] == '\0' ||
+ (_tocheck[1] == '.' && _tocheck[2] == '\0'));
+}
+
+static int
+fs_rmdir_rmdir(WCHAR *_wpath)
+{
+ unsigned retries = 1;
+
+ while (!RemoveDirectoryW(_wpath)) {
+ /* Only retry when we have retries remaining, and the
+ * error was ERROR_DIR_NOT_EMPTY. */
+ if (retries++ > RM_RETRY_COUNT ||
+ ERROR_DIR_NOT_EMPTY != GetLastError())
+ return -1;
+
+ /* Give whatever has a handle to a child item some time
+ * to release it before trying again */
+ Sleep(RM_RETRY_DELAY * retries * retries);
+ }
+
+ return 0;
+}
+
+static void translate_path(WCHAR *path, size_t path_size)
+{
+ size_t path_len, i;
+
+ if (wcsncmp(path, L"\\\\?\\", 4) == 0)
+ return;
+
+ path_len = wcslen(path);
+ cl_assert(path_size > path_len + 4);
+
+ for (i = path_len; i > 0; i--) {
+ WCHAR c = path[i - 1];
+
+ if (c == L'/')
+ path[i + 3] = L'\\';
+ else
+ path[i + 3] = path[i - 1];
+ }
+
+ path[0] = L'\\';
+ path[1] = L'\\';
+ path[2] = L'?';
+ path[3] = L'\\';
+ path[path_len + 4] = L'\0';
+}
+
+static void
+fs_rmdir_helper(WCHAR *_wsource)
+{
+ WCHAR buffer[CLAR_MAX_PATH];
+ HANDLE find_handle;
+ WIN32_FIND_DATAW find_data;
+ size_t buffer_prefix_len;
+
+ /* Set up the buffer and capture the length */
+ wcscpy_s(buffer, CLAR_MAX_PATH, _wsource);
+ translate_path(buffer, CLAR_MAX_PATH);
+ wcscat_s(buffer, CLAR_MAX_PATH, L"\\");
+ buffer_prefix_len = wcslen(buffer);
+
+ /* FindFirstFile needs a wildcard to match multiple items */
+ wcscat_s(buffer, CLAR_MAX_PATH, L"*");
+ find_handle = FindFirstFileW(buffer, &find_data);
+ cl_assert(INVALID_HANDLE_VALUE != find_handle);
+
+ do {
+ /* FindFirstFile/FindNextFile gives back . and ..
+ * entries at the beginning */
+ if (fs__dotordotdot(find_data.cFileName))
+ continue;
+
+ wcscpy_s(buffer + buffer_prefix_len, CLAR_MAX_PATH - buffer_prefix_len, find_data.cFileName);
+
+ if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
+ fs_rmdir_helper(buffer);
+ else {
+ /* If set, the +R bit must be cleared before deleting */
+ if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes)
+ cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY));
+
+ cl_assert(DeleteFileW(buffer));
+ }
+ }
+ while (FindNextFileW(find_handle, &find_data));
+
+ /* Ensure that we successfully completed the enumeration */
+ cl_assert(ERROR_NO_MORE_FILES == GetLastError());
+
+ /* Close the find handle */
+ FindClose(find_handle);
+
+ /* Now that the directory is empty, remove it */
+ cl_assert(0 == fs_rmdir_rmdir(_wsource));
+}
+
+static int
+fs_rm_wait(WCHAR *_wpath)
+{
+ unsigned retries = 1;
+ DWORD last_error;
+
+ do {
+ if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath))
+ last_error = GetLastError();
+ else
+ last_error = ERROR_SUCCESS;
+
+ /* Is the item gone? */
+ if (ERROR_FILE_NOT_FOUND == last_error ||
+ ERROR_PATH_NOT_FOUND == last_error)
+ return 0;
+
+ Sleep(RM_RETRY_DELAY * retries * retries);
+ }
+ while (retries++ <= RM_RETRY_COUNT);
+
+ return -1;
+}
+
+static void
+fs_rm(const char *_source)
+{
+ WCHAR wsource[CLAR_MAX_PATH];
+ DWORD attrs;
+
+ /* The input path is UTF-8. Convert it to wide characters
+ * for use with the Windows API */
+ cl_assert(MultiByteToWideChar(CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ _source,
+ -1, /* Indicates NULL termination */
+ wsource,
+ CLAR_MAX_PATH));
+
+ translate_path(wsource, CLAR_MAX_PATH);
+
+ /* Does the item exist? If not, we have no work to do */
+ attrs = GetFileAttributesW(wsource);
+
+ if (INVALID_FILE_ATTRIBUTES == attrs)
+ return;
+
+ if (FILE_ATTRIBUTE_DIRECTORY & attrs)
+ fs_rmdir_helper(wsource);
+ else {
+ /* The item is a file. Strip the +R bit */
+ if (FILE_ATTRIBUTE_READONLY & attrs)
+ cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY));
+
+ cl_assert(DeleteFileW(wsource));
+ }
+
+ /* Wait for the DeleteFile or RemoveDirectory call to complete */
+ cl_assert(0 == fs_rm_wait(wsource));
+}
+
+static void
+fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
+{
+ WCHAR buf_source[CLAR_MAX_PATH], buf_dest[CLAR_MAX_PATH];
+ HANDLE find_handle;
+ WIN32_FIND_DATAW find_data;
+ size_t buf_source_prefix_len, buf_dest_prefix_len;
+
+ wcscpy_s(buf_source, CLAR_MAX_PATH, _wsource);
+ wcscat_s(buf_source, CLAR_MAX_PATH, L"\\");
+ translate_path(buf_source, CLAR_MAX_PATH);
+ buf_source_prefix_len = wcslen(buf_source);
+
+ wcscpy_s(buf_dest, CLAR_MAX_PATH, _wdest);
+ wcscat_s(buf_dest, CLAR_MAX_PATH, L"\\");
+ translate_path(buf_dest, CLAR_MAX_PATH);
+ buf_dest_prefix_len = wcslen(buf_dest);
+
+ /* Get an enumerator for the items in the source. */
+ wcscat_s(buf_source, CLAR_MAX_PATH, L"*");
+ find_handle = FindFirstFileW(buf_source, &find_data);
+ cl_assert(INVALID_HANDLE_VALUE != find_handle);
+
+ /* Create the target directory. */
+ cl_assert(CreateDirectoryW(_wdest, NULL));
+
+ do {
+ /* FindFirstFile/FindNextFile gives back . and ..
+ * entries at the beginning */
+ if (fs__dotordotdot(find_data.cFileName))
+ continue;
+
+ wcscpy_s(buf_source + buf_source_prefix_len, CLAR_MAX_PATH - buf_source_prefix_len, find_data.cFileName);
+ wcscpy_s(buf_dest + buf_dest_prefix_len, CLAR_MAX_PATH - buf_dest_prefix_len, find_data.cFileName);
+
+ if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
+ fs_copydir_helper(buf_source, buf_dest);
+ else
+ cl_assert(CopyFileW(buf_source, buf_dest, TRUE));
+ }
+ while (FindNextFileW(find_handle, &find_data));
+
+ /* Ensure that we successfully completed the enumeration */
+ cl_assert(ERROR_NO_MORE_FILES == GetLastError());
+
+ /* Close the find handle */
+ FindClose(find_handle);
+}
+
+static void
+fs_copy(const char *_source, const char *_dest)
+{
+ WCHAR wsource[CLAR_MAX_PATH], wdest[CLAR_MAX_PATH];
+ DWORD source_attrs, dest_attrs;
+ HANDLE find_handle;
+ WIN32_FIND_DATAW find_data;
+
+ /* The input paths are UTF-8. Convert them to wide characters
+ * for use with the Windows API. */
+ cl_assert(MultiByteToWideChar(CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ _source,
+ -1,
+ wsource,
+ CLAR_MAX_PATH));
+
+ cl_assert(MultiByteToWideChar(CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ _dest,
+ -1,
+ wdest,
+ CLAR_MAX_PATH));
+
+ translate_path(wsource, CLAR_MAX_PATH);
+ translate_path(wdest, CLAR_MAX_PATH);
+
+ /* Check the source for existence */
+ source_attrs = GetFileAttributesW(wsource);
+ cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs);
+
+ /* Check the target for existence */
+ dest_attrs = GetFileAttributesW(wdest);
+
+ if (INVALID_FILE_ATTRIBUTES != dest_attrs) {
+ /* Target exists; append last path part of source to target.
+ * Use FindFirstFile to parse the path */
+ find_handle = FindFirstFileW(wsource, &find_data);
+ cl_assert(INVALID_HANDLE_VALUE != find_handle);
+ wcscat_s(wdest, CLAR_MAX_PATH, L"\\");
+ wcscat_s(wdest, CLAR_MAX_PATH, find_data.cFileName);
+ FindClose(find_handle);
+
+ /* Check the new target for existence */
+ cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest));
+ }
+
+ if (FILE_ATTRIBUTE_DIRECTORY & source_attrs)
+ fs_copydir_helper(wsource, wdest);
+ else
+ cl_assert(CopyFileW(wsource, wdest, TRUE));
+}
+
+void
+cl_fs_cleanup(void)
+{
+#ifdef CLAR_FIXTURE_PATH
+ fs_rm(fixture_path(_clar_path, "*"));
+#else
+ ((void)fs_copy); /* unused */
+#endif
+}
+
+#else
+
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__linux__)
+# include <sys/sendfile.h>
+#endif
+
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
+static void basename_r(const char **out, int *out_len, const char *in)
+{
+ size_t in_len = strlen(in), start_pos;
+
+ for (in_len = strlen(in); in_len; in_len--) {
+ if (in[in_len - 1] != '/')
+ break;
+ }
+
+ for (start_pos = in_len; start_pos; start_pos--) {
+ if (in[start_pos - 1] == '/')
+ break;
+ }
+
+ cl_assert(in_len - start_pos < INT_MAX);
+
+ if (in_len - start_pos > 0) {
+ *out = &in[start_pos];
+ *out_len = (in_len - start_pos);
+ } else {
+ *out = "/";
+ *out_len = 1;
+ }
+}
+
+static char *joinpath(const char *dir, const char *base, int base_len)
+{
+ char *out;
+ int len;
+
+ if (base_len == -1) {
+ size_t bl = strlen(base);
+
+ cl_assert(bl < INT_MAX);
+ base_len = (int)bl;
+ }
+
+ len = strlen(dir) + base_len + 2;
+ cl_assert(len > 0);
+
+ cl_assert(out = malloc(len));
+ cl_assert(snprintf(out, len, "%s/%.*s", dir, base_len, base) < len);
+
+ return out;
+}
+
+static void
+fs_copydir_helper(const char *source, const char *dest, int dest_mode)
+{
+ DIR *source_dir;
+ struct dirent *d;
+
+ mkdir(dest, dest_mode);
+
+ cl_assert_(source_dir = opendir(source), "Could not open source dir");
+ while ((d = (errno = 0, readdir(source_dir))) != NULL) {
+ char *child;
+
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ child = joinpath(source, d->d_name, -1);
+ fs_copy(child, dest);
+ free(child);
+ }
+
+ cl_assert_(errno == 0, "Failed to iterate source dir");
+
+ closedir(source_dir);
+}
+
+static void
+fs_copyfile_helper(const char *source, size_t source_len, const char *dest, int dest_mode)
+{
+ int in, out;
+
+ cl_must_pass((in = open(source, O_RDONLY)));
+ cl_must_pass((out = open(dest, O_WRONLY|O_CREAT|O_TRUNC, dest_mode)));
+
+#if USE_FCOPYFILE && defined(__APPLE__)
+ ((void)(source_len)); /* unused */
+ cl_must_pass(fcopyfile(in, out, 0, COPYFILE_DATA));
+#elif USE_SENDFILE && defined(__linux__)
+ {
+ ssize_t ret = 0;
+
+ while (source_len && (ret = sendfile(out, in, NULL, source_len)) > 0) {
+ source_len -= (size_t)ret;
+ }
+ cl_assert(ret >= 0);
+ }
+#else
+ {
+ char buf[131072];
+ ssize_t ret;
+
+ ((void)(source_len)); /* unused */
+
+ while ((ret = read(in, buf, sizeof(buf))) > 0) {
+ size_t len = (size_t)ret;
+
+ while (len && (ret = write(out, buf, len)) > 0) {
+ cl_assert(ret <= (ssize_t)len);
+ len -= ret;
+ }
+ cl_assert(ret >= 0);
+ }
+ cl_assert(ret == 0);
+ }
+#endif
+
+ close(in);
+ close(out);
+}
+
+static void
+fs_copy(const char *source, const char *_dest)
+{
+ char *dbuf = NULL;
+ const char *dest = NULL;
+ struct stat source_st, dest_st;
+
+ cl_must_pass_(lstat(source, &source_st), "Failed to stat copy source");
+
+ if (lstat(_dest, &dest_st) == 0) {
+ const char *base;
+ int base_len;
+
+ /* Target exists and is directory; append basename */
+ cl_assert(S_ISDIR(dest_st.st_mode));
+
+ basename_r(&base, &base_len, source);
+ cl_assert(base_len < INT_MAX);
+
+ dbuf = joinpath(_dest, base, base_len);
+ dest = dbuf;
+ } else if (errno != ENOENT) {
+ cl_fail("Cannot copy; cannot stat destination");
+ } else {
+ dest = _dest;
+ }
+
+ if (S_ISDIR(source_st.st_mode)) {
+ fs_copydir_helper(source, dest, source_st.st_mode);
+ } else {
+ fs_copyfile_helper(source, source_st.st_size, dest, source_st.st_mode);
+ }
+
+ free(dbuf);
+}
+
+static void
+fs_rmdir_helper(const char *path)
+{
+ DIR *dir;
+ struct dirent *d;
+
+ cl_assert_(dir = opendir(path), "Could not open dir");
+ while ((d = (errno = 0, readdir(dir))) != NULL) {
+ char *child;
+
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ child = joinpath(path, d->d_name, -1);
+ fs_rm(child);
+ free(child);
+ }
+
+ cl_assert_(errno == 0, "Failed to iterate source dir");
+ closedir(dir);
+
+ cl_must_pass_(rmdir(path), "Could not remove directory");
+}
+
+static void
+fs_rm(const char *path)
+{
+ struct stat st;
+
+ if (lstat(path, &st)) {
+ if (errno == ENOENT)
+ return;
+
+ cl_fail("Cannot copy; cannot stat destination");
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ fs_rmdir_helper(path);
+ } else {
+ cl_must_pass(unlink(path));
+ }
+}
+
+void
+cl_fs_cleanup(void)
+{
+ clar_unsandbox();
+ clar_sandbox();
+}
+#endif
diff --git a/t/unit-tests/clar/clar/print.h b/t/unit-tests/clar/clar/print.h
new file mode 100644
index 0000000000..69d0ee967e
--- /dev/null
+++ b/t/unit-tests/clar/clar/print.h
@@ -0,0 +1,216 @@
+/* clap: clar protocol, the traditional clar output format */
+
+static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names)
+{
+ (void)test_count;
+ printf("Loaded %d suites: %s\n", (int)suite_count, suite_names);
+ printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n");
+}
+
+static void clar_print_clap_shutdown(int test_count, int suite_count, int error_count)
+{
+ (void)test_count;
+ (void)suite_count;
+ (void)error_count;
+
+ printf("\n\n");
+ clar_report_all();
+}
+
+static void clar_print_clap_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+ printf(" %d) Failure:\n", num);
+
+ printf("%s::%s [%s:%"PRIuMAX"]\n",
+ report->suite,
+ report->test,
+ error->file,
+ error->line_number);
+
+ printf(" %s\n", error->error_msg);
+
+ if (error->description != NULL)
+ printf(" %s\n", error->description);
+
+ printf("\n");
+ fflush(stdout);
+}
+
+static void clar_print_clap_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status)
+{
+ (void)test_name;
+ (void)test_number;
+
+ if (_clar.verbosity > 1) {
+ printf("%s::%s: ", suite_name, test_name);
+
+ switch (status) {
+ case CL_TEST_OK: printf("ok\n"); break;
+ case CL_TEST_FAILURE: printf("fail\n"); break;
+ case CL_TEST_SKIP: printf("skipped"); break;
+ case CL_TEST_NOTRUN: printf("notrun"); break;
+ }
+ } else {
+ switch (status) {
+ case CL_TEST_OK: printf("."); break;
+ case CL_TEST_FAILURE: printf("F"); break;
+ case CL_TEST_SKIP: printf("S"); break;
+ case CL_TEST_NOTRUN: printf("N"); break;
+ }
+
+ fflush(stdout);
+ }
+}
+
+static void clar_print_clap_onsuite(const char *suite_name, int suite_index)
+{
+ if (_clar.verbosity == 1)
+ printf("\n%s", suite_name);
+
+ (void)suite_index;
+}
+
+static void clar_print_clap_onabort(const char *fmt, va_list arg)
+{
+ vfprintf(stderr, fmt, arg);
+}
+
+/* tap: test anywhere protocol format */
+
+static void clar_print_tap_init(int test_count, int suite_count, const char *suite_names)
+{
+ (void)test_count;
+ (void)suite_count;
+ (void)suite_names;
+ printf("TAP version 13\n");
+}
+
+static void clar_print_tap_shutdown(int test_count, int suite_count, int error_count)
+{
+ (void)suite_count;
+ (void)error_count;
+
+ printf("1..%d\n", test_count);
+}
+
+static void clar_print_tap_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+ (void)num;
+ (void)report;
+ (void)error;
+}
+
+static void print_escaped(const char *str)
+{
+ char *c;
+
+ while ((c = strchr(str, '\'')) != NULL) {
+ printf("%.*s", (int)(c - str), str);
+ printf("''");
+ str = c + 1;
+ }
+
+ printf("%s", str);
+}
+
+static void clar_print_tap_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status)
+{
+ const struct clar_error *error = _clar.last_report->errors;
+
+ (void)test_name;
+ (void)test_number;
+
+ switch(status) {
+ case CL_TEST_OK:
+ printf("ok %d - %s::%s\n", test_number, suite_name, test_name);
+ break;
+ case CL_TEST_FAILURE:
+ printf("not ok %d - %s::%s\n", test_number, suite_name, test_name);
+
+ printf(" ---\n");
+ printf(" reason: |\n");
+ printf(" %s\n", error->error_msg);
+
+ if (error->description)
+ printf(" %s\n", error->description);
+
+ printf(" at:\n");
+ printf(" file: '"); print_escaped(error->file); printf("'\n");
+ printf(" line: %" PRIuMAX "\n", error->line_number);
+ printf(" function: '%s'\n", error->function);
+ printf(" ---\n");
+
+ break;
+ case CL_TEST_SKIP:
+ case CL_TEST_NOTRUN:
+ printf("ok %d - # SKIP %s::%s\n", test_number, suite_name, test_name);
+ break;
+ }
+
+ fflush(stdout);
+}
+
+static void clar_print_tap_onsuite(const char *suite_name, int suite_index)
+{
+ printf("# start of suite %d: %s\n", suite_index, suite_name);
+}
+
+static void clar_print_tap_onabort(const char *fmt, va_list arg)
+{
+ printf("Bail out! ");
+ vprintf(fmt, arg);
+ fflush(stdout);
+}
+
+/* indirection between protocol output selection */
+
+#define PRINT(FN, ...) do { \
+ switch (_clar.output_format) { \
+ case CL_OUTPUT_CLAP: \
+ clar_print_clap_##FN (__VA_ARGS__); \
+ break; \
+ case CL_OUTPUT_TAP: \
+ clar_print_tap_##FN (__VA_ARGS__); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ } while (0)
+
+static void clar_print_init(int test_count, int suite_count, const char *suite_names)
+{
+ PRINT(init, test_count, suite_count, suite_names);
+}
+
+static void clar_print_shutdown(int test_count, int suite_count, int error_count)
+{
+ PRINT(shutdown, test_count, suite_count, error_count);
+}
+
+static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+ PRINT(error, num, report, error);
+}
+
+static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status)
+{
+ PRINT(ontest, suite_name, test_name, test_number, status);
+}
+
+static void clar_print_onsuite(const char *suite_name, int suite_index)
+{
+ PRINT(onsuite, suite_name, suite_index);
+}
+
+static void clar_print_onabortv(const char *msg, va_list argp)
+{
+ PRINT(onabort, msg, argp);
+}
+
+static void clar_print_onabort(const char *msg, ...)
+{
+ va_list argp;
+ va_start(argp, msg);
+ clar_print_onabortv(msg, argp);
+ va_end(argp);
+}
diff --git a/t/unit-tests/clar/clar/sandbox.h b/t/unit-tests/clar/clar/sandbox.h
new file mode 100644
index 0000000000..bc960f50e0
--- /dev/null
+++ b/t/unit-tests/clar/clar/sandbox.h
@@ -0,0 +1,158 @@
+#ifdef __APPLE__
+#include <sys/syslimits.h>
+#endif
+
+static char _clar_path[4096 + 1];
+
+static int
+is_valid_tmp_path(const char *path)
+{
+ STAT_T st;
+
+ if (stat(path, &st) != 0)
+ return 0;
+
+ if (!S_ISDIR(st.st_mode))
+ return 0;
+
+ return (access(path, W_OK) == 0);
+}
+
+static int
+find_tmp_path(char *buffer, size_t length)
+{
+#ifndef _WIN32
+ static const size_t var_count = 5;
+ static const char *env_vars[] = {
+ "CLAR_TMP", "TMPDIR", "TMP", "TEMP", "USERPROFILE"
+ };
+
+ size_t i;
+
+ for (i = 0; i < var_count; ++i) {
+ const char *env = getenv(env_vars[i]);
+ if (!env)
+ continue;
+
+ if (is_valid_tmp_path(env)) {
+#ifdef __APPLE__
+ if (length >= PATH_MAX && realpath(env, buffer) != NULL)
+ return 0;
+#endif
+ strncpy(buffer, env, length - 1);
+ buffer[length - 1] = '\0';
+ return 0;
+ }
+ }
+
+ /* If the environment doesn't say anything, try to use /tmp */
+ if (is_valid_tmp_path("/tmp")) {
+#ifdef __APPLE__
+ if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL)
+ return 0;
+#endif
+ strncpy(buffer, "/tmp", length - 1);
+ buffer[length - 1] = '\0';
+ return 0;
+ }
+
+#else
+ DWORD env_len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length);
+ if (env_len > 0 && env_len < (DWORD)length)
+ return 0;
+
+ if (GetTempPath((DWORD)length, buffer))
+ return 0;
+#endif
+
+ /* This system doesn't like us, try to use the current directory */
+ if (is_valid_tmp_path(".")) {
+ strncpy(buffer, ".", length - 1);
+ buffer[length - 1] = '\0';
+ return 0;
+ }
+
+ return -1;
+}
+
+static void clar_unsandbox(void)
+{
+ if (_clar_path[0] == '\0')
+ return;
+
+ cl_must_pass(chdir(".."));
+
+ fs_rm(_clar_path);
+}
+
+static int build_sandbox_path(void)
+{
+#ifdef CLAR_TMPDIR
+ const char path_tail[] = CLAR_TMPDIR "_XXXXXX";
+#else
+ const char path_tail[] = "clar_tmp_XXXXXX";
+#endif
+
+ size_t len;
+
+ if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0)
+ return -1;
+
+ len = strlen(_clar_path);
+
+#ifdef _WIN32
+ { /* normalize path to POSIX forward slashes */
+ size_t i;
+ for (i = 0; i < len; ++i) {
+ if (_clar_path[i] == '\\')
+ _clar_path[i] = '/';
+ }
+ }
+#endif
+
+ if (_clar_path[len - 1] != '/') {
+ _clar_path[len++] = '/';
+ }
+
+ strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len);
+
+#if defined(__MINGW32__)
+ if (_mktemp(_clar_path) == NULL)
+ return -1;
+
+ if (mkdir(_clar_path, 0700) != 0)
+ return -1;
+#elif defined(_WIN32)
+ if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0)
+ return -1;
+
+ if (mkdir(_clar_path, 0700) != 0)
+ return -1;
+#elif defined(__sun) || defined(__TANDEM)
+ if (mktemp(_clar_path) == NULL)
+ return -1;
+
+ if (mkdir(_clar_path, 0700) != 0)
+ return -1;
+#else
+ if (mkdtemp(_clar_path) == NULL)
+ return -1;
+#endif
+
+ return 0;
+}
+
+static void clar_sandbox(void)
+{
+ if (_clar_path[0] == '\0' && build_sandbox_path() < 0)
+ clar_abort("Failed to build sandbox path.\n");
+
+ if (chdir(_clar_path) != 0)
+ clar_abort("Failed to change into sandbox directory '%s': %s.\n",
+ _clar_path, strerror(errno));
+}
+
+const char *clar_sandbox_path(void)
+{
+ return _clar_path;
+}
diff --git a/t/unit-tests/clar/clar/summary.h b/t/unit-tests/clar/clar/summary.h
new file mode 100644
index 0000000000..0d0b646fe7
--- /dev/null
+++ b/t/unit-tests/clar/clar/summary.h
@@ -0,0 +1,139 @@
+
+#include <stdio.h>
+#include <time.h>
+
+static int clar_summary_close_tag(
+ struct clar_summary *summary, const char *tag, int indent)
+{
+ const char *indt;
+
+ if (indent == 0) indt = "";
+ else if (indent == 1) indt = "\t";
+ else indt = "\t\t";
+
+ return fprintf(summary->fp, "%s</%s>\n", indt, tag);
+}
+
+static int clar_summary_testsuites(struct clar_summary *summary)
+{
+ return fprintf(summary->fp, "<testsuites>\n");
+}
+
+static int clar_summary_testsuite(struct clar_summary *summary,
+ int idn, const char *name, time_t timestamp,
+ int test_count, int fail_count, int error_count)
+{
+ struct tm *tm = localtime(&timestamp);
+ char iso_dt[20];
+
+ if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", tm) == 0)
+ return -1;
+
+ return fprintf(summary->fp, "\t<testsuite"
+ " id=\"%d\""
+ " name=\"%s\""
+ " hostname=\"localhost\""
+ " timestamp=\"%s\""
+ " tests=\"%d\""
+ " failures=\"%d\""
+ " errors=\"%d\">\n",
+ idn, name, iso_dt, test_count, fail_count, error_count);
+}
+
+static int clar_summary_testcase(struct clar_summary *summary,
+ const char *name, const char *classname, double elapsed)
+{
+ return fprintf(summary->fp,
+ "\t\t<testcase name=\"%s\" classname=\"%s\" time=\"%.2f\">\n",
+ name, classname, elapsed);
+}
+
+static int clar_summary_failure(struct clar_summary *summary,
+ const char *type, const char *message, const char *desc)
+{
+ return fprintf(summary->fp,
+ "\t\t\t<failure type=\"%s\"><![CDATA[%s\n%s]]></failure>\n",
+ type, message, desc);
+}
+
+static int clar_summary_skipped(struct clar_summary *summary)
+{
+ return fprintf(summary->fp, "\t\t\t<skipped />\n");
+}
+
+struct clar_summary *clar_summary_init(const char *filename)
+{
+ struct clar_summary *summary;
+ FILE *fp;
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ clar_abort("Failed to open the summary file '%s': %s.\n",
+ filename, strerror(errno));
+
+ if ((summary = malloc(sizeof(struct clar_summary))) == NULL)
+ clar_abort("Failed to allocate summary.\n");
+
+ summary->filename = filename;
+ summary->fp = fp;
+
+ return summary;
+}
+
+int clar_summary_shutdown(struct clar_summary *summary)
+{
+ struct clar_report *report;
+ const char *last_suite = NULL;
+
+ if (clar_summary_testsuites(summary) < 0)
+ goto on_error;
+
+ report = _clar.reports;
+ while (report != NULL) {
+ struct clar_error *error = report->errors;
+
+ if (last_suite == NULL || strcmp(last_suite, report->suite) != 0) {
+ if (clar_summary_testsuite(summary, 0, report->suite,
+ report->start, _clar.tests_ran, _clar.total_errors, 0) < 0)
+ goto on_error;
+ }
+
+ last_suite = report->suite;
+
+ clar_summary_testcase(summary, report->test, report->suite, report->elapsed);
+
+ while (error != NULL) {
+ if (clar_summary_failure(summary, "assert",
+ error->error_msg, error->description) < 0)
+ goto on_error;
+
+ error = error->next;
+ }
+
+ if (report->status == CL_TEST_SKIP)
+ clar_summary_skipped(summary);
+
+ if (clar_summary_close_tag(summary, "testcase", 2) < 0)
+ goto on_error;
+
+ report = report->next;
+
+ if (!report || strcmp(last_suite, report->suite) != 0) {
+ if (clar_summary_close_tag(summary, "testsuite", 1) < 0)
+ goto on_error;
+ }
+ }
+
+ if (clar_summary_close_tag(summary, "testsuites", 0) < 0 ||
+ fclose(summary->fp) != 0)
+ goto on_error;
+
+ printf("written summary file to %s\n", summary->filename);
+
+ free(summary);
+ return 0;
+
+on_error:
+ fclose(summary->fp);
+ free(summary);
+ return -1;
+}
diff --git a/t/unit-tests/clar/generate.py b/t/unit-tests/clar/generate.py
new file mode 100755
index 0000000000..80996ac3e7
--- /dev/null
+++ b/t/unit-tests/clar/generate.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+#
+# Copyright (c) Vicent Marti. All rights reserved.
+#
+# This file is part of clar, distributed under the ISC license.
+# For full terms see the included COPYING file.
+#
+
+from __future__ import with_statement
+from string import Template
+import re, fnmatch, os, sys, codecs, pickle
+
+class Module(object):
+ class Template(object):
+ def __init__(self, module):
+ self.module = module
+
+ def _render_callback(self, cb):
+ if not cb:
+ return ' { NULL, NULL }'
+ return ' { "%s", &%s }' % (cb['short_name'], cb['symbol'])
+
+ class DeclarationTemplate(Template):
+ def render(self):
+ out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n"
+
+ for initializer in self.module.initializers:
+ out += "extern %s;\n" % initializer['declaration']
+
+ if self.module.cleanup:
+ out += "extern %s;\n" % self.module.cleanup['declaration']
+
+ return out
+
+ class CallbacksTemplate(Template):
+ def render(self):
+ out = "static const struct clar_func _clar_cb_%s[] = {\n" % self.module.name
+ out += ",\n".join(self._render_callback(cb) for cb in self.module.callbacks)
+ out += "\n};\n"
+ return out
+
+ class InfoTemplate(Template):
+ def render(self):
+ templates = []
+
+ initializers = self.module.initializers
+ if len(initializers) == 0:
+ initializers = [ None ]
+
+ for initializer in initializers:
+ name = self.module.clean_name()
+ if initializer and initializer['short_name'].startswith('initialize_'):
+ variant = initializer['short_name'][len('initialize_'):]
+ name += " (%s)" % variant.replace('_', ' ')
+
+ template = Template(
+ r"""
+ {
+ "${clean_name}",
+ ${initialize},
+ ${cleanup},
+ ${cb_ptr}, ${cb_count}, ${enabled}
+ }"""
+ ).substitute(
+ clean_name = name,
+ initialize = self._render_callback(initializer),
+ cleanup = self._render_callback(self.module.cleanup),
+ cb_ptr = "_clar_cb_%s" % self.module.name,
+ cb_count = len(self.module.callbacks),
+ enabled = int(self.module.enabled)
+ )
+ templates.append(template)
+
+ return ','.join(templates)
+
+ def __init__(self, name):
+ self.name = name
+
+ self.mtime = None
+ self.enabled = True
+ self.modified = False
+
+ def clean_name(self):
+ return self.name.replace("_", "::")
+
+ def _skip_comments(self, text):
+ SKIP_COMMENTS_REGEX = re.compile(
+ r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+ re.DOTALL | re.MULTILINE)
+
+ def _replacer(match):
+ s = match.group(0)
+ return "" if s.startswith('/') else s
+
+ return re.sub(SKIP_COMMENTS_REGEX, _replacer, text)
+
+ def parse(self, contents):
+ TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\s*\(\s*void\s*\))\s*\{"
+
+ contents = self._skip_comments(contents)
+ regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE)
+
+ self.callbacks = []
+ self.initializers = []
+ self.cleanup = None
+
+ for (declaration, symbol, short_name) in regex.findall(contents):
+ data = {
+ "short_name" : short_name,
+ "declaration" : declaration,
+ "symbol" : symbol
+ }
+
+ if short_name.startswith('initialize'):
+ self.initializers.append(data)
+ elif short_name == 'cleanup':
+ self.cleanup = data
+ else:
+ self.callbacks.append(data)
+
+ return self.callbacks != []
+
+ def refresh(self, path):
+ self.modified = False
+
+ try:
+ st = os.stat(path)
+
+ # Not modified
+ if st.st_mtime == self.mtime:
+ return True
+
+ self.modified = True
+ self.mtime = st.st_mtime
+
+ with codecs.open(path, encoding='utf-8') as fp:
+ raw_content = fp.read()
+
+ except IOError:
+ return False
+
+ return self.parse(raw_content)
+
+class TestSuite(object):
+
+ def __init__(self, path, output):
+ self.path = path
+ self.output = output
+
+ def should_generate(self, path):
+ if not os.path.isfile(path):
+ return True
+
+ if any(module.modified for module in self.modules.values()):
+ return True
+
+ return False
+
+ def find_modules(self):
+ modules = []
+ for root, _, files in os.walk(self.path):
+ module_root = root[len(self.path):]
+ module_root = [c for c in module_root.split(os.sep) if c]
+
+ tests_in_module = fnmatch.filter(files, "*.c")
+
+ for test_file in tests_in_module:
+ full_path = os.path.join(root, test_file)
+ module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_")
+
+ modules.append((full_path, module_name))
+
+ return modules
+
+ def load_cache(self):
+ path = os.path.join(self.output, '.clarcache')
+ cache = {}
+
+ try:
+ fp = open(path, 'rb')
+ cache = pickle.load(fp)
+ fp.close()
+ except (IOError, ValueError):
+ pass
+
+ return cache
+
+ def save_cache(self):
+ path = os.path.join(self.output, '.clarcache')
+ with open(path, 'wb') as cache:
+ pickle.dump(self.modules, cache)
+
+ def load(self, force = False):
+ module_data = self.find_modules()
+ self.modules = {} if force else self.load_cache()
+
+ for path, name in module_data:
+ if name not in self.modules:
+ self.modules[name] = Module(name)
+
+ if not self.modules[name].refresh(path):
+ del self.modules[name]
+
+ def disable(self, excluded):
+ for exclude in excluded:
+ for module in self.modules.values():
+ name = module.clean_name()
+ if name.startswith(exclude):
+ module.enabled = False
+ module.modified = True
+
+ def suite_count(self):
+ return sum(max(1, len(m.initializers)) for m in self.modules.values())
+
+ def callback_count(self):
+ return sum(len(module.callbacks) for module in self.modules.values())
+
+ def write(self):
+ output = os.path.join(self.output, 'clar.suite')
+
+ if not self.should_generate(output):
+ return False
+
+ with open(output, 'w') as data:
+ modules = sorted(self.modules.values(), key=lambda module: module.name)
+
+ for module in modules:
+ t = Module.DeclarationTemplate(module)
+ data.write(t.render())
+
+ for module in modules:
+ t = Module.CallbacksTemplate(module)
+ data.write(t.render())
+
+ suites = "static struct clar_suite _clar_suites[] = {" + ','.join(
+ Module.InfoTemplate(module).render() for module in modules
+ ) + "\n};\n"
+
+ data.write(suites)
+
+ data.write("static const size_t _clar_suite_count = %d;\n" % self.suite_count())
+ data.write("static const size_t _clar_callback_count = %d;\n" % self.callback_count())
+
+ self.save_cache()
+ return True
+
+if __name__ == '__main__':
+ from optparse import OptionParser
+
+ parser = OptionParser()
+ parser.add_option('-f', '--force', action="store_true", dest='force', default=False)
+ parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[])
+ parser.add_option('-o', '--output', dest='output')
+
+ options, args = parser.parse_args()
+ if len(args) > 1:
+ print("More than one path given")
+ sys.exit(1)
+
+ path = args.pop() if args else '.'
+ output = options.output or path
+ suite = TestSuite(path, output)
+ suite.load(options.force)
+ suite.disable(options.excluded)
+ if suite.write():
+ print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count()))
diff --git a/t/unit-tests/clar/test/CMakeLists.txt b/t/unit-tests/clar/test/CMakeLists.txt
new file mode 100644
index 0000000000..7f2c1dc17a
--- /dev/null
+++ b/t/unit-tests/clar/test/CMakeLists.txt
@@ -0,0 +1,39 @@
+find_package(Python COMPONENTS Interpreter REQUIRED)
+
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite"
+ COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}"
+ DEPENDS main.c sample.c clar_test.h
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+)
+
+add_executable(clar_test)
+set_target_properties(clar_test PROPERTIES
+ C_STANDARD 90
+ C_STANDARD_REQUIRED ON
+ C_EXTENSIONS OFF
+)
+
+# MSVC generates all kinds of warnings. We may want to fix these in the future
+# and then unconditionally treat warnings as errors.
+if(NOT MSVC)
+ set_target_properties(clar_test PROPERTIES
+ COMPILE_WARNING_AS_ERROR ON
+ )
+endif()
+
+target_sources(clar_test PRIVATE
+ main.c
+ sample.c
+ "${CMAKE_CURRENT_BINARY_DIR}/clar.suite"
+)
+target_compile_definitions(clar_test PRIVATE
+ CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/"
+)
+target_compile_options(clar_test PRIVATE
+ $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall>
+)
+target_include_directories(clar_test PRIVATE
+ "${CMAKE_SOURCE_DIR}"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+)
+target_link_libraries(clar_test clar)
diff --git a/t/unit-tests/clar/test/clar_test.h b/t/unit-tests/clar/test/clar_test.h
new file mode 100644
index 0000000000..0fcaa639aa
--- /dev/null
+++ b/t/unit-tests/clar/test/clar_test.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+#ifndef __CLAR_TEST__
+#define __CLAR_TEST__
+
+/* Import the standard clar helper functions */
+#include "clar.h"
+
+/* Your custom shared includes / defines here */
+extern int global_test_counter;
+
+#endif
diff --git a/t/unit-tests/clar/test/main.c b/t/unit-tests/clar/test/main.c
new file mode 100644
index 0000000000..59e56ad255
--- /dev/null
+++ b/t/unit-tests/clar/test/main.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+
+#include "clar_test.h"
+
+/*
+ * Sample main() for clar tests.
+ *
+ * You should write your own main routine for clar tests that does specific
+ * setup and teardown as necessary for your application. The only required
+ * line is the call to `clar_test(argc, argv)`, which will execute the test
+ * suite. If you want to check the return value of the test application,
+ * your main() should return the same value returned by clar_test().
+ */
+
+int global_test_counter = 0;
+
+#ifdef _WIN32
+int __cdecl main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ int ret;
+
+ /* Your custom initialization here */
+ global_test_counter = 0;
+
+ /* Run the test suite */
+ ret = clar_test(argc, argv);
+
+ /* Your custom cleanup here */
+ cl_assert_equal_i(8, global_test_counter);
+
+ return ret;
+}
diff --git a/t/unit-tests/clar/test/main.c.sample b/t/unit-tests/clar/test/main.c.sample
new file mode 100644
index 0000000000..a4d91b72fa
--- /dev/null
+++ b/t/unit-tests/clar/test/main.c.sample
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+
+#include "clar_test.h"
+
+/*
+ * Minimal main() for clar tests.
+ *
+ * Modify this with any application specific setup or teardown that you need.
+ * The only required line is the call to `clar_test(argc, argv)`, which will
+ * execute the test suite. If you want to check the return value of the test
+ * application, main() should return the same value returned by clar_test().
+ */
+
+#ifdef _WIN32
+int __cdecl main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ /* Run the test suite */
+ return clar_test(argc, argv);
+}
diff --git a/t/unit-tests/clar/test/resources/test/file b/t/unit-tests/clar/test/resources/test/file
new file mode 100644
index 0000000000..220f4aa98a
--- /dev/null
+++ b/t/unit-tests/clar/test/resources/test/file
@@ -0,0 +1 @@
+File
diff --git a/t/unit-tests/clar/test/sample.c b/t/unit-tests/clar/test/sample.c
new file mode 100644
index 0000000000..faa1209262
--- /dev/null
+++ b/t/unit-tests/clar/test/sample.c
@@ -0,0 +1,84 @@
+#include "clar_test.h"
+#include <sys/stat.h>
+
+static int file_size(const char *filename)
+{
+ struct stat st;
+
+ if (stat(filename, &st) == 0)
+ return (int)st.st_size;
+ return -1;
+}
+
+void test_sample__initialize(void)
+{
+ global_test_counter++;
+}
+
+void test_sample__cleanup(void)
+{
+ cl_fixture_cleanup("test");
+
+ cl_assert(file_size("test/file") == -1);
+}
+
+void test_sample__1(void)
+{
+ cl_assert(1);
+ cl_must_pass(0); /* 0 == success */
+ cl_must_fail(-1); /* <0 == failure */
+ cl_must_pass(-1); /* demonstrate a failing call */
+}
+
+void test_sample__2(void)
+{
+ cl_fixture_sandbox("test");
+
+ cl_assert(file_size("test/nonexistent") == -1);
+ cl_assert(file_size("test/file") > 0);
+ cl_assert(100 == 101);
+}
+
+void test_sample__strings(void)
+{
+ const char *actual = "expected";
+ cl_assert_equal_s("expected", actual);
+ cl_assert_equal_s_("expected", actual, "second try with annotation");
+ cl_assert_equal_s_("mismatched", actual, "this one fails");
+}
+
+void test_sample__strings_with_length(void)
+{
+ const char *actual = "expected";
+ cl_assert_equal_strn("expected_", actual, 8);
+ cl_assert_equal_strn("exactly", actual, 2);
+ cl_assert_equal_strn_("expected_", actual, 8, "with annotation");
+ cl_assert_equal_strn_("exactly", actual, 3, "this one fails");
+}
+
+void test_sample__int(void)
+{
+ int value = 100;
+ cl_assert_equal_i(100, value);
+ cl_assert_equal_i_(101, value, "extra note on failing test");
+}
+
+void test_sample__int_fmt(void)
+{
+ int value = 100;
+ cl_assert_equal_i_fmt(022, value, "%04o");
+}
+
+void test_sample__bool(void)
+{
+ int value = 100;
+ cl_assert_equal_b(1, value); /* test equality as booleans */
+ cl_assert_equal_b(0, value);
+}
+
+void test_sample__ptr(void)
+{
+ const char *actual = "expected";
+ cl_assert_equal_p(actual, actual); /* pointers to same object */
+ cl_assert_equal_p(&actual, actual);
+}
diff --git a/t/unit-tests/ctype.c b/t/unit-tests/ctype.c
new file mode 100644
index 0000000000..32e65867cd
--- /dev/null
+++ b/t/unit-tests/ctype.c
@@ -0,0 +1,102 @@
+#include "unit-test.h"
+
+#define TEST_CHAR_CLASS(class, string) do { \
+ size_t len = ARRAY_SIZE(string) - 1 + \
+ BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \
+ BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \
+ for (int i = 0; i < 256; i++) { \
+ int actual = class(i), expect = !!memchr(string, i, len); \
+ if (actual != expect) \
+ cl_failf("0x%02x is classified incorrectly: expected %d, got %d", \
+ i, expect, actual); \
+ } \
+ cl_assert(!class(EOF)); \
+} while (0)
+
+#define DIGIT "0123456789"
+#define LOWER "abcdefghijklmnopqrstuvwxyz"
+#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+#define ASCII \
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+#define CNTRL \
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "\x7f"
+
+void test_ctype__isspace(void)
+{
+ TEST_CHAR_CLASS(isspace, " \n\r\t");
+}
+
+void test_ctype__isdigit(void)
+{
+ TEST_CHAR_CLASS(isdigit, DIGIT);
+}
+
+void test_ctype__isalpha(void)
+{
+ TEST_CHAR_CLASS(isalpha, LOWER UPPER);
+}
+
+void test_ctype__isalnum(void)
+{
+ TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT);
+}
+
+void test_ctype__is_glob_special(void)
+{
+ TEST_CHAR_CLASS(is_glob_special, "*?[\\");
+}
+
+void test_ctype__is_regex_special(void)
+{
+ TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|");
+}
+
+void test_ctype__is_pathspec_magic(void)
+{
+ TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~");
+}
+
+void test_ctype__isascii(void)
+{
+ TEST_CHAR_CLASS(isascii, ASCII);
+}
+
+void test_ctype__islower(void)
+{
+ TEST_CHAR_CLASS(islower, LOWER);
+}
+
+void test_ctype__isupper(void)
+{
+ TEST_CHAR_CLASS(isupper, UPPER);
+}
+
+void test_ctype__iscntrl(void)
+{
+ TEST_CHAR_CLASS(iscntrl, CNTRL);
+}
+
+void test_ctype__ispunct(void)
+{
+ TEST_CHAR_CLASS(ispunct, PUNCT);
+}
+
+void test_ctype__isxdigit(void)
+{
+ TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF");
+}
+
+void test_ctype__isprint(void)
+{
+ TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " ");
+}
diff --git a/t/unit-tests/generate-clar-decls.sh b/t/unit-tests/generate-clar-decls.sh
new file mode 100755
index 0000000000..688e0885f4
--- /dev/null
+++ b/t/unit-tests/generate-clar-decls.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+if test $# -lt 2
+then
+ echo "USAGE: $0 <OUTPUT> <SUITE>..." 2>&1
+ exit 1
+fi
+
+OUTPUT="$1"
+shift
+
+for suite in "$@"
+do
+ sed -ne "s/^\(void test_$(basename "${suite%.c}")__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)\)$/extern \1;/p" "$suite" ||
+ exit 1
+done >"$OUTPUT"
diff --git a/t/unit-tests/generate-clar-suites.sh b/t/unit-tests/generate-clar-suites.sh
new file mode 100755
index 0000000000..d5c712221e
--- /dev/null
+++ b/t/unit-tests/generate-clar-suites.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+if test $# -lt 2
+then
+ echo "USAGE: $0 <CLAR_DECLS_H> <OUTPUT>" 2>&1
+ exit 1
+fi
+
+CLAR_DECLS_H="$1"
+OUTPUT="$2"
+
+awk '
+ function add_suite(suite, initialize, cleanup, count) {
+ if (!suite) return
+ suite_count++
+ callback_count += count
+ suites = suites " {\n"
+ suites = suites " \"" suite "\",\n"
+ suites = suites " " initialize ",\n"
+ suites = suites " " cleanup ",\n"
+ suites = suites " _clar_cb_" suite ", " count ", 1\n"
+ suites = suites " },\n"
+ }
+
+ BEGIN {
+ suites = "static struct clar_suite _clar_suites[] = {\n"
+ }
+
+ {
+ print
+ name = $3; sub(/\(.*$/, "", name)
+ suite = name; sub(/^test_/, "", suite); sub(/__.*$/, "", suite)
+ short_name = name; sub(/^.*__/, "", short_name)
+ cb = "{ \"" short_name "\", &" name " }"
+ if (suite != prev_suite) {
+ add_suite(prev_suite, initialize, cleanup, count)
+ if (callbacks) callbacks = callbacks "};\n"
+ callbacks = callbacks "static const struct clar_func _clar_cb_" suite "[] = {\n"
+ initialize = "{ NULL, NULL }"
+ cleanup = "{ NULL, NULL }"
+ count = 0
+ prev_suite = suite
+ }
+ if (short_name == "initialize") {
+ initialize = cb
+ } else if (short_name == "cleanup") {
+ cleanup = cb
+ } else {
+ callbacks = callbacks " " cb ",\n"
+ count++
+ }
+ }
+
+ END {
+ add_suite(suite, initialize, cleanup, count)
+ suites = suites "};"
+ if (callbacks) callbacks = callbacks "};"
+ print callbacks
+ print suites
+ print "static const size_t _clar_suite_count = " suite_count ";"
+ print "static const size_t _clar_callback_count = " callback_count ";"
+ }
+' "$CLAR_DECLS_H" >"$OUTPUT"
diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c
new file mode 100644
index 0000000000..8f0ccac532
--- /dev/null
+++ b/t/unit-tests/lib-oid.c
@@ -0,0 +1,52 @@
+#include "test-lib.h"
+#include "lib-oid.h"
+#include "strbuf.h"
+#include "hex.h"
+
+int init_hash_algo(void)
+{
+ static int algo = -1;
+
+ if (algo < 0) {
+ const char *algo_name = getenv("GIT_TEST_DEFAULT_HASH");
+ algo = algo_name ? hash_algo_by_name(algo_name) : GIT_HASH_SHA1;
+
+ if (!check(algo != GIT_HASH_UNKNOWN))
+ test_msg("BUG: invalid GIT_TEST_DEFAULT_HASH value ('%s')",
+ algo_name);
+ }
+ return algo;
+}
+
+static int get_oid_arbitrary_hex_algop(const char *hex, struct object_id *oid,
+ const struct git_hash_algo *algop)
+{
+ int ret;
+ size_t sz = strlen(hex);
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!check(sz <= algop->hexsz)) {
+ test_msg("BUG: hex string (%s) bigger than maximum allowed (%lu)",
+ hex, (unsigned long)algop->hexsz);
+ return -1;
+ }
+
+ strbuf_add(&buf, hex, sz);
+ strbuf_addchars(&buf, '0', algop->hexsz - sz);
+
+ ret = get_oid_hex_algop(buf.buf, oid, algop);
+ if (!check_int(ret, ==, 0))
+ test_msg("BUG: invalid hex input (%s) provided", hex);
+
+ strbuf_release(&buf);
+ return ret;
+}
+
+int get_oid_arbitrary_hex(const char *hex, struct object_id *oid)
+{
+ int hash_algo = init_hash_algo();
+
+ if (!check_int(hash_algo, !=, GIT_HASH_UNKNOWN))
+ return -1;
+ return get_oid_arbitrary_hex_algop(hex, oid, &hash_algos[hash_algo]);
+}
diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h
new file mode 100644
index 0000000000..4e77c04bd2
--- /dev/null
+++ b/t/unit-tests/lib-oid.h
@@ -0,0 +1,25 @@
+#ifndef LIB_OID_H
+#define LIB_OID_H
+
+#include "hash.h"
+
+/*
+ * Convert arbitrary hex string to object_id.
+ * For example, passing "abc12" will generate
+ * "abc1200000000000000000000000000000000000" hex of length 40 for SHA-1 and
+ * create object_id with that.
+ * WARNING: passing a string of length more than the hexsz of respective hash
+ * algo is not allowed. The hash algo is decided based on GIT_TEST_DEFAULT_HASH
+ * environment variable.
+ */
+int get_oid_arbitrary_hex(const char *s, struct object_id *oid);
+/*
+ * Returns one of GIT_HASH_{SHA1, SHA256, UNKNOWN} based on the value of
+ * GIT_TEST_DEFAULT_HASH environment variable. The fallback value in the
+ * absence of GIT_TEST_DEFAULT_HASH is GIT_HASH_SHA1. It also uses
+ * check(algo != GIT_HASH_UNKNOWN) before returning to verify if the
+ * GIT_TEST_DEFAULT_HASH's value is valid or not.
+ */
+int init_hash_algo(void);
+
+#endif /* LIB_OID_H */
diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c
new file mode 100644
index 0000000000..2ddf480588
--- /dev/null
+++ b/t/unit-tests/lib-reftable.c
@@ -0,0 +1,95 @@
+#include "lib-reftable.h"
+#include "test-lib.h"
+#include "reftable/constants.h"
+#include "reftable/writer.h"
+
+void t_reftable_set_hash(uint8_t *p, int i, uint32_t id)
+{
+ memset(p, (uint8_t)i, hash_size(id));
+}
+
+static ssize_t strbuf_writer_write(void *b, const void *data, size_t sz)
+{
+ strbuf_add(b, data, sz);
+ return sz;
+}
+
+static int strbuf_writer_flush(void *arg UNUSED)
+{
+ return 0;
+}
+
+struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf,
+ struct reftable_write_options *opts)
+{
+ struct reftable_writer *writer;
+ int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush,
+ buf, opts);
+ check(!ret);
+ return writer;
+}
+
+void t_reftable_write_to_buf(struct reftable_buf *buf,
+ struct reftable_ref_record *refs,
+ size_t nrefs,
+ struct reftable_log_record *logs,
+ size_t nlogs,
+ struct reftable_write_options *_opts)
+{
+ struct reftable_write_options opts = { 0 };
+ const struct reftable_stats *stats;
+ struct reftable_writer *writer;
+ uint64_t min = 0xffffffff;
+ uint64_t max = 0;
+ int ret;
+
+ if (_opts)
+ opts = *_opts;
+
+ for (size_t i = 0; i < nrefs; i++) {
+ uint64_t ui = refs[i].update_index;
+ if (ui > max)
+ max = ui;
+ if (ui < min)
+ min = ui;
+ }
+ for (size_t i = 0; i < nlogs; i++) {
+ uint64_t ui = logs[i].update_index;
+ if (ui > max)
+ max = ui;
+ if (ui < min)
+ min = ui;
+ }
+
+ writer = t_reftable_strbuf_writer(buf, &opts);
+ reftable_writer_set_limits(writer, min, max);
+
+ if (nrefs) {
+ ret = reftable_writer_add_refs(writer, refs, nrefs);
+ check_int(ret, ==, 0);
+ }
+
+ if (nlogs) {
+ ret = reftable_writer_add_logs(writer, logs, nlogs);
+ check_int(ret, ==, 0);
+ }
+
+ ret = reftable_writer_close(writer);
+ check_int(ret, ==, 0);
+
+ stats = reftable_writer_stats(writer);
+ for (size_t i = 0; i < stats->ref_stats.blocks; i++) {
+ size_t off = i * (opts.block_size ? opts.block_size
+ : DEFAULT_BLOCK_SIZE);
+ if (!off)
+ off = header_size(opts.hash_id == GIT_SHA256_FORMAT_ID ? 2 : 1);
+ check_char(buf->buf[off], ==, 'r');
+ }
+
+ if (nrefs)
+ check_int(stats->ref_stats.blocks, >, 0);
+ if (nlogs)
+ check_int(stats->log_stats.blocks, >, 0);
+
+ reftable_writer_free(writer);
+}
diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h
new file mode 100644
index 0000000000..d4950fed3d
--- /dev/null
+++ b/t/unit-tests/lib-reftable.h
@@ -0,0 +1,21 @@
+#ifndef LIB_REFTABLE_H
+#define LIB_REFTABLE_H
+
+#include "git-compat-util.h"
+#include "reftable/reftable-writer.h"
+
+struct reftable_buf;
+
+void t_reftable_set_hash(uint8_t *p, int i, uint32_t id);
+
+struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf,
+ struct reftable_write_options *opts);
+
+void t_reftable_write_to_buf(struct reftable_buf *buf,
+ struct reftable_ref_record *refs,
+ size_t nrecords,
+ struct reftable_log_record *logs,
+ size_t nlogs,
+ struct reftable_write_options *opts);
+
+#endif
diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c
new file mode 100644
index 0000000000..855b602337
--- /dev/null
+++ b/t/unit-tests/strvec.c
@@ -0,0 +1,306 @@
+#include "unit-test.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define check_strvec(vec, ...) \
+ do { \
+ const char *expect[] = { __VA_ARGS__ }; \
+ size_t expect_len = ARRAY_SIZE(expect); \
+ cl_assert(expect_len > 0); \
+ cl_assert_equal_p(expect[expect_len - 1], NULL); \
+ cl_assert_equal_i((vec)->nr, expect_len - 1); \
+ cl_assert((vec)->nr <= (vec)->alloc); \
+ for (size_t i = 0; i < expect_len; i++) \
+ cl_assert_equal_s((vec)->v[i], expect[i]); \
+ } while (0)
+
+void test_strvec__init(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ cl_assert_equal_p(vec.v, empty_strvec);
+ cl_assert_equal_i(vec.nr, 0);
+ cl_assert_equal_i(vec.alloc, 0);
+}
+
+void test_strvec__dynamic_init(void)
+{
+ struct strvec vec;
+
+ strvec_init(&vec);
+ cl_assert_equal_p(vec.v, empty_strvec);
+ cl_assert_equal_i(vec.nr, 0);
+ cl_assert_equal_i(vec.alloc, 0);
+}
+
+void test_strvec__clear(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_push(&vec, "foo");
+ strvec_clear(&vec);
+ cl_assert_equal_p(vec.v, empty_strvec);
+ cl_assert_equal_i(vec.nr, 0);
+ cl_assert_equal_i(vec.alloc, 0);
+}
+
+void test_strvec__push(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_push(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+
+ strvec_push(&vec, "bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+
+ strvec_clear(&vec);
+}
+
+void test_strvec__pushf(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushf(&vec, "foo: %d", 1);
+ check_strvec(&vec, "foo: 1", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__pushl(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__pushv(void)
+{
+ const char *strings[] = {
+ "foo", "bar", "baz", NULL,
+ };
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushv(&vec, strings);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+
+ strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_same_size_replacement(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char *replacement[] = { "1" };
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_splice(&vec, 1, 1, replacement, ARRAY_SIZE(replacement));
+ check_strvec(&vec, "foo", "1", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_smaller_replacement(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char *replacement[] = { "1" };
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_splice(&vec, 1, 2, replacement, ARRAY_SIZE(replacement));
+ check_strvec(&vec, "foo", "1", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_bigger_replacement(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char *replacement[] = { "1", "2", "3" };
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_splice(&vec, 0, 2, replacement, ARRAY_SIZE(replacement));
+ check_strvec(&vec, "1", "2", "3", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_empty_replacement(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_splice(&vec, 0, 2, NULL, 0);
+ check_strvec(&vec, "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_empty_original(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char *replacement[] = { "1", "2" };
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_splice(&vec, 1, 0, replacement, ARRAY_SIZE(replacement));
+ check_strvec(&vec, "foo", "1", "2", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__splice_at_tail(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char *replacement[] = { "1", "2" };
+
+ strvec_pushl(&vec, "foo", "bar", NULL);
+ strvec_splice(&vec, 2, 0, replacement, ARRAY_SIZE(replacement));
+ check_strvec(&vec, "foo", "bar", "1", "2", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__replace_at_head(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 0, "replaced");
+ check_strvec(&vec, "replaced", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__replace_at_tail(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 2, "replaced");
+ check_strvec(&vec, "foo", "bar", "replaced", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__replace_in_between(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 1, "replaced");
+ check_strvec(&vec, "foo", "replaced", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__replace_with_substring(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", NULL);
+ strvec_replace(&vec, 0, vec.v[0] + 1);
+ check_strvec(&vec, "oo", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__remove_at_head(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 0);
+ check_strvec(&vec, "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__remove_at_tail(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 2);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__remove_in_between(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 1);
+ check_strvec(&vec, "foo", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__pop_empty_array(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pop(&vec);
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__pop_non_empty_array(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_pop(&vec);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__split_empty_string(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_split(&vec, "");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__split_single_item(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_split(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__split_multiple_items(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_split(&vec, "foo bar baz");
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__split_whitespace_only(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_split(&vec, " \t\n");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__split_multiple_consecutive_whitespaces(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_split(&vec, "foo\n\t bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+}
+
+void test_strvec__detach(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char **detached;
+
+ strvec_push(&vec, "foo");
+
+ detached = strvec_detach(&vec);
+ cl_assert_equal_s(detached[0], "foo");
+ cl_assert_equal_p(detached[1], NULL);
+
+ cl_assert_equal_p(vec.v, empty_strvec);
+ cl_assert_equal_i(vec.nr, 0);
+ cl_assert_equal_i(vec.alloc, 0);
+
+ free((char *) detached[0]);
+ free(detached);
+}
diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c
new file mode 100644
index 0000000000..8bf0709c41
--- /dev/null
+++ b/t/unit-tests/t-example-decorate.c
@@ -0,0 +1,74 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "test-lib.h"
+#include "object.h"
+#include "decorate.h"
+#include "repository.h"
+
+struct test_vars {
+ struct object *one, *two, *three;
+ struct decoration n;
+ int decoration_a, decoration_b;
+};
+
+static void t_add(struct test_vars *vars)
+{
+ void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a);
+
+ check(ret == NULL);
+ ret = add_decoration(&vars->n, vars->two, NULL);
+ check(ret == NULL);
+}
+
+static void t_readd(struct test_vars *vars)
+{
+ void *ret = add_decoration(&vars->n, vars->one, NULL);
+
+ check(ret == &vars->decoration_a);
+ ret = add_decoration(&vars->n, vars->two, &vars->decoration_b);
+ check(ret == NULL);
+}
+
+static void t_lookup(struct test_vars *vars)
+{
+ void *ret = lookup_decoration(&vars->n, vars->one);
+
+ check(ret == NULL);
+ ret = lookup_decoration(&vars->n, vars->two);
+ check(ret == &vars->decoration_b);
+ ret = lookup_decoration(&vars->n, vars->three);
+ check(ret == NULL);
+}
+
+static void t_loop(struct test_vars *vars)
+{
+ int i, objects_noticed = 0;
+
+ for (i = 0; i < vars->n.size; i++) {
+ if (vars->n.entries[i].base)
+ objects_noticed++;
+ }
+ check_int(objects_noticed, ==, 2);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } };
+ struct test_vars vars = { 0 };
+
+ vars.one = lookup_unknown_object(the_repository, &one_oid);
+ vars.two = lookup_unknown_object(the_repository, &two_oid);
+ vars.three = lookup_unknown_object(the_repository, &three_oid);
+
+ TEST(t_add(&vars),
+ "Add 2 objects, one with a non-NULL decoration and one with a NULL decoration.");
+ TEST(t_readd(&vars),
+ "When re-adding an already existing object, the old decoration is returned.");
+ TEST(t_lookup(&vars),
+ "Lookup returns the added declarations, or NULL if the object was never added.");
+ TEST(t_loop(&vars), "The user can also loop through all entries.");
+
+ clear_decoration(&vars.n, NULL);
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c
new file mode 100644
index 0000000000..e62647019b
--- /dev/null
+++ b/t/unit-tests/t-hash.c
@@ -0,0 +1,84 @@
+#include "test-lib.h"
+#include "hex.h"
+#include "strbuf.h"
+
+static void check_hash_data(const void *data, size_t data_length,
+ const char *expected_hashes[])
+{
+ if (!check(data != NULL)) {
+ test_msg("BUG: NULL data pointer provided");
+ return;
+ }
+
+ for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) {
+ git_hash_ctx ctx;
+ unsigned char hash[GIT_MAX_HEXSZ];
+ const struct git_hash_algo *algop = &hash_algos[i];
+
+ algop->init_fn(&ctx);
+ algop->update_fn(&ctx, data, data_length);
+ algop->final_fn(hash, &ctx);
+
+ if (!check_str(hash_to_hex_algop(hash, algop), expected_hashes[i - 1]))
+ test_msg("result does not match with the expected for %s\n", hash_algos[i].name);
+ }
+}
+
+/* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */
+#define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \
+ const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \
+ TEST(check_hash_data(data, strlen(data), expected_hashes), \
+ "SHA1 and SHA256 (%s) works", #data); \
+ } while (0)
+
+/* Only works with a literal string, useful when it contains a NUL character. */
+#define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \
+ const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \
+ TEST(check_hash_data(literal, (sizeof(literal) - 1), expected_hashes), \
+ "SHA1 and SHA256 (%s) works", #literal); \
+ } while (0)
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT;
+ struct strbuf alphabet_100000 = STRBUF_INIT;
+
+ strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000);
+ strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000);
+
+ TEST_HASH_STR("",
+ "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+ TEST_HASH_STR("a",
+ "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
+ "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
+ TEST_HASH_STR("abc",
+ "a9993e364706816aba3e25717850c26c9cd0d89d",
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
+ TEST_HASH_STR("message digest",
+ "c12252ceda8be8994d5fa0290a47231c1d16aae3",
+ "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650");
+ TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz",
+ "32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
+ "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73");
+ TEST_HASH_STR(aaaaaaaaaa_100000.buf,
+ "34aa973cd4c4daa4f61eeb2bdbad27316534016f",
+ "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+ TEST_HASH_STR(alphabet_100000.buf,
+ "e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4",
+ "e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35");
+ TEST_HASH_LITERAL("blob 0\0",
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813");
+ TEST_HASH_LITERAL("blob 3\0abc",
+ "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f",
+ "c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6");
+ TEST_HASH_LITERAL("tree 0\0",
+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904",
+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321");
+
+ strbuf_release(&aaaaaaaaaa_100000);
+ strbuf_release(&alphabet_100000);
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/t-hashmap.c
new file mode 100644
index 0000000000..83b79dff39
--- /dev/null
+++ b/t/unit-tests/t-hashmap.c
@@ -0,0 +1,361 @@
+#include "test-lib.h"
+#include "hashmap.h"
+#include "strbuf.h"
+
+struct test_entry {
+ int padding; /* hashmap entry no longer needs to be the first member */
+ struct hashmap_entry ent;
+ /* key and value as two \0-terminated strings */
+ char key[FLEX_ARRAY];
+};
+
+static int test_entry_cmp(const void *cmp_data,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
+{
+ const unsigned int ignore_case = cmp_data ? *((int *)cmp_data) : 0;
+ const struct test_entry *e1, *e2;
+ const char *key = keydata;
+
+ e1 = container_of(eptr, const struct test_entry, ent);
+ e2 = container_of(entry_or_key, const struct test_entry, ent);
+
+ if (ignore_case)
+ return strcasecmp(e1->key, key ? key : e2->key);
+ else
+ return strcmp(e1->key, key ? key : e2->key);
+}
+
+static const char *get_value(const struct test_entry *e)
+{
+ return e->key + strlen(e->key) + 1;
+}
+
+static struct test_entry *alloc_test_entry(const char *key, const char *value,
+ unsigned int ignore_case)
+{
+ size_t klen = strlen(key);
+ size_t vlen = strlen(value);
+ unsigned int hash = ignore_case ? strihash(key) : strhash(key);
+ struct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));
+
+ hashmap_entry_init(&entry->ent, hash);
+ memcpy(entry->key, key, klen + 1);
+ memcpy(entry->key + klen + 1, value, vlen + 1);
+ return entry;
+}
+
+static struct test_entry *get_test_entry(struct hashmap *map, const char *key,
+ unsigned int ignore_case)
+{
+ return hashmap_get_entry_from_hash(
+ map, ignore_case ? strihash(key) : strhash(key), key,
+ struct test_entry, ent);
+}
+
+static int key_val_contains(const char *key_val[][2], char seen[], size_t n,
+ struct test_entry *entry)
+{
+ for (size_t i = 0; i < n; i++) {
+ if (!strcmp(entry->key, key_val[i][0]) &&
+ !strcmp(get_value(entry), key_val[i][1])) {
+ if (seen[i])
+ return 2;
+ seen[i] = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void setup(void (*f)(struct hashmap *map, unsigned int ignore_case),
+ unsigned int ignore_case)
+{
+ struct hashmap map = HASHMAP_INIT(test_entry_cmp, &ignore_case);
+
+ f(&map, ignore_case);
+ hashmap_clear_and_free(&map, struct test_entry, ent);
+}
+
+static void t_replace(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+
+ entry = alloc_test_entry("key1", "value1", ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+
+ entry = alloc_test_entry(ignore_case ? "Key1" : "key1", "value2",
+ ignore_case);
+ entry = hashmap_put_entry(map, entry, ent);
+ if (check(entry != NULL))
+ check_str(get_value(entry), "value1");
+ free(entry);
+
+ entry = alloc_test_entry("fooBarFrotz", "value3", ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+
+ entry = alloc_test_entry(ignore_case ? "FOObarFrotz" : "fooBarFrotz",
+ "value4", ignore_case);
+ entry = hashmap_put_entry(map, entry, ent);
+ if (check(entry != NULL))
+ check_str(get_value(entry), "value3");
+ free(entry);
+}
+
+static void t_get(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+ const char *key_val[][2] = { { "key1", "value1" },
+ { "key2", "value2" },
+ { "fooBarFrotz", "value3" },
+ { ignore_case ? "key4" : "foobarfrotz",
+ "value4" } };
+ const char *query[][2] = {
+ { ignore_case ? "Key1" : "key1", "value1" },
+ { ignore_case ? "keY2" : "key2", "value2" },
+ { ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value3" },
+ { ignore_case ? "FOObarFrotz" : "foobarfrotz",
+ ignore_case ? "value3" : "value4" }
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1],
+ ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(query); i++) {
+ entry = get_test_entry(map, query[i][0], ignore_case);
+ if (check(entry != NULL))
+ check_str(get_value(entry), query[i][1]);
+ else
+ test_msg("query key: %s", query[i][0]);
+ }
+
+ check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+}
+
+static void t_add(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+ const char *key_val[][2] = {
+ { "key1", "value1" },
+ { ignore_case ? "Key1" : "key1", "value2" },
+ { "fooBarFrotz", "value3" },
+ { ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value4" }
+ };
+ const char *query_keys[] = { "key1", ignore_case ? "FOObarFrotz" :
+ "fooBarFrotz" };
+ char seen[ARRAY_SIZE(key_val)] = { 0 };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
+ hashmap_add(map, &entry->ent);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(query_keys); i++) {
+ int count = 0;
+ entry = hashmap_get_entry_from_hash(map,
+ ignore_case ? strihash(query_keys[i]) :
+ strhash(query_keys[i]),
+ query_keys[i], struct test_entry, ent);
+
+ hashmap_for_each_entry_from(map, entry, ent)
+ {
+ int ret;
+ if (!check_int((ret = key_val_contains(
+ key_val, seen,
+ ARRAY_SIZE(key_val), entry)),
+ ==, 0)) {
+ switch (ret) {
+ case 1:
+ test_msg("found entry was not given in the input\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ case 2:
+ test_msg("duplicate entry detected\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ }
+ } else {
+ count++;
+ }
+ }
+ check_int(count, ==, 2);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
+ if (!check_int(seen[i], ==, 1))
+ test_msg("following key-val pair was not iterated over:\n"
+ " key: %s\n value: %s",
+ key_val[i][0], key_val[i][1]);
+ }
+
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+ check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+}
+
+static void t_remove(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry, *removed;
+ const char *key_val[][2] = { { "key1", "value1" },
+ { "key2", "value2" },
+ { "fooBarFrotz", "value3" } };
+ const char *remove[][2] = { { ignore_case ? "Key1" : "key1", "value1" },
+ { ignore_case ? "keY2" : "key2", "value2" } };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(remove); i++) {
+ entry = alloc_test_entry(remove[i][0], "", ignore_case);
+ removed = hashmap_remove_entry(map, entry, ent, remove[i][0]);
+ if (check(removed != NULL))
+ check_str(get_value(removed), remove[i][1]);
+ free(entry);
+ free(removed);
+ }
+
+ entry = alloc_test_entry("notInMap", "", ignore_case);
+ check_pointer_eq(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL);
+ free(entry);
+
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val) - ARRAY_SIZE(remove));
+}
+
+static void t_iterate(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+ struct hashmap_iter iter;
+ const char *key_val[][2] = { { "key1", "value1" },
+ { "key2", "value2" },
+ { "fooBarFrotz", "value3" } };
+ char seen[ARRAY_SIZE(key_val)] = { 0 };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ }
+
+ hashmap_for_each_entry(map, &iter, entry, ent /* member name */)
+ {
+ int ret;
+ if (!check_int((ret = key_val_contains(key_val, seen,
+ ARRAY_SIZE(key_val),
+ entry)), ==, 0)) {
+ switch (ret) {
+ case 1:
+ test_msg("found entry was not given in the input\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ case 2:
+ test_msg("duplicate entry detected\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
+ if (!check_int(seen[i], ==, 1))
+ test_msg("following key-val pair was not iterated over:\n"
+ " key: %s\n value: %s",
+ key_val[i][0], key_val[i][1]);
+ }
+
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+}
+
+static void t_alloc(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry, *removed;
+
+ for (int i = 1; i <= 51; i++) {
+ char *key = xstrfmt("key%d", i);
+ char *value = xstrfmt("value%d", i);
+ entry = alloc_test_entry(key, value, ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ free(key);
+ free(value);
+ }
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, 51);
+
+ entry = alloc_test_entry("key52", "value52", ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ check_int(map->tablesize, ==, 256);
+ check_int(hashmap_get_size(map), ==, 52);
+
+ for (int i = 1; i <= 12; i++) {
+ char *key = xstrfmt("key%d", i);
+ char *value = xstrfmt("value%d", i);
+
+ entry = alloc_test_entry(key, "", ignore_case);
+ removed = hashmap_remove_entry(map, entry, ent, key);
+ if (check(removed != NULL))
+ check_str(value, get_value(removed));
+ free(key);
+ free(value);
+ free(entry);
+ free(removed);
+ }
+ check_int(map->tablesize, ==, 256);
+ check_int(hashmap_get_size(map), ==, 40);
+
+ entry = alloc_test_entry("key40", "", ignore_case);
+ removed = hashmap_remove_entry(map, entry, ent, "key40");
+ if (check(removed != NULL))
+ check_str("value40", get_value(removed));
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, 39);
+ free(entry);
+ free(removed);
+}
+
+static void t_intern(void)
+{
+ const char *values[] = { "value1", "Value1", "value2", "value2" };
+
+ for (size_t i = 0; i < ARRAY_SIZE(values); i++) {
+ const char *i1 = strintern(values[i]);
+ const char *i2 = strintern(values[i]);
+
+ if (!check(!strcmp(i1, values[i])))
+ test_msg("strintern(%s) returns %s\n", values[i], i1);
+ else if (!check(i1 != values[i]))
+ test_msg("strintern(%s) returns input pointer\n",
+ values[i]);
+ else if (!check_pointer_eq(i1, i2))
+ test_msg("address('%s') != address('%s'), so strintern('%s') != strintern('%s')",
+ i1, i2, values[i], values[i]);
+ else
+ check_str(i1, values[i]);
+ }
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(setup(t_replace, 0), "replace works");
+ TEST(setup(t_replace, 1), "replace (case insensitive) works");
+ TEST(setup(t_get, 0), "get works");
+ TEST(setup(t_get, 1), "get (case insensitive) works");
+ TEST(setup(t_add, 0), "add works");
+ TEST(setup(t_add, 1), "add (case insensitive) works");
+ TEST(setup(t_remove, 0), "remove works");
+ TEST(setup(t_remove, 1), "remove (case insensitive) works");
+ TEST(setup(t_iterate, 0), "iterate works");
+ TEST(setup(t_iterate, 1), "iterate (case insensitive) works");
+ TEST(setup(t_alloc, 0), "grow / shrink works");
+ TEST(t_intern(), "string interning works");
+ return test_done();
+}
diff --git a/t/unit-tests/t-mem-pool.c b/t/unit-tests/t-mem-pool.c
new file mode 100644
index 0000000000..fe500c704b
--- /dev/null
+++ b/t/unit-tests/t-mem-pool.c
@@ -0,0 +1,31 @@
+#include "test-lib.h"
+#include "mem-pool.h"
+
+static void setup_static(void (*f)(struct mem_pool *), size_t block_alloc)
+{
+ struct mem_pool pool = { .block_alloc = block_alloc };
+ f(&pool);
+ mem_pool_discard(&pool, 0);
+}
+
+static void t_calloc_100(struct mem_pool *pool)
+{
+ size_t size = 100;
+ char *buffer = mem_pool_calloc(pool, 1, size);
+ for (size_t i = 0; i < size; i++)
+ check_int(buffer[i], ==, 0);
+ if (!check(pool->mp_block != NULL))
+ return;
+ check(pool->mp_block->next_free != NULL);
+ check(pool->mp_block->end != NULL);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(setup_static(t_calloc_100, 1024 * 1024),
+ "mem_pool_calloc returns 100 zeroed bytes with big block");
+ TEST(setup_static(t_calloc_100, 1),
+ "mem_pool_calloc returns 100 zeroed bytes with tiny block");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-oid-array.c b/t/unit-tests/t-oid-array.c
new file mode 100644
index 0000000000..45b59a2a51
--- /dev/null
+++ b/t/unit-tests/t-oid-array.c
@@ -0,0 +1,126 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "test-lib.h"
+#include "lib-oid.h"
+#include "oid-array.h"
+#include "hex.h"
+
+static int fill_array(struct oid_array *array, const char *hexes[], size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ struct object_id oid;
+
+ if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
+ return -1;
+ oid_array_append(array, &oid);
+ }
+ if (!check_uint(array->nr, ==, n))
+ return -1;
+ return 0;
+}
+
+static int add_to_oid_array(const struct object_id *oid, void *data)
+{
+ struct oid_array *array = data;
+
+ oid_array_append(array, oid);
+ return 0;
+}
+
+static void t_enumeration(const char **input_args, size_t input_sz,
+ const char **expect_args, size_t expect_sz)
+{
+ struct oid_array input = OID_ARRAY_INIT, expect = OID_ARRAY_INIT,
+ actual = OID_ARRAY_INIT;
+ size_t i;
+
+ if (fill_array(&input, input_args, input_sz))
+ return;
+ if (fill_array(&expect, expect_args, expect_sz))
+ return;
+
+ oid_array_for_each_unique(&input, add_to_oid_array, &actual);
+ if (!check_uint(actual.nr, ==, expect.nr))
+ return;
+
+ for (i = 0; i < actual.nr; i++) {
+ if (!check(oideq(&actual.oid[i], &expect.oid[i])))
+ test_msg("expected: %s\n got: %s\n index: %" PRIuMAX,
+ oid_to_hex(&expect.oid[i]), oid_to_hex(&actual.oid[i]),
+ (uintmax_t)i);
+ }
+
+ oid_array_clear(&actual);
+ oid_array_clear(&input);
+ oid_array_clear(&expect);
+}
+
+#define TEST_ENUMERATION(input, expect, desc) \
+ TEST(t_enumeration(input, ARRAY_SIZE(input), expect, ARRAY_SIZE(expect)), \
+ desc " works")
+
+static void t_lookup(const char **input_hexes, size_t n, const char *query_hex,
+ int lower_bound, int upper_bound)
+{
+ struct oid_array array = OID_ARRAY_INIT;
+ struct object_id oid_query;
+ int ret;
+
+ if (!check_int(get_oid_arbitrary_hex(query_hex, &oid_query), ==, 0))
+ return;
+ if (fill_array(&array, input_hexes, n))
+ return;
+ ret = oid_array_lookup(&array, &oid_query);
+
+ if (!check_int(ret, <=, upper_bound) ||
+ !check_int(ret, >=, lower_bound))
+ test_msg("oid query for lookup: %s", oid_to_hex(&oid_query));
+
+ oid_array_clear(&array);
+}
+
+#define TEST_LOOKUP(input_hexes, query, lower_bound, upper_bound, desc) \
+ TEST(t_lookup(input_hexes, ARRAY_SIZE(input_hexes), query, \
+ lower_bound, upper_bound), \
+ desc " works")
+
+static void setup(void)
+{
+ /* The hash algo is used by oid_array_lookup() internally */
+ int algo = init_hash_algo();
+ if (check_int(algo, !=, GIT_HASH_UNKNOWN))
+ repo_set_hash_algo(the_repository, algo);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ const char *arr_input[] = { "88", "44", "aa", "55" };
+ const char *arr_input_dup[] = { "88", "44", "aa", "55",
+ "88", "44", "aa", "55",
+ "88", "44", "aa", "55" };
+ const char *res_sorted[] = { "44", "55", "88", "aa" };
+ const char *nearly_55;
+
+ if (!TEST(setup(), "setup"))
+ test_skip_all("hash algo initialization failed");
+
+ TEST_ENUMERATION(arr_input, res_sorted, "ordered enumeration");
+ TEST_ENUMERATION(arr_input_dup, res_sorted,
+ "ordered enumeration with duplicate suppression");
+
+ TEST_LOOKUP(arr_input, "55", 1, 1, "lookup");
+ TEST_LOOKUP(arr_input, "33", INT_MIN, -1, "lookup non-existent entry");
+ TEST_LOOKUP(arr_input_dup, "55", 3, 5, "lookup with duplicates");
+ TEST_LOOKUP(arr_input_dup, "66", INT_MIN, -1,
+ "lookup non-existent entry with duplicates");
+
+ nearly_55 = init_hash_algo() == GIT_HASH_SHA1 ?
+ "5500000000000000000000000000000000000001" :
+ "5500000000000000000000000000000000000000000000000000000000000001";
+ TEST_LOOKUP(((const char *[]){ "55", nearly_55 }), "55", 0, 0,
+ "lookup with almost duplicate values");
+ TEST_LOOKUP(((const char *[]){ "55", "55" }), "55", 0, 1,
+ "lookup with single duplicate value");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-oidmap.c b/t/unit-tests/t-oidmap.c
new file mode 100644
index 0000000000..b22e52d08b
--- /dev/null
+++ b/t/unit-tests/t-oidmap.c
@@ -0,0 +1,181 @@
+#include "test-lib.h"
+#include "lib-oid.h"
+#include "oidmap.h"
+#include "hash.h"
+#include "hex.h"
+
+/*
+ * Elements we will put in oidmap structs are made of a key: the entry.oid
+ * field, which is of type struct object_id, and a value: the name field (could
+ * be a refname for example).
+ */
+struct test_entry {
+ struct oidmap_entry entry;
+ char name[FLEX_ARRAY];
+};
+
+static const char *const key_val[][2] = { { "11", "one" },
+ { "22", "two" },
+ { "33", "three" } };
+
+static void setup(void (*f)(struct oidmap *map))
+{
+ struct oidmap map = OIDMAP_INIT;
+ int ret = 0;
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){
+ struct test_entry *entry;
+
+ FLEX_ALLOC_STR(entry, name, key_val[i][1]);
+ if ((ret = get_oid_arbitrary_hex(key_val[i][0], &entry->entry.oid))) {
+ free(entry);
+ break;
+ }
+ entry = oidmap_put(&map, entry);
+ if (!check(entry == NULL))
+ free(entry);
+ }
+
+ if (!ret)
+ f(&map);
+ oidmap_free(&map, 1);
+}
+
+static void t_replace(struct oidmap *map)
+{
+ struct test_entry *entry, *prev;
+
+ FLEX_ALLOC_STR(entry, name, "un");
+ if (get_oid_arbitrary_hex("11", &entry->entry.oid))
+ return;
+ prev = oidmap_put(map, entry);
+ if (!check(prev != NULL))
+ return;
+ check_str(prev->name, "one");
+ free(prev);
+
+ FLEX_ALLOC_STR(entry, name, "deux");
+ if (get_oid_arbitrary_hex("22", &entry->entry.oid))
+ return;
+ prev = oidmap_put(map, entry);
+ if (!check(prev != NULL))
+ return;
+ check_str(prev->name, "two");
+ free(prev);
+}
+
+static void t_get(struct oidmap *map)
+{
+ struct test_entry *entry;
+ struct object_id oid;
+
+ if (get_oid_arbitrary_hex("22", &oid))
+ return;
+ entry = oidmap_get(map, &oid);
+ if (!check(entry != NULL))
+ return;
+ check_str(entry->name, "two");
+
+ if (get_oid_arbitrary_hex("44", &oid))
+ return;
+ check(oidmap_get(map, &oid) == NULL);
+
+ if (get_oid_arbitrary_hex("11", &oid))
+ return;
+ entry = oidmap_get(map, &oid);
+ if (!check(entry != NULL))
+ return;
+ check_str(entry->name, "one");
+}
+
+static void t_remove(struct oidmap *map)
+{
+ struct test_entry *entry;
+ struct object_id oid;
+
+ if (get_oid_arbitrary_hex("11", &oid))
+ return;
+ entry = oidmap_remove(map, &oid);
+ if (!check(entry != NULL))
+ return;
+ check_str(entry->name, "one");
+ check(oidmap_get(map, &oid) == NULL);
+ free(entry);
+
+ if (get_oid_arbitrary_hex("22", &oid))
+ return;
+ entry = oidmap_remove(map, &oid);
+ if (!check(entry != NULL))
+ return;
+ check_str(entry->name, "two");
+ check(oidmap_get(map, &oid) == NULL);
+ free(entry);
+
+ if (get_oid_arbitrary_hex("44", &oid))
+ return;
+ check(oidmap_remove(map, &oid) == NULL);
+}
+
+static int key_val_contains(struct test_entry *entry, char seen[])
+{
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ struct object_id oid;
+
+ if (get_oid_arbitrary_hex(key_val[i][0], &oid))
+ return -1;
+
+ if (oideq(&entry->entry.oid, &oid)) {
+ if (seen[i])
+ return 2;
+ seen[i] = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void t_iterate(struct oidmap *map)
+{
+ struct oidmap_iter iter;
+ struct test_entry *entry;
+ char seen[ARRAY_SIZE(key_val)] = { 0 };
+ int count = 0;
+
+ oidmap_iter_init(map, &iter);
+ while ((entry = oidmap_iter_next(&iter))) {
+ int ret;
+ if (!check_int((ret = key_val_contains(entry, seen)), ==, 0)) {
+ switch (ret) {
+ case -1:
+ break; /* error message handled by get_oid_arbitrary_hex() */
+ case 1:
+ test_msg("obtained entry was not given in the input\n"
+ " name: %s\n oid: %s\n",
+ entry->name, oid_to_hex(&entry->entry.oid));
+ break;
+ case 2:
+ test_msg("duplicate entry detected\n"
+ " name: %s\n oid: %s\n",
+ entry->name, oid_to_hex(&entry->entry.oid));
+ break;
+ default:
+ test_msg("BUG: invalid return value (%d) from key_val_contains()",
+ ret);
+ break;
+ }
+ } else {
+ count++;
+ }
+ }
+ check_int(count, ==, ARRAY_SIZE(key_val));
+ check_int(hashmap_get_size(&map->map), ==, ARRAY_SIZE(key_val));
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(setup(t_replace), "replace works");
+ TEST(setup(t_get), "get works");
+ TEST(setup(t_remove), "remove works");
+ TEST(setup(t_iterate), "iterate works");
+ return test_done();
+}
diff --git a/t/unit-tests/t-oidtree.c b/t/unit-tests/t-oidtree.c
new file mode 100644
index 0000000000..a38754b066
--- /dev/null
+++ b/t/unit-tests/t-oidtree.c
@@ -0,0 +1,122 @@
+#include "test-lib.h"
+#include "lib-oid.h"
+#include "oidtree.h"
+#include "hash.h"
+#include "hex.h"
+#include "strvec.h"
+
+#define FILL_TREE(tree, ...) \
+ do { \
+ const char *hexes[] = { __VA_ARGS__ }; \
+ if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \
+ return; \
+ } while (0)
+
+static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ struct object_id oid;
+ if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
+ return -1;
+ oidtree_insert(ot, &oid);
+ }
+ return 0;
+}
+
+static void check_contains(struct oidtree *ot, const char *hex, int expected)
+{
+ struct object_id oid;
+
+ if (!check_int(get_oid_arbitrary_hex(hex, &oid), ==, 0))
+ return;
+ if (!check_int(oidtree_contains(ot, &oid), ==, expected))
+ test_msg("oid: %s", oid_to_hex(&oid));
+}
+
+struct expected_hex_iter {
+ size_t i;
+ struct strvec expected_hexes;
+ const char *query;
+};
+
+static enum cb_next check_each_cb(const struct object_id *oid, void *data)
+{
+ struct expected_hex_iter *hex_iter = data;
+ struct object_id expected;
+
+ if (!check_int(hex_iter->i, <, hex_iter->expected_hexes.nr)) {
+ test_msg("error: extraneous callback for query: ('%s'), object_id: ('%s')",
+ hex_iter->query, oid_to_hex(oid));
+ return CB_BREAK;
+ }
+
+ if (!check_int(get_oid_arbitrary_hex(hex_iter->expected_hexes.v[hex_iter->i],
+ &expected), ==, 0))
+ ; /* the data is bogus and cannot be used */
+ else if (!check(oideq(oid, &expected)))
+ test_msg("expected: %s\n got: %s\n query: %s",
+ oid_to_hex(&expected), oid_to_hex(oid), hex_iter->query);
+
+ hex_iter->i += 1;
+ return CB_CONTINUE;
+}
+
+LAST_ARG_MUST_BE_NULL
+static void check_each(struct oidtree *ot, const char *query, ...)
+{
+ struct object_id oid;
+ struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT,
+ .query = query };
+ const char *arg;
+ va_list hex_args;
+
+ va_start(hex_args, query);
+ while ((arg = va_arg(hex_args, const char *)))
+ strvec_push(&hex_iter.expected_hexes, arg);
+ va_end(hex_args);
+
+ if (!check_int(get_oid_arbitrary_hex(query, &oid), ==, 0))
+ return;
+ oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter);
+
+ if (!check_int(hex_iter.i, ==, hex_iter.expected_hexes.nr))
+ test_msg("error: could not find some 'object_id's for query ('%s')", query);
+ strvec_clear(&hex_iter.expected_hexes);
+}
+
+static void setup(void (*f)(struct oidtree *ot))
+{
+ struct oidtree ot;
+
+ oidtree_init(&ot);
+ f(&ot);
+ oidtree_clear(&ot);
+}
+
+static void t_contains(struct oidtree *ot)
+{
+ FILL_TREE(ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e");
+ check_contains(ot, "44", 0);
+ check_contains(ot, "441", 0);
+ check_contains(ot, "440", 0);
+ check_contains(ot, "444", 1);
+ check_contains(ot, "4440", 1);
+ check_contains(ot, "4444", 0);
+}
+
+static void t_each(struct oidtree *ot)
+{
+ FILL_TREE(ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e");
+ check_each(ot, "12300", "123", NULL);
+ check_each(ot, "3211", NULL); /* should not reach callback */
+ check_each(ot, "3210", "321", NULL);
+ check_each(ot, "32100", "321", NULL);
+ check_each(ot, "32", "320", "321", NULL);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(setup(t_contains), "oidtree insert and contains works");
+ TEST(setup(t_each), "oidtree each works");
+ return test_done();
+}
diff --git a/t/unit-tests/t-prio-queue.c b/t/unit-tests/t-prio-queue.c
new file mode 100644
index 0000000000..fe6ae37935
--- /dev/null
+++ b/t/unit-tests/t-prio-queue.c
@@ -0,0 +1,91 @@
+#include "test-lib.h"
+#include "prio-queue.h"
+
+static int intcmp(const void *va, const void *vb, void *data UNUSED)
+{
+ const int *a = va, *b = vb;
+ return *a - *b;
+}
+
+
+#define MISSING -1
+#define DUMP -2
+#define STACK -3
+#define GET -4
+#define REVERSE -5
+
+static int show(int *v)
+{
+ return v ? *v : MISSING;
+}
+
+static void test_prio_queue(int *input, size_t input_size,
+ int *result, size_t result_size)
+{
+ struct prio_queue pq = { intcmp };
+ int j = 0;
+
+ for (int i = 0; i < input_size; i++) {
+ void *peek, *get;
+ switch(input[i]) {
+ case GET:
+ peek = prio_queue_peek(&pq);
+ get = prio_queue_get(&pq);
+ if (!check(peek == get))
+ return;
+ if (!check_uint(j, <, result_size))
+ break;
+ if (!check_int(result[j], ==, show(get)))
+ test_msg(" j: %d", j);
+ j++;
+ break;
+ case DUMP:
+ while ((peek = prio_queue_peek(&pq))) {
+ get = prio_queue_get(&pq);
+ if (!check(peek == get))
+ return;
+ if (!check_uint(j, <, result_size))
+ break;
+ if (!check_int(result[j], ==, show(get)))
+ test_msg(" j: %d", j);
+ j++;
+ }
+ break;
+ case STACK:
+ pq.compare = NULL;
+ break;
+ case REVERSE:
+ prio_queue_reverse(&pq);
+ break;
+ default:
+ prio_queue_put(&pq, &input[i]);
+ break;
+ }
+ }
+ check_uint(j, ==, result_size);
+ clear_prio_queue(&pq);
+}
+
+#define TEST_INPUT(input, result) \
+ test_prio_queue(input, ARRAY_SIZE(input), result, ARRAY_SIZE(result))
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(TEST_INPUT(((int []){ 2, 6, 3, 10, 9, 5, 7, 4, 5, 8, 1, DUMP }),
+ ((int []){ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10 })),
+ "prio-queue works for basic input");
+ TEST(TEST_INPUT(((int []){ 6, 2, 4, GET, 5, 3, GET, GET, 1, DUMP }),
+ ((int []){ 2, 3, 4, 1, 5, 6 })),
+ "prio-queue works for mixed put & get commands");
+ TEST(TEST_INPUT(((int []){ 1, 2, GET, GET, GET, 1, 2, GET, GET, GET }),
+ ((int []){ 1, 2, MISSING, 1, 2, MISSING })),
+ "prio-queue works when queue is empty");
+ TEST(TEST_INPUT(((int []){ STACK, 8, 1, 5, 4, 6, 2, 3, DUMP }),
+ ((int []){ 3, 2, 6, 4, 5, 1, 8 })),
+ "prio-queue works when used as a LIFO stack");
+ TEST(TEST_INPUT(((int []){ STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP }),
+ ((int []){ 1, 2, 3, 4, 5, 6 })),
+ "prio-queue works when LIFO stack is reversed");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c
new file mode 100644
index 0000000000..65d50df091
--- /dev/null
+++ b/t/unit-tests/t-reftable-basics.c
@@ -0,0 +1,145 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/basics.h"
+
+struct integer_needle_lesseq_args {
+ int needle;
+ int *haystack;
+};
+
+static int integer_needle_lesseq(size_t i, void *_args)
+{
+ struct integer_needle_lesseq_args *args = _args;
+ return args->needle <= args->haystack[i];
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ if_test ("binary search with binsearch works") {
+ int haystack[] = { 2, 4, 6, 8, 10 };
+ struct {
+ int needle;
+ size_t expected_idx;
+ } testcases[] = {
+ {-9000, 0},
+ {-1, 0},
+ {0, 0},
+ {2, 0},
+ {3, 1},
+ {4, 1},
+ {7, 3},
+ {9, 4},
+ {10, 4},
+ {11, 5},
+ {9000, 5},
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
+ struct integer_needle_lesseq_args args = {
+ .haystack = haystack,
+ .needle = testcases[i].needle,
+ };
+ size_t idx;
+
+ idx = binsearch(ARRAY_SIZE(haystack),
+ &integer_needle_lesseq, &args);
+ check_int(idx, ==, testcases[i].expected_idx);
+ }
+ }
+
+ if_test ("names_length returns size of a NULL-terminated string array") {
+ const char *a[] = { "a", "b", NULL };
+ check_int(names_length(a), ==, 2);
+ }
+
+ if_test ("names_equal compares NULL-terminated string arrays") {
+ const char *a[] = { "a", "b", "c", NULL };
+ const char *b[] = { "a", "b", "d", NULL };
+ const char *c[] = { "a", "b", NULL };
+
+ check(names_equal(a, a));
+ check(!names_equal(a, b));
+ check(!names_equal(a, c));
+ }
+
+ if_test ("parse_names works for basic input") {
+ char in1[] = "line\n";
+ char in2[] = "a\nb\nc";
+ char **out = parse_names(in1, strlen(in1));
+ check(out != NULL);
+ check_str(out[0], "line");
+ check(!out[1]);
+ free_names(out);
+
+ out = parse_names(in2, strlen(in2));
+ check(out != NULL);
+ check_str(out[0], "a");
+ check_str(out[1], "b");
+ check_str(out[2], "c");
+ check(!out[3]);
+ free_names(out);
+ }
+
+ if_test ("parse_names drops empty string") {
+ char in[] = "a\n\nb\n";
+ char **out = parse_names(in, strlen(in));
+ check(out != NULL);
+ check_str(out[0], "a");
+ /* simply '\n' should be dropped as empty string */
+ check_str(out[1], "b");
+ check(!out[2]);
+ free_names(out);
+ }
+
+ if_test ("common_prefix_size works") {
+ struct reftable_buf a = REFTABLE_BUF_INIT;
+ struct reftable_buf b = REFTABLE_BUF_INIT;
+ struct {
+ const char *a, *b;
+ int want;
+ } cases[] = {
+ {"abcdef", "abc", 3},
+ { "abc", "ab", 2 },
+ { "", "abc", 0 },
+ { "abc", "abd", 2 },
+ { "abc", "pqr", 0 },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
+ check(!reftable_buf_addstr(&a, cases[i].a));
+ check(!reftable_buf_addstr(&b, cases[i].b));
+ check_int(common_prefix_size(&a, &b), ==, cases[i].want);
+ reftable_buf_reset(&a);
+ reftable_buf_reset(&b);
+ }
+ reftable_buf_release(&a);
+ reftable_buf_release(&b);
+ }
+
+ if_test ("put_be24 and get_be24 work") {
+ uint32_t in = 0x112233;
+ uint8_t dest[3];
+ uint32_t out;
+ put_be24(dest, in);
+ out = get_be24(dest);
+ check_int(in, ==, out);
+ }
+
+ if_test ("put_be16 and get_be16 work") {
+ uint32_t in = 0xfef1;
+ uint8_t dest[3];
+ uint32_t out;
+ put_be16(dest, in);
+ out = get_be16(dest);
+ check_int(in, ==, out);
+ }
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c
new file mode 100644
index 0000000000..f9af907117
--- /dev/null
+++ b/t/unit-tests/t-reftable-block.c
@@ -0,0 +1,382 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/block.h"
+#include "reftable/blocksource.h"
+#include "reftable/constants.h"
+#include "reftable/reftable-error.h"
+
+static void t_ref_block_read_write(void)
+{
+ const int header_off = 21; /* random */
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 1024;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = REFTABLE_BUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_REF,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ check(block.data != NULL);
+ block.len = block_size;
+ block_source_from_buf(&block.source ,&buf);
+ ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ check(!ret);
+
+ rec.u.ref.refname = (char *) "";
+ rec.u.ref.value_type = REFTABLE_REF_DELETION;
+ ret = block_writer_add(&bw, &rec);
+ check_int(ret, ==, REFTABLE_API_ERROR);
+
+ for (i = 0; i < N; i++) {
+ rec.u.ref.refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+ rec.u.ref.value_type = REFTABLE_REF_VAL1;
+ memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ);
+
+ recs[i] = rec;
+ ret = block_writer_add(&bw, &rec);
+ rec.u.ref.refname = NULL;
+ rec.u.ref.value_type = REFTABLE_REF_DELETION;
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_record_key(&recs[i], &want);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+ want.len--;
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ reftable_buf_release(&want);
+ reftable_buf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+static void t_log_block_read_write(void)
+{
+ const int header_off = 21;
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 2048;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = REFTABLE_BUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_LOG,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ check(block.data != NULL);
+ block.len = block_size;
+ block_source_from_buf(&block.source ,&buf);
+ ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ check(!ret);
+
+ for (i = 0; i < N; i++) {
+ rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i);
+ rec.u.log.update_index = i;
+ rec.u.log.value_type = REFTABLE_LOG_UPDATE;
+
+ recs[i] = rec;
+ ret = block_writer_add(&bw, &rec);
+ rec.u.log.refname = NULL;
+ rec.u.log.value_type = REFTABLE_LOG_DELETION;
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_buf_reset(&want);
+ check(!reftable_buf_addstr(&want, recs[i].u.log.refname));
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+ want.len--;
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ reftable_buf_release(&want);
+ reftable_buf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+static void t_obj_block_read_write(void)
+{
+ const int header_off = 21;
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 1024;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = REFTABLE_BUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_OBJ,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ check(block.data != NULL);
+ block.len = block_size;
+ block_source_from_buf(&block.source, &buf);
+ ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ check(!ret);
+
+ for (i = 0; i < N; i++) {
+ uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated;
+ DUP_ARRAY(allocated, bytes, ARRAY_SIZE(bytes));
+
+ rec.u.obj.hash_prefix = allocated;
+ rec.u.obj.hash_prefix_len = 5;
+
+ recs[i] = rec;
+ ret = block_writer_add(&bw, &rec);
+ rec.u.obj.hash_prefix = NULL;
+ rec.u.obj.hash_prefix_len = 0;
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_record_key(&recs[i], &want);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ reftable_buf_release(&want);
+ reftable_buf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+static void t_index_block_read_write(void)
+{
+ const int header_off = 21;
+ struct reftable_record recs[30];
+ const size_t N = ARRAY_SIZE(recs);
+ const size_t block_size = 1024;
+ struct reftable_block block = { 0 };
+ struct block_writer bw = {
+ .last_key = REFTABLE_BUF_INIT,
+ };
+ struct reftable_record rec = {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx.last_key = REFTABLE_BUF_INIT,
+ };
+ size_t i = 0;
+ int ret;
+ struct block_reader br = { 0 };
+ struct block_iter it = BLOCK_ITER_INIT;
+ struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT;
+
+ REFTABLE_CALLOC_ARRAY(block.data, block_size);
+ check(block.data != NULL);
+ block.len = block_size;
+ block_source_from_buf(&block.source, &buf);
+ ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
+ header_off, hash_size(GIT_SHA1_FORMAT_ID));
+ check(!ret);
+
+ for (i = 0; i < N; i++) {
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i);
+
+ reftable_buf_init(&recs[i].u.idx.last_key);
+ recs[i].type = BLOCK_TYPE_INDEX;
+ check(!reftable_buf_addstr(&recs[i].u.idx.last_key, buf));
+ recs[i].u.idx.offset = i;
+
+ ret = block_writer_add(&bw, &recs[i]);
+ check_int(ret, ==, 0);
+ }
+
+ ret = block_writer_finish(&bw);
+ check_int(ret, >, 0);
+
+ block_writer_release(&bw);
+
+ block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+ block_iter_seek_start(&it, &br);
+
+ for (i = 0; ; i++) {
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, >=, 0);
+ if (ret > 0) {
+ check_int(i, ==, N);
+ break;
+ }
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ for (i = 0; i < N; i++) {
+ block_iter_reset(&it);
+ reftable_record_key(&recs[i], &want);
+
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+
+ check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+ want.len--;
+ ret = block_iter_seek_key(&it, &br, &want);
+ check_int(ret, ==, 0);
+
+ ret = block_iter_next(&it, &rec);
+ check_int(ret, ==, 0);
+ check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+ }
+
+ block_reader_release(&br);
+ block_iter_close(&it);
+ reftable_record_release(&rec);
+ reftable_block_done(&br.block);
+ reftable_buf_release(&want);
+ reftable_buf_release(&buf);
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_index_block_read_write(), "read-write operations on index blocks work");
+ TEST(t_log_block_read_write(), "read-write operations on log blocks work");
+ TEST(t_obj_block_read_write(), "read-write operations on obj blocks work");
+ TEST(t_ref_block_read_write(), "read-write operations on ref blocks work");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c
new file mode 100644
index 0000000000..4c25ee5334
--- /dev/null
+++ b/t/unit-tests/t-reftable-merged.c
@@ -0,0 +1,473 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/blocksource.h"
+#include "reftable/constants.h"
+#include "reftable/merged.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-merged.h"
+#include "reftable/reftable-writer.h"
+
+static struct reftable_merged_table *
+merged_table_from_records(struct reftable_ref_record **refs,
+ struct reftable_block_source **source,
+ struct reftable_reader ***readers, const size_t *sizes,
+ struct reftable_buf *buf, const size_t n)
+{
+ struct reftable_merged_table *mt = NULL;
+ struct reftable_write_options opts = {
+ .block_size = 256,
+ };
+ int err;
+
+ REFTABLE_CALLOC_ARRAY(*readers, n);
+ check(*readers != NULL);
+ REFTABLE_CALLOC_ARRAY(*source, n);
+ check(*source != NULL);
+
+ for (size_t i = 0; i < n; i++) {
+ t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts);
+ block_source_from_buf(&(*source)[i], &buf[i]);
+
+ err = reftable_reader_new(&(*readers)[i], &(*source)[i],
+ "name");
+ check(!err);
+ }
+
+ err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
+ check(!err);
+ return mt;
+}
+
+static void readers_destroy(struct reftable_reader **readers, const size_t n)
+{
+ for (size_t i = 0; i < n; i++)
+ reftable_reader_decref(readers[i]);
+ reftable_free(readers);
+}
+
+static void t_merged_single_record(void)
+{
+ struct reftable_ref_record r1[] = { {
+ .refname = (char *) "b",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1, 2, 3, 0 },
+ } };
+ struct reftable_ref_record r2[] = { {
+ .refname = (char *) "a",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_DELETION,
+ } };
+ struct reftable_ref_record r3[] = { {
+ .refname = (char *) "c",
+ .update_index = 3,
+ .value_type = REFTABLE_REF_DELETION,
+ } };
+
+ struct reftable_ref_record *refs[] = { r1, r2, r3 };
+ size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
+ struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
+ struct reftable_block_source *bs = NULL;
+ struct reftable_reader **readers = NULL;
+ struct reftable_merged_table *mt =
+ merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
+ struct reftable_ref_record ref = { 0 };
+ struct reftable_iterator it = { 0 };
+ int err;
+
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, "a");
+ check(!err);
+
+ err = reftable_iterator_next_ref(&it, &ref);
+ check(!err);
+ check(reftable_ref_record_equal(&r2[0], &ref, GIT_SHA1_RAWSZ));
+ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ readers_destroy(readers, 3);
+ reftable_merged_table_free(mt);
+ for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
+ reftable_buf_release(&bufs[i]);
+ reftable_free(bs);
+}
+
+static void t_merged_refs(void)
+{
+ struct reftable_ref_record r1[] = {
+ {
+ .refname = (char *) "a",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1 },
+ },
+ {
+ .refname = (char *) "b",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1 },
+ },
+ {
+ .refname = (char *) "c",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1 },
+ }
+ };
+ struct reftable_ref_record r2[] = { {
+ .refname = (char *) "a",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_DELETION,
+ } };
+ struct reftable_ref_record r3[] = {
+ {
+ .refname = (char *) "c",
+ .update_index = 3,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 2 },
+ },
+ {
+ .refname = (char *) "d",
+ .update_index = 3,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1 },
+ },
+ };
+
+ struct reftable_ref_record *want[] = {
+ &r2[0],
+ &r1[1],
+ &r3[0],
+ &r3[1],
+ };
+
+ struct reftable_ref_record *refs[] = { r1, r2, r3 };
+ size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
+ struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
+ struct reftable_block_source *bs = NULL;
+ struct reftable_reader **readers = NULL;
+ struct reftable_merged_table *mt =
+ merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
+ struct reftable_iterator it = { 0 };
+ int err;
+ struct reftable_ref_record *out = NULL;
+ size_t len = 0;
+ size_t cap = 0;
+ size_t i;
+
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, "a");
+ check(!err);
+ check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
+ check_int(reftable_merged_table_min_update_index(mt), ==, 1);
+ check_int(reftable_merged_table_max_update_index(mt), ==, 3);
+
+ while (len < 100) { /* cap loops/recursion. */
+ struct reftable_ref_record ref = { 0 };
+ int err = reftable_iterator_next_ref(&it, &ref);
+ if (err > 0)
+ break;
+
+ REFTABLE_ALLOC_GROW(out, len + 1, cap);
+ out[len++] = ref;
+ }
+ reftable_iterator_destroy(&it);
+
+ check_int(ARRAY_SIZE(want), ==, len);
+ for (i = 0; i < len; i++)
+ check(reftable_ref_record_equal(want[i], &out[i],
+ GIT_SHA1_RAWSZ));
+ for (i = 0; i < len; i++)
+ reftable_ref_record_release(&out[i]);
+ reftable_free(out);
+
+ for (i = 0; i < 3; i++)
+ reftable_buf_release(&bufs[i]);
+ readers_destroy(readers, 3);
+ reftable_merged_table_free(mt);
+ reftable_free(bs);
+}
+
+static void t_merged_seek_multiple_times(void)
+{
+ struct reftable_ref_record r1[] = {
+ {
+ .refname = (char *) "a",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 1 },
+ },
+ {
+ .refname = (char *) "c",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 2 },
+ }
+ };
+ struct reftable_ref_record r2[] = {
+ {
+ .refname = (char *) "b",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 3 },
+ },
+ {
+ .refname = (char *) "d",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 4 },
+ },
+ };
+ struct reftable_ref_record *refs[] = {
+ r1, r2,
+ };
+ size_t sizes[] = {
+ ARRAY_SIZE(r1), ARRAY_SIZE(r2),
+ };
+ struct reftable_buf bufs[] = {
+ REFTABLE_BUF_INIT, REFTABLE_BUF_INIT,
+ };
+ struct reftable_block_source *sources = NULL;
+ struct reftable_reader **readers = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct reftable_merged_table *mt;
+
+ mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2);
+ merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+
+ for (size_t i = 0; i < 5; i++) {
+ int err = reftable_iterator_seek_ref(&it, "c");
+ check(!err);
+
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ err = reftable_ref_record_equal(&rec, &r1[1], GIT_SHA1_RAWSZ);
+ check(err == 1);
+
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ err = reftable_ref_record_equal(&rec, &r2[1], GIT_SHA1_RAWSZ);
+ check(err == 1);
+
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(err > 0);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
+ reftable_buf_release(&bufs[i]);
+ readers_destroy(readers, ARRAY_SIZE(refs));
+ reftable_ref_record_release(&rec);
+ reftable_iterator_destroy(&it);
+ reftable_merged_table_free(mt);
+ reftable_free(sources);
+}
+
+static struct reftable_merged_table *
+merged_table_from_log_records(struct reftable_log_record **logs,
+ struct reftable_block_source **source,
+ struct reftable_reader ***readers, const size_t *sizes,
+ struct reftable_buf *buf, const size_t n)
+{
+ struct reftable_merged_table *mt = NULL;
+ struct reftable_write_options opts = {
+ .block_size = 256,
+ .exact_log_message = 1,
+ };
+ int err;
+
+ REFTABLE_CALLOC_ARRAY(*readers, n);
+ check(*readers != NULL);
+ REFTABLE_CALLOC_ARRAY(*source, n);
+ check(*source != NULL);
+
+ for (size_t i = 0; i < n; i++) {
+ t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts);
+ block_source_from_buf(&(*source)[i], &buf[i]);
+
+ err = reftable_reader_new(&(*readers)[i], &(*source)[i],
+ "name");
+ check(!err);
+ }
+
+ err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
+ check(!err);
+ return mt;
+}
+
+static void t_merged_logs(void)
+{
+ struct reftable_log_record r1[] = {
+ {
+ .refname = (char *) "a",
+ .update_index = 2,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value.update = {
+ .old_hash = { 2 },
+ /* deletion */
+ .name = (char *) "jane doe",
+ .email = (char *) "jane@invalid",
+ .message = (char *) "message2",
+ }
+ },
+ {
+ .refname = (char *) "a",
+ .update_index = 1,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value.update = {
+ .old_hash = { 1 },
+ .new_hash = { 2 },
+ .name = (char *) "jane doe",
+ .email = (char *) "jane@invalid",
+ .message = (char *) "message1",
+ }
+ },
+ };
+ struct reftable_log_record r2[] = {
+ {
+ .refname = (char *) "a",
+ .update_index = 3,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value.update = {
+ .new_hash = { 3 },
+ .name = (char *) "jane doe",
+ .email = (char *) "jane@invalid",
+ .message = (char *) "message3",
+ }
+ },
+ };
+ struct reftable_log_record r3[] = {
+ {
+ .refname = (char *) "a",
+ .update_index = 2,
+ .value_type = REFTABLE_LOG_DELETION,
+ },
+ };
+ struct reftable_log_record *want[] = {
+ &r2[0],
+ &r3[0],
+ &r1[1],
+ };
+
+ struct reftable_log_record *logs[] = { r1, r2, r3 };
+ size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
+ struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
+ struct reftable_block_source *bs = NULL;
+ struct reftable_reader **readers = NULL;
+ struct reftable_merged_table *mt = merged_table_from_log_records(
+ logs, &bs, &readers, sizes, bufs, 3);
+ struct reftable_iterator it = { 0 };
+ int err;
+ struct reftable_log_record *out = NULL;
+ size_t len = 0;
+ size_t cap = 0;
+ size_t i;
+
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+ check(!err);
+ err = reftable_iterator_seek_log(&it, "a");
+ check(!err);
+ check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
+ check_int(reftable_merged_table_min_update_index(mt), ==, 1);
+ check_int(reftable_merged_table_max_update_index(mt), ==, 3);
+
+ while (len < 100) { /* cap loops/recursion. */
+ struct reftable_log_record log = { 0 };
+ int err = reftable_iterator_next_log(&it, &log);
+ if (err > 0)
+ break;
+
+ REFTABLE_ALLOC_GROW(out, len + 1, cap);
+ out[len++] = log;
+ }
+ reftable_iterator_destroy(&it);
+
+ check_int(ARRAY_SIZE(want), ==, len);
+ for (i = 0; i < len; i++)
+ check(reftable_log_record_equal(want[i], &out[i],
+ GIT_SHA1_RAWSZ));
+
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+ check(!err);
+ err = reftable_iterator_seek_log_at(&it, "a", 2);
+ check(!err);
+ reftable_log_record_release(&out[0]);
+ err = reftable_iterator_next_log(&it, &out[0]);
+ check(!err);
+ check(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ));
+ reftable_iterator_destroy(&it);
+
+ for (i = 0; i < len; i++)
+ reftable_log_record_release(&out[i]);
+ reftable_free(out);
+
+ for (i = 0; i < 3; i++)
+ reftable_buf_release(&bufs[i]);
+ readers_destroy(readers, 3);
+ reftable_merged_table_free(mt);
+ reftable_free(bs);
+}
+
+static void t_default_write_opts(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_ref_record rec = {
+ .refname = (char *) "master",
+ .update_index = 1,
+ };
+ int err;
+ struct reftable_block_source source = { 0 };
+ uint32_t hash_id;
+ struct reftable_reader *rd = NULL;
+ struct reftable_merged_table *merged = NULL;
+
+ reftable_writer_set_limits(w, 1, 1);
+
+ err = reftable_writer_add_ref(w, &rec);
+ check(!err);
+
+ err = reftable_writer_close(w);
+ check(!err);
+ reftable_writer_free(w);
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&rd, &source, "filename");
+ check(!err);
+
+ hash_id = reftable_reader_hash_id(rd);
+ check_int(hash_id, ==, GIT_SHA1_FORMAT_ID);
+
+ err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID);
+ check_int(err, ==, REFTABLE_FORMAT_ERROR);
+ err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID);
+ check(!err);
+
+ reftable_reader_decref(rd);
+ reftable_merged_table_free(merged);
+ reftable_buf_release(&buf);
+}
+
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_default_write_opts(), "merged table with default write opts");
+ TEST(t_merged_logs(), "merged table with multiple log updates for same ref");
+ TEST(t_merged_refs(), "merged table with multiple updates to same ref");
+ TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times");
+ TEST(t_merged_single_record(), "ref occurring in only one record can be fetched");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c
new file mode 100644
index 0000000000..ada4c19f18
--- /dev/null
+++ b/t/unit-tests/t-reftable-pq.c
@@ -0,0 +1,152 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/constants.h"
+#include "reftable/pq.h"
+
+static void merged_iter_pqueue_check(const struct merged_iter_pqueue *pq)
+{
+ for (size_t i = 1; i < pq->len; i++) {
+ size_t parent = (i - 1) / 2;
+ check(pq_less(&pq->heap[parent], &pq->heap[i]));
+ }
+}
+
+static int pq_entry_equal(struct pq_entry *a, struct pq_entry *b)
+{
+ return !reftable_record_cmp(a->rec, b->rec) && (a->index == b->index);
+}
+
+static void t_pq_record(void)
+{
+ struct merged_iter_pqueue pq = { 0 };
+ struct reftable_record recs[54];
+ size_t N = ARRAY_SIZE(recs) - 1, i;
+ char *last = NULL;
+
+ for (i = 0; i < N; i++) {
+ reftable_record_init(&recs[i], BLOCK_TYPE_REF);
+ recs[i].u.ref.refname = xstrfmt("%02"PRIuMAX, (uintmax_t)i);
+ }
+
+ i = 1;
+ do {
+ struct pq_entry e = {
+ .rec = &recs[i],
+ };
+
+ merged_iter_pqueue_add(&pq, &e);
+ merged_iter_pqueue_check(&pq);
+ i = (i * 7) % N;
+ } while (i != 1);
+
+ while (!merged_iter_pqueue_is_empty(pq)) {
+ struct pq_entry top = merged_iter_pqueue_top(pq);
+ struct pq_entry e = merged_iter_pqueue_remove(&pq);
+ merged_iter_pqueue_check(&pq);
+
+ check(pq_entry_equal(&top, &e));
+ check(reftable_record_type(e.rec) == BLOCK_TYPE_REF);
+ if (last)
+ check_int(strcmp(last, e.rec->u.ref.refname), <, 0);
+ last = e.rec->u.ref.refname;
+ }
+
+ for (i = 0; i < N; i++)
+ reftable_record_release(&recs[i]);
+ merged_iter_pqueue_release(&pq);
+}
+
+static void t_pq_index(void)
+{
+ struct merged_iter_pqueue pq = { 0 };
+ struct reftable_record recs[13];
+ char *last = NULL;
+ size_t N = ARRAY_SIZE(recs), i;
+
+ for (i = 0; i < N; i++) {
+ reftable_record_init(&recs[i], BLOCK_TYPE_REF);
+ recs[i].u.ref.refname = (char *) "refs/heads/master";
+ }
+
+ i = 1;
+ do {
+ struct pq_entry e = {
+ .rec = &recs[i],
+ .index = i,
+ };
+
+ merged_iter_pqueue_add(&pq, &e);
+ merged_iter_pqueue_check(&pq);
+ i = (i * 7) % N;
+ } while (i != 1);
+
+ for (i = N - 1; i > 0; i--) {
+ struct pq_entry top = merged_iter_pqueue_top(pq);
+ struct pq_entry e = merged_iter_pqueue_remove(&pq);
+ merged_iter_pqueue_check(&pq);
+
+ check(pq_entry_equal(&top, &e));
+ check(reftable_record_type(e.rec) == BLOCK_TYPE_REF);
+ check_int(e.index, ==, i);
+ if (last)
+ check_str(last, e.rec->u.ref.refname);
+ last = e.rec->u.ref.refname;
+ }
+
+ merged_iter_pqueue_release(&pq);
+}
+
+static void t_merged_iter_pqueue_top(void)
+{
+ struct merged_iter_pqueue pq = { 0 };
+ struct reftable_record recs[13];
+ size_t N = ARRAY_SIZE(recs), i;
+
+ for (i = 0; i < N; i++) {
+ reftable_record_init(&recs[i], BLOCK_TYPE_REF);
+ recs[i].u.ref.refname = (char *) "refs/heads/master";
+ }
+
+ i = 1;
+ do {
+ struct pq_entry e = {
+ .rec = &recs[i],
+ .index = i,
+ };
+
+ merged_iter_pqueue_add(&pq, &e);
+ merged_iter_pqueue_check(&pq);
+ i = (i * 7) % N;
+ } while (i != 1);
+
+ for (i = N - 1; i > 0; i--) {
+ struct pq_entry top = merged_iter_pqueue_top(pq);
+ struct pq_entry e = merged_iter_pqueue_remove(&pq);
+
+ merged_iter_pqueue_check(&pq);
+ check(pq_entry_equal(&top, &e));
+ check(reftable_record_equal(top.rec, &recs[i], GIT_SHA1_RAWSZ));
+ for (size_t j = 0; i < pq.len; j++) {
+ check(pq_less(&top, &pq.heap[j]));
+ check_int(top.index, >, j);
+ }
+ }
+
+ merged_iter_pqueue_release(&pq);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_pq_record(), "pq works with record-based comparison");
+ TEST(t_pq_index(), "pq works with index-based comparison");
+ TEST(t_merged_iter_pqueue_top(), "merged_iter_pqueue_top works");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-reader.c b/t/unit-tests/t-reftable-reader.c
new file mode 100644
index 0000000000..19cb53b641
--- /dev/null
+++ b/t/unit-tests/t-reftable-reader.c
@@ -0,0 +1,96 @@
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/blocksource.h"
+#include "reftable/reader.h"
+
+static int t_reader_seek_once(void)
+{
+ struct reftable_ref_record records[] = {
+ {
+ .refname = (char *) "refs/heads/main",
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 42 },
+ },
+ };
+ struct reftable_block_source source = { 0 };
+ struct reftable_ref_record ref = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct reftable_reader *reader;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ int ret;
+
+ t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
+ block_source_from_buf(&source, &buf);
+
+ ret = reftable_reader_new(&reader, &source, "name");
+ check(!ret);
+
+ reftable_reader_init_ref_iterator(reader, &it);
+ ret = reftable_iterator_seek_ref(&it, "");
+ check(!ret);
+ ret = reftable_iterator_next_ref(&it, &ref);
+ check(!ret);
+
+ ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
+ check_int(ret, ==, 1);
+
+ ret = reftable_iterator_next_ref(&it, &ref);
+ check_int(ret, ==, 1);
+
+ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ reftable_reader_decref(reader);
+ reftable_buf_release(&buf);
+ return 0;
+}
+
+static int t_reader_reseek(void)
+{
+ struct reftable_ref_record records[] = {
+ {
+ .refname = (char *) "refs/heads/main",
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { 42 },
+ },
+ };
+ struct reftable_block_source source = { 0 };
+ struct reftable_ref_record ref = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct reftable_reader *reader;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ int ret;
+
+ t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
+ block_source_from_buf(&source, &buf);
+
+ ret = reftable_reader_new(&reader, &source, "name");
+ check(!ret);
+
+ reftable_reader_init_ref_iterator(reader, &it);
+
+ for (size_t i = 0; i < 5; i++) {
+ ret = reftable_iterator_seek_ref(&it, "");
+ check(!ret);
+ ret = reftable_iterator_next_ref(&it, &ref);
+ check(!ret);
+
+ ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
+ check_int(ret, ==, 1);
+
+ ret = reftable_iterator_next_ref(&it, &ref);
+ check_int(ret, ==, 1);
+ }
+
+ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ reftable_reader_decref(reader);
+ reftable_buf_release(&buf);
+ return 0;
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_reader_seek_once(), "reader can seek once");
+ TEST(t_reader_reseek(), "reader can reseek multiple times");
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c
new file mode 100644
index 0000000000..d279b86df0
--- /dev/null
+++ b/t/unit-tests/t-reftable-readwrite.c
@@ -0,0 +1,939 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/basics.h"
+#include "reftable/blocksource.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-writer.h"
+
+static const int update_index = 5;
+
+static void t_buffer(void)
+{
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_block_source source = { 0 };
+ struct reftable_block out = { 0 };
+ int n;
+ uint8_t in[] = "hello";
+ check(!reftable_buf_add(&buf, in, sizeof(in)));
+ block_source_from_buf(&source, &buf);
+ check_int(block_source_size(&source), ==, 6);
+ n = block_source_read_block(&source, &out, 0, sizeof(in));
+ check_int(n, ==, sizeof(in));
+ check(!memcmp(in, out.data, n));
+ reftable_block_done(&out);
+
+ n = block_source_read_block(&source, &out, 1, 2);
+ check_int(n, ==, 2);
+ check(!memcmp(out.data, "el", 2));
+
+ reftable_block_done(&out);
+ block_source_close(&source);
+ reftable_buf_release(&buf);
+}
+
+static void write_table(char ***names, struct reftable_buf *buf, int N,
+ int block_size, uint32_t hash_id)
+{
+ struct reftable_write_options opts = {
+ .block_size = block_size,
+ .hash_id = hash_id,
+ };
+ struct reftable_ref_record *refs;
+ struct reftable_log_record *logs;
+ int i;
+
+ REFTABLE_CALLOC_ARRAY(*names, N + 1);
+ check(*names != NULL);
+ REFTABLE_CALLOC_ARRAY(refs, N);
+ check(refs != NULL);
+ REFTABLE_CALLOC_ARRAY(logs, N);
+ check(logs != NULL);
+
+ for (i = 0; i < N; i++) {
+ refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i);
+ refs[i].update_index = update_index;
+ refs[i].value_type = REFTABLE_REF_VAL1;
+ t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+ }
+
+ for (i = 0; i < N; i++) {
+ logs[i].refname = (*names)[i];
+ logs[i].update_index = update_index;
+ logs[i].value_type = REFTABLE_LOG_UPDATE;
+ t_reftable_set_hash(logs[i].value.update.new_hash, i,
+ GIT_SHA1_FORMAT_ID);
+ logs[i].value.update.message = (char *) "message";
+ }
+
+ t_reftable_write_to_buf(buf, refs, N, logs, N, &opts);
+
+ reftable_free(refs);
+ reftable_free(logs);
+}
+
+static void t_log_buffer_size(void)
+{
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_write_options opts = {
+ .block_size = 4096,
+ };
+ int err;
+ int i;
+ struct reftable_log_record
+ log = { .refname = (char *) "refs/heads/master",
+ .update_index = 0xa,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = { .update = {
+ .name = (char *) "Han-Wen Nienhuys",
+ .email = (char *) "hanwen@google.com",
+ .tz_offset = 100,
+ .time = 0x5e430672,
+ .message = (char *) "commit: 9\n",
+ } } };
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+
+ /* This tests buffer extension for log compression. Must use a random
+ hash, to ensure that the compressed part is larger than the original.
+ */
+ for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
+ log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256);
+ log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256);
+ }
+ reftable_writer_set_limits(w, update_index, update_index);
+ err = reftable_writer_add_log(w, &log);
+ check(!err);
+ err = reftable_writer_close(w);
+ check(!err);
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
+static void t_log_overflow(void)
+{
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ char msg[256] = { 0 };
+ struct reftable_write_options opts = {
+ .block_size = ARRAY_SIZE(msg),
+ };
+ int err;
+ struct reftable_log_record log = {
+ .refname = (char *) "refs/heads/master",
+ .update_index = 0xa,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = {
+ .update = {
+ .old_hash = { 1 },
+ .new_hash = { 2 },
+ .name = (char *) "Han-Wen Nienhuys",
+ .email = (char *) "hanwen@google.com",
+ .tz_offset = 100,
+ .time = 0x5e430672,
+ .message = msg,
+ },
+ },
+ };
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+
+ memset(msg, 'x', sizeof(msg) - 1);
+ reftable_writer_set_limits(w, update_index, update_index);
+ err = reftable_writer_add_log(w, &log);
+ check_int(err, ==, REFTABLE_ENTRY_TOO_BIG_ERROR);
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
+static void t_log_write_read(void)
+{
+ struct reftable_write_options opts = {
+ .block_size = 256,
+ };
+ struct reftable_ref_record ref = { 0 };
+ struct reftable_log_record log = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct reftable_reader *reader;
+ struct reftable_block_source source = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ const struct reftable_stats *stats = NULL;
+ int N = 2, err, i, n;
+ char **names;
+
+ names = reftable_calloc(N + 1, sizeof(*names));
+ check(names != NULL);
+
+ reftable_writer_set_limits(w, 0, N);
+
+ for (i = 0; i < N; i++) {
+ char name[256];
+ struct reftable_ref_record ref = { 0 };
+ snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
+ names[i] = xstrdup(name);
+ ref.refname = name;
+ ref.update_index = i;
+
+ err = reftable_writer_add_ref(w, &ref);
+ check(!err);
+ }
+
+ for (i = 0; i < N; i++) {
+ struct reftable_log_record log = { 0 };
+
+ log.refname = names[i];
+ log.update_index = i;
+ log.value_type = REFTABLE_LOG_UPDATE;
+ t_reftable_set_hash(log.value.update.old_hash, i,
+ GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(log.value.update.new_hash, i + 1,
+ GIT_SHA1_FORMAT_ID);
+
+ err = reftable_writer_add_log(w, &log);
+ check(!err);
+ }
+
+ n = reftable_writer_close(w);
+ check_int(n, ==, 0);
+
+ stats = reftable_writer_stats(w);
+ check_int(stats->log_stats.blocks, >, 0);
+ reftable_writer_free(w);
+ w = NULL;
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&reader, &source, "file.log");
+ check(!err);
+
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+
+ err = reftable_iterator_seek_ref(&it, names[N - 1]);
+ check(!err);
+
+ err = reftable_iterator_next_ref(&it, &ref);
+ check(!err);
+
+ /* end of iteration. */
+ err = reftable_iterator_next_ref(&it, &ref);
+ check_int(err, >, 0);
+
+ reftable_iterator_destroy(&it);
+ reftable_ref_record_release(&ref);
+
+ err = reftable_reader_init_log_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_log(&it, "");
+ check(!err);
+
+ for (i = 0; ; i++) {
+ int err = reftable_iterator_next_log(&it, &log);
+ if (err > 0)
+ break;
+ check(!err);
+ check_str(names[i], log.refname);
+ check_int(i, ==, log.update_index);
+ reftable_log_record_release(&log);
+ }
+
+ check_int(i, ==, N);
+ reftable_iterator_destroy(&it);
+
+ /* cleanup. */
+ reftable_buf_release(&buf);
+ free_names(names);
+ reftable_reader_decref(reader);
+}
+
+static void t_log_zlib_corruption(void)
+{
+ struct reftable_write_options opts = {
+ .block_size = 256,
+ };
+ struct reftable_iterator it = { 0 };
+ struct reftable_reader *reader;
+ struct reftable_block_source source = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ const struct reftable_stats *stats = NULL;
+ char message[100] = { 0 };
+ int err, i, n;
+ struct reftable_log_record log = {
+ .refname = (char *) "refname",
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = {
+ .update = {
+ .new_hash = { 1 },
+ .old_hash = { 2 },
+ .name = (char *) "My Name",
+ .email = (char *) "myname@invalid",
+ .message = message,
+ },
+ },
+ };
+
+ for (i = 0; i < sizeof(message) - 1; i++)
+ message[i] = (uint8_t)(git_rand() % 64 + ' ');
+
+ reftable_writer_set_limits(w, 1, 1);
+
+ err = reftable_writer_add_log(w, &log);
+ check(!err);
+
+ n = reftable_writer_close(w);
+ check_int(n, ==, 0);
+
+ stats = reftable_writer_stats(w);
+ check_int(stats->log_stats.blocks, >, 0);
+ reftable_writer_free(w);
+ w = NULL;
+
+ /* corrupt the data. */
+ buf.buf[50] ^= 0x99;
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&reader, &source, "file.log");
+ check(!err);
+
+ err = reftable_reader_init_log_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_log(&it, "refname");
+ check_int(err, ==, REFTABLE_ZLIB_ERROR);
+
+ reftable_iterator_destroy(&it);
+
+ /* cleanup. */
+ reftable_reader_decref(reader);
+ reftable_buf_release(&buf);
+}
+
+static void t_table_read_write_sequential(void)
+{
+ char **names;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ int N = 50;
+ struct reftable_iterator it = { 0 };
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader *reader;
+ int err = 0;
+ int j = 0;
+
+ write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&reader, &source, "file.ref");
+ check(!err);
+
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, "");
+ check(!err);
+
+ for (j = 0; ; j++) {
+ struct reftable_ref_record ref = { 0 };
+ int r = reftable_iterator_next_ref(&it, &ref);
+ check_int(r, >=, 0);
+ if (r > 0)
+ break;
+ check_str(names[j], ref.refname);
+ check_int(update_index, ==, ref.update_index);
+ reftable_ref_record_release(&ref);
+ }
+ check_int(j, ==, N);
+
+ reftable_iterator_destroy(&it);
+ reftable_reader_decref(reader);
+ reftable_buf_release(&buf);
+ free_names(names);
+}
+
+static void t_table_write_small_table(void)
+{
+ char **names;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ int N = 1;
+ write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
+ check_int(buf.len, <, 200);
+ reftable_buf_release(&buf);
+ free_names(names);
+}
+
+static void t_table_read_api(void)
+{
+ char **names;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ int N = 50;
+ struct reftable_reader *reader;
+ struct reftable_block_source source = { 0 };
+ int err;
+ struct reftable_log_record log = { 0 };
+ struct reftable_iterator it = { 0 };
+
+ write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&reader, &source, "file.ref");
+ check(!err);
+
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, names[0]);
+ check(!err);
+
+ err = reftable_iterator_next_log(&it, &log);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ reftable_buf_release(&buf);
+ free_names(names);
+ reftable_iterator_destroy(&it);
+ reftable_reader_decref(reader);
+ reftable_buf_release(&buf);
+}
+
+static void t_table_read_write_seek(int index, int hash_id)
+{
+ char **names;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ int N = 50;
+ struct reftable_reader *reader;
+ struct reftable_block_source source = { 0 };
+ int err;
+ int i = 0;
+
+ struct reftable_iterator it = { 0 };
+ struct reftable_buf pastLast = REFTABLE_BUF_INIT;
+ struct reftable_ref_record ref = { 0 };
+
+ write_table(&names, &buf, N, 256, hash_id);
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&reader, &source, "file.ref");
+ check(!err);
+ check_int(hash_id, ==, reftable_reader_hash_id(reader));
+
+ if (!index) {
+ reader->ref_offsets.index_offset = 0;
+ } else {
+ check_int(reader->ref_offsets.index_offset, >, 0);
+ }
+
+ for (i = 1; i < N; i++) {
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, names[i]);
+ check(!err);
+ err = reftable_iterator_next_ref(&it, &ref);
+ check(!err);
+ check_str(names[i], ref.refname);
+ check_int(REFTABLE_REF_VAL1, ==, ref.value_type);
+ check_int(i, ==, ref.value.val1[0]);
+
+ reftable_ref_record_release(&ref);
+ reftable_iterator_destroy(&it);
+ }
+
+ check(!reftable_buf_addstr(&pastLast, names[N - 1]));
+ check(!reftable_buf_addstr(&pastLast, "/"));
+
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, pastLast.buf);
+ if (err == 0) {
+ struct reftable_ref_record ref = { 0 };
+ int err = reftable_iterator_next_ref(&it, &ref);
+ check_int(err, >, 0);
+ } else {
+ check_int(err, >, 0);
+ }
+
+ reftable_buf_release(&pastLast);
+ reftable_iterator_destroy(&it);
+
+ reftable_buf_release(&buf);
+ free_names(names);
+ reftable_reader_decref(reader);
+}
+
+static void t_table_read_write_seek_linear(void)
+{
+ t_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
+}
+
+static void t_table_read_write_seek_linear_sha256(void)
+{
+ t_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
+}
+
+static void t_table_read_write_seek_index(void)
+{
+ t_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
+}
+
+static void t_table_refs_for(int indexed)
+{
+ char **want_names;
+ int want_names_len = 0;
+ uint8_t want_hash[GIT_SHA1_RAWSZ];
+
+ struct reftable_write_options opts = {
+ .block_size = 256,
+ };
+ struct reftable_ref_record ref = { 0 };
+ struct reftable_reader *reader;
+ struct reftable_block_source source = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_iterator it = { 0 };
+ int N = 50, n, j, err, i;
+
+ want_names = reftable_calloc(N + 1, sizeof(*want_names));
+ check(want_names != NULL);
+
+ t_reftable_set_hash(want_hash, 4, GIT_SHA1_FORMAT_ID);
+
+ for (i = 0; i < N; i++) {
+ uint8_t hash[GIT_SHA1_RAWSZ];
+ char fill[51] = { 0 };
+ char name[100];
+ struct reftable_ref_record ref = { 0 };
+
+ memset(hash, i, sizeof(hash));
+ memset(fill, 'x', 50);
+ /* Put the variable part in the start */
+ snprintf(name, sizeof(name), "br%02d%s", i, fill);
+ name[40] = 0;
+ ref.refname = name;
+
+ ref.value_type = REFTABLE_REF_VAL2;
+ t_reftable_set_hash(ref.value.val2.value, i / 4,
+ GIT_SHA1_FORMAT_ID);
+ t_reftable_set_hash(ref.value.val2.target_value, 3 + i / 4,
+ GIT_SHA1_FORMAT_ID);
+
+ /* 80 bytes / entry, so 3 entries per block. Yields 17
+ */
+ /* blocks. */
+ n = reftable_writer_add_ref(w, &ref);
+ check_int(n, ==, 0);
+
+ if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) ||
+ !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ))
+ want_names[want_names_len++] = xstrdup(name);
+ }
+
+ n = reftable_writer_close(w);
+ check_int(n, ==, 0);
+
+ reftable_writer_free(w);
+ w = NULL;
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&reader, &source, "file.ref");
+ check(!err);
+ if (!indexed)
+ reader->obj_offsets.is_present = 0;
+
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, "");
+ check(!err);
+ reftable_iterator_destroy(&it);
+
+ err = reftable_reader_refs_for(reader, &it, want_hash);
+ check(!err);
+
+ for (j = 0; ; j++) {
+ int err = reftable_iterator_next_ref(&it, &ref);
+ check_int(err, >=, 0);
+ if (err > 0)
+ break;
+ check_int(j, <, want_names_len);
+ check_str(ref.refname, want_names[j]);
+ reftable_ref_record_release(&ref);
+ }
+ check_int(j, ==, want_names_len);
+
+ reftable_buf_release(&buf);
+ free_names(want_names);
+ reftable_iterator_destroy(&it);
+ reftable_reader_decref(reader);
+}
+
+static void t_table_refs_for_no_index(void)
+{
+ t_table_refs_for(0);
+}
+
+static void t_table_refs_for_obj_index(void)
+{
+ t_table_refs_for(1);
+}
+
+static void t_write_empty_table(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader *rd = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ int err;
+
+ reftable_writer_set_limits(w, 1, 1);
+
+ err = reftable_writer_close(w);
+ check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
+ reftable_writer_free(w);
+
+ check_int(buf.len, ==, header_size(1) + footer_size(1));
+
+ block_source_from_buf(&source, &buf);
+
+ err = reftable_reader_new(&rd, &source, "filename");
+ check(!err);
+
+ err = reftable_reader_init_ref_iterator(rd, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, "");
+ check(!err);
+
+ err = reftable_iterator_next_ref(&it, &rec);
+ check_int(err, >, 0);
+
+ reftable_iterator_destroy(&it);
+ reftable_reader_decref(rd);
+ reftable_buf_release(&buf);
+}
+
+static void t_write_object_id_min_length(void)
+{
+ struct reftable_write_options opts = {
+ .block_size = 75,
+ };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_ref_record ref = {
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = {42},
+ };
+ int err;
+ int i;
+
+ reftable_writer_set_limits(w, 1, 1);
+
+ /* Write the same hash in many refs. If there is only 1 hash, the
+ * disambiguating prefix is length 0 */
+ for (i = 0; i < 256; i++) {
+ char name[256];
+ snprintf(name, sizeof(name), "ref%05d", i);
+ ref.refname = name;
+ err = reftable_writer_add_ref(w, &ref);
+ check(!err);
+ }
+
+ err = reftable_writer_close(w);
+ check(!err);
+ check_int(reftable_writer_stats(w)->object_id_len, ==, 2);
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
+static void t_write_object_id_length(void)
+{
+ struct reftable_write_options opts = {
+ .block_size = 75,
+ };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_ref_record ref = {
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = {42},
+ };
+ int err;
+ int i;
+
+ reftable_writer_set_limits(w, 1, 1);
+
+ /* Write the same hash in many refs. If there is only 1 hash, the
+ * disambiguating prefix is length 0 */
+ for (i = 0; i < 256; i++) {
+ char name[256];
+ snprintf(name, sizeof(name), "ref%05d", i);
+ ref.refname = name;
+ ref.value.val1[15] = i;
+ err = reftable_writer_add_ref(w, &ref);
+ check(!err);
+ }
+
+ err = reftable_writer_close(w);
+ check(!err);
+ check_int(reftable_writer_stats(w)->object_id_len, ==, 16);
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
+static void t_write_empty_key(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_ref_record ref = {
+ .refname = (char *) "",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_DELETION,
+ };
+ int err;
+
+ reftable_writer_set_limits(w, 1, 1);
+ err = reftable_writer_add_ref(w, &ref);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ err = reftable_writer_close(w);
+ check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
+static void t_write_key_order(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+ struct reftable_ref_record refs[2] = {
+ {
+ .refname = (char *) "b",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value = {
+ .symref = (char *) "target",
+ },
+ }, {
+ .refname = (char *) "a",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value = {
+ .symref = (char *) "target",
+ },
+ }
+ };
+ int err;
+
+ reftable_writer_set_limits(w, 1, 1);
+ err = reftable_writer_add_ref(w, &refs[0]);
+ check(!err);
+ err = reftable_writer_add_ref(w, &refs[1]);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ refs[0].update_index = 2;
+ err = reftable_writer_add_ref(w, &refs[0]);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ reftable_writer_close(w);
+ reftable_writer_free(w);
+ reftable_buf_release(&buf);
+}
+
+static void t_write_multiple_indices(void)
+{
+ struct reftable_write_options opts = {
+ .block_size = 100,
+ };
+ struct reftable_buf writer_buf = REFTABLE_BUF_INIT;
+ struct reftable_block_source source = { 0 };
+ struct reftable_iterator it = { 0 };
+ const struct reftable_stats *stats;
+ struct reftable_writer *writer;
+ struct reftable_reader *reader;
+ char buf[128];
+ int err, i;
+
+ writer = t_reftable_strbuf_writer(&writer_buf, &opts);
+ reftable_writer_set_limits(writer, 1, 1);
+ for (i = 0; i < 100; i++) {
+ struct reftable_ref_record ref = {
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = {i},
+ };
+
+ snprintf(buf, sizeof(buf), "refs/heads/%04d", i);
+ ref.refname = buf;
+
+ err = reftable_writer_add_ref(writer, &ref);
+ check(!err);
+ }
+
+ for (i = 0; i < 100; i++) {
+ struct reftable_log_record log = {
+ .update_index = 1,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value.update = {
+ .old_hash = { i },
+ .new_hash = { i },
+ },
+ };
+
+ snprintf(buf, sizeof(buf), "refs/heads/%04d", i);
+ log.refname = buf;
+
+ err = reftable_writer_add_log(writer, &log);
+ check(!err);
+ }
+
+ reftable_writer_close(writer);
+
+ /*
+ * The written data should be sufficiently large to result in indices
+ * for each of the block types.
+ */
+ stats = reftable_writer_stats(writer);
+ check_int(stats->ref_stats.index_offset, >, 0);
+ check_int(stats->obj_stats.index_offset, >, 0);
+ check_int(stats->log_stats.index_offset, >, 0);
+
+ block_source_from_buf(&source, &writer_buf);
+ err = reftable_reader_new(&reader, &source, "filename");
+ check(!err);
+
+ /*
+ * Seeking the log uses the log index now. In case there is any
+ * confusion regarding indices we would notice here.
+ */
+ err = reftable_reader_init_log_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_log(&it, "");
+ check(!err);
+
+ reftable_iterator_destroy(&it);
+ reftable_writer_free(writer);
+ reftable_reader_decref(reader);
+ reftable_buf_release(&writer_buf);
+}
+
+static void t_write_multi_level_index(void)
+{
+ struct reftable_write_options opts = {
+ .block_size = 100,
+ };
+ struct reftable_buf writer_buf = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT;
+ struct reftable_block_source source = { 0 };
+ struct reftable_iterator it = { 0 };
+ const struct reftable_stats *stats;
+ struct reftable_writer *writer;
+ struct reftable_reader *reader;
+ int err;
+
+ writer = t_reftable_strbuf_writer(&writer_buf, &opts);
+ reftable_writer_set_limits(writer, 1, 1);
+ for (size_t i = 0; i < 200; i++) {
+ struct reftable_ref_record ref = {
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = {i},
+ };
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "refs/heads/%03" PRIuMAX, (uintmax_t)i);
+ ref.refname = buf;
+
+ err = reftable_writer_add_ref(writer, &ref);
+ check(!err);
+ }
+ reftable_writer_close(writer);
+
+ /*
+ * The written refs should be sufficiently large to result in a
+ * multi-level index.
+ */
+ stats = reftable_writer_stats(writer);
+ check_int(stats->ref_stats.max_index_level, ==, 2);
+
+ block_source_from_buf(&source, &writer_buf);
+ err = reftable_reader_new(&reader, &source, "filename");
+ check(!err);
+
+ /*
+ * Seeking the last ref should work as expected.
+ */
+ err = reftable_reader_init_ref_iterator(reader, &it);
+ check(!err);
+ err = reftable_iterator_seek_ref(&it, "refs/heads/199");
+ check(!err);
+
+ reftable_iterator_destroy(&it);
+ reftable_writer_free(writer);
+ reftable_reader_decref(reader);
+ reftable_buf_release(&writer_buf);
+ reftable_buf_release(&buf);
+}
+
+static void t_corrupt_table_empty(void)
+{
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader *reader;
+ int err;
+
+ block_source_from_buf(&source, &buf);
+ err = reftable_reader_new(&reader, &source, "file.log");
+ check_int(err, ==, REFTABLE_FORMAT_ERROR);
+}
+
+static void t_corrupt_table(void)
+{
+ uint8_t zeros[1024] = { 0 };
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader *reader;
+ int err;
+ check(!reftable_buf_add(&buf, zeros, sizeof(zeros)));
+
+ block_source_from_buf(&source, &buf);
+ err = reftable_reader_new(&reader, &source, "file.log");
+ check_int(err, ==, REFTABLE_FORMAT_ERROR);
+
+ reftable_buf_release(&buf);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_buffer(), "strbuf works as blocksource");
+ TEST(t_corrupt_table(), "read-write on corrupted table");
+ TEST(t_corrupt_table_empty(), "read-write on an empty table");
+ TEST(t_log_buffer_size(), "buffer extension for log compression");
+ TEST(t_log_overflow(), "log overflow returns expected error");
+ TEST(t_log_write_read(), "read-write on log records");
+ TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error");
+ TEST(t_table_read_api(), "read on a table");
+ TEST(t_table_read_write_seek_index(), "read-write on a table with index");
+ TEST(t_table_read_write_seek_linear(), "read-write on a table without index (SHA1)");
+ TEST(t_table_read_write_seek_linear_sha256(), "read-write on a table without index (SHA256)");
+ TEST(t_table_read_write_sequential(), "sequential read-write on a table");
+ TEST(t_table_refs_for_no_index(), "refs-only table with no index");
+ TEST(t_table_refs_for_obj_index(), "refs-only table with index");
+ TEST(t_table_write_small_table(), "write_table works");
+ TEST(t_write_empty_key(), "write on refs with empty keys");
+ TEST(t_write_empty_table(), "read-write on empty tables");
+ TEST(t_write_key_order(), "refs must be written in increasing order");
+ TEST(t_write_multi_level_index(), "table with multi-level index");
+ TEST(t_write_multiple_indices(), "table with indices for multiple block types");
+ TEST(t_write_object_id_length(), "prefix compression on writing refs");
+ TEST(t_write_object_id_min_length(), "prefix compression on writing refs");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c
new file mode 100644
index 0000000000..eb98bf2da9
--- /dev/null
+++ b/t/unit-tests/t-reftable-record.c
@@ -0,0 +1,551 @@
+/*
+ Copyright 2020 Google LLC
+
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file or at
+ https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/constants.h"
+#include "reftable/record.h"
+
+static void t_copy(struct reftable_record *rec)
+{
+ struct reftable_record copy;
+ uint8_t typ;
+
+ typ = reftable_record_type(rec);
+ reftable_record_init(&copy, typ);
+ reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
+ /* do it twice to catch memory leaks */
+ reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
+ check(reftable_record_equal(rec, &copy, GIT_SHA1_RAWSZ));
+
+ reftable_record_release(&copy);
+}
+
+static void t_varint_roundtrip(void)
+{
+ uint64_t inputs[] = { 0,
+ 1,
+ 27,
+ 127,
+ 128,
+ 257,
+ 4096,
+ ((uint64_t)1 << 63),
+ ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 };
+
+ for (size_t i = 0; i < ARRAY_SIZE(inputs); i++) {
+ uint8_t dest[10];
+
+ struct string_view out = {
+ .buf = dest,
+ .len = sizeof(dest),
+ };
+ uint64_t in = inputs[i];
+ int n = put_var_int(&out, in);
+ uint64_t got = 0;
+
+ check_int(n, >, 0);
+ out.len = n;
+ n = get_var_int(&got, &out);
+ check_int(n, >, 0);
+
+ check_int(got, ==, in);
+ }
+}
+
+static void set_hash(uint8_t *h, int j)
+{
+ for (int i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++)
+ h[i] = (j >> i) & 0xff;
+}
+
+static void t_reftable_ref_record_comparison(void)
+{
+ struct reftable_record in[3] = {
+ {
+ .type = BLOCK_TYPE_REF,
+ .u.ref.refname = (char *) "refs/heads/master",
+ .u.ref.value_type = REFTABLE_REF_VAL1,
+ },
+ {
+ .type = BLOCK_TYPE_REF,
+ .u.ref.refname = (char *) "refs/heads/master",
+ .u.ref.value_type = REFTABLE_REF_DELETION,
+ },
+ {
+ .type = BLOCK_TYPE_REF,
+ .u.ref.refname = (char *) "HEAD",
+ .u.ref.value_type = REFTABLE_REF_SYMREF,
+ .u.ref.value.symref = (char *) "refs/heads/master",
+ },
+ };
+
+ check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+
+ check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
+
+ in[1].u.ref.value_type = in[0].u.ref.value_type;
+ check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+}
+
+static void t_reftable_ref_record_compare_name(void)
+{
+ struct reftable_ref_record recs[3] = {
+ {
+ .refname = (char *) "refs/heads/a"
+ },
+ {
+ .refname = (char *) "refs/heads/b"
+ },
+ {
+ .refname = (char *) "refs/heads/a"
+ },
+ };
+
+ check_int(reftable_ref_record_compare_name(&recs[0], &recs[1]), <, 0);
+ check_int(reftable_ref_record_compare_name(&recs[1], &recs[0]), >, 0);
+ check_int(reftable_ref_record_compare_name(&recs[0], &recs[2]), ==, 0);
+}
+
+static void t_reftable_ref_record_roundtrip(void)
+{
+ struct reftable_buf scratch = REFTABLE_BUF_INIT;
+
+ for (int i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
+ struct reftable_record in = {
+ .type = BLOCK_TYPE_REF,
+ .u.ref.value_type = i,
+ };
+ struct reftable_record out = { .type = BLOCK_TYPE_REF };
+ struct reftable_buf key = REFTABLE_BUF_INIT;
+ uint8_t buffer[1024] = { 0 };
+ struct string_view dest = {
+ .buf = buffer,
+ .len = sizeof(buffer),
+ };
+ int n, m;
+
+ in.u.ref.value_type = i;
+ switch (i) {
+ case REFTABLE_REF_DELETION:
+ break;
+ case REFTABLE_REF_VAL1:
+ set_hash(in.u.ref.value.val1, 1);
+ break;
+ case REFTABLE_REF_VAL2:
+ set_hash(in.u.ref.value.val2.value, 1);
+ set_hash(in.u.ref.value.val2.target_value, 2);
+ break;
+ case REFTABLE_REF_SYMREF:
+ in.u.ref.value.symref = xstrdup("target");
+ break;
+ }
+ in.u.ref.refname = xstrdup("refs/heads/master");
+
+ t_copy(&in);
+
+ check_int(reftable_record_val_type(&in), ==, i);
+ check_int(reftable_record_is_deletion(&in), ==, i == REFTABLE_REF_DELETION);
+
+ reftable_record_key(&in, &key);
+ n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
+ check_int(n, >, 0);
+
+ /* decode into a non-zero reftable_record to test for leaks. */
+ m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch);
+ check_int(n, ==, m);
+
+ check(reftable_ref_record_equal(&in.u.ref, &out.u.ref,
+ GIT_SHA1_RAWSZ));
+ reftable_record_release(&in);
+
+ reftable_buf_release(&key);
+ reftable_record_release(&out);
+ }
+
+ reftable_buf_release(&scratch);
+}
+
+static void t_reftable_log_record_comparison(void)
+{
+ struct reftable_record in[3] = {
+ {
+ .type = BLOCK_TYPE_LOG,
+ .u.log.refname = (char *) "refs/heads/master",
+ .u.log.update_index = 42,
+ },
+ {
+ .type = BLOCK_TYPE_LOG,
+ .u.log.refname = (char *) "refs/heads/master",
+ .u.log.update_index = 22,
+ },
+ {
+ .type = BLOCK_TYPE_LOG,
+ .u.log.refname = (char *) "refs/heads/main",
+ .u.log.update_index = 22,
+ },
+ };
+
+ check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
+ /* comparison should be reversed for equal keys, because
+ * comparison is now performed on the basis of update indices */
+ check_int(reftable_record_cmp(&in[0], &in[1]), <, 0);
+
+ in[1].u.log.update_index = in[0].u.log.update_index;
+ check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+}
+
+static void t_reftable_log_record_compare_key(void)
+{
+ struct reftable_log_record logs[3] = {
+ {
+ .refname = (char *) "refs/heads/a",
+ .update_index = 1,
+ },
+ {
+ .refname = (char *) "refs/heads/b",
+ .update_index = 2,
+ },
+ {
+ .refname = (char *) "refs/heads/a",
+ .update_index = 3,
+ },
+ };
+
+ check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0);
+ check_int(reftable_log_record_compare_key(&logs[1], &logs[0]), >, 0);
+
+ logs[1].update_index = logs[0].update_index;
+ check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0);
+
+ check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), >, 0);
+ check_int(reftable_log_record_compare_key(&logs[2], &logs[0]), <, 0);
+ logs[2].update_index = logs[0].update_index;
+ check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), ==, 0);
+}
+
+static void t_reftable_log_record_roundtrip(void)
+{
+ struct reftable_log_record in[] = {
+ {
+ .refname = xstrdup("refs/heads/master"),
+ .update_index = 42,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = {
+ .update = {
+ .name = xstrdup("han-wen"),
+ .email = xstrdup("hanwen@google.com"),
+ .message = xstrdup("test"),
+ .time = 1577123507,
+ .tz_offset = 100,
+ },
+ }
+ },
+ {
+ .refname = xstrdup("refs/heads/master"),
+ .update_index = 22,
+ .value_type = REFTABLE_LOG_DELETION,
+ },
+ {
+ .refname = xstrdup("branch"),
+ .update_index = 33,
+ .value_type = REFTABLE_LOG_UPDATE,
+ }
+ };
+ struct reftable_buf scratch = REFTABLE_BUF_INIT;
+ set_hash(in[0].value.update.new_hash, 1);
+ set_hash(in[0].value.update.old_hash, 2);
+ set_hash(in[2].value.update.new_hash, 3);
+ set_hash(in[2].value.update.old_hash, 4);
+
+ check(!reftable_log_record_is_deletion(&in[0]));
+ check(reftable_log_record_is_deletion(&in[1]));
+ check(!reftable_log_record_is_deletion(&in[2]));
+
+ for (size_t i = 0; i < ARRAY_SIZE(in); i++) {
+ struct reftable_record rec = { .type = BLOCK_TYPE_LOG };
+ struct reftable_buf key = REFTABLE_BUF_INIT;
+ uint8_t buffer[1024] = { 0 };
+ struct string_view dest = {
+ .buf = buffer,
+ .len = sizeof(buffer),
+ };
+ /* populate out, to check for leaks. */
+ struct reftable_record out = {
+ .type = BLOCK_TYPE_LOG,
+ .u.log = {
+ .refname = xstrdup("old name"),
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = {
+ .update = {
+ .name = xstrdup("old name"),
+ .email = xstrdup("old@email"),
+ .message = xstrdup("old message"),
+ },
+ },
+ },
+ };
+ int n, m, valtype;
+
+ rec.u.log = in[i];
+
+ t_copy(&rec);
+
+ reftable_record_key(&rec, &key);
+
+ n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
+ check_int(n, >=, 0);
+ valtype = reftable_record_val_type(&rec);
+ m = reftable_record_decode(&out, key, valtype, dest,
+ GIT_SHA1_RAWSZ, &scratch);
+ check_int(n, ==, m);
+
+ check(reftable_log_record_equal(&in[i], &out.u.log,
+ GIT_SHA1_RAWSZ));
+ reftable_log_record_release(&in[i]);
+ reftable_buf_release(&key);
+ reftable_record_release(&out);
+ }
+
+ reftable_buf_release(&scratch);
+}
+
+static void t_key_roundtrip(void)
+{
+ uint8_t buffer[1024] = { 0 };
+ struct string_view dest = {
+ .buf = buffer,
+ .len = sizeof(buffer),
+ };
+ struct reftable_buf last_key = REFTABLE_BUF_INIT;
+ struct reftable_buf key = REFTABLE_BUF_INIT;
+ struct reftable_buf roundtrip = REFTABLE_BUF_INIT;
+ int restart;
+ uint8_t extra;
+ int n, m;
+ uint8_t rt_extra;
+
+ check(!reftable_buf_addstr(&last_key, "refs/heads/master"));
+ check(!reftable_buf_addstr(&key, "refs/tags/bla"));
+ extra = 6;
+ n = reftable_encode_key(&restart, dest, last_key, key, extra);
+ check(!restart);
+ check_int(n, >, 0);
+
+ check(!reftable_buf_addstr(&roundtrip, "refs/heads/master"));
+ m = reftable_decode_key(&roundtrip, &rt_extra, dest);
+ check_int(n, ==, m);
+ check(!reftable_buf_cmp(&key, &roundtrip));
+ check_int(rt_extra, ==, extra);
+
+ reftable_buf_release(&last_key);
+ reftable_buf_release(&key);
+ reftable_buf_release(&roundtrip);
+}
+
+static void t_reftable_obj_record_comparison(void)
+{
+
+ uint8_t id_bytes[] = { 0, 1, 2, 3, 4, 5, 6 };
+ uint64_t offsets[] = { 0, 16, 32, 48, 64, 80, 96, 112};
+ struct reftable_record in[3] = {
+ {
+ .type = BLOCK_TYPE_OBJ,
+ .u.obj.hash_prefix = id_bytes,
+ .u.obj.hash_prefix_len = 7,
+ .u.obj.offsets = offsets,
+ .u.obj.offset_len = 8,
+ },
+ {
+ .type = BLOCK_TYPE_OBJ,
+ .u.obj.hash_prefix = id_bytes,
+ .u.obj.hash_prefix_len = 7,
+ .u.obj.offsets = offsets,
+ .u.obj.offset_len = 5,
+ },
+ {
+ .type = BLOCK_TYPE_OBJ,
+ .u.obj.hash_prefix = id_bytes,
+ .u.obj.hash_prefix_len = 5,
+ },
+ };
+
+ check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+
+ check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
+
+ in[1].u.obj.offset_len = in[0].u.obj.offset_len;
+ check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+}
+
+static void t_reftable_obj_record_roundtrip(void)
+{
+ uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 };
+ uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 };
+ struct reftable_obj_record recs[3] = {
+ {
+ .hash_prefix = testHash1,
+ .hash_prefix_len = 5,
+ .offsets = till9,
+ .offset_len = 3,
+ },
+ {
+ .hash_prefix = testHash1,
+ .hash_prefix_len = 5,
+ .offsets = till9,
+ .offset_len = 9,
+ },
+ {
+ .hash_prefix = testHash1,
+ .hash_prefix_len = 5,
+ },
+ };
+ struct reftable_buf scratch = REFTABLE_BUF_INIT;
+
+ for (size_t i = 0; i < ARRAY_SIZE(recs); i++) {
+ uint8_t buffer[1024] = { 0 };
+ struct string_view dest = {
+ .buf = buffer,
+ .len = sizeof(buffer),
+ };
+ struct reftable_record in = {
+ .type = BLOCK_TYPE_OBJ,
+ .u = {
+ .obj = recs[i],
+ },
+ };
+ struct reftable_buf key = REFTABLE_BUF_INIT;
+ struct reftable_record out = { .type = BLOCK_TYPE_OBJ };
+ int n, m;
+ uint8_t extra;
+
+ check(!reftable_record_is_deletion(&in));
+ t_copy(&in);
+ reftable_record_key(&in, &key);
+ n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
+ check_int(n, >, 0);
+ extra = reftable_record_val_type(&in);
+ m = reftable_record_decode(&out, key, extra, dest,
+ GIT_SHA1_RAWSZ, &scratch);
+ check_int(n, ==, m);
+
+ check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
+ reftable_buf_release(&key);
+ reftable_record_release(&out);
+ }
+
+ reftable_buf_release(&scratch);
+}
+
+static void t_reftable_index_record_comparison(void)
+{
+ struct reftable_record in[3] = {
+ {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx.offset = 22,
+ .u.idx.last_key = REFTABLE_BUF_INIT,
+ },
+ {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx.offset = 32,
+ .u.idx.last_key = REFTABLE_BUF_INIT,
+ },
+ {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx.offset = 32,
+ .u.idx.last_key = REFTABLE_BUF_INIT,
+ },
+ };
+ check(!reftable_buf_addstr(&in[0].u.idx.last_key, "refs/heads/master"));
+ check(!reftable_buf_addstr(&in[1].u.idx.last_key, "refs/heads/master"));
+ check(!reftable_buf_addstr(&in[2].u.idx.last_key, "refs/heads/branch"));
+
+ check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+
+ check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ));
+ check_int(reftable_record_cmp(&in[1], &in[2]), >, 0);
+
+ in[1].u.idx.offset = in[0].u.idx.offset;
+ check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
+ check(!reftable_record_cmp(&in[0], &in[1]));
+
+ for (size_t i = 0; i < ARRAY_SIZE(in); i++)
+ reftable_record_release(&in[i]);
+}
+
+static void t_reftable_index_record_roundtrip(void)
+{
+ struct reftable_record in = {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx = {
+ .offset = 42,
+ .last_key = REFTABLE_BUF_INIT,
+ },
+ };
+ uint8_t buffer[1024] = { 0 };
+ struct string_view dest = {
+ .buf = buffer,
+ .len = sizeof(buffer),
+ };
+ struct reftable_buf scratch = REFTABLE_BUF_INIT;
+ struct reftable_buf key = REFTABLE_BUF_INIT;
+ struct reftable_record out = {
+ .type = BLOCK_TYPE_INDEX,
+ .u.idx = { .last_key = REFTABLE_BUF_INIT },
+ };
+ int n, m;
+ uint8_t extra;
+
+ check(!reftable_buf_addstr(&in.u.idx.last_key, "refs/heads/master"));
+ reftable_record_key(&in, &key);
+ t_copy(&in);
+
+ check(!reftable_record_is_deletion(&in));
+ check(!reftable_buf_cmp(&key, &in.u.idx.last_key));
+ n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ);
+ check_int(n, >, 0);
+
+ extra = reftable_record_val_type(&in);
+ m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ,
+ &scratch);
+ check_int(m, ==, n);
+
+ check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
+
+ reftable_record_release(&out);
+ reftable_buf_release(&key);
+ reftable_buf_release(&scratch);
+ reftable_buf_release(&in.u.idx.last_key);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_reftable_ref_record_comparison(), "comparison operations work on ref record");
+ TEST(t_reftable_log_record_comparison(), "comparison operations work on log record");
+ TEST(t_reftable_index_record_comparison(), "comparison operations work on index record");
+ TEST(t_reftable_obj_record_comparison(), "comparison operations work on obj record");
+ TEST(t_reftable_ref_record_compare_name(), "reftable_ref_record_compare_name works");
+ TEST(t_reftable_log_record_compare_key(), "reftable_log_record_compare_key works");
+ TEST(t_reftable_log_record_roundtrip(), "record operations work on log record");
+ TEST(t_reftable_ref_record_roundtrip(), "record operations work on ref record");
+ TEST(t_varint_roundtrip(), "put_var_int and get_var_int work");
+ TEST(t_key_roundtrip(), "reftable_encode_key and reftable_decode_key work");
+ TEST(t_reftable_obj_record_roundtrip(), "record operations work on obj record");
+ TEST(t_reftable_index_record_roundtrip(), "record operations work on index record");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c
new file mode 100644
index 0000000000..72f6747064
--- /dev/null
+++ b/t/unit-tests/t-reftable-stack.c
@@ -0,0 +1,1394 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/merged.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/stack.h"
+#include <dirent.h>
+
+static void clear_dir(const char *dirname)
+{
+ struct strbuf path = REFTABLE_BUF_INIT;
+ strbuf_addstr(&path, dirname);
+ remove_dir_recursively(&path, 0);
+ strbuf_release(&path);
+}
+
+static int count_dir_entries(const char *dirname)
+{
+ DIR *dir = opendir(dirname);
+ int len = 0;
+ struct dirent *d;
+ if (!dir)
+ return 0;
+
+ while ((d = readdir(dir))) {
+ /*
+ * Besides skipping over "." and "..", we also need to
+ * skip over other files that have a leading ".". This
+ * is due to behaviour of NFS, which will rename files
+ * to ".nfs*" to emulate delete-on-last-close.
+ *
+ * In any case this should be fine as the reftable
+ * library will never write files with leading dots
+ * anyway.
+ */
+ if (starts_with(d->d_name, "."))
+ continue;
+ len++;
+ }
+ closedir(dir);
+ return len;
+}
+
+/*
+ * Work linenumber into the tempdir, so we can see which tests forget to
+ * cleanup.
+ */
+static char *get_tmp_template(int linenumber)
+{
+ const char *tmp = getenv("TMPDIR");
+ static char template[1024];
+ snprintf(template, sizeof(template) - 1, "%s/stack_test-%d.XXXXXX",
+ tmp ? tmp : "/tmp", linenumber);
+ return template;
+}
+
+static char *get_tmp_dir(int linenumber)
+{
+ char *dir = get_tmp_template(linenumber);
+ check(mkdtemp(dir) != NULL);
+ return dir;
+}
+
+static void t_read_file(void)
+{
+ char *fn = get_tmp_template(__LINE__);
+ struct tempfile *tmp = mks_tempfile(fn);
+ int fd = get_tempfile_fd(tmp);
+ char out[1024] = "line1\n\nline2\nline3";
+ int n, err;
+ char **names = NULL;
+ const char *want[] = { "line1", "line2", "line3" };
+
+ check_int(fd, >, 0);
+ n = write_in_full(fd, out, strlen(out));
+ check_int(n, ==, strlen(out));
+ err = close(fd);
+ check_int(err, >=, 0);
+
+ err = read_lines(fn, &names);
+ check(!err);
+
+ for (size_t i = 0; names[i]; i++)
+ check_str(want[i], names[i]);
+ free_names(names);
+ (void) remove(fn);
+ delete_tempfile(&tmp);
+}
+
+static int write_test_ref(struct reftable_writer *wr, void *arg)
+{
+ struct reftable_ref_record *ref = arg;
+ reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
+ return reftable_writer_add_ref(wr, ref);
+}
+
+static void write_n_ref_tables(struct reftable_stack *st,
+ size_t n)
+{
+ int disable_auto_compact;
+ int err;
+
+ disable_auto_compact = st->opts.disable_auto_compact;
+ st->opts.disable_auto_compact = 1;
+
+ for (size_t i = 0; i < n; i++) {
+ struct reftable_ref_record ref = {
+ .update_index = reftable_stack_next_update_index(st),
+ .value_type = REFTABLE_REF_VAL1,
+ };
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i);
+ ref.refname = buf;
+ t_reftable_set_hash(ref.value.val1, i, GIT_SHA1_FORMAT_ID);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
+ check(!err);
+ }
+
+ st->opts.disable_auto_compact = disable_auto_compact;
+}
+
+struct write_log_arg {
+ struct reftable_log_record *log;
+ uint64_t update_index;
+};
+
+static int write_test_log(struct reftable_writer *wr, void *arg)
+{
+ struct write_log_arg *wla = arg;
+
+ reftable_writer_set_limits(wr, wla->update_index, wla->update_index);
+ return reftable_writer_add_log(wr, wla->log);
+}
+
+static void t_reftable_stack_add_one(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_buf scratch = REFTABLE_BUF_INIT;
+ int mask = umask(002);
+ struct reftable_write_options opts = {
+ .default_permissions = 0660,
+ };
+ struct reftable_stack *st = NULL;
+ int err;
+ struct reftable_ref_record ref = {
+ .refname = (char *) "HEAD",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ struct reftable_ref_record dest = { 0 };
+ struct stat stat_result = { 0 };
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_add(st, write_test_ref, &ref);
+ check(!err);
+
+ err = reftable_stack_read_ref(st, ref.refname, &dest);
+ check(!err);
+ check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+ check_int(st->readers_len, >, 0);
+
+#ifndef GIT_WINDOWS_NATIVE
+ check(!reftable_buf_addstr(&scratch, dir));
+ check(!reftable_buf_addstr(&scratch, "/tables.list"));
+ err = stat(scratch.buf, &stat_result);
+ check(!err);
+ check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+
+ reftable_buf_reset(&scratch);
+ check(!reftable_buf_addstr(&scratch, dir));
+ check(!reftable_buf_addstr(&scratch, "/"));
+ /* do not try at home; not an external API for reftable. */
+ check(!reftable_buf_addstr(&scratch, st->readers[0]->name));
+ err = stat(scratch.buf, &stat_result);
+ check(!err);
+ check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+#else
+ (void) stat_result;
+#endif
+
+ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
+ reftable_buf_release(&scratch);
+ clear_dir(dir);
+ umask(mask);
+}
+
+static void t_reftable_stack_uptodate(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st1 = NULL;
+ struct reftable_stack *st2 = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+
+ int err;
+ struct reftable_ref_record ref1 = {
+ .refname = (char *) "HEAD",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ struct reftable_ref_record ref2 = {
+ .refname = (char *) "branch2",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+
+
+ /* simulate multi-process access to the same stack
+ by creating two stacks for the same directory.
+ */
+ err = reftable_new_stack(&st1, dir, &opts);
+ check(!err);
+
+ err = reftable_new_stack(&st2, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_add(st1, write_test_ref, &ref1);
+ check(!err);
+
+ err = reftable_stack_add(st2, write_test_ref, &ref2);
+ check_int(err, ==, REFTABLE_OUTDATED_ERROR);
+
+ err = reftable_stack_reload(st2);
+ check(!err);
+
+ err = reftable_stack_add(st2, write_test_ref, &ref2);
+ check(!err);
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_transaction_api(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+ struct reftable_addition *add = NULL;
+
+ struct reftable_ref_record ref = {
+ .refname = (char *) "HEAD",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ struct reftable_ref_record dest = { 0 };
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ reftable_addition_destroy(add);
+
+ err = reftable_stack_new_addition(&add, st, 0);
+ check(!err);
+
+ err = reftable_addition_add(add, write_test_ref, &ref);
+ check(!err);
+
+ err = reftable_addition_commit(add);
+ check(!err);
+
+ reftable_addition_destroy(add);
+
+ err = reftable_stack_read_ref(st, ref.refname, &dest);
+ check(!err);
+ check_int(REFTABLE_REF_SYMREF, ==, dest.value_type);
+ check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+
+ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_transaction_with_reload(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_stack *st1 = NULL, *st2 = NULL;
+ int err;
+ struct reftable_addition *add = NULL;
+ struct reftable_ref_record refs[2] = {
+ {
+ .refname = (char *) "refs/heads/a",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { '1' },
+ },
+ {
+ .refname = (char *) "refs/heads/b",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { '1' },
+ },
+ };
+ struct reftable_ref_record ref = { 0 };
+
+ err = reftable_new_stack(&st1, dir, NULL);
+ check(!err);
+ err = reftable_new_stack(&st2, dir, NULL);
+ check(!err);
+
+ err = reftable_stack_new_addition(&add, st1, 0);
+ check(!err);
+ err = reftable_addition_add(add, write_test_ref, &refs[0]);
+ check(!err);
+ err = reftable_addition_commit(add);
+ check(!err);
+ reftable_addition_destroy(add);
+
+ /*
+ * The second stack is now outdated, which we should notice. We do not
+ * create the addition and lock the stack by default, but allow the
+ * reload to happen when REFTABLE_STACK_NEW_ADDITION_RELOAD is set.
+ */
+ err = reftable_stack_new_addition(&add, st2, 0);
+ check_int(err, ==, REFTABLE_OUTDATED_ERROR);
+ err = reftable_stack_new_addition(&add, st2, REFTABLE_STACK_NEW_ADDITION_RELOAD);
+ check(!err);
+ err = reftable_addition_add(add, write_test_ref, &refs[1]);
+ check(!err);
+ err = reftable_addition_commit(add);
+ check(!err);
+ reftable_addition_destroy(add);
+
+ for (size_t i = 0; i < ARRAY_SIZE(refs); i++) {
+ err = reftable_stack_read_ref(st2, refs[i].refname, &ref);
+ check(!err);
+ check(reftable_ref_record_equal(&refs[i], &ref, GIT_SHA1_RAWSZ));
+ }
+
+ reftable_ref_record_release(&ref);
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_transaction_api_performs_auto_compaction(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = {0};
+ struct reftable_addition *add = NULL;
+ struct reftable_stack *st = NULL;
+ size_t n = 20;
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (size_t i = 0; i <= n; i++) {
+ struct reftable_ref_record ref = {
+ .update_index = reftable_stack_next_update_index(st),
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ char name[100];
+
+ snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
+ ref.refname = name;
+
+ /*
+ * Disable auto-compaction for all but the last runs. Like this
+ * we can ensure that we indeed honor this setting and have
+ * better control over when exactly auto compaction runs.
+ */
+ st->opts.disable_auto_compact = i != n;
+
+ err = reftable_stack_new_addition(&add, st, 0);
+ check(!err);
+
+ err = reftable_addition_add(add, write_test_ref, &ref);
+ check(!err);
+
+ err = reftable_addition_commit(add);
+ check(!err);
+
+ reftable_addition_destroy(add);
+
+ /*
+ * The stack length should grow continuously for all runs where
+ * auto compaction is disabled. When enabled, we should merge
+ * all tables in the stack.
+ */
+ if (i != n)
+ check_int(st->merged->readers_len, ==, i + 1);
+ else
+ check_int(st->merged->readers_len, ==, 1);
+ }
+
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_auto_compaction_fails_gracefully(void)
+{
+ struct reftable_ref_record ref = {
+ .refname = (char *) "refs/heads/master",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = {0x01},
+ };
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st;
+ struct reftable_buf table_path = REFTABLE_BUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_add(st, write_test_ref, &ref);
+ check(!err);
+ check_int(st->merged->readers_len, ==, 1);
+ check_int(st->stats.attempts, ==, 0);
+ check_int(st->stats.failures, ==, 0);
+
+ /*
+ * Lock the newly written table such that it cannot be compacted.
+ * Adding a new table to the stack should not be impacted by this, even
+ * though auto-compaction will now fail.
+ */
+ check(!reftable_buf_addstr(&table_path, dir));
+ check(!reftable_buf_addstr(&table_path, "/"));
+ check(!reftable_buf_addstr(&table_path, st->readers[0]->name));
+ check(!reftable_buf_addstr(&table_path, ".lock"));
+ write_file_buf(table_path.buf, "", 0);
+
+ ref.update_index = 2;
+ err = reftable_stack_add(st, write_test_ref, &ref);
+ check(!err);
+ check_int(st->merged->readers_len, ==, 2);
+ check_int(st->stats.attempts, ==, 1);
+ check_int(st->stats.failures, ==, 1);
+
+ reftable_stack_destroy(st);
+ reftable_buf_release(&table_path);
+ clear_dir(dir);
+}
+
+static int write_error(struct reftable_writer *wr UNUSED, void *arg)
+{
+ return *((int *)arg);
+}
+
+static void t_reftable_stack_update_index_check(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+ struct reftable_ref_record ref1 = {
+ .refname = (char *) "name1",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ struct reftable_ref_record ref2 = {
+ .refname = (char *) "name2",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_add(st, write_test_ref, &ref1);
+ check(!err);
+
+ err = reftable_stack_add(st, write_test_ref, &ref2);
+ check_int(err, ==, REFTABLE_API_ERROR);
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_lock_failure(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ int err, i;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+ for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) {
+ err = reftable_stack_add(st, write_error, &i);
+ check_int(err, ==, i);
+ }
+
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_add(void)
+{
+ int err = 0;
+ struct reftable_write_options opts = {
+ .exact_log_message = 1,
+ .default_permissions = 0660,
+ .disable_auto_compact = 1,
+ };
+ struct reftable_stack *st = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_ref_record refs[2] = { 0 };
+ struct reftable_log_record logs[2] = { 0 };
+ struct reftable_buf path = REFTABLE_BUF_INIT;
+ struct stat stat_result;
+ size_t i, N = ARRAY_SIZE(refs);
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (i = 0; i < N; i++) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i);
+ refs[i].refname = xstrdup(buf);
+ refs[i].update_index = i + 1;
+ refs[i].value_type = REFTABLE_REF_VAL1;
+ t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+
+ logs[i].refname = xstrdup(buf);
+ logs[i].update_index = N + i + 1;
+ logs[i].value_type = REFTABLE_LOG_UPDATE;
+ logs[i].value.update.email = xstrdup("identity@invalid");
+ t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID);
+ }
+
+ for (i = 0; i < N; i++) {
+ int err = reftable_stack_add(st, write_test_ref, &refs[i]);
+ check(!err);
+ }
+
+ for (i = 0; i < N; i++) {
+ struct write_log_arg arg = {
+ .log = &logs[i],
+ .update_index = reftable_stack_next_update_index(st),
+ };
+ int err = reftable_stack_add(st, write_test_log, &arg);
+ check(!err);
+ }
+
+ err = reftable_stack_compact_all(st, NULL);
+ check(!err);
+
+ for (i = 0; i < N; i++) {
+ struct reftable_ref_record dest = { 0 };
+
+ int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
+ check(!err);
+ check(reftable_ref_record_equal(&dest, refs + i,
+ GIT_SHA1_RAWSZ));
+ reftable_ref_record_release(&dest);
+ }
+
+ for (i = 0; i < N; i++) {
+ struct reftable_log_record dest = { 0 };
+ int err = reftable_stack_read_log(st, refs[i].refname, &dest);
+ check(!err);
+ check(reftable_log_record_equal(&dest, logs + i,
+ GIT_SHA1_RAWSZ));
+ reftable_log_record_release(&dest);
+ }
+
+#ifndef GIT_WINDOWS_NATIVE
+ check(!reftable_buf_addstr(&path, dir));
+ check(!reftable_buf_addstr(&path, "/tables.list"));
+ err = stat(path.buf, &stat_result);
+ check(!err);
+ check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+
+ reftable_buf_reset(&path);
+ check(!reftable_buf_addstr(&path, dir));
+ check(!reftable_buf_addstr(&path, "/"));
+ /* do not try at home; not an external API for reftable. */
+ check(!reftable_buf_addstr(&path, st->readers[0]->name));
+ err = stat(path.buf, &stat_result);
+ check(!err);
+ check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+#else
+ (void) stat_result;
+#endif
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ for (i = 0; i < N; i++) {
+ reftable_ref_record_release(&refs[i]);
+ reftable_log_record_release(&logs[i]);
+ }
+ reftable_buf_release(&path);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_iterator(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_ref_record refs[10] = { 0 };
+ struct reftable_log_record logs[10] = { 0 };
+ struct reftable_iterator it = { 0 };
+ size_t N = ARRAY_SIZE(refs), i;
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (i = 0; i < N; i++) {
+ refs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+ refs[i].update_index = i + 1;
+ refs[i].value_type = REFTABLE_REF_VAL1;
+ t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+
+ logs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+ logs[i].update_index = i + 1;
+ logs[i].value_type = REFTABLE_LOG_UPDATE;
+ logs[i].value.update.email = xstrdup("johndoe@invalid");
+ logs[i].value.update.message = xstrdup("commit\n");
+ t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID);
+ }
+
+ for (i = 0; i < N; i++) {
+ err = reftable_stack_add(st, write_test_ref, &refs[i]);
+ check(!err);
+ }
+
+ for (i = 0; i < N; i++) {
+ struct write_log_arg arg = {
+ .log = &logs[i],
+ .update_index = reftable_stack_next_update_index(st),
+ };
+
+ err = reftable_stack_add(st, write_test_log, &arg);
+ check(!err);
+ }
+
+ reftable_stack_init_ref_iterator(st, &it);
+ reftable_iterator_seek_ref(&it, refs[0].refname);
+ for (i = 0; ; i++) {
+ struct reftable_ref_record ref = { 0 };
+
+ err = reftable_iterator_next_ref(&it, &ref);
+ if (err > 0)
+ break;
+ check(!err);
+ check(reftable_ref_record_equal(&ref, &refs[i], GIT_SHA1_RAWSZ));
+ reftable_ref_record_release(&ref);
+ }
+ check_int(i, ==, N);
+
+ reftable_iterator_destroy(&it);
+
+ err = reftable_stack_init_log_iterator(st, &it);
+ check(!err);
+
+ reftable_iterator_seek_log(&it, logs[0].refname);
+ for (i = 0; ; i++) {
+ struct reftable_log_record log = { 0 };
+
+ err = reftable_iterator_next_log(&it, &log);
+ if (err > 0)
+ break;
+ check(!err);
+ check(reftable_log_record_equal(&log, &logs[i], GIT_SHA1_RAWSZ));
+ reftable_log_record_release(&log);
+ }
+ check_int(i, ==, N);
+
+ reftable_stack_destroy(st);
+ reftable_iterator_destroy(&it);
+ for (i = 0; i < N; i++) {
+ reftable_ref_record_release(&refs[i]);
+ reftable_log_record_release(&logs[i]);
+ }
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_log_normalize(void)
+{
+ int err = 0;
+ struct reftable_write_options opts = {
+ 0,
+ };
+ struct reftable_stack *st = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_log_record input = {
+ .refname = (char *) "branch",
+ .update_index = 1,
+ .value_type = REFTABLE_LOG_UPDATE,
+ .value = {
+ .update = {
+ .new_hash = { 1 },
+ .old_hash = { 2 },
+ },
+ },
+ };
+ struct reftable_log_record dest = {
+ .update_index = 0,
+ };
+ struct write_log_arg arg = {
+ .log = &input,
+ .update_index = 1,
+ };
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ input.value.update.message = (char *) "one\ntwo";
+ err = reftable_stack_add(st, write_test_log, &arg);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ input.value.update.message = (char *) "one";
+ err = reftable_stack_add(st, write_test_log, &arg);
+ check(!err);
+
+ err = reftable_stack_read_log(st, input.refname, &dest);
+ check(!err);
+ check_str(dest.value.update.message, "one\n");
+
+ input.value.update.message = (char *) "two\n";
+ arg.update_index = 2;
+ err = reftable_stack_add(st, write_test_log, &arg);
+ check(!err);
+ err = reftable_stack_read_log(st, input.refname, &dest);
+ check(!err);
+ check_str(dest.value.update.message, "two\n");
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ reftable_log_record_release(&dest);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_tombstone(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+ struct reftable_ref_record refs[2] = { 0 };
+ struct reftable_log_record logs[2] = { 0 };
+ size_t i, N = ARRAY_SIZE(refs);
+ struct reftable_ref_record dest = { 0 };
+ struct reftable_log_record log_dest = { 0 };
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ /* even entries add the refs, odd entries delete them. */
+ for (i = 0; i < N; i++) {
+ const char *buf = "branch";
+ refs[i].refname = xstrdup(buf);
+ refs[i].update_index = i + 1;
+ if (i % 2 == 0) {
+ refs[i].value_type = REFTABLE_REF_VAL1;
+ t_reftable_set_hash(refs[i].value.val1, i,
+ GIT_SHA1_FORMAT_ID);
+ }
+
+ logs[i].refname = xstrdup(buf);
+ /* update_index is part of the key. */
+ logs[i].update_index = 42;
+ if (i % 2 == 0) {
+ logs[i].value_type = REFTABLE_LOG_UPDATE;
+ t_reftable_set_hash(logs[i].value.update.new_hash, i,
+ GIT_SHA1_FORMAT_ID);
+ logs[i].value.update.email =
+ xstrdup("identity@invalid");
+ }
+ }
+ for (i = 0; i < N; i++) {
+ int err = reftable_stack_add(st, write_test_ref, &refs[i]);
+ check(!err);
+ }
+
+ for (i = 0; i < N; i++) {
+ struct write_log_arg arg = {
+ .log = &logs[i],
+ .update_index = reftable_stack_next_update_index(st),
+ };
+ int err = reftable_stack_add(st, write_test_log, &arg);
+ check(!err);
+ }
+
+ err = reftable_stack_read_ref(st, "branch", &dest);
+ check_int(err, ==, 1);
+ reftable_ref_record_release(&dest);
+
+ err = reftable_stack_read_log(st, "branch", &log_dest);
+ check_int(err, ==, 1);
+ reftable_log_record_release(&log_dest);
+
+ err = reftable_stack_compact_all(st, NULL);
+ check(!err);
+
+ err = reftable_stack_read_ref(st, "branch", &dest);
+ check_int(err, ==, 1);
+
+ err = reftable_stack_read_log(st, "branch", &log_dest);
+ check_int(err, ==, 1);
+ reftable_ref_record_release(&dest);
+ reftable_log_record_release(&log_dest);
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ for (i = 0; i < N; i++) {
+ reftable_ref_record_release(&refs[i]);
+ reftable_log_record_release(&logs[i]);
+ }
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_hash_id(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+
+ struct reftable_ref_record ref = {
+ .refname = (char *) "master",
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "target",
+ .update_index = 1,
+ };
+ struct reftable_write_options opts32 = { .hash_id = GIT_SHA256_FORMAT_ID };
+ struct reftable_stack *st32 = NULL;
+ struct reftable_write_options opts_default = { 0 };
+ struct reftable_stack *st_default = NULL;
+ struct reftable_ref_record dest = { 0 };
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_add(st, write_test_ref, &ref);
+ check(!err);
+
+ /* can't read it with the wrong hash ID. */
+ err = reftable_new_stack(&st32, dir, &opts32);
+ check_int(err, ==, REFTABLE_FORMAT_ERROR);
+
+ /* check that we can read it back with default opts too. */
+ err = reftable_new_stack(&st_default, dir, &opts_default);
+ check(!err);
+
+ err = reftable_stack_read_ref(st_default, "master", &dest);
+ check(!err);
+
+ check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+ reftable_ref_record_release(&dest);
+ reftable_stack_destroy(st);
+ reftable_stack_destroy(st_default);
+ clear_dir(dir);
+}
+
+static void t_suggest_compaction_segment(void)
+{
+ uint64_t sizes[] = { 512, 64, 17, 16, 9, 9, 9, 16, 2, 16 };
+ struct segment min =
+ suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2);
+ check_int(min.start, ==, 1);
+ check_int(min.end, ==, 10);
+}
+
+static void t_suggest_compaction_segment_nothing(void)
+{
+ uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 };
+ struct segment result =
+ suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2);
+ check_int(result.start, ==, result.end);
+}
+
+static void t_reflog_expire(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ struct reftable_log_record logs[20] = { 0 };
+ size_t i, N = ARRAY_SIZE(logs) - 1;
+ int err;
+ struct reftable_log_expiry_config expiry = {
+ .time = 10,
+ };
+ struct reftable_log_record log = { 0 };
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (i = 1; i <= N; i++) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i);
+
+ logs[i].refname = xstrdup(buf);
+ logs[i].update_index = i;
+ logs[i].value_type = REFTABLE_LOG_UPDATE;
+ logs[i].value.update.time = i;
+ logs[i].value.update.email = xstrdup("identity@invalid");
+ t_reftable_set_hash(logs[i].value.update.new_hash, i,
+ GIT_SHA1_FORMAT_ID);
+ }
+
+ for (i = 1; i <= N; i++) {
+ struct write_log_arg arg = {
+ .log = &logs[i],
+ .update_index = reftable_stack_next_update_index(st),
+ };
+ int err = reftable_stack_add(st, write_test_log, &arg);
+ check(!err);
+ }
+
+ err = reftable_stack_compact_all(st, NULL);
+ check(!err);
+
+ err = reftable_stack_compact_all(st, &expiry);
+ check(!err);
+
+ err = reftable_stack_read_log(st, logs[9].refname, &log);
+ check_int(err, ==, 1);
+
+ err = reftable_stack_read_log(st, logs[11].refname, &log);
+ check(!err);
+
+ expiry.min_update_index = 15;
+ err = reftable_stack_compact_all(st, &expiry);
+ check(!err);
+
+ err = reftable_stack_read_log(st, logs[14].refname, &log);
+ check_int(err, ==, 1);
+
+ err = reftable_stack_read_log(st, logs[16].refname, &log);
+ check(!err);
+
+ /* cleanup */
+ reftable_stack_destroy(st);
+ for (i = 0; i <= N; i++)
+ reftable_log_record_release(&logs[i]);
+ clear_dir(dir);
+ reftable_log_record_release(&log);
+}
+
+static int write_nothing(struct reftable_writer *wr, void *arg UNUSED)
+{
+ reftable_writer_set_limits(wr, 1, 1);
+ return 0;
+}
+
+static void t_empty_add(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ int err;
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_stack *st2 = NULL;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_add(st, write_nothing, NULL);
+ check(!err);
+
+ err = reftable_new_stack(&st2, dir, &opts);
+ check(!err);
+ clear_dir(dir);
+ reftable_stack_destroy(st);
+ reftable_stack_destroy(st2);
+}
+
+static int fastlogN(uint64_t sz, uint64_t N)
+{
+ int l = 0;
+ if (sz == 0)
+ return 0;
+ for (; sz; sz /= N)
+ l++;
+ return l - 1;
+}
+
+static void t_reftable_stack_auto_compaction(void)
+{
+ struct reftable_write_options opts = {
+ .disable_auto_compact = 1,
+ };
+ struct reftable_stack *st = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+ size_t i, N = 100;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (i = 0; i < N; i++) {
+ char name[100];
+ struct reftable_ref_record ref = {
+ .refname = name,
+ .update_index = reftable_stack_next_update_index(st),
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
+
+ err = reftable_stack_add(st, write_test_ref, &ref);
+ check(!err);
+
+ err = reftable_stack_auto_compact(st);
+ check(!err);
+ check(i < 2 || st->merged->readers_len < 2 * fastlogN(i, 2));
+ }
+
+ check_int(reftable_stack_compaction_stats(st)->entries_written, <,
+ (uint64_t)(N * fastlogN(N, 2)));
+
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_auto_compaction_factor(void)
+{
+ struct reftable_write_options opts = {
+ .auto_compaction_factor = 5,
+ };
+ struct reftable_stack *st = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+ size_t N = 100;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (size_t i = 0; i < N; i++) {
+ char name[20];
+ struct reftable_ref_record ref = {
+ .refname = name,
+ .update_index = reftable_stack_next_update_index(st),
+ .value_type = REFTABLE_REF_VAL1,
+ };
+ xsnprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
+ check(!err);
+
+ check(i < 5 || st->merged->readers_len < 5 * fastlogN(i, 5));
+ }
+
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_auto_compaction_with_locked_tables(void)
+{
+ struct reftable_write_options opts = {
+ .disable_auto_compact = 1,
+ };
+ struct reftable_stack *st = NULL;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ write_n_ref_tables(st, 5);
+ check_int(st->merged->readers_len, ==, 5);
+
+ /*
+ * Given that all tables we have written should be roughly the same
+ * size, we expect that auto-compaction will want to compact all of the
+ * tables. Locking any of the tables will keep it from doing so.
+ */
+ check(!reftable_buf_addstr(&buf, dir));
+ check(!reftable_buf_addstr(&buf, "/"));
+ check(!reftable_buf_addstr(&buf, st->readers[2]->name));
+ check(!reftable_buf_addstr(&buf, ".lock"));
+ write_file_buf(buf.buf, "", 0);
+
+ /*
+ * When parts of the stack are locked, then auto-compaction does a best
+ * effort compaction of those tables which aren't locked. So while this
+ * would in theory compact all tables, due to the preexisting lock we
+ * only compact the newest two tables.
+ */
+ err = reftable_stack_auto_compact(st);
+ check(!err);
+ check_int(st->stats.failures, ==, 0);
+ check_int(st->merged->readers_len, ==, 4);
+
+ reftable_stack_destroy(st);
+ reftable_buf_release(&buf);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_add_performs_auto_compaction(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+ size_t i, n = 20;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ for (i = 0; i <= n; i++) {
+ struct reftable_ref_record ref = {
+ .update_index = reftable_stack_next_update_index(st),
+ .value_type = REFTABLE_REF_SYMREF,
+ .value.symref = (char *) "master",
+ };
+ char buf[128];
+
+ /*
+ * Disable auto-compaction for all but the last runs. Like this
+ * we can ensure that we indeed honor this setting and have
+ * better control over when exactly auto compaction runs.
+ */
+ st->opts.disable_auto_compact = i != n;
+
+ snprintf(buf, sizeof(buf), "branch-%04"PRIuMAX, (uintmax_t)i);
+ ref.refname = buf;
+
+ err = reftable_stack_add(st, write_test_ref, &ref);
+ check(!err);
+
+ /*
+ * The stack length should grow continuously for all runs where
+ * auto compaction is disabled. When enabled, we should merge
+ * all tables in the stack.
+ */
+ if (i != n)
+ check_int(st->merged->readers_len, ==, i + 1);
+ else
+ check_int(st->merged->readers_len, ==, 1);
+ }
+
+ reftable_stack_destroy(st);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_compaction_with_locked_tables(void)
+{
+ struct reftable_write_options opts = {
+ .disable_auto_compact = 1,
+ };
+ struct reftable_stack *st = NULL;
+ struct reftable_buf buf = REFTABLE_BUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+
+ write_n_ref_tables(st, 3);
+ check_int(st->merged->readers_len, ==, 3);
+
+ /* Lock one of the tables that we're about to compact. */
+ check(!reftable_buf_addstr(&buf, dir));
+ check(!reftable_buf_addstr(&buf, "/"));
+ check(!reftable_buf_addstr(&buf, st->readers[1]->name));
+ check(!reftable_buf_addstr(&buf, ".lock"));
+ write_file_buf(buf.buf, "", 0);
+
+ /*
+ * Compaction is expected to fail given that we were not able to
+ * compact all tables.
+ */
+ err = reftable_stack_compact_all(st, NULL);
+ check_int(err, ==, REFTABLE_LOCK_ERROR);
+ check_int(st->stats.failures, ==, 1);
+ check_int(st->merged->readers_len, ==, 3);
+
+ reftable_stack_destroy(st);
+ reftable_buf_release(&buf);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_compaction_concurrent(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st1 = NULL, *st2 = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st1, dir, &opts);
+ check(!err);
+ write_n_ref_tables(st1, 3);
+
+ err = reftable_new_stack(&st2, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_compact_all(st1, NULL);
+ check(!err);
+
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+
+ check_int(count_dir_entries(dir), ==, 2);
+ clear_dir(dir);
+}
+
+static void unclean_stack_close(struct reftable_stack *st)
+{
+ /* break abstraction boundary to simulate unclean shutdown. */
+ for (size_t i = 0; i < st->readers_len; i++)
+ reftable_reader_decref(st->readers[i]);
+ st->readers_len = 0;
+ REFTABLE_FREE_AND_NULL(st->readers);
+}
+
+static void t_reftable_stack_compaction_concurrent_clean(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st1, dir, &opts);
+ check(!err);
+ write_n_ref_tables(st1, 3);
+
+ err = reftable_new_stack(&st2, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_compact_all(st1, NULL);
+ check(!err);
+
+ unclean_stack_close(st1);
+ unclean_stack_close(st2);
+
+ err = reftable_new_stack(&st3, dir, &opts);
+ check(!err);
+
+ err = reftable_stack_clean(st3);
+ check(!err);
+ check_int(count_dir_entries(dir), ==, 2);
+
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+ reftable_stack_destroy(st3);
+
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_read_across_reload(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st1 = NULL, *st2 = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ /* Create a first stack and set up an iterator for it. */
+ err = reftable_new_stack(&st1, dir, &opts);
+ check(!err);
+ write_n_ref_tables(st1, 2);
+ check_int(st1->merged->readers_len, ==, 2);
+ reftable_stack_init_ref_iterator(st1, &it);
+ err = reftable_iterator_seek_ref(&it, "");
+ check(!err);
+
+ /* Set up a second stack for the same directory and compact it. */
+ err = reftable_new_stack(&st2, dir, &opts);
+ check(!err);
+ check_int(st2->merged->readers_len, ==, 2);
+ err = reftable_stack_compact_all(st2, NULL);
+ check(!err);
+ check_int(st2->merged->readers_len, ==, 1);
+
+ /*
+ * Verify that we can continue to use the old iterator even after we
+ * have reloaded its stack.
+ */
+ err = reftable_stack_reload(st1);
+ check(!err);
+ check_int(st1->merged->readers_len, ==, 1);
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ check_str(rec.refname, "refs/heads/branch-0000");
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ check_str(rec.refname, "refs/heads/branch-0001");
+ err = reftable_iterator_next_ref(&it, &rec);
+ check_int(err, >, 0);
+
+ reftable_ref_record_release(&rec);
+ reftable_iterator_destroy(&it);
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+ clear_dir(dir);
+}
+
+static void t_reftable_stack_reload_with_missing_table(void)
+{
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *st = NULL;
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
+ struct reftable_buf table_path = REFTABLE_BUF_INIT, content = REFTABLE_BUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ /* Create a first stack and set up an iterator for it. */
+ err = reftable_new_stack(&st, dir, &opts);
+ check(!err);
+ write_n_ref_tables(st, 2);
+ check_int(st->merged->readers_len, ==, 2);
+ reftable_stack_init_ref_iterator(st, &it);
+ err = reftable_iterator_seek_ref(&it, "");
+ check(!err);
+
+ /*
+ * Update the tables.list file with some garbage data, while reusing
+ * our old readers. This should trigger a partial reload of the stack,
+ * where we try to reuse our old readers.
+ */
+ check(!reftable_buf_addstr(&content, st->readers[0]->name));
+ check(!reftable_buf_addstr(&content, "\n"));
+ check(!reftable_buf_addstr(&content, st->readers[1]->name));
+ check(!reftable_buf_addstr(&content, "\n"));
+ check(!reftable_buf_addstr(&content, "garbage\n"));
+ check(!reftable_buf_addstr(&table_path, st->list_file));
+ check(!reftable_buf_addstr(&table_path, ".lock"));
+ write_file_buf(table_path.buf, content.buf, content.len);
+ err = rename(table_path.buf, st->list_file);
+ check(!err);
+
+ err = reftable_stack_reload(st);
+ check_int(err, ==, -4);
+ check_int(st->merged->readers_len, ==, 2);
+
+ /*
+ * Even though the reload has failed, we should be able to continue
+ * using the iterator.
+ */
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ check_str(rec.refname, "refs/heads/branch-0000");
+ err = reftable_iterator_next_ref(&it, &rec);
+ check(!err);
+ check_str(rec.refname, "refs/heads/branch-0001");
+ err = reftable_iterator_next_ref(&it, &rec);
+ check_int(err, >, 0);
+
+ reftable_ref_record_release(&rec);
+ reftable_iterator_destroy(&it);
+ reftable_stack_destroy(st);
+ reftable_buf_release(&table_path);
+ reftable_buf_release(&content);
+ clear_dir(dir);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_empty_add(), "empty addition to stack");
+ TEST(t_read_file(), "read_lines works");
+ TEST(t_reflog_expire(), "expire reflog entries");
+ TEST(t_reftable_stack_add(), "add multiple refs and logs to stack");
+ TEST(t_reftable_stack_add_one(), "add a single ref record to stack");
+ TEST(t_reftable_stack_add_performs_auto_compaction(), "addition to stack triggers auto-compaction");
+ TEST(t_reftable_stack_auto_compaction(), "stack must form geometric sequence after compaction");
+ TEST(t_reftable_stack_auto_compaction_factor(), "auto-compaction with non-default geometric factor");
+ TEST(t_reftable_stack_auto_compaction_fails_gracefully(), "failure on auto-compaction");
+ TEST(t_reftable_stack_auto_compaction_with_locked_tables(), "auto compaction with locked tables");
+ TEST(t_reftable_stack_compaction_concurrent(), "compaction with concurrent stack");
+ TEST(t_reftable_stack_compaction_concurrent_clean(), "compaction with unclean stack shutdown");
+ TEST(t_reftable_stack_compaction_with_locked_tables(), "compaction with locked tables");
+ TEST(t_reftable_stack_hash_id(), "read stack with wrong hash ID");
+ TEST(t_reftable_stack_iterator(), "log and ref iterator for reftable stack");
+ TEST(t_reftable_stack_lock_failure(), "stack addition with lockfile failure");
+ TEST(t_reftable_stack_log_normalize(), "log messages should be normalized");
+ TEST(t_reftable_stack_read_across_reload(), "stack iterators work across reloads");
+ TEST(t_reftable_stack_reload_with_missing_table(), "stack iteration with garbage tables");
+ TEST(t_reftable_stack_tombstone(), "'tombstone' refs in stack");
+ TEST(t_reftable_stack_transaction_api(), "update transaction to stack");
+ TEST(t_reftable_stack_transaction_with_reload(), "transaction with reload");
+ TEST(t_reftable_stack_transaction_api_performs_auto_compaction(), "update transaction triggers auto-compaction");
+ TEST(t_reftable_stack_update_index_check(), "update transactions with equal update indices");
+ TEST(t_reftable_stack_uptodate(), "stack must be reloaded before ref update");
+ TEST(t_suggest_compaction_segment(), "suggest_compaction_segment with basic input");
+ TEST(t_suggest_compaction_segment_nothing(), "suggest_compaction_segment with pre-compacted input");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-tree.c b/t/unit-tests/t-reftable-tree.c
new file mode 100644
index 0000000000..79b175a45a
--- /dev/null
+++ b/t/unit-tests/t-reftable-tree.c
@@ -0,0 +1,86 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/tree.h"
+
+static int t_compare(const void *a, const void *b)
+{
+ return (char *)a - (char *)b;
+}
+
+struct curry {
+ void **arr;
+ size_t len;
+};
+
+static void store(void *arg, void *key)
+{
+ struct curry *c = arg;
+ c->arr[c->len++] = key;
+}
+
+static void t_tree_search(void)
+{
+ struct tree_node *root = NULL;
+ void *values[11] = { 0 };
+ struct tree_node *nodes[11] = { 0 };
+ size_t i = 1;
+
+ /*
+ * Pseudo-randomly insert the pointers for elements between
+ * values[1] and values[10] (inclusive) in the tree.
+ */
+ do {
+ nodes[i] = tree_insert(&root, &values[i], &t_compare);
+ check(nodes[i] != NULL);
+ i = (i * 7) % 11;
+ } while (i != 1);
+
+ for (i = 1; i < ARRAY_SIZE(nodes); i++) {
+ check_pointer_eq(&values[i], nodes[i]->key);
+ check_pointer_eq(nodes[i], tree_search(root, &values[i], &t_compare));
+ }
+
+ check(!tree_search(root, values, t_compare));
+ tree_free(root);
+}
+
+static void t_infix_walk(void)
+{
+ struct tree_node *root = NULL;
+ void *values[11] = { 0 };
+ void *out[11] = { 0 };
+ struct curry c = {
+ .arr = (void **) &out,
+ };
+ size_t i = 1;
+ size_t count = 0;
+
+ do {
+ struct tree_node *node = tree_insert(&root, &values[i], t_compare);
+ check(node != NULL);
+ i = (i * 7) % 11;
+ count++;
+ } while (i != 1);
+
+ infix_walk(root, &store, &c);
+ for (i = 1; i < ARRAY_SIZE(values); i++)
+ check_pointer_eq(&values[i], out[i - 1]);
+ check(!out[i - 1]);
+ check_int(c.len, ==, count);
+ tree_free(root);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+ TEST(t_tree_search(), "tree_search works");
+ TEST(t_infix_walk(), "infix_walk works");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-strbuf.c b/t/unit-tests/t-strbuf.c
new file mode 100644
index 0000000000..3f4044d697
--- /dev/null
+++ b/t/unit-tests/t-strbuf.c
@@ -0,0 +1,122 @@
+#include "test-lib.h"
+#include "strbuf.h"
+
+/* wrapper that supplies tests with an empty, initialized strbuf */
+static void setup(void (*f)(struct strbuf*, const void*),
+ const void *data)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ f(&buf, data);
+ strbuf_release(&buf);
+ check_uint(buf.len, ==, 0);
+ check_uint(buf.alloc, ==, 0);
+}
+
+/* wrapper that supplies tests with a populated, initialized strbuf */
+static void setup_populated(void (*f)(struct strbuf*, const void*),
+ const char *init_str, const void *data)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, init_str);
+ check_uint(buf.len, ==, strlen(init_str));
+ f(&buf, data);
+ strbuf_release(&buf);
+ check_uint(buf.len, ==, 0);
+ check_uint(buf.alloc, ==, 0);
+}
+
+static int assert_sane_strbuf(struct strbuf *buf)
+{
+ /* Initialized strbufs should always have a non-NULL buffer */
+ if (!check(!!buf->buf))
+ return 0;
+ /* Buffers should always be NUL-terminated */
+ if (!check_char(buf->buf[buf->len], ==, '\0'))
+ return 0;
+ /*
+ * Freshly-initialized strbufs may not have a dynamically allocated
+ * buffer
+ */
+ if (buf->len == 0 && buf->alloc == 0)
+ return 1;
+ /* alloc must be at least one byte larger than len */
+ return check_uint(buf->len, <, buf->alloc);
+}
+
+static void t_static_init(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ check_uint(buf.len, ==, 0);
+ check_uint(buf.alloc, ==, 0);
+ check_char(buf.buf[0], ==, '\0');
+}
+
+static void t_dynamic_init(void)
+{
+ struct strbuf buf;
+
+ strbuf_init(&buf, 1024);
+ check(assert_sane_strbuf(&buf));
+ check_uint(buf.len, ==, 0);
+ check_uint(buf.alloc, >=, 1024);
+ check_char(buf.buf[0], ==, '\0');
+ strbuf_release(&buf);
+}
+
+static void t_addch(struct strbuf *buf, const void *data)
+{
+ const char *p_ch = data;
+ const char ch = *p_ch;
+ size_t orig_alloc = buf->alloc;
+ size_t orig_len = buf->len;
+
+ if (!check(assert_sane_strbuf(buf)))
+ return;
+ strbuf_addch(buf, ch);
+ if (!check(assert_sane_strbuf(buf)))
+ return;
+ if (!(check_uint(buf->len, ==, orig_len + 1) &&
+ check_uint(buf->alloc, >=, orig_alloc)))
+ return; /* avoid de-referencing buf->buf */
+ check_char(buf->buf[buf->len - 1], ==, ch);
+ check_char(buf->buf[buf->len], ==, '\0');
+}
+
+static void t_addstr(struct strbuf *buf, const void *data)
+{
+ const char *text = data;
+ size_t len = strlen(text);
+ size_t orig_alloc = buf->alloc;
+ size_t orig_len = buf->len;
+
+ if (!check(assert_sane_strbuf(buf)))
+ return;
+ strbuf_addstr(buf, text);
+ if (!check(assert_sane_strbuf(buf)))
+ return;
+ if (!(check_uint(buf->len, ==, orig_len + len) &&
+ check_uint(buf->alloc, >=, orig_alloc) &&
+ check_uint(buf->alloc, >, orig_len + len) &&
+ check_char(buf->buf[orig_len + len], ==, '\0')))
+ return;
+ check_str(buf->buf + orig_len, text);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ if (!TEST(t_static_init(), "static initialization works"))
+ test_skip_all("STRBUF_INIT is broken");
+ TEST(t_dynamic_init(), "dynamic initialization works");
+ TEST(setup(t_addch, "a"), "strbuf_addch adds char");
+ TEST(setup(t_addch, ""), "strbuf_addch adds NUL char");
+ TEST(setup_populated(t_addch, "initial value", "a"),
+ "strbuf_addch appends to initial value");
+ TEST(setup(t_addstr, "hello there"), "strbuf_addstr adds string");
+ TEST(setup_populated(t_addstr, "initial value", "hello there"),
+ "strbuf_addstr appends string to initial value");
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c
new file mode 100644
index 0000000000..6880f21161
--- /dev/null
+++ b/t/unit-tests/t-strcmp-offset.c
@@ -0,0 +1,35 @@
+#include "test-lib.h"
+#include "read-cache-ll.h"
+
+static void check_strcmp_offset(const char *string1, const char *string2,
+ int expect_result, uintmax_t expect_offset)
+{
+ size_t offset;
+ int result = strcmp_offset(string1, string2, &offset);
+
+ /*
+ * Because different CRTs behave differently, only rely on signs of the
+ * result values.
+ */
+ result = (result < 0 ? -1 :
+ result > 0 ? 1 :
+ 0);
+
+ check_int(result, ==, expect_result);
+ check_uint((uintmax_t)offset, ==, expect_offset);
+}
+
+#define TEST_STRCMP_OFFSET(string1, string2, expect_result, expect_offset) \
+ TEST(check_strcmp_offset(string1, string2, expect_result, \
+ expect_offset), \
+ "strcmp_offset(%s, %s) works", #string1, #string2)
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST_STRCMP_OFFSET("abc", "abc", 0, 3);
+ TEST_STRCMP_OFFSET("abc", "def", -1, 0);
+ TEST_STRCMP_OFFSET("abc", "abz", -1, 2);
+ TEST_STRCMP_OFFSET("abc", "abcdef", -1, 3);
+
+ return test_done();
+}
diff --git a/t/unit-tests/t-trailer.c b/t/unit-tests/t-trailer.c
new file mode 100644
index 0000000000..e1c6ad7461
--- /dev/null
+++ b/t/unit-tests/t-trailer.c
@@ -0,0 +1,315 @@
+#include "test-lib.h"
+#include "trailer.h"
+
+struct contents {
+ const char *raw;
+ const char *key;
+ const char *val;
+};
+
+static void t_trailer_iterator(const char *msg, size_t num_expected,
+ struct contents *contents)
+{
+ struct trailer_iterator iter;
+ size_t i = 0;
+
+ trailer_iterator_init(&iter, msg);
+ while (trailer_iterator_advance(&iter)) {
+ if (num_expected) {
+ check_str(iter.raw, contents[i].raw);
+ check_str(iter.key.buf, contents[i].key);
+ check_str(iter.val.buf, contents[i].val);
+ }
+ i++;
+ }
+ trailer_iterator_release(&iter);
+
+ check_uint(i, ==, num_expected);
+}
+
+static void run_t_trailer_iterator(void)
+{
+
+ static struct test_cases {
+ const char *name;
+ const char *msg;
+ size_t num_expected;
+ struct contents contents[10];
+ } tc[] = {
+ {
+ "empty input",
+ "",
+ 0,
+ {{0}},
+ },
+ {
+ "no newline at beginning",
+ "Fixes: x\n"
+ "Acked-by: x\n"
+ "Reviewed-by: x\n",
+ 0,
+ {{0}},
+ },
+ {
+ "newline at beginning",
+ "\n"
+ "Fixes: x\n"
+ "Acked-by: x\n"
+ "Reviewed-by: x\n",
+ 3,
+ {
+ {
+ .raw = "Fixes: x\n",
+ .key = "Fixes",
+ .val = "x",
+ },
+ {
+ .raw = "Acked-by: x\n",
+ .key = "Acked-by",
+ .val = "x",
+ },
+ {
+ .raw = "Reviewed-by: x\n",
+ .key = "Reviewed-by",
+ .val = "x",
+ },
+ {
+ 0
+ },
+ },
+ },
+ {
+ "without body text",
+ "subject: foo bar\n"
+ "\n"
+ "Fixes: x\n"
+ "Acked-by: x\n"
+ "Reviewed-by: x\n",
+ 3,
+ {
+ {
+ .raw = "Fixes: x\n",
+ .key = "Fixes",
+ .val = "x",
+ },
+ {
+ .raw = "Acked-by: x\n",
+ .key = "Acked-by",
+ .val = "x",
+ },
+ {
+ .raw = "Reviewed-by: x\n",
+ .key = "Reviewed-by",
+ .val = "x",
+ },
+ {
+ 0
+ },
+ },
+ },
+ {
+ "with body text, without divider",
+ "my subject\n"
+ "\n"
+ "my body which is long\n"
+ "and contains some special\n"
+ "chars like : = ? !\n"
+ "hello\n"
+ "\n"
+ "Fixes: x\n"
+ "Acked-by: x\n"
+ "Reviewed-by: x\n"
+ "Signed-off-by: x\n",
+ 4,
+ {
+ {
+ .raw = "Fixes: x\n",
+ .key = "Fixes",
+ .val = "x",
+ },
+ {
+ .raw = "Acked-by: x\n",
+ .key = "Acked-by",
+ .val = "x",
+ },
+ {
+ .raw = "Reviewed-by: x\n",
+ .key = "Reviewed-by",
+ .val = "x",
+ },
+ {
+ .raw = "Signed-off-by: x\n",
+ .key = "Signed-off-by",
+ .val = "x",
+ },
+ {
+ 0
+ },
+ },
+ },
+ {
+ "with body text, without divider (second trailer block)",
+ "my subject\n"
+ "\n"
+ "my body which is long\n"
+ "and contains some special\n"
+ "chars like : = ? !\n"
+ "hello\n"
+ "\n"
+ "Fixes: x\n"
+ "Acked-by: x\n"
+ "Reviewed-by: x\n"
+ "Signed-off-by: x\n"
+ "\n"
+ /*
+ * Because this is the last trailer block, it takes
+ * precedence over the first one encountered above.
+ */
+ "Helped-by: x\n"
+ "Signed-off-by: x\n",
+ 2,
+ {
+ {
+ .raw = "Helped-by: x\n",
+ .key = "Helped-by",
+ .val = "x",
+ },
+ {
+ .raw = "Signed-off-by: x\n",
+ .key = "Signed-off-by",
+ .val = "x",
+ },
+ {
+ 0
+ },
+ },
+ },
+ {
+ "with body text, with divider",
+ "my subject\n"
+ "\n"
+ "my body which is long\n"
+ "and contains some special\n"
+ "chars like : = ? !\n"
+ "hello\n"
+ "\n"
+ "---\n"
+ "\n"
+ /*
+ * This trailer still counts because the iterator
+ * always ignores the divider.
+ */
+ "Signed-off-by: x\n",
+ 1,
+ {
+ {
+ .raw = "Signed-off-by: x\n",
+ .key = "Signed-off-by",
+ .val = "x",
+ },
+ {
+ 0
+ },
+ },
+ },
+ {
+ "with non-trailer lines in trailer block",
+ "subject: foo bar\n"
+ "\n"
+ /*
+ * Even though this trailer block has a non-trailer line
+ * in it, it's still a valid trailer block because it's
+ * at least 25% trailers and is Git-generated (see
+ * git_generated_prefixes[] in trailer.c).
+ */
+ "not a trailer line\n"
+ "not a trailer line\n"
+ "not a trailer line\n"
+ "Signed-off-by: x\n",
+ /*
+ * Even though there is only really 1 real "trailer"
+ * (Signed-off-by), we still have 4 trailer objects
+ * because we still want to iterate through the entire
+ * block.
+ */
+ 4,
+ {
+ {
+ .raw = "not a trailer line\n",
+ .key = "not a trailer line",
+ .val = "",
+ },
+ {
+ .raw = "not a trailer line\n",
+ .key = "not a trailer line",
+ .val = "",
+ },
+ {
+ .raw = "not a trailer line\n",
+ .key = "not a trailer line",
+ .val = "",
+ },
+ {
+ .raw = "Signed-off-by: x\n",
+ .key = "Signed-off-by",
+ .val = "x",
+ },
+ {
+ 0
+ },
+ },
+ },
+ {
+ "with non-trailer lines (one too many) in trailer block",
+ "subject: foo bar\n"
+ "\n"
+ /*
+ * This block has only 20% trailers, so it's below the
+ * 25% threshold.
+ */
+ "not a trailer line\n"
+ "not a trailer line\n"
+ "not a trailer line\n"
+ "not a trailer line\n"
+ "Signed-off-by: x\n",
+ 0,
+ {{0}},
+ },
+ {
+ "with non-trailer lines (only 1) in trailer block, but no Git-generated trailers",
+ "subject: foo bar\n"
+ "\n"
+ /*
+ * This block has only 1 non-trailer out of 10 (IOW, 90%
+ * trailers) but is not considered a trailer block
+ * because the 25% threshold only applies to cases where
+ * there was a Git-generated trailer.
+ */
+ "Reviewed-by: x\n"
+ "Reviewed-by: x\n"
+ "Reviewed-by: x\n"
+ "Helped-by: x\n"
+ "Helped-by: x\n"
+ "Helped-by: x\n"
+ "Acked-by: x\n"
+ "Acked-by: x\n"
+ "Acked-by: x\n"
+ "not a trailer line\n",
+ 0,
+ {{0}},
+ },
+ };
+
+ for (int i = 0; i < sizeof(tc) / sizeof(tc[0]); i++) {
+ TEST(t_trailer_iterator(tc[i].msg,
+ tc[i].num_expected,
+ tc[i].contents),
+ "%s", tc[i].name);
+ }
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ run_t_trailer_iterator();
+ return test_done();
+}
diff --git a/t/unit-tests/t-urlmatch-normalization.c b/t/unit-tests/t-urlmatch-normalization.c
new file mode 100644
index 0000000000..1769c357b9
--- /dev/null
+++ b/t/unit-tests/t-urlmatch-normalization.c
@@ -0,0 +1,271 @@
+#include "test-lib.h"
+#include "urlmatch.h"
+
+static void check_url_normalizable(const char *url, unsigned int normalizable)
+{
+ char *url_norm = url_normalize(url, NULL);
+
+ if (!check_int(normalizable, ==, url_norm ? 1 : 0))
+ test_msg("input url: %s", url);
+ free(url_norm);
+}
+
+static void check_normalized_url(const char *url, const char *expect)
+{
+ char *url_norm = url_normalize(url, NULL);
+
+ if (!check_str(url_norm, expect))
+ test_msg("input url: %s", url);
+ free(url_norm);
+}
+
+static void compare_normalized_urls(const char *url1, const char *url2,
+ unsigned int equal)
+{
+ char *url1_norm = url_normalize(url1, NULL);
+ char *url2_norm = url_normalize(url2, NULL);
+
+ if (equal) {
+ if (!check_str(url1_norm, url2_norm))
+ test_msg("input url1: %s\n input url2: %s", url1,
+ url2);
+ } else if (!check_int(strcmp(url1_norm, url2_norm), !=, 0)) {
+ test_msg(" normalized url1: %s\n normalized url2: %s\n"
+ " input url1: %s\n input url2: %s",
+ url1_norm, url2_norm, url1, url2);
+ }
+ free(url1_norm);
+ free(url2_norm);
+}
+
+static void check_normalized_url_length(const char *url, size_t len)
+{
+ struct url_info info;
+ char *url_norm = url_normalize(url, &info);
+
+ if (!check_int(info.url_len, ==, len))
+ test_msg(" input url: %s\n normalized url: %s", url,
+ url_norm);
+ free(url_norm);
+}
+
+/* Note that only "file:" URLs should be allowed without a host */
+static void t_url_scheme(void)
+{
+ check_url_normalizable("", 0);
+ check_url_normalizable("_", 0);
+ check_url_normalizable("scheme", 0);
+ check_url_normalizable("scheme:", 0);
+ check_url_normalizable("scheme:/", 0);
+ check_url_normalizable("scheme://", 0);
+ check_url_normalizable("file", 0);
+ check_url_normalizable("file:", 0);
+ check_url_normalizable("file:/", 0);
+ check_url_normalizable("file://", 1);
+ check_url_normalizable("://acme.co", 0);
+ check_url_normalizable("x_test://acme.co", 0);
+ check_url_normalizable("-test://acme.co", 0);
+ check_url_normalizable("0test://acme.co", 0);
+ check_url_normalizable("+test://acme.co", 0);
+ check_url_normalizable(".test://acme.co", 0);
+ check_url_normalizable("schem%6e://", 0);
+ check_url_normalizable("x-Test+v1.0://acme.co", 1);
+ check_normalized_url("AbCdeF://x.Y", "abcdef://x.y/");
+}
+
+static void t_url_authority(void)
+{
+ check_url_normalizable("scheme://user:pass@", 0);
+ check_url_normalizable("scheme://?", 0);
+ check_url_normalizable("scheme://#", 0);
+ check_url_normalizable("scheme:///", 0);
+ check_url_normalizable("scheme://:", 0);
+ check_url_normalizable("scheme://:555", 0);
+ check_url_normalizable("file://user:pass@", 1);
+ check_url_normalizable("file://?", 1);
+ check_url_normalizable("file://#", 1);
+ check_url_normalizable("file:///", 1);
+ check_url_normalizable("file://:", 1);
+ check_url_normalizable("file://:555", 0);
+ check_url_normalizable("scheme://user:pass@host", 1);
+ check_url_normalizable("scheme://@host", 1);
+ check_url_normalizable("scheme://%00@host", 1);
+ check_url_normalizable("scheme://%%@host", 0);
+ check_url_normalizable("scheme://host_", 1);
+ check_url_normalizable("scheme://user:pass@host/", 1);
+ check_url_normalizable("scheme://@host/", 1);
+ check_url_normalizable("scheme://host/", 1);
+ check_url_normalizable("scheme://host?x", 1);
+ check_url_normalizable("scheme://host#x", 1);
+ check_url_normalizable("scheme://host/@", 1);
+ check_url_normalizable("scheme://host?@x", 1);
+ check_url_normalizable("scheme://host#@x", 1);
+ check_url_normalizable("scheme://[::1]", 1);
+ check_url_normalizable("scheme://[::1]/", 1);
+ check_url_normalizable("scheme://hos%41/", 0);
+ check_url_normalizable("scheme://[invalid....:/", 1);
+ check_url_normalizable("scheme://invalid....:]/", 1);
+ check_url_normalizable("scheme://invalid....:[/", 0);
+ check_url_normalizable("scheme://invalid....:[", 0);
+}
+
+static void t_url_port(void)
+{
+ check_url_normalizable("xyz://q@some.host:", 1);
+ check_url_normalizable("xyz://q@some.host:456/", 1);
+ check_url_normalizable("xyz://q@some.host:0", 0);
+ check_url_normalizable("xyz://q@some.host:0000000", 0);
+ check_url_normalizable("xyz://q@some.host:0000001?", 1);
+ check_url_normalizable("xyz://q@some.host:065535#", 1);
+ check_url_normalizable("xyz://q@some.host:65535", 1);
+ check_url_normalizable("xyz://q@some.host:65536", 0);
+ check_url_normalizable("xyz://q@some.host:99999", 0);
+ check_url_normalizable("xyz://q@some.host:100000", 0);
+ check_url_normalizable("xyz://q@some.host:100001", 0);
+ check_url_normalizable("http://q@some.host:80", 1);
+ check_url_normalizable("https://q@some.host:443", 1);
+ check_url_normalizable("http://q@some.host:80/", 1);
+ check_url_normalizable("https://q@some.host:443?", 1);
+ check_url_normalizable("http://q@:8008", 0);
+ check_url_normalizable("http://:8080", 0);
+ check_url_normalizable("http://:", 0);
+ check_url_normalizable("xyz://q@some.host:456/", 1);
+ check_url_normalizable("xyz://[::1]:456/", 1);
+ check_url_normalizable("xyz://[::1]:/", 1);
+ check_url_normalizable("xyz://[::1]:000/", 0);
+ check_url_normalizable("xyz://[::1]:0%300/", 0);
+ check_url_normalizable("xyz://[::1]:0x80/", 0);
+ check_url_normalizable("xyz://[::1]:4294967297/", 0);
+ check_url_normalizable("xyz://[::1]:030f/", 0);
+}
+
+static void t_url_port_normalization(void)
+{
+ check_normalized_url("http://x:800", "http://x:800/");
+ check_normalized_url("http://x:0800", "http://x:800/");
+ check_normalized_url("http://x:00000800", "http://x:800/");
+ check_normalized_url("http://x:065535", "http://x:65535/");
+ check_normalized_url("http://x:1", "http://x:1/");
+ check_normalized_url("http://x:80", "http://x/");
+ check_normalized_url("http://x:080", "http://x/");
+ check_normalized_url("http://x:000000080", "http://x/");
+ check_normalized_url("https://x:443", "https://x/");
+ check_normalized_url("https://x:0443", "https://x/");
+ check_normalized_url("https://x:000000443", "https://x/");
+}
+
+static void t_url_general_escape(void)
+{
+ check_url_normalizable("http://x.y?%fg", 0);
+ check_normalized_url("X://W/%7e%41^%3a", "x://w/~A%5E%3A");
+ check_normalized_url("X://W/:/?#[]@", "x://w/:/?#[]@");
+ check_normalized_url("X://W/$&()*+,;=", "x://w/$&()*+,;=");
+ check_normalized_url("X://W/'", "x://w/'");
+ check_normalized_url("X://W?!", "x://w/?!");
+}
+
+static void t_url_high_bit(void)
+{
+ check_normalized_url(
+ "x://q/\x01\x02\x03\x04\x05\x06\x07\x08\x0e\x0f\x10\x11\x12",
+ "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12");
+ check_normalized_url(
+ "x://q/\x13\x14\x15\x16\x17\x18\x19\x1b\x1c\x1d\x1e\x1f\x7f",
+ "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F");
+ check_normalized_url(
+ "x://q/\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
+ "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F");
+ check_normalized_url(
+ "x://q/\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
+ "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F");
+ check_normalized_url(
+ "x://q/\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
+ "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF");
+ check_normalized_url(
+ "x://q/\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
+ "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF");
+ check_normalized_url(
+ "x://q/\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+ "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF");
+ check_normalized_url(
+ "x://q/\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
+ "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF");
+ check_normalized_url(
+ "x://q/\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+ "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF");
+ check_normalized_url(
+ "x://q/\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF");
+}
+
+static void t_url_utf8_escape(void)
+{
+ check_normalized_url(
+ "x://q/\xc2\x80\xdf\xbf\xe0\xa0\x80\xef\xbf\xbd\xf0\x90\x80\x80\xf0\xaf\xbf\xbd",
+ "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD");
+}
+
+static void t_url_username_pass(void)
+{
+ check_normalized_url("x://%41%62(^):%70+d@foo", "x://Ab(%5E):p+d@foo/");
+}
+
+static void t_url_length(void)
+{
+ check_normalized_url_length("Http://%4d%65:%4d^%70@The.Host", 25);
+ check_normalized_url_length("http://%41:%42@x.y/%61/", 17);
+ check_normalized_url_length("http://@x.y/^", 15);
+}
+
+static void t_url_dots(void)
+{
+ check_normalized_url("x://y/.", "x://y/");
+ check_normalized_url("x://y/./", "x://y/");
+ check_normalized_url("x://y/a/.", "x://y/a");
+ check_normalized_url("x://y/a/./", "x://y/a/");
+ check_normalized_url("x://y/.?", "x://y/?");
+ check_normalized_url("x://y/./?", "x://y/?");
+ check_normalized_url("x://y/a/.?", "x://y/a?");
+ check_normalized_url("x://y/a/./?", "x://y/a/?");
+ check_normalized_url("x://y/a/./b/.././../c", "x://y/c");
+ check_normalized_url("x://y/a/./b/../.././c/", "x://y/c/");
+ check_normalized_url("x://y/a/./b/.././../c/././.././.", "x://y/");
+ check_url_normalizable("x://y/a/./b/.././../c/././.././..", 0);
+ check_normalized_url("x://y/a/./?/././..", "x://y/a/?/././..");
+ check_normalized_url("x://y/%2e/", "x://y/");
+ check_normalized_url("x://y/%2E/", "x://y/");
+ check_normalized_url("x://y/a/%2e./", "x://y/");
+ check_normalized_url("x://y/b/.%2E/", "x://y/");
+ check_normalized_url("x://y/c/%2e%2E/", "x://y/");
+}
+
+/*
+ * "http://@foo" specifies an empty user name but does not specify a password.
+ * "http://foo" specifies neither a user name nor a password.
+ * So they should not be equivalent.
+ */
+static void t_url_equivalents(void)
+{
+ compare_normalized_urls("httP://x", "Http://X/", 1);
+ compare_normalized_urls("Http://%4d%65:%4d^%70@The.Host", "hTTP://Me:%4D^p@the.HOST:80/", 1);
+ compare_normalized_urls("https://@x.y/^", "httpS://x.y:443/^", 0);
+ compare_normalized_urls("https://@x.y/^", "httpS://@x.y:0443/^", 1);
+ compare_normalized_urls("https://@x.y/^/../abc", "httpS://@x.y:0443/abc", 1);
+ compare_normalized_urls("https://@x.y/^/..", "httpS://@x.y:0443/", 1);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(t_url_scheme(), "url scheme");
+ TEST(t_url_authority(), "url authority");
+ TEST(t_url_port(), "url port checks");
+ TEST(t_url_port_normalization(), "url port normalization");
+ TEST(t_url_general_escape(), "url general escapes");
+ TEST(t_url_high_bit(), "url high-bit escapes");
+ TEST(t_url_utf8_escape(), "url utf8 escapes");
+ TEST(t_url_username_pass(), "url username/password escapes");
+ TEST(t_url_length(), "url normalized lengths");
+ TEST(t_url_dots(), "url . and .. segments");
+ TEST(t_url_equivalents(), "url equivalents");
+ return test_done();
+}
diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c
new file mode 100644
index 0000000000..fa1f95965c
--- /dev/null
+++ b/t/unit-tests/test-lib.c
@@ -0,0 +1,454 @@
+#include "test-lib.h"
+
+enum result {
+ RESULT_NONE,
+ RESULT_FAILURE,
+ RESULT_SKIP,
+ RESULT_SUCCESS,
+ RESULT_TODO
+};
+
+static struct {
+ enum result result;
+ int count;
+ unsigned failed :1;
+ unsigned lazy_plan :1;
+ unsigned running :1;
+ unsigned skip_all :1;
+ unsigned todo :1;
+ char location[100];
+ char description[100];
+} ctx = {
+ .lazy_plan = 1,
+ .result = RESULT_NONE,
+};
+
+/*
+ * Visual C interpolates the absolute Windows path for `__FILE__`,
+ * but we want to see relative paths, as verified by t0080.
+ * There are other compilers that do the same, and are not for
+ * Windows.
+ */
+#include "dir.h"
+
+static const char *make_relative(const char *location)
+{
+ static char prefix[] = __FILE__, buf[PATH_MAX], *p;
+ static size_t prefix_len;
+ static int need_bs_to_fs = -1;
+
+ /* one-time preparation */
+ if (need_bs_to_fs < 0) {
+ size_t len = strlen(prefix);
+ char needle[] = "t\\unit-tests\\test-lib.c";
+ size_t needle_len = strlen(needle);
+
+ if (len < needle_len)
+ die("unexpected prefix '%s'", prefix);
+
+ /*
+ * The path could be relative (t/unit-tests/test-lib.c)
+ * or full (/home/user/git/t/unit-tests/test-lib.c).
+ * Check the slash between "t" and "unit-tests".
+ */
+ prefix_len = len - needle_len;
+ if (prefix[prefix_len + 1] == '/') {
+ /* Oh, we're not Windows */
+ for (size_t i = 0; i < needle_len; i++)
+ if (needle[i] == '\\')
+ needle[i] = '/';
+ need_bs_to_fs = 0;
+ } else {
+ need_bs_to_fs = 1;
+ }
+
+ /*
+ * prefix_len == 0 if the compiler gives paths relative
+ * to the root of the working tree. Otherwise, we want
+ * to see that we did find the needle[] at a directory
+ * boundary. Again we rely on that needle[] begins with
+ * "t" followed by the directory separator.
+ */
+ if (fspathcmp(needle, prefix + prefix_len) ||
+ (prefix_len && prefix[prefix_len - 1] != needle[1]))
+ die("unexpected suffix of '%s'", prefix);
+ }
+
+ /*
+ * Does it not start with the expected prefix?
+ * Return it as-is without making it worse.
+ */
+ if (prefix_len && fspathncmp(location, prefix, prefix_len))
+ return location;
+
+ /*
+ * If we do not need to munge directory separator, we can return
+ * the substring at the tail of the location.
+ */
+ if (!need_bs_to_fs)
+ return location + prefix_len;
+
+ /* convert backslashes to forward slashes */
+ strlcpy(buf, location + prefix_len, sizeof(buf));
+ for (p = buf; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+ return buf;
+}
+
+static void msg_with_prefix(const char *prefix, const char *format, va_list ap)
+{
+ fflush(stderr);
+ if (prefix)
+ fprintf(stdout, "%s", prefix);
+ vprintf(format, ap); /* TODO: handle newlines */
+ putc('\n', stdout);
+ fflush(stdout);
+}
+
+void test_msg(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ msg_with_prefix("# ", format, ap);
+ va_end(ap);
+}
+
+void test_plan(int count)
+{
+ assert(!ctx.running);
+
+ fflush(stderr);
+ printf("1..%d\n", count);
+ fflush(stdout);
+ ctx.lazy_plan = 0;
+}
+
+int test_done(void)
+{
+ if (ctx.running && ctx.location[0] && ctx.description[0])
+ test__run_end(1, ctx.location, "%s", ctx.description);
+ assert(!ctx.running);
+
+ if (ctx.lazy_plan)
+ test_plan(ctx.count);
+
+ return ctx.failed;
+}
+
+void test_skip(const char *format, ...)
+{
+ va_list ap;
+
+ assert(ctx.running);
+
+ ctx.result = RESULT_SKIP;
+ va_start(ap, format);
+ if (format)
+ msg_with_prefix("# skipping test - ", format, ap);
+ va_end(ap);
+}
+
+void test_skip_all(const char *format, ...)
+{
+ va_list ap;
+ const char *prefix;
+
+ if (!ctx.count && ctx.lazy_plan) {
+ /* We have not printed a test plan yet */
+ prefix = "1..0 # SKIP ";
+ ctx.lazy_plan = 0;
+ } else {
+ /* We have already printed a test plan */
+ prefix = "Bail out! # ";
+ ctx.failed = 1;
+ }
+ ctx.skip_all = 1;
+ ctx.result = RESULT_SKIP;
+ va_start(ap, format);
+ msg_with_prefix(prefix, format, ap);
+ va_end(ap);
+}
+
+void test__run_describe(const char *location, const char *format, ...)
+{
+ va_list ap;
+ int len;
+
+ assert(ctx.running);
+ assert(!ctx.location[0]);
+ assert(!ctx.description[0]);
+
+ xsnprintf(ctx.location, sizeof(ctx.location), "%s",
+ make_relative(location));
+
+ va_start(ap, format);
+ len = vsnprintf(ctx.description, sizeof(ctx.description), format, ap);
+ va_end(ap);
+ if (len < 0)
+ die("unable to format message: %s", format);
+ if (len >= sizeof(ctx.description))
+ BUG("ctx.description too small to format %s", format);
+}
+
+int test__run_begin(void)
+{
+ if (ctx.running && ctx.location[0] && ctx.description[0])
+ test__run_end(1, ctx.location, "%s", ctx.description);
+ assert(!ctx.running);
+
+ ctx.count++;
+ ctx.result = RESULT_NONE;
+ ctx.running = 1;
+ ctx.location[0] = '\0';
+ ctx.description[0] = '\0';
+
+ return ctx.skip_all;
+}
+
+static void print_description(const char *format, va_list ap)
+{
+ if (format) {
+ fputs(" - ", stdout);
+ vprintf(format, ap);
+ }
+}
+
+int test__run_end(int was_run UNUSED, const char *location, const char *format, ...)
+{
+ va_list ap;
+
+ assert(ctx.running);
+ assert(!ctx.todo);
+
+ fflush(stderr);
+ va_start(ap, format);
+ if (!ctx.skip_all) {
+ switch (ctx.result) {
+ case RESULT_SUCCESS:
+ printf("ok %d", ctx.count);
+ print_description(format, ap);
+ break;
+
+ case RESULT_FAILURE:
+ printf("not ok %d", ctx.count);
+ print_description(format, ap);
+ break;
+
+ case RESULT_TODO:
+ printf("not ok %d", ctx.count);
+ print_description(format, ap);
+ printf(" # TODO");
+ break;
+
+ case RESULT_SKIP:
+ printf("ok %d", ctx.count);
+ print_description(format, ap);
+ printf(" # SKIP");
+ break;
+
+ case RESULT_NONE:
+ test_msg("BUG: test has no checks at %s",
+ make_relative(location));
+ printf("not ok %d", ctx.count);
+ print_description(format, ap);
+ ctx.result = RESULT_FAILURE;
+ break;
+ }
+ }
+ va_end(ap);
+ ctx.running = 0;
+ if (ctx.skip_all)
+ return 1;
+ putc('\n', stdout);
+ fflush(stdout);
+ ctx.failed |= ctx.result == RESULT_FAILURE;
+
+ return ctx.result != RESULT_FAILURE;
+}
+
+static void test_fail(void)
+{
+ assert(ctx.result != RESULT_SKIP);
+
+ ctx.result = RESULT_FAILURE;
+}
+
+static void test_pass(void)
+{
+ assert(ctx.result != RESULT_SKIP);
+
+ if (ctx.result == RESULT_NONE)
+ ctx.result = RESULT_SUCCESS;
+}
+
+static void test_todo(void)
+{
+ assert(ctx.result != RESULT_SKIP);
+
+ if (ctx.result != RESULT_FAILURE)
+ ctx.result = RESULT_TODO;
+}
+
+int test_assert(const char *location, const char *check, int ok)
+{
+ if (!ctx.running) {
+ test_msg("BUG: check outside of test at %s",
+ make_relative(location));
+ ctx.failed = 1;
+ return 0;
+ }
+
+ if (ctx.result == RESULT_SKIP) {
+ test_msg("skipping check '%s' at %s", check,
+ make_relative(location));
+ return 1;
+ }
+ if (!ctx.todo) {
+ if (ok) {
+ test_pass();
+ } else {
+ test_msg("check \"%s\" failed at %s", check,
+ make_relative(location));
+ test_fail();
+ }
+ }
+
+ return !!ok;
+}
+
+void test__todo_begin(void)
+{
+ assert(ctx.running);
+ assert(!ctx.todo);
+
+ ctx.todo = 1;
+}
+
+int test__todo_end(const char *location, const char *check, int res)
+{
+ assert(ctx.running);
+ assert(ctx.todo);
+
+ ctx.todo = 0;
+ if (ctx.result == RESULT_SKIP)
+ return 1;
+ if (res) {
+ test_msg("todo check '%s' succeeded at %s", check,
+ make_relative(location));
+ test_fail();
+ } else {
+ test_todo();
+ }
+
+ return !res;
+}
+
+int check_bool_loc(const char *loc, const char *check, int ok)
+{
+ return test_assert(loc, check, ok);
+}
+
+union test__tmp test__tmp[2];
+
+int check_pointer_eq_loc(const char *loc, const char *check, int ok,
+ const void *a, const void *b)
+{
+ int ret = test_assert(loc, check, ok);
+
+ if (!ret) {
+ test_msg(" left: %p", a);
+ test_msg(" right: %p", b);
+ }
+
+ return ret;
+}
+
+int check_int_loc(const char *loc, const char *check, int ok,
+ intmax_t a, intmax_t b)
+{
+ int ret = test_assert(loc, check, ok);
+
+ if (!ret) {
+ test_msg(" left: %"PRIdMAX, a);
+ test_msg(" right: %"PRIdMAX, b);
+ }
+
+ return ret;
+}
+
+int check_uint_loc(const char *loc, const char *check, int ok,
+ uintmax_t a, uintmax_t b)
+{
+ int ret = test_assert(loc, check, ok);
+
+ if (!ret) {
+ test_msg(" left: %"PRIuMAX, a);
+ test_msg(" right: %"PRIuMAX, b);
+ }
+
+ return ret;
+}
+
+static void print_one_char(char ch, char quote)
+{
+ if ((unsigned char)ch < 0x20u || ch == 0x7f) {
+ /* TODO: improve handling of \a, \b, \f ... */
+ printf("\\%03o", (unsigned char)ch);
+ } else {
+ if (ch == '\\' || ch == quote)
+ putc('\\', stdout);
+ putc(ch, stdout);
+ }
+}
+
+static void print_char(const char *prefix, char ch)
+{
+ printf("# %s: '", prefix);
+ print_one_char(ch, '\'');
+ fputs("'\n", stdout);
+}
+
+int check_char_loc(const char *loc, const char *check, int ok, char a, char b)
+{
+ int ret = test_assert(loc, check, ok);
+
+ if (!ret) {
+ fflush(stderr);
+ print_char(" left", a);
+ print_char(" right", b);
+ fflush(stdout);
+ }
+
+ return ret;
+}
+
+static void print_str(const char *prefix, const char *str)
+{
+ printf("# %s: ", prefix);
+ if (!str) {
+ fputs("NULL\n", stdout);
+ } else {
+ putc('"', stdout);
+ while (*str)
+ print_one_char(*str++, '"');
+ fputs("\"\n", stdout);
+ }
+}
+
+int check_str_loc(const char *loc, const char *check,
+ const char *a, const char *b)
+{
+ int ok = (!a && !b) || (a && b && !strcmp(a, b));
+ int ret = test_assert(loc, check, ok);
+
+ if (!ret) {
+ fflush(stderr);
+ print_str(" left", a);
+ print_str(" right", b);
+ fflush(stdout);
+ }
+
+ return ret;
+}
diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h
new file mode 100644
index 0000000000..e4b234697f
--- /dev/null
+++ b/t/unit-tests/test-lib.h
@@ -0,0 +1,183 @@
+#ifndef TEST_LIB_H
+#define TEST_LIB_H
+
+#include "git-compat-util.h"
+
+/*
+ * Run a test function, returns 1 if the test succeeds, 0 if it
+ * fails. If test_skip_all() has been called then the test will not be
+ * run. The description for each test should be unique. For example:
+ *
+ * TEST(test_something(arg1, arg2), "something %d %d", arg1, arg2)
+ */
+#define TEST(t, ...) \
+ test__run_end(test__run_begin() ? 0 : (t, 1), \
+ TEST_LOCATION(), __VA_ARGS__)
+
+/*
+ * Run a test unless test_skip_all() has been called. Acts like a
+ * conditional; the test body is expected as a statement or block after
+ * the closing parenthesis. The description for each test should be
+ * unique. E.g.:
+ *
+ * if_test ("something else %d %d", arg1, arg2) {
+ * prepare();
+ * test_something_else(arg1, arg2);
+ * cleanup();
+ * }
+ */
+#define if_test(...) \
+ if (test__run_begin() ? \
+ (test__run_end(0, TEST_LOCATION(), __VA_ARGS__), 0) : \
+ (test__run_describe(TEST_LOCATION(), __VA_ARGS__), 1))
+
+/*
+ * Print a test plan, should be called before any tests. If the number
+ * of tests is not known in advance test_done() will automatically
+ * print a plan at the end of the test program.
+ */
+void test_plan(int count);
+
+/*
+ * test_done() must be called at the end of main(). It will print the
+ * plan if plan() was not called at the beginning of the test program
+ * and returns the exit code for the test program.
+ */
+int test_done(void);
+
+/* Skip the current test. */
+__attribute__((format (printf, 1, 2)))
+void test_skip(const char *format, ...);
+
+/* Skip all remaining tests. */
+__attribute__((format (printf, 1, 2)))
+void test_skip_all(const char *format, ...);
+
+/* Print a diagnostic message to stdout. */
+__attribute__((format (printf, 1, 2)))
+void test_msg(const char *format, ...);
+
+/*
+ * Test checks are built around test_assert(). checks return 1 on
+ * success, 0 on failure. If any check fails then the test will fail. To
+ * create a custom check define a function that wraps test_assert() and
+ * a macro to wrap that function to provide a source location and
+ * stringified arguments. Custom checks that take pointer arguments
+ * should be careful to check that they are non-NULL before
+ * dereferencing them. For example:
+ *
+ * static int check_oid_loc(const char *loc, const char *check,
+ * struct object_id *a, struct object_id *b)
+ * {
+ * int res = test_assert(loc, check, a && b && oideq(a, b));
+ *
+ * if (!res) {
+ * test_msg(" left: %s", a ? oid_to_hex(a) : "NULL";
+ * test_msg(" right: %s", b ? oid_to_hex(a) : "NULL";
+ *
+ * }
+ * return res;
+ * }
+ *
+ * #define check_oid(a, b) \
+ * check_oid_loc(TEST_LOCATION(), "oideq("#a", "#b")", a, b)
+ */
+int test_assert(const char *location, const char *check, int ok);
+
+/* Helper macro to pass the location to checks */
+#define TEST_LOCATION() TEST__MAKE_LOCATION(__LINE__)
+
+/* Check a boolean condition. */
+#define check(x) \
+ check_bool_loc(TEST_LOCATION(), #x, x)
+int check_bool_loc(const char *loc, const char *check, int ok);
+
+/*
+ * Compare the equality of two pointers of same type. Prints a message
+ * with the two values if the equality fails. NB this is not thread
+ * safe.
+ */
+#define check_pointer_eq(a, b) \
+ (test__tmp[0].p = (a), test__tmp[1].p = (b), \
+ check_pointer_eq_loc(TEST_LOCATION(), #a" == "#b, \
+ test__tmp[0].p == test__tmp[1].p, \
+ test__tmp[0].p, test__tmp[1].p))
+int check_pointer_eq_loc(const char *loc, const char *check, int ok,
+ const void *a, const void *b);
+
+/*
+ * Compare two integers. Prints a message with the two values if the
+ * comparison fails. NB this is not thread safe.
+ */
+#define check_int(a, op, b) \
+ (test__tmp[0].i = (a), test__tmp[1].i = (b), \
+ check_int_loc(TEST_LOCATION(), #a" "#op" "#b, \
+ test__tmp[0].i op test__tmp[1].i, \
+ test__tmp[0].i, test__tmp[1].i))
+int check_int_loc(const char *loc, const char *check, int ok,
+ intmax_t a, intmax_t b);
+
+/*
+ * Compare two unsigned integers. Prints a message with the two values
+ * if the comparison fails. NB this is not thread safe.
+ */
+#define check_uint(a, op, b) \
+ (test__tmp[0].u = (a), test__tmp[1].u = (b), \
+ check_uint_loc(TEST_LOCATION(), #a" "#op" "#b, \
+ test__tmp[0].u op test__tmp[1].u, \
+ test__tmp[0].u, test__tmp[1].u))
+int check_uint_loc(const char *loc, const char *check, int ok,
+ uintmax_t a, uintmax_t b);
+
+/*
+ * Compare two chars. Prints a message with the two values if the
+ * comparison fails. NB this is not thread safe.
+ */
+#define check_char(a, op, b) \
+ (test__tmp[0].c = (a), test__tmp[1].c = (b), \
+ check_char_loc(TEST_LOCATION(), #a" "#op" "#b, \
+ test__tmp[0].c op test__tmp[1].c, \
+ test__tmp[0].c, test__tmp[1].c))
+int check_char_loc(const char *loc, const char *check, int ok,
+ char a, char b);
+
+/* Check whether two strings are equal. */
+#define check_str(a, b) \
+ check_str_loc(TEST_LOCATION(), "!strcmp("#a", "#b")", a, b)
+int check_str_loc(const char *loc, const char *check,
+ const char *a, const char *b);
+
+/*
+ * Wrap a check that is known to fail. If the check succeeds then the
+ * test will fail. Returns 1 if the check fails, 0 if it
+ * succeeds. For example:
+ *
+ * TEST_TODO(check(0));
+ */
+#define TEST_TODO(check) \
+ (test__todo_begin(), test__todo_end(TEST_LOCATION(), #check, check))
+
+/* Private helpers */
+
+#define TEST__STR(x) #x
+#define TEST__MAKE_LOCATION(line) __FILE__ ":" TEST__STR(line)
+
+union test__tmp {
+ intmax_t i;
+ uintmax_t u;
+ char c;
+ const void *p;
+};
+
+extern union test__tmp test__tmp[2];
+
+__attribute__((format (printf, 2, 3)))
+void test__run_describe(const char *, const char *, ...);
+
+int test__run_begin(void);
+__attribute__((format (printf, 3, 4)))
+int test__run_end(int, const char *, const char *, ...);
+void test__todo_begin(void);
+int test__todo_end(const char *, const char *, int);
+
+#endif /* TEST_LIB_H */
diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c
new file mode 100644
index 0000000000..a474cdcfd3
--- /dev/null
+++ b/t/unit-tests/unit-test.c
@@ -0,0 +1,47 @@
+#include "unit-test.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "strvec.h"
+
+static const char * const unit_test_usage[] = {
+ N_("unit-test [<options>]"),
+ NULL,
+};
+
+int cmd_main(int argc, const char **argv)
+{
+ struct string_list run_args = STRING_LIST_INIT_NODUP;
+ struct string_list exclude_args = STRING_LIST_INIT_NODUP;
+ int immediate = 0;
+ struct option options[] = {
+ OPT_BOOL('i', "immediate", &immediate,
+ N_("immediately exit upon the first failed test")),
+ OPT_STRING_LIST('r', "run", &run_args, N_("suite[::test]"),
+ N_("run only test suite or individual test <suite[::test]>")),
+ OPT_STRING_LIST('x', "exclude", &exclude_args, N_("suite"),
+ N_("exclude test suite <suite>")),
+ OPT_END(),
+ };
+ struct strvec args = STRVEC_INIT;
+ int ret;
+
+ argc = parse_options(argc, argv, NULL, options,
+ unit_test_usage, PARSE_OPT_KEEP_ARGV0);
+ if (argc > 1)
+ usagef(_("extra command line parameter '%s'"), argv[0]);
+
+ strvec_push(&args, argv[0]);
+ strvec_push(&args, "-t");
+ if (immediate)
+ strvec_push(&args, "-Q");
+ for (size_t i = 0; i < run_args.nr; i++)
+ strvec_pushf(&args, "-s%s", run_args.items[i].string);
+ for (size_t i = 0; i < exclude_args.nr; i++)
+ strvec_pushf(&args, "-x%s", exclude_args.items[i].string);
+
+ ret = clar_test(args.nr, (char **) args.v);
+
+ string_list_clear(&run_args, 0);
+ strvec_clear(&args);
+ return ret;
+}
diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h
new file mode 100644
index 0000000000..85e5d6a948
--- /dev/null
+++ b/t/unit-tests/unit-test.h
@@ -0,0 +1,10 @@
+#include "git-compat-util.h"
+#include "clar/clar.h"
+#include "clar-decls.h"
+#include "strbuf.h"
+
+#define cl_failf(fmt, ...) do { \
+ char desc[4096]; \
+ snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \
+ clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1); \
+} while (0)
diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh
index 669ebaf68b..3c8ee19975 100755
--- a/t/valgrind/valgrind.sh
+++ b/t/valgrind/valgrind.sh
@@ -23,7 +23,7 @@ memcheck)
VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
test 3 -gt "$VALGRIND_MAJOR" ||
- test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
+ { test 3 -eq "$VALGRIND_MAJOR" && test 4 -gt "$VALGRIND_MINOR"; } ||
TOOL_OPTIONS="$TOOL_OPTIONS --track-origins=yes"
;;
*)
diff --git a/tag.c b/tag.c
index fc3834db46..d24170e340 100644
--- a/tag.c
+++ b/tag.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "environment.h"
#include "tag.h"
@@ -91,10 +93,10 @@ struct object *deref_tag(struct repository *r, struct object *o, const char *war
return o;
}
-struct object *deref_tag_noverify(struct object *o)
+struct object *deref_tag_noverify(struct repository *r, struct object *o)
{
while (o && o->type == OBJ_TAG) {
- o = parse_object(the_repository, &o->oid);
+ o = parse_object(r, &o->oid);
if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
o = ((struct tag *)o)->tagged;
else
diff --git a/tag.h b/tag.h
index 3ce8e72192..c49d7c19ad 100644
--- a/tag.h
+++ b/tag.h
@@ -16,7 +16,7 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
int parse_tag(struct tag *item);
void release_tag_memory(struct tag *t);
struct object *deref_tag(struct repository *r, struct object *, const char *, int);
-struct object *deref_tag_noverify(struct object *);
+struct object *deref_tag_noverify(struct repository *r, struct object *);
int gpg_verify_tag(const struct object_id *oid,
const char *name_to_report, unsigned flags);
struct object_id *get_tagged_oid(struct tag *tag);
diff --git a/tempfile.c b/tempfile.c
index ecdebf1afb..ed88cf8431 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -50,15 +50,17 @@
static VOLATILE_LIST_HEAD(tempfile_list);
-static void remove_template_directory(struct tempfile *tempfile,
+static int remove_template_directory(struct tempfile *tempfile,
int in_signal_handler)
{
if (tempfile->directory) {
if (in_signal_handler)
- rmdir(tempfile->directory);
+ return rmdir(tempfile->directory);
else
- rmdir_or_warn(tempfile->directory);
+ return rmdir_or_warn(tempfile->directory);
}
+
+ return 0;
}
static void remove_tempfiles(int in_signal_handler)
@@ -353,16 +355,19 @@ int rename_tempfile(struct tempfile **tempfile_p, const char *path)
return 0;
}
-void delete_tempfile(struct tempfile **tempfile_p)
+int delete_tempfile(struct tempfile **tempfile_p)
{
struct tempfile *tempfile = *tempfile_p;
+ int err = 0;
if (!is_tempfile_active(tempfile))
- return;
+ return 0;
- close_tempfile_gently(tempfile);
- unlink_or_warn(tempfile->filename.buf);
- remove_template_directory(tempfile, 0);
+ err |= close_tempfile_gently(tempfile);
+ err |= unlink_or_warn(tempfile->filename.buf);
+ err |= remove_template_directory(tempfile, 0);
deactivate_tempfile(tempfile);
*tempfile_p = NULL;
+
+ return err ? -1 : 0;
}
diff --git a/tempfile.h b/tempfile.h
index d0413af733..2d2ae5b657 100644
--- a/tempfile.h
+++ b/tempfile.h
@@ -269,7 +269,7 @@ int reopen_tempfile(struct tempfile *tempfile);
* `delete_tempfile()` for a `tempfile` object that has already been
* deleted or renamed.
*/
-void delete_tempfile(struct tempfile **tempfile_p);
+int delete_tempfile(struct tempfile **tempfile_p);
/*
* Close the file descriptor and/or file pointer if they are still
diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample
index e144712c85..29ed5ee486 100755
--- a/templates/hooks--pre-commit.sample
+++ b/templates/hooks--pre-commit.sample
@@ -28,7 +28,7 @@ if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
- test $(git diff --cached --name-only --diff-filter=A -z $against |
+ test $(git diff-index --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
diff --git a/tmp-objdir.c b/tmp-objdir.c
index 5f9074ad1c..9da0071cba 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "tmp-objdir.h"
#include "abspath.h"
@@ -6,12 +8,12 @@
#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-ll.h"
+#include "repository.h"
struct tmp_objdir {
struct strbuf path;
@@ -131,7 +133,8 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
* can recognize any stale objdirs left behind by a crash and delete
* them.
*/
- strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", get_object_directory(), prefix);
+ strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX",
+ repo_get_object_directory(the_repository), prefix);
if (!mkdtemp(t->path.buf)) {
/* free, not destroy, as we never touched the filesystem */
@@ -151,7 +154,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
}
env_append(&t->env, ALTERNATE_DB_ENVIRONMENT,
- absolute_path(get_object_directory()));
+ absolute_path(repo_get_object_directory(the_repository)));
env_replace(&t->env, DB_ENVIRONMENT, absolute_path(t->path.buf));
env_replace(&t->env, GIT_QUARANTINE_ENVIRONMENT,
absolute_path(t->path.buf));
@@ -203,9 +206,11 @@ static int read_dir_paths(struct string_list *out, const char *path)
return 0;
}
-static int migrate_paths(struct strbuf *src, struct strbuf *dst);
+static int migrate_paths(struct strbuf *src, struct strbuf *dst,
+ enum finalize_object_file_flags flags);
-static int migrate_one(struct strbuf *src, struct strbuf *dst)
+static int migrate_one(struct strbuf *src, struct strbuf *dst,
+ enum finalize_object_file_flags flags)
{
struct stat st;
@@ -217,12 +222,18 @@ static int migrate_one(struct strbuf *src, struct strbuf *dst)
return -1;
} else if (errno != EEXIST)
return -1;
- return migrate_paths(src, dst);
+ return migrate_paths(src, dst, flags);
}
- return finalize_object_file(src->buf, dst->buf);
+ return finalize_object_file_flags(src->buf, dst->buf, flags);
}
-static int migrate_paths(struct strbuf *src, struct strbuf *dst)
+static int is_loose_object_shard(const char *name)
+{
+ return strlen(name) == 2 && isxdigit(name[0]) && isxdigit(name[1]);
+}
+
+static int migrate_paths(struct strbuf *src, struct strbuf *dst,
+ enum finalize_object_file_flags flags)
{
size_t src_len = src->len, dst_len = dst->len;
struct string_list paths = STRING_LIST_INIT_DUP;
@@ -236,11 +247,15 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst)
for (i = 0; i < paths.nr; i++) {
const char *name = paths.items[i].string;
+ enum finalize_object_file_flags flags_copy = flags;
strbuf_addf(src, "/%s", name);
strbuf_addf(dst, "/%s", name);
- ret |= migrate_one(src, dst);
+ if (is_loose_object_shard(name))
+ flags_copy |= FOF_SKIP_COLLISION_CHECK;
+
+ ret |= migrate_one(src, dst, flags_copy);
strbuf_setlen(src, src_len);
strbuf_setlen(dst, dst_len);
@@ -266,9 +281,9 @@ int tmp_objdir_migrate(struct tmp_objdir *t)
}
strbuf_addbuf(&src, &t->path);
- strbuf_addstr(&dst, get_object_directory());
+ strbuf_addstr(&dst, repo_get_object_directory(the_repository));
- ret = migrate_paths(&src, &dst);
+ ret = migrate_paths(&src, &dst, 0);
strbuf_release(&src);
strbuf_release(&dst);
diff --git a/trace.c b/trace.c
index 971a68abe8..d8c43773ae 100644
--- a/trace.c
+++ b/trace.c
@@ -18,12 +18,14 @@
* 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
-#include "environment.h"
+#include "repository.h"
#include "quote.h"
#include "setup.h"
#include "trace.h"
@@ -305,14 +307,14 @@ void trace_repo_setup(void)
cwd = xgetcwd();
- if (!(git_work_tree = get_git_work_tree()))
+ if (!(git_work_tree = repo_get_work_tree(the_repository)))
git_work_tree = "(null)";
if (!startup_info->prefix)
prefix = "(null)";
- trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
- trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
+ trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(repo_get_git_dir(the_repository)));
+ trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(repo_get_common_dir(the_repository)));
trace_printf_key(&trace_setup_key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
trace_printf_key(&trace_setup_key, "setup: cwd: %s\n", quote_crnl(cwd));
trace_printf_key(&trace_setup_key, "setup: prefix: %s\n", quote_crnl(prefix));
diff --git a/trace2.c b/trace2.c
index 6dc74dff4c..f894532d05 100644
--- a/trace2.c
+++ b/trace2.c
@@ -1,12 +1,9 @@
#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"
@@ -20,6 +17,7 @@
#include "trace2/tr2_tmr.h"
static int trace2_enabled;
+static int trace2_redact = 1;
static int tr2_next_child_id; /* modify under lock */
static int tr2_next_exec_id; /* modify under lock */
@@ -227,6 +225,8 @@ void trace2_initialize_fl(const char *file, int line)
if (!tr2_tgt_want_builtins())
return;
trace2_enabled = 1;
+ if (!git_env_bool("GIT_TRACE2_REDACT", 1))
+ trace2_redact = 0;
tr2_sid_get();
@@ -247,12 +247,93 @@ int trace2_is_enabled(void)
return trace2_enabled;
}
+/*
+ * Redacts an argument, i.e. ensures that no password in
+ * https://user:password@host/-style URLs is logged.
+ *
+ * Returns the original if nothing needed to be redacted.
+ * Returns a pointer that needs to be `free()`d otherwise.
+ */
+static const char *redact_arg(const char *arg)
+{
+ const char *p, *colon;
+ size_t at;
+
+ if (!trace2_redact ||
+ (!skip_prefix(arg, "https://", &p) &&
+ !skip_prefix(arg, "http://", &p)))
+ return arg;
+
+ at = strcspn(p, "@/");
+ if (p[at] != '@')
+ return arg;
+
+ colon = memchr(p, ':', at);
+ if (!colon)
+ return arg;
+
+ return xstrfmt("%.*s:<REDACTED>%s", (int)(colon - arg), arg, p + at);
+}
+
+/*
+ * Redacts arguments in an argument list.
+ *
+ * Returns the original if nothing needed to be redacted.
+ * Otherwise, returns a new array that needs to be released
+ * via `free_redacted_argv()`.
+ */
+static const char **redact_argv(const char **argv)
+{
+ int i, j;
+ const char *redacted = NULL;
+ const char **ret;
+
+ if (!trace2_redact)
+ return argv;
+
+ for (i = 0; argv[i]; i++)
+ if ((redacted = redact_arg(argv[i])) != argv[i])
+ break;
+
+ if (!argv[i])
+ return argv;
+
+ for (j = 0; argv[j]; j++)
+ ; /* keep counting */
+
+ ALLOC_ARRAY(ret, j + 1);
+ ret[j] = NULL;
+
+ for (j = 0; j < i; j++)
+ ret[j] = argv[j];
+ ret[i] = redacted;
+ for (++i; argv[i]; i++) {
+ redacted = redact_arg(argv[i]);
+ ret[i] = redacted ? redacted : argv[i];
+ }
+
+ return ret;
+}
+
+static void free_redacted_argv(const char **redacted, const char **argv)
+{
+ int i;
+
+ if (redacted != argv) {
+ for (i = 0; argv[i]; i++)
+ if (redacted[i] != argv[i])
+ free((void *)redacted[i]);
+ free((void *)redacted);
+ }
+}
+
void trace2_cmd_start_fl(const char *file, int line, const char **argv)
{
struct tr2_tgt *tgt_j;
int j;
uint64_t us_now;
uint64_t us_elapsed_absolute;
+ const char **redacted;
if (!trace2_enabled)
return;
@@ -260,10 +341,14 @@ void trace2_cmd_start_fl(const char *file, int line, const char **argv)
us_now = getnanotime() / 1000;
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
+ redacted = redact_argv(argv);
+
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_start_fl)
tgt_j->pfn_start_fl(file, line, us_elapsed_absolute,
- argv);
+ redacted);
+
+ free_redacted_argv(redacted, argv);
}
void trace2_cmd_exit_fl(const char *file, int line, int code)
@@ -348,6 +433,9 @@ void trace2_cmd_name_fl(const char *file, int line, const char *name)
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_command_name_fl)
tgt_j->pfn_command_name_fl(file, line, name, hierarchy);
+
+ trace2_cmd_list_config();
+ trace2_cmd_list_env_vars();
}
void trace2_cmd_mode_fl(const char *file, int line, const char *mode)
@@ -379,17 +467,29 @@ void trace2_cmd_alias_fl(const char *file, int line, const char *alias,
void trace2_cmd_list_config_fl(const char *file, int line)
{
+ static int emitted = 0;
+
if (!trace2_enabled)
return;
+ if (emitted)
+ return;
+ emitted = 1;
+
tr2_cfg_list_config_fl(file, line);
}
void trace2_cmd_list_env_vars_fl(const char *file, int line)
{
+ static int emitted = 0;
+
if (!trace2_enabled)
return;
+ if (emitted)
+ return;
+ emitted = 1;
+
tr2_list_env_vars_fl(file, line);
}
@@ -409,6 +509,7 @@ void trace2_child_start_fl(const char *file, int line,
int j;
uint64_t us_now;
uint64_t us_elapsed_absolute;
+ const char **orig_argv = cmd->args.v;
if (!trace2_enabled)
return;
@@ -419,10 +520,24 @@ void trace2_child_start_fl(const char *file, int line,
cmd->trace2_child_id = tr2tls_locked_increment(&tr2_next_child_id);
cmd->trace2_child_us_start = us_now;
+ /*
+ * The `pfn_child_start_fl` API takes a `struct child_process`
+ * rather than a simple `argv` for the child because some
+ * targets make use of the additional context bits/values. So
+ * temporarily replace the original argv (inside the `strvec`)
+ * with a possibly redacted version.
+ */
+ cmd->args.v = redact_argv(orig_argv);
+
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_child_start_fl)
tgt_j->pfn_child_start_fl(file, line,
us_elapsed_absolute, cmd);
+
+ if (cmd->args.v != orig_argv) {
+ free_redacted_argv(cmd->args.v, orig_argv);
+ cmd->args.v = orig_argv;
+ }
}
void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
@@ -493,6 +608,7 @@ int trace2_exec_fl(const char *file, int line, const char *exe,
int exec_id;
uint64_t us_now;
uint64_t us_elapsed_absolute;
+ const char **redacted;
if (!trace2_enabled)
return -1;
@@ -502,10 +618,14 @@ int trace2_exec_fl(const char *file, int line, const char *exe,
exec_id = tr2tls_locked_increment(&tr2_next_exec_id);
+ redacted = redact_argv(argv);
+
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_exec_fl)
tgt_j->pfn_exec_fl(file, line, us_elapsed_absolute,
- exec_id, exe, argv);
+ exec_id, exe, redacted);
+
+ free_redacted_argv(redacted, argv);
return exec_id;
}
@@ -637,13 +757,19 @@ void trace2_def_param_fl(const char *file, int line, const char *param,
{
struct tr2_tgt *tgt_j;
int j;
+ const char *redacted;
if (!trace2_enabled)
return;
+ redacted = redact_arg(value);
+
for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_param_fl)
- tgt_j->pfn_param_fl(file, line, param, value, kvi);
+ tgt_j->pfn_param_fl(file, line, param, redacted, kvi);
+
+ if (redacted != value)
+ free((void *)redacted);
}
void trace2_def_repo_fl(const char *file, int line, struct repository *repo)
diff --git a/trace2.h b/trace2.h
index 40d8c2e02a..901f39253a 100644
--- a/trace2.h
+++ b/trace2.h
@@ -337,8 +337,8 @@ struct key_value_info;
void trace2_def_param_fl(const char *file, int line, const char *param,
const char *value, const struct key_value_info *kvi);
-#define trace2_def_param(param, value) \
- trace2_def_param_fl(__FILE__, __LINE__, (param), (value))
+#define trace2_def_param(param, value, kvi) \
+ trace2_def_param_fl(__FILE__, __LINE__, (param), (value), (kvi))
/*
* Tell trace2 about a newly instantiated repo object and assign
@@ -390,6 +390,7 @@ void trace2_region_enter_printf_va_fl(const char *file, int line,
trace2_region_enter_printf_va_fl(__FILE__, __LINE__, (category), \
(label), (repo), (fmt), (ap))
+__attribute__((format (printf, 6, 7)))
void trace2_region_enter_printf_fl(const char *file, int line,
const char *category, const char *label,
const struct repository *repo,
@@ -553,6 +554,7 @@ enum trace2_counter_id {
TRACE2_COUNTER_ID_TEST2, /* emits summary and thread events */
TRACE2_COUNTER_ID_PACKED_REFS_JUMPS, /* counts number of jumps */
+ TRACE2_COUNTER_ID_REFTABLE_RESEEKS, /* counts number of re-seeks */
/* counts number of fsyncs */
TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY,
diff --git a/trace2/tr2_cfg.c b/trace2/tr2_cfg.c
index d96d908bb9..22a99a0682 100644
--- a/trace2/tr2_cfg.c
+++ b/trace2/tr2_cfg.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "strbuf.h"
@@ -124,7 +126,7 @@ void tr2_cfg_list_config_fl(const char *file, int line)
struct tr2_cfg_data data = { file, line };
if (tr2_cfg_load_patterns() > 0)
- read_early_config(tr2_cfg_cb, &data);
+ read_early_config(the_repository, tr2_cfg_cb, &data);
}
void tr2_list_env_vars_fl(const char *file, int line)
diff --git a/trace2/tr2_ctr.c b/trace2/tr2_ctr.c
index 87cf9034fb..ee17bfa86b 100644
--- a/trace2/tr2_ctr.c
+++ b/trace2/tr2_ctr.c
@@ -1,11 +1,10 @@
#include "git-compat-util.h"
-#include "thread-utils.h"
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
#include "trace2/tr2_ctr.h"
/*
- * A global counter block to aggregrate values from the partial sums
+ * A global counter block to aggregate values from the partial sums
* from each thread.
*/
static struct tr2_counter_block final_counter_block; /* access under tr2tls_mutex */
@@ -32,6 +31,11 @@ static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTER
.name = "jumps_made",
.want_per_thread_events = 0,
},
+ [TRACE2_COUNTER_ID_REFTABLE_RESEEKS] = {
+ .category = "reftable",
+ .name = "reseeks_made",
+ .want_per_thread_events = 0,
+ },
[TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY] = {
.category = "fsync",
.name = "writeout-only",
diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c
index f26ec95ab4..048cdd5438 100644
--- a/trace2/tr2_sysenv.c
+++ b/trace2/tr2_sysenv.c
@@ -58,7 +58,8 @@ static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
/* clang-format on */
static int tr2_sysenv_cb(const char *key, const char *value,
- const struct config_context *ctx UNUSED, void *d)
+ const struct config_context *ctx UNUSED,
+ void *d UNUSED)
{
int k;
@@ -67,6 +68,8 @@ static int tr2_sysenv_cb(const char *key, const char *value,
for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) {
if (!strcmp(key, tr2_sysenv_settings[k].git_config_name)) {
+ if (!value)
+ return config_error_nonbool(key);
free(tr2_sysenv_settings[k].value);
tr2_sysenv_settings[k].value = xstrdup(value);
return 0;
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 53091781ec..45b0850a5e 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -24,7 +24,7 @@ static struct tr2_dst tr2dst_event = {
* a new field to an existing event, do not require an increment to the EVENT
* format version.
*/
-#define TR2_EVENT_VERSION "3"
+#define TR2_EVENT_VERSION "4"
/*
* Region nesting limit for messages written to the event target.
@@ -335,7 +335,7 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
}
static void fn_child_start_fl(const char *file, int line,
- uint64_t us_elapsed_absolute,
+ uint64_t us_elapsed_absolute UNUSED,
const struct child_process *cmd)
{
const char *event_name = "child_start";
@@ -367,7 +367,8 @@ static void fn_child_start_fl(const char *file, int line,
}
static void fn_child_exit_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, int cid, int pid,
+ uint64_t us_elapsed_absolute UNUSED,
+ int cid, int pid,
int code, uint64_t us_elapsed_child)
{
const char *event_name = "child_exit";
@@ -388,7 +389,8 @@ static void fn_child_exit_fl(const char *file, int line,
}
static void fn_child_ready_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, int cid, int pid,
+ uint64_t us_elapsed_absolute UNUSED,
+ int cid, int pid,
const char *ready, uint64_t us_elapsed_child)
{
const char *event_name = "child_ready";
@@ -409,7 +411,7 @@ static void fn_child_ready_fl(const char *file, int line,
}
static void fn_thread_start_fl(const char *file, int line,
- uint64_t us_elapsed_absolute)
+ uint64_t us_elapsed_absolute UNUSED)
{
const char *event_name = "thread_start";
struct json_writer jw = JSON_WRITER_INIT;
@@ -423,7 +425,7 @@ static void fn_thread_start_fl(const char *file, int line,
}
static void fn_thread_exit_fl(const char *file, int line,
- uint64_t us_elapsed_absolute,
+ uint64_t us_elapsed_absolute UNUSED,
uint64_t us_elapsed_thread)
{
const char *event_name = "thread_exit";
@@ -439,7 +441,8 @@ static void fn_thread_exit_fl(const char *file, int line,
jw_release(&jw);
}
-static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
+static void fn_exec_fl(const char *file, int line,
+ uint64_t us_elapsed_absolute UNUSED,
int exec_id, const char *exe, const char **argv)
{
const char *event_name = "exec";
@@ -460,8 +463,8 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
}
static void fn_exec_result_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, int exec_id,
- int code)
+ uint64_t us_elapsed_absolute UNUSED,
+ int exec_id, int code)
{
const char *event_name = "exec_result";
struct json_writer jw = JSON_WRITER_INIT;
@@ -511,7 +514,7 @@ static void fn_repo_fl(const char *file, int line,
}
static void fn_region_enter_printf_va_fl(const char *file, int line,
- uint64_t us_elapsed_absolute,
+ uint64_t us_elapsed_absolute UNUSED,
const char *category,
const char *label,
const struct repository *repo,
@@ -538,7 +541,7 @@ static void fn_region_enter_printf_va_fl(const char *file, int line,
}
static void fn_region_leave_printf_va_fl(
- const char *file, int line, uint64_t us_elapsed_absolute,
+ const char *file, int line, uint64_t us_elapsed_absolute UNUSED,
uint64_t us_elapsed_region, const char *category, const char *label,
const struct repository *repo, const char *fmt, va_list ap)
{
@@ -619,6 +622,24 @@ static void fn_data_json_fl(const char *file, int line,
}
}
+static void fn_printf_va_fl(const char *file, int line,
+ uint64_t us_elapsed_absolute,
+ const char *fmt, va_list ap)
+{
+ const char *event_name = "printf";
+ struct json_writer jw = JSON_WRITER_INIT;
+ double t_abs = (double)us_elapsed_absolute / 1000000.0;
+
+ jw_object_begin(&jw, 0);
+ event_fmt_prepare(event_name, file, line, NULL, &jw);
+ jw_object_double(&jw, "t_abs", 6, t_abs);
+ maybe_add_string_va(&jw, "msg", fmt, ap);
+ jw_end(&jw);
+
+ tr2_dst_write_line(&tr2dst_event, &jw.json);
+ jw_release(&jw);
+}
+
static void fn_timer(const struct tr2_timer_metadata *meta,
const struct tr2_timer *timer,
int is_final_data)
@@ -691,7 +712,7 @@ struct tr2_tgt tr2_tgt_event = {
.pfn_region_leave_printf_va_fl = fn_region_leave_printf_va_fl,
.pfn_data_fl = fn_data_fl,
.pfn_data_json_fl = fn_data_json_fl,
- .pfn_printf_va_fl = NULL,
+ .pfn_printf_va_fl = fn_printf_va_fl,
.pfn_timer = fn_timer,
.pfn_counter = fn_counter,
};
diff --git a/trace2/tr2_tgt_normal.c b/trace2/tr2_tgt_normal.c
index d25ea13164..baef48aa69 100644
--- a/trace2/tr2_tgt_normal.c
+++ b/trace2/tr2_tgt_normal.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "run-command.h"
+#include "strbuf.h"
#include "quote.h"
#include "version.h"
#include "trace2/tr2_dst.h"
@@ -86,7 +87,7 @@ static void fn_version_fl(const char *file, int line)
}
static void fn_start_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, const char **argv)
+ uint64_t us_elapsed_absolute UNUSED, const char **argv)
{
struct strbuf buf_payload = STRBUF_INIT;
@@ -215,7 +216,7 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
}
static void fn_child_start_fl(const char *file, int line,
- uint64_t us_elapsed_absolute,
+ uint64_t us_elapsed_absolute UNUSED,
const struct child_process *cmd)
{
struct strbuf buf_payload = STRBUF_INIT;
@@ -243,7 +244,8 @@ static void fn_child_start_fl(const char *file, int line,
}
static void fn_child_exit_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, int cid, int pid,
+ uint64_t us_elapsed_absolute UNUSED,
+ int cid, int pid,
int code, uint64_t us_elapsed_child)
{
struct strbuf buf_payload = STRBUF_INIT;
@@ -256,7 +258,8 @@ static void fn_child_exit_fl(const char *file, int line,
}
static void fn_child_ready_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, int cid, int pid,
+ uint64_t us_elapsed_absolute UNUSED,
+ int cid, int pid,
const char *ready, uint64_t us_elapsed_child)
{
struct strbuf buf_payload = STRBUF_INIT;
@@ -268,7 +271,8 @@ static void fn_child_ready_fl(const char *file, int line,
strbuf_release(&buf_payload);
}
-static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
+static void fn_exec_fl(const char *file, int line,
+ uint64_t us_elapsed_absolute UNUSED,
int exec_id, const char *exe, const char **argv)
{
struct strbuf buf_payload = STRBUF_INIT;
@@ -284,8 +288,8 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
}
static void fn_exec_result_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, int exec_id,
- int code)
+ uint64_t us_elapsed_absolute UNUSED,
+ int exec_id, int code)
{
struct strbuf buf_payload = STRBUF_INIT;
@@ -321,7 +325,8 @@ static void fn_repo_fl(const char *file, int line,
}
static void fn_printf_va_fl(const char *file, int line,
- uint64_t us_elapsed_absolute, const char *fmt,
+ uint64_t us_elapsed_absolute UNUSED,
+ const char *fmt,
va_list ap)
{
struct strbuf buf_payload = STRBUF_INIT;
diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c
index 601c9e5036..7b023c1bfc 100644
--- a/trace2/tr2_tls.c
+++ b/trace2/tr2_tls.c
@@ -1,4 +1,5 @@
#include "git-compat-util.h"
+#include "strbuf.h"
#include "thread-utils.h"
#include "trace.h"
#include "trace2/tr2_tls.h"
@@ -151,11 +152,19 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
return us - tr2tls_us_start_process;
}
+static void tr2tls_key_destructor(void *payload)
+{
+ struct tr2tls_thread_ctx *ctx = payload;
+ free((char *)ctx->thread_name);
+ free(ctx->array_us_start);
+ free(ctx);
+}
+
void tr2tls_init(void)
{
tr2tls_start_process_clock();
- pthread_key_create(&tr2tls_key, NULL);
+ pthread_key_create(&tr2tls_key, tr2tls_key_destructor);
init_recursive_mutex(&tr2tls_mutex);
tr2tls_thread_main =
diff --git a/trace2/tr2_tls.h b/trace2/tr2_tls.h
index f9049805d4..3bdbf4d275 100644
--- a/trace2/tr2_tls.h
+++ b/trace2/tr2_tls.h
@@ -1,7 +1,6 @@
#ifndef TR2_TLS_H
#define TR2_TLS_H
-#include "strbuf.h"
#include "trace2/tr2_ctr.h"
#include "trace2/tr2_tmr.h"
@@ -12,7 +11,7 @@
*/
/*
- * Arbitry limit for thread names for column alignment.
+ * Arbitrary limit for thread names for column alignment.
*/
#define TR2_MAX_THREAD_NAME (24)
diff --git a/trace2/tr2_tmr.c b/trace2/tr2_tmr.c
index 31d0e4d1bd..51f564b07a 100644
--- a/trace2/tr2_tmr.c
+++ b/trace2/tr2_tmr.c
@@ -1,5 +1,4 @@
#include "git-compat-util.h"
-#include "thread-utils.h"
#include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h"
diff --git a/trailer.c b/trailer.c
index f408f9b058..46f0e4610b 100644
--- a/trailer.c
+++ b/trailer.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -5,13 +7,34 @@
#include "string-list.h"
#include "run-command.h"
#include "commit.h"
-#include "tempfile.h"
#include "trailer.h"
#include "list.h"
/*
* Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
*/
+struct trailer_block {
+ /*
+ * True if there is a blank line before the location pointed to by
+ * "start".
+ */
+ int blank_line_before_trailer;
+
+ /*
+ * The locations of the start and end positions of the trailer block
+ * found, as offsets from the beginning of the source text from which
+ * this trailer block was parsed. If no trailer block is found, these
+ * are both set to 0.
+ */
+ size_t start, end;
+
+ /*
+ * Array of trailers found.
+ */
+ char **trailers;
+ size_t trailer_nr;
+};
+
struct conf_info {
char *name;
char *key;
@@ -43,7 +66,7 @@ struct arg_item {
static LIST_HEAD(conf_head);
-static char *separators = ":";
+static const char *separators = ":";
static int configured;
@@ -145,37 +168,6 @@ static char last_non_space_char(const char *s)
return '\0';
}
-static void print_tok_val(FILE *outfile, const char *tok, const char *val)
-{
- char c;
-
- if (!tok) {
- fprintf(outfile, "%s\n", val);
- return;
- }
-
- c = last_non_space_char(tok);
- if (!c)
- return;
- if (strchr(separators, c))
- fprintf(outfile, "%s%s\n", tok, val);
- else
- fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
-}
-
-static void print_all(FILE *outfile, struct list_head *head,
- const struct process_trailer_options *opts)
-{
- struct list_head *pos;
- struct trailer_item *item;
- list_for_each(pos, head) {
- item = list_entry(pos, struct trailer_item, list);
- if ((!opts->trim_empty || strlen(item->value) > 0) &&
- (!opts->only_trailers || item->token))
- print_tok_val(outfile, item->token, item->value);
- }
-}
-
static struct trailer_item *trailer_from_arg(struct arg_item *arg_tok)
{
struct trailer_item *new_item = xcalloc(1, sizeof(*new_item));
@@ -258,7 +250,9 @@ static char *apply_command(struct conf_info *conf, const char *arg)
static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
{
if (arg_tok->conf.command || arg_tok->conf.cmd) {
- const char *arg;
+ char *value_to_free = NULL;
+ char *arg;
+
if (arg_tok->value && arg_tok->value[0]) {
arg = arg_tok->value;
} else {
@@ -266,9 +260,13 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
arg = xstrdup(in_tok->value);
else
arg = xstrdup("");
+ value_to_free = arg_tok->value;
}
+
arg_tok->value = apply_command(&arg_tok->conf, arg);
- free((char *)arg);
+
+ free(value_to_free);
+ free(arg);
}
}
@@ -366,8 +364,8 @@ static int find_same_and_apply_arg(struct list_head *head,
return 0;
}
-static void process_trailers_lists(struct list_head *head,
- struct list_head *arg_head)
+void process_trailers_lists(struct list_head *head,
+ struct list_head *arg_head)
{
struct list_head *pos, *p;
struct arg_item *arg_tok;
@@ -507,6 +505,8 @@ static int git_trailer_default_config(const char *conf_key, const char *value,
warning(_("unknown value '%s' for key '%s'"),
value, conf_key);
} else if (!strcmp(trailer_item, "separators")) {
+ if (!value)
+ return config_error_nonbool(conf_key);
separators = xstrdup(value);
}
}
@@ -551,16 +551,22 @@ static int git_trailer_config(const char *conf_key, const char *value,
case TRAILER_KEY:
if (conf->key)
warning(_("more than one %s"), conf_key);
+ if (!value)
+ return config_error_nonbool(conf_key);
conf->key = xstrdup(value);
break;
case TRAILER_COMMAND:
if (conf->command)
warning(_("more than one %s"), conf_key);
+ if (!value)
+ return config_error_nonbool(conf_key);
conf->command = xstrdup(value);
break;
case TRAILER_CMD:
if (conf->cmd)
warning(_("more than one %s"), conf_key);
+ if (!value)
+ return config_error_nonbool(conf_key);
conf->cmd = xstrdup(value);
break;
case TRAILER_WHERE:
@@ -581,7 +587,7 @@ static int git_trailer_config(const char *conf_key, const char *value,
return 0;
}
-static void ensure_configured(void)
+void trailer_config_init(void)
{
if (configured)
return;
@@ -711,30 +717,35 @@ static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
list_add_tail(&new_item->list, arg_head);
}
-static void process_command_line_args(struct list_head *arg_head,
- struct list_head *new_trailer_head)
+void parse_trailers_from_config(struct list_head *config_head)
{
struct arg_item *item;
- struct strbuf tok = STRBUF_INIT;
- struct strbuf val = STRBUF_INIT;
- const struct conf_info *conf;
struct list_head *pos;
- /*
- * In command-line arguments, '=' is accepted (in addition to the
- * separators that are defined).
- */
- char *cl_separators = xstrfmt("=%s", separators);
-
/* Add an arg item for each configured trailer with a command */
list_for_each(pos, &conf_head) {
item = list_entry(pos, struct arg_item, list);
if (item->conf.command)
- add_arg_item(arg_head,
+ add_arg_item(config_head,
xstrdup(token_from_item(item, NULL)),
xstrdup(""),
&item->conf, NULL);
}
+}
+
+void parse_trailers_from_command_line_args(struct list_head *arg_head,
+ struct list_head *new_trailer_head)
+{
+ struct strbuf tok = STRBUF_INIT;
+ struct strbuf val = STRBUF_INIT;
+ const struct conf_info *conf;
+ struct list_head *pos;
+
+ /*
+ * In command-line arguments, '=' is accepted (in addition to the
+ * separators that are defined).
+ */
+ char *cl_separators = xstrfmt("=%s", separators);
/* Add an arg item for each trailer on the command line */
list_for_each(pos, new_trailer_head) {
@@ -762,17 +773,6 @@ static void process_command_line_args(struct list_head *arg_head,
free(cl_separators);
}
-static void read_input_file(struct strbuf *sb, const char *file)
-{
- if (file) {
- if (strbuf_read_file(sb, file, 0) < 0)
- die_errno(_("could not read input file '%s'"), file);
- } else {
- if (strbuf_read(sb, fileno(stdin), 0) < 0)
- die_errno(_("could not read from stdin"));
- }
-}
-
static const char *next_line(const char *str)
{
const char *nl = strchrnul(str, '\n');
@@ -804,28 +804,55 @@ static ssize_t last_line(const char *buf, size_t len)
}
/*
- * Return the position of the start of the patch or the length of str if there
- * is no patch in the message.
+ * Find the end of the log message as an offset from the start of the input
+ * (where callers of this function are interested in looking for a trailers
+ * block in the same input). We have to consider two categories of content that
+ * can come at the end of the input which we want to ignore (because they don't
+ * belong in the log message):
+ *
+ * (1) the "patch part" which begins with a "---" divider and has patch
+ * information (like the output of git-format-patch), and
+ *
+ * (2) any trailing comment lines, blank lines like in the output of "git
+ * commit -v", or stuff below the "cut" (scissor) line.
+ *
+ * As a formula, the situation looks like this:
+ *
+ * INPUT = LOG MESSAGE + IGNORED
+ *
+ * where IGNORED can be either of the two categories described above. It may be
+ * that there is nothing to ignore. Now it may be the case that the LOG MESSAGE
+ * contains a trailer block, but that's not the concern of this function.
*/
-static size_t find_patch_start(const char *str)
+static size_t find_end_of_log_message(const char *input, int no_divider)
{
+ size_t end;
const char *s;
- for (s = str; *s; s = next_line(s)) {
- const char *v;
+ /* Assume the naive end of the input is already what we want. */
+ end = strlen(input);
+
+ /* Optionally skip over any patch part ("---" line and below). */
+ if (!no_divider) {
+ for (s = input; *s; s = next_line(s)) {
+ const char *v;
- if (skip_prefix(s, "---", &v) && isspace(*v))
- return s - str;
+ if (skip_prefix(s, "---", &v) && isspace(*v)) {
+ end = s - input;
+ break;
+ }
+ }
}
- return s - str;
+ /* Skip over other ignorable bits. */
+ return end - ignored_log_message_bytes(input, end);
}
/*
* Return the position of the first trailer line or len if there are no
* trailers.
*/
-static size_t find_trailer_start(const char *buf, size_t len)
+static size_t find_trailer_block_start(const char *buf, size_t len)
{
const char *s;
ssize_t end_of_title, l;
@@ -842,7 +869,7 @@ static size_t find_trailer_start(const char *buf, size_t len)
/* The first paragraph is the title and cannot be trailers */
for (s = buf; s < buf + len; s = next_line(s)) {
- if (s[0] == comment_line_char)
+ if (starts_with_mem(s, buf + len - s, comment_line_str))
continue;
if (is_blank_line(s))
break;
@@ -862,7 +889,7 @@ static size_t find_trailer_start(const char *buf, size_t len)
const char **p;
ssize_t separator_pos;
- if (bol[0] == comment_line_char) {
+ if (starts_with_mem(bol, buf + len - bol, comment_line_str)) {
non_trailer_lines += possible_continuation_lines;
possible_continuation_lines = 0;
continue;
@@ -920,12 +947,6 @@ continue_outer_loop:
return len;
}
-/* Return the position of the end of the trailers. */
-static size_t find_trailer_end(const char *buf, size_t len)
-{
- return len - ignore_non_trailer(buf, len);
-}
-
static int ends_with_blank_line(const char *buf, size_t len)
{
ssize_t ll = last_line(buf, len);
@@ -961,29 +982,77 @@ static void unfold_value(struct strbuf *val)
strbuf_release(&out);
}
-static size_t process_input_file(FILE *outfile,
- const char *str,
- struct list_head *head,
- const struct process_trailer_options *opts)
+static struct trailer_block *trailer_block_new(void)
+{
+ struct trailer_block *trailer_block = xcalloc(1, sizeof(*trailer_block));
+ return trailer_block;
+}
+
+static struct trailer_block *trailer_block_get(const struct process_trailer_options *opts,
+ const char *str)
+{
+ struct trailer_block *trailer_block = trailer_block_new();
+ size_t end_of_log_message = 0, trailer_block_start = 0;
+ struct strbuf **trailer_lines, **ptr;
+ char **trailer_strings = NULL;
+ size_t nr = 0, alloc = 0;
+ char **last = NULL;
+
+ trailer_config_init();
+
+ end_of_log_message = find_end_of_log_message(str, opts->no_divider);
+ trailer_block_start = find_trailer_block_start(str, end_of_log_message);
+
+ trailer_lines = strbuf_split_buf(str + trailer_block_start,
+ end_of_log_message - trailer_block_start,
+ '\n',
+ 0);
+ for (ptr = trailer_lines; *ptr; ptr++) {
+ if (last && isspace((*ptr)->buf[0])) {
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_attach(&sb, *last, strlen(*last), strlen(*last));
+ strbuf_addbuf(&sb, *ptr);
+ *last = strbuf_detach(&sb, NULL);
+ continue;
+ }
+ ALLOC_GROW(trailer_strings, nr + 1, alloc);
+ trailer_strings[nr] = strbuf_detach(*ptr, NULL);
+ last = find_separator(trailer_strings[nr], separators) >= 1
+ ? &trailer_strings[nr]
+ : NULL;
+ nr++;
+ }
+ strbuf_list_free(trailer_lines);
+
+ trailer_block->blank_line_before_trailer = ends_with_blank_line(str,
+ trailer_block_start);
+ trailer_block->start = trailer_block_start;
+ trailer_block->end = end_of_log_message;
+ trailer_block->trailers = trailer_strings;
+ trailer_block->trailer_nr = nr;
+
+ return trailer_block;
+}
+
+/*
+ * Parse trailers in "str", populating the trailer_block and "trailer_objects"
+ * linked list structure.
+ */
+struct trailer_block *parse_trailers(const struct process_trailer_options *opts,
+ const char *str,
+ struct list_head *trailer_objects)
{
- struct trailer_info info;
+ struct trailer_block *trailer_block;
struct strbuf tok = STRBUF_INIT;
struct strbuf val = STRBUF_INIT;
size_t i;
- trailer_info_get(&info, str, opts);
-
- /* Print lines before the trailers as is */
- if (!opts->only_trailers)
- fwrite(str, 1, info.trailer_start - str, outfile);
+ trailer_block = trailer_block_get(opts, str);
- if (!opts->only_trailers && !info.blank_line_before_trailer)
- fprintf(outfile, "\n");
-
- for (i = 0; i < info.trailer_nr; i++) {
+ for (i = 0; i < trailer_block->trailer_nr; i++) {
int separator_pos;
- char *trailer = info.trailers[i];
- if (trailer[0] == comment_line_char)
+ char *trailer = trailer_block->trailers[i];
+ if (starts_with(trailer, comment_line_str))
continue;
separator_pos = find_separator(trailer, separators);
if (separator_pos >= 1) {
@@ -991,188 +1060,82 @@ static size_t process_input_file(FILE *outfile,
separator_pos);
if (opts->unfold)
unfold_value(&val);
- add_trailer_item(head,
+ add_trailer_item(trailer_objects,
strbuf_detach(&tok, NULL),
strbuf_detach(&val, NULL));
} else if (!opts->only_trailers) {
strbuf_addstr(&val, trailer);
strbuf_strip_suffix(&val, "\n");
- add_trailer_item(head,
+ add_trailer_item(trailer_objects,
NULL,
strbuf_detach(&val, NULL));
}
}
- trailer_info_release(&info);
-
- return info.trailer_end - str;
+ return trailer_block;
}
-static void free_all(struct list_head *head)
+void free_trailers(struct list_head *trailers)
{
struct list_head *pos, *p;
- list_for_each_safe(pos, p, head) {
+ list_for_each_safe(pos, p, trailers) {
list_del(pos);
free_trailer_item(list_entry(pos, struct trailer_item, list));
}
}
-static struct tempfile *trailers_tempfile;
-
-static FILE *create_in_place_tempfile(const char *file)
+size_t trailer_block_start(struct trailer_block *trailer_block)
{
- struct stat st;
- struct strbuf filename_template = STRBUF_INIT;
- const char *tail;
- FILE *outfile;
-
- if (stat(file, &st))
- die_errno(_("could not stat %s"), file);
- if (!S_ISREG(st.st_mode))
- die(_("file %s is not a regular file"), file);
- if (!(st.st_mode & S_IWUSR))
- die(_("file %s is not writable by user"), file);
-
- /* Create temporary file in the same directory as the original */
- tail = strrchr(file, '/');
- if (tail)
- strbuf_add(&filename_template, file, tail - file + 1);
- strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
-
- trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
- strbuf_release(&filename_template);
- outfile = fdopen_tempfile(trailers_tempfile, "w");
- if (!outfile)
- die_errno(_("could not open temporary file"));
-
- return outfile;
+ return trailer_block->start;
}
-void process_trailers(const char *file,
- const struct process_trailer_options *opts,
- struct list_head *new_trailer_head)
+size_t trailer_block_end(struct trailer_block *trailer_block)
{
- LIST_HEAD(head);
- struct strbuf sb = STRBUF_INIT;
- size_t trailer_end;
- FILE *outfile = stdout;
-
- ensure_configured();
-
- read_input_file(&sb, file);
-
- if (opts->in_place)
- outfile = create_in_place_tempfile(file);
-
- /* Print the lines before the trailers */
- trailer_end = process_input_file(outfile, sb.buf, &head, opts);
-
- if (!opts->only_input) {
- LIST_HEAD(arg_head);
- process_command_line_args(&arg_head, new_trailer_head);
- process_trailers_lists(&head, &arg_head);
- }
-
- print_all(outfile, &head, opts);
-
- free_all(&head);
-
- /* Print the lines after the trailers as is */
- if (!opts->only_trailers)
- fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile);
-
- if (opts->in_place)
- if (rename_tempfile(&trailers_tempfile, file))
- die_errno(_("could not rename temporary file to %s"), file);
-
- strbuf_release(&sb);
+ return trailer_block->end;
}
-void trailer_info_get(struct trailer_info *info, const char *str,
- const struct process_trailer_options *opts)
+int blank_line_before_trailer_block(struct trailer_block *trailer_block)
{
- int patch_start, trailer_end, trailer_start;
- struct strbuf **trailer_lines, **ptr;
- char **trailer_strings = NULL;
- size_t nr = 0, alloc = 0;
- char **last = NULL;
-
- ensure_configured();
-
- if (opts->no_divider)
- patch_start = strlen(str);
- else
- patch_start = find_patch_start(str);
-
- trailer_end = find_trailer_end(str, patch_start);
- trailer_start = find_trailer_start(str, trailer_end);
-
- trailer_lines = strbuf_split_buf(str + trailer_start,
- trailer_end - trailer_start,
- '\n',
- 0);
- for (ptr = trailer_lines; *ptr; ptr++) {
- if (last && isspace((*ptr)->buf[0])) {
- struct strbuf sb = STRBUF_INIT;
- strbuf_attach(&sb, *last, strlen(*last), strlen(*last));
- strbuf_addbuf(&sb, *ptr);
- *last = strbuf_detach(&sb, NULL);
- continue;
- }
- ALLOC_GROW(trailer_strings, nr + 1, alloc);
- trailer_strings[nr] = strbuf_detach(*ptr, NULL);
- last = find_separator(trailer_strings[nr], separators) >= 1
- ? &trailer_strings[nr]
- : NULL;
- nr++;
- }
- strbuf_list_free(trailer_lines);
-
- info->blank_line_before_trailer = ends_with_blank_line(str,
- trailer_start);
- info->trailer_start = str + trailer_start;
- info->trailer_end = str + trailer_end;
- info->trailers = trailer_strings;
- info->trailer_nr = nr;
+ return trailer_block->blank_line_before_trailer;
}
-void trailer_info_release(struct trailer_info *info)
+void trailer_block_release(struct trailer_block *trailer_block)
{
size_t i;
- for (i = 0; i < info->trailer_nr; i++)
- free(info->trailers[i]);
- free(info->trailers);
+ for (i = 0; i < trailer_block->trailer_nr; i++)
+ free(trailer_block->trailers[i]);
+ free(trailer_block->trailers);
+ free(trailer_block);
}
-static void format_trailer_info(struct strbuf *out,
- const struct trailer_info *info,
- const struct process_trailer_options *opts)
+void format_trailers(const struct process_trailer_options *opts,
+ struct list_head *trailers,
+ struct strbuf *out)
{
+ struct strbuf tok = STRBUF_INIT;
+ struct strbuf val = STRBUF_INIT;
size_t origlen = out->len;
- size_t i;
-
- /* If we want the whole block untouched, we can take the fast path. */
- if (!opts->only_trailers && !opts->unfold && !opts->filter &&
- !opts->separator && !opts->key_only && !opts->value_only &&
- !opts->key_value_separator) {
- strbuf_add(out, info->trailer_start,
- info->trailer_end - info->trailer_start);
- return;
- }
-
- for (i = 0; i < info->trailer_nr; i++) {
- char *trailer = info->trailers[i];
- ssize_t separator_pos = find_separator(trailer, separators);
+ struct list_head *pos;
+ struct trailer_item *item;
- if (separator_pos >= 1) {
- struct strbuf tok = STRBUF_INIT;
- struct strbuf val = STRBUF_INIT;
+ list_for_each(pos, trailers) {
+ item = list_entry(pos, struct trailer_item, list);
+ if (item->token) {
+ strbuf_reset(&tok);
+ strbuf_addstr(&tok, item->token);
+ strbuf_reset(&val);
+ strbuf_addstr(&val, item->value);
+
+ /*
+ * Skip key/value pairs where the value was empty. This
+ * can happen from trailers specified without a
+ * separator, like `--trailer "Reviewed-by"` (no
+ * corresponding value).
+ */
+ if (opts->trim_empty && !strlen(item->value))
+ continue;
- parse_trailer(&tok, &val, NULL, trailer, separator_pos);
if (!opts->filter || opts->filter(&tok, opts->filter_data)) {
- if (opts->unfold)
- unfold_value(&val);
-
if (opts->separator && out->len != origlen)
strbuf_addbuf(out, opts->separator);
if (!opts->value_only)
@@ -1180,38 +1143,51 @@ static void format_trailer_info(struct strbuf *out,
if (!opts->key_only && !opts->value_only) {
if (opts->key_value_separator)
strbuf_addbuf(out, opts->key_value_separator);
- else
- strbuf_addstr(out, ": ");
+ else {
+ char c = last_non_space_char(tok.buf);
+ if (c && !strchr(separators, c))
+ strbuf_addf(out, "%c ", separators[0]);
+ }
}
if (!opts->key_only)
strbuf_addbuf(out, &val);
if (!opts->separator)
strbuf_addch(out, '\n');
}
- strbuf_release(&tok);
- strbuf_release(&val);
-
} else if (!opts->only_trailers) {
if (opts->separator && out->len != origlen) {
strbuf_addbuf(out, opts->separator);
}
- strbuf_addstr(out, trailer);
- if (opts->separator) {
+ strbuf_addstr(out, item->value);
+ if (opts->separator)
strbuf_rtrim(out);
- }
+ else
+ strbuf_addch(out, '\n');
}
}
+ strbuf_release(&tok);
+ strbuf_release(&val);
}
-void format_trailers_from_commit(struct strbuf *out, const char *msg,
- const struct process_trailer_options *opts)
+void format_trailers_from_commit(const struct process_trailer_options *opts,
+ const char *msg,
+ struct strbuf *out)
{
- struct trailer_info info;
+ LIST_HEAD(trailer_objects);
+ struct trailer_block *trailer_block = parse_trailers(opts, msg, &trailer_objects);
- trailer_info_get(&info, msg, opts);
- format_trailer_info(out, &info, opts);
- trailer_info_release(&info);
+ /* If we want the whole block untouched, we can take the fast path. */
+ if (!opts->only_trailers && !opts->unfold && !opts->filter &&
+ !opts->separator && !opts->key_only && !opts->value_only &&
+ !opts->key_value_separator) {
+ strbuf_add(out, msg + trailer_block->start,
+ trailer_block->end - trailer_block->start);
+ } else
+ format_trailers(opts, &trailer_objects, out);
+
+ free_trailers(&trailer_objects);
+ trailer_block_release(trailer_block);
}
void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
@@ -1220,23 +1196,22 @@ void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
strbuf_init(&iter->key, 0);
strbuf_init(&iter->val, 0);
opts.no_divider = 1;
- trailer_info_get(&iter->info, msg, &opts);
- iter->cur = 0;
+ iter->internal.trailer_block = trailer_block_get(&opts, msg);
+ iter->internal.cur = 0;
}
int trailer_iterator_advance(struct trailer_iterator *iter)
{
- while (iter->cur < iter->info.trailer_nr) {
- char *trailer = iter->info.trailers[iter->cur++];
- int separator_pos = find_separator(trailer, separators);
-
- if (separator_pos < 1)
- continue; /* not a real trailer */
+ if (iter->internal.cur < iter->internal.trailer_block->trailer_nr) {
+ char *line = iter->internal.trailer_block->trailers[iter->internal.cur++];
+ int separator_pos = find_separator(line, separators);
+ iter->raw = line;
strbuf_reset(&iter->key);
strbuf_reset(&iter->val);
parse_trailer(&iter->key, &iter->val, NULL,
- trailer, separator_pos);
+ line, separator_pos);
+ /* Always unfold values during iteration. */
unfold_value(&iter->val);
return 1;
}
@@ -1245,7 +1220,19 @@ int trailer_iterator_advance(struct trailer_iterator *iter)
void trailer_iterator_release(struct trailer_iterator *iter)
{
- trailer_info_release(&iter->info);
+ trailer_block_release(iter->internal.trailer_block);
strbuf_release(&iter->val);
strbuf_release(&iter->key);
}
+
+int amend_file_with_trailers(const char *path, const struct strvec *trailer_args)
+{
+ struct child_process run_trailer = CHILD_PROCESS_INIT;
+
+ run_trailer.git_cmd = 1;
+ strvec_pushl(&run_trailer.args, "interpret-trailers",
+ "--in-place", "--no-divider",
+ path, NULL);
+ strvec_pushv(&run_trailer.args, trailer_args->v);
+ return run_command(&run_trailer);
+}
diff --git a/trailer.h b/trailer.h
index 795d2fccfd..4740549586 100644
--- a/trailer.h
+++ b/trailer.h
@@ -4,6 +4,9 @@
#include "list.h"
#include "strbuf.h"
+struct trailer_block;
+struct strvec;
+
enum trailer_where {
WHERE_DEFAULT,
WHERE_END,
@@ -29,27 +32,6 @@ int trailer_set_where(enum trailer_where *item, const char *value);
int trailer_set_if_exists(enum trailer_if_exists *item, const char *value);
int trailer_set_if_missing(enum trailer_if_missing *item, const char *value);
-struct trailer_info {
- /*
- * True if there is a blank line before the location pointed to by
- * trailer_start.
- */
- int blank_line_before_trailer;
-
- /*
- * Pointers to the start and end of the trailer block found. If there
- * is no trailer block found, these 2 pointers point to the end of the
- * input string.
- */
- const char *trailer_start, *trailer_end;
-
- /*
- * Array of trailers found.
- */
- char **trailers;
- size_t trailer_nr;
-};
-
/*
* A list that represents newly-added trailers, such as those provided
* with the --trailer command line option of git-interpret-trailers.
@@ -81,28 +63,86 @@ struct process_trailer_options {
#define PROCESS_TRAILER_OPTIONS_INIT {0}
-void process_trailers(const char *file,
- const struct process_trailer_options *opts,
- struct list_head *new_trailer_head);
+void parse_trailers_from_config(struct list_head *config_head);
-void trailer_info_get(struct trailer_info *info, const char *str,
- const struct process_trailer_options *opts);
+void parse_trailers_from_command_line_args(struct list_head *arg_head,
+ struct list_head *new_trailer_head);
-void trailer_info_release(struct trailer_info *info);
+void process_trailers_lists(struct list_head *head,
+ struct list_head *arg_head);
/*
- * Format the trailers from the commit msg "msg" into the strbuf "out".
- * Note two caveats about "opts":
+ * Given some input string "str", return a pointer to an opaque trailer_block
+ * structure. Also populate the trailer_objects list with parsed trailer
+ * objects. Internally this calls trailer_info_get() to get the opaque pointer,
+ * but does some extra work to populate the trailer_objects linked list.
+ *
+ * The opaque trailer_block pointer can be used to check the position of the
+ * trailer block as offsets relative to the beginning of "str" in
+ * trailer_block_start() and trailer_block_end().
+ * blank_line_before_trailer_block() returns 1 if there is a blank line just
+ * before the trailer block. All of these functions are useful for preserving
+ * the input before and after the trailer block, if we were to write out the
+ * original input (but with the trailer block itself modified); see
+ * builtin/interpret-trailers.c for an example.
+ *
+ * For iterating through the parsed trailer block (if you don't care about the
+ * position of the trailer block itself in the context of the larger string text
+ * from which it was parsed), please see trailer_iterator_init() which uses the
+ * trailer_block struct internally.
*
- * - this is primarily a helper for pretty.c, and not
- * all of the flags are supported.
+ * Lastly, callers should call trailer_info_release() when they are done using
+ * the opaque pointer.
*
- * - this differs from process_trailers slightly in that we always format
- * only the trailer block itself, even if the "only_trailers" option is not
- * set.
+ * NOTE: Callers should treat both trailer_block and trailer_objects as
+ * read-only items, because there is some overlap between the two (trailer_block
+ * has "char **trailers" string array, and trailer_objects will have the same
+ * data but as a linked list of trailer_item objects). This API does not perform
+ * any synchronization between the two. In the future we should be able to
+ * reduce the duplication and use just the linked list.
+ */
+struct trailer_block *parse_trailers(const struct process_trailer_options *,
+ const char *str,
+ struct list_head *trailer_objects);
+
+/*
+ * Return the offset of the start of the trailer block. That is, 0 is the start
+ * of the input ("str" in parse_trailers()) and some other positive number
+ * indicates how many bytes we have to skip over before we get to the beginning
+ * of the trailer block.
+ */
+size_t trailer_block_start(struct trailer_block *);
+
+/*
+ * Return the end of the trailer block, again relative to the start of the
+ * input.
+ */
+size_t trailer_block_end(struct trailer_block *);
+
+/*
+ * Return 1 if the trailer block had an extra newline (blank line) just before
+ * it.
*/
-void format_trailers_from_commit(struct strbuf *out, const char *msg,
- const struct process_trailer_options *opts);
+int blank_line_before_trailer_block(struct trailer_block *);
+
+/*
+ * Free trailer_block struct.
+ */
+void trailer_block_release(struct trailer_block *);
+
+void trailer_config_init(void);
+void format_trailers(const struct process_trailer_options *,
+ struct list_head *trailers,
+ struct strbuf *out);
+void free_trailers(struct list_head *);
+
+/*
+ * Convenience function to format the trailers from the commit msg "msg" into
+ * the strbuf "out". Reuses format_trailers() internally.
+ */
+void format_trailers_from_commit(const struct process_trailer_options *,
+ const char *msg,
+ struct strbuf *out);
/*
* An interface for iterating over the trailers found in a particular commit
@@ -115,12 +155,21 @@ void format_trailers_from_commit(struct strbuf *out, const char *msg,
* trailer_iterator_release(&iter);
*/
struct trailer_iterator {
+ /*
+ * Raw line (e.g., "foo: bar baz") before being parsed as a trailer
+ * key/val pair as part of a trailer block (as the "key" and "val"
+ * fields below). If a line fails to parse as a trailer, then the "key"
+ * will be the entire line and "val" will be the empty string.
+ */
+ const char *raw;
struct strbuf key;
struct strbuf val;
/* private */
- struct trailer_info info;
- size_t cur;
+ struct {
+ struct trailer_block *trailer_block;
+ size_t cur;
+ } internal;
};
/*
@@ -146,4 +195,11 @@ int trailer_iterator_advance(struct trailer_iterator *iter);
*/
void trailer_iterator_release(struct trailer_iterator *iter);
+/*
+ * Augment a file to add trailers to it by running git-interpret-trailers.
+ * This calls run_command() and its return value is the same (i.e. 0 for
+ * success, various non-zero for other errors). See run-command.h.
+ */
+int amend_file_with_trailers(const char *path, const struct strvec *trailer_args);
+
#endif /* TRAILER_H */
diff --git a/transport-helper.c b/transport-helper.c
index 49811ef176..bc27653cde 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1,15 +1,15 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#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"
#include "thread-utils.h"
@@ -19,11 +19,12 @@
#include "refspec.h"
#include "transport-internal.h"
#include "protocol.h"
+#include "packfile.h"
static int debug;
struct helper_data {
- const char *name;
+ char *name;
struct child_process *helper;
FILE *out;
unsigned fetch : 1,
@@ -88,11 +89,18 @@ static int recvline(struct helper_data *helper, struct strbuf *buffer)
return recvline_fh(helper->out, buffer);
}
-static void write_constant(int fd, const char *str)
+static int write_constant_gently(int fd, const char *str)
{
if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", str);
if (write_in_full(fd, str, strlen(str)) < 0)
+ return -1;
+ return 0;
+}
+
+static void write_constant(int fd, const char *str)
+{
+ if (write_constant_gently(fd, str) < 0)
die_errno(_("full write to remote helper failed"));
}
@@ -112,6 +120,7 @@ static void do_take_over(struct transport *transport)
data = (struct helper_data *)transport->data;
transport_take_over(transport, data->helper);
fclose(data->out);
+ free(data->name);
free(data);
}
@@ -141,7 +150,7 @@ static struct child_process *get_helper(struct transport *transport)
if (have_git_dir())
strvec_pushf(&helper->env, "%s=%s",
- GIT_DIR_ENVIRONMENT, get_git_dir());
+ GIT_DIR_ENVIRONMENT, repo_get_git_dir(the_repository));
helper->trace2_child_class = helper->args.v[0]; /* "remote-<name>" */
@@ -166,13 +175,16 @@ static struct child_process *get_helper(struct transport *transport)
die_errno(_("can't dup helper output fd"));
data->out = xfdopen(duped, "r");
- write_constant(helper->in, "capabilities\n");
+ sigchain_push(SIGPIPE, SIG_IGN);
+ if (write_constant_gently(helper->in, "capabilities\n") < 0)
+ die("remote helper '%s' aborted session", data->name);
+ sigchain_pop(SIGPIPE);
while (1) {
const char *capname, *arg;
int mandatory = 0;
if (recvline(data, &buf))
- exit(128);
+ die("remote helper '%s' aborted session", data->name);
if (!*buf.buf)
break;
@@ -254,6 +266,7 @@ static int disconnect_helper(struct transport *transport)
close(data->helper->out);
fclose(data->out);
res = finish_command(data->helper);
+ FREE_AND_NULL(data->name);
FREE_AND_NULL(data->helper);
}
return res;
@@ -386,6 +399,8 @@ static int release_helper(struct transport *transport)
int res = 0;
struct helper_data *data = transport->data;
refspec_clear(&data->rs);
+ free(data->import_marks);
+ free(data->export_marks);
res = disconnect_helper(transport);
free(transport->data);
return res;
@@ -434,6 +449,8 @@ static int fetch_with_fetch(struct transport *transport,
warning(_("%s unexpectedly said: '%s'"), data->name, buf.buf);
}
strbuf_release(&buf);
+
+ reprepare_packed_git(the_repository);
return 0;
}
@@ -550,7 +567,7 @@ static int fetch_with_import(struct transport *transport,
else
private = xstrdup(name);
if (private) {
- if (read_ref(private, &posn->old_oid) < 0)
+ if (refs_read_ref(get_main_ref_store(the_repository), private, &posn->old_oid) < 0)
die(_("could not read ref %s"), private);
free(private);
}
@@ -628,7 +645,8 @@ static int process_connect_service(struct transport *transport,
ret = run_connect(transport, &cmdbuf);
} else if (data->stateless_connect &&
(get_protocol_version_config() == protocol_v2) &&
- !strcmp("git-upload-pack", name)) {
+ (!strcmp("git-upload-pack", name) ||
+ !strcmp("git-upload-archive", name))) {
strbuf_addf(&cmdbuf, "stateless-connect %s\n", name);
ret = run_connect(transport, &cmdbuf);
if (ret)
@@ -645,6 +663,7 @@ static int process_connect(struct transport *transport,
struct helper_data *data = transport->data;
const char *name;
const char *exec;
+ int ret;
name = for_push ? "git-receive-pack" : "git-upload-pack";
if (for_push)
@@ -652,7 +671,10 @@ static int process_connect(struct transport *transport,
else
exec = data->transport_options.uploadpack;
- return process_connect_service(transport, name, exec);
+ ret = process_connect_service(transport, name, exec);
+ if (ret)
+ do_take_over(transport);
+ return ret;
}
static int connect_helper(struct transport *transport, const char *name,
@@ -662,14 +684,14 @@ static int connect_helper(struct transport *transport, const char *name,
/* Get_helper so connect is inited. */
get_helper(transport);
- if (!data->connect)
- die(_("operation not supported by protocol"));
if (!process_connect_service(transport, name, exec))
die(_("can't connect to subservice %s"), name);
fd[0] = data->helper->out;
fd[1] = data->helper->in;
+
+ do_take_over(transport);
return 0;
}
@@ -684,10 +706,8 @@ static int fetch_refs(struct transport *transport,
get_helper(transport);
- if (process_connect(transport, 0)) {
- do_take_over(transport);
+ if (process_connect(transport, 0))
return transport->vtable->fetch_refs(transport, nr_heads, to_fetch);
- }
/*
* If we reach here, then the server, the client, and/or the transport
@@ -699,8 +719,14 @@ static int fetch_refs(struct transport *transport,
return -1;
}
- if (!data->get_refs_list_called)
- get_refs_list_using_list(transport, 0);
+ if (!data->get_refs_list_called) {
+ /*
+ * We do not care about the list of refs returned, but only
+ * that the "list" command was sent.
+ */
+ struct ref *dummy = get_refs_list_using_list(transport, 0);
+ free_refs(dummy);
+ }
count = 0;
for (i = 0; i < nr_heads; i++)
@@ -919,8 +945,10 @@ static int push_update_refs_status(struct helper_data *data,
private = apply_refspecs(&data->rs, ref->name);
if (!private)
continue;
- update_ref("update by helper", private, &(ref->new_oid),
- NULL, 0, 0);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "update by helper", private,
+ &(ref->new_oid),
+ NULL, 0, 0);
free(private);
} else {
for (report = ref->report; report; report = report->next) {
@@ -930,11 +958,12 @@ static int push_update_refs_status(struct helper_data *data,
: ref->name);
if (!private)
continue;
- update_ref("update by helper", private,
- report->new_oid
- ? report->new_oid
- : &(ref->new_oid),
- NULL, 0, 0);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "update by helper", private,
+ report->new_oid
+ ? report->new_oid
+ : &(ref->new_oid),
+ NULL, 0, 0);
free(private);
}
}
@@ -1002,6 +1031,7 @@ static int push_refs_with_push(struct transport *transport,
if (atomic) {
reject_atomic_push(remote_refs, mirror);
string_list_clear(&cas_options, 0);
+ strbuf_release(&buf);
return 0;
} else
continue;
@@ -1074,7 +1104,7 @@ static int push_refs_with_export(struct transport *transport,
set_common_push_options(transport, data->name, flags);
if (flags & TRANSPORT_PUSH_FORCE) {
if (set_helper_option(transport, "force", "true") != 0)
- warning(_("helper %s does not support 'force'"), data->name);
+ warning(_("helper %s does not support '--force'"), data->name);
}
helper = get_helper(transport);
@@ -1101,9 +1131,11 @@ static int push_refs_with_export(struct transport *transport,
int flag;
/* Follow symbolic refs (mainly for HEAD). */
- name = resolve_ref_unsafe(ref->peer_ref->name,
- RESOLVE_REF_READING,
- &oid, &flag);
+ name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ ref->peer_ref->name,
+ RESOLVE_REF_READING,
+ &oid,
+ &flag);
if (!name || !(flag & REF_ISSYMREF))
name = ref->peer_ref->name;
@@ -1144,10 +1176,8 @@ static int push_refs(struct transport *transport,
{
struct helper_data *data = transport->data;
- if (process_connect(transport, 1)) {
- do_take_over(transport);
+ if (process_connect(transport, 1))
return transport->vtable->push_refs(transport, remote_refs, flags);
- }
if (!remote_refs) {
fprintf(stderr,
@@ -1188,11 +1218,9 @@ static struct ref *get_refs_list(struct transport *transport, int for_push,
{
get_helper(transport);
- if (process_connect(transport, for_push)) {
- do_take_over(transport);
+ if (process_connect(transport, for_push))
return transport->vtable->get_refs_list(transport, for_push,
transport_options);
- }
return get_refs_list_using_list(transport, for_push);
}
@@ -1210,16 +1238,13 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
data->get_refs_list_called = 1;
helper = get_helper(transport);
- if (data->object_format) {
- write_str_in_full(helper->in, "option object-format\n");
- if (recvline(data, &buf) || strcmp(buf.buf, "ok"))
- exit(128);
- }
+ if (data->object_format)
+ set_helper_option(transport, "object-format", "true");
if (data->push && for_push)
- write_str_in_full(helper->in, "list for-push\n");
+ write_constant(helper->in, "list for-push\n");
else
- write_str_in_full(helper->in, "list\n");
+ write_constant(helper->in, "list\n");
while (1) {
char *eov, *eon;
@@ -1255,7 +1280,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
if (eon) {
if (has_attribute(eon + 1, "unchanged")) {
(*tail)->status |= REF_STATUS_UPTODATE;
- if (read_ref((*tail)->name, &(*tail)->old_oid) < 0)
+ if (refs_read_ref(get_main_ref_store(the_repository), (*tail)->name, &(*tail)->old_oid) < 0)
die(_("could not read ref %s"),
(*tail)->name);
}
@@ -1276,10 +1301,8 @@ static int get_bundle_uri(struct transport *transport)
{
get_helper(transport);
- if (process_connect(transport, 0)) {
- do_take_over(transport);
+ if (process_connect(transport, 0))
return transport->vtable->get_bundle_uri(transport);
- }
return -1;
}
@@ -1297,7 +1320,7 @@ static struct transport_vtable vtable = {
int transport_helper_init(struct transport *transport, const char *name)
{
struct helper_data *data = xcalloc(1, sizeof(*data));
- data->name = name;
+ data->name = xstrdup(name);
transport_check_allowed(name);
diff --git a/transport.c b/transport.c
index 219af8fd50..47fda6a773 100644
--- a/transport.c
+++ b/transport.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "config.h"
@@ -10,9 +12,7 @@
#include "remote.h"
#include "connect.h"
#include "send-pack.h"
-#include "walker.h"
#include "bundle.h"
-#include "dir.h"
#include "gettext.h"
#include "refs.h"
#include "refspec.h"
@@ -26,7 +26,6 @@
#include "transport-internal.h"
#include "protocol.h"
#include "object-name.h"
-#include "object-store-ll.h"
#include "color.h"
#include "bundle-uri.h"
@@ -103,8 +102,9 @@ static void set_upstreams(struct transport *transport, struct ref *refs,
/* Follow symbolic refs (mainly for HEAD). */
localname = ref->peer_ref->name;
remotename = ref->name;
- tmp = resolve_ref_unsafe(localname, RESOLVE_REF_READING,
- NULL, &flag);
+ tmp = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ localname, RESOLVE_REF_READING,
+ NULL, &flag);
if (tmp && flag & REF_ISSYMREF &&
starts_with(tmp, "refs/heads/"))
localname = tmp;
@@ -186,8 +186,11 @@ static int fetch_refs_from_bundle(struct transport *transport,
if (!data->get_refs_from_bundle_called)
get_refs_from_bundle_inner(transport);
ret = unbundle(the_repository, &data->header, data->fd,
- &extra_index_pack_args, 0);
+ &extra_index_pack_args,
+ fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0);
transport->hash_algo = data->header.hash_algo;
+
+ strvec_clear(&extra_index_pack_args);
return ret;
}
@@ -331,6 +334,9 @@ static struct ref *handshake(struct transport *transport, int for_push,
data->version = discover_version(&reader);
switch (data->version) {
case protocol_v2:
+ if ((!transport->server_options || !transport->server_options->nr) &&
+ transport->remote->server_options.nr)
+ transport->server_options = &transport->remote->server_options;
if (server_feature_v2("session-id", &server_sid))
trace2_data_string("transfer", NULL, "server-sid", server_sid);
if (must_list_refs)
@@ -411,7 +417,7 @@ static int fetch_refs_via_pack(struct transport *transport,
struct git_transport_data *data = transport->data;
struct ref *refs = NULL;
struct fetch_pack_args args;
- struct ref *refs_tmp = NULL;
+ struct ref *refs_tmp = NULL, **to_fetch_dup = NULL;
memset(&args, 0, sizeof(args));
args.uploadpack = data->options.uploadpack;
@@ -474,6 +480,14 @@ static int fetch_refs_via_pack(struct transport *transport,
goto cleanup;
}
+ /*
+ * Create a shallow copy of `sought` so that we can free all of its entries.
+ * This is because `fetch_pack()` will modify the array to evict some
+ * entries, but won't free those.
+ */
+ DUP_ARRAY(to_fetch_dup, to_fetch, nr_heads);
+ to_fetch = to_fetch_dup;
+
refs = fetch_pack(&args, data->fd,
refs_tmp ? refs_tmp : transport->remote_refs,
to_fetch, nr_heads, &data->shallow,
@@ -497,6 +511,7 @@ cleanup:
ret = -1;
data->conn = NULL;
+ free(to_fetch_dup);
free_refs(refs_tmp);
free_refs(refs);
list_objects_filter_release(&args.filter_options);
@@ -546,10 +561,12 @@ static void update_one_tracking_ref(struct remote *remote, char *refname,
if (verbose)
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
if (deletion)
- delete_ref(NULL, rs.dst, NULL, 0);
+ refs_delete_ref(get_main_ref_store(the_repository),
+ NULL, rs.dst, NULL, 0);
else
- update_ref("update by push", rs.dst, new_oid,
- NULL, 0, 0);
+ refs_update_ref(get_main_ref_store(the_repository),
+ "update by push", rs.dst, new_oid,
+ NULL, 0, 0);
free(rs.dst);
}
}
@@ -817,7 +834,8 @@ void transport_print_push_status(const char *dest, struct ref *refs,
if (transport_color_config() < 0)
warning(_("could not parse transport.color.* config"));
- head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
+ head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+ RESOLVE_REF_READING, NULL, NULL);
if (verbose) {
for (ref = refs; ref; ref = ref->next)
@@ -941,7 +959,13 @@ static int disconnect_git(struct transport *transport)
finish_connect(data->conn);
}
+ if (data->options.negotiation_tips) {
+ oid_array_clear(data->options.negotiation_tips);
+ free(data->options.negotiation_tips);
+ }
list_objects_filter_release(&data->options.filter_options);
+ oid_array_clear(&data->extra_have);
+ oid_array_clear(&data->shallow);
free(data);
return 0;
}
@@ -1087,6 +1111,18 @@ int is_transport_allowed(const char *type, int from_user)
BUG("invalid protocol_allow_config type");
}
+int parse_transport_option(const char *var, const char *value,
+ struct string_list *transport_options)
+{
+ if (!value)
+ return config_error_nonbool(var);
+ if (!*value)
+ string_list_clear(transport_options, 0);
+ else
+ string_list_append(transport_options, value);
+ return 0;
+}
+
void transport_check_allowed(const char *type)
{
if (!is_transport_allowed(type, -1))
@@ -1111,6 +1147,8 @@ static struct transport_vtable builtin_smart_vtable = {
struct transport *transport_get(struct remote *remote, const char *url)
{
const char *helper;
+ char *helper_to_free = NULL;
+ const char *p;
struct transport *ret = xcalloc(1, sizeof(*ret));
ret->progress = isatty(2);
@@ -1126,22 +1164,19 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->remote = remote;
helper = remote->foreign_vcs;
- if (!url && remote->url)
- url = remote->url[0];
+ if (!url)
+ url = remote->url.v[0];
ret->url = url;
- /* maybe it is a foreign URL? */
- if (url) {
- const char *p = url;
-
- while (is_urlschemechar(p == url, *p))
- p++;
- if (starts_with(p, "::"))
- helper = xstrndup(url, p - url);
- }
+ p = url;
+ while (is_urlschemechar(p == url, *p))
+ p++;
+ if (starts_with(p, "::"))
+ helper = helper_to_free = xstrndup(url, p - url);
if (helper) {
transport_helper_init(ret, helper);
+ free(helper_to_free);
} else if (starts_with(url, "rsync:")) {
die(_("git-over-rsync is no longer supported"));
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
@@ -1175,6 +1210,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
int len = external_specification_len(url);
char *handler = xmemdupz(url, len);
transport_helper_init(ret, handler);
+ free(handler);
}
if (ret->smart_options) {
@@ -1269,7 +1305,7 @@ static int run_pre_push_hook(struct transport *transport,
struct ref *r;
struct child_process proc = CHILD_PROCESS_INIT;
struct strbuf buf;
- const char *hook_path = find_hook("pre-push");
+ const char *hook_path = find_hook(the_repository, "pre-push");
if (!hook_path)
return 0;
@@ -1470,6 +1506,7 @@ int transport_push(struct repository *r,
if (porcelain && !push_ret)
puts("Done");
else if (!quiet && !ret && !transport_refs_pushed(remote_refs))
+ /* stable plumbing output; do not modify or localize */
fprintf(stderr, "Everything up-to-date\n");
done:
diff --git a/transport.h b/transport.h
index 6393cd9823..44100fa9b7 100644
--- a/transport.h
+++ b/transport.h
@@ -342,4 +342,8 @@ void transport_print_push_status(const char *dest, struct ref *refs,
/* common method used by transport-helper.c and send-pack.c */
void reject_atomic_push(struct ref *refs, int mirror_mode);
+/* common method to parse push-option or server-option from config */
+int parse_transport_option(const char *var, const char *value,
+ struct string_list *transport_options);
+
#endif
diff --git a/tree-diff.c b/tree-diff.c
index 8fc159b86e..5eab8af631 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -1,12 +1,17 @@
/*
* Helper functions for tree diff generation
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
#include "hash.h"
#include "tree.h"
#include "tree-walk.h"
+#include "environment.h"
+#include "repository.h"
/*
* Some mode bits are also used internally for computations.
@@ -45,7 +50,8 @@
static struct combine_diff_path *ll_diff_tree_paths(
struct combine_diff_path *p, const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
- struct strbuf *base, struct diff_options *opt);
+ struct strbuf *base, struct diff_options *opt,
+ int depth);
static void ll_diff_tree_oid(const struct object_id *old_oid,
const struct object_id *new_oid,
struct strbuf *base, struct diff_options *opt);
@@ -196,7 +202,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
static struct combine_diff_path *emit_path(struct combine_diff_path *p,
struct strbuf *base, struct diff_options *opt, int nparent,
struct tree_desc *t, struct tree_desc *tp,
- int imin)
+ int imin, int depth)
{
unsigned short mode;
const char *path;
@@ -302,7 +308,8 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
strbuf_add(base, path, pathlen);
strbuf_addch(base, '/');
- p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
+ p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt,
+ depth + 1);
FAST_ARRAY_FREE(parents_oid, nparent);
}
@@ -423,12 +430,16 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
static struct combine_diff_path *ll_diff_tree_paths(
struct combine_diff_path *p, const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
- struct strbuf *base, struct diff_options *opt)
+ struct strbuf *base, struct diff_options *opt,
+ int depth)
{
struct tree_desc t, *tp;
void *ttree, **tptree;
int i;
+ if (depth > max_allowed_tree_depth)
+ die("exceeded maximum allowed tree depth");
+
FAST_ARRAY_ALLOC(tp, nparent);
FAST_ARRAY_ALLOC(tptree, nparent);
@@ -522,7 +533,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
/* D += {δ(t,pi) if pi=p[imin]; "+a" if pi > p[imin]} */
p = emit_path(p, base, opt, nparent,
- &t, tp, imin);
+ &t, tp, imin, depth);
skip_emit_t_tp:
/* t↓, ∀ pi=p[imin] pi↓ */
@@ -534,7 +545,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
else if (cmp < 0) {
/* D += "+t" */
p = emit_path(p, base, opt, nparent,
- &t, /*tp=*/NULL, -1);
+ &t, /*tp=*/NULL, -1, depth);
/* t↓ */
update_tree_entry(&t);
@@ -550,7 +561,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
}
p = emit_path(p, base, opt, nparent,
- /*t=*/NULL, tp, imin);
+ /*t=*/NULL, tp, imin, depth);
skip_emit_tp:
/* ∀ pi=p[imin] pi↓ */
@@ -572,7 +583,7 @@ struct combine_diff_path *diff_tree_paths(
const struct object_id **parents_oid, int nparent,
struct strbuf *base, struct diff_options *opt)
{
- p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
+ p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt, 0);
/*
* free pre-allocated last element, if any
diff --git a/tree-walk.c b/tree-walk.c
index 29ead71be1..a033397965 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "tree-walk.h"
#include "dir.h"
@@ -9,36 +11,21 @@
#include "tree.h"
#include "pathspec.h"
#include "json-writer.h"
-
-static const char *get_mode(const char *str, unsigned int *modep)
-{
- unsigned char c;
- unsigned int mode = 0;
-
- if (*str == ' ')
- return NULL;
-
- while ((c = *str++) != ' ') {
- if (c < '0' || c > '7')
- return NULL;
- mode = (mode << 3) + (c - '0');
- }
- *modep = mode;
- return str;
-}
+#include "environment.h"
static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size, struct strbuf *err)
{
const char *path;
- unsigned int mode, len;
- const unsigned hashsz = the_hash_algo->rawsz;
+ unsigned int len;
+ uint16_t mode;
+ const unsigned hashsz = desc->algo->rawsz;
if (size < hashsz + 3 || buf[size - (hashsz + 1)]) {
strbuf_addstr(err, _("too-short tree object"));
return -1;
}
- path = get_mode(buf, &mode);
+ path = parse_mode(buf, &mode);
if (!path) {
strbuf_addstr(err, _("malformed mode in tree entry"));
return -1;
@@ -53,15 +40,19 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
desc->entry.path = path;
desc->entry.mode = (desc->flags & TREE_DESC_RAW_MODES) ? mode : canon_mode(mode);
desc->entry.pathlen = len - 1;
- oidread(&desc->entry.oid, (const unsigned char *)path + len);
+ oidread(&desc->entry.oid, (const unsigned char *)path + len,
+ desc->algo);
return 0;
}
-static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer,
- unsigned long size, struct strbuf *err,
+static int init_tree_desc_internal(struct tree_desc *desc,
+ const struct object_id *oid,
+ const void *buffer, unsigned long size,
+ struct strbuf *err,
enum tree_desc_flags flags)
{
+ desc->algo = (oid && oid->algo) ? &hash_algos[oid->algo] : the_hash_algo;
desc->buffer = buffer;
desc->size = size;
desc->flags = flags;
@@ -70,19 +61,21 @@ static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer,
return 0;
}
-void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
+void init_tree_desc(struct tree_desc *desc, const struct object_id *tree_oid,
+ const void *buffer, unsigned long size)
{
struct strbuf err = STRBUF_INIT;
- if (init_tree_desc_internal(desc, buffer, size, &err, 0))
+ if (init_tree_desc_internal(desc, tree_oid, buffer, size, &err, 0))
die("%s", err.buf);
strbuf_release(&err);
}
-int init_tree_desc_gently(struct tree_desc *desc, const void *buffer, unsigned long size,
+int init_tree_desc_gently(struct tree_desc *desc, const struct object_id *oid,
+ const void *buffer, unsigned long size,
enum tree_desc_flags flags)
{
struct strbuf err = STRBUF_INIT;
- int result = init_tree_desc_internal(desc, buffer, size, &err, flags);
+ int result = init_tree_desc_internal(desc, oid, buffer, size, &err, flags);
if (result)
error("%s", err.buf);
strbuf_release(&err);
@@ -99,9 +92,9 @@ void *fill_tree_descriptor(struct repository *r,
if (oid) {
buf = read_object_with_reference(r, oid, OBJ_TREE, &size, NULL);
if (!buf)
- die("unable to read tree %s", oid_to_hex(oid));
+ die(_("unable to read tree (%s)"), oid_to_hex(oid));
}
- init_tree_desc(desc, buf, size);
+ init_tree_desc(desc, oid, buf, size);
return buf;
}
@@ -118,7 +111,7 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a)
static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
{
const void *buf = desc->buffer;
- const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + the_hash_algo->rawsz;
+ const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + desc->algo->rawsz;
unsigned long size = desc->size;
unsigned long len = end - (const unsigned char *)buf;
@@ -441,22 +434,25 @@ int traverse_trees(struct index_state *istate,
int n, struct tree_desc *t,
struct traverse_info *info)
{
- int error = 0;
- struct name_entry entry[MAX_TRAVERSE_TREES];
+ int ret = 0;
+ struct name_entry *entry;
int i;
- struct tree_desc_x tx[ARRAY_SIZE(entry)];
+ struct tree_desc_x *tx;
struct strbuf base = STRBUF_INIT;
int interesting = 1;
char *traverse_path;
+ if (traverse_trees_cur_depth > max_allowed_tree_depth)
+ return error("exceeded maximum allowed tree depth");
+
traverse_trees_count++;
traverse_trees_cur_depth++;
if (traverse_trees_cur_depth > traverse_trees_max_depth)
traverse_trees_max_depth = traverse_trees_cur_depth;
- if (n >= ARRAY_SIZE(entry))
- BUG("traverse_trees() called with too many trees (%d)", n);
+ ALLOC_ARRAY(entry, n);
+ ALLOC_ARRAY(tx, n);
for (i = 0; i < n; i++) {
tx[i].d = t[i];
@@ -539,7 +535,7 @@ int traverse_trees(struct index_state *istate,
if (interesting) {
trees_used = info->fn(n, mask, dirmask, entry, info);
if (trees_used < 0) {
- error = trees_used;
+ ret = trees_used;
if (!info->show_all_errors)
break;
}
@@ -551,12 +547,14 @@ int traverse_trees(struct index_state *istate,
}
for (i = 0; i < n; i++)
free_extended_entry(tx + i);
+ free(tx);
+ free(entry);
free(traverse_path);
info->traverse_path = NULL;
strbuf_release(&base);
traverse_trees_cur_depth--;
- return error;
+ return ret;
}
struct dir_state {
@@ -627,7 +625,7 @@ int get_tree_entry(struct repository *r,
retval = -1;
} else {
struct tree_desc t;
- init_tree_desc(&t, tree, size);
+ init_tree_desc(&t, tree_oid, tree, size);
retval = find_tree_entry(r, &t, name, oid, mode);
}
free(tree);
@@ -670,7 +668,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
struct tree_desc t;
int follows_remaining = GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS;
- init_tree_desc(&t, NULL, 0UL);
+ init_tree_desc(&t, NULL, NULL, 0UL);
strbuf_addstr(&namebuf, name);
oidcpy(&current_tree_oid, tree_oid);
@@ -706,7 +704,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
goto done;
/* descend */
- init_tree_desc(&t, tree, size);
+ init_tree_desc(&t, &current_tree_oid, tree, size);
}
/* Handle symlinks to e.g. a//b by removing leading slashes */
@@ -740,7 +738,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
free(parent->tree);
parents_nr--;
parent = &parents[parents_nr - 1];
- init_tree_desc(&t, parent->tree, parent->size);
+ init_tree_desc(&t, &parent->oid, parent->tree, parent->size);
strbuf_remove(&namebuf, 0, remainder ? 3 : 2);
continue;
}
@@ -820,7 +818,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
contents_start = contents;
parent = &parents[parents_nr - 1];
- init_tree_desc(&t, parent->tree, parent->size);
+ init_tree_desc(&t, &parent->oid, parent->tree, parent->size);
strbuf_splice(&namebuf, 0, len,
contents_start, link_len);
if (remainder)
diff --git a/tree-walk.h b/tree-walk.h
index 74cdceb3fe..aaea689f9a 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -1,13 +1,11 @@
#ifndef TREE_WALK_H
#define TREE_WALK_H
-#include "hash-ll.h"
+#include "hash.h"
struct index_state;
struct repository;
-#define MAX_TRAVERSE_TREES 8
-
/**
* The tree walking API is used to traverse and inspect trees.
*/
@@ -26,6 +24,7 @@ struct name_entry {
* A semi-opaque data structure used to maintain the current state of the walk.
*/
struct tree_desc {
+ const struct git_hash_algo *algo;
/*
* pointer into the memory representation of the tree. It always
* points at the current entry being visited.
@@ -85,9 +84,11 @@ int update_tree_entry_gently(struct tree_desc *);
* size parameters are assumed to be the same as the buffer and size
* members of `struct tree`.
*/
-void init_tree_desc(struct tree_desc *desc, const void *buf, unsigned long size);
+void init_tree_desc(struct tree_desc *desc, const struct object_id *tree_oid,
+ const void *buf, unsigned long size);
-int init_tree_desc_gently(struct tree_desc *desc, const void *buf, unsigned long size,
+int init_tree_desc_gently(struct tree_desc *desc, const struct object_id *oid,
+ const void *buf, unsigned long size,
enum tree_desc_flags flags);
/*
diff --git a/tree.c b/tree.c
index c745462f96..ad86ad1ba9 100644
--- a/tree.c
+++ b/tree.c
@@ -1,20 +1,21 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
-#include "cache-tree.h"
#include "hex.h"
#include "tree.h"
#include "object-name.h"
#include "object-store-ll.h"
-#include "blob.h"
#include "commit.h"
-#include "tag.h"
#include "alloc.h"
#include "tree-walk.h"
#include "repository.h"
+#include "environment.h"
const char *tree_type = "tree";
int read_tree_at(struct repository *r,
struct tree *tree, struct strbuf *base,
+ int depth,
const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
@@ -24,10 +25,13 @@ int read_tree_at(struct repository *r,
int len, oldlen = base->len;
enum interesting retval = entry_not_interesting;
+ if (depth > max_allowed_tree_depth)
+ return error("exceeded maximum allowed tree depth");
+
if (parse_tree(tree))
return -1;
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
if (retval != all_entries_interesting) {
@@ -74,7 +78,7 @@ int read_tree_at(struct repository *r,
strbuf_add(base, entry.path, len);
strbuf_addch(base, '/');
retval = read_tree_at(r, lookup_tree(r, &oid),
- base, pathspec,
+ base, depth + 1, pathspec,
fn, context);
strbuf_setlen(base, oldlen);
if (retval)
@@ -89,7 +93,7 @@ int read_tree(struct repository *r,
read_tree_fn_t fn, void *context)
{
struct strbuf sb = STRBUF_INIT;
- int ret = read_tree_at(r, tree, &sb, pathspec, fn, context);
+ int ret = read_tree_at(r, tree, &sb, 0, pathspec, fn, context);
strbuf_release(&sb);
return ret;
}
diff --git a/tree.h b/tree.h
index 1b5ecbda6b..cc6ddf51b3 100644
--- a/tree.h
+++ b/tree.h
@@ -44,6 +44,7 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
int read_tree_at(struct repository *r,
struct tree *tree, struct strbuf *base,
+ int depth,
const struct pathspec *pathspec,
read_tree_fn_t fn, void *context);
diff --git a/unicode-width.h b/unicode-width.h
index e15fb0455b..3ffee123a0 100644
--- a/unicode-width.h
+++ b/unicode-width.h
@@ -27,7 +27,7 @@ static const struct interval zero_width[] = {
{ 0x0829, 0x082D },
{ 0x0859, 0x085B },
{ 0x0890, 0x0891 },
-{ 0x0898, 0x089F },
+{ 0x0897, 0x089F },
{ 0x08CA, 0x0902 },
{ 0x093A, 0x093A },
{ 0x093C, 0x093C },
@@ -227,8 +227,9 @@ static const struct interval zero_width[] = {
{ 0x10A3F, 0x10A3F },
{ 0x10AE5, 0x10AE6 },
{ 0x10D24, 0x10D27 },
+{ 0x10D69, 0x10D6D },
{ 0x10EAB, 0x10EAC },
-{ 0x10EFD, 0x10EFF },
+{ 0x10EFC, 0x10EFF },
{ 0x10F46, 0x10F50 },
{ 0x10F82, 0x10F85 },
{ 0x11001, 0x11001 },
@@ -261,6 +262,11 @@ static const struct interval zero_width[] = {
{ 0x11340, 0x11340 },
{ 0x11366, 0x1136C },
{ 0x11370, 0x11374 },
+{ 0x113BB, 0x113C0 },
+{ 0x113CE, 0x113CE },
+{ 0x113D0, 0x113D0 },
+{ 0x113D2, 0x113D2 },
+{ 0x113E1, 0x113E2 },
{ 0x11438, 0x1143F },
{ 0x11442, 0x11444 },
{ 0x11446, 0x11446 },
@@ -280,7 +286,8 @@ static const struct interval zero_width[] = {
{ 0x116AD, 0x116AD },
{ 0x116B0, 0x116B5 },
{ 0x116B7, 0x116B7 },
-{ 0x1171D, 0x1171F },
+{ 0x1171D, 0x1171D },
+{ 0x1171F, 0x1171F },
{ 0x11722, 0x11725 },
{ 0x11727, 0x1172B },
{ 0x1182F, 0x11837 },
@@ -319,8 +326,11 @@ static const struct interval zero_width[] = {
{ 0x11F36, 0x11F3A },
{ 0x11F40, 0x11F40 },
{ 0x11F42, 0x11F42 },
+{ 0x11F5A, 0x11F5A },
{ 0x13430, 0x13440 },
{ 0x13447, 0x13455 },
+{ 0x1611E, 0x16129 },
+{ 0x1612D, 0x1612F },
{ 0x16AF0, 0x16AF4 },
{ 0x16B30, 0x16B36 },
{ 0x16F4F, 0x16F4F },
@@ -351,6 +361,7 @@ static const struct interval zero_width[] = {
{ 0x1E2AE, 0x1E2AE },
{ 0x1E2EC, 0x1E2EF },
{ 0x1E4EC, 0x1E4EF },
+{ 0x1E5EE, 0x1E5EF },
{ 0x1E8D0, 0x1E8D6 },
{ 0x1E944, 0x1E94A },
{ 0xE0001, 0xE0001 },
@@ -366,8 +377,10 @@ static const struct interval double_width[] = {
{ 0x23F3, 0x23F3 },
{ 0x25FD, 0x25FE },
{ 0x2614, 0x2615 },
+{ 0x2630, 0x2637 },
{ 0x2648, 0x2653 },
{ 0x267F, 0x267F },
+{ 0x268A, 0x268F },
{ 0x2693, 0x2693 },
{ 0x26A1, 0x26A1 },
{ 0x26AA, 0x26AB },
@@ -396,17 +409,15 @@ static const struct interval double_width[] = {
{ 0x2E80, 0x2E99 },
{ 0x2E9B, 0x2EF3 },
{ 0x2F00, 0x2FD5 },
-{ 0x2FF0, 0x2FFB },
-{ 0x3000, 0x303E },
+{ 0x2FF0, 0x303E },
{ 0x3041, 0x3096 },
{ 0x3099, 0x30FF },
{ 0x3105, 0x312F },
{ 0x3131, 0x318E },
-{ 0x3190, 0x31E3 },
-{ 0x31F0, 0x321E },
+{ 0x3190, 0x31E5 },
+{ 0x31EF, 0x321E },
{ 0x3220, 0x3247 },
-{ 0x3250, 0x4DBF },
-{ 0x4E00, 0xA48C },
+{ 0x3250, 0xA48C },
{ 0xA490, 0xA4C6 },
{ 0xA960, 0xA97C },
{ 0xAC00, 0xD7A3 },
@@ -421,7 +432,7 @@ static const struct interval double_width[] = {
{ 0x16FF0, 0x16FF1 },
{ 0x17000, 0x187F7 },
{ 0x18800, 0x18CD5 },
-{ 0x18D00, 0x18D08 },
+{ 0x18CFF, 0x18D08 },
{ 0x1AFF0, 0x1AFF3 },
{ 0x1AFF5, 0x1AFFB },
{ 0x1AFFD, 0x1AFFE },
@@ -431,6 +442,8 @@ static const struct interval double_width[] = {
{ 0x1B155, 0x1B155 },
{ 0x1B164, 0x1B167 },
{ 0x1B170, 0x1B2FB },
+{ 0x1D300, 0x1D356 },
+{ 0x1D360, 0x1D376 },
{ 0x1F004, 0x1F004 },
{ 0x1F0CF, 0x1F0CF },
{ 0x1F18E, 0x1F18E },
@@ -471,11 +484,10 @@ static const struct interval double_width[] = {
{ 0x1F93C, 0x1F945 },
{ 0x1F947, 0x1F9FF },
{ 0x1FA70, 0x1FA7C },
-{ 0x1FA80, 0x1FA88 },
-{ 0x1FA90, 0x1FABD },
-{ 0x1FABF, 0x1FAC5 },
-{ 0x1FACE, 0x1FADB },
-{ 0x1FAE0, 0x1FAE8 },
+{ 0x1FA80, 0x1FA89 },
+{ 0x1FA8F, 0x1FAC6 },
+{ 0x1FACE, 0x1FADC },
+{ 0x1FADF, 0x1FAE9 },
{ 0x1FAF0, 0x1FAF8 },
{ 0x20000, 0x2FFFD },
{ 0x30000, 0x3FFFD }
diff --git a/unpack-trees.c b/unpack-trees.c
index 87517364dc..e10a9d1209 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1,8 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "strvec.h"
#include "repository.h"
-#include "config.h"
+#include "parse.h"
#include "dir.h"
#include "environment.h"
#include "gettext.h"
@@ -208,6 +210,7 @@ void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
{
strvec_clear(&opts->internal.msgs_to_free);
memset(opts->internal.msgs, 0, sizeof(opts->internal.msgs));
+ discard_index(&opts->internal.result);
}
static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
@@ -805,6 +808,8 @@ static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names,
if (!o->merge)
BUG("We need cache-tree to do this optimization");
+ if (nr_entries + pos > o->src_index->cache_nr)
+ return error(_("corrupted cache-tree has entries not present in index"));
/*
* Do what unpack_callback() and unpack_single_entry() normally
@@ -864,8 +869,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
struct unpack_trees_options *o = info->data;
int i, ret, bottom;
int nr_buf = 0;
- struct tree_desc t[MAX_UNPACK_TREES];
- void *buf[MAX_UNPACK_TREES];
+ struct tree_desc *t;
+ void **buf;
struct traverse_info newinfo;
struct name_entry *p;
int nr_entries;
@@ -902,6 +907,9 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
newinfo.df_conflicts |= df_conflicts;
+ ALLOC_ARRAY(t, n);
+ ALLOC_ARRAY(buf, n);
+
/*
* Fetch the tree from the ODB for each peer directory in the
* n commits.
@@ -937,6 +945,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
for (i = 0; i < nr_buf; i++)
free(buf[i]);
+ free(buf);
+ free(t);
return ret;
}
@@ -2062,9 +2072,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (o->dst_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->internal.result);
+ if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0) &&
+ cache_tree_verify(the_repository,
+ &o->internal.result) < 0) {
+ ret = -1;
+ goto done;
+ }
+
if (!o->skip_cache_tree_update &&
!cache_tree_fully_valid(o->internal.result.cache_tree))
cache_tree_update(&o->internal.result,
@@ -2075,6 +2089,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
o->internal.result.updated_workdir = 1;
discard_index(o->dst_index);
*o->dst_index = o->internal.result;
+ memset(&o->internal.result, 0, sizeof(o->internal.result));
} else {
discard_index(&o->internal.result);
}
@@ -2313,7 +2328,8 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
if (S_ISGITLINK(ce->ce_mode)) {
struct object_id oid;
- int sub_head = resolve_gitlink_ref(ce->name, "HEAD", &oid);
+ int sub_head = repo_resolve_gitlink_ref(the_repository, ce->name,
+ "HEAD", &oid);
/*
* If we are not going to update the submodule, then
* we don't care.
diff --git a/unpack-trees.h b/unpack-trees.h
index 9b827c307f..5867e26e17 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -7,7 +7,7 @@
#include "string-list.h"
#include "tree-walk.h"
-#define MAX_UNPACK_TREES MAX_TRAVERSE_TREES
+#define MAX_UNPACK_TREES 8
struct cache_entry;
struct unpack_trees_options;
diff --git a/upload-pack.c b/upload-pack.c
index 83f3d2651a..43006c0614 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
@@ -9,13 +11,10 @@
#include "repository.h"
#include "object-store-ll.h"
#include "oid-array.h"
-#include "tag.h"
#include "object.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
-#include "list-objects.h"
-#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "run-command.h"
#include "connect.h"
@@ -24,15 +23,14 @@
#include "string-list.h"
#include "strvec.h"
#include "trace2.h"
-#include "prio-queue.h"
#include "protocol.h"
-#include "quote.h"
#include "upload-pack.h"
-#include "serve.h"
#include "commit-graph.h"
#include "commit-reach.h"
#include "shallow.h"
#include "write-or-die.h"
+#include "json-writer.h"
+#include "strmap.h"
/* Remember to update object flag allocation in object.h */
#define THEY_HAVE (1u << 11)
@@ -66,12 +64,11 @@ struct upload_pack_data {
struct string_list symref; /* v0 only */
struct object_array want_obj;
struct object_array have_obj;
- struct oid_array haves; /* v2 only */
- struct string_list wanted_refs; /* v2 only */
+ struct strmap wanted_refs; /* v2 only */
struct strvec hidden_refs;
struct object_array shallows;
- struct string_list deepen_not;
+ struct oidset deepen_not;
struct object_array extra_edge_obj;
int depth;
timestamp_t deepen_since;
@@ -99,7 +96,7 @@ struct upload_pack_data {
struct packet_writer writer;
- const char *pack_objects_hook;
+ char *pack_objects_hook;
unsigned stateless_rpc : 1; /* v0 only */
unsigned no_done : 1; /* v0 only */
@@ -118,6 +115,8 @@ struct upload_pack_data {
unsigned done : 1; /* v2 only */
unsigned allow_ref_in_want : 1; /* v2 only */
unsigned allow_sideband_all : 1; /* v2 only */
+ unsigned seen_haves : 1; /* v2 only */
+ unsigned allow_packfile_uris : 1; /* v2 only */
unsigned advertise_sid : 1;
unsigned sent_capabilities : 1;
};
@@ -125,13 +124,12 @@ struct upload_pack_data {
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 strmap wanted_refs = STRMAP_INIT;
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;
struct object_array shallows = OBJECT_ARRAY_INIT;
- struct string_list deepen_not = STRING_LIST_INIT_DUP;
+ struct oidset deepen_not = OID_ARRAY_INIT;
struct string_list uri_protocols = STRING_LIST_INIT_DUP;
struct object_array extra_edge_obj = OBJECT_ARRAY_INIT;
struct string_list allowed_filters = STRING_LIST_INIT_DUP;
@@ -142,7 +140,6 @@ static void upload_pack_data_init(struct upload_pack_data *data)
data->hidden_refs = hidden_refs;
data->want_obj = want_obj;
data->have_obj = have_obj;
- data->haves = haves;
data->shallows = shallows;
data->deepen_not = deepen_not;
data->uri_protocols = uri_protocols;
@@ -160,16 +157,16 @@ static void upload_pack_data_init(struct upload_pack_data *data)
static void upload_pack_data_clear(struct upload_pack_data *data)
{
string_list_clear(&data->symref, 1);
- string_list_clear(&data->wanted_refs, 1);
+ strmap_clear(&data->wanted_refs, 1);
strvec_clear(&data->hidden_refs);
object_array_clear(&data->want_obj);
object_array_clear(&data->have_obj);
- oid_array_clear(&data->haves);
object_array_clear(&data->shallows);
- string_list_clear(&data->deepen_not, 0);
+ oidset_clear(&data->deepen_not);
object_array_clear(&data->extra_edge_obj);
list_objects_filter_release(&data->filter_options);
string_list_clear(&data->allowed_filters, 0);
+ string_list_clear(&data->uri_protocols, 0);
free((char *)data->pack_objects_hook);
}
@@ -468,7 +465,7 @@ static void create_pack_file(struct upload_pack_data *pack_data,
fail:
free(output_state);
- send_client_data(3, abort_msg, sizeof(abort_msg),
+ send_client_data(3, abort_msg, strlen(abort_msg),
pack_data->use_sideband);
die("git upload-pack: %s", abort_msg);
}
@@ -476,7 +473,9 @@ static void create_pack_file(struct upload_pack_data *pack_data,
static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid)
{
int we_knew_they_have = 0;
- struct object *o = parse_object(the_repository, oid);
+ struct object *o = parse_object_with_flags(the_repository, oid,
+ PARSE_OBJECT_SKIP_HASH_CHECK |
+ PARSE_OBJECT_DISCARD_TREE);
if (!o)
die("oops (%s)", oid_to_hex(oid));
@@ -533,8 +532,6 @@ static int get_common_commits(struct upload_pack_data *data,
int got_other = 0;
int sent_ready = 0;
- save_commit_buffer = 0;
-
for (;;) {
const char *arg;
@@ -624,7 +621,8 @@ static void for_each_namespaced_ref_1(each_ref_fn fn,
if (allow_hidden_refs(data->allow_uor))
excludes = hidden_refs_to_excludes(&data->hidden_refs);
- for_each_namespaced_ref(excludes, fn, data);
+ refs_for_each_namespaced_ref(get_main_ref_store(the_repository),
+ excludes, fn, data);
}
@@ -712,10 +710,13 @@ static int get_reachable_list(struct upload_pack_data *data,
struct object *o;
char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */
const unsigned hexsz = the_hash_algo->hexsz;
+ int ret;
if (do_reachable_revlist(&cmd, &data->shallows, reachable,
- data->allow_uor) < 0)
- return -1;
+ data->allow_uor) < 0) {
+ ret = -1;
+ goto out;
+ }
while ((i = read_in_full(cmd.out, namebuf, hexsz + 1)) == hexsz + 1) {
struct object_id oid;
@@ -739,10 +740,16 @@ static int get_reachable_list(struct upload_pack_data *data,
}
close(cmd.out);
- if (finish_command(&cmd))
- return -1;
+ if (finish_command(&cmd)) {
+ ret = -1;
+ goto out;
+ }
- return 0;
+ ret = 0;
+
+out:
+ child_process_clear(&cmd);
+ return ret;
}
static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
@@ -752,7 +759,7 @@ static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
int i;
if (do_reachable_revlist(&cmd, src, NULL, allow_uor) < 0)
- return 1;
+ goto error;
/*
* The commits out of the rev-list are not ancestors of
@@ -778,6 +785,7 @@ static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
error:
if (cmd.out >= 0)
close(cmd.out);
+ child_process_clear(&cmd);
return 1;
}
@@ -860,7 +868,7 @@ static void send_unshallow(struct upload_pack_data *data)
}
}
-static int check_ref(const char *refname_full, const struct object_id *oid,
+static int check_ref(const char *refname_full, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data);
static void deepen(struct upload_pack_data *data, int depth)
{
@@ -879,7 +887,8 @@ static void deepen(struct upload_pack_data *data, int depth)
* Checking for reachable shallows requires that our refs be
* marked with OUR_REF.
*/
- head_ref_namespaced(check_ref, data);
+ refs_head_ref_namespaced(get_main_ref_store(the_repository),
+ check_ref, data);
for_each_namespaced_ref_1(check_ref, data);
get_reachable_list(data, &reachable_shallows);
@@ -931,12 +940,13 @@ static int send_shallow_list(struct upload_pack_data *data)
strvec_push(&av, "rev-list");
if (data->deepen_since)
strvec_pushf(&av, "--max-age=%"PRItime, data->deepen_since);
- if (data->deepen_not.nr) {
+ if (oidset_size(&data->deepen_not)) {
+ const struct object_id *oid;
+ struct oidset_iter iter;
strvec_push(&av, "--not");
- for (i = 0; i < data->deepen_not.nr; i++) {
- struct string_list_item *s = data->deepen_not.items + i;
- strvec_push(&av, s->string);
- }
+ oidset_iter_init(&data->deepen_not, &iter);
+ while ((oid = oidset_iter_next(&iter)))
+ strvec_push(&av, oid_to_hex(oid));
strvec_push(&av, "--not");
}
for (i = 0; i < data->want_obj.nr; i++) {
@@ -1012,15 +1022,19 @@ static int process_deepen_since(const char *line, timestamp_t *deepen_since, int
return 0;
}
-static int process_deepen_not(const char *line, struct string_list *deepen_not, int *deepen_rev_list)
+static int process_deepen_not(const char *line, struct oidset *deepen_not, int *deepen_rev_list)
{
const char *arg;
if (skip_prefix(line, "deepen-not ", &arg)) {
+ int cnt;
char *ref = NULL;
struct object_id oid;
- if (expand_ref(the_repository, arg, strlen(arg), &oid, &ref) != 1)
+ cnt = expand_ref(the_repository, arg, strlen(arg), &oid, &ref);
+ if (cnt > 1)
die("git upload-pack: ambiguous deepen-not: %s", line);
- string_list_append(deepen_not, ref);
+ if (cnt < 1)
+ die("git upload-pack: deepen-not is not a ref: %s", line);
+ oidset_insert(deepen_not, &oid);
free(ref);
*deepen_rev_list = 1;
return 1;
@@ -1156,7 +1170,9 @@ static void receive_needs(struct upload_pack_data *data,
free(client_sid);
}
- o = parse_object(the_repository, &oid_buf);
+ o = parse_object_with_flags(the_repository, &oid_buf,
+ PARSE_OBJECT_SKIP_HASH_CHECK |
+ PARSE_OBJECT_DISCARD_TREE);
if (!o) {
packet_writer_error(&data->writer,
"upload-pack: not our ref %s",
@@ -1207,7 +1223,7 @@ static int mark_our_ref(const char *refname, const char *refname_full,
return 0;
}
-static int check_ref(const char *refname_full, const struct object_id *oid,
+static int check_ref(const char *refname_full, const char *referent UNUSED,const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
const char *refname = strip_namespace(refname_full);
@@ -1270,19 +1286,19 @@ static void write_v0_ref(struct upload_pack_data *data,
packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);
}
capabilities = NULL;
- if (!peel_iterated_oid(oid, &peeled))
+ if (!peel_iterated_oid(the_repository, 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,
+static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
write_v0_ref(cb_data, refname, strip_namespace(refname), oid);
return 0;
}
-static int find_symref(const char *refname,
+static int find_symref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag, void *cb_data)
{
@@ -1291,7 +1307,8 @@ static int find_symref(const char *refname,
if ((flag & REF_ISSYMREF) == 0)
return 0;
- symref_target = resolve_ref_unsafe(refname, 0, NULL, &flag);
+ symref_target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ refname, 0, NULL, &flag);
if (!symref_target || (flag & REF_ISSYMREF) == 0)
die("'%s' is a symref but it is not?", refname);
item = string_list_append(cb_data, strip_namespace(refname));
@@ -1367,6 +1384,9 @@ static int upload_pack_config(const char *var, const char *value,
data->allow_ref_in_want = git_config_bool(var, value);
} else if (!strcmp("uploadpack.allowsidebandall", var)) {
data->allow_sideband_all = git_config_bool(var, value);
+ } else if (!strcmp("uploadpack.blobpackfileuri", var)) {
+ if (value)
+ data->allow_packfile_uris = 1;
} else if (!strcmp("core.precomposeunicode", var)) {
precomposed_unicode = git_config_bool(var, value);
} else if (!strcmp("transfer.advertisesid", var)) {
@@ -1390,10 +1410,13 @@ static int upload_pack_protected_config(const char *var, const char *value,
return 0;
}
-static void get_upload_pack_config(struct upload_pack_data *data)
+static void get_upload_pack_config(struct repository *r,
+ struct upload_pack_data *data)
{
- git_config(upload_pack_config, data);
+ repo_config(r, upload_pack_config, data);
git_protected_config(upload_pack_protected_config, data);
+
+ data->allow_sideband_all |= git_env_bool("GIT_TEST_SIDEBAND_ALL", 0);
}
void upload_pack(const int advertise_refs, const int stateless_rpc,
@@ -1403,20 +1426,22 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
struct upload_pack_data data;
upload_pack_data_init(&data);
- get_upload_pack_config(&data);
+ get_upload_pack_config(the_repository, &data);
data.stateless_rpc = stateless_rpc;
data.timeout = timeout;
if (data.timeout)
data.daemon_mode = 1;
- head_ref_namespaced(find_symref, &data.symref);
+ refs_head_ref_namespaced(get_main_ref_store(the_repository),
+ find_symref, &data.symref);
if (advertise_refs || !data.stateless_rpc) {
reset_timeout(data.timeout);
if (advertise_refs)
data.no_done = 1;
- head_ref_namespaced(send_ref, &data);
+ refs_head_ref_namespaced(get_main_ref_store(the_repository),
+ send_ref, &data);
for_each_namespaced_ref_1(send_ref, &data);
if (!data.sent_capabilities) {
const char *refname = "capabilities^{}";
@@ -1430,7 +1455,8 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
advertise_shallow_grafts(1);
packet_flush(1);
} else {
- head_ref_namespaced(check_ref, &data);
+ refs_head_ref_namespaced(get_main_ref_store(the_repository),
+ check_ref, &data);
for_each_namespaced_ref_1(check_ref, &data);
}
@@ -1473,7 +1499,8 @@ static int parse_want(struct packet_writer *writer, const char *line,
"expected to get oid, not '%s'", line);
o = parse_object_with_flags(the_repository, &oid,
- PARSE_OBJECT_SKIP_HASH_CHECK);
+ PARSE_OBJECT_SKIP_HASH_CHECK |
+ PARSE_OBJECT_DISCARD_TREE);
if (!o) {
packet_writer_error(writer,
@@ -1495,27 +1522,29 @@ 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 strmap *wanted_refs,
struct strvec *hidden_refs,
struct object_array *want_obj)
{
const char *refname_nons;
if (skip_prefix(line, "want-ref ", &refname_nons)) {
struct object_id oid;
- struct string_list_item *item;
struct object *o = NULL;
struct strbuf refname = STRBUF_INIT;
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
if (ref_is_hidden(refname_nons, refname.buf, hidden_refs) ||
- read_ref(refname.buf, &oid)) {
+ refs_read_ref(get_main_ref_store(the_repository), refname.buf, &oid)) {
packet_writer_error(writer, "unknown ref %s", refname_nons);
die("unknown ref %s", refname_nons);
}
strbuf_release(&refname);
- item = string_list_append(wanted_refs, refname_nons);
- item->util = oiddup(&oid);
+ if (strmap_put(wanted_refs, refname_nons, oiddup(&oid))) {
+ packet_writer_error(writer, "duplicate want-ref %s",
+ refname_nons);
+ die("duplicate want-ref %s", refname_nons);
+ }
if (!starts_with(refname_nons, "refs/tags/")) {
struct commit *commit = lookup_commit_in_graph(the_repository, &oid);
@@ -1537,21 +1566,44 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
return 0;
}
-static int parse_have(const char *line, struct oid_array *haves)
+static int parse_have(const char *line, struct upload_pack_data *data)
{
const char *arg;
if (skip_prefix(line, "have ", &arg)) {
struct object_id oid;
- if (get_oid_hex(arg, &oid))
- die("git upload-pack: expected SHA1 object, got '%s'", arg);
- oid_array_append(haves, &oid);
+ got_oid(data, arg, &oid);
+ data->seen_haves = 1;
return 1;
}
return 0;
}
+static void trace2_fetch_info(struct upload_pack_data *data)
+{
+ struct json_writer jw = JSON_WRITER_INIT;
+
+ jw_object_begin(&jw, 0);
+ jw_object_intmax(&jw, "haves", data->have_obj.nr);
+ jw_object_intmax(&jw, "wants", data->want_obj.nr);
+ jw_object_intmax(&jw, "want-refs", strmap_get_size(&data->wanted_refs));
+ jw_object_intmax(&jw, "depth", data->depth);
+ jw_object_intmax(&jw, "shallows", data->shallows.nr);
+ jw_object_bool(&jw, "deepen-since", data->deepen_since);
+ jw_object_intmax(&jw, "deepen-not", oidset_size(&data->deepen_not));
+ jw_object_bool(&jw, "deepen-relative", data->deepen_relative);
+ if (data->filter_options.choice)
+ jw_object_string(&jw, "filter", list_object_filter_config_name(data->filter_options.choice));
+ else
+ jw_object_null(&jw, "filter");
+ jw_end(&jw);
+
+ trace2_data_json("upload-pack", the_repository, "fetch-info", &jw);
+
+ jw_release(&jw);
+}
+
static void process_args(struct packet_reader *request,
struct upload_pack_data *data)
{
@@ -1567,7 +1619,7 @@ static void process_args(struct packet_reader *request,
&data->hidden_refs, &data->want_obj))
continue;
/* process have line */
- if (parse_have(arg, &data->haves))
+ if (parse_have(arg, data))
continue;
/* process args like thin-pack */
@@ -1619,14 +1671,17 @@ static void process_args(struct packet_reader *request,
continue;
}
- if ((git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
- data->allow_sideband_all) &&
+ if (data->allow_sideband_all &&
!strcmp(arg, "sideband-all")) {
data->writer.use_sideband = 1;
continue;
}
- if (skip_prefix(arg, "packfile-uris ", &p)) {
+ if (data->allow_packfile_uris &&
+ skip_prefix(arg, "packfile-uris ", &p)) {
+ if (data->uri_protocols.nr)
+ send_err_and_die(data,
+ "multiple packfile-uris lines forbidden");
string_list_split(&data->uri_protocols, p, ',', -1);
continue;
}
@@ -1640,29 +1695,12 @@ static void process_args(struct packet_reader *request,
if (request->status != PACKET_READ_FLUSH)
die(_("expected flush after fetch arguments"));
-}
-
-static int process_haves(struct upload_pack_data *data, struct oid_array *common)
-{
- int i;
-
- /* Process haves */
- for (i = 0; i < data->haves.nr; i++) {
- const struct object_id *oid = &data->haves.oid[i];
-
- if (!repo_has_object_file_with_flags(the_repository, oid,
- OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
- continue;
-
- oid_array_append(common, oid);
-
- do_got_oid(data, oid);
- }
- return 0;
+ if (trace2_is_enabled())
+ trace2_fetch_info(data);
}
-static int send_acks(struct upload_pack_data *data, struct oid_array *acks)
+static int send_acks(struct upload_pack_data *data, struct object_array *acks)
{
int i;
@@ -1674,7 +1712,7 @@ static int send_acks(struct upload_pack_data *data, struct oid_array *acks)
for (i = 0; i < acks->nr; i++) {
packet_writer_write(&data->writer, "ACK %s\n",
- oid_to_hex(&acks->oid[i]));
+ oid_to_hex(&acks->objects[i].item->oid));
}
if (!data->wait_for_done && ok_to_give_up(data)) {
@@ -1688,13 +1726,11 @@ static int send_acks(struct upload_pack_data *data, struct oid_array *acks)
static int process_haves_and_send_acks(struct upload_pack_data *data)
{
- struct oid_array common = OID_ARRAY_INIT;
int ret = 0;
- process_haves(data, &common);
if (data->done) {
ret = 1;
- } else if (send_acks(data, &common)) {
+ } else if (send_acks(data, &data->have_obj)) {
packet_writer_delim(&data->writer);
ret = 1;
} else {
@@ -1703,24 +1739,23 @@ static int process_haves_and_send_acks(struct upload_pack_data *data)
ret = 0;
}
- oid_array_clear(&data->haves);
- oid_array_clear(&common);
return ret;
}
static void send_wanted_ref_info(struct upload_pack_data *data)
{
- const struct string_list_item *item;
+ struct hashmap_iter iter;
+ const struct strmap_entry *e;
- if (!data->wanted_refs.nr)
+ if (strmap_empty(&data->wanted_refs))
return;
packet_writer_write(&data->writer, "wanted-refs\n");
- for_each_string_list_item(item, &data->wanted_refs) {
+ strmap_for_each_entry(&data->wanted_refs, &iter, e) {
packet_writer_write(&data->writer, "%s %s\n",
- oid_to_hex(item->util),
- item->string);
+ oid_to_hex(e->value),
+ e->key);
}
packet_writer_delim(&data->writer);
@@ -1749,7 +1784,7 @@ enum fetch_state {
FETCH_DONE,
};
-int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
+int upload_pack_v2(struct repository *r, struct packet_reader *request)
{
enum fetch_state state = FETCH_PROCESS_ARGS;
struct upload_pack_data data;
@@ -1758,7 +1793,7 @@ int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
upload_pack_data_init(&data);
data.use_sideband = LARGE_PACKET_MAX;
- get_upload_pack_config(&data);
+ get_upload_pack_config(r, &data);
while (state != FETCH_DONE) {
switch (state) {
@@ -1774,7 +1809,7 @@ int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
* they didn't want anything.
*/
state = FETCH_DONE;
- } else if (data.haves.nr) {
+ } else if (data.seen_haves) {
/*
* Request had 'have' lines, so lets ACK them.
*/
@@ -1782,7 +1817,7 @@ int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
} else {
/*
* Request had 'want's but no 'have's so we can
- * immedietly go to construct and send a pack.
+ * immediately go to construct and send a pack.
*/
state = FETCH_SEND_PACK;
}
@@ -1817,41 +1852,28 @@ int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
int upload_pack_advertise(struct repository *r,
struct strbuf *value)
{
- if (value) {
- int allow_filter_value;
- int allow_ref_in_want;
- int allow_sideband_all_value;
- char *str = NULL;
+ struct upload_pack_data data;
+
+ upload_pack_data_init(&data);
+ get_upload_pack_config(r, &data);
+ if (value) {
strbuf_addstr(value, "shallow wait-for-done");
- if (!repo_config_get_bool(r,
- "uploadpack.allowfilter",
- &allow_filter_value) &&
- allow_filter_value)
+ if (data.allow_filter)
strbuf_addstr(value, " filter");
- if (!repo_config_get_bool(r,
- "uploadpack.allowrefinwant",
- &allow_ref_in_want) &&
- allow_ref_in_want)
+ if (data.allow_ref_in_want)
strbuf_addstr(value, " ref-in-want");
- if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
- (!repo_config_get_bool(r,
- "uploadpack.allowsidebandall",
- &allow_sideband_all_value) &&
- allow_sideband_all_value))
+ if (data.allow_sideband_all)
strbuf_addstr(value, " sideband-all");
- if (!repo_config_get_string(r,
- "uploadpack.blobpackfileuri",
- &str) &&
- str) {
+ if (data.allow_packfile_uris)
strbuf_addstr(value, " packfile-uris");
- free(str);
- }
}
+ upload_pack_data_clear(&data);
+
return 1;
}
diff --git a/url.c b/url.c
index 2e1a9f6fee..282b12495a 100644
--- a/url.c
+++ b/url.c
@@ -1,5 +1,5 @@
#include "git-compat-util.h"
-#include "hex.h"
+#include "hex-ll.h"
#include "strbuf.h"
#include "url.h"
diff --git a/urlmatch.c b/urlmatch.c
index 1c45f23adf..1d0254abac 100644
--- a/urlmatch.c
+++ b/urlmatch.c
@@ -1,6 +1,6 @@
#include "git-compat-util.h"
#include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
#include "strbuf.h"
#include "urlmatch.h"
diff --git a/usage.c b/usage.c
index 09f0ed509b..29a9725784 100644
--- a/usage.c
+++ b/usage.c
@@ -19,8 +19,11 @@ static void vreportf(const char *prefix, const char *err, va_list params)
}
memcpy(msg, prefix, prefix_len);
p = msg + prefix_len;
- if (vsnprintf(p, pend - p, err, params) < 0)
+ if (vsnprintf(p, pend - p, err, params) < 0) {
+ fprintf(stderr, _("error: unable to format message: %s\n"),
+ err);
*p = '\0'; /* vsnprintf() failed, clip at prefix */
+ }
for (; p != pend - 1 && *p; p++) {
if (iscntrl(*p) && *p != '\t' && *p != '\n')
@@ -347,18 +350,3 @@ void bug_fl(const char *file, int line, const char *fmt, ...)
trace2_cmd_error_va(fmt, ap);
va_end(ap);
}
-
-#ifdef SUPPRESS_ANNOTATED_LEAKS
-void unleak_memory(const void *ptr, size_t len)
-{
- static struct suppressed_leak_root {
- struct suppressed_leak_root *next;
- char data[FLEX_ARRAY];
- } *suppressed_leaks;
- struct suppressed_leak_root *root;
-
- FLEX_ALLOC_MEM(root, data, ptr, len);
- root->next = suppressed_leaks;
- suppressed_leaks = root;
-}
-#endif
diff --git a/userdiff.c b/userdiff.c
index e399543823..d43d8360d1 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -1,8 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "userdiff.h"
#include "attr.h"
#include "strbuf.h"
+#include "environment.h"
static struct userdiff_driver *drivers;
static int ndrivers;
@@ -89,12 +92,48 @@ PATTERNS("cpp",
"|\\.[0-9][0-9]*([Ee][-+]?[0-9]+)?[fFlL]?"
"|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*|<=>"),
PATTERNS("csharp",
- /* Keywords */
- "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n"
- /* Methods and constructors */
- "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe|async)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[<>@._[:alnum:]]+[ \t]*\\(.*\\))[ \t]*$\n"
- /* Properties */
- "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[@._[:alnum:]]+)[ \t]*$\n"
+ /*
+ * Jump over reserved keywords which are illegal method names, but which
+ * can be followed by parentheses without special characters in between,
+ * making them look like methods.
+ */
+ "!(^|[ \t]+)" /* Start of line or whitespace. */
+ "(do|while|for|foreach|if|else|new|default|return|switch|case|throw"
+ "|catch|using|lock|fixed)"
+ "([ \t(]+|$)\n" /* Whitespace, "(", or end of line. */
+ /*
+ * Methods/constructors:
+ * The strategy is to identify a minimum of two groups (any combination
+ * of keywords/type/name) before the opening parenthesis, and without
+ * final unexpected characters, normally only used in ordinary statements.
+ */
+ "^[ \t]*" /* Remove leading whitespace. */
+ "(" /* Start chunk header capture. */
+ "(" /* First group. */
+ "[][[:alnum:]@_.]" /* Name. */
+ "(<[][[:alnum:]@_, \t<>]+>)?" /* Optional generic parameters. */
+ ")+"
+ "([ \t]+" /* Subsequent groups, prepended with space. */
+ "([][[:alnum:]@_.](<[][[:alnum:]@_, \t<>]+>)?)+"
+ ")+"
+ "[ \t]*" /* Optional space before parameters start. */
+ "\\(" /* Start of method parameters. */
+ "[^;]*" /* Allow complex parameters, but exclude statements (;). */
+ ")$\n" /* Close chunk header capture. */
+ /*
+ * Properties:
+ * As with methods, expect a minimum of two groups. But, more trivial than
+ * methods, the vast majority of properties long enough to be worth
+ * showing a chunk header for don't include "=:;,()" on the line they are
+ * defined, since they don't have a parameter list.
+ */
+ "^[ \t]*("
+ "([][[:alnum:]@_.](<[][[:alnum:]@_, \t<>]+>)?)+"
+ "([ \t]+"
+ "([][[:alnum:]@_.](<[][[:alnum:]@_, \t<>]+>)?)+"
+ ")+" /* Up to here, same as methods regex. */
+ "[^;=:,()]*" /* Compared to methods, no parameter list allowed. */
+ ")$\n"
/* Type definitions */
"^[ \t]*(((static|public|internal|private|protected|new|unsafe|sealed|abstract|partial)[ \t]+)*(class|enum|interface|struct|record)[ \t]+.*)$\n"
/* Namespace */
@@ -296,7 +335,7 @@ PATTERNS("scheme",
"|([^][)(}{[ \t])+"),
PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
"\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"),
-{ "default", NULL, NULL, -1, { NULL, 0 } },
+{ .name = "default", .binary = -1 },
};
#undef PATTERNS
#undef IPATTERN
@@ -323,8 +362,7 @@ static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver,
{
struct find_by_namelen_data *cb_data = priv;
- if (!strncmp(driver->name, cb_data->name, cb_data->len) &&
- !driver->name[cb_data->len]) {
+ if (!xstrncmpz(driver->name, cb_data->name, cb_data->len)) {
cb_data->driver = driver;
return 1; /* tell the caller to stop iterating */
}
@@ -363,8 +401,11 @@ static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t
static int parse_funcname(struct userdiff_funcname *f, const char *k,
const char *v, int cflags)
{
- if (git_config_string(&f->pattern, k, v) < 0)
+ f->pattern = NULL;
+ FREE_AND_NULL(f->pattern_owned);
+ if (git_config_string(&f->pattern_owned, k, v) < 0)
return -1;
+ f->pattern = f->pattern_owned;
f->cflags = cflags;
return 0;
}
@@ -408,16 +449,37 @@ int userdiff_config(const char *k, const char *v)
return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
if (!strcmp(type, "binary"))
return parse_tristate(&drv->binary, k, v);
- if (!strcmp(type, "command"))
- return git_config_string(&drv->external, k, v);
- if (!strcmp(type, "textconv"))
- return git_config_string(&drv->textconv, k, v);
+ if (!strcmp(type, "command")) {
+ FREE_AND_NULL(drv->external.cmd);
+ return git_config_string(&drv->external.cmd, k, v);
+ }
+ if (!strcmp(type, "trustexitcode")) {
+ drv->external.trust_exit_code = git_config_bool(k, v);
+ return 0;
+ }
+ if (!strcmp(type, "textconv")) {
+ int ret;
+ FREE_AND_NULL(drv->textconv_owned);
+ ret = git_config_string(&drv->textconv_owned, k, v);
+ drv->textconv = drv->textconv_owned;
+ return ret;
+ }
if (!strcmp(type, "cachetextconv"))
return parse_bool(&drv->textconv_want_cache, k, v);
- if (!strcmp(type, "wordregex"))
- return git_config_string(&drv->word_regex, k, v);
- if (!strcmp(type, "algorithm"))
- return git_config_string(&drv->algorithm, k, v);
+ if (!strcmp(type, "wordregex")) {
+ int ret;
+ FREE_AND_NULL(drv->word_regex_owned);
+ ret = git_config_string(&drv->word_regex_owned, k, v);
+ drv->word_regex = drv->word_regex_owned;
+ return ret;
+ }
+ if (!strcmp(type, "algorithm")) {
+ int ret;
+ FREE_AND_NULL(drv->algorithm_owned);
+ ret = git_config_string(&drv->algorithm_owned, k, v);
+ drv->algorithm = drv->algorithm_owned;
+ return ret;
+ }
return 0;
}
@@ -460,7 +522,8 @@ struct userdiff_driver *userdiff_get_textconv(struct repository *r,
if (!driver->textconv)
return NULL;
- if (driver->textconv_want_cache && !driver->textconv_cache) {
+ if (driver->textconv_want_cache && !driver->textconv_cache &&
+ have_git_dir()) {
struct notes_cache *c = xmalloc(sizeof(*c));
struct strbuf name = STRBUF_INIT;
diff --git a/userdiff.h b/userdiff.h
index d726804c3e..827361b0bc 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -8,18 +8,27 @@ struct repository;
struct userdiff_funcname {
const char *pattern;
+ char *pattern_owned;
int cflags;
};
+struct external_diff {
+ char *cmd;
+ unsigned trust_exit_code:1;
+};
+
struct userdiff_driver {
const char *name;
- const char *external;
+ struct external_diff external;
const char *algorithm;
+ char *algorithm_owned;
int binary;
struct userdiff_funcname funcname;
const char *word_regex;
+ char *word_regex_owned;
const char *word_regex_multi_byte;
const char *textconv;
+ char *textconv_owned;
struct notes_cache *textconv_cache;
int textconv_want_cache;
};
diff --git a/utf8.c b/utf8.c
index 6a0dd25b0f..6bfaefa28e 100644
--- a/utf8.c
+++ b/utf8.c
@@ -2,7 +2,7 @@
#include "strbuf.h"
#include "utf8.h"
-/* This code is originally from http://www.cl.cam.ac.uk/~mgk25/ucs/ */
+/* This code is originally from https://www.cl.cam.ac.uk/~mgk25/ucs/ */
static const char utf16_be_bom[] = {'\xFE', '\xFF'};
static const char utf16_le_bom[] = {'\xFF', '\xFE'};
diff --git a/utf8.h b/utf8.h
index b68efef6f4..cf8ecb0f21 100644
--- a/utf8.h
+++ b/utf8.h
@@ -33,8 +33,9 @@ char *reencode_string_len(const char *in, size_t insz,
const char *in_encoding,
size_t *outsz);
#else
-static inline char *reencode_string_len(const char *a, size_t b,
- const char *c, const char *d, size_t *e)
+static inline char *reencode_string_len(const char *a UNUSED, size_t b UNUSED,
+ const char *c UNUSED,
+ const char *d UNUSED, size_t *e)
{ if (e) *e = 0; return NULL; }
#endif
@@ -83,7 +84,7 @@ void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int wid
* BOM must not be used [1]. The same applies for the UTF-32 equivalents.
* The function returns true if this rule is violated.
*
- * [1] http://unicode.org/faq/utf_bom.html#bom10
+ * [1] https://unicode.org/faq/utf_bom.html#bom10
*/
int has_prohibited_utf_bom(const char *enc, const char *data, size_t len);
@@ -99,8 +100,8 @@ int has_prohibited_utf_bom(const char *enc, const char *data, size_t len);
* Therefore, strictly requiring a BOM seems to be the safest option for
* content in Git.
*
- * [1] http://unicode.org/faq/utf_bom.html#gen6
- * [2] http://www.unicode.org/versions/Unicode10.0.0/ch03.pdf
+ * [1] https://unicode.org/faq/utf_bom.html#gen6
+ * [2] https://www.unicode.org/versions/Unicode10.0.0/ch03.pdf
* Section 3.10, D98, page 132
* [3] https://encoding.spec.whatwg.org/#utf-16le
*/
diff --git a/versioncmp.c b/versioncmp.c
index 45e676cbca..e3b2a6e330 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "strbuf.h"
diff --git a/walker.c b/walker.c
index 65002a7220..7cc9dbea46 100644
--- a/walker.c
+++ b/walker.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "hex.h"
@@ -45,7 +47,7 @@ static int process_tree(struct walker *walker, struct tree *tree)
if (parse_tree(tree))
return -1;
- init_tree_desc(&desc, tree->buffer, tree->size);
+ init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
struct object *obj = NULL;
@@ -155,7 +157,7 @@ static int process(struct walker *walker, struct object *obj)
else {
if (obj->flags & COMPLETE)
return 0;
- walker->prefetch(walker, obj->oid.hash);
+ walker->prefetch(walker, &obj->oid);
}
object_list_insert(obj, process_queue_end);
@@ -184,7 +186,7 @@ static int loop(struct walker *walker)
* the queue because we needed to fetch it first.
*/
if (! (obj->flags & TO_SCAN)) {
- if (walker->fetch(walker, obj->oid.hash)) {
+ if (walker->fetch(walker, &obj->oid)) {
stop_progress(&progress);
report_missing(obj);
return -1;
@@ -219,6 +221,7 @@ static int interpret_target(struct walker *walker, char *target, struct object_i
}
static int mark_complete(const char *path UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
@@ -286,7 +289,8 @@ int walker_fetch(struct walker *walker, int targets, char **target,
ALLOC_ARRAY(oids, targets);
if (write_ref) {
- transaction = ref_transaction_begin(&err);
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
if (!transaction) {
error("%s", err.buf);
goto done;
@@ -294,7 +298,8 @@ int walker_fetch(struct walker *walker, int targets, char **target,
}
if (!walker->get_recover) {
- for_each_ref(mark_complete, NULL);
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ mark_complete, NULL);
commit_list_sort_by_date(&complete);
}
@@ -324,7 +329,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
strbuf_reset(&refname);
strbuf_addf(&refname, "refs/%s", write_ref[i]);
if (ref_transaction_update(transaction, refname.buf,
- oids + i, NULL, 0,
+ oids + i, NULL, NULL, NULL, 0,
msg ? msg : "fetch (unknown)",
&err)) {
error("%s", err.buf);
diff --git a/walker.h b/walker.h
index d40b016bab..25aaa3631c 100644
--- a/walker.h
+++ b/walker.h
@@ -6,8 +6,8 @@
struct walker {
void *data;
int (*fetch_ref)(struct walker *, struct ref *ref);
- void (*prefetch)(struct walker *, unsigned char *sha1);
- int (*fetch)(struct walker *, unsigned char *sha1);
+ void (*prefetch)(struct walker *, const struct object_id *oid);
+ int (*fetch)(struct walker *, const struct object_id *oid);
void (*cleanup)(struct walker *);
int get_verbosely;
int get_progress;
diff --git a/worktree.c b/worktree.c
index b8cf29e6a1..77ff484d3e 100644
--- a/worktree.c
+++ b/worktree.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "environment.h"
@@ -12,18 +14,23 @@
#include "wt-status.h"
#include "config.h"
+void free_worktree(struct worktree *worktree)
+{
+ if (!worktree)
+ return;
+ free(worktree->path);
+ free(worktree->id);
+ free(worktree->head_ref);
+ free(worktree->lock_reason);
+ free(worktree->prune_reason);
+ free(worktree);
+}
+
void free_worktrees(struct worktree **worktrees)
{
int i = 0;
-
- for (i = 0; worktrees[i]; i++) {
- free(worktrees[i]->path);
- free(worktrees[i]->id);
- free(worktrees[i]->head_ref);
- free(worktrees[i]->lock_reason);
- free(worktrees[i]->prune_reason);
- free(worktrees[i]);
- }
+ for (i = 0; worktrees[i]; i++)
+ free_worktree(worktrees[i]);
free (worktrees);
}
@@ -48,18 +55,28 @@ static void add_head_info(struct worktree *wt)
wt->is_detached = 1;
}
+static int is_current_worktree(struct worktree *wt)
+{
+ char *git_dir = absolute_pathdup(repo_get_git_dir(the_repository));
+ const char *wt_git_dir = get_worktree_git_dir(wt);
+ int is_current = !fspathcmp(git_dir, absolute_path(wt_git_dir));
+ free(git_dir);
+ return is_current;
+}
+
/**
* get the main worktree
*/
-static struct worktree *get_main_worktree(void)
+static struct worktree *get_main_worktree(int skip_reading_head)
{
struct worktree *worktree = NULL;
struct strbuf worktree_path = STRBUF_INIT;
- strbuf_add_real_path(&worktree_path, get_git_common_dir());
+ strbuf_add_real_path(&worktree_path, repo_get_common_dir(the_repository));
strbuf_strip_suffix(&worktree_path, "/.git");
CALLOC_ARRAY(worktree, 1);
+ worktree->repo = the_repository;
worktree->path = strbuf_detach(&worktree_path, NULL);
/*
* NEEDSWORK: If this function is called from a secondary worktree and
@@ -70,11 +87,14 @@ static struct worktree *get_main_worktree(void)
*/
worktree->is_bare = (is_bare_repository_cfg == 1) ||
is_bare_repository();
- add_head_info(worktree);
+ worktree->is_current = is_current_worktree(worktree);
+ if (!skip_reading_head)
+ add_head_info(worktree);
return worktree;
}
-static struct worktree *get_linked_worktree(const char *id)
+struct worktree *get_linked_worktree(const char *id,
+ int skip_reading_head)
{
struct worktree *worktree = NULL;
struct strbuf path = STRBUF_INIT;
@@ -90,10 +110,19 @@ static struct worktree *get_linked_worktree(const char *id)
strbuf_rtrim(&worktree_path);
strbuf_strip_suffix(&worktree_path, "/.git");
+ if (!is_absolute_path(worktree_path.buf)) {
+ strbuf_strip_suffix(&path, "gitdir");
+ strbuf_addbuf(&path, &worktree_path);
+ strbuf_realpath_forgiving(&worktree_path, path.buf, 0);
+ }
+
CALLOC_ARRAY(worktree, 1);
+ worktree->repo = the_repository;
worktree->path = strbuf_detach(&worktree_path, NULL);
worktree->id = xstrdup(id);
- add_head_info(worktree);
+ worktree->is_current = is_current_worktree(worktree);
+ if (!skip_reading_head)
+ add_head_info(worktree);
done:
strbuf_release(&path);
@@ -101,24 +130,14 @@ done:
return worktree;
}
-static void mark_current_worktree(struct worktree **worktrees)
-{
- char *git_dir = absolute_pathdup(get_git_dir());
- int i;
-
- for (i = 0; worktrees[i]; i++) {
- struct worktree *wt = worktrees[i];
- const char *wt_git_dir = get_worktree_git_dir(wt);
-
- if (!fspathcmp(git_dir, absolute_path(wt_git_dir))) {
- wt->is_current = 1;
- break;
- }
- }
- free(git_dir);
-}
-
-struct worktree **get_worktrees(void)
+/*
+ * NEEDSWORK: This function exists so that we can look up metadata of a
+ * worktree without trying to access any of its internals like the refdb. It
+ * would be preferable to instead have a corruption-tolerant function for
+ * retrieving worktree metadata that could be used when the worktree is known
+ * to not be in a healthy state, e.g. when creating or repairing it.
+ */
+static struct worktree **get_worktrees_internal(int skip_reading_head)
{
struct worktree **list = NULL;
struct strbuf path = STRBUF_INIT;
@@ -128,16 +147,16 @@ struct worktree **get_worktrees(void)
ALLOC_ARRAY(list, alloc);
- list[counter++] = get_main_worktree();
+ list[counter++] = get_main_worktree(skip_reading_head);
- strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+ strbuf_addf(&path, "%s/worktrees", repo_get_common_dir(the_repository));
dir = opendir(path.buf);
strbuf_release(&path);
if (dir) {
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
struct worktree *linked = NULL;
- if ((linked = get_linked_worktree(d->d_name))) {
+ if ((linked = get_linked_worktree(d->d_name, skip_reading_head))) {
ALLOC_GROW(list, counter + 1, alloc);
list[counter++] = linked;
}
@@ -147,16 +166,20 @@ struct worktree **get_worktrees(void)
ALLOC_GROW(list, counter + 1, alloc);
list[counter] = NULL;
- mark_current_worktree(list);
return list;
}
+struct worktree **get_worktrees(void)
+{
+ return get_worktrees_internal(0);
+}
+
const char *get_worktree_git_dir(const struct worktree *wt)
{
if (!wt)
- return get_git_dir();
+ return repo_get_git_dir(the_repository);
else if (!wt->id)
- return get_git_common_dir();
+ return repo_get_common_dir(the_repository);
else
return git_common_path("worktrees/%s", wt->id);
}
@@ -235,7 +258,7 @@ const char *worktree_lock_reason(struct worktree *wt)
if (!wt->lock_reason_valid) {
struct strbuf path = STRBUF_INIT;
- strbuf_addstr(&path, worktree_git_path(wt, "locked"));
+ strbuf_addstr(&path, worktree_git_path(the_repository, wt, "locked"));
if (file_exists(path.buf)) {
struct strbuf lock_reason = STRBUF_INIT;
if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
@@ -356,18 +379,29 @@ done:
void update_worktree_location(struct worktree *wt, const char *path_)
{
struct strbuf path = STRBUF_INIT;
+ struct strbuf repo = STRBUF_INIT;
+ struct strbuf file = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
if (is_main_worktree(wt))
BUG("can't relocate main worktree");
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
strbuf_realpath(&path, path_, 1);
if (fspathcmp(wt->path, path.buf)) {
- write_file(git_common_path("worktrees/%s/gitdir", wt->id),
- "%s/.git", path.buf);
+ strbuf_addf(&file, "%s/gitdir", repo.buf);
+ write_file(file.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp));
+ strbuf_reset(&file);
+ strbuf_addf(&file, "%s/.git", path.buf);
+ write_file(file.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
+
free(wt->path);
wt->path = strbuf_detach(&path, NULL);
}
strbuf_release(&path);
+ strbuf_release(&repo);
+ strbuf_release(&file);
+ strbuf_release(&tmp);
}
int is_worktree_being_rebased(const struct worktree *wt,
@@ -395,9 +429,9 @@ int is_worktree_being_bisected(const struct worktree *wt,
memset(&state, 0, sizeof(state));
found_bisect = wt_status_check_bisect(wt, &state) &&
- state.branch &&
+ state.bisecting_from &&
skip_prefix(target, "refs/heads/", &target) &&
- !strcmp(state.branch, target);
+ !strcmp(state.bisecting_from, target);
wt_status_state_free_buffers(&state);
return found_bisect;
}
@@ -529,7 +563,7 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
refname.buf,
RESOLVE_REF_READING,
&oid, &flag))
- ret = fn(refname.buf, &oid, flag, cb_data);
+ ret = fn(refname.buf, NULL, &oid, flag, cb_data);
if (ret)
break;
}
@@ -547,49 +581,65 @@ static void repair_gitfile(struct worktree *wt,
{
struct strbuf dotgit = STRBUF_INIT;
struct strbuf repo = STRBUF_INIT;
- char *backlink;
+ struct strbuf backlink = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
+ char *dotgit_contents = NULL;
const char *repair = NULL;
int err;
/* missing worktree can't be repaired */
if (!file_exists(wt->path))
- return;
+ goto done;
if (!is_directory(wt->path)) {
fn(1, wt->path, _("not a directory"), cb_data);
- return;
+ goto done;
}
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
strbuf_addf(&dotgit, "%s/.git", wt->path);
- backlink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
+ dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
+
+ if (dotgit_contents) {
+ if (is_absolute_path(dotgit_contents)) {
+ strbuf_addstr(&backlink, dotgit_contents);
+ } else {
+ strbuf_addf(&backlink, "%s/%s", wt->path, dotgit_contents);
+ strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
+ }
+ }
if (err == READ_GITFILE_ERR_NOT_A_FILE)
fn(1, wt->path, _(".git is not a file"), cb_data);
else if (err)
repair = _(".git file broken");
- else if (fspathcmp(backlink, repo.buf))
+ else if (fspathcmp(backlink.buf, repo.buf))
repair = _(".git file incorrect");
if (repair) {
fn(0, wt->path, repair, cb_data);
- write_file(dotgit.buf, "gitdir: %s", repo.buf);
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, wt->path, &tmp));
}
- free(backlink);
+done:
+ free(dotgit_contents);
strbuf_release(&repo);
strbuf_release(&dotgit);
+ strbuf_release(&backlink);
+ strbuf_release(&tmp);
}
-static void repair_noop(int iserr, const char *path, const char *msg,
- void *cb_data)
+static void repair_noop(int iserr UNUSED,
+ const char *path UNUSED,
+ const char *msg UNUSED,
+ void *cb_data UNUSED)
{
/* nothing */
}
void repair_worktrees(worktree_repair_fn fn, void *cb_data)
{
- struct worktree **worktrees = get_worktrees();
+ struct worktree **worktrees = get_worktrees_internal(1);
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
if (!fn)
@@ -599,6 +649,59 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data)
free_worktrees(worktrees);
}
+void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path)
+{
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf repo = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
+ struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf olddotgit = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
+
+ if (is_main_worktree(wt))
+ goto done;
+
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
+
+ if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
+ goto done;
+
+ strbuf_rtrim(&olddotgit);
+ if (is_absolute_path(olddotgit.buf)) {
+ strbuf_addbuf(&dotgit, &olddotgit);
+ } else {
+ strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf);
+ strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
+ }
+
+ if (!file_exists(dotgit.buf))
+ goto done;
+
+ strbuf_addbuf(&path, &dotgit);
+ strbuf_strip_suffix(&path, "/.git");
+
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
+ write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp));
+done:
+ strbuf_release(&path);
+ strbuf_release(&repo);
+ strbuf_release(&gitdir);
+ strbuf_release(&dotgit);
+ strbuf_release(&olddotgit);
+ strbuf_release(&tmp);
+}
+
+void repair_worktrees_after_gitdir_move(const char *old_path)
+{
+ struct worktree **worktrees = get_worktrees_internal(1);
+ struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
+
+ for (; *wt; wt++)
+ repair_worktree_after_gitdir_move(*wt, old_path);
+ free_worktrees(worktrees);
+}
+
static int is_main_worktree_path(const char *path)
{
struct strbuf target = STRBUF_INIT;
@@ -607,7 +710,7 @@ static int is_main_worktree_path(const char *path)
strbuf_add_real_path(&target, path);
strbuf_strip_suffix(&target, "/.git");
- strbuf_add_real_path(&maindir, get_git_common_dir());
+ strbuf_add_real_path(&maindir, repo_get_common_dir(the_repository));
strbuf_strip_suffix(&maindir, "/.git");
cmp = fspathcmp(maindir.buf, target.buf);
@@ -623,10 +726,9 @@ static int is_main_worktree_path(const char *path)
* be able to infer the gitdir by manually reading /path/to/worktree/.git,
* extracting the <id>, and checking if <repo>/worktrees/<id> exists.
*/
-static char *infer_backlink(const char *gitfile)
+static int infer_backlink(const char *gitfile, struct strbuf *inferred)
{
struct strbuf actual = STRBUF_INIT;
- struct strbuf inferred = STRBUF_INIT;
const char *id;
if (strbuf_read_file(&actual, gitfile, 0) < 0)
@@ -639,17 +741,18 @@ static char *infer_backlink(const char *gitfile)
id++; /* advance past '/' to point at <id> */
if (!*id)
goto error;
- strbuf_git_common_path(&inferred, the_repository, "worktrees/%s", id);
- if (!is_directory(inferred.buf))
+ strbuf_reset(inferred);
+ strbuf_git_common_path(inferred, the_repository, "worktrees/%s", id);
+ if (!is_directory(inferred->buf))
goto error;
strbuf_release(&actual);
- return strbuf_detach(&inferred, NULL);
+ return 1;
error:
strbuf_release(&actual);
- strbuf_release(&inferred);
- return NULL;
+ strbuf_reset(inferred); /* clear invalid path */
+ return 0;
}
/*
@@ -661,9 +764,13 @@ void repair_worktree_at_path(const char *path,
{
struct strbuf dotgit = STRBUF_INIT;
struct strbuf realdotgit = STRBUF_INIT;
+ struct strbuf backlink = STRBUF_INIT;
+ struct strbuf inferred_backlink = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
struct strbuf olddotgit = STRBUF_INIT;
- char *backlink = NULL;
+ struct strbuf realolddotgit = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
+ char *dotgit_contents = NULL;
const char *repair = NULL;
int err;
@@ -679,115 +786,186 @@ void repair_worktree_at_path(const char *path,
goto done;
}
- backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
- if (err == READ_GITFILE_ERR_NOT_A_FILE) {
+ infer_backlink(realdotgit.buf, &inferred_backlink);
+ strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0);
+ dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
+ if (dotgit_contents) {
+ if (is_absolute_path(dotgit_contents)) {
+ strbuf_addstr(&backlink, dotgit_contents);
+ } else {
+ strbuf_addbuf(&backlink, &realdotgit);
+ strbuf_strip_suffix(&backlink, ".git");
+ strbuf_addstr(&backlink, dotgit_contents);
+ strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
+ }
+ } else if (err == READ_GITFILE_ERR_NOT_A_FILE) {
fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
goto done;
} else if (err == READ_GITFILE_ERR_NOT_A_REPO) {
- if (!(backlink = infer_backlink(realdotgit.buf))) {
+ if (inferred_backlink.len) {
+ /*
+ * Worktree's .git file does not point at a repository
+ * but we found a .git/worktrees/<id> in this
+ * repository with the same <id> as recorded in the
+ * worktree's .git file so make the worktree point at
+ * the discovered .git/worktrees/<id>.
+ */
+ strbuf_swap(&backlink, &inferred_backlink);
+ } else {
fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
goto done;
}
- } else if (err) {
+ } else {
fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
goto done;
}
- strbuf_addf(&gitdir, "%s/gitdir", backlink);
+ /*
+ * If we got this far, either the worktree's .git file pointed at a
+ * valid repository (i.e. read_gitfile_gently() returned success) or
+ * the .git file did not point at a repository but we were able to
+ * infer a suitable new value for the .git file by locating a
+ * .git/worktrees/<id> in *this* repository corresponding to the <id>
+ * recorded in the worktree's .git file.
+ *
+ * However, if, at this point, inferred_backlink is non-NULL (i.e. we
+ * found a suitable .git/worktrees/<id> in *this* repository) *and* the
+ * worktree's .git file points at a valid repository *and* those two
+ * paths differ, then that indicates that the user probably *copied*
+ * the main and linked worktrees to a new location as a unit rather
+ * than *moving* them. Thus, the copied worktree's .git file actually
+ * points at the .git/worktrees/<id> in the *original* repository, not
+ * in the "copy" repository. In this case, point the "copy" worktree's
+ * .git file at the "copy" repository.
+ */
+ if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) {
+ strbuf_swap(&backlink, &inferred_backlink);
+ }
+
+ strbuf_addf(&gitdir, "%s/gitdir", backlink.buf);
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
repair = _("gitdir unreadable");
else {
strbuf_rtrim(&olddotgit);
- if (fspathcmp(olddotgit.buf, realdotgit.buf))
+ if (is_absolute_path(olddotgit.buf)) {
+ strbuf_addbuf(&realolddotgit, &olddotgit);
+ } else {
+ strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf);
+ strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0);
+ }
+ if (fspathcmp(realolddotgit.buf, realdotgit.buf))
repair = _("gitdir incorrect");
}
if (repair) {
fn(0, gitdir.buf, repair, cb_data);
- write_file(gitdir.buf, "%s", realdotgit.buf);
+ write_file(gitdir.buf, "%s", relative_path(realdotgit.buf, backlink.buf, &tmp));
}
done:
- free(backlink);
+ free(dotgit_contents);
strbuf_release(&olddotgit);
+ strbuf_release(&realolddotgit);
+ strbuf_release(&backlink);
+ strbuf_release(&inferred_backlink);
strbuf_release(&gitdir);
strbuf_release(&realdotgit);
strbuf_release(&dotgit);
+ strbuf_release(&tmp);
}
int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire)
{
struct stat st;
- char *path;
+ struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
+ struct strbuf repo = STRBUF_INIT;
+ struct strbuf file = STRBUF_INIT;
+ char *path = NULL;
+ int rc = 0;
int fd;
size_t len;
ssize_t read_result;
*wtpath = NULL;
- if (!is_directory(git_path("worktrees/%s", id))) {
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", id), 1);
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
+ if (!is_directory(repo.buf)) {
strbuf_addstr(reason, _("not a valid directory"));
- return 1;
+ rc = 1;
+ goto done;
}
- if (file_exists(git_path("worktrees/%s/locked", id)))
- return 0;
- if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
+ strbuf_addf(&file, "%s/locked", repo.buf);
+ if (file_exists(file.buf)) {
+ goto done;
+ }
+ if (stat(gitdir.buf, &st)) {
strbuf_addstr(reason, _("gitdir file does not exist"));
- return 1;
+ rc = 1;
+ goto done;
}
- fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
+ fd = open(gitdir.buf, O_RDONLY);
if (fd < 0) {
strbuf_addf(reason, _("unable to read gitdir file (%s)"),
strerror(errno));
- return 1;
+ rc = 1;
+ goto done;
}
len = xsize_t(st.st_size);
path = xmallocz(len);
read_result = read_in_full(fd, path, len);
+ close(fd);
if (read_result < 0) {
strbuf_addf(reason, _("unable to read gitdir file (%s)"),
strerror(errno));
- close(fd);
- free(path);
- return 1;
- }
- close(fd);
-
- if (read_result != len) {
+ rc = 1;
+ goto done;
+ } else if (read_result != len) {
strbuf_addf(reason,
_("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
(uintmax_t)len, (uintmax_t)read_result);
- free(path);
- return 1;
+ rc = 1;
+ goto done;
}
while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
len--;
if (!len) {
strbuf_addstr(reason, _("invalid gitdir file"));
- free(path);
- return 1;
+ rc = 1;
+ goto done;
}
path[len] = '\0';
- if (!file_exists(path)) {
- if (stat(git_path("worktrees/%s/index", id), &st) ||
- st.st_mtime <= expire) {
+ if (is_absolute_path(path)) {
+ strbuf_addstr(&dotgit, path);
+ } else {
+ strbuf_addf(&dotgit, "%s/%s", repo.buf, path);
+ strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
+ }
+ if (!file_exists(dotgit.buf)) {
+ strbuf_reset(&file);
+ strbuf_addf(&file, "%s/index", repo.buf);
+ if (stat(file.buf, &st) || st.st_mtime <= expire) {
strbuf_addstr(reason, _("gitdir file points to non-existent location"));
- free(path);
- return 1;
- } else {
- *wtpath = path;
- return 0;
+ rc = 1;
+ goto done;
}
}
- *wtpath = path;
- return 0;
+ *wtpath = strbuf_detach(&dotgit, NULL);
+done:
+ free(path);
+ strbuf_release(&dotgit);
+ strbuf_release(&gitdir);
+ strbuf_release(&repo);
+ strbuf_release(&file);
+ return rc;
}
static int move_config_setting(const char *key, const char *value,
const char *from_file, const char *to_file)
{
- if (git_config_set_in_file_gently(to_file, key, value))
+ if (git_config_set_in_file_gently(to_file, key, NULL, value))
return error(_("unable to set %s in '%s'"), key, to_file);
- if (git_config_set_in_file_gently(from_file, key, NULL))
+ if (git_config_set_in_file_gently(from_file, key, NULL, NULL))
return error(_("unable to unset %s in '%s'"), key, from_file);
return 0;
}
diff --git a/worktree.h b/worktree.h
index ce45b66de9..e961186216 100644
--- a/worktree.h
+++ b/worktree.h
@@ -6,6 +6,8 @@
struct strbuf;
struct worktree {
+ /* The repository this worktree belongs to. */
+ struct repository *repo;
char *path;
char *id;
char *head_ref; /* NULL if HEAD is broken or detached */
@@ -58,6 +60,13 @@ struct worktree *find_worktree(struct worktree **list,
const char *arg);
/*
+ * Look up the worktree corresponding to `id`, or NULL of no such worktree
+ * exists.
+ */
+struct worktree *get_linked_worktree(const char *id,
+ int skip_reading_head);
+
+/*
* Return the worktree corresponding to `path`, or NULL if no such worktree
* exists.
*/
@@ -123,6 +132,16 @@ typedef void (* worktree_repair_fn)(int iserr, const char *path,
void repair_worktrees(worktree_repair_fn, void *cb_data);
/*
+ * Repair the linked worktrees after the gitdir has been moved.
+ */
+void repair_worktrees_after_gitdir_move(const char *old_path);
+
+/*
+ * Repair the linked worktree after the gitdir has been moved.
+ */
+void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path);
+
+/*
* Repair administrative files corresponding to the worktree at the given path.
* The worktree's .git file pointing at the repository must be intact for the
* repair to succeed. Useful for re-associating an orphaned worktree with the
@@ -135,6 +154,11 @@ void repair_worktrees(worktree_repair_fn, void *cb_data);
void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
/*
+ * Free up the memory for a worktree.
+ */
+void free_worktree(struct worktree *);
+
+/*
* Free up the memory for worktree(s)
*/
void free_worktrees(struct worktree **);
@@ -164,14 +188,6 @@ int is_worktree_being_rebased(const struct worktree *wt, const char *target);
int is_worktree_being_bisected(const struct worktree *wt, const char *target);
/*
- * Similar to git_path() but can produce paths for a specified
- * worktree instead of current one
- */
-const char *worktree_git_path(const struct worktree *wt,
- const char *fmt, ...)
- __attribute__((format (printf, 2, 3)));
-
-/*
* Return a refname suitable for access from the current ref store.
*/
void strbuf_worktree_ref(const struct worktree *wt,
diff --git a/wrapper.c b/wrapper.c
index 5160c9e28d..f87d90bf57 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -3,10 +3,8 @@
*/
#include "git-compat-util.h"
#include "abspath.h"
-#include "config.h"
+#include "parse.h"
#include "gettext.h"
-#include "object.h"
-#include "repository.h"
#include "strbuf.h"
#include "trace2.h"
@@ -632,11 +630,6 @@ int rmdir_or_warn(const char *file)
return warn_if_unremovable("rmdir", file, rmdir(file));
}
-int remove_or_warn(unsigned int mode, const char *file)
-{
- return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
-}
-
static int access_error_is_ok(int err, unsigned flag)
{
return (is_missing_file_error(err) ||
@@ -677,7 +670,7 @@ int xsnprintf(char *dst, size_t max, const char *fmt, ...)
va_end(ap);
if (len < 0)
- BUG("your snprintf is broken");
+ die(_("unable to format message: %s"), fmt);
if (len >= max)
BUG("attempt to snprintf into too-small buffer");
return len;
@@ -819,3 +812,13 @@ int csprng_bytes(void *buf, size_t len)
return 0;
#endif
}
+
+uint32_t git_rand(void)
+{
+ uint32_t result;
+
+ if (csprng_bytes(&result, sizeof(result)) < 0)
+ die(_("unable to get random bytes"));
+
+ return result;
+}
diff --git a/wrapper.h b/wrapper.h
index 79a9c1b507..a6b3e1f09e 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -106,11 +106,6 @@ int unlink_or_msg(const char *file, struct strbuf *err);
* 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"
@@ -139,4 +134,28 @@ void sleep_millisec(int millisec);
*/
int csprng_bytes(void *buf, size_t len);
+/*
+ * Returns a random uint32_t, uniformly distributed across all possible
+ * values.
+ */
+uint32_t git_rand(void);
+
+/* Provide log2 of the given `size_t`. */
+static inline unsigned log2u(uintmax_t sz)
+{
+ unsigned l = 0;
+
+ /*
+ * Technically this isn't required, but it helps the compiler optimize
+ * this to a `bsr` instruction.
+ */
+ if (!sz)
+ return 0;
+
+ for (; sz; sz >>= 1)
+ l++;
+
+ return l - 1;
+}
+
#endif /* WRAPPER_H */
diff --git a/write-or-die.c b/write-or-die.c
index d8355c0c3e..01a9a51fa2 100644
--- a/write-or-die.c
+++ b/write-or-die.c
@@ -1,5 +1,5 @@
#include "git-compat-util.h"
-#include "config.h"
+#include "parse.h"
#include "run-command.h"
#include "write-or-die.h"
@@ -18,23 +18,20 @@
*/
void maybe_flush_or_die(FILE *f, const char *desc)
{
- static int skip_stdout_flush = -1;
- struct stat st;
- char *cp;
-
if (f == stdout) {
- if (skip_stdout_flush < 0) {
- /* NEEDSWORK: make this a normal Boolean */
- cp = getenv("GIT_FLUSH");
- if (cp)
- skip_stdout_flush = (atoi(cp) == 0);
- else if ((fstat(fileno(stdout), &st) == 0) &&
- S_ISREG(st.st_mode))
- skip_stdout_flush = 1;
- else
- skip_stdout_flush = 0;
+ static int force_flush_stdout = -1;
+
+ if (force_flush_stdout < 0) {
+ force_flush_stdout = git_env_bool("GIT_FLUSH", -1);
+ if (force_flush_stdout < 0) {
+ struct stat st;
+ if (fstat(fileno(stdout), &st))
+ force_flush_stdout = 1;
+ else
+ force_flush_stdout = !S_ISREG(st.st_mode);
+ }
}
- if (skip_stdout_flush && !ferror(f))
+ if (!force_flush_stdout && !ferror(f))
return;
}
if (fflush(f)) {
diff --git a/wt-status.c b/wt-status.c
index d03dfab9e4..6a8c05d1cf 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "wt-status.h"
@@ -14,6 +16,7 @@
#include "revision.h"
#include "diffcore.h"
#include "quote.h"
+#include "repository.h"
#include "run-command.h"
#include "strvec.h"
#include "remote.h"
@@ -70,7 +73,7 @@ static void status_vprintf(struct wt_status *s, int at_bol, const char *color,
strbuf_vaddf(&sb, fmt, ap);
if (!sb.len) {
if (s->display_comment_prefix) {
- strbuf_addch(&sb, comment_line_char);
+ strbuf_addstr(&sb, comment_line_str);
if (!trail)
strbuf_addch(&sb, ' ');
}
@@ -85,7 +88,7 @@ static void status_vprintf(struct wt_status *s, int at_bol, const char *color,
strbuf_reset(&linebuf);
if (at_bol && s->display_comment_prefix) {
- strbuf_addch(&linebuf, comment_line_char);
+ strbuf_addstr(&linebuf, comment_line_str);
if (*line != '\n' && *line != '\t')
strbuf_addch(&linebuf, ' ');
}
@@ -126,6 +129,7 @@ void status_printf(struct wt_status *s, const char *color,
va_end(ap);
}
+__attribute__((format (printf, 3, 4)))
static void status_printf_more(struct wt_status *s, const char *color,
const char *fmt, ...)
{
@@ -145,10 +149,11 @@ void wt_status_prepare(struct repository *r, struct wt_status *s)
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
s->use_color = -1;
s->relative_paths = 1;
- s->branch = resolve_refdup("HEAD", 0, NULL, NULL);
+ s->branch = refs_resolve_refdup(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, NULL);
s->reference = "HEAD";
s->fp = stdout;
- s->index_file = get_index_file();
+ s->index_file = repo_get_index_file(the_repository);
s->change.strdup_strings = 1;
s->untracked.strdup_strings = 1;
s->ignored.strdup_strings = 1;
@@ -640,7 +645,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
repo_init_revisions(s->repo, &rev, NULL);
memset(&opt, 0, sizeof(opt));
- opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
+ opt.def = s->is_initial ? empty_tree_oid_hex(the_repository->hash_algo) : s->reference;
setup_revisions(0, NULL, &rev, &opt);
rev.diffopt.flags.override_submodule_config = 1;
@@ -712,6 +717,7 @@ static int add_file_to_list(const struct object_id *oid,
static void wt_status_collect_changes_initial(struct wt_status *s)
{
struct index_state *istate = s->repo->index;
+ struct strbuf base = STRBUF_INIT;
int i;
for (i = 0; i < istate->cache_nr; i++) {
@@ -730,7 +736,6 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
* expanding the trees to find the elements that are new in this
* tree and marking them with DIFF_STATUS_ADDED.
*/
- struct strbuf base = STRBUF_INIT;
struct pathspec ps = { 0 };
struct tree *tree = lookup_tree(istate->repo, &ce->oid);
@@ -738,9 +743,11 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
ps.has_wildcard = 1;
ps.max_depth = -1;
+ strbuf_reset(&base);
strbuf_add(&base, ce->name, ce->ce_namelen);
- read_tree_at(istate->repo, tree, &base, &ps,
+ read_tree_at(istate->repo, tree, &base, 0, &ps,
add_file_to_list, s);
+
continue;
}
@@ -767,6 +774,8 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
s->committable = 1;
}
}
+
+ strbuf_release(&base);
}
static void wt_status_collect_untracked(struct wt_status *s)
@@ -861,6 +870,7 @@ void wt_status_state_free_buffers(struct wt_status_state *state)
FREE_AND_NULL(state->branch);
FREE_AND_NULL(state->onto);
FREE_AND_NULL(state->detached_from);
+ FREE_AND_NULL(state->bisecting_from);
}
static void wt_longstatus_print_unmerged(struct wt_status *s)
@@ -975,7 +985,8 @@ static int stash_count_refs(struct object_id *ooid UNUSED,
static int count_stash_entries(void)
{
int n = 0;
- for_each_reflog_ent("refs/stash", stash_count_refs, &n);
+ refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ "refs/stash", stash_count_refs, &n);
return n;
}
@@ -1027,7 +1038,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, comment_line_char);
+ strbuf_add_commented_lines(&summary, summary_content, len, comment_line_str);
free(summary_content);
}
@@ -1089,11 +1100,14 @@ size_t wt_status_locate_end(const char *s, size_t len)
const char *p;
struct strbuf pattern = STRBUF_INIT;
- strbuf_addf(&pattern, "\n%c %s", comment_line_char, cut_line);
+ strbuf_addf(&pattern, "\n%s %s", comment_line_str, cut_line);
if (starts_with(s, pattern.buf + 1))
len = 0;
- else if ((p = strstr(s, pattern.buf)))
- len = p - s + 1;
+ else if ((p = strstr(s, pattern.buf))) {
+ size_t newlen = p - s + 1;
+ if (newlen < len)
+ len = newlen;
+ }
strbuf_release(&pattern);
return len;
}
@@ -1102,16 +1116,19 @@ 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, comment_line_char, "%s", cut_line);
- strbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);
+ strbuf_commented_addf(buf, comment_line_str, "%s", cut_line);
+ strbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_str);
}
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_add_cut_line(struct wt_status *s)
{
struct strbuf buf = STRBUF_INIT;
+ if (s->added_cut_line)
+ return;
+ s->added_cut_line = 1;
wt_status_append_cut_line(&buf);
- fputs(buf.buf, fp);
+ fputs(buf.buf, s->fp);
strbuf_release(&buf);
}
@@ -1127,7 +1144,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
rev.diffopt.ita_invisible_in_index = 1;
memset(&opt, 0, sizeof(opt));
- opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
+ opt.def = s->is_initial ? empty_tree_oid_hex(the_repository->hash_algo) : s->reference;
setup_revisions(0, NULL, &rev, &opt);
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
@@ -1142,11 +1159,12 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
* file (and even the "auto" setting won't work, since it
* will have checked isatty on stdout). But we then do want
* to insert the scissor line here to reliably remove the
- * diff before committing.
+ * diff before committing, if we didn't already include one
+ * before.
*/
if (s->fp != stdout) {
rev.diffopt.use_color = 0;
- wt_status_add_cut_line(s->fp);
+ wt_status_add_cut_line(s);
}
if (s->verbose > 1 && s->committable) {
/* print_updated() printed a header, so do we */
@@ -1175,8 +1193,6 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
struct strbuf sb = STRBUF_INIT;
const char *cp, *ep, *branch_name;
struct branch *branch;
- char comment_line_string[3];
- int i;
uint64_t t_begin = 0;
assert(s->branch && !s->is_initial);
@@ -1201,20 +1217,15 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
}
}
- i = 0;
- if (s->display_comment_prefix) {
- comment_line_string[i++] = comment_line_char;
- comment_line_string[i++] = ' ';
- }
- comment_line_string[i] = '\0';
-
for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
- "%s%.*s", comment_line_string,
+ "%s%s%.*s",
+ s->display_comment_prefix ? comment_line_str : "",
+ s->display_comment_prefix ? " " : "",
(int)(ep - cp), cp);
if (s->display_comment_prefix)
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
- comment_line_char);
+ color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%s",
+ comment_line_str);
else
fputs("\n", s->fp);
strbuf_release(&sb);
@@ -1295,26 +1306,32 @@ static char *read_line_from_git_path(const char *filename)
static int split_commit_in_progress(struct wt_status *s)
{
int split_in_progress = 0;
- char *head, *orig_head, *rebase_amend, *rebase_orig_head;
+ struct object_id head_oid, orig_head_oid;
+ char *rebase_amend, *rebase_orig_head;
+ int head_flags, orig_head_flags;
if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
!s->branch || strcmp(s->branch, "HEAD"))
return 0;
- head = read_line_from_git_path("HEAD");
- orig_head = read_line_from_git_path("ORIG_HEAD");
+ if (refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ &head_oid, &head_flags) ||
+ refs_read_ref_full(get_main_ref_store(the_repository), "ORIG_HEAD", RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ &orig_head_oid, &orig_head_flags))
+ return 0;
+ if (head_flags & REF_ISSYMREF || orig_head_flags & REF_ISSYMREF)
+ return 0;
+
rebase_amend = read_line_from_git_path("rebase-merge/amend");
rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
- if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
+ if (!rebase_amend || !rebase_orig_head)
; /* fall through, no split in progress */
else if (!strcmp(rebase_amend, rebase_orig_head))
- split_in_progress = !!strcmp(head, rebase_amend);
- else if (strcmp(orig_head, rebase_orig_head))
+ split_in_progress = !!strcmp(oid_to_hex(&head_oid), rebase_amend);
+ else if (strcmp(oid_to_hex(&orig_head_oid), rebase_orig_head))
split_in_progress = 1;
- free(head);
- free(orig_head);
free(rebase_amend);
free(rebase_orig_head);
@@ -1375,7 +1392,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
git_path("%s", fname));
}
while (!strbuf_getline_lf(&line, f)) {
- if (line.len && line.buf[0] == comment_line_char)
+ if (starts_with(line.buf, comment_line_str))
continue;
strbuf_trim(&line);
if (!line.len)
@@ -1569,10 +1586,10 @@ static void show_revert_in_progress(struct wt_status *s,
static void show_bisect_in_progress(struct wt_status *s,
const char *color)
{
- if (s->state.branch)
+ if (s->state.bisecting_from)
status_printf_ln(s, color,
_("You are currently bisecting, started from branch '%s'."),
- s->state.branch);
+ s->state.bisecting_from);
else
status_printf_ln(s, color,
_("You are currently bisecting."));
@@ -1606,7 +1623,7 @@ static char *get_branch(const struct worktree *wt, const char *path)
struct object_id oid;
const char *branch_name;
- if (strbuf_read_file(&sb, worktree_git_path(wt, "%s", path), 0) <= 0)
+ if (strbuf_read_file(&sb, worktree_git_path(the_repository, wt, "%s", path), 0) <= 0)
goto got_nothing;
while (sb.len && sb.buf[sb.len - 1] == '\n')
@@ -1672,7 +1689,7 @@ static void wt_status_get_detached_from(struct repository *r,
char *ref = NULL;
strbuf_init(&cb.buf, 0);
- if (for_each_reflog_ent_reverse("HEAD", grab_1st_switch, &cb) <= 0) {
+ if (refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository), "HEAD", grab_1st_switch, &cb) <= 0) {
strbuf_release(&cb.buf);
return;
}
@@ -1704,18 +1721,18 @@ int wt_status_check_rebase(const struct worktree *wt,
{
struct stat st;
- if (!stat(worktree_git_path(wt, "rebase-apply"), &st)) {
- if (!stat(worktree_git_path(wt, "rebase-apply/applying"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-apply"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/applying"), &st)) {
state->am_in_progress = 1;
- if (!stat(worktree_git_path(wt, "rebase-apply/patch"), &st) && !st.st_size)
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/patch"), &st) && !st.st_size)
state->am_empty_patch = 1;
} else {
state->rebase_in_progress = 1;
state->branch = get_branch(wt, "rebase-apply/head-name");
state->onto = get_branch(wt, "rebase-apply/onto");
}
- } else if (!stat(worktree_git_path(wt, "rebase-merge"), &st)) {
- if (!stat(worktree_git_path(wt, "rebase-merge/interactive"), &st))
+ } else if (!stat(worktree_git_path(the_repository, wt, "rebase-merge"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-merge/interactive"), &st))
state->rebase_interactive_in_progress = 1;
else
state->rebase_in_progress = 1;
@@ -1731,9 +1748,9 @@ int wt_status_check_bisect(const struct worktree *wt,
{
struct stat st;
- if (!stat(worktree_git_path(wt, "BISECT_LOG"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "BISECT_LOG"), &st)) {
state->bisect_in_progress = 1;
- state->branch = get_branch(wt, "BISECT_START");
+ state->bisecting_from = get_branch(wt, "BISECT_START");
return 1;
}
return 0;
@@ -2080,7 +2097,8 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
upstream_is_gone = 1;
}
- short_base = shorten_unambiguous_ref(base, 0);
+ short_base = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ base, 0);
color_fprintf(s->fp, header_color, "...");
color_fprintf(s->fp, branch_color_remote, "%s", short_base);
free(short_base);
@@ -2213,7 +2231,8 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)
ab_info = stat_tracking_info(branch, &nr_ahead, &nr_behind,
&base, 0, s->ahead_behind_flags);
if (base) {
- base = shorten_unambiguous_ref(base, 0);
+ base = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+ base, 0);
fprintf(s->fp, "# branch.upstream %s%c", base, eol);
free((char *)base);
@@ -2397,7 +2416,7 @@ static void wt_porcelain_v2_print_unmerged_entry(
int mode;
struct object_id oid;
} stages[3];
- char *key;
+ const char *key;
char submodule_token[5];
char unmerged_prefix = 'u';
char eol_char = s->null_termination ? '\0' : '\n';
@@ -2581,7 +2600,7 @@ int has_unstaged_changes(struct repository *r, int ignore_submodules)
rev_info.diffopt.flags.quick = 1;
diff_setup_done(&rev_info.diffopt);
run_diff_files(&rev_info, 0);
- result = diff_result_code(&rev_info.diffopt);
+ result = diff_result_code(&rev_info);
release_revisions(&rev_info);
return result;
}
@@ -2615,7 +2634,7 @@ int has_uncommitted_changes(struct repository *r,
diff_setup_done(&rev_info.diffopt);
run_diff_index(&rev_info, DIFF_INDEX_CACHED);
- result = diff_result_code(&rev_info.diffopt);
+ result = diff_result_code(&rev_info);
release_revisions(&rev_info);
return result;
}
diff --git a/wt-status.h b/wt-status.h
index ab9cc9d8f0..4e377ce62b 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -23,7 +23,8 @@ enum color_wt_status {
};
enum untracked_status_type {
- SHOW_NO_UNTRACKED_FILES,
+ SHOW_UNTRACKED_FILES_ERROR = -1,
+ SHOW_NO_UNTRACKED_FILES = 0,
SHOW_NORMAL_UNTRACKED_FILES,
SHOW_ALL_UNTRACKED_FILES
};
@@ -94,6 +95,7 @@ struct wt_status_state {
char *branch;
char *onto;
char *detached_from;
+ char *bisecting_from;
struct object_id detached_oid;
struct object_id revert_head_oid;
struct object_id cherry_pick_head_oid;
@@ -129,6 +131,7 @@ struct wt_status {
int rename_score;
int rename_limit;
enum wt_status_format status_format;
+ unsigned char added_cut_line; /* boolean */
struct wt_status_state state;
struct object_id oid_commit; /* when not Initial */
@@ -146,7 +149,7 @@ struct wt_status {
size_t wt_status_locate_end(const char *s, size_t len);
void wt_status_append_cut_line(struct strbuf *buf);
-void wt_status_add_cut_line(FILE *fp);
+void wt_status_add_cut_line(struct wt_status *s);
void wt_status_prepare(struct repository *r, struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
diff --git a/xdiff-interface.c b/xdiff-interface.c
index adcea109fa..d5dc88661e 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
+#include "gettext.h"
#include "config.h"
#include "hex.h"
#include "object-store-ll.h"
@@ -6,8 +9,6 @@
#include "xdiff-interface.h"
#include "xdiff/xtypes.h"
#include "xdiff/xdiffi.h"
-#include "xdiff/xemit.h"
-#include "xdiff/xmacros.h"
#include "xdiff/xutils.h"
struct xdiff_emit_state {
@@ -306,6 +307,22 @@ int xdiff_compare_lines(const char *l1, long s1,
return xdl_recmatch(l1, s1, l2, s2, flags);
}
+int parse_conflict_style_name(const char *value)
+{
+ if (!strcmp(value, "diff3"))
+ return XDL_MERGE_DIFF3;
+ else if (!strcmp(value, "zdiff3"))
+ return XDL_MERGE_ZEALOUS_DIFF3;
+ else if (!strcmp(value, "merge"))
+ return 0;
+ /*
+ * Please update _git_checkout() in git-completion.bash when
+ * you add new merge config
+ */
+ else
+ return -1;
+}
+
int git_xmerge_style = -1;
int git_xmerge_config(const char *var, const char *value,
@@ -313,20 +330,11 @@ int git_xmerge_config(const char *var, const char *value,
{
if (!strcmp(var, "merge.conflictstyle")) {
if (!value)
- die("'%s' is not a boolean", var);
- if (!strcmp(value, "diff3"))
- git_xmerge_style = XDL_MERGE_DIFF3;
- else if (!strcmp(value, "zdiff3"))
- git_xmerge_style = XDL_MERGE_ZEALOUS_DIFF3;
- else if (!strcmp(value, "merge"))
- git_xmerge_style = 0;
- /*
- * Please update _git_checkout() in
- * git-completion.bash when you add new merge config
- */
- else
- die("unknown style '%s' given for '%s'",
- value, var);
+ return config_error_nonbool(var);
+ git_xmerge_style = parse_conflict_style_name(value);
+ if (git_xmerge_style == -1)
+ return error(_("unknown style '%s' given for '%s'"),
+ value, var);
return 0;
}
return git_default_config(var, value, ctx, cb);
diff --git a/xdiff-interface.h b/xdiff-interface.h
index e6f80df046..1ed430b622 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -1,7 +1,7 @@
#ifndef XDIFF_INTERFACE_H
#define XDIFF_INTERFACE_H
-#include "hash-ll.h"
+#include "hash.h"
#include "xdiff/xdiff.h"
/*
@@ -51,6 +51,7 @@ 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);
struct config_context;
+int parse_conflict_style_name(const char *value);
int git_xmerge_config(const char *var, const char *value,
const struct config_context *ctx, void *cb);
extern int git_xmerge_style;